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 if test "$enable_ipv6" = yes ; then
ip=ipv6 ip=ipv6
SUFFIX6=6 SUFFIX6=6
if test "$with_protocols" = all ; then
with_protocols=bgp,pipe,rip,static
fi
else else
ip=ipv4 ip=ipv4
SUFFIX6="" SUFFIX6=""
if test "$with_protocols" = all ; then fi
if test "$with_protocols" = all ; then
with_protocols=bgp,ospf,pipe,rip,static with_protocols=bgp,ospf,pipe,rip,static
fi
fi fi
AC_SEARCH_LIBS(clock_gettime,[c rt posix4]) AC_SEARCH_LIBS(clock_gettime,[c rt posix4])

View file

@ -71,6 +71,7 @@ ea__find(ea_list *e, unsigned id)
while (e) while (e)
{ {
/*
if (e->flags & EALF_BISECT) if (e->flags & EALF_BISECT)
{ {
l = 0; l = 0;
@ -88,6 +89,7 @@ ea__find(ea_list *e, unsigned id)
} }
} }
else else
*/
for(m=0; m<e->count; m++) for(m=0; m<e->count; m++)
if (e->attrs[m].id == id) if (e->attrs[m].id == id)
return &e->attrs[m]; 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 area_net_config *this_pref;
static struct ospf_stubnet_config *this_stubnet; static struct ospf_stubnet_config *this_stubnet;
#ifdef OSPFv2
static void static void
finish_iface_config(struct ospf_iface_patt *ip) 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)) if ((ip->autype == OSPF_AUTH_NONE) && (ip->passwords != NULL))
log(L_WARN "Password option without authentication option does not make sense"); 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 CF_DECLS

View file

@ -9,6 +9,37 @@
#include "ospf.h" #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) static void ospf_dump_dbdes(struct proto *p, struct ospf_dbdes_packet *pkt)
{ {
struct ospf_packet *op = &pkt->ospf_packet; struct ospf_packet *op = &pkt->ospf_packet;
@ -37,7 +68,7 @@ static void ospf_dump_dbdes(struct proto *p, struct ospf_dbdes_packet *pkt)
* @n: neighbor * @n: neighbor
* @next: whether to send a next packet in a sequence (1) or to retransmit the old one (0) * @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. * 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 * 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 * 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; op = (struct ospf_packet *) pkt;
ospf_pkt_fill_hdr(ifa, pkt, DBDES_P); ospf_pkt_fill_hdr(ifa, pkt, DBDES_P);
pkt->iface_mtu = htons(ifa->iface->mtu); pkt->iface_mtu = htons(ifa->iface->mtu);
pkt->options = oa->opt.byte; pkt->options = hton_opt(oa->options);
pkt->imms = n->myimms; pkt->imms = n->myimms;
pkt->ddseq = htonl(n->dds); pkt->ddseq = htonl(n->dds);
length = sizeof(struct ospf_dbdes_packet); 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); ospf_pkt_fill_hdr(ifa, pkt, DBDES_P);
pkt->iface_mtu = htons(ifa->iface->mtu); pkt->iface_mtu = htons(ifa->iface->mtu);
pkt->options = oa->opt.byte;
pkt->ddseq = htonl(n->dds); 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 */ 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)); 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--) for (; i > 0; i--)
{ {
struct top_hash_entry *en= (struct top_hash_entry *) sn; struct top_hash_entry *en= (struct top_hash_entry *) sn;
int send = 1;
/* Don't send ext LSA into stub areas */ if (ospf_lsa_flooding_allowed(&en->lsa, en->domain, ifa))
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)
{ {
htonlsah(&(en->lsa), lsa); htonlsah(&(en->lsa), lsa);
DBG("Working on: %d\n", i); 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++) for (i = 0; i < j; i++)
{ {
ntohlsah(plsa + i, &lsa); 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)) (lsa_comp(&lsa, &(he->lsa)) == 1))
{ {
/* Is this condition necessary? */ /* 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)); ntohlsah(plsa + i, &(sn->lsa));
s_add_tail(&(n->lsrql), SNODE sn); s_add_tail(&(n->lsrql), SNODE sn);
} }
@ -219,13 +242,17 @@ ospf_dbdes_reqladd(struct ospf_dbdes_packet *ps, struct ospf_neighbor *n)
} }
void void
ospf_dbdes_receive(struct ospf_dbdes_packet *ps, ospf_dbdes_receive(struct ospf_packet *ps_i, struct ospf_iface *ifa,
struct ospf_iface *ifa, struct ospf_neighbor *n) struct ospf_neighbor *n)
{ {
struct ospf_dbdes_packet *ps = (void *) ps_i;
struct proto *p = &ifa->oa->po->proto; struct proto *p = &ifa->oa->po->proto;
u32 myrid = p->cf->global->router_id; u32 myrid = p->cf->global->router_id;
unsigned int size = ntohs(ps->ospf_packet.length); 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_PACKET(ospf_dump_dbdes, ps, "DBDES packet received from %I via %s", n->ip, ifa->iface->name);
ospf_neigh_sm(n, INM_HELLOREC); 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))) && (n->rid > myrid) && (size == sizeof(struct ospf_dbdes_packet)))
{ {
/* I'm slave! */ /* I'm slave! */
n->dds = ntohl(ps->ddseq); n->dds = ps_ddseq;
n->ddr = ntohl(ps->ddseq); n->ddr = ps_ddseq;
n->options = ps->options; n->options = ps_options;
n->myimms.bit.ms = 0; n->myimms.bit.ms = 0;
n->imms.byte = ps->imms.byte; n->imms.byte = ps->imms.byte;
OSPF_TRACE(D_PACKETS, "I'm slave to %I.", n->ip); 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)) && 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! */ /* I'm master! */
n->options = ps->options; n->options = ps_options;
n->ddr = ntohl(ps->ddseq) - 1; /* It will be set corectly a few lines down */ n->ddr = ps_ddseq - 1; /* It will be set corectly a few lines down */
n->imms.byte = ps->imms.byte; n->imms.byte = ps->imms.byte;
OSPF_TRACE(D_PACKETS, "I'm master to %I.", n->ip); OSPF_TRACE(D_PACKETS, "I'm master to %I.", n->ip);
ospf_neigh_sm(n, INM_NEGDONE); ospf_neigh_sm(n, INM_NEGDONE);
@ -274,8 +301,8 @@ ospf_dbdes_receive(struct ospf_dbdes_packet *ps,
break; break;
} }
case NEIGHBOR_EXCHANGE: case NEIGHBOR_EXCHANGE:
if ((ps->imms.byte == n->imms.byte) && (ps->options == n->options) && if ((ps->imms.byte == n->imms.byte) && (ps_options == n->options) &&
(ntohl(ps->ddseq) == n->ddr)) (ps_ddseq == n->ddr))
{ {
/* Duplicate packet */ /* Duplicate packet */
OSPF_TRACE(D_PACKETS, "Received duplicate dbdes from %I.", n->ip); OSPF_TRACE(D_PACKETS, "Received duplicate dbdes from %I.", n->ip);
@ -287,7 +314,7 @@ ospf_dbdes_receive(struct ospf_dbdes_packet *ps,
return; return;
} }
n->ddr = ntohl(ps->ddseq); n->ddr = ps_ddseq;
if (ps->imms.bit.ms != n->imms.bit.ms) /* M/S bit differs */ 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; 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)", OSPF_TRACE(D_PACKETS, "dbdes - sequence mismatch neighbor %I (options)",
n->ip); n->ip);
@ -317,7 +344,7 @@ ospf_dbdes_receive(struct ospf_dbdes_packet *ps,
if (n->myimms.bit.ms) if (n->myimms.bit.ms)
{ {
if (ntohl(ps->ddseq) != n->dds) /* MASTER */ if (ps_ddseq != n->dds) /* MASTER */
{ {
OSPF_TRACE(D_PACKETS, OSPF_TRACE(D_PACKETS,
"dbdes - sequence mismatch neighbor %I (master)", n->ip); "dbdes - sequence mismatch neighbor %I (master)", n->ip);
@ -339,15 +366,15 @@ ospf_dbdes_receive(struct ospf_dbdes_packet *ps,
} }
else 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)", OSPF_TRACE(D_PACKETS, "dbdes - sequence mismatch neighbor %I (slave)",
n->ip); n->ip);
ospf_neigh_sm(n, INM_SEQMIS); ospf_neigh_sm(n, INM_SEQMIS);
break; break;
} }
n->ddr = ntohl(ps->ddseq); n->ddr = ps_ddseq;
n->dds = ntohl(ps->ddseq); n->dds = ps_ddseq;
ospf_dbdes_reqladd(ps, n); ospf_dbdes_reqladd(ps, n);
ospf_dbdes_send(n, 1); ospf_dbdes_send(n, 1);
} }
@ -355,8 +382,8 @@ ospf_dbdes_receive(struct ospf_dbdes_packet *ps,
break; break;
case NEIGHBOR_LOADING: case NEIGHBOR_LOADING:
case NEIGHBOR_FULL: case NEIGHBOR_FULL:
if ((ps->imms.byte == n->imms.byte) && (ps->options == n->options) if ((ps->imms.byte == n->imms.byte) && (ps_options == n->options)
&& (ntohl(ps->ddseq) == n->ddr)) && (ps_ddseq == n->ddr))
/* Only duplicate are accepted */ /* Only duplicate are accepted */
{ {
OSPF_TRACE(D_PACKETS, "Received duplicate dbdes from %I.", n->ip); 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)", OSPF_TRACE(D_PACKETS, "dbdes - sequence mismatch neighbor %I (full)",
n->ip); 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); ospf_neigh_sm(n, INM_SEQMIS);
} }
break; break;

