]> git.proxmox.com Git - mirror_frr.git/blame - zebra/zebra_pbr.c
zebra: cleanup zebra policy context
[mirror_frr.git] / zebra / zebra_pbr.c
CommitLineData
942bf97b 1/* Zebra Policy Based Routing (PBR) main handling.
2 * Copyright (C) 2018 Cumulus Networks, Inc.
3 *
4 * This file is part of FRR.
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
17 * along with FRR; see the file COPYING. If not, write to the Free
18 * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
19 * 02111-1307, USA.
20 */
21
22#include <zebra.h>
23
43fe6a2a
DS
24#include <jhash.h>
25#include <hash.h>
26
942bf97b 27#include "zebra/zebra_pbr.h"
28#include "zebra/rt.h"
bf094f69 29#include "zebra/zapi_msg.h"
942bf97b 30
31/* definitions */
32
33/* static function declarations */
34
35/* Private functions */
36
37/* Public functions */
43fe6a2a 38void zebra_pbr_rules_free(void *arg)
1fbfe5a5 39{
43fe6a2a
DS
40 struct zebra_pbr_rule *rule;
41
42 rule = (struct zebra_pbr_rule *)arg;
43
a0321978 44 kernel_del_pbr_rule(rule);
43fe6a2a
DS
45 XFREE(MTYPE_TMP, rule);
46}
47
48uint32_t zebra_pbr_rules_hash_key(void *arg)
49{
50 struct zebra_pbr_rule *rule;
51 uint32_t key;
52
53 rule = (struct zebra_pbr_rule *)arg;
5dd0722d
PG
54 key = jhash_3words(rule->rule.seq, rule->rule.priority,
55 rule->rule.action.table,
56 prefix_hash_key(&rule->rule.filter.src_ip));
a0321978
DS
57 if (rule->ifp)
58 key = jhash_1word(rule->ifp->ifindex, key);
59 else
60 key = jhash_1word(0, key);
61
5dd0722d
PG
62 if (rule->rule.filter.fwmark)
63 key = jhash_1word(rule->rule.filter.fwmark, key);
1907e4b8
PG
64 else
65 key = jhash_1word(0, key);
5dd0722d
PG
66 return jhash_3words(rule->rule.filter.src_port,
67 rule->rule.filter.dst_port,
68 prefix_hash_key(&rule->rule.filter.dst_ip),
69 jhash_1word(rule->rule.unique, key));
43fe6a2a
DS
70}
71
72int zebra_pbr_rules_hash_equal(const void *arg1, const void *arg2)
73{
74 const struct zebra_pbr_rule *r1, *r2;
75
76 r1 = (const struct zebra_pbr_rule *)arg1;
77 r2 = (const struct zebra_pbr_rule *)arg2;
78
5dd0722d 79 if (r1->rule.seq != r2->rule.seq)
43fe6a2a
DS
80 return 0;
81
5dd0722d 82 if (r1->rule.priority != r2->rule.priority)
43fe6a2a
DS
83 return 0;
84
5dd0722d 85 if (r1->rule.unique != r2->rule.unique)
b6c5d343
DS
86 return 0;
87
5dd0722d 88 if (r1->rule.action.table != r2->rule.action.table)
43fe6a2a
DS
89 return 0;
90
5dd0722d 91 if (r1->rule.filter.src_port != r2->rule.filter.src_port)
43fe6a2a
DS
92 return 0;
93
5dd0722d 94 if (r1->rule.filter.dst_port != r2->rule.filter.dst_port)
43fe6a2a
DS
95 return 0;
96
5dd0722d 97 if (r1->rule.filter.fwmark != r2->rule.filter.fwmark)
1907e4b8
PG
98 return 0;
99
5dd0722d 100 if (!prefix_same(&r1->rule.filter.src_ip, &r2->rule.filter.src_ip))
43fe6a2a
DS
101 return 0;
102
5dd0722d 103 if (!prefix_same(&r1->rule.filter.dst_ip, &r2->rule.filter.dst_ip))
43fe6a2a
DS
104 return 0;
105
a0321978
DS
106 if (r1->ifp != r2->ifp)
107 return 0;
108
43fe6a2a
DS
109 return 1;
110}
111
f46bbab4 112struct pbr_rule_unique_lookup {
8c3cd6c6
DS
113 struct zebra_pbr_rule *rule;
114 uint32_t unique;
37c606ff 115 struct interface *ifp;
8c3cd6c6
DS
116};
117
118static int pbr_rule_lookup_unique_walker(struct hash_backet *b, void *data)
119{
f46bbab4 120 struct pbr_rule_unique_lookup *pul = data;
8c3cd6c6
DS
121 struct zebra_pbr_rule *rule = b->data;
122
37c606ff 123 if (pul->unique == rule->rule.unique && pul->ifp == rule->ifp) {
8c3cd6c6
DS
124 pul->rule = rule;
125 return HASHWALK_ABORT;
126 }
127
128 return HASHWALK_CONTINUE;
129}
130
131static struct zebra_pbr_rule *pbr_rule_lookup_unique(struct zebra_ns *zns,
37c606ff
DS
132 uint32_t unique,
133 struct interface *ifp)
8c3cd6c6 134{
f46bbab4 135 struct pbr_rule_unique_lookup pul;
8c3cd6c6
DS
136
137 pul.unique = unique;
37c606ff 138 pul.ifp = ifp;
8c3cd6c6
DS
139 pul.rule = NULL;
140 hash_walk(zns->rules_hash, &pbr_rule_lookup_unique_walker, &pul);
141
142 return pul.rule;
143}
144
7661461a
PG
145void zebra_pbr_ipset_free(void *arg)
146{
147 struct zebra_pbr_ipset *ipset;
148
149 ipset = (struct zebra_pbr_ipset *)arg;
150
151 XFREE(MTYPE_TMP, ipset);
152}
153
154uint32_t zebra_pbr_ipset_hash_key(void *arg)
155{
156 struct zebra_pbr_ipset *ipset = (struct zebra_pbr_ipset *)arg;
425bdd6b 157 uint32_t *pnt = (uint32_t *)&ipset->ipset_name;
7661461a 158
425bdd6b 159 return jhash2(pnt, ZEBRA_IPSET_NAME_HASH_SIZE, 0x63ab42de);
7661461a
PG
160}
161
162int zebra_pbr_ipset_hash_equal(const void *arg1, const void *arg2)
163{
164 const struct zebra_pbr_ipset *r1, *r2;
165
166 r1 = (const struct zebra_pbr_ipset *)arg1;
167 r2 = (const struct zebra_pbr_ipset *)arg2;
168
169 if (r1->type != r2->type)
170 return 0;
171 if (r1->unique != r2->unique)
172 return 0;
173 if (strncmp(r1->ipset_name, r2->ipset_name,
174 ZEBRA_IPSET_NAME_SIZE))
175 return 0;
176 return 1;
177}
178
179void zebra_pbr_ipset_entry_free(void *arg)
180{
181 struct zebra_pbr_ipset_entry *ipset;
182
183 ipset = (struct zebra_pbr_ipset_entry *)arg;
184
185 XFREE(MTYPE_TMP, ipset);
186}
187
188uint32_t zebra_pbr_ipset_entry_hash_key(void *arg)
189{
190 struct zebra_pbr_ipset_entry *ipset;
191 uint32_t key;
192
193 ipset = (struct zebra_pbr_ipset_entry *)arg;
194 key = prefix_hash_key(&ipset->src);
195 key = jhash_1word(ipset->unique, key);
196 key = jhash_1word(prefix_hash_key(&ipset->dst), key);
197
198 return key;
199}
200
201int zebra_pbr_ipset_entry_hash_equal(const void *arg1, const void *arg2)
202{
203 const struct zebra_pbr_ipset_entry *r1, *r2;
204
205 r1 = (const struct zebra_pbr_ipset_entry *)arg1;
206 r2 = (const struct zebra_pbr_ipset_entry *)arg2;
207
208 if (r1->unique != r2->unique)
209 return 0;
210
211 if (!prefix_same(&r1->src, &r2->src))
212 return 0;
213
214 if (!prefix_same(&r1->dst, &r2->dst))
215 return 0;
216
217 return 1;
218}
219
7abd6c4f
PG
220void zebra_pbr_iptable_free(void *arg)
221{
222 struct zebra_pbr_iptable *iptable;
223
224 iptable = (struct zebra_pbr_iptable *)arg;
225
226 XFREE(MTYPE_TMP, iptable);
227}
228
229uint32_t zebra_pbr_iptable_hash_key(void *arg)
230{
231 struct zebra_pbr_iptable *iptable = (struct zebra_pbr_iptable *)arg;
232 uint32_t *pnt = (uint32_t *)&(iptable->ipset_name);
233 uint32_t key;
234
235 key = jhash2(pnt, ZEBRA_IPSET_NAME_HASH_SIZE,
236 0x63ab42de);
237 key = jhash_1word(iptable->fwmark, key);
238 return jhash_3words(iptable->filter_bm, iptable->type,
239 iptable->unique, key);
240}
241
242int zebra_pbr_iptable_hash_equal(const void *arg1, const void *arg2)
243{
244 const struct zebra_pbr_iptable *r1, *r2;
245
246 r1 = (const struct zebra_pbr_iptable *)arg1;
247 r2 = (const struct zebra_pbr_iptable *)arg2;
248
249 if (r1->type != r2->type)
250 return 0;
251 if (r1->unique != r2->unique)
252 return 0;
253 if (r1->filter_bm != r2->filter_bm)
254 return 0;
255 if (r1->fwmark != r2->fwmark)
256 return 0;
257 if (r1->action != r2->action)
258 return 0;
259 if (strncmp(r1->ipset_name, r2->ipset_name,
260 ZEBRA_IPSET_NAME_SIZE))
261 return 0;
262 return 1;
263}
264
43fe6a2a
DS
265static void *pbr_rule_alloc_intern(void *arg)
266{
267 struct zebra_pbr_rule *zpr;
268 struct zebra_pbr_rule *new;
269
270 zpr = (struct zebra_pbr_rule *)arg;
271
272 new = XCALLOC(MTYPE_TMP, sizeof(*new));
273
274 memcpy(new, zpr, sizeof(*zpr));
275
276 return new;
277}
278
a0321978 279void zebra_pbr_add_rule(struct zebra_ns *zns, struct zebra_pbr_rule *rule)
43fe6a2a 280{
8c3cd6c6 281 struct zebra_pbr_rule *unique =
37c606ff 282 pbr_rule_lookup_unique(zns, rule->rule.unique, rule->ifp);
8c3cd6c6 283
43fe6a2a 284 (void)hash_get(zns->rules_hash, rule, pbr_rule_alloc_intern);
a0321978 285 kernel_add_pbr_rule(rule);
8c3cd6c6
DS
286
287 /*
288 * Rule Replace semantics, if we have an old, install the
289 * new rule, look above, and then delete the old
290 */
291 if (unique)
292 zebra_pbr_del_rule(zns, unique);
1fbfe5a5
DS
293}
294
a0321978 295void zebra_pbr_del_rule(struct zebra_ns *zns, struct zebra_pbr_rule *rule)
1fbfe5a5 296{
43fe6a2a
DS
297 struct zebra_pbr_rule *lookup;
298
299 lookup = hash_lookup(zns->rules_hash, rule);
a0321978 300 kernel_del_pbr_rule(rule);
43fe6a2a 301
d5c52f76
DS
302 if (lookup) {
303 hash_release(zns->rules_hash, lookup);
43fe6a2a 304 XFREE(MTYPE_TMP, lookup);
d5c52f76 305 } else
43fe6a2a
DS
306 zlog_warn("%s: Rule being deleted we know nothing about",
307 __PRETTY_FUNCTION__);
1fbfe5a5
DS
308}
309
e69aa084
DS
310static void zebra_pbr_cleanup_rules(struct hash_backet *b, void *data)
311{
312 struct zebra_ns *zns = zebra_ns_lookup(NS_DEFAULT);
313 struct zebra_pbr_rule *rule = b->data;
314 int *sock = data;
315
316 if (rule->sock == *sock) {
317 kernel_del_pbr_rule(rule);
318 hash_release(zns->rules_hash, rule);
d5c52f76 319 XFREE(MTYPE_TMP, rule);
e69aa084
DS
320 }
321}
322
c2ef5232
PG
323static void zebra_pbr_cleanup_ipset(struct hash_backet *b, void *data)
324{
325 struct zebra_ns *zns = zebra_ns_lookup(NS_DEFAULT);
326 struct zebra_pbr_ipset *ipset = b->data;
327 int *sock = data;
328
329 if (ipset->sock == *sock)
330 hash_release(zns->ipset_hash, ipset);
331}
332
333static void zebra_pbr_cleanup_ipset_entry(struct hash_backet *b, void *data)
334{
335 struct zebra_ns *zns = zebra_ns_lookup(NS_DEFAULT);
336 struct zebra_pbr_ipset_entry *ipset = b->data;
337 int *sock = data;
338
339 if (ipset->sock == *sock)
340 hash_release(zns->ipset_entry_hash, ipset);
341}
342
343static void zebra_pbr_cleanup_iptable(struct hash_backet *b, void *data)
344{
345 struct zebra_ns *zns = zebra_ns_lookup(NS_DEFAULT);
346 struct zebra_pbr_iptable *iptable = b->data;
347 int *sock = data;
348
349 if (iptable->sock == *sock)
350 hash_release(zns->iptable_hash, iptable);
351}
352
4c0ec639 353static int zebra_pbr_client_close_cleanup(struct zserv *client)
e69aa084 354{
4c0ec639 355 int sock = client->sock;
e69aa084
DS
356 struct zebra_ns *zns = zebra_ns_lookup(NS_DEFAULT);
357
4c0ec639
PG
358 if (!sock)
359 return 0;
e69aa084 360 hash_iterate(zns->rules_hash, zebra_pbr_cleanup_rules, &sock);
c2ef5232
PG
361 hash_iterate(zns->iptable_hash,
362 zebra_pbr_cleanup_iptable, &sock);
363 hash_iterate(zns->ipset_entry_hash,
364 zebra_pbr_cleanup_ipset_entry, &sock);
365 hash_iterate(zns->ipset_hash,
366 zebra_pbr_cleanup_ipset, &sock);
4c0ec639
PG
367 return 1;
368}
369
370void zebra_pbr_init(void)
371{
372 hook_register(zapi_client_close, zebra_pbr_client_close_cleanup);
e69aa084
DS
373}
374
7661461a
PG
375static void *pbr_ipset_alloc_intern(void *arg)
376{
377 struct zebra_pbr_ipset *zpi;
378 struct zebra_pbr_ipset *new;
379
380 zpi = (struct zebra_pbr_ipset *)arg;
381
382 new = XCALLOC(MTYPE_TMP, sizeof(struct zebra_pbr_ipset));
383
384 memcpy(new, zpi, sizeof(*zpi));
385
386 return new;
387}
388
389void zebra_pbr_create_ipset(struct zebra_ns *zns,
390 struct zebra_pbr_ipset *ipset)
391{
392 (void)hash_get(zns->ipset_hash, ipset, pbr_ipset_alloc_intern);
393 /* TODO:
394 * - Netlink call
395 */
396}
397
398void zebra_pbr_destroy_ipset(struct zebra_ns *zns,
399 struct zebra_pbr_ipset *ipset)
400{
401 struct zebra_pbr_ipset *lookup;
402
403 lookup = hash_lookup(zns->ipset_hash, ipset);
404 /* TODO:
405 * - Netlink destroy from kernel
406 * - ?? destroy ipset entries before
407 */
de67547d
PG
408 if (lookup) {
409 hash_release(zns->ipset_hash, lookup);
7661461a 410 XFREE(MTYPE_TMP, lookup);
de67547d 411 } else
425bdd6b 412 zlog_warn("%s: IPSet Entry being deleted we know nothing about",
7661461a
PG
413 __PRETTY_FUNCTION__);
414}
415
ed78b7c8
PG
416struct pbr_ipset_name_lookup {
417 struct zebra_pbr_ipset *ipset;
418 char ipset_name[ZEBRA_IPSET_NAME_SIZE];
419};
420
421static int zebra_pbr_ipset_pername_walkcb(struct hash_backet *backet, void *arg)
422{
423 struct pbr_ipset_name_lookup *pinl =
424 (struct pbr_ipset_name_lookup *)arg;
425 struct zebra_pbr_ipset *zpi = (struct zebra_pbr_ipset *)backet->data;
426
427 if (!strncmp(pinl->ipset_name, zpi->ipset_name,
428 ZEBRA_IPSET_NAME_SIZE)) {
429 pinl->ipset = zpi;
430 return HASHWALK_ABORT;
431 }
432 return HASHWALK_CONTINUE;
433}
434
d59c13af
PG
435struct zebra_pbr_ipset *zebra_pbr_lookup_ipset_pername(struct zebra_ns *zns,
436 char *ipsetname)
437{
ed78b7c8
PG
438 struct pbr_ipset_name_lookup pinl;
439 struct pbr_ipset_name_lookup *ptr = &pinl;
440
d59c13af
PG
441 if (!ipsetname)
442 return NULL;
ed78b7c8
PG
443 memset(ptr, 0, sizeof(struct pbr_ipset_name_lookup));
444 snprintf((char *)ptr->ipset_name, ZEBRA_IPSET_NAME_SIZE, "%s",
445 ipsetname);
446 hash_walk(zns->ipset_hash, zebra_pbr_ipset_pername_walkcb, ptr);
447 return ptr->ipset;
d59c13af
PG
448}
449
7661461a
PG
450static void *pbr_ipset_entry_alloc_intern(void *arg)
451{
452 struct zebra_pbr_ipset_entry *zpi;
453 struct zebra_pbr_ipset_entry *new;
454
455 zpi = (struct zebra_pbr_ipset_entry *)arg;
456
457 new = XCALLOC(MTYPE_TMP, sizeof(struct zebra_pbr_ipset_entry));
458
459 memcpy(new, zpi, sizeof(*zpi));
460
461 return new;
462}
463
464void zebra_pbr_add_ipset_entry(struct zebra_ns *zns,
465 struct zebra_pbr_ipset_entry *ipset)
466{
467 (void)hash_get(zns->ipset_entry_hash, ipset,
468 pbr_ipset_entry_alloc_intern);
469 /* TODO:
470 * - attach to ipset list
471 * - Netlink add to kernel
472 */
473}
474
475void zebra_pbr_del_ipset_entry(struct zebra_ns *zns,
476 struct zebra_pbr_ipset_entry *ipset)
477{
478 struct zebra_pbr_ipset_entry *lookup;
479
425bdd6b 480 lookup = hash_lookup(zns->ipset_entry_hash, ipset);
7661461a
PG
481 /* TODO:
482 * - Netlink destroy
483 * - detach from ipset list
484 * - ?? if no more entres, delete ipset
485 */
de67547d
PG
486 if (lookup) {
487 hash_release(zns->ipset_entry_hash, lookup);
7661461a 488 XFREE(MTYPE_TMP, lookup);
de67547d 489 } else
7661461a
PG
490 zlog_warn("%s: IPSet being deleted we know nothing about",
491 __PRETTY_FUNCTION__);
492}
493
7abd6c4f
PG
494static void *pbr_iptable_alloc_intern(void *arg)
495{
496 struct zebra_pbr_iptable *zpi;
497 struct zebra_pbr_iptable *new;
498
499 zpi = (struct zebra_pbr_iptable *)arg;
500
501 new = XCALLOC(MTYPE_TMP, sizeof(struct zebra_pbr_iptable));
502
503 memcpy(new, zpi, sizeof(*zpi));
504
505 return new;
506}
507
508void zebra_pbr_add_iptable(struct zebra_ns *zns,
509 struct zebra_pbr_iptable *iptable)
510{
511 (void)hash_get(zns->iptable_hash, iptable,
512 pbr_iptable_alloc_intern);
513 /* TODO call netlink layer */
514}
515
516void zebra_pbr_del_iptable(struct zebra_ns *zns,
517 struct zebra_pbr_iptable *iptable)
518{
519 struct zebra_pbr_ipset_entry *lookup;
520
521 lookup = hash_lookup(zns->iptable_hash, iptable);
522 /* TODO:
523 * - call netlink layer
524 * - detach from iptable list
525 */
526 if (lookup)
527 XFREE(MTYPE_TMP, lookup);
528 else
529 zlog_warn("%s: IPTable being deleted we know nothing about",
530 __PRETTY_FUNCTION__);
531}
532
942bf97b 533/*
534 * Handle success or failure of rule (un)install in the kernel.
535 */
536void kernel_pbr_rule_add_del_status(struct zebra_pbr_rule *rule,
942bf97b 537 enum southbound_results res)
538{
b6c5d343
DS
539 switch (res) {
540 case SOUTHBOUND_INSTALL_SUCCESS:
541 zsend_rule_notify_owner(rule, ZAPI_RULE_INSTALLED);
542 break;
543 case SOUTHBOUND_INSTALL_FAILURE:
544 zsend_rule_notify_owner(rule, ZAPI_RULE_FAIL_INSTALL);
545 break;
546 case SOUTHBOUND_DELETE_SUCCESS:
0f03639d 547 zsend_rule_notify_owner(rule, ZAPI_RULE_REMOVED);
b6c5d343
DS
548 break;
549 case SOUTHBOUND_DELETE_FAILURE:
0f03639d 550 zsend_rule_notify_owner(rule, ZAPI_RULE_REMOVED);
b6c5d343
DS
551 break;
552 }
942bf97b 553}
554
425bdd6b
PG
555/*
556 * Handle success or failure of ipset (un)install in the kernel.
557 */
558void kernel_pbr_ipset_add_del_status(struct zebra_pbr_ipset *ipset,
559 enum southbound_results res)
560{
561 switch (res) {
562 case SOUTHBOUND_INSTALL_SUCCESS:
563 zsend_ipset_notify_owner(ipset, ZAPI_IPSET_INSTALLED);
564 break;
565 case SOUTHBOUND_INSTALL_FAILURE:
566 zsend_ipset_notify_owner(ipset, ZAPI_IPSET_FAIL_INSTALL);
567 break;
568 case SOUTHBOUND_DELETE_SUCCESS:
569 case SOUTHBOUND_DELETE_FAILURE:
570 /* TODO : handling of delete event */
571 break;
572 }
573}
574
575/*
576 * Handle success or failure of ipset (un)install in the kernel.
577 */
578void kernel_pbr_ipset_entry_add_del_status(
579 struct zebra_pbr_ipset_entry *ipset,
580 enum southbound_results res)
581{
582 switch (res) {
583 case SOUTHBOUND_INSTALL_SUCCESS:
584 zsend_ipset_entry_notify_owner(ipset,
585 ZAPI_IPSET_ENTRY_INSTALLED);
586 break;
587 case SOUTHBOUND_INSTALL_FAILURE:
588 zsend_ipset_entry_notify_owner(ipset,
589 ZAPI_IPSET_ENTRY_FAIL_INSTALL);
590 break;
591 case SOUTHBOUND_DELETE_SUCCESS:
592 case SOUTHBOUND_DELETE_FAILURE:
593 /* TODO : handling of delete event */
594 break;
595 }
596}
597
7abd6c4f
PG
598/*
599 * Handle success or failure of ipset (un)install in the kernel.
600 */
601void kernel_pbr_iptable_add_del_status(struct zebra_pbr_iptable *iptable,
602 enum southbound_results res)
603{
604 switch (res) {
605 case SOUTHBOUND_INSTALL_SUCCESS:
606 zsend_iptable_notify_owner(iptable, ZAPI_IPTABLE_INSTALLED);
607 break;
608 case SOUTHBOUND_INSTALL_FAILURE:
609 zsend_iptable_notify_owner(iptable, ZAPI_IPTABLE_FAIL_INSTALL);
610 break;
611 case SOUTHBOUND_DELETE_SUCCESS:
612 case SOUTHBOUND_DELETE_FAILURE:
613 /* TODO : handling of delete event */
614 break;
615 }
616}
617
942bf97b 618/*
619 * Handle rule delete notification from kernel.
620 */
a0321978 621int kernel_pbr_rule_del(struct zebra_pbr_rule *rule)
942bf97b 622{
623 return 0;
624}