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_debug.h"
33 #include "bgpd/bgp_evpn_private.h"
35 DEFINE_MTYPE_STATIC(BGPD
, BSM
, "Mac Hash Entry");
36 DEFINE_MTYPE_STATIC(BGPD
, BSM_STRING
, "Mac Hash Entry Interface String");
39 struct ethaddr macaddr
;
40 struct list
*ifp_list
;
43 static unsigned int bgp_mac_hash_key_make(void *data
)
45 struct bgp_self_mac
*bsm
= data
;
47 return jhash(&bsm
->macaddr
, ETH_ALEN
, 0xa5a5dead);
50 static bool bgp_mac_hash_cmp(const void *d1
, const void *d2
)
52 const struct bgp_self_mac
*bsm1
= d1
;
53 const struct bgp_self_mac
*bsm2
= d2
;
55 if (memcmp(&bsm1
->macaddr
, &bsm2
->macaddr
, ETH_ALEN
) == 0)
61 void bgp_mac_init(void)
63 bm
->self_mac_hash
= hash_create(bgp_mac_hash_key_make
, bgp_mac_hash_cmp
,
67 static void bgp_mac_hash_free(void *data
)
69 struct bgp_self_mac
*bsm
= data
;
72 list_delete(&bsm
->ifp_list
);
74 XFREE(MTYPE_BSM
, bsm
);
77 void bgp_mac_finish(void)
79 hash_clean(bm
->self_mac_hash
, bgp_mac_hash_free
);
80 hash_free(bm
->self_mac_hash
);
83 static void bgp_mac_hash_interface_string_del(void *val
)
87 XFREE(MTYPE_BSM_STRING
, data
);
90 static void *bgp_mac_hash_alloc(void *p
)
92 const struct bgp_self_mac
*orig
= p
;
93 struct bgp_self_mac
*bsm
;
95 bsm
= XCALLOC(MTYPE_BSM
, sizeof(struct bgp_self_mac
));
96 memcpy(&bsm
->macaddr
, &orig
->macaddr
, ETH_ALEN
);
98 bsm
->ifp_list
= list_new();
99 bsm
->ifp_list
->del
= bgp_mac_hash_interface_string_del
;
104 struct bgp_mac_find_internal
{
105 struct bgp_self_mac
*bsm
;
109 static void bgp_mac_find_ifp_internal(struct hash_backet
*backet
, void *arg
)
111 struct bgp_mac_find_internal
*bmfi
= arg
;
112 struct bgp_self_mac
*bsm
= backet
->data
;
113 struct listnode
*node
;
116 for (ALL_LIST_ELEMENTS_RO(bsm
->ifp_list
, node
, name
)) {
117 if (strcmp(name
, bmfi
->ifname
) == 0) {
124 static struct bgp_self_mac
*bgp_mac_find_interface_name(const char *ifname
)
126 struct bgp_mac_find_internal bmfi
;
129 bmfi
.ifname
= ifname
;
130 hash_iterate(bm
->self_mac_hash
, bgp_mac_find_ifp_internal
, &bmfi
);
135 static void bgp_process_mac_rescan_table(struct bgp
*bgp
, struct peer
*peer
,
136 struct bgp_table
*table
)
138 struct bgp_node
*prn
, *rn
;
139 struct bgp_path_info
*pi
;
142 for (prn
= bgp_table_top(table
); prn
; prn
= bgp_route_next(prn
)) {
143 struct bgp_table
*sub
= prn
->info
;
148 for (rn
= bgp_table_top(sub
); rn
; rn
= bgp_route_next(rn
)) {
149 struct prefix_rd prd
;
150 uint32_t num_labels
= 0;
151 mpls_label_t
*label_pnt
= NULL
;
152 struct bgp_route_evpn evpn
;
155 for (pi
= rn
->info
; pi
; pi
= pi
->next
) {
156 if (pi
->peer
== peer
)
164 num_labels
= pi
->extra
->num_labels
;
166 label_pnt
= &pi
->extra
->label
[0];
168 prd
.family
= AF_UNSPEC
;
170 memcpy(&prd
.val
, &prn
->p
.u
.val
, 8);
172 memcpy(&evpn
, &pi
->attr
->evpn_overlay
, sizeof(evpn
));
173 int32_t ret
= bgp_update(peer
, &rn
->p
,
175 pi
->attr
, AFI_L2VPN
, SAFI_EVPN
,
177 BGP_ROUTE_NORMAL
, &prd
,
178 label_pnt
, num_labels
,
187 static void bgp_mac_rescan_evpn_table(struct bgp
*bgp
)
189 struct listnode
*node
;
196 for (ALL_LIST_ELEMENTS_RO(bgp
->peer
, node
, peer
)) {
198 if (CHECK_FLAG(peer
->sflags
, PEER_STATUS_GROUP
))
201 if (peer
->status
!= Established
)
204 if (CHECK_FLAG(peer
->af_flags
[afi
][safi
],
205 PEER_FLAG_SOFT_RECONFIG
)) {
206 if (bgp_debug_update(peer
, NULL
, NULL
, 1))
207 zlog_debug("Processing EVPN MAC interface change on peer %s (inbound, soft-reconfig)",
210 bgp_soft_reconfig_in(peer
, afi
, safi
);
212 struct bgp_table
*table
= bgp
->rib
[afi
][safi
];
214 if (bgp_debug_update(peer
, NULL
, NULL
, 1))
215 zlog_debug("Processing EVPN MAC interface change on peer %s",
217 bgp_process_mac_rescan_table(bgp
, peer
, table
);
222 static void bgp_mac_rescan_all_evpn_tables(void)
224 struct listnode
*node
;
227 for (ALL_LIST_ELEMENTS_RO(bm
->bgp
, node
, bgp
)) {
228 struct bgp_table
*table
= bgp
->rib
[AFI_L2VPN
][SAFI_EVPN
];
231 bgp_mac_rescan_evpn_table(bgp
);
235 static void bgp_mac_remove_ifp_internal(struct bgp_self_mac
*bsm
, char *ifname
)
237 struct listnode
*node
= NULL
;
240 for (ALL_LIST_ELEMENTS_RO(bsm
->ifp_list
, node
, name
)) {
241 if (strcmp(name
, ifname
) == 0)
246 list_delete_node(bsm
->ifp_list
, node
);
247 XFREE(MTYPE_BSM_STRING
, name
);
250 if (bsm
->ifp_list
->count
== 0) {
251 hash_release(bm
->self_mac_hash
, bsm
);
252 list_delete(&bsm
->ifp_list
);
253 XFREE(MTYPE_BSM
, bsm
);
255 bgp_mac_rescan_all_evpn_tables();
259 void bgp_mac_add_mac_entry(struct interface
*ifp
)
261 struct bgp_self_mac lookup
;
262 struct bgp_self_mac
*bsm
;
263 struct bgp_self_mac
*old_bsm
;
266 memcpy(&lookup
.macaddr
, &ifp
->hw_addr
, ETH_ALEN
);
267 bsm
= hash_get(bm
->self_mac_hash
, &lookup
, bgp_mac_hash_alloc
);
270 * Does this happen to be a move
272 old_bsm
= bgp_mac_find_interface_name(ifp
->name
);
273 ifname
= XSTRDUP(MTYPE_BSM_STRING
, ifp
->name
);
275 if (bsm
->ifp_list
->count
== 0) {
277 listnode_add(bsm
->ifp_list
, ifname
);
279 bgp_mac_remove_ifp_internal(old_bsm
, ifname
);
282 * If old mac address is the same as the new,
283 * then there is nothing to do here
289 bgp_mac_remove_ifp_internal(old_bsm
, ifp
->name
);
291 listnode_add(bsm
->ifp_list
, ifname
);
294 bgp_mac_rescan_all_evpn_tables();
297 void bgp_mac_del_mac_entry(struct interface
*ifp
)
299 struct bgp_self_mac lookup
;
300 struct bgp_self_mac
*bsm
;
302 memcpy(&lookup
.macaddr
, &ifp
->hw_addr
, ETH_ALEN
);
303 bsm
= hash_lookup(bm
->self_mac_hash
, &lookup
);
308 * Write code to allow old mac address to no-longer
309 * win if we happen to have received it from a peer.
311 bgp_mac_remove_ifp_internal(bsm
, ifp
->name
);
314 bool bgp_mac_entry_exists(struct prefix
*p
)
316 struct prefix_evpn
*pevpn
= (struct prefix_evpn
*)p
;
317 struct bgp_self_mac lookup
;
318 struct bgp_self_mac
*bsm
;
320 if (pevpn
->family
!= AF_EVPN
)
323 if (pevpn
->prefix
.route_type
!= BGP_EVPN_MAC_IP_ROUTE
)
326 memcpy(&lookup
.macaddr
, &p
->u
.prefix_evpn
.macip_addr
.mac
, ETH_ALEN
);
327 bsm
= hash_lookup(bm
->self_mac_hash
, &lookup
);
334 static void bgp_mac_show_mac_entry(struct hash_backet
*backet
, void *arg
)
336 struct vty
*vty
= arg
;
337 struct bgp_self_mac
*bsm
= backet
->data
;
338 struct listnode
*node
;
340 char buf_mac
[ETHER_ADDR_STRLEN
];
342 vty_out(vty
, "Mac Address: %s ",
343 prefix_mac2str(&bsm
->macaddr
, buf_mac
, sizeof(buf_mac
)));
345 for (ALL_LIST_ELEMENTS_RO(bsm
->ifp_list
, node
, name
))
346 vty_out(vty
, "%s ", name
);
351 void bgp_mac_dump_table(struct vty
*vty
)
353 hash_iterate(bm
->self_mac_hash
, bgp_mac_show_mac_entry
, vty
);