ospf6_route.c 38 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402
  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. }