View file

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

View file

@ -8,12 +8,46 @@
#include "ospf.h" #include "ospf.h"
void
ospf_hello_receive(struct ospf_hello_packet *ps, #ifdef OSPFv2
struct ospf_iface *ifa, struct ospf_neighbor *n, ip_addr faddr) 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; u32 *pnrid;
ip_addr olddr, oldbdr; u32 olddr, oldbdr, oldiface_id, tmp;
ip_addr mask; ip_addr mask;
char *beg = "Bad OSPF hello packet from ", *rec = " received: "; char *beg = "Bad OSPF hello packet from ", *rec = " received: ";
struct proto *p = (struct proto *) ifa->oa->po; 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, OSPF_TRACE(D_PACKETS, "HELLO packet received from %I via %s%s", faddr,
(ifa->type == OSPF_IT_VLINK ? "vlink-" : ""), ifa->iface->name); (ifa->type == OSPF_IT_VLINK ? "vlink-" : ""), ifa->iface->name);
#ifdef OSPFv2
mask = ps->netmask; mask = ps->netmask;
ipa_ntoh(mask); ipa_ntoh(mask);
if (ifa->type != OSPF_IT_VLINK) if (ifa->type != OSPF_IT_VLINK)
{ {
char *msg = L_WARN "Received HELLO packet %s (%I) is inconsistent " char *msg = L_WARN "Received HELLO packet %s (%I) is inconsistent "
@ -50,24 +85,30 @@ ospf_hello_receive(struct ospf_hello_packet *ps,
return; 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, log(L_ERR "%s%I%shello interval mismatch (%d).", beg, faddr, rec, tmp);
ntohs(ps->helloint));
return; 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, log(L_ERR "%s%I%sdead interval mismatch (%d).", beg, faddr, rec, tmp);
ntohl(ps->deadint));
return; 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; return;
} }
@ -111,12 +152,12 @@ ospf_hello_receive(struct ospf_hello_packet *ps,
n->rid = ntohl(((struct ospf_packet *) ps)->routerid); n->rid = ntohl(((struct ospf_packet *) ps)->routerid);
n->ip = faddr; n->ip = faddr;
n->dr = ps->dr; n->dr = ntohl(ps->dr);
ipa_ntoh(n->dr); n->bdr = ntohl(ps->bdr);
n->bdr = ps->bdr;
ipa_ntoh(n->bdr);
n->priority = ps->priority; n->priority = ps->priority;
n->options = ps->options; #ifdef OSPFv3
n->iface_id = ntohl(ps->iface_id);
#endif
} }
ospf_neigh_sm(n, INM_HELLOREC); ospf_neigh_sm(n, INM_HELLOREC);
@ -140,35 +181,54 @@ ospf_hello_receive(struct ospf_hello_packet *ps,
ospf_neigh_sm(n, INM_1WAYREC); ospf_neigh_sm(n, INM_1WAYREC);
olddr = n->dr; olddr = n->dr;
n->dr = ipa_ntoh(ps->dr);
oldbdr = n->bdr; oldbdr = n->bdr;
n->bdr = ipa_ntoh(ps->bdr);
oldpriority = n->priority; 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; n->priority = ps->priority;
#ifdef OSPFv3
n->iface_id = ntohl(ps->iface_id);
#endif
/* Check priority change */ /* Check priority change */
if (n->state >= NEIGHBOR_2WAY) 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) if (n->priority != oldpriority)
ospf_iface_sm(ifa, ISM_NEICH); 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 */ /* 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)) && (n->state != NEIGHBOR_FULL))
ospf_iface_sm(ifa, ISM_BACKS); ospf_iface_sm(ifa, ISM_BACKS);
/* Neighbor is declaring itself as BDR */ /* 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); ospf_iface_sm(ifa, ISM_BACKS);
/* Neighbor is newly declaring itself as DR or BDR */ /* Neighbor is newly declaring itself as DR or BDR */
if ((ipa_equal(n->ip, n->dr) && (!ipa_equal(n->dr, olddr))) if (((rid == n->dr) && (n->dr != olddr))
|| (ipa_equal(n->ip, n->bdr) && (!ipa_equal(n->bdr, oldbdr)))) || ((rid == n->bdr) && (n->bdr != oldbdr)))
ospf_iface_sm(ifa, ISM_NEICH); ospf_iface_sm(ifa, ISM_NEICH);
/* Neighbor is no more declaring itself as DR or BDR */ /* Neighbor is no more declaring itself as DR or BDR */
if ((ipa_equal(n->ip, olddr) && (!ipa_equal(n->dr, olddr))) if (((rid == olddr) && (n->dr != olddr))
|| (ipa_equal(n->ip, oldbdr) && (!ipa_equal(n->bdr, oldbdr)))) || ((rid == oldbdr) && (n->bdr != oldbdr)))
ospf_iface_sm(ifa, ISM_NEICH); ospf_iface_sm(ifa, ISM_NEICH);
} }
@ -181,7 +241,7 @@ ospf_hello_receive(struct ospf_hello_packet *ps,
} }
void 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_iface *ifa;
struct ospf_hello_packet *pkt; 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); ospf_pkt_fill_hdr(ifa, pkt, HELLO_P);
#ifdef OSPFv2
pkt->netmask = ipa_mkmask(ifa->iface->addr->pxlen); pkt->netmask = ipa_mkmask(ifa->iface->addr->pxlen);
ipa_hton(pkt->netmask); ipa_hton(pkt->netmask);
if ((ifa->type == OSPF_IT_VLINK) || (ifa->type == OSPF_IT_PTP)) if ((ifa->type == OSPF_IT_VLINK) || (ifa->type == OSPF_IT_PTP))
pkt->netmask = IPA_NONE; pkt->netmask = IPA_NONE;
#endif
pkt->helloint = ntohs(ifa->helloint); pkt->helloint = ntohs(ifa->helloint);
pkt->options = ifa->oa->opt.byte;
pkt->priority = ifa->priority; 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->deadint = htonl(ifa->dead);
pkt->dr = ifa->drip; pkt->dr = htonl(ipa_to_u32(ifa->drip));
ipa_hton(pkt->dr); pkt->bdr = htonl(ipa_to_u32(ifa->bdrip));
pkt->bdr = ifa->bdrip; #else /* OSPFv3 */
ipa_hton(pkt->bdr); pkt->deadint = htons(ifa->dead);
pkt->dr = htonl(ifa->drid);
pkt->bdr = htonl(ifa->bdrid);
#endif
/* Fill all neighbors */ /* Fill all neighbors */
i = 0; i = 0;

View file

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

View file

