1 /* Zebra Policy Based Routing (PBR) main handling.
2 * Copyright (C) 2018 Cumulus Networks, Inc.
4 * This file is part of FRR.
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
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.
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
29 #include "zebra/zebra_router.h"
30 #include "zebra/zebra_pbr.h"
32 #include "zebra/zapi_msg.h"
33 #include "zebra/zebra_memory.h"
34 #include "zebra/zserv.h"
37 DEFINE_MTYPE_STATIC(ZEBRA
, PBR_IPTABLE_IFNAME
, "PBR interface list")
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"},
48 const struct message icmp_typecode_str
[] = {
49 { 0 << 8, "echo-reply"},
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"},
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"},
87 static const struct message tcp_value_str
[] = {
88 {TCP_HEADER_FIN
, "FIN"},
89 {TCP_HEADER_SYN
, "SYN"},
90 {TCP_HEADER_RST
, "RST"},
91 {TCP_HEADER_PSH
, "PSH"},
92 {TCP_HEADER_ACK
, "ACK"},
93 {TCP_HEADER_URG
, "URG"},
97 static const struct message fragment_value_str
[] = {
100 {4, "first-fragment"},
101 {8, "last-fragment"},
105 /* static function declarations */
106 DEFINE_HOOK(zebra_pbr_ipset_entry_get_stat
,
107 (struct zebra_pbr_ipset_entry
*ipset
, uint64_t *pkts
,
109 (ipset
, pkts
, bytes
))
111 DEFINE_HOOK(zebra_pbr_iptable_get_stat
,
112 (struct zebra_pbr_iptable
*iptable
, uint64_t *pkts
,
114 (iptable
, pkts
, bytes
))
116 DEFINE_HOOK(zebra_pbr_iptable_update
,
117 (int cmd
, struct zebra_pbr_iptable
*iptable
), (cmd
, iptable
));
119 DEFINE_HOOK(zebra_pbr_ipset_entry_update
,
120 (int cmd
, struct zebra_pbr_ipset_entry
*ipset
), (cmd
, ipset
));
122 DEFINE_HOOK(zebra_pbr_ipset_update
,
123 (int cmd
, struct zebra_pbr_ipset
*ipset
), (cmd
, ipset
));
125 /* Private functions */
127 /* Public functions */
128 void zebra_pbr_rules_free(void *arg
)
130 struct zebra_pbr_rule
*rule
;
132 rule
= (struct zebra_pbr_rule
*)arg
;
134 (void)dplane_pbr_rule_delete(rule
);
135 XFREE(MTYPE_TMP
, rule
);
138 uint32_t zebra_pbr_rules_hash_key(const void *arg
)
140 const struct zebra_pbr_rule
*rule
;
144 key
= jhash_3words(rule
->rule
.seq
, rule
->rule
.priority
,
145 rule
->rule
.action
.table
,
146 prefix_hash_key(&rule
->rule
.filter
.src_ip
));
148 if (rule
->rule
.filter
.fwmark
)
149 key
= jhash_3words(rule
->rule
.filter
.fwmark
, rule
->vrf_id
,
150 rule
->rule
.ifindex
, key
);
152 key
= jhash_2words(rule
->vrf_id
, rule
->rule
.ifindex
, key
);
154 return jhash_3words(rule
->rule
.filter
.src_port
,
155 rule
->rule
.filter
.dst_port
,
156 prefix_hash_key(&rule
->rule
.filter
.dst_ip
),
157 jhash_1word(rule
->rule
.unique
, key
));
160 bool zebra_pbr_rules_hash_equal(const void *arg1
, const void *arg2
)
162 const struct zebra_pbr_rule
*r1
, *r2
;
164 r1
= (const struct zebra_pbr_rule
*)arg1
;
165 r2
= (const struct zebra_pbr_rule
*)arg2
;
167 if (r1
->rule
.seq
!= r2
->rule
.seq
)
170 if (r1
->rule
.priority
!= r2
->rule
.priority
)
173 if (r1
->rule
.unique
!= r2
->rule
.unique
)
176 if (r1
->rule
.action
.table
!= r2
->rule
.action
.table
)
179 if (r1
->rule
.filter
.src_port
!= r2
->rule
.filter
.src_port
)
182 if (r1
->rule
.filter
.dst_port
!= r2
->rule
.filter
.dst_port
)
185 if (r1
->rule
.filter
.fwmark
!= r2
->rule
.filter
.fwmark
)
188 if (!prefix_same(&r1
->rule
.filter
.src_ip
, &r2
->rule
.filter
.src_ip
))
191 if (!prefix_same(&r1
->rule
.filter
.dst_ip
, &r2
->rule
.filter
.dst_ip
))
194 if (r1
->rule
.ifindex
!= r2
->rule
.ifindex
)
197 if (r1
->vrf_id
!= r2
->vrf_id
)
203 struct pbr_rule_unique_lookup
{
204 struct zebra_pbr_rule
*rule
;
210 static int pbr_rule_lookup_unique_walker(struct hash_bucket
*b
, void *data
)
212 struct pbr_rule_unique_lookup
*pul
= data
;
213 struct zebra_pbr_rule
*rule
= b
->data
;
215 if (pul
->unique
== rule
->rule
.unique
216 && pul
->ifindex
== rule
->rule
.ifindex
217 && pul
->vrf_id
== rule
->vrf_id
) {
219 return HASHWALK_ABORT
;
222 return HASHWALK_CONTINUE
;
225 static struct zebra_pbr_rule
*
226 pbr_rule_lookup_unique(struct zebra_pbr_rule
*zrule
)
228 struct pbr_rule_unique_lookup pul
;
230 pul
.unique
= zrule
->rule
.unique
;
231 pul
.ifindex
= zrule
->rule
.ifindex
;
233 pul
.vrf_id
= zrule
->vrf_id
;
234 hash_walk(zrouter
.rules_hash
, &pbr_rule_lookup_unique_walker
, &pul
);
239 void zebra_pbr_ipset_free(void *arg
)
241 struct zebra_pbr_ipset
*ipset
;
243 ipset
= (struct zebra_pbr_ipset
*)arg
;
244 hook_call(zebra_pbr_ipset_update
, 0, ipset
);
245 XFREE(MTYPE_TMP
, ipset
);
248 uint32_t zebra_pbr_ipset_hash_key(const void *arg
)
250 const struct zebra_pbr_ipset
*ipset
= arg
;
251 uint32_t *pnt
= (uint32_t *)&ipset
->ipset_name
;
252 uint32_t key
= jhash_1word(ipset
->vrf_id
, 0x63ab42de);
254 return jhash2(pnt
, ZEBRA_IPSET_NAME_HASH_SIZE
, key
);
257 bool zebra_pbr_ipset_hash_equal(const void *arg1
, const void *arg2
)
259 const struct zebra_pbr_ipset
*r1
, *r2
;
261 r1
= (const struct zebra_pbr_ipset
*)arg1
;
262 r2
= (const struct zebra_pbr_ipset
*)arg2
;
264 if (r1
->type
!= r2
->type
)
266 if (r1
->unique
!= r2
->unique
)
268 if (r1
->vrf_id
!= r2
->vrf_id
)
271 if (strncmp(r1
->ipset_name
, r2
->ipset_name
,
272 ZEBRA_IPSET_NAME_SIZE
))
277 void zebra_pbr_ipset_entry_free(void *arg
)
279 struct zebra_pbr_ipset_entry
*ipset
;
281 ipset
= (struct zebra_pbr_ipset_entry
*)arg
;
283 hook_call(zebra_pbr_ipset_entry_update
, 0, ipset
);
285 XFREE(MTYPE_TMP
, ipset
);
288 uint32_t zebra_pbr_ipset_entry_hash_key(const void *arg
)
290 const struct zebra_pbr_ipset_entry
*ipset
;
294 key
= prefix_hash_key(&ipset
->src
);
295 key
= jhash_1word(ipset
->unique
, key
);
296 key
= jhash_1word(prefix_hash_key(&ipset
->dst
), key
);
297 key
= jhash(&ipset
->dst_port_min
, 2, key
);
298 key
= jhash(&ipset
->dst_port_max
, 2, key
);
299 key
= jhash(&ipset
->src_port_min
, 2, key
);
300 key
= jhash(&ipset
->src_port_max
, 2, key
);
301 key
= jhash(&ipset
->proto
, 1, key
);
306 bool zebra_pbr_ipset_entry_hash_equal(const void *arg1
, const void *arg2
)
308 const struct zebra_pbr_ipset_entry
*r1
, *r2
;
310 r1
= (const struct zebra_pbr_ipset_entry
*)arg1
;
311 r2
= (const struct zebra_pbr_ipset_entry
*)arg2
;
313 if (r1
->unique
!= r2
->unique
)
316 if (!prefix_same(&r1
->src
, &r2
->src
))
319 if (!prefix_same(&r1
->dst
, &r2
->dst
))
322 if (r1
->src_port_min
!= r2
->src_port_min
)
325 if (r1
->src_port_max
!= r2
->src_port_max
)
328 if (r1
->dst_port_min
!= r2
->dst_port_min
)
331 if (r1
->dst_port_max
!= r2
->dst_port_max
)
334 if (r1
->proto
!= r2
->proto
)
339 /* this function gives option to flush plugin memory contexts
340 * with all parameter. set it to true to flush all
341 * set it to false to flush only passed arg argument
343 static void _zebra_pbr_iptable_free_all(void *arg
, bool all
)
345 struct zebra_pbr_iptable
*iptable
;
346 struct listnode
*node
, *nnode
;
349 iptable
= (struct zebra_pbr_iptable
*)arg
;
352 hook_call(zebra_pbr_iptable_update
, 0, iptable
);
354 if (iptable
->interface_name_list
) {
355 for (ALL_LIST_ELEMENTS(iptable
->interface_name_list
, node
,
357 XFREE(MTYPE_PBR_IPTABLE_IFNAME
, name
);
358 list_delete_node(iptable
->interface_name_list
, node
);
360 list_delete(&iptable
->interface_name_list
);
362 XFREE(MTYPE_TMP
, iptable
);
365 void zebra_pbr_iptable_free(void *arg
)
367 _zebra_pbr_iptable_free_all(arg
, false);
370 uint32_t zebra_pbr_iptable_hash_key(const void *arg
)
372 const struct zebra_pbr_iptable
*iptable
= arg
;
373 uint32_t *pnt
= (uint32_t *)&(iptable
->ipset_name
);
376 key
= jhash2(pnt
, ZEBRA_IPSET_NAME_HASH_SIZE
,
378 key
= jhash_1word(iptable
->fwmark
, key
);
379 key
= jhash_1word(iptable
->pkt_len_min
, key
);
380 key
= jhash_1word(iptable
->pkt_len_max
, key
);
381 key
= jhash_1word(iptable
->tcp_flags
, key
);
382 key
= jhash_1word(iptable
->tcp_mask_flags
, key
);
383 key
= jhash_1word(iptable
->dscp_value
, key
);
384 key
= jhash_1word(iptable
->protocol
, key
);
385 key
= jhash_1word(iptable
->fragment
, key
);
386 key
= jhash_1word(iptable
->vrf_id
, key
);
388 return jhash_3words(iptable
->filter_bm
, iptable
->type
,
389 iptable
->unique
, key
);
392 bool zebra_pbr_iptable_hash_equal(const void *arg1
, const void *arg2
)
394 const struct zebra_pbr_iptable
*r1
, *r2
;
396 r1
= (const struct zebra_pbr_iptable
*)arg1
;
397 r2
= (const struct zebra_pbr_iptable
*)arg2
;
399 if (r1
->vrf_id
!= r2
->vrf_id
)
401 if (r1
->type
!= r2
->type
)
403 if (r1
->unique
!= r2
->unique
)
405 if (r1
->filter_bm
!= r2
->filter_bm
)
407 if (r1
->fwmark
!= r2
->fwmark
)
409 if (r1
->action
!= r2
->action
)
411 if (strncmp(r1
->ipset_name
, r2
->ipset_name
,
412 ZEBRA_IPSET_NAME_SIZE
))
414 if (r1
->pkt_len_min
!= r2
->pkt_len_min
)
416 if (r1
->pkt_len_max
!= r2
->pkt_len_max
)
418 if (r1
->tcp_flags
!= r2
->tcp_flags
)
420 if (r1
->tcp_mask_flags
!= r2
->tcp_mask_flags
)
422 if (r1
->dscp_value
!= r2
->dscp_value
)
424 if (r1
->fragment
!= r2
->fragment
)
426 if (r1
->protocol
!= r2
->protocol
)
431 static void *pbr_rule_alloc_intern(void *arg
)
433 struct zebra_pbr_rule
*zpr
;
434 struct zebra_pbr_rule
*new;
436 zpr
= (struct zebra_pbr_rule
*)arg
;
438 new = XCALLOC(MTYPE_TMP
, sizeof(*new));
440 memcpy(new, zpr
, sizeof(*zpr
));
445 static int pbr_rule_release(struct zebra_pbr_rule
*rule
)
447 struct zebra_pbr_rule
*lookup
;
449 lookup
= hash_lookup(zrouter
.rules_hash
, rule
);
454 hash_release(zrouter
.rules_hash
, lookup
);
455 XFREE(MTYPE_TMP
, lookup
);
460 void zebra_pbr_add_rule(struct zebra_pbr_rule
*rule
)
462 struct zebra_pbr_rule
*found
;
465 * Check if we already have it (this checks via a unique ID, walking
466 * over the hash table, not via a hash operation).
468 found
= pbr_rule_lookup_unique(rule
);
470 (void)hash_get(zrouter
.rules_hash
, rule
, pbr_rule_alloc_intern
);
472 /* If found, this is an update */
474 (void)dplane_pbr_rule_update(found
, rule
);
476 if (pbr_rule_release(found
))
478 "%s: Rule being updated we know nothing about",
479 __PRETTY_FUNCTION__
);
482 (void)dplane_pbr_rule_add(rule
);
485 void zebra_pbr_del_rule(struct zebra_pbr_rule
*rule
)
487 (void)dplane_pbr_rule_delete(rule
);
489 if (pbr_rule_release(rule
))
490 zlog_debug("%s: Rule being deleted we know nothing about",
494 static void zebra_pbr_cleanup_rules(struct hash_bucket
*b
, void *data
)
496 struct zebra_pbr_rule
*rule
= b
->data
;
499 if (rule
->sock
== *sock
) {
500 (void)dplane_pbr_rule_delete(rule
);
501 if (hash_release(zrouter
.rules_hash
, rule
))
502 XFREE(MTYPE_TMP
, rule
);
505 "%s: Rule seq: %u is being cleaned but we can't find it in our tables",
506 __func__
, rule
->rule
.seq
);
510 static void zebra_pbr_cleanup_ipset(struct hash_bucket
*b
, void *data
)
512 struct zebra_pbr_ipset
*ipset
= b
->data
;
515 if (ipset
->sock
== *sock
) {
516 if (hash_release(zrouter
.ipset_hash
, ipset
))
517 zebra_pbr_ipset_free(ipset
);
519 hook_call(zebra_pbr_ipset_update
, 0, ipset
);
523 static void zebra_pbr_cleanup_ipset_entry(struct hash_bucket
*b
, void *data
)
525 struct zebra_pbr_ipset_entry
*ipset
= b
->data
;
528 if (ipset
->sock
== *sock
) {
529 if (hash_release(zrouter
.ipset_entry_hash
, ipset
))
530 zebra_pbr_ipset_entry_free(ipset
);
532 hook_call(zebra_pbr_ipset_entry_update
, 0, ipset
);
536 static void zebra_pbr_cleanup_iptable(struct hash_bucket
*b
, void *data
)
538 struct zebra_pbr_iptable
*iptable
= b
->data
;
541 if (iptable
->sock
== *sock
) {
542 if (hash_release(zrouter
.iptable_hash
, iptable
))
543 _zebra_pbr_iptable_free_all(iptable
, true);
545 hook_call(zebra_pbr_iptable_update
, 0, iptable
);
549 static int zebra_pbr_client_close_cleanup(struct zserv
*client
)
551 int sock
= client
->sock
;
555 hash_iterate(zrouter
.rules_hash
, zebra_pbr_cleanup_rules
, &sock
);
556 hash_iterate(zrouter
.iptable_hash
, zebra_pbr_cleanup_iptable
, &sock
);
557 hash_iterate(zrouter
.ipset_entry_hash
, zebra_pbr_cleanup_ipset_entry
,
559 hash_iterate(zrouter
.ipset_hash
, zebra_pbr_cleanup_ipset
, &sock
);
563 void zebra_pbr_init(void)
565 hook_register(zserv_client_close
, zebra_pbr_client_close_cleanup
);
568 static void *pbr_ipset_alloc_intern(void *arg
)
570 struct zebra_pbr_ipset
*zpi
;
571 struct zebra_pbr_ipset
*new;
573 zpi
= (struct zebra_pbr_ipset
*)arg
;
575 new = XCALLOC(MTYPE_TMP
, sizeof(struct zebra_pbr_ipset
));
577 memcpy(new, zpi
, sizeof(*zpi
));
582 void zebra_pbr_create_ipset(struct zebra_pbr_ipset
*ipset
)
586 (void)hash_get(zrouter
.ipset_hash
, ipset
, pbr_ipset_alloc_intern
);
587 ret
= hook_call(zebra_pbr_ipset_update
, 1, ipset
);
588 kernel_pbr_ipset_add_del_status(ipset
,
589 ret
? ZEBRA_DPLANE_INSTALL_SUCCESS
590 : ZEBRA_DPLANE_INSTALL_FAILURE
);
593 void zebra_pbr_destroy_ipset(struct zebra_pbr_ipset
*ipset
)
595 struct zebra_pbr_ipset
*lookup
;
597 lookup
= hash_lookup(zrouter
.ipset_hash
, ipset
);
598 hook_call(zebra_pbr_ipset_update
, 0, ipset
);
600 hash_release(zrouter
.ipset_hash
, lookup
);
601 XFREE(MTYPE_TMP
, lookup
);
604 "%s: IPSet Entry being deleted we know nothing about",
608 struct pbr_ipset_name_lookup
{
609 struct zebra_pbr_ipset
*ipset
;
610 char ipset_name
[ZEBRA_IPSET_NAME_SIZE
];
613 const char *zebra_pbr_ipset_type2str(uint32_t type
)
615 return lookup_msg(ipset_type_msg
, type
,
616 "Unrecognized IPset Type");
619 static int zebra_pbr_ipset_pername_walkcb(struct hash_bucket
*bucket
, void *arg
)
621 struct pbr_ipset_name_lookup
*pinl
=
622 (struct pbr_ipset_name_lookup
*)arg
;
623 struct zebra_pbr_ipset
*zpi
= (struct zebra_pbr_ipset
*)bucket
->data
;
625 if (!strncmp(pinl
->ipset_name
, zpi
->ipset_name
,
626 ZEBRA_IPSET_NAME_SIZE
)) {
628 return HASHWALK_ABORT
;
630 return HASHWALK_CONTINUE
;
633 struct zebra_pbr_ipset
*zebra_pbr_lookup_ipset_pername(char *ipsetname
)
635 struct pbr_ipset_name_lookup pinl
;
636 struct pbr_ipset_name_lookup
*ptr
= &pinl
;
640 memset(ptr
, 0, sizeof(struct pbr_ipset_name_lookup
));
641 snprintf((char *)ptr
->ipset_name
, ZEBRA_IPSET_NAME_SIZE
, "%s",
643 hash_walk(zrouter
.ipset_hash
, zebra_pbr_ipset_pername_walkcb
, ptr
);
647 static void *pbr_ipset_entry_alloc_intern(void *arg
)
649 struct zebra_pbr_ipset_entry
*zpi
;
650 struct zebra_pbr_ipset_entry
*new;
652 zpi
= (struct zebra_pbr_ipset_entry
*)arg
;
654 new = XCALLOC(MTYPE_TMP
, sizeof(struct zebra_pbr_ipset_entry
));
656 memcpy(new, zpi
, sizeof(*zpi
));
661 void zebra_pbr_add_ipset_entry(struct zebra_pbr_ipset_entry
*ipset
)
665 (void)hash_get(zrouter
.ipset_entry_hash
, ipset
,
666 pbr_ipset_entry_alloc_intern
);
667 ret
= hook_call(zebra_pbr_ipset_entry_update
, 1, ipset
);
668 kernel_pbr_ipset_entry_add_del_status(ipset
,
669 ret
? ZEBRA_DPLANE_INSTALL_SUCCESS
670 : ZEBRA_DPLANE_INSTALL_FAILURE
);
673 void zebra_pbr_del_ipset_entry(struct zebra_pbr_ipset_entry
*ipset
)
675 struct zebra_pbr_ipset_entry
*lookup
;
677 lookup
= hash_lookup(zrouter
.ipset_entry_hash
, ipset
);
678 hook_call(zebra_pbr_ipset_entry_update
, 0, ipset
);
680 hash_release(zrouter
.ipset_entry_hash
, lookup
);
681 XFREE(MTYPE_TMP
, lookup
);
683 zlog_debug("%s: IPSet being deleted we know nothing about",
687 static void *pbr_iptable_alloc_intern(void *arg
)
689 struct zebra_pbr_iptable
*zpi
;
690 struct zebra_pbr_iptable
*new;
694 zpi
= (struct zebra_pbr_iptable
*)arg
;
696 new = XCALLOC(MTYPE_TMP
, sizeof(struct zebra_pbr_iptable
));
698 /* Deep structure copy */
699 memcpy(new, zpi
, sizeof(*zpi
));
700 new->interface_name_list
= list_new();
702 if (zpi
->interface_name_list
) {
703 for (ALL_LIST_ELEMENTS_RO(zpi
->interface_name_list
, ln
, ifname
))
704 listnode_add(new->interface_name_list
,
705 XSTRDUP(MTYPE_PBR_IPTABLE_IFNAME
, ifname
));
711 void zebra_pbr_add_iptable(struct zebra_pbr_iptable
*iptable
)
715 (void)hash_get(zrouter
.iptable_hash
, iptable
, pbr_iptable_alloc_intern
);
716 ret
= hook_call(zebra_pbr_iptable_update
, 1, iptable
);
717 kernel_pbr_iptable_add_del_status(iptable
,
718 ret
? ZEBRA_DPLANE_INSTALL_SUCCESS
719 : ZEBRA_DPLANE_INSTALL_FAILURE
);
722 void zebra_pbr_del_iptable(struct zebra_pbr_iptable
*iptable
)
724 struct zebra_pbr_iptable
*lookup
;
726 lookup
= hash_lookup(zrouter
.iptable_hash
, iptable
);
727 hook_call(zebra_pbr_iptable_update
, 0, iptable
);
729 struct listnode
*node
, *nnode
;
732 hash_release(zrouter
.iptable_hash
, lookup
);
733 for (ALL_LIST_ELEMENTS(iptable
->interface_name_list
,
734 node
, nnode
, name
)) {
735 XFREE(MTYPE_PBR_IPTABLE_IFNAME
, name
);
736 list_delete_node(iptable
->interface_name_list
,
739 list_delete(&iptable
->interface_name_list
);
740 XFREE(MTYPE_TMP
, lookup
);
742 zlog_debug("%s: IPTable being deleted we know nothing about",
747 * Handle success or failure of rule (un)install in the kernel.
749 void zebra_pbr_dplane_result(struct zebra_dplane_ctx
*ctx
)
751 enum zebra_dplane_result res
;
754 res
= dplane_ctx_get_status(ctx
);
755 op
= dplane_ctx_get_op(ctx
);
756 if (op
== DPLANE_OP_RULE_ADD
|| op
== DPLANE_OP_RULE_UPDATE
)
757 zsend_rule_notify_owner(ctx
, res
== ZEBRA_DPLANE_REQUEST_SUCCESS
758 ? ZAPI_RULE_INSTALLED
759 : ZAPI_RULE_FAIL_INSTALL
);
760 else if (op
== DPLANE_OP_RULE_DELETE
)
761 zsend_rule_notify_owner(ctx
, res
== ZEBRA_DPLANE_REQUEST_SUCCESS
763 : ZAPI_RULE_FAIL_REMOVE
);
766 EC_ZEBRA_PBR_RULE_UPDATE
,
767 "Context received in pbr rule dplane result handler with incorrect OP code (%u)",
771 dplane_ctx_fini(&ctx
);
775 * Handle success or failure of ipset (un)install in the kernel.
777 void kernel_pbr_ipset_add_del_status(struct zebra_pbr_ipset
*ipset
,
778 enum zebra_dplane_status res
)
781 case ZEBRA_DPLANE_INSTALL_SUCCESS
:
782 zsend_ipset_notify_owner(ipset
, ZAPI_IPSET_INSTALLED
);
784 case ZEBRA_DPLANE_INSTALL_FAILURE
:
785 zsend_ipset_notify_owner(ipset
, ZAPI_IPSET_FAIL_INSTALL
);
787 case ZEBRA_DPLANE_DELETE_SUCCESS
:
788 zsend_ipset_notify_owner(ipset
, ZAPI_IPSET_REMOVED
);
790 case ZEBRA_DPLANE_DELETE_FAILURE
:
791 zsend_ipset_notify_owner(ipset
, ZAPI_IPSET_FAIL_REMOVE
);
793 case ZEBRA_DPLANE_STATUS_NONE
:
799 * Handle success or failure of ipset (un)install in the kernel.
801 void kernel_pbr_ipset_entry_add_del_status(
802 struct zebra_pbr_ipset_entry
*ipset
,
803 enum zebra_dplane_status res
)
806 case ZEBRA_DPLANE_INSTALL_SUCCESS
:
807 zsend_ipset_entry_notify_owner(ipset
,
808 ZAPI_IPSET_ENTRY_INSTALLED
);
810 case ZEBRA_DPLANE_INSTALL_FAILURE
:
811 zsend_ipset_entry_notify_owner(ipset
,
812 ZAPI_IPSET_ENTRY_FAIL_INSTALL
);
814 case ZEBRA_DPLANE_DELETE_SUCCESS
:
815 zsend_ipset_entry_notify_owner(ipset
,
816 ZAPI_IPSET_ENTRY_REMOVED
);
818 case ZEBRA_DPLANE_DELETE_FAILURE
:
819 zsend_ipset_entry_notify_owner(ipset
,
820 ZAPI_IPSET_ENTRY_FAIL_REMOVE
);
822 case ZEBRA_DPLANE_STATUS_NONE
:
828 * Handle success or failure of ipset (un)install in the kernel.
830 void kernel_pbr_iptable_add_del_status(struct zebra_pbr_iptable
*iptable
,
831 enum zebra_dplane_status res
)
834 case ZEBRA_DPLANE_INSTALL_SUCCESS
:
835 zsend_iptable_notify_owner(iptable
, ZAPI_IPTABLE_INSTALLED
);
837 case ZEBRA_DPLANE_INSTALL_FAILURE
:
838 zsend_iptable_notify_owner(iptable
, ZAPI_IPTABLE_FAIL_INSTALL
);
840 case ZEBRA_DPLANE_DELETE_SUCCESS
:
841 zsend_iptable_notify_owner(iptable
,
842 ZAPI_IPTABLE_REMOVED
);
844 case ZEBRA_DPLANE_DELETE_FAILURE
:
845 zsend_iptable_notify_owner(iptable
,
846 ZAPI_IPTABLE_FAIL_REMOVE
);
848 case ZEBRA_DPLANE_STATUS_NONE
:
854 * Handle rule delete notification from kernel.
856 int kernel_pbr_rule_del(struct zebra_pbr_rule
*rule
)
861 struct zebra_pbr_ipset_entry_unique_display
{
862 struct zebra_pbr_ipset
*zpi
;
864 struct zebra_ns
*zns
;
867 struct zebra_pbr_env_display
{
868 struct zebra_ns
*zns
;
873 static const char *zebra_pbr_prefix2str(union prefixconstptr pu
,
876 const struct prefix
*p
= pu
.p
;
877 char buf
[PREFIX2STR_BUFFER
];
879 if (p
->family
== AF_INET
&& p
->prefixlen
== IPV4_MAX_PREFIXLEN
) {
880 snprintf(str
, size
, "%s", inet_ntop(p
->family
, &p
->u
.prefix
,
881 buf
, PREFIX2STR_BUFFER
));
884 return prefix2str(pu
, str
, size
);
887 static void zebra_pbr_display_icmp(struct vty
*vty
,
888 struct zebra_pbr_ipset_entry
*zpie
)
890 char decoded_str
[20];
893 /* range icmp type */
894 if (zpie
->src_port_max
|| zpie
->dst_port_max
) {
895 vty_out(vty
, ":icmp:[type <%u:%u>;code <%u:%u>",
896 zpie
->src_port_min
, zpie
->src_port_max
,
897 zpie
->dst_port_min
, zpie
->dst_port_max
);
899 port
= ((zpie
->src_port_min
<< 8) & 0xff00) +
900 (zpie
->dst_port_min
& 0xff);
901 memset(decoded_str
, 0, sizeof(decoded_str
));
902 snprintf(decoded_str
, sizeof(decoded_str
), "%u/%u",
903 zpie
->src_port_min
, zpie
->dst_port_min
);
904 vty_out(vty
, ":icmp:%s",
905 lookup_msg(icmp_typecode_str
,
910 static void zebra_pbr_display_port(struct vty
*vty
, uint32_t filter_bm
,
911 uint16_t port_min
, uint16_t port_max
,
914 if (!(filter_bm
& PBR_FILTER_PROTO
)) {
916 vty_out(vty
, ":udp/tcp:%d-%d",
919 vty_out(vty
, ":udp/tcp:%d",
923 vty_out(vty
, ":proto %d:%d-%d",
924 proto
, port_min
, port_max
);
926 vty_out(vty
, ":proto %d:%d",
931 static int zebra_pbr_show_ipset_entry_walkcb(struct hash_bucket
*bucket
,
934 struct zebra_pbr_ipset_entry_unique_display
*unique
=
935 (struct zebra_pbr_ipset_entry_unique_display
*)arg
;
936 struct zebra_pbr_ipset
*zpi
= unique
->zpi
;
937 struct vty
*vty
= unique
->vty
;
938 struct zebra_pbr_ipset_entry
*zpie
=
939 (struct zebra_pbr_ipset_entry
*)bucket
->data
;
940 uint64_t pkts
= 0, bytes
= 0;
943 if (zpie
->backpointer
!= zpi
)
944 return HASHWALK_CONTINUE
;
946 if ((zpi
->type
== IPSET_NET_NET
) ||
947 (zpi
->type
== IPSET_NET_PORT_NET
)) {
948 char buf
[PREFIX_STRLEN
];
950 zebra_pbr_prefix2str(&(zpie
->src
), buf
, sizeof(buf
));
951 vty_out(vty
, "\tfrom %s", buf
);
952 if (zpie
->filter_bm
& PBR_FILTER_SRC_PORT
&&
953 zpie
->proto
!= IPPROTO_ICMP
)
954 zebra_pbr_display_port(vty
, zpie
->filter_bm
,
958 vty_out(vty
, " to ");
959 zebra_pbr_prefix2str(&(zpie
->dst
), buf
, sizeof(buf
));
960 vty_out(vty
, "%s", buf
);
961 if (zpie
->filter_bm
& PBR_FILTER_DST_PORT
&&
962 zpie
->proto
!= IPPROTO_ICMP
)
963 zebra_pbr_display_port(vty
, zpie
->filter_bm
,
967 if (zpie
->proto
== IPPROTO_ICMP
)
968 zebra_pbr_display_icmp(vty
, zpie
);
969 } else if ((zpi
->type
== IPSET_NET
) ||
970 (zpi
->type
== IPSET_NET_PORT
)) {
971 char buf
[PREFIX_STRLEN
];
973 if (zpie
->filter_bm
& PBR_FILTER_SRC_IP
) {
974 zebra_pbr_prefix2str(&(zpie
->src
), buf
, sizeof(buf
));
975 vty_out(vty
, "\tfrom %s", buf
);
977 if (zpie
->filter_bm
& PBR_FILTER_SRC_PORT
&&
978 zpie
->proto
!= IPPROTO_ICMP
)
979 zebra_pbr_display_port(vty
, zpie
->filter_bm
,
983 if (zpie
->filter_bm
& PBR_FILTER_DST_IP
) {
984 zebra_pbr_prefix2str(&(zpie
->dst
), buf
, sizeof(buf
));
985 vty_out(vty
, "\tto %s", buf
);
987 if (zpie
->filter_bm
& PBR_FILTER_DST_PORT
&&
988 zpie
->proto
!= IPPROTO_ICMP
)
989 zebra_pbr_display_port(vty
, zpie
->filter_bm
,
993 if (zpie
->proto
== IPPROTO_ICMP
)
994 zebra_pbr_display_icmp(vty
, zpie
);
996 vty_out(vty
, " (%u)\n", zpie
->unique
);
998 ret
= hook_call(zebra_pbr_ipset_entry_get_stat
, zpie
, &pkts
,
1000 if (ret
&& pkts
> 0)
1001 vty_out(vty
, "\t pkts %" PRIu64
", bytes %" PRIu64
"\n",
1003 return HASHWALK_CONTINUE
;
1006 static int zebra_pbr_show_ipset_walkcb(struct hash_bucket
*bucket
, void *arg
)
1008 struct zebra_pbr_env_display
*uniqueipset
=
1009 (struct zebra_pbr_env_display
*)arg
;
1010 struct zebra_pbr_ipset
*zpi
= (struct zebra_pbr_ipset
*)bucket
->data
;
1011 struct zebra_pbr_ipset_entry_unique_display unique
;
1012 struct vty
*vty
= uniqueipset
->vty
;
1013 struct zebra_ns
*zns
= uniqueipset
->zns
;
1015 vty_out(vty
, "IPset %s type %s\n", zpi
->ipset_name
,
1016 zebra_pbr_ipset_type2str(zpi
->type
));
1020 hash_walk(zrouter
.ipset_entry_hash
, zebra_pbr_show_ipset_entry_walkcb
,
1023 return HASHWALK_CONTINUE
;
1026 size_t zebra_pbr_tcpflags_snprintf(char *buffer
, size_t len
,
1029 size_t len_written
= 0;
1030 static struct message nt
= {0};
1031 const struct message
*pnt
;
1034 for (pnt
= tcp_value_str
;
1035 memcmp(pnt
, &nt
, sizeof(struct message
)); pnt
++)
1036 if (pnt
->key
& tcp_val
) {
1037 len_written
+= snprintf(buffer
+ len_written
,
1048 void zebra_pbr_show_ipset_list(struct vty
*vty
, char *ipsetname
)
1050 struct zebra_pbr_ipset
*zpi
;
1051 struct zebra_ns
*zns
= zebra_ns_lookup(NS_DEFAULT
);
1052 struct zebra_pbr_ipset_entry_unique_display unique
;
1053 struct zebra_pbr_env_display uniqueipset
;
1056 zpi
= zebra_pbr_lookup_ipset_pername(ipsetname
);
1058 vty_out(vty
, "No IPset %s found\n", ipsetname
);
1061 vty_out(vty
, "IPset %s type %s\n", ipsetname
,
1062 zebra_pbr_ipset_type2str(zpi
->type
));
1067 hash_walk(zrouter
.ipset_entry_hash
,
1068 zebra_pbr_show_ipset_entry_walkcb
, &unique
);
1071 uniqueipset
.zns
= zns
;
1072 uniqueipset
.vty
= vty
;
1073 uniqueipset
.name
= NULL
;
1074 hash_walk(zrouter
.ipset_hash
, zebra_pbr_show_ipset_walkcb
,
1078 struct pbr_rule_fwmark_lookup
{
1079 struct zebra_pbr_rule
*ptr
;
1083 static int zebra_pbr_rule_lookup_fwmark_walkcb(struct hash_bucket
*bucket
,
1086 struct pbr_rule_fwmark_lookup
*iprule
=
1087 (struct pbr_rule_fwmark_lookup
*)arg
;
1088 struct zebra_pbr_rule
*zpr
= (struct zebra_pbr_rule
*)bucket
->data
;
1090 if (iprule
->fwmark
== zpr
->rule
.filter
.fwmark
) {
1092 return HASHWALK_ABORT
;
1094 return HASHWALK_CONTINUE
;
1097 static void zebra_pbr_show_iptable_unit(struct zebra_pbr_iptable
*iptable
,
1099 struct zebra_ns
*zns
)
1102 uint64_t pkts
= 0, bytes
= 0;
1104 vty_out(vty
, "IPtable %s action %s (%u)\n", iptable
->ipset_name
,
1105 iptable
->action
== ZEBRA_IPTABLES_DROP
? "drop" : "redirect",
1107 if (iptable
->type
== IPSET_NET_PORT
||
1108 iptable
->type
== IPSET_NET_PORT_NET
) {
1109 if (!(iptable
->filter_bm
& MATCH_ICMP_SET
)) {
1110 if (iptable
->filter_bm
& PBR_FILTER_DST_PORT
)
1111 vty_out(vty
, "\t lookup dst port\n");
1112 else if (iptable
->filter_bm
& PBR_FILTER_SRC_PORT
)
1113 vty_out(vty
, "\t lookup src port\n");
1116 if (iptable
->pkt_len_min
|| iptable
->pkt_len_max
) {
1117 if (!iptable
->pkt_len_max
)
1118 vty_out(vty
, "\t pkt len %u\n",
1119 iptable
->pkt_len_min
);
1121 vty_out(vty
, "\t pkt len [%u;%u]\n",
1122 iptable
->pkt_len_min
,
1123 iptable
->pkt_len_max
);
1125 if (iptable
->tcp_flags
|| iptable
->tcp_mask_flags
) {
1126 char tcp_flag_str
[64];
1127 char tcp_flag_mask_str
[64];
1129 zebra_pbr_tcpflags_snprintf(tcp_flag_str
,
1130 sizeof(tcp_flag_str
),
1131 iptable
->tcp_flags
);
1132 zebra_pbr_tcpflags_snprintf(tcp_flag_mask_str
,
1133 sizeof(tcp_flag_mask_str
),
1134 iptable
->tcp_mask_flags
);
1135 vty_out(vty
, "\t tcpflags [%s/%s]\n",
1136 tcp_flag_str
, tcp_flag_mask_str
);
1138 if (iptable
->filter_bm
& (MATCH_DSCP_SET
| MATCH_DSCP_INVERSE_SET
)) {
1139 vty_out(vty
, "\t dscp %s %d\n",
1140 iptable
->filter_bm
& MATCH_DSCP_INVERSE_SET
?
1141 "not" : "", iptable
->dscp_value
);
1143 if (iptable
->fragment
) {
1146 snprintf(val_str
, sizeof(val_str
), "%d", iptable
->fragment
);
1147 vty_out(vty
, "\t fragment%s %s\n",
1148 iptable
->filter_bm
& MATCH_FRAGMENT_INVERSE_SET
?
1149 " not" : "", lookup_msg(fragment_value_str
,
1150 iptable
->fragment
, val_str
));
1152 if (iptable
->protocol
) {
1153 vty_out(vty
, "\t protocol %d\n",
1156 ret
= hook_call(zebra_pbr_iptable_get_stat
, iptable
, &pkts
,
1158 if (ret
&& pkts
> 0)
1159 vty_out(vty
, "\t pkts %" PRIu64
", bytes %" PRIu64
"\n",
1161 if (iptable
->action
!= ZEBRA_IPTABLES_DROP
) {
1162 struct pbr_rule_fwmark_lookup prfl
;
1164 prfl
.fwmark
= iptable
->fwmark
;
1166 hash_walk(zrouter
.rules_hash
,
1167 &zebra_pbr_rule_lookup_fwmark_walkcb
, &prfl
);
1169 struct zebra_pbr_rule
*zpr
= prfl
.ptr
;
1171 vty_out(vty
, "\t table %u, fwmark %u\n",
1172 zpr
->rule
.action
.table
,
1178 static int zebra_pbr_show_iptable_walkcb(struct hash_bucket
*bucket
, void *arg
)
1180 struct zebra_pbr_iptable
*iptable
=
1181 (struct zebra_pbr_iptable
*)bucket
->data
;
1182 struct zebra_pbr_env_display
*env
= (struct zebra_pbr_env_display
*)arg
;
1183 struct vty
*vty
= env
->vty
;
1184 struct zebra_ns
*zns
= env
->zns
;
1185 char *iptable_name
= env
->name
;
1188 zebra_pbr_show_iptable_unit(iptable
, vty
, zns
);
1189 else if (!strncmp(iptable_name
,
1190 iptable
->ipset_name
,
1191 ZEBRA_IPSET_NAME_SIZE
))
1192 zebra_pbr_show_iptable_unit(iptable
, vty
, zns
);
1193 return HASHWALK_CONTINUE
;
1196 void zebra_pbr_show_iptable(struct vty
*vty
, char *iptable_name
)
1198 struct zebra_ns
*zns
= zebra_ns_lookup(NS_DEFAULT
);
1199 struct zebra_pbr_env_display env
;
1203 env
.name
= iptable_name
;
1204 hash_walk(zrouter
.iptable_hash
, zebra_pbr_show_iptable_walkcb
, &env
);
1207 void zebra_pbr_iptable_update_interfacelist(struct stream
*s
,
1208 struct zebra_pbr_iptable
*zpi
)
1210 uint32_t i
= 0, index
;
1211 struct interface
*ifp
;
1214 for (i
= 0; i
< zpi
->nb_interface
; i
++) {
1215 STREAM_GETL(s
, index
);
1216 ifp
= if_lookup_by_index(index
, zpi
->vrf_id
);
1219 name
= XSTRDUP(MTYPE_PBR_IPTABLE_IFNAME
, ifp
->name
);
1220 listnode_add(zpi
->interface_name_list
, name
);