]>
Commit | Line | Data |
---|---|---|
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 |
34 | DEFINE_MTYPE_STATIC(LIB, ACCESS_LIST, "Access List"); |
35 | DEFINE_MTYPE_STATIC(LIB, ACCESS_LIST_STR, "Access List Str"); | |
36 | DEFINE_MTYPE_STATIC(LIB, ACCESS_FILTER, "Access Filter"); | |
d62a17ae | 37 | |
b34fd35d | 38 | /* Static structure for mac access_list's master. */ |
d37ba549 MK |
39 | static 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 | 47 | static 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 | 55 | static struct access_master access_master_ipv6 = { |
56 | {NULL, NULL}, | |
57 | {NULL, NULL}, | |
58 | NULL, | |
59 | NULL, | |
718e3744 | 60 | }; |
6b0655a2 | 61 | |
d62a17ae | 62 | static 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 | 74 | struct filter *filter_new(void) |
718e3744 | 75 | { |
9f5dc319 | 76 | return XCALLOC(MTYPE_ACCESS_FILTER, sizeof(struct filter)); |
718e3744 | 77 | } |
78 | ||
d62a17ae | 79 | static 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 | 85 | static 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 | 100 | static 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 | 124 | static 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 | 143 | static 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 | 149 | static 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 | 155 | void 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 | 193 | static 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 | 276 | struct 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 | 301 | struct 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 |
312 | enum 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 | 335 | void 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 | 343 | void 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 | 351 | int64_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. */ | |
370 | static 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 |
383 | void 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 |
409 | void 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 |
472 | static void config_write_access_zebra(struct vty *, struct filter *); |
473 | static void config_write_access_cisco(struct vty *, struct filter *); | |
718e3744 | 474 | |
475 | /* show access-list command. */ | |
d62a17ae | 476 | static 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*/ |
588 | DEFUN (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 | ||
598 | DEFUN (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 | 609 | DEFUN (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 | ||
619 | DEFUN (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 | 635 | DEFUN (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 | ||
645 | DEFUN (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 | 657 | static 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 | 695 | static 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 | 721 | static 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 |
727 | static 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. */ | |
754 | static 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 | 763 | static int config_write_access(struct vty *vty); |
62b346ee | 764 | static 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 | 771 | static 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 | 785 | static 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 | 812 | static 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 | 820 | static 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 | 826 | static 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 | 852 | static 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 | 860 | void 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 | 869 | void 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 | } |