]>
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 | |
d62a17ae | 34 | DEFINE_MTYPE_STATIC(LIB, ACCESS_LIST, "Access List") |
4a1ab8e4 | 35 | DEFINE_MTYPE_STATIC(LIB, ACCESS_LIST_STR, "Access List Str") |
d62a17ae | 36 | DEFINE_MTYPE_STATIC(LIB, ACCESS_FILTER, "Access Filter") |
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 | ||
4cf24501 RZ |
472 | struct filter *filter_lookup_cisco(struct access_list *access, |
473 | struct filter *mnew) | |
d62a17ae | 474 | { |
475 | struct filter *mfilter; | |
476 | struct filter_cisco *filter; | |
477 | struct filter_cisco *new; | |
478 | ||
479 | new = &mnew->u.cfilter; | |
480 | ||
481 | for (mfilter = access->head; mfilter; mfilter = mfilter->next) { | |
482 | filter = &mfilter->u.cfilter; | |
483 | ||
484 | if (filter->extended) { | |
485 | if (mfilter->type == mnew->type | |
486 | && filter->addr.s_addr == new->addr.s_addr | |
487 | && filter->addr_mask.s_addr == new->addr_mask.s_addr | |
488 | && filter->mask.s_addr == new->mask.s_addr | |
489 | && filter->mask_mask.s_addr | |
490 | == new->mask_mask.s_addr) | |
491 | return mfilter; | |
492 | } else { | |
493 | if (mfilter->type == mnew->type | |
494 | && filter->addr.s_addr == new->addr.s_addr | |
495 | && filter->addr_mask.s_addr | |
496 | == new->addr_mask.s_addr) | |
497 | return mfilter; | |
498 | } | |
499 | } | |
500 | ||
501 | return NULL; | |
502 | } | |
503 | ||
4cf24501 RZ |
504 | struct filter *filter_lookup_zebra(struct access_list *access, |
505 | struct filter *mnew) | |
718e3744 | 506 | { |
d62a17ae | 507 | struct filter *mfilter; |
508 | struct filter_zebra *filter; | |
509 | struct filter_zebra *new; | |
718e3744 | 510 | |
d62a17ae | 511 | new = &mnew->u.zfilter; |
718e3744 | 512 | |
d62a17ae | 513 | for (mfilter = access->head; mfilter; mfilter = mfilter->next) { |
514 | filter = &mfilter->u.zfilter; | |
718e3744 | 515 | |
d62a17ae | 516 | if (filter->exact == new->exact |
d37ba549 | 517 | && mfilter->type == mnew->type) { |
0f6476cc DS |
518 | if (prefix_same(&filter->prefix, &new->prefix)) |
519 | return mfilter; | |
d37ba549 | 520 | } |
718e3744 | 521 | } |
d62a17ae | 522 | return NULL; |
523 | } | |
524 | ||
eb51bb9b DL |
525 | static void config_write_access_zebra(struct vty *, struct filter *); |
526 | static void config_write_access_cisco(struct vty *, struct filter *); | |
718e3744 | 527 | |
528 | /* show access-list command. */ | |
d62a17ae | 529 | static int filter_show(struct vty *vty, const char *name, afi_t afi) |
530 | { | |
531 | struct access_list *access; | |
532 | struct access_master *master; | |
533 | struct filter *mfilter; | |
534 | struct filter_cisco *filter; | |
535 | int write = 0; | |
536 | ||
537 | master = access_master_get(afi); | |
538 | if (master == NULL) | |
539 | return 0; | |
540 | ||
541 | /* Print the name of the protocol */ | |
542 | vty_out(vty, "%s:\n", frr_protoname); | |
543 | ||
544 | for (access = master->num.head; access; access = access->next) { | |
545 | if (name && strcmp(access->name, name) != 0) | |
546 | continue; | |
547 | ||
548 | write = 1; | |
549 | ||
550 | for (mfilter = access->head; mfilter; mfilter = mfilter->next) { | |
551 | filter = &mfilter->u.cfilter; | |
552 | ||
553 | if (write) { | |
d37ba549 | 554 | vty_out(vty, "%s %s access list %s\n", |
d62a17ae | 555 | mfilter->cisco ? (filter->extended |
556 | ? "Extended" | |
557 | : "Standard") | |
558 | : "Zebra", | |
d37ba549 | 559 | (afi == AFI_IP) |
3b0f6068 DL |
560 | ? ("IP") |
561 | : ((afi == AFI_IP6) ? ("IPv6 ") | |
562 | : ("MAC ")), | |
d62a17ae | 563 | access->name); |
564 | write = 0; | |
565 | } | |
566 | ||
358189ad DA |
567 | vty_out(vty, " seq %" PRId64, mfilter->seq); |
568 | vty_out(vty, " %s%s", filter_type_str(mfilter), | |
d62a17ae | 569 | mfilter->type == FILTER_DENY ? " " : ""); |
570 | ||
571 | if (!mfilter->cisco) | |
572 | config_write_access_zebra(vty, mfilter); | |
573 | else if (filter->extended) | |
574 | config_write_access_cisco(vty, mfilter); | |
575 | else { | |
576 | if (filter->addr_mask.s_addr == 0xffffffff) | |
577 | vty_out(vty, " any\n"); | |
578 | else { | |
579 | vty_out(vty, " %s", | |
580 | inet_ntoa(filter->addr)); | |
975a328e DA |
581 | if (filter->addr_mask.s_addr |
582 | != INADDR_ANY) | |
d62a17ae | 583 | vty_out(vty, |
584 | ", wildcard bits %s", | |
585 | inet_ntoa( | |
586 | filter->addr_mask)); | |
587 | vty_out(vty, "\n"); | |
588 | } | |
589 | } | |
718e3744 | 590 | } |
718e3744 | 591 | } |
d62a17ae | 592 | |
593 | for (access = master->str.head; access; access = access->next) { | |
594 | if (name && strcmp(access->name, name) != 0) | |
595 | continue; | |
596 | ||
597 | write = 1; | |
598 | ||
599 | for (mfilter = access->head; mfilter; mfilter = mfilter->next) { | |
600 | filter = &mfilter->u.cfilter; | |
601 | ||
602 | if (write) { | |
d37ba549 | 603 | vty_out(vty, "%s %s access list %s\n", |
d62a17ae | 604 | mfilter->cisco ? (filter->extended |
605 | ? "Extended" | |
606 | : "Standard") | |
607 | : "Zebra", | |
d37ba549 | 608 | (afi == AFI_IP) |
3b0f6068 DL |
609 | ? ("IP") |
610 | : ((afi == AFI_IP6) ? ("IPv6 ") | |
611 | : ("MAC ")), | |
d62a17ae | 612 | access->name); |
613 | write = 0; | |
614 | } | |
615 | ||
358189ad DA |
616 | vty_out(vty, " seq %" PRId64, mfilter->seq); |
617 | vty_out(vty, " %s%s", filter_type_str(mfilter), | |
d62a17ae | 618 | mfilter->type == FILTER_DENY ? " " : ""); |
619 | ||
620 | if (!mfilter->cisco) | |
621 | config_write_access_zebra(vty, mfilter); | |
622 | else if (filter->extended) | |
623 | config_write_access_cisco(vty, mfilter); | |
624 | else { | |
625 | if (filter->addr_mask.s_addr == 0xffffffff) | |
626 | vty_out(vty, " any\n"); | |
627 | else { | |
628 | vty_out(vty, " %s", | |
629 | inet_ntoa(filter->addr)); | |
975a328e DA |
630 | if (filter->addr_mask.s_addr |
631 | != INADDR_ANY) | |
d62a17ae | 632 | vty_out(vty, |
633 | ", wildcard bits %s", | |
634 | inet_ntoa( | |
635 | filter->addr_mask)); | |
636 | vty_out(vty, "\n"); | |
637 | } | |
638 | } | |
718e3744 | 639 | } |
718e3744 | 640 | } |
d62a17ae | 641 | return CMD_SUCCESS; |
718e3744 | 642 | } |
643 | ||
d37ba549 MK |
644 | /* show MAC access list - this only has MAC filters for now*/ |
645 | DEFUN (show_mac_access_list, | |
646 | show_mac_access_list_cmd, | |
647 | "show mac access-list", | |
648 | SHOW_STR | |
649 | "mac access lists\n" | |
650 | "List mac access lists\n") | |
651 | { | |
652 | return filter_show(vty, NULL, AFI_L2VPN); | |
653 | } | |
654 | ||
655 | DEFUN (show_mac_access_list_name, | |
656 | show_mac_access_list_name_cmd, | |
657 | "show mac access-list WORD", | |
658 | SHOW_STR | |
1667fc40 | 659 | "mac access lists\n" |
d37ba549 | 660 | "List mac access lists\n" |
1667fc40 | 661 | "mac address\n") |
d37ba549 MK |
662 | { |
663 | return filter_show(vty, argv[3]->arg, AFI_L2VPN); | |
664 | } | |
665 | ||
718e3744 | 666 | DEFUN (show_ip_access_list, |
667 | show_ip_access_list_cmd, | |
668 | "show ip access-list", | |
669 | SHOW_STR | |
670 | IP_STR | |
671 | "List IP access lists\n") | |
672 | { | |
d62a17ae | 673 | return filter_show(vty, NULL, AFI_IP); |
718e3744 | 674 | } |
675 | ||
676 | DEFUN (show_ip_access_list_name, | |
677 | show_ip_access_list_name_cmd, | |
6147e2c6 | 678 | "show ip access-list <(1-99)|(100-199)|(1300-1999)|(2000-2699)|WORD>", |
718e3744 | 679 | SHOW_STR |
680 | IP_STR | |
681 | "List IP access lists\n" | |
682 | "IP standard access list\n" | |
683 | "IP extended access list\n" | |
684 | "IP standard access list (expanded range)\n" | |
685 | "IP extended access list (expanded range)\n" | |
686 | "IP zebra access-list\n") | |
687 | { | |
d62a17ae | 688 | int idx_acl = 3; |
689 | return filter_show(vty, argv[idx_acl]->arg, AFI_IP); | |
718e3744 | 690 | } |
691 | ||
718e3744 | 692 | DEFUN (show_ipv6_access_list, |
693 | show_ipv6_access_list_cmd, | |
694 | "show ipv6 access-list", | |
695 | SHOW_STR | |
696 | IPV6_STR | |
697 | "List IPv6 access lists\n") | |
698 | { | |
d62a17ae | 699 | return filter_show(vty, NULL, AFI_IP6); |
718e3744 | 700 | } |
701 | ||
702 | DEFUN (show_ipv6_access_list_name, | |
703 | show_ipv6_access_list_name_cmd, | |
704 | "show ipv6 access-list WORD", | |
705 | SHOW_STR | |
706 | IPV6_STR | |
707 | "List IPv6 access lists\n" | |
708 | "IPv6 zebra access-list\n") | |
709 | { | |
d62a17ae | 710 | int idx_word = 3; |
711 | return filter_show(vty, argv[idx_word]->arg, AFI_IP6); | |
712 | } | |
713 | ||
eb51bb9b | 714 | static void config_write_access_cisco(struct vty *vty, struct filter *mfilter) |
d62a17ae | 715 | { |
716 | struct filter_cisco *filter; | |
717 | ||
718 | filter = &mfilter->u.cfilter; | |
719 | ||
720 | if (filter->extended) { | |
721 | vty_out(vty, " ip"); | |
722 | if (filter->addr_mask.s_addr == 0xffffffff) | |
723 | vty_out(vty, " any"); | |
975a328e | 724 | else if (filter->addr_mask.s_addr == INADDR_ANY) |
d62a17ae | 725 | vty_out(vty, " host %s", inet_ntoa(filter->addr)); |
726 | else { | |
727 | vty_out(vty, " %s", inet_ntoa(filter->addr)); | |
728 | vty_out(vty, " %s", inet_ntoa(filter->addr_mask)); | |
729 | } | |
730 | ||
731 | if (filter->mask_mask.s_addr == 0xffffffff) | |
732 | vty_out(vty, " any"); | |
975a328e | 733 | else if (filter->mask_mask.s_addr == INADDR_ANY) |
d62a17ae | 734 | vty_out(vty, " host %s", inet_ntoa(filter->mask)); |
735 | else { | |
736 | vty_out(vty, " %s", inet_ntoa(filter->mask)); | |
737 | vty_out(vty, " %s", inet_ntoa(filter->mask_mask)); | |
738 | } | |
739 | vty_out(vty, "\n"); | |
740 | } else { | |
741 | if (filter->addr_mask.s_addr == 0xffffffff) | |
742 | vty_out(vty, " any\n"); | |
743 | else { | |
744 | vty_out(vty, " %s", inet_ntoa(filter->addr)); | |
975a328e | 745 | if (filter->addr_mask.s_addr != INADDR_ANY) |
d62a17ae | 746 | vty_out(vty, " %s", |
747 | inet_ntoa(filter->addr_mask)); | |
748 | vty_out(vty, "\n"); | |
749 | } | |
718e3744 | 750 | } |
718e3744 | 751 | } |
752 | ||
eb51bb9b | 753 | static void config_write_access_zebra(struct vty *vty, struct filter *mfilter) |
718e3744 | 754 | { |
d62a17ae | 755 | struct filter_zebra *filter; |
756 | struct prefix *p; | |
757 | char buf[BUFSIZ]; | |
718e3744 | 758 | |
d62a17ae | 759 | filter = &mfilter->u.zfilter; |
760 | p = &filter->prefix; | |
718e3744 | 761 | |
d62a17ae | 762 | if (p->prefixlen == 0 && !filter->exact) |
763 | vty_out(vty, " any"); | |
d37ba549 | 764 | else if (p->family == AF_INET6 || p->family == AF_INET) |
d62a17ae | 765 | vty_out(vty, " %s/%d%s", |
766 | inet_ntop(p->family, &p->u.prefix, buf, BUFSIZ), | |
767 | p->prefixlen, filter->exact ? " exact-match" : ""); | |
69b61704 | 768 | else if (p->family == AF_ETHERNET) { |
3b0f6068 | 769 | if (p->prefixlen == 0) |
69b61704 MK |
770 | vty_out(vty, " any"); |
771 | else | |
772 | vty_out(vty, " %s", prefix_mac2str(&(p->u.prefix_eth), | |
773 | buf, sizeof(buf))); | |
774 | } | |
718e3744 | 775 | |
d62a17ae | 776 | vty_out(vty, "\n"); |
718e3744 | 777 | } |
778 | ||
d37ba549 | 779 | static struct cmd_node access_mac_node = { |
f4b8291f | 780 | .name = "MAC access list", |
62b346ee DL |
781 | .node = ACCESS_MAC_NODE, |
782 | .prompt = "", | |
62b346ee | 783 | }; |
d37ba549 | 784 | |
d37ba549 MK |
785 | static void access_list_reset_mac(void) |
786 | { | |
787 | struct access_list *access; | |
788 | struct access_list *next; | |
789 | struct access_master *master; | |
790 | ||
791 | master = access_master_get(AFI_L2VPN); | |
792 | if (master == NULL) | |
793 | return; | |
794 | ||
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 | } | |
803 | ||
804 | assert(master->num.head == NULL); | |
805 | assert(master->num.tail == NULL); | |
806 | ||
807 | assert(master->str.head == NULL); | |
808 | assert(master->str.tail == NULL); | |
809 | } | |
810 | ||
811 | /* Install vty related command. */ | |
812 | static void access_list_init_mac(void) | |
813 | { | |
612c2c15 | 814 | install_node(&access_mac_node); |
d37ba549 MK |
815 | |
816 | install_element(ENABLE_NODE, &show_mac_access_list_cmd); | |
817 | install_element(ENABLE_NODE, &show_mac_access_list_name_cmd); | |
d37ba549 MK |
818 | } |
819 | ||
718e3744 | 820 | /* Access-list node. */ |
1d3c4b66 | 821 | static int config_write_access(struct vty *vty); |
62b346ee | 822 | static struct cmd_node access_node = { |
f4b8291f | 823 | .name = "ipv4 access list", |
62b346ee DL |
824 | .node = ACCESS_NODE, |
825 | .prompt = "", | |
1d3c4b66 | 826 | .config_write = config_write_access, |
62b346ee | 827 | }; |
718e3744 | 828 | |
1d3c4b66 | 829 | static int config_write_access(struct vty *vty) |
718e3744 | 830 | { |
1d3c4b66 RZ |
831 | struct lyd_node *dnode; |
832 | int written = 0; | |
833 | ||
834 | dnode = yang_dnode_get(running_config->dnode, "/frr-filter:lib"); | |
835 | if (dnode) { | |
836 | nb_cli_show_dnode_cmds(vty, dnode, false); | |
837 | written = 1; | |
838 | } | |
839 | ||
840 | return written; | |
718e3744 | 841 | } |
842 | ||
d62a17ae | 843 | static void access_list_reset_ipv4(void) |
718e3744 | 844 | { |
d62a17ae | 845 | struct access_list *access; |
846 | struct access_list *next; | |
847 | struct access_master *master; | |
718e3744 | 848 | |
d62a17ae | 849 | master = access_master_get(AFI_IP); |
850 | if (master == NULL) | |
851 | return; | |
718e3744 | 852 | |
d62a17ae | 853 | for (access = master->num.head; access; access = next) { |
854 | next = access->next; | |
855 | access_list_delete(access); | |
856 | } | |
857 | for (access = master->str.head; access; access = next) { | |
858 | next = access->next; | |
859 | access_list_delete(access); | |
860 | } | |
718e3744 | 861 | |
d62a17ae | 862 | assert(master->num.head == NULL); |
863 | assert(master->num.tail == NULL); | |
718e3744 | 864 | |
d62a17ae | 865 | assert(master->str.head == NULL); |
866 | assert(master->str.tail == NULL); | |
718e3744 | 867 | } |
868 | ||
869 | /* Install vty related command. */ | |
d62a17ae | 870 | static void access_list_init_ipv4(void) |
871 | { | |
612c2c15 | 872 | install_node(&access_node); |
d62a17ae | 873 | |
874 | install_element(ENABLE_NODE, &show_ip_access_list_cmd); | |
875 | install_element(ENABLE_NODE, &show_ip_access_list_name_cmd); | |
d62a17ae | 876 | } |
877 | ||
62b346ee | 878 | static struct cmd_node access_ipv6_node = { |
f4b8291f | 879 | .name = "ipv6 access list", |
62b346ee DL |
880 | .node = ACCESS_IPV6_NODE, |
881 | .prompt = "", | |
62b346ee | 882 | }; |
d62a17ae | 883 | |
d62a17ae | 884 | static void access_list_reset_ipv6(void) |
885 | { | |
886 | struct access_list *access; | |
887 | struct access_list *next; | |
888 | struct access_master *master; | |
889 | ||
890 | master = access_master_get(AFI_IP6); | |
891 | if (master == NULL) | |
892 | return; | |
893 | ||
894 | for (access = master->num.head; access; access = next) { | |
895 | next = access->next; | |
896 | access_list_delete(access); | |
897 | } | |
898 | for (access = master->str.head; access; access = next) { | |
899 | next = access->next; | |
900 | access_list_delete(access); | |
901 | } | |
718e3744 | 902 | |
d62a17ae | 903 | assert(master->num.head == NULL); |
904 | assert(master->num.tail == NULL); | |
718e3744 | 905 | |
d62a17ae | 906 | assert(master->str.head == NULL); |
907 | assert(master->str.tail == NULL); | |
718e3744 | 908 | } |
909 | ||
d62a17ae | 910 | static void access_list_init_ipv6(void) |
718e3744 | 911 | { |
612c2c15 | 912 | install_node(&access_ipv6_node); |
718e3744 | 913 | |
d62a17ae | 914 | install_element(ENABLE_NODE, &show_ipv6_access_list_cmd); |
915 | install_element(ENABLE_NODE, &show_ipv6_access_list_name_cmd); | |
718e3744 | 916 | } |
718e3744 | 917 | |
4d762f26 | 918 | void access_list_init(void) |
718e3744 | 919 | { |
d62a17ae | 920 | access_list_init_ipv4(); |
921 | access_list_init_ipv6(); | |
d37ba549 | 922 | access_list_init_mac(); |
b62578bd RZ |
923 | |
924 | filter_cli_init(); | |
718e3744 | 925 | } |
926 | ||
4d762f26 | 927 | void access_list_reset(void) |
718e3744 | 928 | { |
d62a17ae | 929 | access_list_reset_ipv4(); |
930 | access_list_reset_ipv6(); | |
d37ba549 | 931 | access_list_reset_mac(); |
718e3744 | 932 | } |