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