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"
35 #include "zebra/debug.h"
38 DEFINE_MTYPE_STATIC(ZEBRA
, PBR_IPTABLE_IFNAME
, "PBR interface list");
41 static const struct message ipset_type_msg
[] = {
42 {IPSET_NET_PORT_NET
, "net,port,net"},
43 {IPSET_NET_PORT
, "net,port"},
44 {IPSET_NET_NET
, "net,net"},
49 const struct message icmp_typecode_str
[] = {
50 { 0 << 8, "echo-reply"},
52 { 3 << 8, "network-unreachable"},
53 { (3 << 8) + 1, "host-unreachable"},
54 { (3 << 8) + 2, "protocol-unreachable"},
55 { (3 << 8) + 3, "port-unreachable"},
56 { (3 << 8) + 4, "fragmentation-needed"},
57 { (3 << 8) + 5, "source-route-failed"},
58 { (3 << 8) + 6, "network-unknown"},
59 { (3 << 8) + 7, "host-unknown"},
60 { (3 << 8) + 9, "network-prohibited"},
61 { (3 << 8) + 10, "host-prohibited"},
62 { (3 << 8) + 11, "TOS-network-unreachable"},
63 { (3 << 8) + 12, "TOS-host-unreachable"},
64 { (3 << 8) + 13, "communication-prohibited"},
65 { (3 << 8) + 14, "host-precedence-violation"},
66 { (3 << 8) + 15, "precedence-cutoff"},
67 { 4 << 8, "source-quench"},
68 { 5 << 8, "network-redirect"},
69 { (5 << 8) + 1, "host-redirect"},
70 { (5 << 8) + 2, "TOS-network-redirect"},
71 { (5 << 8) + 3, "TOS-host-redirect"},
72 { 8 << 8, "echo-request"},
74 { 9 << 8, "router-advertisement"},
75 { 10 << 8, "router-solicitation"},
76 { 11 << 8, "ttl-zero-during-transit"},
77 { (11 << 8) + 1, "ttl-zero-during-reassembly"},
78 { 12 << 8, "ip-header-bad"},
79 { (12 << 8) + 1, "required-option-missing"},
80 { 13 << 8, "timestamp-request"},
81 { 14 << 8, "timestamp-reply"},
82 { 17 << 8, "address-mask-request"},
83 { 18 << 8, "address-mask-reply"},
87 const struct message icmpv6_typecode_str
[] = {
88 { 128 << 8, "echo-request"},
89 { 129 << 8, "echo-reply"},
90 { 1 << 8, "no-route"},
91 { (1 << 8) + 1, "communication-prohibited"},
92 { (1 << 8) + 3, "address-unreachable"},
93 { (1 << 8) + 4, "port-unreachable"},
94 { (2 << 8), "packet-too-big"},
95 { 3 << 0, "ttl-zero-during-transit"},
96 { (3 << 8) + 1, "ttl-zero-during-reassembly"},
97 { 4 << 0, "bad-header"},
98 { (4 << 0) + 1, "unknown-header-type"},
99 { (4 << 0) + 2, "unknown-option"},
100 { 133 << 8, "router-solicitation"},
101 { 134 << 8, "router-advertisement"},
102 { 135 << 8, "neighbor-solicitation"},
103 { 136 << 8, "neighbor-advertisement"},
104 { 137 << 8, "redirect"},
109 static const struct message tcp_value_str
[] = {
110 {TCP_HEADER_FIN
, "FIN"},
111 {TCP_HEADER_SYN
, "SYN"},
112 {TCP_HEADER_RST
, "RST"},
113 {TCP_HEADER_PSH
, "PSH"},
114 {TCP_HEADER_ACK
, "ACK"},
115 {TCP_HEADER_URG
, "URG"},
119 static const struct message fragment_value_str
[] = {
120 {1, "dont-fragment"},
122 {4, "first-fragment"},
123 {8, "last-fragment"},
127 /* static function declarations */
128 DEFINE_HOOK(zebra_pbr_ipset_entry_get_stat
,
129 (struct zebra_pbr_ipset_entry
*ipset
, uint64_t *pkts
,
131 (ipset
, pkts
, bytes
));
133 DEFINE_HOOK(zebra_pbr_iptable_get_stat
,
134 (struct zebra_pbr_iptable
*iptable
, uint64_t *pkts
,
136 (iptable
, pkts
, bytes
));
138 DEFINE_HOOK(zebra_pbr_iptable_update
,
139 (int cmd
, struct zebra_pbr_iptable
*iptable
), (cmd
, iptable
));
141 DEFINE_HOOK(zebra_pbr_ipset_entry_update
,
142 (int cmd
, struct zebra_pbr_ipset_entry
*ipset
), (cmd
, ipset
));
144 DEFINE_HOOK(zebra_pbr_ipset_update
,
145 (int cmd
, struct zebra_pbr_ipset
*ipset
), (cmd
, ipset
));
147 /* Private functions */
149 /* Public functions */
150 void zebra_pbr_rules_free(void *arg
)
152 struct zebra_pbr_rule
*rule
;
154 rule
= (struct zebra_pbr_rule
*)arg
;
156 (void)dplane_pbr_rule_delete(rule
);
157 XFREE(MTYPE_TMP
, rule
);
160 uint32_t zebra_pbr_rules_hash_key(const void *arg
)
162 const struct zebra_pbr_rule
*rule
;
166 key
= jhash_3words(rule
->rule
.seq
, rule
->rule
.priority
,
167 rule
->rule
.action
.table
,
168 prefix_hash_key(&rule
->rule
.filter
.src_ip
));
170 if (rule
->rule
.filter
.fwmark
)
171 key
= jhash_2words(rule
->rule
.filter
.fwmark
, rule
->vrf_id
, key
);
173 key
= jhash_1word(rule
->vrf_id
, key
);
175 key
= jhash(rule
->ifname
, strlen(rule
->ifname
), key
);
177 return jhash_3words(rule
->rule
.filter
.src_port
,
178 rule
->rule
.filter
.dst_port
,
179 prefix_hash_key(&rule
->rule
.filter
.dst_ip
),
180 jhash_1word(rule
->rule
.unique
, key
));
183 bool zebra_pbr_rules_hash_equal(const void *arg1
, const void *arg2
)
185 const struct zebra_pbr_rule
*r1
, *r2
;
187 r1
= (const struct zebra_pbr_rule
*)arg1
;
188 r2
= (const struct zebra_pbr_rule
*)arg2
;
190 if (r1
->rule
.seq
!= r2
->rule
.seq
)
193 if (r1
->rule
.priority
!= r2
->rule
.priority
)
196 if (r1
->rule
.unique
!= r2
->rule
.unique
)
199 if (r1
->rule
.action
.table
!= r2
->rule
.action
.table
)
202 if (r1
->rule
.filter
.src_port
!= r2
->rule
.filter
.src_port
)
205 if (r1
->rule
.filter
.dst_port
!= r2
->rule
.filter
.dst_port
)
208 if (r1
->rule
.filter
.fwmark
!= r2
->rule
.filter
.fwmark
)
211 if (!prefix_same(&r1
->rule
.filter
.src_ip
, &r2
->rule
.filter
.src_ip
))
214 if (!prefix_same(&r1
->rule
.filter
.dst_ip
, &r2
->rule
.filter
.dst_ip
))
217 if (strcmp(r1
->rule
.ifname
, r2
->rule
.ifname
) != 0)
220 if (r1
->vrf_id
!= r2
->vrf_id
)
226 struct pbr_rule_unique_lookup
{
227 struct zebra_pbr_rule
*rule
;
229 char ifname
[INTERFACE_NAMSIZ
+ 1];
233 static int pbr_rule_lookup_unique_walker(struct hash_bucket
*b
, void *data
)
235 struct pbr_rule_unique_lookup
*pul
= data
;
236 struct zebra_pbr_rule
*rule
= b
->data
;
238 if (pul
->unique
== rule
->rule
.unique
239 && strncmp(pul
->ifname
, rule
->rule
.ifname
, INTERFACE_NAMSIZ
) == 0
240 && pul
->vrf_id
== rule
->vrf_id
) {
242 return HASHWALK_ABORT
;
245 return HASHWALK_CONTINUE
;
248 static struct zebra_pbr_rule
*
249 pbr_rule_lookup_unique(struct zebra_pbr_rule
*zrule
)
251 struct pbr_rule_unique_lookup pul
;
253 pul
.unique
= zrule
->rule
.unique
;
254 strlcpy(pul
.ifname
, zrule
->rule
.ifname
, INTERFACE_NAMSIZ
);
256 pul
.vrf_id
= zrule
->vrf_id
;
257 hash_walk(zrouter
.rules_hash
, &pbr_rule_lookup_unique_walker
, &pul
);
262 void zebra_pbr_ipset_free(void *arg
)
264 struct zebra_pbr_ipset
*ipset
;
266 ipset
= (struct zebra_pbr_ipset
*)arg
;
267 hook_call(zebra_pbr_ipset_update
, 0, ipset
);
268 XFREE(MTYPE_TMP
, ipset
);
271 uint32_t zebra_pbr_ipset_hash_key(const void *arg
)
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);
277 key
= jhash_1word(ipset
->family
, key
);
279 return jhash2(pnt
, ZEBRA_IPSET_NAME_HASH_SIZE
, key
);
282 bool zebra_pbr_ipset_hash_equal(const void *arg1
, const void *arg2
)
284 const struct zebra_pbr_ipset
*r1
, *r2
;
286 r1
= (const struct zebra_pbr_ipset
*)arg1
;
287 r2
= (const struct zebra_pbr_ipset
*)arg2
;
289 if (r1
->type
!= r2
->type
)
291 if (r1
->unique
!= r2
->unique
)
293 if (r1
->vrf_id
!= r2
->vrf_id
)
295 if (r1
->family
!= r2
->family
)
298 if (strncmp(r1
->ipset_name
, r2
->ipset_name
,
299 ZEBRA_IPSET_NAME_SIZE
))
304 void zebra_pbr_ipset_entry_free(void *arg
)
306 struct zebra_pbr_ipset_entry
*ipset
;
308 ipset
= (struct zebra_pbr_ipset_entry
*)arg
;
310 hook_call(zebra_pbr_ipset_entry_update
, 0, ipset
);
312 XFREE(MTYPE_TMP
, ipset
);
315 uint32_t zebra_pbr_ipset_entry_hash_key(const void *arg
)
317 const struct zebra_pbr_ipset_entry
*ipset
;
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
);
333 bool zebra_pbr_ipset_entry_hash_equal(const void *arg1
, const void *arg2
)
335 const struct zebra_pbr_ipset_entry
*r1
, *r2
;
337 r1
= (const struct zebra_pbr_ipset_entry
*)arg1
;
338 r2
= (const struct zebra_pbr_ipset_entry
*)arg2
;
340 if (r1
->unique
!= r2
->unique
)
343 if (!prefix_same(&r1
->src
, &r2
->src
))
346 if (!prefix_same(&r1
->dst
, &r2
->dst
))
349 if (r1
->src_port_min
!= r2
->src_port_min
)
352 if (r1
->src_port_max
!= r2
->src_port_max
)
355 if (r1
->dst_port_min
!= r2
->dst_port_min
)
358 if (r1
->dst_port_max
!= r2
->dst_port_max
)
361 if (r1
->proto
!= r2
->proto
)
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
370 static void _zebra_pbr_iptable_free_all(void *arg
, bool all
)
372 struct zebra_pbr_iptable
*iptable
;
373 struct listnode
*node
, *nnode
;
376 iptable
= (struct zebra_pbr_iptable
*)arg
;
379 hook_call(zebra_pbr_iptable_update
, 0, iptable
);
381 if (iptable
->interface_name_list
) {
382 for (ALL_LIST_ELEMENTS(iptable
->interface_name_list
, node
,
384 XFREE(MTYPE_PBR_IPTABLE_IFNAME
, name
);
385 list_delete_node(iptable
->interface_name_list
, node
);
387 list_delete(&iptable
->interface_name_list
);
389 XFREE(MTYPE_TMP
, iptable
);
392 void zebra_pbr_iptable_free(void *arg
)
394 _zebra_pbr_iptable_free_all(arg
, false);
397 uint32_t zebra_pbr_iptable_hash_key(const void *arg
)
399 const struct zebra_pbr_iptable
*iptable
= arg
;
400 uint32_t *pnt
= (uint32_t *)&(iptable
->ipset_name
);
403 key
= jhash2(pnt
, ZEBRA_IPSET_NAME_HASH_SIZE
,
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
);
417 return jhash_3words(iptable
->filter_bm
, iptable
->type
,
418 iptable
->unique
, key
);
421 bool zebra_pbr_iptable_hash_equal(const void *arg1
, const void *arg2
)
423 const struct zebra_pbr_iptable
*r1
, *r2
;
425 r1
= (const struct zebra_pbr_iptable
*)arg1
;
426 r2
= (const struct zebra_pbr_iptable
*)arg2
;
428 if (r1
->vrf_id
!= r2
->vrf_id
)
430 if (r1
->type
!= r2
->type
)
432 if (r1
->unique
!= r2
->unique
)
434 if (r1
->filter_bm
!= r2
->filter_bm
)
436 if (r1
->fwmark
!= r2
->fwmark
)
438 if (r1
->action
!= r2
->action
)
440 if (strncmp(r1
->ipset_name
, r2
->ipset_name
,
441 ZEBRA_IPSET_NAME_SIZE
))
443 if (r1
->family
!= r2
->family
)
445 if (r1
->flow_label
!= r2
->flow_label
)
447 if (r1
->pkt_len_min
!= r2
->pkt_len_min
)
449 if (r1
->pkt_len_max
!= r2
->pkt_len_max
)
451 if (r1
->tcp_flags
!= r2
->tcp_flags
)
453 if (r1
->tcp_mask_flags
!= r2
->tcp_mask_flags
)
455 if (r1
->dscp_value
!= r2
->dscp_value
)
457 if (r1
->fragment
!= r2
->fragment
)
459 if (r1
->protocol
!= r2
->protocol
)
464 static void *pbr_rule_alloc_intern(void *arg
)
466 struct zebra_pbr_rule
*zpr
;
467 struct zebra_pbr_rule
*new;
469 zpr
= (struct zebra_pbr_rule
*)arg
;
471 new = XCALLOC(MTYPE_TMP
, sizeof(*new));
473 memcpy(new, zpr
, sizeof(*zpr
));
478 static int pbr_rule_release(struct zebra_pbr_rule
*rule
)
480 struct zebra_pbr_rule
*lookup
;
482 lookup
= hash_lookup(zrouter
.rules_hash
, rule
);
487 hash_release(zrouter
.rules_hash
, lookup
);
488 XFREE(MTYPE_TMP
, lookup
);
493 void zebra_pbr_add_rule(struct zebra_pbr_rule
*rule
)
495 struct zebra_pbr_rule
*found
;
498 * Check if we already have it (this checks via a unique ID, walking
499 * over the hash table, not via a hash operation).
501 found
= pbr_rule_lookup_unique(rule
);
503 /* If found, this is an update */
505 if (IS_ZEBRA_DEBUG_PBR
)
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
);
511 (void)dplane_pbr_rule_update(found
, rule
);
513 if (pbr_rule_release(found
))
515 "%s: Rule being updated we know nothing about",
516 __PRETTY_FUNCTION__
);
519 if (IS_ZEBRA_DEBUG_PBR
)
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
);
525 (void)dplane_pbr_rule_add(rule
);
528 (void)hash_get(zrouter
.rules_hash
, rule
, pbr_rule_alloc_intern
);
531 void zebra_pbr_del_rule(struct zebra_pbr_rule
*rule
)
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
);
538 (void)dplane_pbr_rule_delete(rule
);
540 if (pbr_rule_release(rule
))
541 zlog_debug("%s: Rule being deleted we know nothing about",
545 void zebra_pbr_process_iptable(struct zebra_dplane_ctx
*ctx
)
548 struct zebra_pbr_iptable ipt
;
550 if (dplane_ctx_get_op(ctx
) == DPLANE_OP_IPTABLE_ADD
)
555 if (dplane_ctx_get_pbr_iptable(ctx
, &ipt
)) {
556 ret
= hook_call(zebra_pbr_iptable_update
, mode
, &ipt
);
558 dplane_ctx_set_status(ctx
,
559 ZEBRA_DPLANE_REQUEST_SUCCESS
);
562 dplane_ctx_set_status(ctx
, ZEBRA_DPLANE_REQUEST_FAILURE
);
565 void zebra_pbr_process_ipset(struct zebra_dplane_ctx
*ctx
)
568 struct zebra_pbr_ipset ipset
;
570 if (dplane_ctx_get_op(ctx
) == DPLANE_OP_IPSET_ADD
)
574 if (dplane_ctx_get_pbr_ipset(ctx
, &ipset
)) {
575 ret
= hook_call(zebra_pbr_ipset_update
, mode
, &ipset
);
577 dplane_ctx_set_status(ctx
,
578 ZEBRA_DPLANE_REQUEST_SUCCESS
);
581 dplane_ctx_set_status(ctx
, ZEBRA_DPLANE_REQUEST_FAILURE
);
584 void zebra_pbr_process_ipset_entry(struct zebra_dplane_ctx
*ctx
)
587 struct zebra_pbr_ipset_entry ipset_entry
;
588 struct zebra_pbr_ipset ipset
;
590 if (dplane_ctx_get_op(ctx
) == DPLANE_OP_IPSET_ENTRY_ADD
)
595 if (!dplane_ctx_get_pbr_ipset_entry(ctx
, &ipset_entry
))
597 if (!dplane_ctx_get_pbr_ipset(ctx
, &ipset
))
599 ipset_entry
.backpointer
= &ipset
;
601 ret
= hook_call(zebra_pbr_ipset_entry_update
, mode
, &ipset_entry
);
603 dplane_ctx_set_status(ctx
, ZEBRA_DPLANE_REQUEST_SUCCESS
);
605 dplane_ctx_set_status(ctx
, ZEBRA_DPLANE_REQUEST_FAILURE
);
608 static void zebra_pbr_cleanup_rules(struct hash_bucket
*b
, void *data
)
610 struct zebra_pbr_rule
*rule
= b
->data
;
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
);
619 "%s: Rule seq: %u is being cleaned but we can't find it in our tables",
620 __func__
, rule
->rule
.seq
);
624 static void zebra_pbr_cleanup_ipset(struct hash_bucket
*b
, void *data
)
626 struct zebra_pbr_ipset
*ipset
= b
->data
;
629 if (ipset
->sock
== *sock
) {
630 if (hash_release(zrouter
.ipset_hash
, ipset
))
631 zebra_pbr_ipset_free(ipset
);
633 hook_call(zebra_pbr_ipset_update
, 0, ipset
);
637 static void zebra_pbr_cleanup_ipset_entry(struct hash_bucket
*b
, void *data
)
639 struct zebra_pbr_ipset_entry
*ipset
= b
->data
;
642 if (ipset
->sock
== *sock
) {
643 if (hash_release(zrouter
.ipset_entry_hash
, ipset
))
644 zebra_pbr_ipset_entry_free(ipset
);
646 hook_call(zebra_pbr_ipset_entry_update
, 0, ipset
);
650 static void zebra_pbr_cleanup_iptable(struct hash_bucket
*b
, void *data
)
652 struct zebra_pbr_iptable
*iptable
= b
->data
;
655 if (iptable
->sock
== *sock
) {
656 if (hash_release(zrouter
.iptable_hash
, iptable
))
657 _zebra_pbr_iptable_free_all(iptable
, true);
659 hook_call(zebra_pbr_iptable_update
, 0, iptable
);
663 static int zebra_pbr_client_close_cleanup(struct zserv
*client
)
665 int sock
= client
->sock
;
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
,
673 hash_iterate(zrouter
.ipset_hash
, zebra_pbr_cleanup_ipset
, &sock
);
677 void zebra_pbr_init(void)
679 hook_register(zserv_client_close
, zebra_pbr_client_close_cleanup
);
682 static void *pbr_ipset_alloc_intern(void *arg
)
684 struct zebra_pbr_ipset
*zpi
;
685 struct zebra_pbr_ipset
*new;
687 zpi
= (struct zebra_pbr_ipset
*)arg
;
689 new = XCALLOC(MTYPE_TMP
, sizeof(struct zebra_pbr_ipset
));
691 memcpy(new, zpi
, sizeof(*zpi
));
696 void zebra_pbr_create_ipset(struct zebra_pbr_ipset
*ipset
)
698 (void)hash_get(zrouter
.ipset_hash
, ipset
, pbr_ipset_alloc_intern
);
699 (void)dplane_pbr_ipset_add(ipset
);
702 void zebra_pbr_destroy_ipset(struct zebra_pbr_ipset
*ipset
)
704 struct zebra_pbr_ipset
*lookup
;
706 lookup
= hash_lookup(zrouter
.ipset_hash
, ipset
);
707 (void)dplane_pbr_ipset_delete(ipset
);
709 hash_release(zrouter
.ipset_hash
, lookup
);
710 XFREE(MTYPE_TMP
, lookup
);
713 "%s: IPSet Entry being deleted we know nothing about",
717 struct pbr_ipset_name_lookup
{
718 struct zebra_pbr_ipset
*ipset
;
719 char ipset_name
[ZEBRA_IPSET_NAME_SIZE
];
722 const char *zebra_pbr_ipset_type2str(uint32_t type
)
724 return lookup_msg(ipset_type_msg
, type
,
725 "Unrecognized IPset Type");
728 static int zebra_pbr_ipset_pername_walkcb(struct hash_bucket
*bucket
, void *arg
)
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
;
734 if (!strncmp(pinl
->ipset_name
, zpi
->ipset_name
,
735 ZEBRA_IPSET_NAME_SIZE
)) {
737 return HASHWALK_ABORT
;
739 return HASHWALK_CONTINUE
;
742 struct zebra_pbr_ipset
*zebra_pbr_lookup_ipset_pername(char *ipsetname
)
744 struct pbr_ipset_name_lookup pinl
;
745 struct pbr_ipset_name_lookup
*ptr
= &pinl
;
749 memset(ptr
, 0, sizeof(struct pbr_ipset_name_lookup
));
750 snprintf((char *)ptr
->ipset_name
, ZEBRA_IPSET_NAME_SIZE
, "%s",
752 hash_walk(zrouter
.ipset_hash
, zebra_pbr_ipset_pername_walkcb
, ptr
);
756 static void *pbr_ipset_entry_alloc_intern(void *arg
)
758 struct zebra_pbr_ipset_entry
*zpi
;
759 struct zebra_pbr_ipset_entry
*new;
761 zpi
= (struct zebra_pbr_ipset_entry
*)arg
;
763 new = XCALLOC(MTYPE_TMP
, sizeof(struct zebra_pbr_ipset_entry
));
765 memcpy(new, zpi
, sizeof(*zpi
));
770 void zebra_pbr_add_ipset_entry(struct zebra_pbr_ipset_entry
*ipset
)
772 (void)hash_get(zrouter
.ipset_entry_hash
, ipset
,
773 pbr_ipset_entry_alloc_intern
);
774 (void)dplane_pbr_ipset_entry_add(ipset
);
777 void zebra_pbr_del_ipset_entry(struct zebra_pbr_ipset_entry
*ipset
)
779 struct zebra_pbr_ipset_entry
*lookup
;
781 lookup
= hash_lookup(zrouter
.ipset_entry_hash
, ipset
);
782 (void)dplane_pbr_ipset_entry_delete(ipset
);
784 hash_release(zrouter
.ipset_entry_hash
, lookup
);
785 XFREE(MTYPE_TMP
, lookup
);
787 zlog_debug("%s: IPSet being deleted we know nothing about",
791 static void *pbr_iptable_alloc_intern(void *arg
)
793 struct zebra_pbr_iptable
*zpi
;
794 struct zebra_pbr_iptable
*new;
798 zpi
= (struct zebra_pbr_iptable
*)arg
;
800 new = XCALLOC(MTYPE_TMP
, sizeof(struct zebra_pbr_iptable
));
802 /* Deep structure copy */
803 memcpy(new, zpi
, sizeof(*zpi
));
804 new->interface_name_list
= list_new();
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
));
815 void zebra_pbr_add_iptable(struct zebra_pbr_iptable
*iptable
)
817 (void)hash_get(zrouter
.iptable_hash
, iptable
, pbr_iptable_alloc_intern
);
818 (void)dplane_pbr_iptable_add(iptable
);
821 void zebra_pbr_del_iptable(struct zebra_pbr_iptable
*iptable
)
823 struct zebra_pbr_iptable
*lookup
;
825 lookup
= hash_lookup(zrouter
.iptable_hash
, iptable
);
826 (void)dplane_pbr_iptable_delete(iptable
);
828 struct listnode
*node
, *nnode
;
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
,
838 list_delete(&iptable
->interface_name_list
);
839 XFREE(MTYPE_TMP
, lookup
);
841 zlog_debug("%s: IPTable being deleted we know nothing about",
846 * Handle success or failure of rule (un)install in the kernel.
848 void zebra_pbr_dplane_result(struct zebra_dplane_ctx
*ctx
)
850 enum zebra_dplane_result res
;
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
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
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
);
895 EC_ZEBRA_PBR_RULE_UPDATE
,
896 "Context received in pbr rule dplane result handler with incorrect OP code (%u)",
900 dplane_ctx_fini(&ctx
);
904 * Handle rule delete notification from kernel.
906 int kernel_pbr_rule_del(struct zebra_pbr_rule
*rule
)
911 struct zebra_pbr_ipset_entry_unique_display
{
912 struct zebra_pbr_ipset
*zpi
;
914 struct zebra_ns
*zns
;
917 struct zebra_pbr_env_display
{
918 struct zebra_ns
*zns
;
923 static const char *zebra_pbr_prefix2str(union prefixconstptr pu
,
926 const struct prefix
*p
= pu
.p
;
927 char buf
[PREFIX2STR_BUFFER
];
929 if ((p
->family
== AF_INET
&& p
->prefixlen
== IPV4_MAX_PREFIXLEN
) ||
930 (p
->family
== AF_INET6
&& p
->prefixlen
== IPV6_MAX_PREFIXLEN
)) {
931 snprintf(str
, size
, "%s", inet_ntop(p
->family
, &p
->u
.prefix
,
932 buf
, PREFIX2STR_BUFFER
));
935 return prefix2str(pu
, str
, size
);
938 static void zebra_pbr_display_icmp(struct vty
*vty
,
939 struct zebra_pbr_ipset_entry
*zpie
)
941 char decoded_str
[20];
943 struct zebra_pbr_ipset
*zpi
;
945 zpi
= zpie
->backpointer
;
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
);
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
,
966 static void zebra_pbr_display_port(struct vty
*vty
, uint32_t filter_bm
,
967 uint16_t port_min
, uint16_t port_max
,
970 if (!(filter_bm
& PBR_FILTER_PROTO
)) {
972 vty_out(vty
, ":udp/tcp:%d-%d",
975 vty_out(vty
, ":udp/tcp:%d",
979 vty_out(vty
, ":proto %d:%d-%d",
980 proto
, port_min
, port_max
);
982 vty_out(vty
, ":proto %d:%d",
987 static int zebra_pbr_show_ipset_entry_walkcb(struct hash_bucket
*bucket
,
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;
999 if (zpie
->backpointer
!= zpi
)
1000 return HASHWALK_CONTINUE
;
1002 if ((zpi
->type
== IPSET_NET_NET
) ||
1003 (zpi
->type
== IPSET_NET_PORT_NET
)) {
1004 char buf
[PREFIX_STRLEN
];
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
,
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
,
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
];
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
);
1033 if (zpie
->filter_bm
& PBR_FILTER_SRC_PORT
&&
1034 zpie
->proto
!= IPPROTO_ICMP
)
1035 zebra_pbr_display_port(vty
, zpie
->filter_bm
,
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
);
1043 if (zpie
->filter_bm
& PBR_FILTER_DST_PORT
&&
1044 zpie
->proto
!= IPPROTO_ICMP
)
1045 zebra_pbr_display_port(vty
, zpie
->filter_bm
,
1049 if (zpie
->proto
== IPPROTO_ICMP
)
1050 zebra_pbr_display_icmp(vty
, zpie
);
1052 vty_out(vty
, " (%u)\n", zpie
->unique
);
1054 ret
= hook_call(zebra_pbr_ipset_entry_get_stat
, zpie
, &pkts
,
1056 if (ret
&& pkts
> 0)
1057 vty_out(vty
, "\t pkts %" PRIu64
", bytes %" PRIu64
"\n",
1059 return HASHWALK_CONTINUE
;
1062 static int zebra_pbr_show_ipset_walkcb(struct hash_bucket
*bucket
, void *arg
)
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
;
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
));
1077 hash_walk(zrouter
.ipset_entry_hash
, zebra_pbr_show_ipset_entry_walkcb
,
1080 return HASHWALK_CONTINUE
;
1083 size_t zebra_pbr_tcpflags_snprintf(char *buffer
, size_t len
,
1086 size_t len_written
= 0;
1087 static struct message nt
= {0};
1088 const struct message
*pnt
;
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
,
1105 void zebra_pbr_show_ipset_list(struct vty
*vty
, char *ipsetname
)
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
;
1113 zpi
= zebra_pbr_lookup_ipset_pername(ipsetname
);
1115 vty_out(vty
, "No IPset %s found\n", ipsetname
);
1118 vty_out(vty
, "IPset %s type %s family %s\n", ipsetname
,
1119 zebra_pbr_ipset_type2str(zpi
->type
),
1120 family2str(zpi
->family
));
1124 hash_walk(zrouter
.ipset_entry_hash
,
1125 zebra_pbr_show_ipset_entry_walkcb
, &unique
);
1128 uniqueipset
.zns
= zns
;
1129 uniqueipset
.vty
= vty
;
1130 uniqueipset
.name
= NULL
;
1131 hash_walk(zrouter
.ipset_hash
, zebra_pbr_show_ipset_walkcb
,
1135 struct pbr_rule_fwmark_lookup
{
1136 struct zebra_pbr_rule
*ptr
;
1140 static int zebra_pbr_rule_lookup_fwmark_walkcb(struct hash_bucket
*bucket
,
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
;
1147 if (iprule
->fwmark
== zpr
->rule
.filter
.fwmark
) {
1149 return HASHWALK_ABORT
;
1151 return HASHWALK_CONTINUE
;
1154 static void zebra_pbr_show_iptable_unit(struct zebra_pbr_iptable
*iptable
,
1156 struct zebra_ns
*zns
)
1159 uint64_t pkts
= 0, bytes
= 0;
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",
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");
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
);
1180 vty_out(vty
, "\t pkt len [%u;%u]\n",
1181 iptable
->pkt_len_min
,
1182 iptable
->pkt_len_max
);
1184 if (iptable
->tcp_flags
|| iptable
->tcp_mask_flags
) {
1185 char tcp_flag_str
[64];
1186 char tcp_flag_mask_str
[64];
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
);
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
);
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
);
1208 if (iptable
->fragment
) {
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
));
1217 if (iptable
->protocol
) {
1218 vty_out(vty
, "\t protocol %d\n",
1221 ret
= hook_call(zebra_pbr_iptable_get_stat
, iptable
, &pkts
,
1223 if (ret
&& pkts
> 0)
1224 vty_out(vty
, "\t pkts %" PRIu64
", bytes %" PRIu64
"\n",
1226 if (iptable
->action
!= ZEBRA_IPTABLES_DROP
) {
1227 struct pbr_rule_fwmark_lookup prfl
;
1229 prfl
.fwmark
= iptable
->fwmark
;
1231 hash_walk(zrouter
.rules_hash
,
1232 &zebra_pbr_rule_lookup_fwmark_walkcb
, &prfl
);
1234 struct zebra_pbr_rule
*zpr
= prfl
.ptr
;
1236 vty_out(vty
, "\t table %u, fwmark %u\n",
1237 zpr
->rule
.action
.table
,
1243 static int zebra_pbr_show_iptable_walkcb(struct hash_bucket
*bucket
, void *arg
)
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
;
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
;
1261 void zebra_pbr_show_iptable(struct vty
*vty
, char *iptable_name
)
1263 struct zebra_ns
*zns
= zebra_ns_lookup(NS_DEFAULT
);
1264 struct zebra_pbr_env_display env
;
1268 env
.name
= iptable_name
;
1269 hash_walk(zrouter
.iptable_hash
, zebra_pbr_show_iptable_walkcb
, &env
);
1272 void zebra_pbr_iptable_update_interfacelist(struct stream
*s
,
1273 struct zebra_pbr_iptable
*zpi
)
1275 uint32_t i
= 0, index
;
1276 struct interface
*ifp
;
1279 for (i
= 0; i
< zpi
->nb_interface
; i
++) {
1280 STREAM_GETL(s
, index
);
1281 ifp
= if_lookup_by_index(index
, zpi
->vrf_id
);
1284 name
= XSTRDUP(MTYPE_PBR_IPTABLE_IFNAME
, ifp
->name
);
1285 listnode_add(zpi
->interface_name_list
, name
);