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"
35 DEFINE_MTYPE_STATIC(LIB
, ACCESS_LIST
, "Access List");
36 DEFINE_MTYPE_STATIC(LIB
, ACCESS_LIST_STR
, "Access List Str");
37 DEFINE_MTYPE_STATIC(LIB
, ACCESS_FILTER
, "Access Filter");
39 /* Static structure for mac access_list's master. */
40 static struct access_master access_master_mac
= {
46 /* Static structure for IPv4 access_list's master. */
47 static struct access_master access_master_ipv4
= {
53 /* Static structure for IPv6 access_list's master. */
54 static struct access_master access_master_ipv6
= {
60 static struct access_master
*access_master_get(afi_t afi
)
63 return &access_master_ipv4
;
64 else if (afi
== AFI_IP6
)
65 return &access_master_ipv6
;
66 else if (afi
== AFI_L2VPN
)
67 return &access_master_mac
;
71 /* Allocate new filter structure. */
72 struct filter
*filter_new(void)
74 return XCALLOC(MTYPE_ACCESS_FILTER
, sizeof(struct filter
));
77 static void filter_free(struct filter
*filter
)
79 XFREE(MTYPE_ACCESS_FILTER
, filter
);
82 /* Return string of filter_type. */
83 static const char *filter_type_str(struct filter
*filter
)
85 switch (filter
->type
) {
97 /* If filter match to the prefix then return 1. */
98 static int filter_match_cisco(struct filter
*mfilter
, const struct prefix
*p
)
100 struct filter_cisco
*filter
;
105 filter
= &mfilter
->u
.cfilter
;
106 check_addr
= p
->u
.prefix4
.s_addr
& ~filter
->addr_mask
.s_addr
;
108 if (filter
->extended
) {
109 masklen2ip(p
->prefixlen
, &mask
);
110 check_mask
= mask
.s_addr
& ~filter
->mask_mask
.s_addr
;
112 if (memcmp(&check_addr
, &filter
->addr
.s_addr
, IPV4_MAX_BYTELEN
)
114 && memcmp(&check_mask
, &filter
->mask
.s_addr
,
118 } else if (memcmp(&check_addr
, &filter
->addr
.s_addr
, IPV4_MAX_BYTELEN
)
125 /* If filter match to the prefix then return 1. */
126 static int filter_match_zebra(struct filter
*mfilter
, const struct prefix
*p
)
128 struct filter_zebra
*filter
= NULL
;
130 filter
= &mfilter
->u
.zfilter
;
132 if (filter
->prefix
.family
== p
->family
) {
134 if (filter
->prefix
.prefixlen
== p
->prefixlen
)
135 return prefix_match(&filter
->prefix
, p
);
139 return prefix_match(&filter
->prefix
, p
);
144 /* Allocate new access list structure. */
145 static struct access_list
*access_list_new(void)
147 return XCALLOC(MTYPE_ACCESS_LIST
, sizeof(struct access_list
));
150 /* Free allocated access_list. */
151 static void access_list_free(struct access_list
*access
)
153 XFREE(MTYPE_ACCESS_LIST
, access
);
156 /* Delete access_list from access_master and free it. */
157 void access_list_delete(struct access_list
*access
)
159 struct filter
*filter
;
161 struct access_list_list
*list
;
162 struct access_master
*master
;
164 for (filter
= access
->head
; filter
; filter
= next
) {
169 master
= access
->master
;
174 access
->next
->prev
= access
->prev
;
176 list
->tail
= access
->prev
;
179 access
->prev
->next
= access
->next
;
181 list
->head
= access
->next
;
183 route_map_notify_dependencies(access
->name
, RMAP_EVENT_FILTER_DELETED
);
185 if (master
->delete_hook
)
186 master
->delete_hook(access
);
188 XFREE(MTYPE_ACCESS_LIST_STR
, access
->name
);
190 XFREE(MTYPE_TMP
, access
->remark
);
192 access_list_free(access
);
195 /* Insert new access list to list of access_list. Each acceess_list
196 is sorted by the name. */
197 static struct access_list
*access_list_insert(afi_t afi
, const char *name
)
199 struct access_list
*access
;
200 struct access_list
*point
;
201 struct access_list_list
*alist
;
202 struct access_master
*master
;
204 master
= access_master_get(afi
);
208 /* Allocate new access_list and copy given name. */
209 access
= access_list_new();
210 access
->name
= XSTRDUP(MTYPE_ACCESS_LIST_STR
, name
);
211 access
->master
= master
;
213 /* Set access_list to string list. */
214 alist
= &master
->str
;
216 /* Set point to insertion point. */
217 for (point
= alist
->head
; point
; point
= point
->next
)
218 if (strcmp(point
->name
, name
) >= 0)
221 /* In case of this is the first element of master. */
222 if (alist
->head
== NULL
) {
223 alist
->head
= alist
->tail
= access
;
227 /* In case of insertion is made at the tail of access_list. */
229 access
->prev
= alist
->tail
;
230 alist
->tail
->next
= access
;
231 alist
->tail
= access
;
235 /* In case of insertion is made at the head of access_list. */
236 if (point
== alist
->head
) {
237 access
->next
= alist
->head
;
238 alist
->head
->prev
= access
;
239 alist
->head
= access
;
243 /* Insertion is made at middle of the access_list. */
244 access
->next
= point
;
245 access
->prev
= point
->prev
;
248 point
->prev
->next
= access
;
249 point
->prev
= access
;
254 /* Lookup access_list from list of access_list by name. */
255 struct access_list
*access_list_lookup(afi_t afi
, const char *name
)
257 struct access_list
*access
;
258 struct access_master
*master
;
263 master
= access_master_get(afi
);
267 for (access
= master
->str
.head
; access
; access
= access
->next
)
268 if (strcmp(access
->name
, name
) == 0)
274 /* Get access list from list of access_list. If there isn't matched
275 access_list create new one and return it. */
276 struct access_list
*access_list_get(afi_t afi
, const char *name
)
278 struct access_list
*access
;
280 access
= access_list_lookup(afi
, name
);
282 access
= access_list_insert(afi
, name
);
286 /* Apply access list to object (which should be struct prefix *). */
287 enum filter_type
access_list_apply(struct access_list
*access
,
290 struct filter
*filter
;
291 const struct prefix
*p
= (const struct prefix
*)object
;
296 for (filter
= access
->head
; filter
; filter
= filter
->next
) {
298 if (filter_match_cisco(filter
, p
))
301 if (filter_match_zebra(filter
, p
))
309 /* Add hook function. */
310 void access_list_add_hook(void (*func
)(struct access_list
*access
))
312 access_master_ipv4
.add_hook
= func
;
313 access_master_ipv6
.add_hook
= func
;
314 access_master_mac
.add_hook
= func
;
317 /* Delete hook function. */
318 void access_list_delete_hook(void (*func
)(struct access_list
*access
))
320 access_master_ipv4
.delete_hook
= func
;
321 access_master_ipv6
.delete_hook
= func
;
322 access_master_mac
.delete_hook
= func
;
325 /* Calculate new sequential number. */
326 int64_t filter_new_seq_get(struct access_list
*access
)
330 struct filter
*filter
;
334 for (filter
= access
->head
; filter
; filter
= filter
->next
) {
335 if (maxseq
< filter
->seq
)
336 maxseq
= filter
->seq
;
339 newseq
= ((maxseq
/ 5) * 5) + 5;
341 return (newseq
> UINT_MAX
) ? UINT_MAX
: newseq
;
344 /* Return access list entry which has same seq number. */
345 static struct filter
*filter_seq_check(struct access_list
*access
,
348 struct filter
*filter
;
350 for (filter
= access
->head
; filter
; filter
= filter
->next
)
351 if (filter
->seq
== seq
)
356 /* Delete filter from specified access_list. If there is hook
357 function execute it. */
358 void access_list_filter_delete(struct access_list
*access
,
359 struct filter
*filter
)
361 struct access_master
*master
;
363 master
= access
->master
;
366 filter
->next
->prev
= filter
->prev
;
368 access
->tail
= filter
->prev
;
371 filter
->prev
->next
= filter
->next
;
373 access
->head
= filter
->next
;
377 route_map_notify_dependencies(access
->name
, RMAP_EVENT_FILTER_DELETED
);
378 /* Run hook function. */
379 if (master
->delete_hook
)
380 (*master
->delete_hook
)(access
);
383 /* Add new filter to the end of specified access_list. */
384 void access_list_filter_add(struct access_list
*access
,
385 struct filter
*filter
)
387 struct filter
*replace
;
388 struct filter
*point
;
390 /* Automatic asignment of seq no. */
391 if (filter
->seq
== -1)
392 filter
->seq
= filter_new_seq_get(access
);
394 if (access
->tail
&& filter
->seq
> access
->tail
->seq
)
397 /* Is there any same seq access list filter? */
398 replace
= filter_seq_check(access
, filter
->seq
);
400 access_list_filter_delete(access
, replace
);
402 /* Check insert point. */
403 for (point
= access
->head
; point
; point
= point
->next
)
404 if (point
->seq
>= filter
->seq
)
408 /* In case of this is the first element of the list. */
409 filter
->next
= point
;
413 point
->prev
->next
= filter
;
415 access
->head
= filter
;
417 filter
->prev
= point
->prev
;
418 point
->prev
= filter
;
421 access
->tail
->next
= filter
;
423 access
->head
= filter
;
425 filter
->prev
= access
->tail
;
426 access
->tail
= filter
;
429 /* Run hook function. */
430 if (access
->master
->add_hook
)
431 (*access
->master
->add_hook
)(access
);
432 route_map_notify_dependencies(access
->name
, RMAP_EVENT_FILTER_ADDED
);
436 deny Specify packets to reject
437 permit Specify packets to forward
442 Hostname or A.B.C.D Address to match
444 host A single host address
447 static void config_write_access_zebra(struct vty
*, struct filter
*,
449 static void config_write_access_cisco(struct vty
*, struct filter
*,
452 static const char *filter_type2str(struct filter
*filter
)
455 if (filter
->u
.cfilter
.extended
)
463 /* show access-list command. */
464 static int filter_show(struct vty
*vty
, const char *name
, afi_t afi
,
467 struct access_list
*access
;
468 struct access_master
*master
;
469 struct filter
*mfilter
;
470 struct filter_cisco
*filter
;
472 json_object
*json
= NULL
;
473 json_object
*json_proto
= NULL
;
475 master
= access_master_get(afi
);
476 if (master
== NULL
) {
478 vty_out(vty
, "{}\n");
483 json
= json_object_new_object();
485 /* Print the name of the protocol */
487 json_proto
= json_object_new_object();
488 json_object_object_add(json
, frr_protoname
, json_proto
);
490 vty_out(vty
, "%s:\n", frr_protoname
);
492 for (access
= master
->str
.head
; access
; access
= access
->next
) {
493 json_object
*json_acl
= NULL
;
494 json_object
*json_rules
= NULL
;
496 if (name
&& strcmp(access
->name
, name
) != 0)
501 for (mfilter
= access
->head
; mfilter
; mfilter
= mfilter
->next
) {
502 json_object
*json_rule
= NULL
;
504 filter
= &mfilter
->u
.cfilter
;
507 const char *type
= filter_type2str(mfilter
);
510 json_acl
= json_object_new_object();
511 json_object_object_add(json_proto
,
515 json_object_string_add(json_acl
, "type",
517 json_object_string_add(json_acl
,
520 json_rules
= json_object_new_array();
521 json_object_object_add(
522 json_acl
, "rules", json_rules
);
524 vty_out(vty
, "%s %s access list %s\n",
538 json_rule
= json_object_new_object();
539 json_object_array_add(json_rules
, json_rule
);
541 json_object_int_add(json_rule
, "sequenceNumber",
543 json_object_string_add(
544 json_rule
, "filterType",
545 filter_type_str(mfilter
));
547 vty_out(vty
, " seq %" PRId64
, mfilter
->seq
);
548 vty_out(vty
, " %s%s", filter_type_str(mfilter
),
549 mfilter
->type
== FILTER_DENY
? " "
554 config_write_access_zebra(vty
, mfilter
,
556 else if (filter
->extended
)
557 config_write_access_cisco(vty
, mfilter
,
563 json_object_string_add(
564 json_rule
, "address",
568 json_object_string_add(
574 if (filter
->addr_mask
.s_addr
576 vty_out(vty
, " any\n");
578 vty_out(vty
, " %pI4",
580 if (filter
->addr_mask
.s_addr
583 ", wildcard bits %pI4",
594 json_object_to_json_string_ext(
595 json
, JSON_C_TO_STRING_PRETTY
));
596 json_object_free(json
);
602 /* show MAC access list - this only has MAC filters for now*/
603 DEFUN (show_mac_access_list
,
604 show_mac_access_list_cmd
,
605 "show mac access-list",
608 "List mac access lists\n")
610 return filter_show(vty
, NULL
, AFI_L2VPN
, false);
613 DEFUN (show_mac_access_list_name
,
614 show_mac_access_list_name_cmd
,
615 "show mac access-list WORD",
618 "List mac access lists\n"
621 return filter_show(vty
, argv
[3]->arg
, AFI_L2VPN
, false);
624 DEFUN (show_ip_access_list
,
625 show_ip_access_list_cmd
,
626 "show ip access-list [json]",
629 "List IP access lists\n"
632 bool uj
= use_json(argc
, argv
);
633 return filter_show(vty
, NULL
, AFI_IP
, uj
);
636 DEFUN (show_ip_access_list_name
,
637 show_ip_access_list_name_cmd
,
638 "show ip access-list WORD [json]",
641 "List IP access lists\n"
642 "IP access-list name\n"
645 bool uj
= use_json(argc
, argv
);
647 return filter_show(vty
, argv
[idx_acl
]->arg
, AFI_IP
, uj
);
650 DEFUN (show_ipv6_access_list
,
651 show_ipv6_access_list_cmd
,
652 "show ipv6 access-list [json]",
655 "List IPv6 access lists\n"
658 bool uj
= use_json(argc
, argv
);
659 return filter_show(vty
, NULL
, AFI_IP6
, uj
);
662 DEFUN (show_ipv6_access_list_name
,
663 show_ipv6_access_list_name_cmd
,
664 "show ipv6 access-list WORD [json]",
667 "List IPv6 access lists\n"
668 "IPv6 access-list name\n"
671 bool uj
= use_json(argc
, argv
);
673 return filter_show(vty
, argv
[idx_word
]->arg
, AFI_IP6
, uj
);
676 static void config_write_access_cisco(struct vty
*vty
, struct filter
*mfilter
,
679 struct filter_cisco
*filter
;
681 filter
= &mfilter
->u
.cfilter
;
686 json_object_boolean_add(json
, "extended", !!filter
->extended
);
687 json_object_string_add(
688 json
, "sourceAddress",
689 inet_ntop(AF_INET
, &filter
->addr
, buf
, sizeof(buf
)));
690 json_object_string_add(json
, "sourceMask",
691 inet_ntop(AF_INET
, &filter
->addr_mask
,
693 json_object_string_add(
694 json
, "destinationAddress",
695 inet_ntop(AF_INET
, &filter
->mask
, buf
, sizeof(buf
)));
696 json_object_string_add(json
, "destinationMask",
697 inet_ntop(AF_INET
, &filter
->mask_mask
,
701 if (filter
->addr_mask
.s_addr
== 0xffffffff)
702 vty_out(vty
, " any");
703 else if (filter
->addr_mask
.s_addr
== INADDR_ANY
)
704 vty_out(vty
, " host %pI4", &filter
->addr
);
706 vty_out(vty
, " %pI4", &filter
->addr
);
707 vty_out(vty
, " %pI4", &filter
->addr_mask
);
710 if (filter
->mask_mask
.s_addr
== 0xffffffff)
711 vty_out(vty
, " any");
712 else if (filter
->mask_mask
.s_addr
== INADDR_ANY
)
713 vty_out(vty
, " host %pI4", &filter
->mask
);
715 vty_out(vty
, " %pI4", &filter
->mask
);
716 vty_out(vty
, " %pI4", &filter
->mask_mask
);
722 static void config_write_access_zebra(struct vty
*vty
, struct filter
*mfilter
,
725 struct filter_zebra
*filter
;
729 filter
= &mfilter
->u
.zfilter
;
733 json_object_string_add(json
, "prefix",
734 prefix2str(p
, buf
, sizeof(buf
)));
735 json_object_boolean_add(json
, "exact-match", !!filter
->exact
);
737 if (p
->prefixlen
== 0 && !filter
->exact
)
738 vty_out(vty
, " any");
739 else if (p
->family
== AF_INET6
|| p
->family
== AF_INET
)
740 vty_out(vty
, " %s/%d%s",
741 inet_ntop(p
->family
, &p
->u
.prefix
, buf
, BUFSIZ
),
743 filter
->exact
? " exact-match" : "");
744 else if (p
->family
== AF_ETHERNET
) {
745 if (p
->prefixlen
== 0)
746 vty_out(vty
, " any");
749 prefix_mac2str(&(p
->u
.prefix_eth
), buf
,
757 static struct cmd_node access_mac_node
= {
758 .name
= "MAC access list",
759 .node
= ACCESS_MAC_NODE
,
763 static void access_list_reset_mac(void)
765 struct access_list
*access
;
766 struct access_list
*next
;
767 struct access_master
*master
;
769 master
= access_master_get(AFI_L2VPN
);
773 for (access
= master
->str
.head
; access
; access
= next
) {
775 access_list_delete(access
);
778 assert(master
->str
.head
== NULL
);
779 assert(master
->str
.tail
== NULL
);
782 /* Install vty related command. */
783 static void access_list_init_mac(void)
785 install_node(&access_mac_node
);
787 install_element(ENABLE_NODE
, &show_mac_access_list_cmd
);
788 install_element(ENABLE_NODE
, &show_mac_access_list_name_cmd
);
791 /* Access-list node. */
792 static int config_write_access(struct vty
*vty
);
793 static struct cmd_node access_node
= {
794 .name
= "ipv4 access list",
797 .config_write
= config_write_access
,
800 static int config_write_access(struct vty
*vty
)
802 struct lyd_node
*dnode
;
805 dnode
= yang_dnode_get(running_config
->dnode
, "/frr-filter:lib");
807 nb_cli_show_dnode_cmds(vty
, dnode
, false);
814 static void access_list_reset_ipv4(void)
816 struct access_list
*access
;
817 struct access_list
*next
;
818 struct access_master
*master
;
820 master
= access_master_get(AFI_IP
);
824 for (access
= master
->str
.head
; access
; access
= next
) {
826 access_list_delete(access
);
829 assert(master
->str
.head
== NULL
);
830 assert(master
->str
.tail
== NULL
);
833 /* Install vty related command. */
834 static void access_list_init_ipv4(void)
836 install_node(&access_node
);
838 install_element(ENABLE_NODE
, &show_ip_access_list_cmd
);
839 install_element(ENABLE_NODE
, &show_ip_access_list_name_cmd
);
842 static struct cmd_node access_ipv6_node
= {
843 .name
= "ipv6 access list",
844 .node
= ACCESS_IPV6_NODE
,
848 static void access_list_reset_ipv6(void)
850 struct access_list
*access
;
851 struct access_list
*next
;
852 struct access_master
*master
;
854 master
= access_master_get(AFI_IP6
);
858 for (access
= master
->str
.head
; access
; access
= next
) {
860 access_list_delete(access
);
863 assert(master
->str
.head
== NULL
);
864 assert(master
->str
.tail
== NULL
);
867 static void access_list_init_ipv6(void)
869 install_node(&access_ipv6_node
);
871 install_element(ENABLE_NODE
, &show_ipv6_access_list_cmd
);
872 install_element(ENABLE_NODE
, &show_ipv6_access_list_name_cmd
);
875 void access_list_init(void)
877 access_list_init_ipv4();
878 access_list_init_ipv6();
879 access_list_init_mac();
884 void access_list_reset(void)
886 access_list_reset_ipv4();
887 access_list_reset_ipv6();
888 access_list_reset_mac();