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