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