>
> Ondrej Zajicek <santi...@crfreenet.org> wrote on 2010/04/21 20:15:07:
> > On Wed, Apr 21, 2010 at 09:41:47AM +0200, Joakim Tjernlund wrote:
> > > I am using Quagga ATM but I had a quick look at BIRD and I got a few
> > > observations.
> >
> > Hello. Thank you for your tips and notes.
> >
> > > The LSA/checksum code seem very inefficient.
> > > LSAs are built allocating/reallocing bits
> > > of memory. This is slow and will case memory fragmentation.
> >
> > You mean lsab_alloc() in originate_rt_lsa_body()?
> > This allocation is just a sequential allocation in a persistent memory 
> > buffer,
> > therefore it is very efficient (in most cases just increase of lsab_used 
> > counter)
> > and there si no memory fragmentation (all is done inside a persistent 
> > memory buffer).
>
> Yes, you do realloc on small amounts of memory. Also, receives LSAs
> seems to be impl. differently so you need handle these somewhat
> differently.
> >
> > > The fletcher checksum is very slow as it has extra tests in the hot path 
> > > and also
> > > flips endian in the LSA back and forth.
> >
> > Do you have some suggestions for a better algorithm, or just a better
> > implementation? Yes, the problem with flipping endianity is known.
> > I do not studied this part of the code yet (the checksum algorithm).
>
> Yes, but not at the moment. The endian problem should be addressed when you
> build the lsa.
>
> >
> > > I can't work out how the SPF next hop works(calc_next_hop). I tried to
> compare it with
> > > Quagga's ospf_nexthop_calculation() but the structure is too different. 
> > > The reason
> > > for me looking into this was to see how much work it would be to add
> > unnumbered ppp links
> > > but as I can't work out how nexthop is working I didn't get very far.
> >
> > The current code is different from what RFC says. For direct neighbors
> > (on both ptp and non-ptp networks), we just use IP address taken from
> > the source address of the HELLO packet of the neighbor (stored in
> > neighbor structure returned by find_neigh_noifa()).
> >
> > This works well [*] for both broadcast and ptp links (numbered or
> > unnumbered), but is broken on NBMA networks. I have some not-yet-commited
> > changes to calc_next_hop() that on broadcast and NBMA networks uses the
> > standard way (taking IP address from the router LSA) and the source address
> > from HELLO packet as a nexthop is used just for PTP links.
> > Such behavior is also suggested by RFC 5340 (for OSFPv3).
> >
> > [*] Regardless of how the other side is implemented.
> >
> > > I have impl. unnumbered ppp link for Quagga that works really well but 
> > > this work
> > > hasn't been accepted into Quagga yet since Quagga development has stalled.
> > > I could show you how I did it Quagga though.
> >
> > The development state of Quagga is sad. Do you implement it in a different
> > way than in BIRD? I wonder whether there is any other possible way to get
> > next hop address for unnumbered ptp links than from source address
> > of HELLO packet.

> Yep, now it gets tricky. It took me quite some time to figure out what to
> do. The secret is that you never use search for the interface using IP 
> addresses
> in the LSA's. Instead you record what interface created what entry in in your
> own Router LSA. Based on the position of on entry in your own router
> LSA you can lookup the interface that created that entry. Once
> you know the interface, the reset is easy.
>
> One way to impl. this is to build an array of interface pointers when
> you construct the Router LSA:
> RLSA     Array
> Item 0   ptr to ppp0
> Item 1   ptr to ppp0
> Item 2   ptr to eth0
> ...
> Item n   ptr to if n
>
> Now you can easily find the interface if you pass on the position of the
> the entry in the RLSA you are processing to the nexthop calculation.
>
> I have a few patches to Quagga that does this somewhere, they are all
> on the Quagga mailing list and a few of them are also in my personal
> git repo at the Quagga site.
>
>  Jocke

Found two different impl. I did for Quagga. Figured you could use
them to get an idea.

>From e4703f876b2085fdb583a3ee8bd5d524255f71e4 Mon Sep 17 00:00:00 2001
From: Joakim Tjernlund <joakim.tjernl...@transmode.se>
Date: Tue, 3 Jun 2008 18:41:28 +0200
Subject: [PATCH] [ospfd] Optimize and improve SPF nexthop calculation

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.
---
 ospfd/ospf_interface.c |    2 +
 ospfd/ospf_lsa.c       |   91 +++++++++++++++++++++++++++--
 ospfd/ospf_lsa.h       |   12 ++++
 ospfd/ospf_spf.c       |  151 +++++++++++++++++++++++++----------------------
 4 files changed, 179 insertions(+), 77 deletions(-)

