| /* |
| * OSPF flap dampening by Manav Bhatia |
| * Copyright (C) 2002 |
| * |
| * 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 GNU Zebra; see the file COPYING. If not, write to the Free |
| * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA |
| * 02111-1307, USA. |
| */ |
| |
| #include <zebra.h> |
| #include <math.h> |
| |
| #include "log.h" |
| #include "prefix.h" |
| #include "thread.h" |
| #include "table.h" |
| #include "command.h" |
| #include "vty.h" |
| |
| extern struct thread_master *master; |
| |
| #include "ospf6_damp.h" |
| |
| #ifdef HAVE_OSPF6_DAMP |
| |
| #define DELTA_REUSE 10 /* Time granularity for reuse lists */ |
| #define DELTA_T 5 /* Time granularity for decay arrays */ |
| #define DEFAULT_HALF_LIFE 60 /* (sec) 1 min */ |
| |
| #define DEFAULT_PENALTY 1000 |
| #define DEFAULT_REUSE 750 |
| #define DEFAULT_SUPPRESS 2000 |
| |
| #define REUSE_LIST_SIZE 256 |
| #define REUSE_ARRAY_SIZE 1024 |
| |
| /* Global variable to access damping configuration */ |
| struct ospf6_damp_config damp_config; |
| struct ospf6_damp_config *dc = &damp_config; |
| u_int reuse_array_offset = 0; |
| struct route_table *damp_info_table[OSPF6_DAMP_TYPE_MAX]; |
| struct thread *ospf6_reuse_thread = NULL; |
| |
| int ospf6_damp_debug = 0; |
| #define IS_OSPF6_DEBUG_DAMP (ospf6_damp_debug) |
| |
| static struct ospf6_damp_info * |
| ospf6_damp_lookup (u_short type, struct prefix *name) |
| { |
| struct route_node *node; |
| |
| node = route_node_lookup (damp_info_table[type], name); |
| if (node && node->info) |
| return (struct ospf6_damp_info *) node->info; |
| return NULL; |
| } |
| |
| static struct ospf6_damp_info * |
| ospf6_damp_create (u_short type, struct prefix *name) |
| { |
| struct route_node *node; |
| struct ospf6_damp_info *di; |
| char namebuf[64]; |
| |
| di = ospf6_damp_lookup (type, name); |
| if (di) |
| return di; |
| |
| if (IS_OSPF6_DEBUG_DAMP) |
| { |
| prefix2str (name, namebuf, sizeof (namebuf)); |
| zlog_info ("DAMP: create: type: %d, name: %s", type, namebuf); |
| } |
| |
| di = (struct ospf6_damp_info *) |
| malloc (sizeof (struct ospf6_damp_info)); |
| memset (di, 0, sizeof (struct ospf6_damp_info)); |
| di->type = type; |
| prefix_copy (&di->name, name); |
| |
| node = route_node_get (damp_info_table[type], name); |
| node->info = di; |
| |
| return di; |
| } |
| |
| static void |
| ospf6_damp_delete (u_short type, struct prefix *name) |
| { |
| struct route_node *node; |
| struct ospf6_damp_info *di; |
| char namebuf[64]; |
| |
| node = route_node_lookup (damp_info_table[type], name); |
| if (! node || ! node->info) |
| return; |
| |
| di = node->info; |
| |
| if (IS_OSPF6_DEBUG_DAMP) |
| { |
| prefix2str (&di->name, namebuf, sizeof (namebuf)); |
| zlog_info ("DAMP: delete: type: %d, name: %s", |
| di->type, namebuf); |
| } |
| |
| node->info = NULL; |
| free (di); |
| } |
| |
| /* compute and fill the configuration parameter */ |
| void |
| ospf6_damp_init_config (u_int half_life, u_int reuse, |
| u_int suppress, u_int t_hold) |
| { |
| int i; |
| double max_ratio, max_ratio1, max_ratio2; |
| |
| dc->half_life = half_life ? half_life : DEFAULT_HALF_LIFE; |
| dc->reuse = reuse ? reuse : DEFAULT_REUSE; |
| dc->suppress = suppress ? suppress : DEFAULT_SUPPRESS; |
| dc->t_hold = t_hold ? t_hold : 4 * dc->half_life; |
| |
| /* Initialize system-wide params */ |
| dc->delta_t = DELTA_T; |
| dc->delta_reuse = DELTA_REUSE; |
| dc->default_penalty = DEFAULT_PENALTY; |
| dc->reuse_index_array_size = REUSE_ARRAY_SIZE; |
| |
| /* ceiling is the maximum penalty a route may attain */ |
| /* ceiling = reuse * 2^(T-hold/half-life) */ |
| dc->ceiling = (int) |
| (dc->reuse * (pow (2, (double) dc->t_hold / dc->half_life))); |
| |
| /* Decay-array computations */ |
| /* decay_array_size = decay memory/time granularity */ |
| dc->decay_array_size = ceil ((double) dc->t_hold / dc->delta_t); |
| dc->decay_array = malloc (sizeof (double) * (dc->decay_array_size)); |
| |
| /* Each i-th element is per tick delay raised to the i-th power */ |
| dc->decay_array[0] = 1.0; |
| dc->decay_array[1] = exp ((1.0 / (dc->half_life / dc->delta_t)) * log (0.5)); |
| for (i = 2; i < dc->decay_array_size; i++) |
| dc->decay_array[i] = dc->decay_array[i - 1] * dc->decay_array[1]; |
| |
| /* Reuse-list computations (reuse queue head array ?) */ |
| dc->reuse_list_size = ceil ((double) dc->t_hold / dc->delta_reuse) + 1; |
| if (dc->reuse_list_size == 0 || dc->reuse_list_size > REUSE_LIST_SIZE) |
| dc->reuse_list_size = REUSE_LIST_SIZE; |
| dc->reuse_list_array = (struct ospf6_damp_info **) |
| malloc (dc->reuse_list_size * sizeof (struct ospf6_reuse_list *)); |
| memset (dc->reuse_list_array, 0x00, |
| dc->reuse_list_size * sizeof (struct ospf6_reuse_list *)); |
| |
| /* Reuse-array computations */ |
| dc->reuse_index_array = malloc (sizeof (int) * dc->reuse_index_array_size); |
| |
| /* |
| * This is the maximum ratio between the current value of the penalty and |
| * the reuse value which can be indexed by the reuse array. It will be |
| * limited by the ceiling or by the amount of time that the reuse list |
| * covers |
| */ |
| max_ratio1 = (double) dc->ceiling / dc->reuse; |
| max_ratio2 = exp ((double) dc->t_hold / dc->half_life) * log10 (2.0); |
| max_ratio = (max_ratio2 != 0 && max_ratio2 < max_ratio1 ? |
| max_ratio2 : max_ratio1); |
| |
| /* |
| * reuse array is just an estimator and we need something |
| * to use the full array |
| */ |
| dc->scale_factor = (double) dc->reuse_index_array_size / (max_ratio - 1); |
| |
| for (i = 0; i < dc->reuse_index_array_size; i++) |
| { |
| dc->reuse_index_array[i] = (int) |
| (((double) dc->half_life / dc->delta_reuse) * |
| log10 (1.0 / (dc->reuse * (1.0 + ((double) i / dc->scale_factor)))) |
| / log10 (0.5)); |
| } |
| |
| dc->enabled = ON; |
| } |
| |
| static double |
| ospf6_damp_decay (time_t tdiff) |
| { |
| int index = tdiff / dc->delta_t; |
| |
| if (index >= dc->decay_array_size) |
| return 0; |
| |
| return dc->decay_array[index]; |
| } |
| |
| static int |
| ospf6_damp_reuse_index (int penalty) |
| { |
| int index; |
| |
| index = (int) (((double) penalty / dc->reuse - 1.0) * dc->scale_factor); |
| |
| if (index >= dc->reuse_index_array_size) |
| index = dc->reuse_index_array_size - 1; |
| |
| return (dc->reuse_index_array[index] - dc->reuse_index_array[0]); |
| } |
| |
| static int |
| ospf6_reuse_list_lookup (struct ospf6_damp_info *di) |
| { |
| struct ospf6_damp_info *info; |
| |
| for (info = dc->reuse_list_array[di->index]; info; info = info->next) |
| { |
| if (info == di) |
| return 1; |
| } |
| return 0; |
| } |
| |
| static void |
| ospf6_reuse_list_remove (struct ospf6_damp_info *di) |
| { |
| if (di->prev) |
| di->prev->next = di->next; |
| else |
| dc->reuse_list_array[di->index] = di->next; |
| if (di->next) |
| di->next->prev = di->prev; |
| |
| di->index = -1; |
| di->prev = NULL; |
| di->next = NULL; |
| } |
| |
| static void |
| ospf6_reuse_list_add (struct ospf6_damp_info *di) |
| { |
| /* set the index of reuse-array */ |
| di->index = (reuse_array_offset + (ospf6_damp_reuse_index (di->penalty))) |
| % dc->reuse_list_size; |
| |
| /* insert to the head of the reuse list */ |
| di->next = dc->reuse_list_array[di->index]; |
| if (di->next) |
| di->next->prev = di; |
| di->prev = NULL; |
| dc->reuse_list_array[di->index] = di; |
| } |
| |
| /* When we quit damping for a target, we should execute proper event |
| which have been postponed during damping */ |
| static void |
| ospf6_damp_stop (struct ospf6_damp_info *di) |
| { |
| time_t t_now; |
| char namebuf[64]; |
| struct timeval now; |
| |
| if (IS_OSPF6_DEBUG_DAMP) |
| { |
| t_now = time (NULL); |
| prefix2str (&di->name, namebuf, sizeof (namebuf)); |
| gettimeofday (&now, NULL); |
| zlog_info ("DAMP: %lu.%06lu stop damping: %ld: type: %d, name: %s", |
| now.tv_sec, now.tv_usec, |
| t_now, di->type, namebuf); |
| } |
| |
| /* set flag indicates that we're damping this target */ |
| di->damping = OFF; |
| |
| /* if the target's current status differ from that it should be, |
| execute the proper event to repair his status */ |
| if (di->target_status != di->event_type) |
| { |
| (*(di->event)) (di->target); |
| di->target_status = di->event_type; |
| |
| di->event = NULL; |
| di->event_type = event_none; |
| } |
| } |
| |
| /* ospf6_reuse_timer is called every DELTA_REUSE seconds. |
| Each route in the current reuse-list is evaluated |
| and is used or requeued */ |
| int |
| ospf6_damp_reuse_timer (struct thread *t) |
| { |
| struct ospf6_damp_info *di, *next; |
| time_t t_now, t_diff; |
| char namebuf[64]; |
| struct timeval now; |
| |
| /* Restart the reuse timer */ |
| ospf6_reuse_thread = |
| thread_add_timer (master, ospf6_damp_reuse_timer, NULL, dc->delta_reuse); |
| |
| t_now = time (NULL); |
| |
| /* get the damp info list head */ |
| di = dc->reuse_list_array[reuse_array_offset]; |
| dc->reuse_list_array[reuse_array_offset] = NULL; |
| |
| /* rotate the circular reuse list head array */ |
| reuse_array_offset = (reuse_array_offset + 1) % dc->reuse_list_size; |
| |
| /* for each damp info */ |
| while (di) |
| { |
| next = di->next; |
| di->next = NULL; |
| |
| /* Update penalty */ |
| t_diff = t_now - di->t_updated; |
| di->t_updated = t_now; |
| di->penalty = (int) |
| ((double) di->penalty * ospf6_damp_decay (t_diff)); |
| /* configration of ceiling may be just changed */ |
| if (di->penalty > dc->ceiling) |
| di->penalty = dc->ceiling; |
| |
| if (IS_OSPF6_DEBUG_DAMP) |
| { |
| prefix2str (&di->name, namebuf, sizeof (namebuf)); |
| gettimeofday (&now, NULL); |
| zlog_info ("DAMP: %lu.%06lu update penalty: type: %d, name: %s, penalty: %d", |
| now.tv_sec, now.tv_usec, |
| di->type, namebuf, di->penalty); |
| } |
| |
| /* If the penalty becomes under reuse, |
| call real event that we have been postponed. */ |
| if (di->penalty < dc->reuse && di->damping == ON) |
| ospf6_damp_stop (di); |
| |
| /* If the penalty becomes less than the half of the |
| reuse value, this damp info will be freed from reuse-list, |
| by assuming that it is considered to be stable enough already, |
| and there's no need to maintain flapping history for this. */ |
| if (di->penalty <= dc->reuse / 2) |
| { |
| ospf6_damp_delete (di->type, &di->name); |
| di = next; |
| continue; |
| } |
| |
| /* re-insert to the reuse-list */ |
| ospf6_reuse_list_add (di); |
| |
| di = next; |
| } |
| |
| return 0; |
| } |
| |
| static void |
| ospf6_damp_event (damp_event_t event_type, |
| u_short type, struct prefix *name, |
| int (*event) (void *), void *target) |
| { |
| time_t t_now, t_diff; |
| struct ospf6_damp_info *di; |
| char namebuf[64]; |
| struct timeval now; |
| |
| if (dc->enabled == OFF) |
| { |
| (*event) (target); |
| return; |
| } |
| |
| di = ospf6_damp_lookup (type, name); |
| if (! di) |
| di = ospf6_damp_create (type, name); |
| |
| t_now = time (NULL); |
| |
| di->event = event; |
| di->target = target; |
| di->event_type = event_type; |
| |
| if (! ospf6_reuse_list_lookup (di)) |
| di->t_start = t_now; |
| else |
| { |
| ospf6_reuse_list_remove (di); |
| |
| t_diff = t_now - di->t_updated; |
| di->penalty = (int) (di->penalty * ospf6_damp_decay (t_diff)); |
| } |
| |
| /* penalty only on down event */ |
| if (event_type == event_down) |
| { |
| di->flap++; |
| di->penalty += dc->default_penalty; |
| } |
| |
| /* limit penalty up to ceiling */ |
| if (di->penalty > dc->ceiling) |
| di->penalty = dc->ceiling; |
| |
| if (IS_OSPF6_DEBUG_DAMP) |
| { |
| prefix2str (&di->name, namebuf, sizeof (namebuf)); |
| gettimeofday (&now, NULL); |
| zlog_info ("DAMP: %lu.%06lu update penalty: type: %d, name: %s, penalty: %d", |
| now.tv_sec, now.tv_usec, |
| di->type, namebuf, di->penalty); |
| } |
| |
| /* if penalty < reuse, stop damping here */ |
| if (di->penalty < dc->reuse && di->damping == ON) |
| { |
| if (IS_OSPF6_DEBUG_DAMP) |
| { |
| prefix2str (&di->name, namebuf, sizeof (namebuf)); |
| gettimeofday (&now, NULL); |
| zlog_info ("DAMP: %lu.%06lu stop damping: %ld: type: %d, name: %s", |
| now.tv_sec, now.tv_usec, |
| t_now, di->type, namebuf); |
| } |
| di->damping = OFF; |
| } |
| |
| /* if event == up and if penalty >= suppress , start damping here */ |
| if (di->event_type == event_up && di->penalty >= dc->suppress && |
| di->damping == OFF) |
| { |
| if (IS_OSPF6_DEBUG_DAMP) |
| { |
| prefix2str (&di->name, namebuf, sizeof (namebuf)); |
| gettimeofday (&now, NULL); |
| zlog_info ("DAMP: %lu.%06lu start damping: %ld: type: %d, name: %s", |
| now.tv_sec, now.tv_usec, |
| t_now, type, namebuf); |
| } |
| di->damping = ON; |
| } |
| |
| /* execute event if we're not damping */ |
| if (di->damping == OFF) |
| { |
| (*(di->event)) (di->target); |
| di->target_status = di->event_type; |
| } |
| |
| /* if the penalty goes beyond suppress value, start damping */ |
| if (di->penalty >= dc->suppress && di->damping == OFF) |
| { |
| if (IS_OSPF6_DEBUG_DAMP) |
| { |
| prefix2str (name, namebuf, sizeof (namebuf)); |
| gettimeofday (&now, NULL); |
| zlog_info ("DAMP: %lu.%06lu start damping: %ld: type: %d, name: %s", |
| now.tv_sec, now.tv_usec, |
| t_now, type, namebuf); |
| } |
| di->damping = ON; |
| } |
| |
| /* update last-updated-time field */ |
| di->t_updated = t_now; |
| |
| /* Insert it into the reuse list */ |
| ospf6_reuse_list_add (di); |
| } |
| |
| void |
| ospf6_damp_event_up (u_short type, struct prefix *name, |
| int (*event) (void *), void *target) |
| { |
| struct timeval now; |
| |
| gettimeofday (&now, NULL); |
| if (IS_OSPF6_DEBUG_DAMP) |
| zlog_info ("DAMP: Up Event at %lu.%06lu", now.tv_sec, now.tv_usec); |
| |
| ospf6_damp_event (event_up, type, name, event, target); |
| } |
| |
| void |
| ospf6_damp_event_down (u_short type, struct prefix *name, |
| int (*event) (void *), void *target) |
| { |
| struct timeval now; |
| |
| gettimeofday (&now, NULL); |
| if (IS_OSPF6_DEBUG_DAMP) |
| zlog_info ("DAMP: Down Event at %lu.%06lu", now.tv_sec, now.tv_usec); |
| |
| ospf6_damp_event (event_down, type, name, event, target); |
| } |
| |
| int |
| ospf6_damp_debug_thread (struct thread *thread) |
| { |
| int i; |
| struct ospf6_damp_info *di; |
| char buf[256]; |
| time_t t_now; |
| struct timeval now; |
| |
| for (i = 0; i < dc->reuse_list_size; i++) |
| { |
| for (di = dc->reuse_list_array[i]; di; di = di->next) |
| { |
| t_now = time (NULL); |
| gettimeofday (&now, NULL); |
| prefix2str (&di->name, buf, sizeof (buf)); |
| zlog_info ("DAMP: %lu.%06lu %c %-32s penalty %7u", |
| now.tv_sec, now.tv_usec, |
| (di->damping == ON ? 'D' : 'A'), buf, |
| (u_int) (di->penalty * |
| ospf6_damp_decay (t_now - di->t_updated))); |
| } |
| } |
| thread_add_timer (master, ospf6_damp_debug_thread, NULL, 1); |
| return 0; |
| } |
| |
| DEFUN (show_ipv6_ospf6_route_flapping, |
| show_ipv6_ospf6_route_flapping_cmd, |
| "show ipv6 ospf6 route flapping", |
| SHOW_STR |
| IP6_STR |
| OSPF6_STR) |
| { |
| int i; |
| struct ospf6_damp_info *di; |
| char buf[256]; |
| time_t t_now; |
| |
| t_now = time (NULL); |
| vty_out (vty, "%c %-32s %7s%s", ' ', "Prefix", "penalty", VTY_NEWLINE); |
| |
| for (i = 0; i < dc->reuse_list_size; i++) |
| { |
| for (di = dc->reuse_list_array[i]; di; di = di->next) |
| { |
| prefix2str (&di->name, buf, sizeof (buf)); |
| vty_out (vty, "%c %-32s %7u%s", |
| (di->damping == ON ? 'D' : ' '), buf, |
| (u_int) (di->penalty * |
| ospf6_damp_decay (t_now - di->t_updated)), |
| VTY_NEWLINE); |
| } |
| } |
| |
| return CMD_SUCCESS; |
| } |
| |
| DEFUN (ospf6_flap_damping_route, |
| ospf6_flap_damping_route_cmd, |
| "flap-damping route <0-4294967295> <0-4294967295> " |
| "<0-4294967295> <0-4294967295>", |
| "enable flap dampening\n" |
| "enable route flap dampening\n" |
| "half-life in second\n" |
| "reuse value\n" |
| "suppress value\n" |
| "t-hold in second (maximum time that the target can be damped)\n" |
| ) |
| { |
| u_int half_life, reuse, suppress, t_hold; |
| |
| if (argc) |
| { |
| half_life = (u_int) strtoul (argv[0], NULL, 10); |
| reuse = (u_int) strtoul (argv[1], NULL, 10); |
| suppress = (u_int) strtoul (argv[2], NULL, 10); |
| t_hold = (u_int) strtoul (argv[3], NULL, 10); |
| } |
| else |
| { |
| half_life = (u_int) DEFAULT_HALF_LIFE; |
| reuse = (u_int) DEFAULT_REUSE; |
| suppress = (u_int) DEFAULT_SUPPRESS; |
| t_hold = (u_int) DEFAULT_HALF_LIFE * 4; |
| } |
| |
| if (reuse && suppress && reuse >= suppress) |
| { |
| vty_out (vty, "reuse value exceeded suppress value, failed%s\n", |
| VTY_NEWLINE); |
| return CMD_SUCCESS; |
| } |
| |
| if (half_life && t_hold && half_life >= t_hold) |
| { |
| vty_out (vty, "half-life exceeded t-hold, failed%s\n", VTY_NEWLINE); |
| return CMD_SUCCESS; |
| } |
| |
| ospf6_damp_init_config (half_life, reuse, suppress, t_hold); |
| |
| if (ospf6_reuse_thread == NULL) |
| ospf6_reuse_thread = |
| thread_add_timer (master, ospf6_damp_reuse_timer, NULL, dc->delta_reuse); |
| |
| return CMD_SUCCESS; |
| } |
| |
| DEFUN (show_ipv6_ospf6_damp_config, |
| show_ipv6_ospf6_camp_config_cmd, |
| "show ipv6 ospf6 damp config", |
| SHOW_STR |
| IP6_STR |
| OSPF6_STR |
| "Flap-dampening information\n" |
| "shows dampening configuration\n" |
| ) |
| { |
| int i; |
| |
| vty_out (vty, "%10s %10s %10s %10s%s", |
| "Half life", "Suppress", "Reuse", "T-hold", |
| VTY_NEWLINE); |
| vty_out (vty, "%10u %10u %10u %10u%s", |
| dc->half_life, dc->suppress, dc->reuse, dc->t_hold, |
| VTY_NEWLINE); |
| vty_out (vty, "%s", VTY_NEWLINE); |
| |
| vty_out (vty, "Delta-t = %u%s", dc->delta_t, VTY_NEWLINE); |
| vty_out (vty, "Delta-Reuse = %u%s", dc->delta_reuse, VTY_NEWLINE); |
| vty_out (vty, "Default-Penalty = %u%s", dc->default_penalty, VTY_NEWLINE); |
| vty_out (vty, "Ceiling = %u%s", dc->ceiling, VTY_NEWLINE); |
| vty_out (vty, "ScaleFactor = %f%s", dc->scale_factor, VTY_NEWLINE); |
| |
| vty_out (vty, "DecayArray(%d) =%s", dc->decay_array_size, VTY_NEWLINE); |
| for (i = 0; i < dc->decay_array_size; i++) |
| { |
| if (i % 10 == 0) |
| vty_out (vty, " "); |
| vty_out (vty, " %f", dc->decay_array[i]); |
| if (i % 10 == 0) |
| vty_out (vty, "%s", VTY_NEWLINE); |
| } |
| vty_out (vty, "%s", VTY_NEWLINE); |
| |
| vty_out (vty, "ReuseIndexArray(%d) =%s", |
| dc->reuse_index_array_size, VTY_NEWLINE); |
| for (i = 0; i < dc->reuse_index_array_size; i++) |
| { |
| if (i % 10 == 0) |
| vty_out (vty, " "); |
| vty_out (vty, " %d", dc->reuse_index_array[i]); |
| if (i % 10 == 0) |
| vty_out (vty, "%s", VTY_NEWLINE); |
| } |
| vty_out (vty, "%s", VTY_NEWLINE); |
| |
| return CMD_SUCCESS; |
| } |
| |
| void |
| ospf6_damp_config_write (struct vty *vty) |
| { |
| if (dc->enabled == ON) |
| { |
| vty_out (vty, " flap-damping route %u %u %u %u%s", |
| dc->half_life, dc->reuse, dc->suppress, dc->t_hold, |
| VTY_NEWLINE); |
| } |
| } |
| |
| DEFUN (debug_ospf6_damp, |
| debug_ospf6_damp_cmd, |
| "debug ospf6 damp", |
| DEBUG_STR |
| OSPF6_STR |
| "Flap-dampening information\n" |
| ) |
| { |
| ospf6_damp_debug = 1; |
| return CMD_SUCCESS; |
| } |
| |
| DEFUN (no_debug_ospf6_damp, |
| no_debug_ospf6_damp_cmd, |
| "no debug ospf6 damp", |
| NO_STR |
| DEBUG_STR |
| OSPF6_STR |
| "Flap-dampening information\n" |
| ) |
| { |
| ospf6_damp_debug = 0; |
| return CMD_SUCCESS; |
| } |
| |
| DEFUN (show_debug_ospf6_damp, |
| show_debug_ospf6_damp_cmd, |
| "show debugging ospf6 damp", |
| SHOW_STR |
| DEBUG_STR |
| OSPF6_STR |
| "Flap-dampening information\n" |
| ) |
| { |
| vty_out (vty, "debugging ospf6 damp is "); |
| if (IS_OSPF6_DEBUG_DAMP) |
| vty_out (vty, "enabled."); |
| else |
| vty_out (vty, "disabled."); |
| vty_out (vty, "%s", VTY_NEWLINE); |
| return CMD_SUCCESS; |
| } |
| |
| void |
| ospf6_damp_init () |
| { |
| int i; |
| for (i = 0; i < OSPF6_DAMP_TYPE_MAX; i++) |
| damp_info_table[i] = route_table_init (); |
| |
| install_element (VIEW_NODE, &show_ipv6_ospf6_route_flapping_cmd); |
| install_element (ENABLE_NODE, &show_ipv6_ospf6_route_flapping_cmd); |
| install_element (ENABLE_NODE, &show_ipv6_ospf6_camp_config_cmd); |
| install_element (OSPF6_NODE, &ospf6_flap_damping_route_cmd); |
| |
| install_element (ENABLE_NODE, &show_debug_ospf6_damp_cmd); |
| install_element (CONFIG_NODE, &debug_ospf6_damp_cmd); |
| install_element (CONFIG_NODE, &no_debug_ospf6_damp_cmd); |
| |
| thread_add_event (master, ospf6_damp_debug_thread, NULL, 0); |
| } |
| |
| #endif /* HAVE_OSPF6_DAMP */ |
| |
| |