In lsp_regenerate_schedule should timeout be a knob of some sort to allow
the delay to be configurable?

doanld

On Tue, Nov 10, 2015 at 12:43 PM, Christian Franke <
[email protected]> wrote:

> isisd implements a holdoff interval and will refrain from regenerating
> an lsp if the difference between the current time and its last refresh
> is less than the holdoff interval. Instead, it will schedule a timer
> to regenerate the lsp after the holdoff interval has passed.
>
> This implementation has one disadvantage in the case where there is a
> succession of calls to lsp_regenerate_schedule. In such a case, the
> first call will trigger an immediate regeneration of the lsp, while the
> other calls will only schedule the regeneration timer. This leads to
> cases where it takes holdoff interval time for information to propagate,
> just because the information was only available e.g. at the second call
> of lsp_regenerate_schedule in such a succession of calls.
>
> By not immediately regenerating an lsp if the last generation time
> is sufficiently long ago, but instead scheduling the regeneration with a
> very small delay, we allow all information from such a succession of
> calls to be considered.
>
> Signed-off-by: Christian Franke <[email protected]>
> ---
>  isisd/isis_circuit.c |   2 +
>  isisd/isis_events.c  |   4 ++
>  isisd/isis_lsp.c     | 141
> ++++++++++++++++++++++++++++++++++++++-------------
>  isisd/isisd.c        |  37 ++++++++++++++
>  isisd/isisd.h        |  20 ++++++++
>  5 files changed, 169 insertions(+), 35 deletions(-)
>
> diff --git a/isisd/isis_circuit.c b/isisd/isis_circuit.c
> index 9fe11c2..81c6076 100644
> --- a/isisd/isis_circuit.c
> +++ b/isisd/isis_circuit.c
> @@ -789,6 +789,8 @@ isis_circuit_down (struct isis_circuit *circuit)
>        THREAD_TIMER_OFF (circuit->u.bc.t_run_dr[1]);
>        THREAD_TIMER_OFF (circuit->u.bc.t_refresh_pseudo_lsp[0]);
>        THREAD_TIMER_OFF (circuit->u.bc.t_refresh_pseudo_lsp[1]);
> +      circuit->lsp_regenerate_pending[0] = 0;
> +      circuit->lsp_regenerate_pending[1] = 0;
>      }
>    else if (circuit->circ_type == CIRCUIT_T_P2P)
>      {
> diff --git a/isisd/isis_events.c b/isisd/isis_events.c
> index 96d5762..0dee9e6 100644
> --- a/isisd/isis_events.c
> +++ b/isisd/isis_events.c
> @@ -110,7 +110,10 @@ area_resign_level (struct isis_area *area, int level)
>      }
>  #endif /* HAVE_IPV6 */
>
> +  sched_debug("ISIS (%s): Resigned from L%d - canceling LSP regeneration
> timer.",
> +              area->area_tag, level);
>    THREAD_TIMER_OFF (area->t_lsp_refresh[level - 1]);
> +  area->lsp_regenerate_pending[level - 1] = 0;
>  }
>
>  void
> @@ -245,6 +248,7 @@ circuit_resign_level (struct isis_circuit *circuit,
> int level)
>        THREAD_TIMER_OFF (circuit->u.bc.t_send_lan_hello[idx]);
>        THREAD_TIMER_OFF (circuit->u.bc.t_run_dr[idx]);
>        THREAD_TIMER_OFF (circuit->u.bc.t_refresh_pseudo_lsp[idx]);
> +      circuit->lsp_regenerate_pending[idx] = 0;
>        circuit->u.bc.run_dr_elect[idx] = 0;
>        list_delete (circuit->u.bc.lan_neighs[idx]);
>        circuit->u.bc.lan_neighs[idx] = NULL;
> diff --git a/isisd/isis_lsp.c b/isisd/isis_lsp.c
> index 221c04f..0d5ca26 100644
> --- a/isisd/isis_lsp.c
> +++ b/isisd/isis_lsp.c
> @@ -1677,10 +1677,13 @@ lsp_generate (struct isis_area *area, int level)
>    lsp_build (newlsp, area);
>    /* time to calculate our checksum */
>    lsp_seqnum_update (newlsp);
> +  newlsp->last_generated = time(NULL);
>    lsp_set_all_srmflags (newlsp);
>
>    refresh_time = lsp_refresh_time (newlsp, rem_lifetime);
> +
>    THREAD_TIMER_OFF (area->t_lsp_refresh[level - 1]);
> +  area->lsp_regenerate_pending[level - 1] = 0;
>    if (level == IS_LEVEL_1)
>      THREAD_TIMER_ON (master, area->t_lsp_refresh[level - 1],
>                       lsp_l1_refresh, area, refresh_time);
> @@ -1700,6 +1703,8 @@ lsp_generate (struct isis_area *area, int level)
>                    ntohs (newlsp->lsp_header->rem_lifetime),
>                    refresh_time);
>      }
> +  sched_debug("ISIS (%s): Built L%d LSP. Set triggered regenerate to
> non-pending.",
> +              area->area_tag, level);
>
>    return ISIS_OK;
>  }
> @@ -1762,6 +1767,7 @@ lsp_regenerate (struct isis_area *area, int level)
>    else if (level == IS_LEVEL_2)
>      THREAD_TIMER_ON (master, area->t_lsp_refresh[level - 1],
>                       lsp_l2_refresh, area, refresh_time);
> +  area->lsp_regenerate_pending[level - 1] = 0;
>
>    if (isis->debugs & DEBUG_UPDATE_PACKETS)
>      {
> @@ -1775,6 +1781,8 @@ lsp_regenerate (struct isis_area *area, int level)
>                    ntohs (lsp->lsp_header->rem_lifetime),
>                    refresh_time);
>      }
> +  sched_debug("ISIS (%s): Rebuilt L%d LSP. Set triggered regenerate to
> non-pending.",
> +              area->area_tag, level);
>
>    return ISIS_OK;
>  }
> @@ -1796,6 +1804,7 @@ lsp_l1_refresh (struct thread *thread)
>    if ((area->is_type & IS_LEVEL_1) == 0)
>      return ISIS_ERROR;
>
> +  sched_debug("ISIS (%s): LSP L1 refresh timer expired. Refreshing
> LSP...", area->area_tag);
>    return lsp_regenerate (area, IS_LEVEL_1);
>  }
>
> @@ -1813,6 +1822,7 @@ lsp_l2_refresh (struct thread *thread)
>    if ((area->is_type & IS_LEVEL_2) == 0)
>      return ISIS_ERROR;
>
> +  sched_debug("ISIS (%s): LSP L2 refresh timer expired. Refreshing
> LSP...", area->area_tag);
>    return lsp_regenerate (area, IS_LEVEL_2);
>  }
>
> @@ -1822,6 +1832,7 @@ lsp_regenerate_schedule (struct isis_area *area, int
> level, int all_pseudo)
>    struct isis_lsp *lsp;
>    u_char id[ISIS_SYS_ID_LEN + 2];
>    time_t now, diff;
> +  long timeout;
>    struct listnode *cnode;
>    struct isis_circuit *circuit;
>    int lvl;
> @@ -1829,6 +1840,9 @@ lsp_regenerate_schedule (struct isis_area *area, int
> level, int all_pseudo)
>    if (area == NULL)
>      return ISIS_ERROR;
>
> +  sched_debug("ISIS (%s): Scheduling regeneration of %s LSPs, %sincluding
> PSNs",
> +            area->area_tag, circuit_t2string(level), all_pseudo ? "" :
> "not ");
> +
>    memcpy (id, isis->sysid, ISIS_SYS_ID_LEN);
>    LSP_PSEUDO_ID (id) = LSP_FRAGMENT (id) = 0;
>    now = time (NULL);
> @@ -1838,29 +1852,38 @@ lsp_regenerate_schedule (struct isis_area *area,
> int level, int all_pseudo)
>        if (!((level & lvl) && (area->is_type & lvl)))
>          continue;
>
> +      sched_debug("ISIS (%s): Checking whether L%d needs to be scheduled",
> +                  area->area_tag, lvl);
> +
>        if (area->lsp_regenerate_pending[lvl - 1])
> -        continue;
> +        {
> +          struct timeval remain =
> thread_timer_remain(area->t_lsp_refresh[lvl - 1]);
> +          sched_debug("ISIS (%s): Regeneration is already pending,
> nothing todo."
> +                      " (Due in %lld.%03lld seconds)", area->area_tag,
> +                      (long long)remain.tv_sec, (long long)remain.tv_usec
> / 1000);
> +          continue;
> +        }
>
>        lsp = lsp_search (id, area->lspdb[lvl - 1]);
>        if (!lsp)
> -        continue;
> +        {
> +          sched_debug("ISIS (%s): We do not have any LSPs to regenerate,
> nothing todo.",
> +                      area->area_tag);
> +          continue;
> +        }
>
>        /*
>         * Throttle avoidance
>         */
> +      sched_debug("ISIS (%s): Will schedule regen timer. Last run was:
> %lld, Now is: %lld",
> +                  area->area_tag, (long long)lsp->last_generated, (long
> long)now);
>        THREAD_TIMER_OFF (area->t_lsp_refresh[lvl - 1]);
>        diff = now - lsp->last_generated;
>        if (diff < area->lsp_gen_interval[lvl - 1])
>          {
> -          area->lsp_regenerate_pending[lvl - 1] = 1;
> -          if (lvl == IS_LEVEL_1)
> -            THREAD_TIMER_ON (master, area->t_lsp_refresh[lvl - 1],
> -                             lsp_l1_refresh, area,
> -                             area->lsp_gen_interval[lvl - 1] - diff);
> -          else if (lvl == IS_LEVEL_2)
> -            THREAD_TIMER_ON (master, area->t_lsp_refresh[lvl - 1],
> -                             lsp_l2_refresh, area,
> -                             area->lsp_gen_interval[lvl - 1] - diff);
> +          timeout = 1000 * (area->lsp_gen_interval[lvl - 1] - diff);
> +          sched_debug("ISIS (%s): Scheduling in %ld ms to match
> configured lsp_gen_interval",
> +                      area->area_tag, timeout);
>          }
>        else
>          {
> @@ -1869,13 +1892,21 @@ lsp_regenerate_schedule (struct isis_area *area,
> int level, int all_pseudo)
>             * directly. However if the lsp_regenerate call is queued for
>             * later execution it works.
>             */
> -          area->lsp_regenerate_pending[lvl - 1] = 1;
> -          if (lvl == IS_LEVEL_1)
> -            THREAD_TIMER_ON (master, area->t_lsp_refresh[lvl - 1],
> -                             lsp_l1_refresh, area, 0);
> -          else if (lvl == IS_LEVEL_2)
> -            THREAD_TIMER_ON (master, area->t_lsp_refresh[lvl - 1],
> -                             lsp_l2_refresh, area, 0);
> +          timeout = 100;
> +          sched_debug("ISIS (%s): Last generation was more than
> lsp_gen_interval ago."
> +                      " Scheduling for execution in %ld ms.",
> area->area_tag, timeout);
> +        }
> +
> +      area->lsp_regenerate_pending[lvl - 1] = 1;
> +      if (lvl == IS_LEVEL_1)
> +        {
> +          THREAD_TIMER_MSEC_ON(master, area->t_lsp_refresh[lvl - 1],
> +                               lsp_l1_refresh, area, timeout);
> +        }
> +      else if (lvl == IS_LEVEL_2)
> +        {
> +          THREAD_TIMER_MSEC_ON(master, area->t_lsp_refresh[lvl - 1],
> +                               lsp_l2_refresh, area, timeout);
>          }
>      }
>
> @@ -2227,13 +2258,18 @@ lsp_regenerate_schedule_pseudo (struct
> isis_circuit *circuit, int level)
>    struct isis_lsp *lsp;
>    u_char lsp_id[ISIS_SYS_ID_LEN + 2];
>    time_t now, diff;
> +  long timeout;
>    int lvl;
> +  struct isis_area *area = circuit->area;
>
>    if (circuit == NULL ||
>        circuit->circ_type != CIRCUIT_T_BROADCAST ||
>        circuit->state != C_STATE_UP)
>      return ISIS_OK;
>
> +  sched_debug("ISIS (%s): Scheduling regeneration of %s pseudo LSP for
> interface %s",
> +              area->area_tag, circuit_t2string(level),
> circuit->interface->name);
> +
>    memcpy (lsp_id, isis->sysid, ISIS_SYS_ID_LEN);
>    LSP_PSEUDO_ID (lsp_id) = circuit->circuit_id;
>    LSP_FRAGMENT (lsp_id) = 0;
> @@ -2241,39 +2277,74 @@ lsp_regenerate_schedule_pseudo (struct
> isis_circuit *circuit, int level)
>
>    for (lvl = IS_LEVEL_1; lvl <= IS_LEVEL_2; lvl++)
>      {
> +      sched_debug("ISIS (%s): Checking whether L%d pseudo LSP needs to be
> scheduled",
> +                  area->area_tag, lvl);
> +
>        if (!((level & lvl) && (circuit->is_type & lvl)))
> -        continue;
> +        {
> +          sched_debug("ISIS (%s): Level is not active on circuit",
> +                      area->area_tag);
> +          continue;
> +        }
>
> -      if (circuit->u.bc.is_dr[lvl - 1] == 0 ||
> -          circuit->lsp_regenerate_pending[lvl - 1])
> -        continue;
> +      if (circuit->u.bc.is_dr[lvl - 1] == 0)
> +        {
> +          sched_debug("ISIS (%s): This IS is not DR, nothing to do.",
> +                      area->area_tag);
> +          continue;
> +        }
> +
> +      if (circuit->lsp_regenerate_pending[lvl - 1])
> +        {
> +          struct timeval remain =
> +
> thread_timer_remain(circuit->u.bc.t_refresh_pseudo_lsp[lvl - 1]);
> +          sched_debug("ISIS (%s): Regenerate is already pending, nothing
> todo."
> +                      " (Due in %lld.%03lld seconds)", area->area_tag,
> +                      (long long)remain.tv_sec, (long
> long)remain.tv_usec/1000);
> +          continue;
> +        }
>
>        lsp = lsp_search (lsp_id, circuit->area->lspdb[lvl - 1]);
>        if (!lsp)
> -        continue;
> +        {
> +          sched_debug("ISIS (%s): Pseudonode LSP does not exist yet,
> nothing to regenerate.",
> +                      area->area_tag);
> +          continue;
> +        }
>
>        /*
>         * Throttle avoidance
>         */
> +      sched_debug("ISIS (%s): Will schedule PSN regen timer. Last run
> was: %lld, Now is: %lld",
> +                  area->area_tag, (long long)lsp->last_generated, (long
> long) now);
>        THREAD_TIMER_OFF (circuit->u.bc.t_refresh_pseudo_lsp[lvl - 1]);
>        diff = now - lsp->last_generated;
>        if (diff < circuit->area->lsp_gen_interval[lvl - 1])
>          {
> -          circuit->lsp_regenerate_pending[lvl - 1] = 1;
> -          if (lvl == IS_LEVEL_1)
> -            THREAD_TIMER_ON (master,
> -                             circuit->u.bc.t_refresh_pseudo_lsp[lvl - 1],
> -                             lsp_l1_refresh_pseudo, circuit,
> -                             circuit->area->lsp_gen_interval[lvl - 1] -
> diff);
> -          else if (lvl == IS_LEVEL_2)
> -            THREAD_TIMER_ON (master,
> -                             circuit->u.bc.t_refresh_pseudo_lsp[lvl - 1],
> -                             lsp_l2_refresh_pseudo, circuit,
> -                             circuit->area->lsp_gen_interval[lvl - 1] -
> diff);
> +          timeout = 1000 * (circuit->area->lsp_gen_interval[lvl - 1] -
> diff);
> +          sched_debug("ISIS (%s): Sechduling in %ld ms to match
> configured lsp_gen_interval",
> +                      area->area_tag, timeout);
>          }
>        else
>          {
> -          lsp_regenerate_pseudo (circuit, lvl);
> +          timeout = 100;
> +          sched_debug("ISIS (%s): Last generation was more than
> lsp_gen_interval ago."
> +                      " Scheduling for execution in %ld ms.",
> area->area_tag, timeout);
> +        }
> +
> +      circuit->lsp_regenerate_pending[lvl - 1] = 1;
> +
> +      if (lvl == IS_LEVEL_1)
> +        {
> +          THREAD_TIMER_MSEC_ON(master,
> +                               circuit->u.bc.t_refresh_pseudo_lsp[lvl -
> 1],
> +                               lsp_l1_refresh_pseudo, circuit, timeout);
> +        }
> +      else if (lvl == IS_LEVEL_2)
> +        {
> +          THREAD_TIMER_MSEC_ON(master,
> +                               circuit->u.bc.t_refresh_pseudo_lsp[lvl -
> 1],
> +                               lsp_l2_refresh_pseudo, circuit, timeout);
>          }
>      }
>
> diff --git a/isisd/isisd.c b/isisd/isisd.c
> index b601032..0a5286e 100644
> --- a/isisd/isisd.c
> +++ b/isisd/isisd.c
> @@ -774,6 +774,8 @@ print_debug (struct vty *vty, int flags, int onoff)
>      vty_out (vty, "IS-IS Packet dump debugging is %s%s", onoffs,
> VTY_NEWLINE);
>    if (flags & DEBUG_LSP_GEN)
>      vty_out (vty, "IS-IS LSP generation debugging is %s%s", onoffs,
> VTY_NEWLINE);
> +  if (flags & DEBUG_LSP_SCHED)
> +    vty_out (vty, "IS-IS LSP scheduling debugging is %s%s", onoffs,
> VTY_NEWLINE);
>  }
>
>  DEFUN (show_debugging,
> @@ -865,6 +867,11 @@ config_write_debug (struct vty *vty)
>        vty_out (vty, "debug isis lsp-gen%s", VTY_NEWLINE);
>        write++;
>      }
> +  if (flags & DEBUG_LSP_SCHED)
> +    {
> +      vty_out (vty, "debug isis lsp-sched%s", VTY_NEWLINE);
> +      write++;
> +    }
>
>    return write;
>  }
> @@ -1207,6 +1214,32 @@ DEFUN (no_debug_isis_lsp_gen,
>    return CMD_SUCCESS;
>  }
>
> +DEFUN (debug_isis_lsp_sched,
> +       debug_isis_lsp_sched_cmd,
> +       "debug isis lsp-sched",
> +       DEBUG_STR
> +       "IS-IS information\n"
> +       "IS-IS scheduling of LSP generation\n")
> +{
> +  isis->debugs |= DEBUG_LSP_SCHED;
> +  print_debug (vty, DEBUG_LSP_SCHED, 1);
> +
> +  return CMD_SUCCESS;
> +}
> +
> +DEFUN (no_debug_isis_lsp_sched,
> +       no_debug_isis_lsp_sched_cmd,
> +       "no debug isis lsp-gen",
> +       UNDEBUG_STR
> +       "IS-IS information\n"
> +       "IS-IS scheduling of LSP generation\n")
> +{
> +  isis->debugs &= ~DEBUG_LSP_SCHED;
> +  print_debug (vty, DEBUG_LSP_SCHED, 0);
> +
> +  return CMD_SUCCESS;
> +}
> +
>  DEFUN (show_hostname,
>         show_hostname_cmd,
>         "show isis hostname",
> @@ -3295,6 +3328,8 @@ isis_init ()
>    install_element (ENABLE_NODE, &no_debug_isis_packet_dump_cmd);
>    install_element (ENABLE_NODE, &debug_isis_lsp_gen_cmd);
>    install_element (ENABLE_NODE, &no_debug_isis_lsp_gen_cmd);
> +  install_element (ENABLE_NODE, &debug_isis_lsp_sched_cmd);
> +  install_element (ENABLE_NODE, &no_debug_isis_lsp_sched_cmd);
>
>    install_element (CONFIG_NODE, &debug_isis_adj_cmd);
>    install_element (CONFIG_NODE, &no_debug_isis_adj_cmd);
> @@ -3322,6 +3357,8 @@ isis_init ()
>    install_element (CONFIG_NODE, &no_debug_isis_packet_dump_cmd);
>    install_element (CONFIG_NODE, &debug_isis_lsp_gen_cmd);
>    install_element (CONFIG_NODE, &no_debug_isis_lsp_gen_cmd);
> +  install_element (CONFIG_NODE, &debug_isis_lsp_sched_cmd);
> +  install_element (CONFIG_NODE, &no_debug_isis_lsp_sched_cmd);
>
>    install_element (CONFIG_NODE, &router_isis_cmd);
>    install_element (CONFIG_NODE, &no_router_isis_cmd);
> diff --git a/isisd/isisd.h b/isisd/isisd.h
> index 51a72ab..96c3ba3 100644
> --- a/isisd/isisd.h
> +++ b/isisd/isisd.h
> @@ -97,6 +97,17 @@ struct isis_area
>    struct flags flags;
>    struct thread *t_tick;       /* LSP walker */
>    struct thread *t_lsp_refresh[ISIS_LEVELS];
> +  /* t_lsp_refresh is used in two ways:
> +   * a) regular refresh of LSPs
> +   * b) (possibly throttled) updates to LSPs
> +   *
> +   * The lsp_regenerate_pending flag tracks whether the timer is active
> +   * for the a) or the b) case.
> +   *
> +   * It is of utmost importance to clear this flag when the timer is
> +   * rescheduled for normal refresh, because otherwise, updates will
> +   * be delayed until the next regular refresh.
> +   */
>    int lsp_regenerate_pending[ISIS_LEVELS];
>
>    /*
> @@ -167,6 +178,7 @@ extern struct thread_master *master;
>  #define DEBUG_ZEBRA                      (1<<11)
>  #define DEBUG_PACKET_DUMP                (1<<12)
>  #define DEBUG_LSP_GEN                    (1<<13)
> +#define DEBUG_LSP_SCHED                  (1<<14)
>
>  #define lsp_debug(...) \
>    do \
> @@ -176,4 +188,12 @@ extern struct thread_master *master;
>      } \
>    while (0)
>
> +#define sched_debug(...) \
> +  do \
> +    { \
> +      if (isis->debugs & DEBUG_LSP_SCHED) \
> +        zlog_debug(__VA_ARGS__); \
> +    } \
> +  while (0)
> +
>  #endif /* ISISD_H */
> --
> 2.6.1
>
>
> _______________________________________________
> Quagga-dev mailing list
> [email protected]
> https://lists.quagga.net/mailman/listinfo/quagga-dev
>
_______________________________________________
Quagga-dev mailing list
[email protected]
https://lists.quagga.net/mailman/listinfo/quagga-dev

Reply via email to