]> git.ipfire.org Git - thirdparty/bird.git/commitdiff
Temporary OSPFv3 development commit
authorOndrej Zajicek <santiago@crfreenet.org>
Fri, 21 Aug 2009 07:27:52 +0000 (09:27 +0200)
committerOndrej Zajicek <santiago@crfreenet.org>
Fri, 21 Aug 2009 07:27:52 +0000 (09:27 +0200)
24 files changed:
configure.in
nest/rt-attr.c
proto/ospf/config.Y
proto/ospf/dbdes.c
proto/ospf/dbdes.h
proto/ospf/hello.c
proto/ospf/hello.h
proto/ospf/iface.c
proto/ospf/lsack.c
proto/ospf/lsack.h
proto/ospf/lsalib.c
proto/ospf/lsalib.h
proto/ospf/lsreq.c
proto/ospf/lsreq.h
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/rt.h
proto/ospf/topology.c
proto/ospf/topology.h

index 8d519fddf40b3bd2519e837f9a06f59fa5cfdc13..89cf970166409c1d1ff4ab76bd57f50d8f3f17a2 100644 (file)
@@ -43,15 +43,13 @@ AC_SUBST(srcdir_rel_mf)
 if test "$enable_ipv6" = yes ; then
        ip=ipv6
        SUFFIX6=6
-       if test "$with_protocols" = all ; then
-               with_protocols=bgp,pipe,rip,static
-       fi
 else
        ip=ipv4
        SUFFIX6=""
-       if test "$with_protocols" = all ; then
-               with_protocols=bgp,ospf,pipe,rip,static
-       fi
+fi
+
+if test "$with_protocols" = all ; then
+       with_protocols=bgp,ospf,pipe,rip,static
 fi
 
 AC_SEARCH_LIBS(clock_gettime,[c rt posix4])
index de63198ee57982b95d9a284a4178a217e3c45f2a..8daebae013062c47134576d1c624028d83206ac0 100644 (file)
@@ -71,6 +71,7 @@ ea__find(ea_list *e, unsigned id)
 
   while (e)
     {
+    /*
       if (e->flags & EALF_BISECT)
        {
          l = 0;
@@ -88,6 +89,7 @@ ea__find(ea_list *e, unsigned id)
            }
        }
       else
+      */
        for(m=0; m<e->count; m++)
          if (e->attrs[m].id == id)
            return &e->attrs[m];
index 77ca26cfdd627e3fca83a04b0bada4e81f532284..6acc7d246789c205be0ef87a42f69fc78f89dcf5 100644 (file)
@@ -20,6 +20,7 @@ static struct nbma_node *this_nbma;
 static struct area_net_config *this_pref;
 static struct ospf_stubnet_config *this_stubnet; 
 
+#ifdef OSPFv2
 static void
 finish_iface_config(struct ospf_iface_patt *ip)
 {
@@ -31,6 +32,16 @@ finish_iface_config(struct ospf_iface_patt *ip)
   if ((ip->autype == OSPF_AUTH_NONE) && (ip->passwords != NULL))
     log(L_WARN "Password option without authentication option does not make sense");
 }
+#endif
+
+#ifdef OSPFv3
+static void
+finish_iface_config(struct ospf_iface_patt *ip)
+{
+  if ((ip->autype != OSPF_AUTH_NONE) || (get_passwords() != NULL))
+    log(L_WARN "Authentication not supported in OSPFv3");
+}
+#endif
 
 CF_DECLS
 
index adc0276fec623d6ab730e159c9c42bf20076f32f..31075791b16de2d566fec5898795ebc8008d00eb 100644 (file)
@@ -8,6 +8,37 @@
 
 #include "ospf.h"
 
+
+#ifdef OSPFv2
+struct ospf_dbdes_packet
+{
+  struct ospf_packet ospf_packet;
+  u16 iface_mtu;
+  u8 options;
+  union imms imms;             /* I, M, MS bits */
+  u32 ddseq;
+};
+
+#define hton_opt(X) X
+#define ntoh_opt(X) X
+#endif
+
+
+#ifdef OSPFv3
+struct ospf_dbdes_packet
+{
+  struct ospf_packet ospf_packet;
+  u32 options;
+  u16 iface_mtu;
+  u8 padding;
+  union imms imms;             /* I, M, MS bits */
+  u32 ddseq;
+};
+
+#define hton_opt(X) htonl(X)
+#define ntoh_opt(X) ntohl(X)
+#endif
+
   
 static void ospf_dump_dbdes(struct proto *p, struct ospf_dbdes_packet *pkt)
 {
@@ -37,7 +68,7 @@ static void ospf_dump_dbdes(struct proto *p, struct ospf_dbdes_packet *pkt)
  * @n: neighbor
  * @next: whether to send a next packet in a sequence (1) or to retransmit the old one (0)
  *
- * Sending of a database description packet is described in 10.6 of RFC 2328.
+ * Sending of a database description packet is described in 10.8 of RFC 2328.
  * Reception of each packet is acknowledged in the sequence number of another.
  * When I send a packet to a neighbor I keep a copy in a buffer. If the neighbor
  * does not reply, I don't create a new packet but just send the content
@@ -65,7 +96,7 @@ ospf_dbdes_send(struct ospf_neighbor *n, int next)
     op = (struct ospf_packet *) pkt;
     ospf_pkt_fill_hdr(ifa, pkt, DBDES_P);
     pkt->iface_mtu = htons(ifa->iface->mtu);
-    pkt->options = oa->opt.byte;
+    pkt->options = hton_opt(oa->options);
     pkt->imms = n->myimms;
     pkt->ddseq = htonl(n->dds);
     length = sizeof(struct ospf_dbdes_packet);
@@ -88,8 +119,8 @@ ospf_dbdes_send(struct ospf_neighbor *n, int next)
 
       ospf_pkt_fill_hdr(ifa, pkt, DBDES_P);
       pkt->iface_mtu = htons(ifa->iface->mtu);
-      pkt->options = oa->opt.byte;
       pkt->ddseq = htonl(n->dds);
+      pkt->options = hton_opt(oa->options);
 
       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));
