summaryrefslogtreecommitdiff
path: root/proto/ospf/lsupd.c
diff options
context:
space:
mode:
Diffstat (limited to 'proto/ospf/lsupd.c')
-rw-r--r--proto/ospf/lsupd.c88
1 files changed, 57 insertions, 31 deletions
diff --git a/proto/ospf/lsupd.c b/proto/ospf/lsupd.c
index b0bf21cd..37c89a24 100644
--- a/proto/ospf/lsupd.c
+++ b/proto/ospf/lsupd.c
@@ -115,7 +115,8 @@ ospf_lsa_lsrt_up(struct top_hash_entry *en, struct ospf_neighbor *n)
s_add_tail(&n->lsrtl, SNODE ret);
}
- memcpy(&ret->lsa, &en->lsa, sizeof(struct ospf_lsa_header));
+ ret->lsa = en->lsa;
+ ret->lsa_body = LSA_BODY_DUMMY;
}
static inline int
@@ -134,25 +135,37 @@ ospf_lsa_lsrt_down(struct top_hash_entry *en, struct ospf_neighbor *n)
return 0;
}
+void
+ospf_add_flushed_to_lsrt(struct ospf_proto *p, struct ospf_neighbor *n)
+{
+ struct top_hash_entry *en;
+
+ WALK_SLIST(en, p->lsal)
+ 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);
+}
+
-static void ospf_lsupd_flood_ifa(struct ospf_proto *p, struct ospf_iface *ifa, struct top_hash_entry *en);
+static void ospf_send_lsupd_to_ifa(struct ospf_proto *p, struct top_hash_entry *en, struct ospf_iface *ifa);
/**
- * ospf_lsupd_flood - send received or generated LSA to the neighbors
- * @p: OSPF protocol
+ * ospf_flood_lsa - send LSA to the neighbors
+ * @p: OSPF protocol instance
* @en: LSA entry
* @from: neighbor than sent this LSA (or NULL if LSA is local)
*
* return value - was the LSA flooded back?
*/
-
int
-ospf_lsupd_flood(struct ospf_proto *p, struct top_hash_entry *en, struct ospf_neighbor *from)
+ospf_flood_lsa(struct ospf_proto *p, struct top_hash_entry *en, struct ospf_neighbor *from)
{
struct ospf_iface *ifa;
struct ospf_neighbor *n;
+ /* RFC 2328 13.3 */
+
int back = 0;
WALK_LIST(ifa, p->iface_list)
{
@@ -185,6 +198,8 @@ ospf_lsupd_flood(struct ospf_proto *p, struct top_hash_entry *en, struct ospf_ne
{
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);
}
@@ -227,7 +242,7 @@ ospf_lsupd_flood(struct ospf_proto *p, struct top_hash_entry *en, struct ospf_ne
}
/* 13.3 (5) - finally flood the packet */
- ospf_lsupd_flood_ifa(p, ifa, en);
+ ospf_send_lsupd_to_ifa(p, en, ifa);
}
return back;
@@ -288,7 +303,7 @@ ospf_prepare_lsupd(struct ospf_proto *p, struct ospf_iface *ifa,
static void
-ospf_lsupd_flood_ifa(struct ospf_proto *p, struct ospf_iface *ifa, struct top_hash_entry *en)
+ospf_send_lsupd_to_ifa(struct ospf_proto *p, struct top_hash_entry *en, struct ospf_iface *ifa)
{
uint c = ospf_prepare_lsupd(p, ifa, &en, 1);
@@ -384,7 +399,8 @@ ospf_receive_lsupd(struct ospf_packet *pkt, struct ospf_iface *ifa,
/* RFC 2328 13. */
- int sendreq = 1; /* XXXX: review sendreq */
+ int skip_lsreq = 0;
+ n->want_lsreq = 0;
uint plen = ntohs(pkt->length);
if (plen < (ospf_lsupd_hdrlen(p) + sizeof(struct ospf_lsa_header)))
@@ -436,7 +452,7 @@ ospf_receive_lsupd(struct ospf_packet *pkt, struct ospf_iface *ifa,
u16 chsum = lsa_n->checksum;
if (chsum != lsasum_check(lsa_n, NULL))
{
- log(L_WARN "%s: Received LSA from %I with bad checskum: %x %x",
+ log(L_WARN "%s: Received LSA from %I with bad checksum: %x %x",
p->p.name, n->ip, chsum, lsa_n->checksum);
continue;
}
@@ -501,7 +517,7 @@ 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");
- sendreq = 0;
+ skip_lsreq = 1;
continue;
}
@@ -514,7 +530,6 @@ ospf_receive_lsupd(struct ospf_packet *pkt, struct ospf_iface *ifa,
{
log(L_WARN "%s: Received invalid LSA from %I", p->p.name, n->ip);
mb_free(body);
- sendreq = 0;
continue;
}
@@ -528,22 +543,27 @@ ospf_receive_lsupd(struct ospf_packet *pkt, struct ospf_iface *ifa,
}
/* 13. (5c) - remove old LSA from all retransmission lists */
- /* Must be done before (5b), otherwise it also removes the new entries from (5b) */
-
+ /*
+ * We only need to remove it from the retransmission list of the neighbor
+ * that send us the new LSA. The old LSA is automatically replaced in
+ * retransmission lists by the new LSA.
+ */
if (en)
ospf_lsa_lsrt_down(en, n);
+#if 0
/*
- {
- struct ospf_iface *ifi;
- struct ospf_neighbor *ni;
-
- WALK_LIST(ifi, p->iface_list)
- WALK_LIST(ni, ifi->neigh_list)
- if (ni->state > NEIGHBOR_EXSTART)
- ospf_lsa_lsrt_down(en, ni);
- }
- */
+ * Old code for removing LSA from all retransmission lists. Must be done
+ * before (5b), otherwise it also removes the new entries from (5b).
+ */
+ struct ospf_iface *ifi;
+ struct ospf_neighbor *ni;
+
+ WALK_LIST(ifi, p->iface_list)
+ WALK_LIST(ni, ifi->neigh_list)
+ if (ni->state > NEIGHBOR_EXSTART)
+ ospf_lsa_lsrt_down(en, ni);
+#endif
/* 13. (5d) - install new LSA into database */
en = ospf_install_lsa(p, &lsa, lsa_type, lsa_domain, body);
@@ -553,7 +573,7 @@ ospf_receive_lsupd(struct ospf_packet *pkt, struct ospf_iface *ifa,
ospf_notify_net_lsa(ifa);
/* 13. (5b) - flood new LSA */
- int flood_back = ospf_lsupd_flood(p, en, n);
+ int flood_back = ospf_flood_lsa(p, en, n);
/* 13.5. - schedule ACKs (tbl 19, cases 1+2) */
if (! flood_back)
@@ -582,7 +602,7 @@ ospf_receive_lsupd(struct ospf_packet *pkt, struct ospf_iface *ifa,
else
ospf_enqueue_lsack(n, lsa_n, ACKL_DIRECT);
- sendreq = 0;
+ skip_lsreq = 1;
continue;
}
@@ -598,11 +618,17 @@ ospf_receive_lsupd(struct ospf_packet *pkt, struct ospf_iface *ifa,
}
}
- /* Send direct LSAs */
- ospf_lsack_send(n, ACKL_DIRECT);
-
- /* If loading, ask for another part of neighbor's database */
- if (sendreq && (n->state == NEIGHBOR_LOADING))
+ /* Send direct LSACKs */
+ ospf_send_lsack(p, n, ACKL_DIRECT);
+
+ /*
+ * 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.
+ */
+ if ((n->state == NEIGHBOR_LOADING) && n->want_lsreq && !skip_lsreq)
ospf_send_lsreq(p, n);
}