}
}
+
+/**
+ * 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 LSA 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)) && (n->state == NEIGHBOR_LOADING))
+ 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 */
+ ospf_lsa_lsrt_up(en, n);
+
+ 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, uint lsa_count)
+{
+ struct ospf_packet *pkt;
+ uint 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];
+ uint 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 (ospf_iface_assure_bufsize(ifa, pos + len) < 0)
+ {
+ /* Cannot fit in a tx buffer, skip that */
+ log(L_ERR "OSPF: LSA too large to send on %s (Type: %04x, Id: %R, Rt: %R)",
+ ifa->ifname, en->lsa_type, en->lsa.id, en->lsa.rt);
+ XXXX(); /* XXXX: handle packets with no LSA */
+ continue;
+ }
+
+ /* TX buffer could be reallocated */
+ pkt = ospf_tx_buffer(ifa);
+ }
+
+ 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->ifname);
+
+ 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, uint lsa_count)
+{
+ struct ospf_iface *ifa = n->ifa;
+ struct proto_ospf *po = ifa->oa->po;
+ uint 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->ifname);
+
+ ospf_send_to(ifa, n->ip);
+ }
+
+ return lsa_count;
+}
+
void
-ospf_lsupd_flush_nlsa(struct proto_ospf *po, struct top_hash_entry *en)
+ospf_lsupd_rxmt(struct ospf_neighbor *n)
{
- struct ospf_lsa_header *lsa = &en->lsa;
- struct proto *p = &po->proto;
+ struct proto_ospf *po = n->ifa->oa->po;
+
+ const uint max = 128;
+ struct top_hash_entry *entries[max];
+ struct top_hash_entry *ret, *en;
+ uint 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);
++ // 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;
+ }
- 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", lsa->type, lsa->id, lsa->rt);
- ospf_lsupd_flood(po, NULL, NULL, lsa, en->domain, 0);
+ ospf_lsupd_send(n, entries, i);
}