@@ -102,16 +133,8 @@ ospf_dbdes_send(struct ospf_neighbor *n, int next)
        for (; i > 0; i--)
        {
          struct top_hash_entry *en= (struct top_hash_entry *) sn;
-          int send = 1;
 
-          /* Don't send ext LSA into stub areas */
-          if (oa->stub && (en->lsa.type == LSA_T_EXT)) send = 0;
-          /* Don't send ext LSAs through VLINK  */
-          if ((ifa->type == OSPF_IT_VLINK) && (en->lsa.type == LSA_T_EXT)) send = 0;;
-          /* Don't send LSA of other areas */
-          if ((en->lsa.type != LSA_T_EXT) && (en->oa != oa)) send = 0;
-
-          if (send)
+          if (ospf_lsa_flooding_allowed(&en->lsa, en->domain, ifa))
           {
            htonlsah(&(en->lsa), lsa);
            DBG("Working on: %d\n", i);
@@ -204,13 +227,13 @@ ospf_dbdes_reqladd(struct ospf_dbdes_packet *ps, struct ospf_neighbor *n)
   for (i = 0; i < j; i++)
   {
     ntohlsah(plsa + i, &lsa);
-    if (((he = ospf_hash_find(gr, oa->areaid, lsa.id, lsa.rt, lsa.type)) == NULL) ||
+    if (((he = ospfxx_hash_find_smart(gr, n->ifa, &lsa)) == NULL) ||
        (lsa_comp(&lsa, &(he->lsa)) == 1))
     {
       /* Is this condition necessary? */
-      if (ospf_hash_find(n->lsrqh, oa->areaid, lsa.id, lsa.rt, lsa.type) == NULL)
+      if (ospfxx_hash_find_smart(n->lsrqh, n->ifa, &lsa) == NULL)
       {
-       sn = ospf_hash_get(n->lsrqh, oa, lsa.id, lsa.rt, lsa.type);
+       sn = ospfxx_hash_get_smart(n->lsrqh, n->ifa, &lsa);
        ntohlsah(plsa + i, &(sn->lsa));
        s_add_tail(&(n->lsrql), SNODE sn);
       }
@@ -219,13 +242,17 @@ ospf_dbdes_reqladd(struct ospf_dbdes_packet *ps, struct ospf_neighbor *n)
 }
 
 void
-ospf_dbdes_receive(struct ospf_dbdes_packet *ps,
-                  struct ospf_iface *ifa, struct ospf_neighbor *n)
+ospf_dbdes_receive(struct ospf_packet *ps_i, struct ospf_iface *ifa,
+                  struct ospf_neighbor *n)
 {
+  struct ospf_dbdes_packet *ps = (void *) ps_i;
   struct proto *p = &ifa->oa->po->proto;
   u32 myrid = p->cf->global->router_id;
   unsigned int size = ntohs(ps->ospf_packet.length);
 
+  u32 ps_ddseq = ntohl(ps->ddseq);
+  u32 ps_options = ntoh_opt(ps->options);
+  
   OSPF_PACKET(ospf_dump_dbdes, ps, "DBDES packet received from %I via %s", n->ip, ifa->iface->name);
 
   ospf_neigh_sm(n, INM_HELLOREC);
@@ -246,9 +273,9 @@ ospf_dbdes_receive(struct ospf_dbdes_packet *ps,
        && (n->rid > myrid) && (size == sizeof(struct ospf_dbdes_packet)))
     {
       /* I'm slave! */
-      n->dds = ntohl(ps->ddseq);
-      n->ddr = ntohl(ps->ddseq);
-      n->options = ps->options;
+      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);
@@ -258,11 +285,11 @@ ospf_dbdes_receive(struct ospf_dbdes_packet *ps,
     }
 
     if (((ps->imms.bit.i == 0) && (ps->imms.bit.ms == 0)) &&
-        (n->rid < myrid) && (n->dds == ntohl(ps->ddseq)))
+        (n->rid < myrid) && (n->dds == ps_ddseq))
     {
       /* I'm master! */
-      n->options = ps->options;
-      n->ddr = ntohl(ps->ddseq) - 1;   /* It will be set corectly a few lines down */
+      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);
       ospf_neigh_sm(n, INM_NEGDONE);
@@ -274,8 +301,8 @@ ospf_dbdes_receive(struct ospf_dbdes_packet *ps,
       break;
     }
   case NEIGHBOR_EXCHANGE:
-    if ((ps->imms.byte == n->imms.byte) && (ps->options == n->options) &&
-       (ntohl(ps->ddseq) == n->ddr))
+    if ((ps->imms.byte == n->imms.byte) && (ps_options == n->options) &&
+       (ps_ddseq == n->ddr))
     {
       /* Duplicate packet */
       OSPF_TRACE(D_PACKETS, "Received duplicate dbdes from %I.", n->ip);
@@ -287,7 +314,7 @@ ospf_dbdes_receive(struct ospf_dbdes_packet *ps,
       return;
     }
 
-    n->ddr = ntohl(ps->ddseq);
+    n->ddr = ps_ddseq;
 
     if (ps->imms.bit.ms != n->imms.bit.ms)     /* M/S bit differs */
     {
@@ -307,7 +334,7 @@ ospf_dbdes_receive(struct ospf_dbdes_packet *ps,
 
     n->imms.byte = ps->imms.byte;
 
-    if (ps->options != n->options)     /* Options differs */
+    if (ps_options != n->options)      /* Options differs */
     {
       OSPF_TRACE(D_PACKETS, "dbdes - sequence mismatch neighbor %I (options)",
                 n->ip);
@@ -317,7 +344,7 @@ ospf_dbdes_receive(struct ospf_dbdes_packet *ps,
 
     if (n->myimms.bit.ms)
     {
-      if (ntohl(ps->ddseq) != n->dds)  /* MASTER */
+      if (ps_ddseq != n->dds)  /* MASTER */
       {
        OSPF_TRACE(D_PACKETS,
                   "dbdes - sequence mismatch neighbor %I (master)", n->ip);
@@ -339,15 +366,15 @@ ospf_dbdes_receive(struct ospf_dbdes_packet *ps,
     }
     else
     {
-      if (ntohl(ps->ddseq) != (n->dds + 1))    /* SLAVE */
+      if (ps_ddseq != (n->dds + 1))    /* SLAVE */
       {
        OSPF_TRACE(D_PACKETS, "dbdes - sequence mismatch neighbor %I (slave)",
                   n->ip);
        ospf_neigh_sm(n, INM_SEQMIS);
        break;
       }
-      n->ddr = ntohl(ps->ddseq);
-      n->dds = ntohl(ps->ddseq);
+      n->ddr = ps_ddseq;
+      n->dds = ps_ddseq;
       ospf_dbdes_reqladd(ps, n);
       ospf_dbdes_send(n, 1);
     }
@@ -355,8 +382,8 @@ ospf_dbdes_receive(struct ospf_dbdes_packet *ps,
     break;
   case NEIGHBOR_LOADING:
   case NEIGHBOR_FULL:
-    if ((ps->imms.byte == n->imms.byte) && (ps->options == n->options)
-       && (ntohl(ps->ddseq) == n->ddr))
+    if ((ps->imms.byte == n->imms.byte) && (ps_options == n->options)
+       && (ps_ddseq == n->ddr))
       /* Only duplicate are accepted */
     {
       OSPF_TRACE(D_PACKETS, "Received duplicate dbdes from %I.", n->ip);
@@ -371,7 +398,7 @@ ospf_dbdes_receive(struct ospf_dbdes_packet *ps,
     {
       OSPF_TRACE(D_PACKETS, "dbdes - sequence mismatch neighbor %I (full)",
                 n->ip);
-      DBG("PS=%u, DDR=%u, DDS=%u\n", ntohl(ps->ddseq), n->ddr, n->dds);
+      DBG("PS=%u, DDR=%u, DDS=%u\n", ps_ddseq, n->ddr, n->dds);
       ospf_neigh_sm(n, INM_SEQMIS);
     }
     break;
index af962928241a24158f52825a9c46cf659793f9e2..63cca0a2b11bf90ba6d1586c543c96ab3f4dfeda 100644 (file)
@@ -11,7 +11,7 @@
 #define _BIRD_OSPF_DBDES_H_
 
 void ospf_dbdes_send(struct ospf_neighbor *n, int next);
-void ospf_dbdes_receive(struct ospf_dbdes_packet *ps,
-                       struct ospf_iface *ifa, struct ospf_neighbor *n);
+void ospf_dbdes_receive(struct ospf_packet *ps, struct ospf_iface *ifa,
+                       struct ospf_neighbor *n);
 
 #endif /* _BIRD_OSPF_DBDES_H_ */
index 45b6b613f99dfe0e0b0a8584d37e86d45e7cbd6c..7eeee3b3d6119fdcdc4a59acd6377abdfaaf9fdb 100644 (file)
@@ -8,12 +8,46 @@
 
 #include "ospf.h"
 
+
+#ifdef OSPFv2
+struct ospf_hello_packet
+{
+  struct ospf_packet ospf_packet;
+  ip_addr netmask;
+  u16 helloint;
+  u8 options;
+  u8 priority;
+  u32 deadint;
+  u32 dr;
+  u32 bdr;
+};
+#endif
+
+
+#ifdef OSPFv3
+struct ospf_hello_packet
+{
+  struct ospf_packet ospf_packet;
+  u32 iface_id;
+  u8 priority;
+  u8 options3;
+  u8 options2;
+  u8 options;
+  u16 helloint;
+  u16 deadint;
+  u32 dr;
+  u32 bdr;
+};
+#endif
+
+
 void
-ospf_hello_receive(struct ospf_hello_packet *ps,
-                  struct ospf_iface *ifa, struct ospf_neighbor *n, ip_addr faddr)
+ospf_hello_receive(struct ospf_packet *ps_i, struct ospf_iface *ifa,
+                  struct ospf_neighbor *n, ip_addr faddr)
 {
+  struct ospf_hello_packet *ps = (void *) ps_i;
   u32 *pnrid;
-  ip_addr olddr, oldbdr;
+  u32 olddr, oldbdr, oldiface_id, tmp;
   ip_addr mask;
   char *beg = "Bad OSPF hello packet from ", *rec = " received: ";
   struct proto *p = (struct proto *) ifa->oa->po;
@@ -21,9 +55,10 @@ ospf_hello_receive(struct ospf_hello_packet *ps,
 
   OSPF_TRACE(D_PACKETS, "HELLO packet received from %I via %s%s", faddr,
       (ifa->type == OSPF_IT_VLINK ? "vlink-" : ""), ifa->iface->name);
+
+#ifdef OSPFv2
   mask = ps->netmask;
   ipa_ntoh(mask);
-
   if (ifa->type != OSPF_IT_VLINK)
     {
       char *msg = L_WARN "Received HELLO packet %s (%I) is inconsistent "
@@ -50,24 +85,30 @@ ospf_hello_receive(struct ospf_hello_packet *ps,
          return;
        }
     }
+#endif
 
-  if (ntohs(ps->helloint) != ifa->helloint)
+  tmp = ntohs(ps->helloint);
+  if (tmp != ifa->helloint)
   {
-    log(L_ERR "%s%I%shello interval mismatch (%d).", beg, faddr, rec,
-       ntohs(ps->helloint));
+    log(L_ERR "%s%I%shello interval mismatch (%d).", beg, faddr, rec, tmp);
     return;
   }
 
-  if (ntohl(ps->deadint) != ifa->dead)
+#ifdef OSPFv2
+  tmp = ntohl(ps->deadint);
+#else /* OSPFv3 */
+  tmp = ntohs(ps->deadint);
+#endif
+  if (tmp != ifa->dead)
   {
-    log(L_ERR "%s%I%sdead interval mismatch (%d).", beg, faddr, rec,
-       ntohl(ps->deadint));
+    log(L_ERR "%s%I%sdead interval mismatch (%d).", beg, faddr, rec, tmp);
     return;
   }
 
-  if (ps->options != ifa->oa->opt.byte)
+  tmp = !(ps->options & OPT_E);
+  if (tmp != ifa->oa->stub)
   {
-    log(L_ERR "%s%I%soptions mismatch (0x%x).", beg, faddr, rec, ps->options);
+    log(L_ERR "%s%I%sstub area flag mismatch (%d).", beg, faddr, rec, tmp);
     return;
   }
 
@@ -111,12 +152,12 @@ ospf_hello_receive(struct ospf_hello_packet *ps,
 
     n->rid = ntohl(((struct ospf_packet *) ps)->routerid);
     n->ip = faddr;
-    n->dr = ps->dr;
-    ipa_ntoh(n->dr);
-    n->bdr = ps->bdr;
-    ipa_ntoh(n->bdr);
+    n->dr = ntohl(ps->dr);
+    n->bdr = ntohl(ps->bdr);
     n->priority = ps->priority;
-    n->options = ps->options;
+#ifdef OSPFv3
+    n->iface_id = ntohl(ps->iface_id);
+#endif
   }
   ospf_neigh_sm(n, INM_HELLOREC);
 
@@ -140,35 +181,54 @@ ospf_hello_receive(struct ospf_hello_packet *ps,
     ospf_neigh_sm(n, INM_1WAYREC);
 
   olddr = n->dr;
-  n->dr = ipa_ntoh(ps->dr);
   oldbdr = n->bdr;
-  n->bdr = ipa_ntoh(ps->bdr);
   oldpriority = n->priority;
+#ifdef OSPFv3
+  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
+
 
   /* Check priority change */
   if (n->state >= NEIGHBOR_2WAY)
   {
+#ifdef OSPFv2
+    u32 rid = n->ip;
+#else /* OSPFv3 */
+    u32 rid = p->cf->global->router_id;
+#endif
+
     if (n->priority != oldpriority)
       ospf_iface_sm(ifa, ISM_NEICH);
 
+#ifdef OSPFv3
+    if (n->iface_id != oldiface_id)
+      ospf_iface_sm(ifa, ISM_NEICH);
+#endif
+
     /* Router is declaring itself ad DR and there is no BDR */
-    if (ipa_equal(n->ip, n->dr) && (ipa_to_u32(n->bdr) == 0)
+    if ((rid == n->dr) && (n->bdr == 0)
        && (n->state != NEIGHBOR_FULL))
       ospf_iface_sm(ifa, ISM_BACKS);
 
     /* Neighbor is declaring itself as BDR */
-    if (ipa_equal(n->ip, n->bdr) && (n->state != NEIGHBOR_FULL))
+    if ((rid == n->bdr) && (n->state != NEIGHBOR_FULL))
       ospf_iface_sm(ifa, ISM_BACKS);
 
     /* Neighbor is newly declaring itself as DR or BDR */
-    if ((ipa_equal(n->ip, n->dr) && (!ipa_equal(n->dr, olddr)))
-       || (ipa_equal(n->ip, n->bdr) && (!ipa_equal(n->bdr, oldbdr))))
+    if (((rid == n->dr) && (n->dr != olddr))
+       || ((rid == n->bdr) && (n->bdr != oldbdr)))
       ospf_iface_sm(ifa, ISM_NEICH);
 
     /* Neighbor is no more declaring itself as DR or BDR */
-    if ((ipa_equal(n->ip, olddr) && (!ipa_equal(n->dr, olddr)))
-       || (ipa_equal(n->ip, oldbdr) && (!ipa_equal(n->bdr, oldbdr))))
+    if (((rid == olddr) && (n->dr != olddr))
+       || ((rid == oldbdr) && (n->bdr != oldbdr)))
       ospf_iface_sm(ifa, ISM_NEICH);
   }
 
@@ -181,7 +241,7 @@ ospf_hello_receive(struct ospf_hello_packet *ps,
 }
 
 void
-ospf_hello_send(timer * timer, int poll, struct ospf_neighbor *dirn)
+ospf_hello_send(timer *timer, int poll, struct ospf_neighbor *dirn)
 {
   struct ospf_iface *ifa;
   struct ospf_hello_packet *pkt;
@@ -223,18 +283,33 @@ ospf_hello_send(timer * timer, int poll, struct ospf_neighbor *dirn)
 
   ospf_pkt_fill_hdr(ifa, pkt, HELLO_P);
 
+#ifdef OSPFv2
   pkt->netmask = ipa_mkmask(ifa->iface->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->options = ifa->oa->opt.byte;
   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->dead);
-  pkt->dr = ifa->drip;
-  ipa_hton(pkt->dr);
-  pkt->bdr = ifa->bdrip;
-  ipa_hton(pkt->bdr);
+  pkt->dr = htonl(ipa_to_u32(ifa->drip));
+  pkt->bdr = htonl(ipa_to_u32(ifa->bdrip));
+#else /* OSPFv3 */
+  pkt->deadint = htons(ifa->dead);
+  pkt->dr = htonl(ifa->drid);
+  pkt->bdr = htonl(ifa->bdrid);
+#endif
 
   /* Fill all neighbors */
   i = 0;
index d535935232362ba9a57d201e5895cfdd52f07744..5d73c09ec5befa84f2ad0e72e54d134483e7b300 100644 (file)
@@ -10,8 +10,8 @@
 #ifndef _BIRD_OSPF_HELLO_H_
 #define _BIRD_OSPF_HELLO_H_
 
-void ospf_hello_receive(struct ospf_hello_packet *ps,
-                       struct ospf_iface *ifa, struct ospf_neighbor *n, ip_addr faddr);
+void ospf_hello_receive(struct ospf_packet *ps_i, struct ospf_iface *ifa,
+                       struct ospf_neighbor *n, ip_addr faddr);
 void ospf_hello_send(timer *timer, int poll, struct ospf_neighbor *dirn);
 
 #endif /* _BIRD_OSPF_HELLO_H_ */
index ea38461d495a7b919acfa30ab3753b6b2e915eef..ea3baa23769ee84f0bd57ade3bb80c0a3874d71a 100644 (file)
@@ -157,16 +157,16 @@ ospf_iface_chstate(struct ospf_iface *ifa, u8 state)
          rfree(ifa->dr_sk);
          ifa->dr_sk = NULL;
        }
-       if ((oldstate == OSPF_IS_DR) && (ifa->nlsa != NULL))
+       if ((oldstate == OSPF_IS_DR) && (ifa->net_lsa != NULL))
        {
-         ifa->nlsa->lsa.age = LSA_MAXAGE;
+         ifa->net_lsa->lsa.age = LSA_MAXAGE;
          if (state >= OSPF_IS_WAITING)
          {
-           ospf_lsupd_flush_nlsa(ifa->nlsa, ifa->oa);
+           ospf_lsupd_flush_nlsa(po, ifa->net_lsa);
          }
          if (can_flush_lsa(po))
-           flush_lsa(ifa->nlsa, po);
-         ifa->nlsa = NULL;
+           flush_lsa(ifa->net_lsa, po);
+         ifa->net_lsa = NULL;
        }
       }
     }
@@ -412,8 +412,16 @@ ospf_iface_new(struct proto_ospf *po, struct iface *iface,
   ifa->waitint = ip->waitint;
   ifa->dead = (ip->dead == 0) ? ip->deadc * ifa->helloint : ip->dead;
   ifa->stub = ip->stub;
+
+#ifdef OSPFv2
   ifa->autype = ip->autype;
   ifa->passwords = ip->passwords;
+#endif
+
+#ifdef OSPFv3
+  ifa->instance_id = ip->instance_id;
+#endif
+
   ifa->rxbuf = ip->rxbuf;
 
   if (ip->type == OSPF_IT_UNDEF)
index 824767a68951fe05ef598ba749dcaa13a108cbf0..7871b8f427818b948f27f2fc8ddd88565ef1ed8c 100644 (file)
@@ -8,6 +8,14 @@
 
 #include "ospf.h"
 
+
+struct ospf_lsack_packet
+{
+  struct ospf_packet ospf_packet;
+  struct ospf_lsa_header lsh[];
+};
+
+
 char *s_queue[] = { "direct", "delayed" };
 
 
@@ -18,14 +26,12 @@ static void ospf_dump_lsack(struct proto *p, struct ospf_lsack_packet *pkt)
   ASSERT(op->type == LSACK_P);
   ospf_dump_common(p, op);
 
-  struct ospf_lsa_header *plsa = (void *) (pkt + 1);
   int i, j;
-
   j = (ntohs(op->length) - sizeof(struct ospf_lsack_packet)) /
     sizeof(struct ospf_lsa_header);
 
   for (i = 0; i < j; i++)
-    ospf_dump_lsahdr(p, plsa + i);
+    ospf_dump_lsahdr(p, pkt->lsh + i);
 }
 
 
@@ -70,7 +76,7 @@ ospf_lsack_send(struct ospf_neighbor *n, int queue)
   op = (struct ospf_packet *) sk->tbuf;
 
   ospf_pkt_fill_hdr(n->ifa, pk, LSACK_P);
-  h = (struct ospf_lsa_header *) (pk + 1);
+  h = pk->lsh;
 
   while (!EMPTY_LIST(n->ackl[queue]))
   {
@@ -141,10 +147,11 @@ ospf_lsack_send(struct ospf_neighbor *n, int queue)
 }
 
 void
-ospf_lsack_receive(struct ospf_lsack_packet *ps,
-                  struct ospf_iface *ifa, struct ospf_neighbor *n)
+ospf_lsack_receive(struct ospf_packet *ps_i, struct ospf_iface *ifa,
+                  struct ospf_neighbor *n)
 {
-  struct ospf_lsa_header lsa, *plsa;
+  struct ospf_lsack_packet *ps = (void *) ps_i;
+  struct ospf_lsa_header lsa;
   u16 nolsa;
   struct top_hash_entry *en;
   struct proto *p = &ifa->oa->po->proto;
@@ -167,12 +174,10 @@ ospf_lsack_receive(struct ospf_lsack_packet *ps,
     return;
   }
 
-  plsa = (struct ospf_lsa_header *) (ps + 1);
-
   for (i = 0; i < nolsa; i++)
   {
-    ntohlsah(plsa + i, &lsa);
-    if ((en = ospf_hash_find_header(n->lsrth, n->ifa->oa->areaid, &lsa)) == NULL)
+    ntohlsah(ps->lsh + i, &lsa);
+    if ((en = ospfxx_hash_find_smart(n->lsrth, n->ifa, &lsa)) == NULL)
       continue;                        /* pg 155 */
 
     if (lsa_comp(&lsa, &en->lsa) != CMP_SAME)  /* pg 156 */
index 05cc22f09607d10f8a67e8f53fa2cea58a363794..63a436d609bc1c51ef575a3852a2e42216612a24 100644 (file)
@@ -16,8 +16,8 @@ struct lsah_n
   struct ospf_lsa_header lsa;
 };
 
-void ospf_lsack_receive(struct ospf_lsack_packet *ps,
-                       struct ospf_iface *ifa, struct ospf_neighbor *n);
+void ospf_lsack_receive(struct ospf_packet *ps_i, struct ospf_iface *ifa,
+                       struct ospf_neighbor *n);
 void ospf_lsack_send(struct ospf_neighbor *n, int queue);
 void ospf_lsack_enqueue(struct ospf_neighbor *n, struct ospf_lsa_header *h,
                        int queue);
index e624b6ce291bae27eca94c4971ed7fe5fa56c54a..7c4001d96b601bcda0c866c9f4ef1f5a2fd3261f 100644 (file)
@@ -65,8 +65,8 @@ ospf_age(struct proto_ospf *po)
        flush_lsa(en, po);
       continue;
     }
-    if ((en->lsa.rt == p->cf->global->router_id) &&(en->lsa.age >=
-                                                   LSREFRESHTIME))
+    if ((en->lsa.rt == p->cf->global->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);
@@ -75,7 +75,7 @@ ospf_age(struct proto_ospf *po)
       en->inst_t = now;
       en->ini_age = 0;
       lsasum_calculate(&en->lsa, en->lsa_body);
-      ospf_lsupd_flood(NULL, NULL, &en->lsa, NULL, en->oa, 1);
+      ospf_lsupd_flood(po, NULL, NULL, &en->lsa, en->domain, 1);
       continue;
     }
     if ((en->lsa.age = (en->ini_age + (now - en->inst_t))) >= LSA_MAXAGE)
@@ -96,7 +96,9 @@ 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 = h->type;
   n->id = htonl(h->id);
   n->rt = htonl(h->rt);
@@ -109,7 +111,9 @@ 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 = n->type;
   h->id = ntohl(n->id);
   h->rt = ntohl(n->rt);
@@ -119,7 +123,7 @@ ntohlsah(struct ospf_lsa_header *n, struct ospf_lsa_header *h)
 };
 
 void
-htonlsab(void *h, void *n, u8 type, u16 len)
+htonlsab(void *h, void *n, u16 type, u16 len)
 {
   unsigned int i;
   switch (type)
@@ -132,24 +136,43 @@ htonlsab(void *h, void *n, u8 type, u16 len)
 
       nrt = n;
       hrt = h;
-      links = hrt->links;
 
+#ifdef OSPFv2
       nrt->veb.byte = hrt->veb.byte;
       nrt->padding = 0;
       nrt->links = htons(hrt->links);
+      links = hrt->links;
+#else /* OSPFv3 */
+      hrt->options = htonl(nrt->options);
+      links = (len - sizeof(struct ospf_lsa_rt)) /
+       sizeof(struct ospf_lsa_rt_link);
+#endif
+
       nrtl = (struct ospf_lsa_rt_link *) (nrt + 1);
       hrtl = (struct ospf_lsa_rt_link *) (hrt + 1);
       for (i = 0; i < links; i++)
       {
-       (nrtl + i)->id = htonl((hrtl + i)->id);
-       (nrtl + i)->data = htonl((hrtl + i)->data);
-       (nrtl + i)->type = (hrtl + i)->type;
-       (nrtl + i)->notos = (hrtl + i)->notos;
-       (nrtl + i)->metric = htons((hrtl + i)->metric);
+#ifdef OSPFv2
+       nrtl[i].id = htonl(hrtl[i].id);
+       nrtl[i].data = htonl(hrtl[i].data);
+       nrtl[i].type = hrtl[i].type;
+       nrtl[i].notos = hrtl[i].notos;
+       nrtl[i].metric = htons(hrtl[i].metric);
+#else /* OSPFv3 */
+       nrtl[i].type = hrtl[i].type;
+       nrtl[i].padding = 0;
+       nrtl[i].metric = htons(hrtl[i].metric);
+       nrtl[i].lif = htonl(hrtl[i].lif);
+       nrtl[i].nif = htonl(hrtl[i].nif);
+       nrtl[i].id = htonl(hrtl[i].id);
+#endif
       }
       break;
     }
   case LSA_T_NET:
+  case LSA_T_SUM_NET:
+  case LSA_T_SUM_RT:
+  case LSA_T_EXT:
     {
       u32 *hid, *nid;
 
@@ -162,59 +185,14 @@ htonlsab(void *h, void *n, u8 type, u16 len)
       }
       break;
     }
-  case LSA_T_SUM_NET:
-  case LSA_T_SUM_RT:
-    {
-      struct ospf_lsa_sum *hs, *ns;
-      union ospf_lsa_sum_tm *hn, *nn;
-
-      hs = h;
-      ns = n;
-
-      ns->netmask = hs->netmask;
-      ipa_hton(ns->netmask);
-
-      hn = (union ospf_lsa_sum_tm *) (hs + 1);
-      nn = (union ospf_lsa_sum_tm *) (ns + 1);
 
-      for (i = 0; i < ((len - sizeof(struct ospf_lsa_sum)) /
-                      sizeof(union ospf_lsa_sum_tm)); i++)
-      {
-       (nn + i)->metric = htonl((hn + i)->metric);
-      }
-      break;
-    }
-  case LSA_T_EXT:
-    {
-      struct ospf_lsa_ext *he, *ne;
-      struct ospf_lsa_ext_tos *ht, *nt;
-
-      he = h;
-      ne = n;
-
-      ne->netmask = he->netmask;
-      ipa_hton(ne->netmask);
-
-      ht = (struct ospf_lsa_ext_tos *) (he + 1);
-      nt = (struct ospf_lsa_ext_tos *) (ne + 1);
-
-      for (i = 0; i < ((len - sizeof(struct ospf_lsa_ext)) /
-                      sizeof(struct ospf_lsa_ext_tos)); i++)
-      {
-       (nt + i)->etm.metric = htonl((ht + i)->etm.metric);
-       (nt + i)->fwaddr = (ht + i)->fwaddr;
-       ipa_hton((nt + i)->fwaddr);
-       (nt + i)->tag = htonl((ht + i)->tag);
-      }
-      break;
-    }
   default:
     bug("(hton): Unknown LSA");
   }
 };
 
 void
-ntohlsab(void *n, void *h, u8 type, u16 len)
+ntohlsab(void *n, void *h, u16 type, u16 len)
 {
   unsigned int i;
   switch (type)
@@ -228,22 +206,41 @@ ntohlsab(void *n, void *h, u8 type, u16 len)
       nrt = n;
       hrt = h;
 
+#ifdef OSPFv2
       hrt->veb.byte = nrt->veb.byte;
       hrt->padding = 0;
       links = hrt->links = ntohs(nrt->links);
+#else /* OSPFv3 */
+      hrt->options = ntohl(nrt->options);
+      links = (len - sizeof(struct ospf_lsa_rt)) /
+       sizeof(struct ospf_lsa_rt_link);
+#endif
+
       nrtl = (struct ospf_lsa_rt_link *) (nrt + 1);
       hrtl = (struct ospf_lsa_rt_link *) (hrt + 1);
       for (i = 0; i < links; i++)
       {
-       (hrtl + i)->id = ntohl((nrtl + i)->id);
-       (hrtl + i)->data = ntohl((nrtl + i)->data);
-       (hrtl + i)->type = (nrtl + i)->type;
-       (hrtl + i)->notos = (nrtl + i)->notos;
-       (hrtl + i)->metric = ntohs((nrtl + i)->metric);
+#ifdef OSPFv2
+       hrtl[i].id = ntohl(nrtl[i].id);
+       hrtl[i].data = ntohl(nrtl[i].data);
+       hrtl[i].type = nrtl[i].type;
+       hrtl[i].notos = nrtl[i].notos;
+       hrtl[i].metric = ntohs(nrtl[i].metric);
+#else /* OSPFv3 */
+       hrtl[i].type = nrtl[i].type;
+       hrtl[i].padding = 0;
+       hrtl[i].metric = ntohs(nrtl[i].metric);
+       hrtl[i].lif = ntohl(nrtl[i].lif);
+       hrtl[i].nif = ntohl(nrtl[i].nif);
+       hrtl[i].id = ntohl(nrtl[i].id);
+#endif
       }
       break;
     }
   case LSA_T_NET:
+  case LSA_T_SUM_NET:
+  case LSA_T_SUM_RT:
+  case LSA_T_EXT:
     {
       u32 *hid, *nid;
 
@@ -252,53 +249,7 @@ ntohlsab(void *n, void *h, u8 type, u16 len)
 
       for (i = 0; i < (len / sizeof(u32)); i++)
       {
-       *(hid + i) = ntohl(*(nid + i));
-      }
-      break;
-    }
-  case LSA_T_SUM_NET:
-  case LSA_T_SUM_RT:
-    {
-      struct ospf_lsa_sum *hs, *ns;
-      union ospf_lsa_sum_tm *hn, *nn;
-
-      hs = h;
-      ns = n;
-
-      hs->netmask = ns->netmask;
-      ipa_ntoh(hs->netmask);
-
-      hn = (union ospf_lsa_sum_tm *) (hs + 1);
-      nn = (union ospf_lsa_sum_tm *) (ns + 1);
-
-      for (i = 0; i < ((len - sizeof(struct ospf_lsa_sum)) /
-                      sizeof(union ospf_lsa_sum_tm)); i++)
-      {
-       (hn + i)->metric = ntohl((nn + i)->metric);
-      }
-      break;
-    }
-  case LSA_T_EXT:
-    {
-      struct ospf_lsa_ext *he, *ne;
-      struct ospf_lsa_ext_tos *ht, *nt;
-
-      he = h;
-      ne = n;
-
-      he->netmask = ne->netmask;
-      ipa_ntoh(he->netmask);
-
-      ht = (struct ospf_lsa_ext_tos *) (he + 1);
-      nt = (struct ospf_lsa_ext_tos *) (ne + 1);
-
-      for (i = 0; i < ((len - sizeof(struct ospf_lsa_ext)) /
-                      sizeof(struct ospf_lsa_ext_tos)); i++)
-      {
-       (ht + i)->etm.metric = ntohl((nt + i)->etm.metric);
-       (ht + i)->fwaddr = (nt + i)->fwaddr;
-       ipa_ntoh((ht + i)->fwaddr);
-       (ht + i)->tag = ntohl((nt + i)->tag);
+       hid[i] = ntohl(nid[i]);
       }
       break;
     }
@@ -343,7 +294,8 @@ lsasum_check(struct ospf_lsa_header *h, void *body)
   u16 length;
 
   b = body;
-  sp = (char *) &h->options;
+  sp = (char *) &h;
+  sp += 2; /* Skip Age field */
   length = ntohs(h->length) - 2;
   h->checksum = 0;
 
@@ -417,45 +369,40 @@ lsa_comp(struct ospf_lsa_header *l1, struct ospf_lsa_header *l2)
 
 /**
  * lsa_install_new - install new LSA into database
+ * @po: OSPF protocol
  * @lsa: LSA header
+ * @domain: domain of LSA
  * @body: pointer to LSA body
- * @oa: current ospf_area
+
  *
  * This function ensures installing new LSA into LSA database. Old instance is
  * replaced. Several actions are taken to detect if new routing table
  * calculation is necessary. This is described in 13.2 of RFC 2328.
  */
 struct top_hash_entry *
-lsa_install_new(struct ospf_lsa_header *lsa, void *body, struct ospf_area *oa)
+lsa_install_new(struct proto_ospf *po, struct ospf_lsa_header *lsa, u32 domain, void *body)
 {
   /* LSA can be temporarrily, but body must be mb_allocated. */
   int change = 0;
   unsigned i;
   struct top_hash_entry *en;
-  struct proto_ospf *po = oa->po;
 
-  if ((en = ospf_hash_find_header(po->gr, oa->areaid, lsa)) == NULL)
+  if ((en = ospfxx_hash_find_header(po->gr, domain, lsa)) == NULL)
   {
-    en = ospf_hash_get_header(po->gr, oa, lsa);
+    en = ospfxx_hash_get_header(po->gr, domain, lsa);
     change = 1;
   }
   else
   {
-    if ((en->lsa.length != lsa->length) || (en->lsa.options != lsa->options)
-       || ((en->lsa.age == LSA_MAXAGE) || (lsa->age == LSA_MAXAGE)))
+    if ((en->lsa.length != lsa->length)
+#ifdef OSPFv2       
+       || (en->lsa.options != lsa->options)
+#endif
+       || (en->lsa.age == LSA_MAXAGE)
+       || (lsa->age == LSA_MAXAGE)
+       || memcmp(en->lsa_body, body, lsa->length - sizeof(struct ospf_lsa_header)))
       change = 1;
-    else
-    {
-      u8 *k = en->lsa_body, *l = body;
-      for (i = 0; i < (lsa->length - sizeof(struct ospf_lsa_header)); i++)
-      {
-       if (*(k + i) != *(l + i))
-       {
-         change = 1;
-         break;
-       }
-      }
-    }
+
     s_rem_node(SNODE en);
   }
 
index c7f16d511bbbe8c34115c8d34b703767cc9f5fc0..640fa1731b69f05b13cc60b57a05a99120faaa98 100644 (file)
 
 void htonlsah(struct ospf_lsa_header *h, struct ospf_lsa_header *n);
 void ntohlsah(struct ospf_lsa_header *n, struct ospf_lsa_header *h);
-void htonlsab(void *h, void *n, u8 type, u16 len);
-void ntohlsab(void *n, void *h, u8 type, u16 len);
+void htonlsab(void *h, void *n, u16 type, u16 len);
+void ntohlsab(void *n, void *h, u16 type, u16 len);
 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);
-struct top_hash_entry *lsa_install_new(struct ospf_lsa_header *lsa,
-                                      void *body, struct ospf_area *oa);
+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);
 void flush_lsa(struct top_hash_entry *en, struct proto_ospf *po);
 
index 5eeb06f0ad0be15f0805d245d8b5d272048b1eea..cc5afa0ffc92173a92e3b14f8d8e7e56a9ff5f1b 100644 (file)
@@ -8,6 +8,14 @@
 
 #include "ospf.h"
 
+
+struct ospf_lsreq_packet
+{
+  struct ospf_packet ospf_packet;
+  struct ospf_lsreq_header lsh[];
+};
+
+
 static void ospf_dump_lsreq(struct proto *p, struct ospf_lsreq_packet *pkt)
 {
   struct ospf_packet *op = &pkt->ospf_packet;
@@ -15,15 +23,13 @@ static void ospf_dump_lsreq(struct proto *p, struct ospf_lsreq_packet *pkt)
   ASSERT(op->type == LSREQ_P);
   ospf_dump_common(p, op);
 
-  struct ospf_lsreq_header *plsr = (void *) (pkt + 1);
   int i, j;
-
-  j = (ntohs(op->length) - sizeof(struct ospf_dbdes_packet)) /
+  j = (ntohs(op->length) - sizeof(struct ospf_lsreq_packet)) /
     sizeof(struct ospf_lsreq_header);
 
   for (i = 0; i < j; i++)
-    log(L_TRACE "%s:     LSR      Id: %R, Rt: %R, Type: %u",
-       p->name, htonl(plsr[i].id), htonl(plsr[i].rt), plsr[i].type);
+    log(L_TRACE "%s:     LSR      Id: %R, Rt: %R, Type: %u", p->name,
+       htonl(pkt->lsh[i].id), htonl(pkt->lsh[i].rt), pkt->lsh[i].type);
 }
 
 void
@@ -53,14 +59,12 @@ ospf_lsreq_send(struct ospf_neighbor *n)
 
   i = j = (ospf_pkt_maxsize(n->ifa) - sizeof(struct ospf_lsreq_packet)) /
     sizeof(struct ospf_lsreq_header);
-  lsh = (struct ospf_lsreq_header *) (pk + 1);
+  lsh = pk->lsh;
 
   for (; i > 0; i--)
   {
     en = (struct top_hash_entry *) sn;
-    lsh->padd1 = 0;
-    lsh->padd2 = 0;
-    lsh->type = en->lsa.type;
+    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",
@@ -84,9 +88,10 @@ ospf_lsreq_send(struct ospf_neighbor *n)
 }
 
 void
-ospf_lsreq_receive(struct ospf_lsreq_packet *ps,
-                  struct ospf_iface *ifa, struct ospf_neighbor *n)
+ospf_lsreq_receive(struct ospf_packet *ps_i, struct ospf_iface *ifa,
+                  struct ospf_neighbor *n)
 {
+  struct ospf_lsreq_packet *ps = (void *) ps_i;
   struct ospf_lsreq_header *lsh;
   struct l_lsr_head *llsh;
   list uplist;
@@ -104,7 +109,7 @@ ospf_lsreq_receive(struct ospf_lsreq_packet *ps,
 
   ospf_neigh_sm(n, INM_HELLOREC);
 
-  lsh = (void *) (ps + 1);
+  lsh = ps->lsh;
   init_list(&uplist);
   upslab = sl_new(n->pool, sizeof(struct l_lsr_head));
 
@@ -114,18 +119,19 @@ ospf_lsreq_receive(struct ospf_lsreq_packet *ps,
   {
     u32 hid = ntohl(lsh->id);
     u32 hrt = ntohl(lsh->rt);
+    u32 htype = ntohl(lsh->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 = lsh->type;
+    llsh->lsh.type = htype;
     add_tail(&uplist, NODE llsh);
-    if (ospf_hash_find(po->gr, oa->areaid, llsh->lsh.id, llsh->lsh.rt,
-                      llsh->lsh.type) == NULL)
+    if (ospfxx_hash_find(po->gr, dom, hid, hrt, htype) == NULL)
     {
       log(L_WARN
          "Received bad LS req from: %I looking: Type: %u, ID: %R, RT: %R",
-         n->ip, lsh->type, hid, hrt);
+         n->ip, htype, hid, hrt);
       ospf_neigh_sm(n, INM_BADLSREQ);
       rfree(upslab);
       return;
index f917f05ce6c97b4ee6bad8463236cd942c360b90..a12edde2919ac452a72fae506d726ba052718184 100644 (file)
@@ -11,7 +11,7 @@
 #define _BIRD_OSPF_LSREQ_H_
 
 void ospf_lsreq_send(struct ospf_neighbor *n);
-void ospf_lsreq_receive(struct ospf_lsreq_packet *ps,
-                       struct ospf_iface *ifa, struct ospf_neighbor *n);
+void ospf_lsreq_receive(struct ospf_packet *ps_i, struct ospf_iface *ifa,
+                       struct ospf_neighbor *n);
 
 #endif /* _BIRD_OSPF_LSREQ_H_ */
index ba09fec0b2ecc8a084ee7f1156930a0d5f56328c..8c26f5487a83cbe07fa11be62d378b4bae6085f0 100644 (file)
@@ -9,6 +9,13 @@
 #include "ospf.h"
 
 
+struct ospf_lsupd_packet
+{
+  struct ospf_packet ospf_packet;
+  u32 lsano;                   /* Number of LSA's */
+};
+
+
 void ospf_dump_lsahdr(struct proto *p, struct ospf_lsa_header *lsa_n)
 {
   struct ospf_lsa_header lsa;
@@ -51,27 +58,79 @@ static void ospf_dump_lsupd(struct proto *p, struct ospf_lsupd_packet *pkt)
     }
 }
 
+
+#ifdef OSPFv2
+
+int
+ospf_lsa_flooding_allowed(struct ospf_lsa_header *lsa, u32 domain, struct ospf_iface *ifa)
+{
+  if (lsa->type == LSA_T_EXT)
+    {
+      if (ifa->type == OSPF_IT_VLINK)
+       return 0;
+      if (ifa->oa->stub)
+       return 0;
+      return 1
+    }
+  else
+    return ifa->oa->areaid == domain;
+}
+
+#else /* OSPFv3 */
+
+int
+ospf_lsa_flooding_allowed(struct ospf_lsa_header *lsa, u32 domain, struct ospf_iface *ifa)
+{    
+  u32 scope = LSA_SCOPE(lsa);
+
+  /* 4.5.2 (Case 2) */
+  if (unknown_type(lsa) && !(lsa->type & LSA_UBIT))
+    scope = LSA_SCOPE_LINK;
+
+  switch (scope)
+    {
+    case LSA_SCOPE_LINK:
+      return ifa->iface->index == domain;
+
+    case LSA_SCOPE_AREA:
+      return ifa->oa->areaid == domain;
+
+    case LSA_SCOPE_AS:
+      if (ifa->type == OSPF_IT_VLINK)
+       return 0;
+      if (ifa->oa->stub)
+       return 0;
+      return 1;
+
+    default:
+      log(L_ERR "LSA with invalid scope");
+      return 0;
+    }
+}
+
+#endif
+
 /**
  * ospf_lsupd_flood - send received or generated lsa to the neighbors
+ * @po: OSPF protocol
  * @n: neighbor than sent this lsa (or NULL if generated)
  * @hn: LSA header followed by lsa body in network endianity (may be NULL) 
  * @hh: LSA header in host endianity (must be filled)
- * @iff: interface which received this LSA (or NULL if LSA is generated)
- * @oa: ospf_area which is the LSA generated for
+ * @domain: domain of LSA (must be filled)
  * @rtl: add this LSA into retransmission list
  *
+ *
  * return value - was the LSA flooded back?
  */
 
 int
-ospf_lsupd_flood(struct ospf_neighbor *n, struct ospf_lsa_header *hn,
-                struct ospf_lsa_header *hh, struct ospf_iface *iff,
-                struct ospf_area *oa, int rtl)
+ospf_lsupd_flood(struct proto_ospf *po,
+                struct ospf_neighbor *n, struct ospf_lsa_header *hn,
+                struct ospf_lsa_header *hh, u32 domain, int rtl)
 {
   struct ospf_iface *ifa;
   struct ospf_neighbor *nn;
   struct top_hash_entry *en;
-  struct proto_ospf *po = oa->po;
   struct proto *p = &po->proto;
   int ret, retval = 0;
 
@@ -81,18 +140,8 @@ ospf_lsupd_flood(struct ospf_neighbor *n, struct ospf_lsa_header *hn,
     if (ifa->stub)
       continue;
 
-    if (hh->type == LSA_T_EXT)
-    {
-      if (ifa->type == OSPF_IT_VLINK)
-       continue;
-      if (ifa->oa->stub)
-       continue;
-    }
-    else
-    {
-      if (ifa->oa != oa)
-        continue;
-    }
+    if (! ospf_lsa_flooding_allowed(hh, domain, ifa))
+      continue;
 
     DBG("Wanted to flood LSA: Type: %u, ID: %R, RT: %R, SN: 0x%x, Age %u\n",
        hh->type, hh->id, hh->rt, hh->sn, hh->age);
@@ -100,11 +149,14 @@ ospf_lsupd_flood(struct ospf_neighbor *n, struct ospf_lsa_header *hn,
     ret = 0;
     WALK_LIST(nn, ifa->neigh_list)
     {
+      /* 13.3 (1a) */
       if (nn->state < NEIGHBOR_EXCHANGE)
        continue;
+
+      /* 13.3 (1b) */
       if (nn->state < NEIGHBOR_FULL)
       {
-       if ((en = ospf_hash_find_header(nn->lsrqh, nn->ifa->oa->areaid, hh)) != NULL)
+       if ((en = ospfxx_hash_find_header(nn->lsrqh, domain, hh)) != NULL)
        {
          DBG("That LSA found in lsreq list for neigh %R\n", nn->rid);
 
@@ -140,14 +192,20 @@ ospf_lsupd_flood(struct ospf_neighbor *n, struct ospf_lsa_header *hn,
        }
       }
 
+      /* 13.3 (1c) */
       if (nn == n)
        continue;
 
+      /* 13.3 (1d) */
       if (rtl)
       {
-       if ((en = ospf_hash_find_header(nn->lsrth, nn->ifa->oa->areaid, hh)) == NULL)
+       /* In OSPFv3, there should be check whether receiving router understand
+          that type of LSA (for LSA types with U-bit == 0). But as we does not support
+          any optional LSA types, this is not needed yet */
+
+       if ((en = ospfxx_hash_find_header(nn->lsrth, domain, hh)) == NULL)
        {
-         en = ospf_hash_get_header(nn->lsrth, nn->ifa->oa, hh);
+         en = ospfxx_hash_get_header(nn->lsrth, domain, hh);
        }
        else
        {
@@ -159,7 +217,7 @@ ospf_lsupd_flood(struct ospf_neighbor *n, struct ospf_lsa_header *hn,
       }
       else
       {
-       if ((en = ospf_hash_find_header(nn->lsrth, nn->ifa->oa->areaid, hh)) != NULL)
+       if ((en = ospfxx_hash_find_header(nn->lsrth, domain, hh)) != NULL)
        {
          s_rem_node(SNODE en);
          if (en->lsa_body != NULL)
@@ -175,11 +233,11 @@ ospf_lsupd_flood(struct ospf_neighbor *n, struct ospf_lsa_header *hn,
     if (ret == 0)
       continue;                        /* pg 150 (2) */
 
-    if (ifa == iff)
+    if (n && (n->ifa == ifa))
     {
-      if ((n->rid == iff->drid) || n->rid == iff->bdrid)
+      if ((n->rid == ifa->drid) || n->rid == ifa->bdrid)
        continue;               /* pg 150 (3) */
-      if (iff->state == OSPF_IS_BACKUP)
+      if (ifa->state == OSPF_IS_BACKUP)
        continue;               /* pg 150 (4) */
       retval = 1;
     }
@@ -216,7 +274,7 @@ ospf_lsupd_flood(struct ospf_neighbor *n, struct ospf_lsa_header *hn,
 
        htonlsah(hh, lh);
        help = (u8 *) (lh + 1);
-       en = ospf_hash_find_header(po->gr, oa->areaid, hh);
+       en = ospfxx_hash_find_header(po->gr, domain, hh);
        htonlsab(en->lsa_body, help, hh->type, hh->length
                 - sizeof(struct ospf_lsa_header));
       }
@@ -288,8 +346,9 @@ ospf_lsupd_send_list(struct ospf_neighbor *n, list * l)
 
   WALK_LIST(llsh, *l)
   {
-    if ((en = ospf_hash_find(po->gr, oa->areaid, llsh->lsh.id, llsh->lsh.rt,
-                            llsh->lsh.type)) == NULL)
+    u32 domain = ospf_lsa_domain(llsh->lsh.type, n->ifa);
+    if ((en = ospfxx_hash_find(po->gr, domain, llsh->lsh.id,
+                              llsh->lsh.rt, llsh->lsh.type)) == NULL)
       continue;                        /* Probably flushed LSA */
     /* FIXME This is a bug! I cannot flush LSA that is in lsrt */
 
@@ -330,13 +389,12 @@ ospf_lsupd_send_list(struct ospf_neighbor *n, list * l)
 }
 
 void
-ospf_lsupd_receive(struct ospf_lsupd_packet *ps,
-                  struct ospf_iface *ifa, struct ospf_neighbor *n)
+ospf_lsupd_receive(struct ospf_packet *ps_i, struct ospf_iface *ifa,
+                  struct ospf_neighbor *n)
 {
-  u32 area;
+  struct ospf_lsupd_packet *ps = (void *) ps_i;
   struct ospf_neighbor *ntmp;
   struct ospf_lsa_header *lsa;
-  struct ospf_area *oa;
   struct proto_ospf *po = ifa->oa->po;
   struct proto *p = &po->proto;
   unsigned int i, sendreq = 1, size = ntohs(ps->ospf_packet.length);
@@ -359,8 +417,6 @@ ospf_lsupd_receive(struct ospf_lsupd_packet *ps,
   ospf_neigh_sm(n, INM_HELLOREC);      /* Questionable */
 
   lsa = (struct ospf_lsa_header *) (ps + 1);
-  area = htonl(ps->ospf_packet.areaid);
-  oa = ospf_find_area((struct proto_ospf *) p, area);
 
   for (i = 0; i < ntohl(ps->lsano); i++,
        lsa = (struct ospf_lsa_header *) (((u8 *) lsa) + ntohs(lsa->length)))
@@ -394,6 +450,8 @@ ospf_lsupd_receive(struct ospf_lsupd_packet *ps,
       continue;
     }
 
+
+#ifdef OSPFv2
     /* pg 143 (2) */
     if ((lsa->type < LSA_T_RT) || (lsa->type > LSA_T_EXT))
     {
@@ -402,18 +460,34 @@ ospf_lsupd_receive(struct ospf_lsupd_packet *ps,
     }
 
     /* pg 143 (3) */
-    if ((lsa->type == LSA_T_EXT) && oa->stub)
+    if ((lsa->type == LSA_T_EXT) && ifa->oa->stub)
     {
       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) && ifa->oa->stub)
+    {
+      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))
+    {
+      log(L_WARN "Received LSA with invalid scope from %I", n->ip);
+      continue;
+    }
+#endif
 
     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);
 
-    lsadb = ospf_hash_find_header(po->gr, oa->areaid, &lsatmp);
+    u32 domain = ospf_lsa_domain(lsatmp.type, ifa);
+    lsadb = ospfxx_hash_find_header(po->gr, domain, &lsatmp);
 
 #ifdef LOCAL_DEBUG
     if (lsadb)
@@ -439,7 +513,8 @@ ospf_lsupd_receive(struct ospf_lsupd_packet *ps,
 
       DBG("PG143(5): Received LSA is newer\n");
 
-      /* pg 145 (5f) - premature aging of self originated lsa */
+#ifdef OSPFv2
+      /* 13.4 - check self-originated LSAs of NET type */
       if ((!self) && (lsatmp.type == LSA_T_NET))
       {
        WALK_LIST(nifa, po->iface_list)
@@ -453,7 +528,9 @@ ospf_lsupd_receive(struct ospf_lsupd_packet *ps,
          }
        }
       }
+#endif
 
+      /* pg 145 (5f) - premature aging of self originated lsa */
       if (self)
       {
        struct top_hash_entry *en;
@@ -473,10 +550,10 @@ ospf_lsupd_receive(struct ospf_lsupd_packet *ps,
                   lsatmp.type, lsatmp.id, lsatmp.rt);
        lsasum_check(lsa, (lsa + 1));   /* It also calculates chsum! */
        lsatmp.checksum = ntohs(lsa->checksum);
-       ospf_lsupd_flood(NULL, lsa, &lsatmp, NULL, oa, 0);
-       if (en = ospf_hash_find_header(po->gr, oa->areaid, &lsatmp))
-       {
-         ospf_lsupd_flood(NULL, NULL, &en->lsa, NULL, oa, 1);
+       ospf_lsupd_flood(po, NULL, lsa, &lsatmp, domain, 0);
+       if (en = ospfxx_hash_find_header(po->gr, domain, &lsatmp))
+       { /* FIXME verify hacks */
+         ospf_lsupd_flood(po, NULL, NULL, &en->lsa, domain, 1);
        }
        continue;
       }
@@ -489,7 +566,7 @@ ospf_lsupd_receive(struct ospf_lsupd_packet *ps,
        continue;
       }
 
-      if (ospf_lsupd_flood(n, lsa, &lsatmp, ifa, ifa->oa, 1) == 0)
+      if (ospf_lsupd_flood(po, n, lsa, &lsatmp, domain, 1) == 0)
       {
        DBG("Wasn't flooded back\n");   /* ps 144(5e), pg 153 */
        if (ifa->state == OSPF_IS_BACKUP)
@@ -509,7 +586,7 @@ ospf_lsupd_receive(struct ospf_lsupd_packet *ps,
       {
        struct top_hash_entry *en;
        if (ntmp->state > NEIGHBOR_EXSTART)
-         if ((en = ospf_hash_find_header(ntmp->lsrth, ntmp->ifa->oa->areaid, &lsadb->lsa)) != NULL)
+         if ((en = ospfxx_hash_find_header(ntmp->lsrth, domain, &lsadb->lsa)) != NULL)
          {
            s_rem_node(SNODE en);
            if (en->lsa_body != NULL)
@@ -532,7 +609,7 @@ ospf_lsupd_receive(struct ospf_lsupd_packet *ps,
        mb_alloc(p->pool, lsatmp.length - sizeof(struct ospf_lsa_header));
       ntohlsab(lsa + 1, body, lsatmp.type,
               lsatmp.length - sizeof(struct ospf_lsa_header));
-      lsadb = lsa_install_new(&lsatmp, body, oa);
+      lsadb = lsa_install_new(po, &lsatmp, domain, body);
       DBG("New LSA installed in DB\n");
 
       continue;
@@ -545,7 +622,7 @@ ospf_lsupd_receive(struct ospf_lsupd_packet *ps,
     {
       struct top_hash_entry *en;
       DBG("PG145(7) Got the same LSA\n");
-      if ((en = ospf_hash_find_header(n->lsrth, n->ifa->oa->areaid, &lsadb->lsa)) != NULL)
+      if ((en = ospfxx_hash_find_header(n->lsrth, lsadb->domain, &lsadb->lsa)) != NULL)
       {
        /* pg145 (7a) */
        s_rem_node(SNODE en);
@@ -596,10 +673,9 @@ ospf_lsupd_receive(struct ospf_lsupd_packet *ps,
 }
 
 void
-ospf_lsupd_flush_nlsa(struct top_hash_entry *en, struct ospf_area *oa)
+ospf_lsupd_flush_nlsa(struct proto_ospf *po, struct top_hash_entry *en)
 {
   struct ospf_lsa_header *lsa = &en->lsa;
-  struct proto_ospf *po = oa->po;
   struct proto *p = &po->proto;
 
   lsa->age = LSA_MAXAGE;
@@ -607,5 +683,5 @@ ospf_lsupd_flush_nlsa(struct top_hash_entry *en, struct ospf_area *oa)
   lsasum_calculate(lsa, en->lsa_body);
   OSPF_TRACE(D_EVENTS, "Premature aging self originated lsa!");
   OSPF_TRACE(D_EVENTS, "Type: %d, Id: %R, Rt: %R", lsa->type, lsa->id, lsa->rt);
-  ospf_lsupd_flood(NULL, NULL, lsa, NULL, oa, 0);
+  ospf_lsupd_flood(po, NULL, NULL, lsa, en->domain, 0);
 }
index 524a0a2d091527674dac4a91d1b33fcfaaf76c41..8bacfe655d07d49c373b3acfc10726ca80800f83 100644 (file)
 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_lsupd_send_list(struct ospf_neighbor *n, list * l);
-void ospf_lsupd_receive(struct ospf_lsupd_packet *ps,
+void ospf_lsupd_receive(struct ospf_packet *ps_i,
                        struct ospf_iface *ifa, struct ospf_neighbor *n);
-int ospf_lsupd_flood(struct ospf_neighbor *n, struct ospf_lsa_header *hn,
-                    struct ospf_lsa_header *hh, struct ospf_iface *iff,
-                    struct ospf_area *oa, int rtl);
-void ospf_lsupd_flush_nlsa(struct top_hash_entry *en, struct ospf_area *oa);
+int ospf_lsupd_flood(struct proto_ospf *po,
+                    struct ospf_neighbor *n, struct ospf_lsa_header *hn,
+                    struct ospf_lsa_header *hh, u32 domain, int rtl);
+void ospf_lsupd_flush_nlsa(struct proto_ospf *po, struct top_hash_entry *en);
+int ospf_lsa_flooding_allowed(struct ospf_lsa_header *lsa, u32 domain, struct ospf_iface *ifa);
+
 
 #endif /* _BIRD_OSPF_LSUPD_H_ */
index bb681c226b897f7a502cb0eaa8b8da9ddbb07ab0..d86895eddcd971a0eaa0f3c3f3cd4e78d4d47a9a 100644 (file)
@@ -171,16 +171,23 @@ static struct ospf_neighbor *
 electbdr(list nl)
 {
   struct ospf_neighbor *neigh, *n1, *n2;
+  u32 nid;
+
+#ifdef OSPFv2
+  nid = ipa_to_u32(neigh->ip);
+#else /* OSPFv3 */
+  nid = neigh->rid;
+#endif
 
   n1 = NULL;
   n2 = NULL;
-  WALK_LIST(neigh, nl)         /* First try those decl. themselves */
+  WALK_LIST(neigh, nl)                 /* First try those decl. themselves */
   {
     if (neigh->state >= NEIGHBOR_2WAY) /* Higher than 2WAY */
-      if (neigh->priority > 0) /* Eligible */
-       if (ipa_compare(neigh->ip, neigh->dr) != 0)     /* And not decl. itself DR */
+      if (neigh->priority > 0)         /* Eligible */
+       if (neigh->dr != nid)           /* And not decl. itself DR */
        {
-         if (ipa_compare(neigh->ip, neigh->bdr) == 0)  /* Declaring BDR */
+         if (neigh->bdr == nid)        /* Declaring BDR */
          {
            if (n1 != NULL)
            {
@@ -222,13 +229,20 @@ static struct ospf_neighbor *
 electdr(list nl)
 {
   struct ospf_neighbor *neigh, *n;
+  u32 nid;
+
+#ifdef OSPFv2
+  nid = ipa_to_u32(neigh->ip);
+#else /* OSPFv3 */
+  nid = neigh->rid;
+#endif
 
   n = NULL;
-  WALK_LIST(neigh, nl)         /* And now DR */
+  WALK_LIST(neigh, nl)                 /* And now DR */
   {
     if (neigh->state >= NEIGHBOR_2WAY) /* Higher than 2WAY */
-      if (neigh->priority > 0) /* Eligible */
-       if (ipa_compare(neigh->ip, neigh->dr) == 0)     /* And declaring itself DR */
+      if (neigh->priority > 0)         /* Eligible */
+       if (neigh->dr == nid)           /* And declaring itself DR */
        {
          if (n != NULL)
          {
@@ -427,7 +441,6 @@ bdr_election(struct ospf_iface *ifa)
 {
   struct ospf_neighbor *neigh, *ndr, *nbdr, me;
   u32 myid;
-  ip_addr ndrip, nbdrip;
   int doadj;
   struct proto *p = &ifa->oa->po->proto;
 
@@ -438,10 +451,17 @@ bdr_election(struct ospf_iface *ifa)
   me.state = NEIGHBOR_2WAY;
   me.rid = myid;
   me.priority = ifa->priority;
-  me.dr = ifa->drip;
-  me.bdr = ifa->bdrip;
   me.ip = ifa->iface->addr->ip;
 
+#ifdef OSPFv2
+  me.dr = ipa_to_u32(ifa->drip);
+  me.bdr = ipa_to_u32(ifa->bdrip);
+#else /* OSPFv3 */
+  me.dr = ifa->drid;
+  me.bdr = ifa->bdrid;
+  me.iface_id = ifa->iface->index;
+#endif
+
   add_tail(&ifa->neigh_list, NODE & me);
 
   nbdr = electbdr(ifa->neigh_list);
@@ -450,64 +470,43 @@ bdr_election(struct ospf_iface *ifa)
   if (ndr == NULL)
     ndr = nbdr;
 
+  /* 9.4. (4) */
   if (((ifa->drid == myid) && (ndr != &me))
       || ((ifa->drid != myid) && (ndr == &me))
       || ((ifa->bdrid == myid) && (nbdr != &me))
       || ((ifa->bdrid != myid) && (nbdr == &me)))
   {
-    if (ndr == NULL)
-      ifa->drip = me.dr = IPA_NONE;
-    else
-      ifa->drip = me.dr = ndr->ip;
-
-    if (nbdr == NULL)
-      ifa->bdrip = me.bdr = IPA_NONE;
-    else
-      ifa->bdrip = me.bdr = nbdr->ip;
+#ifdef OSPFv2
+    me.dr = ndr ? ipa_to_u32(ndr->ip) : IPA_NONE;
+    me.bdr = nbdr ? ipa_to_u32(nbdr->ip) : IPA_NONE;
+#else /* OSPFv3 */
+    me.dr = ndr ? ndr->rid : 0;
+    me.bdr = nbdr ? nbdr->rid : 0;
+#endif
 
     nbdr = electbdr(ifa->neigh_list);
     ndr = electdr(ifa->neigh_list);
-  }
-
-  if (ndr == NULL)
-    ndrip = IPA_NONE;
-  else
-    ndrip = ndr->ip;
-
-  if (nbdr == NULL)
-    nbdrip = IPA_NONE;
-  else
-    nbdrip = nbdr->ip;
-
-  doadj = 0;
-  if ((ipa_compare(ifa->drip, ndrip) != 0)
-      || (ipa_compare(ifa->bdrip, nbdrip) != 0))
-    doadj = 1;
 
-  if (ndr == NULL)
-  {
-    ifa->drid = 0;
-    ifa->drip = IPA_NONE;
-  }
-  else
-  {
-    ifa->drid = ndr->rid;
-    ifa->drip = ndr->ip;
+    if (ndr == NULL)
+      ndr = nbdr;
   }
 
-  if (nbdr == NULL)
-  {
-    ifa->bdrid = 0;
-    ifa->bdrip = IPA_NONE;
-  }
-  else
-  {
-    ifa->bdrid = nbdr->rid;
-    ifa->bdrip = nbdr->ip;
-  }
+  u32 odrid = ifa->drid;
+  u32 obdrid = ifa->bdrid;
+  ifa->drid = ndr ? ndr->rid : 0;
+  ifa->drip = ndr ? ndr->ip  : IPA_NONE;
+  ifa->bdrid = nbdr ? nbdr->rid : 0;
+  ifa->bdrip = nbdr ? nbdr->ip  : IPA_NONE;
+
+#ifdef OSPFv3
+  ifa->dr_iface_id = ndr ? ndr->iface_id : 0;
+#endif
 
   DBG("DR=%R, BDR=%R\n", ifa->drid, ifa->bdrid);
 
+  doadj = ((ifa->drid != odrid) || (ifa->bdrid != obdrid));
+
   if (myid == ifa->drid)
     ospf_iface_chstate(ifa, OSPF_IS_DR);
   else
index d4bcbed764d08b8dd6b8ec1027138936c0abaf57..2ee6e631036dd1a16019aaedcddf39ac12fd9e98 100644 (file)
@@ -163,8 +163,11 @@ ospf_start(struct proto *p)
       oa->stub = 0;
     }
 
-    oa->opt.byte = 0;
-    if(!oa->stub) oa->opt.bit.e = 1;
+#ifdef OSPFv2
+    oa->options = (oa->stub ? 0 : OPT_E);
+#else /* OSPFv3 */
+    oa->options = OPT_R | (oa->stub ? 0 : OPT_E) | OPT_V6;
+#endif
   }
 
   /* Add all virtual links as interfaces */
@@ -186,8 +189,11 @@ ospf_start(struct proto *p)
          fib_init(&oa->net_fib, p->pool, sizeof(struct area_net), 16, ospf_area_initfib);
           fib_init(&oa->rtr, p->pool, sizeof(ort), 16, ospf_rt_initort);
           po->backbone = oa;
-          oa->opt.byte = 0;
-          oa->opt.bit.e = 1;
+#ifdef OSPFv2
+         oa->options = OPT_E;
+#else /* OSPFv3 */
+         oa->options = OPT_R | OPT_E | OPT_V6;
+#endif
        }
         ospf_iface_new(po, NULL, ac, ipatt);
       }
@@ -448,36 +454,9 @@ ospf_rt_notify(struct proto *p, net * n, rte * new, rte * old UNUSED,
 */
 
   if (new)                     /* Got some new route */
-  {
     originate_ext_lsa(n, new, po, attrs);
-  }
   else
-  {
-    u32 rtid = po->proto.cf->global->router_id;
-    struct ospf_area *oa;
-    struct top_hash_entry *en;
-    u32 pr = ipa_to_u32(n->n.prefix);
-    struct ospf_lsa_ext *ext;
-    int i;
-    int max = max_ext_lsa(n->n.pxlen);
-
-    /* Flush old external LSA */
-    for (i = 0; i < max; i++, pr++)
-    {
-      if (en = ospf_hash_find(po->gr, 0, pr, rtid, LSA_T_EXT))
-      {
-        ext = en->lsa_body;
-       if (ipa_compare(ext->netmask, ipa_mkmask(n->n.pxlen)) == 0)
-       {
-          WALK_LIST(oa, po->area_list)
-          {
-           ospf_lsupd_flush_nlsa(en, oa);
-         }
-       }
-        break;
-      }
-    }
-  }
+    flush_ext_lsa(n, po);
 }
 
 static void
@@ -762,6 +741,7 @@ ospf_reconfigure(struct proto *p, struct proto_config *c)
                     "Interface %s is no longer stub.", ifa->iface->name);
        }
 
+#ifdef OSPFv2  
        /* AUTHENTICATION */
        if (oldip->autype != newip->autype)
        {
@@ -772,6 +752,7 @@ ospf_reconfigure(struct proto *p, struct proto_config *c)
        }
         /* Add *passwords */
        ifa->passwords = newip->passwords;
+#endif
 
        /* priority */
        if (oldip->priority != newip->priority)
@@ -1076,24 +1057,24 @@ he_compare(const void *p1, const void *p2)
       return lsa1->age - lsa2->age;
     }
 }
-
+/*
 static inline void
 show_lsa_router(struct top_hash_entry *he)
 {
   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);
-  u32 i;
+  int max = lsa_rt_count(lsa);
 
-  for (i = 0; i < rt->links; i++)
+  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);
 
-  for (i = 0; i < rt->links; i++)
+  for (i = 0; i < max; i++)
     if (rr[i].type == LSART_NET)
     {
       struct proto_ospf *po = he->oa->po;
-      struct top_hash_entry *net_he = ospf_hash_find(po->gr, he->oa->areaid, rr[i].id, rr[i].id, LSA_T_NET);
+      struct top_hash_entry *net_he = ospfxx_hash_find(po->gr, he->oa->areaid, rr[i].id, rr[i].id, LSA_T_NET);
       if (net_he)
       {
        struct ospf_lsa_header *net_lsa = &(net_he->lsa);
@@ -1104,11 +1085,11 @@ show_lsa_router(struct top_hash_entry *he)
        cli_msg(-1016, "\t\tnetwork ??? metric %u ", rr[i].metric);
     }
 
-  for (i = 0; i < rt->links; i++)
+  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);
 
-  for (i = 0; i < rt->links; i++)
+  for (i = 0; i < max; i++)
     if (rr[i].type == LSART_VLNK)
       cli_msg(-1016, "\t\tvlink %I metric %u ", ipa_from_u32(rr[i].id), rr[i].metric);
 }
@@ -1119,14 +1100,13 @@ show_lsa_network(struct top_hash_entry *he)
   struct ospf_lsa_header *lsa = &(he->lsa);
   struct ospf_lsa_net *ln = he->lsa_body;
   u32 *rts = (u32 *) (ln + 1);
-  u32 max = (lsa->length - sizeof(struct ospf_lsa_header) - sizeof(struct ospf_lsa_net)) / sizeof(u32);
   u32 i;
 
   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);
 
-  for (i = 0; i < max; i++)
+  for (i = 0; i < lsa_net_count(lsa); i++)
     cli_msg(-1016, "\t\trouter %R", rts[i]);
 }
 
@@ -1168,7 +1148,7 @@ show_lsa_external(struct top_hash_entry *he)
          et->etm.metric & METRIC_MASK, str_via, str_tag);
 }
 
-
+*/
 void
 ospf_sh_state(struct proto *p, int verbose)
 {
@@ -1177,7 +1157,7 @@ ospf_sh_state(struct proto *p, int verbose)
   unsigned int i, j;
   u32 last_rt = 0xFFFFFFFF;
   u32 last_area = 0xFFFFFFFF;
-
+  /*
   if (p->proto_state != PS_UP)
   {
     cli_msg(-1016, "%s: is not up", p->name);
@@ -1240,7 +1220,7 @@ ospf_sh_state(struct proto *p, int verbose)
        break;
     }
   }
-
+  */
   cli_msg(0, "");
 }
 
index 22790899f78c86d0df823466dc6ed06fb9e46acf..1e46d3be405f5bd02ee828185ad4e39e860bcbdf 100644 (file)
@@ -49,13 +49,17 @@ do { if ((p->debug & D_PACKETS) || OSPF_FORCE_DEBUG) \
 #include "lib/string.h"
 
 #define OSPF_PROTO 89
+
 #ifndef IPV6
+#define OSPFv2 1
 #define OSPF_VERSION 2
 #define AllSPFRouters ipa_from_u32(0xe0000005) /* 224.0.0.5 */
 #define AllDRouters ipa_from_u32(0xe0000006)   /* 224.0.0.6 */
-#define DEFAULTDES ipa_from_u32(0)
 #else
-#error OSPF for IPv6 is not implemented (mail to Feela <feela@network.cz>)
+#define OSPFv3 1
+#define OSPF_VERSION 3
+#define AllSPFRouters _MI(0xFF020000, 0, 0, 5) /* FF02::5 */
+#define AllDRouters   _MI(0xFF020000, 0, 0, 6) /* FF02::6 */
 #endif
 
 
@@ -118,32 +122,37 @@ struct ospf_area_config
   list stubnet_list;
 };
 
-struct obits
-{
-#ifdef CPU_BIG_ENDIAN
-  u8 unused2:2;
-  u8 dc:1;
-  u8 ea:1;
-  u8 np:1;
-  u8 mc:1;
-  u8 e:1;
-  u8 unused1:1;
-#else
-  u8 unused1:1;
-  u8 e:1;
-  u8 mc:1;
-  u8 np:1;
-  u8 ea:1;
-  u8 dc:1;
-  u8 unused2:2;
+
+/* Option flags */
+
+#define OPT_E  0x02
+#define OPT_N  0x08
+#define OPT_DC 0x20
+
+#ifdef OSPFv2
+#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)
 #endif
-};
 
-union options
-{
-  u8 byte;
-  struct obits bit;
-};
+#ifdef OSPFv3
+#define OPT_V6 0x01
+#define OPT_R  0x10
+
+/* VEB flags are are stored together with options in 'u32 options' */
+#define OPT_RT_B  (0x01 << 24)
+#define OPT_RT_E  (0x02 << 24)
+#define OPT_RT_V  (0x04 << 24)
+#define OPT_RT_NT (0x10 << 24)
+
+#define OPT_PX_NU 0x01
+#define OPT_PX_LA 0x02
+#define OPT_PX_P  0x08
+#define OPT_PX_DN 0x10
+#endif
 
 
 struct ospf_iface
@@ -167,15 +176,26 @@ struct ospf_iface
   u16 inftransdelay;           /* The estimated number of seconds it takes to
                                   transmit a Link State Update Packet over this
                                   interface.  LSAs contained in the update */
-  u16 autype;
   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 drip;                        /* Designated router */
   u32 drid;
   ip_addr bdrip;               /* Backup DR */
   u32 bdrid;
+
+#ifdef OSPFv3
+  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
@@ -206,14 +226,19 @@ struct ospf_iface
 #define HELLOINT_D 10
 #define POLLINT_D 20
 #define DEADC_D 4
-#define WAIT_DMH 4             /* Value of Wait timer - not found it in RFC 
-                                * - using 4*HELLO
-                                */
-  struct top_hash_entry *nlsa; /* Originated net lsa */
-  int orignet;                 /* Schedule network LSA origination */
-  int fadj;                    /* Number of full adjacent neigh */
+#define WAIT_DMH 4             
+  /* Value of Wait timer - not found it in RFC * - using 4*HELLO */
+
+  struct top_hash_entry *net_lsa;      /* Originated network LSA */
+  int orignet;                         /* Schedule network LSA origination */
+#ifdef OSPFv3
+  struct top_hash_entry *link_lsa;     /* Originated link LSA */
+  int origlink;                                /* Schedule link LSA origination */
+  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 */
+  u8 priority;                         /* A router priority for DR election */
   u8 ioprob;
   u32 rxbuf;
 };
@@ -232,35 +257,17 @@ union ospf_auth
   struct ospf_md5 md5;
 };
 
-struct ospf_packet
-{
-  u8 version;
-  u8 type;
+
+/* 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 */
-  u16 length;
-  u32 routerid;
-  u32 areaid;
+
+/* Area IDs */
 #define BACKBONE 0
-  u16 checksum;
-  u16 autype;
-  union ospf_auth u;
-};
 
-struct ospf_hello_packet
-{
-  struct ospf_packet ospf_packet;
-  ip_addr netmask;
-  u16 helloint;
-  u8 options;
-  u8 priority;
-  u32 deadint;
-  ip_addr dr;
-  ip_addr bdr;
-};
 
 struct immsb
 {
@@ -282,34 +289,86 @@ union imms
   u8 byte;
   struct immsb bit;
 };
-
-struct ospf_dbdes_packet
-{
-  struct ospf_packet ospf_packet;
-  u16 iface_mtu;
-  u8 options;
-  union imms imms;             /* I, M, MS bits */
 #define DBDES_MS 1
 #define DBDES_M 2
 #define DBDES_I 4
-  u32 ddseq;
+
+
+#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 */
+
+struct ospf_packet
+{
+  u8 version;
+  u8 type;
+  u16 length;
+  u32 routerid;
+  u32 areaid;
+  u16 checksum;
+  u8 instance_id;
+  u8 zero;
 };
 
 
+#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;
+
+#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
+
+#else /* OSPFv3 */
+  u16 type;
+
+#define LSA_T_RT       0x2001
+#define LSA_T_NET      0x2002
+#define LSA_T_SUM_NET  0x2003
+#define LSA_T_SUM_RT   0x2004
+#define LSA_T_EXT      0x4005
+#define LSA_T_LINK     0x0008
+#define LSA_T_PREFIX   0x2009
+
+#define LSA_UBIT       0x8000
+
+#define LSA_SCOPE_LINK 0x0000
+#define LSA_SCOPE_AREA 0x2000
+#define LSA_SCOPE_AS   0x4000
+#define LSA_SCOPE_RES  0x6000
+#define LSA_SCOPE_MASK 0x6000
+
+#define LSA_SCOPE(lsa) ((lsa)->type & LSA_SCOPE_MASK)
+#endif
+
   u32 id;
-#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
   u32 rt;                      /* Advertising router */
   s32 sn;                      /* LS Sequence number */
 #define LSA_INITSEQNO 0x80000001
@@ -318,31 +377,18 @@ struct ospf_lsa_header
   u16 length;
 };
 
-struct vebb
-{
-#ifdef CPU_BIG_ENDIAN
-  u8 padding:5;
-  u8 v:1;
-  u8 e:1;
-  u8 b:1;
-#else
-  u8 b:1;
-  u8 e:1;
-  u8 v:1;
-  u8 padding:5;
-#endif
-};
 
-union veb
-{
-  u8 byte;
-  struct vebb bit;
-};
+#define LSART_PTP 1
+#define LSART_NET 2
+#define LSART_STUB 3
+#define LSART_VLNK 4
+
+
+#ifdef OSPFv2
 
 struct ospf_lsa_rt
 {
-  union veb veb;
-  u8 padding;
+  u16 options; /* VEB flags only */
   u16 links;
 };
 
@@ -351,37 +397,115 @@ struct ospf_lsa_rt_link
   u32 id;
   u32 data;
   u8 type;
-#define LSART_PTP 1
-#define LSART_NET 2
-#define LSART_STUB 3
-#define LSART_VLNK 4
   u8 notos;
   u16 metric;
 };
 
-struct ospf_lsa_rt_link_tos
-{                              /* Actually we ignore TOS. This is useless */
-  u8 tos;
+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_EXT_EBIT 0x80000000
+
+
+#else  /* OSPFv3 */
+
+struct ospf_lsa_rt
+{
+  u32 options;
+};
+
+struct ospf_lsa_rt_link
+{
+  u8 type;
   u8 padding;
   u16 metric;
+  u32 lif;     /* Local interface ID */
+  u32 nif;     /* Neighbor interface ID */
+  u32 id;      /* Neighbor router ID */
 };
 
 struct ospf_lsa_net
 {
-  ip_addr netmask;
+  u32 options;
+  u32 routers[];
 };
 
-struct ospf_lsa_sum
+struct ospf_lsa_sum_net
 {
-  ip_addr netmask;
+  u32 metric;
+  u32 prefix[];
 };
 
+struct ospf_lsa_sum_rt
+{
+  u32 options;
+  u32 metric;
+  u32 drid;
+};
 
 struct ospf_lsa_ext
 {
-  ip_addr netmask;
+  u32 metric;
+  u32 rest[];
+};
+
+struct ospf_lsa_link
+{
+  u32 options;
+  ip_addr lladdr;
+  u32 pxcount;
+  u32 rest[];
+};
+
+struct ospf_lsa_prefix
+{
+  u16 pxcount;
+  u16 ref_type;
+  u32 ref_id;
+  u32 ref_rt;
+  u32 rest[];
 };
 
+#define LSA_EXT_EBIT 0x4000000
+#define LSA_EXT_FBIT 0x2000000
+#define LSA_EXT_TBIT 0x1000000
+
+#endif
+
+#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)
+{
+  return (lsa->length - sizeof(struct ospf_lsa_header) - sizeof(struct ospf_lsa_net))
+    / sizeof(u32);
+}
+
+
+/*
 struct ospf_lsa_ext_etos 
 {
 #ifdef CPU_BIG_ENDIAN
@@ -397,7 +521,7 @@ struct ospf_lsa_ext_etos
 #endif
 };
 
-#define METRIC_MASK 0x00FFFFFF
+
 struct ospf_lsa_sum_tos 
 {
 #ifdef CPU_BIG_ENDIAN
@@ -430,16 +554,11 @@ struct ospf_lsa_ext_tos
   u32 tag;
 };
 
-struct ospf_lsreq_packet
-{
-  struct ospf_packet ospf_packet;
-};
+*/
 
 struct ospf_lsreq_header
 {
-  u16 padd1;
-  u8 padd2;
-  u8 type;
+  u32 type;
   u32 id;
   u32 rt;                      /* Advertising router */
 };
@@ -450,17 +569,6 @@ struct l_lsr_head
   struct ospf_lsreq_header lsh;
 };
 
-struct ospf_lsupd_packet
-{
-  struct ospf_packet ospf_packet;
-  u32 lsano;                   /* Number of LSA's */
-};
-
-struct ospf_lsack_packet
-{
-  struct ospf_packet ospf_packet;
-};
-
 
 struct ospf_neighbor
 {
@@ -484,10 +592,18 @@ struct ospf_neighbor
   u32 rid;                     /* Router ID */
   ip_addr ip;                  /* IP of it's interface */
   u8 priority;                 /* Priority */
-  u8 options;                  /* Options received */
-  ip_addr dr;                  /* Neigbour's idea of DR */
-  ip_addr bdr;                 /* Neigbour's idea of BDR */
   u8 adj;                      /* built adjacency? */
+  u32 options;                 /* Options received */
+
+  /* dr and bdr store IP address in OSPFv2 and router ID in OSPFv3,
+     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 */
   struct top_graph *lsrqh;     /* LSA graph */
@@ -535,13 +651,14 @@ struct ospf_area
   struct ospf_area_config *ac; /* Related area config */
   int origrt;                  /* Rt lsa origination scheduled? */
   struct top_hash_entry *rt;   /* My own router LSA */
+  struct top_hash_entry *pxr_lsa; /* Originated prefix LSA */
   list cand;                   /* List of candidates for RT calc. */
   struct fib net_fib;          /* Networks to advertise or not */
   int stub;
   int trcap;                   /* Transit capability? */
+  u32 options;                 /* Optional features */
   struct proto_ospf *po;
   struct fib rtr;              /* Routing tables for routers */
-  union options opt;            /* RFC2328 - A.2 */
 };
 
 struct proto_ospf
@@ -577,20 +694,28 @@ struct ospf_iface_patt
   u32 deadc;
   u32 dead;
   u32 type;
-  u32 autype;
   u32 strictnbma;
   u32 stub;
   u32 vid;
-#define OSPF_AUTH_NONE 0
-#define OSPF_AUTH_SIMPLE 1
-#define OSPF_AUTH_CRYPT 2
-#define OSPF_AUTH_CRYPT_SIZE 16
   u32 rxbuf;
 #define OSPF_RXBUF_NORMAL 0
 #define OSPF_RXBUF_LARGE 1
 #define OSPF_RXBUF_MINSIZE 256 /* Minimal allowed size */
-  list *passwords;
   list nbma_list;
+
+  u32 autype;                    /* Not really used in OSPFv3 */
+#define OSPF_AUTH_NONE 0
+#define OSPF_AUTH_SIMPLE 1
+#define OSPF_AUTH_CRYPT 2
+#define OSPF_AUTH_CRYPT_SIZE 16
+
+#ifdef OSPFv2
+  list *passwords;
+#endif
+
+#ifdef OSPFv3
+  u8 instance_id;
+#endif
 };
 
 int ospf_import_control(struct proto *p, rte **new, ea_list **attrs,
index 783d28ed453e0c8a98c09825e11cbafd652b3f15..e3a3115bf7966271fb189d68423583b22f6b0310 100644 (file)
@@ -24,21 +24,37 @@ ospf_pkt_fill_hdr(struct ospf_iface *ifa, void *buf, u8 h_type)
 
   pkt->routerid = htonl(p->cf->global->router_id);
   pkt->areaid = htonl(ifa->oa->areaid);
+
+#ifdef OSPFv3
+  pkt->instance_id = ifa->instance_id;
+#endif
+
+#ifdef OSPFv2
   pkt->autype = htons(ifa->autype);
+#endif
+
   pkt->checksum = 0;
 }
 
 unsigned
 ospf_pkt_maxsize(struct ospf_iface *ifa)
 {
+  /* For virtual links use mtu=576, can be mtu < 576? */
   unsigned mtu = (ifa->type == OSPF_IT_VLINK) ? OSPF_VLINK_MTU : ifa->iface->mtu;
-  /* Can be mtu < 576? */
+  unsigned add = 0;
+
+#ifdef OSPFv2
+  add = ((ifa->autype == OSPF_AUTH_CRYPT) ? OSPF_AUTH_CRYPT_SIZE : 0);
+#endif
+
   return ((mtu <=  ifa->iface->mtu) ? mtu : ifa->iface->mtu) -
-  SIZE_OF_IP_HEADER - ((ifa->autype == OSPF_AUTH_CRYPT) ? OSPF_AUTH_CRYPT_SIZE : 0);
-  /* For virtual links use mtu=576 */
+  SIZE_OF_IP_HEADER - add;
 }
 
-void
+
+#ifdef OSPFv2
+
+static void
 ospf_pkt_finalize(struct ospf_iface *ifa, struct ospf_packet *pkt)
 {
   struct password_item *passwd = NULL;
@@ -224,6 +240,20 @@ ospf_pkt_checkauth(struct ospf_neighbor *n, struct ospf_iface *ifa, struct ospf_
   }
 }
 
+#else
+
+/* OSPFv3 authentication not yet supported */
+
+static inline void
+ospf_pkt_finalize(struct ospf_iface *ifa, struct ospf_packet *pkt)
+{ }
+
+static int
+ospf_pkt_checkauth(struct ospf_neighbor *n, struct ospf_iface *ifa, struct ospf_packet *pkt, int size)
+{ return 1; }
+
+#endif
+
 /**
  * ospf_rx_hook
  * @sk: socket we received the packet. Its ignored.
@@ -290,6 +320,8 @@ ospf_rx_hook(sock * sk, int size)
     return 1;
   }
 
+  /* FIXME - handle checksums in OSPFv3  */ 
+#ifdef OSPFv2
   if ((ps->autype != htons(OSPF_AUTH_CRYPT)) &&
       (!ipsum_verify(ps, 16, (void *) ps + sizeof(struct ospf_packet),
                    ntohs(ps->length) - sizeof(struct ospf_packet), NULL)))
@@ -297,13 +329,23 @@ ospf_rx_hook(sock * sk, int size)
     log(L_ERR "%s%I - bad checksum", mesg, sk->faddr);
     return 1;
   }
+#endif
 
   if (ntohl(ps->areaid) != ifa->oa->areaid)
   {
-    log(L_ERR "%s%I - different area %ld", mesg, sk->faddr, ntohl(ps->areaid));
+    log(L_ERR "%s%I - different area (%u)", mesg, sk->faddr, ntohl(ps->areaid));
     return 1;
   }
 
+  /* FIXME - handling of instance id should be better */
+#ifdef OSPFv3
+  if (ps->instance_id != ifa->instance_id)
+  {
+    log(L_ERR "%s%I - different instance (%u)", mesg, sk->faddr, ps->instance_id);
+    return 1;
+  }
+#endif
+
   if (ntohl(ps->routerid) == p->cf->global->router_id)
   {
     log(L_ERR "%s%I - received my own router ID!", mesg, sk->faddr);
@@ -352,23 +394,23 @@ ospf_rx_hook(sock * sk, int size)
   {
   case HELLO_P:
     DBG("%s: Hello received.\n", p->name);
-    ospf_hello_receive((struct ospf_hello_packet *) ps, ifa, n, sk->faddr);
+    ospf_hello_receive(ps, ifa, n, sk->faddr);
     break;
   case DBDES_P:
     DBG("%s: Database description received.\n", p->name);
-    ospf_dbdes_receive((struct ospf_dbdes_packet *) ps, ifa, n);
+    ospf_dbdes_receive(ps, ifa, n);
     break;
   case LSREQ_P:
     DBG("%s: Link state request received.\n", p->name);
-    ospf_lsreq_receive((struct ospf_lsreq_packet *) ps, ifa, n);
+    ospf_lsreq_receive(ps, ifa, n);
     break;
   case LSUPD_P:
     DBG("%s: Link state update received.\n", p->name);
-    ospf_lsupd_receive((struct ospf_lsupd_packet *) ps, ifa, n);
+    ospf_lsupd_receive(ps, ifa, n);
     break;
   case LSACK_P:
     DBG("%s: Link state ack received.\n", p->name);
-    ospf_lsack_receive((struct ospf_lsack_packet *) ps, ifa, n);
+    ospf_lsack_receive(ps, ifa, n);
     break;
   default:
     log(L_ERR "%s%I - wrong type %u", mesg, sk->faddr, ps->type);
@@ -416,9 +458,14 @@ void
 ospf_send_to(sock *sk, ip_addr ip, struct ospf_iface *ifa)
 {
   struct ospf_packet *pkt = (struct ospf_packet *) sk->tbuf;
-  int len = ntohs(pkt->length) + ((ifa->autype == OSPF_AUTH_CRYPT) ? OSPF_AUTH_CRYPT_SIZE : 0);
-  ospf_pkt_finalize(ifa, pkt);
+  int len = ntohs(pkt->length);
 
+#ifdef OSPFv2
+  if (ifa->autype == OSPF_AUTH_CRYPT)
+    len += OSPF_AUTH_CRYPT_SIZE;
+#endif
+
+  ospf_pkt_finalize(ifa, pkt);
   if (sk->tbuf != sk->tpos)
     log(L_ERR "Aiee, old packet was overwritted in TX buffer");
 
index a230d38f9be6465f28ad1fcccd3f27e722c04c95..e64e68af5ebbb5dd1c64466bfac8b24265225108 100644 (file)
 
 static void
 add_cand(list * l, struct top_hash_entry *en,
-        struct top_hash_entry *par, u16 dist, struct ospf_area *oa);
+        struct top_hash_entry *par, u32 dist, struct ospf_area *oa);
 static void
 calc_next_hop(struct top_hash_entry *en,
              struct top_hash_entry *par, struct ospf_area *oa);
 static void ospf_ext_spf(struct proto_ospf *po);
 static void rt_sync(struct proto_ospf *po);
 
+/* In ospf_area->rtr we store paths to routers, but we use RID (and not IP address)
+   as index, so we need to encapsulate RID to IP addresss */
+#ifdef OSPFv2
+#define ipa_from_rid(x) _MI(x)
+#else /* OSPFv3 */
+#define ipa_from_rid(x) _MI(0,0,0,x)
+#endif
+
+
+static inline u32 *
+get_ipv6_prefix(u32 *buf, ip_addr *addr, int *pxlen, u8 *pxopts)
+{
+  u8 pxl = (*buf >> 24);
+  *pxopts = (*buf >> 16);
+  *pxlen = pxl;
+  buf++;
+
+  *addr = IPA_NONE;
+
+  if (pxl > 0)
+    _I0(*addr) = *buf++;
+  if (pxl > 32)
+    _I1(*addr) = *buf++;
+  if (pxl > 64)
+    _I2(*addr) = *buf++;
+  if (pxl > 96)
+    _I3(*addr) = *buf++;
+
+  return buf;
+}
+
+static inline u32 *
+get_ipv6_addr(u32 *buf, ip_addr *addr)
+{
+  *addr = *(ip_addr *) buf;
+  return buf + 4;
+}
+
 static void
 fill_ri(orta * orta)
 {
   orta->type = RTS_DUMMY;
-  orta->capa = 0;
+  orta->options = 0;
   orta->oa = NULL;
   orta->metric1 = LSINFINITY;
   orta->metric2 = LSINFINITY;
@@ -159,6 +197,7 @@ ospf_rt_spfa(struct ospf_area *oa)
   if (oa->rt->dist != LSINFINITY)
     bug("Aging was not processed.");
 
+  /* 16.1. (1) */
   init_list(&oa->cand);                /* Empty list of candidates */
   oa->trcap = 0;
 
@@ -183,15 +222,15 @@ ospf_rt_spfa(struct ospf_area *oa)
     switch (act->lsa.type)
     {
     case LSA_T_RT:
+      /* FIXME - in OSPFv3 we should process all RT LSAs from that router */
       rt = (struct ospf_lsa_rt *) act->lsa_body;
-      if (rt->veb.bit.v)
+      if (rt->options & OPT_RT_V)
        oa->trcap = 1;
-      if (rt->veb.bit.b || rt->veb.bit.e)
+      /* FIXME - in OSPFv3, should we add all routers, or just ABRs an ASBRs? */
+      if ((rt->options & OPT_RT_V) || (rt->options & OPT_RT_E))
       {
        nf.type = RTS_OSPF;
-       nf.capa = 0;
-        if (rt->veb.bit.b) nf.capa |= ORTA_ABR;
-        if (rt->veb.bit.e) nf.capa |= ORTA_ASBR;
+       nf.options = rt->options;
        nf.metric1 = act->dist;
        nf.metric2 = LSINFINITY;
        nf.tag = 0;
@@ -199,26 +238,27 @@ ospf_rt_spfa(struct ospf_area *oa)
        nf.ar = act;
        nf.nh = act->nh;
        nf.ifa = act->nhi;
-       ri_install(po, ipa_from_u32(act->lsa.id), 32, ORT_ROUTER, &nf, NULL);
+       ri_install(po, ipa_from_rid(act->lsa.rt), 32, ORT_ROUTER, &nf, NULL);
       }
       rr = (struct ospf_lsa_rt_link *) (rt + 1);
       DBG("  Number of links: %u\n", rt->links);
-      for (i = 0; i < rt->links; i++)
+      for (i = 0; i < lsa_rt_count(&act->lsa); i++)
       {
        tmp = NULL;
        rtl = (rr + i);
        DBG("     Working on link: %R (type: %u)  ", rtl->id, rtl->type);
        switch (rtl->type)
        {
+#ifdef OSPFv2
        case LSART_STUB:
          /*
-          * This violates rfc2328! but I hope
-          * it's also correct.
+          * This violates rfc2328! But it is mostly harmless.
+          * But it causes that the cost of the stub is ignored.
           */
          DBG("\n");
 
          nf.type = RTS_OSPF;
-         nf.capa = 0;
+         nf.options = 0;
          nf.metric1 = act->dist + rtl->metric;
          nf.metric2 = LSINFINITY;
          nf.tag = 0;
@@ -249,9 +289,14 @@ ospf_rt_spfa(struct ospf_area *oa)
          ri_install(po, ipa_from_u32(rtl->id),
                     ipa_mklen(ipa_from_u32(rtl->data)), ORT_NET, &nf, NULL);
          break;
-
+#endif
        case LSART_NET:
-         tmp = ospf_hash_find(po->gr, oa->areaid, rtl->id, rtl->id, LSA_T_NET);
+#ifdef OSPFv2
+         /* In OSPFv2, rtl->id is IP addres of DR, router ID is not known */
+         tmp = ospfxx_hash_find(po->gr, oa->areaid, rtl->id, 0, LSA_T_NET);
+#else /* OSPFv3 */
+         tmp = ospfxx_hash_find(po->gr, oa->areaid, rtl->nif, rtl->id, LSA_T_NET);
+#endif
          if (tmp == NULL)
            DBG("Not found!\n");
          else
@@ -260,7 +305,8 @@ ospf_rt_spfa(struct ospf_area *oa)
 
        case LSART_VLNK:
        case LSART_PTP:
-         tmp = ospf_hash_find(po->gr, oa->areaid, rtl->id, rtl->id, LSA_T_RT);
+         /* FIXME - in OSPFv3, find any LSA ID */
+         tmp = ospfxx_hash_find(po->gr, oa->areaid, rtl->id, rtl->id, LSA_T_RT);
          DBG("PTP found.\n");
          break;
        default:
@@ -276,7 +322,7 @@ ospf_rt_spfa(struct ospf_area *oa)
     case LSA_T_NET:
       ln = act->lsa_body;
       nf.type = RTS_OSPF;
-      nf.capa = 0;
+      nf.options = 0;
       nf.metric1 = act->dist;
       nf.metric2 = LSINFINITY;
       nf.tag = 0;
@@ -288,11 +334,11 @@ ospf_rt_spfa(struct ospf_area *oa)
                 ipa_mklen(ln->netmask), ORT_NET, &nf, NULL);
 
       rts = (u32 *) (ln + 1);
-      for (i = 0; i < (act->lsa.length - sizeof(struct ospf_lsa_header) -
-                      sizeof(struct ospf_lsa_net)) / sizeof(u32); i++)
+      for (i = 0; i < lsa_net_count(&act->lsa); i++)
       {
        DBG("     Working on router %R ", rts[i]);
-       tmp = ospf_hash_find(po->gr, oa->areaid, rts[i], rts[i], LSA_T_RT);
+       /* FIXME - in OSPFv3, find any LSA ID */
+       tmp = ospfxx_hash_find(po->gr, oa->areaid, rts[i], rts[i], LSA_T_RT);
        if (tmp != NULL)
          DBG("Found :-)\n");
        else
@@ -308,7 +354,8 @@ ospf_rt_spfa(struct ospf_area *oa)
   {
     if ((iface->type == OSPF_IT_VLINK) && (iface->voa == oa))
     {
-      if ((tmp = ospf_hash_find(po->gr, oa->areaid, iface->vid, iface->vid, LSA_T_RT)) &&
+      /* FIXME in OSPFv3, different LSAID */
+      if ((tmp = ospfxx_hash_find(po->gr, oa->areaid, iface->vid, iface->vid, LSA_T_RT)) &&
         (!ipa_equal(tmp->lb, IPA_NONE)))
       {
         if ((iface->state != OSPF_IS_PTP) || (iface->iface != tmp->nhi->iface) || (!ipa_equal(iface->vip, tmp->lb)))
@@ -348,7 +395,7 @@ link_back(struct ospf_area *oa, struct top_hash_entry *fol, struct top_hash_entr
     case LSA_T_RT:
       rt = (struct ospf_lsa_rt *) fol->lsa_body;
       rr = (struct ospf_lsa_rt_link *) (rt + 1);
-      for (i = 0; i < rt->links; i++)
+      for (i = 0; i < lsa_rt_count(&fol->lsa); i++)
       {
        rtl = (rr + i);
        switch (rtl->type)
@@ -356,7 +403,7 @@ link_back(struct ospf_area *oa, struct top_hash_entry *fol, struct top_hash_entr
        case LSART_STUB:
          break;
        case LSART_NET:
-         if (ospf_hash_find(po->gr, oa->areaid, rtl->id, rtl->id, LSA_T_NET) == pre)
+         if (ospfxx_hash_find(po->gr, oa->areaid, rtl->id, rtl->id, LSA_T_NET) == pre)
           {
             fol->lb = ipa_from_u32(rtl->data);
             return 1;
@@ -364,7 +411,7 @@ link_back(struct ospf_area *oa, struct top_hash_entry *fol, struct top_hash_entr
          break;
        case LSART_VLNK:
        case LSART_PTP:
-         if (ospf_hash_find(po->gr, oa->areaid, rtl->id, rtl->id, LSA_T_RT) == pre)
+         if (ospfxx_hash_find(po->gr, oa->areaid, rtl->id, rtl->id, LSA_T_RT) == pre)
           {
             fol->lb = ipa_from_u32(rtl->data);
             return 1;
@@ -379,10 +426,9 @@ link_back(struct ospf_area *oa, struct top_hash_entry *fol, struct top_hash_entr
     case LSA_T_NET:
       ln = fol->lsa_body;
       rts = (u32 *) (ln + 1);
-      for (i = 0; i < (fol->lsa.length - sizeof(struct ospf_lsa_header) -
-                      sizeof(struct ospf_lsa_net)) / sizeof(u32); i++)
+      for (i = 0; i < lsa_net_count(&fol->lsa); i++)
       {
-       if (ospf_hash_find(po->gr, oa->areaid, *(rts + i), *(rts + i), LSA_T_RT) == pre)
+       if (ospfxx_hash_find(po->gr, oa->areaid, *(rts + i), *(rts + i), LSA_T_RT) == pre)
         {
           return 1;
         }
@@ -400,10 +446,10 @@ ospf_rt_sum_tr(struct ospf_area *oa)
   struct proto *p = &oa->po->proto;
   struct proto_ospf *po = oa->po;
   struct ospf_area *bb = po->backbone;
-  ip_addr *mask, ip, abrip;
+  ip_addr ip, abrip;
   struct top_hash_entry *en;
-  int mlen = -1, type = -1;
-  union ospf_lsa_sum_tm *tm;
+  u32 dst_rid, metric, options;
+  int pxlen = -1, type = -1;
   ort *re = NULL, *abr;
   orta nf;
 
@@ -411,57 +457,80 @@ ospf_rt_sum_tr(struct ospf_area *oa)
 
   WALK_SLIST(en, po->lsal)
   {
-    if (en->oa != oa)
+    if ((en->lsa.type != LSA_T_SUM_RT) && (en->lsa.type != LSA_T_SUM_NET))
       continue;
+
+    if (en->domain != oa->areaid)
+      continue;
+
     if (en->lsa.age == LSA_MAXAGE)
       continue;
+
     if (en->dist == LSINFINITY)
       continue;
 
     if (en->lsa.rt == p->cf->global->router_id)
       continue;
 
-    if ((en->lsa.type != LSA_T_SUM_RT) && (en->lsa.type != LSA_T_SUM_NET))
-      continue;
-
-    mask = (ip_addr *)en->lsa_body;
 
     if (en->lsa.type == LSA_T_SUM_NET)
     {
-      mlen = ipa_mklen(*mask);
-      ip = ipa_and(ipa_from_u32(en->lsa.id), *mask);
+#ifdef OSPFv2
+      struct ospf_lsa_sum *ls = en->lsa_body;
+      pxlen = ipa_mklen(ls->netmask);
+      ip = ipa_and(ipa_from_u32(en->lsa.id), ls->netmask);
+#else /* OSPFv3 */
+      u8 pxopts;
+      struct ospf_lsa_sum_net *ls = en->lsa_body;
+      get_ipv6_prefix(ls->prefix, &ip, &pxlen, &pxopts);
+      if (pxopts & OPT_PX_NU)
+       continue;
+#endif
+
+      metric = ls->metric & METRIC_MASK;
+      options = 0;
       type = ORT_NET;
-      re = (ort *) fib_find(&po->rtf, &ip, 32);
+      re = (ort *) fib_find(&po->rtf, &ip, pxlen);
     }
-
-    if (en->lsa.type == LSA_T_SUM_RT)
+    else if (en->lsa.type == LSA_T_SUM_RT)
     {
-      ip = ipa_from_u32(en->lsa.id);
-      mlen = 32;
+#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
+
+      ip = ipa_from_rid(dst_rid);
+      pxlen = 32;
+      metric = ls->metric & METRIC_MASK;
+      options |= ORTA_ASBR;
       type = ORT_ROUTER;
-      re = (ort *) fib_find(&bb->rtr, &ip, 32);
+      re = (ort *) fib_find(&bb->rtr, &ip, pxlen);
     }
+
     if (!re) continue;
     if (re->n.oa->areaid != 0) continue;
     if ((re->n.type != RTS_OSPF) && (re->n.type != RTS_OSPF_IA)) continue;
 
-    abrip = ipa_from_u32(en->lsa.rt);
+    abrip = ipa_from_rid(en->lsa.rt);
 
     abr = fib_find(&oa->rtr, &abrip, 32);
     if (!abr) continue;
 
-    tm = (union ospf_lsa_sum_tm *)(mask + 1);
-
     nf.type = re->n.type;
-    nf.capa = ORTA_ASBR;
-    nf.metric1 = abr->n.metric1 + (tm->metric & METRIC_MASK);
+    nf.options = options;
+    nf.metric1 = abr->n.metric1 + metric;
     nf.metric2 = LSINFINITY;
     nf.tag = 0;
     nf.oa = oa;
     nf.ar = abr->n.ar;
     nf.nh = abr->n.nh;
     nf.ifa = abr->n.ifa;
-    ri_install(po, ip, mlen, type, &nf, NULL);
+    ri_install(po, ip, pxlen, type, &nf, NULL);
   }
 }
   
@@ -472,76 +541,103 @@ 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 *mask, ip, abrip;    /* abrIP is actually ID */
+  ip_addr ip, abrip;   /* abrIP is actually ID */
+  u32 dst_rid, metric, options;
   struct area_net *anet;
   orta nf;
   ort *abr;
-  int mlen = -1, type = -1;
-  union ospf_lsa_sum_tm *tm;
+  int pxlen = -1, type = -1;
 
   OSPF_TRACE(D_EVENTS, "Starting routing table calculation for inter-area (area %R)", oa->areaid);
 
   WALK_SLIST(en, po->lsal)
   {
-    if (en->oa != oa)
+    if ((en->lsa.type != LSA_T_SUM_RT) && (en->lsa.type != LSA_T_SUM_NET))
+      continue;
+
+    if (en->domain != oa->areaid)
       continue;
+
     /* Page 169 (1) */
     if (en->lsa.age == LSA_MAXAGE)
       continue;
+
     /* Page 169 (2) */
     if (en->lsa.rt == p->cf->global->router_id)
       continue;
 
-    if ((en->lsa.type != LSA_T_SUM_RT) && (en->lsa.type != LSA_T_SUM_NET))
-      continue;
-
-    mask = (ip_addr *)en->lsa_body;
-    tm = (union ospf_lsa_sum_tm *)(mask + 1);
-
-    if ((tm->metric & METRIC_MASK) == LSINFINITY)
-      continue;
 
     if (en->lsa.type == LSA_T_SUM_NET)
     {
       struct ospf_area *oaa;
       int skip = 0;
-      mlen = ipa_mklen(*mask);
-      ip = ipa_and(ipa_from_u32(en->lsa.id), *mask);
+
+#ifdef OSPFv2
+      struct ospf_lsa_sum *ls = en->lsa_body;
+      pxlen = ipa_mklen(ls->netmask);
+      ip = ipa_and(ipa_from_u32(en->lsa.id), ls->netmask);
+#else /* OSPFv3 */
+      u8 pxopts;
+      struct ospf_lsa_sum_net *ls = en->lsa_body;
+      get_ipv6_prefix(ls->prefix, &ip, &pxlen, &pxopts);
+      if (pxopts & OPT_PX_NU)
+       continue;
+#endif
+
+      metric = ls->metric & METRIC_MASK;
+      options = 0;
+      type = ORT_NET;
+
       /* Page 169 (3) */
       WALK_LIST(oaa, po->area_list)
       {
-        if ((anet = fib_find(&oaa->net_fib, &ip, mlen)) && anet->active)
+        if ((anet = fib_find(&oaa->net_fib, &ip, pxlen)) && anet->active)
        {
          skip = 1;
          break;
        }
       }
       if (skip) continue;
-
-      type = ORT_NET;
     }
     else
     {
-      ip = ipa_from_u32(en->lsa.id);
-      mlen = 32;
+#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
+
+      ip = ipa_from_rid(dst_rid);
+      pxlen = 32;
+      metric = ls->metric & METRIC_MASK;
+      options |= ORTA_ASBR;
       type = ORT_ROUTER;
     }
-    abrip = ipa_from_u32(en->lsa.rt);
 
+    /* Page 169 (1) */
+    if (metric == LSINFINITY)
+      continue;
+
+    /* Page 169 (4) */
+    abrip = ipa_from_rid(en->lsa.rt);
     if (!(abr = (ort *) fib_find(&oa->rtr, &abrip, 32))) continue;
     if (abr->n.metric1 == LSINFINITY) continue;
-    if (!(abr->n.capa & ORTA_ABR)) continue;
+    if (!(abr->n.options & ORTA_ABR)) continue;
 
     nf.type = RTS_OSPF_IA;
-    nf.capa = ORTA_ASBR;
-    nf.metric1 = abr->n.metric1 + (tm->metric & METRIC_MASK);
+    nf.options = options;
+    nf.metric1 = abr->n.metric1 + metric;
     nf.metric2 = LSINFINITY;
     nf.tag = 0;
     nf.oa = oa;
     nf.ar = abr->n.ar;
     nf.nh = abr->n.nh;
     nf.ifa = abr->n.ifa;
-    ri_install(po, ip, mlen, type, &nf, NULL);
+    ri_install(po, ip, pxlen, type, &nf, NULL);
   }
 }
 
@@ -567,7 +663,7 @@ ospf_rt_spf(struct proto_ospf *po)
 
   OSPF_TRACE(D_EVENTS, "Starting routing table calculation");
 
-  /* Invalidate old routing table */
+  /* 16. (1) - Invalidate old routing table */
   FIB_WALK(&po->rtf, nftmp)
   {
     ri = (ort *) nftmp;
@@ -594,9 +690,12 @@ ospf_rt_spf(struct proto_ospf *po)
       anet->metric = 1;
     }
     FIB_WALK_END;
+
+    /* 16. (2) */
     ospf_rt_spfa(oa);
   }
 
+  /* 16. (3) */
   if ((po->areano == 1) || (!po->backbone))
   {
     ospf_rt_sum(HEAD(po->area_list));
@@ -606,6 +705,7 @@ ospf_rt_spf(struct proto_ospf *po)
     ospf_rt_sum(po->backbone);
   }
 
+  /* 16. (4) */
   WALK_LIST(oa, po->area_list)
   {
     if (oa->trcap && (oa->areaid != 0))
@@ -615,6 +715,7 @@ ospf_rt_spf(struct proto_ospf *po)
     }
   }
 
+  /* 16. (5) */
   ospf_ext_spf(po);
 
   rt_sync(po);
@@ -622,13 +723,12 @@ ospf_rt_spf(struct proto_ospf *po)
   po->calcrt = 0;
 }
 
-
 /**
  * ospf_ext_spf - calculate external paths
  * @po: protocol
  *
  * After routing table for any area is calculated, calculation of external
- * path is invoked. This process is described in 16.6 of RFC 2328.
+ * path is invoked. This process is described in 16.4 of RFC 2328.
  * Inter- and Intra-area paths are always prefered over externals.
  */
 static void
@@ -639,50 +739,75 @@ ospf_ext_spf(struct proto_ospf *po)
   struct top_hash_entry *en;
   struct proto *p = &po->proto;
   struct ospf_lsa_ext *le;
-  struct ospf_lsa_ext_tos *lt;
-  int mlen;
-  ip_addr ip, nh, rtid;
+  int pxlen, ebit, rt_fwaddr_valid;
+  ip_addr ip, nh, rtid, rt_fwaddr;
   struct ospf_iface *nhi = NULL;
-  int met1, met2;
+  u32 br_metric, rt_metric, rt_tag;
   neighbor *nn;
   struct ospf_area *atmp;
 
-
   OSPF_TRACE(D_EVENTS, "Starting routing table calculation for ext routes");
 
   WALK_SLIST(en, po->lsal)
   {
+    /* 16.4. (1) */
     if (en->lsa.type != LSA_T_EXT)
       continue;
     if (en->lsa.age == LSA_MAXAGE)
       continue;
+
+    /* 16.4. (2) */
     if (en->lsa.rt == p->cf->global->router_id)
       continue;
 
-    le = en->lsa_body;
-    lt = (struct ospf_lsa_ext_tos *) (le + 1);
-
     DBG("%s: Working on LSA. ID: %R, RT: %R, Type: %u, Mask %I\n",
        p->name, en->lsa.id, en->lsa.rt, en->lsa.type, le->netmask);
 
-    if ((lt->etm.metric & METRIC_MASK) == LSINFINITY)
+    le = en->lsa_body;
+
+    rt_metric = le->metric & METRIC_MASK;
+    ebit = le->metric & LSA_EXT_EBIT;
+
+    if (rt_metric == LSINFINITY)
       continue;
+
+#ifdef OSPFv2
     ip = ipa_and(ipa_from_u32(en->lsa.id), le->netmask);
-    mlen = ipa_mklen(le->netmask);
-    if ((mlen < 0) || (mlen > 32))
+    pxlen = ipa_mklen(le->netmask);
+    rt_fwaddr = le->fwaddr;
+    rt_fwaddr_valid = !ipa_equal(rt_fwaddr, IPA_NONE);
+    rt_tag = le->tag;
+#else /* OSPFv3 */
+    u8 pxopts;
+    u32 *buf = le->rest;
+    buf = get_ipv6_prefix(buf, &ip, &pxlen, &pxopts);
+
+    if (pxopts & OPT_PX_NU)
+      continue;
+
+    rt_fwaddr_valid = le->metric & LSA_EXT_FBIT;
+    if (rt_fwaddr_valid)
+      buf = get_ipv6_addr(buf, &rt_fwaddr);
+    else 
+      rt_fwaddr = IPA_NONE;
+
+    if (le->metric & LSA_EXT_TBIT)
+      rt_tag = *buf++;
+    else
+      rt_tag = 0;
+#endif
+
+    if (pxlen < 0)
     {
-      log("%s: Invalid mask in LSA. ID: %R, RT: %R, Type: %u, Mask %I",
-         p->name, en->lsa.id, en->lsa.rt, en->lsa.type, le->netmask);
+      log("%s: Invalid mask in LSA. ID: %R, RT: %R, Type: %u",
+         p->name, en->lsa.id, en->lsa.rt, en->lsa.type);
       continue;
     }
     nhi = NULL;
     nh = IPA_NONE;
 
-    met1 = LSINFINITY;
-    met2 = LSINFINITY;
-
-    rtid = ipa_from_u32(en->lsa.rt);
-
+    /* 16.4. (3) */
+    rtid = ipa_from_rid(en->lsa.rt);
     nf1 = NULL;
     WALK_LIST(atmp, po->area_list)
     {
@@ -698,50 +823,30 @@ ospf_ext_spf(struct proto_ospf *po)
     if (nf1->n.metric1 == LSINFINITY)
       continue;                        /* distance is INF */
 
-    if (!(nf1->n.capa & ORTA_ASBR))
+    if (!(nf1->n.options & ORTA_ASBR))
       continue;                        /* It is not ASBR */
 
-    if (ipa_equal(lt->fwaddr, IPA_NONE))
+    if (!rt_fwaddr_valid)
     {
-      if (lt->etm.etos.ebit)
-      {                                /* FW address == 0 */
-       met1 = nf1->n.metric1;
-       met2 = (lt->etm.metric & METRIC_MASK);
-      }
-      else
-      {
-       met1 = nf1->n.metric1 + (lt->etm.metric & METRIC_MASK);
-       met2 = LSINFINITY;
-      }
-
       nh = nf1->n.nh;
       nhi = nf1->n.ifa;
       nfh = nf1;
+      br_metric = nf1->n.metric1;
     }
     else
-    {                          /* FW address !=0 */
-      nf2 = fib_route(&po->rtf, lt->fwaddr, 32);
+    {
+      nf2 = fib_route(&po->rtf, rt_fwaddr, 32);
 
       if (!nf2)
       {
-       DBG("Cannot find network route (GW=%I)\n", lt->fwaddr);
+       DBG("Cannot find network route (GW=%I)\n", rt_fwaddr);
        continue;
       }
 
-      if (lt->etm.etos.ebit)
-      {
-       met1 = nf2->n.metric1;
-       met2 = (lt->etm.metric & METRIC_MASK);
-      }
-      else
-      {
-       met1 = nf2->n.metric1 + (lt->etm.metric & METRIC_MASK);
-       met2 = LSINFINITY;
-      }
 
-      if ((nn = neigh_find(p, &lt->fwaddr, 0)) != NULL)
+      if ((nn = neigh_find(p, &rt_fwaddr, 0)) != NULL)
       {
-       nh = lt->fwaddr;
+       nh = rt_fwaddr;
        nhi = ospf_iface_find(po, nn->iface);
       }
       else
@@ -750,20 +855,31 @@ ospf_ext_spf(struct proto_ospf *po)
        nhi = nf2->n.ifa;
       }
 
-      if (nf2->n.metric1 == LSINFINITY)
+      br_metric = nf2->n.metric1;
+      if (br_metric == LSINFINITY)
         continue;                      /* distance is INF */
     }
 
-    nfa.type = (met2 == LSINFINITY) ? RTS_OSPF_EXT1 : RTS_OSPF_EXT2;
-    nfa.capa = 0;
-    nfa.metric1 = met1;
-    nfa.metric2 = met2;
-    nfa.tag = lt->tag;
+    if (ebit)
+    {
+      nfa.type = RTS_OSPF_EXT2;
+      nfa.metric1 = br_metric;
+      nfa.metric2 = rt_metric;
+    }
+    else
+    {
+      nfa.type = RTS_OSPF_EXT1;
+      nfa.metric1 = br_metric + rt_metric;
+      nfa.metric2 = LSINFINITY;
+    }
+
+    nfa.options = 0;
+    nfa.tag = rt_tag;
     nfa.oa = (po->backbone == NULL) ? HEAD(po->area_list) : po->backbone;
     nfa.ar = nf1->n.ar;
     nfa.nh = nh;
     nfa.ifa = nhi;
-    ri_install(po, ip, mlen, ORT_NET, &nfa, nfh);
+    ri_install(po, ip, pxlen, ORT_NET, &nfa, nfh);
   }
 
 }
@@ -771,7 +887,7 @@ ospf_ext_spf(struct proto_ospf *po)
 /* Add LSA into list of candidates in Dijkstra's algorithm */
 static void
 add_cand(list * l, struct top_hash_entry *en, struct top_hash_entry *par,
-        u16 dist, struct ospf_area *oa)
+        u32 dist, struct ospf_area *oa)
 {
   node *prev, *n;
   int added = 0;
@@ -782,9 +898,11 @@ add_cand(list * l, struct top_hash_entry *en, struct top_hash_entry *par,
   if (en->lsa.age == LSA_MAXAGE)
     return;
 
+  /* 16.1. (2c) */
   if (en->color == INSPF)
     return;
 
+  /* 16.1. (2d) */
   if (dist >= en->dist)
     return;
   /*
@@ -826,6 +944,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_NET)))
+      /* FIXME - shouldn't be here LSA_T_RT ??? */
       {
        if (prev == NULL)
          add_head(l, &en->cn);
@@ -854,6 +973,7 @@ calc_next_hop(struct top_hash_entry *en, struct top_hash_entry *par,
   struct ospf_iface *ifa;
   u32 myrid = p->cf->global->router_id;
 
+  /* 16.1.1. The next hop calculation */
   DBG("     Next hop called.\n");
   if (ipa_equal(par->nh, IPA_NONE))
   {
@@ -861,6 +981,7 @@ calc_next_hop(struct top_hash_entry *en, struct top_hash_entry *par,
     DBG("     Next hop calculating for id: %R rt: %R type: %u\n",
        en->lsa.id, en->lsa.rt, en->lsa.type);
 
+    /* The parent vertex is the root */
     if (par == oa->rt)
     {
       if (en->lsa.type == LSA_T_NET)
@@ -898,6 +1019,9 @@ calc_next_hop(struct top_hash_entry *en, struct top_hash_entry *par,
        return;
       }
     }
+
+    /* The parent vertex is a network that directly connects the
+       calculating router to the destination router. */
     if (par->lsa.type == LSA_T_NET)
     {
       if (en->lsa.type == LSA_T_NET)
@@ -973,7 +1097,8 @@ again1:
         {
           if ((ifa->type == OSPF_IT_VLINK) && ipa_equal(ifa->vip, nf->n.nh))
           {
-            if ((en = ospf_hash_find(po->gr, ifa->voa->areaid, ifa->vid, ifa->vid, LSA_T_RT))
+           /* FIXME in OSPFv3, may be different LSA ID */
+            if ((en = ospfxx_hash_find(po->gr, ifa->voa->areaid, ifa->vid, ifa->vid, LSA_T_RT))
              && (!ipa_equal(en->nh, IPA_NONE)))
             {
               a0.gw = en->nh;
@@ -1054,7 +1179,7 @@ again2:
        if (oaa->stub) fl = 1;
 
         if (fl) flush_sum_lsa(oaa, &anet->fn, ORT_NET);
-        else originate_sum_lsa(oaa, &anet->fn, ORT_NET, anet->metric);
+        else originate_sum_lsa(oaa, &anet->fn, ORT_NET, anet->metric, 0);
       }
     }
     FIB_WALK_END;
@@ -1067,7 +1192,7 @@ again2:
 
       fnn.prefix = IPA_NONE;
       fnn.pxlen = 0;
-      if (oa->stub) originate_sum_lsa(oa, &fnn, ORT_NET, oa->stub);
+      if (oa->stub) originate_sum_lsa(oa, &fnn, ORT_NET, oa->stub, 0);
       else flush_sum_lsa(oa, &fnn, ORT_NET);
     }
   }
index acb0a1ac88361c6c0feb95691186b7b6052e8278..d4b85ae26a83b82564ac949433e9981165c2f2e5 100644 (file)
 typedef struct orta
 {
   int type;
-  int capa;
-#define ORTA_ASBR 1
-#define ORTA_ABR 2
+  u32 options;                 
+  /* router-LSA style options (for ORT_ROUTER), with V,E,B bits.
+     In OSPFv2, ASBRs from another areas (that we know from rt-summary-lsa),
+     have just ORTA_ASBR in options, their real options are unknown */
+#define ORTA_ASBR OPT_RT_E
+#define ORTA_ABR  OPT_RT_V
   struct ospf_area *oa;
   u32 metric1;
   u32 metric2;
index 5d8c7a9df51ed476a463b874756231423835a89e..21627f05943263826b65343906f83209072b112b 100644 (file)
@@ -20,8 +20,6 @@
 #define HASH_LO_STEP 2
 #define HASH_LO_MIN 8
 
-int ptp_unnumbered_stub_lsa = 0;
-
 static void *
 lsab_alloc(struct proto_ospf *po, unsigned size)
 {
@@ -52,6 +50,50 @@ lsab_flush(struct proto_ospf *po)
   return r;
 }
 
+static inline void *
+lsab_offset(struct proto_ospf *po, unsigned offset)
+{
+  return ((byte *) po->lsab) + offset;
+}
+
+static inline void *
+lsab_end(struct proto_ospf *po)
+{
+  return ((byte *) po->lsab) + po->lsab_used;
+}
+
+#ifdef OSPFv3
+
+#define IPV6_PREFIX_SPACE(x) ((((x) + 63) / 32) * 4)
+#define IPV6_PREFIX_WORDS(x) (((x) + 63) / 32)
+
+static inline u32 *
+put_ipv6_prefix(u32 *buf, ip_addr addr, u8 pxlen, u8 pxopts, u16 lh)
+{
+  *buf++ = ((pxlen << 24) | (pxopts << 16) | lh);
+
+  if (pxlen > 0)
+    *buf++ = _I0(addr);
+  if (pxlen > 32)
+    *buf++ = _I1(addr);
+  if (pxlen > 64)
+    *buf++ = _I2(addr);
+  if (pxlen > 96)
+    *buf++ = _I3(addr);
+  return buf;
+}
+
+
+static inline u32 *
+put_ipv6_addr(u32 *buf, ip_addr addr)
+{
+  *(ip_addr *) buf = addr;
+  return buf + 4;
+}
+
+#endif
+
+
 static int
 configured_stubnet(struct ospf_area *oa, struct ifa *a)
 {
@@ -72,12 +114,38 @@ configured_stubnet(struct ospf_area *oa, struct ifa *a)
   return 0;
 }
 
+int
+bcast_net_active(struct ospf_iface *ifa)
+{
+  struct ospf_neighbor *neigh;
+
+  if (ifa->state == OSPF_IS_WAITING)
+    return 0;
+
+  WALK_LIST(neigh, ifa->neigh_list)
+    {
+      if (neigh->state == NEIGHBOR_FULL)
+       {
+         if (neigh->rid == ifa->drid)
+           return 1;
+
+         if (ifa->state == OSPF_IS_DR)
+           return 1;
+       }
+    }
+
+  return 0;
+}
+
+
+#ifdef OSPFv2
+
 static void *
-originate_rt_lsa_body(struct ospf_area *oa, u16 * length)
+originate_rt_lsa_body(struct ospf_area *oa, u16 *length)
 {
   struct proto_ospf *po = oa->po;
   struct ospf_iface *ifa;
-  int i = 0, j = 0, k = 0, bitv = 0;
+  int i = 0, bitv = 0;
   struct ospf_lsa_rt *rt;
   struct ospf_lsa_rt_link *ln;
   struct ospf_neighbor *neigh;
@@ -87,10 +155,15 @@ originate_rt_lsa_body(struct ospf_area *oa, u16 * length)
     
   ASSERT(po->lsab_used == 0);
   rt = lsab_allocz(po, sizeof(struct ospf_lsa_rt));
+
+  rt->options = 0
+
   if (po->areano > 1)
-    rt->veb.bit.b = 1;
+    rt->options |= OPT_RT_B;
+
   if ((po->ebit) && (!oa->stub))
-    rt->veb.bit.e = 1;
+    rt->options |= OPT_RT_E;
+
   rt = NULL; /* buffer might be reallocated later */
 
   WALK_LIST(ifa, po->iface_list)
@@ -131,19 +204,7 @@ originate_rt_lsa_body(struct ospf_area *oa, u16 * length)
 
       case OSPF_IT_BCAST: /* RFC2328 - 12.4.1.2 */
       case OSPF_IT_NBMA:
-       if (ifa->state == OSPF_IS_WAITING)
-         break;
-
-       j = 0, k = 0;
-       WALK_LIST(neigh, ifa->neigh_list)
-         {
-           if ((neigh->rid == ifa->drid) && (neigh->state == NEIGHBOR_FULL))
-             k = 1;
-           if (neigh->state == NEIGHBOR_FULL)
-             j = 1;
-         }
-
-       if (((ifa->state == OSPF_IS_DR) && (j == 1)) || (k == 1))
+       if (bcast_net_active(ifa))
          {
            ln = lsab_alloc(po, sizeof(struct ospf_lsa_rt_link));
            ln->type = LSART_NET;
@@ -212,11 +273,108 @@ originate_rt_lsa_body(struct ospf_area *oa, u16 * length)
 
   rt = po->lsab;
   rt->links = i;
-  rt->veb.bit.v = bitv;
+
+  if (bitv) 
+    rt->options |= OPT_RT_V;
+
   *length = po->lsab_used + sizeof(struct ospf_lsa_header);
   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)
+{
+  struct ospf_lsa_rt_link *ln = lsab_alloc(po, sizeof(struct ospf_lsa_rt_link));
+  ln->type = type;
+  ln->padding = 0;
+  ln->metric = ifa->cost;
+  ln->lif = ifa->iface->index;
+  ln->nif = nif;
+  ln->id = id;
+}
+
+static void *
+originate_rt_lsa_body(struct ospf_area *oa, u16 *length)
+{
+  struct proto_ospf *po = oa->po;
+  struct ospf_iface *ifa;
+  int i = 0, j = 0, k = 0, bitv = 0;
+  struct ospf_lsa_rt *rt;
+  struct ospf_neighbor *neigh;
+
+  DBG("%s: Originating RT_lsa body for area %R.\n", po->proto.name,
+      oa->areaid);
+  
+  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->ebit) && (!oa->stub))
+    rt->options |= OPT_RT_E;
+
+  rt = NULL; /* buffer might be reallocated later */
+
+  WALK_LIST(ifa, po->iface_list)
+  {
+    if ((ifa->type == OSPF_IT_VLINK) && (ifa->voa == oa) &&
+       (!EMPTY_LIST(ifa->neigh_list)))
+    {
+      neigh = (struct ospf_neighbor *) HEAD(ifa->neigh_list);
+      if ((neigh->state == NEIGHBOR_FULL) && (ifa->cost <= 0xffff))
+       bitv = 1;
+    }
+
+    if ((ifa->oa != oa) || (ifa->state == OSPF_IS_DOWN))
+      continue;
+
+    /* BIRD does not support interface loops */
+    ASSERT(ifa->state != OSPF_IS_LOOP);
+
+    /* RFC5340 - 4.4.3.2 */
+    switch (ifa->type)
+      {
+      case OSPF_IT_PTP:
+       neigh = (struct ospf_neighbor *) HEAD(ifa->neigh_list);
+       if ((!EMPTY_LIST(ifa->neigh_list)) && (neigh->state == NEIGHBOR_FULL))
+         add_lsa_rt_link(po, ifa, LSART_PTP, neigh->iface_id, neigh->rid);
+       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);
+       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);
+        break;
+
+      default:
+        log("Unknown interface type %s", ifa->iface->name);
+        break;
+      }
+  }
+
+  if (bitv)
+    {
+      rt = po->lsab;
+      rt->options |= OPT_RT_V;
+    }
+
+  *length = po->lsab_used + sizeof(struct ospf_lsa_header);
+  return lsab_flush(po);
+}
+
+#endif
+
 /**
  * originate_rt_lsa - build new instance of router LSA
  * @oa: ospf_area which is LSA built to
@@ -247,53 +405,72 @@ originate_rt_lsa(struct ospf_area *oa)
   OSPF_TRACE(D_EVENTS, "Originating RT_lsa for area %R.", oa->areaid);
 
   lsa.age = 0;
-  lsa.id = rtid;
   lsa.type = LSA_T_RT;
+  
+#ifdef OSPFv2
+  lsa.options = oa->options;
+#endif
+  
+  lsa.id = rtid;
   lsa.rt = rtid;
-  lsa.options = oa->opt.byte;
-  if (oa->rt == NULL)
-  {
-    lsa.sn = LSA_INITSEQNO;
-  }
-  else
-  {
-    lsa.sn = oa->rt->lsa.sn + 1;
-  }
+  lsa.sn = oa->rt ? (oa->rt->lsa.sn + 1) : LSA_INITSEQNO;
+  u32 dom = oa->areaid;
+
   body = originate_rt_lsa_body(oa, &lsa.length);
   lsasum_calculate(&lsa, body);
-  en = lsa_install_new(&lsa, body, oa);
+  en = lsa_install_new(po, &lsa, dom, body);
   oa->rt = en;
-  ospf_lsupd_flood(NULL, NULL, &oa->rt->lsa, NULL, oa, 1);
+  ospf_lsupd_flood(po, NULL, NULL, &oa->rt->lsa, dom, 1);
   schedule_rtcalc(po);
   oa->origrt = 0;
 }
 
 static void *
-originate_net_lsa_body(struct ospf_iface *ifa, u16 * length,
+originate_net_lsa_body(struct ospf_iface *ifa, u16 *length,
                       struct proto_ospf *po)
 {
   u16 i = 1;
   struct ospf_neighbor *n;
-  u32 *body;
   struct ospf_lsa_net *net;
+  int nodes = ifa->fadj + 1;
+
+  net = mb_alloc(po->proto.pool, sizeof(struct ospf_lsa_net)
+                + nodes * sizeof(u32));
 
-  net = mb_alloc(po->proto.pool, sizeof(u32) * (ifa->fadj + 1) +
-                sizeof(struct ospf_lsa_net));
+#ifdef OSPFv2
   net->netmask = ipa_mkmask(ifa->iface->addr->pxlen);
+#endif
+
+#ifdef OSPFv3
+  /* In OSPFv3, we would like to merge options from Link LSAs of added neighbors */
+  struct top_hash_entry *en;
+  u32 options = 0;
+#endif
+
+  net->routers[0] = po->proto.cf->global->router_id;
 
-  body = (u32 *) (net + 1);
-  i = 1;
-  *body = po->proto.cf->global->router_id;
   WALK_LIST(n, ifa->neigh_list)
   {
     if (n->state == NEIGHBOR_FULL)
     {
-      *(body + i) = n->rid;
+#ifdef OSPFv3
+      en = ospfxx_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++;
     }
   }
-  *length = i * sizeof(u32) + sizeof(struct ospf_lsa_header) +
-    sizeof(struct ospf_lsa_net);
+  ASSERT(i == nodes);
+
+#ifdef OSPFv3
+  net->options = options & OPTIONS_MASK;
+#endif
+  
+  *length = sizeof(struct ospf_lsa_header) + sizeof(struct ospf_lsa_net)
+    + nodes * sizeof(u32);
   return net;
 }
 
@@ -312,10 +489,11 @@ originate_net_lsa(struct ospf_iface *ifa)
   struct proto_ospf *po = ifa->oa->po;
   struct ospf_lsa_header lsa;
   u32 rtid = po->proto.cf->global->router_id;
+  u32 dom = ifa->oa->areaid;
   struct proto *p = &po->proto;
   void *body;
 
-  if (ifa->nlsa && ((ifa->nlsa->inst_t + MINLSINTERVAL) > now))
+  if (ifa->net_lsa && ((ifa->net_lsa->inst_t + MINLSINTERVAL) > now))
     return;
   /*
    * It's too early to originate new network LSA. We will
@@ -324,22 +502,22 @@ originate_net_lsa(struct ospf_iface *ifa)
 
   if ((ifa->state != OSPF_IS_DR) || (ifa->fadj == 0))
   {
-    if (ifa->nlsa == NULL)
+    if (ifa->net_lsa == NULL)
       return;
 
     OSPF_TRACE(D_EVENTS, "Deleting Net lsa for iface \"%s\".",
               ifa->iface->name);
-    ifa->nlsa->lsa.sn += 1;
-    ifa->nlsa->lsa.age = LSA_MAXAGE;
-    lsasum_calculate(&ifa->nlsa->lsa, ifa->nlsa->lsa_body);
-    ospf_lsupd_flood(NULL, NULL, &ifa->nlsa->lsa, NULL, ifa->oa, 0);
-    s_rem_node(SNODE ifa->nlsa);
-    if (ifa->nlsa->lsa_body != NULL)
-      mb_free(ifa->nlsa->lsa_body);
-    ifa->nlsa->lsa_body = NULL;
-    ospf_hash_delete(po->gr, ifa->nlsa);
+    ifa->net_lsa->lsa.sn += 1;
+    ifa->net_lsa->lsa.age = LSA_MAXAGE;
+    lsasum_calculate(&ifa->net_lsa->lsa, ifa->net_lsa->lsa_body);
+    ospf_lsupd_flood(po, NULL, NULL, &ifa->net_lsa->lsa, dom, 0);
+    s_rem_node(SNODE ifa->net_lsa);
+    if (ifa->net_lsa->lsa_body != NULL)
+      mb_free(ifa->net_lsa->lsa_body);
+    ifa->net_lsa->lsa_body = NULL;
+    ospf_hash_delete(po->gr, ifa->net_lsa);
     schedule_rtcalc(po);
-    ifa->nlsa = NULL;
+    ifa->net_lsa = NULL;
     return;
   }
 
@@ -347,209 +525,173 @@ originate_net_lsa(struct ospf_iface *ifa)
             ifa->iface->name);
 
   lsa.age = 0;
-  lsa.id = ipa_to_u32(ifa->iface->addr->ip);
   lsa.type = LSA_T_NET;
+
+#ifdef OSPFv2
+  lsa.options = ifa->oa->options;
+  lsa.id = ipa_to_u32(ifa->iface->addr->ip);
+#else /* OSPFv3 */
+  lsa.id = ifa->iface->index;
+#endif
+
   lsa.rt = rtid;
-  lsa.options = ifa->oa->opt.byte;
-  if (ifa->nlsa == NULL)
-  {
-    lsa.sn = LSA_INITSEQNO;
-  }
-  else
-  {
-    lsa.sn = ifa->nlsa->lsa.sn + 1;
-  }
+  lsa.sn = ifa->net_lsa ? (ifa->net_lsa->lsa.sn + 1) : LSA_INITSEQNO;
 
   body = originate_net_lsa_body(ifa, &lsa.length, po);
   lsasum_calculate(&lsa, body);
-  ifa->nlsa = lsa_install_new(&lsa, body, ifa->oa);
-  ospf_lsupd_flood(NULL, NULL, &ifa->nlsa->lsa, NULL, ifa->oa, 1);
+  ifa->net_lsa = lsa_install_new(po, &lsa, dom, body);
+  ospf_lsupd_flood(po, NULL, NULL, &lsa, dom, 1);
   ifa->orignet = 0;
 }
 
 
+#ifdef OSPFv2
+
 static void *
-originate_ext_lsa_body(net * n, rte * e, struct proto_ospf *po,
-                      struct ea_list *attrs)
+originate_sum_lsa_body(struct proto_ospf *po, u16 *length, u32 mlen, u32 metric)
 {
-  struct proto *p = &po->proto;
-  struct ospf_lsa_ext *ext;
-  struct ospf_lsa_ext_tos *et;
-  u32 m1 = ea_get_int(attrs, EA_OSPF_METRIC1, LSINFINITY);
-  u32 m2 = ea_get_int(attrs, EA_OSPF_METRIC2, 10000);
-  u32 tag = ea_get_int(attrs, EA_OSPF_TAG, 0);
-  int inas = 0;
+  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);
 
-  ext = mb_alloc(p->pool, sizeof(struct ospf_lsa_ext) +
-                sizeof(struct ospf_lsa_ext_tos));
-  ext->netmask = ipa_mkmask(n->n.pxlen);
+  sum->netmask = ipa_mkmask(mlen);
+  sum->metric = metric;
 
-  et = (struct ospf_lsa_ext_tos *) (ext + 1);
+  return sum;
+}
 
-  if (m1 != LSINFINITY)
-  {
-    et->etm.metric = m1;
-    et->etm.etos.tos = 0;
-    et->etm.etos.ebit = 0;
-  }
-  else
-  {
-    et->etm.metric = m2;
-    et->etm.etos.tos = 0;
-    et->etm.etos.ebit = 1;
-  }
-  et->tag = tag;
-  if (!ipa_equal(e->attrs->gw, IPA_NONE))
-  {
-    if (ospf_iface_find((struct proto_ospf *) p, e->attrs->iface) != NULL)
-      inas = 1;
-  }
+#define originate_sum_net_lsa_body(po,length,fn,metric) \
+  originate_sum_lsa_body(po, length, (fn)->pxlen, metric)
 
-  if (!inas)
-    et->fwaddr = IPA_NONE;
-  else
-    et->fwaddr = e->attrs->gw;
-  return ext;
-}
+#define originate_sum_rt_lsa_body(po,length,drid,metric,options) \
+  originate_sum_lsa_body(po, length, 0, metric)
 
-/**
- * max_ext_lsa - calculate the maximum amount of external networks
- * possible for the given prefix length.
- * @pxlen: network prefix length
- *
- * This is a fix for the previous static use of MAXNETS which did
- * only work correct if MAXNETS < possible IPs for given prefix.
- * This solution is kind of a hack as there can now only be one
- * route for /32 type entries but this is better than the crashes
- * I did experience whith close together /32 routes originating
- * on different hosts.
- */
+#else /* OSPFv3 */
 
-int
-max_ext_lsa(unsigned pxlen)
+static void *
+originate_sum_net_lsa_body(struct proto_ospf *po, u16 *length, struct fib_node *fn, u32 metric)
 {
-  int i;
-  for (i = 1; pxlen < BITS_PER_IP_ADDRESS; pxlen++, i <<= 1)
-    if (i >= MAXNETS)
-      return MAXNETS;
-  return i;
+  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;
+
+  sum->metric = metric;
+  put_ipv6_prefix(sum->prefix, fn->prefix, fn->pxlen, 0, 0);
+
+  return sum;
+}
+
+static void *
+originate_sum_rt_lsa_body(struct proto_ospf *po, u16 *length, u32 drid, u32 metric, u32 options)
+{
+  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);
+
+  sum->options = options & OPTIONS_MASK;
+  sum->metric = metric;
+  sum->drid = drid;
+
+  return sum;
 }
 
+#endif
+
 void
-flush_sum_lsa(struct ospf_area *oa, struct fib_node *fn, int type)
+originate_sum_lsa(struct ospf_area *oa, struct fib_node *fn, int type, int metric, u32 options)
 {
   struct proto_ospf *po = oa->po;
   struct proto *p = &po->proto;
   struct top_hash_entry *en;
-  u32 rtid = po->proto.cf->global->router_id;
+  u32 rid = po->proto.cf->global->router_id;
   struct ospf_lsa_header lsa;
-  int max, i;
-  struct ospf_lsa_sum *sum = NULL;
+  void *body;
 
-  lsa.rt = rtid;
-  lsa.type = LSA_T_SUM_NET;
-  if (type == ORT_ROUTER)
-    lsa.type = LSA_T_SUM_RT;
+  /* options argument is used in ORT_NET and OSPFv3 only */
+
+  lsa.age = 0;
+  lsa.rt = rid;
+  lsa.sn = LSA_INITSEQNO;
+#ifdef OSPFv2
+  lsa.options = oa->options;
+#endif
 
-  max = max_ext_lsa(fn->pxlen);
+  if (type == ORT_NET)
+    {
+      /* FIXME proper handling of LSA IDs and check for the same network */
+      lsa.id = ipa_to_lsaid(fn->prefix);
+      lsa.type = LSA_T_SUM_NET;
+    }
+  else
+    {
+      /* In OSPFv6, 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;
+    }
 
-  for (i = 0; i < max; i++)
-  {
-    lsa.id = ipa_to_u32(fn->prefix) + i;
-    if ((en = ospf_hash_find_header(po->gr, oa->areaid, &lsa)) != NULL)
+  u32 dom = oa->areaid;  
+
+  /* FIXME check for the same LSA */
+  if ((en = ospfxx_hash_find_header(po->gr, oa->areaid, &lsa)) != NULL)
+    lsa.sn = en->lsa.sn + 1;
+
+  if (type == ORT_NET)
     {
-      sum = en->lsa_body;
-      if ((type == ORT_ROUTER) || (fn->pxlen == ipa_mklen(sum->netmask)))
-      {
-        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(NULL, NULL, &en->lsa, NULL, oa, 1);
-        if (can_flush_lsa(po)) flush_lsa(en, po);
-        break;
-      }
+      OSPF_TRACE(D_EVENTS, "Originating Net-Summary-LSA for %I/%d (metric %d).",
+                fn->prefix, fn->pxlen, metric);
+
+      body = originate_sum_net_lsa_body(po, &lsa.length, fn, metric);
     }
-  }
+  else
+    {
+      OSPF_TRACE(D_EVENTS, "Originating RT-Summary-LSA for %R (metric %d).",
+                lsa.id, metric);
+
+      body = originate_sum_rt_lsa_body(po, &lsa.length, lsa.id, metric, options);
+    }
+
+  lsasum_calculate(&lsa, body);
+  en = lsa_install_new(po, &lsa, dom, body);
+  ospf_lsupd_flood(po, NULL, NULL, &lsa, dom, 1);
 }
 
+
 void
-originate_sum_lsa(struct ospf_area *oa, struct fib_node *fn, int type, int metric)
+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;
-  u32 rtid = po->proto.cf->global->router_id;
+  u32 rid = po->proto.cf->global->router_id;
   struct ospf_lsa_header lsa;
-  int i, max, mlen = fn->pxlen, free = 0;
-  u32 freeid = 0xFFFF;
-  struct ospf_lsa_sum *sum = NULL;
-  union ospf_lsa_sum_tm *tm;
-  lsa.type = LSA_T_SUM_NET;
-
-  if (type == ORT_ROUTER)
-  {
-    lsa.type = LSA_T_SUM_RT;
-    mlen = 0;
-  }
-
-  lsa.age = 0;
-  lsa.rt = rtid;
-  lsa.sn = LSA_INITSEQNO;
-  lsa.length = sizeof(struct ospf_lsa_sum) + sizeof(union ospf_lsa_sum_tm) +
-    sizeof(struct ospf_lsa_header);
-  lsa.options = oa->opt.byte;
 
-  max = max_ext_lsa(fn->pxlen);
-  for (i = 0; i < max; i++)
-  {
-    lsa.id = ipa_to_u32(fn->prefix) + i;
-    if ((en = ospf_hash_find_header(po->gr, oa->areaid, &lsa)) == NULL)
+  lsa.rt = rid;
+  if (type == ORT_NET)
     {
-      if (!free)
-      {
-        freeid = lsa.id;
-       free = 1;
-      }
+      /* FIXME proper handling of LSA IDs and check for the same network */
+      lsa.id = ipa_to_lsaid(fn->prefix);
+      lsa.type = LSA_T_SUM_NET;
     }
-    else
+  else
     {
-      sum = en->lsa_body;
-      if (mlen == ipa_mklen(sum->netmask))
-      {
-        tm = (union ospf_lsa_sum_tm *) (sum + 1);
-        if (tm->metric == (unsigned) metric) return;   /* No reason for origination */
-        lsa.sn = en->lsa.sn + 1;
-        freeid = en->lsa.id;
-       free = 1;
-        break;
-      }
+      /* In OSPFv6, 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;
     }
-  }
-
-  if(!free)
-  {
-    log("%s: got more routes for one /%d network then %d, ignoring", p->name,
-        fn->pxlen, max);
-    return;
-  }
-  lsa.id = freeid;
-  
-  OSPF_TRACE(D_EVENTS, "Originating summary (type %d) lsa for %I/%d (met %d).", lsa.type, fn->prefix,
-             fn->pxlen, metric);
 
-  sum = mb_alloc(p->pool, sizeof(struct ospf_lsa_sum) + sizeof(union ospf_lsa_sum_tm));
-  sum->netmask = ipa_mkmask(mlen);
-  tm = (union ospf_lsa_sum_tm *) (sum + 1);
-  tm->metric = metric;
-  tm->tos.tos = 0;
-
-  lsasum_calculate(&lsa, sum);
-  en = lsa_install_new(&lsa, sum, oa);
-  ospf_lsupd_flood(NULL, NULL, &en->lsa, NULL, oa, 1);
+  if ((en = ospfxx_hash_find_header(po->gr, oa->areaid, &lsa)) != NULL)
+    {
+      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);
+      if (can_flush_lsa(po)) flush_lsa(en, po);
+    }
 }
 
+
 void
 check_sum_lsa(struct proto_ospf *po, ort *nf, int dest)
 {
@@ -572,7 +714,7 @@ check_sum_lsa(struct proto_ospf *po, ort *nf, int dest)
     flush = 0;
     if ((nf->n.metric1 >= LSINFINITY) || (nf->n.type > RTS_OSPF_IA))
       flush = 1;
-    if ((dest == ORT_ROUTER) && (!(nf->n.capa & ORTA_ASBR)))
+    if ((dest == ORT_ROUTER) && (!(nf->n.options & ORTA_ASBR)))
       flush = 1;
     if ((!nf->n.oa) || (nf->n.oa->areaid == oa->areaid))
       flush = 1;
@@ -599,13 +741,73 @@ check_sum_lsa(struct proto_ospf *po, ort *nf, int dest)
       if ((nf->n.oa == po->backbone) && (oa->trcap)) flush = 0;
     }
 
-    if(flush)
+    if (flush)
       flush_sum_lsa(oa, &nf->fn, dest);
     else
-      originate_sum_lsa(oa, &nf->fn, dest, nf->n.metric1);
+      originate_sum_lsa(oa, &nf->fn, dest, nf->n.metric1, nf->n.options);
   }
 }
 
+
+static void *
+originate_ext_lsa_body(net *n, rte *e, u16 *length, struct proto_ospf *po,
+                      struct ea_list *attrs)
+{
+  struct proto *p = &po->proto;
+  struct ospf_lsa_ext *ext;
+  u32 m1 = ea_get_int(attrs, EA_OSPF_METRIC1, LSINFINITY);
+  u32 m2 = ea_get_int(attrs, EA_OSPF_METRIC2, 10000);
+  u32 tag = ea_get_int(attrs, EA_OSPF_TAG, 0);
+  int gw = 0;
+  int size = sizeof(struct ospf_lsa_ext);
+  u32 *buf;
+
+  if (!ipa_equal(e->attrs->gw, IPA_NONE))
+  {
+    /* FIXME: check for link-local in OSPFv3 ? */
+    if (ospf_iface_find((struct proto_ospf *) p, e->attrs->iface) != NULL)
+      gw = 1;
+  }
+
+#ifdef OSPFv3
+  size += IPV6_PREFIX_SPACE(n->n.pxlen);
+
+  if (gw)
+    size += 16;
+  
+  if (tag)
+    size += 4;
+#endif
+  
+  ext = mb_alloc(p->pool, size);
+  *length = sizeof(struct ospf_lsa_header) + size;
+
+  ext->metric = (m1 != LSINFINITY) ? m1 : (m2 & LSA_EXT_EBIT); 
+
+#ifdef OSPFv2
+  ext->netmask = ipa_mkmask(n->n.pxlen);
+  ext->fwaddr = gw ? IPA_NONE : e->attrs->gw;
+  ext->tag = tag;
+#else /* OSPFv3 */
+  buf = ext->rest;
+  buf = put_ipv6_prefix(buf, n->n.prefix, n->n.pxlen, 0, 0);
+
+  if (gw)
+    {
+      ext->metric |= LSA_EXT_FBIT;
+      buf = put_ipv6_addr(buf, e->attrs->gw);
+    }
+
+  if (tag)
+    {
+      ext->metric |= LSA_EXT_TBIT;
+      *buf++ = tag;
+    }
+#endif
+
+  return ext;
+}
+
 /**
  * originate_ext_lsa - new route received from nest and filters
  * @n: network prefix and mask
@@ -626,9 +828,9 @@ originate_ext_lsa(net * n, rte * e, struct proto_ospf *po,
                  struct ea_list *attrs)
 {
   struct ospf_lsa_header lsa;
-  u32 rtid = po->proto.cf->global->router_id;
+  u32 rid = po->proto.cf->global->router_id;
   struct top_hash_entry *en = NULL;
-  void *body = NULL;
+  void *body;
   struct proto *p = &po->proto;
   struct ospf_area *oa;
   struct ospf_lsa_ext *ext1, *ext2;
@@ -638,50 +840,26 @@ originate_ext_lsa(net * n, rte * e, struct proto_ospf *po,
             n->n.pxlen);
 
   lsa.age = 0;
-  lsa.id = ipa_to_u32(n->n.prefix);
   lsa.type = LSA_T_EXT;
-  lsa.rt = rtid;
+  lsa.rt = rid;
   lsa.sn = LSA_INITSEQNO;
-  lsa.options = 0;
+#ifdef OSPFv2
+  lsa.options = 0; /* or oa->options ? */
+#endif
 
-  body = originate_ext_lsa_body(n, e, po, attrs);
-  lsa.length = sizeof(struct ospf_lsa_ext) + sizeof(struct ospf_lsa_ext_tos) +
-    sizeof(struct ospf_lsa_header);
-  ext1 = body;
-  max = max_ext_lsa(n->n.pxlen);
+  /* FIXME proper handling of LSA IDs and check for the same network */
+  lsa.id = ipa_to_lsaid(n->n.prefix);
 
-  for (i = 0; i < max; i++)
-  {
-    if ((en = ospf_hash_find_header(po->gr, 0 , &lsa)) != NULL)
+  if ((en = ospfxx_hash_find_header(po->gr, 0, &lsa)) != NULL)
     {
-      ext2 = en->lsa_body;
-      if (ipa_compare(ext1->netmask, ext2->netmask) != 0)
-       lsa.id++;
-      else
-       break;
+      lsa.sn = en->lsa.sn + 1;
     }
-    else
-      break;
-  }
 
-  if (i == max)
-  {
-    log("%s: got more routes for one /%d network then %d, ignoring", p->name,
-       n->n.pxlen, max);
-    mb_free(body);
-    return;
-  }
+  body = originate_ext_lsa_body(n, e, &lsa.length, po, attrs);
   lsasum_calculate(&lsa, body);
-  WALK_LIST(oa, po->area_list)
-  {
-    if (!oa->stub)
-    {
-      en = lsa_install_new(&lsa, body, oa);
-      ospf_lsupd_flood(NULL, NULL, &en->lsa, NULL, oa, 1);
-      body = originate_ext_lsa_body(n, e, po, attrs);
-    }
-  }
-  mb_free(body);
+
+  en = lsa_install_new(po, &lsa, 0, body);
+  ospf_lsupd_flood(po, NULL, NULL, &lsa, 0, 1);
 
   if (po->ebit == 0)
   {
@@ -693,6 +871,304 @@ originate_ext_lsa(net * n, rte * e, struct proto_ospf *po,
   }
 }
 
+void
+flush_ext_lsa(net *n, struct proto_ospf *po)
+{
+  u32 rid = po->proto.cf->global->router_id;
+  struct ospf_area *oa;
+  struct top_hash_entry *en;
+  struct ospf_lsa_ext *ext;
+  int i;
+
+  /* FIXME proper handling of LSA IDs and check for the same network */
+  u32 lsaid = ipa_to_lsaid(n->n.prefix);
+
+  if (en = ospfxx_hash_find(po->gr, 0, lsaid, rid, LSA_T_EXT))
+    {
+      /* FIXME this is nonsense */
+      WALK_LIST(oa, po->area_list)
+       {
+         ospf_lsupd_flush_nlsa(po, en);
+       }
+    }
+}
+
+
+#ifdef OSPFv3
+
+static void *
+originate_link_lsa_body(struct ospf_iface *ifa, u16 *length)
+{
+  struct proto_ospf *po = ifa->oa->po;
+  struct ospf_lsa_link *ll;
+  int i = 0;
+  u8 flags;
+
+  ASSERT(po->lsab_used == 0);
+  ll = lsab_allocz(po, sizeof(struct ospf_lsa_link));
+  ll->options = ifa->oa->options | (ifa->priority << 24);
+  ll->lladdr = FIX;
+  ll = NULL; /* buffer might be reallocated later */
+
+  struct ifa *a;
+  WALK_LIST(a, ifa->iface->addrs)
+    {
+      if ((a->flags & IA_SECONDARY) ||
+         (a->scope < SCOPE_SITE))
+       continue;
+
+      flags = (a->pxlen < MAX_PREFIX_LENGTH) ? 0 : OPT_PX_LA;
+      put_ipv6_prefix(lsab_alloc(po, IPV6_PREFIX_SPACE(a->pxlen)),
+                     a->ip, a->pxlen, flags, 0);
+      i++;
+    }
+
+  ll = po->lsab;
+  ll->pxcount = i;
+  *length = po->lsab_used + sizeof(struct ospf_lsa_header);
+  return lsab_flush(po);
+}
+
+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;
+  u32 rtid = po->proto.cf->global->router_id;
+  void *body;
+
+  if (ifa->link_lsa && ((ifa->link_lsa->inst_t + MINLSINTERVAL) > now))
+    return;
+  /*
+   * It's too early to originate new link LSA. We will
+   * try to do it next tick
+   */
+
+  /* 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.id = ifa->iface->index;
+  lsa.rt = rtid;
+  lsa.sn = ifa->link_lsa ? (ifa->link_lsa->lsa.sn + 1) : LSA_INITSEQNO;
+  u32 dom = ifa->iface->index;
+
+  body = originate_link_lsa_body(ifa, &lsa.length);
+  lsasum_calculate(&lsa, body);
+  ifa->link_lsa = lsa_install_new(po, &lsa, dom, body);
+  ospf_lsupd_flood(po, NULL, NULL, &lsa, dom, 1);
+  ifa->origlink = 0;
+}
+
+
+static void *
+originate_prefix_rt_lsa_body(struct ospf_area *oa, u16 *length)
+{
+  struct proto_ospf *po = oa->po;
+  struct ospf_iface *ifa;
+  struct ospf_lsa_prefix *lp;
+  u32 rid = po->proto.cf->global->router_id;
+  int net_lsa;
+  int i = 0;
+  u8 flags;
+
+  ASSERT(po->lsab_used == 0);
+  lp = lsab_allocz(po, sizeof(struct ospf_lsa_prefix));
+  lp->ref_type = LSA_T_RT;
+  lp->ref_id = 0;
+  lp->ref_rt = rid;
+  lp = NULL; /* buffer might be reallocated later */
+
+  WALK_LIST(ifa, po->iface_list)
+  {
+    if ((ifa->oa != oa) || (ifa->state == OSPF_IS_DOWN))
+      continue;
+
+    if ((ifa->type == OSPF_IT_BCAST) ||
+       (ifa->type == OSPF_IT_NBMA))
+      net_lsa = bcast_net_active(ifa);
+    else
+      net_lsa = 0;
+
+    struct ifa *a;
+    WALK_LIST(a, ifa->iface->addrs)
+      {
+       if (((a->pxlen < MAX_PREFIX_LENGTH) && net_lsa) ||
+           (a->flags & IA_SECONDARY) ||
+           (a->flags & IA_UNNUMBERED) ||
+           configured_stubnet(oa, a))
+         continue;
+
+       flags = (a->pxlen < MAX_PREFIX_LENGTH) ? 0 : OPT_PX_LA;
+       put_ipv6_prefix(lsab_alloc(po, IPV6_PREFIX_SPACE(a->pxlen)),
+                       a->ip, a->pxlen, flags, ifa->cost);
+       i++;
+      }
+  }
+
+  /* FIXME Handle vlinks? see RFC5340, page 38 */
+
+  struct ospf_stubnet_config *sn;
+  WALK_LIST(sn, oa->ac->stubnet_list)
+    if (!sn->hidden)
+      {
+       flags = (sn->px.len < MAX_PREFIX_LENGTH) ? 0 : OPT_PX_LA;
+       put_ipv6_prefix(lsab_alloc(po, IPV6_PREFIX_SPACE(sn->px.len)),
+                       sn->px.addr, sn->px.len, flags, sn->cost);
+       i++;
+      }
+
+  lp = po->lsab;
+  lp->pxcount = i;
+  *length = po->lsab_used + sizeof(struct ospf_lsa_header);
+  return lsab_flush(po);
+}
+
+void
+originate_prefix_rt_lsa(struct ospf_area *oa)
+{
+  struct ospf_lsa_header lsa;
+  struct proto_ospf *po = oa->po;
+  u32 rid = po->proto.cf->global->router_id;
+  void *body;
+
+  lsa.age = 0;
+  lsa.type = LSA_T_PREFIX;
+  lsa.id = 1 << 31;
+  lsa.rt = rid;
+  lsa.sn = oa->pxr_lsa ? (oa->pxr_lsa->lsa.sn + 1) : LSA_INITSEQNO;
+  u32 dom = oa->areaid;
+
+  body = originate_prefix_rt_lsa_body(oa, &lsa.length);
+  lsasum_calculate(&lsa, body);
+  oa->pxr_lsa = lsa_install_new(po, &lsa, dom, body);
+  ospf_lsupd_flood(po, NULL, NULL, &lsa, dom, 1);
+}
+
+
+static inline int
+prefix_space(u32 *buf)
+{
+  int pxl = *buf >> 24;
+  return IPV6_PREFIX_SPACE(pxl);
+}
+
+static inline int
+prefix_same(u32 *b1, u32 *b2)
+{
+  int pxl1 = *b1 >> 24;
+  int pxl2 = *b2 >> 24;
+  int pxs, i;
+  
+  if (pxl1 != pxl2)
+    return 0;
+
+  pxs = IPV6_PREFIX_WORDS(pxl1);
+  for (i = 1; i < pxs; i++)
+    if (b1[i] != b2[i])
+      return 0;
+
+  return 1;
+}
+
+static inline u32 *
+prefix_advance(u32 *buf)
+{
+  return buf + prefix_space(buf);
+}
+
+static void
+add_prefix(struct proto_ospf *po, u32 *px, u32 *pxl, int *pxc)
+{
+  int i;
+  for (i = 0; i < *pxc; i++)
+    {
+      if (prefix_same(px, pxl))
+       {
+         /* Options should be logically OR'ed together */
+         *pxl |= *px;
+         return;
+       }
+      pxl = prefix_advance(pxl);
+    }
+
+  ASSERT(pxl == lsab_end(po));
+
+  int pxspace = prefix_space(px);
+  pxl = lsab_alloc(po, pxspace);
+  memcpy(pxl, px, pxspace);
+  (*pxc)++;
+}
+
+
+static void *
+originate_prefix_net_lsa_body(struct ospf_iface *ifa, u16 *length)
+{
+  struct proto_ospf *po = ifa->oa->po;
+  struct ospf_lsa_prefix *lp;
+  struct ospf_lsa_link *ll;
+  struct ospf_neighbor *n;
+  struct top_hash_entry *en;
+  u32 rid = po->proto.cf->global->router_id;
+  u32 *pxb;
+  int i, j, offset;
+
+
+  ASSERT(po->lsab_used == 0);
+  lp = lsab_allocz(po, sizeof(struct ospf_lsa_prefix));
+  lp->ref_type = LSA_T_NET;
+  lp->ref_id = ifa->net_lsa->lsa.id;
+  lp->ref_rt = rid;
+  lp = NULL; /* buffer might be reallocated later */
+
+  i = 0;
+  offset = po->lsab_used;
+
+  /* Find all Link LSA associated with the link and merge their prefixes */
+  WALK_LIST(n, ifa->neigh_list)
+    if ((n->state == NEIGHBOR_FULL) &&
+       (en = ospfxx_hash_find(po->gr, ifa->iface->index, n->iface_id, n->rid, LSA_T_LINK)))
+      {
+       ll = en->lsa_body;
+       pxb = ll->rest;
+
+       for (j = 0; j < ll->pxcount; j++)
+         {
+           add_prefix(po, pxb, lsab_offset(po, offset), &i);
+           pxb = prefix_advance(pxb);
+         }
+      }
+
+  lp = po->lsab;
+  lp->pxcount = i;
+  *length = po->lsab_used + sizeof(struct ospf_lsa_header);
+  return lsab_flush(po);
+}
+
+void
+originate_prefix_net_lsa(struct ospf_iface *ifa)
+{
+  struct ospf_lsa_header lsa;
+  struct proto_ospf *po = ifa->oa->po;
+  u32 rid = po->proto.cf->global->router_id;
+  void *body;
+
+  lsa.age = 0;
+  lsa.type = LSA_T_PREFIX;
+  lsa.id = ifa->iface->index;
+  lsa.rt = rid;
+  lsa.sn = ifa->pxn_lsa ? (ifa->pxn_lsa->lsa.sn + 1) : LSA_INITSEQNO;
+  u32 dom = ifa->oa->areaid;
+
+  body = originate_prefix_net_lsa_body(ifa, &lsa.length);
+  lsasum_calculate(&lsa, body);
+  ifa->pxn_lsa = lsa_install_new(po, &lsa, dom, body);
+  ospf_lsupd_flood(po, NULL, NULL, &lsa, dom, 1);
+}
+
+#endif
 
 static void
 ospf_top_ht_alloc(struct top_graph *f)
@@ -730,24 +1206,30 @@ ospf_top_hash_u32(u32 a)
 }
 
 static inline unsigned
-ospf_top_hash(struct top_graph *f, u32 areaid, u32 lsaid, u32 rtrid, u32 type)
-{
-#if 1                          /* Dirty patch to make rt table calculation work. */
-  return (ospf_top_hash_u32(lsaid) +
-         ospf_top_hash_u32((type ==
-                            LSA_T_NET) ? lsaid : rtrid) + type +
-          (type == LSA_T_EXT ? 0 : areaid)) & f->hash_mask;
-#else
+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.
+     dirty patch to make rt table calculation work. */
+
+  return (ospf_top_hash_u32(lsaid) + type +
+#ifdef OSPFv2
+         ((type == LSA_T_NET) ? 0 : ospf_top_hash_u32(rtrid)) +
+#else /* OSPFv3 */
+         ospf_top_hash_u32(rtrid) +
+#endif
+         domain) & f->hash_mask;
+
+  /*
   return (ospf_top_hash_u32(lsaid) + ospf_top_hash_u32(rtrid) +
          type + areaid) & f->hash_mask;
-#endif
+  */
 }
 
 /**
  * ospf_top_new - allocated new topology database
- * @p: current instance of OSPF
+ * @p: current instance of ospf
  *
- * This dynamically hashed structure is often used for keeping LSAs. Mainly
+ * this dynamically hashed structure is often used for keeping lsas. mainly
  * its used in @ospf_area structure.
  */
 struct top_graph *
@@ -781,7 +1263,7 @@ ospf_top_rehash(struct top_graph *f, int step)
 
   oldn = f->hash_size;
   oldt = f->hash_table;
-  DBG("Re-hashing topology hash from order %d to %d\n", f->hash_order,
+  dbg("re-hashing topology hash from order %d to %d\n", f->hash_order,
       f->hash_order + step);
   f->hash_order += step;
   ospf_top_ht_alloc(f);
@@ -793,7 +1275,7 @@ ospf_top_rehash(struct top_graph *f, int step)
     while (e)
     {
       x = e->next;
-      n = newt + ospf_top_hash(f, e->oa->areaid, e->lsa.id, e->lsa.rt, e->lsa.type);
+      n = newt + ospf_top_hash(f, e->domain, e->lsa.id, e->lsa.rt, e->lsa.type);
       e->next = *n;
       *n = e;
       e = x;
@@ -803,64 +1285,53 @@ ospf_top_rehash(struct top_graph *f, int step)
 }
 
 struct top_hash_entry *
-ospf_hash_find_header(struct top_graph *f, u32 areaid, struct ospf_lsa_header *h)
+ospfxx_hash_find_header(struct top_graph *f, u32 domain, struct ospf_lsa_header *h)
 {
-  return ospf_hash_find(f, areaid, h->id, h->rt, h->type);
+  return ospfxx_hash_find(f, domain, h->id, h->rt, h->type);
 }
 
 struct top_hash_entry *
-ospf_hash_get_header(struct top_graph *f, struct ospf_area *oa, struct ospf_lsa_header *h)
+ospfxx_hash_get_header(struct top_graph *f, u32 domain, struct ospf_lsa_header *h)
 {
-  return ospf_hash_get(f, oa, h->id, h->rt, h->type);
+  return ospfxx_hash_get(f, domain, h->id, h->rt, h->type);
 }
 
 struct top_hash_entry *
-ospf_hash_find(struct top_graph *f, u32 areaid, u32 lsa, u32 rtr, u32 type)
+ospfxx_hash_find(struct top_graph *f, u32 domain, u32 lsa, u32 rtr, u32 type)
 {
   struct top_hash_entry *e;
 
-  e = f->hash_table[ospf_top_hash(f, areaid, lsa, rtr, type)];
+  e = f->hash_table[ospf_top_hash(f, domain, lsa, rtr, type)];
 
-  /* Dirty patch to make rt table calculation work. */
+#ifdef OSPFv2
+  /* dirty patch to make rt table calculation work. */
   if (type == LSA_T_NET)
   {
-    while (e && (e->lsa.id != lsa || e->lsa.type != LSA_T_NET || e->oa->areaid != areaid))
-      e = e->next;
-  }
-  else if (type == LSA_T_EXT)
-  {
-    while (e && (e->lsa.id != lsa || e->lsa.type != type || e->lsa.rt != rtr))
-      e = e->next;
-  }
-  else
-  {
-    while (e && (e->lsa.id != lsa || e->lsa.type != type || e->lsa.rt != rtr || e->oa->areaid != areaid))
+    while (e && (e->lsa.id != lsa || e->lsa.type != LSA_T_NET || e->domain != domain))
       e = e->next;
+
+    return e;
   }
 
+#endif
+
+  while (e && (e->lsa.id != lsa || e->lsa.type != type || e->lsa.rt != rtr || e->domain != domain))
+    e = e->next;
+
   return e;
 }
 
 struct top_hash_entry *
-ospf_hash_get(struct top_graph *f, struct ospf_area *oa, u32 lsa, u32 rtr, u32 type)
+ospfxx_hash_get(struct top_graph *f, u32 domain, u32 lsa, u32 rtr, u32 type)
 {
   struct top_hash_entry **ee;
   struct top_hash_entry *e;
-  u32 nareaid = (type == LSA_T_EXT ? 0 : oa->areaid);
 
-  ee = f->hash_table + ospf_top_hash(f, nareaid, lsa, rtr, type);
+  ee = f->hash_table + ospf_top_hash(f, domain, lsa, rtr, type);
   e = *ee;
 
-  if (type == LSA_T_EXT)
-  {
-    while (e && (e->lsa.id != lsa || e->lsa.rt != rtr || e->lsa.type != type))
-      e = e->next;
-  }
-  else
-  {
-    while (e && (e->lsa.id != lsa || e->lsa.rt != rtr || e->lsa.type != type || e->oa->areaid != nareaid))
-      e = e->next;
-  }
+  while (e && (e->lsa.id != lsa || e->lsa.rt != rtr || e->lsa.type != type || e->domain != domain))
+    e = e->next;
 
   if (e)
     return e;
@@ -876,7 +1347,7 @@ ospf_hash_get(struct top_graph *f, struct ospf_area *oa, u32 lsa, u32 rtr, u32 t
   e->lsa.type = type;
   e->lsa_body = NULL;
   e->nhi = NULL;
-  e->oa = oa;
+  e->domain = domain;
   e->next = *ee;
   *ee = e;
   if (f->hash_entries++ > f->hash_entries_max)
@@ -888,7 +1359,7 @@ void
 ospf_hash_delete(struct top_graph *f, struct top_hash_entry *e)
 {
   struct top_hash_entry **ee = f->hash_table + 
-    ospf_top_hash(f, e->oa->areaid, e->lsa.id, e->lsa.rt, e->lsa.type);
+    ospf_top_hash(f, e->domain, e->lsa.id, e->lsa.rt, e->lsa.type);
 
   while (*ee)
   {
@@ -916,15 +1387,16 @@ ospf_dump_lsa(struct top_hash_entry *he, struct proto *p)
 
   OSPF_TRACE(D_EVENTS, "- %1x %-1R %-1R %4u 0x%08x 0x%04x %-1R",
             he->lsa.type, he->lsa.id, he->lsa.rt, he->lsa.age, he->lsa.sn,
-            he->lsa.checksum, he->oa ? he->oa->areaid : 0 );
+            he->lsa.checksum, he->domain);
 
+  /*
   switch (he->lsa.type)
     {
     case LSA_T_RT:
       rt = he->lsa_body;
       rr = (struct ospf_lsa_rt_link *) (rt + 1);
 
-      for (i = 0; i < rt->links; i++)
+      for (i = 0; i < lsa_rt_items(&he->lsa); i++)
         OSPF_TRACE(D_EVENTS, "  - %1x %-1R %-1R %5u",
                   rr[i].type, rr[i].id, rr[i].data, rr[i].metric);
       break;
@@ -932,16 +1404,15 @@ ospf_dump_lsa(struct top_hash_entry *he, struct proto *p)
     case LSA_T_NET:
       ln = he->lsa_body;
       rts = (u32 *) (ln + 1);
-      max = (he->lsa.length - sizeof(struct ospf_lsa_header) -
-               sizeof(struct ospf_lsa_net)) / sizeof(u32);
 
-      for (i = 0; i < max; i++)
+      for (i = 0; i < lsa_net_items(&he->lsa); i++)
         OSPF_TRACE(D_EVENTS, "  - %-1R", rts[i]);
       break;
 
     default:
       break;
     }
+  */
 }
 
 void
index 21e545e7df0c77d96d6e9d2941e37ad8fbc66da1..4555bea2855a274ee53eb041f7f0557b44b6e5d3 100644 (file)
@@ -13,12 +13,11 @@ struct top_hash_entry
 {                              /* Index for fast mapping (type,rtrid,LSid)->vertex */
   snode n;
   node cn;                     /* For adding into list of candidates
-                                * in intra-area routing table
-                                * calculation
-                                */
+                                  in intra-area routing table calculation */
   struct top_hash_entry *next; /* Next in hash chain */
   struct ospf_lsa_header lsa;
-  struct ospf_area *oa;
+  u32 domain;                  /* Area ID for area-wide LSAs, Iface ID for link-wide LSAs */
+  //  struct ospf_area *oa;
   void *lsa_body;
   bird_clock_t inst_t;         /* Time of installation into DB */
   ip_addr nh;                  /* Next hop */
@@ -48,13 +47,19 @@ struct top_graph
 struct top_graph *ospf_top_new(pool *);
 void ospf_top_free(struct top_graph *);
 void ospf_top_dump(struct top_graph *, struct proto *);
-struct top_hash_entry *ospf_hash_find_header(struct top_graph *f, u32 areaid,
+struct top_hash_entry *ospfxx_hash_find_header(struct top_graph *f, u32 areaid,
                                             struct ospf_lsa_header *h);
-struct top_hash_entry *ospf_hash_get_header(struct top_graph *f, struct ospf_area *oa,
+struct top_hash_entry *ospfxx_hash_get_header(struct top_graph *f, u32 domain,
                                            struct ospf_lsa_header *h);
-struct top_hash_entry *ospf_hash_find(struct top_graph *, u32 areaid, u32 lsa, u32 rtr,
+
+struct top_hash_entry *ospfxx_hash_find_smart(struct top_graph *f, struct ospf_iface *ifa,
+                                            struct ospf_lsa_header *h);
+struct top_hash_entry *ospfxx_hash_get_smart(struct top_graph *f, struct ospf_iface *ifa,
+                                           struct ospf_lsa_header *h);
+
+struct top_hash_entry *ospfxx_hash_find(struct top_graph *, u32 domain, u32 lsa, u32 rtr,
                                      u32 type);
-struct top_hash_entry *ospf_hash_get(struct top_graph *, struct ospf_area *oa, u32 lsa, u32 rtr,
+struct top_hash_entry *ospfxx_hash_get(struct top_graph *, u32 domain, u32 lsa, u32 rtr,
                                     u32 type);
 void ospf_hash_delete(struct top_graph *, struct top_hash_entry *);
 void originate_rt_lsa(struct ospf_area *oa);
@@ -64,7 +69,7 @@ int max_ext_lsa(unsigned pxlen);
 void originate_ext_lsa(net * n, rte * e, struct proto_ospf *po,
                       struct ea_list *attrs);
 void check_sum_lsa(struct proto_ospf *po, ort *nf, int);
-void originate_sum_lsa(struct ospf_area *oa, struct fib_node *fn, int type, int metric);
+void originate_sum_lsa(struct ospf_area *oa, struct fib_node *fn, int type, int metric, u32 options);
 void flush_sum_lsa(struct ospf_area *oa, struct fib_node *fn, int type);