@ -157,16 +157,16 @@ ospf_iface_chstate(struct ospf_iface *ifa, u8 state)
rfree(ifa->dr_sk); rfree(ifa->dr_sk);
ifa->dr_sk = NULL; 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) 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)) if (can_flush_lsa(po))
flush_lsa(ifa->nlsa, po); flush_lsa(ifa->net_lsa, po);
ifa->nlsa = NULL; ifa->net_lsa = NULL;
} }
} }
} }
@ -412,8 +412,16 @@ ospf_iface_new(struct proto_ospf *po, struct iface *iface,
ifa->waitint = ip->waitint; ifa->waitint = ip->waitint;
ifa->dead = (ip->dead == 0) ? ip->deadc * ifa->helloint : ip->dead; ifa->dead = (ip->dead == 0) ? ip->deadc * ifa->helloint : ip->dead;
ifa->stub = ip->stub; ifa->stub = ip->stub;
#ifdef OSPFv2
ifa->autype = ip->autype; ifa->autype = ip->autype;
ifa->passwords = ip->passwords; ifa->passwords = ip->passwords;
#endif
#ifdef OSPFv3
ifa->instance_id = ip->instance_id;
#endif
ifa->rxbuf = ip->rxbuf; ifa->rxbuf = ip->rxbuf;
if (ip->type == OSPF_IT_UNDEF) if (ip->type == OSPF_IT_UNDEF)

View file

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

View file

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

View file

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

View file

@ -12,16 +12,15 @@
void htonlsah(struct ospf_lsa_header *h, struct ospf_lsa_header *n); 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 ntohlsah(struct ospf_lsa_header *n, struct ospf_lsa_header *h);
void htonlsab(void *h, void *n, u8 type, u16 len); void htonlsab(void *h, void *n, u16 type, u16 len);
void ntohlsab(void *n, void *h, u8 type, u16 len); void ntohlsab(void *n, void *h, u16 type, u16 len);
void lsasum_calculate(struct ospf_lsa_header *header, void *body); void lsasum_calculate(struct ospf_lsa_header *header, void *body);
u16 lsasum_check(struct ospf_lsa_header *h, void *body); u16 lsasum_check(struct ospf_lsa_header *h, void *body);
#define CMP_NEWER 1 #define CMP_NEWER 1
#define CMP_SAME 0 #define CMP_SAME 0
#define CMP_OLDER -1 #define CMP_OLDER -1
int lsa_comp(struct ospf_lsa_header *l1, struct ospf_lsa_header *l2); 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, struct top_hash_entry * lsa_install_new(struct proto_ospf *po, struct ospf_lsa_header *lsa, u32 domain, void *body);
void *body, struct ospf_area *oa);
void ospf_age(struct proto_ospf *po); void ospf_age(struct proto_ospf *po);
void flush_lsa(struct top_hash_entry *en, 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" #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) static void ospf_dump_lsreq(struct proto *p, struct ospf_lsreq_packet *pkt)
{ {
struct ospf_packet *op = &pkt->ospf_packet; 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); ASSERT(op->type == LSREQ_P);
ospf_dump_common(p, op); ospf_dump_common(p, op);
struct ospf_lsreq_header *plsr = (void *) (pkt + 1);
int i, j; int i, j;
j = (ntohs(op->length) - sizeof(struct ospf_lsreq_packet)) /
j = (ntohs(op->length) - sizeof(struct ospf_dbdes_packet)) /
sizeof(struct ospf_lsreq_header); sizeof(struct ospf_lsreq_header);
for (i = 0; i < j; i++) for (i = 0; i < j; i++)
log(L_TRACE "%s: LSR Id: %R, Rt: %R, Type: %u", log(L_TRACE "%s: LSR Id: %R, Rt: %R, Type: %u", p->name,
p->name, htonl(plsr[i].id), htonl(plsr[i].rt), plsr[i].type); htonl(pkt->lsh[i].id), htonl(pkt->lsh[i].rt), pkt->lsh[i].type);
} }
void void
@ -53,14 +59,12 @@ ospf_lsreq_send(struct ospf_neighbor *n)
i = j = (ospf_pkt_maxsize(n->ifa) - sizeof(struct ospf_lsreq_packet)) / i = j = (ospf_pkt_maxsize(n->ifa) - sizeof(struct ospf_lsreq_packet)) /
sizeof(struct ospf_lsreq_header); sizeof(struct ospf_lsreq_header);
lsh = (struct ospf_lsreq_header *) (pk + 1); lsh = pk->lsh;
for (; i > 0; i--) for (; i > 0; i--)
{ {
en = (struct top_hash_entry *) sn; en = (struct top_hash_entry *) sn;
lsh->padd1 = 0; lsh->type = htonl(en->lsa.type);
lsh->padd2 = 0;
lsh->type = en->lsa.type;
lsh->rt = htonl(en->lsa.rt); lsh->rt = htonl(en->lsa.rt);
lsh->id = htonl(en->lsa.id); lsh->id = htonl(en->lsa.id);
DBG("Requesting %uth LSA: Type: %u, ID: %R, RT: %R, SN: 0x%x, Age %u\n", 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 void
ospf_lsreq_receive(struct ospf_lsreq_packet *ps, ospf_lsreq_receive(struct ospf_packet *ps_i, struct ospf_iface *ifa,
struct ospf_iface *ifa, struct ospf_neighbor *n) struct ospf_neighbor *n)
{ {
struct ospf_lsreq_packet *ps = (void *) ps_i;
struct ospf_lsreq_header *lsh; struct ospf_lsreq_header *lsh;
struct l_lsr_head *llsh; struct l_lsr_head *llsh;
list uplist; list uplist;
@ -104,7 +109,7 @@ ospf_lsreq_receive(struct ospf_lsreq_packet *ps,
ospf_neigh_sm(n, INM_HELLOREC); ospf_neigh_sm(n, INM_HELLOREC);
lsh = (void *) (ps + 1); lsh = ps->lsh;
init_list(&uplist); init_list(&uplist);
upslab = sl_new(n->pool, sizeof(struct l_lsr_head)); 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 hid = ntohl(lsh->id);
u32 hrt = ntohl(lsh->rt); 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); DBG("Processing requested LSA: Type: %u, ID: %R, RT: %R\n", lsh->type, hid, hrt);
llsh = sl_alloc(upslab); llsh = sl_alloc(upslab);
llsh->lsh.id = hid; llsh->lsh.id = hid;
llsh->lsh.rt = hrt; llsh->lsh.rt = hrt;
llsh->lsh.type = lsh->type; llsh->lsh.type = htype;
add_tail(&uplist, NODE llsh); add_tail(&uplist, NODE llsh);
if (ospf_hash_find(po->gr, oa->areaid, llsh->lsh.id, llsh->lsh.rt, if (ospfxx_hash_find(po->gr, dom, hid, hrt, htype) == NULL)
llsh->lsh.type) == NULL)
{ {
log(L_WARN log(L_WARN
"Received bad LS req from: %I looking: Type: %u, ID: %R, RT: %R", "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); ospf_neigh_sm(n, INM_BADLSREQ);
rfree(upslab); rfree(upslab);
return; return;

View file

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

View file

@ -9,6 +9,13 @@
#include "ospf.h" #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) void ospf_dump_lsahdr(struct proto *p, struct ospf_lsa_header *lsa_n)
{ {
struct ospf_lsa_header lsa; 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 * ospf_lsupd_flood - send received or generated lsa to the neighbors
* @po: OSPF protocol
* @n: neighbor than sent this lsa (or NULL if generated) * @n: neighbor than sent this lsa (or NULL if generated)
* @hn: LSA header followed by lsa body in network endianity (may be NULL) * @hn: LSA header followed by lsa body in network endianity (may be NULL)
* @hh: LSA header in host endianity (must be filled) * @hh: LSA header in host endianity (must be filled)
* @iff: interface which received this LSA (or NULL if LSA is generated) * @domain: domain of LSA (must be filled)
* @oa: ospf_area which is the LSA generated for
* @rtl: add this LSA into retransmission list * @rtl: add this LSA into retransmission list
* *
*
* return value - was the LSA flooded back? * return value - was the LSA flooded back?
*/ */
int int
ospf_lsupd_flood(struct ospf_neighbor *n, struct ospf_lsa_header *hn, ospf_lsupd_flood(struct proto_ospf *po,
struct ospf_lsa_header *hh, struct ospf_iface *iff, struct ospf_neighbor *n, struct ospf_lsa_header *hn,
struct ospf_area *oa, int rtl) struct ospf_lsa_header *hh, u32 domain, int rtl)
{ {
struct ospf_iface *ifa; struct ospf_iface *ifa;
struct ospf_neighbor *nn; struct ospf_neighbor *nn;
struct top_hash_entry *en; struct top_hash_entry *en;
struct proto_ospf *po = oa->po;
struct proto *p = &po->proto; struct proto *p = &po->proto;
int ret, retval = 0; int ret, retval = 0;
@ -81,18 +140,8 @@ ospf_lsupd_flood(struct ospf_neighbor *n, struct ospf_lsa_header *hn,
if (ifa->stub) if (ifa->stub)
continue; continue;
if (hh->type == LSA_T_EXT) if (! ospf_lsa_flooding_allowed(hh, domain, ifa))
{
if (ifa->type == OSPF_IT_VLINK)
continue; continue;
if (ifa->oa->stub)
continue;
}
else
{
if (ifa->oa != oa)
continue;
}
DBG("Wanted to flood LSA: Type: %u, ID: %R, RT: %R, SN: 0x%x, Age %u\n", 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); 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; ret = 0;
WALK_LIST(nn, ifa->neigh_list) WALK_LIST(nn, ifa->neigh_list)
{ {
/* 13.3 (1a) */
if (nn->state < NEIGHBOR_EXCHANGE) if (nn->state < NEIGHBOR_EXCHANGE)
continue; continue;
/* 13.3 (1b) */
if (nn->state < NEIGHBOR_FULL) 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); 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) if (nn == n)
continue; continue;
/* 13.3 (1d) */
if (rtl) 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 else
{ {
@ -159,7 +217,7 @@ ospf_lsupd_flood(struct ospf_neighbor *n, struct ospf_lsa_header *hn,
} }
else 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); s_rem_node(SNODE en);
if (en->lsa_body != NULL) if (en->lsa_body != NULL)
@ -175,11 +233,11 @@ ospf_lsupd_flood(struct ospf_neighbor *n, struct ospf_lsa_header *hn,
if (ret == 0) if (ret == 0)
continue; /* pg 150 (2) */ 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) */ continue; /* pg 150 (3) */
if (iff->state == OSPF_IS_BACKUP) if (ifa->state == OSPF_IS_BACKUP)
continue; /* pg 150 (4) */ continue; /* pg 150 (4) */
retval = 1; retval = 1;
} }
@ -216,7 +274,7 @@ ospf_lsupd_flood(struct ospf_neighbor *n, struct ospf_lsa_header *hn,
htonlsah(hh, lh); htonlsah(hh, lh);
help = (u8 *) (lh + 1); 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 htonlsab(en->lsa_body, help, hh->type, hh->length
- sizeof(struct ospf_lsa_header)); - sizeof(struct ospf_lsa_header));
} }
@ -288,8 +346,9 @@ ospf_lsupd_send_list(struct ospf_neighbor *n, list * l)
WALK_LIST(llsh, *l) WALK_LIST(llsh, *l)
{ {
if ((en = ospf_hash_find(po->gr, oa->areaid, llsh->lsh.id, llsh->lsh.rt, u32 domain = ospf_lsa_domain(llsh->lsh.type, n->ifa);
llsh->lsh.type)) == NULL) if ((en = ospfxx_hash_find(po->gr, domain, llsh->lsh.id,
llsh->lsh.rt, llsh->lsh.type)) == NULL)
continue; /* Probably flushed LSA */ continue; /* Probably flushed LSA */
/* FIXME This is a bug! I cannot flush LSA that is in lsrt */ /* 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 void
ospf_lsupd_receive(struct ospf_lsupd_packet *ps, ospf_lsupd_receive(struct ospf_packet *ps_i, struct ospf_iface *ifa,
struct ospf_iface *ifa, struct ospf_neighbor *n) struct ospf_neighbor *n)
{ {
u32 area; struct ospf_lsupd_packet *ps = (void *) ps_i;
struct ospf_neighbor *ntmp; struct ospf_neighbor *ntmp;
struct ospf_lsa_header *lsa; struct ospf_lsa_header *lsa;
struct ospf_area *oa;
struct proto_ospf *po = ifa->oa->po; struct proto_ospf *po = ifa->oa->po;
struct proto *p = &po->proto; struct proto *p = &po->proto;
unsigned int i, sendreq = 1, size = ntohs(ps->ospf_packet.length); 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 */ ospf_neigh_sm(n, INM_HELLOREC); /* Questionable */
lsa = (struct ospf_lsa_header *) (ps + 1); 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++, for (i = 0; i < ntohl(ps->lsano); i++,
lsa = (struct ospf_lsa_header *) (((u8 *) lsa) + ntohs(lsa->length))) lsa = (struct ospf_lsa_header *) (((u8 *) lsa) + ntohs(lsa->length)))
@ -394,6 +450,8 @@ ospf_lsupd_receive(struct ospf_lsupd_packet *ps,
continue; continue;
} }
#ifdef OSPFv2
/* pg 143 (2) */ /* pg 143 (2) */
if ((lsa->type < LSA_T_RT) || (lsa->type > LSA_T_EXT)) 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) */ /* 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); log(L_WARN "Received External LSA in stub area from %I", n->ip);
continue; 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); ntohlsah(lsa, &lsatmp);
DBG("Update Type: %u ID: %R RT: %R, Sn: 0x%08x Age: %u, Sum: %u\n", 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); 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 #ifdef LOCAL_DEBUG
if (lsadb) if (lsadb)
@ -439,7 +513,8 @@ ospf_lsupd_receive(struct ospf_lsupd_packet *ps,
DBG("PG143(5): Received LSA is newer\n"); 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)) if ((!self) && (lsatmp.type == LSA_T_NET))
{ {
WALK_LIST(nifa, po->iface_list) 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) if (self)
{ {
struct top_hash_entry *en; struct top_hash_entry *en;
@ -473,10 +550,10 @@ ospf_lsupd_receive(struct ospf_lsupd_packet *ps,
lsatmp.type, lsatmp.id, lsatmp.rt); lsatmp.type, lsatmp.id, lsatmp.rt);
lsasum_check(lsa, (lsa + 1)); /* It also calculates chsum! */ lsasum_check(lsa, (lsa + 1)); /* It also calculates chsum! */
lsatmp.checksum = ntohs(lsa->checksum); lsatmp.checksum = ntohs(lsa->checksum);
ospf_lsupd_flood(NULL, lsa, &lsatmp, NULL, oa, 0); ospf_lsupd_flood(po, NULL, lsa, &lsatmp, domain, 0);
if (en = ospf_hash_find_header(po->gr, oa->areaid, &lsatmp)) if (en = ospfxx_hash_find_header(po->gr, domain, &lsatmp))
{ { /* FIXME verify hacks */
ospf_lsupd_flood(NULL, NULL, &en->lsa, NULL, oa, 1); ospf_lsupd_flood(po, NULL, NULL, &en->lsa, domain, 1);
} }
continue; continue;
} }
@ -489,7 +566,7 @@ ospf_lsupd_receive(struct ospf_lsupd_packet *ps,
continue; 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 */ DBG("Wasn't flooded back\n"); /* ps 144(5e), pg 153 */
if (ifa->state == OSPF_IS_BACKUP) if (ifa->state == OSPF_IS_BACKUP)
@ -509,7 +586,7 @@ ospf_lsupd_receive(struct ospf_lsupd_packet *ps,
{ {
struct top_hash_entry *en; struct top_hash_entry *en;
if (ntmp->state > NEIGHBOR_EXSTART) 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); s_rem_node(SNODE en);
if (en->lsa_body != NULL) 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)); mb_alloc(p->pool, lsatmp.length - sizeof(struct ospf_lsa_header));
ntohlsab(lsa + 1, body, lsatmp.type, ntohlsab(lsa + 1, body, lsatmp.type,
lsatmp.length - sizeof(struct ospf_lsa_header)); 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"); DBG("New LSA installed in DB\n");
continue; continue;
@ -545,7 +622,7 @@ ospf_lsupd_receive(struct ospf_lsupd_packet *ps,
{ {
struct top_hash_entry *en; struct top_hash_entry *en;
DBG("PG145(7) Got the same LSA\n"); 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) */ /* pg145 (7a) */
s_rem_node(SNODE en); s_rem_node(SNODE en);
@ -596,10 +673,9 @@ ospf_lsupd_receive(struct ospf_lsupd_packet *ps,
} }
void 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 ospf_lsa_header *lsa = &en->lsa;
struct proto_ospf *po = oa->po;
struct proto *p = &po->proto; struct proto *p = &po->proto;
lsa->age = LSA_MAXAGE; 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); lsasum_calculate(lsa, en->lsa_body);
OSPF_TRACE(D_EVENTS, "Premature aging self originated lsa!"); 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_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_lsahdr(struct proto *p, struct ospf_lsa_header *lsa_n);
void ospf_dump_common(struct proto *p, struct ospf_packet *op); 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_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); struct ospf_iface *ifa, struct ospf_neighbor *n);
int ospf_lsupd_flood(struct ospf_neighbor *n, struct ospf_lsa_header *hn, int ospf_lsupd_flood(struct proto_ospf *po,
struct ospf_lsa_header *hh, struct ospf_iface *iff, struct ospf_neighbor *n, struct ospf_lsa_header *hn,
struct ospf_area *oa, int rtl); struct ospf_lsa_header *hh, u32 domain, int rtl);
void ospf_lsupd_flush_nlsa(struct top_hash_entry *en, struct ospf_area *oa); 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_ */ #endif /* _BIRD_OSPF_LSUPD_H_ */

View file

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

View file

@ -163,8 +163,11 @@ ospf_start(struct proto *p)
oa->stub = 0; oa->stub = 0;
} }
oa->opt.byte = 0; #ifdef OSPFv2
if(!oa->stub) oa->opt.bit.e = 1; 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 */ /* 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->net_fib, p->pool, sizeof(struct area_net), 16, ospf_area_initfib);
fib_init(&oa->rtr, p->pool, sizeof(ort), 16, ospf_rt_initort); fib_init(&oa->rtr, p->pool, sizeof(ort), 16, ospf_rt_initort);
po->backbone = oa; po->backbone = oa;
oa->opt.byte = 0; #ifdef OSPFv2
oa->opt.bit.e = 1; oa->options = OPT_E;
#else /* OSPFv3 */
oa->options = OPT_R | OPT_E | OPT_V6;
#endif
} }
ospf_iface_new(po, NULL, ac, ipatt); 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 */ if (new) /* Got some new route */
{
originate_ext_lsa(n, new, po, attrs); originate_ext_lsa(n, new, po, attrs);
}
else else
{ flush_ext_lsa(n, po);
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;
}
}
}
} }
static void static void
@ -762,6 +741,7 @@ ospf_reconfigure(struct proto *p, struct proto_config *c)
"Interface %s is no longer stub.", ifa->iface->name); "Interface %s is no longer stub.", ifa->iface->name);
} }
#ifdef OSPFv2
/* AUTHENTICATION */ /* AUTHENTICATION */
if (oldip->autype != newip->autype) if (oldip->autype != newip->autype)
{ {
@ -772,6 +752,7 @@ ospf_reconfigure(struct proto *p, struct proto_config *c)
} }
/* Add *passwords */ /* Add *passwords */
ifa->passwords = newip->passwords; ifa->passwords = newip->passwords;
#endif
/* priority */ /* priority */
if (oldip->priority != newip->priority) if (oldip->priority != newip->priority)
@ -1076,24 +1057,24 @@ he_compare(const void *p1, const void *p2)
return lsa1->age - lsa2->age; return lsa1->age - lsa2->age;
} }
} }
/*
static inline void static inline void
show_lsa_router(struct top_hash_entry *he) show_lsa_router(struct top_hash_entry *he)
{ {
struct ospf_lsa_header *lsa = &(he->lsa); struct ospf_lsa_header *lsa = &(he->lsa);
struct ospf_lsa_rt *rt = he->lsa_body; struct ospf_lsa_rt *rt = he->lsa_body;
struct ospf_lsa_rt_link *rr = (struct ospf_lsa_rt_link *) (rt + 1); 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) if (rr[i].type == LSART_PTP)
cli_msg(-1016, "\t\trouter %R metric %u ", rr[i].id, rr[i].metric); 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) if (rr[i].type == LSART_NET)
{ {
struct proto_ospf *po = he->oa->po; 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) if (net_he)
{ {
struct ospf_lsa_header *net_lsa = &(net_he->lsa); 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); 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) 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); 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) if (rr[i].type == LSART_VLNK)
cli_msg(-1016, "\t\tvlink %I metric %u ", ipa_from_u32(rr[i].id), rr[i].metric); 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_header *lsa = &(he->lsa);
struct ospf_lsa_net *ln = he->lsa_body; struct ospf_lsa_net *ln = he->lsa_body;
u32 *rts = (u32 *) (ln + 1); u32 *rts = (u32 *) (ln + 1);
u32 max = (lsa->length - sizeof(struct ospf_lsa_header) - sizeof(struct ospf_lsa_net)) / sizeof(u32);
u32 i; u32 i;
cli_msg(-1016, ""); 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, "\tnetwork %I/%d", ipa_and(ipa_from_u32(lsa->id), ln->netmask), ipa_mklen(ln->netmask));
cli_msg(-1016, "\t\tdr %R", lsa->rt); 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]); 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); et->etm.metric & METRIC_MASK, str_via, str_tag);
} }
*/
void void
ospf_sh_state(struct proto *p, int verbose) ospf_sh_state(struct proto *p, int verbose)
{ {
@ -1177,7 +1157,7 @@ ospf_sh_state(struct proto *p, int verbose)
unsigned int i, j; unsigned int i, j;
u32 last_rt = 0xFFFFFFFF; u32 last_rt = 0xFFFFFFFF;
u32 last_area = 0xFFFFFFFF; u32 last_area = 0xFFFFFFFF;
/*
if (p->proto_state != PS_UP) if (p->proto_state != PS_UP)
{ {
cli_msg(-1016, "%s: is not up", p->name); cli_msg(-1016, "%s: is not up", p->name);
@ -1240,7 +1220,7 @@ ospf_sh_state(struct proto *p, int verbose)
break; break;
} }
} }
*/
cli_msg(0, ""); cli_msg(0, "");
} }