diff --git a/ospfd/ospf_interface.c b/ospfd/ospf_interface.c
index afe3acf..fc39a81 100644
--- a/ospfd/ospf_interface.c
+++ b/ospfd/ospf_interface.c
@@ -335,6 +335,8 @@ ospf_if_free (struct ospf_interface *oi)
   listnode_delete (oi->ospf->oiflist, oi);
   listnode_delete (oi->area->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 0ba1834..a12dd7a 100644
--- a/ospfd/ospf_lsa.c
+++ b/ospfd/ospf_lsa.c
@@ -241,6 +241,27 @@ 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->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->area->router_lsa_self;
+
+  if (!lsa || !lsa->oi_seq)
+    return;
+  /* "delete" all entries of oi */
+  for (i=0; i < lsa->oi_seq->length/sizeof(seq_nr_t); i++)
+    if (lsa->oi_seq->seq_nr[i] == oi)
+      lsa->oi_seq->seq_nr[i] = NULL;
+}
+
 /* Free OSPF LSA. */
 void
 ospf_lsa_free (struct ospf_lsa *lsa)
@@ -254,6 +275,8 @@ ospf_lsa_free (struct ospf_lsa *lsa)
   if (lsa->data != NULL)
     ospf_lsa_data_free (lsa->data);

+  if (lsa->oi_seq != NULL)
+    ospf_lsa_oi_seq_free (lsa->oi_seq);
   assert (lsa->refresh_list < 0);

   memset (lsa, 0, sizeof (struct ospf_lsa));
@@ -306,6 +329,24 @@ ospf_lsa_data_new (size_t size)
   return XCALLOC (MTYPE_OSPF_LSA_DATA, size);
 }

+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)
@@ -318,6 +359,18 @@ 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->length = oi_seq->length;
+  new->seq_nr = ospf_lsa_oi_seq_data_new (oi_seq->length);
+  memcpy (new->seq_nr, oi_seq->seq_nr, oi_seq->length);
+  return new;
+}
+
 /* Free LSA data. */
 void
 ospf_lsa_data_free (struct lsa_header *lsah)
@@ -653,13 +706,24 @@ 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->oi_seq && index >= 0)
+    return lsa->oi_seq->seq_nr[index];
+
+  zlog_debug ("%s: oi_seq:%p, index:%d!",
+             __func__, lsa->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->oiflist, node, oi))
     {
@@ -670,6 +734,7 @@ router_lsa_link_set (struct stream *s, struct ospf_area 
*area)
        {
          if (oi->state != ISM_Down)
            {
+             old_links = links;
              /* Describe each link. */
              switch (oi->type)
                {
@@ -691,6 +756,8 @@ 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 < links; i++)
+               oi_list[i] = oi;
            }
        }
     }
@@ -699,8 +766,9 @@ 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;
@@ -718,10 +786,12 @@ 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
@@ -790,6 +860,9 @@ 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");
@@ -806,7 +879,8 @@ ospf_router_lsa_new (struct ospf_area *area)
                  OSPF_ROUTER_LSA, ospf->router_id, ospf->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);
@@ -826,6 +900,11 @@ ospf_router_lsa_new (struct ospf_area *area)
   /* Copy LSA data to store, discard stream. */
   new->data = ospf_lsa_data_new (length);
   memcpy (new->data, lsah, length);
