<?xml version="1.0" encoding="UTF-8"?>
<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns="http://purl.org/rss/1.0/" xmlns:taxo="http://purl.org/rss/1.0/modules/taxonomy/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:syn="http://purl.org/rss/1.0/modules/syndication/" xmlns:admin="http://webns.net/mvcb/">
  <channel about="http://blog.gmane.org/gmane.network.quagga.devel">
    <title>gmane.network.quagga.devel</title>
    <link>http://blog.gmane.org/gmane.network.quagga.devel</link>
    <description/>
    <syn:updatePeriod>hourly</syn:updatePeriod>
    <syn:updateFrequency>1</syn:updateFrequency>
    <syn:updateBase>1901-01-01T00:00+00:00</syn:updateBase>
    <items>
      <rdf:Seq>
        <rdf:li rdf:resource="http://comments.gmane.org/gmane.network.quagga.devel/6242"/>
        <rdf:li rdf:resource="http://comments.gmane.org/gmane.network.quagga.devel/6234"/>
        <rdf:li rdf:resource="http://comments.gmane.org/gmane.network.quagga.devel/6195"/>
        <rdf:li rdf:resource="http://comments.gmane.org/gmane.network.quagga.devel/6165"/>
        <rdf:li rdf:resource="http://comments.gmane.org/gmane.network.quagga.devel/6162"/>
        <rdf:li rdf:resource="http://comments.gmane.org/gmane.network.quagga.devel/6161"/>
        <rdf:li rdf:resource="http://comments.gmane.org/gmane.network.quagga.devel/6156"/>
        <rdf:li rdf:resource="http://comments.gmane.org/gmane.network.quagga.devel/6142"/>
        <rdf:li rdf:resource="http://comments.gmane.org/gmane.network.quagga.devel/6124"/>
        <rdf:li rdf:resource="http://comments.gmane.org/gmane.network.quagga.devel/6123"/>
        <rdf:li rdf:resource="http://comments.gmane.org/gmane.network.quagga.devel/6122"/>
        <rdf:li rdf:resource="http://comments.gmane.org/gmane.network.quagga.devel/6121"/>
        <rdf:li rdf:resource="http://comments.gmane.org/gmane.network.quagga.devel/6115"/>
        <rdf:li rdf:resource="http://comments.gmane.org/gmane.network.quagga.devel/6110"/>
        <rdf:li rdf:resource="http://comments.gmane.org/gmane.network.quagga.devel/6107"/>
        <rdf:li rdf:resource="http://comments.gmane.org/gmane.network.quagga.devel/6104"/>
        <rdf:li rdf:resource="http://comments.gmane.org/gmane.network.quagga.devel/6101"/>
        <rdf:li rdf:resource="http://comments.gmane.org/gmane.network.quagga.devel/6093"/>
        <rdf:li rdf:resource="http://comments.gmane.org/gmane.network.quagga.devel/6092"/>
        <rdf:li rdf:resource="http://comments.gmane.org/gmane.network.quagga.devel/6091"/>
      </rdf:Seq>
    </items>
    <image rdf:resource="http://gmane.org/img/gmane-25t.png"/>
    <textinput rdf:resource=""/>
  </channel>
  <image rdf:about="http://gmane.org/img/gmane-25t.png">
    <title>Gmane</title>
    <url>http://gmane.org/img/gmane-25t.png</url>
    <link>http://gmane.org</link>
  </image>
  <item rdf:about="http://comments.gmane.org/gmane.network.quagga.devel/6242">
    <title>[quagga-dev 6253]  quagga &amp; mpls</title>
    <link>http://comments.gmane.org/gmane.network.quagga.devel/6242</link>
    <description></description>
    <dc:creator>Pali</dc:creator>
    <dc:date>2008-12-02T17:06:48</dc:date>
  </item>
  <item rdf:about="http://comments.gmane.org/gmane.network.quagga.devel/6234">
    <title>[quagga-dev 6228]  [PATCH 04/21] Mark assert() tests as unlikely</title>
    <link>http://comments.gmane.org/gmane.network.quagga.devel/6234</link>
    <description>This forces GCC compiler to generate the more common code on the
faster path.
---
 lib/zassert.h |   14 +++++++++++---
 1 files changed, 11 insertions(+), 3 deletions(-)

diff --git a/lib/zassert.h b/lib/zassert.h
index 7912676..123aee1 100644
--- a/lib/zassert.h
+++ b/lib/zassert.h
&lt; at &gt;&lt; at &gt; -17,9 +17,17 &lt; at &gt;&lt; at &gt; extern void _zlog_assert_failed (const char *assertion, const char *file,
 #define __ASSERT_FUNCTION    NULL
 #endif
 
-#define zassert(EX) ((void)((EX) ?  0 :\
-    (_zlog_assert_failed(#EX, __FILE__, __LINE__, \
- __ASSERT_FUNCTION), 0)))
+#ifdef __GNUC__
+#define UNLIKELY(EX)__builtin_expect(!!(EX), 0)
+#define LIKELY(EX)__builtin_expect(!!(EX), 1)
+#else
+#define UNLIKELY(EX)(EX)
+#define LIKELY(EX)(EX)
+#endif
+
+#define zassert(EX) ((void)(UNLIKELY(EX) ? 0 :\
+  (_zlog_assert_failed(#EX, __FILE__, __LINE__, \
+       __ASSERT_FUNCTION), 0)))
 
 #undef assert
 #define assert(EX) zassert(EX)
</description>
    <dc:creator>Stephen Hemminger</dc:creator>
    <dc:date>2008-08-08T22:33:16</dc:date>
  </item>
  <item rdf:about="http://comments.gmane.org/gmane.network.quagga.devel/6195">
    <title>[quagga-dev 6187]  patch: setsockopt SO_PRIORITY</title>
    <link>http://comments.gmane.org/gmane.network.quagga.devel/6195</link>
    <description>This patch permit to specify a value for setsockopt SO_PRIORITY, this 
can be quite useful in linux to select a specific traffic control queue 
discipline. I think that SO_PRIORITY is available only in linux and the 
code is inside #ifdef SO_PRIORITY (no autoconf stuff).

At the moment the code is implemented only for ospfd and ripd but should 
bit quite trivial to extend to other daemons.

-Francesco
Index: quagga/quagga/lib/sockopt.c
===================================================================
--- quagga.orig/quagga/lib/sockopt.c2008-11-11 16:55:13.000000000 +0100
+++ quagga/quagga/lib/sockopt.c2008-11-11 16:56:00.000000000 +0100
&lt; at &gt;&lt; at &gt; -376,6 +376,19 &lt; at &gt;&lt; at &gt;
   return ret;
 }
   
+int
+setsockopt_priority (int sock, int so_priority)
+{
+  int ret;
+
+  ret = setsockopt (sock, SOL_SOCKET, SO_PRIORITY, &amp;so_priority, sizeof (so_priority));
+  if (ret &lt; 0)
+    zlog_warn ("Can't set SO_PRIORITY option for fd %d to %#x: %s",
+       sock, so_priority, safe_strerror(errno));
+
+  return ret;
+}
+
 /*
  * Requires: msgh is not NULL and points to a valid struct msghdr, which
  * may or may not have control data about the incoming interface.
Index: quagga/quagga/lib/sockopt.h
===================================================================
--- quagga.orig/quagga/lib/sockopt.h2008-11-11 16:55:13.000000000 +0100
+++ quagga/quagga/lib/sockopt.h2008-11-11 16:56:00.000000000 +0100
&lt; at &gt;&lt; at &gt; -95,6 +95,8 &lt; at &gt;&lt; at &gt;
 extern int setsockopt_ifindex (int, int, int);
 extern int getsockopt_ifindex (int, struct msghdr *);
 
+extern int setsockopt_priority (int sock, int so_priority);
+
 /* swab the fields in iph between the host order and system order expected 
  * for IP_HDRINCL.
  */
Index: quagga/quagga/ospfd/ospf_main.c
===================================================================
--- quagga.orig/quagga/ospfd/ospf_main.c2008-11-11 16:55:13.000000000 +0100
+++ quagga/quagga/ospfd/ospf_main.c2008-11-11 16:56:00.000000000 +0100
&lt; at &gt;&lt; at &gt; -87,6 +87,9 &lt; at &gt;&lt; at &gt;
   { "vty_port",    required_argument, NULL, 'P'},
   { "user",        required_argument, NULL, 'u'},
   { "group",       required_argument, NULL, 'g'},
+#ifdef SO_PRIORITY
+  { "so_priority", required_argument, NULL, 'p'},
+#endif
   { "apiserver",   no_argument,       NULL, 'a'},
   { "version",     no_argument,       NULL, 'v'},
   { 0 }
&lt; at &gt;&lt; at &gt; -104,6 +107,10 &lt; at &gt;&lt; at &gt;
 extern int ospf_apiserver_enable;
 #endif /* SUPPORT_OSPF_API */
 
+#ifdef SO_PRIORITY
+int so_priority = 0;
+#endif
+
 /* Help information display. */
 static void __attribute__ ((noreturn))
 usage (char *progname, int status)
&lt; at &gt;&lt; at &gt; -112,21 +119,24 &lt; at &gt;&lt; at &gt;
     fprintf (stderr, "Try `%s --help' for more information.\n", progname);
   else
     {    
-      printf ("Usage : %s [OPTION...]\n\
-Daemon which manages OSPF.\n\n\
--d, --daemon       Runs in daemon mode\n\
--f, --config_file  Set configuration file name\n\
--i, --pid_file     Set process identifier file name\n\
--A, --vty_addr     Set vty's bind address\n\
--P, --vty_port     Set vty's port number\n\
--u, --user         User to run as\n\
--g, --group        Group to run as\n\
--a. --apiserver    Enable OSPF apiserver\n\
--v, --version      Print program version\n\
--C, --dryrun       Check configuration for validity and exit\n\
--h, --help         Display this help and exit\n\
-\n\
-Report bugs to %s\n", progname, ZEBRA_BUG_ADDRESS);
+      printf ("Usage : %s [OPTION...]\n"
+      "Daemon which manages OSPF.\n\n"
+      "-d, --daemon       Runs in daemon mode\n"
+      "-f, --config_file  Set configuration file name\n"
+      "-i, --pid_file     Set process identifier file name\n"
+      "-A, --vty_addr     Set vty's bind address\n"
+      "-P, --vty_port     Set vty's port number\n"
+      "-u, --user         User to run as\n"
+      "-g, --group        Group to run as\n"
+#ifdef SO_PRIORITY
+      "-p, --so_priority  Set socket priority\n"
+#endif
+      "-a, --apiserver    Enable OSPF apiserver\n"
+      "-v, --version      Print program version\n"
+      "-C, --dryrun       Check configuration for validity and exit\n"
+      "-h, --help         Display this help and exit\n"
+      "\n"
+      "Report bugs to %s\n", progname, ZEBRA_BUG_ADDRESS);
     }
   exit (status);
 }
