]> git.proxmox.com Git - mirror_frr.git/blame - zebra/zebra_pbr.c
Merge pull request #12665 from opensourcerouting/cs-misc
[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"
59f47eb0 35#include "zebra/zebra_neigh.h"
f80ec7e3
PG
36
37/* definitions */
bf8d3d6a 38DEFINE_MTYPE_STATIC(ZEBRA, PBR_IPTABLE_IFNAME, "PBR interface list");
c0ce4875 39DEFINE_MTYPE(ZEBRA, PBR_OBJ, "PBR");
942bf97b 40
41/* definitions */
586f4ccf
PG
42static const struct message ipset_type_msg[] = {
43 {IPSET_NET_PORT_NET, "net,port,net"},
44 {IPSET_NET_PORT, "net,port"},
45 {IPSET_NET_NET, "net,net"},
46 {IPSET_NET, "net"},
47 {0}
48};
942bf97b 49
be729dd7
PG
50const struct message icmp_typecode_str[] = {
51 { 0 << 8, "echo-reply"},
52 { 0 << 8, "pong"},
53 { 3 << 8, "network-unreachable"},
54 { (3 << 8) + 1, "host-unreachable"},
55 { (3 << 8) + 2, "protocol-unreachable"},
56 { (3 << 8) + 3, "port-unreachable"},
57 { (3 << 8) + 4, "fragmentation-needed"},
58 { (3 << 8) + 5, "source-route-failed"},
59 { (3 << 8) + 6, "network-unknown"},
60 { (3 << 8) + 7, "host-unknown"},
61 { (3 << 8) + 9, "network-prohibited"},
62 { (3 << 8) + 10, "host-prohibited"},
63 { (3 << 8) + 11, "TOS-network-unreachable"},
64 { (3 << 8) + 12, "TOS-host-unreachable"},
65 { (3 << 8) + 13, "communication-prohibited"},
66 { (3 << 8) + 14, "host-precedence-violation"},
67 { (3 << 8) + 15, "precedence-cutoff"},
68 { 4 << 8, "source-quench"},
69 { 5 << 8, "network-redirect"},
70 { (5 << 8) + 1, "host-redirect"},
71 { (5 << 8) + 2, "TOS-network-redirect"},
72 { (5 << 8) + 3, "TOS-host-redirect"},
73 { 8 << 8, "echo-request"},
74 { 8 << 8, "ping"},
75 { 9 << 8, "router-advertisement"},
76 { 10 << 8, "router-solicitation"},
77 { 11 << 8, "ttl-zero-during-transit"},
78 { (11 << 8) + 1, "ttl-zero-during-reassembly"},
79 { 12 << 8, "ip-header-bad"},
80 { (12 << 8) + 1, "required-option-missing"},
81 { 13 << 8, "timestamp-request"},
82 { 14 << 8, "timestamp-reply"},
83 { 17 << 8, "address-mask-request"},
84 { 18 << 8, "address-mask-reply"},
85 {0}
86};
87
c9b1139a
PG
88const struct message icmpv6_typecode_str[] = {
89 { 128 << 8, "echo-request"},
90 { 129 << 8, "echo-reply"},
91 { 1 << 8, "no-route"},
92 { (1 << 8) + 1, "communication-prohibited"},
93 { (1 << 8) + 3, "address-unreachable"},
94 { (1 << 8) + 4, "port-unreachable"},
95 { (2 << 8), "packet-too-big"},
96 { 3 << 0, "ttl-zero-during-transit"},
97 { (3 << 8) + 1, "ttl-zero-during-reassembly"},
98 { 4 << 0, "bad-header"},
99 { (4 << 0) + 1, "unknown-header-type"},
100 { (4 << 0) + 2, "unknown-option"},
101 { 133 << 8, "router-solicitation"},
102 { 134 << 8, "router-advertisement"},
103 { 135 << 8, "neighbor-solicitation"},
104 { 136 << 8, "neighbor-advertisement"},
105 { 137 << 8, "redirect"},
106 {0}
107};
108
dc993e76
PG
109/* definitions */
110static const struct message tcp_value_str[] = {
111 {TCP_HEADER_FIN, "FIN"},
112 {TCP_HEADER_SYN, "SYN"},
113 {TCP_HEADER_RST, "RST"},
114 {TCP_HEADER_PSH, "PSH"},
115 {TCP_HEADER_ACK, "ACK"},
116 {TCP_HEADER_URG, "URG"},
117 {0}
118};
119
5ac5b7cc
PG
120static const struct message fragment_value_str[] = {
121 {1, "dont-fragment"},
122 {2, "is-fragment"},
123 {4, "first-fragment"},
124 {8, "last-fragment"},
125 {0}
126};
127
59f47eb0
AK
128struct zebra_pbr_env_display {
129 struct zebra_ns *zns;
130 struct vty *vty;
131 char *name;
132};
133
942bf97b 134/* static function declarations */
1c6fca1f 135DEFINE_HOOK(zebra_pbr_ipset_entry_get_stat,
62f20a52
DS
136 (struct zebra_pbr_ipset_entry *ipset, uint64_t *pkts,
137 uint64_t *bytes),
8451921b 138 (ipset, pkts, bytes));
62f20a52 139
1c6fca1f 140DEFINE_HOOK(zebra_pbr_iptable_get_stat,
62f20a52
DS
141 (struct zebra_pbr_iptable *iptable, uint64_t *pkts,
142 uint64_t *bytes),
8451921b 143 (iptable, pkts, bytes));
62f20a52 144
1c6fca1f 145DEFINE_HOOK(zebra_pbr_iptable_update,
62f20a52
DS
146 (int cmd, struct zebra_pbr_iptable *iptable), (cmd, iptable));
147
1c6fca1f 148DEFINE_HOOK(zebra_pbr_ipset_entry_update,
62f20a52
DS
149 (int cmd, struct zebra_pbr_ipset_entry *ipset), (cmd, ipset));
150
1c6fca1f 151DEFINE_HOOK(zebra_pbr_ipset_update,
62f20a52 152 (int cmd, struct zebra_pbr_ipset *ipset), (cmd, ipset));
942bf97b 153
59f47eb0
AK
154/* resolve nexthop for dataplane (dpdk) programming */
155static bool zebra_pbr_expand_action;
156
942bf97b 157/* Private functions */
158
159/* Public functions */
43fe6a2a 160void zebra_pbr_rules_free(void *arg)
1fbfe5a5 161{
43fe6a2a
DS
162 struct zebra_pbr_rule *rule;
163
164 rule = (struct zebra_pbr_rule *)arg;
165
f62e5480 166 (void)dplane_pbr_rule_delete(rule);
c0ce4875 167 XFREE(MTYPE_PBR_OBJ, rule);
43fe6a2a
DS
168}
169
d8b87afe 170uint32_t zebra_pbr_rules_hash_key(const void *arg)
43fe6a2a 171{
d8b87afe 172 const struct zebra_pbr_rule *rule;
43fe6a2a
DS
173 uint32_t key;
174
d8b87afe 175 rule = arg;
5dd0722d
PG
176 key = jhash_3words(rule->rule.seq, rule->rule.priority,
177 rule->rule.action.table,
178 prefix_hash_key(&rule->rule.filter.src_ip));
a0321978 179
b94683f0
DS
180 key = jhash_3words(rule->rule.filter.fwmark, rule->vrf_id,
181 rule->rule.filter.ip_proto, key);
58a1d249
DS
182
183 key = jhash(rule->ifname, strlen(rule->ifname), key);
7f0ea8a4 184
5dd0722d
PG
185 return jhash_3words(rule->rule.filter.src_port,
186 rule->rule.filter.dst_port,
187 prefix_hash_key(&rule->rule.filter.dst_ip),
188 jhash_1word(rule->rule.unique, key));
43fe6a2a
DS
189}
190
74df8d6d 191bool zebra_pbr_rules_hash_equal(const void *arg1, const void *arg2)
43fe6a2a
DS
192{
193 const struct zebra_pbr_rule *r1, *r2;
194
195 r1 = (const struct zebra_pbr_rule *)arg1;
196 r2 = (const struct zebra_pbr_rule *)arg2;
197
5dd0722d 198 if (r1->rule.seq != r2->rule.seq)
74df8d6d 199 return false;
43fe6a2a 200
5dd0722d 201 if (r1->rule.priority != r2->rule.priority)
74df8d6d 202 return false;
43fe6a2a 203
5dd0722d 204 if (r1->rule.unique != r2->rule.unique)
74df8d6d 205 return false;
b6c5d343 206
5dd0722d 207 if (r1->rule.action.table != r2->rule.action.table)
74df8d6d 208 return false;
43fe6a2a 209
5dd0722d 210 if (r1->rule.filter.src_port != r2->rule.filter.src_port)
74df8d6d 211 return false;
43fe6a2a 212
5dd0722d 213 if (r1->rule.filter.dst_port != r2->rule.filter.dst_port)
74df8d6d 214 return false;
43fe6a2a 215
5dd0722d 216 if (r1->rule.filter.fwmark != r2->rule.filter.fwmark)
74df8d6d 217 return false;
b94683f0
DS
218
219 if (r1->rule.filter.ip_proto != r2->rule.filter.ip_proto)
220 return false;
1907e4b8 221
5dd0722d 222 if (!prefix_same(&r1->rule.filter.src_ip, &r2->rule.filter.src_ip))
74df8d6d 223 return false;
43fe6a2a 224
5dd0722d 225 if (!prefix_same(&r1->rule.filter.dst_ip, &r2->rule.filter.dst_ip))
74df8d6d 226 return false;
43fe6a2a 227
58a1d249 228 if (strcmp(r1->rule.ifname, r2->rule.ifname) != 0)
74df8d6d 229 return false;
a0321978 230
7f0ea8a4
DS
231 if (r1->vrf_id != r2->vrf_id)
232 return false;
233
74df8d6d 234 return true;
43fe6a2a
DS
235}
236
f46bbab4 237struct pbr_rule_unique_lookup {
8c3cd6c6
DS
238 struct zebra_pbr_rule *rule;
239 uint32_t unique;
58a1d249 240 char ifname[INTERFACE_NAMSIZ + 1];
7f0ea8a4 241 vrf_id_t vrf_id;
8c3cd6c6
DS
242};
243
e3b78da8 244static int pbr_rule_lookup_unique_walker(struct hash_bucket *b, void *data)
8c3cd6c6 245{
f46bbab4 246 struct pbr_rule_unique_lookup *pul = data;
8c3cd6c6
DS
247 struct zebra_pbr_rule *rule = b->data;
248
7f0ea8a4 249 if (pul->unique == rule->rule.unique
58a1d249 250 && strncmp(pul->ifname, rule->rule.ifname, INTERFACE_NAMSIZ) == 0
7f0ea8a4 251 && pul->vrf_id == rule->vrf_id) {
8c3cd6c6
DS
252 pul->rule = rule;
253 return HASHWALK_ABORT;
254 }
255
256 return HASHWALK_CONTINUE;
257}
258
62f20a52
DS
259static struct zebra_pbr_rule *
260pbr_rule_lookup_unique(struct zebra_pbr_rule *zrule)
8c3cd6c6 261{
f46bbab4 262 struct pbr_rule_unique_lookup pul;
8c3cd6c6 263
7f0ea8a4 264 pul.unique = zrule->rule.unique;
58a1d249 265 strlcpy(pul.ifname, zrule->rule.ifname, INTERFACE_NAMSIZ);
8c3cd6c6 266 pul.rule = NULL;
7f0ea8a4
DS
267 pul.vrf_id = zrule->vrf_id;
268 hash_walk(zrouter.rules_hash, &pbr_rule_lookup_unique_walker, &pul);
8c3cd6c6
DS
269
270 return pul.rule;
271}
272
7661461a
PG
273void zebra_pbr_ipset_free(void *arg)
274{
275 struct zebra_pbr_ipset *ipset;
276
277 ipset = (struct zebra_pbr_ipset *)arg;
1c6fca1f 278 hook_call(zebra_pbr_ipset_update, 0, ipset);
c0ce4875 279 XFREE(MTYPE_PBR_OBJ, ipset);
7661461a
PG
280}
281
d8b87afe 282uint32_t zebra_pbr_ipset_hash_key(const void *arg)
7661461a 283{
d8b87afe 284 const struct zebra_pbr_ipset *ipset = arg;
425bdd6b 285 uint32_t *pnt = (uint32_t *)&ipset->ipset_name;
62f20a52 286 uint32_t key = jhash_1word(ipset->vrf_id, 0x63ab42de);
7661461a 287
a60b7031
PG
288 key = jhash_1word(ipset->family, key);
289
62f20a52 290 return jhash2(pnt, ZEBRA_IPSET_NAME_HASH_SIZE, key);
7661461a
PG
291}
292
74df8d6d 293bool zebra_pbr_ipset_hash_equal(const void *arg1, const void *arg2)
7661461a
PG
294{
295 const struct zebra_pbr_ipset *r1, *r2;
296
297 r1 = (const struct zebra_pbr_ipset *)arg1;
298 r2 = (const struct zebra_pbr_ipset *)arg2;
299
300 if (r1->type != r2->type)
74df8d6d 301 return false;
7661461a 302 if (r1->unique != r2->unique)
74df8d6d 303 return false;
62f20a52
DS
304 if (r1->vrf_id != r2->vrf_id)
305 return false;
a60b7031
PG
306 if (r1->family != r2->family)
307 return false;
62f20a52 308
7661461a
PG
309 if (strncmp(r1->ipset_name, r2->ipset_name,
310 ZEBRA_IPSET_NAME_SIZE))
74df8d6d
DS
311 return false;
312 return true;
7661461a
PG
313}
314
315void zebra_pbr_ipset_entry_free(void *arg)
316{
317 struct zebra_pbr_ipset_entry *ipset;
318
319 ipset = (struct zebra_pbr_ipset_entry *)arg;
73a829f7 320
1c6fca1f 321 hook_call(zebra_pbr_ipset_entry_update, 0, ipset);
7661461a 322
c0ce4875 323 XFREE(MTYPE_PBR_OBJ, ipset);
7661461a
PG
324}
325
d8b87afe 326uint32_t zebra_pbr_ipset_entry_hash_key(const void *arg)
7661461a 327{
d8b87afe 328 const struct zebra_pbr_ipset_entry *ipset;
7661461a
PG
329 uint32_t key;
330
d8b87afe 331 ipset = arg;
7661461a
PG
332 key = prefix_hash_key(&ipset->src);
333 key = jhash_1word(ipset->unique, key);
334 key = jhash_1word(prefix_hash_key(&ipset->dst), key);
25d760c5
PG
335 key = jhash(&ipset->dst_port_min, 2, key);
336 key = jhash(&ipset->dst_port_max, 2, key);
337 key = jhash(&ipset->src_port_min, 2, key);
338 key = jhash(&ipset->src_port_max, 2, key);
339 key = jhash(&ipset->proto, 1, key);
7661461a
PG
340
341 return key;
342}
343
74df8d6d 344bool zebra_pbr_ipset_entry_hash_equal(const void *arg1, const void *arg2)
7661461a
PG
345{
346 const struct zebra_pbr_ipset_entry *r1, *r2;
347
348 r1 = (const struct zebra_pbr_ipset_entry *)arg1;
349 r2 = (const struct zebra_pbr_ipset_entry *)arg2;
350
351 if (r1->unique != r2->unique)
74df8d6d 352 return false;
7661461a
PG
353
354 if (!prefix_same(&r1->src, &r2->src))
74df8d6d 355 return false;
7661461a
PG
356
357 if (!prefix_same(&r1->dst, &r2->dst))
74df8d6d 358 return false;
7661461a 359
25d760c5 360 if (r1->src_port_min != r2->src_port_min)
74df8d6d 361 return false;
25d760c5
PG
362
363 if (r1->src_port_max != r2->src_port_max)
74df8d6d 364 return false;
25d760c5
PG
365
366 if (r1->dst_port_min != r2->dst_port_min)
74df8d6d 367 return false;
25d760c5
PG
368
369 if (r1->dst_port_max != r2->dst_port_max)
74df8d6d 370 return false;
25d760c5
PG
371
372 if (r1->proto != r2->proto)
74df8d6d
DS
373 return false;
374 return true;
7661461a
PG
375}
376
3b1de7b8
PG
377/* this function gives option to flush plugin memory contexts
378 * with all parameter. set it to true to flush all
379 * set it to false to flush only passed arg argument
380 */
381static void _zebra_pbr_iptable_free_all(void *arg, bool all)
7abd6c4f
PG
382{
383 struct zebra_pbr_iptable *iptable;
f80ec7e3
PG
384 struct listnode *node, *nnode;
385 char *name;
7abd6c4f
PG
386
387 iptable = (struct zebra_pbr_iptable *)arg;
3b1de7b8
PG
388
389 if (all)
390 hook_call(zebra_pbr_iptable_update, 0, iptable);
7abd6c4f 391
8b5c4dce
QY
392 if (iptable->interface_name_list) {
393 for (ALL_LIST_ELEMENTS(iptable->interface_name_list, node,
394 nnode, name)) {
395 XFREE(MTYPE_PBR_IPTABLE_IFNAME, name);
396 list_delete_node(iptable->interface_name_list, node);
397 }
398 list_delete(&iptable->interface_name_list);
f80ec7e3 399 }
c0ce4875 400 XFREE(MTYPE_PBR_OBJ, iptable);
7abd6c4f
PG
401}
402
3b1de7b8
PG
403void zebra_pbr_iptable_free(void *arg)
404{
405 _zebra_pbr_iptable_free_all(arg, false);
406}
407
d8b87afe 408uint32_t zebra_pbr_iptable_hash_key(const void *arg)
7abd6c4f 409{
d8b87afe 410 const struct zebra_pbr_iptable *iptable = arg;
7abd6c4f
PG
411 uint32_t *pnt = (uint32_t *)&(iptable->ipset_name);
412 uint32_t key;
413
414 key = jhash2(pnt, ZEBRA_IPSET_NAME_HASH_SIZE,
415 0x63ab42de);
416 key = jhash_1word(iptable->fwmark, key);
a60b7031
PG
417 key = jhash_1word(iptable->family, key);
418 key = jhash_1word(iptable->flow_label, key);
e7f7dad4
PG
419 key = jhash_1word(iptable->pkt_len_min, key);
420 key = jhash_1word(iptable->pkt_len_max, key);
dc993e76
PG
421 key = jhash_1word(iptable->tcp_flags, key);
422 key = jhash_1word(iptable->tcp_mask_flags, key);
4977bd6c 423 key = jhash_1word(iptable->dscp_value, key);
f449d223 424 key = jhash_1word(iptable->protocol, key);
5ac5b7cc 425 key = jhash_1word(iptable->fragment, key);
62f20a52
DS
426 key = jhash_1word(iptable->vrf_id, key);
427
7abd6c4f
PG
428 return jhash_3words(iptable->filter_bm, iptable->type,
429 iptable->unique, key);
430}
431
74df8d6d 432bool zebra_pbr_iptable_hash_equal(const void *arg1, const void *arg2)
7abd6c4f
PG
433{
434 const struct zebra_pbr_iptable *r1, *r2;
435
436 r1 = (const struct zebra_pbr_iptable *)arg1;
437 r2 = (const struct zebra_pbr_iptable *)arg2;
438
62f20a52 439 if (r1->vrf_id != r2->vrf_id)
b08047f8 440 return false;
7abd6c4f 441 if (r1->type != r2->type)
74df8d6d 442 return false;
7abd6c4f 443 if (r1->unique != r2->unique)
74df8d6d 444 return false;
7abd6c4f 445 if (r1->filter_bm != r2->filter_bm)
74df8d6d 446 return false;
7abd6c4f 447 if (r1->fwmark != r2->fwmark)
74df8d6d 448 return false;
7abd6c4f 449 if (r1->action != r2->action)
74df8d6d 450 return false;
7abd6c4f
PG
451 if (strncmp(r1->ipset_name, r2->ipset_name,
452 ZEBRA_IPSET_NAME_SIZE))
74df8d6d 453 return false;
a60b7031
PG
454 if (r1->family != r2->family)
455 return false;
456 if (r1->flow_label != r2->flow_label)
457 return false;
e7f7dad4 458 if (r1->pkt_len_min != r2->pkt_len_min)
74df8d6d 459 return false;
e7f7dad4 460 if (r1->pkt_len_max != r2->pkt_len_max)
74df8d6d 461 return false;
dc993e76 462 if (r1->tcp_flags != r2->tcp_flags)
74df8d6d 463 return false;
dc993e76 464 if (r1->tcp_mask_flags != r2->tcp_mask_flags)
74df8d6d 465 return false;
4977bd6c 466 if (r1->dscp_value != r2->dscp_value)
74df8d6d 467 return false;
5ac5b7cc 468 if (r1->fragment != r2->fragment)
74df8d6d 469 return false;
f449d223
PG
470 if (r1->protocol != r2->protocol)
471 return false;
74df8d6d 472 return true;
7abd6c4f
PG
473}
474
43fe6a2a
DS
475static void *pbr_rule_alloc_intern(void *arg)
476{
477 struct zebra_pbr_rule *zpr;
478 struct zebra_pbr_rule *new;
479
480 zpr = (struct zebra_pbr_rule *)arg;
481
c0ce4875 482 new = XCALLOC(MTYPE_PBR_OBJ, sizeof(*new));
43fe6a2a
DS
483
484 memcpy(new, zpr, sizeof(*zpr));
485
486 return new;
487}
488
59f47eb0
AK
489static struct zebra_pbr_rule *pbr_rule_free(struct zebra_pbr_rule *hash_data,
490 bool free_data)
491{
492 if (hash_data->action.neigh)
493 zebra_neigh_deref(hash_data);
494 hash_release(zrouter.rules_hash, hash_data);
495 if (free_data) {
c0ce4875 496 XFREE(MTYPE_PBR_OBJ, hash_data);
59f47eb0
AK
497 return NULL;
498 }
499
500 return hash_data;
501}
502
503static struct zebra_pbr_rule *pbr_rule_release(struct zebra_pbr_rule *rule,
504 bool free_data)
3ae327cb
SW
505{
506 struct zebra_pbr_rule *lookup;
507
508 lookup = hash_lookup(zrouter.rules_hash, rule);
509
510 if (!lookup)
59f47eb0 511 return NULL;
3ae327cb 512
59f47eb0
AK
513 return pbr_rule_free(lookup, free_data);
514}
3ae327cb 515
59f47eb0
AK
516void zebra_pbr_show_rule_unit(struct zebra_pbr_rule *rule, struct vty *vty)
517{
518 struct pbr_rule *prule = &rule->rule;
519 struct zebra_pbr_action *zaction = &rule->action;
520
521 vty_out(vty, "Rules if %s\n", rule->ifname);
522 vty_out(vty, " Seq %u pri %u\n", prule->seq, prule->priority);
523 if (prule->filter.filter_bm & PBR_FILTER_SRC_IP)
524 vty_out(vty, " SRC IP Match: %pFX\n", &prule->filter.src_ip);
525 if (prule->filter.filter_bm & PBR_FILTER_DST_IP)
526 vty_out(vty, " DST IP Match: %pFX\n", &prule->filter.dst_ip);
527 if (prule->filter.filter_bm & PBR_FILTER_IP_PROTOCOL)
528 vty_out(vty, " IP protocol Match: %u\n",
529 prule->filter.ip_proto);
530 if (prule->filter.filter_bm & PBR_FILTER_SRC_PORT)
531 vty_out(vty, " SRC Port Match: %u\n", prule->filter.src_port);
532 if (prule->filter.filter_bm & PBR_FILTER_DST_PORT)
533 vty_out(vty, " DST Port Match: %u\n", prule->filter.dst_port);
534
535 if (prule->filter.filter_bm & PBR_FILTER_DSFIELD) {
536 vty_out(vty, " DSCP Match: %u\n",
537 (prule->filter.dsfield & PBR_DSFIELD_DSCP) >> 2);
538 vty_out(vty, " ECN Match: %u\n",
539 prule->filter.dsfield & PBR_DSFIELD_ECN);
540 }
541
542 if (prule->filter.filter_bm & PBR_FILTER_FWMARK)
543 vty_out(vty, " MARK Match: %u\n", prule->filter.fwmark);
544
545 vty_out(vty, " Tableid: %u\n", prule->action.table);
546 if (zaction->afi == AFI_IP)
547 vty_out(vty, " Action: nh: %pI4 intf: %s\n",
548 &zaction->gate.ipv4,
549 ifindex2ifname(zaction->ifindex, rule->vrf_id));
550 if (zaction->afi == AFI_IP6)
551 vty_out(vty, " Action: nh: %pI6 intf: %s\n",
552 &zaction->gate.ipv6,
553 ifindex2ifname(zaction->ifindex, rule->vrf_id));
554 if (zaction->neigh && (zaction->neigh->flags & ZEBRA_NEIGH_ENT_ACTIVE))
555 vty_out(vty, " Action: mac: %pEA\n", &zaction->neigh->mac);
556}
557
558static int zebra_pbr_show_rules_walkcb(struct hash_bucket *bucket, void *arg)
559{
560 struct zebra_pbr_rule *rule = (struct zebra_pbr_rule *)bucket->data;
561 struct zebra_pbr_env_display *env = (struct zebra_pbr_env_display *)arg;
562 struct vty *vty = env->vty;
563
564 zebra_pbr_show_rule_unit(rule, vty);
565
566 return HASHWALK_CONTINUE;
567}
568
569void zebra_pbr_show_rule(struct vty *vty)
570{
571 struct zebra_pbr_env_display env;
572
573 env.vty = vty;
574 hash_walk(zrouter.rules_hash, zebra_pbr_show_rules_walkcb, &env);
575}
576
577void zebra_pbr_config_write(struct vty *vty)
578{
579 if (zebra_pbr_expand_action)
580 vty_out(vty, "pbr nexthop-resolve\n");
581}
582
583void zebra_pbr_expand_action_update(bool enable)
584{
585 zebra_pbr_expand_action = enable;
586}
587
588static void zebra_pbr_expand_rule(struct zebra_pbr_rule *rule)
589{
590 struct prefix p;
591 struct route_table *table;
592 struct route_node *rn;
593 rib_dest_t *dest;
594 struct route_entry *re;
595 const struct nexthop_group *nhg;
596 const struct nexthop *nexthop;
597 struct zebra_pbr_action *action = &rule->action;
598 struct ipaddr ip;
599
600 if (!zebra_pbr_expand_action)
601 return;
602
603 table = zebra_vrf_get_table_with_table_id(
604 AFI_IP, SAFI_UNICAST, VRF_DEFAULT, rule->rule.action.table);
605 if (!table)
606 return;
607
608 memset(&p, 0, sizeof(p));
609 p.family = AF_INET;
610
611 rn = route_node_lookup(table, &p);
612 if (!rn)
613 return;
614
615 dest = rib_dest_from_rnode(rn);
616 re = dest->selected_fib;
617 if (!re) {
618 route_unlock_node(rn);
619 return;
620 }
621
622 nhg = rib_get_fib_nhg(re);
623 if (!nhg) {
624 route_unlock_node(rn);
625 return;
626 }
627
628 nexthop = nhg->nexthop;
629 if (nexthop) {
630 switch (nexthop->type) {
631 case NEXTHOP_TYPE_IPV4:
632 case NEXTHOP_TYPE_IPV4_IFINDEX:
633 action->afi = AFI_IP;
634 action->gate.ipv4 = nexthop->gate.ipv4;
635 action->ifindex = nexthop->ifindex;
636 ip.ipa_type = AF_INET;
637 ip.ipaddr_v4 = action->gate.ipv4;
638 zebra_neigh_ref(action->ifindex, &ip, rule);
639 break;
640
641 case NEXTHOP_TYPE_IPV6:
642 case NEXTHOP_TYPE_IPV6_IFINDEX:
643 action->afi = AFI_IP6;
644 action->gate.ipv6 = nexthop->gate.ipv6;
645 action->ifindex = nexthop->ifindex;
646 ip.ipa_type = AF_INET6;
647 ip.ipaddr_v6 = action->gate.ipv6;
648 zebra_neigh_ref(action->ifindex, &ip, rule);
649 break;
650
651 default:
652 action->afi = AFI_UNSPEC;
653 }
654 }
655
656 route_unlock_node(rn);
3ae327cb
SW
657}
658
7f0ea8a4 659void zebra_pbr_add_rule(struct zebra_pbr_rule *rule)
43fe6a2a 660{
3ae327cb 661 struct zebra_pbr_rule *found;
59f47eb0
AK
662 struct zebra_pbr_rule *old;
663 struct zebra_pbr_rule *new;
8c3cd6c6 664
3ae327cb
SW
665 /**
666 * Check if we already have it (this checks via a unique ID, walking
667 * over the hash table, not via a hash operation).
8c3cd6c6 668 */
3ae327cb
SW
669 found = pbr_rule_lookup_unique(rule);
670
3ae327cb
SW
671 /* If found, this is an update */
672 if (found) {
8eeca5a2
SW
673 if (IS_ZEBRA_DEBUG_PBR)
674 zlog_debug(
675 "%s: seq: %d, prior: %d, unique: %d, ifname: %s -- update",
676 __func__, rule->rule.seq, rule->rule.priority,
677 rule->rule.unique, rule->rule.ifname);
678
59f47eb0
AK
679 /* remove the old entry from the hash but don't free the hash
680 * data yet as we need it for the dplane update
681 */
682 old = pbr_rule_release(found, false);
683
684 /* insert new entry into hash */
685 new = hash_get(zrouter.rules_hash, rule, pbr_rule_alloc_intern);
686 /* expand the action if needed */
687 zebra_pbr_expand_rule(new);
688 /* update dataplane */
689 (void)dplane_pbr_rule_update(found, new);
690 /* release the old hash data */
691 if (old)
c0ce4875 692 XFREE(MTYPE_PBR_OBJ, old);
8eeca5a2
SW
693 } else {
694 if (IS_ZEBRA_DEBUG_PBR)
695 zlog_debug(
696 "%s: seq: %d, prior: %d, unique: %d, ifname: %s -- new",
697 __func__, rule->rule.seq, rule->rule.priority,
698 rule->rule.unique, rule->rule.ifname);
699
59f47eb0
AK
700 /* insert new entry into hash */
701 new = hash_get(zrouter.rules_hash, rule, pbr_rule_alloc_intern);
702 /* expand the action if needed */
703 zebra_pbr_expand_rule(new);
704 (void)dplane_pbr_rule_add(new);
8eeca5a2 705 }
f7692085 706
1fbfe5a5
DS
707}
708
7f0ea8a4 709void zebra_pbr_del_rule(struct zebra_pbr_rule *rule)
1fbfe5a5 710{
8eeca5a2
SW
711 if (IS_ZEBRA_DEBUG_PBR)
712 zlog_debug("%s: seq: %d, prior: %d, unique: %d, ifname: %s",
713 __func__, rule->rule.seq, rule->rule.priority,
714 rule->rule.unique, rule->rule.ifname);
715
f62e5480 716 (void)dplane_pbr_rule_delete(rule);
43fe6a2a 717
59f47eb0 718 if (pbr_rule_release(rule, true))
9df414fe 719 zlog_debug("%s: Rule being deleted we know nothing about",
15569c58 720 __func__);
1fbfe5a5
DS
721}
722
5162e000
PG
723void zebra_pbr_process_iptable(struct zebra_dplane_ctx *ctx)
724{
725 int mode, ret = 0;
726 struct zebra_pbr_iptable ipt;
727
728 if (dplane_ctx_get_op(ctx) == DPLANE_OP_IPTABLE_ADD)
729 mode = 1;
730 else
731 mode = 0;
732
8d78e148
DS
733 dplane_ctx_get_pbr_iptable(ctx, &ipt);
734
735 ret = hook_call(zebra_pbr_iptable_update, mode, &ipt);
736 if (ret)
737 dplane_ctx_set_status(ctx, ZEBRA_DPLANE_REQUEST_SUCCESS);
738 else
5162e000
PG
739 dplane_ctx_set_status(ctx, ZEBRA_DPLANE_REQUEST_FAILURE);
740}
741
ef524230
PG
742void zebra_pbr_process_ipset(struct zebra_dplane_ctx *ctx)
743{
744 int mode, ret = 0;
745 struct zebra_pbr_ipset ipset;
746
747 if (dplane_ctx_get_op(ctx) == DPLANE_OP_IPSET_ADD)
748 mode = 1;
749 else
750 mode = 0;
8249f96a
DS
751
752 dplane_ctx_get_pbr_ipset(ctx, &ipset);
753
754 ret = hook_call(zebra_pbr_ipset_update, mode, &ipset);
755 if (ret)
756 dplane_ctx_set_status(ctx, ZEBRA_DPLANE_REQUEST_SUCCESS);
757 else
ef524230
PG
758 dplane_ctx_set_status(ctx, ZEBRA_DPLANE_REQUEST_FAILURE);
759}
760
761void zebra_pbr_process_ipset_entry(struct zebra_dplane_ctx *ctx)
762{
763 int mode, ret = 0;
764 struct zebra_pbr_ipset_entry ipset_entry;
765 struct zebra_pbr_ipset ipset;
766
767 if (dplane_ctx_get_op(ctx) == DPLANE_OP_IPSET_ENTRY_ADD)
768 mode = 1;
769 else
770 mode = 0;
771
f284c132 772 dplane_ctx_get_pbr_ipset_entry(ctx, &ipset_entry);
8249f96a
DS
773 dplane_ctx_get_pbr_ipset(ctx, &ipset);
774
ef524230
PG
775 ipset_entry.backpointer = &ipset;
776
777 ret = hook_call(zebra_pbr_ipset_entry_update, mode, &ipset_entry);
778 if (ret)
779 dplane_ctx_set_status(ctx, ZEBRA_DPLANE_REQUEST_SUCCESS);
780 else
781 dplane_ctx_set_status(ctx, ZEBRA_DPLANE_REQUEST_FAILURE);
782}
783
e3b78da8 784static void zebra_pbr_cleanup_rules(struct hash_bucket *b, void *data)
e69aa084 785{
e69aa084
DS
786 struct zebra_pbr_rule *rule = b->data;
787 int *sock = data;
788
789 if (rule->sock == *sock) {
f62e5480 790 (void)dplane_pbr_rule_delete(rule);
59f47eb0 791 pbr_rule_free(rule, true);
e69aa084
DS
792 }
793}
794
e3b78da8 795static void zebra_pbr_cleanup_ipset(struct hash_bucket *b, void *data)
c2ef5232 796{
c2ef5232
PG
797 struct zebra_pbr_ipset *ipset = b->data;
798 int *sock = data;
799
73a829f7 800 if (ipset->sock == *sock) {
b147e204
QY
801 if (hash_release(zrouter.ipset_hash, ipset))
802 zebra_pbr_ipset_free(ipset);
803 else
804 hook_call(zebra_pbr_ipset_update, 0, ipset);
73a829f7 805 }
c2ef5232
PG
806}
807
e3b78da8 808static void zebra_pbr_cleanup_ipset_entry(struct hash_bucket *b, void *data)
c2ef5232 809{
c2ef5232
PG
810 struct zebra_pbr_ipset_entry *ipset = b->data;
811 int *sock = data;
812
73a829f7 813 if (ipset->sock == *sock) {
b147e204
QY
814 if (hash_release(zrouter.ipset_entry_hash, ipset))
815 zebra_pbr_ipset_entry_free(ipset);
816 else
817 hook_call(zebra_pbr_ipset_entry_update, 0, ipset);
73a829f7 818 }
c2ef5232
PG
819}
820
e3b78da8 821static void zebra_pbr_cleanup_iptable(struct hash_bucket *b, void *data)
c2ef5232 822{
c2ef5232
PG
823 struct zebra_pbr_iptable *iptable = b->data;
824 int *sock = data;
825
73a829f7 826 if (iptable->sock == *sock) {
b147e204 827 if (hash_release(zrouter.iptable_hash, iptable))
3b1de7b8 828 _zebra_pbr_iptable_free_all(iptable, true);
b147e204
QY
829 else
830 hook_call(zebra_pbr_iptable_update, 0, iptable);
73a829f7 831 }
c2ef5232
PG
832}
833
4c0ec639 834static int zebra_pbr_client_close_cleanup(struct zserv *client)
e69aa084 835{
4c0ec639 836 int sock = client->sock;
e69aa084 837
4c0ec639
PG
838 if (!sock)
839 return 0;
7f0ea8a4 840 hash_iterate(zrouter.rules_hash, zebra_pbr_cleanup_rules, &sock);
62f20a52
DS
841 hash_iterate(zrouter.iptable_hash, zebra_pbr_cleanup_iptable, &sock);
842 hash_iterate(zrouter.ipset_entry_hash, zebra_pbr_cleanup_ipset_entry,
843 &sock);
844 hash_iterate(zrouter.ipset_hash, zebra_pbr_cleanup_ipset, &sock);
4c0ec639
PG
845 return 1;
846}
847
848void zebra_pbr_init(void)
849{
c0ea1ae7 850 hook_register(zserv_client_close, zebra_pbr_client_close_cleanup);
e69aa084
DS
851}
852
7661461a
PG
853static void *pbr_ipset_alloc_intern(void *arg)
854{
855 struct zebra_pbr_ipset *zpi;
856 struct zebra_pbr_ipset *new;
857
858 zpi = (struct zebra_pbr_ipset *)arg;
859
c0ce4875 860 new = XCALLOC(MTYPE_PBR_OBJ, sizeof(struct zebra_pbr_ipset));
7661461a
PG
861
862 memcpy(new, zpi, sizeof(*zpi));
863
864 return new;
865}
866
62f20a52 867void zebra_pbr_create_ipset(struct zebra_pbr_ipset *ipset)
7661461a 868{
62f20a52 869 (void)hash_get(zrouter.ipset_hash, ipset, pbr_ipset_alloc_intern);
ef524230 870 (void)dplane_pbr_ipset_add(ipset);
7661461a
PG
871}
872
62f20a52 873void zebra_pbr_destroy_ipset(struct zebra_pbr_ipset *ipset)
7661461a
PG
874{
875 struct zebra_pbr_ipset *lookup;
876
62f20a52 877 lookup = hash_lookup(zrouter.ipset_hash, ipset);
ef524230 878 (void)dplane_pbr_ipset_delete(ipset);
de67547d 879 if (lookup) {
62f20a52 880 hash_release(zrouter.ipset_hash, lookup);
c0ce4875 881 XFREE(MTYPE_PBR_OBJ, lookup);
de67547d 882 } else
9df414fe
QY
883 zlog_debug(
884 "%s: IPSet Entry being deleted we know nothing about",
15569c58 885 __func__);
7661461a
PG
886}
887
ed78b7c8
PG
888struct pbr_ipset_name_lookup {
889 struct zebra_pbr_ipset *ipset;
890 char ipset_name[ZEBRA_IPSET_NAME_SIZE];
891};
892
5b0d92b8 893const char *zebra_pbr_ipset_type2str(uint32_t type)
586f4ccf
PG
894{
895 return lookup_msg(ipset_type_msg, type,
896 "Unrecognized IPset Type");
897}
898
e3b78da8 899static int zebra_pbr_ipset_pername_walkcb(struct hash_bucket *bucket, void *arg)
ed78b7c8
PG
900{
901 struct pbr_ipset_name_lookup *pinl =
902 (struct pbr_ipset_name_lookup *)arg;
e3b78da8 903 struct zebra_pbr_ipset *zpi = (struct zebra_pbr_ipset *)bucket->data;
ed78b7c8
PG
904
905 if (!strncmp(pinl->ipset_name, zpi->ipset_name,
906 ZEBRA_IPSET_NAME_SIZE)) {
907 pinl->ipset = zpi;
908 return HASHWALK_ABORT;
909 }
910 return HASHWALK_CONTINUE;
911}
912
62f20a52 913struct zebra_pbr_ipset *zebra_pbr_lookup_ipset_pername(char *ipsetname)
d59c13af 914{
ed78b7c8
PG
915 struct pbr_ipset_name_lookup pinl;
916 struct pbr_ipset_name_lookup *ptr = &pinl;
917
d59c13af
PG
918 if (!ipsetname)
919 return NULL;
ed78b7c8
PG
920 memset(ptr, 0, sizeof(struct pbr_ipset_name_lookup));
921 snprintf((char *)ptr->ipset_name, ZEBRA_IPSET_NAME_SIZE, "%s",
922 ipsetname);
62f20a52 923 hash_walk(zrouter.ipset_hash, zebra_pbr_ipset_pername_walkcb, ptr);
ed78b7c8 924 return ptr->ipset;
d59c13af
PG
925}
926
7661461a
PG
927static void *pbr_ipset_entry_alloc_intern(void *arg)
928{
929 struct zebra_pbr_ipset_entry *zpi;
930 struct zebra_pbr_ipset_entry *new;
931
932 zpi = (struct zebra_pbr_ipset_entry *)arg;
933
c0ce4875 934 new = XCALLOC(MTYPE_PBR_OBJ, sizeof(struct zebra_pbr_ipset_entry));
7661461a
PG
935
936 memcpy(new, zpi, sizeof(*zpi));
937
938 return new;
939}
940
62f20a52 941void zebra_pbr_add_ipset_entry(struct zebra_pbr_ipset_entry *ipset)
7661461a 942{
62f20a52 943 (void)hash_get(zrouter.ipset_entry_hash, ipset,
7661461a 944 pbr_ipset_entry_alloc_intern);
ef524230 945 (void)dplane_pbr_ipset_entry_add(ipset);
7661461a
PG
946}
947
62f20a52 948void zebra_pbr_del_ipset_entry(struct zebra_pbr_ipset_entry *ipset)
7661461a
PG
949{
950 struct zebra_pbr_ipset_entry *lookup;
951
62f20a52 952 lookup = hash_lookup(zrouter.ipset_entry_hash, ipset);
ef524230 953 (void)dplane_pbr_ipset_entry_delete(ipset);
de67547d 954 if (lookup) {
62f20a52 955 hash_release(zrouter.ipset_entry_hash, lookup);
c0ce4875 956 XFREE(MTYPE_PBR_OBJ, lookup);
de67547d 957 } else
9df414fe 958 zlog_debug("%s: IPSet being deleted we know nothing about",
15569c58 959 __func__);
7661461a
PG
960}
961
7abd6c4f
PG
962static void *pbr_iptable_alloc_intern(void *arg)
963{
964 struct zebra_pbr_iptable *zpi;
965 struct zebra_pbr_iptable *new;
592af4cc
QY
966 struct listnode *ln;
967 char *ifname;
7abd6c4f
PG
968
969 zpi = (struct zebra_pbr_iptable *)arg;
970
c0ce4875 971 new = XCALLOC(MTYPE_PBR_OBJ, sizeof(struct zebra_pbr_iptable));
7abd6c4f 972
592af4cc 973 /* Deep structure copy */
7abd6c4f 974 memcpy(new, zpi, sizeof(*zpi));
592af4cc
QY
975 new->interface_name_list = list_new();
976
977 if (zpi->interface_name_list) {
978 for (ALL_LIST_ELEMENTS_RO(zpi->interface_name_list, ln, ifname))
979 listnode_add(new->interface_name_list,
980 XSTRDUP(MTYPE_PBR_IPTABLE_IFNAME, ifname));
981 }
7abd6c4f
PG
982
983 return new;
984}
985
62f20a52 986void zebra_pbr_add_iptable(struct zebra_pbr_iptable *iptable)
7abd6c4f 987{
c9250e28
PG
988 struct zebra_pbr_iptable *ipt_hash;
989
990 ipt_hash = hash_get(zrouter.iptable_hash, iptable,
991 pbr_iptable_alloc_intern);
992 (void)dplane_pbr_iptable_add(ipt_hash);
7abd6c4f
PG
993}
994
62f20a52 995void zebra_pbr_del_iptable(struct zebra_pbr_iptable *iptable)
7abd6c4f 996{
f80ec7e3 997 struct zebra_pbr_iptable *lookup;
7abd6c4f 998
62f20a52 999 lookup = hash_lookup(zrouter.iptable_hash, iptable);
5162e000 1000 (void)dplane_pbr_iptable_delete(iptable);
f80ec7e3
PG
1001 if (lookup) {
1002 struct listnode *node, *nnode;
1003 char *name;
1004
62f20a52 1005 hash_release(zrouter.iptable_hash, lookup);
f80ec7e3
PG
1006 for (ALL_LIST_ELEMENTS(iptable->interface_name_list,
1007 node, nnode, name)) {
1008 XFREE(MTYPE_PBR_IPTABLE_IFNAME, name);
1009 list_delete_node(iptable->interface_name_list,
1010 node);
1011 }
8b5c4dce 1012 list_delete(&iptable->interface_name_list);
c0ce4875 1013 XFREE(MTYPE_PBR_OBJ, lookup);
f80ec7e3 1014 } else
9df414fe 1015 zlog_debug("%s: IPTable being deleted we know nothing about",
5e81f5dd 1016 __func__);
7abd6c4f
PG
1017}
1018
942bf97b 1019/*
1020 * Handle success or failure of rule (un)install in the kernel.
1021 */
f62e5480
JU
1022void zebra_pbr_dplane_result(struct zebra_dplane_ctx *ctx)
1023{
1024 enum zebra_dplane_result res;
1025 enum dplane_op_e op;
1026
1027 res = dplane_ctx_get_status(ctx);
1028 op = dplane_ctx_get_op(ctx);
1029 if (op == DPLANE_OP_RULE_ADD || op == DPLANE_OP_RULE_UPDATE)
1030 zsend_rule_notify_owner(ctx, res == ZEBRA_DPLANE_REQUEST_SUCCESS
1031 ? ZAPI_RULE_INSTALLED
1032 : ZAPI_RULE_FAIL_INSTALL);
1033 else if (op == DPLANE_OP_RULE_DELETE)
1034 zsend_rule_notify_owner(ctx, res == ZEBRA_DPLANE_REQUEST_SUCCESS
1035 ? ZAPI_RULE_REMOVED
1036 : ZAPI_RULE_FAIL_REMOVE);
5162e000
PG
1037 else if (op == DPLANE_OP_IPTABLE_ADD)
1038 zsend_iptable_notify_owner(ctx,
1039 res == ZEBRA_DPLANE_REQUEST_SUCCESS
1040 ? ZAPI_IPTABLE_INSTALLED
1041 : ZAPI_IPTABLE_FAIL_INSTALL);
1042 else if (op == DPLANE_OP_IPTABLE_DELETE)
1043 zsend_iptable_notify_owner(ctx,
1044 res == ZEBRA_DPLANE_REQUEST_SUCCESS
1045 ? ZAPI_IPTABLE_REMOVED
1046 : ZAPI_IPTABLE_FAIL_REMOVE);
ef524230
PG
1047 else if (op == DPLANE_OP_IPSET_ADD)
1048 zsend_ipset_notify_owner(ctx,
1049 res == ZEBRA_DPLANE_REQUEST_SUCCESS
1050 ? ZAPI_IPSET_INSTALLED
1051 : ZAPI_IPSET_FAIL_INSTALL);
1052 else if (op == DPLANE_OP_IPSET_DELETE)
1053 zsend_ipset_notify_owner(ctx,
1054 res == ZEBRA_DPLANE_REQUEST_SUCCESS
1055 ? ZAPI_IPSET_REMOVED
1056 : ZAPI_IPSET_FAIL_REMOVE);
1057 else if (op == DPLANE_OP_IPSET_ENTRY_ADD)
1058 zsend_ipset_entry_notify_owner(
1059 ctx, res == ZEBRA_DPLANE_REQUEST_SUCCESS
1060 ? ZAPI_IPSET_ENTRY_INSTALLED
1061 : ZAPI_IPSET_ENTRY_FAIL_INSTALL);
1062 else if (op == DPLANE_OP_IPSET_ENTRY_DELETE)
1063 zsend_ipset_entry_notify_owner(
1064 ctx, res == ZEBRA_DPLANE_REQUEST_SUCCESS
1065 ? ZAPI_IPSET_ENTRY_REMOVED
1066 : ZAPI_IPSET_ENTRY_FAIL_REMOVE);
f62e5480
JU
1067 else
1068 flog_err(
1069 EC_ZEBRA_PBR_RULE_UPDATE,
1070 "Context received in pbr rule dplane result handler with incorrect OP code (%u)",
1071 op);
942bf97b 1072}
1073
1074/*
1075 * Handle rule delete notification from kernel.
1076 */
a0321978 1077int kernel_pbr_rule_del(struct zebra_pbr_rule *rule)
942bf97b 1078{
1079 return 0;
1080}
586f4ccf
PG
1081
1082struct zebra_pbr_ipset_entry_unique_display {
1083 struct zebra_pbr_ipset *zpi;
1084 struct vty *vty;
73a829f7 1085 struct zebra_ns *zns;
586f4ccf
PG
1086};
1087
586f4ccf
PG
1088
1089static const char *zebra_pbr_prefix2str(union prefixconstptr pu,
1090 char *str, int size)
1091{
1092 const struct prefix *p = pu.p;
1093 char buf[PREFIX2STR_BUFFER];
1094
936fbaef 1095 if ((p->family == AF_INET && p->prefixlen == IPV4_MAX_BITLEN)
f4d81e55 1096 || (p->family == AF_INET6 && p->prefixlen == IPV6_MAX_BITLEN)) {
586f4ccf
PG
1097 snprintf(str, size, "%s", inet_ntop(p->family, &p->u.prefix,
1098 buf, PREFIX2STR_BUFFER));
1099 return str;
1100 }
1101 return prefix2str(pu, str, size);
1102}
1103
be729dd7
PG
1104static void zebra_pbr_display_icmp(struct vty *vty,
1105 struct zebra_pbr_ipset_entry *zpie)
1106{
1107 char decoded_str[20];
1108 uint16_t port;
c9b1139a
PG
1109 struct zebra_pbr_ipset *zpi;
1110
1111 zpi = zpie->backpointer;
be729dd7
PG
1112
1113 /* range icmp type */
1114 if (zpie->src_port_max || zpie->dst_port_max) {
2b7165e7 1115 vty_out(vty, ":icmp:[type <%u:%u>;code <%u:%u>",
be729dd7
PG
1116 zpie->src_port_min, zpie->src_port_max,
1117 zpie->dst_port_min, zpie->dst_port_max);
1118 } else {
1119 port = ((zpie->src_port_min << 8) & 0xff00) +
1120 (zpie->dst_port_min & 0xff);
1121 memset(decoded_str, 0, sizeof(decoded_str));
2b7165e7 1122 snprintf(decoded_str, sizeof(decoded_str), "%u/%u",
772270f3 1123 zpie->src_port_min, zpie->dst_port_min);
c9b1139a
PG
1124 vty_out(vty, ":%s:%s",
1125 zpi->family == AF_INET6 ? "ipv6-icmp" : "icmp",
1126 lookup_msg(zpi->family == AF_INET6 ?
1127 icmpv6_typecode_str : icmp_typecode_str,
be729dd7
PG
1128 port, decoded_str));
1129 }
1130}
1131
25d760c5
PG
1132static void zebra_pbr_display_port(struct vty *vty, uint32_t filter_bm,
1133 uint16_t port_min, uint16_t port_max,
1134 uint8_t proto)
1135{
1136 if (!(filter_bm & PBR_FILTER_PROTO)) {
1137 if (port_max)
1138 vty_out(vty, ":udp/tcp:%d-%d",
1139 port_min, port_max);
1140 else
1141 vty_out(vty, ":udp/tcp:%d",
1142 port_min);
1143 } else {
1144 if (port_max)
1145 vty_out(vty, ":proto %d:%d-%d",
1146 proto, port_min, port_max);
1147 else
1148 vty_out(vty, ":proto %d:%d",
1149 proto, port_min);
1150 }
1151}
1152
e3b78da8 1153static int zebra_pbr_show_ipset_entry_walkcb(struct hash_bucket *bucket,
586f4ccf
PG
1154 void *arg)
1155{
1156 struct zebra_pbr_ipset_entry_unique_display *unique =
1157 (struct zebra_pbr_ipset_entry_unique_display *)arg;
1158 struct zebra_pbr_ipset *zpi = unique->zpi;
1159 struct vty *vty = unique->vty;
1160 struct zebra_pbr_ipset_entry *zpie =
e3b78da8 1161 (struct zebra_pbr_ipset_entry *)bucket->data;
73a829f7 1162 uint64_t pkts = 0, bytes = 0;
73a829f7 1163 int ret = 0;
586f4ccf
PG
1164
1165 if (zpie->backpointer != zpi)
1166 return HASHWALK_CONTINUE;
1167
25d760c5
PG
1168 if ((zpi->type == IPSET_NET_NET) ||
1169 (zpi->type == IPSET_NET_PORT_NET)) {
586f4ccf
PG
1170 char buf[PREFIX_STRLEN];
1171
1172 zebra_pbr_prefix2str(&(zpie->src), buf, sizeof(buf));
1173 vty_out(vty, "\tfrom %s", buf);
be729dd7
PG
1174 if (zpie->filter_bm & PBR_FILTER_SRC_PORT &&
1175 zpie->proto != IPPROTO_ICMP)
25d760c5
PG
1176 zebra_pbr_display_port(vty, zpie->filter_bm,
1177 zpie->src_port_min,
1178 zpie->src_port_max,
1179 zpie->proto);
586f4ccf
PG
1180 vty_out(vty, " to ");
1181 zebra_pbr_prefix2str(&(zpie->dst), buf, sizeof(buf));
1182 vty_out(vty, "%s", buf);
be729dd7
PG
1183 if (zpie->filter_bm & PBR_FILTER_DST_PORT &&
1184 zpie->proto != IPPROTO_ICMP)
25d760c5
PG
1185 zebra_pbr_display_port(vty, zpie->filter_bm,
1186 zpie->dst_port_min,
1187 zpie->dst_port_max,
1188 zpie->proto);
be729dd7
PG
1189 if (zpie->proto == IPPROTO_ICMP)
1190 zebra_pbr_display_icmp(vty, zpie);
25d760c5
PG
1191 } else if ((zpi->type == IPSET_NET) ||
1192 (zpi->type == IPSET_NET_PORT)) {
586f4ccf
PG
1193 char buf[PREFIX_STRLEN];
1194
1195 if (zpie->filter_bm & PBR_FILTER_SRC_IP) {
1196 zebra_pbr_prefix2str(&(zpie->src), buf, sizeof(buf));
1197 vty_out(vty, "\tfrom %s", buf);
1198 }
be729dd7
PG
1199 if (zpie->filter_bm & PBR_FILTER_SRC_PORT &&
1200 zpie->proto != IPPROTO_ICMP)
25d760c5
PG
1201 zebra_pbr_display_port(vty, zpie->filter_bm,
1202 zpie->src_port_min,
1203 zpie->src_port_max,
1204 zpie->proto);
586f4ccf
PG
1205 if (zpie->filter_bm & PBR_FILTER_DST_IP) {
1206 zebra_pbr_prefix2str(&(zpie->dst), buf, sizeof(buf));
1207 vty_out(vty, "\tto %s", buf);
1208 }
be729dd7
PG
1209 if (zpie->filter_bm & PBR_FILTER_DST_PORT &&
1210 zpie->proto != IPPROTO_ICMP)
25d760c5
PG
1211 zebra_pbr_display_port(vty, zpie->filter_bm,
1212 zpie->dst_port_min,
1213 zpie->dst_port_max,
1214 zpie->proto);
be729dd7
PG
1215 if (zpie->proto == IPPROTO_ICMP)
1216 zebra_pbr_display_icmp(vty, zpie);
586f4ccf
PG
1217 }
1218 vty_out(vty, " (%u)\n", zpie->unique);
1219
1c6fca1f 1220 ret = hook_call(zebra_pbr_ipset_entry_get_stat, zpie, &pkts,
62f20a52 1221 &bytes);
73a829f7
PG
1222 if (ret && pkts > 0)
1223 vty_out(vty, "\t pkts %" PRIu64 ", bytes %" PRIu64"\n",
1224 pkts, bytes);
586f4ccf
PG
1225 return HASHWALK_CONTINUE;
1226}
1227
e3b78da8 1228static int zebra_pbr_show_ipset_walkcb(struct hash_bucket *bucket, void *arg)
586f4ccf
PG
1229{
1230 struct zebra_pbr_env_display *uniqueipset =
1231 (struct zebra_pbr_env_display *)arg;
e3b78da8 1232 struct zebra_pbr_ipset *zpi = (struct zebra_pbr_ipset *)bucket->data;
586f4ccf
PG
1233 struct zebra_pbr_ipset_entry_unique_display unique;
1234 struct vty *vty = uniqueipset->vty;
1235 struct zebra_ns *zns = uniqueipset->zns;
1236
a60b7031
PG
1237 vty_out(vty, "IPset %s type %s family %s\n", zpi->ipset_name,
1238 zebra_pbr_ipset_type2str(zpi->type),
c6423c31 1239 family2str(zpi->family));
586f4ccf
PG
1240 unique.vty = vty;
1241 unique.zpi = zpi;
73a829f7 1242 unique.zns = zns;
62f20a52 1243 hash_walk(zrouter.ipset_entry_hash, zebra_pbr_show_ipset_entry_walkcb,
586f4ccf
PG
1244 &unique);
1245 vty_out(vty, "\n");
1246 return HASHWALK_CONTINUE;
1247}
1248
dc993e76
PG
1249size_t zebra_pbr_tcpflags_snprintf(char *buffer, size_t len,
1250 uint16_t tcp_val)
1251{
1252 size_t len_written = 0;
1253 static struct message nt = {0};
1254 const struct message *pnt;
1255 int incr = 0;
1256
1257 for (pnt = tcp_value_str;
1258 memcmp(pnt, &nt, sizeof(struct message)); pnt++)
1259 if (pnt->key & tcp_val) {
1260 len_written += snprintf(buffer + len_written,
1261 len - len_written,
1262 "%s%s", incr ?
1263 ",":"", pnt->str);
1264 incr++;
1265 }
1266 return len_written;
1267}
1268
586f4ccf
PG
1269/*
1270 */
1271void zebra_pbr_show_ipset_list(struct vty *vty, char *ipsetname)
1272{
1273 struct zebra_pbr_ipset *zpi;
1274 struct zebra_ns *zns = zebra_ns_lookup(NS_DEFAULT);
1275 struct zebra_pbr_ipset_entry_unique_display unique;
1276 struct zebra_pbr_env_display uniqueipset;
1277
1278 if (ipsetname) {
62f20a52 1279 zpi = zebra_pbr_lookup_ipset_pername(ipsetname);
586f4ccf
PG
1280 if (!zpi) {
1281 vty_out(vty, "No IPset %s found\n", ipsetname);
1282 return;
1283 }
a60b7031
PG
1284 vty_out(vty, "IPset %s type %s family %s\n", ipsetname,
1285 zebra_pbr_ipset_type2str(zpi->type),
c6423c31 1286 family2str(zpi->family));
586f4ccf
PG
1287 unique.vty = vty;
1288 unique.zpi = zpi;
73a829f7 1289 unique.zns = zns;
62f20a52
DS
1290 hash_walk(zrouter.ipset_entry_hash,
1291 zebra_pbr_show_ipset_entry_walkcb, &unique);
586f4ccf
PG
1292 return;
1293 }
1294 uniqueipset.zns = zns;
1295 uniqueipset.vty = vty;
7929821a 1296 uniqueipset.name = NULL;
62f20a52 1297 hash_walk(zrouter.ipset_hash, zebra_pbr_show_ipset_walkcb,
586f4ccf
PG
1298 &uniqueipset);
1299}
1300
1301struct pbr_rule_fwmark_lookup {
1302 struct zebra_pbr_rule *ptr;
1303 uint32_t fwmark;
1304};
1305
e3b78da8 1306static int zebra_pbr_rule_lookup_fwmark_walkcb(struct hash_bucket *bucket,
586f4ccf
PG
1307 void *arg)
1308{
1309 struct pbr_rule_fwmark_lookup *iprule =
1310 (struct pbr_rule_fwmark_lookup *)arg;
e3b78da8 1311 struct zebra_pbr_rule *zpr = (struct zebra_pbr_rule *)bucket->data;
586f4ccf
PG
1312
1313 if (iprule->fwmark == zpr->rule.filter.fwmark) {
1314 iprule->ptr = zpr;
1315 return HASHWALK_ABORT;
1316 }
1317 return HASHWALK_CONTINUE;
1318}
1319
7929821a
PG
1320static void zebra_pbr_show_iptable_unit(struct zebra_pbr_iptable *iptable,
1321 struct vty *vty,
1322 struct zebra_ns *zns)
586f4ccf 1323{
73a829f7
PG
1324 int ret;
1325 uint64_t pkts = 0, bytes = 0;
586f4ccf 1326
a60b7031
PG
1327 vty_out(vty, "IPtable %s family %s action %s (%u)\n",
1328 iptable->ipset_name,
c9b1139a 1329 family2str(iptable->family),
586f4ccf
PG
1330 iptable->action == ZEBRA_IPTABLES_DROP ? "drop" : "redirect",
1331 iptable->unique);
0b328d3f
PG
1332 if (iptable->type == IPSET_NET_PORT ||
1333 iptable->type == IPSET_NET_PORT_NET) {
1334 if (!(iptable->filter_bm & MATCH_ICMP_SET)) {
1335 if (iptable->filter_bm & PBR_FILTER_DST_PORT)
1336 vty_out(vty, "\t lookup dst port\n");
1337 else if (iptable->filter_bm & PBR_FILTER_SRC_PORT)
1338 vty_out(vty, "\t lookup src port\n");
1339 }
1340 }
e7f7dad4
PG
1341 if (iptable->pkt_len_min || iptable->pkt_len_max) {
1342 if (!iptable->pkt_len_max)
1343 vty_out(vty, "\t pkt len %u\n",
1344 iptable->pkt_len_min);
1345 else
1346 vty_out(vty, "\t pkt len [%u;%u]\n",
1347 iptable->pkt_len_min,
1348 iptable->pkt_len_max);
1349 }
dc993e76
PG
1350 if (iptable->tcp_flags || iptable->tcp_mask_flags) {
1351 char tcp_flag_str[64];
1352 char tcp_flag_mask_str[64];
1353
1354 zebra_pbr_tcpflags_snprintf(tcp_flag_str,
1355 sizeof(tcp_flag_str),
1356 iptable->tcp_flags);
1357 zebra_pbr_tcpflags_snprintf(tcp_flag_mask_str,
1358 sizeof(tcp_flag_mask_str),
1359 iptable->tcp_mask_flags);
1360 vty_out(vty, "\t tcpflags [%s/%s]\n",
1361 tcp_flag_str, tcp_flag_mask_str);
1362 }
69214c57
PG
1363 if (iptable->filter_bm & (MATCH_DSCP_SET | MATCH_DSCP_INVERSE_SET)) {
1364 vty_out(vty, "\t dscp %s %d\n",
1365 iptable->filter_bm & MATCH_DSCP_INVERSE_SET ?
1366 "not" : "", iptable->dscp_value);
1367 }
a60b7031
PG
1368 if (iptable->filter_bm & (MATCH_FLOW_LABEL_SET |
1369 MATCH_FLOW_LABEL_INVERSE_SET)) {
1370 vty_out(vty, "\t flowlabel %s %d\n",
1371 iptable->filter_bm & MATCH_FLOW_LABEL_INVERSE_SET ?
1372 "not" : "", iptable->flow_label);
1373 }
5ac5b7cc
PG
1374 if (iptable->fragment) {
1375 char val_str[10];
1376
772270f3 1377 snprintf(val_str, sizeof(val_str), "%d", iptable->fragment);
5ac5b7cc
PG
1378 vty_out(vty, "\t fragment%s %s\n",
1379 iptable->filter_bm & MATCH_FRAGMENT_INVERSE_SET ?
1380 " not" : "", lookup_msg(fragment_value_str,
1381 iptable->fragment, val_str));
1382 }
f449d223
PG
1383 if (iptable->protocol) {
1384 vty_out(vty, "\t protocol %d\n",
1385 iptable->protocol);
1386 }
1c6fca1f 1387 ret = hook_call(zebra_pbr_iptable_get_stat, iptable, &pkts,
62f20a52 1388 &bytes);
73a829f7
PG
1389 if (ret && pkts > 0)
1390 vty_out(vty, "\t pkts %" PRIu64 ", bytes %" PRIu64"\n",
1391 pkts, bytes);
586f4ccf
PG
1392 if (iptable->action != ZEBRA_IPTABLES_DROP) {
1393 struct pbr_rule_fwmark_lookup prfl;
1394
1395 prfl.fwmark = iptable->fwmark;
1396 prfl.ptr = NULL;
7f0ea8a4 1397 hash_walk(zrouter.rules_hash,
586f4ccf
PG
1398 &zebra_pbr_rule_lookup_fwmark_walkcb, &prfl);
1399 if (prfl.ptr) {
1400 struct zebra_pbr_rule *zpr = prfl.ptr;
1401
1402 vty_out(vty, "\t table %u, fwmark %u\n",
1403 zpr->rule.action.table,
1404 prfl.fwmark);
1405 }
1406 }
7929821a
PG
1407}
1408
e3b78da8 1409static int zebra_pbr_show_iptable_walkcb(struct hash_bucket *bucket, void *arg)
7929821a
PG
1410{
1411 struct zebra_pbr_iptable *iptable =
e3b78da8 1412 (struct zebra_pbr_iptable *)bucket->data;
7929821a
PG
1413 struct zebra_pbr_env_display *env = (struct zebra_pbr_env_display *)arg;
1414 struct vty *vty = env->vty;
1415 struct zebra_ns *zns = env->zns;
1416 char *iptable_name = env->name;
1417
1418 if (!iptable_name)
1419 zebra_pbr_show_iptable_unit(iptable, vty, zns);
1420 else if (!strncmp(iptable_name,
1421 iptable->ipset_name,
1422 ZEBRA_IPSET_NAME_SIZE))
1423 zebra_pbr_show_iptable_unit(iptable, vty, zns);
586f4ccf
PG
1424 return HASHWALK_CONTINUE;
1425}
1426
7929821a 1427void zebra_pbr_show_iptable(struct vty *vty, char *iptable_name)
586f4ccf
PG
1428{
1429 struct zebra_ns *zns = zebra_ns_lookup(NS_DEFAULT);
1430 struct zebra_pbr_env_display env;
1431
1432 env.vty = vty;
1433 env.zns = zns;
7929821a 1434 env.name = iptable_name;
62f20a52 1435 hash_walk(zrouter.iptable_hash, zebra_pbr_show_iptable_walkcb, &env);
586f4ccf 1436}
f80ec7e3
PG
1437
1438void zebra_pbr_iptable_update_interfacelist(struct stream *s,
1439 struct zebra_pbr_iptable *zpi)
1440{
1441 uint32_t i = 0, index;
1442 struct interface *ifp;
1443 char *name;
1444
1445 for (i = 0; i < zpi->nb_interface; i++) {
1446 STREAM_GETL(s, index);
1447 ifp = if_lookup_by_index(index, zpi->vrf_id);
1448 if (!ifp)
1449 continue;
1450 name = XSTRDUP(MTYPE_PBR_IPTABLE_IFNAME, ifp->name);
1451 listnode_add(zpi->interface_name_list, name);
1452 }
1453stream_failure:
1454 return;
1455}