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"
39 DEFINE_MTYPE_STATIC(PBRD
, PBR_MAP
, "PBR Map")
40 DEFINE_MTYPE_STATIC(PBRD
, PBR_MAP_SEQNO
, "PBR Map Sequence")
41 DEFINE_MTYPE_STATIC(PBRD
, PBR_MAP_INTERFACE
, "PBR Map Interface")
43 static uint32_t pbr_map_sequence_unique
;
45 static inline int pbr_map_compare(const struct pbr_map
*pbrmap1
,
46 const struct pbr_map
*pbrmap2
);
48 RB_GENERATE(pbr_map_entry_head
, pbr_map
, pbr_map_entry
, pbr_map_compare
)
50 struct pbr_map_entry_head pbr_maps
= RB_INITIALIZER(&pbr_maps
);
52 DEFINE_QOBJ_TYPE(pbr_map_sequence
)
54 static inline int pbr_map_compare(const struct pbr_map
*pbrmap1
,
55 const struct pbr_map
*pbrmap2
)
57 return strcmp(pbrmap1
->name
, pbrmap2
->name
);
60 static int pbr_map_sequence_compare(const struct pbr_map_sequence
*pbrms1
,
61 const struct pbr_map_sequence
*pbrms2
)
63 if (pbrms1
->seqno
== pbrms2
->seqno
)
66 if (pbrms1
->seqno
< pbrms2
->seqno
)
72 static void pbr_map_sequence_delete(struct pbr_map_sequence
*pbrms
)
74 XFREE(MTYPE_TMP
, pbrms
->internal_nhg_name
);
76 XFREE(MTYPE_PBR_MAP_SEQNO
, pbrms
);
79 static int pbr_map_interface_compare(const struct pbr_map_interface
*pmi1
,
80 const struct pbr_map_interface
*pmi2
)
82 return strcmp(pmi1
->ifp
->name
, pmi2
->ifp
->name
);
85 static void pbr_map_interface_list_delete(struct pbr_map_interface
*pmi
)
87 struct pbr_map_interface
*pmi_int
;
88 struct listnode
*node
, *nnode
;
91 RB_FOREACH (pbrm
, pbr_map_entry_head
, &pbr_maps
) {
92 for (ALL_LIST_ELEMENTS(pbrm
->incoming
, node
, nnode
, pmi_int
)) {
94 pbr_map_policy_delete(pbrm
, pmi
);
101 static const char *pbr_map_reason_str
[] = {
102 "Invalid NH-group", "Invalid NH", "No Nexthops",
103 "Both NH and NH-Group", "Invalid Src or Dst", "Deleting Sequence",
106 void pbr_map_reason_string(unsigned int reason
, char *buf
, int size
)
114 for (bit
= 0; bit
< array_size(pbr_map_reason_str
); bit
++) {
115 if ((reason
& (1 << bit
)) && (len
< size
)) {
116 len
+= snprintf((buf
+ len
), (size
- len
), "%s%s",
117 (len
> 0) ? ", " : "",
118 pbr_map_reason_str
[bit
]);
123 void pbr_map_final_interface_deletion(struct pbr_map
*pbrm
,
124 struct pbr_map_interface
*pmi
)
126 if (pmi
->delete == true) {
127 listnode_delete(pbrm
->incoming
, pmi
);
130 bf_release_index(pbrm
->ifi_bitfield
, pmi
->install_bit
);
131 XFREE(MTYPE_PBR_MAP_INTERFACE
, pmi
);
135 void pbr_map_interface_delete(struct pbr_map
*pbrm
, struct interface
*ifp_del
)
138 struct listnode
*node
;
139 struct pbr_map_interface
*pmi
;
141 for (ALL_LIST_ELEMENTS_RO(pbrm
->incoming
, node
, pmi
)) {
142 if (ifp_del
== pmi
->ifp
)
147 pbr_map_policy_delete(pbrm
, pmi
);
150 void pbr_map_add_interface(struct pbr_map
*pbrm
, struct interface
*ifp_add
)
152 struct listnode
*node
;
153 struct pbr_map_interface
*pmi
;
155 for (ALL_LIST_ELEMENTS_RO(pbrm
->incoming
, node
, pmi
)) {
156 if (ifp_add
== pmi
->ifp
)
160 pmi
= XCALLOC(MTYPE_PBR_MAP_INTERFACE
, sizeof(*pmi
));
163 listnode_add_sort(pbrm
->incoming
, pmi
);
165 bf_assign_index(pbrm
->ifi_bitfield
, pmi
->install_bit
);
166 pbr_map_check_valid(pbrm
->name
);
168 pbr_map_install(pbrm
);
171 void pbr_map_write_interfaces(struct vty
*vty
, struct interface
*ifp
)
173 struct pbr_interface
*pbr_ifp
= ifp
->info
;
176 && strncmp(pbr_ifp
->mapname
, "", sizeof(pbr_ifp
->mapname
)) != 0)
177 vty_out(vty
, " pbr-policy %s\n", pbr_ifp
->mapname
);
180 struct pbr_map
*pbrm_find(const char *name
)
184 strlcpy(pbrm
.name
, name
, sizeof(pbrm
.name
));
186 return RB_FIND(pbr_map_entry_head
, &pbr_maps
, &pbrm
);
189 extern void pbr_map_delete(struct pbr_map_sequence
*pbrms
)
191 struct pbr_map
*pbrm
;
192 struct listnode
*inode
;
193 struct pbr_map_interface
*pmi
;
195 pbrm
= pbrms
->parent
;
197 for (ALL_LIST_ELEMENTS_RO(pbrm
->incoming
, inode
, pmi
))
198 pbr_send_pbr_map(pbrms
, pmi
, false);
201 pbr_nht_delete_individual_nexthop(pbrms
);
203 listnode_delete(pbrm
->seqnumbers
, pbrms
);
205 if (pbrm
->seqnumbers
->count
== 0) {
206 RB_REMOVE(pbr_map_entry_head
, &pbr_maps
, pbrm
);
208 bf_free(pbrm
->ifi_bitfield
);
209 XFREE(MTYPE_PBR_MAP
, pbrm
);
213 void pbr_map_delete_nexthop_group(struct pbr_map_sequence
*pbrms
)
215 struct pbr_map
*pbrm
= pbrms
->parent
;
216 struct listnode
*node
;
217 struct pbr_map_interface
*pmi
;
219 if (pbrm
->valid
&& pbrms
->nhs_installed
&& pbrm
->incoming
->count
) {
220 for (ALL_LIST_ELEMENTS_RO(pbrm
->incoming
, node
, pmi
))
221 pbr_send_pbr_map(pbrms
, pmi
, false);
225 pbrms
->nhs_installed
= false;
226 pbrms
->reason
|= PBR_MAP_INVALID_NO_NEXTHOPS
;
227 pbrms
->nhgrp_name
= NULL
;
230 struct pbr_map_sequence
*pbrms_lookup_unique(uint32_t unique
, ifindex_t ifindex
,
231 struct pbr_map_interface
**ppmi
)
233 struct pbr_map_sequence
*pbrms
;
234 struct listnode
*snode
, *inode
;
235 struct pbr_map_interface
*pmi
;
236 struct pbr_map
*pbrm
;
238 RB_FOREACH (pbrm
, pbr_map_entry_head
, &pbr_maps
) {
239 for (ALL_LIST_ELEMENTS_RO(pbrm
->incoming
, inode
, pmi
)) {
240 if (pmi
->ifp
->ifindex
!= ifindex
)
246 for (ALL_LIST_ELEMENTS_RO(pbrm
->seqnumbers
, snode
,
248 DEBUGD(&pbr_dbg_map
, "%s: Comparing %u to %u",
249 __PRETTY_FUNCTION__
, pbrms
->unique
,
251 if (pbrms
->unique
== unique
)
260 static void pbr_map_add_interfaces(struct pbr_map
*pbrm
)
262 struct interface
*ifp
;
263 struct pbr_interface
*pbr_ifp
;
266 RB_FOREACH (vrf
, vrf_name_head
, &vrfs_by_name
) {
267 FOR_ALL_INTERFACES (vrf
, ifp
) {
270 if (strcmp(pbrm
->name
, pbr_ifp
->mapname
) == 0)
271 pbr_map_add_interface(pbrm
, ifp
);
277 struct pbr_map_sequence
*pbrms_get(const char *name
, uint32_t seqno
)
279 struct pbr_map
*pbrm
;
280 struct pbr_map_sequence
*pbrms
;
281 struct listnode
*node
;
283 pbrm
= pbrm_find(name
);
285 pbrm
= XCALLOC(MTYPE_PBR_MAP
, sizeof(*pbrm
));
286 snprintf(pbrm
->name
, sizeof(pbrm
->name
), "%s", name
);
288 pbrm
->seqnumbers
= list_new();
289 pbrm
->seqnumbers
->cmp
=
290 (int (*)(void *, void *))pbr_map_sequence_compare
;
291 pbrm
->seqnumbers
->del
=
292 (void (*)(void *))pbr_map_sequence_delete
;
294 pbrm
->incoming
= list_new();
295 pbrm
->incoming
->cmp
=
296 (int (*)(void *, void *))pbr_map_interface_compare
;
297 pbrm
->incoming
->del
=
298 (void (*)(void *))pbr_map_interface_list_delete
;
300 RB_INSERT(pbr_map_entry_head
, &pbr_maps
, pbrm
);
302 bf_init(pbrm
->ifi_bitfield
, 64);
303 pbr_map_add_interfaces(pbrm
);
306 for (ALL_LIST_ELEMENTS_RO(pbrm
->seqnumbers
, node
, pbrms
)) {
307 if (pbrms
->seqno
== seqno
)
313 pbrms
= XCALLOC(MTYPE_PBR_MAP_SEQNO
, sizeof(*pbrms
));
314 pbrms
->unique
= pbr_map_sequence_unique
++;
315 pbrms
->seqno
= seqno
;
316 pbrms
->ruleno
= pbr_nht_get_next_rule(seqno
);
317 pbrms
->parent
= pbrm
;
319 PBR_MAP_INVALID_SRCDST
|
320 PBR_MAP_INVALID_NO_NEXTHOPS
;
322 QOBJ_REG(pbrms
, pbr_map_sequence
);
323 listnode_add_sort(pbrm
->seqnumbers
, pbrms
);
330 pbr_map_sequence_check_nexthops_valid(struct pbr_map_sequence
*pbrms
)
333 * Check validness of the nexthop or nexthop-group
335 if (!pbrms
->nhg
&& !pbrms
->nhgrp_name
)
336 pbrms
->reason
|= PBR_MAP_INVALID_NO_NEXTHOPS
;
338 if (pbrms
->nhg
&& pbrms
->nhgrp_name
)
339 pbrms
->reason
|= PBR_MAP_INVALID_BOTH_NHANDGRP
;
342 !pbr_nht_nexthop_group_valid(pbrms
->internal_nhg_name
))
343 pbrms
->reason
|= PBR_MAP_INVALID_NEXTHOP
;
345 if (pbrms
->nhgrp_name
) {
346 if (!pbr_nht_nexthop_group_valid(pbrms
->nhgrp_name
))
347 pbrms
->reason
|= PBR_MAP_INVALID_NEXTHOP_GROUP
;
349 pbrms
->nhs_installed
= true;
353 static void pbr_map_sequence_check_src_dst_valid(struct pbr_map_sequence
*pbrms
)
355 if (!pbrms
->src
&& !pbrms
->dst
)
356 pbrms
->reason
|= PBR_MAP_INVALID_SRCDST
;
360 * Checks to see if we think that the pbmrs is valid. If we think
361 * the config is valid return true.
363 static void pbr_map_sequence_check_valid(struct pbr_map_sequence
*pbrms
)
365 pbr_map_sequence_check_nexthops_valid(pbrms
);
367 pbr_map_sequence_check_src_dst_valid(pbrms
);
370 static bool pbr_map_check_valid_internal(struct pbr_map
*pbrm
)
372 struct pbr_map_sequence
*pbrms
;
373 struct listnode
*node
;
376 for (ALL_LIST_ELEMENTS_RO(pbrm
->seqnumbers
, node
, pbrms
)) {
378 pbr_map_sequence_check_valid(pbrms
);
380 * A pbr_map_sequence that is invalid causes
381 * the whole shebang to be invalid
383 if (pbrms
->reason
!= 0)
391 * For a given PBR-MAP check to see if we think it is a
392 * valid config or not. If so note that it is and return
395 bool pbr_map_check_valid(const char *name
)
397 struct pbr_map
*pbrm
;
399 pbrm
= pbrm_find(name
);
402 "%s: Specified PBR-MAP(%s) does not exist?",
403 __PRETTY_FUNCTION__
, name
);
407 pbr_map_check_valid_internal(pbrm
);
411 void pbr_map_schedule_policy_from_nhg(const char *nh_group
)
413 struct pbr_map_sequence
*pbrms
;
414 struct pbr_map
*pbrm
;
415 struct listnode
*node
;
417 RB_FOREACH (pbrm
, pbr_map_entry_head
, &pbr_maps
) {
418 DEBUGD(&pbr_dbg_map
, "%s: Looking at %s", __PRETTY_FUNCTION__
,
420 for (ALL_LIST_ELEMENTS_RO(pbrm
->seqnumbers
, node
, pbrms
)) {
421 DEBUGD(&pbr_dbg_map
, "\tNH Grp name: %s",
423 pbrms
->nhgrp_name
: pbrms
->internal_nhg_name
);
425 if (pbrms
->nhgrp_name
426 && (strcmp(nh_group
, pbrms
->nhgrp_name
) == 0)) {
427 pbrms
->nhs_installed
= true;
429 pbr_map_check(pbrms
);
433 && (strcmp(nh_group
, pbrms
->internal_nhg_name
)
435 pbrms
->nhs_installed
= true;
437 pbr_map_check(pbrms
);
443 void pbr_map_policy_install(const char *name
)
445 struct pbr_map_sequence
*pbrms
;
446 struct pbr_map
*pbrm
;
447 struct listnode
*node
, *inode
;
448 struct pbr_map_interface
*pmi
;
450 DEBUGD(&pbr_dbg_map
, "%s: for %s", __PRETTY_FUNCTION__
, name
);
451 pbrm
= pbrm_find(name
);
455 for (ALL_LIST_ELEMENTS_RO(pbrm
->seqnumbers
, node
, pbrms
)) {
457 "%s: Looking at what to install %s(%u) %d %d",
458 __PRETTY_FUNCTION__
, name
, pbrms
->seqno
, pbrm
->valid
,
459 pbrms
->nhs_installed
);
461 if (pbrm
->valid
&& pbrms
->nhs_installed
&& pbrm
->incoming
->count
) {
462 DEBUGD(&pbr_dbg_map
, "\tInstalling %s %u",
463 pbrm
->name
, pbrms
->seqno
);
464 for (ALL_LIST_ELEMENTS_RO(pbrm
->incoming
, inode
, pmi
))
465 pbr_send_pbr_map(pbrms
, pmi
, true);
470 void pbr_map_policy_delete(struct pbr_map
*pbrm
, struct pbr_map_interface
*pmi
)
472 struct listnode
*node
;
473 struct pbr_map_sequence
*pbrms
;
476 for (ALL_LIST_ELEMENTS_RO(pbrm
->seqnumbers
, node
, pbrms
))
477 pbr_send_pbr_map(pbrms
, pmi
, false);
483 * For a nexthop group specified, see if any of the pbr-maps
484 * are using it and if so, check to see that we are still
485 * valid for usage. If we are valid then schedule the installation/deletion
488 void pbr_map_check_nh_group_change(const char *nh_group
)
490 struct pbr_map_sequence
*pbrms
;
491 struct pbr_map
*pbrm
;
492 struct listnode
*node
, *inode
;
493 struct pbr_map_interface
*pmi
;
496 RB_FOREACH (pbrm
, pbr_map_entry_head
, &pbr_maps
) {
497 for (ALL_LIST_ELEMENTS_RO(pbrm
->seqnumbers
, node
, pbrms
)) {
499 if (pbrms
->nhgrp_name
)
501 !strcmp(nh_group
, pbrms
->nhgrp_name
);
503 found_name
= !strcmp(nh_group
,
504 pbrms
->internal_nhg_name
);
507 bool original
= pbrm
->valid
;
509 pbr_map_check_valid_internal(pbrm
);
511 if (pbrm
->valid
&& (original
!= pbrm
->valid
))
512 pbr_map_install(pbrm
);
514 if (pbrm
->valid
== false)
515 for (ALL_LIST_ELEMENTS_RO(
516 pbrm
->incoming
, inode
,
518 pbr_send_pbr_map(pbrms
, pmi
,
525 void pbr_map_check(struct pbr_map_sequence
*pbrms
)
527 struct pbr_map
*pbrm
;
528 struct listnode
*inode
;
529 struct pbr_map_interface
*pmi
;
532 pbrm
= pbrms
->parent
;
533 DEBUGD(&pbr_dbg_map
, "%s: for %s(%u)", __PRETTY_FUNCTION__
,
534 pbrm
->name
, pbrms
->seqno
);
535 if (pbr_map_check_valid(pbrm
->name
))
536 DEBUGD(&pbr_dbg_map
, "We are totally valid %s",
539 if (pbrms
->reason
== PBR_MAP_VALID_SEQUENCE_NUMBER
) {
541 DEBUGD(&pbr_dbg_map
, "%s: Installing %s(%u) reason: %" PRIu64
,
542 __PRETTY_FUNCTION__
, pbrm
->name
, pbrms
->seqno
,
545 "\tSending PBR_MAP_POLICY_INSTALL event");
549 "%s: Removing %s(%u) reason: %" PRIu64
,
550 __PRETTY_FUNCTION__
, pbrm
->name
,
551 pbrms
->seqno
, pbrms
->reason
);
554 for (ALL_LIST_ELEMENTS_RO(pbrm
->incoming
, inode
, pmi
)) {
555 pbr_send_pbr_map(pbrms
, pmi
, install
);
559 void pbr_map_install(struct pbr_map
*pbrm
)
561 struct listnode
*node
, *inode
;
562 struct pbr_map_sequence
*pbrms
;
563 struct pbr_map_interface
*pmi
;
565 if (!pbrm
->incoming
->count
)
568 for (ALL_LIST_ELEMENTS_RO(pbrm
->seqnumbers
, node
, pbrms
))
569 for (ALL_LIST_ELEMENTS_RO(pbrm
->incoming
, inode
, pmi
))
570 pbr_send_pbr_map(pbrms
, pmi
, true);
573 void pbr_map_init(void)
575 RB_INIT(pbr_map_entry_head
, &pbr_maps
);
577 pbr_map_sequence_unique
= 1;