+
+  new->oi_seq = ospf_lsa_oi_seq_new ();
+  new->oi_seq->length = cnt*sizeof(seq_nr_t);
+  new->oi_seq->seq_nr = ospf_lsa_oi_seq_data_new (new->oi_seq->length);
+  memcpy (new->oi_seq->seq_nr, oi_list, new->oi_seq->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
@@ -68,6 +68,13 @@ 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
 {
@@ -84,6 +91,9 @@ 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;

@@ -247,10 +257,12 @@ 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 610fc9b..07a31c5 100644
--- a/ospfd/ospf_spf.c
+++ b/ospfd/ospf_spf.c
@@ -480,13 +480,16 @@ 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)
     {
@@ -505,30 +508,41 @@ 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->router_lsa_self, lsa_pos);
+      if (!oi)
+       {
+         zlog_debug("%s: OI not found in LSA: lsa_pos:%d link_id:%s 
link_data:%s",
+                    __func__, lsa_pos,
+                    inet_ntop (AF_INET, &l->link_id, buf1, BUFSIZ),
+                    inet_ntop (AF_INET, &l->link_data, buf2, BUFSIZ));
+         return 0;
+       }
+
       if (w->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->m[0].type,
+                        __func__, l->m[0].type,
                         inet_ntop (AF_INET, &l->link_id, buf1, BUFSIZ),
                         inet_ntop (AF_INET, &l->link_data, buf2, BUFSIZ));
             }

           if (l->m[0].type == LSA_LINK_TYPE_POINTOPOINT)
             {
+             int nh_found = 0;
+             struct in_addr nexthop;
+             unsigned long ifindex;
+
               /* If the destination is a router which connects to
                  the calculating router via a Point-to-MultiPoint
                  network, the destination's next hop IP address(es)
@@ -548,59 +562,50 @@ 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.
               */
-              oi = ospf_if_is_configured (area->ospf, &l->link_data);
-              if (oi && oi->type == OSPF_IFTYPE_POINTOMULTIPOINT)
-                {
-                  struct prefix_ipv4 la;
-
-                  la.family = AF_INET;
-                  la.prefixlen = oi->address->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->link_data;
-
-                      if (prefix_cmp ((struct prefix *) &la,
-                                      oi->address) == 0)
-                        /* link_data is on our PtMP network */
-                        break;
-                    }
-                } /* end l is on point-to-multipoint link */
-              else
-                {
-                  /* 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)))
-                    {
-                      oi = ospf_if_is_configured (area->ospf,
-                                                  &(l2->link_data));
-
-                      if (oi == NULL)
-                        continue;
-
-                      if (!IPV4_ADDR_SAME (&oi->address->u.prefix4,
-                                           &l->link_data))
-                        continue;
-
-                      break;
-                    }
-                }
-
-              if (oi && l2)
+             if (oi->type == OSPF_IFTYPE_POINTOPOINT)
+               {
+                 if (ntohl(l->link_data.s_addr) <= 0x00ffffff)
+                   nh_found = 1; /* Unnumbered */
+                 else if (IPV4_ADDR_SAME (&oi->address->u.prefix4,
+                                          &l->link_data))
+                   nh_found = 1;
+                 nexthop.s_addr = 0; /* Nexthop not required */
+               }
+             else if (oi->type == OSPF_IFTYPE_POINTOMULTIPOINT)
+               {
+                 struct prefix_ipv4 la;
+
+                 la.family = AF_INET;
+                 la.prefixlen = oi->address->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->link_data;
+
+                     if (prefix_cmp ((struct prefix *) &la,
+                                     oi->address) != 0)
+                       continue;
+                     /* link_data is on our PtMP network */
+                     nh_found = 1;
+                     nexthop = l2->link_data;
+                     break;
+                   }
+               }
+
+              if (nh_found)
                 {
                   /* found all necessary info to build nexthop */
                   nh = vertex_nexthop_new ();
                   nh->oi = oi;
-                  nh->router = l2->link_data;
+                  nh->router = nexthop;
                   ospf_spf_add_parent (v, w, nh, distance);
                   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->m[0].type == LSA_LINK_TYPE_VIRTUALLINK)
             {
@@ -633,19 +638,22 @@ ospf_nexthop_calculation (struct ospf_area *area, struct 
vertex *v,
       else
         {
           assert(w->type == OSPF_VERTEX_NETWORK);
-          oi = ospf_if_is_configured (area->ospf, &(l->link_data));
-          if (oi)
+         if (!IPV4_ADDR_SAME (&oi->address->u.prefix4,
+                              &l->link_data))
             {
-              nh = vertex_nexthop_new ();
-              nh->oi = oi;
-              nh->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->ifp->name,
+                       inet_ntop (AF_INET, &oi->address->u.prefix4, buf1, 
BUFSIZ),
+                       inet_ntop (AF_INET, &l->link_id, buf2, BUFSIZ));
+             return 0;
+           }
+
+         nh = vertex_nexthop_new ();
+         nh->oi = oi;
+         nh->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->type == OSPF_VERTEX_NETWORK)
@@ -714,7 +722,7 @@ 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.  */
@@ -742,7 +750,8 @@ ospf_spf_next (struct vertex *v, struct ospf_area *area,
       if (v->lsa->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->m[0].tos_count * ROUTER_LSA_TOS_SIZE));

@@ -864,7 +873,7 @@ 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");
@@ -884,7 +893,7 @@ 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
@@ -894,7 +903,7 @@ 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.
--
1.6.4.4



>From a33c98b1bb7c54e97b10e239c2134f184ea93d56 Mon Sep 17 00:00:00 2001
From: Joakim Tjernlund <joakim.tjernl...@transmode.se>
Date: Fri, 7 Aug 2009 20:57:51 +0200
Subject: [PATCH] ospfd: Optimize and improve SPF nexthop calculation

    Maintain router LSA positions in OSPF interface.
    Find the OSPF interface in nexthop_calculation using
    the position in the router LSA.

    This has the following advantages:
    - Multiple PtP interfaces with the same IP address between two routers.
    - Use Unnumbered PtP on just one end of the link.
    - Faster OI lookup for the OSPF interface and only
      done once for PtoP links.

*ospf_interface.h: (struct ospf_interface) Add storage for
                   storing router LSA position.

*ospf_interface.c: (ospf_if_lookup_by_lsa_pos)
                   lookup OSPF I/F in an area using LSA position.
                   (ospf_lsa_pos_set) assign LSA position to OSPF
                   interface.

*ospf_lsa.c: (router_lsa_link_set) Call ospf_lsa_pos_set() to record
             LSA position.

*ospf_spf.c: (ospf_spf_next) Count and pass along lsa position.
             (ospf_nexthop_calculation) Add lsa position argument.
             call ospf_if_lookup_by_lsa_pos() for OSFP interface handle.
             Clean up and remove all calls ospf_if_is_configured() the
             rest. Adjust a few debug logs.
---
 ospfd/ospf_interface.c |   28 ++++++++-
 ospfd/ospf_interface.h |    7 ++
 ospfd/ospf_lsa.c       |    4 +-
 ospfd/ospf_spf.c       |  158 ++++++++++++++++++++++-------------------------
 4 files changed, 111 insertions(+), 86 deletions(-)

diff --git a/ospfd/ospf_interface.c b/ospfd/ospf_interface.c
index afe3acf..f11fdef 100644
--- a/ospfd/ospf_interface.c
+++ b/ospfd/ospf_interface.c
@@ -211,7 +211,9 @@ ospf_if_new (struct ospf *ospf, struct interface *ifp, 
struct prefix *p)
     }
   else
     return oi;
