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