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