summaryrefslogtreecommitdiff
path: root/proto
diff options
context:
space:
mode:
authorOndrej Zajicek <santiago@crfreenet.org>2009-08-21 09:27:52 +0200
committerOndrej Zajicek <santiago@crfreenet.org>2009-08-21 09:27:52 +0200
commitc3226991a061415fa83b757cbff678111c586e58 (patch)
treeecbc7e7a5a2724463e2672bf8a3d1f64956467c0 /proto
parent3aab39f589c352e30e9db92346b579dd561482b3 (diff)
Temporary OSPFv3 development commit
Diffstat (limited to 'proto')
-rw-r--r--proto/ospf/config.Y11
-rw-r--r--proto/ospf/dbdes.c95
-rw-r--r--proto/ospf/dbdes.h4
-rw-r--r--proto/ospf/hello.c137
-rw-r--r--proto/ospf/hello.h4
-rw-r--r--proto/ospf/iface.c18
-rw-r--r--proto/ospf/lsack.c27
-rw-r--r--proto/ospf/lsack.h4
-rw-r--r--proto/ospf/lsalib.c203
-rw-r--r--proto/ospf/lsalib.h7
-rw-r--r--proto/ospf/lsreq.c38
-rw-r--r--proto/ospf/lsreq.h4
-rw-r--r--proto/ospf/lsupd.c172
-rw-r--r--proto/ospf/lsupd.h12
-rw-r--r--proto/ospf/neighbor.c107
-rw-r--r--proto/ospf/ospf.c68
-rw-r--r--proto/ospf/ospf.h385
-rw-r--r--proto/ospf/packet.c71
-rw-r--r--proto/ospf/rt.c389
-rw-r--r--proto/ospf/rt.h9
-rw-r--r--proto/ospf/topology.c1075
-rw-r--r--proto/ospf/topology.h23
22 files changed, 1887 insertions, 976 deletions
diff --git a/proto/ospf/config.Y b/proto/ospf/config.Y
index 77ca26cf..6acc7d24 100644
--- a/proto/ospf/config.Y
+++ b/proto/ospf/config.Y
@@ -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
diff --git a/proto/ospf/dbdes.c b/proto/ospf/dbdes.c
index adc0276f..31075791 100644
--- a/proto/ospf/dbdes.c
+++ b/proto/ospf/dbdes.c
@@ -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;
diff --git a/proto/ospf/dbdes.h b/proto/ospf/dbdes.h
index af962928..63cca0a2 100644
--- a/proto/ospf/dbdes.h
+++ b/proto/ospf/dbdes.h
@@ -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_ */
diff --git a/proto/ospf/hello.c b/proto/ospf/hello.c
index 45b6b613..7eeee3b3 100644
--- a/proto/ospf/hello.c
+++ b/proto/ospf/hello.c
@@ -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;
diff --git a/proto/ospf/hello.h b/proto/ospf/hello.h
index d5359352..5d73c09e 100644
--- a/proto/ospf/hello.h
+++ b/proto/ospf/hello.h
@@ -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_ */
diff --git a/proto/ospf/iface.c b/proto/ospf/iface.c
index ea38461d..ea3baa23 100644
--- a/proto/ospf/iface.c
+++ b/proto/ospf/iface.c
@@ -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)
diff --git a/proto/ospf/lsack.c b/proto/ospf/lsack.c
index 824767a6..7871b8f4 100644
--- a/proto/ospf/lsack.c
+++ b/proto/ospf/lsack.c
@@ -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 */
diff --git a/proto/ospf/lsack.h b/proto/ospf/lsack.h
index 05cc22f0..63a436d6 100644
--- a/proto/ospf/lsack.h
+++ b/proto/ospf/lsack.h
@@ -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);
diff --git a/proto/ospf/lsalib.c b/proto/ospf/lsalib.c
index e624b6ce..7c4001d9 100644
--- a/proto/ospf/lsalib.c
+++ b/proto/ospf/lsalib.c
@@ -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);
}
diff --git a/proto/ospf/lsalib.h b/proto/ospf/lsalib.h
index c7f16d51..640fa173 100644
--- a/proto/ospf/lsalib.h
+++ b/proto/ospf/lsalib.h
@@ -12,16 +12,15 @@
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);
diff --git a/proto/ospf/lsreq.c b/proto/ospf/lsreq.c
index 5eeb06f0..cc5afa0f 100644
--- a/proto/ospf/lsreq.c
+++ b/proto/ospf/lsreq.c
@@ -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;
diff --git a/proto/ospf/lsreq.h b/proto/ospf/lsreq.h
index f917f05c..a12edde2 100644
--- a/proto/ospf/lsreq.h
+++ b/proto/ospf/lsreq.h
@@ -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_ */
diff --git a/proto/ospf/lsupd.c b/proto/ospf/lsupd.c
index ba09fec0..8c26f548 100644
--- a/proto/ospf/lsupd.c
+++ b/proto/ospf/lsupd.c
@@ -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);
}
diff --git a/proto/ospf/lsupd.h b/proto/ospf/lsupd.h
index 524a0a2d..8bacfe65 100644
--- a/proto/ospf/lsupd.h
+++ b/proto/ospf/lsupd.h
@@ -13,11 +13,13 @@
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_ */
diff --git a/proto/ospf/neighbor.c b/proto/ospf/neighbor.c
index bb681c22..d86895ed 100644
--- a/proto/ospf/neighbor.c
+++ b/proto/ospf/neighbor.c
@@ -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
diff --git a/proto/ospf/ospf.c b/proto/ospf/ospf.c
index d4bcbed7..2ee6e631 100644
--- a/proto/ospf/ospf.c
+++ b/proto/ospf/ospf.c
@@ -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, "");
}
diff --git a/proto/ospf/ospf.h b/proto/ospf/ospf.h
index 22790899..1e46d3be 100644
--- a/proto/ospf/ospf.h
+++ b/proto/ospf/ospf.h
@@ -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,
diff --git a/proto/ospf/packet.c b/proto/ospf/packet.c
index 783d28ed..e3a3115b 100644
--- a/proto/ospf/packet.c
+++ b/proto/ospf/packet.c
@@ -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");
diff --git a/proto/ospf/rt.c b/proto/ospf/rt.c
index a230d38f..e64e68af 100644
--- a/proto/ospf/rt.c
+++ b/proto/ospf/rt.c
@@ -10,18 +10,56 @@
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);
}
}
diff --git a/proto/ospf/rt.h b/proto/ospf/rt.h
index acb0a1ac..d4b85ae2 100644
--- a/proto/ospf/rt.h
+++ b/proto/ospf/rt.h
@@ -17,9 +17,12 @@
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;
diff --git a/proto/ospf/topology.c b/proto/ospf/topology.c
index 5d8c7a9d..21627f05 100644
--- a/proto/ospf/topology.c
+++ b/proto/ospf/topology.c
@@ -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
diff --git a/proto/ospf/topology.h b/proto/ospf/topology.h
index 21e545e7..4555bea2 100644
--- a/proto/ospf/topology.h
+++ b/proto/ospf/topology.h
@@ -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);