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