bgp_damp.c
上传用户:xiaozhuqw
上传日期:2009-11-15
资源大小:1338k
文件大小:17k
源码类别:

网络

开发平台:

Unix_Linux

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