mirror of
https://git.proxmox.com/git/mirror_frr
synced 2025-05-29 15:07:51 +00:00

Problem reported that some bgp and ospf json commands did not return any json output at all if the bgp/ospf instance did not exist. Additionally, some bgp and ospf json commands did not return any json output if the instance existed but no neighbors were defined. This fix makes these commands more consistent in returning empty braces for json output and issue a message if not using json output. Additionally, made the flag "use_json" a bool to make it consistent since previously, it had been defined as an int, char, u_char, and bool at various places. Ticket: CM-21040 Signed-off-by: Don Slice <dslice@cumulusnetworks.com>
695 lines
18 KiB
C
695 lines
18 KiB
C
/* BGP flap dampening
|
|
* Copyright (C) 2001 IP Infusion Inc.
|
|
*
|
|
* This file is part of GNU Zebra.
|
|
*
|
|
* GNU Zebra is free software; you can redistribute it and/or modify it
|
|
* under the terms of the GNU General Public License as published by the
|
|
* Free Software Foundation; either version 2, or (at your option) any
|
|
* later version.
|
|
*
|
|
* GNU Zebra is distributed in the hope that it will be useful, but
|
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License along
|
|
* with this program; see the file COPYING; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
*/
|
|
|
|
#include <zebra.h>
|
|
#include <math.h>
|
|
|
|
#include "prefix.h"
|
|
#include "memory.h"
|
|
#include "command.h"
|
|
#include "log.h"
|
|
#include "thread.h"
|
|
#include "queue.h"
|
|
#include "filter.h"
|
|
|
|
#include "bgpd/bgpd.h"
|
|
#include "bgpd/bgp_damp.h"
|
|
#include "bgpd/bgp_table.h"
|
|
#include "bgpd/bgp_route.h"
|
|
#include "bgpd/bgp_attr.h"
|
|
#include "bgpd/bgp_advertise.h"
|
|
|
|
/* Global variable to access damping configuration */
|
|
struct bgp_damp_config bgp_damp_cfg;
|
|
static struct bgp_damp_config *damp = &bgp_damp_cfg;
|
|
|
|
/* Utility macro to add and delete BGP dampening information to no
|
|
used list. */
|
|
#define BGP_DAMP_LIST_ADD(N,A) BGP_INFO_ADD(N,A,no_reuse_list)
|
|
#define BGP_DAMP_LIST_DEL(N,A) BGP_INFO_DEL(N,A,no_reuse_list)
|
|
|
|
/* Calculate reuse list index by penalty value. */
|
|
static int bgp_reuse_index(int penalty)
|
|
{
|
|
unsigned int i;
|
|
int index;
|
|
|
|
i = (int)(((double)penalty / damp->reuse_limit - 1.0)
|
|
* damp->scale_factor);
|
|
|
|
if (i >= damp->reuse_index_size)
|
|
i = damp->reuse_index_size - 1;
|
|
|
|
index = damp->reuse_index[i] - damp->reuse_index[0];
|
|
|
|
return (damp->reuse_offset + index) % damp->reuse_list_size;
|
|
}
|
|
|
|
/* Add BGP dampening information to reuse list. */
|
|
static void bgp_reuse_list_add(struct bgp_damp_info *bdi)
|
|
{
|
|
int index;
|
|
|
|
index = bdi->index = bgp_reuse_index(bdi->penalty);
|
|
|
|
bdi->prev = NULL;
|
|
bdi->next = damp->reuse_list[index];
|
|
if (damp->reuse_list[index])
|
|
damp->reuse_list[index]->prev = bdi;
|
|
damp->reuse_list[index] = bdi;
|
|
}
|
|
|
|
/* Delete BGP dampening information from reuse list. */
|
|
static void bgp_reuse_list_delete(struct bgp_damp_info *bdi)
|
|
{
|
|
if (bdi->next)
|
|
bdi->next->prev = bdi->prev;
|
|
if (bdi->prev)
|
|
bdi->prev->next = bdi->next;
|
|
else
|
|
damp->reuse_list[bdi->index] = bdi->next;
|
|
}
|
|
|
|
/* Return decayed penalty value. */
|
|
int bgp_damp_decay(time_t tdiff, int penalty)
|
|
{
|
|
unsigned int i;
|
|
|
|
i = (int)((double)tdiff / DELTA_T);
|
|
|
|
if (i == 0)
|
|
return penalty;
|
|
|
|
if (i >= damp->decay_array_size)
|
|
return 0;
|
|
|
|
return (int)(penalty * damp->decay_array[i]);
|
|
}
|
|
|
|
/* Handler of reuse timer event. Each route in the current reuse-list
|
|
is evaluated. RFC2439 Section 4.8.7. */
|
|
static int bgp_reuse_timer(struct thread *t)
|
|
{
|
|
struct bgp_damp_info *bdi;
|
|
struct bgp_damp_info *next;
|
|
time_t t_now, t_diff;
|
|
|
|
damp->t_reuse = NULL;
|
|
thread_add_timer(bm->master, bgp_reuse_timer, NULL, DELTA_REUSE,
|
|
&damp->t_reuse);
|
|
|
|
t_now = bgp_clock();
|
|
|
|
/* 1. save a pointer to the current zeroth queue head and zero the
|
|
list head entry. */
|
|
bdi = damp->reuse_list[damp->reuse_offset];
|
|
damp->reuse_list[damp->reuse_offset] = NULL;
|
|
|
|
/* 2. set offset = modulo reuse-list-size ( offset + 1 ), thereby
|
|
rotating the circular queue of list-heads. */
|
|
damp->reuse_offset = (damp->reuse_offset + 1) % damp->reuse_list_size;
|
|
|
|
/* 3. if ( the saved list head pointer is non-empty ) */
|
|
for (; bdi; bdi = next) {
|
|
struct bgp *bgp = bdi->binfo->peer->bgp;
|
|
|
|
next = bdi->next;
|
|
|
|
/* Set t-diff = t-now - t-updated. */
|
|
t_diff = t_now - bdi->t_updated;
|
|
|
|
/* Set figure-of-merit = figure-of-merit * decay-array-ok
|
|
* [t-diff] */
|
|
bdi->penalty = bgp_damp_decay(t_diff, bdi->penalty);
|
|
|
|
/* Set t-updated = t-now. */
|
|
bdi->t_updated = t_now;
|
|
|
|
/* if (figure-of-merit < reuse). */
|
|
if (bdi->penalty < damp->reuse_limit) {
|
|
/* Reuse the route. */
|
|
bgp_info_unset_flag(bdi->rn, bdi->binfo,
|
|
BGP_INFO_DAMPED);
|
|
bdi->suppress_time = 0;
|
|
|
|
if (bdi->lastrecord == BGP_RECORD_UPDATE) {
|
|
bgp_info_unset_flag(bdi->rn, bdi->binfo,
|
|
BGP_INFO_HISTORY);
|
|
bgp_aggregate_increment(bgp, &bdi->rn->p,
|
|
bdi->binfo, bdi->afi,
|
|
bdi->safi);
|
|
bgp_process(bgp, bdi->rn, bdi->afi, bdi->safi);
|
|
}
|
|
|
|
if (bdi->penalty <= damp->reuse_limit / 2.0)
|
|
bgp_damp_info_free(bdi, 1);
|
|
else
|
|
BGP_DAMP_LIST_ADD(damp, bdi);
|
|
} else
|
|
/* Re-insert into another list (See RFC2439 Section
|
|
* 4.8.6). */
|
|
bgp_reuse_list_add(bdi);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* A route becomes unreachable (RFC2439 Section 4.8.2). */
|
|
int bgp_damp_withdraw(struct bgp_info *binfo, struct bgp_node *rn, afi_t afi,
|
|
safi_t safi, int attr_change)
|
|
{
|
|
time_t t_now;
|
|
struct bgp_damp_info *bdi = NULL;
|
|
double last_penalty = 0;
|
|
|
|
t_now = bgp_clock();
|
|
|
|
/* Processing Unreachable Messages. */
|
|
if (binfo->extra)
|
|
bdi = binfo->extra->damp_info;
|
|
|
|
if (bdi == NULL) {
|
|
/* If there is no previous stability history. */
|
|
|
|
/* RFC2439 said:
|
|
1. allocate a damping structure.
|
|
2. set figure-of-merit = 1.
|
|
3. withdraw the route. */
|
|
|
|
bdi = XCALLOC(MTYPE_BGP_DAMP_INFO,
|
|
sizeof(struct bgp_damp_info));
|
|
bdi->binfo = binfo;
|
|
bdi->rn = rn;
|
|
bdi->penalty =
|
|
(attr_change ? DEFAULT_PENALTY / 2 : DEFAULT_PENALTY);
|
|
bdi->flap = 1;
|
|
bdi->start_time = t_now;
|
|
bdi->suppress_time = 0;
|
|
bdi->index = -1;
|
|
bdi->afi = afi;
|
|
bdi->safi = safi;
|
|
(bgp_info_extra_get(binfo))->damp_info = bdi;
|
|
BGP_DAMP_LIST_ADD(damp, bdi);
|
|
} else {
|
|
last_penalty = bdi->penalty;
|
|
|
|
/* 1. Set t-diff = t-now - t-updated. */
|
|
bdi->penalty =
|
|
(bgp_damp_decay(t_now - bdi->t_updated, bdi->penalty)
|
|
+ (attr_change ? DEFAULT_PENALTY / 2
|
|
: DEFAULT_PENALTY));
|
|
|
|
if (bdi->penalty > damp->ceiling)
|
|
bdi->penalty = damp->ceiling;
|
|
|
|
bdi->flap++;
|
|
}
|
|
|
|
assert((rn == bdi->rn) && (binfo == bdi->binfo));
|
|
|
|
bdi->lastrecord = BGP_RECORD_WITHDRAW;
|
|
bdi->t_updated = t_now;
|
|
|
|
/* Make this route as historical status. */
|
|
bgp_info_set_flag(rn, binfo, BGP_INFO_HISTORY);
|
|
|
|
/* Remove the route from a reuse list if it is on one. */
|
|
if (CHECK_FLAG(bdi->binfo->flags, BGP_INFO_DAMPED)) {
|
|
/* If decay rate isn't equal to 0, reinsert brn. */
|
|
if (bdi->penalty != last_penalty && bdi->index >= 0) {
|
|
bgp_reuse_list_delete(bdi);
|
|
bgp_reuse_list_add(bdi);
|
|
}
|
|
return BGP_DAMP_SUPPRESSED;
|
|
}
|
|
|
|
/* If not suppressed before, do annonunce this withdraw and
|
|
insert into reuse_list. */
|
|
if (bdi->penalty >= damp->suppress_value) {
|
|
bgp_info_set_flag(rn, binfo, BGP_INFO_DAMPED);
|
|
bdi->suppress_time = t_now;
|
|
BGP_DAMP_LIST_DEL(damp, bdi);
|
|
bgp_reuse_list_add(bdi);
|
|
}
|
|
|
|
return BGP_DAMP_USED;
|
|
}
|
|
|
|
int bgp_damp_update(struct bgp_info *binfo, struct bgp_node *rn, afi_t afi,
|
|
safi_t safi)
|
|
{
|
|
time_t t_now;
|
|
struct bgp_damp_info *bdi;
|
|
int status;
|
|
|
|
if (!binfo->extra || !((bdi = binfo->extra->damp_info)))
|
|
return BGP_DAMP_USED;
|
|
|
|
t_now = bgp_clock();
|
|
bgp_info_unset_flag(rn, binfo, BGP_INFO_HISTORY);
|
|
|
|
bdi->lastrecord = BGP_RECORD_UPDATE;
|
|
bdi->penalty = bgp_damp_decay(t_now - bdi->t_updated, bdi->penalty);
|
|
|
|
if (!CHECK_FLAG(bdi->binfo->flags, BGP_INFO_DAMPED)
|
|
&& (bdi->penalty < damp->suppress_value))
|
|
status = BGP_DAMP_USED;
|
|
else if (CHECK_FLAG(bdi->binfo->flags, BGP_INFO_DAMPED)
|
|
&& (bdi->penalty < damp->reuse_limit)) {
|
|
bgp_info_unset_flag(rn, binfo, BGP_INFO_DAMPED);
|
|
bgp_reuse_list_delete(bdi);
|
|
BGP_DAMP_LIST_ADD(damp, bdi);
|
|
bdi->suppress_time = 0;
|
|
status = BGP_DAMP_USED;
|
|
} else
|
|
status = BGP_DAMP_SUPPRESSED;
|
|
|
|
if (bdi->penalty > damp->reuse_limit / 2.0)
|
|
bdi->t_updated = t_now;
|
|
else
|
|
bgp_damp_info_free(bdi, 0);
|
|
|
|
return status;
|
|
}
|
|
|
|
/* Remove dampening information and history route. */
|
|
int bgp_damp_scan(struct bgp_info *binfo, afi_t afi, safi_t safi)
|
|
{
|
|
time_t t_now, t_diff;
|
|
struct bgp_damp_info *bdi;
|
|
|
|
assert(binfo->extra && binfo->extra->damp_info);
|
|
|
|
t_now = bgp_clock();
|
|
bdi = binfo->extra->damp_info;
|
|
|
|
if (CHECK_FLAG(binfo->flags, BGP_INFO_DAMPED)) {
|
|
t_diff = t_now - bdi->suppress_time;
|
|
|
|
if (t_diff >= damp->max_suppress_time) {
|
|
bgp_info_unset_flag(bdi->rn, binfo, BGP_INFO_DAMPED);
|
|
bgp_reuse_list_delete(bdi);
|
|
BGP_DAMP_LIST_ADD(damp, bdi);
|
|
bdi->penalty = damp->reuse_limit;
|
|
bdi->suppress_time = 0;
|
|
bdi->t_updated = t_now;
|
|
|
|
/* Need to announce UPDATE once this binfo is usable
|
|
* again. */
|
|
if (bdi->lastrecord == BGP_RECORD_UPDATE)
|
|
return 1;
|
|
else
|
|
return 0;
|
|
}
|
|
} else {
|
|
t_diff = t_now - bdi->t_updated;
|
|
bdi->penalty = bgp_damp_decay(t_diff, bdi->penalty);
|
|
|
|
if (bdi->penalty <= damp->reuse_limit / 2.0) {
|
|
/* release the bdi, bdi->binfo. */
|
|
bgp_damp_info_free(bdi, 1);
|
|
return 0;
|
|
} else
|
|
bdi->t_updated = t_now;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
void bgp_damp_info_free(struct bgp_damp_info *bdi, int withdraw)
|
|
{
|
|
struct bgp_info *binfo;
|
|
|
|
if (!bdi)
|
|
return;
|
|
|
|
binfo = bdi->binfo;
|
|
binfo->extra->damp_info = NULL;
|
|
|
|
if (CHECK_FLAG(binfo->flags, BGP_INFO_DAMPED))
|
|
bgp_reuse_list_delete(bdi);
|
|
else
|
|
BGP_DAMP_LIST_DEL(damp, bdi);
|
|
|
|
bgp_info_unset_flag(bdi->rn, binfo, BGP_INFO_HISTORY | BGP_INFO_DAMPED);
|
|
|
|
if (bdi->lastrecord == BGP_RECORD_WITHDRAW && withdraw)
|
|
bgp_info_delete(bdi->rn, binfo);
|
|
|
|
XFREE(MTYPE_BGP_DAMP_INFO, bdi);
|
|
}
|
|
|
|
static void bgp_damp_parameter_set(int hlife, int reuse, int sup, int maxsup)
|
|
{
|
|
double reuse_max_ratio;
|
|
unsigned int i;
|
|
double j;
|
|
|
|
damp->suppress_value = sup;
|
|
damp->half_life = hlife;
|
|
damp->reuse_limit = reuse;
|
|
damp->max_suppress_time = maxsup;
|
|
|
|
/* Initialize params per bgp_damp_config. */
|
|
damp->reuse_index_size = REUSE_ARRAY_SIZE;
|
|
|
|
damp->ceiling =
|
|
(int)(damp->reuse_limit * (pow(2,
|
|
(double)damp->max_suppress_time
|
|
/ damp->half_life)));
|
|
|
|
/* Decay-array computations */
|
|
damp->decay_array_size =
|
|
ceil((double)damp->max_suppress_time / DELTA_T);
|
|
damp->decay_array = XMALLOC(MTYPE_BGP_DAMP_ARRAY,
|
|
sizeof(double) * (damp->decay_array_size));
|
|
damp->decay_array[0] = 1.0;
|
|
damp->decay_array[1] =
|
|
exp((1.0 / ((double)damp->half_life / DELTA_T)) * log(0.5));
|
|
|
|
/* Calculate decay values for all possible times */
|
|
for (i = 2; i < damp->decay_array_size; i++)
|
|
damp->decay_array[i] =
|
|
damp->decay_array[i - 1] * damp->decay_array[1];
|
|
|
|
/* Reuse-list computations */
|
|
i = ceil((double)damp->max_suppress_time / DELTA_REUSE) + 1;
|
|
if (i > REUSE_LIST_SIZE || i == 0)
|
|
i = REUSE_LIST_SIZE;
|
|
damp->reuse_list_size = i;
|
|
|
|
damp->reuse_list = XCALLOC(MTYPE_BGP_DAMP_ARRAY,
|
|
damp->reuse_list_size
|
|
* sizeof(struct bgp_reuse_node *));
|
|
|
|
/* Reuse-array computations */
|
|
damp->reuse_index = XCALLOC(MTYPE_BGP_DAMP_ARRAY,
|
|
sizeof(int) * damp->reuse_index_size);
|
|
|
|
reuse_max_ratio = (double)damp->ceiling / damp->reuse_limit;
|
|
j = (exp((double)damp->max_suppress_time / damp->half_life)
|
|
* log10(2.0));
|
|
if (reuse_max_ratio > j && j != 0)
|
|
reuse_max_ratio = j;
|
|
|
|
damp->scale_factor =
|
|
(double)damp->reuse_index_size / (reuse_max_ratio - 1);
|
|
|
|
for (i = 0; i < damp->reuse_index_size; i++) {
|
|
damp->reuse_index[i] =
|
|
(int)(((double)damp->half_life / DELTA_REUSE)
|
|
* log10(1.0 / (damp->reuse_limit
|
|
* (1.0 + ((double)i
|
|
/ damp->scale_factor))))
|
|
/ log10(0.5));
|
|
}
|
|
}
|
|
|
|
int bgp_damp_enable(struct bgp *bgp, afi_t afi, safi_t safi, time_t half,
|
|
unsigned int reuse, unsigned int suppress, time_t max)
|
|
{
|
|
if (CHECK_FLAG(bgp->af_flags[afi][safi], BGP_CONFIG_DAMPENING)) {
|
|
if (damp->half_life == half && damp->reuse_limit == reuse
|
|
&& damp->suppress_value == suppress
|
|
&& damp->max_suppress_time == max)
|
|
return 0;
|
|
bgp_damp_disable(bgp, afi, safi);
|
|
}
|
|
|
|
SET_FLAG(bgp->af_flags[afi][safi], BGP_CONFIG_DAMPENING);
|
|
bgp_damp_parameter_set(half, reuse, suppress, max);
|
|
|
|
/* Register reuse timer. */
|
|
thread_add_timer(bm->master, bgp_reuse_timer, NULL, DELTA_REUSE,
|
|
&damp->t_reuse);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void bgp_damp_config_clean(struct bgp_damp_config *damp)
|
|
{
|
|
/* Free decay array */
|
|
XFREE(MTYPE_BGP_DAMP_ARRAY, damp->decay_array);
|
|
|
|
/* Free reuse index array */
|
|
XFREE(MTYPE_BGP_DAMP_ARRAY, damp->reuse_index);
|
|
|
|
/* Free reuse list array. */
|
|
XFREE(MTYPE_BGP_DAMP_ARRAY, damp->reuse_list);
|
|
}
|
|
|
|
/* Clean all the bgp_damp_info stored in reuse_list. */
|
|
void bgp_damp_info_clean(void)
|
|
{
|
|
unsigned int i;
|
|
struct bgp_damp_info *bdi, *next;
|
|
|
|
damp->reuse_offset = 0;
|
|
|
|
for (i = 0; i < damp->reuse_list_size; i++) {
|
|
if (!damp->reuse_list[i])
|
|
continue;
|
|
|
|
for (bdi = damp->reuse_list[i]; bdi; bdi = next) {
|
|
next = bdi->next;
|
|
bgp_damp_info_free(bdi, 1);
|
|
}
|
|
damp->reuse_list[i] = NULL;
|
|
}
|
|
|
|
for (bdi = damp->no_reuse_list; bdi; bdi = next) {
|
|
next = bdi->next;
|
|
bgp_damp_info_free(bdi, 1);
|
|
}
|
|
damp->no_reuse_list = NULL;
|
|
}
|
|
|
|
int bgp_damp_disable(struct bgp *bgp, afi_t afi, safi_t safi)
|
|
{
|
|
/* If it wasn't enabled, there's nothing to do. */
|
|
if (!CHECK_FLAG(bgp->af_flags[afi][safi], BGP_CONFIG_DAMPENING))
|
|
return 0;
|
|
|
|
/* Cancel reuse thread. */
|
|
if (damp->t_reuse)
|
|
thread_cancel(damp->t_reuse);
|
|
damp->t_reuse = NULL;
|
|
|
|
/* Clean BGP dampening information. */
|
|
bgp_damp_info_clean();
|
|
|
|
/* Clear configuration */
|
|
bgp_damp_config_clean(&bgp_damp_cfg);
|
|
|
|
UNSET_FLAG(bgp->af_flags[afi][safi], BGP_CONFIG_DAMPENING);
|
|
return 0;
|
|
}
|
|
|
|
void bgp_config_write_damp(struct vty *vty)
|
|
{
|
|
if (bgp_damp_cfg.half_life == DEFAULT_HALF_LIFE * 60
|
|
&& bgp_damp_cfg.reuse_limit == DEFAULT_REUSE
|
|
&& bgp_damp_cfg.suppress_value == DEFAULT_SUPPRESS
|
|
&& bgp_damp_cfg.max_suppress_time == bgp_damp_cfg.half_life * 4)
|
|
vty_out(vty, " bgp dampening\n");
|
|
else if (bgp_damp_cfg.half_life != DEFAULT_HALF_LIFE * 60
|
|
&& bgp_damp_cfg.reuse_limit == DEFAULT_REUSE
|
|
&& bgp_damp_cfg.suppress_value == DEFAULT_SUPPRESS
|
|
&& bgp_damp_cfg.max_suppress_time
|
|
== bgp_damp_cfg.half_life * 4)
|
|
vty_out(vty, " bgp dampening %lld\n",
|
|
bgp_damp_cfg.half_life / 60LL);
|
|
else
|
|
vty_out(vty, " bgp dampening %lld %d %d %lld\n",
|
|
bgp_damp_cfg.half_life / 60LL, bgp_damp_cfg.reuse_limit,
|
|
bgp_damp_cfg.suppress_value,
|
|
bgp_damp_cfg.max_suppress_time / 60LL);
|
|
}
|
|
|
|
static const char *bgp_get_reuse_time(unsigned int penalty, char *buf,
|
|
size_t len, bool use_json,
|
|
json_object *json)
|
|
{
|
|
time_t reuse_time = 0;
|
|
struct tm *tm = NULL;
|
|
int time_store = 0;
|
|
|
|
if (penalty > damp->reuse_limit) {
|
|
reuse_time = (int)(DELTA_T
|
|
* ((log((double)damp->reuse_limit / penalty))
|
|
/ (log(damp->decay_array[1]))));
|
|
|
|
if (reuse_time > damp->max_suppress_time)
|
|
reuse_time = damp->max_suppress_time;
|
|
|
|
tm = gmtime(&reuse_time);
|
|
} else
|
|
reuse_time = 0;
|
|
|
|
/* Making formatted timer strings. */
|
|
if (reuse_time == 0) {
|
|
if (use_json)
|
|
json_object_int_add(json, "reuseTimerMsecs", 0);
|
|
else
|
|
snprintf(buf, len, "00:00:00");
|
|
} else if (reuse_time < ONE_DAY_SECOND) {
|
|
if (use_json) {
|
|
time_store = (3600000 * tm->tm_hour)
|
|
+ (60000 * tm->tm_min)
|
|
+ (1000 * tm->tm_sec);
|
|
json_object_int_add(json, "reuseTimerMsecs",
|
|
time_store);
|
|
} else
|
|
snprintf(buf, len, "%02d:%02d:%02d", tm->tm_hour,
|
|
tm->tm_min, tm->tm_sec);
|
|
} else if (reuse_time < ONE_WEEK_SECOND) {
|
|
if (use_json) {
|
|
time_store = (86400000 * tm->tm_yday)
|
|
+ (3600000 * tm->tm_hour)
|
|
+ (60000 * tm->tm_min)
|
|
+ (1000 * tm->tm_sec);
|
|
json_object_int_add(json, "reuseTimerMsecs",
|
|
time_store);
|
|
} else
|
|
snprintf(buf, len, "%dd%02dh%02dm", tm->tm_yday,
|
|
tm->tm_hour, tm->tm_min);
|
|
} else {
|
|
if (use_json) {
|
|
time_store =
|
|
(604800000 * tm->tm_yday / 7)
|
|
+ (86400000
|
|
* (tm->tm_yday - ((tm->tm_yday / 7) * 7)))
|
|
+ (3600000 * tm->tm_hour) + (60000 * tm->tm_min)
|
|
+ (1000 * tm->tm_sec);
|
|
json_object_int_add(json, "reuseTimerMsecs",
|
|
time_store);
|
|
} else
|
|
snprintf(buf, len, "%02dw%dd%02dh", tm->tm_yday / 7,
|
|
tm->tm_yday - ((tm->tm_yday / 7) * 7),
|
|
tm->tm_hour);
|
|
}
|
|
|
|
return buf;
|
|
}
|
|
|
|
void bgp_damp_info_vty(struct vty *vty, struct bgp_info *binfo,
|
|
json_object *json_path)
|
|
{
|
|
struct bgp_damp_info *bdi;
|
|
time_t t_now, t_diff;
|
|
char timebuf[BGP_UPTIME_LEN];
|
|
int penalty;
|
|
|
|
if (!binfo->extra)
|
|
return;
|
|
|
|
/* BGP dampening information. */
|
|
bdi = binfo->extra->damp_info;
|
|
|
|
/* If dampening is not enabled or there is no dampening information,
|
|
return immediately. */
|
|
if (!damp || !bdi)
|
|
return;
|
|
|
|
/* Calculate new penalty. */
|
|
t_now = bgp_clock();
|
|
t_diff = t_now - bdi->t_updated;
|
|
penalty = bgp_damp_decay(t_diff, bdi->penalty);
|
|
|
|
if (json_path) {
|
|
json_object_int_add(json_path, "dampeningPenalty", penalty);
|
|
json_object_int_add(json_path, "dampeningFlapCount", bdi->flap);
|
|
peer_uptime(bdi->start_time, timebuf, BGP_UPTIME_LEN, 1,
|
|
json_path);
|
|
|
|
if (CHECK_FLAG(binfo->flags, BGP_INFO_DAMPED)
|
|
&& !CHECK_FLAG(binfo->flags, BGP_INFO_HISTORY))
|
|
bgp_get_reuse_time(penalty, timebuf, BGP_UPTIME_LEN, 1,
|
|
json_path);
|
|
} else {
|
|
vty_out(vty,
|
|
" Dampinfo: penalty %d, flapped %d times in %s",
|
|
penalty, bdi->flap,
|
|
peer_uptime(bdi->start_time, timebuf, BGP_UPTIME_LEN, 0,
|
|
json_path));
|
|
|
|
if (CHECK_FLAG(binfo->flags, BGP_INFO_DAMPED)
|
|
&& !CHECK_FLAG(binfo->flags, BGP_INFO_HISTORY))
|
|
vty_out(vty, ", reuse in %s",
|
|
bgp_get_reuse_time(penalty, timebuf,
|
|
BGP_UPTIME_LEN, 0,
|
|
json_path));
|
|
|
|
vty_out(vty, "\n");
|
|
}
|
|
}
|
|
|
|
const char *bgp_damp_reuse_time_vty(struct vty *vty, struct bgp_info *binfo,
|
|
char *timebuf, size_t len, bool use_json,
|
|
json_object *json)
|
|
{
|
|
struct bgp_damp_info *bdi;
|
|
time_t t_now, t_diff;
|
|
int penalty;
|
|
|
|
if (!binfo->extra)
|
|
return NULL;
|
|
|
|
/* BGP dampening information. */
|
|
bdi = binfo->extra->damp_info;
|
|
|
|
/* If dampening is not enabled or there is no dampening information,
|
|
return immediately. */
|
|
if (!damp || !bdi)
|
|
return NULL;
|
|
|
|
/* Calculate new penalty. */
|
|
t_now = bgp_clock();
|
|
t_diff = t_now - bdi->t_updated;
|
|
penalty = bgp_damp_decay(t_diff, bdi->penalty);
|
|
|
|
return bgp_get_reuse_time(penalty, timebuf, len, use_json, json);
|
|
}
|
|
|
|
int bgp_show_dampening_parameters(struct vty *vty, afi_t afi, safi_t safi)
|
|
{
|
|
struct bgp *bgp;
|
|
bgp = bgp_get_default();
|
|
|
|
if (bgp == NULL) {
|
|
vty_out(vty, "No BGP process is configured\n");
|
|
return CMD_WARNING;
|
|
}
|
|
|
|
if (CHECK_FLAG(bgp->af_flags[afi][safi], BGP_CONFIG_DAMPENING)) {
|
|
vty_out(vty, "Half-life time: %lld min\n",
|
|
(long long)damp->half_life / 60);
|
|
vty_out(vty, "Reuse penalty: %d\n", damp->reuse_limit);
|
|
vty_out(vty, "Suppress penalty: %d\n", damp->suppress_value);
|
|
vty_out(vty, "Max suppress time: %lld min\n",
|
|
(long long)damp->max_suppress_time / 60);
|
|
vty_out(vty, "Max supress penalty: %u\n", damp->ceiling);
|
|
vty_out(vty, "\n");
|
|
} else
|
|
vty_out(vty, "dampening not enabled for %s\n",
|
|
afi == AFI_IP ? "IPv4" : "IPv6");
|
|
|
|
return CMD_SUCCESS;
|
|
}
|