ospf6_route.c 38 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403
  1. /*
  2. * Copyright (C) 2003 Yasuhiro Ohara
  3. *
  4. * This file is part of GNU Zebra.
  5. *
  6. * GNU Zebra is free software; you can redistribute it and/or modify it
  7. * under the terms of the GNU General Public License as published by the
  8. * Free Software Foundation; either version 2, or (at your option) any
  9. * later version.
  10. *
  11. * GNU Zebra is distributed in the hope that it will be useful, but
  12. * WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  14. * General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with GNU Zebra; see the file COPYING. If not, write to the
  18. * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
  19. * Boston, MA 02111-1307, USA.
  20. */
  21. #include <zebra.h>
  22. #include "log.h"
  23. #include "memory.h"
  24. #include "prefix.h"
  25. #include "table.h"
  26. #include "vty.h"
  27. #include "command.h"
  28. #include "linklist.h"
  29. #include "ospf6_proto.h"
  30. #include "ospf6_lsa.h"
  31. #include "ospf6_lsdb.h"
  32. #include "ospf6_route.h"
  33. #include "ospf6_top.h"
  34. #include "ospf6_area.h"
  35. #include "ospf6_interface.h"
  36. #include "ospf6d.h"
  37. unsigned char conf_debug_ospf6_route = 0;
  38. static char *
  39. ospf6_route_table_name (struct ospf6_route_table *table)
  40. {
  41. static char name[32];
  42. switch (table->scope_type)
  43. {
  44. case OSPF6_SCOPE_TYPE_GLOBAL:
  45. {
  46. switch (table->table_type)
  47. {
  48. case OSPF6_TABLE_TYPE_ROUTES:
  49. snprintf (name, sizeof (name), "global route table");
  50. break;
  51. case OSPF6_TABLE_TYPE_BORDER_ROUTERS:
  52. snprintf (name, sizeof (name), "global brouter table");
  53. break;
  54. case OSPF6_TABLE_TYPE_EXTERNAL_ROUTES:
  55. snprintf (name, sizeof (name), "global external table");
  56. break;
  57. default:
  58. snprintf (name, sizeof (name), "global unknown table");
  59. break;
  60. }
  61. }
  62. break;
  63. case OSPF6_SCOPE_TYPE_AREA:
  64. {
  65. struct ospf6_area *oa = (struct ospf6_area *) table->scope;
  66. switch (table->table_type)
  67. {
  68. case OSPF6_TABLE_TYPE_SPF_RESULTS:
  69. snprintf (name, sizeof (name),
  70. "area %s spf table", oa->name);
  71. break;
  72. case OSPF6_TABLE_TYPE_ROUTES:
  73. snprintf (name, sizeof (name),
  74. "area %s route table", oa->name);
  75. break;
  76. case OSPF6_TABLE_TYPE_PREFIX_RANGES:
  77. snprintf (name, sizeof (name),
  78. "area %s range table", oa->name);
  79. break;
  80. case OSPF6_TABLE_TYPE_SUMMARY_PREFIXES:
  81. snprintf (name, sizeof (name),
  82. "area %s summary prefix table", oa->name);
  83. break;
  84. case OSPF6_TABLE_TYPE_SUMMARY_ROUTERS:
  85. snprintf (name, sizeof (name),
  86. "area %s summary router table", oa->name);
  87. break;
  88. default:
  89. snprintf (name, sizeof (name),
  90. "area %s unknown table", oa->name);
  91. break;
  92. }
  93. }
  94. break;
  95. case OSPF6_SCOPE_TYPE_INTERFACE:
  96. {
  97. struct ospf6_interface *oi = (struct ospf6_interface *) table->scope;
  98. switch (table->table_type)
  99. {
  100. case OSPF6_TABLE_TYPE_CONNECTED_ROUTES:
  101. snprintf (name, sizeof (name), "interface %s connected table",
  102. oi->interface->name);
  103. break;
  104. default:
  105. snprintf (name, sizeof (name), "interface %s unknown table",
  106. oi->interface->name);
  107. break;
  108. }
  109. }
  110. break;
  111. default:
  112. {
  113. switch (table->table_type)
  114. {
  115. case OSPF6_TABLE_TYPE_SPF_RESULTS:
  116. snprintf (name, sizeof (name), "temporary spf table");
  117. break;
  118. default:
  119. snprintf (name, sizeof (name), "temporary unknown table");
  120. break;
  121. }
  122. }
  123. break;
  124. }
  125. return name;
  126. }
  127. void
  128. ospf6_linkstate_prefix (u_int32_t adv_router, u_int32_t id,
  129. struct prefix *prefix)
  130. {
  131. memset (prefix, 0, sizeof (struct prefix));
  132. prefix->family = AF_INET6;
  133. prefix->prefixlen = 64;
  134. memcpy (&prefix->u.prefix6.s6_addr[0], &adv_router, 4);
  135. memcpy (&prefix->u.prefix6.s6_addr[4], &id, 4);
  136. }
  137. void
  138. ospf6_linkstate_prefix2str (struct prefix *prefix, char *buf, int size)
  139. {
  140. u_int32_t adv_router, id;
  141. char adv_router_str[16], id_str[16];
  142. memcpy (&adv_router, &prefix->u.prefix6.s6_addr[0], 4);
  143. memcpy (&id, &prefix->u.prefix6.s6_addr[4], 4);
  144. inet_ntop (AF_INET, &adv_router, adv_router_str, sizeof (adv_router_str));
  145. inet_ntop (AF_INET, &id, id_str, sizeof (id_str));
  146. if (ntohl (id))
  147. snprintf (buf, size, "%s Net-ID: %s", adv_router_str, id_str);
  148. else
  149. snprintf (buf, size, "%s", adv_router_str);
  150. }
  151. /* Global strings for logging */
  152. const char *ospf6_dest_type_str[OSPF6_DEST_TYPE_MAX] =
  153. { "Unknown", "Router", "Network", "Discard", "Linkstate", "AddressRange", };
  154. const char *ospf6_dest_type_substr[OSPF6_DEST_TYPE_MAX] =
  155. { "?", "R", "N", "D", "L", "A", };
  156. const char *ospf6_path_type_str[OSPF6_PATH_TYPE_MAX] =
  157. { "Unknown", "Intra-Area", "Inter-Area", "External-1", "External-2", };
  158. const char *ospf6_path_type_substr[OSPF6_PATH_TYPE_MAX] =
  159. { "??", "IA", "IE", "E1", "E2", };
  160. struct ospf6_route *
  161. ospf6_route_create (void)
  162. {
  163. struct ospf6_route *route;
  164. route = XCALLOC (MTYPE_OSPF6_ROUTE, sizeof (struct ospf6_route));
  165. return route;
  166. }
  167. void
  168. ospf6_route_delete (struct ospf6_route *route)
  169. {
  170. XFREE (MTYPE_OSPF6_ROUTE, route);
  171. }
  172. struct ospf6_route *
  173. ospf6_route_copy (struct ospf6_route *route)
  174. {
  175. struct ospf6_route *new;
  176. new = ospf6_route_create ();
  177. memcpy (new, route, sizeof (struct ospf6_route));
  178. new->rnode = NULL;
  179. new->prev = NULL;
  180. new->next = NULL;
  181. new->table = NULL;
  182. new->lock = 0;
  183. return new;
  184. }
  185. void
  186. ospf6_route_lock (struct ospf6_route *route)
  187. {
  188. route->lock++;
  189. }
  190. void
  191. ospf6_route_unlock (struct ospf6_route *route)
  192. {
  193. assert (route->lock > 0);
  194. route->lock--;
  195. if (route->lock == 0)
  196. {
  197. /* Can't detach from the table until here
  198. because ospf6_route_next () will use
  199. the 'route->table' pointer for logging */
  200. route->table = NULL;
  201. ospf6_route_delete (route);
  202. }
  203. }
  204. /* Route compare function. If ra is more preferred, it returns
  205. less than 0. If rb is more preferred returns greater than 0.
  206. Otherwise (neither one is preferred), returns 0 */
  207. static int
  208. ospf6_route_cmp (struct ospf6_route *ra, struct ospf6_route *rb)
  209. {
  210. assert (ospf6_route_is_same (ra, rb));
  211. assert (OSPF6_PATH_TYPE_NONE < ra->path.type &&
  212. ra->path.type < OSPF6_PATH_TYPE_MAX);
  213. assert (OSPF6_PATH_TYPE_NONE < rb->path.type &&
  214. rb->path.type < OSPF6_PATH_TYPE_MAX);
  215. if (ra->type != rb->type)
  216. return (ra->type - rb->type);
  217. if (ra->path.area_id != rb->path.area_id)
  218. return (ntohl (ra->path.area_id) - ntohl (rb->path.area_id));
  219. if (ra->path.type != rb->path.type)
  220. return (ra->path.type - rb->path.type);
  221. if (ra->path.type == OSPF6_PATH_TYPE_EXTERNAL2)
  222. {
  223. if (ra->path.cost_e2 != rb->path.cost_e2)
  224. return (ra->path.cost_e2 - rb->path.cost_e2);
  225. }
  226. else
  227. {
  228. if (ra->path.cost != rb->path.cost)
  229. return (ra->path.cost - rb->path.cost);
  230. }
  231. return 0;
  232. }
  233. struct ospf6_route *
  234. ospf6_route_lookup (struct prefix *prefix,
  235. struct ospf6_route_table *table)
  236. {
  237. struct route_node *node;
  238. struct ospf6_route *route;
  239. node = route_node_lookup (table->table, prefix);
  240. if (node == NULL)
  241. return NULL;
  242. route = (struct ospf6_route *) node->info;
  243. return route;
  244. }
  245. struct ospf6_route *
  246. ospf6_route_lookup_identical (struct ospf6_route *route,
  247. struct ospf6_route_table *table)
  248. {
  249. struct ospf6_route *target;
  250. for (target = ospf6_route_lookup (&route->prefix, table);
  251. target; target = target->next)
  252. {
  253. if (ospf6_route_is_identical (target, route))
  254. return target;
  255. }
  256. return NULL;
  257. }
  258. struct ospf6_route *
  259. ospf6_route_lookup_bestmatch (struct prefix *prefix,
  260. struct ospf6_route_table *table)
  261. {
  262. struct route_node *node;
  263. struct ospf6_route *route;
  264. node = route_node_match (table->table, prefix);
  265. if (node == NULL)
  266. return NULL;
  267. route_unlock_node (node);
  268. route = (struct ospf6_route *) node->info;
  269. return route;
  270. }
  271. #ifndef NDEBUG
  272. static void
  273. route_table_assert (struct ospf6_route_table *table)
  274. {
  275. struct ospf6_route *prev, *r, *next;
  276. char buf[64];
  277. unsigned int link_error = 0, num = 0;
  278. r = ospf6_route_head (table);
  279. prev = NULL;
  280. while (r)
  281. {
  282. if (r->prev != prev)
  283. link_error++;
  284. next = ospf6_route_next (r);
  285. if (r->next != next)
  286. link_error++;
  287. prev = r;
  288. r = next;
  289. }
  290. for (r = ospf6_route_head (table); r; r = ospf6_route_next (r))
  291. num++;
  292. if (link_error == 0 && num == table->count)
  293. return;
  294. zlog_err ("PANIC !!");
  295. zlog_err ("Something has gone wrong with ospf6_route_table[%p]", table);
  296. zlog_debug ("table count = %d, real number = %d", table->count, num);
  297. zlog_debug ("DUMP START");
  298. for (r = ospf6_route_head (table); r; r = ospf6_route_next (r))
  299. {
  300. prefix2str (&r->prefix, buf, sizeof (buf));
  301. zlog_info ("%p<-[%p]->%p : %s", r->prev, r, r->next, buf);
  302. }
  303. zlog_debug ("DUMP END");
  304. assert (link_error == 0 && num == table->count);
  305. }
  306. #define ospf6_route_table_assert(t) (route_table_assert (t))
  307. #else
  308. #define ospf6_route_table_assert(t) ((void) 0)
  309. #endif /*NDEBUG*/
  310. struct ospf6_route *
  311. ospf6_route_add (struct ospf6_route *route,
  312. struct ospf6_route_table *table)
  313. {
  314. struct route_node *node, *nextnode, *prevnode;
  315. struct ospf6_route *current = NULL;
  316. struct ospf6_route *prev = NULL, *old = NULL, *next = NULL;
  317. char buf[64];
  318. struct timeval now;
  319. assert (route->rnode == NULL);
  320. assert (route->lock == 0);
  321. assert (route->next == NULL);
  322. assert (route->prev == NULL);
  323. if (route->type == OSPF6_DEST_TYPE_LINKSTATE)
  324. ospf6_linkstate_prefix2str (&route->prefix, buf, sizeof (buf));
  325. else
  326. prefix2str (&route->prefix, buf, sizeof (buf));
  327. if (IS_OSPF6_DEBUG_ROUTE (MEMORY))
  328. zlog_debug ("%s %p: route add %p: %s", ospf6_route_table_name (table),
  329. table, route, buf);
  330. else if (IS_OSPF6_DEBUG_ROUTE (TABLE))
  331. zlog_debug ("%s: route add: %s", ospf6_route_table_name (table), buf);
  332. quagga_gettime (QUAGGA_CLK_MONOTONIC, &now);
  333. node = route_node_get (table->table, &route->prefix);
  334. route->rnode = node;
  335. /* find place to insert */
  336. for (current = node->info; current; current = current->next)
  337. {
  338. if (! ospf6_route_is_same (current, route))
  339. next = current;
  340. else if (current->type != route->type)
  341. prev = current;
  342. else if (ospf6_route_is_same_origin (current, route))
  343. old = current;
  344. else if (ospf6_route_cmp (current, route) > 0)
  345. next = current;
  346. else
  347. prev = current;
  348. if (old || next)
  349. break;
  350. }
  351. if (old)
  352. {
  353. /* if route does not actually change, return unchanged */
  354. if (ospf6_route_is_identical (old, route))
  355. {
  356. if (IS_OSPF6_DEBUG_ROUTE (MEMORY))
  357. zlog_debug ("%s %p: route add %p: needless update of %p",
  358. ospf6_route_table_name (table), table, route, old);
  359. else if (IS_OSPF6_DEBUG_ROUTE (TABLE))
  360. zlog_debug ("%s: route add: needless update",
  361. ospf6_route_table_name (table));
  362. ospf6_route_delete (route);
  363. SET_FLAG (old->flag, OSPF6_ROUTE_ADD);
  364. ospf6_route_table_assert (table);
  365. return old;
  366. }
  367. if (IS_OSPF6_DEBUG_ROUTE (MEMORY))
  368. zlog_debug ("%s %p: route add %p: update of %p",
  369. ospf6_route_table_name (table), table, route, old);
  370. else if (IS_OSPF6_DEBUG_ROUTE (TABLE))
  371. zlog_debug ("%s: route add: update",
  372. ospf6_route_table_name (table));
  373. /* replace old one if exists */
  374. if (node->info == old)
  375. {
  376. node->info = route;
  377. SET_FLAG (route->flag, OSPF6_ROUTE_BEST);
  378. }
  379. if (old->prev)
  380. old->prev->next = route;
  381. route->prev = old->prev;
  382. if (old->next)
  383. old->next->prev = route;
  384. route->next = old->next;
  385. route->installed = old->installed;
  386. route->changed = now;
  387. assert (route->table == NULL);
  388. route->table = table;
  389. ospf6_route_unlock (old); /* will be deleted later */
  390. ospf6_route_lock (route);
  391. SET_FLAG (route->flag, OSPF6_ROUTE_CHANGE);
  392. ospf6_route_table_assert (table);
  393. if (table->hook_add)
  394. (*table->hook_add) (route);
  395. return route;
  396. }
  397. /* insert if previous or next node found */
  398. if (prev || next)
  399. {
  400. if (IS_OSPF6_DEBUG_ROUTE (MEMORY))
  401. zlog_debug ("%s %p: route add %p: another path: prev %p, next %p",
  402. ospf6_route_table_name (table), table, route, prev, next);
  403. else if (IS_OSPF6_DEBUG_ROUTE (TABLE))
  404. zlog_debug ("%s: route add: another path found",
  405. ospf6_route_table_name (table));
  406. if (prev == NULL)
  407. prev = next->prev;
  408. if (next == NULL)
  409. next = prev->next;
  410. if (prev)
  411. prev->next = route;
  412. route->prev = prev;
  413. if (next)
  414. next->prev = route;
  415. route->next = next;
  416. if (node->info == next)
  417. {
  418. assert (next->rnode == node);
  419. node->info = route;
  420. UNSET_FLAG (next->flag, OSPF6_ROUTE_BEST);
  421. SET_FLAG (route->flag, OSPF6_ROUTE_BEST);
  422. if (IS_OSPF6_DEBUG_ROUTE (MEMORY))
  423. zlog_info ("%s %p: route add %p: replacing previous best: %p",
  424. ospf6_route_table_name (table), table, route, next);
  425. }
  426. route->installed = now;
  427. route->changed = now;
  428. assert (route->table == NULL);
  429. route->table = table;
  430. ospf6_route_lock (route);
  431. table->count++;
  432. ospf6_route_table_assert (table);
  433. SET_FLAG (route->flag, OSPF6_ROUTE_ADD);
  434. if (table->hook_add)
  435. (*table->hook_add) (route);
  436. return route;
  437. }
  438. /* Else, this is the brand new route regarding to the prefix */
  439. if (IS_OSPF6_DEBUG_ROUTE (MEMORY))
  440. zlog_debug ("%s %p: route add %p: brand new route",
  441. ospf6_route_table_name (table), table, route);
  442. else if (IS_OSPF6_DEBUG_ROUTE (TABLE))
  443. zlog_debug ("%s: route add: brand new route",
  444. ospf6_route_table_name (table));
  445. assert (node->info == NULL);
  446. node->info = route;
  447. SET_FLAG (route->flag, OSPF6_ROUTE_BEST);
  448. ospf6_route_lock (route);
  449. route->installed = now;
  450. route->changed = now;
  451. assert (route->table == NULL);
  452. route->table = table;
  453. /* lookup real existing next route */
  454. nextnode = node;
  455. route_lock_node (nextnode);
  456. do {
  457. nextnode = route_next (nextnode);
  458. } while (nextnode && nextnode->info == NULL);
  459. /* set next link */
  460. if (nextnode == NULL)
  461. route->next = NULL;
  462. else
  463. {
  464. route_unlock_node (nextnode);
  465. next = nextnode->info;
  466. route->next = next;
  467. next->prev = route;
  468. }
  469. /* lookup real existing prev route */
  470. prevnode = node;
  471. route_lock_node (prevnode);
  472. do {
  473. prevnode = route_prev (prevnode);
  474. } while (prevnode && prevnode->info == NULL);
  475. /* set prev link */
  476. if (prevnode == NULL)
  477. route->prev = NULL;
  478. else
  479. {
  480. route_unlock_node (prevnode);
  481. prev = prevnode->info;
  482. while (prev->next && ospf6_route_is_same (prev, prev->next))
  483. prev = prev->next;
  484. route->prev = prev;
  485. prev->next = route;
  486. }
  487. table->count++;
  488. ospf6_route_table_assert (table);
  489. SET_FLAG (route->flag, OSPF6_ROUTE_ADD);
  490. if (table->hook_add)
  491. (*table->hook_add) (route);
  492. return route;
  493. }
  494. void
  495. ospf6_route_remove (struct ospf6_route *route,
  496. struct ospf6_route_table *table)
  497. {
  498. struct route_node *node;
  499. struct ospf6_route *current;
  500. char buf[64];
  501. if (route->type == OSPF6_DEST_TYPE_LINKSTATE)
  502. ospf6_linkstate_prefix2str (&route->prefix, buf, sizeof (buf));
  503. else
  504. prefix2str (&route->prefix, buf, sizeof (buf));
  505. if (IS_OSPF6_DEBUG_ROUTE (MEMORY))
  506. zlog_debug ("%s %p: route remove %p: %s",
  507. ospf6_route_table_name (table), table, route, buf);
  508. else if (IS_OSPF6_DEBUG_ROUTE (TABLE))
  509. zlog_debug ("%s: route remove: %s", ospf6_route_table_name (table), buf);
  510. node = route_node_lookup (table->table, &route->prefix);
  511. assert (node);
  512. /* find the route to remove, making sure that the route pointer
  513. is from the route table. */
  514. current = node->info;
  515. while (current && ospf6_route_is_same (current, route))
  516. {
  517. if (current == route)
  518. break;
  519. current = current->next;
  520. }
  521. assert (current == route);
  522. /* adjust doubly linked list */
  523. if (route->prev)
  524. route->prev->next = route->next;
  525. if (route->next)
  526. route->next->prev = route->prev;
  527. if (node->info == route)
  528. {
  529. if (route->next && ospf6_route_is_same (route->next, route))
  530. {
  531. node->info = route->next;
  532. SET_FLAG (route->next->flag, OSPF6_ROUTE_BEST);
  533. }
  534. else
  535. node->info = NULL; /* should unlock route_node here ? */
  536. }
  537. table->count--;
  538. ospf6_route_table_assert (table);
  539. SET_FLAG (route->flag, OSPF6_ROUTE_WAS_REMOVED);
  540. if (table->hook_remove)
  541. (*table->hook_remove) (route);
  542. ospf6_route_unlock (route);
  543. }
  544. struct ospf6_route *
  545. ospf6_route_head (struct ospf6_route_table *table)
  546. {
  547. struct route_node *node;
  548. struct ospf6_route *route;
  549. node = route_top (table->table);
  550. if (node == NULL)
  551. return NULL;
  552. /* skip to the real existing entry */
  553. while (node && node->info == NULL)
  554. node = route_next (node);
  555. if (node == NULL)
  556. return NULL;
  557. route_unlock_node (node);
  558. assert (node->info);
  559. route = (struct ospf6_route *) node->info;
  560. assert (route->prev == NULL);
  561. assert (route->table == table);
  562. ospf6_route_lock (route);
  563. if (IS_OSPF6_DEBUG_ROUTE (MEMORY))
  564. zlog_info ("%s %p: route head: %p<-[%p]->%p",
  565. ospf6_route_table_name (table), table,
  566. route->prev, route, route->next);
  567. return route;
  568. }
  569. struct ospf6_route *
  570. ospf6_route_next (struct ospf6_route *route)
  571. {
  572. struct ospf6_route *next = route->next;
  573. if (IS_OSPF6_DEBUG_ROUTE (MEMORY))
  574. zlog_info ("%s %p: route next: %p<-[%p]->%p",
  575. ospf6_route_table_name (route->table), route->table,
  576. route->prev, route, route->next);
  577. ospf6_route_unlock (route);
  578. if (next)
  579. ospf6_route_lock (next);
  580. return next;
  581. }
  582. struct ospf6_route *
  583. ospf6_route_best_next (struct ospf6_route *route)
  584. {
  585. struct route_node *rnode;
  586. struct ospf6_route *next;
  587. rnode = route->rnode;
  588. route_lock_node (rnode);
  589. rnode = route_next (rnode);
  590. while (rnode && rnode->info == NULL)
  591. rnode = route_next (rnode);
  592. if (rnode == NULL)
  593. return NULL;
  594. route_unlock_node (rnode);
  595. assert (rnode->info);
  596. next = (struct ospf6_route *) rnode->info;
  597. ospf6_route_unlock (route);
  598. ospf6_route_lock (next);
  599. return next;
  600. }
  601. struct ospf6_route *
  602. ospf6_route_match_head (struct prefix *prefix,
  603. struct ospf6_route_table *table)
  604. {
  605. struct route_node *node;
  606. struct ospf6_route *route;
  607. /* Walk down tree. */
  608. node = table->table->top;
  609. while (node && node->p.prefixlen < prefix->prefixlen &&
  610. prefix_match (&node->p, prefix))
  611. node = node->link[prefix_bit(&prefix->u.prefix, node->p.prefixlen)];
  612. if (node)
  613. route_lock_node (node);
  614. while (node && node->info == NULL)
  615. node = route_next (node);
  616. if (node == NULL)
  617. return NULL;
  618. route_unlock_node (node);
  619. if (! prefix_match (prefix, &node->p))
  620. return NULL;
  621. route = node->info;
  622. ospf6_route_lock (route);
  623. return route;
  624. }
  625. struct ospf6_route *
  626. ospf6_route_match_next (struct prefix *prefix,
  627. struct ospf6_route *route)
  628. {
  629. struct ospf6_route *next;
  630. next = ospf6_route_next (route);
  631. if (next && ! prefix_match (prefix, &next->prefix))
  632. {
  633. ospf6_route_unlock (next);
  634. next = NULL;
  635. }
  636. return next;
  637. }
  638. void
  639. ospf6_route_remove_all (struct ospf6_route_table *table)
  640. {
  641. struct ospf6_route *route;
  642. for (route = ospf6_route_head (table); route;
  643. route = ospf6_route_next (route))
  644. ospf6_route_remove (route, table);
  645. }
  646. struct ospf6_route_table *
  647. ospf6_route_table_create (int s, int t)
  648. {
  649. struct ospf6_route_table *new;
  650. new = XCALLOC (MTYPE_OSPF6_ROUTE, sizeof (struct ospf6_route_table));
  651. new->table = route_table_init ();
  652. new->scope_type = s;
  653. new->table_type = t;
  654. return new;
  655. }
  656. void
  657. ospf6_route_table_delete (struct ospf6_route_table *table)
  658. {
  659. ospf6_route_remove_all (table);
  660. route_table_finish (table->table);
  661. XFREE (MTYPE_OSPF6_ROUTE, table);
  662. }
  663. /* VTY commands */
  664. void
  665. ospf6_route_show (struct vty *vty, struct ospf6_route *route)
  666. {
  667. int i;
  668. char destination[64], nexthop[64];
  669. char duration[16], ifname[IFNAMSIZ];
  670. struct timeval now, res;
  671. quagga_gettime (QUAGGA_CLK_MONOTONIC, &now);
  672. timersub (&now, &route->changed, &res);
  673. timerstring (&res, duration, sizeof (duration));
  674. /* destination */
  675. if (route->type == OSPF6_DEST_TYPE_LINKSTATE)
  676. ospf6_linkstate_prefix2str (&route->prefix, destination,
  677. sizeof (destination));
  678. else if (route->type == OSPF6_DEST_TYPE_ROUTER)
  679. inet_ntop (route->prefix.family, &route->prefix.u.prefix,
  680. destination, sizeof (destination));
  681. else
  682. prefix2str (&route->prefix, destination, sizeof (destination));
  683. /* nexthop */
  684. inet_ntop (AF_INET6, &route->nexthop[0].address, nexthop,
  685. sizeof (nexthop));
  686. if (! if_indextoname (route->nexthop[0].ifindex, ifname))
  687. snprintf (ifname, sizeof (ifname), "%d", route->nexthop[0].ifindex);
  688. vty_out (vty, "%c%1s %2s %-30s %-25s %6.*s %s%s",
  689. (ospf6_route_is_best (route) ? '*' : ' '),
  690. OSPF6_DEST_TYPE_SUBSTR (route->type),
  691. OSPF6_PATH_TYPE_SUBSTR (route->path.type),
  692. destination, nexthop, IFNAMSIZ, ifname, duration, VNL);
  693. for (i = 1; ospf6_nexthop_is_set (&route->nexthop[i]) &&
  694. i < OSPF6_MULTI_PATH_LIMIT; i++)
  695. {
  696. /* nexthop */
  697. inet_ntop (AF_INET6, &route->nexthop[i].address, nexthop,
  698. sizeof (nexthop));
  699. if (! if_indextoname (route->nexthop[i].ifindex, ifname))
  700. snprintf (ifname, sizeof (ifname), "%d", route->nexthop[i].ifindex);
  701. vty_out (vty, "%c%1s %2s %-30s %-25s %6.*s %s%s",
  702. ' ', "", "", "", nexthop, IFNAMSIZ, ifname, "", VNL);
  703. }
  704. }
  705. void
  706. ospf6_route_show_detail (struct vty *vty, struct ospf6_route *route)
  707. {
  708. char destination[64], nexthop[64], ifname[IFNAMSIZ];
  709. char area_id[16], id[16], adv_router[16], capa[16], options[16];
  710. struct timeval now, res;
  711. char duration[16];
  712. int i;
  713. quagga_gettime (QUAGGA_CLK_MONOTONIC, &now);
  714. /* destination */
  715. if (route->type == OSPF6_DEST_TYPE_LINKSTATE)
  716. ospf6_linkstate_prefix2str (&route->prefix, destination,
  717. sizeof (destination));
  718. else if (route->type == OSPF6_DEST_TYPE_ROUTER)
  719. inet_ntop (route->prefix.family, &route->prefix.u.prefix,
  720. destination, sizeof (destination));
  721. else
  722. prefix2str (&route->prefix, destination, sizeof (destination));
  723. vty_out (vty, "Destination: %s%s", destination, VNL);
  724. /* destination type */
  725. vty_out (vty, "Destination type: %s%s",
  726. OSPF6_DEST_TYPE_NAME (route->type),
  727. VNL);
  728. /* Time */
  729. timersub (&now, &route->installed, &res);
  730. timerstring (&res, duration, sizeof (duration));
  731. vty_out (vty, "Installed Time: %s ago%s", duration, VNL);
  732. timersub (&now, &route->changed, &res);
  733. timerstring (&res, duration, sizeof (duration));
  734. vty_out (vty, " Changed Time: %s ago%s", duration, VNL);
  735. /* Debugging info */
  736. vty_out (vty, "Lock: %d Flags: %s%s%s%s%s", route->lock,
  737. (CHECK_FLAG (route->flag, OSPF6_ROUTE_BEST) ? "B" : "-"),
  738. (CHECK_FLAG (route->flag, OSPF6_ROUTE_ADD) ? "A" : "-"),
  739. (CHECK_FLAG (route->flag, OSPF6_ROUTE_REMOVE) ? "R" : "-"),
  740. (CHECK_FLAG (route->flag, OSPF6_ROUTE_CHANGE) ? "C" : "-"),
  741. VNL);
  742. vty_out (vty, "Memory: prev: %p this: %p next: %p%s",
  743. route->prev, route, route->next, VNL);
  744. /* Path section */
  745. /* Area-ID */
  746. inet_ntop (AF_INET, &route->path.area_id, area_id, sizeof (area_id));
  747. vty_out (vty, "Associated Area: %s%s", area_id, VNL);
  748. /* Path type */
  749. vty_out (vty, "Path Type: %s%s",
  750. OSPF6_PATH_TYPE_NAME (route->path.type), VNL);
  751. /* LS Origin */
  752. inet_ntop (AF_INET, &route->path.origin.id, id, sizeof (id));
  753. inet_ntop (AF_INET, &route->path.origin.adv_router, adv_router,
  754. sizeof (adv_router));
  755. vty_out (vty, "LS Origin: %s Id: %s Adv: %s%s",
  756. ospf6_lstype_name (route->path.origin.type),
  757. id, adv_router, VNL);
  758. /* Options */
  759. ospf6_options_printbuf (route->path.options, options, sizeof (options));
  760. vty_out (vty, "Options: %s%s", options, VNL);
  761. /* Router Bits */
  762. ospf6_capability_printbuf (route->path.router_bits, capa, sizeof (capa));
  763. vty_out (vty, "Router Bits: %s%s", capa, VNL);
  764. /* Prefix Options */
  765. vty_out (vty, "Prefix Options: xxx%s", VNL);
  766. /* Metrics */
  767. vty_out (vty, "Metric Type: %d%s", route->path.metric_type,
  768. VNL);
  769. vty_out (vty, "Metric: %d (%d)%s",
  770. route->path.cost, route->path.cost_e2, VNL);
  771. /* Nexthops */
  772. vty_out (vty, "Nexthop:%s", VNL);
  773. for (i = 0; ospf6_nexthop_is_set (&route->nexthop[i]) &&
  774. i < OSPF6_MULTI_PATH_LIMIT; i++)
  775. {
  776. /* nexthop */
  777. inet_ntop (AF_INET6, &route->nexthop[i].address, nexthop,
  778. sizeof (nexthop));
  779. if (! if_indextoname (route->nexthop[i].ifindex, ifname))
  780. snprintf (ifname, sizeof (ifname), "%d", route->nexthop[i].ifindex);
  781. vty_out (vty, " %s %.*s%s", nexthop, IFNAMSIZ, ifname, VNL);
  782. }
  783. vty_out (vty, "%s", VNL);
  784. }
  785. static void
  786. ospf6_route_show_table_summary (struct vty *vty,
  787. struct ospf6_route_table *table)
  788. {
  789. struct ospf6_route *route, *prev = NULL;
  790. int i, pathtype[OSPF6_PATH_TYPE_MAX];
  791. unsigned int number = 0;
  792. int nhinval = 0, ecmp = 0;
  793. int alternative = 0, destination = 0;
  794. for (i = 0; i < OSPF6_PATH_TYPE_MAX; i++)
  795. pathtype[i] = 0;
  796. for (route = ospf6_route_head (table); route;
  797. route = ospf6_route_next (route))
  798. {
  799. if (prev == NULL || ! ospf6_route_is_same (prev, route))
  800. destination++;
  801. else
  802. alternative++;
  803. if (! ospf6_nexthop_is_set (&route->nexthop[0]))
  804. nhinval++;
  805. else if (ospf6_nexthop_is_set (&route->nexthop[1]))
  806. ecmp++;
  807. pathtype[route->path.type]++;
  808. number++;
  809. prev = route;
  810. }
  811. assert (number == table->count);
  812. vty_out (vty, "Number of OSPFv3 routes: %d%s", number, VNL);
  813. vty_out (vty, "Number of Destination: %d%s", destination, VNL);
  814. vty_out (vty, "Number of Alternative routes: %d%s", alternative, VNL);
  815. vty_out (vty, "Number of Equal Cost Multi Path: %d%s", ecmp, VNL);
  816. for (i = OSPF6_PATH_TYPE_INTRA; i <= OSPF6_PATH_TYPE_EXTERNAL2; i++)
  817. {
  818. vty_out (vty, "Number of %s routes: %d%s",
  819. OSPF6_PATH_TYPE_NAME (i), pathtype[i], VNL);
  820. }
  821. }
  822. static void
  823. ospf6_route_show_table_prefix (struct vty *vty,
  824. struct prefix *prefix,
  825. struct ospf6_route_table *table)
  826. {
  827. struct ospf6_route *route;
  828. route = ospf6_route_lookup (prefix, table);
  829. if (route == NULL)
  830. return;
  831. ospf6_route_lock (route);
  832. while (route && ospf6_route_is_prefix (prefix, route))
  833. {
  834. /* Specifying a prefix will always display details */
  835. ospf6_route_show_detail (vty, route);
  836. route = ospf6_route_next (route);
  837. }
  838. if (route)
  839. ospf6_route_unlock (route);
  840. }
  841. static void
  842. ospf6_route_show_table_address (struct vty *vty,
  843. struct prefix *prefix,
  844. struct ospf6_route_table *table)
  845. {
  846. struct ospf6_route *route;
  847. route = ospf6_route_lookup_bestmatch (prefix, table);
  848. if (route == NULL)
  849. return;
  850. prefix = &route->prefix;
  851. ospf6_route_lock (route);
  852. while (route && ospf6_route_is_prefix (prefix, route))
  853. {
  854. /* Specifying a prefix will always display details */
  855. ospf6_route_show_detail (vty, route);
  856. route = ospf6_route_next (route);
  857. }
  858. if (route)
  859. ospf6_route_unlock (route);
  860. }
  861. static void
  862. ospf6_route_show_table_match (struct vty *vty, int detail,
  863. struct prefix *prefix,
  864. struct ospf6_route_table *table)
  865. {
  866. struct ospf6_route *route;
  867. assert (prefix->family);
  868. route = ospf6_route_match_head (prefix, table);
  869. while (route)
  870. {
  871. if (detail)
  872. ospf6_route_show_detail (vty, route);
  873. else
  874. ospf6_route_show (vty, route);
  875. route = ospf6_route_match_next (prefix, route);
  876. }
  877. }
  878. static void
  879. ospf6_route_show_table_type (struct vty *vty, int detail, u_char type,
  880. struct ospf6_route_table *table)
  881. {
  882. struct ospf6_route *route;
  883. route = ospf6_route_head (table);
  884. while (route)
  885. {
  886. if (route->path.type == type)
  887. {
  888. if (detail)
  889. ospf6_route_show_detail (vty, route);
  890. else
  891. ospf6_route_show (vty, route);
  892. }
  893. route = ospf6_route_next (route);
  894. }
  895. }
  896. static void
  897. ospf6_route_show_table (struct vty *vty, int detail,
  898. struct ospf6_route_table *table)
  899. {
  900. struct ospf6_route *route;
  901. route = ospf6_route_head (table);
  902. while (route)
  903. {
  904. if (detail)
  905. ospf6_route_show_detail (vty, route);
  906. else
  907. ospf6_route_show (vty, route);
  908. route = ospf6_route_next (route);
  909. }
  910. }
  911. int
  912. ospf6_route_table_show (struct vty *vty, int argc, const char *argv[],
  913. struct ospf6_route_table *table)
  914. {
  915. int summary = 0;
  916. int match = 0;
  917. int detail = 0;
  918. int slash = 0;
  919. int isprefix = 0;
  920. int i, ret;
  921. struct prefix prefix;
  922. u_char type = 0;
  923. memset (&prefix, 0, sizeof (struct prefix));
  924. for (i = 0; i < argc; i++)
  925. {
  926. if (! strcmp (argv[i], "summary"))
  927. {
  928. summary++;
  929. continue;
  930. }
  931. if (! strcmp (argv[i], "intra-area"))
  932. {
  933. type = OSPF6_PATH_TYPE_INTRA;
  934. continue;
  935. }
  936. if (! strcmp (argv[i], "inter-area"))
  937. {
  938. type = OSPF6_PATH_TYPE_INTER;
  939. continue;
  940. }
  941. if (! strcmp (argv[i], "external-1"))
  942. {
  943. type = OSPF6_PATH_TYPE_EXTERNAL1;
  944. continue;
  945. }
  946. if (! strcmp (argv[i], "external-2"))
  947. {
  948. type = OSPF6_PATH_TYPE_EXTERNAL2;
  949. continue;
  950. }
  951. if (! strcmp (argv[i], "detail"))
  952. {
  953. detail++;
  954. continue;
  955. }
  956. if (! strcmp (argv[i], "match"))
  957. {
  958. match++;
  959. continue;
  960. }
  961. ret = str2prefix (argv[i], &prefix);
  962. if (ret == 1 && prefix.family == AF_INET6)
  963. {
  964. isprefix++;
  965. if (strchr (argv[i], '/'))
  966. slash++;
  967. continue;
  968. }
  969. vty_out (vty, "Malformed argument: %s%s", argv[i], VNL);
  970. return CMD_SUCCESS;
  971. }
  972. /* Give summary of this route table */
  973. if (summary)
  974. {
  975. ospf6_route_show_table_summary (vty, table);
  976. return CMD_SUCCESS;
  977. }
  978. /* Give exact prefix-match route */
  979. if (isprefix && ! match)
  980. {
  981. /* If exact address, give best matching route */
  982. if (! slash)
  983. ospf6_route_show_table_address (vty, &prefix, table);
  984. else
  985. ospf6_route_show_table_prefix (vty, &prefix, table);
  986. return CMD_SUCCESS;
  987. }
  988. if (match)
  989. ospf6_route_show_table_match (vty, detail, &prefix, table);
  990. else if (type)
  991. ospf6_route_show_table_type (vty, detail, type, table);
  992. else
  993. ospf6_route_show_table (vty, detail, table);
  994. return CMD_SUCCESS;
  995. }
  996. static void
  997. ospf6_linkstate_show_header (struct vty *vty)
  998. {
  999. vty_out (vty, "%-7s %-15s %-15s %-8s %-14s %s%s",
  1000. "Type", "Router-ID", "Net-ID", "Rtr-Bits", "Options", "Cost", VNL);
  1001. }
  1002. static void
  1003. ospf6_linkstate_show (struct vty *vty, struct ospf6_route *route)
  1004. {
  1005. u_int32_t router, id;
  1006. char routername[16], idname[16], rbits[16], options[16];
  1007. router = ospf6_linkstate_prefix_adv_router (&route->prefix);
  1008. inet_ntop (AF_INET, &router, routername, sizeof (routername));
  1009. id = ospf6_linkstate_prefix_id (&route->prefix);
  1010. inet_ntop (AF_INET, &id, idname, sizeof (idname));
  1011. ospf6_capability_printbuf (route->path.router_bits, rbits, sizeof (rbits));
  1012. ospf6_options_printbuf (route->path.options, options, sizeof (options));
  1013. if (ntohl (id))
  1014. vty_out (vty, "%-7s %-15s %-15s %-8s %-14s %lu%s",
  1015. "Network", routername, idname, rbits, options,
  1016. (unsigned long) route->path.cost, VNL);
  1017. else
  1018. vty_out (vty, "%-7s %-15s %-15s %-8s %-14s %lu%s",
  1019. "Router", routername, idname, rbits, options,
  1020. (unsigned long) route->path.cost, VNL);
  1021. }
  1022. static void
  1023. ospf6_linkstate_show_table_exact (struct vty *vty,
  1024. struct prefix *prefix,
  1025. struct ospf6_route_table *table)
  1026. {
  1027. struct ospf6_route *route;
  1028. route = ospf6_route_lookup (prefix, table);
  1029. if (route == NULL)
  1030. return;
  1031. ospf6_route_lock (route);
  1032. while (route && ospf6_route_is_prefix (prefix, route))
  1033. {
  1034. /* Specifying a prefix will always display details */
  1035. ospf6_route_show_detail (vty, route);
  1036. route = ospf6_route_next (route);
  1037. }
  1038. if (route)
  1039. ospf6_route_unlock (route);
  1040. }
  1041. static void
  1042. ospf6_linkstate_show_table (struct vty *vty, int detail,
  1043. struct ospf6_route_table *table)
  1044. {
  1045. struct ospf6_route *route;
  1046. if (! detail)
  1047. ospf6_linkstate_show_header (vty);
  1048. route = ospf6_route_head (table);
  1049. while (route)
  1050. {
  1051. if (detail)
  1052. ospf6_route_show_detail (vty, route);
  1053. else
  1054. ospf6_linkstate_show (vty, route);
  1055. route = ospf6_route_next (route);
  1056. }
  1057. }
  1058. int
  1059. ospf6_linkstate_table_show (struct vty *vty, int argc, const char *argv[],
  1060. struct ospf6_route_table *table)
  1061. {
  1062. int detail = 0;
  1063. int is_id = 0;
  1064. int is_router = 0;
  1065. int i, ret;
  1066. struct prefix router, id, prefix;
  1067. memset (&router, 0, sizeof (struct prefix));
  1068. memset (&id, 0, sizeof (struct prefix));
  1069. memset (&prefix, 0, sizeof (struct prefix));
  1070. for (i = 0; i < argc; i++)
  1071. {
  1072. if (! strcmp (argv[i], "detail"))
  1073. {
  1074. detail++;
  1075. continue;
  1076. }
  1077. if (! is_router)
  1078. {
  1079. ret = str2prefix (argv[i], &router);
  1080. if (ret == 1 && router.family == AF_INET)
  1081. {
  1082. is_router++;
  1083. continue;
  1084. }
  1085. vty_out (vty, "Malformed argument: %s%s", argv[i], VNL);
  1086. return CMD_SUCCESS;
  1087. }
  1088. if (! is_id)
  1089. {
  1090. ret = str2prefix (argv[i], &id);
  1091. if (ret == 1 && id.family == AF_INET)
  1092. {
  1093. is_id++;
  1094. continue;
  1095. }
  1096. vty_out (vty, "Malformed argument: %s%s", argv[i], VNL);
  1097. return CMD_SUCCESS;
  1098. }
  1099. vty_out (vty, "Malformed argument: %s%s", argv[i], VNL);
  1100. return CMD_SUCCESS;
  1101. }
  1102. if (is_router)
  1103. ospf6_linkstate_prefix (router.u.prefix4.s_addr,
  1104. id.u.prefix4.s_addr, &prefix);
  1105. if (prefix.family)
  1106. ospf6_linkstate_show_table_exact (vty, &prefix, table);
  1107. else
  1108. ospf6_linkstate_show_table (vty, detail, table);
  1109. return CMD_SUCCESS;
  1110. }
  1111. void
  1112. ospf6_brouter_show_header (struct vty *vty)
  1113. {
  1114. vty_out (vty, "%-15s %-8s %-14s %-10s %-15s%s",
  1115. "Router-ID", "Rtr-Bits", "Options", "Path-Type", "Area", VNL);
  1116. }
  1117. void
  1118. ospf6_brouter_show (struct vty *vty, struct ospf6_route *route)
  1119. {
  1120. u_int32_t adv_router;
  1121. char adv[16], rbits[16], options[16], area[16];
  1122. adv_router = ospf6_linkstate_prefix_adv_router (&route->prefix);
  1123. inet_ntop (AF_INET, &adv_router, adv, sizeof (adv));
  1124. ospf6_capability_printbuf (route->path.router_bits, rbits, sizeof (rbits));
  1125. ospf6_options_printbuf (route->path.options, options, sizeof (options));
  1126. inet_ntop (AF_INET, &route->path.area_id, area, sizeof (area));
  1127. /* vty_out (vty, "%-15s %-8s %-14s %-10s %-15s%s",
  1128. "Router-ID", "Rtr-Bits", "Options", "Path-Type", "Area", VNL); */
  1129. vty_out (vty, "%-15s %-8s %-14s %-10s %-15s%s",
  1130. adv, rbits, options, OSPF6_PATH_TYPE_NAME (route->path.type),
  1131. area, VNL);
  1132. }
  1133. DEFUN (debug_ospf6_route,
  1134. debug_ospf6_route_cmd,
  1135. "debug ospf6 route (table|intra-area|inter-area)",
  1136. DEBUG_STR
  1137. OSPF6_STR
  1138. "Debug route table calculation\n"
  1139. "Debug detail\n"
  1140. "Debug intra-area route calculation\n"
  1141. "Debug inter-area route calculation\n"
  1142. )
  1143. {
  1144. unsigned char level = 0;
  1145. if (! strncmp (argv[0], "table", 5))
  1146. level = OSPF6_DEBUG_ROUTE_TABLE;
  1147. else if (! strncmp (argv[0], "intra", 5))
  1148. level = OSPF6_DEBUG_ROUTE_INTRA;
  1149. else if (! strncmp (argv[0], "inter", 5))
  1150. level = OSPF6_DEBUG_ROUTE_INTER;
  1151. OSPF6_DEBUG_ROUTE_ON (level);
  1152. return CMD_SUCCESS;
  1153. }
  1154. DEFUN (no_debug_ospf6_route,
  1155. no_debug_ospf6_route_cmd,
  1156. "no debug ospf6 route (table|intra-area|inter-area)",
  1157. NO_STR
  1158. DEBUG_STR
  1159. OSPF6_STR
  1160. "Debug route table calculation\n"
  1161. "Debug intra-area route calculation\n")
  1162. {
  1163. unsigned char level = 0;
  1164. if (! strncmp (argv[0], "table", 5))
  1165. level = OSPF6_DEBUG_ROUTE_TABLE;
  1166. else if (! strncmp (argv[0], "intra", 5))
  1167. level = OSPF6_DEBUG_ROUTE_INTRA;
  1168. else if (! strncmp (argv[0], "inter", 5))
  1169. level = OSPF6_DEBUG_ROUTE_INTER;
  1170. OSPF6_DEBUG_ROUTE_OFF (level);
  1171. return CMD_SUCCESS;
  1172. }
  1173. int
  1174. config_write_ospf6_debug_route (struct vty *vty)
  1175. {
  1176. if (IS_OSPF6_DEBUG_ROUTE (TABLE))
  1177. vty_out (vty, "debug ospf6 route table%s", VNL);
  1178. if (IS_OSPF6_DEBUG_ROUTE (INTRA))
  1179. vty_out (vty, "debug ospf6 route intra-area%s", VNL);
  1180. if (IS_OSPF6_DEBUG_ROUTE (INTER))
  1181. vty_out (vty, "debug ospf6 route inter-area%s", VNL);
  1182. return 0;
  1183. }
  1184. void
  1185. install_element_ospf6_debug_route (void)
  1186. {
  1187. install_element (ENABLE_NODE, &debug_ospf6_route_cmd);
  1188. install_element (ENABLE_NODE, &no_debug_ospf6_route_cmd);
  1189. install_element (CONFIG_NODE, &debug_ospf6_route_cmd);
  1190. install_element (CONFIG_NODE, &no_debug_ospf6_route_cmd);
  1191. }