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