summaryrefslogtreecommitdiff
path: root/proto/ospf/lsupd.c
diff options
context:
space:
mode:
authorOndrej Zajicek <santiago@crfreenet.org>2014-11-03 10:42:55 +0100
committerOndrej Zajicek <santiago@crfreenet.org>2014-11-03 10:42:55 +0100
commit6f8bbaa10bbd21729d0b62a5878febcbee2c0811 (patch)
tree5b20f464388a529084e53b24406b99df2210264d /proto/ospf/lsupd.c
parent88a183c6c9a2b86b52f67e87bbc8b7edd32670c6 (diff)
Fininshing integrated OSPF.
Diffstat (limited to 'proto/ospf/lsupd.c')
-rw-r--r--proto/ospf/lsupd.c232
1 files changed, 162 insertions, 70 deletions
diff --git a/proto/ospf/lsupd.c b/proto/ospf/lsupd.c
index 0aa45f6a..ea32923a 100644
--- a/proto/ospf/lsupd.c
+++ b/proto/ospf/lsupd.c
@@ -32,8 +32,8 @@ ospf_dump_lsahdr(struct ospf_proto *p, struct ospf_lsa_header *lsa_n)
lsa_ntoh_hdr(lsa_n, &lsa);
lsa_etype = lsa_get_etype(&lsa, p);
- log(L_TRACE "%s: LSA Type: %04x, Id: %R, Rt: %R, Age: %u, Seq: %08x, Sum: %04x",
- p->p.name, lsa_etype, lsa.id, lsa.rt, lsa.age, lsa.sn, lsa.checksum);
+ log(L_TRACE "%s: LSA Type: %04x, Id: %R, Rt: %R, Seq: %08x, Age: %u, Sum: %04x",
+ p->p.name, lsa_etype, lsa.id, lsa.rt, lsa.sn, lsa.age, lsa.checksum);
}
void
@@ -65,46 +65,64 @@ ospf_lsupd_set_lsa_count(struct ospf_packet *pkt, uint hdrlen, u32 val)
static inline void
ospf_lsupd_body(struct ospf_proto *p, struct ospf_packet *pkt,
- uint *offset, uint *bound, uint *lsa_count)
+ uint *offset, uint *lsa_count)
{
uint hlen = ospf_lsupd_hdrlen(p);
*offset = hlen;
- *bound = ntohs(pkt->length) - sizeof(struct ospf_lsa_header);
*lsa_count = ospf_lsupd_get_lsa_count(pkt, hlen);
}
static void
ospf_dump_lsupd(struct ospf_proto *p, struct ospf_packet *pkt)
{
- uint offset, bound, i, lsa_count, lsalen;
+ uint offset, plen, i, lsa_count, lsa_len;
ASSERT(pkt->type == LSUPD_P);
ospf_dump_common(p, pkt);
- ospf_lsupd_body(p, pkt, &offset, &bound, &lsa_count);
+ plen = ntohs(pkt->length);
+ ospf_lsupd_body(p, pkt, &offset, &lsa_count);
for (i = 0; i < lsa_count; i++)
{
- if (offset > bound)
- {
- log(L_TRACE "%s: LSA invalid", p->p.name);
- return;
- }
+ if ((offset + sizeof(struct ospf_lsa_header)) > plen)
+ goto invalid;
struct ospf_lsa_header *lsa = ((void *) pkt) + offset;
- ospf_dump_lsahdr(p, lsa);
- lsalen = ntohs(lsa->length);
- offset += lsalen;
+ lsa_len = ntohs(lsa->length);
- if (((lsalen % 4) != 0) || (lsalen <= sizeof(struct ospf_lsa_header)))
- {
- log(L_TRACE "%s: LSA invalid", p->p.name);
- return;
- }
+ if (((lsa_len % 4) != 0) || (lsa_len <= sizeof(struct ospf_lsa_header)))
+ goto invalid;
+
+ ospf_dump_lsahdr(p, lsa);
+ offset += lsa_len;
}
+ return;
+
+invalid:
+ log(L_TRACE "%s: LSA invalid", p->p.name);
+ return;
}
static inline void
+ospf_lsa_lsrq_down(struct top_hash_entry *req, struct ospf_neighbor *n, struct ospf_neighbor *from)
+{
+ if (req == n->lsrqi)
+ n->lsrqi = SNODE_NEXT(req);
+
+ s_rem_node(SNODE req);
+ ospf_hash_delete(n->lsrqh, req);
+
+ if (EMPTY_SLIST(n->lsrql))
+ {
+ tm_stop(n->lsrq_timer);
+
+ if (n->state == NEIGHBOR_LOADING)
+ ospf_neigh_sm(n, INM_LOADDONE);
+ }
+}
+
+static inline void
ospf_lsa_lsrt_up(struct top_hash_entry *en, struct ospf_neighbor *n)
{
struct top_hash_entry *ret = ospf_hash_get_entry(n->lsrth, en);
@@ -117,6 +135,22 @@ ospf_lsa_lsrt_up(struct top_hash_entry *en, struct ospf_neighbor *n)
ret->lsa = en->lsa;
ret->lsa_body = LSA_BODY_DUMMY;
+
+ if (!tm_active(n->lsrt_timer))
+ tm_start(n->lsrt_timer, n->ifa->rxmtint);
+}
+
+void
+ospf_lsa_lsrt_down_(struct top_hash_entry *en, struct ospf_neighbor *n, struct top_hash_entry *ret)
+{
+ if (en)
+ en->ret_count--;
+
+ s_rem_node(SNODE ret);
+ ospf_hash_delete(n->lsrth, ret);
+
+ if (EMPTY_SLIST(n->lsrtl))
+ tm_stop(n->lsrt_timer);
}
static inline int
@@ -125,14 +159,9 @@ ospf_lsa_lsrt_down(struct top_hash_entry *en, struct ospf_neighbor *n)
struct top_hash_entry *ret = ospf_hash_find_entry(n->lsrth, en);
if (ret)
- {
- en->ret_count--;
- s_rem_node(SNODE ret);
- ospf_hash_delete(n->lsrth, ret);
- return 1;
- }
+ ospf_lsa_lsrt_down_(en, n, ret);
- return 0;
+ return ret != NULL;
}
void
@@ -144,10 +173,61 @@ ospf_add_flushed_to_lsrt(struct ospf_proto *p, struct ospf_neighbor *n)
if ((en->lsa.age == LSA_MAXAGE) && (en->lsa_body != NULL) &&
lsa_flooding_allowed(en->lsa_type, en->domain, n->ifa))
ospf_lsa_lsrt_up(en, n);
+
+ /* If we found any flushed LSA, we send them ASAP */
+ if (tm_active(n->lsrt_timer))
+ tm_start(n->lsrt_timer, 0);
}
+static int ospf_flood_lsupd(struct ospf_proto *p, struct top_hash_entry **lsa_list, uint lsa_count, uint lsa_min_count, struct ospf_iface *ifa);
+
+static void
+ospf_enqueue_lsa(struct ospf_proto *p, struct top_hash_entry *en, struct ospf_iface *ifa)
+{
+ if (ifa->flood_queue_used == ifa->flood_queue_size)
+ {
+ /* If we already have full queue, we send some packets */
+ uint sent = ospf_flood_lsupd(p, ifa->flood_queue, ifa->flood_queue_used, ifa->flood_queue_used / 2, ifa);
+ int i;
+
+ for (i = 0; i < sent; i++)
+ ifa->flood_queue[i]->ret_count--;
-static void ospf_send_lsupd_to_ifa(struct ospf_proto *p, struct top_hash_entry *en, struct ospf_iface *ifa);
+ ifa->flood_queue_used -= sent;
+ memmove(ifa->flood_queue, ifa->flood_queue + sent, ifa->flood_queue_used * sizeof(void *));
+ bzero(ifa->flood_queue + ifa->flood_queue_used, sent * sizeof(void *));
+ }
+
+ en->ret_count++;
+ ifa->flood_queue[ifa->flood_queue_used] = en;
+ ifa->flood_queue_used++;
+
+ if (!ev_active(p->flood_event))
+ ev_schedule(p->flood_event);
+}
+
+void
+ospf_flood_event(void *ptr)
+{
+ struct ospf_proto *p = ptr;
+ struct ospf_iface *ifa;
+ int i, count;
+
+ WALK_LIST(ifa, p->iface_list)
+ {
+ if (ifa->flood_queue_used == 0)
+ continue;
+
+ count = ifa->flood_queue_used;
+ ospf_flood_lsupd(p, ifa->flood_queue, count, count, ifa);
+
+ for (i = 0; i < count; i++)
+ ifa->flood_queue[i]->ret_count--;
+
+ ifa->flood_queue_used = 0;
+ bzero(ifa->flood_queue, count * sizeof(void *));
+ }
+}
/**
@@ -195,14 +275,7 @@ ospf_flood_lsa(struct ospf_proto *p, struct top_hash_entry *en, struct ospf_neig
/* If same or newer, remove LSA from the link state request list */
if (cmp > CMP_OLDER)
- {
- s_rem_node(SNODE req);
- ospf_hash_delete(n->lsrqh, req);
- n->want_lsreq = 1;
-
- if ((EMPTY_SLIST(n->lsrql)) && (n->state == NEIGHBOR_LOADING))
- ospf_neigh_sm(n, INM_LOADDONE);
- }
+ ospf_lsa_lsrq_down(req, n, from);
/* If older or same, skip processing of this neighbor */
if (cmp < CMP_NEWER)
@@ -242,7 +315,7 @@ ospf_flood_lsa(struct ospf_proto *p, struct top_hash_entry *en, struct ospf_neig
}
/* 13.3 (5) - finally flood the packet */
- ospf_send_lsupd_to_ifa(p, en, ifa);
+ ospf_enqueue_lsa(p, en, ifa);
}
return back;
@@ -302,26 +375,33 @@ ospf_prepare_lsupd(struct ospf_proto *p, struct ospf_iface *ifa,
}
-static void
-ospf_send_lsupd_to_ifa(struct ospf_proto *p, struct top_hash_entry *en, struct ospf_iface *ifa)
+static int
+ospf_flood_lsupd(struct ospf_proto *p, struct top_hash_entry **lsa_list, uint lsa_count, uint lsa_min_count, struct ospf_iface *ifa)
{
- uint c = ospf_prepare_lsupd(p, ifa, &en, 1);
+ uint i, c;
- if (!c) /* Too large LSA */
- return;
+ for (i = 0; i < lsa_min_count; i += c)
+ {
+ c = ospf_prepare_lsupd(p, ifa, lsa_list + i, lsa_count - i);
- OSPF_PACKET(ospf_dump_lsupd, ospf_tx_buffer(ifa),
- "LSUPD packet flooded via %s", ifa->ifname);
+ if (!c) /* Too large LSA */
+ { i++; continue; }
- if (ifa->type == OSPF_IT_BCAST)
- {
- if ((ifa->state == OSPF_IS_DR) || (ifa->state == OSPF_IS_BACKUP))
- ospf_send_to_all(ifa);
+ OSPF_PACKET(ospf_dump_lsupd, ospf_tx_buffer(ifa),
+ "LSUPD packet flooded via %s", ifa->ifname);
+
+ if (ifa->type == OSPF_IT_BCAST)
+ {
+ if ((ifa->state == OSPF_IS_DR) || (ifa->state == OSPF_IS_BACKUP))
+ ospf_send_to_all(ifa);
+ else
+ ospf_send_to_des(ifa);
+ }
else
- ospf_send_to_des(ifa);
+ ospf_send_to_agt(ifa, NEIGHBOR_EXCHANGE);
}
- else
- ospf_send_to_agt(ifa, NEIGHBOR_EXCHANGE);
+
+ return i;
}
int
@@ -343,17 +423,19 @@ ospf_send_lsupd(struct ospf_proto *p, struct top_hash_entry **lsa_list, uint lsa
ospf_send_to(ifa, n->ip);
}
- return lsa_count;
+ return i;
}
void
ospf_rxmt_lsupd(struct ospf_proto *p, struct ospf_neighbor *n)
{
- const uint max = 128;
+ uint max = 2 * n->ifa->flood_queue_size;
struct top_hash_entry *entries[max];
struct top_hash_entry *ret, *nxt, *en;
uint i = 0;
+ /* ASSERT((n->state >= NEIGHBOR_EXCHANGE) && !EMPTY_SLIST(n->lsrtl)); */
+
WALK_SLIST_DELSAFE(ret, nxt, n->lsrtl)
{
if (i == max)
@@ -398,14 +480,15 @@ ospf_receive_lsupd(struct ospf_packet *pkt, struct ospf_iface *ifa,
struct ospf_proto *p = ifa->oa->po;
const char *err_dsc = NULL;
uint plen, err_val = 0;
- int skip_lsreq = 0;
- n->want_lsreq = 0;
/* RFC 2328 13. */
plen = ntohs(pkt->length);
- if (plen < (ospf_lsupd_hdrlen(p) + sizeof(struct ospf_lsa_header)))
- DROP("too short", plen);
+ if (plen < ospf_lsupd_hdrlen(p))
+ {
+ LOG_PKT("Bad LSUPD packet from nbr %R on %s - %s (%u)", n->rid, ifa->ifname, "too short", plen);
+ return;
+ }
OSPF_PACKET(ospf_dump_lsupd, pkt, "LSUPD packet received from nbr %R on %s", n->rid, ifa->ifname);
@@ -417,8 +500,8 @@ ospf_receive_lsupd(struct ospf_packet *pkt, struct ospf_iface *ifa,
ospf_neigh_sm(n, INM_HELLOREC); /* Questionable */
- uint offset, bound, i, lsa_count;
- ospf_lsupd_body(p, pkt, &offset, &bound, &lsa_count);
+ uint offset, i, lsa_count;
+ ospf_lsupd_body(p, pkt, &offset, &lsa_count);
for (i = 0; i < lsa_count; i++)
{
@@ -426,7 +509,7 @@ ospf_receive_lsupd(struct ospf_packet *pkt, struct ospf_iface *ifa,
struct top_hash_entry *en;
u32 lsa_len, lsa_type, lsa_domain;
- if (offset > bound)
+ if ((offset + sizeof(struct ospf_lsa_header)) > plen)
DROP("too short", plen);
/* LSA header in network order */
@@ -492,7 +575,6 @@ ospf_receive_lsupd(struct ospf_packet *pkt, struct ospf_iface *ifa,
if (en && ((now - en->inst_time) < MINLSARRIVAL))
{
OSPF_TRACE(D_EVENTS, "Skipping LSA received in less that MinLSArrival");
- skip_lsreq = 1;
continue;
}
@@ -559,7 +641,9 @@ ospf_receive_lsupd(struct ospf_packet *pkt, struct ospf_iface *ifa,
continue;
}
- /* FIXME pg145 (6) */
+ /* 13. (6) - received LSA is in Link state request list (but not newer) */
+ if (ospf_hash_find_entry(n->lsrqh, en) != NULL)
+ DROP1("error in LSA database exchange");
/* 13. (7) - received LSA is same */
if (lsa_comp(&lsa, &en->lsa) == CMP_SAME)
@@ -576,7 +660,6 @@ ospf_receive_lsupd(struct ospf_packet *pkt, struct ospf_iface *ifa,
else
ospf_enqueue_lsack(n, lsa_n, ACKL_DIRECT);
- skip_lsreq = 1;
continue;
}
@@ -601,15 +684,24 @@ ospf_receive_lsupd(struct ospf_packet *pkt, struct ospf_iface *ifa,
/* Send direct LSACKs */
ospf_send_lsack(p, n, ACKL_DIRECT);
+ /* Send enqueued LSAs immediately, do not wait for flood_event */
+ if (ev_active(p->flood_event))
+ {
+ ev_postpone(p->flood_event);
+ ospf_flood_event(p);
+ }
+
/*
- * In loading state, we should ask for another batch of LSAs. This is only
- * vaguely mentioned in RFC 2328. We send a new LSREQ only if the current
- * LSUPD actually removed some entries from LSA request list (want_lsreq) and
- * did not contain duplicate or early LSAs (skip_lsreq). The first condition
- * prevents endless floods, the second condition helps with flow control.
+ * During loading, we should ask for another batch of LSAs. This is only
+ * vaguely mentioned in RFC 2328. We send a new LSREQ if all requests sent in
+ * the last packet were already answered and/or removed from the LS request
+ * list and therefore lsrqi is pointing to the first node of the list.
*/
- if ((n->state == NEIGHBOR_LOADING) && n->want_lsreq && !skip_lsreq)
+ if (!EMPTY_SLIST(n->lsrql) && (n->lsrqi == SHEAD(n->lsrql)))
+ {
ospf_send_lsreq(p, n);
+ tm_start(n->lsrq_timer, n->ifa->rxmtint);
+ }
return;
@@ -617,7 +709,7 @@ drop:
LOG_PKT("Bad LSUPD packet from nbr %R on %s - %s (%u)",
n->rid, ifa->ifname, err_dsc, err_val);
- // XXXX realy?
- ospf_neigh_sm(n, INM_SEQMIS);
+ /* Malformed LSUPD - there is no defined error event, we abuse BadLSReq */
+ ospf_neigh_sm(n, INM_BADLSREQ);
return;
}