]> git.proxmox.com Git - mirror_frr.git/blob - pbrd/pbr_map.c
Merge pull request #3823 from opensourcerouting/confd-build-fix
[mirror_frr.git] / pbrd / pbr_map.c
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"
35 #include "pbr_zebra.h"
36 #include "pbr_memory.h"
37 #include "pbr_debug.h"
38
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")
42
43 static uint32_t pbr_map_sequence_unique;
44
45 static inline int pbr_map_compare(const struct pbr_map *pbrmap1,
46 const struct pbr_map *pbrmap2);
47
48 RB_GENERATE(pbr_map_entry_head, pbr_map, pbr_map_entry, pbr_map_compare)
49
50 struct pbr_map_entry_head pbr_maps = RB_INITIALIZER(&pbr_maps);
51
52 DEFINE_QOBJ_TYPE(pbr_map_sequence)
53
54 static inline int pbr_map_compare(const struct pbr_map *pbrmap1,
55 const struct pbr_map *pbrmap2)
56 {
57 return strcmp(pbrmap1->name, pbrmap2->name);
58 }
59
60 static int pbr_map_sequence_compare(const struct pbr_map_sequence *pbrms1,
61 const struct pbr_map_sequence *pbrms2)
62 {
63 if (pbrms1->seqno == pbrms2->seqno)
64 return 0;
65
66 if (pbrms1->seqno < pbrms2->seqno)
67 return -1;
68
69 return 1;
70 }
71
72 static void pbr_map_sequence_delete(struct pbr_map_sequence *pbrms)
73 {
74 if (pbrms->internal_nhg_name)
75 XFREE(MTYPE_TMP, pbrms->internal_nhg_name);
76
77 XFREE(MTYPE_PBR_MAP_SEQNO, pbrms);
78 }
79
80 static int pbr_map_interface_compare(const struct pbr_map_interface *pmi1,
81 const struct pbr_map_interface *pmi2)
82 {
83 return strcmp(pmi1->ifp->name, pmi2->ifp->name);
84 }
85
86 static void pbr_map_interface_list_delete(struct pbr_map_interface *pmi)
87 {
88 struct pbr_map_interface *pmi_int;
89 struct listnode *node, *nnode;
90 struct pbr_map *pbrm;
91
92 RB_FOREACH (pbrm, pbr_map_entry_head, &pbr_maps) {
93 for (ALL_LIST_ELEMENTS(pbrm->incoming, node, nnode, pmi_int)) {
94 if (pmi == pmi_int) {
95 pbr_map_policy_delete(pbrm, pmi);
96 return;
97 }
98 }
99 }
100 }
101
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",
105 };
106
107 void pbr_map_reason_string(unsigned int reason, char *buf, int size)
108 {
109 unsigned int bit;
110 int len = 0;
111
112 if (!buf)
113 return;
114
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]);
120 }
121 }
122 }
123
124 void pbr_map_final_interface_deletion(struct pbr_map *pbrm,
125 struct pbr_map_interface *pmi)
126 {
127 if (pmi->delete == true) {
128 listnode_delete(pbrm->incoming, pmi);
129 pmi->pbrm = NULL;
130
131 bf_release_index(pbrm->ifi_bitfield, pmi->install_bit);
132 XFREE(MTYPE_PBR_MAP_INTERFACE, pmi);
133 }
134 }
135
136 void pbr_map_interface_delete(struct pbr_map *pbrm, struct interface *ifp_del)
137 {
138
139 struct listnode *node;
140 struct pbr_map_interface *pmi;
141
142 for (ALL_LIST_ELEMENTS_RO(pbrm->incoming, node, pmi)) {
143 if (ifp_del == pmi->ifp)
144 break;
145 }
146
147 if (pmi)
148 pbr_map_policy_delete(pbrm, pmi);
149 }
150
151 void pbr_map_add_interface(struct pbr_map *pbrm, struct interface *ifp_add)
152 {
153 struct listnode *node;
154 struct pbr_map_interface *pmi;
155
156 for (ALL_LIST_ELEMENTS_RO(pbrm->incoming, node, pmi)) {
157 if (ifp_add == pmi->ifp)
158 return;
159 }
160
161 pmi = XCALLOC(MTYPE_PBR_MAP_INTERFACE, sizeof(*pmi));
162 pmi->ifp = ifp_add;
163 pmi->pbrm = pbrm;
164 listnode_add_sort(pbrm->incoming, pmi);
165
166 bf_assign_index(pbrm->ifi_bitfield, pmi->install_bit);
167 pbr_map_check_valid(pbrm->name);
168 if (pbrm->valid)
169 pbr_map_install(pbrm);
170 }
171
172 void pbr_map_write_interfaces(struct vty *vty, struct interface *ifp)
173 {
174 struct pbr_interface *pbr_ifp = ifp->info;
175
176 if (pbr_ifp
177 && strncmp(pbr_ifp->mapname, "", sizeof(pbr_ifp->mapname)) != 0)
178 vty_out(vty, " pbr-policy %s\n", pbr_ifp->mapname);
179 }
180
181 struct pbr_map *pbrm_find(const char *name)
182 {
183 struct pbr_map pbrm;
184
185 strlcpy(pbrm.name, name, sizeof(pbrm.name));
186
187 return RB_FIND(pbr_map_entry_head, &pbr_maps, &pbrm);
188 }
189
190 extern void pbr_map_delete(struct pbr_map_sequence *pbrms)
191 {
192 struct pbr_map *pbrm;
193 struct listnode *inode;
194 struct pbr_map_interface *pmi;
195
196 pbrm = pbrms->parent;
197
198 for (ALL_LIST_ELEMENTS_RO(pbrm->incoming, inode, pmi))
199 pbr_send_pbr_map(pbrms, pmi, false);
200
201 if (pbrms->nhg)
202 pbr_nht_delete_individual_nexthop(pbrms);
203
204 listnode_delete(pbrm->seqnumbers, pbrms);
205
206 if (pbrm->seqnumbers->count == 0) {
207 RB_REMOVE(pbr_map_entry_head, &pbr_maps, pbrm);
208
209 bf_free(pbrm->ifi_bitfield);
210 XFREE(MTYPE_PBR_MAP, pbrm);
211 }
212 }
213
214 void pbr_map_delete_nexthop_group(struct pbr_map_sequence *pbrms)
215 {
216 struct pbr_map *pbrm = pbrms->parent;
217 struct listnode *node;
218 struct pbr_map_interface *pmi;
219
220 if (pbrm->valid && pbrms->nhs_installed && pbrm->incoming->count) {
221 for (ALL_LIST_ELEMENTS_RO(pbrm->incoming, node, pmi))
222 pbr_send_pbr_map(pbrms, pmi, false);
223 }
224
225 pbrm->valid = false;
226 pbrms->nhs_installed = false;
227 pbrms->reason |= PBR_MAP_INVALID_NO_NEXTHOPS;
228 pbrms->nhgrp_name = NULL;
229 }
230
231 struct pbr_map_sequence *pbrms_lookup_unique(uint32_t unique, ifindex_t ifindex,
232 struct pbr_map_interface **ppmi)
233 {
234 struct pbr_map_sequence *pbrms;
235 struct listnode *snode, *inode;
236 struct pbr_map_interface *pmi;
237 struct pbr_map *pbrm;
238
239 RB_FOREACH (pbrm, pbr_map_entry_head, &pbr_maps) {
240 for (ALL_LIST_ELEMENTS_RO(pbrm->incoming, inode, pmi)) {
241 if (pmi->ifp->ifindex != ifindex)
242 continue;
243
244 if (ppmi)
245 *ppmi = pmi;
246
247 for (ALL_LIST_ELEMENTS_RO(pbrm->seqnumbers, snode,
248 pbrms)) {
249 DEBUGD(&pbr_dbg_map, "%s: Comparing %u to %u",
250 __PRETTY_FUNCTION__, pbrms->unique,
251 unique);
252 if (pbrms->unique == unique)
253 return pbrms;
254 }
255 }
256 }
257
258 return NULL;
259 }
260
261 static void pbr_map_add_interfaces(struct pbr_map *pbrm)
262 {
263 struct interface *ifp;
264 struct pbr_interface *pbr_ifp;
265 struct vrf *vrf;
266
267 RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) {
268 FOR_ALL_INTERFACES (vrf, ifp) {
269 if (ifp->info) {
270 pbr_ifp = ifp->info;
271 if (strcmp(pbrm->name, pbr_ifp->mapname) == 0)
272 pbr_map_add_interface(pbrm, ifp);
273 }
274 }
275 }
276 }
277
278 struct pbr_map_sequence *pbrms_get(const char *name, uint32_t seqno)
279 {
280 struct pbr_map *pbrm;
281 struct pbr_map_sequence *pbrms;
282 struct listnode *node;
283
284 pbrm = pbrm_find(name);
285 if (!pbrm) {
286 pbrm = XCALLOC(MTYPE_PBR_MAP, sizeof(*pbrm));
287 snprintf(pbrm->name, sizeof(pbrm->name), "%s", name);
288
289 pbrm->seqnumbers = list_new();
290 pbrm->seqnumbers->cmp =
291 (int (*)(void *, void *))pbr_map_sequence_compare;
292 pbrm->seqnumbers->del =
293 (void (*)(void *))pbr_map_sequence_delete;
294
295 pbrm->incoming = list_new();
296 pbrm->incoming->cmp =
297 (int (*)(void *, void *))pbr_map_interface_compare;
298 pbrm->incoming->del =
299 (void (*)(void *))pbr_map_interface_list_delete;
300
301 RB_INSERT(pbr_map_entry_head, &pbr_maps, pbrm);
302
303 bf_init(pbrm->ifi_bitfield, 64);
304 pbr_map_add_interfaces(pbrm);
305 }
306
307 for (ALL_LIST_ELEMENTS_RO(pbrm->seqnumbers, node, pbrms)) {
308 if (pbrms->seqno == seqno)
309 break;
310
311 }
312
313 if (!pbrms) {
314 pbrms = XCALLOC(MTYPE_PBR_MAP_SEQNO, sizeof(*pbrms));
315 pbrms->unique = pbr_map_sequence_unique++;
316 pbrms->seqno = seqno;
317 pbrms->ruleno = pbr_nht_get_next_rule(seqno);
318 pbrms->parent = pbrm;
319 pbrms->reason =
320 PBR_MAP_INVALID_SRCDST |
321 PBR_MAP_INVALID_NO_NEXTHOPS;
322
323 QOBJ_REG(pbrms, pbr_map_sequence);
324 listnode_add_sort(pbrm->seqnumbers, pbrms);
325 }
326
327 return pbrms;
328 }
329
330 static void
331 pbr_map_sequence_check_nexthops_valid(struct pbr_map_sequence *pbrms)
332 {
333 /*
334 * Check validness of the nexthop or nexthop-group
335 */
336 if (!pbrms->nhg && !pbrms->nhgrp_name)
337 pbrms->reason |= PBR_MAP_INVALID_NO_NEXTHOPS;
338
339 if (pbrms->nhg && pbrms->nhgrp_name)
340 pbrms->reason |= PBR_MAP_INVALID_BOTH_NHANDGRP;
341
342 if (pbrms->nhg &&
343 !pbr_nht_nexthop_group_valid(pbrms->internal_nhg_name))
344 pbrms->reason |= PBR_MAP_INVALID_NEXTHOP;
345
346 if (pbrms->nhgrp_name) {
347 if (!pbr_nht_nexthop_group_valid(pbrms->nhgrp_name))
348 pbrms->reason |= PBR_MAP_INVALID_NEXTHOP_GROUP;
349 else
350 pbrms->nhs_installed = true;
351 }
352 }
353
354 static void pbr_map_sequence_check_src_dst_valid(struct pbr_map_sequence *pbrms)
355 {
356 if (!pbrms->src && !pbrms->dst)
357 pbrms->reason |= PBR_MAP_INVALID_SRCDST;
358 }
359
360 /*
361 * Checks to see if we think that the pbmrs is valid. If we think
362 * the config is valid return true.
363 */
364 static void pbr_map_sequence_check_valid(struct pbr_map_sequence *pbrms)
365 {
366 pbr_map_sequence_check_nexthops_valid(pbrms);
367
368 pbr_map_sequence_check_src_dst_valid(pbrms);
369 }
370
371 static bool pbr_map_check_valid_internal(struct pbr_map *pbrm)
372 {
373 struct pbr_map_sequence *pbrms;
374 struct listnode *node;
375
376 pbrm->valid = true;
377 for (ALL_LIST_ELEMENTS_RO(pbrm->seqnumbers, node, pbrms)) {
378 pbrms->reason = 0;
379 pbr_map_sequence_check_valid(pbrms);
380 /*
381 * A pbr_map_sequence that is invalid causes
382 * the whole shebang to be invalid
383 */
384 if (pbrms->reason != 0)
385 pbrm->valid = false;
386 }
387
388 return pbrm->valid;
389 }
390
391 /*
392 * For a given PBR-MAP check to see if we think it is a
393 * valid config or not. If so note that it is and return
394 * that we are valid.
395 */
396 bool pbr_map_check_valid(const char *name)
397 {
398 struct pbr_map *pbrm;
399
400 pbrm = pbrm_find(name);
401 if (!pbrm) {
402 DEBUGD(&pbr_dbg_map,
403 "%s: Specified PBR-MAP(%s) does not exist?",
404 __PRETTY_FUNCTION__, name);
405 return false;
406 }
407
408 pbr_map_check_valid_internal(pbrm);
409 return pbrm->valid;
410 }
411
412 void pbr_map_schedule_policy_from_nhg(const char *nh_group)
413 {
414 struct pbr_map_sequence *pbrms;
415 struct pbr_map *pbrm;
416 struct listnode *node;
417
418 RB_FOREACH (pbrm, pbr_map_entry_head, &pbr_maps) {
419 DEBUGD(&pbr_dbg_map, "%s: Looking at %s", __PRETTY_FUNCTION__,
420 pbrm->name);
421 for (ALL_LIST_ELEMENTS_RO(pbrm->seqnumbers, node, pbrms)) {
422 DEBUGD(&pbr_dbg_map, "\tNH Grp name: %s",
423 pbrms->nhgrp_name ?
424 pbrms->nhgrp_name : pbrms->internal_nhg_name);
425
426 if (pbrms->nhgrp_name
427 && (strcmp(nh_group, pbrms->nhgrp_name) == 0)) {
428 pbrms->nhs_installed = true;
429
430 pbr_map_check(pbrms);
431 }
432
433 if (pbrms->nhg
434 && (strcmp(nh_group, pbrms->internal_nhg_name)
435 == 0)) {
436 pbrms->nhs_installed = true;
437
438 pbr_map_check(pbrms);
439 }
440 }
441 }
442 }
443
444 void pbr_map_policy_install(const char *name)
445 {
446 struct pbr_map_sequence *pbrms;
447 struct pbr_map *pbrm;
448 struct listnode *node, *inode;
449 struct pbr_map_interface *pmi;
450
451 DEBUGD(&pbr_dbg_map, "%s: for %s", __PRETTY_FUNCTION__, name);
452 pbrm = pbrm_find(name);
453 if (!pbrm)
454 return;
455
456 for (ALL_LIST_ELEMENTS_RO(pbrm->seqnumbers, node, pbrms)) {
457 DEBUGD(&pbr_dbg_map,
458 "%s: Looking at what to install %s(%u) %d %d",
459 __PRETTY_FUNCTION__, name, pbrms->seqno, pbrm->valid,
460 pbrms->nhs_installed);
461
462 if (pbrm->valid && pbrms->nhs_installed && pbrm->incoming->count) {
463 DEBUGD(&pbr_dbg_map, "\tInstalling %s %u",
464 pbrm->name, pbrms->seqno);
465 for (ALL_LIST_ELEMENTS_RO(pbrm->incoming, inode, pmi))
466 pbr_send_pbr_map(pbrms, pmi, true);
467 }
468 }
469 }
470
471 void pbr_map_policy_delete(struct pbr_map *pbrm, struct pbr_map_interface *pmi)
472 {
473 struct listnode *node;
474 struct pbr_map_sequence *pbrms;
475
476
477 for (ALL_LIST_ELEMENTS_RO(pbrm->seqnumbers, node, pbrms))
478 pbr_send_pbr_map(pbrms, pmi, false);
479
480 pmi->delete = true;
481 }
482
483 /*
484 * For a nexthop group specified, see if any of the pbr-maps
485 * are using it and if so, check to see that we are still
486 * valid for usage. If we are valid then schedule the installation/deletion
487 * of the pbr-policy.
488 */
489 void pbr_map_check_nh_group_change(const char *nh_group)
490 {
491 struct pbr_map_sequence *pbrms;
492 struct pbr_map *pbrm;
493 struct listnode *node, *inode;
494 struct pbr_map_interface *pmi;
495 bool found_name;
496
497 RB_FOREACH (pbrm, pbr_map_entry_head, &pbr_maps) {
498 for (ALL_LIST_ELEMENTS_RO(pbrm->seqnumbers, node, pbrms)) {
499 found_name = false;
500 if (pbrms->nhgrp_name)
501 found_name =
502 !strcmp(nh_group, pbrms->nhgrp_name);
503 else if (pbrms->nhg)
504 found_name = !strcmp(nh_group,
505 pbrms->internal_nhg_name);
506
507 if (found_name) {
508 bool original = pbrm->valid;
509
510 pbr_map_check_valid_internal(pbrm);
511
512 if (pbrm->valid && (original != pbrm->valid))
513 pbr_map_install(pbrm);
514
515 if (pbrm->valid == false)
516 for (ALL_LIST_ELEMENTS_RO(
517 pbrm->incoming, inode,
518 pmi))
519 pbr_send_pbr_map(pbrms, pmi,
520 false);
521 }
522 }
523 }
524 }
525
526 void pbr_map_check(struct pbr_map_sequence *pbrms)
527 {
528 struct pbr_map *pbrm;
529 struct listnode *inode;
530 struct pbr_map_interface *pmi;
531 bool install;
532
533 pbrm = pbrms->parent;
534 DEBUGD(&pbr_dbg_map, "%s: for %s(%u)", __PRETTY_FUNCTION__,
535 pbrm->name, pbrms->seqno);
536 if (pbr_map_check_valid(pbrm->name))
537 DEBUGD(&pbr_dbg_map, "We are totally valid %s",
538 pbrm->name);
539
540 if (pbrms->reason == PBR_MAP_VALID_SEQUENCE_NUMBER) {
541 install = true;
542 DEBUGD(&pbr_dbg_map, "%s: Installing %s(%u) reason: %" PRIu64,
543 __PRETTY_FUNCTION__, pbrm->name, pbrms->seqno,
544 pbrms->reason);
545 DEBUGD(&pbr_dbg_map,
546 "\tSending PBR_MAP_POLICY_INSTALL event");
547 } else {
548 install = false;
549 DEBUGD(&pbr_dbg_map,
550 "%s: Removing %s(%u) reason: %" PRIu64,
551 __PRETTY_FUNCTION__, pbrm->name,
552 pbrms->seqno, pbrms->reason);
553 }
554
555 for (ALL_LIST_ELEMENTS_RO(pbrm->incoming, inode, pmi)) {
556 pbr_send_pbr_map(pbrms, pmi, install);
557 }
558 }
559
560 void pbr_map_install(struct pbr_map *pbrm)
561 {
562 struct listnode *node, *inode;
563 struct pbr_map_sequence *pbrms;
564 struct pbr_map_interface *pmi;
565
566 if (!pbrm->incoming->count)
567 return;
568
569 for (ALL_LIST_ELEMENTS_RO(pbrm->seqnumbers, node, pbrms))
570 for (ALL_LIST_ELEMENTS_RO(pbrm->incoming, inode, pmi))
571 pbr_send_pbr_map(pbrms, pmi, true);
572 }
573
574 void pbr_map_init(void)
575 {
576 RB_INIT(pbr_map_entry_head, &pbr_maps);
577
578 pbr_map_sequence_unique = 1;
579 }