bgp_filter.c 16 KB

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