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