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
28 #include "nexthop_group.h"
35 #include "pbr_zebra.h"
36 #include "pbr_memory.h"
37 #include "pbr_debug.h"
40 DEFINE_MTYPE_STATIC(PBRD
, PBR_MAP
, "PBR Map")
41 DEFINE_MTYPE_STATIC(PBRD
, PBR_MAP_SEQNO
, "PBR Map Sequence")
42 DEFINE_MTYPE_STATIC(PBRD
, PBR_MAP_INTERFACE
, "PBR Map Interface")
44 static uint32_t pbr_map_sequence_unique
;
46 static bool pbr_map_check_valid_internal(struct pbr_map
*pbrm
);
47 static inline int pbr_map_compare(const struct pbr_map
*pbrmap1
,
48 const struct pbr_map
*pbrmap2
);
50 RB_GENERATE(pbr_map_entry_head
, pbr_map
, pbr_map_entry
, pbr_map_compare
)
52 struct pbr_map_entry_head pbr_maps
= RB_INITIALIZER(&pbr_maps
);
54 DEFINE_QOBJ_TYPE(pbr_map_sequence
)
56 static inline int pbr_map_compare(const struct pbr_map
*pbrmap1
,
57 const struct pbr_map
*pbrmap2
)
59 return strcmp(pbrmap1
->name
, pbrmap2
->name
);
62 static int pbr_map_sequence_compare(const struct pbr_map_sequence
*pbrms1
,
63 const struct pbr_map_sequence
*pbrms2
)
65 if (pbrms1
->seqno
== pbrms2
->seqno
)
68 if (pbrms1
->seqno
< pbrms2
->seqno
)
74 static void pbr_map_sequence_delete(struct pbr_map_sequence
*pbrms
)
76 XFREE(MTYPE_TMP
, pbrms
->internal_nhg_name
);
78 XFREE(MTYPE_PBR_MAP_SEQNO
, pbrms
);
81 static int pbr_map_interface_compare(const struct pbr_map_interface
*pmi1
,
82 const struct pbr_map_interface
*pmi2
)
84 return strcmp(pmi1
->ifp
->name
, pmi2
->ifp
->name
);
87 static void pbr_map_interface_list_delete(struct pbr_map_interface
*pmi
)
89 struct pbr_map_interface
*pmi_int
;
90 struct listnode
*node
, *nnode
;
93 RB_FOREACH (pbrm
, pbr_map_entry_head
, &pbr_maps
) {
94 for (ALL_LIST_ELEMENTS(pbrm
->incoming
, node
, nnode
, pmi_int
)) {
96 pbr_map_policy_delete(pbrm
, pmi
);
103 static bool pbr_map_interface_is_valid(const struct pbr_map_interface
*pmi
)
105 /* Don't install rules without a real ifindex on the incoming interface.
107 * This can happen when we have config for an interface that does not
108 * exist or when an interface is changing vrfs.
110 if (pmi
->ifp
&& pmi
->ifp
->ifindex
!= IFINDEX_INTERNAL
)
116 static void pbr_map_pbrms_update_common(struct pbr_map_sequence
*pbrms
,
119 struct pbr_map
*pbrm
;
120 struct listnode
*node
;
121 struct pbr_map_interface
*pmi
;
123 pbrm
= pbrms
->parent
;
125 if (pbrms
->nhs_installed
&& pbrm
->incoming
->count
) {
126 for (ALL_LIST_ELEMENTS_RO(pbrm
->incoming
, node
, pmi
)) {
130 if (install
&& !pbr_map_interface_is_valid(pmi
))
133 pbr_send_pbr_map(pbrms
, pmi
, install
);
138 static void pbr_map_pbrms_install(struct pbr_map_sequence
*pbrms
)
140 pbr_map_pbrms_update_common(pbrms
, true);
143 static void pbr_map_pbrms_uninstall(struct pbr_map_sequence
*pbrms
)
145 pbr_map_pbrms_update_common(pbrms
, false);
148 static const char *const pbr_map_reason_str
[] = {
149 "Invalid NH-group", "Invalid NH", "No Nexthops",
150 "Both NH and NH-Group", "Invalid Src or Dst", "Invalid VRF",
154 void pbr_map_reason_string(unsigned int reason
, char *buf
, int size
)
162 for (bit
= 0; bit
< array_size(pbr_map_reason_str
); bit
++) {
163 if ((reason
& (1 << bit
)) && (len
< size
)) {
164 len
+= snprintf((buf
+ len
), (size
- len
), "%s%s",
165 (len
> 0) ? ", " : "",
166 pbr_map_reason_str
[bit
]);
171 void pbr_map_final_interface_deletion(struct pbr_map
*pbrm
,
172 struct pbr_map_interface
*pmi
)
174 if (pmi
->delete == true) {
175 listnode_delete(pbrm
->incoming
, pmi
);
178 bf_release_index(pbrm
->ifi_bitfield
, pmi
->install_bit
);
179 XFREE(MTYPE_PBR_MAP_INTERFACE
, pmi
);
183 void pbr_map_interface_delete(struct pbr_map
*pbrm
, struct interface
*ifp_del
)
186 struct listnode
*node
;
187 struct pbr_map_interface
*pmi
;
189 for (ALL_LIST_ELEMENTS_RO(pbrm
->incoming
, node
, pmi
)) {
190 if (ifp_del
== pmi
->ifp
)
195 pbr_map_policy_delete(pbrm
, pmi
);
198 void pbr_map_add_interface(struct pbr_map
*pbrm
, struct interface
*ifp_add
)
200 struct listnode
*node
;
201 struct pbr_map_interface
*pmi
;
203 for (ALL_LIST_ELEMENTS_RO(pbrm
->incoming
, node
, pmi
)) {
204 if (ifp_add
== pmi
->ifp
)
208 pmi
= XCALLOC(MTYPE_PBR_MAP_INTERFACE
, sizeof(*pmi
));
211 listnode_add_sort(pbrm
->incoming
, pmi
);
213 bf_assign_index(pbrm
->ifi_bitfield
, pmi
->install_bit
);
214 pbr_map_check_valid(pbrm
->name
);
216 pbr_map_install(pbrm
);
220 pbr_map_policy_interface_update_common(const struct interface
*ifp
,
221 struct pbr_interface
**pbr_ifp
,
222 struct pbr_map
**pbrm
)
225 DEBUGD(&pbr_dbg_map
, "%s: %s has no pbr_interface info",
226 __func__
, ifp
->name
);
230 *pbr_ifp
= ifp
->info
;
232 *pbrm
= pbrm_find((*pbr_ifp
)->mapname
);
235 DEBUGD(&pbr_dbg_map
, "%s: applied PBR-MAP(%s) does not exist?",
236 __func__
, (*pbr_ifp
)->mapname
);
243 void pbr_map_policy_interface_update(const struct interface
*ifp
, bool state_up
)
245 struct pbr_interface
*pbr_ifp
;
246 struct pbr_map_sequence
*pbrms
;
247 struct pbr_map
*pbrm
;
248 struct listnode
*node
, *inode
;
249 struct pbr_map_interface
*pmi
;
251 if (pbr_map_policy_interface_update_common(ifp
, &pbr_ifp
, &pbrm
))
254 DEBUGD(&pbr_dbg_map
, "%s: %s %s rules on interface %s", __func__
,
255 pbr_ifp
->mapname
, (state_up
? "installing" : "removing"),
259 * Walk the list and install/remove maps on the interface.
261 for (ALL_LIST_ELEMENTS_RO(pbrm
->seqnumbers
, node
, pbrms
))
262 for (ALL_LIST_ELEMENTS_RO(pbrm
->incoming
, inode
, pmi
))
263 if (pmi
->ifp
== ifp
&& pbr_map_interface_is_valid(pmi
))
264 pbr_send_pbr_map(pbrms
, pmi
, state_up
);
267 static void pbrms_vrf_update(struct pbr_map_sequence
*pbrms
,
268 const struct pbr_vrf
*pbr_vrf
)
270 const char *vrf_name
= pbr_vrf_name(pbr_vrf
);
272 if (pbrms
->vrf_lookup
273 && (strncmp(vrf_name
, pbrms
->vrf_name
, sizeof(pbrms
->vrf_name
))
275 DEBUGD(&pbr_dbg_map
, "\tSeq %u uses vrf %s (%u), updating map",
276 pbrms
->seqno
, vrf_name
, pbr_vrf_id(pbr_vrf
));
278 pbr_map_check(pbrms
);
282 /* Vrf enabled/disabled */
283 void pbr_map_vrf_update(const struct pbr_vrf
*pbr_vrf
)
285 struct pbr_map
*pbrm
;
286 struct pbr_map_sequence
*pbrms
;
287 struct listnode
*node
;
292 bool enabled
= pbr_vrf_is_enabled(pbr_vrf
);
294 DEBUGD(&pbr_dbg_map
, "%s: %s (%u) %s, updating pbr maps", __func__
,
295 pbr_vrf_name(pbr_vrf
), pbr_vrf_id(pbr_vrf
),
296 enabled
? "enabled" : "disabled");
298 RB_FOREACH (pbrm
, pbr_map_entry_head
, &pbr_maps
) {
299 DEBUGD(&pbr_dbg_map
, "%s: Looking at %s", __PRETTY_FUNCTION__
,
301 for (ALL_LIST_ELEMENTS_RO(pbrm
->seqnumbers
, node
, pbrms
))
302 pbrms_vrf_update(pbrms
, pbr_vrf
);
306 void pbr_map_write_interfaces(struct vty
*vty
, struct interface
*ifp
)
308 struct pbr_interface
*pbr_ifp
= ifp
->info
;
311 && strncmp(pbr_ifp
->mapname
, "", sizeof(pbr_ifp
->mapname
)) != 0)
312 vty_out(vty
, " pbr-policy %s\n", pbr_ifp
->mapname
);
315 struct pbr_map
*pbrm_find(const char *name
)
319 strlcpy(pbrm
.name
, name
, sizeof(pbrm
.name
));
321 return RB_FIND(pbr_map_entry_head
, &pbr_maps
, &pbrm
);
324 extern void pbr_map_delete(struct pbr_map_sequence
*pbrms
)
326 struct pbr_map
*pbrm
;
327 struct listnode
*inode
;
328 struct pbr_map_interface
*pmi
;
330 pbrm
= pbrms
->parent
;
332 for (ALL_LIST_ELEMENTS_RO(pbrm
->incoming
, inode
, pmi
))
333 pbr_send_pbr_map(pbrms
, pmi
, false);
336 pbr_nht_delete_individual_nexthop(pbrms
);
338 listnode_delete(pbrm
->seqnumbers
, pbrms
);
340 if (pbrm
->seqnumbers
->count
== 0) {
341 RB_REMOVE(pbr_map_entry_head
, &pbr_maps
, pbrm
);
343 bf_free(pbrm
->ifi_bitfield
);
344 XFREE(MTYPE_PBR_MAP
, pbrm
);
348 static void pbr_map_delete_common(struct pbr_map_sequence
*pbrms
)
350 struct pbr_map
*pbrm
= pbrms
->parent
;
352 pbr_map_pbrms_uninstall(pbrms
);
355 pbrms
->nhs_installed
= false;
356 pbrms
->reason
|= PBR_MAP_INVALID_NO_NEXTHOPS
;
357 pbrms
->nhgrp_name
= NULL
;
360 void pbr_map_delete_nexthops(struct pbr_map_sequence
*pbrms
)
362 pbr_map_delete_common(pbrms
);
365 void pbr_map_delete_vrf(struct pbr_map_sequence
*pbrms
)
367 pbr_map_delete_common(pbrms
);
370 struct pbr_map_sequence
*pbrms_lookup_unique(uint32_t unique
, ifindex_t ifindex
,
371 struct pbr_map_interface
**ppmi
)
373 struct pbr_map_sequence
*pbrms
;
374 struct listnode
*snode
, *inode
;
375 struct pbr_map_interface
*pmi
;
376 struct pbr_map
*pbrm
;
378 RB_FOREACH (pbrm
, pbr_map_entry_head
, &pbr_maps
) {
379 for (ALL_LIST_ELEMENTS_RO(pbrm
->incoming
, inode
, pmi
)) {
380 if (pmi
->ifp
->ifindex
!= ifindex
)
386 for (ALL_LIST_ELEMENTS_RO(pbrm
->seqnumbers
, snode
,
388 DEBUGD(&pbr_dbg_map
, "%s: Comparing %u to %u",
389 __PRETTY_FUNCTION__
, pbrms
->unique
,
391 if (pbrms
->unique
== unique
)
400 static void pbr_map_add_interfaces(struct pbr_map
*pbrm
)
402 struct interface
*ifp
;
403 struct pbr_interface
*pbr_ifp
;
406 RB_FOREACH (vrf
, vrf_name_head
, &vrfs_by_name
) {
407 FOR_ALL_INTERFACES (vrf
, ifp
) {
410 if (strcmp(pbrm
->name
, pbr_ifp
->mapname
) == 0)
411 pbr_map_add_interface(pbrm
, ifp
);
417 struct pbr_map_sequence
*pbrms_get(const char *name
, uint32_t seqno
)
419 struct pbr_map
*pbrm
;
420 struct pbr_map_sequence
*pbrms
;
421 struct listnode
*node
;
423 pbrm
= pbrm_find(name
);
425 pbrm
= XCALLOC(MTYPE_PBR_MAP
, sizeof(*pbrm
));
426 snprintf(pbrm
->name
, sizeof(pbrm
->name
), "%s", name
);
428 pbrm
->seqnumbers
= list_new();
429 pbrm
->seqnumbers
->cmp
=
430 (int (*)(void *, void *))pbr_map_sequence_compare
;
431 pbrm
->seqnumbers
->del
=
432 (void (*)(void *))pbr_map_sequence_delete
;
434 pbrm
->incoming
= list_new();
435 pbrm
->incoming
->cmp
=
436 (int (*)(void *, void *))pbr_map_interface_compare
;
437 pbrm
->incoming
->del
=
438 (void (*)(void *))pbr_map_interface_list_delete
;
440 RB_INSERT(pbr_map_entry_head
, &pbr_maps
, pbrm
);
442 bf_init(pbrm
->ifi_bitfield
, 64);
443 pbr_map_add_interfaces(pbrm
);
446 for (ALL_LIST_ELEMENTS_RO(pbrm
->seqnumbers
, node
, pbrms
)) {
447 if (pbrms
->seqno
== seqno
)
453 pbrms
= XCALLOC(MTYPE_PBR_MAP_SEQNO
, sizeof(*pbrms
));
454 pbrms
->unique
= pbr_map_sequence_unique
++;
455 pbrms
->seqno
= seqno
;
456 pbrms
->ruleno
= pbr_nht_get_next_rule(seqno
);
457 pbrms
->parent
= pbrm
;
459 PBR_MAP_INVALID_EMPTY
|
460 PBR_MAP_INVALID_NO_NEXTHOPS
;
461 pbrms
->vrf_name
[0] = '\0';
463 QOBJ_REG(pbrms
, pbr_map_sequence
);
464 listnode_add_sort(pbrm
->seqnumbers
, pbrms
);
471 pbr_map_sequence_check_nexthops_valid(struct pbr_map_sequence
*pbrms
)
473 /* Check if any are present first */
474 if (!pbrms
->vrf_unchanged
&& !pbrms
->vrf_lookup
&& !pbrms
->nhg
475 && !pbrms
->nhgrp_name
) {
476 pbrms
->reason
|= PBR_MAP_INVALID_NO_NEXTHOPS
;
481 * Check validness of vrf.
484 /* This one can be considered always valid */
485 if (pbrms
->vrf_unchanged
)
486 pbrms
->nhs_installed
= true;
488 if (pbrms
->vrf_lookup
) {
489 struct pbr_vrf
*pbr_vrf
=
490 pbr_vrf_lookup_by_name(pbrms
->vrf_name
);
492 if (pbr_vrf
&& pbr_vrf_is_valid(pbr_vrf
))
493 pbrms
->nhs_installed
= true;
495 pbrms
->reason
|= PBR_MAP_INVALID_VRF
;
499 * Check validness of the nexthop or nexthop-group
502 /* Only nexthop or nexthop group allowed */
503 if (pbrms
->nhg
&& pbrms
->nhgrp_name
)
504 pbrms
->reason
|= PBR_MAP_INVALID_BOTH_NHANDGRP
;
507 !pbr_nht_nexthop_group_valid(pbrms
->internal_nhg_name
))
508 pbrms
->reason
|= PBR_MAP_INVALID_NEXTHOP
;
510 if (pbrms
->nhgrp_name
) {
511 if (!pbr_nht_nexthop_group_valid(pbrms
->nhgrp_name
))
512 pbrms
->reason
|= PBR_MAP_INVALID_NEXTHOP_GROUP
;
514 pbrms
->nhs_installed
= true;
518 static void pbr_map_sequence_check_not_empty(struct pbr_map_sequence
*pbrms
)
520 if (!pbrms
->src
&& !pbrms
->dst
&& !pbrms
->mark
)
521 pbrms
->reason
|= PBR_MAP_INVALID_EMPTY
;
525 * Checks to see if we think that the pbmrs is valid. If we think
526 * the config is valid return true.
528 static void pbr_map_sequence_check_valid(struct pbr_map_sequence
*pbrms
)
530 pbr_map_sequence_check_nexthops_valid(pbrms
);
532 pbr_map_sequence_check_not_empty(pbrms
);
535 static bool pbr_map_check_valid_internal(struct pbr_map
*pbrm
)
537 struct pbr_map_sequence
*pbrms
;
538 struct listnode
*node
;
541 for (ALL_LIST_ELEMENTS_RO(pbrm
->seqnumbers
, node
, pbrms
)) {
543 pbr_map_sequence_check_valid(pbrms
);
545 * A pbr_map_sequence that is invalid causes
546 * the whole shebang to be invalid
548 if (pbrms
->reason
!= 0)
556 * For a given PBR-MAP check to see if we think it is a
557 * valid config or not. If so note that it is and return
560 bool pbr_map_check_valid(const char *name
)
562 struct pbr_map
*pbrm
;
564 pbrm
= pbrm_find(name
);
567 "%s: Specified PBR-MAP(%s) does not exist?",
568 __PRETTY_FUNCTION__
, name
);
572 pbr_map_check_valid_internal(pbrm
);
576 void pbr_map_schedule_policy_from_nhg(const char *nh_group
)
578 struct pbr_map_sequence
*pbrms
;
579 struct pbr_map
*pbrm
;
580 struct listnode
*node
;
582 RB_FOREACH (pbrm
, pbr_map_entry_head
, &pbr_maps
) {
583 DEBUGD(&pbr_dbg_map
, "%s: Looking at %s", __PRETTY_FUNCTION__
,
585 for (ALL_LIST_ELEMENTS_RO(pbrm
->seqnumbers
, node
, pbrms
)) {
586 DEBUGD(&pbr_dbg_map
, "\tNH Grp name: %s",
588 pbrms
->nhgrp_name
: pbrms
->internal_nhg_name
);
590 if (pbrms
->nhgrp_name
591 && (strcmp(nh_group
, pbrms
->nhgrp_name
) == 0)) {
592 pbrms
->nhs_installed
= true;
594 pbr_map_check(pbrms
);
598 && (strcmp(nh_group
, pbrms
->internal_nhg_name
)
600 pbrms
->nhs_installed
= true;
602 pbr_map_check(pbrms
);
608 void pbr_map_policy_install(const char *name
)
610 struct pbr_map_sequence
*pbrms
;
611 struct pbr_map
*pbrm
;
612 struct listnode
*node
, *inode
;
613 struct pbr_map_interface
*pmi
;
615 DEBUGD(&pbr_dbg_map
, "%s: for %s", __PRETTY_FUNCTION__
, name
);
616 pbrm
= pbrm_find(name
);
620 for (ALL_LIST_ELEMENTS_RO(pbrm
->seqnumbers
, node
, pbrms
)) {
622 "%s: Looking at what to install %s(%u) %d %d",
623 __PRETTY_FUNCTION__
, name
, pbrms
->seqno
, pbrm
->valid
,
624 pbrms
->nhs_installed
);
626 if (pbrm
->valid
&& pbrms
->nhs_installed
627 && pbrm
->incoming
->count
) {
628 DEBUGD(&pbr_dbg_map
, "\tInstalling %s %u", pbrm
->name
,
630 for (ALL_LIST_ELEMENTS_RO(pbrm
->incoming
, inode
, pmi
))
631 if (pbr_map_interface_is_valid(pmi
))
632 pbr_send_pbr_map(pbrms
, pmi
, true);
637 void pbr_map_policy_delete(struct pbr_map
*pbrm
, struct pbr_map_interface
*pmi
)
639 struct listnode
*node
;
640 struct pbr_map_sequence
*pbrms
;
643 for (ALL_LIST_ELEMENTS_RO(pbrm
->seqnumbers
, node
, pbrms
))
644 pbr_send_pbr_map(pbrms
, pmi
, false);
650 * For a nexthop group specified, see if any of the pbr-maps
651 * are using it and if so, check to see that we are still
652 * valid for usage. If we are valid then schedule the installation/deletion
655 void pbr_map_check_nh_group_change(const char *nh_group
)
657 struct pbr_map_sequence
*pbrms
;
658 struct pbr_map
*pbrm
;
659 struct listnode
*node
, *inode
;
660 struct pbr_map_interface
*pmi
;
663 RB_FOREACH (pbrm
, pbr_map_entry_head
, &pbr_maps
) {
664 for (ALL_LIST_ELEMENTS_RO(pbrm
->seqnumbers
, node
, pbrms
)) {
666 if (pbrms
->nhgrp_name
)
668 !strcmp(nh_group
, pbrms
->nhgrp_name
);
670 found_name
= !strcmp(nh_group
,
671 pbrms
->internal_nhg_name
);
674 bool original
= pbrm
->valid
;
676 pbr_map_check_valid_internal(pbrm
);
678 if (pbrm
->valid
&& (original
!= pbrm
->valid
))
679 pbr_map_install(pbrm
);
681 if (pbrm
->valid
== false)
682 for (ALL_LIST_ELEMENTS_RO(
683 pbrm
->incoming
, inode
,
685 pbr_send_pbr_map(pbrms
, pmi
,
692 void pbr_map_check(struct pbr_map_sequence
*pbrms
)
694 struct pbr_map
*pbrm
;
697 pbrm
= pbrms
->parent
;
698 DEBUGD(&pbr_dbg_map
, "%s: for %s(%u)", __PRETTY_FUNCTION__
,
699 pbrm
->name
, pbrms
->seqno
);
700 if (pbr_map_check_valid(pbrm
->name
))
701 DEBUGD(&pbr_dbg_map
, "We are totally valid %s",
704 if (pbrms
->reason
== PBR_MAP_VALID_SEQUENCE_NUMBER
) {
706 DEBUGD(&pbr_dbg_map
, "%s: Installing %s(%u) reason: %" PRIu64
,
707 __PRETTY_FUNCTION__
, pbrm
->name
, pbrms
->seqno
,
710 "\tSending PBR_MAP_POLICY_INSTALL event");
714 "%s: Removing %s(%u) reason: %" PRIu64
,
715 __PRETTY_FUNCTION__
, pbrm
->name
,
716 pbrms
->seqno
, pbrms
->reason
);
720 pbr_map_pbrms_install(pbrms
);
722 pbr_map_pbrms_uninstall(pbrms
);
725 void pbr_map_install(struct pbr_map
*pbrm
)
727 struct pbr_map_sequence
*pbrms
;
728 struct listnode
*node
;
730 if (!pbrm
->incoming
->count
)
733 for (ALL_LIST_ELEMENTS_RO(pbrm
->seqnumbers
, node
, pbrms
))
734 pbr_map_pbrms_install(pbrms
);
737 void pbr_map_init(void)
739 RB_INIT(pbr_map_entry_head
, &pbr_maps
);
741 pbr_map_sequence_unique
= 1;