bgp_filter.c 16 KB

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