bgp_damp.c 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642
  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. 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. struct bgp *bgp;
  92. damp->t_reuse = NULL;
  93. damp->t_reuse =
  94. thread_add_timer (master, bgp_reuse_timer, NULL, DELTA_REUSE);
  95. bgp = bgp_get_default ();
  96. if (! bgp)
  97. return 0;
  98. t_now = time (NULL);
  99. /* 1. save a pointer to the current zeroth queue head and zero the
  100. list head entry. */
  101. bdi = damp->reuse_list[damp->reuse_offset];
  102. damp->reuse_list[damp->reuse_offset] = NULL;
  103. /* 2. set offset = modulo reuse-list-size ( offset + 1 ), thereby
  104. rotating the circular queue of list-heads. */
  105. damp->reuse_offset = (damp->reuse_offset + 1) % damp->reuse_list_size;
  106. /* 3. if ( the saved list head pointer is non-empty ) */
  107. for (; bdi; bdi = next)
  108. {
  109. next = bdi->next;
  110. /* Set t-diff = t-now - t-updated. */
  111. t_diff = t_now - bdi->t_updated;
  112. /* Set figure-of-merit = figure-of-merit * decay-array-ok [t-diff] */
  113. bdi->penalty = bgp_damp_decay (t_diff, bdi->penalty);
  114. /* Set t-updated = t-now. */
  115. bdi->t_updated = t_now;
  116. /* if (figure-of-merit < reuse). */
  117. if (bdi->penalty < damp->reuse_limit)
  118. {
  119. /* Reuse the route. */
  120. UNSET_FLAG (bdi->binfo->flags, BGP_INFO_DAMPED);
  121. bdi->suppress_time = 0;
  122. if (bdi->lastrecord == BGP_RECORD_UPDATE)
  123. {
  124. UNSET_FLAG (bdi->binfo->flags, BGP_INFO_HISTORY);
  125. bgp_aggregate_increment (bgp, &bdi->rn->p, bdi->binfo,
  126. bdi->afi, bdi->safi);
  127. bgp_process (bgp, bdi->rn, bdi->afi, bdi->safi);
  128. }
  129. if (bdi->penalty <= damp->reuse_limit / 2.0)
  130. bgp_damp_info_free (bdi, 1);
  131. else
  132. BGP_DAMP_LIST_ADD (damp, bdi);
  133. }
  134. else
  135. /* Re-insert into another list (See RFC2439 Section 4.8.6). */
  136. bgp_reuse_list_add (bdi);
  137. }
  138. return 0;
  139. }
  140. /* A route becomes unreachable (RFC2439 Section 4.8.2). */
  141. int
  142. bgp_damp_withdraw (struct bgp_info *binfo, struct bgp_node *rn,
  143. afi_t afi, safi_t safi, int attr_change)
  144. {
  145. time_t t_now;
  146. struct bgp_damp_info *bdi;
  147. double last_penalty = 0;
  148. t_now = time (NULL);
  149. /* Processing Unreachable Messages. */
  150. bdi = binfo->damp_info;
  151. if (bdi == NULL)
  152. {
  153. /* If there is no previous stability history. */
  154. /* RFC2439 said:
  155. 1. allocate a damping structure.
  156. 2. set figure-of-merit = 1.
  157. 3. withdraw the route. */
  158. bdi = XCALLOC (MTYPE_BGP_DAMP_INFO, sizeof (struct bgp_damp_info));
  159. bdi->binfo = binfo;
  160. bdi->rn = rn;
  161. bdi->penalty = (attr_change ? DEFAULT_PENALTY / 2 : DEFAULT_PENALTY);
  162. bdi->flap = 1;
  163. bdi->start_time = t_now;
  164. bdi->suppress_time = 0;
  165. bdi->index = -1;
  166. bdi->afi = afi;
  167. bdi->safi = safi;
  168. binfo->damp_info = bdi;
  169. BGP_DAMP_LIST_ADD (damp, bdi);
  170. }
  171. else
  172. {
  173. last_penalty = bdi->penalty;
  174. /* 1. Set t-diff = t-now - t-updated. */
  175. bdi->penalty =
  176. (bgp_damp_decay (t_now - bdi->t_updated, bdi->penalty)
  177. + (attr_change ? DEFAULT_PENALTY / 2 : DEFAULT_PENALTY));
  178. if (bdi->penalty > damp->ceiling)
  179. bdi->penalty = damp->ceiling;
  180. bdi->flap++;
  181. }
  182. bdi->lastrecord = BGP_RECORD_WITHDRAW;
  183. bdi->t_updated = t_now;
  184. /* Make this route as historical status. */
  185. SET_FLAG (binfo->flags, BGP_INFO_HISTORY);
  186. /* Remove the route from a reuse list if it is on one. */
  187. if (CHECK_FLAG (bdi->binfo->flags, BGP_INFO_DAMPED))
  188. {
  189. /* If decay rate isn't equal to 0, reinsert brn. */
  190. if (bdi->penalty != last_penalty)
  191. {
  192. bgp_reuse_list_delete (bdi);
  193. bgp_reuse_list_add (bdi);
  194. }
  195. return BGP_DAMP_SUPPRESSED;
  196. }
  197. /* If not suppressed before, do annonunce this withdraw and
  198. insert into reuse_list. */
  199. if (bdi->penalty >= damp->suppress_value)
  200. {
  201. SET_FLAG (bdi->binfo->flags, BGP_INFO_DAMPED);
  202. bdi->suppress_time = t_now;
  203. BGP_DAMP_LIST_DEL (damp, bdi);
  204. bgp_reuse_list_add (bdi);
  205. }
  206. return BGP_DAMP_USED;
  207. }
  208. int
  209. bgp_damp_update (struct bgp_info *binfo, struct bgp_node *rn,
  210. afi_t afi, safi_t safi)
  211. {
  212. time_t t_now;
  213. struct bgp_damp_info *bdi;
  214. int status;
  215. bdi = binfo->damp_info;
  216. if (! bdi)
  217. return BGP_DAMP_USED;
  218. t_now = time (NULL);
  219. UNSET_FLAG (binfo->flags, BGP_INFO_HISTORY);
  220. bdi->lastrecord = BGP_RECORD_UPDATE;
  221. bdi->penalty = bgp_damp_decay (t_now - bdi->t_updated, bdi->penalty);
  222. if (! CHECK_FLAG (bdi->binfo->flags, BGP_INFO_DAMPED)
  223. && (bdi->penalty < damp->suppress_value))
  224. status = BGP_DAMP_USED;
  225. else if (CHECK_FLAG (bdi->binfo->flags, BGP_INFO_DAMPED)
  226. && (bdi->penalty < damp->reuse_limit) )
  227. {
  228. UNSET_FLAG (bdi->binfo->flags, BGP_INFO_DAMPED);
  229. bgp_reuse_list_delete (bdi);
  230. BGP_DAMP_LIST_ADD (damp, bdi);
  231. bdi->suppress_time = 0;
  232. status = BGP_DAMP_USED;
  233. }
  234. else
  235. status = BGP_DAMP_SUPPRESSED;
  236. if (bdi->penalty > damp->reuse_limit / 2.0)
  237. bdi->t_updated = t_now;
  238. else
  239. bgp_damp_info_free (bdi, 0);
  240. return status;
  241. }
  242. /* Remove dampening information and history route. */
  243. int
  244. bgp_damp_scan (struct bgp_info *binfo, afi_t afi, safi_t safi)
  245. {
  246. time_t t_now, t_diff;
  247. struct bgp_damp_info *bdi;
  248. t_now = time (NULL);
  249. bdi = binfo->damp_info;
  250. if (CHECK_FLAG (binfo->flags, BGP_INFO_DAMPED))
  251. {
  252. t_diff = t_now - bdi->suppress_time;
  253. if (t_diff >= damp->max_suppress_time)
  254. {
  255. UNSET_FLAG (binfo->flags, BGP_INFO_DAMPED);
  256. bgp_reuse_list_delete (bdi);
  257. BGP_DAMP_LIST_ADD (damp, bdi);
  258. bdi->penalty = damp->reuse_limit;
  259. bdi->suppress_time = 0;
  260. bdi->t_updated = t_now;
  261. /* Need to announce UPDATE once this binfo is usable again. */
  262. if (bdi->lastrecord == BGP_RECORD_UPDATE)
  263. return 1;
  264. else
  265. return 0;
  266. }
  267. }
  268. else
  269. {
  270. t_diff = t_now - bdi->t_updated;
  271. bdi->penalty = bgp_damp_decay (t_diff, bdi->penalty);
  272. if (bdi->penalty <= damp->reuse_limit / 2.0)
  273. {
  274. /* release the bdi, bdi->binfo. */
  275. bgp_damp_info_free (bdi, 1);
  276. return 0;
  277. }
  278. else
  279. bdi->t_updated = t_now;
  280. }
  281. return 0;
  282. }
  283. void
  284. bgp_damp_info_free (struct bgp_damp_info *bdi, int withdraw)
  285. {
  286. struct bgp_info *binfo;
  287. if (! bdi)
  288. return;
  289. binfo = bdi->binfo;
  290. binfo->damp_info = NULL;
  291. if (CHECK_FLAG (binfo->flags, BGP_INFO_DAMPED))
  292. bgp_reuse_list_delete (bdi);
  293. else
  294. BGP_DAMP_LIST_DEL (damp, bdi);
  295. UNSET_FLAG (binfo->flags, BGP_INFO_DAMPED);
  296. UNSET_FLAG (binfo->flags, BGP_INFO_HISTORY);
  297. if (bdi->lastrecord == BGP_RECORD_WITHDRAW && withdraw)
  298. bgp_info_delete (bdi->rn, binfo);
  299. XFREE (MTYPE_BGP_DAMP_INFO, bdi);
  300. }
  301. static void
  302. bgp_damp_parameter_set (int hlife, int reuse, int sup, int maxsup)
  303. {
  304. double reuse_max_ratio;
  305. unsigned int i;
  306. double j;
  307. damp->suppress_value = sup;
  308. damp->half_life = hlife;
  309. damp->reuse_limit = reuse;
  310. damp->max_suppress_time = maxsup;
  311. /* Initialize params per bgp_damp_config. */
  312. damp->reuse_index_size = REUSE_ARRAY_SIZE;
  313. damp->ceiling = (int)(damp->reuse_limit * (pow(2, (double)damp->max_suppress_time/damp->half_life)));
  314. /* Decay-array computations */
  315. damp->decay_array_size = ceil ((double) damp->max_suppress_time / DELTA_T);
  316. damp->decay_array = XMALLOC (MTYPE_BGP_DAMP_ARRAY,
  317. sizeof(double) * (damp->decay_array_size));
  318. damp->decay_array[0] = 1.0;
  319. damp->decay_array[1] = exp ((1.0/((double)damp->half_life/DELTA_T)) * log(0.5));
  320. /* Calculate decay values for all possible times */
  321. for (i = 2; i < damp->decay_array_size; i++)
  322. damp->decay_array[i] = damp->decay_array[i-1] * damp->decay_array[1];
  323. /* Reuse-list computations */
  324. i = ceil ((double)damp->max_suppress_time / DELTA_REUSE) + 1;
  325. if (i > REUSE_LIST_SIZE || i == 0)
  326. i = REUSE_LIST_SIZE;
  327. damp->reuse_list_size = i;
  328. damp->reuse_list = XCALLOC (MTYPE_BGP_DAMP_ARRAY,
  329. damp->reuse_list_size
  330. * sizeof (struct bgp_reuse_node *));
  331. memset (damp->reuse_list, 0x00,
  332. damp->reuse_list_size * sizeof (struct bgp_reuse_node *));
  333. /* Reuse-array computations */
  334. damp->reuse_index = XMALLOC (MTYPE_BGP_DAMP_ARRAY,
  335. sizeof(int) * damp->reuse_index_size);
  336. memset (damp->reuse_index, 0x00,
  337. damp->reuse_list_size * sizeof (int));
  338. reuse_max_ratio = (double)damp->ceiling/damp->reuse_limit;
  339. j = (exp((double)damp->max_suppress_time/damp->half_life) * log10(2.0));
  340. if ( reuse_max_ratio > j && j != 0 )
  341. reuse_max_ratio = j;
  342. damp->scale_factor = (double)damp->reuse_index_size/(reuse_max_ratio - 1);
  343. for (i = 0; i < damp->reuse_index_size; i++)
  344. {
  345. damp->reuse_index[i] =
  346. (int)(((double)damp->half_life / DELTA_REUSE)
  347. * log10 (1.0 / (damp->reuse_limit * ( 1.0 + ((double)i/damp->scale_factor)))) / log10(0.5));
  348. }
  349. }
  350. int
  351. bgp_damp_enable (struct bgp *bgp, afi_t afi, safi_t safi, time_t half,
  352. unsigned int reuse, unsigned int suppress, time_t max)
  353. {
  354. if (CHECK_FLAG (bgp->af_flags[afi][safi], BGP_CONFIG_DAMPENING))
  355. {
  356. if (damp->half_life == half
  357. && damp->reuse_limit == reuse
  358. && damp->suppress_value == suppress
  359. && damp->max_suppress_time == max)
  360. return 0;
  361. bgp_damp_disable (bgp, afi, safi);
  362. }
  363. SET_FLAG (bgp->af_flags[afi][safi], BGP_CONFIG_DAMPENING);
  364. bgp_damp_parameter_set (half, reuse, suppress, max);
  365. /* Register reuse timer. */
  366. if (! damp->t_reuse)
  367. damp->t_reuse =
  368. thread_add_timer (master, bgp_reuse_timer, NULL, DELTA_REUSE);
  369. return 0;
  370. }
  371. static void
  372. bgp_damp_config_clean (struct bgp_damp_config *damp)
  373. {
  374. /* Free decay array */
  375. XFREE (MTYPE_BGP_DAMP_ARRAY, damp->decay_array);
  376. /* Free reuse index array */
  377. XFREE (MTYPE_BGP_DAMP_ARRAY, damp->reuse_index);
  378. /* Free reuse list array. */
  379. XFREE (MTYPE_BGP_DAMP_ARRAY, damp->reuse_list);
  380. }
  381. /* Clean all the bgp_damp_info stored in reuse_list. */
  382. void
  383. bgp_damp_info_clean (void)
  384. {
  385. unsigned int i;
  386. struct bgp_damp_info *bdi, *next;
  387. damp->reuse_offset = 0;
  388. for (i = 0; i < damp->reuse_list_size; i++)
  389. {
  390. if (! damp->reuse_list[i])
  391. continue;
  392. for (bdi = damp->reuse_list[i]; bdi; bdi = next)
  393. {
  394. next = bdi->next;
  395. bgp_damp_info_free (bdi, 1);
  396. }
  397. damp->reuse_list[i] = NULL;
  398. }
  399. for (bdi = damp->no_reuse_list; bdi; bdi = next)
  400. {
  401. next = bdi->next;
  402. bgp_damp_info_free (bdi, 1);
  403. }
  404. damp->no_reuse_list = NULL;
  405. }
  406. int
  407. bgp_damp_disable (struct bgp *bgp, afi_t afi, safi_t safi)
  408. {
  409. /* Cancel reuse thread. */
  410. if (damp->t_reuse )
  411. thread_cancel (damp->t_reuse);
  412. damp->t_reuse = NULL;
  413. /* Clean BGP dampening information. */
  414. bgp_damp_info_clean ();
  415. /* Clear configuration */
  416. bgp_damp_config_clean (&bgp_damp_cfg);
  417. UNSET_FLAG (bgp->af_flags[afi][safi], BGP_CONFIG_DAMPENING);
  418. return 0;
  419. }
  420. int
  421. bgp_config_write_damp (struct vty *vty)
  422. {
  423. if (&bgp_damp_cfg)
  424. {
  425. 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%s", VTY_NEWLINE);
  430. else if (bgp_damp_cfg.half_life != DEFAULT_HALF_LIFE*60
  431. && bgp_damp_cfg.reuse_limit == DEFAULT_REUSE
  432. && bgp_damp_cfg.suppress_value == DEFAULT_SUPPRESS
  433. && bgp_damp_cfg.max_suppress_time == bgp_damp_cfg.half_life*4)
  434. vty_out (vty, " bgp dampening %ld%s",
  435. bgp_damp_cfg.half_life/60,
  436. VTY_NEWLINE);
  437. else
  438. vty_out (vty, " bgp dampening %ld %d %d %ld%s",
  439. bgp_damp_cfg.half_life/60,
  440. bgp_damp_cfg.reuse_limit,
  441. bgp_damp_cfg.suppress_value,
  442. bgp_damp_cfg.max_suppress_time/60,
  443. VTY_NEWLINE);
  444. return 1;
  445. }
  446. return 0;
  447. }
  448. #define BGP_UPTIME_LEN 25
  449. char *
  450. bgp_get_reuse_time (unsigned int penalty, char *buf, size_t len)
  451. {
  452. time_t reuse_time = 0;
  453. struct tm *tm = NULL;
  454. if (penalty > damp->reuse_limit)
  455. {
  456. reuse_time = (int) (DELTA_T * ((log((double)damp->reuse_limit/penalty))/(log(damp->decay_array[1]))));
  457. if (reuse_time > damp->max_suppress_time)
  458. reuse_time = damp->max_suppress_time;
  459. tm = gmtime (&reuse_time);
  460. }
  461. else
  462. reuse_time = 0;
  463. /* Making formatted timer strings. */
  464. #define ONE_DAY_SECOND 60*60*24
  465. #define ONE_WEEK_SECOND 60*60*24*7
  466. if (reuse_time == 0)
  467. snprintf (buf, len, "00:00:00");
  468. else if (reuse_time < ONE_DAY_SECOND)
  469. snprintf (buf, len, "%02d:%02d:%02d",
  470. tm->tm_hour, tm->tm_min, tm->tm_sec);
  471. else if (reuse_time < ONE_WEEK_SECOND)
  472. snprintf (buf, len, "%dd%02dh%02dm",
  473. tm->tm_yday, tm->tm_hour, tm->tm_min);
  474. else
  475. snprintf (buf, len, "%02dw%dd%02dh",
  476. tm->tm_yday/7, tm->tm_yday - ((tm->tm_yday/7) * 7), tm->tm_hour);
  477. return buf;
  478. }
  479. void
  480. bgp_damp_info_vty (struct vty *vty, struct bgp_info *binfo)
  481. {
  482. struct bgp_damp_info *bdi;
  483. time_t t_now, t_diff;
  484. char timebuf[BGP_UPTIME_LEN];
  485. int penalty;
  486. /* BGP dampening information. */
  487. bdi = binfo->damp_info;
  488. /* If dampening is not enabled or there is no dampening information,
  489. return immediately. */
  490. if (! damp || ! bdi)
  491. return;
  492. /* Calculate new penalty. */
  493. t_now = time (NULL);
  494. t_diff = t_now - bdi->t_updated;
  495. penalty = bgp_damp_decay (t_diff, bdi->penalty);
  496. vty_out (vty, " Dampinfo: penalty %d, flapped %d times in %s",
  497. penalty, bdi->flap,
  498. peer_uptime (bdi->start_time, timebuf, BGP_UPTIME_LEN));
  499. if (CHECK_FLAG (binfo->flags, BGP_INFO_DAMPED)
  500. && ! CHECK_FLAG (binfo->flags, BGP_INFO_HISTORY))
  501. vty_out (vty, ", reuse in %s",
  502. bgp_get_reuse_time (penalty, timebuf, BGP_UPTIME_LEN));
  503. vty_out (vty, "%s", VTY_NEWLINE);
  504. }
  505. char *
  506. bgp_damp_reuse_time_vty (struct vty *vty, struct bgp_info *binfo)
  507. {
  508. struct bgp_damp_info *bdi;
  509. time_t t_now, t_diff;
  510. char timebuf[BGP_UPTIME_LEN];
  511. int penalty;
  512. /* BGP dampening information. */
  513. bdi = binfo->damp_info;
  514. /* If dampening is not enabled or there is no dampening information,
  515. return immediately. */
  516. if (! damp || ! bdi)
  517. return NULL;
  518. /* Calculate new penalty. */
  519. t_now = time (NULL);
  520. t_diff = t_now - bdi->t_updated;
  521. penalty = bgp_damp_decay (t_diff, bdi->penalty);
  522. return bgp_get_reuse_time (penalty, timebuf, BGP_UPTIME_LEN);
  523. }