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