From c3226991a061415fa83b757cbff678111c586e58 Mon Sep 17 00:00:00 2001 From: Ondrej Zajicek Date: Fri, 21 Aug 2009 09:27:52 +0200 Subject: Temporary OSPFv3 development commit --- proto/ospf/config.Y | 11 + proto/ospf/dbdes.c | 95 +++-- proto/ospf/dbdes.h | 4 +- proto/ospf/hello.c | 137 +++++-- proto/ospf/hello.h | 4 +- proto/ospf/iface.c | 18 +- proto/ospf/lsack.c | 27 +- proto/ospf/lsack.h | 4 +- proto/ospf/lsalib.c | 203 ++++------ proto/ospf/lsalib.h | 7 +- proto/ospf/lsreq.c | 38 +- proto/ospf/lsreq.h | 4 +- proto/ospf/lsupd.c | 172 +++++--- proto/ospf/lsupd.h | 12 +- proto/ospf/neighbor.c | 107 +++-- proto/ospf/ospf.c | 68 ++-- proto/ospf/ospf.h | 385 ++++++++++++------ proto/ospf/packet.c | 71 +++- proto/ospf/rt.c | 389 ++++++++++++------ proto/ospf/rt.h | 9 +- proto/ospf/topology.c | 1075 +++++++++++++++++++++++++++++++++++-------------- proto/ospf/topology.h | 23 +- 22 files changed, 1887 insertions(+), 976 deletions(-) (limited to 'proto/ospf') diff --git a/proto/ospf/config.Y b/proto/ospf/config.Y index 77ca26c..6acc7d2 100644 --- a/proto/ospf/config.Y +++ b/proto/ospf/config.Y @@ -20,6 +20,7 @@ static struct nbma_node *this_nbma; static struct area_net_config *this_pref; static struct ospf_stubnet_config *this_stubnet; +#ifdef OSPFv2 static void finish_iface_config(struct ospf_iface_patt *ip) { @@ -31,6 +32,16 @@ finish_iface_config(struct ospf_iface_patt *ip) if ((ip->autype == OSPF_AUTH_NONE) && (ip->passwords != NULL)) log(L_WARN "Password option without authentication option does not make sense"); } +#endif + +#ifdef OSPFv3 +static void +finish_iface_config(struct ospf_iface_patt *ip) +{ + if ((ip->autype != OSPF_AUTH_NONE) || (get_passwords() != NULL)) + log(L_WARN "Authentication not supported in OSPFv3"); +} +#endif CF_DECLS diff --git a/proto/ospf/dbdes.c b/proto/ospf/dbdes.c index adc0276..3107579 100644 --- a/proto/ospf/dbdes.c +++ b/proto/ospf/dbdes.c @@ -8,6 +8,37 @@ #include "ospf.h" + +#ifdef OSPFv2 +struct ospf_dbdes_packet +{ + struct ospf_packet ospf_packet; + u16 iface_mtu; + u8 options; + union imms imms; /* I, M, MS bits */ + u32 ddseq; +}; + +#define hton_opt(X) X +#define ntoh_opt(X) X +#endif + + +#ifdef OSPFv3 +struct ospf_dbdes_packet +{ + struct ospf_packet ospf_packet; + u32 options; + u16 iface_mtu; + u8 padding; + union imms imms; /* I, M, MS bits */ + u32 ddseq; +}; + +#define hton_opt(X) htonl(X) +#define ntoh_opt(X) ntohl(X) +#endif + static void ospf_dump_dbdes(struct proto *p, struct ospf_dbdes_packet *pkt) { @@ -37,7 +68,7 @@ static void ospf_dump_dbdes(struct proto *p, struct ospf_dbdes_packet *pkt) * @n: neighbor * @next: whether to send a next packet in a sequence (1) or to retransmit the old one (0) * - * Sending of a database description packet is described in 10.6 of RFC 2328. + * Sending of a database description packet is described in 10.8 of RFC 2328. * Reception of each packet is acknowledged in the sequence number of another. * When I send a packet to a neighbor I keep a copy in a buffer. If the neighbor * does not reply, I don't create a new packet but just send the content @@ -65,7 +96,7 @@ ospf_dbdes_send(struct ospf_neighbor *n, int next) op = (struct ospf_packet *) pkt; ospf_pkt_fill_hdr(ifa, pkt, DBDES_P); pkt->iface_mtu = htons(ifa->iface->mtu); - pkt->options = oa->opt.byte; + pkt->options = hton_opt(oa->options); pkt->imms = n->myimms; pkt->ddseq = htonl(n->dds); length = sizeof(struct ospf_dbdes_packet); @@ -88,8 +119,8 @@ ospf_dbdes_send(struct ospf_neighbor *n, int next) ospf_pkt_fill_hdr(ifa, pkt, DBDES_P); pkt->iface_mtu = htons(ifa->iface->mtu); - pkt->options = oa->opt.byte; pkt->ddseq = htonl(n->dds); + pkt->options = hton_opt(oa->options); j = i = (ospf_pkt_maxsize(ifa) - sizeof(struct ospf_dbdes_packet)) / sizeof(struct ospf_lsa_header); /* Number of possible lsaheaders to send */ lsa = (n->ldbdes + sizeof(struct ospf_dbdes_packet)); @@ -102,16 +133,8 @@ ospf_dbdes_send(struct ospf_neighbor *n, int next) for (; i > 0; i--) { struct top_hash_entry *en= (struct top_hash_entry *) sn; - int send = 1; - /* Don't send ext LSA into stub areas */ - if (oa->stub && (en->lsa.type == LSA_T_EXT)) send = 0; - /* Don't send ext LSAs through VLINK */ - if ((ifa->type == OSPF_IT_VLINK) && (en->lsa.type == LSA_T_EXT)) send = 0;; - /* Don't send LSA of other areas */ - if ((en->lsa.type != LSA_T_EXT) && (en->oa != oa)) send = 0; - - if (send) + if (ospf_lsa_flooding_allowed(&en->lsa, en->domain, ifa)) { htonlsah(&(en->lsa), lsa); DBG("Working on: %d\n", i); @@ -204,13 +227,13 @@ ospf_dbdes_reqladd(struct ospf_dbdes_packet *ps, struct ospf_neighbor *n) for (i = 0; i < j; i++) { ntohlsah(plsa + i, &lsa); - if (((he = ospf_hash_find(gr, oa->areaid, lsa.id, lsa.rt, lsa.type)) == NULL) || + if (((he = ospfxx_hash_find_smart(gr, n->ifa, &lsa)) == NULL) || (lsa_comp(&lsa, &(he->lsa)) == 1)) { /* Is this condition necessary? */ - if (ospf_hash_find(n->lsrqh, oa->areaid, lsa.id, lsa.rt, lsa.type) == NULL) + if (ospfxx_hash_find_smart(n->lsrqh, n->ifa, &lsa) == NULL) { - sn = ospf_hash_get(n->lsrqh, oa, lsa.id, lsa.rt, lsa.type); + sn = ospfxx_hash_get_smart(n->lsrqh, n->ifa, &lsa); ntohlsah(plsa + i, &(sn->lsa)); s_add_tail(&(n->lsrql), SNODE sn); } @@ -219,13 +242,17 @@ ospf_dbdes_reqladd(struct ospf_dbdes_packet *ps, struct ospf_neighbor *n) } void -ospf_dbdes_receive(struct ospf_dbdes_packet *ps, - struct ospf_iface *ifa, struct ospf_neighbor *n) +ospf_dbdes_receive(struct ospf_packet *ps_i, struct ospf_iface *ifa, + struct ospf_neighbor *n) { + struct ospf_dbdes_packet *ps = (void *) ps_i; struct proto *p = &ifa->oa->po->proto; u32 myrid = p->cf->global->router_id; unsigned int size = ntohs(ps->ospf_packet.length); + u32 ps_ddseq = ntohl(ps->ddseq); + u32 ps_options = ntoh_opt(ps->options); + OSPF_PACKET(ospf_dump_dbdes, ps, "DBDES packet received from %I via %s", n->ip, ifa->iface->name); ospf_neigh_sm(n, INM_HELLOREC); @@ -246,9 +273,9 @@ ospf_dbdes_receive(struct ospf_dbdes_packet *ps, && (n->rid > myrid) && (size == sizeof(struct ospf_dbdes_packet))) { /* I'm slave! */ - n->dds = ntohl(ps->ddseq); - n->ddr = ntohl(ps->ddseq); - n->options = ps->options; + n->dds = ps_ddseq; + n->ddr = ps_ddseq; + n->options = ps_options; n->myimms.bit.ms = 0; n->imms.byte = ps->imms.byte; OSPF_TRACE(D_PACKETS, "I'm slave to %I.", n->ip); @@ -258,11 +285,11 @@ ospf_dbdes_receive(struct ospf_dbdes_packet *ps, } if (((ps->imms.bit.i == 0) && (ps->imms.bit.ms == 0)) && - (n->rid < myrid) && (n->dds == ntohl(ps->ddseq))) + (n->rid < myrid) && (n->dds == ps_ddseq)) { /* I'm master! */ - n->options = ps->options; - n->ddr = ntohl(ps->ddseq) - 1; /* It will be set corectly a few lines down */ + n->options = ps_options; + n->ddr = ps_ddseq - 1; /* It will be set corectly a few lines down */ n->imms.byte = ps->imms.byte; OSPF_TRACE(D_PACKETS, "I'm master to %I.", n->ip); ospf_neigh_sm(n, INM_NEGDONE); @@ -274,8 +301,8 @@ ospf_dbdes_receive(struct ospf_dbdes_packet *ps, break; } case NEIGHBOR_EXCHANGE: - if ((ps->imms.byte == n->imms.byte) && (ps->options == n->options) && - (ntohl(ps->ddseq) == n->ddr)) + if ((ps->imms.byte == n->imms.byte) && (ps_options == n->options) && + (ps_ddseq == n->ddr)) { /* Duplicate packet */ OSPF_TRACE(D_PACKETS, "Received duplicate dbdes from %I.", n->ip); @@ -287,7 +314,7 @@ ospf_dbdes_receive(struct ospf_dbdes_packet *ps, return; } - n->ddr = ntohl(ps->ddseq); + n->ddr = ps_ddseq; if (ps->imms.bit.ms != n->imms.bit.ms) /* M/S bit differs */ { @@ -307,7 +334,7 @@ ospf_dbdes_receive(struct ospf_dbdes_packet *ps, n->imms.byte = ps->imms.byte; - if (ps->options != n->options) /* Options differs */ + if (ps_options != n->options) /* Options differs */ { OSPF_TRACE(D_PACKETS, "dbdes - sequence mismatch neighbor %I (options)", n->ip); @@ -317,7 +344,7 @@ ospf_dbdes_receive(struct ospf_dbdes_packet *ps, if (n->myimms.bit.ms) { - if (ntohl(ps->ddseq) != n->dds) /* MASTER */ + if (ps_ddseq != n->dds) /* MASTER */ { OSPF_TRACE(D_PACKETS, "dbdes - sequence mismatch neighbor %I (master)", n->ip); @@ -339,15 +366,15 @@ ospf_dbdes_receive(struct ospf_dbdes_packet *ps, } else { - if (ntohl(ps->ddseq) != (n->dds + 1)) /* SLAVE */ + if (ps_ddseq != (n->dds + 1)) /* SLAVE */ { OSPF_TRACE(D_PACKETS, "dbdes - sequence mismatch neighbor %I (slave)", n->ip); ospf_neigh_sm(n, INM_SEQMIS); break; } - n->ddr = ntohl(ps->ddseq); - n->dds = ntohl(ps->ddseq); + n->ddr = ps_ddseq; + n->dds = ps_ddseq; ospf_dbdes_reqladd(ps, n); ospf_dbdes_send(n, 1); } @@ -355,8 +382,8 @@ ospf_dbdes_receive(struct ospf_dbdes_packet *ps, break; case NEIGHBOR_LOADING: case NEIGHBOR_FULL: - if ((ps->imms.byte == n->imms.byte) && (ps->options == n->options) - && (ntohl(ps->ddseq) == n->ddr)) + if ((ps->imms.byte == n->imms.byte) && (ps_options == n->options) + && (ps_ddseq == n->ddr)) /* Only duplicate are accepted */ { OSPF_TRACE(D_PACKETS, "Received duplicate dbdes from %I.", n->ip); @@ -371,7 +398,7 @@ ospf_dbdes_receive(struct ospf_dbdes_packet *ps, { OSPF_TRACE(D_PACKETS, "dbdes - sequence mismatch neighbor %I (full)", n->ip); - DBG("PS=%u, DDR=%u, DDS=%u\n", ntohl(ps->ddseq), n->ddr, n->dds); + DBG("PS=%u, DDR=%u, DDS=%u\n", ps_ddseq, n->ddr, n->dds); ospf_neigh_sm(n, INM_SEQMIS); } break; diff --git a/proto/ospf/dbdes.h b/proto/ospf/dbdes.h index af96292..63cca0a 100644 --- a/proto/ospf/dbdes.h +++ b/proto/ospf/dbdes.h @@ -11,7 +11,7 @@ #define _BIRD_OSPF_DBDES_H_ void ospf_dbdes_send(struct ospf_neighbor *n, int next); -void ospf_dbdes_receive(struct ospf_dbdes_packet *ps, - struct ospf_iface *ifa, struct ospf_neighbor *n); +void ospf_dbdes_receive(struct ospf_packet *ps, struct ospf_iface *ifa, + struct ospf_neighbor *n); #endif /* _BIRD_OSPF_DBDES_H_ */ diff --git a/proto/ospf/hello.c b/proto/ospf/hello.c index 45b6b61..7eeee3b 100644 --- a/proto/ospf/hello.c +++ b/proto/ospf/hello.c @@ -8,12 +8,46 @@ #include "ospf.h" + +#ifdef OSPFv2 +struct ospf_hello_packet +{ + struct ospf_packet ospf_packet; + ip_addr netmask; + u16 helloint; + u8 options; + u8 priority; + u32 deadint; + u32 dr; + u32 bdr; +}; +#endif + + +#ifdef OSPFv3 +struct ospf_hello_packet +{ + struct ospf_packet ospf_packet; + u32 iface_id; + u8 priority; + u8 options3; + u8 options2; + u8 options; + u16 helloint; + u16 deadint; + u32 dr; + u32 bdr; +}; +#endif + + void -ospf_hello_receive(struct ospf_hello_packet *ps, - struct ospf_iface *ifa, struct ospf_neighbor *n, ip_addr faddr) +ospf_hello_receive(struct ospf_packet *ps_i, struct ospf_iface *ifa, + struct ospf_neighbor *n, ip_addr faddr) { + struct ospf_hello_packet *ps = (void *) ps_i; u32 *pnrid; - ip_addr olddr, oldbdr; + u32 olddr, oldbdr, oldiface_id, tmp; ip_addr mask; char *beg = "Bad OSPF hello packet from ", *rec = " received: "; struct proto *p = (struct proto *) ifa->oa->po; @@ -21,9 +55,10 @@ ospf_hello_receive(struct ospf_hello_packet *ps, OSPF_TRACE(D_PACKETS, "HELLO packet received from %I via %s%s", faddr, (ifa->type == OSPF_IT_VLINK ? "vlink-" : ""), ifa->iface->name); + +#ifdef OSPFv2 mask = ps->netmask; ipa_ntoh(mask); - if (ifa->type != OSPF_IT_VLINK) { char *msg = L_WARN "Received HELLO packet %s (%I) is inconsistent " @@ -50,24 +85,30 @@ ospf_hello_receive(struct ospf_hello_packet *ps, return; } } +#endif - if (ntohs(ps->helloint) != ifa->helloint) + tmp = ntohs(ps->helloint); + if (tmp != ifa->helloint) { - log(L_ERR "%s%I%shello interval mismatch (%d).", beg, faddr, rec, - ntohs(ps->helloint)); + log(L_ERR "%s%I%shello interval mismatch (%d).", beg, faddr, rec, tmp); return; } - if (ntohl(ps->deadint) != ifa->dead) +#ifdef OSPFv2 + tmp = ntohl(ps->deadint); +#else /* OSPFv3 */ + tmp = ntohs(ps->deadint); +#endif + if (tmp != ifa->dead) { - log(L_ERR "%s%I%sdead interval mismatch (%d).", beg, faddr, rec, - ntohl(ps->deadint)); + log(L_ERR "%s%I%sdead interval mismatch (%d).", beg, faddr, rec, tmp); return; } - if (ps->options != ifa->oa->opt.byte) + tmp = !(ps->options & OPT_E); + if (tmp != ifa->oa->stub) { - log(L_ERR "%s%I%soptions mismatch (0x%x).", beg, faddr, rec, ps->options); + log(L_ERR "%s%I%sstub area flag mismatch (%d).", beg, faddr, rec, tmp); return; } @@ -111,12 +152,12 @@ ospf_hello_receive(struct ospf_hello_packet *ps, n->rid = ntohl(((struct ospf_packet *) ps)->routerid); n->ip = faddr; - n->dr = ps->dr; - ipa_ntoh(n->dr); - n->bdr = ps->bdr; - ipa_ntoh(n->bdr); + n->dr = ntohl(ps->dr); + n->bdr = ntohl(ps->bdr); n->priority = ps->priority; - n->options = ps->options; +#ifdef OSPFv3 + n->iface_id = ntohl(ps->iface_id); +#endif } ospf_neigh_sm(n, INM_HELLOREC); @@ -140,35 +181,54 @@ ospf_hello_receive(struct ospf_hello_packet *ps, ospf_neigh_sm(n, INM_1WAYREC); olddr = n->dr; - n->dr = ipa_ntoh(ps->dr); oldbdr = n->bdr; - n->bdr = ipa_ntoh(ps->bdr); oldpriority = n->priority; +#ifdef OSPFv3 + oldiface_id = n->iface_id; +#endif + + n->dr = ntohl(ps->dr); + n->bdr = ntohl(ps->bdr); n->priority = ps->priority; +#ifdef OSPFv3 + n->iface_id = ntohl(ps->iface_id); +#endif + /* Check priority change */ if (n->state >= NEIGHBOR_2WAY) { +#ifdef OSPFv2 + u32 rid = n->ip; +#else /* OSPFv3 */ + u32 rid = p->cf->global->router_id; +#endif + if (n->priority != oldpriority) ospf_iface_sm(ifa, ISM_NEICH); +#ifdef OSPFv3 + if (n->iface_id != oldiface_id) + ospf_iface_sm(ifa, ISM_NEICH); +#endif + /* Router is declaring itself ad DR and there is no BDR */ - if (ipa_equal(n->ip, n->dr) && (ipa_to_u32(n->bdr) == 0) + if ((rid == n->dr) && (n->bdr == 0) && (n->state != NEIGHBOR_FULL)) ospf_iface_sm(ifa, ISM_BACKS); /* Neighbor is declaring itself as BDR */ - if (ipa_equal(n->ip, n->bdr) && (n->state != NEIGHBOR_FULL)) + if ((rid == n->bdr) && (n->state != NEIGHBOR_FULL)) ospf_iface_sm(ifa, ISM_BACKS); /* Neighbor is newly declaring itself as DR or BDR */ - if ((ipa_equal(n->ip, n->dr) && (!ipa_equal(n->dr, olddr))) - || (ipa_equal(n->ip, n->bdr) && (!ipa_equal(n->bdr, oldbdr)))) + if (((rid == n->dr) && (n->dr != olddr)) + || ((rid == n->bdr) && (n->bdr != oldbdr))) ospf_iface_sm(ifa, ISM_NEICH); /* Neighbor is no more declaring itself as DR or BDR */ - if ((ipa_equal(n->ip, olddr) && (!ipa_equal(n->dr, olddr))) - || (ipa_equal(n->ip, oldbdr) && (!ipa_equal(n->bdr, oldbdr)))) + if (((rid == olddr) && (n->dr != olddr)) + || ((rid == oldbdr) && (n->bdr != oldbdr))) ospf_iface_sm(ifa, ISM_NEICH); } @@ -181,7 +241,7 @@ ospf_hello_receive(struct ospf_hello_packet *ps, } void -ospf_hello_send(timer * timer, int poll, struct ospf_neighbor *dirn) +ospf_hello_send(timer *timer, int poll, struct ospf_neighbor *dirn) { struct ospf_iface *ifa; struct ospf_hello_packet *pkt; @@ -223,18 +283,33 @@ ospf_hello_send(timer * timer, int poll, struct ospf_neighbor *dirn) ospf_pkt_fill_hdr(ifa, pkt, HELLO_P); +#ifdef OSPFv2 pkt->netmask = ipa_mkmask(ifa->iface->addr->pxlen); ipa_hton(pkt->netmask); if ((ifa->type == OSPF_IT_VLINK) || (ifa->type == OSPF_IT_PTP)) pkt->netmask = IPA_NONE; +#endif + pkt->helloint = ntohs(ifa->helloint); - pkt->options = ifa->oa->opt.byte; pkt->priority = ifa->priority; + +#ifdef OSPFv3 + pkt->iface_id = htonl(ifa->iface->index); + + pkt->options3 = ifa->oa->options >> 16; + pkt->options2 = ifa->oa->options >> 8; +#endif + pkt->options = ifa->oa->options; + +#ifdef OSPFv2 pkt->deadint = htonl(ifa->dead); - pkt->dr = ifa->drip; - ipa_hton(pkt->dr); - pkt->bdr = ifa->bdrip; - ipa_hton(pkt->bdr); + pkt->dr = htonl(ipa_to_u32(ifa->drip)); + pkt->bdr = htonl(ipa_to_u32(ifa->bdrip)); +#else /* OSPFv3 */ + pkt->deadint = htons(ifa->dead); + pkt->dr = htonl(ifa->drid); + pkt->bdr = htonl(ifa->bdrid); +#endif /* Fill all neighbors */ i = 0; diff --git a/proto/ospf/hello.h b/proto/ospf/hello.h index d535935..5d73c09 100644 --- a/proto/ospf/hello.h +++ b/proto/ospf/hello.h @@ -10,8 +10,8 @@ #ifndef _BIRD_OSPF_HELLO_H_ #define _BIRD_OSPF_HELLO_H_ -void ospf_hello_receive(struct ospf_hello_packet *ps, - struct ospf_iface *ifa, struct ospf_neighbor *n, ip_addr faddr); +void ospf_hello_receive(struct ospf_packet *ps_i, struct ospf_iface *ifa, + struct ospf_neighbor *n, ip_addr faddr); void ospf_hello_send(timer *timer, int poll, struct ospf_neighbor *dirn); #endif /* _BIRD_OSPF_HELLO_H_ */ diff --git a/proto/ospf/iface.c b/proto/ospf/iface.c index ea38461..ea3baa2 100644 --- a/proto/ospf/iface.c +++ b/proto/ospf/iface.c @@ -157,16 +157,16 @@ ospf_iface_chstate(struct ospf_iface *ifa, u8 state) rfree(ifa->dr_sk); ifa->dr_sk = NULL; } - if ((oldstate == OSPF_IS_DR) && (ifa->nlsa != NULL)) + if ((oldstate == OSPF_IS_DR) && (ifa->net_lsa != NULL)) { - ifa->nlsa->lsa.age = LSA_MAXAGE; + ifa->net_lsa->lsa.age = LSA_MAXAGE; if (state >= OSPF_IS_WAITING) { - ospf_lsupd_flush_nlsa(ifa->nlsa, ifa->oa); + ospf_lsupd_flush_nlsa(po, ifa->net_lsa); } if (can_flush_lsa(po)) - flush_lsa(ifa->nlsa, po); - ifa->nlsa = NULL; + flush_lsa(ifa->net_lsa, po); + ifa->net_lsa = NULL; } } } @@ -412,8 +412,16 @@ ospf_iface_new(struct proto_ospf *po, struct iface *iface, ifa->waitint = ip->waitint; ifa->dead = (ip->dead == 0) ? ip->deadc * ifa->helloint : ip->dead; ifa->stub = ip->stub; + +#ifdef OSPFv2 ifa->autype = ip->autype; ifa->passwords = ip->passwords; +#endif + +#ifdef OSPFv3 + ifa->instance_id = ip->instance_id; +#endif + ifa->rxbuf = ip->rxbuf; if (ip->type == OSPF_IT_UNDEF) diff --git a/proto/ospf/lsack.c b/proto/ospf/lsack.c index 824767a..7871b8f 100644 --- a/proto/ospf/lsack.c +++ b/proto/ospf/lsack.c @@ -8,6 +8,14 @@ #include "ospf.h" + +struct ospf_lsack_packet +{ + struct ospf_packet ospf_packet; + struct ospf_lsa_header lsh[]; +}; + + char *s_queue[] = { "direct", "delayed" }; @@ -18,14 +26,12 @@ static void ospf_dump_lsack(struct proto *p, struct ospf_lsack_packet *pkt) ASSERT(op->type == LSACK_P); ospf_dump_common(p, op); - struct ospf_lsa_header *plsa = (void *) (pkt + 1); int i, j; - j = (ntohs(op->length) - sizeof(struct ospf_lsack_packet)) / sizeof(struct ospf_lsa_header); for (i = 0; i < j; i++) - ospf_dump_lsahdr(p, plsa + i); + ospf_dump_lsahdr(p, pkt->lsh + i); } @@ -70,7 +76,7 @@ ospf_lsack_send(struct ospf_neighbor *n, int queue) op = (struct ospf_packet *) sk->tbuf; ospf_pkt_fill_hdr(n->ifa, pk, LSACK_P); - h = (struct ospf_lsa_header *) (pk + 1); + h = pk->lsh; while (!EMPTY_LIST(n->ackl[queue])) { @@ -141,10 +147,11 @@ ospf_lsack_send(struct ospf_neighbor *n, int queue) } void -ospf_lsack_receive(struct ospf_lsack_packet *ps, - struct ospf_iface *ifa, struct ospf_neighbor *n) +ospf_lsack_receive(struct ospf_packet *ps_i, struct ospf_iface *ifa, + struct ospf_neighbor *n) { - struct ospf_lsa_header lsa, *plsa; + struct ospf_lsack_packet *ps = (void *) ps_i; + struct ospf_lsa_header lsa; u16 nolsa; struct top_hash_entry *en; struct proto *p = &ifa->oa->po->proto; @@ -167,12 +174,10 @@ ospf_lsack_receive(struct ospf_lsack_packet *ps, return; } - plsa = (struct ospf_lsa_header *) (ps + 1); - for (i = 0; i < nolsa; i++) { - ntohlsah(plsa + i, &lsa); - if ((en = ospf_hash_find_header(n->lsrth, n->ifa->oa->areaid, &lsa)) == NULL) + ntohlsah(ps->lsh + i, &lsa); + if ((en = ospfxx_hash_find_smart(n->lsrth, n->ifa, &lsa)) == NULL) continue; /* pg 155 */ if (lsa_comp(&lsa, &en->lsa) != CMP_SAME) /* pg 156 */ diff --git a/proto/ospf/lsack.h b/proto/ospf/lsack.h index 05cc22f..63a436d 100644 --- a/proto/ospf/lsack.h +++ b/proto/ospf/lsack.h @@ -16,8 +16,8 @@ struct lsah_n struct ospf_lsa_header lsa; }; -void ospf_lsack_receive(struct ospf_lsack_packet *ps, - struct ospf_iface *ifa, struct ospf_neighbor *n); +void ospf_lsack_receive(struct ospf_packet *ps_i, struct ospf_iface *ifa, + struct ospf_neighbor *n); void ospf_lsack_send(struct ospf_neighbor *n, int queue); void ospf_lsack_enqueue(struct ospf_neighbor *n, struct ospf_lsa_header *h, int queue); diff --git a/proto/ospf/lsalib.c b/proto/ospf/lsalib.c index e624b6c..7c4001d 100644 --- a/proto/ospf/lsalib.c +++ b/proto/ospf/lsalib.c @@ -65,8 +65,8 @@ ospf_age(struct proto_ospf *po) flush_lsa(en, po); continue; } - if ((en->lsa.rt == p->cf->global->router_id) &&(en->lsa.age >= - LSREFRESHTIME)) + if ((en->lsa.rt == p->cf->global->router_id) && + (en->lsa.age >= LSREFRESHTIME)) { OSPF_TRACE(D_EVENTS, "Refreshing my LSA: Type: %u, Id: %R, Rt: %R", en->lsa.type, en->lsa.id, en->lsa.rt); @@ -75,7 +75,7 @@ ospf_age(struct proto_ospf *po) en->inst_t = now; en->ini_age = 0; lsasum_calculate(&en->lsa, en->lsa_body); - ospf_lsupd_flood(NULL, NULL, &en->lsa, NULL, en->oa, 1); + ospf_lsupd_flood(po, NULL, NULL, &en->lsa, en->domain, 1); continue; } if ((en->lsa.age = (en->ini_age + (now - en->inst_t))) >= LSA_MAXAGE) @@ -96,7 +96,9 @@ void htonlsah(struct ospf_lsa_header *h, struct ospf_lsa_header *n) { n->age = htons(h->age); +#ifdef OSPFv2 n->options = h->options; +#endif n->type = h->type; n->id = htonl(h->id); n->rt = htonl(h->rt); @@ -109,7 +111,9 @@ void ntohlsah(struct ospf_lsa_header *n, struct ospf_lsa_header *h) { h->age = ntohs(n->age); +#ifdef OSPFv2 h->options = n->options; +#endif h->type = n->type; h->id = ntohl(n->id); h->rt = ntohl(n->rt); @@ -119,7 +123,7 @@ ntohlsah(struct ospf_lsa_header *n, struct ospf_lsa_header *h) }; void -htonlsab(void *h, void *n, u8 type, u16 len) +htonlsab(void *h, void *n, u16 type, u16 len) { unsigned int i; switch (type) @@ -132,24 +136,43 @@ htonlsab(void *h, void *n, u8 type, u16 len) nrt = n; hrt = h; - links = hrt->links; +#ifdef OSPFv2 nrt->veb.byte = hrt->veb.byte; nrt->padding = 0; nrt->links = htons(hrt->links); + links = hrt->links; +#else /* OSPFv3 */ + hrt->options = htonl(nrt->options); + links = (len - sizeof(struct ospf_lsa_rt)) / + sizeof(struct ospf_lsa_rt_link); +#endif + nrtl = (struct ospf_lsa_rt_link *) (nrt + 1); hrtl = (struct ospf_lsa_rt_link *) (hrt + 1); for (i = 0; i < links; i++) { - (nrtl + i)->id = htonl((hrtl + i)->id); - (nrtl + i)->data = htonl((hrtl + i)->data); - (nrtl + i)->type = (hrtl + i)->type; - (nrtl + i)->notos = (hrtl + i)->notos; - (nrtl + i)->metric = htons((hrtl + i)->metric); +#ifdef OSPFv2 + nrtl[i].id = htonl(hrtl[i].id); + nrtl[i].data = htonl(hrtl[i].data); + nrtl[i].type = hrtl[i].type; + nrtl[i].notos = hrtl[i].notos; + nrtl[i].metric = htons(hrtl[i].metric); +#else /* OSPFv3 */ + nrtl[i].type = hrtl[i].type; + nrtl[i].padding = 0; + nrtl[i].metric = htons(hrtl[i].metric); + nrtl[i].lif = htonl(hrtl[i].lif); + nrtl[i].nif = htonl(hrtl[i].nif); + nrtl[i].id = htonl(hrtl[i].id); +#endif } break; } case LSA_T_NET: + case LSA_T_SUM_NET: + case LSA_T_SUM_RT: + case LSA_T_EXT: { u32 *hid, *nid; @@ -162,59 +185,14 @@ htonlsab(void *h, void *n, u8 type, u16 len) } break; } - case LSA_T_SUM_NET: - case LSA_T_SUM_RT: - { - struct ospf_lsa_sum *hs, *ns; - union ospf_lsa_sum_tm *hn, *nn; - - hs = h; - ns = n; - - ns->netmask = hs->netmask; - ipa_hton(ns->netmask); - - hn = (union ospf_lsa_sum_tm *) (hs + 1); - nn = (union ospf_lsa_sum_tm *) (ns + 1); - for (i = 0; i < ((len - sizeof(struct ospf_lsa_sum)) / - sizeof(union ospf_lsa_sum_tm)); i++) - { - (nn + i)->metric = htonl((hn + i)->metric); - } - break; - } - case LSA_T_EXT: - { - struct ospf_lsa_ext *he, *ne; - struct ospf_lsa_ext_tos *ht, *nt; - - he = h; - ne = n; - - ne->netmask = he->netmask; - ipa_hton(ne->netmask); - - ht = (struct ospf_lsa_ext_tos *) (he + 1); - nt = (struct ospf_lsa_ext_tos *) (ne + 1); - - for (i = 0; i < ((len - sizeof(struct ospf_lsa_ext)) / - sizeof(struct ospf_lsa_ext_tos)); i++) - { - (nt + i)->etm.metric = htonl((ht + i)->etm.metric); - (nt + i)->fwaddr = (ht + i)->fwaddr; - ipa_hton((nt + i)->fwaddr); - (nt + i)->tag = htonl((ht + i)->tag); - } - break; - } default: bug("(hton): Unknown LSA"); } }; void -ntohlsab(void *n, void *h, u8 type, u16 len) +ntohlsab(void *n, void *h, u16 type, u16 len) { unsigned int i; switch (type) @@ -228,22 +206,41 @@ ntohlsab(void *n, void *h, u8 type, u16 len) nrt = n; hrt = h; +#ifdef OSPFv2 hrt->veb.byte = nrt->veb.byte; hrt->padding = 0; links = hrt->links = ntohs(nrt->links); +#else /* OSPFv3 */ + hrt->options = ntohl(nrt->options); + links = (len - sizeof(struct ospf_lsa_rt)) / + sizeof(struct ospf_lsa_rt_link); +#endif + nrtl = (struct ospf_lsa_rt_link *) (nrt + 1); hrtl = (struct ospf_lsa_rt_link *) (hrt + 1); for (i = 0; i < links; i++) { - (hrtl + i)->id = ntohl((nrtl + i)->id); - (hrtl + i)->data = ntohl((nrtl + i)->data); - (hrtl + i)->type = (nrtl + i)->type; - (hrtl + i)->notos = (nrtl + i)->notos; - (hrtl + i)->metric = ntohs((nrtl + i)->metric); +#ifdef OSPFv2 + hrtl[i].id = ntohl(nrtl[i].id); + hrtl[i].data = ntohl(nrtl[i].data); + hrtl[i].type = nrtl[i].type; + hrtl[i].notos = nrtl[i].notos; + hrtl[i].metric = ntohs(nrtl[i].metric); +#else /* OSPFv3 */ + hrtl[i].type = nrtl[i].type; + hrtl[i].padding = 0; + hrtl[i].metric = ntohs(nrtl[i].metric); + hrtl[i].lif = ntohl(nrtl[i].lif); + hrtl[i].nif = ntohl(nrtl[i].nif); + hrtl[i].id = ntohl(nrtl[i].id); +#endif } break; } case LSA_T_NET: + case LSA_T_SUM_NET: + case LSA_T_SUM_RT: + case LSA_T_EXT: { u32 *hid, *nid; @@ -252,53 +249,7 @@ ntohlsab(void *n, void *h, u8 type, u16 len) for (i = 0; i < (len / sizeof(u32)); i++) { - *(hid + i) = ntohl(*(nid + i)); - } - break; - } - case LSA_T_SUM_NET: - case LSA_T_SUM_RT: - { - struct ospf_lsa_sum *hs, *ns; - union ospf_lsa_sum_tm *hn, *nn; - - hs = h; - ns = n; - - hs->netmask = ns->netmask; - ipa_ntoh(hs->netmask); - - hn = (union ospf_lsa_sum_tm *) (hs + 1); - nn = (union ospf_lsa_sum_tm *) (ns + 1); - - for (i = 0; i < ((len - sizeof(struct ospf_lsa_sum)) / - sizeof(union ospf_lsa_sum_tm)); i++) - { - (hn + i)->metric = ntohl((nn + i)->metric); - } - break; - } - case LSA_T_EXT: - { - struct ospf_lsa_ext *he, *ne; - struct ospf_lsa_ext_tos *ht, *nt; - - he = h; - ne = n; - - he->netmask = ne->netmask; - ipa_ntoh(he->netmask); - - ht = (struct ospf_lsa_ext_tos *) (he + 1); - nt = (struct ospf_lsa_ext_tos *) (ne + 1); - - for (i = 0; i < ((len - sizeof(struct ospf_lsa_ext)) / - sizeof(struct ospf_lsa_ext_tos)); i++) - { - (ht + i)->etm.metric = ntohl((nt + i)->etm.metric); - (ht + i)->fwaddr = (nt + i)->fwaddr; - ipa_ntoh((ht + i)->fwaddr); - (ht + i)->tag = ntohl((nt + i)->tag); + hid[i] = ntohl(nid[i]); } break; } @@ -343,7 +294,8 @@ lsasum_check(struct ospf_lsa_header *h, void *body) u16 length; b = body; - sp = (char *) &h->options; + sp = (char *) &h; + sp += 2; /* Skip Age field */ length = ntohs(h->length) - 2; h->checksum = 0; @@ -417,45 +369,40 @@ lsa_comp(struct ospf_lsa_header *l1, struct ospf_lsa_header *l2) /** * lsa_install_new - install new LSA into database + * @po: OSPF protocol * @lsa: LSA header + * @domain: domain of LSA * @body: pointer to LSA body - * @oa: current ospf_area + * * This function ensures installing new LSA into LSA database. Old instance is * replaced. Several actions are taken to detect if new routing table * calculation is necessary. This is described in 13.2 of RFC 2328. */ struct top_hash_entry * -lsa_install_new(struct ospf_lsa_header *lsa, void *body, struct ospf_area *oa) +lsa_install_new(struct proto_ospf *po, struct ospf_lsa_header *lsa, u32 domain, void *body) { /* LSA can be temporarrily, but body must be mb_allocated. */ int change = 0; unsigned i; struct top_hash_entry *en; - struct proto_ospf *po = oa->po; - if ((en = ospf_hash_find_header(po->gr, oa->areaid, lsa)) == NULL) + if ((en = ospfxx_hash_find_header(po->gr, domain, lsa)) == NULL) { - en = ospf_hash_get_header(po->gr, oa, lsa); + en = ospfxx_hash_get_header(po->gr, domain, lsa); change = 1; } else { - if ((en->lsa.length != lsa->length) || (en->lsa.options != lsa->options) - || ((en->lsa.age == LSA_MAXAGE) || (lsa->age == LSA_MAXAGE))) + if ((en->lsa.length != lsa->length) +#ifdef OSPFv2 + || (en->lsa.options != lsa->options) +#endif + || (en->lsa.age == LSA_MAXAGE) + || (lsa->age == LSA_MAXAGE) + || memcmp(en->lsa_body, body, lsa->length - sizeof(struct ospf_lsa_header))) change = 1; - else - { - u8 *k = en->lsa_body, *l = body; - for (i = 0; i < (lsa->length - sizeof(struct ospf_lsa_header)); i++) - { - if (*(k + i) != *(l + i)) - { - change = 1; - break; - } - } - } + s_rem_node(SNODE en); } diff --git a/proto/ospf/lsalib.h b/proto/ospf/lsalib.h index c7f16d5..640fa17 100644 --- a/proto/ospf/lsalib.h +++ b/proto/ospf/lsalib.h @@ -12,16 +12,15 @@ void htonlsah(struct ospf_lsa_header *h, struct ospf_lsa_header *n); void ntohlsah(struct ospf_lsa_header *n, struct ospf_lsa_header *h); -void htonlsab(void *h, void *n, u8 type, u16 len); -void ntohlsab(void *n, void *h, u8 type, u16 len); +void htonlsab(void *h, void *n, u16 type, u16 len); +void ntohlsab(void *n, void *h, u16 type, u16 len); void lsasum_calculate(struct ospf_lsa_header *header, void *body); u16 lsasum_check(struct ospf_lsa_header *h, void *body); #define CMP_NEWER 1 #define CMP_SAME 0 #define CMP_OLDER -1 int lsa_comp(struct ospf_lsa_header *l1, struct ospf_lsa_header *l2); -struct top_hash_entry *lsa_install_new(struct ospf_lsa_header *lsa, - void *body, struct ospf_area *oa); +struct top_hash_entry * lsa_install_new(struct proto_ospf *po, struct ospf_lsa_header *lsa, u32 domain, void *body); void ospf_age(struct proto_ospf *po); void flush_lsa(struct top_hash_entry *en, struct proto_ospf *po); diff --git a/proto/ospf/lsreq.c b/proto/ospf/lsreq.c index 5eeb06f..cc5afa0 100644 --- a/proto/ospf/lsreq.c +++ b/proto/ospf/lsreq.c @@ -8,6 +8,14 @@ #include "ospf.h" + +struct ospf_lsreq_packet +{ + struct ospf_packet ospf_packet; + struct ospf_lsreq_header lsh[]; +}; + + static void ospf_dump_lsreq(struct proto *p, struct ospf_lsreq_packet *pkt) { struct ospf_packet *op = &pkt->ospf_packet; @@ -15,15 +23,13 @@ static void ospf_dump_lsreq(struct proto *p, struct ospf_lsreq_packet *pkt) ASSERT(op->type == LSREQ_P); ospf_dump_common(p, op); - struct ospf_lsreq_header *plsr = (void *) (pkt + 1); int i, j; - - j = (ntohs(op->length) - sizeof(struct ospf_dbdes_packet)) / + j = (ntohs(op->length) - sizeof(struct ospf_lsreq_packet)) / sizeof(struct ospf_lsreq_header); for (i = 0; i < j; i++) - log(L_TRACE "%s: LSR Id: %R, Rt: %R, Type: %u", - p->name, htonl(plsr[i].id), htonl(plsr[i].rt), plsr[i].type); + log(L_TRACE "%s: LSR Id: %R, Rt: %R, Type: %u", p->name, + htonl(pkt->lsh[i].id), htonl(pkt->lsh[i].rt), pkt->lsh[i].type); } void @@ -53,14 +59,12 @@ ospf_lsreq_send(struct ospf_neighbor *n) i = j = (ospf_pkt_maxsize(n->ifa) - sizeof(struct ospf_lsreq_packet)) / sizeof(struct ospf_lsreq_header); - lsh = (struct ospf_lsreq_header *) (pk + 1); + lsh = pk->lsh; for (; i > 0; i--) { en = (struct top_hash_entry *) sn; - lsh->padd1 = 0; - lsh->padd2 = 0; - lsh->type = en->lsa.type; + 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", @@ -84,9 +88,10 @@ ospf_lsreq_send(struct ospf_neighbor *n) } void -ospf_lsreq_receive(struct ospf_lsreq_packet *ps, - struct ospf_iface *ifa, struct ospf_neighbor *n) +ospf_lsreq_receive(struct ospf_packet *ps_i, struct ospf_iface *ifa, + struct ospf_neighbor *n) { + struct ospf_lsreq_packet *ps = (void *) ps_i; struct ospf_lsreq_header *lsh; struct l_lsr_head *llsh; list uplist; @@ -104,7 +109,7 @@ ospf_lsreq_receive(struct ospf_lsreq_packet *ps, ospf_neigh_sm(n, INM_HELLOREC); - lsh = (void *) (ps + 1); + lsh = ps->lsh; init_list(&uplist); upslab = sl_new(n->pool, sizeof(struct l_lsr_head)); @@ -114,18 +119,19 @@ ospf_lsreq_receive(struct ospf_lsreq_packet *ps, { 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 = lsh->type; + llsh->lsh.type = htype; add_tail(&uplist, NODE llsh); - if (ospf_hash_find(po->gr, oa->areaid, llsh->lsh.id, llsh->lsh.rt, - llsh->lsh.type) == NULL) + if (ospfxx_hash_find(po->gr, dom, hid, hrt, htype) == NULL) { log(L_WARN "Received bad LS req from: %I looking: Type: %u, ID: %R, RT: %R", - n->ip, lsh->type, hid, hrt); + n->ip, htype, hid, hrt); ospf_neigh_sm(n, INM_BADLSREQ); rfree(upslab); return; diff --git a/proto/ospf/lsreq.h b/proto/ospf/lsreq.h index f917f05..a12edde 100644 --- a/proto/ospf/lsreq.h +++ b/proto/ospf/lsreq.h @@ -11,7 +11,7 @@ #define _BIRD_OSPF_LSREQ_H_ void ospf_lsreq_send(struct ospf_neighbor *n); -void ospf_lsreq_receive(struct ospf_lsreq_packet *ps, - struct ospf_iface *ifa, struct ospf_neighbor *n); +void ospf_lsreq_receive(struct ospf_packet *ps_i, struct ospf_iface *ifa, + struct ospf_neighbor *n); #endif /* _BIRD_OSPF_LSREQ_H_ */ 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); } diff --git a/proto/ospf/lsupd.h b/proto/ospf/lsupd.h index 524a0a2..8bacfe6 100644 --- a/proto/ospf/lsupd.h +++ b/proto/ospf/lsupd.h @@ -13,11 +13,13 @@ void ospf_dump_lsahdr(struct proto *p, struct ospf_lsa_header *lsa_n); void ospf_dump_common(struct proto *p, struct ospf_packet *op); void ospf_lsupd_send_list(struct ospf_neighbor *n, list * l); -void ospf_lsupd_receive(struct ospf_lsupd_packet *ps, +void ospf_lsupd_receive(struct ospf_packet *ps_i, struct ospf_iface *ifa, struct ospf_neighbor *n); -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); -void ospf_lsupd_flush_nlsa(struct top_hash_entry *en, struct ospf_area *oa); +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); + #endif /* _BIRD_OSPF_LSUPD_H_ */ diff --git a/proto/ospf/neighbor.c b/proto/ospf/neighbor.c index bb681c2..d86895e 100644 --- a/proto/ospf/neighbor.c +++ b/proto/ospf/neighbor.c @@ -171,16 +171,23 @@ static struct ospf_neighbor * electbdr(list nl) { struct ospf_neighbor *neigh, *n1, *n2; + u32 nid; + +#ifdef OSPFv2 + nid = ipa_to_u32(neigh->ip); +#else /* OSPFv3 */ + nid = neigh->rid; +#endif n1 = NULL; n2 = NULL; - WALK_LIST(neigh, nl) /* First try those decl. themselves */ + WALK_LIST(neigh, nl) /* First try those decl. themselves */ { if (neigh->state >= NEIGHBOR_2WAY) /* Higher than 2WAY */ - if (neigh->priority > 0) /* Eligible */ - if (ipa_compare(neigh->ip, neigh->dr) != 0) /* And not decl. itself DR */ + if (neigh->priority > 0) /* Eligible */ + if (neigh->dr != nid) /* And not decl. itself DR */ { - if (ipa_compare(neigh->ip, neigh->bdr) == 0) /* Declaring BDR */ + if (neigh->bdr == nid) /* Declaring BDR */ { if (n1 != NULL) { @@ -222,13 +229,20 @@ static struct ospf_neighbor * electdr(list nl) { struct ospf_neighbor *neigh, *n; + u32 nid; + +#ifdef OSPFv2 + nid = ipa_to_u32(neigh->ip); +#else /* OSPFv3 */ + nid = neigh->rid; +#endif n = NULL; - WALK_LIST(neigh, nl) /* And now DR */ + WALK_LIST(neigh, nl) /* And now DR */ { if (neigh->state >= NEIGHBOR_2WAY) /* Higher than 2WAY */ - if (neigh->priority > 0) /* Eligible */ - if (ipa_compare(neigh->ip, neigh->dr) == 0) /* And declaring itself DR */ + if (neigh->priority > 0) /* Eligible */ + if (neigh->dr == nid) /* And declaring itself DR */ { if (n != NULL) { @@ -427,7 +441,6 @@ bdr_election(struct ospf_iface *ifa) { struct ospf_neighbor *neigh, *ndr, *nbdr, me; u32 myid; - ip_addr ndrip, nbdrip; int doadj; struct proto *p = &ifa->oa->po->proto; @@ -438,10 +451,17 @@ bdr_election(struct ospf_iface *ifa) me.state = NEIGHBOR_2WAY; me.rid = myid; me.priority = ifa->priority; - me.dr = ifa->drip; - me.bdr = ifa->bdrip; me.ip = ifa->iface->addr->ip; +#ifdef OSPFv2 + me.dr = ipa_to_u32(ifa->drip); + me.bdr = ipa_to_u32(ifa->bdrip); +#else /* OSPFv3 */ + me.dr = ifa->drid; + me.bdr = ifa->bdrid; + me.iface_id = ifa->iface->index; +#endif + add_tail(&ifa->neigh_list, NODE & me); nbdr = electbdr(ifa->neigh_list); @@ -450,64 +470,43 @@ bdr_election(struct ospf_iface *ifa) if (ndr == NULL) ndr = nbdr; + /* 9.4. (4) */ if (((ifa->drid == myid) && (ndr != &me)) || ((ifa->drid != myid) && (ndr == &me)) || ((ifa->bdrid == myid) && (nbdr != &me)) || ((ifa->bdrid != myid) && (nbdr == &me))) { - if (ndr == NULL) - ifa->drip = me.dr = IPA_NONE; - else - ifa->drip = me.dr = ndr->ip; - - if (nbdr == NULL) - ifa->bdrip = me.bdr = IPA_NONE; - else - ifa->bdrip = me.bdr = nbdr->ip; +#ifdef OSPFv2 + me.dr = ndr ? ipa_to_u32(ndr->ip) : IPA_NONE; + me.bdr = nbdr ? ipa_to_u32(nbdr->ip) : IPA_NONE; +#else /* OSPFv3 */ + me.dr = ndr ? ndr->rid : 0; + me.bdr = nbdr ? nbdr->rid : 0; +#endif nbdr = electbdr(ifa->neigh_list); ndr = electdr(ifa->neigh_list); - } - - if (ndr == NULL) - ndrip = IPA_NONE; - else - ndrip = ndr->ip; - - if (nbdr == NULL) - nbdrip = IPA_NONE; - else - nbdrip = nbdr->ip; - - doadj = 0; - if ((ipa_compare(ifa->drip, ndrip) != 0) - || (ipa_compare(ifa->bdrip, nbdrip) != 0)) - doadj = 1; - if (ndr == NULL) - { - ifa->drid = 0; - ifa->drip = IPA_NONE; - } - else - { - ifa->drid = ndr->rid; - ifa->drip = ndr->ip; + if (ndr == NULL) + ndr = nbdr; } - if (nbdr == NULL) - { - ifa->bdrid = 0; - ifa->bdrip = IPA_NONE; - } - else - { - ifa->bdrid = nbdr->rid; - ifa->bdrip = nbdr->ip; - } + u32 odrid = ifa->drid; + u32 obdrid = ifa->bdrid; + + ifa->drid = ndr ? ndr->rid : 0; + ifa->drip = ndr ? ndr->ip : IPA_NONE; + ifa->bdrid = nbdr ? nbdr->rid : 0; + ifa->bdrip = nbdr ? nbdr->ip : IPA_NONE; + +#ifdef OSPFv3 + ifa->dr_iface_id = ndr ? ndr->iface_id : 0; +#endif DBG("DR=%R, BDR=%R\n", ifa->drid, ifa->bdrid); + doadj = ((ifa->drid != odrid) || (ifa->bdrid != obdrid)); + if (myid == ifa->drid) ospf_iface_chstate(ifa, OSPF_IS_DR); else diff --git a/proto/ospf/ospf.c b/proto/ospf/ospf.c index d4bcbed..2ee6e63 100644 --- a/proto/ospf/ospf.c +++ b/proto/ospf/ospf.c @@ -163,8 +163,11 @@ ospf_start(struct proto *p) oa->stub = 0; } - oa->opt.byte = 0; - if(!oa->stub) oa->opt.bit.e = 1; +#ifdef OSPFv2 + oa->options = (oa->stub ? 0 : OPT_E); +#else /* OSPFv3 */ + oa->options = OPT_R | (oa->stub ? 0 : OPT_E) | OPT_V6; +#endif } /* Add all virtual links as interfaces */ @@ -186,8 +189,11 @@ ospf_start(struct proto *p) fib_init(&oa->net_fib, p->pool, sizeof(struct area_net), 16, ospf_area_initfib); fib_init(&oa->rtr, p->pool, sizeof(ort), 16, ospf_rt_initort); po->backbone = oa; - oa->opt.byte = 0; - oa->opt.bit.e = 1; +#ifdef OSPFv2 + oa->options = OPT_E; +#else /* OSPFv3 */ + oa->options = OPT_R | OPT_E | OPT_V6; +#endif } ospf_iface_new(po, NULL, ac, ipatt); } @@ -448,36 +454,9 @@ ospf_rt_notify(struct proto *p, net * n, rte * new, rte * old UNUSED, */ if (new) /* Got some new route */ - { originate_ext_lsa(n, new, po, attrs); - } else - { - u32 rtid = po->proto.cf->global->router_id; - struct ospf_area *oa; - struct top_hash_entry *en; - u32 pr = ipa_to_u32(n->n.prefix); - struct ospf_lsa_ext *ext; - int i; - int max = max_ext_lsa(n->n.pxlen); - - /* Flush old external LSA */ - for (i = 0; i < max; i++, pr++) - { - if (en = ospf_hash_find(po->gr, 0, pr, rtid, LSA_T_EXT)) - { - ext = en->lsa_body; - if (ipa_compare(ext->netmask, ipa_mkmask(n->n.pxlen)) == 0) - { - WALK_LIST(oa, po->area_list) - { - ospf_lsupd_flush_nlsa(en, oa); - } - } - break; - } - } - } + flush_ext_lsa(n, po); } static void @@ -762,6 +741,7 @@ ospf_reconfigure(struct proto *p, struct proto_config *c) "Interface %s is no longer stub.", ifa->iface->name); } +#ifdef OSPFv2 /* AUTHENTICATION */ if (oldip->autype != newip->autype) { @@ -772,6 +752,7 @@ ospf_reconfigure(struct proto *p, struct proto_config *c) } /* Add *passwords */ ifa->passwords = newip->passwords; +#endif /* priority */ if (oldip->priority != newip->priority) @@ -1076,24 +1057,24 @@ he_compare(const void *p1, const void *p2) return lsa1->age - lsa2->age; } } - +/* static inline void show_lsa_router(struct top_hash_entry *he) { struct ospf_lsa_header *lsa = &(he->lsa); struct ospf_lsa_rt *rt = he->lsa_body; struct ospf_lsa_rt_link *rr = (struct ospf_lsa_rt_link *) (rt + 1); - u32 i; + int max = lsa_rt_count(lsa); - for (i = 0; i < rt->links; i++) + for (i = 0; i < max; i++) if (rr[i].type == LSART_PTP) cli_msg(-1016, "\t\trouter %R metric %u ", rr[i].id, rr[i].metric); - for (i = 0; i < rt->links; i++) + for (i = 0; i < max; i++) if (rr[i].type == LSART_NET) { struct proto_ospf *po = he->oa->po; - struct top_hash_entry *net_he = ospf_hash_find(po->gr, he->oa->areaid, rr[i].id, rr[i].id, LSA_T_NET); + struct top_hash_entry *net_he = ospfxx_hash_find(po->gr, he->oa->areaid, rr[i].id, rr[i].id, LSA_T_NET); if (net_he) { struct ospf_lsa_header *net_lsa = &(net_he->lsa); @@ -1104,11 +1085,11 @@ show_lsa_router(struct top_hash_entry *he) cli_msg(-1016, "\t\tnetwork ??? metric %u ", rr[i].metric); } - for (i = 0; i < rt->links; i++) + for (i = 0; i < max; i++) if (rr[i].type == LSART_STUB) cli_msg(-1016, "\t\tstubnet %I/%d metric %u ", ipa_from_u32(rr[i].id), ipa_mklen(ipa_from_u32(rr[i].data)), rr[i].metric); - for (i = 0; i < rt->links; i++) + for (i = 0; i < max; i++) if (rr[i].type == LSART_VLNK) cli_msg(-1016, "\t\tvlink %I metric %u ", ipa_from_u32(rr[i].id), rr[i].metric); } @@ -1119,14 +1100,13 @@ show_lsa_network(struct top_hash_entry *he) struct ospf_lsa_header *lsa = &(he->lsa); struct ospf_lsa_net *ln = he->lsa_body; u32 *rts = (u32 *) (ln + 1); - u32 max = (lsa->length - sizeof(struct ospf_lsa_header) - sizeof(struct ospf_lsa_net)) / sizeof(u32); u32 i; cli_msg(-1016, ""); cli_msg(-1016, "\tnetwork %I/%d", ipa_and(ipa_from_u32(lsa->id), ln->netmask), ipa_mklen(ln->netmask)); cli_msg(-1016, "\t\tdr %R", lsa->rt); - for (i = 0; i < max; i++) + for (i = 0; i < lsa_net_count(lsa); i++) cli_msg(-1016, "\t\trouter %R", rts[i]); } @@ -1168,7 +1148,7 @@ show_lsa_external(struct top_hash_entry *he) et->etm.metric & METRIC_MASK, str_via, str_tag); } - +*/ void ospf_sh_state(struct proto *p, int verbose) { @@ -1177,7 +1157,7 @@ ospf_sh_state(struct proto *p, int verbose) unsigned int i, j; u32 last_rt = 0xFFFFFFFF; u32 last_area = 0xFFFFFFFF; - + /* if (p->proto_state != PS_UP) { cli_msg(-1016, "%s: is not up", p->name); @@ -1240,7 +1220,7 @@ ospf_sh_state(struct proto *p, int verbose) break; } } - + */ cli_msg(0, ""); } diff --git a/proto/ospf/ospf.h b/proto/ospf/ospf.h index 2279089..1e46d3b 100644 --- a/proto/ospf/ospf.h +++ b/proto/ospf/ospf.h @@ -49,13 +49,17 @@ do { if ((p->debug & D_PACKETS) || OSPF_FORCE_DEBUG) \ #include "lib/string.h" #define OSPF_PROTO 89 + #ifndef IPV6 +#define OSPFv2 1 #define OSPF_VERSION 2 #define AllSPFRouters ipa_from_u32(0xe0000005) /* 224.0.0.5 */ #define AllDRouters ipa_from_u32(0xe0000006) /* 224.0.0.6 */ -#define DEFAULTDES ipa_from_u32(0) #else -#error OSPF for IPv6 is not implemented (mail to Feela ) +#define OSPFv3 1 +#define OSPF_VERSION 3 +#define AllSPFRouters _MI(0xFF020000, 0, 0, 5) /* FF02::5 */ +#define AllDRouters _MI(0xFF020000, 0, 0, 6) /* FF02::6 */ #endif @@ -118,32 +122,37 @@ struct ospf_area_config list stubnet_list; }; -struct obits -{ -#ifdef CPU_BIG_ENDIAN - u8 unused2:2; - u8 dc:1; - u8 ea:1; - u8 np:1; - u8 mc:1; - u8 e:1; - u8 unused1:1; -#else - u8 unused1:1; - u8 e:1; - u8 mc:1; - u8 np:1; - u8 ea:1; - u8 dc:1; - u8 unused2:2; + +/* Option flags */ + +#define OPT_E 0x02 +#define OPT_N 0x08 +#define OPT_DC 0x20 + +#ifdef OSPFv2 +#define OPT_EA 0x10 + +/* VEB flags are are stored independently in 'u16 options' */ +#define OPT_RT_B (0x01 << 8) +#define OPT_RT_E (0x02 << 8) +#define OPT_RT_V (0x04 << 8) #endif -}; -union options -{ - u8 byte; - struct obits bit; -}; +#ifdef OSPFv3 +#define OPT_V6 0x01 +#define OPT_R 0x10 + +/* VEB flags are are stored together with options in 'u32 options' */ +#define OPT_RT_B (0x01 << 24) +#define OPT_RT_E (0x02 << 24) +#define OPT_RT_V (0x04 << 24) +#define OPT_RT_NT (0x10 << 24) + +#define OPT_PX_NU 0x01 +#define OPT_PX_LA 0x02 +#define OPT_PX_P 0x08 +#define OPT_PX_DN 0x10 +#endif struct ospf_iface @@ -167,15 +176,26 @@ struct ospf_iface u16 inftransdelay; /* The estimated number of seconds it takes to transmit a Link State Update Packet over this interface. LSAs contained in the update */ - u16 autype; u16 helloint; /* number of seconds between hello sending */ + +#ifdef OSPFv2 list *passwords; + u16 autype; u32 csn; /* Last used crypt seq number */ bird_clock_t csn_use; /* Last time when packet with that CSN was sent */ +#endif + ip_addr drip; /* Designated router */ u32 drid; ip_addr bdrip; /* Backup DR */ u32 bdrid; + +#ifdef OSPFv3 + u32 dr_iface_id; /* if drid is valid, this is iface_id of DR (for connecting network) */ + u8 instance_id; /* Used to differentiate between more OSPF + instances on one interface */ +#endif + u8 type; /* OSPF view of type */ #define OSPF_IT_BCAST 0 #define OSPF_IT_NBMA 1 @@ -206,14 +226,19 @@ struct ospf_iface #define HELLOINT_D 10 #define POLLINT_D 20 #define DEADC_D 4 -#define WAIT_DMH 4 /* Value of Wait timer - not found it in RFC - * - using 4*HELLO - */ - struct top_hash_entry *nlsa; /* Originated net lsa */ - int orignet; /* Schedule network LSA origination */ - int fadj; /* Number of full adjacent neigh */ +#define WAIT_DMH 4 + /* Value of Wait timer - not found it in RFC * - using 4*HELLO */ + + struct top_hash_entry *net_lsa; /* Originated network LSA */ + int orignet; /* Schedule network LSA origination */ +#ifdef OSPFv3 + struct top_hash_entry *link_lsa; /* Originated link LSA */ + int origlink; /* Schedule link LSA origination */ + struct top_hash_entry *pxn_lsa; /* Originated prefix LSA */ +#endif + int fadj; /* Number of full adjacent neigh */ list nbma_list; - u8 priority; /* A router priority for DR election */ + u8 priority; /* A router priority for DR election */ u8 ioprob; u32 rxbuf; }; @@ -232,35 +257,17 @@ union ospf_auth struct ospf_md5 md5; }; -struct ospf_packet -{ - u8 version; - u8 type; + +/* Packet types */ #define HELLO_P 1 /* Hello */ #define DBDES_P 2 /* Database description */ #define LSREQ_P 3 /* Link state request */ #define LSUPD_P 4 /* Link state update */ #define LSACK_P 5 /* Link state acknowledgement */ - u16 length; - u32 routerid; - u32 areaid; + +/* Area IDs */ #define BACKBONE 0 - u16 checksum; - u16 autype; - union ospf_auth u; -}; -struct ospf_hello_packet -{ - struct ospf_packet ospf_packet; - ip_addr netmask; - u16 helloint; - u8 options; - u8 priority; - u32 deadint; - ip_addr dr; - ip_addr bdr; -}; struct immsb { @@ -282,34 +289,86 @@ union imms u8 byte; struct immsb bit; }; - -struct ospf_dbdes_packet -{ - struct ospf_packet ospf_packet; - u16 iface_mtu; - u8 options; - union imms imms; /* I, M, MS bits */ #define DBDES_MS 1 #define DBDES_M 2 #define DBDES_I 4 - u32 ddseq; + + +#ifdef OSPFv2 + +struct ospf_packet +{ + u8 version; + u8 type; + u16 length; + u32 routerid; + u32 areaid; + u16 checksum; + u16 autype; + union ospf_auth u; +}; + + +#else /* OSPFv3 packet descriptions */ + +struct ospf_packet +{ + u8 version; + u8 type; + u16 length; + u32 routerid; + u32 areaid; + u16 checksum; + u8 instance_id; + u8 zero; }; +#endif + + + + struct ospf_lsa_header { u16 age; /* LS Age */ #define LSA_MAXAGE 3600 /* 1 hour */ #define LSA_CHECKAGE 300 /* 5 minutes */ #define LSA_MAXAGEDIFF 900 /* 15 minutes */ + +#ifdef OSPFv2 u8 options; u8 type; + +#define LSA_T_RT 1 +#define LSA_T_NET 2 +#define LSA_T_SUM_NET 3 +#define LSA_T_SUM_RT 4 +#define LSA_T_EXT 5 + +#else /* OSPFv3 */ + u16 type; + +#define LSA_T_RT 0x2001 +#define LSA_T_NET 0x2002 +#define LSA_T_SUM_NET 0x2003 +#define LSA_T_SUM_RT 0x2004 +#define LSA_T_EXT 0x4005 +#define LSA_T_LINK 0x0008 +#define LSA_T_PREFIX 0x2009 + +#define LSA_UBIT 0x8000 + +#define LSA_SCOPE_LINK 0x0000 +#define LSA_SCOPE_AREA 0x2000 +#define LSA_SCOPE_AS 0x4000 +#define LSA_SCOPE_RES 0x6000 +#define LSA_SCOPE_MASK 0x6000 + +#define LSA_SCOPE(lsa) ((lsa)->type & LSA_SCOPE_MASK) +#endif + u32 id; -#define LSA_T_RT 1 -#define LSA_T_NET 2 -#define LSA_T_SUM_NET 3 -#define LSA_T_SUM_RT 4 -#define LSA_T_EXT 5 u32 rt; /* Advertising router */ s32 sn; /* LS Sequence number */ #define LSA_INITSEQNO 0x80000001 @@ -318,31 +377,18 @@ struct ospf_lsa_header u16 length; }; -struct vebb -{ -#ifdef CPU_BIG_ENDIAN - u8 padding:5; - u8 v:1; - u8 e:1; - u8 b:1; -#else - u8 b:1; - u8 e:1; - u8 v:1; - u8 padding:5; -#endif -}; -union veb -{ - u8 byte; - struct vebb bit; -}; +#define LSART_PTP 1 +#define LSART_NET 2 +#define LSART_STUB 3 +#define LSART_VLNK 4 + + +#ifdef OSPFv2 struct ospf_lsa_rt { - union veb veb; - u8 padding; + u16 options; /* VEB flags only */ u16 links; }; @@ -351,37 +397,115 @@ struct ospf_lsa_rt_link u32 id; u32 data; u8 type; -#define LSART_PTP 1 -#define LSART_NET 2 -#define LSART_STUB 3 -#define LSART_VLNK 4 u8 notos; u16 metric; }; -struct ospf_lsa_rt_link_tos -{ /* Actually we ignore TOS. This is useless */ - u8 tos; +struct ospf_lsa_net +{ + ip_addr netmask; + u32 routers[]; +}; + +struct ospf_lsa_sum +{ + ip_addr netmask; + u32 metric; +}; + +struct ospf_lsa_ext +{ + ip_addr netmask; + u32 metric; + ip_addr fwaddr; + u32 tag; +}; + +#define LSA_EXT_EBIT 0x80000000 + + +#else /* OSPFv3 */ + +struct ospf_lsa_rt +{ + u32 options; +}; + +struct ospf_lsa_rt_link +{ + u8 type; u8 padding; u16 metric; + u32 lif; /* Local interface ID */ + u32 nif; /* Neighbor interface ID */ + u32 id; /* Neighbor router ID */ }; struct ospf_lsa_net { - ip_addr netmask; + u32 options; + u32 routers[]; }; -struct ospf_lsa_sum +struct ospf_lsa_sum_net { - ip_addr netmask; + u32 metric; + u32 prefix[]; }; +struct ospf_lsa_sum_rt +{ + u32 options; + u32 metric; + u32 drid; +}; struct ospf_lsa_ext { - ip_addr netmask; + u32 metric; + u32 rest[]; +}; + +struct ospf_lsa_link +{ + u32 options; + ip_addr lladdr; + u32 pxcount; + u32 rest[]; +}; + +struct ospf_lsa_prefix +{ + u16 pxcount; + u16 ref_type; + u32 ref_id; + u32 ref_rt; + u32 rest[]; }; +#define LSA_EXT_EBIT 0x4000000 +#define LSA_EXT_FBIT 0x2000000 +#define LSA_EXT_TBIT 0x1000000 + +#endif + +#define METRIC_MASK 0x00FFFFFF +#define OPTIONS_MASK 0x00FFFFFF + +static inline unsigned lsa_rt_count(struct ospf_lsa_header *lsa) +{ + return (lsa->length - sizeof(struct ospf_lsa_header) - sizeof(struct ospf_lsa_rt)) + / sizeof(struct ospf_lsa_rt_link); +} + +static inline unsigned lsa_net_count(struct ospf_lsa_header *lsa) +{ + return (lsa->length - sizeof(struct ospf_lsa_header) - sizeof(struct ospf_lsa_net)) + / sizeof(u32); +} + + +/* struct ospf_lsa_ext_etos { #ifdef CPU_BIG_ENDIAN @@ -397,7 +521,7 @@ struct ospf_lsa_ext_etos #endif }; -#define METRIC_MASK 0x00FFFFFF + struct ospf_lsa_sum_tos { #ifdef CPU_BIG_ENDIAN @@ -430,16 +554,11 @@ struct ospf_lsa_ext_tos u32 tag; }; -struct ospf_lsreq_packet -{ - struct ospf_packet ospf_packet; -}; +*/ struct ospf_lsreq_header { - u16 padd1; - u8 padd2; - u8 type; + u32 type; u32 id; u32 rt; /* Advertising router */ }; @@ -450,17 +569,6 @@ struct l_lsr_head struct ospf_lsreq_header lsh; }; -struct ospf_lsupd_packet -{ - struct ospf_packet ospf_packet; - u32 lsano; /* Number of LSA's */ -}; - -struct ospf_lsack_packet -{ - struct ospf_packet ospf_packet; -}; - struct ospf_neighbor { @@ -484,10 +592,18 @@ struct ospf_neighbor u32 rid; /* Router ID */ ip_addr ip; /* IP of it's interface */ u8 priority; /* Priority */ - u8 options; /* Options received */ - ip_addr dr; /* Neigbour's idea of DR */ - ip_addr bdr; /* Neigbour's idea of BDR */ u8 adj; /* built adjacency? */ + u32 options; /* Options received */ + + /* dr and bdr store IP address in OSPFv2 and router ID in OSPFv3, + we use the same type to simplify handling */ + u32 dr; /* Neigbour's idea of DR */ + u32 bdr; /* Neigbour's idea of BDR */ + +#ifdef OSPFv3 + u32 iface_id; /* ID of Neighbour's iface connected to common network */ +#endif + siterator dbsi; /* Database summary list iterator */ slist lsrql; /* Link state request */ struct top_graph *lsrqh; /* LSA graph */ @@ -535,13 +651,14 @@ struct ospf_area struct ospf_area_config *ac; /* Related area config */ int origrt; /* Rt lsa origination scheduled? */ struct top_hash_entry *rt; /* My own router LSA */ + struct top_hash_entry *pxr_lsa; /* Originated prefix LSA */ list cand; /* List of candidates for RT calc. */ struct fib net_fib; /* Networks to advertise or not */ int stub; int trcap; /* Transit capability? */ + u32 options; /* Optional features */ struct proto_ospf *po; struct fib rtr; /* Routing tables for routers */ - union options opt; /* RFC2328 - A.2 */ }; struct proto_ospf @@ -577,20 +694,28 @@ struct ospf_iface_patt u32 deadc; u32 dead; u32 type; - u32 autype; u32 strictnbma; u32 stub; u32 vid; -#define OSPF_AUTH_NONE 0 -#define OSPF_AUTH_SIMPLE 1 -#define OSPF_AUTH_CRYPT 2 -#define OSPF_AUTH_CRYPT_SIZE 16 u32 rxbuf; #define OSPF_RXBUF_NORMAL 0 #define OSPF_RXBUF_LARGE 1 #define OSPF_RXBUF_MINSIZE 256 /* Minimal allowed size */ - list *passwords; list nbma_list; + + u32 autype; /* Not really used in OSPFv3 */ +#define OSPF_AUTH_NONE 0 +#define OSPF_AUTH_SIMPLE 1 +#define OSPF_AUTH_CRYPT 2 +#define OSPF_AUTH_CRYPT_SIZE 16 + +#ifdef OSPFv2 + list *passwords; +#endif + +#ifdef OSPFv3 + u8 instance_id; +#endif }; int ospf_import_control(struct proto *p, rte **new, ea_list **attrs, diff --git a/proto/ospf/packet.c b/proto/ospf/packet.c index 783d28e..e3a3115 100644 --- a/proto/ospf/packet.c +++ b/proto/ospf/packet.c @@ -24,21 +24,37 @@ ospf_pkt_fill_hdr(struct ospf_iface *ifa, void *buf, u8 h_type) pkt->routerid = htonl(p->cf->global->router_id); pkt->areaid = htonl(ifa->oa->areaid); + +#ifdef OSPFv3 + pkt->instance_id = ifa->instance_id; +#endif + +#ifdef OSPFv2 pkt->autype = htons(ifa->autype); +#endif + pkt->checksum = 0; } unsigned ospf_pkt_maxsize(struct ospf_iface *ifa) { + /* For virtual links use mtu=576, can be mtu < 576? */ unsigned mtu = (ifa->type == OSPF_IT_VLINK) ? OSPF_VLINK_MTU : ifa->iface->mtu; - /* Can be mtu < 576? */ + unsigned add = 0; + +#ifdef OSPFv2 + add = ((ifa->autype == OSPF_AUTH_CRYPT) ? OSPF_AUTH_CRYPT_SIZE : 0); +#endif + return ((mtu <= ifa->iface->mtu) ? mtu : ifa->iface->mtu) - - SIZE_OF_IP_HEADER - ((ifa->autype == OSPF_AUTH_CRYPT) ? OSPF_AUTH_CRYPT_SIZE : 0); - /* For virtual links use mtu=576 */ + SIZE_OF_IP_HEADER - add; } -void + +#ifdef OSPFv2 + +static void ospf_pkt_finalize(struct ospf_iface *ifa, struct ospf_packet *pkt) { struct password_item *passwd = NULL; @@ -224,6 +240,20 @@ ospf_pkt_checkauth(struct ospf_neighbor *n, struct ospf_iface *ifa, struct ospf_ } } +#else + +/* OSPFv3 authentication not yet supported */ + +static inline void +ospf_pkt_finalize(struct ospf_iface *ifa, struct ospf_packet *pkt) +{ } + +static int +ospf_pkt_checkauth(struct ospf_neighbor *n, struct ospf_iface *ifa, struct ospf_packet *pkt, int size) +{ return 1; } + +#endif + /** * ospf_rx_hook * @sk: socket we received the packet. Its ignored. @@ -290,6 +320,8 @@ ospf_rx_hook(sock * sk, int size) return 1; } + /* FIXME - handle checksums in OSPFv3 */ +#ifdef OSPFv2 if ((ps->autype != htons(OSPF_AUTH_CRYPT)) && (!ipsum_verify(ps, 16, (void *) ps + sizeof(struct ospf_packet), ntohs(ps->length) - sizeof(struct ospf_packet), NULL))) @@ -297,13 +329,23 @@ ospf_rx_hook(sock * sk, int size) log(L_ERR "%s%I - bad checksum", mesg, sk->faddr); return 1; } +#endif if (ntohl(ps->areaid) != ifa->oa->areaid) { - log(L_ERR "%s%I - different area %ld", mesg, sk->faddr, ntohl(ps->areaid)); + log(L_ERR "%s%I - different area (%u)", mesg, sk->faddr, ntohl(ps->areaid)); return 1; } + /* FIXME - handling of instance id should be better */ +#ifdef OSPFv3 + if (ps->instance_id != ifa->instance_id) + { + log(L_ERR "%s%I - different instance (%u)", mesg, sk->faddr, ps->instance_id); + return 1; + } +#endif + if (ntohl(ps->routerid) == p->cf->global->router_id) { log(L_ERR "%s%I - received my own router ID!", mesg, sk->faddr); @@ -352,23 +394,23 @@ ospf_rx_hook(sock * sk, int size) { case HELLO_P: DBG("%s: Hello received.\n", p->name); - ospf_hello_receive((struct ospf_hello_packet *) ps, ifa, n, sk->faddr); + ospf_hello_receive(ps, ifa, n, sk->faddr); break; case DBDES_P: DBG("%s: Database description received.\n", p->name); - ospf_dbdes_receive((struct ospf_dbdes_packet *) ps, ifa, n); + ospf_dbdes_receive(ps, ifa, n); break; case LSREQ_P: DBG("%s: Link state request received.\n", p->name); - ospf_lsreq_receive((struct ospf_lsreq_packet *) ps, ifa, n); + ospf_lsreq_receive(ps, ifa, n); break; case LSUPD_P: DBG("%s: Link state update received.\n", p->name); - ospf_lsupd_receive((struct ospf_lsupd_packet *) ps, ifa, n); + ospf_lsupd_receive(ps, ifa, n); break; case LSACK_P: DBG("%s: Link state ack received.\n", p->name); - ospf_lsack_receive((struct ospf_lsack_packet *) ps, ifa, n); + ospf_lsack_receive(ps, ifa, n); break; default: log(L_ERR "%s%I - wrong type %u", mesg, sk->faddr, ps->type); @@ -416,9 +458,14 @@ void ospf_send_to(sock *sk, ip_addr ip, struct ospf_iface *ifa) { struct ospf_packet *pkt = (struct ospf_packet *) sk->tbuf; - int len = ntohs(pkt->length) + ((ifa->autype == OSPF_AUTH_CRYPT) ? OSPF_AUTH_CRYPT_SIZE : 0); - ospf_pkt_finalize(ifa, pkt); + int len = ntohs(pkt->length); +#ifdef OSPFv2 + if (ifa->autype == OSPF_AUTH_CRYPT) + len += OSPF_AUTH_CRYPT_SIZE; +#endif + + ospf_pkt_finalize(ifa, pkt); if (sk->tbuf != sk->tpos) log(L_ERR "Aiee, old packet was overwritted in TX buffer"); diff --git a/proto/ospf/rt.c b/proto/ospf/rt.c index a230d38..e64e68a 100644 --- a/proto/ospf/rt.c +++ b/proto/ospf/rt.c @@ -10,18 +10,56 @@ static void add_cand(list * l, struct top_hash_entry *en, - struct top_hash_entry *par, u16 dist, struct ospf_area *oa); + struct top_hash_entry *par, u32 dist, struct ospf_area *oa); static void calc_next_hop(struct top_hash_entry *en, struct top_hash_entry *par, struct ospf_area *oa); static void ospf_ext_spf(struct proto_ospf *po); static void rt_sync(struct proto_ospf *po); +/* In ospf_area->rtr we store paths to routers, but we use RID (and not IP address) + as index, so we need to encapsulate RID to IP addresss */ +#ifdef OSPFv2 +#define ipa_from_rid(x) _MI(x) +#else /* OSPFv3 */ +#define ipa_from_rid(x) _MI(0,0,0,x) +#endif + + +static inline u32 * +get_ipv6_prefix(u32 *buf, ip_addr *addr, int *pxlen, u8 *pxopts) +{ + u8 pxl = (*buf >> 24); + *pxopts = (*buf >> 16); + *pxlen = pxl; + buf++; + + *addr = IPA_NONE; + + if (pxl > 0) + _I0(*addr) = *buf++; + if (pxl > 32) + _I1(*addr) = *buf++; + if (pxl > 64) + _I2(*addr) = *buf++; + if (pxl > 96) + _I3(*addr) = *buf++; + + return buf; +} + +static inline u32 * +get_ipv6_addr(u32 *buf, ip_addr *addr) +{ + *addr = *(ip_addr *) buf; + return buf + 4; +} + static void fill_ri(orta * orta) { orta->type = RTS_DUMMY; - orta->capa = 0; + orta->options = 0; orta->oa = NULL; orta->metric1 = LSINFINITY; orta->metric2 = LSINFINITY; @@ -159,6 +197,7 @@ ospf_rt_spfa(struct ospf_area *oa) if (oa->rt->dist != LSINFINITY) bug("Aging was not processed."); + /* 16.1. (1) */ init_list(&oa->cand); /* Empty list of candidates */ oa->trcap = 0; @@ -183,15 +222,15 @@ ospf_rt_spfa(struct ospf_area *oa) switch (act->lsa.type) { case LSA_T_RT: + /* FIXME - in OSPFv3 we should process all RT LSAs from that router */ rt = (struct ospf_lsa_rt *) act->lsa_body; - if (rt->veb.bit.v) + if (rt->options & OPT_RT_V) oa->trcap = 1; - if (rt->veb.bit.b || rt->veb.bit.e) + /* FIXME - in OSPFv3, should we add all routers, or just ABRs an ASBRs? */ + if ((rt->options & OPT_RT_V) || (rt->options & OPT_RT_E)) { nf.type = RTS_OSPF; - nf.capa = 0; - if (rt->veb.bit.b) nf.capa |= ORTA_ABR; - if (rt->veb.bit.e) nf.capa |= ORTA_ASBR; + nf.options = rt->options; nf.metric1 = act->dist; nf.metric2 = LSINFINITY; nf.tag = 0; @@ -199,26 +238,27 @@ ospf_rt_spfa(struct ospf_area *oa) nf.ar = act; nf.nh = act->nh; nf.ifa = act->nhi; - ri_install(po, ipa_from_u32(act->lsa.id), 32, ORT_ROUTER, &nf, NULL); + ri_install(po, ipa_from_rid(act->lsa.rt), 32, ORT_ROUTER, &nf, NULL); } rr = (struct ospf_lsa_rt_link *) (rt + 1); DBG(" Number of links: %u\n", rt->links); - for (i = 0; i < rt->links; i++) + for (i = 0; i < lsa_rt_count(&act->lsa); i++) { tmp = NULL; rtl = (rr + i); DBG(" Working on link: %R (type: %u) ", rtl->id, rtl->type); switch (rtl->type) { +#ifdef OSPFv2 case LSART_STUB: /* - * This violates rfc2328! but I hope - * it's also correct. + * This violates rfc2328! But it is mostly harmless. + * But it causes that the cost of the stub is ignored. */ DBG("\n"); nf.type = RTS_OSPF; - nf.capa = 0; + nf.options = 0; nf.metric1 = act->dist + rtl->metric; nf.metric2 = LSINFINITY; nf.tag = 0; @@ -249,9 +289,14 @@ ospf_rt_spfa(struct ospf_area *oa) ri_install(po, ipa_from_u32(rtl->id), ipa_mklen(ipa_from_u32(rtl->data)), ORT_NET, &nf, NULL); break; - +#endif case LSART_NET: - tmp = ospf_hash_find(po->gr, oa->areaid, rtl->id, rtl->id, LSA_T_NET); +#ifdef OSPFv2 + /* In OSPFv2, rtl->id is IP addres of DR, router ID is not known */ + tmp = ospfxx_hash_find(po->gr, oa->areaid, rtl->id, 0, LSA_T_NET); +#else /* OSPFv3 */ + tmp = ospfxx_hash_find(po->gr, oa->areaid, rtl->nif, rtl->id, LSA_T_NET); +#endif if (tmp == NULL) DBG("Not found!\n"); else @@ -260,7 +305,8 @@ ospf_rt_spfa(struct ospf_area *oa) case LSART_VLNK: case LSART_PTP: - tmp = ospf_hash_find(po->gr, oa->areaid, rtl->id, rtl->id, LSA_T_RT); + /* FIXME - in OSPFv3, find any LSA ID */ + tmp = ospfxx_hash_find(po->gr, oa->areaid, rtl->id, rtl->id, LSA_T_RT); DBG("PTP found.\n"); break; default: @@ -276,7 +322,7 @@ ospf_rt_spfa(struct ospf_area *oa) case LSA_T_NET: ln = act->lsa_body; nf.type = RTS_OSPF; - nf.capa = 0; + nf.options = 0; nf.metric1 = act->dist; nf.metric2 = LSINFINITY; nf.tag = 0; @@ -288,11 +334,11 @@ ospf_rt_spfa(struct ospf_area *oa) ipa_mklen(ln->netmask), ORT_NET, &nf, NULL); rts = (u32 *) (ln + 1); - for (i = 0; i < (act->lsa.length - sizeof(struct ospf_lsa_header) - - sizeof(struct ospf_lsa_net)) / sizeof(u32); i++) + for (i = 0; i < lsa_net_count(&act->lsa); i++) { DBG(" Working on router %R ", rts[i]); - tmp = ospf_hash_find(po->gr, oa->areaid, rts[i], rts[i], LSA_T_RT); + /* FIXME - in OSPFv3, find any LSA ID */ + tmp = ospfxx_hash_find(po->gr, oa->areaid, rts[i], rts[i], LSA_T_RT); if (tmp != NULL) DBG("Found :-)\n"); else @@ -308,7 +354,8 @@ ospf_rt_spfa(struct ospf_area *oa) { if ((iface->type == OSPF_IT_VLINK) && (iface->voa == oa)) { - if ((tmp = ospf_hash_find(po->gr, oa->areaid, iface->vid, iface->vid, LSA_T_RT)) && + /* FIXME in OSPFv3, different LSAID */ + if ((tmp = ospfxx_hash_find(po->gr, oa->areaid, iface->vid, iface->vid, LSA_T_RT)) && (!ipa_equal(tmp->lb, IPA_NONE))) { if ((iface->state != OSPF_IS_PTP) || (iface->iface != tmp->nhi->iface) || (!ipa_equal(iface->vip, tmp->lb))) @@ -348,7 +395,7 @@ link_back(struct ospf_area *oa, struct top_hash_entry *fol, struct top_hash_entr case LSA_T_RT: rt = (struct ospf_lsa_rt *) fol->lsa_body; rr = (struct ospf_lsa_rt_link *) (rt + 1); - for (i = 0; i < rt->links; i++) + for (i = 0; i < lsa_rt_count(&fol->lsa); i++) { rtl = (rr + i); switch (rtl->type) @@ -356,7 +403,7 @@ link_back(struct ospf_area *oa, struct top_hash_entry *fol, struct top_hash_entr case LSART_STUB: break; case LSART_NET: - if (ospf_hash_find(po->gr, oa->areaid, rtl->id, rtl->id, LSA_T_NET) == pre) + if (ospfxx_hash_find(po->gr, oa->areaid, rtl->id, rtl->id, LSA_T_NET) == pre) { fol->lb = ipa_from_u32(rtl->data); return 1; @@ -364,7 +411,7 @@ link_back(struct ospf_area *oa, struct top_hash_entry *fol, struct top_hash_entr break; case LSART_VLNK: case LSART_PTP: - if (ospf_hash_find(po->gr, oa->areaid, rtl->id, rtl->id, LSA_T_RT) == pre) + if (ospfxx_hash_find(po->gr, oa->areaid, rtl->id, rtl->id, LSA_T_RT) == pre) { fol->lb = ipa_from_u32(rtl->data); return 1; @@ -379,10 +426,9 @@ link_back(struct ospf_area *oa, struct top_hash_entry *fol, struct top_hash_entr case LSA_T_NET: ln = fol->lsa_body; rts = (u32 *) (ln + 1); - for (i = 0; i < (fol->lsa.length - sizeof(struct ospf_lsa_header) - - sizeof(struct ospf_lsa_net)) / sizeof(u32); i++) + for (i = 0; i < lsa_net_count(&fol->lsa); i++) { - if (ospf_hash_find(po->gr, oa->areaid, *(rts + i), *(rts + i), LSA_T_RT) == pre) + if (ospfxx_hash_find(po->gr, oa->areaid, *(rts + i), *(rts + i), LSA_T_RT) == pre) { return 1; } @@ -400,10 +446,10 @@ ospf_rt_sum_tr(struct ospf_area *oa) struct proto *p = &oa->po->proto; struct proto_ospf *po = oa->po; struct ospf_area *bb = po->backbone; - ip_addr *mask, ip, abrip; + ip_addr ip, abrip; struct top_hash_entry *en; - int mlen = -1, type = -1; - union ospf_lsa_sum_tm *tm; + u32 dst_rid, metric, options; + int pxlen = -1, type = -1; ort *re = NULL, *abr; orta nf; @@ -411,57 +457,80 @@ ospf_rt_sum_tr(struct ospf_area *oa) WALK_SLIST(en, po->lsal) { - if (en->oa != oa) + if ((en->lsa.type != LSA_T_SUM_RT) && (en->lsa.type != LSA_T_SUM_NET)) continue; + + if (en->domain != oa->areaid) + continue; + if (en->lsa.age == LSA_MAXAGE) continue; + if (en->dist == LSINFINITY) continue; if (en->lsa.rt == p->cf->global->router_id) continue; - if ((en->lsa.type != LSA_T_SUM_RT) && (en->lsa.type != LSA_T_SUM_NET)) - continue; - - mask = (ip_addr *)en->lsa_body; if (en->lsa.type == LSA_T_SUM_NET) { - mlen = ipa_mklen(*mask); - ip = ipa_and(ipa_from_u32(en->lsa.id), *mask); +#ifdef OSPFv2 + struct ospf_lsa_sum *ls = en->lsa_body; + pxlen = ipa_mklen(ls->netmask); + ip = ipa_and(ipa_from_u32(en->lsa.id), ls->netmask); +#else /* OSPFv3 */ + u8 pxopts; + struct ospf_lsa_sum_net *ls = en->lsa_body; + get_ipv6_prefix(ls->prefix, &ip, &pxlen, &pxopts); + if (pxopts & OPT_PX_NU) + continue; +#endif + + metric = ls->metric & METRIC_MASK; + options = 0; type = ORT_NET; - re = (ort *) fib_find(&po->rtf, &ip, 32); + re = (ort *) fib_find(&po->rtf, &ip, pxlen); } - - if (en->lsa.type == LSA_T_SUM_RT) + else if (en->lsa.type == LSA_T_SUM_RT) { - ip = ipa_from_u32(en->lsa.id); - mlen = 32; +#ifdef OSPFv2 + struct ospf_lsa_sum *ls = en->lsa_body; + dst_rid = en->lsa.id; + options = 0; +#else /* OSPFv3 */ + struct ospf_lsa_sum_rt *ls = en->lsa_body; + dst_rid = ls->drid; + options = ls->options & OPTIONS_MASK; +#endif + + ip = ipa_from_rid(dst_rid); + pxlen = 32; + metric = ls->metric & METRIC_MASK; + options |= ORTA_ASBR; type = ORT_ROUTER; - re = (ort *) fib_find(&bb->rtr, &ip, 32); + re = (ort *) fib_find(&bb->rtr, &ip, pxlen); } + if (!re) continue; if (re->n.oa->areaid != 0) continue; if ((re->n.type != RTS_OSPF) && (re->n.type != RTS_OSPF_IA)) continue; - abrip = ipa_from_u32(en->lsa.rt); + abrip = ipa_from_rid(en->lsa.rt); abr = fib_find(&oa->rtr, &abrip, 32); if (!abr) continue; - tm = (union ospf_lsa_sum_tm *)(mask + 1); - nf.type = re->n.type; - nf.capa = ORTA_ASBR; - nf.metric1 = abr->n.metric1 + (tm->metric & METRIC_MASK); + nf.options = options; + nf.metric1 = abr->n.metric1 + metric; nf.metric2 = LSINFINITY; nf.tag = 0; nf.oa = oa; nf.ar = abr->n.ar; nf.nh = abr->n.nh; nf.ifa = abr->n.ifa; - ri_install(po, ip, mlen, type, &nf, NULL); + ri_install(po, ip, pxlen, type, &nf, NULL); } } @@ -472,76 +541,103 @@ ospf_rt_sum(struct ospf_area *oa) struct proto_ospf *po = oa->po; struct proto *p = &po->proto; struct top_hash_entry *en; - ip_addr *mask, ip, abrip; /* abrIP is actually ID */ + ip_addr ip, abrip; /* abrIP is actually ID */ + u32 dst_rid, metric, options; struct area_net *anet; orta nf; ort *abr; - int mlen = -1, type = -1; - union ospf_lsa_sum_tm *tm; + int pxlen = -1, type = -1; OSPF_TRACE(D_EVENTS, "Starting routing table calculation for inter-area (area %R)", oa->areaid); WALK_SLIST(en, po->lsal) { - if (en->oa != oa) + if ((en->lsa.type != LSA_T_SUM_RT) && (en->lsa.type != LSA_T_SUM_NET)) + continue; + + if (en->domain != oa->areaid) continue; + /* Page 169 (1) */ if (en->lsa.age == LSA_MAXAGE) continue; + /* Page 169 (2) */ if (en->lsa.rt == p->cf->global->router_id) continue; - if ((en->lsa.type != LSA_T_SUM_RT) && (en->lsa.type != LSA_T_SUM_NET)) - continue; - - mask = (ip_addr *)en->lsa_body; - tm = (union ospf_lsa_sum_tm *)(mask + 1); - - if ((tm->metric & METRIC_MASK) == LSINFINITY) - continue; if (en->lsa.type == LSA_T_SUM_NET) { struct ospf_area *oaa; int skip = 0; - mlen = ipa_mklen(*mask); - ip = ipa_and(ipa_from_u32(en->lsa.id), *mask); + +#ifdef OSPFv2 + struct ospf_lsa_sum *ls = en->lsa_body; + pxlen = ipa_mklen(ls->netmask); + ip = ipa_and(ipa_from_u32(en->lsa.id), ls->netmask); +#else /* OSPFv3 */ + u8 pxopts; + struct ospf_lsa_sum_net *ls = en->lsa_body; + get_ipv6_prefix(ls->prefix, &ip, &pxlen, &pxopts); + if (pxopts & OPT_PX_NU) + continue; +#endif + + metric = ls->metric & METRIC_MASK; + options = 0; + type = ORT_NET; + /* Page 169 (3) */ WALK_LIST(oaa, po->area_list) { - if ((anet = fib_find(&oaa->net_fib, &ip, mlen)) && anet->active) + if ((anet = fib_find(&oaa->net_fib, &ip, pxlen)) && anet->active) { skip = 1; break; } } if (skip) continue; - - type = ORT_NET; } else { - ip = ipa_from_u32(en->lsa.id); - mlen = 32; +#ifdef OSPFv2 + struct ospf_lsa_sum *ls = en->lsa_body; + dst_rid = en->lsa.id; + options = 0; +#else /* OSPFv3 */ + struct ospf_lsa_sum_rt *ls = en->lsa_body; + dst_rid = ls->drid; + options = ls->options & OPTIONS_MASK; +#endif + + ip = ipa_from_rid(dst_rid); + pxlen = 32; + metric = ls->metric & METRIC_MASK; + options |= ORTA_ASBR; type = ORT_ROUTER; } - abrip = ipa_from_u32(en->lsa.rt); + /* Page 169 (1) */ + if (metric == LSINFINITY) + continue; + + /* Page 169 (4) */ + abrip = ipa_from_rid(en->lsa.rt); if (!(abr = (ort *) fib_find(&oa->rtr, &abrip, 32))) continue; if (abr->n.metric1 == LSINFINITY) continue; - if (!(abr->n.capa & ORTA_ABR)) continue; + if (!(abr->n.options & ORTA_ABR)) continue; nf.type = RTS_OSPF_IA; - nf.capa = ORTA_ASBR; - nf.metric1 = abr->n.metric1 + (tm->metric & METRIC_MASK); + nf.options = options; + nf.metric1 = abr->n.metric1 + metric; nf.metric2 = LSINFINITY; nf.tag = 0; nf.oa = oa; nf.ar = abr->n.ar; nf.nh = abr->n.nh; nf.ifa = abr->n.ifa; - ri_install(po, ip, mlen, type, &nf, NULL); + ri_install(po, ip, pxlen, type, &nf, NULL); } } @@ -567,7 +663,7 @@ ospf_rt_spf(struct proto_ospf *po) OSPF_TRACE(D_EVENTS, "Starting routing table calculation"); - /* Invalidate old routing table */ + /* 16. (1) - Invalidate old routing table */ FIB_WALK(&po->rtf, nftmp) { ri = (ort *) nftmp; @@ -594,9 +690,12 @@ ospf_rt_spf(struct proto_ospf *po) anet->metric = 1; } FIB_WALK_END; + + /* 16. (2) */ ospf_rt_spfa(oa); } + /* 16. (3) */ if ((po->areano == 1) || (!po->backbone)) { ospf_rt_sum(HEAD(po->area_list)); @@ -606,6 +705,7 @@ ospf_rt_spf(struct proto_ospf *po) ospf_rt_sum(po->backbone); } + /* 16. (4) */ WALK_LIST(oa, po->area_list) { if (oa->trcap && (oa->areaid != 0)) @@ -615,6 +715,7 @@ ospf_rt_spf(struct proto_ospf *po) } } + /* 16. (5) */ ospf_ext_spf(po); rt_sync(po); @@ -622,13 +723,12 @@ ospf_rt_spf(struct proto_ospf *po) po->calcrt = 0; } - /** * ospf_ext_spf - calculate external paths * @po: protocol * * After routing table for any area is calculated, calculation of external - * path is invoked. This process is described in 16.6 of RFC 2328. + * path is invoked. This process is described in 16.4 of RFC 2328. * Inter- and Intra-area paths are always prefered over externals. */ static void @@ -639,50 +739,75 @@ ospf_ext_spf(struct proto_ospf *po) struct top_hash_entry *en; struct proto *p = &po->proto; struct ospf_lsa_ext *le; - struct ospf_lsa_ext_tos *lt; - int mlen; - ip_addr ip, nh, rtid; + int pxlen, ebit, rt_fwaddr_valid; + ip_addr ip, nh, rtid, rt_fwaddr; struct ospf_iface *nhi = NULL; - int met1, met2; + u32 br_metric, rt_metric, rt_tag; neighbor *nn; struct ospf_area *atmp; - OSPF_TRACE(D_EVENTS, "Starting routing table calculation for ext routes"); WALK_SLIST(en, po->lsal) { + /* 16.4. (1) */ if (en->lsa.type != LSA_T_EXT) continue; if (en->lsa.age == LSA_MAXAGE) continue; + + /* 16.4. (2) */ if (en->lsa.rt == p->cf->global->router_id) continue; - le = en->lsa_body; - lt = (struct ospf_lsa_ext_tos *) (le + 1); - DBG("%s: Working on LSA. ID: %R, RT: %R, Type: %u, Mask %I\n", p->name, en->lsa.id, en->lsa.rt, en->lsa.type, le->netmask); - if ((lt->etm.metric & METRIC_MASK) == LSINFINITY) + le = en->lsa_body; + + rt_metric = le->metric & METRIC_MASK; + ebit = le->metric & LSA_EXT_EBIT; + + if (rt_metric == LSINFINITY) continue; + +#ifdef OSPFv2 ip = ipa_and(ipa_from_u32(en->lsa.id), le->netmask); - mlen = ipa_mklen(le->netmask); - if ((mlen < 0) || (mlen > 32)) + pxlen = ipa_mklen(le->netmask); + rt_fwaddr = le->fwaddr; + rt_fwaddr_valid = !ipa_equal(rt_fwaddr, IPA_NONE); + rt_tag = le->tag; +#else /* OSPFv3 */ + u8 pxopts; + u32 *buf = le->rest; + buf = get_ipv6_prefix(buf, &ip, &pxlen, &pxopts); + + if (pxopts & OPT_PX_NU) + continue; + + rt_fwaddr_valid = le->metric & LSA_EXT_FBIT; + if (rt_fwaddr_valid) + buf = get_ipv6_addr(buf, &rt_fwaddr); + else + rt_fwaddr = IPA_NONE; + + if (le->metric & LSA_EXT_TBIT) + rt_tag = *buf++; + else + rt_tag = 0; +#endif + + if (pxlen < 0) { - log("%s: Invalid mask in LSA. ID: %R, RT: %R, Type: %u, Mask %I", - p->name, en->lsa.id, en->lsa.rt, en->lsa.type, le->netmask); + log("%s: Invalid mask in LSA. ID: %R, RT: %R, Type: %u", + p->name, en->lsa.id, en->lsa.rt, en->lsa.type); continue; } nhi = NULL; nh = IPA_NONE; - met1 = LSINFINITY; - met2 = LSINFINITY; - - rtid = ipa_from_u32(en->lsa.rt); - + /* 16.4. (3) */ + rtid = ipa_from_rid(en->lsa.rt); nf1 = NULL; WALK_LIST(atmp, po->area_list) { @@ -698,50 +823,30 @@ ospf_ext_spf(struct proto_ospf *po) if (nf1->n.metric1 == LSINFINITY) continue; /* distance is INF */ - if (!(nf1->n.capa & ORTA_ASBR)) + if (!(nf1->n.options & ORTA_ASBR)) continue; /* It is not ASBR */ - if (ipa_equal(lt->fwaddr, IPA_NONE)) + if (!rt_fwaddr_valid) { - if (lt->etm.etos.ebit) - { /* FW address == 0 */ - met1 = nf1->n.metric1; - met2 = (lt->etm.metric & METRIC_MASK); - } - else - { - met1 = nf1->n.metric1 + (lt->etm.metric & METRIC_MASK); - met2 = LSINFINITY; - } - nh = nf1->n.nh; nhi = nf1->n.ifa; nfh = nf1; + br_metric = nf1->n.metric1; } else - { /* FW address !=0 */ - nf2 = fib_route(&po->rtf, lt->fwaddr, 32); + { + nf2 = fib_route(&po->rtf, rt_fwaddr, 32); if (!nf2) { - DBG("Cannot find network route (GW=%I)\n", lt->fwaddr); + DBG("Cannot find network route (GW=%I)\n", rt_fwaddr); continue; } - if (lt->etm.etos.ebit) - { - met1 = nf2->n.metric1; - met2 = (lt->etm.metric & METRIC_MASK); - } - else - { - met1 = nf2->n.metric1 + (lt->etm.metric & METRIC_MASK); - met2 = LSINFINITY; - } - if ((nn = neigh_find(p, <->fwaddr, 0)) != NULL) + if ((nn = neigh_find(p, &rt_fwaddr, 0)) != NULL) { - nh = lt->fwaddr; + nh = rt_fwaddr; nhi = ospf_iface_find(po, nn->iface); } else @@ -750,20 +855,31 @@ ospf_ext_spf(struct proto_ospf *po) nhi = nf2->n.ifa; } - if (nf2->n.metric1 == LSINFINITY) + br_metric = nf2->n.metric1; + if (br_metric == LSINFINITY) continue; /* distance is INF */ } - nfa.type = (met2 == LSINFINITY) ? RTS_OSPF_EXT1 : RTS_OSPF_EXT2; - nfa.capa = 0; - nfa.metric1 = met1; - nfa.metric2 = met2; - nfa.tag = lt->tag; + if (ebit) + { + nfa.type = RTS_OSPF_EXT2; + nfa.metric1 = br_metric; + nfa.metric2 = rt_metric; + } + else + { + nfa.type = RTS_OSPF_EXT1; + nfa.metric1 = br_metric + rt_metric; + nfa.metric2 = LSINFINITY; + } + + nfa.options = 0; + nfa.tag = rt_tag; nfa.oa = (po->backbone == NULL) ? HEAD(po->area_list) : po->backbone; nfa.ar = nf1->n.ar; nfa.nh = nh; nfa.ifa = nhi; - ri_install(po, ip, mlen, ORT_NET, &nfa, nfh); + ri_install(po, ip, pxlen, ORT_NET, &nfa, nfh); } } @@ -771,7 +887,7 @@ ospf_ext_spf(struct proto_ospf *po) /* Add LSA into list of candidates in Dijkstra's algorithm */ static void add_cand(list * l, struct top_hash_entry *en, struct top_hash_entry *par, - u16 dist, struct ospf_area *oa) + u32 dist, struct ospf_area *oa) { node *prev, *n; int added = 0; @@ -782,9 +898,11 @@ add_cand(list * l, struct top_hash_entry *en, struct top_hash_entry *par, if (en->lsa.age == LSA_MAXAGE) return; + /* 16.1. (2c) */ if (en->color == INSPF) return; + /* 16.1. (2d) */ if (dist >= en->dist) return; /* @@ -826,6 +944,7 @@ add_cand(list * l, struct top_hash_entry *en, struct top_hash_entry *par, act = SKIP_BACK(struct top_hash_entry, cn, n); if ((act->dist > dist) || ((act->dist == dist) && (act->lsa.type == LSA_T_NET))) + /* FIXME - shouldn't be here LSA_T_RT ??? */ { if (prev == NULL) add_head(l, &en->cn); @@ -854,6 +973,7 @@ calc_next_hop(struct top_hash_entry *en, struct top_hash_entry *par, struct ospf_iface *ifa; u32 myrid = p->cf->global->router_id; + /* 16.1.1. The next hop calculation */ DBG(" Next hop called.\n"); if (ipa_equal(par->nh, IPA_NONE)) { @@ -861,6 +981,7 @@ calc_next_hop(struct top_hash_entry *en, struct top_hash_entry *par, DBG(" Next hop calculating for id: %R rt: %R type: %u\n", en->lsa.id, en->lsa.rt, en->lsa.type); + /* The parent vertex is the root */ if (par == oa->rt) { if (en->lsa.type == LSA_T_NET) @@ -898,6 +1019,9 @@ calc_next_hop(struct top_hash_entry *en, struct top_hash_entry *par, return; } } + + /* The parent vertex is a network that directly connects the + calculating router to the destination router. */ if (par->lsa.type == LSA_T_NET) { if (en->lsa.type == LSA_T_NET) @@ -973,7 +1097,8 @@ again1: { if ((ifa->type == OSPF_IT_VLINK) && ipa_equal(ifa->vip, nf->n.nh)) { - if ((en = ospf_hash_find(po->gr, ifa->voa->areaid, ifa->vid, ifa->vid, LSA_T_RT)) + /* FIXME in OSPFv3, may be different LSA ID */ + if ((en = ospfxx_hash_find(po->gr, ifa->voa->areaid, ifa->vid, ifa->vid, LSA_T_RT)) && (!ipa_equal(en->nh, IPA_NONE))) { a0.gw = en->nh; @@ -1054,7 +1179,7 @@ again2: if (oaa->stub) fl = 1; if (fl) flush_sum_lsa(oaa, &anet->fn, ORT_NET); - else originate_sum_lsa(oaa, &anet->fn, ORT_NET, anet->metric); + else originate_sum_lsa(oaa, &anet->fn, ORT_NET, anet->metric, 0); } } FIB_WALK_END; @@ -1067,7 +1192,7 @@ again2: fnn.prefix = IPA_NONE; fnn.pxlen = 0; - if (oa->stub) originate_sum_lsa(oa, &fnn, ORT_NET, oa->stub); + if (oa->stub) originate_sum_lsa(oa, &fnn, ORT_NET, oa->stub, 0); else flush_sum_lsa(oa, &fnn, ORT_NET); } } diff --git a/proto/ospf/rt.h b/proto/ospf/rt.h index acb0a1a..d4b85ae 100644 --- a/proto/ospf/rt.h +++ b/proto/ospf/rt.h @@ -17,9 +17,12 @@ typedef struct orta { int type; - int capa; -#define ORTA_ASBR 1 -#define ORTA_ABR 2 + u32 options; + /* router-LSA style options (for ORT_ROUTER), with V,E,B bits. + In OSPFv2, ASBRs from another areas (that we know from rt-summary-lsa), + have just ORTA_ASBR in options, their real options are unknown */ +#define ORTA_ASBR OPT_RT_E +#define ORTA_ABR OPT_RT_V struct ospf_area *oa; u32 metric1; u32 metric2; diff --git a/proto/ospf/topology.c b/proto/ospf/topology.c index 5d8c7a9..21627f0 100644 --- a/proto/ospf/topology.c +++ b/proto/ospf/topology.c @@ -20,8 +20,6 @@ #define HASH_LO_STEP 2 #define HASH_LO_MIN 8 -int ptp_unnumbered_stub_lsa = 0; - static void * lsab_alloc(struct proto_ospf *po, unsigned size) { @@ -52,6 +50,50 @@ lsab_flush(struct proto_ospf *po) return r; } +static inline void * +lsab_offset(struct proto_ospf *po, unsigned offset) +{ + return ((byte *) po->lsab) + offset; +} + +static inline void * +lsab_end(struct proto_ospf *po) +{ + return ((byte *) po->lsab) + po->lsab_used; +} + +#ifdef OSPFv3 + +#define IPV6_PREFIX_SPACE(x) ((((x) + 63) / 32) * 4) +#define IPV6_PREFIX_WORDS(x) (((x) + 63) / 32) + +static inline u32 * +put_ipv6_prefix(u32 *buf, ip_addr addr, u8 pxlen, u8 pxopts, u16 lh) +{ + *buf++ = ((pxlen << 24) | (pxopts << 16) | lh); + + if (pxlen > 0) + *buf++ = _I0(addr); + if (pxlen > 32) + *buf++ = _I1(addr); + if (pxlen > 64) + *buf++ = _I2(addr); + if (pxlen > 96) + *buf++ = _I3(addr); + return buf; +} + + +static inline u32 * +put_ipv6_addr(u32 *buf, ip_addr addr) +{ + *(ip_addr *) buf = addr; + return buf + 4; +} + +#endif + + static int configured_stubnet(struct ospf_area *oa, struct ifa *a) { @@ -72,12 +114,38 @@ configured_stubnet(struct ospf_area *oa, struct ifa *a) return 0; } +int +bcast_net_active(struct ospf_iface *ifa) +{ + struct ospf_neighbor *neigh; + + if (ifa->state == OSPF_IS_WAITING) + return 0; + + WALK_LIST(neigh, ifa->neigh_list) + { + if (neigh->state == NEIGHBOR_FULL) + { + if (neigh->rid == ifa->drid) + return 1; + + if (ifa->state == OSPF_IS_DR) + return 1; + } + } + + return 0; +} + + +#ifdef OSPFv2 + static void * -originate_rt_lsa_body(struct ospf_area *oa, u16 * length) +originate_rt_lsa_body(struct ospf_area *oa, u16 *length) { struct proto_ospf *po = oa->po; struct ospf_iface *ifa; - int i = 0, j = 0, k = 0, bitv = 0; + int i = 0, bitv = 0; struct ospf_lsa_rt *rt; struct ospf_lsa_rt_link *ln; struct ospf_neighbor *neigh; @@ -87,10 +155,15 @@ originate_rt_lsa_body(struct ospf_area *oa, u16 * length) ASSERT(po->lsab_used == 0); rt = lsab_allocz(po, sizeof(struct ospf_lsa_rt)); + + rt->options = 0 + if (po->areano > 1) - rt->veb.bit.b = 1; + rt->options |= OPT_RT_B; + if ((po->ebit) && (!oa->stub)) - rt->veb.bit.e = 1; + rt->options |= OPT_RT_E; + rt = NULL; /* buffer might be reallocated later */ WALK_LIST(ifa, po->iface_list) @@ -131,19 +204,7 @@ originate_rt_lsa_body(struct ospf_area *oa, u16 * length) case OSPF_IT_BCAST: /* RFC2328 - 12.4.1.2 */ case OSPF_IT_NBMA: - if (ifa->state == OSPF_IS_WAITING) - break; - - j = 0, k = 0; - WALK_LIST(neigh, ifa->neigh_list) - { - if ((neigh->rid == ifa->drid) && (neigh->state == NEIGHBOR_FULL)) - k = 1; - if (neigh->state == NEIGHBOR_FULL) - j = 1; - } - - if (((ifa->state == OSPF_IS_DR) && (j == 1)) || (k == 1)) + if (bcast_net_active(ifa)) { ln = lsab_alloc(po, sizeof(struct ospf_lsa_rt_link)); ln->type = LSART_NET; @@ -212,11 +273,108 @@ originate_rt_lsa_body(struct ospf_area *oa, u16 * length) rt = po->lsab; rt->links = i; - rt->veb.bit.v = bitv; + + if (bitv) + rt->options |= OPT_RT_V; + *length = po->lsab_used + sizeof(struct ospf_lsa_header); return lsab_flush(po); } +#else /* OSPFv3 */ + +static void +add_lsa_rt_link(struct proto_ospf *po, struct ospf_iface *ifa, u8 type, u32 nif, u32 id) +{ + struct ospf_lsa_rt_link *ln = lsab_alloc(po, sizeof(struct ospf_lsa_rt_link)); + ln->type = type; + ln->padding = 0; + ln->metric = ifa->cost; + ln->lif = ifa->iface->index; + ln->nif = nif; + ln->id = id; +} + +static void * +originate_rt_lsa_body(struct ospf_area *oa, u16 *length) +{ + struct proto_ospf *po = oa->po; + struct ospf_iface *ifa; + int i = 0, j = 0, k = 0, bitv = 0; + struct ospf_lsa_rt *rt; + struct ospf_neighbor *neigh; + + DBG("%s: Originating RT_lsa body for area %R.\n", po->proto.name, + oa->areaid); + + ASSERT(po->lsab_used == 0); + rt = lsab_allocz(po, sizeof(struct ospf_lsa_rt)); + + rt->options = oa->options & OPTIONS_MASK; + + if (po->areano > 1) + rt->options |= OPT_RT_B; + + if ((po->ebit) && (!oa->stub)) + rt->options |= OPT_RT_E; + + rt = NULL; /* buffer might be reallocated later */ + + WALK_LIST(ifa, po->iface_list) + { + if ((ifa->type == OSPF_IT_VLINK) && (ifa->voa == oa) && + (!EMPTY_LIST(ifa->neigh_list))) + { + neigh = (struct ospf_neighbor *) HEAD(ifa->neigh_list); + if ((neigh->state == NEIGHBOR_FULL) && (ifa->cost <= 0xffff)) + bitv = 1; + } + + if ((ifa->oa != oa) || (ifa->state == OSPF_IS_DOWN)) + continue; + + /* BIRD does not support interface loops */ + ASSERT(ifa->state != OSPF_IS_LOOP); + + /* RFC5340 - 4.4.3.2 */ + switch (ifa->type) + { + case OSPF_IT_PTP: + neigh = (struct ospf_neighbor *) HEAD(ifa->neigh_list); + if ((!EMPTY_LIST(ifa->neigh_list)) && (neigh->state == NEIGHBOR_FULL)) + add_lsa_rt_link(po, ifa, LSART_PTP, neigh->iface_id, neigh->rid); + break; + + case OSPF_IT_BCAST: + case OSPF_IT_NBMA: + if (bcast_net_active(ifa)) + add_lsa_rt_link(po, ifa, LSART_NET, ifa->dr_iface_id, ifa->drid); + break; + + case OSPF_IT_VLINK: + neigh = (struct ospf_neighbor *) HEAD(ifa->neigh_list); + if ((!EMPTY_LIST(ifa->neigh_list)) && (neigh->state == NEIGHBOR_FULL) && (ifa->cost <= 0xffff)) + add_lsa_rt_link(po, ifa, LSART_VLNK, neigh->iface_id, neigh->rid); + break; + + default: + log("Unknown interface type %s", ifa->iface->name); + break; + } + } + + if (bitv) + { + rt = po->lsab; + rt->options |= OPT_RT_V; + } + + *length = po->lsab_used + sizeof(struct ospf_lsa_header); + return lsab_flush(po); +} + +#endif + /** * originate_rt_lsa - build new instance of router LSA * @oa: ospf_area which is LSA built to @@ -247,53 +405,72 @@ originate_rt_lsa(struct ospf_area *oa) OSPF_TRACE(D_EVENTS, "Originating RT_lsa for area %R.", oa->areaid); lsa.age = 0; - lsa.id = rtid; lsa.type = LSA_T_RT; + +#ifdef OSPFv2 + lsa.options = oa->options; +#endif + + lsa.id = rtid; lsa.rt = rtid; - lsa.options = oa->opt.byte; - if (oa->rt == NULL) - { - lsa.sn = LSA_INITSEQNO; - } - else - { - lsa.sn = oa->rt->lsa.sn + 1; - } + lsa.sn = oa->rt ? (oa->rt->lsa.sn + 1) : LSA_INITSEQNO; + u32 dom = oa->areaid; + body = originate_rt_lsa_body(oa, &lsa.length); lsasum_calculate(&lsa, body); - en = lsa_install_new(&lsa, body, oa); + en = lsa_install_new(po, &lsa, dom, body); oa->rt = en; - ospf_lsupd_flood(NULL, NULL, &oa->rt->lsa, NULL, oa, 1); + ospf_lsupd_flood(po, NULL, NULL, &oa->rt->lsa, dom, 1); schedule_rtcalc(po); oa->origrt = 0; } static void * -originate_net_lsa_body(struct ospf_iface *ifa, u16 * length, +originate_net_lsa_body(struct ospf_iface *ifa, u16 *length, struct proto_ospf *po) { u16 i = 1; struct ospf_neighbor *n; - u32 *body; struct ospf_lsa_net *net; + int nodes = ifa->fadj + 1; + + net = mb_alloc(po->proto.pool, sizeof(struct ospf_lsa_net) + + nodes * sizeof(u32)); - net = mb_alloc(po->proto.pool, sizeof(u32) * (ifa->fadj + 1) + - sizeof(struct ospf_lsa_net)); +#ifdef OSPFv2 net->netmask = ipa_mkmask(ifa->iface->addr->pxlen); +#endif + +#ifdef OSPFv3 + /* In OSPFv3, we would like to merge options from Link LSAs of added neighbors */ + struct top_hash_entry *en; + u32 options = 0; +#endif + + net->routers[0] = po->proto.cf->global->router_id; - body = (u32 *) (net + 1); - i = 1; - *body = po->proto.cf->global->router_id; WALK_LIST(n, ifa->neigh_list) { if (n->state == NEIGHBOR_FULL) { - *(body + i) = n->rid; +#ifdef OSPFv3 + en = ospfxx_hash_find(po->gr, ifa->iface->index, n->iface_id, n->rid, LSA_T_LINK); + if (en) + options |= ((struct ospf_lsa_link *) en->lsa_body)->options; +#endif + + net->routers[i] = n->rid; i++; } } - *length = i * sizeof(u32) + sizeof(struct ospf_lsa_header) + - sizeof(struct ospf_lsa_net); + ASSERT(i == nodes); + +#ifdef OSPFv3 + net->options = options & OPTIONS_MASK; +#endif + + *length = sizeof(struct ospf_lsa_header) + sizeof(struct ospf_lsa_net) + + nodes * sizeof(u32); return net; } @@ -312,10 +489,11 @@ originate_net_lsa(struct ospf_iface *ifa) struct proto_ospf *po = ifa->oa->po; struct ospf_lsa_header lsa; u32 rtid = po->proto.cf->global->router_id; + u32 dom = ifa->oa->areaid; struct proto *p = &po->proto; void *body; - if (ifa->nlsa && ((ifa->nlsa->inst_t + MINLSINTERVAL) > now)) + if (ifa->net_lsa && ((ifa->net_lsa->inst_t + MINLSINTERVAL) > now)) return; /* * It's too early to originate new network LSA. We will @@ -324,22 +502,22 @@ originate_net_lsa(struct ospf_iface *ifa) if ((ifa->state != OSPF_IS_DR) || (ifa->fadj == 0)) { - if (ifa->nlsa == NULL) + if (ifa->net_lsa == NULL) return; OSPF_TRACE(D_EVENTS, "Deleting Net lsa for iface \"%s\".", ifa->iface->name); - ifa->nlsa->lsa.sn += 1; - ifa->nlsa->lsa.age = LSA_MAXAGE; - lsasum_calculate(&ifa->nlsa->lsa, ifa->nlsa->lsa_body); - ospf_lsupd_flood(NULL, NULL, &ifa->nlsa->lsa, NULL, ifa->oa, 0); - s_rem_node(SNODE ifa->nlsa); - if (ifa->nlsa->lsa_body != NULL) - mb_free(ifa->nlsa->lsa_body); - ifa->nlsa->lsa_body = NULL; - ospf_hash_delete(po->gr, ifa->nlsa); + ifa->net_lsa->lsa.sn += 1; + ifa->net_lsa->lsa.age = LSA_MAXAGE; + lsasum_calculate(&ifa->net_lsa->lsa, ifa->net_lsa->lsa_body); + ospf_lsupd_flood(po, NULL, NULL, &ifa->net_lsa->lsa, dom, 0); + s_rem_node(SNODE ifa->net_lsa); + if (ifa->net_lsa->lsa_body != NULL) + mb_free(ifa->net_lsa->lsa_body); + ifa->net_lsa->lsa_body = NULL; + ospf_hash_delete(po->gr, ifa->net_lsa); schedule_rtcalc(po); - ifa->nlsa = NULL; + ifa->net_lsa = NULL; return; } @@ -347,209 +525,173 @@ originate_net_lsa(struct ospf_iface *ifa) ifa->iface->name); lsa.age = 0; - lsa.id = ipa_to_u32(ifa->iface->addr->ip); lsa.type = LSA_T_NET; + +#ifdef OSPFv2 + lsa.options = ifa->oa->options; + lsa.id = ipa_to_u32(ifa->iface->addr->ip); +#else /* OSPFv3 */ + lsa.id = ifa->iface->index; +#endif + lsa.rt = rtid; - lsa.options = ifa->oa->opt.byte; - if (ifa->nlsa == NULL) - { - lsa.sn = LSA_INITSEQNO; - } - else - { - lsa.sn = ifa->nlsa->lsa.sn + 1; - } + lsa.sn = ifa->net_lsa ? (ifa->net_lsa->lsa.sn + 1) : LSA_INITSEQNO; body = originate_net_lsa_body(ifa, &lsa.length, po); lsasum_calculate(&lsa, body); - ifa->nlsa = lsa_install_new(&lsa, body, ifa->oa); - ospf_lsupd_flood(NULL, NULL, &ifa->nlsa->lsa, NULL, ifa->oa, 1); + ifa->net_lsa = lsa_install_new(po, &lsa, dom, body); + ospf_lsupd_flood(po, NULL, NULL, &lsa, dom, 1); ifa->orignet = 0; } +#ifdef OSPFv2 + static void * -originate_ext_lsa_body(net * n, rte * e, struct proto_ospf *po, - struct ea_list *attrs) +originate_sum_lsa_body(struct proto_ospf *po, u16 *length, u32 mlen, u32 metric) { - struct proto *p = &po->proto; - struct ospf_lsa_ext *ext; - struct ospf_lsa_ext_tos *et; - u32 m1 = ea_get_int(attrs, EA_OSPF_METRIC1, LSINFINITY); - u32 m2 = ea_get_int(attrs, EA_OSPF_METRIC2, 10000); - u32 tag = ea_get_int(attrs, EA_OSPF_TAG, 0); - int inas = 0; + struct ospf_lsa_sum *sum = mb_alloc(po->proto.pool, sizeof(struct ospf_lsa_sum)); + *length = sizeof(struct ospf_lsa_header) + sizeof(struct ospf_lsa_sum); - ext = mb_alloc(p->pool, sizeof(struct ospf_lsa_ext) + - sizeof(struct ospf_lsa_ext_tos)); - ext->netmask = ipa_mkmask(n->n.pxlen); + sum->netmask = ipa_mkmask(mlen); + sum->metric = metric; - et = (struct ospf_lsa_ext_tos *) (ext + 1); + return sum; +} - if (m1 != LSINFINITY) - { - et->etm.metric = m1; - et->etm.etos.tos = 0; - et->etm.etos.ebit = 0; - } - else - { - et->etm.metric = m2; - et->etm.etos.tos = 0; - et->etm.etos.ebit = 1; - } - et->tag = tag; - if (!ipa_equal(e->attrs->gw, IPA_NONE)) - { - if (ospf_iface_find((struct proto_ospf *) p, e->attrs->iface) != NULL) - inas = 1; - } +#define originate_sum_net_lsa_body(po,length,fn,metric) \ + originate_sum_lsa_body(po, length, (fn)->pxlen, metric) - if (!inas) - et->fwaddr = IPA_NONE; - else - et->fwaddr = e->attrs->gw; - return ext; -} +#define originate_sum_rt_lsa_body(po,length,drid,metric,options) \ + originate_sum_lsa_body(po, length, 0, metric) -/** - * max_ext_lsa - calculate the maximum amount of external networks - * possible for the given prefix length. - * @pxlen: network prefix length - * - * This is a fix for the previous static use of MAXNETS which did - * only work correct if MAXNETS < possible IPs for given prefix. - * This solution is kind of a hack as there can now only be one - * route for /32 type entries but this is better than the crashes - * I did experience whith close together /32 routes originating - * on different hosts. - */ +#else /* OSPFv3 */ -int -max_ext_lsa(unsigned pxlen) +static void * +originate_sum_net_lsa_body(struct proto_ospf *po, u16 *length, struct fib_node *fn, u32 metric) { - int i; - for (i = 1; pxlen < BITS_PER_IP_ADDRESS; pxlen++, i <<= 1) - if (i >= MAXNETS) - return MAXNETS; - return i; + int size = sizeof(struct ospf_lsa_sum_net) + IPV6_PREFIX_SPACE(fn->pxlen); + struct ospf_lsa_sum_net *sum = mb_alloc(po->proto.pool, size); + *length = sizeof(struct ospf_lsa_header) + size; + + sum->metric = metric; + put_ipv6_prefix(sum->prefix, fn->prefix, fn->pxlen, 0, 0); + + return sum; +} + +static void * +originate_sum_rt_lsa_body(struct proto_ospf *po, u16 *length, u32 drid, u32 metric, u32 options) +{ + struct ospf_lsa_sum_rt *sum = mb_alloc(po->proto.pool, sizeof(struct ospf_lsa_sum_rt)); + *length = sizeof(struct ospf_lsa_header) + sizeof(struct ospf_lsa_sum_rt); + + sum->options = options & OPTIONS_MASK; + sum->metric = metric; + sum->drid = drid; + + return sum; } +#endif + void -flush_sum_lsa(struct ospf_area *oa, struct fib_node *fn, int type) +originate_sum_lsa(struct ospf_area *oa, struct fib_node *fn, int type, int metric, u32 options) { struct proto_ospf *po = oa->po; struct proto *p = &po->proto; struct top_hash_entry *en; - u32 rtid = po->proto.cf->global->router_id; + u32 rid = po->proto.cf->global->router_id; struct ospf_lsa_header lsa; - int max, i; - struct ospf_lsa_sum *sum = NULL; + void *body; - lsa.rt = rtid; - lsa.type = LSA_T_SUM_NET; - if (type == ORT_ROUTER) - lsa.type = LSA_T_SUM_RT; + /* options argument is used in ORT_NET and OSPFv3 only */ + + lsa.age = 0; + lsa.rt = rid; + lsa.sn = LSA_INITSEQNO; +#ifdef OSPFv2 + lsa.options = oa->options; +#endif - max = max_ext_lsa(fn->pxlen); + if (type == ORT_NET) + { + /* FIXME proper handling of LSA IDs and check for the same network */ + lsa.id = ipa_to_lsaid(fn->prefix); + lsa.type = LSA_T_SUM_NET; + } + else + { + /* In OSPFv6, LSA ID is meaningless, but we still use Router ID of ASBR */ + lsa.id = ipa_to_rid(fn->prefix); + lsa.type = LSA_T_SUM_RT; + } - for (i = 0; i < max; i++) - { - lsa.id = ipa_to_u32(fn->prefix) + i; - if ((en = ospf_hash_find_header(po->gr, oa->areaid, &lsa)) != NULL) + u32 dom = oa->areaid; + + /* FIXME check for the same LSA */ + if ((en = ospfxx_hash_find_header(po->gr, oa->areaid, &lsa)) != NULL) + lsa.sn = en->lsa.sn + 1; + + if (type == ORT_NET) { - sum = en->lsa_body; - if ((type == ORT_ROUTER) || (fn->pxlen == ipa_mklen(sum->netmask))) - { - en->lsa.age = LSA_MAXAGE; - en->lsa.sn = LSA_MAXSEQNO; - lsasum_calculate(&en->lsa, sum); - OSPF_TRACE(D_EVENTS, "Flushing summary lsa. (id=%R, type=%d)", - en->lsa.id, en->lsa.type); - ospf_lsupd_flood(NULL, NULL, &en->lsa, NULL, oa, 1); - if (can_flush_lsa(po)) flush_lsa(en, po); - break; - } + OSPF_TRACE(D_EVENTS, "Originating Net-Summary-LSA for %I/%d (metric %d).", + fn->prefix, fn->pxlen, metric); + + body = originate_sum_net_lsa_body(po, &lsa.length, fn, metric); } - } + else + { + OSPF_TRACE(D_EVENTS, "Originating RT-Summary-LSA for %R (metric %d).", + lsa.id, metric); + + body = originate_sum_rt_lsa_body(po, &lsa.length, lsa.id, metric, options); + } + + lsasum_calculate(&lsa, body); + en = lsa_install_new(po, &lsa, dom, body); + ospf_lsupd_flood(po, NULL, NULL, &lsa, dom, 1); } + void -originate_sum_lsa(struct ospf_area *oa, struct fib_node *fn, int type, int metric) +flush_sum_lsa(struct ospf_area *oa, struct fib_node *fn, int type) { struct proto_ospf *po = oa->po; struct proto *p = &po->proto; struct top_hash_entry *en; - u32 rtid = po->proto.cf->global->router_id; + u32 rid = po->proto.cf->global->router_id; struct ospf_lsa_header lsa; - int i, max, mlen = fn->pxlen, free = 0; - u32 freeid = 0xFFFF; - struct ospf_lsa_sum *sum = NULL; - union ospf_lsa_sum_tm *tm; - lsa.type = LSA_T_SUM_NET; - - if (type == ORT_ROUTER) - { - lsa.type = LSA_T_SUM_RT; - mlen = 0; - } - - lsa.age = 0; - lsa.rt = rtid; - lsa.sn = LSA_INITSEQNO; - lsa.length = sizeof(struct ospf_lsa_sum) + sizeof(union ospf_lsa_sum_tm) + - sizeof(struct ospf_lsa_header); - lsa.options = oa->opt.byte; - max = max_ext_lsa(fn->pxlen); - for (i = 0; i < max; i++) - { - lsa.id = ipa_to_u32(fn->prefix) + i; - if ((en = ospf_hash_find_header(po->gr, oa->areaid, &lsa)) == NULL) + lsa.rt = rid; + if (type == ORT_NET) { - if (!free) - { - freeid = lsa.id; - free = 1; - } + /* FIXME proper handling of LSA IDs and check for the same network */ + lsa.id = ipa_to_lsaid(fn->prefix); + lsa.type = LSA_T_SUM_NET; } - else + else { - sum = en->lsa_body; - if (mlen == ipa_mklen(sum->netmask)) - { - tm = (union ospf_lsa_sum_tm *) (sum + 1); - if (tm->metric == (unsigned) metric) return; /* No reason for origination */ - lsa.sn = en->lsa.sn + 1; - freeid = en->lsa.id; - free = 1; - break; - } + /* In OSPFv6, LSA ID is meaningless, but we still use Router ID of ASBR */ + lsa.id = ipa_to_rid(fn->prefix); + lsa.type = LSA_T_SUM_RT; } - } - - if(!free) - { - log("%s: got more routes for one /%d network then %d, ignoring", p->name, - fn->pxlen, max); - return; - } - lsa.id = freeid; - - OSPF_TRACE(D_EVENTS, "Originating summary (type %d) lsa for %I/%d (met %d).", lsa.type, fn->prefix, - fn->pxlen, metric); - sum = mb_alloc(p->pool, sizeof(struct ospf_lsa_sum) + sizeof(union ospf_lsa_sum_tm)); - sum->netmask = ipa_mkmask(mlen); - tm = (union ospf_lsa_sum_tm *) (sum + 1); - tm->metric = metric; - tm->tos.tos = 0; - - lsasum_calculate(&lsa, sum); - en = lsa_install_new(&lsa, sum, oa); - ospf_lsupd_flood(NULL, NULL, &en->lsa, NULL, oa, 1); + if ((en = ospfxx_hash_find_header(po->gr, oa->areaid, &lsa)) != NULL) + { + struct ospf_lsa_sum *sum = en->lsa_body; + en->lsa.age = LSA_MAXAGE; + en->lsa.sn = LSA_MAXSEQNO; + lsasum_calculate(&en->lsa, sum); + + OSPF_TRACE(D_EVENTS, "Flushing summary lsa. (id=%R, type=%d)", + en->lsa.id, en->lsa.type); + ospf_lsupd_flood(po, NULL, NULL, &en->lsa, oa->areaid, 1); + if (can_flush_lsa(po)) flush_lsa(en, po); + } } + void check_sum_lsa(struct proto_ospf *po, ort *nf, int dest) { @@ -572,7 +714,7 @@ check_sum_lsa(struct proto_ospf *po, ort *nf, int dest) flush = 0; if ((nf->n.metric1 >= LSINFINITY) || (nf->n.type > RTS_OSPF_IA)) flush = 1; - if ((dest == ORT_ROUTER) && (!(nf->n.capa & ORTA_ASBR))) + if ((dest == ORT_ROUTER) && (!(nf->n.options & ORTA_ASBR))) flush = 1; if ((!nf->n.oa) || (nf->n.oa->areaid == oa->areaid)) flush = 1; @@ -599,13 +741,73 @@ check_sum_lsa(struct proto_ospf *po, ort *nf, int dest) if ((nf->n.oa == po->backbone) && (oa->trcap)) flush = 0; } - if(flush) + if (flush) flush_sum_lsa(oa, &nf->fn, dest); else - originate_sum_lsa(oa, &nf->fn, dest, nf->n.metric1); + originate_sum_lsa(oa, &nf->fn, dest, nf->n.metric1, nf->n.options); } } + +static void * +originate_ext_lsa_body(net *n, rte *e, u16 *length, struct proto_ospf *po, + struct ea_list *attrs) +{ + struct proto *p = &po->proto; + struct ospf_lsa_ext *ext; + u32 m1 = ea_get_int(attrs, EA_OSPF_METRIC1, LSINFINITY); + u32 m2 = ea_get_int(attrs, EA_OSPF_METRIC2, 10000); + u32 tag = ea_get_int(attrs, EA_OSPF_TAG, 0); + int gw = 0; + int size = sizeof(struct ospf_lsa_ext); + u32 *buf; + + if (!ipa_equal(e->attrs->gw, IPA_NONE)) + { + /* FIXME: check for link-local in OSPFv3 ? */ + if (ospf_iface_find((struct proto_ospf *) p, e->attrs->iface) != NULL) + gw = 1; + } + +#ifdef OSPFv3 + size += IPV6_PREFIX_SPACE(n->n.pxlen); + + if (gw) + size += 16; + + if (tag) + size += 4; +#endif + + ext = mb_alloc(p->pool, size); + *length = sizeof(struct ospf_lsa_header) + size; + + ext->metric = (m1 != LSINFINITY) ? m1 : (m2 & LSA_EXT_EBIT); + +#ifdef OSPFv2 + ext->netmask = ipa_mkmask(n->n.pxlen); + ext->fwaddr = gw ? IPA_NONE : e->attrs->gw; + ext->tag = tag; +#else /* OSPFv3 */ + buf = ext->rest; + buf = put_ipv6_prefix(buf, n->n.prefix, n->n.pxlen, 0, 0); + + if (gw) + { + ext->metric |= LSA_EXT_FBIT; + buf = put_ipv6_addr(buf, e->attrs->gw); + } + + if (tag) + { + ext->metric |= LSA_EXT_TBIT; + *buf++ = tag; + } +#endif + + return ext; +} + /** * originate_ext_lsa - new route received from nest and filters * @n: network prefix and mask @@ -626,9 +828,9 @@ originate_ext_lsa(net * n, rte * e, struct proto_ospf *po, struct ea_list *attrs) { struct ospf_lsa_header lsa; - u32 rtid = po->proto.cf->global->router_id; + u32 rid = po->proto.cf->global->router_id; struct top_hash_entry *en = NULL; - void *body = NULL; + void *body; struct proto *p = &po->proto; struct ospf_area *oa; struct ospf_lsa_ext *ext1, *ext2; @@ -638,50 +840,26 @@ originate_ext_lsa(net * n, rte * e, struct proto_ospf *po, n->n.pxlen); lsa.age = 0; - lsa.id = ipa_to_u32(n->n.prefix); lsa.type = LSA_T_EXT; - lsa.rt = rtid; + lsa.rt = rid; lsa.sn = LSA_INITSEQNO; - lsa.options = 0; +#ifdef OSPFv2 + lsa.options = 0; /* or oa->options ? */ +#endif - body = originate_ext_lsa_body(n, e, po, attrs); - lsa.length = sizeof(struct ospf_lsa_ext) + sizeof(struct ospf_lsa_ext_tos) + - sizeof(struct ospf_lsa_header); - ext1 = body; - max = max_ext_lsa(n->n.pxlen); + /* FIXME proper handling of LSA IDs and check for the same network */ + lsa.id = ipa_to_lsaid(n->n.prefix); - for (i = 0; i < max; i++) - { - if ((en = ospf_hash_find_header(po->gr, 0 , &lsa)) != NULL) + if ((en = ospfxx_hash_find_header(po->gr, 0, &lsa)) != NULL) { - ext2 = en->lsa_body; - if (ipa_compare(ext1->netmask, ext2->netmask) != 0) - lsa.id++; - else - break; + lsa.sn = en->lsa.sn + 1; } - else - break; - } - if (i == max) - { - log("%s: got more routes for one /%d network then %d, ignoring", p->name, - n->n.pxlen, max); - mb_free(body); - return; - } + body = originate_ext_lsa_body(n, e, &lsa.length, po, attrs); lsasum_calculate(&lsa, body); - WALK_LIST(oa, po->area_list) - { - if (!oa->stub) - { - en = lsa_install_new(&lsa, body, oa); - ospf_lsupd_flood(NULL, NULL, &en->lsa, NULL, oa, 1); - body = originate_ext_lsa_body(n, e, po, attrs); - } - } - mb_free(body); + + en = lsa_install_new(po, &lsa, 0, body); + ospf_lsupd_flood(po, NULL, NULL, &lsa, 0, 1); if (po->ebit == 0) { @@ -693,6 +871,304 @@ originate_ext_lsa(net * n, rte * e, struct proto_ospf *po, } } +void +flush_ext_lsa(net *n, struct proto_ospf *po) +{ + u32 rid = po->proto.cf->global->router_id; + struct ospf_area *oa; + struct top_hash_entry *en; + struct ospf_lsa_ext *ext; + int i; + + /* FIXME proper handling of LSA IDs and check for the same network */ + u32 lsaid = ipa_to_lsaid(n->n.prefix); + + if (en = ospfxx_hash_find(po->gr, 0, lsaid, rid, LSA_T_EXT)) + { + /* FIXME this is nonsense */ + WALK_LIST(oa, po->area_list) + { + ospf_lsupd_flush_nlsa(po, en); + } + } +} + + +#ifdef OSPFv3 + +static void * +originate_link_lsa_body(struct ospf_iface *ifa, u16 *length) +{ + struct proto_ospf *po = ifa->oa->po; + struct ospf_lsa_link *ll; + int i = 0; + u8 flags; + + ASSERT(po->lsab_used == 0); + ll = lsab_allocz(po, sizeof(struct ospf_lsa_link)); + ll->options = ifa->oa->options | (ifa->priority << 24); + ll->lladdr = FIX; + ll = NULL; /* buffer might be reallocated later */ + + struct ifa *a; + WALK_LIST(a, ifa->iface->addrs) + { + if ((a->flags & IA_SECONDARY) || + (a->scope < SCOPE_SITE)) + continue; + + flags = (a->pxlen < MAX_PREFIX_LENGTH) ? 0 : OPT_PX_LA; + put_ipv6_prefix(lsab_alloc(po, IPV6_PREFIX_SPACE(a->pxlen)), + a->ip, a->pxlen, flags, 0); + i++; + } + + ll = po->lsab; + ll->pxcount = i; + *length = po->lsab_used + sizeof(struct ospf_lsa_header); + return lsab_flush(po); +} + +void +originate_link_lsa(struct ospf_iface *ifa) +{ + struct ospf_lsa_header lsa; + struct proto_ospf *po = ifa->oa->po; + struct proto *p = &po->proto; + u32 rtid = po->proto.cf->global->router_id; + void *body; + + if (ifa->link_lsa && ((ifa->link_lsa->inst_t + MINLSINTERVAL) > now)) + return; + /* + * It's too early to originate new link LSA. We will + * try to do it next tick + */ + + /* 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 = LSA_T_LINK; + lsa.id = ifa->iface->index; + lsa.rt = rtid; + lsa.sn = ifa->link_lsa ? (ifa->link_lsa->lsa.sn + 1) : LSA_INITSEQNO; + u32 dom = ifa->iface->index; + + 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->origlink = 0; +} + + +static void * +originate_prefix_rt_lsa_body(struct ospf_area *oa, u16 *length) +{ + struct proto_ospf *po = oa->po; + struct ospf_iface *ifa; + struct ospf_lsa_prefix *lp; + u32 rid = po->proto.cf->global->router_id; + int net_lsa; + int i = 0; + u8 flags; + + ASSERT(po->lsab_used == 0); + lp = lsab_allocz(po, sizeof(struct ospf_lsa_prefix)); + lp->ref_type = LSA_T_RT; + lp->ref_id = 0; + lp->ref_rt = rid; + lp = NULL; /* buffer might be reallocated later */ + + WALK_LIST(ifa, po->iface_list) + { + if ((ifa->oa != oa) || (ifa->state == OSPF_IS_DOWN)) + continue; + + if ((ifa->type == OSPF_IT_BCAST) || + (ifa->type == OSPF_IT_NBMA)) + net_lsa = bcast_net_active(ifa); + else + net_lsa = 0; + + struct ifa *a; + WALK_LIST(a, ifa->iface->addrs) + { + if (((a->pxlen < MAX_PREFIX_LENGTH) && net_lsa) || + (a->flags & IA_SECONDARY) || + (a->flags & IA_UNNUMBERED) || + configured_stubnet(oa, a)) + continue; + + flags = (a->pxlen < MAX_PREFIX_LENGTH) ? 0 : OPT_PX_LA; + put_ipv6_prefix(lsab_alloc(po, IPV6_PREFIX_SPACE(a->pxlen)), + a->ip, a->pxlen, flags, ifa->cost); + i++; + } + } + + /* FIXME Handle vlinks? see RFC5340, page 38 */ + + struct ospf_stubnet_config *sn; + WALK_LIST(sn, oa->ac->stubnet_list) + if (!sn->hidden) + { + flags = (sn->px.len < MAX_PREFIX_LENGTH) ? 0 : OPT_PX_LA; + put_ipv6_prefix(lsab_alloc(po, IPV6_PREFIX_SPACE(sn->px.len)), + sn->px.addr, sn->px.len, flags, sn->cost); + i++; + } + + lp = po->lsab; + lp->pxcount = i; + *length = po->lsab_used + sizeof(struct ospf_lsa_header); + return lsab_flush(po); +} + +void +originate_prefix_rt_lsa(struct ospf_area *oa) +{ + struct ospf_lsa_header lsa; + struct proto_ospf *po = oa->po; + u32 rid = po->proto.cf->global->router_id; + void *body; + + lsa.age = 0; + lsa.type = LSA_T_PREFIX; + lsa.id = 1 << 31; + lsa.rt = rid; + lsa.sn = oa->pxr_lsa ? (oa->pxr_lsa->lsa.sn + 1) : LSA_INITSEQNO; + u32 dom = oa->areaid; + + 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); +} + + +static inline int +prefix_space(u32 *buf) +{ + int pxl = *buf >> 24; + return IPV6_PREFIX_SPACE(pxl); +} + +static inline int +prefix_same(u32 *b1, u32 *b2) +{ + int pxl1 = *b1 >> 24; + int pxl2 = *b2 >> 24; + int pxs, i; + + if (pxl1 != pxl2) + return 0; + + pxs = IPV6_PREFIX_WORDS(pxl1); + for (i = 1; i < pxs; i++) + if (b1[i] != b2[i]) + return 0; + + return 1; +} + +static inline u32 * +prefix_advance(u32 *buf) +{ + return buf + prefix_space(buf); +} + +static void +add_prefix(struct proto_ospf *po, u32 *px, u32 *pxl, int *pxc) +{ + int i; + for (i = 0; i < *pxc; i++) + { + if (prefix_same(px, pxl)) + { + /* Options should be logically OR'ed together */ + *pxl |= *px; + return; + } + pxl = prefix_advance(pxl); + } + + ASSERT(pxl == lsab_end(po)); + + int pxspace = prefix_space(px); + pxl = lsab_alloc(po, pxspace); + memcpy(pxl, px, pxspace); + (*pxc)++; +} + + +static void * +originate_prefix_net_lsa_body(struct ospf_iface *ifa, u16 *length) +{ + struct proto_ospf *po = ifa->oa->po; + struct ospf_lsa_prefix *lp; + struct ospf_lsa_link *ll; + struct ospf_neighbor *n; + struct top_hash_entry *en; + u32 rid = po->proto.cf->global->router_id; + u32 *pxb; + int i, j, offset; + + + ASSERT(po->lsab_used == 0); + lp = lsab_allocz(po, sizeof(struct ospf_lsa_prefix)); + lp->ref_type = LSA_T_NET; + lp->ref_id = ifa->net_lsa->lsa.id; + lp->ref_rt = rid; + lp = NULL; /* buffer might be reallocated later */ + + i = 0; + offset = po->lsab_used; + + /* Find all Link LSA associated with the link and merge their prefixes */ + WALK_LIST(n, ifa->neigh_list) + if ((n->state == NEIGHBOR_FULL) && + (en = ospfxx_hash_find(po->gr, ifa->iface->index, n->iface_id, n->rid, LSA_T_LINK))) + { + ll = en->lsa_body; + pxb = ll->rest; + + for (j = 0; j < ll->pxcount; j++) + { + add_prefix(po, pxb, lsab_offset(po, offset), &i); + pxb = prefix_advance(pxb); + } + } + + lp = po->lsab; + lp->pxcount = i; + *length = po->lsab_used + sizeof(struct ospf_lsa_header); + return lsab_flush(po); +} + +void +originate_prefix_net_lsa(struct ospf_iface *ifa) +{ + struct ospf_lsa_header lsa; + struct proto_ospf *po = ifa->oa->po; + u32 rid = po->proto.cf->global->router_id; + void *body; + + lsa.age = 0; + lsa.type = LSA_T_PREFIX; + lsa.id = ifa->iface->index; + lsa.rt = rid; + lsa.sn = ifa->pxn_lsa ? (ifa->pxn_lsa->lsa.sn + 1) : LSA_INITSEQNO; + u32 dom = ifa->oa->areaid; + + 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); +} + +#endif static void ospf_top_ht_alloc(struct top_graph *f) @@ -730,24 +1206,30 @@ ospf_top_hash_u32(u32 a) } static inline unsigned -ospf_top_hash(struct top_graph *f, u32 areaid, u32 lsaid, u32 rtrid, u32 type) -{ -#if 1 /* Dirty patch to make rt table calculation work. */ - return (ospf_top_hash_u32(lsaid) + - ospf_top_hash_u32((type == - LSA_T_NET) ? lsaid : rtrid) + type + - (type == LSA_T_EXT ? 0 : areaid)) & f->hash_mask; -#else +ospf_top_hash(struct top_graph *f, u32 domain, u32 lsaid, u32 rtrid, u32 type) +{ + /* In OSPFv2, we don't know Router ID when looking for network lsas. + dirty patch to make rt table calculation work. */ + + return (ospf_top_hash_u32(lsaid) + type + +#ifdef OSPFv2 + ((type == LSA_T_NET) ? 0 : ospf_top_hash_u32(rtrid)) + +#else /* OSPFv3 */ + ospf_top_hash_u32(rtrid) + +#endif + domain) & f->hash_mask; + + /* return (ospf_top_hash_u32(lsaid) + ospf_top_hash_u32(rtrid) + type + areaid) & f->hash_mask; -#endif + */ } /** * ospf_top_new - allocated new topology database - * @p: current instance of OSPF + * @p: current instance of ospf * - * This dynamically hashed structure is often used for keeping LSAs. Mainly + * this dynamically hashed structure is often used for keeping lsas. mainly * its used in @ospf_area structure. */ struct top_graph * @@ -781,7 +1263,7 @@ ospf_top_rehash(struct top_graph *f, int step) oldn = f->hash_size; oldt = f->hash_table; - DBG("Re-hashing topology hash from order %d to %d\n", f->hash_order, + dbg("re-hashing topology hash from order %d to %d\n", f->hash_order, f->hash_order + step); f->hash_order += step; ospf_top_ht_alloc(f); @@ -793,7 +1275,7 @@ ospf_top_rehash(struct top_graph *f, int step) while (e) { x = e->next; - n = newt + ospf_top_hash(f, e->oa->areaid, e->lsa.id, e->lsa.rt, e->lsa.type); + n = newt + ospf_top_hash(f, e->domain, e->lsa.id, e->lsa.rt, e->lsa.type); e->next = *n; *n = e; e = x; @@ -803,64 +1285,53 @@ ospf_top_rehash(struct top_graph *f, int step) } struct top_hash_entry * -ospf_hash_find_header(struct top_graph *f, u32 areaid, struct ospf_lsa_header *h) +ospfxx_hash_find_header(struct top_graph *f, u32 domain, struct ospf_lsa_header *h) { - return ospf_hash_find(f, areaid, h->id, h->rt, h->type); + return ospfxx_hash_find(f, domain, h->id, h->rt, h->type); } struct top_hash_entry * -ospf_hash_get_header(struct top_graph *f, struct ospf_area *oa, struct ospf_lsa_header *h) +ospfxx_hash_get_header(struct top_graph *f, u32 domain, struct ospf_lsa_header *h) { - return ospf_hash_get(f, oa, h->id, h->rt, h->type); + return ospfxx_hash_get(f, domain, h->id, h->rt, h->type); } struct top_hash_entry * -ospf_hash_find(struct top_graph *f, u32 areaid, u32 lsa, u32 rtr, u32 type) +ospfxx_hash_find(struct top_graph *f, u32 domain, u32 lsa, u32 rtr, u32 type) { struct top_hash_entry *e; - e = f->hash_table[ospf_top_hash(f, areaid, lsa, rtr, type)]; + e = f->hash_table[ospf_top_hash(f, domain, lsa, rtr, type)]; - /* Dirty patch to make rt table calculation work. */ +#ifdef OSPFv2 + /* dirty patch to make rt table calculation work. */ if (type == LSA_T_NET) { - while (e && (e->lsa.id != lsa || e->lsa.type != LSA_T_NET || e->oa->areaid != areaid)) - e = e->next; - } - else if (type == LSA_T_EXT) - { - while (e && (e->lsa.id != lsa || e->lsa.type != type || e->lsa.rt != rtr)) - e = e->next; - } - else - { - while (e && (e->lsa.id != lsa || e->lsa.type != type || e->lsa.rt != rtr || e->oa->areaid != areaid)) + while (e && (e->lsa.id != lsa || e->lsa.type != LSA_T_NET || e->domain != domain)) e = e->next; + + return e; } +#endif + + while (e && (e->lsa.id != lsa || e->lsa.type != type || e->lsa.rt != rtr || e->domain != domain)) + e = e->next; + return e; } struct top_hash_entry * -ospf_hash_get(struct top_graph *f, struct ospf_area *oa, u32 lsa, u32 rtr, u32 type) +ospfxx_hash_get(struct top_graph *f, u32 domain, u32 lsa, u32 rtr, u32 type) { struct top_hash_entry **ee; struct top_hash_entry *e; - u32 nareaid = (type == LSA_T_EXT ? 0 : oa->areaid); - ee = f->hash_table + ospf_top_hash(f, nareaid, lsa, rtr, type); + ee = f->hash_table + ospf_top_hash(f, domain, lsa, rtr, type); e = *ee; - if (type == LSA_T_EXT) - { - while (e && (e->lsa.id != lsa || e->lsa.rt != rtr || e->lsa.type != type)) - e = e->next; - } - else - { - while (e && (e->lsa.id != lsa || e->lsa.rt != rtr || e->lsa.type != type || e->oa->areaid != nareaid)) - e = e->next; - } + while (e && (e->lsa.id != lsa || e->lsa.rt != rtr || e->lsa.type != type || e->domain != domain)) + e = e->next; if (e) return e; @@ -876,7 +1347,7 @@ ospf_hash_get(struct top_graph *f, struct ospf_area *oa, u32 lsa, u32 rtr, u32 t e->lsa.type = type; e->lsa_body = NULL; e->nhi = NULL; - e->oa = oa; + e->domain = domain; e->next = *ee; *ee = e; if (f->hash_entries++ > f->hash_entries_max) @@ -888,7 +1359,7 @@ void ospf_hash_delete(struct top_graph *f, struct top_hash_entry *e) { struct top_hash_entry **ee = f->hash_table + - ospf_top_hash(f, e->oa->areaid, e->lsa.id, e->lsa.rt, e->lsa.type); + ospf_top_hash(f, e->domain, e->lsa.id, e->lsa.rt, e->lsa.type); while (*ee) { @@ -916,15 +1387,16 @@ ospf_dump_lsa(struct top_hash_entry *he, struct proto *p) OSPF_TRACE(D_EVENTS, "- %1x %-1R %-1R %4u 0x%08x 0x%04x %-1R", he->lsa.type, he->lsa.id, he->lsa.rt, he->lsa.age, he->lsa.sn, - he->lsa.checksum, he->oa ? he->oa->areaid : 0 ); + he->lsa.checksum, he->domain); + /* switch (he->lsa.type) { case LSA_T_RT: rt = he->lsa_body; rr = (struct ospf_lsa_rt_link *) (rt + 1); - for (i = 0; i < rt->links; i++) + for (i = 0; i < lsa_rt_items(&he->lsa); i++) OSPF_TRACE(D_EVENTS, " - %1x %-1R %-1R %5u", rr[i].type, rr[i].id, rr[i].data, rr[i].metric); break; @@ -932,16 +1404,15 @@ ospf_dump_lsa(struct top_hash_entry *he, struct proto *p) case LSA_T_NET: ln = he->lsa_body; rts = (u32 *) (ln + 1); - max = (he->lsa.length - sizeof(struct ospf_lsa_header) - - sizeof(struct ospf_lsa_net)) / sizeof(u32); - for (i = 0; i < max; i++) + for (i = 0; i < lsa_net_items(&he->lsa); i++) OSPF_TRACE(D_EVENTS, " - %-1R", rts[i]); break; default: break; } + */ } void diff --git a/proto/ospf/topology.h b/proto/ospf/topology.h index 21e545e..4555bea 100644 --- a/proto/ospf/topology.h +++ b/proto/ospf/topology.h @@ -13,12 +13,11 @@ struct top_hash_entry { /* Index for fast mapping (type,rtrid,LSid)->vertex */ snode n; node cn; /* For adding into list of candidates - * in intra-area routing table - * calculation - */ + in intra-area routing table calculation */ struct top_hash_entry *next; /* Next in hash chain */ struct ospf_lsa_header lsa; - struct ospf_area *oa; + u32 domain; /* Area ID for area-wide LSAs, Iface ID for link-wide LSAs */ + // struct ospf_area *oa; void *lsa_body; bird_clock_t inst_t; /* Time of installation into DB */ ip_addr nh; /* Next hop */ @@ -48,13 +47,19 @@ struct top_graph 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 areaid, +struct top_hash_entry *ospfxx_hash_find_header(struct top_graph *f, u32 areaid, struct ospf_lsa_header *h); -struct top_hash_entry *ospf_hash_get_header(struct top_graph *f, struct ospf_area *oa, +struct top_hash_entry *ospfxx_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 areaid, u32 lsa, u32 rtr, + +struct top_hash_entry *ospfxx_hash_find_smart(struct top_graph *f, struct ospf_iface *ifa, + struct ospf_lsa_header *h); +struct top_hash_entry *ospfxx_hash_get_smart(struct top_graph *f, struct ospf_iface *ifa, + struct ospf_lsa_header *h); + +struct top_hash_entry *ospfxx_hash_find(struct top_graph *, u32 domain, u32 lsa, u32 rtr, u32 type); -struct top_hash_entry *ospf_hash_get(struct top_graph *, struct ospf_area *oa, u32 lsa, u32 rtr, +struct top_hash_entry *ospfxx_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); @@ -64,7 +69,7 @@ int max_ext_lsa(unsigned pxlen); void originate_ext_lsa(net * n, rte * e, struct proto_ospf *po, struct ea_list *attrs); void check_sum_lsa(struct proto_ospf *po, ort *nf, int); -void originate_sum_lsa(struct ospf_area *oa, struct fib_node *fn, int type, int metric); +void originate_sum_lsa(struct ospf_area *oa, struct fib_node *fn, int type, int metric, u32 options); void flush_sum_lsa(struct ospf_area *oa, struct fib_node *fn, int type); -- cgit v1.2.3