]> git.proxmox.com Git - mirror_frr.git/blob - bgpd/bgp_mac.c
Merge pull request #6017 from sarav511/ovrride
[mirror_frr.git] / bgpd / bgp_mac.c
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 DEFINE_MTYPE_STATIC(BGPD, BSM, "Mac Hash Entry");
37 DEFINE_MTYPE_STATIC(BGPD, BSM_STRING, "Mac Hash Entry Interface String");
38
39 struct bgp_self_mac {
40 struct ethaddr macaddr;
41 struct list *ifp_list;
42 };
43
44 static unsigned int bgp_mac_hash_key_make(const void *data)
45 {
46 const struct bgp_self_mac *bsm = data;
47
48 return jhash(&bsm->macaddr, ETH_ALEN, 0xa5a5dead);
49 }
50
51 static bool bgp_mac_hash_cmp(const void *d1, const void *d2)
52 {
53 const struct bgp_self_mac *bsm1 = d1;
54 const struct bgp_self_mac *bsm2 = d2;
55
56 if (memcmp(&bsm1->macaddr, &bsm2->macaddr, ETH_ALEN) == 0)
57 return true;
58
59 return false;
60 }
61
62 void bgp_mac_init(void)
63 {
64 bm->self_mac_hash = hash_create(bgp_mac_hash_key_make, bgp_mac_hash_cmp,
65 "BGP MAC Hash");
66 }
67
68 static void bgp_mac_hash_free(void *data)
69 {
70 struct bgp_self_mac *bsm = data;
71
72 if (bsm->ifp_list)
73 list_delete(&bsm->ifp_list);
74
75 XFREE(MTYPE_BSM, bsm);
76 }
77
78 void bgp_mac_finish(void)
79 {
80 hash_clean(bm->self_mac_hash, bgp_mac_hash_free);
81 hash_free(bm->self_mac_hash);
82 }
83
84 static void bgp_mac_hash_interface_string_del(void *val)
85 {
86 char *data = val;
87
88 XFREE(MTYPE_BSM_STRING, data);
89 }
90
91 static void *bgp_mac_hash_alloc(void *p)
92 {
93 const struct bgp_self_mac *orig = p;
94 struct bgp_self_mac *bsm;
95
96 bsm = XCALLOC(MTYPE_BSM, sizeof(struct bgp_self_mac));
97 memcpy(&bsm->macaddr, &orig->macaddr, ETH_ALEN);
98
99 bsm->ifp_list = list_new();
100 bsm->ifp_list->del = bgp_mac_hash_interface_string_del;
101
102 return bsm;
103 }
104
105 struct bgp_mac_find_internal {
106 struct bgp_self_mac *bsm;
107 const char *ifname;
108 };
109
110 static void bgp_mac_find_ifp_internal(struct hash_bucket *bucket, void *arg)
111 {
112 struct bgp_mac_find_internal *bmfi = arg;
113 struct bgp_self_mac *bsm = bucket->data;
114 struct listnode *node;
115 char *name;
116
117 for (ALL_LIST_ELEMENTS_RO(bsm->ifp_list, node, name)) {
118 if (strcmp(name, bmfi->ifname) == 0) {
119 bmfi->bsm = bsm;
120 return;
121 }
122 }
123 }
124
125 static struct bgp_self_mac *bgp_mac_find_interface_name(const char *ifname)
126 {
127 struct bgp_mac_find_internal bmfi;
128
129 bmfi.bsm = NULL;
130 bmfi.ifname = ifname;
131 hash_iterate(bm->self_mac_hash, bgp_mac_find_ifp_internal, &bmfi);
132
133 return bmfi.bsm;
134 }
135
136 static void bgp_process_mac_rescan_table(struct bgp *bgp, struct peer *peer,
137 struct bgp_table *table,
138 struct ethaddr *macaddr)
139 {
140 struct bgp_node *prn, *rn;
141 struct bgp_path_info *pi;
142
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);
146
147 if (!sub)
148 continue;
149
150 for (rn = bgp_table_top(sub); rn; rn = bgp_route_next(rn)) {
151 bool rn_affected;
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;
158
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)
163 rn_affected = true;
164 else
165 rn_affected = false;
166
167 for (pi = rn->info; pi; pi = pi->next) {
168 if (pi->peer == peer)
169 break;
170 }
171
172 if (!pi)
173 continue;
174
175 /*
176 * If the mac address is not the same then
177 * we don't care and since we are looking
178 */
179 if ((memcmp(&pi->attr->rmac, macaddr, ETH_ALEN) != 0) &&
180 !rn_affected)
181 continue;
182
183 if (pi->extra)
184 num_labels = pi->extra->num_labels;
185 if (num_labels)
186 label_pnt = &pi->extra->label[0];
187
188 prd.family = AF_UNSPEC;
189 prd.prefixlen = 64;
190 memcpy(&prd.val, prn_p->u.val, 8);
191
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];
195
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,
201 sizeof(pfx_buf));
202 zlog_debug(
203 "%s skip update of %s marked as removed",
204 peer->host, pfx_buf);
205 }
206 continue;
207 }
208
209 memcpy(&evpn, &pi->attr->evpn_overlay, sizeof(evpn));
210 int32_t ret = bgp_update(peer, p,
211 pi->addpath_rx_id,
212 pi->attr, AFI_L2VPN, SAFI_EVPN,
213 ZEBRA_ROUTE_BGP,
214 BGP_ROUTE_NORMAL, &prd,
215 label_pnt, num_labels,
216 1, &evpn);
217
218 if (ret < 0)
219 bgp_unlock_node(rn);
220 }
221 }
222 }
223
224 static void bgp_mac_rescan_evpn_table(struct bgp *bgp, struct ethaddr *macaddr)
225 {
226 struct listnode *node;
227 struct peer *peer;
228 safi_t safi;
229 afi_t afi;
230
231 afi = AFI_L2VPN;
232 safi = SAFI_EVPN;
233 for (ALL_LIST_ELEMENTS_RO(bgp->peer, node, peer)) {
234
235 if (CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP))
236 continue;
237
238 if (peer->status != Established)
239 continue;
240
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)",
245 peer->host);
246
247 bgp_soft_reconfig_in(peer, afi, safi);
248 } else {
249 struct bgp_table *table = bgp->rib[afi][safi];
250
251 if (bgp_debug_update(peer, NULL, NULL, 1))
252 zlog_debug("Processing EVPN MAC interface change on peer %s",
253 peer->host);
254 bgp_process_mac_rescan_table(bgp, peer, table, macaddr);
255 }
256 }
257 }
258
259 static void bgp_mac_rescan_all_evpn_tables(struct ethaddr *macaddr)
260 {
261 struct listnode *node;
262 struct bgp *bgp;
263
264 for (ALL_LIST_ELEMENTS_RO(bm->bgp, node, bgp)) {
265 struct bgp_table *table = bgp->rib[AFI_L2VPN][SAFI_EVPN];
266
267 if (table)
268 bgp_mac_rescan_evpn_table(bgp, macaddr);
269 }
270 }
271
272 static void bgp_mac_remove_ifp_internal(struct bgp_self_mac *bsm, char *ifname,
273 struct ethaddr *macaddr)
274 {
275 struct listnode *node = NULL;
276 char *name;
277
278 for (ALL_LIST_ELEMENTS_RO(bsm->ifp_list, node, name)) {
279 if (strcmp(name, ifname) == 0)
280 break;
281 }
282
283 if (node) {
284 list_delete_node(bsm->ifp_list, node);
285 XFREE(MTYPE_BSM_STRING, name);
286 }
287
288 if (bsm->ifp_list->count == 0) {
289 struct ethaddr mac = *macaddr;
290
291 hash_release(bm->self_mac_hash, bsm);
292 list_delete(&bsm->ifp_list);
293 XFREE(MTYPE_BSM, bsm);
294
295 bgp_mac_rescan_all_evpn_tables(&mac);
296 }
297 }
298
299 void bgp_mac_add_mac_entry(struct interface *ifp)
300 {
301 struct bgp_self_mac lookup;
302 struct bgp_self_mac *bsm;
303 struct bgp_self_mac *old_bsm;
304 char *ifname;
305
306 memcpy(&lookup.macaddr, &ifp->hw_addr, ETH_ALEN);
307 bsm = hash_get(bm->self_mac_hash, &lookup, bgp_mac_hash_alloc);
308
309 /*
310 * Does this happen to be a move
311 */
312 old_bsm = bgp_mac_find_interface_name(ifp->name);
313 ifname = XSTRDUP(MTYPE_BSM_STRING, ifp->name);
314
315 if (bsm->ifp_list->count == 0) {
316
317 listnode_add(bsm->ifp_list, ifname);
318 if (old_bsm)
319 bgp_mac_remove_ifp_internal(old_bsm, ifname,
320 &old_bsm->macaddr);
321 } else {
322 /*
323 * If old mac address is the same as the new,
324 * then there is nothing to do here
325 */
326 if (old_bsm == bsm) {
327 XFREE(MTYPE_BSM_STRING, ifname);
328 return;
329 }
330
331 if (old_bsm)
332 bgp_mac_remove_ifp_internal(old_bsm, ifp->name,
333 &old_bsm->macaddr);
334
335 listnode_add(bsm->ifp_list, ifname);
336 }
337
338 bgp_mac_rescan_all_evpn_tables(&bsm->macaddr);
339 }
340
341 void bgp_mac_del_mac_entry(struct interface *ifp)
342 {
343 struct bgp_self_mac lookup;
344 struct bgp_self_mac *bsm;
345
346 memcpy(&lookup.macaddr, &ifp->hw_addr, ETH_ALEN);
347 bsm = hash_lookup(bm->self_mac_hash, &lookup);
348 if (!bsm)
349 return;
350
351 /*
352 * Write code to allow old mac address to no-longer
353 * win if we happen to have received it from a peer.
354 */
355 bgp_mac_remove_ifp_internal(bsm, ifp->name, &bsm->macaddr);
356 }
357
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.
362 */
363 bool bgp_mac_exist(const struct ethaddr *mac)
364 {
365 struct bgp_self_mac lookup;
366 struct bgp_self_mac *bsm;
367 static uint8_t tmp [ETHER_ADDR_STRLEN] = {0};
368
369 if (memcmp(mac, &tmp, ETH_ALEN) == 0)
370 return false;
371
372 memcpy(&lookup.macaddr, mac, ETH_ALEN);
373 bsm = hash_lookup(bm->self_mac_hash, &lookup);
374 if (!bsm)
375 return false;
376
377 return true;
378 }
379
380 /* This API checks EVPN type-2 prefix and comapares
381 * mac against any of local assigned (SVIs) MAC
382 * address.
383 */
384 bool bgp_mac_entry_exists(const struct prefix *p)
385 {
386 const struct prefix_evpn *pevpn = (const struct prefix_evpn *)p;
387
388 if (pevpn->family != AF_EVPN)
389 return false;
390
391 if (pevpn->prefix.route_type != BGP_EVPN_MAC_IP_ROUTE)
392 return false;
393
394 return bgp_mac_exist(&p->u.prefix_evpn.macip_addr.mac);
395
396 return true;
397 }
398
399 static void bgp_mac_show_mac_entry(struct hash_bucket *bucket, void *arg)
400 {
401 struct vty *vty = arg;
402 struct bgp_self_mac *bsm = bucket->data;
403 struct listnode *node;
404 char *name;
405 char buf_mac[ETHER_ADDR_STRLEN];
406
407 vty_out(vty, "Mac Address: %s ",
408 prefix_mac2str(&bsm->macaddr, buf_mac, sizeof(buf_mac)));
409
410 for (ALL_LIST_ELEMENTS_RO(bsm->ifp_list, node, name))
411 vty_out(vty, "%s ", name);
412
413 vty_out(vty, "\n");
414 }
415
416 void bgp_mac_dump_table(struct vty *vty)
417 {
418 hash_iterate(bm->self_mac_hash, bgp_mac_show_mac_entry, vty);
419 }