diff options
Diffstat (limited to 'proto/ospf/lsreq.c')
-rw-r--r-- | proto/ospf/lsreq.c | 175 |
1 files changed, 88 insertions, 87 deletions
diff --git a/proto/ospf/lsreq.c b/proto/ospf/lsreq.c index 15854ce7..a6c0cf24 100644 --- a/proto/ospf/lsreq.c +++ b/proto/ospf/lsreq.c @@ -2,6 +2,8 @@ * BIRD -- OSPF * * (c) 2000--2004 Ondrej Filip <feela@network.cz> + * (c) 2009--2014 Ondrej Zajicek <santiago@crfreenet.org> + * (c) 2009--2014 CZ.NIC z.s.p.o. * * Can be freely distributed and used under the terms of the GNU GPL. */ @@ -9,47 +11,55 @@ #include "ospf.h" +/* struct ospf_lsreq_packet { - struct ospf_packet ospf_packet; - struct ospf_lsreq_header lsh[]; + struct ospf_packet hdr; + // union ospf_auth auth; + + struct ospf_lsreq_header lsrs[]; }; +*/ -static void ospf_dump_lsreq(struct proto *p, struct ospf_lsreq_packet *pkt) +static inline void +ospf_lsreq_body(struct ospf_proto *p, struct ospf_packet *pkt, + struct ospf_lsreq_header **body, uint *count) { - struct ospf_packet *op = &pkt->ospf_packet; + uint plen = ntohs(pkt->length); + uint hlen = ospf_pkt_hdrlen(p); + + *body = ((void *) pkt) + hlen; + *count = (plen - hlen) / sizeof(struct ospf_lsreq_header); +} - ASSERT(op->type == LSREQ_P); - ospf_dump_common(p, op); +static void +ospf_dump_lsreq(struct ospf_proto *p, struct ospf_packet *pkt) +{ + struct ospf_lsreq_header *lsrs; + uint i, lsr_count; - unsigned int i, j; - j = (ntohs(op->length) - sizeof(struct ospf_lsreq_packet)) / - sizeof(struct ospf_lsreq_header); + ASSERT(pkt->type == LSREQ_P); + ospf_dump_common(p, pkt); - for (i = 0; i < j; i++) - log(L_TRACE "%s: LSR Type: %04x, Id: %R, Rt: %R", p->name, - htonl(pkt->lsh[i].type), htonl(pkt->lsh[i].id), htonl(pkt->lsh[i].rt)); + ospf_lsreq_body(p, pkt, &lsrs, &lsr_count); + for (i = 0; i < lsr_count; i++) + log(L_TRACE "%s: LSR Type: %04x, Id: %R, Rt: %R", p->p.name, + ntohl(lsrs[i].type), ntohl(lsrs[i].id), ntohl(lsrs[i].rt)); } + void -ospf_lsreq_send(struct ospf_neighbor *n) +ospf_send_lsreq(struct ospf_proto *p, struct ospf_neighbor *n) { - snode *sn; + struct ospf_iface *ifa = n->ifa; + struct ospf_lsreq_header *lsrs; struct top_hash_entry *en; - struct ospf_lsreq_packet *pk; - struct ospf_packet *op; - struct ospf_lsreq_header *lsh; - u16 length; - int i, j; - struct proto *p = &n->ifa->oa->po->proto; + struct ospf_packet *pkt; + uint i, lsr_max, length; - pk = ospf_tx_buffer(n->ifa); - op = &pk->ospf_packet; + /* RFC 2328 10.9 */ - ospf_pkt_fill_hdr(n->ifa, pk, LSREQ_P); - - sn = SHEAD(n->lsrql); if (EMPTY_SLIST(n->lsrql)) { if (n->state == NEIGHBOR_LOADING) @@ -57,90 +67,81 @@ ospf_lsreq_send(struct ospf_neighbor *n) return; } - i = j = (ospf_pkt_maxsize(n->ifa) - sizeof(struct ospf_lsreq_packet)) / - sizeof(struct ospf_lsreq_header); - lsh = pk->lsh; + pkt = ospf_tx_buffer(ifa); + ospf_pkt_fill_hdr(ifa, pkt, LSREQ_P); + ospf_lsreq_body(p, pkt, &lsrs, &lsr_max); + + /* We send smaller LSREQ to prevent multiple LSACKs as answer */ + lsr_max = lsr_max / 4; - for (; i > 0; i--) + i = 0; + WALK_SLIST(en, n->lsrql) { - en = (struct top_hash_entry *) sn; - lsh->type = htonl(en->lsa.type); - lsh->rt = htonl(en->lsa.rt); - lsh->id = htonl(en->lsa.id); - DBG("Requesting %uth LSA: Type: %u, ID: %R, RT: %R, SN: 0x%x, Age %u\n", - i, en->lsa.type, en->lsa.id, en->lsa.rt, en->lsa.sn, en->lsa.age); - lsh++; - if (sn == STAIL(n->lsrql)) + if (i == lsr_max) break; - sn = sn->next; + + DBG("Requesting %uth LSA: Type: %04u, ID: %R, RT: %R, SN: 0x%x, Age %u\n", + i, en->lsa_type, en->lsa.id, en->lsa.rt, en->lsa.sn, en->lsa.age); + + u32 etype = lsa_get_etype(&en->lsa, p); + lsrs[i].type = htonl(etype); + lsrs[i].rt = htonl(en->lsa.rt); + lsrs[i].id = htonl(en->lsa.id); + i++; } - if (i != 0) - i--; - length = - sizeof(struct ospf_lsreq_packet) + (j - - i) * sizeof(struct ospf_lsreq_header); - op->length = htons(length); + length = ospf_pkt_hdrlen(p) + i * sizeof(struct ospf_lsreq_header); + pkt->length = htons(length); - OSPF_PACKET(ospf_dump_lsreq, pk, "LSREQ packet sent to %I via %s", n->ip, n->ifa->ifname); - ospf_send_to(n->ifa, n->ip); + OSPF_PACKET(ospf_dump_lsreq, pkt, "LSREQ packet sent to %I via %s", n->ip, ifa->ifname); + ospf_send_to(ifa, n->ip); } + void -ospf_lsreq_receive(struct ospf_packet *ps_i, struct ospf_iface *ifa, +ospf_receive_lsreq(struct ospf_packet *pkt, struct ospf_iface *ifa, struct ospf_neighbor *n) { - struct ospf_area *oa = ifa->oa; - struct proto_ospf *po = oa->po; - struct proto *p = &po->proto; - struct ospf_lsreq_header *lsh; - struct l_lsr_head *llsh; - list uplist; - slab *upslab; - int i, lsano; - - unsigned int size = ntohs(ps_i->length); - if (size < sizeof(struct ospf_lsreq_packet)) - { - log(L_ERR "Bad OSPF LSREQ packet from %I - too short (%u B)", n->ip, size); - return; - } + struct ospf_proto *p = ifa->oa->po; + struct ospf_lsreq_header *lsrs; + uint i, lsr_count; - struct ospf_lsreq_packet *ps = (void *) ps_i; - OSPF_PACKET(ospf_dump_lsreq, ps, "LSREQ packet received from %I via %s", n->ip, ifa->ifname); + /* RFC 2328 10.7 */ + + /* No need to check length, lsreq has only basic header */ + + OSPF_PACKET(ospf_dump_lsreq, pkt, "LSREQ packet received from %I via %s", n->ip, ifa->ifname); if (n->state < NEIGHBOR_EXCHANGE) return; - ospf_neigh_sm(n, INM_HELLOREC); + ospf_neigh_sm(n, INM_HELLOREC); /* Not in RFC */ + + ospf_lsreq_body(p, pkt, &lsrs, &lsr_count); - lsh = ps->lsh; - init_list(&uplist); - upslab = sl_new(n->pool, sizeof(struct l_lsr_head)); + struct top_hash_entry *en, *entries[lsr_count]; - lsano = (size - sizeof(struct ospf_lsreq_packet)) / - sizeof(struct ospf_lsreq_header); - for (i = 0; i < lsano; lsh++, i++) + for (i = 0; i < lsr_count; i++) { - u32 hid = ntohl(lsh->id); - u32 hrt = ntohl(lsh->rt); - u32 htype = ntohl(lsh->type); - u32 dom = ospf_lsa_domain(htype, ifa); - DBG("Processing requested LSA: Type: %u, ID: %R, RT: %R\n", lsh->type, hid, hrt); - llsh = sl_alloc(upslab); - llsh->lsh.id = hid; - llsh->lsh.rt = hrt; - llsh->lsh.type = htype; - add_tail(&uplist, NODE llsh); - if (ospf_hash_find(po->gr, dom, hid, hrt, htype) == NULL) + u32 id, rt, type, domain; + + id = ntohl(lsrs[i].id); + rt = ntohl(lsrs[i].rt); + lsa_get_type_domain_(ntohl(lsrs[i].type), ifa, &type, &domain); + + DBG("Processing requested LSA: Type: %04x, Id: %R, Rt: %R\n", type, id, rt); + + en = ospf_hash_find(p->gr, domain, id, rt, type); + if (!en) { - log(L_WARN "Received bad LSREQ from %I: Type: %04x, Id: %R, Rt: %R", - n->ip, htype, hid, hrt); + log(L_WARN "%s: Received LSREQ from %I for missing LSA (Type: %04x, Id: %R, Rt: %R)", + p->p.name, n->ip, type, id, rt); ospf_neigh_sm(n, INM_BADLSREQ); - rfree(upslab); return; } + + entries[i] = en; } - ospf_lsupd_send_list(n, &uplist); - rfree(upslab); + + ospf_send_lsupd(p, entries, lsr_count, n); } |