bgp_filter.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706
  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) ();
  40. /* Hook function which is executed when access_list is deleted. */
  41. void (*delete_hook) ();
  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 ()
  78. {
  79. struct as_filter *new;
  80. new = XMALLOC (MTYPE_AS_FILTER, sizeof (struct as_filter));
  81. memset (new, 0, sizeof (struct as_filter));
  82. return new;
  83. }
  84. /* Free allocated AS filter. */
  85. static void
  86. as_filter_free (struct as_filter *asfilter)
  87. {
  88. if (asfilter->reg)
  89. bgp_regex_free (asfilter->reg);
  90. if (asfilter->reg_str)
  91. XFREE (MTYPE_AS_FILTER_STR, asfilter->reg_str);
  92. XFREE (MTYPE_AS_FILTER, asfilter);
  93. }
  94. /* Make new AS filter. */
  95. static struct as_filter *
  96. as_filter_make (regex_t *reg, const char *reg_str, enum as_filter_type type)
  97. {
  98. struct as_filter *asfilter;
  99. asfilter = as_filter_new ();
  100. asfilter->reg = reg;
  101. asfilter->type = type;
  102. asfilter->reg_str = XSTRDUP (MTYPE_AS_FILTER_STR, reg_str);
  103. return asfilter;
  104. }
  105. static struct as_filter *
  106. as_filter_lookup (struct as_list *aslist, const char *reg_str,
  107. enum as_filter_type type)
  108. {
  109. struct as_filter *asfilter;
  110. for (asfilter = aslist->head; asfilter; asfilter = asfilter->next)
  111. if (strcmp (reg_str, asfilter->reg_str) == 0)
  112. return asfilter;
  113. return NULL;
  114. }
  115. static void
  116. as_list_filter_add (struct as_list *aslist, struct as_filter *asfilter)
  117. {
  118. asfilter->next = NULL;
  119. asfilter->prev = aslist->tail;
  120. if (aslist->tail)
  121. aslist->tail->next = asfilter;
  122. else
  123. aslist->head = asfilter;
  124. aslist->tail = asfilter;
  125. }
  126. /* Lookup as_list from list of as_list by name. */
  127. struct as_list *
  128. as_list_lookup (const char *name)
  129. {
  130. struct as_list *aslist;
  131. if (name == NULL)
  132. return NULL;
  133. for (aslist = as_list_master.num.head; aslist; aslist = aslist->next)
  134. if (strcmp (aslist->name, name) == 0)
  135. return aslist;
  136. for (aslist = as_list_master.str.head; aslist; aslist = aslist->next)
  137. if (strcmp (aslist->name, name) == 0)
  138. return aslist;
  139. return NULL;
  140. }
  141. static struct as_list *
  142. as_list_new ()
  143. {
  144. struct as_list *new;
  145. new = XMALLOC (MTYPE_AS_LIST, sizeof (struct as_list));
  146. memset (new, 0, sizeof (struct as_list));
  147. return new;
  148. }
  149. static void
  150. as_list_free (struct as_list *aslist)
  151. {
  152. XFREE (MTYPE_AS_LIST, aslist);
  153. }
  154. /* Insert new AS list to list of as_list. Each as_list is sorted by
  155. the name. */
  156. static struct as_list *
  157. as_list_insert (const char *name)
  158. {
  159. size_t i;
  160. long number;
  161. struct as_list *aslist;
  162. struct as_list *point;
  163. struct as_list_list *list;
  164. /* Allocate new access_list and copy given name. */
  165. aslist = as_list_new ();
  166. aslist->name = strdup (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. break;
  248. case AS_FILTER_DENY:
  249. return "deny";
  250. break;
  251. default:
  252. return "";
  253. break;
  254. }
  255. }
  256. static void
  257. as_list_delete (struct as_list *aslist)
  258. {
  259. struct as_list_list *list;
  260. struct as_filter *filter, *next;
  261. for (filter = aslist->head; filter; filter = next)
  262. {
  263. next = filter->next;
  264. as_filter_free (filter);
  265. }
  266. if (aslist->type == ACCESS_TYPE_NUMBER)
  267. list = &as_list_master.num;
  268. else
  269. list = &as_list_master.str;
  270. if (aslist->next)
  271. aslist->next->prev = aslist->prev;
  272. else
  273. list->tail = aslist->prev;
  274. if (aslist->prev)
  275. aslist->prev->next = aslist->next;
  276. else
  277. list->head = aslist->next;
  278. as_list_free (aslist);
  279. }
  280. static int
  281. as_list_empty (struct as_list *aslist)
  282. {
  283. if (aslist->head == NULL && aslist->tail == NULL)
  284. return 1;
  285. else
  286. return 0;
  287. }
  288. static void
  289. as_list_filter_delete (struct as_list *aslist, struct as_filter *asfilter)
  290. {
  291. if (asfilter->next)
  292. asfilter->next->prev = asfilter->prev;
  293. else
  294. aslist->tail = asfilter->prev;
  295. if (asfilter->prev)
  296. asfilter->prev->next = asfilter->next;
  297. else
  298. aslist->head = asfilter->next;
  299. as_filter_free (asfilter);
  300. /* If access_list becomes empty delete it from access_master. */
  301. if (as_list_empty (aslist))
  302. as_list_delete (aslist);
  303. /* Run hook function. */
  304. if (as_list_master.delete_hook)
  305. (*as_list_master.delete_hook) ();
  306. }
  307. static int
  308. as_filter_match (struct as_filter *asfilter, struct aspath *aspath)
  309. {
  310. if (bgp_regexec (asfilter->reg, aspath) != REG_NOMATCH)
  311. return 1;
  312. return 0;
  313. }
  314. /* Apply AS path filter to AS. */
  315. enum as_filter_type
  316. as_list_apply (struct as_list *aslist, void *object)
  317. {
  318. struct as_filter *asfilter;
  319. struct aspath *aspath;
  320. aspath = (struct aspath *) object;
  321. if (aslist == NULL)
  322. return AS_FILTER_DENY;
  323. for (asfilter = aslist->head; asfilter; asfilter = asfilter->next)
  324. {
  325. if (as_filter_match (asfilter, aspath))
  326. return asfilter->type;
  327. }
  328. return AS_FILTER_DENY;
  329. }
  330. /* Add hook function. */
  331. void
  332. as_list_add_hook (void (*func) ())
  333. {
  334. as_list_master.add_hook = func;
  335. }
  336. /* Delete hook function. */
  337. void
  338. as_list_delete_hook (void (*func) ())
  339. {
  340. as_list_master.delete_hook = func;
  341. }
  342. static int
  343. as_list_dup_check (struct as_list *aslist, struct as_filter *new)
  344. {
  345. struct as_filter *asfilter;
  346. for (asfilter = aslist->head; asfilter; asfilter = asfilter->next)
  347. {
  348. if (asfilter->type == new->type
  349. && strcmp (asfilter->reg_str, new->reg_str) == 0)
  350. return 1;
  351. }
  352. return 0;
  353. }
  354. DEFUN (ip_as_path, ip_as_path_cmd,
  355. "ip as-path access-list WORD (deny|permit) .LINE",
  356. IP_STR
  357. "BGP autonomous system path filter\n"
  358. "Specify an access list name\n"
  359. "Regular expression access list name\n"
  360. "Specify packets to reject\n"
  361. "Specify packets to forward\n"
  362. "A regular-expression to match the BGP AS paths\n")
  363. {
  364. enum as_filter_type type;
  365. struct as_filter *asfilter;
  366. struct as_list *aslist;
  367. regex_t *regex;
  368. char *regstr;
  369. /* Check the filter type. */
  370. if (strncmp (argv[1], "p", 1) == 0)
  371. type = AS_FILTER_PERMIT;
  372. else if (strncmp (argv[1], "d", 1) == 0)
  373. type = AS_FILTER_DENY;
  374. else
  375. {
  376. vty_out (vty, "filter type must be [permit|deny]%s", VTY_NEWLINE);
  377. return CMD_WARNING;
  378. }
  379. /* Check AS path regex. */
  380. regstr = argv_concat(argv, argc, 2);
  381. regex = bgp_regcomp (regstr);
  382. if (!regex)
  383. {
  384. XFREE (MTYPE_TMP, regstr);
  385. vty_out (vty, "can't compile regexp %s%s", argv[0],
  386. VTY_NEWLINE);
  387. return CMD_WARNING;
  388. }
  389. asfilter = as_filter_make (regex, regstr, type);
  390. XFREE (MTYPE_TMP, regstr);
  391. /* Install new filter to the access_list. */
  392. aslist = as_list_get (argv[0]);
  393. /* Duplicate insertion check. */;
  394. if (as_list_dup_check (aslist, asfilter))
  395. as_filter_free (asfilter);
  396. else
  397. as_list_filter_add (aslist, asfilter);
  398. return CMD_SUCCESS;
  399. }
  400. DEFUN (no_ip_as_path,
  401. no_ip_as_path_cmd,
  402. "no ip as-path access-list WORD (deny|permit) .LINE",
  403. NO_STR
  404. IP_STR
  405. "BGP autonomous system path filter\n"
  406. "Specify an access list name\n"
  407. "Regular expression access list name\n"
  408. "Specify packets to reject\n"
  409. "Specify packets to forward\n"
  410. "A regular-expression to match the BGP AS paths\n")
  411. {
  412. enum as_filter_type type;
  413. struct as_filter *asfilter;
  414. struct as_list *aslist;
  415. char *regstr;
  416. regex_t *regex;
  417. /* Lookup AS list from AS path list. */
  418. aslist = as_list_lookup (argv[0]);
  419. if (aslist == NULL)
  420. {
  421. vty_out (vty, "ip as-path access-list %s doesn't exist%s", argv[0],
  422. VTY_NEWLINE);
  423. return CMD_WARNING;
  424. }
  425. /* Check the filter type. */
  426. if (strncmp (argv[1], "p", 1) == 0)
  427. type = AS_FILTER_PERMIT;
  428. else if (strncmp (argv[1], "d", 1) == 0)
  429. type = AS_FILTER_DENY;
  430. else
  431. {
  432. vty_out (vty, "filter type must be [permit|deny]%s", VTY_NEWLINE);
  433. return CMD_WARNING;
  434. }
  435. /* Compile AS path. */
  436. regstr = argv_concat(argv, argc, 2);
  437. regex = bgp_regcomp (regstr);
  438. if (!regex)
  439. {
  440. XFREE (MTYPE_TMP, regstr);
  441. vty_out (vty, "can't compile regexp %s%s", argv[0],
  442. VTY_NEWLINE);
  443. return CMD_WARNING;
  444. }
  445. /* Lookup asfilter. */
  446. asfilter = as_filter_lookup (aslist, regstr, type);
  447. XFREE (MTYPE_TMP, regstr);
  448. bgp_regex_free (regex);
  449. if (asfilter == NULL)
  450. {
  451. vty_out (vty, "%s", VTY_NEWLINE);
  452. return CMD_WARNING;
  453. }
  454. as_list_filter_delete (aslist, asfilter);
  455. return CMD_SUCCESS;
  456. }
  457. DEFUN (no_ip_as_path_all,
  458. no_ip_as_path_all_cmd,
  459. "no ip as-path access-list WORD",
  460. NO_STR
  461. IP_STR
  462. "BGP autonomous system path filter\n"
  463. "Specify an access list name\n"
  464. "Regular expression access list name\n")
  465. {
  466. struct as_list *aslist;
  467. aslist = as_list_lookup (argv[0]);
  468. if (aslist == NULL)
  469. {
  470. vty_out (vty, "ip as-path access-list %s doesn't exist%s", argv[0],
  471. VTY_NEWLINE);
  472. return CMD_WARNING;
  473. }
  474. as_list_delete (aslist);
  475. /* Run hook function. */
  476. if (as_list_master.delete_hook)
  477. (*as_list_master.delete_hook) ();
  478. return CMD_SUCCESS;
  479. }
  480. static void
  481. as_list_show (struct vty *vty, struct as_list *aslist)
  482. {
  483. struct as_filter *asfilter;
  484. vty_out (vty, "AS path access list %s%s", aslist->name, VTY_NEWLINE);
  485. for (asfilter = aslist->head; asfilter; asfilter = asfilter->next)
  486. {
  487. vty_out (vty, " %s %s%s", filter_type_str (asfilter->type),
  488. asfilter->reg_str, VTY_NEWLINE);
  489. }
  490. }
  491. static void
  492. as_list_show_all (struct vty *vty)
  493. {
  494. struct as_list *aslist;
  495. struct as_filter *asfilter;
  496. for (aslist = as_list_master.num.head; aslist; aslist = aslist->next)
  497. {
  498. vty_out (vty, "AS path access list %s%s", aslist->name, VTY_NEWLINE);
  499. for (asfilter = aslist->head; asfilter; asfilter = asfilter->next)
  500. {
  501. vty_out (vty, " %s %s%s", filter_type_str (asfilter->type),
  502. asfilter->reg_str, VTY_NEWLINE);
  503. }
  504. }
  505. for (aslist = as_list_master.str.head; aslist; aslist = aslist->next)
  506. {
  507. vty_out (vty, "AS path access list %s%s", aslist->name, VTY_NEWLINE);
  508. for (asfilter = aslist->head; asfilter; asfilter = asfilter->next)
  509. {
  510. vty_out (vty, " %s %s%s", filter_type_str (asfilter->type),
  511. asfilter->reg_str, VTY_NEWLINE);
  512. }
  513. }
  514. }
  515. DEFUN (show_ip_as_path_access_list,
  516. show_ip_as_path_access_list_cmd,
  517. "show ip as-path-access-list WORD",
  518. SHOW_STR
  519. IP_STR
  520. "List AS path access lists\n"
  521. "AS path access list name\n")
  522. {
  523. struct as_list *aslist;
  524. aslist = as_list_lookup (argv[0]);
  525. if (aslist)
  526. as_list_show (vty, aslist);
  527. return CMD_SUCCESS;
  528. }
  529. DEFUN (show_ip_as_path_access_list_all,
  530. show_ip_as_path_access_list_all_cmd,
  531. "show ip as-path-access-list",
  532. SHOW_STR
  533. IP_STR
  534. "List AS path access lists\n")
  535. {
  536. as_list_show_all (vty);
  537. return CMD_SUCCESS;
  538. }
  539. static int
  540. config_write_as_list (struct vty *vty)
  541. {
  542. struct as_list *aslist;
  543. struct as_filter *asfilter;
  544. int write = 0;
  545. for (aslist = as_list_master.num.head; aslist; aslist = aslist->next)
  546. for (asfilter = aslist->head; asfilter; asfilter = asfilter->next)
  547. {
  548. vty_out (vty, "ip as-path access-list %s %s %s%s",
  549. aslist->name, filter_type_str (asfilter->type),
  550. asfilter->reg_str,
  551. VTY_NEWLINE);
  552. write++;
  553. }
  554. for (aslist = as_list_master.str.head; aslist; aslist = aslist->next)
  555. for (asfilter = aslist->head; asfilter; asfilter = asfilter->next)
  556. {
  557. vty_out (vty, "ip as-path access-list %s %s %s%s",
  558. aslist->name, filter_type_str (asfilter->type),
  559. asfilter->reg_str,
  560. VTY_NEWLINE);
  561. write++;
  562. }
  563. return write;
  564. }
  565. struct cmd_node as_list_node =
  566. {
  567. AS_LIST_NODE,
  568. "",
  569. 1
  570. };
  571. /* Register functions. */
  572. void
  573. bgp_filter_init (void)
  574. {
  575. install_node (&as_list_node, config_write_as_list);
  576. install_element (CONFIG_NODE, &ip_as_path_cmd);
  577. install_element (CONFIG_NODE, &no_ip_as_path_cmd);
  578. install_element (CONFIG_NODE, &no_ip_as_path_all_cmd);
  579. install_element (VIEW_NODE, &show_ip_as_path_access_list_cmd);
  580. install_element (VIEW_NODE, &show_ip_as_path_access_list_all_cmd);
  581. install_element (ENABLE_NODE, &show_ip_as_path_access_list_cmd);
  582. install_element (ENABLE_NODE, &show_ip_as_path_access_list_all_cmd);
  583. }