Line data Source code
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 670 : DEFINE_MTYPE_STATIC(LIB, ACCESS_LIST, "Access List");
36 670 : DEFINE_MTYPE_STATIC(LIB, ACCESS_LIST_STR, "Access List Str");
37 670 : 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 18 : static struct access_master *access_master_get(afi_t afi)
61 : {
62 18 : 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 3 : struct filter *filter_new(void)
73 : {
74 3 : return XCALLOC(MTYPE_ACCESS_FILTER, sizeof(struct filter));
75 : }
76 :
77 3 : static void filter_free(struct filter *filter)
78 : {
79 3 : XFREE(MTYPE_ACCESS_FILTER, filter);
80 : }
81 :
82 : /* Return string of filter_type. */
83 0 : static const char *filter_type_str(struct filter *filter)
84 : {
85 0 : switch (filter->type) {
86 : case FILTER_PERMIT:
87 : return "permit";
88 0 : case FILTER_DENY:
89 0 : return "deny";
90 0 : case FILTER_DYNAMIC:
91 0 : return "dynamic";
92 0 : default:
93 0 : return "";
94 : }
95 : }
96 :
97 : /* If filter match to the prefix then return 1. */
98 0 : static int filter_match_cisco(struct filter *mfilter, const struct prefix *p)
99 : {
100 0 : struct filter_cisco *filter;
101 0 : struct in_addr mask;
102 0 : uint32_t check_addr;
103 0 : uint32_t check_mask;
104 :
105 0 : filter = &mfilter->u.cfilter;
106 0 : check_addr = p->u.prefix4.s_addr & ~filter->addr_mask.s_addr;
107 :
108 0 : if (filter->extended) {
109 0 : masklen2ip(p->prefixlen, &mask);
110 0 : check_mask = mask.s_addr & ~filter->mask_mask.s_addr;
111 :
112 0 : if (memcmp(&check_addr, &filter->addr.s_addr, IPV4_MAX_BYTELEN)
113 : == 0
114 0 : && memcmp(&check_mask, &filter->mask.s_addr,
115 : IPV4_MAX_BYTELEN)
116 : == 0)
117 : return 1;
118 0 : } 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 21 : static int filter_match_zebra(struct filter *mfilter, const struct prefix *p)
127 : {
128 21 : struct filter_zebra *filter = NULL;
129 :
130 21 : filter = &mfilter->u.zfilter;
131 :
132 21 : if (filter->prefix.family == p->family) {
133 21 : if (filter->exact) {
134 0 : if (filter->prefix.prefixlen == p->prefixlen)
135 0 : return prefix_match(&filter->prefix, p);
136 : else
137 : return 0;
138 : } else
139 21 : return prefix_match(&filter->prefix, p);
140 : } else
141 : return 0;
142 : }
143 :
144 : /* Allocate new access list structure. */
145 3 : static struct access_list *access_list_new(void)
146 : {
147 3 : return XCALLOC(MTYPE_ACCESS_LIST, sizeof(struct access_list));
148 : }
149 :
150 : /* Free allocated access_list. */
151 3 : static void access_list_free(struct access_list *access)
152 : {
153 6 : XFREE(MTYPE_ACCESS_LIST, access);
154 : }
155 :
156 : /* Delete access_list from access_master and free it. */
157 3 : void access_list_delete(struct access_list *access)
158 : {
159 3 : struct filter *filter;
160 3 : struct filter *next;
161 3 : struct access_list_list *list;
162 3 : struct access_master *master;
163 :
164 6 : for (filter = access->head; filter; filter = next) {
165 3 : next = filter->next;
166 3 : filter_free(filter);
167 : }
168 :
169 3 : master = access->master;
170 :
171 3 : list = &master->str;
172 :
173 3 : if (access->next)
174 2 : access->next->prev = access->prev;
175 : else
176 1 : list->tail = access->prev;
177 :
178 3 : if (access->prev)
179 0 : access->prev->next = access->next;
180 : else
181 3 : list->head = access->next;
182 :
183 3 : route_map_notify_dependencies(access->name, RMAP_EVENT_FILTER_DELETED);
184 :
185 3 : if (master->delete_hook)
186 0 : master->delete_hook(access);
187 :
188 3 : XFREE(MTYPE_ACCESS_LIST_STR, access->name);
189 :
190 3 : XFREE(MTYPE_TMP, access->remark);
191 :
192 3 : access_list_free(access);
193 3 : }
194 :
195 : /* Insert new access list to list of access_list. Each access_list
196 : is sorted by the name. */
197 3 : static struct access_list *access_list_insert(afi_t afi, const char *name)
198 : {
199 3 : struct access_list *access;
200 3 : struct access_list *point;
201 3 : struct access_list_list *alist;
202 3 : struct access_master *master;
203 :
204 3 : master = access_master_get(afi);
205 : if (master == NULL)
206 : return NULL;
207 :
208 : /* Allocate new access_list and copy given name. */
209 3 : access = access_list_new();
210 3 : access->name = XSTRDUP(MTYPE_ACCESS_LIST_STR, name);
211 3 : access->master = master;
212 :
213 : /* Set access_list to string list. */
214 3 : alist = &master->str;
215 :
216 : /* Set point to insertion point. */
217 6 : for (point = alist->head; point; point = point->next)
218 3 : if (strcmp(point->name, name) >= 0)
219 : break;
220 :
221 : /* In case of this is the first element of master. */
222 3 : if (alist->head == NULL) {
223 1 : alist->head = alist->tail = access;
224 1 : return access;
225 : }
226 :
227 : /* In case of insertion is made at the tail of access_list. */
228 2 : if (point == NULL) {
229 2 : access->prev = alist->tail;
230 2 : alist->tail->next = access;
231 2 : alist->tail = access;
232 2 : return access;
233 : }
234 :
235 : /* In case of insertion is made at the head of access_list. */
236 0 : if (point == alist->head) {
237 0 : access->next = alist->head;
238 0 : alist->head->prev = access;
239 0 : alist->head = access;
240 0 : return access;
241 : }
242 :
243 : /* Insertion is made at middle of the access_list. */
244 0 : access->next = point;
245 0 : access->prev = point->prev;
246 :
247 0 : if (point->prev)
248 0 : point->prev->next = access;
249 0 : point->prev = access;
250 :
251 0 : return access;
252 : }
253 :
254 : /* Lookup access_list from list of access_list by name. */
255 15 : struct access_list *access_list_lookup(afi_t afi, const char *name)
256 : {
257 15 : struct access_list *access;
258 15 : struct access_master *master;
259 :
260 15 : if (name == NULL)
261 : return NULL;
262 :
263 15 : master = access_master_get(afi);
264 : if (master == NULL)
265 : return NULL;
266 :
267 28 : for (access = master->str.head; access; access = access->next)
268 25 : if (strcmp(access->name, name) == 0)
269 12 : 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 3 : struct access_list *access_list_get(afi_t afi, const char *name)
277 : {
278 3 : struct access_list *access;
279 :
280 3 : access = access_list_lookup(afi, name);
281 3 : if (access == NULL)
282 3 : access = access_list_insert(afi, name);
283 3 : return access;
284 : }
285 :
286 : /* Apply access list to object (which should be struct prefix *). */
287 21 : enum filter_type access_list_apply(struct access_list *access,
288 : const void *object)
289 : {
290 21 : struct filter *filter;
291 21 : const struct prefix *p = (const struct prefix *)object;
292 :
293 21 : if (access == NULL)
294 : return FILTER_DENY;
295 :
296 39 : for (filter = access->head; filter; filter = filter->next) {
297 21 : if (filter->cisco) {
298 0 : if (filter_match_cisco(filter, p))
299 0 : return filter->type;
300 : } else {
301 21 : if (filter_match_zebra(filter, p))
302 3 : return filter->type;
303 : }
304 : }
305 :
306 : return FILTER_DENY;
307 : }
308 :
309 : /* Add hook function. */
310 122 : void access_list_add_hook(void (*func)(struct access_list *access))
311 : {
312 122 : access_master_ipv4.add_hook = func;
313 122 : access_master_ipv6.add_hook = func;
314 122 : access_master_mac.add_hook = func;
315 122 : }
316 :
317 : /* Delete hook function. */
318 122 : void access_list_delete_hook(void (*func)(struct access_list *access))
319 : {
320 122 : access_master_ipv4.delete_hook = func;
321 122 : access_master_ipv6.delete_hook = func;
322 122 : access_master_mac.delete_hook = func;
323 122 : }
324 :
325 : /* Calculate new sequential number. */
326 0 : int64_t filter_new_seq_get(struct access_list *access)
327 : {
328 0 : int64_t maxseq;
329 0 : int64_t newseq;
330 0 : struct filter *filter;
331 :
332 0 : maxseq = 0;
333 :
334 0 : for (filter = access->head; filter; filter = filter->next) {
335 0 : if (maxseq < filter->seq)
336 : maxseq = filter->seq;
337 : }
338 :
339 0 : newseq = ((maxseq / 5) * 5) + 5;
340 :
341 0 : return (newseq > UINT_MAX) ? UINT_MAX : newseq;
342 : }
343 :
344 : /* Return access list entry which has same seq number. */
345 3 : static struct filter *filter_seq_check(struct access_list *access,
346 : int64_t seq)
347 : {
348 3 : struct filter *filter;
349 :
350 3 : for (filter = access->head; filter; filter = filter->next)
351 0 : 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 0 : void access_list_filter_delete(struct access_list *access,
359 : struct filter *filter)
360 : {
361 0 : struct access_master *master;
362 :
363 0 : master = access->master;
364 :
365 0 : if (filter->next)
366 0 : filter->next->prev = filter->prev;
367 : else
368 0 : access->tail = filter->prev;
369 :
370 0 : if (filter->prev)
371 0 : filter->prev->next = filter->next;
372 : else
373 0 : access->head = filter->next;
374 :
375 0 : filter_free(filter);
376 :
377 0 : route_map_notify_dependencies(access->name, RMAP_EVENT_FILTER_DELETED);
378 : /* Run hook function. */
379 0 : if (master->delete_hook)
380 0 : (*master->delete_hook)(access);
381 0 : }
382 :
383 : /* Add new filter to the end of specified access_list. */
384 3 : void access_list_filter_add(struct access_list *access,
385 : struct filter *filter)
386 : {
387 3 : struct filter *replace;
388 3 : struct filter *point;
389 :
390 : /* Automatic assignment of seq no. */
391 3 : if (filter->seq == -1)
392 0 : filter->seq = filter_new_seq_get(access);
393 :
394 3 : if (access->tail && filter->seq > access->tail->seq)
395 : point = NULL;
396 : else {
397 : /* Is there any same seq access list filter? */
398 3 : replace = filter_seq_check(access, filter->seq);
399 3 : if (replace)
400 0 : access_list_filter_delete(access, replace);
401 :
402 : /* Check insert point. */
403 3 : for (point = access->head; point; point = point->next)
404 0 : if (point->seq >= filter->seq)
405 : break;
406 : }
407 :
408 : /* In case of this is the first element of the list. */
409 3 : filter->next = point;
410 :
411 3 : if (point) {
412 0 : if (point->prev)
413 0 : point->prev->next = filter;
414 : else
415 0 : access->head = filter;
416 :
417 0 : filter->prev = point->prev;
418 0 : point->prev = filter;
419 : } else {
420 3 : if (access->tail)
421 0 : access->tail->next = filter;
422 : else
423 3 : access->head = filter;
424 :
425 3 : filter->prev = access->tail;
426 3 : access->tail = filter;
427 : }
428 :
429 : /* Run hook function. */
430 3 : if (access->master->add_hook)
431 3 : (*access->master->add_hook)(access);
432 3 : route_map_notify_dependencies(access->name, RMAP_EVENT_FILTER_ADDED);
433 3 : }
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 0 : static const char *filter_type2str(struct filter *filter)
453 : {
454 0 : if (filter->cisco) {
455 0 : if (filter->u.cfilter.extended)
456 : return "Extended";
457 : else
458 0 : return "Standard";
459 : } else
460 : return "Zebra";
461 : }
462 :
463 : /* show access-list command. */
464 0 : static int filter_show(struct vty *vty, const char *name, afi_t afi,
465 : bool use_json)
466 : {
467 0 : struct access_list *access;
468 0 : struct access_master *master;
469 0 : struct filter *mfilter;
470 0 : struct filter_cisco *filter;
471 0 : bool first;
472 0 : json_object *json = NULL;
473 0 : json_object *json_proto = NULL;
474 :
475 0 : master = access_master_get(afi);
476 0 : if (master == NULL) {
477 0 : if (use_json)
478 0 : vty_out(vty, "{}\n");
479 0 : return 0;
480 : }
481 :
482 0 : if (use_json)
483 0 : json = json_object_new_object();
484 :
485 : /* Print the name of the protocol */
486 0 : if (json) {
487 0 : json_proto = json_object_new_object();
488 0 : json_object_object_add(json, frr_protoname, json_proto);
489 : } else
490 0 : vty_out(vty, "%s:\n", frr_protoname);
491 :
492 0 : for (access = master->str.head; access; access = access->next) {
493 0 : json_object *json_acl = NULL;
494 0 : json_object *json_rules = NULL;
495 :
496 0 : if (name && strcmp(access->name, name) != 0)
497 0 : continue;
498 :
499 0 : first = true;
500 :
501 0 : for (mfilter = access->head; mfilter; mfilter = mfilter->next) {
502 0 : json_object *json_rule = NULL;
503 :
504 0 : filter = &mfilter->u.cfilter;
505 :
506 0 : if (first) {
507 0 : const char *type = filter_type2str(mfilter);
508 :
509 0 : if (json) {
510 0 : json_acl = json_object_new_object();
511 0 : json_object_object_add(json_proto,
512 0 : access->name,
513 : json_acl);
514 :
515 0 : json_object_string_add(json_acl, "type",
516 : type);
517 0 : json_object_string_add(json_acl,
518 : "addressFamily",
519 : afi2str(afi));
520 0 : json_rules = json_object_new_array();
521 0 : json_object_object_add(
522 : json_acl, "rules", json_rules);
523 : } else {
524 0 : vty_out(vty, "%s %s access list %s\n",
525 : type,
526 : (afi == AFI_IP)
527 : ? ("IP")
528 : : ((afi == AFI_IP6)
529 : ? ("IPv6 ")
530 0 : : ("MAC ")),
531 : access->name);
532 : }
533 :
534 : first = false;
535 : }
536 :
537 0 : if (json) {
538 0 : json_rule = json_object_new_object();
539 0 : json_object_array_add(json_rules, json_rule);
540 :
541 0 : json_object_int_add(json_rule, "sequenceNumber",
542 : mfilter->seq);
543 0 : json_object_string_add(
544 : json_rule, "filterType",
545 : filter_type_str(mfilter));
546 : } else {
547 0 : vty_out(vty, " seq %" PRId64, mfilter->seq);
548 0 : vty_out(vty, " %s%s", filter_type_str(mfilter),
549 0 : mfilter->type == FILTER_DENY ? " "
550 : : "");
551 : }
552 :
553 0 : if (!mfilter->cisco)
554 0 : config_write_access_zebra(vty, mfilter,
555 : json_rule);
556 0 : else if (filter->extended)
557 0 : config_write_access_cisco(vty, mfilter,
558 : json_rule);
559 : else {
560 0 : if (json) {
561 0 : json_object_string_addf(
562 : json_rule, "address", "%pI4",
563 : &filter->addr);
564 0 : json_object_string_addf(
565 : json_rule, "mask", "%pI4",
566 : &filter->addr_mask);
567 : } else {
568 0 : if (filter->addr_mask.s_addr
569 : == 0xffffffff)
570 0 : vty_out(vty, " any\n");
571 : else {
572 0 : vty_out(vty, " %pI4",
573 : &filter->addr);
574 0 : if (filter->addr_mask.s_addr
575 : != INADDR_ANY)
576 0 : vty_out(vty,
577 : ", wildcard bits %pI4",
578 : &filter->addr_mask);
579 0 : vty_out(vty, "\n");
580 : }
581 : }
582 : }
583 : }
584 : }
585 :
586 0 : return vty_json(vty, json);
587 : }
588 :
589 : /* show MAC access list - this only has MAC filters for now*/
590 0 : 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 0 : return filter_show(vty, NULL, AFI_L2VPN, false);
598 : }
599 :
600 0 : 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 0 : return filter_show(vty, argv[3]->arg, AFI_L2VPN, false);
609 : }
610 :
611 0 : 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 0 : bool uj = use_json(argc, argv);
620 0 : return filter_show(vty, NULL, AFI_IP, uj);
621 : }
622 :
623 0 : 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 0 : bool uj = use_json(argc, argv);
633 0 : int idx_acl = 3;
634 0 : return filter_show(vty, argv[idx_acl]->arg, AFI_IP, uj);
635 : }
636 :
637 0 : 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 0 : bool uj = use_json(argc, argv);
646 0 : return filter_show(vty, NULL, AFI_IP6, uj);
647 : }
648 :
649 0 : 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 0 : bool uj = use_json(argc, argv);
659 0 : int idx_word = 3;
660 0 : return filter_show(vty, argv[idx_word]->arg, AFI_IP6, uj);
661 : }
662 :
663 0 : static void config_write_access_cisco(struct vty *vty, struct filter *mfilter,
664 : json_object *json)
665 : {
666 0 : struct filter_cisco *filter;
667 :
668 0 : filter = &mfilter->u.cfilter;
669 :
670 0 : if (json) {
671 0 : json_object_boolean_add(json, "extended", !!filter->extended);
672 0 : json_object_string_addf(json, "sourceAddress", "%pI4",
673 : &filter->addr);
674 0 : json_object_string_addf(json, "sourceMask", "%pI4",
675 : &filter->addr_mask);
676 0 : json_object_string_addf(json, "destinationAddress", "%pI4",
677 : &filter->mask);
678 0 : json_object_string_addf(json, "destinationMask", "%pI4",
679 : &filter->mask_mask);
680 : } else {
681 0 : vty_out(vty, " ip");
682 0 : if (filter->addr_mask.s_addr == 0xffffffff)
683 0 : vty_out(vty, " any");
684 0 : else if (filter->addr_mask.s_addr == INADDR_ANY)
685 0 : vty_out(vty, " host %pI4", &filter->addr);
686 : else {
687 0 : vty_out(vty, " %pI4", &filter->addr);
688 0 : vty_out(vty, " %pI4", &filter->addr_mask);
689 : }
690 :
691 0 : if (filter->mask_mask.s_addr == 0xffffffff)
692 0 : vty_out(vty, " any");
693 0 : else if (filter->mask_mask.s_addr == INADDR_ANY)
694 0 : vty_out(vty, " host %pI4", &filter->mask);
695 : else {
696 0 : vty_out(vty, " %pI4", &filter->mask);
697 0 : vty_out(vty, " %pI4", &filter->mask_mask);
698 : }
699 0 : vty_out(vty, "\n");
700 : }
701 0 : }
702 :
703 0 : static void config_write_access_zebra(struct vty *vty, struct filter *mfilter,
704 : json_object *json)
705 : {
706 0 : struct filter_zebra *filter;
707 0 : struct prefix *p;
708 0 : char buf[BUFSIZ];
709 :
710 0 : filter = &mfilter->u.zfilter;
711 0 : p = &filter->prefix;
712 :
713 0 : if (json) {
714 0 : json_object_string_addf(json, "prefix", "%pFX", p);
715 0 : json_object_boolean_add(json, "exact-match", !!filter->exact);
716 : } else {
717 0 : if (p->prefixlen == 0 && !filter->exact)
718 0 : vty_out(vty, " any");
719 0 : else if (p->family == AF_INET6 || p->family == AF_INET)
720 0 : vty_out(vty, " %pFX%s", p,
721 0 : filter->exact ? " exact-match" : "");
722 0 : else if (p->family == AF_ETHERNET) {
723 0 : if (p->prefixlen == 0)
724 0 : vty_out(vty, " any");
725 : else
726 0 : vty_out(vty, " %s",
727 0 : prefix_mac2str(&(p->u.prefix_eth), buf,
728 : sizeof(buf)));
729 : }
730 :
731 0 : vty_out(vty, "\n");
732 : }
733 0 : }
734 :
735 : static struct cmd_node access_mac_node = {
736 : .name = "MAC access list",
737 : .node = ACCESS_MAC_NODE,
738 : .prompt = "",
739 : };
740 :
741 165 : static void access_list_reset_mac(void)
742 : {
743 165 : struct access_list *access;
744 165 : struct access_list *next;
745 165 : struct access_master *master;
746 :
747 165 : master = access_master_get(AFI_L2VPN);
748 165 : if (master == NULL)
749 : return;
750 :
751 165 : for (access = master->str.head; access; access = next) {
752 0 : next = access->next;
753 0 : access_list_delete(access);
754 : }
755 :
756 165 : assert(master->str.head == NULL);
757 165 : assert(master->str.tail == NULL);
758 : }
759 :
760 : /* Install vty related command. */
761 201 : static void access_list_init_mac(void)
762 : {
763 201 : install_node(&access_mac_node);
764 :
765 201 : install_element(ENABLE_NODE, &show_mac_access_list_cmd);
766 201 : install_element(ENABLE_NODE, &show_mac_access_list_name_cmd);
767 201 : }
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 0 : static int config_write_access(struct vty *vty)
779 : {
780 0 : struct lyd_node *dnode;
781 0 : int written = 0;
782 :
783 0 : dnode = yang_dnode_get(running_config->dnode, "/frr-filter:lib");
784 0 : if (dnode) {
785 0 : nb_cli_show_dnode_cmds(vty, dnode, false);
786 0 : written = 1;
787 : }
788 :
789 0 : return written;
790 : }
791 :
792 165 : static void access_list_reset_ipv4(void)
793 : {
794 165 : struct access_list *access;
795 165 : struct access_list *next;
796 165 : struct access_master *master;
797 :
798 165 : master = access_master_get(AFI_IP);
799 165 : if (master == NULL)
800 : return;
801 :
802 165 : for (access = master->str.head; access; access = next) {
803 0 : next = access->next;
804 0 : access_list_delete(access);
805 : }
806 :
807 165 : assert(master->str.head == NULL);
808 165 : assert(master->str.tail == NULL);
809 : }
810 :
811 : /* Install vty related command. */
812 201 : static void access_list_init_ipv4(void)
813 : {
814 201 : install_node(&access_node);
815 :
816 201 : install_element(ENABLE_NODE, &show_ip_access_list_cmd);
817 201 : install_element(ENABLE_NODE, &show_ip_access_list_name_cmd);
818 201 : }
819 :
820 0 : static void access_list_autocomplete_afi(afi_t afi, vector comps,
821 : struct cmd_token *token)
822 : {
823 0 : struct access_list *access;
824 0 : struct access_list *next;
825 0 : struct access_master *master;
826 :
827 0 : master = access_master_get(afi);
828 : if (master == NULL)
829 : return;
830 :
831 0 : for (access = master->str.head; access; access = next) {
832 0 : next = access->next;
833 0 : 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 0 : static void access_list_autocomplete(vector comps, struct cmd_token *token)
844 : {
845 0 : access_list_autocomplete_afi(AFI_IP, comps, token);
846 0 : access_list_autocomplete_afi(AFI_IP6, comps, token);
847 0 : access_list_autocomplete_afi(AFI_L2VPN, comps, token);
848 0 : }
849 :
850 0 : static void access_list4_autocomplete(vector comps, struct cmd_token *token)
851 : {
852 0 : access_list_autocomplete_afi(AFI_IP, comps, token);
853 0 : }
854 :
855 0 : static void access_list6_autocomplete(vector comps, struct cmd_token *token)
856 : {
857 0 : access_list_autocomplete_afi(AFI_IP6, comps, token);
858 0 : }
859 :
860 0 : static void access_list_mac_autocomplete(vector comps, struct cmd_token *token)
861 : {
862 0 : access_list_autocomplete_afi(AFI_L2VPN, comps, token);
863 0 : }
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 165 : static void access_list_reset_ipv6(void)
877 : {
878 165 : struct access_list *access;
879 165 : struct access_list *next;
880 165 : struct access_master *master;
881 :
882 165 : master = access_master_get(AFI_IP6);
883 165 : if (master == NULL)
884 : return;
885 :
886 168 : for (access = master->str.head; access; access = next) {
887 3 : next = access->next;
888 3 : access_list_delete(access);
889 : }
890 :
891 165 : assert(master->str.head == NULL);
892 165 : assert(master->str.tail == NULL);
893 : }
894 :
895 201 : static void access_list_init_ipv6(void)
896 : {
897 201 : install_node(&access_ipv6_node);
898 :
899 201 : install_element(ENABLE_NODE, &show_ipv6_access_list_cmd);
900 201 : install_element(ENABLE_NODE, &show_ipv6_access_list_name_cmd);
901 201 : }
902 :
903 201 : void access_list_init(void)
904 : {
905 201 : cmd_variable_handler_register(access_list_handlers);
906 :
907 201 : access_list_init_ipv4();
908 201 : access_list_init_ipv6();
909 201 : access_list_init_mac();
910 :
911 201 : filter_cli_init();
912 201 : }
913 :
914 165 : void access_list_reset(void)
915 : {
916 165 : access_list_reset_ipv4();
917 165 : access_list_reset_ipv6();
918 165 : access_list_reset_mac();
919 165 : }
|