0
0
mirror of https://gitlab.nic.cz/labs/bird.git synced 2025-01-08 18:11:54 +00:00

Temporary integrated commit (OSPF), unfinished.

This commit is contained in:
Ondrej Zajicek 2012-10-02 11:44:05 +02:00
parent a7b7b2bd0f
commit 5aa9d7447c
19 changed files with 895 additions and 894 deletions

View File

@ -19,13 +19,13 @@
#define IP4_MIN_MTU 576 /* RFC 2328 A.1 */ #define IP4_MIN_MTU 576 /* RFC 2328 A.1 */
#define IP6_MIN_MTU 1280 /* RFC 5340 A.1 */ #define IP6_MIN_MTU 1280 /* RFC 5340 A.1 */
#define IP4_ALL_SPF_ROUTERS ipa_build4(224, 0, 0, 5) #define IP4_OSPF_ALL_ROUTERS ipa_build4(224, 0, 0, 5)
#define IP4_ALL_D_ROUTERS ipa_build4(224, 0, 0, 6) #define IP4_OSPF_DES_ROUTERS ipa_build4(224, 0, 0, 6)
#define IP6_All_NODES ipa_build6(0xFF020000, 0, 0, 1) #define IP6_ALL_NODES ipa_build6(0xFF020000, 0, 0, 1)
#define IP6_ALL_ROUTERS ipa_build6(0xFF020000, 0, 0, 2) #define IP6_ALL_ROUTERS ipa_build6(0xFF020000, 0, 0, 2)
#define IP6_ALL_OSPF_ROUTERS ipa_build6(0xFF020000, 0, 0, 5) #define IP6_OSPF_ALL_ROUTERS ipa_build6(0xFF020000, 0, 0, 5)
#define IP6_ALL_OSPF_D_ROUTERS ipa_build6(0xFF020000, 0, 0, 6) #define IP6_OSPF_DES_ROUTERS ipa_build6(0xFF020000, 0, 0, 6)
#define IP4_NONE _MI4(0) #define IP4_NONE _MI4(0)
#define IP6_NONE _MI6(0,0,0,0) #define IP6_NONE _MI6(0,0,0,0)

View File

