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