]> git.proxmox.com Git - mirror_frr.git/blame - pbrd/pbr_nht.c
doc: Add documentation for PBRD
[mirror_frr.git] / pbrd / pbr_nht.c
CommitLineData
e5c83d9b
DS
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 <hash.h>
26#include <jhash.h>
27#include <vty.h>
28#include <zclient.h>
29
30#include "pbrd/pbr_nht.h"
31#include "pbrd/pbr_map.h"
32#include "pbrd/pbr_event.h"
33#include "pbrd/pbr_zebra.h"
34#include "pbrd/pbr_memory.h"
35#include "pbrd/pbr_debug.h"
36
37DEFINE_MTYPE_STATIC(PBRD, PBR_NHG, "PBR Nexthop Groups")
38
39static struct hash *pbr_nhg_hash;
40
41static uint32_t pbr_nhg_low_table;
42static uint32_t pbr_nhg_high_table;
43static uint32_t pbr_nhg_low_rule;
44static uint32_t pbr_nhg_high_rule;
45static bool nhg_tableid[65535];
46
47static void *pbr_nh_alloc(void *p)
48{
49 struct pbr_nexthop_cache *new;
50 struct pbr_nexthop_cache *pnhc = (struct pbr_nexthop_cache *)p;
51
52 new = XCALLOC(MTYPE_PBR_NHG, sizeof(*new));
53 memcpy(&new->nexthop, &pnhc->nexthop, sizeof(struct nexthop));
54
55 DEBUGD(&pbr_dbg_nht, "%s: Sending nexthop to Zebra",
56 __PRETTY_FUNCTION__);
57
58 pbr_send_rnh(&new->nexthop, true);
59
60 new->valid = false;
61 return new;
62}
63
64static void pbr_nh_delete(struct pbr_nexthop_cache **pnhc)
65{
66 pbr_send_rnh(&(*pnhc)->nexthop, false);
67
68 XFREE(MTYPE_PBR_NHG, *pnhc);
69}
70
71static uint32_t pbr_nh_hash_key(void *arg)
72{
73 uint32_t key;
74 struct pbr_nexthop_cache *pbrnc = (struct pbr_nexthop_cache *)arg;
75
76 key = jhash_1word(pbrnc->nexthop.vrf_id, 0x45afe398);
77 key = jhash_1word(pbrnc->nexthop.ifindex, key);
78 key = jhash_1word(pbrnc->nexthop.type, key);
79 key = jhash(&pbrnc->nexthop.gate, sizeof(union g_addr), key);
80
81 return key;
82}
83
84static int pbr_nh_hash_equal(const void *arg1, const void *arg2)
85{
86 const struct pbr_nexthop_cache *pbrnc1 =
87 (const struct pbr_nexthop_cache *)arg1;
88 const struct pbr_nexthop_cache *pbrnc2 =
89 (const struct pbr_nexthop_cache *)arg2;
90
91 if (pbrnc1->nexthop.vrf_id != pbrnc2->nexthop.vrf_id)
92 return 0;
93
94 if (pbrnc1->nexthop.ifindex != pbrnc2->nexthop.ifindex)
95 return 0;
96
97 if (pbrnc1->nexthop.type != pbrnc2->nexthop.type)
98 return 0;
99
100 switch (pbrnc1->nexthop.type) {
101 case NEXTHOP_TYPE_IFINDEX:
102 return 1;
103 case NEXTHOP_TYPE_IPV4_IFINDEX:
104 case NEXTHOP_TYPE_IPV4:
105 return pbrnc1->nexthop.gate.ipv4.s_addr
106 == pbrnc2->nexthop.gate.ipv4.s_addr;
107 case NEXTHOP_TYPE_IPV6_IFINDEX:
108 case NEXTHOP_TYPE_IPV6:
109 return !memcmp(&pbrnc1->nexthop.gate.ipv6,
110 &pbrnc2->nexthop.gate.ipv6, 16);
111 case NEXTHOP_TYPE_BLACKHOLE:
112 return pbrnc1->nexthop.bh_type == pbrnc2->nexthop.bh_type;
113 }
114
115 /*
116 * We should not get here
117 */
118 return 0;
119}
120
121void pbr_nhgroup_add_cb(const char *name)
122{
123 struct pbr_event *pbre;
124
125 pbre = pbr_event_new(PBR_NHG_NEW, name);
126
127 pbr_event_enqueue(pbre);
128 DEBUGD(&pbr_dbg_nht, "%s: Received ADD cb for %s", __PRETTY_FUNCTION__,
129 name);
130}
131
132void pbr_nhgroup_add_nexthop_cb(const struct nexthop_group_cmd *nhg,
133 const struct nexthop *nhop)
134{
135 struct pbr_event *pbre;
136
137 pbre = pbr_event_new(PBR_NHG_ADD_NEXTHOP, nhg->name);
138
139 pbr_event_enqueue(pbre);
140 DEBUGD(&pbr_dbg_nht, "%s: Received NEXTHOP_ADD cb for %s",
141 __PRETTY_FUNCTION__, nhg->name);
142}
143
144void pbr_nhgroup_del_nexthop_cb(const struct nexthop_group_cmd *nhg,
145 const struct nexthop *nhop)
146{
147 struct pbr_event *pbre;
148
149 pbre = pbr_event_new(PBR_NHG_DEL_NEXTHOP, nhg->name);
150
151 pbr_event_enqueue(pbre);
152 DEBUGD(&pbr_dbg_nht, "%s: Received NEXTHOP_DEL cb for %s",
153 __PRETTY_FUNCTION__, nhg->name);
154}
155
156void pbr_nhgroup_delete_cb(const char *name)
157{
158 struct pbr_event *pbre;
159
160 pbre = pbr_event_new(PBR_NHG_DELETE, name);
161
162 pbr_event_enqueue(pbre);
163 DEBUGD(&pbr_dbg_nht, "%s: Received DELETE cb for %s",
164 __PRETTY_FUNCTION__, name);
165}
166
167#if 0
168static struct pbr_nexthop_cache *pbr_nht_lookup_nexthop(struct nexthop *nexthop)
169{
170 return NULL;
171}
172#endif
173
174static void pbr_nht_find_nhg_from_table_install(struct hash_backet *b,
175 void *data)
176{
177 struct pbr_nexthop_group_cache *pnhgc =
178 (struct pbr_nexthop_group_cache *)b->data;
179 uint32_t *table_id = (uint32_t *)data;
180
181 if (pnhgc->table_id == *table_id) {
182 DEBUGD(&pbr_dbg_nht, "%s: Table ID (%u) matches %s",
183 __PRETTY_FUNCTION__, *table_id, pnhgc->name);
184 pnhgc->installed = true;
185 pbr_map_schedule_policy_from_nhg(pnhgc->name);
186 }
187}
188
189void pbr_nht_route_installed_for_table(uint32_t table_id)
190{
191 hash_iterate(pbr_nhg_hash, pbr_nht_find_nhg_from_table_install,
192 &table_id);
193}
194
195static void pbr_nht_find_nhg_from_table_remove(struct hash_backet *b,
196 void *data)
197{
198 ;
199}
200
201void pbr_nht_route_removed_for_table(uint32_t table_id)
202{
203 hash_iterate(pbr_nhg_hash, pbr_nht_find_nhg_from_table_remove,
204 &table_id);
205}
206
207/*
208 * Loop through all nexthops in a nexthop group to check that they are all the
209 * same. If they are not all the same, log this peculiarity.
210 *
211 * nhg
212 * The nexthop group to check
213 *
214 * Returns:
215 * - AFI of last nexthop in the group
216 * - AFI_MAX on error
217 */
218static afi_t pbr_nht_which_afi(struct nexthop_group nhg)
219{
220 struct nexthop *nexthop;
221 afi_t install_afi = AFI_MAX;
222 bool v6, v4, bh;
223 v6 = v4 = bh = false;
224
225 for (ALL_NEXTHOPS(nhg, nexthop)) {
226 switch (nexthop->type) {
227 case NEXTHOP_TYPE_IFINDEX:
228 break;
229 case NEXTHOP_TYPE_IPV4:
230 case NEXTHOP_TYPE_IPV4_IFINDEX:
231 v6 = true;
232 install_afi = AFI_IP;
233 break;
234 case NEXTHOP_TYPE_IPV6:
235 case NEXTHOP_TYPE_IPV6_IFINDEX:
236 v4 = true;
237 install_afi = AFI_IP6;
238 break;
239 case NEXTHOP_TYPE_BLACKHOLE:
240 bh = true;
241 install_afi = AFI_MAX;
242 break;
243 }
244 }
245
246 if (!bh && v6 && v4)
247 DEBUGD(&pbr_dbg_nht,
248 "%s: Saw both V6 and V4 nexthops...using %s",
249 __PRETTY_FUNCTION__, afi2str(install_afi));
250 if (bh && (v6 || v4))
251 DEBUGD(&pbr_dbg_nht,
252 "%s: Saw blackhole nexthop(s) with %s%s%s nexthop(s), using AFI_MAX.",
253 __PRETTY_FUNCTION__, v4 ? "v4" : "",
254 (v4 && v6) ? " and " : "", v6 ? "v6" : "");
255
256 return install_afi;
257}
258
259static void pbr_nht_install_nexthop_group(struct pbr_nexthop_group_cache *pnhgc,
260 struct nexthop_group nhg)
261{
262 afi_t install_afi;
263
264 install_afi = pbr_nht_which_afi(nhg);
265
266 pnhgc->installed = false;
267 route_add(pnhgc, nhg, install_afi);
268}
269
270static void
271pbr_nht_uninstall_nexthop_group(struct pbr_nexthop_group_cache *pnhgc,
272 struct nexthop_group nhg)
273{
274 afi_t install_afi;
275
276 install_afi = pbr_nht_which_afi(nhg);
277
278 pnhgc->installed = false;
279 pnhgc->valid = false;
280 route_delete(pnhgc, install_afi);
281}
282
283void pbr_nht_change_group(const char *name)
284{
285 struct nexthop_group_cmd *nhgc;
286 struct pbr_nexthop_group_cache *pnhgc;
287 struct pbr_nexthop_group_cache find;
288 struct nexthop *nhop;
289
290 nhgc = nhgc_find(name);
291 if (!nhgc)
292 return;
293
294 memset(&find, 0, sizeof(find));
295 strcpy(find.name, name);
296 pnhgc = hash_lookup(pbr_nhg_hash, &find);
297
298 if (!pnhgc) {
299 DEBUGD(&pbr_dbg_nht,
300 "%s: Could not find nexthop-group cache w/ name '%s'",
301 __PRETTY_FUNCTION__, name);
302 return;
303 }
304
305 for (ALL_NEXTHOPS(nhgc->nhg, nhop)) {
306 struct pbr_nexthop_cache lookup;
307 struct pbr_nexthop_cache *pnhc;
308
309 memcpy(&lookup.nexthop, nhop, sizeof(*nhop));
310 pnhc = hash_lookup(pnhgc->nhh, &lookup);
311 if (!pnhc) {
312 pnhc = hash_get(pnhgc->nhh, &lookup, pbr_nh_alloc);
313 pnhc->parent = pnhgc;
314 }
315 }
316 pbr_nht_install_nexthop_group(pnhgc, nhgc->nhg);
317}
318
319char *pbr_nht_nexthop_make_name(char *name, size_t l,
320 uint32_t seqno, char *buffer)
321{
322 snprintf(buffer, l, "%s%u", name, seqno);
323 return buffer;
324}
325
326static void *pbr_nhgc_alloc(void *p)
327{
328 struct pbr_nexthop_group_cache *new;
329 struct pbr_nexthop_group_cache *pnhgc =
330 (struct pbr_nexthop_group_cache *)p;
331
332 new = XCALLOC(MTYPE_PBR_NHG, sizeof(*new));
333
334 strcpy(new->name, pnhgc->name);
335 new->table_id = pbr_nht_get_next_tableid();
336
337 DEBUGD(&pbr_dbg_nht, "%s: NHT: %s assigned Table ID: %u",
338 __PRETTY_FUNCTION__, new->name, new->table_id);
339
340 new->nhh = hash_create_size(8, pbr_nh_hash_key, pbr_nh_hash_equal,
341 "PBR NH Cache Hash");
342 return new;
343}
344
345void pbr_nht_add_individual_nexthop(const char *name, uint32_t seqno)
346{
347 struct pbr_nexthop_group_cache *pnhgc;
348 struct pbr_nexthop_group_cache find;
349 struct pbr_nexthop_cache *pnhc;
350 struct pbr_map_sequence *pbrms;
351 struct pbr_nexthop_cache lookup;
352
353 pbrms = pbrms_get(name, seqno);
354
355 memset(&find, 0, sizeof(find));
356 pbr_nht_nexthop_make_name(pbrms->parent->name, PBR_MAP_NAMELEN,
357 pbrms->seqno, find.name);
358 if (!pbrms->internal_nhg_name)
359 pbrms->internal_nhg_name = XSTRDUP(MTYPE_TMP, find.name);
360
361 pnhgc = hash_get(pbr_nhg_hash, &find, pbr_nhgc_alloc);
362
363 memcpy(&lookup.nexthop, pbrms->nhg->nexthop, sizeof(struct nexthop));
364 pnhc = hash_get(pnhgc->nhh, &lookup, pbr_nh_alloc);
365 pnhc->parent = pnhgc;
366 pbr_nht_install_nexthop_group(pnhgc, *pbrms->nhg);
367}
368
369void pbr_nht_delete_individual_nexthop(const char *name, uint32_t seqno)
370{
371 struct pbr_nexthop_group_cache *pnhgc;
372 struct pbr_nexthop_group_cache find;
373 struct pbr_nexthop_cache *pnhc;
374 struct pbr_nexthop_cache lup;
375 struct pbr_map_sequence *pbrms;
376 struct nexthop *nh;
377
378 pbrms = pbrms_get(name, seqno);
379
380 memset(&find, 0, sizeof(find));
381 strcpy(&find.name[0], pbrms->internal_nhg_name);
382 pnhgc = hash_lookup(pbr_nhg_hash, &find);
383
384 nh = pbrms->nhg->nexthop;
385 memcpy(&lup.nexthop, nh, sizeof(struct nexthop));
386 pnhc = hash_lookup(pnhgc->nhh, &lup);
387 pnhc->parent = NULL;
388 hash_release(pnhgc->nhh, pnhc);
389 pbr_nh_delete(&pnhc);
390 pbr_nht_uninstall_nexthop_group(pnhgc, *pbrms->nhg);
391
392 hash_release(pbr_nhg_hash, pnhgc);
393
394 nexthop_del(pbrms->nhg, nh);
395 nexthop_free(nh);
396 nexthop_group_delete(&pbrms->nhg);
397 XFREE(MTYPE_TMP, pbrms->internal_nhg_name);
398}
399
400void pbr_nht_add_group(const char *name)
401{
402 struct nexthop *nhop;
403 struct nexthop_group_cmd *nhgc;
404 struct pbr_nexthop_group_cache *pnhgc;
405 struct pbr_nexthop_group_cache lookup;
406
407 nhgc = nhgc_find(name);
408
409 if (!nhgc) {
410 zlog_warn("%s: Could not find group %s to add",
411 __PRETTY_FUNCTION__, name);
412 return;
413 }
414
415 strcpy(lookup.name, name);
416 pnhgc = hash_get(pbr_nhg_hash, &lookup, pbr_nhgc_alloc);
417 DEBUGD(&pbr_dbg_nht, "%s: Retrieved NHGC @ %p", __PRETTY_FUNCTION__,
418 pnhgc);
419
420 for (ALL_NEXTHOPS(nhgc->nhg, nhop)) {
421 struct pbr_nexthop_cache lookup;
422 struct pbr_nexthop_cache *pnhc;
423
424 memcpy(&lookup.nexthop, nhop, sizeof(*nhop));
425 pnhc = hash_lookup(pnhgc->nhh, &lookup);
426 if (!pnhc) {
427 pnhc = hash_get(pnhgc->nhh, &lookup, pbr_nh_alloc);
428 pnhc->parent = pnhgc;
429 }
430 }
431}
432
433void pbr_nht_delete_group(const char *name)
434{
435 struct pbr_map_sequence *pbrms;
436 struct listnode *snode;
437 struct pbr_map *pbrm;
438
439 RB_FOREACH (pbrm, pbr_map_entry_head, &pbr_maps) {
440 for (ALL_LIST_ELEMENTS_RO(pbrm->seqnumbers, snode, pbrms)) {
441 if (pbrms->nhgrp_name
442 && strcmp(pbrms->nhgrp_name, name) == 0) {
443 pbrms->reason |= PBR_MAP_INVALID_NO_NEXTHOPS;
444 pbrm->valid = false;
445 }
446 }
447 }
448}
449
450bool pbr_nht_nexthop_valid(struct nexthop_group *nhg)
451{
452 DEBUGD(&pbr_dbg_nht, "%s: %p", __PRETTY_FUNCTION__, nhg);
453 return true;
454}
455
456bool pbr_nht_nexthop_group_valid(const char *name)
457{
458 struct pbr_nexthop_group_cache *pnhgc;
459 struct pbr_nexthop_group_cache lookup;
460
461 DEBUGD(&pbr_dbg_nht, "%s: %s", __PRETTY_FUNCTION__, name);
462
463 strcpy(lookup.name, name);
464 pnhgc = hash_get(pbr_nhg_hash, &lookup, NULL);
465 if (!pnhgc)
466 return false;
467 DEBUGD(&pbr_dbg_nht, "%s: \t%d %d", __PRETTY_FUNCTION__, pnhgc->valid,
468 pnhgc->installed);
469 if (pnhgc->valid && pnhgc->installed)
470 return true;
471
472 return false;
473}
474
475struct pbr_nht_individual {
476 struct zapi_route *nhr;
477
478 uint32_t valid;
479};
480
481static void pbr_nht_individual_nexthop_update_lookup(struct hash_backet *b,
482 void *data)
483{
484 struct pbr_nexthop_cache *pnhc = b->data;
485 struct pbr_nht_individual *pnhi = data;
486 char buf[PREFIX_STRLEN];
487 bool old_valid;
488
489 old_valid = pnhc->valid;
490
491 switch (pnhi->nhr->prefix.family) {
492 case AF_INET:
493 if (pnhc->nexthop.gate.ipv4.s_addr
494 == pnhi->nhr->prefix.u.prefix4.s_addr)
495 pnhc->valid = !!pnhi->nhr->nexthop_num;
496 break;
497 case AF_INET6:
498 if (memcmp(&pnhc->nexthop.gate.ipv6,
499 &pnhi->nhr->prefix.u.prefix6, 16) == 0)
500 pnhc->valid = !!pnhi->nhr->nexthop_num;
501 break;
502 }
503
504 DEBUGD(&pbr_dbg_nht, "\tFound %s: old: %d new: %d",
505 prefix2str(&pnhi->nhr->prefix, buf, sizeof(buf)), old_valid,
506 pnhc->valid);
507
508 if (old_valid != pnhc->valid) {
509 struct pbr_event *pbre;
510
511 pbre = pbr_event_new(PBR_NH_CHANGED, pnhc->parent->name);
512
513 pbr_event_enqueue(pbre);
514 }
515
516 if (pnhc->valid)
517 pnhi->valid += 1;
518}
519
520static void pbr_nht_nexthop_update_lookup(struct hash_backet *b, void *data)
521{
522 struct pbr_nexthop_group_cache *pnhgc = b->data;
523 struct pbr_nht_individual pnhi;
524
525 pnhi.nhr = (struct zapi_route *)data;
526 pnhi.valid = 0;
527 hash_iterate(pnhgc->nhh, pbr_nht_individual_nexthop_update_lookup,
528 &pnhi);
529
530 /*
531 * If any of the specified nexthops are valid we are valid
532 */
533 pnhgc->valid = !!pnhi.valid;
534}
535
536void pbr_nht_nexthop_update(struct zapi_route *nhr)
537{
538 hash_iterate(pbr_nhg_hash, pbr_nht_nexthop_update_lookup, nhr);
539}
540
541static uint32_t pbr_nhg_hash_key(void *arg)
542{
543 struct pbr_nexthop_group_cache *nhgc =
544 (struct pbr_nexthop_group_cache *)arg;
545
546 return jhash(&nhgc->name, strlen(nhgc->name), 0x52c34a96);
547}
548
549static int pbr_nhg_hash_equal(const void *arg1, const void *arg2)
550{
551 const struct pbr_nexthop_group_cache *nhgc1 =
552 (const struct pbr_nexthop_group_cache *)arg1;
553 const struct pbr_nexthop_group_cache *nhgc2 =
554 (const struct pbr_nexthop_group_cache *)arg2;
555
556 return !strcmp(nhgc1->name, nhgc2->name);
557}
558
559
560uint32_t pbr_nht_get_next_tableid(void)
561{
562 uint32_t i;
563 bool found = false;
564
565 for (i = pbr_nhg_low_table; i <= pbr_nhg_high_table; i++) {
566 if (nhg_tableid[i] == false) {
567 found = true;
568 break;
569 }
570 }
571
572 if (found) {
573 nhg_tableid[i] = true;
574 return i;
575 } else
576 return 0;
577}
578
579void pbr_nht_set_tableid_range(uint32_t low, uint32_t high)
580{
581 pbr_nhg_low_table = low;
582 pbr_nhg_high_table = high;
583}
584
585void pbr_nht_write_table_range(struct vty *vty)
586{
587 if (pbr_nhg_low_table != PBR_NHT_DEFAULT_LOW_TABLEID
588 || pbr_nhg_high_table != PBR_NHT_DEFAULT_HIGH_TABLEID) {
589 vty_out(vty, "pbr table range %u %u\n", pbr_nhg_low_table,
590 pbr_nhg_high_table);
591 }
592}
593
594uint32_t pbr_nht_get_next_rule(uint32_t seqno)
595{
596 return seqno + pbr_nhg_low_rule - 1;
597}
598void pbr_nht_set_rule_range(uint32_t low, uint32_t high)
599{
600 pbr_nhg_low_rule = low;
601 pbr_nhg_high_rule = high;
602}
603
604void pbr_nht_write_rule_range(struct vty *vty)
605{
606 if (pbr_nhg_low_rule != PBR_NHT_DEFAULT_LOW_RULE
607 || pbr_nhg_high_rule != PBR_NHT_DEFAULT_HIGH_RULE) {
608 vty_out(vty, "pbr rule range %u %u\n", pbr_nhg_low_rule,
609 pbr_nhg_high_rule);
610 }
611}
612
613uint32_t pbr_nht_get_table(const char *name)
614{
615 struct pbr_nexthop_group_cache find;
616 struct pbr_nexthop_group_cache *pnhgc;
617
618 memset(&find, 0, sizeof(find));
619 strcpy(find.name, name);
620 pnhgc = hash_lookup(pbr_nhg_hash, &find);
621
622 if (!pnhgc) {
623 DEBUGD(&pbr_dbg_nht,
624 "%s: Could not find nexthop-group cache w/ name '%s'",
625 __PRETTY_FUNCTION__, name);
626 return 5000;
627 }
628
629 return pnhgc->table_id;
630}
631
632bool pbr_nht_get_installed(const char *name)
633{
634 struct pbr_nexthop_group_cache find;
635 struct pbr_nexthop_group_cache *pnhgc;
636
637 memset(&find, 0, sizeof(find));
638 strcpy(find.name, name);
639
640 pnhgc = hash_lookup(pbr_nhg_hash, &find);
641
642 if (!pnhgc) {
643 return false;
644 }
645
646 return pnhgc->installed;
647}
648
649static void pbr_nht_show_nhg_nexthops(struct hash_backet *b, void *data)
650{
651 struct pbr_nexthop_cache *pnhc = b->data;
652 struct vty *vty = data;
653
654 vty_out(vty, "\tValid: %d", pnhc->valid);
655 nexthop_group_write_nexthop(vty, &pnhc->nexthop);
656}
657
658struct pbr_nht_show {
659 struct vty *vty;
660 const char *name;
661};
662
663static void pbr_nht_show_nhg(struct hash_backet *b, void *data)
664{
665 struct pbr_nexthop_group_cache *pnhgc = b->data;
666 struct pbr_nht_show *pns = data;
667 struct vty *vty;
668
669 if (pns->name && strcmp(pns->name, pnhgc->name) != 0)
670 return;
671
672 vty = pns->vty;
673 vty_out(vty, "Nexthop-Group: %s Table: %u Valid: %d Installed: %d\n",
674 pnhgc->name, pnhgc->table_id, pnhgc->valid, pnhgc->installed);
675
676 hash_iterate(pnhgc->nhh, pbr_nht_show_nhg_nexthops, vty);
677}
678
679void pbr_nht_show_nexthop_group(struct vty *vty, const char *name)
680{
681 struct pbr_nht_show pns;
682
683 pns.vty = vty;
684 pns.name = name;
685
686 hash_iterate(pbr_nhg_hash, pbr_nht_show_nhg, &pns);
687}
688
689void pbr_nht_init(void)
690{
691 pbr_nhg_hash = hash_create_size(
692 16, pbr_nhg_hash_key, pbr_nhg_hash_equal, "PBR NHG Cache Hash");
693
694 pbr_nhg_low_table = PBR_NHT_DEFAULT_LOW_TABLEID;
695 pbr_nhg_high_table = PBR_NHT_DEFAULT_HIGH_TABLEID;
696 pbr_nhg_low_rule = PBR_NHT_DEFAULT_LOW_RULE;
697 pbr_nhg_high_rule = PBR_NHT_DEFAULT_HIGH_RULE;
698 memset(&nhg_tableid, 0, 65535 * sizeof(uint8_t));
699}