]> git.ipfire.org Git - thirdparty/bird.git/commitdiff
Temporary integrated commit (OSPF), unfinished.
authorOndrej Zajicek <santiago@crfreenet.org>
Sun, 5 Aug 2012 20:32:06 +0000 (22:32 +0200)
committerOndrej Zajicek <santiago@crfreenet.org>
Wed, 29 Aug 2012 10:37:17 +0000 (12:37 +0200)
23 files changed:
filter/filter.h
lib/ip.h
nest/iface.c
nest/neighbor.c
proto/ospf/config.Y
proto/ospf/dbdes.c
proto/ospf/hello.c
proto/ospf/iface.c
proto/ospf/lsack.c
proto/ospf/lsalib.c
proto/ospf/lsalib.h
proto/ospf/lsreq.c
proto/ospf/lsupd.c
proto/ospf/lsupd.h
proto/ospf/neighbor.c
proto/ospf/ospf.c
proto/ospf/ospf.h
proto/ospf/packet.c
proto/ospf/rt.c
proto/ospf/topology.c
proto/ospf/topology.h
proto/radv/packets.c
proto/radv/radv.h

index 2386fc9598c5db55723ecce5ccb960885dce7a7f..e2f3d09f431c7319573ccd3d6c0b722197f4ef43 100644 (file)
@@ -14,6 +14,9 @@
 #include "nest/route.h"
 #include "nest/attrs.h"
 
