]> git.proxmox.com Git - mirror_frr.git/blame - pbrd/pbr_nht.c
lib: Note old ifindex on shutdown
[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>
50d89650
SW
24#include "nexthop_group.h"
25#include "nexthop_group_private.h"
e5c83d9b
DS
26#include <hash.h>
27#include <jhash.h>
28#include <vty.h>
29#include <zclient.h>
b13e5ad6 30#include <debug.h>
e5c83d9b
DS
31
32#include "pbrd/pbr_nht.h"
33#include "pbrd/pbr_map.h"
e5c83d9b
DS
34#include "pbrd/pbr_zebra.h"
35#include "pbrd/pbr_memory.h"
36#include "pbrd/pbr_debug.h"
37
38DEFINE_MTYPE_STATIC(PBRD, PBR_NHG, "PBR Nexthop Groups")
39
fcf29c69 40struct hash *pbr_nhg_hash;
b13e5ad6 41static struct hash *pbr_nhrc_hash;
e5c83d9b
DS
42
43static uint32_t pbr_nhg_low_table;
44static uint32_t pbr_nhg_high_table;
45static uint32_t pbr_nhg_low_rule;
46static uint32_t pbr_nhg_high_rule;
47static bool nhg_tableid[65535];
48
b13e5ad6
DS
49static void pbr_nht_install_nexthop_group(struct pbr_nexthop_group_cache *pnhgc,
50 struct nexthop_group nhg);
ff9799c3
DS
51static void
52pbr_nht_uninstall_nexthop_group(struct pbr_nexthop_group_cache *pnhgc,
53 struct nexthop_group nhg,
aafac994 54 enum nexthop_types_t nh_type);
b13e5ad6
DS
55
56/*
57 * Nexthop refcount.
58 */
59struct nhrc {
60 struct nexthop nexthop;
61 unsigned int refcount;
62};
63
64/* Hash functions for pbr_nhrc_hash ---------------------------------------- */
65
66static 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;
ad9255f8
SW
70 nhrc->nexthop.next = NULL;
71 nhrc->nexthop.prev = NULL;
b13e5ad6
DS
72 return nhrc;
73}
74
74df8d6d 75static bool pbr_nhrc_hash_equal(const void *arg1, const void *arg2)
b13e5ad6
DS
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
e5c83d9b
DS
87static void *pbr_nh_alloc(void *p)
88{
89 struct pbr_nexthop_cache *new;
90 struct pbr_nexthop_cache *pnhc = (struct pbr_nexthop_cache *)p;
b13e5ad6 91 struct nhrc *nhrc;
e5c83d9b
DS
92
93 new = XCALLOC(MTYPE_PBR_NHG, sizeof(*new));
b13e5ad6
DS
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;
e5c83d9b 99
15569c58 100 DEBUGD(&pbr_dbg_nht, "%s: Sending nexthop to Zebra", __func__);
e5c83d9b 101
b13e5ad6 102 pbr_send_rnh(new->nexthop, true);
e5c83d9b
DS
103
104 new->valid = false;
105 return new;
106}
107
108static void pbr_nh_delete(struct pbr_nexthop_cache **pnhc)
109{
b13e5ad6
DS
110 struct nhrc *nhrc;
111
112 nhrc = hash_lookup(pbr_nhrc_hash, (*pnhc)->nexthop);
113
114 if (nhrc)
115 --nhrc->refcount;
116 if (!nhrc || nhrc->refcount == 0) {
117 DEBUGD(&pbr_dbg_nht, "%s: Removing nexthop from Zebra",
15569c58 118 __func__);
b13e5ad6
DS
119 pbr_send_rnh((*pnhc)->nexthop, false);
120 }
121 if (nhrc && nhrc->refcount == 0) {
122 hash_release(pbr_nhrc_hash, nhrc);
123 XFREE(MTYPE_PBR_NHG, nhrc);
124 }
e5c83d9b
DS
125
126 XFREE(MTYPE_PBR_NHG, *pnhc);
127}
128
e3b78da8 129static void pbr_nh_delete_iterate(struct hash_bucket *b, void *p)
b13e5ad6
DS
130{
131 pbr_nh_delete((struct pbr_nexthop_cache **)&b->data);
132}
133
d8b87afe 134static uint32_t pbr_nh_hash_key(const void *arg)
e5c83d9b
DS
135{
136 uint32_t key;
d8b87afe 137 const struct pbr_nexthop_cache *pbrnc = arg;
e5c83d9b 138
b13e5ad6 139 key = nexthop_hash(pbrnc->nexthop);
e5c83d9b
DS
140
141 return key;
142}
143
74df8d6d 144static bool pbr_nh_hash_equal(const void *arg1, const void *arg2)
e5c83d9b
DS
145{
146 const struct pbr_nexthop_cache *pbrnc1 =
147 (const struct pbr_nexthop_cache *)arg1;
148 const struct pbr_nexthop_cache *pbrnc2 =
149 (const struct pbr_nexthop_cache *)arg2;
150
b13e5ad6 151 if (pbrnc1->nexthop->vrf_id != pbrnc2->nexthop->vrf_id)
74df8d6d 152 return false;
e5c83d9b 153
b13e5ad6 154 if (pbrnc1->nexthop->ifindex != pbrnc2->nexthop->ifindex)
74df8d6d 155 return false;
e5c83d9b 156
b13e5ad6 157 if (pbrnc1->nexthop->type != pbrnc2->nexthop->type)
74df8d6d 158 return false;
e5c83d9b 159
b13e5ad6 160 switch (pbrnc1->nexthop->type) {
e5c83d9b 161 case NEXTHOP_TYPE_IFINDEX:
a106a408 162 return pbrnc1->nexthop->ifindex == pbrnc2->nexthop->ifindex;
e5c83d9b
DS
163 case NEXTHOP_TYPE_IPV4_IFINDEX:
164 case NEXTHOP_TYPE_IPV4:
b13e5ad6
DS
165 return pbrnc1->nexthop->gate.ipv4.s_addr
166 == pbrnc2->nexthop->gate.ipv4.s_addr;
e5c83d9b
DS
167 case NEXTHOP_TYPE_IPV6_IFINDEX:
168 case NEXTHOP_TYPE_IPV6:
f24f3450
RW
169 return !memcmp(&pbrnc1->nexthop->gate.ipv6,
170 &pbrnc2->nexthop->gate.ipv6, 16);
e5c83d9b 171 case NEXTHOP_TYPE_BLACKHOLE:
b13e5ad6 172 return pbrnc1->nexthop->bh_type == pbrnc2->nexthop->bh_type;
e5c83d9b
DS
173 }
174
175 /*
176 * We should not get here
177 */
74df8d6d 178 return false;
e5c83d9b
DS
179}
180
b13e5ad6
DS
181static void pbr_nhgc_delete(struct pbr_nexthop_group_cache *p)
182{
183 hash_iterate(p->nhh, pbr_nh_delete_iterate, NULL);
184 hash_free(p->nhh);
185 XFREE(MTYPE_PBR_NHG, p);
186}
187
188static void *pbr_nhgc_alloc(void *p)
189{
190 struct pbr_nexthop_group_cache *new;
191 struct pbr_nexthop_group_cache *pnhgc =
192 (struct pbr_nexthop_group_cache *)p;
193
194 new = XCALLOC(MTYPE_PBR_NHG, sizeof(*new));
195
65b88efa 196 strlcpy(new->name, pnhgc->name, sizeof(pnhgc->name));
a4044dc1 197 new->table_id = pbr_nht_get_next_tableid(false);
b13e5ad6 198
15569c58
DA
199 DEBUGD(&pbr_dbg_nht, "%s: NHT: %s assigned Table ID: %u", __func__,
200 new->name, new->table_id);
b13e5ad6
DS
201
202 new->nhh = hash_create_size(8, pbr_nh_hash_key, pbr_nh_hash_equal,
203 "PBR NH Cache Hash");
204 return new;
205}
206
207
e5c83d9b
DS
208void pbr_nhgroup_add_cb(const char *name)
209{
b13e5ad6
DS
210 struct pbr_nexthop_group_cache *pnhgc;
211 struct nexthop_group_cmd *nhgc;
e5c83d9b 212
b13e5ad6 213 nhgc = nhgc_find(name);
68a63f60
QY
214
215 if (!nhgc) {
216 DEBUGD(&pbr_dbg_nht, "%s: Could not find nhgc with name: %s\n",
15569c58 217 __func__, name);
68a63f60
QY
218 return;
219 }
220
b13e5ad6 221 pnhgc = pbr_nht_add_group(name);
e5c83d9b 222
a4044dc1
QY
223 if (!pnhgc)
224 return;
225
15569c58 226 DEBUGD(&pbr_dbg_nht, "%s: Added nexthop-group %s", __func__, name);
b13e5ad6 227
b13e5ad6 228 pbr_map_check_nh_group_change(name);
e5c83d9b
DS
229}
230
b13e5ad6 231void pbr_nhgroup_add_nexthop_cb(const struct nexthop_group_cmd *nhgc,
e5c83d9b
DS
232 const struct nexthop *nhop)
233{
b13e5ad6 234 char debugstr[256];
3e300703 235 struct pbr_nexthop_group_cache pnhgc_find = {};
b13e5ad6 236 struct pbr_nexthop_group_cache *pnhgc;
3e300703 237 struct pbr_nexthop_cache pnhc_find = {};
b13e5ad6
DS
238 struct pbr_nexthop_cache *pnhc;
239
a4044dc1
QY
240 if (!pbr_nht_get_next_tableid(true)) {
241 zlog_warn(
242 "%s: Exhausted all table identifiers; cannot create nexthop-group cache for nexthop-group '%s'",
15569c58 243 __func__, nhgc->name);
a4044dc1
QY
244 return;
245 }
246
b13e5ad6
DS
247 /* find pnhgc by name */
248 strlcpy(pnhgc_find.name, nhgc->name, sizeof(pnhgc_find.name));
249 pnhgc = hash_get(pbr_nhg_hash, &pnhgc_find, pbr_nhgc_alloc);
e5c83d9b 250
b13e5ad6
DS
251 /* create & insert new pnhc into pnhgc->nhh */
252 pnhc_find.nexthop = (struct nexthop *)nhop;
253 pnhc = hash_get(pnhgc->nhh, &pnhc_find, pbr_nh_alloc);
254 pnhc_find.nexthop = NULL;
255
256 /* set parent pnhgc */
257 pnhc->parent = pnhgc;
e5c83d9b 258
b13e5ad6
DS
259 if (DEBUG_MODE_CHECK(&pbr_dbg_nht, DEBUG_MODE_ALL)) {
260 nexthop2str(nhop, debugstr, sizeof(debugstr));
261 DEBUGD(&pbr_dbg_nht, "%s: Added %s to nexthop-group %s",
15569c58 262 __func__, debugstr, nhgc->name);
b13e5ad6
DS
263 }
264
265 pbr_nht_install_nexthop_group(pnhgc, nhgc->nhg);
266 pbr_map_check_nh_group_change(nhgc->name);
a106a408 267
cb254f41
SW
268 if (nhop->type == NEXTHOP_TYPE_IFINDEX
269 || (nhop->type == NEXTHOP_TYPE_IPV6_IFINDEX
270 && IN6_IS_ADDR_LINKLOCAL(&nhop->gate.ipv6))) {
a106a408
RW
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 }
e5c83d9b
DS
277}
278
b13e5ad6 279void pbr_nhgroup_del_nexthop_cb(const struct nexthop_group_cmd *nhgc,
e5c83d9b
DS
280 const struct nexthop *nhop)
281{
b13e5ad6 282 char debugstr[256];
3e300703 283 struct pbr_nexthop_group_cache pnhgc_find = {};
b13e5ad6 284 struct pbr_nexthop_group_cache *pnhgc;
3e300703 285 struct pbr_nexthop_cache pnhc_find = {};
b13e5ad6 286 struct pbr_nexthop_cache *pnhc;
aafac994 287 enum nexthop_types_t nh_type = nhop->type;
b13e5ad6
DS
288
289 /* find pnhgc by name */
290 strlcpy(pnhgc_find.name, nhgc->name, sizeof(pnhgc_find.name));
a4044dc1 291 pnhgc = hash_lookup(pbr_nhg_hash, &pnhgc_find);
b13e5ad6
DS
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);
e5c83d9b 299
b13e5ad6
DS
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",
15569c58 303 __func__, debugstr, nhgc->name);
b13e5ad6 304 }
e5c83d9b 305
ff9799c3
DS
306 if (pnhgc->nhh->count)
307 pbr_nht_install_nexthop_group(pnhgc, nhgc->nhg);
308 else
aafac994 309 pbr_nht_uninstall_nexthop_group(pnhgc, nhgc->nhg, nh_type);
ff9799c3 310
b13e5ad6 311 pbr_map_check_nh_group_change(nhgc->name);
e5c83d9b
DS
312}
313
314void pbr_nhgroup_delete_cb(const char *name)
315{
15569c58 316 DEBUGD(&pbr_dbg_nht, "%s: Removed nexthop-group %s", __func__, name);
b13e5ad6 317
ff9799c3
DS
318 /* delete group from all pbrms's */
319 pbr_nht_delete_group(name);
320
b13e5ad6 321 pbr_map_check_nh_group_change(name);
e5c83d9b
DS
322}
323
324#if 0
325static struct pbr_nexthop_cache *pbr_nht_lookup_nexthop(struct nexthop *nexthop)
326{
327 return NULL;
328}
329#endif
330
09813729
SW
331static void
332pbr_nht_find_nhg_from_table_update(struct pbr_nexthop_group_cache *pnhgc,
333 uint32_t table_id, bool installed)
334{
335 if (pnhgc->table_id == table_id) {
336 DEBUGD(&pbr_dbg_nht, "%s: %s: Table ID (%u) matches %s",
337 __func__, (installed ? "install" : "remove"), table_id,
338 pnhgc->name);
339
340 pnhgc->installed = installed;
341 pnhgc->valid = installed;
342 pbr_map_schedule_policy_from_nhg(pnhgc->name, pnhgc->installed);
343 }
344}
345
e3b78da8 346static void pbr_nht_find_nhg_from_table_install(struct hash_bucket *b,
e5c83d9b
DS
347 void *data)
348{
349 struct pbr_nexthop_group_cache *pnhgc =
350 (struct pbr_nexthop_group_cache *)b->data;
09813729
SW
351 uint32_t table_id = *(uint32_t *)data;
352
353 pbr_nht_find_nhg_from_table_update(pnhgc, table_id, true);
e5c83d9b
DS
354}
355
356void 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
e3b78da8 362static void pbr_nht_find_nhg_from_table_remove(struct hash_bucket *b,
e5c83d9b
DS
363 void *data)
364{
09813729
SW
365 struct pbr_nexthop_group_cache *pnhgc =
366 (struct pbr_nexthop_group_cache *)b->data;
367 uint32_t table_id = *(uint32_t *)data;
368
369 pbr_nht_find_nhg_from_table_update(pnhgc, table_id, false);
e5c83d9b
DS
370}
371
372void pbr_nht_route_removed_for_table(uint32_t table_id)
373{
374 hash_iterate(pbr_nhg_hash, pbr_nht_find_nhg_from_table_remove,
375 &table_id);
376}
377
378/*
379 * Loop through all nexthops in a nexthop group to check that they are all the
380 * same. If they are not all the same, log this peculiarity.
381 *
382 * nhg
383 * The nexthop group to check
384 *
385 * Returns:
386 * - AFI of last nexthop in the group
387 * - AFI_MAX on error
388 */
ff9799c3 389static afi_t pbr_nht_which_afi(struct nexthop_group nhg,
aafac994 390 enum nexthop_types_t nh_type)
e5c83d9b
DS
391{
392 struct nexthop *nexthop;
393 afi_t install_afi = AFI_MAX;
394 bool v6, v4, bh;
d3765386 395
268c24ee
RW
396 if (nh_type) {
397 switch (nh_type) {
398 case NEXTHOP_TYPE_IPV4:
399 case NEXTHOP_TYPE_IPV4_IFINDEX:
400 return AFI_IP;
401 case NEXTHOP_TYPE_IPV6:
402 case NEXTHOP_TYPE_IPV6_IFINDEX:
403 return AFI_IP6;
404 case NEXTHOP_TYPE_IFINDEX:
405 case NEXTHOP_TYPE_BLACKHOLE:
406 return AFI_MAX;
407 }
408 }
409
e5c83d9b
DS
410 v6 = v4 = bh = false;
411
268c24ee
RW
412 for (ALL_NEXTHOPS(nhg, nexthop)) {
413 nh_type = nexthop->type;
414
415 switch (nh_type) {
416 case NEXTHOP_TYPE_IFINDEX:
417 break;
418 case NEXTHOP_TYPE_IPV4:
419 case NEXTHOP_TYPE_IPV4_IFINDEX:
420 v6 = true;
421 install_afi = AFI_IP;
422 break;
423 case NEXTHOP_TYPE_IPV6:
424 case NEXTHOP_TYPE_IPV6_IFINDEX:
425 v4 = true;
426 install_afi = AFI_IP6;
427 break;
428 case NEXTHOP_TYPE_BLACKHOLE:
429 bh = true;
e5c83d9b
DS
430 break;
431 }
432 }
433
268c24ee
RW
434 /* Interface and/or blackhole nexthops only. */
435 if (!v4 && !v6)
ff9799c3 436 install_afi = AFI_MAX;
ff9799c3 437
e5c83d9b
DS
438 if (!bh && v6 && v4)
439 DEBUGD(&pbr_dbg_nht,
5e81f5dd
DS
440 "%s: Saw both V6 and V4 nexthops...using %s", __func__,
441 afi2str(install_afi));
e5c83d9b
DS
442 if (bh && (v6 || v4))
443 DEBUGD(&pbr_dbg_nht,
444 "%s: Saw blackhole nexthop(s) with %s%s%s nexthop(s), using AFI_MAX.",
5e81f5dd
DS
445 __func__, v4 ? "v4" : "", (v4 && v6) ? " and " : "",
446 v6 ? "v6" : "");
e5c83d9b
DS
447
448 return install_afi;
449}
450
451static void pbr_nht_install_nexthop_group(struct pbr_nexthop_group_cache *pnhgc,
452 struct nexthop_group nhg)
453{
454 afi_t install_afi;
aafac994 455 enum nexthop_types_t nh_type = 0;
e5c83d9b 456
aafac994 457 install_afi = pbr_nht_which_afi(nhg, nh_type);
e5c83d9b 458
e5c83d9b
DS
459 route_add(pnhgc, nhg, install_afi);
460}
461
462static void
463pbr_nht_uninstall_nexthop_group(struct pbr_nexthop_group_cache *pnhgc,
ff9799c3 464 struct nexthop_group nhg,
aafac994 465 enum nexthop_types_t nh_type)
e5c83d9b
DS
466{
467 afi_t install_afi;
468
aafac994 469 install_afi = pbr_nht_which_afi(nhg, nh_type);
e5c83d9b
DS
470
471 pnhgc->installed = false;
472 pnhgc->valid = false;
473 route_delete(pnhgc, install_afi);
474}
475
476void pbr_nht_change_group(const char *name)
477{
478 struct nexthop_group_cmd *nhgc;
479 struct pbr_nexthop_group_cache *pnhgc;
480 struct pbr_nexthop_group_cache find;
481 struct nexthop *nhop;
482
483 nhgc = nhgc_find(name);
484 if (!nhgc)
485 return;
486
487 memset(&find, 0, sizeof(find));
6612590d 488 snprintf(find.name, sizeof(find.name), "%s", name);
e5c83d9b
DS
489 pnhgc = hash_lookup(pbr_nhg_hash, &find);
490
491 if (!pnhgc) {
492 DEBUGD(&pbr_dbg_nht,
493 "%s: Could not find nexthop-group cache w/ name '%s'",
5e81f5dd 494 __func__, name);
e5c83d9b
DS
495 return;
496 }
497
498 for (ALL_NEXTHOPS(nhgc->nhg, nhop)) {
499 struct pbr_nexthop_cache lookup;
500 struct pbr_nexthop_cache *pnhc;
501
b13e5ad6 502 lookup.nexthop = nhop;
e5c83d9b
DS
503 pnhc = hash_lookup(pnhgc->nhh, &lookup);
504 if (!pnhc) {
505 pnhc = hash_get(pnhgc->nhh, &lookup, pbr_nh_alloc);
506 pnhc->parent = pnhgc;
507 }
508 }
509 pbr_nht_install_nexthop_group(pnhgc, nhgc->nhg);
510}
511
512char *pbr_nht_nexthop_make_name(char *name, size_t l,
513 uint32_t seqno, char *buffer)
514{
515 snprintf(buffer, l, "%s%u", name, seqno);
516 return buffer;
517}
518
f143cffa
SW
519void pbr_nht_add_individual_nexthop(struct pbr_map_sequence *pbrms,
520 const struct nexthop *nhop)
e5c83d9b
DS
521{
522 struct pbr_nexthop_group_cache *pnhgc;
523 struct pbr_nexthop_group_cache find;
524 struct pbr_nexthop_cache *pnhc;
e5c83d9b 525 struct pbr_nexthop_cache lookup;
f143cffa
SW
526 struct nexthop *nh;
527 char buf[PBR_NHC_NAMELEN];
528
529 pbrms->nhg = nexthop_group_new();
530 pbrms->internal_nhg_name = XSTRDUP(
531 MTYPE_TMP,
532 pbr_nht_nexthop_make_name(pbrms->parent->name, PBR_NHC_NAMELEN,
533 pbrms->seqno, buf));
534
535 nh = nexthop_new();
536 memcpy(nh, nhop, sizeof(*nh));
537
538 nexthop_group_add_sorted(pbrms->nhg, nh);
e5c83d9b 539
e5c83d9b 540 memset(&find, 0, sizeof(find));
06210d1f 541 pbr_nht_nexthop_make_name(pbrms->parent->name, PBR_NHC_NAMELEN,
e5c83d9b 542 pbrms->seqno, find.name);
a4044dc1
QY
543
544 if (!pbr_nht_get_next_tableid(true)) {
545 zlog_warn(
546 "%s: Exhausted all table identifiers; cannot create nexthop-group cache for nexthop-group '%s'",
15569c58 547 __func__, find.name);
a4044dc1
QY
548 return;
549 }
550
e5c83d9b
DS
551 if (!pbrms->internal_nhg_name)
552 pbrms->internal_nhg_name = XSTRDUP(MTYPE_TMP, find.name);
553
554 pnhgc = hash_get(pbr_nhg_hash, &find, pbr_nhgc_alloc);
555
b13e5ad6 556 lookup.nexthop = pbrms->nhg->nexthop;
e5c83d9b
DS
557 pnhc = hash_get(pnhgc->nhh, &lookup, pbr_nh_alloc);
558 pnhc->parent = pnhgc;
fcf29c69
DS
559 if (nhop->vrf_id != VRF_DEFAULT) {
560 struct vrf *vrf = vrf_lookup_by_id(nhop->vrf_id);
561
562 if (vrf)
563 strlcpy(pnhc->vrf_name, vrf->name,
564 sizeof(pnhc->vrf_name));
565 }
7cbdabff
DS
566
567 if (nhop->ifindex != 0) {
568 struct interface *ifp =
569 if_lookup_by_index(nhop->ifindex, nhop->vrf_id);
570
571 if (ifp)
572 strlcpy(pnhc->intf_name, ifp->name,
573 sizeof(pnhc->intf_name));
574 }
e5c83d9b
DS
575 pbr_nht_install_nexthop_group(pnhgc, *pbrms->nhg);
576}
577
f143cffa 578static void pbr_nht_release_individual_nexthop(struct pbr_map_sequence *pbrms)
e5c83d9b
DS
579{
580 struct pbr_nexthop_group_cache *pnhgc;
581 struct pbr_nexthop_group_cache find;
582 struct pbr_nexthop_cache *pnhc;
583 struct pbr_nexthop_cache lup;
e5c83d9b 584 struct nexthop *nh;
aafac994 585 enum nexthop_types_t nh_type = 0;
e5c83d9b 586
e5c83d9b 587 memset(&find, 0, sizeof(find));
6612590d 588 snprintf(find.name, sizeof(find.name), "%s", pbrms->internal_nhg_name);
e5c83d9b
DS
589 pnhgc = hash_lookup(pbr_nhg_hash, &find);
590
591 nh = pbrms->nhg->nexthop;
aafac994 592 nh_type = nh->type;
b13e5ad6 593 lup.nexthop = nh;
e5c83d9b
DS
594 pnhc = hash_lookup(pnhgc->nhh, &lup);
595 pnhc->parent = NULL;
596 hash_release(pnhgc->nhh, pnhc);
597 pbr_nh_delete(&pnhc);
aafac994 598 pbr_nht_uninstall_nexthop_group(pnhgc, *pbrms->nhg, nh_type);
e5c83d9b
DS
599
600 hash_release(pbr_nhg_hash, pnhgc);
1f375577 601 pbr_nhgc_delete(pnhgc);
e5c83d9b 602
e5c83d9b
DS
603 nexthop_group_delete(&pbrms->nhg);
604 XFREE(MTYPE_TMP, pbrms->internal_nhg_name);
605}
606
f143cffa
SW
607void pbr_nht_delete_individual_nexthop(struct pbr_map_sequence *pbrms)
608{
609 pbr_map_delete_nexthops(pbrms);
610
611 pbr_nht_release_individual_nexthop(pbrms);
612}
613
b13e5ad6 614struct pbr_nexthop_group_cache *pbr_nht_add_group(const char *name)
e5c83d9b
DS
615{
616 struct nexthop *nhop;
617 struct nexthop_group_cmd *nhgc;
618 struct pbr_nexthop_group_cache *pnhgc;
619 struct pbr_nexthop_group_cache lookup;
620
a4044dc1
QY
621 if (!pbr_nht_get_next_tableid(true)) {
622 zlog_warn(
623 "%s: Exhausted all table identifiers; cannot create nexthop-group cache for nexthop-group '%s'",
5e81f5dd 624 __func__, name);
a4044dc1
QY
625 return NULL;
626 }
627
e5c83d9b
DS
628 nhgc = nhgc_find(name);
629
630 if (!nhgc) {
a4044dc1 631 DEBUGD(&pbr_dbg_nht, "%s: Could not find nhgc with name: %s\n",
5e81f5dd 632 __func__, name);
b13e5ad6 633 return NULL;
e5c83d9b
DS
634 }
635
6612590d 636 snprintf(lookup.name, sizeof(lookup.name), "%s", name);
e5c83d9b 637 pnhgc = hash_get(pbr_nhg_hash, &lookup, pbr_nhgc_alloc);
5e81f5dd 638 DEBUGD(&pbr_dbg_nht, "%s: Retrieved NHGC @ %p", __func__, pnhgc);
e5c83d9b
DS
639
640 for (ALL_NEXTHOPS(nhgc->nhg, nhop)) {
7fe96307 641 struct pbr_nexthop_cache lookupc;
e5c83d9b
DS
642 struct pbr_nexthop_cache *pnhc;
643
7fe96307
A
644 lookupc.nexthop = nhop;
645 pnhc = hash_lookup(pnhgc->nhh, &lookupc);
e5c83d9b 646 if (!pnhc) {
7fe96307 647 pnhc = hash_get(pnhgc->nhh, &lookupc, pbr_nh_alloc);
e5c83d9b
DS
648 pnhc->parent = pnhgc;
649 }
650 }
b13e5ad6
DS
651
652 return pnhgc;
e5c83d9b
DS
653}
654
655void pbr_nht_delete_group(const char *name)
656{
657 struct pbr_map_sequence *pbrms;
658 struct listnode *snode;
659 struct pbr_map *pbrm;
b13e5ad6
DS
660 struct pbr_nexthop_group_cache pnhgc_find;
661 struct pbr_nexthop_group_cache *pnhgc;
e5c83d9b
DS
662
663 RB_FOREACH (pbrm, pbr_map_entry_head, &pbr_maps) {
664 for (ALL_LIST_ELEMENTS_RO(pbrm->seqnumbers, snode, pbrms)) {
665 if (pbrms->nhgrp_name
b13e5ad6 666 && strmatch(pbrms->nhgrp_name, name)) {
e5c83d9b 667 pbrms->reason |= PBR_MAP_INVALID_NO_NEXTHOPS;
b13e5ad6
DS
668 pbrms->nhg = NULL;
669 pbrms->internal_nhg_name = NULL;
e5c83d9b
DS
670 pbrm->valid = false;
671 }
672 }
673 }
b13e5ad6
DS
674
675 strlcpy(pnhgc_find.name, name, sizeof(pnhgc_find.name));
676 pnhgc = hash_release(pbr_nhg_hash, &pnhgc_find);
677 pbr_nhgc_delete(pnhgc);
e5c83d9b
DS
678}
679
680bool pbr_nht_nexthop_valid(struct nexthop_group *nhg)
681{
15569c58 682 DEBUGD(&pbr_dbg_nht, "%s: %p", __func__, nhg);
e5c83d9b
DS
683 return true;
684}
685
686bool pbr_nht_nexthop_group_valid(const char *name)
687{
688 struct pbr_nexthop_group_cache *pnhgc;
689 struct pbr_nexthop_group_cache lookup;
690
15569c58 691 DEBUGD(&pbr_dbg_nht, "%s: %s", __func__, name);
e5c83d9b 692
6612590d 693 snprintf(lookup.name, sizeof(lookup.name), "%s", name);
e5c83d9b
DS
694 pnhgc = hash_get(pbr_nhg_hash, &lookup, NULL);
695 if (!pnhgc)
696 return false;
15569c58 697 DEBUGD(&pbr_dbg_nht, "%s: \t%d %d", __func__, pnhgc->valid,
e5c83d9b
DS
698 pnhgc->installed);
699 if (pnhgc->valid && pnhgc->installed)
700 return true;
701
702 return false;
703}
704
705struct pbr_nht_individual {
706 struct zapi_route *nhr;
a106a408 707 struct interface *ifp;
fcf29c69
DS
708 struct pbr_vrf *pbr_vrf;
709 struct pbr_nexthop_cache *pnhc;
e5c83d9b
DS
710
711 uint32_t valid;
fcf29c69
DS
712
713 bool nhr_matched;
e5c83d9b
DS
714};
715
8babeb1a
SW
716static bool
717pbr_nht_individual_nexthop_gw_update(struct pbr_nexthop_cache *pnhc,
718 const struct pbr_nht_individual *pnhi)
e5c83d9b 719{
8babeb1a 720 bool is_valid = pnhc->valid;
e5c83d9b 721
8babeb1a
SW
722 if (!pnhi->nhr) /* It doesn't care about non-nexthop updates */
723 goto done;
e5c83d9b
DS
724
725 switch (pnhi->nhr->prefix.family) {
726 case AF_INET:
b13e5ad6 727 if (pnhc->nexthop->gate.ipv4.s_addr
8babeb1a
SW
728 != pnhi->nhr->prefix.u.prefix4.s_addr)
729 goto done; /* Unrelated change */
e5c83d9b
DS
730 break;
731 case AF_INET6:
b13e5ad6
DS
732 if (memcmp(&pnhc->nexthop->gate.ipv6,
733 &pnhi->nhr->prefix.u.prefix6, 16)
8babeb1a
SW
734 != 0)
735 goto done; /* Unrelated change */
736 break;
737 }
738
739 if (!pnhi->nhr->nexthop_num) {
740 is_valid = false;
741 goto done;
742 }
743
744 if (pnhc->nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX
4550d5df 745 || pnhc->nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX) {
8babeb1a
SW
746
747 /* GATEWAY_IFINDEX type shouldn't resolve to group */
748 if (pnhi->nhr->nexthop_num > 1) {
749 is_valid = false;
750 goto done;
751 }
752
753 /* If whatever we resolved to wasn't on the interface we
754 * specified. (i.e. not a connected route), its invalid.
755 */
756 if (pnhi->nhr->nexthops[0].ifindex != pnhc->nexthop->ifindex) {
757 is_valid = false;
758 goto done;
759 }
760 }
761
762 is_valid = true;
763
764done:
765 pnhc->valid = is_valid;
766
767 return pnhc->valid;
768}
769
770static bool pbr_nht_individual_nexthop_interface_update(
771 struct pbr_nexthop_cache *pnhc, const struct pbr_nht_individual *pnhi)
772{
773 bool is_valid = pnhc->valid;
774
775 if (!pnhi->ifp) /* It doesn't care about non-interface updates */
776 goto done;
777
778 if (pnhc->nexthop->ifindex
779 != pnhi->ifp->ifindex) /* Un-related interface */
780 goto done;
781
782 is_valid = !!if_is_up(pnhi->ifp);
783
784done:
785 pnhc->valid = is_valid;
786
787 return pnhc->valid;
788}
789
790/* Given this update either from interface or nexthop tracking, re-validate this
791 * nexthop.
792 *
793 * If the update is un-related, the subroutines shoud just return their cached
794 * valid state.
795 */
796static void
797pbr_nht_individual_nexthop_update(struct pbr_nexthop_cache *pnhc,
798 const struct pbr_nht_individual *pnhi)
799{
800 assert(pnhi->nhr || pnhi->ifp); /* Either nexthop or interface update */
801
802 switch (pnhc->nexthop->type) {
803 case NEXTHOP_TYPE_IFINDEX:
804 pbr_nht_individual_nexthop_interface_update(pnhc, pnhi);
805 break;
cb254f41
SW
806 case NEXTHOP_TYPE_IPV6_IFINDEX:
807 if (IN6_IS_ADDR_LINKLOCAL(&pnhc->nexthop->gate.ipv6)) {
808 pbr_nht_individual_nexthop_interface_update(pnhc, pnhi);
809 break;
810 }
811 /* Intentional fall thru */
812 case NEXTHOP_TYPE_IPV4_IFINDEX:
8babeb1a
SW
813 case NEXTHOP_TYPE_IPV4:
814 case NEXTHOP_TYPE_IPV6:
8babeb1a
SW
815 pbr_nht_individual_nexthop_gw_update(pnhc, pnhi);
816 break;
817 case NEXTHOP_TYPE_BLACKHOLE:
818 pnhc->valid = true;
e5c83d9b
DS
819 break;
820 }
8babeb1a
SW
821}
822
823static void pbr_nht_individual_nexthop_update_lookup(struct hash_bucket *b,
824 void *data)
825{
826 struct pbr_nexthop_cache *pnhc = b->data;
827 struct pbr_nht_individual *pnhi = data;
828 char buf[PREFIX_STRLEN];
829 bool old_valid;
830
831 old_valid = pnhc->valid;
832
833 pbr_nht_individual_nexthop_update(pnhc, pnhi);
e5c83d9b
DS
834
835 DEBUGD(&pbr_dbg_nht, "\tFound %s: old: %d new: %d",
836 prefix2str(&pnhi->nhr->prefix, buf, sizeof(buf)), old_valid,
837 pnhc->valid);
838
e5c83d9b
DS
839 if (pnhc->valid)
840 pnhi->valid += 1;
841}
842
b822b93a
SW
843static void pbr_nexthop_group_cache_iterate_to_group(struct hash_bucket *b,
844 void *data)
845{
846 struct pbr_nexthop_cache *pnhc = b->data;
847 struct nexthop_group *nhg = data;
848 struct nexthop *nh = NULL;
849
850 copy_nexthops(&nh, pnhc->nexthop, NULL);
851
50d89650 852 _nexthop_add(&nhg->nexthop, nh);
b822b93a
SW
853}
854
855static void
856pbr_nexthop_group_cache_to_nexthop_group(struct nexthop_group *nhg,
857 struct pbr_nexthop_group_cache *pnhgc)
858{
859 hash_iterate(pnhgc->nhh, pbr_nexthop_group_cache_iterate_to_group, nhg);
860}
861
e3b78da8 862static void pbr_nht_nexthop_update_lookup(struct hash_bucket *b, void *data)
e5c83d9b
DS
863{
864 struct pbr_nexthop_group_cache *pnhgc = b->data;
8babeb1a 865 struct pbr_nht_individual pnhi = {};
b822b93a 866 struct nexthop_group nhg = {};
b13e5ad6
DS
867 bool old_valid;
868
869 old_valid = pnhgc->valid;
e5c83d9b
DS
870
871 pnhi.nhr = (struct zapi_route *)data;
872 pnhi.valid = 0;
873 hash_iterate(pnhgc->nhh, pbr_nht_individual_nexthop_update_lookup,
874 &pnhi);
875
876 /*
877 * If any of the specified nexthops are valid we are valid
878 */
879 pnhgc->valid = !!pnhi.valid;
b13e5ad6 880
6db1188f
SW
881 pbr_nexthop_group_cache_to_nexthop_group(&nhg, pnhgc);
882
883 if (pnhgc->valid)
b822b93a 884 pbr_nht_install_nexthop_group(pnhgc, nhg);
6db1188f
SW
885 else
886 pbr_nht_uninstall_nexthop_group(pnhgc, nhg, 0);
887
888 /* Don't need copied nexthops anymore */
889 nexthops_free(nhg.nexthop);
b822b93a 890
b13e5ad6
DS
891 if (old_valid != pnhgc->valid)
892 pbr_map_check_nh_group_change(pnhgc->name);
e5c83d9b
DS
893}
894
895void pbr_nht_nexthop_update(struct zapi_route *nhr)
896{
897 hash_iterate(pbr_nhg_hash, pbr_nht_nexthop_update_lookup, nhr);
898}
899
fcf29c69
DS
900static void pbr_nht_individual_nexthop_vrf_handle(struct hash_bucket *b,
901 void *data)
902{
903 struct pbr_nexthop_cache *pnhc = b->data;
904 struct pbr_nht_individual *pnhi = data;
905
906 if (pnhc->nexthop->vrf_id == VRF_DEFAULT)
907 return;
908
909 if ((strncmp(pnhc->vrf_name, pbr_vrf_name(pnhi->pbr_vrf),
910 sizeof(pnhc->vrf_name))
911 == 0)
912 && pnhc->nexthop->vrf_id != pbr_vrf_id(pnhi->pbr_vrf)) {
913 pnhi->pnhc = pnhc;
914 pnhi->nhr_matched = true;
915 }
916}
917
918static void pbr_nht_nexthop_vrf_handle(struct hash_bucket *b, void *data)
919{
920 struct pbr_nexthop_group_cache *pnhgc = b->data;
921 struct pbr_vrf *pbr_vrf = data;
922 struct pbr_nht_individual pnhi = {};
923 struct nhrc *nhrc;
924 uint32_t old_vrf_id;
925
926 do {
927 memset(&pnhi, 0, sizeof(pnhi));
928 pnhi.pbr_vrf = pbr_vrf;
929 hash_iterate(pnhgc->nhh, pbr_nht_individual_nexthop_vrf_handle,
930 &pnhi);
931
932 if (!pnhi.pnhc)
933 continue;
934
935 pnhi.pnhc = hash_release(pnhgc->nhh, pnhi.pnhc);
936 old_vrf_id = pnhi.pnhc->nexthop->vrf_id;
937
938 nhrc = hash_lookup(pbr_nhrc_hash, pnhi.pnhc->nexthop);
939 if (nhrc) {
940 hash_release(pbr_nhrc_hash, nhrc);
941 nhrc->nexthop.vrf_id = pbr_vrf_id(pbr_vrf);
942 hash_get(pbr_nhrc_hash, nhrc, hash_alloc_intern);
943 pbr_send_rnh(pnhi.pnhc->nexthop, true);
944 }
945 pnhi.pnhc->nexthop->vrf_id = pbr_vrf_id(pbr_vrf);
946
947 hash_get(pnhgc->nhh, pnhi.pnhc, hash_alloc_intern);
948
949 pbr_map_check_vrf_nh_group_change(pnhgc->name, pbr_vrf,
950 old_vrf_id);
951 } while (pnhi.pnhc);
952}
953
954void pbr_nht_vrf_update(struct pbr_vrf *pbr_vrf)
955{
956 hash_iterate(pbr_nhg_hash, pbr_nht_nexthop_vrf_handle, pbr_vrf);
957}
958
7cbdabff
DS
959static void pbr_nht_individual_nexthop_interface_handle(struct hash_bucket *b,
960 void *data)
961{
962 struct pbr_nexthop_cache *pnhc = b->data;
963 struct pbr_nht_individual *pnhi = data;
964
965 if (pnhc->nexthop->ifindex == 0)
966 return;
967
968 if ((strncmp(pnhc->intf_name, pnhi->ifp->name, sizeof(pnhc->intf_name))
969 == 0)
970 && pnhc->nexthop->ifindex != pnhi->ifp->ifindex)
971 pnhi->pnhc = pnhc;
972}
973
974static void pbr_nht_nexthop_interface_handle(struct hash_bucket *b, void *data)
975{
976 struct pbr_nexthop_group_cache *pnhgc = b->data;
977 struct interface *ifp = data;
978 struct pbr_nht_individual pnhi = {};
979 struct nhrc *nhrc;
980 uint32_t old_ifindex;
981
982 do {
983 memset(&pnhi, 0, sizeof(pnhi));
984 pnhi.ifp = ifp;
985 hash_iterate(pnhgc->nhh,
986 pbr_nht_individual_nexthop_interface_handle,
987 &pnhi);
988
989 if (!pnhi.pnhc)
990 continue;
991
992 pnhi.pnhc = hash_release(pnhgc->nhh, pnhi.pnhc);
993 old_ifindex = pnhi.pnhc->nexthop->ifindex;
994
995 nhrc = hash_lookup(pbr_nhrc_hash, pnhi.pnhc->nexthop);
996 if (nhrc) {
997 hash_release(pbr_nhrc_hash, nhrc);
998 nhrc->nexthop.ifindex = ifp->ifindex;
999 hash_get(pbr_nhrc_hash, nhrc, hash_alloc_intern);
1000 }
1001 pnhi.pnhc->nexthop->ifindex = ifp->ifindex;
1002
1003 hash_get(pnhgc->nhh, pnhi.pnhc, hash_alloc_intern);
1004
1005 pbr_map_check_interface_nh_group_change(pnhgc->name, ifp,
1006 old_ifindex);
1007 } while (pnhi.pnhc);
1008}
1009
1010void pbr_nht_interface_update(struct interface *ifp)
1011{
1012 hash_iterate(pbr_nhg_hash, pbr_nht_nexthop_interface_handle, ifp);
1013}
1014
a106a408 1015static void
7f5818fb 1016pbr_nht_individual_nexthop_interface_update_lookup(struct hash_bucket *b,
a106a408
RW
1017 void *data)
1018{
1019 struct pbr_nexthop_cache *pnhc = b->data;
1020 struct pbr_nht_individual *pnhi = data;
1021 bool old_valid;
1022
1023 old_valid = pnhc->valid;
1024
8babeb1a 1025 pbr_nht_individual_nexthop_update(pnhc, pnhi);
a106a408
RW
1026
1027 DEBUGD(&pbr_dbg_nht, "\tFound %s: old: %d new: %d", pnhi->ifp->name,
1028 old_valid, pnhc->valid);
1029
1030 if (pnhc->valid)
1031 pnhi->valid += 1;
1032}
1033
7f5818fb 1034static void pbr_nht_nexthop_interface_update_lookup(struct hash_bucket *b,
a106a408
RW
1035 void *data)
1036{
1037 struct pbr_nexthop_group_cache *pnhgc = b->data;
8babeb1a 1038 struct pbr_nht_individual pnhi = {};
a106a408
RW
1039 bool old_valid;
1040
1041 old_valid = pnhgc->valid;
1042
1043 pnhi.ifp = data;
1044 pnhi.valid = 0;
1045 hash_iterate(pnhgc->nhh,
1046 pbr_nht_individual_nexthop_interface_update_lookup, &pnhi);
1047
1048 /*
1049 * If any of the specified nexthops are valid we are valid
1050 */
1051 pnhgc->valid = !!pnhi.valid;
1052
1053 if (old_valid != pnhgc->valid)
1054 pbr_map_check_nh_group_change(pnhgc->name);
1055}
1056
1057void pbr_nht_nexthop_interface_update(struct interface *ifp)
1058{
1059 hash_iterate(pbr_nhg_hash, pbr_nht_nexthop_interface_update_lookup,
1060 ifp);
1061}
1062
d8b87afe 1063static uint32_t pbr_nhg_hash_key(const void *arg)
e5c83d9b 1064{
d8b87afe 1065 const struct pbr_nexthop_group_cache *nhgc = arg;
e5c83d9b
DS
1066
1067 return jhash(&nhgc->name, strlen(nhgc->name), 0x52c34a96);
1068}
1069
74df8d6d 1070static bool pbr_nhg_hash_equal(const void *arg1, const void *arg2)
e5c83d9b
DS
1071{
1072 const struct pbr_nexthop_group_cache *nhgc1 =
1073 (const struct pbr_nexthop_group_cache *)arg1;
1074 const struct pbr_nexthop_group_cache *nhgc2 =
1075 (const struct pbr_nexthop_group_cache *)arg2;
1076
1077 return !strcmp(nhgc1->name, nhgc2->name);
1078}
1079
a4044dc1 1080uint32_t pbr_nht_get_next_tableid(bool peek)
e5c83d9b
DS
1081{
1082 uint32_t i;
1083 bool found = false;
1084
1085 for (i = pbr_nhg_low_table; i <= pbr_nhg_high_table; i++) {
d8729f8c 1086 if (!nhg_tableid[i]) {
e5c83d9b
DS
1087 found = true;
1088 break;
1089 }
1090 }
1091
1092 if (found) {
a4044dc1 1093 nhg_tableid[i] = !peek;
e5c83d9b
DS
1094 return i;
1095 } else
1096 return 0;
1097}
1098
1099void pbr_nht_set_tableid_range(uint32_t low, uint32_t high)
1100{
1101 pbr_nhg_low_table = low;
1102 pbr_nhg_high_table = high;
1103}
1104
1105void pbr_nht_write_table_range(struct vty *vty)
1106{
1107 if (pbr_nhg_low_table != PBR_NHT_DEFAULT_LOW_TABLEID
1108 || pbr_nhg_high_table != PBR_NHT_DEFAULT_HIGH_TABLEID) {
1109 vty_out(vty, "pbr table range %u %u\n", pbr_nhg_low_table,
1110 pbr_nhg_high_table);
1111 }
1112}
1113
1114uint32_t pbr_nht_get_next_rule(uint32_t seqno)
1115{
1116 return seqno + pbr_nhg_low_rule - 1;
1117}
1118void pbr_nht_set_rule_range(uint32_t low, uint32_t high)
1119{
1120 pbr_nhg_low_rule = low;
1121 pbr_nhg_high_rule = high;
1122}
1123
1124void pbr_nht_write_rule_range(struct vty *vty)
1125{
1126 if (pbr_nhg_low_rule != PBR_NHT_DEFAULT_LOW_RULE
1127 || pbr_nhg_high_rule != PBR_NHT_DEFAULT_HIGH_RULE) {
1128 vty_out(vty, "pbr rule range %u %u\n", pbr_nhg_low_rule,
1129 pbr_nhg_high_rule);
1130 }
1131}
1132
1133uint32_t pbr_nht_get_table(const char *name)
1134{
1135 struct pbr_nexthop_group_cache find;
1136 struct pbr_nexthop_group_cache *pnhgc;
1137
1138 memset(&find, 0, sizeof(find));
6612590d 1139 snprintf(find.name, sizeof(find.name), "%s", name);
e5c83d9b
DS
1140 pnhgc = hash_lookup(pbr_nhg_hash, &find);
1141
1142 if (!pnhgc) {
1143 DEBUGD(&pbr_dbg_nht,
1144 "%s: Could not find nexthop-group cache w/ name '%s'",
15569c58 1145 __func__, name);
e5c83d9b
DS
1146 return 5000;
1147 }
1148
1149 return pnhgc->table_id;
1150}
1151
1152bool pbr_nht_get_installed(const char *name)
1153{
1154 struct pbr_nexthop_group_cache find;
1155 struct pbr_nexthop_group_cache *pnhgc;
1156
1157 memset(&find, 0, sizeof(find));
6612590d 1158 snprintf(find.name, sizeof(find.name), "%s", name);
e5c83d9b
DS
1159
1160 pnhgc = hash_lookup(pbr_nhg_hash, &find);
1161
d3765386 1162 if (!pnhgc)
e5c83d9b 1163 return false;
e5c83d9b
DS
1164
1165 return pnhgc->installed;
1166}
1167
e3b78da8 1168static void pbr_nht_show_nhg_nexthops(struct hash_bucket *b, void *data)
e5c83d9b
DS
1169{
1170 struct pbr_nexthop_cache *pnhc = b->data;
1171 struct vty *vty = data;
1172
57cdafc4 1173 vty_out(vty, "\tValid: %d ", pnhc->valid);
b13e5ad6 1174 nexthop_group_write_nexthop(vty, pnhc->nexthop);
e5c83d9b
DS
1175}
1176
010dd8ed
WC
1177static void pbr_nht_json_nhg_nexthops(struct hash_bucket *b, void *data)
1178{
1179 struct pbr_nexthop_cache *pnhc = b->data;
1180 json_object *all_hops = data;
1181 json_object *this_hop;
1182
1183 this_hop = json_object_new_object();
010dd8ed 1184 nexthop_group_json_nexthop(this_hop, pnhc->nexthop);
3e81618d 1185 json_object_boolean_add(this_hop, "valid", pnhc->valid);
010dd8ed
WC
1186
1187 json_object_array_add(all_hops, this_hop);
1188}
1189
e5c83d9b
DS
1190struct pbr_nht_show {
1191 struct vty *vty;
010dd8ed 1192 json_object *json;
e5c83d9b
DS
1193 const char *name;
1194};
1195
e3b78da8 1196static void pbr_nht_show_nhg(struct hash_bucket *b, void *data)
e5c83d9b
DS
1197{
1198 struct pbr_nexthop_group_cache *pnhgc = b->data;
1199 struct pbr_nht_show *pns = data;
1200 struct vty *vty;
1201
1202 if (pns->name && strcmp(pns->name, pnhgc->name) != 0)
1203 return;
1204
1205 vty = pns->vty;
1206 vty_out(vty, "Nexthop-Group: %s Table: %u Valid: %d Installed: %d\n",
1207 pnhgc->name, pnhgc->table_id, pnhgc->valid, pnhgc->installed);
1208
1209 hash_iterate(pnhgc->nhh, pbr_nht_show_nhg_nexthops, vty);
1210}
1211
010dd8ed
WC
1212static void pbr_nht_json_nhg(struct hash_bucket *b, void *data)
1213{
1214 struct pbr_nexthop_group_cache *pnhgc = b->data;
1215 struct pbr_nht_show *pns = data;
1216 json_object *j, *this_group, *group_hops;
1217
1218 if (pns->name && strcmp(pns->name, pnhgc->name) != 0)
1219 return;
1220
1221 j = pns->json;
1222 this_group = json_object_new_object();
1223
1224 if (!j || !this_group)
1225 return;
1226
010dd8ed 1227 json_object_int_add(this_group, "id", pnhgc->table_id);
81c0078e 1228 json_object_string_add(this_group, "name", pnhgc->name);
3e81618d
WC
1229 json_object_boolean_add(this_group, "valid", pnhgc->valid);
1230 json_object_boolean_add(this_group, "installed", pnhgc->installed);
010dd8ed
WC
1231
1232 group_hops = json_object_new_array();
1233
1234 if (group_hops) {
1235 hash_iterate(pnhgc->nhh, pbr_nht_json_nhg_nexthops, group_hops);
1236 json_object_object_add(this_group, "nexthops", group_hops);
1237 }
1238
dadba1a2 1239 json_object_array_add(j, this_group);
010dd8ed
WC
1240}
1241
e5c83d9b
DS
1242void pbr_nht_show_nexthop_group(struct vty *vty, const char *name)
1243{
1244 struct pbr_nht_show pns;
1245
1246 pns.vty = vty;
1247 pns.name = name;
1248
1249 hash_iterate(pbr_nhg_hash, pbr_nht_show_nhg, &pns);
1250}
1251
010dd8ed
WC
1252void pbr_nht_json_nexthop_group(json_object *j, const char *name)
1253{
1254 struct pbr_nht_show pns;
1255
1256 pns.name = name;
1257 pns.json = j;
1258
1259 hash_iterate(pbr_nhg_hash, pbr_nht_json_nhg, &pns);
1260}
1261
e5c83d9b
DS
1262void pbr_nht_init(void)
1263{
1264 pbr_nhg_hash = hash_create_size(
1265 16, pbr_nhg_hash_key, pbr_nhg_hash_equal, "PBR NHG Cache Hash");
b13e5ad6 1266 pbr_nhrc_hash =
d8b87afe 1267 hash_create_size(16, (unsigned int (*)(const void *))nexthop_hash,
b13e5ad6 1268 pbr_nhrc_hash_equal, "PBR NH Hash");
e5c83d9b
DS
1269
1270 pbr_nhg_low_table = PBR_NHT_DEFAULT_LOW_TABLEID;
1271 pbr_nhg_high_table = PBR_NHT_DEFAULT_HIGH_TABLEID;
1272 pbr_nhg_low_rule = PBR_NHT_DEFAULT_LOW_RULE;
1273 pbr_nhg_high_rule = PBR_NHT_DEFAULT_HIGH_RULE;
1274 memset(&nhg_tableid, 0, 65535 * sizeof(uint8_t));
1275}