bgp_damp.c 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641
  1. /* BGP flap dampening
  2. Copyright (C) 2001 IP Infusion Inc.
  3. This file is part of GNU Zebra.
  4. GNU Zebra is free software; you can redistribute it and/or modify it
  5. under the terms of the GNU General Public License as published by the
  6. Free Software Foundation; either version 2, or (at your option) any
  7. later version.
  8. GNU Zebra is distributed in the hope that it will be useful, but
  9. WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  11. General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with GNU Zebra; see the file COPYING. If not, write to the Free
  14. Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
  15. 02111-1307, USA. */
  16. #include <zebra.h>
  17. #include <math.h>
  18. #include "prefix.h"
  19. #include "memory.h"
  20. #include "command.h"
  21. #include "log.h"
  22. #include "thread.h"
  23. #include "bgpd/bgpd.h"
  24. #include "bgpd/bgp_damp.h"
  25. #include "bgpd/bgp_table.h"
  26. #include "bgpd/bgp_route.h"
  27. #include "bgpd/bgp_attr.h"
  28. #include "bgpd/bgp_advertise.h"
  29. /* Global variable to access damping configuration */
  30. struct bgp_damp_config bgp_damp_cfg;
  31. static struct bgp_damp_config *damp = &bgp_damp_cfg;
  32. /* Utility macro to add and delete BGP dampening information to no
  33. used list. */
  34. #define BGP_DAMP_LIST_ADD(N,A) BGP_INFO_ADD(N,A,no_reuse_list)
  35. #define BGP_DAMP_LIST_DEL(N,A) BGP_INFO_DEL(N,A,no_reuse_list)
  36. /* Calculate reuse list index by penalty value. */
  37. static int
  38. bgp_reuse_index (int penalty)
  39. {
  40. unsigned int i;
  41. int index;
  42. i = (int)(((double) penalty / damp->reuse_limit - 1.0) * damp->scale_factor);
  43. if ( i >= damp->reuse_index_size )
  44. i = damp->reuse_index_size - 1;
  45. index = damp->reuse_index[i] - damp->reuse_index[0];
  46. return (damp->reuse_offset + index) % damp->reuse_list_size;
  47. }
  48. /* Add BGP dampening information to reuse list. */
  49. static void
  50. bgp_reuse_list_add (struct bgp_damp_info *bdi)
  51. {
  52. int index;
  53. index = bdi->index = bgp_reuse_index (bdi->penalty);
  54. bdi->prev = NULL;
  55. bdi->next = damp->reuse_list[index];
  56. if (damp->reuse_list[index])
  57. damp->reuse_list[index]->prev = bdi;
  58. damp->reuse_list[index] = bdi;
  59. }
  60. /* Delete BGP dampening information from reuse list. */
  61. static void
  62. bgp_reuse_list_delete (struct bgp_damp_info *bdi)
  63. {
  64. if (bdi->next)
  65. bdi->next->prev = bdi->prev;
  66. if (bdi->prev)
  67. bdi->prev->next = bdi->next;
  68. else
  69. damp->reuse_list[bdi->index] = bdi->next;
  70. }
  71. /* Return decayed penalty value. */
  72. int
  73. bgp_damp_decay (time_t tdiff, int penalty)
  74. {
  75. unsigned int i;
  76. i = (int) ((double) tdiff / DELTA_T);
  77. if (i == 0)
  78. return penalty;
  79. if (i >= damp->decay_array_size)
  80. return 0;
  81. return (int) (penalty * damp->decay_array[i]);
  82. }
  83. /* Handler of reuse timer event. Each route in the current reuse-list
  84. is evaluated. RFC2439 Section 4.8.7. */
  85. static int
  86. bgp_reuse_timer (struct thread *t)
  87. {
  88. struct bgp_damp_info *bdi;
  89. struct bgp_damp_info *next;
  90. time_t t_now, t_diff;
  91. damp->t_reuse = NULL;
  92. damp->t_reuse =
  93. thread_add_timer (master, bgp_reuse_timer, NULL, DELTA_REUSE);
  94. t_now = bgp_clock ();
  95. /* 1. save a pointer to the current zeroth queue head and zero the
  96. list head entry. */
  97. bdi = damp->reuse_list[damp->reuse_offset];
  98. damp->reuse_list[damp->reuse_offset] = NULL;
  99. /* 2. set offset = modulo reuse-list-size ( offset + 1 ), thereby
  100. rotating the circular queue of list-heads. */
  101. damp->reuse_offset = (damp->reuse_offset + 1) % damp->reuse_list_size;
  102. /* 3. if ( the saved list head pointer is non-empty ) */
  103. for (; bdi; bdi = next)
  104. {
  105. struct bgp *bgp = bdi->binfo->peer->bgp;
  106. next = bdi->next;
  107. /* Set t-diff = t-now - t-updated. */
  108. t_diff = t_now - bdi->t_updated;
  109. /* Set figure-of-merit = figure-of-merit * decay-array-ok [t-diff] */
  110. bdi->penalty = bgp_damp_decay (t_diff, bdi->penalty);
  111. /* Set t-updated = t-now. */
  112. bdi->t_updated = t_now;
  113. /* if (figure-of-merit < reuse). */
  114. if (bdi->penalty < damp->reuse_limit)
  115. {
  116. /* Reuse the route. */
  117. bgp_info_unset_flag (bdi->rn, bdi->binfo, BGP_INFO_DAMPED);
  118. bdi->suppress_time = 0;
  119. if (bdi->lastrecord == BGP_RECORD_UPDATE)
  120. {
  121. bgp_info_unset_flag (bdi->rn, bdi->binfo, BGP_INFO_HISTORY);
  122. bgp_aggregate_increment (bgp, &bdi->rn->p, bdi->binfo,
  123. bdi->afi, bdi->safi);
  124. bgp_process (bgp, bdi->rn, bdi->afi, bdi->safi);
  125. }
  126. if (bdi->penalty <= damp->reuse_limit / 2.0)
  127. bgp_damp_info_free (bdi, 1);
  128. else
  129. BGP_DAMP_LIST_ADD (damp, bdi);
  130. }
  131. else
  132. /* Re-insert into another list (See RFC2439 Section 4.8.6). */
  133. bgp_reuse_list_add (bdi);
  134. }
  135. return 0;
  136. }
  137. /* A route becomes unreachable (RFC2439 Section 4.8.2). */
  138. int
  139. bgp_damp_withdraw (struct bgp_info *binfo, struct bgp_node *rn,
  140. afi_t afi, safi_t safi, int attr_change)
  141. {
  142. time_t t_now;
  143. struct bgp_damp_info *bdi = NULL;
  144. double last_penalty = 0;
  145. t_now = bgp_clock ();
  146. /* Processing Unreachable Messages. */
  147. if (binfo->extra)
  148. bdi = binfo->extra->damp_info;
  149. if (bdi == NULL)
  150. {
  151. /* If there is no previous stability history. */
  152. /* RFC2439 said:
  153. 1. allocate a damping structure.
  154. 2. set figure-of-merit = 1.
  155. 3. withdraw the route. */
  156. bdi = XCALLOC (MTYPE_BGP_DAMP_INFO, sizeof (struct bgp_damp_info));
  157. bdi->binfo = binfo;
  158. bdi->rn = rn;
  159. bdi->penalty = (attr_change ? DEFAULT_PENALTY / 2 : DEFAULT_PENALTY);
  160. bdi->flap = 1;
  161. bdi->start_time = t_now;
  162. bdi->suppress_time = 0;
  163. bdi->index = -1;
  164. bdi->afi = afi;
  165. bdi->safi = safi;
  166. (bgp_info_extra_get (binfo))->damp_info = bdi;
  167. BGP_DAMP_LIST_ADD (damp, bdi);
  168. }
  169. else
  170. {
  171. last_penalty = bdi->penalty;
  172. /* 1. Set t-diff = t-now - t-updated. */
  173. bdi->penalty =
  174. (bgp_damp_decay (t_now - bdi->t_updated, bdi->penalty)
  175. + (attr_change ? DEFAULT_PENALTY / 2 : DEFAULT_PENALTY));
  176. if (bdi->penalty > damp->ceiling)
  177. bdi->penalty = damp->ceiling;
  178. bdi->flap++;
  179. }
  180. assert ((rn == bdi->rn) && (binfo == bdi->binfo));
  181. bdi->lastrecord = BGP_RECORD_WITHDRAW;
  182. bdi->t_updated = t_now;
  183. /* Make this route as historical status. */
  184. bgp_info_set_flag (rn, binfo, BGP_INFO_HISTORY);
  185. /* Remove the route from a reuse list if it is on one. */
  186. if (CHECK_FLAG (bdi->binfo->flags, BGP_INFO_DAMPED))
  187. {
  188. /* If decay rate isn't equal to 0, reinsert brn. */
  189. if (bdi->penalty != last_penalty)
  190. {
  191. bgp_reuse_list_delete (bdi);
  192. bgp_reuse_list_add (bdi);
  193. }
  194. return BGP_DAMP_SUPPRESSED;
  195. }
  196. /* If not suppressed before, do annonunce this withdraw and
  197. insert into reuse_list. */
  198. if (bdi->penalty >= damp->suppress_value)
  199. {
  200. bgp_info_set_flag (rn, binfo, BGP_INFO_DAMPED);
  201. bdi->suppress_time = t_now;
  202. BGP_DAMP_LIST_DEL (damp, bdi);
  203. bgp_reuse_list_add (bdi);
  204. }
  205. return BGP_DAMP_USED;
  206. }
  207. int
  208. bgp_damp_update (struct bgp_info *binfo, struct bgp_node *rn,
  209. afi_t afi, safi_t safi)
  210. {
  211. time_t t_now;
  212. struct bgp_damp_info *bdi;
  213. int status;
  214. if (!binfo->extra || !((bdi = binfo->extra->damp_info)))
  215. return BGP_DAMP_USED;
  216. t_now = bgp_clock ();
  217. bgp_info_unset_flag (rn, binfo, BGP_INFO_HISTORY);
  218. bdi->lastrecord = BGP_RECORD_UPDATE;
  219. bdi->penalty = bgp_damp_decay (t_now - bdi->t_updated, bdi->penalty);
  220. if (! CHECK_FLAG (bdi->binfo->flags, BGP_INFO_DAMPED)
  221. && (bdi->penalty < damp->suppress_value))
  222. status = BGP_DAMP_USED;
  223. else if (CHECK_FLAG (bdi->binfo->flags, BGP_INFO_DAMPED)
  224. && (bdi->penalty < damp->reuse_limit) )
  225. {
  226. bgp_info_unset_flag (rn, binfo, BGP_INFO_DAMPED);
  227. bgp_reuse_list_delete (bdi);
  228. BGP_DAMP_LIST_ADD (damp, bdi);
  229. bdi->suppress_time = 0;
  230. status = BGP_DAMP_USED;
  231. }
  232. else
  233. status = BGP_DAMP_SUPPRESSED;
  234. if (bdi->penalty > damp->reuse_limit / 2.0)
  235. bdi->t_updated = t_now;
  236. else
  237. bgp_damp_info_free (bdi, 0);
  238. return status;
  239. }
  240. /* Remove dampening information and history route. */
  241. int
  242. bgp_damp_scan (struct bgp_info *binfo, afi_t afi, safi_t safi)
  243. {
  244. time_t t_now, t_diff;
  245. struct bgp_damp_info *bdi;
  246. assert (binfo->extra && binfo->extra->damp_info);
  247. t_now = bgp_clock ();
  248. bdi = binfo->extra->damp_info;
  249. if (CHECK_FLAG (binfo->flags, BGP_INFO_DAMPED))
  250. {
  251. t_diff = t_now - bdi->suppress_time;
  252. if (t_diff >= damp->max_suppress_time)
  253. {
  254. bgp_info_unset_flag (bdi->rn, binfo, BGP_INFO_DAMPED);
  255. bgp_reuse_list_delete (bdi);
  256. BGP_DAMP_LIST_ADD (damp, bdi);
  257. bdi->penalty = damp->reuse_limit;
  258. bdi->suppress_time = 0;
  259. bdi->t_updated = t_now;
  260. /* Need to announce UPDATE once this binfo is usable again. */
  261. if (bdi->lastrecord == BGP_RECORD_UPDATE)
  262. return 1;
  263. else
  264. return 0;
  265. }
  266. }
  267. else
  268. {
  269. t_diff = t_now - bdi->t_updated;
  270. bdi->penalty = bgp_damp_decay (t_diff, bdi->penalty);
  271. if (bdi->penalty <= damp->reuse_limit / 2.0)
  272. {
  273. /* release the bdi, bdi->binfo. */
  274. bgp_damp_info_free (bdi, 1);
  275. return 0;
  276. }
  277. else
  278. bdi->t_updated = t_now;
  279. }
  280. return 0;
  281. }
  282. void
  283. bgp_damp_info_free (struct bgp_damp_info *bdi, int withdraw)
  284. {
  285. struct bgp_info *binfo;
  286. if (! bdi)
  287. return;
  288. binfo = bdi->binfo;
  289. binfo->extra->damp_info = NULL;
  290. if (CHECK_FLAG (binfo->flags, BGP_INFO_DAMPED))
  291. bgp_reuse_list_delete (bdi);
  292. else
  293. BGP_DAMP_LIST_DEL (damp, bdi);
  294. bgp_info_unset_flag (bdi->rn, binfo, BGP_INFO_HISTORY|BGP_INFO_DAMPED);
  295. if (bdi->lastrecord == BGP_RECORD_WITHDRAW && withdraw)
  296. bgp_info_delete (bdi->rn, binfo);
  297. XFREE (MTYPE_BGP_DAMP_INFO, bdi);
  298. }
  299. static void
  300. bgp_damp_parameter_set (int hlife, int reuse, int sup, int maxsup)
  301. {
  302. double reuse_max_ratio;
  303. unsigned int i;
  304. double j;
  305. damp->suppress_value = sup;
  306. damp->half_life = hlife;
  307. damp->reuse_limit = reuse;
  308. damp->max_suppress_time = maxsup;
  309. /* Initialize params per bgp_damp_config. */
  310. damp->reuse_index_size = REUSE_ARRAY_SIZE;
  311. damp->ceiling = (int)(damp->reuse_limit * (pow(2, (double)damp->max_suppress_time/damp->half_life)));
  312. /* Decay-array computations */
  313. damp->decay_array_size = ceil ((double) damp->max_suppress_time / DELTA_T);
  314. damp->decay_array = XMALLOC (MTYPE_BGP_DAMP_ARRAY,
  315. sizeof(double) * (damp->decay_array_size));
  316. damp->decay_array[0] = 1.0;
  317. damp->decay_array[1] = exp ((1.0/((double)damp->half_life/DELTA_T)) * log(0.5));
  318. /* Calculate decay values for all possible times */
  319. for (i = 2; i < damp->decay_array_size; i++)
  320. damp->decay_array[i] = damp->decay_array[i-1] * damp->decay_array[1];
  321. /* Reuse-list computations */
  322. i = ceil ((double)damp->max_suppress_time / DELTA_REUSE) + 1;
  323. if (i > REUSE_LIST_SIZE || i == 0)
  324. i = REUSE_LIST_SIZE;
  325. damp->reuse_list_size = i;
  326. damp->reuse_list = XCALLOC (MTYPE_BGP_DAMP_ARRAY,
  327. damp->reuse_list_size
  328. * sizeof (struct bgp_reuse_node *));
  329. /* Reuse-array computations */
  330. damp->reuse_index = XCALLOC (MTYPE_BGP_DAMP_ARRAY,
  331. sizeof(int) * damp->reuse_index_size);
  332. reuse_max_ratio = (double)damp->ceiling/damp->reuse_limit;
  333. j = (exp((double)damp->max_suppress_time/damp->half_life) * log10(2.0));
  334. if ( reuse_max_ratio > j && j != 0 )
  335. reuse_max_ratio = j;
  336. damp->scale_factor = (double)damp->reuse_index_size/(reuse_max_ratio - 1);
  337. for (i = 0; i < damp->reuse_index_size; i++)
  338. {
  339. damp->reuse_index[i] =
  340. (int)(((double)damp->half_life / DELTA_REUSE)
  341. * log10 (1.0 / (damp->reuse_limit * ( 1.0 + ((double)i/damp->scale_factor)))) / log10(0.5));
  342. }
  343. }
  344. int
  345. bgp_damp_enable (struct bgp *bgp, afi_t afi, safi_t safi, time_t half,
  346. unsigned int reuse, unsigned int suppress, time_t max)
  347. {
  348. if (CHECK_FLAG (bgp->af_flags[afi][safi], BGP_CONFIG_DAMPENING))
  349. {
  350. if (damp->half_life == half
  351. && damp->reuse_limit == reuse
  352. && damp->suppress_value == suppress
  353. && damp->max_suppress_time == max)
  354. return 0;
  355. bgp_damp_disable (bgp, afi, safi);
  356. }
  357. SET_FLAG (bgp->af_flags[afi][safi], BGP_CONFIG_DAMPENING);
  358. bgp_damp_parameter_set (half, reuse, suppress, max);
  359. /* Register reuse timer. */
  360. if (! damp->t_reuse)
  361. damp->t_reuse =
  362. thread_add_timer (master, bgp_reuse_timer, NULL, DELTA_REUSE);
  363. return 0;
  364. }
  365. static void
  366. bgp_damp_config_clean (struct bgp_damp_config *damp)
  367. {
  368. /* Free decay array */
  369. XFREE (MTYPE_BGP_DAMP_ARRAY, damp->decay_array);
  370. /* Free reuse index array */
  371. XFREE (MTYPE_BGP_DAMP_ARRAY, damp->reuse_index);
  372. /* Free reuse list array. */
  373. XFREE (MTYPE_BGP_DAMP_ARRAY, damp->reuse_list);
  374. }
  375. /* Clean all the bgp_damp_info stored in reuse_list. */
  376. void
  377. bgp_damp_info_clean (void)
  378. {
  379. unsigned int i;
  380. struct bgp_damp_info *bdi, *next;
  381. damp->reuse_offset = 0;
  382. for (i = 0; i < damp->reuse_list_size; i++)
  383. {
  384. if (! damp->reuse_list[i])
  385. continue;
  386. for (bdi = damp->reuse_list[i]; bdi; bdi = next)
  387. {
  388. next = bdi->next;
  389. bgp_damp_info_free (bdi, 1);
  390. }
  391. damp->reuse_list[i] = NULL;
  392. }
  393. for (bdi = damp->no_reuse_list; bdi; bdi = next)
  394. {
  395. next = bdi->next;
  396. bgp_damp_info_free (bdi, 1);
  397. }
  398. damp->no_reuse_list = NULL;
  399. }
  400. int
  401. bgp_damp_disable (struct bgp *bgp, afi_t afi, safi_t safi)
  402. {
  403. /* If it wasn't enabled, there's nothing to do. */
  404. if (! CHECK_FLAG (bgp->af_flags[afi][safi], BGP_CONFIG_DAMPENING))
  405. return 0;
  406. /* Cancel reuse thread. */
  407. if (damp->t_reuse )
  408. thread_cancel (damp->t_reuse);
  409. damp->t_reuse = NULL;
  410. /* Clean BGP dampening information. */
  411. bgp_damp_info_clean ();
  412. /* Clear configuration */
  413. bgp_damp_config_clean (&bgp_damp_cfg);
  414. UNSET_FLAG (bgp->af_flags[afi][safi], BGP_CONFIG_DAMPENING);
  415. return 0;
  416. }
  417. void
  418. bgp_config_write_damp (struct vty *vty)
  419. {
  420. if (bgp_damp_cfg.half_life == DEFAULT_HALF_LIFE*60
  421. && bgp_damp_cfg.reuse_limit == DEFAULT_REUSE
  422. && bgp_damp_cfg.suppress_value == DEFAULT_SUPPRESS
  423. && bgp_damp_cfg.max_suppress_time == bgp_damp_cfg.half_life*4)
  424. vty_out (vty, " bgp dampening%s", VTY_NEWLINE);
  425. else if (bgp_damp_cfg.half_life != DEFAULT_HALF_LIFE*60
  426. && bgp_damp_cfg.reuse_limit == DEFAULT_REUSE
  427. && bgp_damp_cfg.suppress_value == DEFAULT_SUPPRESS
  428. && bgp_damp_cfg.max_suppress_time == bgp_damp_cfg.half_life*4)
  429. vty_out (vty, " bgp dampening %ld%s",
  430. bgp_damp_cfg.half_life/60,
  431. VTY_NEWLINE);
  432. else
  433. vty_out (vty, " bgp dampening %ld %d %d %ld%s",
  434. bgp_damp_cfg.half_life/60,
  435. bgp_damp_cfg.reuse_limit,
  436. bgp_damp_cfg.suppress_value,
  437. bgp_damp_cfg.max_suppress_time/60,
  438. VTY_NEWLINE);
  439. }
  440. static const char *
  441. bgp_get_reuse_time (unsigned int penalty, char *buf, size_t len)
  442. {
  443. time_t reuse_time = 0;
  444. struct tm *tm = NULL;
  445. if (penalty > damp->reuse_limit)
  446. {
  447. reuse_time = (int) (DELTA_T * ((log((double)damp->reuse_limit/penalty))/(log(damp->decay_array[1]))));
  448. if (reuse_time > damp->max_suppress_time)
  449. reuse_time = damp->max_suppress_time;
  450. tm = gmtime (&reuse_time);
  451. }
  452. else
  453. reuse_time = 0;
  454. /* Making formatted timer strings. */
  455. #define ONE_DAY_SECOND 60*60*24
  456. #define ONE_WEEK_SECOND 60*60*24*7
  457. if (reuse_time == 0)
  458. snprintf (buf, len, "00:00:00");
  459. else if (reuse_time < ONE_DAY_SECOND)
  460. snprintf (buf, len, "%02d:%02d:%02d",
  461. tm->tm_hour, tm->tm_min, tm->tm_sec);
  462. else if (reuse_time < ONE_WEEK_SECOND)
  463. snprintf (buf, len, "%dd%02dh%02dm",
  464. tm->tm_yday, tm->tm_hour, tm->tm_min);
  465. else
  466. snprintf (buf, len, "%02dw%dd%02dh",
  467. tm->tm_yday/7, tm->tm_yday - ((tm->tm_yday/7) * 7), tm->tm_hour);
  468. return buf;
  469. }
  470. void
  471. bgp_damp_info_vty (struct vty *vty, struct bgp_info *binfo)
  472. {
  473. struct bgp_damp_info *bdi;
  474. time_t t_now, t_diff;
  475. char timebuf[BGP_UPTIME_LEN];
  476. int penalty;
  477. if (!binfo->extra)
  478. return;
  479. /* BGP dampening information. */
  480. bdi = binfo->extra->damp_info;
  481. /* If dampening is not enabled or there is no dampening information,
  482. return immediately. */
  483. if (! damp || ! bdi)
  484. return;
  485. /* Calculate new penalty. */
  486. t_now = bgp_clock ();
  487. t_diff = t_now - bdi->t_updated;
  488. penalty = bgp_damp_decay (t_diff, bdi->penalty);
  489. vty_out (vty, " Dampinfo: penalty %d, flapped %d times in %s",
  490. penalty, bdi->flap,
  491. peer_uptime (bdi->start_time, timebuf, BGP_UPTIME_LEN));
  492. if (CHECK_FLAG (binfo->flags, BGP_INFO_DAMPED)
  493. && ! CHECK_FLAG (binfo->flags, BGP_INFO_HISTORY))
  494. vty_out (vty, ", reuse in %s",
  495. bgp_get_reuse_time (penalty, timebuf, BGP_UPTIME_LEN));
  496. vty_out (vty, "%s", VTY_NEWLINE);
  497. }
  498. const char *
  499. bgp_damp_reuse_time_vty (struct vty *vty, struct bgp_info *binfo,
  500. char *timebuf, size_t len)
  501. {
  502. struct bgp_damp_info *bdi;
  503. time_t t_now, t_diff;
  504. int penalty;
  505. if (!binfo->extra)
  506. return NULL;
  507. /* BGP dampening information. */
  508. bdi = binfo->extra->damp_info;
  509. /* If dampening is not enabled or there is no dampening information,
  510. return immediately. */
  511. if (! damp || ! bdi)
  512. return NULL;
  513. /* Calculate new penalty. */
  514. t_now = bgp_clock ();
  515. t_diff = t_now - bdi->t_updated;
  516. penalty = bgp_damp_decay (t_diff, bdi->penalty);
  517. return bgp_get_reuse_time (penalty, timebuf, len);
  518. }