]> git.proxmox.com Git - mirror_frr.git/commitdiff
Merge pull request #224 from donaldsharp/pim_patches_feb
authorRuss White <russ@riw.us>
Wed, 1 Mar 2017 14:52:24 +0000 (09:52 -0500)
committerGitHub <noreply@github.com>
Wed, 1 Mar 2017 14:52:24 +0000 (09:52 -0500)
Pim patches feb

38 files changed:
bgpd/bgp_clist.c
bgpd/bgp_encap.c
bgpd/bgp_evpn.c
bgpd/bgp_evpn_vty.c
bgpd/bgp_vty.c
bgpd/bgpd.c
bgpd/rfapi/vnc_zebra.c
debian/README.Debian
debian/frr.preinst
doc/vtysh.1.in
doc/vtysh.texi
isisd/isis_lsp.c
isisd/isis_route.c
isisd/isis_spf.c
isisd/isis_spf.h
isisd/isis_vty.c
isisd/isisd.c
isisd/isisd.h
lib/Makefile.am
lib/monotime.h
lib/spf_backoff.c [new file with mode: 0644]
lib/spf_backoff.h [new file with mode: 0644]
lib/vty.h
ospf6d/ospf6_zebra.c
pimd/pim_igmpv3.c
tools/frr
tools/frr-reload.py
tools/frr.service
vtysh/vtysh.c
vtysh/vtysh.h
vtysh/vtysh_main.c
watchfrr/watchfrr_vty.c
zebra/if_netlink.c
zebra/if_netlink.h
zebra/kernel_netlink.c
zebra/kernel_netlink.h
zebra/rt_netlink.c
zebra/rt_netlink.h

index 637c95fa7c40d9251a032fe41773d6f83a68cf07..3def97c73d132eac0cdfb99cc0710f590689a8cc 100644 (file)
@@ -506,18 +506,22 @@ lcommunity_str_get (struct lcommunity *lcom, int i)
 static int
 lcommunity_regexp_include (regex_t * reg, struct lcommunity *lcom, int i)
 {
-  const char *str;
+  char *str;
 
   /* When there is no communities attribute it is treated as empty string. */
   if (lcom == NULL || lcom->size == 0)
-    str = "";
+    str = XSTRDUP (MTYPE_LCOMMUNITY_STR, "");
   else
     str = lcommunity_str_get (lcom, i);
 
   /* Regular expression match.  */
   if (regexec (reg, str, 0, NULL, 0) == 0)
-    return 1;
+    {
+      XFREE (MTYPE_LCOMMUNITY_STR, str);
+      return 1;
+    }
 
+  XFREE (MTYPE_LCOMMUNITY_STR, str);
   /* No match.  */
   return 0;
 }
