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