]>
Commit | Line | Data |
---|---|---|
718e3744 | 1 | /* AS path filter list. |
896014f4 DL |
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 along | |
17 | * with this program; see the file COPYING; if not, write to the Free Software | |
18 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | |
19 | */ | |
718e3744 | 20 | |
21 | #include <zebra.h> | |
22 | ||
23 | #include "command.h" | |
24 | #include "log.h" | |
25 | #include "memory.h" | |
26 | #include "buffer.h" | |
3f9c7369 | 27 | #include "queue.h" |
039f3a34 | 28 | #include "filter.h" |
718e3744 | 29 | |
30 | #include "bgpd/bgpd.h" | |
31 | #include "bgpd/bgp_aspath.h" | |
32 | #include "bgpd/bgp_regex.h" | |
33 | #include "bgpd/bgp_filter.h" | |
34 | ||
35 | /* List of AS filter list. */ | |
d62a17ae | 36 | struct as_list_list { |
37 | struct as_list *head; | |
38 | struct as_list *tail; | |
718e3744 | 39 | }; |
40 | ||
41 | /* AS path filter master. */ | |
d62a17ae | 42 | struct as_list_master { |
d62a17ae | 43 | /* List of access_list which name is string. */ |
44 | struct as_list_list str; | |
718e3744 | 45 | |
d62a17ae | 46 | /* Hook function which is executed when new access_list is added. */ |
47 | void (*add_hook)(char *); | |
718e3744 | 48 | |
d62a17ae | 49 | /* Hook function which is executed when access_list is deleted. */ |
50 | void (*delete_hook)(const char *); | |
718e3744 | 51 | }; |
52 | ||
53 | /* Element of AS path filter. */ | |
d62a17ae | 54 | struct as_filter { |
55 | struct as_filter *next; | |
56 | struct as_filter *prev; | |
718e3744 | 57 | |
d62a17ae | 58 | enum as_filter_type type; |
718e3744 | 59 | |
d62a17ae | 60 | regex_t *reg; |
61 | char *reg_str; | |
9b6f73ee CS |
62 | |
63 | /* Sequence number. */ | |
64 | int64_t seq; | |
718e3744 | 65 | }; |
66 | ||
718e3744 | 67 | /* AS path filter list. */ |
d62a17ae | 68 | struct as_list { |
69 | char *name; | |
718e3744 | 70 | |
d62a17ae | 71 | struct as_list *next; |
72 | struct as_list *prev; | |
718e3744 | 73 | |
d62a17ae | 74 | struct as_filter *head; |
75 | struct as_filter *tail; | |
718e3744 | 76 | }; |
6b0655a2 | 77 | |
9b6f73ee CS |
78 | |
79 | /* Calculate new sequential number. */ | |
80 | static int64_t bgp_alist_new_seq_get(struct as_list *list) | |
81 | { | |
82 | int64_t maxseq; | |
83 | int64_t newseq; | |
84 | struct as_filter *entry; | |
85 | ||
86 | maxseq = 0; | |
87 | ||
88 | for (entry = list->head; entry; entry = entry->next) { | |
89 | if (maxseq < entry->seq) | |
90 | maxseq = entry->seq; | |
91 | } | |
92 | ||
93 | newseq = ((maxseq / 5) * 5) + 5; | |
94 | ||
95 | return (newseq > UINT_MAX) ? UINT_MAX : newseq; | |
96 | } | |
97 | ||
98 | /* Return as-list entry which has same seq number. */ | |
99 | static struct as_filter *bgp_aslist_seq_check(struct as_list *list, int64_t seq) | |
100 | { | |
101 | struct as_filter *entry; | |
102 | ||
103 | for (entry = list->head; entry; entry = entry->next) | |
104 | if (entry->seq == seq) | |
105 | return entry; | |
106 | ||
107 | return NULL; | |
108 | } | |
109 | ||
7336e101 | 110 | /* as-path access-list 10 permit AS1. */ |
718e3744 | 111 | |
d62a17ae | 112 | static struct as_list_master as_list_master = {{NULL, NULL}, |
d62a17ae | 113 | NULL, |
114 | NULL}; | |
718e3744 | 115 | |
116 | /* Allocate new AS filter. */ | |
d62a17ae | 117 | static struct as_filter *as_filter_new(void) |
718e3744 | 118 | { |
d62a17ae | 119 | return XCALLOC(MTYPE_AS_FILTER, sizeof(struct as_filter)); |
718e3744 | 120 | } |
121 | ||
122 | /* Free allocated AS filter. */ | |
d62a17ae | 123 | static void as_filter_free(struct as_filter *asfilter) |
718e3744 | 124 | { |
d62a17ae | 125 | if (asfilter->reg) |
126 | bgp_regex_free(asfilter->reg); | |
0a22ddfb | 127 | XFREE(MTYPE_AS_FILTER_STR, asfilter->reg_str); |
d62a17ae | 128 | XFREE(MTYPE_AS_FILTER, asfilter); |
718e3744 | 129 | } |
130 | ||
131 | /* Make new AS filter. */ | |
d62a17ae | 132 | static struct as_filter *as_filter_make(regex_t *reg, const char *reg_str, |
133 | enum as_filter_type type) | |
718e3744 | 134 | { |
d62a17ae | 135 | struct as_filter *asfilter; |
718e3744 | 136 | |
d62a17ae | 137 | asfilter = as_filter_new(); |
138 | asfilter->reg = reg; | |
139 | asfilter->type = type; | |
140 | asfilter->reg_str = XSTRDUP(MTYPE_AS_FILTER_STR, reg_str); | |
718e3744 | 141 | |
d62a17ae | 142 | return asfilter; |
718e3744 | 143 | } |
144 | ||
d62a17ae | 145 | static struct as_filter *as_filter_lookup(struct as_list *aslist, |
146 | const char *reg_str, | |
147 | enum as_filter_type type) | |
718e3744 | 148 | { |
d62a17ae | 149 | struct as_filter *asfilter; |
718e3744 | 150 | |
d62a17ae | 151 | for (asfilter = aslist->head; asfilter; asfilter = asfilter->next) |
152 | if (strcmp(reg_str, asfilter->reg_str) == 0) | |
153 | return asfilter; | |
154 | return NULL; | |
718e3744 | 155 | } |
156 | ||
9b6f73ee CS |
157 | static void as_filter_entry_replace(struct as_list *list, |
158 | struct as_filter *replace, | |
159 | struct as_filter *entry) | |
160 | { | |
161 | if (replace->next) { | |
162 | entry->next = replace->next; | |
163 | replace->next->prev = entry; | |
164 | } else { | |
165 | entry->next = NULL; | |
166 | list->tail = entry; | |
167 | } | |
168 | ||
169 | if (replace->prev) { | |
170 | entry->prev = replace->prev; | |
171 | replace->prev->next = entry; | |
172 | } else { | |
173 | entry->prev = NULL; | |
174 | list->head = entry; | |
175 | } | |
176 | ||
177 | as_filter_free(replace); | |
178 | } | |
179 | ||
d62a17ae | 180 | static void as_list_filter_add(struct as_list *aslist, |
181 | struct as_filter *asfilter) | |
718e3744 | 182 | { |
9b6f73ee CS |
183 | struct as_filter *point; |
184 | struct as_filter *replace; | |
718e3744 | 185 | |
9b6f73ee CS |
186 | if (aslist->tail && asfilter->seq > aslist->tail->seq) |
187 | point = NULL; | |
188 | else { | |
189 | replace = bgp_aslist_seq_check(aslist, asfilter->seq); | |
190 | if (replace) { | |
191 | as_filter_entry_replace(aslist, replace, asfilter); | |
f709b31b | 192 | goto hook; |
9b6f73ee CS |
193 | } |
194 | ||
195 | /* Check insert point. */ | |
196 | for (point = aslist->head; point; point = point->next) | |
197 | if (point->seq >= asfilter->seq) | |
198 | break; | |
199 | } | |
200 | ||
201 | asfilter->next = point; | |
202 | ||
203 | if (point) { | |
204 | if (point->prev) | |
205 | point->prev->next = asfilter; | |
206 | else | |
207 | aslist->head = asfilter; | |
208 | ||
209 | asfilter->prev = point->prev; | |
210 | point->prev = asfilter; | |
211 | } else { | |
212 | if (aslist->tail) | |
213 | aslist->tail->next = asfilter; | |
214 | else | |
215 | aslist->head = asfilter; | |
216 | ||
217 | asfilter->prev = aslist->tail; | |
218 | aslist->tail = asfilter; | |
219 | } | |
518f0eb1 | 220 | |
f709b31b | 221 | hook: |
d62a17ae | 222 | /* Run hook function. */ |
223 | if (as_list_master.add_hook) | |
224 | (*as_list_master.add_hook)(aslist->name); | |
718e3744 | 225 | } |
226 | ||
227 | /* Lookup as_list from list of as_list by name. */ | |
d62a17ae | 228 | struct as_list *as_list_lookup(const char *name) |
718e3744 | 229 | { |
d62a17ae | 230 | struct as_list *aslist; |
718e3744 | 231 | |
d62a17ae | 232 | if (name == NULL) |
233 | return NULL; | |
718e3744 | 234 | |
d62a17ae | 235 | for (aslist = as_list_master.str.head; aslist; aslist = aslist->next) |
236 | if (strcmp(aslist->name, name) == 0) | |
237 | return aslist; | |
718e3744 | 238 | |
d62a17ae | 239 | return NULL; |
718e3744 | 240 | } |
241 | ||
d62a17ae | 242 | static struct as_list *as_list_new(void) |
718e3744 | 243 | { |
d62a17ae | 244 | return XCALLOC(MTYPE_AS_LIST, sizeof(struct as_list)); |
718e3744 | 245 | } |
246 | ||
d62a17ae | 247 | static void as_list_free(struct as_list *aslist) |
718e3744 | 248 | { |
e1b36e13 | 249 | XFREE(MTYPE_AS_STR, aslist->name); |
d62a17ae | 250 | XFREE(MTYPE_AS_LIST, aslist); |
718e3744 | 251 | } |
252 | ||
253 | /* Insert new AS list to list of as_list. Each as_list is sorted by | |
254 | the name. */ | |
d62a17ae | 255 | static struct as_list *as_list_insert(const char *name) |
256 | { | |
d62a17ae | 257 | struct as_list *aslist; |
258 | struct as_list *point; | |
259 | struct as_list_list *list; | |
260 | ||
261 | /* Allocate new access_list and copy given name. */ | |
262 | aslist = as_list_new(); | |
263 | aslist->name = XSTRDUP(MTYPE_AS_STR, name); | |
264 | assert(aslist->name); | |
265 | ||
3eff8e2f IR |
266 | /* Set access_list to string list. */ |
267 | list = &as_list_master.str; | |
d62a17ae | 268 | |
3eff8e2f IR |
269 | /* Set point to insertion point. */ |
270 | for (point = list->head; point; point = point->next) | |
271 | if (strcmp(point->name, name) >= 0) | |
272 | break; | |
d62a17ae | 273 | |
274 | /* In case of this is the first element of master. */ | |
275 | if (list->head == NULL) { | |
276 | list->head = list->tail = aslist; | |
277 | return aslist; | |
278 | } | |
279 | ||
280 | /* In case of insertion is made at the tail of access_list. */ | |
281 | if (point == NULL) { | |
282 | aslist->prev = list->tail; | |
283 | list->tail->next = aslist; | |
284 | list->tail = aslist; | |
285 | return aslist; | |
286 | } | |
287 | ||
288 | /* In case of insertion is made at the head of access_list. */ | |
289 | if (point == list->head) { | |
290 | aslist->next = list->head; | |
291 | list->head->prev = aslist; | |
292 | list->head = aslist; | |
293 | return aslist; | |
294 | } | |
295 | ||
296 | /* Insertion is made at middle of the access_list. */ | |
297 | aslist->next = point; | |
298 | aslist->prev = point->prev; | |
299 | ||
300 | if (point->prev) | |
301 | point->prev->next = aslist; | |
302 | point->prev = aslist; | |
303 | ||
304 | return aslist; | |
718e3744 | 305 | } |
306 | ||
d62a17ae | 307 | static struct as_list *as_list_get(const char *name) |
718e3744 | 308 | { |
d62a17ae | 309 | struct as_list *aslist; |
718e3744 | 310 | |
d62a17ae | 311 | aslist = as_list_lookup(name); |
312 | if (aslist == NULL) | |
313 | aslist = as_list_insert(name); | |
718e3744 | 314 | |
d62a17ae | 315 | return aslist; |
718e3744 | 316 | } |
317 | ||
d62a17ae | 318 | static const char *filter_type_str(enum as_filter_type type) |
718e3744 | 319 | { |
d62a17ae | 320 | switch (type) { |
321 | case AS_FILTER_PERMIT: | |
322 | return "permit"; | |
323 | case AS_FILTER_DENY: | |
324 | return "deny"; | |
325 | default: | |
326 | return ""; | |
327 | } | |
718e3744 | 328 | } |
329 | ||
d62a17ae | 330 | static void as_list_delete(struct as_list *aslist) |
718e3744 | 331 | { |
d62a17ae | 332 | struct as_list_list *list; |
333 | struct as_filter *filter, *next; | |
334 | ||
335 | for (filter = aslist->head; filter; filter = next) { | |
336 | next = filter->next; | |
337 | as_filter_free(filter); | |
338 | } | |
339 | ||
3eff8e2f | 340 | list = &as_list_master.str; |
d62a17ae | 341 | |
342 | if (aslist->next) | |
343 | aslist->next->prev = aslist->prev; | |
344 | else | |
345 | list->tail = aslist->prev; | |
346 | ||
347 | if (aslist->prev) | |
348 | aslist->prev->next = aslist->next; | |
349 | else | |
350 | list->head = aslist->next; | |
351 | ||
352 | as_list_free(aslist); | |
718e3744 | 353 | } |
354 | ||
3dc339cd | 355 | static bool as_list_empty(struct as_list *aslist) |
718e3744 | 356 | { |
3dc339cd | 357 | return aslist->head == NULL && aslist->tail == NULL; |
718e3744 | 358 | } |
359 | ||
d62a17ae | 360 | static void as_list_filter_delete(struct as_list *aslist, |
361 | struct as_filter *asfilter) | |
718e3744 | 362 | { |
d62a17ae | 363 | char *name = XSTRDUP(MTYPE_AS_STR, aslist->name); |
518f0eb1 | 364 | |
d62a17ae | 365 | if (asfilter->next) |
366 | asfilter->next->prev = asfilter->prev; | |
367 | else | |
368 | aslist->tail = asfilter->prev; | |
718e3744 | 369 | |
d62a17ae | 370 | if (asfilter->prev) |
371 | asfilter->prev->next = asfilter->next; | |
372 | else | |
373 | aslist->head = asfilter->next; | |
718e3744 | 374 | |
d62a17ae | 375 | as_filter_free(asfilter); |
718e3744 | 376 | |
d62a17ae | 377 | /* If access_list becomes empty delete it from access_master. */ |
378 | if (as_list_empty(aslist)) | |
379 | as_list_delete(aslist); | |
718e3744 | 380 | |
d62a17ae | 381 | /* Run hook function. */ |
382 | if (as_list_master.delete_hook) | |
383 | (*as_list_master.delete_hook)(name); | |
0a22ddfb | 384 | XFREE(MTYPE_AS_STR, name); |
718e3744 | 385 | } |
6b0655a2 | 386 | |
3dc339cd | 387 | static bool as_filter_match(struct as_filter *asfilter, struct aspath *aspath) |
718e3744 | 388 | { |
3dc339cd | 389 | return bgp_regexec(asfilter->reg, aspath) != REG_NOMATCH; |
718e3744 | 390 | } |
391 | ||
392 | /* Apply AS path filter to AS. */ | |
d62a17ae | 393 | enum as_filter_type as_list_apply(struct as_list *aslist, void *object) |
718e3744 | 394 | { |
d62a17ae | 395 | struct as_filter *asfilter; |
396 | struct aspath *aspath; | |
718e3744 | 397 | |
d62a17ae | 398 | aspath = (struct aspath *)object; |
718e3744 | 399 | |
d62a17ae | 400 | if (aslist == NULL) |
401 | return AS_FILTER_DENY; | |
718e3744 | 402 | |
d62a17ae | 403 | for (asfilter = aslist->head; asfilter; asfilter = asfilter->next) { |
404 | if (as_filter_match(asfilter, aspath)) | |
405 | return asfilter->type; | |
406 | } | |
407 | return AS_FILTER_DENY; | |
718e3744 | 408 | } |
409 | ||
410 | /* Add hook function. */ | |
d62a17ae | 411 | void as_list_add_hook(void (*func)(char *)) |
718e3744 | 412 | { |
d62a17ae | 413 | as_list_master.add_hook = func; |
718e3744 | 414 | } |
415 | ||
416 | /* Delete hook function. */ | |
d62a17ae | 417 | void as_list_delete_hook(void (*func)(const char *)) |
718e3744 | 418 | { |
d62a17ae | 419 | as_list_master.delete_hook = func; |
718e3744 | 420 | } |
6b0655a2 | 421 | |
3dc339cd | 422 | static bool as_list_dup_check(struct as_list *aslist, struct as_filter *new) |
718e3744 | 423 | { |
d62a17ae | 424 | struct as_filter *asfilter; |
425 | ||
426 | for (asfilter = aslist->head; asfilter; asfilter = asfilter->next) { | |
427 | if (asfilter->type == new->type | |
428 | && strcmp(asfilter->reg_str, new->reg_str) == 0) | |
3dc339cd | 429 | return true; |
d62a17ae | 430 | } |
3dc339cd | 431 | return false; |
718e3744 | 432 | } |
433 | ||
3dc339cd | 434 | bool config_bgp_aspath_validate(const char *regstr) |
672c2d75 | 435 | { |
da6035e9 | 436 | char valid_chars[] = "1234567890_^|[,{}() ]$*+.?-\\"; |
672c2d75 DA |
437 | |
438 | if (strspn(regstr, valid_chars) == strlen(regstr)) | |
3dc339cd DA |
439 | return true; |
440 | return false; | |
672c2d75 DA |
441 | } |
442 | ||
7336e101 | 443 | DEFUN(as_path, bgp_as_path_cmd, |
2a342b35 | 444 | "bgp as-path access-list AS_PATH_FILTER_NAME [seq (0-4294967295)] <deny|permit> LINE...", |
7336e101 | 445 | BGP_STR |
672c2d75 DA |
446 | "BGP autonomous system path filter\n" |
447 | "Specify an access list name\n" | |
448 | "Regular expression access list name\n" | |
9b6f73ee CS |
449 | "Sequence number of an entry\n" |
450 | "Sequence number\n" | |
672c2d75 DA |
451 | "Specify packets to reject\n" |
452 | "Specify packets to forward\n" | |
a818ea74 | 453 | "A regular-expression (1234567890_^|[,{}() ]$*+.?-\\) to match the BGP AS paths\n") |
718e3744 | 454 | { |
d62a17ae | 455 | int idx = 0; |
456 | enum as_filter_type type; | |
457 | struct as_filter *asfilter; | |
458 | struct as_list *aslist; | |
459 | regex_t *regex; | |
460 | char *regstr; | |
9b6f73ee | 461 | int64_t seqnum = ASPATH_SEQ_NUMBER_AUTO; |
d62a17ae | 462 | |
463 | /* Retrieve access list name */ | |
2a342b35 | 464 | argv_find(argv, argc, "AS_PATH_FILTER_NAME", &idx); |
e991f75c | 465 | char *alname = argv[idx]->arg; |
d62a17ae | 466 | |
9b6f73ee CS |
467 | if (argv_find(argv, argc, "(0-4294967295)", &idx)) |
468 | seqnum = (int64_t)atol(argv[idx]->arg); | |
469 | ||
d62a17ae | 470 | /* Check the filter type. */ |
471 | type = argv_find(argv, argc, "deny", &idx) ? AS_FILTER_DENY | |
472 | : AS_FILTER_PERMIT; | |
473 | ||
474 | /* Check AS path regex. */ | |
475 | argv_find(argv, argc, "LINE", &idx); | |
476 | regstr = argv_concat(argv, argc, idx); | |
477 | ||
478 | regex = bgp_regcomp(regstr); | |
479 | if (!regex) { | |
480 | vty_out(vty, "can't compile regexp %s\n", regstr); | |
481 | XFREE(MTYPE_TMP, regstr); | |
482 | return CMD_WARNING_CONFIG_FAILED; | |
483 | } | |
484 | ||
672c2d75 DA |
485 | if (!config_bgp_aspath_validate(regstr)) { |
486 | vty_out(vty, "Invalid character in as-path access-list %s\n", | |
487 | regstr); | |
e88307cf | 488 | XFREE(MTYPE_TMP, regstr); |
672c2d75 DA |
489 | return CMD_WARNING_CONFIG_FAILED; |
490 | } | |
491 | ||
d62a17ae | 492 | asfilter = as_filter_make(regex, regstr, type); |
493 | ||
494 | XFREE(MTYPE_TMP, regstr); | |
495 | ||
496 | /* Install new filter to the access_list. */ | |
497 | aslist = as_list_get(alname); | |
498 | ||
9b6f73ee CS |
499 | if (seqnum == ASPATH_SEQ_NUMBER_AUTO) |
500 | seqnum = bgp_alist_new_seq_get(aslist); | |
501 | ||
502 | asfilter->seq = seqnum; | |
503 | ||
d62a17ae | 504 | /* Duplicate insertion check. */; |
505 | if (as_list_dup_check(aslist, asfilter)) | |
506 | as_filter_free(asfilter); | |
507 | else | |
508 | as_list_filter_add(aslist, asfilter); | |
509 | ||
510 | return CMD_SUCCESS; | |
718e3744 | 511 | } |
512 | ||
7336e101 | 513 | DEFUN(no_as_path, no_bgp_as_path_cmd, |
2a342b35 | 514 | "no bgp as-path access-list AS_PATH_FILTER_NAME [seq (0-4294967295)] <deny|permit> LINE...", |
7336e101 SP |
515 | NO_STR |
516 | BGP_STR | |
672c2d75 DA |
517 | "BGP autonomous system path filter\n" |
518 | "Specify an access list name\n" | |
519 | "Regular expression access list name\n" | |
9b6f73ee CS |
520 | "Sequence number of an entry\n" |
521 | "Sequence number\n" | |
672c2d75 DA |
522 | "Specify packets to reject\n" |
523 | "Specify packets to forward\n" | |
a818ea74 | 524 | "A regular-expression (1234567890_^|[,{}() ]$*+.?-\\) to match the BGP AS paths\n") |
718e3744 | 525 | { |
d62a17ae | 526 | int idx = 0; |
527 | enum as_filter_type type; | |
528 | struct as_filter *asfilter; | |
529 | struct as_list *aslist; | |
530 | char *regstr; | |
531 | regex_t *regex; | |
532 | ||
533 | char *aslistname = | |
2a342b35 | 534 | argv_find(argv, argc, "AS_PATH_FILTER_NAME", &idx) ? argv[idx]->arg : NULL; |
d62a17ae | 535 | |
536 | /* Lookup AS list from AS path list. */ | |
537 | aslist = as_list_lookup(aslistname); | |
538 | if (aslist == NULL) { | |
7336e101 | 539 | vty_out(vty, "bgp as-path access-list %s doesn't exist\n", |
d62a17ae | 540 | aslistname); |
541 | return CMD_WARNING_CONFIG_FAILED; | |
542 | } | |
543 | ||
544 | /* Check the filter type. */ | |
545 | if (argv_find(argv, argc, "permit", &idx)) | |
546 | type = AS_FILTER_PERMIT; | |
547 | else if (argv_find(argv, argc, "deny", &idx)) | |
548 | type = AS_FILTER_DENY; | |
549 | else { | |
550 | vty_out(vty, "filter type must be [permit|deny]\n"); | |
551 | return CMD_WARNING_CONFIG_FAILED; | |
552 | } | |
553 | ||
554 | /* Compile AS path. */ | |
555 | argv_find(argv, argc, "LINE", &idx); | |
556 | regstr = argv_concat(argv, argc, idx); | |
557 | ||
672c2d75 DA |
558 | if (!config_bgp_aspath_validate(regstr)) { |
559 | vty_out(vty, "Invalid character in as-path access-list %s\n", | |
560 | regstr); | |
561 | return CMD_WARNING_CONFIG_FAILED; | |
562 | } | |
563 | ||
d62a17ae | 564 | regex = bgp_regcomp(regstr); |
565 | if (!regex) { | |
566 | vty_out(vty, "can't compile regexp %s\n", regstr); | |
567 | XFREE(MTYPE_TMP, regstr); | |
568 | return CMD_WARNING_CONFIG_FAILED; | |
569 | } | |
570 | ||
571 | /* Lookup asfilter. */ | |
572 | asfilter = as_filter_lookup(aslist, regstr, type); | |
573 | ||
d62a17ae | 574 | bgp_regex_free(regex); |
575 | ||
576 | if (asfilter == NULL) { | |
17b4e8c4 IR |
577 | vty_out(vty, "Regex entered %s does not exist\n", regstr); |
578 | XFREE(MTYPE_TMP, regstr); | |
d62a17ae | 579 | return CMD_WARNING_CONFIG_FAILED; |
580 | } | |
581 | ||
17b4e8c4 IR |
582 | XFREE(MTYPE_TMP, regstr); |
583 | ||
d62a17ae | 584 | as_list_filter_delete(aslist, asfilter); |
585 | ||
586 | return CMD_SUCCESS; | |
718e3744 | 587 | } |
588 | ||
7336e101 SP |
589 | DEFUN (no_as_path_all, |
590 | no_bgp_as_path_all_cmd, | |
2a342b35 | 591 | "no bgp as-path access-list AS_PATH_FILTER_NAME", |
718e3744 | 592 | NO_STR |
7336e101 | 593 | BGP_STR |
718e3744 | 594 | "BGP autonomous system path filter\n" |
595 | "Specify an access list name\n" | |
596 | "Regular expression access list name\n") | |
597 | { | |
d62a17ae | 598 | int idx_word = 4; |
599 | struct as_list *aslist; | |
718e3744 | 600 | |
d62a17ae | 601 | aslist = as_list_lookup(argv[idx_word]->arg); |
602 | if (aslist == NULL) { | |
7336e101 | 603 | vty_out(vty, "bgp as-path access-list %s doesn't exist\n", |
d62a17ae | 604 | argv[idx_word]->arg); |
605 | return CMD_WARNING_CONFIG_FAILED; | |
606 | } | |
718e3744 | 607 | |
d62a17ae | 608 | as_list_delete(aslist); |
718e3744 | 609 | |
d62a17ae | 610 | /* Run hook function. */ |
611 | if (as_list_master.delete_hook) | |
612 | (*as_list_master.delete_hook)(argv[idx_word]->arg); | |
e0701b79 | 613 | |
d62a17ae | 614 | return CMD_SUCCESS; |
718e3744 | 615 | } |
616 | ||
b15e8360 RW |
617 | static void as_list_show(struct vty *vty, struct as_list *aslist, |
618 | json_object *json) | |
4f991ef0 | 619 | { |
d62a17ae | 620 | struct as_filter *asfilter; |
b15e8360 | 621 | json_object *json_aslist = NULL; |
4f991ef0 | 622 | |
b15e8360 RW |
623 | if (json) { |
624 | json_aslist = json_object_new_array(); | |
625 | json_object_object_add(json, aslist->name, json_aslist); | |
626 | } else | |
627 | vty_out(vty, "AS path access list %s\n", aslist->name); | |
4f991ef0 | 628 | |
d62a17ae | 629 | for (asfilter = aslist->head; asfilter; asfilter = asfilter->next) { |
b15e8360 RW |
630 | if (json) { |
631 | json_object *json_asfilter = json_object_new_object(); | |
632 | ||
633 | json_object_int_add(json_asfilter, "sequenceNumber", | |
634 | asfilter->seq); | |
635 | json_object_string_add(json_asfilter, "type", | |
636 | filter_type_str(asfilter->type)); | |
637 | json_object_string_add(json_asfilter, "regExp", | |
638 | asfilter->reg_str); | |
639 | ||
640 | json_object_array_add(json_aslist, json_asfilter); | |
641 | } else | |
642 | vty_out(vty, " %s %s\n", | |
643 | filter_type_str(asfilter->type), | |
644 | asfilter->reg_str); | |
d62a17ae | 645 | } |
4f991ef0 | 646 | } |
647 | ||
b15e8360 | 648 | static void as_list_show_all(struct vty *vty, json_object *json) |
4f991ef0 | 649 | { |
d62a17ae | 650 | struct as_list *aslist; |
4f991ef0 | 651 | |
b15e8360 RW |
652 | for (aslist = as_list_master.str.head; aslist; aslist = aslist->next) |
653 | as_list_show(vty, aslist, json); | |
4f991ef0 | 654 | } |
655 | ||
7336e101 SP |
656 | DEFUN (show_as_path_access_list, |
657 | show_bgp_as_path_access_list_cmd, | |
2a342b35 | 658 | "show bgp as-path-access-list AS_PATH_FILTER_NAME [json]", |
4f991ef0 | 659 | SHOW_STR |
7336e101 | 660 | BGP_STR |
4f991ef0 | 661 | "List AS path access lists\n" |
b15e8360 RW |
662 | "AS path access list name\n" |
663 | JSON_STR) | |
4f991ef0 | 664 | { |
d62a17ae | 665 | int idx_word = 3; |
666 | struct as_list *aslist; | |
b15e8360 RW |
667 | bool uj = use_json(argc, argv); |
668 | json_object *json = NULL; | |
669 | ||
670 | if (uj) | |
671 | json = json_object_new_object(); | |
4f991ef0 | 672 | |
d62a17ae | 673 | aslist = as_list_lookup(argv[idx_word]->arg); |
674 | if (aslist) | |
b15e8360 RW |
675 | as_list_show(vty, aslist, json); |
676 | ||
c48349e3 | 677 | if (uj) |
75eeda93 | 678 | vty_json(vty, json); |
4f991ef0 | 679 | |
d62a17ae | 680 | return CMD_SUCCESS; |
4f991ef0 | 681 | } |
682 | ||
7336e101 SP |
683 | ALIAS (show_as_path_access_list, |
684 | show_ip_as_path_access_list_cmd, | |
2a342b35 | 685 | "show ip as-path-access-list AS_PATH_FILTER_NAME [json]", |
4f991ef0 | 686 | SHOW_STR |
687 | IP_STR | |
7336e101 | 688 | "List AS path access lists\n" |
b15e8360 RW |
689 | "AS path access list name\n" |
690 | JSON_STR) | |
7336e101 SP |
691 | |
692 | DEFUN (show_as_path_access_list_all, | |
693 | show_bgp_as_path_access_list_all_cmd, | |
b15e8360 | 694 | "show bgp as-path-access-list [json]", |
7336e101 SP |
695 | SHOW_STR |
696 | BGP_STR | |
b15e8360 RW |
697 | "List AS path access lists\n" |
698 | JSON_STR) | |
4f991ef0 | 699 | { |
b15e8360 RW |
700 | bool uj = use_json(argc, argv); |
701 | json_object *json = NULL; | |
702 | ||
703 | if (uj) | |
704 | json = json_object_new_object(); | |
705 | ||
706 | as_list_show_all(vty, json); | |
707 | ||
c48349e3 | 708 | if (uj) |
75eeda93 | 709 | vty_json(vty, json); |
b15e8360 | 710 | |
d62a17ae | 711 | return CMD_SUCCESS; |
4f991ef0 | 712 | } |
713 | ||
7336e101 SP |
714 | ALIAS (show_as_path_access_list_all, |
715 | show_ip_as_path_access_list_all_cmd, | |
b15e8360 | 716 | "show ip as-path-access-list [json]", |
7336e101 SP |
717 | SHOW_STR |
718 | IP_STR | |
b15e8360 RW |
719 | "List AS path access lists\n" |
720 | JSON_STR) | |
7336e101 | 721 | |
d62a17ae | 722 | static int config_write_as_list(struct vty *vty) |
723 | { | |
724 | struct as_list *aslist; | |
725 | struct as_filter *asfilter; | |
726 | int write = 0; | |
727 | ||
d62a17ae | 728 | for (aslist = as_list_master.str.head; aslist; aslist = aslist->next) |
729 | for (asfilter = aslist->head; asfilter; | |
730 | asfilter = asfilter->next) { | |
9b6f73ee CS |
731 | vty_out(vty, |
732 | "bgp as-path access-list %s seq %" PRId64 | |
733 | " %s %s\n", | |
734 | aslist->name, asfilter->seq, | |
735 | filter_type_str(asfilter->type), | |
d62a17ae | 736 | asfilter->reg_str); |
737 | write++; | |
738 | } | |
739 | return write; | |
718e3744 | 740 | } |
741 | ||
612c2c15 | 742 | static int config_write_as_list(struct vty *vty); |
62b346ee | 743 | static struct cmd_node as_list_node = { |
f4b8291f | 744 | .name = "as list", |
62b346ee DL |
745 | .node = AS_LIST_NODE, |
746 | .prompt = "", | |
612c2c15 | 747 | .config_write = config_write_as_list, |
62b346ee | 748 | }; |
718e3744 | 749 | |
2a342b35 DA |
750 | static void bgp_aspath_filter_cmd_completion(vector comps, |
751 | struct cmd_token *token) | |
752 | { | |
753 | struct as_list *aslist; | |
754 | ||
755 | for (aslist = as_list_master.str.head; aslist; aslist = aslist->next) | |
756 | vector_set(comps, XSTRDUP(MTYPE_COMPLETION, aslist->name)); | |
757 | } | |
758 | ||
759 | static const struct cmd_variable_handler aspath_filter_handlers[] = { | |
760 | {.tokenname = "AS_PATH_FILTER_NAME", | |
761 | .completions = bgp_aspath_filter_cmd_completion}, | |
762 | {.completions = NULL}}; | |
763 | ||
718e3744 | 764 | /* Register functions. */ |
d62a17ae | 765 | void bgp_filter_init(void) |
718e3744 | 766 | { |
612c2c15 | 767 | install_node(&as_list_node); |
718e3744 | 768 | |
7336e101 | 769 | install_element(CONFIG_NODE, &bgp_as_path_cmd); |
7336e101 | 770 | install_element(CONFIG_NODE, &no_bgp_as_path_cmd); |
7336e101 | 771 | install_element(CONFIG_NODE, &no_bgp_as_path_all_cmd); |
4f991ef0 | 772 | |
7336e101 | 773 | install_element(VIEW_NODE, &show_bgp_as_path_access_list_cmd); |
d62a17ae | 774 | install_element(VIEW_NODE, &show_ip_as_path_access_list_cmd); |
7336e101 | 775 | install_element(VIEW_NODE, &show_bgp_as_path_access_list_all_cmd); |
d62a17ae | 776 | install_element(VIEW_NODE, &show_ip_as_path_access_list_all_cmd); |
2a342b35 DA |
777 | |
778 | cmd_variable_handler_register(aspath_filter_handlers); | |
718e3744 | 779 | } |
228da428 | 780 | |
d62a17ae | 781 | void bgp_filter_reset(void) |
228da428 | 782 | { |
d62a17ae | 783 | struct as_list *aslist; |
784 | struct as_list *next; | |
785 | ||
d62a17ae | 786 | for (aslist = as_list_master.str.head; aslist; aslist = next) { |
787 | next = aslist->next; | |
788 | as_list_delete(aslist); | |
789 | } | |
790 | ||
d62a17ae | 791 | assert(as_list_master.str.head == NULL); |
792 | assert(as_list_master.str.tail == NULL); | |
228da428 | 793 | } |