View file

@ -49,13 +49,17 @@ do { if ((p->debug & D_PACKETS) || OSPF_FORCE_DEBUG) \
#include "lib/string.h" #include "lib/string.h"
#define OSPF_PROTO 89 #define OSPF_PROTO 89
#ifndef IPV6 #ifndef IPV6
#define OSPFv2 1
#define OSPF_VERSION 2 #define OSPF_VERSION 2
#define AllSPFRouters ipa_from_u32(0xe0000005) /* 224.0.0.5 */ #define AllSPFRouters ipa_from_u32(0xe0000005) /* 224.0.0.5 */
#define AllDRouters ipa_from_u32(0xe0000006) /* 224.0.0.6 */ #define AllDRouters ipa_from_u32(0xe0000006) /* 224.0.0.6 */
#define DEFAULTDES ipa_from_u32(0)
#else #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 #endif
@ -118,32 +122,37 @@ struct ospf_area_config
list stubnet_list; 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 /* Option flags */
{
u8 byte; #define OPT_E 0x02
struct obits bit; #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 struct ospf_iface
@ -167,15 +176,26 @@ struct ospf_iface
u16 inftransdelay; /* The estimated number of seconds it takes to u16 inftransdelay; /* The estimated number of seconds it takes to
transmit a Link State Update Packet over this transmit a Link State Update Packet over this
interface. LSAs contained in the update */ interface. LSAs contained in the update */
u16 autype;
u16 helloint; /* number of seconds between hello sending */ u16 helloint; /* number of seconds between hello sending */
#ifdef OSPFv2
list *passwords; list *passwords;
u16 autype;
u32 csn; /* Last used crypt seq number */ u32 csn; /* Last used crypt seq number */
bird_clock_t csn_use; /* Last time when packet with that CSN was sent */ bird_clock_t csn_use; /* Last time when packet with that CSN was sent */
#endif
ip_addr drip; /* Designated router */ ip_addr drip; /* Designated router */
u32 drid; u32 drid;
ip_addr bdrip; /* Backup DR */ ip_addr bdrip; /* Backup DR */
u32 bdrid; 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 */ u8 type; /* OSPF view of type */
#define OSPF_IT_BCAST 0 #define OSPF_IT_BCAST 0
#define OSPF_IT_NBMA 1 #define OSPF_IT_NBMA 1
@ -206,11 +226,16 @@ struct ospf_iface
#define HELLOINT_D 10 #define HELLOINT_D 10
#define POLLINT_D 20 #define POLLINT_D 20
#define DEADC_D 4 #define DEADC_D 4
#define WAIT_DMH 4 /* Value of Wait timer - not found it in RFC #define WAIT_DMH 4
* - using 4*HELLO /* Value of Wait timer - not found it in RFC * - using 4*HELLO */
*/
struct top_hash_entry *nlsa; /* Originated net lsa */ struct top_hash_entry *net_lsa; /* Originated network LSA */
int orignet; /* Schedule network LSA origination */ 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 */ int fadj; /* Number of full adjacent neigh */
list nbma_list; list nbma_list;
u8 priority; /* A router priority for DR election */ u8 priority; /* A router priority for DR election */
@ -232,35 +257,17 @@ union ospf_auth
struct ospf_md5 md5; struct ospf_md5 md5;
}; };
struct ospf_packet
{ /* Packet types */
u8 version;
u8 type;
#define HELLO_P 1 /* Hello */ #define HELLO_P 1 /* Hello */
#define DBDES_P 2 /* Database description */ #define DBDES_P 2 /* Database description */
#define LSREQ_P 3 /* Link state request */ #define LSREQ_P 3 /* Link state request */
#define LSUPD_P 4 /* Link state update */ #define LSUPD_P 4 /* Link state update */
#define LSACK_P 5 /* Link state acknowledgement */ #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 /* Area IDs */
{ #define BACKBONE 0
struct ospf_packet ospf_packet;
ip_addr netmask;
u16 helloint;
u8 options;
u8 priority;
u32 deadint;
ip_addr dr;
ip_addr bdr;
};
struct immsb struct immsb
{ {
@ -282,34 +289,86 @@ union imms
u8 byte; u8 byte;
struct immsb bit; 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_MS 1
#define DBDES_M 2 #define DBDES_M 2
#define DBDES_I 4 #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 struct ospf_lsa_header
{ {
u16 age; /* LS Age */ u16 age; /* LS Age */
#define LSA_MAXAGE 3600 /* 1 hour */ #define LSA_MAXAGE 3600 /* 1 hour */
#define LSA_CHECKAGE 300 /* 5 minutes */ #define LSA_CHECKAGE 300 /* 5 minutes */
#define LSA_MAXAGEDIFF 900 /* 15 minutes */ #define LSA_MAXAGEDIFF 900 /* 15 minutes */
#ifdef OSPFv2
u8 options; u8 options;
u8 type; u8 type;
u32 id;
#define LSA_T_RT 1 #define LSA_T_RT 1
#define LSA_T_NET 2 #define LSA_T_NET 2
#define LSA_T_SUM_NET 3 #define LSA_T_SUM_NET 3
#define LSA_T_SUM_RT 4 #define LSA_T_SUM_RT 4
#define LSA_T_EXT 5 #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;
u32 rt; /* Advertising router */ u32 rt; /* Advertising router */
s32 sn; /* LS Sequence number */ s32 sn; /* LS Sequence number */
#define LSA_INITSEQNO 0x80000001 #define LSA_INITSEQNO 0x80000001
@ -318,31 +377,18 @@ struct ospf_lsa_header
u16 length; 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 #define LSART_PTP 1
{ #define LSART_NET 2
u8 byte; #define LSART_STUB 3
struct vebb bit; #define LSART_VLNK 4
};
#ifdef OSPFv2
struct ospf_lsa_rt struct ospf_lsa_rt
{ {
union veb veb; u16 options; /* VEB flags only */
u8 padding;
u16 links; u16 links;
}; };
@ -351,37 +397,115 @@ struct ospf_lsa_rt_link
u32 id; u32 id;
u32 data; u32 data;
u8 type; u8 type;
#define LSART_PTP 1
#define LSART_NET 2
#define LSART_STUB 3
#define LSART_VLNK 4
u8 notos; u8 notos;
u16 metric; 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 struct ospf_lsa_net
{ {
ip_addr netmask; ip_addr netmask;
u32 routers[];
}; };
struct ospf_lsa_sum struct ospf_lsa_sum
{ {
ip_addr netmask; ip_addr netmask;
u32 metric;
}; };
struct ospf_lsa_ext struct ospf_lsa_ext
{ {
ip_addr netmask; 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 struct ospf_lsa_ext_etos
{ {
#ifdef CPU_BIG_ENDIAN #ifdef CPU_BIG_ENDIAN
@ -397,7 +521,7 @@ struct ospf_lsa_ext_etos
#endif #endif
}; };
#define METRIC_MASK 0x00FFFFFF
struct ospf_lsa_sum_tos struct ospf_lsa_sum_tos
{ {
#ifdef CPU_BIG_ENDIAN #ifdef CPU_BIG_ENDIAN
@ -430,16 +554,11 @@ struct ospf_lsa_ext_tos
u32 tag; u32 tag;
}; };
struct ospf_lsreq_packet */
{
struct ospf_packet ospf_packet;
};
struct ospf_lsreq_header struct ospf_lsreq_header
{ {
u16 padd1; u32 type;
u8 padd2;
u8 type;
u32 id; u32 id;
u32 rt; /* Advertising router */ u32 rt; /* Advertising router */
}; };
@ -450,17 +569,6 @@ struct l_lsr_head
struct ospf_lsreq_header lsh; 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 struct ospf_neighbor
{ {
@ -484,10 +592,18 @@ struct ospf_neighbor
u32 rid; /* Router ID */ u32 rid; /* Router ID */
ip_addr ip; /* IP of it's interface */ ip_addr ip; /* IP of it's interface */
u8 priority; /* Priority */ 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? */ 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 */ siterator dbsi; /* Database summary list iterator */
slist lsrql; /* Link state request */ slist lsrql; /* Link state request */
struct top_graph *lsrqh; /* LSA graph */ struct top_graph *lsrqh; /* LSA graph */
@ -535,13 +651,14 @@ struct ospf_area
struct ospf_area_config *ac; /* Related area config */ struct ospf_area_config *ac; /* Related area config */
int origrt; /* Rt lsa origination scheduled? */ int origrt; /* Rt lsa origination scheduled? */
struct top_hash_entry *rt; /* My own router LSA */ 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. */ list cand; /* List of candidates for RT calc. */
struct fib net_fib; /* Networks to advertise or not */ struct fib net_fib; /* Networks to advertise or not */
int stub; int stub;
int trcap; /* Transit capability? */ int trcap; /* Transit capability? */
u32 options; /* Optional features */
struct proto_ospf *po; struct proto_ospf *po;
struct fib rtr; /* Routing tables for routers */ struct fib rtr; /* Routing tables for routers */
union options opt; /* RFC2328 - A.2 */
}; };
struct proto_ospf struct proto_ospf
@ -577,20 +694,28 @@ struct ospf_iface_patt
u32 deadc; u32 deadc;
u32 dead; u32 dead;
u32 type; u32 type;
u32 autype;
u32 strictnbma; u32 strictnbma;
u32 stub; u32 stub;
u32 vid; 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; u32 rxbuf;
#define OSPF_RXBUF_NORMAL 0 #define OSPF_RXBUF_NORMAL 0
#define OSPF_RXBUF_LARGE 1 #define OSPF_RXBUF_LARGE 1
#define OSPF_RXBUF_MINSIZE 256 /* Minimal allowed size */ #define OSPF_RXBUF_MINSIZE 256 /* Minimal allowed size */
list *passwords;
list nbma_list; 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, 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->routerid = htonl(p->cf->global->router_id);
pkt->areaid = htonl(ifa->oa->areaid); pkt->areaid = htonl(ifa->oa->areaid);
#ifdef OSPFv3
pkt->instance_id = ifa->instance_id;
#endif
#ifdef OSPFv2
pkt->autype = htons(ifa->autype); pkt->autype = htons(ifa->autype);
#endif
pkt->checksum = 0; pkt->checksum = 0;
} }
unsigned unsigned
ospf_pkt_maxsize(struct ospf_iface *ifa) 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; 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) - return ((mtu <= ifa->iface->mtu) ? mtu : ifa->iface->mtu) -
SIZE_OF_IP_HEADER - ((ifa->autype == OSPF_AUTH_CRYPT) ? OSPF_AUTH_CRYPT_SIZE : 0); SIZE_OF_IP_HEADER - add;
/* For virtual links use mtu=576 */
} }
void
#ifdef OSPFv2
static void
ospf_pkt_finalize(struct ospf_iface *ifa, struct ospf_packet *pkt) ospf_pkt_finalize(struct ospf_iface *ifa, struct ospf_packet *pkt)
{ {
struct password_item *passwd = NULL; 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 * ospf_rx_hook
* @sk: socket we received the packet. Its ignored. * @sk: socket we received the packet. Its ignored.
@ -290,6 +320,8 @@ ospf_rx_hook(sock * sk, int size)
return 1; return 1;
} }
/* FIXME - handle checksums in OSPFv3 */
#ifdef OSPFv2
if ((ps->autype != htons(OSPF_AUTH_CRYPT)) && if ((ps->autype != htons(OSPF_AUTH_CRYPT)) &&
(!ipsum_verify(ps, 16, (void *) ps + sizeof(struct ospf_packet), (!ipsum_verify(ps, 16, (void *) ps + sizeof(struct ospf_packet),
ntohs(ps->length) - sizeof(struct ospf_packet), NULL))) 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); log(L_ERR "%s%I - bad checksum", mesg, sk->faddr);
return 1; return 1;
} }
#endif
if (ntohl(ps->areaid) != ifa->oa->areaid) 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; 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) if (ntohl(ps->routerid) == p->cf->global->router_id)
{ {
log(L_ERR "%s%I - received my own router ID!", mesg, sk->faddr); 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: case HELLO_P:
DBG("%s: Hello received.\n", p->name); 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; break;
case DBDES_P: case DBDES_P:
DBG("%s: Database description received.\n", p->name); 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; break;
case LSREQ_P: case LSREQ_P:
DBG("%s: Link state request received.\n", p->name); 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; break;
case LSUPD_P: case LSUPD_P:
DBG("%s: Link state update received.\n", p->name); 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; break;
case LSACK_P: case LSACK_P:
DBG("%s: Link state ack received.\n", p->name); 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; break;
default: default:
log(L_ERR "%s%I - wrong type %u", mesg, sk->faddr, ps->type); 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) ospf_send_to(sock *sk, ip_addr ip, struct ospf_iface *ifa)
{ {
struct ospf_packet *pkt = (struct ospf_packet *) sk->tbuf; struct ospf_packet *pkt = (struct ospf_packet *) sk->tbuf;
int len = ntohs(pkt->length) + ((ifa->autype == OSPF_AUTH_CRYPT) ? OSPF_AUTH_CRYPT_SIZE : 0); int len = ntohs(pkt->length);
ospf_pkt_finalize(ifa, pkt);
#ifdef OSPFv2
if (ifa->autype == OSPF_AUTH_CRYPT)
len += OSPF_AUTH_CRYPT_SIZE;
#endif
ospf_pkt_finalize(ifa, pkt);
if (sk->tbuf != sk->tpos) if (sk->tbuf != sk->tpos)
log(L_ERR "Aiee, old packet was overwritted in TX buffer"); log(L_ERR "Aiee, old packet was overwritted in TX buffer");

View file

@ -10,18 +10,56 @@
static void static void
add_cand(list * l, struct top_hash_entry *en, 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 static void
calc_next_hop(struct top_hash_entry *en, calc_next_hop(struct top_hash_entry *en,
struct top_hash_entry *par, struct ospf_area *oa); struct top_hash_entry *par, struct ospf_area *oa);
static void ospf_ext_spf(struct proto_ospf *po); static void ospf_ext_spf(struct proto_ospf *po);
static void rt_sync(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 static void
fill_ri(orta * orta) fill_ri(orta * orta)
{ {
orta->type = RTS_DUMMY; orta->type = RTS_DUMMY;
orta->capa = 0; orta->options = 0;
orta->oa = NULL; orta->oa = NULL;
orta->metric1 = LSINFINITY; orta->metric1 = LSINFINITY;
orta->metric2 = LSINFINITY; orta->metric2 = LSINFINITY;
@ -159,6 +197,7 @@ ospf_rt_spfa(struct ospf_area *oa)
if (oa->rt->dist != LSINFINITY) if (oa->rt->dist != LSINFINITY)
bug("Aging was not processed."); bug("Aging was not processed.");
/* 16.1. (1) */
init_list(&oa->cand); /* Empty list of candidates */ init_list(&oa->cand); /* Empty list of candidates */
oa->trcap = 0; oa->trcap = 0;
@ -183,15 +222,15 @@ ospf_rt_spfa(struct ospf_area *oa)
switch (act->lsa.type) switch (act->lsa.type)
{ {
case LSA_T_RT: case LSA_T_RT:
/* FIXME - in OSPFv3 we should process all RT LSAs from that router */
rt = (struct ospf_lsa_rt *) act->lsa_body; rt = (struct ospf_lsa_rt *) act->lsa_body;
if (rt->veb.bit.v) if (rt->options & OPT_RT_V)
oa->trcap = 1; 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.type = RTS_OSPF;
nf.capa = 0; nf.options = rt->options;
if (rt->veb.bit.b) nf.capa |= ORTA_ABR;
if (rt->veb.bit.e) nf.capa |= ORTA_ASBR;
nf.metric1 = act->dist; nf.metric1 = act->dist;
nf.metric2 = LSINFINITY; nf.metric2 = LSINFINITY;
nf.tag = 0; nf.tag = 0;
@ -199,26 +238,27 @@ ospf_rt_spfa(struct ospf_area *oa)
nf.ar = act; nf.ar = act;
nf.nh = act->nh; nf.nh = act->nh;
nf.ifa = act->nhi; 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); rr = (struct ospf_lsa_rt_link *) (rt + 1);
DBG(" Number of links: %u\n", rt->links); 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; tmp = NULL;
rtl = (rr + i); rtl = (rr + i);
DBG(" Working on link: %R (type: %u) ", rtl->id, rtl->type); DBG(" Working on link: %R (type: %u) ", rtl->id, rtl->type);
switch (rtl->type) switch (rtl->type)
{ {
#ifdef OSPFv2
case LSART_STUB: case LSART_STUB:
/* /*
* This violates rfc2328! but I hope * This violates rfc2328! But it is mostly harmless.
* it's also correct. * But it causes that the cost of the stub is ignored.
*/ */
DBG("\n"); DBG("\n");
nf.type = RTS_OSPF; nf.type = RTS_OSPF;
nf.capa = 0; nf.options = 0;
nf.metric1 = act->dist + rtl->metric; nf.metric1 = act->dist + rtl->metric;
nf.metric2 = LSINFINITY; nf.metric2 = LSINFINITY;
nf.tag = 0; nf.tag = 0;
@ -249,9 +289,14 @@ ospf_rt_spfa(struct ospf_area *oa)
ri_install(po, ipa_from_u32(rtl->id), ri_install(po, ipa_from_u32(rtl->id),
ipa_mklen(ipa_from_u32(rtl->data)), ORT_NET, &nf, NULL); ipa_mklen(ipa_from_u32(rtl->data)), ORT_NET, &nf, NULL);
break; break;
#endif
case LSART_NET: 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) if (tmp == NULL)
DBG("Not found!\n"); DBG("Not found!\n");
else else
@ -260,7 +305,8 @@ ospf_rt_spfa(struct ospf_area *oa)
case LSART_VLNK: case LSART_VLNK:
case LSART_PTP: 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"); DBG("PTP found.\n");
break; break;
default: default:
@ -276,7 +322,7 @@ ospf_rt_spfa(struct ospf_area *oa)
case LSA_T_NET: case LSA_T_NET:
ln = act->lsa_body; ln = act->lsa_body;
nf.type = RTS_OSPF; nf.type = RTS_OSPF;
nf.capa = 0; nf.options = 0;
nf.metric1 = act->dist; nf.metric1 = act->dist;
nf.metric2 = LSINFINITY; nf.metric2 = LSINFINITY;
nf.tag = 0; nf.tag = 0;
@ -288,11 +334,11 @@ ospf_rt_spfa(struct ospf_area *oa)
ipa_mklen(ln->netmask), ORT_NET, &nf, NULL); ipa_mklen(ln->netmask), ORT_NET, &nf, NULL);
rts = (u32 *) (ln + 1); rts = (u32 *) (ln + 1);
for (i = 0; i < (act->lsa.length - sizeof(struct ospf_lsa_header) - for (i = 0; i < lsa_net_count(&act->lsa); i++)
sizeof(struct ospf_lsa_net)) / sizeof(u32); i++)
{ {
DBG(" Working on router %R ", rts[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) if (tmp != NULL)
DBG("Found :-)\n"); DBG("Found :-)\n");
else else
@ -308,7 +354,8 @@ ospf_rt_spfa(struct ospf_area *oa)
{ {
if ((iface->type == OSPF_IT_VLINK) && (iface->voa == 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))) (!ipa_equal(tmp->lb, IPA_NONE)))
{ {
if ((iface->state != OSPF_IS_PTP) || (iface->iface != tmp->nhi->iface) || (!ipa_equal(iface->vip, tmp->lb))) 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: case LSA_T_RT:
rt = (struct ospf_lsa_rt *) fol->lsa_body; rt = (struct ospf_lsa_rt *) fol->lsa_body;
rr = (struct ospf_lsa_rt_link *) (rt + 1); 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); rtl = (rr + i);
switch (rtl->type) 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: case LSART_STUB:
break; break;
case LSART_NET: 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); fol->lb = ipa_from_u32(rtl->data);
return 1; return 1;
@ -364,7 +411,7 @@ link_back(struct ospf_area *oa, struct top_hash_entry *fol, struct top_hash_entr
break; break;
case LSART_VLNK: case LSART_VLNK:
case LSART_PTP: 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); fol->lb = ipa_from_u32(rtl->data);
return 1; 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: case LSA_T_NET:
ln = fol->lsa_body; ln = fol->lsa_body;
rts = (u32 *) (ln + 1); rts = (u32 *) (ln + 1);
for (i = 0; i < (fol->lsa.length - sizeof(struct ospf_lsa_header) - for (i = 0; i < lsa_net_count(&fol->lsa); i++)
sizeof(struct ospf_lsa_net)) / sizeof(u32); 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; return 1;
} }
@ -400,10 +446,10 @@ ospf_rt_sum_tr(struct ospf_area *oa)
struct proto *p = &oa->po->proto; struct proto *p = &oa->po->proto;
struct proto_ospf *po = oa->po; struct proto_ospf *po = oa->po;
struct ospf_area *bb = po->backbone; struct ospf_area *bb = po->backbone;
ip_addr *mask, ip, abrip; ip_addr ip, abrip;
struct top_hash_entry *en; struct top_hash_entry *en;
int mlen = -1, type = -1; u32 dst_rid, metric, options;
union ospf_lsa_sum_tm *tm; int pxlen = -1, type = -1;
ort *re = NULL, *abr; ort *re = NULL, *abr;
orta nf; orta nf;
@ -411,57 +457,80 @@ ospf_rt_sum_tr(struct ospf_area *oa)
WALK_SLIST(en, po->lsal) 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; continue;
if (en->domain != oa->areaid)
continue;
if (en->lsa.age == LSA_MAXAGE) if (en->lsa.age == LSA_MAXAGE)
continue; continue;
if (en->dist == LSINFINITY) if (en->dist == LSINFINITY)
continue; continue;
if (en->lsa.rt == p->cf->global->router_id) if (en->lsa.rt == p->cf->global->router_id)
continue; 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) if (en->lsa.type == LSA_T_SUM_NET)
{ {
mlen = ipa_mklen(*mask); #ifdef OSPFv2
ip = ipa_and(ipa_from_u32(en->lsa.id), *mask); 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; 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) continue;
if (re->n.oa->areaid != 0) continue; if (re->n.oa->areaid != 0) continue;
if ((re->n.type != RTS_OSPF) && (re->n.type != RTS_OSPF_IA)) 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); abr = fib_find(&oa->rtr, &abrip, 32);
if (!abr) continue; if (!abr) continue;
tm = (union ospf_lsa_sum_tm *)(mask + 1);
nf.type = re->n.type; nf.type = re->n.type;
nf.capa = ORTA_ASBR; nf.options = options;
nf.metric1 = abr->n.metric1 + (tm->metric & METRIC_MASK); nf.metric1 = abr->n.metric1 + metric;
nf.metric2 = LSINFINITY; nf.metric2 = LSINFINITY;
nf.tag = 0; nf.tag = 0;
nf.oa = oa; nf.oa = oa;
nf.ar = abr->n.ar; nf.ar = abr->n.ar;
nf.nh = abr->n.nh; nf.nh = abr->n.nh;
nf.ifa = abr->n.ifa; 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_ospf *po = oa->po;
struct proto *p = &po->proto; struct proto *p = &po->proto;
struct top_hash_entry *en; 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; struct area_net *anet;
orta nf; orta nf;
ort *abr; ort *abr;
int mlen = -1, type = -1; int pxlen = -1, type = -1;
union ospf_lsa_sum_tm *tm;
OSPF_TRACE(D_EVENTS, "Starting routing table calculation for inter-area (area %R)", oa->areaid); OSPF_TRACE(D_EVENTS, "Starting routing table calculation for inter-area (area %R)", oa->areaid);
WALK_SLIST(en, po->lsal) 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; continue;
if (en->domain != oa->areaid)
continue;
/* Page 169 (1) */ /* Page 169 (1) */
if (en->lsa.age == LSA_MAXAGE) if (en->lsa.age == LSA_MAXAGE)
continue; continue;
/* Page 169 (2) */ /* Page 169 (2) */
if (en->lsa.rt == p->cf->global->router_id) if (en->lsa.rt == p->cf->global->router_id)
continue; 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) if (en->lsa.type == LSA_T_SUM_NET)
{ {
struct ospf_area *oaa; struct ospf_area *oaa;
int skip = 0; 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) */ /* Page 169 (3) */
WALK_LIST(oaa, po->area_list) 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; skip = 1;
break; break;
} }
} }
if (skip) continue; if (skip) continue;
type = ORT_NET;
} }
else else
{ {
ip = ipa_from_u32(en->lsa.id); #ifdef OSPFv2
mlen = 32; 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; 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 = (ort *) fib_find(&oa->rtr, &abrip, 32))) continue;
if (abr->n.metric1 == LSINFINITY) 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.type = RTS_OSPF_IA;
nf.capa = ORTA_ASBR; nf.options = options;
nf.metric1 = abr->n.metric1 + (tm->metric & METRIC_MASK); nf.metric1 = abr->n.metric1 + metric;
nf.metric2 = LSINFINITY; nf.metric2 = LSINFINITY;
nf.tag = 0; nf.tag = 0;
nf.oa = oa; nf.oa = oa;
nf.ar = abr->n.ar; nf.ar = abr->n.ar;
nf.nh = abr->n.nh; nf.nh = abr->n.nh;
nf.ifa = abr->n.ifa; 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"); OSPF_TRACE(D_EVENTS, "Starting routing table calculation");
/* Invalidate old routing table */ /* 16. (1) - Invalidate old routing table */
FIB_WALK(&po->rtf, nftmp) FIB_WALK(&po->rtf, nftmp)
{ {
ri = (ort *) nftmp; ri = (ort *) nftmp;
@ -594,9 +690,12 @@ ospf_rt_spf(struct proto_ospf *po)
anet->metric = 1; anet->metric = 1;
} }
FIB_WALK_END; FIB_WALK_END;
/* 16. (2) */
ospf_rt_spfa(oa); ospf_rt_spfa(oa);
} }
/* 16. (3) */
if ((po->areano == 1) || (!po->backbone)) if ((po->areano == 1) || (!po->backbone))
{ {
ospf_rt_sum(HEAD(po->area_list)); ospf_rt_sum(HEAD(po->area_list));
@ -606,6 +705,7 @@ ospf_rt_spf(struct proto_ospf *po)
ospf_rt_sum(po->backbone); ospf_rt_sum(po->backbone);
} }
/* 16. (4) */
WALK_LIST(oa, po->area_list) WALK_LIST(oa, po->area_list)
{ {
if (oa->trcap && (oa->areaid != 0)) if (oa->trcap && (oa->areaid != 0))
@ -615,6 +715,7 @@ ospf_rt_spf(struct proto_ospf *po)
} }
} }
/* 16. (5) */
ospf_ext_spf(po); ospf_ext_spf(po);
rt_sync(po); rt_sync(po);
@ -622,13 +723,12 @@ ospf_rt_spf(struct proto_ospf *po)
po->calcrt = 0; po->calcrt = 0;
} }
/** /**
* ospf_ext_spf - calculate external paths * ospf_ext_spf - calculate external paths
* @po: protocol * @po: protocol
* *
* After routing table for any area is calculated, calculation of external * 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. * Inter- and Intra-area paths are always prefered over externals.
*/ */
static void static void
@ -639,50 +739,75 @@ ospf_ext_spf(struct proto_ospf *po)
struct top_hash_entry *en; struct top_hash_entry *en;
struct proto *p = &po->proto; struct proto *p = &po->proto;
struct ospf_lsa_ext *le; struct ospf_lsa_ext *le;
struct ospf_lsa_ext_tos *lt; int pxlen, ebit, rt_fwaddr_valid;
int mlen; ip_addr ip, nh, rtid, rt_fwaddr;
ip_addr ip, nh, rtid;
struct ospf_iface *nhi = NULL; struct ospf_iface *nhi = NULL;
int met1, met2; u32 br_metric, rt_metric, rt_tag;
neighbor *nn; neighbor *nn;
struct ospf_area *atmp; struct ospf_area *atmp;
OSPF_TRACE(D_EVENTS, "Starting routing table calculation for ext routes"); OSPF_TRACE(D_EVENTS, "Starting routing table calculation for ext routes");
WALK_SLIST(en, po->lsal) WALK_SLIST(en, po->lsal)
{ {
/* 16.4. (1) */
if (en->lsa.type != LSA_T_EXT) if (en->lsa.type != LSA_T_EXT)
continue; continue;
if (en->lsa.age == LSA_MAXAGE) if (en->lsa.age == LSA_MAXAGE)
continue; continue;
/* 16.4. (2) */
if (en->lsa.rt == p->cf->global->router_id) if (en->lsa.rt == p->cf->global->router_id)
continue; 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", 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); 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; continue;
#ifdef OSPFv2
ip = ipa_and(ipa_from_u32(en->lsa.id), le->netmask); ip = ipa_and(ipa_from_u32(en->lsa.id), le->netmask);
mlen = ipa_mklen(le->netmask); pxlen = ipa_mklen(le->netmask);
if ((mlen < 0) || (mlen > 32)) 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", log("%s: Invalid mask in LSA. ID: %R, RT: %R, Type: %u",
p->name, en->lsa.id, en->lsa.rt, en->lsa.type, le->netmask); p->name, en->lsa.id, en->lsa.rt, en->lsa.type);
continue; continue;
} }
nhi = NULL; nhi = NULL;
nh = IPA_NONE; nh = IPA_NONE;
met1 = LSINFINITY; /* 16.4. (3) */
met2 = LSINFINITY; rtid = ipa_from_rid(en->lsa.rt);
rtid = ipa_from_u32(en->lsa.rt);
nf1 = NULL; nf1 = NULL;
WALK_LIST(atmp, po->area_list) WALK_LIST(atmp, po->area_list)
{ {
@ -698,50 +823,30 @@ ospf_ext_spf(struct proto_ospf *po)
if (nf1->n.metric1 == LSINFINITY) if (nf1->n.metric1 == LSINFINITY)
continue; /* distance is INF */ continue; /* distance is INF */
if (!(nf1->n.capa & ORTA_ASBR)) if (!(nf1->n.options & ORTA_ASBR))
continue; /* It is not 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; nh = nf1->n.nh;
nhi = nf1->n.ifa; nhi = nf1->n.ifa;
nfh = nf1; nfh = nf1;
br_metric = nf1->n.metric1;
} }
else else
{ /* FW address !=0 */ {
nf2 = fib_route(&po->rtf, lt->fwaddr, 32); nf2 = fib_route(&po->rtf, rt_fwaddr, 32);
if (!nf2) if (!nf2)
{ {
DBG("Cannot find network route (GW=%I)\n", lt->fwaddr); DBG("Cannot find network route (GW=%I)\n", rt_fwaddr);
continue; 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); nhi = ospf_iface_find(po, nn->iface);
} }
else else
@ -750,20 +855,31 @@ ospf_ext_spf(struct proto_ospf *po)
nhi = nf2->n.ifa; nhi = nf2->n.ifa;
} }
if (nf2->n.metric1 == LSINFINITY) br_metric = nf2->n.metric1;
if (br_metric == LSINFINITY)
continue; /* distance is INF */ continue; /* distance is INF */
} }
nfa.type = (met2 == LSINFINITY) ? RTS_OSPF_EXT1 : RTS_OSPF_EXT2; if (ebit)
nfa.capa = 0; {
nfa.metric1 = met1; nfa.type = RTS_OSPF_EXT2;
nfa.metric2 = met2; nfa.metric1 = br_metric;
nfa.tag = lt->tag; 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.oa = (po->backbone == NULL) ? HEAD(po->area_list) : po->backbone;
nfa.ar = nf1->n.ar; nfa.ar = nf1->n.ar;
nfa.nh = nh; nfa.nh = nh;
nfa.ifa = nhi; 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 */ /* Add LSA into list of candidates in Dijkstra's algorithm */
static void static void
add_cand(list * l, struct top_hash_entry *en, struct top_hash_entry *par, 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; node *prev, *n;
int added = 0; 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) if (en->lsa.age == LSA_MAXAGE)
return; return;
/* 16.1. (2c) */
if (en->color == INSPF) if (en->color == INSPF)
return; return;
/* 16.1. (2d) */
if (dist >= en->dist) if (dist >= en->dist)
return; 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); act = SKIP_BACK(struct top_hash_entry, cn, n);
if ((act->dist > dist) || if ((act->dist > dist) ||
((act->dist == dist) && (act->lsa.type == LSA_T_NET))) ((act->dist == dist) && (act->lsa.type == LSA_T_NET)))
/* FIXME - shouldn't be here LSA_T_RT ??? */
{ {
if (prev == NULL) if (prev == NULL)
add_head(l, &en->cn); 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; struct ospf_iface *ifa;
u32 myrid = p->cf->global->router_id; u32 myrid = p->cf->global->router_id;
/* 16.1.1. The next hop calculation */
DBG(" Next hop called.\n"); DBG(" Next hop called.\n");
if (ipa_equal(par->nh, IPA_NONE)) 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", DBG(" Next hop calculating for id: %R rt: %R type: %u\n",
en->lsa.id, en->lsa.rt, en->lsa.type); en->lsa.id, en->lsa.rt, en->lsa.type);
/* The parent vertex is the root */
if (par == oa->rt) if (par == oa->rt)
{ {
if (en->lsa.type == LSA_T_NET) 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; 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 (par->lsa.type == LSA_T_NET)
{ {
if (en->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 ((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))) && (!ipa_equal(en->nh, IPA_NONE)))
{ {
a0.gw = en->nh; a0.gw = en->nh;
@ -1054,7 +1179,7 @@ again2:
if (oaa->stub) fl = 1; if (oaa->stub) fl = 1;
if (fl) flush_sum_lsa(oaa, &anet->fn, ORT_NET); 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; FIB_WALK_END;
@ -1067,7 +1192,7 @@ again2:
fnn.prefix = IPA_NONE; fnn.prefix = IPA_NONE;
fnn.pxlen = 0; 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); else flush_sum_lsa(oa, &fnn, ORT_NET);
} }
} }

