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