-
+
+  ospf_lsa_pos_set(-1,-1, oi); /* delete position in router LSA */
+
   /* Set zebra interface pointer. */
   oi->ifp = ifp;
   oi->address = p;
@@ -397,6 +399,29 @@ ospf_if_exists (struct ospf_interface *oic)
   return NULL;
 }

+/* Lookup OSPF interface by router LSA posistion */
+struct ospf_interface *
+ospf_if_lookup_by_lsa_pos (struct ospf_area *area, int lsa_pos)
+{
+  struct listnode *node;
+  struct ospf_interface *oi;
+
+  for (ALL_LIST_ELEMENTS_RO (area->oiflist, node, oi))
+    {
+      if (lsa_pos >= oi->lsa_pos_beg && lsa_pos < oi->lsa_pos_end)
+       return oi;
+    }
+  return NULL;
+}
+
+/* Set OSPF interface position in router LSA */
+void
+ospf_lsa_pos_set(int pos_beg, int pos_end, struct ospf_interface *oi)
+{
+  oi->lsa_pos_beg = pos_beg;
+  oi->lsa_pos_end = pos_end;
+}
+
 struct ospf_interface *
 ospf_if_lookup_by_local_addr (struct ospf *ospf,
                              struct interface *ifp, struct in_addr address)
@@ -803,6 +828,7 @@ ospf_if_down (struct ospf_interface *oi)
     return 0;

   OSPF_ISM_EVENT_EXECUTE (oi, ISM_InterfaceDown);
