routemap.c 34 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364
  1. /* Route map function.
  2. Copyright (C) 1998, 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 "linklist.h"
  18. #include "memory.h"
  19. #include "vector.h"
  20. #include "prefix.h"
  21. #include "routemap.h"
  22. #include "command.h"
  23. #include "vty.h"
  24. #include "log.h"
  25. /* Vector for route match rules. */
  26. static vector route_match_vec;
  27. /* Vector for route set rules. */
  28. static vector route_set_vec;
  29. /* Route map rule. This rule has both `match' rule and `set' rule. */
  30. struct route_map_rule
  31. {
  32. /* Rule type. */
  33. struct route_map_rule_cmd *cmd;
  34. /* For pretty printing. */
  35. char *rule_str;
  36. /* Pre-compiled match rule. */
  37. void *value;
  38. /* Linked list. */
  39. struct route_map_rule *next;
  40. struct route_map_rule *prev;
  41. };
  42. /* Making route map list. */
  43. struct route_map_list
  44. {
  45. struct route_map *head;
  46. struct route_map *tail;
  47. void (*add_hook) (const char *);
  48. void (*delete_hook) (const char *);
  49. void (*event_hook) (route_map_event_t, const char *);
  50. };
  51. /* Master list of route map. */
  52. static struct route_map_list route_map_master = { NULL, NULL, NULL, NULL };
  53. static void
  54. route_map_rule_delete (struct route_map_rule_list *,
  55. struct route_map_rule *);
  56. static void
  57. route_map_index_delete (struct route_map_index *, int);
  58. /* New route map allocation. Please note route map's name must be
  59. specified. */
  60. static struct route_map *
  61. route_map_new (const char *name)
  62. {
  63. struct route_map *new;
  64. new = XCALLOC (MTYPE_ROUTE_MAP, sizeof (struct route_map));
  65. new->name = XSTRDUP (MTYPE_ROUTE_MAP_NAME, name);
  66. return new;
  67. }
  68. /* Add new name to route_map. */
  69. static struct route_map *
  70. route_map_add (const char *name)
  71. {
  72. struct route_map *map;
  73. struct route_map_list *list;
  74. map = route_map_new (name);
  75. list = &route_map_master;
  76. map->next = NULL;
  77. map->prev = list->tail;
  78. if (list->tail)
  79. list->tail->next = map;
  80. else
  81. list->head = map;
  82. list->tail = map;
  83. /* Execute hook. */
  84. if (route_map_master.add_hook)
  85. (*route_map_master.add_hook) (name);
  86. return map;
  87. }
  88. /* Route map delete from list. */
  89. static void
  90. route_map_delete (struct route_map *map)
  91. {
  92. struct route_map_list *list;
  93. struct route_map_index *index;
  94. char *name;
  95. while ((index = map->head) != NULL)
  96. route_map_index_delete (index, 0);
  97. name = map->name;
  98. list = &route_map_master;
  99. if (map->next)
  100. map->next->prev = map->prev;
  101. else
  102. list->tail = map->prev;
  103. if (map->prev)
  104. map->prev->next = map->next;
  105. else
  106. list->head = map->next;
  107. XFREE (MTYPE_ROUTE_MAP, map);
  108. /* Execute deletion hook. */
  109. if (route_map_master.delete_hook)
  110. (*route_map_master.delete_hook) (name);
  111. if (name)
  112. XFREE (MTYPE_ROUTE_MAP_NAME, name);
  113. }
  114. /* Lookup route map by route map name string. */
  115. struct route_map *
  116. route_map_lookup_by_name (const char *name)
  117. {
  118. struct route_map *map;
  119. for (map = route_map_master.head; map; map = map->next)
  120. if (strcmp (map->name, name) == 0)
  121. return map;
  122. return NULL;
  123. }
  124. /* Lookup route map. If there isn't route map create one and return
  125. it. */
  126. static struct route_map *
  127. route_map_get (const char *name)
  128. {
  129. struct route_map *map;
  130. map = route_map_lookup_by_name (name);
  131. if (map == NULL)
  132. map = route_map_add (name);
  133. return map;
  134. }
  135. /* Return route map's type string. */
  136. static const char *
  137. route_map_type_str (enum route_map_type type)
  138. {
  139. switch (type)
  140. {
  141. case RMAP_PERMIT:
  142. return "permit";
  143. break;
  144. case RMAP_DENY:
  145. return "deny";
  146. break;
  147. default:
  148. return "";
  149. break;
  150. }
  151. }
  152. static int
  153. route_map_empty (struct route_map *map)
  154. {
  155. if (map->head == NULL && map->tail == NULL)
  156. return 1;
  157. else
  158. return 0;
  159. }
  160. /* show route-map */
  161. static void
  162. vty_show_route_map_entry (struct vty *vty, struct route_map *map)
  163. {
  164. struct route_map_index *index;
  165. struct route_map_rule *rule;
  166. /* Print the name of the protocol */
  167. if (zlog_default)
  168. vty_out (vty, "%s:%s", zlog_proto_names[zlog_default->protocol],
  169. VTY_NEWLINE);
  170. for (index = map->head; index; index = index->next)
  171. {
  172. vty_out (vty, "route-map %s, %s, sequence %d%s",
  173. map->name, route_map_type_str (index->type),
  174. index->pref, VTY_NEWLINE);
  175. /* Description */
  176. if (index->description)
  177. vty_out (vty, " Description:%s %s%s", VTY_NEWLINE,
  178. index->description, VTY_NEWLINE);
  179. /* Match clauses */
  180. vty_out (vty, " Match clauses:%s", VTY_NEWLINE);
  181. for (rule = index->match_list.head; rule; rule = rule->next)
  182. vty_out (vty, " %s %s%s",
  183. rule->cmd->str, rule->rule_str, VTY_NEWLINE);
  184. vty_out (vty, " Set clauses:%s", VTY_NEWLINE);
  185. for (rule = index->set_list.head; rule; rule = rule->next)
  186. vty_out (vty, " %s %s%s",
  187. rule->cmd->str, rule->rule_str, VTY_NEWLINE);
  188. /* Call clause */
  189. vty_out (vty, " Call clause:%s", VTY_NEWLINE);
  190. if (index->nextrm)
  191. vty_out (vty, " Call %s%s", index->nextrm, VTY_NEWLINE);
  192. /* Exit Policy */
  193. vty_out (vty, " Action:%s", VTY_NEWLINE);
  194. if (index->exitpolicy == RMAP_GOTO)
  195. vty_out (vty, " Goto %d%s", index->nextpref, VTY_NEWLINE);
  196. else if (index->exitpolicy == RMAP_NEXT)
  197. vty_out (vty, " Continue to next entry%s", VTY_NEWLINE);
  198. else if (index->exitpolicy == RMAP_EXIT)
  199. vty_out (vty, " Exit routemap%s", VTY_NEWLINE);
  200. }
  201. }
  202. static int
  203. vty_show_route_map (struct vty *vty, const char *name)
  204. {
  205. struct route_map *map;
  206. if (name)
  207. {
  208. map = route_map_lookup_by_name (name);
  209. if (map)
  210. {
  211. vty_show_route_map_entry (vty, map);
  212. return CMD_SUCCESS;
  213. }
  214. else
  215. {
  216. vty_out (vty, "%%route-map %s not found%s", name, VTY_NEWLINE);
  217. return CMD_WARNING;
  218. }
  219. }
  220. else
  221. {
  222. for (map = route_map_master.head; map; map = map->next)
  223. vty_show_route_map_entry (vty, map);
  224. }
  225. return CMD_SUCCESS;
  226. }
  227. /* New route map allocation. Please note route map's name must be
  228. specified. */
  229. static struct route_map_index *
  230. route_map_index_new (void)
  231. {
  232. struct route_map_index *new;
  233. new = XCALLOC (MTYPE_ROUTE_MAP_INDEX, sizeof (struct route_map_index));
  234. new->exitpolicy = RMAP_EXIT; /* Default to Cisco-style */
  235. return new;
  236. }
  237. /* Free route map index. */
  238. static void
  239. route_map_index_delete (struct route_map_index *index, int notify)
  240. {
  241. struct route_map_rule *rule;
  242. /* Free route match. */
  243. while ((rule = index->match_list.head) != NULL)
  244. route_map_rule_delete (&index->match_list, rule);
  245. /* Free route set. */
  246. while ((rule = index->set_list.head) != NULL)
  247. route_map_rule_delete (&index->set_list, rule);
  248. /* Remove index from route map list. */
  249. if (index->next)
  250. index->next->prev = index->prev;
  251. else
  252. index->map->tail = index->prev;
  253. if (index->prev)
  254. index->prev->next = index->next;
  255. else
  256. index->map->head = index->next;
  257. /* Free 'char *nextrm' if not NULL */
  258. if (index->nextrm)
  259. XFREE (MTYPE_ROUTE_MAP_NAME, index->nextrm);
  260. /* Execute event hook. */
  261. if (route_map_master.event_hook && notify)
  262. (*route_map_master.event_hook) (RMAP_EVENT_INDEX_DELETED,
  263. index->map->name);
  264. XFREE (MTYPE_ROUTE_MAP_INDEX, index);
  265. }
  266. /* Lookup index from route map. */
  267. static struct route_map_index *
  268. route_map_index_lookup (struct route_map *map, enum route_map_type type,
  269. int pref)
  270. {
  271. struct route_map_index *index;
  272. for (index = map->head; index; index = index->next)
  273. if ((index->type == type || type == RMAP_ANY)
  274. && index->pref == pref)
  275. return index;
  276. return NULL;
  277. }
  278. /* Add new index to route map. */
  279. static struct route_map_index *
  280. route_map_index_add (struct route_map *map, enum route_map_type type,
  281. int pref)
  282. {
  283. struct route_map_index *index;
  284. struct route_map_index *point;
  285. /* Allocate new route map inex. */
  286. index = route_map_index_new ();
  287. index->map = map;
  288. index->type = type;
  289. index->pref = pref;
  290. /* Compare preference. */
  291. for (point = map->head; point; point = point->next)
  292. if (point->pref >= pref)
  293. break;
  294. if (map->head == NULL)
  295. {
  296. map->head = map->tail = index;
  297. }
  298. else if (point == NULL)
  299. {
  300. index->prev = map->tail;
  301. map->tail->next = index;
  302. map->tail = index;
  303. }
  304. else if (point == map->head)
  305. {
  306. index->next = map->head;
  307. map->head->prev = index;
  308. map->head = index;
  309. }
  310. else
  311. {
  312. index->next = point;
  313. index->prev = point->prev;
  314. if (point->prev)
  315. point->prev->next = index;
  316. point->prev = index;
  317. }
  318. /* Execute event hook. */
  319. if (route_map_master.event_hook)
  320. (*route_map_master.event_hook) (RMAP_EVENT_INDEX_ADDED,
  321. map->name);
  322. return index;
  323. }
  324. /* Get route map index. */
  325. static struct route_map_index *
  326. route_map_index_get (struct route_map *map, enum route_map_type type,
  327. int pref)
  328. {
  329. struct route_map_index *index;
  330. index = route_map_index_lookup (map, RMAP_ANY, pref);
  331. if (index && index->type != type)
  332. {
  333. /* Delete index from route map. */
  334. route_map_index_delete (index, 1);
  335. index = NULL;
  336. }
  337. if (index == NULL)
  338. index = route_map_index_add (map, type, pref);
  339. return index;
  340. }
  341. /* New route map rule */
  342. static struct route_map_rule *
  343. route_map_rule_new (void)
  344. {
  345. struct route_map_rule *new;
  346. new = XCALLOC (MTYPE_ROUTE_MAP_RULE, sizeof (struct route_map_rule));
  347. return new;
  348. }
  349. /* Install rule command to the match list. */
  350. void
  351. route_map_install_match (struct route_map_rule_cmd *cmd)
  352. {
  353. vector_set (route_match_vec, cmd);
  354. }
  355. /* Install rule command to the set list. */
  356. void
  357. route_map_install_set (struct route_map_rule_cmd *cmd)
  358. {
  359. vector_set (route_set_vec, cmd);
  360. }
  361. /* Lookup rule command from match list. */
  362. static struct route_map_rule_cmd *
  363. route_map_lookup_match (const char *name)
  364. {
  365. unsigned int i;
  366. struct route_map_rule_cmd *rule;
  367. for (i = 0; i < vector_active (route_match_vec); i++)
  368. if ((rule = vector_slot (route_match_vec, i)) != NULL)
  369. if (strcmp (rule->str, name) == 0)
  370. return rule;
  371. return NULL;
  372. }
  373. /* Lookup rule command from set list. */
  374. static struct route_map_rule_cmd *
  375. route_map_lookup_set (const char *name)
  376. {
  377. unsigned int i;
  378. struct route_map_rule_cmd *rule;
  379. for (i = 0; i < vector_active (route_set_vec); i++)
  380. if ((rule = vector_slot (route_set_vec, i)) != NULL)
  381. if (strcmp (rule->str, name) == 0)
  382. return rule;
  383. return NULL;
  384. }
  385. /* Add match and set rule to rule list. */
  386. static void
  387. route_map_rule_add (struct route_map_rule_list *list,
  388. struct route_map_rule *rule)
  389. {
  390. rule->next = NULL;
  391. rule->prev = list->tail;
  392. if (list->tail)
  393. list->tail->next = rule;
  394. else
  395. list->head = rule;
  396. list->tail = rule;
  397. }
  398. /* Delete rule from rule list. */
  399. static void
  400. route_map_rule_delete (struct route_map_rule_list *list,
  401. struct route_map_rule *rule)
  402. {
  403. if (rule->cmd->func_free)
  404. (*rule->cmd->func_free) (rule->value);
  405. if (rule->rule_str)
  406. XFREE (MTYPE_ROUTE_MAP_RULE_STR, rule->rule_str);
  407. if (rule->next)
  408. rule->next->prev = rule->prev;
  409. else
  410. list->tail = rule->prev;
  411. if (rule->prev)
  412. rule->prev->next = rule->next;
  413. else
  414. list->head = rule->next;
  415. XFREE (MTYPE_ROUTE_MAP_RULE, rule);
  416. }
  417. /* strcmp wrapper function which don't crush even argument is NULL. */
  418. static int
  419. rulecmp (const char *dst, const char *src)
  420. {
  421. if (dst == NULL)
  422. {
  423. if (src == NULL)
  424. return 0;
  425. else
  426. return 1;
  427. }
  428. else
  429. {
  430. if (src == NULL)
  431. return 1;
  432. else
  433. return strcmp (dst, src);
  434. }
  435. return 1;
  436. }
  437. /* Add match statement to route map. */
  438. int
  439. route_map_add_match (struct route_map_index *index, const char *match_name,
  440. const char *match_arg)
  441. {
  442. struct route_map_rule *rule;
  443. struct route_map_rule *next;
  444. struct route_map_rule_cmd *cmd;
  445. void *compile;
  446. int replaced = 0;
  447. /* First lookup rule for add match statement. */
  448. cmd = route_map_lookup_match (match_name);
  449. if (cmd == NULL)
  450. return RMAP_RULE_MISSING;
  451. /* Next call compile function for this match statement. */
  452. if (cmd->func_compile)
  453. {
  454. compile= (*cmd->func_compile)(match_arg);
  455. if (compile == NULL)
  456. return RMAP_COMPILE_ERROR;
  457. }
  458. else
  459. compile = NULL;
  460. /* If argument is completely same ignore it. */
  461. for (rule = index->match_list.head; rule; rule = next)
  462. {
  463. next = rule->next;
  464. if (rule->cmd == cmd)
  465. {
  466. route_map_rule_delete (&index->match_list, rule);
  467. replaced = 1;
  468. }
  469. }
  470. /* Add new route map match rule. */
  471. rule = route_map_rule_new ();
  472. rule->cmd = cmd;
  473. rule->value = compile;
  474. if (match_arg)
  475. rule->rule_str = XSTRDUP (MTYPE_ROUTE_MAP_RULE_STR, match_arg);
  476. else
  477. rule->rule_str = NULL;
  478. /* Add new route match rule to linked list. */
  479. route_map_rule_add (&index->match_list, rule);
  480. /* Execute event hook. */
  481. if (route_map_master.event_hook)
  482. (*route_map_master.event_hook) (replaced ?
  483. RMAP_EVENT_MATCH_REPLACED:
  484. RMAP_EVENT_MATCH_ADDED,
  485. index->map->name);
  486. return 0;
  487. }
  488. /* Delete specified route match rule. */
  489. int
  490. route_map_delete_match (struct route_map_index *index, const char *match_name,
  491. const char *match_arg)
  492. {
  493. struct route_map_rule *rule;
  494. struct route_map_rule_cmd *cmd;
  495. cmd = route_map_lookup_match (match_name);
  496. if (cmd == NULL)
  497. return 1;
  498. for (rule = index->match_list.head; rule; rule = rule->next)
  499. if (rule->cmd == cmd &&
  500. (rulecmp (rule->rule_str, match_arg) == 0 || match_arg == NULL))
  501. {
  502. route_map_rule_delete (&index->match_list, rule);
  503. /* Execute event hook. */
  504. if (route_map_master.event_hook)
  505. (*route_map_master.event_hook) (RMAP_EVENT_MATCH_DELETED,
  506. index->map->name);
  507. return 0;
  508. }
  509. /* Can't find matched rule. */
  510. return 1;
  511. }
  512. /* Add route-map set statement to the route map. */
  513. int
  514. route_map_add_set (struct route_map_index *index, const char *set_name,
  515. const char *set_arg)
  516. {
  517. struct route_map_rule *rule;
  518. struct route_map_rule *next;
  519. struct route_map_rule_cmd *cmd;
  520. void *compile;
  521. int replaced = 0;
  522. cmd = route_map_lookup_set (set_name);
  523. if (cmd == NULL)
  524. return RMAP_RULE_MISSING;
  525. /* Next call compile function for this match statement. */
  526. if (cmd->func_compile)
  527. {
  528. compile= (*cmd->func_compile)(set_arg);
  529. if (compile == NULL)
  530. return RMAP_COMPILE_ERROR;
  531. }
  532. else
  533. compile = NULL;
  534. /* Add by WJL. if old set command of same kind exist, delete it first
  535. to ensure only one set command of same kind exist under a
  536. route_map_index. */
  537. for (rule = index->set_list.head; rule; rule = next)
  538. {
  539. next = rule->next;
  540. if (rule->cmd == cmd)
  541. {
  542. route_map_rule_delete (&index->set_list, rule);
  543. replaced = 1;
  544. }
  545. }
  546. /* Add new route map match rule. */
  547. rule = route_map_rule_new ();
  548. rule->cmd = cmd;
  549. rule->value = compile;
  550. if (set_arg)
  551. rule->rule_str = XSTRDUP (MTYPE_ROUTE_MAP_RULE_STR, set_arg);
  552. else
  553. rule->rule_str = NULL;
  554. /* Add new route match rule to linked list. */
  555. route_map_rule_add (&index->set_list, rule);
  556. /* Execute event hook. */
  557. if (route_map_master.event_hook)
  558. (*route_map_master.event_hook) (replaced ?
  559. RMAP_EVENT_SET_REPLACED:
  560. RMAP_EVENT_SET_ADDED,
  561. index->map->name);
  562. return 0;
  563. }
  564. /* Delete route map set rule. */
  565. int
  566. route_map_delete_set (struct route_map_index *index, const char *set_name,
  567. const char *set_arg)
  568. {
  569. struct route_map_rule *rule;
  570. struct route_map_rule_cmd *cmd;
  571. cmd = route_map_lookup_set (set_name);
  572. if (cmd == NULL)
  573. return 1;
  574. for (rule = index->set_list.head; rule; rule = rule->next)
  575. if ((rule->cmd == cmd) &&
  576. (rulecmp (rule->rule_str, set_arg) == 0 || set_arg == NULL))
  577. {
  578. route_map_rule_delete (&index->set_list, rule);
  579. /* Execute event hook. */
  580. if (route_map_master.event_hook)
  581. (*route_map_master.event_hook) (RMAP_EVENT_SET_DELETED,
  582. index->map->name);
  583. return 0;
  584. }
  585. /* Can't find matched rule. */
  586. return 1;
  587. }
  588. /* Apply route map's each index to the object.
  589. The matrix for a route-map looks like this:
  590. (note, this includes the description for the "NEXT"
  591. and "GOTO" frobs now
  592. Match | No Match
  593. |
  594. permit action | cont
  595. |
  596. ------------------+---------------
  597. |
  598. deny deny | cont
  599. |
  600. action)
  601. -Apply Set statements, accept route
  602. -If Call statement is present jump to the specified route-map, if it
  603. denies the route we finish.
  604. -If NEXT is specified, goto NEXT statement
  605. -If GOTO is specified, goto the first clause where pref > nextpref
  606. -If nothing is specified, do as Cisco and finish
  607. deny)
  608. -Route is denied by route-map.
  609. cont)
  610. -Goto Next index
  611. If we get no matches after we've processed all updates, then the route
  612. is dropped too.
  613. Some notes on the new "CALL", "NEXT" and "GOTO"
  614. call WORD - If this clause is matched, then the set statements
  615. are executed and then we jump to route-map 'WORD'. If
  616. this route-map denies the route, we finish, in other case we
  617. do whatever the exit policy (EXIT, NEXT or GOTO) tells.
  618. on-match next - If this clause is matched, then the set statements
  619. are executed and then we drop through to the next clause
  620. on-match goto n - If this clause is matched, then the set statments
  621. are executed and then we goto the nth clause, or the
  622. first clause greater than this. In order to ensure
  623. route-maps *always* exit, you cannot jump backwards.
  624. Sorry ;)
  625. We need to make sure our route-map processing matches the above
  626. */
  627. static route_map_result_t
  628. route_map_apply_match (struct route_map_rule_list *match_list,
  629. struct prefix *prefix, route_map_object_t type,
  630. void *object)
  631. {
  632. route_map_result_t ret = RMAP_NOMATCH;
  633. struct route_map_rule *match;
  634. /* Check all match rule and if there is no match rule, go to the
  635. set statement. */
  636. if (!match_list->head)
  637. ret = RMAP_MATCH;
  638. else
  639. {
  640. for (match = match_list->head; match; match = match->next)
  641. {
  642. /* Try each match statement in turn, If any do not return
  643. RMAP_MATCH, return, otherwise continue on to next match
  644. statement. All match statements must match for end-result
  645. to be a match. */
  646. ret = (*match->cmd->func_apply) (match->value, prefix,
  647. type, object);
  648. if (ret != RMAP_MATCH)
  649. return ret;
  650. }
  651. }
  652. return ret;
  653. }
  654. /* Apply route map to the object. */
  655. route_map_result_t
  656. route_map_apply (struct route_map *map, struct prefix *prefix,
  657. route_map_object_t type, void *object)
  658. {
  659. static int recursion = 0;
  660. int ret = 0;
  661. struct route_map_index *index;
  662. struct route_map_rule *set;
  663. if (recursion > RMAP_RECURSION_LIMIT)
  664. {
  665. zlog (NULL, LOG_WARNING,
  666. "route-map recursion limit (%d) reached, discarding route",
  667. RMAP_RECURSION_LIMIT);
  668. recursion = 0;
  669. return RMAP_DENYMATCH;
  670. }
  671. if (map == NULL)
  672. return RMAP_DENYMATCH;
  673. for (index = map->head; index; index = index->next)
  674. {
  675. /* Apply this index. */
  676. ret = route_map_apply_match (&index->match_list, prefix, type, object);
  677. /* Now we apply the matrix from above */
  678. if (ret == RMAP_NOMATCH)
  679. /* 'cont' from matrix - continue to next route-map sequence */
  680. continue;
  681. else if (ret == RMAP_MATCH)
  682. {
  683. if (index->type == RMAP_PERMIT)
  684. /* 'action' */
  685. {
  686. /* permit+match must execute sets */
  687. for (set = index->set_list.head; set; set = set->next)
  688. ret = (*set->cmd->func_apply) (set->value, prefix,
  689. type, object);
  690. /* Call another route-map if available */
  691. if (index->nextrm)
  692. {
  693. struct route_map *nextrm =
  694. route_map_lookup_by_name (index->nextrm);
  695. if (nextrm) /* Target route-map found, jump to it */
  696. {
  697. recursion++;
  698. ret = route_map_apply (nextrm, prefix, type, object);
  699. recursion--;
  700. }
  701. /* If nextrm returned 'deny', finish. */
  702. if (ret == RMAP_DENYMATCH)
  703. return ret;
  704. }
  705. switch (index->exitpolicy)
  706. {
  707. case RMAP_EXIT:
  708. return ret;
  709. case RMAP_NEXT:
  710. continue;
  711. case RMAP_GOTO:
  712. {
  713. /* Find the next clause to jump to */
  714. struct route_map_index *next = index->next;
  715. int nextpref = index->nextpref;
  716. while (next && next->pref < nextpref)
  717. {
  718. index = next;
  719. next = next->next;
  720. }
  721. if (next == NULL)
  722. {
  723. /* No clauses match! */
  724. return ret;
  725. }
  726. }
  727. }
  728. }
  729. else if (index->type == RMAP_DENY)
  730. /* 'deny' */
  731. {
  732. return RMAP_DENYMATCH;
  733. }
  734. }
  735. }
  736. /* Finally route-map does not match at all. */
  737. return RMAP_DENYMATCH;
  738. }
  739. void
  740. route_map_add_hook (void (*func) (const char *))
  741. {
  742. route_map_master.add_hook = func;
  743. }
  744. void
  745. route_map_delete_hook (void (*func) (const char *))
  746. {
  747. route_map_master.delete_hook = func;
  748. }
  749. void
  750. route_map_event_hook (void (*func) (route_map_event_t, const char *))
  751. {
  752. route_map_master.event_hook = func;
  753. }
  754. void
  755. route_map_init (void)
  756. {
  757. /* Make vector for match and set. */
  758. route_match_vec = vector_init (1);
  759. route_set_vec = vector_init (1);
  760. }
  761. void
  762. route_map_finish (void)
  763. {
  764. vector_free (route_match_vec);
  765. route_match_vec = NULL;
  766. vector_free (route_set_vec);
  767. route_set_vec = NULL;
  768. /* cleanup route_map */
  769. while (route_map_master.head)
  770. route_map_delete (route_map_master.head);
  771. }
  772. /* VTY related functions. */
  773. DEFUN (route_map,
  774. route_map_cmd,
  775. "route-map WORD (deny|permit) <1-65535>",
  776. "Create route-map or enter route-map command mode\n"
  777. "Route map tag\n"
  778. "Route map denies set operations\n"
  779. "Route map permits set operations\n"
  780. "Sequence to insert to/delete from existing route-map entry\n")
  781. {
  782. int permit;
  783. unsigned long pref;
  784. struct route_map *map;
  785. struct route_map_index *index;
  786. char *endptr = NULL;
  787. /* Permit check. */
  788. if (strncmp (argv[1], "permit", strlen (argv[1])) == 0)
  789. permit = RMAP_PERMIT;
  790. else if (strncmp (argv[1], "deny", strlen (argv[1])) == 0)
  791. permit = RMAP_DENY;
  792. else
  793. {
  794. vty_out (vty, "the third field must be [permit|deny]%s", VTY_NEWLINE);
  795. return CMD_WARNING;
  796. }
  797. /* Preference check. */
  798. pref = strtoul (argv[2], &endptr, 10);
  799. if (pref == ULONG_MAX || *endptr != '\0')
  800. {
  801. vty_out (vty, "the fourth field must be positive integer%s",
  802. VTY_NEWLINE);
  803. return CMD_WARNING;
  804. }
  805. if (pref == 0 || pref > 65535)
  806. {
  807. vty_out (vty, "the fourth field must be <1-65535>%s", VTY_NEWLINE);
  808. return CMD_WARNING;
  809. }
  810. /* Get route map. */
  811. map = route_map_get (argv[0]);
  812. index = route_map_index_get (map, permit, pref);
  813. vty->index = index;
  814. vty->node = RMAP_NODE;
  815. return CMD_SUCCESS;
  816. }
  817. DEFUN (no_route_map_all,
  818. no_route_map_all_cmd,
  819. "no route-map WORD",
  820. NO_STR
  821. "Create route-map or enter route-map command mode\n"
  822. "Route map tag\n")
  823. {
  824. struct route_map *map;
  825. map = route_map_lookup_by_name (argv[0]);
  826. if (map == NULL)
  827. {
  828. vty_out (vty, "%% Could not find route-map %s%s",
  829. argv[0], VTY_NEWLINE);
  830. return CMD_WARNING;
  831. }
  832. route_map_delete (map);
  833. return CMD_SUCCESS;
  834. }
  835. DEFUN (no_route_map,
  836. no_route_map_cmd,
  837. "no route-map WORD (deny|permit) <1-65535>",
  838. NO_STR
  839. "Create route-map or enter route-map command mode\n"
  840. "Route map tag\n"
  841. "Route map denies set operations\n"
  842. "Route map permits set operations\n"
  843. "Sequence to insert to/delete from existing route-map entry\n")
  844. {
  845. int permit;
  846. unsigned long pref;
  847. struct route_map *map;
  848. struct route_map_index *index;
  849. char *endptr = NULL;
  850. /* Permit check. */
  851. if (strncmp (argv[1], "permit", strlen (argv[1])) == 0)
  852. permit = RMAP_PERMIT;
  853. else if (strncmp (argv[1], "deny", strlen (argv[1])) == 0)
  854. permit = RMAP_DENY;
  855. else
  856. {
  857. vty_out (vty, "the third field must be [permit|deny]%s", VTY_NEWLINE);
  858. return CMD_WARNING;
  859. }
  860. /* Preference. */
  861. pref = strtoul (argv[2], &endptr, 10);
  862. if (pref == ULONG_MAX || *endptr != '\0')
  863. {
  864. vty_out (vty, "the fourth field must be positive integer%s",
  865. VTY_NEWLINE);
  866. return CMD_WARNING;
  867. }
  868. if (pref == 0 || pref > 65535)
  869. {
  870. vty_out (vty, "the fourth field must be <1-65535>%s", VTY_NEWLINE);
  871. return CMD_WARNING;
  872. }
  873. /* Existence check. */
  874. map = route_map_lookup_by_name (argv[0]);
  875. if (map == NULL)
  876. {
  877. vty_out (vty, "%% Could not find route-map %s%s",
  878. argv[0], VTY_NEWLINE);
  879. return CMD_WARNING;
  880. }
  881. /* Lookup route map index. */
  882. index = route_map_index_lookup (map, permit, pref);
  883. if (index == NULL)
  884. {
  885. vty_out (vty, "%% Could not find route-map entry %s %s%s",
  886. argv[0], argv[2], VTY_NEWLINE);
  887. return CMD_WARNING;
  888. }
  889. /* Delete index from route map. */
  890. route_map_index_delete (index, 1);
  891. /* If this route rule is the last one, delete route map itself. */
  892. if (route_map_empty (map))
  893. route_map_delete (map);
  894. return CMD_SUCCESS;
  895. }
  896. DEFUN (rmap_onmatch_next,
  897. rmap_onmatch_next_cmd,
  898. "on-match next",
  899. "Exit policy on matches\n"
  900. "Next clause\n")
  901. {
  902. struct route_map_index *index;
  903. index = vty->index;
  904. if (index)
  905. index->exitpolicy = RMAP_NEXT;
  906. return CMD_SUCCESS;
  907. }
  908. DEFUN (no_rmap_onmatch_next,
  909. no_rmap_onmatch_next_cmd,
  910. "no on-match next",
  911. NO_STR
  912. "Exit policy on matches\n"
  913. "Next clause\n")
  914. {
  915. struct route_map_index *index;
  916. index = vty->index;
  917. if (index)
  918. index->exitpolicy = RMAP_EXIT;
  919. return CMD_SUCCESS;
  920. }
  921. DEFUN (rmap_onmatch_goto,
  922. rmap_onmatch_goto_cmd,
  923. "on-match goto <1-65535>",
  924. "Exit policy on matches\n"
  925. "Goto Clause number\n"
  926. "Number\n")
  927. {
  928. struct route_map_index *index = vty->index;
  929. int d = 0;
  930. if (index)
  931. {
  932. if (argc == 1 && argv[0])
  933. VTY_GET_INTEGER_RANGE("route-map index", d, argv[0], 1, 65536);
  934. else
  935. d = index->pref + 1;
  936. if (d <= index->pref)
  937. {
  938. /* Can't allow you to do that, Dave */
  939. vty_out (vty, "can't jump backwards in route-maps%s",
  940. VTY_NEWLINE);
  941. return CMD_WARNING;
  942. }
  943. else
  944. {
  945. index->exitpolicy = RMAP_GOTO;
  946. index->nextpref = d;
  947. }
  948. }
  949. return CMD_SUCCESS;
  950. }
  951. DEFUN (no_rmap_onmatch_goto,
  952. no_rmap_onmatch_goto_cmd,
  953. "no on-match goto",
  954. NO_STR
  955. "Exit policy on matches\n"
  956. "Goto Clause number\n")
  957. {
  958. struct route_map_index *index;
  959. index = vty->index;
  960. if (index)
  961. index->exitpolicy = RMAP_EXIT;
  962. return CMD_SUCCESS;
  963. }
  964. /* Cisco/GNU Zebra compatible ALIASes for on-match next */
  965. ALIAS (rmap_onmatch_goto,
  966. rmap_continue_cmd,
  967. "continue",
  968. "Continue on a different entry within the route-map\n")
  969. ALIAS (no_rmap_onmatch_goto,
  970. no_rmap_continue_cmd,
  971. "no continue",
  972. NO_STR
  973. "Continue on a different entry within the route-map\n")
  974. /* GNU Zebra compatible */
  975. ALIAS (rmap_onmatch_goto,
  976. rmap_continue_seq_cmd,
  977. "continue <1-65535>",
  978. "Continue on a different entry within the route-map\n"
  979. "Route-map entry sequence number\n")
  980. ALIAS (no_rmap_onmatch_goto,
  981. no_rmap_continue_seq,
  982. "no continue <1-65535>",
  983. NO_STR
  984. "Continue on a different entry within the route-map\n"
  985. "Route-map entry sequence number\n")
  986. DEFUN (rmap_show_name,
  987. rmap_show_name_cmd,
  988. "show route-map [WORD]",
  989. SHOW_STR
  990. "route-map information\n"
  991. "route-map name\n")
  992. {
  993. const char *name = NULL;
  994. if (argc)
  995. name = argv[0];
  996. return vty_show_route_map (vty, name);
  997. }
  998. ALIAS (rmap_onmatch_goto,
  999. rmap_continue_index_cmd,
  1000. "continue <1-65536>",
  1001. "Exit policy on matches\n"
  1002. "Goto Clause number\n")
  1003. DEFUN (rmap_call,
  1004. rmap_call_cmd,
  1005. "call WORD",
  1006. "Jump to another Route-Map after match+set\n"
  1007. "Target route-map name\n")
  1008. {
  1009. struct route_map_index *index;
  1010. index = vty->index;
  1011. if (index)
  1012. {
  1013. if (index->nextrm)
  1014. XFREE (MTYPE_ROUTE_MAP_NAME, index->nextrm);
  1015. index->nextrm = XSTRDUP (MTYPE_ROUTE_MAP_NAME, argv[0]);
  1016. }
  1017. return CMD_SUCCESS;
  1018. }
  1019. DEFUN (no_rmap_call,
  1020. no_rmap_call_cmd,
  1021. "no call",
  1022. NO_STR
  1023. "Jump to another Route-Map after match+set\n")
  1024. {
  1025. struct route_map_index *index;
  1026. index = vty->index;
  1027. if (index->nextrm)
  1028. {
  1029. XFREE (MTYPE_ROUTE_MAP_NAME, index->nextrm);
  1030. index->nextrm = NULL;
  1031. }
  1032. return CMD_SUCCESS;
  1033. }
  1034. DEFUN (rmap_description,
  1035. rmap_description_cmd,
  1036. "description .LINE",
  1037. "Route-map comment\n"
  1038. "Comment describing this route-map rule\n")
  1039. {
  1040. struct route_map_index *index;
  1041. index = vty->index;
  1042. if (index)
  1043. {
  1044. if (index->description)
  1045. XFREE (MTYPE_TMP, index->description);
  1046. index->description = argv_concat (argv, argc, 0);
  1047. }
  1048. return CMD_SUCCESS;
  1049. }
  1050. DEFUN (no_rmap_description,
  1051. no_rmap_description_cmd,
  1052. "no description",
  1053. NO_STR
  1054. "Route-map comment\n")
  1055. {
  1056. struct route_map_index *index;
  1057. index = vty->index;
  1058. if (index)
  1059. {
  1060. if (index->description)
  1061. XFREE (MTYPE_TMP, index->description);
  1062. index->description = NULL;
  1063. }
  1064. return CMD_SUCCESS;
  1065. }
  1066. /* Configuration write function. */
  1067. static int
  1068. route_map_config_write (struct vty *vty)
  1069. {
  1070. struct route_map *map;
  1071. struct route_map_index *index;
  1072. struct route_map_rule *rule;
  1073. int first = 1;
  1074. int write = 0;
  1075. for (map = route_map_master.head; map; map = map->next)
  1076. for (index = map->head; index; index = index->next)
  1077. {
  1078. if (!first)
  1079. vty_out (vty, "!%s", VTY_NEWLINE);
  1080. else
  1081. first = 0;
  1082. vty_out (vty, "route-map %s %s %d%s",
  1083. map->name,
  1084. route_map_type_str (index->type),
  1085. index->pref, VTY_NEWLINE);
  1086. if (index->description)
  1087. vty_out (vty, " description %s%s", index->description, VTY_NEWLINE);
  1088. for (rule = index->match_list.head; rule; rule = rule->next)
  1089. vty_out (vty, " match %s %s%s", rule->cmd->str,
  1090. rule->rule_str ? rule->rule_str : "",
  1091. VTY_NEWLINE);
  1092. for (rule = index->set_list.head; rule; rule = rule->next)
  1093. vty_out (vty, " set %s %s%s", rule->cmd->str,
  1094. rule->rule_str ? rule->rule_str : "",
  1095. VTY_NEWLINE);
  1096. if (index->nextrm)
  1097. vty_out (vty, " call %s%s", index->nextrm, VTY_NEWLINE);
  1098. if (index->exitpolicy == RMAP_GOTO)
  1099. vty_out (vty, " on-match goto %d%s", index->nextpref, VTY_NEWLINE);
  1100. if (index->exitpolicy == RMAP_NEXT)
  1101. vty_out (vty," on-match next%s", VTY_NEWLINE);
  1102. write++;
  1103. }
  1104. return write;
  1105. }
  1106. /* Route map node structure. */
  1107. static struct cmd_node rmap_node =
  1108. {
  1109. RMAP_NODE,
  1110. "%s(config-route-map)# ",
  1111. 1
  1112. };
  1113. /* Common route map rules */
  1114. void *
  1115. route_map_rule_tag_compile (const char *arg)
  1116. {
  1117. unsigned long int tmp;
  1118. char *endptr;
  1119. route_tag_t *tag;
  1120. errno = 0;
  1121. tmp = strtoul(arg, &endptr, 0);
  1122. if (arg[0] == '\0' || *endptr != '\0' || errno || tmp > ROUTE_TAG_MAX)
  1123. return NULL;
  1124. tag = XMALLOC(MTYPE_ROUTE_MAP_COMPILED, sizeof(*tag));
  1125. *tag = tmp;
  1126. return tag;
  1127. }
  1128. void
  1129. route_map_rule_tag_free (void *rule)
  1130. {
  1131. XFREE (MTYPE_ROUTE_MAP_COMPILED, rule);
  1132. }
  1133. /* Initialization of route map vector. */
  1134. void
  1135. route_map_init_vty (void)
  1136. {
  1137. /* Install route map top node. */
  1138. install_node (&rmap_node, route_map_config_write);
  1139. /* Install route map commands. */
  1140. install_default (RMAP_NODE);
  1141. install_element (CONFIG_NODE, &route_map_cmd);
  1142. install_element (CONFIG_NODE, &no_route_map_cmd);
  1143. install_element (CONFIG_NODE, &no_route_map_all_cmd);
  1144. /* Install the on-match stuff */
  1145. install_element (RMAP_NODE, &route_map_cmd);
  1146. install_element (RMAP_NODE, &rmap_onmatch_next_cmd);
  1147. install_element (RMAP_NODE, &no_rmap_onmatch_next_cmd);
  1148. install_element (RMAP_NODE, &rmap_onmatch_goto_cmd);
  1149. install_element (RMAP_NODE, &no_rmap_onmatch_goto_cmd);
  1150. /* Install the continue stuff (ALIAS of on-match). */
  1151. install_element (RMAP_NODE, &rmap_continue_cmd);
  1152. install_element (RMAP_NODE, &no_rmap_continue_cmd);
  1153. install_element (RMAP_NODE, &rmap_continue_index_cmd);
  1154. /* Install the call stuff. */
  1155. install_element (RMAP_NODE, &rmap_call_cmd);
  1156. install_element (RMAP_NODE, &no_rmap_call_cmd);
  1157. /* Install description commands. */
  1158. install_element (RMAP_NODE, &rmap_description_cmd);
  1159. install_element (RMAP_NODE, &no_rmap_description_cmd);
  1160. /* Install show command */
  1161. install_element (ENABLE_NODE, &rmap_show_name_cmd);
  1162. }