1 /* Route filtering function.
2 * Copyright (C) 1998, 1999 Kunihiro Ishiguro
4 * This file is part of GNU Zebra.
6 * GNU Zebra is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published
8 * by the Free Software Foundation; either version 2, or (at your
9 * option) any later version.
11 * GNU Zebra 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 along
17 * with this program; see the file COPYING; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
27 #include "sockunion.h"
32 #include "northbound_cli.h"
34 DEFINE_MTYPE_STATIC(LIB
, ACCESS_LIST
, "Access List");
35 DEFINE_MTYPE_STATIC(LIB
, ACCESS_LIST_STR
, "Access List Str");
36 DEFINE_MTYPE_STATIC(LIB
, ACCESS_FILTER
, "Access Filter");
38 /* Static structure for mac access_list's master. */
39 static struct access_master access_master_mac
= {
45 /* Static structure for IPv4 access_list's master. */
46 static struct access_master access_master_ipv4
= {
52 /* Static structure for IPv6 access_list's master. */
53 static struct access_master access_master_ipv6
= {
59 static struct access_master
*access_master_get(afi_t afi
)
62 return &access_master_ipv4
;
63 else if (afi
== AFI_IP6
)
64 return &access_master_ipv6
;
65 else if (afi
== AFI_L2VPN
)
66 return &access_master_mac
;
70 /* Allocate new filter structure. */
71 struct filter
*filter_new(void)
73 return XCALLOC(MTYPE_ACCESS_FILTER
, sizeof(struct filter
));
76 static void filter_free(struct filter
*filter
)
78 XFREE(MTYPE_ACCESS_FILTER
, filter
);
81 /* Return string of filter_type. */
82 static const char *filter_type_str(struct filter
*filter
)
84 switch (filter
->type
) {
96 /* If filter match to the prefix then return 1. */
97 static int filter_match_cisco(struct filter
*mfilter
, const struct prefix
*p
)
99 struct filter_cisco
*filter
;
104 filter
= &mfilter
->u
.cfilter
;
105 check_addr
= p
->u
.prefix4
.s_addr
& ~filter
->addr_mask
.s_addr
;
107 if (filter
->extended
) {
108 masklen2ip(p
->prefixlen
, &mask
);
109 check_mask
= mask
.s_addr
& ~filter
->mask_mask
.s_addr
;
111 if (memcmp(&check_addr
, &filter
->addr
.s_addr
, IPV4_MAX_BYTELEN
)
113 && memcmp(&check_mask
, &filter
->mask
.s_addr
,
117 } else if (memcmp(&check_addr
, &filter
->addr
.s_addr
, IPV4_MAX_BYTELEN
)
124 /* If filter match to the prefix then return 1. */
125 static int filter_match_zebra(struct filter
*mfilter
, const struct prefix
*p
)
127 struct filter_zebra
*filter
= NULL
;
129 filter
= &mfilter
->u
.zfilter
;
131 if (filter
->prefix
.family
== p
->family
) {
133 if (filter
->prefix
.prefixlen
== p
->prefixlen
)
134 return prefix_match(&filter
->prefix
, p
);
138 return prefix_match(&filter
->prefix
, p
);
143 /* Allocate new access list structure. */
144 static struct access_list
*access_list_new(void)
146 return XCALLOC(MTYPE_ACCESS_LIST
, sizeof(struct access_list
));
149 /* Free allocated access_list. */
150 static void access_list_free(struct access_list
*access
)
152 XFREE(MTYPE_ACCESS_LIST
, access
);
155 /* Delete access_list from access_master and free it. */
156 void access_list_delete(struct access_list
*access
)
158 struct filter
*filter
;
160 struct access_list_list
*list
;
161 struct access_master
*master
;
163 for (filter
= access
->head
; filter
; filter
= next
) {
168 master
= access
->master
;
173 access
->next
->prev
= access
->prev
;
175 list
->tail
= access
->prev
;
178 access
->prev
->next
= access
->next
;
180 list
->head
= access
->next
;
182 route_map_notify_dependencies(access
->name
, RMAP_EVENT_FILTER_DELETED
);
184 if (master
->delete_hook
)
185 master
->delete_hook(access
);
187 XFREE(MTYPE_ACCESS_LIST_STR
, access
->name
);
189 XFREE(MTYPE_TMP
, access
->remark
);
191 access_list_free(access
);
194 /* Insert new access list to list of access_list. Each acceess_list
195 is sorted by the name. */
196 static struct access_list
*access_list_insert(afi_t afi
, const char *name
)
198 struct access_list
*access
;
199 struct access_list
*point
;
200 struct access_list_list
*alist
;
201 struct access_master
*master
;
203 master
= access_master_get(afi
);
207 /* Allocate new access_list and copy given name. */
208 access
= access_list_new();
209 access
->name
= XSTRDUP(MTYPE_ACCESS_LIST_STR
, name
);
210 access
->master
= master
;
212 /* Set access_list to string list. */
213 alist
= &master
->str
;
215 /* Set point to insertion point. */
216 for (point
= alist
->head
; point
; point
= point
->next
)
217 if (strcmp(point
->name
, name
) >= 0)
220 /* In case of this is the first element of master. */
221 if (alist
->head
== NULL
) {
222 alist
->head
= alist
->tail
= access
;
226 /* In case of insertion is made at the tail of access_list. */
228 access
->prev
= alist
->tail
;
229 alist
->tail
->next
= access
;
230 alist
->tail
= access
;
234 /* In case of insertion is made at the head of access_list. */
235 if (point
== alist
->head
) {
236 access
->next
= alist
->head
;
237 alist
->head
->prev
= access
;
238 alist
->head
= access
;
242 /* Insertion is made at middle of the access_list. */
243 access
->next
= point
;
244 access
->prev
= point
->prev
;
247 point
->prev
->next
= access
;
248 point
->prev
= access
;
253 /* Lookup access_list from list of access_list by name. */
254 struct access_list
*access_list_lookup(afi_t afi
, const char *name
)
256 struct access_list
*access
;
257 struct access_master
*master
;
262 master
= access_master_get(afi
);
266 for (access
= master
->str
.head
; access
; access
= access
->next
)
267 if (strcmp(access
->name
, name
) == 0)
273 /* Get access list from list of access_list. If there isn't matched
274 access_list create new one and return it. */
275 struct access_list
*access_list_get(afi_t afi
, const char *name
)
277 struct access_list
*access
;
279 access
= access_list_lookup(afi
, name
);
281 access
= access_list_insert(afi
, name
);
285 /* Apply access list to object (which should be struct prefix *). */
286 enum filter_type
access_list_apply(struct access_list
*access
,
289 struct filter
*filter
;
290 const struct prefix
*p
= (const struct prefix
*)object
;
295 for (filter
= access
->head
; filter
; filter
= filter
->next
) {
297 if (filter_match_cisco(filter
, p
))
300 if (filter_match_zebra(filter
, p
))
308 /* Add hook function. */
309 void access_list_add_hook(void (*func
)(struct access_list
*access
))
311 access_master_ipv4
.add_hook
= func
;
312 access_master_ipv6
.add_hook
= func
;
313 access_master_mac
.add_hook
= func
;
316 /* Delete hook function. */
317 void access_list_delete_hook(void (*func
)(struct access_list
*access
))
319 access_master_ipv4
.delete_hook
= func
;
320 access_master_ipv6
.delete_hook
= func
;
321 access_master_mac
.delete_hook
= func
;
324 /* Calculate new sequential number. */
325 int64_t filter_new_seq_get(struct access_list
*access
)
329 struct filter
*filter
;
333 for (filter
= access
->head
; filter
; filter
= filter
->next
) {
334 if (maxseq
< filter
->seq
)
335 maxseq
= filter
->seq
;
338 newseq
= ((maxseq
/ 5) * 5) + 5;
340 return (newseq
> UINT_MAX
) ? UINT_MAX
: newseq
;
343 /* Return access list entry which has same seq number. */
344 static struct filter
*filter_seq_check(struct access_list
*access
,
347 struct filter
*filter
;
349 for (filter
= access
->head
; filter
; filter
= filter
->next
)
350 if (filter
->seq
== seq
)
355 /* Delete filter from specified access_list. If there is hook
356 function execute it. */
357 void access_list_filter_delete(struct access_list
*access
,
358 struct filter
*filter
)
360 struct access_master
*master
;
362 master
= access
->master
;
365 filter
->next
->prev
= filter
->prev
;
367 access
->tail
= filter
->prev
;
370 filter
->prev
->next
= filter
->next
;
372 access
->head
= filter
->next
;
376 route_map_notify_dependencies(access
->name
, RMAP_EVENT_FILTER_DELETED
);
377 /* Run hook function. */
378 if (master
->delete_hook
)
379 (*master
->delete_hook
)(access
);
382 /* Add new filter to the end of specified access_list. */
383 void access_list_filter_add(struct access_list
*access
,
384 struct filter
*filter
)
386 struct filter
*replace
;
387 struct filter
*point
;
389 /* Automatic asignment of seq no. */
390 if (filter
->seq
== -1)
391 filter
->seq
= filter_new_seq_get(access
);
393 if (access
->tail
&& filter
->seq
> access
->tail
->seq
)
396 /* Is there any same seq access list filter? */
397 replace
= filter_seq_check(access
, filter
->seq
);
399 access_list_filter_delete(access
, replace
);
401 /* Check insert point. */
402 for (point
= access
->head
; point
; point
= point
->next
)
403 if (point
->seq
>= filter
->seq
)
407 /* In case of this is the first element of the list. */
408 filter
->next
= point
;
412 point
->prev
->next
= filter
;
414 access
->head
= filter
;
416 filter
->prev
= point
->prev
;
417 point
->prev
= filter
;
420 access
->tail
->next
= filter
;
422 access
->head
= filter
;
424 filter
->prev
= access
->tail
;
425 access
->tail
= filter
;
428 /* Run hook function. */
429 if (access
->master
->add_hook
)
430 (*access
->master
->add_hook
)(access
);
431 route_map_notify_dependencies(access
->name
, RMAP_EVENT_FILTER_ADDED
);
435 deny Specify packets to reject
436 permit Specify packets to forward
441 Hostname or A.B.C.D Address to match
443 host A single host address
446 static void config_write_access_zebra(struct vty
*, struct filter
*);
447 static void config_write_access_cisco(struct vty
*, struct filter
*);
449 /* show access-list command. */
450 static int filter_show(struct vty
*vty
, const char *name
, afi_t afi
)
452 struct access_list
*access
;
453 struct access_master
*master
;
454 struct filter
*mfilter
;
455 struct filter_cisco
*filter
;
458 master
= access_master_get(afi
);
462 /* Print the name of the protocol */
463 vty_out(vty
, "%s:\n", frr_protoname
);
465 for (access
= master
->str
.head
; access
; access
= access
->next
) {
466 if (name
&& strcmp(access
->name
, name
) != 0)
471 for (mfilter
= access
->head
; mfilter
; mfilter
= mfilter
->next
) {
472 filter
= &mfilter
->u
.cfilter
;
475 vty_out(vty
, "%s %s access list %s\n",
476 mfilter
->cisco
? (filter
->extended
482 : ((afi
== AFI_IP6
) ? ("IPv6 ")
488 vty_out(vty
, " seq %" PRId64
, mfilter
->seq
);
489 vty_out(vty
, " %s%s", filter_type_str(mfilter
),
490 mfilter
->type
== FILTER_DENY
? " " : "");
493 config_write_access_zebra(vty
, mfilter
);
494 else if (filter
->extended
)
495 config_write_access_cisco(vty
, mfilter
);
497 if (filter
->addr_mask
.s_addr
== 0xffffffff)
498 vty_out(vty
, " any\n");
500 vty_out(vty
, " %pI4", &filter
->addr
);
501 if (filter
->addr_mask
.s_addr
504 ", wildcard bits %pI4",
514 /* show MAC access list - this only has MAC filters for now*/
515 DEFUN (show_mac_access_list
,
516 show_mac_access_list_cmd
,
517 "show mac access-list",
520 "List mac access lists\n")
522 return filter_show(vty
, NULL
, AFI_L2VPN
);
525 DEFUN (show_mac_access_list_name
,
526 show_mac_access_list_name_cmd
,
527 "show mac access-list WORD",
530 "List mac access lists\n"
533 return filter_show(vty
, argv
[3]->arg
, AFI_L2VPN
);
536 DEFUN (show_ip_access_list
,
537 show_ip_access_list_cmd
,
538 "show ip access-list",
541 "List IP access lists\n")
543 return filter_show(vty
, NULL
, AFI_IP
);
546 DEFUN (show_ip_access_list_name
,
547 show_ip_access_list_name_cmd
,
548 "show ip access-list <(1-99)|(100-199)|(1300-1999)|(2000-2699)|WORD>",
551 "List IP access lists\n"
552 "IP standard access list\n"
553 "IP extended access list\n"
554 "IP standard access list (expanded range)\n"
555 "IP extended access list (expanded range)\n"
556 "IP zebra access-list\n")
559 return filter_show(vty
, argv
[idx_acl
]->arg
, AFI_IP
);
562 DEFUN (show_ipv6_access_list
,
563 show_ipv6_access_list_cmd
,
564 "show ipv6 access-list",
567 "List IPv6 access lists\n")
569 return filter_show(vty
, NULL
, AFI_IP6
);
572 DEFUN (show_ipv6_access_list_name
,
573 show_ipv6_access_list_name_cmd
,
574 "show ipv6 access-list WORD",
577 "List IPv6 access lists\n"
578 "IPv6 zebra access-list\n")
581 return filter_show(vty
, argv
[idx_word
]->arg
, AFI_IP6
);
584 static void config_write_access_cisco(struct vty
*vty
, struct filter
*mfilter
)
586 struct filter_cisco
*filter
;
588 filter
= &mfilter
->u
.cfilter
;
590 if (filter
->extended
) {
592 if (filter
->addr_mask
.s_addr
== 0xffffffff)
593 vty_out(vty
, " any");
594 else if (filter
->addr_mask
.s_addr
== INADDR_ANY
)
595 vty_out(vty
, " host %pI4", &filter
->addr
);
597 vty_out(vty
, " %pI4", &filter
->addr
);
598 vty_out(vty
, " %pI4", &filter
->addr_mask
);
601 if (filter
->mask_mask
.s_addr
== 0xffffffff)
602 vty_out(vty
, " any");
603 else if (filter
->mask_mask
.s_addr
== INADDR_ANY
)
604 vty_out(vty
, " host %pI4", &filter
->mask
);
606 vty_out(vty
, " %pI4", &filter
->mask
);
607 vty_out(vty
, " %pI4", &filter
->mask_mask
);
611 if (filter
->addr_mask
.s_addr
== 0xffffffff)
612 vty_out(vty
, " any\n");
614 vty_out(vty
, " %pI4", &filter
->addr
);
615 if (filter
->addr_mask
.s_addr
!= INADDR_ANY
)
616 vty_out(vty
, " %pI4", &filter
->addr_mask
);
622 static void config_write_access_zebra(struct vty
*vty
, struct filter
*mfilter
)
624 struct filter_zebra
*filter
;
628 filter
= &mfilter
->u
.zfilter
;
631 if (p
->prefixlen
== 0 && !filter
->exact
)
632 vty_out(vty
, " any");
633 else if (p
->family
== AF_INET6
|| p
->family
== AF_INET
)
634 vty_out(vty
, " %s/%d%s",
635 inet_ntop(p
->family
, &p
->u
.prefix
, buf
, BUFSIZ
),
636 p
->prefixlen
, filter
->exact
? " exact-match" : "");
637 else if (p
->family
== AF_ETHERNET
) {
638 if (p
->prefixlen
== 0)
639 vty_out(vty
, " any");
641 vty_out(vty
, " %s", prefix_mac2str(&(p
->u
.prefix_eth
),
648 static struct cmd_node access_mac_node
= {
649 .name
= "MAC access list",
650 .node
= ACCESS_MAC_NODE
,
654 static void access_list_reset_mac(void)
656 struct access_list
*access
;
657 struct access_list
*next
;
658 struct access_master
*master
;
660 master
= access_master_get(AFI_L2VPN
);
664 for (access
= master
->str
.head
; access
; access
= next
) {
666 access_list_delete(access
);
669 assert(master
->str
.head
== NULL
);
670 assert(master
->str
.tail
== NULL
);
673 /* Install vty related command. */
674 static void access_list_init_mac(void)
676 install_node(&access_mac_node
);
678 install_element(ENABLE_NODE
, &show_mac_access_list_cmd
);
679 install_element(ENABLE_NODE
, &show_mac_access_list_name_cmd
);
682 /* Access-list node. */
683 static int config_write_access(struct vty
*vty
);
684 static struct cmd_node access_node
= {
685 .name
= "ipv4 access list",
688 .config_write
= config_write_access
,
691 static int config_write_access(struct vty
*vty
)
693 struct lyd_node
*dnode
;
696 dnode
= yang_dnode_get(running_config
->dnode
, "/frr-filter:lib");
698 nb_cli_show_dnode_cmds(vty
, dnode
, false);
705 static void access_list_reset_ipv4(void)
707 struct access_list
*access
;
708 struct access_list
*next
;
709 struct access_master
*master
;
711 master
= access_master_get(AFI_IP
);
715 for (access
= master
->str
.head
; access
; access
= next
) {
717 access_list_delete(access
);
720 assert(master
->str
.head
== NULL
);
721 assert(master
->str
.tail
== NULL
);
724 /* Install vty related command. */
725 static void access_list_init_ipv4(void)
727 install_node(&access_node
);
729 install_element(ENABLE_NODE
, &show_ip_access_list_cmd
);
730 install_element(ENABLE_NODE
, &show_ip_access_list_name_cmd
);
733 static struct cmd_node access_ipv6_node
= {
734 .name
= "ipv6 access list",
735 .node
= ACCESS_IPV6_NODE
,
739 static void access_list_reset_ipv6(void)
741 struct access_list
*access
;
742 struct access_list
*next
;
743 struct access_master
*master
;
745 master
= access_master_get(AFI_IP6
);
749 for (access
= master
->str
.head
; access
; access
= next
) {
751 access_list_delete(access
);
754 assert(master
->str
.head
== NULL
);
755 assert(master
->str
.tail
== NULL
);
758 static void access_list_init_ipv6(void)
760 install_node(&access_ipv6_node
);
762 install_element(ENABLE_NODE
, &show_ipv6_access_list_cmd
);
763 install_element(ENABLE_NODE
, &show_ipv6_access_list_name_cmd
);
766 void access_list_init(void)
768 access_list_init_ipv4();
769 access_list_init_ipv6();
770 access_list_init_mac();
775 void access_list_reset(void)
777 access_list_reset_ipv4();
778 access_list_reset_ipv6();
779 access_list_reset_mac();