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
27 #include "zebra/zebra_pbr.h"
29 #include "zebra/zapi_msg.h"
33 /* static function declarations */
35 /* Private functions */
37 /* Public functions */
38 void zebra_pbr_rules_free(void *arg
)
40 struct zebra_pbr_rule
*rule
;
42 rule
= (struct zebra_pbr_rule
*)arg
;
44 kernel_del_pbr_rule(rule
);
45 XFREE(MTYPE_TMP
, rule
);
48 uint32_t zebra_pbr_rules_hash_key(void *arg
)
50 struct zebra_pbr_rule
*rule
;
53 rule
= (struct zebra_pbr_rule
*)arg
;
54 key
= jhash_3words(rule
->rule
.seq
, rule
->rule
.priority
,
55 rule
->rule
.action
.table
,
56 prefix_hash_key(&rule
->rule
.filter
.src_ip
));
58 key
= jhash_1word(rule
->ifp
->ifindex
, key
);
60 key
= jhash_1word(0, key
);
62 if (rule
->rule
.filter
.fwmark
)
63 key
= jhash_1word(rule
->rule
.filter
.fwmark
, key
);
65 key
= jhash_1word(0, key
);
66 return jhash_3words(rule
->rule
.filter
.src_port
,
67 rule
->rule
.filter
.dst_port
,
68 prefix_hash_key(&rule
->rule
.filter
.dst_ip
),
69 jhash_1word(rule
->rule
.unique
, key
));
72 int zebra_pbr_rules_hash_equal(const void *arg1
, const void *arg2
)
74 const struct zebra_pbr_rule
*r1
, *r2
;
76 r1
= (const struct zebra_pbr_rule
*)arg1
;
77 r2
= (const struct zebra_pbr_rule
*)arg2
;
79 if (r1
->rule
.seq
!= r2
->rule
.seq
)
82 if (r1
->rule
.priority
!= r2
->rule
.priority
)
85 if (r1
->rule
.unique
!= r2
->rule
.unique
)
88 if (r1
->rule
.action
.table
!= r2
->rule
.action
.table
)
91 if (r1
->rule
.filter
.src_port
!= r2
->rule
.filter
.src_port
)
94 if (r1
->rule
.filter
.dst_port
!= r2
->rule
.filter
.dst_port
)
97 if (r1
->rule
.filter
.fwmark
!= r2
->rule
.filter
.fwmark
)
100 if (!prefix_same(&r1
->rule
.filter
.src_ip
, &r2
->rule
.filter
.src_ip
))
103 if (!prefix_same(&r1
->rule
.filter
.dst_ip
, &r2
->rule
.filter
.dst_ip
))
106 if (r1
->ifp
!= r2
->ifp
)
112 struct pbr_rule_unique_lookup
{
113 struct zebra_pbr_rule
*rule
;
115 struct interface
*ifp
;
118 static int pbr_rule_lookup_unique_walker(struct hash_backet
*b
, void *data
)
120 struct pbr_rule_unique_lookup
*pul
= data
;
121 struct zebra_pbr_rule
*rule
= b
->data
;
123 if (pul
->unique
== rule
->rule
.unique
&& pul
->ifp
== rule
->ifp
) {
125 return HASHWALK_ABORT
;
128 return HASHWALK_CONTINUE
;
131 static struct zebra_pbr_rule
*pbr_rule_lookup_unique(struct zebra_ns
*zns
,
133 struct interface
*ifp
)
135 struct pbr_rule_unique_lookup pul
;
140 hash_walk(zns
->rules_hash
, &pbr_rule_lookup_unique_walker
, &pul
);
145 void zebra_pbr_ipset_free(void *arg
)
147 struct zebra_pbr_ipset
*ipset
;
149 ipset
= (struct zebra_pbr_ipset
*)arg
;
151 XFREE(MTYPE_TMP
, ipset
);
154 uint32_t zebra_pbr_ipset_hash_key(void *arg
)
156 struct zebra_pbr_ipset
*ipset
= (struct zebra_pbr_ipset
*)arg
;
157 uint32_t *pnt
= (uint32_t *)&ipset
->ipset_name
;
159 return jhash2(pnt
, ZEBRA_IPSET_NAME_HASH_SIZE
, 0x63ab42de);
162 int zebra_pbr_ipset_hash_equal(const void *arg1
, const void *arg2
)
164 const struct zebra_pbr_ipset
*r1
, *r2
;
166 r1
= (const struct zebra_pbr_ipset
*)arg1
;
167 r2
= (const struct zebra_pbr_ipset
*)arg2
;
169 if (r1
->type
!= r2
->type
)
171 if (r1
->unique
!= r2
->unique
)
173 if (strncmp(r1
->ipset_name
, r2
->ipset_name
,
174 ZEBRA_IPSET_NAME_SIZE
))
179 void zebra_pbr_ipset_entry_free(void *arg
)
181 struct zebra_pbr_ipset_entry
*ipset
;
183 ipset
= (struct zebra_pbr_ipset_entry
*)arg
;
185 XFREE(MTYPE_TMP
, ipset
);
188 uint32_t zebra_pbr_ipset_entry_hash_key(void *arg
)
190 struct zebra_pbr_ipset_entry
*ipset
;
193 ipset
= (struct zebra_pbr_ipset_entry
*)arg
;
194 key
= prefix_hash_key(&ipset
->src
);
195 key
= jhash_1word(ipset
->unique
, key
);
196 key
= jhash_1word(prefix_hash_key(&ipset
->dst
), key
);
201 int zebra_pbr_ipset_entry_hash_equal(const void *arg1
, const void *arg2
)
203 const struct zebra_pbr_ipset_entry
*r1
, *r2
;
205 r1
= (const struct zebra_pbr_ipset_entry
*)arg1
;
206 r2
= (const struct zebra_pbr_ipset_entry
*)arg2
;
208 if (r1
->unique
!= r2
->unique
)
211 if (!prefix_same(&r1
->src
, &r2
->src
))
214 if (!prefix_same(&r1
->dst
, &r2
->dst
))
220 void zebra_pbr_iptable_free(void *arg
)
222 struct zebra_pbr_iptable
*iptable
;
224 iptable
= (struct zebra_pbr_iptable
*)arg
;
226 XFREE(MTYPE_TMP
, iptable
);
229 uint32_t zebra_pbr_iptable_hash_key(void *arg
)
231 struct zebra_pbr_iptable
*iptable
= (struct zebra_pbr_iptable
*)arg
;
232 uint32_t *pnt
= (uint32_t *)&(iptable
->ipset_name
);
235 key
= jhash2(pnt
, ZEBRA_IPSET_NAME_HASH_SIZE
,
237 key
= jhash_1word(iptable
->fwmark
, key
);
238 return jhash_3words(iptable
->filter_bm
, iptable
->type
,
239 iptable
->unique
, key
);
242 int zebra_pbr_iptable_hash_equal(const void *arg1
, const void *arg2
)
244 const struct zebra_pbr_iptable
*r1
, *r2
;
246 r1
= (const struct zebra_pbr_iptable
*)arg1
;
247 r2
= (const struct zebra_pbr_iptable
*)arg2
;
249 if (r1
->type
!= r2
->type
)
251 if (r1
->unique
!= r2
->unique
)
253 if (r1
->filter_bm
!= r2
->filter_bm
)
255 if (r1
->fwmark
!= r2
->fwmark
)
257 if (r1
->action
!= r2
->action
)
259 if (strncmp(r1
->ipset_name
, r2
->ipset_name
,
260 ZEBRA_IPSET_NAME_SIZE
))
265 static void *pbr_rule_alloc_intern(void *arg
)
267 struct zebra_pbr_rule
*zpr
;
268 struct zebra_pbr_rule
*new;
270 zpr
= (struct zebra_pbr_rule
*)arg
;
272 new = XCALLOC(MTYPE_TMP
, sizeof(*new));
274 memcpy(new, zpr
, sizeof(*zpr
));
279 void zebra_pbr_add_rule(struct zebra_ns
*zns
, struct zebra_pbr_rule
*rule
)
281 struct zebra_pbr_rule
*unique
=
282 pbr_rule_lookup_unique(zns
, rule
->rule
.unique
, rule
->ifp
);
284 (void)hash_get(zns
->rules_hash
, rule
, pbr_rule_alloc_intern
);
285 kernel_add_pbr_rule(rule
);
288 * Rule Replace semantics, if we have an old, install the
289 * new rule, look above, and then delete the old
292 zebra_pbr_del_rule(zns
, unique
);
295 void zebra_pbr_del_rule(struct zebra_ns
*zns
, struct zebra_pbr_rule
*rule
)
297 struct zebra_pbr_rule
*lookup
;
299 lookup
= hash_lookup(zns
->rules_hash
, rule
);
300 kernel_del_pbr_rule(rule
);
303 hash_release(zns
->rules_hash
, lookup
);
304 XFREE(MTYPE_TMP
, lookup
);
306 zlog_warn("%s: Rule being deleted we know nothing about",
307 __PRETTY_FUNCTION__
);
310 static void zebra_pbr_cleanup_rules(struct hash_backet
*b
, void *data
)
312 struct zebra_ns
*zns
= zebra_ns_lookup(NS_DEFAULT
);
313 struct zebra_pbr_rule
*rule
= b
->data
;
316 if (rule
->sock
== *sock
) {
317 kernel_del_pbr_rule(rule
);
318 hash_release(zns
->rules_hash
, rule
);
319 XFREE(MTYPE_TMP
, rule
);
323 void zebra_pbr_client_close_cleanup(int sock
)
325 struct zebra_ns
*zns
= zebra_ns_lookup(NS_DEFAULT
);
327 hash_iterate(zns
->rules_hash
, zebra_pbr_cleanup_rules
, &sock
);
330 static void *pbr_ipset_alloc_intern(void *arg
)
332 struct zebra_pbr_ipset
*zpi
;
333 struct zebra_pbr_ipset
*new;
335 zpi
= (struct zebra_pbr_ipset
*)arg
;
337 new = XCALLOC(MTYPE_TMP
, sizeof(struct zebra_pbr_ipset
));
339 memcpy(new, zpi
, sizeof(*zpi
));
344 void zebra_pbr_create_ipset(struct zebra_ns
*zns
,
345 struct zebra_pbr_ipset
*ipset
)
347 (void)hash_get(zns
->ipset_hash
, ipset
, pbr_ipset_alloc_intern
);
353 void zebra_pbr_destroy_ipset(struct zebra_ns
*zns
,
354 struct zebra_pbr_ipset
*ipset
)
356 struct zebra_pbr_ipset
*lookup
;
358 lookup
= hash_lookup(zns
->ipset_hash
, ipset
);
360 * - Netlink destroy from kernel
361 * - ?? destroy ipset entries before
364 XFREE(MTYPE_TMP
, lookup
);
366 zlog_warn("%s: IPSet Entry being deleted we know nothing about",
367 __PRETTY_FUNCTION__
);
370 struct pbr_ipset_name_lookup
{
371 struct zebra_pbr_ipset
*ipset
;
372 char ipset_name
[ZEBRA_IPSET_NAME_SIZE
];
375 static int zebra_pbr_ipset_pername_walkcb(struct hash_backet
*backet
, void *arg
)
377 struct pbr_ipset_name_lookup
*pinl
=
378 (struct pbr_ipset_name_lookup
*)arg
;
379 struct zebra_pbr_ipset
*zpi
= (struct zebra_pbr_ipset
*)backet
->data
;
381 if (!strncmp(pinl
->ipset_name
, zpi
->ipset_name
,
382 ZEBRA_IPSET_NAME_SIZE
)) {
384 return HASHWALK_ABORT
;
386 return HASHWALK_CONTINUE
;
389 struct zebra_pbr_ipset
*zebra_pbr_lookup_ipset_pername(struct zebra_ns
*zns
,
392 struct pbr_ipset_name_lookup pinl
;
393 struct pbr_ipset_name_lookup
*ptr
= &pinl
;
397 memset(ptr
, 0, sizeof(struct pbr_ipset_name_lookup
));
398 snprintf((char *)ptr
->ipset_name
, ZEBRA_IPSET_NAME_SIZE
, "%s",
400 hash_walk(zns
->ipset_hash
, zebra_pbr_ipset_pername_walkcb
, ptr
);
404 static void *pbr_ipset_entry_alloc_intern(void *arg
)
406 struct zebra_pbr_ipset_entry
*zpi
;
407 struct zebra_pbr_ipset_entry
*new;
409 zpi
= (struct zebra_pbr_ipset_entry
*)arg
;
411 new = XCALLOC(MTYPE_TMP
, sizeof(struct zebra_pbr_ipset_entry
));
413 memcpy(new, zpi
, sizeof(*zpi
));
418 void zebra_pbr_add_ipset_entry(struct zebra_ns
*zns
,
419 struct zebra_pbr_ipset_entry
*ipset
)
421 (void)hash_get(zns
->ipset_entry_hash
, ipset
,
422 pbr_ipset_entry_alloc_intern
);
424 * - attach to ipset list
425 * - Netlink add to kernel
429 void zebra_pbr_del_ipset_entry(struct zebra_ns
*zns
,
430 struct zebra_pbr_ipset_entry
*ipset
)
432 struct zebra_pbr_ipset_entry
*lookup
;
434 lookup
= hash_lookup(zns
->ipset_entry_hash
, ipset
);
437 * - detach from ipset list
438 * - ?? if no more entres, delete ipset
441 XFREE(MTYPE_TMP
, lookup
);
443 zlog_warn("%s: IPSet being deleted we know nothing about",
444 __PRETTY_FUNCTION__
);
447 static void *pbr_iptable_alloc_intern(void *arg
)
449 struct zebra_pbr_iptable
*zpi
;
450 struct zebra_pbr_iptable
*new;
452 zpi
= (struct zebra_pbr_iptable
*)arg
;
454 new = XCALLOC(MTYPE_TMP
, sizeof(struct zebra_pbr_iptable
));
456 memcpy(new, zpi
, sizeof(*zpi
));
461 void zebra_pbr_add_iptable(struct zebra_ns
*zns
,
462 struct zebra_pbr_iptable
*iptable
)
464 (void)hash_get(zns
->iptable_hash
, iptable
,
465 pbr_iptable_alloc_intern
);
466 /* TODO call netlink layer */
469 void zebra_pbr_del_iptable(struct zebra_ns
*zns
,
470 struct zebra_pbr_iptable
*iptable
)
472 struct zebra_pbr_ipset_entry
*lookup
;
474 lookup
= hash_lookup(zns
->iptable_hash
, iptable
);
476 * - call netlink layer
477 * - detach from iptable list
480 XFREE(MTYPE_TMP
, lookup
);
482 zlog_warn("%s: IPTable being deleted we know nothing about",
483 __PRETTY_FUNCTION__
);
487 * Handle success or failure of rule (un)install in the kernel.
489 void kernel_pbr_rule_add_del_status(struct zebra_pbr_rule
*rule
,
490 enum southbound_results res
)
493 case SOUTHBOUND_INSTALL_SUCCESS
:
494 zsend_rule_notify_owner(rule
, ZAPI_RULE_INSTALLED
);
496 case SOUTHBOUND_INSTALL_FAILURE
:
497 zsend_rule_notify_owner(rule
, ZAPI_RULE_FAIL_INSTALL
);
499 case SOUTHBOUND_DELETE_SUCCESS
:
500 zsend_rule_notify_owner(rule
, ZAPI_RULE_REMOVED
);
502 case SOUTHBOUND_DELETE_FAILURE
:
503 zsend_rule_notify_owner(rule
, ZAPI_RULE_REMOVED
);
509 * Handle success or failure of ipset (un)install in the kernel.
511 void kernel_pbr_ipset_add_del_status(struct zebra_pbr_ipset
*ipset
,
512 enum southbound_results res
)
515 case SOUTHBOUND_INSTALL_SUCCESS
:
516 zsend_ipset_notify_owner(ipset
, ZAPI_IPSET_INSTALLED
);
518 case SOUTHBOUND_INSTALL_FAILURE
:
519 zsend_ipset_notify_owner(ipset
, ZAPI_IPSET_FAIL_INSTALL
);
521 case SOUTHBOUND_DELETE_SUCCESS
:
522 case SOUTHBOUND_DELETE_FAILURE
:
523 /* TODO : handling of delete event */
529 * Handle success or failure of ipset (un)install in the kernel.
531 void kernel_pbr_ipset_entry_add_del_status(
532 struct zebra_pbr_ipset_entry
*ipset
,
533 enum southbound_results res
)
536 case SOUTHBOUND_INSTALL_SUCCESS
:
537 zsend_ipset_entry_notify_owner(ipset
,
538 ZAPI_IPSET_ENTRY_INSTALLED
);
540 case SOUTHBOUND_INSTALL_FAILURE
:
541 zsend_ipset_entry_notify_owner(ipset
,
542 ZAPI_IPSET_ENTRY_FAIL_INSTALL
);
544 case SOUTHBOUND_DELETE_SUCCESS
:
545 case SOUTHBOUND_DELETE_FAILURE
:
546 /* TODO : handling of delete event */
552 * Handle success or failure of ipset (un)install in the kernel.
554 void kernel_pbr_iptable_add_del_status(struct zebra_pbr_iptable
*iptable
,
555 enum southbound_results res
)
558 case SOUTHBOUND_INSTALL_SUCCESS
:
559 zsend_iptable_notify_owner(iptable
, ZAPI_IPTABLE_INSTALLED
);
561 case SOUTHBOUND_INSTALL_FAILURE
:
562 zsend_iptable_notify_owner(iptable
, ZAPI_IPTABLE_FAIL_INSTALL
);
564 case SOUTHBOUND_DELETE_SUCCESS
:
565 case SOUTHBOUND_DELETE_FAILURE
:
566 /* TODO : handling of delete event */
572 * Handle rule delete notification from kernel.
574 int kernel_pbr_rule_del(struct zebra_pbr_rule
*rule
)