]> git.proxmox.com Git - mirror_frr.git/blame - zebra/zebra_pbr.c
zebra: misc fixes, perf improvements
[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>
f80ec7e3 26#include <memory.h>
73a829f7 27#include <hook.h>
43fe6a2a 28
942bf97b 29#include "zebra/zebra_pbr.h"
30#include "zebra/rt.h"
bf094f69 31#include "zebra/zapi_msg.h"
f80ec7e3 32#include "zebra/zebra_memory.h"
f80ec7e3
PG
33
34/* definitions */
35DEFINE_MTYPE_STATIC(ZEBRA, PBR_IPTABLE_IFNAME, "PBR interface list")
942bf97b 36
37/* definitions */
586f4ccf
PG
38static const struct message ipset_type_msg[] = {
39 {IPSET_NET_PORT_NET, "net,port,net"},
40 {IPSET_NET_PORT, "net,port"},
41 {IPSET_NET_NET, "net,net"},
42 {IPSET_NET, "net"},
43 {0}
44};
942bf97b 45
46/* static function declarations */
73a829f7
PG
47DEFINE_HOOK(zebra_pbr_ipset_entry_wrap_script_get_stat, (struct zebra_ns *zns,
48 struct zebra_pbr_ipset_entry *ipset,
49 uint64_t *pkts, uint64_t *bytes),
50 (zns, ipset, pkts, bytes))
51
52DEFINE_HOOK(zebra_pbr_iptable_wrap_script_get_stat, (struct zebra_ns *zns,
53 struct zebra_pbr_iptable *iptable,
54 uint64_t *pkts, uint64_t *bytes),
55 (zns, iptable, pkts, bytes))
56
57DEFINE_HOOK(zebra_pbr_iptable_wrap_script_update, (struct zebra_ns *zns,
58 int cmd,
59 struct zebra_pbr_iptable *iptable),
60 (zns, cmd, iptable));
61
62DEFINE_HOOK(zebra_pbr_ipset_entry_wrap_script_update, (struct zebra_ns *zns,
63 int cmd,
64 struct zebra_pbr_ipset_entry *ipset),
65 (zns, cmd, ipset));
66
67DEFINE_HOOK(zebra_pbr_ipset_wrap_script_update, (struct zebra_ns *zns,
68 int cmd,
69 struct zebra_pbr_ipset *ipset),
70 (zns, cmd, ipset));
942bf97b 71
72/* Private functions */
73
74/* Public functions */
43fe6a2a 75void zebra_pbr_rules_free(void *arg)
1fbfe5a5 76{
43fe6a2a
DS
77 struct zebra_pbr_rule *rule;
78
79 rule = (struct zebra_pbr_rule *)arg;
80
a0321978 81 kernel_del_pbr_rule(rule);
43fe6a2a
DS
82 XFREE(MTYPE_TMP, rule);
83}
84
85uint32_t zebra_pbr_rules_hash_key(void *arg)
86{
87 struct zebra_pbr_rule *rule;
88 uint32_t key;
89
90 rule = (struct zebra_pbr_rule *)arg;
5dd0722d
PG
91 key = jhash_3words(rule->rule.seq, rule->rule.priority,
92 rule->rule.action.table,
93 prefix_hash_key(&rule->rule.filter.src_ip));
a0321978
DS
94 if (rule->ifp)
95 key = jhash_1word(rule->ifp->ifindex, key);
96 else
97 key = jhash_1word(0, key);
98
5dd0722d
PG
99 if (rule->rule.filter.fwmark)
100 key = jhash_1word(rule->rule.filter.fwmark, key);
1907e4b8
PG
101 else
102 key = jhash_1word(0, key);
5dd0722d
PG
103 return jhash_3words(rule->rule.filter.src_port,
104 rule->rule.filter.dst_port,
105 prefix_hash_key(&rule->rule.filter.dst_ip),
106 jhash_1word(rule->rule.unique, key));
43fe6a2a
DS
107}
108
109int zebra_pbr_rules_hash_equal(const void *arg1, const void *arg2)
110{
111 const struct zebra_pbr_rule *r1, *r2;
112
113 r1 = (const struct zebra_pbr_rule *)arg1;
114 r2 = (const struct zebra_pbr_rule *)arg2;
115
5dd0722d 116 if (r1->rule.seq != r2->rule.seq)
43fe6a2a
DS
117 return 0;
118
5dd0722d 119 if (r1->rule.priority != r2->rule.priority)
43fe6a2a
DS
120 return 0;
121
5dd0722d 122 if (r1->rule.unique != r2->rule.unique)
b6c5d343
DS
123 return 0;
124
5dd0722d 125 if (r1->rule.action.table != r2->rule.action.table)
43fe6a2a
DS
126 return 0;
127
5dd0722d 128 if (r1->rule.filter.src_port != r2->rule.filter.src_port)
43fe6a2a
DS
129 return 0;
130
5dd0722d 131 if (r1->rule.filter.dst_port != r2->rule.filter.dst_port)
43fe6a2a
DS
132 return 0;
133
5dd0722d 134 if (r1->rule.filter.fwmark != r2->rule.filter.fwmark)
1907e4b8
PG
135 return 0;
136
5dd0722d 137 if (!prefix_same(&r1->rule.filter.src_ip, &r2->rule.filter.src_ip))
43fe6a2a
DS
138 return 0;
139
5dd0722d 140 if (!prefix_same(&r1->rule.filter.dst_ip, &r2->rule.filter.dst_ip))
43fe6a2a
DS
141 return 0;
142
a0321978
DS
143 if (r1->ifp != r2->ifp)
144 return 0;
145
43fe6a2a
DS
146 return 1;
147}
148
f46bbab4 149struct pbr_rule_unique_lookup {
8c3cd6c6
DS
150 struct zebra_pbr_rule *rule;
151 uint32_t unique;
37c606ff 152 struct interface *ifp;
8c3cd6c6
DS
153};
154
155static int pbr_rule_lookup_unique_walker(struct hash_backet *b, void *data)
156{
f46bbab4 157 struct pbr_rule_unique_lookup *pul = data;
8c3cd6c6
DS
158 struct zebra_pbr_rule *rule = b->data;
159
37c606ff 160 if (pul->unique == rule->rule.unique && pul->ifp == rule->ifp) {
8c3cd6c6
DS
161 pul->rule = rule;
162 return HASHWALK_ABORT;
163 }
164
165 return HASHWALK_CONTINUE;
166}
167
168static struct zebra_pbr_rule *pbr_rule_lookup_unique(struct zebra_ns *zns,
37c606ff
DS
169 uint32_t unique,
170 struct interface *ifp)
8c3cd6c6 171{
f46bbab4 172 struct pbr_rule_unique_lookup pul;
8c3cd6c6
DS
173
174 pul.unique = unique;
37c606ff 175 pul.ifp = ifp;
8c3cd6c6
DS
176 pul.rule = NULL;
177 hash_walk(zns->rules_hash, &pbr_rule_lookup_unique_walker, &pul);
178
179 return pul.rule;
180}
181
7661461a
PG
182void zebra_pbr_ipset_free(void *arg)
183{
184 struct zebra_pbr_ipset *ipset;
73a829f7 185 struct zebra_ns *zns;
7661461a
PG
186
187 ipset = (struct zebra_pbr_ipset *)arg;
73a829f7
PG
188 if (vrf_is_backend_netns())
189 zns = zebra_ns_lookup(ipset->vrf_id);
190 else
191 zns = zebra_ns_lookup(NS_DEFAULT);
192 hook_call(zebra_pbr_ipset_wrap_script_update,
193 zns, 0, ipset);
7661461a
PG
194 XFREE(MTYPE_TMP, ipset);
195}
196
197uint32_t zebra_pbr_ipset_hash_key(void *arg)
198{
199 struct zebra_pbr_ipset *ipset = (struct zebra_pbr_ipset *)arg;
425bdd6b 200 uint32_t *pnt = (uint32_t *)&ipset->ipset_name;
7661461a 201
425bdd6b 202 return jhash2(pnt, ZEBRA_IPSET_NAME_HASH_SIZE, 0x63ab42de);
7661461a
PG
203}
204
205int zebra_pbr_ipset_hash_equal(const void *arg1, const void *arg2)
206{
207 const struct zebra_pbr_ipset *r1, *r2;
208
209 r1 = (const struct zebra_pbr_ipset *)arg1;
210 r2 = (const struct zebra_pbr_ipset *)arg2;
211
212 if (r1->type != r2->type)
213 return 0;
214 if (r1->unique != r2->unique)
215 return 0;
216 if (strncmp(r1->ipset_name, r2->ipset_name,
217 ZEBRA_IPSET_NAME_SIZE))
218 return 0;
219 return 1;
220}
221
222void zebra_pbr_ipset_entry_free(void *arg)
223{
224 struct zebra_pbr_ipset_entry *ipset;
73a829f7 225 struct zebra_ns *zns;
7661461a
PG
226
227 ipset = (struct zebra_pbr_ipset_entry *)arg;
73a829f7
PG
228 if (ipset->backpointer && vrf_is_backend_netns()) {
229 struct zebra_pbr_ipset *ips = ipset->backpointer;
230
231 zns = zebra_ns_lookup((ns_id_t)ips->vrf_id);
232 } else
233 zns = zebra_ns_lookup(NS_DEFAULT);
234 hook_call(zebra_pbr_ipset_entry_wrap_script_update,
235 zns, 0, ipset);
7661461a
PG
236
237 XFREE(MTYPE_TMP, ipset);
238}
239
240uint32_t zebra_pbr_ipset_entry_hash_key(void *arg)
241{
242 struct zebra_pbr_ipset_entry *ipset;
243 uint32_t key;
244
245 ipset = (struct zebra_pbr_ipset_entry *)arg;
246 key = prefix_hash_key(&ipset->src);
247 key = jhash_1word(ipset->unique, key);
248 key = jhash_1word(prefix_hash_key(&ipset->dst), key);
25d760c5
PG
249 key = jhash(&ipset->dst_port_min, 2, key);
250 key = jhash(&ipset->dst_port_max, 2, key);
251 key = jhash(&ipset->src_port_min, 2, key);
252 key = jhash(&ipset->src_port_max, 2, key);
253 key = jhash(&ipset->proto, 1, key);
7661461a
PG
254
255 return key;
256}
257
258int zebra_pbr_ipset_entry_hash_equal(const void *arg1, const void *arg2)
259{
260 const struct zebra_pbr_ipset_entry *r1, *r2;
261
262 r1 = (const struct zebra_pbr_ipset_entry *)arg1;
263 r2 = (const struct zebra_pbr_ipset_entry *)arg2;
264
265 if (r1->unique != r2->unique)
266 return 0;
267
268 if (!prefix_same(&r1->src, &r2->src))
269 return 0;
270
271 if (!prefix_same(&r1->dst, &r2->dst))
272 return 0;
273
25d760c5
PG
274 if (r1->src_port_min != r2->src_port_min)
275 return 0;
276
277 if (r1->src_port_max != r2->src_port_max)
278 return 0;
279
280 if (r1->dst_port_min != r2->dst_port_min)
281 return 0;
282
283 if (r1->dst_port_max != r2->dst_port_max)
284 return 0;
285
286 if (r1->proto != r2->proto)
287 return 0;
7661461a
PG
288 return 1;
289}
290
7abd6c4f
PG
291void zebra_pbr_iptable_free(void *arg)
292{
293 struct zebra_pbr_iptable *iptable;
f80ec7e3
PG
294 struct listnode *node, *nnode;
295 char *name;
73a829f7 296 struct zebra_ns *zns;
7abd6c4f
PG
297
298 iptable = (struct zebra_pbr_iptable *)arg;
73a829f7
PG
299 if (vrf_is_backend_netns())
300 zns = zebra_ns_lookup((ns_id_t)iptable->vrf_id);
301 else
302 zns = zebra_ns_lookup(NS_DEFAULT);
303 hook_call(zebra_pbr_iptable_wrap_script_update,
304 zns, 0, iptable);
7abd6c4f 305
f80ec7e3
PG
306 for (ALL_LIST_ELEMENTS(iptable->interface_name_list,
307 node, nnode, name)) {
308 XFREE(MTYPE_PBR_IPTABLE_IFNAME, name);
309 list_delete_node(iptable->interface_name_list,
310 node);
311 }
7abd6c4f
PG
312 XFREE(MTYPE_TMP, iptable);
313}
314
315uint32_t zebra_pbr_iptable_hash_key(void *arg)
316{
317 struct zebra_pbr_iptable *iptable = (struct zebra_pbr_iptable *)arg;
318 uint32_t *pnt = (uint32_t *)&(iptable->ipset_name);
319 uint32_t key;
320
321 key = jhash2(pnt, ZEBRA_IPSET_NAME_HASH_SIZE,
322 0x63ab42de);
323 key = jhash_1word(iptable->fwmark, key);
324 return jhash_3words(iptable->filter_bm, iptable->type,
325 iptable->unique, key);
326}
327
328int zebra_pbr_iptable_hash_equal(const void *arg1, const void *arg2)
329{
330 const struct zebra_pbr_iptable *r1, *r2;
331
332 r1 = (const struct zebra_pbr_iptable *)arg1;
333 r2 = (const struct zebra_pbr_iptable *)arg2;
334
335 if (r1->type != r2->type)
336 return 0;
337 if (r1->unique != r2->unique)
338 return 0;
339 if (r1->filter_bm != r2->filter_bm)
340 return 0;
341 if (r1->fwmark != r2->fwmark)
342 return 0;
343 if (r1->action != r2->action)
344 return 0;
345 if (strncmp(r1->ipset_name, r2->ipset_name,
346 ZEBRA_IPSET_NAME_SIZE))
347 return 0;
348 return 1;
349}
350
43fe6a2a
DS
351static void *pbr_rule_alloc_intern(void *arg)
352{
353 struct zebra_pbr_rule *zpr;
354 struct zebra_pbr_rule *new;
355
356 zpr = (struct zebra_pbr_rule *)arg;
357
358 new = XCALLOC(MTYPE_TMP, sizeof(*new));
359
360 memcpy(new, zpr, sizeof(*zpr));
361
362 return new;
363}
364
a0321978 365void zebra_pbr_add_rule(struct zebra_ns *zns, struct zebra_pbr_rule *rule)
43fe6a2a 366{
8c3cd6c6 367 struct zebra_pbr_rule *unique =
37c606ff 368 pbr_rule_lookup_unique(zns, rule->rule.unique, rule->ifp);
8c3cd6c6 369
43fe6a2a 370 (void)hash_get(zns->rules_hash, rule, pbr_rule_alloc_intern);
a0321978 371 kernel_add_pbr_rule(rule);
8c3cd6c6
DS
372 /*
373 * Rule Replace semantics, if we have an old, install the
374 * new rule, look above, and then delete the old
375 */
376 if (unique)
377 zebra_pbr_del_rule(zns, unique);
1fbfe5a5
DS
378}
379
a0321978 380void zebra_pbr_del_rule(struct zebra_ns *zns, struct zebra_pbr_rule *rule)
1fbfe5a5 381{
43fe6a2a
DS
382 struct zebra_pbr_rule *lookup;
383
384 lookup = hash_lookup(zns->rules_hash, rule);
a0321978 385 kernel_del_pbr_rule(rule);
43fe6a2a 386
d5c52f76
DS
387 if (lookup) {
388 hash_release(zns->rules_hash, lookup);
43fe6a2a 389 XFREE(MTYPE_TMP, lookup);
d5c52f76 390 } else
43fe6a2a
DS
391 zlog_warn("%s: Rule being deleted we know nothing about",
392 __PRETTY_FUNCTION__);
1fbfe5a5
DS
393}
394
e69aa084
DS
395static void zebra_pbr_cleanup_rules(struct hash_backet *b, void *data)
396{
397 struct zebra_ns *zns = zebra_ns_lookup(NS_DEFAULT);
398 struct zebra_pbr_rule *rule = b->data;
399 int *sock = data;
400
401 if (rule->sock == *sock) {
402 kernel_del_pbr_rule(rule);
403 hash_release(zns->rules_hash, rule);
d5c52f76 404 XFREE(MTYPE_TMP, rule);
e69aa084
DS
405 }
406}
407
c2ef5232
PG
408static void zebra_pbr_cleanup_ipset(struct hash_backet *b, void *data)
409{
410 struct zebra_ns *zns = zebra_ns_lookup(NS_DEFAULT);
411 struct zebra_pbr_ipset *ipset = b->data;
412 int *sock = data;
413
73a829f7
PG
414 if (ipset->sock == *sock) {
415 hook_call(zebra_pbr_ipset_wrap_script_update,
416 zns, 0, ipset);
c2ef5232 417 hash_release(zns->ipset_hash, ipset);
73a829f7 418 }
c2ef5232
PG
419}
420
421static void zebra_pbr_cleanup_ipset_entry(struct hash_backet *b, void *data)
422{
423 struct zebra_ns *zns = zebra_ns_lookup(NS_DEFAULT);
424 struct zebra_pbr_ipset_entry *ipset = b->data;
425 int *sock = data;
426
73a829f7
PG
427 if (ipset->sock == *sock) {
428 hook_call(zebra_pbr_ipset_entry_wrap_script_update,
429 zns, 0, ipset);
c2ef5232 430 hash_release(zns->ipset_entry_hash, ipset);
73a829f7 431 }
c2ef5232
PG
432}
433
434static void zebra_pbr_cleanup_iptable(struct hash_backet *b, void *data)
435{
436 struct zebra_ns *zns = zebra_ns_lookup(NS_DEFAULT);
437 struct zebra_pbr_iptable *iptable = b->data;
438 int *sock = data;
439
73a829f7
PG
440 if (iptable->sock == *sock) {
441 hook_call(zebra_pbr_iptable_wrap_script_update,
442 zns, 0, iptable);
c2ef5232 443 hash_release(zns->iptable_hash, iptable);
73a829f7 444 }
c2ef5232
PG
445}
446
4c0ec639 447static int zebra_pbr_client_close_cleanup(struct zserv *client)
e69aa084 448{
4c0ec639 449 int sock = client->sock;
e69aa084
DS
450 struct zebra_ns *zns = zebra_ns_lookup(NS_DEFAULT);
451
4c0ec639
PG
452 if (!sock)
453 return 0;
e69aa084 454 hash_iterate(zns->rules_hash, zebra_pbr_cleanup_rules, &sock);
c2ef5232
PG
455 hash_iterate(zns->iptable_hash,
456 zebra_pbr_cleanup_iptable, &sock);
457 hash_iterate(zns->ipset_entry_hash,
458 zebra_pbr_cleanup_ipset_entry, &sock);
459 hash_iterate(zns->ipset_hash,
460 zebra_pbr_cleanup_ipset, &sock);
4c0ec639
PG
461 return 1;
462}
463
464void zebra_pbr_init(void)
465{
466 hook_register(zapi_client_close, zebra_pbr_client_close_cleanup);
e69aa084
DS
467}
468
7661461a
PG
469static void *pbr_ipset_alloc_intern(void *arg)
470{
471 struct zebra_pbr_ipset *zpi;
472 struct zebra_pbr_ipset *new;
473
474 zpi = (struct zebra_pbr_ipset *)arg;
475
476 new = XCALLOC(MTYPE_TMP, sizeof(struct zebra_pbr_ipset));
477
478 memcpy(new, zpi, sizeof(*zpi));
479
480 return new;
481}
482
483void zebra_pbr_create_ipset(struct zebra_ns *zns,
484 struct zebra_pbr_ipset *ipset)
485{
73a829f7
PG
486 int ret;
487
7661461a 488 (void)hash_get(zns->ipset_hash, ipset, pbr_ipset_alloc_intern);
73a829f7
PG
489 ret = hook_call(zebra_pbr_ipset_wrap_script_update,
490 zns, 1, ipset);
491 kernel_pbr_ipset_add_del_status(ipset,
492 ret ? SOUTHBOUND_INSTALL_SUCCESS
493 : SOUTHBOUND_INSTALL_FAILURE);
7661461a
PG
494}
495
496void zebra_pbr_destroy_ipset(struct zebra_ns *zns,
497 struct zebra_pbr_ipset *ipset)
498{
499 struct zebra_pbr_ipset *lookup;
500
501 lookup = hash_lookup(zns->ipset_hash, ipset);
73a829f7
PG
502 hook_call(zebra_pbr_ipset_wrap_script_update,
503 zns, 0, ipset);
de67547d
PG
504 if (lookup) {
505 hash_release(zns->ipset_hash, lookup);
7661461a 506 XFREE(MTYPE_TMP, lookup);
de67547d 507 } else
425bdd6b 508 zlog_warn("%s: IPSet Entry being deleted we know nothing about",
7661461a
PG
509 __PRETTY_FUNCTION__);
510}
511
ed78b7c8
PG
512struct pbr_ipset_name_lookup {
513 struct zebra_pbr_ipset *ipset;
514 char ipset_name[ZEBRA_IPSET_NAME_SIZE];
515};
516
586f4ccf
PG
517static const char *zebra_pbr_ipset_type2str(uint32_t type)
518{
519 return lookup_msg(ipset_type_msg, type,
520 "Unrecognized IPset Type");
521}
522
ed78b7c8
PG
523static int zebra_pbr_ipset_pername_walkcb(struct hash_backet *backet, void *arg)
524{
525 struct pbr_ipset_name_lookup *pinl =
526 (struct pbr_ipset_name_lookup *)arg;
527 struct zebra_pbr_ipset *zpi = (struct zebra_pbr_ipset *)backet->data;
528
529 if (!strncmp(pinl->ipset_name, zpi->ipset_name,
530 ZEBRA_IPSET_NAME_SIZE)) {
531 pinl->ipset = zpi;
532 return HASHWALK_ABORT;
533 }
534 return HASHWALK_CONTINUE;
535}
536
d59c13af
PG
537struct zebra_pbr_ipset *zebra_pbr_lookup_ipset_pername(struct zebra_ns *zns,
538 char *ipsetname)
539{
ed78b7c8
PG
540 struct pbr_ipset_name_lookup pinl;
541 struct pbr_ipset_name_lookup *ptr = &pinl;
542
d59c13af
PG
543 if (!ipsetname)
544 return NULL;
ed78b7c8
PG
545 memset(ptr, 0, sizeof(struct pbr_ipset_name_lookup));
546 snprintf((char *)ptr->ipset_name, ZEBRA_IPSET_NAME_SIZE, "%s",
547 ipsetname);
548 hash_walk(zns->ipset_hash, zebra_pbr_ipset_pername_walkcb, ptr);
549 return ptr->ipset;
d59c13af
PG
550}
551
7661461a
PG
552static void *pbr_ipset_entry_alloc_intern(void *arg)
553{
554 struct zebra_pbr_ipset_entry *zpi;
555 struct zebra_pbr_ipset_entry *new;
556
557 zpi = (struct zebra_pbr_ipset_entry *)arg;
558
559 new = XCALLOC(MTYPE_TMP, sizeof(struct zebra_pbr_ipset_entry));
560
561 memcpy(new, zpi, sizeof(*zpi));
562
563 return new;
564}
565
566void zebra_pbr_add_ipset_entry(struct zebra_ns *zns,
567 struct zebra_pbr_ipset_entry *ipset)
568{
73a829f7
PG
569 int ret;
570
7661461a
PG
571 (void)hash_get(zns->ipset_entry_hash, ipset,
572 pbr_ipset_entry_alloc_intern);
73a829f7
PG
573 ret = hook_call(zebra_pbr_ipset_entry_wrap_script_update,
574 zns, 1, ipset);
575 kernel_pbr_ipset_entry_add_del_status(ipset,
576 ret ? SOUTHBOUND_INSTALL_SUCCESS
577 : SOUTHBOUND_INSTALL_FAILURE);
7661461a
PG
578}
579
580void zebra_pbr_del_ipset_entry(struct zebra_ns *zns,
581 struct zebra_pbr_ipset_entry *ipset)
582{
583 struct zebra_pbr_ipset_entry *lookup;
584
425bdd6b 585 lookup = hash_lookup(zns->ipset_entry_hash, ipset);
73a829f7
PG
586 hook_call(zebra_pbr_ipset_entry_wrap_script_update,
587 zns, 0, ipset);
de67547d
PG
588 if (lookup) {
589 hash_release(zns->ipset_entry_hash, lookup);
7661461a 590 XFREE(MTYPE_TMP, lookup);
de67547d 591 } else
7661461a
PG
592 zlog_warn("%s: IPSet being deleted we know nothing about",
593 __PRETTY_FUNCTION__);
594}
595
7abd6c4f
PG
596static void *pbr_iptable_alloc_intern(void *arg)
597{
598 struct zebra_pbr_iptable *zpi;
599 struct zebra_pbr_iptable *new;
600
601 zpi = (struct zebra_pbr_iptable *)arg;
602
603 new = XCALLOC(MTYPE_TMP, sizeof(struct zebra_pbr_iptable));
604
605 memcpy(new, zpi, sizeof(*zpi));
606
607 return new;
608}
609
610void zebra_pbr_add_iptable(struct zebra_ns *zns,
611 struct zebra_pbr_iptable *iptable)
612{
73a829f7
PG
613 int ret;
614
7abd6c4f
PG
615 (void)hash_get(zns->iptable_hash, iptable,
616 pbr_iptable_alloc_intern);
73a829f7
PG
617 ret = hook_call(zebra_pbr_iptable_wrap_script_update, zns, 1, iptable);
618 kernel_pbr_iptable_add_del_status(iptable,
619 ret ? SOUTHBOUND_INSTALL_SUCCESS
620 : SOUTHBOUND_INSTALL_FAILURE);
7abd6c4f
PG
621}
622
623void zebra_pbr_del_iptable(struct zebra_ns *zns,
624 struct zebra_pbr_iptable *iptable)
625{
f80ec7e3 626 struct zebra_pbr_iptable *lookup;
7abd6c4f
PG
627
628 lookup = hash_lookup(zns->iptable_hash, iptable);
73a829f7 629 hook_call(zebra_pbr_iptable_wrap_script_update, zns, 0, iptable);
f80ec7e3
PG
630 if (lookup) {
631 struct listnode *node, *nnode;
632 char *name;
633
634 hash_release(zns->iptable_hash, lookup);
635 for (ALL_LIST_ELEMENTS(iptable->interface_name_list,
636 node, nnode, name)) {
637 XFREE(MTYPE_PBR_IPTABLE_IFNAME, name);
638 list_delete_node(iptable->interface_name_list,
639 node);
640 }
7abd6c4f 641 XFREE(MTYPE_TMP, lookup);
f80ec7e3 642 } else
7abd6c4f
PG
643 zlog_warn("%s: IPTable being deleted we know nothing about",
644 __PRETTY_FUNCTION__);
645}
646
942bf97b 647/*
648 * Handle success or failure of rule (un)install in the kernel.
649 */
650void kernel_pbr_rule_add_del_status(struct zebra_pbr_rule *rule,
942bf97b 651 enum southbound_results res)
652{
b6c5d343
DS
653 switch (res) {
654 case SOUTHBOUND_INSTALL_SUCCESS:
655 zsend_rule_notify_owner(rule, ZAPI_RULE_INSTALLED);
656 break;
657 case SOUTHBOUND_INSTALL_FAILURE:
658 zsend_rule_notify_owner(rule, ZAPI_RULE_FAIL_INSTALL);
659 break;
660 case SOUTHBOUND_DELETE_SUCCESS:
0f03639d 661 zsend_rule_notify_owner(rule, ZAPI_RULE_REMOVED);
b6c5d343
DS
662 break;
663 case SOUTHBOUND_DELETE_FAILURE:
34d9d5be 664 zsend_rule_notify_owner(rule, ZAPI_RULE_FAIL_REMOVE);
b6c5d343
DS
665 break;
666 }
942bf97b 667}
668
425bdd6b
PG
669/*
670 * Handle success or failure of ipset (un)install in the kernel.
671 */
672void kernel_pbr_ipset_add_del_status(struct zebra_pbr_ipset *ipset,
673 enum southbound_results res)
674{
675 switch (res) {
676 case SOUTHBOUND_INSTALL_SUCCESS:
677 zsend_ipset_notify_owner(ipset, ZAPI_IPSET_INSTALLED);
678 break;
679 case SOUTHBOUND_INSTALL_FAILURE:
680 zsend_ipset_notify_owner(ipset, ZAPI_IPSET_FAIL_INSTALL);
681 break;
682 case SOUTHBOUND_DELETE_SUCCESS:
4c550bcf
PG
683 zsend_ipset_notify_owner(ipset, ZAPI_IPSET_REMOVED);
684 break;
425bdd6b 685 case SOUTHBOUND_DELETE_FAILURE:
34d9d5be 686 zsend_ipset_notify_owner(ipset, ZAPI_IPSET_FAIL_REMOVE);
425bdd6b
PG
687 break;
688 }
689}
690
691/*
692 * Handle success or failure of ipset (un)install in the kernel.
693 */
694void kernel_pbr_ipset_entry_add_del_status(
695 struct zebra_pbr_ipset_entry *ipset,
696 enum southbound_results res)
697{
698 switch (res) {
699 case SOUTHBOUND_INSTALL_SUCCESS:
700 zsend_ipset_entry_notify_owner(ipset,
701 ZAPI_IPSET_ENTRY_INSTALLED);
702 break;
703 case SOUTHBOUND_INSTALL_FAILURE:
704 zsend_ipset_entry_notify_owner(ipset,
705 ZAPI_IPSET_ENTRY_FAIL_INSTALL);
706 break;
707 case SOUTHBOUND_DELETE_SUCCESS:
4c550bcf
PG
708 zsend_ipset_entry_notify_owner(ipset,
709 ZAPI_IPSET_ENTRY_REMOVED);
710 break;
425bdd6b 711 case SOUTHBOUND_DELETE_FAILURE:
4c550bcf 712 zsend_ipset_entry_notify_owner(ipset,
34d9d5be 713 ZAPI_IPSET_ENTRY_FAIL_REMOVE);
425bdd6b
PG
714 break;
715 }
716}
717
7abd6c4f
PG
718/*
719 * Handle success or failure of ipset (un)install in the kernel.
720 */
721void kernel_pbr_iptable_add_del_status(struct zebra_pbr_iptable *iptable,
722 enum southbound_results res)
723{
724 switch (res) {
725 case SOUTHBOUND_INSTALL_SUCCESS:
726 zsend_iptable_notify_owner(iptable, ZAPI_IPTABLE_INSTALLED);
727 break;
728 case SOUTHBOUND_INSTALL_FAILURE:
729 zsend_iptable_notify_owner(iptable, ZAPI_IPTABLE_FAIL_INSTALL);
730 break;
731 case SOUTHBOUND_DELETE_SUCCESS:
4c550bcf
PG
732 zsend_iptable_notify_owner(iptable,
733 ZAPI_IPTABLE_REMOVED);
734 break;
7abd6c4f 735 case SOUTHBOUND_DELETE_FAILURE:
4c550bcf 736 zsend_iptable_notify_owner(iptable,
34d9d5be 737 ZAPI_IPTABLE_FAIL_REMOVE);
7abd6c4f
PG
738 break;
739 }
740}
741
942bf97b 742/*
743 * Handle rule delete notification from kernel.
744 */
a0321978 745int kernel_pbr_rule_del(struct zebra_pbr_rule *rule)
942bf97b 746{
747 return 0;
748}
586f4ccf
PG
749
750struct zebra_pbr_ipset_entry_unique_display {
751 struct zebra_pbr_ipset *zpi;
752 struct vty *vty;
73a829f7 753 struct zebra_ns *zns;
586f4ccf
PG
754};
755
756struct zebra_pbr_env_display {
757 struct zebra_ns *zns;
758 struct vty *vty;
759};
760
761static const char *zebra_pbr_prefix2str(union prefixconstptr pu,
762 char *str, int size)
763{
764 const struct prefix *p = pu.p;
765 char buf[PREFIX2STR_BUFFER];
766
767 if (p->family == AF_INET && p->prefixlen == IPV4_MAX_PREFIXLEN) {
768 snprintf(str, size, "%s", inet_ntop(p->family, &p->u.prefix,
769 buf, PREFIX2STR_BUFFER));
770 return str;
771 }
772 return prefix2str(pu, str, size);
773}
774
25d760c5
PG
775static void zebra_pbr_display_port(struct vty *vty, uint32_t filter_bm,
776 uint16_t port_min, uint16_t port_max,
777 uint8_t proto)
778{
779 if (!(filter_bm & PBR_FILTER_PROTO)) {
780 if (port_max)
781 vty_out(vty, ":udp/tcp:%d-%d",
782 port_min, port_max);
783 else
784 vty_out(vty, ":udp/tcp:%d",
785 port_min);
786 } else {
787 if (port_max)
788 vty_out(vty, ":proto %d:%d-%d",
789 proto, port_min, port_max);
790 else
791 vty_out(vty, ":proto %d:%d",
792 proto, port_min);
793 }
794}
795
586f4ccf
PG
796static int zebra_pbr_show_ipset_entry_walkcb(struct hash_backet *backet,
797 void *arg)
798{
799 struct zebra_pbr_ipset_entry_unique_display *unique =
800 (struct zebra_pbr_ipset_entry_unique_display *)arg;
801 struct zebra_pbr_ipset *zpi = unique->zpi;
802 struct vty *vty = unique->vty;
803 struct zebra_pbr_ipset_entry *zpie =
804 (struct zebra_pbr_ipset_entry *)backet->data;
73a829f7
PG
805 uint64_t pkts = 0, bytes = 0;
806 struct zebra_ns *zns = unique->zns;
807 int ret = 0;
586f4ccf
PG
808
809 if (zpie->backpointer != zpi)
810 return HASHWALK_CONTINUE;
811
25d760c5
PG
812 if ((zpi->type == IPSET_NET_NET) ||
813 (zpi->type == IPSET_NET_PORT_NET)) {
586f4ccf
PG
814 char buf[PREFIX_STRLEN];
815
816 zebra_pbr_prefix2str(&(zpie->src), buf, sizeof(buf));
817 vty_out(vty, "\tfrom %s", buf);
25d760c5
PG
818 if (zpie->filter_bm & PBR_FILTER_SRC_PORT)
819 zebra_pbr_display_port(vty, zpie->filter_bm,
820 zpie->src_port_min,
821 zpie->src_port_max,
822 zpie->proto);
586f4ccf
PG
823 vty_out(vty, " to ");
824 zebra_pbr_prefix2str(&(zpie->dst), buf, sizeof(buf));
825 vty_out(vty, "%s", buf);
25d760c5
PG
826 if (zpie->filter_bm & PBR_FILTER_DST_PORT)
827 zebra_pbr_display_port(vty, zpie->filter_bm,
828 zpie->dst_port_min,
829 zpie->dst_port_max,
830 zpie->proto);
831 } else if ((zpi->type == IPSET_NET) ||
832 (zpi->type == IPSET_NET_PORT)) {
586f4ccf
PG
833 char buf[PREFIX_STRLEN];
834
835 if (zpie->filter_bm & PBR_FILTER_SRC_IP) {
836 zebra_pbr_prefix2str(&(zpie->src), buf, sizeof(buf));
837 vty_out(vty, "\tfrom %s", buf);
838 }
25d760c5
PG
839 if (zpie->filter_bm & PBR_FILTER_SRC_PORT)
840 zebra_pbr_display_port(vty, zpie->filter_bm,
841 zpie->src_port_min,
842 zpie->src_port_max,
843 zpie->proto);
586f4ccf
PG
844 if (zpie->filter_bm & PBR_FILTER_DST_IP) {
845 zebra_pbr_prefix2str(&(zpie->dst), buf, sizeof(buf));
846 vty_out(vty, "\tto %s", buf);
847 }
25d760c5
PG
848 if (zpie->filter_bm & PBR_FILTER_DST_PORT)
849 zebra_pbr_display_port(vty, zpie->filter_bm,
850 zpie->dst_port_min,
851 zpie->dst_port_max,
852 zpie->proto);
586f4ccf
PG
853 }
854 vty_out(vty, " (%u)\n", zpie->unique);
855
73a829f7
PG
856 ret = hook_call(zebra_pbr_ipset_entry_wrap_script_get_stat,
857 zns, zpie, &pkts, &bytes);
858 if (ret && pkts > 0)
859 vty_out(vty, "\t pkts %" PRIu64 ", bytes %" PRIu64"\n",
860 pkts, bytes);
586f4ccf
PG
861 return HASHWALK_CONTINUE;
862}
863
864static int zebra_pbr_show_ipset_walkcb(struct hash_backet *backet, void *arg)
865{
866 struct zebra_pbr_env_display *uniqueipset =
867 (struct zebra_pbr_env_display *)arg;
868 struct zebra_pbr_ipset *zpi = (struct zebra_pbr_ipset *)backet->data;
869 struct zebra_pbr_ipset_entry_unique_display unique;
870 struct vty *vty = uniqueipset->vty;
871 struct zebra_ns *zns = uniqueipset->zns;
872
873 vty_out(vty, "IPset %s type %s\n", zpi->ipset_name,
874 zebra_pbr_ipset_type2str(zpi->type));
875 unique.vty = vty;
876 unique.zpi = zpi;
73a829f7 877 unique.zns = zns;
586f4ccf
PG
878 hash_walk(zns->ipset_entry_hash, zebra_pbr_show_ipset_entry_walkcb,
879 &unique);
880 vty_out(vty, "\n");
881 return HASHWALK_CONTINUE;
882}
883
884/*
885 */
886void zebra_pbr_show_ipset_list(struct vty *vty, char *ipsetname)
887{
888 struct zebra_pbr_ipset *zpi;
889 struct zebra_ns *zns = zebra_ns_lookup(NS_DEFAULT);
890 struct zebra_pbr_ipset_entry_unique_display unique;
891 struct zebra_pbr_env_display uniqueipset;
892
893 if (ipsetname) {
894 zpi = zebra_pbr_lookup_ipset_pername(zns, ipsetname);
895 if (!zpi) {
896 vty_out(vty, "No IPset %s found\n", ipsetname);
897 return;
898 }
899 vty_out(vty, "IPset %s type %s\n", ipsetname,
900 zebra_pbr_ipset_type2str(zpi->type));
901
902 unique.vty = vty;
903 unique.zpi = zpi;
73a829f7 904 unique.zns = zns;
586f4ccf
PG
905 hash_walk(zns->ipset_entry_hash,
906 zebra_pbr_show_ipset_entry_walkcb,
907 &unique);
908 return;
909 }
910 uniqueipset.zns = zns;
911 uniqueipset.vty = vty;
912 hash_walk(zns->ipset_hash, zebra_pbr_show_ipset_walkcb,
913 &uniqueipset);
914}
915
916struct pbr_rule_fwmark_lookup {
917 struct zebra_pbr_rule *ptr;
918 uint32_t fwmark;
919};
920
921static int zebra_pbr_rule_lookup_fwmark_walkcb(struct hash_backet *backet,
922 void *arg)
923{
924 struct pbr_rule_fwmark_lookup *iprule =
925 (struct pbr_rule_fwmark_lookup *)arg;
926 struct zebra_pbr_rule *zpr = (struct zebra_pbr_rule *)backet->data;
927
928 if (iprule->fwmark == zpr->rule.filter.fwmark) {
929 iprule->ptr = zpr;
930 return HASHWALK_ABORT;
931 }
932 return HASHWALK_CONTINUE;
933}
934
935static int zebra_pbr_show_iptable_walkcb(struct hash_backet *backet, void *arg)
936{
937 struct zebra_pbr_iptable *iptable =
938 (struct zebra_pbr_iptable *)backet->data;
939 struct zebra_pbr_env_display *env = (struct zebra_pbr_env_display *)arg;
940 struct vty *vty = env->vty;
941 struct zebra_ns *zns = env->zns;
73a829f7
PG
942 int ret;
943 uint64_t pkts = 0, bytes = 0;
586f4ccf
PG
944
945 vty_out(vty, "IPtable %s action %s (%u)\n", iptable->ipset_name,
946 iptable->action == ZEBRA_IPTABLES_DROP ? "drop" : "redirect",
947 iptable->unique);
948
73a829f7
PG
949 ret = hook_call(zebra_pbr_iptable_wrap_script_get_stat,
950 zns, iptable, &pkts, &bytes);
951 if (ret && pkts > 0)
952 vty_out(vty, "\t pkts %" PRIu64 ", bytes %" PRIu64"\n",
953 pkts, bytes);
586f4ccf
PG
954 if (iptable->action != ZEBRA_IPTABLES_DROP) {
955 struct pbr_rule_fwmark_lookup prfl;
956
957 prfl.fwmark = iptable->fwmark;
958 prfl.ptr = NULL;
959 hash_walk(zns->rules_hash,
960 &zebra_pbr_rule_lookup_fwmark_walkcb, &prfl);
961 if (prfl.ptr) {
962 struct zebra_pbr_rule *zpr = prfl.ptr;
963
964 vty_out(vty, "\t table %u, fwmark %u\n",
965 zpr->rule.action.table,
966 prfl.fwmark);
967 }
968 }
969 return HASHWALK_CONTINUE;
970}
971
972void zebra_pbr_show_iptable(struct vty *vty)
973{
974 struct zebra_ns *zns = zebra_ns_lookup(NS_DEFAULT);
975 struct zebra_pbr_env_display env;
976
977 env.vty = vty;
978 env.zns = zns;
979
980 hash_walk(zns->iptable_hash, zebra_pbr_show_iptable_walkcb,
981 &env);
982}
f80ec7e3
PG
983
984void zebra_pbr_iptable_update_interfacelist(struct stream *s,
985 struct zebra_pbr_iptable *zpi)
986{
987 uint32_t i = 0, index;
988 struct interface *ifp;
989 char *name;
990
991 for (i = 0; i < zpi->nb_interface; i++) {
992 STREAM_GETL(s, index);
993 ifp = if_lookup_by_index(index, zpi->vrf_id);
994 if (!ifp)
995 continue;
996 name = XSTRDUP(MTYPE_PBR_IPTABLE_IFNAME, ifp->name);
997 listnode_add(zpi->interface_name_list, name);
998 }
999stream_failure:
1000 return;
1001}