Fixes a bug in LSA update of large LSAs.
This commit is contained in:
parent
d3209d939d
commit
d5356072ac
6 changed files with 81 additions and 62 deletions
|
@ -33,10 +33,10 @@ typedef struct list { /* In fact two overlayed nodes */
|
||||||
#define NODE (node *)
|
#define NODE (node *)
|
||||||
#define HEAD(list) ((void *)((list).head))
|
#define HEAD(list) ((void *)((list).head))
|
||||||
#define TAIL(list) ((void *)((list).tail))
|
#define TAIL(list) ((void *)((list).tail))
|
||||||
#define WALK_LIST(n,list) for(n=HEAD(list);(NODE (n))->next; \
|
#define NODE_NEXT(n) ((void *)((NODE (n))->next))
|
||||||
n=(void *)((NODE (n))->next))
|
#define WALK_LIST(n,list) for(n=HEAD(list);(NODE (n))->next; n=NODE_NEXT(n))
|
||||||
#define WALK_LIST_DELSAFE(n,nxt,list) \
|
#define WALK_LIST_DELSAFE(n,nxt,list) \
|
||||||
for(n=HEAD(list); nxt=(void *)((NODE (n))->next); n=(void *) nxt)
|
for(n=HEAD(list); nxt=NODE_NEXT(n); n=(void *) nxt)
|
||||||
/* WALK_LIST_FIRST supposes that called code removes each processed node */
|
/* WALK_LIST_FIRST supposes that called code removes each processed node */
|
||||||
#define WALK_LIST_FIRST(n,list) \
|
#define WALK_LIST_FIRST(n,list) \
|
||||||
while(n=HEAD(list), (NODE (n))->next)
|
while(n=HEAD(list), (NODE (n))->next)
|
||||||
|
|
|
@ -297,7 +297,7 @@ ospf_hello_send(timer *timer, int poll, struct ospf_neighbor *dirn)
|
||||||
pp = (u32 *) (((u8 *) pkt) + sizeof(struct ospf_hello_packet));
|
pp = (u32 *) (((u8 *) pkt) + sizeof(struct ospf_hello_packet));
|
||||||
WALK_LIST(neigh, ifa->neigh_list)
|
WALK_LIST(neigh, ifa->neigh_list)
|
||||||
{
|
{
|
||||||
if ((i+1) * sizeof(u32) + sizeof(struct ospf_hello_packet) > ospf_pkt_maxsize(ifa))
|
if ((i+1) * sizeof(u32) + sizeof(struct ospf_hello_packet) > ospf_pkt_bufsize(ifa))
|
||||||
{
|
{
|
||||||
OSPF_TRACE(D_PACKETS, "Too many neighbors on the interface!");
|
OSPF_TRACE(D_PACKETS, "Too many neighbors on the interface!");
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -330,67 +330,74 @@ 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, list * l)
|
||||||
{
|
{
|
||||||
struct l_lsr_head *llsh;
|
|
||||||
u16 len;
|
|
||||||
u32 lsano;
|
|
||||||
struct top_hash_entry *en;
|
|
||||||
struct ospf_lsupd_packet *pk;
|
|
||||||
struct ospf_packet *op;
|
|
||||||
struct ospf_area *oa = n->ifa->oa;
|
struct ospf_area *oa = n->ifa->oa;
|
||||||
struct proto_ospf *po = oa->po;
|
struct proto *p = &oa->po->proto;
|
||||||
struct proto *p = &po->proto;
|
struct l_lsr_head *lsr;
|
||||||
void *pktpos;
|
struct top_hash_entry *en;
|
||||||
|
struct ospf_lsupd_packet *pkt;
|
||||||
|
u32 len, len2, lsano;
|
||||||
|
char *buf;
|
||||||
|
|
||||||
if (EMPTY_LIST(*l))
|
pkt = ospf_tx_buffer(n->ifa);
|
||||||
return;
|
buf = (void *) pkt;
|
||||||
|
|
||||||
DBG("LSupd: 1st packet\n");
|
lsr = HEAD(*l);
|
||||||
|
while(NODE_NEXT(lsr))
|
||||||
pk= ospf_tx_buffer(n->ifa);
|
|
||||||
op = &pk->ospf_packet;
|
|
||||||
|
|
||||||
ospf_pkt_fill_hdr(n->ifa, pk, LSUPD_P);
|
|
||||||
len = sizeof(struct ospf_lsupd_packet);
|
|
||||||
lsano = 0;
|
|
||||||
pktpos = (pk + 1);
|
|
||||||
|
|
||||||
WALK_LIST(llsh, *l)
|
|
||||||
{
|
{
|
||||||
u32 domain = ospf_lsa_domain(llsh->lsh.type, n->ifa);
|
/* Prepare the packet */
|
||||||
if ((en = ospf_hash_find(po->gr, domain, llsh->lsh.id,
|
ospf_pkt_fill_hdr(n->ifa, pkt, LSUPD_P);
|
||||||
llsh->lsh.rt, llsh->lsh.type)) == NULL)
|
len = sizeof(struct ospf_lsupd_packet);
|
||||||
continue; /* Probably flushed LSA */
|
lsano = 0;
|
||||||
/* FIXME This is a bug! I cannot flush LSA that is in lsrt */
|
|
||||||
|
|
||||||
DBG("Sending LSA: Type=%u, ID=%R, RT=%R, SN: 0x%x, Age: %u\n",
|
/* Fill the packet with LSAs */
|
||||||
llsh->lsh.type, llsh->lsh.id, llsh->lsh.rt, en->lsa.sn, en->lsa.age);
|
while(NODE_NEXT(lsr))
|
||||||
if (((u32) (len + en->lsa.length)) > ospf_pkt_maxsize(n->ifa))
|
|
||||||
{
|
{
|
||||||
pk->lsano = htonl(lsano);
|
u32 domain = ospf_lsa_domain(lsr->lsh.type, n->ifa);
|
||||||
op->length = htons(len);
|
en = ospf_hash_find(oa->po->gr, domain, lsr->lsh.id, lsr->lsh.rt, lsr->lsh.type);
|
||||||
|
if (en == NULL)
|
||||||
|
{
|
||||||
|
/* Probably flushed LSA, this should not happen */
|
||||||
|
log(L_WARN "OSPF: LSA disappeared (Type: %04x, Id: %R, Rt: %R)",
|
||||||
|
lsr->lsh.type, lsr->lsh.id, lsr->lsh.rt);
|
||||||
|
lsr = NODE_NEXT(lsr);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
OSPF_PACKET(ospf_dump_lsupd, pk, "LSUPD packet sent to %I via %s", n->ip, n->ifa->iface->name);
|
len2 = len + en->lsa.length;
|
||||||
ospf_send_to(n->ifa, n->ip);
|
if (len2 > ospf_pkt_maxsize(n->ifa))
|
||||||
|
{
|
||||||
|
/* The packet if full, stop adding LSAs and sent it */
|
||||||
|
if (lsano > 0)
|
||||||
|
break;
|
||||||
|
|
||||||
DBG("LSupd: next packet\n");
|
/* LSA is larger than MTU, check buffer size */
|
||||||
ospf_pkt_fill_hdr(n->ifa, pk, LSUPD_P);
|
if (len2 > ospf_pkt_bufsize(n->ifa))
|
||||||
len = sizeof(struct ospf_lsupd_packet);
|
{
|
||||||
lsano = 0;
|
/* Cannot fit in a tx buffer, skip that */
|
||||||
pktpos = (pk + 1);
|
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 = NODE_NEXT(lsr);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Copy the LSA to the packet */
|
||||||
|
htonlsah(&(en->lsa), (struct ospf_lsa_header *) (buf + len));
|
||||||
|
htonlsab(en->lsa_body, buf + len + sizeof(struct ospf_lsa_header),
|
||||||
|
en->lsa.length - sizeof(struct ospf_lsa_header));
|
||||||
|
len = len2;
|
||||||
|
lsano++;
|
||||||
|
lsr = NODE_NEXT(lsr);
|
||||||
}
|
}
|
||||||
htonlsah(&(en->lsa), pktpos);
|
|
||||||
pktpos = pktpos + sizeof(struct ospf_lsa_header);
|
|
||||||
htonlsab(en->lsa_body, pktpos, en->lsa.length - sizeof(struct ospf_lsa_header));
|
|
||||||
pktpos = pktpos + en->lsa.length - sizeof(struct ospf_lsa_header);
|
|
||||||
len += en->lsa.length;
|
|
||||||
lsano++;
|
|
||||||
}
|
|
||||||
if (lsano > 0)
|
|
||||||
{
|
|
||||||
pk->lsano = htonl(lsano);
|
|
||||||
op->length = htons(len);
|
|
||||||
|
|
||||||
OSPF_PACKET(ospf_dump_lsupd, pk, "LSUPD packet sent to %I via %s", n->ip, n->ifa->iface->name);
|
if (lsano == 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
/* Send the packet */
|
||||||
|
pkt->lsano = htonl(lsano);
|
||||||
|
pkt->ospf_packet.length = htons(len);
|
||||||
|
OSPF_PACKET(ospf_dump_lsupd, pkt, "LSUPD packet sent to %I via %s",
|
||||||
|
n->ip, n->ifa->iface->name);
|
||||||
ospf_send_to(n->ifa, n->ip);
|
ospf_send_to(n->ifa, n->ip);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,7 +10,6 @@
|
||||||
#define _BIRD_OSPF_H_
|
#define _BIRD_OSPF_H_
|
||||||
|
|
||||||
#define MAXNETS 10
|
#define MAXNETS 10
|
||||||
#define OSPF_VLINK_MTU 576 /* RFC2328 - A.1 */
|
|
||||||
#define OSPF_MAX_PKT_SIZE 65536
|
#define OSPF_MAX_PKT_SIZE 65536
|
||||||
/*
|
/*
|
||||||
* RFC 2328 says, maximum packet size is 65535
|
* RFC 2328 says, maximum packet size is 65535
|
||||||
|
@ -53,11 +52,13 @@ do { if ((p->debug & D_PACKETS) || OSPF_FORCE_DEBUG) \
|
||||||
#ifndef IPV6
|
#ifndef IPV6
|
||||||
#define OSPFv2 1
|
#define OSPFv2 1
|
||||||
#define OSPF_VERSION 2
|
#define OSPF_VERSION 2
|
||||||
|
#define OSPF_VLINK_MTU 576 /* RFC 2328 A.1 */
|
||||||
#define AllSPFRouters ipa_from_u32(0xe0000005) /* 224.0.0.5 */
|
#define AllSPFRouters ipa_from_u32(0xe0000005) /* 224.0.0.5 */
|
||||||
#define AllDRouters ipa_from_u32(0xe0000006) /* 224.0.0.6 */
|
#define AllDRouters ipa_from_u32(0xe0000006) /* 224.0.0.6 */
|
||||||
#else
|
#else
|
||||||
#define OSPFv3 1
|
#define OSPFv3 1
|
||||||
#define OSPF_VERSION 3
|
#define OSPF_VERSION 3
|
||||||
|
#define OSPF_VLINK_MTU 1280 /* RFC 5340 A.1 */
|
||||||
#define AllSPFRouters _MI(0xFF020000, 0, 0, 5) /* FF02::5 */
|
#define AllSPFRouters _MI(0xFF020000, 0, 0, 5) /* FF02::5 */
|
||||||
#define AllDRouters _MI(0xFF020000, 0, 0, 6) /* FF02::6 */
|
#define AllDRouters _MI(0xFF020000, 0, 0, 6) /* FF02::6 */
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -39,19 +39,17 @@ ospf_pkt_fill_hdr(struct ospf_iface *ifa, void *buf, u8 h_type)
|
||||||
unsigned
|
unsigned
|
||||||
ospf_pkt_maxsize(struct ospf_iface *ifa)
|
ospf_pkt_maxsize(struct ospf_iface *ifa)
|
||||||
{
|
{
|
||||||
/* For virtual links use mtu=576, can be mtu < 576? */
|
|
||||||
unsigned mtu = (ifa->type == OSPF_IT_VLINK) ? OSPF_VLINK_MTU : ifa->iface->mtu;
|
unsigned mtu = (ifa->type == OSPF_IT_VLINK) ? OSPF_VLINK_MTU : ifa->iface->mtu;
|
||||||
unsigned add = 0;
|
unsigned headers = SIZE_OF_IP_HEADER;
|
||||||
|
|
||||||
#ifdef OSPFv2
|
#ifdef OSPFv2
|
||||||
add = ((ifa->autype == OSPF_AUTH_CRYPT) ? OSPF_AUTH_CRYPT_SIZE : 0);
|
if (ifa->autype == OSPF_AUTH_CRYPT)
|
||||||
|
headers += OSPF_AUTH_CRYPT_SIZE;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return ((mtu <= ifa->iface->mtu) ? mtu : ifa->iface->mtu) -
|
return mtu - headers;
|
||||||
SIZE_OF_IP_HEADER - add;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#ifdef OSPFv2
|
#ifdef OSPFv2
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
|
|
@ -21,4 +21,17 @@ void ospf_send_to(struct ospf_iface *ifa, ip_addr ip);
|
||||||
|
|
||||||
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
|
||||||
|
ospf_pkt_bufsize(struct ospf_iface *ifa)
|
||||||
|
{
|
||||||
|
#ifdef OSPFv2
|
||||||
|
unsigned headers = (ifa->autype == OSPF_AUTH_CRYPT) ? OSPF_AUTH_CRYPT_SIZE : 0;
|
||||||
|
#else
|
||||||
|
unsigned headers = 0;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return ifa->sk->tbsize - headers;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
#endif /* _BIRD_OSPF_PACKET_H_ */
|
#endif /* _BIRD_OSPF_PACKET_H_ */
|
||||||
|
|
Loading…
Reference in a new issue