]>
Commit | Line | Data |
---|---|---|
718e3744 | 1 | /* AS path filter list. |
2 | Copyright (C) 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 it | |
7 | under the terms of the GNU General Public License as published by the | |
8 | Free Software Foundation; either version 2, or (at your option) any | |
9 | 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 | |
17 | along with GNU Zebra; see the file COPYING. If not, write to the Free | |
18 | Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA | |
19 | 02111-1307, USA. */ | |
20 | ||
21 | #include <zebra.h> | |
22 | ||
23 | #include "command.h" | |
24 | #include "log.h" | |
25 | #include "memory.h" | |
26 | #include "buffer.h" | |
27 | ||
28 | #include "bgpd/bgpd.h" | |
29 | #include "bgpd/bgp_aspath.h" | |
30 | #include "bgpd/bgp_regex.h" | |
31 | #include "bgpd/bgp_filter.h" | |
32 | ||
33 | /* List of AS filter list. */ | |
34 | struct as_list_list | |
35 | { | |
36 | struct as_list *head; | |
37 | struct as_list *tail; | |
38 | }; | |
39 | ||
40 | /* AS path filter master. */ | |
41 | struct as_list_master | |
42 | { | |
43 | /* List of access_list which name is number. */ | |
44 | struct as_list_list num; | |
45 | ||
46 | /* List of access_list which name is string. */ | |
47 | struct as_list_list str; | |
48 | ||
49 | /* Hook function which is executed when new access_list is added. */ | |
50 | void (*add_hook) (); | |
51 | ||
52 | /* Hook function which is executed when access_list is deleted. */ | |
53 | void (*delete_hook) (); | |
54 | }; | |
55 | ||
56 | /* Element of AS path filter. */ | |
57 | struct as_filter | |
58 | { | |
59 | struct as_filter *next; | |
60 | struct as_filter *prev; | |
61 | ||
62 | enum as_filter_type type; | |
63 | ||
64 | regex_t *reg; | |
65 | char *reg_str; | |
66 | }; | |
67 | ||
68 | enum as_list_type | |
69 | { | |
70 | ACCESS_TYPE_STRING, | |
71 | ACCESS_TYPE_NUMBER | |
72 | }; | |
73 | ||
74 | /* AS path filter list. */ | |
75 | struct as_list | |
76 | { | |
77 | char *name; | |
78 | ||
79 | enum as_list_type type; | |
80 | ||
81 | struct as_list *next; | |
82 | struct as_list *prev; | |
83 | ||
84 | struct as_filter *head; | |
85 | struct as_filter *tail; | |
86 | }; | |
87 | \f | |
88 | /* ip as-path access-list 10 permit AS1. */ | |
89 | ||
90 | static struct as_list_master as_list_master = | |
91 | { | |
92 | {NULL, NULL}, | |
93 | {NULL, NULL}, | |
94 | NULL, | |
95 | NULL | |
96 | }; | |
97 | ||
98 | /* Allocate new AS filter. */ | |
99 | struct as_filter * | |
100 | as_filter_new () | |
101 | { | |
102 | struct as_filter *new; | |
103 | ||
104 | new = XMALLOC (MTYPE_AS_FILTER, sizeof (struct as_filter)); | |
105 | memset (new, 0, sizeof (struct as_filter)); | |
106 | return new; | |
107 | } | |
108 | ||
109 | /* Free allocated AS filter. */ | |
110 | void | |
111 | as_filter_free (struct as_filter *asfilter) | |
112 | { | |
113 | if (asfilter->reg) | |
114 | bgp_regex_free (asfilter->reg); | |
115 | if (asfilter->reg_str) | |
116 | XFREE (MTYPE_AS_FILTER_STR, asfilter->reg_str); | |
117 | XFREE (MTYPE_AS_FILTER, asfilter); | |
118 | } | |
119 | ||
120 | /* Make new AS filter. */ | |
121 | struct as_filter * | |
fd79ac91 | 122 | as_filter_make (regex_t *reg, const char *reg_str, enum as_filter_type type) |
718e3744 | 123 | { |
124 | struct as_filter *asfilter; | |
125 | ||
126 | asfilter = as_filter_new (); | |
127 | asfilter->reg = reg; | |
128 | asfilter->type = type; | |
129 | asfilter->reg_str = XSTRDUP (MTYPE_AS_FILTER_STR, reg_str); | |
130 | ||
131 | return asfilter; | |
132 | } | |
133 | ||
134 | struct as_filter * | |
fd79ac91 | 135 | as_filter_lookup (struct as_list *aslist, const char *reg_str, |
718e3744 | 136 | enum as_filter_type type) |
137 | { | |
138 | struct as_filter *asfilter; | |
139 | ||
140 | for (asfilter = aslist->head; asfilter; asfilter = asfilter->next) | |
141 | if (strcmp (reg_str, asfilter->reg_str) == 0) | |
142 | return asfilter; | |
143 | return NULL; | |
144 | } | |
145 | ||
146 | void | |
147 | as_list_filter_add (struct as_list *aslist, struct as_filter *asfilter) | |
148 | { | |
149 | asfilter->next = NULL; | |
150 | asfilter->prev = aslist->tail; | |
151 | ||
152 | if (aslist->tail) | |
153 | aslist->tail->next = asfilter; | |
154 | else | |
155 | aslist->head = asfilter; | |
156 | aslist->tail = asfilter; | |
157 | } | |
158 | ||
159 | /* Lookup as_list from list of as_list by name. */ | |
160 | struct as_list * | |
fd79ac91 | 161 | as_list_lookup (const char *name) |
718e3744 | 162 | { |
163 | struct as_list *aslist; | |
164 | ||
165 | if (name == NULL) | |
166 | return NULL; | |
167 | ||
168 | for (aslist = as_list_master.num.head; aslist; aslist = aslist->next) | |
169 | if (strcmp (aslist->name, name) == 0) | |
170 | return aslist; | |
171 | ||
172 | for (aslist = as_list_master.str.head; aslist; aslist = aslist->next) | |
173 | if (strcmp (aslist->name, name) == 0) | |
174 | return aslist; | |
175 | ||
176 | return NULL; | |
177 | } | |
178 | ||
179 | struct as_list * | |
180 | as_list_new () | |
181 | { | |
182 | struct as_list *new; | |
183 | ||
184 | new = XMALLOC (MTYPE_AS_LIST, sizeof (struct as_list)); | |
185 | memset (new, 0, sizeof (struct as_list)); | |
186 | return new; | |
187 | } | |
188 | ||
189 | void | |
190 | as_list_free (struct as_list *aslist) | |
191 | { | |
192 | XFREE (MTYPE_AS_LIST, aslist); | |
193 | } | |
194 | ||
195 | /* Insert new AS list to list of as_list. Each as_list is sorted by | |
196 | the name. */ | |
197 | struct as_list * | |
fd79ac91 | 198 | as_list_insert (const char *name) |
718e3744 | 199 | { |
fd79ac91 | 200 | size_t i; |
718e3744 | 201 | long number; |
202 | struct as_list *aslist; | |
203 | struct as_list *point; | |
204 | struct as_list_list *list; | |
205 | ||
206 | /* Allocate new access_list and copy given name. */ | |
207 | aslist = as_list_new (); | |
208 | aslist->name = strdup (name); | |
209 | ||
210 | /* If name is made by all digit character. We treat it as | |
211 | number. */ | |
212 | for (number = 0, i = 0; i < strlen (name); i++) | |
213 | { | |
214 | if (isdigit ((int) name[i])) | |
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 | { | |
223 | aslist->type = ACCESS_TYPE_NUMBER; | |
224 | ||
225 | /* Set access_list to number list. */ | |
226 | list = &as_list_master.num; | |
227 | ||
228 | for (point = list->head; point; point = point->next) | |
229 | if (atol (point->name) >= number) | |
230 | break; | |
231 | } | |
232 | else | |
233 | { | |
234 | aslist->type = ACCESS_TYPE_STRING; | |
235 | ||
236 | /* Set access_list to string list. */ | |
237 | list = &as_list_master.str; | |
238 | ||
239 | /* Set point to insertion point. */ | |
240 | for (point = list->head; point; point = point->next) | |
241 | if (strcmp (point->name, name) >= 0) | |
242 | break; | |
243 | } | |
244 | ||
245 | /* In case of this is the first element of master. */ | |
246 | if (list->head == NULL) | |
247 | { | |
248 | list->head = list->tail = aslist; | |
249 | return aslist; | |
250 | } | |
251 | ||
252 | /* In case of insertion is made at the tail of access_list. */ | |
253 | if (point == NULL) | |
254 | { | |
255 | aslist->prev = list->tail; | |
256 | list->tail->next = aslist; | |
257 | list->tail = aslist; | |
258 | return aslist; | |
259 | } | |
260 | ||
261 | /* In case of insertion is made at the head of access_list. */ | |
262 | if (point == list->head) | |
263 | { | |
264 | aslist->next = list->head; | |
265 | list->head->prev = aslist; | |
266 | list->head = aslist; | |
267 | return aslist; | |
268 | } | |
269 | ||
270 | /* Insertion is made at middle of the access_list. */ | |
271 | aslist->next = point; | |
272 | aslist->prev = point->prev; | |
273 | ||
274 | if (point->prev) | |
275 | point->prev->next = aslist; | |
276 | point->prev = aslist; | |
277 | ||
278 | return aslist; | |
279 | } | |
280 | ||
281 | struct as_list * | |
fd79ac91 | 282 | as_list_get (const char *name) |
718e3744 | 283 | { |
284 | struct as_list *aslist; | |
285 | ||
286 | aslist = as_list_lookup (name); | |
287 | if (aslist == NULL) | |
288 | { | |
289 | aslist = as_list_insert (name); | |
290 | ||
291 | /* Run hook function. */ | |
292 | if (as_list_master.add_hook) | |
293 | (*as_list_master.add_hook) (); | |
294 | } | |
295 | ||
296 | return aslist; | |
297 | } | |
298 | ||
fd79ac91 | 299 | static const char * |
718e3744 | 300 | filter_type_str (enum as_filter_type type) |
301 | { | |
302 | switch (type) | |
303 | { | |
304 | case AS_FILTER_PERMIT: | |
305 | return "permit"; | |
306 | break; | |
307 | case AS_FILTER_DENY: | |
308 | return "deny"; | |
309 | break; | |
310 | default: | |
311 | return ""; | |
312 | break; | |
313 | } | |
314 | } | |
315 | ||
316 | void | |
317 | as_list_delete (struct as_list *aslist) | |
318 | { | |
319 | struct as_list_list *list; | |
320 | struct as_filter *filter, *next; | |
321 | ||
322 | for (filter = aslist->head; filter; filter = next) | |
323 | { | |
324 | next = filter->next; | |
325 | as_filter_free (filter); | |
326 | } | |
327 | ||
328 | if (aslist->type == ACCESS_TYPE_NUMBER) | |
329 | list = &as_list_master.num; | |
330 | else | |
331 | list = &as_list_master.str; | |
332 | ||
333 | if (aslist->next) | |
334 | aslist->next->prev = aslist->prev; | |
335 | else | |
336 | list->tail = aslist->prev; | |
337 | ||
338 | if (aslist->prev) | |
339 | aslist->prev->next = aslist->next; | |
340 | else | |
341 | list->head = aslist->next; | |
342 | ||
343 | as_list_free (aslist); | |
344 | } | |
345 | ||
346 | static int | |
347 | as_list_empty (struct as_list *aslist) | |
348 | { | |
349 | if (aslist->head == NULL && aslist->tail == NULL) | |
350 | return 1; | |
351 | else | |
352 | return 0; | |
353 | } | |
354 | ||
355 | void | |
356 | as_list_filter_delete (struct as_list *aslist, struct as_filter *asfilter) | |
357 | { | |
358 | if (asfilter->next) | |
359 | asfilter->next->prev = asfilter->prev; | |
360 | else | |
361 | aslist->tail = asfilter->prev; | |
362 | ||
363 | if (asfilter->prev) | |
364 | asfilter->prev->next = asfilter->next; | |
365 | else | |
366 | aslist->head = asfilter->next; | |
367 | ||
368 | as_filter_free (asfilter); | |
369 | ||
370 | /* If access_list becomes empty delete it from access_master. */ | |
371 | if (as_list_empty (aslist)) | |
372 | as_list_delete (aslist); | |
373 | ||
374 | /* Run hook function. */ | |
375 | if (as_list_master.delete_hook) | |
376 | (*as_list_master.delete_hook) (); | |
377 | } | |
378 | \f | |
379 | static int | |
380 | as_filter_match (struct as_filter *asfilter, struct aspath *aspath) | |
381 | { | |
382 | if (bgp_regexec (asfilter->reg, aspath) != REG_NOMATCH) | |
383 | return 1; | |
384 | return 0; | |
385 | } | |
386 | ||
387 | /* Apply AS path filter to AS. */ | |
388 | enum as_filter_type | |
389 | as_list_apply (struct as_list *aslist, void *object) | |
390 | { | |
391 | struct as_filter *asfilter; | |
392 | struct aspath *aspath; | |
393 | ||
394 | aspath = (struct aspath *) object; | |
395 | ||
396 | if (aslist == NULL) | |
397 | return AS_FILTER_DENY; | |
398 | ||
399 | for (asfilter = aslist->head; asfilter; asfilter = asfilter->next) | |
400 | { | |
401 | if (as_filter_match (asfilter, aspath)) | |
402 | return asfilter->type; | |
403 | } | |
404 | return AS_FILTER_DENY; | |
405 | } | |
406 | ||
407 | /* Add hook function. */ | |
408 | void | |
409 | as_list_add_hook (void (*func) ()) | |
410 | { | |
411 | as_list_master.add_hook = func; | |
412 | } | |
413 | ||
414 | /* Delete hook function. */ | |
415 | void | |
416 | as_list_delete_hook (void (*func) ()) | |
417 | { | |
418 | as_list_master.delete_hook = func; | |
419 | } | |
420 | \f | |
421 | int | |
422 | as_list_dup_check (struct as_list *aslist, struct as_filter *new) | |
423 | { | |
424 | struct as_filter *asfilter; | |
425 | ||
426 | for (asfilter = aslist->head; asfilter; asfilter = asfilter->next) | |
427 | { | |
428 | if (asfilter->type == new->type | |
429 | && strcmp (asfilter->reg_str, new->reg_str) == 0) | |
430 | return 1; | |
431 | } | |
432 | return 0; | |
433 | } | |
434 | ||
435 | DEFUN (ip_as_path, ip_as_path_cmd, | |
436 | "ip as-path access-list WORD (deny|permit) .LINE", | |
437 | IP_STR | |
438 | "BGP autonomous system path filter\n" | |
439 | "Specify an access list name\n" | |
440 | "Regular expression access list name\n" | |
441 | "Specify packets to reject\n" | |
442 | "Specify packets to forward\n" | |
443 | "A regular-expression to match the BGP AS paths\n") | |
444 | { | |
445 | enum as_filter_type type; | |
446 | struct as_filter *asfilter; | |
447 | struct as_list *aslist; | |
448 | regex_t *regex; | |
449 | struct buffer *b; | |
450 | int i; | |
451 | char *regstr; | |
452 | int first = 0; | |
453 | ||
454 | /* Check the filter type. */ | |
455 | if (strncmp (argv[1], "p", 1) == 0) | |
456 | type = AS_FILTER_PERMIT; | |
457 | else if (strncmp (argv[1], "d", 1) == 0) | |
458 | type = AS_FILTER_DENY; | |
459 | else | |
460 | { | |
461 | vty_out (vty, "filter type must be [permit|deny]%s", VTY_NEWLINE); | |
462 | return CMD_WARNING; | |
463 | } | |
464 | ||
465 | /* Check AS path regex. */ | |
466 | b = buffer_new (1024); | |
467 | for (i = 2; i < argc; i++) | |
468 | { | |
469 | if (first) | |
470 | buffer_putc (b, ' '); | |
471 | else | |
472 | first = 1; | |
473 | ||
474 | buffer_putstr (b, argv[i]); | |
475 | } | |
476 | buffer_putc (b, '\0'); | |
477 | ||
478 | regstr = buffer_getstr (b); | |
479 | buffer_free (b); | |
480 | ||
481 | regex = bgp_regcomp (regstr); | |
482 | if (!regex) | |
483 | { | |
484 | free (regstr); | |
485 | vty_out (vty, "can't compile regexp %s%s", argv[0], | |
486 | VTY_NEWLINE); | |
487 | return CMD_WARNING; | |
488 | } | |
489 | ||
490 | asfilter = as_filter_make (regex, regstr, type); | |
491 | ||
492 | free (regstr); | |
493 | ||
494 | /* Install new filter to the access_list. */ | |
495 | aslist = as_list_get (argv[0]); | |
496 | ||
497 | /* Duplicate insertion check. */; | |
498 | if (as_list_dup_check (aslist, asfilter)) | |
499 | as_filter_free (asfilter); | |
500 | else | |
501 | as_list_filter_add (aslist, asfilter); | |
502 | ||
503 | return CMD_SUCCESS; | |
504 | } | |
505 | ||
506 | DEFUN (no_ip_as_path, | |
507 | no_ip_as_path_cmd, | |
508 | "no ip as-path access-list WORD (deny|permit) .LINE", | |
509 | NO_STR | |
510 | IP_STR | |
511 | "BGP autonomous system path filter\n" | |
512 | "Specify an access list name\n" | |
513 | "Regular expression access list name\n" | |
514 | "Specify packets to reject\n" | |
515 | "Specify packets to forward\n" | |
516 | "A regular-expression to match the BGP AS paths\n") | |
517 | { | |
518 | enum as_filter_type type; | |
519 | struct as_filter *asfilter; | |
520 | struct as_list *aslist; | |
521 | struct buffer *b; | |
522 | int i; | |
523 | int first = 0; | |
524 | char *regstr; | |
525 | regex_t *regex; | |
526 | ||
527 | /* Lookup AS list from AS path list. */ | |
528 | aslist = as_list_lookup (argv[0]); | |
529 | if (aslist == NULL) | |
530 | { | |
531 | vty_out (vty, "ip as-path access-list %s doesn't exist%s", argv[0], | |
532 | VTY_NEWLINE); | |
533 | return CMD_WARNING; | |
534 | } | |
535 | ||
536 | /* Check the filter type. */ | |
537 | if (strncmp (argv[1], "p", 1) == 0) | |
538 | type = AS_FILTER_PERMIT; | |
539 | else if (strncmp (argv[1], "d", 1) == 0) | |
540 | type = AS_FILTER_DENY; | |
541 | else | |
542 | { | |
543 | vty_out (vty, "filter type must be [permit|deny]%s", VTY_NEWLINE); | |
544 | return CMD_WARNING; | |
545 | } | |
546 | ||
547 | /* Compile AS path. */ | |
548 | b = buffer_new (1024); | |
549 | for (i = 2; i < argc; i++) | |
550 | { | |
551 | if (first) | |
552 | buffer_putc (b, ' '); | |
553 | else | |
554 | first = 1; | |
555 | ||
556 | buffer_putstr (b, argv[i]); | |
557 | } | |
558 | buffer_putc (b, '\0'); | |
559 | ||
560 | regstr = buffer_getstr (b); | |
561 | buffer_free (b); | |
562 | ||
563 | regex = bgp_regcomp (regstr); | |
564 | if (!regex) | |
565 | { | |
566 | free (regstr); | |
567 | vty_out (vty, "can't compile regexp %s%s", argv[0], | |
568 | VTY_NEWLINE); | |
569 | return CMD_WARNING; | |
570 | } | |
571 | ||
572 | /* Lookup asfilter. */ | |
573 | asfilter = as_filter_lookup (aslist, regstr, type); | |
574 | ||
575 | free (regstr); | |
576 | bgp_regex_free (regex); | |
577 | ||
578 | if (asfilter == NULL) | |
579 | { | |
580 | vty_out (vty, "%s", VTY_NEWLINE); | |
581 | return CMD_WARNING; | |
582 | } | |
583 | ||
584 | as_list_filter_delete (aslist, asfilter); | |
585 | ||
586 | return CMD_SUCCESS; | |
587 | } | |
588 | ||
589 | DEFUN (no_ip_as_path_all, | |
590 | no_ip_as_path_all_cmd, | |
591 | "no ip as-path access-list WORD", | |
592 | NO_STR | |
593 | IP_STR | |
594 | "BGP autonomous system path filter\n" | |
595 | "Specify an access list name\n" | |
596 | "Regular expression access list name\n") | |
597 | { | |
598 | struct as_list *aslist; | |
599 | ||
600 | aslist = as_list_lookup (argv[0]); | |
601 | if (aslist == NULL) | |
602 | { | |
603 | vty_out (vty, "ip as-path access-list %s doesn't exist%s", argv[0], | |
604 | VTY_NEWLINE); | |
605 | return CMD_WARNING; | |
606 | } | |
607 | ||
608 | as_list_delete (aslist); | |
609 | ||
e0701b79 | 610 | /* Run hook function. */ |
611 | if (as_list_master.delete_hook) | |
612 | (*as_list_master.delete_hook) (); | |
613 | ||
718e3744 | 614 | return CMD_SUCCESS; |
615 | } | |
616 | ||
4f991ef0 | 617 | void |
618 | as_list_show (struct vty *vty, struct as_list *aslist) | |
619 | { | |
620 | struct as_filter *asfilter; | |
621 | ||
622 | vty_out (vty, "AS path access list %s%s", aslist->name, VTY_NEWLINE); | |
623 | ||
624 | for (asfilter = aslist->head; asfilter; asfilter = asfilter->next) | |
625 | { | |
626 | vty_out (vty, " %s %s%s", filter_type_str (asfilter->type), | |
627 | asfilter->reg_str, VTY_NEWLINE); | |
628 | } | |
629 | } | |
630 | ||
631 | void | |
632 | as_list_show_all (struct vty *vty) | |
633 | { | |
634 | struct as_list *aslist; | |
635 | struct as_filter *asfilter; | |
636 | ||
637 | for (aslist = as_list_master.num.head; aslist; aslist = aslist->next) | |
638 | { | |
639 | vty_out (vty, "AS path access list %s%s", aslist->name, VTY_NEWLINE); | |
640 | ||
641 | for (asfilter = aslist->head; asfilter; asfilter = asfilter->next) | |
642 | { | |
643 | vty_out (vty, " %s %s%s", filter_type_str (asfilter->type), | |
644 | asfilter->reg_str, VTY_NEWLINE); | |
645 | } | |
646 | } | |
647 | ||
648 | for (aslist = as_list_master.str.head; aslist; aslist = aslist->next) | |
649 | { | |
650 | vty_out (vty, "AS path access list %s%s", aslist->name, VTY_NEWLINE); | |
651 | ||
652 | for (asfilter = aslist->head; asfilter; asfilter = asfilter->next) | |
653 | { | |
654 | vty_out (vty, " %s %s%s", filter_type_str (asfilter->type), | |
655 | asfilter->reg_str, VTY_NEWLINE); | |
656 | } | |
657 | } | |
658 | } | |
659 | ||
660 | DEFUN (show_ip_as_path_access_list, | |
661 | show_ip_as_path_access_list_cmd, | |
662 | "show ip as-path-access-list WORD", | |
663 | SHOW_STR | |
664 | IP_STR | |
665 | "List AS path access lists\n" | |
666 | "AS path access list name\n") | |
667 | { | |
668 | struct as_list *aslist; | |
669 | ||
670 | aslist = as_list_lookup (argv[0]); | |
671 | if (aslist) | |
672 | as_list_show (vty, aslist); | |
673 | ||
674 | return CMD_SUCCESS; | |
675 | } | |
676 | ||
677 | DEFUN (show_ip_as_path_access_list_all, | |
678 | show_ip_as_path_access_list_all_cmd, | |
679 | "show ip as-path-access-list", | |
680 | SHOW_STR | |
681 | IP_STR | |
682 | "List AS path access lists\n") | |
683 | { | |
684 | as_list_show_all (vty); | |
685 | return CMD_SUCCESS; | |
686 | } | |
687 | ||
718e3744 | 688 | int |
689 | config_write_as_list (struct vty *vty) | |
690 | { | |
691 | struct as_list *aslist; | |
692 | struct as_filter *asfilter; | |
693 | int write = 0; | |
694 | ||
695 | for (aslist = as_list_master.num.head; aslist; aslist = aslist->next) | |
696 | for (asfilter = aslist->head; asfilter; asfilter = asfilter->next) | |
697 | { | |
698 | vty_out (vty, "ip as-path access-list %s %s %s%s", | |
699 | aslist->name, filter_type_str (asfilter->type), | |
700 | asfilter->reg_str, | |
701 | VTY_NEWLINE); | |
702 | write++; | |
703 | } | |
704 | ||
705 | for (aslist = as_list_master.str.head; aslist; aslist = aslist->next) | |
706 | for (asfilter = aslist->head; asfilter; asfilter = asfilter->next) | |
707 | { | |
708 | vty_out (vty, "ip as-path access-list %s %s %s%s", | |
709 | aslist->name, filter_type_str (asfilter->type), | |
710 | asfilter->reg_str, | |
711 | VTY_NEWLINE); | |
712 | write++; | |
713 | } | |
714 | return write; | |
715 | } | |
716 | ||
717 | struct cmd_node as_list_node = | |
718 | { | |
719 | AS_LIST_NODE, | |
720 | "", | |
721 | 1 | |
722 | }; | |
723 | ||
724 | /* Register functions. */ | |
725 | void | |
726 | bgp_filter_init () | |
727 | { | |
728 | install_node (&as_list_node, config_write_as_list); | |
729 | ||
730 | install_element (CONFIG_NODE, &ip_as_path_cmd); | |
731 | install_element (CONFIG_NODE, &no_ip_as_path_cmd); | |
732 | install_element (CONFIG_NODE, &no_ip_as_path_all_cmd); | |
4f991ef0 | 733 | |
734 | install_element (VIEW_NODE, &show_ip_as_path_access_list_cmd); | |
735 | install_element (VIEW_NODE, &show_ip_as_path_access_list_all_cmd); | |
736 | install_element (ENABLE_NODE, &show_ip_as_path_access_list_cmd); | |
737 | install_element (ENABLE_NODE, &show_ip_as_path_access_list_all_cmd); | |
718e3744 | 738 | } |