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