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