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