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