1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /* Route filtering function.
3 * Copyright (C) 1998, 1999 Kunihiro Ishiguro
12 #include "sockunion.h"
17 #include "northbound_cli.h"
20 DEFINE_MTYPE_STATIC(LIB
, ACCESS_LIST
, "Access List");
21 DEFINE_MTYPE_STATIC(LIB
, ACCESS_LIST_STR
, "Access List Str");
22 DEFINE_MTYPE_STATIC(LIB
, ACCESS_FILTER
, "Access Filter");
24 /* Static structure for mac access_list's master. */
25 static struct access_master access_master_mac
= {
31 /* Static structure for IPv4 access_list's master. */
32 static struct access_master access_master_ipv4
= {
38 /* Static structure for IPv6 access_list's master. */
39 static struct access_master access_master_ipv6
= {
45 static struct access_master
*access_master_get(afi_t afi
)
48 return &access_master_ipv4
;
49 else if (afi
== AFI_IP6
)
50 return &access_master_ipv6
;
51 else if (afi
== AFI_L2VPN
)
52 return &access_master_mac
;
56 /* Allocate new filter structure. */
57 struct filter
*filter_new(void)
59 return XCALLOC(MTYPE_ACCESS_FILTER
, sizeof(struct filter
));
62 static void filter_free(struct filter
*filter
)
64 XFREE(MTYPE_ACCESS_FILTER
, filter
);
67 /* Return string of filter_type. */
68 static const char *filter_type_str(struct filter
*filter
)
70 switch (filter
->type
) {
82 /* If filter match to the prefix then return 1. */
83 static int filter_match_cisco(struct filter
*mfilter
, const struct prefix
*p
)
85 struct filter_cisco
*filter
;
90 filter
= &mfilter
->u
.cfilter
;
91 check_addr
= p
->u
.prefix4
.s_addr
& ~filter
->addr_mask
.s_addr
;
93 if (filter
->extended
) {
94 masklen2ip(p
->prefixlen
, &mask
);
95 check_mask
= mask
.s_addr
& ~filter
->mask_mask
.s_addr
;
97 if (memcmp(&check_addr
, &filter
->addr
.s_addr
, IPV4_MAX_BYTELEN
)
99 && memcmp(&check_mask
, &filter
->mask
.s_addr
,
103 } else if (memcmp(&check_addr
, &filter
->addr
.s_addr
, IPV4_MAX_BYTELEN
)
110 /* If filter match to the prefix then return 1. */
111 static int filter_match_zebra(struct filter
*mfilter
, const struct prefix
*p
)
113 struct filter_zebra
*filter
= NULL
;
115 filter
= &mfilter
->u
.zfilter
;
117 if (filter
->prefix
.family
== p
->family
) {
119 if (filter
->prefix
.prefixlen
== p
->prefixlen
)
120 return prefix_match(&filter
->prefix
, p
);
124 return prefix_match(&filter
->prefix
, p
);
129 /* Allocate new access list structure. */
130 static struct access_list
*access_list_new(void)
132 return XCALLOC(MTYPE_ACCESS_LIST
, sizeof(struct access_list
));
135 /* Free allocated access_list. */
136 static void access_list_free(struct access_list
*access
)
138 XFREE(MTYPE_ACCESS_LIST
, access
);
141 /* Delete access_list from access_master and free it. */
142 void access_list_delete(struct access_list
*access
)
144 struct filter
*filter
;
146 struct access_list_list
*list
;
147 struct access_master
*master
;
149 for (filter
= access
->head
; filter
; filter
= next
) {
154 master
= access
->master
;
159 access
->next
->prev
= access
->prev
;
161 list
->tail
= access
->prev
;
164 access
->prev
->next
= access
->next
;
166 list
->head
= access
->next
;
168 route_map_notify_dependencies(access
->name
, RMAP_EVENT_FILTER_DELETED
);
170 if (master
->delete_hook
)
171 master
->delete_hook(access
);
173 XFREE(MTYPE_ACCESS_LIST_STR
, access
->name
);
175 XFREE(MTYPE_TMP
, access
->remark
);
177 access_list_free(access
);
180 /* Insert new access list to list of access_list. Each access_list
181 is sorted by the name. */
182 static struct access_list
*access_list_insert(afi_t afi
, const char *name
)
184 struct access_list
*access
;
185 struct access_list
*point
;
186 struct access_list_list
*alist
;
187 struct access_master
*master
;
189 master
= access_master_get(afi
);
193 /* Allocate new access_list and copy given name. */
194 access
= access_list_new();
195 access
->name
= XSTRDUP(MTYPE_ACCESS_LIST_STR
, name
);
196 access
->master
= master
;
198 /* Set access_list to string list. */
199 alist
= &master
->str
;
201 /* Set point to insertion point. */
202 for (point
= alist
->head
; point
; point
= point
->next
)
203 if (strcmp(point
->name
, name
) >= 0)
206 /* In case of this is the first element of master. */
207 if (alist
->head
== NULL
) {
208 alist
->head
= alist
->tail
= access
;
212 /* In case of insertion is made at the tail of access_list. */
214 access
->prev
= alist
->tail
;
215 alist
->tail
->next
= access
;
216 alist
->tail
= access
;
220 /* In case of insertion is made at the head of access_list. */
221 if (point
== alist
->head
) {
222 access
->next
= alist
->head
;
223 alist
->head
->prev
= access
;
224 alist
->head
= access
;
228 /* Insertion is made at middle of the access_list. */
229 access
->next
= point
;
230 access
->prev
= point
->prev
;
233 point
->prev
->next
= access
;
234 point
->prev
= access
;
239 /* Lookup access_list from list of access_list by name. */
240 struct access_list
*access_list_lookup(afi_t afi
, const char *name
)
242 struct access_list
*access
;
243 struct access_master
*master
;
248 master
= access_master_get(afi
);
252 for (access
= master
->str
.head
; access
; access
= access
->next
)
253 if (strcmp(access
->name
, name
) == 0)
259 /* Get access list from list of access_list. If there isn't matched
260 access_list create new one and return it. */
261 struct access_list
*access_list_get(afi_t afi
, const char *name
)
263 struct access_list
*access
;
265 access
= access_list_lookup(afi
, name
);
267 access
= access_list_insert(afi
, name
);
271 /* Apply access list to object (which should be struct prefix *). */
272 enum filter_type
access_list_apply(struct access_list
*access
,
275 struct filter
*filter
;
276 const struct prefix
*p
= (const struct prefix
*)object
;
281 for (filter
= access
->head
; filter
; filter
= filter
->next
) {
283 if (filter_match_cisco(filter
, p
))
286 if (filter_match_zebra(filter
, p
))
294 /* Add hook function. */
295 void access_list_add_hook(void (*func
)(struct access_list
*access
))
297 access_master_ipv4
.add_hook
= func
;
298 access_master_ipv6
.add_hook
= func
;
299 access_master_mac
.add_hook
= func
;
302 /* Delete hook function. */
303 void access_list_delete_hook(void (*func
)(struct access_list
*access
))
305 access_master_ipv4
.delete_hook
= func
;
306 access_master_ipv6
.delete_hook
= func
;
307 access_master_mac
.delete_hook
= func
;
310 /* Calculate new sequential number. */
311 int64_t filter_new_seq_get(struct access_list
*access
)
315 struct filter
*filter
;
319 for (filter
= access
->head
; filter
; filter
= filter
->next
) {
320 if (maxseq
< filter
->seq
)
321 maxseq
= filter
->seq
;
324 newseq
= ((maxseq
/ 5) * 5) + 5;
326 return (newseq
> UINT_MAX
) ? UINT_MAX
: newseq
;
329 /* Return access list entry which has same seq number. */
330 static struct filter
*filter_seq_check(struct access_list
*access
,
333 struct filter
*filter
;
335 for (filter
= access
->head
; filter
; filter
= filter
->next
)
336 if (filter
->seq
== seq
)
341 /* Delete filter from specified access_list. If there is hook
342 function execute it. */
343 void access_list_filter_delete(struct access_list
*access
,
344 struct filter
*filter
)
346 struct access_master
*master
;
348 master
= access
->master
;
351 filter
->next
->prev
= filter
->prev
;
353 access
->tail
= filter
->prev
;
356 filter
->prev
->next
= filter
->next
;
358 access
->head
= filter
->next
;
362 route_map_notify_dependencies(access
->name
, RMAP_EVENT_FILTER_DELETED
);
363 /* Run hook function. */
364 if (master
->delete_hook
)
365 (*master
->delete_hook
)(access
);
368 /* Add new filter to the end of specified access_list. */
369 void access_list_filter_add(struct access_list
*access
,
370 struct filter
*filter
)
372 struct filter
*replace
;
373 struct filter
*point
;
375 /* Automatic assignment of seq no. */
376 if (filter
->seq
== -1)
377 filter
->seq
= filter_new_seq_get(access
);
379 if (access
->tail
&& filter
->seq
> access
->tail
->seq
)
382 /* Is there any same seq access list filter? */
383 replace
= filter_seq_check(access
, filter
->seq
);
385 access_list_filter_delete(access
, replace
);
387 /* Check insert point. */
388 for (point
= access
->head
; point
; point
= point
->next
)
389 if (point
->seq
>= filter
->seq
)
393 /* In case of this is the first element of the list. */
394 filter
->next
= point
;
398 point
->prev
->next
= filter
;
400 access
->head
= filter
;
402 filter
->prev
= point
->prev
;
403 point
->prev
= filter
;
406 access
->tail
->next
= filter
;
408 access
->head
= filter
;
410 filter
->prev
= access
->tail
;
411 access
->tail
= filter
;
414 /* Run hook function. */
415 if (access
->master
->add_hook
)
416 (*access
->master
->add_hook
)(access
);
417 route_map_notify_dependencies(access
->name
, RMAP_EVENT_FILTER_ADDED
);
421 deny Specify packets to reject
422 permit Specify packets to forward
427 Hostname or A.B.C.D Address to match
429 host A single host address
432 static void config_write_access_zebra(struct vty
*, struct filter
*,
434 static void config_write_access_cisco(struct vty
*, struct filter
*,
437 static const char *filter_type2str(struct filter
*filter
)
440 if (filter
->u
.cfilter
.extended
)
448 /* show access-list command. */
449 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
;
457 json_object
*json
= NULL
;
458 json_object
*json_proto
= NULL
;
460 master
= access_master_get(afi
);
461 if (master
== NULL
) {
463 vty_out(vty
, "{}\n");
468 json
= json_object_new_object();
470 /* Print the name of the protocol */
472 json_proto
= json_object_new_object();
473 json_object_object_add(json
, frr_protoname
, json_proto
);
475 vty_out(vty
, "%s:\n", frr_protoname
);
477 for (access
= master
->str
.head
; access
; access
= access
->next
) {
478 json_object
*json_acl
= NULL
;
479 json_object
*json_rules
= NULL
;
481 if (name
&& strcmp(access
->name
, name
) != 0)
486 for (mfilter
= access
->head
; mfilter
; mfilter
= mfilter
->next
) {
487 json_object
*json_rule
= NULL
;
489 filter
= &mfilter
->u
.cfilter
;
492 const char *type
= filter_type2str(mfilter
);
495 json_acl
= json_object_new_object();
496 json_object_object_add(json_proto
,
500 json_object_string_add(json_acl
, "type",
502 json_object_string_add(json_acl
,
505 json_rules
= json_object_new_array();
506 json_object_object_add(
507 json_acl
, "rules", json_rules
);
509 vty_out(vty
, "%s %s access list %s\n",
523 json_rule
= json_object_new_object();
524 json_object_array_add(json_rules
, json_rule
);
526 json_object_int_add(json_rule
, "sequenceNumber",
528 json_object_string_add(
529 json_rule
, "filterType",
530 filter_type_str(mfilter
));
532 vty_out(vty
, " seq %" PRId64
, mfilter
->seq
);
533 vty_out(vty
, " %s%s", filter_type_str(mfilter
),
534 mfilter
->type
== FILTER_DENY
? " "
539 config_write_access_zebra(vty
, mfilter
,
541 else if (filter
->extended
)
542 config_write_access_cisco(vty
, mfilter
,
546 json_object_string_addf(
547 json_rule
, "address", "%pI4",
549 json_object_string_addf(
550 json_rule
, "mask", "%pI4",
553 if (filter
->addr_mask
.s_addr
555 vty_out(vty
, " any\n");
557 vty_out(vty
, " %pI4",
559 if (filter
->addr_mask
.s_addr
562 ", wildcard bits %pI4",
571 return vty_json(vty
, json
);
574 /* show MAC access list - this only has MAC filters for now*/
575 DEFUN (show_mac_access_list
,
576 show_mac_access_list_cmd
,
577 "show mac access-list",
580 "List mac access lists\n")
582 return filter_show(vty
, NULL
, AFI_L2VPN
, false);
585 DEFUN (show_mac_access_list_name
,
586 show_mac_access_list_name_cmd
,
587 "show mac access-list ACCESSLIST_MAC_NAME",
590 "List mac access lists\n"
593 return filter_show(vty
, argv
[3]->arg
, AFI_L2VPN
, false);
596 DEFUN (show_ip_access_list
,
597 show_ip_access_list_cmd
,
598 "show ip access-list [json]",
601 "List IP access lists\n"
604 bool uj
= use_json(argc
, argv
);
605 return filter_show(vty
, NULL
, AFI_IP
, uj
);
608 DEFUN (show_ip_access_list_name
,
609 show_ip_access_list_name_cmd
,
610 "show ip access-list ACCESSLIST4_NAME [json]",
613 "List IP access lists\n"
614 "IP access-list name\n"
617 bool uj
= use_json(argc
, argv
);
619 return filter_show(vty
, argv
[idx_acl
]->arg
, AFI_IP
, uj
);
622 DEFUN (show_ipv6_access_list
,
623 show_ipv6_access_list_cmd
,
624 "show ipv6 access-list [json]",
627 "List IPv6 access lists\n"
630 bool uj
= use_json(argc
, argv
);
631 return filter_show(vty
, NULL
, AFI_IP6
, uj
);
634 DEFUN (show_ipv6_access_list_name
,
635 show_ipv6_access_list_name_cmd
,
636 "show ipv6 access-list ACCESSLIST6_NAME [json]",
639 "List IPv6 access lists\n"
640 "IPv6 access-list name\n"
643 bool uj
= use_json(argc
, argv
);
645 return filter_show(vty
, argv
[idx_word
]->arg
, AFI_IP6
, uj
);
648 static void config_write_access_cisco(struct vty
*vty
, struct filter
*mfilter
,
651 struct filter_cisco
*filter
;
653 filter
= &mfilter
->u
.cfilter
;
656 json_object_boolean_add(json
, "extended", !!filter
->extended
);
657 json_object_string_addf(json
, "sourceAddress", "%pI4",
659 json_object_string_addf(json
, "sourceMask", "%pI4",
661 json_object_string_addf(json
, "destinationAddress", "%pI4",
663 json_object_string_addf(json
, "destinationMask", "%pI4",
667 if (filter
->addr_mask
.s_addr
== 0xffffffff)
668 vty_out(vty
, " any");
669 else if (filter
->addr_mask
.s_addr
== INADDR_ANY
)
670 vty_out(vty
, " host %pI4", &filter
->addr
);
672 vty_out(vty
, " %pI4", &filter
->addr
);
673 vty_out(vty
, " %pI4", &filter
->addr_mask
);
676 if (filter
->mask_mask
.s_addr
== 0xffffffff)
677 vty_out(vty
, " any");
678 else if (filter
->mask_mask
.s_addr
== INADDR_ANY
)
679 vty_out(vty
, " host %pI4", &filter
->mask
);
681 vty_out(vty
, " %pI4", &filter
->mask
);
682 vty_out(vty
, " %pI4", &filter
->mask_mask
);
688 static void config_write_access_zebra(struct vty
*vty
, struct filter
*mfilter
,
691 struct filter_zebra
*filter
;
695 filter
= &mfilter
->u
.zfilter
;
699 json_object_string_addf(json
, "prefix", "%pFX", p
);
700 json_object_boolean_add(json
, "exact-match", !!filter
->exact
);
702 if (p
->prefixlen
== 0 && !filter
->exact
)
703 vty_out(vty
, " any");
704 else if (p
->family
== AF_INET6
|| p
->family
== AF_INET
)
705 vty_out(vty
, " %pFX%s", p
,
706 filter
->exact
? " exact-match" : "");
707 else if (p
->family
== AF_ETHERNET
) {
708 if (p
->prefixlen
== 0)
709 vty_out(vty
, " any");
712 prefix_mac2str(&(p
->u
.prefix_eth
), buf
,
720 static struct cmd_node access_mac_node
= {
721 .name
= "MAC access list",
722 .node
= ACCESS_MAC_NODE
,
726 static void access_list_reset_mac(void)
728 struct access_list
*access
;
729 struct access_list
*next
;
730 struct access_master
*master
;
732 master
= access_master_get(AFI_L2VPN
);
736 for (access
= master
->str
.head
; access
; access
= next
) {
738 access_list_delete(access
);
741 assert(master
->str
.head
== NULL
);
742 assert(master
->str
.tail
== NULL
);
745 /* Install vty related command. */
746 static void access_list_init_mac(void)
748 install_node(&access_mac_node
);
750 install_element(ENABLE_NODE
, &show_mac_access_list_cmd
);
751 install_element(ENABLE_NODE
, &show_mac_access_list_name_cmd
);
754 /* Access-list node. */
755 static int config_write_access(struct vty
*vty
);
756 static struct cmd_node access_node
= {
757 .name
= "ipv4 access list",
760 .config_write
= config_write_access
,
763 static int config_write_access(struct vty
*vty
)
765 struct lyd_node
*dnode
;
768 dnode
= yang_dnode_get(running_config
->dnode
, "/frr-filter:lib");
770 nb_cli_show_dnode_cmds(vty
, dnode
, false);
777 static void access_list_reset_ipv4(void)
779 struct access_list
*access
;
780 struct access_list
*next
;
781 struct access_master
*master
;
783 master
= access_master_get(AFI_IP
);
787 for (access
= master
->str
.head
; access
; access
= next
) {
789 access_list_delete(access
);
792 assert(master
->str
.head
== NULL
);
793 assert(master
->str
.tail
== NULL
);
796 /* Install vty related command. */
797 static void access_list_init_ipv4(void)
799 install_node(&access_node
);
801 install_element(ENABLE_NODE
, &show_ip_access_list_cmd
);
802 install_element(ENABLE_NODE
, &show_ip_access_list_name_cmd
);
805 static void access_list_autocomplete_afi(afi_t afi
, vector comps
,
806 struct cmd_token
*token
)
808 struct access_list
*access
;
809 struct access_list
*next
;
810 struct access_master
*master
;
812 master
= access_master_get(afi
);
816 for (access
= master
->str
.head
; access
; access
= next
) {
818 vector_set(comps
, XSTRDUP(MTYPE_COMPLETION
, access
->name
));
822 static struct cmd_node access_ipv6_node
= {
823 .name
= "ipv6 access list",
824 .node
= ACCESS_IPV6_NODE
,
828 static void access_list_autocomplete(vector comps
, struct cmd_token
*token
)
830 access_list_autocomplete_afi(AFI_IP
, comps
, token
);
831 access_list_autocomplete_afi(AFI_IP6
, comps
, token
);
832 access_list_autocomplete_afi(AFI_L2VPN
, comps
, token
);
835 static void access_list4_autocomplete(vector comps
, struct cmd_token
*token
)
837 access_list_autocomplete_afi(AFI_IP
, comps
, token
);
840 static void access_list6_autocomplete(vector comps
, struct cmd_token
*token
)
842 access_list_autocomplete_afi(AFI_IP6
, comps
, token
);
845 static void access_list_mac_autocomplete(vector comps
, struct cmd_token
*token
)
847 access_list_autocomplete_afi(AFI_L2VPN
, comps
, token
);
850 static const struct cmd_variable_handler access_list_handlers
[] = {
851 {.tokenname
= "ACCESSLIST_NAME",
852 .completions
= access_list_autocomplete
},
853 {.tokenname
= "ACCESSLIST4_NAME",
854 .completions
= access_list4_autocomplete
},
855 {.tokenname
= "ACCESSLIST6_NAME",
856 .completions
= access_list6_autocomplete
},
857 {.tokenname
= "ACCESSLIST_MAC_NAME",
858 .completions
= access_list_mac_autocomplete
},
859 {.completions
= NULL
}};
861 static void access_list_reset_ipv6(void)
863 struct access_list
*access
;
864 struct access_list
*next
;
865 struct access_master
*master
;
867 master
= access_master_get(AFI_IP6
);
871 for (access
= master
->str
.head
; access
; access
= next
) {
873 access_list_delete(access
);
876 assert(master
->str
.head
== NULL
);
877 assert(master
->str
.tail
== NULL
);
880 static void access_list_init_ipv6(void)
882 install_node(&access_ipv6_node
);
884 install_element(ENABLE_NODE
, &show_ipv6_access_list_cmd
);
885 install_element(ENABLE_NODE
, &show_ipv6_access_list_name_cmd
);
888 void access_list_init(void)
890 cmd_variable_handler_register(access_list_handlers
);
892 access_list_init_ipv4();
893 access_list_init_ipv6();
894 access_list_init_mac();
899 void access_list_reset(void)
901 access_list_reset_ipv4();
902 access_list_reset_ipv6();
903 access_list_reset_mac();