]> git.proxmox.com Git - mirror_frr.git/blame - bgpd/bgp_mac.c
Merge pull request #5703 from ton31337/feature/limit_outgoing_prefixes
[mirror_frr.git] / bgpd / bgp_mac.c
CommitLineData
48ecf8f5
DS
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"
c869b3f8 32#include "bgpd/bgp_rd.h"
48ecf8f5 33#include "bgpd/bgp_debug.h"
4e802e66 34#include "bgpd/bgp_evpn_private.h"
48ecf8f5
DS
35
36DEFINE_MTYPE_STATIC(BGPD, BSM, "Mac Hash Entry");
6a69ac51 37DEFINE_MTYPE_STATIC(BGPD, BSM_STRING, "Mac Hash Entry Interface String");
48ecf8f5
DS
38
39struct bgp_self_mac {
40 struct ethaddr macaddr;
41 struct list *ifp_list;
42};
43
d8b87afe 44static unsigned int bgp_mac_hash_key_make(const void *data)
48ecf8f5 45{
d8b87afe 46 const struct bgp_self_mac *bsm = data;
48ecf8f5
DS
47
48 return jhash(&bsm->macaddr, ETH_ALEN, 0xa5a5dead);
49}
50
51static 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
62void 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
68static void bgp_mac_hash_free(void *data)
69{
70 struct bgp_self_mac *bsm = data;
71
4e802e66
DS
72 if (bsm->ifp_list)
73 list_delete(&bsm->ifp_list);
74
48ecf8f5
DS
75 XFREE(MTYPE_BSM, bsm);
76}
77
78void 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
6a69ac51
DS
84static void bgp_mac_hash_interface_string_del(void *val)
85{
86 char *data = val;
87
88 XFREE(MTYPE_BSM_STRING, data);
89}
90
91static 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
105struct bgp_mac_find_internal {
106 struct bgp_self_mac *bsm;
107 const char *ifname;
108};
109
e3b78da8 110static void bgp_mac_find_ifp_internal(struct hash_bucket *bucket, void *arg)
6a69ac51
DS
111{
112 struct bgp_mac_find_internal *bmfi = arg;
e3b78da8 113 struct bgp_self_mac *bsm = bucket->data;
6a69ac51
DS
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
125static 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
4e802e66 136static void bgp_process_mac_rescan_table(struct bgp *bgp, struct peer *peer,
78869ebf
DS
137 struct bgp_table *table,
138 struct ethaddr *macaddr)
4e802e66
DS
139{
140 struct bgp_node *prn, *rn;
141 struct bgp_path_info *pi;
4e802e66
DS
142
143 for (prn = bgp_table_top(table); prn; prn = bgp_route_next(prn)) {
144 struct bgp_table *sub = prn->info;
145
146 if (!sub)
147 continue;
148
149 for (rn = bgp_table_top(sub); rn; rn = bgp_route_next(rn)) {
78869ebf
DS
150 bool rn_affected;
151 struct prefix_evpn *pevpn = (struct prefix_evpn *)&rn->p;
4e802e66
DS
152 struct prefix_rd prd;
153 uint32_t num_labels = 0;
154 mpls_label_t *label_pnt = NULL;
155 struct bgp_route_evpn evpn;
156
78869ebf
DS
157 if (pevpn->family == AF_EVPN &&
158 pevpn->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE &&
159 memcmp(&rn->p.u.prefix_evpn.macip_addr.mac,
160 macaddr, ETH_ALEN) == 0)
161 rn_affected = true;
162 else
163 rn_affected = false;
164
4e802e66
DS
165 for (pi = rn->info; pi; pi = pi->next) {
166 if (pi->peer == peer)
167 break;
168 }
169
170 if (!pi)
171 continue;
172
78869ebf
DS
173 /*
174 * If the mac address is not the same then
175 * we don't care and since we are looking
176 */
177 if ((memcmp(&pi->attr->rmac, macaddr, ETH_ALEN) != 0) &&
178 !rn_affected)
179 continue;
180
4e802e66
DS
181 if (pi->extra)
182 num_labels = pi->extra->num_labels;
183 if (num_labels)
184 label_pnt = &pi->extra->label[0];
185
186 prd.family = AF_UNSPEC;
187 prd.prefixlen = 64;
188 memcpy(&prd.val, &prn->p.u.val, 8);
189
c869b3f8
CS
190 if (CHECK_FLAG(pi->flags, BGP_PATH_REMOVED)) {
191 if (bgp_debug_update(peer, &rn->p, NULL, 1)) {
192 char pfx_buf[BGP_PRD_PATH_STRLEN];
193
194 bgp_debug_rdpfxpath2str(
195 AFI_L2VPN, SAFI_EVPN, &prd,
196 &rn->p, label_pnt, num_labels,
197 pi->addpath_rx_id ? 1 : 0,
198 pi->addpath_rx_id, pfx_buf,
199 sizeof(pfx_buf));
200 zlog_debug(
201 "%s skip update of %s marked as removed",
202 peer->host, pfx_buf);
203 }
204 continue;
205 }
206
4e802e66
DS
207 memcpy(&evpn, &pi->attr->evpn_overlay, sizeof(evpn));
208 int32_t ret = bgp_update(peer, &rn->p,
209 pi->addpath_rx_id,
210 pi->attr, AFI_L2VPN, SAFI_EVPN,
211 ZEBRA_ROUTE_BGP,
212 BGP_ROUTE_NORMAL, &prd,
213 label_pnt, num_labels,
214 1, &evpn);
215
216 if (ret < 0)
217 bgp_unlock_node(rn);
218 }
219 }
220}
221
78869ebf 222static void bgp_mac_rescan_evpn_table(struct bgp *bgp, struct ethaddr *macaddr)
6a69ac51
DS
223{
224 struct listnode *node;
4e802e66
DS
225 struct peer *peer;
226 safi_t safi;
227 afi_t afi;
228
229 afi = AFI_L2VPN;
230 safi = SAFI_EVPN;
231 for (ALL_LIST_ELEMENTS_RO(bgp->peer, node, peer)) {
232
233 if (CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP))
234 continue;
235
236 if (peer->status != Established)
237 continue;
238
239 if (CHECK_FLAG(peer->af_flags[afi][safi],
240 PEER_FLAG_SOFT_RECONFIG)) {
241 if (bgp_debug_update(peer, NULL, NULL, 1))
242 zlog_debug("Processing EVPN MAC interface change on peer %s (inbound, soft-reconfig)",
243 peer->host);
244
245 bgp_soft_reconfig_in(peer, afi, safi);
246 } else {
247 struct bgp_table *table = bgp->rib[afi][safi];
248
249 if (bgp_debug_update(peer, NULL, NULL, 1))
250 zlog_debug("Processing EVPN MAC interface change on peer %s",
251 peer->host);
78869ebf 252 bgp_process_mac_rescan_table(bgp, peer, table, macaddr);
4e802e66
DS
253 }
254 }
255}
256
78869ebf 257static void bgp_mac_rescan_all_evpn_tables(struct ethaddr *macaddr)
4e802e66
DS
258{
259 struct listnode *node;
260 struct bgp *bgp;
261
262 for (ALL_LIST_ELEMENTS_RO(bm->bgp, node, bgp)) {
263 struct bgp_table *table = bgp->rib[AFI_L2VPN][SAFI_EVPN];
264
265 if (table)
78869ebf 266 bgp_mac_rescan_evpn_table(bgp, macaddr);
4e802e66
DS
267 }
268}
269
78869ebf
DS
270static void bgp_mac_remove_ifp_internal(struct bgp_self_mac *bsm, char *ifname,
271 struct ethaddr *macaddr)
4e802e66
DS
272{
273 struct listnode *node = NULL;
6a69ac51
DS
274 char *name;
275
276 for (ALL_LIST_ELEMENTS_RO(bsm->ifp_list, node, name)) {
277 if (strcmp(name, ifname) == 0)
278 break;
279 }
280
281 if (node) {
282 list_delete_node(bsm->ifp_list, node);
283 XFREE(MTYPE_BSM_STRING, name);
284 }
285
286 if (bsm->ifp_list->count == 0) {
c86e8d64
DS
287 struct ethaddr mac = *macaddr;
288
6a69ac51
DS
289 hash_release(bm->self_mac_hash, bsm);
290 list_delete(&bsm->ifp_list);
291 XFREE(MTYPE_BSM, bsm);
292
c86e8d64 293 bgp_mac_rescan_all_evpn_tables(&mac);
6a69ac51
DS
294 }
295}
296
297void bgp_mac_add_mac_entry(struct interface *ifp)
298{
299 struct bgp_self_mac lookup;
300 struct bgp_self_mac *bsm;
301 struct bgp_self_mac *old_bsm;
302 char *ifname;
303
304 memcpy(&lookup.macaddr, &ifp->hw_addr, ETH_ALEN);
305 bsm = hash_get(bm->self_mac_hash, &lookup, bgp_mac_hash_alloc);
306
307 /*
308 * Does this happen to be a move
309 */
310 old_bsm = bgp_mac_find_interface_name(ifp->name);
311 ifname = XSTRDUP(MTYPE_BSM_STRING, ifp->name);
312
313 if (bsm->ifp_list->count == 0) {
314
315 listnode_add(bsm->ifp_list, ifname);
316 if (old_bsm)
78869ebf
DS
317 bgp_mac_remove_ifp_internal(old_bsm, ifname,
318 &old_bsm->macaddr);
6a69ac51
DS
319 } else {
320 /*
321 * If old mac address is the same as the new,
322 * then there is nothing to do here
323 */
308000ee
DS
324 if (old_bsm == bsm) {
325 XFREE(MTYPE_BSM_STRING, ifname);
6a69ac51 326 return;
308000ee 327 }
6a69ac51
DS
328
329 if (old_bsm)
78869ebf
DS
330 bgp_mac_remove_ifp_internal(old_bsm, ifp->name,
331 &old_bsm->macaddr);
6a69ac51
DS
332
333 listnode_add(bsm->ifp_list, ifname);
334 }
335
78869ebf 336 bgp_mac_rescan_all_evpn_tables(&bsm->macaddr);
6a69ac51
DS
337}
338
339void bgp_mac_del_mac_entry(struct interface *ifp)
340{
341 struct bgp_self_mac lookup;
342 struct bgp_self_mac *bsm;
343
344 memcpy(&lookup.macaddr, &ifp->hw_addr, ETH_ALEN);
345 bsm = hash_lookup(bm->self_mac_hash, &lookup);
346 if (!bsm)
347 return;
348
349 /*
350 * Write code to allow old mac address to no-longer
351 * win if we happen to have received it from a peer.
352 */
78869ebf 353 bgp_mac_remove_ifp_internal(bsm, ifp->name, &bsm->macaddr);
6a69ac51
DS
354}
355
eee353c5
CS
356/* This API checks MAC address against any of local
357 * assigned (SVIs) MAC address.
358 * An example: router-mac attribute in any of evpn update
359 * requires to compare against local mac.
360 */
361bool bgp_mac_exist(struct ethaddr *mac)
4e802e66 362{
4e802e66
DS
363 struct bgp_self_mac lookup;
364 struct bgp_self_mac *bsm;
eee353c5
CS
365 static uint8_t tmp [ETHER_ADDR_STRLEN] = {0};
366
367 if (memcmp(mac, &tmp, ETH_ALEN) == 0)
368 return false;
369
370 memcpy(&lookup.macaddr, mac, ETH_ALEN);
371 bsm = hash_lookup(bm->self_mac_hash, &lookup);
372 if (!bsm)
373 return false;
374
375 return true;
376}
377
378/* This API checks EVPN type-2 prefix and comapares
379 * mac against any of local assigned (SVIs) MAC
380 * address.
381 */
382bool bgp_mac_entry_exists(struct prefix *p)
383{
384 struct prefix_evpn *pevpn = (struct prefix_evpn *)p;
4e802e66
DS
385
386 if (pevpn->family != AF_EVPN)
387 return false;
388
389 if (pevpn->prefix.route_type != BGP_EVPN_MAC_IP_ROUTE)
390 return false;
391
eee353c5 392 return bgp_mac_exist(&p->u.prefix_evpn.macip_addr.mac);
4e802e66
DS
393
394 return true;
395}
396
e3b78da8 397static void bgp_mac_show_mac_entry(struct hash_bucket *bucket, void *arg)
48ecf8f5
DS
398{
399 struct vty *vty = arg;
e3b78da8 400 struct bgp_self_mac *bsm = bucket->data;
48ecf8f5
DS
401 struct listnode *node;
402 char *name;
403 char buf_mac[ETHER_ADDR_STRLEN];
404
405 vty_out(vty, "Mac Address: %s ",
406 prefix_mac2str(&bsm->macaddr, buf_mac, sizeof(buf_mac)));
407
408 for (ALL_LIST_ELEMENTS_RO(bsm->ifp_list, node, name))
409 vty_out(vty, "%s ", name);
410
411 vty_out(vty, "\n");
412}
413
414void bgp_mac_dump_table(struct vty *vty)
415{
416 hash_iterate(bm->self_mac_hash, bgp_mac_show_mac_entry, vty);
417}