diff --git a/proto/ospf/dbdes.c b/proto/ospf/dbdes.c index 120c20e8..d0d8e306 100644 --- a/proto/ospf/dbdes.c +++ b/proto/ospf/dbdes.c @@ -268,7 +268,7 @@ ospf_dbdes_process(struct ospf_neighbor *n, struct ospf_packet *pkt, unsigned pl if (ospf_hash_is_new(req)) s_add_tail(&(n->lsrql), SNODE req); - en->lsa = lsa; + en->lsa = lsa; // XXXX ??? should be req->lsa ? } } } diff --git a/proto/ospf/lsreq.c b/proto/ospf/lsreq.c index 721e0379..e0270b9f 100644 --- a/proto/ospf/lsreq.c +++ b/proto/ospf/lsreq.c @@ -91,6 +91,7 @@ ospf_lsreq_send(struct ospf_neighbor *n) ospf_send_to(ifa, n->ip); } + void ospf_lsreq_receive(struct ospf_packet *pkt, struct ospf_iface *ifa, struct ospf_neighbor *n) @@ -99,11 +100,6 @@ ospf_lsreq_receive(struct ospf_packet *pkt, struct ospf_iface *ifa, struct ospf_lsreq_header *lsrs; unsigned i, lsr_count; - struct ospf_lsreq_item *lsr_head, *lsr; - struct ospf_lsreq_item **lsr_pos = &lsr_head; - slab *upslab; - - /* No need to check length, lsreq has only basic header */ OSPF_PACKET(ospf_lsreq_dump, pkt, "LSREQ packet received from %I via %s", @@ -114,9 +110,10 @@ ospf_lsreq_receive(struct ospf_packet *pkt, struct ospf_iface *ifa, ospf_neigh_sm(n, INM_HELLOREC); /* Not in RFC */ - upslab = sl_new(n->pool, sizeof(struct ospf_lsreq_item)); - ospf_lsreq_body(po, pkt, ntohs(pkt->length), &lsrs, &lsr_count); + + struct top_hash_entry *en, *entries[lsr_count]; + for (i = 0; i < lsr_count; i++) { u32 id, rt, type, dom; @@ -127,26 +124,17 @@ ospf_lsreq_receive(struct ospf_packet *pkt, struct ospf_iface *ifa, 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) + en = ospf_hash_find(po->gr, dom, id, rt, type); + if (!en) { - log(L_WARN "Received bad LSREQ from %I: Type: %04x, Id: %R, Rt: %R", - n->ip, type, id, rt); + log(L_WARN "%s: Received LSREQ from %I for missing LSA (Type: %04x, Id: %R, Rt: %R)", + po->proto.name, n->ip, type, id, rt); ospf_neigh_sm(n, INM_BADLSREQ); - rfree(upslab); return; } - lsr = sl_alloc(upslab); - lsr->domain = dom; - lsr->type = type; - lsr->id = id; - lsr->rt = rt; - - *lsr_pos = lsr; - lsr_pos = &(lsr->next); + entries[i] = en; } - *lsr_pos = NULL; - ospf_lsupd_send_list(n, lsr_head); - rfree(upslab); + ospf_lsupd_send(n, entries, lsr_count); } diff --git a/proto/ospf/lsupd.c b/proto/ospf/lsupd.c index 94e1b743..86e1b1af 100644 --- a/proto/ospf/lsupd.c +++ b/proto/ospf/lsupd.c @@ -47,9 +47,19 @@ 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 u32 +ospf_lsupd_get_lsa_count(struct ospf_packet *pkt, unsigned hdrlen) +{ + u32 *c = ((void *) pkt) + hdrlen - 4; + return ntohl(*c); +} + +static inline void +ospf_lsupd_set_lsa_count(struct ospf_packet *pkt, unsigned hdrlen, u32 val) +{ + u32 *c = ((void *) pkt) + hdrlen - 4; + *c = htonl(val); +} static inline void ospf_lsupd_body(struct proto_ospf *po, struct ospf_packet *pkt, @@ -58,7 +68,7 @@ ospf_lsupd_body(struct proto_ospf *po, struct ospf_packet *pkt, 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)); + *lsa_count = ospf_lsupd_get_lsa_count(pkt, hlen); } static void ospf_lsupd_dump(struct proto_ospf *po, struct ospf_packet *pkt) @@ -93,291 +103,19 @@ static void ospf_lsupd_dump(struct proto_ospf *po, struct ospf_packet *pkt) } } -/** - * 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) - * @domain: domain of LSA (must be filled) - * @rtl: add this LSA into retransmission list - * - * - * return value - was the LSA flooded back? - */ +static void ospf_lsupd_flood_ifa(struct proto_ospf *po, struct ospf_iface *ifa, struct top_hash_entry *en); -int -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; - int ret, retval = 0; - /* pg 148 */ - WALK_LIST(ifa, po->iface_list) - { - if (ifa->stub) - 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); - - 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, domain, hh)) != NULL) - { - DBG("That LSA found in lsreq list for neigh %R\n", nn->rid); - - switch (lsa_comp(hh, &en->lsa)) - { - case CMP_OLDER: - continue; - break; - case CMP_SAME: - s_rem_node(SNODE en); - if (en->lsa_body != NULL) - mb_free(en->lsa_body); - en->lsa_body = NULL; - DBG("Removing from lsreq list for neigh %R\n", nn->rid); - ospf_hash_delete(nn->lsrqh, en); - if (EMPTY_SLIST(nn->lsrql)) - ospf_neigh_sm(nn, INM_LOADDONE); - continue; - break; - case CMP_NEWER: - s_rem_node(SNODE en); - if (en->lsa_body != NULL) - mb_free(en->lsa_body); - en->lsa_body = NULL; - DBG("Removing from lsreq list for neigh %R\n", nn->rid); - ospf_hash_delete(nn->lsrqh, en); - if (EMPTY_SLIST(nn->lsrql)) - ospf_neigh_sm(nn, INM_LOADDONE); - break; - default: - bug("Bug in lsa_comp?"); - } - } - } - - /* 13.3 (1c) */ - if (nn == n) - continue; - - /* 13.3 (1d) */ - if (rtl) - { - /* 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 = ospf_hash_find_header(nn->lsrth, domain, hh)) == NULL) - { - en = ospf_hash_get_header(nn->lsrth, domain, hh); - } - else - { - s_rem_node(SNODE en); - } - s_add_tail(&nn->lsrtl, SNODE en); - memcpy(&en->lsa, hh, sizeof(struct ospf_lsa_header)); - DBG("Adding that LSA for flood to %I\n", nn->ip); - } - else - { - if ((en = ospf_hash_find_header(nn->lsrth, domain, hh)) != NULL) - { - s_rem_node(SNODE en); - ospf_hash_delete(nn->lsrth, en); - } - } - - ret = 1; - } - - if (ret == 0) - continue; /* pg 150 (2) */ - - if (n && (n->ifa == ifa)) - { - if ((n->rid == ifa->drid) || n->rid == ifa->bdrid) - continue; /* pg 150 (3) */ - if (ifa->state == OSPF_IS_BACKUP) - continue; /* pg 150 (4) */ - retval = 1; - } - - { - u16 len, age; - unsigned hlen; - struct ospf_packet *pkt; - struct ospf_lsa_header *lh; - - pkt = ospf_tx_buffer(ifa); - hlen = ospf_lsupd_hdrlen(po); - - ospf_pkt_fill_hdr(ifa, pkt, LSUPD_P); - *ospf_lsupd_lsa_count(pkt, hlen) = htonl(1); - lh = (((void *) pkt) + hlen); - - /* Copy LSA into the packet */ - if (hn) - { - memcpy(lh, hn, ntohs(hn->length)); - } - else - { - u8 *help; - struct top_hash_entry *en; - - lsa_hton_hdr(hh, lh); - help = (u8 *) (lh + 1); - en = ospf_hash_find_header(po->gr, domain, hh); - lsa_hton_body(en->lsa_body, help, hh->length - sizeof(struct ospf_lsa_header)); - } - - age = ntohs(lh->age); - age += ifa->inftransdelay; - if (age > LSA_MAXAGE) - age = LSA_MAXAGE; - lh->age = htons(age); - - len = hlen + ntohs(lh->length); - pkt->length = htons(len); - - OSPF_PACKET(ospf_lsupd_dump, pkt, "LSUPD packet flooded via %s", ifa->iface->name); - - switch (ifa->type) - { - case OSPF_IT_BCAST: - if ((ifa->state == OSPF_IS_BACKUP) || (ifa->state == OSPF_IS_DR)) - ospf_send_to_all(ifa); - else - ospf_send_to_des(ifa); - break; - - case OSPF_IT_NBMA: - if ((ifa->state == OSPF_IS_BACKUP) || (ifa->state == OSPF_IS_DR)) - ospf_send_to_agt(ifa, NEIGHBOR_EXCHANGE); - else - ospf_send_to_bdr(ifa); - break; - - case OSPF_IT_PTP: - ospf_send_to_all(ifa); - break; - - case OSPF_IT_PTMP: - ospf_send_to_agt(ifa, NEIGHBOR_EXCHANGE); - break; - - case OSPF_IT_VLINK: - ospf_send_to(ifa, ifa->vip); - break; - - default: - bug("Bug in ospf_lsupd_flood()"); - } - } - } - return retval; -} - -void /* I send all I received in LSREQ */ -ospf_lsupd_send_list(struct ospf_neighbor *n, struct ospf_lsreq_item *lsr) -{ - struct ospf_area *oa = n->ifa->oa; - struct proto_ospf *po = oa->po; - struct top_hash_entry *en; - struct ospf_packet *pkt; - unsigned hlen, pos, pos2, maxsize, lsano; - - pkt = ospf_tx_buffer(n->ifa); - hlen = ospf_lsupd_hdrlen(po); - maxsize = ospf_pkt_maxsize(n->ifa); - - while (lsr) - { - /* Prepare the packet */ - ospf_pkt_fill_hdr(n->ifa, pkt, LSUPD_P); - pos = hlen; - lsano = 0; - - /* Fill the packet with LSAs */ - while (lsr) - { - en = ospf_hash_find(oa->po->gr, lsr->domain, lsr->id, lsr->rt, lsr->type); - if (!en) - { - /* Probably flushed LSA, this should not happen */ - log(L_WARN "OSPF: LSA disappeared (Type: %04x, Id: %R, Rt: %R)", - lsr->type, lsr->id, lsr->rt); - lsr = lsr->next; - continue; - } - - pos2 = pos + en->lsa.length; - if (pos2 > maxsize) - { - /* The packet if full, stop adding LSAs and sent it */ - if (lsano > 0) - break; - - /* LSA is larger than MTU, check buffer size */ - if (pos2 > ospf_pkt_bufsize(n->ifa)) - { - /* Cannot fit in a tx buffer, skip that */ - log(L_WARN "OSPF: LSA too large to send (Type: %04x, Id: %R, Rt: %R)", - lsr->type, lsr->id, lsr->rt); - lsr = lsr->next; - continue; - } - } - - /* Copy the LSA to the packet */ - void *lsabuf = ((void *) pkt) + pos; - lsa_hton_hdr(&(en->lsa), (struct ospf_lsa_header *) lsabuf); - lsa_hton_body(en->lsa_body, lsabuf + sizeof(struct ospf_lsa_header), - en->lsa.length - sizeof(struct ospf_lsa_header)); - pos = pos2; - lsano++; - lsr = lsr->next; - } - - if (lsano == 0) - break; - - /* Send the packet */ - pkt->length = htons(pos); - *ospf_lsupd_lsa_count(pkt, hlen) = htonl(lsano); - OSPF_PACKET(ospf_lsupd_dump, pkt, "LSUPD packet sent to %I via %s", - n->ip, n->ifa->iface->name); - ospf_send_to(n->ifa, n->ip); - } -} void ospf_lsupd_receive(struct ospf_packet *pkt, struct ospf_iface *ifa, struct ospf_neighbor *n) { - - struct ospf_neighbor *ntmp; struct proto_ospf *po = ifa->oa->po; struct proto *p = &po->proto; + struct ospf_neighbor *ntmp; + + unsigned sendreq = 1; unsigned plen = ntohs(pkt->length); @@ -402,8 +140,9 @@ ospf_lsupd_receive(struct ospf_packet *pkt, struct ospf_iface *ifa, for (i = 0; i < lsa_count; i++) { - struct ospf_lsa_header lsatmp; - struct top_hash_entry *lsadb; + struct ospf_lsa_header lsa, *lsa_n; + struct top_hash_entry *en, *ret; + u32 lsa_len, lsa_type, lsa_domain; if (offset > bound) { @@ -412,78 +151,79 @@ ospf_lsupd_receive(struct ospf_packet *pkt, struct ospf_iface *ifa, return; } - struct ospf_lsa_header *lsa = ((void *) pkt) + offset; - unsigned int lsalen = ntohs(lsa->length); - offset += lsalen; + /* LSA header in network order */ + lsa_n = ((void *) pkt) + offset; + lsa_len = ntohs(lsa_n->length); + offset += lsa_len; - if ((offset > plen) || ((lsalen % 4) != 0) || - (lsalen <= sizeof(struct ospf_lsa_header))) + if ((offset > plen) || ((lsa_len % 4) != 0) || + (lsa_len <= sizeof(struct ospf_lsa_header))) { - log(L_WARN "OSPF: Received LSA from %I with bad length", n->ip); + log(L_WARN "%s: Received LSA from %I with bad length", p->name, n->ip); ospf_neigh_sm(n, INM_BADLSREQ); break; } - /* pg 143 (1) */ - u16 chsum = lsa->checksum; - if (chsum != lsasum_check(lsa, NULL)) + /* RFC 2328 13. (1) - validate LSA checksum */ + u16 chsum = lsa_n->checksum; + if (chsum != lsasum_check(lsa_n, NULL)) { - log(L_WARN "OSPF: Received LSA from %I with bad checskum: %x %x", - n->ip, chsum, lsa->checksum); + log(L_WARN "%s: Received LSA from %I with bad checskum: %x %x", + p->name, n->ip, chsum, lsa_n->checksum); continue; } - u32 lsa_type, lsa_domain; - lsa_ntoh_hdr(lsa, &lsatmp); - lsa_xxxxtype(lsatmp.type_raw, ifa, &lsa_type, &lsa_domain); - - /* pg 143 (2) */ - if (!lsa_type) - { - log(L_WARN "OSPF: Received unknown LSA type from %I", n->ip); - continue; - } - - /* 4.5.1 (2) */ - if ((LSA_SCOPE(lsa_type) == LSA_SCOPE_AS) && !oa_is_ext(ifa->oa)) - { - log(L_WARN "OSPF: Received LSA with AS scope in stub area from %I", n->ip); - continue; - } - - /* 4.5.1 (3) */ - if (LSA_SCOPE(lsa_type) == LSA_SCOPE_RES) - { - log(L_WARN "OSPF: Received LSA with invalid scope from %I", n->ip); - continue; - } + /* LSA header in host order */ + lsa_ntoh_hdr(lsa_n, &lsa); + lsa_xxxxtype(lsa.type_raw, ifa, &lsa_type, &lsa_domain); DBG("Update Type: %04x, 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, lsa.id, lsa.rt, lsa.sn, lsa.age, lsa.checksum); - lsadb = ospf_hash_find(po->gr, lsa_domain, lsatmp.id, lsatmp.rt, lsa_type); - -#ifdef LOCAL_DEBUG - if (lsadb) - 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.sn, lsadb->lsa.age, lsadb->lsa.checksum); -#endif - - /* pg 143 (4) */ - if ((lsatmp.age == LSA_MAXAGE) && (lsadb == NULL) && can_flush_lsa(po)) + /* RFC 2328 13. (2) */ + if (!lsa_type) { - ospf_lsack_enqueue(n, lsa, ACKL_DIRECT); + log(L_WARN "%s: Received unknown LSA type from %I", p->name, n->ip); continue; } - /* pg 144 (5) */ - if ((lsadb == NULL) || (lsa_comp(&lsatmp, &lsadb->lsa) == CMP_NEWER)) + /* RFC 5340 4.5.1 (2) and RFC 2328 13. (3) */ + if ((LSA_SCOPE(lsa_type) == LSA_SCOPE_AS) && !oa_is_ext(ifa->oa)) + { + log(L_WARN "%s: Received LSA with AS scope in stub area from %I", p->name, n->ip); + continue; + } + + /* RFC 5340 4.5.1 (3) */ + if (LSA_SCOPE(lsa_type) == LSA_SCOPE_RES) + { + log(L_WARN "%s: Received LSA with invalid scope from %I", p->name, n->ip); + continue; + } + + /* Find local copy of LSA in link state database */ + en = ospf_hash_find(po->gr, lsa_domain, lsa.id, lsa.rt, lsa_type); + +#ifdef LOCAL_DEBUG + if (en) + DBG("I have Type: %04x, Id: %R, Rt: %R, Sn: 0x%08x, Age: %u, Sum: %u\n", + en->lsa_type, en->lsa.id, en->lsa.rt, en->lsa.sn, en->lsa.age, en->lsa.checksum); +#endif + + /* 13. (4) - ignore maxage LSA if i have no local copy */ + if ((lsa.age == LSA_MAXAGE) && !en && can_flush_lsa(po)) + { + ospf_lsack_enqueue(n, lsa_n, ACKL_DIRECT); + continue; + } + + int cmp = : CMP_NEWER; + + /* 13. (5) - received LSA is newer (or no local copy) */ + if (!en || (lsa_comp(&lsa, &en->lsa) == CMP_NEWER)) { struct ospf_iface *ift = NULL; - int self = (lsatmp.rt == po->router_id); - - DBG("PG143(5): Received LSA is newer\n"); + int self = (lsa.rt == po->router_id); #ifdef OSPFv2 /* 13.4 - check self-originated LSAs of NET type */ @@ -494,7 +234,7 @@ ospf_lsupd_receive(struct ospf_packet *pkt, struct ospf_iface *ifa, { if (!nifa->iface) continue; - if (ipa_equal(nifa->addr->ip, ipa_from_u32(lsatmp.id))) + if (ipa_equal(nifa->addr->ip, ipa_from_u32(lsa.id))) { self = 1; break; @@ -506,102 +246,101 @@ ospf_lsupd_receive(struct ospf_packet *pkt, struct ospf_iface *ifa, /* pg 145 (5f) - premature aging of self originated lsa */ if (self) { - if ((lsatmp.age == LSA_MAXAGE) && (lsatmp.sn == LSA_MAXSEQNO)) + if ((lsa.age == LSA_MAXAGE) && (lsa.sn == LSA_MAXSEQNO)) { - ospf_lsack_enqueue(n, lsa, ACKL_DIRECT); + ospf_lsack_enqueue(n, lsa_n, ACKL_DIRECT); continue; } OSPF_TRACE(D_EVENTS, "Received old self-originated LSA (Type: %04x, Id: %R, Rt: %R)", - lsa_type, lsatmp.id, lsatmp.rt); + lsa_type, lsa.id, lsa.rt); - if (lsadb) + if (en) { OSPF_TRACE(D_EVENTS, "Reflooding new self-originated LSA with newer sequence number"); - lsadb->lsa.sn = lsatmp.sn + 1; - lsadb->lsa.age = 0; - lsadb->inst_t = now; - lsadb->ini_age = 0; - lsasum_calculate(&lsadb->lsa, lsadb->lsa_body); - ospf_lsupd_flood(po, NULL, NULL, &lsadb->lsa, lsa_domain, 1); + en->lsa.sn = lsa.sn + 1; + en->lsa.age = 0; + en->inst_t = now; + en->ini_age = 0; + lsasum_calculate(&en->lsa, en->lsa_body); + ospf_lsupd_flood(po, NULL, NULL, &en->lsa, lsa_domain, 1); } else { OSPF_TRACE(D_EVENTS, "Premature aging it"); - lsatmp.age = LSA_MAXAGE; - lsatmp.sn = LSA_MAXSEQNO; - lsa->age = htons(LSA_MAXAGE); - lsa->sn = htonl(LSA_MAXSEQNO); - lsasum_check(lsa, (lsa + 1)); /* It also calculates chsum! */ - lsatmp.checksum = ntohs(lsa->checksum); - ospf_lsupd_flood(po, NULL, lsa, &lsatmp, lsa_domain, 0); + lsa.age = LSA_MAXAGE; + lsa.sn = LSA_MAXSEQNO; + lsa_n->age = htons(LSA_MAXAGE); + lsa_n->sn = htonl(LSA_MAXSEQNO); + lsasum_check(lsa_n, (lsa_n + 1)); /* It also calculates chsum! */ + lsa.checksum = ntohs(lsa_n->checksum); + ospf_lsupd_flood(po, NULL, lsa_n, &lsa, lsa_domain, 0); } continue; } /* pg 144 (5a) */ - if (lsadb && ((now - lsadb->inst_t) <= MINLSARRIVAL)) /* FIXME: test for flooding? */ + if (en && ((now - en->inst_t) <= MINLSARRIVAL)) /* FIXME: test for flooding? */ { OSPF_TRACE(D_EVENTS, "Skipping LSA received in less that MINLSARRIVAL"); sendreq = 0; continue; } - /* Remove old from all ret lists */ - /* pg 144 (5c) */ + /* 13. (5c) - remove old LSA from all retransmission lists */ /* Must be done before (5b), otherwise it also removes the new entries from (5b) */ - if (lsadb) + if (en) WALK_LIST(ift, po->iface_list) WALK_LIST(ntmp, ift->neigh_list) { - struct top_hash_entry *en; + struct top_hash_entry *ret; if (ntmp->state > NEIGHBOR_EXSTART) - if ((en = ospf_hash_find_header(ntmp->lsrth, lsa_domain, &lsadb->lsa)) != NULL) + if ((ret = ospf_hash_find_header(ntmp->lsrth, lsa_domain, &en->lsa)) != NULL) { - s_rem_node(SNODE en); - ospf_hash_delete(ntmp->lsrth, en); + s_rem_node(SNODE ret); + ospf_hash_delete(ntmp->lsrth, ret); } } /* pg 144 (5b) */ - if (ospf_lsupd_flood(po, n, lsa, &lsatmp, lsa_domain, 1) == 0) + if (ospf_lsupd_flood(po, n, lsa_n, &lsa, lsa_domain, 1) == 0) { DBG("Wasn't flooded back\n"); /* ps 144(5e), pg 153 */ if (ifa->state == OSPF_IS_BACKUP) { if (ifa->drid == n->rid) - ospf_lsack_enqueue(n, lsa, ACKL_DELAY); + ospf_lsack_enqueue(n, lsa_n, ACKL_DELAY); } else - ospf_lsack_enqueue(n, lsa, ACKL_DELAY); + ospf_lsack_enqueue(n, lsa_n, ACKL_DELAY); } - if ((lsatmp.age == LSA_MAXAGE) && (lsatmp.sn == LSA_MAXSEQNO) - && lsadb && can_flush_lsa(po)) + if ((lsa.age == LSA_MAXAGE) && (lsa.sn == LSA_MAXSEQNO) + && en && can_flush_lsa(po)) { - flush_lsa(lsadb, po); + flush_lsa(en, po); schedule_rtcalc(po); continue; } /* FIXME lsack? */ /* pg 144 (5d) */ - void *body = mb_alloc(p->pool, lsatmp.length - sizeof(struct ospf_lsa_header)); - lsa_ntoh_body(lsa + 1, body, lsatmp.length - sizeof(struct ospf_lsa_header)); + void *body = mb_alloc(p->pool, lsa.length - sizeof(struct ospf_lsa_header)); + lsa_ntoh_body(lsa_n + 1, body, lsa.length - sizeof(struct ospf_lsa_header)); /* We will do validation check after flooding and acknowledging given LSA to minimize problems when communicating with non-validating peer */ - if (lsa_validate(&lsatmp, lsa_type, ospf_is_v2(po), body) == 0) + if (lsa_validate(&lsa, lsa_type, ospf_is_v2(po), body) == 0) { log(L_WARN "Received invalid LSA from %I", n->ip); mb_free(body); continue; } - lsadb = lsa_install_new(po, &lsatmp, lsa_domain, body); + en = lsa_install_new(po, &lsa, lsa_domain, body); DBG("New LSA installed in DB\n"); - /* Events 6,7 from RFC5340 4.4.3. */ + /* Events 6,7 from RFC 5340 4.4.3. */ if ((lsa_type == LSA_T_LINK) && (ifa->state == OSPF_IS_DR)) schedule_net_lsa(ifa); @@ -610,45 +349,41 @@ ospf_lsupd_receive(struct ospf_packet *pkt, struct ospf_iface *ifa, /* FIXME pg145 (6) */ - /* pg145 (7) */ - if (lsa_comp(&lsatmp, &lsadb->lsa) == CMP_SAME) + /* 13. (7) - received LSA is same */ + if (lsa_comp(&lsa, &en->lsa) == CMP_SAME) { - struct top_hash_entry *en; - DBG("PG145(7) Got the same LSA\n"); - if ((en = ospf_hash_find_header(n->lsrth, lsadb->domain, &lsadb->lsa)) != NULL) + ret = ospf_hash_find_entry(n->lsrth, en); + if (ret) { /* pg145 (7a) */ - s_rem_node(SNODE en); - ospf_hash_delete(n->lsrth, en); + s_rem_node(SNODE ret); + ospf_hash_delete(n->lsrth, ret); if (ifa->state == OSPF_IS_BACKUP) { if (n->rid == ifa->drid) - ospf_lsack_enqueue(n, lsa, ACKL_DELAY); + ospf_lsack_enqueue(n, lsa_n, ACKL_DELAY); } } else { /* pg145 (7b) */ - ospf_lsack_enqueue(n, lsa, ACKL_DIRECT); + ospf_lsack_enqueue(n, lsa_n, ACKL_DIRECT); } sendreq = 0; continue; } - /* pg145 (8) */ - if ((lsadb->lsa.age == LSA_MAXAGE) && (lsadb->lsa.sn == LSA_MAXSEQNO)) + /* 13. (8) - received LSA is older */ { - continue; - } + /* Seqnum is wrapping, wait until it is flushed */ + if ((en->lsa.age == LSA_MAXAGE) && (en->lsa.sn == LSA_MAXSEQNO)) + continue; - struct ospf_lsreq_item lsr = { - .domain = lsadb->domain, - .type = lsadb->lsa_type, - .id = lsadb->lsa.id, - .rt = lsadb->lsa.rt - }; - ospf_lsupd_send_list(n, &lsr); + /* Send newer local copy back to neighbor */ + /* FIXME - check for MinLSArrival ? */ + ospf_lsupd_send(n, &en, 1); + } } /* Send direct LSAs */ @@ -660,15 +395,251 @@ ospf_lsupd_receive(struct ospf_packet *pkt, struct ospf_iface *ifa, } } -void -ospf_lsupd_flush_nlsa(struct proto_ospf *po, struct top_hash_entry *en) -{ - struct ospf_lsa_header *lsa = &en->lsa; - lsa->age = LSA_MAXAGE; - lsa->sn = LSA_MAXSEQNO; - lsasum_calculate(lsa, en->lsa_body); - OSPF_TRACE(D_EVENTS, "Premature aging self originated lsa!"); - OSPF_TRACE(D_EVENTS, "Type: %04x, Id: %R, Rt: %R", en->lsa_type, lsa->id, lsa->rt); - ospf_lsupd_flood(po, NULL, NULL, lsa, en->domain, 0); +/** + * ospf_lsupd_flood - send received or generated LSA to the neighbors + * @po: OSPF protocol + * @en: LSA entry + * @from: neighbor than sent this LSA (or NULL if LSI is local) + * + * return value - was the LSA flooded back? + */ + +int +ospf_lsupd_flood(struct proto_ospf *po, struct top_hash_entry *en, struct ospf_neighbor *from) +{ + struct ospf_iface *ifa; + struct ospf_neighbor *n; + + int back = 0; + WALK_LIST(ifa, po->iface_list) + { + if (ifa->stub) + continue; + + if (! lsa_flooding_allowed(en->lsa_type, en->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); + + int used = 0; + WALK_LIST(n, ifa->neigh_list) + { + /* 13.3 (1a) */ + if (n->state < NEIGHBOR_EXCHANGE) + continue; + + /* 13.3 (1b) */ + if (n->state < NEIGHBOR_FULL) + { + struct top_hash_entry *req = ospf_hash_find_entry(n->lsrqh, en); + if (req != NULL) + { + int cmp = lsa_comp(&en->lsa, &req->lsa); + + /* 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); + if (EMPTY_SLIST(n->lsrql)) + ospf_neigh_sm(n, INM_LOADDONE); + } + + /* If older or same, skip processing of this LSA */ + if (cmp < CMP_NEWER) + continue; + } + } + + /* 13.3 (1c) */ + if (n == from) + continue; + + /* In OSPFv3, there should be check whether receiving router understand + that type of LSA (for LSA types with U-bit == 0). But as we do not support + any optional LSA types, this is not needed yet */ + + /* 13.3 (1d) - add LSA to the link state retransmission list */ + { + struct top_hash_entry *ret = ospf_hash_get_entry(n->lsrth, en); + if (! ospf_hash_is_new(ret)) + s_rem_node(SNODE ret); + + s_add_tail(&n->lsrtl, SNODE ret); + memcpy(&ret->lsa, hh, sizeof(struct ospf_lsa_header)); + } + + used = 1; + } + + /* 13.3 (2) */ + if (!used) + continue; + + if (from && (from->ifa == ifa)) + { + /* 13.3 (3) */ + if ((from->rid == ifa->drid) || from->rid == ifa->bdrid) + continue; + + /* 13.3 (4) */ + if (ifa->state == OSPF_IS_BACKUP) + continue; + + back = 1; + } + + /* 13.3 (5) - finally flood the packet */ + ospf_lsupd_flood_ifa(po, ifa, en); + } + + return back; +} + +static int +ospf_lsupd_prepare(struct proto_ospf *po, struct ospf_iface *ifa, + struct top_hash_entry **lsa_list, unsigned lsa_count) +{ + struct ospf_packet *pkt; + unsigned hlen, pos, i, maxsize; + + pkt = ospf_tx_buffer(ifa); + hlen = ospf_lsupd_hdrlen(po); + maxsize = ospf_pkt_maxsize(ifa); + + ospf_pkt_fill_hdr(ifa, pkt, LSUPD_P); + pos = hlen; + + for (i = 0; i < lsa_count; i++) + { + struct top_hash_entry *en = lsa_list[i]; + unsigned len = en->lsa.length; + + if ((pos + len) > maxsize) + { + /* The packet if full, stop adding LSAs and sent it */ + if (i > 0) + break; + + /* LSA is larger than MTU, check buffer size */ + if ((pos + len) > ospf_pkt_bufsize(ifa)) + { + /* Cannot fit in a tx buffer, skip that */ + log(L_WARN "OSPF: LSA too large to send (Type: %04x, Id: %R, Rt: %R)", + en->lsa_type, en->lsa.id, en->lsa.rt); + XXXX(); + continue; + } + } + + struct ospf_lsa_header *buf = ((void *) pkt) + pos; + lsa_hton_hdr(&en->lsa, buf); + lsa_hton_body(en->lsa_body, ((void *) buf) + sizeof(struct ospf_lsa_header), + len - sizeof(struct ospf_lsa_header)); + buf->age = htons(MIN(en->lsa.age + ifa->inftransdelay, LSA_MAXAGE)); + + pos += len; + } + + ospf_lsupd_set_lsa_count(pkt, hlen, i); + pkt->length = htons(pos); + + return i; +} + + +static void +ospf_lsupd_flood_ifa(struct proto_ospf *po, struct ospf_iface *ifa, struct top_hash_entry *en) +{ + ospf_lsupd_prepare(po, ifa, &en, 1); + + OSPF_PACKET(ospf_lsupd_dump, ospf_tx_buffer(ifa), + "LSUPD packet flooded via %s", ifa->iface->name); + + switch (ifa->type) + { + case OSPF_IT_BCAST: + if ((ifa->state == OSPF_IS_BACKUP) || (ifa->state == OSPF_IS_DR)) + ospf_send_to_all(ifa); + else + ospf_send_to_des(ifa); + break; + + case OSPF_IT_NBMA: + if ((ifa->state == OSPF_IS_BACKUP) || (ifa->state == OSPF_IS_DR)) + ospf_send_to_agt(ifa, NEIGHBOR_EXCHANGE); + else + ospf_send_to_bdr(ifa); + break; + + case OSPF_IT_PTP: + ospf_send_to_all(ifa); + break; + + case OSPF_IT_PTMP: + ospf_send_to_agt(ifa, NEIGHBOR_EXCHANGE); + break; + + case OSPF_IT_VLINK: + ospf_send_to(ifa, ifa->vip); + break; + + default: + bug("Bug in ospf_lsupd_flood()"); + } +} + +int +ospf_lsupd_send(struct ospf_neighbor *n, struct top_hash_entry **lsa_list, unsigned lsa_count) +{ + struct ospf_iface *ifa = n->ifa; + struct proto_ospf *po = ifa->oa->po; + unsigned i, c; + + for (i = 0; i < lsa_count; i += c) + { + c = ospf_lsupd_prepare(po, ifa, lsa_list + i, lsa_count - i); + + OSPF_PACKET(ospf_lsupd_dump, ospf_tx_buffer(ifa), + "LSUPD packet sent to %I via %s", n->ip, ifa->iface->name); + + ospf_send_to(ifa, n->ip); + } + + return lsa_count; +} + +void +ospf_lsupd_rxmt(struct ospf_neighbor *n) +{ + struct proto_ospf *po = n->ifa->oa->po; + + const unsigned max = 128; + struct top_hash_entry *entries[max]; + struct top_hash_entry *ret, *en; + unsigned i = 0; + + WALK_SLIST(ret, n->lsrtl) + { + en = ospf_hash_find_entry(po->gr, ret); + if (!en) + { + /* Probably flushed LSA, this should not happen */ + log(L_WARN "%s: LSA disappeared (Type: %04x, Id: %R, Rt: %R)", + po->proto.name, ret->lsa_type, ret->lsa.id, ret->lsa.rt); + + XXXX(); /* remove entry */ + continue; + } + + entries[i] = en; + i++; + + if (i == max) + break; + } + + ospf_lsupd_send(n, entries, i); } diff --git a/proto/ospf/lsupd.h b/proto/ospf/lsupd.h index 476775e2..0c7a1ef1 100644 --- a/proto/ospf/lsupd.h +++ b/proto/ospf/lsupd.h @@ -12,14 +12,9 @@ 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_lsupd_send_list(struct ospf_neighbor *n, struct ospf_lsreq_item *lsr); -void ospf_lsupd_receive(struct ospf_packet *ps_i, - struct ospf_iface *ifa, struct ospf_neighbor *n); -int 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); -void ospf_lsupd_flush_nlsa(struct proto_ospf *po, struct top_hash_entry *en); -int ospf_lsa_flooding_allowed(struct ospf_lsa_header *lsa, u32 domain, struct ospf_iface *ifa); +void ospf_lsupd_receive(struct ospf_packet *ps_i, struct ospf_iface *ifa, struct ospf_neighbor *n); +int ospf_lsupd_flood(struct proto_ospf *po, struct top_hash_entry *en, struct ospf_neighbor *from); +int ospf_lsupd_send(struct ospf_neighbor *n, struct top_hash_entry **lsa_list, unsigned lsa_count); #endif /* _BIRD_OSPF_LSUPD_H_ */ diff --git a/proto/ospf/neighbor.c b/proto/ospf/neighbor.c index 228e02d2..8d7abc95 100644 --- a/proto/ospf/neighbor.c +++ b/proto/ospf/neighbor.c @@ -600,51 +600,30 @@ rxmt_timer_hook(timer * timer) // struct proto *p = &n->ifa->oa->po->proto; struct top_hash_entry *en; - DBG("%s: RXMT timer fired on interface %s for neigh: %I.\n", + DBG("%s: RXMT timer fired on interface %s for neigh %I\n", p->name, n->ifa->iface->name, n->ip); - if(n->state < NEIGHBOR_EXSTART) return; - - if (n->state == NEIGHBOR_EXSTART) + switch (n->state) { + case NEIGHBOR_EXSTART: ospf_dbdes_send(n, 1); return; - } - if ((n->state == NEIGHBOR_EXCHANGE) && (n->myimms & DBDES_MS)) /* I'm master */ + case NEIGHBOR_EXCHANGE: + if (n->myimms & DBDES_MS) ospf_dbdes_send(n, 0); + case NEIGHBOR_LOADING: + ospf_lsreq_send(n); + return; + case NEIGHBOR_FULL: + /* LSA retransmissions */ + if (!EMPTY_SLIST(n->lsrtl)) + ospf_lsupd_rxmt(n); + return; - if (n->state < NEIGHBOR_FULL) - ospf_lsreq_send(n); /* EXCHANGE or LOADING */ - else - { - if (!EMPTY_SLIST(n->lsrtl)) /* FULL */ - { - struct ospf_lsreq_item *lsr_head, *lsr; - struct ospf_lsreq_item **lsr_pos = &lsr_head; - - slab *upslab = sl_new(n->pool, sizeof(struct ospf_lsreq_item)); - - WALK_SLIST(en, n->lsrtl) - { - if ((SNODE en)->next == (SNODE en)) - bug("RTList is cycled"); - - lsr = sl_alloc(upslab); - lsr->domain = en->domain; - lsr->type = en->lsa_type; - lsr->id = en->lsa.id; - lsr->rt = en->lsa.rt; - - *lsr_pos = lsr; - lsr_pos = &(lsr->next); - } - *lsr_pos = NULL; - - ospf_lsupd_send_list(n, lsr_head); - rfree(upslab); - } + default: + return; } } diff --git a/proto/ospf/ospf.h b/proto/ospf/ospf.h index 4dbf27c5..146d07f6 100644 --- a/proto/ospf/ospf.h +++ b/proto/ospf/ospf.h @@ -586,15 +586,6 @@ struct ospf_lsreq_header u32 rt; }; -struct ospf_lsreq_item -{ - struct ospf_lsreq_item *next; - u32 domain; - u32 type; - u32 id; - u32 rt; -}; - struct ospf_neighbor { diff --git a/proto/ospf/topology.c b/proto/ospf/topology.c index cb5b4e96..f02ddc7b 100644 --- a/proto/ospf/topology.c +++ b/proto/ospf/topology.c @@ -429,23 +429,23 @@ void originate_rt_lsa(struct ospf_area *oa) { struct proto_ospf *po = oa->po; - struct ospf_lsa_header lsa; - u32 dom = oa->areaid; - void *body; + struct ospf_lsa_new lsa; OSPF_TRACE(D_EVENTS, "Originating router-LSA for area %R", oa->areaid); - lsa.age = 0; - lsa.type_raw = LSA_T_RT; - lsa.id = ospf_is_v2(po) ? po->router_id : 0; - lsa.rt = po->router_id; - lsa.sn = get_seqnum(oa->rt); - lsa_fix_options(po, &lsa, oa->options); + lsa.type = LSA_T_RT; + lsa.dom = oa->areaid; + lsa.id = ospf_is_v2(po) ? po->router_id : 0; + lsa.opts = oa->options; + lsa.body = originate_rt_lsa_body(po, oa, &lsa.length); - body = originate_rt_lsa_body(po, oa, &lsa.length); - lsasum_calculate(&lsa, body); - oa->rt = lsa_install_new(po, &lsa, dom, body); - ospf_lsupd_flood(po, NULL, NULL, &lsa, dom, 1); + ospf_originate_lsa(po, &lsa, &oa->rt); + + // lsa.rt = po->router_id; + // lsa_fix_options(po, &lsa, oa->options); + // lsasum_calculate(&lsa, body); + // ospf_lsupd_flood(po, NULL, NULL, &lsa, dom, 1); + // lsa_install_new(po, &lsa, oa->rt); } void @@ -559,24 +559,17 @@ void originate_net_lsa(struct ospf_iface *ifa) { struct proto_ospf *po = ifa->oa->po; - struct ospf_lsa_header lsa; - u32 dom = ifa->oa->areaid; - void *body; + struct ospf_lsa_new lsa; - OSPF_TRACE(D_EVENTS, "Originating network-LSA for iface %s", - ifa->iface->name); + OSPF_TRACE(D_EVENTS, "Originating network-LSA for iface %s", ifa->iface->name); - lsa.age = 0; - lsa.type_raw = LSA_T_NET; - lsa.id = ospf_is_v2(po) ? ipa_to_u32(ifa->addr->ip) : ifa->iface_id; - lsa.rt = po->router_id; - lsa.sn = get_seqnum(ifa->net_lsa); - lsa_fix_options(po, &lsa, ifa->oa->options); + lsa.type = LSA_T_NET; + lsa.dom = ifa->oa->areaid; + lsa.id = ospf_is_v2(po) ? ipa_to_u32(ifa->addr->ip) : ifa->iface_id; + lsa.opts = ifa->oa->options; + lsa.body = originate_net_lsa_body(po, ifa, &lsa.length); - body = originate_net_lsa_body(po, ifa, &lsa.length); - lsasum_calculate(&lsa, body); - ifa->net_lsa = lsa_install_new(po, &lsa, dom, body); - ospf_lsupd_flood(po, NULL, NULL, &lsa, dom, 1); + ifa->net_lsa = ospf_originate_lsa(po, &lsa, ifa->net_lsa); } void @@ -755,89 +748,76 @@ void originate_sum_net_lsa(struct ospf_area *oa, struct fib_node *fn, int metric) { struct proto_ospf *po = oa->po; - struct ospf_lsa_header lsa; + struct ospf_lsa_new lsa; struct top_hash_entry *en; - u32 dom = oa->areaid; - void *body; - OSPF_TRACE(D_EVENTS, "Originating net-summary-LSA for %I/%d (metric %d)", - fn->prefix, fn->pxlen, metric); + OSPF_TRACE(D_EVENTS, "Originating net-summary-LSA for %I/%d (metric %d)", fn->prefix, fn->pxlen, metric); - lsa.age = 0; - lsa.type_raw = LSA_T_SUM_NET; - lsa.id = fibnode_to_lsaid(po, fn); - lsa.rt = po->router_id; - lsa_fix_options(po, &lsa, oa->options); + lsa.type = LSA_T_SUM_NET; + lsa.dom = oa->areaid; + lsa.id = fibnode_to_lsaid(po, fn); + lsa.opts = oa->options; - en = ospf_hash_find_header(po->gr, dom, &lsa); + en = ospf_hash_find(po->gr, lsa.dom, lsa.id, po->router_id, lsa.type); if (en && check_sum_net_lsa(po, en, fn, metric)) return; - lsa.sn = get_seqnum(en); - body = originate_sum_net_lsa_body(po, &lsa.length, fn, metric); - lsasum_calculate(&lsa, body); - lsa_install_new(po, &lsa, dom, body); - ospf_lsupd_flood(po, NULL, NULL, &lsa, dom, 1); + lsa.body = originate_sum_net_lsa_body(po, &lsa.length, fn, metric); + + ospf_originate_lsa(po, &lsa, en); } void originate_sum_rt_lsa(struct ospf_area *oa, struct fib_node *fn, int metric, u32 options) { struct proto_ospf *po = oa->po; - struct ospf_lsa_header lsa; + struct ospf_lsa_new lsa; struct top_hash_entry *en; u32 rid = ipa_to_rid(fn->prefix); - u32 dom = oa->areaid; - void *body; - OSPF_TRACE(D_EVENTS, "Originating rt-summary-LSA for %R (metric %d)", - rid, metric); + OSPF_TRACE(D_EVENTS, "Originating rt-summary-LSA for %R (metric %d)", rid, metric); - lsa.age = 0; - lsa.type_raw = LSA_T_SUM_RT; - lsa.id = rid; /* In OSPFv3, LSA ID is meaningless, but we still use Router ID of ASBR */ - lsa.rt = po->router_id; - lsa_fix_options(po, &lsa, oa->options); + lsa.type = LSA_T_SUM_RT; + lsa.dom = oa->areaid; + lsa.id = rid; /* In OSPFv3, LSA ID is meaningless, but we still use Router ID of ASBR */ + lsa.opts = oa->options; options &= OPTIONS_MASK; - en = ospf_hash_find_header(po->gr, dom, &lsa); + en = ospf_hash_find(po->gr, lsa.dom, lsa.id, po->router_id, lsa.type); if (en && check_sum_rt_lsa(po, en, rid, metric, options)) return; - lsa.sn = get_seqnum(en); - body = originate_sum_rt_lsa_body(po, &lsa.length, rid, metric, options); - lsasum_calculate(&lsa, body); - lsa_install_new(po, &lsa, dom, body); - ospf_lsupd_flood(po, NULL, NULL, &lsa, dom, 1); + lsa.body = originate_sum_rt_lsa_body(po, &lsa.length, rid, metric, options); + + ospf_originate_lsa(po, &lsa, en); } void flush_sum_lsa(struct ospf_area *oa, struct fib_node *fn, int type) { struct proto_ospf *po = oa->po; - struct ospf_lsa_header lsa; struct top_hash_entry *en; - u32 dom = oa->areaid; + u32 dom, lsid, type; - lsa.rt = po->router_id; if (type == ORT_NET) - { - lsa.id = fibnode_to_lsaid(po, fn); - lsa.type_raw = LSA_T_SUM_NET; - } + { + dom = oa->areaid; + type = LSA_T_SUM_NET; + lsid = fibnode_to_lsaid(po, fn); + } else - { - /* In OSPFv3, LSA ID is meaningless, but we still use Router ID of ASBR */ - lsa.id = ipa_to_rid(fn->prefix); - lsa.type_raw = LSA_T_SUM_RT; - } + { + /* In OSPFv3, LSA ID is meaningless, but we still use Router ID of ASBR */ + dom = oa->areaid; + type = LSA_T_SUM_RT; + lsid = ipa_to_rid(fn->prefix); + } - en = ospf_hash_find_header(po->gr, dom, &lsa); + en = ospf_hash_find(po->gr, dom, lsid, po->router_id, type); if (en) { - OSPF_TRACE(D_EVENTS, "Flushing summary-LSA (id=%R, type=%d)", - en->lsa.id, en->lsa.type_raw); + OSPF_TRACE(D_EVENTS, "Flushing summary-LSA (id=%R, type=%x)", lsid, type); if ((type == ORT_NET) && (check_sum_net_lsa(po, en, fn, 0) < 0)) return; @@ -1061,42 +1041,45 @@ originate_ext_lsa(struct ospf_area *oa, struct fib_node *fn, int src, u32 metric, ip_addr fwaddr, u32 tag, int pbit) { struct proto_ospf *po = oa->po; - struct proto *p = &po->proto; - struct ospf_lsa_header lsa; + struct ospf_lsa_new lsa; struct top_hash_entry *en; int nssa = oa_is_nssa(oa); - u32 dom = nssa ? oa->areaid : 0; - void *body; OSPF_TRACE(D_EVENTS, "Originating %s-LSA for %I/%d", nssa ? "NSSA" : "AS-external", fn->prefix, fn->pxlen); - lsa.age = 0; - lsa.type_raw = nssa ? LSA_T_NSSA : LSA_T_EXT; - lsa.id = fibnode_to_lsaid(po, fn); - lsa.rt = po->router_id; - lsa_fix_options(po, &lsa, nssa ? (pbit ? OPT_P : 0) : OPT_E); - - if (nssa && pbit && ipa_zero(fwaddr)) + if (! nssa) { - /* NSSA-LSA with P-bit set must have non-zero forwarding address */ + lsa.type = LSA_T_EXT; + lsa.dom = 0; + lsa.id = fibnode_to_lsaid(po, fn); + lsa.opts = OPT_E; + } + else + { + lsa.type = LSA_T_NSSA; + lsa.dom = oa->areaid; + lsa.id = fibnode_to_lsaid(po, fn); + lsa.opts = pbit ? OPT_P : 0; - fwaddr = find_surrogate_fwaddr(oa); - if (ipa_zero(fwaddr)) + /* NSSA-LSA with P-bit set must have non-zero forwarding address */ + if (pbit && ipa_zero(fwaddr)) { - log(L_ERR "%s: Cannot find forwarding address for NSSA-LSA %I/%d", - p->name, fn->prefix, fn->pxlen); - return; + fwaddr = find_surrogate_fwaddr(oa); + if (ipa_zero(fwaddr)) + { + log(L_ERR "%s: Cannot find forwarding address for NSSA-LSA %I/%d", + po->proto.name, fn->prefix, fn->pxlen); + return; + } } } - en = ospf_hash_find_header(po->gr, dom, &lsa); + en = ospf_hash_find(po->gr, lsa.dom, lsa.id, po->router_id, lsa.type); if (en && check_ext_lsa(po, en, fn, metric, fwaddr, tag)) return; - lsa.sn = get_seqnum(en); - body = originate_ext_lsa_body(po, &lsa.length, fn, metric, fwaddr, tag, pbit); - lsasum_calculate(&lsa, body); + lsa.body = originate_ext_lsa_body(po, &lsa.length, fn, metric, fwaddr, tag, pbit); if (src) { @@ -1104,8 +1087,7 @@ originate_ext_lsa(struct ospf_area *oa, struct fib_node *fn, int src, fn->flags |= src; } - lsa_install_new(po, &lsa, dom, body); - ospf_lsupd_flood(po, NULL, NULL, &lsa, dom, 1); + ospf_originate_lsa(po, &lsa, en); if (po->ebit == 0) { @@ -1126,20 +1108,16 @@ flush_ext_lsa(struct ospf_area *oa, struct fib_node *fn, int src, int nssa) u32 dom = nssa ? oa->areaid : 0; u32 type = nssa ? LSA_T_NSSA : LSA_T_EXT; - u32 lsaid = fibnode_to_lsaid(po, fn); + u32 lsid = fibnode_to_lsaid(po, fn); - en = ospf_hash_find(po->gr, dom, lsaid, po->router_id, type); + en = ospf_hash_find(po->gr, dom, lsid, po->router_id, type); if (en) { OSPF_TRACE(D_EVENTS, "Flushing %s-LSA for %I/%d", nssa ? "NSSA" : "AS-external", fn->prefix, fn->pxlen); if (check_ext_lsa(po, en, fn, 0, IPA_NONE, 0) < 0) - { - log(L_ERR "%s: LSAID collision for %I/%d", - p->name, fn->prefix, fn->pxlen); - return; - } + return; /* Clean up source bits */ if (src) // XXXX ??? @@ -1192,22 +1170,17 @@ originate_link_lsa(struct ospf_iface *ifa) { struct proto_ospf *po = ifa->oa->po; struct ospf_lsa_header lsa; - u32 dom = ifa->iface_id; - void *body; /* FIXME check for vlink and skip that? */ OSPF_TRACE(D_EVENTS, "Originating link-LSA for iface %s", ifa->iface->name); - lsa.age = 0; - lsa.type_raw = LSA_T_LINK; - lsa.id = ifa->iface_id; - lsa.rt = po->router_id; - lsa.sn = get_seqnum(ifa->link_lsa); + lsa.type = LSA_T_LINK; + lsa.dom = ifa->iface_id; + lsa.id = ifa->iface_id; + lsa.opts = 0; + lsa.body = originate_link_lsa_body(ifa, &lsa.length); - body = originate_link_lsa_body(ifa, &lsa.length); - lsasum_calculate(&lsa, body); - ifa->link_lsa = lsa_install_new(po, &lsa, dom, body); - ospf_lsupd_flood(po, NULL, NULL, &lsa, dom, 1); + ifa->link_lsa = ospf_originate_lsa(po, &lsa, ifa->link_lsa); /* Just to be sure to not forget on our link LSA */ if (ifa->state == OSPF_IS_DR) @@ -1344,21 +1317,16 @@ originate_prefix_rt_lsa(struct ospf_area *oa) { struct proto_ospf *po = oa->po; struct ospf_lsa_header lsa; - u32 dom = oa->areaid; - void *body; OSPF_TRACE(D_EVENTS, "Originating router prefix-LSA for area %R", oa->areaid); - lsa.age = 0; - lsa.type_raw = LSA_T_PREFIX; - lsa.id = 0; - lsa.rt = po->router_id; - lsa.sn = get_seqnum(oa->pxr_lsa); + lsa.type = LSA_T_PREFIX; + lsa.dom = oa->areaid; + lsa.id = 0; + lsa.opts = 0; + lsa.body = originate_prefix_rt_lsa_body(oa, &lsa.length); - body = originate_prefix_rt_lsa_body(oa, &lsa.length); - lsasum_calculate(&lsa, body); - oa->pxr_lsa = lsa_install_new(po, &lsa, dom, body); - ospf_lsupd_flood(po, NULL, NULL, &lsa, dom, 1); + oa->pxr_lsa = ospf_originate_lsa(po, &lsa, oa->pxr_lsa); } @@ -1485,23 +1453,17 @@ void originate_prefix_net_lsa(struct ospf_iface *ifa) { struct proto_ospf *po = ifa->oa->po; - struct ospf_lsa_header lsa; - u32 dom = ifa->oa->areaid; - void *body; + struct ospf_lsa_new lsa; - OSPF_TRACE(D_EVENTS, "Originating network prefix-LSA for iface %s", - ifa->iface->name); + OSPF_TRACE(D_EVENTS, "Originating network prefix-LSA for iface %s", ifa->iface->name); - lsa.age = 0; - lsa.type_raw = LSA_T_PREFIX; - lsa.id = ifa->iface_id; - lsa.rt = po->router_id; - lsa.sn = get_seqnum(ifa->pxn_lsa); + lsa.type = LSA_T_PREFIX; + lsa.dom = ifa->oa->areaid; + lsa.id = ifa->iface_id; + lsa.opts = 0; + lsa.body = originate_prefix_net_lsa_body(ifa, &lsa.length); - body = originate_prefix_net_lsa_body(ifa, &lsa.length); - lsasum_calculate(&lsa, body); - ifa->pxn_lsa = lsa_install_new(po, &lsa, dom, body); - ospf_lsupd_flood(po, NULL, NULL, &lsa, dom, 1); + ifa->pxn_lsa = ospf_originate_lsa(po, &lsa, ifa->pxn_lsa); } void @@ -1638,18 +1600,6 @@ ospf_top_rehash(struct top_graph *f, int step) ospf_top_ht_free(oldt); } -struct top_hash_entry * -ospf_hash_find_header(struct top_graph *f, u32 domain, struct ospf_lsa_header *h) -{ - return ospf_hash_find(f, domain, h->id, h->rt, h->type); -} - -struct top_hash_entry * -ospf_hash_get_header(struct top_graph *f, u32 domain, struct ospf_lsa_header *h) -{ - return ospf_hash_get(f, domain, h->id, h->rt, h->type); -} - struct top_hash_entry * ospf_hash_find(struct top_graph *f, u32 domain, u32 lsa, u32 rtr, u32 type) { @@ -1861,3 +1811,13 @@ can_flush_lsa(struct proto_ospf *po) return 1; } + +ospf_originate_lsa(struct proto_ospf *po, struct ospf_lsa_header *lsa) +{ + struct ospf_lsa_header hdr; + + lsasum_calculate(&lsa, body); + xx = lsa_install_new(po, &lsa, dom, body); + ospf_lsupd_flood(po, NULL, NULL, &lsa, dom, 1); + +} diff --git a/proto/ospf/topology.h b/proto/ospf/topology.h index 5858e11a..a3c6ffef 100644 --- a/proto/ospf/topology.h +++ b/proto/ospf/topology.h @@ -47,18 +47,22 @@ struct top_graph unsigned int hash_entries_min, hash_entries_max; }; +struct ospf_lsa_new +{ + u16 type; + u32 dom; + u32 id; + u16 opts; + u16 length; + void *body; + +}; + struct top_graph *ospf_top_new(pool *); void ospf_top_free(struct top_graph *); void ospf_top_dump(struct top_graph *, struct proto *); -struct top_hash_entry *ospf_hash_find_header(struct top_graph *f, u32 domain, - struct ospf_lsa_header *h); -struct top_hash_entry *ospf_hash_get_header(struct top_graph *f, u32 domain, - struct ospf_lsa_header *h); -struct top_hash_entry *ospf_hash_find(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 originate_rt_lsa(struct ospf_area *oa); void update_rt_lsa(struct ospf_area *oa); void originate_net_lsa(struct ospf_iface *ifa); @@ -72,6 +76,17 @@ void flush_sum_lsa(struct ospf_area *oa, struct fib_node *fn, int type); void originate_ext_lsa(struct ospf_area *oa, struct fib_node *fn, int src, u32 metric, ip_addr fwaddr, u32 tag, int pbit); void flush_ext_lsa(struct ospf_area *oa, struct fib_node *fn, int src, int nssa); + +struct top_hash_entry *ospf_hash_find(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 *); + +static inline struct top_hash_entry * ospf_hash_find_entry(struct top_graph *f, struct top_hash_entry *en) +{ return ospf_hash_find(f, en->domain, en->lsa.id, en->lsa.rt, en->lsa_type); } + +static inline struct top_hash_entry * ospf_hash_get_entry(struct top_graph *f, struct top_hash_entry *en) +{ return ospf_hash_get(f, en->domain, en->lsa.id, en->lsa.rt, en->lsa_type); } + struct top_hash_entry * ospf_hash_find_rt(struct top_graph *f, u32 domain, u32 rtr); struct top_hash_entry * ospf_hash_find_rt3_first(struct top_graph *f, u32 domain, u32 rtr); struct top_hash_entry * ospf_hash_find_rt3_next(struct top_hash_entry *e);