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