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 access_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 assignment 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
,
561 json_object_string_addf(
562 json_rule
, "address", "%pI4",
564 json_object_string_addf(
565 json_rule
, "mask", "%pI4",
568 if (filter
->addr_mask
.s_addr
570 vty_out(vty
, " any\n");
572 vty_out(vty
, " %pI4",
574 if (filter
->addr_mask
.s_addr
577 ", wildcard bits %pI4",
586 return vty_json(vty
, json
);
589 /* show MAC access list - this only has MAC filters for now*/
590 DEFUN (show_mac_access_list
,
591 show_mac_access_list_cmd
,
592 "show mac access-list",
595 "List mac access lists\n")
597 return filter_show(vty
, NULL
, AFI_L2VPN
, false);
600 DEFUN (show_mac_access_list_name
,
601 show_mac_access_list_name_cmd
,
602 "show mac access-list ACCESSLIST_MAC_NAME",
605 "List mac access lists\n"
608 return filter_show(vty
, argv
[3]->arg
, AFI_L2VPN
, false);
611 DEFUN (show_ip_access_list
,
612 show_ip_access_list_cmd
,
613 "show ip access-list [json]",
616 "List IP access lists\n"
619 bool uj
= use_json(argc
, argv
);
620 return filter_show(vty
, NULL
, AFI_IP
, uj
);
623 DEFUN (show_ip_access_list_name
,
624 show_ip_access_list_name_cmd
,
625 "show ip access-list ACCESSLIST4_NAME [json]",
628 "List IP access lists\n"
629 "IP access-list name\n"
632 bool uj
= use_json(argc
, argv
);
634 return filter_show(vty
, argv
[idx_acl
]->arg
, AFI_IP
, uj
);
637 DEFUN (show_ipv6_access_list
,
638 show_ipv6_access_list_cmd
,
639 "show ipv6 access-list [json]",
642 "List IPv6 access lists\n"
645 bool uj
= use_json(argc
, argv
);
646 return filter_show(vty
, NULL
, AFI_IP6
, uj
);
649 DEFUN (show_ipv6_access_list_name
,
650 show_ipv6_access_list_name_cmd
,
651 "show ipv6 access-list ACCESSLIST6_NAME [json]",
654 "List IPv6 access lists\n"
655 "IPv6 access-list name\n"
658 bool uj
= use_json(argc
, argv
);
660 return filter_show(vty
, argv
[idx_word
]->arg
, AFI_IP6
, uj
);
663 static void config_write_access_cisco(struct vty
*vty
, struct filter
*mfilter
,
666 struct filter_cisco
*filter
;
668 filter
= &mfilter
->u
.cfilter
;
671 json_object_boolean_add(json
, "extended", !!filter
->extended
);
672 json_object_string_addf(json
, "sourceAddress", "%pI4",
674 json_object_string_addf(json
, "sourceMask", "%pI4",
676 json_object_string_addf(json
, "destinationAddress", "%pI4",
678 json_object_string_addf(json
, "destinationMask", "%pI4",
682 if (filter
->addr_mask
.s_addr
== 0xffffffff)
683 vty_out(vty
, " any");
684 else if (filter
->addr_mask
.s_addr
== INADDR_ANY
)
685 vty_out(vty
, " host %pI4", &filter
->addr
);
687 vty_out(vty
, " %pI4", &filter
->addr
);
688 vty_out(vty
, " %pI4", &filter
->addr_mask
);
691 if (filter
->mask_mask
.s_addr
== 0xffffffff)
692 vty_out(vty
, " any");
693 else if (filter
->mask_mask
.s_addr
== INADDR_ANY
)
694 vty_out(vty
, " host %pI4", &filter
->mask
);
696 vty_out(vty
, " %pI4", &filter
->mask
);
697 vty_out(vty
, " %pI4", &filter
->mask_mask
);
703 static void config_write_access_zebra(struct vty
*vty
, struct filter
*mfilter
,
706 struct filter_zebra
*filter
;
710 filter
= &mfilter
->u
.zfilter
;
714 json_object_string_addf(json
, "prefix", "%pFX", p
);
715 json_object_boolean_add(json
, "exact-match", !!filter
->exact
);
717 if (p
->prefixlen
== 0 && !filter
->exact
)
718 vty_out(vty
, " any");
719 else if (p
->family
== AF_INET6
|| p
->family
== AF_INET
)
720 vty_out(vty
, " %pFX%s", p
,
721 filter
->exact
? " exact-match" : "");
722 else if (p
->family
== AF_ETHERNET
) {
723 if (p
->prefixlen
== 0)
724 vty_out(vty
, " any");
727 prefix_mac2str(&(p
->u
.prefix_eth
), buf
,
735 static struct cmd_node access_mac_node
= {
736 .name
= "MAC access list",
737 .node
= ACCESS_MAC_NODE
,
741 static void access_list_reset_mac(void)
743 struct access_list
*access
;
744 struct access_list
*next
;
745 struct access_master
*master
;
747 master
= access_master_get(AFI_L2VPN
);
751 for (access
= master
->str
.head
; access
; access
= next
) {
753 access_list_delete(access
);
756 assert(master
->str
.head
== NULL
);
757 assert(master
->str
.tail
== NULL
);
760 /* Install vty related command. */
761 static void access_list_init_mac(void)
763 install_node(&access_mac_node
);
765 install_element(ENABLE_NODE
, &show_mac_access_list_cmd
);
766 install_element(ENABLE_NODE
, &show_mac_access_list_name_cmd
);
769 /* Access-list node. */
770 static int config_write_access(struct vty
*vty
);
771 static struct cmd_node access_node
= {
772 .name
= "ipv4 access list",
775 .config_write
= config_write_access
,
778 static int config_write_access(struct vty
*vty
)
780 struct lyd_node
*dnode
;
783 dnode
= yang_dnode_get(running_config
->dnode
, "/frr-filter:lib");
785 nb_cli_show_dnode_cmds(vty
, dnode
, false);
792 static void access_list_reset_ipv4(void)
794 struct access_list
*access
;
795 struct access_list
*next
;
796 struct access_master
*master
;
798 master
= access_master_get(AFI_IP
);
802 for (access
= master
->str
.head
; access
; access
= next
) {
804 access_list_delete(access
);
807 assert(master
->str
.head
== NULL
);
808 assert(master
->str
.tail
== NULL
);
811 /* Install vty related command. */
812 static void access_list_init_ipv4(void)
814 install_node(&access_node
);
816 install_element(ENABLE_NODE
, &show_ip_access_list_cmd
);
817 install_element(ENABLE_NODE
, &show_ip_access_list_name_cmd
);
820 static void access_list_autocomplete_afi(afi_t afi
, vector comps
,
821 struct cmd_token
*token
)
823 struct access_list
*access
;
824 struct access_list
*next
;
825 struct access_master
*master
;
827 master
= access_master_get(afi
);
831 for (access
= master
->str
.head
; access
; access
= next
) {
833 vector_set(comps
, XSTRDUP(MTYPE_COMPLETION
, access
->name
));
837 static struct cmd_node access_ipv6_node
= {
838 .name
= "ipv6 access list",
839 .node
= ACCESS_IPV6_NODE
,
843 static void access_list_autocomplete(vector comps
, struct cmd_token
*token
)
845 access_list_autocomplete_afi(AFI_IP
, comps
, token
);
846 access_list_autocomplete_afi(AFI_IP6
, comps
, token
);
847 access_list_autocomplete_afi(AFI_L2VPN
, comps
, token
);
850 static void access_list4_autocomplete(vector comps
, struct cmd_token
*token
)
852 access_list_autocomplete_afi(AFI_IP
, comps
, token
);
855 static void access_list6_autocomplete(vector comps
, struct cmd_token
*token
)
857 access_list_autocomplete_afi(AFI_IP6
, comps
, token
);
860 static void access_list_mac_autocomplete(vector comps
, struct cmd_token
*token
)
862 access_list_autocomplete_afi(AFI_L2VPN
, comps
, token
);
865 static const struct cmd_variable_handler access_list_handlers
[] = {
866 {.tokenname
= "ACCESSLIST_NAME",
867 .completions
= access_list_autocomplete
},
868 {.tokenname
= "ACCESSLIST4_NAME",
869 .completions
= access_list4_autocomplete
},
870 {.tokenname
= "ACCESSLIST6_NAME",
871 .completions
= access_list6_autocomplete
},
872 {.tokenname
= "ACCESSLIST_MAC_NAME",
873 .completions
= access_list_mac_autocomplete
},
874 {.completions
= NULL
}};
876 static void access_list_reset_ipv6(void)
878 struct access_list
*access
;
879 struct access_list
*next
;
880 struct access_master
*master
;
882 master
= access_master_get(AFI_IP6
);
886 for (access
= master
->str
.head
; access
; access
= next
) {
888 access_list_delete(access
);
891 assert(master
->str
.head
== NULL
);
892 assert(master
->str
.tail
== NULL
);
895 static void access_list_init_ipv6(void)
897 install_node(&access_ipv6_node
);
899 install_element(ENABLE_NODE
, &show_ipv6_access_list_cmd
);
900 install_element(ENABLE_NODE
, &show_ipv6_access_list_name_cmd
);
903 void access_list_init(void)
905 cmd_variable_handler_register(access_list_handlers
);
907 access_list_init_ipv4();
908 access_list_init_ipv6();
909 access_list_init_mac();
914 void access_list_reset(void)
916 access_list_reset_ipv4();
917 access_list_reset_ipv6();
918 access_list_reset_mac();