+  ospf_lsa_pos_set(-1, -1, oi); /* delete position in router LSA */
   /* Shutdown packet reception and sending */
   ospf_if_stream_unset (oi);

diff --git a/ospfd/ospf_interface.h b/ospfd/ospf_interface.h
index ab0b758..cd39411 100644
--- a/ospfd/ospf_interface.h
+++ b/ospfd/ospf_interface.h
@@ -124,6 +124,10 @@ struct ospf_interface
   /* OSPF Area. */
   struct ospf_area *area;

+  /* Position range in Router LSA */
+  int lsa_pos_beg; /* inclusive, >= */
+  int lsa_pos_end; /* exclusive, <  */
+
   /* Interface data from zebra. */
   struct interface *ifp;
   struct ospf_vl_data *vl_data;                /* Data for Virtual Link */
@@ -242,6 +246,9 @@ extern int ospf_if_down (struct ospf_interface *);

 extern int ospf_if_is_up (struct ospf_interface *);
 extern struct ospf_interface *ospf_if_exists (struct ospf_interface *);
+extern struct ospf_interface *ospf_if_lookup_by_lsa_pos (struct ospf_area *,
+                                                        int);
+extern void ospf_lsa_pos_set(int, int, struct ospf_interface *);
 extern struct ospf_interface *ospf_if_lookup_by_local_addr (struct ospf *,
                                                            struct interface
                                                            *,
diff --git a/ospfd/ospf_lsa.c b/ospfd/ospf_lsa.c
index 0ba1834..3cbd99b 100644
--- a/ospfd/ospf_lsa.c
+++ b/ospfd/ospf_lsa.c
@@ -659,7 +659,7 @@ router_lsa_link_set (struct stream *s, struct ospf_area 
*area)
 {
   struct listnode *node;
   struct ospf_interface *oi;
-  int links = 0;
+  int links = 0, old_links;

   for (ALL_LIST_ELEMENTS_RO (area->oiflist, node, oi))
     {
@@ -670,6 +670,7 @@ router_lsa_link_set (struct stream *s, struct ospf_area 
*area)
        {
          if (oi->state != ISM_Down)
            {
+             old_links = links;
              /* Describe each link. */
              switch (oi->type)
                {
@@ -691,6 +692,7 @@ router_lsa_link_set (struct stream *s, struct ospf_area 
*area)
                case OSPF_IFTYPE_LOOPBACK:
                  links += lsa_link_loopback_set (s, oi);
                }
+             ospf_lsa_pos_set(old_links, links, oi);
            }
        }
     }
diff --git a/ospfd/ospf_spf.c b/ospfd/ospf_spf.c
index 610fc9b..3cac594 100644
--- a/ospfd/ospf_spf.c
+++ b/ospfd/ospf_spf.c
@@ -480,13 +480,15 @@ 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)
     {
@@ -505,30 +507,38 @@ 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 = ospf_if_lookup_by_lsa_pos (area, lsa_pos);
+      if (!oi)
+       {
+         zlog_debug("%s: OI not found in LSA: lsa_pos:%d link_id:%s 
link_data:%s",
+                    __func__, lsa_pos,
+                    inet_ntop (AF_INET, &l->link_id, buf1, BUFSIZ),
+                    inet_ntop (AF_INET, &l->link_data, buf2, BUFSIZ));
+         return 0;
+       }
+
+      if (IS_DEBUG_OSPF_EVENT)
+       {
+         zlog_debug("%s: considering link:%s "
+                    "type:%d link_id:%s link_data:%s",
+                    __func__, oi->ifp->name, l->m[0].type,
+                    inet_ntop (AF_INET, &l->link_id, buf1, BUFSIZ),
+                    inet_ntop (AF_INET, &l->link_data, buf2, BUFSIZ));
+       }
+
       if (w->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 "
-                        "type %d link_id %s link_data %s",
-                        l->m[0].type,
-                        inet_ntop (AF_INET, &l->link_id, buf1, BUFSIZ),
-                        inet_ntop (AF_INET, &l->link_data, buf2, BUFSIZ));
-            }

           if (l->m[0].type == LSA_LINK_TYPE_POINTOPOINT)
             {
+             struct in_addr nexthop;
+
               /* If the destination is a router which connects to
                  the calculating router via a Point-to-MultiPoint
                  network, the destination's next hop IP address(es)
@@ -539,68 +549,53 @@ ospf_nexthop_calculation (struct ospf_area *area, struct 
vertex *v,
                  provides an IP address of the next hop router.

                  At this point l is a link from V to W, and V is the
-                 root ("us").  Find the local interface associated
-                 with l (its address is in l->link_data).  If it
-                 is a point-to-multipoint interface, then look through
-                 the links in the opposite direction (W to V).  If
-                 any of them have an address that lands within the
+                 root ("us"). If it is a point-to-multipoint interface,
+                then look through the links in the opposite direction (W to V).
+                If any of them have an address that lands within the
                  subnet declared by the PtMP link, then that link
-                 is a constituent of the PtMP link, and its address is
+                 is a constituent of the PtMP link, and its address is
                  a nexthop address for V.
               */
-              oi = ospf_if_is_configured (area->ospf, &l->link_data);
-              if (oi && oi->type == OSPF_IFTYPE_POINTOMULTIPOINT)
-                {
-                  struct prefix_ipv4 la;
-
-                  la.family = AF_INET;
-                  la.prefixlen = oi->address->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->link_data;
-
-                      if (prefix_cmp ((struct prefix *) &la,
-                                      oi->address) == 0)
-                        /* link_data is on our PtMP network */
-                        break;
-                    }
-                } /* end l is on point-to-multipoint link */
-              else
-                {
-                  /* 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)))
-                    {
-                      oi = ospf_if_is_configured (area->ospf,
-                                                  &(l2->link_data));
-
-                      if (oi == NULL)
-                        continue;
-
-                      if (!IPV4_ADDR_SAME (&oi->address->u.prefix4,
-                                           &l->link_data))
-                        continue;
-
-                      break;
-                    }
-                }
-
-              if (oi && l2)
+             if (oi->type == OSPF_IFTYPE_POINTOPOINT)
+               {
+                 added = 1;
+                 nexthop.s_addr = 0; /* Nexthop not required */
+               }
+             else if (oi->type == OSPF_IFTYPE_POINTOMULTIPOINT)
+               {
+                 struct prefix_ipv4 la;
+
+                 la.family = AF_INET;
+                 la.prefixlen = oi->address->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->link_data;
+
+                     if (prefix_cmp ((struct prefix *) &la,
+                                     oi->address) != 0)
+                       continue;
+                     /* link_data is on our PtMP network */
+                     added = 1;
+                     nexthop = l2->link_data;
+                     break;
+                   }
+               }
+
+              if (added)
                 {
                   /* found all necessary info to build nexthop */
                   nh = vertex_nexthop_new ();
                   nh->oi = oi;
-                  nh->router = l2->link_data;
+                  nh->router = nexthop;
                   ospf_spf_add_parent (v, w, nh, distance);
                   return 1;
                 }
               else