@ -143,8 +143,7 @@ ospf_proto_start: proto_start OSPF {
this_proto = proto_config_new(&proto_ospf, sizeof(struct ospf_config), $1); this_proto = proto_config_new(&proto_ospf, sizeof(struct ospf_config), $1);
init_list(&OSPF_CFG->area_list); init_list(&OSPF_CFG->area_list);
init_list(&OSPF_CFG->vlink_list); init_list(&OSPF_CFG->vlink_list);
OSPF_CFG->rfc1583 = DEFAULT_RFC1583; OSPF_CFG->tick = OSPF_DEFAULT_TICK;
OSPF_CFG->tick = DEFAULT_OSPFTICK;
} }
; ;
@ -166,9 +165,9 @@ ospf_area_start: AREA idval {
this_area = cfg_allocz(sizeof(struct ospf_area_config)); this_area = cfg_allocz(sizeof(struct ospf_area_config));
add_tail(&OSPF_CFG->area_list, NODE this_area); add_tail(&OSPF_CFG->area_list, NODE this_area);
this_area->areaid = $2; this_area->areaid = $2;
this_area->default_cost = DEFAULT_STUB_COST; this_area->default_cost = OSPF_DEFAULT_STUB_COST;
this_area->type = OPT_E; this_area->type = OPT_E;
this_area->transint = DEFAULT_TRANSINT; this_area->transint = OSPF_DEFAULT_TRANSINT;
init_list(&this_area->patt_list); init_list(&this_area->patt_list);
init_list(&this_area->net_list); init_list(&this_area->net_list);

View File

@ -36,20 +36,6 @@ struct ospf_dbdes3_packet
}; };
#ifdef OSPFv2
#define hton_opt(X) X
#define ntoh_opt(X) X
#endif
#ifdef OSPFv3
#define hton_opt(X) htonl(X)
#define ntoh_opt(X) ntohl(X)
#endif
static inline unsigned static inline unsigned
ospf_dbdes_hdrlen(struct proto_ospf *po) ospf_dbdes_hdrlen(struct proto_ospf *po)
{ {
@ -69,30 +55,113 @@ ospf_dbdes_body(struct proto_ospf *po, struct ospf_packet *pkt, unsigned plen,
static void ospf_dbdes_dump(struct proto_ospf *po, struct ospf_packet *pkt) static void ospf_dbdes_dump(struct proto_ospf *po, struct ospf_packet *pkt)
{ {
struct proto *p = &po->proto;
struct ospf_lsa_header *lsas; struct ospf_lsa_header *lsas;
unsigned i, lsa_count; unsigned i, lsa_count;
u32 pkt_ddseq;
u16 pkt_iface_mtu;
u8 pkt_imms;
ASSERT(pkt->type == DBDES_P); ASSERT(pkt->type == DBDES_P);
ospf_dump_common(po, pkt); ospf_dump_common(po, pkt);
log(L_TRACE "%s: imms %s%s%s", p->name, if (ospf_is_v2(po))
(imms & DBDES_I) ? "I " : "", {
(imms & DBDES_M) ? "M " : "", struct ospf_dbdes2_packet *ps = (void *) pkt;
(imms & DBDES_MS) ? "MS" : ""); pkt_iface_mtu = ntohs(ps->iface_mtu);
log(L_TRACE "%s: ddseq %u", p->name, ntohl(pkt->ddseq)); pkt_imms = ps->imms;
pkt_ddseq = ntohl(ps->ddseq);
}
else /* OSPFv3 */
{
struct ospf_dbdes3_packet *ps = (void *) pkt;
pkt_iface_mtu = ntohs(ps->iface_mtu);
pkt_imms = ps->imms;
pkt_ddseq = ntohl(ps->ddseq);
}
struct ospf_lsa_header *plsa = (void *) (pkt + 1); log(L_TRACE "%s: mtu %u", po->proto.name, pkt_iface_mtu);
unsigned int i, j; log(L_TRACE "%s: imms %s%s%s", po->proto.name,
(pkt_imms & DBDES_I) ? "I " : "",
(pkt_imms & DBDES_M) ? "M " : "",
(pkt_imms & DBDES_MS) ? "MS" : "");
log(L_TRACE "%s: ddseq %u", po->proto.name, pkt_ddseq);
j = (ntohs(op->length) - sizeof(struct ospf_dbdes_packet)) / ospf_dbdes_body(po, pkt, ntohs(pkt->length), &lsas, &lsa_count);
sizeof(struct ospf_lsa_header); for (i = 0; i < lsa_count; i++)
ospf_dump_lsahdr(po, lsas + i);
for (i = 0; i < j; i++)
ospf_dump_lsahdr(p, &lsas[i]);
} }
static void
ospf_dbdes_prepare(struct ospf_neighbor *n, struct ospf_packet *pkt, int lsdb)
{
struct ospf_iface *ifa = n->ifa;
struct proto_ospf *po = ifa->oa->po;
int i = 0;
ospf_pkt_fill_hdr(ifa, pkt, DBDES_P);
if (lsdb && (n->myimms & DBDES_M))
{
struct ospf_lsa_header *lsas;
unsigned lsa_max;
snode *sn;
ospf_dbdes_body(po, pkt, ospf_pkt_maxsize(ifa), &lsas, &lsa_max);
sn = s_get(&(n->dbsi));
while (i < lsa_max)
{
struct top_hash_entry *en = (struct top_hash_entry *) sn;
if (lsa_flooding_allowed(en->lsa_type, en->domain, ifa))
{
lsa_hton_hdr(&(en->lsa), lsas + i);
i++;
}
if (sn == STAIL(po->lsal))
{
n->myimms &= ~DBDES_M; /* Unset more bit */
break;
}
sn = sn->next;
}
s_put(&(n->dbsi), sn);
}
u16 iface_mtu = (ifa->type == OSPF_IT_VLINK) ? 0 : ifa->iface->mtu;
unsigned length;
if (ospf_is_v2(po))
{
struct ospf_dbdes2_packet *ps = (void *) pkt;
ps->iface_mtu = htons(iface_mtu);
ps->options = ifa->oa->options;
ps->imms = n->myimms;
ps->ddseq = htonl(n->dds);
length = sizeof(struct ospf_dbdes2_packet);
}
else /* OSPFv3 */
{
struct ospf_dbdes3_packet *ps = (void *) pkt;
ps->options = htonl(ifa->oa->options);
ps->iface_mtu = htons(iface_mtu);
ps->imms = n->myimms;
ps->ddseq = htonl(n->dds);
length = sizeof(struct ospf_dbdes3_packet);
}
length += i * sizeof(struct ospf_lsa_header);
pkt->length = htons(length);
}
/** /**
* ospf_dbdes_send - transmit database description packet * ospf_dbdes_send - transmit database description packet
* @n: neighbor * @n: neighbor
@ -110,10 +179,8 @@ ospf_dbdes_send(struct ospf_neighbor *n, int next)
struct ospf_iface *ifa = n->ifa; struct ospf_iface *ifa = n->ifa;
struct ospf_area *oa = ifa->oa; struct ospf_area *oa = ifa->oa;
struct proto_ospf *po = oa->po; struct proto_ospf *po = oa->po;
struct ospf_packet *pkt;
struct ospf_dbdes_packet *pkt; unsigned length;
struct ospf_packet *op;
u16 length, i, j;
/* FIXME ??? */ /* FIXME ??? */
if ((oa->rt == NULL) || (EMPTY_LIST(po->lsal))) if ((oa->rt == NULL) || (EMPTY_LIST(po->lsal)))
@ -121,19 +188,13 @@ ospf_dbdes_send(struct ospf_neighbor *n, int next)
switch (n->state) switch (n->state)
{ {
case NEIGHBOR_EXSTART: /* Send empty packets */ case NEIGHBOR_EXSTART:
n->myimms |= DBDES_I; n->myimms |= DBDES_I;
pkt = ospf_tx_buffer(ifa);
op = &pkt->ospf_packet;
ospf_pkt_fill_hdr(ifa, pkt, DBDES_P);
pkt->iface_mtu = (ifa->type == OSPF_IT_VLINK) ? 0 : htons(ifa->iface->mtu);
pkt->options = hton_opt(oa->options);
pkt->imms = n->myimms;
pkt->ddseq = htonl(n->dds);
length = sizeof(struct ospf_dbdes_packet);
op->length = htons(length);
OSPF_PACKET(ospf_dump_dbdes, pkt, "DBDES packet sent to %I via %s", n->ip, ifa->iface->name); /* Send empty packets */
pkt = ospf_tx_buffer(ifa);
ospf_dbdes_prepare(n, pkt, 0);
OSPF_PACKET(ospf_dbdes_dump, pkt, "DBDES packet sent to %I via %s", n->ip, ifa->iface->name);
ospf_send_to(ifa, n->ip); ospf_send_to(ifa, n->ip);
break; break;
@ -141,72 +202,12 @@ ospf_dbdes_send(struct ospf_neighbor *n, int next)
n->myimms &= ~DBDES_I; n->myimms &= ~DBDES_I;
if (next) if (next)
{ ospf_dbdes_prepare(n, n->ldbdes, 1);
snode *sn;
struct ospf_lsa_header *lsa;
pkt = n->ldbdes;
op = (struct ospf_packet *) pkt;
ospf_pkt_fill_hdr(ifa, pkt, DBDES_P);
pkt->iface_mtu = (ifa->type == OSPF_IT_VLINK) ? 0 : htons(ifa->iface->mtu);
pkt->ddseq = htonl(n->dds);
pkt->options = hton_opt(oa->options);
j = i = (ospf_pkt_maxsize(ifa) - sizeof(struct ospf_dbdes_packet)) / sizeof(struct ospf_lsa_header); /* Number of possible lsaheaders to send */
lsa = (n->ldbdes + sizeof(struct ospf_dbdes_packet));
if (n->myimms & DBDES_M)
{
sn = s_get(&(n->dbsi));
DBG("Number of LSA: %d\n", j);
for (; i > 0; i--)
{
struct top_hash_entry *en= (struct top_hash_entry *) sn;
if (ospf_lsa_flooding_allowed(&en->lsa, en->domain, ifa))
{
htonlsah(&(en->lsa), lsa);
DBG("Working on: %d\n", i);
DBG("\tX%01x %-1R %-1R %p\n", en->lsa.type, en->lsa.id, en->lsa.rt, en->lsa_body);
lsa++;
}
else i++; /* No lsa added */
if (sn == STAIL(po->lsal))
{
i--;
break;
}
sn = sn->next;
}
if (sn == STAIL(po->lsal))
{
DBG("Number of LSA NOT sent: %d\n", i);
DBG("M bit unset.\n");
n->myimms &= ~DBDES_M; /* Unset more bit */
}
s_put(&(n->dbsi), sn);
}
pkt->imms = n->myimms;
length = (j - i) * sizeof(struct ospf_lsa_header) +
sizeof(struct ospf_dbdes_packet);
op->length = htons(length);
DBG("%s: DB_DES (M) prepared for %I.\n", p->name, n->ip);
}
case NEIGHBOR_LOADING: case NEIGHBOR_LOADING:
case NEIGHBOR_FULL: case NEIGHBOR_FULL:
length = ntohs(((struct ospf_packet *) n->ldbdes)->length);
length = ntohs(((struct ospf_packet *) n->ldbdes)->length);
if (!length) if (!length)
{ {
OSPF_TRACE(D_PACKETS, "No packet in my buffer for repeating"); OSPF_TRACE(D_PACKETS, "No packet in my buffer for repeating");
@ -218,21 +219,19 @@ ospf_dbdes_send(struct ospf_neighbor *n, int next)
pkt = ospf_tx_buffer(ifa); pkt = ospf_tx_buffer(ifa);
memcpy(pkt, n->ldbdes, length); memcpy(pkt, n->ldbdes, length);
OSPF_PACKET(ospf_dump_dbdes, pkt, "DBDES packet sent to %I via %s", n->ip, ifa->iface->name); OSPF_PACKET(ospf_dbdes_dump, pkt, "DBDES packet sent to %I via %s", n->ip, ifa->iface->name);
ospf_send_to(ifa, n->ip); ospf_send_to(ifa, n->ip);
/* XXXX remove this? */
if (n->myimms & DBDES_MS) if (n->myimms & DBDES_MS)
tm_start(n->rxmt_timer, n->ifa->rxmtint); /* Restart timer */ tm_start(n->rxmt_timer, n->ifa->rxmtint); /* Restart timer */
if (!(n->myimms & DBDES_MS)) if (!(n->myimms & DBDES_MS))
{
if (!(n->myimms & DBDES_M) && if (!(n->myimms & DBDES_M) &&
!(n->imms & DBDES_M) && !(n->imms & DBDES_M) &&
(n->state == NEIGHBOR_EXCHANGE)) (n->state == NEIGHBOR_EXCHANGE))
{
ospf_neigh_sm(n, INM_EXDONE); ospf_neigh_sm(n, INM_EXDONE);
}
}
break; break;
default: /* Ignore it */ default: /* Ignore it */
@ -241,36 +240,35 @@ ospf_dbdes_send(struct ospf_neighbor *n, int next)
} }
static void static void
ospf_dbdes_reqladd(struct ospf_dbdes_packet *ps, struct ospf_neighbor *n) ospf_dbdes_process(struct ospf_neighbor *n, struct ospf_packet *pkt, unsigned plen)
{ {
struct ospf_lsa_header *plsa, lsa; struct ospf_iface *ifa = n->ifa;
struct top_hash_entry *he, *sn; struct proto_ospf *po = ifa->oa->po;
struct ospf_area *oa = n->ifa->oa; struct ospf_lsa_header *lsas;
struct top_graph *gr = oa->po->gr; unsigned i, lsa_count;
struct ospf_packet *op;
int i, j;
op = (struct ospf_packet *) ps; ospf_dbdes_body(po, pkt, plen, &lsas, &lsa_count);
plsa = (void *) (ps + 1); for (i = 0; i < lsa_count; i++)
j = (ntohs(op->length) - sizeof(struct ospf_dbdes_packet)) /
sizeof(struct ospf_lsa_header);
for (i = 0; i < j; i++)
{ {
ntohlsah(plsa + i, &lsa); struct top_hash_entry *en, *req;
u32 dom = ospf_lsa_domain(lsa.type, n->ifa); struct ospf_lsa_header lsa;
if (((he = ospf_hash_find_header(gr, dom, &lsa)) == NULL) || u32 lsa_type, lsa_domain;
(lsa_comp(&lsa, &(he->lsa)) == 1))
lsa_ntoh_hdr(lsas + i, &lsa);
lsa_xxxxtype(lsa.type_raw, ifa, &lsa_type, &lsa_domain);
/* XXXX: Add check for 0-type or flooding_allowed */
en = ospf_hash_find(po->gr, lsa_domain, lsa.id, lsa.rt, lsa_type);
if (!en || (lsa_comp(&lsa, &(en->lsa)) == CMP_NEWER))
{ {
/* Is this condition necessary? */ req = ospf_hash_get(n->lsrqh, lsa_domain, lsa.id, lsa.rt, lsa_type);
if (ospf_hash_find_header(n->lsrqh, dom, &lsa) == NULL)
{ if (ospf_hash_is_new(req))
sn = ospf_hash_get_header(n->lsrqh, dom, &lsa); s_add_tail(&(n->lsrql), SNODE req);
ntohlsah(plsa + i, &(sn->lsa));
s_add_tail(&(n->lsrql), SNODE sn); en->lsa = lsa;
}
} }
} }
} }
@ -280,19 +278,22 @@ ospf_dbdes_receive(struct ospf_packet *pkt, struct ospf_iface *ifa,
struct ospf_neighbor *n) struct ospf_neighbor *n)
{ {
struct proto_ospf *po = ifa->oa->po; struct proto_ospf *po = ifa->oa->po;
u32 rcv_ddseq, rcv_options; u32 rcv_ddseq, rcv_options;
u16 rcv_iface_mtu; u16 rcv_iface_mtu;
u8 rcv_imms; u8 rcv_imms;
unsigned plen;
plen = ntohs(pkt->length);
unsigned int size = ntohs(ps_i->length); if (plen < ospf_dbdes_hdrlen(po))
if (size < sizeof(struct ospf_dbdes_packet))
{ {
log(L_ERR "Bad OSPF DBDES packet from %I - too short (%u B)", n->ip, size); log(L_ERR "OSPF: Bad DBDES packet from %I - too short (%u B)", n->ip, plen);
return; return;
} }
OSPF_PACKET(ospf_dbdes_dump, pkt, "DBDES packet received from %I via %s", n->ip, ifa->iface->name);
ospf_neigh_sm(n, INM_HELLOREC);
if (ospf_is_v2(po)) if (ospf_is_v2(po))
{ {
struct ospf_dbdes2_packet *ps = (void *) pkt; struct ospf_dbdes2_packet *ps = (void *) pkt;
@ -310,10 +311,6 @@ ospf_dbdes_receive(struct ospf_packet *pkt, struct ospf_iface *ifa,
rcv_ddseq = ntohl(ps->ddseq); rcv_ddseq = ntohl(ps->ddseq);
} }
OSPF_PACKET(ospf_dbdes_dump, ps, "DBDES packet received from %I via %s", n->ip, ifa->iface->name);
ospf_neigh_sm(n, INM_HELLOREC);
switch (n->state) switch (n->state)
{ {
case NEIGHBOR_DOWN: case NEIGHBOR_DOWN:
@ -331,12 +328,12 @@ ospf_dbdes_receive(struct ospf_packet *pkt, struct ospf_iface *ifa,
(rcv_iface_mtu != 0) && (rcv_iface_mtu != 0) &&
(ifa->iface->mtu != 0) && (ifa->iface->mtu != 0) &&
(ifa->type != OSPF_IT_VLINK)) (ifa->type != OSPF_IT_VLINK))
log(L_WARN "OSPF: MTU mismatch with neighbour %I on interface %s (remote %d, local %d)", log(L_WARN "OSPF: MTU mismatch with neighbor %I on interface %s (remote %d, local %d)",
n->ip, ifa->iface->name, rcv_iface_mtu, ifa->iface->mtu); n->ip, ifa->iface->name, rcv_iface_mtu, ifa->iface->mtu);
if ((rcv_imms == DBDES_IMMS) && if ((rcv_imms == DBDES_IMMS) &&
(n->rid > po->router_id) && (n->rid > po->router_id) &&
(size == sizeof(struct ospf_dbdes_packet))) (plen == ospf_dbdes_hdrlen(po)))
{ {
/* I'm slave! */ /* I'm slave! */
n->dds = rcv_ddseq; n->dds = rcv_ddseq;
@ -374,7 +371,7 @@ ospf_dbdes_receive(struct ospf_packet *pkt, struct ospf_iface *ifa,
(rcv_ddseq == n->ddr)) (rcv_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);
if (!(n->myimms & DBDES_MS)) if (!(n->myimms & DBDES_MS))
{ {
/* Slave should retransmit dbdes packet */ /* Slave should retransmit dbdes packet */
@ -417,7 +414,7 @@ ospf_dbdes_receive(struct ospf_packet *pkt, struct ospf_iface *ifa,
} }
n->dds++; n->dds++;
DBG("Incrementing dds\n"); DBG("Incrementing dds\n");
ospf_dbdes_reqladd(ps, n); ospf_dbdes_process(n, pkt, plen);
if (!(n->myimms & DBDES_M) && if (!(n->myimms & DBDES_M) &&
!(rcv_imms & DBDES_M)) !(rcv_imms & DBDES_M))
{ {
@ -439,7 +436,7 @@ ospf_dbdes_receive(struct ospf_packet *pkt, struct ospf_iface *ifa,
} }
n->ddr = rcv_ddseq; n->ddr = rcv_ddseq;
n->dds = rcv_ddseq; n->dds = rcv_ddseq;
ospf_dbdes_reqladd(ps, n); ospf_dbdes_process(n, pkt, plen);
ospf_dbdes_send(n, 1); ospf_dbdes_send(n, 1);
} }
break; break;
@ -451,7 +448,7 @@ ospf_dbdes_receive(struct ospf_packet *pkt, struct ospf_iface *ifa,
(rcv_ddseq == n->ddr)) (rcv_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);
if (!(n->myimms & DBDES_MS)) if (!(n->myimms & DBDES_MS))
{ {
/* Slave should retransmit dbdes packet */ /* Slave should retransmit dbdes packet */

View File

@ -48,7 +48,6 @@ ospf_hello_receive(struct ospf_packet *pkt, struct ospf_iface *ifa,
struct ospf_neighbor *n, ip_addr faddr) struct ospf_neighbor *n, ip_addr faddr)
{ {
struct proto_ospf *po = ifa->oa->po; struct proto_ospf *po = ifa->oa->po;
struct proto *p = &po->proto;
char *beg = "OSPF: Bad HELLO packet from "; char *beg = "OSPF: Bad HELLO packet from ";
unsigned int size, i, two_way; unsigned int size, i, two_way;

View File

@ -72,6 +72,8 @@ find_nbma_node_in(list *nnl, ip_addr ip)
static int static int
ospf_sk_open(struct ospf_iface *ifa) ospf_sk_open(struct ospf_iface *ifa)
{ {
struct proto_ospf *po = ifa->oa->po;
sock *sk = sk_new(ifa->pool); sock *sk = sk_new(ifa->pool);
sk->type = SK_IP; sk->type = SK_IP;
sk->dport = OSPF_PROTO; sk->dport = OSPF_PROTO;
@ -90,11 +92,10 @@ ospf_sk_open(struct ospf_iface *ifa)
if (sk_open(sk) != 0) if (sk_open(sk) != 0)
goto err; goto err;
#ifdef OSPFv3 /* 12 is an offset of the checksum in an OSPFv3 packet */
/* 12 is an offset of the checksum in an OSPF packet */ if (ospf_is_v3(po))
if (sk_set_ipv6_checksum(sk, 12) < 0) if (sk_set_ipv6_checksum(sk, 12) < 0)
goto err; goto err;
#endif
/* /*
* For OSPFv2: When sending a packet, it is important to have a * For OSPFv2: When sending a packet, it is important to have a
@ -123,14 +124,16 @@ ospf_sk_open(struct ospf_iface *ifa)
if (ifa->cf->real_bcast) if (ifa->cf->real_bcast)
{ {
ifa->all_routers = ifa->addr->brd; ifa->all_routers = ifa->addr->brd;
ifa->des_routers = IPA_NONE;
if (sk_set_broadcast(sk, 1) < 0) if (sk_set_broadcast(sk, 1) < 0)
goto err; goto err;
} }
else else
{ {
ifa->all_routers = AllSPFRouters; ifa->all_routers = ospf_is_v2(po) ? IP4_OSPF_ALL_ROUTERS : IP6_OSPF_ALL_ROUTERS;
sk->ttl = 1; /* Hack, this will affect just multicast packets */ ifa->des_routers = ospf_is_v2(po) ? IP4_OSPF_DES_ROUTERS : IP6_OSPF_DES_ROUTERS;
sk->ttl = 1; /* Hack, this will affect just the multicast packets */
if (sk_setup_multicast(sk) < 0) if (sk_setup_multicast(sk) < 0)
goto err; goto err;
@ -155,7 +158,7 @@ ospf_sk_join_dr(struct ospf_iface *ifa)
if (ifa->sk_dr) if (ifa->sk_dr)
return; return;
sk_join_group(ifa->sk, AllDRouters); sk_join_group(ifa->sk, ifa->des_routers);
ifa->sk_dr = 1; ifa->sk_dr = 1;
} }
@ -165,7 +168,7 @@ ospf_sk_leave_dr(struct ospf_iface *ifa)
if (!ifa->sk_dr) if (!ifa->sk_dr)
return; return;
sk_leave_group(ifa->sk, AllDRouters); sk_leave_group(ifa->sk, ifa->des_routers);
ifa->sk_dr = 0; ifa->sk_dr = 0;
} }
@ -178,13 +181,15 @@ ospf_iface_down(struct ospf_iface *ifa)
if (ifa->type != OSPF_IT_VLINK) if (ifa->type != OSPF_IT_VLINK)
{ {
#ifdef OSPFv2 if (ospf_is_v3(ifa->oa->po))
OSPF_TRACE(D_EVENTS, "Removing interface %s (%I/%d) from area %R", OSPF_TRACE(D_EVENTS, "Removing interface %s (IID %d) from area %R",
ifa->iface->name, ifa->addr->prefix, ifa->addr->pxlen, ifa->oa->areaid); ifa->iface->name, ifa->instance_id, ifa->oa->areaid);
#else else if (ifa->addr->flags & IA_PEER)
OSPF_TRACE(D_EVENTS, "Removing interface %s (IID %d) from area %R", OSPF_TRACE(D_EVENTS, "Removing interface %s (peer %I) from area %R",
ifa->iface->name, ifa->instance_id, ifa->oa->areaid); ifa->iface->name, ifa->addr->opposite, ifa->oa->areaid);
#endif else
OSPF_TRACE(D_EVENTS, "Removing interface %s (%I/%d) from area %R",
ifa->iface->name, ifa->addr->prefix, ifa->addr->pxlen, ifa->oa->areaid);
/* First of all kill all the related vlinks */ /* First of all kill all the related vlinks */
WALK_LIST(iff, po->iface_list) WALK_LIST(iff, po->iface_list)
@ -221,10 +226,8 @@ ospf_iface_down(struct ospf_iface *ifa)
ifa->rt_pos_beg = 0; ifa->rt_pos_beg = 0;
ifa->rt_pos_end = 0; ifa->rt_pos_end = 0;
#ifdef OSPFv3
ifa->px_pos_beg = 0; ifa->px_pos_beg = 0;
ifa->px_pos_end = 0; ifa->px_pos_end = 0;
#endif
} }
@ -275,7 +278,7 @@ ospf_iface_chstate(struct ospf_iface *ifa, u8 state)
OSPF_TRACE(D_EVENTS, "Changing state of iface %s from %s to %s", OSPF_TRACE(D_EVENTS, "Changing state of iface %s from %s to %s",
ifa->iface->name, ospf_is[oldstate], ospf_is[state]); ifa->iface->name, ospf_is[oldstate], ospf_is[state]);
if ((ifa->type == OSPF_IT_BCAST) && !ifa->cf->real_bcast && ifa->sk) if ((ifa->type == OSPF_IT_BCAST) && ipa_nonzero(ifa->des_routers) && ifa->sk)
{ {
if ((state == OSPF_IS_BACKUP) || (state == OSPF_IS_DR)) if ((state == OSPF_IS_BACKUP) || (state == OSPF_IS_DR))
ospf_sk_join_dr(ifa); ospf_sk_join_dr(ifa);
@ -499,16 +502,15 @@ ospf_iface_new(struct ospf_area *oa, struct ifa *addr, struct ospf_iface_patt *i
if (ip->type == OSPF_IT_VLINK) if (ip->type == OSPF_IT_VLINK)
OSPF_TRACE(D_EVENTS, "Adding vlink to %R via area %R", ip->vid, ip->voa); OSPF_TRACE(D_EVENTS, "Adding vlink to %R via area %R", ip->vid, ip->voa);
else else if (ospf_is_v3(po))
{
#ifdef OSPFv2
OSPF_TRACE(D_EVENTS, "Adding interface %s (%I/%d) to area %R",
iface->name, addr->prefix, addr->pxlen, oa->areaid);
#else
OSPF_TRACE(D_EVENTS, "Adding interface %s (IID %d) to area %R", OSPF_TRACE(D_EVENTS, "Adding interface %s (IID %d) to area %R",
iface->name, ip->instance_id, oa->areaid); iface->name, ip->instance_id, oa->areaid);
#endif else if (ifa->addr->flags & IA_PEER)
} OSPF_TRACE(D_EVENTS, "Adding interface %s (peer %I) to area %R",
iface->name, addr->opposite, oa->areaid);
else
OSPF_TRACE(D_EVENTS, "Adding interface %s (%I/%d) to area %R",
iface->name, addr->prefix, addr->pxlen, oa->areaid);
pool = rp_new(po->proto.pool, "OSPF Interface"); pool = rp_new(po->proto.pool, "OSPF Interface");
ifa = mb_allocz(pool, sizeof(struct ospf_iface)); ifa = mb_allocz(pool, sizeof(struct ospf_iface));
@ -532,15 +534,9 @@ ospf_iface_new(struct ospf_area *oa, struct ifa *addr, struct ospf_iface_patt *i
ifa->rxbuf = ip->rxbuf; ifa->rxbuf = ip->rxbuf;
ifa->check_link = ip->check_link; ifa->check_link = ip->check_link;
ifa->ecmp_weight = ip->ecmp_weight; ifa->ecmp_weight = ip->ecmp_weight;
#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; ifa->instance_id = ip->instance_id;
#endif
ifa->type = ospf_iface_classify(ip->type, addr); ifa->type = ospf_iface_classify(ip->type, addr);
@ -548,13 +544,11 @@ ospf_iface_new(struct ospf_area *oa, struct ifa *addr, struct ospf_iface_patt *i
int old_type = ifa->type; int old_type = ifa->type;
u32 if_multi_flag = ip->real_bcast ? IF_BROADCAST : IF_MULTICAST; u32 if_multi_flag = ip->real_bcast ? IF_BROADCAST : IF_MULTICAST;
#ifdef OSPFv2 if (ospf_is_v2(po) && (ifa->type == OSPF_IT_BCAST) && (addr->flags & IA_PEER))
if ((ifa->type == OSPF_IT_BCAST) && (addr->flags & IA_PEER))
ifa->type = OSPF_IT_PTP; ifa->type = OSPF_IT_PTP;
if ((ifa->type == OSPF_IT_NBMA) && (addr->flags & IA_PEER)) if (ospf_is_v2(po) && (ifa->type == OSPF_IT_NBMA) && (addr->flags & IA_PEER))
ifa->type = OSPF_IT_PTMP; ifa->type = OSPF_IT_PTMP;
#endif
if ((ifa->type == OSPF_IT_BCAST) && !(iface->flags & if_multi_flag)) if ((ifa->type == OSPF_IT_BCAST) && !(iface->flags & if_multi_flag))
ifa->type = OSPF_IT_NBMA; ifa->type = OSPF_IT_NBMA;
@ -564,7 +558,7 @@ ospf_iface_new(struct ospf_area *oa, struct ifa *addr, struct ospf_iface_patt *i
if (ifa->type != old_type) if (ifa->type != old_type)
log(L_WARN "%s: Cannot use interface %s as %s, forcing %s", log(L_WARN "%s: Cannot use interface %s as %s, forcing %s",
p->name, iface->name, ospf_it[old_type], ospf_it[ifa->type]); po->proto.name, iface->name, ospf_it[old_type], ospf_it[ifa->type]);
init_list(&ifa->neigh_list); init_list(&ifa->neigh_list);
@ -595,11 +589,7 @@ ospf_iface_new(struct ospf_area *oa, struct ifa *addr, struct ospf_iface_patt *i
*/ */
lock = olock_new(pool); lock = olock_new(pool);
#ifdef OSPFv2 lock->addr = ospf_is_v2(po) ? ifa->addr->prefix : _MI6(0,0,0,ifa->instance_id);
lock->addr = ifa->addr->prefix;
#else /* OSPFv3 */
lock->addr = _MI(0,0,0,ifa->instance_id);
#endif
lock->type = OBJLOCK_IP; lock->type = OBJLOCK_IP;
lock->port = OSPF_PROTO; lock->port = OSPF_PROTO;
lock->iface = iface; lock->iface = iface;
@ -702,7 +692,6 @@ ospf_iface_reconfigure(struct ospf_iface *ifa, struct ospf_iface_patt *new)
ifa->inftransdelay = new->inftransdelay; ifa->inftransdelay = new->inftransdelay;
} }
#ifdef OSPFv2
/* AUTHENTICATION */ /* AUTHENTICATION */
if (ifa->autype != new->autype) if (ifa->autype != new->autype)
{ {
@ -712,7 +701,6 @@ ospf_iface_reconfigure(struct ospf_iface *ifa, struct ospf_iface_patt *new)
/* Update passwords */ /* Update passwords */
ifa->passwords = new->passwords; ifa->passwords = new->passwords;
#endif
/* Remaining options are just for proper interfaces */ /* Remaining options are just for proper interfaces */
if (ifa->type == OSPF_IT_VLINK) if (ifa->type == OSPF_IT_VLINK)
@ -1133,14 +1121,13 @@ ospf_iface_info(struct ospf_iface *ifa)
} }
else else
{ {
#ifdef OSPFv2 if (ospf_is_v3(ifa->oa->po))
if (ifa->addr->flags & IA_PEER) cli_msg(-1015, "Interface %s (IID %d)", ifa->iface->name, ifa->instance_id);
else if (ifa->addr->flags & IA_PEER)
cli_msg(-1015, "Interface %s (peer %I)", ifa->iface->name, ifa->addr->opposite); cli_msg(-1015, "Interface %s (peer %I)", ifa->iface->name, ifa->addr->opposite);
else else
cli_msg(-1015, "Interface %s (%I/%d)", ifa->iface->name, ifa->addr->prefix, ifa->addr->pxlen); cli_msg(-1015, "Interface %s (%I/%d)", ifa->iface->name, ifa->addr->prefix, ifa->addr->pxlen);
#else /* OSPFv3 */
cli_msg(-1015, "Interface %s (IID %d)", ifa->iface->name, ifa->instance_id);
#endif
cli_msg(-1015, "\tType: %s%s", ospf_it[ifa->type], more); cli_msg(-1015, "\tType: %s%s", ospf_it[ifa->type], more);
cli_msg(-1015, "\tArea: %R (%u)", ifa->oa->areaid, ifa->oa->areaid); cli_msg(-1015, "\tArea: %R (%u)", ifa->oa->areaid, ifa->oa->areaid);
} }

View File

@ -96,10 +96,8 @@ ospf_lsack_send_one(struct ospf_neighbor *n, int queue)
{ {
if ((ifa->state == OSPF_IS_DR) || (ifa->state == OSPF_IS_BACKUP)) if ((ifa->state == OSPF_IS_DR) || (ifa->state == OSPF_IS_BACKUP))
ospf_send_to_all(ifa); ospf_send_to_all(ifa);
else if (ifa->cf->real_bcast)
ospf_send_to_bdr(ifa);
else else
ospf_send_to(ifa, AllDRouters); ospf_send_to_des(ifa);
} }
else else
ospf_send_to_agt(ifa, NEIGHBOR_EXCHANGE); ospf_send_to_agt(ifa, NEIGHBOR_EXCHANGE);
@ -127,6 +125,7 @@ ospf_lsack_receive(struct ospf_packet *pkt, struct ospf_iface *ifa,
struct ospf_lsa_header lsa, *lsas; struct ospf_lsa_header lsa, *lsas;
struct top_hash_entry *en; struct top_hash_entry *en;
unsigned i, lsa_count; unsigned i, lsa_count;
u32 lsa_dom, lsa_type;
/* No need to check length, lsack has only basic header */ /* No need to check length, lsack has only basic header */
@ -142,9 +141,11 @@ ospf_lsack_receive(struct ospf_packet *pkt, struct ospf_iface *ifa,
ospf_lsack_body(po, pkt, ntohs(pkt->length), &lsas, &lsa_count); ospf_lsack_body(po, pkt, ntohs(pkt->length), &lsas, &lsa_count);
for (i = 0; i < lsa_count; i++) for (i = 0; i < lsa_count; i++)
{ {
ntohlsah(&lsas[i], &lsa); lsa_ntoh_hdr(&lsas[i], &lsa);
u32 dom = ospf_lsa_domain(lsa.type, n->ifa); lsa_xxxxtype(lsa.type_raw, n->ifa, &lsa_type, &lsa_dom);
if ((en = ospf_hash_find_header(n->lsrth, dom, &lsa)) == NULL)
en = ospf_hash_find(n->lsrth, lsa_dom, lsa.id, lsa.rt, lsa_type);
if (!en)
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 */
@ -154,7 +155,7 @@ ospf_lsack_receive(struct ospf_packet *pkt, struct ospf_iface *ifa,
OSPF_TRACE(D_PACKETS, "Strange LSACK from %I", n->ip); OSPF_TRACE(D_PACKETS, "Strange LSACK from %I", n->ip);
OSPF_TRACE(D_PACKETS, "Type: %04x, Id: %R, Rt: %R", OSPF_TRACE(D_PACKETS, "Type: %04x, Id: %R, Rt: %R",
lsa.type, lsa.id, lsa.rt); lsa_type, lsa.id, lsa.rt);
OSPF_TRACE(D_PACKETS, "I have: Age: %4u, Seq: %08x, Sum: %04x", OSPF_TRACE(D_PACKETS, "I have: Age: %4u, Seq: %08x, Sum: %04x",
en->lsa.age, en->lsa.sn, en->lsa.checksum); en->lsa.age, en->lsa.sn, en->lsa.checksum);
OSPF_TRACE(D_PACKETS, "He has: Age: %4u, Seq: %08x, Sum: %04x", OSPF_TRACE(D_PACKETS, "He has: Age: %4u, Seq: %08x, Sum: %04x",
@ -162,8 +163,8 @@ ospf_lsack_receive(struct ospf_packet *pkt, struct ospf_iface *ifa,
continue; continue;
} }
DBG("Deleting LS Id: %R RT: %R Type: %u from LS Retl for neighbor %R\n", DBG("Deleting LSA (Type: %04x Id: %R Rt: %R) from lsrtl for neighbor %R\n",
lsa.id, lsa.rt, lsa.type, n->rid); lsa_type, lsa.id, lsa.rt, n->rid);
s_rem_node(SNODE en); s_rem_node(SNODE en);
ospf_hash_delete(n->lsrth, en); ospf_hash_delete(n->lsrth, en);
} }

View File

@ -89,10 +89,10 @@ ospf_age(struct proto_ospf *po)
#ifndef CPU_BIG_ENDIAN #ifndef CPU_BIG_ENDIAN
void void
htonlsah(struct ospf_lsa_header *h, struct ospf_lsa_header *n) lsa_hton_hdr(struct ospf_lsa_header *h, struct ospf_lsa_header *n)
{ {
n->age = htons(h->age); n->age = htons(h->age);
n->type_raw = htont(h->type_raw); n->type_raw = htons(h->type_raw);
n->id = htonl(h->id); n->id = htonl(h->id);
n->rt = htonl(h->rt); n->rt = htonl(h->rt);
n->sn = htonl(h->sn); n->sn = htonl(h->sn);
@ -101,10 +101,10 @@ htonlsah(struct ospf_lsa_header *h, struct ospf_lsa_header *n)
} }
void void
ntohlsah(struct ospf_lsa_header *n, struct ospf_lsa_header *h) lsa_ntoh_hdr(struct ospf_lsa_header *n, struct ospf_lsa_header *h)
{ {
h->age = ntohs(n->age); h->age = ntohs(n->age);
h->type_raw = ntoht(n->type_raw); h->type_raw = ntohs(n->type_raw);
h->id = ntohl(n->id); h->id = ntohl(n->id);
h->rt = ntohl(n->rt); h->rt = ntohl(n->rt);
h->sn = ntohl(n->sn); h->sn = ntohl(n->sn);
@ -113,7 +113,7 @@ ntohlsah(struct ospf_lsa_header *n, struct ospf_lsa_header *h)
} }
void void
htonlsab(void *h, void *n, u16 len) lsa_hton_body(void *h, void *n, u16 len)
{ {
u32 *hid = h; u32 *hid = h;
u32 *nid = n; u32 *nid = n;
@ -124,7 +124,7 @@ htonlsab(void *h, void *n, u16 len)
} }
void void
ntohlsab(void *n, void *h, u16 len) lsa_ntoh_body(void *n, void *h, u16 len)
{ {
u32 *nid = n; u32 *nid = n;
u32 *hid = h; u32 *hid = h;
@ -135,6 +135,95 @@ ntohlsab(void *n, void *h, u16 len)
} }
#endif /* little endian */ #endif /* little endian */
int
lsa_flooding_allowed(u32 type, u32 domain, struct ospf_iface *ifa)
{
/* 4.5.2 (Case 2) */
switch (LSA_SCOPE(type))
{
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 (!oa_is_ext(ifa->oa))
return 0;
return 1;
default:
log(L_ERR "OSPF: LSA with invalid scope");
return 0;
}
}
static int
unknown_lsa_type(u32 type)
{
switch (type)
{
case LSA_T_RT:
case LSA_T_NET:
case LSA_T_SUM_NET:
case LSA_T_SUM_RT:
case LSA_T_EXT:
case LSA_T_NSSA:
case LSA_T_LINK:
case LSA_T_PREFIX:
return 0;
default:
return 1;
}
}
#define LSA_V2_TMAX 8
static const u16 lsa_v2_types[LSA_V2_TMAX] =
{0, LSA_T_RT, LSA_T_NET, LSA_T_SUM_NET, LSA_T_SUM_RT, LSA_T_EXT, 0, LSA_T_NSSA};
void
lsa_xxxxtype(u32 itype, struct ospf_iface *ifa, u32 *otype, u32 *domain)
{
if (ospf_is_v2(ifa->oa->po))
{
itype = itype & LSA_T_V2_MASK;
itype = (itype < LSA_V2_TMAX) ? lsa_v2_types[itype] : 0;
}
else
{
/* For unkown LSAs without U-bit change scope to LSA_SCOPE_LINK */
if (unknown_lsa_type(itype) && !(itype & LSA_UBIT))
itype = itype & ~LSA_SCOPE_MASK;
}
*otype = itype;
switch (LSA_SCOPE(itype))
{
case LSA_SCOPE_LINK:
*domain = ifa->iface->index;
return;
case LSA_SCOPE_AREA:
*domain = ifa->oa->areaid;
return;
case LSA_SCOPE_AS:
default:
*domain = 0;
return;
}
}
/* /*
void void
buf_dump(const char *hdr, const byte *buf, int blen) buf_dump(const char *hdr, const byte *buf, int blen)
@ -179,8 +268,8 @@ lsasum_calculate(struct ospf_lsa_header *h, void *body)
u16 length = h->length; u16 length = h->length;
// log(L_WARN "Checksum %R %R %d start (len %d)", h->id, h->rt, h->type, length); // log(L_WARN "Checksum %R %R %d start (len %d)", h->id, h->rt, h->type, length);
htonlsah(h, h); lsa_hton_hdr(h, h);
htonlsab1(body, length - sizeof(struct ospf_lsa_header)); lsa_hton_body1(body, length - sizeof(struct ospf_lsa_header));
/* /*
char buf[1024]; char buf[1024];
@ -193,8 +282,8 @@ lsasum_calculate(struct ospf_lsa_header *h, void *body)
// log(L_WARN "Checksum result %4x", h->checksum); // log(L_WARN "Checksum result %4x", h->checksum);
ntohlsah(h, h); lsa_ntoh_hdr(h, h);
ntohlsab1(body, length - sizeof(struct ospf_lsa_header)); lsa_ntoh_body1(body, length - sizeof(struct ospf_lsa_header));
} }
/* /*
@ -427,30 +516,60 @@ lsa_parse_ext(struct top_hash_entry *en, int ospf2, struct ospf_lsa_ext_local *r
#define HDRLEN sizeof(struct ospf_lsa_header) #define HDRLEN sizeof(struct ospf_lsa_header)
static int static int
lsa_validate_rt(struct ospf_lsa_header *lsa, struct ospf_lsa_rt *body) lsa_validate_rt2(struct ospf_lsa_header *lsa, struct ospf_lsa_rt *body)
{ {
unsigned int i, max;
if (lsa->length < (HDRLEN + sizeof(struct ospf_lsa_rt))) if (lsa->length < (HDRLEN + sizeof(struct ospf_lsa_rt)))
return 0; return 0;
struct ospf_lsa_rt_link *rtl = (struct ospf_lsa_rt_link *) (body + 1); unsigned i = 0;
max = lsa_rt_count(lsa); void *buf = body;
void *bufend = buf + lsa->length - HDRLEN;
buf += sizeof(struct ospf_lsa_rt);
#ifdef OSPFv2 while (buf < bufend)
if (body->links != max)
return 0;
#endif
for (i = 0; i < max; i++)
{ {
u8 type = rtl[i].type; struct ospf_lsa_rt2_link *l = buf;
if (!((type == LSART_PTP) || buf += sizeof(struct ospf_lsa_rt2_link) + l->no_tos * sizeof(struct ospf_lsa_rt2_tos);
(type == LSART_NET) || i++;
#ifdef OSPFv2
(type == LSART_STUB) || if (buf > bufend)
#endif return 0;
(type == LSART_VLNK)))
if (!((l->type == LSART_PTP) ||
(l->type == LSART_NET) ||
(l->type == LSART_STUB) ||
(l->type == LSART_VLNK)))
return 0;
}
if ((body->options & LSA_RT2_LINKS) != i)
return 0;
return 1;
}
static int
lsa_validate_rt3(struct ospf_lsa_header *lsa, struct ospf_lsa_rt *body)
{
if (lsa->length < (HDRLEN + sizeof(struct ospf_lsa_rt)))
return 0;
void *buf = body;
void *bufend = buf + lsa->length - HDRLEN;
buf += sizeof(struct ospf_lsa_rt);
while (buf < bufend)
{
struct ospf_lsa_rt3_link *l = buf;
buf += sizeof(struct ospf_lsa_rt3_link);
if (buf > bufend)
return 0;
if (!((l->type == LSART_PTP) ||
(l->type == LSART_NET) ||
(l->type == LSART_VLNK)))
return 0; return 0;
} }
return 1; return 1;
@ -465,37 +584,18 @@ lsa_validate_net(struct ospf_lsa_header *lsa, struct ospf_lsa_net *body UNUSED)
return 1; return 1;
} }
#ifdef OSPFv2
static int static int
lsa_validate_sum(struct ospf_lsa_header *lsa, struct ospf_lsa_sum *body) lsa_validate_sum2(struct ospf_lsa_header *lsa, struct ospf_lsa_sum2 *body)
{ {
if (lsa->length < (HDRLEN + sizeof(struct ospf_lsa_sum))) if (lsa->length < (HDRLEN + sizeof(struct ospf_lsa_sum2)))
return 0; return 0;
/* First field should have TOS = 0, we ignore other TOS fields */ /* First field should have TOS = 0, we ignore other TOS fields */
if ((body->metric & LSA_SUM_TOS) != 0) if ((body->metric & LSA_SUM2_TOS) != 0)
return 0; return 0;
return 1; return 1;
} }
#define lsa_validate_sum_net(A,B) lsa_validate_sum(A,B)
#define lsa_validate_sum_rt(A,B) lsa_validate_sum(A,B)
static int
lsa_validate_ext(struct ospf_lsa_header *lsa, struct ospf_lsa_ext *body)
{
if (lsa->length < (HDRLEN + sizeof(struct ospf_lsa_ext)))
return 0;
/* First field should have TOS = 0, we ignore other TOS fields */
if ((body->metric & LSA_EXT_TOS) != 0)
return 0;
return 1;
}
#else /* OSPFv3 */
static inline int static inline int
pxlen(u32 *buf) pxlen(u32 *buf)
@ -504,7 +604,7 @@ pxlen(u32 *buf)
} }
static int static int
lsa_validate_sum_net(struct ospf_lsa_header *lsa, struct ospf_lsa_sum3_net *body) lsa_validate_sum3_net(struct ospf_lsa_header *lsa, struct ospf_lsa_sum3_net *body)
{ {
if (lsa->length < (HDRLEN + sizeof(struct ospf_lsa_sum3_net) + 4)) if (lsa->length < (HDRLEN + sizeof(struct ospf_lsa_sum3_net) + 4))
return 0; return 0;
@ -520,9 +620,8 @@ lsa_validate_sum_net(struct ospf_lsa_header *lsa, struct ospf_lsa_sum3_net *body
return 1; return 1;
} }
static int static int
lsa_validate_sum_rt(struct ospf_lsa_header *lsa, struct ospf_lsa_sum3_rt *body) lsa_validate_sum3_rt(struct ospf_lsa_header *lsa, struct ospf_lsa_sum3_rt *body)
{ {
if (lsa->length != (HDRLEN + sizeof(struct ospf_lsa_sum3_rt))) if (lsa->length != (HDRLEN + sizeof(struct ospf_lsa_sum3_rt)))
return 0; return 0;
@ -531,7 +630,20 @@ lsa_validate_sum_rt(struct ospf_lsa_header *lsa, struct ospf_lsa_sum3_rt *body)
} }
static int static int
lsa_validate_ext(struct ospf_lsa_header *lsa, struct ospf_lsa_ext3 *body) lsa_validate_ext2(struct ospf_lsa_header *lsa, struct ospf_lsa_ext2 *body)
{
if (lsa->length < (HDRLEN + sizeof(struct ospf_lsa_ext2)))
return 0;
/* First field should have TOS = 0, we ignore other TOS fields */
if ((body->metric & LSA_EXT2_TOS) != 0)
return 0;
return 1;
}
static int
lsa_validate_ext3(struct ospf_lsa_header *lsa, struct ospf_lsa_ext3 *body)
{ {
if (lsa->length < (HDRLEN + sizeof(struct ospf_lsa_ext3) + 4)) if (lsa->length < (HDRLEN + sizeof(struct ospf_lsa_ext3) + 4))
return 0; return 0;
@ -596,8 +708,6 @@ lsa_validate_prefix(struct ospf_lsa_header *lsa, struct ospf_lsa_prefix *body)
return lsa_validate_pxlist(lsa, body->pxcount, sizeof(struct ospf_lsa_prefix), (u8 *) body); return lsa_validate_pxlist(lsa, body->pxcount, sizeof(struct ospf_lsa_prefix), (u8 *) body);
} }
#endif
/** /**
* lsa_validate - check whether given LSA is valid * lsa_validate - check whether given LSA is valid
@ -609,31 +719,50 @@ lsa_validate_prefix(struct ospf_lsa_header *lsa, struct ospf_lsa_prefix *body)
*/ */
int int
lsa_validate(struct ospf_lsa_header *lsa, void *body) lsa_validate(struct ospf_lsa_header *lsa, u32 lsa_type, int ospf2, void *body)
{ {
switch (lsa->type) if (ospf2)
{
switch (lsa_type)
{ {
case LSA_T_RT: case LSA_T_RT:
return lsa_validate_rt(lsa, body); return lsa_validate_rt2(lsa, body);
case LSA_T_NET: case LSA_T_NET:
return lsa_validate_net(lsa, body); return lsa_validate_net(lsa, body);
case LSA_T_SUM_NET: case LSA_T_SUM_NET:
return lsa_validate_sum_net(lsa, body); return lsa_validate_sum2(lsa, body);
case LSA_T_SUM_RT: case LSA_T_SUM_RT:
return lsa_validate_sum_rt(lsa, body); return lsa_validate_sum2(lsa, body);
case LSA_T_EXT: case LSA_T_EXT:
case LSA_T_NSSA: case LSA_T_NSSA:
return lsa_validate_ext(lsa, body); return lsa_validate_ext2(lsa, body);
default:
return 0; /* Should not happen, unknown LSAs are already rejected */
}
}
else
{
switch (lsa_type)
{
case LSA_T_RT:
return lsa_validate_rt3(lsa, body);
case LSA_T_NET:
return lsa_validate_net(lsa, body);
case LSA_T_SUM_NET:
return lsa_validate_sum3_net(lsa, body);
case LSA_T_SUM_RT:
return lsa_validate_sum3_rt(lsa, body);
case LSA_T_EXT:
case LSA_T_NSSA:
return lsa_validate_ext3(lsa, body);
case LSA_T_LINK: case LSA_T_LINK:
return lsa_validate_link(lsa, body); return lsa_validate_link(lsa, body);
case LSA_T_PREFIX: case LSA_T_PREFIX:
return lsa_validate_prefix(lsa, body); return lsa_validate_prefix(lsa, body);
default: default:
/* In OSPFv3, unknown LSAs are OK, return 1; /* Unknown LSAs are OK in OSPFv3 */
In OSPFv2, unknown LSAs are already rejected
*/
return 1;
} }
}
} }
/** /**

View File

@ -11,19 +11,19 @@
#define _BIRD_OSPF_LSALIB_H_ #define _BIRD_OSPF_LSALIB_H_
#ifdef CPU_BIG_ENDIAN #ifdef CPU_BIG_ENDIAN
static inline void htonlsah(struct ospf_lsa_header *h, struct ospf_lsa_header *n) { *n = *h; }; static inline void lsa_hton_hdr(struct ospf_lsa_header *h, struct ospf_lsa_header *n) { *n = *h; };
static inline void ntohlsah(struct ospf_lsa_header *n, struct ospf_lsa_header *h) { *h = *n; }; static inline void lsa_ntoh_hdr(struct ospf_lsa_header *n, struct ospf_lsa_header *h) { *h = *n; };
static inline void htonlsab(void *h, void *n, u16 len) { ASSERT(h != n); memcpy(n, h, len); }; static inline void lsa_hton_body(void *h, void *n, u16 len) { ASSERT(h != n); memcpy(n, h, len); };
static inline void ntohlsab(void *n, void *h, u16 len) { ASSERT(n != h); memcpy(h, n, len); }; static inline void lsa_ntoh_body(void *n, void *h, u16 len) { ASSERT(n != h); memcpy(h, n, len); };
static inline void htonlsab1(void *h, u16 len) { }; static inline void lsa_hton_body1(void *h, u16 len) { };
static inline void ntohlsab1(void *n, u16 len) { }; static inline void lsa_ntoh_body1(void *n, u16 len) { };
#else #else
void htonlsah(struct ospf_lsa_header *h, struct ospf_lsa_header *n); void lsa_hton_hdr(struct ospf_lsa_header *h, struct ospf_lsa_header *n);
void ntohlsah(struct ospf_lsa_header *n, struct ospf_lsa_header *h); void lsa_ntoh_hdr(struct ospf_lsa_header *n, struct ospf_lsa_header *h);
void htonlsab(void *h, void *n, u16 len); void lsa_hton_body(void *h, void *n, u16 len);
void ntohlsab(void *n, void *h, u16 len); void lsa_ntoh_body(void *n, void *h, u16 len);
static inline void htonlsab1(void *h, u16 len) { htonlsab(h, h, len); }; static inline void lsa_hton_body1(void *h, u16 len) { lsa_hton_body(h, h, len); };
static inline void ntohlsab1(void *n, u16 len) { ntohlsab(n, n, len); }; static inline void lsa_ntoh_body1(void *n, u16 len) { lsa_ntoh_body(n, n, len); };
#endif #endif
struct ospf_lsa_rt_walk { struct ospf_lsa_rt_walk {
@ -34,6 +34,11 @@ struct ospf_lsa_rt_walk {
u32 id, data, lif, nif; u32 id, data, lif, nif;
}; };
static inline u32 lsa_get_type(struct proto_ospf *po, u32 type_raw)
{ return ospf_is_v2(po) ? (type_raw & LSA_T_V2_MASK) : type_raw; }
int lsa_flooding_allowed(u32 type, u32 domain, struct ospf_iface *ifa);
void lsa_xxxxtype(u32 itype, struct ospf_iface *ifa, u32 *otype, u32 *domain);
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
@ -45,7 +50,7 @@ int lsa_walk_rt(struct ospf_lsa_rt_walk *rt);
void lsa_parse_sum_net(struct top_hash_entry *en, int ospf2, ip_addr *ip, int *pxlen, u8 *pxopts, u32 *metric); void lsa_parse_sum_net(struct top_hash_entry *en, int ospf2, ip_addr *ip, int *pxlen, u8 *pxopts, u32 *metric);
void lsa_parse_sum_rt(struct top_hash_entry *en, int ospf2, u32 *drid, u32 *metric, u32 *options); void lsa_parse_sum_rt(struct top_hash_entry *en, int ospf2, u32 *drid, u32 *metric, u32 *options);
void lsa_parse_ext(struct top_hash_entry *en, int ospf2, struct ospf_lsa_ext_local *rt); void lsa_parse_ext(struct top_hash_entry *en, int ospf2, struct ospf_lsa_ext_local *rt);
int lsa_validate(struct ospf_lsa_header *lsa, void *body); int lsa_validate(struct ospf_lsa_header *lsa, u32 lsa_type, int ospf2, void *body);
struct top_hash_entry * lsa_install_new(struct proto_ospf *po, struct ospf_lsa_header *lsa, u32 domain, void *body); struct top_hash_entry * lsa_install_new(struct proto_ospf *po, struct ospf_lsa_header *lsa, u32 domain, void *body);
void ospf_age(struct proto_ospf *po); 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

@ -19,7 +19,7 @@ struct ospf_lsreq_packet
}; };
*/ */
static void static inline void
ospf_lsreq_body(struct proto_ospf *po, struct ospf_packet *pkt, unsigned plen, ospf_lsreq_body(struct proto_ospf *po, struct ospf_packet *pkt, unsigned plen,
struct ospf_lsreq_header **body, unsigned *count) struct ospf_lsreq_header **body, unsigned *count)
{ {
@ -71,9 +71,10 @@ ospf_lsreq_send(struct ospf_neighbor *n)
{ {
en = (struct top_hash_entry *) sn; en = (struct top_hash_entry *) sn;
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",
i, en->lsa.type, en->lsa.id, en->lsa.rt, en->lsa.sn, en->lsa.age); i, en->lsa_type, en->lsa.id, en->lsa.rt, en->lsa.sn, en->lsa.age);
lsrs[i].type = htonl(en->lsa.type); u32 rtype = lsa_get_type(po, en->lsa.type_raw);
lsrs[i].type = htonl(rtype);
lsrs[i].rt = htonl(en->lsa.rt); lsrs[i].rt = htonl(en->lsa.rt);
lsrs[i].id = htonl(en->lsa.id); lsrs[i].id = htonl(en->lsa.id);
@ -97,7 +98,9 @@ ospf_lsreq_receive(struct ospf_packet *pkt, struct ospf_iface *ifa,
struct proto_ospf *po = ifa->oa->po; struct proto_ospf *po = ifa->oa->po;
struct ospf_lsreq_header *lsrs; struct ospf_lsreq_header *lsrs;
unsigned i, lsr_count; unsigned i, lsr_count;
list uplist;
struct ospf_lsreq_item *lsr_head, *lsr;
struct ospf_lsreq_item **lsr_pos = &lsr_head;
slab *upslab; slab *upslab;
@ -111,35 +114,39 @@ ospf_lsreq_receive(struct ospf_packet *pkt, struct ospf_iface *ifa,
ospf_neigh_sm(n, INM_HELLOREC); /* Not in RFC */ ospf_neigh_sm(n, INM_HELLOREC); /* Not in RFC */
init_list(&uplist); upslab = sl_new(n->pool, sizeof(struct ospf_lsreq_item));
upslab = sl_new(n->pool, sizeof(struct l_lsr_head));
ospf_lsreq_body(po, pkt, ntohs(pkt->length), &lsrs, &lsr_count); ospf_lsreq_body(po, pkt, ntohs(pkt->length), &lsrs, &lsr_count);
for (i = 0; i < lsr_count; i++) for (i = 0; i < lsr_count; i++)
{ {
u32 hid = ntohl(lsrs[i].id); u32 id, rt, type, dom;
u32 hrt = ntohl(lsrs[i].rt);
u32 htype = ntohl(lsrs[i].type);
u32 dom = ospf_lsa_domain(htype, ifa);
// XXXX check
DBG("Processing requested LSA: Type: %u, ID: %R, RT: %R\n", htype, hid, hrt);
if (ospf_hash_find(po->gr, dom, hid, hrt, htype) == NULL) id = ntohl(lsrs[i].id);
rt = ntohl(lsrs[i].rt);
lsa_xxxxtype(ntohl(lsrs[i].type), ifa, &type, &dom);
DBG("Processing requested LSA: Type: %04x, Id: %R, Rt: %R\n", type, id, rt);
if (ospf_hash_find(po->gr, dom, id, rt, type) == NULL)
{ {
log(L_WARN "Received bad LSREQ from %I: Type: %04x, Id: %R, Rt: %R", log(L_WARN "Received bad LSREQ from %I: Type: %04x, Id: %R, Rt: %R",
n->ip, htype, hid, hrt); n->ip, type, id, rt);
ospf_neigh_sm(n, INM_BADLSREQ); ospf_neigh_sm(n, INM_BADLSREQ);
rfree(upslab); rfree(upslab);
return; return;
} }
struct l_lsr_head *llsh = sl_alloc(upslab); lsr = sl_alloc(upslab);
llsh->lsh.id = hid; lsr->domain = dom;
llsh->lsh.rt = hrt; lsr->type = type;
llsh->lsh.type = htype; lsr->id = id;
add_tail(&uplist, NODE llsh); lsr->rt = rt;
}
ospf_lsupd_send_list(n, &uplist); *lsr_pos = lsr;
lsr_pos = &(lsr->next);
}
*lsr_pos = NULL;
ospf_lsupd_send_list(n, lsr_head);
rfree(upslab); rfree(upslab);
} }

View File

@ -9,21 +9,29 @@
#include "ospf.h" #include "ospf.h"
/*
struct ospf_lsupd_packet struct ospf_lsupd_packet
{ {
struct ospf_packet ospf_packet; struct ospf_packet hdr;
u32 lsano; /* Number of LSA's */ // union ospf_auth auth;
u32 lsa_count;
void lsas[];
}; };
*/
/* Beware of unaligned access */ /* Beware of unaligned access */
void ospf_dump_lsahdr(struct proto_ospf *po, struct ospf_lsa_header *lsa_n) void ospf_dump_lsahdr(struct proto_ospf *po, struct ospf_lsa_header *lsa_n)
{ {
struct ospf_lsa_header lsa; struct ospf_lsa_header lsa;
ntohlsah(lsa_n, &lsa); u32 lsa_type;
lsa_ntoh_hdr(lsa_n, &lsa);
lsa_type = lsa_get_type(po, lsa.type_raw);
log(L_TRACE "%s: LSA Type: %04x, Id: %R, Rt: %R, Age: %u, Seq: %08x, Sum: %04x", log(L_TRACE "%s: LSA Type: %04x, Id: %R, Rt: %R, Age: %u, Seq: %08x, Sum: %04x",
po->proto.name, lsa.type, lsa.id, lsa.rt, lsa.age, lsa.sn, lsa.checksum); po->proto.name, lsa_type, lsa.id, lsa.rt, lsa.age, lsa.sn, lsa.checksum);
} }
void ospf_dump_common(struct proto_ospf *po, struct ospf_packet *pkt) void ospf_dump_common(struct proto_ospf *po, struct ospf_packet *pkt)
@ -33,22 +41,38 @@ void ospf_dump_common(struct proto_ospf *po, struct ospf_packet *pkt)
log(L_TRACE "%s: router %R", p->name, ntohl(pkt->routerid)); log(L_TRACE "%s: router %R", p->name, ntohl(pkt->routerid));
} }
static void ospf_dump_lsupd(struct proto_ospf *po, struct ospf_lsupd_packet *pkt) static inline unsigned
ospf_lsupd_hdrlen(struct proto_ospf *po)
{
return ospf_pkt_hdrlen(po) + 4; /* + u32 lsa count field */
}
static inline u32 *
ospf_lsupd_lsa_count(struct ospf_packet *pkt, unsigned hdrlen)
{ return ((void *) pkt) + hdrlen - 4; }
static inline void
ospf_lsupd_body(struct proto_ospf *po, struct ospf_packet *pkt,
unsigned *offset, unsigned *bound, unsigned *lsa_count)
{
unsigned hlen = ospf_lsupd_hdrlen(po);
*offset = hlen;
*bound = ntohs(pkt->length) - sizeof(struct ospf_lsa_header);
*lsa_count = ntohl(*ospf_lsupd_lsa_count(pkt, hlen));
}
static void ospf_lsupd_dump(struct proto_ospf *po, struct ospf_packet *pkt)
{ {
struct proto *p = &po->proto; struct proto *p = &po->proto;
struct ospf_packet *op = &pkt->ospf_packet;
ASSERT(op->type == LSUPD_P); ASSERT(pkt->type == LSUPD_P);
ospf_dump_common(po, op); ospf_dump_common(po, pkt);
/* We know that ntohs(op->length) >= sizeof(struct ospf_lsa_header) */ /* We know that ntohs(pkt->length) >= sizeof(struct ospf_lsa_header) */
u8 *pbuf= (u8 *) pkt; unsigned offset, bound, i, lsa_count, lsalen;
unsigned int offset = sizeof(struct ospf_lsupd_packet); ospf_lsupd_body(po, pkt, &offset, &bound, &lsa_count);
unsigned int bound = ntohs(op->length) - sizeof(struct ospf_lsa_header);
unsigned int i, j, lsalen;
j = ntohl(pkt->lsano); for (i = 0; i < lsa_count; i++)
for (i = 0; i < j; i++)
{ {
if (offset > bound) if (offset > bound)
{ {
@ -56,8 +80,8 @@ static void ospf_dump_lsupd(struct proto_ospf *po, struct ospf_lsupd_packet *pkt
return; return;
} }
struct ospf_lsa_header *lsa = (void *) (pbuf + offset); struct ospf_lsa_header *lsa = ((void *) pkt) + offset;
ospf_dump_lsahdr(p, lsa); ospf_dump_lsahdr(po, lsa);
lsalen = ntohs(lsa->length); lsalen = ntohs(lsa->length);
offset += lsalen; offset += lsalen;
@ -70,77 +94,6 @@ static void ospf_dump_lsupd(struct proto_ospf *po, 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 (!oa_is_ext(ifa->oa))
return 0;
return 1;
}
else
return ifa->oa->areaid == domain;
}
#else /* OSPFv3 */
static int
unknown_lsa_type(struct ospf_lsa_header *lsa)
{
switch (lsa->type)
{
case LSA_T_RT:
case LSA_T_NET:
case LSA_T_SUM_NET:
case LSA_T_SUM_RT:
case LSA_T_EXT:
case LSA_T_NSSA:
case LSA_T_LINK:
case LSA_T_PREFIX:
return 0;
default:
return 1;
}
}
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_lsa_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 (!oa_is_ext(ifa->oa))
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 * @po: OSPF protocol
@ -271,17 +224,16 @@ ospf_lsupd_flood(struct proto_ospf *po,
{ {
u16 len, age; u16 len, age;
struct ospf_lsupd_packet *pk; unsigned hlen;
struct ospf_packet *op; struct ospf_packet *pkt;
struct ospf_lsa_header *lh; struct ospf_lsa_header *lh;
pk = ospf_tx_buffer(ifa); pkt = ospf_tx_buffer(ifa);
op = &pk->ospf_packet; hlen = ospf_lsupd_hdrlen(po);
ospf_pkt_fill_hdr(ifa, pk, LSUPD_P); ospf_pkt_fill_hdr(ifa, pkt, LSUPD_P);
pk->lsano = htonl(1); *ospf_lsupd_lsa_count(pkt, hlen) = htonl(1);
lh = (((void *) pkt) + hlen);
lh = (struct ospf_lsa_header *) (pk + 1);
/* Copy LSA into the packet */ /* Copy LSA into the packet */
if (hn) if (hn)
@ -293,33 +245,30 @@ ospf_lsupd_flood(struct proto_ospf *po,
u8 *help; u8 *help;
struct top_hash_entry *en; struct top_hash_entry *en;
htonlsah(hh, lh); lsa_hton_hdr(hh, lh);
help = (u8 *) (lh + 1); help = (u8 *) (lh + 1);
en = ospf_hash_find_header(po->gr, domain, hh); en = ospf_hash_find_header(po->gr, domain, hh);
htonlsab(en->lsa_body, help, hh->length - sizeof(struct ospf_lsa_header)); lsa_hton_body(en->lsa_body, help, hh->length - sizeof(struct ospf_lsa_header));
} }
len = sizeof(struct ospf_lsupd_packet) + ntohs(lh->length);
age = ntohs(lh->age); age = ntohs(lh->age);
age += ifa->inftransdelay; age += ifa->inftransdelay;
if (age > LSA_MAXAGE) if (age > LSA_MAXAGE)
age = LSA_MAXAGE; age = LSA_MAXAGE;
lh->age = htons(age); lh->age = htons(age);
op->length = htons(len); len = hlen + ntohs(lh->length);
pkt->length = htons(len);
OSPF_PACKET(ospf_dump_lsupd, pk, "LSUPD packet flooded via %s", ifa->iface->name); OSPF_PACKET(ospf_lsupd_dump, pkt, "LSUPD packet flooded via %s", ifa->iface->name);
switch (ifa->type) switch (ifa->type)
{ {
case OSPF_IT_BCAST: case OSPF_IT_BCAST:
if ((ifa->state == OSPF_IS_BACKUP) || (ifa->state == OSPF_IS_DR)) if ((ifa->state == OSPF_IS_BACKUP) || (ifa->state == OSPF_IS_DR))
ospf_send_to_all(ifa); ospf_send_to_all(ifa);
else if (ifa->cf->real_bcast)
ospf_send_to_bdr(ifa);
else else
ospf_send_to(ifa, AllDRouters); ospf_send_to_des(ifa);
break; break;
case OSPF_IT_NBMA: case OSPF_IT_NBMA:
@ -350,99 +299,96 @@ ospf_lsupd_flood(struct proto_ospf *po,
} }
void /* I send all I received in LSREQ */ void /* I send all I received in LSREQ */
ospf_lsupd_send_list(struct ospf_neighbor *n, list * l) ospf_lsupd_send_list(struct ospf_neighbor *n, struct ospf_lsreq_item *lsr)
{ {
struct ospf_area *oa = n->ifa->oa; struct ospf_area *oa = n->ifa->oa;
struct proto_ospf *po = oa->po; struct proto_ospf *po = oa->po;
struct l_lsr_head *lsr;
struct top_hash_entry *en; struct top_hash_entry *en;
struct ospf_lsupd_packet *pkt; struct ospf_packet *pkt;
u32 len, len2, lsano; unsigned hlen, pos, pos2, maxsize, lsano;
char *buf;
pkt = ospf_tx_buffer(n->ifa); pkt = ospf_tx_buffer(n->ifa);
buf = (void *) pkt; hlen = ospf_lsupd_hdrlen(po);
maxsize = ospf_pkt_maxsize(n->ifa);
lsr = HEAD(*l); while (lsr)
while(NODE_NEXT(lsr))
{ {
/* Prepare the packet */ /* Prepare the packet */
ospf_pkt_fill_hdr(n->ifa, pkt, LSUPD_P); ospf_pkt_fill_hdr(n->ifa, pkt, LSUPD_P);
len = sizeof(struct ospf_lsupd_packet); pos = hlen;
lsano = 0; lsano = 0;
/* Fill the packet with LSAs */ /* Fill the packet with LSAs */
while(NODE_NEXT(lsr)) while (lsr)
{ {
u32 domain = ospf_lsa_domain(lsr->lsh.type, n->ifa); en = ospf_hash_find(oa->po->gr, lsr->domain, lsr->id, lsr->rt, lsr->type);
en = ospf_hash_find(oa->po->gr, domain, lsr->lsh.id, lsr->lsh.rt, lsr->lsh.type); if (!en)
if (en == NULL)
{ {
/* Probably flushed LSA, this should not happen */ /* Probably flushed LSA, this should not happen */
log(L_WARN "OSPF: LSA disappeared (Type: %04x, Id: %R, Rt: %R)", log(L_WARN "OSPF: LSA disappeared (Type: %04x, Id: %R, Rt: %R)",
lsr->lsh.type, lsr->lsh.id, lsr->lsh.rt); lsr->type, lsr->id, lsr->rt);
lsr = NODE_NEXT(lsr); lsr = lsr->next;
continue; continue;
} }
len2 = len + en->lsa.length; pos2 = pos + en->lsa.length;
if (len2 > ospf_pkt_maxsize(n->ifa)) if (pos2 > maxsize)
{ {
/* The packet if full, stop adding LSAs and sent it */ /* The packet if full, stop adding LSAs and sent it */
if (lsano > 0) if (lsano > 0)
break; break;
/* LSA is larger than MTU, check buffer size */ /* LSA is larger than MTU, check buffer size */
if (len2 > ospf_pkt_bufsize(n->ifa)) if (pos2 > ospf_pkt_bufsize(n->ifa))
{ {
/* Cannot fit in a tx buffer, skip that */ /* Cannot fit in a tx buffer, skip that */
log(L_WARN "OSPF: LSA too large to send (Type: %04x, Id: %R, Rt: %R)", log(L_WARN "OSPF: LSA too large to send (Type: %04x, Id: %R, Rt: %R)",
lsr->lsh.type, lsr->lsh.id, lsr->lsh.rt); lsr->type, lsr->id, lsr->rt);
lsr = NODE_NEXT(lsr); lsr = lsr->next;
continue; continue;
} }
} }
/* Copy the LSA to the packet */ /* Copy the LSA to the packet */
htonlsah(&(en->lsa), (struct ospf_lsa_header *) (buf + len)); void *lsabuf = ((void *) pkt) + pos;
htonlsab(en->lsa_body, buf + len + sizeof(struct ospf_lsa_header), lsa_hton_hdr(&(en->lsa), (struct ospf_lsa_header *) lsabuf);
en->lsa.length - sizeof(struct ospf_lsa_header)); lsa_hton_body(en->lsa_body, lsabuf + sizeof(struct ospf_lsa_header),
len = len2; en->lsa.length - sizeof(struct ospf_lsa_header));
pos = pos2;
lsano++; lsano++;
lsr = NODE_NEXT(lsr); lsr = lsr->next;
} }
if (lsano == 0) if (lsano == 0)
break; break;
/* Send the packet */ /* Send the packet */
pkt->lsano = htonl(lsano); pkt->length = htons(pos);
pkt->ospf_packet.length = htons(len); *ospf_lsupd_lsa_count(pkt, hlen) = htonl(lsano);
OSPF_PACKET(ospf_dump_lsupd, pkt, "LSUPD packet sent to %I via %s", OSPF_PACKET(ospf_lsupd_dump, pkt, "LSUPD packet sent to %I via %s",
n->ip, n->ifa->iface->name); n->ip, n->ifa->iface->name);
ospf_send_to(n->ifa, n->ip); ospf_send_to(n->ifa, n->ip);
} }
} }
void void
ospf_lsupd_receive(struct ospf_packet *ps_i, struct ospf_iface *ifa, ospf_lsupd_receive(struct ospf_packet *pkt, struct ospf_iface *ifa,
struct ospf_neighbor *n) struct ospf_neighbor *n)
{ {
struct ospf_neighbor *ntmp; struct ospf_neighbor *ntmp;
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, max, sendreq = 1; unsigned sendreq = 1;
unsigned int size = ntohs(ps_i->length); unsigned plen = ntohs(pkt->length);
if (size < (sizeof(struct ospf_lsupd_packet) + sizeof(struct ospf_lsa_header))) if (plen < (ospf_lsupd_hdrlen(po) + sizeof(struct ospf_lsa_header)))
{ {
log(L_ERR "OSPF: Bad LSUPD packet from %I - too short (%u B)", n->ip, size); log(L_ERR "OSPF: Bad LSUPD packet from %I - too short (%u B)", n->ip, plen);
return; return;
} }
struct ospf_lsupd_packet *ps = (void *) ps_i; OSPF_PACKET(ospf_lsupd_dump, pkt, "LSUPD packet received from %I via %s", n->ip, ifa->iface->name);
OSPF_PACKET(ospf_dump_lsupd, ps, "LSUPD packet received from %I via %s", n->ip, ifa->iface->name);
if (n->state < NEIGHBOR_EXCHANGE) if (n->state < NEIGHBOR_EXCHANGE)
{ {
@ -452,30 +398,29 @@ ospf_lsupd_receive(struct ospf_packet *ps_i, struct ospf_iface *ifa,
ospf_neigh_sm(n, INM_HELLOREC); /* Questionable */ ospf_neigh_sm(n, INM_HELLOREC); /* Questionable */
unsigned int offset = sizeof(struct ospf_lsupd_packet); unsigned offset, bound, i, lsa_count;
unsigned int bound = size - sizeof(struct ospf_lsa_header); ospf_lsupd_body(po, pkt, &offset, &bound, &lsa_count);
max = ntohl(ps->lsano); for (i = 0; i < lsa_count; i++)
for (i = 0; i < max; i++)
{ {
struct ospf_lsa_header lsatmp; struct ospf_lsa_header lsatmp;
struct top_hash_entry *lsadb; struct top_hash_entry *lsadb;
if (offset > bound) if (offset > bound)
{ {
log(L_WARN "Received lsupd from %I is too short!", n->ip); log(L_WARN "OSPF: Received LSUPD from %I is too short", n->ip);
ospf_neigh_sm(n, INM_BADLSREQ); ospf_neigh_sm(n, INM_BADLSREQ);
return; return;
} }
struct ospf_lsa_header *lsa = (void *) (((u8 *) ps) + offset); struct ospf_lsa_header *lsa = ((void *) pkt) + offset;
unsigned int lsalen = ntohs(lsa->length); unsigned int lsalen = ntohs(lsa->length);
offset += lsalen; offset += lsalen;
if ((offset > size) || ((lsalen % 4) != 0) || if ((offset > plen) || ((lsalen % 4) != 0) ||
(lsalen <= sizeof(struct ospf_lsa_header))) (lsalen <= sizeof(struct ospf_lsa_header)))
{ {
log(L_WARN "Received LSA from %I with bad length", n->ip); log(L_WARN "OSPF: Received LSA from %I with bad length", n->ip);
ospf_neigh_sm(n, INM_BADLSREQ); ospf_neigh_sm(n, INM_BADLSREQ);
break; break;
} }
@ -484,55 +429,45 @@ ospf_lsupd_receive(struct ospf_packet *ps_i, struct ospf_iface *ifa,
u16 chsum = lsa->checksum; u16 chsum = lsa->checksum;
if (chsum != lsasum_check(lsa, NULL)) if (chsum != lsasum_check(lsa, NULL))
{ {
log(L_WARN "Received bad lsa checksum from %I: %x %x", n->ip, chsum, lsa->checksum); log(L_WARN "OSPF: Received LSA from %I with bad checskum: %x %x",
n->ip, chsum, lsa->checksum);
continue; continue;
} }
u16 lsa_type = ntohs(lsa->type_raw); u32 lsa_type, lsa_domain;
lsa_type = xxxx(lsa_type); // XXXX finish lsa_ntoh_hdr(lsa, &lsatmp);
#ifdef OSPFv2 lsa_xxxxtype(lsatmp.type_raw, ifa, &lsa_type, &lsa_domain);
/* pg 143 (2) */ /* pg 143 (2) */
if ((lsa->type == 0) || (lsa->type == 6) || (lsa->type > LSA_T_NSSA)) if (!lsa_type)
{ {
log(L_WARN "Unknown LSA type from %I", n->ip); log(L_WARN "OSPF: Received unknown LSA type from %I", n->ip);
continue; continue;
} }
/* pg 143 (3) */
if ((lsa_type == LSA_T_EXT) && !oa_is_ext(ifa->oa))
{
log(L_WARN "Received External LSA in stub area from %I", n->ip);
continue;
}
#else /* OSPFv3 */
/* 4.5.1 (2) */ /* 4.5.1 (2) */
if ((LSA_SCOPE(lsa_type) == LSA_SCOPE_AS) && !oa_is_ext(ifa->oa)) if ((LSA_SCOPE(lsa_type) == LSA_SCOPE_AS) && !oa_is_ext(ifa->oa))
{ {
log(L_WARN "Received LSA with AS scope in stub area from %I", n->ip); log(L_WARN "OSPF: Received LSA with AS scope in stub area from %I", n->ip);
continue; continue;
} }
/* 4.5.1 (3) */ /* 4.5.1 (3) */
if ((LSA_SCOPE(lsa_type) == LSA_SCOPE_RES)) if (LSA_SCOPE(lsa_type) == LSA_SCOPE_RES)
{ {
log(L_WARN "Received LSA with invalid scope from %I", n->ip); log(L_WARN "OSPF: Received LSA with invalid scope from %I", n->ip);
continue; continue;
} }
#endif
ntohlsah(lsa, &lsatmp); DBG("Update Type: %04x, 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",
lsa_type, lsatmp.id, lsatmp.rt, lsatmp.sn, lsatmp.age, lsatmp.checksum); lsa_type, lsatmp.id, lsatmp.rt, lsatmp.sn, lsatmp.age, lsatmp.checksum);
/* FIXME domain should be link id for unknown LSA types with zero Ubit */ lsadb = ospf_hash_find(po->gr, lsa_domain, lsatmp.id, lsatmp.rt, lsa_type);
u32 domain = ospf_lsa_domain(lsa_type, ifa);
lsadb = ospf_hash_find_header(po->gr, domain, &lsatmp);
#ifdef LOCAL_DEBUG #ifdef LOCAL_DEBUG
if (lsadb) if (lsadb)
DBG("I have Type: %u ID: %R RT: %R, Sn: 0x%08x Age: %u, Sum: %u\n", DBG("I have Type: %04x, Id: %R, Rt: %R, Sn: 0x%08x, Age: %u, Sum: %u\n",
lsadb->lsa.type, lsadb->lsa.id, lsadb->lsa.rt, lsadb->lsa_type, lsadb->lsa.id, lsadb->lsa.rt,
lsadb->lsa.sn, lsadb->lsa.age, lsadb->lsa.checksum); lsadb->lsa.sn, lsadb->lsa.age, lsadb->lsa.checksum);
#endif #endif
@ -589,7 +524,7 @@ ospf_lsupd_receive(struct ospf_packet *ps_i, struct ospf_iface *ifa,
lsadb->inst_t = now; lsadb->inst_t = now;
lsadb->ini_age = 0; lsadb->ini_age = 0;
lsasum_calculate(&lsadb->lsa, lsadb->lsa_body); lsasum_calculate(&lsadb->lsa, lsadb->lsa_body);
ospf_lsupd_flood(po, NULL, NULL, &lsadb->lsa, domain, 1); ospf_lsupd_flood(po, NULL, NULL, &lsadb->lsa, lsa_domain, 1);
} }
else else
{ {
@ -600,7 +535,7 @@ ospf_lsupd_receive(struct ospf_packet *ps_i, struct ospf_iface *ifa,
lsa->sn = htonl(LSA_MAXSEQNO); lsa->sn = htonl(LSA_MAXSEQNO);
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(po, NULL, lsa, &lsatmp, domain, 0); ospf_lsupd_flood(po, NULL, lsa, &lsatmp, lsa_domain, 0);
} }
continue; continue;
} }
@ -622,7 +557,7 @@ ospf_lsupd_receive(struct ospf_packet *ps_i, struct ospf_iface *ifa,
{ {
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, domain, &lsadb->lsa)) != NULL) if ((en = ospf_hash_find_header(ntmp->lsrth, lsa_domain, &lsadb->lsa)) != NULL)
{ {
s_rem_node(SNODE en); s_rem_node(SNODE en);
ospf_hash_delete(ntmp->lsrth, en); ospf_hash_delete(ntmp->lsrth, en);
@ -630,7 +565,7 @@ ospf_lsupd_receive(struct ospf_packet *ps_i, struct ospf_iface *ifa,
} }
/* pg 144 (5b) */ /* pg 144 (5b) */
if (ospf_lsupd_flood(po, n, lsa, &lsatmp, domain, 1) == 0) if (ospf_lsupd_flood(po, n, lsa, &lsatmp, lsa_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)
@ -652,26 +587,24 @@ ospf_lsupd_receive(struct ospf_packet *ps_i, struct ospf_iface *ifa,
/* pg 144 (5d) */ /* pg 144 (5d) */
void *body = mb_alloc(p->pool, lsatmp.length - sizeof(struct ospf_lsa_header)); void *body = mb_alloc(p->pool, lsatmp.length - sizeof(struct ospf_lsa_header));
ntohlsab(lsa + 1, body, lsatmp.length - sizeof(struct ospf_lsa_header)); lsa_ntoh_body(lsa + 1, body, lsatmp.length - sizeof(struct ospf_lsa_header));
/* We will do validation check after flooding and /* We will do validation check after flooding and
acknowledging given LSA to minimize problems acknowledging given LSA to minimize problems
when communicating with non-validating peer */ when communicating with non-validating peer */
if (lsa_validate(&lsatmp, body) == 0) if (lsa_validate(&lsatmp, lsa_type, ospf_is_v2(po), body) == 0)
{ {
log(L_WARN "Received invalid LSA from %I", n->ip); log(L_WARN "Received invalid LSA from %I", n->ip);
mb_free(body); mb_free(body);
continue; continue;
} }
lsadb = lsa_install_new(po, &lsatmp, domain, body); lsadb = lsa_install_new(po, &lsatmp, lsa_domain, body);
DBG("New LSA installed in DB\n"); DBG("New LSA installed in DB\n");
#ifdef OSPFv3
/* Events 6,7 from RFC5340 4.4.3. */ /* Events 6,7 from RFC5340 4.4.3. */
if ((lsa_type == LSA_T_LINK) && (ifa->state == OSPF_IS_DR)) if ((lsa_type == LSA_T_LINK) && (ifa->state == OSPF_IS_DR))
schedule_net_lsa(ifa); schedule_net_lsa(ifa);
#endif
continue; continue;
} }
@ -710,16 +643,13 @@ ospf_lsupd_receive(struct ospf_packet *ps_i, struct ospf_iface *ifa,
continue; continue;
} }
{ struct ospf_lsreq_item lsr = {
list l; .domain = lsadb->domain,
struct l_lsr_head ll; .type = lsadb->lsa_type,
init_list(&l); .id = lsadb->lsa.id,
ll.lsh.id = lsadb->lsa.id; .rt = lsadb->lsa.rt
ll.lsh.rt = lsadb->lsa.rt; };
ll.lsh.type = lsadb->lsa.type; ospf_lsupd_send_list(n, &lsr);
add_tail(&l, NODE & ll);
ospf_lsupd_send_list(n, &l);
}
} }
/* Send direct LSAs */ /* Send direct LSAs */

View File

@ -12,7 +12,7 @@
void ospf_dump_lsahdr(struct proto_ospf *po, struct ospf_lsa_header *lsa_n); void ospf_dump_lsahdr(struct proto_ospf *po, struct ospf_lsa_header *lsa_n);
void ospf_dump_common(struct proto_ospf *po, struct ospf_packet *pkt); void ospf_dump_common(struct proto_ospf *po, struct ospf_packet *pkt);
void ospf_lsupd_send_list(struct ospf_neighbor *n, list * l); void ospf_lsupd_send_list(struct ospf_neighbor *n, struct ospf_lsreq_item *lsr);
void ospf_lsupd_receive(struct ospf_packet *ps_i, 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 proto_ospf *po, int ospf_lsupd_flood(struct proto_ospf *po,

View File

@ -26,8 +26,8 @@ const char *ospf_inm[] =
}; };
static void neigh_chstate(struct ospf_neighbor *n, u8 state); static void neigh_chstate(struct ospf_neighbor *n, u8 state);
static struct ospf_neighbor *electbdr(list nl); static struct ospf_neighbor *electbdr(struct proto_ospf *, list nl);
static struct ospf_neighbor *electdr(list nl); static struct ospf_neighbor *electdr(struct proto_ospf *, list nl);
static void neighbor_timer_hook(timer * timer); static void neighbor_timer_hook(timer * timer);
static void rxmt_timer_hook(timer * timer); static void rxmt_timer_hook(timer * timer);
static void ackd_timer_hook(timer * t); static void ackd_timer_hook(timer * t);
@ -37,11 +37,9 @@ init_lists(struct ospf_neighbor *n)
{ {
s_init_list(&(n->lsrql)); s_init_list(&(n->lsrql));
n->lsrqh = ospf_top_new(n->pool); n->lsrqh = ospf_top_new(n->pool);
s_init(&(n->lsrqi), &(n->lsrql));
s_init_list(&(n->lsrtl)); s_init_list(&(n->lsrtl));
n->lsrth = ospf_top_new(n->pool); n->lsrth = ospf_top_new(n->pool);
s_init(&(n->lsrti), &(n->lsrtl));
} }
/* Resets LSA request and retransmit lists. /* Resets LSA request and retransmit lists.
@ -163,8 +161,11 @@ neigh_chstate(struct ospf_neighbor *n, u8 state)
} }
} }
static inline u32 neigh_get_id(struct proto_ospf *po, struct ospf_neighbor *n)
{ return ospf_is_v2(po) ? ipa_to_u32(n->ip) : n->rid; }
static struct ospf_neighbor * static struct ospf_neighbor *
electbdr(list nl) electbdr(struct proto_ospf *po, list nl)
{ {
struct ospf_neighbor *neigh, *n1, *n2; struct ospf_neighbor *neigh, *n1, *n2;
u32 nid; u32 nid;
@ -173,11 +174,7 @@ electbdr(list nl)
n2 = NULL; n2 = NULL;
WALK_LIST(neigh, nl) /* First try those decl. themselves */ WALK_LIST(neigh, nl) /* First try those decl. themselves */
{ {
#ifdef OSPFv2 nid = neigh_get_id(po, neigh);
nid = ipa_to_u32(neigh->ip);
#else /* OSPFv3 */
nid = neigh->rid;
#endif
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 */
@ -222,7 +219,7 @@ electbdr(list nl)
} }
static struct ospf_neighbor * static struct ospf_neighbor *
electdr(list nl) electdr(struct proto_ospf *po, list nl)
{ {
struct ospf_neighbor *neigh, *n; struct ospf_neighbor *neigh, *n;
u32 nid; u32 nid;
@ -230,11 +227,7 @@ electdr(list nl)
n = NULL; n = NULL;
WALK_LIST(neigh, nl) /* And now DR */ WALK_LIST(neigh, nl) /* And now DR */
{ {
#ifdef OSPFv2 nid = neigh_get_id(po, neigh);
nid = ipa_to_u32(neigh->ip);
#else /* OSPFv3 */
nid = neigh->rid;
#endif
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 */
@ -449,19 +442,14 @@ bdr_election(struct ospf_iface *ifa)
me.priority = ifa->priority; me.priority = ifa->priority;
me.ip = ifa->addr->ip; me.ip = ifa->addr->ip;
#ifdef OSPFv2 me.dr = ospf_is_v2(po) ? ipa_to_u32(ifa->drip) : ifa->drid;
me.dr = ipa_to_u32(ifa->drip); me.bdr = ospf_is_v2(po) ? ipa_to_u32(ifa->bdrip) : ifa->bdrid;
me.bdr = ipa_to_u32(ifa->bdrip);
#else /* OSPFv3 */
me.dr = ifa->drid;
me.bdr = ifa->bdrid;
me.iface_id = ifa->iface->index; 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(po, ifa->neigh_list);
ndr = electdr(ifa->neigh_list); ndr = electdr(po, ifa->neigh_list);
if (ndr == NULL) if (ndr == NULL)
ndr = nbdr; ndr = nbdr;
@ -472,16 +460,11 @@ bdr_election(struct ospf_iface *ifa)
|| ((ifa->bdrid == myid) && (nbdr != &me)) || ((ifa->bdrid == myid) && (nbdr != &me))
|| ((ifa->bdrid != myid) && (nbdr == &me))) || ((ifa->bdrid != myid) && (nbdr == &me)))
{ {
#ifdef OSPFv2 me.dr = ndr ? neigh_get_id(po, ndr) : 0;
me.dr = ndr ? ipa_to_u32(ndr->ip) : 0; me.bdr = nbdr ? neigh_get_id(po, nbdr) : 0;
me.bdr = nbdr ? ipa_to_u32(nbdr->ip) : 0;
#else /* OSPFv3 */
me.dr = ndr ? ndr->rid : 0;
me.bdr = nbdr ? nbdr->rid : 0;
#endif
nbdr = electbdr(ifa->neigh_list); nbdr = electbdr(po, ifa->neigh_list);
ndr = electdr(ifa->neigh_list); ndr = electdr(po, ifa->neigh_list);
if (ndr == NULL) if (ndr == NULL)
ndr = nbdr; ndr = nbdr;
@ -492,13 +475,11 @@ bdr_election(struct ospf_iface *ifa)
ifa->drid = ndr ? ndr->rid : 0; ifa->drid = ndr ? ndr->rid : 0;
ifa->drip = ndr ? ndr->ip : IPA_NONE; ifa->drip = ndr ? ndr->ip : IPA_NONE;
ifa->dr_iface_id = ndr ? ndr->iface_id : 0;
ifa->bdrid = nbdr ? nbdr->rid : 0; ifa->bdrid = nbdr ? nbdr->rid : 0;
ifa->bdrip = nbdr ? nbdr->ip : IPA_NONE; ifa->bdrip = nbdr ? nbdr->ip : IPA_NONE;
#ifdef OSPFv3
ifa->dr_iface_id = ndr ? ndr->iface_id : 0;
#endif
DBG("DR=%R, BDR=%R\n", ifa->drid, ifa->bdrid); DBG("DR=%R, BDR=%R\n", ifa->drid, ifa->bdrid);
doadj = ((ifa->drid != odrid) || (ifa->bdrid != obdrid)); doadj = ((ifa->drid != odrid) || (ifa->bdrid != obdrid));
@ -640,26 +621,28 @@ rxmt_timer_hook(timer * timer)
{ {
if (!EMPTY_SLIST(n->lsrtl)) /* FULL */ if (!EMPTY_SLIST(n->lsrtl)) /* FULL */
{ {
list uplist; struct ospf_lsreq_item *lsr_head, *lsr;
slab *upslab; struct ospf_lsreq_item **lsr_pos = &lsr_head;
struct l_lsr_head *llsh;
init_list(&uplist); slab *upslab = sl_new(n->pool, sizeof(struct ospf_lsreq_item));
upslab = sl_new(n->pool, sizeof(struct l_lsr_head));
WALK_SLIST(en, n->lsrtl) WALK_SLIST(en, n->lsrtl)
{ {
if ((SNODE en)->next == (SNODE en)) if ((SNODE en)->next == (SNODE en))
bug("RTList is cycled"); bug("RTList is cycled");
llsh = sl_alloc(upslab);
llsh->lsh.id = en->lsa.id; lsr = sl_alloc(upslab);
llsh->lsh.rt = en->lsa.rt; lsr->domain = en->domain;
llsh->lsh.type = en->lsa.type; lsr->type = en->lsa_type;
DBG("Working on ID: %R, RT: %R, Type: %u\n", lsr->id = en->lsa.id;
en->lsa.id, en->lsa.rt, en->lsa.type); lsr->rt = en->lsa.rt;
add_tail(&uplist, NODE llsh);
*lsr_pos = lsr;
lsr_pos = &(lsr->next);
} }
ospf_lsupd_send_list(n, &uplist); *lsr_pos = NULL;
ospf_lsupd_send_list(n, lsr_head);
rfree(upslab); rfree(upslab);
} }
} }

View File

@ -164,11 +164,7 @@ ospf_area_add(struct proto_ospf *po, struct ospf_area_config *ac, int reconf)
if (oa->areaid == 0) if (oa->areaid == 0)
po->backbone = oa; po->backbone = oa;
#ifdef OSPFv2 oa->options = ospf_is_v2(po) ? ac->type : (OPT_R | ac->type | OPT_V6);
oa->options = ac->type;
#else /* OSPFv3 */
oa->options = OPT_R | ac->type | OPT_V6;
#endif
/* /*
* Set E-bit for NSSA ABR routers. No need to explicitly call * Set E-bit for NSSA ABR routers. No need to explicitly call
@ -383,7 +379,6 @@ schedule_net_lsa(struct ospf_iface *ifa)
ifa->orignet = 1; ifa->orignet = 1;
} }
#ifdef OSPFv3
void void
schedule_link_lsa(struct ospf_iface *ifa) schedule_link_lsa(struct ospf_iface *ifa)
{ {
@ -392,7 +387,6 @@ schedule_link_lsa(struct ospf_iface *ifa)
OSPF_TRACE(D_EVENTS, "Scheduling link-LSA origination for iface %s", ifa->iface->name); OSPF_TRACE(D_EVENTS, "Scheduling link-LSA origination for iface %s", ifa->iface->name);
ifa->origlink = 1; ifa->origlink = 1;
} }
#endif
void void
schedule_rt_lsa(struct ospf_area *oa) schedule_rt_lsa(struct ospf_area *oa)
@ -589,7 +583,7 @@ ospf_rt_notify(struct proto *p, rtable *tbl UNUSED, net * n, rte * new, rte * ol
// FIXME check for gw should be per ifa, not per iface // FIXME check for gw should be per ifa, not per iface
if ((new->attrs->dest == RTD_ROUTER) && if ((new->attrs->dest == RTD_ROUTER) &&
ipa_nonzero(new->attrs->gw) && ipa_nonzero(new->attrs->gw) &&
!ipa_has_link_scope(new->attrs->gw) && !ipa_is_link_local(new->attrs->gw) &&
(ospf_iface_find((struct proto_ospf *) p, new->attrs->iface) != NULL)) (ospf_iface_find((struct proto_ospf *) p, new->attrs->iface) != NULL))
gw = new->attrs->gw; gw = new->attrs->gw;
@ -682,11 +676,8 @@ ospf_area_reconfigure(struct ospf_area *oa, struct ospf_area_config *nac)
oa->ac = nac; oa->ac = nac;
// FIXME better area type reconfiguration // FIXME better area type reconfiguration
#ifdef OSPFv2 oa->options = ospf_is_v2(oa->po) ? nac->type : (OPT_R | nac->type | OPT_V6);
oa->options = nac->type;
#else /* OSPFv3 */
oa->options = OPT_R | nac->type | OPT_V6;
#endif
if (oa_is_nssa(oa) && (oa->po->areano > 1)) if (oa_is_nssa(oa) && (oa->po->areano > 1))
oa->po->ebit = 1; oa->po->ebit = 1;
@ -986,7 +977,7 @@ lsa_compare_for_state(const void *p1, const void *p2)
if (nt1) if (nt1)
{ {
#ifdef OSPFv3 #ifdef OSPFv3
/* In OSPFv3, neworks are named base on ID of DR */ /* In OSPFv3, networks are named based on ID of DR */
if (lsa1->rt != lsa2->rt) if (lsa1->rt != lsa2->rt)
return lsa1->rt - lsa2->rt; return lsa1->rt - lsa2->rt;
#endif #endif
@ -1488,17 +1479,17 @@ ospf_sh_lsadb(struct lsadb_show_data *ld)
case LSA_SCOPE_AS: case LSA_SCOPE_AS:
cli_msg(-1017, "Global"); cli_msg(-1017, "Global");
break; break;
case LSA_SCOPE_AREA: case LSA_SCOPE_AREA:
cli_msg(-1017, "Area %R", hea[i]->domain); cli_msg(-1017, "Area %R", hea[i]->domain);
break; break;
#ifdef OSPFv3
case LSA_SCOPE_LINK: case LSA_SCOPE_LINK:
{ {
struct iface *ifa = if_find_by_index(hea[i]->domain); struct iface *ifa = if_find_by_index(hea[i]->domain);
cli_msg(-1017, "Link %s", (ifa != NULL) ? ifa->name : "?"); cli_msg(-1017, "Link %s", (ifa != NULL) ? ifa->name : "?");
} }
break; break;
#endif
} }
cli_msg(-1017, ""); cli_msg(-1017, "");
cli_msg(-1017," Type LS ID Router Age Sequence Checksum"); cli_msg(-1017," Type LS ID Router Age Sequence Checksum");
@ -1507,7 +1498,6 @@ ospf_sh_lsadb(struct lsadb_show_data *ld)
last_domain = hea[i]->domain; last_domain = hea[i]->domain;
} }
cli_msg(-1017," %04x %-15R %-15R %5u %08x %04x", cli_msg(-1017," %04x %-15R %-15R %5u %08x %04x",
lsa->type, lsa->id, lsa->rt, lsa->age, lsa->sn, lsa->checksum); lsa->type, lsa->id, lsa->rt, lsa->age, lsa->sn, lsa->checksum);
} }

View File

@ -65,11 +65,10 @@ do { if ((po->proto.debug & D_PACKETS) || OSPF_FORCE_DEBUG) \
#define MINLSARRIVAL 1 #define MINLSARRIVAL 1
#define LSINFINITY 0xffffff #define LSINFINITY 0xffffff
#define DEFAULT_OSPFTICK 1 #define OSPF_DEFAULT_TICK 1
#define DEFAULT_RFC1583 0 /* compatibility with rfc1583 */ #define OSPF_DEFAULT_STUB_COST 1000
#define DEFAULT_STUB_COST 1000 #define OSPF_DEFAULT_ECMP_LIMIT 16
#define DEFAULT_ECMP_LIMIT 16 #define OSPF_DEFAULT_TRANSINT 40
#define DEFAULT_TRANSINT 40
struct ospf_config struct ospf_config
@ -202,11 +201,12 @@ struct ospf_iface
u16 autype; 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 */
ip_addr all_routers; /* */ ip_addr all_routers; /* XXXX */
ip_addr drip; /* Designated router */ ip_addr des_routers; /* XXXX */
ip_addr bdrip; /* Backup DR */ ip_addr drip; /* Designated router IP */
u32 drid; ip_addr bdrip; /* Backup DR IP */
u32 bdrid; u32 drid; /* DR Router ID */
u32 bdrid; /* BDR Router ID */
s16 rt_pos_beg; /* Position of iface in Router-LSA, begin, inclusive */ s16 rt_pos_beg; /* Position of iface in Router-LSA, begin, inclusive */
s16 rt_pos_end; /* Position of iface in Router-LSA, end, exclusive */ s16 rt_pos_end; /* Position of iface in Router-LSA, end, exclusive */
s16 px_pos_beg; /* Position of iface in Rt Prefix-LSA, begin, inclusive */ s16 px_pos_beg; /* Position of iface in Rt Prefix-LSA, begin, inclusive */
@ -244,7 +244,7 @@ struct ospf_iface
#define OSPF_I_OK 0 /* Everything OK */ #define OSPF_I_OK 0 /* Everything OK */
#define OSPF_I_SK 1 /* Socket open failed */ #define OSPF_I_SK 1 /* Socket open failed */
#define OSPF_I_LL 2 /* Missing link-local address (OSPFv3) */ #define OSPF_I_LL 2 /* Missing link-local address (OSPFv3) */
u8 sk_dr; /* Socket is a member of DRouters group */ u8 sk_dr; /* Socket is a member of designated routers group */
u8 marked; /* Used in OSPF reconfigure */ u8 marked; /* Used in OSPF reconfigure */
u16 rxbuf; /* Buffer size */ u16 rxbuf; /* Buffer size */
u8 check_link; /* Whether iface link change is used */ u8 check_link; /* Whether iface link change is used */
@ -276,7 +276,6 @@ union ospf_auth
/* Area IDs */ /* Area IDs */
#define BACKBONE 0 #define BACKBONE 0
#define DBDES_I 4 /* Init bit */ #define DBDES_I 4 /* Init bit */
#define DBDES_M 2 /* More bit */ #define DBDES_M 2 /* More bit */
#define DBDES_MS 1 /* Master/Slave bit */ #define DBDES_MS 1 /* Master/Slave bit */
@ -284,7 +283,6 @@ union ospf_auth
/* /*
* There is slight difference in OSPF packet header between v2 and v3 * There is slight difference in OSPF packet header between v2 and v3
* in vdep field. For OSPFv2, vdep is u16 authentication type and * in vdep field. For OSPFv2, vdep is u16 authentication type and
@ -303,6 +301,18 @@ struct ospf_packet
u16 vdep; u16 vdep;
}; };
static inline u16 ospf_pkt_get_autype(struct ospf_packet *pkt)
{ return ntohs(pkt->vdep); }
static inline void ospf_pkt_set_autype(struct ospf_packet *pkt, u16 val)
{ pkt->vdep = htons(val); }
static inline u8 ospf_pkt_get_instance_id(struct ospf_packet *pkt)
{ return ntohs(pkt->vdep) >> 8; }
static inline void ospf_pkt_set_instance_id(struct ospf_packet *pkt, u16 val)
{ pkt->vdep = htons(val << 8); }
// XXXX // XXXX
/* /*
@ -323,6 +333,8 @@ struct ospf_packet
#define LSA_T_LINK 0x0008 #define LSA_T_LINK 0x0008
#define LSA_T_PREFIX 0x2009 #define LSA_T_PREFIX 0x2009
#define LSA_T_V2_MASK 0x00ff
#define LSA_UBIT 0x8000 #define LSA_UBIT 0x8000
#define LSA_SCOPE_LINK 0x0000 #define LSA_SCOPE_LINK 0x0000
@ -330,7 +342,7 @@ struct ospf_packet
#define LSA_SCOPE_AS 0x4000 #define LSA_SCOPE_AS 0x4000
#define LSA_SCOPE_RES 0x6000 #define LSA_SCOPE_RES 0x6000
#define LSA_SCOPE_MASK 0x6000 #define LSA_SCOPE_MASK 0x6000
#define LSA_SCOPE(lsa) ((lsa) & LSA_SCOPE_MASK) #define LSA_SCOPE(type) ((type) & LSA_SCOPE_MASK)
#define LSA_MAXAGE 3600 /* 1 hour */ #define LSA_MAXAGE 3600 /* 1 hour */
@ -346,6 +358,8 @@ struct ospf_packet
#define LSART_STUB 3 #define LSART_STUB 3
#define LSART_VLNK 4 #define LSART_VLNK 4
#define LSA_RT2_LINKS 0x0000FFFF
#define LSA_SUM2_TOS 0xFF000000 #define LSA_SUM2_TOS 0xFF000000
#define LSA_EXT2_TOS 0x7F000000 #define LSA_EXT2_TOS 0x7F000000
@ -399,6 +413,19 @@ struct ospf_lsa_rt2_link
#endif #endif
}; };
struct ospf_lsa_rt2_tos
{
#ifdef CPU_BIG_ENDIAN
u8 tos;
u8 padding;
u16 metric;
#else
u16 metric;
u8 padding;
u8 tos;
#endif
};
struct ospf_lsa_rt3_link struct ospf_lsa_rt3_link
{ {
#ifdef CPU_BIG_ENDIAN #ifdef CPU_BIG_ENDIAN
@ -486,27 +513,6 @@ struct ospf_lsa_prefix
}; };
#ifdef OSPFv2
/* Endianity swap for lsa->type */
#define ntoht(x) x
#define htont(x) x
#else /* OSPFv3 */
/* Endianity swap for lsa->type */
#define ntoht(x) ntohs(x)
#define htont(x) htons(x)
#endif
#define METRIC_MASK 0x00FFFFFF #define METRIC_MASK 0x00FFFFFF
#define OPTIONS_MASK 0x00FFFFFF #define OPTIONS_MASK 0x00FFFFFF
@ -519,8 +525,6 @@ lsa_net_count(struct ospf_lsa_header *lsa)
} }
#ifdef OSPFv3
#define IPV6_PREFIX_SPACE(x) ((((x) + 63) / 32) * 4) #define IPV6_PREFIX_SPACE(x) ((((x) + 63) / 32) * 4)
#define IPV6_PREFIX_WORDS(x) (((x) + 63) / 32) #define IPV6_PREFIX_WORDS(x) (((x) + 63) / 32)
@ -581,21 +585,21 @@ put_ipv6_addr(u32 *buf, ip_addr addr)
return buf + 4; return buf + 4;
} }
#endif
struct ospf_lsreq_header struct ospf_lsreq_header
{ {
u32 type; u32 type;
u32 id; u32 id;
u32 rt; /* Advertising router */ u32 rt;
}; };
struct l_lsr_head struct ospf_lsreq_item
{ {
node n; struct ospf_lsreq_item *next;
struct ospf_lsreq_header lsh; u32 domain;
u32 type;
u32 id;
u32 rt;
}; };
@ -625,19 +629,30 @@ struct ospf_neighbor
u8 adj; /* built adjacency? */ u8 adj; /* built adjacency? */
u32 options; /* Options received */ u32 options; /* Options received */
/* dr and bdr store IP address in OSPFv2 and router ID in OSPFv3, /* Entries dr and bdr store IP addresses in OSPFv2 and router IDs in
we use the same type to simplify handling */ * OSPFv3, we use the same type to simplify handling
*/
u32 dr; /* Neigbour's idea of DR */ u32 dr; /* Neigbour's idea of DR */
u32 bdr; /* Neigbour's idea of BDR */ u32 bdr; /* Neigbour's idea of BDR */
u32 iface_id; /* ID of Neighbour's iface connected to common network */ u32 iface_id; /* ID of Neighbour's iface connected to common network */
siterator dbsi; /* Database summary list iterator */ /* Database summary list iterator, controls initial dbdes exchange.
slist lsrql; /* Link state request */ * Advances in the LSA list as dbdes packets are sent.
struct top_graph *lsrqh; /* LSA graph */ */
siterator lsrqi; siterator dbsi; /* iterator of po->lsal */
slist lsrtl; /* Link state retransmission list */
siterator lsrti; /* Link state request list, controls initial LSA exchange.
* Entries added when received in dbdes packets, removed as sent in lsreq packets.
*/
slist lsrql; /* slist of struct top_hash_entry from n->lsrqh */
struct top_graph *lsrqh;
/* Link state retransmission list, controls LSA retransmission during flood.
* Entries added as sent in lsupd packets, removed when received in lsack packets.
*/
slist lsrtl; /* slist of struct top_hash_entry from n->lsrth */
struct top_graph *lsrth; struct top_graph *lsrth;
void *ldbdes; /* Last database description packet */ void *ldbdes; /* Last database description packet */
timer *rxmt_timer; /* RXMT timer */ timer *rxmt_timer; /* RXMT timer */
list ackl[2]; list ackl[2];

View File

@ -24,16 +24,12 @@ ospf_pkt_fill_hdr(struct ospf_iface *ifa, void *buf, u8 h_type)
pkt->routerid = htonl(po->router_id); pkt->routerid = htonl(po->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);
#endif
pkt->checksum = 0; pkt->checksum = 0;
if (ospf_is_v2(po))
ospf_pkt_set_autype(pkt, ifa->autype);
else
ospf_pkt_set_instance_id(pkt, ifa->instance_id);
} }
unsigned unsigned
@ -42,47 +38,48 @@ ospf_pkt_maxsize(struct ospf_iface *ifa)
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;
unsigned headers = SIZE_OF_IP_HEADER; unsigned headers = SIZE_OF_IP_HEADER;
#ifdef OSPFv2 /* For OSPFv2 */
if (ifa->autype == OSPF_AUTH_CRYPT) if (ifa->autype == OSPF_AUTH_CRYPT)
headers += OSPF_AUTH_CRYPT_SIZE; headers += OSPF_AUTH_CRYPT_SIZE;
#endif
return mtu - headers; return mtu - headers;
} }
#ifdef OSPFv2
/* We assume OSPFv2 in ospf_pkt_finalize() */
static void 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;
void *tail; union ospf_auth *auth = (void *) (pkt + 1);
struct MD5Context ctxt; unsigned plen = ntohs(pkt->length);
char password[OSPF_AUTH_CRYPT_SIZE];
pkt->checksum = 0; pkt->checksum = 0;
pkt->autype = htons(ifa->autype); ospf_pkt_set_autype(pkt, ifa->autype);
bzero(&pkt->u, sizeof(union ospf_auth)); bzero(auth, sizeof(union ospf_auth));
/* Compatibility note: pkt->u may contain anything if autype is /* Compatibility note: auth may contain anything if autype is
none, but nonzero values do not work with Mikrotik OSPF */ none, but nonzero values do not work with Mikrotik OSPF */
switch(ifa->autype) switch (ifa->autype)
{ {
case OSPF_AUTH_SIMPLE: case OSPF_AUTH_SIMPLE:
passwd = password_find(ifa->passwords, 1); passwd = password_find(ifa->passwords, 1);
if (!passwd) if (!passwd)
{ {
log( L_ERR "No suitable password found for authentication" ); log(L_ERR "No suitable password found for authentication");
return; return;
} }
password_cpy(pkt->u.password, passwd->password, sizeof(union ospf_auth)); password_cpy(auth->password, passwd->password, sizeof(union ospf_auth));
case OSPF_AUTH_NONE: case OSPF_AUTH_NONE:
pkt->checksum = ipsum_calculate(pkt, sizeof(struct ospf_packet) - {
sizeof(union ospf_auth), (pkt + 1), void *body = (void *) (auth + 1);
ntohs(pkt->length) - unsigned blen = plen - sizeof(struct ospf_packet) - sizeof(union ospf_auth);
sizeof(struct ospf_packet), NULL); pkt->checksum = ipsum_calculate(pkt, sizeof(struct ospf_packet), body, blen, NULL);
}
break; break;
case OSPF_AUTH_CRYPT: case OSPF_AUTH_CRYPT:
passwd = password_find(ifa->passwords, 0); passwd = password_find(ifa->passwords, 0);
if (!passwd) if (!passwd)
@ -106,45 +103,53 @@ ospf_pkt_finalize(struct ospf_iface *ifa, struct ospf_packet *pkt)
ifa->csn_use = now; ifa->csn_use = now;
pkt->u.md5.keyid = passwd->id; auth->md5.zero = 0;
pkt->u.md5.len = OSPF_AUTH_CRYPT_SIZE; auth->md5.keyid = passwd->id;
pkt->u.md5.zero = 0; auth->md5.len = OSPF_AUTH_CRYPT_SIZE;
pkt->u.md5.csn = htonl(ifa->csn); auth->md5.csn = htonl(ifa->csn);
tail = ((void *)pkt) + ntohs(pkt->length);
MD5Init(&ctxt); {
MD5Update(&ctxt, (char *) pkt, ntohs(pkt->length)); void *tail = ((void *) pkt) + plen;
password_cpy(password, passwd->password, OSPF_AUTH_CRYPT_SIZE); char password[OSPF_AUTH_CRYPT_SIZE];
MD5Update(&ctxt, password, OSPF_AUTH_CRYPT_SIZE); password_cpy(password, passwd->password, OSPF_AUTH_CRYPT_SIZE);
MD5Final(tail, &ctxt);
struct MD5Context ctxt;
MD5Init(&ctxt);
MD5Update(&ctxt, (char *) pkt, plen);
MD5Update(&ctxt, password, OSPF_AUTH_CRYPT_SIZE);
MD5Final(tail, &ctxt);
}
break; break;
default: default:
bug("Unknown authentication type"); bug("Unknown authentication type");
} }
} }
/* We assume OSPFv2 in ospf_pkt_checkauth() */
static int static int
ospf_pkt_checkauth(struct ospf_neighbor *n, struct ospf_iface *ifa, struct ospf_packet *pkt, int size) ospf_pkt_checkauth(struct ospf_neighbor *n, struct ospf_iface *ifa, struct ospf_packet *pkt, int size)
{ {
struct proto_ospf *po = ifa->oa->po; struct proto_ospf *po = ifa->oa->po;
struct proto *p = &po->proto; union ospf_auth *auth = (void *) (pkt + 1);
struct password_item *pass = NULL, *ptmp; struct password_item *pass = NULL, *ptmp;
void *tail;
char md5sum[OSPF_AUTH_CRYPT_SIZE];
char password[OSPF_AUTH_CRYPT_SIZE]; char password[OSPF_AUTH_CRYPT_SIZE];
struct MD5Context ctxt;
unsigned plen = ntohs(pkt->length);
u16 autype = ospf_pkt_get_autype(pkt);
if (pkt->autype != htons(ifa->autype)) if (autype != ifa->autype)
{ {
OSPF_TRACE(D_PACKETS, "OSPF_auth: Method differs (%d)", ntohs(pkt->autype)); OSPF_TRACE(D_PACKETS, "OSPF_auth: Method differs (%d)", autype);
return 0; return 0;
} }
switch(ifa->autype) switch (autype)
{ {
case OSPF_AUTH_NONE: case OSPF_AUTH_NONE:
return 1; return 1;
break; break;
case OSPF_AUTH_SIMPLE: case OSPF_AUTH_SIMPLE:
pass = password_find(ifa->passwords, 1); pass = password_find(ifa->passwords, 1);
if (!pass) if (!pass)
@ -154,37 +159,48 @@ ospf_pkt_checkauth(struct ospf_neighbor *n, struct ospf_iface *ifa, struct ospf_
} }
password_cpy(password, pass->password, sizeof(union ospf_auth)); password_cpy(password, pass->password, sizeof(union ospf_auth));
if (memcmp(pkt->u.password, password, sizeof(union ospf_auth))) if (memcmp(auth->password, password, sizeof(union ospf_auth)))
{ {
char ppass[sizeof(union ospf_auth) + 1]; char ppass[sizeof(union ospf_auth) + 1];
bzero(ppass, (sizeof(union ospf_auth) + 1)); bzero(ppass, (sizeof(union ospf_auth) + 1));
memcpy(ppass, pkt->u.password, sizeof(union ospf_auth)); memcpy(ppass, auth->password, sizeof(union ospf_auth));
OSPF_TRACE(D_PACKETS, "OSPF_auth: different passwords (%s)", ppass); OSPF_TRACE(D_PACKETS, "OSPF_auth: different passwords (%s)", ppass);
return 0; return 0;
} }
return 1; return 1;
break; break;
case OSPF_AUTH_CRYPT: case OSPF_AUTH_CRYPT:
if (pkt->u.md5.len != OSPF_AUTH_CRYPT_SIZE) if (auth->md5.len != OSPF_AUTH_CRYPT_SIZE)
{ {
OSPF_TRACE(D_PACKETS, "OSPF_auth: wrong size of md5 digest"); OSPF_TRACE(D_PACKETS, "OSPF_auth: wrong size of md5 digest");
return 0; return 0;
} }
if (ntohs(pkt->length) + OSPF_AUTH_CRYPT_SIZE > size) if (plen + OSPF_AUTH_CRYPT_SIZE > size)
{ {
OSPF_TRACE(D_PACKETS, "OSPF_auth: size mismatch (%d vs %d)", OSPF_TRACE(D_PACKETS, "OSPF_auth: size mismatch (%d vs %d)",
ntohs(pkt->length) + OSPF_AUTH_CRYPT_SIZE, size); plen + OSPF_AUTH_CRYPT_SIZE, size);
return 0; return 0;
} }
tail = ((void *)pkt) + ntohs(pkt->length); if (n)
{
u32 rcv_csn = ntohl(auth->md5.csn);
if(rcv_csn < n->csn)
{
OSPF_TRACE(D_PACKETS, "OSPF_auth: lower sequence number (rcv %d, old %d)", rcv_csn, n->csn);
return 0;
}
n->csn = rcv_csn;
}
if (ifa->passwords) if (ifa->passwords)
{ {
WALK_LIST(ptmp, *(ifa->passwords)) WALK_LIST(ptmp, *(ifa->passwords))
{ {
if (pkt->u.md5.keyid != ptmp->id) continue; if (auth->md5.keyid != ptmp->id) continue;
if ((ptmp->accfrom > now_real) || (ptmp->accto < now_real)) continue; if ((ptmp->accfrom > now_real) || (ptmp->accto < now_real)) continue;
pass = ptmp; pass = ptmp;
break; break;
@ -197,50 +213,32 @@ ospf_pkt_checkauth(struct ospf_neighbor *n, struct ospf_iface *ifa, struct ospf_
return 0; return 0;
} }
if (n) password_cpy(password, pass->password, OSPF_AUTH_CRYPT_SIZE);
{ {
u32 rcv_csn = ntohl(pkt->u.md5.csn); void *tail = ((void *) pkt) + plen;
if(rcv_csn < n->csn) char md5sum[OSPF_AUTH_CRYPT_SIZE];
struct MD5Context ctxt;
MD5Init(&ctxt);
MD5Update(&ctxt, (char *) pkt, plen);
MD5Update(&ctxt, password, OSPF_AUTH_CRYPT_SIZE);
MD5Final(md5sum, &ctxt);
if (memcmp(md5sum, tail, OSPF_AUTH_CRYPT_SIZE))
{ {
OSPF_TRACE(D_PACKETS, "OSPF_auth: lower sequence number (rcv %d, old %d)", rcv_csn, n->csn); OSPF_TRACE(D_PACKETS, "OSPF_auth: wrong md5 digest");
return 0; return 0;
} }
n->csn = rcv_csn;
}
MD5Init(&ctxt);
MD5Update(&ctxt, (char *) pkt, ntohs(pkt->length));
password_cpy(password, pass->password, OSPF_AUTH_CRYPT_SIZE);
MD5Update(&ctxt, password, OSPF_AUTH_CRYPT_SIZE);
MD5Final(md5sum, &ctxt);
if (memcmp(md5sum, tail, OSPF_AUTH_CRYPT_SIZE))
{
OSPF_TRACE(D_PACKETS, "OSPF_auth: wrong md5 digest");
return 0;
} }
return 1; return 1;
break; break;
default: default:
OSPF_TRACE(D_PACKETS, "OSPF_auth: unknown auth type"); OSPF_TRACE(D_PACKETS, "OSPF_auth: unknown auth type");
return 0; return 0;
} }
} }
#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
@ -273,37 +271,39 @@ ospf_rx_hook(sock *sk, int size)
int src_local, dst_local UNUSED, dst_mcast; int src_local, dst_local UNUSED, dst_mcast;
src_local = ipa_in_net(sk->faddr, ifa->addr->prefix, ifa->addr->pxlen); src_local = ipa_in_net(sk->faddr, ifa->addr->prefix, ifa->addr->pxlen);
dst_local = ipa_equal(sk->laddr, ifa->addr->ip); dst_local = ipa_equal(sk->laddr, ifa->addr->ip);
dst_mcast = ipa_equal(sk->laddr, ifa->all_routers) || ipa_equal(sk->laddr, AllDRouters); dst_mcast = ipa_equal(sk->laddr, ifa->all_routers) || ipa_equal(sk->laddr, ifa->des_routers);
#ifdef OSPFv2 if (ospf_is_v2(po))
/* First, we eliminate packets with strange address combinations. {
* In OSPFv2, they might be for other ospf_ifaces (with different IP /* First, we eliminate packets with strange address combinations.
* prefix) on the same real iface, so we don't log it. We enforce * In OSPFv2, they might be for other ospf_ifaces (with different IP
* that (src_local || dst_local), therefore we are eliminating all * prefix) on the same real iface, so we don't log it. We enforce
* such cases. * that (src_local || dst_local), therefore we are eliminating all
*/ * such cases.
if (dst_mcast && !src_local) */
return 1; if (dst_mcast && !src_local)
if (!dst_mcast && !dst_local) return 1;
return 1; if (!dst_mcast && !dst_local)
return 1;
/* Ignore my own broadcast packets */ /* Ignore my own broadcast packets */
if (ifa->cf->real_bcast && ipa_equal(sk->faddr, ifa->addr->ip)) if (ifa->cf->real_bcast && ipa_equal(sk->faddr, ifa->addr->ip))
return 1; return 1;
#else /* OSPFv3 */ }
else
/* In OSPFv3, src_local and dst_local mean link-local. {
* RFC 5340 says that local (non-vlink) packets use /* In OSPFv3, src_local and dst_local mean link-local.
* link-local src address, but does not enforce it. Strange. * RFC 5340 says that local (non-vlink) packets use
*/ * link-local src address, but does not enforce it. Strange.
if (dst_mcast && !src_local) */
log(L_WARN "OSPF: Received multicast packet from %I (not link-local)", sk->faddr); if (dst_mcast && !src_local)
#endif log(L_WARN "OSPF: Received multicast packet from %I (not link-local)", sk->faddr);
}
/* Second, we check packet size, checksum, and the protocol version */ /* Second, we check packet size, checksum, and the protocol version */
struct ospf_packet *ps = (struct ospf_packet *) ip_skip_header(sk->rbuf, &size); struct ospf_packet *pkt = (struct ospf_packet *) ip_skip_header(sk->rbuf, &size);
if (ps == NULL) if (pkt == NULL)
{ {
log(L_ERR "%s%I - bad IP header", mesg, sk->faddr); log(L_ERR "%s%I - bad IP header", mesg, sk->faddr);
return 1; return 1;
@ -315,16 +315,16 @@ ospf_rx_hook(sock *sk, int size)
return 1; return 1;
} }
int osize = ntohs(ps->length); unsigned plen = ntohs(pkt->length);
if ((unsigned) osize < sizeof(struct ospf_packet)) if (plen < sizeof(struct ospf_packet))
{ {
log(L_ERR "%s%I - too low value in size field (%u bytes)", mesg, sk->faddr, osize); log(L_ERR "%s%I - too low value in size field (%u bytes)", mesg, sk->faddr, plen);
return 1; return 1;
} }
if ((osize > size) || ((osize % 4) != 0)) if ((plen > size) || ((plen % 4) != 0))
{ {
log(L_ERR "%s%I - size field does not match (%d/%d)", mesg, sk->faddr, osize, size); log(L_ERR "%s%I - size field does not match (%d/%d)", mesg, sk->faddr, plen, size);
return 1; return 1;
} }
@ -334,50 +334,47 @@ ospf_rx_hook(sock *sk, int size)
return 1; return 1;
} }
if (ps->version != OSPF_VERSION) if (pkt->version != OSPF_VERSION)
{ {
log(L_ERR "%s%I - version %u", mesg, sk->faddr, ps->version); log(L_ERR "%s%I - version %u", mesg, sk->faddr, pkt->version);
return 1; return 1;
} }
#ifdef OSPFv2 if (ospf_is_v2(po) && ospf_pkt_get_autype(pkt) != OSPF_AUTH_CRYPT)
if ((ps->autype != htons(OSPF_AUTH_CRYPT)) &&
(!ipsum_verify(ps, 16, (void *) ps + sizeof(struct ospf_packet),
osize - sizeof(struct ospf_packet), NULL)))
{ {
log(L_ERR "%s%I - bad checksum", mesg, sk->faddr); unsigned hlen = sizeof(struct ospf_packet) - sizeof(union ospf_auth);
return 1; unsigned blen = plen - hlen;
} void *body = ((void *) pkt) + hlen;
#endif
if (! ipsum_verify(pkt, sizeof(struct ospf_packet), body, blen, NULL))
{
log(L_ERR "%s%I - bad checksum", mesg, sk->faddr);
return 1;
}
}
/* Third, we resolve associated iface and handle vlinks. */ /* Third, we resolve associated iface and handle vlinks. */
u32 areaid = ntohl(ps->areaid); u32 areaid = ntohl(pkt->areaid);
u32 rid = ntohl(ps->routerid); u32 rid = ntohl(pkt->routerid);
u8 instance_id = ospf_is_v2(po) ? 0 : ospf_pkt_get_instance_id(pkt);
if ((areaid == ifa->oa->areaid) if ((areaid == ifa->oa->areaid) &&
#ifdef OSPFv3 (instance_id == ifa->instance_id))
&& (ps->instance_id == ifa->instance_id)
#endif
)
{ {
/* It is real iface, source should be local (in OSPFv2) */ /* It is real iface, source should be local (in OSPFv2) */
#ifdef OSPFv2 if (ospf_is_v2(po) && !src_local)
if (!src_local)
return 1; return 1;
#endif
} }
else if (dst_mcast || (areaid != 0)) else if (dst_mcast || (areaid != 0))
{ {
/* Obvious mismatch */ /* Obvious mismatch */
#ifdef OSPFv2 /* We ignore mismatch in OSPFv3 when there might be
/* We ignore mismatch in OSPFv3, because there might be another instance with a different instance ID */
other instance with different instance ID */ if (instance_id == ifa->instance_id)
log(L_ERR "%s%I - area does not match (%R vs %R)", log(L_ERR "%s%I - area does not match (%R vs %R)",
mesg, sk->faddr, areaid, ifa->oa->areaid); mesg, sk->faddr, areaid, ifa->oa->areaid);
#endif
return 1; return 1;
} }
else else
@ -389,9 +386,7 @@ ospf_rx_hook(sock *sk, int size)
{ {
if ((iff->type == OSPF_IT_VLINK) && if ((iff->type == OSPF_IT_VLINK) &&
(iff->voa == ifa->oa) && (iff->voa == ifa->oa) &&
#ifdef OSPFv3 (iff->instance_id == instance_id) &&
(iff->instance_id == ps->instance_id) &&
#endif
(iff->vid == rid)) (iff->vid == rid))
{ {
/* Vlink should be UP */ /* Vlink should be UP */
@ -403,9 +398,10 @@ ospf_rx_hook(sock *sk, int size)
} }
} }
#ifdef OSPFv2 /* FIXME: this warning is strange - NBMA could trigger it too */
log(L_WARN "OSPF: Received packet for unknown vlink (ID %R, IP %I)", rid, sk->faddr); if (ospf_is_v2(po))
#endif log(L_WARN "OSPF: Received packet for unknown vlink (ID %R, IP %I)", rid, sk->faddr);
return 1; return 1;
} }
@ -413,7 +409,7 @@ ospf_rx_hook(sock *sk, int size)
if (ifa->stub) /* This shouldn't happen */ if (ifa->stub) /* This shouldn't happen */
return 1; return 1;
if (ipa_equal(sk->laddr, AllDRouters) && (ifa->sk_dr == 0)) if (ipa_equal(sk->laddr, ifa->des_routers) && (ifa->sk_dr == 0))
return 1; return 1;
if (rid == po->router_id) if (rid == po->router_id)
@ -428,25 +424,22 @@ ospf_rx_hook(sock *sk, int size)
return 1; return 1;
} }
#ifdef OSPFv2
/* In OSPFv2, neighbors are identified by either IP or Router ID, base on network type */ /* In OSPFv2, neighbors are identified by either IP or Router ID, base on network type */
unsigned t = ifa->type;
struct ospf_neighbor *n; struct ospf_neighbor *n;
if ((ifa->type == OSPF_IT_BCAST) || (ifa->type == OSPF_IT_NBMA) || (ifa->type == OSPF_IT_PTMP)) if (ospf_is_v2(po) && ((t == OSPF_IT_BCAST) || (t == OSPF_IT_NBMA) || (t == OSPF_IT_PTMP)))
n = find_neigh_by_ip(ifa, sk->faddr); n = find_neigh_by_ip(ifa, sk->faddr);
else else
n = find_neigh(ifa, rid); n = find_neigh(ifa, rid);
#else
struct ospf_neighbor *n = find_neigh(ifa, rid);
#endif
if (!n && (ps->type != HELLO_P)) if (!n && (pkt->type != HELLO_P))
{ {
log(L_WARN "OSPF: Received non-hello packet from unknown neighbor (src %I, iface %s)", log(L_WARN "OSPF: Received non-hello packet from unknown neighbor (src %I, iface %s)",
sk->faddr, ifa->iface->name); sk->faddr, ifa->iface->name);
return 1; return 1;
} }
if (!ospf_pkt_checkauth(n, ifa, ps, size)) if (ospf_is_v2(po) && ! ospf_pkt_checkauth(n, ifa, pkt, size))
{ {
log(L_ERR "%s%I - authentication failed", mesg, sk->faddr); log(L_ERR "%s%I - authentication failed", mesg, sk->faddr);
return 1; return 1;
@ -454,36 +447,36 @@ ospf_rx_hook(sock *sk, int size)
/* Dump packet /* Dump packet
pu8=(u8 *)(sk->rbuf+5*4); pu8=(u8 *)(sk->rbuf+5*4);
for(i=0;i<ntohs(ps->length);i+=4) for(i=0;i<ntohs(pkt->length);i+=4)
DBG("%s: received %u,%u,%u,%u\n",p->name, pu8[i+0], pu8[i+1], pu8[i+2], DBG("%s: received %u,%u,%u,%u\n",p->name, pu8[i+0], pu8[i+1], pu8[i+2],
pu8[i+3]); pu8[i+3]);
DBG("%s: received size: %u\n",p->name,size); DBG("%s: received size: %u\n",p->name,size);
*/ */
switch (ps->type) switch (pkt->type)
{ {
case HELLO_P: case HELLO_P:
DBG("%s: Hello received.\n", p->name); DBG("%s: Hello received.\n", p->name);
ospf_hello_receive(ps, ifa, n, sk->faddr); ospf_hello_receive(pkt, 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(ps, ifa, n); ospf_dbdes_receive(pkt, 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(ps, ifa, n); ospf_lsreq_receive(pkt, 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(ps, ifa, n); ospf_lsupd_receive(pkt, 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(ps, ifa, n); ospf_lsack_receive(pkt, 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, pkt->type);
return 1; return 1;
}; };
return 1; return 1;
@ -505,6 +498,27 @@ ospf_err_hook(sock * sk, int err)
log(L_ERR "OSPF: Socket error on %s: %M", ifa->iface->name, err); log(L_ERR "OSPF: Socket error on %s: %M", ifa->iface->name, err);
} }
void
ospf_send_to(struct ospf_iface *ifa, ip_addr dst)
{
sock *sk = ifa->sk;
struct ospf_packet *pkt = (struct ospf_packet *) sk->tbuf;
int plen = ntohs(pkt->length);
if (sk->tbuf != sk->tpos)
log(L_ERR "Aiee, old packet was overwritten in TX buffer");
if (ospf_is_v2(ifa->oa->po))
{
if (ifa->autype == OSPF_AUTH_CRYPT)
plen += OSPF_AUTH_CRYPT_SIZE;
ospf_pkt_finalize(ifa, pkt);
}
sk_send_to(sk, plen, dst, 0);
}
void void
ospf_send_to_agt(struct ospf_iface *ifa, u8 state) ospf_send_to_agt(struct ospf_iface *ifa, u8 state)
{ {
@ -518,28 +532,8 @@ ospf_send_to_agt(struct ospf_iface *ifa, u8 state)
void void
ospf_send_to_bdr(struct ospf_iface *ifa) ospf_send_to_bdr(struct ospf_iface *ifa)
{ {
if (!ipa_equal(ifa->drip, IPA_NONE)) if (ipa_nonzero(ifa->drip))
ospf_send_to(ifa, ifa->drip); ospf_send_to(ifa, ifa->drip);
if (!ipa_equal(ifa->bdrip, IPA_NONE)) if (ipa_nonzero(ifa->bdrip))
ospf_send_to(ifa, ifa->bdrip); ospf_send_to(ifa, ifa->bdrip);
} }
void
ospf_send_to(struct ospf_iface *ifa, ip_addr dst)
{
sock *sk = ifa->sk;
struct ospf_packet *pkt = (struct ospf_packet *) sk->tbuf;
int len = ntohs(pkt->length);
#ifdef OSPFv2
if (ifa->autype == OSPF_AUTH_CRYPT)
len += OSPF_AUTH_CRYPT_SIZE;
#endif
ospf_pkt_finalize(ifa, pkt);
if (sk->tbuf != sk->tpos)
log(L_ERR "Aiee, old packet was overwritten in TX buffer");
sk_send_to(sk, len, dst, 0);
}

View File

@ -15,24 +15,32 @@ unsigned ospf_pkt_maxsize(struct ospf_iface *ifa);
int ospf_rx_hook(sock * sk, int size); int ospf_rx_hook(sock * sk, int size);
void ospf_tx_hook(sock * sk); void ospf_tx_hook(sock * sk);
void ospf_err_hook(sock * sk, int err); void ospf_err_hook(sock * sk, int err);
void ospf_send_to_agt(struct ospf_iface *ifa, u8 state);
void ospf_send_to_bdr(struct ospf_iface *ifa);
void ospf_send_to(struct ospf_iface *ifa, ip_addr ip); void ospf_send_to(struct ospf_iface *ifa, ip_addr ip);
static inline void ospf_send_to_all(struct ospf_iface *ifa) { ospf_send_to(ifa, ifa->all_routers); } void ospf_send_to_agt(struct ospf_iface *ifa, u8 state);
void ospf_send_to_bdr(struct ospf_iface *ifa);
static inline void ospf_send_to_all(struct ospf_iface *ifa)
{
ospf_send_to(ifa, ifa->all_routers);
}
static inline void ospf_send_to_des(struct ospf_iface *ifa)
{
if (ipa_nonzero(ifa->des_routers))
ospf_send_to(ifa, ifa->des_routers);
else
ospf_send_to_bdr(ifa);
}
static inline void * ospf_tx_buffer(struct ospf_iface *ifa) { return ifa->sk->tbuf; } static inline void * ospf_tx_buffer(struct ospf_iface *ifa) { return ifa->sk->tbuf; }
static inline unsigned static inline unsigned
ospf_pkt_bufsize(struct ospf_iface *ifa) ospf_pkt_bufsize(struct ospf_iface *ifa)
{ {
#ifdef OSPFv2 /* Reserve buffer space for authentication footer */
unsigned headers = (ifa->autype == OSPF_AUTH_CRYPT) ? OSPF_AUTH_CRYPT_SIZE : 0; return ifa->sk->tbsize -
#else (ifa->autype == OSPF_AUTH_CRYPT) ? OSPF_AUTH_CRYPT_SIZE : 0;
unsigned headers = 0;
#endif
return ifa->sk->tbsize - headers;
} }

View File

@ -15,12 +15,8 @@ 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) /* 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 address */ as index, so we need to encapsulate RID to IP address */
#ifdef OSPFv2
#define ipa_from_rid(x) _MI(x)
#else /* OSPFv3 */
#define ipa_from_rid(x) _MI6(0,0,0,x)
#endif
#define ipa_from_rid(x) ipa_from_u32(x)
static inline void reset_ri(ort *ort) static inline void reset_ri(ort *ort)
{ {
@ -311,7 +307,7 @@ spfa_process_rt(struct ospf_area *oa, struct top_hash_entry *act)
struct ospf_lsa_rt_walk rtl; struct ospf_lsa_rt_walk rtl;
struct top_hash_entry *tmp; struct top_hash_entry *tmp;
ip_addr prefix; ip_addr prefix;
int pxlen; int pxlen, i;
if (rt->options & OPT_RT_V) if (rt->options & OPT_RT_V)
oa->trcap = 1; oa->trcap = 1;
@ -339,8 +335,7 @@ spfa_process_rt(struct ospf_area *oa, struct top_hash_entry *act)
} }
/* Now process Rt links */ /* Now process Rt links */
lsa_walk_rt_init(po, act, &rtl); for (lsa_walk_rt_init(po, act, &rtl), i = 0; lsa_walk_rt(&rtl); i++)
while (lsa_walk_rt(&rtl))
{ {
tmp = NULL; tmp = NULL;

View File

@ -31,12 +31,11 @@ void flush_prefix_net_lsa(struct ospf_iface *ifa);
#endif #endif
#ifdef OSPFv2
static inline u32 static inline u32
fibnode_to_lsaid(struct proto_ospf *po, struct fib_node *fn) fibnode_to_lsaid(struct proto_ospf *po, struct fib_node *fn)
{ {
/* We have to map IP prefixes to u32 in such manner that resulting /* In OSPFv2, We have to map IP prefixes to u32 in such manner
u32 interpreted as IP address is a member of given that resulting u32 interpreted as IP address is a member of given
prefix. Therefore, /32 prefix have to be mapped on itself. prefix. Therefore, /32 prefix have to be mapped on itself.
All received prefixes have to be mapped on different u32s. All received prefixes have to be mapped on different u32s.
@ -63,7 +62,18 @@ fibnode_to_lsaid(struct proto_ospf *po, struct fib_node *fn)
possible to have both reliably and the suggested algorithm was possible to have both reliably and the suggested algorithm was
unnecessary complicated and it does crazy things like changing unnecessary complicated and it does crazy things like changing
LSA ID for a network because different network appeared, we LSA ID for a network because different network appeared, we
choose a different way. */ choose a different way.
In OSPFv3, it is simpler. There is not a requirement for
membership of the result in the input network, so we just use a
hash-based unique ID of a routing table entry for a route that
originated given LSA. For ext-LSA, it is an imported route in the
nest's routing table (p->table). For summary-LSA, it is a
'source' route in the protocol internal routing table (po->rtf).
*/
if (ospf_is_v3(po))
return fn->uid;
u32 id = _I(fn->prefix); u32 id = _I(fn->prefix);
@ -76,24 +86,6 @@ fibnode_to_lsaid(struct proto_ospf *po, struct fib_node *fn)
return id | ~u32_mkmask(fn->pxlen); return id | ~u32_mkmask(fn->pxlen);
} }
#else /* OSPFv3 */
static inline u32
fibnode_to_lsaid(struct proto_ospf *po, struct fib_node *fn)
{
/*
* In OSPFv3, it is simpler. There is not a requirement for
* membership of the result in the input network, so we just use a
* hash-based unique ID of a routing table entry for a route that
* originated given LSA. For ext-LSA, it is an imported route in the
* nest's routing table (p->table). For summary-LSA, it is a
* 'source' route in the protocol internal routing table (po->rtf).
*/
return fn->uid;
}
#endif
static void * static void *
lsab_alloc(struct proto_ospf *po, unsigned size) lsab_alloc(struct proto_ospf *po, unsigned size)
@ -1611,7 +1603,7 @@ ospf_top_rehash(struct top_graph *f, int step)
while (e) while (e)
{ {
x = e->next; x = e->next;
n = newt + ospf_top_hash(f, e->domain, e->lsa.id, e->lsa.rt, e->lsa.type); n = newt + ospf_top_hash(f, e->domain, e->lsa.id, e->lsa.rt, e->lsa_type);
e->next = *n; e->next = *n;
*n = e; *n = e;
e = x; e = x;
@ -1620,35 +1612,6 @@ ospf_top_rehash(struct top_graph *f, int step)
ospf_top_ht_free(oldt); ospf_top_ht_free(oldt);
} }
#ifdef OSPFv2
u32
ospf_lsa_domain(u32 type, struct ospf_iface *ifa)
{
return (type == LSA_T_EXT) ? 0 : ifa->oa->areaid;
}
#else /* OSPFv3 */
u32
ospf_lsa_domain(u32 type, struct ospf_iface *ifa)
{
switch (type & LSA_SCOPE_MASK)
{
case LSA_SCOPE_LINK:
return ifa->iface->index;
case LSA_SCOPE_AREA:
return ifa->oa->areaid;
case LSA_SCOPE_AS:
default:
return 0;
}
}
#endif
struct top_hash_entry * struct top_hash_entry *
ospf_hash_find_header(struct top_graph *f, u32 domain, struct ospf_lsa_header *h) ospf_hash_find_header(struct top_graph *f, u32 domain, struct ospf_lsa_header *h)
{ {
@ -1667,7 +1630,8 @@ ospf_hash_find(struct top_graph *f, u32 domain, u32 lsa, u32 rtr, u32 type)
struct top_hash_entry *e; struct top_hash_entry *e;
e = f->hash_table[ospf_top_hash(f, domain, lsa, rtr, type)]; e = f->hash_table[ospf_top_hash(f, domain, lsa, rtr, type)];
while (e && (e->lsa.id != lsa || e->lsa.type != type || e->lsa.rt != rtr || e->domain != domain)) while (e && (e->lsa.id != lsa || e->lsa.rt != rtr ||
e->lsa_type != type || e->domain != domain))
e = e->next; e = e->next;
return e; return e;
@ -1749,7 +1713,8 @@ ospf_hash_get(struct top_graph *f, u32 domain, u32 lsa, u32 rtr, u32 type)
ee = f->hash_table + ospf_top_hash(f, domain, lsa, rtr, type); ee = f->hash_table + ospf_top_hash(f, domain, lsa, rtr, type);
e = *ee; e = *ee;
while (e && (e->lsa.id != lsa || e->lsa.rt != rtr || e->lsa.type != type || e->domain != domain)) while (e && (e->lsa.id != lsa || e->lsa.rt != rtr ||
e->lsa_type != type || e->domain != domain))
e = e->next; e = e->next;
if (e) if (e)
@ -1762,8 +1727,9 @@ ospf_hash_get(struct top_graph *f, u32 domain, u32 lsa, u32 rtr, u32 type)
e->lb = IPA_NONE; e->lb = IPA_NONE;
e->lsa.id = lsa; e->lsa.id = lsa;
e->lsa.rt = rtr; e->lsa.rt = rtr;
e->lsa.type = type; e->lsa.type = type;
e->lsa_body = NULL; e->lsa_body = NULL;
e->lsa_type = type;
e->domain = domain; e->domain = domain;
e->next = *ee; e->next = *ee;
*ee = e; *ee = e;
@ -1776,7 +1742,7 @@ void
ospf_hash_delete(struct top_graph *f, struct top_hash_entry *e) ospf_hash_delete(struct top_graph *f, struct top_hash_entry *e)
{ {
struct top_hash_entry **ee = f->hash_table + struct top_hash_entry **ee = f->hash_table +
ospf_top_hash(f, e->domain, e->lsa.id, e->lsa.rt, e->lsa.type); ospf_top_hash(f, e->domain, e->lsa.id, e->lsa.rt, e->lsa_type);
while (*ee) while (*ee)
{ {

View File

@ -23,9 +23,7 @@ struct top_hash_entry
bird_clock_t inst_t; /* Time of installation into DB */ bird_clock_t inst_t; /* Time of installation into DB */
struct mpnh *nhs; /* Computed nexthops - valid only in ospf_rt_spf() */ struct mpnh *nhs; /* Computed nexthops - valid only in ospf_rt_spf() */
ip_addr lb; /* In OSPFv2, link back address. In OSPFv3, any global address in the area useful for vlinks */ ip_addr lb; /* In OSPFv2, link back address. In OSPFv3, any global address in the area useful for vlinks */
#ifdef OSPFv3
u32 lb_id; /* Interface ID of link back iface (for bcast or NBMA networks) */ u32 lb_id; /* Interface ID of link back iface (for bcast or NBMA networks) */
#endif
u32 dist; /* Distance from the root */ u32 dist; /* Distance from the root */
u16 ini_age; u16 ini_age;
u8 color; u8 color;
@ -51,16 +49,14 @@ 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 *);
u32 ospf_lsa_domain(u32 type, struct ospf_iface *ifa);
struct top_hash_entry *ospf_hash_find_header(struct top_graph *f, u32 domain, struct top_hash_entry *ospf_hash_find_header(struct top_graph *f, u32 domain,
struct ospf_lsa_header *h); struct ospf_lsa_header *h);
struct top_hash_entry *ospf_hash_get_header(struct top_graph *f, u32 domain, struct top_hash_entry *ospf_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 domain, u32 lsa, u32 rtr, struct top_hash_entry *ospf_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 *, u32 domain, u32 lsa, u32 rtr, u32 type);
struct top_hash_entry *ospf_hash_get(struct top_graph *, u32 domain, u32 lsa, u32 rtr,
u32 type);
void ospf_hash_delete(struct top_graph *, struct top_hash_entry *); void 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);
void update_rt_lsa(struct ospf_area *oa); void update_rt_lsa(struct ospf_area *oa);