&lt; at &gt;&lt; at &gt; -215,7 +225,7 &lt; at &gt;&lt; at &gt;
     {
       int opt;
 
-      opt = getopt_long (argc, argv, "dlf:i:hA:P:u:g:avC", longopts, 0);
+      opt = getopt_long (argc, argv, "dlf:i:hA:P:u:g:p:avC", longopts, 0);
     
       if (opt == EOF)
 break;
&lt; at &gt;&lt; at &gt; -259,6 +269,11 &lt; at &gt;&lt; at &gt;
   ospf_apiserver_enable = 1;
   break;
 #endif /* SUPPORT_OSPF_API */
+#ifdef SO_PRIORITY
+case 'p':
+  so_priority = atoi(optarg);
+  break;
+#endif /* SO_PRIORITY */
 case 'v':
   print_version (progname);
   exit (0);
Index: quagga/quagga/ospfd/ospf_network.c
===================================================================
--- quagga.orig/quagga/ospfd/ospf_network.c2008-11-11 16:55:13.000000000 +0100
+++ quagga/quagga/ospfd/ospf_network.c2008-11-14 10:17:37.000000000 +0100
&lt; at &gt;&lt; at &gt; -33,6 +33,10 &lt; at &gt;&lt; at &gt;
 
 extern struct zebra_privs_t ospfd_privs;
 
+#ifdef SO_PRIORITY
+extern int so_priority;
+#endif
+
 #include "ospfd/ospfd.h"
 #include "ospfd/ospf_network.h"
 #include "ospfd/ospf_interface.h"
&lt; at &gt;&lt; at &gt; -219,6 +223,13 &lt; at &gt;&lt; at &gt;
   if (ret &lt; 0)
      zlog_warn ("Can't set pktinfo option for fd %d", ospf_sock);
 
+#ifdef SO_PRIORITY
+  ret = setsockopt_priority (ospf_sock, so_priority);
+
+  if (ret &lt; 0)
+     zlog_warn ("Can't set so_priority option for fd %d", ospf_sock);
+#endif
+
   if (ospfd_privs.change (ZPRIVS_LOWER))
     {
       zlog_err ("ospf_sock_init: could not lower privs, %s",
Index: quagga/quagga/ripd/rip_main.c
===================================================================
--- quagga.orig/quagga/ripd/rip_main.c2008-11-14 10:58:25.000000000 +0100
+++ quagga/quagga/ripd/rip_main.c2008-11-14 11:16:39.000000000 +0100
&lt; at &gt;&lt; at &gt; -48,6 +48,9 &lt; at &gt;&lt; at &gt;
   { "retain",      no_argument,       NULL, 'r'},
   { "user",        required_argument, NULL, 'u'},
   { "group",       required_argument, NULL, 'g'},
+#ifdef SO_PRIORITY
+  { "so_priority", required_argument, NULL, 'p'},
+#endif
   { "version",     no_argument,       NULL, 'v'},
   { 0 }
 };
&lt; at &gt;&lt; at &gt; -90,6 +93,11 &lt; at &gt;&lt; at &gt;
 /* RIP VTY connection port. */
 int vty_port = RIP_VTY_PORT;
 
+/* RIP socket SO_PRIORITY */
+#ifdef SO_PRIORITY
+int so_priority = 0;
+#endif
+
 /* Master of threads. */
 struct thread_master *master;
 
&lt; at &gt;&lt; at &gt; -104,21 +112,24 &lt; at &gt;&lt; at &gt;
     fprintf (stderr, "Try `%s --help' for more information.\n", progname);
   else
     {    
-      printf ("Usage : %s [OPTION...]\n\
-Daemon which manages RIP version 1 and 2.\n\n\
--d, --daemon       Runs in daemon mode\n\
--f, --config_file  Set configuration file name\n\
--i, --pid_file     Set process identifier file name\n\
--A, --vty_addr     Set vty's bind address\n\
--P, --vty_port     Set vty's port number\n\
--C, --dryrun       Check configuration for validity and exit\n\
--r, --retain       When program terminates, retain added route by ripd.\n\
--u, --user         User to run as\n\
--g, --group        Group to run as\n\
--v, --version      Print program version\n\
--h, --help         Display this help and exit\n\
-\n\
-Report bugs to %s\n", progname, ZEBRA_BUG_ADDRESS);
+      printf ("Usage : %s [OPTION...]\n"
+      "Daemon which manages RIP version 1 and 2.\n\n"
+      "-d, --daemon       Runs in daemon mode\n"
+      "-f, --config_file  Set configuration file name\n"
+      "-i, --pid_file     Set process identifier file name\n"
+      "-A, --vty_addr     Set vty's bind address\n"
+      "-P, --vty_port     Set vty's port number\n"
+      "-C, --dryrun       Check configuration for validity and exit\n"
+      "-r, --retain       When program terminates, retain added route by ripd.\n"
+      "-u, --user         User to run as\n"
+      "-g, --group        Group to run as\n"
+#ifdef SO_PRIORITY
+      "-p, --so_priority  Set socket priority\n"
+#endif
+      "-v, --version      Print program version\n"
+      "-h, --help         Display this help and exit\n"
+      "\n"
+      "Report bugs to %s\n", progname, ZEBRA_BUG_ADDRESS);
     }
 
   exit (status);
&lt; at &gt;&lt; at &gt; -206,7 +217,7 &lt; at &gt;&lt; at &gt;
     {
       int opt;
 
-      opt = getopt_long (argc, argv, "df:i:hA:P:u:g:rvC", longopts, 0);
+      opt = getopt_long (argc, argv, "df:i:hA:P:u:g:p:rvC", longopts, 0);
     
       if (opt == EOF)
 break;
&lt; at &gt;&lt; at &gt; -251,6 +262,11 &lt; at &gt;&lt; at &gt;
 case 'g':
   ripd_privs.group = optarg;
   break;
+#ifdef SO_PRIORITY
+case 'p':
+  so_priority = atoi(optarg);
+  break;
+#endif /* SO_PRIORITY */
 case 'v':
   print_version (progname);
   exit (0);
Index: quagga/quagga/ripd/ripd.c
===================================================================
--- quagga.orig/quagga/ripd/ripd.c2008-11-14 10:58:36.000000000 +0100
+++ quagga/quagga/ripd/ripd.c2008-11-14 11:29:52.000000000 +0100
&lt; at &gt;&lt; at &gt; -50,6 +50,11 &lt; at &gt;&lt; at &gt;
 /* privileges global */
 extern struct zebra_privs_t ripd_privs;
 
+/* socket SO_PRIORITY global */
+#ifdef SO_PRIORITY
+extern int so_priority;
+#endif
+
 /* RIP Structure. */
 struct rip *rip = NULL;
 
&lt; at &gt;&lt; at &gt; -1380,6 +1385,13 &lt; at &gt;&lt; at &gt;
   if (ripd_privs.change (ZPRIVS_RAISE))
       zlog_err ("rip_create_socket: could not raise privs");
   setsockopt_so_recvbuf (sock, RIP_UDP_RCV_BUF);
+
+#ifdef SO_PRIORITY
+  ret = setsockopt_priority (sock, so_priority);
+  if (ret &lt; 0)
+     zlog_warn ("Can't set so_priority option for fd %d", sock);
+#endif
+
   if ( (ret = bind (sock, (struct sockaddr *) &amp; addr, sizeof (addr))) &lt; 0)
   
     {
</description>
    <dc:creator>Francesco Dolcini</dc:creator>
    <dc:date>2008-11-19T09:15:35</dc:date>
  </item>
  <item rdf:about="http://comments.gmane.org/gmane.network.quagga.devel/6165">
    <title>[quagga-dev 6157] OSPF: No host route when interface changes to~RUNNING</title>
    <link>http://comments.gmane.org/gmane.network.quagga.devel/6165</link>
    <description>Pulling the ethernet cable makes the interface change to ~RUNNING and
with link-detect enabled on said interface the whole subnet is
removed from OSPF.
I think this is a bit too much. A host route should remain for
that interface as the router can still be reached with the IP
address on this interface via other still functional links.

Comments?

 Jocke
</description>
    <dc:creator>Joakim Tjernlund</dc:creator>
    <dc:date>2008-11-18T08:47:25</dc:date>
  </item>
  <item rdf:about="http://comments.gmane.org/gmane.network.quagga.devel/6162">
    <title>[quagga-dev 6154] [PATCH] Fix removal of IPv4 route in ripd when aninterface goes down</title>
    <link>http://comments.gmane.org/gmane.network.quagga.devel/6162</link>
    <description>Hi,

While studying the ripd code I've found a potential problem (most probably
not triggering a real problem, at least on Linux.) When an interface goes
down and ripd tries to delete the corresponding route it errorneously
passes the interface's index instead of the metric to zebra.

Cheers,
Kris


rip_if_down() calls rip_zebra_ipv4_delete() with the interface index
passed instead of the metric.
---
 ripd/rip_interface.c |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/ripd/rip_interface.c b/ripd/rip_interface.c
index b6d9240..7c5577b 100644
--- a/ripd/rip_interface.c
+++ b/ripd/rip_interface.c
&lt; at &gt;&lt; at &gt; -591,7 +591,7 &lt; at &gt;&lt; at &gt; rip_if_down(struct interface *ifp)
       {
 rip_zebra_ipv4_delete ((struct prefix_ipv4 *) &amp;rp-&gt;p,
        &amp;rinfo-&gt;nexthop,
-       rinfo-&gt;ifindex);
+       rinfo-&gt;metric);
 
 rip_redistribute_delete (rinfo-&gt;type,rinfo-&gt;sub_type,
  (struct prefix_ipv4 *)&amp;rp-&gt;p,
</description>
    <dc:creator>Krisztian Kovacs</dc:creator>
    <dc:date>2008-11-17T16:36:20</dc:date>
  </item>
  <item rdf:about="http://comments.gmane.org/gmane.network.quagga.devel/6161">
    <title>[quagga-dev 6153]  Adding a host route for a non OSFP interface?</title>
    <link>http://comments.gmane.org/gmane.network.quagga.devel/6161</link>
    <description>I have tried to add a a host route for an interface that isn't part of
OSPF and I can't find a way to do it.

Making the interface passive will announce the whole subnet
the interface spans.
The ospf network X.X.X.X/32 area Y wont let me add it either
as it requires the masks to be the same.

So it seems Quagga OSPF is missing some way to do this.
How would one add this to OSPF? 
Extend network X.X.X.X/32 area Y to accept smaller subnets?
Add a new command? How should the syntax look like?

Note that the host route only requires the interface to be
UP, not RUNNING.

 Jocke
</description>
    <dc:creator>Joakim Tjernlund</dc:creator>
    <dc:date>2008-11-17T16:34:20</dc:date>
  </item>
  <item rdf:about="http://comments.gmane.org/gmane.network.quagga.devel/6156">
    <title>[quagga-dev 6148] Per-Prefix MRAI timer and path-damping in Quagga0.99.10</title>
    <link>http://comments.gmane.org/gmane.network.quagga.devel/6156</link>
    <description>Hi!

I'm proud to announce the first results of the BGP Heuristics Project at 
CAIA:
http://caia.swin.edu.au/urp/bgp/

I've implemented a per-prefix MRAI timer and Geoff Huston's path-damping
algorithm in Quagga 0.99.10
(http://www.potaroo.net/ispcol/2007-06/dampbgp.html)

The algorithm only works with the per prefix MRAI timer,
but you may also try the new timer only.

The patches for Quagga 0.99.10 can be found here:
http://caia.swin.edu.au/urp/bgp/tools.html

The implementations seem fairly stable, but have not been tested with 
fancy topologies and setups. Please feel free to report any bugs and 
concerns back to me.

I can also produce a patch for Quagga 0.99.11 if necessary.

Mat
</description>
    <dc:creator>Mattia Rossi</dc:creator>
    <dc:date>2008-11-17T01:26:03</dc:date>
  </item>
  <item rdf:about="http://comments.gmane.org/gmane.network.quagga.devel/6142">
    <title>[quagga-dev 6134] Strange check in bgp_open.c leads tointeroperability problem</title>
    <link>http://comments.gmane.org/gmane.network.quagga.devel/6142</link>
    <description>Hello

I found strange check in bgp_open.c:

  /* Check there is no common capability send Unsupported Capability
     error. */
  if (*capability &amp;&amp; ! CHECK_FLAG (peer-&gt;flags, PEER_FLAG_OVERRIDE_CAPABILITY))
    {
      if (! peer-&gt;afc_nego[AFI_IP][SAFI_UNICAST] 
          &amp;&amp; ! peer-&gt;afc_nego[AFI_IP][SAFI_MULTICAST]
          &amp;&amp; ! peer-&gt;afc_nego[AFI_IP][SAFI_MPLS_VPN]
          &amp;&amp; ! peer-&gt;afc_nego[AFI_IP6][SAFI_UNICAST]
          &amp;&amp; ! peer-&gt;afc_nego[AFI_IP6][SAFI_MULTICAST])


If BGP peer send capability list that does not contain multiprotocol
extensions, the connection is interrrupted. But when BGP peer does
not send any capability list, the connection is OK. Is there a reason
for that behavior? This creates interoperability problem with BGP
speakers that support some capabilities (for example AS4) but not
multiprotocol extensions.

</description>
    <dc:creator>Ondrej Zajicek</dc:creator>
    <dc:date>2008-11-16T15:10:12</dc:date>
  </item>
  <item rdf:about="http://comments.gmane.org/gmane.network.quagga.devel/6124">
    <title>[quagga-dev 6116]  [PATCH] [ospfd] Improve DR selection</title>
    <link>http://comments.gmane.org/gmane.network.quagga.devel/6124</link>
    <description>OSPF RFC Chap 9.4:
(4) If Router X is now newly the Designated Router or newly the
    Backup Designated Router, or is now no longer the Designated
    Router or no longer the Backup Designated Router, repeat
    steps 2 and 3, and then proceed to step 5.
This test was performed with the following test:
 if (new_state != old_state &amp;&amp;
     !(new_state == ISM_DROther &amp;&amp; old_state &lt; ISM_DROther))
Which can be rewritten to:
 if (new_state != old_state &amp;&amp;
     (new_state != ISM_DROther || old_state &gt;= ISM_DROther))
Now it is easy to se that this expression is true for more states
than (4) specifies, hint, try with old_state==ISM_DROther.
Fix with a new better if statement.
---
 ospfd/ospf_ism.c |    7 +++----
 1 files changed, 3 insertions(+), 4 deletions(-)

diff --git a/ospfd/ospf_ism.c b/ospfd/ospf_ism.c
index f215bfc..40f2cfb 100644
--- a/ospfd/ospf_ism.c
+++ b/ospfd/ospf_ism.c
&lt; at &gt;&lt; at &gt; -219,13 +219,12 &lt; at &gt;&lt; at &gt; ospf_dr_election (struct ospf_interface *oi)
   bdr = ospf_elect_bdr (oi, el_list);
   dr = ospf_elect_dr (oi, el_list);
 
-  new_state = ospf_ism_state (oi);
+  new_state = ospf_ism_state (oi); /* DR, Backup or DROther */
 
   zlog_info ("DR-Election[1st]: Backup %s", inet_ntoa (BDR (oi)));
   zlog_info ("DR-Election[1st]: DR     %s", inet_ntoa (DR (oi)));
-
-  if (new_state != old_state &amp;&amp;
-      !(new_state == ISM_DROther &amp;&amp; old_state &lt; ISM_DROther))
+  if (new_state != old_state &amp;&amp; new_state != ISM_DROther
+      &amp;&amp; (old_state == ISM_DR || old_state == ISM_Backup))
     {
       ospf_elect_bdr (oi, el_list);
       ospf_elect_dr (oi, el_list); 
</description>
    <dc:creator>Joakim Tjernlund</dc:creator>
    <dc:date>2008-11-14T16:36:02</dc:date>
  </item>
  <item rdf:about="http://comments.gmane.org/gmane.network.quagga.devel/6123">
    <title>[quagga-dev 6115] [PATCH] [ospfd] Optimize and improve SPF nexthopcalculation</title>
    <link>http://comments.gmane.org/gmane.network.quagga.devel/6123</link>
    <description>Maintain a table of OSPF interface pointers paralell
to the router LSA. Use the table in nexthop_calculation to
find the right OSPF interface for the nexthop.
This has the following advantages:
- Possible to have multiple PtP interfaces with the same
  IP address between two routers.
- Possible to use Unnumbered PtP on just one end of
  the link.
- No more seaching for the OSPF interface, hence much faster.
---

This is on top of my Unnumberd PtP patches.
Needs "[ospfd] Do not install received self-originated LSA" sent
earlier.

Comments welcome.

 Jocke

 ospfd/ospf_interface.c |    2 +
 ospfd/ospf_lsa.c       |   91 ++++++++++++++++++++++++++++--
 ospfd/ospf_lsa.h       |   12 ++++
 ospfd/ospf_spf.c       |  145 ++++++++++++++++++++++--------------------------
 4 files changed, 165 insertions(+), 85 deletions(-)

diff --git a/ospfd/ospf_interface.c b/ospfd/ospf_interface.c
index 98d7337..b7e2946 100644
--- a/ospfd/ospf_interface.c
+++ b/ospfd/ospf_interface.c
&lt; at &gt;&lt; at &gt; -335,6 +335,8 &lt; at &gt;&lt; at &gt; ospf_if_free (struct ospf_interface *oi)
   listnode_delete (oi-&gt;ospf-&gt;oiflist, oi);
   listnode_delete (oi-&gt;area-&gt;oiflist, oi);
 
+  ospf_oi_seq_if_delete(oi);
+
   memset (oi, 0, sizeof (*oi));
   XFREE (MTYPE_OSPF_IF, oi);
 }
diff --git a/ospfd/ospf_lsa.c b/ospfd/ospf_lsa.c
index c0db3e8..fc76c85 100644
--- a/ospfd/ospf_lsa.c
+++ b/ospfd/ospf_lsa.c
&lt; at &gt;&lt; at &gt; -242,6 +242,27 &lt; at &gt;&lt; at &gt; ospf_lsa_dup (struct ospf_lsa *lsa)
   return new;
 }
 
+static void
+ospf_lsa_oi_seq_free (struct lsa_oi_seq *oi_seq)
+{
+  XFREE (MTYPE_OSPF_LSA_DATA, oi_seq-&gt;seq_nr);
+  XFREE (MTYPE_OSPF_LSA_DATA, oi_seq);
+}
+
+void
+ospf_oi_seq_if_delete(struct ospf_interface *oi)
+{
+  int i;
+  struct ospf_lsa *lsa = oi-&gt;area-&gt;router_lsa_self;
+
+  if (!lsa || !lsa-&gt;oi_seq)
+    return;
+  /* "delete" all entries of oi */
+  for (i=0; i &lt; lsa-&gt;oi_seq-&gt;length/sizeof(seq_nr_t); i++)
+    if (lsa-&gt;oi_seq-&gt;seq_nr[i] == oi)
+      lsa-&gt;oi_seq-&gt;seq_nr[i] = NULL;
+}
+
 /* Free OSPF LSA. */
 void
 ospf_lsa_free (struct ospf_lsa *lsa)
&lt; at &gt;&lt; at &gt; -255,6 +276,8 &lt; at &gt;&lt; at &gt; ospf_lsa_free (struct ospf_lsa *lsa)
   if (lsa-&gt;data != NULL)
     ospf_lsa_data_free (lsa-&gt;data);
 
+  if (lsa-&gt;oi_seq != NULL)
+    ospf_lsa_oi_seq_free (lsa-&gt;oi_seq);
   assert (lsa-&gt;refresh_list &lt; 0);
 
   memset (lsa, 0, sizeof (struct ospf_lsa)); 
&lt; at &gt;&lt; at &gt; -312,6 +335,24 &lt; at &gt;&lt; at &gt; ospf_lsa_data_new (size_t size)
   return new;
 }
 
+static struct lsa_oi_seq *
+ospf_lsa_oi_seq_new (void)
+{
+  struct lsa_oi_seq *new;
+
+  new = XCALLOC (MTYPE_OSPF_LSA_DATA, sizeof(*new));
+  return new;
+}
+
+static seq_nr_t *
+ospf_lsa_oi_seq_data_new (size_t size)
+{
+  seq_nr_t *new;
+
+  new = XMALLOC (MTYPE_OSPF_LSA_DATA, size);
+  return new;
+}
+
 /* Duplicate LSA data. */
 struct lsa_header *
 ospf_lsa_data_dup (struct lsa_header *lsah)
&lt; at &gt;&lt; at &gt; -324,6 +365,18 &lt; at &gt;&lt; at &gt; ospf_lsa_data_dup (struct lsa_header *lsah)
   return new;
 }
 
+static void *
+ospf_lsa_oi_seq_dup (struct lsa_oi_seq *oi_seq)
+{
+  struct lsa_oi_seq *new;
+
+  new = ospf_lsa_oi_seq_new ();
+  new-&gt;length = oi_seq-&gt;length;
+  new-&gt;seq_nr = ospf_lsa_oi_seq_data_new (oi_seq-&gt;length);
+  memcpy (new-&gt;seq_nr, oi_seq-&gt;seq_nr, oi_seq-&gt;length);
+  return new;
+}
+
 /* Free LSA data. */
 void
 ospf_lsa_data_free (struct lsa_header *lsah)
&lt; at &gt;&lt; at &gt; -664,13 +717,24 &lt; at &gt;&lt; at &gt; lsa_link_ptomp_set (struct stream *s, struct ospf_interface *oi)
   return links;
 }
 
+struct ospf_interface *
+router_lsa_to_oi(struct ospf_lsa *lsa, int index)
+{
+  if (lsa-&gt;oi_seq &amp;&amp; index &gt;= 0)
+    return lsa-&gt;oi_seq-&gt;seq_nr[index];
+
+  zlog_debug ("%s: oi_seq:%p, index:%d!",
+      __func__, lsa-&gt;oi_seq, index);
+  return NULL;
+}
 /* Set router-LSA link information. */
 static int
-router_lsa_link_set (struct stream *s, struct ospf_area *area)
+router_lsa_link_set (struct stream *s, seq_nr_t oi_list[],
+     struct ospf_area *area)
 {
   struct listnode *node;
   struct ospf_interface *oi;
-  int links = 0;
+  int links = 0, old_links, i;
 
   for (ALL_LIST_ELEMENTS_RO (area-&gt;oiflist, node, oi))
     {
&lt; at &gt;&lt; at &gt; -681,6 +745,7 &lt; at &gt;&lt; at &gt; router_lsa_link_set (struct stream *s, struct ospf_area *area)
 {
   if (oi-&gt;state != ISM_Down)
     {
+      old_links = links;
       /* Describe each link. */
       switch (oi-&gt;type)
 {
&lt; at &gt;&lt; at &gt; -702,6 +767,8 &lt; at &gt;&lt; at &gt; router_lsa_link_set (struct stream *s, struct ospf_area *area)
 case OSPF_IFTYPE_LOOPBACK:
   links += lsa_link_loopback_set (s, oi); 
 }
+      for (i = old_links; i &lt; links; i++)
+oi_list[i] = oi;
     }
 }
     }
&lt; at &gt;&lt; at &gt; -710,8 +777,9 &lt; at &gt;&lt; at &gt; router_lsa_link_set (struct stream *s, struct ospf_area *area)
 }
 
 /* Set router-LSA body. */
-static void
-ospf_router_lsa_body_set (struct stream *s, struct ospf_area *area)
+static  u_int16_t
+ospf_router_lsa_body_set (struct stream *s, seq_nr_t oi_list[],
+  struct ospf_area *area)
 {
   unsigned long putp;
   u_int16_t cnt;
&lt; at &gt;&lt; at &gt; -729,10 +797,12 &lt; at &gt;&lt; at &gt; ospf_router_lsa_body_set (struct stream *s, struct ospf_area *area)
   stream_putw(s, 0);
 
   /* Set all link information. */
-  cnt = router_lsa_link_set (s, area);
+  cnt = router_lsa_link_set (s, oi_list, area);
 
   /* Set # of links here. */
   stream_putw_at (s, putp, cnt);
+
+  return cnt;
 }
 
 static int
&lt; at &gt;&lt; at &gt; -801,6 +871,9 &lt; at &gt;&lt; at &gt; ospf_router_lsa_new (struct ospf_area *area)
   struct lsa_header *lsah;
   struct ospf_lsa *new;
   int length;
+  u_int16_t cnt;
+ /* oi_list, less than 1KB, allocat on stack */
+  seq_nr_t oi_list[((OSPF_MAX_LSA_SIZE*2)/3)/sizeof(seq_nr_t)];
 
   if (IS_DEBUG_OSPF (lsa, LSA_GENERATE))
     zlog_debug ("LSA[Type1]: Create router-LSA instance");
&lt; at &gt;&lt; at &gt; -817,7 +890,8 &lt; at &gt;&lt; at &gt; ospf_router_lsa_new (struct ospf_area *area)
   OSPF_ROUTER_LSA, ospf-&gt;router_id, ospf-&gt;router_id);
 
   /* Set router-LSA body fields. */
-  ospf_router_lsa_body_set (s, area);
+  memset(oi_list, 0, sizeof(oi_list));
+  cnt = ospf_router_lsa_body_set (s, oi_list, area);
 
   /* Set length. */
   length = stream_get_endp (s);
&lt; at &gt;&lt; at &gt; -837,6 +911,11 &lt; at &gt;&lt; at &gt; ospf_router_lsa_new (struct ospf_area *area)
   /* Copy LSA data to store, discard stream. */
   new-&gt;data = ospf_lsa_data_new (length);
   memcpy (new-&gt;data, lsah, length);
+
+  new-&gt;oi_seq = ospf_lsa_oi_seq_new ();
+  new-&gt;oi_seq-&gt;length = cnt*sizeof(seq_nr_t);
+  new-&gt;oi_seq-&gt;seq_nr = ospf_lsa_oi_seq_data_new (new-&gt;oi_seq-&gt;length);
+  memcpy (new-&gt;oi_seq-&gt;seq_nr, oi_list, new-&gt;oi_seq-&gt;length);
   stream_free (s);
 
   return new;
diff --git a/ospfd/ospf_lsa.h b/ospfd/ospf_lsa.h
index 8dd054c..7bee1dc 100644
--- a/ospfd/ospf_lsa.h
+++ b/ospfd/ospf_lsa.h
&lt; at &gt;&lt; at &gt; -68,6 +68,13 &lt; at &gt;&lt; at &gt; struct lsa_header
   u_int16_t length;
 };
 
