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