]> git.proxmox.com Git - mirror_frr.git/blob - pbrd/pbr_nht.c
Merge pull request #4609 from ton31337/fix/show_set_comm-list_delete
[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_nht_install_nexthop_group(pnhgc, nhgc->nhg);
231 pbr_map_check_nh_group_change(name);
232 }
233
234 void pbr_nhgroup_add_nexthop_cb(const struct nexthop_group_cmd *nhgc,
235 const struct nexthop *nhop)
236 {
237 char debugstr[256];
238 struct pbr_nexthop_group_cache pnhgc_find = {};
239 struct pbr_nexthop_group_cache *pnhgc;
240 struct pbr_nexthop_cache pnhc_find = {};
241 struct pbr_nexthop_cache *pnhc;
242
243 if (!pbr_nht_get_next_tableid(true)) {
244 zlog_warn(
245 "%s: Exhausted all table identifiers; cannot create nexthop-group cache for nexthop-group '%s'",
246 __PRETTY_FUNCTION__, nhgc->name);
247 return;
248 }
249
250 /* find pnhgc by name */
251 strlcpy(pnhgc_find.name, nhgc->name, sizeof(pnhgc_find.name));
252 pnhgc = hash_get(pbr_nhg_hash, &pnhgc_find, pbr_nhgc_alloc);
253
254 /* create & insert new pnhc into pnhgc->nhh */
255 pnhc_find.nexthop = (struct nexthop *)nhop;
256 pnhc = hash_get(pnhgc->nhh, &pnhc_find, pbr_nh_alloc);
257 pnhc_find.nexthop = NULL;
258
259 /* set parent pnhgc */
260 pnhc->parent = pnhgc;
261
262 if (DEBUG_MODE_CHECK(&pbr_dbg_nht, DEBUG_MODE_ALL)) {
263 nexthop2str(nhop, debugstr, sizeof(debugstr));
264 DEBUGD(&pbr_dbg_nht, "%s: Added %s to nexthop-group %s",
265 __PRETTY_FUNCTION__, debugstr, nhgc->name);
266 }
267
268 pbr_nht_install_nexthop_group(pnhgc, nhgc->nhg);
269 pbr_map_check_nh_group_change(nhgc->name);
270
271 if (nhop->type == NEXTHOP_TYPE_IFINDEX) {
272 struct interface *ifp;
273
274 ifp = if_lookup_by_index(nhop->ifindex, nhop->vrf_id);
275 if (ifp)
276 pbr_nht_nexthop_interface_update(ifp);
277 }
278 }
279
280 void pbr_nhgroup_del_nexthop_cb(const struct nexthop_group_cmd *nhgc,
281 const struct nexthop *nhop)
282 {
283 char debugstr[256];
284 struct pbr_nexthop_group_cache pnhgc_find = {};
285 struct pbr_nexthop_group_cache *pnhgc;
286 struct pbr_nexthop_cache pnhc_find = {};
287 struct pbr_nexthop_cache *pnhc;
288 enum nexthop_types_t nh_type = nhop->type;
289
290 /* find pnhgc by name */
291 strlcpy(pnhgc_find.name, nhgc->name, sizeof(pnhgc_find.name));
292 pnhgc = hash_lookup(pbr_nhg_hash, &pnhgc_find);
293
294 /* delete pnhc from pnhgc->nhh */
295 pnhc_find.nexthop = (struct nexthop *)nhop;
296 pnhc = hash_release(pnhgc->nhh, &pnhc_find);
297
298 /* delete pnhc */
299 pbr_nh_delete(&pnhc);
300
301 if (DEBUG_MODE_CHECK(&pbr_dbg_nht, DEBUG_MODE_ALL)) {
302 nexthop2str(nhop, debugstr, sizeof(debugstr));
303 DEBUGD(&pbr_dbg_nht, "%s: Removed %s from nexthop-group %s",
304 __PRETTY_FUNCTION__, debugstr, nhgc->name);
305 }
306
307 if (pnhgc->nhh->count)
308 pbr_nht_install_nexthop_group(pnhgc, nhgc->nhg);
309 else
310 pbr_nht_uninstall_nexthop_group(pnhgc, nhgc->nhg, nh_type);
311
312 pbr_map_check_nh_group_change(nhgc->name);
313 }
314
315 void pbr_nhgroup_delete_cb(const char *name)
316 {
317 DEBUGD(&pbr_dbg_nht, "%s: Removed nexthop-group %s",
318 __PRETTY_FUNCTION__, name);
319
320 /* delete group from all pbrms's */
321 pbr_nht_delete_group(name);
322
323 pbr_map_check_nh_group_change(name);
324 }
325
326 #if 0
327 static struct pbr_nexthop_cache *pbr_nht_lookup_nexthop(struct nexthop *nexthop)
328 {
329 return NULL;
330 }
331 #endif
332
333 static void pbr_nht_find_nhg_from_table_install(struct hash_bucket *b,
334 void *data)
335 {
336 struct pbr_nexthop_group_cache *pnhgc =
337 (struct pbr_nexthop_group_cache *)b->data;
338 uint32_t *table_id = (uint32_t *)data;
339
340 if (pnhgc->table_id == *table_id) {
341 DEBUGD(&pbr_dbg_nht, "%s: Table ID (%u) matches %s",
342 __PRETTY_FUNCTION__, *table_id, pnhgc->name);
343
344 /*
345 * If the table has been re-handled by zebra
346 * and we are already installed no need to do
347 * anything here.
348 */
349 if (!pnhgc->installed) {
350 pnhgc->installed = true;
351 pbr_map_schedule_policy_from_nhg(pnhgc->name);
352 }
353 }
354 }
355
356 void pbr_nht_route_installed_for_table(uint32_t table_id)
357 {
358 hash_iterate(pbr_nhg_hash, pbr_nht_find_nhg_from_table_install,
359 &table_id);
360 }
361
362 static void pbr_nht_find_nhg_from_table_remove(struct hash_bucket *b,
363 void *data)
364 {
365 ;
366 }
367
368 void pbr_nht_route_removed_for_table(uint32_t table_id)
369 {
370 hash_iterate(pbr_nhg_hash, pbr_nht_find_nhg_from_table_remove,
371 &table_id);
372 }
373
374 /*
375 * Loop through all nexthops in a nexthop group to check that they are all the
376 * same. If they are not all the same, log this peculiarity.
377 *
378 * nhg
379 * The nexthop group to check
380 *
381 * Returns:
382 * - AFI of last nexthop in the group
383 * - AFI_MAX on error
384 */
385 static afi_t pbr_nht_which_afi(struct nexthop_group nhg,
386 enum nexthop_types_t nh_type)
387 {
388 struct nexthop *nexthop;
389 afi_t install_afi = AFI_MAX;
390 bool v6, v4, bh;
391
392 if (nh_type) {
393 switch (nh_type) {
394 case NEXTHOP_TYPE_IPV4:
395 case NEXTHOP_TYPE_IPV4_IFINDEX:
396 return AFI_IP;
397 case NEXTHOP_TYPE_IPV6:
398 case NEXTHOP_TYPE_IPV6_IFINDEX:
399 return AFI_IP6;
400 case NEXTHOP_TYPE_IFINDEX:
401 case NEXTHOP_TYPE_BLACKHOLE:
402 return AFI_MAX;
403 }
404 }
405
406 v6 = v4 = bh = false;
407
408 for (ALL_NEXTHOPS(nhg, nexthop)) {
409 nh_type = nexthop->type;
410
411 switch (nh_type) {
412 case NEXTHOP_TYPE_IFINDEX:
413 break;
414 case NEXTHOP_TYPE_IPV4:
415 case NEXTHOP_TYPE_IPV4_IFINDEX:
416 v6 = true;
417 install_afi = AFI_IP;
418 break;
419 case NEXTHOP_TYPE_IPV6:
420 case NEXTHOP_TYPE_IPV6_IFINDEX:
421 v4 = true;
422 install_afi = AFI_IP6;
423 break;
424 case NEXTHOP_TYPE_BLACKHOLE:
425 bh = true;
426 break;
427 }
428 }
429
430 /* Interface and/or blackhole nexthops only. */
431 if (!v4 && !v6)
432 install_afi = AFI_MAX;
433
434 if (!bh && v6 && v4)
435 DEBUGD(&pbr_dbg_nht,
436 "%s: Saw both V6 and V4 nexthops...using %s",
437 __PRETTY_FUNCTION__, afi2str(install_afi));
438 if (bh && (v6 || v4))
439 DEBUGD(&pbr_dbg_nht,
440 "%s: Saw blackhole nexthop(s) with %s%s%s nexthop(s), using AFI_MAX.",
441 __PRETTY_FUNCTION__, v4 ? "v4" : "",
442 (v4 && v6) ? " and " : "", v6 ? "v6" : "");
443
444 return install_afi;
445 }
446
447 static void pbr_nht_install_nexthop_group(struct pbr_nexthop_group_cache *pnhgc,
448 struct nexthop_group nhg)
449 {
450 afi_t install_afi;
451 enum nexthop_types_t nh_type = 0;
452
453 install_afi = pbr_nht_which_afi(nhg, nh_type);
454
455 route_add(pnhgc, nhg, install_afi);
456 }
457
458 static void
459 pbr_nht_uninstall_nexthop_group(struct pbr_nexthop_group_cache *pnhgc,
460 struct nexthop_group nhg,
461 enum nexthop_types_t nh_type)
462 {
463 afi_t install_afi;
464
465 install_afi = pbr_nht_which_afi(nhg, nh_type);
466
467 pnhgc->installed = false;
468 pnhgc->valid = false;
469 route_delete(pnhgc, install_afi);
470 }
471
472 void pbr_nht_change_group(const char *name)
473 {
474 struct nexthop_group_cmd *nhgc;
475 struct pbr_nexthop_group_cache *pnhgc;
476 struct pbr_nexthop_group_cache find;
477 struct nexthop *nhop;
478
479 nhgc = nhgc_find(name);
480 if (!nhgc)
481 return;
482
483 memset(&find, 0, sizeof(find));
484 snprintf(find.name, sizeof(find.name), "%s", name);
485 pnhgc = hash_lookup(pbr_nhg_hash, &find);
486
487 if (!pnhgc) {
488 DEBUGD(&pbr_dbg_nht,
489 "%s: Could not find nexthop-group cache w/ name '%s'",
490 __PRETTY_FUNCTION__, name);
491 return;
492 }
493
494 for (ALL_NEXTHOPS(nhgc->nhg, nhop)) {
495 struct pbr_nexthop_cache lookup;
496 struct pbr_nexthop_cache *pnhc;
497
498 lookup.nexthop = nhop;
499 pnhc = hash_lookup(pnhgc->nhh, &lookup);
500 if (!pnhc) {
501 pnhc = hash_get(pnhgc->nhh, &lookup, pbr_nh_alloc);
502 pnhc->parent = pnhgc;
503 }
504 }
505 pbr_nht_install_nexthop_group(pnhgc, nhgc->nhg);
506 }
507
508 char *pbr_nht_nexthop_make_name(char *name, size_t l,
509 uint32_t seqno, char *buffer)
510 {
511 snprintf(buffer, l, "%s%u", name, seqno);
512 return buffer;
513 }
514
515 void pbr_nht_add_individual_nexthop(struct pbr_map_sequence *pbrms)
516 {
517 struct pbr_nexthop_group_cache *pnhgc;
518 struct pbr_nexthop_group_cache find;
519 struct pbr_nexthop_cache *pnhc;
520 struct pbr_nexthop_cache lookup;
521
522 memset(&find, 0, sizeof(find));
523 pbr_nht_nexthop_make_name(pbrms->parent->name, PBR_NHC_NAMELEN,
524 pbrms->seqno, find.name);
525
526 if (!pbr_nht_get_next_tableid(true)) {
527 zlog_warn(
528 "%s: Exhausted all table identifiers; cannot create nexthop-group cache for nexthop-group '%s'",
529 __PRETTY_FUNCTION__, find.name);
530 return;
531 }
532
533 if (!pbrms->internal_nhg_name)
534 pbrms->internal_nhg_name = XSTRDUP(MTYPE_TMP, find.name);
535
536 pnhgc = hash_get(pbr_nhg_hash, &find, pbr_nhgc_alloc);
537
538 lookup.nexthop = pbrms->nhg->nexthop;
539 pnhc = hash_get(pnhgc->nhh, &lookup, pbr_nh_alloc);
540 pnhc->parent = pnhgc;
541 pbr_nht_install_nexthop_group(pnhgc, *pbrms->nhg);
542 }
543
544 void pbr_nht_delete_individual_nexthop(struct pbr_map_sequence *pbrms)
545 {
546 struct pbr_nexthop_group_cache *pnhgc;
547 struct pbr_nexthop_group_cache find;
548 struct pbr_nexthop_cache *pnhc;
549 struct pbr_nexthop_cache lup;
550 struct pbr_map *pbrm = pbrms->parent;
551 struct listnode *node;
552 struct pbr_map_interface *pmi;
553 struct nexthop *nh;
554 enum nexthop_types_t nh_type = 0;
555
556 if (pbrm->valid && pbrms->nhs_installed && pbrm->incoming->count) {
557 for (ALL_LIST_ELEMENTS_RO(pbrm->incoming, node, pmi))
558 pbr_send_pbr_map(pbrms, pmi, false);
559 }
560
561 pbrm->valid = false;
562 pbrms->nhs_installed = false;
563 pbrms->reason |= PBR_MAP_INVALID_NO_NEXTHOPS;
564
565 memset(&find, 0, sizeof(find));
566 snprintf(find.name, sizeof(find.name), "%s", pbrms->internal_nhg_name);
567 pnhgc = hash_lookup(pbr_nhg_hash, &find);
568
569 nh = pbrms->nhg->nexthop;
570 nh_type = nh->type;
571 lup.nexthop = nh;
572 pnhc = hash_lookup(pnhgc->nhh, &lup);
573 pnhc->parent = NULL;
574 hash_release(pnhgc->nhh, pnhc);
575 pbr_nh_delete(&pnhc);
576 pbr_nht_uninstall_nexthop_group(pnhgc, *pbrms->nhg, nh_type);
577
578 hash_release(pbr_nhg_hash, pnhgc);
579
580 _nexthop_del(pbrms->nhg, nh);
581 nexthop_free(nh);
582 nexthop_group_delete(&pbrms->nhg);
583 XFREE(MTYPE_TMP, pbrms->internal_nhg_name);
584 }
585
586 struct pbr_nexthop_group_cache *pbr_nht_add_group(const char *name)
587 {
588 struct nexthop *nhop;
589 struct nexthop_group_cmd *nhgc;
590 struct pbr_nexthop_group_cache *pnhgc;
591 struct pbr_nexthop_group_cache lookup;
592
593 if (!pbr_nht_get_next_tableid(true)) {
594 zlog_warn(
595 "%s: Exhausted all table identifiers; cannot create nexthop-group cache for nexthop-group '%s'",
596 __PRETTY_FUNCTION__, name);
597 return NULL;
598 }
599
600 nhgc = nhgc_find(name);
601
602 if (!nhgc) {
603 DEBUGD(&pbr_dbg_nht, "%s: Could not find nhgc with name: %s\n",
604 __PRETTY_FUNCTION__, name);
605 return NULL;
606 }
607
608 snprintf(lookup.name, sizeof(lookup.name), "%s", name);
609 pnhgc = hash_get(pbr_nhg_hash, &lookup, pbr_nhgc_alloc);
610 DEBUGD(&pbr_dbg_nht, "%s: Retrieved NHGC @ %p", __PRETTY_FUNCTION__,
611 pnhgc);
612
613 for (ALL_NEXTHOPS(nhgc->nhg, nhop)) {
614 struct pbr_nexthop_cache lookupc;
615 struct pbr_nexthop_cache *pnhc;
616
617 lookupc.nexthop = nhop;
618 pnhc = hash_lookup(pnhgc->nhh, &lookupc);
619 if (!pnhc) {
620 pnhc = hash_get(pnhgc->nhh, &lookupc, pbr_nh_alloc);
621 pnhc->parent = pnhgc;
622 }
623 }
624
625 return pnhgc;
626 }
627
628 void pbr_nht_delete_group(const char *name)
629 {
630 struct pbr_map_sequence *pbrms;
631 struct listnode *snode;
632 struct pbr_map *pbrm;
633 struct pbr_nexthop_group_cache pnhgc_find;
634 struct pbr_nexthop_group_cache *pnhgc;
635
636 RB_FOREACH (pbrm, pbr_map_entry_head, &pbr_maps) {
637 for (ALL_LIST_ELEMENTS_RO(pbrm->seqnumbers, snode, pbrms)) {
638 if (pbrms->nhgrp_name
639 && strmatch(pbrms->nhgrp_name, name)) {
640 pbrms->reason |= PBR_MAP_INVALID_NO_NEXTHOPS;
641 nexthop_group_delete(&pbrms->nhg);
642 pbrms->nhg = NULL;
643 pbrms->internal_nhg_name = NULL;
644 pbrm->valid = false;
645 }
646 }
647 }
648
649 strlcpy(pnhgc_find.name, name, sizeof(pnhgc_find.name));
650 pnhgc = hash_release(pbr_nhg_hash, &pnhgc_find);
651 pbr_nhgc_delete(pnhgc);
652 }
653
654 bool pbr_nht_nexthop_valid(struct nexthop_group *nhg)
655 {
656 DEBUGD(&pbr_dbg_nht, "%s: %p", __PRETTY_FUNCTION__, nhg);
657 return true;
658 }
659
660 bool pbr_nht_nexthop_group_valid(const char *name)
661 {
662 struct pbr_nexthop_group_cache *pnhgc;
663 struct pbr_nexthop_group_cache lookup;
664
665 DEBUGD(&pbr_dbg_nht, "%s: %s", __PRETTY_FUNCTION__, name);
666
667 snprintf(lookup.name, sizeof(lookup.name), "%s", name);
668 pnhgc = hash_get(pbr_nhg_hash, &lookup, NULL);
669 if (!pnhgc)
670 return false;
671 DEBUGD(&pbr_dbg_nht, "%s: \t%d %d", __PRETTY_FUNCTION__, pnhgc->valid,
672 pnhgc->installed);
673 if (pnhgc->valid && pnhgc->installed)
674 return true;
675
676 return false;
677 }
678
679 struct pbr_nht_individual {
680 struct zapi_route *nhr;
681 struct interface *ifp;
682
683 uint32_t valid;
684 };
685
686 static void pbr_nht_individual_nexthop_update_lookup(struct hash_bucket *b,
687 void *data)
688 {
689 struct pbr_nexthop_cache *pnhc = b->data;
690 struct pbr_nht_individual *pnhi = data;
691 char buf[PREFIX_STRLEN];
692 bool old_valid;
693
694 old_valid = pnhc->valid;
695
696 switch (pnhi->nhr->prefix.family) {
697 case AF_INET:
698 if (pnhc->nexthop->gate.ipv4.s_addr
699 == pnhi->nhr->prefix.u.prefix4.s_addr)
700 pnhc->valid = !!pnhi->nhr->nexthop_num;
701 break;
702 case AF_INET6:
703 if (memcmp(&pnhc->nexthop->gate.ipv6,
704 &pnhi->nhr->prefix.u.prefix6, 16)
705 == 0)
706 pnhc->valid = !!pnhi->nhr->nexthop_num;
707 break;
708 }
709
710 DEBUGD(&pbr_dbg_nht, "\tFound %s: old: %d new: %d",
711 prefix2str(&pnhi->nhr->prefix, buf, sizeof(buf)), old_valid,
712 pnhc->valid);
713
714 if (pnhc->valid)
715 pnhi->valid += 1;
716 }
717
718 static void pbr_nexthop_group_cache_iterate_to_group(struct hash_bucket *b,
719 void *data)
720 {
721 struct pbr_nexthop_cache *pnhc = b->data;
722 struct nexthop_group *nhg = data;
723 struct nexthop *nh = NULL;
724
725 copy_nexthops(&nh, pnhc->nexthop, NULL);
726
727 _nexthop_add(&nhg->nexthop, nh);
728 }
729
730 static void
731 pbr_nexthop_group_cache_to_nexthop_group(struct nexthop_group *nhg,
732 struct pbr_nexthop_group_cache *pnhgc)
733 {
734 hash_iterate(pnhgc->nhh, pbr_nexthop_group_cache_iterate_to_group, nhg);
735 }
736
737 static void pbr_nht_nexthop_update_lookup(struct hash_bucket *b, void *data)
738 {
739 struct pbr_nexthop_group_cache *pnhgc = b->data;
740 struct pbr_nht_individual pnhi;
741 struct nexthop_group nhg = {};
742 bool old_valid;
743
744 old_valid = pnhgc->valid;
745
746 pnhi.nhr = (struct zapi_route *)data;
747 pnhi.valid = 0;
748 hash_iterate(pnhgc->nhh, pbr_nht_individual_nexthop_update_lookup,
749 &pnhi);
750
751 /*
752 * If any of the specified nexthops are valid we are valid
753 */
754 pnhgc->valid = !!pnhi.valid;
755
756 if (pnhgc->valid) {
757 pbr_nexthop_group_cache_to_nexthop_group(&nhg, pnhgc);
758 pbr_nht_install_nexthop_group(pnhgc, nhg);
759 /* Don't need copied nexthops anymore */
760 nexthops_free(nhg.nexthop);
761 }
762
763 if (old_valid != pnhgc->valid)
764 pbr_map_check_nh_group_change(pnhgc->name);
765 }
766
767 void pbr_nht_nexthop_update(struct zapi_route *nhr)
768 {
769 hash_iterate(pbr_nhg_hash, pbr_nht_nexthop_update_lookup, nhr);
770 }
771
772 static void
773 pbr_nht_individual_nexthop_interface_update_lookup(struct hash_backet *b,
774 void *data)
775 {
776 struct pbr_nexthop_cache *pnhc = b->data;
777 struct pbr_nht_individual *pnhi = data;
778 bool old_valid;
779
780 old_valid = pnhc->valid;
781
782 if (pnhc->nexthop->type == NEXTHOP_TYPE_IFINDEX
783 && pnhc->nexthop->ifindex == pnhi->ifp->ifindex)
784 pnhc->valid = !!if_is_up(pnhi->ifp);
785
786 DEBUGD(&pbr_dbg_nht, "\tFound %s: old: %d new: %d", pnhi->ifp->name,
787 old_valid, pnhc->valid);
788
789 if (pnhc->valid)
790 pnhi->valid += 1;
791 }
792
793 static void pbr_nht_nexthop_interface_update_lookup(struct hash_backet *b,
794 void *data)
795 {
796 struct pbr_nexthop_group_cache *pnhgc = b->data;
797 struct pbr_nht_individual pnhi;
798 bool old_valid;
799
800 old_valid = pnhgc->valid;
801
802 pnhi.ifp = data;
803 pnhi.valid = 0;
804 hash_iterate(pnhgc->nhh,
805 pbr_nht_individual_nexthop_interface_update_lookup, &pnhi);
806
807 /*
808 * If any of the specified nexthops are valid we are valid
809 */
810 pnhgc->valid = !!pnhi.valid;
811
812 if (old_valid != pnhgc->valid)
813 pbr_map_check_nh_group_change(pnhgc->name);
814 }
815
816 void pbr_nht_nexthop_interface_update(struct interface *ifp)
817 {
818 hash_iterate(pbr_nhg_hash, pbr_nht_nexthop_interface_update_lookup,
819 ifp);
820 }
821
822 static uint32_t pbr_nhg_hash_key(const void *arg)
823 {
824 const struct pbr_nexthop_group_cache *nhgc = arg;
825
826 return jhash(&nhgc->name, strlen(nhgc->name), 0x52c34a96);
827 }
828
829 static bool pbr_nhg_hash_equal(const void *arg1, const void *arg2)
830 {
831 const struct pbr_nexthop_group_cache *nhgc1 =
832 (const struct pbr_nexthop_group_cache *)arg1;
833 const struct pbr_nexthop_group_cache *nhgc2 =
834 (const struct pbr_nexthop_group_cache *)arg2;
835
836 return !strcmp(nhgc1->name, nhgc2->name);
837 }
838
839 uint32_t pbr_nht_get_next_tableid(bool peek)
840 {
841 uint32_t i;
842 bool found = false;
843
844 for (i = pbr_nhg_low_table; i <= pbr_nhg_high_table; i++) {
845 if (!nhg_tableid[i]) {
846 found = true;
847 break;
848 }
849 }
850
851 if (found) {
852 nhg_tableid[i] = !peek;
853 return i;
854 } else
855 return 0;
856 }
857
858 void pbr_nht_set_tableid_range(uint32_t low, uint32_t high)
859 {
860 pbr_nhg_low_table = low;
861 pbr_nhg_high_table = high;
862 }
863
864 void pbr_nht_write_table_range(struct vty *vty)
865 {
866 if (pbr_nhg_low_table != PBR_NHT_DEFAULT_LOW_TABLEID
867 || pbr_nhg_high_table != PBR_NHT_DEFAULT_HIGH_TABLEID) {
868 vty_out(vty, "pbr table range %u %u\n", pbr_nhg_low_table,
869 pbr_nhg_high_table);
870 }
871 }
872
873 uint32_t pbr_nht_get_next_rule(uint32_t seqno)
874 {
875 return seqno + pbr_nhg_low_rule - 1;
876 }
877 void pbr_nht_set_rule_range(uint32_t low, uint32_t high)
878 {
879 pbr_nhg_low_rule = low;
880 pbr_nhg_high_rule = high;
881 }
882
883 void pbr_nht_write_rule_range(struct vty *vty)
884 {
885 if (pbr_nhg_low_rule != PBR_NHT_DEFAULT_LOW_RULE
886 || pbr_nhg_high_rule != PBR_NHT_DEFAULT_HIGH_RULE) {
887 vty_out(vty, "pbr rule range %u %u\n", pbr_nhg_low_rule,
888 pbr_nhg_high_rule);
889 }
890 }
891
892 uint32_t pbr_nht_get_table(const char *name)
893 {
894 struct pbr_nexthop_group_cache find;
895 struct pbr_nexthop_group_cache *pnhgc;
896
897 memset(&find, 0, sizeof(find));
898 snprintf(find.name, sizeof(find.name), "%s", name);
899 pnhgc = hash_lookup(pbr_nhg_hash, &find);
900
901 if (!pnhgc) {
902 DEBUGD(&pbr_dbg_nht,
903 "%s: Could not find nexthop-group cache w/ name '%s'",
904 __PRETTY_FUNCTION__, name);
905 return 5000;
906 }
907
908 return pnhgc->table_id;
909 }
910
911 bool pbr_nht_get_installed(const char *name)
912 {
913 struct pbr_nexthop_group_cache find;
914 struct pbr_nexthop_group_cache *pnhgc;
915
916 memset(&find, 0, sizeof(find));
917 snprintf(find.name, sizeof(find.name), "%s", name);
918
919 pnhgc = hash_lookup(pbr_nhg_hash, &find);
920
921 if (!pnhgc)
922 return false;
923
924 return pnhgc->installed;
925 }
926
927 static void pbr_nht_show_nhg_nexthops(struct hash_bucket *b, void *data)
928 {
929 struct pbr_nexthop_cache *pnhc = b->data;
930 struct vty *vty = data;
931
932 vty_out(vty, "\tValid: %d ", pnhc->valid);
933 nexthop_group_write_nexthop(vty, pnhc->nexthop);
934 }
935
936 struct pbr_nht_show {
937 struct vty *vty;
938 const char *name;
939 };
940
941 static void pbr_nht_show_nhg(struct hash_bucket *b, void *data)
942 {
943 struct pbr_nexthop_group_cache *pnhgc = b->data;
944 struct pbr_nht_show *pns = data;
945 struct vty *vty;
946
947 if (pns->name && strcmp(pns->name, pnhgc->name) != 0)
948 return;
949
950 vty = pns->vty;
951 vty_out(vty, "Nexthop-Group: %s Table: %u Valid: %d Installed: %d\n",
952 pnhgc->name, pnhgc->table_id, pnhgc->valid, pnhgc->installed);
953
954 hash_iterate(pnhgc->nhh, pbr_nht_show_nhg_nexthops, vty);
955 }
956
957 void pbr_nht_show_nexthop_group(struct vty *vty, const char *name)
958 {
959 struct pbr_nht_show pns;
960
961 pns.vty = vty;
962 pns.name = name;
963
964 hash_iterate(pbr_nhg_hash, pbr_nht_show_nhg, &pns);
965 }
966
967 void pbr_nht_init(void)
968 {
969 pbr_nhg_hash = hash_create_size(
970 16, pbr_nhg_hash_key, pbr_nhg_hash_equal, "PBR NHG Cache Hash");
971 pbr_nhrc_hash =
972 hash_create_size(16, (unsigned int (*)(const void *))nexthop_hash,
973 pbr_nhrc_hash_equal, "PBR NH Hash");
974
975 pbr_nhg_low_table = PBR_NHT_DEFAULT_LOW_TABLEID;
976 pbr_nhg_high_table = PBR_NHT_DEFAULT_HIGH_TABLEID;
977 pbr_nhg_low_rule = PBR_NHT_DEFAULT_LOW_RULE;
978 pbr_nhg_high_rule = PBR_NHT_DEFAULT_HIGH_RULE;
979 memset(&nhg_tableid, 0, 65535 * sizeof(uint8_t));
980 }