summaryrefslogtreecommitdiffstats
path: root/proto/ospf/lsupd.c
diff options
context:
space:
mode:
Diffstat (limited to 'proto/ospf/lsupd.c')
-rw-r--r--proto/ospf/lsupd.c172
1 files changed, 124 insertions, 48 deletions
diff --git a/proto/ospf/lsupd.c b/proto/ospf/lsupd.c
index ba09fec..8c26f54 100644
--- a/proto/ospf/lsupd.c
+++ b/proto/ospf/lsupd.c
@@ -9,6 +9,13 @@
#include "ospf.h"
+struct ospf_lsupd_packet
+{
+ struct ospf_packet ospf_packet;
+ u32 lsano; /* Number of LSA's */
+};
+
+
void ospf_dump_lsahdr(struct proto *p, struct ospf_lsa_header *lsa_n)
{
struct ospf_lsa_header lsa;
@@ -51,27 +58,79 @@ static void ospf_dump_lsupd(struct proto *p, struct ospf_lsupd_packet *pkt)
}
}
+
+#ifdef OSPFv2
+
+int
+ospf_lsa_flooding_allowed(struct ospf_lsa_header *lsa, u32 domain, struct ospf_iface *ifa)
+{
+ if (lsa->type == LSA_T_EXT)
+ {
+ if (ifa->type == OSPF_IT_VLINK)
+ return 0;
+ if (ifa->oa->stub)
+ return 0;
+ return 1
+ }
+ else
+ return ifa->oa->areaid == domain;
+}
+
+#else /* OSPFv3 */
+
+int
+ospf_lsa_flooding_allowed(struct ospf_lsa_header *lsa, u32 domain, struct ospf_iface *ifa)
+{
+ u32 scope = LSA_SCOPE(lsa);
+
+ /* 4.5.2 (Case 2) */
+ if (unknown_type(lsa) && !(lsa->type & LSA_UBIT))
+ scope = LSA_SCOPE_LINK;
+
+ switch (scope)
+ {
+ case LSA_SCOPE_LINK:
+ return ifa->iface->index == domain;
+
+ case LSA_SCOPE_AREA:
+ return ifa->oa->areaid == domain;
+
+ case LSA_SCOPE_AS:
+ if (ifa->type == OSPF_IT_VLINK)
+ return 0;
+ if (ifa->oa->stub)
+ return 0;
+ return 1;
+
+ default:
+ log(L_ERR "LSA with invalid scope");
+ return 0;
+ }
+}
+
+#endif
+
/**
* ospf_lsupd_flood - send received or generated lsa to the neighbors
+ * @po: OSPF protocol
* @n: neighbor than sent this lsa (or NULL if generated)
* @hn: LSA header followed by lsa body in network endianity (may be NULL)
* @hh: LSA header in host endianity (must be filled)
- * @iff: interface which received this LSA (or NULL if LSA is generated)
- * @oa: ospf_area which is the LSA generated for
+ * @domain: domain of LSA (must be filled)
* @rtl: add this LSA into retransmission list
*
+ *
* return value - was the LSA flooded back?
*/
int
-ospf_lsupd_flood(struct ospf_neighbor *n, struct ospf_lsa_header *hn,
- struct ospf_lsa_header *hh, struct ospf_iface *iff,
- struct ospf_area *oa, int rtl)
+ospf_lsupd_flood(struct proto_ospf *po,
+ struct ospf_neighbor *n, struct ospf_lsa_header *hn,
+ struct ospf_lsa_header *hh, u32 domain, int rtl)
{
struct ospf_iface *ifa;
struct ospf_neighbor *nn;
struct top_hash_entry *en;
- struct proto_ospf *po = oa->po;
struct proto *p = &po->proto;
int ret, retval = 0;
@@ -81,18 +140,8 @@ ospf_lsupd_flood(struct ospf_neighbor *n, struct ospf_lsa_header *hn,
if (ifa->stub)
continue;
- if (hh->type == LSA_T_EXT)
- {
- if (ifa->type == OSPF_IT_VLINK)
- continue;
- if (ifa->oa->stub)
- continue;
- }
- else
- {
- if (ifa->oa != oa)
- continue;
- }
+ if (! ospf_lsa_flooding_allowed(hh, domain, ifa))
+ continue;
DBG("Wanted to flood LSA: Type: %u, ID: %R, RT: %R, SN: 0x%x, Age %u\n",
hh->type, hh->id, hh->rt, hh->sn, hh->age);
@@ -100,11 +149,14 @@ ospf_lsupd_flood(struct ospf_neighbor *n, struct ospf_lsa_header *hn,
ret = 0;
WALK_LIST(nn, ifa->neigh_list)
{
+ /* 13.3 (1a) */
if (nn->state < NEIGHBOR_EXCHANGE)
continue;
+
+ /* 13.3 (1b) */
if (nn->state < NEIGHBOR_FULL)
{
- if ((en = ospf_hash_find_header(nn->lsrqh, nn->ifa->oa->areaid, hh)) != NULL)
+ if ((en = ospfxx_hash_find_header(nn->lsrqh, domain, hh)) != NULL)
{
DBG("That LSA found in lsreq list for neigh %R\n", nn->rid);
@@ -140,14 +192,20 @@ ospf_lsupd_flood(struct ospf_neighbor *n, struct ospf_lsa_header *hn,
}
}
+ /* 13.3 (1c) */
if (nn == n)
continue;
+ /* 13.3 (1d) */
if (rtl)
{
- if ((en = ospf_hash_find_header(nn->lsrth, nn->ifa->oa->areaid, hh)) == NULL)
+ /* In OSPFv3, there should be check whether receiving router understand
+ that type of LSA (for LSA types with U-bit == 0). But as we does not support
+ any optional LSA types, this is not needed yet */
+
+ if ((en = ospfxx_hash_find_header(nn->lsrth, domain, hh)) == NULL)
{
- en = ospf_hash_get_header(nn->lsrth, nn->ifa->oa, hh);
+ en = ospfxx_hash_get_header(nn->lsrth, domain, hh);
}
else
{
@@ -159,7 +217,7 @@ ospf_lsupd_flood(struct ospf_neighbor *n, struct ospf_lsa_header *hn,
}
else
{
- if ((en = ospf_hash_find_header(nn->lsrth, nn->ifa->oa->areaid, hh)) != NULL)
+ if ((en = ospfxx_hash_find_header(nn->lsrth, domain, hh)) != NULL)
{
s_rem_node(SNODE en);
if (en->lsa_body != NULL)
@@ -175,11 +233,11 @@ ospf_lsupd_flood(struct ospf_neighbor *n, struct ospf_lsa_header *hn,
if (ret == 0)
continue; /* pg 150 (2) */
- if (ifa == iff)
+ if (n && (n->ifa == ifa))
{
- if ((n->rid == iff->drid) || n->rid == iff->bdrid)
+ if ((n->rid == ifa->drid) || n->rid == ifa->bdrid)
continue; /* pg 150 (3) */
- if (iff->state == OSPF_IS_BACKUP)
+ if (ifa->state == OSPF_IS_BACKUP)
continue; /* pg 150 (4) */
retval = 1;
}
@@ -216,7 +274,7 @@ ospf_lsupd_flood(struct ospf_neighbor *n, struct ospf_lsa_header *hn,
htonlsah(hh, lh);
help = (u8 *) (lh + 1);
- en = ospf_hash_find_header(po->gr, oa->areaid, hh);
+ en = ospfxx_hash_find_header(po->gr, domain, hh);
htonlsab(en->lsa_body, help, hh->type, hh->length
- sizeof(struct ospf_lsa_header));
}
@@ -288,8 +346,9 @@ ospf_lsupd_send_list(struct ospf_neighbor *n, list * l)
WALK_LIST(llsh, *l)
{
- if ((en = ospf_hash_find(po->gr, oa->areaid, llsh->lsh.id, llsh->lsh.rt,
- llsh->lsh.type)) == NULL)
+ u32 domain = ospf_lsa_domain(llsh->lsh.type, n->ifa);
+ if ((en = ospfxx_hash_find(po->gr, domain, llsh->lsh.id,
+ llsh->lsh.rt, llsh->lsh.type)) == NULL)
continue; /* Probably flushed LSA */
/* FIXME This is a bug! I cannot flush LSA that is in lsrt */
@@ -330,13 +389,12 @@ ospf_lsupd_send_list(struct ospf_neighbor *n, list * l)
}
void
-ospf_lsupd_receive(struct ospf_lsupd_packet *ps,
- struct ospf_iface *ifa, struct ospf_neighbor *n)
+ospf_lsupd_receive(struct ospf_packet *ps_i, struct ospf_iface *ifa,
+ struct ospf_neighbor *n)
{
- u32 area;
+ struct ospf_lsupd_packet *ps = (void *) ps_i;
struct ospf_neighbor *ntmp;
struct ospf_lsa_header *lsa;
- struct ospf_area *oa;
struct proto_ospf *po = ifa->oa->po;
struct proto *p = &po->proto;
unsigned int i, sendreq = 1, size = ntohs(ps->ospf_packet.length);
@@ -359,8 +417,6 @@ ospf_lsupd_receive(struct ospf_lsupd_packet *ps,
ospf_neigh_sm(n, INM_HELLOREC); /* Questionable */
lsa = (struct ospf_lsa_header *) (ps + 1);
- area = htonl(ps->ospf_packet.areaid);
- oa = ospf_find_area((struct proto_ospf *) p, area);
for (i = 0; i < ntohl(ps->lsano); i++,
lsa = (struct ospf_lsa_header *) (((u8 *) lsa) + ntohs(lsa->length)))
@@ -394,6 +450,8 @@ ospf_lsupd_receive(struct ospf_lsupd_packet *ps,
continue;
}
+
+#ifdef OSPFv2
/* pg 143 (2) */
if ((lsa->type < LSA_T_RT) || (lsa->type > LSA_T_EXT))
{
@@ -402,18 +460,34 @@ ospf_lsupd_receive(struct ospf_lsupd_packet *ps,
}
/* pg 143 (3) */
- if ((lsa->type == LSA_T_EXT) && oa->stub)
+ if ((lsa->type == LSA_T_EXT) && ifa->oa->stub)
{
log(L_WARN "Received External LSA in stub area from %I", n->ip);
continue;
}
+#else /* OSPFv3 */
+ /* 4.5.1 (2) */
+ if ((LSA_SCOPE(lsa) == LSA_SCOPE_AS) && ifa->oa->stub)
+ {
+ log(L_WARN "Received LSA with AS scope in stub area from %I", n->ip);
+ continue;
+ }
+
+ /* 4.5.1 (3) */
+ if ((LSA_SCOPE(lsa) == LSA_SCOPE_RES))
+ {
+ log(L_WARN "Received LSA with invalid scope from %I", n->ip);
+ continue;
+ }
+#endif
ntohlsah(lsa, &lsatmp);
DBG("Update Type: %u ID: %R RT: %R, Sn: 0x%08x Age: %u, Sum: %u\n",
lsatmp.type, lsatmp.id, lsatmp.rt, lsatmp.sn, lsatmp.age, lsatmp.checksum);
- lsadb = ospf_hash_find_header(po->gr, oa->areaid, &lsatmp);
+ u32 domain = ospf_lsa_domain(lsatmp.type, ifa);
+ lsadb = ospfxx_hash_find_header(po->gr, domain, &lsatmp);
#ifdef LOCAL_DEBUG
if (lsadb)
@@ -439,7 +513,8 @@ ospf_lsupd_receive(struct ospf_lsupd_packet *ps,
DBG("PG143(5): Received LSA is newer\n");
- /* pg 145 (5f) - premature aging of self originated lsa */
+#ifdef OSPFv2
+ /* 13.4 - check self-originated LSAs of NET type */
if ((!self) && (lsatmp.type == LSA_T_NET))
{
WALK_LIST(nifa, po->iface_list)
@@ -453,7 +528,9 @@ ospf_lsupd_receive(struct ospf_lsupd_packet *ps,
}
}
}
+#endif
+ /* pg 145 (5f) - premature aging of self originated lsa */
if (self)
{
struct top_hash_entry *en;
@@ -473,10 +550,10 @@ ospf_lsupd_receive(struct ospf_lsupd_packet *ps,
lsatmp.type, lsatmp.id, lsatmp.rt);
lsasum_check(lsa, (lsa + 1)); /* It also calculates chsum! */
lsatmp.checksum = ntohs(lsa->checksum);
- ospf_lsupd_flood(NULL, lsa, &lsatmp, NULL, oa, 0);
- if (en = ospf_hash_find_header(po->gr, oa->areaid, &lsatmp))
- {
- ospf_lsupd_flood(NULL, NULL, &en->lsa, NULL, oa, 1);
+ ospf_lsupd_flood(po, NULL, lsa, &lsatmp, domain, 0);
+ if (en = ospfxx_hash_find_header(po->gr, domain, &lsatmp))
+ { /* FIXME verify hacks */
+ ospf_lsupd_flood(po, NULL, NULL, &en->lsa, domain, 1);
}
continue;
}
@@ -489,7 +566,7 @@ ospf_lsupd_receive(struct ospf_lsupd_packet *ps,
continue;
}
- if (ospf_lsupd_flood(n, lsa, &lsatmp, ifa, ifa->oa, 1) == 0)
+ if (ospf_lsupd_flood(po, n, lsa, &lsatmp, domain, 1) == 0)
{
DBG("Wasn't flooded back\n"); /* ps 144(5e), pg 153 */
if (ifa->state == OSPF_IS_BACKUP)
@@ -509,7 +586,7 @@ ospf_lsupd_receive(struct ospf_lsupd_packet *ps,
{
struct top_hash_entry *en;
if (ntmp->state > NEIGHBOR_EXSTART)
- if ((en = ospf_hash_find_header(ntmp->lsrth, ntmp->ifa->oa->areaid, &lsadb->lsa)) != NULL)
+ if ((en = ospfxx_hash_find_header(ntmp->lsrth, domain, &lsadb->lsa)) != NULL)
{
s_rem_node(SNODE en);
if (en->lsa_body != NULL)
@@ -532,7 +609,7 @@ ospf_lsupd_receive(struct ospf_lsupd_packet *ps,
mb_alloc(p->pool, lsatmp.length - sizeof(struct ospf_lsa_header));
ntohlsab(lsa + 1, body, lsatmp.type,
lsatmp.length - sizeof(struct ospf_lsa_header));
- lsadb = lsa_install_new(&lsatmp, body, oa);
+ lsadb = lsa_install_new(po, &lsatmp, domain, body);
DBG("New LSA installed in DB\n");
continue;
@@ -545,7 +622,7 @@ ospf_lsupd_receive(struct ospf_lsupd_packet *ps,
{
struct top_hash_entry *en;
DBG("PG145(7) Got the same LSA\n");
- if ((en = ospf_hash_find_header(n->lsrth, n->ifa->oa->areaid, &lsadb->lsa)) != NULL)
+ if ((en = ospfxx_hash_find_header(n->lsrth, lsadb->domain, &lsadb->lsa)) != NULL)
{
/* pg145 (7a) */
s_rem_node(SNODE en);
@@ -596,10 +673,9 @@ ospf_lsupd_receive(struct ospf_lsupd_packet *ps,
}
void
-ospf_lsupd_flush_nlsa(struct top_hash_entry *en, struct ospf_area *oa)
+ospf_lsupd_flush_nlsa(struct proto_ospf *po, struct top_hash_entry *en)
{
struct ospf_lsa_header *lsa = &en->lsa;
- struct proto_ospf *po = oa->po;
struct proto *p = &po->proto;
lsa->age = LSA_MAXAGE;
@@ -607,5 +683,5 @@ ospf_lsupd_flush_nlsa(struct top_hash_entry *en, struct ospf_area *oa)
lsasum_calculate(lsa, en->lsa_body);
OSPF_TRACE(D_EVENTS, "Premature aging self originated lsa!");
OSPF_TRACE(D_EVENTS, "Type: %d, Id: %R, Rt: %R", lsa->type, lsa->id, lsa->rt);
- ospf_lsupd_flood(NULL, NULL, lsa, NULL, oa, 0);
+ ospf_lsupd_flood(po, NULL, NULL, lsa, en->domain, 0);
}