index 6e021c4e9e44068b78cddf0d06fdc8fee8cac83e..603979942d6bcdfd33f6263b67a60c816e18c3c9 100644 (file)
@@ -589,24 +589,27 @@ DEFUN (show_bgp_ipv4_encap_neighbor_routes,
        "Neighbor to display information about\n"
        "Display routes learned from neighbor\n")
 {
-  int idx_peer = 5;
-  union sockunion su;
+  int idx_peer = 0;
+  union sockunion *su;
   struct peer *peer;
 
-  if (sockunion_str2su (argv[idx_peer]->arg))
+  argv_find(argv, argc, "A.B.C.D", &idx_peer);
+  su = sockunion_str2su (argv[idx_peer]->arg);
+
+  if (!su)
     {
       vty_out (vty, "Malformed address: %s%s", argv[idx_peer]->arg, VTY_NEWLINE);
                return CMD_WARNING;
     }
 
-  peer = peer_lookup (NULL, &su);
+  peer = peer_lookup (NULL, su);
   if (! peer || ! peer->afc[AFI_IP][SAFI_ENCAP])
     {
       vty_out (vty, "%% No such neighbor or address family%s", VTY_NEWLINE);
       return CMD_WARNING;
     }
 
-  return bgp_show_encap (vty, AFI_IP, NULL, bgp_show_type_neighbor, &su, 0);
+  return bgp_show_encap (vty, AFI_IP, NULL, bgp_show_type_neighbor, su, 0);
 }
 
 DEFUN (show_bgp_ipv6_encap_neighbor_routes,
index b9acbbed08bcef2edf6e2d05d0e8fcf122fcb3a7..1ab8e23236b9ceb256b5ff60da6205d96dca85ec 100644 (file)
@@ -125,7 +125,7 @@ bgp_nlri_parse_evpn(struct peer *peer, struct attr *attr,
                        if (route_length - 4 - 10 - 8 -
                            3 /* label to be read */  >= 32) {
                                p_evpn_p->flags = IP_PREFIX_V6;
-                               memcpy(&(p_evpn_p->ip.v4_addr), pnt, 16);
+                               memcpy(&(p_evpn_p->ip.v6_addr), pnt, 16);
                                pnt += 16;
                                memcpy(&evpn.gw_ip.ipv6, pnt, 16);
                                pnt += 16;
index ed67a61f69172d2086235fdf9892e9a4aa5a64a4..1654265a7246bfccaaf3711c5354c0338eb91732 100644 (file)
@@ -677,7 +677,9 @@ DEFUN(evpnrt5_network,
       "Gateway IP ( A.B.C.D )\n"
       "Gateway IPv6 ( X:X::X:X )\n"
       "Router Mac Ext Comm\n"
-      "Router Mac address Value ( aa:bb:cc:dd:ee:ff format)\n")
+      "Router Mac address Value ( aa:bb:cc:dd:ee:ff format)\n"
+      "Route-map to modify the attributes\n"
+      "Name of the route map\n")
 {
        int idx_ipv4_prefixlen = 1;
        int idx_ext_community = 3;
index aa8c3145f98d1b1283de81786afbd42953beeee1..6ad356a04c985a19cdf68fe7011fd25556bb63bb 100644 (file)
@@ -11093,6 +11093,8 @@ DEFUN (no_ip_community_list_standard_all,
 
   int ret = community_list_unset (bgp_clist, cl_name_or_number, str, direct, style, delete_all);
 
+  XFREE (MTYPE_TMP, str);
+
   if (ret < 0)
     {
       community_list_perror (vty, ret);
@@ -11170,6 +11172,8 @@ DEFUN (no_ip_community_list_expanded_all,
 
   int ret = community_list_unset (bgp_clist, cl_name_or_number, str, direct, style, delete_all);
 
+  XFREE (MTYPE_TMP, str);
+
   if (ret < 0)
     {
       community_list_perror (vty, ret);
index 3512167b02ff3f24ffd82fc7309c8f07b00a76ba..42a0f8d4b8f871f3caa698522723d12545a6d346 100644 (file)
@@ -2524,7 +2524,7 @@ peer_group_delete (struct peer_group *group)
       list_delete (group->listen_range[afi]);
     }
 
-  XFREE(MTYPE_BGP_PEER_HOST, group->name);
+  XFREE(MTYPE_PEER_GROUP_HOST, group->name);
   group->name = NULL;
 
   group->conf->group = NULL;
@@ -5458,7 +5458,7 @@ peer_prefix_list_unset (struct peer *peer, afi_t afi, safi_t safi, int direct)
       if (gfilter->plist[direct].name)
        {
          if (filter->plist[direct].name)
-           XSTRDUP(MTYPE_BGP_FILTER_NAME, filter->plist[direct].name);
+           XFREE(MTYPE_BGP_FILTER_NAME, filter->plist[direct].name);
          filter->plist[direct].name = XSTRDUP(MTYPE_BGP_FILTER_NAME, gfilter->plist[direct].name);
          filter->plist[direct].plist = gfilter->plist[direct].plist;
           peer_on_policy_change(peer, afi, safi,
index 23b6e9dbb48856d1017f8ea640362e3fc897965b..84b299ce1d120d9e224d2d8c0730a24f69154d18 100644 (file)
@@ -547,6 +547,7 @@ vnc_zebra_route_msg (
       api.nexthop = nhp_ary;
       api.ifindex_num = 0;
       api.instance = 0;
+      api.safi = SAFI_UNICAST;
 
       if (BGP_DEBUG (zebra, ZEBRA))
         {
@@ -582,6 +583,7 @@ vnc_zebra_route_msg (
       api.ifindex_num = 1;
       api.ifindex = &ifindex;
       api.instance = 0;
+      api.safi = SAFI_UNICAST;
 
       if (BGP_DEBUG (zebra, ZEBRA))
         {
index 893c1decaae5dcb9cf8f0e20c6a4d495189a7df8..caded52075820c61dcc6f62db9802b3501cfd214 100644 (file)
@@ -93,5 +93,5 @@ See message #4525 from 2005-05-09 in the quagga-users mailing list.
 ===========================
 
 Check /etc/pam.d/frr, it probably denies access to your user. The passwords
-configured in /etc/frr/Frr.conf are only for telnet access.
+configured in /etc/frr/frr.conf are only for telnet access.
 
index abdaa7277b6bd7ce1cd385b14d9d1232e2b3178e..29162e3b56a92bab011cf527d0ed0d29a35280b7 100644 (file)
@@ -66,7 +66,7 @@ if [ "$1" = "install" ]; then
     fi
 
     # Exceptions for vtysh.
-    f=$d/Frr.conf
+    f=$d/frr.conf
     if [ -f $d/Zebra.conf ]; then
       mv $d/Zebra.conf $f
     fi
index 7b5d4f132e4d8010bbfce0544d71165e1fc80bf8..ba8f3df72021653e9177af43f0d0f950c3b257a1 100644 (file)
@@ -73,7 +73,7 @@ The default location of the
 .B vtysh
 config file.
 .TP
-.BI @CFG_SYSCONF@/Frr.conf
+.BI @CFG_SYSCONF@/frr.conf
 The default location of the integrated @PACKAGE_FULLNAME@ routing engine config file
 if integrated config file is in use (not default).
 .TP
index f3ebc26a128bf6f52d1ff734ca370de93c348406..de681c8013a28b8f3c876f4a8c9ba12889c306d0 100644 (file)
@@ -61,13 +61,13 @@ at all.
 @section Integrated configuration mode
 
 Integrated configuration mode uses a single configuration file,
-@file{Frr.conf}, for all daemons.  This replaces the individual files like
+@file{frr.conf}, for all daemons.  This replaces the individual files like
 @file{zebra.conf} or @file{bgpd.conf}.
 
-@file{Frr.conf} is located in @file{@value{INSTALL_PREFIX_ETC}}.  All
+@file{frr.conf} is located in @file{@value{INSTALL_PREFIX_ETC}}.  All
 daemons check for the existence of this file at startup, and if it exists
 will not load their individual configuration files.  Instead,
-@command{vtysh -b} must be invoked to process @file{Frr.conf} and apply
+@command{vtysh -b} must be invoked to process @file{frr.conf} and apply
 its settings to the individual daemons.
 
 @quotation Warning
@@ -76,7 +76,7 @@ its settings to the individual daemons.
 
 @subsection Configuration saving, file ownership and permissions
 
-The @file{Frr.conf} file is not written by any of the daemons; instead
+The @file{frr.conf} file is not written by any of the daemons; instead
 @command{vtysh} contains the neccessary logic to collect configuration from
 all of the daemons, combine it and write it out.
 
@@ -90,7 +90,7 @@ Since the @command{vtysh} command may be running as ordinary user on the
 system, configuration writes will be tried through @command{watchfrr},
 using the @command{write integrated} command internally.  Since
 @command{watchfrr} is running as superuser, @command{vtysh} is able to
-ensure correct ownership and permissions on @file{Frr.conf}.
+ensure correct ownership and permissions on @file{frr.conf}.
 
 If @command{watchfrr} is not running or the configuration write fails,
 @command{vtysh} will attempt to directly write to the file.  This is likely
@@ -102,7 +102,7 @@ Writing the configuration can be triggered directly by invoking
 should be run as either the superuser or the Frr user.
 
 We recommend you do not mix the use of the two types of files. Further, it
-is better not to use the integrated Frr.conf file, as any syntax error in
+is better not to use the integrated frr.conf file, as any syntax error in
 it can lead to /all/ of your daemons being unable to start up. Per daemon
 files are more robust as impact of errors in configuration are limited to
 the daemon in whose file the error is made.
@@ -110,7 +110,7 @@ the daemon in whose file the error is made.
 @deffn {Command} {service integrated-vtysh-config} {}
 @deffnx {Command} {no service integrated-vtysh-config} {}
 
-Control whether integrated @file{Frr.conf} file is written when
+Control whether integrated @file{frr.conf} file is written when
 'write file' is issued.
 
 These commands need to be placed in @file{vtysh.conf} to have any effect.
@@ -122,18 +122,18 @@ This command has 3 states:
 @item
 @command{service integrated-vtysh-config}
 
-@command{vtysh} will always write @file{Frr.conf}.
+@command{vtysh} will always write @file{frr.conf}.
 
 @item
 @command{no service integrated-vtysh-config}
 
-@command{vtysh} will never write @file{Frr.conf}; instead it will ask
+@command{vtysh} will never write @file{frr.conf}; instead it will ask
 daemons to write their individual configuration files.
 
 @item
 Neither option present (default)
 
-@command{vtysh} will check whether @file{Frr.conf} exists.  If it does,
+@command{vtysh} will check whether @file{frr.conf} exists.  If it does,
 configuration writes will update that file.  Otherwise, writes are performed
 through the individual daemons.
 @end itemize
@@ -146,7 +146,7 @@ installations.
 @deffn {Command} {write integrated} {}
 
 Unconditionally (regardless of @command{service integrated-vtysh-config}
-setting) write out integrated @file{Frr.conf} file through
+setting) write out integrated @file{frr.conf} file through
 @command{watchfrr}.  If @command{watchfrr} is not running, this command
 is unavailable.
 
@@ -156,6 +156,6 @@ is unavailable.
 
 Configuration changes made while some daemon is not running will be invisible
 to that daemon.  The daemon will start up with its saved configuration
-(either in its individual configuration file, or in @file{Frr.conf}).
+(either in its individual configuration file, or in @file{frr.conf}).
 This is particularly troublesome for route-maps and prefix lists, which would
 otherwise be synchronized between daemons.
index fac62f6e1bf68222d73141a78cd3113153b7708a..f633a8fb78fb062602b684dcb1ef1aa11b25e0aa 100644 (file)
@@ -156,7 +156,6 @@ lsp_destroy (struct isis_lsp *lsp)
     }
 
   isis_spf_schedule (lsp->area, lsp->level);
-  isis_spf_schedule6 (lsp->area, lsp->level);
 
   if (lsp->pdu)
     stream_free (lsp->pdu);
@@ -425,7 +424,6 @@ lsp_inc_seqnum (struct isis_lsp *lsp, u_int32_t seq_num)
                     ntohs (lsp->lsp_header->pdu_len) - 12, 12);
 
   isis_spf_schedule (lsp->area, lsp->level);
-  isis_spf_schedule6 (lsp->area, lsp->level);
 
   return;
 }
@@ -640,7 +638,6 @@ lsp_insert (struct isis_lsp *lsp, dict_t * lspdb)
   if (lsp->lsp_header->seq_num != 0)
     {
       isis_spf_schedule (lsp->area, lsp->level);
-      isis_spf_schedule6 (lsp->area, lsp->level);
     }
 }
 
index 4f82edaefb851a6ae1d2ab07a9b946fe6e1540b4..e3256f2d027ddd54072e9cf86b620e282fc97838 100644 (file)
@@ -574,6 +574,7 @@ isis_route_validate_merge (struct isis_area *area, int family)
     {
       zlog_warn ("ISIS-Rte (%s) %s called for unknown family %d",
                  area->area_tag, __func__, family);
+      route_table_finish(merge);
       return;
     }
 
index c1fb062e5506b2d988fe9e23eba91d78f3c5ebc6..db46078f20c5ce06ed6c9d9f3752a3509ec56f83 100644 (file)
@@ -33,6 +33,7 @@
 #include "hash.h"
 #include "if.h"
 #include "table.h"
+#include "spf_backoff.h"
 
 #include "isis_constants.h"
 #include "isis_common.h"
@@ -50,9 +51,6 @@
 #include "isis_route.h"
 #include "isis_csm.h"
 
-int isis_run_spf_l1 (struct thread *thread);
-int isis_run_spf_l2 (struct thread *thread);
-
 /* 7.2.7 */
 static void
 remove_excess_adjs (struct list *adjs)
@@ -266,14 +264,12 @@ isis_spftree_new (struct isis_area *area)
   tree->last_run_timestamp = 0;
   tree->last_run_duration = 0;
   tree->runcount = 0;
-  tree->pending = 0;
   return tree;
 }
 
 void
 isis_spftree_del (struct isis_spftree *spftree)
 {
-  THREAD_TIMER_OFF (spftree->t_spf);
 
   spftree->tents->del = (void (*)(void *)) isis_vertex_del;
   list_delete (spftree->tents);
@@ -1240,7 +1236,6 @@ isis_run_spf (struct isis_area *area, int level, int family, u_char *sysid)
 
 out:
   isis_route_validate (area);
-  spftree->pending = 0;
   spftree->runcount++;
   spftree->last_run_timestamp = time (NULL);
   monotime(&time_now);
@@ -1248,11 +1243,10 @@ out:
   end_time = (end_time * 1000000) + time_now.tv_usec;
   spftree->last_run_duration = end_time - start_time;
 
-
   return retval;
 }
 
-int
+static int
 isis_run_spf_l1 (struct thread *thread)
 {
   struct isis_area *area;
@@ -1261,8 +1255,7 @@ isis_run_spf_l1 (struct thread *thread)
   area = THREAD_ARG (thread);
   assert (area);
 
-  area->spftree[0]->t_spf = NULL;
-  area->spftree[0]->pending = 0;
+  area->spf_timer[0] = NULL;
 
   if (!(area->is_type & IS_LEVEL_1))
     {
@@ -1277,11 +1270,13 @@ isis_run_spf_l1 (struct thread *thread)
 
   if (area->ip_circuits)
     retval = isis_run_spf (area, 1, AF_INET, isis->sysid);
+  if (area->ipv6_circuits)
+    retval = isis_run_spf (area, 1, AF_INET6, isis->sysid);
 
   return retval;
 }
 
-int
+static int
 isis_run_spf_l2 (struct thread *thread)
 {
   struct isis_area *area;
@@ -1290,8 +1285,7 @@ isis_run_spf_l2 (struct thread *thread)
   area = THREAD_ARG (thread);
   assert (area);
 
-  area->spftree[1]->t_spf = NULL;
-  area->spftree[1]->pending = 0;
+  area->spf_timer[1] = NULL;
 
   if (!(area->is_type & IS_LEVEL_2))
     {
@@ -1305,6 +1299,8 @@ isis_run_spf_l2 (struct thread *thread)
 
   if (area->ip_circuits)
     retval = isis_run_spf (area, 2, AF_INET, isis->sysid);
+  if (area->ipv6_circuits)
+    retval = isis_run_spf (area, 2, AF_INET6, isis->sysid);
 
   return retval;
 }
@@ -1323,126 +1319,55 @@ isis_spf_schedule (struct isis_area *area, int level)
     zlog_debug ("ISIS-Spf (%s) L%d SPF schedule called, lastrun %d sec ago",
                 area->area_tag, level, diff);
 
-  if (spftree->pending)
-    return ISIS_OK;
-
-  THREAD_TIMER_OFF (spftree->t_spf);
-
-  /* wait configured min_spf_interval before doing the SPF */
-  if (diff >= area->min_spf_interval[level-1])
-      return isis_run_spf (area, level, AF_INET, isis->sysid);
-
-  if (level == 1)
-    THREAD_TIMER_ON (master, spftree->t_spf, isis_run_spf_l1, area,
-                     area->min_spf_interval[0] - diff);
-  else
-    THREAD_TIMER_ON (master, spftree->t_spf, isis_run_spf_l2, area,
-                     area->min_spf_interval[1] - diff);
-
-  if (isis->debugs & DEBUG_SPF_EVENTS)
-    zlog_debug ("ISIS-Spf (%s) L%d SPF scheduled %d sec from now",
-                area->area_tag, level, area->min_spf_interval[level-1] - diff);
-
-  spftree->pending = 1;
-
-  return ISIS_OK;
-}
-
-static int
-isis_run_spf6_l1 (struct thread *thread)
-{
-  struct isis_area *area;
-  int retval = ISIS_OK;
-
-  area = THREAD_ARG (thread);
-  assert (area);
-
-  area->spftree6[0]->t_spf = NULL;
-  area->spftree6[0]->pending = 0;
-
-  if (!(area->is_type & IS_LEVEL_1))
+  if (area->spf_delay_ietf[level - 1])
     {
-      if (isis->debugs & DEBUG_SPF_EVENTS)
-        zlog_warn ("ISIS-SPF (%s) area does not share level", area->area_tag);
-      return ISIS_WARNING;
-    }
-
-  if (isis->debugs & DEBUG_SPF_EVENTS)
-    zlog_debug ("ISIS-Spf (%s) L1 SPF needed, periodic SPF", area->area_tag);
-
-  if (area->ipv6_circuits)
-    retval = isis_run_spf (area, 1, AF_INET6, isis->sysid);
+      /* Need to call schedule function also if spf delay is running to
+       * restart holdoff timer - compare draft-ietf-rtgwg-backoff-algo-04 */
+      long delay = spf_backoff_schedule(area->spf_delay_ietf[level -1]);
+      if (area->spf_timer[level - 1])
+        return ISIS_OK;
 
-  return retval;
-}
-
-static int
-isis_run_spf6_l2 (struct thread *thread)
-{
-  struct isis_area *area;
-  int retval = ISIS_OK;
-
-  area = THREAD_ARG (thread);
-  assert (area);
-
-  area->spftree6[1]->t_spf = NULL;
-  area->spftree6[1]->pending = 0;
-
-  if (!(area->is_type & IS_LEVEL_2))
-    {
-      if (isis->debugs & DEBUG_SPF_EVENTS)
-        zlog_warn ("ISIS-SPF (%s) area does not share level", area->area_tag);
-      return ISIS_WARNING;
+      if (level == 1)
+        {
+          THREAD_TIMER_MSEC_ON(master, area->spf_timer[0],
+                               isis_run_spf_l1, area, delay);
+        }
+      else
+        {
+          THREAD_TIMER_MSEC_ON(master, area->spf_timer[1],
+                               isis_run_spf_l2, area, delay);
+        }
+      return ISIS_OK;
     }
 
-  if (isis->debugs & DEBUG_SPF_EVENTS)
-    zlog_debug ("ISIS-Spf (%s) L2 SPF needed, periodic SPF.", area->area_tag);
-
-  if (area->ipv6_circuits)
-    retval = isis_run_spf (area, 2, AF_INET6, isis->sysid);
-
-  return retval;
-}
-
-int
-isis_spf_schedule6 (struct isis_area *area, int level)
-{
-  int retval = ISIS_OK;
-  struct isis_spftree *spftree = area->spftree6[level - 1];
-  time_t now = time (NULL);
-  time_t diff = now - spftree->last_run_timestamp;
-
-  assert (diff >= 0);
-  assert (area->is_type & level);
-
-  if (isis->debugs & DEBUG_SPF_EVENTS)
-    zlog_debug ("ISIS-Spf (%s) L%d SPF schedule called, lastrun %lld sec ago",
-                area->area_tag, level, (long long)diff);
-
-  if (spftree->pending)
+  if (area->spf_timer[level -1])
     return ISIS_OK;
 
-  THREAD_TIMER_OFF (spftree->t_spf);
-
   /* wait configured min_spf_interval before doing the SPF */
   if (diff >= area->min_spf_interval[level-1])
-      return isis_run_spf (area, level, AF_INET6, isis->sysid);
+    {
+      int retval = ISIS_OK;
+
+      if (area->ip_circuits)
+        retval = isis_run_spf (area, level, AF_INET, isis->sysid);
+      if (area->ipv6_circuits)
+        retval = isis_run_spf (area, level, AF_INET6, isis->sysid);
+
+      return retval;
+    }
 
   if (level == 1)
-    THREAD_TIMER_ON (master, spftree->t_spf, isis_run_spf6_l1, area,
+    THREAD_TIMER_ON (master, area->spf_timer[0], isis_run_spf_l1, area,
                      area->min_spf_interval[0] - diff);
   else
-    THREAD_TIMER_ON (master, spftree->t_spf, isis_run_spf6_l2, area,
+    THREAD_TIMER_ON (master, area->spf_timer[1], isis_run_spf_l2, area,
                      area->min_spf_interval[1] - diff);
 
   if (isis->debugs & DEBUG_SPF_EVENTS)
-    zlog_debug ("ISIS-Spf (%s) L%d SPF scheduled %lld sec from now",
-                area->area_tag, level,
-               (long long)(area->min_spf_interval[level-1] - diff));
-
-  spftree->pending = 1;
+    zlog_debug ("ISIS-Spf (%s) L%d SPF scheduled %d sec from now",
+                area->area_tag, level, area->min_spf_interval[level-1] - diff);
 
-  return retval;
+  return ISIS_OK;
 }
 
 static void
index 0e42cac81f0506772c388d7f3cb3747e7a44642d..fb534542d05dabde70039e96a2bab9bbe0d5f12a 100644 (file)
@@ -60,11 +60,9 @@ struct isis_vertex
 
 struct isis_spftree
 {
-  struct thread *t_spf;                /* spf threads */
   struct list *paths;          /* the SPT */
   struct list *tents;          /* TENT */
   struct isis_area *area;       /* back pointer to area */
-  int pending;                 /* already scheduled */
   unsigned int runcount;        /* number of runs since uptime */
   time_t last_run_timestamp;    /* last run timestamp for scheduling */
   time_t last_run_duration;     /* last run duration in msec */
@@ -80,5 +78,4 @@ void spftree_area_adj_del (struct isis_area *area,
                            struct isis_adjacency *adj);
 int isis_spf_schedule (struct isis_area *area, int level);
 void isis_spf_cmds_init (void);
-int isis_spf_schedule6 (struct isis_area *area, int level);
 #endif /* _ZEBRA_ISIS_SPF_H */
index 848c56a6acf606a6024ff01cf62e49a9151fc1cd..721959859a0cb46b31f1d154091b6c0d500778f5 100644 (file)
@@ -22,7 +22,9 @@
  */
 
 #include <zebra.h>
-#include <command.h>
+
+#include "command.h"
+#include "spf_backoff.h"
 
 #include "isis_circuit.h"
 #include "isis_csm.h"
@@ -1707,6 +1709,63 @@ DEFUN (no_spf_interval_l2,
   return CMD_SUCCESS;
 }
 
+DEFUN (no_spf_delay_ietf,
+       no_spf_delay_ietf_cmd,
+       "no spf-delay-ietf",
+       NO_STR
+       "IETF SPF delay algorithm\n")
+{
+  VTY_DECLVAR_CONTEXT (isis_area, area);
+
+  spf_backoff_free(area->spf_delay_ietf[0]);
+  spf_backoff_free(area->spf_delay_ietf[1]);
+  area->spf_delay_ietf[0] = NULL;
+  area->spf_delay_ietf[1] = NULL;
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (spf_delay_ietf,
+       spf_delay_ietf_cmd,
+       "spf-delay-ietf init-delay (0-60000) short-delay (0-60000) long-delay (0-60000) holddown (0-60000) time-to-learn (0-60000)",
+       "IETF SPF delay algorithm\n"
+       "Delay used while in QUIET state\n"
+       "Delay used while in QUIET state in milliseconds\n"
+       "Delay used while in SHORT_WAIT state\n"
+       "Delay used while in SHORT_WAIT state in milliseconds\n"
+       "Delay used while in LONG_WAIT\n"
+       "Delay used while in LONG_WAIT state in milliseconds\n"
+       "Time with no received IGP events before considering IGP stable\n"
+       "Time with no received IGP events before considering IGP stable (in milliseconds)\n"
+       "Maximum duration needed to learn all the events related to a single failure\n"
+       "Maximum duration needed to learn all the events related to a single failure (in milliseconds)\n")
+{
+  VTY_DECLVAR_CONTEXT (isis_area, area);
+
+  long init_delay = atol(argv[2]->arg);
+  long short_delay = atol(argv[4]->arg);
+  long long_delay = atol(argv[6]->arg);
+  long holddown = atol(argv[8]->arg);
+  long timetolearn = atol(argv[10]->arg);
+
+  size_t bufsiz = strlen(area->area_tag) + sizeof("IS-IS  Lx");
+  char *buf = XCALLOC(MTYPE_TMP, bufsiz);
+
+  snprintf(buf, bufsiz, "IS-IS %s L1", area->area_tag);
+  spf_backoff_free(area->spf_delay_ietf[0]);
+  area->spf_delay_ietf[0] = spf_backoff_new(master, buf, init_delay,
+                                            short_delay, long_delay,
+                                            holddown, timetolearn);
+
+  snprintf(buf, bufsiz, "IS-IS %s L2", area->area_tag);
+  spf_backoff_free(area->spf_delay_ietf[1]);
+  area->spf_delay_ietf[1] = spf_backoff_new(master, buf, init_delay,
+                                            short_delay, long_delay,
+                                            holddown, timetolearn);
+
+  XFREE(MTYPE_TMP, buf);
+  return CMD_SUCCESS;
+}
 
 static int
 area_max_lsp_lifetime_set(struct vty *vty, int level,
@@ -2096,4 +2155,8 @@ isis_vty_init (void)
   install_element (ISIS_NODE, &domain_passwd_md5_cmd);
   install_element (ISIS_NODE, &domain_passwd_clear_cmd);
   install_element (ISIS_NODE, &no_area_passwd_cmd);
+
+  install_element (ISIS_NODE, &spf_delay_ietf_cmd);
+  install_element (ISIS_NODE, &no_spf_delay_ietf_cmd);
+
 }
index 9bef25088308ac353e9dca3e6128569251c97c62..2863d2f67885cbd0c7bd81a3289292d834204bad 100644 (file)
@@ -35,6 +35,7 @@
 #include "prefix.h"
 #include "table.h"
 #include "qobj.h"
+#include "spf_backoff.h"
 
 #include "isisd/dict.h"
 #include "isisd/isis_constants.h"
@@ -245,6 +246,12 @@ isis_area_destroy (struct vty *vty, const char *area_tag)
 
   spftree_area_del (area);
 
+  THREAD_TIMER_OFF(area->spf_timer[0]);
+  THREAD_TIMER_OFF(area->spf_timer[1]);
+
+  spf_backoff_free(area->spf_delay_ietf[0]);
+  spf_backoff_free(area->spf_delay_ietf[1]);
+
   /* invalidate and validate would delete all routes from zebra */
   isis_route_invalidate (area);
   isis_route_validate (area);
@@ -856,6 +863,7 @@ config_write_debug (struct vty *vty)
       vty_out (vty, "debug isis lsp-sched%s", VTY_NEWLINE);
       write++;
     }
+  write += spf_backoff_write_config(vty);
 
   return write;
 }
@@ -1273,6 +1281,57 @@ vty_out_timestr(struct vty *vty, time_t uptime)
   vty_out (vty, " ago");
 }
 
+DEFUN (show_isis_spf_ietf,
+       show_isis_spf_ietf_cmd,
+       "show isis spf-delay-ietf",
+       SHOW_STR
+       "IS-IS information\n"
+       "IS-IS SPF delay IETF information\n")
+{
+  if (!isis)
+    {
+      vty_out (vty, "ISIS is not running%s", VTY_NEWLINE);
+      return CMD_SUCCESS;
+    }
+
+  struct listnode *node;
+  struct isis_area *area;
+
+  for (ALL_LIST_ELEMENTS_RO (isis->area_list, node, area))
+    {
+      vty_out (vty, "Area %s:%s", area->area_tag ? area->area_tag : "null",
+               VTY_NEWLINE);
+
+      for (int level = ISIS_LEVEL1; level <= ISIS_LEVELS; level++)
+        {
+          if ((area->is_type & level) == 0)
+            continue;
+
+          vty_out (vty, "  Level-%d:%s", level, VTY_NEWLINE);
+          vty_out (vty, "    SPF delay status: ");
+          if (area->spf_timer[level -1])
+            {
+              struct timeval remain = thread_timer_remain(area->spf_timer[level - 1]);
+              vty_out(vty, "Pending, due in %ld msec%s",
+                      remain.tv_sec * 1000 + remain.tv_usec / 1000,
+                      VTY_NEWLINE);
+            }
+          else
+            {
+              vty_out(vty, "Not scheduled%s", VTY_NEWLINE);
+            }
+
+          if (area->spf_delay_ietf[level - 1]) {
+            vty_out(vty,  "    Using draft-ietf-rtgwg-backoff-algo-04%s", VTY_NEWLINE);
+            spf_backoff_show(area->spf_delay_ietf[level - 1], vty, "    ");
+          } else {
+            vty_out(vty,  "    Using legacy backoff algo%s", VTY_NEWLINE);
+          }
+        }
+    }
+  return CMD_SUCCESS;
+}
+
 DEFUN (show_isis_summary,
        show_isis_summary_cmd,
        "show isis summary",
@@ -1327,14 +1386,18 @@ DEFUN (show_isis_summary,
 
       vty_out (vty, "  Level-%d:%s", level, VTY_NEWLINE);
       spftree = area->spftree[level - 1];
-      if (spftree->pending)
-        vty_out (vty, "    IPv4 SPF: (pending)%s", VTY_NEWLINE);
+      if (area->spf_timer[level - 1])
+        vty_out (vty, "    SPF: (pending)%s", VTY_NEWLINE);
       else
-        vty_out (vty, "    IPv4 SPF:%s", VTY_NEWLINE);
+        vty_out (vty, "    SPF:%s", VTY_NEWLINE);
 
-      vty_out (vty, "      minimum interval  : %d%s",
-          area->min_spf_interval[level - 1], VTY_NEWLINE);
+      vty_out (vty, "      minimum interval  : %d",
+          area->min_spf_interval[level - 1]);
+      if (area->spf_delay_ietf[level - 1])
+         vty_out (vty, " (not used, IETF SPF delay activated)");
+      vty_out (vty, VTY_NEWLINE);
 
+      vty_out (vty, "    IPv4 route computation:%s", VTY_NEWLINE);
       vty_out (vty, "      last run elapsed  : ");
       vty_out_timestr(vty, spftree->last_run_timestamp);
       vty_out (vty, "%s", VTY_NEWLINE);
@@ -1346,13 +1409,7 @@ DEFUN (show_isis_summary,
           spftree->runcount, VTY_NEWLINE);
 
       spftree = area->spftree6[level - 1];
-      if (spftree->pending)
-        vty_out (vty, "    IPv6 SPF: (pending)%s", VTY_NEWLINE);
-      else
-        vty_out (vty, "    IPv6 SPF:%s", VTY_NEWLINE);
-
-      vty_out (vty, "      minimum interval  : %d%s",
-          area->min_spf_interval[level - 1], VTY_NEWLINE);
+      vty_out (vty, "    IPv6 route computation:%s", VTY_NEWLINE);
 
       vty_out (vty, "      last run elapsed  : ");
       vty_out_timestr(vty, spftree->last_run_timestamp);
@@ -1651,6 +1708,7 @@ area_resign_level (struct isis_area *area, int level)
       isis_spftree_del (area->spftree6[level - 1]);
       area->spftree6[level - 1] = NULL;
     }
+  THREAD_TIMER_OFF(area->spf_timer[level - 1]);
   if (area->route_table[level - 1])
     {
       route_table_finish (area->route_table[level - 1]);
@@ -2010,6 +2068,20 @@ isis_config_write (struct vty *vty)
                write++;
              }
          }
+
+       /* IETF SPF interval */
+       if (area->spf_delay_ietf[0])
+         {
+           vty_out (vty, " spf-delay-ietf init-delay %ld short-delay %ld long-delay %ld holddown %ld time-to-learn %ld%s",
+                    spf_backoff_init_delay(area->spf_delay_ietf[0]),
+                    spf_backoff_short_delay(area->spf_delay_ietf[0]),
+                    spf_backoff_long_delay(area->spf_delay_ietf[0]),
+                    spf_backoff_holddown(area->spf_delay_ietf[0]),
+                    spf_backoff_timetolearn(area->spf_delay_ietf[0]),
+                    VTY_NEWLINE);
+           write++;
+         }
+
        /* Authentication passwords. */
        if (area->area_passwd.type == ISIS_PASSWD_TYPE_HMAC_MD5)
          {
@@ -2097,6 +2169,8 @@ isis_init ()
 
   install_element (VIEW_NODE, &show_isis_summary_cmd);
 
+  install_element (VIEW_NODE, &show_isis_spf_ietf_cmd);
+
   install_element (VIEW_NODE, &show_isis_interface_cmd);
   install_element (VIEW_NODE, &show_isis_interface_detail_cmd);
   install_element (VIEW_NODE, &show_isis_interface_arg_cmd);
@@ -2182,4 +2256,6 @@ isis_init ()
 
   install_element (ISIS_NODE, &log_adj_changes_cmd);
   install_element (ISIS_NODE, &no_log_adj_changes_cmd);
+
+  spf_backoff_cmd_init();
 }
index efbfafc5fbd7803f8a27dd2cd571f14032eb9978..e1d3a69f8dcc5e4ac7bf8ab6f71b9cfdf80ccf35 100644 (file)
@@ -127,6 +127,9 @@ struct isis_area
                                     [ZEBRA_ROUTE_MAX + 1][ISIS_LEVELS];
   struct route_table *ext_reach[REDIST_PROTOCOL_COUNT][ISIS_LEVELS];
 
+  struct spf_backoff *spf_delay_ietf[ISIS_LEVELS]; /*Structure with IETF SPF algo parameters*/
+  struct thread *spf_timer[ISIS_LEVELS];
+
   QOBJ_FIELDS
 };
 DECLARE_QOBJ_TYPE(isis_area)
index 780d4bc1b8386bac505a67d52482648dacc34ebb..a9fe646938f4738823ab9c6dc288acbbf3787b57 100644 (file)
@@ -28,6 +28,7 @@ libfrr_la_SOURCES = \
        event_counter.c \
        grammar_sandbox.c \
        srcdest_table.c \
+       spf_backoff.c \
        strlcpy.c \
        strlcat.c
 
@@ -50,6 +51,7 @@ pkginclude_HEADERS = \
        skiplist.h qobj.h wheel.h \
        event_counter.h \
        monotime.h \
+       spf_backoff.h \
        srcdest_table.h
 
 noinst_HEADERS = \
index 0fd49404311b8e51f35f92f8cd53bab926095423..ad44bf511a2c6c558df784fcc7b935dfd60dc171 100644 (file)
 
 #ifndef TIMESPEC_TO_TIMEVAL
 /* should be in sys/time.h on BSD & Linux libcs */
-#define TIMESPEC_TO_TIMEVAL(tv, ts) do {       \
-       (tv)->tv_sec = (ts)->tv_sec;            \
-       (tv)->tv_usec = (ts)->tv_nsec / 1000;   \
-       } while (0)
+#define TIMESPEC_TO_TIMEVAL(tv, ts) do {        \
+        (tv)->tv_sec = (ts)->tv_sec;            \
+        (tv)->tv_usec = (ts)->tv_nsec / 1000;   \
+        } while (0)
 #endif
 #ifndef TIMEVAL_TO_TIMESPEC
 /* should be in sys/time.h on BSD & Linux libcs */
-#define TIMEVAL_TO_TIMESPEC(tv, ts) do {       \
-       (ts)->tv_sec = (tv)->tv_sec;            \
-       (ts)->tv_nsec = (tv)->tv_usec * 1000;   \
-       } while (0)
+#define TIMEVAL_TO_TIMESPEC(tv, ts) do {        \
+        (ts)->tv_sec = (tv)->tv_sec;            \
+        (ts)->tv_nsec = (tv)->tv_usec * 1000;   \
+        } while (0)
 #endif
 
 static inline time_t monotime(struct timeval *tvo)
 {
-       struct timespec ts;
+        struct timespec ts;
 
-       clock_gettime(CLOCK_MONOTONIC, &ts);
-       if (tvo) {
-               TIMESPEC_TO_TIMEVAL(tvo, &ts);
-       }
-       return ts.tv_sec;
+        clock_gettime(CLOCK_MONOTONIC, &ts);
+        if (tvo) {
+                TIMESPEC_TO_TIMEVAL(tvo, &ts);
+        }
+        return ts.tv_sec;
 }
 
 /* the following two return microseconds, not time_t!
@@ -53,25 +53,25 @@ static inline time_t monotime(struct timeval *tvo)
  * code more readable
  */
 static inline int64_t monotime_since(const struct timeval *ref,
-                                    struct timeval *out)
+                                     struct timeval *out)
 {
-       struct timeval tv;
-       monotime(&tv);
-       timersub(&tv, ref, &tv);
-       if (out)
-               *out = tv;
-       return (int64_t)tv.tv_sec * 1000000LL + tv.tv_usec;
+        struct timeval tv;
+        monotime(&tv);
+        timersub(&tv, ref, &tv);
+        if (out)
+                *out = tv;
+        return (int64_t)tv.tv_sec * 1000000LL + tv.tv_usec;
 }
 
 static inline int64_t monotime_until(const struct timeval *ref,
-                                    struct timeval *out)
+                                     struct timeval *out)
 {
-       struct timeval tv;
-       monotime(&tv);
-       timersub(ref, &tv, &tv);
-       if (out)
-               *out = tv;
-       return (int64_t)tv.tv_sec * 1000000LL + tv.tv_usec;
+        struct timeval tv;
+        monotime(&tv);
+        timersub(ref, &tv, &tv);
+        if (out)
+                *out = tv;
+        return (int64_t)tv.tv_sec * 1000000LL + tv.tv_usec;
 }
 
 #endif /* _FRR_MONOTIME_H */
diff --git a/lib/spf_backoff.c b/lib/spf_backoff.c
new file mode 100644 (file)
index 0000000..e923f23
--- /dev/null
@@ -0,0 +1,341 @@
+/*
+ * This is an implementation of the IETF SPF delay algorithm
+ * as explained in draft-ietf-rtgwg-backoff-algo-04
+ *
+ * Created: 25-01-2017 by S. Litkowski
+ *
+ * Copyright (C) 2017 Orange Labs http://www.orange.com/
+ * Copyright (C) 2017 by Christian Franke, Open Source Routing / NetDEF Inc.
+ *
+ * This file is part of FreeRangeRouting (FRR)
+ *
+ * FRR 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.
+ *
+ * FRR 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 FRR; 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 "spf_backoff.h"
+
+#include "command.h"
+#include "memory.h"
+#include "thread.h"
+#include "vty.h"
+
+DEFINE_MTYPE_STATIC(LIB, SPF_BACKOFF, "SPF backoff")
+DEFINE_MTYPE_STATIC(LIB, SPF_BACKOFF_NAME, "SPF backoff name")
+
+static bool debug_spf_backoff = false;
+#define backoff_debug(...) \
+  do \
+    { \
+      if (debug_spf_backoff) \
+        zlog_debug(__VA_ARGS__); \
+    } \
+  while (0)
+
+enum spf_backoff_state {
+  SPF_BACKOFF_QUIET,
+  SPF_BACKOFF_SHORT_WAIT,
+  SPF_BACKOFF_LONG_WAIT
+};
+
+struct spf_backoff {
+  struct thread_master *m;
+
+  /* Timers as per draft */
+  long init_delay;
+  long short_delay;
+  long long_delay;
+  long holddown;
+  long timetolearn;
+
+  /* State machine */
+  enum spf_backoff_state state;
+  struct thread *t_holddown;
+  struct thread *t_timetolearn;
+
+  /* For debugging */
+  char *name;
+  struct timeval first_event_time;
+  struct timeval last_event_time;
+};
+
+static const char *
+spf_backoff_state2str(enum spf_backoff_state state)
+{
+  switch (state)
+    {
+    case SPF_BACKOFF_QUIET:
+      return "QUIET";
+    case SPF_BACKOFF_SHORT_WAIT:
+      return "SHORT_WAIT";
+    case SPF_BACKOFF_LONG_WAIT:
+      return "LONG_WAIT";
+    }
+  return "???";
+}
+
+struct spf_backoff *
+spf_backoff_new(struct thread_master *m,
+                const char *name,
+                long init_delay,
+                long short_delay,
+                long long_delay,
+                long holddown,
+                long timetolearn)
+{
+  struct spf_backoff *rv;
+
+  rv = XCALLOC(MTYPE_SPF_BACKOFF, sizeof(*rv));
+  rv->m = m;
+
+  rv->init_delay = init_delay;
+  rv->short_delay = short_delay;
+  rv->long_delay = long_delay;
+  rv->holddown = holddown;
+  rv->timetolearn = timetolearn;
+
+  rv->state = SPF_BACKOFF_QUIET;
+
+  rv->name = XSTRDUP(MTYPE_SPF_BACKOFF_NAME, name);
+  return rv;
+}
+
+void
+spf_backoff_free(struct spf_backoff *backoff)
+{
+  if (!backoff)
+    return;
+
+  THREAD_TIMER_OFF(backoff->t_holddown);
+  THREAD_TIMER_OFF(backoff->t_timetolearn);
+  XFREE(MTYPE_SPF_BACKOFF_NAME, backoff->name);
+
+  XFREE(MTYPE_SPF_BACKOFF, backoff);
+}
+
+static int
+spf_backoff_timetolearn_elapsed(struct thread *thread)
+{
+  struct spf_backoff *backoff = THREAD_ARG(thread);
+
+  backoff->t_timetolearn = NULL;
+  backoff->state = SPF_BACKOFF_LONG_WAIT;
+  backoff_debug("SPF Back-off(%s) TIMETOLEARN elapsed, move to state %s",
+                backoff->name, spf_backoff_state2str(backoff->state));
+  return 0;
+}
+
+static int
+spf_backoff_holddown_elapsed(struct thread *thread)
+{
+  struct spf_backoff *backoff = THREAD_ARG(thread);
+
+  backoff->t_holddown = NULL;
+  THREAD_TIMER_OFF(backoff->t_timetolearn);
+  timerclear(&backoff->first_event_time);
+  backoff->state = SPF_BACKOFF_QUIET;
+  backoff_debug("SPF Back-off(%s) HOLDDOWN elapsed, move to state %s",
+                backoff->name, spf_backoff_state2str(backoff->state));
+  return 0;
+}
+
+long spf_backoff_schedule(struct spf_backoff *backoff)
+{
+  long rv;
+  struct timeval now;
+
+  gettimeofday(&now, NULL);
+
+  backoff_debug("SPF Back-off(%s) schedule called in state %s",
+                backoff->name, spf_backoff_state2str(backoff->state));
+
+  backoff->last_event_time = now;
+
+  switch (backoff->state)
+    {
+    case SPF_BACKOFF_QUIET:
+      backoff->state = SPF_BACKOFF_SHORT_WAIT;
+      THREAD_TIMER_MSEC_ON(backoff->m, backoff->t_timetolearn,
+                           spf_backoff_timetolearn_elapsed, backoff,
+                           backoff->timetolearn);
+      THREAD_TIMER_MSEC_ON(backoff->m, backoff->t_holddown,
+                           spf_backoff_holddown_elapsed, backoff,
+                           backoff->holddown);
+      backoff->first_event_time = now;
+      rv = backoff->init_delay;
+      break;
+    case SPF_BACKOFF_SHORT_WAIT:
+    case SPF_BACKOFF_LONG_WAIT:
+      THREAD_TIMER_OFF(backoff->t_holddown);
+      THREAD_TIMER_MSEC_ON(backoff->m, backoff->t_holddown,
+                           spf_backoff_holddown_elapsed, backoff,
+                           backoff->holddown);
+      if (backoff->state == SPF_BACKOFF_SHORT_WAIT)
+        rv = backoff->short_delay;
+      else
+        rv = backoff->long_delay;
+      break;
+    default:
+      zlog_warn("SPF Back-off(%s) in unknown state", backoff->name);
+      rv = backoff->init_delay;
+    }
+
+  backoff_debug("SPF Back-off(%s) changed state to %s and returned %ld delay",
+                backoff->name, spf_backoff_state2str(backoff->state), rv);
+  return rv;
+}
+
+static const char *
+timeval_format(struct timeval *tv)
+{
+  struct tm tm_store;
+  struct tm *tm;
+  static char timebuf[256];
+
+  if (!tv->tv_sec && !tv->tv_usec)
+    return "(never)";
+
+  tm = localtime_r(&tv->tv_sec, &tm_store);
+  if (!tm || strftime(timebuf, sizeof(timebuf),
+                      "%Z %a %Y-%m-%d %H:%M:%S", tm) == 0)
+    {
+      return "???";
+    }
+
+  size_t offset = strlen(timebuf);
+  snprintf(timebuf + offset, sizeof(timebuf) - offset, ".%ld", tv->tv_usec);
+
+  return timebuf;
+}
+
+void
+spf_backoff_show(struct spf_backoff *backoff, struct vty *vty,
+                 const char *prefix)
+{
+  vty_out(vty, "%sCurrent state:     %s%s", prefix,
+          spf_backoff_state2str(backoff->state), VTY_NEWLINE);
+  vty_out(vty, "%sInit timer:        %ld msec%s", prefix,
+          backoff->init_delay, VTY_NEWLINE);
+  vty_out(vty, "%sShort timer:       %ld msec%s", prefix,
+          backoff->short_delay, VTY_NEWLINE);
+  vty_out(vty, "%sLong timer:        %ld msec%s", prefix,
+          backoff->long_delay, VTY_NEWLINE);
+  vty_out(vty, "%sHolddown timer:    %ld msec%s", prefix,
+          backoff->holddown, VTY_NEWLINE);
+  if (backoff->t_holddown)
+    {
+      struct timeval remain = thread_timer_remain(backoff->t_holddown);
+      vty_out(vty, "%s                   Still runs for %ld msec%s",
+              prefix, remain.tv_sec * 1000 + remain.tv_usec/1000, VTY_NEWLINE);
+    }
+  else
+    {
+      vty_out(vty, "%s                   Inactive%s", prefix, VTY_NEWLINE);
+    }
+
+  vty_out(vty, "%sTimeToLearn timer: %ld msec%s", prefix,
+          backoff->timetolearn, VTY_NEWLINE);
+  if (backoff->t_timetolearn)
+    {
+      struct timeval remain = thread_timer_remain(backoff->t_timetolearn);
+      vty_out(vty, "%s                   Still runs for %ld msec%s",
+              prefix, remain.tv_sec * 1000 + remain.tv_usec/1000, VTY_NEWLINE);
+    }
+  else
+    {
+      vty_out(vty, "%s                   Inactive%s", prefix, VTY_NEWLINE);
+    }
+
+  vty_out(vty, "%sFirst event:       %s%s", prefix,
+          timeval_format(&backoff->first_event_time), VTY_NEWLINE);
+  vty_out(vty, "%sLast event:        %s%s", prefix,
+          timeval_format(&backoff->last_event_time), VTY_NEWLINE);
+}
+
+DEFUN(spf_backoff_debug,
+      spf_backoff_debug_cmd,
+      "debug spf-delay-ietf",
+      DEBUG_STR
+      "SPF Back-off Debugging\n")
+{
+  debug_spf_backoff = true;
+  return CMD_SUCCESS;
+}
+
+DEFUN(no_spf_backoff_debug,
+      no_spf_backoff_debug_cmd,
+      "no debug spf-delay-ietf",
+      NO_STR
+      DEBUG_STR
+      "SPF Back-off Debugging\n")
+{
+  debug_spf_backoff = false;
+  return CMD_SUCCESS;
+}
+
+int
+spf_backoff_write_config(struct vty *vty)
+{
+  int written = 0;
+
+  if (debug_spf_backoff)
+    {
+      vty_out(vty, "debug spf-delay-ietf%s", VTY_NEWLINE);
+      written++;
+    }
+
+  return written;
+}
+
+void
+spf_backoff_cmd_init(void)
+{
+  install_element(ENABLE_NODE, &spf_backoff_debug_cmd);
+  install_element(CONFIG_NODE, &spf_backoff_debug_cmd);
+  install_element(ENABLE_NODE, &no_spf_backoff_debug_cmd);
+  install_element(CONFIG_NODE, &no_spf_backoff_debug_cmd);
+}
+
+long
+spf_backoff_init_delay(struct spf_backoff *backoff)
+{
+  return backoff->init_delay;
+}
+
+long
+spf_backoff_short_delay(struct spf_backoff *backoff)
+{
+  return backoff->short_delay;
+}
+
+long
+spf_backoff_long_delay(struct spf_backoff *backoff)
+{
+  return backoff->long_delay;
+}
+
+long
+spf_backoff_holddown(struct spf_backoff *backoff)
+{
+  return backoff->holddown;
+}
+
+long
+spf_backoff_timetolearn(struct spf_backoff *backoff)
+{
+  return backoff->timetolearn;
+}
diff --git a/lib/spf_backoff.h b/lib/spf_backoff.h
new file mode 100644 (file)
index 0000000..552ca4a
--- /dev/null
@@ -0,0 +1,66 @@
+/*
+ * This is an implementation of the IETF SPF delay algorithm
+ * as explained in draft-ietf-rtgwg-backoff-algo-04
+ *
+ * Created: 25-01-2017 by S. Litkowski
+ *
+ * Copyright (C) 2017 Orange Labs http://www.orange.com/
+ * Copyright (C) 2017 by Christian Franke, Open Source Routing / NetDEF Inc.
+ *
+ * This file is part of FreeRangeRouting (FRR)
+ *
+ * FRR 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.
+ *
+ * FRR 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 FRR; see the file COPYING.  If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+#ifndef _ZEBRA_SPF_BACKOFF_H
+#define _ZEBRA_SPF_BACKOFF_H
+
+struct spf_backoff;
+struct thread_master;
+struct vty;
+
+struct spf_backoff *spf_backoff_new(struct thread_master *m,
+                                    const char *name,
+                                    long init_delay,
+                                    long short_delay,
+                                    long long_delay,
+                                    long holddown,
+                                    long timetolearn);
+
+void spf_backoff_free(struct spf_backoff *backoff);
+
+/* Called whenever an IGP event is received, returns how many
+ * milliseconds routing table computation should be delayed */
+long spf_backoff_schedule(struct spf_backoff *backoff);
+
+/* Shows status of SPF backoff instance */
+void spf_backoff_show(struct spf_backoff *backoff,
+                      struct vty *vty,
+                      const char *prefix);
+
+/* Writes out global SPF backoff debug config */
+int spf_backoff_write_config(struct vty *vty);
+
+/* Registers global SPF backoff debug commands */
+void spf_backoff_cmd_init(void);
+
+/* Accessor functions for SPF backoff parameters */
+long spf_backoff_init_delay(struct spf_backoff *backoff);
+long spf_backoff_short_delay(struct spf_backoff *backoff);
+long spf_backoff_long_delay(struct spf_backoff *backoff);
+long spf_backoff_holddown(struct spf_backoff *backoff);
+long spf_backoff_timetolearn(struct spf_backoff *backoff);
+
+#endif
index f3be18a66081db7738dbcff3f77bbed934aa5f6a..72a4f6394d1f93d887581912a5b7b96599bbe0fb 100644 (file)
--- a/lib/vty.h
+++ b/lib/vty.h
@@ -177,7 +177,7 @@ struct vty_arg
 };
 
 /* Integrated configuration file. */
