ospf6_damp.c 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748
  1. /*
  2. * OSPF flap dampening by Manav Bhatia
  3. * Copyright (C) 2002
  4. *
  5. * This file is part of GNU Zebra.
  6. *
  7. * GNU Zebra is free software; you can redistribute it and/or modify it
  8. * under the terms of the GNU General Public License as published by the
  9. * Free Software Foundation; either version 2, or (at your option) any
  10. * later version.
  11. *
  12. * GNU Zebra is distributed in the hope that it will be useful, but
  13. * WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  15. * General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU General Public License
  18. * along with GNU Zebra; see the file COPYING. If not, write to the Free
  19. * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
  20. * 02111-1307, USA.
  21. */
  22. #include <zebra.h>
  23. #include <math.h>
  24. #include "log.h"
  25. #include "prefix.h"
  26. #include "thread.h"
  27. #include "table.h"
  28. #include "command.h"
  29. #include "vty.h"
  30. extern struct thread_master *master;
  31. #include "ospf6_damp.h"
  32. #ifdef HAVE_OSPF6_DAMP
  33. #define DELTA_REUSE 10 /* Time granularity for reuse lists */
  34. #define DELTA_T 5 /* Time granularity for decay arrays */
  35. #define DEFAULT_HALF_LIFE 60 /* (sec) 1 min */
  36. #define DEFAULT_PENALTY 1000
  37. #define DEFAULT_REUSE 750
  38. #define DEFAULT_SUPPRESS 2000
  39. #define REUSE_LIST_SIZE 256
  40. #define REUSE_ARRAY_SIZE 1024
  41. /* Global variable to access damping configuration */
  42. struct ospf6_damp_config damp_config;
  43. struct ospf6_damp_config *dc = &damp_config;
  44. u_int reuse_array_offset = 0;
  45. struct route_table *damp_info_table[OSPF6_DAMP_TYPE_MAX];
  46. struct thread *ospf6_reuse_thread = NULL;
  47. int ospf6_damp_debug = 0;
  48. #define IS_OSPF6_DEBUG_DAMP (ospf6_damp_debug)
  49. static struct ospf6_damp_info *
  50. ospf6_damp_lookup (u_short type, struct prefix *name)
  51. {
  52. struct route_node *node;
  53. node = route_node_lookup (damp_info_table[type], name);
  54. if (node && node->info)
  55. return (struct ospf6_damp_info *) node->info;
  56. return NULL;
  57. }
  58. static struct ospf6_damp_info *
  59. ospf6_damp_create (u_short type, struct prefix *name)
  60. {
  61. struct route_node *node;
  62. struct ospf6_damp_info *di;
  63. char namebuf[64];
  64. di = ospf6_damp_lookup (type, name);
  65. if (di)
  66. return di;
  67. if (IS_OSPF6_DEBUG_DAMP)
  68. {
  69. prefix2str (name, namebuf, sizeof (namebuf));
  70. zlog_info ("DAMP: create: type: %d, name: %s", type, namebuf);
  71. }
  72. di = (struct ospf6_damp_info *)
  73. malloc (sizeof (struct ospf6_damp_info));
  74. memset (di, 0, sizeof (struct ospf6_damp_info));
  75. di->type = type;
  76. prefix_copy (&di->name, name);
  77. node = route_node_get (damp_info_table[type], name);
  78. node->info = di;
  79. return di;
  80. }
  81. static void
  82. ospf6_damp_delete (u_short type, struct prefix *name)
  83. {
  84. struct route_node *node;
  85. struct ospf6_damp_info *di;
  86. char namebuf[64];
  87. node = route_node_lookup (damp_info_table[type], name);
  88. if (! node || ! node->info)
  89. return;
  90. di = node->info;
  91. if (IS_OSPF6_DEBUG_DAMP)
  92. {
  93. prefix2str (&di->name, namebuf, sizeof (namebuf));
  94. zlog_info ("DAMP: delete: type: %d, name: %s",
  95. di->type, namebuf);
  96. }
  97. node->info = NULL;
  98. free (di);
  99. }
  100. /* compute and fill the configuration parameter */
  101. void
  102. ospf6_damp_init_config (u_int half_life, u_int reuse,
  103. u_int suppress, u_int t_hold)
  104. {
  105. int i;
  106. double max_ratio, max_ratio1, max_ratio2;
  107. dc->half_life = half_life ? half_life : DEFAULT_HALF_LIFE;
  108. dc->reuse = reuse ? reuse : DEFAULT_REUSE;
  109. dc->suppress = suppress ? suppress : DEFAULT_SUPPRESS;
  110. dc->t_hold = t_hold ? t_hold : 4 * dc->half_life;
  111. /* Initialize system-wide params */
  112. dc->delta_t = DELTA_T;
  113. dc->delta_reuse = DELTA_REUSE;
  114. dc->default_penalty = DEFAULT_PENALTY;
  115. dc->reuse_index_array_size = REUSE_ARRAY_SIZE;
  116. /* ceiling is the maximum penalty a route may attain */
  117. /* ceiling = reuse * 2^(T-hold/half-life) */
  118. dc->ceiling = (int)
  119. (dc->reuse * (pow (2, (double) dc->t_hold / dc->half_life)));
  120. /* Decay-array computations */
  121. /* decay_array_size = decay memory/time granularity */
  122. dc->decay_array_size = ceil ((double) dc->t_hold / dc->delta_t);
  123. dc->decay_array = malloc (sizeof (double) * (dc->decay_array_size));
  124. /* Each i-th element is per tick delay raised to the i-th power */
  125. dc->decay_array[0] = 1.0;
  126. dc->decay_array[1] = exp ((1.0 / (dc->half_life / dc->delta_t)) * log (0.5));
  127. for (i = 2; i < dc->decay_array_size; i++)
  128. dc->decay_array[i] = dc->decay_array[i - 1] * dc->decay_array[1];
  129. /* Reuse-list computations (reuse queue head array ?) */
  130. dc->reuse_list_size = ceil ((double) dc->t_hold / dc->delta_reuse) + 1;
  131. if (dc->reuse_list_size == 0 || dc->reuse_list_size > REUSE_LIST_SIZE)
  132. dc->reuse_list_size = REUSE_LIST_SIZE;
  133. dc->reuse_list_array = (struct ospf6_damp_info **)
  134. malloc (dc->reuse_list_size * sizeof (struct ospf6_reuse_list *));
  135. memset (dc->reuse_list_array, 0x00,
  136. dc->reuse_list_size * sizeof (struct ospf6_reuse_list *));
  137. /* Reuse-array computations */
  138. dc->reuse_index_array = malloc (sizeof (int) * dc->reuse_index_array_size);
  139. /*
  140. * This is the maximum ratio between the current value of the penalty and
  141. * the reuse value which can be indexed by the reuse array. It will be
  142. * limited by the ceiling or by the amount of time that the reuse list
  143. * covers
  144. */
  145. max_ratio1 = (double) dc->ceiling / dc->reuse;
  146. max_ratio2 = exp ((double) dc->t_hold / dc->half_life) * log10 (2.0);
  147. max_ratio = (max_ratio2 != 0 && max_ratio2 < max_ratio1 ?
  148. max_ratio2 : max_ratio1);
  149. /*
  150. * reuse array is just an estimator and we need something
  151. * to use the full array
  152. */
  153. dc->scale_factor = (double) dc->reuse_index_array_size / (max_ratio - 1);
  154. for (i = 0; i < dc->reuse_index_array_size; i++)
  155. {
  156. dc->reuse_index_array[i] = (int)
  157. (((double) dc->half_life / dc->delta_reuse) *
  158. log10 (1.0 / (dc->reuse * (1.0 + ((double) i / dc->scale_factor))))
  159. / log10 (0.5));
  160. }
  161. dc->enabled = ON;
  162. }
  163. static double
  164. ospf6_damp_decay (time_t tdiff)
  165. {
  166. int index = tdiff / dc->delta_t;
  167. if (index >= dc->decay_array_size)
  168. return 0;
  169. return dc->decay_array[index];
  170. }
  171. static int
  172. ospf6_damp_reuse_index (int penalty)
  173. {
  174. int index;
  175. index = (int) (((double) penalty / dc->reuse - 1.0) * dc->scale_factor);
  176. if (index >= dc->reuse_index_array_size)
  177. index = dc->reuse_index_array_size - 1;
  178. return (dc->reuse_index_array[index] - dc->reuse_index_array[0]);
  179. }
  180. static int
  181. ospf6_reuse_list_lookup (struct ospf6_damp_info *di)
  182. {
  183. struct ospf6_damp_info *info;
  184. for (info = dc->reuse_list_array[di->index]; info; info = info->next)
  185. {
  186. if (info == di)
  187. return 1;
  188. }
  189. return 0;
  190. }
  191. static void
  192. ospf6_reuse_list_remove (struct ospf6_damp_info *di)
  193. {
  194. if (di->prev)
  195. di->prev->next = di->next;
  196. else
  197. dc->reuse_list_array[di->index] = di->next;
  198. if (di->next)
  199. di->next->prev = di->prev;
  200. di->index = -1;
  201. di->prev = NULL;
  202. di->next = NULL;
  203. }
  204. static void
  205. ospf6_reuse_list_add (struct ospf6_damp_info *di)
  206. {
  207. /* set the index of reuse-array */
  208. di->index = (reuse_array_offset + (ospf6_damp_reuse_index (di->penalty)))
  209. % dc->reuse_list_size;
  210. /* insert to the head of the reuse list */
  211. di->next = dc->reuse_list_array[di->index];
  212. if (di->next)
  213. di->next->prev = di;
  214. di->prev = NULL;
  215. dc->reuse_list_array[di->index] = di;
  216. }
  217. /* When we quit damping for a target, we should execute proper event
  218. which have been postponed during damping */
  219. static void
  220. ospf6_damp_stop (struct ospf6_damp_info *di)
  221. {
  222. time_t t_now;
  223. char namebuf[64];
  224. struct timeval now;
  225. if (IS_OSPF6_DEBUG_DAMP)
  226. {
  227. t_now = time (NULL);
  228. prefix2str (&di->name, namebuf, sizeof (namebuf));
  229. gettimeofday (&now, NULL);
  230. zlog_info ("DAMP: %lu.%06lu stop damping: %ld: type: %d, name: %s",
  231. now.tv_sec, now.tv_usec,
  232. (long)t_now, di->type, namebuf);
  233. }
  234. /* set flag indicates that we're damping this target */
  235. di->damping = OFF;
  236. /* if the target's current status differ from that it should be,
  237. execute the proper event to repair his status */
  238. if (di->target_status != di->event_type)
  239. {
  240. (*(di->event)) (di->target);
  241. di->target_status = di->event_type;
  242. di->event = NULL;
  243. di->event_type = event_none;
  244. }
  245. }
  246. /* ospf6_reuse_timer is called every DELTA_REUSE seconds.
  247. Each route in the current reuse-list is evaluated
  248. and is used or requeued */
  249. int
  250. ospf6_damp_reuse_timer (struct thread *t)
  251. {
  252. struct ospf6_damp_info *di, *next;
  253. time_t t_now, t_diff;
  254. char namebuf[64];
  255. struct timeval now;
  256. /* Restart the reuse timer */
  257. ospf6_reuse_thread =
  258. thread_add_timer (master, ospf6_damp_reuse_timer, NULL, dc->delta_reuse);
  259. t_now = time (NULL);
  260. /* get the damp info list head */
  261. di = dc->reuse_list_array[reuse_array_offset];
  262. dc->reuse_list_array[reuse_array_offset] = NULL;
  263. /* rotate the circular reuse list head array */
  264. reuse_array_offset = (reuse_array_offset + 1) % dc->reuse_list_size;
  265. /* for each damp info */
  266. while (di)
  267. {
  268. next = di->next;
  269. di->next = NULL;
  270. /* Update penalty */
  271. t_diff = t_now - di->t_updated;
  272. di->t_updated = t_now;
  273. di->penalty = (int)
  274. ((double) di->penalty * ospf6_damp_decay (t_diff));
  275. /* configration of ceiling may be just changed */
  276. if (di->penalty > dc->ceiling)
  277. di->penalty = dc->ceiling;
  278. if (IS_OSPF6_DEBUG_DAMP)
  279. {
  280. prefix2str (&di->name, namebuf, sizeof (namebuf));
  281. gettimeofday (&now, NULL);
  282. zlog_info ("DAMP: %lu.%06lu update penalty: type: %d, name: %s, penalty: %d",
  283. now.tv_sec, now.tv_usec,
  284. di->type, namebuf, di->penalty);
  285. }
  286. /* If the penalty becomes under reuse,
  287. call real event that we have been postponed. */
  288. if (di->penalty < dc->reuse && di->damping == ON)
  289. ospf6_damp_stop (di);
  290. /* If the penalty becomes less than the half of the
  291. reuse value, this damp info will be freed from reuse-list,
  292. by assuming that it is considered to be stable enough already,
  293. and there's no need to maintain flapping history for this. */
  294. if (di->penalty <= dc->reuse / 2)
  295. {
  296. ospf6_damp_delete (di->type, &di->name);
  297. di = next;
  298. continue;
  299. }
  300. /* re-insert to the reuse-list */
  301. ospf6_reuse_list_add (di);
  302. di = next;
  303. }
  304. return 0;
  305. }
  306. static void
  307. ospf6_damp_event (damp_event_t event_type,
  308. u_short type, struct prefix *name,
  309. int (*event) (void *), void *target)
  310. {
  311. time_t t_now, t_diff;
  312. struct ospf6_damp_info *di;
  313. char namebuf[64];
  314. struct timeval now;
  315. if (dc->enabled == OFF)
  316. {
  317. (*event) (target);
  318. return;
  319. }
  320. di = ospf6_damp_lookup (type, name);
  321. if (! di)
  322. di = ospf6_damp_create (type, name);
  323. t_now = time (NULL);
  324. di->event = event;
  325. di->target = target;
  326. di->event_type = event_type;
  327. if (! ospf6_reuse_list_lookup (di))
  328. di->t_start = t_now;
  329. else
  330. {
  331. ospf6_reuse_list_remove (di);
  332. t_diff = t_now - di->t_updated;
  333. di->penalty = (int) (di->penalty * ospf6_damp_decay (t_diff));
  334. }
  335. /* penalty only on down event */
  336. if (event_type == event_down)
  337. {
  338. di->flap++;
  339. di->penalty += dc->default_penalty;
  340. }
  341. /* limit penalty up to ceiling */
  342. if (di->penalty > dc->ceiling)
  343. di->penalty = dc->ceiling;
  344. if (IS_OSPF6_DEBUG_DAMP)
  345. {
  346. prefix2str (&di->name, namebuf, sizeof (namebuf));
  347. gettimeofday (&now, NULL);
  348. zlog_info ("DAMP: %lu.%06lu update penalty: type: %d, name: %s, penalty: %d",
  349. now.tv_sec, now.tv_usec,
  350. di->type, namebuf, di->penalty);
  351. }
  352. /* if penalty < reuse, stop damping here */
  353. if (di->penalty < dc->reuse && di->damping == ON)
  354. {
  355. if (IS_OSPF6_DEBUG_DAMP)
  356. {
  357. prefix2str (&di->name, namebuf, sizeof (namebuf));
  358. gettimeofday (&now, NULL);
  359. zlog_info ("DAMP: %lu.%06lu stop damping: %ld: type: %d, name: %s",
  360. now.tv_sec, now.tv_usec,
  361. (long)t_now, di->type, namebuf);
  362. }
  363. di->damping = OFF;
  364. }
  365. /* if event == up and if penalty >= suppress , start damping here */
  366. if (di->event_type == event_up && di->penalty >= dc->suppress &&
  367. di->damping == OFF)
  368. {
  369. if (IS_OSPF6_DEBUG_DAMP)
  370. {
  371. prefix2str (&di->name, namebuf, sizeof (namebuf));
  372. gettimeofday (&now, NULL);
  373. zlog_info ("DAMP: %lu.%06lu start damping: %ld: type: %d, name: %s",
  374. now.tv_sec, now.tv_usec,
  375. (long)t_now, type, namebuf);
  376. }
  377. di->damping = ON;
  378. }
  379. /* execute event if we're not damping */
  380. if (di->damping == OFF)
  381. {
  382. (*(di->event)) (di->target);
  383. di->target_status = di->event_type;
  384. }
  385. /* if the penalty goes beyond suppress value, start damping */
  386. if (di->penalty >= dc->suppress && di->damping == OFF)
  387. {
  388. if (IS_OSPF6_DEBUG_DAMP)
  389. {
  390. prefix2str (name, namebuf, sizeof (namebuf));
  391. gettimeofday (&now, NULL);
  392. zlog_info ("DAMP: %lu.%06lu start damping: %ld: type: %d, name: %s",
  393. now.tv_sec, now.tv_usec,
  394. (long) t_now, type, namebuf);
  395. }
  396. di->damping = ON;
  397. }
  398. /* update last-updated-time field */
  399. di->t_updated = t_now;
  400. /* Insert it into the reuse list */
  401. ospf6_reuse_list_add (di);
  402. }
  403. void
  404. ospf6_damp_event_up (u_short type, struct prefix *name,
  405. int (*event) (void *), void *target)
  406. {
  407. struct timeval now;
  408. gettimeofday (&now, NULL);
  409. if (IS_OSPF6_DEBUG_DAMP)
  410. zlog_info ("DAMP: Up Event at %lu.%06lu", now.tv_sec, now.tv_usec);
  411. ospf6_damp_event (event_up, type, name, event, target);
  412. }
  413. void
  414. ospf6_damp_event_down (u_short type, struct prefix *name,
  415. int (*event) (void *), void *target)
  416. {
  417. struct timeval now;
  418. gettimeofday (&now, NULL);
  419. if (IS_OSPF6_DEBUG_DAMP)
  420. zlog_info ("DAMP: Down Event at %lu.%06lu", now.tv_sec, now.tv_usec);
  421. ospf6_damp_event (event_down, type, name, event, target);
  422. }
  423. int
  424. ospf6_damp_debug_thread (struct thread *thread)
  425. {
  426. int i;
  427. struct ospf6_damp_info *di;
  428. char buf[256];
  429. time_t t_now;
  430. struct timeval now;
  431. for (i = 0; i < dc->reuse_list_size; i++)
  432. {
  433. for (di = dc->reuse_list_array[i]; di; di = di->next)
  434. {
  435. t_now = time (NULL);
  436. gettimeofday (&now, NULL);
  437. prefix2str (&di->name, buf, sizeof (buf));
  438. zlog_info ("DAMP: %lu.%06lu %c %-32s penalty %7u",
  439. now.tv_sec, now.tv_usec,
  440. (di->damping == ON ? 'D' : 'A'), buf,
  441. (u_int) (di->penalty *
  442. ospf6_damp_decay (t_now - di->t_updated)));
  443. }
  444. }
  445. thread_add_timer (master, ospf6_damp_debug_thread, NULL, 1);
  446. return 0;
  447. }
  448. DEFUN (show_ipv6_ospf6_route_flapping,
  449. show_ipv6_ospf6_route_flapping_cmd,
  450. "show ipv6 ospf6 route flapping",
  451. SHOW_STR
  452. IP6_STR
  453. OSPF6_STR)
  454. {
  455. int i;
  456. struct ospf6_damp_info *di;
  457. char buf[256];
  458. time_t t_now;
  459. t_now = time (NULL);
  460. vty_out (vty, "%c %-32s %7s%s", ' ', "Prefix", "penalty", VTY_NEWLINE);
  461. for (i = 0; i < dc->reuse_list_size; i++)
  462. {
  463. for (di = dc->reuse_list_array[i]; di; di = di->next)
  464. {
  465. prefix2str (&di->name, buf, sizeof (buf));
  466. vty_out (vty, "%c %-32s %7u%s",
  467. (di->damping == ON ? 'D' : ' '), buf,
  468. (u_int) (di->penalty *
  469. ospf6_damp_decay (t_now - di->t_updated)),
  470. VTY_NEWLINE);
  471. }
  472. }
  473. return CMD_SUCCESS;
  474. }
  475. DEFUN (ospf6_flap_damping_route,
  476. ospf6_flap_damping_route_cmd,
  477. "flap-damping route <0-4294967295> <0-4294967295> "
  478. "<0-4294967295> <0-4294967295>",
  479. "enable flap dampening\n"
  480. "enable route flap dampening\n"
  481. "half-life in second\n"
  482. "reuse value\n"
  483. "suppress value\n"
  484. "t-hold in second (maximum time that the target can be damped)\n"
  485. )
  486. {
  487. u_int half_life, reuse, suppress, t_hold;
  488. if (argc)
  489. {
  490. half_life = (u_int) strtoul (argv[0], NULL, 10);
  491. reuse = (u_int) strtoul (argv[1], NULL, 10);
  492. suppress = (u_int) strtoul (argv[2], NULL, 10);
  493. t_hold = (u_int) strtoul (argv[3], NULL, 10);
  494. }
  495. else
  496. {
  497. half_life = (u_int) DEFAULT_HALF_LIFE;
  498. reuse = (u_int) DEFAULT_REUSE;
  499. suppress = (u_int) DEFAULT_SUPPRESS;
  500. t_hold = (u_int) DEFAULT_HALF_LIFE * 4;
  501. }
  502. if (reuse && suppress && reuse >= suppress)
  503. {
  504. vty_out (vty, "reuse value exceeded suppress value, failed%s\n",
  505. VTY_NEWLINE);
  506. return CMD_SUCCESS;
  507. }
  508. if (half_life && t_hold && half_life >= t_hold)
  509. {
  510. vty_out (vty, "half-life exceeded t-hold, failed%s\n", VTY_NEWLINE);
  511. return CMD_SUCCESS;
  512. }
  513. ospf6_damp_init_config (half_life, reuse, suppress, t_hold);
  514. if (ospf6_reuse_thread == NULL)
  515. ospf6_reuse_thread =
  516. thread_add_timer (master, ospf6_damp_reuse_timer, NULL, dc->delta_reuse);
  517. return CMD_SUCCESS;
  518. }
  519. DEFUN (show_ipv6_ospf6_damp_config,
  520. show_ipv6_ospf6_camp_config_cmd,
  521. "show ipv6 ospf6 damp config",
  522. SHOW_STR
  523. IP6_STR
  524. OSPF6_STR
  525. "Flap-dampening information\n"
  526. "shows dampening configuration\n"
  527. )
  528. {
  529. int i;
  530. vty_out (vty, "%10s %10s %10s %10s%s",
  531. "Half life", "Suppress", "Reuse", "T-hold",
  532. VTY_NEWLINE);
  533. vty_out (vty, "%10u %10u %10u %10u%s",
  534. dc->half_life, dc->suppress, dc->reuse, dc->t_hold,
  535. VTY_NEWLINE);
  536. vty_out (vty, "%s", VTY_NEWLINE);
  537. vty_out (vty, "Delta-t = %u%s", dc->delta_t, VTY_NEWLINE);
  538. vty_out (vty, "Delta-Reuse = %u%s", dc->delta_reuse, VTY_NEWLINE);
  539. vty_out (vty, "Default-Penalty = %u%s", dc->default_penalty, VTY_NEWLINE);
  540. vty_out (vty, "Ceiling = %u%s", dc->ceiling, VTY_NEWLINE);
  541. vty_out (vty, "ScaleFactor = %f%s", dc->scale_factor, VTY_NEWLINE);
  542. vty_out (vty, "DecayArray(%d) =%s", dc->decay_array_size, VTY_NEWLINE);
  543. for (i = 0; i < dc->decay_array_size; i++)
  544. {
  545. if (i % 10 == 0)
  546. vty_out (vty, " ");
  547. vty_out (vty, " %f", dc->decay_array[i]);
  548. if (i % 10 == 0)
  549. vty_out (vty, "%s", VTY_NEWLINE);
  550. }
  551. vty_out (vty, "%s", VTY_NEWLINE);
  552. vty_out (vty, "ReuseIndexArray(%d) =%s",
  553. dc->reuse_index_array_size, VTY_NEWLINE);
  554. for (i = 0; i < dc->reuse_index_array_size; i++)
  555. {
  556. if (i % 10 == 0)
  557. vty_out (vty, " ");
  558. vty_out (vty, " %d", dc->reuse_index_array[i]);
  559. if (i % 10 == 0)
  560. vty_out (vty, "%s", VTY_NEWLINE);
  561. }
  562. vty_out (vty, "%s", VTY_NEWLINE);
  563. return CMD_SUCCESS;
  564. }
  565. void
  566. ospf6_damp_config_write (struct vty *vty)
  567. {
  568. if (dc->enabled == ON)
  569. {
  570. vty_out (vty, " flap-damping route %u %u %u %u%s",
  571. dc->half_life, dc->reuse, dc->suppress, dc->t_hold,
  572. VTY_NEWLINE);
  573. }
  574. }
  575. DEFUN (debug_ospf6_damp,
  576. debug_ospf6_damp_cmd,
  577. "debug ospf6 damp",
  578. DEBUG_STR
  579. OSPF6_STR
  580. "Flap-dampening information\n"
  581. )
  582. {
  583. ospf6_damp_debug = 1;
  584. return CMD_SUCCESS;
  585. }
  586. DEFUN (no_debug_ospf6_damp,
  587. no_debug_ospf6_damp_cmd,
  588. "no debug ospf6 damp",
  589. NO_STR
  590. DEBUG_STR
  591. OSPF6_STR
  592. "Flap-dampening information\n"
  593. )
  594. {
  595. ospf6_damp_debug = 0;
  596. return CMD_SUCCESS;
  597. }
  598. DEFUN (show_debug_ospf6_damp,
  599. show_debug_ospf6_damp_cmd,
  600. "show debugging ospf6 damp",
  601. SHOW_STR
  602. DEBUG_STR
  603. OSPF6_STR
  604. "Flap-dampening information\n"
  605. )
  606. {
  607. vty_out (vty, "debugging ospf6 damp is ");
  608. if (IS_OSPF6_DEBUG_DAMP)
  609. vty_out (vty, "enabled.");
  610. else
  611. vty_out (vty, "disabled.");
  612. vty_out (vty, "%s", VTY_NEWLINE);
  613. return CMD_SUCCESS;
  614. }
  615. void
  616. ospf6_damp_init ()
  617. {
  618. int i;
  619. for (i = 0; i < OSPF6_DAMP_TYPE_MAX; i++)
  620. damp_info_table[i] = route_table_init ();
  621. install_element (VIEW_NODE, &show_ipv6_ospf6_route_flapping_cmd);
  622. install_element (ENABLE_NODE, &show_ipv6_ospf6_route_flapping_cmd);
  623. install_element (ENABLE_NODE, &show_ipv6_ospf6_camp_config_cmd);
  624. install_element (OSPF6_NODE, &ospf6_flap_damping_route_cmd);
  625. install_element (ENABLE_NODE, &show_debug_ospf6_damp_cmd);
  626. install_element (CONFIG_NODE, &debug_ospf6_damp_cmd);
  627. install_element (CONFIG_NODE, &no_debug_ospf6_damp_cmd);
  628. thread_add_event (master, ospf6_damp_debug_thread, NULL, 0);
  629. }
  630. #endif /* HAVE_OSPF6_DAMP */