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