+
+#define IPV6 1 // XXXX temporary
+
 struct f_inst {                /* Instruction */
   struct f_inst *next; /* Structure is 16 bytes, anyway */
   u16 code;
index b62937ef43868433a6380858acdc9ab5c623c5c1..056207f9cc990f116ffa4aa523285b58ef216bcf 100644 (file)
--- a/lib/ip.h
+++ b/lib/ip.h
 #include "lib/unaligned.h"
 
 
-#ifdef DEBUGGING
+
+#define IP4_MIN_MTU            576     /* RFC 2328 A.1 */
+#define IP6_MIN_MTU            1280    /* RFC 5340 A.1 */
+
+#define IP4_ALL_SPF_ROUTERS    ipa_build4(224, 0, 0, 5)
+#define IP4_ALL_D_ROUTERS      ipa_build4(224, 0, 0, 6)
+
+#define IP6_All_NODES          ipa_build6(0xFF020000, 0, 0, 1)
+#define IP6_ALL_ROUTERS                ipa_build6(0xFF020000, 0, 0, 2)
+#define IP6_ALL_OSPF_ROUTERS   ipa_build6(0xFF020000, 0, 0, 5)
+#define IP6_ALL_OSPF_D_ROUTERS ipa_build6(0xFF020000, 0, 0, 6)
+
+#define IP4_NONE _MI4(0)
+#define IP6_NONE _MI6(0,0,0,0)
+#define IPA_NONE IP6_NONE
+
 
 /*
  *     Use the structural representation when you want to make sure
  *     nobody unauthorized attempts to handle ip_addr as number.
  */
 
+#ifdef DEBUGGING
+
 typedef struct ip4_addr {
   u32 addr;
 } ip4_addr;
@@ -54,11 +71,6 @@ typedef ip6_addr ip_addr;
 
 
 
-#define IPA_NONE IP6_NONE
-#define IP4_NONE _MI4(0)
-#define IP6_NONE _MI6(0,0,0,0)
-
-
 /*
  *     ip_classify() returns either a negative number for invalid addresses
  *     or scope OR'ed together with address type.
@@ -123,9 +135,11 @@ static inline ip6_addr ip6_not(ip6_addr a)
 
 #define ipa_from_ip4(x) _MI6(0,0,0xffff,_I(x))
 #define ipa_from_ip6(x) x
+#define ipa_from_u32(x) ipa_from_ip4(ip4_from_u32(x))
 
 #define ipa_to_ip4(x) _I3(x)
 #define ipa_to_ip6(x) x
+#define ipa_to_u32(x) ip4_to_u32(ipa_to_ip4(x))
 
 #define ip4_from_u32(x) _MI4(x)
 #define ip4_to_u32(x) _I(x)
index eea3d3b1ac8f24b53c0051b2953a13954de9efcc..7f756e5c80bf27f05edf6ba6ef2f560bd5a4c2e7 100644 (file)
@@ -534,10 +534,8 @@ ifa_update(struct ifa *a)
        break;
       }
 
-#ifndef IPV6
-  if ((i->flags & IF_BROADCAST) && !ipa_nonzero(a->brd))
-    log(L_ERR "Missing broadcast address for interface %s", i->name);
-#endif
+  if (ipa_is_ip4(a->ip) && (i->flags & IF_BROADCAST) && !ipa_nonzero(a->brd))
+    log(L_WARN "Missing broadcast address for interface %s", i->name);
 
   b = mb_alloc(if_pool, sizeof(struct ifa));
   memcpy(b, a, sizeof(struct ifa));
@@ -583,10 +581,13 @@ ifa_delete(struct ifa *a)
       }
 }
 
+
 static void
 auto_router_id(void)
 {
-#ifndef IPV6
+// XXXX check this
+#if 0
+
   struct iface *i, *j;
 
   j = NULL;
index 506d9bdee4618b76d2171c4dbeb54bc50ffb2072..bbd21330ef428ba87cb9a0cf77a8763b928f36e0 100644 (file)
@@ -75,12 +75,11 @@ if_connected(ip_addr *a, struct iface *i) /* -1=error, 1=match, 0=no match */
        {
          if (ipa_in_net(*a, b->prefix, b->pxlen))
            {
-#ifndef IPV6
+             // XXXX what about this ?
              if ((b->pxlen < (BITS_PER_IP_ADDRESS - 1)) &&
                  (ipa_equal(*a, b->prefix) ||  /* Network address */
                   ipa_equal(*a, b->brd)))      /* Broadcast */
                return -1;
-#endif
 
              return b->scope;
            }
index 67b0785f5fb992ca8d71c9e7681e70ff1c6bb3a0..40d3f1f14a8873139f164e4bc909a0a853abbaee 100644 (file)
@@ -335,7 +335,7 @@ ipa_item:
     ipa_el
   | ipa_ne;
  
-ipa_el: IPA ';'
+ipa_el: ipa ';'
  {
    this_nbma = cfg_allocz(sizeof(struct nbma_node));
    add_tail(&OSPF_PATT->nbma_list, NODE this_nbma);
@@ -344,7 +344,7 @@ ipa_el: IPA ';'
  }
 ;
 
-ipa_ne: IPA ELIGIBLE ';'
+ipa_ne: ipa ELIGIBLE ';'
  {
    this_nbma = cfg_allocz(sizeof(struct nbma_node));
    add_tail(&OSPF_PATT->nbma_list, NODE this_nbma);
index 75ecf24c7d52b1228639a853a715419cb186f895..e1e0e81f9171d36ca6c7216e6e9e22d5fb866fdb 100644 (file)
@@ -9,47 +9,77 @@
 #include "ospf.h"
 
 
-#ifdef OSPFv2
-struct ospf_dbdes_packet
+struct ospf_dbdes2_packet
 {
-  struct ospf_packet ospf_packet;
+  struct ospf_packet hdr;
+  union ospf_auth auth;
+
   u16 iface_mtu;
   u8 options;
-  union imms imms;             /* I, M, MS bits */
+  u8 imms;                     /* I, M, MS bits */
   u32 ddseq;
-};
-
-#define hton_opt(X) X
-#define ntoh_opt(X) X
-#endif
 
+  struct ospf_lsa_header lsas[];
+};
 
-#ifdef OSPFv3
-struct ospf_dbdes_packet
+struct ospf_dbdes3_packet
 {
-  struct ospf_packet ospf_packet;
+  struct ospf_packet hdr;
+
   u32 options;
   u16 iface_mtu;
   u8 padding;
-  union imms imms;             /* I, M, MS bits */
+  u8 imms;                     /* I, M, MS bits */
   u32 ddseq;
+
+  struct ospf_lsa_header lsas[];
 };
 
+
+
+#ifdef OSPFv2
+
+#define hton_opt(X) X
+#define ntoh_opt(X) X
+#endif
+
+
+#ifdef OSPFv3
+
 #define hton_opt(X) htonl(X)
 #define ntoh_opt(X) ntohl(X)
 #endif
 
+static inline unsigned
+ospf_dbdes_hdrlen(struct proto_ospf *po)
+{
+  return ospf_is_v2(po) ?
+    sizeof(struct ospf_dbdes2_packet) :
+    sizeof(struct ospf_dbdes3_packet);
+}
+
+static void
+ospf_dbdes_body(struct proto_ospf *po, struct ospf_packet *pkt, unsigned plen,
+               struct ospf_lsa_header **body, unsigned *count)
+{
+  unsigned hdrlen = ospf_dbdes_hdrlen(po);
+  *body = ((void *) pkt) + hdrlen;
+  *count = (plen - hdrlen) / sizeof(struct ospf_lsa_header);
+}
   
-static void ospf_dump_dbdes(struct proto *p, struct ospf_dbdes_packet *pkt)
+static void ospf_dbdes_dump(struct proto_ospf *po, struct ospf_packet *pkt)
 {
-  struct ospf_packet *op = &pkt->ospf_packet;
-
-  ASSERT(op->type == DBDES_P);
-  ospf_dump_common(p, op);
-  log(L_TRACE "%s:     imms     %s%s%s",
-      p->name, pkt->imms.bit.ms ? "MS " : "",
-      pkt->imms.bit.m ? "M " : "",
-      pkt->imms.bit.i ? "I " : "" );
+  struct proto *p = &po->proto;
+  struct ospf_lsa_header *lsas;
+  unsigned i, lsa_count;
+
+  ASSERT(pkt->type == DBDES_P);
+  ospf_dump_common(po, pkt);
+
+  log(L_TRACE "%s:     imms     %s%s%s", p->name,
+      (imms & DBDES_I) ? "I " : "",
+      (imms & DBDES_M) ? "M " : "",
+      (imms & DBDES_MS) ? "MS" : "");
   log(L_TRACE "%s:     ddseq    %u", p->name, ntohl(pkt->ddseq));
 
   struct ospf_lsa_header *plsa = (void *) (pkt + 1);
@@ -59,7 +89,7 @@ static void ospf_dump_dbdes(struct proto *p, struct ospf_dbdes_packet *pkt)
     sizeof(struct ospf_lsa_header);
 
   for (i = 0; i < j; i++)
-    ospf_dump_lsahdr(p, plsa + i);
+    ospf_dump_lsahdr(p, &lsas[i]);
 }
 
 
@@ -77,12 +107,12 @@ static void ospf_dump_dbdes(struct proto *p, struct ospf_dbdes_packet *pkt)
 void
 ospf_dbdes_send(struct ospf_neighbor *n, int next)
 {
-  struct ospf_dbdes_packet *pkt;
-  struct ospf_packet *op;
   struct ospf_iface *ifa = n->ifa;
   struct ospf_area *oa = ifa->oa;
   struct proto_ospf *po = oa->po;
-  struct proto *p = &po->proto;
+
+  struct ospf_dbdes_packet *pkt;
+  struct ospf_packet *op;
   u16 length, i, j;
 
   /* FIXME ??? */
@@ -92,7 +122,7 @@ ospf_dbdes_send(struct ospf_neighbor *n, int next)
   switch (n->state)
   {
   case NEIGHBOR_EXSTART:       /* Send empty packets */
-    n->myimms.bit.i = 1;
+    n->myimms |= DBDES_I;
     pkt = ospf_tx_buffer(ifa);
     op = &pkt->ospf_packet;
     ospf_pkt_fill_hdr(ifa, pkt, DBDES_P);
@@ -108,7 +138,7 @@ ospf_dbdes_send(struct ospf_neighbor *n, int next)
     break;
 
   case NEIGHBOR_EXCHANGE:
-    n->myimms.bit.i = 0;
+    n->myimms &= ~DBDES_I;
 
     if (next)
     {
@@ -126,7 +156,7 @@ ospf_dbdes_send(struct ospf_neighbor *n, int next)
       j = i = (ospf_pkt_maxsize(ifa) - sizeof(struct ospf_dbdes_packet)) / sizeof(struct ospf_lsa_header);     /* Number of possible lsaheaders to send */
       lsa = (n->ldbdes + sizeof(struct ospf_dbdes_packet));
 
-      if (n->myimms.bit.m)
+      if (n->myimms & DBDES_M)
       {
        sn = s_get(&(n->dbsi));
 
@@ -158,13 +188,13 @@ ospf_dbdes_send(struct ospf_neighbor *n, int next)
        {
          DBG("Number of LSA NOT sent: %d\n", i);
          DBG("M bit unset.\n");
-         n->myimms.bit.m = 0;  /* Unset more bit */
+         n->myimms &= ~DBDES_M;        /* Unset more bit */
        }
 
        s_put(&(n->dbsi), sn);
       }
 
-      pkt->imms.byte = n->myimms.byte;
+      pkt->imms = n->myimms;
 
       length = (j - i) * sizeof(struct ospf_lsa_header) +
        sizeof(struct ospf_dbdes_packet);
@@ -191,11 +221,13 @@ ospf_dbdes_send(struct ospf_neighbor *n, int next)
     OSPF_PACKET(ospf_dump_dbdes, pkt, "DBDES packet sent to %I via %s", n->ip, ifa->iface->name);
     ospf_send_to(ifa, n->ip);
 
-    if(n->myimms.bit.ms) tm_start(n->rxmt_timer, n->ifa->rxmtint);             /* Restart timer */
+    if (n->myimms & DBDES_MS)
+      tm_start(n->rxmt_timer, n->ifa->rxmtint);                /* Restart timer */
 
-    if (!n->myimms.bit.ms)
+    if (!(n->myimms & DBDES_MS))
     {
-      if ((n->myimms.bit.m == 0) && (n->imms.bit.m == 0) &&
+      if (!(n->myimms & DBDES_M) && 
+         !(n->imms & DBDES_M) &&
          (n->state == NEIGHBOR_EXCHANGE))
       {
        ospf_neigh_sm(n, INM_EXDONE);
@@ -244,11 +276,15 @@ ospf_dbdes_reqladd(struct ospf_dbdes_packet *ps, struct ospf_neighbor *n)
 }
 
 void
-ospf_dbdes_receive(struct ospf_packet *ps_i, struct ospf_iface *ifa,
+ospf_dbdes_receive(struct ospf_packet *pkt, struct ospf_iface *ifa,
                   struct ospf_neighbor *n)
 {
   struct proto_ospf *po = ifa->oa->po;
-  struct proto *p = &po->proto;
+
+  u32 rcv_ddseq, rcv_options;
+  u16 rcv_iface_mtu;
+  u8 rcv_imms;
+
 
   unsigned int size = ntohs(ps_i->length);
   if (size < sizeof(struct ospf_dbdes_packet))
@@ -257,12 +293,24 @@ ospf_dbdes_receive(struct ospf_packet *ps_i, struct ospf_iface *ifa,
     return;
   }
 
-  struct ospf_dbdes_packet *ps = (void *) ps_i;
-  u32 ps_ddseq = ntohl(ps->ddseq);
-  u32 ps_options = ntoh_opt(ps->options);
-  u16 ps_iface_mtu = ntohs(ps->iface_mtu);
+  if (ospf_is_v2(po))
+  {
+    struct ospf_dbdes2_packet *ps = (void *) pkt;
+    rcv_iface_mtu = ntohs(ps->iface_mtu);
+    rcv_options = ps->options;
+    rcv_imms = ps->imms;
+    rcv_ddseq = ntohl(ps->ddseq);
+  }
+  else /* OSPFv3 */
+  {
+    struct ospf_dbdes3_packet *ps = (void *) pkt;
+    rcv_options = ntohl(ps->options);
+    rcv_iface_mtu = ntohs(ps->iface_mtu);
+    rcv_imms = ps->imms;
+    rcv_ddseq = ntohl(ps->ddseq);
+  }
   
-  OSPF_PACKET(ospf_dump_dbdes, ps, "DBDES packet received from %I via %s", n->ip, ifa->iface->name);
+  OSPF_PACKET(ospf_dbdes_dump, ps, "DBDES packet received from %I via %s", n->ip, ifa->iface->name);
 
   ospf_neigh_sm(n, INM_HELLOREC);
 
@@ -272,56 +320,62 @@ ospf_dbdes_receive(struct ospf_packet *ps_i, struct ospf_iface *ifa,
   case NEIGHBOR_ATTEMPT:
   case NEIGHBOR_2WAY:
     return;
-    break;
+
   case NEIGHBOR_INIT:
     ospf_neigh_sm(n, INM_2WAYREC);
     if (n->state != NEIGHBOR_EXSTART)
       return;
-  case NEIGHBOR_EXSTART:
 
-    if ((ps_iface_mtu != ifa->iface->mtu) && (ifa->type != OSPF_IT_VLINK)
-       && (ps_iface_mtu != 0) && (ifa->iface->mtu != 0))
+  case NEIGHBOR_EXSTART:
+    if ((rcv_iface_mtu != ifa->iface->mtu) &&
+       (rcv_iface_mtu != 0) &&
+       (ifa->iface->mtu != 0) && 
+       (ifa->type != OSPF_IT_VLINK))
       log(L_WARN "OSPF: MTU mismatch with neighbour %I on interface %s (remote %d, local %d)",
-         n->ip, ifa->iface->name, ps_iface_mtu, ifa->iface->mtu);
+         n->ip, ifa->iface->name, rcv_iface_mtu, ifa->iface->mtu);
 
-    if ((ps->imms.bit.m && ps->imms.bit.ms && ps->imms.bit.i)
-       && (n->rid > po->router_id) && (size == sizeof(struct ospf_dbdes_packet)))
+    if ((rcv_imms == DBDES_IMMS) &&
+       (n->rid > po->router_id) &&
+       (size == sizeof(struct ospf_dbdes_packet)))
     {
       /* I'm slave! */
-      n->dds = ps_ddseq;
-      n->ddr = ps_ddseq;
-      n->options = ps_options;
-      n->myimms.bit.ms = 0;
-      n->imms.byte = ps->imms.byte;
-      OSPF_TRACE(D_PACKETS, "I'm slave to %I.", n->ip);
+      n->dds = rcv_ddseq;
+      n->ddr = rcv_ddseq;
+      n->options = rcv_options;
+      n->myimms &= ~DBDES_MS;
+      n->imms = rcv_imms;
+      OSPF_TRACE(D_PACKETS, "I'm slave to %I", n->ip);
       ospf_neigh_sm(n, INM_NEGDONE);
       ospf_dbdes_send(n, 1);
       break;
     }
 
-    if (((ps->imms.bit.i == 0) && (ps->imms.bit.ms == 0)) &&
-        (n->rid < po->router_id) && (n->dds == ps_ddseq))
+    if (!(rcv_imms & DBDES_I) &&
+       !(rcv_imms & DBDES_MS) &&
+        (n->rid < po->router_id) &&
+       (n->dds == rcv_ddseq))
     {
       /* I'm master! */
-      n->options = ps_options;
-      n->ddr = ps_ddseq - 1;   /* It will be set corectly a few lines down */
-      n->imms.byte = ps->imms.byte;
-      OSPF_TRACE(D_PACKETS, "I'm master to %I.", n->ip);
+      n->options = rcv_options;
+      n->ddr = rcv_ddseq - 1;  /* It will be set corectly a few lines down */
+      n->imms = rcv_imms;
+      OSPF_TRACE(D_PACKETS, "I'm master to %I", n->ip);
       ospf_neigh_sm(n, INM_NEGDONE);
     }
     else
     {
-      DBG("%s: Nothing happend to %I (imms=%u)\n", p->name, n->ip,
-          ps->imms.byte);
+      DBG("%s: Nothing happend to %I (imms=%d)\n", p->name, n->ip, rcv_imms);
       break;
     }
+
   case NEIGHBOR_EXCHANGE:
-    if ((ps->imms.byte == n->imms.byte) && (ps_options == n->options) &&
-       (ps_ddseq == n->ddr))
+    if ((rcv_imms == n->imms) &&
+       (rcv_options == n->options) &&
+       (rcv_ddseq == n->ddr))
     {
       /* Duplicate packet */
       OSPF_TRACE(D_PACKETS, "Received duplicate dbdes from %I.", n->ip);
-      if (n->myimms.bit.ms == 0)
+      if (!(n->myimms & DBDES_MS))
       {
        /* Slave should retransmit dbdes packet */
        ospf_dbdes_send(n, 0);
@@ -329,47 +383,43 @@ ospf_dbdes_receive(struct ospf_packet *ps_i, struct ospf_iface *ifa,
       return;
     }
 
-    n->ddr = ps_ddseq;
-
-    if (ps->imms.bit.ms != n->imms.bit.ms)     /* M/S bit differs */
+    if ((rcv_imms & DBDES_MS) != (n->imms & DBDES_MS)) /* M/S bit differs */
     {
-      OSPF_TRACE(D_PACKETS, "dbdes - sequence mismatch neighbor %I (bit MS)",
-                n->ip);
+      OSPF_TRACE(D_PACKETS, "dbdes - sequence mismatch neighbor %I (bit MS)", n->ip);
       ospf_neigh_sm(n, INM_SEQMIS);
       break;
     }
 
-    if (ps->imms.bit.i)                /* I bit is set */
+    if (rcv_imms & DBDES_I)            /* I bit is set */
     {
-      OSPF_TRACE(D_PACKETS, "dbdes - sequence mismatch neighbor %I (bit I)",
-                n->ip);
+      OSPF_TRACE(D_PACKETS, "dbdes - sequence mismatch neighbor %I (bit I)", n->ip);
       ospf_neigh_sm(n, INM_SEQMIS);
       break;
     }
 
-    n->imms.byte = ps->imms.byte;
-
-    if (ps_options != n->options)      /* Options differs */
+    if (rcv_options != n->options)     /* Options differs */
     {
-      OSPF_TRACE(D_PACKETS, "dbdes - sequence mismatch neighbor %I (options)",
-                n->ip);
+      OSPF_TRACE(D_PACKETS, "dbdes - sequence mismatch neighbor %I (options)", n->ip);
       ospf_neigh_sm(n, INM_SEQMIS);
       break;
     }
 
-    if (n->myimms.bit.ms)
+    n->ddr = rcv_ddseq;
+    n->imms = rcv_imms;
+
+    if (n->myimms & DBDES_MS)
     {
-      if (ps_ddseq != n->dds)  /* MASTER */
+      if (rcv_ddseq != n->dds) /* MASTER */
       {
-       OSPF_TRACE(D_PACKETS,
-                  "dbdes - sequence mismatch neighbor %I (master)", n->ip);
+       OSPF_TRACE(D_PACKETS, "dbdes - sequence mismatch neighbor %I (master)", n->ip);
        ospf_neigh_sm(n, INM_SEQMIS);
        break;
       }
       n->dds++;
       DBG("Incrementing dds\n");
       ospf_dbdes_reqladd(ps, n);
-      if ((n->myimms.bit.m == 0) && (ps->imms.bit.m == 0))
+      if (!(n->myimms & DBDES_M) &&
+         !(rcv_imms & DBDES_M))
       {
        ospf_neigh_sm(n, INM_EXDONE);
       }
@@ -381,28 +431,28 @@ ospf_dbdes_receive(struct ospf_packet *ps_i, struct ospf_iface *ifa,
     }
     else
     {
-      if (ps_ddseq != (n->dds + 1))    /* SLAVE */
+      if (rcv_ddseq != (n->dds + 1))   /* SLAVE */
       {
-       OSPF_TRACE(D_PACKETS, "dbdes - sequence mismatch neighbor %I (slave)",
-                  n->ip);
+       OSPF_TRACE(D_PACKETS, "dbdes - sequence mismatch neighbor %I (slave)", n->ip);
        ospf_neigh_sm(n, INM_SEQMIS);
        break;
       }
-      n->ddr = ps_ddseq;
-      n->dds = ps_ddseq;
+      n->ddr = rcv_ddseq;
+      n->dds = rcv_ddseq;
       ospf_dbdes_reqladd(ps, n);
       ospf_dbdes_send(n, 1);
     }
-
     break;
+
   case NEIGHBOR_LOADING:
   case NEIGHBOR_FULL:
-    if ((ps->imms.byte == n->imms.byte) && (ps_options == n->options)
-       && (ps_ddseq == n->ddr))
+    if ((rcv_imms == n->imms) &&
+       (rcv_options == n->options) &&
+       (rcv_ddseq == n->ddr))
       /* Only duplicate are accepted */
     {
       OSPF_TRACE(D_PACKETS, "Received duplicate dbdes from %I.", n->ip);
-      if (n->myimms.bit.ms == 0)
+      if (!(n->myimms & DBDES_MS))
       {
        /* Slave should retransmit dbdes packet */
        ospf_dbdes_send(n, 0);
@@ -411,9 +461,8 @@ ospf_dbdes_receive(struct ospf_packet *ps_i, struct ospf_iface *ifa,
     }
     else
     {
-      OSPF_TRACE(D_PACKETS, "dbdes - sequence mismatch neighbor %I (full)",
-                n->ip);
-      DBG("PS=%u, DDR=%u, DDS=%u\n", ps_ddseq, n->ddr, n->dds);
+      OSPF_TRACE(D_PACKETS, "dbdes - sequence mismatch neighbor %I (full)", n->ip);
+      DBG("PS=%u, DDR=%u, DDS=%u\n", rcv_ddseq, n->ddr, n->dds);
       ospf_neigh_sm(n, INM_SEQMIS);
     }
     break;
index f9ba28f659665bb2f12a3ced76d6691e89e92297..b699dd7e59c1c90da3346c51d924469cc29f04b0 100644 (file)
@@ -9,25 +9,26 @@
 #include "ospf.h"
 
 
-#ifdef OSPFv2
-struct ospf_hello_packet
+struct ospf_hello2_packet
 {
-  struct ospf_packet ospf_packet;
-  ip_addr netmask;
+  struct ospf_packet hdr;
+  union ospf_auth auth;
+
+  u32 netmask;
   u16 helloint;
   u8 options;
   u8 priority;
   u32 deadint;
   u32 dr;
   u32 bdr;
-};
-#endif
 
+  u32 neighbors[];
+};
 
-#ifdef OSPFv3
-struct ospf_hello_packet
+struct ospf_hello3_packet
 {
-  struct ospf_packet ospf_packet;
+  struct ospf_packet hdr;
+
   u32 iface_id;
   u8 priority;
   u8 options3;
@@ -37,67 +38,100 @@ struct ospf_hello_packet
   u16 deadint;
   u32 dr;
   u32 bdr;
+
+  u32 neighbors[];
 };
-#endif
 
 
 void
-ospf_hello_receive(struct ospf_packet *ps_i, struct ospf_iface *ifa,
+ospf_hello_receive(struct ospf_packet *pkt, struct ospf_iface *ifa,
                   struct ospf_neighbor *n, ip_addr faddr)
 {
   struct proto_ospf *po = ifa->oa->po;
   struct proto *p = &po->proto;
   char *beg = "OSPF: Bad HELLO packet from ";
-  unsigned int size, i, twoway, peers;
-  u32 tmp;
-  u32 *pnrid;
+  unsigned int size, i, two_way;
 
-  size = ntohs(ps_i->length);
-  if (size < sizeof(struct ospf_hello_packet))
-  {
-    log(L_ERR "%s%I - too short (%u B)", beg, faddr, size);
-    return;
-  }
+  u32 rcv_iface_id, rcv_helloint, rcv_deadint, rcv_dr, rcv_bdr;
+  u8 rcv_options, rcv_priority;
+
+  u32 *neighbors;
+  u32 neigh_count;
 
-  struct ospf_hello_packet *ps = (void *) ps_i;
 
   OSPF_TRACE(D_PACKETS, "HELLO packet received from %I via %s%s", faddr,
-      (ifa->type == OSPF_IT_VLINK ? "vlink-" : ""), ifa->iface->name);
-
-#ifdef OSPFv2
-  ip_addr mask = ps->netmask;
-  ipa_ntoh(mask);
-  if ((ifa->type != OSPF_IT_VLINK) &&
-      (ifa->type != OSPF_IT_PTP) &&
-      !ipa_equal(mask, ipa_mkmask(ifa->addr->pxlen)))
+            (ifa->type == OSPF_IT_VLINK ? "vlink-" : ""), ifa->iface->name);
+
+  size = ntohs(pkt->length);
+
+  if (ospf_is_v2(po))
   {
-    log(L_ERR "%s%I - netmask mismatch (%I)", beg, faddr, mask);
-    return;
+    struct ospf_hello2_packet *ps = (void *) pkt;
+
+    if (size < sizeof(struct ospf_hello2_packet))
+    {
+      log(L_ERR "%s%I - too short (%u B)", beg, faddr, size);
+      return;
+    }
+
+    rcv_iface_id = 0;
+    rcv_helloint = ntohs(ps->helloint);
+    rcv_deadint = ntohl(ps->deadint);
+    rcv_dr = ntohl(ps->dr);
+    rcv_bdr = ntohl(ps->bdr);
+    rcv_options = ps->options;
+    rcv_priority = ps->priority;
+
+    int pxlen = u32_masklen(ntohl(ps->netmask));
+    if ((ifa->type != OSPF_IT_VLINK) &&
+       (ifa->type != OSPF_IT_PTP) &&
+       (pxlen != ifa->addr->pxlen))
+    {
+      log(L_ERR "%s%I - prefix length mismatch (%d)", beg, faddr, pxlen);
+      return;
+    }
+
+    neighbors = ps->neighbors;
+    neigh_count = (size - sizeof(struct ospf_hello2_packet)) / sizeof(u32);
+  }
+  else /* OSPFv3 */
+  {
+    struct ospf_hello3_packet *ps = (void *) pkt;
+
+    if (size < sizeof(struct ospf_hello3_packet))
+    {
+      log(L_ERR "%s%I - too short (%u B)", beg, faddr, size);
+      return;
+    }
+
+    rcv_iface_id = ntohl(ps->iface_id);
+    rcv_helloint = ntohs(ps->helloint);
+    rcv_deadint = ntohs(ps->deadint);
+    rcv_dr = ntohl(ps->dr);
+    rcv_bdr = ntohl(ps->bdr);
+    rcv_options = ps->options;
+    rcv_priority = ps->priority;
+
+    neighbors = ps->neighbors;
+    neigh_count = (size - sizeof(struct ospf_hello3_packet)) / sizeof(u32);
   }
-#endif
 
-  tmp = ntohs(ps->helloint);
-  if (tmp != ifa->helloint)
+  if (rcv_helloint != ifa->helloint)
   {
-    log(L_ERR "%s%I - hello interval mismatch (%d)", beg, faddr, tmp);
+    log(L_ERR "%s%I - hello interval mismatch (%d)", beg, faddr, rcv_helloint);
     return;
   }
 
-#ifdef OSPFv2
-  tmp = ntohl(ps->deadint);
-#else /* OSPFv3 */
-  tmp = ntohs(ps->deadint);
-#endif
-  if (tmp != ifa->deadint)
+  if (rcv_deadint != ifa->deadint)
   {
-    log(L_ERR "%s%I - dead interval mismatch (%d)", beg, faddr, tmp);
+    log(L_ERR "%s%I - dead interval mismatch (%d)", beg, faddr, rcv_deadint);
     return;
   }
 
   /* Check whether bits E, N match */
-  if ((ps->options ^ ifa->oa->options) & (OPT_E | OPT_N))
+  if ((rcv_options ^ ifa->oa->options) & (OPT_E | OPT_N))
   {
-    log(L_ERR "%s%I - area type mismatch (%x)", beg, faddr, ps->options);
+    log(L_ERR "%s%I - area type mismatch (%x)", beg, faddr, rcv_options);
     return;
   }
 
@@ -115,8 +149,8 @@ ospf_hello_receive(struct ospf_packet *ps_i, struct ospf_iface *ifa,
       }
 
       if (nn && (ifa->type == OSPF_IT_NBMA) &&
-         (((ps->priority == 0) && nn->eligible) ||
-          ((ps->priority > 0) && !nn->eligible)))
+         (((rcv_priority == 0) && nn->eligible) ||
+          ((rcv_priority > 0) && !nn->eligible)))
       {
        log(L_ERR "Eligibility mismatch for neighbor: %I on %s",
            faddr, ifa->iface->name);
@@ -132,85 +166,67 @@ ospf_hello_receive(struct ospf_packet *ps_i, struct ospf_iface *ifa,
 
     n = ospf_neighbor_new(ifa);
 
-    n->rid = ntohl(((struct ospf_packet *) ps)->routerid);
+    n->rid = ntohl(pkt->routerid);
     n->ip = faddr;
-    n->dr = ntohl(ps->dr);
-    n->bdr = ntohl(ps->bdr);
-    n->priority = ps->priority;
-#ifdef OSPFv3
-    n->iface_id = ntohl(ps->iface_id);
-#endif
+    n->dr = rcv_dr;
+    n->bdr = rcv_bdr;
+    n->priority = rcv_priority;
+    n->iface_id = rcv_iface_id;
   }
   ospf_neigh_sm(n, INM_HELLOREC);
 
-  pnrid = (u32 *) ((struct ospf_hello_packet *) (ps + 1));
-
-  peers = (size - sizeof(struct ospf_hello_packet))/ sizeof(u32);
-
-  twoway = 0;
-  for (i = 0; i < peers; i++)
+  two_way = 0;
+  for (i = 0; i < neigh_count; i++)
   {
-    if (ntohl(pnrid[i]) == po->router_id)
+    if (ntohl(neighbors[i]) == po->router_id)
     {
       DBG("%s: Twoway received from %I\n", p->name, faddr);
       ospf_neigh_sm(n, INM_2WAYREC);
-      twoway = 1;
+      two_way = 1;
       break;
     }
   }
-
-  if (!twoway)
+  if (!two_way)
     ospf_neigh_sm(n, INM_1WAYREC);
 
-  u32 olddr = n->dr;
-  u32 oldbdr = n->bdr;
-  u32 oldpriority = n->priority;
-#ifdef OSPFv3
-  u32 oldiface_id = n->iface_id;
-#endif
-
-  n->dr = ntohl(ps->dr);
-  n->bdr = ntohl(ps->bdr);
-  n->priority = ps->priority;
-#ifdef OSPFv3
-  n->iface_id = ntohl(ps->iface_id);
-#endif
+  u32 old_dr = n->dr;
+  u32 old_bdr = n->bdr;
+  u32 old_priority = n->priority;
+  u32 old_iface_id = n->iface_id;
 
+  n->dr = rcv_dr;
+  n->bdr = rcv_bdr;
+  n->priority = rcv_priority;
+  n->iface_id = rcv_iface_id;
 
   /* Check priority change */
   if (n->state >= NEIGHBOR_2WAY)
   {
-#ifdef OSPFv2
-    u32 neigh = ipa_to_u32(n->ip);
-#else /* OSPFv3 */
-    u32 neigh = n->rid;
-#endif
+    u32 n_id = ospf_is_v2(po) ? ipa_to_u32(n->ip) : n->rid;
 
-    if (n->priority != oldpriority)
+    if (n->priority != old_priority)
       ospf_iface_sm(ifa, ISM_NEICH);
 
-#ifdef OSPFv3
-    if (n->iface_id != oldiface_id)
+    if (n->iface_id != old_iface_id)
       ospf_iface_sm(ifa, ISM_NEICH);
-#endif
 
     /* Neighbor is declaring itself ad DR and there is no BDR */
-    if ((n->dr == neigh) && (n->bdr == 0)
+    if ((n->dr == n_id) && (n->bdr == 0)
        && (n->state != NEIGHBOR_FULL))
       ospf_iface_sm(ifa, ISM_BACKS);
 
     /* Neighbor is declaring itself as BDR */
-    if ((n->bdr == neigh) && (n->state != NEIGHBOR_FULL))
+    if ((n->bdr == n_id) && (n->state != NEIGHBOR_FULL))
       ospf_iface_sm(ifa, ISM_BACKS);
 
     /* Neighbor is newly declaring itself as DR or BDR */
-    if (((n->dr == neigh) && (n->dr != olddr))
-       || ((n->bdr == neigh) && (n->bdr != oldbdr)))
+    if (((n->dr == n_id) && (n->dr != old_dr))
+       || ((n->bdr == n_id) && (n->bdr != old_bdr)))
       ospf_iface_sm(ifa, ISM_NEICH);
 
     /* Neighbor is no more declaring itself as DR or BDR */
-    if (((olddr == neigh) && (n->dr != olddr))
-       || ((oldbdr == neigh) && (n->bdr != oldbdr)))
+    if (((old_dr == n_id) && (n->dr != old_dr))
+       || ((old_bdr == n_id) && (n->bdr != old_bdr)))
       ospf_iface_sm(ifa, ISM_NEICH);
   }
 
@@ -225,13 +241,14 @@ ospf_hello_receive(struct ospf_packet *ps_i, struct ospf_iface *ifa,
 void
 ospf_hello_send(struct ospf_iface *ifa, int kind, struct ospf_neighbor *dirn)
 {
-  struct ospf_hello_packet *pkt;
-  struct ospf_packet *op;
-  struct proto *p;
+  struct proto_ospf *po = ifa->oa->po;
+  struct proto *p = &po->proto;
+  struct ospf_packet *pkt;
   struct ospf_neighbor *neigh, *n1;
-  u16 length;
-  int i;
   struct nbma_node *nb;
+  u32 *neighbors;
+  u16 length;
+  int i, max;
 
   if (ifa->state <= OSPF_IS_LOOP)
     return;
@@ -239,65 +256,69 @@ ospf_hello_send(struct ospf_iface *ifa, int kind, struct ospf_neighbor *dirn)
   if (ifa->stub)
     return;                    /* Don't send any packet on stub iface */
 
-  p = (struct proto *) (ifa->oa->po);
   DBG("%s: Hello/Poll timer fired on interface %s with IP %I\n",
       p->name, ifa->iface->name, ifa->addr->ip);
 
-  /* Now we should send a hello packet */
   pkt = ospf_tx_buffer(ifa);
-  op = &pkt->ospf_packet;
-
-  /* Now fill ospf_hello header */
   ospf_pkt_fill_hdr(ifa, pkt, HELLO_P);
 
-#ifdef OSPFv2
-  pkt->netmask = ipa_mkmask(ifa->addr->pxlen);
-  ipa_hton(pkt->netmask);
-  if ((ifa->type == OSPF_IT_VLINK) || (ifa->type == OSPF_IT_PTP))
-    pkt->netmask = IPA_NONE;
-#endif
-
-  pkt->helloint = ntohs(ifa->helloint);
-  pkt->priority = ifa->priority;
-
-#ifdef OSPFv3
-  pkt->iface_id = htonl(ifa->iface->index);
-
-  pkt->options3 = ifa->oa->options >> 16;
-  pkt->options2 = ifa->oa->options >> 8;
-#endif
-  pkt->options = ifa->oa->options;
-
-#ifdef OSPFv2
-  pkt->deadint = htonl(ifa->deadint);
-  pkt->dr = htonl(ipa_to_u32(ifa->drip));
-  pkt->bdr = htonl(ipa_to_u32(ifa->bdrip));
-#else /* OSPFv3 */
-  pkt->deadint = htons(ifa->deadint);
-  pkt->dr = htonl(ifa->drid);
-  pkt->bdr = htonl(ifa->bdrid);
-#endif
+  if (ospf_is_v2(po))
+  {
+    struct ospf_hello2_packet *ps = (void *) pkt;
+
+    ps->netmask = htonl(u32_mkmask(ifa->addr->pxlen));
+
+    if ((ifa->type == OSPF_IT_VLINK) || (ifa->type == OSPF_IT_PTP))
+      ps->netmask = 0;
+
+    ps->helloint = ntohs(ifa->helloint);
+    ps->options = ifa->oa->options;
+    ps->priority = ifa->priority;
+    ps->deadint = htonl(ifa->deadint);
+    ps->dr = htonl(ipa_to_u32(ifa->drip));
+    ps->bdr = htonl(ipa_to_u32(ifa->bdrip));
+
+    length = sizeof(struct ospf_hello2_packet);
+    neighbors = ps->neighbors;
+  }
+  else
+  {
+    struct ospf_hello3_packet *ps = (void *) pkt;
+
+    ps->iface_id = htonl(ifa->iface->index);
+    ps->priority = ifa->priority;
+    ps->options3 = ifa->oa->options >> 16;
+    ps->options2 = ifa->oa->options >> 8;
+    ps->options = ifa->oa->options;
+    ps->helloint = ntohs(ifa->helloint);
+    ps->deadint = htons(ifa->deadint);
+    ps->dr = htonl(ifa->drid);
+    ps->bdr = htonl(ifa->bdrid);
+
+    length = sizeof(struct ospf_hello3_packet);
+    neighbors = ps->neighbors;
+  }
 
-  /* Fill all neighbors */
   i = 0;
+  max = (ospf_pkt_bufsize(ifa) - length) / sizeof(u32);
 
+  /* Fill all neighbors */
   if (kind != OHS_SHUTDOWN)
   {
-    u32 *pp = (u32 *) (((u8 *) pkt) + sizeof(struct ospf_hello_packet));
     WALK_LIST(neigh, ifa->neigh_list)
     {
-      if ((i+1) * sizeof(u32) + sizeof(struct ospf_hello_packet) > ospf_pkt_bufsize(ifa))
+      if (i == max)
       {
        log(L_WARN "%s: Too many neighbors on interface %s", p->name, ifa->iface->name);
        break;
       }
-      *(pp + i) = htonl(neigh->rid);
+      neighbors[i] = htonl(neigh->rid);
       i++;
     }
   }
 
-  length = sizeof(struct ospf_hello_packet) + i * sizeof(u32);
-  op->length = htons(length);
+  length += i * sizeof(u32);
+  pkt->length = htons(length);
 
   switch(ifa->type)
   {
index a6a0c6c11efa7ddf5e8e96d22d12440460ba31ff..e004c05e785a8dd3fe3591a39013c106cb59d033 100644 (file)
@@ -34,7 +34,7 @@ static void
 wait_timer_hook(timer * timer)
 {
   struct ospf_iface *ifa = (struct ospf_iface *) timer->data;
-  struct proto *p = &ifa->oa->po->proto;
+  struct proto_ospf *po = ifa->oa->po;
 
   OSPF_TRACE(D_EVENTS, "Wait timer fired on interface %s.", ifa->iface->name);
   ospf_iface_sm(ifa, ISM_WAITF);
@@ -172,9 +172,8 @@ ospf_sk_leave_dr(struct ospf_iface *ifa)
 static void
 ospf_iface_down(struct ospf_iface *ifa)
 {
-  struct ospf_neighbor *n, *nx;
   struct proto_ospf *po = ifa->oa->po;
-  struct proto *p = &po->proto;
+  struct ospf_neighbor *n, *nx;
   struct ospf_iface *iff;
 
   if (ifa->type != OSPF_IT_VLINK)
@@ -232,7 +231,8 @@ ospf_iface_down(struct ospf_iface *ifa)
 void
 ospf_iface_remove(struct ospf_iface *ifa)
 {
-  struct proto *p = &ifa->oa->po->proto;
+  struct proto_ospf *po = ifa->oa->po;
+
   if (ifa->type == OSPF_IT_VLINK)
     OSPF_TRACE(D_EVENTS, "Removing vlink to %R via area %R", ifa->vid, ifa->voa->areaid);
 
@@ -261,7 +261,6 @@ void
 ospf_iface_chstate(struct ospf_iface *ifa, u8 state)
 {
   struct proto_ospf *po = ifa->oa->po;
-  struct proto *p = &po->proto;
   u8 oldstate = ifa->state;
 
   if (oldstate == state)
@@ -490,7 +489,7 @@ ospf_iface_stubby(struct ospf_iface_patt *ip, struct ifa *addr)
 void
 ospf_iface_new(struct ospf_area *oa, struct ifa *addr, struct ospf_iface_patt *ip)
 {
-  struct proto *p = &oa->po->proto;
+  struct proto_ospf *po = oa->po;
   struct iface *iface = addr ? addr->iface : NULL;
   struct pool *pool;
 
@@ -511,7 +510,7 @@ ospf_iface_new(struct ospf_area *oa, struct ifa *addr, struct ospf_iface_patt *i
 #endif
   }
 
-  pool = rp_new(p->pool, "OSPF Interface");
+  pool = rp_new(po->proto.pool, "OSPF Interface");
   ifa = mb_allocz(pool, sizeof(struct ospf_iface));
   ifa->iface = iface;
   ifa->addr = addr;
@@ -625,7 +624,7 @@ ospf_iface_change_timer(timer *tm, unsigned val)
 int
 ospf_iface_reconfigure(struct ospf_iface *ifa, struct ospf_iface_patt *new)
 {
-  struct proto *p = &ifa->oa->po->proto;
+  struct proto_ospf *po = ifa->oa->po;
   struct nbma_node *nb, *nbx;
   char *ifname = (ifa->type != OSPF_IT_VLINK) ? ifa->iface->name : "vlink";
 
@@ -1047,7 +1046,6 @@ ospf_ifaces_reconfigure(struct ospf_area *oa, struct ospf_area_config *nac)
 static void
 ospf_iface_change_mtu(struct proto_ospf *po, struct ospf_iface *ifa)
 {
-  struct proto *p = &po->proto;
   struct ospf_packet *op;
   struct ospf_neighbor *n;
   OSPF_TRACE(D_EVENTS, "Changing MTU on interface %s", ifa->iface->name);
index 00c50cafb4d8884a72109fdc3c12a1a4825ab151..dc59dde081047b38538f1dd9a946196356045d75 100644 (file)
@@ -9,29 +9,38 @@
 #include "ospf.h"
 
 
+/*
 struct ospf_lsack_packet
 {
-  struct ospf_packet ospf_packet;
-  struct ospf_lsa_header lsh[];
-};
+  struct ospf_packet hdr;
+  // union ospf_auth auth;
 
-
-char *s_queue[] = { "direct", "delayed" };
+  struct ospf_lsa_header lsas[];
+};
+*/
 
 
-static void ospf_dump_lsack(struct proto *p, struct ospf_lsack_packet *pkt)
+static void
+ospf_lsack_body(struct proto_ospf *po, struct ospf_packet *pkt, unsigned plen,
+               struct ospf_lsa_header **body, unsigned *count)
 {
-  struct ospf_packet *op = &pkt->ospf_packet;
+  unsigned hdrlen = ospf_pkt_hdrlen(po);
+  *body = ((void *) pkt) + hdrlen;
+  *count = (plen - hdrlen) / sizeof(struct ospf_lsa_header);
+}
 
-  ASSERT(op->type == LSACK_P);
-  ospf_dump_common(p, op);
+static void
+ospf_lsack_dump(struct proto_ospf *po, struct ospf_packet *pkt)
+{
+  struct ospf_lsa_header *lsas;
+  unsigned i, lsa_count;
 
-  unsigned int i, j;
-  j = (ntohs(op->length) - sizeof(struct ospf_lsack_packet)) /
-    sizeof(struct ospf_lsa_header);
+  ASSERT(pkt->type == LSACK_P);
+  ospf_dump_common(po, pkt);
 
-  for (i = 0; i < j; i++)
-    ospf_dump_lsahdr(p, pkt->lsh + i);
+  ospf_lsack_body(po, pkt, ntohs(pkt->length), &lsas, &lsa_count);
+  for (i = 0; i < lsa_count; i++)
+    ospf_dump_lsahdr(po, lsas + i);
 }
 
 
@@ -42,87 +51,47 @@ static void ospf_dump_lsack(struct proto *p, struct ospf_lsack_packet *pkt)
  */
 
 void
-ospf_lsack_enqueue(struct ospf_neighbor *n, struct ospf_lsa_header *h,
-                  int queue)
+ospf_lsack_enqueue(struct ospf_neighbor *n, struct ospf_lsa_header *h, int queue)
 {
   struct lsah_n *no = mb_alloc(n->pool, sizeof(struct lsah_n));
   memcpy(&no->lsa, h, sizeof(struct ospf_lsa_header));
   add_tail(&n->ackl[queue], NODE no);
-  DBG("Adding (%s) ack for %R, ID: %R, RT: %R, Type: %u\n", s_queue[queue],
+  DBG("Adding (%s) ack for %R, ID: %R, RT: %R, Type: %u\n",
+      (queue == ACKL_DIRECT) ? "direct" : "delayed",
       n->rid, ntohl(h->id), ntohl(h->rt), h->type);
 }
 
-void
-ospf_lsack_send(struct ospf_neighbor *n, int queue)
+static inline void
+ospf_lsack_send_one(struct ospf_neighbor *n, int queue)
 {
-  struct ospf_packet *op;
-  struct ospf_lsack_packet *pk;
-  u16 len, i = 0;
-  struct ospf_lsa_header *h;
-  struct lsah_n *no;
   struct ospf_iface *ifa = n->ifa;
-  struct proto *p = &n->ifa->oa->po->proto;
-
-  if (EMPTY_LIST(n->ackl[queue]))
-    return;
+  struct proto_ospf *po = ifa->oa->po;
+  struct ospf_lsa_header *lsas;
+  struct ospf_packet *pkt;
+  struct lsah_n *no;
+  unsigned i, lsa_max, length;
 
-  pk = ospf_tx_buffer(ifa);
-  op = &pk->ospf_packet;
 
-  ospf_pkt_fill_hdr(n->ifa, pk, LSACK_P);
-  h = pk->lsh;
+  pkt = ospf_tx_buffer(ifa);
+  ospf_pkt_fill_hdr(ifa, pkt, LSACK_P);
+  ospf_lsack_body(po, pkt, ospf_pkt_maxsize(ifa), &lsas, &lsa_max);
 
-  while (!EMPTY_LIST(n->ackl[queue]))
+  for (i = 0; i < lsa_max && !EMPTY_LIST(n->ackl[queue]); i++)
   {
     no = (struct lsah_n *) HEAD(n->ackl[queue]);
-    memcpy(h + i, &no->lsa, sizeof(struct ospf_lsa_header));
-    DBG("Iter %u ID: %R, RT: %R, Type: %04x\n", i, ntohl((h + i)->id),
-       ntohl((h + i)->rt), (h + i)->type);
-    i++;
+    memcpy(&lsas[i], &no->lsa, sizeof(struct ospf_lsa_header));
+    DBG("Iter %u ID: %R, RT: %R, Type: %04x\n",
+       i, ntohl(lsas[i].id), ntohl(lsas[i].rt), lsas[i].type);
     rem_node(NODE no);
     mb_free(no);
-    if ((i * sizeof(struct ospf_lsa_header) +
-        sizeof(struct ospf_lsack_packet)) > ospf_pkt_maxsize(n->ifa))
-    {
-      if (!EMPTY_LIST(n->ackl[queue]))
-      {
-       len =
-         sizeof(struct ospf_lsack_packet) +
-         i * sizeof(struct ospf_lsa_header);
-       op->length = htons(len);
-       DBG("Sending and continuing! Len=%u\n", len);
-
-       OSPF_PACKET(ospf_dump_lsack, pk, "LSACK packet sent via %s", ifa->iface->name);
-
-       if (ifa->type == OSPF_IT_BCAST)
-       {
-         if ((ifa->state == OSPF_IS_DR) || (ifa->state == OSPF_IS_BACKUP))
-           ospf_send_to_all(ifa);
-         else if (ifa->cf->real_bcast)
-           ospf_send_to_bdr(ifa);
-         else
-           ospf_send_to(ifa, AllDRouters);
-       }
-       else
-       {
-         if ((ifa->state == OSPF_IS_DR) || (ifa->state == OSPF_IS_BACKUP))
-           ospf_send_to_agt(ifa, NEIGHBOR_EXCHANGE);
-         else
-           ospf_send_to_bdr(ifa);
-       }
-
-       ospf_pkt_fill_hdr(n->ifa, pk, LSACK_P);
-       i = 0;
-      }
-    }
   }
 
-  len = sizeof(struct ospf_lsack_packet) + i * sizeof(struct ospf_lsa_header);
-  op->length = htons(len);
-  DBG("Sending! Len=%u\n", len);
+  length = ospf_pkt_hdrlen(po) + i * sizeof(struct ospf_lsa_header);
+  pkt->length = htons(length);
 
-  OSPF_PACKET(ospf_dump_lsack, pk, "LSACK packet sent via %s", ifa->iface->name);
+  OSPF_PACKET(ospf_lsack_dump, pkt, "LSACK packet sent via %s", ifa->iface->name);
 
+  /* XXXX this is very strange */
   if (ifa->type == OSPF_IT_BCAST)
   {
     if ((ifa->state == OSPF_IS_DR) || (ifa->state == OSPF_IS_BACKUP))
@@ -134,37 +103,46 @@ ospf_lsack_send(struct ospf_neighbor *n, int queue)
   }
   else
     ospf_send_to_agt(ifa, NEIGHBOR_EXCHANGE);
+
+  /*
+    if ((ifa->state == OSPF_IS_DR) || (ifa->state == OSPF_IS_BACKUP))
+      ospf_send_to_agt(ifa, NEIGHBOR_EXCHANGE);
+    else
+      ospf_send_to_bdr(ifa);
+  */
+}
+
+void
+ospf_lsack_send(struct ospf_neighbor *n, int queue)
+{
+  while (!EMPTY_LIST(n->ackl[queue]))
+    ospf_lsack_send_one(n, queue);
 }
 
 void
-ospf_lsack_receive(struct ospf_packet *ps_i, struct ospf_iface *ifa,
+ospf_lsack_receive(struct ospf_packet *pkt, struct ospf_iface *ifa,
                   struct ospf_neighbor *n)
 {
-  struct proto *p = &ifa->oa->po->proto;
-  struct ospf_lsa_header lsa;
+  struct proto_ospf *po = ifa->oa->po;
+  struct ospf_lsa_header lsa, *lsas;
   struct top_hash_entry *en;
-  unsigned int i, lsano;
+  unsigned i, lsa_count;
 
-  unsigned int size = ntohs(ps_i->length);
-  if (size < sizeof(struct ospf_lsack_packet))
-  {
-    log(L_ERR "Bad OSPF LSACK packet from %I -  too short (%u B)", n->ip, size);
-    return;
-  }
 
-  struct ospf_lsack_packet *ps = (void *) ps_i;
-  OSPF_PACKET(ospf_dump_lsack, ps, "LSACK packet received from %I via %s", n->ip, ifa->iface->name);
+  /* No need to check length, lsack has only basic header */
 
-  ospf_neigh_sm(n, INM_HELLOREC);
+  OSPF_PACKET(ospf_lsack_dump, pkt, "LSACK packet received from %I via %s",
+             n->ip, ifa->iface->name);
 
   if (n->state < NEIGHBOR_EXCHANGE)
     return;
 
-  lsano = (size - sizeof(struct ospf_lsack_packet)) /
-    sizeof(struct ospf_lsa_header);
-  for (i = 0; i < lsano; i++)
+  ospf_neigh_sm(n, INM_HELLOREC);      /* Not in RFC */
+
+  ospf_lsack_body(po, pkt, ntohs(pkt->length), &lsas, &lsa_count);
+  for (i = 0; i < lsa_count; i++)
   {
-    ntohlsah(ps->lsh + i, &lsa);
+    ntohlsah(&lsas[i], &lsa);
     u32 dom = ospf_lsa_domain(lsa.type, n->ifa);
     if ((en = ospf_hash_find_header(n->lsrth, dom, &lsa)) == NULL)
       continue;                        /* pg 155 */
index bcf7bcdddf3e3a7242d61b8b9d221514c1eb27c5..00dd2893a6e14965eae8f873b8a9447943b90305 100644 (file)
 void
 flush_lsa(struct top_hash_entry *en, struct proto_ospf *po)
 {
-  struct proto *p = &po->proto;
-
   OSPF_TRACE(D_EVENTS,
             "Going to remove LSA Type: %04x, Id: %R, Rt: %R, Age: %u, Seqno: 0x%x",
-            en->lsa.type, en->lsa.id, en->lsa.rt, en->lsa.age, en->lsa.sn);
+            en->lsa_type, en->lsa.id, en->lsa.rt, en->lsa.age, en->lsa.sn);
   s_rem_node(SNODE en);
   if (en->lsa_body != NULL)
     mb_free(en->lsa_body);
@@ -30,7 +28,7 @@ ospf_flush_area(struct proto_ospf *po, u32 areaid)
 
   WALK_SLIST_DELSAFE(en, nxt, po->lsal)
   {
-    if ((LSA_SCOPE(&en->lsa) == LSA_SCOPE_AREA) && (en->domain == areaid))
+    if ((LSA_SCOPE(en->lsa_type) == LSA_SCOPE_AREA) && (en->domain == areaid))
       flush_lsa(en, po);
   }
 }
@@ -53,7 +51,6 @@ ospf_flush_area(struct proto_ospf *po, u32 areaid)
 void
 ospf_age(struct proto_ospf *po)
 {
-  struct proto *p = &po->proto;
   struct top_hash_entry *en, *nxt;
   int flush = can_flush_lsa(po);
 
@@ -68,7 +65,7 @@ ospf_age(struct proto_ospf *po)
     if ((en->lsa.rt == po->router_id) && (en->lsa.age >= LSREFRESHTIME))
     {
       OSPF_TRACE(D_EVENTS, "Refreshing my LSA: Type: %u, Id: %R, Rt: %R",
-                en->lsa.type, en->lsa.id, en->lsa.rt);
+                en->lsa_type, en->lsa.id, en->lsa.rt);
       en->lsa.sn++;
       en->lsa.age = 0;
       en->inst_t = now;
@@ -95,10 +92,7 @@ void
 htonlsah(struct ospf_lsa_header *h, struct ospf_lsa_header *n)
 {
   n->age = htons(h->age);
-#ifdef OSPFv2
-  n->options = h->options;
-#endif
-  n->type = htont(h->type);
+  n->type_raw = htont(h->type_raw);
   n->id = htonl(h->id);
   n->rt = htonl(h->rt);
   n->sn = htonl(h->sn);
@@ -110,10 +104,7 @@ void
 ntohlsah(struct ospf_lsa_header *n, struct ospf_lsa_header *h)
 {
   h->age = ntohs(n->age);
-#ifdef OSPFv2
-  h->options = n->options;
-#endif
-  h->type = ntoht(n->type);
+  h->type_raw = ntoht(n->type_raw);
   h->id = ntohl(n->id);
   h->rt = ntohl(n->rt);
   h->sn = ntohl(n->sn);
@@ -292,6 +283,147 @@ lsa_comp(struct ospf_lsa_header *l1, struct ospf_lsa_header *l2)
   return CMP_SAME;
 }
 
+
+static inline int
+lsa_walk_rt2(struct ospf_lsa_rt_walk *rt)
+{
+  if (rt->buf >= rt->bufend)
+    return 0;
+
+  struct ospf_lsa_rt2_link *l = rt->buf;
+  rt->buf += sizeof(struct ospf_lsa_rt2_link) + l->no_tos * sizeof(struct ospf_lsa_rt2_tos);
+
+  rt->type = l->type;
+  rt->metric = l->metric;
+  rt->id = l->id;
+  rt->data = l->data;
+  return 1;
+}
+
+static inline int
+lsa_walk_rt3(struct ospf_lsa_rt_walk *rt)
+{
+  while (rt->buf >= rt->bufend)
+  {
+    rt->en = ospf_hash_find_rt_next(rt->en);
+    if (!rt->en)
+      return 0;
+
+    rt->buf = rt->en->lsa_body;
+    rt->bufend = rt->buf + rt->en->lsa.length - sizeof(struct ospf_lsa_header);
+    rt->buf += sizeof(struct ospf_lsa_rt);
+  }
+
+  struct ospf_lsa_rt3_link *l = rt->buf;
+  rt->buf += sizeof(struct ospf_lsa_rt3_link);
+
+  rt->type = l->type;
+  rt->metric = l->metric;
+  rt->lif = l->lif;
+  rt->nif = l->nif;
+  rt->id = l->id;
+  return 1;
+}
+
+void
+lsa_walk_rt_init(struct proto_ospf *po, struct top_hash_entry *act, struct ospf_lsa_rt_walk *rt)
+{
+  rt->ospf2 = ospf_is_v2(po);
+  rt->id = rt->data = rt->lif = rt->nif = 0;
+
+  if (rt->ospf2)
+    rt->en = act;
+  else
+    rt->en = ospf_hash_find_rt_first(po->gr, act->domain, act->lsa.rt);
+
+  rt->buf = rt->en->lsa_body;
+  rt->bufend = rt->buf + rt->en->lsa.length - sizeof(struct ospf_lsa_header);
+  rt->buf += sizeof(struct ospf_lsa_rt);
+}
+
+int
+lsa_walk_rt(struct ospf_lsa_rt_walk *rt)
+{
+  return rt->ospf2 ? lsa_walk_rt2(rt) : lsa_walk_rt3(rt);
+}
+
+
+void
+lsa_parse_sum_net(struct top_hash_entry *en, int ospf2, ip_addr *ip, int *pxlen, u8 *pxopts, u32 *metric)
+{
+  if (ospf2)
+  {
+    struct ospf_lsa_sum2 *ls = en->lsa_body;
+    *ip = ipa_from_u32(en->lsa.id & ls->netmask);
+    *pxlen = u32_masklen(ls->netmask);
+    *pxopts = 0;
+    *metric = ls->metric & METRIC_MASK;
+  }
+  else
+  {
+    struct ospf_lsa_sum3_net *ls = en->lsa_body;
+    u16 rest;
+    lsa_get_ipv6_prefix(ls->prefix, ip, pxlen, pxopts, &rest);
+    *metric = ls->metric & METRIC_MASK;
+  }
+}
+
+void
+lsa_parse_sum_rt(struct top_hash_entry *en, int ospf2, u32 *drid, u32 *metric, u32 *options)
+{
+  if (ospf2)
+  {
+    struct ospf_lsa_sum2 *ls = en->lsa_body;
+    *drid = en->lsa.id;
+    *metric = ls->metric & METRIC_MASK;
+    *options = 0;
+  }
+  else
+  {
+    struct ospf_lsa_sum3_rt *ls = en->lsa_body;
+    *drid = ls->drid;
+    *metric = ls->metric & METRIC_MASK;
+    *options = ls->options & OPTIONS_MASK;
+  }
+}
+
+void
+lsa_parse_ext(struct top_hash_entry *en, int ospf2, struct ospf_lsa_ext_local *rt)
+{
+  if (ospf2)
+  {
+    struct ospf_lsa_ext2 *ext = en->lsa_body;
+    rt->ip = ipa_from_u32(en->lsa.id & ext->netmask);
+    rt->pxlen = u32_masklen(ext->netmask);
+    rt->pxopts = 0;
+    rt->metric = ext->metric & METRIC_MASK;
+    rt->ebit = ext->metric & LSA_EXT2_EBIT;
+
+    rt->fbit = ip4_nonzero(ext->fwaddr);
+    rt->fwaddr = ipa_from_ip4(ext->fwaddr);
+
+    rt->tag = ext->tag;
+    rt->propagate = lsa_get_options(&en->lsa) & OPT_P;
+  }
+  else
+  {
+    struct ospf_lsa_ext3 *ext = en->lsa_body;
+    u16 rest;
+    u32 *buf = lsa_get_ipv6_prefix(ext->rest, &rt->ip, &rt->pxlen, &rt->pxopts, &rest);
+    rt->metric = ext->metric & METRIC_MASK;
+    rt->ebit = ext->metric & LSA_EXT3_EBIT;
+
+    rt->fbit = ext->metric & LSA_EXT3_FBIT;
+    if (rt->fbit)
+      buf = lsa_get_ipv6_addr(buf, &rt->fwaddr);
+    else 
+      rt->fwaddr = IPA_NONE;
+
+    rt->tag = (ext->metric & LSA_EXT3_TBIT) ? *buf++ : 0;
+    rt->propagate = rt->pxopts & OPT_PX_P;
+  }
+}
+
 #define HDRLEN sizeof(struct ospf_lsa_header)
 
 static int
@@ -372,16 +504,16 @@ pxlen(u32 *buf)
 }
 
 static int
-lsa_validate_sum_net(struct ospf_lsa_header *lsa, struct ospf_lsa_sum_net *body)
+lsa_validate_sum_net(struct ospf_lsa_header *lsa, struct ospf_lsa_sum3_net *body)
 {
-  if (lsa->length < (HDRLEN + sizeof(struct ospf_lsa_sum_net) + 4))
+  if (lsa->length < (HDRLEN + sizeof(struct ospf_lsa_sum3_net) + 4))
     return 0;
 
   u8 pxl = pxlen(body->prefix);
   if (pxl > MAX_PREFIX_LENGTH)
     return 0;
 
-  if (lsa->length != (HDRLEN + sizeof(struct ospf_lsa_sum_net) + 
+  if (lsa->length != (HDRLEN + sizeof(struct ospf_lsa_sum3_net) + 
                      IPV6_PREFIX_SPACE(pxl)))
     return 0;
 
@@ -390,18 +522,18 @@ lsa_validate_sum_net(struct ospf_lsa_header *lsa, struct ospf_lsa_sum_net *body)
 
 
 static int
-lsa_validate_sum_rt(struct ospf_lsa_header *lsa, struct ospf_lsa_sum_rt *body)
+lsa_validate_sum_rt(struct ospf_lsa_header *lsa, struct ospf_lsa_sum3_rt *body)
 {
-  if (lsa->length != (HDRLEN + sizeof(struct ospf_lsa_sum_rt)))
+  if (lsa->length != (HDRLEN + sizeof(struct ospf_lsa_sum3_rt)))
     return 0;
 
   return 1;
 }
 
 static int
-lsa_validate_ext(struct ospf_lsa_header *lsa, struct ospf_lsa_ext *body)
+lsa_validate_ext(struct ospf_lsa_header *lsa, struct ospf_lsa_ext3 *body)
 {
-  if (lsa->length < (HDRLEN + sizeof(struct ospf_lsa_ext) + 4))
+  if (lsa->length < (HDRLEN + sizeof(struct ospf_lsa_ext3) + 4))
     return 0;
 
   u8 pxl = pxlen(body->rest);
@@ -409,14 +541,14 @@ lsa_validate_ext(struct ospf_lsa_header *lsa, struct ospf_lsa_ext *body)
     return 0;
 
   int len = IPV6_PREFIX_SPACE(pxl);
-  if (body->metric & LSA_EXT_FBIT) // forwardinf address
+  if (body->metric & LSA_EXT3_FBIT) // forwardinf address
     len += 16;
-  if (body->metric & LSA_EXT_TBIT) // route tag
+  if (body->metric & LSA_EXT3_TBIT) // route tag
     len += 4;
   if (*body->rest & 0xFFFF) // referenced LS type field
     len += 4;
 
-  if (lsa->length != (HDRLEN + sizeof(struct ospf_lsa_ext) + len))
+  if (lsa->length != (HDRLEN + sizeof(struct ospf_lsa_ext3) + len))
     return 0;
 
   return 1;
@@ -492,12 +624,10 @@ lsa_validate(struct ospf_lsa_header *lsa, void *body)
     case LSA_T_EXT:
     case LSA_T_NSSA:
       return lsa_validate_ext(lsa, body);
-#ifdef OSPFv3
     case LSA_T_LINK:
       return lsa_validate_link(lsa, body);
     case LSA_T_PREFIX:
       return lsa_validate_prefix(lsa, body);
-#endif
     default:
       /* In OSPFv3, unknown LSAs are OK,
         In OSPFv2, unknown LSAs are already rejected
index 0b556ec5ead3dfbf97facd8d45d80223f4a36d51..3bdd814f6a1ca0f5ca68d9c4f8feb50fa6f94cae 100644 (file)
@@ -26,12 +26,25 @@ static inline void htonlsab1(void *h, u16 len) { htonlsab(h, h, len); };
 static inline void ntohlsab1(void *n, u16 len) { ntohlsab(n, n, len); };
 #endif
 
+struct ospf_lsa_rt_walk {
+  struct top_hash_entry *en;
+  void *buf, *bufend;
+  int ospf2;
+  u16 type, metric;
+  u32 id, data, lif, nif;
+};
+
 void lsasum_calculate(struct ospf_lsa_header *header, void *body);
 u16 lsasum_check(struct ospf_lsa_header *h, void *body);
 #define CMP_NEWER 1
 #define CMP_SAME 0
 #define CMP_OLDER -1
 int lsa_comp(struct ospf_lsa_header *l1, struct ospf_lsa_header *l2);
+void lsa_walk_rt_init(struct proto_ospf *po, struct top_hash_entry *act, struct ospf_lsa_rt_walk *rt);
+int lsa_walk_rt(struct ospf_lsa_rt_walk *rt);
+void lsa_parse_sum_net(struct top_hash_entry *en, int ospf2, ip_addr *ip, int *pxlen, u8 *pxopts, u32 *metric);
+void lsa_parse_sum_rt(struct top_hash_entry *en, int ospf2, u32 *drid, u32 *metric, u32 *options);
+void lsa_parse_ext(struct top_hash_entry *en, int ospf2, struct ospf_lsa_ext_local *rt);
 int lsa_validate(struct ospf_lsa_header *lsa, void *body);
 struct top_hash_entry * lsa_install_new(struct proto_ospf *po, struct ospf_lsa_header *lsa, u32 domain, void *body);
 void ospf_age(struct proto_ospf *po);
index 1ba4fff9314ef3fefc98b675051c288cecaea77a..ae9e7e4114edf334e5d84a6282b6152e6d72da59 100644 (file)
@@ -9,47 +9,52 @@
 #include "ospf.h"
 
 
+/*
 struct ospf_lsreq_packet
 {
-  struct ospf_packet ospf_packet;
-  struct ospf_lsreq_header lsh[];
-};
+  struct ospf_packet hdr;
+  // union ospf_auth auth;
 
+  struct ospf_lsreq_header lsrs[];
+};
+*/
 
-static void ospf_dump_lsreq(struct proto *p, struct ospf_lsreq_packet *pkt)
+static void
+ospf_lsreq_body(struct proto_ospf *po, struct ospf_packet *pkt, unsigned plen,
+               struct ospf_lsreq_header **body, unsigned *count)
 {
-  struct ospf_packet *op = &pkt->ospf_packet;
+  unsigned hdrlen = ospf_pkt_hdrlen(po);
+  *body = ((void *) pkt) + hdrlen;
+  *count = (plen - hdrlen) / sizeof(struct ospf_lsreq_header);
+}
 
-  ASSERT(op->type == LSREQ_P);
-  ospf_dump_common(p, op);
+static void
+ospf_lsreq_dump(struct proto_ospf *po, struct ospf_packet *pkt)
+{
+  struct ospf_lsreq_header *lsrs;
+  unsigned i, lsr_count;
 
-  unsigned int i, j;
-  j = (ntohs(op->length) - sizeof(struct ospf_lsreq_packet)) /
-    sizeof(struct ospf_lsreq_header);
+  ASSERT(pkt->type == LSREQ_P);
+  ospf_dump_common(po, pkt);
 
-  for (i = 0; i < j; i++)
-    log(L_TRACE "%s:     LSR      Type: %04x, Id: %R, Rt: %R", p->name,
-       htonl(pkt->lsh[i].type), htonl(pkt->lsh[i].id), htonl(pkt->lsh[i].rt));
+  ospf_lsreq_body(po, pkt, ntohs(pkt->length), &lsrs, &lsr_count);
+  for (i = 0; i < lsr_count; i++)
+    log(L_TRACE "%s:     LSR      Type: %04x, Id: %R, Rt: %R", po->proto.name,
+       ntohl(lsrs[i].type), ntohl(lsrs[i].id), ntohl(lsrs[i].rt));
 }
 
 void
 ospf_lsreq_send(struct ospf_neighbor *n)
 {
-  snode *sn;
+  struct ospf_iface *ifa = n->ifa;
+  struct proto_ospf *po = ifa->oa->po;
+  struct ospf_lsreq_header *lsrs;
   struct top_hash_entry *en;
-  struct ospf_lsreq_packet *pk;
-  struct ospf_packet *op;
-  struct ospf_lsreq_header *lsh;
-  u16 length;
-  int i, j;
-  struct proto *p = &n->ifa->oa->po->proto;
-
-  pk = ospf_tx_buffer(n->ifa);
-  op = &pk->ospf_packet;
+  struct ospf_packet *pkt;
+  unsigned i, lsh_max, length;
+  snode *sn;
 
-  ospf_pkt_fill_hdr(n->ifa, pk, LSREQ_P);
 
-  sn = SHEAD(n->lsrql);
   if (EMPTY_SLIST(n->lsrql))
   {
     if (n->state == NEIGHBOR_LOADING)
@@ -57,81 +62,68 @@ ospf_lsreq_send(struct ospf_neighbor *n)
     return;
   }
 
-  i = j = (ospf_pkt_maxsize(n->ifa) - sizeof(struct ospf_lsreq_packet)) /
-    sizeof(struct ospf_lsreq_header);
-  lsh = pk->lsh;
+  pkt = ospf_tx_buffer(ifa);
+  ospf_pkt_fill_hdr(ifa, pkt, LSREQ_P);
+  ospf_lsreq_body(po, pkt, ospf_pkt_maxsize(ifa), &lsrs, &lsh_max);
 
-  for (; i > 0; i--)
+  sn = SHEAD(n->lsrql);
+  for (i = 0; i < lsh_max; i++)
   {
     en = (struct top_hash_entry *) sn;
-    lsh->type = htonl(en->lsa.type);
-    lsh->rt = htonl(en->lsa.rt);
-    lsh->id = htonl(en->lsa.id);
     DBG("Requesting %uth LSA: Type: %u, ID: %R, RT: %R, SN: 0x%x, Age %u\n",
        i, en->lsa.type, en->lsa.id, en->lsa.rt, en->lsa.sn, en->lsa.age);
-    lsh++;
+
+    lsrs[i].type = htonl(en->lsa.type);
+    lsrs[i].rt = htonl(en->lsa.rt);
+    lsrs[i].id = htonl(en->lsa.id);
+
     if (sn == STAIL(n->lsrql))
       break;
     sn = sn->next;
   }
-  if (i != 0)
-    i--;
 
-  length =
-    sizeof(struct ospf_lsreq_packet) + (j -
-                                       i) * sizeof(struct ospf_lsreq_header);
-  op->length = htons(length);
+  length = ospf_pkt_hdrlen(po) + i * sizeof(struct ospf_lsreq_header);
+  pkt->length = htons(length);
 
-  OSPF_PACKET(ospf_dump_lsreq, pk, "LSREQ packet sent to %I via %s", n->ip, n->ifa->iface->name);
-  ospf_send_to(n->ifa, n->ip);
+  OSPF_PACKET(ospf_lsreq_dump, pkt, "LSREQ packet sent to %I via %s",
+             n->ip, ifa->iface->name);
+  ospf_send_to(ifa, n->ip);
 }
 
 void
-ospf_lsreq_receive(struct ospf_packet *ps_i, struct ospf_iface *ifa,
+ospf_lsreq_receive(struct ospf_packet *pkt, struct ospf_iface *ifa,
                   struct ospf_neighbor *n)
 {
-  struct ospf_area *oa = ifa->oa;
-  struct proto_ospf *po = oa->po;
-  struct proto *p = &po->proto;
-  struct ospf_lsreq_header *lsh;
-  struct l_lsr_head *llsh;
+  struct proto_ospf *po = ifa->oa->po;
+  struct ospf_lsreq_header *lsrs;
+  unsigned i, lsr_count;
   list uplist;
   slab *upslab;
-  int i, lsano;
 
-  unsigned int size = ntohs(ps_i->length);
-  if (size < sizeof(struct ospf_lsreq_packet))
-  {
-    log(L_ERR "Bad OSPF LSREQ packet from %I -  too short (%u B)", n->ip, size);
-    return;
-  }
 
-  struct ospf_lsreq_packet *ps = (void *) ps_i;
-  OSPF_PACKET(ospf_dump_lsreq, ps, "LSREQ packet received from %I via %s", n->ip, ifa->iface->name);
+  /* No need to check length, lsreq has only basic header */
+
+  OSPF_PACKET(ospf_lsreq_dump, pkt, "LSREQ packet received from %I via %s",
+             n->ip, ifa->iface->name);
 
   if (n->state < NEIGHBOR_EXCHANGE)
     return;
 
-  ospf_neigh_sm(n, INM_HELLOREC);
+  ospf_neigh_sm(n, INM_HELLOREC);      /* Not in RFC */
 
-  lsh = ps->lsh;
   init_list(&uplist);
   upslab = sl_new(n->pool, sizeof(struct l_lsr_head));
 
-  lsano = (size - sizeof(struct ospf_lsreq_packet)) /
-    sizeof(struct ospf_lsreq_header);
-  for (i = 0; i < lsano; lsh++, i++)
+  ospf_lsreq_body(po, pkt, ntohs(pkt->length), &lsrs, &lsr_count);
+  for (i = 0; i < lsr_count; i++)
   {
-    u32 hid = ntohl(lsh->id);
-    u32 hrt = ntohl(lsh->rt);
-    u32 htype = ntohl(lsh->type);
+    u32 hid = ntohl(lsrs[i].id);
+    u32 hrt = ntohl(lsrs[i].rt);
+    u32 htype = ntohl(lsrs[i].type);
     u32 dom = ospf_lsa_domain(htype, ifa);
-    DBG("Processing requested LSA: Type: %u, ID: %R, RT: %R\n", lsh->type, hid, hrt);
-    llsh = sl_alloc(upslab);
-    llsh->lsh.id = hid;
-    llsh->lsh.rt = hrt;
-    llsh->lsh.type = htype;
-    add_tail(&uplist, NODE llsh);
+    // XXXX check
+    DBG("Processing requested LSA: Type: %u, ID: %R, RT: %R\n", htype, hid, hrt);
+
     if (ospf_hash_find(po->gr, dom, hid, hrt, htype) == NULL)
     {
       log(L_WARN "Received bad LSREQ from %I: Type: %04x, Id: %R, Rt: %R",
@@ -140,7 +132,14 @@ ospf_lsreq_receive(struct ospf_packet *ps_i, struct ospf_iface *ifa,
       rfree(upslab);
       return;
     }
+
+    struct l_lsr_head *llsh = sl_alloc(upslab);
+    llsh->lsh.id = hid;
+    llsh->lsh.rt = hrt;
+    llsh->lsh.type = htype;
+    add_tail(&uplist, NODE llsh);
   }
+
   ospf_lsupd_send_list(n, &uplist);
   rfree(upslab);
 }
index f71c72d1d5186f4f94544b58e7e14fd8ae9c835c..9255785e05c9af069023f0f08dc36fea31663978 100644 (file)
@@ -17,27 +17,29 @@ struct ospf_lsupd_packet
 
 
 /* Beware of unaligned access */
-void ospf_dump_lsahdr(struct proto *p, struct ospf_lsa_header *lsa_n)
+void ospf_dump_lsahdr(struct proto_ospf *po, struct ospf_lsa_header *lsa_n)
 {
   struct ospf_lsa_header lsa;
   ntohlsah(lsa_n, &lsa);
 
   log(L_TRACE "%s:     LSA      Type: %04x, Id: %R, Rt: %R, Age: %u, Seq: %08x, Sum: %04x",
-      p->name, lsa.type, lsa.id, lsa.rt, lsa.age, lsa.sn, lsa.checksum);
+      po->proto.name, lsa.type, lsa.id, lsa.rt, lsa.age, lsa.sn, lsa.checksum);
 }
 
-void ospf_dump_common(struct proto *p, struct ospf_packet *op)
+void ospf_dump_common(struct proto_ospf *po, struct ospf_packet *pkt)
 {
-  log(L_TRACE "%s:     length   %d", p->name, ntohs(op->length));
-  log(L_TRACE "%s:     router   %R", p->name, ntohl(op->routerid));
+  struct proto *p = &po->proto;
+  log(L_TRACE "%s:     length   %d", p->name, ntohs(pkt->length));
+  log(L_TRACE "%s:     router   %R", p->name, ntohl(pkt->routerid));
 }
 
-static void ospf_dump_lsupd(struct proto *p, struct ospf_lsupd_packet *pkt)
+static void ospf_dump_lsupd(struct proto_ospf *po, struct ospf_lsupd_packet *pkt)
 {
+  struct proto *p = &po->proto;
   struct ospf_packet *op = &pkt->ospf_packet;
 
   ASSERT(op->type == LSUPD_P);
-  ospf_dump_common(p, op);
+  ospf_dump_common(po, op);
 
   /* We know that ntohs(op->length) >= sizeof(struct ospf_lsa_header) */
   u8 *pbuf= (u8 *) pkt;
@@ -160,7 +162,6 @@ ospf_lsupd_flood(struct proto_ospf *po,
   struct ospf_iface *ifa;
   struct ospf_neighbor *nn;
   struct top_hash_entry *en;
-  struct proto *p = &po->proto;
   int ret, retval = 0;
 
   /* pg 148 */
@@ -352,7 +353,7 @@ void                                /* I send all I received in LSREQ */
 ospf_lsupd_send_list(struct ospf_neighbor *n, list * l)
 {
   struct ospf_area *oa = n->ifa->oa;
-  struct proto *p = &oa->po->proto;
+  struct proto_ospf *po = oa->po;
   struct l_lsr_head *lsr;
   struct top_hash_entry *en;
   struct ospf_lsupd_packet *pkt;
@@ -487,6 +488,8 @@ ospf_lsupd_receive(struct ospf_packet *ps_i, struct ospf_iface *ifa,
       continue;
     }
 
+    u16 lsa_type = ntohs(lsa->type_raw);
+    lsa_type = xxxx(lsa_type); // XXXX finish
 #ifdef OSPFv2
     /* pg 143 (2) */
     if ((lsa->type == 0) || (lsa->type == 6) || (lsa->type > LSA_T_NSSA))
@@ -496,21 +499,21 @@ ospf_lsupd_receive(struct ospf_packet *ps_i, struct ospf_iface *ifa,
     }
 
     /* pg 143 (3) */
-    if ((lsa->type == LSA_T_EXT) && !oa_is_ext(ifa->oa))
+    if ((lsa_type == LSA_T_EXT) && !oa_is_ext(ifa->oa))
     {
       log(L_WARN "Received External LSA in stub area from %I", n->ip);
       continue;
     }
 #else /* OSPFv3 */
     /* 4.5.1 (2) */
-    if ((LSA_SCOPE(lsa) == LSA_SCOPE_AS) && !oa_is_ext(ifa->oa))
+    if ((LSA_SCOPE(lsa_type) == LSA_SCOPE_AS) && !oa_is_ext(ifa->oa))
     {
       log(L_WARN "Received LSA with AS scope in stub area from %I", n->ip);
       continue;
     }
 
     /* 4.5.1 (3) */
-    if ((LSA_SCOPE(lsa) == LSA_SCOPE_RES))
+    if ((LSA_SCOPE(lsa_type) == LSA_SCOPE_RES))
     {
       log(L_WARN "Received LSA with invalid scope from %I", n->ip);
       continue;
@@ -520,10 +523,10 @@ ospf_lsupd_receive(struct ospf_packet *ps_i, struct ospf_iface *ifa,
     ntohlsah(lsa, &lsatmp);
 
     DBG("Update Type: %u ID: %R RT: %R, Sn: 0x%08x Age: %u, Sum: %u\n",
-       lsatmp.type, lsatmp.id, lsatmp.rt, lsatmp.sn, lsatmp.age, lsatmp.checksum);
+       lsa_type, lsatmp.id, lsatmp.rt, lsatmp.sn, lsatmp.age, lsatmp.checksum);
 
     /* FIXME domain should be link id for unknown LSA types with zero Ubit */
-    u32 domain = ospf_lsa_domain(lsatmp.type, ifa);
+    u32 domain = ospf_lsa_domain(lsa_type, ifa);
     lsadb = ospf_hash_find_header(po->gr, domain, &lsatmp);
 
 #ifdef LOCAL_DEBUG
@@ -550,7 +553,7 @@ ospf_lsupd_receive(struct ospf_packet *ps_i, struct ospf_iface *ifa,
 
 #ifdef OSPFv2
       /* 13.4 - check self-originated LSAs of NET type */
-      if ((!self) && (lsatmp.type == LSA_T_NET))
+      if ((!self) && (lsa_type == LSA_T_NET))
       {
        struct ospf_iface *nifa;
        WALK_LIST(nifa, po->iface_list)
@@ -576,7 +579,7 @@ ospf_lsupd_receive(struct ospf_packet *ps_i, struct ospf_iface *ifa,
        }
 
        OSPF_TRACE(D_EVENTS, "Received old self-originated LSA (Type: %04x, Id: %R, Rt: %R)",
-                  lsatmp.type, lsatmp.id, lsatmp.rt);
+                  lsa_type, lsatmp.id, lsatmp.rt);
 
        if (lsadb)
        {
@@ -666,8 +669,7 @@ ospf_lsupd_receive(struct ospf_packet *ps_i, struct ospf_iface *ifa,
 
 #ifdef OSPFv3
       /* Events 6,7 from RFC5340 4.4.3. */
-      if ((lsatmp.type == LSA_T_LINK) &&
-         (ifa->state == OSPF_IS_DR))
+      if ((lsa_type == LSA_T_LINK) && (ifa->state == OSPF_IS_DR))
        schedule_net_lsa(ifa);
 #endif
 
@@ -733,12 +735,11 @@ void
 ospf_lsupd_flush_nlsa(struct proto_ospf *po, struct top_hash_entry *en)
 {
   struct ospf_lsa_header *lsa = &en->lsa;
-  struct proto *p = &po->proto;
 
   lsa->age = LSA_MAXAGE;
   lsa->sn = LSA_MAXSEQNO;
   lsasum_calculate(lsa, en->lsa_body);
   OSPF_TRACE(D_EVENTS, "Premature aging self originated lsa!");
-  OSPF_TRACE(D_EVENTS, "Type: %04x, Id: %R, Rt: %R", lsa->type, lsa->id, lsa->rt);
+  OSPF_TRACE(D_EVENTS, "Type: %04x, Id: %R, Rt: %R", en->lsa_type, lsa->id, lsa->rt);
   ospf_lsupd_flood(po, NULL, NULL, lsa, en->domain, 0);
 }
index 8bacfe655d07d49c373b3acfc10726ca80800f83..29ea491f4aa9e0cdff66cf3daec895905cb95fe7 100644 (file)
@@ -10,8 +10,8 @@
 #ifndef _BIRD_OSPF_LSUPD_H_
 #define _BIRD_OSPF_LSUPD_H_
 
-void ospf_dump_lsahdr(struct proto *p, struct ospf_lsa_header *lsa_n);
-void ospf_dump_common(struct proto *p, struct ospf_packet *op);
+void ospf_dump_lsahdr(struct proto_ospf *po, struct ospf_lsa_header *lsa_n);
+void ospf_dump_common(struct proto_ospf *po, struct ospf_packet *pkt);
 void ospf_lsupd_send_list(struct ospf_neighbor *n, list * l);
 void ospf_lsupd_receive(struct ospf_packet *ps_i,
                        struct ospf_iface *ifa, struct ospf_neighbor *n);
index 642365b35a7c8484834c4a85609b99cbc68e2620..2c55f58c405e5cd2c710fe05f5746c23758c50cd 100644 (file)
@@ -123,7 +123,6 @@ neigh_chstate(struct ospf_neighbor *n, u8 state)
   {
     struct ospf_iface *ifa = n->ifa;
     struct proto_ospf *po = ifa->oa->po;
-    struct proto *p = &po->proto;
 
     n->state = state;
 
@@ -157,13 +156,10 @@ neigh_chstate(struct ospf_neighbor *n, u8 state)
        n->dds = random_u32();
       }
       n->dds++;
-      n->myimms.byte = 0;
-      n->myimms.bit.ms = 1;
-      n->myimms.bit.m = 1;
-      n->myimms.bit.i = 1;
+      n->myimms = DBDES_IMMS;
     }
     if (state > NEIGHBOR_EXSTART)
-      n->myimms.bit.i = 0;
+      n->myimms &= ~DBDES_I;
   }
 }
 
@@ -554,7 +550,7 @@ neighbor_timer_hook(timer * timer)
 {
   struct ospf_neighbor *n = (struct ospf_neighbor *) timer->data;
   struct ospf_iface *ifa = n->ifa;
-  struct proto *p = &ifa->oa->po->proto;
+  struct proto_ospf *po = ifa->oa->po;
 
   OSPF_TRACE(D_EVENTS,
             "Inactivity timer fired on interface %s for neighbor %I.",
@@ -566,7 +562,8 @@ void
 ospf_neigh_remove(struct ospf_neighbor *n)
 {
   struct ospf_iface *ifa = n->ifa;
-  struct proto *p = &ifa->oa->po->proto;
+  struct proto_ospf *po = ifa->oa->po;
+  u32 rid = n->rid;
 
   if ((ifa->type == OSPF_IT_NBMA) || (ifa->type == OSPF_IT_PTMP))
   {
@@ -579,7 +576,7 @@ ospf_neigh_remove(struct ospf_neighbor *n)
   neigh_chstate(n, NEIGHBOR_DOWN);
   rem_node(NODE n);
   rfree(n->pool);
-  OSPF_TRACE(D_EVENTS, "Deleting neigbor.");
+  OSPF_TRACE(D_EVENTS, "Deleting neigbor %R", rid);
 }
 
 void
@@ -633,7 +630,7 @@ rxmt_timer_hook(timer * timer)
     return;
   }
 
-  if ((n->state == NEIGHBOR_EXCHANGE) && n->myimms.bit.ms)     /* I'm master */
+  if ((n->state == NEIGHBOR_EXCHANGE) && (n->myimms & DBDES_MS))       /* I'm master */
     ospf_dbdes_send(n, 0);
 
 
index 44dd7fef16903c7406b3b4e3184f419efaef1e85..556e54842f0944157f55d5dc9432998dc3c8f8ee 100644 (file)
@@ -185,11 +185,11 @@ ospf_area_add(struct proto_ospf *po, struct ospf_area_config *ac, int reconf)
 static void
 ospf_area_remove(struct ospf_area *oa)
 {
-  struct proto *p = &oa->po->proto;
+  struct proto_ospf *po = oa->po;
   OSPF_TRACE(D_EVENTS, "Removing area %R", oa->areaid);
 
   /* We suppose that interfaces are already removed */
-  ospf_flush_area(oa->po, oa->areaid);
+  ospf_flush_area(po, oa->areaid);
  
   fib_free(&oa->rtr);
   fib_free(&oa->net_fib);
@@ -198,7 +198,7 @@ ospf_area_remove(struct ospf_area *oa)
   if (oa->translator_timer)
     rfree(oa->translator_timer);
 
-  oa->po->areano--;
+  po->areano--;
   rem_node(NODE oa);
   mb_free(oa);
 }
@@ -377,7 +377,7 @@ ospf_build_attrs(ea_list * next, struct linpool *pool, u32 m1, u32 m2,
 void
 schedule_net_lsa(struct ospf_iface *ifa)
 {
-  struct proto *p = &ifa->oa->po->proto;
+  struct proto_ospf *po = ifa->oa->po;
 
   OSPF_TRACE(D_EVENTS, "Scheduling network-LSA origination for iface %s", ifa->iface->name);
   ifa->orignet = 1;
@@ -387,7 +387,7 @@ schedule_net_lsa(struct ospf_iface *ifa)
 void
 schedule_link_lsa(struct ospf_iface *ifa)
 {
-  struct proto *p = &ifa->oa->po->proto;
+  struct proto_ospf *po = ifa->oa->po;
 
   OSPF_TRACE(D_EVENTS, "Scheduling link-LSA origination for iface %s", ifa->iface->name);
   ifa->origlink = 1;
@@ -397,7 +397,7 @@ schedule_link_lsa(struct ospf_iface *ifa)
 void
 schedule_rt_lsa(struct ospf_area *oa)
 {
-  struct proto *p = &oa->po->proto;
+  struct proto_ospf *po = oa->po;
 
   OSPF_TRACE(D_EVENTS, "Scheduling router-LSA origination for area %R", oa->areaid);
   oa->origrt = 1;
@@ -406,8 +406,6 @@ schedule_rt_lsa(struct ospf_area *oa)
 void
 schedule_rtcalc(struct proto_ospf *po)
 {
-  struct proto *p = &po->proto;
-
   if (po->calcrt)
     return;
 
@@ -449,11 +447,9 @@ area_disp(struct ospf_area *oa)
   /* Now try to originate network LSA's */
   WALK_LIST(ifa, po->iface_list)
   {
-#ifdef OSPFv3
     /* Link LSA should be originated before Network LSA */
-    if (ifa->origlink && (ifa->oa == oa))
+    if (ospf_is_v3(po) && ifa->origlink && (ifa->oa == oa))
       update_link_lsa(ifa);
-#endif
 
     if (ifa->orignet && (ifa->oa == oa))
       update_net_lsa(ifa);
@@ -945,32 +941,44 @@ fake_lsa_from_prefix_lsa(struct ospf_lsa_header *dst, struct ospf_lsa_header *sr
 
 #endif
 
+static int lsa_compare_ospf3; // XXXX fixme
+
 static int
 lsa_compare_for_state(const void *p1, const void *p2)
 {
-  struct top_hash_entry * he1 = * (struct top_hash_entry **) p1;
-  struct top_hash_entry * he2 = * (struct top_hash_entry **) p2;
+  struct top_hash_entry *he1 = * (struct top_hash_entry **) p1;
+  struct top_hash_entry *he2 = * (struct top_hash_entry **) p2;
   struct ospf_lsa_header *lsa1 = &(he1->lsa);
   struct ospf_lsa_header *lsa2 = &(he2->lsa);
+  struct ospf_lsa_header lsatmp1, lsatmp2;
+  u16 lsa1_type = he1->lsa_type;
+  u16 lsa2_type = he2->lsa_type;
+  int px1 = 0;
+  int px2 = 0;
 
   if (he1->domain != he2->domain)
     return he1->domain - he2->domain;
 
-#ifdef OSPFv3
-  struct ospf_lsa_header lsatmp1, lsatmp2;
+  if (lsa_compare_ospf3)
+  {
+    px1 = (lsa1_type == LSA_T_PREFIX);
+    px2 = (lsa2_type == LSA_T_PREFIX);
+    xxxx();
 
-  int px1 = (lsa1->type == LSA_T_PREFIX);
-  int px2 = (lsa2->type == LSA_T_PREFIX);
+    if (px1)
+    {
+      lsa1 = fake_lsa_from_prefix_lsa(&lsatmp1, lsa1, he1->lsa_body);
+      lsa1_type = lsa1->type;
+      px1 = 1;
+    }
 
-  if (px1)
-    lsa1 = fake_lsa_from_prefix_lsa(&lsatmp1, lsa1, he1->lsa_body);
+    if (px2)
+      lsa2 = fake_lsa_from_prefix_lsa(&lsatmp2, lsa2, he2->lsa_body);
+  }
 
-  if (px2)
-    lsa2 = fake_lsa_from_prefix_lsa(&lsatmp2, lsa2, he2->lsa_body);
-#endif
 
-  int nt1 = (lsa1->type == LSA_T_NET);
-  int nt2 = (lsa2->type == LSA_T_NET);
+  int nt1 = (lsa1_type == LSA_T_NET);
+  int nt2 = (lsa2_type == LSA_T_NET);
 
   if (nt1 != nt2)
     return nt1 - nt2;
@@ -988,10 +996,8 @@ lsa_compare_for_state(const void *p1, const void *p2)
     if (lsa1->id != lsa2->id)
       return lsa1->id - lsa2->id;
 
-#ifdef OSPFv3
     if (px1 != px2)
       return px1 - px2;
-#endif
 
     return lsa1->sn - lsa2->sn;
   }
@@ -1000,16 +1006,14 @@ lsa_compare_for_state(const void *p1, const void *p2)
     if (lsa1->rt != lsa2->rt)
       return lsa1->rt - lsa2->rt;
 
-    if (lsa1->type != lsa2->type)
-      return lsa1->type - lsa2->type;
+    if (lsa1_type != lsa2_type)
+      return lsa1_type - lsa2_type;
   
     if (lsa1->id != lsa2->id)
       return lsa1->id - lsa2->id;
 
-#ifdef OSPFv3
     if (px1 != px2)
       return px1 - px2;
-#endif
   
     return lsa1->sn - lsa2->sn;
   }
@@ -1042,79 +1046,77 @@ show_lsa_distance(struct top_hash_entry *he)
 }
 
 static inline void
-show_lsa_router(struct proto_ospf *po, struct top_hash_entry *he, int first, int verbose)
+show_lsa_router(struct proto_ospf *po, struct top_hash_entry *he, int verbose)
 {
-  struct ospf_lsa_header *lsa = &(he->lsa);
-  struct ospf_lsa_rt *rt = he->lsa_body;
-  struct ospf_lsa_rt_link *rr = (struct ospf_lsa_rt_link *) (rt + 1);
-  int max = lsa_rt_count(lsa);
-  int i;
-
-  if (first)
-  {
-    cli_msg(-1016, "");
-    cli_msg(-1016, "\trouter %R", he->lsa.rt);
-    show_lsa_distance(he);
-  }
+  struct ospf_lsa_rt_walk rtl;
 
+  cli_msg(-1016, "");
+  cli_msg(-1016, "\trouter %R", he->lsa.rt);
+  show_lsa_distance(he);
 
-  for (i = 0; i < max; i++)
-    if (rr[i].type == LSART_VLNK)
-      cli_msg(-1016, "\t\tvlink %R metric %u", rr[i].id, rr[i].metric);
+  lsa_walk_rt_init(po, he, &rtl);
+  while (lsa_walk_rt(&rtl))
+    if (rtl.type == LSART_VLNK)
+      cli_msg(-1016, "\t\tvlink %R metric %u", rtl.id, rtl.metric);
 
-  for (i = 0; i < max; i++)
-    if (rr[i].type == LSART_PTP)
-      cli_msg(-1016, "\t\trouter %R metric %u", rr[i].id, rr[i].metric);
+  lsa_walk_rt_init(po, he, &rtl);
+  while (lsa_walk_rt(&rtl))
+    if (rtl.type == LSART_PTP)
+      cli_msg(-1016, "\t\trouter %R metric %u", rtl.id, rtl.metric);
 
-  for (i = 0; i < max; i++)
-    if (rr[i].type == LSART_NET)
+  lsa_walk_rt_init(po, he, &rtl);
+  while (lsa_walk_rt(&rtl))
+    if (rtl.type == LSART_NET)
     {
-#ifdef OSPFv2
-      struct top_hash_entry *net_he = ospf_hash_find_net(po->gr, he->domain, rr[i].id);
-
-      if (net_he)
+      if (ospf_is_v2(po))
       {
-       struct ospf_lsa_header *net_lsa = &(net_he->lsa);
-       struct ospf_lsa_net *net_ln = net_he->lsa_body;
+       /* In OSPFv2, we try to find network-LSA to get prefix/pxlen */
+       struct top_hash_entry *net_he = ospf_hash_find_net(po->gr, he->domain, rtl.id, 0);
+
+       if (net_he)
+       {
+         struct ospf_lsa_header *net_lsa = &(net_he->lsa);
+         struct ospf_lsa_net *net_ln = net_he->lsa_body;
 
-       cli_msg(-1016, "\t\tnetwork %I/%d metric %u", 
-               ipa_and(ipa_from_u32(net_lsa->id), net_ln->netmask),
-               ipa_mklen(net_ln->netmask), rr[i].metric);
+         cli_msg(-1016, "\t\tnetwork %I/%d metric %u", 
+                 ipa_from_u32(net_lsa->id & net_ln->optx),
+                 u32_masklen(net_ln->optx), rtl.metric);
+       }
+       else
+         cli_msg(-1016, "\t\tnetwork [%R] metric %u", rtl.id, rtl.metric);
       }
       else
-       cli_msg(-1016, "\t\tnetwork [%R] metric %u", rr[i].id, rr[i].metric);
-
-#else /* OSPFv3 */
-      cli_msg(-1016, "\t\tnetwork [%R-%u] metric %u", rr[i].id, rr[i].nif, rr[i].metric);
-#endif
+       cli_msg(-1016, "\t\tnetwork [%R-%u] metric %u", rtl.id, rtl.nif, rtl.metric);
     }
 
-#ifdef OSPFv2
-  if (!verbose)
-    return;
-
-  for (i = 0; i < max; i++)
-    if (rr[i].type == LSART_STUB)
-      cli_msg(-1016, "\t\tstubnet %I/%d metric %u", ipa_from_u32(rr[i].id),
-             ipa_mklen(ipa_from_u32(rr[i].data)), rr[i].metric);
-#endif
+  if (ospf_is_v2(po) && verbose)
+  {
+    lsa_walk_rt_init(po, he, &rtl);
+    while (lsa_walk_rt(&rtl))
+      if (rtl.type == LSART_STUB)
+       cli_msg(-1016, "\t\tstubnet %I/%d metric %u",
+               ipa_from_u32(rtl.id), u32_masklen(rtl.data), rtl.metric);
+  }
 }
 
 static inline void
-show_lsa_network(struct top_hash_entry *he)
+show_lsa_network(struct top_hash_entry *he, int ospf2)
 {
   struct ospf_lsa_header *lsa = &(he->lsa);
   struct ospf_lsa_net *ln = he->lsa_body;
   u32 i;
 
-#ifdef OSPFv2
-  cli_msg(-1016, "");
-  cli_msg(-1016, "\tnetwork %I/%d", ipa_and(ipa_from_u32(lsa->id), ln->netmask), ipa_mklen(ln->netmask));
-  cli_msg(-1016, "\t\tdr %R", lsa->rt);
-#else /* OSPFv3 */
-  cli_msg(-1016, "");
-  cli_msg(-1016, "\tnetwork [%R-%u]", lsa->rt, lsa->id);
-#endif
+  if (ospf2)
+  {
+    cli_msg(-1016, "");
+    cli_msg(-1016, "\tnetwork %I/%d", ipa_from_u32(lsa->id & ln->optx), u32_masklen(ln->optx));
+    cli_msg(-1016, "\t\tdr %R", lsa->rt);
+  }
+  else
+  {
+    cli_msg(-1016, "");
+    cli_msg(-1016, "\tnetwork [%R-%u]", lsa->rt, lsa->id);
+  }
 
   show_lsa_distance(he);
 
@@ -1123,95 +1125,52 @@ show_lsa_network(struct top_hash_entry *he)
 }
 
 static inline void
-show_lsa_sum_net(struct top_hash_entry *he)
+show_lsa_sum_net(struct top_hash_entry *he, int ospf2)
 {
   ip_addr ip;
   int pxlen;
-
-#ifdef OSPFv2
-  struct ospf_lsa_sum *ls = he->lsa_body;
-  pxlen = ipa_mklen(ls->netmask);
-  ip = ipa_and(ipa_from_u32(he->lsa.id), ls->netmask);
-#else /* OSPFv3 */
   u8 pxopts;
-  u16 rest;
-  struct ospf_lsa_sum_net *ls = he->lsa_body;
-  lsa_get_ipv6_prefix(ls->prefix, &ip, &pxlen, &pxopts, &rest);
-#endif
+  u32 metric;
 
-  cli_msg(-1016, "\t\txnetwork %I/%d metric %u", ip, pxlen, ls->metric);
+  lsa_parse_sum_net(he, ospf2, &ip, &pxlen, &pxopts, &metric);
+  cli_msg(-1016, "\t\txnetwork %I/%d metric %u", ip, pxlen, metric);
 }
 
 static inline void
-show_lsa_sum_rt(struct top_hash_entry *he)
+show_lsa_sum_rt(struct top_hash_entry *he, int ospf2)
 {
+  u32 metric;
   u32 dst_rid;
+  u32 options;
 
-#ifdef OSPFv2
-  struct ospf_lsa_sum *ls = he->lsa_body;
-  dst_rid = he->lsa.id;
-  // options = 0;
-#else /* OSPFv3 */
-  struct ospf_lsa_sum_rt *ls = he->lsa_body;
-  dst_rid = ls->drid; 
-  // options = ls->options & OPTIONS_MASK;
-#endif
-
-  cli_msg(-1016, "\t\txrouter %R metric %u", dst_rid, ls->metric);
+  lsa_parse_sum_rt(he, ospf2, &dst_rid, &metric, &options);
+  cli_msg(-1016, "\t\txrouter %R metric %u", dst_rid, metric);
 }
 
 
 static inline void
-show_lsa_external(struct top_hash_entry *he)
+show_lsa_external(struct top_hash_entry *he, int ospf2)
 {
-  struct ospf_lsa_ext *ext = he->lsa_body;
+  struct ospf_lsa_ext_local rt;
   char str_via[STD_ADDRESS_P_LENGTH + 8] = "";
   char str_tag[16] = "";
-  ip_addr ip, rt_fwaddr;
-  int pxlen, ebit, rt_fwaddr_valid;
-  u32 rt_tag, rt_metric;
 
-  if (he->lsa.type == LSA_T_EXT)
+  if (he->lsa_type == LSA_T_EXT)
     he->domain = 0; /* Unmark the LSA */
 
-  rt_metric = ext->metric & METRIC_MASK;
-  ebit = ext->metric & LSA_EXT_EBIT;
-#ifdef OSPFv2
-  ip = ipa_and(ipa_from_u32(he->lsa.id), ext->netmask);
-  pxlen = ipa_mklen(ext->netmask);
-  rt_fwaddr = ext->fwaddr;
-  rt_fwaddr_valid = !ipa_equal(rt_fwaddr, IPA_NONE);
-  rt_tag = ext->tag;
-#else /* OSPFv3 */
-  u8 pxopts;
-  u16 rest;
-  u32 *buf = ext->rest;
-  buf = lsa_get_ipv6_prefix(buf, &ip, &pxlen, &pxopts, &rest);
-
-  rt_fwaddr_valid = ext->metric & LSA_EXT_FBIT;
-  if (rt_fwaddr_valid)
-    buf = lsa_get_ipv6_addr(buf, &rt_fwaddr);
-  else 
-    rt_fwaddr = IPA_NONE;
-
-  if (ext->metric & LSA_EXT_TBIT)
-    rt_tag = *buf++;
-  else
-    rt_tag = 0;
-#endif
+  lsa_parse_ext(he, ospf2, &rt);
   
-  if (rt_fwaddr_valid)
-    bsprintf(str_via, " via %I", rt_fwaddr);
+  if (rt.fbit)
+    bsprintf(str_via, " via %I", rt.fwaddr);
 
-  if (rt_tag)
-    bsprintf(str_tag, " tag %08x", rt_tag);
+  if (rt.tag)
+    bsprintf(str_tag, " tag %08x", rt.tag);
 
   cli_msg(-1016, "\t\t%s %I/%d metric%s %u%s%s",
-         (he->lsa.type == LSA_T_NSSA) ? "nssa-ext" : "external",
-         ip, pxlen, ebit ? "2" : "", rt_metric, str_via, str_tag);
+         (he->lsa_type == LSA_T_NSSA) ? "nssa-ext" : "external",
+         rt.ip, rt.pxlen, rt.ebit ? "2" : "", rt.metric, str_via, str_tag);
 }
 
-#ifdef OSPFv3
 static inline void
 show_lsa_prefix(struct top_hash_entry *he, struct ospf_lsa_header *cnode)
 {
@@ -1224,7 +1183,7 @@ show_lsa_prefix(struct top_hash_entry *he, struct ospf_lsa_header *cnode)
   int i;
 
   /* We check whether given prefix-LSA is related to the current node */
-  if ((px->ref_type != cnode->type) || (px->ref_rt != cnode->rt))
+  if ((px->ref_type != cnode->type_raw) || (px->ref_rt != cnode->rt))
     return;
 
   if ((px->ref_type == LSA_T_RT) && (px->ref_id != 0))
@@ -1244,13 +1203,13 @@ show_lsa_prefix(struct top_hash_entry *he, struct ospf_lsa_header *cnode)
        cli_msg(-1016, "\t\taddress %I/%d", pxa, pxlen);
     }
 }
-#endif
 
 void
 ospf_sh_state(struct proto *p, int verbose, int reachable)
 {
   struct proto_ospf *po = (struct proto_ospf *) p;
   struct ospf_lsa_header *cnode = NULL;
+  int ospf2 = ospf_is_v2(po);
   int num = po->gr->hash_entries;
   unsigned int i, ix, j1, j2, jx;
   u32 last_area = 0xFFFFFFFF;
@@ -1274,7 +1233,7 @@ ospf_sh_state(struct proto *p, int verbose, int reachable)
   {
     int accept;
 
-    switch (he->lsa.type)
+    switch (he->lsa_type)
       {
       case LSA_T_RT:
       case LSA_T_NET:
@@ -1284,9 +1243,7 @@ ospf_sh_state(struct proto *p, int verbose, int reachable)
       case LSA_T_SUM_NET:
       case LSA_T_SUM_RT:
       case LSA_T_NSSA:
-#ifdef OSPFv3
       case LSA_T_PREFIX:
-#endif
        accept = verbose;
        break;
 
@@ -1339,7 +1296,7 @@ ospf_sh_state(struct proto *p, int verbose, int reachable)
     /* If there is no opened node, we open the LSA (if appropriate) or skip to the next one */
     if (!cnode)
     {
-      if (((he->lsa.type == LSA_T_RT) || (he->lsa.type == LSA_T_NET))
+      if (((he->lsa_type == LSA_T_RT) || (he->lsa_type == LSA_T_NET))
          && ((he->color == INSPF) || !reachable))
       {
        cnode = &(he->lsa);
@@ -1358,35 +1315,34 @@ ospf_sh_state(struct proto *p, int verbose, int reachable)
 
     ASSERT(cnode && (he->domain == last_area) && (he->lsa.rt == cnode->rt));
 
-    switch (he->lsa.type)
+    switch (he->lsa_type)
     {
       case LSA_T_RT:
-       show_lsa_router(po, he, he->lsa.id == cnode->id, verbose);
+       if (he->lsa.id == cnode->id)
+         show_lsa_router(po, he, verbose);
        break;
 
       case LSA_T_NET:
-       show_lsa_network(he);
+       show_lsa_network(he, ospf2);
        break;
 
       case LSA_T_SUM_NET:
        if (cnode->type == LSA_T_RT)
-         show_lsa_sum_net(he);
+         show_lsa_sum_net(he, ospf2);
        break;
 
       case LSA_T_SUM_RT:
        if (cnode->type == LSA_T_RT)
-         show_lsa_sum_rt(he);
+         show_lsa_sum_rt(he, ospf2);
        break;
 
-#ifdef OSPFv3
-      case LSA_T_PREFIX:
-       show_lsa_prefix(he, cnode);
-       break;
-#endif
-
       case LSA_T_EXT:
       case LSA_T_NSSA:
-       show_lsa_external(he);
+       show_lsa_external(he, ospf2);
+       break;
+
+      case LSA_T_PREFIX:
+       show_lsa_prefix(he, cnode);
        break;
     }
 
@@ -1394,13 +1350,13 @@ ospf_sh_state(struct proto *p, int verbose, int reachable)
     if ((i+1 == j1)
        || (hea[i+1]->domain != last_area)
        || (hea[i+1]->lsa.rt != cnode->rt)
-       || (hea[i+1]->lsa.type == LSA_T_NET))
+       || (hea[i+1]->lsa_type == LSA_T_NET))
     {
       while ((ix < jx) && (hex[ix]->lsa.rt < cnode->rt))
        ix++;
 
       while ((ix < jx) && (hex[ix]->lsa.rt == cnode->rt))
-       show_lsa_external(hex[ix++]);
+       show_lsa_external(hex[ix++], ospf2);
 
       cnode = NULL;
     }
@@ -1434,7 +1390,7 @@ ospf_sh_state(struct proto *p, int verbose, int reachable)
        last_rt = he->lsa.rt;
       }
 
-      show_lsa_external(he);
+      show_lsa_external(he, ospf2);
     }
   }
 
@@ -1449,8 +1405,8 @@ lsa_compare_for_lsadb(const void *p1, const void *p2)
   struct top_hash_entry * he2 = * (struct top_hash_entry **) p2;
   struct ospf_lsa_header *lsa1 = &(he1->lsa);
   struct ospf_lsa_header *lsa2 = &(he2->lsa);
-  int sc1 = LSA_SCOPE(lsa1);
-  int sc2 = LSA_SCOPE(lsa2);
+  int sc1 = LSA_SCOPE(he1->lsa_type);
+  int sc2 = LSA_SCOPE(he2->lsa_type);
 
   if (sc1 != sc2)
     return sc2 - sc1;
@@ -1464,8 +1420,8 @@ lsa_compare_for_lsadb(const void *p1, const void *p2)
   if (lsa1->id != lsa2->id)
     return lsa1->id - lsa2->id;
 
-  if (lsa1->type != lsa2->type)
-    return lsa1->type - lsa2->type;
+  if (he1->lsa_type != he2->lsa_type)
+    return he1->lsa_type - he2->lsa_type;
 
   return lsa1->sn - lsa2->sn;
 }
@@ -1505,7 +1461,7 @@ ospf_sh_lsadb(struct lsadb_show_data *ld)
   for (i = 0; i < j; i++)
   {
     struct ospf_lsa_header *lsa = &(hea[i]->lsa);
-    int dscope = LSA_SCOPE(lsa);
+    int dscope = LSA_SCOPE(hea[i]->lsa_type);
 
     if (ld->scope && (dscope != (ld->scope & 0xf000)))
       continue;
@@ -1514,6 +1470,7 @@ ospf_sh_lsadb(struct lsadb_show_data *ld)
       continue;
 
     /* Ignore high nibble */
+    // XXXX check
     if (ld->type && ((lsa->type & 0x0fff) != (ld->type & 0x0fff)))
       continue;
 
index 3bffaf91c435b79ca69abdd08eafbcd10d781171..4d4cf67540a43d0bd39ff0a087f559938daa6d4f 100644 (file)
@@ -9,7 +9,7 @@
 #ifndef _BIRD_OSPF_H_
 #define _BIRD_OSPF_H_
 
-#define MAXNETS 10
+
 #define OSPF_MAX_PKT_SIZE 65535
 /*
  * RFC 2328 says, maximum packet size is 65535 (IP packet size
 #else
 #define OSPF_FORCE_DEBUG 0
 #endif
-#define OSPF_TRACE(flags, msg, args...) do { if ((p->debug & flags) || OSPF_FORCE_DEBUG) \
-  log(L_TRACE "%s: " msg, p->name , ## args ); } while(0)
+
+#define OSPF_TRACE(flags, msg, args...) \
+do { if ((po->proto.debug & flags) || OSPF_FORCE_DEBUG) \
+  log(L_TRACE "%s: " msg, po->proto.name , ## args ); } while(0)
 
 #define OSPF_PACKET(dumpfn, buffer, msg, args...) \
-do { if ((p->debug & D_PACKETS) || OSPF_FORCE_DEBUG) \
-{ log(L_TRACE "%s: " msg, p->name, ## args ); dumpfn(p, buffer); } } while(0)
+do { if ((po->proto.debug & D_PACKETS) || OSPF_FORCE_DEBUG) \
+{ log(L_TRACE "%s: " msg, po->proto.name, ## args ); dumpfn(po, buffer); } } while(0)
 
 
 #include "nest/bird.h"
@@ -51,19 +53,11 @@ do { if ((p->debug & D_PACKETS) || OSPF_FORCE_DEBUG) \
 
 #define OSPF_PROTO 89
 
-#ifndef IPV6
-#define OSPFv2 1
-#define OSPF_VERSION 2
-#define OSPF_VLINK_MTU 576                     /* RFC 2328 A.1 */
-#define AllSPFRouters ipa_from_u32(0xe0000005) /* 224.0.0.5 */
-#define AllDRouters ipa_from_u32(0xe0000006)   /* 224.0.0.6 */
-#else
+
+// XXXX
 #define OSPFv3 1
 #define OSPF_VERSION 3
-#define OSPF_VLINK_MTU 1280                    /* RFC 5340 A.1 */
-#define AllSPFRouters _MI(0xFF020000, 0, 0, 5) /* FF02::5 */
-#define AllDRouters   _MI(0xFF020000, 0, 0, 6) /* FF02::6 */
-#endif
+
 
 
 #define LSREFRESHTIME 1800     /* 30 minutes */
@@ -140,38 +134,45 @@ struct ospf_area_config
 };
 
 
-/* Option flags */
+/* Generic option flags */
+#define OPT_V6 0x01            /* OSPFv3, LSA relevant for IPv6 routing calculation */
+#define OPT_E  0x02            /* Related to AS-external LSAs */
+#define OPT_MC 0x04            /* Related to MOSPF, not used and obsolete */
+#define OPT_N  0x08            /* Related to NSSA */
+#define OPT_P  0x08            /* OSPFv2, flags P and N share position, see NSSA RFC */
+#define OPT_EA 0x10            /* OSPFv2, external attributes, not used and obsolete */
+#define OPT_R  0x10            /* OSPFv3, originator is active router */
+#define OPT_DC 0x20            /* Related to demand circuits, not used */
 
-#define OPT_E  0x02
-#define OPT_N  0x08
-#define OPT_DC 0x20
-
-#ifdef OSPFv2
-#define OPT_P  0x08            /* flags P and N share position, see NSSA RFC */
-#define OPT_EA 0x10
-
-/* VEB flags are are stored independently in 'u16 options' */
-#define OPT_RT_B  (0x01 << 8)
-#define OPT_RT_E  (0x02 << 8)
-#define OPT_RT_V  (0x04 << 8)
-#define OPT_RT_NT (0x10 << 8)
-#endif
-
-#ifdef OSPFv3
-#define OPT_V6 0x01
-#define OPT_R  0x10
-
-/* VEB flags are are stored together with options in 'u32 options' */
+/* Router-LSA VEB flags are are stored together with links (OSPFv2) or options (OSPFv3) */
 #define OPT_RT_B  (0x01 << 24)
 #define OPT_RT_E  (0x02 << 24)
 #define OPT_RT_V  (0x04 << 24)
 #define OPT_RT_NT (0x10 << 24)
 
+/* Prefix flags, specific for OSPFv3 */
 #define OPT_PX_NU 0x01
 #define OPT_PX_LA 0x02
 #define OPT_PX_P  0x08
 #define OPT_PX_DN 0x10
-#endif
+
+
+/* OSPF interface types */
+#define OSPF_IT_BCAST  0
+#define OSPF_IT_NBMA   1
+#define OSPF_IT_PTP    2
+#define OSPF_IT_PTMP   3
+#define OSPF_IT_VLINK  4
+#define OSPF_IT_UNDEF  5
+
+/* OSPF interface states */
+#define OSPF_IS_DOWN   0       /* Not active */
+#define OSPF_IS_LOOP   1       /* Iface with no link */
+#define OSPF_IS_WAITING        2       /* Waiting for Wait timer */
+#define OSPF_IS_PTP    3       /* PTP operational */
+#define OSPF_IS_DROTHER        4       /* I'm on BCAST or NBMA and I'm not DR */
+#define OSPF_IS_BACKUP 5       /* I'm BDR */
+#define OSPF_IS_DR     6       /* I'm DR */
 
 
 struct ospf_iface
@@ -197,14 +198,10 @@ struct ospf_iface
                                   transmit a Link State Update Packet over this
                                   interface.  LSAs contained in the update */
   u16 helloint;                        /* number of seconds between hello sending */
-
-#ifdef OSPFv2
   list *passwords;
   u16 autype;
   u32 csn;                      /* Last used crypt seq number */
   bird_clock_t csn_use;         /* Last time when packet with that CSN was sent */
-#endif
-
   ip_addr all_routers;         /*  */
   ip_addr drip;                        /* Designated router */
   ip_addr bdrip;               /* Backup DR */
@@ -212,33 +209,15 @@ struct ospf_iface
   u32 bdrid;
   s16 rt_pos_beg;              /* Position of iface in Router-LSA, begin, inclusive */
   s16 rt_pos_end;              /* Position of iface in Router-LSA, end, exclusive */
-
-#ifdef OSPFv3
   s16 px_pos_beg;              /* Position of iface in Rt Prefix-LSA, begin, inclusive */
   s16 px_pos_end;              /* Position of iface in Rt Prefix-LSA, end, exclusive */
-
   u32 dr_iface_id;             /* if drid is valid, this is iface_id of DR (for connecting network) */
   u8 instance_id;              /* Used to differentiate between more OSPF
                                   instances on one interface */
-#endif
-
-  u8 type;                     /* OSPF view of type */
-#define OSPF_IT_BCAST 0
-#define OSPF_IT_NBMA 1
-#define OSPF_IT_PTP 2
-#define OSPF_IT_PTMP 3
-#define OSPF_IT_VLINK 4
-#define OSPF_IT_UNDEF 5
+  u8 type;                     /* OSPF view of type (OSPF_IT_*) */
   u8 strictnbma;               /* Can I talk with unknown neighbors? */
   u8 stub;                     /* Inactive interface */
-  u8 state;                    /* Interface state machine */
-#define OSPF_IS_DOWN 0         /* Not working */
-#define OSPF_IS_LOOP 1         /* Iface with no link */
-#define OSPF_IS_WAITING 2      /* Waiting for Wait timer */
-#define OSPF_IS_PTP 3          /* PTP operational */
-#define OSPF_IS_DROTHER 4      /* I'm on BCAST or NBMA and I'm not DR */
-#define OSPF_IS_BACKUP 5       /* I'm BDR */
-#define OSPF_IS_DR 6           /* I'm DR */
+  u8 state;                    /* Interface state machine (OSPF_IS_*) */
   timer *wait_timer;           /* WAIT timer */
   timer *hello_timer;          /* HELLOINT timer */
   timer *poll_timer;           /* Poll Interval - for NBMA */
@@ -255,11 +234,9 @@ struct ospf_iface
 
   struct top_hash_entry *net_lsa;      /* Originated network LSA */
   int orignet;                         /* Schedule network LSA origination */
-#ifdef OSPFv3
   int origlink;                                /* Schedule link LSA origination */
   struct top_hash_entry *link_lsa;     /* Originated link LSA */
   struct top_hash_entry *pxn_lsa;      /* Originated prefix LSA */
-#endif
   int fadj;                            /* Number of full adjacent neigh */
   list nbma_list;
   u8 priority;                 /* A router priority for DR election */
@@ -290,57 +267,30 @@ union ospf_auth
 
 
 /* Packet types */
-#define HELLO_P 1              /* Hello */
-#define DBDES_P 2              /* Database description */
-#define LSREQ_P 3              /* Link state request */
-#define LSUPD_P 4              /* Link state update */
-#define LSACK_P 5              /* Link state acknowledgement */
+#define HELLO_P                1       /* Hello */
+#define DBDES_P                2       /* Database description */
+#define LSREQ_P                3       /* Link state request */
+#define LSUPD_P                4       /* Link state update */
+#define LSACK_P                5       /* Link state acknowledgement */
 
 /* Area IDs */
-#define BACKBONE 0
-
-
-struct immsb
-{
-#ifdef CPU_BIG_ENDIAN
-  u8 padding:5;
-  u8 i:1;
-  u8 m:1;
-  u8 ms:1;
-#else
-  u8 ms:1;
-  u8 m:1;
-  u8 i:1;
-  u8 padding:5;
-#endif
-};
+#define BACKBONE       0
 
-union imms
-{
-  u8 byte;
-  struct immsb bit;
-};
-#define DBDES_MS 1
-#define DBDES_M 2
-#define DBDES_I 4
 
+#define DBDES_I                4       /* Init bit */
+#define DBDES_M                2       /* More bit */
+#define DBDES_MS       1       /* Master/Slave bit */
+#define DBDES_IMMS     (DBDES_I | DBDES_M | DBDES_MS)
 
-#ifdef OSPFv2
 
-struct ospf_packet
-{
-  u8 version;
-  u8 type;
-  u16 length;
-  u32 routerid;
-  u32 areaid;
-  u16 checksum;
-  u16 autype;
-  union ospf_auth u;
-};
 
 
-#else /* OSPFv3 packet descriptions */
+/*
+ * There is slight difference in OSPF packet header between v2 and v3
+ * in vdep field. For OSPFv2, vdep is u16 authentication type and
+ * ospf_header is followed by union ospf_auth. For OSPFv3, higher byte
+ * of vdep is instance ID and lower byte is zero.
+ */
 
 struct ospf_packet
 {
@@ -350,41 +300,19 @@ struct ospf_packet
   u32 routerid;
   u32 areaid;
   u16 checksum;
-  u8 instance_id;
-  u8 zero;
+  u16 vdep;
 };
 
 
-#endif
-
-
-
-
-struct ospf_lsa_header
-{
-  u16 age;                     /* LS Age */
-#define LSA_MAXAGE 3600                /* 1 hour */
-#define LSA_CHECKAGE 300       /* 5 minutes */
-#define LSA_MAXAGEDIFF 900     /* 15 minutes */
-
-#ifdef OSPFv2
-  u8 options;
-  u8 type;
-
+// XXXX
+/*
 #define LSA_T_RT       1
 #define LSA_T_NET      2
 #define LSA_T_SUM_NET  3
 #define LSA_T_SUM_RT   4
 #define LSA_T_EXT      5
 #define LSA_T_NSSA     7
-
-#define LSA_SCOPE_AREA 0x2000
-#define LSA_SCOPE_AS   0x4000
-
-#define LSA_SCOPE(lsa) (((lsa)->type == LSA_T_EXT) ? LSA_SCOPE_AS : LSA_SCOPE_AREA)
-
-#else /* OSPFv3 */
-  u16 type;
+*/
 
 #define LSA_T_RT       0x2001
 #define LSA_T_NET      0x2002
@@ -402,91 +330,76 @@ struct ospf_lsa_header
 #define LSA_SCOPE_AS   0x4000
 #define LSA_SCOPE_RES  0x6000
 #define LSA_SCOPE_MASK 0x6000
+#define LSA_SCOPE(lsa) ((lsa) & LSA_SCOPE_MASK)
 
-#define LSA_SCOPE(lsa) ((lsa)->type & LSA_SCOPE_MASK)
-#endif
+
+#define LSA_MAXAGE     3600    /* 1 hour */
+#define LSA_CHECKAGE   300     /* 5 minutes */
+#define LSA_MAXAGEDIFF 900     /* 15 minutes */
+
+#define LSA_INITSEQNO  ((s32) 0x80000001)
+#define LSA_MAXSEQNO   ((s32) 0x7fffffff)
+
+
+#define LSART_PTP      1
+#define LSART_NET      2
+#define LSART_STUB     3
+#define LSART_VLNK     4
+
+#define LSA_SUM2_TOS   0xFF000000
+
+#define LSA_EXT2_TOS   0x7F000000
+#define LSA_EXT2_EBIT  0x80000000
+
+#define LSA_EXT3_EBIT  0x4000000
+#define LSA_EXT3_FBIT  0x2000000
+#define LSA_EXT3_TBIT  0x1000000
+
+// XXXX remove
+#define LSA_EXT_EBIT   0x4000000
+
+
+struct ospf_lsa_header
+{
+  u16 age;                     /* LS Age */
+  u16 type_raw;                        /* Type, mixed with options on OSPFv2 */
 
   u32 id;
   u32 rt;                      /* Advertising router */
   s32 sn;                      /* LS Sequence number */
-#define LSA_INITSEQNO ((s32) 0x80000001)
-#define LSA_MAXSEQNO ((s32) 0x7fffffff)
   u16 checksum;
   u16 length;
 };
 
+/* In OSPFv2, options are embedded in higher half of type_raw */
+static inline u8 lsa_get_options(struct ospf_lsa_header *lsa)
+{ return lsa->type_raw >> 8; }
 
-#define LSART_PTP 1
-#define LSART_NET 2
-#define LSART_STUB 3
-#define LSART_VLNK 4
+static inline void lsa_set_options(struct ospf_lsa_header *lsa, u16 options)
+{ lsa->type_raw = (lsa->type_raw & 0xff) | (options << 8); }
 
 
-#ifdef OSPFv2
-
 struct ospf_lsa_rt
 {
-#ifdef CPU_BIG_ENDIAN
-  u16 options; /* VEB flags only */
-  u16 links;
-#else
-  u16 links;
-  u16 options; /* VEB flags only */
-#endif
+  u32 options; /* VEB flags, mixed with link count for OSPFv2 and options for OSPFv3 */
 };
 
-struct ospf_lsa_rt_link
+struct ospf_lsa_rt2_link
 {
   u32 id;
   u32 data;
 #ifdef CPU_BIG_ENDIAN
   u8 type;
-  u8 padding;
+  u8 no_tos;
   u16 metric;
 #else
   u16 metric;
-  u8 padding;
+  u8 no_tos;
   u8 type;
 #endif
 };
 
-struct ospf_lsa_net
-{
-  ip_addr netmask;
-  u32 routers[];
-};
-
-struct ospf_lsa_sum
-{
-  ip_addr netmask;
-  u32 metric;
-};
-
-struct ospf_lsa_ext
-{
-  ip_addr netmask;
-  u32 metric;
-  ip_addr fwaddr;
-  u32 tag;
-};
-
-#define LSA_SUM_TOS  0xFF000000
-#define LSA_EXT_TOS  0x7F000000
-#define LSA_EXT_EBIT 0x80000000
-
-/* Endianity swap for lsa->type */
-#define ntoht(x) x
-#define htont(x) x
-
-
-#else  /* OSPFv3 */
-
-struct ospf_lsa_rt
-{
-  u32 options;
-};
-
-struct ospf_lsa_rt_link
+struct ospf_lsa_rt3_link
 {
 #ifdef CPU_BIG_ENDIAN
   u8 type;
@@ -502,35 +415,58 @@ struct ospf_lsa_rt_link
   u32 id;      /* Neighbor router ID */
 };
 
+
 struct ospf_lsa_net
 {
-  u32 options;
+  u32 optx;    /* Netmask for OSPFv2, options for OSPFv3 */
   u32 routers[];
 };
 
-struct ospf_lsa_sum_net
+struct ospf_lsa_sum2
+{
+  ip4_addr netmask;
+  u32 metric;
+};
+
+struct ospf_lsa_sum3_net
 {
   u32 metric;
   u32 prefix[];
 };
 
-struct ospf_lsa_sum_rt
+struct ospf_lsa_sum3_rt
 {
   u32 options;
   u32 metric;
   u32 drid;
 };
 
-struct ospf_lsa_ext
+struct ospf_lsa_ext2
+{
+  ip4_addr netmask;
+  u32 metric;
+  ip4_addr fwaddr;
+  u32 tag;
+};
+
+struct ospf_lsa_ext3
 {
   u32 metric;
   u32 rest[];
 };
 
+struct ospf_lsa_ext_local
+{
+  ip_addr ip, fwaddr;
+  int pxlen;
+  u32 metric, ebit, fbit, tag, propagate;
+  u8 pxopts;
+};
+
 struct ospf_lsa_link
 {
   u32 options;
-  ip_addr lladdr;
+  ip6_addr lladdr;
   u32 pxcount;
   u32 rest[];
 };
@@ -549,9 +485,21 @@ struct ospf_lsa_prefix
   u32 rest[];
 };
 
-#define LSA_EXT_EBIT 0x4000000
-#define LSA_EXT_FBIT 0x2000000
-#define LSA_EXT_TBIT 0x1000000
+
+
+
+#ifdef OSPFv2
+
+
+/* Endianity swap for lsa->type */
+#define ntoht(x) x
+#define htont(x) x
+
+
+#else  /* OSPFv3 */
+
+
+
 
 /* Endianity swap for lsa->type */
 #define ntoht(x) ntohs(x)
@@ -562,12 +510,6 @@ struct ospf_lsa_prefix
 #define METRIC_MASK  0x00FFFFFF
 #define OPTIONS_MASK 0x00FFFFFF
 
-static inline unsigned
-lsa_rt_count(struct ospf_lsa_header *lsa)
-{
-  return (lsa->length - sizeof(struct ospf_lsa_header) - sizeof(struct ospf_lsa_rt))
-    / sizeof(struct ospf_lsa_rt_link);
-}
 
 static inline unsigned
 lsa_net_count(struct ospf_lsa_header *lsa)
@@ -672,10 +614,11 @@ struct ospf_neighbor
 #define NEIGHBOR_LOADING 6
 #define NEIGHBOR_FULL 7
   timer *inactim;              /* Inactivity timer */
-  union imms imms;             /* I, M, Master/slave received */
+  u8 imms;                     /* I, M, Master/slave received */
+  u8 myimms;                   /* I, M Master/slave */
   u32 dds;                     /* DD Sequence number being sent */
   u32 ddr;                     /* last Dat Des packet received */
-  union imms myimms;           /* I, M Master/slave */
+
   u32 rid;                     /* Router ID */
   ip_addr ip;                  /* IP of it's interface */
   u8 priority;                 /* Priority */
@@ -686,10 +629,7 @@ struct ospf_neighbor
      we use the same type to simplify handling */
   u32 dr;                      /* Neigbour's idea of DR */
   u32 bdr;                     /* Neigbour's idea of BDR */
-
-#ifdef OSPFv3
   u32 iface_id;                        /* ID of Neighbour's iface connected to common network */
-#endif
 
   siterator dbsi;              /* Database summary list iterator */
   slist lsrql;                 /* Link state request */
@@ -808,14 +748,8 @@ struct ospf_iface_patt
   u8 check_link;
   u8 ecmp_weight;
   u8 real_bcast;               /* Not really used in OSPFv3 */
-
-#ifdef OSPFv2
   list *passwords;
-#endif
-
-#ifdef OSPFv3
   u8 instance_id;
-#endif
 };
 
 int ospf_import_control(struct proto *p, rte **new, ea_list **attrs,
@@ -826,6 +760,14 @@ void schedule_rt_lsa(struct ospf_area *oa);
 void schedule_rtcalc(struct proto_ospf *po);
 void schedule_net_lsa(struct ospf_iface *ifa);
 
+static inline int ospf_is_v2(struct proto_ospf *po)
+{ return 0; } // XXXX fixme
+static inline int ospf_is_v3(struct proto_ospf *po)
+{ return 1; } // XXXX fixme
+
+static inline void lsa_fix_options(struct proto_ospf *po, struct ospf_lsa_header *lsa, u8 options)
+{ if (ospf_is_v2(po)) lsa_set_options(lsa, options); }
+
 struct ospf_area *ospf_find_area(struct proto_ospf *po, u32 aid);
 static inline struct ospf_area *ospf_main_area(struct proto_ospf *po)
 { return (po->areano == 1) ? HEAD(po->area_list) : po->backbone; }
@@ -838,11 +780,8 @@ static inline int oa_is_nssa(struct ospf_area *oa)
 { return oa->options & OPT_N; }
 
 
-#ifdef OSPFv3
-void schedule_link_lsa(struct ospf_iface *ifa);
-#else
-static inline void schedule_link_lsa(struct ospf_iface *ifa UNUSED) {}
-#endif
+
+void schedule_link_lsa(struct ospf_iface *ifa); // XXXX caller ?? 
 
 void ospf_sh_neigh(struct proto *p, char *iff);
 void ospf_sh(struct proto *p);
index 241a58f73831309f6080e5be6db4ed249132418e..f42f6a10b7a9ecda7d2d377428c78470c2fd1f7d 100644 (file)
@@ -439,7 +439,7 @@ ospf_rx_hook(sock *sk, int size)
   struct ospf_neighbor *n = find_neigh(ifa, rid);
 #endif
 
-  if(!n && (ps->type != HELLO_P))
+  if (!n && (ps->type != HELLO_P))
   {
     log(L_WARN "OSPF: Received non-hello packet from unknown neighbor (src %I, iface %s)",
        sk->faddr, ifa->iface->name);
index 4ef8f416d85f5388088745a9e64ba7895fa4ca99..40de6561eab9986539c318575bec2c3d00acf73b 100644 (file)
@@ -18,7 +18,7 @@ static void rt_sync(struct proto_ospf *po);
 #ifdef OSPFv2
 #define ipa_from_rid(x) _MI(x)
 #else /* OSPFv3 */
-#define ipa_from_rid(x) _MI(0,0,0,x)
+#define ipa_from_rid(x) _MI6(0,0,0,x)
 #endif
 
 
@@ -249,7 +249,6 @@ rt_pos_to_ifa(struct ospf_area *oa, int pos)
   return NULL;
 }
 
-#ifdef OSPFv3
 static inline struct ospf_iface *
 px_pos_to_ifa(struct ospf_area *oa, int pos)
 {
@@ -259,12 +258,13 @@ px_pos_to_ifa(struct ospf_area *oa, int pos)
       return ifa;
   return NULL;
 }
-#endif
 
 
 static void
 add_network(struct ospf_area *oa, ip_addr px, int pxlen, int metric, struct top_hash_entry *en, int pos)
 {
+  struct proto_ospf *po = oa->po;
+
   orta nf = {
     .type = RTS_OSPF,
     .options = 0,
@@ -279,7 +279,7 @@ add_network(struct ospf_area *oa, ip_addr px, int pxlen, int metric, struct top_
   if (pxlen < 0 || pxlen > MAX_PREFIX_LENGTH)
   {
     log(L_WARN "%s: Invalid prefix in LSA (Type: %04x, Id: %R, Rt: %R)",
-       oa->po->proto.name, en->lsa.type, en->lsa.id, en->lsa.rt);
+       po->proto.name, en->lsa_type, en->lsa.id, en->lsa.rt);
     return;
   }
 
@@ -294,21 +294,115 @@ add_network(struct ospf_area *oa, ip_addr px, int pxlen, int metric, struct top_
      */
 
     struct ospf_iface *ifa;
-#ifdef OSPFv2
-    ifa = rt_pos_to_ifa(oa, pos);
-#else /* OSPFv3 */
-    ifa = px_pos_to_ifa(oa, pos);
-#endif
+    ifa = ospf_is_v2(po) ? rt_pos_to_ifa(oa, pos) : px_pos_to_ifa(oa, pos);
+    nf.nhs = ifa ? new_nexthop(po, IPA_NONE, ifa->iface, ifa->ecmp_weight) : NULL;
+  }
+
+  ri_install_net(po, px, pxlen, &nf);
+}
+
+
+
+static inline void
+spfa_process_rt(struct ospf_area *oa, struct top_hash_entry *act)
+{
+  struct proto_ospf *po = oa->po;
+  struct ospf_lsa_rt *rt = act->lsa_body;
+  struct ospf_lsa_rt_walk rtl;
+  struct top_hash_entry *tmp;
+  ip_addr prefix;
+  int pxlen;
+
+  if (rt->options & OPT_RT_V)
+    oa->trcap = 1;
 
-    nf.nhs = ifa ? new_nexthop(oa->po, IPA_NONE, ifa->iface, ifa->ecmp_weight) : NULL;
+  /*
+   * In OSPFv3, all routers are added to per-area routing
+   * tables. But we use it just for ASBRs and ABRs. For the
+   * purpose of the last step in SPF - prefix-LSA processing in
+   * spfa_process_prefixes(), we use information stored in LSA db.
+   */
+  if (((rt->options & OPT_RT_E) || (rt->options & OPT_RT_B))
+      && (act->lsa.rt != po->router_id))
+  {
+    orta nf = {
+      .type = RTS_OSPF,
+      .options = rt->options,
+      .metric1 = act->dist,
+      .metric2 = LSINFINITY,
+      .tag = 0,
+      .rid = act->lsa.rt,
+      .oa = oa,
+      .nhs = act->nhs
+    };
+    ri_install_rt(oa, act->lsa.rt, &nf);
   }
 
-  ri_install_net(oa->po, px, pxlen, &nf);
+  /* Now process Rt links */
+  lsa_walk_rt_init(po, act, &rtl);
+  while (lsa_walk_rt(&rtl))
+  {
+    tmp = NULL;
+
+    switch (rtl.type)
+    {
+    case LSART_STUB:
+
+      /* Should not happen, LSART_STUB is not defined in OSPFv3 */
+      if (ospf_is_v3(po))
+       break;
+
+      /*
+       * RFC 2328 in 16.1. (2a) says to handle stub networks in an
+       * second phase after the SPF for an area is calculated. We get
+       * the same result by handing them here because add_network()
+       * will keep the best (not the first) found route.
+       */
+      prefix = ipa_from_u32(rtl.id & rtl.data);
+      pxlen = u32_masklen(rtl.data);
+      add_network(oa, prefix, pxlen, act->dist + rtl.metric, act, i);
+      break;
+
+    case LSART_NET:
+      tmp = ospf_hash_find_net(po->gr, oa->areaid, rtl.id, rtl.nif);
+      break;
+
+    case LSART_VLNK:
+    case LSART_PTP:
+      tmp = ospf_hash_find_rt(po->gr, oa->areaid, rtl.id);
+      break;
+    }
+
+    add_cand(&oa->cand, tmp, act, act->dist + rtl.metric, oa, i);
+  }
 }
 
-#ifdef OSPFv3
-static void
-process_prefixes(struct ospf_area *oa)
+static inline void
+spfa_process_net(struct ospf_area *oa, struct top_hash_entry *act)
+{
+  struct proto_ospf *po = oa->po;
+  struct ospf_lsa_net *ln = act->lsa_body;
+  struct top_hash_entry *tmp;
+  ip_addr prefix;
+  int pxlen, i, cnt;
+
+  if (ospf_is_v2(po))
+  {
+    prefix = ipa_from_u32(act->lsa.id & ln->optx);
+    pxlen = u32_masklen(ln->optx);
+    add_network(oa, prefix, pxlen, act->dist, act, -1);
+  }
+
+  cnt = lsa_net_count(&act->lsa);
+  for (i = 0; i < cnt; i++)
+  {
+    tmp = ospf_hash_find_rt(po->gr, oa->areaid, ln->routers[i]);
+    add_cand(&oa->cand, tmp, act, act->dist, oa, -1);
+  }
+}
+
+static inline void
+spfa_process_prefixes(struct ospf_area *oa)
 {
   struct proto_ospf *po = oa->po;
   // struct proto *p = &po->proto;
@@ -323,7 +417,7 @@ process_prefixes(struct ospf_area *oa)
 
   WALK_SLIST(en, po->lsal)
   {
-    if (en->lsa.type != LSA_T_PREFIX)
+    if (en->lsa_type != LSA_T_PREFIX)
       continue;
 
     if (en->domain != oa->areaid)
@@ -347,7 +441,7 @@ process_prefixes(struct ospf_area *oa)
     if (src->color != INSPF)
       continue;
 
-    if ((src->lsa.type != LSA_T_RT) && (src->lsa.type != LSA_T_NET))
+    if ((src->lsa_type != LSA_T_RT) && (src->lsa_type != LSA_T_NET))
       continue;
 
     buf = px->rest;
@@ -366,80 +460,14 @@ process_prefixes(struct ospf_area *oa)
       }
   }
 }
-#endif
-
-
-static void
-ospf_rt_spfa_rtlinks(struct ospf_area *oa, struct top_hash_entry *act, struct top_hash_entry *en)
-{
-  // struct proto *p = &oa->po->proto;
-  struct proto_ospf *po = oa->po;
-  ip_addr prefix UNUSED;
-  int pxlen UNUSED, i;
-
-  struct ospf_lsa_rt *rt = en->lsa_body;
-  struct ospf_lsa_rt_link *rr = (struct ospf_lsa_rt_link *) (rt + 1);
-
-  for (i = 0; i < lsa_rt_count(&en->lsa); i++)
-    {
-      struct ospf_lsa_rt_link *rtl = rr + i;
-      struct top_hash_entry *tmp = NULL;
-
-      DBG("     Working on link: %R (type: %u)  ", rtl->id, rtl->type);
-      switch (rtl->type)
-       {
-#ifdef OSPFv2
-       case LSART_STUB:
-         /*
-          * RFC 2328 in 16.1. (2a) says to handle stub networks in an
-          * second phase after the SPF for an area is calculated. We get
-          * the same result by handing them here because add_network()
-          * will keep the best (not the first) found route.
-          */
-         prefix = ipa_from_u32(rtl->id & rtl->data);
-         pxlen = ipa_mklen(ipa_from_u32(rtl->data));
-         add_network(oa, prefix, pxlen, act->dist + rtl->metric, act, i);
-         break;
-#endif
-
-       case LSART_NET:
-#ifdef OSPFv2
-         /* In OSPFv2, rtl->id is IP addres of DR, Router ID is not known */
-         tmp = ospf_hash_find_net(po->gr, oa->areaid, rtl->id);
-#else /* OSPFv3 */
-         tmp = ospf_hash_find(po->gr, oa->areaid, rtl->nif, rtl->id, LSA_T_NET);
-#endif
-         break;
-
-       case LSART_VLNK:
-       case LSART_PTP:
-         tmp = ospf_hash_find_rt(po->gr, oa->areaid, rtl->id);
-         break;
-
-       default:
-         log("Unknown link type in router lsa. (rid = %R)", act->lsa.id);
-         break;
-       }
-
-      if (tmp)
-       DBG("Going to add cand, Mydist: %u, Req: %u\n",
-           tmp->dist, act->dist + rtl->metric);
-      add_cand(&oa->cand, tmp, act, act->dist + rtl->metric, oa, i);
-    }
-}
 
 /* RFC 2328 16.1. calculating shortest paths for an area */
 static void
 ospf_rt_spfa(struct ospf_area *oa)
 {
-  struct proto *p = &oa->po->proto;
   struct proto_ospf *po = oa->po;
-  struct ospf_lsa_rt *rt;
-  struct ospf_lsa_net *ln;
-  struct top_hash_entry *act, *tmp;
-  ip_addr prefix UNUSED;
-  int pxlen UNUSED;
-  u32 i, *rts;
+  struct proto *p = &po->proto;
+  struct top_hash_entry *act;
   node *n;
 
   if (oa->rt == NULL)
@@ -457,7 +485,7 @@ ospf_rt_spfa(struct ospf_area *oa)
   oa->rt->color = CANDIDATE;
   add_head(&oa->cand, &oa->rt->cn);
   DBG("RT LSA: rt: %R, id: %R, type: %u\n",
-      oa->rt->lsa.rt, oa->rt->lsa.id, oa->rt->lsa.type);
+      oa->rt->lsa.rt, oa->rt->lsa.id, oa->rt->lsa_type);
 
   while (!EMPTY_LIST(oa->cand))
   {
@@ -466,85 +494,37 @@ ospf_rt_spfa(struct ospf_area *oa)
     rem_node(n);
 
     DBG("Working on LSA: rt: %R, id: %R, type: %u\n",
-       act->lsa.rt, act->lsa.id, act->lsa.type);
+       act->lsa.rt, act->lsa.id, act->lsa_type);
 
     act->color = INSPF;
-    switch (act->lsa.type)
+    switch (act->lsa_type)
     {
     case LSA_T_RT:
-      rt = (struct ospf_lsa_rt *) act->lsa_body;
-      if (rt->options & OPT_RT_V)
-       oa->trcap = 1;
-
-      /*
-       * In OSPFv3, all routers are added to per-area routing
-       * tables. But we use it just for ASBRs and ABRs. For the
-       * purpose of the last step in SPF - prefix-LSA processing in
-       * process_prefixes(), we use information stored in LSA db.
-       */
-      if (((rt->options & OPT_RT_E) || (rt->options & OPT_RT_B))
-         && (act->lsa.rt != po->router_id))
-      {
-       orta nf = {
-         .type = RTS_OSPF,
-         .options = rt->options,
-         .metric1 = act->dist,
-         .metric2 = LSINFINITY,
-         .tag = 0,
-         .rid = act->lsa.rt,
-         .oa = oa,
-         .nhs = act->nhs
-       };
-       ri_install_rt(oa, act->lsa.rt, &nf);
-      }
-
-#ifdef OSPFv2
-      ospf_rt_spfa_rtlinks(oa, act, act);
-#else /* OSPFv3 */
-      for (tmp = ospf_hash_find_rt_first(po->gr, act->domain, act->lsa.rt);
-          tmp; tmp = ospf_hash_find_rt_next(tmp))
-       ospf_rt_spfa_rtlinks(oa, act, tmp);
-#endif
-
+      spfa_process_rt(oa, act);
       break;
-    case LSA_T_NET:
-      ln = act->lsa_body;
 
-#ifdef OSPFv2
-      prefix = ipa_and(ipa_from_u32(act->lsa.id), ln->netmask);
-      pxlen = ipa_mklen(ln->netmask);
-      add_network(oa, prefix, pxlen, act->dist, act, -1);
-#endif
-
-      rts = (u32 *) (ln + 1);
-      for (i = 0; i < lsa_net_count(&act->lsa); i++)
-      {
-       DBG("     Working on router %R ", rts[i]);
-       tmp = ospf_hash_find_rt(po->gr, oa->areaid, rts[i]);
-       if (tmp != NULL)
-         DBG("Found :-)\n");
-       else
-         DBG("Not found!\n");
-       add_cand(&oa->cand, tmp, act, act->dist, oa, -1);
-      }
+    case LSA_T_NET:
+      spfa_process_net(oa, act);
       break;
+
+    default:
+      log(L_WARN "%s: Unknown LSA type in SPF: %d", p->name, act->lsa_type);
     }
   }
 
-#ifdef OSPFv3
-  process_prefixes(oa);
-#endif
+  if (ospf_is_v3(po))
+    spfa_process_prefixes(oa);
 }
 
 static int
 link_back(struct ospf_area *oa, struct top_hash_entry *en, struct top_hash_entry *par)
 {
-  u32 i, *rts;
-  struct ospf_lsa_net *ln;
-  struct ospf_lsa_rt *rt;
-  struct ospf_lsa_rt_link *rtl, *rr;
-  struct top_hash_entry *tmp;
   struct proto_ospf *po = oa->po;
+  struct proto *p = &po->proto;
+  struct ospf_lsa_rt_walk rtl;
+  struct top_hash_entry *tmp;
+  struct ospf_lsa_net *ln;
+  u32 i, cnt;
 
   if (!en || !par) return 0;
 
@@ -559,65 +539,56 @@ link_back(struct ospf_area *oa, struct top_hash_entry *en, struct top_hash_entry
      it is set in process_prefixes() to any global addres in the area */
 
   en->lb = IPA_NONE;
-#ifdef OSPFv3
   en->lb_id = 0;
-#endif
-  switch (en->lsa.type)
+
+  switch (en->lsa_type)
   {
     case LSA_T_RT:
-      rt = (struct ospf_lsa_rt *) en->lsa_body;
-      rr = (struct ospf_lsa_rt_link *) (rt + 1);
-      for (i = 0; i < lsa_rt_count(&en->lsa); i++)
+      lsa_walk_rt_init(po, en, &rtl);
+      while (lsa_walk_rt(&rtl))
       {
-       rtl = (rr + i);
-       switch (rtl->type)
+       switch (rtl.type)
        {
        case LSART_STUB:
          break;
+
        case LSART_NET:
-#ifdef OSPFv2
-         /* In OSPFv2, rtl->id is IP addres of DR, Router ID is not known */
-         tmp = ospf_hash_find_net(po->gr, oa->areaid, rtl->id);
-#else /* OSPFv3 */
-         tmp = ospf_hash_find(po->gr, oa->areaid, rtl->nif, rtl->id, LSA_T_NET);
-#endif
+         tmp = ospf_hash_find_net(po->gr, oa->areaid, rtl.id, rtl.nif);
          if (tmp == par)
          {
-#ifdef OSPFv2
-           en->lb = ipa_from_u32(rtl->data);
-#else /* OSPFv3 */
-           en->lb_id = rtl->lif;
-#endif
+           if (ospf_is_v2(po))
+             en->lb = ipa_from_u32(rtl.data);
+           else
+             en->lb_id = rtl.lif;
+
            return 1;
          }
-
          break;
+
        case LSART_VLNK:
        case LSART_PTP:
          /* Not necessary the same link, see RFC 2328 [23] */
-         tmp = ospf_hash_find_rt(po->gr, oa->areaid, rtl->id);
+         tmp = ospf_hash_find_rt(po->gr, oa->areaid, rtl.id);
          if (tmp == par)
             return 1;
-
-         break;
-       default:
-         log(L_WARN "Unknown link type in router lsa. (rid = %R)", en->lsa.rt);
          break;
        }
       }
       break;
+
     case LSA_T_NET:
       ln = en->lsa_body;
-      rts = (u32 *) (ln + 1);
-      for (i = 0; i < lsa_net_count(&en->lsa); i++)
+      cnt = lsa_net_count(&en->lsa);
+      for (i = 0; i < cnt; i++)
       {
-       tmp = ospf_hash_find_rt(po->gr, oa->areaid, rts[i]);
+       tmp = ospf_hash_find_rt(po->gr, oa->areaid, ln->routers[i]);
        if (tmp == par)
           return 1;
       }
       break;
+
     default:
-      bug("Unknown lsa type %x.", en->lsa.type);
+      log(L_WARN "%s: Unknown LSA type in SPF: %d", p->name, en->lsa_type);
   }
   return 0;
 }
@@ -630,17 +601,18 @@ ospf_rt_sum(struct ospf_area *oa)
   struct proto_ospf *po = oa->po;
   struct proto *p = &po->proto;
   struct top_hash_entry *en;
-  ip_addr ip = IPA_NONE;
-  u32 dst_rid = 0;
-  u32 metric, options;
+  ip_addr ip, abrip;
+  u32 dst_rid, metric, options;
   ort *abr;
   int pxlen = -1, type = -1;
+  u8 pxopts;
+  
 
   OSPF_TRACE(D_EVENTS, "Starting routing table calculation for inter-area (area %R)", oa->areaid);
 
   WALK_SLIST(en, po->lsal)
   {
-    if ((en->lsa.type != LSA_T_SUM_RT) && (en->lsa.type != LSA_T_SUM_NET))
+    if ((en->lsa_type != LSA_T_SUM_RT) && (en->lsa_type != LSA_T_SUM_NET))
       continue;
 
     if (en->domain != oa->areaid)
@@ -656,50 +628,31 @@ ospf_rt_sum(struct ospf_area *oa)
 
     /* 16.2. (3) is handled later in ospf_rt_abr() by resetting such rt entry */
 
-    if (en->lsa.type == LSA_T_SUM_NET)
+    if (en->lsa_type == LSA_T_SUM_NET)
     {
-#ifdef OSPFv2
-      struct ospf_lsa_sum *ls = en->lsa_body;
-      ip = ipa_and(ipa_from_u32(en->lsa.id), ls->netmask);
-      pxlen = ipa_mklen(ls->netmask);
-#else /* OSPFv3 */
-      u8 pxopts;
-      u16 rest;
-      struct ospf_lsa_sum_net *ls = en->lsa_body;
-      lsa_get_ipv6_prefix(ls->prefix, &ip, &pxlen, &pxopts, &rest);
+      lsa_parse_sum_net(en, ospf_is_v2(po), &ip, &pxlen, &pxopts, &metric);
 
       if (pxopts & OPT_PX_NU)
        continue;
-#endif
 
       if (pxlen < 0 || pxlen > MAX_PREFIX_LENGTH)
       {
        log(L_WARN "%s: Invalid prefix in LSA (Type: %04x, Id: %R, Rt: %R)",
-           p->name, en->lsa.type, en->lsa.id, en->lsa.rt);
+           p->name, en->lsa_type, en->lsa.id, en->lsa.rt);
        continue;
       }
 
-      metric = ls->metric & METRIC_MASK;
       options = 0;
       type = ORT_NET;
     }
     else /* LSA_T_SUM_RT */
     {
-#ifdef OSPFv2
-      struct ospf_lsa_sum *ls = en->lsa_body;
-      dst_rid = en->lsa.id;
-      options = 0;
-#else /* OSPFv3 */
-      struct ospf_lsa_sum_rt *ls = en->lsa_body;
-      dst_rid = ls->drid; 
-      options = ls->options & OPTIONS_MASK;
-#endif
+      lsa_parse_sum_rt(en, ospf_is_v2(po), &dst_rid, &metric, &options);
       
       /* We don't want local router in ASBR routing table */
       if (dst_rid == po->router_id)
        continue;
 
-      metric = ls->metric & METRIC_MASK;
       options |= ORTA_ASBR;
       type = ORT_ROUTER;
     }
@@ -709,7 +662,7 @@ ospf_rt_sum(struct ospf_area *oa)
       continue;
 
     /* 16.2. (4) */
-    ip_addr abrip = ipa_from_rid(en->lsa.rt);
+    abrip = ipa_from_rid(en->lsa.rt);
     abr = (ort *) fib_find(&oa->rtr, &abrip, MAX_PREFIX_LENGTH);
     if (!abr || !abr->n.type)
       continue;
@@ -744,20 +697,23 @@ ospf_rt_sum(struct ospf_area *oa)
 static void
 ospf_rt_sum_tr(struct ospf_area *oa)
 {
-  struct proto *p = &oa->po->proto;
   struct proto_ospf *po = oa->po;
+  struct proto *p = &po->proto;
   struct ospf_area *bb = po->backbone;
-  ip_addr abrip;
   struct top_hash_entry *en;
-  u32 dst_rid, metric;
-  ort *re = NULL, *abr;
+  ort *re, *abr;
+  ip_addr ip, abrip;
+  u32 dst_rid, metric, options;
+  int pxlen;
+  u8 pxopts;
 
 
-  if (!bb) return;
+  if (!bb)
+    return;
 
   WALK_SLIST(en, po->lsal)
   {
-    if ((en->lsa.type != LSA_T_SUM_RT) && (en->lsa.type != LSA_T_SUM_NET))
+    if ((en->lsa_type != LSA_T_SUM_RT) && (en->lsa_type != LSA_T_SUM_NET))
       continue;
 
     if (en->domain != oa->areaid)
@@ -771,46 +727,27 @@ ospf_rt_sum_tr(struct ospf_area *oa)
     if (en->lsa.rt == po->router_id)
       continue;
 
-    if (en->lsa.type == LSA_T_SUM_NET)
+    if (en->lsa_type == LSA_T_SUM_NET)
     {
-      ip_addr ip;
-      int pxlen;
-#ifdef OSPFv2
-      struct ospf_lsa_sum *ls = en->lsa_body;
-      ip = ipa_and(ipa_from_u32(en->lsa.id), ls->netmask);
-      pxlen = ipa_mklen(ls->netmask);
-#else /* OSPFv3 */
-      u8 pxopts;
-      u16 rest;
-      struct ospf_lsa_sum_net *ls = en->lsa_body;
-      lsa_get_ipv6_prefix(ls->prefix, &ip, &pxlen, &pxopts, &rest);
+      lsa_parse_sum_net(en, ospf_is_v2(po), &ip, &pxlen, &pxopts, &metric);
 
       if (pxopts & OPT_PX_NU)
        continue;
-#endif
 
       if (pxlen < 0 || pxlen > MAX_PREFIX_LENGTH)
       {
        log(L_WARN "%s: Invalid prefix in LSA (Type: %04x, Id: %R, Rt: %R)",
-           p->name, en->lsa.type, en->lsa.id, en->lsa.rt);
+           p->name, en->lsa_type, en->lsa.id, en->lsa.rt);
        continue;
       }
 
-      metric = ls->metric & METRIC_MASK;
       re = fib_find(&po->rtf, &ip, pxlen);
     }
-    else // en->lsa.type == LSA_T_SUM_RT
+    else // en->lsa_type == LSA_T_SUM_RT
     {
-#ifdef OSPFv2
-      struct ospf_lsa_sum *ls = en->lsa_body;
-      dst_rid = en->lsa.id;
-#else /* OSPFv3 */
-      struct ospf_lsa_sum_rt *ls = en->lsa_body;
-      dst_rid = ls->drid; 
-#endif
+      lsa_parse_sum_rt(en, ospf_is_v2(po), &dst_rid, &metric, &options);
 
-      metric = ls->metric & METRIC_MASK;
-      ip_addr ip = ipa_from_rid(dst_rid);
+      ip = ipa_from_rid(dst_rid);
       re = fib_find(&bb->rtr, &ip, MAX_PREFIX_LENGTH);
     }
 
@@ -979,11 +916,11 @@ check_sum_rt_lsa(struct proto_ospf *po, ort *nf)
 }
 
 static inline int
-decide_nssa_lsa(ort *nf, u32 *rt_metric, ip_addr *rt_fwaddr, u32 *rt_tag)
+decide_nssa_lsa(struct proto_ospf *po, ort *nf, u32 *rt_metric, ip_addr *rt_fwaddr, u32 *rt_tag)
 {
   struct ospf_area *oa = nf->n.oa;
   struct top_hash_entry *en = nf->n.en;
-  int propagate;
+  struct ospf_lsa_ext_local rt;
 
   if (!rt_is_nssa(nf) || !oa->translate)
     return 0;
@@ -992,42 +929,21 @@ decide_nssa_lsa(ort *nf, u32 *rt_metric, ip_addr *rt_fwaddr, u32 *rt_tag)
   if (fib_route(&oa->enet_fib, &nf->fn.prefix, nf->fn.pxlen))
     return 0;
 
-  if (!en || (en->lsa.type != LSA_T_NSSA))
+  if (!en || (en->lsa_type != LSA_T_NSSA))
     return 0;
 
   /* We do not store needed data in struct orta, we have to parse the LSA */
-  struct ospf_lsa_ext *le = en->lsa_body;
-
-#ifdef OSPFv2
-  *rt_fwaddr = le->fwaddr;
-  *rt_tag = le->tag;
-  propagate = en->lsa.options & OPT_P;
-#else /* OSPFv3 */
-  u32 *buf = le->rest;
-  u8 pxlen = (*buf >> 24);
-  u8 pxopts = (*buf >> 16);
-  buf += IPV6_PREFIX_WORDS(pxlen);  /* Skip the IP prefix */
-
-  if (pxopts & OPT_PX_NU)
+  lsa_parse_ext(en, ospf_is_v2(po), &rt);
+  
+  if (rt.pxopts & OPT_PX_NU)
     return 0;
 
-  if (le->metric & LSA_EXT_FBIT)
-    buf = lsa_get_ipv6_addr(buf, rt_fwaddr);
-  else
-    *rt_fwaddr = IPA_NONE;
-
-  if (le->metric & LSA_EXT_TBIT)
-    *rt_tag = *buf++;
-  else
-    *rt_tag = 0;
-
-  propagate = pxopts & OPT_PX_P;
-#endif
-
-  if (!propagate || ipa_zero(*rt_fwaddr))
+  if (!rt.propagate || ipa_zero(rt.fwaddr))
     return 0;
 
-  *rt_metric = le->metric & (METRIC_MASK | LSA_EXT_EBIT);
+  *rt_metric = rt.metric | rt.ebit;
+  *rt_fwaddr = rt.fwaddr;
+  *rt_tag = rt.tag;
   return 1;
 }
 
@@ -1062,7 +978,7 @@ check_nssa_lsa(struct proto_ospf *po, ort *nf)
     originate_ext_lsa(po->backbone, fn, EXT_NSSA, anet->metric, IPA_NONE, anet->tag, 0);
 
   /* RFC 3103 3.2 (2) - originate the same network */
-  else if (decide_nssa_lsa(nf, &rt_metric, &rt_fwaddr, &rt_tag))
+  else if (decide_nssa_lsa(po, nf, &rt_metric, &rt_fwaddr, &rt_tag))
     originate_ext_lsa(po->backbone, fn, EXT_NSSA, rt_metric, rt_fwaddr, rt_tag, 0);
 
   else if (fn->flags & OSPF_RT_NSSA)
@@ -1073,8 +989,6 @@ check_nssa_lsa(struct proto_ospf *po, ort *nf)
 static void
 ospf_check_vlinks(struct proto_ospf *po)
 {
-  struct proto *p = &po->proto;
-
   struct ospf_iface *iface;
   WALK_LIST(iface, po->iface_list)
   {
@@ -1358,14 +1272,13 @@ ospf_fib_route(struct fib *f, ip_addr a, int len)
 static void
 ospf_ext_spf(struct proto_ospf *po)
 {
+  struct proto *p = &po->proto;
+  struct top_hash_entry *en;
+  struct ospf_lsa_ext_local rt;
   ort *nf1, *nf2;
   orta nfa;
-  struct top_hash_entry *en;
-  struct proto *p = &po->proto;
-  struct ospf_lsa_ext *le;
-  int pxlen, ebit, rt_fwaddr_valid, rt_propagate;
-  ip_addr ip, rtid, rt_fwaddr;
-  u32 br_metric, rt_metric, rt_tag;
+  ip_addr rtid;
+  u32 br_metric;
   struct ospf_area *atmp;
   struct mpnh* nhs = NULL;
 
@@ -1374,7 +1287,7 @@ ospf_ext_spf(struct proto_ospf *po)
   WALK_SLIST(en, po->lsal)
   {
     /* 16.4. (1) */
-    if ((en->lsa.type != LSA_T_EXT) && (en->lsa.type != LSA_T_NSSA))
+    if ((en->lsa_type != LSA_T_EXT) && (en->lsa_type != LSA_T_NSSA))
       continue;
 
     if (en->lsa.age == LSA_MAXAGE)
@@ -1385,50 +1298,20 @@ ospf_ext_spf(struct proto_ospf *po)
       continue;
 
     DBG("%s: Working on LSA. ID: %R, RT: %R, Type: %u\n",
-       p->name, en->lsa.id, en->lsa.rt, en->lsa.type);
-
-    le = en->lsa_body;
+       p->name, en->lsa.id, en->lsa.rt, en->lsa_type);
 
-    rt_metric = le->metric & METRIC_MASK;
-    ebit = le->metric & LSA_EXT_EBIT;
+    lsa_parse_ext(en, ospf_is_v2(po), &rt);
 
-    if (rt_metric == LSINFINITY)
+    if (rt.metric == LSINFINITY)
       continue;
 
-#ifdef OSPFv2
-    ip = ipa_and(ipa_from_u32(en->lsa.id), le->netmask);
-    pxlen = ipa_mklen(le->netmask);
-    rt_fwaddr = le->fwaddr;
-    rt_fwaddr_valid = !ipa_equal(rt_fwaddr, IPA_NONE);
-    rt_tag = le->tag;
-    rt_propagate = en->lsa.options & OPT_P;
-#else /* OSPFv3 */
-    u8 pxopts;
-    u16 rest;
-    u32 *buf = le->rest;
-    buf = lsa_get_ipv6_prefix(buf, &ip, &pxlen, &pxopts, &rest);
-
-    if (pxopts & OPT_PX_NU)
+    if (rt.pxopts & OPT_PX_NU)
       continue;
 
-    rt_fwaddr_valid = le->metric & LSA_EXT_FBIT;
-    if (rt_fwaddr_valid)
-      buf = lsa_get_ipv6_addr(buf, &rt_fwaddr);
-    else 
-      rt_fwaddr = IPA_NONE;
-
-    if (le->metric & LSA_EXT_TBIT)
-      rt_tag = *buf++;
-    else
-      rt_tag = 0;
-
-    rt_propagate = pxopts & OPT_PX_P;
-#endif
-
-    if (pxlen < 0 || pxlen > MAX_PREFIX_LENGTH)
+    if (rt.pxlen < 0 || rt.pxlen > MAX_PREFIX_LENGTH)
     {
       log(L_WARN "%s: Invalid prefix in LSA (Type: %04x, Id: %R, Rt: %R)",
-         p->name, en->lsa.type, en->lsa.id, en->lsa.rt);
+         p->name, en->lsa_type, en->lsa.id, en->lsa.rt);
       continue;
     }
 
@@ -1437,7 +1320,7 @@ ospf_ext_spf(struct proto_ospf *po)
     /* If there are more areas, we already precomputed preferred ASBR
        entries in ospf_rt_abr1() and stored them in the backbone
        table. For NSSA, we examine the area to which the LSA is assigned */
-    if (en->lsa.type == LSA_T_EXT)
+    if (en->lsa_type == LSA_T_EXT)
       atmp = ospf_main_area(po);
     else /* NSSA */
       atmp = ospf_find_area(po, en->domain);
@@ -1456,11 +1339,11 @@ ospf_ext_spf(struct proto_ospf *po)
 
     /* 16.4. (3) NSSA - special rule for default routes */
     /* ABR should use default only if P-bit is set and summaries are active */
-    if ((en->lsa.type == LSA_T_NSSA) && ipa_zero(ip) && (pxlen == 0) &&
-       (po->areano > 1) && !(rt_propagate && atmp->ac->summary))
+    if ((en->lsa_type == LSA_T_NSSA) && ipa_zero(rt.ip) && (rt.pxlen == 0) &&
+       (po->areano > 1) && !(rt.propagate && atmp->ac->summary))
       continue;
 
-    if (!rt_fwaddr_valid)
+    if (!rt.fbit)
     {
       nf2 = nf1;
       nhs = nf1->n.nhs;
@@ -1468,11 +1351,11 @@ ospf_ext_spf(struct proto_ospf *po)
     }
     else
     {
-      nf2 = ospf_fib_route(&po->rtf, rt_fwaddr, MAX_PREFIX_LENGTH);
+      nf2 = ospf_fib_route(&po->rtf, rt.fwaddr, MAX_PREFIX_LENGTH);
       if (!nf2)
        continue;
 
-      if (en->lsa.type == LSA_T_EXT)
+      if (en->lsa_type == LSA_T_EXT)
       {
        /* For ext routes, we accept intra-area or inter-area routes */
        if ((nf2->n.type != RTS_OSPF) && (nf2->n.type != RTS_OSPF_IA))
@@ -1492,20 +1375,20 @@ ospf_ext_spf(struct proto_ospf *po)
       nhs = nf2->n.nhs;
       /* If gw is zero, it is a device route */
       if (ipa_zero(nhs->gw))
-       nhs = new_nexthop(po, rt_fwaddr, nhs->iface, nhs->weight);
+       nhs = new_nexthop(po, rt.fwaddr, nhs->iface, nhs->weight);
       br_metric = nf2->n.metric1;
     }
 
-    if (ebit)
+    if (rt.ebit)
     {
       nfa.type = RTS_OSPF_EXT2;
       nfa.metric1 = br_metric;
-      nfa.metric2 = rt_metric;
+      nfa.metric2 = rt.metric;
     }
     else
     {
       nfa.type = RTS_OSPF_EXT1;
-      nfa.metric1 = br_metric + rt_metric;
+      nfa.metric1 = br_metric + rt.metric;
       nfa.metric2 = LSINFINITY;
     }
 
@@ -1514,21 +1397,21 @@ ospf_ext_spf(struct proto_ospf *po)
 
     /* Whether the route is preferred in route selection according to 16.4.1 */
     nfa.options = epath_preferred(&nf2->n) ? ORTA_PREF : 0;
-    if (en->lsa.type == LSA_T_NSSA)
+    if (en->lsa_type == LSA_T_NSSA)
     {
       nfa.options |= ORTA_NSSA;
-      if (rt_propagate)
+      if (rt.propagate)
        nfa.options |= ORTA_PROP;
     }
 
-    nfa.tag = rt_tag;
+    nfa.tag = rt.tag;
     nfa.rid = en->lsa.rt;
     nfa.oa = atmp; /* undefined in RFC 2328 */
     nfa.voa = NULL;
     nfa.nhs = nhs;
     nfa.en = en; /* store LSA for later (NSSA processing) */
 
-    ri_install_ext(po, ip, pxlen, &nfa);
+    ri_install_ext(po, rt.ip, rt.pxlen, &nfa);
   }
 }
 
@@ -1602,7 +1485,6 @@ ospf_rt_reset(struct proto_ospf *po)
 void
 ospf_rt_spf(struct proto_ospf *po)
 {
-  struct proto *p = &po->proto;
   struct ospf_area *oa;
 
   if (po->areano == 0)
@@ -1660,7 +1542,7 @@ calc_next_hop(struct ospf_area *oa, struct top_hash_entry *en,
 
   /* 16.1.1. The next hop calculation */
   DBG("     Next hop calculating for id: %R rt: %R type: %u\n",
-      en->lsa.id, en->lsa.rt, en->lsa.type);
+      en->lsa.id, en->lsa.rt, en->lsa_type);
 
   /* Usually, we inherit parent nexthops */
   if (inherit_nexthops(pn))
@@ -1674,7 +1556,7 @@ calc_next_hop(struct ospf_area *oa, struct top_hash_entry *en,
    */
 
   /* The first case - local network */
-  if ((en->lsa.type == LSA_T_NET) && (par == oa->rt))
+  if ((en->lsa_type == LSA_T_NET) && (par == oa->rt))
   {
     ifa = rt_pos_to_ifa(oa, pos);
     if (!ifa)
@@ -1684,7 +1566,7 @@ calc_next_hop(struct ospf_area *oa, struct top_hash_entry *en,
   }
 
   /* The second case - ptp or ptmp neighbor */
-  if ((en->lsa.type == LSA_T_RT) && (par == oa->rt))
+  if ((en->lsa_type == LSA_T_RT) && (par == oa->rt))
   {
     ifa = rt_pos_to_ifa(oa, pos);
     if (!ifa)
@@ -1701,40 +1583,42 @@ calc_next_hop(struct ospf_area *oa, struct top_hash_entry *en,
   }
 
   /* The third case - bcast or nbma neighbor */
-  if ((en->lsa.type == LSA_T_RT) && (par->lsa.type == LSA_T_NET))
+  if ((en->lsa_type == LSA_T_RT) && (par->lsa_type == LSA_T_NET))
   {
     /* par->nhi should be defined from parent's calc_next_hop() */
     if (!pn)
       goto bad;
 
-#ifdef OSPFv2
-    /*
-     * In this case, next-hop is the same as link-back, which is
-     * already computed in link_back().
-     */
-    if (ipa_zero(en->lb))
-      goto bad;
-
-    return new_nexthop(po, en->lb, pn->iface, pn->weight);
+    if (ospf_is_v2(po))
+    {
+      /*
+       * In this case, next-hop is the same as link-back, which is
+       * already computed in link_back().
+       */
+      if (ipa_zero(en->lb))
+       goto bad;
 
-#else /* OSPFv3 */
-    /*
-     * Next-hop is taken from lladdr field of Link-LSA, en->lb_id
-     * is computed in link_back().
-     */
-    struct top_hash_entry *lhe;
-    lhe = ospf_hash_find(po->gr, pn->iface->index, en->lb_id, rid, LSA_T_LINK);
+      return new_nexthop(po, en->lb, pn->iface, pn->weight);
+    }
+    else /* OSPFv3 */
+    {
+      /*
+       * Next-hop is taken from lladdr field of Link-LSA, en->lb_id
+       * is computed in link_back().
+       */
+      struct top_hash_entry *lhe;
+      lhe = ospf_hash_find(po->gr, pn->iface->index, en->lb_id, rid, LSA_T_LINK);
 
-    if (!lhe)
-      return NULL;
+      if (!lhe)
+       return NULL;
 
-    struct ospf_lsa_link *llsa = lhe->lsa_body;
+      struct ospf_lsa_link *llsa = lhe->lsa_body;
       
-    if (ipa_zero(llsa->lladdr))
-      return NULL;
+      if (ipa_zero(llsa->lladdr))
+       return NULL;
 
-    return new_nexthop(po, llsa->lladdr, pn->iface, pn->weight);
-#endif
+      return new_nexthop(po, llsa->lladdr, pn->iface, pn->weight);
+    }
   }
 
  bad:
@@ -1835,14 +1719,13 @@ add_cand(list * l, struct top_hash_entry *en, struct top_hash_entry *par,
   if (en->lsa.age == LSA_MAXAGE)
     return;
 
-#ifdef OSPFv3
-  if (en->lsa.type == LSA_T_RT)
+  if (ospf_is_v3(po) && (en->lsa_type == LSA_T_RT))
     {
+      /* In OSPFv3, check V6 and R flags */
       struct ospf_lsa_rt *rt = en->lsa_body;
       if (!(rt->options & OPT_V6) || !(rt->options & OPT_R))
        return;
     }
-#endif
 
   /* 16.1. (2c) */
   if (en->color == INSPF)
@@ -1860,7 +1743,7 @@ add_cand(list * l, struct top_hash_entry *en, struct top_hash_entry *par,
   if (!nhs)
   {
     log(L_WARN "Cannot find next hop for LSA (Type: %04x, Id: %R, Rt: %R)",
-       en->lsa.type, en->lsa.id, en->lsa.rt);
+       en->lsa_type, en->lsa.id, en->lsa.rt);
     return;
   }
 
@@ -1892,7 +1775,7 @@ add_cand(list * l, struct top_hash_entry *en, struct top_hash_entry *par,
   }
 
   DBG("     Adding candidate: rt: %R, id: %R, type: %u\n",
-      en->lsa.rt, en->lsa.id, en->lsa.type);
+      en->lsa.rt, en->lsa.id, en->lsa_type);
 
   if (en->color == CANDIDATE)
   {                            /* We found a shorter path */
@@ -1915,7 +1798,7 @@ add_cand(list * l, struct top_hash_entry *en, struct top_hash_entry *par,
     {
       act = SKIP_BACK(struct top_hash_entry, cn, n);
       if ((act->dist > dist) ||
-         ((act->dist == dist) && (act->lsa.type == LSA_T_RT)))
+         ((act->dist == dist) && (act->lsa_type == LSA_T_RT)))
       {
        if (prev == NULL)
          add_head(l, &en->cn);
index 9ae620fbca26d33678514d1f37b9ad966d02ff65..7e625493fb5ebd1f701f0115d21a6f4ff819adcf 100644 (file)
@@ -146,7 +146,7 @@ get_seqnum(struct top_hash_entry *en)
   if (en->lsa.sn == LSA_MAXSEQNO)
   {
     log(L_WARN "OSPF: Premature origination of LSA (Type: %04x, Id: %R, Rt: %R)",
-       en->lsa.type, en->lsa.id, en->lsa.rt);
+       en->lsa_type, en->lsa.id, en->lsa.rt);
     return LSA_INITSEQNO;
   }
 
@@ -154,6 +154,11 @@ get_seqnum(struct top_hash_entry *en)
 }
 
 
+/*
+ *     Router-LSA handling
+ *     Type = LSA_T_RT
+ */
+
 static int
 configured_stubnet(struct ospf_area *oa, struct ifa *a)
 {
@@ -201,34 +206,48 @@ bcast_net_active(struct ospf_iface *ifa)
   return 0;
 }
 
+static inline u32
+get_rt_options(struct proto_ospf *po, struct ospf_area *oa, int bitv)
+{
+  u32 opts = 0;
 
-#ifdef OSPFv2
+  if (po->areano > 1)
+    opts |= OPT_RT_B;
+
+  if ((po->areano > 1) && oa_is_nssa(oa) && oa->ac->translator)
+    opts |= OPT_RT_NT;
+
+  if (po->ebit && !oa_is_stub(oa))
+    opts |= OPT_RT_E;
+
+  if (bitv)
+    opts |= OPT_RT_V;
+
+  return opts;
+}
+
+static inline void
+add_rt2_lsa_link(struct proto_ospf *po, u8 type, u32 id, u32 data, u16 metric)
+{
+  struct ospf_lsa_rt2_link *ln = lsab_alloc(po, sizeof(struct ospf_lsa_rt2_link));
+  ln->type = type;
+  ln->id = id;
+  ln->data = data;
+  ln->metric = metric;
+  ln->no_tos = 0;
+}
 
 static void *
-originate_rt_lsa_body(struct ospf_area *oa, u16 *length)
+originate_rt2_lsa_body(struct ospf_area *oa, u16 *length)
 {
   struct proto_ospf *po = oa->po;
   struct ospf_iface *ifa;
   int i = 0, bitv = 0;
-  struct ospf_lsa_rt *rt;
-  struct ospf_lsa_rt_link *ln;
   struct ospf_neighbor *neigh;
 
   ASSERT(po->lsab_used == 0);
-  rt = lsab_allocz(po, sizeof(struct ospf_lsa_rt));
-
-  rt->options = 0;
-
-  if (po->areano > 1)
-    rt->options |= OPT_RT_B;
-
-  if ((po->areano > 1) && oa_is_nssa(oa) && oa->ac->translator)
-    rt->options |= OPT_RT_NT;
-
-  if (po->ebit && !oa_is_stub(oa))
-    rt->options |= OPT_RT_E;
-
-  rt = NULL; /* buffer might be reallocated later */
+  lsab_allocz(po, sizeof(struct ospf_lsa_rt));
+  /* ospf_lsa_rt header will be filled later */
 
   WALK_LIST(ifa, po->iface_list)
   {
@@ -255,13 +274,8 @@ originate_rt_lsa_body(struct ospf_area *oa, u16 *length)
        WALK_LIST(neigh, ifa->neigh_list)
          if (neigh->state == NEIGHBOR_FULL)
          {
-           ln = lsab_alloc(po, sizeof(struct ospf_lsa_rt_link));
-           ln->type = LSART_PTP;
-           ln->id = neigh->rid;
-           ln->data = (ifa->addr->flags & IA_PEER) ?
-             ifa->iface->index : ipa_to_u32(ifa->addr->ip);
-           ln->metric = ifa->cost;
-           ln->padding = 0;
+           u32 data = (ifa->addr->flags & IA_PEER) ? ifa->iface->index : ipa_to_u32(ifa->addr->ip);
+           add_rt2_lsa_link(po, LSART_PTP, neigh->rid, data, ifa->cost);
            i++;
          }
        break;
@@ -270,12 +284,7 @@ originate_rt_lsa_body(struct ospf_area *oa, u16 *length)
       case OSPF_IT_NBMA:
        if (bcast_net_active(ifa))
          {
-           ln = lsab_alloc(po, sizeof(struct ospf_lsa_rt_link));
-           ln->type = LSART_NET;
-           ln->id = ipa_to_u32(ifa->drip);
-           ln->data = ipa_to_u32(ifa->addr->ip);
-           ln->metric = ifa->cost;
-           ln->padding = 0;
+           add_rt2_lsa_link(po, LSART_NET, ipa_to_u32(ifa->drip), ipa_to_u32(ifa->addr->ip), ifa->cost);
            i++;
            net_lsa = 1;
          }
@@ -284,15 +293,7 @@ originate_rt_lsa_body(struct ospf_area *oa, u16 *length)
       case OSPF_IT_VLINK:
        neigh = (struct ospf_neighbor *) HEAD(ifa->neigh_list);
        if ((!EMPTY_LIST(ifa->neigh_list)) && (neigh->state == NEIGHBOR_FULL) && (ifa->cost <= 0xffff))
-       {
-         ln = lsab_alloc(po, sizeof(struct ospf_lsa_rt_link));
-         ln->type = LSART_VLNK;
-         ln->id = neigh->rid;
-         ln->data = ipa_to_u32(ifa->addr->ip);
-         ln->metric = ifa->cost;
-         ln->padding = 0;
-         i++;
-        }
+         add_rt2_lsa_link(po, LSART_VLNK, neigh->rid, ipa_to_u32(ifa->addr->ip), ifa->cost), i++;
         break;
 
       default:
@@ -309,62 +310,36 @@ originate_rt_lsa_body(struct ospf_area *oa, u16 *length)
        configured_stubnet(oa, ifa->addr))
       continue;
 
-    ln = lsab_alloc(po, sizeof(struct ospf_lsa_rt_link));
+      /* Host or network stub entry */
     if ((ifa->addr->flags & IA_HOST) ||
        (ifa->state == OSPF_IS_LOOP) ||
        (ifa->type == OSPF_IT_PTMP))
-    {
-      /* Host stub entry */
-      ln->type = LSART_STUB;
-      ln->id = ipa_to_u32(ifa->addr->ip);
-      ln->data = 0xffffffff;
-      ln->metric = 0;
-      ln->padding = 0;
-    }
+      add_rt2_lsa_link(po, LSART_STUB, ipa_to_u32(ifa->addr->ip), 0xffffffff, 0);
     else 
-    {
-      /* Network stub entry */
-      ln->type = LSART_STUB;
-      ln->id = ipa_to_u32(ifa->addr->prefix);
-      ln->data = ipa_to_u32(ipa_mkmask(ifa->addr->pxlen));
-      ln->metric = ifa->cost;
-      ln->padding = 0;
-    }
+      add_rt2_lsa_link(po, LSART_STUB, ipa_to_u32(ifa->addr->prefix), u32_mkmask(ifa->addr->pxlen), ifa->cost);
     i++;
 
     ifa->rt_pos_end = i;
   }
 
   struct ospf_stubnet_config *sn;
-  if (oa->ac)
+  if (oa->ac) // XXXX ???
     WALK_LIST(sn, oa->ac->stubnet_list)
       if (!sn->hidden)
-      {
-       ln = lsab_alloc(po, sizeof(struct ospf_lsa_rt_link));
-       ln->type = LSART_STUB;
-       ln->id = ipa_to_u32(sn->px.addr);
-       ln->data = ipa_to_u32(ipa_mkmask(sn->px.len));
-       ln->metric = sn->cost;
-       ln->padding = 0;
-       i++;
-      }
-
-  rt = po->lsab;
-  rt->links = i;
+       add_rt2_lsa_link(po, LSART_STUB, ipa_to_u32(sn->px.addr), u32_mkmask(sn->px.len), sn->cost), i++;
 
-  if (bitv) 
-    rt->options |= OPT_RT_V;
+  struct ospf_lsa_rt *rt = po->lsab;
+  /* Store number of links in lower half of options */ 
+  rt->options = get_rt_options(po, oa, bitv) | (u16) i;
 
-  *length = po->lsab_used + sizeof(struct ospf_lsa_header);
+  *length = sizeof(struct ospf_lsa_header) + po->lsab_used;
   return lsab_flush(po);
 }
 
-#else /* OSPFv3 */
-
-static void
-add_lsa_rt_link(struct proto_ospf *po, struct ospf_iface *ifa, u8 type, u32 nif, u32 id)
+static inline void
+add_rt3_lsa_link(struct proto_ospf *po, u8 type, struct ospf_iface *ifa, u32 nif, u32 id)
 {
-  struct ospf_lsa_rt_link *ln = lsab_alloc(po, sizeof(struct ospf_lsa_rt_link));
+  struct ospf_lsa_rt3_link *ln = lsab_alloc(po, sizeof(struct ospf_lsa_rt3_link));
   ln->type = type;
   ln->padding = 0;
   ln->metric = ifa->cost;
@@ -374,30 +349,17 @@ add_lsa_rt_link(struct proto_ospf *po, struct ospf_iface *ifa, u8 type, u32 nif,
 }
 
 static void *
-originate_rt_lsa_body(struct ospf_area *oa, u16 *length)
+originate_rt3_lsa_body(struct ospf_area *oa, u16 *length)
 {
   struct proto_ospf *po = oa->po;
   struct ospf_iface *ifa;
+  struct ospf_neighbor *neigh;
   int bitv = 0;
   int i = 0;
-  struct ospf_lsa_rt *rt;
-  struct ospf_neighbor *neigh;
 
   ASSERT(po->lsab_used == 0);
-  rt = lsab_allocz(po, sizeof(struct ospf_lsa_rt));
-
-  rt->options = oa->options & OPTIONS_MASK;
-
-  if (po->areano > 1)
-    rt->options |= OPT_RT_B;
-
-  if ((po->areano > 1) && oa_is_nssa(oa) && oa->ac->translator)
-    rt->options |= OPT_RT_NT;
-
-  if (po->ebit && !oa_is_stub(oa))
-    rt->options |= OPT_RT_E;
-
-  rt = NULL; /* buffer might be reallocated later */
+  lsab_allocz(po, sizeof(struct ospf_lsa_rt));
+  /* ospf_lsa_rt header will be filled later */
 
   WALK_LIST(ifa, po->iface_list)
   {
@@ -421,19 +383,19 @@ originate_rt_lsa_body(struct ospf_area *oa, u16 *length)
       case OSPF_IT_PTMP:
        WALK_LIST(neigh, ifa->neigh_list)
          if (neigh->state == NEIGHBOR_FULL)
-           add_lsa_rt_link(po, ifa, LSART_PTP, neigh->iface_id, neigh->rid), i++;
+           add_rt3_lsa_link(po, LSART_PTP, ifa, neigh->iface_id, neigh->rid), i++;
        break;
 
       case OSPF_IT_BCAST:
       case OSPF_IT_NBMA:
        if (bcast_net_active(ifa))
-         add_lsa_rt_link(po, ifa, LSART_NET, ifa->dr_iface_id, ifa->drid), i++;
+         add_rt3_lsa_link(po, LSART_NET, ifa, ifa->dr_iface_id, ifa->drid), i++;
        break;
 
       case OSPF_IT_VLINK:
        neigh = (struct ospf_neighbor *) HEAD(ifa->neigh_list);
        if ((!EMPTY_LIST(ifa->neigh_list)) && (neigh->state == NEIGHBOR_FULL) && (ifa->cost <= 0xffff))
-         add_lsa_rt_link(po, ifa, LSART_VLNK, neigh->iface_id, neigh->rid), i++;
+         add_rt3_lsa_link(po, LSART_VLNK, ifa, neigh->iface_id, neigh->rid), i++;
         break;
 
       default:
@@ -444,17 +406,20 @@ originate_rt_lsa_body(struct ospf_area *oa, u16 *length)
     ifa->rt_pos_end = i;
   }
 
-  if (bitv)
-    {
-      rt = po->lsab;
-      rt->options |= OPT_RT_V;
-    }
+  struct ospf_lsa_rt *rt = po->lsab;
+  rt->options = get_rt_options(po, oa, bitv) | (oa->options & OPTIONS_MASK);
 
   *length = po->lsab_used + sizeof(struct ospf_lsa_header);
   return lsab_flush(po);
 }
 
-#endif
+static inline void *
+originate_rt_lsa_body(struct proto_ospf *po, struct ospf_area *oa, u16 *length)
+{
+  return ospf_is_v2(po) ?
+    originate_rt2_lsa_body(oa, length) :
+    originate_rt3_lsa_body(oa, length);
+}
 
 /**
  * originate_rt_lsa - build new instance of router LSA
@@ -468,28 +433,21 @@ originate_rt_lsa_body(struct ospf_area *oa, u16 *length)
 void
 originate_rt_lsa(struct ospf_area *oa)
 {
-  struct ospf_lsa_header lsa;
   struct proto_ospf *po = oa->po;
-  struct proto *p = &po->proto;
+  struct ospf_lsa_header lsa;
+  u32 dom = oa->areaid;
   void *body;
 
   OSPF_TRACE(D_EVENTS, "Originating router-LSA for area %R", oa->areaid);
 
   lsa.age = 0;
-  lsa.type = LSA_T_RT;
-  
-#ifdef OSPFv2
-  lsa.options = oa->options;
-  lsa.id = po->router_id;
-#else /* OSPFv3 */
-  lsa.id = 0;
-#endif
-
+  lsa.type_raw = LSA_T_RT;
+  lsa.id = ospf_is_v2(po) ? po->router_id : 0;
   lsa.rt = po->router_id;
   lsa.sn = get_seqnum(oa->rt);
-  u32 dom = oa->areaid;
+  lsa_fix_options(po, &lsa, oa->options);
 
-  body = originate_rt_lsa_body(oa, &lsa.length);
+  body = originate_rt_lsa_body(po, oa, &lsa.length);
   lsasum_calculate(&lsa, body);
   oa->rt = lsa_install_new(po, &lsa, dom, body);
   ospf_lsupd_flood(po, NULL, NULL, &lsa, dom, 1);
@@ -509,35 +467,58 @@ update_rt_lsa(struct ospf_area *oa)
    */
 
   originate_rt_lsa(oa);
-#ifdef OSPFv3
-  originate_prefix_rt_lsa(oa);
-#endif
+  if (ospf_is_v3(po))
+    originate_prefix_rt_lsa(oa);
 
   schedule_rtcalc(po);
   oa->origrt = 0;
 }
 
+
+/*
+ *     Net-LSA handling
+ *     Type = LSA_T_NET
+ */
+
 static void *
-originate_net_lsa_body(struct ospf_iface *ifa, u16 *length,
-                      struct proto_ospf *po)
+originate_net2_lsa_body(struct proto_ospf *po, struct ospf_iface *ifa, u16 *length)
 {
-  u16 i = 1;
   struct ospf_neighbor *n;
-  struct ospf_lsa_net *net;
   int nodes = ifa->fadj + 1;
+  int bsize = sizeof(struct ospf_lsa_net) + nodes * sizeof(u32);
+  u16 i = 1;
 
-  net = mb_alloc(po->proto.pool, sizeof(struct ospf_lsa_net)
-                + nodes * sizeof(u32));
+  struct ospf_lsa_net *net = mb_alloc(po->proto.pool, bsize);
+  *length = sizeof(struct ospf_lsa_header) + bsize;
 
-#ifdef OSPFv2
-  net->netmask = ipa_mkmask(ifa->addr->pxlen);
-#endif
+  net->optx = u32_mkmask(ifa->addr->pxlen);
+  net->routers[0] = po->router_id;
 
-#ifdef OSPFv3
-  /* In OSPFv3, we would like to merge options from Link LSAs of added neighbors */
+  WALK_LIST(n, ifa->neigh_list)
+  {
+    if (n->state == NEIGHBOR_FULL)
+    {
+      net->routers[i] = n->rid;
+      i++;
+    }
+  }
+  ASSERT(i == nodes);
+
+  return net;
+}
+
+static void *
+originate_net3_lsa_body(struct proto_ospf *po, struct ospf_iface *ifa, u16 *length)
+{
   struct top_hash_entry *en;
+  struct ospf_neighbor *n;
+  int nodes = ifa->fadj + 1;
+  int bsize = sizeof(struct ospf_lsa_net) + nodes * sizeof(u32);
   u32 options = 0;
-#endif
+  u16 i = 1;
+
+  struct ospf_lsa_net *net = mb_alloc(po->proto.pool, bsize);
+  *length = sizeof(struct ospf_lsa_header) + bsize;
 
   net->routers[0] = po->router_id;
 
@@ -545,11 +526,10 @@ originate_net_lsa_body(struct ospf_iface *ifa, u16 *length,
   {
     if (n->state == NEIGHBOR_FULL)
     {
-#ifdef OSPFv3
+      /* In OSPFv3, we would like to merge options from Link LSAs of added neighbors */
       en = ospf_hash_find(po->gr, ifa->iface->index, n->iface_id, n->rid, LSA_T_LINK);
       if (en)
        options |= ((struct ospf_lsa_link *) en->lsa_body)->options;
-#endif
 
       net->routers[i] = n->rid;
       i++;
@@ -557,15 +537,19 @@ originate_net_lsa_body(struct ospf_iface *ifa, u16 *length,
   }
   ASSERT(i == nodes);
 
-#ifdef OSPFv3
-  net->options = options & OPTIONS_MASK;
-#endif
+  net->optx = options & OPTIONS_MASK;
   
-  *length = sizeof(struct ospf_lsa_header) + sizeof(struct ospf_lsa_net)
-    + nodes * sizeof(u32);
   return net;
 }
 
+static inline void *
+originate_net_lsa_body(struct proto_ospf *po, struct ospf_iface *ifa, u16 *length)
+{
+  return ospf_is_v2(po) ?
+    originate_net2_lsa_body(po, ifa, length) :
+    originate_net3_lsa_body(po, ifa, length);
+}
+
 
 /**
  * originate_net_lsa - originates of deletes network LSA
@@ -580,29 +564,21 @@ void
 originate_net_lsa(struct ospf_iface *ifa)
 {
   struct proto_ospf *po = ifa->oa->po;
-  struct proto *p = &po->proto;
   struct ospf_lsa_header lsa;
   u32 dom = ifa->oa->areaid;
-  
   void *body;
 
   OSPF_TRACE(D_EVENTS, "Originating network-LSA for iface %s",
             ifa->iface->name);
 
   lsa.age = 0;
-  lsa.type = LSA_T_NET;
-
-#ifdef OSPFv2
-  lsa.options = ifa->oa->options;
-  lsa.id = ipa_to_u32(ifa->addr->ip);
-#else /* OSPFv3 */
-  lsa.id = ifa->iface->index;
-#endif
-
+  lsa.type_raw = LSA_T_NET;
+  lsa.id = ospf_is_v2(po) ? ipa_to_u32(ifa->addr->ip) : ifa->iface->index;
   lsa.rt = po->router_id;
   lsa.sn = get_seqnum(ifa->net_lsa);
+  lsa_fix_options(po, &lsa, ifa->oa->options);
 
-  body = originate_net_lsa_body(ifa, &lsa.length, po);
+  body = originate_net_lsa_body(po, ifa, &lsa.length);
   lsasum_calculate(&lsa, body);
   ifa->net_lsa = lsa_install_new(po, &lsa, dom, body);
   ospf_lsupd_flood(po, NULL, NULL, &lsa, dom, 1);
@@ -612,7 +588,6 @@ void
 flush_net_lsa(struct ospf_iface *ifa)
 {
   struct proto_ospf *po = ifa->oa->po;
-  struct proto *p = &po->proto;
   u32 dom = ifa->oa->areaid;
 
   if (ifa->net_lsa == NULL)
@@ -620,6 +595,7 @@ flush_net_lsa(struct ospf_iface *ifa)
 
   OSPF_TRACE(D_EVENTS, "Flushing network-LSA for iface %s",
             ifa->iface->name);
+
   ifa->net_lsa->lsa.sn += 1;
   ifa->net_lsa->lsa.age = LSA_MAXAGE;
   lsasum_calculate(&ifa->net_lsa->lsa, ifa->net_lsa->lsa_body);
@@ -643,131 +619,150 @@ update_net_lsa(struct ospf_iface *ifa)
   if ((ifa->state != OSPF_IS_DR) || (ifa->fadj == 0))
     {
       flush_net_lsa(ifa);
-#ifdef OSPFv3
-      flush_prefix_net_lsa(ifa);
-#endif
+      if (ospf_is_v3(po))
+       flush_prefix_net_lsa(ifa);
     }
   else
     {
       originate_net_lsa(ifa);
-#ifdef OSPFv3
-      originate_prefix_net_lsa(ifa);
-#endif
+      if (ospf_is_v3(po))
+       originate_prefix_net_lsa(ifa);
     }
 
   schedule_rtcalc(po);
   ifa->orignet = 0;
 }
 
-#ifdef OSPFv2
+
+/*
+ *     (Net|Rt)-summary-LSA handling
+ *     (a.k.a. Inter-Area-(Prefix|Router)-LSA)
+ *     Type = LSA_T_SUM_NET, LSA_T_SUM_RT
+ */
 
 static inline void *
-originate_sum_lsa_body(struct proto_ospf *po, u16 *length, u32 mlen, u32 metric)
+originate_sum2_lsa_body(struct proto_ospf *po, u16 *length, u32 mlen, u32 metric)
 {
-  struct ospf_lsa_sum *sum = mb_alloc(po->proto.pool, sizeof(struct ospf_lsa_sum));
-  *length = sizeof(struct ospf_lsa_header) + sizeof(struct ospf_lsa_sum);
+  struct ospf_lsa_sum2 *sum = mb_alloc(po->proto.pool, sizeof(struct ospf_lsa_sum2));
+  *length = sizeof(struct ospf_lsa_header) + sizeof(struct ospf_lsa_sum2);
 
-  sum->netmask = ipa_mkmask(mlen);
+  sum->netmask = ip4_mkmask(mlen);
   sum->metric = metric;
 
   return sum;
 }
 
-#define originate_sum_net_lsa_body(po,length,fn,metric) \
-  originate_sum_lsa_body(po, length, (fn)->pxlen, metric)
+static inline void *
+originate_sum3_net_lsa_body(struct proto_ospf *po, u16 *length, struct fib_node *fn, u32 metric)
+{
+  int bsize = sizeof(struct ospf_lsa_sum3_net) + IPV6_PREFIX_SPACE(fn->pxlen);
+  struct ospf_lsa_sum3_net *sum = mb_alloc(po->proto.pool, bsize);
+  *length = sizeof(struct ospf_lsa_header) + bsize;
 
-#define originate_sum_rt_lsa_body(po,length,drid,metric,options) \
-  originate_sum_lsa_body(po, length, 0, metric)
+  sum->metric = metric;
+  put_ipv6_prefix(sum->prefix, fn->prefix, fn->pxlen, 0, 0);
 
-static inline int
-check_sum_net_lsaid_collision(struct fib_node *fn, struct top_hash_entry *en)
-{
-  struct ospf_lsa_sum *sum = en->lsa_body;
-  return fn->pxlen != ipa_mklen(sum->netmask);
+  return sum;
 }
 
-static inline int
-check_sum_lsa_same(struct top_hash_entry *en, u32 metric)
+static inline void *
+originate_sum3_rt_lsa_body(struct proto_ospf *po, u16 *length, u32 drid, u32 metric, u32 options)
 {
-  /* Netmask already checked in check_sum_net_lsaid_collision() */
-  struct ospf_lsa_sum *sum = en->lsa_body;
-  return (en->lsa.sn != LSA_MAXSEQNO) && (sum->metric == metric);
-}
-
-#define check_sum_net_lsa_same(en,metric) \
-  check_sum_lsa_same(en, metric)
-
-#define check_sum_rt_lsa_same(en,drid,metric,options) \
-  check_sum_lsa_same(en, metric)
+  struct ospf_lsa_sum3_rt *sum = mb_alloc(po->proto.pool, sizeof(struct ospf_lsa_sum3_rt));
+  *length = sizeof(struct ospf_lsa_header) + sizeof(struct ospf_lsa_sum3_rt);
 
+  sum->options = options;
+  sum->metric = metric;
+  sum->drid = drid;
 
-#else /* OSPFv3 */
+  return sum;
+}
 
 static inline void *
 originate_sum_net_lsa_body(struct proto_ospf *po, u16 *length, struct fib_node *fn, u32 metric)
 {
-  int size = sizeof(struct ospf_lsa_sum_net) + IPV6_PREFIX_SPACE(fn->pxlen);
-  struct ospf_lsa_sum_net *sum = mb_alloc(po->proto.pool, size);
-  *length = sizeof(struct ospf_lsa_header) + size;
+  return ospf_is_v2(po) ?
+    originate_sum2_lsa_body(po, length, fn->pxlen, metric) :
+    originate_sum3_net_lsa_body(po, length, fn, metric);
+}
 
-  sum->metric = metric;
-  put_ipv6_prefix(sum->prefix, fn->prefix, fn->pxlen, 0, 0);
+static inline void *
+originate_sum_rt_lsa_body(struct proto_ospf *po, u16 *length, u32 drid, u32 metric, u32 options)
+{
+  return ospf_is_v2(po) ?
+    originate_sum2_lsa_body(po, length, 0, metric) :
+    originate_sum3_rt_lsa_body(po, length, drid, metric, options);
+}
 
-  return sum;
+
+static inline int
+check_sum2_net_lsa(struct top_hash_entry *en, struct fib_node *fn, u32 metric)
+{
+  struct ospf_lsa_sum2 *sum = en->lsa_body;
+
+  /* LSAID collision */
+  if (fn->pxlen != ip4_masklen(sum->netmask))
+    return -1;
+
+  return (en->lsa.sn != LSA_MAXSEQNO) && (sum->metric == metric);
 }
 
 static inline int
-check_sum_net_lsaid_collision(struct fib_node *fn, struct top_hash_entry *en)
+check_sum3_net_lsa(struct top_hash_entry *en, struct fib_node *fn, u32 metric)
 {
-  struct ospf_lsa_sum_net *sum = en->lsa_body;
-  ip_addr prefix;
+  struct ospf_lsa_sum3_net *sum = en->lsa_body;
+  ip6_addr prefix;
   int pxlen;
   u8 pxopts;
   u16 rest;
-
   lsa_get_ipv6_prefix(sum->prefix, &prefix, &pxlen, &pxopts, &rest);
-  return (fn->pxlen != pxlen) || !ipa_equal(fn->prefix, prefix);
-}
 
-static inline int
-check_sum_net_lsa_same(struct top_hash_entry *en, u32 metric)
-{
-  /* Prefix already checked in check_sum_net_lsaid_collision() */
-  struct ospf_lsa_sum_net *sum = en->lsa_body;
+  /* LSAID collision */
+  if ((fn->pxlen != pxlen) || !ip6_equal(fn->prefix, prefix))
+    return -1;
+
   return (en->lsa.sn != LSA_MAXSEQNO) && (sum->metric == metric);
 }
 
-static inline void *
-originate_sum_rt_lsa_body(struct proto_ospf *po, u16 *length, u32 drid, u32 metric, u32 options)
+static int
+check_sum_net_lsa(struct proto_ospf *po, struct top_hash_entry *en, struct fib_node *fn, u32 metric)
 {
-  struct ospf_lsa_sum_rt *sum = mb_alloc(po->proto.pool, sizeof(struct ospf_lsa_sum_rt));
-  *length = sizeof(struct ospf_lsa_header) + sizeof(struct ospf_lsa_sum_rt);
+  int rv = ospf_is_v2(po) ?
+    check_sum2_net_lsa(en, fn, metric) :
+    check_sum3_net_lsa(en, fn, metric);
 
-  sum->options = options;
-  sum->metric = metric;
-  sum->drid = drid;
+  if (rv < 0)
+    log(L_ERR "%s: LSAID collision for %I/%d", po->proto.name, fn->prefix, fn->pxlen);
 
-  return sum;
+  return rv;
 }
 
-static inline int
-check_sum_rt_lsa_same(struct top_hash_entry *en, u32 drid, u32 metric, u32 options)
+static int
+check_sum_rt_lsa(struct proto_ospf *po, struct top_hash_entry *en, u32 drid, u32 metric, u32 options)
 {
-  struct ospf_lsa_sum_rt *sum = en->lsa_body;
-  return (en->lsa.sn != LSA_MAXSEQNO) && (sum->options == options) &&
-    (sum->metric == metric) && (sum->drid == drid);
+  if (en->lsa.sn == LSA_MAXSEQNO)
+    return 0;
+
+  if (ospf_is_v2(po))
+  {
+    struct ospf_lsa_sum2 *sum = en->lsa_body;
+    return (sum->metric == metric);
+  }
+  else
+  {
+    struct ospf_lsa_sum3_rt *sum = en->lsa_body;
+    return (sum->options == options) && (sum->metric == metric) && (sum->drid == drid);
+  }
 }
 
-#endif
 
 void
 originate_sum_net_lsa(struct ospf_area *oa, struct fib_node *fn, int metric)
 {
   struct proto_ospf *po = oa->po;
-  struct proto *p = &po->proto;
+  struct ospf_lsa_header lsa;
   struct top_hash_entry *en;
   u32 dom = oa->areaid;
-  struct ospf_lsa_header lsa;
   void *body;
 
   OSPF_TRACE(D_EVENTS, "Originating net-summary-LSA for %I/%d (metric %d)",
@@ -775,25 +770,14 @@ originate_sum_net_lsa(struct ospf_area *oa, struct fib_node *fn, int metric)
 
   /* options argument is used in ORT_NET and OSPFv3 only */
   lsa.age = 0;
-#ifdef OSPFv2
-  lsa.options = oa->options;
-#endif
-  lsa.type = LSA_T_SUM_NET;
+  lsa.type_raw = LSA_T_SUM_NET;
   lsa.id = fibnode_to_lsaid(po, fn);
   lsa.rt = po->router_id;
+  lsa_fix_options(po, &lsa, oa->options);
 
-  if ((en = ospf_hash_find_header(po->gr, dom, &lsa)) != NULL)
-  {
-    if (check_sum_net_lsaid_collision(fn, en))
-    {
-      log(L_ERR "%s: LSAID collision for %I/%d",
-         p->name, fn->prefix, fn->pxlen);
-      return;
-    }
-
-    if (check_sum_net_lsa_same(en, metric))
-      return;
-  }
+  en = ospf_hash_find_header(po->gr, dom, &lsa);
+  if (en && check_sum_net_lsa(po, en, fn, metric))
+    return;
   lsa.sn = get_seqnum(en);
 
   body = originate_sum_net_lsa_body(po, &lsa.length, fn, metric);
@@ -803,37 +787,32 @@ originate_sum_net_lsa(struct ospf_area *oa, struct fib_node *fn, int metric)
 }
 
 void
-originate_sum_rt_lsa(struct ospf_area *oa, struct fib_node *fn, int metric, u32 options UNUSED)
+originate_sum_rt_lsa(struct ospf_area *oa, struct fib_node *fn, int metric, u32 options)
 {
   struct proto_ospf *po = oa->po;
-  struct proto *p = &po->proto;
+  struct ospf_lsa_header lsa;
   struct top_hash_entry *en;
-  u32 dom = oa->areaid;
   u32 rid = ipa_to_rid(fn->prefix);
-  struct ospf_lsa_header lsa;
+  u32 dom = oa->areaid;
   void *body;
 
   OSPF_TRACE(D_EVENTS, "Originating rt-summary-LSA for %R (metric %d)",
             rid, metric);
 
   lsa.age = 0;
-#ifdef OSPFv2
-  lsa.options = oa->options;
-#endif
-  lsa.type = LSA_T_SUM_RT;
-  /* In OSPFv3, LSA ID is meaningless, but we still use Router ID of ASBR */
-  lsa.id = rid;
+  lsa.type_raw = LSA_T_SUM_RT;
+  lsa.id = rid;                /* In OSPFv3, LSA ID is meaningless, but we still use Router ID of ASBR */
   lsa.rt = po->router_id;
+  lsa_fix_options(po, &lsa, oa->options);
 
   options &= OPTIONS_MASK;
-  if ((en = ospf_hash_find_header(po->gr, dom, &lsa)) != NULL)
-  {
-    if (check_sum_rt_lsa_same(en, lsa.id, metric, options))
-      return;
-  }
+
+  en = ospf_hash_find_header(po->gr, dom, &lsa);
+  if (en && check_sum_rt_lsa(po, en, rid, metric, options))
+    return;
   lsa.sn = get_seqnum(en);
 
-  body = originate_sum_rt_lsa_body(po, &lsa.length, lsa.id, metric, options);
+  body = originate_sum_rt_lsa_body(po, &lsa.length, rid, metric, options);
   lsasum_calculate(&lsa, body);
   lsa_install_new(po, &lsa, dom, body);
   ospf_lsupd_flood(po, NULL, NULL, &lsa, dom, 1);
@@ -843,101 +822,73 @@ void
 flush_sum_lsa(struct ospf_area *oa, struct fib_node *fn, int type)
 {
   struct proto_ospf *po = oa->po;
-  struct proto *p = &po->proto;
-  struct top_hash_entry *en;
   struct ospf_lsa_header lsa;
+  struct top_hash_entry *en;
+  u32 dom = oa->areaid;
 
   lsa.rt = po->router_id;
   if (type == ORT_NET)
     {
       lsa.id = fibnode_to_lsaid(po, fn);
-      lsa.type = LSA_T_SUM_NET;
+      lsa.type_raw = LSA_T_SUM_NET;
     }
   else
     {
       /* In OSPFv3, LSA ID is meaningless, but we still use Router ID of ASBR */
       lsa.id = ipa_to_rid(fn->prefix);
-      lsa.type = LSA_T_SUM_RT;
+      lsa.type_raw = LSA_T_SUM_RT;
     }
 
-  if ((en = ospf_hash_find_header(po->gr, oa->areaid, &lsa)) != NULL)
+  en = ospf_hash_find_header(po->gr, dom, &lsa);
+  if (en)
     {
-      if ((type == ORT_NET) && check_sum_net_lsaid_collision(fn, en))
-       {
-         log(L_ERR "%s: LSAID collision for %I/%d",
-             p->name, fn->prefix, fn->pxlen);
-         return;
-       }
+      OSPF_TRACE(D_EVENTS, "Flushing summary-LSA (id=%R, type=%d)",
+                en->lsa.id, en->lsa.type_raw);
+
+      if ((type == ORT_NET) && (check_sum_net_lsa(po, en, fn, 0) < 0))
+       return;
 
       struct ospf_lsa_sum *sum = en->lsa_body;
       en->lsa.age = LSA_MAXAGE;
       en->lsa.sn = LSA_MAXSEQNO;
       lsasum_calculate(&en->lsa, sum);
-
-      OSPF_TRACE(D_EVENTS, "Flushing summary-LSA (id=%R, type=%d)",
-                en->lsa.id, en->lsa.type);
-      ospf_lsupd_flood(po, NULL, NULL, &en->lsa, oa->areaid, 1);
+      ospf_lsupd_flood(po, NULL, NULL, &en->lsa, dom, 1);
       if (can_flush_lsa(po)) flush_lsa(en, po);
     }
 }
 
-#ifdef OSPFv2
+
+/*
+ *     AS-external-LSA and NSSA-LSA handling
+ *     Type = LSA_T_EXT, LSA_T_NSSA
+ */
 
 static inline void *
-originate_ext_lsa_body(struct proto_ospf *po, u16 *length, struct fib_node *fn,
-                      u32 metric, ip_addr fwaddr, u32 tag, int pbit UNUSED)
+originate_ext2_lsa_body(struct proto_ospf *po, u16 *length, struct fib_node *fn,
+                       u32 metric, ip_addr fwaddr, u32 tag)
 {
-  struct ospf_lsa_ext *ext = mb_alloc(po->proto.pool, sizeof(struct ospf_lsa_ext));
-  *length = sizeof(struct ospf_lsa_header) + sizeof(struct ospf_lsa_ext);
+  struct ospf_lsa_ext2 *ext = mb_alloc(po->proto.pool, sizeof(struct ospf_lsa_ext2));
+  *length = sizeof(struct ospf_lsa_header) + sizeof(struct ospf_lsa_ext2);
 
   ext->metric = metric; 
-  ext->netmask = ipa_mkmask(fn->pxlen);
-  ext->fwaddr = fwaddr;
+  ext->netmask = ip4_mkmask(fn->pxlen);
+  ext->fwaddr = ipa_to_ip4(fwaddr);
   ext->tag = tag;
 
   return ext;
 }
 
-/*
- * check_ext_lsa() combines functions of check_*_lsaid_collision() and
- * check_*_lsa_same(). 'en' is existing ext LSA, and rest parameters
- * are parameters of new ext route.  Function returns -1 if there is
- * LSAID collision, returns 1 if the existing LSA is the same and
- * returns 0 otherwise (in that case, we need to originate a new LSA).
- *
- * Really, checking for the same parameters is not as important as in
- * summary LSA origination, because in most cases the duplicate
- * external route propagation would be stopped by the nest. But there
- * are still some cases (route reload, the same route propagated through
- * different protocol) so it is also done here.
- */
-
-static inline int
-check_ext_lsa(struct top_hash_entry *en, struct fib_node *fn, u32 metric, ip_addr fwaddr, u32 tag)
-{
-  struct ospf_lsa_ext *ext = en->lsa_body;
-
-  /* LSAID collision */
-  if  (fn->pxlen != ipa_mklen(ext->netmask))
-    return -1;
-
-  return (en->lsa.sn != LSA_MAXSEQNO) && (ext->metric == metric) &&
-    (ext->tag == tag) && ipa_equal(ext->fwaddr,fwaddr);
-}
-
-#else /* OSPFv3 */
-
 static inline void *
-originate_ext_lsa_body(struct proto_ospf *po, u16 *length, struct fib_node *fn,
-                      u32 metric, ip_addr fwaddr, u32 tag, int pbit)
+originate_ext3_lsa_body(struct proto_ospf *po, u16 *length, struct fib_node *fn,
+                       u32 metric, ip_addr fwaddr, u32 tag, int pbit)
 {
-  int size = sizeof(struct ospf_lsa_ext)
+  int bsize = sizeof(struct ospf_lsa_ext3)
     + IPV6_PREFIX_SPACE(fn->pxlen)
     + (ipa_nonzero(fwaddr) ? 16 : 0)
     + (tag ? 4 : 0);
 
-  struct ospf_lsa_ext *ext = mb_alloc(po->proto.pool, size);
-  *length = sizeof(struct ospf_lsa_header) + size;
+  struct ospf_lsa_ext3 *ext = mb_alloc(po->proto.pool, bsize);
+  *length = sizeof(struct ospf_lsa_header) + bsize;
 
   ext->metric = metric;
 
@@ -946,23 +897,60 @@ originate_ext_lsa_body(struct proto_ospf *po, u16 *length, struct fib_node *fn,
 
   if (ipa_nonzero(fwaddr))
   {
-    ext->metric |= LSA_EXT_FBIT;
+    ext->metric |= LSA_EXT3_FBIT;
     buf = put_ipv6_addr(buf, fwaddr);
   }
 
   if (tag)
   {
-    ext->metric |= LSA_EXT_TBIT;
+    ext->metric |= LSA_EXT3_TBIT;
     *buf++ = tag;
   }
 
   return ext;
 }
 
+static inline void *
+originate_ext_lsa_body(struct proto_ospf *po, u16 *length, struct fib_node *fn,
+                      u32 metric, ip_addr fwaddr, u32 tag, int pbit)
+{
+  return ospf_is_v2(po) ?
+    originate_ext2_lsa_body(po, length, fn, metric, fwaddr, tag) :
+    originate_ext3_lsa_body(po, length, fn, metric, fwaddr, tag, pbit);
+}
+
+
+/*
+ * check_ext_lsa() combines functions of check_*_lsaid_collision() and
+ * check_*_lsa_same(). 'en' is existing ext LSA, and rest parameters
+ * are parameters of new ext route.  Function returns -1 if there is
+ * LSAID collision, returns 1 if the existing LSA is the same and
+ * returns 0 otherwise (in that case, we need to originate a new LSA).
+ *
+ * Really, checking for the same parameters is not as important as in
+ * summary LSA origination, because in most cases the duplicate
+ * external route propagation would be stopped by the nest. But there
+ * are still some cases (route reload, the same route propagated through
+ * different protocol) so it is also done here.
+ */
+
+static inline int
+check_ext2_lsa(struct top_hash_entry *en, struct fib_node *fn, u32 metric, ip_addr fwaddr, u32 tag)
+{
+  struct ospf_lsa_ext2 *ext = en->lsa_body;
+
+  /* LSAID collision */
+  if  (fn->pxlen != ip4_masklen(ext->netmask))
+    return -1;
+
+  return (en->lsa.sn != LSA_MAXSEQNO) && (ext->metric == metric) &&
+    (ext->tag == tag) && ip4_equal(ext->fwaddr, ipa_to_ip4(fwaddr));
+}
+
 static inline int
-check_ext_lsa(struct top_hash_entry *en, struct fib_node *fn, u32 metric, ip_addr fwaddr, u32 tag)
+check_ext3_lsa(struct top_hash_entry *en, struct fib_node *fn, u32 metric, ip_addr fwaddr, u32 tag)
 {
-  struct ospf_lsa_ext *ext = en->lsa_body;
+  struct ospf_lsa_ext3 *ext = en->lsa_body;
   ip_addr prefix;
   int pxlen;
   u8 pxopts;
@@ -981,17 +969,29 @@ check_ext_lsa(struct top_hash_entry *en, struct fib_node *fn, u32 metric, ip_add
   ip_addr rt_fwaddr = IPA_NONE;
   u32 rt_tag = 0;
 
-  if (ext->metric & LSA_EXT_FBIT)
+  if (ext->metric & LSA_EXT3_FBIT)
     buf = lsa_get_ipv6_addr(buf, &rt_fwaddr);
 
-  if (ext->metric & LSA_EXT_TBIT)
+  if (ext->metric & LSA_EXT3_TBIT)
     rt_tag = *buf++;
 
   return (rt_metric == metric) && ipa_equal(rt_fwaddr, fwaddr) && (rt_tag == tag);
 }
 
+static int
+check_ext_lsa(struct proto_ospf *po, struct top_hash_entry *en, struct fib_node *fn,
+             u32 metric, ip_addr fwaddr, u32 tag)
+{
+  int rv = ospf_is_v2(po) ?
+    check_ext2_lsa(en, fn, metric, fwaddr, tag) :
+    check_ext3_lsa(en, fn, metric, fwaddr, tag);
+
+  if (rv < 0)
+    log(L_ERR "%s: LSAID collision for %I/%d", po->proto.name, fn->prefix, fn->pxlen);
+
+  return rv;
+}
 
-#endif
 
 static inline ip_addr
 find_surrogate_fwaddr(struct ospf_area *oa)
@@ -1046,7 +1046,7 @@ find_surrogate_fwaddr(struct ospf_area *oa)
  * @oa: ospf_area for which LSA is originated
  * @fn: network prefix and mask
  * @src: the source of origination of the LSA (EXT_EXPORT/EXT_NSSA)
- * @metric: the metric of a route
+ * @metric: the metric of a route (possibly with appropriate E-bit)
  * @fwaddr: the forwarding address
  * @tag: the route tag
  * @pbit: P-bit for NSSA LSAs, ignored for external LSAs
@@ -1067,21 +1067,19 @@ originate_ext_lsa(struct ospf_area *oa, struct fib_node *fn, int src,
   struct proto_ospf *po = oa->po;
   struct proto *p = &po->proto;
   struct ospf_lsa_header lsa;
-  struct top_hash_entry *en = NULL;
-  void *body;
+  struct top_hash_entry *en;
   int nssa = oa_is_nssa(oa);
   u32 dom = nssa ? oa->areaid : 0;
+  void *body;
 
   OSPF_TRACE(D_EVENTS, "Originating %s-LSA for %I/%d",
             nssa ? "NSSA" : "AS-external", fn->prefix, fn->pxlen);
 
   lsa.age = 0;
-#ifdef OSPFv2
-  lsa.options = nssa ? (pbit ? OPT_P : 0) : OPT_E;
-#endif
-  lsa.type = nssa ? LSA_T_NSSA : LSA_T_EXT;
+  lsa.type_raw = nssa ? LSA_T_NSSA : LSA_T_EXT;
   lsa.id = fibnode_to_lsaid(po, fn);
   lsa.rt = po->router_id;
+  lsa_fix_options(po, &lsa, nssa ? (pbit ? OPT_P : 0) : OPT_E);
 
   if (nssa && pbit && ipa_zero(fwaddr))
   {
@@ -1096,19 +1094,9 @@ originate_ext_lsa(struct ospf_area *oa, struct fib_node *fn, int src,
     }
   }
 
-  if ((en = ospf_hash_find_header(po->gr, dom, &lsa)) != NULL)
-  {
-    int rv = check_ext_lsa(en, fn, metric, fwaddr, tag);
-    if (rv < 0)
-    {
-      log(L_ERR "%s: LSAID collision for %I/%d",
-         p->name, fn->prefix, fn->pxlen);
-      return;
-    }
-
-    if (rv > 0)
-      return;
-  }
+  en = ospf_hash_find_header(po->gr, dom, &lsa);
+  if (en && check_ext_lsa(po, en, fn, metric, fwaddr, tag))
+    return;
   lsa.sn = get_seqnum(en);
 
   body = originate_ext_lsa_body(po, &lsa.length, fn, metric, fwaddr, tag, pbit);
@@ -1140,17 +1128,17 @@ flush_ext_lsa(struct ospf_area *oa, struct fib_node *fn, int src)
   struct proto *p = &po->proto;
   struct top_hash_entry *en;
   int nssa = oa_is_nssa(oa);
-
-  OSPF_TRACE(D_EVENTS, "Flushing %s-LSA for %I/%d",
-            nssa ? "NSSA" : "AS-external", fn->prefix, fn->pxlen);
-
   u32 dom = nssa ? oa->areaid : 0;
   u32 type = nssa ? LSA_T_NSSA : LSA_T_EXT;
   u32 lsaid = fibnode_to_lsaid(po, fn);
 
-  if (en = ospf_hash_find(po->gr, dom, lsaid, po->router_id, type))
+  en = ospf_hash_find(po->gr, dom, lsaid, po->router_id, type);
+  if (en)
     {
-      if (check_ext_lsa(en, fn, 0, IPA_NONE, 0) < 0)
+      OSPF_TRACE(D_EVENTS, "Flushing %s-LSA for %I/%d",
+                nssa ? "NSSA" : "AS-external", fn->prefix, fn->pxlen);
+
+      if (check_ext_lsa(po, en, fn, 0, IPA_NONE, 0) < 0)
        {
          log(L_ERR "%s: LSAID collision for %I/%d",
              p->name, fn->prefix, fn->pxlen);
@@ -1158,14 +1146,17 @@ flush_ext_lsa(struct ospf_area *oa, struct fib_node *fn, int src)
        }
 
       /* Clean up source bits */
-      if (src)
+      if (src) // XXXX ???
        fn->flags &= ~OSPF_RT_SRC;
       ospf_lsupd_flush_nlsa(po, en);
     }
 }
 
 
-#ifdef OSPFv3
+/*
+ *     Link-LSA handling (assume OSPFv3)
+ *     Type = LSA_T_LINK
+ */
 
 static void *
 originate_link_lsa_body(struct ospf_iface *ifa, u16 *length)
@@ -1203,20 +1194,19 @@ originate_link_lsa_body(struct ospf_iface *ifa, u16 *length)
 void
 originate_link_lsa(struct ospf_iface *ifa)
 {
-  struct ospf_lsa_header lsa;
   struct proto_ospf *po = ifa->oa->po;
-  struct proto *p = &po->proto;
+  struct ospf_lsa_header lsa;
+  u32 dom = ifa->iface->index;
   void *body;
 
   /* FIXME check for vlink and skip that? */
   OSPF_TRACE(D_EVENTS, "Originating link-LSA for iface %s", ifa->iface->name);
 
   lsa.age = 0;
-  lsa.type = LSA_T_LINK;
+  lsa.type_raw = LSA_T_LINK;
   lsa.id = ifa->iface->index;
   lsa.rt = po->router_id;
   lsa.sn = get_seqnum(ifa->link_lsa);
-  u32 dom = ifa->iface->index;
 
   body = originate_link_lsa_body(ifa, &lsa.length);
   lsasum_calculate(&lsa, body);
@@ -1241,6 +1231,12 @@ update_link_lsa(struct ospf_iface *ifa)
   ifa->origlink = 0;
 }
 
+
+/*
+ *     Prefix-Rt-LSA handling (assume OSPFv3)
+ *     Type = LSA_T_PREFIX, referred type = LSA_T_RT
+ */
+
 static inline void
 lsa_put_prefix(struct proto_ospf *po, ip_addr prefix, u32 pxlen, u32 cost)
 {
@@ -1337,18 +1333,17 @@ void
 originate_prefix_rt_lsa(struct ospf_area *oa)
 {
   struct proto_ospf *po = oa->po;
-  struct proto *p = &po->proto;  
   struct ospf_lsa_header lsa;
+  u32 dom = oa->areaid;
   void *body;
 
   OSPF_TRACE(D_EVENTS, "Originating router prefix-LSA for area %R", oa->areaid);
 
   lsa.age = 0;
-  lsa.type = LSA_T_PREFIX;
+  lsa.type_raw = LSA_T_PREFIX;
   lsa.id = 0;
   lsa.rt = po->router_id;
   lsa.sn = get_seqnum(oa->pxr_lsa);
-  u32 dom = oa->areaid;
 
   body = originate_prefix_rt_lsa_body(oa, &lsa.length);
   lsasum_calculate(&lsa, body);
@@ -1357,6 +1352,11 @@ originate_prefix_rt_lsa(struct ospf_area *oa)
 }
 
 
+/*
+ *     Prefix-Net-LSA handling (assume OSPFv3)
+ *     Type = LSA_T_PREFIX, referred type = LSA_T_NET
+ */
+
 static inline int
 prefix_space(u32 *buf)
 {
@@ -1429,7 +1429,6 @@ add_link_lsa(struct proto_ospf *po, struct top_hash_entry *en, int offset, int *
 }
 
 
-
 static void *
 originate_prefix_net_lsa_body(struct ospf_iface *ifa, u16 *length)
 {
@@ -1468,19 +1467,18 @@ void
 originate_prefix_net_lsa(struct ospf_iface *ifa)
 {
   struct proto_ospf *po = ifa->oa->po;
-  struct proto *p = &po->proto;
   struct ospf_lsa_header lsa;
+  u32 dom = ifa->oa->areaid;
   void *body;
 
   OSPF_TRACE(D_EVENTS, "Originating network prefix-LSA for iface %s",
             ifa->iface->name);
 
   lsa.age = 0;
-  lsa.type = LSA_T_PREFIX;
+  lsa.type_raw = LSA_T_PREFIX;
   lsa.id = ifa->iface->index;
   lsa.rt = po->router_id;
   lsa.sn = get_seqnum(ifa->pxn_lsa);
-  u32 dom = ifa->oa->areaid;
 
   body = originate_prefix_net_lsa_body(ifa, &lsa.length);
   lsasum_calculate(&lsa, body);
@@ -1492,7 +1490,6 @@ void
 flush_prefix_net_lsa(struct ospf_iface *ifa)
 {
   struct proto_ospf *po = ifa->oa->po;
-  struct proto *p = &po->proto;
   struct top_hash_entry *en = ifa->pxn_lsa;
   u32 dom = ifa->oa->areaid;
 
@@ -1511,9 +1508,6 @@ flush_prefix_net_lsa(struct ospf_iface *ifa)
 }
 
 
-#endif
-
-
 static void
 ospf_top_ht_alloc(struct top_graph *f)
 {
@@ -1549,7 +1543,7 @@ ospf_top_hash_u32(u32 a)
   return a;
 }
 
-static inline unsigned
+static unsigned
 ospf_top_hash(struct top_graph *f, u32 domain, u32 lsaid, u32 rtrid, u32 type)
 {
   /* In OSPFv2, we don't know Router ID when looking for network LSAs.
@@ -1557,14 +1551,8 @@ ospf_top_hash(struct top_graph *f, u32 domain, u32 lsaid, u32 rtrid, u32 type)
      In both cases, there is (usually) just one (or small number)
      appropriate LSA, so we just clear unknown part of key. */
 
-  return (
-#ifdef OSPFv2
-         ((type == LSA_T_NET) ? 0 : ospf_top_hash_u32(rtrid)) +
-         ospf_top_hash_u32(lsaid) + 
-#else /* OSPFv3 */
-         ospf_top_hash_u32(rtrid) +
-         ((type == LSA_T_RT) ? 0 : ospf_top_hash_u32(lsaid)) +
-#endif
+  return (((f->ospf2 && (type == LSA_T_NET)) ? 0 : ospf_top_hash_u32(rtrid)) +
+         ((!f->ospf2 && (type == LSA_T_RT)) ? 0 : ospf_top_hash_u32(lsaid)) +
          type + domain) & f->hash_mask;
 
   /*
@@ -1691,12 +1679,12 @@ ospf_hash_find(struct top_graph *f, u32 domain, u32 lsa, u32 rtr, u32 type)
 /* In OSPFv2, sometimes we don't know Router ID when looking for network LSAs.
    There should be just one, so we find any match. */
 struct top_hash_entry *
-ospf_hash_find_net(struct top_graph *f, u32 domain, u32 lsa)
+ospf_hash_find_net(struct top_graph *f, u32 domain, u32 id, u32 nif)
 {
   struct top_hash_entry *e;
-  e = f->hash_table[ospf_top_hash(f, domain, lsa, 0, LSA_T_NET)];
+  e = f->hash_table[ospf_top_hash(f, domain, id, 0, LSA_T_NET)];
 
-  while (e && (e->lsa.id != lsa || e->lsa.type != LSA_T_NET || e->domain != domain))
+  while (e && (e->lsa.id != id || e->lsa.type != LSA_T_NET || e->domain != domain))
     e = e->next;
 
   return e;
index 1e9544445fae3457bef99cabef88cdaf5b20a62f..909f9d30294d4cebad3b20dd86775c3411bc4b1e 100644 (file)
@@ -16,6 +16,7 @@ struct top_hash_entry
                                   in intra-area routing table calculation */
   struct top_hash_entry *next; /* Next in hash chain */
   struct ospf_lsa_header lsa;
+  u16 lsa_type;                        /* lsa.type processed and converted to common values */ 
   u32 domain;                  /* Area ID for area-wide LSAs, Iface ID for link-wide LSAs */
   //  struct ospf_area *oa;
   void *lsa_body;
@@ -76,7 +77,7 @@ void flush_ext_lsa(struct ospf_area *oa, struct fib_node *fn, int src);
 
 
 #ifdef OSPFv2
-struct top_hash_entry * ospf_hash_find_net(struct top_graph *f, u32 domain, u32 lsa);
+struct top_hash_entry * ospf_hash_find_net(struct top_graph *f, u32 domain, u32 id, u32 nif);
 
 static inline struct top_hash_entry *
 ospf_hash_find_rt(struct top_graph *f, u32 domain, u32 rtr)
@@ -85,6 +86,13 @@ ospf_hash_find_rt(struct top_graph *f, u32 domain, u32 rtr)
 }
 
 #else /* OSPFv3 */
+static inline struct top_hash_entry *
+ospf_hash_find_net(struct top_graph *f, u32 domain, u32 id, u32 nif)
+{
+  return ospf_hash_find(f, domain, nif, id, LSA_T_NET);
+}
+
+
 struct top_hash_entry * ospf_hash_find_rt(struct top_graph *f, u32 domain, u32 rtr);
 struct top_hash_entry * ospf_hash_find_rt_first(struct top_graph *f, u32 domain, u32 rtr);
 struct top_hash_entry * ospf_hash_find_rt_next(struct top_hash_entry *e);
index a87b96891a7d85a467558bce0094ad742aae6eb8..6c5511e6479b3ab8dbb67368c4c6d71eca55b53d 100644 (file)
@@ -160,7 +160,7 @@ radv_send_ra(struct radv_iface *ifa, int shutdown)
   }
 
   RADV_TRACE(D_PACKETS, "Sending RA via %s", ifa->iface->name);
-  sk_send_to(ifa->sk, ifa->plen, AllNodes, 0);
+  sk_send_to(ifa->sk, ifa->plen, IP6_ALL_NODES, 0);
 }
 
 
@@ -251,7 +251,7 @@ radv_sk_open(struct radv_iface *ifa)
   if (sk_setup_multicast(sk) < 0)
     goto err;
 
-  if (sk_join_group(sk, AllRouters) < 0)
+  if (sk_join_group(sk, IP6_ALL_ROUTERS) < 0)
     goto err;
 
   ifa->sk = sk;
index 3f88eac886bd17469e6b3214efa2bfb8cb1a91cb..bffdbda97460434e5a0960de3d9ea84a4793c17a 100644 (file)
@@ -26,9 +26,6 @@
 
 #define ICMPV6_PROTO 58
 
-#define AllNodes   ipa_build6(0xFF020000, 0, 0, 1)     /* FF02::1 */
-#define AllRouters ipa_build6(0xFF020000, 0, 0, 2)     /* FF02::2 */
-
 #define ICMPV6_RS 133
 #define ICMPV6_RA 134