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 if (pbrms
->internal_nhg_name
)
75 XFREE(MTYPE_TMP
, pbrms
->internal_nhg_name
);
77 XFREE(MTYPE_PBR_MAP_SEQNO
, pbrms
);
80 static int pbr_map_interface_compare(const struct pbr_map_interface
*pmi1
,
81 const struct pbr_map_interface
*pmi2
)
83 return strcmp(pmi1
->ifp
->name
, pmi2
->ifp
->name
);
86 static void pbr_map_interface_list_delete(struct pbr_map_interface
*pmi
)
88 struct pbr_map_interface
*pmi_int
;
89 struct listnode
*node
, *nnode
;
92 RB_FOREACH (pbrm
, pbr_map_entry_head
, &pbr_maps
) {
93 for (ALL_LIST_ELEMENTS(pbrm
->incoming
, node
, nnode
, pmi_int
)) {
95 pbr_map_policy_delete(pbrm
, pmi
);
102 static const char *pbr_map_reason_str
[] = {
103 "Invalid NH-group", "Invalid NH", "No Nexthops",
104 "Both NH and NH-Group", "Invalid Src or Dst", "Deleting Sequence",
107 void pbr_map_reason_string(unsigned int reason
, char *buf
, int size
)
115 for (bit
= 0; bit
< array_size(pbr_map_reason_str
); bit
++) {
116 if ((reason
& (1 << bit
)) && (len
< size
)) {
117 len
+= snprintf((buf
+ len
), (size
- len
), "%s%s",
118 (len
> 0) ? ", " : "",
119 pbr_map_reason_str
[bit
]);
125 void pbr_map_interface_delete(struct pbr_map
*pbrm
, struct interface
*ifp_del
)
128 struct listnode
*node
;
129 struct pbr_map_interface
*pmi
;
131 for (ALL_LIST_ELEMENTS_RO(pbrm
->incoming
, node
, pmi
)) {
132 if (ifp_del
== pmi
->ifp
)
137 pbr_map_policy_delete(pbrm
, pmi
);
140 void pbr_map_add_interface(struct pbr_map
*pbrm
, struct interface
*ifp_add
)
142 struct listnode
*node
;
143 struct pbr_map_interface
*pmi
;
145 for (ALL_LIST_ELEMENTS_RO(pbrm
->incoming
, node
, pmi
)) {
146 if (ifp_add
== pmi
->ifp
)
150 pmi
= XCALLOC(MTYPE_PBR_MAP_INTERFACE
, sizeof(*pmi
));
153 listnode_add_sort(pbrm
->incoming
, pmi
);
155 bf_assign_index(pbrm
->ifi_bitfield
, pmi
->install_bit
);
156 pbr_map_check_valid(pbrm
->name
);
157 if (pbrm
->valid
&& !pbrm
->installed
)
158 pbr_map_install(pbrm
);
161 void pbr_map_write_interfaces(struct vty
*vty
, struct interface
*ifp
)
163 struct pbr_interface
*pbr_ifp
= ifp
->info
;
166 && strncmp(pbr_ifp
->mapname
, "", sizeof(pbr_ifp
->mapname
)) != 0)
167 vty_out(vty
, " pbr-policy %s\n", pbr_ifp
->mapname
);
170 struct pbr_map
*pbrm_find(const char *name
)
174 strlcpy(pbrm
.name
, name
, sizeof(pbrm
.name
));
176 return RB_FIND(pbr_map_entry_head
, &pbr_maps
, &pbrm
);
179 extern void pbr_map_delete(struct pbr_map_sequence
*pbrms
)
181 struct pbr_map
*pbrm
;
182 struct listnode
*inode
;
183 struct pbr_map_interface
*pmi
;
185 pbrm
= pbrms
->parent
;
187 for (ALL_LIST_ELEMENTS_RO(pbrm
->incoming
, inode
, pmi
))
188 pbr_send_pbr_map(pbrms
, pmi
, false);
191 pbr_nht_delete_individual_nexthop(pbrms
);
193 listnode_delete(pbrm
->seqnumbers
, pbrms
);
195 if (pbrm
->seqnumbers
->count
== 0) {
196 RB_REMOVE(pbr_map_entry_head
, &pbr_maps
, pbrm
);
198 bf_free(pbrm
->ifi_bitfield
);
199 XFREE(MTYPE_PBR_MAP
, pbrm
);
203 void pbr_map_delete_nexthop_group(struct pbr_map_sequence
*pbrms
)
205 struct pbr_map
*pbrm
= pbrms
->parent
;
206 struct listnode
*node
;
207 struct pbr_map_interface
*pmi
;
209 if (pbrm
->valid
&& pbrms
->nhs_installed
&& pbrm
->incoming
->count
) {
210 for (ALL_LIST_ELEMENTS_RO(pbrm
->incoming
, node
, pmi
))
211 pbr_send_pbr_map(pbrms
, pmi
, false);
215 pbrms
->nhs_installed
= false;
216 pbrms
->reason
|= PBR_MAP_INVALID_NO_NEXTHOPS
;
217 pbrms
->nhgrp_name
= NULL
;
220 struct pbr_map_sequence
*pbrms_lookup_unique(uint32_t unique
, ifindex_t ifindex
,
221 struct pbr_map_interface
**ppmi
)
223 struct pbr_map_sequence
*pbrms
;
224 struct listnode
*snode
, *inode
;
225 struct pbr_map_interface
*pmi
;
226 struct pbr_map
*pbrm
;
228 RB_FOREACH (pbrm
, pbr_map_entry_head
, &pbr_maps
) {
229 for (ALL_LIST_ELEMENTS_RO(pbrm
->incoming
, inode
, pmi
)) {
230 if (pmi
->ifp
->ifindex
!= ifindex
)
236 for (ALL_LIST_ELEMENTS_RO(pbrm
->seqnumbers
, snode
,
238 DEBUGD(&pbr_dbg_map
, "%s: Comparing %u to %u",
239 __PRETTY_FUNCTION__
, pbrms
->unique
,
241 if (pbrms
->unique
== unique
)
250 static void pbr_map_add_interfaces(struct pbr_map
*pbrm
)
252 struct interface
*ifp
;
253 struct pbr_interface
*pbr_ifp
;
256 RB_FOREACH (vrf
, vrf_name_head
, &vrfs_by_name
) {
257 FOR_ALL_INTERFACES (vrf
, ifp
) {
260 if (strcmp(pbrm
->name
, pbr_ifp
->mapname
) == 0)
261 pbr_map_add_interface(pbrm
, ifp
);
267 struct pbr_map_sequence
*pbrms_get(const char *name
, uint32_t seqno
)
269 struct pbr_map
*pbrm
;
270 struct pbr_map_sequence
*pbrms
;
271 struct listnode
*node
;
273 pbrm
= pbrm_find(name
);
275 pbrm
= XCALLOC(MTYPE_PBR_MAP
, sizeof(*pbrm
));
276 strcpy(pbrm
->name
, name
);
278 pbrm
->seqnumbers
= list_new();
279 pbrm
->seqnumbers
->cmp
=
280 (int (*)(void *, void *))pbr_map_sequence_compare
;
281 pbrm
->seqnumbers
->del
=
282 (void (*)(void *))pbr_map_sequence_delete
;
284 pbrm
->incoming
= list_new();
285 pbrm
->incoming
->cmp
=
286 (int (*)(void *, void *))pbr_map_interface_compare
;
287 pbrm
->incoming
->del
=
288 (void (*)(void *))pbr_map_interface_list_delete
;
290 RB_INSERT(pbr_map_entry_head
, &pbr_maps
, pbrm
);
292 bf_init(pbrm
->ifi_bitfield
, 64);
293 pbr_map_add_interfaces(pbrm
);
296 for (ALL_LIST_ELEMENTS_RO(pbrm
->seqnumbers
, node
, pbrms
)) {
297 if (pbrms
->seqno
== seqno
)
303 pbrms
= XCALLOC(MTYPE_PBR_MAP_SEQNO
, sizeof(*pbrms
));
304 pbrms
->unique
= pbr_map_sequence_unique
++;
305 pbrms
->seqno
= seqno
;
306 pbrms
->ruleno
= pbr_nht_get_next_rule(seqno
);
307 pbrms
->parent
= pbrm
;
309 PBR_MAP_INVALID_SRCDST
|
310 PBR_MAP_INVALID_NO_NEXTHOPS
;
312 QOBJ_REG(pbrms
, pbr_map_sequence
);
313 listnode_add_sort(pbrm
->seqnumbers
, pbrms
);
315 pbrm
->installed
= false;
322 pbr_map_sequence_check_nexthops_valid(struct pbr_map_sequence
*pbrms
)
325 * Check validness of the nexthop or nexthop-group
327 if (!pbrms
->nhg
&& !pbrms
->nhgrp_name
)
328 pbrms
->reason
|= PBR_MAP_INVALID_NO_NEXTHOPS
;
330 if (pbrms
->nhg
&& pbrms
->nhgrp_name
)
331 pbrms
->reason
|= PBR_MAP_INVALID_BOTH_NHANDGRP
;
334 !pbr_nht_nexthop_group_valid(pbrms
->internal_nhg_name
))
335 pbrms
->reason
|= PBR_MAP_INVALID_NEXTHOP
;
337 if (pbrms
->nhgrp_name
) {
338 if (!pbr_nht_nexthop_group_valid(pbrms
->nhgrp_name
))
339 pbrms
->reason
|= PBR_MAP_INVALID_NEXTHOP_GROUP
;
341 pbrms
->nhs_installed
= true;
345 static void pbr_map_sequence_check_src_dst_valid(struct pbr_map_sequence
*pbrms
)
347 if (!pbrms
->src
&& !pbrms
->dst
)
348 pbrms
->reason
|= PBR_MAP_INVALID_SRCDST
;
352 * Checks to see if we think that the pbmrs is valid. If we think
353 * the config is valid return true.
355 static void pbr_map_sequence_check_valid(struct pbr_map_sequence
*pbrms
)
357 pbr_map_sequence_check_nexthops_valid(pbrms
);
359 pbr_map_sequence_check_src_dst_valid(pbrms
);
362 static bool pbr_map_check_valid_internal(struct pbr_map
*pbrm
)
364 struct pbr_map_sequence
*pbrms
;
365 struct listnode
*node
;
368 for (ALL_LIST_ELEMENTS_RO(pbrm
->seqnumbers
, node
, pbrms
)) {
370 pbr_map_sequence_check_valid(pbrms
);
372 * A pbr_map_sequence that is invalid causes
373 * the whole shebang to be invalid
375 if (pbrms
->reason
!= 0)
383 * For a given PBR-MAP check to see if we think it is a
384 * valid config or not. If so note that it is and return
387 bool pbr_map_check_valid(const char *name
)
389 struct pbr_map
*pbrm
;
391 pbrm
= pbrm_find(name
);
394 "%s: Specified PBR-MAP(%s) does not exist?",
395 __PRETTY_FUNCTION__
, name
);
399 pbr_map_check_valid_internal(pbrm
);
403 void pbr_map_schedule_policy_from_nhg(const char *nh_group
)
405 struct pbr_map_sequence
*pbrms
;
406 struct pbr_map
*pbrm
;
407 struct listnode
*node
;
409 RB_FOREACH (pbrm
, pbr_map_entry_head
, &pbr_maps
) {
410 DEBUGD(&pbr_dbg_map
, "%s: Looking at %s", __PRETTY_FUNCTION__
,
412 for (ALL_LIST_ELEMENTS_RO(pbrm
->seqnumbers
, node
, pbrms
)) {
413 DEBUGD(&pbr_dbg_map
, "\tNH Grp name: %s",
414 pbrms
->nhgrp_name
? pbrms
->nhgrp_name
: "NULL");
416 if (pbrms
->nhgrp_name
417 && (strcmp(nh_group
, pbrms
->nhgrp_name
) == 0)) {
418 pbrms
->nhs_installed
= true;
420 pbr_map_check(pbrms
);
424 && (strcmp(nh_group
, pbrms
->internal_nhg_name
)
426 pbrms
->nhs_installed
= true;
428 pbr_map_check(pbrms
);
434 void pbr_map_policy_install(const char *name
)
436 struct pbr_map_sequence
*pbrms
;
437 struct pbr_map
*pbrm
;
438 struct listnode
*node
, *inode
;
439 struct pbr_map_interface
*pmi
;
441 DEBUGD(&pbr_dbg_map
, "%s: for %s", __PRETTY_FUNCTION__
, name
);
442 pbrm
= pbrm_find(name
);
446 for (ALL_LIST_ELEMENTS_RO(pbrm
->seqnumbers
, node
, pbrms
)) {
448 "%s: Looking at what to install %s(%u) %d %d",
449 __PRETTY_FUNCTION__
, name
, pbrms
->seqno
, pbrm
->valid
,
450 pbrms
->nhs_installed
);
452 if (pbrm
->valid
&& pbrms
->nhs_installed
&& pbrm
->incoming
->count
) {
453 DEBUGD(&pbr_dbg_map
, "\tInstalling %s %u",
454 pbrm
->name
, pbrms
->seqno
);
455 for (ALL_LIST_ELEMENTS_RO(pbrm
->incoming
, inode
, pmi
))
456 pbr_send_pbr_map(pbrms
, pmi
, true);
461 void pbr_map_policy_delete(struct pbr_map
*pbrm
, struct pbr_map_interface
*pmi
)
463 struct listnode
*node
;
464 struct pbr_map_sequence
*pbrms
;
467 for (ALL_LIST_ELEMENTS_RO(pbrm
->seqnumbers
, node
, pbrms
))
468 pbr_send_pbr_map(pbrms
, pmi
, false);
470 listnode_delete(pbrm
->incoming
, pmi
);
473 bf_release_index(pbrm
->ifi_bitfield
, pmi
->install_bit
);
474 XFREE(MTYPE_PBR_MAP_INTERFACE
, pmi
);
478 * For a nexthop group specified, see if any of the pbr-maps
479 * are using it and if so, check to see that we are still
480 * valid for usage. If we are valid then schedule the installation/deletion
483 void pbr_map_check_nh_group_change(const char *nh_group
)
485 struct pbr_map_sequence
*pbrms
;
486 struct pbr_map
*pbrm
;
487 struct listnode
*node
, *inode
;
488 struct pbr_map_interface
*pmi
;
491 RB_FOREACH (pbrm
, pbr_map_entry_head
, &pbr_maps
) {
492 for (ALL_LIST_ELEMENTS_RO(pbrm
->seqnumbers
, node
, pbrms
)) {
494 if (pbrms
->nhgrp_name
)
496 !strcmp(nh_group
, pbrms
->nhgrp_name
);
498 found_name
= !strcmp(nh_group
,
499 pbrms
->internal_nhg_name
);
502 bool original
= pbrm
->valid
;
504 pbr_map_check_valid_internal(pbrm
);
506 if (pbrm
->valid
&& (original
!= pbrm
->valid
))
507 pbr_map_install(pbrm
);
509 if (pbrm
->valid
== false)
510 for (ALL_LIST_ELEMENTS_RO(
511 pbrm
->incoming
, inode
,
513 pbr_send_pbr_map(pbrms
, pmi
,
520 void pbr_map_check(struct pbr_map_sequence
*pbrms
)
522 struct pbr_map
*pbrm
;
523 struct listnode
*inode
;
524 struct pbr_map_interface
*pmi
;
527 pbrm
= pbrms
->parent
;
528 DEBUGD(&pbr_dbg_map
, "%s: for %s(%u)", __PRETTY_FUNCTION__
,
529 pbrm
->name
, pbrms
->seqno
);
530 if (pbr_map_check_valid(pbrm
->name
))
531 DEBUGD(&pbr_dbg_map
, "We are totally valid %s\n",
534 DEBUGD(&pbr_dbg_map
, "%s: Installing %s(%u) reason: %" PRIu64
,
535 __PRETTY_FUNCTION__
, pbrm
->name
, pbrms
->seqno
, pbrms
->reason
);
537 if (pbrms
->reason
== PBR_MAP_VALID_SEQUENCE_NUMBER
) {
539 DEBUGD(&pbr_dbg_map
, "%s: Installing %s(%u) reason: %" PRIu64
,
540 __PRETTY_FUNCTION__
, pbrm
->name
, pbrms
->seqno
,
543 "\tSending PBR_MAP_POLICY_INSTALL event");
547 "%s: Removing %s(%u) reason: %" PRIu64
,
548 __PRETTY_FUNCTION__
, pbrm
->name
,
549 pbrms
->seqno
, pbrms
->reason
);
552 for (ALL_LIST_ELEMENTS_RO(pbrm
->incoming
, inode
, pmi
)) {
553 pbr_send_pbr_map(pbrms
, pmi
, install
);
557 void pbr_map_install(struct pbr_map
*pbrm
)
559 struct listnode
*node
, *inode
;
560 struct pbr_map_sequence
*pbrms
;
561 struct pbr_map_interface
*pmi
;
563 if (!pbrm
->incoming
->count
)
566 for (ALL_LIST_ELEMENTS_RO(pbrm
->seqnumbers
, node
, pbrms
))
567 for (ALL_LIST_ELEMENTS_RO(pbrm
->incoming
, inode
, pmi
))
568 pbr_send_pbr_map(pbrms
, pmi
, true);
570 pbrm
->installed
= true;
573 void pbr_map_init(void)
575 RB_INIT(pbr_map_entry_head
, &pbr_maps
);
577 pbr_map_sequence_unique
= 1;