-                zlog_info("ospf_nexthop_calculation(): "
-                          "could not determine nexthop for link");
+               zlog_info("%s: could not determine nexthop for link %s",
+                         __func__, oi->ifp->name);
             } /* end point-to-point link from V to W */
           else if (l->m[0].type == LSA_LINK_TYPE_VIRTUALLINK)
             {
@@ -633,19 +628,13 @@ ospf_nexthop_calculation (struct ospf_area *area, struct 
vertex *v,
       else
         {
           assert(w->type == OSPF_VERTEX_NETWORK);
-          oi = ospf_if_is_configured (area->ospf, &(l->link_data));
-          if (oi)
-            {
-              nh = vertex_nexthop_new ();
-              nh->oi = oi;
-              nh->router.s_addr = 0;
-              ospf_spf_add_parent (v, w, nh, distance);
-              return 1;
-            }
+
+         nh = vertex_nexthop_new ();
+         nh->oi = oi;
+         nh->router.s_addr = 0; /* Nexthop not required */
+         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->type == OSPF_VERTEX_NETWORK)
@@ -714,7 +703,7 @@ 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.  */
@@ -742,7 +731,8 @@ ospf_spf_next (struct vertex *v, struct ospf_area *area,
       if (v->lsa->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->m[0].tos_count * ROUTER_LSA_TOS_SIZE));

@@ -864,7 +854,7 @@ 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");
@@ -884,7 +874,7 @@ 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
@@ -894,7 +884,7 @@ 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.
--
1.6.4.4


Reply via email to