]> git.proxmox.com Git - mirror_frr.git/blame - zebra/zebra_pbr.c
Merge pull request #6738 from deastoe/frr-reload-log-level
[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
7f0ea8a4 29#include "zebra/zebra_router.h"
942bf97b 30#include "zebra/zebra_pbr.h"
31#include "zebra/rt.h"
bf094f69 32#include "zebra/zapi_msg.h"
f80ec7e3 33#include "zebra/zebra_memory.h"
c0ea1ae7 34#include "zebra/zserv.h"
f80ec7e3
PG
35
36/* definitions */
37DEFINE_MTYPE_STATIC(ZEBRA, PBR_IPTABLE_IFNAME, "PBR interface list")
942bf97b 38
39/* definitions */
586f4ccf
PG
40static const struct message ipset_type_msg[] = {
41 {IPSET_NET_PORT_NET, "net,port,net"},
42 {IPSET_NET_PORT, "net,port"},
43 {IPSET_NET_NET, "net,net"},
44 {IPSET_NET, "net"},
45 {0}
46};
942bf97b 47
be729dd7
PG
48const struct message icmp_typecode_str[] = {
49 { 0 << 8, "echo-reply"},
50 { 0 << 8, "pong"},
51 { 3 << 8, "network-unreachable"},
52 { (3 << 8) + 1, "host-unreachable"},
53 { (3 << 8) + 2, "protocol-unreachable"},
54 { (3 << 8) + 3, "port-unreachable"},
55 { (3 << 8) + 4, "fragmentation-needed"},
56 { (3 << 8) + 5, "source-route-failed"},
57 { (3 << 8) + 6, "network-unknown"},
58 { (3 << 8) + 7, "host-unknown"},
59 { (3 << 8) + 9, "network-prohibited"},
60 { (3 << 8) + 10, "host-prohibited"},
61 { (3 << 8) + 11, "TOS-network-unreachable"},
62 { (3 << 8) + 12, "TOS-host-unreachable"},
63 { (3 << 8) + 13, "communication-prohibited"},
64 { (3 << 8) + 14, "host-precedence-violation"},
65 { (3 << 8) + 15, "precedence-cutoff"},
66 { 4 << 8, "source-quench"},
67 { 5 << 8, "network-redirect"},
68 { (5 << 8) + 1, "host-redirect"},
69 { (5 << 8) + 2, "TOS-network-redirect"},
70 { (5 << 8) + 3, "TOS-host-redirect"},
71 { 8 << 8, "echo-request"},
72 { 8 << 8, "ping"},
73 { 9 << 8, "router-advertisement"},
74 { 10 << 8, "router-solicitation"},
75 { 11 << 8, "ttl-zero-during-transit"},
76 { (11 << 8) + 1, "ttl-zero-during-reassembly"},
77 { 12 << 8, "ip-header-bad"},
78 { (12 << 8) + 1, "required-option-missing"},
79 { 13 << 8, "timestamp-request"},
80 { 14 << 8, "timestamp-reply"},
81 { 17 << 8, "address-mask-request"},
82 { 18 << 8, "address-mask-reply"},
83 {0}
84};
85
dc993e76
PG
86/* definitions */
87static const struct message tcp_value_str[] = {
88 {TCP_HEADER_FIN, "FIN"},
89 {TCP_HEADER_SYN, "SYN"},
90 {TCP_HEADER_RST, "RST"},
91 {TCP_HEADER_PSH, "PSH"},
92 {TCP_HEADER_ACK, "ACK"},
93 {TCP_HEADER_URG, "URG"},
94 {0}
95};
96
5ac5b7cc
PG
97static const struct message fragment_value_str[] = {
98 {1, "dont-fragment"},
99 {2, "is-fragment"},
100 {4, "first-fragment"},
101 {8, "last-fragment"},
102 {0}
103};
104
942bf97b 105/* static function declarations */
1c6fca1f 106DEFINE_HOOK(zebra_pbr_ipset_entry_get_stat,
62f20a52
DS
107 (struct zebra_pbr_ipset_entry *ipset, uint64_t *pkts,
108 uint64_t *bytes),
109 (ipset, pkts, bytes))
110
1c6fca1f 111DEFINE_HOOK(zebra_pbr_iptable_get_stat,
62f20a52
DS
112 (struct zebra_pbr_iptable *iptable, uint64_t *pkts,
113 uint64_t *bytes),
114 (iptable, pkts, bytes))
115
1c6fca1f 116DEFINE_HOOK(zebra_pbr_iptable_update,
62f20a52
DS
117 (int cmd, struct zebra_pbr_iptable *iptable), (cmd, iptable));
118
1c6fca1f 119DEFINE_HOOK(zebra_pbr_ipset_entry_update,
62f20a52
DS
120 (int cmd, struct zebra_pbr_ipset_entry *ipset), (cmd, ipset));
121
1c6fca1f 122DEFINE_HOOK(zebra_pbr_ipset_update,
62f20a52 123 (int cmd, struct zebra_pbr_ipset *ipset), (cmd, ipset));
942bf97b 124
125/* Private functions */
126
127/* Public functions */
43fe6a2a 128void zebra_pbr_rules_free(void *arg)
1fbfe5a5 129{
43fe6a2a
DS
130 struct zebra_pbr_rule *rule;
131
132 rule = (struct zebra_pbr_rule *)arg;
133
f62e5480 134 (void)dplane_pbr_rule_delete(rule);
43fe6a2a
DS
135 XFREE(MTYPE_TMP, rule);
136}
137
d8b87afe 138uint32_t zebra_pbr_rules_hash_key(const void *arg)
43fe6a2a 139{
d8b87afe 140 const struct zebra_pbr_rule *rule;
43fe6a2a
DS
141 uint32_t key;
142
d8b87afe 143 rule = arg;
5dd0722d
PG
144 key = jhash_3words(rule->rule.seq, rule->rule.priority,
145 rule->rule.action.table,
146 prefix_hash_key(&rule->rule.filter.src_ip));
a0321978 147
5dd0722d 148 if (rule->rule.filter.fwmark)
b77a69bd
SW
149 key = jhash_3words(rule->rule.filter.fwmark, rule->vrf_id,
150 rule->rule.ifindex, key);
1907e4b8 151 else
b77a69bd 152 key = jhash_2words(rule->vrf_id, rule->rule.ifindex, key);
7f0ea8a4 153
5dd0722d
PG
154 return jhash_3words(rule->rule.filter.src_port,
155 rule->rule.filter.dst_port,
156 prefix_hash_key(&rule->rule.filter.dst_ip),
157 jhash_1word(rule->rule.unique, key));
43fe6a2a
DS
158}
159
74df8d6d 160bool zebra_pbr_rules_hash_equal(const void *arg1, const void *arg2)
43fe6a2a
DS
161{
162 const struct zebra_pbr_rule *r1, *r2;
163
164 r1 = (const struct zebra_pbr_rule *)arg1;
165 r2 = (const struct zebra_pbr_rule *)arg2;
166
5dd0722d 167 if (r1->rule.seq != r2->rule.seq)
74df8d6d 168 return false;
43fe6a2a 169
5dd0722d 170 if (r1->rule.priority != r2->rule.priority)
74df8d6d 171 return false;
43fe6a2a 172
5dd0722d 173 if (r1->rule.unique != r2->rule.unique)
74df8d6d 174 return false;
b6c5d343 175
5dd0722d 176 if (r1->rule.action.table != r2->rule.action.table)
74df8d6d 177 return false;
43fe6a2a 178
5dd0722d 179 if (r1->rule.filter.src_port != r2->rule.filter.src_port)
74df8d6d 180 return false;
43fe6a2a 181
5dd0722d 182 if (r1->rule.filter.dst_port != r2->rule.filter.dst_port)
74df8d6d 183 return false;
43fe6a2a 184
5dd0722d 185 if (r1->rule.filter.fwmark != r2->rule.filter.fwmark)
74df8d6d 186 return false;
1907e4b8 187
5dd0722d 188 if (!prefix_same(&r1->rule.filter.src_ip, &r2->rule.filter.src_ip))
74df8d6d 189 return false;
43fe6a2a 190
5dd0722d 191 if (!prefix_same(&r1->rule.filter.dst_ip, &r2->rule.filter.dst_ip))
74df8d6d 192 return false;
43fe6a2a 193
b19d55d0 194 if (r1->rule.ifindex != r2->rule.ifindex)
74df8d6d 195 return false;
a0321978 196
7f0ea8a4
DS
197 if (r1->vrf_id != r2->vrf_id)
198 return false;
199
74df8d6d 200 return true;
43fe6a2a
DS
201}
202
f46bbab4 203struct pbr_rule_unique_lookup {
8c3cd6c6
DS
204 struct zebra_pbr_rule *rule;
205 uint32_t unique;
b77a69bd 206 ifindex_t ifindex;
7f0ea8a4 207 vrf_id_t vrf_id;
8c3cd6c6
DS
208};
209
e3b78da8 210static int pbr_rule_lookup_unique_walker(struct hash_bucket *b, void *data)
8c3cd6c6 211{
f46bbab4 212 struct pbr_rule_unique_lookup *pul = data;
8c3cd6c6
DS
213 struct zebra_pbr_rule *rule = b->data;
214
7f0ea8a4 215 if (pul->unique == rule->rule.unique
b77a69bd 216 && pul->ifindex == rule->rule.ifindex
7f0ea8a4 217 && pul->vrf_id == rule->vrf_id) {
8c3cd6c6
DS
218 pul->rule = rule;
219 return HASHWALK_ABORT;
220 }
221
222 return HASHWALK_CONTINUE;
223}
224
62f20a52
DS
225static struct zebra_pbr_rule *
226pbr_rule_lookup_unique(struct zebra_pbr_rule *zrule)
8c3cd6c6 227{
f46bbab4 228 struct pbr_rule_unique_lookup pul;
8c3cd6c6 229
7f0ea8a4 230 pul.unique = zrule->rule.unique;
b77a69bd 231 pul.ifindex = zrule->rule.ifindex;
8c3cd6c6 232 pul.rule = NULL;
7f0ea8a4
DS
233 pul.vrf_id = zrule->vrf_id;
234 hash_walk(zrouter.rules_hash, &pbr_rule_lookup_unique_walker, &pul);
8c3cd6c6
DS
235
236 return pul.rule;
237}
238
7661461a
PG
239void zebra_pbr_ipset_free(void *arg)
240{
241 struct zebra_pbr_ipset *ipset;
242
243 ipset = (struct zebra_pbr_ipset *)arg;
1c6fca1f 244 hook_call(zebra_pbr_ipset_update, 0, ipset);
7661461a
PG
245 XFREE(MTYPE_TMP, ipset);
246}
247
d8b87afe 248uint32_t zebra_pbr_ipset_hash_key(const void *arg)
7661461a 249{
d8b87afe 250 const struct zebra_pbr_ipset *ipset = arg;
425bdd6b 251 uint32_t *pnt = (uint32_t *)&ipset->ipset_name;
62f20a52 252 uint32_t key = jhash_1word(ipset->vrf_id, 0x63ab42de);
7661461a 253
62f20a52 254 return jhash2(pnt, ZEBRA_IPSET_NAME_HASH_SIZE, key);
7661461a
PG
255}
256
74df8d6d 257bool zebra_pbr_ipset_hash_equal(const void *arg1, const void *arg2)
7661461a
PG
258{
259 const struct zebra_pbr_ipset *r1, *r2;
260
261 r1 = (const struct zebra_pbr_ipset *)arg1;
262 r2 = (const struct zebra_pbr_ipset *)arg2;
263
264 if (r1->type != r2->type)
74df8d6d 265 return false;
7661461a 266 if (r1->unique != r2->unique)
74df8d6d 267 return false;
62f20a52
DS
268 if (r1->vrf_id != r2->vrf_id)
269 return false;
270
7661461a
PG
271 if (strncmp(r1->ipset_name, r2->ipset_name,
272 ZEBRA_IPSET_NAME_SIZE))
74df8d6d
DS
273 return false;
274 return true;
7661461a
PG
275}
276
277void zebra_pbr_ipset_entry_free(void *arg)
278{
279 struct zebra_pbr_ipset_entry *ipset;
280
281 ipset = (struct zebra_pbr_ipset_entry *)arg;
73a829f7 282
1c6fca1f 283 hook_call(zebra_pbr_ipset_entry_update, 0, ipset);
7661461a
PG
284
285 XFREE(MTYPE_TMP, ipset);
286}
287
d8b87afe 288uint32_t zebra_pbr_ipset_entry_hash_key(const void *arg)
7661461a 289{
d8b87afe 290 const struct zebra_pbr_ipset_entry *ipset;
7661461a
PG
291 uint32_t key;
292
d8b87afe 293 ipset = arg;
7661461a
PG
294 key = prefix_hash_key(&ipset->src);
295 key = jhash_1word(ipset->unique, key);
296 key = jhash_1word(prefix_hash_key(&ipset->dst), key);
25d760c5
PG
297 key = jhash(&ipset->dst_port_min, 2, key);
298 key = jhash(&ipset->dst_port_max, 2, key);
299 key = jhash(&ipset->src_port_min, 2, key);
300 key = jhash(&ipset->src_port_max, 2, key);
301 key = jhash(&ipset->proto, 1, key);
7661461a
PG
302
303 return key;
304}
305
74df8d6d 306bool zebra_pbr_ipset_entry_hash_equal(const void *arg1, const void *arg2)
7661461a
PG
307{
308 const struct zebra_pbr_ipset_entry *r1, *r2;
309
310 r1 = (const struct zebra_pbr_ipset_entry *)arg1;
311 r2 = (const struct zebra_pbr_ipset_entry *)arg2;
312
313 if (r1->unique != r2->unique)
74df8d6d 314 return false;
7661461a
PG
315
316 if (!prefix_same(&r1->src, &r2->src))
74df8d6d 317 return false;
7661461a
PG
318
319 if (!prefix_same(&r1->dst, &r2->dst))
74df8d6d 320 return false;
7661461a 321
25d760c5 322 if (r1->src_port_min != r2->src_port_min)
74df8d6d 323 return false;
25d760c5
PG
324
325 if (r1->src_port_max != r2->src_port_max)
74df8d6d 326 return false;
25d760c5
PG
327
328 if (r1->dst_port_min != r2->dst_port_min)
74df8d6d 329 return false;
25d760c5
PG
330
331 if (r1->dst_port_max != r2->dst_port_max)
74df8d6d 332 return false;
25d760c5
PG
333
334 if (r1->proto != r2->proto)
74df8d6d
DS
335 return false;
336 return true;
7661461a
PG
337}
338
3b1de7b8
PG
339/* this function gives option to flush plugin memory contexts
340 * with all parameter. set it to true to flush all
341 * set it to false to flush only passed arg argument
342 */
343static void _zebra_pbr_iptable_free_all(void *arg, bool all)
7abd6c4f
PG
344{
345 struct zebra_pbr_iptable *iptable;
f80ec7e3
PG
346 struct listnode *node, *nnode;
347 char *name;
7abd6c4f
PG
348
349 iptable = (struct zebra_pbr_iptable *)arg;
3b1de7b8
PG
350
351 if (all)
352 hook_call(zebra_pbr_iptable_update, 0, iptable);
7abd6c4f 353
8b5c4dce
QY
354 if (iptable->interface_name_list) {
355 for (ALL_LIST_ELEMENTS(iptable->interface_name_list, node,
356 nnode, name)) {
357 XFREE(MTYPE_PBR_IPTABLE_IFNAME, name);
358 list_delete_node(iptable->interface_name_list, node);
359 }
360 list_delete(&iptable->interface_name_list);
f80ec7e3 361 }
7abd6c4f
PG
362 XFREE(MTYPE_TMP, iptable);
363}
364
3b1de7b8
PG
365void zebra_pbr_iptable_free(void *arg)
366{
367 _zebra_pbr_iptable_free_all(arg, false);
368}
369
d8b87afe 370uint32_t zebra_pbr_iptable_hash_key(const void *arg)
7abd6c4f 371{
d8b87afe 372 const struct zebra_pbr_iptable *iptable = arg;
7abd6c4f
PG
373 uint32_t *pnt = (uint32_t *)&(iptable->ipset_name);
374 uint32_t key;
375
376 key = jhash2(pnt, ZEBRA_IPSET_NAME_HASH_SIZE,
377 0x63ab42de);
378 key = jhash_1word(iptable->fwmark, key);
e7f7dad4
PG
379 key = jhash_1word(iptable->pkt_len_min, key);
380 key = jhash_1word(iptable->pkt_len_max, key);
dc993e76
PG
381 key = jhash_1word(iptable->tcp_flags, key);
382 key = jhash_1word(iptable->tcp_mask_flags, key);
4977bd6c 383 key = jhash_1word(iptable->dscp_value, key);
f449d223 384 key = jhash_1word(iptable->protocol, key);
5ac5b7cc 385 key = jhash_1word(iptable->fragment, key);
62f20a52
DS
386 key = jhash_1word(iptable->vrf_id, key);
387
7abd6c4f
PG
388 return jhash_3words(iptable->filter_bm, iptable->type,
389 iptable->unique, key);
390}
391
74df8d6d 392bool zebra_pbr_iptable_hash_equal(const void *arg1, const void *arg2)
7abd6c4f
PG
393{
394 const struct zebra_pbr_iptable *r1, *r2;
395
396 r1 = (const struct zebra_pbr_iptable *)arg1;
397 r2 = (const struct zebra_pbr_iptable *)arg2;
398
62f20a52 399 if (r1->vrf_id != r2->vrf_id)
b08047f8 400 return false;
7abd6c4f 401 if (r1->type != r2->type)
74df8d6d 402 return false;
7abd6c4f 403 if (r1->unique != r2->unique)
74df8d6d 404 return false;
7abd6c4f 405 if (r1->filter_bm != r2->filter_bm)
74df8d6d 406 return false;
7abd6c4f 407 if (r1->fwmark != r2->fwmark)
74df8d6d 408 return false;
7abd6c4f 409 if (r1->action != r2->action)
74df8d6d 410 return false;
7abd6c4f
PG
411 if (strncmp(r1->ipset_name, r2->ipset_name,
412 ZEBRA_IPSET_NAME_SIZE))
74df8d6d 413 return false;
e7f7dad4 414 if (r1->pkt_len_min != r2->pkt_len_min)
74df8d6d 415 return false;
e7f7dad4 416 if (r1->pkt_len_max != r2->pkt_len_max)
74df8d6d 417 return false;
dc993e76 418 if (r1->tcp_flags != r2->tcp_flags)
74df8d6d 419 return false;
dc993e76 420 if (r1->tcp_mask_flags != r2->tcp_mask_flags)
74df8d6d 421 return false;
4977bd6c 422 if (r1->dscp_value != r2->dscp_value)
74df8d6d 423 return false;
5ac5b7cc 424 if (r1->fragment != r2->fragment)
74df8d6d 425 return false;
f449d223
PG
426 if (r1->protocol != r2->protocol)
427 return false;
74df8d6d 428 return true;
7abd6c4f
PG
429}
430
43fe6a2a
DS
431static void *pbr_rule_alloc_intern(void *arg)
432{
433 struct zebra_pbr_rule *zpr;
434 struct zebra_pbr_rule *new;
435
436 zpr = (struct zebra_pbr_rule *)arg;
437
438 new = XCALLOC(MTYPE_TMP, sizeof(*new));
439
440 memcpy(new, zpr, sizeof(*zpr));
441
442 return new;
443}
444
3ae327cb
SW
445static int pbr_rule_release(struct zebra_pbr_rule *rule)
446{
447 struct zebra_pbr_rule *lookup;
448
449 lookup = hash_lookup(zrouter.rules_hash, rule);
450
451 if (!lookup)
452 return -ENOENT;
453
454 hash_release(zrouter.rules_hash, lookup);
455 XFREE(MTYPE_TMP, lookup);
456
457 return 0;
458}
459
7f0ea8a4 460void zebra_pbr_add_rule(struct zebra_pbr_rule *rule)
43fe6a2a 461{
3ae327cb 462 struct zebra_pbr_rule *found;
8c3cd6c6 463
3ae327cb
SW
464 /**
465 * Check if we already have it (this checks via a unique ID, walking
466 * over the hash table, not via a hash operation).
8c3cd6c6 467 */
3ae327cb
SW
468 found = pbr_rule_lookup_unique(rule);
469
470 (void)hash_get(zrouter.rules_hash, rule, pbr_rule_alloc_intern);
471
472 /* If found, this is an update */
473 if (found) {
f62e5480 474 (void)dplane_pbr_rule_update(found, rule);
3ae327cb
SW
475
476 if (pbr_rule_release(found))
477 zlog_debug(
478 "%s: Rule being updated we know nothing about",
479 __PRETTY_FUNCTION__);
480
481 } else
f62e5480 482 (void)dplane_pbr_rule_add(rule);
1fbfe5a5
DS
483}
484
7f0ea8a4 485void zebra_pbr_del_rule(struct zebra_pbr_rule *rule)
1fbfe5a5 486{
f62e5480 487 (void)dplane_pbr_rule_delete(rule);
43fe6a2a 488
3ae327cb 489 if (pbr_rule_release(rule))
9df414fe 490 zlog_debug("%s: Rule being deleted we know nothing about",
15569c58 491 __func__);
1fbfe5a5
DS
492}
493
e3b78da8 494static void zebra_pbr_cleanup_rules(struct hash_bucket *b, void *data)
e69aa084 495{
e69aa084
DS
496 struct zebra_pbr_rule *rule = b->data;
497 int *sock = data;
498
499 if (rule->sock == *sock) {
f62e5480 500 (void)dplane_pbr_rule_delete(rule);
c4097b75
SW
501 if (hash_release(zrouter.rules_hash, rule))
502 XFREE(MTYPE_TMP, rule);
503 else
504 zlog_debug(
505 "%s: Rule seq: %u is being cleaned but we can't find it in our tables",
506 __func__, rule->rule.seq);
e69aa084
DS
507 }
508}
509
e3b78da8 510static void zebra_pbr_cleanup_ipset(struct hash_bucket *b, void *data)
c2ef5232 511{
c2ef5232
PG
512 struct zebra_pbr_ipset *ipset = b->data;
513 int *sock = data;
514
73a829f7 515 if (ipset->sock == *sock) {
b147e204
QY
516 if (hash_release(zrouter.ipset_hash, ipset))
517 zebra_pbr_ipset_free(ipset);
518 else
519 hook_call(zebra_pbr_ipset_update, 0, ipset);
73a829f7 520 }
c2ef5232
PG
521}
522
e3b78da8 523static void zebra_pbr_cleanup_ipset_entry(struct hash_bucket *b, void *data)
c2ef5232 524{
c2ef5232
PG
525 struct zebra_pbr_ipset_entry *ipset = b->data;
526 int *sock = data;
527
73a829f7 528 if (ipset->sock == *sock) {
b147e204
QY
529 if (hash_release(zrouter.ipset_entry_hash, ipset))
530 zebra_pbr_ipset_entry_free(ipset);
531 else
532 hook_call(zebra_pbr_ipset_entry_update, 0, ipset);
73a829f7 533 }
c2ef5232
PG
534}
535
e3b78da8 536static void zebra_pbr_cleanup_iptable(struct hash_bucket *b, void *data)
c2ef5232 537{
c2ef5232
PG
538 struct zebra_pbr_iptable *iptable = b->data;
539 int *sock = data;
540
73a829f7 541 if (iptable->sock == *sock) {
b147e204 542 if (hash_release(zrouter.iptable_hash, iptable))
3b1de7b8 543 _zebra_pbr_iptable_free_all(iptable, true);
b147e204
QY
544 else
545 hook_call(zebra_pbr_iptable_update, 0, iptable);
73a829f7 546 }
c2ef5232
PG
547}
548
4c0ec639 549static int zebra_pbr_client_close_cleanup(struct zserv *client)
e69aa084 550{
4c0ec639 551 int sock = client->sock;
e69aa084 552
4c0ec639
PG
553 if (!sock)
554 return 0;
7f0ea8a4 555 hash_iterate(zrouter.rules_hash, zebra_pbr_cleanup_rules, &sock);
62f20a52
DS
556 hash_iterate(zrouter.iptable_hash, zebra_pbr_cleanup_iptable, &sock);
557 hash_iterate(zrouter.ipset_entry_hash, zebra_pbr_cleanup_ipset_entry,
558 &sock);
559 hash_iterate(zrouter.ipset_hash, zebra_pbr_cleanup_ipset, &sock);
4c0ec639
PG
560 return 1;
561}
562
563void zebra_pbr_init(void)
564{
c0ea1ae7 565 hook_register(zserv_client_close, zebra_pbr_client_close_cleanup);
e69aa084
DS
566}
567
7661461a
PG
568static void *pbr_ipset_alloc_intern(void *arg)
569{
570 struct zebra_pbr_ipset *zpi;
571 struct zebra_pbr_ipset *new;
572
573 zpi = (struct zebra_pbr_ipset *)arg;
574
575 new = XCALLOC(MTYPE_TMP, sizeof(struct zebra_pbr_ipset));
576
577 memcpy(new, zpi, sizeof(*zpi));
578
579 return new;
580}
581
62f20a52 582void zebra_pbr_create_ipset(struct zebra_pbr_ipset *ipset)
7661461a 583{
73a829f7
PG
584 int ret;
585
62f20a52 586 (void)hash_get(zrouter.ipset_hash, ipset, pbr_ipset_alloc_intern);
1c6fca1f 587 ret = hook_call(zebra_pbr_ipset_update, 1, ipset);
73a829f7 588 kernel_pbr_ipset_add_del_status(ipset,
ea1c14f6
MS
589 ret ? ZEBRA_DPLANE_INSTALL_SUCCESS
590 : ZEBRA_DPLANE_INSTALL_FAILURE);
7661461a
PG
591}
592
62f20a52 593void zebra_pbr_destroy_ipset(struct zebra_pbr_ipset *ipset)
7661461a
PG
594{
595 struct zebra_pbr_ipset *lookup;
596
62f20a52 597 lookup = hash_lookup(zrouter.ipset_hash, ipset);
1c6fca1f 598 hook_call(zebra_pbr_ipset_update, 0, ipset);
de67547d 599 if (lookup) {
62f20a52 600 hash_release(zrouter.ipset_hash, lookup);
7661461a 601 XFREE(MTYPE_TMP, lookup);
de67547d 602 } else
9df414fe
QY
603 zlog_debug(
604 "%s: IPSet Entry being deleted we know nothing about",
15569c58 605 __func__);
7661461a
PG
606}
607
ed78b7c8
PG
608struct pbr_ipset_name_lookup {
609 struct zebra_pbr_ipset *ipset;
610 char ipset_name[ZEBRA_IPSET_NAME_SIZE];
611};
612
5b0d92b8 613const char *zebra_pbr_ipset_type2str(uint32_t type)
586f4ccf
PG
614{
615 return lookup_msg(ipset_type_msg, type,
616 "Unrecognized IPset Type");
617}
618
e3b78da8 619static int zebra_pbr_ipset_pername_walkcb(struct hash_bucket *bucket, void *arg)
ed78b7c8
PG
620{
621 struct pbr_ipset_name_lookup *pinl =
622 (struct pbr_ipset_name_lookup *)arg;
e3b78da8 623 struct zebra_pbr_ipset *zpi = (struct zebra_pbr_ipset *)bucket->data;
ed78b7c8
PG
624
625 if (!strncmp(pinl->ipset_name, zpi->ipset_name,
626 ZEBRA_IPSET_NAME_SIZE)) {
627 pinl->ipset = zpi;
628 return HASHWALK_ABORT;
629 }
630 return HASHWALK_CONTINUE;
631}
632
62f20a52 633struct zebra_pbr_ipset *zebra_pbr_lookup_ipset_pername(char *ipsetname)
d59c13af 634{
ed78b7c8
PG
635 struct pbr_ipset_name_lookup pinl;
636 struct pbr_ipset_name_lookup *ptr = &pinl;
637
d59c13af
PG
638 if (!ipsetname)
639 return NULL;
ed78b7c8
PG
640 memset(ptr, 0, sizeof(struct pbr_ipset_name_lookup));
641 snprintf((char *)ptr->ipset_name, ZEBRA_IPSET_NAME_SIZE, "%s",
642 ipsetname);
62f20a52 643 hash_walk(zrouter.ipset_hash, zebra_pbr_ipset_pername_walkcb, ptr);
ed78b7c8 644 return ptr->ipset;
d59c13af
PG
645}
646
7661461a
PG
647static void *pbr_ipset_entry_alloc_intern(void *arg)
648{
649 struct zebra_pbr_ipset_entry *zpi;
650 struct zebra_pbr_ipset_entry *new;
651
652 zpi = (struct zebra_pbr_ipset_entry *)arg;
653
654 new = XCALLOC(MTYPE_TMP, sizeof(struct zebra_pbr_ipset_entry));
655
656 memcpy(new, zpi, sizeof(*zpi));
657
658 return new;
659}
660
62f20a52 661void zebra_pbr_add_ipset_entry(struct zebra_pbr_ipset_entry *ipset)
7661461a 662{
73a829f7
PG
663 int ret;
664
62f20a52 665 (void)hash_get(zrouter.ipset_entry_hash, ipset,
7661461a 666 pbr_ipset_entry_alloc_intern);
1c6fca1f 667 ret = hook_call(zebra_pbr_ipset_entry_update, 1, ipset);
73a829f7 668 kernel_pbr_ipset_entry_add_del_status(ipset,
ea1c14f6
MS
669 ret ? ZEBRA_DPLANE_INSTALL_SUCCESS
670 : ZEBRA_DPLANE_INSTALL_FAILURE);
7661461a
PG
671}
672
62f20a52 673void zebra_pbr_del_ipset_entry(struct zebra_pbr_ipset_entry *ipset)
7661461a
PG
674{
675 struct zebra_pbr_ipset_entry *lookup;
676
62f20a52 677 lookup = hash_lookup(zrouter.ipset_entry_hash, ipset);
1c6fca1f 678 hook_call(zebra_pbr_ipset_entry_update, 0, ipset);
de67547d 679 if (lookup) {
62f20a52 680 hash_release(zrouter.ipset_entry_hash, lookup);
7661461a 681 XFREE(MTYPE_TMP, lookup);
de67547d 682 } else
9df414fe 683 zlog_debug("%s: IPSet being deleted we know nothing about",
15569c58 684 __func__);
7661461a
PG
685}
686
7abd6c4f
PG
687static void *pbr_iptable_alloc_intern(void *arg)
688{
689 struct zebra_pbr_iptable *zpi;
690 struct zebra_pbr_iptable *new;
592af4cc
QY
691 struct listnode *ln;
692 char *ifname;
7abd6c4f
PG
693
694 zpi = (struct zebra_pbr_iptable *)arg;
695
696 new = XCALLOC(MTYPE_TMP, sizeof(struct zebra_pbr_iptable));
697
592af4cc 698 /* Deep structure copy */
7abd6c4f 699 memcpy(new, zpi, sizeof(*zpi));
592af4cc
QY
700 new->interface_name_list = list_new();
701
702 if (zpi->interface_name_list) {
703 for (ALL_LIST_ELEMENTS_RO(zpi->interface_name_list, ln, ifname))
704 listnode_add(new->interface_name_list,
705 XSTRDUP(MTYPE_PBR_IPTABLE_IFNAME, ifname));
706 }
7abd6c4f
PG
707
708 return new;
709}
710
62f20a52 711void zebra_pbr_add_iptable(struct zebra_pbr_iptable *iptable)
7abd6c4f 712{
73a829f7
PG
713 int ret;
714
62f20a52 715 (void)hash_get(zrouter.iptable_hash, iptable, pbr_iptable_alloc_intern);
1c6fca1f 716 ret = hook_call(zebra_pbr_iptable_update, 1, iptable);
73a829f7 717 kernel_pbr_iptable_add_del_status(iptable,
ea1c14f6
MS
718 ret ? ZEBRA_DPLANE_INSTALL_SUCCESS
719 : ZEBRA_DPLANE_INSTALL_FAILURE);
7abd6c4f
PG
720}
721
62f20a52 722void zebra_pbr_del_iptable(struct zebra_pbr_iptable *iptable)
7abd6c4f 723{
f80ec7e3 724 struct zebra_pbr_iptable *lookup;
7abd6c4f 725
62f20a52 726 lookup = hash_lookup(zrouter.iptable_hash, iptable);
1c6fca1f 727 hook_call(zebra_pbr_iptable_update, 0, iptable);
f80ec7e3
PG
728 if (lookup) {
729 struct listnode *node, *nnode;
730 char *name;
731
62f20a52 732 hash_release(zrouter.iptable_hash, lookup);
f80ec7e3
PG
733 for (ALL_LIST_ELEMENTS(iptable->interface_name_list,
734 node, nnode, name)) {
735 XFREE(MTYPE_PBR_IPTABLE_IFNAME, name);
736 list_delete_node(iptable->interface_name_list,
737 node);
738 }
8b5c4dce 739 list_delete(&iptable->interface_name_list);
7abd6c4f 740 XFREE(MTYPE_TMP, lookup);
f80ec7e3 741 } else
9df414fe 742 zlog_debug("%s: IPTable being deleted we know nothing about",
5e81f5dd 743 __func__);
7abd6c4f
PG
744}
745
942bf97b 746/*
747 * Handle success or failure of rule (un)install in the kernel.
748 */
f62e5480
JU
749void zebra_pbr_dplane_result(struct zebra_dplane_ctx *ctx)
750{
751 enum zebra_dplane_result res;
752 enum dplane_op_e op;
753
754 res = dplane_ctx_get_status(ctx);
755 op = dplane_ctx_get_op(ctx);
756 if (op == DPLANE_OP_RULE_ADD || op == DPLANE_OP_RULE_UPDATE)
757 zsend_rule_notify_owner(ctx, res == ZEBRA_DPLANE_REQUEST_SUCCESS
758 ? ZAPI_RULE_INSTALLED
759 : ZAPI_RULE_FAIL_INSTALL);
760 else if (op == DPLANE_OP_RULE_DELETE)
761 zsend_rule_notify_owner(ctx, res == ZEBRA_DPLANE_REQUEST_SUCCESS
762 ? ZAPI_RULE_REMOVED
763 : ZAPI_RULE_FAIL_REMOVE);
764 else
765 flog_err(
766 EC_ZEBRA_PBR_RULE_UPDATE,
767 "Context received in pbr rule dplane result handler with incorrect OP code (%u)",
768 op);
769
770
771 dplane_ctx_fini(&ctx);
942bf97b 772}
773
425bdd6b
PG
774/*
775 * Handle success or failure of ipset (un)install in the kernel.
776 */
777void kernel_pbr_ipset_add_del_status(struct zebra_pbr_ipset *ipset,
ea1c14f6 778 enum zebra_dplane_status res)
425bdd6b
PG
779{
780 switch (res) {
ea1c14f6 781 case ZEBRA_DPLANE_INSTALL_SUCCESS:
425bdd6b
PG
782 zsend_ipset_notify_owner(ipset, ZAPI_IPSET_INSTALLED);
783 break;
ea1c14f6 784 case ZEBRA_DPLANE_INSTALL_FAILURE:
425bdd6b
PG
785 zsend_ipset_notify_owner(ipset, ZAPI_IPSET_FAIL_INSTALL);
786 break;
ea1c14f6 787 case ZEBRA_DPLANE_DELETE_SUCCESS:
4c550bcf
PG
788 zsend_ipset_notify_owner(ipset, ZAPI_IPSET_REMOVED);
789 break;
ea1c14f6 790 case ZEBRA_DPLANE_DELETE_FAILURE:
34d9d5be 791 zsend_ipset_notify_owner(ipset, ZAPI_IPSET_FAIL_REMOVE);
425bdd6b 792 break;
ea1c14f6
MS
793 case ZEBRA_DPLANE_STATUS_NONE:
794 break;
425bdd6b
PG
795 }
796}
797
798/*
799 * Handle success or failure of ipset (un)install in the kernel.
800 */
801void kernel_pbr_ipset_entry_add_del_status(
802 struct zebra_pbr_ipset_entry *ipset,
ea1c14f6 803 enum zebra_dplane_status res)
425bdd6b
PG
804{
805 switch (res) {
ea1c14f6 806 case ZEBRA_DPLANE_INSTALL_SUCCESS:
425bdd6b
PG
807 zsend_ipset_entry_notify_owner(ipset,
808 ZAPI_IPSET_ENTRY_INSTALLED);
809 break;
ea1c14f6 810 case ZEBRA_DPLANE_INSTALL_FAILURE:
425bdd6b
PG
811 zsend_ipset_entry_notify_owner(ipset,
812 ZAPI_IPSET_ENTRY_FAIL_INSTALL);
813 break;
ea1c14f6 814 case ZEBRA_DPLANE_DELETE_SUCCESS:
4c550bcf
PG
815 zsend_ipset_entry_notify_owner(ipset,
816 ZAPI_IPSET_ENTRY_REMOVED);
817 break;
ea1c14f6 818 case ZEBRA_DPLANE_DELETE_FAILURE:
4c550bcf 819 zsend_ipset_entry_notify_owner(ipset,
34d9d5be 820 ZAPI_IPSET_ENTRY_FAIL_REMOVE);
425bdd6b 821 break;
ea1c14f6
MS
822 case ZEBRA_DPLANE_STATUS_NONE:
823 break;
425bdd6b
PG
824 }
825}
826
7abd6c4f
PG
827/*
828 * Handle success or failure of ipset (un)install in the kernel.
829 */
830void kernel_pbr_iptable_add_del_status(struct zebra_pbr_iptable *iptable,
ea1c14f6 831 enum zebra_dplane_status res)
7abd6c4f
PG
832{
833 switch (res) {
ea1c14f6 834 case ZEBRA_DPLANE_INSTALL_SUCCESS:
7abd6c4f
PG
835 zsend_iptable_notify_owner(iptable, ZAPI_IPTABLE_INSTALLED);
836 break;
ea1c14f6 837 case ZEBRA_DPLANE_INSTALL_FAILURE:
7abd6c4f
PG
838 zsend_iptable_notify_owner(iptable, ZAPI_IPTABLE_FAIL_INSTALL);
839 break;
ea1c14f6 840 case ZEBRA_DPLANE_DELETE_SUCCESS:
4c550bcf
PG
841 zsend_iptable_notify_owner(iptable,
842 ZAPI_IPTABLE_REMOVED);
843 break;
ea1c14f6 844 case ZEBRA_DPLANE_DELETE_FAILURE:
4c550bcf 845 zsend_iptable_notify_owner(iptable,
34d9d5be 846 ZAPI_IPTABLE_FAIL_REMOVE);
7abd6c4f 847 break;
ea1c14f6
MS
848 case ZEBRA_DPLANE_STATUS_NONE:
849 break;
7abd6c4f
PG
850 }
851}
852
942bf97b 853/*
854 * Handle rule delete notification from kernel.
855 */
a0321978 856int kernel_pbr_rule_del(struct zebra_pbr_rule *rule)
942bf97b 857{
858 return 0;
859}
586f4ccf
PG
860
861struct zebra_pbr_ipset_entry_unique_display {
862 struct zebra_pbr_ipset *zpi;
863 struct vty *vty;
73a829f7 864 struct zebra_ns *zns;
586f4ccf
PG
865};
866
867struct zebra_pbr_env_display {
868 struct zebra_ns *zns;
869 struct vty *vty;
7929821a 870 char *name;
586f4ccf
PG
871};
872
873static const char *zebra_pbr_prefix2str(union prefixconstptr pu,
874 char *str, int size)
875{
876 const struct prefix *p = pu.p;
877 char buf[PREFIX2STR_BUFFER];
878
879 if (p->family == AF_INET && p->prefixlen == IPV4_MAX_PREFIXLEN) {
880 snprintf(str, size, "%s", inet_ntop(p->family, &p->u.prefix,
881 buf, PREFIX2STR_BUFFER));
882 return str;
883 }
884 return prefix2str(pu, str, size);
885}
886
be729dd7
PG
887static void zebra_pbr_display_icmp(struct vty *vty,
888 struct zebra_pbr_ipset_entry *zpie)
889{
890 char decoded_str[20];
891 uint16_t port;
892
893 /* range icmp type */
894 if (zpie->src_port_max || zpie->dst_port_max) {
2b7165e7 895 vty_out(vty, ":icmp:[type <%u:%u>;code <%u:%u>",
be729dd7
PG
896 zpie->src_port_min, zpie->src_port_max,
897 zpie->dst_port_min, zpie->dst_port_max);
898 } else {
899 port = ((zpie->src_port_min << 8) & 0xff00) +
900 (zpie->dst_port_min & 0xff);
901 memset(decoded_str, 0, sizeof(decoded_str));
2b7165e7 902 snprintf(decoded_str, sizeof(decoded_str), "%u/%u",
772270f3 903 zpie->src_port_min, zpie->dst_port_min);
be729dd7
PG
904 vty_out(vty, ":icmp:%s",
905 lookup_msg(icmp_typecode_str,
906 port, decoded_str));
907 }
908}
909
25d760c5
PG
910static void zebra_pbr_display_port(struct vty *vty, uint32_t filter_bm,
911 uint16_t port_min, uint16_t port_max,
912 uint8_t proto)
913{
914 if (!(filter_bm & PBR_FILTER_PROTO)) {
915 if (port_max)
916 vty_out(vty, ":udp/tcp:%d-%d",
917 port_min, port_max);
918 else
919 vty_out(vty, ":udp/tcp:%d",
920 port_min);
921 } else {
922 if (port_max)
923 vty_out(vty, ":proto %d:%d-%d",
924 proto, port_min, port_max);
925 else
926 vty_out(vty, ":proto %d:%d",
927 proto, port_min);
928 }
929}
930
e3b78da8 931static int zebra_pbr_show_ipset_entry_walkcb(struct hash_bucket *bucket,
586f4ccf
PG
932 void *arg)
933{
934 struct zebra_pbr_ipset_entry_unique_display *unique =
935 (struct zebra_pbr_ipset_entry_unique_display *)arg;
936 struct zebra_pbr_ipset *zpi = unique->zpi;
937 struct vty *vty = unique->vty;
938 struct zebra_pbr_ipset_entry *zpie =
e3b78da8 939 (struct zebra_pbr_ipset_entry *)bucket->data;
73a829f7 940 uint64_t pkts = 0, bytes = 0;
73a829f7 941 int ret = 0;
586f4ccf
PG
942
943 if (zpie->backpointer != zpi)
944 return HASHWALK_CONTINUE;
945
25d760c5
PG
946 if ((zpi->type == IPSET_NET_NET) ||
947 (zpi->type == IPSET_NET_PORT_NET)) {
586f4ccf
PG
948 char buf[PREFIX_STRLEN];
949
950 zebra_pbr_prefix2str(&(zpie->src), buf, sizeof(buf));
951 vty_out(vty, "\tfrom %s", buf);
be729dd7
PG
952 if (zpie->filter_bm & PBR_FILTER_SRC_PORT &&
953 zpie->proto != IPPROTO_ICMP)
25d760c5
PG
954 zebra_pbr_display_port(vty, zpie->filter_bm,
955 zpie->src_port_min,
956 zpie->src_port_max,
957 zpie->proto);
586f4ccf
PG
958 vty_out(vty, " to ");
959 zebra_pbr_prefix2str(&(zpie->dst), buf, sizeof(buf));
960 vty_out(vty, "%s", buf);
be729dd7
PG
961 if (zpie->filter_bm & PBR_FILTER_DST_PORT &&
962 zpie->proto != IPPROTO_ICMP)
25d760c5
PG
963 zebra_pbr_display_port(vty, zpie->filter_bm,
964 zpie->dst_port_min,
965 zpie->dst_port_max,
966 zpie->proto);
be729dd7
PG
967 if (zpie->proto == IPPROTO_ICMP)
968 zebra_pbr_display_icmp(vty, zpie);
25d760c5
PG
969 } else if ((zpi->type == IPSET_NET) ||
970 (zpi->type == IPSET_NET_PORT)) {
586f4ccf
PG
971 char buf[PREFIX_STRLEN];
972
973 if (zpie->filter_bm & PBR_FILTER_SRC_IP) {
974 zebra_pbr_prefix2str(&(zpie->src), buf, sizeof(buf));
975 vty_out(vty, "\tfrom %s", buf);
976 }
be729dd7
PG
977 if (zpie->filter_bm & PBR_FILTER_SRC_PORT &&
978 zpie->proto != IPPROTO_ICMP)
25d760c5
PG
979 zebra_pbr_display_port(vty, zpie->filter_bm,
980 zpie->src_port_min,
981 zpie->src_port_max,
982 zpie->proto);
586f4ccf
PG
983 if (zpie->filter_bm & PBR_FILTER_DST_IP) {
984 zebra_pbr_prefix2str(&(zpie->dst), buf, sizeof(buf));
985 vty_out(vty, "\tto %s", buf);
986 }
be729dd7
PG
987 if (zpie->filter_bm & PBR_FILTER_DST_PORT &&
988 zpie->proto != IPPROTO_ICMP)
25d760c5
PG
989 zebra_pbr_display_port(vty, zpie->filter_bm,
990 zpie->dst_port_min,
991 zpie->dst_port_max,
992 zpie->proto);
be729dd7
PG
993 if (zpie->proto == IPPROTO_ICMP)
994 zebra_pbr_display_icmp(vty, zpie);
586f4ccf
PG
995 }
996 vty_out(vty, " (%u)\n", zpie->unique);
997
1c6fca1f 998 ret = hook_call(zebra_pbr_ipset_entry_get_stat, zpie, &pkts,
62f20a52 999 &bytes);
73a829f7
PG
1000 if (ret && pkts > 0)
1001 vty_out(vty, "\t pkts %" PRIu64 ", bytes %" PRIu64"\n",
1002 pkts, bytes);
586f4ccf
PG
1003 return HASHWALK_CONTINUE;
1004}
1005
e3b78da8 1006static int zebra_pbr_show_ipset_walkcb(struct hash_bucket *bucket, void *arg)
586f4ccf
PG
1007{
1008 struct zebra_pbr_env_display *uniqueipset =
1009 (struct zebra_pbr_env_display *)arg;
e3b78da8 1010 struct zebra_pbr_ipset *zpi = (struct zebra_pbr_ipset *)bucket->data;
586f4ccf
PG
1011 struct zebra_pbr_ipset_entry_unique_display unique;
1012 struct vty *vty = uniqueipset->vty;
1013 struct zebra_ns *zns = uniqueipset->zns;
1014
1015 vty_out(vty, "IPset %s type %s\n", zpi->ipset_name,
1016 zebra_pbr_ipset_type2str(zpi->type));
1017 unique.vty = vty;
1018 unique.zpi = zpi;
73a829f7 1019 unique.zns = zns;
62f20a52 1020 hash_walk(zrouter.ipset_entry_hash, zebra_pbr_show_ipset_entry_walkcb,
586f4ccf
PG
1021 &unique);
1022 vty_out(vty, "\n");
1023 return HASHWALK_CONTINUE;
1024}
1025
dc993e76
PG
1026size_t zebra_pbr_tcpflags_snprintf(char *buffer, size_t len,
1027 uint16_t tcp_val)
1028{
1029 size_t len_written = 0;
1030 static struct message nt = {0};
1031 const struct message *pnt;
1032 int incr = 0;
1033
1034 for (pnt = tcp_value_str;
1035 memcmp(pnt, &nt, sizeof(struct message)); pnt++)
1036 if (pnt->key & tcp_val) {
1037 len_written += snprintf(buffer + len_written,
1038 len - len_written,
1039 "%s%s", incr ?
1040 ",":"", pnt->str);
1041 incr++;
1042 }
1043 return len_written;
1044}
1045
586f4ccf
PG
1046/*
1047 */
1048void zebra_pbr_show_ipset_list(struct vty *vty, char *ipsetname)
1049{
1050 struct zebra_pbr_ipset *zpi;
1051 struct zebra_ns *zns = zebra_ns_lookup(NS_DEFAULT);
1052 struct zebra_pbr_ipset_entry_unique_display unique;
1053 struct zebra_pbr_env_display uniqueipset;
1054
1055 if (ipsetname) {
62f20a52 1056 zpi = zebra_pbr_lookup_ipset_pername(ipsetname);
586f4ccf
PG
1057 if (!zpi) {
1058 vty_out(vty, "No IPset %s found\n", ipsetname);
1059 return;
1060 }
1061 vty_out(vty, "IPset %s type %s\n", ipsetname,
1062 zebra_pbr_ipset_type2str(zpi->type));
1063
1064 unique.vty = vty;
1065 unique.zpi = zpi;
73a829f7 1066 unique.zns = zns;
62f20a52
DS
1067 hash_walk(zrouter.ipset_entry_hash,
1068 zebra_pbr_show_ipset_entry_walkcb, &unique);
586f4ccf
PG
1069 return;
1070 }
1071 uniqueipset.zns = zns;
1072 uniqueipset.vty = vty;
7929821a 1073 uniqueipset.name = NULL;
62f20a52 1074 hash_walk(zrouter.ipset_hash, zebra_pbr_show_ipset_walkcb,
586f4ccf
PG
1075 &uniqueipset);
1076}
1077
1078struct pbr_rule_fwmark_lookup {
1079 struct zebra_pbr_rule *ptr;
1080 uint32_t fwmark;
1081};
1082
e3b78da8 1083static int zebra_pbr_rule_lookup_fwmark_walkcb(struct hash_bucket *bucket,
586f4ccf
PG
1084 void *arg)
1085{
1086 struct pbr_rule_fwmark_lookup *iprule =
1087 (struct pbr_rule_fwmark_lookup *)arg;
e3b78da8 1088 struct zebra_pbr_rule *zpr = (struct zebra_pbr_rule *)bucket->data;
586f4ccf
PG
1089
1090 if (iprule->fwmark == zpr->rule.filter.fwmark) {
1091 iprule->ptr = zpr;
1092 return HASHWALK_ABORT;
1093 }
1094 return HASHWALK_CONTINUE;
1095}
1096
7929821a
PG
1097static void zebra_pbr_show_iptable_unit(struct zebra_pbr_iptable *iptable,
1098 struct vty *vty,
1099 struct zebra_ns *zns)
586f4ccf 1100{
73a829f7
PG
1101 int ret;
1102 uint64_t pkts = 0, bytes = 0;
586f4ccf
PG
1103
1104 vty_out(vty, "IPtable %s action %s (%u)\n", iptable->ipset_name,
1105 iptable->action == ZEBRA_IPTABLES_DROP ? "drop" : "redirect",
1106 iptable->unique);
0b328d3f
PG
1107 if (iptable->type == IPSET_NET_PORT ||
1108 iptable->type == IPSET_NET_PORT_NET) {
1109 if (!(iptable->filter_bm & MATCH_ICMP_SET)) {
1110 if (iptable->filter_bm & PBR_FILTER_DST_PORT)
1111 vty_out(vty, "\t lookup dst port\n");
1112 else if (iptable->filter_bm & PBR_FILTER_SRC_PORT)
1113 vty_out(vty, "\t lookup src port\n");
1114 }
1115 }
e7f7dad4
PG
1116 if (iptable->pkt_len_min || iptable->pkt_len_max) {
1117 if (!iptable->pkt_len_max)
1118 vty_out(vty, "\t pkt len %u\n",
1119 iptable->pkt_len_min);
1120 else
1121 vty_out(vty, "\t pkt len [%u;%u]\n",
1122 iptable->pkt_len_min,
1123 iptable->pkt_len_max);
1124 }
dc993e76
PG
1125 if (iptable->tcp_flags || iptable->tcp_mask_flags) {
1126 char tcp_flag_str[64];
1127 char tcp_flag_mask_str[64];
1128
1129 zebra_pbr_tcpflags_snprintf(tcp_flag_str,
1130 sizeof(tcp_flag_str),
1131 iptable->tcp_flags);
1132 zebra_pbr_tcpflags_snprintf(tcp_flag_mask_str,
1133 sizeof(tcp_flag_mask_str),
1134 iptable->tcp_mask_flags);
1135 vty_out(vty, "\t tcpflags [%s/%s]\n",
1136 tcp_flag_str, tcp_flag_mask_str);
1137 }
69214c57
PG
1138 if (iptable->filter_bm & (MATCH_DSCP_SET | MATCH_DSCP_INVERSE_SET)) {
1139 vty_out(vty, "\t dscp %s %d\n",
1140 iptable->filter_bm & MATCH_DSCP_INVERSE_SET ?
1141 "not" : "", iptable->dscp_value);
1142 }
5ac5b7cc
PG
1143 if (iptable->fragment) {
1144 char val_str[10];
1145
772270f3 1146 snprintf(val_str, sizeof(val_str), "%d", iptable->fragment);
5ac5b7cc
PG
1147 vty_out(vty, "\t fragment%s %s\n",
1148 iptable->filter_bm & MATCH_FRAGMENT_INVERSE_SET ?
1149 " not" : "", lookup_msg(fragment_value_str,
1150 iptable->fragment, val_str));
1151 }
f449d223
PG
1152 if (iptable->protocol) {
1153 vty_out(vty, "\t protocol %d\n",
1154 iptable->protocol);
1155 }
1c6fca1f 1156 ret = hook_call(zebra_pbr_iptable_get_stat, iptable, &pkts,
62f20a52 1157 &bytes);
73a829f7
PG
1158 if (ret && pkts > 0)
1159 vty_out(vty, "\t pkts %" PRIu64 ", bytes %" PRIu64"\n",
1160 pkts, bytes);
586f4ccf
PG
1161 if (iptable->action != ZEBRA_IPTABLES_DROP) {
1162 struct pbr_rule_fwmark_lookup prfl;
1163
1164 prfl.fwmark = iptable->fwmark;
1165 prfl.ptr = NULL;
7f0ea8a4 1166 hash_walk(zrouter.rules_hash,
586f4ccf
PG
1167 &zebra_pbr_rule_lookup_fwmark_walkcb, &prfl);
1168 if (prfl.ptr) {
1169 struct zebra_pbr_rule *zpr = prfl.ptr;
1170
1171 vty_out(vty, "\t table %u, fwmark %u\n",
1172 zpr->rule.action.table,
1173 prfl.fwmark);
1174 }
1175 }
7929821a
PG
1176}
1177
e3b78da8 1178static int zebra_pbr_show_iptable_walkcb(struct hash_bucket *bucket, void *arg)
7929821a
PG
1179{
1180 struct zebra_pbr_iptable *iptable =
e3b78da8 1181 (struct zebra_pbr_iptable *)bucket->data;
7929821a
PG
1182 struct zebra_pbr_env_display *env = (struct zebra_pbr_env_display *)arg;
1183 struct vty *vty = env->vty;
1184 struct zebra_ns *zns = env->zns;
1185 char *iptable_name = env->name;
1186
1187 if (!iptable_name)
1188 zebra_pbr_show_iptable_unit(iptable, vty, zns);
1189 else if (!strncmp(iptable_name,
1190 iptable->ipset_name,
1191 ZEBRA_IPSET_NAME_SIZE))
1192 zebra_pbr_show_iptable_unit(iptable, vty, zns);
586f4ccf
PG
1193 return HASHWALK_CONTINUE;
1194}
1195
7929821a 1196void zebra_pbr_show_iptable(struct vty *vty, char *iptable_name)
586f4ccf
PG
1197{
1198 struct zebra_ns *zns = zebra_ns_lookup(NS_DEFAULT);
1199 struct zebra_pbr_env_display env;
1200
1201 env.vty = vty;
1202 env.zns = zns;
7929821a 1203 env.name = iptable_name;
62f20a52 1204 hash_walk(zrouter.iptable_hash, zebra_pbr_show_iptable_walkcb, &env);
586f4ccf 1205}
f80ec7e3
PG
1206
1207void zebra_pbr_iptable_update_interfacelist(struct stream *s,
1208 struct zebra_pbr_iptable *zpi)
1209{
1210 uint32_t i = 0, index;
1211 struct interface *ifp;
1212 char *name;
1213
1214 for (i = 0; i < zpi->nb_interface; i++) {
1215 STREAM_GETL(s, index);
1216 ifp = if_lookup_by_index(index, zpi->vrf_id);
1217 if (!ifp)
1218 continue;
1219 name = XSTRDUP(MTYPE_PBR_IPTABLE_IFNAME, ifp->name);
1220 listnode_add(zpi->interface_name_list, name);
1221 }
1222stream_failure:
1223 return;
1224}