bgp_damp.c 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676
  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 "filter.h"
  24. #include "bgpd/bgpd.h"
  25. #include "bgpd/bgp_damp.h"
  26. #include "bgpd/bgp_table.h"
  27. #include "bgpd/bgp_route.h"
  28. #include "bgpd/bgp_attr.h"
  29. #include "bgpd/bgp_advertise.h"
  30. /* Global variable to access damping configuration */
  31. struct bgp_damp_config bgp_damp_cfg;
  32. static struct bgp_damp_config *damp = &bgp_damp_cfg;
  33. /* Utility macro to add and delete BGP dampening information to no
  34. used list. */
  35. #define BGP_DAMP_LIST_ADD(N,A) BGP_INFO_ADD(N,A,no_reuse_list)
  36. #define BGP_DAMP_LIST_DEL(N,A) BGP_INFO_DEL(N,A,no_reuse_list)
  37. /* Calculate reuse list index by penalty value. */
  38. static int
  39. bgp_reuse_index (int penalty)
  40. {
  41. unsigned int i;
  42. int index;
  43. i = (int)(((double) penalty / damp->reuse_limit - 1.0) * damp->scale_factor);
  44. if ( i >= damp->reuse_index_size )
  45. i = damp->reuse_index_size - 1;
  46. index = damp->reuse_index[i] - damp->reuse_index[0];
  47. return (damp->reuse_offset + index) % damp->reuse_list_size;
  48. }
  49. /* Add BGP dampening information to reuse list. */
  50. static void
  51. bgp_reuse_list_add (struct bgp_damp_info *bdi)
  52. {
  53. int index;
  54. index = bdi->index = bgp_reuse_index (bdi->penalty);
  55. bdi->prev = NULL;
  56. bdi->next = damp->reuse_list[index];
  57. if (damp->reuse_list[index])
  58. damp->reuse_list[index]->prev = bdi;
  59. damp->reuse_list[index] = bdi;
  60. }
  61. /* Delete BGP dampening information from reuse list. */
  62. static void
  63. bgp_reuse_list_delete (struct bgp_damp_info *bdi)
  64. {
  65. if (bdi->next)
  66. bdi->next->prev = bdi->prev;
  67. if (bdi->prev)
  68. bdi->prev->next = bdi->next;
  69. else
  70. damp->reuse_list[bdi->index] = bdi->next;
  71. }
  72. /* Return decayed penalty value. */
  73. int
  74. bgp_damp_decay (time_t tdiff, int penalty)
  75. {
  76. unsigned int i;
  77. i = (int) ((double) tdiff / DELTA_T);
  78. if (i == 0)
  79. return penalty;
  80. if (i >= damp->decay_array_size)
  81. return 0;
  82. return (int) (penalty * damp->decay_array[i]);
  83. }
  84. /* Handler of reuse timer event. Each route in the current reuse-list
  85. is evaluated. RFC2439 Section 4.8.7. */
  86. static int
  87. bgp_reuse_timer (struct thread *t)
  88. {
  89. struct bgp_damp_info *bdi;
  90. struct bgp_damp_info *next;
  91. time_t t_now, t_diff;
  92. damp->t_reuse = NULL;
  93. damp->t_reuse =
  94. thread_add_timer (bm->master, bgp_reuse_timer, NULL, DELTA_REUSE);
  95. t_now = bgp_clock ();
  96. /* 1. save a pointer to the current zeroth queue head and zero the
  97. list head entry. */
  98. bdi = damp->reuse_list[damp->reuse_offset];
  99. damp->reuse_list[damp->reuse_offset] = NULL;
  100. /* 2. set offset = modulo reuse-list-size ( offset + 1 ), thereby
  101. rotating the circular queue of list-heads. */
  102. damp->reuse_offset = (damp->reuse_offset + 1) % damp->reuse_list_size;
  103. /* 3. if ( the saved list head pointer is non-empty ) */
  104. for (; bdi; bdi = next)
  105. {
  106. struct bgp *bgp = bdi->binfo->peer->bgp;
  107. next = bdi->next;
  108. /* Set t-diff = t-now - t-updated. */
  109. t_diff = t_now - bdi->t_updated;
  110. /* Set figure-of-merit = figure-of-merit * decay-array-ok [t-diff] */
  111. bdi->penalty = bgp_damp_decay (t_diff, bdi->penalty);
  112. /* Set t-updated = t-now. */
  113. bdi->t_updated = t_now;
  114. /* if (figure-of-merit < reuse). */
  115. if (bdi->penalty < damp->reuse_limit)
  116. {
  117. /* Reuse the route. */
  118. bgp_info_unset_flag (bdi->rn, bdi->binfo, BGP_INFO_DAMPED);
  119. bdi->suppress_time = 0;
  120. if (bdi->lastrecord == BGP_RECORD_UPDATE)
  121. {
  122. bgp_info_unset_flag (bdi->rn, bdi->binfo, BGP_INFO_HISTORY);
  123. bgp_aggregate_increment (bgp, &bdi->rn->p, bdi->binfo,
  124. bdi->afi, bdi->safi);
  125. bgp_process (bgp, bdi->rn, bdi->afi, bdi->safi);
  126. }
  127. if (bdi->penalty <= damp->reuse_limit / 2.0)
  128. bgp_damp_info_free (bdi, 1);
  129. else
  130. BGP_DAMP_LIST_ADD (damp, bdi);
  131. }
  132. else
  133. /* Re-insert into another list (See RFC2439 Section 4.8.6). */
  134. bgp_reuse_list_add (bdi);
  135. }
  136. return 0;
  137. }
  138. /* A route becomes unreachable (RFC2439 Section 4.8.2). */
  139. int
  140. bgp_damp_withdraw (struct bgp_info *binfo, struct bgp_node *rn,
  141. afi_t afi, safi_t safi, int attr_change)
  142. {
  143. time_t t_now;
  144. struct bgp_damp_info *bdi = NULL;
  145. double last_penalty = 0;
  146. t_now = bgp_clock ();
  147. /* Processing Unreachable Messages. */
  148. if (binfo->extra)
  149. bdi = binfo->extra->damp_info;
  150. if (bdi == NULL)
  151. {
  152. /* If there is no previous stability history. */
  153. /* RFC2439 said:
  154. 1. allocate a damping structure.
  155. 2. set figure-of-merit = 1.
  156. 3. withdraw the route. */
  157. bdi = XCALLOC (MTYPE_BGP_DAMP_INFO, sizeof (struct bgp_damp_info));
  158. bdi->binfo = binfo;
  159. bdi->rn = rn;
  160. bdi->penalty = (attr_change ? DEFAULT_PENALTY / 2 : DEFAULT_PENALTY);
  161. bdi->flap = 1;
  162. bdi->start_time = t_now;
  163. bdi->suppress_time = 0;
  164. bdi->index = -1;
  165. bdi->afi = afi;
  166. bdi->safi = safi;
  167. (bgp_info_extra_get (binfo))->damp_info = bdi;
  168. BGP_DAMP_LIST_ADD (damp, bdi);
  169. }
  170. else
  171. {
  172. last_penalty = bdi->penalty;
  173. /* 1. Set t-diff = t-now - t-updated. */
  174. bdi->penalty =
  175. (bgp_damp_decay (t_now - bdi->t_updated, bdi->penalty)
  176. + (attr_change ? DEFAULT_PENALTY / 2 : DEFAULT_PENALTY));
  177. if (bdi->penalty > damp->ceiling)
  178. bdi->penalty = damp->ceiling;
  179. bdi->flap++;
  180. }
  181. assert ((rn == bdi->rn) && (binfo == bdi->binfo));
  182. bdi->lastrecord = BGP_RECORD_WITHDRAW;
  183. bdi->t_updated = t_now;
  184. /* Make this route as historical status. */
  185. bgp_info_set_flag (rn, binfo, 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. bgp_info_set_flag (rn, binfo, 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. if (!binfo->extra || !((bdi = binfo->extra->damp_info)))
  216. return BGP_DAMP_USED;
  217. t_now = bgp_clock ();
  218. bgp_info_unset_flag (rn, binfo, BGP_INFO_HISTORY);
  219. bdi->lastrecord = BGP_RECORD_UPDATE;
  220. bdi->penalty = bgp_damp_decay (t_now - bdi->t_updated, bdi->penalty);
  221. if (! CHECK_FLAG (bdi->binfo->flags, BGP_INFO_DAMPED)
  222. && (bdi->penalty < damp->suppress_value))
  223. status = BGP_DAMP_USED;
  224. else if (CHECK_FLAG (bdi->binfo->flags, BGP_INFO_DAMPED)
  225. && (bdi->penalty < damp->reuse_limit) )
  226. {
  227. bgp_info_unset_flag (rn, binfo, BGP_INFO_DAMPED);
  228. bgp_reuse_list_delete (bdi);
  229. BGP_DAMP_LIST_ADD (damp, bdi);
  230. bdi->suppress_time = 0;
  231. status = BGP_DAMP_USED;
  232. }
  233. else
  234. status = BGP_DAMP_SUPPRESSED;
  235. if (bdi->penalty > damp->reuse_limit / 2.0)
  236. bdi->t_updated = t_now;
  237. else
  238. bgp_damp_info_free (bdi, 0);
  239. return status;
  240. }
  241. /* Remove dampening information and history route. */
  242. int
  243. bgp_damp_scan (struct bgp_info *binfo, afi_t afi, safi_t safi)
  244. {
  245. time_t t_now, t_diff;
  246. struct bgp_damp_info *bdi;
  247. assert (binfo->extra && binfo->extra->damp_info);
  248. t_now = bgp_clock ();
  249. bdi = binfo->extra->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. bgp_info_unset_flag (bdi->rn, binfo, 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->extra->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. bgp_info_unset_flag (bdi->rn, binfo, BGP_INFO_HISTORY|BGP_INFO_DAMPED);
  296. if (bdi->lastrecord == BGP_RECORD_WITHDRAW && withdraw)
  297. bgp_info_delete (bdi->rn, binfo);
  298. XFREE (MTYPE_BGP_DAMP_INFO, bdi);
  299. }
  300. static void
  301. bgp_damp_parameter_set (int hlife, int reuse, int sup, int maxsup)
  302. {
  303. double reuse_max_ratio;
  304. unsigned int i;
  305. double j;
  306. damp->suppress_value = sup;
  307. damp->half_life = hlife;
  308. damp->reuse_limit = reuse;
  309. damp->max_suppress_time = maxsup;
  310. /* Initialize params per bgp_damp_config. */
  311. damp->reuse_index_size = REUSE_ARRAY_SIZE;
  312. damp->ceiling = (int)(damp->reuse_limit * (pow(2, (double)damp->max_suppress_time/damp->half_life)));
  313. /* Decay-array computations */
  314. damp->decay_array_size = ceil ((double) damp->max_suppress_time / DELTA_T);
  315. damp->decay_array = XMALLOC (MTYPE_BGP_DAMP_ARRAY,
  316. sizeof(double) * (damp->decay_array_size));
  317. damp->decay_array[0] = 1.0;
  318. damp->decay_array[1] = exp ((1.0/((double)damp->half_life/DELTA_T)) * log(0.5));
  319. /* Calculate decay values for all possible times */
  320. for (i = 2; i < damp->decay_array_size; i++)
  321. damp->decay_array[i] = damp->decay_array[i-1] * damp->decay_array[1];
  322. /* Reuse-list computations */
  323. i = ceil ((double)damp->max_suppress_time / DELTA_REUSE) + 1;
  324. if (i > REUSE_LIST_SIZE || i == 0)
  325. i = REUSE_LIST_SIZE;
  326. damp->reuse_list_size = i;
  327. damp->reuse_list = XCALLOC (MTYPE_BGP_DAMP_ARRAY,
  328. damp->reuse_list_size
  329. * sizeof (struct bgp_reuse_node *));
  330. /* Reuse-array computations */
  331. damp->reuse_index = XCALLOC (MTYPE_BGP_DAMP_ARRAY,
  332. sizeof(int) * damp->reuse_index_size);
  333. reuse_max_ratio = (double)damp->ceiling/damp->reuse_limit;
  334. j = (exp((double)damp->max_suppress_time/damp->half_life) * log10(2.0));
  335. if ( reuse_max_ratio > j && j != 0 )
  336. reuse_max_ratio = j;
  337. damp->scale_factor = (double)damp->reuse_index_size/(reuse_max_ratio - 1);
  338. for (i = 0; i < damp->reuse_index_size; i++)
  339. {
  340. damp->reuse_index[i] =
  341. (int)(((double)damp->half_life / DELTA_REUSE)
  342. * log10 (1.0 / (damp->reuse_limit * ( 1.0 + ((double)i/damp->scale_factor)))) / log10(0.5));
  343. }
  344. }
  345. int
  346. bgp_damp_enable (struct bgp *bgp, afi_t afi, safi_t safi, time_t half,
  347. unsigned int reuse, unsigned int suppress, time_t max)
  348. {
  349. if (CHECK_FLAG (bgp->af_flags[afi][safi], BGP_CONFIG_DAMPENING))
  350. {
  351. if (damp->half_life == half
  352. && damp->reuse_limit == reuse
  353. && damp->suppress_value == suppress
  354. && damp->max_suppress_time == max)
  355. return 0;
  356. bgp_damp_disable (bgp, afi, safi);
  357. }
  358. SET_FLAG (bgp->af_flags[afi][safi], BGP_CONFIG_DAMPENING);
  359. bgp_damp_parameter_set (half, reuse, suppress, max);
  360. /* Register reuse timer. */
  361. if (! damp->t_reuse)
  362. damp->t_reuse =
  363. thread_add_timer (bm->master, bgp_reuse_timer, NULL, DELTA_REUSE);
  364. return 0;
  365. }
  366. static void
  367. bgp_damp_config_clean (struct bgp_damp_config *damp)
  368. {
  369. /* Free decay array */
  370. XFREE (MTYPE_BGP_DAMP_ARRAY, damp->decay_array);
  371. /* Free reuse index array */
  372. XFREE (MTYPE_BGP_DAMP_ARRAY, damp->reuse_index);
  373. /* Free reuse list array. */
  374. XFREE (MTYPE_BGP_DAMP_ARRAY, damp->reuse_list);
  375. }
  376. /* Clean all the bgp_damp_info stored in reuse_list. */
  377. void
  378. bgp_damp_info_clean (void)
  379. {
  380. unsigned int i;
  381. struct bgp_damp_info *bdi, *next;
  382. damp->reuse_offset = 0;
  383. for (i = 0; i < damp->reuse_list_size; i++)
  384. {
  385. if (! damp->reuse_list[i])
  386. continue;
  387. for (bdi = damp->reuse_list[i]; bdi; bdi = next)
  388. {
  389. next = bdi->next;
  390. bgp_damp_info_free (bdi, 1);
  391. }
  392. damp->reuse_list[i] = NULL;
  393. }
  394. for (bdi = damp->no_reuse_list; bdi; bdi = next)
  395. {
  396. next = bdi->next;
  397. bgp_damp_info_free (bdi, 1);
  398. }
  399. damp->no_reuse_list = NULL;
  400. }
  401. int
  402. bgp_damp_disable (struct bgp *bgp, afi_t afi, safi_t safi)
  403. {
  404. /* If it wasn't enabled, there's nothing to do. */
  405. if (! CHECK_FLAG (bgp->af_flags[afi][safi], BGP_CONFIG_DAMPENING))
  406. return 0;
  407. /* Cancel reuse thread. */
  408. if (damp->t_reuse )
  409. thread_cancel (damp->t_reuse);
  410. damp->t_reuse = NULL;
  411. /* Clean BGP dampening information. */
  412. bgp_damp_info_clean ();
  413. /* Clear configuration */
  414. bgp_damp_config_clean (&bgp_damp_cfg);
  415. UNSET_FLAG (bgp->af_flags[afi][safi], BGP_CONFIG_DAMPENING);
  416. return 0;
  417. }
  418. void
  419. bgp_config_write_damp (struct vty *vty)
  420. {
  421. if (bgp_damp_cfg.half_life == DEFAULT_HALF_LIFE*60
  422. && bgp_damp_cfg.reuse_limit == DEFAULT_REUSE
  423. && bgp_damp_cfg.suppress_value == DEFAULT_SUPPRESS
  424. && bgp_damp_cfg.max_suppress_time == bgp_damp_cfg.half_life*4)
  425. vty_out (vty, " bgp dampening%s", VTY_NEWLINE);
  426. else if (bgp_damp_cfg.half_life != DEFAULT_HALF_LIFE*60
  427. && bgp_damp_cfg.reuse_limit == DEFAULT_REUSE
  428. && bgp_damp_cfg.suppress_value == DEFAULT_SUPPRESS
  429. && bgp_damp_cfg.max_suppress_time == bgp_damp_cfg.half_life*4)
  430. vty_out (vty, " bgp dampening %lld%s",
  431. bgp_damp_cfg.half_life/60LL,
  432. VTY_NEWLINE);
  433. else
  434. vty_out (vty, " bgp dampening %lld %d %d %lld%s",
  435. bgp_damp_cfg.half_life/60LL,
  436. bgp_damp_cfg.reuse_limit,
  437. bgp_damp_cfg.suppress_value,
  438. bgp_damp_cfg.max_suppress_time/60LL,
  439. VTY_NEWLINE);
  440. }
  441. static const char *
  442. bgp_get_reuse_time (unsigned int penalty, char *buf, size_t len)
  443. {
  444. time_t reuse_time = 0;
  445. struct tm *tm = NULL;
  446. if (penalty > damp->reuse_limit)
  447. {
  448. reuse_time = (int) (DELTA_T * ((log((double)damp->reuse_limit/penalty))/(log(damp->decay_array[1]))));
  449. if (reuse_time > damp->max_suppress_time)
  450. reuse_time = damp->max_suppress_time;
  451. tm = gmtime (&reuse_time);
  452. }
  453. else
  454. reuse_time = 0;
  455. /* Making formatted timer strings. */
  456. #define ONE_DAY_SECOND 60*60*24
  457. #define ONE_WEEK_SECOND 60*60*24*7
  458. if (reuse_time == 0)
  459. snprintf (buf, len, "00:00:00");
  460. else if (reuse_time < ONE_DAY_SECOND)
  461. snprintf (buf, len, "%02d:%02d:%02d",
  462. tm->tm_hour, tm->tm_min, tm->tm_sec);
  463. else if (reuse_time < ONE_WEEK_SECOND)
  464. snprintf (buf, len, "%dd%02dh%02dm",
  465. tm->tm_yday, tm->tm_hour, tm->tm_min);
  466. else
  467. snprintf (buf, len, "%02dw%dd%02dh",
  468. tm->tm_yday/7, tm->tm_yday - ((tm->tm_yday/7) * 7), tm->tm_hour);
  469. return buf;
  470. }
  471. void
  472. bgp_damp_info_vty (struct vty *vty, struct bgp_info *binfo)
  473. {
  474. struct bgp_damp_info *bdi;
  475. time_t t_now, t_diff;
  476. char timebuf[BGP_UPTIME_LEN];
  477. int penalty;
  478. if (!binfo->extra)
  479. return;
  480. /* BGP dampening information. */
  481. bdi = binfo->extra->damp_info;
  482. /* If dampening is not enabled or there is no dampening information,
  483. return immediately. */
  484. if (! damp || ! bdi)
  485. return;
  486. /* Calculate new penalty. */
  487. t_now = bgp_clock ();
  488. t_diff = t_now - bdi->t_updated;
  489. penalty = bgp_damp_decay (t_diff, bdi->penalty);
  490. vty_out (vty, " Dampinfo: penalty %d, flapped %d times in %s",
  491. penalty, bdi->flap,
  492. peer_uptime (bdi->start_time, timebuf, BGP_UPTIME_LEN));
  493. if (CHECK_FLAG (binfo->flags, BGP_INFO_DAMPED)
  494. && ! CHECK_FLAG (binfo->flags, BGP_INFO_HISTORY))
  495. vty_out (vty, ", reuse in %s",
  496. bgp_get_reuse_time (penalty, timebuf, BGP_UPTIME_LEN));
  497. vty_out (vty, "%s", VTY_NEWLINE);
  498. }
  499. const char *
  500. bgp_damp_reuse_time_vty (struct vty *vty, struct bgp_info *binfo,
  501. char *timebuf, size_t len)
  502. {
  503. struct bgp_damp_info *bdi;
  504. time_t t_now, t_diff;
  505. int penalty;
  506. if (!binfo->extra)
  507. return NULL;
  508. /* BGP dampening information. */
  509. bdi = binfo->extra->damp_info;
  510. /* If dampening is not enabled or there is no dampening information,
  511. return immediately. */
  512. if (! damp || ! bdi)
  513. return NULL;
  514. /* Calculate new penalty. */
  515. t_now = bgp_clock ();
  516. t_diff = t_now - bdi->t_updated;
  517. penalty = bgp_damp_decay (t_diff, bdi->penalty);
  518. return bgp_get_reuse_time (penalty, timebuf, len);
  519. }
  520. int
  521. bgp_show_dampening_parameters (struct vty *vty, afi_t afi, safi_t safi)
  522. {
  523. struct bgp *bgp;
  524. bgp = bgp_get_default();
  525. if (bgp == NULL)
  526. {
  527. vty_out (vty, "No BGP process is configured%s", VTY_NEWLINE);
  528. return CMD_WARNING;
  529. }
  530. if (CHECK_FLAG (bgp->af_flags[afi][safi], BGP_CONFIG_DAMPENING))
  531. {
  532. vty_out (vty, "Half-life time: %ld min%s",
  533. damp->half_life / 60, VTY_NEWLINE);
  534. vty_out (vty, "Reuse penalty: %d%s",
  535. damp->reuse_limit, VTY_NEWLINE);
  536. vty_out (vty, "Suppress penalty: %d%s",
  537. damp->suppress_value, VTY_NEWLINE);
  538. vty_out (vty, "Max suppress time: %ld min%s",
  539. damp->max_suppress_time / 60, VTY_NEWLINE);
  540. vty_out (vty, "Max suppress penalty: %u%s",
  541. damp->ceiling, VTY_NEWLINE);
  542. vty_out (vty, "%s", VTY_NEWLINE);
  543. }
  544. else
  545. vty_out (vty, "dampening not enabled for %s%s",
  546. afi == AFI_IP ? "IPv4" : "IPv6", VTY_NEWLINE);
  547. return CMD_SUCCESS;
  548. }