View file

@ -17,9 +17,12 @@
typedef struct orta typedef struct orta
{ {
int type; int type;
int capa; u32 options;
#define ORTA_ASBR 1 /* router-LSA style options (for ORT_ROUTER), with V,E,B bits.
#define ORTA_ABR 2 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; struct ospf_area *oa;
u32 metric1; u32 metric1;
u32 metric2; 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 */ { /* Index for fast mapping (type,rtrid,LSid)->vertex */
snode n; snode n;
node cn; /* For adding into list of candidates node cn; /* For adding into list of candidates
* in intra-area routing table in intra-area routing table calculation */
* calculation
*/
struct top_hash_entry *next; /* Next in hash chain */ struct top_hash_entry *next; /* Next in hash chain */
struct ospf_lsa_header lsa; 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; void *lsa_body;
bird_clock_t inst_t; /* Time of installation into DB */ bird_clock_t inst_t; /* Time of installation into DB */
ip_addr nh; /* Next hop */ ip_addr nh; /* Next hop */
@ -48,13 +47,19 @@ struct top_graph
struct top_graph *ospf_top_new(pool *); struct top_graph *ospf_top_new(pool *);
void ospf_top_free(struct top_graph *); void ospf_top_free(struct top_graph *);
void ospf_top_dump(struct top_graph *, struct proto *); 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 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 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); 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); u32 type);
void ospf_hash_delete(struct top_graph *, struct top_hash_entry *); void ospf_hash_delete(struct top_graph *, struct top_hash_entry *);
void originate_rt_lsa(struct ospf_area *oa); 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, void originate_ext_lsa(net * n, rte * e, struct proto_ospf *po,
struct ea_list *attrs); struct ea_list *attrs);
void check_sum_lsa(struct proto_ospf *po, ort *nf, int); 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); void flush_sum_lsa(struct ospf_area *oa, struct fib_node *fn, int type);