]> git.proxmox.com Git - mirror_frr.git/blob - pbrd/pbr_nht.c
bgpd: fix unaligned access to addpath id
[mirror_frr.git] / pbrd / pbr_nht.c
1 /*
2 * PBR-nht Code
3 * Copyright (C) 2018 Cumulus Networks, Inc.
4 * Donald Sharp
5 *
6 * FRR 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
8 * Free Software Foundation; either version 2, or (at your option) any
9 * later version.
10 *
11 * FRR is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for 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 <log.h>
23 #include <nexthop.h>
24 #include "nexthop_group.h"
25 #include "nexthop_group_private.h"
26 #include <hash.h>
27 #include <jhash.h>
28 #include <vty.h>
29 #include <zclient.h>
30 #include <debug.h>
31
32 #include "pbrd/pbr_nht.h"
33 #include "pbrd/pbr_map.h"
34 #include "pbrd/pbr_zebra.h"
35 #include "pbrd/pbr_memory.h"
36 #include "pbrd/pbr_debug.h"
37
38 DEFINE_MTYPE_STATIC(PBRD, PBR_NHG, "PBR Nexthop Groups")
39
40 static struct hash *pbr_nhg_hash;
41 static struct hash *pbr_nhrc_hash;
42
43 static uint32_t pbr_nhg_low_table;
44 static uint32_t pbr_nhg_high_table;
45 static uint32_t pbr_nhg_low_rule;
46 static uint32_t pbr_nhg_high_rule;
47 static bool nhg_tableid[65535];
48
49 static void pbr_nht_install_nexthop_group(struct pbr_nexthop_group_cache *pnhgc,
50 struct nexthop_group nhg);
51 static void
52 pbr_nht_uninstall_nexthop_group(struct pbr_nexthop_group_cache *pnhgc,
53 struct nexthop_group nhg,
54 enum nexthop_types_t nh_type);
55
56 /*
57 * Nexthop refcount.
58 */
59 struct nhrc {
60 struct nexthop nexthop;
61 unsigned int refcount;
62 };
63
64 /* Hash functions for pbr_nhrc_hash ---------------------------------------- */
65
66 static void *pbr_nhrc_hash_alloc(void *p)
67 {
68 struct nhrc *nhrc = XCALLOC(MTYPE_PBR_NHG, sizeof(struct nhrc));
69 nhrc->nexthop = *(struct nexthop *)p;
70 nhrc->nexthop.next = NULL;
71 nhrc->nexthop.prev = NULL;
72 return nhrc;
73 }
74
75 static bool pbr_nhrc_hash_equal(const void *arg1, const void *arg2)
76 {
77 const struct nexthop *nh1, *nh2;
78
79 nh1 = arg1;
80 nh2 = arg2;
81
82 return nexthop_same(nh1, nh2);
83 }
84
85 /* ------------------------------------------------------------------------- */
86
87 static void *pbr_nh_alloc(void *p)
88 {
89 struct pbr_nexthop_cache *new;
90 struct pbr_nexthop_cache *pnhc = (struct pbr_nexthop_cache *)p;
91 struct nhrc *nhrc;
92
93 new = XCALLOC(MTYPE_PBR_NHG, sizeof(*new));
94 nhrc = hash_get(pbr_nhrc_hash, pnhc->nexthop, pbr_nhrc_hash_alloc);
95 new->nexthop = &nhrc->nexthop;
96
97 /* Decremented again in pbr_nh_delete */
98 ++nhrc->refcount;
99
100 DEBUGD(&pbr_dbg_nht, "%s: Sending nexthop to Zebra",
101 __PRETTY_FUNCTION__);
102
103 pbr_send_rnh(new->nexthop, true);
104
105 new->valid = false;
106 return new;
107 }
108
109 static void pbr_nh_delete(struct pbr_nexthop_cache **pnhc)
110 {
111 struct nhrc *nhrc;
112
113 nhrc = hash_lookup(pbr_nhrc_hash, (*pnhc)->nexthop);
114
115 if (nhrc)
116 --nhrc->refcount;
117 if (!nhrc || nhrc->refcount == 0) {
118 DEBUGD(&pbr_dbg_nht, "%s: Removing nexthop from Zebra",
119 __PRETTY_FUNCTION__);
120 pbr_send_rnh((*pnhc)->nexthop, false);
121 }
122 if (nhrc && nhrc->refcount == 0) {
123 hash_release(pbr_nhrc_hash, nhrc);
124 XFREE(MTYPE_PBR_NHG, nhrc);
125 }
126
127 XFREE(MTYPE_PBR_NHG, *pnhc);
128 }
129
130 static void pbr_nh_delete_iterate(struct hash_bucket *b, void *p)
131 {
132 pbr_nh_delete((struct pbr_nexthop_cache **)&b->data);
133 }
134
135 static uint32_t pbr_nh_hash_key(const void *arg)
136 {
137 uint32_t key;
138 const struct pbr_nexthop_cache *pbrnc = arg;
139
140 key = nexthop_hash(pbrnc->nexthop);
141
142 return key;
143 }
144
145 static bool pbr_nh_hash_equal(const void *arg1, const void *arg2)
146 {
147 const struct pbr_nexthop_cache *pbrnc1 =
148 (const struct pbr_nexthop_cache *)arg1;
149 const struct pbr_nexthop_cache *pbrnc2 =
150 (const struct pbr_nexthop_cache *)arg2;
151
152 if (pbrnc1->nexthop->vrf_id != pbrnc2->nexthop->vrf_id)
153 return false;
154
155 if (pbrnc1->nexthop->ifindex != pbrnc2->nexthop->ifindex)
156 return false;
157
158 if (pbrnc1->nexthop->type != pbrnc2->nexthop->type)
159 return false;
160
161 switch (pbrnc1->nexthop->type) {
162 case NEXTHOP_TYPE_IFINDEX:
163 return pbrnc1->nexthop->ifindex == pbrnc2->nexthop->ifindex;
164 case NEXTHOP_TYPE_IPV4_IFINDEX:
165 case NEXTHOP_TYPE_IPV4:
166 return pbrnc1->nexthop->gate.ipv4.s_addr
167 == pbrnc2->nexthop->gate.ipv4.s_addr;
168 case NEXTHOP_TYPE_IPV6_IFINDEX:
169 case NEXTHOP_TYPE_IPV6:
170 return !memcmp(&pbrnc1->nexthop->gate.ipv6,
171 &pbrnc2->nexthop->gate.ipv6, 16);
172 case NEXTHOP_TYPE_BLACKHOLE:
173 return pbrnc1->nexthop->bh_type == pbrnc2->nexthop->bh_type;
174 }
175
176 /*
177 * We should not get here
178 */
179 return false;
180 }
181
182 static void pbr_nhgc_delete(struct pbr_nexthop_group_cache *p)
183 {
184 hash_iterate(p->nhh, pbr_nh_delete_iterate, NULL);
185 hash_free(p->nhh);
186 XFREE(MTYPE_PBR_NHG, p);
187 }
188
189 static void *pbr_nhgc_alloc(void *p)
190 {
191 struct pbr_nexthop_group_cache *new;
192 struct pbr_nexthop_group_cache *pnhgc =
193 (struct pbr_nexthop_group_cache *)p;
194
195 new = XCALLOC(MTYPE_PBR_NHG, sizeof(*new));
196
197 strlcpy(new->name, pnhgc->name, sizeof(pnhgc->name));
198 new->table_id = pbr_nht_get_next_tableid(false);
199
200 DEBUGD(&pbr_dbg_nht, "%s: NHT: %s assigned Table ID: %u",
201 __PRETTY_FUNCTION__, new->name, new->table_id);
202
203 new->nhh = hash_create_size(8, pbr_nh_hash_key, pbr_nh_hash_equal,
204 "PBR NH Cache Hash");
205 return new;
206 }
207
208
209 void pbr_nhgroup_add_cb(const char *name)
210 {
211 struct pbr_nexthop_group_cache *pnhgc;
212 struct nexthop_group_cmd *nhgc;
213
214 nhgc = nhgc_find(name);
215
216 if (!nhgc) {
217 DEBUGD(&pbr_dbg_nht, "%s: Could not find nhgc with name: %s\n",
218 __PRETTY_FUNCTION__, name);
219 return;
220 }
221
222 pnhgc = pbr_nht_add_group(name);
223
224 if (!pnhgc)
225 return;
226
227 DEBUGD(&pbr_dbg_nht, "%s: Added nexthop-group %s", __PRETTY_FUNCTION__,
228 name);
229
230 pbr_map_check_nh_group_change(name);
231 }
232
233 void pbr_nhgroup_add_nexthop_cb(const struct nexthop_group_cmd *nhgc,
234 const struct nexthop *nhop)
235 {
236 char debugstr[256];
237 struct pbr_nexthop_group_cache pnhgc_find = {};
238 struct pbr_nexthop_group_cache *pnhgc;
239 struct pbr_nexthop_cache pnhc_find = {};
240 struct pbr_nexthop_cache *pnhc;
241
242 if (!pbr_nht_get_next_tableid(true)) {
243 zlog_warn(
244 "%s: Exhausted all table identifiers; cannot create nexthop-group cache for nexthop-group '%s'",
245 __PRETTY_FUNCTION__, nhgc->name);
246 return;
247 }
248
249 /* find pnhgc by name */
250 strlcpy(pnhgc_find.name, nhgc->name, sizeof(pnhgc_find.name));
251 pnhgc = hash_get(pbr_nhg_hash, &pnhgc_find, pbr_nhgc_alloc);
252
253 /* create & insert new pnhc into pnhgc->nhh */
254 pnhc_find.nexthop = (struct nexthop *)nhop;
255 pnhc = hash_get(pnhgc->nhh, &pnhc_find, pbr_nh_alloc);
256 pnhc_find.nexthop = NULL;
257
258 /* set parent pnhgc */
259 pnhc->parent = pnhgc;
260
261 if (DEBUG_MODE_CHECK(&pbr_dbg_nht, DEBUG_MODE_ALL)) {
262 nexthop2str(nhop, debugstr, sizeof(debugstr));
263 DEBUGD(&pbr_dbg_nht, "%s: Added %s to nexthop-group %s",
264 __PRETTY_FUNCTION__, debugstr, nhgc->name);
265 }
266
267 pbr_nht_install_nexthop_group(pnhgc, nhgc->nhg);
268 pbr_map_check_nh_group_change(nhgc->name);
269
270 if (nhop->type == NEXTHOP_TYPE_IFINDEX) {
271 struct interface *ifp;
272
273 ifp = if_lookup_by_index(nhop->ifindex, nhop->vrf_id);
274 if (ifp)
275 pbr_nht_nexthop_interface_update(ifp);
276 }
277 }
278
279 void pbr_nhgroup_del_nexthop_cb(const struct nexthop_group_cmd *nhgc,
280 const struct nexthop *nhop)
281 {
282 char debugstr[256];
283 struct pbr_nexthop_group_cache pnhgc_find = {};
284 struct pbr_nexthop_group_cache *pnhgc;
285 struct pbr_nexthop_cache pnhc_find = {};
286 struct pbr_nexthop_cache *pnhc;
287 enum nexthop_types_t nh_type = nhop->type;
288
289 /* find pnhgc by name */
290 strlcpy(pnhgc_find.name, nhgc->name, sizeof(pnhgc_find.name));
291 pnhgc = hash_lookup(pbr_nhg_hash, &pnhgc_find);
292
293 /* delete pnhc from pnhgc->nhh */
294 pnhc_find.nexthop = (struct nexthop *)nhop;
295 pnhc = hash_release(pnhgc->nhh, &pnhc_find);
296
297 /* delete pnhc */
298 pbr_nh_delete(&pnhc);
299
300 if (DEBUG_MODE_CHECK(&pbr_dbg_nht, DEBUG_MODE_ALL)) {
301 nexthop2str(nhop, debugstr, sizeof(debugstr));
302 DEBUGD(&pbr_dbg_nht, "%s: Removed %s from nexthop-group %s",
303 __PRETTY_FUNCTION__, debugstr, nhgc->name);
304 }
305
306 if (pnhgc->nhh->count)
307 pbr_nht_install_nexthop_group(pnhgc, nhgc->nhg);
308 else
309 pbr_nht_uninstall_nexthop_group(pnhgc, nhgc->nhg, nh_type);
310
311 pbr_map_check_nh_group_change(nhgc->name);
312 }
313
314 void pbr_nhgroup_delete_cb(const char *name)
315 {
316 DEBUGD(&pbr_dbg_nht, "%s: Removed nexthop-group %s",
317 __PRETTY_FUNCTION__, name);
318
319 /* delete group from all pbrms's */
320 pbr_nht_delete_group(name);
321
322 pbr_map_check_nh_group_change(name);
323 }
324
325 #if 0
326 static struct pbr_nexthop_cache *pbr_nht_lookup_nexthop(struct nexthop *nexthop)
327 {
328 return NULL;
329 }
330 #endif
331
332 static void pbr_nht_find_nhg_from_table_install(struct hash_bucket *b,
333 void *data)
334 {
335 struct pbr_nexthop_group_cache *pnhgc =
336 (struct pbr_nexthop_group_cache *)b->data;
337 uint32_t *table_id = (uint32_t *)data;
338
339 if (pnhgc->table_id == *table_id) {
340 DEBUGD(&pbr_dbg_nht, "%s: Table ID (%u) matches %s",
341 __PRETTY_FUNCTION__, *table_id, pnhgc->name);
342
343 /*
344 * If the table has been re-handled by zebra
345 * and we are already installed no need to do
346 * anything here.
347 */
348 if (!pnhgc->installed) {
349 pnhgc->installed = true;
350 pbr_map_schedule_policy_from_nhg(pnhgc->name);
351 }
352 }
353 }
354
355 void pbr_nht_route_installed_for_table(uint32_t table_id)
356 {
357 hash_iterate(pbr_nhg_hash, pbr_nht_find_nhg_from_table_install,
358 &table_id);
359 }
360
361 static void pbr_nht_find_nhg_from_table_remove(struct hash_bucket *b,
362 void *data)
363 {
364 ;
365 }
366
367 void pbr_nht_route_removed_for_table(uint32_t table_id)
368 {
369 hash_iterate(pbr_nhg_hash, pbr_nht_find_nhg_from_table_remove,
370 &table_id);
371 }
372
373 /*
374 * Loop through all nexthops in a nexthop group to check that they are all the
375 * same. If they are not all the same, log this peculiarity.
376 *
377 * nhg
378 * The nexthop group to check
379 *
380 * Returns:
381 * - AFI of last nexthop in the group
382 * - AFI_MAX on error
383 */
384 static afi_t pbr_nht_which_afi(struct nexthop_group nhg,
385 enum nexthop_types_t nh_type)
386 {
387 struct nexthop *nexthop;
388 afi_t install_afi = AFI_MAX;
389 bool v6, v4, bh;
390
391 if (nh_type) {
392 switch (nh_type) {
393 case NEXTHOP_TYPE_IPV4:
394 case NEXTHOP_TYPE_IPV4_IFINDEX:
395 return AFI_IP;
396 case NEXTHOP_TYPE_IPV6:
397 case NEXTHOP_TYPE_IPV6_IFINDEX:
398 return AFI_IP6;
399 case NEXTHOP_TYPE_IFINDEX:
400 case NEXTHOP_TYPE_BLACKHOLE:
401 return AFI_MAX;
402 }
403 }
404
405 v6 = v4 = bh = false;
406
407 for (ALL_NEXTHOPS(nhg, nexthop)) {
408 nh_type = nexthop->type;
409
410 switch (nh_type) {
411 case NEXTHOP_TYPE_IFINDEX:
412 break;
413 case NEXTHOP_TYPE_IPV4:
414 case NEXTHOP_TYPE_IPV4_IFINDEX:
415 v6 = true;
416 install_afi = AFI_IP;
417 break;
418 case NEXTHOP_TYPE_IPV6:
419 case NEXTHOP_TYPE_IPV6_IFINDEX:
420 v4 = true;
421 install_afi = AFI_IP6;
422 break;
423 case NEXTHOP_TYPE_BLACKHOLE:
424 bh = true;
425 break;
426 }
427 }
428
429 /* Interface and/or blackhole nexthops only. */
430 if (!v4 && !v6)
431 install_afi = AFI_MAX;
432
433 if (!bh && v6 && v4)
434 DEBUGD(&pbr_dbg_nht,
435 "%s: Saw both V6 and V4 nexthops...using %s",
436 __PRETTY_FUNCTION__, afi2str(install_afi));
437 if (bh && (v6 || v4))
438 DEBUGD(&pbr_dbg_nht,
439 "%s: Saw blackhole nexthop(s) with %s%s%s nexthop(s), using AFI_MAX.",
440 __PRETTY_FUNCTION__, v4 ? "v4" : "",
441 (v4 && v6) ? " and " : "", v6 ? "v6" : "");
442
443 return install_afi;
444 }
445
446 static void pbr_nht_install_nexthop_group(struct pbr_nexthop_group_cache *pnhgc,
447 struct nexthop_group nhg)
448 {
449 afi_t install_afi;
450 enum nexthop_types_t nh_type = 0;
451
452 install_afi = pbr_nht_which_afi(nhg, nh_type);
453
454 route_add(pnhgc, nhg, install_afi);
455 }
456
457 static void
458 pbr_nht_uninstall_nexthop_group(struct pbr_nexthop_group_cache *pnhgc,
459 struct nexthop_group nhg,
460 enum nexthop_types_t nh_type)
461 {
462 afi_t install_afi;
463
464 install_afi = pbr_nht_which_afi(nhg, nh_type);
465
466 pnhgc->installed = false;
467 pnhgc->valid = false;
468 route_delete(pnhgc, install_afi);
469 }
470
471 void pbr_nht_change_group(const char *name)
472 {
473 struct nexthop_group_cmd *nhgc;
474 struct pbr_nexthop_group_cache *pnhgc;
475 struct pbr_nexthop_group_cache find;
476 struct nexthop *nhop;
477
478 nhgc = nhgc_find(name);
479 if (!nhgc)
480 return;
481
482 memset(&find, 0, sizeof(find));
483 snprintf(find.name, sizeof(find.name), "%s", name);
484 pnhgc = hash_lookup(pbr_nhg_hash, &find);
485
486 if (!pnhgc) {
487 DEBUGD(&pbr_dbg_nht,
488 "%s: Could not find nexthop-group cache w/ name '%s'",
489 __PRETTY_FUNCTION__, name);
490 return;
491 }
492
493 for (ALL_NEXTHOPS(nhgc->nhg, nhop)) {
494 struct pbr_nexthop_cache lookup;
495 struct pbr_nexthop_cache *pnhc;
496
497 lookup.nexthop = nhop;
498 pnhc = hash_lookup(pnhgc->nhh, &lookup);
499 if (!pnhc) {
500 pnhc = hash_get(pnhgc->nhh, &lookup, pbr_nh_alloc);
501 pnhc->parent = pnhgc;
502 }
503 }
504 pbr_nht_install_nexthop_group(pnhgc, nhgc->nhg);
505 }
506
507 char *pbr_nht_nexthop_make_name(char *name, size_t l,
508 uint32_t seqno, char *buffer)
509 {
510 snprintf(buffer, l, "%s%u", name, seqno);
511 return buffer;
512 }
513
514 void pbr_nht_add_individual_nexthop(struct pbr_map_sequence *pbrms)
515 {
516 struct pbr_nexthop_group_cache *pnhgc;
517 struct pbr_nexthop_group_cache find;
518 struct pbr_nexthop_cache *pnhc;
519 struct pbr_nexthop_cache lookup;
520
521 memset(&find, 0, sizeof(find));
522 pbr_nht_nexthop_make_name(pbrms->parent->name, PBR_NHC_NAMELEN,
523 pbrms->seqno, find.name);
524
525 if (!pbr_nht_get_next_tableid(true)) {
526 zlog_warn(
527 "%s: Exhausted all table identifiers; cannot create nexthop-group cache for nexthop-group '%s'",
528 __PRETTY_FUNCTION__, find.name);
529 return;
530 }
531
532 if (!pbrms->internal_nhg_name)
533 pbrms->internal_nhg_name = XSTRDUP(MTYPE_TMP, find.name);
534
535 pnhgc = hash_get(pbr_nhg_hash, &find, pbr_nhgc_alloc);
536
537 lookup.nexthop = pbrms->nhg->nexthop;
538 pnhc = hash_get(pnhgc->nhh, &lookup, pbr_nh_alloc);
539 pnhc->parent = pnhgc;
540 pbr_nht_install_nexthop_group(pnhgc, *pbrms->nhg);
541 }
542
543 void pbr_nht_delete_individual_nexthop(struct pbr_map_sequence *pbrms)
544 {
545 struct pbr_nexthop_group_cache *pnhgc;
546 struct pbr_nexthop_group_cache find;
547 struct pbr_nexthop_cache *pnhc;
548 struct pbr_nexthop_cache lup;
549 struct pbr_map *pbrm = pbrms->parent;
550 struct listnode *node;
551 struct pbr_map_interface *pmi;
552 struct nexthop *nh;
553 enum nexthop_types_t nh_type = 0;
554
555 if (pbrm->valid && pbrms->nhs_installed && pbrm->incoming->count) {
556 for (ALL_LIST_ELEMENTS_RO(pbrm->incoming, node, pmi))
557 pbr_send_pbr_map(pbrms, pmi, false);
558 }
559
560 pbrm->valid = false;
561 pbrms->nhs_installed = false;
562 pbrms->reason |= PBR_MAP_INVALID_NO_NEXTHOPS;
563
564 memset(&find, 0, sizeof(find));
565 snprintf(find.name, sizeof(find.name), "%s", pbrms->internal_nhg_name);
566 pnhgc = hash_lookup(pbr_nhg_hash, &find);
567
568 nh = pbrms->nhg->nexthop;
569 nh_type = nh->type;
570 lup.nexthop = nh;
571 pnhc = hash_lookup(pnhgc->nhh, &lup);
572 pnhc->parent = NULL;
573 hash_release(pnhgc->nhh, pnhc);
574 pbr_nh_delete(&pnhc);
575 pbr_nht_uninstall_nexthop_group(pnhgc, *pbrms->nhg, nh_type);
576
577 hash_release(pbr_nhg_hash, pnhgc);
578
579 _nexthop_del(pbrms->nhg, nh);
580 nexthop_free(nh);
581 nexthop_group_delete(&pbrms->nhg);
582 XFREE(MTYPE_TMP, pbrms->internal_nhg_name);
583 }
584
585 struct pbr_nexthop_group_cache *pbr_nht_add_group(const char *name)
586 {
587 struct nexthop *nhop;
588 struct nexthop_group_cmd *nhgc;
589 struct pbr_nexthop_group_cache *pnhgc;
590 struct pbr_nexthop_group_cache lookup;
591
592 if (!pbr_nht_get_next_tableid(true)) {
593 zlog_warn(
594 "%s: Exhausted all table identifiers; cannot create nexthop-group cache for nexthop-group '%s'",
595 __PRETTY_FUNCTION__, name);
596 return NULL;
597 }
598
599 nhgc = nhgc_find(name);
600
601 if (!nhgc) {
602 DEBUGD(&pbr_dbg_nht, "%s: Could not find nhgc with name: %s\n",
603 __PRETTY_FUNCTION__, name);
604 return NULL;
605 }
606
607 snprintf(lookup.name, sizeof(lookup.name), "%s", name);
608 pnhgc = hash_get(pbr_nhg_hash, &lookup, pbr_nhgc_alloc);
609 DEBUGD(&pbr_dbg_nht, "%s: Retrieved NHGC @ %p", __PRETTY_FUNCTION__,
610 pnhgc);
611
612 for (ALL_NEXTHOPS(nhgc->nhg, nhop)) {
613 struct pbr_nexthop_cache lookupc;
614 struct pbr_nexthop_cache *pnhc;
615
616 lookupc.nexthop = nhop;
617 pnhc = hash_lookup(pnhgc->nhh, &lookupc);
618 if (!pnhc) {
619 pnhc = hash_get(pnhgc->nhh, &lookupc, pbr_nh_alloc);
620 pnhc->parent = pnhgc;
621 }
622 }
623
624 return pnhgc;
625 }
626
627 void pbr_nht_delete_group(const char *name)
628 {
629 struct pbr_map_sequence *pbrms;
630 struct listnode *snode;
631 struct pbr_map *pbrm;
632 struct pbr_nexthop_group_cache pnhgc_find;
633 struct pbr_nexthop_group_cache *pnhgc;
634
635 RB_FOREACH (pbrm, pbr_map_entry_head, &pbr_maps) {
636 for (ALL_LIST_ELEMENTS_RO(pbrm->seqnumbers, snode, pbrms)) {
637 if (pbrms->nhgrp_name
638 && strmatch(pbrms->nhgrp_name, name)) {
639 pbrms->reason |= PBR_MAP_INVALID_NO_NEXTHOPS;
640 nexthop_group_delete(&pbrms->nhg);
641 pbrms->nhg = NULL;
642 pbrms->internal_nhg_name = NULL;
643 pbrm->valid = false;
644 }
645 }
646 }
647
648 strlcpy(pnhgc_find.name, name, sizeof(pnhgc_find.name));
649 pnhgc = hash_release(pbr_nhg_hash, &pnhgc_find);
650 pbr_nhgc_delete(pnhgc);
651 }
652
653 bool pbr_nht_nexthop_valid(struct nexthop_group *nhg)
654 {
655 DEBUGD(&pbr_dbg_nht, "%s: %p", __PRETTY_FUNCTION__, nhg);
656 return true;
657 }
658
659 bool pbr_nht_nexthop_group_valid(const char *name)
660 {
661 struct pbr_nexthop_group_cache *pnhgc;
662 struct pbr_nexthop_group_cache lookup;
663
664 DEBUGD(&pbr_dbg_nht, "%s: %s", __PRETTY_FUNCTION__, name);
665
666 snprintf(lookup.name, sizeof(lookup.name), "%s", name);
667 pnhgc = hash_get(pbr_nhg_hash, &lookup, NULL);
668 if (!pnhgc)
669 return false;
670 DEBUGD(&pbr_dbg_nht, "%s: \t%d %d", __PRETTY_FUNCTION__, pnhgc->valid,
671 pnhgc->installed);
672 if (pnhgc->valid && pnhgc->installed)
673 return true;
674
675 return false;
676 }
677
678 struct pbr_nht_individual {
679 struct zapi_route *nhr;
680 struct interface *ifp;
681
682 uint32_t valid;
683 };
684
685 static void pbr_nht_individual_nexthop_update_lookup(struct hash_bucket *b,
686 void *data)
687 {
688 struct pbr_nexthop_cache *pnhc = b->data;
689 struct pbr_nht_individual *pnhi = data;
690 char buf[PREFIX_STRLEN];
691 bool old_valid;
692
693 old_valid = pnhc->valid;
694
695 switch (pnhi->nhr->prefix.family) {
696 case AF_INET:
697 if (pnhc->nexthop->gate.ipv4.s_addr
698 == pnhi->nhr->prefix.u.prefix4.s_addr)
699 pnhc->valid = !!pnhi->nhr->nexthop_num;
700 break;
701 case AF_INET6:
702 if (memcmp(&pnhc->nexthop->gate.ipv6,
703 &pnhi->nhr->prefix.u.prefix6, 16)
704 == 0)
705 pnhc->valid = !!pnhi->nhr->nexthop_num;
706 break;
707 }
708
709 DEBUGD(&pbr_dbg_nht, "\tFound %s: old: %d new: %d",
710 prefix2str(&pnhi->nhr->prefix, buf, sizeof(buf)), old_valid,
711 pnhc->valid);
712
713 if (pnhc->valid)
714 pnhi->valid += 1;
715 }
716
717 static void pbr_nexthop_group_cache_iterate_to_group(struct hash_bucket *b,
718 void *data)
719 {
720 struct pbr_nexthop_cache *pnhc = b->data;
721 struct nexthop_group *nhg = data;
722 struct nexthop *nh = NULL;
723
724 copy_nexthops(&nh, pnhc->nexthop, NULL);
725
726 _nexthop_add(&nhg->nexthop, nh);
727 }
728
729 static void
730 pbr_nexthop_group_cache_to_nexthop_group(struct nexthop_group *nhg,
731 struct pbr_nexthop_group_cache *pnhgc)
732 {
733 hash_iterate(pnhgc->nhh, pbr_nexthop_group_cache_iterate_to_group, nhg);
734 }
735
736 static void pbr_nht_nexthop_update_lookup(struct hash_bucket *b, void *data)
737 {
738 struct pbr_nexthop_group_cache *pnhgc = b->data;
739 struct pbr_nht_individual pnhi;
740 struct nexthop_group nhg = {};
741 bool old_valid;
742
743 old_valid = pnhgc->valid;
744
745 pnhi.nhr = (struct zapi_route *)data;
746 pnhi.valid = 0;
747 hash_iterate(pnhgc->nhh, pbr_nht_individual_nexthop_update_lookup,
748 &pnhi);
749
750 /*
751 * If any of the specified nexthops are valid we are valid
752 */
753 pnhgc->valid = !!pnhi.valid;
754
755 if (pnhgc->valid) {
756 pbr_nexthop_group_cache_to_nexthop_group(&nhg, pnhgc);
757 pbr_nht_install_nexthop_group(pnhgc, nhg);
758 /* Don't need copied nexthops anymore */
759 nexthops_free(nhg.nexthop);
760 }
761
762 if (old_valid != pnhgc->valid)
763 pbr_map_check_nh_group_change(pnhgc->name);
764 }
765
766 void pbr_nht_nexthop_update(struct zapi_route *nhr)
767 {
768 hash_iterate(pbr_nhg_hash, pbr_nht_nexthop_update_lookup, nhr);
769 }
770
771 static void
772 pbr_nht_individual_nexthop_interface_update_lookup(struct hash_backet *b,
773 void *data)
774 {
775 struct pbr_nexthop_cache *pnhc = b->data;
776 struct pbr_nht_individual *pnhi = data;
777 bool old_valid;
778
779 old_valid = pnhc->valid;
780
781 if (pnhc->nexthop->type == NEXTHOP_TYPE_IFINDEX
782 && pnhc->nexthop->ifindex == pnhi->ifp->ifindex)
783 pnhc->valid = !!if_is_up(pnhi->ifp);
784
785 DEBUGD(&pbr_dbg_nht, "\tFound %s: old: %d new: %d", pnhi->ifp->name,
786 old_valid, pnhc->valid);
787
788 if (pnhc->valid)
789 pnhi->valid += 1;
790 }
791
792 static void pbr_nht_nexthop_interface_update_lookup(struct hash_backet *b,
793 void *data)
794 {
795 struct pbr_nexthop_group_cache *pnhgc = b->data;
796 struct pbr_nht_individual pnhi;
797 bool old_valid;
798
799 old_valid = pnhgc->valid;
800
801 pnhi.ifp = data;
802 pnhi.valid = 0;
803 hash_iterate(pnhgc->nhh,
804 pbr_nht_individual_nexthop_interface_update_lookup, &pnhi);
805
806 /*
807 * If any of the specified nexthops are valid we are valid
808 */
809 pnhgc->valid = !!pnhi.valid;
810
811 if (old_valid != pnhgc->valid)
812 pbr_map_check_nh_group_change(pnhgc->name);
813 }
814
815 void pbr_nht_nexthop_interface_update(struct interface *ifp)
816 {
817 hash_iterate(pbr_nhg_hash, pbr_nht_nexthop_interface_update_lookup,
818 ifp);
819 }
820
821 static uint32_t pbr_nhg_hash_key(const void *arg)
822 {
823 const struct pbr_nexthop_group_cache *nhgc = arg;
824
825 return jhash(&nhgc->name, strlen(nhgc->name), 0x52c34a96);
826 }
827
828 static bool pbr_nhg_hash_equal(const void *arg1, const void *arg2)
829 {
830 const struct pbr_nexthop_group_cache *nhgc1 =
831 (const struct pbr_nexthop_group_cache *)arg1;
832 const struct pbr_nexthop_group_cache *nhgc2 =
833 (const struct pbr_nexthop_group_cache *)arg2;
834
835 return !strcmp(nhgc1->name, nhgc2->name);
836 }
837
838 uint32_t pbr_nht_get_next_tableid(bool peek)
839 {
840 uint32_t i;
841 bool found = false;
842
843 for (i = pbr_nhg_low_table; i <= pbr_nhg_high_table; i++) {
844 if (!nhg_tableid[i]) {
845 found = true;
846 break;
847 }
848 }
849
850 if (found) {
851 nhg_tableid[i] = !peek;
852 return i;
853 } else
854 return 0;
855 }
856
857 void pbr_nht_set_tableid_range(uint32_t low, uint32_t high)
858 {
859 pbr_nhg_low_table = low;
860 pbr_nhg_high_table = high;
861 }
862
863 void pbr_nht_write_table_range(struct vty *vty)
864 {
865 if (pbr_nhg_low_table != PBR_NHT_DEFAULT_LOW_TABLEID
866 || pbr_nhg_high_table != PBR_NHT_DEFAULT_HIGH_TABLEID) {
867 vty_out(vty, "pbr table range %u %u\n", pbr_nhg_low_table,
868 pbr_nhg_high_table);
869 }
870 }
871
872 uint32_t pbr_nht_get_next_rule(uint32_t seqno)
873 {
874 return seqno + pbr_nhg_low_rule - 1;
875 }
876 void pbr_nht_set_rule_range(uint32_t low, uint32_t high)
877 {
878 pbr_nhg_low_rule = low;
879 pbr_nhg_high_rule = high;
880 }
881
882 void pbr_nht_write_rule_range(struct vty *vty)
883 {
884 if (pbr_nhg_low_rule != PBR_NHT_DEFAULT_LOW_RULE
885 || pbr_nhg_high_rule != PBR_NHT_DEFAULT_HIGH_RULE) {
886 vty_out(vty, "pbr rule range %u %u\n", pbr_nhg_low_rule,
887 pbr_nhg_high_rule);
888 }
889 }
890
891 uint32_t pbr_nht_get_table(const char *name)
892 {
893 struct pbr_nexthop_group_cache find;
894 struct pbr_nexthop_group_cache *pnhgc;
895
896 memset(&find, 0, sizeof(find));
897 snprintf(find.name, sizeof(find.name), "%s", name);
898 pnhgc = hash_lookup(pbr_nhg_hash, &find);
899
900 if (!pnhgc) {
901 DEBUGD(&pbr_dbg_nht,
902 "%s: Could not find nexthop-group cache w/ name '%s'",
903 __PRETTY_FUNCTION__, name);
904 return 5000;
905 }
906
907 return pnhgc->table_id;
908 }
909
910 bool pbr_nht_get_installed(const char *name)
911 {
912 struct pbr_nexthop_group_cache find;
913 struct pbr_nexthop_group_cache *pnhgc;
914
915 memset(&find, 0, sizeof(find));
916 snprintf(find.name, sizeof(find.name), "%s", name);
917
918 pnhgc = hash_lookup(pbr_nhg_hash, &find);
919
920 if (!pnhgc)
921 return false;
922
923 return pnhgc->installed;
924 }
925
926 static void pbr_nht_show_nhg_nexthops(struct hash_bucket *b, void *data)
927 {
928 struct pbr_nexthop_cache *pnhc = b->data;
929 struct vty *vty = data;
930
931 vty_out(vty, "\tValid: %d ", pnhc->valid);
932 nexthop_group_write_nexthop(vty, pnhc->nexthop);
933 }
934
935 struct pbr_nht_show {
936 struct vty *vty;
937 const char *name;
938 };
939
940 static void pbr_nht_show_nhg(struct hash_bucket *b, void *data)
941 {
942 struct pbr_nexthop_group_cache *pnhgc = b->data;
943 struct pbr_nht_show *pns = data;
944 struct vty *vty;
945
946 if (pns->name && strcmp(pns->name, pnhgc->name) != 0)
947 return;
948
949 vty = pns->vty;
950 vty_out(vty, "Nexthop-Group: %s Table: %u Valid: %d Installed: %d\n",
951 pnhgc->name, pnhgc->table_id, pnhgc->valid, pnhgc->installed);
952
953 hash_iterate(pnhgc->nhh, pbr_nht_show_nhg_nexthops, vty);
954 }
955
956 void pbr_nht_show_nexthop_group(struct vty *vty, const char *name)
957 {
958 struct pbr_nht_show pns;
959
960 pns.vty = vty;
961 pns.name = name;
962
963 hash_iterate(pbr_nhg_hash, pbr_nht_show_nhg, &pns);
964 }
965
966 void pbr_nht_init(void)
967 {
968 pbr_nhg_hash = hash_create_size(
969 16, pbr_nhg_hash_key, pbr_nhg_hash_equal, "PBR NHG Cache Hash");
970 pbr_nhrc_hash =
971 hash_create_size(16, (unsigned int (*)(const void *))nexthop_hash,
972 pbr_nhrc_hash_equal, "PBR NH Hash");
973
974 pbr_nhg_low_table = PBR_NHT_DEFAULT_LOW_TABLEID;
975 pbr_nhg_high_table = PBR_NHT_DEFAULT_HIGH_TABLEID;
976 pbr_nhg_low_rule = PBR_NHT_DEFAULT_LOW_RULE;
977 pbr_nhg_high_rule = PBR_NHT_DEFAULT_HIGH_RULE;
978 memset(&nhg_tableid, 0, 65535 * sizeof(uint8_t));
979 }