+#define seq_nr_t struct ospf_interface *
+/* Router LSA sequnce number list */
+struct lsa_oi_seq {
+  u_int16_t length;
+  seq_nr_t *seq_nr;
+};
+
 /* OSPF LSA. */
 struct ospf_lsa
 {
&lt; at &gt;&lt; at &gt; -84,6 +91,9 &lt; at &gt;&lt; at &gt; struct ospf_lsa
   /* LSA data. */
   struct lsa_header *data;
 
+  /* Router LSA OI sequence number */
+  struct lsa_oi_seq *oi_seq;
+
   /* Received time stamp. */
   struct timeval tv_recv;
 
&lt; at &gt;&lt; at &gt; -247,10 +257,12 &lt; at &gt;&lt; at &gt; extern void ospf_lsa_free (struct ospf_lsa *);
 extern struct ospf_lsa *ospf_lsa_lock (struct ospf_lsa *);
 extern void ospf_lsa_unlock (struct ospf_lsa **);
 extern void ospf_lsa_discard (struct ospf_lsa *);
+extern struct ospf_interface * router_lsa_to_oi(struct ospf_lsa *, int);
 
 extern struct lsa_header *ospf_lsa_data_new (size_t);
 extern struct lsa_header *ospf_lsa_data_dup (struct lsa_header *);
 extern void ospf_lsa_data_free (struct lsa_header *);
+extern void ospf_oi_seq_if_delete(struct ospf_interface *);
 
 /* Prototype for various LSAs */
 extern int ospf_router_lsa_update_timer (struct thread *);
diff --git a/ospfd/ospf_spf.c b/ospfd/ospf_spf.c
index 494eb5a..c02965a 100644
--- a/ospfd/ospf_spf.c
+++ b/ospfd/ospf_spf.c
&lt; at &gt;&lt; at &gt; -482,13 +482,16 &lt; at &gt;&lt; at &gt; ospf_spf_add_parent (struct vertex *v, struct vertex *w,
 static unsigned int
 ospf_nexthop_calculation (struct ospf_area *area, struct vertex *v,
                           struct vertex *w, struct router_lsa_link *l,
-                          unsigned int distance)
+                          unsigned int distance, int lsa_pos)
 {
   struct listnode *node, *nnode;
   struct vertex_nexthop *nh;
   struct vertex_parent *vp;
   struct ospf_interface *oi = NULL;
   unsigned int added = 0;
+  char buf1[BUFSIZ];
+  char buf2[BUFSIZ];
+
 
   if (IS_DEBUG_OSPF_EVENT)
     {
&lt; at &gt;&lt; at &gt; -507,24 +510,31 &lt; at &gt;&lt; at &gt; ospf_nexthop_calculation (struct ospf_area *area, struct vertex *v,
          the OSPF interface connecting to the destination network/router.
       */
 
+      /* we *must* be supplied with the link data */
+      assert (l != NULL);
+
+      oi = router_lsa_to_oi(area-&gt;router_lsa_self, lsa_pos);
+      if (!oi)
+{
+  zlog_err("%s: OI not found in LSA: lsa_pos:%d link_id:%s link_data:%s",
+   __func__, lsa_pos,
+   inet_ntop (AF_INET, &amp;l-&gt;link_id, buf1, BUFSIZ),
+   inet_ntop (AF_INET, &amp;l-&gt;link_data, buf2, BUFSIZ));
+  return 0;
+}
+
       if (w-&gt;type == OSPF_VERTEX_ROUTER)
         {
           /* l  is a link from v to w
            * l2 will be link from w to v
            */
           struct router_lsa_link *l2 = NULL;
-          
-          /* we *must* be supplied with the link data */
-          assert (l != NULL);
-          
+
           if (IS_DEBUG_OSPF_EVENT)
             {
-              char buf1[BUFSIZ];
-              char buf2[BUFSIZ];
-              
-              zlog_debug("ospf_nexthop_calculation(): considering link "
+              zlog_debug("%s: considering link "
                         "type %d link_id %s link_data %s",
-                        l-&gt;m[0].type,
+ __func__, l-&gt;m[0].type,
                         inet_ntop (AF_INET, &amp;l-&gt;link_id, buf1, BUFSIZ),
                         inet_ntop (AF_INET, &amp;l-&gt;link_data, buf2, BUFSIZ));
             }
&lt; at &gt;&lt; at &gt; -554,62 +564,35 &lt; at &gt;&lt; at &gt; ospf_nexthop_calculation (struct ospf_area *area, struct vertex *v,
                  is a constituent of the PtMP link, and its address is 
                  a nexthop address for V.
               */
-      ifindex = ntohl(l-&gt;link_data.s_addr);
-      if (ifindex &lt;= 0x00ffffff) /* unnumbered ? */
+      if (oi-&gt;type == OSPF_IFTYPE_POINTOPOINT)
 {
-  oi = ospf_if_lookup_by_ifindex(area-&gt;ospf, ifindex);
-  if (oi &amp;&amp; oi-&gt;type == OSPF_IFTYPE_POINTOPOINT)
+  if (ntohl(l-&gt;link_data.s_addr) &lt;= 0x00ffffff)
+    nh_found = 1; /* Unnumbered */
+  else if (IPV4_ADDR_SAME (&amp;oi-&gt;address-&gt;u.prefix4,
+   &amp;l-&gt;link_data))
     nh_found = 1;
-  nexthop.s_addr = 0;
+  nexthop.s_addr = 0; /* Nexthop not required */
 }
-      else
+      else if (oi-&gt;type == OSPF_IFTYPE_POINTOMULTIPOINT)
 {
-  oi = ospf_if_is_configured (area-&gt;ospf, &amp;l-&gt;link_data);
-  if (oi &amp;&amp; oi-&gt;type == OSPF_IFTYPE_POINTOMULTIPOINT)
-    {
-      struct prefix_ipv4 la;
-
-      la.family = AF_INET;
-      la.prefixlen = oi-&gt;address-&gt;prefixlen;
-
-      /* V links to W on PtMP interface
- - find the interface address on W */
-      while ((l2 = ospf_get_next_link (w, v, l2)))
-{
-  la.prefix = l2-&gt;link_data;
-
-  if (prefix_cmp ((struct prefix *) &amp;la,
-  oi-&gt;address) != 0)
-    continue;
-  /* link_data is on our PtMP network */
-  nh_found = 1;
-  nexthop = l2-&gt;link_data;
-  break;
-}
-    } /* end l is on point-to-multipoint link */
-  else
+  struct prefix_ipv4 la;
+
+  la.family = AF_INET;
+  la.prefixlen = oi-&gt;address-&gt;prefixlen;
+
+  /* V links to W on PtMP interface
+     - find the interface address on W */
+  while ((l2 = ospf_get_next_link (w, v, l2)))
     {
-      /* l is a regular point-to-point link.
- Look for a link from W to V.
-      */
-      while ((l2 = ospf_get_next_link (w, v, l2)))
-{
-  if (ntohl(l2-&gt;link_data.s_addr) &lt;= 0x00ffffff)
-    continue; /* skip unnumbered links */
-
-  oi = ospf_if_is_configured (area-&gt;ospf,
-      &amp;l2-&gt;link_data);
-
-  if (oi == NULL)
-    continue;
-
-  if (!IPV4_ADDR_SAME (&amp;oi-&gt;address-&gt;u.prefix4,
-       &amp;l-&gt;link_data))
-    continue;
-  nexthop.s_addr = 0; /* zero better for equal-cost ? */
-  nh_found = 1;
-  break;
-}
+      la.prefix = l2-&gt;link_data;
+
+      if (prefix_cmp ((struct prefix *) &amp;la,
+      oi-&gt;address) != 0)
+continue;
+      /* link_data is on our PtMP network */
+      nh_found = 1;
+      nexthop = l2-&gt;link_data;
+      break;
     }
 }
 
&lt; at &gt;&lt; at &gt; -623,8 +606,8 &lt; at &gt;&lt; at &gt; ospf_nexthop_calculation (struct ospf_area *area, struct vertex *v,
                   return 1;
                 }
               else
-                zlog_info("ospf_nexthop_calculation(): "
-                          "could not determine nexthop for link");
+                zlog_info("%s: could not determine nexthop for link",
+  __func__);
             } /* end point-to-point link from V to W */
           else if (l-&gt;m[0].type == LSA_LINK_TYPE_VIRTUALLINK)
             {
&lt; at &gt;&lt; at &gt; -657,19 +640,22 &lt; at &gt;&lt; at &gt; ospf_nexthop_calculation (struct ospf_area *area, struct vertex *v,
       else
         {
           assert(w-&gt;type == OSPF_VERTEX_NETWORK);
-          oi = ospf_if_is_configured (area-&gt;ospf, &amp;(l-&gt;link_data));
-          if (oi)
+  if (!IPV4_ADDR_SAME (&amp;oi-&gt;address-&gt;u.prefix4,
+       &amp;l-&gt;link_data))
             {
-              nh = vertex_nexthop_new ();
-              nh-&gt;oi = oi;
-              nh-&gt;router.s_addr = 0;
-              ospf_spf_add_parent (v, w, nh, distance);
-              return 1;
-            }
+      zlog_info("%s: Interface %s:%s does not match Link Data:%s",
+__func__, oi-&gt;ifp-&gt;name,
+inet_ntop (AF_INET, &amp;oi-&gt;address-&gt;u.prefix4, buf1, BUFSIZ),
+inet_ntop (AF_INET, &amp;l-&gt;link_id, buf2, BUFSIZ));
+      return 0;
+    }
+
+  nh = vertex_nexthop_new ();
+  nh-&gt;oi = oi;
+  nh-&gt;router.s_addr = 0;
+  ospf_spf_add_parent (v, w, nh, distance);
+  return 1;
         }
-      zlog_info("ospf_nexthop_calculation(): "
-                "Unknown attached link");
-      return 0;
     } /* end V is the root */
   /* Check if W's parent is a network connected to root. */
   else if (v-&gt;type == OSPF_VERTEX_NETWORK)
&lt; at &gt;&lt; at &gt; -744,7 +730,7 &lt; at &gt;&lt; at &gt; ospf_spf_next (struct vertex *v, struct ospf_area *area,
   u_char *lim;
   struct router_lsa_link *l = NULL;
   struct in_addr *r;
-  int type = 0;
+  int type = 0, lsa_pos=-1, lsa_pos_next=0;
 
   /* If this is a router-LSA, and bit V of the router-LSA (see Section
      A.4.2:RFC2328) is set, set Area A's TransitCapability to TRUE.  */
&lt; at &gt;&lt; at &gt; -772,7 +758,8 &lt; at &gt;&lt; at &gt; ospf_spf_next (struct vertex *v, struct ospf_area *area,
       if (v-&gt;lsa-&gt;type == OSPF_ROUTER_LSA)
         {
           l = (struct router_lsa_link *) p;
-
+  lsa_pos = lsa_pos_next; /* LSA link position */
+  lsa_pos_next++;
           p += (ROUTER_LSA_MIN_SIZE +
                 (l-&gt;m[0].tos_count * ROUTER_LSA_TOS_SIZE));
 
&lt; at &gt;&lt; at &gt; -894,7 +881,7 &lt; at &gt;&lt; at &gt; ospf_spf_next (struct vertex *v, struct ospf_area *area,
           w = ospf_vertex_new (w_lsa);
 
           /* Calculate nexthop to W. */
-          if (ospf_nexthop_calculation (area, v, w, l, distance))
+          if (ospf_nexthop_calculation (area, v, w, l, distance, lsa_pos))
             pqueue_enqueue (w, candidate);
           else if (IS_DEBUG_OSPF_EVENT)
             zlog_debug ("Nexthop Calc failed");
&lt; at &gt;&lt; at &gt; -914,7 +901,7 &lt; at &gt;&lt; at &gt; ospf_spf_next (struct vertex *v, struct ospf_area *area,
             {
       /* Found an equal-cost path to W.  
                * Calculate nexthop of to W from V. */
-              ospf_nexthop_calculation (area, v, w, l, distance);
+      ospf_nexthop_calculation (area, v, w, l, distance, lsa_pos);
             }
            /* less than. */
   else
&lt; at &gt;&lt; at &gt; -924,7 +911,7 &lt; at &gt;&lt; at &gt; ospf_spf_next (struct vertex *v, struct ospf_area *area,
                * valid nexthop it will call spf_add_parents, which
                * will flush the old parents
                */
-              if (ospf_nexthop_calculation (area, v, w, l, distance))
+      if (ospf_nexthop_calculation (area, v, w, l, distance, lsa_pos))
                 /* Decrease the key of the node in the heap.
                  * trickle-sort it up towards root, just in case this
                  * node should now be the new root due the cost change. 
</description>
    <dc:creator>Joakim Tjernlund</dc:creator>
    <dc:date>2008-11-14T12:44:36</dc:date>
  </item>
  <item rdf:about="http://comments.gmane.org/gmane.network.quagga.devel/6122">
    <title>[quagga-dev 6114]  (no subject)</title>
    <link>http://comments.gmane.org/gmane.network.quagga.devel/6122</link>
    <description/>
    <dc:creator>Greg S</dc:creator>
    <dc:date>2008-11-11T21:03:14</dc:date>
  </item>
  <item rdf:about="http://comments.gmane.org/gmane.network.quagga.devel/6121">
    <title>[quagga-dev 6113]  RFC 5082 GTSM for quagga bgpd</title>
    <link>http://comments.gmane.org/gmane.network.quagga.devel/6121</link>
    <description>Hello,

I've attached a patch set to implement RFC 5082 GTSM for quagga.  This 
depends on the IP_MINTTL socket option which was implemented by Andre 
Oppermann:

http://lists.quagga.net/pipermail/quagga-dev/2005-August/003607.html

Implementation
==============

The code is implemented using the "neighbor XXX ttl-security hops YYY" 
command in the BGP router context.  The configuration is fully compatible 
with the equivalent Cisco IOS commands.  Normally, YYY will be set to be 
the number of hops between the two bgp neighbors.  The process works as 
follows:

- all outgoing packets are set up with TTL of "MAXTTL + 1 - gtsm_hops"
- all incoming packets are checked to ensure that the TTL falls within the 
hop limit specified in the configuration

Internally, this is implemented by silently using the ebgp-multihop command 
when ttl-security hops is configured on a neighbor, and by configuring the 
master BGP listening socket to have a TTL of 255.

The code prohibits ebgp-multihop and ttl-security from being configured 
together.

I've fixed a very minor bug in peer_ebgp_multihop_set_vty() and 
peer_ebgp_multihop_unset_vty().  These commands should not return 
CMD_SUCCESS by default.

If "ttl-security hops" is configured on an operating system which does not 
support the IP_MINTTL socket option, or if ttl security is enabled on an 
IPv6 socket, then a warning will be logged on the system log.  However, 
bgpd will accept the configuration.

ttl-security hops is fully peer-group aware (including checking for 
conflicts with ebgp-multihop).

Usage
=====

Usage is described in the cisco documentation:

http://www.cisco.com/en/US/docs/ios/12_3t/12_3t7/feature/guide/gt_btsh.html

Under normal circumstances the ttl-security hops parameter should be set to 
the exact number of hops between the two BGP peers.  So, for directly 
connected peers, this will be "ttl-security hops 1".

Cisco have also implemented GTSM for OSPF.  I haven't attempted that with 
this patch, and don't have any plans to do so in future.

Caveats
=======

-  Right now, this socket option is supported in FreeBSD &gt;= 5.x, OpenBSD 
 &gt;=4.1 and DragonflyBSD &gt;= 2.0.0.  There is a minor bug in all these 
implementations which is addressed here:

http://www.freebsd.org/cgi/query-pr.cgi?pr=128790

-  as there is no equivalent IP6_MINTTL socket option, this only works for 
IPv4 sockets.

Enjoy,

Nick
Index: bgpd/bgp_network.c
===================================================================
RCS file: /data/CVSROOT/quagga/bgpd/bgp_network.c,v
retrieving revision 1.1.1.1
diff -u -r1.1.1.1 bgp_network.c
--- bgpd/bgp_network.c25 Oct 2008 22:01:33 -00001.1.1.1
+++ bgpd/bgp_network.c4 Nov 2008 12:58:15 -0000
&lt; at &gt;&lt; at &gt; -166,8 +166,11 &lt; at &gt;&lt; at &gt;
     }
 
   /* In case of peer is EBGP, we should set TTL for this connection.  */
-  if (peer_sort (peer1) == BGP_PEER_EBGP)
+  if (peer_sort (peer1) == BGP_PEER_EBGP) {
     sockopt_ttl (peer1-&gt;su.sa.sa_family, bgp_sock, peer1-&gt;ttl);
+    if (peer1-&gt;gtsm_hops)
+      sockopt_minttl (peer1-&gt;su.sa.sa_family, bgp_sock, MAXTTL + 1 - peer1-&gt;gtsm_hops);
+  }
 
   if (! bgp)
     bgp = peer1-&gt;bgp;
&lt; at &gt;&lt; at &gt; -308,8 +311,11 &lt; at &gt;&lt; at &gt;
     return -1;
 
   /* If we can get socket for the peer, adjest TTL and make connection. */
-  if (peer_sort (peer) == BGP_PEER_EBGP)
+  if (peer_sort (peer) == BGP_PEER_EBGP) {
     sockopt_ttl (peer-&gt;su.sa.sa_family, peer-&gt;fd, peer-&gt;ttl);
+    if (peer-&gt;gtsm_hops)
+      sockopt_minttl (peer-&gt;su.sa.sa_family, peer-&gt;fd, MAXTTL + 1 - peer-&gt;gtsm_hops);
+  }
 
   sockopt_reuseaddr (peer-&gt;fd);
   sockopt_reuseport (peer-&gt;fd);
&lt; at &gt;&lt; at &gt; -412,6 +418,9 &lt; at &gt;&lt; at &gt;
 setsockopt_ipv4_tos (sock, IPTOS_PREC_INTERNETCONTROL);
 #endif
 
+      /* if we intend to implement ttl-security, this socket needs ttl=255 */
+      sockopt_ttl (ainfo-&gt;ai_family, sock, MAXTTL);
+
       if (bgpd_privs.change (ZPRIVS_RAISE) )
         zlog_err ("bgp_socket: could not raise privs");
 
&lt; at &gt;&lt; at &gt; -468,6 +477,9 &lt; at &gt;&lt; at &gt;
   setsockopt_ipv4_tos (sock, IPTOS_PREC_INTERNETCONTROL);
 #endif
 
+  /* if we intend to implement ttl-security, this socket needs ttl=255 */
+  sockopt_ttl (AF_INET, sock, MAXTTL);
+
   memset (&amp;sin, 0, sizeof (struct sockaddr_in));
 
   sin.sin_family = AF_INET;
Index: bgpd/bgp_vty.c
===================================================================
RCS file: /data/CVSROOT/quagga/bgpd/bgp_vty.c,v
retrieving revision 1.1.1.1
retrieving revision 1.5
diff -u -r1.1.1.1 -r1.5
--- bgpd/bgp_vty.c25 Oct 2008 22:01:33 -00001.1.1.1
+++ bgpd/bgp_vty.c4 Nov 2008 12:07:16 -00001.5
&lt; at &gt;&lt; at &gt; -213,6 +213,9 &lt; at &gt;&lt; at &gt;
     case BGP_ERR_TCPSIG_FAILED:
       str = "Error while applying TCP-Sig to session(s)";
       break;
+    case BGP_ERR_NO_EBGP_MULTIHOP_WITH_TTLHACK:
+      str = "ebgp-multihop and ttl-security cannot be configured together";
+      break;
     }
   if (str)
     {
&lt; at &gt;&lt; at &gt; -2614,6 +2617,7 &lt; at &gt;&lt; at &gt;
 {
   struct peer *peer;
   unsigned int ttl;
+  int ret;
 
   peer = peer_and_group_lookup_vty (vty, ip_str);
   if (! peer)
&lt; at &gt;&lt; at &gt; -2624,23 +2628,24 &lt; at &gt;&lt; at &gt;
   else
     VTY_GET_INTEGER_RANGE ("TTL", ttl, ttl_str, 1, 255);
 
-  peer_ebgp_multihop_set (peer, ttl);
-
-  return CMD_SUCCESS;
+  ret = peer_ebgp_multihop_set (peer, ttl);
+  
+  return bgp_vty_return (vty, ret);
 }
 
 static int
 peer_ebgp_multihop_unset_vty (struct vty *vty, const char *ip_str) 
 {
   struct peer *peer;
+  int ret;
 
   peer = peer_and_group_lookup_vty (vty, ip_str);
   if (! peer)
     return CMD_WARNING;
 
-  peer_ebgp_multihop_unset (peer);
-
-  return CMD_SUCCESS;
+  ret = peer_ebgp_multihop_unset (peer);
+  
+  return bgp_vty_return (vty, ret);
 }
 
 /* neighbor ebgp-multihop. */
&lt; at &gt;&lt; at &gt; -3941,6 +3946,47 &lt; at &gt;&lt; at &gt;
   return bgp_vty_return (vty, ret);
 }
 
+DEFUN (neighbor_ttl_security,
+       neighbor_ttl_security_cmd,
+       NEIGHBOR_CMD2 "ttl-security hops &lt;1-254&gt;",
+       NEIGHBOR_STR
+       NEIGHBOR_ADDR_STR2
+       "Specify the maximum number of hops to the BGP peer\n")
+{
+  struct peer *peer;
+  int ret, gtsm_hops;
+
+  peer = peer_and_group_lookup_vty (vty, argv[0]);
+  if (! peer)
+    return CMD_WARNING;
+    
+  VTY_GET_INTEGER_RANGE ("", gtsm_hops, argv[1], 1, 254);
+
+  ret = peer_ttl_security_hops_set (peer, gtsm_hops);
+
+  return bgp_vty_return (vty, ret);
+}
+
+DEFUN (no_neighbor_ttl_security,
+       no_neighbor_ttl_security_cmd,
+       NO_NEIGHBOR_CMD2 "ttl-security hops &lt;1-254&gt;",
+       NO_STR
+       NEIGHBOR_STR
+       NEIGHBOR_ADDR_STR2
+       "Specify the maximum number of hops to the BGP peer\n")
+{
+  struct peer *peer;
+  int ret;
+
+  peer = peer_and_group_lookup_vty (vty, argv[0]);
+  if (! peer)
+    return CMD_WARNING;
+
+  ret = peer_ttl_security_hops_unset (peer);
+
+  return bgp_vty_return (vty, ret);
+}
+
 /* Address family configuration.  */
 DEFUN (address_family_ipv4,
        address_family_ipv4_cmd,
&lt; at &gt;&lt; at &gt; -9870,6 +9916,10 &lt; at &gt;&lt; at &gt;
   install_element (BGP_IPV6_NODE, &amp;no_bgp_redistribute_ipv6_metric_rmap_cmd);
 #endif /* HAVE_IPV6 */
 
+  /* ttl_security commands */
+  install_element (BGP_NODE, &amp;neighbor_ttl_security_cmd);
+  install_element (BGP_NODE, &amp;no_neighbor_ttl_security_cmd);
+
   /* "show bgp memory" commands. */
   install_element (VIEW_NODE, &amp;show_bgp_memory_cmd);
   install_element (RESTRICTED_NODE, &amp;show_bgp_memory_cmd);
Index: bgpd/bgpd.c
===================================================================
RCS file: /data/CVSROOT/quagga/bgpd/bgpd.c,v
retrieving revision 1.1.1.1
diff -u -r1.1.1.1 bgpd.c
--- bgpd/bgpd.c25 Oct 2008 22:01:33 -00001.1.1.1
+++ bgpd/bgpd.c4 Nov 2008 12:58:00 -0000
&lt; at &gt;&lt; at &gt; -1367,6 +1367,7 &lt; at &gt;&lt; at &gt;
   group-&gt;conf-&gt;group = group;
   group-&gt;conf-&gt;as = 0; 
   group-&gt;conf-&gt;ttl = 1;
+  group-&gt;conf-&gt;gtsm_hops = 0;
   group-&gt;conf-&gt;v_routeadv = BGP_DEFAULT_EBGP_ROUTEADV;
   UNSET_FLAG (group-&gt;conf-&gt;config, PEER_CONFIG_TIMER);
   UNSET_FLAG (group-&gt;conf-&gt;config, PEER_CONFIG_CONNECT);
&lt; at &gt;&lt; at &gt; -1404,6 +1405,9 &lt; at &gt;&lt; at &gt;
   /* TTL */
   peer-&gt;ttl = conf-&gt;ttl;
 
+  /* GTSM hops */
+  peer-&gt;gtsm_hops = conf-&gt;gtsm_hops;
+
   /* Weight */
   peer-&gt;weight = conf-&gt;weight;
 
&lt; at &gt;&lt; at &gt; -2597,10 +2601,36 &lt; at &gt;&lt; at &gt;
 {
   struct peer_group *group;
   struct listnode *node, *nnode;
+  struct peer *peer1;
 
   if (peer_sort (peer) == BGP_PEER_IBGP)
     return 0;
 
+  /* see comment in peer_ttl_security_hops_set() */
+  if (ttl != MAXTTL)
+    {
+      if (CHECK_FLAG (peer-&gt;sflags, PEER_STATUS_GROUP))
+        {
+          group = peer-&gt;group;
+          if (group-&gt;conf-&gt;gtsm_hops != 0)
+            return BGP_ERR_NO_EBGP_MULTIHOP_WITH_TTLHACK;
+
+          for (ALL_LIST_ELEMENTS (group-&gt;peer, node, nnode, peer1))
+            {
+              if (peer_sort (peer1) == BGP_PEER_IBGP)
+                continue;
+
+              if (peer1-&gt;gtsm_hops != 0)
+                return BGP_ERR_NO_EBGP_MULTIHOP_WITH_TTLHACK;
+            }
+        }
+      else
+        {
+          if (peer-&gt;gtsm_hops != 0)
+            return BGP_ERR_NO_EBGP_MULTIHOP_WITH_TTLHACK;
+        }
+    }
+
   peer-&gt;ttl = ttl;
 
   if (! CHECK_FLAG (peer-&gt;sflags, PEER_STATUS_GROUP))
&lt; at &gt;&lt; at &gt; -2634,6 +2664,9 &lt; at &gt;&lt; at &gt;
   if (peer_sort (peer) == BGP_PEER_IBGP)
     return 0;
 
+  if (peer-&gt;gtsm_hops != 0 &amp;&amp; peer-&gt;ttl != MAXTTL)
+      return BGP_ERR_NO_EBGP_MULTIHOP_WITH_TTLHACK;
+
   if (peer_group_active (peer))
     peer-&gt;ttl = peer-&gt;group-&gt;conf-&gt;ttl;
   else
&lt; at &gt;&lt; at &gt; -4265,6 +4298,121 &lt; at &gt;&lt; at &gt;
   return 0;
 }
 
+/* Set # of hops between us and BGP peer. */
+int
+peer_ttl_security_hops_set (struct peer *peer, int gtsm_hops)
+{
+  struct peer_group *group;
+  struct listnode *node, *nnode;
+  struct peer *peer1;
+  int ret;
+
+  zlog_debug ("peer_ttl_security_hops_set: set gtsm_hops to %d for %s", gtsm_hops, peer-&gt;host);
+
+  if (peer_sort (peer) == BGP_PEER_IBGP)
+      return 0;
+
+  /* We cannot configure ttl-security hops when ebgp-multihop is already
+     set.  For non peer-groups, the check is simple.  For peer-groups, it's
+     slightly messy, because we need to check both the peer-group structure
+     and all peer-group members for any trace of ebgp-multihop configuration
+     before actually applying the ttl-security rules.  Cisco really made a
+     mess of this configuration parameter, and OpenBGPD got it right.
+  */
+
+  if (CHECK_FLAG (peer-&gt;sflags, PEER_STATUS_GROUP))
+    {
+      group = peer-&gt;group;
+      if (group-&gt;conf-&gt;ttl != 1)
+        return BGP_ERR_NO_EBGP_MULTIHOP_WITH_TTLHACK;
+
+      for (ALL_LIST_ELEMENTS (group-&gt;peer, node, nnode, peer1))
+        {
+          if (peer_sort (peer1) == BGP_PEER_IBGP)
+            continue;
+
+          if (peer1-&gt;ttl != 1)
+            return BGP_ERR_NO_EBGP_MULTIHOP_WITH_TTLHACK;
+        }
+    }
+  else
+    {
+      if (peer-&gt;ttl != 1)
+        return BGP_ERR_NO_EBGP_MULTIHOP_WITH_TTLHACK;
+    }
+
+  peer-&gt;gtsm_hops = gtsm_hops;
+
+  /* specify MAXTTL on outgoing packets */
+  ret = peer_ebgp_multihop_set (peer, MAXTTL);
+  if (ret != 0)
+    return ret;
+
+  if (! CHECK_FLAG (peer-&gt;sflags, PEER_STATUS_GROUP))
+    {
+      if (peer-&gt;fd &gt;= 0 &amp;&amp; peer_sort (peer) != BGP_PEER_IBGP)
+sockopt_minttl (peer-&gt;su.sa.sa_family, peer-&gt;fd, MAXTTL + 1 - gtsm_hops);
+    }
+  else
+    {
+      group = peer-&gt;group;
+      for (ALL_LIST_ELEMENTS (group-&gt;peer, node, nnode, peer))
+{
+  if (peer_sort (peer) == BGP_PEER_IBGP)
+    continue;
+
+  peer-&gt;gtsm_hops = group-&gt;conf-&gt;gtsm_hops;
+
+  if (peer-&gt;fd &gt;= 0 &amp;&amp; peer-&gt;gtsm_hops != 0)
+            sockopt_minttl (peer-&gt;su.sa.sa_family, peer-&gt;fd, MAXTTL + 1 - peer-&gt;gtsm_hops);
+}
+    }
+
+  return 0;
+}
+
+int
+peer_ttl_security_hops_unset (struct peer *peer)
+{
+  struct peer_group *group;
+  struct listnode *node, *nnode;
+  struct peer *opeer;
+
+  zlog_debug ("peer_ttl_security_hops_unset: set gtsm_hops to zero for %s", peer-&gt;host);
+
+  if (peer_sort (peer) == BGP_PEER_IBGP)
+      return 0;
+
+  /* if a peer-group member, then reset to peer-group default rather than 0 */
+  if (peer_group_active (peer))
+    peer-&gt;gtsm_hops = peer-&gt;group-&gt;conf-&gt;gtsm_hops;
+  else
+    peer-&gt;gtsm_hops = 0;
+
+  opeer = peer;
+  if (! CHECK_FLAG (peer-&gt;sflags, PEER_STATUS_GROUP))
+    {
+      if (peer-&gt;fd &gt;= 0 &amp;&amp; peer_sort (peer) != BGP_PEER_IBGP)
+sockopt_minttl (peer-&gt;su.sa.sa_family, peer-&gt;fd, 0);
+    }
+  else
+    {
+      group = peer-&gt;group;
+      for (ALL_LIST_ELEMENTS (group-&gt;peer, node, nnode, peer))
+{
+  if (peer_sort (peer) == BGP_PEER_IBGP)
+    continue;
+
+  peer-&gt;gtsm_hops = 0;
+  
+  if (peer-&gt;fd &gt;= 0)
+    sockopt_minttl (peer-&gt;su.sa.sa_family, peer-&gt;fd, 0);
+}
+    }
+
+  return peer_ebgp_multihop_unset (opeer);
+}
+
 int
 peer_clear (struct peer *peer)
 {
&lt; at &gt;&lt; at &gt; -4569,12 +4717,19 &lt; at &gt;&lt; at &gt;
   vty_out (vty, " neighbor %s passive%s", addr, VTY_NEWLINE);
 
       /* EBGP multihop.  */
-      if (peer_sort (peer) != BGP_PEER_IBGP &amp;&amp; peer-&gt;ttl != 1)
+      if (peer_sort (peer) != BGP_PEER_IBGP &amp;&amp; peer-&gt;ttl != 1 &amp;&amp;
+                   !(peer-&gt;gtsm_hops != 0 &amp;&amp; peer-&gt;ttl == MAXTTL))
         if (! peer_group_active (peer) ||
     g_peer-&gt;ttl != peer-&gt;ttl)
   vty_out (vty, " neighbor %s ebgp-multihop %d%s", addr, peer-&gt;ttl,
    VTY_NEWLINE);
 
+     /* ttl-security hops */
+      if (peer_sort (peer) != BGP_PEER_IBGP &amp;&amp; peer-&gt;gtsm_hops != 0)
+        if (! peer_group_active (peer) || g_peer-&gt;gtsm_hops != peer-&gt;gtsm_hops)
+          vty_out (vty, " neighbor %s ttl-security hops %d%s", addr, 
+                   peer-&gt;gtsm_hops, VTY_NEWLINE);
+
       /* disable-connected-check.  */
       if (CHECK_FLAG (peer-&gt;flags, PEER_FLAG_DISABLE_CONNECTED_CHECK))
 if (! peer_group_active (peer) ||
Index: bgpd/bgpd.h
===================================================================
RCS file: /data/CVSROOT/quagga/bgpd/bgpd.h,v
retrieving revision 1.1.1.1
retrieving revision 1.5
diff -u -r1.1.1.1 -r1.5
--- bgpd/bgpd.h25 Oct 2008 22:01:33 -00001.1.1.1
+++ bgpd/bgpd.h4 Nov 2008 12:07:16 -00001.5
&lt; at &gt;&lt; at &gt; -300,6 +300,7 &lt; at &gt;&lt; at &gt;
   /* Peer information */
   int fd;/* File descriptor */
   int ttl;/* TTL of TCP connection to the peer. */
+  int gtsm_hops;/* minimum hopcount to peer */
   char *desc;/* Description of the peer. */
   unsigned short port;          /* Destination port for peer */
   char *host;/* Printable address of the peer. */
&lt; at &gt;&lt; at &gt; -797,7 +798,8 &lt; at &gt;&lt; at &gt;
 #define BGP_ERR_LOCAL_AS_ALLOWED_ONLY_FOR_EBGP  -27
 #define BGP_ERR_CANNOT_HAVE_LOCAL_AS_SAME_AS    -28
 #define BGP_ERR_TCPSIG_FAILED-29
-#define BGP_ERR_MAX                             -30
+#define BGP_ERR_NO_EBGP_MULTIHOP_WITH_TTLHACK-30
+#define BGP_ERR_MAX-31
 
 extern struct bgp_master *bm;
 
&lt; at &gt;&lt; at &gt; -948,4 +950,7 &lt; at &gt;&lt; at &gt;
 
 extern void peer_nsf_stop (struct peer *);
 
+extern int peer_ttl_security_hops_set (struct peer *, int);
+extern int peer_ttl_security_hops_unset (struct peer *);
+
 #endif /* _QUAGGA_BGPD_H */
Index: lib/sockunion.c
===================================================================
RCS file: /data/CVSROOT/quagga/lib/sockunion.c,v
retrieving revision 1.1.1.1
diff -u -r1.1.1.1 sockunion.c
--- lib/sockunion.c25 Oct 2008 22:01:33 -00001.1.1.1
+++ lib/sockunion.c4 Nov 2008 12:56:34 -0000
&lt; at &gt;&lt; at &gt; -526,6 +526,28 &lt; at &gt;&lt; at &gt;
   return 0;
 }
 
+int
+sockopt_minttl (int family, int sock, int minttl)
+{
+  int ret;
+  
+  zlog_debug ("sockopt_minttl: set minttl to %d", minttl);
+
+#ifdef IP_MINTTL
+  ret = setsockopt (sock, IPPROTO_IP, IP_MINTTL, &amp;minttl, sizeof(minttl));
+#else
+  ret = -1;
+  errno = EOPNOTSUPP;
+#endif /* IP_MINTTL */
+  if (ret &lt; 0)
+    {
+      zlog (NULL, LOG_WARNING, "can't set sockopt IP_MINTTL to %d on socket %d: %s", minttl, sock, safe_strerror (errno));
+      return -1;
+    }
+
+  return 0;
+}
+
 /* If same family and same prefix return 1. */
 int
 sockunion_same (union sockunion *su1, union sockunion *su2)
Index: lib/sockunion.h
===================================================================
RCS file: /data/CVSROOT/quagga/lib/sockunion.h,v
retrieving revision 1.1.1.1
diff -u -r1.1.1.1 sockunion.h
--- lib/sockunion.h25 Oct 2008 22:01:33 -00001.1.1.1
+++ lib/sockunion.h4 Nov 2008 12:56:55 -0000
&lt; at &gt;&lt; at &gt; -102,6 +102,7 &lt; at &gt;&lt; at &gt;
 extern int sockunion_bind (int sock, union sockunion *, 
                            unsigned short, union sockunion *);
 extern int sockopt_ttl (int family, int sock, int ttl);
+extern int sockopt_minttl (int family, int sock, int minttl);
 extern int sockunion_socket (union sockunion *su);
 extern const char *inet_sutop (union sockunion *su, char *str);
 extern enum connect_result sockunion_connect (int fd, union sockunion *su, 
</description>
    <dc:creator>Nick Hilliard</dc:creator>
    <dc:date>2008-11-11T16:10:44</dc:date>
  </item>
  <item rdf:about="http://comments.gmane.org/gmane.network.quagga.devel/6115">
    <title>[quagga-dev 6107] thread bug: quagga_gettimeofday() vs.quagga_get_relative() ?</title>
    <link>http://comments.gmane.org/gmane.network.quagga.devel/6115</link>
    <description>Whenever a thread adds an timer funcname_thread_add_timer_timeval() gets called
to add the timer. Before adding the timer a quagga_gettimeofday() call
is made to some time house keeping. Hovever quagga_gettimeofday() only
updates recent_time, not relative_time that is used to calculate
the alarm_time.
Therefore I think quagga_gettimeofday() should be replaced by
quagga_get_relative (NULL);

Comments and especially testing welcome. I am locked out of the
lab as there are release work in progress.

       Jocke

diff --git a/lib/thread.c b/lib/thread.c
index 5a398f3..1fcb8c3 100644
--- a/lib/thread.c
+++ b/lib/thread.c
&lt; at &gt;&lt; at &gt; -661,7 +661,7 &lt; at &gt;&lt; at &gt; funcname_thread_add_timer_timeval (struct thread_master *m,
   thread = thread_get (m, type, func, arg, funcname);
 
   /* Do we need jitter here? */
-  quagga_gettimeofday (&amp;recent_time);
+  quagga_get_relative (NULL);
   alarm_time.tv_sec = relative_time.tv_sec + time_relative-&gt;tv_sec;
   alarm_time.tv_usec = relative_time.tv_usec + time_relative-&gt;tv_usec;
   thread-&gt;u.sands = timeval_adjust(alarm_time);

</description>
    <dc:creator>Joakim Tjernlund</dc:creator>
    <dc:date>2008-11-09T16:46:40</dc:date>
  </item>
  <item rdf:about="http://comments.gmane.org/gmane.network.quagga.devel/6110">
    <title>[quagga-dev 6102]  [PATCH] [lib] Try to ignore time warps better.</title>
    <link>http://comments.gmane.org/gmane.network.quagga.devel/6110</link>
    <description>Relative and monotonic time steps quite much when TOD has
been changed by NTP. Make such changes have less impact by
basically ignore a big change in time. 10 seconds has
randomly been choosen as too big a step so ignore that.
---

Hopefully this is useful. Feedback welcome.

 lib/thread.c |    6 ++++--
 1 files changed, 4 insertions(+), 2 deletions(-)

diff --git a/lib/thread.c b/lib/thread.c
index 260e8c8..5a398f3 100644
--- a/lib/thread.c
+++ b/lib/thread.c
&lt; at &gt;&lt; at &gt; -100,12 +100,14 &lt; at &gt;&lt; at &gt; quagga_gettimeofday_relative_adjust (void)
   struct timeval diff;
   if (timeval_cmp (recent_time, last_recent_time) &lt; 0)
     {
-      relative_time.tv_sec++;
-      relative_time.tv_usec = 0;
+      relative_time.tv_usec += 1000; /* pretend some time has passed */
+      relative_time = timeval_adjust (relative_time);
     }
   else
     {
       diff = timeval_subtract (recent_time, last_recent_time);
+      if (diff.tv_sec &gt; 10) /* Time stepped? */
+diff.tv_sec = 0;/* Pretend it was just a few usecs */
       relative_time.tv_sec += diff.tv_sec;
       relative_time.tv_usec += diff.tv_usec;
       relative_time = timeval_adjust (relative_time);
</description>
    <dc:creator>Joakim Tjernlund</dc:creator>
    <dc:date>2008-11-08T16:15:02</dc:date>
  </item>
  <item rdf:about="http://comments.gmane.org/gmane.network.quagga.devel/6107">
    <title>[quagga-dev 6099]  New Quagga release soon?</title>
    <link>http://comments.gmane.org/gmane.network.quagga.devel/6107</link>
    <description>Now that the Fletcher checksum appers to be resolved, a new release
should be considered.
Since .99.11 has a checksum error, it won't operate correctly against
older Quagga releases, nor any other OSPF router.
Once .99.12 is out, it won't operate correctly against .99.11
So you really want to get rid of .99.11 ASAP.

I would really like see, the below patch too in the next release.

    Jocke

From: Joakim Tjernlund &lt;Joakim.Tjernlund&lt; at &gt;transmode.se&gt;
Date: Mon, 3 Nov 2008 17:47:44 +0100
Subject: [PATCH] [ospfd] Do not install received self-originated LSA.

According to the OSPF RCF, chapter 13.4 and 12.1.6, ospf
should reoriginate its own LSA with LS sequence number
set to the received LS sequence number+1. Currently the
Router LSA and the Network LSA is just copied over and you
end up with a stale LSA.
Fix it to just copy the sequence number and orginate its
own LSA again with seq nr + 1.
---
 ospfd/ospf_flood.c |   34 +++++++++++++++-------------------
 1 files changed, 15 insertions(+), 19 deletions(-)

diff --git a/ospfd/ospf_flood.c b/ospfd/ospf_flood.c
index 0f485fe..8f27060 100644
--- a/ospfd/ospf_flood.c
+++ b/ospfd/ospf_flood.c
&lt; at &gt;&lt; at &gt; -134,9 +134,8 &lt; at &gt;&lt; at &gt; ospf_process_self_originated_lsa (struct ospf *ospf,
     case OSPF_ROUTER_LSA:
       /* Originate a new instance and schedule flooding */
       /* It shouldn't be necessary, but anyway */
-      ospf_lsa_unlock (&amp;area-&gt;router_lsa_self);
-      area-&gt;router_lsa_self = ospf_lsa_lock (new);
-
+      if (area-&gt;router_lsa_self)
+area-&gt;router_lsa_self-&gt;data-&gt;ls_seqnum = new-&gt;data-&gt;ls_seqnum;
       ospf_router_lsa_timer_add (area);
       return;
     case OSPF_NETWORK_LSA:
&lt; at &gt;&lt; at &gt; -169,10 +168,8 &lt; at &gt;&lt; at &gt; ospf_process_self_originated_lsa (struct ospf *ospf,
                 return;
               }
 #endif /* HAVE_OPAQUE_LSA */
-
-            ospf_lsa_unlock (&amp;oi-&gt;network_lsa_self);
-            oi-&gt;network_lsa_self = ospf_lsa_lock (new);
-            
+    if (oi-&gt;network_lsa_self)
+      oi-&gt;network_lsa_self-&gt;data-&gt;ls_seqnum = new-&gt;data-&gt;ls_seqnum;
             /* Schedule network-LSA origination. */
             ospf_network_lsa_timer_add (oi);
             return;
&lt; at &gt;&lt; at &gt; -315,15 +312,6 &lt; at &gt;&lt; at &gt; ospf_flood (struct ospf *ospf, struct ospf_neighbor *nbr,
   SET_FLAG (new-&gt;flags, OSPF_LSA_RECEIVED);
   ospf_lsa_is_self_originated (ospf, new); /* Let it set the flag */
 
-  /* Install the new LSA in the link state database
-     (replacing the current database copy).  This may cause the
-     routing table calculation to be scheduled.  In addition,
-     timestamp the new LSA with the current time.  The flooding
-     procedure cannot overwrite the newly installed LSA until
-     MinLSArrival seconds have elapsed. */  
-
-  new = ospf_lsa_install (ospf, nbr-&gt;oi, new);
-
   /* Acknowledge the receipt of the LSA by sending a Link State
      Acknowledgment packet back out the receiving interface. */
   if (lsa_ack_flag)
&lt; at &gt;&lt; at &gt; -336,9 +324,17 &lt; at &gt;&lt; at &gt; ospf_flood (struct ospf *ospf, struct ospf_neighbor *nbr,
   if (ospf_lsa_is_self_originated (ospf, new))
     ospf_process_self_originated_lsa (ospf, new, oi-&gt;area);
   else
-    /* Update statistics value for OSPF-MIB. */
-    ospf-&gt;rx_lsa_count++;
-
+    {
+      /* Install the new LSA in the link state database
+ (replacing the current database copy).  This may cause the
+ routing table calculation to be scheduled.  In addition,
+ timestamp the new LSA with the current time.  The flooding
+ procedure cannot overwrite the newly installed LSA until
+ MinLSArrival seconds have elapsed. */
+      new = ospf_lsa_install (ospf, nbr-&gt;oi, new);
+      /* Update statistics value for OSPF-MIB. */
+      ospf-&gt;rx_lsa_count++;
+    }
   return 0;
 }
 
</description>
    <dc:creator>Joakim Tjernlund</dc:creator>
    <dc:date>2008-11-07T10:38:57</dc:date>
  </item>
  <item rdf:about="http://comments.gmane.org/gmane.network.quagga.devel/6104">
    <title>[quagga-dev 6096] removing BGP update-source causes session reset?</title>
    <link>http://comments.gmane.org/gmane.network.quagga.devel/6104</link>
    <description>I just did a "no neighbor x.x.x.x update-source y.y.y.y" which didn't
change the source address, but the session was hard-reset anyway.  Is
this behaviour required, or is it just a case of nobody has written an
optimization yet?

</description>
    <dc:creator>Jeremy Jackson</dc:creator>
    <dc:date>2008-11-06T19:26:50</dc:date>
  </item>
  <item rdf:about="http://comments.gmane.org/gmane.network.quagga.devel/6101">
    <title>[quagga-dev 6093]  [PATCH] [lib] Fix Fletcher checksum bug.</title>
    <link>http://comments.gmane.org/gmane.network.quagga.devel/6101</link>
    <description>The new impl. of the Fletcher checkum is buggy. I have
changed back the critical part to the orginal method
and fixed the buggy one, hid it behind UNSIGNED_FLETCHER.

Also did some simple optimizations to reduce the number
of instructions in the hot path for both fletcher_checksum()
and in_cksum().
---

I really hope this is corrent. I am unable to test as the lab
is busy doing release verification.

 lib/checksum.c |   76 +++++++++++++++++++++++++++----------------------------
 1 files changed, 37 insertions(+), 39 deletions(-)

diff --git a/lib/checksum.c b/lib/checksum.c
index 88ec72a..c9a590b 100644
--- a/lib/checksum.c
+++ b/lib/checksum.c
&lt; at &gt;&lt; at &gt; -14,27 +14,20 &lt; at &gt;&lt; at &gt; in_cksum(void *parg, int nbytes)
 {
 u_short *ptr = parg;
 register longsum;/* assumes long == 32 bits */
-u_shortoddbyte;
 register u_shortanswer;/* assumes u_short == 16 bits */
-
+register int count;
 /*
  * Our algorithm is simple, using a 32-bit accumulator (sum),
  * we add sequential 16-bit words to it, and at the end, fold back
  * all the carry bits from the top 16 bits into the lower 16 bits.
  */
-
 sum = 0;
-while (nbytes &gt; 1)  {
-sum += *ptr++;
-nbytes -= 2;
-}
-
-/* mop up an odd byte, if necessary */
-if (nbytes == 1) {
-oddbyte = 0;/* make sure top half is zero */
-*((u_char *) &amp;oddbyte) = *(u_char *)ptr;   /* one byte only */
-sum += oddbyte;
-}
+count = nbytes &gt;&gt; 1; /* div by 2 */
+for(ptr--; count; --count)
+  sum += *++ptr;
+
+if (nbytes &amp; 1) /* Odd */
+  sum += *(u_char *)(++ptr);   /* one byte only */
 
 /*
  * Add back carry outs from top 16 bits to low 16 bits.
&lt; at &gt;&lt; at &gt; -57,22 +50,22 &lt; at &gt;&lt; at &gt; fletcher_checksum(u_char * buffer, int len, u_int16_t offset)
   u_int8_t *p;
   int x;
   int y;
+#ifdef UNSIGNED_FLETCHER
   u_int32_t mul;
-  u_int32_t c0;
-  u_int32_t c1;
-  u_int16_t checksum;
+  u_int32_t c0, c1;
+#else
+  int32_t c0, c1;
+#endif
   u_int16_t *csum;
-  int i, init_len, partial_len;
-
-  checksum = 0;
+  int init_len, partial_len;
 
   /*
    * Zero the csum in the packet.
    */
   csum = (u_int16_t *) (buffer + offset);
-  *(csum) = checksum;
+  *csum = 0;
 
-  p = buffer;
+  p = buffer - 1;
   c0 = 0;
   c1 = 0;
   init_len = len;
&lt; at &gt;&lt; at &gt; -80,47 +73,52 &lt; at &gt;&lt; at &gt; fletcher_checksum(u_char * buffer, int len, u_int16_t offset)
   while (len != 0)
     {
       partial_len = MIN(len, MODX);
+      len -= partial_len;
 
-      for (i = 0; i &lt; partial_len; i++)
+      do
 {
-  c0 = c0 + *(p++);
+  c0 = c0 + *(++p);
   c1 += c0;
-}
+} while (--partial_len);
 
       c0 = c0 % 255;
       c1 = c1 % 255;
-
-      len -= partial_len;
     }
-
+#ifdef UNSIGNED_FLETCHER
+  /* This can do both unsigned and signed c0, c1 and MODX=5802
+   * but costs more instructions.
+   */
   mul = (init_len - offset)*(c0);
 
   x = mul - c0 - c1;
   y = c1 - mul - 1;
 
+  x %= 255;
+  y %= 255;
+
   if (y &gt; 0)
     y++;
   if (x &lt; 0)
     x--;
 
-  x %= 255;
-  y %= 255;
-
   if (x == 0)
     x = 255;
   if (y == 0)
     y = 1;
-
+#else
+  x = ((init_len - offset - 1) * c0 - c1) % 255;
+  if (x &lt;= 0)
+    x += 255;
+  y = 510 - c0 - x;
+  if (y &gt; 255)
+    y -= 255;
+#endif
   /*
    * Now we write this to the packet.
    * We could skip this step too, since the checksum returned would
    * be stored into the checksum field by the caller.
+   * Checksum is always big endian.
    */
-  buffer[offset] = x;
-  buffer[offset + 1] = y;
-
-  /* Take care of the endian issue */
-  checksum = htons((x &lt;&lt; 8) | (y &amp; 0xFF));
-
-  return checksum;
+  *csum = htons((x &lt;&lt; 8) | (y &amp; 0xFF));
+  return *csum;
 }
</description>
    <dc:creator>Joakim Tjernlund</dc:creator>
    <dc:date>2008-11-06T18:01:55</dc:date>
  </item>
  <item rdf:about="http://comments.gmane.org/gmane.network.quagga.devel/6093">
    <title>[quagga-dev 6085] [PATCH] [ospfd] Do not install receivedself-originated LSA.</title>
    <link>http://comments.gmane.org/gmane.network.quagga.devel/6093</link>
    <description>According to the OSPF RCF, chapter 13.4 and 12.1.6, ospf
should reoriginate its own LSA with LS sequence number
set to the received LS sequence number. Currently the
LSA is just copied over. Fix it to just copy the sequence
number and orginate its own LSA again with seq nr + 1.
---
 ospfd/ospf_flood.c |   34 +++++++++++++++-------------------
 1 files changed, 15 insertions(+), 19 deletions(-)

diff --git a/ospfd/ospf_flood.c b/ospfd/ospf_flood.c
index 0f485fe..8f27060 100644
--- a/ospfd/ospf_flood.c
+++ b/ospfd/ospf_flood.c
&lt; at &gt;&lt; at &gt; -134,9 +134,8 &lt; at &gt;&lt; at &gt; ospf_process_self_originated_lsa (struct ospf *ospf,
     case OSPF_ROUTER_LSA:
       /* Originate a new instance and schedule flooding */
       /* It shouldn't be necessary, but anyway */
-      ospf_lsa_unlock (&amp;area-&gt;router_lsa_self);
-      area-&gt;router_lsa_self = ospf_lsa_lock (new);
-
+      if (area-&gt;router_lsa_self)
+area-&gt;router_lsa_self-&gt;data-&gt;ls_seqnum = new-&gt;data-&gt;ls_seqnum;
       ospf_router_lsa_timer_add (area);
       return;
     case OSPF_NETWORK_LSA:
&lt; at &gt;&lt; at &gt; -169,10 +168,8 &lt; at &gt;&lt; at &gt; ospf_process_self_originated_lsa (struct ospf *ospf,
                 return;
               }
 #endif /* HAVE_OPAQUE_LSA */
-
-            ospf_lsa_unlock (&amp;oi-&gt;network_lsa_self);
-            oi-&gt;network_lsa_self = ospf_lsa_lock (new);
-            
+    if (oi-&gt;network_lsa_self)
+      oi-&gt;network_lsa_self-&gt;data-&gt;ls_seqnum = new-&gt;data-&gt;ls_seqnum;
             /* Schedule network-LSA origination. */
             ospf_network_lsa_timer_add (oi);
             return;
&lt; at &gt;&lt; at &gt; -315,15 +312,6 &lt; at &gt;&lt; at &gt; ospf_flood (struct ospf *ospf, struct ospf_neighbor *nbr,
   SET_FLAG (new-&gt;flags, OSPF_LSA_RECEIVED);
   ospf_lsa_is_self_originated (ospf, new); /* Let it set the flag */
 
-  /* Install the new LSA in the link state database
-     (replacing the current database copy).  This may cause the
-     routing table calculation to be scheduled.  In addition,
-     timestamp the new LSA with the current time.  The flooding
-     procedure cannot overwrite the newly installed LSA until
-     MinLSArrival seconds have elapsed. */  
-
-  new = ospf_lsa_install (ospf, nbr-&gt;oi, new);
-
   /* Acknowledge the receipt of the LSA by sending a Link State
      Acknowledgment packet back out the receiving interface. */
   if (lsa_ack_flag)
&lt; at &gt;&lt; at &gt; -336,9 +324,17 &lt; at &gt;&lt; at &gt; ospf_flood (struct ospf *ospf, struct ospf_neighbor *nbr,
   if (ospf_lsa_is_self_originated (ospf, new))
     ospf_process_self_originated_lsa (ospf, new, oi-&gt;area);
   else
-    /* Update statistics value for OSPF-MIB. */
-    ospf-&gt;rx_lsa_count++;
-
+    {
+      /* Install the new LSA in the link state database
+ (replacing the current database copy).  This may cause the
+ routing table calculation to be scheduled.  In addition,
+ timestamp the new LSA with the current time.  The flooding
+ procedure cannot overwrite the newly installed LSA until
+ MinLSArrival seconds have elapsed. */
+      new = ospf_lsa_install (ospf, nbr-&gt;oi, new);
+      /* Update statistics value for OSPF-MIB. */
+      ospf-&gt;rx_lsa_count++;
+    }
   return 0;
 }
 
</description>
    <dc:creator>Joakim Tjernlund</dc:creator>
    <dc:date>2008-11-06T09:35:12</dc:date>
  </item>
  <item rdf:about="http://comments.gmane.org/gmane.network.quagga.devel/6092">
    <title>[quagga-dev 6084]  [PATCH] [lib] Fix Fletcher checksum error.</title>
    <link>http://comments.gmane.org/gmane.network.quagga.devel/6092</link>
    <description>The new impl. of Fletcher checkum is buggy. I have
changed back the critical part to the orginal method
and left the buggy one inside a #if 0 for now.

Also did some simple optimizations to reduce the number
of instructions in the hot path for both fletcher_checksum()
and in_cksum().
---
 lib/checksum.c |   67 +++++++++++++++++++++++++++----------------------------
 1 files changed, 33 insertions(+), 34 deletions(-)

diff --git a/lib/checksum.c b/lib/checksum.c
index 88ec72a..6077ccb 100644
--- a/lib/checksum.c
+++ b/lib/checksum.c
&lt; at &gt;&lt; at &gt; -14,27 +14,23 &lt; at &gt;&lt; at &gt; in_cksum(void *parg, int nbytes)
 {
 u_short *ptr = parg;
 register longsum;/* assumes long == 32 bits */
-u_shortoddbyte;
 register u_shortanswer;/* assumes u_short == 16 bits */
-
+register int count;
 /*
  * Our algorithm is simple, using a 32-bit accumulator (sum),
  * we add sequential 16-bit words to it, and at the end, fold back
  * all the carry bits from the top 16 bits into the lower 16 bits.
  */
-
 sum = 0;
-while (nbytes &gt; 1)  {
-sum += *ptr++;
-nbytes -= 2;
-}
-
-/* mop up an odd byte, if necessary */
-if (nbytes == 1) {
-oddbyte = 0;/* make sure top half is zero */
-*((u_char *) &amp;oddbyte) = *(u_char *)ptr;   /* one byte only */
-sum += oddbyte;
-}
+count = nbytes &gt;&gt; 1; /* div by 2 */
+ptr--;
+if (count)
+  do
+    sum += *++ptr;
+  while (--count);
+
+if (nbytes &amp; 1) /* Odd */
+  sum += *(u_char *)(++ptr);   /* one byte only */
 
 /*
  * Add back carry outs from top 16 bits to low 16 bits.
&lt; at &gt;&lt; at &gt; -60,19 +56,16 &lt; at &gt;&lt; at &gt; fletcher_checksum(u_char * buffer, int len, u_int16_t offset)
   u_int32_t mul;
   u_int32_t c0;
   u_int32_t c1;
-  u_int16_t checksum;
   u_int16_t *csum;
-  int i, init_len, partial_len;
-
-  checksum = 0;
+  int init_len, partial_len;
 
   /*
    * Zero the csum in the packet.
    */
   csum = (u_int16_t *) (buffer + offset);
-  *(csum) = checksum;
+  *csum = 0;
 
-  p = buffer;
+  p = buffer - 1;
   c0 = 0;
   c1 = 0;
   init_len = len;
&lt; at &gt;&lt; at &gt; -80,19 +73,22 &lt; at &gt;&lt; at &gt; fletcher_checksum(u_char * buffer, int len, u_int16_t offset)
   while (len != 0)
     {
       partial_len = MIN(len, MODX);
+      len -= partial_len;
 
-      for (i = 0; i &lt; partial_len; i++)
+      do
 {
-  c0 = c0 + *(p++);
+  c0 = c0 + *(++p);
   c1 += c0;
-}
+} while (--partial_len);
 
       c0 = c0 % 255;
       c1 = c1 % 255;
-
-      len -= partial_len;
     }
-
+#if 0
+  /* This is buggy. Try using it on a buffer with all 0xff, len 65025.
+     Doing so I get csum1:0xfe01, csum2:0xfeff.
+     I suspect the mul = (init_len - offset)*(c0) overflows.
+  */
   mul = (init_len - offset)*(c0);
 
   x = mul - c0 - c1;
&lt; at &gt;&lt; at &gt; -110,17 +106,20 &lt; at &gt;&lt; at &gt; fletcher_checksum(u_char * buffer, int len, u_int16_t offset)
     x = 255;
   if (y == 0)
     y = 1;
-
+#else
+  x = ((init_len - offset - 1) * c0 - c1) % 255;
+  if (x &lt;= 0)
+    x += 255;
+  y = 510 - c0 - x;
+  if (y &gt; 255)
+    y -= 255;
+#endif
   /*
    * Now we write this to the packet.
    * We could skip this step too, since the checksum returned would
    * be stored into the checksum field by the caller.
+   * Checksum is always big endian.
    */
-  buffer[offset] = x;
-  buffer[offset + 1] = y;
-
-  /* Take care of the endian issue */
-  checksum = htons((x &lt;&lt; 8) | (y &amp; 0xFF));
-
-  return checksum;
+  *csum = htons((x &lt;&lt; 8) | (y &amp; 0xFF));
+  return *csum;
 }
</description>
    <dc:creator>Joakim Tjernlund</dc:creator>
    <dc:date>2008-11-06T09:29:36</dc:date>
  </item>
  <item rdf:about="http://comments.gmane.org/gmane.network.quagga.devel/6091">
    <title>[quagga-dev 6083]  Merge Unnumbered PtP patches?</title>
    <link>http://comments.gmane.org/gmane.network.quagga.devel/6091</link>
    <description>I have some more updates that touch the same area as the
Unnumbered PtP patches so it is becoming harder
to do development.
So can we merge the Unnumbered PtP support now?
I am not aware of any regressions from the Unnumbered patches.

Paul, what do you say?

 Jocke  
</description>
    <dc:creator>Joakim Tjernlund</dc:creator>
    <dc:date>2008-11-05T16:55:00</dc:date>
  </item>
  <item rdf:about="http://comments.gmane.org/gmane.network.quagga.devel/6083">
    <title>[quagga-dev 6075] [PATCH] [zebra] Fix repeated add/delete of the same IP address on the same interface</title>
    <link>http://comments.gmane.org/gmane.network.quagga.devel/6083</link>
    <description/>
    <dc:creator>Paul Evans</dc:creator>
    <dc:date>2008-11-03T17:22:16</dc:date>
  </item>
  <textinput about="http://search.gmane.org/?group=$group=gmane.network.quagga.devel">
    <title>Search Engine</title>
    <description>Search the mailing list at Gmane</description>
    <name>query</name>
    <link>http://search.gmane.org/?group=$group=gmane.network.quagga.devel</link>
  </textinput>
</rdf:RDF>
