]> git.proxmox.com Git - mirror_frr.git/blob - lib/filter.c
lib: use json-printf in filter code
[mirror_frr.git] / lib / filter.c
1 /* Route filtering function.
2 * Copyright (C) 1998, 1999 Kunihiro Ishiguro
3 *
4 * This file is part of GNU Zebra.
5 *
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.
10 *
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.
15 *
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
19 */
20
21 #include <zebra.h>
22
23 #include "prefix.h"
24 #include "filter.h"
25 #include "memory.h"
26 #include "command.h"
27 #include "sockunion.h"
28 #include "buffer.h"
29 #include "log.h"
30 #include "routemap.h"
31 #include "libfrr.h"
32 #include "northbound_cli.h"
33 #include "json.h"
34
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");
38
39 /* Static structure for mac access_list's master. */
40 static struct access_master access_master_mac = {
41 {NULL, NULL},
42 NULL,
43 NULL,
44 };
45
46 /* Static structure for IPv4 access_list's master. */
47 static struct access_master access_master_ipv4 = {
48 {NULL, NULL},
49 NULL,
50 NULL,
51 };
52
53 /* Static structure for IPv6 access_list's master. */
54 static struct access_master access_master_ipv6 = {
55 {NULL, NULL},
56 NULL,
57 NULL,
58 };
59
60 static struct access_master *access_master_get(afi_t afi)
61 {
62 if (afi == AFI_IP)
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;
68 return NULL;
69 }
70
71 /* Allocate new filter structure. */
72 struct filter *filter_new(void)
73 {
74 return XCALLOC(MTYPE_ACCESS_FILTER, sizeof(struct filter));
75 }
76
77 static void filter_free(struct filter *filter)
78 {
79 XFREE(MTYPE_ACCESS_FILTER, filter);
80 }
81
82 /* Return string of filter_type. */
83 static const char *filter_type_str(struct filter *filter)
84 {
85 switch (filter->type) {
86 case FILTER_PERMIT:
87 return "permit";
88 case FILTER_DENY:
89 return "deny";
90 case FILTER_DYNAMIC:
91 return "dynamic";
92 default:
93 return "";
94 }
95 }
96
97 /* If filter match to the prefix then return 1. */
98 static int filter_match_cisco(struct filter *mfilter, const struct prefix *p)
99 {
100 struct filter_cisco *filter;
101 struct in_addr mask;
102 uint32_t check_addr;
103 uint32_t check_mask;
104
105 filter = &mfilter->u.cfilter;
106 check_addr = p->u.prefix4.s_addr & ~filter->addr_mask.s_addr;
107
108 if (filter->extended) {
109 masklen2ip(p->prefixlen, &mask);
110 check_mask = mask.s_addr & ~filter->mask_mask.s_addr;
111
112 if (memcmp(&check_addr, &filter->addr.s_addr, IPV4_MAX_BYTELEN)
113 == 0
114 && memcmp(&check_mask, &filter->mask.s_addr,
115 IPV4_MAX_BYTELEN)
116 == 0)
117 return 1;
118 } else if (memcmp(&check_addr, &filter->addr.s_addr, IPV4_MAX_BYTELEN)
119 == 0)
120 return 1;
121
122 return 0;
123 }
124
125 /* If filter match to the prefix then return 1. */
126 static int filter_match_zebra(struct filter *mfilter, const struct prefix *p)
127 {
128 struct filter_zebra *filter = NULL;
129
130 filter = &mfilter->u.zfilter;
131
132 if (filter->prefix.family == p->family) {
133 if (filter->exact) {
134 if (filter->prefix.prefixlen == p->prefixlen)
135 return prefix_match(&filter->prefix, p);
136 else
137 return 0;
138 } else
139 return prefix_match(&filter->prefix, p);
140 } else
141 return 0;
142 }
143
144 /* Allocate new access list structure. */
145 static struct access_list *access_list_new(void)
146 {
147 return XCALLOC(MTYPE_ACCESS_LIST, sizeof(struct access_list));
148 }
149
150 /* Free allocated access_list. */
151 static void access_list_free(struct access_list *access)
152 {
153 XFREE(MTYPE_ACCESS_LIST, access);
154 }
155
156 /* Delete access_list from access_master and free it. */
157 void access_list_delete(struct access_list *access)
158 {
159 struct filter *filter;
160 struct filter *next;
161 struct access_list_list *list;
162 struct access_master *master;
163
164 for (filter = access->head; filter; filter = next) {
165 next = filter->next;
166 filter_free(filter);
167 }
168
169 master = access->master;
170
171 list = &master->str;
172
173 if (access->next)
174 access->next->prev = access->prev;
175 else
176 list->tail = access->prev;
177
178 if (access->prev)
179 access->prev->next = access->next;
180 else
181 list->head = access->next;
182
183 route_map_notify_dependencies(access->name, RMAP_EVENT_FILTER_DELETED);
184
185 if (master->delete_hook)
186 master->delete_hook(access);
187
188 XFREE(MTYPE_ACCESS_LIST_STR, access->name);
189
190 XFREE(MTYPE_TMP, access->remark);
191
192 access_list_free(access);
193 }
194
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)
198 {
199 struct access_list *access;
200 struct access_list *point;
201 struct access_list_list *alist;
202 struct access_master *master;
203
204 master = access_master_get(afi);
205 if (master == NULL)
206 return NULL;
207
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;
212
213 /* Set access_list to string list. */
214 alist = &master->str;
215
216 /* Set point to insertion point. */
217 for (point = alist->head; point; point = point->next)
218 if (strcmp(point->name, name) >= 0)
219 break;
220
221 /* In case of this is the first element of master. */
222 if (alist->head == NULL) {
223 alist->head = alist->tail = access;
224 return access;
225 }
226
227 /* In case of insertion is made at the tail of access_list. */
228 if (point == NULL) {
229 access->prev = alist->tail;
230 alist->tail->next = access;
231 alist->tail = access;
232 return access;
233 }
234
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;
240 return access;
241 }
242
243 /* Insertion is made at middle of the access_list. */
244 access->next = point;
245 access->prev = point->prev;
246
247 if (point->prev)
248 point->prev->next = access;
249 point->prev = access;
250
251 return access;
252 }
253
254 /* Lookup access_list from list of access_list by name. */
255 struct access_list *access_list_lookup(afi_t afi, const char *name)
256 {
257 struct access_list *access;
258 struct access_master *master;
259
260 if (name == NULL)
261 return NULL;
262
263 master = access_master_get(afi);
264 if (master == NULL)
265 return NULL;
266
267 for (access = master->str.head; access; access = access->next)
268 if (strcmp(access->name, name) == 0)
269 return access;
270
271 return NULL;
272 }
273
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)
277 {
278 struct access_list *access;
279
280 access = access_list_lookup(afi, name);
281 if (access == NULL)
282 access = access_list_insert(afi, name);
283 return access;
284 }
285
286 /* Apply access list to object (which should be struct prefix *). */
287 enum filter_type access_list_apply(struct access_list *access,
288 const void *object)
289 {
290 struct filter *filter;
291 const struct prefix *p = (const struct prefix *)object;
292
293 if (access == NULL)
294 return FILTER_DENY;
295
296 for (filter = access->head; filter; filter = filter->next) {
297 if (filter->cisco) {
298 if (filter_match_cisco(filter, p))
299 return filter->type;
300 } else {
301 if (filter_match_zebra(filter, p))
302 return filter->type;
303 }
304 }
305
306 return FILTER_DENY;
307 }
308
309 /* Add hook function. */
310 void access_list_add_hook(void (*func)(struct access_list *access))
311 {
312 access_master_ipv4.add_hook = func;
313 access_master_ipv6.add_hook = func;
314 access_master_mac.add_hook = func;
315 }
316
317 /* Delete hook function. */
318 void access_list_delete_hook(void (*func)(struct access_list *access))
319 {
320 access_master_ipv4.delete_hook = func;
321 access_master_ipv6.delete_hook = func;
322 access_master_mac.delete_hook = func;
323 }
324
325 /* Calculate new sequential number. */
326 int64_t filter_new_seq_get(struct access_list *access)
327 {
328 int64_t maxseq;
329 int64_t newseq;
330 struct filter *filter;
331
332 maxseq = 0;
333
334 for (filter = access->head; filter; filter = filter->next) {
335 if (maxseq < filter->seq)
336 maxseq = filter->seq;
337 }
338
339 newseq = ((maxseq / 5) * 5) + 5;
340
341 return (newseq > UINT_MAX) ? UINT_MAX : newseq;
342 }
343
344 /* Return access list entry which has same seq number. */
345 static struct filter *filter_seq_check(struct access_list *access,
346 int64_t seq)
347 {
348 struct filter *filter;
349
350 for (filter = access->head; filter; filter = filter->next)
351 if (filter->seq == seq)
352 return filter;
353 return NULL;
354 }
355
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)
360 {
361 struct access_master *master;
362
363 master = access->master;
364
365 if (filter->next)
366 filter->next->prev = filter->prev;
367 else
368 access->tail = filter->prev;
369
370 if (filter->prev)
371 filter->prev->next = filter->next;
372 else
373 access->head = filter->next;
374
375 filter_free(filter);
376
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);
381 }
382
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)
386 {
387 struct filter *replace;
388 struct filter *point;
389
390 /* Automatic assignment of seq no. */
391 if (filter->seq == -1)
392 filter->seq = filter_new_seq_get(access);
393
394 if (access->tail && filter->seq > access->tail->seq)
395 point = NULL;
396 else {
397 /* Is there any same seq access list filter? */
398 replace = filter_seq_check(access, filter->seq);
399 if (replace)
400 access_list_filter_delete(access, replace);
401
402 /* Check insert point. */
403 for (point = access->head; point; point = point->next)
404 if (point->seq >= filter->seq)
405 break;
406 }
407
408 /* In case of this is the first element of the list. */
409 filter->next = point;
410
411 if (point) {
412 if (point->prev)
413 point->prev->next = filter;
414 else
415 access->head = filter;
416
417 filter->prev = point->prev;
418 point->prev = filter;
419 } else {
420 if (access->tail)
421 access->tail->next = filter;
422 else
423 access->head = filter;
424
425 filter->prev = access->tail;
426 access->tail = filter;
427 }
428
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);
433 }
434
435 /*
436 deny Specify packets to reject
437 permit Specify packets to forward
438 dynamic ?
439 */
440
441 /*
442 Hostname or A.B.C.D Address to match
443 any Any source host
444 host A single host address
445 */
446
447 static void config_write_access_zebra(struct vty *, struct filter *,
448 json_object *);
449 static void config_write_access_cisco(struct vty *, struct filter *,
450 json_object *);
451
452 static const char *filter_type2str(struct filter *filter)
453 {
454 if (filter->cisco) {
455 if (filter->u.cfilter.extended)
456 return "Extended";
457 else
458 return "Standard";
459 } else
460 return "Zebra";
461 }
462
463 /* show access-list command. */
464 static int filter_show(struct vty *vty, const char *name, afi_t afi,
465 bool use_json)
466 {
467 struct access_list *access;
468 struct access_master *master;
469 struct filter *mfilter;
470 struct filter_cisco *filter;
471 bool first;
472 json_object *json = NULL;
473 json_object *json_proto = NULL;
474
475 master = access_master_get(afi);
476 if (master == NULL) {
477 if (use_json)
478 vty_out(vty, "{}\n");
479 return 0;
480 }
481
482 if (use_json)
483 json = json_object_new_object();
484
485 /* Print the name of the protocol */
486 if (json) {
487 json_proto = json_object_new_object();
488 json_object_object_add(json, frr_protoname, json_proto);
489 } else
490 vty_out(vty, "%s:\n", frr_protoname);
491
492 for (access = master->str.head; access; access = access->next) {
493 json_object *json_acl = NULL;
494 json_object *json_rules = NULL;
495
496 if (name && strcmp(access->name, name) != 0)
497 continue;
498
499 first = true;
500
501 for (mfilter = access->head; mfilter; mfilter = mfilter->next) {
502 json_object *json_rule = NULL;
503
504 filter = &mfilter->u.cfilter;
505
506 if (first) {
507 const char *type = filter_type2str(mfilter);
508
509 if (json) {
510 json_acl = json_object_new_object();
511 json_object_object_add(json_proto,
512 access->name,
513 json_acl);
514
515 json_object_string_add(json_acl, "type",
516 type);
517 json_object_string_add(json_acl,
518 "addressFamily",
519 afi2str(afi));
520 json_rules = json_object_new_array();
521 json_object_object_add(
522 json_acl, "rules", json_rules);
523 } else {
524 vty_out(vty, "%s %s access list %s\n",
525 type,
526 (afi == AFI_IP)
527 ? ("IP")
528 : ((afi == AFI_IP6)
529 ? ("IPv6 ")
530 : ("MAC ")),
531 access->name);
532 }
533
534 first = false;
535 }
536
537 if (json) {
538 json_rule = json_object_new_object();
539 json_object_array_add(json_rules, json_rule);
540
541 json_object_int_add(json_rule, "sequenceNumber",
542 mfilter->seq);
543 json_object_string_add(
544 json_rule, "filterType",
545 filter_type_str(mfilter));
546 } else {
547 vty_out(vty, " seq %" PRId64, mfilter->seq);
548 vty_out(vty, " %s%s", filter_type_str(mfilter),
549 mfilter->type == FILTER_DENY ? " "
550 : "");
551 }
552
553 if (!mfilter->cisco)
554 config_write_access_zebra(vty, mfilter,
555 json_rule);
556 else if (filter->extended)
557 config_write_access_cisco(vty, mfilter,
558 json_rule);
559 else {
560 if (json) {
561 json_object_string_addf(
562 json_rule, "address", "%pI4",
563 &filter->addr);
564 json_object_string_addf(
565 json_rule, "mask", "%pI4",
566 &filter->addr_mask);
567 } else {
568 if (filter->addr_mask.s_addr
569 == 0xffffffff)
570 vty_out(vty, " any\n");
571 else {
572 vty_out(vty, " %pI4",
573 &filter->addr);
574 if (filter->addr_mask.s_addr
575 != INADDR_ANY)
576 vty_out(vty,
577 ", wildcard bits %pI4",
578 &filter->addr_mask);
579 vty_out(vty, "\n");
580 }
581 }
582 }
583 }
584 }
585
586 return vty_json(vty, json);
587 }
588
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",
593 SHOW_STR
594 "mac access lists\n"
595 "List mac access lists\n")
596 {
597 return filter_show(vty, NULL, AFI_L2VPN, false);
598 }
599
600 DEFUN (show_mac_access_list_name,
601 show_mac_access_list_name_cmd,
602 "show mac access-list ACCESSLIST_MAC_NAME",
603 SHOW_STR
604 "mac access lists\n"
605 "List mac access lists\n"
606 "mac address\n")
607 {
608 return filter_show(vty, argv[3]->arg, AFI_L2VPN, false);
609 }
610
611 DEFUN (show_ip_access_list,
612 show_ip_access_list_cmd,
613 "show ip access-list [json]",
614 SHOW_STR
615 IP_STR
616 "List IP access lists\n"
617 JSON_STR)
618 {
619 bool uj = use_json(argc, argv);
620 return filter_show(vty, NULL, AFI_IP, uj);
621 }
622
623 DEFUN (show_ip_access_list_name,
624 show_ip_access_list_name_cmd,
625 "show ip access-list ACCESSLIST4_NAME [json]",
626 SHOW_STR
627 IP_STR
628 "List IP access lists\n"
629 "IP access-list name\n"
630 JSON_STR)
631 {
632 bool uj = use_json(argc, argv);
633 int idx_acl = 3;
634 return filter_show(vty, argv[idx_acl]->arg, AFI_IP, uj);
635 }
636
637 DEFUN (show_ipv6_access_list,
638 show_ipv6_access_list_cmd,
639 "show ipv6 access-list [json]",
640 SHOW_STR
641 IPV6_STR
642 "List IPv6 access lists\n"
643 JSON_STR)
644 {
645 bool uj = use_json(argc, argv);
646 return filter_show(vty, NULL, AFI_IP6, uj);
647 }
648
649 DEFUN (show_ipv6_access_list_name,
650 show_ipv6_access_list_name_cmd,
651 "show ipv6 access-list ACCESSLIST6_NAME [json]",
652 SHOW_STR
653 IPV6_STR
654 "List IPv6 access lists\n"
655 "IPv6 access-list name\n"
656 JSON_STR)
657 {
658 bool uj = use_json(argc, argv);
659 int idx_word = 3;
660 return filter_show(vty, argv[idx_word]->arg, AFI_IP6, uj);
661 }
662
663 static void config_write_access_cisco(struct vty *vty, struct filter *mfilter,
664 json_object *json)
665 {
666 struct filter_cisco *filter;
667
668 filter = &mfilter->u.cfilter;
669
670 if (json) {
671 json_object_boolean_add(json, "extended", !!filter->extended);
672 json_object_string_addf(json, "sourceAddress", "%pI4",
673 &filter->addr);
674 json_object_string_addf(json, "sourceMask", "%pI4",
675 &filter->addr_mask);
676 json_object_string_addf(json, "destinationAddress", "%pI4",
677 &filter->mask);
678 json_object_string_addf(json, "destinationMask", "%pI4",
679 &filter->mask_mask);
680 } else {
681 vty_out(vty, " ip");
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);
686 else {
687 vty_out(vty, " %pI4", &filter->addr);
688 vty_out(vty, " %pI4", &filter->addr_mask);
689 }
690
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);
695 else {
696 vty_out(vty, " %pI4", &filter->mask);
697 vty_out(vty, " %pI4", &filter->mask_mask);
698 }
699 vty_out(vty, "\n");
700 }
701 }
702
703 static void config_write_access_zebra(struct vty *vty, struct filter *mfilter,
704 json_object *json)
705 {
706 struct filter_zebra *filter;
707 struct prefix *p;
708 char buf[BUFSIZ];
709
710 filter = &mfilter->u.zfilter;
711 p = &filter->prefix;
712
713 if (json) {
714 json_object_string_addf(json, "prefix", "%pFX", p);
715 json_object_boolean_add(json, "exact-match", !!filter->exact);
716 } else {
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");
725 else
726 vty_out(vty, " %s",
727 prefix_mac2str(&(p->u.prefix_eth), buf,
728 sizeof(buf)));
729 }
730
731 vty_out(vty, "\n");
732 }
733 }
734
735 static struct cmd_node access_mac_node = {
736 .name = "MAC access list",
737 .node = ACCESS_MAC_NODE,
738 .prompt = "",
739 };
740
741 static void access_list_reset_mac(void)
742 {
743 struct access_list *access;
744 struct access_list *next;
745 struct access_master *master;
746
747 master = access_master_get(AFI_L2VPN);
748 if (master == NULL)
749 return;
750
751 for (access = master->str.head; access; access = next) {
752 next = access->next;
753 access_list_delete(access);
754 }
755
756 assert(master->str.head == NULL);
757 assert(master->str.tail == NULL);
758 }
759
760 /* Install vty related command. */
761 static void access_list_init_mac(void)
762 {
763 install_node(&access_mac_node);
764
765 install_element(ENABLE_NODE, &show_mac_access_list_cmd);
766 install_element(ENABLE_NODE, &show_mac_access_list_name_cmd);
767 }
768
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",
773 .node = ACCESS_NODE,
774 .prompt = "",
775 .config_write = config_write_access,
776 };
777
778 static int config_write_access(struct vty *vty)
779 {
780 struct lyd_node *dnode;
781 int written = 0;
782
783 dnode = yang_dnode_get(running_config->dnode, "/frr-filter:lib");
784 if (dnode) {
785 nb_cli_show_dnode_cmds(vty, dnode, false);
786 written = 1;
787 }
788
789 return written;
790 }
791
792 static void access_list_reset_ipv4(void)
793 {
794 struct access_list *access;
795 struct access_list *next;
796 struct access_master *master;
797
798 master = access_master_get(AFI_IP);
799 if (master == NULL)
800 return;
801
802 for (access = master->str.head; access; access = next) {
803 next = access->next;
804 access_list_delete(access);
805 }
806
807 assert(master->str.head == NULL);
808 assert(master->str.tail == NULL);
809 }
810
811 /* Install vty related command. */
812 static void access_list_init_ipv4(void)
813 {
814 install_node(&access_node);
815
816 install_element(ENABLE_NODE, &show_ip_access_list_cmd);
817 install_element(ENABLE_NODE, &show_ip_access_list_name_cmd);
818 }
819
820 static void access_list_autocomplete_afi(afi_t afi, vector comps,
821 struct cmd_token *token)
822 {
823 struct access_list *access;
824 struct access_list *next;
825 struct access_master *master;
826
827 master = access_master_get(afi);
828 if (master == NULL)
829 return;
830
831 for (access = master->str.head; access; access = next) {
832 next = access->next;
833 vector_set(comps, XSTRDUP(MTYPE_COMPLETION, access->name));
834 }
835 }
836
837 static struct cmd_node access_ipv6_node = {
838 .name = "ipv6 access list",
839 .node = ACCESS_IPV6_NODE,
840 .prompt = "",
841 };
842
843 static void access_list_autocomplete(vector comps, struct cmd_token *token)
844 {
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);
848 }
849
850 static void access_list4_autocomplete(vector comps, struct cmd_token *token)
851 {
852 access_list_autocomplete_afi(AFI_IP, comps, token);
853 }
854
855 static void access_list6_autocomplete(vector comps, struct cmd_token *token)
856 {
857 access_list_autocomplete_afi(AFI_IP6, comps, token);
858 }
859
860 static void access_list_mac_autocomplete(vector comps, struct cmd_token *token)
861 {
862 access_list_autocomplete_afi(AFI_L2VPN, comps, token);
863 }
864
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}};
875
876 static void access_list_reset_ipv6(void)
877 {
878 struct access_list *access;
879 struct access_list *next;
880 struct access_master *master;
881
882 master = access_master_get(AFI_IP6);
883 if (master == NULL)
884 return;
885
886 for (access = master->str.head; access; access = next) {
887 next = access->next;
888 access_list_delete(access);
889 }
890
891 assert(master->str.head == NULL);
892 assert(master->str.tail == NULL);
893 }
894
895 static void access_list_init_ipv6(void)
896 {
897 install_node(&access_ipv6_node);
898
899 install_element(ENABLE_NODE, &show_ipv6_access_list_cmd);
900 install_element(ENABLE_NODE, &show_ipv6_access_list_name_cmd);
901 }
902
903 void access_list_init(void)
904 {
905 cmd_variable_handler_register(access_list_handlers);
906
907 access_list_init_ipv4();
908 access_list_init_ipv6();
909 access_list_init_mac();
910
911 filter_cli_init();
912 }
913
914 void access_list_reset(void)
915 {
916 access_list_reset_ipv4();
917 access_list_reset_ipv6();
918 access_list_reset_mac();
919 }