]> git.proxmox.com Git - mirror_frr.git/blob - zebra/zebra_pbr.c
zebra:add df flag into evpn esi json output
[mirror_frr.git] / zebra / zebra_pbr.c
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /* Zebra Policy Based Routing (PBR) main handling.
3 * Copyright (C) 2018 Cumulus Networks, Inc.
4 */
5
6 #include <zebra.h>
7
8 #include <jhash.h>
9 #include <hash.h>
10 #include <memory.h>
11 #include <hook.h>
12
13 #include "zebra/zebra_router.h"
14 #include "zebra/zebra_pbr.h"
15 #include "zebra/rt.h"
16 #include "zebra/zapi_msg.h"
17 #include "zebra/zserv.h"
18 #include "zebra/debug.h"
19 #include "zebra/zebra_neigh.h"
20
21 /* definitions */
22 DEFINE_MTYPE_STATIC(ZEBRA, PBR_IPTABLE_IFNAME, "PBR interface list");
23 DEFINE_MTYPE(ZEBRA, PBR_OBJ, "PBR");
24
25 /* definitions */
26 static 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 };
33
34 const 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
72 const 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
93 /* definitions */
94 static 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
104 static 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
112 struct zebra_pbr_env_display {
113 struct zebra_ns *zns;
114 struct vty *vty;
115 char *name;
116 };
117
118 /* static function declarations */
119 DEFINE_HOOK(zebra_pbr_ipset_entry_get_stat,
120 (struct zebra_pbr_ipset_entry *ipset, uint64_t *pkts,
121 uint64_t *bytes),
122 (ipset, pkts, bytes));
123
124 DEFINE_HOOK(zebra_pbr_iptable_get_stat,
125 (struct zebra_pbr_iptable *iptable, uint64_t *pkts,
126 uint64_t *bytes),
127 (iptable, pkts, bytes));
128
129 DEFINE_HOOK(zebra_pbr_iptable_update,
130 (int cmd, struct zebra_pbr_iptable *iptable), (cmd, iptable));
131
132 DEFINE_HOOK(zebra_pbr_ipset_entry_update,
133 (int cmd, struct zebra_pbr_ipset_entry *ipset), (cmd, ipset));
134
135 DEFINE_HOOK(zebra_pbr_ipset_update,
136 (int cmd, struct zebra_pbr_ipset *ipset), (cmd, ipset));
137
138 /* resolve nexthop for dataplane (dpdk) programming */
139 static bool zebra_pbr_expand_action;
140
141 /* Private functions */
142
143 /* Public functions */
144 void zebra_pbr_rules_free(void *arg)
145 {
146 struct zebra_pbr_rule *rule;
147
148 rule = (struct zebra_pbr_rule *)arg;
149
150 (void)dplane_pbr_rule_delete(rule);
151 XFREE(MTYPE_PBR_OBJ, rule);
152 }
153
154 uint32_t zebra_pbr_rules_hash_key(const void *arg)
155 {
156 const struct zebra_pbr_rule *rule;
157 uint32_t key;
158
159 rule = arg;
160 key = jhash_3words(rule->rule.seq, rule->rule.priority,
161 rule->rule.action.table,
162 prefix_hash_key(&rule->rule.filter.src_ip));
163
164 key = jhash_3words(rule->rule.filter.fwmark, rule->vrf_id,
165 rule->rule.filter.ip_proto, key);
166
167 key = jhash(rule->ifname, strlen(rule->ifname), key);
168
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));
173 }
174
175 bool zebra_pbr_rules_hash_equal(const void *arg1, const void *arg2)
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
182 if (r1->rule.seq != r2->rule.seq)
183 return false;
184
185 if (r1->rule.priority != r2->rule.priority)
186 return false;
187
188 if (r1->rule.unique != r2->rule.unique)
189 return false;
190
191 if (r1->rule.action.table != r2->rule.action.table)
192 return false;
193
194 if (r1->rule.filter.src_port != r2->rule.filter.src_port)
195 return false;
196
197 if (r1->rule.filter.dst_port != r2->rule.filter.dst_port)
198 return false;
199
200 if (r1->rule.filter.fwmark != r2->rule.filter.fwmark)
201 return false;
202
203 if (r1->rule.filter.ip_proto != r2->rule.filter.ip_proto)
204 return false;
205
206 if (!prefix_same(&r1->rule.filter.src_ip, &r2->rule.filter.src_ip))
207 return false;
208
209 if (!prefix_same(&r1->rule.filter.dst_ip, &r2->rule.filter.dst_ip))
210 return false;
211
212 if (strcmp(r1->rule.ifname, r2->rule.ifname) != 0)
213 return false;
214
215 if (r1->vrf_id != r2->vrf_id)
216 return false;
217
218 return true;
219 }
220
221 struct pbr_rule_unique_lookup {
222 struct zebra_pbr_rule *rule;
223 uint32_t unique;
224 char ifname[INTERFACE_NAMSIZ + 1];
225 vrf_id_t vrf_id;
226 };
227
228 static int pbr_rule_lookup_unique_walker(struct hash_bucket *b, void *data)
229 {
230 struct pbr_rule_unique_lookup *pul = data;
231 struct zebra_pbr_rule *rule = b->data;
232
233 if (pul->unique == rule->rule.unique
234 && strncmp(pul->ifname, rule->rule.ifname, INTERFACE_NAMSIZ) == 0
235 && pul->vrf_id == rule->vrf_id) {
236 pul->rule = rule;
237 return HASHWALK_ABORT;
238 }
239
240 return HASHWALK_CONTINUE;
241 }
242
243 static struct zebra_pbr_rule *
244 pbr_rule_lookup_unique(struct zebra_pbr_rule *zrule)
245 {
246 struct pbr_rule_unique_lookup pul;
247
248 pul.unique = zrule->rule.unique;
249 strlcpy(pul.ifname, zrule->rule.ifname, INTERFACE_NAMSIZ);
250 pul.rule = NULL;
251 pul.vrf_id = zrule->vrf_id;
252 hash_walk(zrouter.rules_hash, &pbr_rule_lookup_unique_walker, &pul);
253
254 return pul.rule;
255 }
256
257 void zebra_pbr_ipset_free(void *arg)
258 {
259 struct zebra_pbr_ipset *ipset;
260
261 ipset = (struct zebra_pbr_ipset *)arg;
262 hook_call(zebra_pbr_ipset_update, 0, ipset);
263 XFREE(MTYPE_PBR_OBJ, ipset);
264 }
265
266 uint32_t zebra_pbr_ipset_hash_key(const void *arg)
267 {
268 const struct zebra_pbr_ipset *ipset = arg;
269 uint32_t *pnt = (uint32_t *)&ipset->ipset_name;
270 uint32_t key = jhash_1word(ipset->vrf_id, 0x63ab42de);
271
272 key = jhash_1word(ipset->family, key);
273
274 return jhash2(pnt, ZEBRA_IPSET_NAME_HASH_SIZE, key);
275 }
276
277 bool zebra_pbr_ipset_hash_equal(const void *arg1, const void *arg2)
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)
285 return false;
286 if (r1->unique != r2->unique)
287 return false;
288 if (r1->vrf_id != r2->vrf_id)
289 return false;
290 if (r1->family != r2->family)
291 return false;
292
293 if (strncmp(r1->ipset_name, r2->ipset_name,
294 ZEBRA_IPSET_NAME_SIZE))
295 return false;
296 return true;
297 }
298
299 void zebra_pbr_ipset_entry_free(void *arg)
300 {
301 struct zebra_pbr_ipset_entry *ipset;
302
303 ipset = (struct zebra_pbr_ipset_entry *)arg;
304
305 hook_call(zebra_pbr_ipset_entry_update, 0, ipset);
306
307 XFREE(MTYPE_PBR_OBJ, ipset);
308 }
309
310 uint32_t zebra_pbr_ipset_entry_hash_key(const void *arg)
311 {
312 const struct zebra_pbr_ipset_entry *ipset;
313 uint32_t key;
314
315 ipset = arg;
316 key = prefix_hash_key(&ipset->src);
317 key = jhash_1word(ipset->unique, key);
318 key = jhash_1word(prefix_hash_key(&ipset->dst), key);
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);
324
325 return key;
326 }
327
328 bool zebra_pbr_ipset_entry_hash_equal(const void *arg1, const void *arg2)
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)
336 return false;
337
338 if (!prefix_same(&r1->src, &r2->src))
339 return false;
340
341 if (!prefix_same(&r1->dst, &r2->dst))
342 return false;
343
344 if (r1->src_port_min != r2->src_port_min)
345 return false;
346
347 if (r1->src_port_max != r2->src_port_max)
348 return false;
349
350 if (r1->dst_port_min != r2->dst_port_min)
351 return false;
352
353 if (r1->dst_port_max != r2->dst_port_max)
354 return false;
355
356 if (r1->proto != r2->proto)
357 return false;
358 return true;
359 }
360
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 */
365 static void _zebra_pbr_iptable_free_all(void *arg, bool all)
366 {
367 struct zebra_pbr_iptable *iptable;
368 struct listnode *node, *nnode;
369 char *name;
370
371 iptable = (struct zebra_pbr_iptable *)arg;
372
373 if (all)
374 hook_call(zebra_pbr_iptable_update, 0, iptable);
375
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);
383 }
384 XFREE(MTYPE_PBR_OBJ, iptable);
385 }
386
387 void zebra_pbr_iptable_free(void *arg)
388 {
389 _zebra_pbr_iptable_free_all(arg, false);
390 }
391
392 uint32_t zebra_pbr_iptable_hash_key(const void *arg)
393 {
394 const struct zebra_pbr_iptable *iptable = arg;
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);
401 key = jhash_1word(iptable->family, key);
402 key = jhash_1word(iptable->flow_label, key);
403 key = jhash_1word(iptable->pkt_len_min, key);
404 key = jhash_1word(iptable->pkt_len_max, key);
405 key = jhash_1word(iptable->tcp_flags, key);
406 key = jhash_1word(iptable->tcp_mask_flags, key);
407 key = jhash_1word(iptable->dscp_value, key);
408 key = jhash_1word(iptable->protocol, key);
409 key = jhash_1word(iptable->fragment, key);
410 key = jhash_1word(iptable->vrf_id, key);
411
412 return jhash_3words(iptable->filter_bm, iptable->type,
413 iptable->unique, key);
414 }
415
416 bool zebra_pbr_iptable_hash_equal(const void *arg1, const void *arg2)
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
423 if (r1->vrf_id != r2->vrf_id)
424 return false;
425 if (r1->type != r2->type)
426 return false;
427 if (r1->unique != r2->unique)
428 return false;
429 if (r1->filter_bm != r2->filter_bm)
430 return false;
431 if (r1->fwmark != r2->fwmark)
432 return false;
433 if (r1->action != r2->action)
434 return false;
435 if (strncmp(r1->ipset_name, r2->ipset_name,
436 ZEBRA_IPSET_NAME_SIZE))
437 return false;
438 if (r1->family != r2->family)
439 return false;
440 if (r1->flow_label != r2->flow_label)
441 return false;
442 if (r1->pkt_len_min != r2->pkt_len_min)
443 return false;
444 if (r1->pkt_len_max != r2->pkt_len_max)
445 return false;
446 if (r1->tcp_flags != r2->tcp_flags)
447 return false;
448 if (r1->tcp_mask_flags != r2->tcp_mask_flags)
449 return false;
450 if (r1->dscp_value != r2->dscp_value)
451 return false;
452 if (r1->fragment != r2->fragment)
453 return false;
454 if (r1->protocol != r2->protocol)
455 return false;
456 return true;
457 }
458
459 static 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
466 new = XCALLOC(MTYPE_PBR_OBJ, sizeof(*new));
467
468 memcpy(new, zpr, sizeof(*zpr));
469
470 return new;
471 }
472
473 static 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) {
480 XFREE(MTYPE_PBR_OBJ, hash_data);
481 return NULL;
482 }
483
484 return hash_data;
485 }
486
487 static struct zebra_pbr_rule *pbr_rule_release(struct zebra_pbr_rule *rule,
488 bool free_data)
489 {
490 struct zebra_pbr_rule *lookup;
491
492 lookup = hash_lookup(zrouter.rules_hash, rule);
493
494 if (!lookup)
495 return NULL;
496
497 return pbr_rule_free(lookup, free_data);
498 }
499
500 void 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
542 static 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
553 void 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
561 void zebra_pbr_config_write(struct vty *vty)
562 {
563 if (zebra_pbr_expand_action)
564 vty_out(vty, "pbr nexthop-resolve\n");
565 }
566
567 void zebra_pbr_expand_action_update(bool enable)
568 {
569 zebra_pbr_expand_action = enable;
570 }
571
572 static 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
635 case NEXTHOP_TYPE_BLACKHOLE:
636 case NEXTHOP_TYPE_IFINDEX:
637 action->afi = AFI_UNSPEC;
638 }
639 }
640
641 route_unlock_node(rn);
642 }
643
644 void zebra_pbr_add_rule(struct zebra_pbr_rule *rule)
645 {
646 struct zebra_pbr_rule *found;
647 struct zebra_pbr_rule *old;
648 struct zebra_pbr_rule *new;
649
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).
653 */
654 found = pbr_rule_lookup_unique(rule);
655
656 /* If found, this is an update */
657 if (found) {
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
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)
677 XFREE(MTYPE_PBR_OBJ, old);
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
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);
690 }
691
692 }
693
694 void zebra_pbr_del_rule(struct zebra_pbr_rule *rule)
695 {
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
701 (void)dplane_pbr_rule_delete(rule);
702
703 if (pbr_rule_release(rule, true))
704 zlog_debug("%s: Rule being deleted we know nothing about",
705 __func__);
706 }
707
708 void 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
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
724 dplane_ctx_set_status(ctx, ZEBRA_DPLANE_REQUEST_FAILURE);
725 }
726
727 void 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;
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
743 dplane_ctx_set_status(ctx, ZEBRA_DPLANE_REQUEST_FAILURE);
744 }
745
746 void 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
757 dplane_ctx_get_pbr_ipset_entry(ctx, &ipset_entry);
758 dplane_ctx_get_pbr_ipset(ctx, &ipset);
759
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
769 static void zebra_pbr_cleanup_rules(struct hash_bucket *b, void *data)
770 {
771 struct zebra_pbr_rule *rule = b->data;
772 int *sock = data;
773
774 if (rule->sock == *sock) {
775 (void)dplane_pbr_rule_delete(rule);
776 pbr_rule_free(rule, true);
777 }
778 }
779
780 static void zebra_pbr_cleanup_ipset(struct hash_bucket *b, void *data)
781 {
782 struct zebra_pbr_ipset *ipset = b->data;
783 int *sock = data;
784
785 if (ipset->sock == *sock) {
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);
790 }
791 }
792
793 static void zebra_pbr_cleanup_ipset_entry(struct hash_bucket *b, void *data)
794 {
795 struct zebra_pbr_ipset_entry *ipset = b->data;
796 int *sock = data;
797
798 if (ipset->sock == *sock) {
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);
803 }
804 }
805
806 static void zebra_pbr_cleanup_iptable(struct hash_bucket *b, void *data)
807 {
808 struct zebra_pbr_iptable *iptable = b->data;
809 int *sock = data;
810
811 if (iptable->sock == *sock) {
812 if (hash_release(zrouter.iptable_hash, iptable))
813 _zebra_pbr_iptable_free_all(iptable, true);
814 else
815 hook_call(zebra_pbr_iptable_update, 0, iptable);
816 }
817 }
818
819 static int zebra_pbr_client_close_cleanup(struct zserv *client)
820 {
821 int sock = client->sock;
822
823 if (!sock)
824 return 0;
825 hash_iterate(zrouter.rules_hash, zebra_pbr_cleanup_rules, &sock);
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);
830 return 1;
831 }
832
833 void zebra_pbr_init(void)
834 {
835 hook_register(zserv_client_close, zebra_pbr_client_close_cleanup);
836 }
837
838 static 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
845 new = XCALLOC(MTYPE_PBR_OBJ, sizeof(struct zebra_pbr_ipset));
846
847 memcpy(new, zpi, sizeof(*zpi));
848
849 return new;
850 }
851
852 void zebra_pbr_create_ipset(struct zebra_pbr_ipset *ipset)
853 {
854 (void)hash_get(zrouter.ipset_hash, ipset, pbr_ipset_alloc_intern);
855 (void)dplane_pbr_ipset_add(ipset);
856 }
857
858 void zebra_pbr_destroy_ipset(struct zebra_pbr_ipset *ipset)
859 {
860 struct zebra_pbr_ipset *lookup;
861
862 lookup = hash_lookup(zrouter.ipset_hash, ipset);
863 (void)dplane_pbr_ipset_delete(ipset);
864 if (lookup) {
865 hash_release(zrouter.ipset_hash, lookup);
866 XFREE(MTYPE_PBR_OBJ, lookup);
867 } else
868 zlog_debug(
869 "%s: IPSet Entry being deleted we know nothing about",
870 __func__);
871 }
872
873 struct pbr_ipset_name_lookup {
874 struct zebra_pbr_ipset *ipset;
875 char ipset_name[ZEBRA_IPSET_NAME_SIZE];
876 };
877
878 const char *zebra_pbr_ipset_type2str(uint32_t type)
879 {
880 return lookup_msg(ipset_type_msg, type,
881 "Unrecognized IPset Type");
882 }
883
884 static int zebra_pbr_ipset_pername_walkcb(struct hash_bucket *bucket, void *arg)
885 {
886 struct pbr_ipset_name_lookup *pinl =
887 (struct pbr_ipset_name_lookup *)arg;
888 struct zebra_pbr_ipset *zpi = (struct zebra_pbr_ipset *)bucket->data;
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
898 struct zebra_pbr_ipset *zebra_pbr_lookup_ipset_pername(char *ipsetname)
899 {
900 struct pbr_ipset_name_lookup pinl;
901 struct pbr_ipset_name_lookup *ptr = &pinl;
902
903 if (!ipsetname)
904 return NULL;
905 memset(ptr, 0, sizeof(struct pbr_ipset_name_lookup));
906 snprintf((char *)ptr->ipset_name, ZEBRA_IPSET_NAME_SIZE, "%s",
907 ipsetname);
908 hash_walk(zrouter.ipset_hash, zebra_pbr_ipset_pername_walkcb, ptr);
909 return ptr->ipset;
910 }
911
912 static 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
919 new = XCALLOC(MTYPE_PBR_OBJ, sizeof(struct zebra_pbr_ipset_entry));
920
921 memcpy(new, zpi, sizeof(*zpi));
922
923 return new;
924 }
925
926 void zebra_pbr_add_ipset_entry(struct zebra_pbr_ipset_entry *ipset)
927 {
928 (void)hash_get(zrouter.ipset_entry_hash, ipset,
929 pbr_ipset_entry_alloc_intern);
930 (void)dplane_pbr_ipset_entry_add(ipset);
931 }
932
933 void zebra_pbr_del_ipset_entry(struct zebra_pbr_ipset_entry *ipset)
934 {
935 struct zebra_pbr_ipset_entry *lookup;
936
937 lookup = hash_lookup(zrouter.ipset_entry_hash, ipset);
938 (void)dplane_pbr_ipset_entry_delete(ipset);
939 if (lookup) {
940 hash_release(zrouter.ipset_entry_hash, lookup);
941 XFREE(MTYPE_PBR_OBJ, lookup);
942 } else
943 zlog_debug("%s: IPSet being deleted we know nothing about",
944 __func__);
945 }
946
947 static void *pbr_iptable_alloc_intern(void *arg)
948 {
949 struct zebra_pbr_iptable *zpi;
950 struct zebra_pbr_iptable *new;
951 struct listnode *ln;
952 char *ifname;
953
954 zpi = (struct zebra_pbr_iptable *)arg;
955
956 new = XCALLOC(MTYPE_PBR_OBJ, sizeof(struct zebra_pbr_iptable));
957
958 /* Deep structure copy */
959 memcpy(new, zpi, sizeof(*zpi));
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 }
967
968 return new;
969 }
970
971 void zebra_pbr_add_iptable(struct zebra_pbr_iptable *iptable)
972 {
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);
978 }
979
980 void zebra_pbr_del_iptable(struct zebra_pbr_iptable *iptable)
981 {
982 struct zebra_pbr_iptable *lookup;
983
984 lookup = hash_lookup(zrouter.iptable_hash, iptable);
985 (void)dplane_pbr_iptable_delete(iptable);
986 if (lookup) {
987 struct listnode *node, *nnode;
988 char *name;
989
990 hash_release(zrouter.iptable_hash, lookup);
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 }
997 list_delete(&iptable->interface_name_list);
998 XFREE(MTYPE_PBR_OBJ, lookup);
999 } else
1000 zlog_debug("%s: IPTable being deleted we know nothing about",
1001 __func__);
1002 }
1003
1004 /*
1005 * Handle success or failure of rule (un)install in the kernel.
1006 */
1007 void 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);
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);
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);
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);
1057 }
1058
1059 /*
1060 * Handle rule delete notification from kernel.
1061 */
1062 int kernel_pbr_rule_del(struct zebra_pbr_rule *rule)
1063 {
1064 return 0;
1065 }
1066
1067 struct zebra_pbr_ipset_entry_unique_display {
1068 struct zebra_pbr_ipset *zpi;
1069 struct vty *vty;
1070 struct zebra_ns *zns;
1071 };
1072
1073
1074 static 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
1080 if ((p->family == AF_INET && p->prefixlen == IPV4_MAX_BITLEN)
1081 || (p->family == AF_INET6 && p->prefixlen == IPV6_MAX_BITLEN)) {
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
1089 static 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;
1094 struct zebra_pbr_ipset *zpi;
1095
1096 zpi = zpie->backpointer;
1097
1098 /* range icmp type */
1099 if (zpie->src_port_max || zpie->dst_port_max) {
1100 vty_out(vty, ":icmp:[type <%u:%u>;code <%u:%u>",
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));
1107 snprintf(decoded_str, sizeof(decoded_str), "%u/%u",
1108 zpie->src_port_min, zpie->dst_port_min);
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,
1113 port, decoded_str));
1114 }
1115 }
1116
1117 static 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
1138 static int zebra_pbr_show_ipset_entry_walkcb(struct hash_bucket *bucket,
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 =
1146 (struct zebra_pbr_ipset_entry *)bucket->data;
1147 uint64_t pkts = 0, bytes = 0;
1148 int ret = 0;
1149
1150 if (zpie->backpointer != zpi)
1151 return HASHWALK_CONTINUE;
1152
1153 if ((zpi->type == IPSET_NET_NET) ||
1154 (zpi->type == IPSET_NET_PORT_NET)) {
1155 char buf[PREFIX_STRLEN];
1156
1157 zebra_pbr_prefix2str(&(zpie->src), buf, sizeof(buf));
1158 vty_out(vty, "\tfrom %s", buf);
1159 if (zpie->filter_bm & PBR_FILTER_SRC_PORT &&
1160 zpie->proto != IPPROTO_ICMP)
1161 zebra_pbr_display_port(vty, zpie->filter_bm,
1162 zpie->src_port_min,
1163 zpie->src_port_max,
1164 zpie->proto);
1165 vty_out(vty, " to ");
1166 zebra_pbr_prefix2str(&(zpie->dst), buf, sizeof(buf));
1167 vty_out(vty, "%s", buf);
1168 if (zpie->filter_bm & PBR_FILTER_DST_PORT &&
1169 zpie->proto != IPPROTO_ICMP)
1170 zebra_pbr_display_port(vty, zpie->filter_bm,
1171 zpie->dst_port_min,
1172 zpie->dst_port_max,
1173 zpie->proto);
1174 if (zpie->proto == IPPROTO_ICMP)
1175 zebra_pbr_display_icmp(vty, zpie);
1176 } else if ((zpi->type == IPSET_NET) ||
1177 (zpi->type == IPSET_NET_PORT)) {
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 }
1184 if (zpie->filter_bm & PBR_FILTER_SRC_PORT &&
1185 zpie->proto != IPPROTO_ICMP)
1186 zebra_pbr_display_port(vty, zpie->filter_bm,
1187 zpie->src_port_min,
1188 zpie->src_port_max,
1189 zpie->proto);
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 }
1194 if (zpie->filter_bm & PBR_FILTER_DST_PORT &&
1195 zpie->proto != IPPROTO_ICMP)
1196 zebra_pbr_display_port(vty, zpie->filter_bm,
1197 zpie->dst_port_min,
1198 zpie->dst_port_max,
1199 zpie->proto);
1200 if (zpie->proto == IPPROTO_ICMP)
1201 zebra_pbr_display_icmp(vty, zpie);
1202 }
1203 vty_out(vty, " (%u)\n", zpie->unique);
1204
1205 ret = hook_call(zebra_pbr_ipset_entry_get_stat, zpie, &pkts,
1206 &bytes);
1207 if (ret && pkts > 0)
1208 vty_out(vty, "\t pkts %" PRIu64 ", bytes %" PRIu64"\n",
1209 pkts, bytes);
1210 return HASHWALK_CONTINUE;
1211 }
1212
1213 static int zebra_pbr_show_ipset_walkcb(struct hash_bucket *bucket, void *arg)
1214 {
1215 struct zebra_pbr_env_display *uniqueipset =
1216 (struct zebra_pbr_env_display *)arg;
1217 struct zebra_pbr_ipset *zpi = (struct zebra_pbr_ipset *)bucket->data;
1218 struct zebra_pbr_ipset_entry_unique_display unique;
1219 struct vty *vty = uniqueipset->vty;
1220 struct zebra_ns *zns = uniqueipset->zns;
1221
1222 vty_out(vty, "IPset %s type %s family %s\n", zpi->ipset_name,
1223 zebra_pbr_ipset_type2str(zpi->type),
1224 family2str(zpi->family));
1225 unique.vty = vty;
1226 unique.zpi = zpi;
1227 unique.zns = zns;
1228 hash_walk(zrouter.ipset_entry_hash, zebra_pbr_show_ipset_entry_walkcb,
1229 &unique);
1230 vty_out(vty, "\n");
1231 return HASHWALK_CONTINUE;
1232 }
1233
1234 size_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
1254 /*
1255 */
1256 void 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) {
1264 zpi = zebra_pbr_lookup_ipset_pername(ipsetname);
1265 if (!zpi) {
1266 vty_out(vty, "No IPset %s found\n", ipsetname);
1267 return;
1268 }
1269 vty_out(vty, "IPset %s type %s family %s\n", ipsetname,
1270 zebra_pbr_ipset_type2str(zpi->type),
1271 family2str(zpi->family));
1272 unique.vty = vty;
1273 unique.zpi = zpi;
1274 unique.zns = zns;
1275 hash_walk(zrouter.ipset_entry_hash,
1276 zebra_pbr_show_ipset_entry_walkcb, &unique);
1277 return;
1278 }
1279 uniqueipset.zns = zns;
1280 uniqueipset.vty = vty;
1281 uniqueipset.name = NULL;
1282 hash_walk(zrouter.ipset_hash, zebra_pbr_show_ipset_walkcb,
1283 &uniqueipset);
1284 }
1285
1286 struct pbr_rule_fwmark_lookup {
1287 struct zebra_pbr_rule *ptr;
1288 uint32_t fwmark;
1289 };
1290
1291 static int zebra_pbr_rule_lookup_fwmark_walkcb(struct hash_bucket *bucket,
1292 void *arg)
1293 {
1294 struct pbr_rule_fwmark_lookup *iprule =
1295 (struct pbr_rule_fwmark_lookup *)arg;
1296 struct zebra_pbr_rule *zpr = (struct zebra_pbr_rule *)bucket->data;
1297
1298 if (iprule->fwmark == zpr->rule.filter.fwmark) {
1299 iprule->ptr = zpr;
1300 return HASHWALK_ABORT;
1301 }
1302 return HASHWALK_CONTINUE;
1303 }
1304
1305 static void zebra_pbr_show_iptable_unit(struct zebra_pbr_iptable *iptable,
1306 struct vty *vty,
1307 struct zebra_ns *zns)
1308 {
1309 int ret;
1310 uint64_t pkts = 0, bytes = 0;
1311
1312 vty_out(vty, "IPtable %s family %s action %s (%u)\n",
1313 iptable->ipset_name,
1314 family2str(iptable->family),
1315 iptable->action == ZEBRA_IPTABLES_DROP ? "drop" : "redirect",
1316 iptable->unique);
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 }
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 }
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 }
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 }
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 }
1359 if (iptable->fragment) {
1360 char val_str[10];
1361
1362 snprintf(val_str, sizeof(val_str), "%d", iptable->fragment);
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 }
1368 if (iptable->protocol) {
1369 vty_out(vty, "\t protocol %d\n",
1370 iptable->protocol);
1371 }
1372 ret = hook_call(zebra_pbr_iptable_get_stat, iptable, &pkts,
1373 &bytes);
1374 if (ret && pkts > 0)
1375 vty_out(vty, "\t pkts %" PRIu64 ", bytes %" PRIu64"\n",
1376 pkts, bytes);
1377 if (iptable->action != ZEBRA_IPTABLES_DROP) {
1378 struct pbr_rule_fwmark_lookup prfl;
1379
1380 prfl.fwmark = iptable->fwmark;
1381 prfl.ptr = NULL;
1382 hash_walk(zrouter.rules_hash,
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 }
1392 }
1393
1394 static int zebra_pbr_show_iptable_walkcb(struct hash_bucket *bucket, void *arg)
1395 {
1396 struct zebra_pbr_iptable *iptable =
1397 (struct zebra_pbr_iptable *)bucket->data;
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);
1409 return HASHWALK_CONTINUE;
1410 }
1411
1412 void zebra_pbr_show_iptable(struct vty *vty, char *iptable_name)
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;
1419 env.name = iptable_name;
1420 hash_walk(zrouter.iptable_hash, zebra_pbr_show_iptable_walkcb, &env);
1421 }
1422
1423 void 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 }
1438 stream_failure:
1439 return;
1440 }