-#define INTEGRATE_DEFAULT_CONFIG "Frr.conf"
+#define INTEGRATE_DEFAULT_CONFIG "frr.conf"
 
 /* Small macro to determine newline is newline only or linefeed needed. */
 #define VTY_NEWLINE  ((vty->type == VTY_TERM) ? "\r\n" : "\n")
index 76bee9cf55eadc1f75adc90a2ce1264251f0d1fa..1904623e714208e3c32e5c880cc71ad2878f5b71 100644 (file)
@@ -217,7 +217,7 @@ ospf6_zebra_read_ipv6 (int command, struct zclient *zclient,
   struct stream *s;
   struct zapi_ipv6 api;
   unsigned long ifindex;
-  struct prefix_ipv6 p, src_p;
+  struct prefix p, src_p;
   struct in6_addr *nexthop;
 
   if (ospf6 == NULL)
@@ -235,17 +235,17 @@ ospf6_zebra_read_ipv6 (int command, struct zclient *zclient,
   api.message = stream_getc (s);
 
   /* IPv6 prefix. */
-  memset (&p, 0, sizeof (struct prefix_ipv6));
+  memset (&p, 0, sizeof (struct prefix));
   p.family = AF_INET6;
   p.prefixlen = MIN(IPV6_MAX_PREFIXLEN, stream_getc (s));
-  stream_get (&p.prefix, s, PSIZE (p.prefixlen));
+  stream_get (&p.u.prefix6, s, PSIZE (p.prefixlen));
 
-  memset (&src_p, 0, sizeof (struct prefix_ipv6));
+  memset (&src_p, 0, sizeof (struct prefix));
   src_p.family = AF_INET6;
   if (CHECK_FLAG (api.message, ZAPI_MESSAGE_SRCPFX))
     {
       src_p.prefixlen = stream_getc (s);
-      stream_get (&src_p.prefix, s, PSIZE (src_p.prefixlen));
+      stream_get (&src_p.u.prefix6, s, PSIZE (src_p.prefixlen));
     }
 
   if (src_p.prefixlen)
@@ -294,10 +294,10 @@ ospf6_zebra_read_ipv6 (int command, struct zclient *zclient,
     }
  
   if (command == ZEBRA_REDISTRIBUTE_IPV6_ADD)
-    ospf6_asbr_redistribute_add (api.type, ifindex, (struct prefix *) &p,
+    ospf6_asbr_redistribute_add (api.type, ifindex, &p,
                                  api.nexthop_num, nexthop, api.tag);
   else
-    ospf6_asbr_redistribute_remove (api.type, ifindex, (struct prefix *) &p);
+    ospf6_asbr_redistribute_remove (api.type, ifindex, &p);
 
   if (CHECK_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP))
     free (nexthop);
index fb65665135c8d631c87d9c0641c578f1fdce7418..8c7083d83df21b85b116834104527292db169564 100644 (file)
@@ -348,6 +348,7 @@ static void source_channel_oil_detach(struct igmp_source *source)
 void igmp_source_delete(struct igmp_source *source)
 {
   struct igmp_group *group;
+  struct in_addr src;
 
   group = source->source_group;
 
@@ -388,12 +389,14 @@ void igmp_source_delete(struct igmp_source *source)
   */
   listnode_delete(group->group_source_list, source);
 
+  src.s_addr = source->source_addr.s_addr;
   igmp_source_free(source);
+
   /* Group source list is empty and current source is * then
    *,G group going away so do not trigger start */
   if (group->group_filtermode_isexcl &&
       (listcount (group->group_source_list) != 0) &&
-      source->source_addr.s_addr != INADDR_ANY)
+      src.s_addr != INADDR_ANY)
     {
       group_exclude_fwd_anysrc_ifempty (group);
     }
index 2ecaadbb5382a848edd438b3d5896bebc1ee683e..ba0b1a84c772db3bf1f13b3f8688c3e667503389 100755 (executable)
--- a/tools/frr
+++ b/tools/frr
@@ -61,7 +61,7 @@ started()
 vtysh_b ()
 {
         # Rember, that all variables have been incremented by 1 in convert_daemon_prios()
-        if [ "$vtysh_enable" = 2 -a -f $C_PATH/Frr.conf ]; then
+        if [ "$vtysh_enable" = 2 -a -f $C_PATH/frr.conf ]; then
                 /usr/bin/vtysh -b -n
         fi
 }
@@ -73,7 +73,7 @@ vtysh_b ()
 check_daemon()
 {
         # If the integrated config file is used the others are not checked.
-        if [ -r "$C_PATH/Frr.conf" ]; then
+        if [ -r "$C_PATH/frr.conf" ]; then
           return 0
         fi
 
@@ -543,10 +543,10 @@ case "$1" in
     reload)
        # Just apply the commands that have changed, no restart necessary
        [ ! -x "$RELOAD_SCRIPT" ] && echo "frr-reload script not available" && exit 0
-       NEW_CONFIG_FILE="${2:-$C_PATH/Frr.conf}"
+       NEW_CONFIG_FILE="${2:-$C_PATH/frr.conf}"
        [ ! -r $NEW_CONFIG_FILE ] && echo "Unable to read new configuration file $NEW_CONFIG_FILE" && exit 1
-       echo "Applying only incremental changes to running configuration from Frr.conf"
-       "$RELOAD_SCRIPT" --reload /etc/frr/Frr.conf
+       echo "Applying only incremental changes to running configuration from frr.conf"
+       "$RELOAD_SCRIPT" --reload /etc/frr/frr.conf
        exit $?
        ;;
 
index 80e259961a6db71b0592d3f5c0840c21d6520375..bf2b006963c234a6c12be68786afd8aeb57d0b8f 100755 (executable)
@@ -488,7 +488,7 @@ def line_to_vtysh_conft(ctx_keys, line, delete):
 
 def line_for_vtysh_file(ctx_keys, line, delete):
     """
-    Return the command as it would appear in Frr.conf
+    Return the command as it would appear in frr.conf
     """
     cmd = []
 
@@ -859,7 +859,7 @@ if __name__ == '__main__':
     parser.add_argument('--debug', action='store_true', help='Enable debugs', default=False)
     parser.add_argument('--stdout', action='store_true', help='Log to STDOUT', default=False)
     parser.add_argument('filename', help='Location of new frr config file')
-    parser.add_argument('--overwrite', action='store_true', help='Overwrite Frr.conf with running config output', default=False)
+    parser.add_argument('--overwrite', action='store_true', help='Overwrite frr.conf with running config output', default=False)
     args = parser.parse_args()
 
     # Logging
@@ -1081,5 +1081,5 @@ if __name__ == '__main__':
                     os.unlink(filename)
 
         # Make these changes persistent
-        if args.overwrite or args.filename != '/etc/frr/Frr.conf':
+        if args.overwrite or args.filename != '/etc/frr/frr.conf':
             subprocess.call(['/usr/bin/vtysh', '-c', 'write'])
index efc23ece888cf73e661e2d404b028e4ea4cd45e6..51dbbe2f32da5be2a6437486fd796bcbcdd67511 100644 (file)
@@ -17,6 +17,6 @@ Restart=on-abnormal
 LimitNOFILE=1024
 ExecStart=/usr/lib/frr/frr start
 ExecStop=/usr/lib/frr/frr stop
-ExecReload=/usr/lib/frr/frr-reload.py --reload /etc/frr/Frr.conf
+ExecReload=/usr/lib/frr/frr-reload.py --reload /etc/frr/frr.conf
 [Install]
 WantedBy=network-online.target
index c2e3bbbca1d6928aa59e4b6d97c1ef6565b5acd5..38f28e453010c00d79a48370cff0023b9d7d1f56 100644 (file)
@@ -2573,7 +2573,7 @@ DEFUN (vtysh_write_memory,
 
   fprintf (stdout, "Note: this version of vtysh never writes vtysh.conf\n");
 
-  /* If integrated Frr.conf explicitely set. */
+  /* If integrated frr.conf explicitely set. */
   if (want_config_integrated())
     {
       ret = CMD_WARNING;
index 39bf64f307ecd3275f15e25cc9f1273c46bbe9d4..ad31195ac4a28124015d6ae3ae7e515b681268e4 100644 (file)
@@ -49,7 +49,7 @@ DECLARE_MGROUP(MVTYSH)
 
 /* vtysh local configuration file. */
 #define VTYSH_DEFAULT_CONFIG "vtysh.conf"
-#define FRR_DEFAULT_CONFIG "Frr.conf"
+#define FRR_DEFAULT_CONFIG "frr.conf"
 
 enum vtysh_write_integrated {
        WRITE_INTEGRATED_UNSPECIFIED,
index 561eda045418c05e2529a62a2b37cd67f0961647..a24571a2bec97149413d77a1b4b2bd7ba4ae12cd 100644 (file)
@@ -151,7 +151,7 @@ usage (int status)
            "-m, --markfile           Mark input file with context end\n" \
            "    --vty_socket         Override vty socket path\n" \
            "    --config_dir         Override config directory path\n" \
-           "-w, --writeconfig        Write integrated config (Frr.conf) and exit\n" \
+           "-w, --writeconfig        Write integrated config (frr.conf) and exit\n" \
            "-h, --help               Display this help and exit\n\n" \
            "Note that multiple commands may be executed from the command\n" \
            "line by passing multiple -c args, or by embedding linefeed\n" \
@@ -355,7 +355,7 @@ main (int argc, char **argv, char **env)
          strlcat(vtysh_config_always, vtysh_configfile_name, 
              sizeof(vtysh_config_always));
          /* 
-          * Overwrite location for Frr.conf
+          * Overwrite location for frr.conf
           */
          vtysh_configfile_name = strrchr(FRR_DEFAULT_CONFIG, '/');
          if (vtysh_configfile_name)
index bf3e1510a7410763a0602457862dd8447bf90abb..64af7d7f4a59dac6f7857f665cece9e6567cc5aa 100644 (file)
@@ -35,7 +35,7 @@ DEFUN(config_write_integrated,
       config_write_integrated_cmd,
       "write integrated",
       "Write running configuration to memory, network, or terminal\n"
-      "Write integrated all-daemon Frr.conf file\n")
+      "Write integrated all-daemon frr.conf file\n")
 {
        pid_t child;
        sigset_t oldmask, sigmask;
index 660fad65307bfdd27781f5bd7d31b3850174ae12..65fc8789f9064c571d2319816034a637f9e59e93 100644 (file)
@@ -302,7 +302,7 @@ netlink_vrf_change (struct nlmsghdr *h, struct rtattr *tb, const char *name)
    during bootstrap. */
 static int
 netlink_interface (struct sockaddr_nl *snl, struct nlmsghdr *h,
-                   ns_id_t ns_id)
+                   ns_id_t ns_id, int startup)
 {
   int len;
   struct ifinfomsg *ifi;
@@ -403,7 +403,7 @@ interface_lookup_netlink (struct zebra_ns *zns)
   ret = netlink_request (AF_PACKET, RTM_GETLINK, &zns->netlink_cmd);
   if (ret < 0)
     return ret;
-  ret = netlink_parse_info (netlink_interface, &zns->netlink_cmd, zns, 0);
+  ret = netlink_parse_info (netlink_interface, &zns->netlink_cmd, zns, 0, 1);
   if (ret < 0)
     return ret;
 
@@ -411,7 +411,7 @@ interface_lookup_netlink (struct zebra_ns *zns)
   ret = netlink_request (AF_INET, RTM_GETADDR, &zns->netlink_cmd);
   if (ret < 0)
     return ret;
-  ret = netlink_parse_info (netlink_interface_addr, &zns->netlink_cmd, zns, 0);
+  ret = netlink_parse_info (netlink_interface_addr, &zns->netlink_cmd, zns, 0, 1);
   if (ret < 0)
     return ret;
 
@@ -419,7 +419,7 @@ interface_lookup_netlink (struct zebra_ns *zns)
   ret = netlink_request (AF_INET6, RTM_GETADDR, &zns->netlink_cmd);
   if (ret < 0)
     return ret;
-  ret = netlink_parse_info (netlink_interface_addr, &zns->netlink_cmd, zns, 0);
+  ret = netlink_parse_info (netlink_interface_addr, &zns->netlink_cmd, zns, 0, 1);
   if (ret < 0)
     return ret;
 
@@ -475,7 +475,7 @@ netlink_address (int cmd, int family, struct interface *ifp,
     addattr_l (&req.n, sizeof req, IFA_LABEL, ifc->label,
                strlen (ifc->label) + 1);
 
-  return netlink_talk (netlink_talk_filter, &req.n, &zns->netlink_cmd, zns);
+  return netlink_talk (netlink_talk_filter, &req.n, &zns->netlink_cmd, zns, 0);
 }
 
 int
@@ -492,7 +492,7 @@ kernel_address_delete_ipv4 (struct interface *ifp, struct connected *ifc)
 
 int
 netlink_interface_addr (struct sockaddr_nl *snl, struct nlmsghdr *h,
-                        ns_id_t ns_id)
+                        ns_id_t ns_id, int startup)
 {
   int len;
   struct ifaddrmsg *ifa;
@@ -630,7 +630,7 @@ netlink_interface_addr (struct sockaddr_nl *snl, struct nlmsghdr *h,
 
 int
 netlink_link_change (struct sockaddr_nl *snl, struct nlmsghdr *h,
-                     ns_id_t ns_id)
+                     ns_id_t ns_id, int startup)
 {
   int len;
   struct ifinfomsg *ifi;
index aac67916c034986a7382915617c0f49c3dceeb4d..6fa39ccab24ee9b53b5a184797d8f94a5983167e 100644 (file)
@@ -25,9 +25,9 @@
 #ifdef HAVE_NETLINK
 
 extern int netlink_interface_addr (struct sockaddr_nl *snl,
-                                   struct nlmsghdr *h, ns_id_t ns_id);
+                                   struct nlmsghdr *h, ns_id_t ns_id, int startup);
 extern int netlink_link_change (struct sockaddr_nl *snl, struct nlmsghdr *h,
-                                ns_id_t ns_id);
+                                ns_id_t ns_id, int startup);
 extern int interface_lookup_netlink (struct zebra_ns *zns);
 
 #endif /* HAVE_NETLINK */
index 058d14481e979a0ab693a66a8c30ebfc9f2e5c21..c9c2d90eac399f8e303b3909bea01fa0cfa20081 100644 (file)
@@ -125,7 +125,7 @@ extern struct zebra_privs_t zserv_privs;
 
 int
 netlink_talk_filter (struct sockaddr_nl *snl, struct nlmsghdr *h,
-    ns_id_t ns_id)
+                     ns_id_t ns_id, int startup)
 {
   zlog_warn ("netlink_talk: ignoring message type 0x%04x NS %u", h->nlmsg_type,
              ns_id);
@@ -239,7 +239,7 @@ netlink_socket (struct nlsock *nl, unsigned long groups, ns_id_t ns_id)
 
 static int
 netlink_information_fetch (struct sockaddr_nl *snl, struct nlmsghdr *h,
-    ns_id_t ns_id)
+                           ns_id_t ns_id, int startup)
 {
   /* JF: Ignore messages that aren't from the kernel */
   if ( snl->nl_pid != 0 )
@@ -251,22 +251,22 @@ netlink_information_fetch (struct sockaddr_nl *snl, struct nlmsghdr *h,
   switch (h->nlmsg_type)
     {
     case RTM_NEWROUTE:
-      return netlink_route_change (snl, h, ns_id);
+      return netlink_route_change (snl, h, ns_id, startup);
       break;
     case RTM_DELROUTE:
-      return netlink_route_change (snl, h, ns_id);
+      return netlink_route_change (snl, h, ns_id, startup);
       break;
     case RTM_NEWLINK:
-      return netlink_link_change (snl, h, ns_id);
+      return netlink_link_change (snl, h, ns_id, startup);
       break;
     case RTM_DELLINK:
-      return netlink_link_change (snl, h, ns_id);
+      return netlink_link_change (snl, h, ns_id, startup);
       break;
     case RTM_NEWADDR:
-      return netlink_interface_addr (snl, h, ns_id);
+      return netlink_interface_addr (snl, h, ns_id, startup);
       break;
     case RTM_DELADDR:
-      return netlink_interface_addr (snl, h, ns_id);
+      return netlink_interface_addr (snl, h, ns_id, startup);
       break;
     default:
       zlog_warn ("Unknown netlink nlmsg_type %d vrf %u\n", h->nlmsg_type,
@@ -280,7 +280,7 @@ static int
 kernel_read (struct thread *thread)
 {
   struct zebra_ns *zns = (struct zebra_ns *)THREAD_ARG (thread);
-  netlink_parse_info (netlink_information_fetch, &zns->netlink, zns, 5);
+  netlink_parse_info (netlink_information_fetch, &zns->netlink, zns, 5, 0);
   zns->t_netlink = thread_add_read (zebrad.master, kernel_read, zns,
                                      zns->netlink.sock);
 
@@ -444,12 +444,23 @@ nl_rttype_to_str (u_char rttype)
   return lookup (rttype_str, rttype);
 }
 
-/* Receive message from netlink interface and pass those information
-   to the given function. */
+/*
+ * netlink_parse_info
+ *
+ * Receive message from netlink interface and pass those information
+ *  to the given function.
+ *
+ * filter  -> Function to call to read the results
+ * nl      -> netlink socket information
+ * zns     -> The zebra namespace data
+ * count   -> How many we should read in, 0 means as much as possible
+ * startup -> Are we reading in under startup conditions? passed to
+ *            the filter.
+ */
 int
 netlink_parse_info (int (*filter) (struct sockaddr_nl *, struct nlmsghdr *,
-                                   ns_id_t),
-                    struct nlsock *nl, struct zebra_ns *zns, int count)
+                                   ns_id_t, int),
+                    struct nlsock *nl, struct zebra_ns *zns, int count, int startup)
 {
   int status;
   int ret = 0;
@@ -613,7 +624,7 @@ netlink_parse_info (int (*filter) (struct sockaddr_nl *, struct nlmsghdr *,
               continue;
             }
 
-          error = (*filter) (&snl, h, zns->ns_id);
+          error = (*filter) (&snl, h, zns->ns_id, startup);
           if (error < 0)
             {
               zlog (NULL, LOG_ERR, "%s filter function error", nl->name);
@@ -637,11 +648,23 @@ netlink_parse_info (int (*filter) (struct sockaddr_nl *, struct nlmsghdr *,
   return ret;
 }
 
-/* sendmsg() to netlink socket then recvmsg(). */
+/*
+ * netlink_talk
+ *
+ * sendmsg() to netlink socket then recvmsg().
+ * Calls netlink_parse_info to parse returned data
+ *
+ * filter   -> The filter to read final results from kernel
+ * nlmsghdr -> The data to send to the kernel
+ * nl       -> The netlink socket information
+ * zns      -> The zebra namespace information
+ * startup  -> Are we reading in under startup conditions
+ *             This is passed through eventually to filter.
+ */
 int
 netlink_talk (int (*filter) (struct sockaddr_nl *, struct nlmsghdr *,
-                            ns_id_t),
-             struct nlmsghdr *n, struct nlsock *nl, struct zebra_ns *zns)
+                             ns_id_t, int startup),
+              struct nlmsghdr *n, struct nlsock *nl, struct zebra_ns *zns, int startup)
 {
   int status;
   struct sockaddr_nl snl;
@@ -697,7 +720,7 @@ netlink_talk (int (*filter) (struct sockaddr_nl *, struct nlmsghdr *,
    * Get reply from netlink socket.
    * The reply should either be an acknowlegement or an error.
    */
-  return netlink_parse_info (filter, nl, zns, 0);
+  return netlink_parse_info (filter, nl, zns, 0, startup);
 }
 
 /* Get type specified information from netlink. */
index f17f1380c25c3aaf6ba59f20e771bd00dabdd3fc..adbcf71f636fa7c3607de14c66c33cb652792a4f 100644 (file)
@@ -44,14 +44,15 @@ extern const char * nl_family_to_str (u_char family);
 extern const char * nl_rttype_to_str (u_char rttype);
 
 extern int netlink_parse_info (int (*filter) (struct sockaddr_nl *,
-                               struct nlmsghdr *, ns_id_t), struct nlsock *nl,
-                               struct zebra_ns *zns, int count);
+                                              struct nlmsghdr *, ns_id_t, int),
+                               struct nlsock *nl, struct zebra_ns *zns,
+                               int count, int startup);
 extern int netlink_talk_filter (struct sockaddr_nl *, struct nlmsghdr *,
-                               ns_id_t);
+                               ns_id_t, int startup);
 extern int netlink_talk (int (*filter) (struct sockaddr_nl *, struct nlmsghdr *,
-                                       ns_id_t),
+                                       ns_id_t, int startup),
                         struct nlmsghdr *n, struct nlsock *nl,
-                         struct zebra_ns *zns);
+                         struct zebra_ns *zns, int startup);
 extern int netlink_request (int family, int type, struct nlsock *nl);
 
 #endif /* HAVE_NETLINK */
index d88dc05b2875b531ee62f33d17c0fd4f894b235b..450e15e0f7b6a625471daebaae2e2e9b68c55574 100644 (file)
@@ -126,8 +126,8 @@ vrf_lookup_by_table (u_int32_t table_id)
 
 /* Looking up routing table by netlink interface. */
 static int
-netlink_routing_table (struct sockaddr_nl *snl, struct nlmsghdr *h,
-                       ns_id_t ns_id)
+netlink_route_change_read_unicast (struct sockaddr_nl *snl, struct nlmsghdr *h,
+                                   ns_id_t ns_id, int startup)
 {
   int len;
   struct rtmsg *rtm;
@@ -151,9 +151,9 @@ netlink_routing_table (struct sockaddr_nl *snl, struct nlmsghdr *h,
 
   rtm = NLMSG_DATA (h);
 
-  if (h->nlmsg_type != RTM_NEWROUTE)
+  if (startup && h->nlmsg_type != RTM_NEWROUTE)
     return 0;
-  if (rtm->rtm_type != RTN_UNICAST)
+  if (startup && rtm->rtm_type != RTN_UNICAST)
     return 0;
 
   len = h->nlmsg_len - NLMSG_LENGTH (sizeof (struct rtmsg));
@@ -170,6 +170,11 @@ netlink_routing_table (struct sockaddr_nl *snl, struct nlmsghdr *h,
   if (rtm->rtm_protocol == RTPROT_KERNEL)
     return 0;
 
+  if (!startup &&
+      rtm->rtm_protocol == RTPROT_ZEBRA &&
+      h->nlmsg_type == RTM_NEWROUTE)
+    return 0;
+
   /* We don't care about change notifications for the MPLS table. */
   /* TODO: Revisit this. */
   if (rtm->rtm_family == AF_MPLS)
@@ -213,19 +218,22 @@ netlink_routing_table (struct sockaddr_nl *snl, struct nlmsghdr *h,
   if (tb[RTA_GATEWAY])
     gate = RTA_DATA (tb[RTA_GATEWAY]);
 
-  if (tb[RTA_PRIORITY])
-    metric = *(int *) RTA_DATA(tb[RTA_PRIORITY]);
-
-  if (tb[RTA_METRICS])
+  if (h->nlmsg_type == RTM_NEWROUTE)
     {
-      struct rtattr *mxrta[RTAX_MAX+1];
+      if (tb[RTA_PRIORITY])
+        metric = *(int *) RTA_DATA(tb[RTA_PRIORITY]);
 
-      memset (mxrta, 0, sizeof mxrta);
-      netlink_parse_rtattr (mxrta, RTAX_MAX, RTA_DATA(tb[RTA_METRICS]),
-                            RTA_PAYLOAD(tb[RTA_METRICS]));
+      if (tb[RTA_METRICS])
+        {
+          struct rtattr *mxrta[RTAX_MAX+1];
+
+          memset (mxrta, 0, sizeof mxrta);
+          netlink_parse_rtattr (mxrta, RTAX_MAX, RTA_DATA(tb[RTA_METRICS]),
+                                RTA_PAYLOAD(tb[RTA_METRICS]));
 
-      if (mxrta[RTAX_MTU])
-        mtu = *(u_int32_t *) RTA_DATA(mxrta[RTAX_MTU]);
+          if (mxrta[RTAX_MTU])
+            mtu = *(u_int32_t *) RTA_DATA(mxrta[RTAX_MTU]);
+        }
     }
 
   if (rtm->rtm_family == AF_INET)
@@ -233,14 +241,48 @@ netlink_routing_table (struct sockaddr_nl *snl, struct nlmsghdr *h,
       p.family = AF_INET;
       memcpy (&p.u.prefix4, dest, 4);
       p.prefixlen = rtm->rtm_dst_len;
+    }
+  else if (rtm->rtm_family == AF_INET6)
+    {
+      p.family = AF_INET6;
+      memcpy (&p.u.prefix6, dest, 16);
+      p.prefixlen = rtm->rtm_dst_len;
+
+      src_p.family = AF_INET6;
+      memcpy (&src_p.prefix, src, 16);
+      src_p.prefixlen = rtm->rtm_src_len;
+    }
 
-      if (rtm->rtm_src_len != 0)
-       return 0;
+  if (rtm->rtm_src_len != 0)
+    {
+      char buf[PREFIX_STRLEN];
+      zlog_warn ("unsupported IPv[4|6] sourcedest route (dest %s vrf %u)",
+                 prefix2str (&p, buf, sizeof(buf)), vrf_id);
+      return 0;
+    }
+
+  if (IS_ZEBRA_DEBUG_KERNEL)
+    {
+      char buf[PREFIX_STRLEN];
+      char buf2[PREFIX_STRLEN];
+      zlog_debug ("%s %s%s%s vrf %u",
+                  nl_msg_type_to_str (h->nlmsg_type),
+                  prefix2str (&p, buf, sizeof(buf)),
+                  src_p.prefixlen ? " from " : "",
+                  src_p.prefixlen ? prefix2str(&src_p, buf2, sizeof(buf2)) : "",
+                  vrf_id);
+    }
+
+  afi_t afi = AFI_IP;
+  if (rtm->rtm_family == AF_INET6)
+    afi = AFI_IP6;
 
+  if (h->nlmsg_type == RTM_NEWROUTE)
+    {
       if (!tb[RTA_MULTIPATH])
-       rib_add (AFI_IP, SAFI_UNICAST, vrf_id, ZEBRA_ROUTE_KERNEL,
-                0, flags, &p, NULL, gate, prefsrc, index,
-                table, metric, mtu, 0);
+        rib_add (afi, SAFI_UNICAST, vrf_id, ZEBRA_ROUTE_KERNEL,
+                 0, flags, &p, NULL, gate, prefsrc, index,
+                 table, metric, mtu, 0);
       else
         {
           /* This is a multipath route */
@@ -280,10 +322,20 @@ netlink_routing_table (struct sockaddr_nl *snl, struct nlmsghdr *h,
 
               if (gate)
                 {
-                  if (index)
-                    rib_nexthop_ipv4_ifindex_add (rib, gate, prefsrc, index);
-                  else
-                    rib_nexthop_ipv4_add (rib, gate, prefsrc);
+                  if (rtm->rtm_family == AF_INET)
+                    {
+                      if (index)
+                        rib_nexthop_ipv4_ifindex_add (rib, gate, prefsrc, index);
+                      else
+                        rib_nexthop_ipv4_add (rib, gate, prefsrc);
+                    }
+                  else if (rtm->rtm_family == AF_INET6)
+                    {
+                      if (index)
+                        rib_nexthop_ipv6_ifindex_add (rib, gate, index);
+                      else
+                        rib_nexthop_ipv6_add (rib,gate);
+                    }
                 }
               else
                 rib_nexthop_ifindex_add (rib, index);
@@ -292,250 +344,49 @@ netlink_routing_table (struct sockaddr_nl *snl, struct nlmsghdr *h,
               rtnh = RTNH_NEXT(rtnh);
             }
 
-         zserv_nexthop_num_warn(__func__, (const struct prefix *)&p,
-                                rib->nexthop_num);
+          zserv_nexthop_num_warn(__func__, (const struct prefix *)&p,
+                                 rib->nexthop_num);
           if (rib->nexthop_num == 0)
             XFREE (MTYPE_RIB, rib);
           else
             rib_add_multipath (AFI_IP, SAFI_UNICAST, &p, NULL, rib);
         }
     }
-  if (rtm->rtm_family == AF_INET6)
-    {
-      p.family = AF_INET6;
-      memcpy (&p.u.prefix6, dest, 16);
-      p.prefixlen = rtm->rtm_dst_len;
-
-      src_p.family = AF_INET6;
-      memcpy (&src_p.prefix, src, 16);
-      src_p.prefixlen = rtm->rtm_src_len;
-
-      rib_add (AFI_IP6, SAFI_UNICAST, vrf_id, ZEBRA_ROUTE_KERNEL,
-               0, flags, &p, &src_p, gate, prefsrc, index,
-              table, metric, mtu, 0);
-    }
-
-  return 0;
-}
-
-/* Routing information change from the kernel. */
-static int
-netlink_route_change_read_unicast (struct sockaddr_nl *snl, struct nlmsghdr *h,
-                      ns_id_t ns_id)
-{
-  int len;
-  struct rtmsg *rtm;
-  struct rtattr *tb[RTA_MAX + 1];
-  u_char zebra_flags = 0;
-  struct prefix p;
-  vrf_id_t vrf_id = VRF_DEFAULT;
-  char anyaddr[16] = { 0 };
-
-  int index = 0;
-  int table;
-  int metric = 0;
-  u_int32_t mtu = 0;
-
-  void *dest = NULL;
-  void *gate = NULL;
-  void *prefsrc = NULL;                /* IPv4 preferred source host address */
-  void *src = NULL;            /* IPv6 srcdest   source prefix */
-
-  rtm = NLMSG_DATA (h);
-
-  len = h->nlmsg_len - NLMSG_LENGTH (sizeof (struct rtmsg));
-
-  memset (tb, 0, sizeof tb);
-  netlink_parse_rtattr (tb, RTA_MAX, RTM_RTA (rtm), len);
-
-  if (rtm->rtm_flags & RTM_F_CLONED)
-    return 0;
-  if (rtm->rtm_protocol == RTPROT_REDIRECT)
-    return 0;
-  if (rtm->rtm_protocol == RTPROT_KERNEL)
-    return 0;
-
-  if (rtm->rtm_protocol == RTPROT_ZEBRA && h->nlmsg_type == RTM_NEWROUTE)
-    return 0;
-  if (rtm->rtm_protocol == RTPROT_ZEBRA)
-    SET_FLAG(zebra_flags, ZEBRA_FLAG_SELFROUTE);
-
-  /* Table corresponding to route. */
-  if (tb[RTA_TABLE])
-    table = *(int *) RTA_DATA (tb[RTA_TABLE]);
   else
-    table = rtm->rtm_table;
-
-  /* Map to VRF */
-  vrf_id = vrf_lookup_by_table(table);
-  if (vrf_id == VRF_DEFAULT)
     {
-      if (!is_zebra_valid_kernel_table(table) &&
-          !is_zebra_main_routing_table(table))
-        return 0;
-    }
-
-  if (tb[RTA_OIF])
-    index = *(int *) RTA_DATA (tb[RTA_OIF]);
-
-  if (tb[RTA_DST])
-    dest = RTA_DATA (tb[RTA_DST]);
-  else
-    dest = anyaddr;
-
-  if (tb[RTA_SRC])
-    src = RTA_DATA (tb[RTA_SRC]);
-  else
-    src = anyaddr;
-
-  if (tb[RTA_GATEWAY])
-    gate = RTA_DATA (tb[RTA_GATEWAY]);
-
-  if (tb[RTA_PREFSRC])
-    prefsrc = RTA_DATA (tb[RTA_PREFSRC]);
-
-  if (h->nlmsg_type == RTM_NEWROUTE)
-    {
-      if (tb[RTA_PRIORITY])
-        metric = *(int *) RTA_DATA(tb[RTA_PRIORITY]);
-
-      if (tb[RTA_METRICS])
+      if (!tb[RTA_MULTIPATH])
+        rib_delete (afi, SAFI_UNICAST, vrf_id, ZEBRA_ROUTE_KERNEL, 0, flags,
+                    &p, NULL, gate, index, table);
+      else
         {
-          struct rtattr *mxrta[RTAX_MAX+1];
-
-          memset (mxrta, 0, sizeof mxrta);
-          netlink_parse_rtattr (mxrta, RTAX_MAX, RTA_DATA(tb[RTA_METRICS]),
-                                RTA_PAYLOAD(tb[RTA_METRICS]));
-
-          if (mxrta[RTAX_MTU])
-            mtu = *(u_int32_t *) RTA_DATA(mxrta[RTAX_MTU]);
-        }
-    }
-
-  if (rtm->rtm_family == AF_INET)
-    {
-      p.family = AF_INET;
-      memcpy (&p.u.prefix4, dest, 4);
-      p.prefixlen = rtm->rtm_dst_len;
-
-      if (rtm->rtm_src_len != 0)
-       {
-         zlog_warn ("unsupported IPv4 sourcedest route (dest %s/%d)",
-                    inet_ntoa (p.u.prefix4), p.prefixlen);
-         return 0;
-       }
+          struct rtnexthop *rtnh =
+            (struct rtnexthop *) RTA_DATA (tb[RTA_MULTIPATH]);
 
-      if (IS_ZEBRA_DEBUG_KERNEL)
-        {
-          char buf[PREFIX_STRLEN];
-          zlog_debug ("%s %s vrf %u",
-                      nl_msg_type_to_str (h->nlmsg_type),
-                      prefix2str (&p, buf, sizeof(buf)), vrf_id);
-        }
+          len = RTA_PAYLOAD (tb[RTA_MULTIPATH]);
 
-      if (h->nlmsg_type == RTM_NEWROUTE)
-        {
-          if (!tb[RTA_MULTIPATH])
-            rib_add (AFI_IP, SAFI_UNICAST, vrf_id, ZEBRA_ROUTE_KERNEL,
-                     0, 0, &p, NULL, gate, prefsrc, index,
-                     table, metric, mtu, 0);
-          else
+          for (;;)
             {
-              /* This is a multipath route */
-
-              struct rib *rib;
-              struct rtnexthop *rtnh =
-                (struct rtnexthop *) RTA_DATA (tb[RTA_MULTIPATH]);
-
-              len = RTA_PAYLOAD (tb[RTA_MULTIPATH]);
-
-              rib = XCALLOC (MTYPE_RIB, sizeof (struct rib));
-              rib->type = ZEBRA_ROUTE_KERNEL;
-              rib->distance = 0;
-              rib->flags = 0;
-              rib->metric = metric;
-              rib->mtu = mtu;
-              rib->vrf_id = vrf_id;
-              rib->table = table;
-              rib->nexthop_num = 0;
-              rib->uptime = time (NULL);
-
-              for (;;)
-                {
-                  if (len < (int) sizeof (*rtnh) || rtnh->rtnh_len > len)
-                    break;
-
-                  index = rtnh->rtnh_ifindex;
-                  gate = 0;
-                  if (rtnh->rtnh_len > sizeof (*rtnh))
-                    {
-                      memset (tb, 0, sizeof (tb));
-                      netlink_parse_rtattr (tb, RTA_MAX, RTNH_DATA (rtnh),
-                                            rtnh->rtnh_len - sizeof (*rtnh));
-                      if (tb[RTA_GATEWAY])
-                        gate = RTA_DATA (tb[RTA_GATEWAY]);
-                    }
-
-                  if (gate)
-                    {
-                      if (index)
-                        rib_nexthop_ipv4_ifindex_add (rib, gate, prefsrc, index);
-                      else
-                        rib_nexthop_ipv4_add (rib, gate, prefsrc);
-                    }
-                  else
-                    rib_nexthop_ifindex_add (rib, index);
+              if (len < (int) sizeof (*rtnh) || rtnh->rtnh_len > len)
+                break;
 
-                  len -= NLMSG_ALIGN(rtnh->rtnh_len);
-                  rtnh = RTNH_NEXT(rtnh);
+              gate = NULL;
+              if (rtnh->rtnh_len > sizeof (*rtnh))
+                {
+                  memset (tb, 0, sizeof (tb));
+                  netlink_parse_rtattr (tb, RTA_MAX, RTNH_DATA (rtnh),
+                                        rtnh->rtnh_len - sizeof (*rtnh));
+                  if (tb[RTA_GATEWAY])
+                    gate = RTA_DATA (tb[RTA_GATEWAY]);
                 }
 
-             zserv_nexthop_num_warn(__func__, (const struct prefix *)&p,
-                                    rib->nexthop_num);
+              if (gate)
+                rib_delete (afi, SAFI_UNICAST, vrf_id, ZEBRA_ROUTE_KERNEL, 0, flags,
+                            &p, NULL, gate, index, table);
 
-              if (rib->nexthop_num == 0)
-                XFREE (MTYPE_RIB, rib);
-              else
-                rib_add_multipath (AFI_IP, SAFI_UNICAST, &p, NULL, rib);
+              len -= NLMSG_ALIGN(rtnh->rtnh_len);
+              rtnh = RTNH_NEXT(rtnh);
             }
         }
-      else
-        rib_delete (AFI_IP, SAFI_UNICAST, vrf_id, ZEBRA_ROUTE_KERNEL, 0, zebra_flags,
-                   &p, NULL, gate, index, table);
-    }
-
-  if (rtm->rtm_family == AF_INET6)
-    {
-      struct prefix p;
-      struct prefix_ipv6 src_p;
-
-      p.family = AF_INET6;
-      memcpy (&p.u.prefix6, dest, 16);
-      p.prefixlen = rtm->rtm_dst_len;
-
-      src_p.family = AF_INET6;
-      memcpy (&src_p.prefix, src, 16);
-      src_p.prefixlen = rtm->rtm_src_len;
-
-      if (IS_ZEBRA_DEBUG_KERNEL)
-        {
-         char buf[PREFIX_STRLEN];
-         char buf2[PREFIX_STRLEN];
-          zlog_debug ("%s %s%s%s vrf %u",
-                      nl_msg_type_to_str (h->nlmsg_type),
-                      prefix2str (&p, buf, sizeof(buf)),
-                      src_p.prefixlen ? " from " : "",
-                      src_p.prefixlen ? prefix2str(&src_p, buf2, sizeof(buf2)) : "",
-                      vrf_id);
-        }
-
-      if (h->nlmsg_type == RTM_NEWROUTE)
-        rib_add (AFI_IP6, SAFI_UNICAST, vrf_id, ZEBRA_ROUTE_KERNEL,
-                0, 0, &p, &src_p, gate, prefsrc, index,
-                table, metric, mtu, 0);
-      else
-        rib_delete (AFI_IP6, SAFI_UNICAST, vrf_id, ZEBRA_ROUTE_KERNEL,
-                   0, zebra_flags, &p, &src_p, gate, index, table);
     }
 
   return 0;
@@ -545,7 +396,7 @@ static struct mcast_route_data *mroute = NULL;
 
 static int
 netlink_route_change_read_multicast (struct sockaddr_nl *snl, struct nlmsghdr *h,
-                                    ns_id_t ns_id)
+                                     ns_id_t ns_id, int startup)
 {
   int len;
   struct rtmsg *rtm;
@@ -629,7 +480,7 @@ netlink_route_change_read_multicast (struct sockaddr_nl *snl, struct nlmsghdr *h
 
 int
 netlink_route_change (struct sockaddr_nl *snl, struct nlmsghdr *h,
-                     ns_id_t ns_id)
+                     ns_id_t ns_id, int startup)
 {
   int len;
   vrf_id_t vrf_id = ns_id;
@@ -665,10 +516,10 @@ netlink_route_change (struct sockaddr_nl *snl, struct nlmsghdr *h,
   switch (rtm->rtm_type)
     {
     case RTN_UNICAST:
-      netlink_route_change_read_unicast (snl, h, ns_id);
+      netlink_route_change_read_unicast (snl, h, ns_id, startup);
       break;
     case RTN_MULTICAST:
-      netlink_route_change_read_multicast (snl, h, ns_id);
+      netlink_route_change_read_multicast (snl, h, ns_id, startup);
       break;
     default:
       return 0;
@@ -689,7 +540,7 @@ netlink_route_read (struct zebra_ns *zns)
   ret = netlink_request (AF_INET, RTM_GETROUTE, &zns->netlink_cmd);
   if (ret < 0)
     return ret;
-  ret = netlink_parse_info (netlink_routing_table, &zns->netlink_cmd, zns, 0);
+  ret = netlink_parse_info (netlink_route_change_read_unicast, &zns->netlink_cmd, zns, 0, 1);
   if (ret < 0)
     return ret;
 
@@ -697,7 +548,7 @@ netlink_route_read (struct zebra_ns *zns)
   ret = netlink_request (AF_INET6, RTM_GETROUTE, &zns->netlink_cmd);
   if (ret < 0)
     return ret;
-  ret = netlink_parse_info (netlink_routing_table, &zns->netlink_cmd, zns, 0);
+  ret = netlink_parse_info (netlink_route_change_read_unicast, &zns->netlink_cmd, zns, 0, 1);
   if (ret < 0)
     return ret;
 
@@ -1244,7 +1095,7 @@ netlink_neigh_update (int cmd, int ifindex, uint32_t addr, char *lla, int llalen
   addattr_l(&req.n, sizeof(req), NDA_DST, &addr, 4);
   addattr_l(&req.n, sizeof(req), NDA_LLADDR, lla, llalen);
 
-  return netlink_talk (netlink_talk_filter, &req.n, &zns->netlink_cmd, zns);
+  return netlink_talk (netlink_talk_filter, &req.n, &zns->netlink_cmd, zns, 0);
 }
 
 /* Routing table change via netlink interface. */
@@ -1542,7 +1393,7 @@ skip:
   snl.nl_family = AF_NETLINK;
 
   /* Talk to netlink socket. */
-  return netlink_talk (netlink_talk_filter, &req.n, &zns->netlink_cmd, zns);
+  return netlink_talk (netlink_talk_filter, &req.n, &zns->netlink_cmd, zns, 0);
 }
 
 int
@@ -1572,7 +1423,7 @@ kernel_get_ipmr_sg_stats (void *in)
   addattr_l (&req.n, sizeof (req), RTA_SRC, &mroute->sg.src.s_addr, 4);
   addattr_l (&req.n, sizeof (req), RTA_DST, &mroute->sg.grp.s_addr, 4);
 
-  suc = netlink_talk (netlink_route_change_read_multicast, &req.n, &zns->netlink_cmd, zns);
+  suc = netlink_talk (netlink_route_change_read_multicast, &req.n, &zns->netlink_cmd, zns, 0);
 
   mroute = NULL;
   return suc;
@@ -1766,7 +1617,7 @@ netlink_mpls_multipath (int cmd, zebra_lsp_t *lsp)
     }
 
   /* Talk to netlink socket. */
-  return netlink_talk (netlink_talk_filter, &req.n, &zns->netlink_cmd, zns);
+  return netlink_talk (netlink_talk_filter, &req.n, &zns->netlink_cmd, zns, 0);
 }
 
 /*
index 7183525fba6ec8c48052afb6893f78833233cdbb..93ee622e3530bcdc446f1f959eca7aad24801e13 100644 (file)
@@ -34,7 +34,7 @@ extern int
 netlink_mpls_multipath (int cmd, zebra_lsp_t *lsp);
 
 extern int netlink_route_change (struct sockaddr_nl *snl, struct nlmsghdr *h,
-                                 ns_id_t ns_id);
+                                 ns_id_t ns_id, int startup);
 extern int netlink_route_read (struct zebra_ns *zns);
 
 #endif /* HAVE_NETLINK */