]> git.proxmox.com Git - mirror_frr.git/blame - lib/filter.c
Merge pull request #8153 from reubendowle/nhrp-multicast
[mirror_frr.git] / lib / filter.c
CommitLineData
718e3744 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 *
896014f4
DL
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
718e3744 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"
fbf5d033 29#include "log.h"
518f0eb1 30#include "routemap.h"
b85120bc 31#include "libfrr.h"
1d3c4b66 32#include "northbound_cli.h"
718e3744 33
bf8d3d6a
DL
34DEFINE_MTYPE_STATIC(LIB, ACCESS_LIST, "Access List");
35DEFINE_MTYPE_STATIC(LIB, ACCESS_LIST_STR, "Access List Str");
36DEFINE_MTYPE_STATIC(LIB, ACCESS_FILTER, "Access Filter");
d62a17ae 37
b34fd35d 38/* Static structure for mac access_list's master. */
d37ba549
MK
39static struct access_master access_master_mac = {
40 {NULL, NULL},
41 {NULL, NULL},
42 NULL,
43 NULL,
44};
45
718e3744 46/* Static structure for IPv4 access_list's master. */
d62a17ae 47static struct access_master access_master_ipv4 = {
48 {NULL, NULL},
49 {NULL, NULL},
50 NULL,
51 NULL,
718e3744 52};
53
718e3744 54/* Static structure for IPv6 access_list's master. */
d62a17ae 55static struct access_master access_master_ipv6 = {
56 {NULL, NULL},
57 {NULL, NULL},
58 NULL,
59 NULL,
718e3744 60};
6b0655a2 61
d62a17ae 62static struct access_master *access_master_get(afi_t afi)
718e3744 63{
d62a17ae 64 if (afi == AFI_IP)
65 return &access_master_ipv4;
66 else if (afi == AFI_IP6)
67 return &access_master_ipv6;
d37ba549
MK
68 else if (afi == AFI_L2VPN)
69 return &access_master_mac;
d62a17ae 70 return NULL;
718e3744 71}
72
73/* Allocate new filter structure. */
4cf24501 74struct filter *filter_new(void)
718e3744 75{
9f5dc319 76 return XCALLOC(MTYPE_ACCESS_FILTER, sizeof(struct filter));
718e3744 77}
78
d62a17ae 79static void filter_free(struct filter *filter)
718e3744 80{
d62a17ae 81 XFREE(MTYPE_ACCESS_FILTER, filter);
718e3744 82}
83
84/* Return string of filter_type. */
d62a17ae 85static const char *filter_type_str(struct filter *filter)
86{
87 switch (filter->type) {
88 case FILTER_PERMIT:
89 return "permit";
d62a17ae 90 case FILTER_DENY:
91 return "deny";
d62a17ae 92 case FILTER_DYNAMIC:
93 return "dynamic";
d62a17ae 94 default:
95 return "";
d62a17ae 96 }
718e3744 97}
98
99/* If filter match to the prefix then return 1. */
123214ef 100static int filter_match_cisco(struct filter *mfilter, const struct prefix *p)
718e3744 101{
d62a17ae 102 struct filter_cisco *filter;
103 struct in_addr mask;
d7c0a89a
QY
104 uint32_t check_addr;
105 uint32_t check_mask;
718e3744 106
d62a17ae 107 filter = &mfilter->u.cfilter;
108 check_addr = p->u.prefix4.s_addr & ~filter->addr_mask.s_addr;
718e3744 109
d62a17ae 110 if (filter->extended) {
111 masklen2ip(p->prefixlen, &mask);
112 check_mask = mask.s_addr & ~filter->mask_mask.s_addr;
718e3744 113
d62a17ae 114 if (memcmp(&check_addr, &filter->addr.s_addr, 4) == 0
115 && memcmp(&check_mask, &filter->mask.s_addr, 4) == 0)
116 return 1;
117 } else if (memcmp(&check_addr, &filter->addr.s_addr, 4) == 0)
118 return 1;
718e3744 119
d62a17ae 120 return 0;
718e3744 121}
122
123/* If filter match to the prefix then return 1. */
123214ef 124static int filter_match_zebra(struct filter *mfilter, const struct prefix *p)
718e3744 125{
d37ba549 126 struct filter_zebra *filter = NULL;
718e3744 127
d62a17ae 128 filter = &mfilter->u.zfilter;
718e3744 129
3b0f6068
DL
130 if (filter->prefix.family == p->family) {
131 if (filter->exact) {
132 if (filter->prefix.prefixlen == p->prefixlen)
d62a17ae 133 return prefix_match(&filter->prefix, p);
3b0f6068
DL
134 else
135 return 0;
d62a17ae 136 } else
3b0f6068
DL
137 return prefix_match(&filter->prefix, p);
138 } else
139 return 0;
718e3744 140}
6b0655a2 141
718e3744 142/* Allocate new access list structure. */
d62a17ae 143static struct access_list *access_list_new(void)
718e3744 144{
9f5dc319 145 return XCALLOC(MTYPE_ACCESS_LIST, sizeof(struct access_list));
718e3744 146}
147
148/* Free allocated access_list. */
d62a17ae 149static void access_list_free(struct access_list *access)
718e3744 150{
d62a17ae 151 XFREE(MTYPE_ACCESS_LIST, access);
718e3744 152}
153
154/* Delete access_list from access_master and free it. */
4cf24501 155void access_list_delete(struct access_list *access)
718e3744 156{
d62a17ae 157 struct filter *filter;
158 struct filter *next;
159 struct access_list_list *list;
160 struct access_master *master;
718e3744 161
d62a17ae 162 for (filter = access->head; filter; filter = next) {
163 next = filter->next;
164 filter_free(filter);
165 }
718e3744 166
d62a17ae 167 master = access->master;
718e3744 168
d62a17ae 169 if (access->type == ACCESS_TYPE_NUMBER)
170 list = &master->num;
171 else
172 list = &master->str;
718e3744 173
d62a17ae 174 if (access->next)
175 access->next->prev = access->prev;
176 else
177 list->tail = access->prev;
718e3744 178
d62a17ae 179 if (access->prev)
180 access->prev->next = access->next;
181 else
182 list->head = access->next;
718e3744 183
0a22ddfb 184 XFREE(MTYPE_ACCESS_LIST_STR, access->name);
718e3744 185
0a22ddfb 186 XFREE(MTYPE_TMP, access->remark);
718e3744 187
d62a17ae 188 access_list_free(access);
718e3744 189}
190
191/* Insert new access list to list of access_list. Each acceess_list
192 is sorted by the name. */
d62a17ae 193static struct access_list *access_list_insert(afi_t afi, const char *name)
194{
195 unsigned int i;
196 long number;
197 struct access_list *access;
198 struct access_list *point;
199 struct access_list_list *alist;
200 struct access_master *master;
201
202 master = access_master_get(afi);
203 if (master == NULL)
204 return NULL;
205
206 /* Allocate new access_list and copy given name. */
207 access = access_list_new();
208 access->name = XSTRDUP(MTYPE_ACCESS_LIST_STR, name);
209 access->master = master;
210
211 /* If name is made by all digit character. We treat it as
212 number. */
213 for (number = 0, i = 0; i < strlen(name); i++) {
fefa5e0f 214 if (isdigit((unsigned char)name[i]))
d62a17ae 215 number = (number * 10) + (name[i] - '0');
216 else
217 break;
218 }
219
220 /* In case of name is all digit character */
221 if (i == strlen(name)) {
222 access->type = ACCESS_TYPE_NUMBER;
223
224 /* Set access_list to number list. */
225 alist = &master->num;
226
227 for (point = alist->head; point; point = point->next)
228 if (atol(point->name) >= number)
229 break;
230 } else {
231 access->type = ACCESS_TYPE_STRING;
232
233 /* Set access_list to string list. */
234 alist = &master->str;
235
236 /* Set point to insertion point. */
237 for (point = alist->head; point; point = point->next)
238 if (strcmp(point->name, name) >= 0)
239 break;
240 }
241
242 /* In case of this is the first element of master. */
243 if (alist->head == NULL) {
244 alist->head = alist->tail = access;
245 return access;
246 }
247
248 /* In case of insertion is made at the tail of access_list. */
249 if (point == NULL) {
250 access->prev = alist->tail;
251 alist->tail->next = access;
252 alist->tail = access;
253 return access;
254 }
255
256 /* In case of insertion is made at the head of access_list. */
257 if (point == alist->head) {
258 access->next = alist->head;
259 alist->head->prev = access;
260 alist->head = access;
261 return access;
262 }
263
264 /* Insertion is made at middle of the access_list. */
265 access->next = point;
266 access->prev = point->prev;
267
268 if (point->prev)
269 point->prev->next = access;
270 point->prev = access;
271
272 return access;
718e3744 273}
274
275/* Lookup access_list from list of access_list by name. */
d62a17ae 276struct access_list *access_list_lookup(afi_t afi, const char *name)
718e3744 277{
d62a17ae 278 struct access_list *access;
279 struct access_master *master;
718e3744 280
d62a17ae 281 if (name == NULL)
282 return NULL;
718e3744 283
d62a17ae 284 master = access_master_get(afi);
285 if (master == NULL)
286 return NULL;
718e3744 287
d62a17ae 288 for (access = master->num.head; access; access = access->next)
289 if (strcmp(access->name, name) == 0)
290 return access;
718e3744 291
d62a17ae 292 for (access = master->str.head; access; access = access->next)
293 if (strcmp(access->name, name) == 0)
294 return access;
718e3744 295
d62a17ae 296 return NULL;
718e3744 297}
298
299/* Get access list from list of access_list. If there isn't matched
300 access_list create new one and return it. */
4cf24501 301struct access_list *access_list_get(afi_t afi, const char *name)
718e3744 302{
d62a17ae 303 struct access_list *access;
718e3744 304
d62a17ae 305 access = access_list_lookup(afi, name);
306 if (access == NULL)
307 access = access_list_insert(afi, name);
308 return access;
718e3744 309}
310
311/* Apply access list to object (which should be struct prefix *). */
123214ef
MS
312enum filter_type access_list_apply(struct access_list *access,
313 const void *object)
718e3744 314{
d62a17ae 315 struct filter *filter;
123214ef 316 const struct prefix *p = (const struct prefix *)object;
718e3744 317
d62a17ae 318 if (access == NULL)
319 return FILTER_DENY;
718e3744 320
d62a17ae 321 for (filter = access->head; filter; filter = filter->next) {
322 if (filter->cisco) {
323 if (filter_match_cisco(filter, p))
324 return filter->type;
325 } else {
0f6476cc 326 if (filter_match_zebra(filter, p))
d62a17ae 327 return filter->type;
328 }
718e3744 329 }
718e3744 330
d62a17ae 331 return FILTER_DENY;
718e3744 332}
333
334/* Add hook function. */
d62a17ae 335void access_list_add_hook(void (*func)(struct access_list *access))
718e3744 336{
d62a17ae 337 access_master_ipv4.add_hook = func;
338 access_master_ipv6.add_hook = func;
d37ba549 339 access_master_mac.add_hook = func;
718e3744 340}
341
342/* Delete hook function. */
d62a17ae 343void access_list_delete_hook(void (*func)(struct access_list *access))
718e3744 344{
d62a17ae 345 access_master_ipv4.delete_hook = func;
346 access_master_ipv6.delete_hook = func;
d37ba549 347 access_master_mac.delete_hook = func;
718e3744 348}
349
358189ad 350/* Calculate new sequential number. */
4cf24501 351int64_t filter_new_seq_get(struct access_list *access)
718e3744 352{
358189ad
DA
353 int64_t maxseq;
354 int64_t newseq;
355 struct filter *filter;
718e3744 356
5037cc3e 357 maxseq = 0;
718e3744 358
358189ad
DA
359 for (filter = access->head; filter; filter = filter->next) {
360 if (maxseq < filter->seq)
361 maxseq = filter->seq;
362 }
363
364 newseq = ((maxseq / 5) * 5) + 5;
365
366 return (newseq > UINT_MAX) ? UINT_MAX : newseq;
367}
368
369/* Return access list entry which has same seq number. */
370static struct filter *filter_seq_check(struct access_list *access,
371 int64_t seq)
372{
373 struct filter *filter;
374
375 for (filter = access->head; filter; filter = filter->next)
376 if (filter->seq == seq)
377 return filter;
378 return NULL;
718e3744 379}
380
718e3744 381/* Delete filter from specified access_list. If there is hook
382 function execute it. */
4cf24501
RZ
383void access_list_filter_delete(struct access_list *access,
384 struct filter *filter)
718e3744 385{
d62a17ae 386 struct access_master *master;
718e3744 387
d62a17ae 388 master = access->master;
718e3744 389
d62a17ae 390 if (filter->next)
391 filter->next->prev = filter->prev;
392 else
393 access->tail = filter->prev;
718e3744 394
d62a17ae 395 if (filter->prev)
396 filter->prev->next = filter->next;
397 else
398 access->head = filter->next;
718e3744 399
d62a17ae 400 filter_free(filter);
718e3744 401
d62a17ae 402 route_map_notify_dependencies(access->name, RMAP_EVENT_FILTER_DELETED);
403 /* Run hook function. */
404 if (master->delete_hook)
405 (*master->delete_hook)(access);
718e3744 406}
6b0655a2 407
358189ad 408/* Add new filter to the end of specified access_list. */
4cf24501
RZ
409void access_list_filter_add(struct access_list *access,
410 struct filter *filter)
358189ad
DA
411{
412 struct filter *replace;
413 struct filter *point;
414
415 /* Automatic asignment of seq no. */
416 if (filter->seq == -1)
417 filter->seq = filter_new_seq_get(access);
418
419 if (access->tail && filter->seq > access->tail->seq)
420 point = NULL;
421 else {
422 /* Is there any same seq access list filter? */
423 replace = filter_seq_check(access, filter->seq);
424 if (replace)
425 access_list_filter_delete(access, replace);
426
427 /* Check insert point. */
428 for (point = access->head; point; point = point->next)
429 if (point->seq >= filter->seq)
430 break;
431 }
432
433 /* In case of this is the first element of the list. */
434 filter->next = point;
435
436 if (point) {
437 if (point->prev)
438 point->prev->next = filter;
439 else
440 access->head = filter;
441
442 filter->prev = point->prev;
443 point->prev = filter;
444 } else {
445 if (access->tail)
446 access->tail->next = filter;
447 else
448 access->head = filter;
449
450 filter->prev = access->tail;
451 access->tail = filter;
452 }
453
454 /* Run hook function. */
455 if (access->master->add_hook)
456 (*access->master->add_hook)(access);
457 route_map_notify_dependencies(access->name, RMAP_EVENT_FILTER_ADDED);
458}
459
718e3744 460/*
461 deny Specify packets to reject
462 permit Specify packets to forward
463 dynamic ?
464*/
465
466/*
467 Hostname or A.B.C.D Address to match
468 any Any source host
469 host A single host address
470*/
471
eb51bb9b
DL
472static void config_write_access_zebra(struct vty *, struct filter *);
473static void config_write_access_cisco(struct vty *, struct filter *);
718e3744 474
475/* show access-list command. */
d62a17ae 476static int filter_show(struct vty *vty, const char *name, afi_t afi)
477{
478 struct access_list *access;
479 struct access_master *master;
480 struct filter *mfilter;
481 struct filter_cisco *filter;
482 int write = 0;
483
484 master = access_master_get(afi);
485 if (master == NULL)
486 return 0;
487
488 /* Print the name of the protocol */
489 vty_out(vty, "%s:\n", frr_protoname);
490
491 for (access = master->num.head; access; access = access->next) {
492 if (name && strcmp(access->name, name) != 0)
493 continue;
494
495 write = 1;
496
497 for (mfilter = access->head; mfilter; mfilter = mfilter->next) {
498 filter = &mfilter->u.cfilter;
499
500 if (write) {
d37ba549 501 vty_out(vty, "%s %s access list %s\n",
d62a17ae 502 mfilter->cisco ? (filter->extended
503 ? "Extended"
504 : "Standard")
505 : "Zebra",
d37ba549 506 (afi == AFI_IP)
3b0f6068
DL
507 ? ("IP")
508 : ((afi == AFI_IP6) ? ("IPv6 ")
509 : ("MAC ")),
d62a17ae 510 access->name);
511 write = 0;
512 }
513
358189ad
DA
514 vty_out(vty, " seq %" PRId64, mfilter->seq);
515 vty_out(vty, " %s%s", filter_type_str(mfilter),
d62a17ae 516 mfilter->type == FILTER_DENY ? " " : "");
517
518 if (!mfilter->cisco)
519 config_write_access_zebra(vty, mfilter);
520 else if (filter->extended)
521 config_write_access_cisco(vty, mfilter);
522 else {
523 if (filter->addr_mask.s_addr == 0xffffffff)
524 vty_out(vty, " any\n");
525 else {
af3b34f6 526 vty_out(vty, " %pI4", &filter->addr);
975a328e
DA
527 if (filter->addr_mask.s_addr
528 != INADDR_ANY)
d62a17ae 529 vty_out(vty,
af3b34f6
DA
530 ", wildcard bits %pI4",
531 &filter->addr_mask);
d62a17ae 532 vty_out(vty, "\n");
533 }
534 }
718e3744 535 }
718e3744 536 }
d62a17ae 537
538 for (access = master->str.head; access; access = access->next) {
539 if (name && strcmp(access->name, name) != 0)
540 continue;
541
542 write = 1;
543
544 for (mfilter = access->head; mfilter; mfilter = mfilter->next) {
545 filter = &mfilter->u.cfilter;
546
547 if (write) {
d37ba549 548 vty_out(vty, "%s %s access list %s\n",
d62a17ae 549 mfilter->cisco ? (filter->extended
550 ? "Extended"
551 : "Standard")
552 : "Zebra",
d37ba549 553 (afi == AFI_IP)
3b0f6068
DL
554 ? ("IP")
555 : ((afi == AFI_IP6) ? ("IPv6 ")
556 : ("MAC ")),
d62a17ae 557 access->name);
558 write = 0;
559 }
560
358189ad
DA
561 vty_out(vty, " seq %" PRId64, mfilter->seq);
562 vty_out(vty, " %s%s", filter_type_str(mfilter),
d62a17ae 563 mfilter->type == FILTER_DENY ? " " : "");
564
565 if (!mfilter->cisco)
566 config_write_access_zebra(vty, mfilter);
567 else if (filter->extended)
568 config_write_access_cisco(vty, mfilter);
569 else {
570 if (filter->addr_mask.s_addr == 0xffffffff)
571 vty_out(vty, " any\n");
572 else {
af3b34f6 573 vty_out(vty, " %pI4", &filter->addr);
975a328e
DA
574 if (filter->addr_mask.s_addr
575 != INADDR_ANY)
d62a17ae 576 vty_out(vty,
af3b34f6
DA
577 ", wildcard bits %pI4",
578 &filter->addr_mask);
d62a17ae 579 vty_out(vty, "\n");
580 }
581 }
718e3744 582 }
718e3744 583 }
d62a17ae 584 return CMD_SUCCESS;
718e3744 585}
586
d37ba549
MK
587/* show MAC access list - this only has MAC filters for now*/
588DEFUN (show_mac_access_list,
589 show_mac_access_list_cmd,
590 "show mac access-list",
591 SHOW_STR
592 "mac access lists\n"
593 "List mac access lists\n")
594{
595 return filter_show(vty, NULL, AFI_L2VPN);
596}
597
598DEFUN (show_mac_access_list_name,
599 show_mac_access_list_name_cmd,
600 "show mac access-list WORD",
601 SHOW_STR
1667fc40 602 "mac access lists\n"
d37ba549 603 "List mac access lists\n"
1667fc40 604 "mac address\n")
d37ba549
MK
605{
606 return filter_show(vty, argv[3]->arg, AFI_L2VPN);
607}
608
718e3744 609DEFUN (show_ip_access_list,
610 show_ip_access_list_cmd,
611 "show ip access-list",
612 SHOW_STR
613 IP_STR
614 "List IP access lists\n")
615{
d62a17ae 616 return filter_show(vty, NULL, AFI_IP);
718e3744 617}
618
619DEFUN (show_ip_access_list_name,
620 show_ip_access_list_name_cmd,
6147e2c6 621 "show ip access-list <(1-99)|(100-199)|(1300-1999)|(2000-2699)|WORD>",
718e3744 622 SHOW_STR
623 IP_STR
624 "List IP access lists\n"
625 "IP standard access list\n"
626 "IP extended access list\n"
627 "IP standard access list (expanded range)\n"
628 "IP extended access list (expanded range)\n"
629 "IP zebra access-list\n")
630{
d62a17ae 631 int idx_acl = 3;
632 return filter_show(vty, argv[idx_acl]->arg, AFI_IP);
718e3744 633}
634
718e3744 635DEFUN (show_ipv6_access_list,
636 show_ipv6_access_list_cmd,
637 "show ipv6 access-list",
638 SHOW_STR
639 IPV6_STR
640 "List IPv6 access lists\n")
641{
d62a17ae 642 return filter_show(vty, NULL, AFI_IP6);
718e3744 643}
644
645DEFUN (show_ipv6_access_list_name,
646 show_ipv6_access_list_name_cmd,
647 "show ipv6 access-list WORD",
648 SHOW_STR
649 IPV6_STR
650 "List IPv6 access lists\n"
651 "IPv6 zebra access-list\n")
652{
d62a17ae 653 int idx_word = 3;
654 return filter_show(vty, argv[idx_word]->arg, AFI_IP6);
655}
656
eb51bb9b 657static void config_write_access_cisco(struct vty *vty, struct filter *mfilter)
d62a17ae 658{
659 struct filter_cisco *filter;
660
661 filter = &mfilter->u.cfilter;
662
663 if (filter->extended) {
664 vty_out(vty, " ip");
665 if (filter->addr_mask.s_addr == 0xffffffff)
666 vty_out(vty, " any");
975a328e 667 else if (filter->addr_mask.s_addr == INADDR_ANY)
af3b34f6 668 vty_out(vty, " host %pI4", &filter->addr);
d62a17ae 669 else {
af3b34f6
DA
670 vty_out(vty, " %pI4", &filter->addr);
671 vty_out(vty, " %pI4", &filter->addr_mask);
d62a17ae 672 }
673
674 if (filter->mask_mask.s_addr == 0xffffffff)
675 vty_out(vty, " any");
975a328e 676 else if (filter->mask_mask.s_addr == INADDR_ANY)
af3b34f6 677 vty_out(vty, " host %pI4", &filter->mask);
d62a17ae 678 else {
af3b34f6
DA
679 vty_out(vty, " %pI4", &filter->mask);
680 vty_out(vty, " %pI4", &filter->mask_mask);
d62a17ae 681 }
682 vty_out(vty, "\n");
683 } else {
684 if (filter->addr_mask.s_addr == 0xffffffff)
685 vty_out(vty, " any\n");
686 else {
af3b34f6 687 vty_out(vty, " %pI4", &filter->addr);
975a328e 688 if (filter->addr_mask.s_addr != INADDR_ANY)
af3b34f6 689 vty_out(vty, " %pI4", &filter->addr_mask);
d62a17ae 690 vty_out(vty, "\n");
691 }
718e3744 692 }
718e3744 693}
694
eb51bb9b 695static void config_write_access_zebra(struct vty *vty, struct filter *mfilter)
718e3744 696{
d62a17ae 697 struct filter_zebra *filter;
698 struct prefix *p;
699 char buf[BUFSIZ];
718e3744 700
d62a17ae 701 filter = &mfilter->u.zfilter;
702 p = &filter->prefix;
718e3744 703
d62a17ae 704 if (p->prefixlen == 0 && !filter->exact)
705 vty_out(vty, " any");
d37ba549 706 else if (p->family == AF_INET6 || p->family == AF_INET)
d62a17ae 707 vty_out(vty, " %s/%d%s",
708 inet_ntop(p->family, &p->u.prefix, buf, BUFSIZ),
709 p->prefixlen, filter->exact ? " exact-match" : "");
69b61704 710 else if (p->family == AF_ETHERNET) {
3b0f6068 711 if (p->prefixlen == 0)
69b61704
MK
712 vty_out(vty, " any");
713 else
714 vty_out(vty, " %s", prefix_mac2str(&(p->u.prefix_eth),
715 buf, sizeof(buf)));
716 }
718e3744 717
d62a17ae 718 vty_out(vty, "\n");
718e3744 719}
720
d37ba549 721static struct cmd_node access_mac_node = {
f4b8291f 722 .name = "MAC access list",
62b346ee
DL
723 .node = ACCESS_MAC_NODE,
724 .prompt = "",
62b346ee 725};
d37ba549 726
d37ba549
MK
727static void access_list_reset_mac(void)
728{
729 struct access_list *access;
730 struct access_list *next;
731 struct access_master *master;
732
733 master = access_master_get(AFI_L2VPN);
734 if (master == NULL)
735 return;
736
737 for (access = master->num.head; access; access = next) {
738 next = access->next;
739 access_list_delete(access);
740 }
741 for (access = master->str.head; access; access = next) {
742 next = access->next;
743 access_list_delete(access);
744 }
745
746 assert(master->num.head == NULL);
747 assert(master->num.tail == NULL);
748
749 assert(master->str.head == NULL);
750 assert(master->str.tail == NULL);
751}
752
753/* Install vty related command. */
754static void access_list_init_mac(void)
755{
612c2c15 756 install_node(&access_mac_node);
d37ba549
MK
757
758 install_element(ENABLE_NODE, &show_mac_access_list_cmd);
759 install_element(ENABLE_NODE, &show_mac_access_list_name_cmd);
d37ba549
MK
760}
761
718e3744 762/* Access-list node. */
1d3c4b66 763static int config_write_access(struct vty *vty);
62b346ee 764static struct cmd_node access_node = {
f4b8291f 765 .name = "ipv4 access list",
62b346ee
DL
766 .node = ACCESS_NODE,
767 .prompt = "",
1d3c4b66 768 .config_write = config_write_access,
62b346ee 769};
718e3744 770
1d3c4b66 771static int config_write_access(struct vty *vty)
718e3744 772{
1d3c4b66
RZ
773 struct lyd_node *dnode;
774 int written = 0;
775
776 dnode = yang_dnode_get(running_config->dnode, "/frr-filter:lib");
777 if (dnode) {
778 nb_cli_show_dnode_cmds(vty, dnode, false);
779 written = 1;
780 }
781
782 return written;
718e3744 783}
784
d62a17ae 785static void access_list_reset_ipv4(void)
718e3744 786{
d62a17ae 787 struct access_list *access;
788 struct access_list *next;
789 struct access_master *master;
718e3744 790
d62a17ae 791 master = access_master_get(AFI_IP);
792 if (master == NULL)
793 return;
718e3744 794
d62a17ae 795 for (access = master->num.head; access; access = next) {
796 next = access->next;
797 access_list_delete(access);
798 }
799 for (access = master->str.head; access; access = next) {
800 next = access->next;
801 access_list_delete(access);
802 }
718e3744 803
d62a17ae 804 assert(master->num.head == NULL);
805 assert(master->num.tail == NULL);
718e3744 806
d62a17ae 807 assert(master->str.head == NULL);
808 assert(master->str.tail == NULL);
718e3744 809}
810
811/* Install vty related command. */
d62a17ae 812static void access_list_init_ipv4(void)
813{
612c2c15 814 install_node(&access_node);
d62a17ae 815
816 install_element(ENABLE_NODE, &show_ip_access_list_cmd);
817 install_element(ENABLE_NODE, &show_ip_access_list_name_cmd);
d62a17ae 818}
819
62b346ee 820static struct cmd_node access_ipv6_node = {
f4b8291f 821 .name = "ipv6 access list",
62b346ee
DL
822 .node = ACCESS_IPV6_NODE,
823 .prompt = "",
62b346ee 824};
d62a17ae 825
d62a17ae 826static void access_list_reset_ipv6(void)
827{
828 struct access_list *access;
829 struct access_list *next;
830 struct access_master *master;
831
832 master = access_master_get(AFI_IP6);
833 if (master == NULL)
834 return;
835
836 for (access = master->num.head; access; access = next) {
837 next = access->next;
838 access_list_delete(access);
839 }
840 for (access = master->str.head; access; access = next) {
841 next = access->next;
842 access_list_delete(access);
843 }
718e3744 844
d62a17ae 845 assert(master->num.head == NULL);
846 assert(master->num.tail == NULL);
718e3744 847
d62a17ae 848 assert(master->str.head == NULL);
849 assert(master->str.tail == NULL);
718e3744 850}
851
d62a17ae 852static void access_list_init_ipv6(void)
718e3744 853{
612c2c15 854 install_node(&access_ipv6_node);
718e3744 855
d62a17ae 856 install_element(ENABLE_NODE, &show_ipv6_access_list_cmd);
857 install_element(ENABLE_NODE, &show_ipv6_access_list_name_cmd);
718e3744 858}
718e3744 859
4d762f26 860void access_list_init(void)
718e3744 861{
d62a17ae 862 access_list_init_ipv4();
863 access_list_init_ipv6();
d37ba549 864 access_list_init_mac();
b62578bd
RZ
865
866 filter_cli_init();
718e3744 867}
868
4d762f26 869void access_list_reset(void)
718e3744 870{
d62a17ae 871 access_list_reset_ipv4();
872 access_list_reset_ipv6();
d37ba549 873 access_list_reset_mac();
718e3744 874}