From: Ondrej Zajicek Date: Tue, 29 Apr 2014 14:24:59 +0000 (+0200) Subject: Merge commit '1fba34a7a1e245f08212a31a65030230da8c451d' into integrated X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=f353a1b09e8a6dc9b19692e62f94a57e50b6aa63;p=thirdparty%2Fbird.git Merge commit '1fba34a7a1e245f08212a31a65030230da8c451d' into integrated --- f353a1b09e8a6dc9b19692e62f94a57e50b6aa63 diff --cc proto/ospf/lsupd.c index a2d04fb4f,beac6c83d..ad7d33237 --- a/proto/ospf/lsupd.c +++ b/proto/ospf/lsupd.c @@@ -406,244 -745,16 +406,244 @@@ ospf_lsupd_receive(struct ospf_packet * } } + +/** + * 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, 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)", ++ log(L_ERR "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_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 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; + } - 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); }