3 * Copyright (C) 2018 Cumulus Networks, Inc.
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
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.
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
24 #include "nexthop_group.h"
25 #include "nexthop_group_private.h"
32 #include "pbrd/pbr_nht.h"
33 #include "pbrd/pbr_map.h"
34 #include "pbrd/pbr_zebra.h"
35 #include "pbrd/pbr_memory.h"
36 #include "pbrd/pbr_debug.h"
38 DEFINE_MTYPE_STATIC(PBRD
, PBR_NHG
, "PBR Nexthop Groups")
40 static struct hash
*pbr_nhg_hash
;
41 static struct hash
*pbr_nhrc_hash
;
43 static uint32_t pbr_nhg_low_table
;
44 static uint32_t pbr_nhg_high_table
;
45 static uint32_t pbr_nhg_low_rule
;
46 static uint32_t pbr_nhg_high_rule
;
47 static bool nhg_tableid
[65535];
49 static void pbr_nht_install_nexthop_group(struct pbr_nexthop_group_cache
*pnhgc
,
50 struct nexthop_group nhg
);
52 pbr_nht_uninstall_nexthop_group(struct pbr_nexthop_group_cache
*pnhgc
,
53 struct nexthop_group nhg
,
54 enum nexthop_types_t nh_type
);
60 struct nexthop nexthop
;
61 unsigned int refcount
;
64 /* Hash functions for pbr_nhrc_hash ---------------------------------------- */
66 static void *pbr_nhrc_hash_alloc(void *p
)
68 struct nhrc
*nhrc
= XCALLOC(MTYPE_PBR_NHG
, sizeof(struct nhrc
));
69 nhrc
->nexthop
= *(struct nexthop
*)p
;
70 nhrc
->nexthop
.next
= NULL
;
71 nhrc
->nexthop
.prev
= NULL
;
75 static bool pbr_nhrc_hash_equal(const void *arg1
, const void *arg2
)
77 const struct nexthop
*nh1
, *nh2
;
82 return nexthop_same(nh1
, nh2
);
85 /* ------------------------------------------------------------------------- */
87 static void *pbr_nh_alloc(void *p
)
89 struct pbr_nexthop_cache
*new;
90 struct pbr_nexthop_cache
*pnhc
= (struct pbr_nexthop_cache
*)p
;
93 new = XCALLOC(MTYPE_PBR_NHG
, sizeof(*new));
94 nhrc
= hash_get(pbr_nhrc_hash
, pnhc
->nexthop
, pbr_nhrc_hash_alloc
);
95 new->nexthop
= &nhrc
->nexthop
;
97 /* Decremented again in pbr_nh_delete */
100 DEBUGD(&pbr_dbg_nht
, "%s: Sending nexthop to Zebra",
101 __PRETTY_FUNCTION__
);
103 pbr_send_rnh(new->nexthop
, true);
109 static void pbr_nh_delete(struct pbr_nexthop_cache
**pnhc
)
113 nhrc
= hash_lookup(pbr_nhrc_hash
, (*pnhc
)->nexthop
);
117 if (!nhrc
|| nhrc
->refcount
== 0) {
118 DEBUGD(&pbr_dbg_nht
, "%s: Removing nexthop from Zebra",
119 __PRETTY_FUNCTION__
);
120 pbr_send_rnh((*pnhc
)->nexthop
, false);
122 if (nhrc
&& nhrc
->refcount
== 0) {
123 hash_release(pbr_nhrc_hash
, nhrc
);
124 XFREE(MTYPE_PBR_NHG
, nhrc
);
127 XFREE(MTYPE_PBR_NHG
, *pnhc
);
130 static void pbr_nh_delete_iterate(struct hash_bucket
*b
, void *p
)
132 pbr_nh_delete((struct pbr_nexthop_cache
**)&b
->data
);
135 static uint32_t pbr_nh_hash_key(const void *arg
)
138 const struct pbr_nexthop_cache
*pbrnc
= arg
;
140 key
= nexthop_hash(pbrnc
->nexthop
);
145 static bool pbr_nh_hash_equal(const void *arg1
, const void *arg2
)
147 const struct pbr_nexthop_cache
*pbrnc1
=
148 (const struct pbr_nexthop_cache
*)arg1
;
149 const struct pbr_nexthop_cache
*pbrnc2
=
150 (const struct pbr_nexthop_cache
*)arg2
;
152 if (pbrnc1
->nexthop
->vrf_id
!= pbrnc2
->nexthop
->vrf_id
)
155 if (pbrnc1
->nexthop
->ifindex
!= pbrnc2
->nexthop
->ifindex
)
158 if (pbrnc1
->nexthop
->type
!= pbrnc2
->nexthop
->type
)
161 switch (pbrnc1
->nexthop
->type
) {
162 case NEXTHOP_TYPE_IFINDEX
:
163 return pbrnc1
->nexthop
->ifindex
== pbrnc2
->nexthop
->ifindex
;
164 case NEXTHOP_TYPE_IPV4_IFINDEX
:
165 case NEXTHOP_TYPE_IPV4
:
166 return pbrnc1
->nexthop
->gate
.ipv4
.s_addr
167 == pbrnc2
->nexthop
->gate
.ipv4
.s_addr
;
168 case NEXTHOP_TYPE_IPV6_IFINDEX
:
169 case NEXTHOP_TYPE_IPV6
:
170 return !memcmp(&pbrnc1
->nexthop
->gate
.ipv6
,
171 &pbrnc2
->nexthop
->gate
.ipv6
, 16);
172 case NEXTHOP_TYPE_BLACKHOLE
:
173 return pbrnc1
->nexthop
->bh_type
== pbrnc2
->nexthop
->bh_type
;
177 * We should not get here
182 static void pbr_nhgc_delete(struct pbr_nexthop_group_cache
*p
)
184 hash_iterate(p
->nhh
, pbr_nh_delete_iterate
, NULL
);
186 XFREE(MTYPE_PBR_NHG
, p
);
189 static void *pbr_nhgc_alloc(void *p
)
191 struct pbr_nexthop_group_cache
*new;
192 struct pbr_nexthop_group_cache
*pnhgc
=
193 (struct pbr_nexthop_group_cache
*)p
;
195 new = XCALLOC(MTYPE_PBR_NHG
, sizeof(*new));
197 strlcpy(new->name
, pnhgc
->name
, sizeof(pnhgc
->name
));
198 new->table_id
= pbr_nht_get_next_tableid(false);
200 DEBUGD(&pbr_dbg_nht
, "%s: NHT: %s assigned Table ID: %u",
201 __PRETTY_FUNCTION__
, new->name
, new->table_id
);
203 new->nhh
= hash_create_size(8, pbr_nh_hash_key
, pbr_nh_hash_equal
,
204 "PBR NH Cache Hash");
209 void pbr_nhgroup_add_cb(const char *name
)
211 struct pbr_nexthop_group_cache
*pnhgc
;
212 struct nexthop_group_cmd
*nhgc
;
214 nhgc
= nhgc_find(name
);
217 DEBUGD(&pbr_dbg_nht
, "%s: Could not find nhgc with name: %s\n",
218 __PRETTY_FUNCTION__
, name
);
222 pnhgc
= pbr_nht_add_group(name
);
227 DEBUGD(&pbr_dbg_nht
, "%s: Added nexthop-group %s", __PRETTY_FUNCTION__
,
230 pbr_nht_install_nexthop_group(pnhgc
, nhgc
->nhg
);
231 pbr_map_check_nh_group_change(name
);
234 void pbr_nhgroup_add_nexthop_cb(const struct nexthop_group_cmd
*nhgc
,
235 const struct nexthop
*nhop
)
238 struct pbr_nexthop_group_cache pnhgc_find
= {};
239 struct pbr_nexthop_group_cache
*pnhgc
;
240 struct pbr_nexthop_cache pnhc_find
= {};
241 struct pbr_nexthop_cache
*pnhc
;
243 if (!pbr_nht_get_next_tableid(true)) {
245 "%s: Exhausted all table identifiers; cannot create nexthop-group cache for nexthop-group '%s'",
246 __PRETTY_FUNCTION__
, nhgc
->name
);
250 /* find pnhgc by name */
251 strlcpy(pnhgc_find
.name
, nhgc
->name
, sizeof(pnhgc_find
.name
));
252 pnhgc
= hash_get(pbr_nhg_hash
, &pnhgc_find
, pbr_nhgc_alloc
);
254 /* create & insert new pnhc into pnhgc->nhh */
255 pnhc_find
.nexthop
= (struct nexthop
*)nhop
;
256 pnhc
= hash_get(pnhgc
->nhh
, &pnhc_find
, pbr_nh_alloc
);
257 pnhc_find
.nexthop
= NULL
;
259 /* set parent pnhgc */
260 pnhc
->parent
= pnhgc
;
262 if (DEBUG_MODE_CHECK(&pbr_dbg_nht
, DEBUG_MODE_ALL
)) {
263 nexthop2str(nhop
, debugstr
, sizeof(debugstr
));
264 DEBUGD(&pbr_dbg_nht
, "%s: Added %s to nexthop-group %s",
265 __PRETTY_FUNCTION__
, debugstr
, nhgc
->name
);
268 pbr_nht_install_nexthop_group(pnhgc
, nhgc
->nhg
);
269 pbr_map_check_nh_group_change(nhgc
->name
);
271 if (nhop
->type
== NEXTHOP_TYPE_IFINDEX
) {
272 struct interface
*ifp
;
274 ifp
= if_lookup_by_index(nhop
->ifindex
, nhop
->vrf_id
);
276 pbr_nht_nexthop_interface_update(ifp
);
280 void pbr_nhgroup_del_nexthop_cb(const struct nexthop_group_cmd
*nhgc
,
281 const struct nexthop
*nhop
)
284 struct pbr_nexthop_group_cache pnhgc_find
= {};
285 struct pbr_nexthop_group_cache
*pnhgc
;
286 struct pbr_nexthop_cache pnhc_find
= {};
287 struct pbr_nexthop_cache
*pnhc
;
288 enum nexthop_types_t nh_type
= nhop
->type
;
290 /* find pnhgc by name */
291 strlcpy(pnhgc_find
.name
, nhgc
->name
, sizeof(pnhgc_find
.name
));
292 pnhgc
= hash_lookup(pbr_nhg_hash
, &pnhgc_find
);
294 /* delete pnhc from pnhgc->nhh */
295 pnhc_find
.nexthop
= (struct nexthop
*)nhop
;
296 pnhc
= hash_release(pnhgc
->nhh
, &pnhc_find
);
299 pbr_nh_delete(&pnhc
);
301 if (DEBUG_MODE_CHECK(&pbr_dbg_nht
, DEBUG_MODE_ALL
)) {
302 nexthop2str(nhop
, debugstr
, sizeof(debugstr
));
303 DEBUGD(&pbr_dbg_nht
, "%s: Removed %s from nexthop-group %s",
304 __PRETTY_FUNCTION__
, debugstr
, nhgc
->name
);
307 if (pnhgc
->nhh
->count
)
308 pbr_nht_install_nexthop_group(pnhgc
, nhgc
->nhg
);
310 pbr_nht_uninstall_nexthop_group(pnhgc
, nhgc
->nhg
, nh_type
);
312 pbr_map_check_nh_group_change(nhgc
->name
);
315 void pbr_nhgroup_delete_cb(const char *name
)
317 DEBUGD(&pbr_dbg_nht
, "%s: Removed nexthop-group %s",
318 __PRETTY_FUNCTION__
, name
);
320 /* delete group from all pbrms's */
321 pbr_nht_delete_group(name
);
323 pbr_map_check_nh_group_change(name
);
327 static struct pbr_nexthop_cache
*pbr_nht_lookup_nexthop(struct nexthop
*nexthop
)
333 static void pbr_nht_find_nhg_from_table_install(struct hash_bucket
*b
,
336 struct pbr_nexthop_group_cache
*pnhgc
=
337 (struct pbr_nexthop_group_cache
*)b
->data
;
338 uint32_t *table_id
= (uint32_t *)data
;
340 if (pnhgc
->table_id
== *table_id
) {
341 DEBUGD(&pbr_dbg_nht
, "%s: Table ID (%u) matches %s",
342 __PRETTY_FUNCTION__
, *table_id
, pnhgc
->name
);
345 * If the table has been re-handled by zebra
346 * and we are already installed no need to do
349 if (!pnhgc
->installed
) {
350 pnhgc
->installed
= true;
351 pbr_map_schedule_policy_from_nhg(pnhgc
->name
);
356 void pbr_nht_route_installed_for_table(uint32_t table_id
)
358 hash_iterate(pbr_nhg_hash
, pbr_nht_find_nhg_from_table_install
,
362 static void pbr_nht_find_nhg_from_table_remove(struct hash_bucket
*b
,
368 void pbr_nht_route_removed_for_table(uint32_t table_id
)
370 hash_iterate(pbr_nhg_hash
, pbr_nht_find_nhg_from_table_remove
,
375 * Loop through all nexthops in a nexthop group to check that they are all the
376 * same. If they are not all the same, log this peculiarity.
379 * The nexthop group to check
382 * - AFI of last nexthop in the group
385 static afi_t
pbr_nht_which_afi(struct nexthop_group nhg
,
386 enum nexthop_types_t nh_type
)
388 struct nexthop
*nexthop
;
389 afi_t install_afi
= AFI_MAX
;
394 case NEXTHOP_TYPE_IPV4
:
395 case NEXTHOP_TYPE_IPV4_IFINDEX
:
397 case NEXTHOP_TYPE_IPV6
:
398 case NEXTHOP_TYPE_IPV6_IFINDEX
:
400 case NEXTHOP_TYPE_IFINDEX
:
401 case NEXTHOP_TYPE_BLACKHOLE
:
406 v6
= v4
= bh
= false;
408 for (ALL_NEXTHOPS(nhg
, nexthop
)) {
409 nh_type
= nexthop
->type
;
412 case NEXTHOP_TYPE_IFINDEX
:
414 case NEXTHOP_TYPE_IPV4
:
415 case NEXTHOP_TYPE_IPV4_IFINDEX
:
417 install_afi
= AFI_IP
;
419 case NEXTHOP_TYPE_IPV6
:
420 case NEXTHOP_TYPE_IPV6_IFINDEX
:
422 install_afi
= AFI_IP6
;
424 case NEXTHOP_TYPE_BLACKHOLE
:
430 /* Interface and/or blackhole nexthops only. */
432 install_afi
= AFI_MAX
;
436 "%s: Saw both V6 and V4 nexthops...using %s",
437 __PRETTY_FUNCTION__
, afi2str(install_afi
));
438 if (bh
&& (v6
|| v4
))
440 "%s: Saw blackhole nexthop(s) with %s%s%s nexthop(s), using AFI_MAX.",
441 __PRETTY_FUNCTION__
, v4
? "v4" : "",
442 (v4
&& v6
) ? " and " : "", v6
? "v6" : "");
447 static void pbr_nht_install_nexthop_group(struct pbr_nexthop_group_cache
*pnhgc
,
448 struct nexthop_group nhg
)
451 enum nexthop_types_t nh_type
= 0;
453 install_afi
= pbr_nht_which_afi(nhg
, nh_type
);
455 route_add(pnhgc
, nhg
, install_afi
);
459 pbr_nht_uninstall_nexthop_group(struct pbr_nexthop_group_cache
*pnhgc
,
460 struct nexthop_group nhg
,
461 enum nexthop_types_t nh_type
)
465 install_afi
= pbr_nht_which_afi(nhg
, nh_type
);
467 pnhgc
->installed
= false;
468 pnhgc
->valid
= false;
469 route_delete(pnhgc
, install_afi
);
472 void pbr_nht_change_group(const char *name
)
474 struct nexthop_group_cmd
*nhgc
;
475 struct pbr_nexthop_group_cache
*pnhgc
;
476 struct pbr_nexthop_group_cache find
;
477 struct nexthop
*nhop
;
479 nhgc
= nhgc_find(name
);
483 memset(&find
, 0, sizeof(find
));
484 snprintf(find
.name
, sizeof(find
.name
), "%s", name
);
485 pnhgc
= hash_lookup(pbr_nhg_hash
, &find
);
489 "%s: Could not find nexthop-group cache w/ name '%s'",
490 __PRETTY_FUNCTION__
, name
);
494 for (ALL_NEXTHOPS(nhgc
->nhg
, nhop
)) {
495 struct pbr_nexthop_cache lookup
;
496 struct pbr_nexthop_cache
*pnhc
;
498 lookup
.nexthop
= nhop
;
499 pnhc
= hash_lookup(pnhgc
->nhh
, &lookup
);
501 pnhc
= hash_get(pnhgc
->nhh
, &lookup
, pbr_nh_alloc
);
502 pnhc
->parent
= pnhgc
;
505 pbr_nht_install_nexthop_group(pnhgc
, nhgc
->nhg
);
508 char *pbr_nht_nexthop_make_name(char *name
, size_t l
,
509 uint32_t seqno
, char *buffer
)
511 snprintf(buffer
, l
, "%s%u", name
, seqno
);
515 void pbr_nht_add_individual_nexthop(struct pbr_map_sequence
*pbrms
)
517 struct pbr_nexthop_group_cache
*pnhgc
;
518 struct pbr_nexthop_group_cache find
;
519 struct pbr_nexthop_cache
*pnhc
;
520 struct pbr_nexthop_cache lookup
;
522 memset(&find
, 0, sizeof(find
));
523 pbr_nht_nexthop_make_name(pbrms
->parent
->name
, PBR_NHC_NAMELEN
,
524 pbrms
->seqno
, find
.name
);
526 if (!pbr_nht_get_next_tableid(true)) {
528 "%s: Exhausted all table identifiers; cannot create nexthop-group cache for nexthop-group '%s'",
529 __PRETTY_FUNCTION__
, find
.name
);
533 if (!pbrms
->internal_nhg_name
)
534 pbrms
->internal_nhg_name
= XSTRDUP(MTYPE_TMP
, find
.name
);
536 pnhgc
= hash_get(pbr_nhg_hash
, &find
, pbr_nhgc_alloc
);
538 lookup
.nexthop
= pbrms
->nhg
->nexthop
;
539 pnhc
= hash_get(pnhgc
->nhh
, &lookup
, pbr_nh_alloc
);
540 pnhc
->parent
= pnhgc
;
541 pbr_nht_install_nexthop_group(pnhgc
, *pbrms
->nhg
);
544 void pbr_nht_delete_individual_nexthop(struct pbr_map_sequence
*pbrms
)
546 struct pbr_nexthop_group_cache
*pnhgc
;
547 struct pbr_nexthop_group_cache find
;
548 struct pbr_nexthop_cache
*pnhc
;
549 struct pbr_nexthop_cache lup
;
550 struct pbr_map
*pbrm
= pbrms
->parent
;
551 struct listnode
*node
;
552 struct pbr_map_interface
*pmi
;
554 enum nexthop_types_t nh_type
= 0;
556 if (pbrm
->valid
&& pbrms
->nhs_installed
&& pbrm
->incoming
->count
) {
557 for (ALL_LIST_ELEMENTS_RO(pbrm
->incoming
, node
, pmi
))
558 pbr_send_pbr_map(pbrms
, pmi
, false);
562 pbrms
->nhs_installed
= false;
563 pbrms
->reason
|= PBR_MAP_INVALID_NO_NEXTHOPS
;
565 memset(&find
, 0, sizeof(find
));
566 snprintf(find
.name
, sizeof(find
.name
), "%s", pbrms
->internal_nhg_name
);
567 pnhgc
= hash_lookup(pbr_nhg_hash
, &find
);
569 nh
= pbrms
->nhg
->nexthop
;
572 pnhc
= hash_lookup(pnhgc
->nhh
, &lup
);
574 hash_release(pnhgc
->nhh
, pnhc
);
575 pbr_nh_delete(&pnhc
);
576 pbr_nht_uninstall_nexthop_group(pnhgc
, *pbrms
->nhg
, nh_type
);
578 hash_release(pbr_nhg_hash
, pnhgc
);
580 _nexthop_del(pbrms
->nhg
, nh
);
582 nexthop_group_delete(&pbrms
->nhg
);
583 XFREE(MTYPE_TMP
, pbrms
->internal_nhg_name
);
586 struct pbr_nexthop_group_cache
*pbr_nht_add_group(const char *name
)
588 struct nexthop
*nhop
;
589 struct nexthop_group_cmd
*nhgc
;
590 struct pbr_nexthop_group_cache
*pnhgc
;
591 struct pbr_nexthop_group_cache lookup
;
593 if (!pbr_nht_get_next_tableid(true)) {
595 "%s: Exhausted all table identifiers; cannot create nexthop-group cache for nexthop-group '%s'",
596 __PRETTY_FUNCTION__
, name
);
600 nhgc
= nhgc_find(name
);
603 DEBUGD(&pbr_dbg_nht
, "%s: Could not find nhgc with name: %s\n",
604 __PRETTY_FUNCTION__
, name
);
608 snprintf(lookup
.name
, sizeof(lookup
.name
), "%s", name
);
609 pnhgc
= hash_get(pbr_nhg_hash
, &lookup
, pbr_nhgc_alloc
);
610 DEBUGD(&pbr_dbg_nht
, "%s: Retrieved NHGC @ %p", __PRETTY_FUNCTION__
,
613 for (ALL_NEXTHOPS(nhgc
->nhg
, nhop
)) {
614 struct pbr_nexthop_cache lookupc
;
615 struct pbr_nexthop_cache
*pnhc
;
617 lookupc
.nexthop
= nhop
;
618 pnhc
= hash_lookup(pnhgc
->nhh
, &lookupc
);
620 pnhc
= hash_get(pnhgc
->nhh
, &lookupc
, pbr_nh_alloc
);
621 pnhc
->parent
= pnhgc
;
628 void pbr_nht_delete_group(const char *name
)
630 struct pbr_map_sequence
*pbrms
;
631 struct listnode
*snode
;
632 struct pbr_map
*pbrm
;
633 struct pbr_nexthop_group_cache pnhgc_find
;
634 struct pbr_nexthop_group_cache
*pnhgc
;
636 RB_FOREACH (pbrm
, pbr_map_entry_head
, &pbr_maps
) {
637 for (ALL_LIST_ELEMENTS_RO(pbrm
->seqnumbers
, snode
, pbrms
)) {
638 if (pbrms
->nhgrp_name
639 && strmatch(pbrms
->nhgrp_name
, name
)) {
640 pbrms
->reason
|= PBR_MAP_INVALID_NO_NEXTHOPS
;
641 nexthop_group_delete(&pbrms
->nhg
);
643 pbrms
->internal_nhg_name
= NULL
;
649 strlcpy(pnhgc_find
.name
, name
, sizeof(pnhgc_find
.name
));
650 pnhgc
= hash_release(pbr_nhg_hash
, &pnhgc_find
);
651 pbr_nhgc_delete(pnhgc
);
654 bool pbr_nht_nexthop_valid(struct nexthop_group
*nhg
)
656 DEBUGD(&pbr_dbg_nht
, "%s: %p", __PRETTY_FUNCTION__
, nhg
);
660 bool pbr_nht_nexthop_group_valid(const char *name
)
662 struct pbr_nexthop_group_cache
*pnhgc
;
663 struct pbr_nexthop_group_cache lookup
;
665 DEBUGD(&pbr_dbg_nht
, "%s: %s", __PRETTY_FUNCTION__
, name
);
667 snprintf(lookup
.name
, sizeof(lookup
.name
), "%s", name
);
668 pnhgc
= hash_get(pbr_nhg_hash
, &lookup
, NULL
);
671 DEBUGD(&pbr_dbg_nht
, "%s: \t%d %d", __PRETTY_FUNCTION__
, pnhgc
->valid
,
673 if (pnhgc
->valid
&& pnhgc
->installed
)
679 struct pbr_nht_individual
{
680 struct zapi_route
*nhr
;
681 struct interface
*ifp
;
686 static void pbr_nht_individual_nexthop_update_lookup(struct hash_bucket
*b
,
689 struct pbr_nexthop_cache
*pnhc
= b
->data
;
690 struct pbr_nht_individual
*pnhi
= data
;
691 char buf
[PREFIX_STRLEN
];
694 old_valid
= pnhc
->valid
;
696 switch (pnhi
->nhr
->prefix
.family
) {
698 if (pnhc
->nexthop
->gate
.ipv4
.s_addr
699 == pnhi
->nhr
->prefix
.u
.prefix4
.s_addr
)
700 pnhc
->valid
= !!pnhi
->nhr
->nexthop_num
;
703 if (memcmp(&pnhc
->nexthop
->gate
.ipv6
,
704 &pnhi
->nhr
->prefix
.u
.prefix6
, 16)
706 pnhc
->valid
= !!pnhi
->nhr
->nexthop_num
;
710 DEBUGD(&pbr_dbg_nht
, "\tFound %s: old: %d new: %d",
711 prefix2str(&pnhi
->nhr
->prefix
, buf
, sizeof(buf
)), old_valid
,
718 static void pbr_nexthop_group_cache_iterate_to_group(struct hash_bucket
*b
,
721 struct pbr_nexthop_cache
*pnhc
= b
->data
;
722 struct nexthop_group
*nhg
= data
;
723 struct nexthop
*nh
= NULL
;
725 copy_nexthops(&nh
, pnhc
->nexthop
, NULL
);
727 _nexthop_add(&nhg
->nexthop
, nh
);
731 pbr_nexthop_group_cache_to_nexthop_group(struct nexthop_group
*nhg
,
732 struct pbr_nexthop_group_cache
*pnhgc
)
734 hash_iterate(pnhgc
->nhh
, pbr_nexthop_group_cache_iterate_to_group
, nhg
);
737 static void pbr_nht_nexthop_update_lookup(struct hash_bucket
*b
, void *data
)
739 struct pbr_nexthop_group_cache
*pnhgc
= b
->data
;
740 struct pbr_nht_individual pnhi
;
741 struct nexthop_group nhg
= {};
744 old_valid
= pnhgc
->valid
;
746 pnhi
.nhr
= (struct zapi_route
*)data
;
748 hash_iterate(pnhgc
->nhh
, pbr_nht_individual_nexthop_update_lookup
,
752 * If any of the specified nexthops are valid we are valid
754 pnhgc
->valid
= !!pnhi
.valid
;
757 pbr_nexthop_group_cache_to_nexthop_group(&nhg
, pnhgc
);
758 pbr_nht_install_nexthop_group(pnhgc
, nhg
);
759 /* Don't need copied nexthops anymore */
760 nexthops_free(nhg
.nexthop
);
763 if (old_valid
!= pnhgc
->valid
)
764 pbr_map_check_nh_group_change(pnhgc
->name
);
767 void pbr_nht_nexthop_update(struct zapi_route
*nhr
)
769 hash_iterate(pbr_nhg_hash
, pbr_nht_nexthop_update_lookup
, nhr
);
773 pbr_nht_individual_nexthop_interface_update_lookup(struct hash_backet
*b
,
776 struct pbr_nexthop_cache
*pnhc
= b
->data
;
777 struct pbr_nht_individual
*pnhi
= data
;
780 old_valid
= pnhc
->valid
;
782 if (pnhc
->nexthop
->type
== NEXTHOP_TYPE_IFINDEX
783 && pnhc
->nexthop
->ifindex
== pnhi
->ifp
->ifindex
)
784 pnhc
->valid
= !!if_is_up(pnhi
->ifp
);
786 DEBUGD(&pbr_dbg_nht
, "\tFound %s: old: %d new: %d", pnhi
->ifp
->name
,
787 old_valid
, pnhc
->valid
);
793 static void pbr_nht_nexthop_interface_update_lookup(struct hash_backet
*b
,
796 struct pbr_nexthop_group_cache
*pnhgc
= b
->data
;
797 struct pbr_nht_individual pnhi
;
800 old_valid
= pnhgc
->valid
;
804 hash_iterate(pnhgc
->nhh
,
805 pbr_nht_individual_nexthop_interface_update_lookup
, &pnhi
);
808 * If any of the specified nexthops are valid we are valid
810 pnhgc
->valid
= !!pnhi
.valid
;
812 if (old_valid
!= pnhgc
->valid
)
813 pbr_map_check_nh_group_change(pnhgc
->name
);
816 void pbr_nht_nexthop_interface_update(struct interface
*ifp
)
818 hash_iterate(pbr_nhg_hash
, pbr_nht_nexthop_interface_update_lookup
,
822 static uint32_t pbr_nhg_hash_key(const void *arg
)
824 const struct pbr_nexthop_group_cache
*nhgc
= arg
;
826 return jhash(&nhgc
->name
, strlen(nhgc
->name
), 0x52c34a96);
829 static bool pbr_nhg_hash_equal(const void *arg1
, const void *arg2
)
831 const struct pbr_nexthop_group_cache
*nhgc1
=
832 (const struct pbr_nexthop_group_cache
*)arg1
;
833 const struct pbr_nexthop_group_cache
*nhgc2
=
834 (const struct pbr_nexthop_group_cache
*)arg2
;
836 return !strcmp(nhgc1
->name
, nhgc2
->name
);
839 uint32_t pbr_nht_get_next_tableid(bool peek
)
844 for (i
= pbr_nhg_low_table
; i
<= pbr_nhg_high_table
; i
++) {
845 if (!nhg_tableid
[i
]) {
852 nhg_tableid
[i
] = !peek
;
858 void pbr_nht_set_tableid_range(uint32_t low
, uint32_t high
)
860 pbr_nhg_low_table
= low
;
861 pbr_nhg_high_table
= high
;
864 void pbr_nht_write_table_range(struct vty
*vty
)
866 if (pbr_nhg_low_table
!= PBR_NHT_DEFAULT_LOW_TABLEID
867 || pbr_nhg_high_table
!= PBR_NHT_DEFAULT_HIGH_TABLEID
) {
868 vty_out(vty
, "pbr table range %u %u\n", pbr_nhg_low_table
,
873 uint32_t pbr_nht_get_next_rule(uint32_t seqno
)
875 return seqno
+ pbr_nhg_low_rule
- 1;
877 void pbr_nht_set_rule_range(uint32_t low
, uint32_t high
)
879 pbr_nhg_low_rule
= low
;
880 pbr_nhg_high_rule
= high
;
883 void pbr_nht_write_rule_range(struct vty
*vty
)
885 if (pbr_nhg_low_rule
!= PBR_NHT_DEFAULT_LOW_RULE
886 || pbr_nhg_high_rule
!= PBR_NHT_DEFAULT_HIGH_RULE
) {
887 vty_out(vty
, "pbr rule range %u %u\n", pbr_nhg_low_rule
,
892 uint32_t pbr_nht_get_table(const char *name
)
894 struct pbr_nexthop_group_cache find
;
895 struct pbr_nexthop_group_cache
*pnhgc
;
897 memset(&find
, 0, sizeof(find
));
898 snprintf(find
.name
, sizeof(find
.name
), "%s", name
);
899 pnhgc
= hash_lookup(pbr_nhg_hash
, &find
);
903 "%s: Could not find nexthop-group cache w/ name '%s'",
904 __PRETTY_FUNCTION__
, name
);
908 return pnhgc
->table_id
;
911 bool pbr_nht_get_installed(const char *name
)
913 struct pbr_nexthop_group_cache find
;
914 struct pbr_nexthop_group_cache
*pnhgc
;
916 memset(&find
, 0, sizeof(find
));
917 snprintf(find
.name
, sizeof(find
.name
), "%s", name
);
919 pnhgc
= hash_lookup(pbr_nhg_hash
, &find
);
924 return pnhgc
->installed
;
927 static void pbr_nht_show_nhg_nexthops(struct hash_bucket
*b
, void *data
)
929 struct pbr_nexthop_cache
*pnhc
= b
->data
;
930 struct vty
*vty
= data
;
932 vty_out(vty
, "\tValid: %d ", pnhc
->valid
);
933 nexthop_group_write_nexthop(vty
, pnhc
->nexthop
);
936 struct pbr_nht_show
{
941 static void pbr_nht_show_nhg(struct hash_bucket
*b
, void *data
)
943 struct pbr_nexthop_group_cache
*pnhgc
= b
->data
;
944 struct pbr_nht_show
*pns
= data
;
947 if (pns
->name
&& strcmp(pns
->name
, pnhgc
->name
) != 0)
951 vty_out(vty
, "Nexthop-Group: %s Table: %u Valid: %d Installed: %d\n",
952 pnhgc
->name
, pnhgc
->table_id
, pnhgc
->valid
, pnhgc
->installed
);
954 hash_iterate(pnhgc
->nhh
, pbr_nht_show_nhg_nexthops
, vty
);
957 void pbr_nht_show_nexthop_group(struct vty
*vty
, const char *name
)
959 struct pbr_nht_show pns
;
964 hash_iterate(pbr_nhg_hash
, pbr_nht_show_nhg
, &pns
);
967 void pbr_nht_init(void)
969 pbr_nhg_hash
= hash_create_size(
970 16, pbr_nhg_hash_key
, pbr_nhg_hash_equal
, "PBR NHG Cache Hash");
972 hash_create_size(16, (unsigned int (*)(const void *))nexthop_hash
,
973 pbr_nhrc_hash_equal
, "PBR NH Hash");
975 pbr_nhg_low_table
= PBR_NHT_DEFAULT_LOW_TABLEID
;
976 pbr_nhg_high_table
= PBR_NHT_DEFAULT_HIGH_TABLEID
;
977 pbr_nhg_low_rule
= PBR_NHT_DEFAULT_LOW_RULE
;
978 pbr_nhg_high_rule
= PBR_NHT_DEFAULT_HIGH_RULE
;
979 memset(&nhg_tableid
, 0, 65535 * sizeof(uint8_t));