Temporary OSPFv3 development commit

This commit is contained in:
Ondrej Zajicek 2009-08-21 09:27:52 +02:00
parent 3aab39f589
commit c3226991a0
24 changed files with 1911 additions and 1000 deletions

View file

@ -43,15 +43,13 @@ AC_SUBST(srcdir_rel_mf)
if test "$enable_ipv6" = yes ; then
ip=ipv6
SUFFIX6=6
if test "$with_protocols" = all ; then
with_protocols=bgp,pipe,rip,static
fi
else
ip=ipv4
SUFFIX6=""
if test "$with_protocols" = all ; then
with_protocols=bgp,ospf,pipe,rip,static
fi
fi
if test "$with_protocols" = all ; then
with_protocols=bgp,ospf,pipe,rip,static
fi
AC_SEARCH_LIBS(clock_gettime,[c rt posix4])

View file

@ -71,6 +71,7 @@ ea__find(ea_list *e, unsigned id)
while (e)
{
/*
if (e->flags & EALF_BISECT)
{
l = 0;
@ -88,6 +89,7 @@ ea__find(ea_list *e, unsigned id)
}
}
else
*/
for(m=0; m<e->count; m++)
if (e->attrs[m].id == id)
return &e->attrs[m];

View file

@ -20,6 +20,7 @@ static struct nbma_node *this_nbma;
static struct area_net_config *this_pref;
static struct ospf_stubnet_config *this_stubnet;
#ifdef OSPFv2
static void
finish_iface_config(struct ospf_iface_patt *ip)
{
@ -31,6 +32,16 @@ finish_iface_config(struct ospf_iface_patt *ip)
if ((ip->autype == OSPF_AUTH_NONE) && (ip->passwords != NULL))
log(L_WARN "Password option without authentication option does not make sense");
}
#endif
#ifdef OSPFv3
static void
finish_iface_config(struct ospf_iface_patt *ip)
{
if ((ip->autype != OSPF_AUTH_NONE) || (get_passwords() != NULL))
log(L_WARN "Authentication not supported in OSPFv3");
}
#endif
CF_DECLS

View file

@ -8,6 +8,37 @@
#include "ospf.h"
#ifdef OSPFv2
struct ospf_dbdes_packet
{
struct ospf_packet ospf_packet;
u16 iface_mtu;
u8 options;
union imms imms; /* I, M, MS bits */
u32 ddseq;
};
#define hton_opt(X) X
#define ntoh_opt(X) X
#endif
#ifdef OSPFv3
struct ospf_dbdes_packet
{
struct ospf_packet ospf_packet;
u32 options;
u16 iface_mtu;
u8 padding;
union imms imms; /* I, M, MS bits */
u32 ddseq;
};
#define hton_opt(X) htonl(X)
#define ntoh_opt(X) ntohl(X)
#endif
static void ospf_dump_dbdes(struct proto *p, struct ospf_dbdes_packet *pkt)
{
@ -37,7 +68,7 @@ static void ospf_dump_dbdes(struct proto *p, struct ospf_dbdes_packet *pkt)
* @n: neighbor
* @next: whether to send a next packet in a sequence (1) or to retransmit the old one (0)
*
* Sending of a database description packet is described in 10.6 of RFC 2328.
* Sending of a database description packet is described in 10.8 of RFC 2328.
* Reception of each packet is acknowledged in the sequence number of another.
* When I send a packet to a neighbor I keep a copy in a buffer. If the neighbor
* does not reply, I don't create a new packet but just send the content
@ -65,7 +96,7 @@ ospf_dbdes_send(struct ospf_neighbor *n, int next)
op = (struct ospf_packet *) pkt;
ospf_pkt_fill_hdr(ifa, pkt, DBDES_P);
pkt->iface_mtu = htons(ifa->iface->mtu);
pkt->options = oa->opt.byte;
pkt->options = hton_opt(oa->options);
pkt->imms = n->myimms;
pkt->ddseq = htonl(n->dds);
length = sizeof(struct ospf_dbdes_packet);
@ -88,8 +119,8 @@ ospf_dbdes_send(struct ospf_neighbor *n, int next)
ospf_pkt_fill_hdr(ifa, pkt, DBDES_P);
pkt->iface_mtu = htons(ifa->iface->mtu);
pkt->options = oa->opt.byte;
pkt->ddseq = htonl(n->dds);
pkt->options = hton_opt(oa->options);
j = i = (ospf_pkt_maxsize(ifa) - sizeof(struct ospf_dbdes_packet)) / sizeof(struct ospf_lsa_header); /* Number of possible lsaheaders to send */
lsa = (n->ldbdes + sizeof(struct ospf_dbdes_packet));
@ -102,16 +133,8 @@ ospf_dbdes_send(struct ospf_neighbor *n, int next)
for (; i > 0; i--)
{
struct top_hash_entry *en= (struct top_hash_entry *) sn;
int send = 1;
/* Don't send ext LSA into stub areas */
if (oa->stub && (en->lsa.type == LSA_T_EXT)) send = 0;
/* Don't send ext LSAs through VLINK */
if ((ifa->type == OSPF_IT_VLINK) && (en->lsa.type == LSA_T_EXT)) send = 0;;
/* Don't send LSA of other areas */
if ((en->lsa.type != LSA_T_EXT) && (en->oa != oa)) send = 0;
if (send)
if (ospf_lsa_flooding_allowed(&en->lsa, en->domain, ifa))
{
htonlsah(&(en->lsa), lsa);
DBG("Working on: %d\n", i);
@ -204,13 +227,13 @@ ospf_dbdes_reqladd(struct ospf_dbdes_packet *ps, struct ospf_neighbor *n)
for (i = 0; i < j; i++)
{
ntohlsah(plsa + i, &lsa);
if (((he = ospf_hash_find(gr, oa->areaid, lsa.id, lsa.rt, lsa.type)) == NULL) ||
if (((he = ospfxx_hash_find_smart(gr, n->ifa, &lsa)) == NULL) ||
(lsa_comp(&lsa, &(he->lsa)) == 1))
{
/* Is this condition necessary? */
if (ospf_hash_find(n->lsrqh, oa->areaid, lsa.id, lsa.rt, lsa.type) == NULL)
if (ospfxx_hash_find_smart(n->lsrqh, n->ifa, &lsa) == NULL)
{
sn = ospf_hash_get(n->lsrqh, oa, lsa.id, lsa.rt, lsa.type);
sn = ospfxx_hash_get_smart(n->lsrqh, n->ifa, &lsa);
ntohlsah(plsa + i, &(sn->lsa));
s_add_tail(&(n->lsrql), SNODE sn);
}
@ -219,13 +242,17 @@ ospf_dbdes_reqladd(struct ospf_dbdes_packet *ps, struct ospf_neighbor *n)
}
void
ospf_dbdes_receive(struct ospf_dbdes_packet *ps,
struct ospf_iface *ifa, struct ospf_neighbor *n)
ospf_dbdes_receive(struct ospf_packet *ps_i, struct ospf_iface *ifa,
struct ospf_neighbor *n)
{
struct ospf_dbdes_packet *ps = (void *) ps_i;
struct proto *p = &ifa->oa->po->proto;
u32 myrid = p->cf->global->router_id;
unsigned int size = ntohs(ps->ospf_packet.length);
u32 ps_ddseq = ntohl(ps->ddseq);
u32 ps_options = ntoh_opt(ps->options);
OSPF_PACKET(ospf_dump_dbdes, ps, "DBDES packet received from %I via %s", n->ip, ifa->iface->name);
ospf_neigh_sm(n, INM_HELLOREC);
@ -246,9 +273,9 @@ ospf_dbdes_receive(struct ospf_dbdes_packet *ps,
&& (n->rid > myrid) && (size == sizeof(struct ospf_dbdes_packet)))
{
/* I'm slave! */
n->dds = ntohl(ps->ddseq);
n->ddr = ntohl(ps->ddseq);
n->options = ps->options;
n->dds = ps_ddseq;
n->ddr = ps_ddseq;
n->options = ps_options;
n->myimms.bit.ms = 0;
n->imms.byte = ps->imms.byte;
OSPF_TRACE(D_PACKETS, "I'm slave to %I.", n->ip);
@ -258,11 +285,11 @@ ospf_dbdes_receive(struct ospf_dbdes_packet *ps,
}
if (((ps->imms.bit.i == 0) && (ps->imms.bit.ms == 0)) &&
(n->rid < myrid) && (n->dds == ntohl(ps->ddseq)))
(n->rid < myrid) && (n->dds == ps_ddseq))
{
/* I'm master! */
n->options = ps->options;
n->ddr = ntohl(ps->ddseq) - 1; /* It will be set corectly a few lines down */
n->options = ps_options;
n->ddr = ps_ddseq - 1; /* It will be set corectly a few lines down */
n->imms.byte = ps->imms.byte;
OSPF_TRACE(D_PACKETS, "I'm master to %I.", n->ip);
ospf_neigh_sm(n, INM_NEGDONE);
@ -274,8 +301,8 @@ ospf_dbdes_receive(struct ospf_dbdes_packet *ps,
break;
}
case NEIGHBOR_EXCHANGE:
if ((ps->imms.byte == n->imms.byte) && (ps->options == n->options) &&
(ntohl(ps->ddseq) == n->ddr))
if ((ps->imms.byte == n->imms.byte) && (ps_options == n->options) &&
(ps_ddseq == n->ddr))
{
/* Duplicate packet */
OSPF_TRACE(D_PACKETS, "Received duplicate dbdes from %I.", n->ip);
@ -287,7 +314,7 @@ ospf_dbdes_receive(struct ospf_dbdes_packet *ps,
return;
}
n->ddr = ntohl(ps->ddseq);
n->ddr = ps_ddseq;
if (ps->imms.bit.ms != n->imms.bit.ms) /* M/S bit differs */
{
@ -307,7 +334,7 @@ ospf_dbdes_receive(struct ospf_dbdes_packet *ps,
n->imms.byte = ps->imms.byte;
if (ps->options != n->options) /* Options differs */
if (ps_options != n->options) /* Options differs */
{
OSPF_TRACE(D_PACKETS, "dbdes - sequence mismatch neighbor %I (options)",
n->ip);
@ -317,7 +344,7 @@ ospf_dbdes_receive(struct ospf_dbdes_packet *ps,
if (n->myimms.bit.ms)
{
if (ntohl(ps->ddseq) != n->dds) /* MASTER */
if (ps_ddseq != n->dds) /* MASTER */
{
OSPF_TRACE(D_PACKETS,
"dbdes - sequence mismatch neighbor %I (master)", n->ip);
@ -339,15 +366,15 @@ ospf_dbdes_receive(struct ospf_dbdes_packet *ps,
}
else
{
if (ntohl(ps->ddseq) != (n->dds + 1)) /* SLAVE */
if (ps_ddseq != (n->dds + 1)) /* SLAVE */
{
OSPF_TRACE(D_PACKETS, "dbdes - sequence mismatch neighbor %I (slave)",
n->ip);
ospf_neigh_sm(n, INM_SEQMIS);
break;
}
n->ddr = ntohl(ps->ddseq);
n->dds = ntohl(ps->ddseq);
n->ddr = ps_ddseq;
n->dds = ps_ddseq;
ospf_dbdes_reqladd(ps, n);
ospf_dbdes_send(n, 1);
}
@ -355,8 +382,8 @@ ospf_dbdes_receive(struct ospf_dbdes_packet *ps,
break;
case NEIGHBOR_LOADING:
case NEIGHBOR_FULL:
if ((ps->imms.byte == n->imms.byte) && (ps->options == n->options)
&& (ntohl(ps->ddseq) == n->ddr))
if ((ps->imms.byte == n->imms.byte) && (ps_options == n->options)
&& (ps_ddseq == n->ddr))
/* Only duplicate are accepted */
{
OSPF_TRACE(D_PACKETS, "Received duplicate dbdes from %I.", n->ip);
@ -371,7 +398,7 @@ ospf_dbdes_receive(struct ospf_dbdes_packet *ps,
{
OSPF_TRACE(D_PACKETS, "dbdes - sequence mismatch neighbor %I (full)",
n->ip);
DBG("PS=%u, DDR=%u, DDS=%u\n", ntohl(ps->ddseq), n->ddr, n->dds);
DBG("PS=%u, DDR=%u, DDS=%u\n", ps_ddseq, n->ddr, n->dds);
ospf_neigh_sm(n, INM_SEQMIS);
}
break;

View file

@ -11,7 +11,7 @@
#define _BIRD_OSPF_DBDES_H_
void ospf_dbdes_send(struct ospf_neighbor *n, int next);
void ospf_dbdes_receive(struct ospf_dbdes_packet *ps,
struct ospf_iface *ifa, struct ospf_neighbor *n);
void ospf_dbdes_receive(struct ospf_packet *ps, struct ospf_iface *ifa,
struct ospf_neighbor *n);
#endif /* _BIRD_OSPF_DBDES_H_ */

View file

@ -8,12 +8,46 @@
#include "ospf.h"
void
ospf_hello_receive(struct ospf_hello_packet *ps,
struct ospf_iface *ifa, struct ospf_neighbor *n, ip_addr faddr)
#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_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;

View file

@ -10,8 +10,8 @@
#ifndef _BIRD_OSPF_HELLO_H_
#define _BIRD_OSPF_HELLO_H_
void ospf_hello_receive(struct ospf_hello_packet *ps,
struct ospf_iface *ifa, struct ospf_neighbor *n, ip_addr faddr);
void ospf_hello_receive(struct ospf_packet *ps_i, struct ospf_iface *ifa,
struct ospf_neighbor *n, ip_addr faddr);
void ospf_hello_send(timer *timer, int poll, struct ospf_neighbor *dirn);
#endif /* _BIRD_OSPF_HELLO_H_ */

View file

@ -157,16 +157,16 @@ ospf_iface_chstate(struct ospf_iface *ifa, u8 state)
rfree(ifa->dr_sk);
ifa->dr_sk = NULL;
}
if ((oldstate == OSPF_IS_DR) && (ifa->nlsa != NULL))
if ((oldstate == OSPF_IS_DR) && (ifa->net_lsa != NULL))
{
ifa->nlsa->lsa.age = LSA_MAXAGE;
ifa->net_lsa->lsa.age = LSA_MAXAGE;
if (state >= OSPF_IS_WAITING)
{
ospf_lsupd_flush_nlsa(ifa->nlsa, ifa->oa);
ospf_lsupd_flush_nlsa(po, ifa->net_lsa);
}
if (can_flush_lsa(po))
flush_lsa(ifa->nlsa, po);
ifa->nlsa = NULL;
flush_lsa(ifa->net_lsa, po);
ifa->net_lsa = NULL;
}
}
}
@ -412,8 +412,16 @@ ospf_iface_new(struct proto_ospf *po, struct iface *iface,
ifa->waitint = ip->waitint;
ifa->dead = (ip->dead == 0) ? ip->deadc * ifa->helloint : ip->dead;
ifa->stub = ip->stub;
#ifdef OSPFv2
ifa->autype = ip->autype;
ifa->passwords = ip->passwords;
#endif
#ifdef OSPFv3
ifa->instance_id = ip->instance_id;
#endif
ifa->rxbuf = ip->rxbuf;
if (ip->type == OSPF_IT_UNDEF)

View file

@ -8,6 +8,14 @@
#include "ospf.h"
struct ospf_lsack_packet
{
struct ospf_packet ospf_packet;
struct ospf_lsa_header lsh[];
};
char *s_queue[] = { "direct", "delayed" };
@ -18,14 +26,12 @@ static void ospf_dump_lsack(struct proto *p, struct ospf_lsack_packet *pkt)
ASSERT(op->type == LSACK_P);
ospf_dump_common(p, op);
struct ospf_lsa_header *plsa = (void *) (pkt + 1);
int i, j;
j = (ntohs(op->length) - sizeof(struct ospf_lsack_packet)) /
sizeof(struct ospf_lsa_header);
for (i = 0; i < j; i++)
ospf_dump_lsahdr(p, plsa + i);
ospf_dump_lsahdr(p, pkt->lsh + i);
}
@ -70,7 +76,7 @@ ospf_lsack_send(struct ospf_neighbor *n, int queue)
op = (struct ospf_packet *) sk->tbuf;
ospf_pkt_fill_hdr(n->ifa, pk, LSACK_P);
h = (struct ospf_lsa_header *) (pk + 1);
h = pk->lsh;
while (!EMPTY_LIST(n->ackl[queue]))
{
@ -141,10 +147,11 @@ ospf_lsack_send(struct ospf_neighbor *n, int queue)
}
void
ospf_lsack_receive(struct ospf_lsack_packet *ps,
struct ospf_iface *ifa, struct ospf_neighbor *n)
ospf_lsack_receive(struct ospf_packet *ps_i, struct ospf_iface *ifa,
struct ospf_neighbor *n)
{
struct ospf_lsa_header lsa, *plsa;
struct ospf_lsack_packet *ps = (void *) ps_i;
struct ospf_lsa_header lsa;
u16 nolsa;
struct top_hash_entry *en;
struct proto *p = &ifa->oa->po->proto;
@ -167,12 +174,10 @@ ospf_lsack_receive(struct ospf_lsack_packet *ps,
return;
}
plsa = (struct ospf_lsa_header *) (ps + 1);
for (i = 0; i < nolsa; i++)
{
ntohlsah(plsa + i, &lsa);
if ((en = ospf_hash_find_header(n->lsrth, n->ifa->oa->areaid, &lsa)) == NULL)
ntohlsah(ps->lsh + i, &lsa);
if ((en = ospfxx_hash_find_smart(n->lsrth, n->ifa, &lsa)) == NULL)
continue; /* pg 155 */
if (lsa_comp(&lsa, &en->lsa) != CMP_SAME) /* pg 156 */

View file

@ -16,8 +16,8 @@ struct lsah_n
struct ospf_lsa_header lsa;
};
void ospf_lsack_receive(struct ospf_lsack_packet *ps,
struct ospf_iface *ifa, struct ospf_neighbor *n);
void ospf_lsack_receive(struct ospf_packet *ps_i, struct ospf_iface *ifa,
struct ospf_neighbor *n);
void ospf_lsack_send(struct ospf_neighbor *n, int queue);
void ospf_lsack_enqueue(struct ospf_neighbor *n, struct ospf_lsa_header *h,
int queue);

View file

@ -65,8 +65,8 @@ ospf_age(struct proto_ospf *po)
flush_lsa(en, po);
continue;
}
if ((en->lsa.rt == p->cf->global->router_id) &&(en->lsa.age >=
LSREFRESHTIME))
if ((en->lsa.rt == p->cf->global->router_id) &&
(en->lsa.age >= LSREFRESHTIME))
{
OSPF_TRACE(D_EVENTS, "Refreshing my LSA: Type: %u, Id: %R, Rt: %R",
en->lsa.type, en->lsa.id, en->lsa.rt);
@ -75,7 +75,7 @@ ospf_age(struct proto_ospf *po)
en->inst_t = now;
en->ini_age = 0;
lsasum_calculate(&en->lsa, en->lsa_body);
ospf_lsupd_flood(NULL, NULL, &en->lsa, NULL, en->oa, 1);
ospf_lsupd_flood(po, NULL, NULL, &en->lsa, en->domain, 1);
continue;
}
if ((en->lsa.age = (en->ini_age + (now - en->inst_t))) >= LSA_MAXAGE)
@ -96,7 +96,9 @@ void
htonlsah(struct ospf_lsa_header *h, struct ospf_lsa_header *n)
{
n->age = htons(h->age);
#ifdef OSPFv2
n->options = h->options;
#endif
n->type = h->type;
n->id = htonl(h->id);
n->rt = htonl(h->rt);
@ -109,7 +111,9 @@ void
ntohlsah(struct ospf_lsa_header *n, struct ospf_lsa_header *h)
{
h->age = ntohs(n->age);
#ifdef OSPFv2
h->options = n->options;
#endif
h->type = n->type;
h->id = ntohl(n->id);
h->rt = ntohl(n->rt);
@ -119,7 +123,7 @@ ntohlsah(struct ospf_lsa_header *n, struct ospf_lsa_header *h)
};
void
htonlsab(void *h, void *n, u8 type, u16 len)
htonlsab(void *h, void *n, u16 type, u16 len)
{
unsigned int i;
switch (type)
@ -132,24 +136,43 @@ htonlsab(void *h, void *n, u8 type, u16 len)
nrt = n;
hrt = h;
links = hrt->links;
#ifdef OSPFv2
nrt->veb.byte = hrt->veb.byte;
nrt->padding = 0;
nrt->links = htons(hrt->links);
links = hrt->links;
#else /* OSPFv3 */
hrt->options = htonl(nrt->options);
links = (len - sizeof(struct ospf_lsa_rt)) /
sizeof(struct ospf_lsa_rt_link);
#endif
nrtl = (struct ospf_lsa_rt_link *) (nrt + 1);
hrtl = (struct ospf_lsa_rt_link *) (hrt + 1);
for (i = 0; i < links; i++)
{
(nrtl + i)->id = htonl((hrtl + i)->id);
(nrtl + i)->data = htonl((hrtl + i)->data);
(nrtl + i)->type = (hrtl + i)->type;
(nrtl + i)->notos = (hrtl + i)->notos;
(nrtl + i)->metric = htons((hrtl + i)->metric);
#ifdef OSPFv2
nrtl[i].id = htonl(hrtl[i].id);
nrtl[i].data = htonl(hrtl[i].data);
nrtl[i].type = hrtl[i].type;
nrtl[i].notos = hrtl[i].notos;
nrtl[i].metric = htons(hrtl[i].metric);
#else /* OSPFv3 */
nrtl[i].type = hrtl[i].type;
nrtl[i].padding = 0;
nrtl[i].metric = htons(hrtl[i].metric);
nrtl[i].lif = htonl(hrtl[i].lif);
nrtl[i].nif = htonl(hrtl[i].nif);
nrtl[i].id = htonl(hrtl[i].id);
#endif
}
break;
}
case LSA_T_NET:
case LSA_T_SUM_NET:
case LSA_T_SUM_RT:
case LSA_T_EXT:
{
u32 *hid, *nid;
@ -162,59 +185,14 @@ htonlsab(void *h, void *n, u8 type, u16 len)
}
break;
}
case LSA_T_SUM_NET:
case LSA_T_SUM_RT:
{
struct ospf_lsa_sum *hs, *ns;
union ospf_lsa_sum_tm *hn, *nn;
hs = h;
ns = n;
ns->netmask = hs->netmask;
ipa_hton(ns->netmask);
hn = (union ospf_lsa_sum_tm *) (hs + 1);
nn = (union ospf_lsa_sum_tm *) (ns + 1);
for (i = 0; i < ((len - sizeof(struct ospf_lsa_sum)) /
sizeof(union ospf_lsa_sum_tm)); i++)
{
(nn + i)->metric = htonl((hn + i)->metric);
}
break;
}
case LSA_T_EXT:
{
struct ospf_lsa_ext *he, *ne;
struct ospf_lsa_ext_tos *ht, *nt;
he = h;
ne = n;
ne->netmask = he->netmask;
ipa_hton(ne->netmask);
ht = (struct ospf_lsa_ext_tos *) (he + 1);
nt = (struct ospf_lsa_ext_tos *) (ne + 1);
for (i = 0; i < ((len - sizeof(struct ospf_lsa_ext)) /
sizeof(struct ospf_lsa_ext_tos)); i++)
{
(nt + i)->etm.metric = htonl((ht + i)->etm.metric);
(nt + i)->fwaddr = (ht + i)->fwaddr;
ipa_hton((nt + i)->fwaddr);
(nt + i)->tag = htonl((ht + i)->tag);
}
break;
}
default:
bug("(hton): Unknown LSA");
}
};
void
ntohlsab(void *n, void *h, u8 type, u16 len)
ntohlsab(void *n, void *h, u16 type, u16 len)
{
unsigned int i;
switch (type)
@ -228,22 +206,41 @@ ntohlsab(void *n, void *h, u8 type, u16 len)
nrt = n;
hrt = h;
#ifdef OSPFv2
hrt->veb.byte = nrt->veb.byte;
hrt->padding = 0;
links = hrt->links = ntohs(nrt->links);
#else /* OSPFv3 */
hrt->options = ntohl(nrt->options);
links = (len - sizeof(struct ospf_lsa_rt)) /
sizeof(struct ospf_lsa_rt_link);
#endif
nrtl = (struct ospf_lsa_rt_link *) (nrt + 1);
hrtl = (struct ospf_lsa_rt_link *) (hrt + 1);
for (i = 0; i < links; i++)
{
(hrtl + i)->id = ntohl((nrtl + i)->id);
(hrtl + i)->data = ntohl((nrtl + i)->data);
(hrtl + i)->type = (nrtl + i)->type;
(hrtl + i)->notos = (nrtl + i)->notos;
(hrtl + i)->metric = ntohs((nrtl + i)->metric);
#ifdef OSPFv2
hrtl[i].id = ntohl(nrtl[i].id);
hrtl[i].data = ntohl(nrtl[i].data);
hrtl[i].type = nrtl[i].type;
hrtl[i].notos = nrtl[i].notos;
hrtl[i].metric = ntohs(nrtl[i].metric);
#else /* OSPFv3 */
hrtl[i].type = nrtl[i].type;
hrtl[i].padding = 0;
hrtl[i].metric = ntohs(nrtl[i].metric);
hrtl[i].lif = ntohl(nrtl[i].lif);
hrtl[i].nif = ntohl(nrtl[i].nif);
hrtl[i].id = ntohl(nrtl[i].id);
#endif
}
break;
}
case LSA_T_NET:
case LSA_T_SUM_NET:
case LSA_T_SUM_RT:
case LSA_T_EXT:
{
u32 *hid, *nid;
@ -252,53 +249,7 @@ ntohlsab(void *n, void *h, u8 type, u16 len)
for (i = 0; i < (len / sizeof(u32)); i++)
{
*(hid + i) = ntohl(*(nid + i));
}
break;
}
case LSA_T_SUM_NET:
case LSA_T_SUM_RT:
{
struct ospf_lsa_sum *hs, *ns;
union ospf_lsa_sum_tm *hn, *nn;
hs = h;
ns = n;
hs->netmask = ns->netmask;
ipa_ntoh(hs->netmask);
hn = (union ospf_lsa_sum_tm *) (hs + 1);
nn = (union ospf_lsa_sum_tm *) (ns + 1);
for (i = 0; i < ((len - sizeof(struct ospf_lsa_sum)) /
sizeof(union ospf_lsa_sum_tm)); i++)
{
(hn + i)->metric = ntohl((nn + i)->metric);
}
break;
}
case LSA_T_EXT:
{
struct ospf_lsa_ext *he, *ne;
struct ospf_lsa_ext_tos *ht, *nt;
he = h;
ne = n;
he->netmask = ne->netmask;
ipa_ntoh(he->netmask);
ht = (struct ospf_lsa_ext_tos *) (he + 1);
nt = (struct ospf_lsa_ext_tos *) (ne + 1);
for (i = 0; i < ((len - sizeof(struct ospf_lsa_ext)) /
sizeof(struct ospf_lsa_ext_tos)); i++)
{
(ht + i)->etm.metric = ntohl((nt + i)->etm.metric);
(ht + i)->fwaddr = (nt + i)->fwaddr;
ipa_ntoh((ht + i)->fwaddr);
(ht + i)->tag = ntohl((nt + i)->tag);
hid[i] = ntohl(nid[i]);
}
break;
}
@ -343,7 +294,8 @@ lsasum_check(struct ospf_lsa_header *h, void *body)
u16 length;
b = body;
sp = (char *) &h->options;
sp = (char *) &h;
sp += 2; /* Skip Age field */
length = ntohs(h->length) - 2;
h->checksum = 0;
@ -417,45 +369,40 @@ lsa_comp(struct ospf_lsa_header *l1, struct ospf_lsa_header *l2)
/**
* lsa_install_new - install new LSA into database
* @po: OSPF protocol
* @lsa: LSA header
* @domain: domain of LSA
* @body: pointer to LSA body
* @oa: current ospf_area
*
* This function ensures installing new LSA into LSA database. Old instance is
* replaced. Several actions are taken to detect if new routing table
* calculation is necessary. This is described in 13.2 of RFC 2328.
*/
struct top_hash_entry *
lsa_install_new(struct ospf_lsa_header *lsa, void *body, struct ospf_area *oa)
lsa_install_new(struct proto_ospf *po, struct ospf_lsa_header *lsa, u32 domain, void *body)
{
/* LSA can be temporarrily, but body must be mb_allocated. */
int change = 0;
unsigned i;
struct top_hash_entry *en;
struct proto_ospf *po = oa->po;
if ((en = ospf_hash_find_header(po->gr, oa->areaid, lsa)) == NULL)
if ((en = ospfxx_hash_find_header(po->gr, domain, lsa)) == NULL)
{
en = ospf_hash_get_header(po->gr, oa, lsa);
en = ospfxx_hash_get_header(po->gr, domain, lsa);
change = 1;
}
else
{
if ((en->lsa.length != lsa->length) || (en->lsa.options != lsa->options)
|| ((en->lsa.age == LSA_MAXAGE) || (lsa->age == LSA_MAXAGE)))
if ((en->lsa.length != lsa->length)
#ifdef OSPFv2
|| (en->lsa.options != lsa->options)
#endif
|| (en->lsa.age == LSA_MAXAGE)
|| (lsa->age == LSA_MAXAGE)
|| memcmp(en->lsa_body, body, lsa->length - sizeof(struct ospf_lsa_header)))
change = 1;
else
{
u8 *k = en->lsa_body, *l = body;
for (i = 0; i < (lsa->length - sizeof(struct ospf_lsa_header)); i++)
{
if (*(k + i) != *(l + i))
{
change = 1;
break;
}
}
}
s_rem_node(SNODE en);
}

View file

@ -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);

View file

@ -8,6 +8,14 @@
#include "ospf.h"
struct ospf_lsreq_packet
{
struct ospf_packet ospf_packet;
struct ospf_lsreq_header lsh[];
};
static void ospf_dump_lsreq(struct proto *p, struct ospf_lsreq_packet *pkt)
{
struct ospf_packet *op = &pkt->ospf_packet;
@ -15,15 +23,13 @@ static void ospf_dump_lsreq(struct proto *p, struct ospf_lsreq_packet *pkt)
ASSERT(op->type == LSREQ_P);
ospf_dump_common(p, op);
struct ospf_lsreq_header *plsr = (void *) (pkt + 1);
int i, j;
j = (ntohs(op->length) - sizeof(struct ospf_dbdes_packet)) /
j = (ntohs(op->length) - sizeof(struct ospf_lsreq_packet)) /
sizeof(struct ospf_lsreq_header);
for (i = 0; i < j; i++)
log(L_TRACE "%s: LSR Id: %R, Rt: %R, Type: %u",
p->name, htonl(plsr[i].id), htonl(plsr[i].rt), plsr[i].type);
log(L_TRACE "%s: LSR Id: %R, Rt: %R, Type: %u", p->name,
htonl(pkt->lsh[i].id), htonl(pkt->lsh[i].rt), pkt->lsh[i].type);
}
void
@ -53,14 +59,12 @@ ospf_lsreq_send(struct ospf_neighbor *n)
i = j = (ospf_pkt_maxsize(n->ifa) - sizeof(struct ospf_lsreq_packet)) /
sizeof(struct ospf_lsreq_header);
lsh = (struct ospf_lsreq_header *) (pk + 1);
lsh = pk->lsh;
for (; i > 0; i--)
{
en = (struct top_hash_entry *) sn;
lsh->padd1 = 0;
lsh->padd2 = 0;
lsh->type = en->lsa.type;
lsh->type = htonl(en->lsa.type);
lsh->rt = htonl(en->lsa.rt);
lsh->id = htonl(en->lsa.id);
DBG("Requesting %uth LSA: Type: %u, ID: %R, RT: %R, SN: 0x%x, Age %u\n",
@ -84,9 +88,10 @@ ospf_lsreq_send(struct ospf_neighbor *n)
}
void
ospf_lsreq_receive(struct ospf_lsreq_packet *ps,
struct ospf_iface *ifa, struct ospf_neighbor *n)
ospf_lsreq_receive(struct ospf_packet *ps_i, struct ospf_iface *ifa,
struct ospf_neighbor *n)
{
struct ospf_lsreq_packet *ps = (void *) ps_i;
struct ospf_lsreq_header *lsh;
struct l_lsr_head *llsh;
list uplist;
@ -104,7 +109,7 @@ ospf_lsreq_receive(struct ospf_lsreq_packet *ps,
ospf_neigh_sm(n, INM_HELLOREC);
lsh = (void *) (ps + 1);
lsh = ps->lsh;
init_list(&uplist);
upslab = sl_new(n->pool, sizeof(struct l_lsr_head));
@ -114,18 +119,19 @@ ospf_lsreq_receive(struct ospf_lsreq_packet *ps,
{
u32 hid = ntohl(lsh->id);
u32 hrt = ntohl(lsh->rt);
u32 htype = ntohl(lsh->type);
u32 dom = ospf_lsa_domain(htype, ifa);
DBG("Processing requested LSA: Type: %u, ID: %R, RT: %R\n", lsh->type, hid, hrt);
llsh = sl_alloc(upslab);
llsh->lsh.id = hid;
llsh->lsh.rt = hrt;
llsh->lsh.type = lsh->type;
llsh->lsh.type = htype;
add_tail(&uplist, NODE llsh);
if (ospf_hash_find(po->gr, oa->areaid, llsh->lsh.id, llsh->lsh.rt,
llsh->lsh.type) == NULL)
if (ospfxx_hash_find(po->gr, dom, hid, hrt, htype) == NULL)
{
log(L_WARN
"Received bad LS req from: %I looking: Type: %u, ID: %R, RT: %R",
n->ip, lsh->type, hid, hrt);
n->ip, htype, hid, hrt);
ospf_neigh_sm(n, INM_BADLSREQ);
rfree(upslab);
return;

View file

@ -11,7 +11,7 @@
#define _BIRD_OSPF_LSREQ_H_
void ospf_lsreq_send(struct ospf_neighbor *n);
void ospf_lsreq_receive(struct ospf_lsreq_packet *ps,
struct ospf_iface *ifa, struct ospf_neighbor *n);
void ospf_lsreq_receive(struct ospf_packet *ps_i, struct ospf_iface *ifa,
struct ospf_neighbor *n);
#endif /* _BIRD_OSPF_LSREQ_H_ */

View file

@ -9,6 +9,13 @@
#include "ospf.h"
struct ospf_lsupd_packet
{
struct ospf_packet ospf_packet;
u32 lsano; /* Number of LSA's */
};
void ospf_dump_lsahdr(struct proto *p, struct ospf_lsa_header *lsa_n)
{
struct ospf_lsa_header lsa;
@ -51,27 +58,79 @@ static void ospf_dump_lsupd(struct proto *p, struct ospf_lsupd_packet *pkt)
}
}
#ifdef OSPFv2
int
ospf_lsa_flooding_allowed(struct ospf_lsa_header *lsa, u32 domain, struct ospf_iface *ifa)
{
if (lsa->type == LSA_T_EXT)
{
if (ifa->type == OSPF_IT_VLINK)
return 0;
if (ifa->oa->stub)
return 0;
return 1
}
else
return ifa->oa->areaid == domain;
}
#else /* OSPFv3 */
int
ospf_lsa_flooding_allowed(struct ospf_lsa_header *lsa, u32 domain, struct ospf_iface *ifa)
{
u32 scope = LSA_SCOPE(lsa);
/* 4.5.2 (Case 2) */
if (unknown_type(lsa) && !(lsa->type & LSA_UBIT))
scope = LSA_SCOPE_LINK;
switch (scope)
{
case LSA_SCOPE_LINK:
return ifa->iface->index == domain;
case LSA_SCOPE_AREA:
return ifa->oa->areaid == domain;
case LSA_SCOPE_AS:
if (ifa->type == OSPF_IT_VLINK)
return 0;
if (ifa->oa->stub)
return 0;
return 1;
default:
log(L_ERR "LSA with invalid scope");
return 0;
}
}
#endif
/**
* ospf_lsupd_flood - send received or generated lsa to the neighbors
* @po: OSPF protocol
* @n: neighbor than sent this lsa (or NULL if generated)
* @hn: LSA header followed by lsa body in network endianity (may be NULL)
* @hh: LSA header in host endianity (must be filled)
* @iff: interface which received this LSA (or NULL if LSA is generated)
* @oa: ospf_area which is the LSA generated for
* @domain: domain of LSA (must be filled)
* @rtl: add this LSA into retransmission list
*
*
* return value - was the LSA flooded back?
*/
int
ospf_lsupd_flood(struct ospf_neighbor *n, struct ospf_lsa_header *hn,
struct ospf_lsa_header *hh, struct ospf_iface *iff,
struct ospf_area *oa, int rtl)
ospf_lsupd_flood(struct proto_ospf *po,
struct ospf_neighbor *n, struct ospf_lsa_header *hn,
struct ospf_lsa_header *hh, u32 domain, int rtl)
{
struct ospf_iface *ifa;
struct ospf_neighbor *nn;
struct top_hash_entry *en;
struct proto_ospf *po = oa->po;
struct proto *p = &po->proto;
int ret, retval = 0;
@ -81,18 +140,8 @@ ospf_lsupd_flood(struct ospf_neighbor *n, struct ospf_lsa_header *hn,
if (ifa->stub)
continue;
if (hh->type == LSA_T_EXT)
{
if (ifa->type == OSPF_IT_VLINK)
continue;
if (ifa->oa->stub)
continue;
}
else
{
if (ifa->oa != oa)
continue;
}
if (! ospf_lsa_flooding_allowed(hh, domain, ifa))
continue;
DBG("Wanted to flood LSA: Type: %u, ID: %R, RT: %R, SN: 0x%x, Age %u\n",
hh->type, hh->id, hh->rt, hh->sn, hh->age);
@ -100,11 +149,14 @@ ospf_lsupd_flood(struct ospf_neighbor *n, struct ospf_lsa_header *hn,
ret = 0;
WALK_LIST(nn, ifa->neigh_list)
{
/* 13.3 (1a) */
if (nn->state < NEIGHBOR_EXCHANGE)
continue;
/* 13.3 (1b) */
if (nn->state < NEIGHBOR_FULL)
{
if ((en = ospf_hash_find_header(nn->lsrqh, nn->ifa->oa->areaid, hh)) != NULL)
if ((en = ospfxx_hash_find_header(nn->lsrqh, domain, hh)) != NULL)
{
DBG("That LSA found in lsreq list for neigh %R\n", nn->rid);
@ -140,14 +192,20 @@ ospf_lsupd_flood(struct ospf_neighbor *n, struct ospf_lsa_header *hn,
}
}
/* 13.3 (1c) */
if (nn == n)
continue;
/* 13.3 (1d) */
if (rtl)
{
if ((en = ospf_hash_find_header(nn->lsrth, nn->ifa->oa->areaid, hh)) == NULL)
/* In OSPFv3, there should be check whether receiving router understand
that type of LSA (for LSA types with U-bit == 0). But as we does not support
any optional LSA types, this is not needed yet */
if ((en = ospfxx_hash_find_header(nn->lsrth, domain, hh)) == NULL)
{
en = ospf_hash_get_header(nn->lsrth, nn->ifa->oa, hh);
en = ospfxx_hash_get_header(nn->lsrth, domain, hh);
}
else
{
@ -159,7 +217,7 @@ ospf_lsupd_flood(struct ospf_neighbor *n, struct ospf_lsa_header *hn,
}
else
{
if ((en = ospf_hash_find_header(nn->lsrth, nn->ifa->oa->areaid, hh)) != NULL)
if ((en = ospfxx_hash_find_header(nn->lsrth, domain, hh)) != NULL)
{
s_rem_node(SNODE en);
if (en->lsa_body != NULL)
@ -175,11 +233,11 @@ ospf_lsupd_flood(struct ospf_neighbor *n, struct ospf_lsa_header *hn,
if (ret == 0)
continue; /* pg 150 (2) */
if (ifa == iff)
if (n && (n->ifa == ifa))
{
if ((n->rid == iff->drid) || n->rid == iff->bdrid)
if ((n->rid == ifa->drid) || n->rid == ifa->bdrid)
continue; /* pg 150 (3) */
if (iff->state == OSPF_IS_BACKUP)
if (ifa->state == OSPF_IS_BACKUP)
continue; /* pg 150 (4) */
retval = 1;
}
@ -216,7 +274,7 @@ ospf_lsupd_flood(struct ospf_neighbor *n, struct ospf_lsa_header *hn,
htonlsah(hh, lh);
help = (u8 *) (lh + 1);
en = ospf_hash_find_header(po->gr, oa->areaid, hh);
en = ospfxx_hash_find_header(po->gr, domain, hh);
htonlsab(en->lsa_body, help, hh->type, hh->length
- sizeof(struct ospf_lsa_header));
}
@ -288,8 +346,9 @@ ospf_lsupd_send_list(struct ospf_neighbor *n, list * l)
WALK_LIST(llsh, *l)
{
if ((en = ospf_hash_find(po->gr, oa->areaid, llsh->lsh.id, llsh->lsh.rt,
llsh->lsh.type)) == NULL)
u32 domain = ospf_lsa_domain(llsh->lsh.type, n->ifa);
if ((en = ospfxx_hash_find(po->gr, domain, llsh->lsh.id,
llsh->lsh.rt, llsh->lsh.type)) == NULL)
continue; /* Probably flushed LSA */
/* FIXME This is a bug! I cannot flush LSA that is in lsrt */
@ -330,13 +389,12 @@ ospf_lsupd_send_list(struct ospf_neighbor *n, list * l)
}
void
ospf_lsupd_receive(struct ospf_lsupd_packet *ps,
struct ospf_iface *ifa, struct ospf_neighbor *n)
ospf_lsupd_receive(struct ospf_packet *ps_i, struct ospf_iface *ifa,
struct ospf_neighbor *n)
{
u32 area;
struct ospf_lsupd_packet *ps = (void *) ps_i;
struct ospf_neighbor *ntmp;
struct ospf_lsa_header *lsa;
struct ospf_area *oa;
struct proto_ospf *po = ifa->oa->po;
struct proto *p = &po->proto;
unsigned int i, sendreq = 1, size = ntohs(ps->ospf_packet.length);
@ -359,8 +417,6 @@ ospf_lsupd_receive(struct ospf_lsupd_packet *ps,
ospf_neigh_sm(n, INM_HELLOREC); /* Questionable */
lsa = (struct ospf_lsa_header *) (ps + 1);
area = htonl(ps->ospf_packet.areaid);
oa = ospf_find_area((struct proto_ospf *) p, area);
for (i = 0; i < ntohl(ps->lsano); i++,
lsa = (struct ospf_lsa_header *) (((u8 *) lsa) + ntohs(lsa->length)))
@ -394,6 +450,8 @@ ospf_lsupd_receive(struct ospf_lsupd_packet *ps,
continue;
}
#ifdef OSPFv2
/* pg 143 (2) */
if ((lsa->type < LSA_T_RT) || (lsa->type > LSA_T_EXT))
{
@ -402,18 +460,34 @@ ospf_lsupd_receive(struct ospf_lsupd_packet *ps,
}
/* pg 143 (3) */
if ((lsa->type == LSA_T_EXT) && oa->stub)
if ((lsa->type == LSA_T_EXT) && ifa->oa->stub)
{
log(L_WARN "Received External LSA in stub area from %I", n->ip);
continue;
}
#else /* OSPFv3 */
/* 4.5.1 (2) */
if ((LSA_SCOPE(lsa) == LSA_SCOPE_AS) && ifa->oa->stub)
{
log(L_WARN "Received LSA with AS scope in stub area from %I", n->ip);
continue;
}
/* 4.5.1 (3) */
if ((LSA_SCOPE(lsa) == LSA_SCOPE_RES))
{
log(L_WARN "Received LSA with invalid scope from %I", n->ip);
continue;
}
#endif
ntohlsah(lsa, &lsatmp);
DBG("Update Type: %u ID: %R RT: %R, Sn: 0x%08x Age: %u, Sum: %u\n",
lsatmp.type, lsatmp.id, lsatmp.rt, lsatmp.sn, lsatmp.age, lsatmp.checksum);
lsadb = ospf_hash_find_header(po->gr, oa->areaid, &lsatmp);
u32 domain = ospf_lsa_domain(lsatmp.type, ifa);
lsadb = ospfxx_hash_find_header(po->gr, domain, &lsatmp);
#ifdef LOCAL_DEBUG
if (lsadb)
@ -439,7 +513,8 @@ ospf_lsupd_receive(struct ospf_lsupd_packet *ps,
DBG("PG143(5): Received LSA is newer\n");
/* pg 145 (5f) - premature aging of self originated lsa */
#ifdef OSPFv2
/* 13.4 - check self-originated LSAs of NET type */
if ((!self) && (lsatmp.type == LSA_T_NET))
{
WALK_LIST(nifa, po->iface_list)
@ -453,7 +528,9 @@ ospf_lsupd_receive(struct ospf_lsupd_packet *ps,
}
}
}
#endif
/* pg 145 (5f) - premature aging of self originated lsa */
if (self)
{
struct top_hash_entry *en;
@ -473,10 +550,10 @@ ospf_lsupd_receive(struct ospf_lsupd_packet *ps,
lsatmp.type, lsatmp.id, lsatmp.rt);
lsasum_check(lsa, (lsa + 1)); /* It also calculates chsum! */
lsatmp.checksum = ntohs(lsa->checksum);
ospf_lsupd_flood(NULL, lsa, &lsatmp, NULL, oa, 0);
if (en = ospf_hash_find_header(po->gr, oa->areaid, &lsatmp))
{
ospf_lsupd_flood(NULL, NULL, &en->lsa, NULL, oa, 1);
ospf_lsupd_flood(po, NULL, lsa, &lsatmp, domain, 0);
if (en = ospfxx_hash_find_header(po->gr, domain, &lsatmp))
{ /* FIXME verify hacks */
ospf_lsupd_flood(po, NULL, NULL, &en->lsa, domain, 1);
}
continue;
}
@ -489,7 +566,7 @@ ospf_lsupd_receive(struct ospf_lsupd_packet *ps,
continue;
}
if (ospf_lsupd_flood(n, lsa, &lsatmp, ifa, ifa->oa, 1) == 0)
if (ospf_lsupd_flood(po, n, lsa, &lsatmp, domain, 1) == 0)
{
DBG("Wasn't flooded back\n"); /* ps 144(5e), pg 153 */
if (ifa->state == OSPF_IS_BACKUP)
@ -509,7 +586,7 @@ ospf_lsupd_receive(struct ospf_lsupd_packet *ps,
{
struct top_hash_entry *en;
if (ntmp->state > NEIGHBOR_EXSTART)
if ((en = ospf_hash_find_header(ntmp->lsrth, ntmp->ifa->oa->areaid, &lsadb->lsa)) != NULL)
if ((en = ospfxx_hash_find_header(ntmp->lsrth, domain, &lsadb->lsa)) != NULL)
{
s_rem_node(SNODE en);
if (en->lsa_body != NULL)
@ -532,7 +609,7 @@ ospf_lsupd_receive(struct ospf_lsupd_packet *ps,
mb_alloc(p->pool, lsatmp.length - sizeof(struct ospf_lsa_header));
ntohlsab(lsa + 1, body, lsatmp.type,
lsatmp.length - sizeof(struct ospf_lsa_header));
lsadb = lsa_install_new(&lsatmp, body, oa);
lsadb = lsa_install_new(po, &lsatmp, domain, body);
DBG("New LSA installed in DB\n");
continue;
@ -545,7 +622,7 @@ ospf_lsupd_receive(struct ospf_lsupd_packet *ps,
{
struct top_hash_entry *en;
DBG("PG145(7) Got the same LSA\n");
if ((en = ospf_hash_find_header(n->lsrth, n->ifa->oa->areaid, &lsadb->lsa)) != NULL)
if ((en = ospfxx_hash_find_header(n->lsrth, lsadb->domain, &lsadb->lsa)) != NULL)
{
/* pg145 (7a) */
s_rem_node(SNODE en);
@ -596,10 +673,9 @@ ospf_lsupd_receive(struct ospf_lsupd_packet *ps,
}
void
ospf_lsupd_flush_nlsa(struct top_hash_entry *en, struct ospf_area *oa)
ospf_lsupd_flush_nlsa(struct proto_ospf *po, struct top_hash_entry *en)
{
struct ospf_lsa_header *lsa = &en->lsa;
struct proto_ospf *po = oa->po;
struct proto *p = &po->proto;
lsa->age = LSA_MAXAGE;
@ -607,5 +683,5 @@ ospf_lsupd_flush_nlsa(struct top_hash_entry *en, struct ospf_area *oa)
lsasum_calculate(lsa, en->lsa_body);
OSPF_TRACE(D_EVENTS, "Premature aging self originated lsa!");
OSPF_TRACE(D_EVENTS, "Type: %d, Id: %R, Rt: %R", lsa->type, lsa->id, lsa->rt);
ospf_lsupd_flood(NULL, NULL, lsa, NULL, oa, 0);
ospf_lsupd_flood(po, NULL, NULL, lsa, en->domain, 0);
}

View file

@ -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_ */

View file

@ -171,16 +171,23 @@ static struct ospf_neighbor *
electbdr(list nl)
{
struct ospf_neighbor *neigh, *n1, *n2;
u32 nid;
#ifdef OSPFv2
nid = ipa_to_u32(neigh->ip);
#else /* OSPFv3 */
nid = neigh->rid;
#endif
n1 = NULL;
n2 = NULL;
WALK_LIST(neigh, nl) /* First try those decl. themselves */
WALK_LIST(neigh, nl) /* First try those decl. themselves */
{
if (neigh->state >= NEIGHBOR_2WAY) /* Higher than 2WAY */
if (neigh->priority > 0) /* Eligible */
if (ipa_compare(neigh->ip, neigh->dr) != 0) /* And not decl. itself DR */
if (neigh->priority > 0) /* Eligible */
if (neigh->dr != nid) /* And not decl. itself DR */
{
if (ipa_compare(neigh->ip, neigh->bdr) == 0) /* Declaring BDR */
if (neigh->bdr == nid) /* Declaring BDR */
{
if (n1 != NULL)
{
@ -222,13 +229,20 @@ static struct ospf_neighbor *
electdr(list nl)
{
struct ospf_neighbor *neigh, *n;
u32 nid;
#ifdef OSPFv2
nid = ipa_to_u32(neigh->ip);
#else /* OSPFv3 */
nid = neigh->rid;
#endif
n = NULL;
WALK_LIST(neigh, nl) /* And now DR */
WALK_LIST(neigh, nl) /* And now DR */
{
if (neigh->state >= NEIGHBOR_2WAY) /* Higher than 2WAY */
if (neigh->priority > 0) /* Eligible */
if (ipa_compare(neigh->ip, neigh->dr) == 0) /* And declaring itself DR */
if (neigh->priority > 0) /* Eligible */
if (neigh->dr == nid) /* And declaring itself DR */
{
if (n != NULL)
{
@ -427,7 +441,6 @@ bdr_election(struct ospf_iface *ifa)
{
struct ospf_neighbor *neigh, *ndr, *nbdr, me;
u32 myid;
ip_addr ndrip, nbdrip;
int doadj;
struct proto *p = &ifa->oa->po->proto;
@ -438,10 +451,17 @@ bdr_election(struct ospf_iface *ifa)
me.state = NEIGHBOR_2WAY;
me.rid = myid;
me.priority = ifa->priority;
me.dr = ifa->drip;
me.bdr = ifa->bdrip;
me.ip = ifa->iface->addr->ip;
#ifdef OSPFv2
me.dr = ipa_to_u32(ifa->drip);
me.bdr = ipa_to_u32(ifa->bdrip);
#else /* OSPFv3 */
me.dr = ifa->drid;
me.bdr = ifa->bdrid;
me.iface_id = ifa->iface->index;
#endif
add_tail(&ifa->neigh_list, NODE & me);
nbdr = electbdr(ifa->neigh_list);
@ -450,64 +470,43 @@ bdr_election(struct ospf_iface *ifa)
if (ndr == NULL)
ndr = nbdr;
/* 9.4. (4) */
if (((ifa->drid == myid) && (ndr != &me))
|| ((ifa->drid != myid) && (ndr == &me))
|| ((ifa->bdrid == myid) && (nbdr != &me))
|| ((ifa->bdrid != myid) && (nbdr == &me)))
{
if (ndr == NULL)
ifa->drip = me.dr = IPA_NONE;
else
ifa->drip = me.dr = ndr->ip;
if (nbdr == NULL)
ifa->bdrip = me.bdr = IPA_NONE;
else
ifa->bdrip = me.bdr = nbdr->ip;
#ifdef OSPFv2
me.dr = ndr ? ipa_to_u32(ndr->ip) : IPA_NONE;
me.bdr = nbdr ? ipa_to_u32(nbdr->ip) : IPA_NONE;
#else /* OSPFv3 */
me.dr = ndr ? ndr->rid : 0;
me.bdr = nbdr ? nbdr->rid : 0;
#endif
nbdr = electbdr(ifa->neigh_list);
ndr = electdr(ifa->neigh_list);
if (ndr == NULL)
ndr = nbdr;
}
if (ndr == NULL)
ndrip = IPA_NONE;
else
ndrip = ndr->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;
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 (nbdr == NULL)
{
ifa->bdrid = 0;
ifa->bdrip = IPA_NONE;
}
else
{
ifa->bdrid = nbdr->rid;
ifa->bdrip = nbdr->ip;
}
#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

View file

@ -163,8 +163,11 @@ ospf_start(struct proto *p)
oa->stub = 0;
}
oa->opt.byte = 0;
if(!oa->stub) oa->opt.bit.e = 1;
#ifdef OSPFv2
oa->options = (oa->stub ? 0 : OPT_E);
#else /* OSPFv3 */
oa->options = OPT_R | (oa->stub ? 0 : OPT_E) | OPT_V6;
#endif
}
/* Add all virtual links as interfaces */
@ -186,8 +189,11 @@ ospf_start(struct proto *p)
fib_init(&oa->net_fib, p->pool, sizeof(struct area_net), 16, ospf_area_initfib);
fib_init(&oa->rtr, p->pool, sizeof(ort), 16, ospf_rt_initort);
po->backbone = oa;
oa->opt.byte = 0;
oa->opt.bit.e = 1;
#ifdef OSPFv2
oa->options = OPT_E;
#else /* OSPFv3 */
oa->options = OPT_R | OPT_E | OPT_V6;
#endif
}
ospf_iface_new(po, NULL, ac, ipatt);
}
@ -448,36 +454,9 @@ ospf_rt_notify(struct proto *p, net * n, rte * new, rte * old UNUSED,
*/
if (new) /* Got some new route */
{
originate_ext_lsa(n, new, po, attrs);
}
else
{
u32 rtid = po->proto.cf->global->router_id;
struct ospf_area *oa;
struct top_hash_entry *en;
u32 pr = ipa_to_u32(n->n.prefix);
struct ospf_lsa_ext *ext;
int i;
int max = max_ext_lsa(n->n.pxlen);
/* Flush old external LSA */
for (i = 0; i < max; i++, pr++)
{
if (en = ospf_hash_find(po->gr, 0, pr, rtid, LSA_T_EXT))
{
ext = en->lsa_body;
if (ipa_compare(ext->netmask, ipa_mkmask(n->n.pxlen)) == 0)
{
WALK_LIST(oa, po->area_list)
{
ospf_lsupd_flush_nlsa(en, oa);
}
}
break;
}
}
}
flush_ext_lsa(n, po);
}
static void
@ -762,6 +741,7 @@ ospf_reconfigure(struct proto *p, struct proto_config *c)
"Interface %s is no longer stub.", ifa->iface->name);
}
#ifdef OSPFv2
/* AUTHENTICATION */
if (oldip->autype != newip->autype)
{
@ -772,6 +752,7 @@ ospf_reconfigure(struct proto *p, struct proto_config *c)
}
/* Add *passwords */
ifa->passwords = newip->passwords;
#endif
/* priority */
if (oldip->priority != newip->priority)
@ -1076,24 +1057,24 @@ he_compare(const void *p1, const void *p2)
return lsa1->age - lsa2->age;
}
}
/*
static inline void
show_lsa_router(struct top_hash_entry *he)
{
struct ospf_lsa_header *lsa = &(he->lsa);
struct ospf_lsa_rt *rt = he->lsa_body;
struct ospf_lsa_rt_link *rr = (struct ospf_lsa_rt_link *) (rt + 1);
u32 i;
int max = lsa_rt_count(lsa);
for (i = 0; i < rt->links; i++)
for (i = 0; i < max; i++)
if (rr[i].type == LSART_PTP)
cli_msg(-1016, "\t\trouter %R metric %u ", rr[i].id, rr[i].metric);
for (i = 0; i < rt->links; i++)
for (i = 0; i < max; i++)
if (rr[i].type == LSART_NET)
{
struct proto_ospf *po = he->oa->po;
struct top_hash_entry *net_he = ospf_hash_find(po->gr, he->oa->areaid, rr[i].id, rr[i].id, LSA_T_NET);
struct top_hash_entry *net_he = ospfxx_hash_find(po->gr, he->oa->areaid, rr[i].id, rr[i].id, LSA_T_NET);
if (net_he)
{
struct ospf_lsa_header *net_lsa = &(net_he->lsa);
@ -1104,11 +1085,11 @@ show_lsa_router(struct top_hash_entry *he)
cli_msg(-1016, "\t\tnetwork ??? metric %u ", rr[i].metric);
}
for (i = 0; i < rt->links; i++)
for (i = 0; i < max; i++)
if (rr[i].type == LSART_STUB)
cli_msg(-1016, "\t\tstubnet %I/%d metric %u ", ipa_from_u32(rr[i].id), ipa_mklen(ipa_from_u32(rr[i].data)), rr[i].metric);
for (i = 0; i < rt->links; i++)
for (i = 0; i < max; i++)
if (rr[i].type == LSART_VLNK)
cli_msg(-1016, "\t\tvlink %I metric %u ", ipa_from_u32(rr[i].id), rr[i].metric);
}
@ -1119,14 +1100,13 @@ show_lsa_network(struct top_hash_entry *he)
struct ospf_lsa_header *lsa = &(he->lsa);
struct ospf_lsa_net *ln = he->lsa_body;
u32 *rts = (u32 *) (ln + 1);
u32 max = (lsa->length - sizeof(struct ospf_lsa_header) - sizeof(struct ospf_lsa_net)) / sizeof(u32);
u32 i;
cli_msg(-1016, "");
cli_msg(-1016, "\tnetwork %I/%d", ipa_and(ipa_from_u32(lsa->id), ln->netmask), ipa_mklen(ln->netmask));
cli_msg(-1016, "\t\tdr %R", lsa->rt);
for (i = 0; i < max; i++)
for (i = 0; i < lsa_net_count(lsa); i++)
cli_msg(-1016, "\t\trouter %R", rts[i]);
}
@ -1168,7 +1148,7 @@ show_lsa_external(struct top_hash_entry *he)
et->etm.metric & METRIC_MASK, str_via, str_tag);
}
*/
void
ospf_sh_state(struct proto *p, int verbose)
{
@ -1177,7 +1157,7 @@ ospf_sh_state(struct proto *p, int verbose)
unsigned int i, j;
u32 last_rt = 0xFFFFFFFF;
u32 last_area = 0xFFFFFFFF;
/*
if (p->proto_state != PS_UP)
{
cli_msg(-1016, "%s: is not up", p->name);
@ -1240,7 +1220,7 @@ ospf_sh_state(struct proto *p, int verbose)
break;
}
}
*/
cli_msg(0, "");
}

View file

@ -49,13 +49,17 @@ do { if ((p->debug & D_PACKETS) || OSPF_FORCE_DEBUG) \
#include "lib/string.h"
#define OSPF_PROTO 89
#ifndef IPV6
#define OSPFv2 1
#define OSPF_VERSION 2
#define AllSPFRouters ipa_from_u32(0xe0000005) /* 224.0.0.5 */
#define AllDRouters ipa_from_u32(0xe0000006) /* 224.0.0.6 */
#define DEFAULTDES ipa_from_u32(0)
#else
#error OSPF for IPv6 is not implemented (mail to Feela <feela@network.cz>)
#define OSPFv3 1
#define OSPF_VERSION 3
#define AllSPFRouters _MI(0xFF020000, 0, 0, 5) /* FF02::5 */
#define AllDRouters _MI(0xFF020000, 0, 0, 6) /* FF02::6 */
#endif
@ -118,32 +122,37 @@ struct ospf_area_config
list stubnet_list;
};
struct obits
{
#ifdef CPU_BIG_ENDIAN
u8 unused2:2;
u8 dc:1;
u8 ea:1;
u8 np:1;
u8 mc:1;
u8 e:1;
u8 unused1:1;
#else
u8 unused1:1;
u8 e:1;
u8 mc:1;
u8 np:1;
u8 ea:1;
u8 dc:1;
u8 unused2:2;
#endif
};
union options
{
u8 byte;
struct obits bit;
};
/* 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
#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;
#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;
};
/* Area IDs */
#define BACKBONE 0
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;
u8 padding;
u16 metric;
};
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
{
u32 options;
u32 routers[];
};
struct ospf_lsa_sum_net
{
u32 metric;
u32 prefix[];
};
struct ospf_lsa_sum_rt
{
u32 options;
u32 metric;
u32 drid;
};
struct ospf_lsa_ext
{
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,

View file

@ -24,21 +24,37 @@ ospf_pkt_fill_hdr(struct ospf_iface *ifa, void *buf, u8 h_type)
pkt->routerid = htonl(p->cf->global->router_id);
pkt->areaid = htonl(ifa->oa->areaid);
#ifdef OSPFv3
pkt->instance_id = ifa->instance_id;
#endif
#ifdef OSPFv2
pkt->autype = htons(ifa->autype);
#endif
pkt->checksum = 0;
}
unsigned
ospf_pkt_maxsize(struct ospf_iface *ifa)
{
/* For virtual links use mtu=576, can be mtu < 576? */
unsigned mtu = (ifa->type == OSPF_IT_VLINK) ? OSPF_VLINK_MTU : ifa->iface->mtu;
/* Can be mtu < 576? */
unsigned add = 0;
#ifdef OSPFv2
add = ((ifa->autype == OSPF_AUTH_CRYPT) ? OSPF_AUTH_CRYPT_SIZE : 0);
#endif
return ((mtu <= ifa->iface->mtu) ? mtu : ifa->iface->mtu) -
SIZE_OF_IP_HEADER - ((ifa->autype == OSPF_AUTH_CRYPT) ? OSPF_AUTH_CRYPT_SIZE : 0);
/* For virtual links use mtu=576 */
SIZE_OF_IP_HEADER - add;
}
void
#ifdef OSPFv2
static void
ospf_pkt_finalize(struct ospf_iface *ifa, struct ospf_packet *pkt)
{
struct password_item *passwd = NULL;
@ -224,6 +240,20 @@ ospf_pkt_checkauth(struct ospf_neighbor *n, struct ospf_iface *ifa, struct ospf_
}
}
#else
/* OSPFv3 authentication not yet supported */
static inline void
ospf_pkt_finalize(struct ospf_iface *ifa, struct ospf_packet *pkt)
{ }
static int
ospf_pkt_checkauth(struct ospf_neighbor *n, struct ospf_iface *ifa, struct ospf_packet *pkt, int size)
{ return 1; }
#endif
/**
* ospf_rx_hook
* @sk: socket we received the packet. Its ignored.
@ -290,6 +320,8 @@ ospf_rx_hook(sock * sk, int size)
return 1;
}
/* FIXME - handle checksums in OSPFv3 */
#ifdef OSPFv2
if ((ps->autype != htons(OSPF_AUTH_CRYPT)) &&
(!ipsum_verify(ps, 16, (void *) ps + sizeof(struct ospf_packet),
ntohs(ps->length) - sizeof(struct ospf_packet), NULL)))
@ -297,13 +329,23 @@ ospf_rx_hook(sock * sk, int size)
log(L_ERR "%s%I - bad checksum", mesg, sk->faddr);
return 1;
}
#endif
if (ntohl(ps->areaid) != ifa->oa->areaid)
{
log(L_ERR "%s%I - different area %ld", mesg, sk->faddr, ntohl(ps->areaid));
log(L_ERR "%s%I - different area (%u)", mesg, sk->faddr, ntohl(ps->areaid));
return 1;
}
/* FIXME - handling of instance id should be better */
#ifdef OSPFv3
if (ps->instance_id != ifa->instance_id)
{
log(L_ERR "%s%I - different instance (%u)", mesg, sk->faddr, ps->instance_id);
return 1;
}
#endif
if (ntohl(ps->routerid) == p->cf->global->router_id)
{
log(L_ERR "%s%I - received my own router ID!", mesg, sk->faddr);
@ -352,23 +394,23 @@ ospf_rx_hook(sock * sk, int size)
{
case HELLO_P:
DBG("%s: Hello received.\n", p->name);
ospf_hello_receive((struct ospf_hello_packet *) ps, ifa, n, sk->faddr);
ospf_hello_receive(ps, ifa, n, sk->faddr);
break;
case DBDES_P:
DBG("%s: Database description received.\n", p->name);
ospf_dbdes_receive((struct ospf_dbdes_packet *) ps, ifa, n);
ospf_dbdes_receive(ps, ifa, n);
break;
case LSREQ_P:
DBG("%s: Link state request received.\n", p->name);
ospf_lsreq_receive((struct ospf_lsreq_packet *) ps, ifa, n);
ospf_lsreq_receive(ps, ifa, n);
break;
case LSUPD_P:
DBG("%s: Link state update received.\n", p->name);
ospf_lsupd_receive((struct ospf_lsupd_packet *) ps, ifa, n);
ospf_lsupd_receive(ps, ifa, n);
break;
case LSACK_P:
DBG("%s: Link state ack received.\n", p->name);
ospf_lsack_receive((struct ospf_lsack_packet *) ps, ifa, n);
ospf_lsack_receive(ps, ifa, n);
break;
default:
log(L_ERR "%s%I - wrong type %u", mesg, sk->faddr, ps->type);
@ -416,9 +458,14 @@ void
ospf_send_to(sock *sk, ip_addr ip, struct ospf_iface *ifa)
{
struct ospf_packet *pkt = (struct ospf_packet *) sk->tbuf;
int len = ntohs(pkt->length) + ((ifa->autype == OSPF_AUTH_CRYPT) ? OSPF_AUTH_CRYPT_SIZE : 0);
ospf_pkt_finalize(ifa, pkt);
int len = ntohs(pkt->length);
#ifdef OSPFv2
if (ifa->autype == OSPF_AUTH_CRYPT)
len += OSPF_AUTH_CRYPT_SIZE;
#endif
ospf_pkt_finalize(ifa, pkt);
if (sk->tbuf != sk->tpos)
log(L_ERR "Aiee, old packet was overwritted in TX buffer");

View file

@ -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);
}
else if (en->lsa.type == LSA_T_SUM_RT)
{
#ifdef OSPFv2
struct ospf_lsa_sum *ls = en->lsa_body;
dst_rid = en->lsa.id;
options = 0;
#else /* OSPFv3 */
struct ospf_lsa_sum_rt *ls = en->lsa_body;
dst_rid = ls->drid;
options = ls->options & OPTIONS_MASK;
#endif
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, pxlen);
}
if (en->lsa.type == LSA_T_SUM_RT)
{
ip = ipa_from_u32(en->lsa.id);
mlen = 32;
type = ORT_ROUTER;
re = (ort *) fib_find(&bb->rtr, &ip, 32);
}
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);
}
}

View file

@ -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;

File diff suppressed because it is too large Load diff

View file

@ -13,12 +13,11 @@ struct top_hash_entry
{ /* Index for fast mapping (type,rtrid,LSid)->vertex */
snode n;
node cn; /* For adding into list of candidates
* in intra-area routing table
* calculation
*/
in intra-area routing table calculation */
struct top_hash_entry *next; /* Next in hash chain */
struct ospf_lsa_header lsa;
struct ospf_area *oa;
u32 domain; /* Area ID for area-wide LSAs, Iface ID for link-wide LSAs */
// struct ospf_area *oa;
void *lsa_body;
bird_clock_t inst_t; /* Time of installation into DB */
ip_addr nh; /* Next hop */
@ -48,13 +47,19 @@ struct top_graph
struct top_graph *ospf_top_new(pool *);
void ospf_top_free(struct top_graph *);
void ospf_top_dump(struct top_graph *, struct proto *);
struct top_hash_entry *ospf_hash_find_header(struct top_graph *f, u32 areaid,
struct top_hash_entry *ospfxx_hash_find_header(struct top_graph *f, u32 areaid,
struct ospf_lsa_header *h);
struct top_hash_entry *ospf_hash_get_header(struct top_graph *f, struct ospf_area *oa,
struct top_hash_entry *ospfxx_hash_get_header(struct top_graph *f, u32 domain,
struct ospf_lsa_header *h);
struct top_hash_entry *ospf_hash_find(struct top_graph *, u32 areaid, u32 lsa, u32 rtr,
struct top_hash_entry *ospfxx_hash_find_smart(struct top_graph *f, struct ospf_iface *ifa,
struct ospf_lsa_header *h);
struct top_hash_entry *ospfxx_hash_get_smart(struct top_graph *f, struct ospf_iface *ifa,
struct ospf_lsa_header *h);
struct top_hash_entry *ospfxx_hash_find(struct top_graph *, u32 domain, u32 lsa, u32 rtr,
u32 type);
struct top_hash_entry *ospf_hash_get(struct top_graph *, struct ospf_area *oa, u32 lsa, u32 rtr,
struct top_hash_entry *ospfxx_hash_get(struct top_graph *, u32 domain, u32 lsa, u32 rtr,
u32 type);
void ospf_hash_delete(struct top_graph *, struct top_hash_entry *);
void originate_rt_lsa(struct ospf_area *oa);
@ -64,7 +69,7 @@ int max_ext_lsa(unsigned pxlen);
void originate_ext_lsa(net * n, rte * e, struct proto_ospf *po,
struct ea_list *attrs);
void check_sum_lsa(struct proto_ospf *po, ort *nf, int);
void originate_sum_lsa(struct ospf_area *oa, struct fib_node *fn, int type, int metric);
void originate_sum_lsa(struct ospf_area *oa, struct fib_node *fn, int type, int metric, u32 options);
void flush_sum_lsa(struct ospf_area *oa, struct fib_node *fn, int type);