]> git.proxmox.com Git - mirror_frr.git/blob - pbrd/pbr_map.c
Merge pull request #12798 from donaldsharp/rib_match_multicast
[mirror_frr.git] / pbrd / pbr_map.c
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3 * PBR-map Code
4 * Copyright (C) 2018 Cumulus Networks, Inc.
5 * Donald Sharp
6 */
7 #include <zebra.h>
8
9 #include "thread.h"
10 #include "linklist.h"
11 #include "prefix.h"
12 #include "table.h"
13 #include "vrf.h"
14 #include "nexthop.h"
15 #include "nexthop_group.h"
16 #include "memory.h"
17 #include "log.h"
18 #include "vty.h"
19
20 #include "pbr_nht.h"
21 #include "pbr_map.h"
22 #include "pbr_zebra.h"
23 #include "pbr_memory.h"
24 #include "pbr_debug.h"
25 #include "pbr_vrf.h"
26
27 DEFINE_MTYPE_STATIC(PBRD, PBR_MAP, "PBR Map");
28 DEFINE_MTYPE_STATIC(PBRD, PBR_MAP_SEQNO, "PBR Map Sequence");
29 DEFINE_MTYPE_STATIC(PBRD, PBR_MAP_INTERFACE, "PBR Map Interface");
30
31 static uint32_t pbr_map_sequence_unique;
32
33 static bool pbr_map_check_valid_internal(struct pbr_map *pbrm);
34 static inline int pbr_map_compare(const struct pbr_map *pbrmap1,
35 const struct pbr_map *pbrmap2);
36
37 RB_GENERATE(pbr_map_entry_head, pbr_map, pbr_map_entry, pbr_map_compare)
38
39 struct pbr_map_entry_head pbr_maps = RB_INITIALIZER(&pbr_maps);
40
41 DEFINE_QOBJ_TYPE(pbr_map_sequence);
42
43 static inline int pbr_map_compare(const struct pbr_map *pbrmap1,
44 const struct pbr_map *pbrmap2)
45 {
46 return strcmp(pbrmap1->name, pbrmap2->name);
47 }
48
49 static int pbr_map_sequence_compare(const struct pbr_map_sequence *pbrms1,
50 const struct pbr_map_sequence *pbrms2)
51 {
52 if (pbrms1->seqno == pbrms2->seqno)
53 return 0;
54
55 if (pbrms1->seqno < pbrms2->seqno)
56 return -1;
57
58 return 1;
59 }
60
61 static void pbr_map_sequence_delete(struct pbr_map_sequence *pbrms)
62 {
63 XFREE(MTYPE_TMP, pbrms->internal_nhg_name);
64
65 QOBJ_UNREG(pbrms);
66 XFREE(MTYPE_PBR_MAP_SEQNO, pbrms);
67 }
68
69 static int pbr_map_interface_compare(const struct pbr_map_interface *pmi1,
70 const struct pbr_map_interface *pmi2)
71 {
72 return strcmp(pmi1->ifp->name, pmi2->ifp->name);
73 }
74
75 static void pbr_map_interface_list_delete(struct pbr_map_interface *pmi)
76 {
77 struct pbr_map_interface *pmi_int;
78 struct listnode *node, *nnode;
79 struct pbr_map *pbrm;
80
81 RB_FOREACH (pbrm, pbr_map_entry_head, &pbr_maps) {
82 for (ALL_LIST_ELEMENTS(pbrm->incoming, node, nnode, pmi_int)) {
83 if (pmi == pmi_int) {
84 pbr_map_policy_delete(pbrm, pmi);
85 return;
86 }
87 }
88 }
89 }
90
91 static bool pbrms_is_installed(const struct pbr_map_sequence *pbrms,
92 const struct pbr_map_interface *pmi)
93 {
94 uint64_t is_installed = (uint64_t)1 << pmi->install_bit;
95
96 is_installed &= pbrms->installed;
97
98 if (is_installed)
99 return true;
100
101 return false;
102 }
103
104 /* If any sequence is installed on the interface, assume installed */
105 static bool
106 pbr_map_interface_is_installed(const struct pbr_map *pbrm,
107 const struct pbr_map_interface *check_pmi)
108 {
109
110 struct pbr_map_sequence *pbrms;
111 struct pbr_map_interface *pmi;
112 struct listnode *node, *inode;
113
114 for (ALL_LIST_ELEMENTS_RO(pbrm->seqnumbers, node, pbrms))
115 for (ALL_LIST_ELEMENTS_RO(pbrm->incoming, inode, pmi))
116 if (pmi == check_pmi && pbrms_is_installed(pbrms, pmi))
117 return true;
118
119 return false;
120 }
121
122 static bool pbr_map_interface_is_valid(const struct pbr_map_interface *pmi)
123 {
124 /* Don't install rules without a real ifindex on the incoming interface.
125 *
126 * This can happen when we have config for an interface that does not
127 * exist or when an interface is changing vrfs.
128 */
129 if (pmi->ifp && pmi->ifp->ifindex != IFINDEX_INTERNAL)
130 return true;
131
132 return false;
133 }
134
135 static void pbr_map_pbrms_update_common(struct pbr_map_sequence *pbrms,
136 bool install, bool changed)
137 {
138 struct pbr_map *pbrm;
139 struct listnode *node;
140 struct pbr_map_interface *pmi;
141
142 pbrm = pbrms->parent;
143
144 if (pbrms->nhs_installed && pbrm->incoming->count) {
145 for (ALL_LIST_ELEMENTS_RO(pbrm->incoming, node, pmi)) {
146 if (!pmi->ifp)
147 continue;
148
149 if (install && !pbr_map_interface_is_valid(pmi))
150 continue;
151
152 pbr_send_pbr_map(pbrms, pmi, install, changed);
153 }
154 }
155 }
156
157 static void pbr_map_pbrms_install(struct pbr_map_sequence *pbrms, bool changed)
158 {
159 pbr_map_pbrms_update_common(pbrms, true, changed);
160 }
161
162 static void pbr_map_pbrms_uninstall(struct pbr_map_sequence *pbrms)
163 {
164 pbr_map_pbrms_update_common(pbrms, false, false);
165 }
166
167 static const char *const pbr_map_reason_str[] = {
168 "Invalid NH-group", "Invalid NH", "No Nexthops",
169 "Both NH and NH-Group", "Invalid Src or Dst", "Invalid VRF",
170 "Both VLAN Set and Strip", "Deleting Sequence",
171 };
172
173 void pbr_map_reason_string(unsigned int reason, char *buf, int size)
174 {
175 unsigned int bit;
176 int len = 0;
177
178 if (!buf)
179 return;
180
181 for (bit = 0; bit < array_size(pbr_map_reason_str); bit++) {
182 if ((reason & (1 << bit)) && (len < size)) {
183 len += snprintf((buf + len), (size - len), "%s%s",
184 (len > 0) ? ", " : "",
185 pbr_map_reason_str[bit]);
186 }
187 }
188 }
189
190 void pbr_map_final_interface_deletion(struct pbr_map *pbrm,
191 struct pbr_map_interface *pmi)
192 {
193 if (pmi->delete && !pbr_map_interface_is_installed(pbrm, pmi)) {
194 listnode_delete(pbrm->incoming, pmi);
195 pmi->pbrm = NULL;
196
197 bf_release_index(pbrm->ifi_bitfield, pmi->install_bit);
198 XFREE(MTYPE_PBR_MAP_INTERFACE, pmi);
199 }
200 }
201
202 void pbr_map_interface_delete(struct pbr_map *pbrm, struct interface *ifp_del)
203 {
204
205 struct listnode *node;
206 struct pbr_map_interface *pmi;
207
208 for (ALL_LIST_ELEMENTS_RO(pbrm->incoming, node, pmi)) {
209 if (ifp_del == pmi->ifp)
210 break;
211 }
212
213 if (pmi)
214 pbr_map_policy_delete(pbrm, pmi);
215 }
216
217 void pbr_map_add_interface(struct pbr_map *pbrm, struct interface *ifp_add)
218 {
219 struct listnode *node;
220 struct pbr_map_interface *pmi;
221
222 for (ALL_LIST_ELEMENTS_RO(pbrm->incoming, node, pmi)) {
223 if (ifp_add == pmi->ifp)
224 return;
225 }
226
227 pmi = XCALLOC(MTYPE_PBR_MAP_INTERFACE, sizeof(*pmi));
228 pmi->ifp = ifp_add;
229 pmi->pbrm = pbrm;
230 listnode_add_sort(pbrm->incoming, pmi);
231
232 bf_assign_index(pbrm->ifi_bitfield, pmi->install_bit);
233 pbr_map_check_valid(pbrm->name);
234 if (pbrm->valid)
235 pbr_map_install(pbrm);
236 }
237
238 static int
239 pbr_map_policy_interface_update_common(const struct interface *ifp,
240 struct pbr_interface **pbr_ifp,
241 struct pbr_map **pbrm)
242 {
243 if (!ifp->info) {
244 DEBUGD(&pbr_dbg_map, "%s: %s has no pbr_interface info",
245 __func__, ifp->name);
246 return -1;
247 }
248
249 *pbr_ifp = ifp->info;
250
251 *pbrm = pbrm_find((*pbr_ifp)->mapname);
252
253 if (!*pbrm) {
254 DEBUGD(&pbr_dbg_map, "%s: applied PBR-MAP(%s) does not exist?",
255 __func__, (*pbr_ifp)->mapname);
256 return -1;
257 }
258
259 return 0;
260 }
261
262 void pbr_map_policy_interface_update(const struct interface *ifp, bool state_up)
263 {
264 struct pbr_interface *pbr_ifp;
265 struct pbr_map_sequence *pbrms;
266 struct pbr_map *pbrm;
267 struct listnode *node, *inode;
268 struct pbr_map_interface *pmi;
269
270 if (pbr_map_policy_interface_update_common(ifp, &pbr_ifp, &pbrm))
271 return;
272
273 DEBUGD(&pbr_dbg_map, "%s: %s %s rules on interface %s", __func__,
274 pbr_ifp->mapname, (state_up ? "installing" : "removing"),
275 ifp->name);
276
277 /*
278 * Walk the list and install/remove maps on the interface.
279 */
280 for (ALL_LIST_ELEMENTS_RO(pbrm->seqnumbers, node, pbrms))
281 for (ALL_LIST_ELEMENTS_RO(pbrm->incoming, inode, pmi))
282 if (pmi->ifp == ifp && pbr_map_interface_is_valid(pmi))
283 pbr_send_pbr_map(pbrms, pmi, state_up, true);
284 }
285
286 static void pbrms_vrf_update(struct pbr_map_sequence *pbrms,
287 const struct pbr_vrf *pbr_vrf)
288 {
289 const char *vrf_name = pbr_vrf_name(pbr_vrf);
290
291 if (pbrms->vrf_lookup
292 && (strncmp(vrf_name, pbrms->vrf_name, sizeof(pbrms->vrf_name))
293 == 0)) {
294 DEBUGD(&pbr_dbg_map, " Seq %u uses vrf %s (%u), updating map",
295 pbrms->seqno, vrf_name, pbr_vrf_id(pbr_vrf));
296
297 pbr_map_check(pbrms, false);
298 }
299 }
300
301 /* Vrf enabled/disabled */
302 void pbr_map_vrf_update(const struct pbr_vrf *pbr_vrf)
303 {
304 struct pbr_map *pbrm;
305 struct pbr_map_sequence *pbrms;
306 struct listnode *node;
307
308 if (!pbr_vrf)
309 return;
310
311 bool enabled = pbr_vrf_is_enabled(pbr_vrf);
312
313 DEBUGD(&pbr_dbg_map, "%s: %s (%u) %s, updating pbr maps", __func__,
314 pbr_vrf_name(pbr_vrf), pbr_vrf_id(pbr_vrf),
315 enabled ? "enabled" : "disabled");
316
317 RB_FOREACH (pbrm, pbr_map_entry_head, &pbr_maps) {
318 DEBUGD(&pbr_dbg_map, "%s: Looking at %s", __func__, pbrm->name);
319 for (ALL_LIST_ELEMENTS_RO(pbrm->seqnumbers, node, pbrms))
320 pbrms_vrf_update(pbrms, pbr_vrf);
321 }
322 }
323
324 void pbr_map_write_interfaces(struct vty *vty, struct interface *ifp)
325 {
326 struct pbr_interface *pbr_ifp = ifp->info;
327
328 if (pbr_ifp
329 && strncmp(pbr_ifp->mapname, "", sizeof(pbr_ifp->mapname)) != 0)
330 vty_out(vty, " pbr-policy %s\n", pbr_ifp->mapname);
331 }
332
333 struct pbr_map *pbrm_find(const char *name)
334 {
335 struct pbr_map pbrm;
336
337 strlcpy(pbrm.name, name, sizeof(pbrm.name));
338
339 return RB_FIND(pbr_map_entry_head, &pbr_maps, &pbrm);
340 }
341
342 extern void pbr_map_delete(struct pbr_map_sequence *pbrms)
343 {
344 struct pbr_map *pbrm;
345 struct listnode *inode;
346 struct pbr_map_interface *pmi;
347
348 pbrm = pbrms->parent;
349
350 for (ALL_LIST_ELEMENTS_RO(pbrm->incoming, inode, pmi))
351 pbr_send_pbr_map(pbrms, pmi, false, false);
352
353 if (pbrms->nhg)
354 pbr_nht_delete_individual_nexthop(pbrms);
355
356 listnode_delete(pbrm->seqnumbers, pbrms);
357
358 if (pbrm->seqnumbers->count == 0) {
359 RB_REMOVE(pbr_map_entry_head, &pbr_maps, pbrm);
360
361 bf_free(pbrm->ifi_bitfield);
362 XFREE(MTYPE_PBR_MAP, pbrm);
363 }
364 }
365
366 static void pbr_map_delete_common(struct pbr_map_sequence *pbrms)
367 {
368 struct pbr_map *pbrm = pbrms->parent;
369
370 pbr_map_pbrms_uninstall(pbrms);
371
372 pbrm->valid = false;
373 pbrms->nhs_installed = false;
374 pbrms->reason |= PBR_MAP_INVALID_NO_NEXTHOPS;
375 XFREE(MTYPE_TMP, pbrms->nhgrp_name);
376 }
377
378 void pbr_map_delete_nexthops(struct pbr_map_sequence *pbrms)
379 {
380 pbr_map_delete_common(pbrms);
381 }
382
383 void pbr_map_delete_vrf(struct pbr_map_sequence *pbrms)
384 {
385 pbr_map_delete_common(pbrms);
386 }
387
388 struct pbr_map_sequence *pbrms_lookup_unique(uint32_t unique, char *ifname,
389 struct pbr_map_interface **ppmi)
390 {
391 struct pbr_map_sequence *pbrms;
392 struct listnode *snode, *inode;
393 struct pbr_map_interface *pmi;
394 struct pbr_map *pbrm;
395
396 RB_FOREACH (pbrm, pbr_map_entry_head, &pbr_maps) {
397 for (ALL_LIST_ELEMENTS_RO(pbrm->incoming, inode, pmi)) {
398 if (strcmp(pmi->ifp->name, ifname) != 0)
399 continue;
400
401 if (ppmi)
402 *ppmi = pmi;
403
404 for (ALL_LIST_ELEMENTS_RO(pbrm->seqnumbers, snode,
405 pbrms)) {
406 DEBUGD(&pbr_dbg_map, "%s: Comparing %u to %u",
407 __func__, pbrms->unique, unique);
408 if (pbrms->unique == unique)
409 return pbrms;
410 }
411 }
412 }
413
414 return NULL;
415 }
416
417 static void pbr_map_add_interfaces(struct pbr_map *pbrm)
418 {
419 struct interface *ifp;
420 struct pbr_interface *pbr_ifp;
421 struct vrf *vrf;
422
423 RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) {
424 FOR_ALL_INTERFACES (vrf, ifp) {
425 if (ifp->info) {
426 pbr_ifp = ifp->info;
427 if (strcmp(pbrm->name, pbr_ifp->mapname) == 0)
428 pbr_map_add_interface(pbrm, ifp);
429 }
430 }
431 }
432 }
433
434 /* Decodes a standardized DSCP into its representative value */
435 uint8_t pbr_map_decode_dscp_enum(const char *name)
436 {
437 /* Standard Differentiated Services Field Codepoints */
438 if (!strcmp(name, "cs0"))
439 return 0;
440 if (!strcmp(name, "cs1"))
441 return 8;
442 if (!strcmp(name, "cs2"))
443 return 16;
444 if (!strcmp(name, "cs3"))
445 return 24;
446 if (!strcmp(name, "cs4"))
447 return 32;
448 if (!strcmp(name, "cs5"))
449 return 40;
450 if (!strcmp(name, "cs6"))
451 return 48;
452 if (!strcmp(name, "cs7"))
453 return 56;
454 if (!strcmp(name, "af11"))
455 return 10;
456 if (!strcmp(name, "af12"))
457 return 12;
458 if (!strcmp(name, "af13"))
459 return 14;
460 if (!strcmp(name, "af21"))
461 return 18;
462 if (!strcmp(name, "af22"))
463 return 20;
464 if (!strcmp(name, "af23"))
465 return 22;
466 if (!strcmp(name, "af31"))
467 return 26;
468 if (!strcmp(name, "af32"))
469 return 28;
470 if (!strcmp(name, "af33"))
471 return 30;
472 if (!strcmp(name, "af41"))
473 return 34;
474 if (!strcmp(name, "af42"))
475 return 36;
476 if (!strcmp(name, "af43"))
477 return 38;
478 if (!strcmp(name, "ef"))
479 return 46;
480 if (!strcmp(name, "voice-admit"))
481 return 44;
482
483 /* No match? Error out */
484 return -1;
485 }
486
487 struct pbr_map_sequence *pbrms_get(const char *name, uint32_t seqno)
488 {
489 struct pbr_map *pbrm;
490 struct pbr_map_sequence *pbrms;
491 struct listnode *node;
492
493 pbrm = pbrm_find(name);
494 if (!pbrm) {
495 pbrm = XCALLOC(MTYPE_PBR_MAP, sizeof(*pbrm));
496 snprintf(pbrm->name, sizeof(pbrm->name), "%s", name);
497
498 pbrm->seqnumbers = list_new();
499 pbrm->seqnumbers->cmp =
500 (int (*)(void *, void *))pbr_map_sequence_compare;
501 pbrm->seqnumbers->del =
502 (void (*)(void *))pbr_map_sequence_delete;
503
504 pbrm->incoming = list_new();
505 pbrm->incoming->cmp =
506 (int (*)(void *, void *))pbr_map_interface_compare;
507 pbrm->incoming->del =
508 (void (*)(void *))pbr_map_interface_list_delete;
509
510 RB_INSERT(pbr_map_entry_head, &pbr_maps, pbrm);
511
512 bf_init(pbrm->ifi_bitfield, 64);
513 pbr_map_add_interfaces(pbrm);
514 }
515
516 for (ALL_LIST_ELEMENTS_RO(pbrm->seqnumbers, node, pbrms)) {
517 if (pbrms->seqno == seqno)
518 break;
519
520 }
521
522 if (!pbrms) {
523 pbrms = XCALLOC(MTYPE_PBR_MAP_SEQNO, sizeof(*pbrms));
524 pbrms->unique = pbr_map_sequence_unique++;
525 pbrms->seqno = seqno;
526 pbrms->ruleno = pbr_nht_get_next_rule(seqno);
527 pbrms->parent = pbrm;
528
529 pbrms->action_vlan_id = 0;
530 pbrms->action_vlan_flags = 0;
531 pbrms->action_pcp = 0;
532
533 pbrms->action_queue_id = PBR_MAP_UNDEFINED_QUEUE_ID;
534
535 pbrms->reason =
536 PBR_MAP_INVALID_EMPTY |
537 PBR_MAP_INVALID_NO_NEXTHOPS;
538 pbrms->vrf_name[0] = '\0';
539
540 QOBJ_REG(pbrms, pbr_map_sequence);
541 listnode_add_sort(pbrm->seqnumbers, pbrms);
542 }
543
544 return pbrms;
545 }
546
547 static void
548 pbr_map_sequence_check_nexthops_valid(struct pbr_map_sequence *pbrms)
549 {
550 /* Check if any are present first */
551 if (!pbrms->vrf_unchanged && !pbrms->vrf_lookup && !pbrms->nhg
552 && !pbrms->nhgrp_name) {
553 pbrms->reason |= PBR_MAP_INVALID_NO_NEXTHOPS;
554 return;
555 }
556
557 /*
558 * Check validness of vrf.
559 */
560
561 /* This one can be considered always valid */
562 if (pbrms->vrf_unchanged)
563 pbrms->nhs_installed = true;
564
565 if (pbrms->vrf_lookup) {
566 struct pbr_vrf *pbr_vrf =
567 pbr_vrf_lookup_by_name(pbrms->vrf_name);
568
569 if (pbr_vrf && pbr_vrf_is_valid(pbr_vrf))
570 pbrms->nhs_installed = true;
571 else
572 pbrms->reason |= PBR_MAP_INVALID_VRF;
573 }
574
575 /*
576 * Check validness of the nexthop or nexthop-group
577 */
578
579 /* Only nexthop or nexthop group allowed */
580 if (pbrms->nhg && pbrms->nhgrp_name)
581 pbrms->reason |= PBR_MAP_INVALID_BOTH_NHANDGRP;
582
583 if (pbrms->nhg &&
584 !pbr_nht_nexthop_group_valid(pbrms->internal_nhg_name))
585 pbrms->reason |= PBR_MAP_INVALID_NEXTHOP;
586
587 if (pbrms->nhgrp_name) {
588 if (!pbr_nht_nexthop_group_valid(pbrms->nhgrp_name))
589 pbrms->reason |= PBR_MAP_INVALID_NEXTHOP_GROUP;
590 else
591 pbrms->nhs_installed = true;
592 }
593 }
594
595 static void pbr_map_sequence_check_not_empty(struct pbr_map_sequence *pbrms)
596 {
597 if (!pbrms->src && !pbrms->dst && !pbrms->mark && !pbrms->dsfield
598 && !pbrms->action_vlan_id && !pbrms->action_vlan_flags
599 && !pbrms->action_pcp
600 && pbrms->action_queue_id == PBR_MAP_UNDEFINED_QUEUE_ID)
601 pbrms->reason |= PBR_MAP_INVALID_EMPTY;
602 }
603
604 static void pbr_map_sequence_check_vlan_actions(struct pbr_map_sequence *pbrms)
605 {
606 /* The set vlan tag action does the following:
607 * 1. If the frame is untagged, it tags the frame with the
608 * configured VLAN ID.
609 * 2. If the frame is tagged, if replaces the tag.
610 *
611 * The strip vlan action removes any inner tag, so it is invalid to
612 * specify both a set and strip action.
613 */
614 if ((pbrms->action_vlan_id != 0) && (pbrms->action_vlan_flags != 0))
615 pbrms->reason |= PBR_MAP_INVALID_SET_STRIP_VLAN;
616 }
617
618
619 /*
620 * Checks to see if we think that the pbmrs is valid. If we think
621 * the config is valid return true.
622 */
623 static void pbr_map_sequence_check_valid(struct pbr_map_sequence *pbrms)
624 {
625 pbr_map_sequence_check_nexthops_valid(pbrms);
626 pbr_map_sequence_check_vlan_actions(pbrms);
627 pbr_map_sequence_check_not_empty(pbrms);
628 }
629
630 static bool pbr_map_check_valid_internal(struct pbr_map *pbrm)
631 {
632 struct pbr_map_sequence *pbrms;
633 struct listnode *node;
634
635 pbrm->valid = true;
636 for (ALL_LIST_ELEMENTS_RO(pbrm->seqnumbers, node, pbrms)) {
637 pbrms->reason = 0;
638 pbr_map_sequence_check_valid(pbrms);
639 /*
640 * A pbr_map_sequence that is invalid causes
641 * the whole shebang to be invalid
642 */
643 if (pbrms->reason != 0)
644 pbrm->valid = false;
645 }
646
647 return pbrm->valid;
648 }
649
650 /*
651 * For a given PBR-MAP check to see if we think it is a
652 * valid config or not. If so note that it is and return
653 * that we are valid.
654 */
655 bool pbr_map_check_valid(const char *name)
656 {
657 struct pbr_map *pbrm;
658
659 pbrm = pbrm_find(name);
660 if (!pbrm) {
661 DEBUGD(&pbr_dbg_map,
662 "%s: Specified PBR-MAP(%s) does not exist?", __func__,
663 name);
664 return false;
665 }
666
667 pbr_map_check_valid_internal(pbrm);
668 return pbrm->valid;
669 }
670
671 void pbr_map_schedule_policy_from_nhg(const char *nh_group, bool installed)
672 {
673 struct pbr_map_sequence *pbrms;
674 struct pbr_map *pbrm;
675 struct listnode *node;
676
677 RB_FOREACH (pbrm, pbr_map_entry_head, &pbr_maps) {
678 DEBUGD(&pbr_dbg_map, "%s: Looking at %s", __func__, pbrm->name);
679 for (ALL_LIST_ELEMENTS_RO(pbrm->seqnumbers, node, pbrms)) {
680 DEBUGD(&pbr_dbg_map, " NH Grp name: %s",
681 pbrms->nhgrp_name ?
682 pbrms->nhgrp_name : pbrms->internal_nhg_name);
683
684 if (pbrms->nhgrp_name
685 && (strcmp(nh_group, pbrms->nhgrp_name) == 0)) {
686 pbrms->nhs_installed = installed;
687
688 pbr_map_check(pbrms, false);
689 }
690
691 if (pbrms->nhg
692 && (strcmp(nh_group, pbrms->internal_nhg_name)
693 == 0)) {
694 pbrms->nhs_installed = installed;
695
696 pbr_map_check(pbrms, false);
697 }
698 }
699 }
700 }
701
702 void pbr_map_policy_install(const char *name)
703 {
704 struct pbr_map_sequence *pbrms;
705 struct pbr_map *pbrm;
706 struct listnode *node, *inode;
707 struct pbr_map_interface *pmi;
708
709 DEBUGD(&pbr_dbg_map, "%s: for %s", __func__, name);
710 pbrm = pbrm_find(name);
711 if (!pbrm)
712 return;
713
714 for (ALL_LIST_ELEMENTS_RO(pbrm->seqnumbers, node, pbrms)) {
715 DEBUGD(&pbr_dbg_map,
716 "%s: Looking at what to install %s(%u) %d %d", __func__,
717 name, pbrms->seqno, pbrm->valid, pbrms->nhs_installed);
718
719 if (pbrm->valid && pbrms->nhs_installed
720 && pbrm->incoming->count) {
721 DEBUGD(&pbr_dbg_map, " Installing %s %u", pbrm->name,
722 pbrms->seqno);
723 for (ALL_LIST_ELEMENTS_RO(pbrm->incoming, inode, pmi))
724 if (pbr_map_interface_is_valid(pmi))
725 pbr_send_pbr_map(pbrms, pmi, true,
726 false);
727 }
728 }
729 }
730
731 void pbr_map_policy_delete(struct pbr_map *pbrm, struct pbr_map_interface *pmi)
732 {
733 struct listnode *node;
734 struct pbr_map_sequence *pbrms;
735 bool sent = false;
736
737
738 for (ALL_LIST_ELEMENTS_RO(pbrm->seqnumbers, node, pbrms))
739 if (pbr_send_pbr_map(pbrms, pmi, false, true))
740 sent = true; /* rule removal sent to zebra */
741
742 pmi->delete = true;
743
744 /*
745 * If we actually sent something for deletion, wait on zapi callback
746 * before clearing data.
747 */
748 if (sent)
749 return;
750
751 pbr_map_final_interface_deletion(pbrm, pmi);
752 }
753
754 /*
755 * For a nexthop group specified, see if any of the pbr-maps
756 * are using it and if so, check to see that we are still
757 * valid for usage. If we are valid then schedule the installation/deletion
758 * of the pbr-policy.
759 */
760 void pbr_map_check_nh_group_change(const char *nh_group)
761 {
762 struct pbr_map_sequence *pbrms;
763 struct pbr_map *pbrm;
764 struct listnode *node, *inode;
765 struct pbr_map_interface *pmi;
766 bool found_name;
767
768 RB_FOREACH (pbrm, pbr_map_entry_head, &pbr_maps) {
769 for (ALL_LIST_ELEMENTS_RO(pbrm->seqnumbers, node, pbrms)) {
770 found_name = false;
771 if (pbrms->nhgrp_name)
772 found_name =
773 !strcmp(nh_group, pbrms->nhgrp_name);
774 else if (pbrms->nhg)
775 found_name = !strcmp(nh_group,
776 pbrms->internal_nhg_name);
777
778 if (found_name) {
779 bool original = pbrm->valid;
780
781 /* Set data we were waiting on */
782 if (pbrms->nhgrp_name)
783 pbr_nht_set_seq_nhg_data(
784 pbrms,
785 nhgc_find(pbrms->nhgrp_name));
786
787 pbr_map_check_valid_internal(pbrm);
788
789 if (pbrm->valid && (original != pbrm->valid))
790 pbr_map_install(pbrm);
791
792 if (pbrm->valid == false)
793 for (ALL_LIST_ELEMENTS_RO(
794 pbrm->incoming, inode,
795 pmi))
796 pbr_send_pbr_map(pbrms, pmi,
797 false, false);
798 }
799 }
800 }
801 }
802
803 void pbr_map_check_vrf_nh_group_change(const char *nh_group,
804 struct pbr_vrf *pbr_vrf,
805 uint32_t old_vrf_id)
806 {
807 struct pbr_map *pbrm;
808 struct pbr_map_sequence *pbrms;
809 struct listnode *node;
810
811
812 RB_FOREACH (pbrm, pbr_map_entry_head, &pbr_maps) {
813 for (ALL_LIST_ELEMENTS_RO(pbrm->seqnumbers, node, pbrms)) {
814 if (pbrms->nhgrp_name)
815 continue;
816
817 if (pbrms->nhg == NULL)
818 continue;
819
820 if (strcmp(nh_group, pbrms->internal_nhg_name))
821 continue;
822
823 if (pbrms->nhg->nexthop == NULL)
824 continue;
825
826 if (pbrms->nhg->nexthop->vrf_id != old_vrf_id)
827 continue;
828
829 pbrms->nhg->nexthop->vrf_id = pbr_vrf_id(pbr_vrf);
830 }
831 }
832 }
833
834 void pbr_map_check_interface_nh_group_change(const char *nh_group,
835 struct interface *ifp,
836 ifindex_t oldifindex)
837 {
838 struct pbr_map *pbrm;
839 struct pbr_map_sequence *pbrms;
840 struct listnode *node;
841
842 RB_FOREACH (pbrm, pbr_map_entry_head, &pbr_maps) {
843 for (ALL_LIST_ELEMENTS_RO(pbrm->seqnumbers, node, pbrms)) {
844 if (pbrms->nhgrp_name)
845 continue;
846
847 if (pbrms->nhg == NULL)
848 continue;
849
850 if (strcmp(nh_group, pbrms->internal_nhg_name))
851 continue;
852
853 if (pbrms->nhg->nexthop == NULL)
854 continue;
855
856 if (pbrms->nhg->nexthop->ifindex != oldifindex)
857 continue;
858
859 pbrms->nhg->nexthop->ifindex = ifp->ifindex;
860 }
861 }
862 }
863
864 void pbr_map_check(struct pbr_map_sequence *pbrms, bool changed)
865 {
866 struct pbr_map *pbrm;
867 bool install;
868
869 pbrm = pbrms->parent;
870 DEBUGD(&pbr_dbg_map, "%s: for %s(%u)", __func__, pbrm->name,
871 pbrms->seqno);
872 if (pbr_map_check_valid(pbrm->name))
873 DEBUGD(&pbr_dbg_map, "We are totally valid %s",
874 pbrm->name);
875
876 if (pbrms->reason == PBR_MAP_VALID_SEQUENCE_NUMBER) {
877 install = true;
878 DEBUGD(&pbr_dbg_map, "%s: Installing %s(%u) reason: %" PRIu64,
879 __func__, pbrm->name, pbrms->seqno, pbrms->reason);
880 DEBUGD(&pbr_dbg_map,
881 " Sending PBR_MAP_POLICY_INSTALL event");
882 } else {
883 install = false;
884 DEBUGD(&pbr_dbg_map, "%s: Removing %s(%u) reason: %" PRIu64,
885 __func__, pbrm->name, pbrms->seqno, pbrms->reason);
886 }
887
888 if (install)
889 pbr_map_pbrms_install(pbrms, changed);
890 else
891 pbr_map_pbrms_uninstall(pbrms);
892 }
893
894 void pbr_map_install(struct pbr_map *pbrm)
895 {
896 struct pbr_map_sequence *pbrms;
897 struct listnode *node;
898
899 if (!pbrm->incoming->count)
900 return;
901
902 for (ALL_LIST_ELEMENTS_RO(pbrm->seqnumbers, node, pbrms))
903 pbr_map_pbrms_install(pbrms, false);
904 }
905
906 void pbr_map_init(void)
907 {
908 RB_INIT(pbr_map_entry_head, &pbr_maps);
909
910 pbr_map_sequence_unique = 1;
911 }