diff --git a/lib/ip.h b/lib/ip.h index 056207f9..e38137e6 100644 --- a/lib/ip.h +++ b/lib/ip.h @@ -19,13 +19,13 @@ #define IP4_MIN_MTU 576 /* RFC 2328 A.1 */ #define IP6_MIN_MTU 1280 /* RFC 5340 A.1 */ -#define IP4_ALL_SPF_ROUTERS ipa_build4(224, 0, 0, 5) -#define IP4_ALL_D_ROUTERS ipa_build4(224, 0, 0, 6) +#define IP4_OSPF_ALL_ROUTERS ipa_build4(224, 0, 0, 5) +#define IP4_OSPF_DES_ROUTERS ipa_build4(224, 0, 0, 6) -#define IP6_All_NODES ipa_build6(0xFF020000, 0, 0, 1) +#define IP6_ALL_NODES ipa_build6(0xFF020000, 0, 0, 1) #define IP6_ALL_ROUTERS ipa_build6(0xFF020000, 0, 0, 2) -#define IP6_ALL_OSPF_ROUTERS ipa_build6(0xFF020000, 0, 0, 5) -#define IP6_ALL_OSPF_D_ROUTERS ipa_build6(0xFF020000, 0, 0, 6) +#define IP6_OSPF_ALL_ROUTERS ipa_build6(0xFF020000, 0, 0, 5) +#define IP6_OSPF_DES_ROUTERS ipa_build6(0xFF020000, 0, 0, 6) #define IP4_NONE _MI4(0) #define IP6_NONE _MI6(0,0,0,0) diff --git a/proto/ospf/config.Y b/proto/ospf/config.Y index 40d3f1f1..46e78761 100644 --- a/proto/ospf/config.Y +++ b/proto/ospf/config.Y @@ -143,8 +143,7 @@ ospf_proto_start: proto_start OSPF { this_proto = proto_config_new(&proto_ospf, sizeof(struct ospf_config), $1); init_list(&OSPF_CFG->area_list); init_list(&OSPF_CFG->vlink_list); - OSPF_CFG->rfc1583 = DEFAULT_RFC1583; - OSPF_CFG->tick = DEFAULT_OSPFTICK; + OSPF_CFG->tick = OSPF_DEFAULT_TICK; } ; @@ -166,9 +165,9 @@ ospf_area_start: AREA idval { this_area = cfg_allocz(sizeof(struct ospf_area_config)); add_tail(&OSPF_CFG->area_list, NODE this_area); this_area->areaid = $2; - this_area->default_cost = DEFAULT_STUB_COST; + this_area->default_cost = OSPF_DEFAULT_STUB_COST; this_area->type = OPT_E; - this_area->transint = DEFAULT_TRANSINT; + this_area->transint = OSPF_DEFAULT_TRANSINT; init_list(&this_area->patt_list); init_list(&this_area->net_list); diff --git a/proto/ospf/dbdes.c b/proto/ospf/dbdes.c index e1e0e81f..120c20e8 100644 --- a/proto/ospf/dbdes.c +++ b/proto/ospf/dbdes.c @@ -36,20 +36,6 @@ struct ospf_dbdes3_packet }; - -#ifdef OSPFv2 - -#define hton_opt(X) X -#define ntoh_opt(X) X -#endif - - -#ifdef OSPFv3 - -#define hton_opt(X) htonl(X) -#define ntoh_opt(X) ntohl(X) -#endif - static inline unsigned ospf_dbdes_hdrlen(struct proto_ospf *po) { @@ -69,30 +55,113 @@ ospf_dbdes_body(struct proto_ospf *po, struct ospf_packet *pkt, unsigned plen, static void ospf_dbdes_dump(struct proto_ospf *po, struct ospf_packet *pkt) { - struct proto *p = &po->proto; struct ospf_lsa_header *lsas; unsigned i, lsa_count; + u32 pkt_ddseq; + u16 pkt_iface_mtu; + u8 pkt_imms; ASSERT(pkt->type == DBDES_P); ospf_dump_common(po, pkt); - log(L_TRACE "%s: imms %s%s%s", p->name, - (imms & DBDES_I) ? "I " : "", - (imms & DBDES_M) ? "M " : "", - (imms & DBDES_MS) ? "MS" : ""); - log(L_TRACE "%s: ddseq %u", p->name, ntohl(pkt->ddseq)); + if (ospf_is_v2(po)) + { + struct ospf_dbdes2_packet *ps = (void *) pkt; + pkt_iface_mtu = ntohs(ps->iface_mtu); + pkt_imms = ps->imms; + pkt_ddseq = ntohl(ps->ddseq); + } + else /* OSPFv3 */ + { + struct ospf_dbdes3_packet *ps = (void *) pkt; + pkt_iface_mtu = ntohs(ps->iface_mtu); + pkt_imms = ps->imms; + pkt_ddseq = ntohl(ps->ddseq); + } - struct ospf_lsa_header *plsa = (void *) (pkt + 1); - unsigned int i, j; + log(L_TRACE "%s: mtu %u", po->proto.name, pkt_iface_mtu); + log(L_TRACE "%s: imms %s%s%s", po->proto.name, + (pkt_imms & DBDES_I) ? "I " : "", + (pkt_imms & DBDES_M) ? "M " : "", + (pkt_imms & DBDES_MS) ? "MS" : ""); + log(L_TRACE "%s: ddseq %u", po->proto.name, pkt_ddseq); - j = (ntohs(op->length) - sizeof(struct ospf_dbdes_packet)) / - sizeof(struct ospf_lsa_header); - - for (i = 0; i < j; i++) - ospf_dump_lsahdr(p, &lsas[i]); + ospf_dbdes_body(po, pkt, ntohs(pkt->length), &lsas, &lsa_count); + for (i = 0; i < lsa_count; i++) + ospf_dump_lsahdr(po, lsas + i); } +static void +ospf_dbdes_prepare(struct ospf_neighbor *n, struct ospf_packet *pkt, int lsdb) +{ + struct ospf_iface *ifa = n->ifa; + struct proto_ospf *po = ifa->oa->po; + int i = 0; + + ospf_pkt_fill_hdr(ifa, pkt, DBDES_P); + + if (lsdb && (n->myimms & DBDES_M)) + { + struct ospf_lsa_header *lsas; + unsigned lsa_max; + snode *sn; + + ospf_dbdes_body(po, pkt, ospf_pkt_maxsize(ifa), &lsas, &lsa_max); + sn = s_get(&(n->dbsi)); + + while (i < lsa_max) + { + struct top_hash_entry *en = (struct top_hash_entry *) sn; + + if (lsa_flooding_allowed(en->lsa_type, en->domain, ifa)) + { + lsa_hton_hdr(&(en->lsa), lsas + i); + i++; + } + + if (sn == STAIL(po->lsal)) + { + n->myimms &= ~DBDES_M; /* Unset more bit */ + break; + } + + sn = sn->next; + } + + s_put(&(n->dbsi), sn); + } + + u16 iface_mtu = (ifa->type == OSPF_IT_VLINK) ? 0 : ifa->iface->mtu; + unsigned length; + + if (ospf_is_v2(po)) + { + struct ospf_dbdes2_packet *ps = (void *) pkt; + + ps->iface_mtu = htons(iface_mtu); + ps->options = ifa->oa->options; + ps->imms = n->myimms; + ps->ddseq = htonl(n->dds); + + length = sizeof(struct ospf_dbdes2_packet); + } + else /* OSPFv3 */ + { + struct ospf_dbdes3_packet *ps = (void *) pkt; + + ps->options = htonl(ifa->oa->options); + ps->iface_mtu = htons(iface_mtu); + ps->imms = n->myimms; + ps->ddseq = htonl(n->dds); + + length = sizeof(struct ospf_dbdes3_packet); + } + + length += i * sizeof(struct ospf_lsa_header); + pkt->length = htons(length); +} + /** * ospf_dbdes_send - transmit database description packet * @n: neighbor @@ -110,10 +179,8 @@ ospf_dbdes_send(struct ospf_neighbor *n, int next) struct ospf_iface *ifa = n->ifa; struct ospf_area *oa = ifa->oa; struct proto_ospf *po = oa->po; - - struct ospf_dbdes_packet *pkt; - struct ospf_packet *op; - u16 length, i, j; + struct ospf_packet *pkt; + unsigned length; /* FIXME ??? */ if ((oa->rt == NULL) || (EMPTY_LIST(po->lsal))) @@ -121,19 +188,13 @@ ospf_dbdes_send(struct ospf_neighbor *n, int next) switch (n->state) { - case NEIGHBOR_EXSTART: /* Send empty packets */ + case NEIGHBOR_EXSTART: n->myimms |= DBDES_I; - pkt = ospf_tx_buffer(ifa); - op = &pkt->ospf_packet; - ospf_pkt_fill_hdr(ifa, pkt, DBDES_P); - pkt->iface_mtu = (ifa->type == OSPF_IT_VLINK) ? 0 : htons(ifa->iface->mtu); - pkt->options = hton_opt(oa->options); - pkt->imms = n->myimms; - pkt->ddseq = htonl(n->dds); - length = sizeof(struct ospf_dbdes_packet); - op->length = htons(length); - OSPF_PACKET(ospf_dump_dbdes, pkt, "DBDES packet sent to %I via %s", n->ip, ifa->iface->name); + /* Send empty packets */ + pkt = ospf_tx_buffer(ifa); + ospf_dbdes_prepare(n, pkt, 0); + OSPF_PACKET(ospf_dbdes_dump, pkt, "DBDES packet sent to %I via %s", n->ip, ifa->iface->name); ospf_send_to(ifa, n->ip); break; @@ -141,72 +202,12 @@ ospf_dbdes_send(struct ospf_neighbor *n, int next) n->myimms &= ~DBDES_I; if (next) - { - snode *sn; - struct ospf_lsa_header *lsa; - - pkt = n->ldbdes; - op = (struct ospf_packet *) pkt; - - ospf_pkt_fill_hdr(ifa, pkt, DBDES_P); - pkt->iface_mtu = (ifa->type == OSPF_IT_VLINK) ? 0 : htons(ifa->iface->mtu); - 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)); - - if (n->myimms & DBDES_M) - { - sn = s_get(&(n->dbsi)); - - DBG("Number of LSA: %d\n", j); - for (; i > 0; i--) - { - struct top_hash_entry *en= (struct top_hash_entry *) sn; - - if (ospf_lsa_flooding_allowed(&en->lsa, en->domain, ifa)) - { - htonlsah(&(en->lsa), lsa); - DBG("Working on: %d\n", i); - DBG("\tX%01x %-1R %-1R %p\n", en->lsa.type, en->lsa.id, en->lsa.rt, en->lsa_body); - - lsa++; - } - else i++; /* No lsa added */ - - if (sn == STAIL(po->lsal)) - { - i--; - break; - } - - sn = sn->next; - } - - if (sn == STAIL(po->lsal)) - { - DBG("Number of LSA NOT sent: %d\n", i); - DBG("M bit unset.\n"); - n->myimms &= ~DBDES_M; /* Unset more bit */ - } - - s_put(&(n->dbsi), sn); - } - - pkt->imms = n->myimms; - - length = (j - i) * sizeof(struct ospf_lsa_header) + - sizeof(struct ospf_dbdes_packet); - op->length = htons(length); - - DBG("%s: DB_DES (M) prepared for %I.\n", p->name, n->ip); - } + ospf_dbdes_prepare(n, n->ldbdes, 1); case NEIGHBOR_LOADING: case NEIGHBOR_FULL: - length = ntohs(((struct ospf_packet *) n->ldbdes)->length); + length = ntohs(((struct ospf_packet *) n->ldbdes)->length); if (!length) { OSPF_TRACE(D_PACKETS, "No packet in my buffer for repeating"); @@ -218,21 +219,19 @@ ospf_dbdes_send(struct ospf_neighbor *n, int next) pkt = ospf_tx_buffer(ifa); memcpy(pkt, n->ldbdes, length); - OSPF_PACKET(ospf_dump_dbdes, pkt, "DBDES packet sent to %I via %s", n->ip, ifa->iface->name); + OSPF_PACKET(ospf_dbdes_dump, pkt, "DBDES packet sent to %I via %s", n->ip, ifa->iface->name); ospf_send_to(ifa, n->ip); + /* XXXX remove this? */ if (n->myimms & DBDES_MS) tm_start(n->rxmt_timer, n->ifa->rxmtint); /* Restart timer */ if (!(n->myimms & DBDES_MS)) - { if (!(n->myimms & DBDES_M) && !(n->imms & DBDES_M) && (n->state == NEIGHBOR_EXCHANGE)) - { ospf_neigh_sm(n, INM_EXDONE); - } - } + break; default: /* Ignore it */ @@ -241,36 +240,35 @@ ospf_dbdes_send(struct ospf_neighbor *n, int next) } static void -ospf_dbdes_reqladd(struct ospf_dbdes_packet *ps, struct ospf_neighbor *n) +ospf_dbdes_process(struct ospf_neighbor *n, struct ospf_packet *pkt, unsigned plen) { - struct ospf_lsa_header *plsa, lsa; - struct top_hash_entry *he, *sn; - struct ospf_area *oa = n->ifa->oa; - struct top_graph *gr = oa->po->gr; - struct ospf_packet *op; - int i, j; + struct ospf_iface *ifa = n->ifa; + struct proto_ospf *po = ifa->oa->po; + struct ospf_lsa_header *lsas; + unsigned i, lsa_count; - op = (struct ospf_packet *) ps; + ospf_dbdes_body(po, pkt, plen, &lsas, &lsa_count); - plsa = (void *) (ps + 1); - - j = (ntohs(op->length) - sizeof(struct ospf_dbdes_packet)) / - sizeof(struct ospf_lsa_header); - - for (i = 0; i < j; i++) + for (i = 0; i < lsa_count; i++) { - ntohlsah(plsa + i, &lsa); - u32 dom = ospf_lsa_domain(lsa.type, n->ifa); - if (((he = ospf_hash_find_header(gr, dom, &lsa)) == NULL) || - (lsa_comp(&lsa, &(he->lsa)) == 1)) + struct top_hash_entry *en, *req; + struct ospf_lsa_header lsa; + u32 lsa_type, lsa_domain; + + lsa_ntoh_hdr(lsas + i, &lsa); + lsa_xxxxtype(lsa.type_raw, ifa, &lsa_type, &lsa_domain); + + /* XXXX: Add check for 0-type or flooding_allowed */ + + en = ospf_hash_find(po->gr, lsa_domain, lsa.id, lsa.rt, lsa_type); + if (!en || (lsa_comp(&lsa, &(en->lsa)) == CMP_NEWER)) { - /* Is this condition necessary? */ - if (ospf_hash_find_header(n->lsrqh, dom, &lsa) == NULL) - { - sn = ospf_hash_get_header(n->lsrqh, dom, &lsa); - ntohlsah(plsa + i, &(sn->lsa)); - s_add_tail(&(n->lsrql), SNODE sn); - } + req = ospf_hash_get(n->lsrqh, lsa_domain, lsa.id, lsa.rt, lsa_type); + + if (ospf_hash_is_new(req)) + s_add_tail(&(n->lsrql), SNODE req); + + en->lsa = lsa; } } } @@ -280,19 +278,22 @@ ospf_dbdes_receive(struct ospf_packet *pkt, struct ospf_iface *ifa, struct ospf_neighbor *n) { struct proto_ospf *po = ifa->oa->po; - u32 rcv_ddseq, rcv_options; u16 rcv_iface_mtu; u8 rcv_imms; + unsigned plen; - - unsigned int size = ntohs(ps_i->length); - if (size < sizeof(struct ospf_dbdes_packet)) + plen = ntohs(pkt->length); + if (plen < ospf_dbdes_hdrlen(po)) { - log(L_ERR "Bad OSPF DBDES packet from %I - too short (%u B)", n->ip, size); + log(L_ERR "OSPF: Bad DBDES packet from %I - too short (%u B)", n->ip, plen); return; } + OSPF_PACKET(ospf_dbdes_dump, pkt, "DBDES packet received from %I via %s", n->ip, ifa->iface->name); + + ospf_neigh_sm(n, INM_HELLOREC); + if (ospf_is_v2(po)) { struct ospf_dbdes2_packet *ps = (void *) pkt; @@ -310,10 +311,6 @@ ospf_dbdes_receive(struct ospf_packet *pkt, struct ospf_iface *ifa, rcv_ddseq = ntohl(ps->ddseq); } - OSPF_PACKET(ospf_dbdes_dump, ps, "DBDES packet received from %I via %s", n->ip, ifa->iface->name); - - ospf_neigh_sm(n, INM_HELLOREC); - switch (n->state) { case NEIGHBOR_DOWN: @@ -331,12 +328,12 @@ ospf_dbdes_receive(struct ospf_packet *pkt, struct ospf_iface *ifa, (rcv_iface_mtu != 0) && (ifa->iface->mtu != 0) && (ifa->type != OSPF_IT_VLINK)) - log(L_WARN "OSPF: MTU mismatch with neighbour %I on interface %s (remote %d, local %d)", + log(L_WARN "OSPF: MTU mismatch with neighbor %I on interface %s (remote %d, local %d)", n->ip, ifa->iface->name, rcv_iface_mtu, ifa->iface->mtu); if ((rcv_imms == DBDES_IMMS) && (n->rid > po->router_id) && - (size == sizeof(struct ospf_dbdes_packet))) + (plen == ospf_dbdes_hdrlen(po))) { /* I'm slave! */ n->dds = rcv_ddseq; @@ -374,7 +371,7 @@ ospf_dbdes_receive(struct ospf_packet *pkt, struct ospf_iface *ifa, (rcv_ddseq == n->ddr)) { /* Duplicate packet */ - OSPF_TRACE(D_PACKETS, "Received duplicate dbdes from %I.", n->ip); + OSPF_TRACE(D_PACKETS, "Received duplicate dbdes from %I", n->ip); if (!(n->myimms & DBDES_MS)) { /* Slave should retransmit dbdes packet */ @@ -417,7 +414,7 @@ ospf_dbdes_receive(struct ospf_packet *pkt, struct ospf_iface *ifa, } n->dds++; DBG("Incrementing dds\n"); - ospf_dbdes_reqladd(ps, n); + ospf_dbdes_process(n, pkt, plen); if (!(n->myimms & DBDES_M) && !(rcv_imms & DBDES_M)) { @@ -439,7 +436,7 @@ ospf_dbdes_receive(struct ospf_packet *pkt, struct ospf_iface *ifa, } n->ddr = rcv_ddseq; n->dds = rcv_ddseq; - ospf_dbdes_reqladd(ps, n); + ospf_dbdes_process(n, pkt, plen); ospf_dbdes_send(n, 1); } break; @@ -451,7 +448,7 @@ ospf_dbdes_receive(struct ospf_packet *pkt, struct ospf_iface *ifa, (rcv_ddseq == n->ddr)) /* Only duplicate are accepted */ { - OSPF_TRACE(D_PACKETS, "Received duplicate dbdes from %I.", n->ip); + OSPF_TRACE(D_PACKETS, "Received duplicate dbdes from %I", n->ip); if (!(n->myimms & DBDES_MS)) { /* Slave should retransmit dbdes packet */ diff --git a/proto/ospf/hello.c b/proto/ospf/hello.c index b699dd7e..08ad6f91 100644 --- a/proto/ospf/hello.c +++ b/proto/ospf/hello.c @@ -48,7 +48,6 @@ ospf_hello_receive(struct ospf_packet *pkt, struct ospf_iface *ifa, struct ospf_neighbor *n, ip_addr faddr) { struct proto_ospf *po = ifa->oa->po; - struct proto *p = &po->proto; char *beg = "OSPF: Bad HELLO packet from "; unsigned int size, i, two_way; diff --git a/proto/ospf/iface.c b/proto/ospf/iface.c index e004c05e..d029545b 100644 --- a/proto/ospf/iface.c +++ b/proto/ospf/iface.c @@ -72,6 +72,8 @@ find_nbma_node_in(list *nnl, ip_addr ip) static int ospf_sk_open(struct ospf_iface *ifa) { + struct proto_ospf *po = ifa->oa->po; + sock *sk = sk_new(ifa->pool); sk->type = SK_IP; sk->dport = OSPF_PROTO; @@ -90,11 +92,10 @@ ospf_sk_open(struct ospf_iface *ifa) if (sk_open(sk) != 0) goto err; -#ifdef OSPFv3 - /* 12 is an offset of the checksum in an OSPF packet */ - if (sk_set_ipv6_checksum(sk, 12) < 0) - goto err; -#endif + /* 12 is an offset of the checksum in an OSPFv3 packet */ + if (ospf_is_v3(po)) + if (sk_set_ipv6_checksum(sk, 12) < 0) + goto err; /* * For OSPFv2: When sending a packet, it is important to have a @@ -123,14 +124,16 @@ ospf_sk_open(struct ospf_iface *ifa) if (ifa->cf->real_bcast) { ifa->all_routers = ifa->addr->brd; + ifa->des_routers = IPA_NONE; if (sk_set_broadcast(sk, 1) < 0) goto err; } else { - ifa->all_routers = AllSPFRouters; - sk->ttl = 1; /* Hack, this will affect just multicast packets */ + ifa->all_routers = ospf_is_v2(po) ? IP4_OSPF_ALL_ROUTERS : IP6_OSPF_ALL_ROUTERS; + ifa->des_routers = ospf_is_v2(po) ? IP4_OSPF_DES_ROUTERS : IP6_OSPF_DES_ROUTERS; + sk->ttl = 1; /* Hack, this will affect just the multicast packets */ if (sk_setup_multicast(sk) < 0) goto err; @@ -155,7 +158,7 @@ ospf_sk_join_dr(struct ospf_iface *ifa) if (ifa->sk_dr) return; - sk_join_group(ifa->sk, AllDRouters); + sk_join_group(ifa->sk, ifa->des_routers); ifa->sk_dr = 1; } @@ -165,7 +168,7 @@ ospf_sk_leave_dr(struct ospf_iface *ifa) if (!ifa->sk_dr) return; - sk_leave_group(ifa->sk, AllDRouters); + sk_leave_group(ifa->sk, ifa->des_routers); ifa->sk_dr = 0; } @@ -178,13 +181,15 @@ ospf_iface_down(struct ospf_iface *ifa) if (ifa->type != OSPF_IT_VLINK) { -#ifdef OSPFv2 - OSPF_TRACE(D_EVENTS, "Removing interface %s (%I/%d) from area %R", - ifa->iface->name, ifa->addr->prefix, ifa->addr->pxlen, ifa->oa->areaid); -#else - OSPF_TRACE(D_EVENTS, "Removing interface %s (IID %d) from area %R", - ifa->iface->name, ifa->instance_id, ifa->oa->areaid); -#endif + if (ospf_is_v3(ifa->oa->po)) + OSPF_TRACE(D_EVENTS, "Removing interface %s (IID %d) from area %R", + ifa->iface->name, ifa->instance_id, ifa->oa->areaid); + else if (ifa->addr->flags & IA_PEER) + OSPF_TRACE(D_EVENTS, "Removing interface %s (peer %I) from area %R", + ifa->iface->name, ifa->addr->opposite, ifa->oa->areaid); + else + OSPF_TRACE(D_EVENTS, "Removing interface %s (%I/%d) from area %R", + ifa->iface->name, ifa->addr->prefix, ifa->addr->pxlen, ifa->oa->areaid); /* First of all kill all the related vlinks */ WALK_LIST(iff, po->iface_list) @@ -221,10 +226,8 @@ ospf_iface_down(struct ospf_iface *ifa) ifa->rt_pos_beg = 0; ifa->rt_pos_end = 0; -#ifdef OSPFv3 ifa->px_pos_beg = 0; ifa->px_pos_end = 0; -#endif } @@ -275,7 +278,7 @@ ospf_iface_chstate(struct ospf_iface *ifa, u8 state) OSPF_TRACE(D_EVENTS, "Changing state of iface %s from %s to %s", ifa->iface->name, ospf_is[oldstate], ospf_is[state]); - if ((ifa->type == OSPF_IT_BCAST) && !ifa->cf->real_bcast && ifa->sk) + if ((ifa->type == OSPF_IT_BCAST) && ipa_nonzero(ifa->des_routers) && ifa->sk) { if ((state == OSPF_IS_BACKUP) || (state == OSPF_IS_DR)) ospf_sk_join_dr(ifa); @@ -499,16 +502,15 @@ ospf_iface_new(struct ospf_area *oa, struct ifa *addr, struct ospf_iface_patt *i if (ip->type == OSPF_IT_VLINK) OSPF_TRACE(D_EVENTS, "Adding vlink to %R via area %R", ip->vid, ip->voa); - else - { -#ifdef OSPFv2 - OSPF_TRACE(D_EVENTS, "Adding interface %s (%I/%d) to area %R", - iface->name, addr->prefix, addr->pxlen, oa->areaid); -#else + else if (ospf_is_v3(po)) OSPF_TRACE(D_EVENTS, "Adding interface %s (IID %d) to area %R", iface->name, ip->instance_id, oa->areaid); -#endif - } + else if (ifa->addr->flags & IA_PEER) + OSPF_TRACE(D_EVENTS, "Adding interface %s (peer %I) to area %R", + iface->name, addr->opposite, oa->areaid); + else + OSPF_TRACE(D_EVENTS, "Adding interface %s (%I/%d) to area %R", + iface->name, addr->prefix, addr->pxlen, oa->areaid); pool = rp_new(po->proto.pool, "OSPF Interface"); ifa = mb_allocz(pool, sizeof(struct ospf_iface)); @@ -532,15 +534,9 @@ ospf_iface_new(struct ospf_area *oa, struct ifa *addr, struct ospf_iface_patt *i ifa->rxbuf = ip->rxbuf; ifa->check_link = ip->check_link; ifa->ecmp_weight = ip->ecmp_weight; - -#ifdef OSPFv2 ifa->autype = ip->autype; ifa->passwords = ip->passwords; -#endif - -#ifdef OSPFv3 ifa->instance_id = ip->instance_id; -#endif ifa->type = ospf_iface_classify(ip->type, addr); @@ -548,13 +544,11 @@ ospf_iface_new(struct ospf_area *oa, struct ifa *addr, struct ospf_iface_patt *i int old_type = ifa->type; u32 if_multi_flag = ip->real_bcast ? IF_BROADCAST : IF_MULTICAST; -#ifdef OSPFv2 - if ((ifa->type == OSPF_IT_BCAST) && (addr->flags & IA_PEER)) + if (ospf_is_v2(po) && (ifa->type == OSPF_IT_BCAST) && (addr->flags & IA_PEER)) ifa->type = OSPF_IT_PTP; - if ((ifa->type == OSPF_IT_NBMA) && (addr->flags & IA_PEER)) + if (ospf_is_v2(po) && (ifa->type == OSPF_IT_NBMA) && (addr->flags & IA_PEER)) ifa->type = OSPF_IT_PTMP; -#endif if ((ifa->type == OSPF_IT_BCAST) && !(iface->flags & if_multi_flag)) ifa->type = OSPF_IT_NBMA; @@ -564,7 +558,7 @@ ospf_iface_new(struct ospf_area *oa, struct ifa *addr, struct ospf_iface_patt *i if (ifa->type != old_type) log(L_WARN "%s: Cannot use interface %s as %s, forcing %s", - p->name, iface->name, ospf_it[old_type], ospf_it[ifa->type]); + po->proto.name, iface->name, ospf_it[old_type], ospf_it[ifa->type]); init_list(&ifa->neigh_list); @@ -595,11 +589,7 @@ ospf_iface_new(struct ospf_area *oa, struct ifa *addr, struct ospf_iface_patt *i */ lock = olock_new(pool); -#ifdef OSPFv2 - lock->addr = ifa->addr->prefix; -#else /* OSPFv3 */ - lock->addr = _MI(0,0,0,ifa->instance_id); -#endif + lock->addr = ospf_is_v2(po) ? ifa->addr->prefix : _MI6(0,0,0,ifa->instance_id); lock->type = OBJLOCK_IP; lock->port = OSPF_PROTO; lock->iface = iface; @@ -702,7 +692,6 @@ ospf_iface_reconfigure(struct ospf_iface *ifa, struct ospf_iface_patt *new) ifa->inftransdelay = new->inftransdelay; } -#ifdef OSPFv2 /* AUTHENTICATION */ if (ifa->autype != new->autype) { @@ -712,7 +701,6 @@ ospf_iface_reconfigure(struct ospf_iface *ifa, struct ospf_iface_patt *new) /* Update passwords */ ifa->passwords = new->passwords; -#endif /* Remaining options are just for proper interfaces */ if (ifa->type == OSPF_IT_VLINK) @@ -1133,14 +1121,13 @@ ospf_iface_info(struct ospf_iface *ifa) } else { -#ifdef OSPFv2 - if (ifa->addr->flags & IA_PEER) + if (ospf_is_v3(ifa->oa->po)) + cli_msg(-1015, "Interface %s (IID %d)", ifa->iface->name, ifa->instance_id); + else if (ifa->addr->flags & IA_PEER) cli_msg(-1015, "Interface %s (peer %I)", ifa->iface->name, ifa->addr->opposite); else cli_msg(-1015, "Interface %s (%I/%d)", ifa->iface->name, ifa->addr->prefix, ifa->addr->pxlen); -#else /* OSPFv3 */ - cli_msg(-1015, "Interface %s (IID %d)", ifa->iface->name, ifa->instance_id); -#endif + cli_msg(-1015, "\tType: %s%s", ospf_it[ifa->type], more); cli_msg(-1015, "\tArea: %R (%u)", ifa->oa->areaid, ifa->oa->areaid); } diff --git a/proto/ospf/lsack.c b/proto/ospf/lsack.c index dc59dde0..35ddfec6 100644 --- a/proto/ospf/lsack.c +++ b/proto/ospf/lsack.c @@ -96,10 +96,8 @@ ospf_lsack_send_one(struct ospf_neighbor *n, int queue) { if ((ifa->state == OSPF_IS_DR) || (ifa->state == OSPF_IS_BACKUP)) ospf_send_to_all(ifa); - else if (ifa->cf->real_bcast) - ospf_send_to_bdr(ifa); else - ospf_send_to(ifa, AllDRouters); + ospf_send_to_des(ifa); } else ospf_send_to_agt(ifa, NEIGHBOR_EXCHANGE); @@ -127,6 +125,7 @@ ospf_lsack_receive(struct ospf_packet *pkt, struct ospf_iface *ifa, struct ospf_lsa_header lsa, *lsas; struct top_hash_entry *en; unsigned i, lsa_count; + u32 lsa_dom, lsa_type; /* No need to check length, lsack has only basic header */ @@ -142,9 +141,11 @@ ospf_lsack_receive(struct ospf_packet *pkt, struct ospf_iface *ifa, ospf_lsack_body(po, pkt, ntohs(pkt->length), &lsas, &lsa_count); for (i = 0; i < lsa_count; i++) { - ntohlsah(&lsas[i], &lsa); - u32 dom = ospf_lsa_domain(lsa.type, n->ifa); - if ((en = ospf_hash_find_header(n->lsrth, dom, &lsa)) == NULL) + lsa_ntoh_hdr(&lsas[i], &lsa); + lsa_xxxxtype(lsa.type_raw, n->ifa, &lsa_type, &lsa_dom); + + en = ospf_hash_find(n->lsrth, lsa_dom, lsa.id, lsa.rt, lsa_type); + if (!en) continue; /* pg 155 */ if (lsa_comp(&lsa, &en->lsa) != CMP_SAME) /* pg 156 */ @@ -154,7 +155,7 @@ ospf_lsack_receive(struct ospf_packet *pkt, struct ospf_iface *ifa, OSPF_TRACE(D_PACKETS, "Strange LSACK from %I", n->ip); OSPF_TRACE(D_PACKETS, "Type: %04x, Id: %R, Rt: %R", - lsa.type, lsa.id, lsa.rt); + lsa_type, lsa.id, lsa.rt); OSPF_TRACE(D_PACKETS, "I have: Age: %4u, Seq: %08x, Sum: %04x", en->lsa.age, en->lsa.sn, en->lsa.checksum); OSPF_TRACE(D_PACKETS, "He has: Age: %4u, Seq: %08x, Sum: %04x", @@ -162,8 +163,8 @@ ospf_lsack_receive(struct ospf_packet *pkt, struct ospf_iface *ifa, continue; } - DBG("Deleting LS Id: %R RT: %R Type: %u from LS Retl for neighbor %R\n", - lsa.id, lsa.rt, lsa.type, n->rid); + DBG("Deleting LSA (Type: %04x Id: %R Rt: %R) from lsrtl for neighbor %R\n", + lsa_type, lsa.id, lsa.rt, n->rid); s_rem_node(SNODE en); ospf_hash_delete(n->lsrth, en); } diff --git a/proto/ospf/lsalib.c b/proto/ospf/lsalib.c index 00dd2893..aa3dc741 100644 --- a/proto/ospf/lsalib.c +++ b/proto/ospf/lsalib.c @@ -89,10 +89,10 @@ ospf_age(struct proto_ospf *po) #ifndef CPU_BIG_ENDIAN void -htonlsah(struct ospf_lsa_header *h, struct ospf_lsa_header *n) +lsa_hton_hdr(struct ospf_lsa_header *h, struct ospf_lsa_header *n) { n->age = htons(h->age); - n->type_raw = htont(h->type_raw); + n->type_raw = htons(h->type_raw); n->id = htonl(h->id); n->rt = htonl(h->rt); n->sn = htonl(h->sn); @@ -101,10 +101,10 @@ htonlsah(struct ospf_lsa_header *h, struct ospf_lsa_header *n) } void -ntohlsah(struct ospf_lsa_header *n, struct ospf_lsa_header *h) +lsa_ntoh_hdr(struct ospf_lsa_header *n, struct ospf_lsa_header *h) { h->age = ntohs(n->age); - h->type_raw = ntoht(n->type_raw); + h->type_raw = ntohs(n->type_raw); h->id = ntohl(n->id); h->rt = ntohl(n->rt); h->sn = ntohl(n->sn); @@ -113,7 +113,7 @@ ntohlsah(struct ospf_lsa_header *n, struct ospf_lsa_header *h) } void -htonlsab(void *h, void *n, u16 len) +lsa_hton_body(void *h, void *n, u16 len) { u32 *hid = h; u32 *nid = n; @@ -124,7 +124,7 @@ htonlsab(void *h, void *n, u16 len) } void -ntohlsab(void *n, void *h, u16 len) +lsa_ntoh_body(void *n, void *h, u16 len) { u32 *nid = n; u32 *hid = h; @@ -135,6 +135,95 @@ ntohlsab(void *n, void *h, u16 len) } #endif /* little endian */ + + +int +lsa_flooding_allowed(u32 type, u32 domain, struct ospf_iface *ifa) +{ + /* 4.5.2 (Case 2) */ + + switch (LSA_SCOPE(type)) + { + 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 (!oa_is_ext(ifa->oa)) + return 0; + return 1; + + default: + log(L_ERR "OSPF: LSA with invalid scope"); + return 0; + } +} + + +static int +unknown_lsa_type(u32 type) +{ + switch (type) + { + case LSA_T_RT: + case LSA_T_NET: + case LSA_T_SUM_NET: + case LSA_T_SUM_RT: + case LSA_T_EXT: + case LSA_T_NSSA: + case LSA_T_LINK: + case LSA_T_PREFIX: + return 0; + + default: + return 1; + } +} + +#define LSA_V2_TMAX 8 +static const u16 lsa_v2_types[LSA_V2_TMAX] = + {0, LSA_T_RT, LSA_T_NET, LSA_T_SUM_NET, LSA_T_SUM_RT, LSA_T_EXT, 0, LSA_T_NSSA}; + +void +lsa_xxxxtype(u32 itype, struct ospf_iface *ifa, u32 *otype, u32 *domain) +{ + if (ospf_is_v2(ifa->oa->po)) + { + itype = itype & LSA_T_V2_MASK; + itype = (itype < LSA_V2_TMAX) ? lsa_v2_types[itype] : 0; + } + else + { + /* For unkown LSAs without U-bit change scope to LSA_SCOPE_LINK */ + if (unknown_lsa_type(itype) && !(itype & LSA_UBIT)) + itype = itype & ~LSA_SCOPE_MASK; + } + + *otype = itype; + + switch (LSA_SCOPE(itype)) + { + case LSA_SCOPE_LINK: + *domain = ifa->iface->index; + return; + + case LSA_SCOPE_AREA: + *domain = ifa->oa->areaid; + return; + + case LSA_SCOPE_AS: + default: + *domain = 0; + return; + } +} + + + /* void buf_dump(const char *hdr, const byte *buf, int blen) @@ -179,8 +268,8 @@ lsasum_calculate(struct ospf_lsa_header *h, void *body) u16 length = h->length; // log(L_WARN "Checksum %R %R %d start (len %d)", h->id, h->rt, h->type, length); - htonlsah(h, h); - htonlsab1(body, length - sizeof(struct ospf_lsa_header)); + lsa_hton_hdr(h, h); + lsa_hton_body1(body, length - sizeof(struct ospf_lsa_header)); /* char buf[1024]; @@ -193,8 +282,8 @@ lsasum_calculate(struct ospf_lsa_header *h, void *body) // log(L_WARN "Checksum result %4x", h->checksum); - ntohlsah(h, h); - ntohlsab1(body, length - sizeof(struct ospf_lsa_header)); + lsa_ntoh_hdr(h, h); + lsa_ntoh_body1(body, length - sizeof(struct ospf_lsa_header)); } /* @@ -427,30 +516,60 @@ lsa_parse_ext(struct top_hash_entry *en, int ospf2, struct ospf_lsa_ext_local *r #define HDRLEN sizeof(struct ospf_lsa_header) static int -lsa_validate_rt(struct ospf_lsa_header *lsa, struct ospf_lsa_rt *body) +lsa_validate_rt2(struct ospf_lsa_header *lsa, struct ospf_lsa_rt *body) { - unsigned int i, max; - if (lsa->length < (HDRLEN + sizeof(struct ospf_lsa_rt))) return 0; - struct ospf_lsa_rt_link *rtl = (struct ospf_lsa_rt_link *) (body + 1); - max = lsa_rt_count(lsa); + unsigned i = 0; + void *buf = body; + void *bufend = buf + lsa->length - HDRLEN; + buf += sizeof(struct ospf_lsa_rt); -#ifdef OSPFv2 - if (body->links != max) - return 0; -#endif - - for (i = 0; i < max; i++) + while (buf < bufend) { - u8 type = rtl[i].type; - if (!((type == LSART_PTP) || - (type == LSART_NET) || -#ifdef OSPFv2 - (type == LSART_STUB) || -#endif - (type == LSART_VLNK))) + struct ospf_lsa_rt2_link *l = buf; + buf += sizeof(struct ospf_lsa_rt2_link) + l->no_tos * sizeof(struct ospf_lsa_rt2_tos); + i++; + + if (buf > bufend) + return 0; + + if (!((l->type == LSART_PTP) || + (l->type == LSART_NET) || + (l->type == LSART_STUB) || + (l->type == LSART_VLNK))) + return 0; + } + + if ((body->options & LSA_RT2_LINKS) != i) + return 0; + + return 1; +} + + +static int +lsa_validate_rt3(struct ospf_lsa_header *lsa, struct ospf_lsa_rt *body) +{ + if (lsa->length < (HDRLEN + sizeof(struct ospf_lsa_rt))) + return 0; + + void *buf = body; + void *bufend = buf + lsa->length - HDRLEN; + buf += sizeof(struct ospf_lsa_rt); + + while (buf < bufend) + { + struct ospf_lsa_rt3_link *l = buf; + buf += sizeof(struct ospf_lsa_rt3_link); + + if (buf > bufend) + return 0; + + if (!((l->type == LSART_PTP) || + (l->type == LSART_NET) || + (l->type == LSART_VLNK))) return 0; } return 1; @@ -465,37 +584,18 @@ lsa_validate_net(struct ospf_lsa_header *lsa, struct ospf_lsa_net *body UNUSED) return 1; } -#ifdef OSPFv2 - static int -lsa_validate_sum(struct ospf_lsa_header *lsa, struct ospf_lsa_sum *body) +lsa_validate_sum2(struct ospf_lsa_header *lsa, struct ospf_lsa_sum2 *body) { - if (lsa->length < (HDRLEN + sizeof(struct ospf_lsa_sum))) + if (lsa->length < (HDRLEN + sizeof(struct ospf_lsa_sum2))) return 0; /* First field should have TOS = 0, we ignore other TOS fields */ - if ((body->metric & LSA_SUM_TOS) != 0) + if ((body->metric & LSA_SUM2_TOS) != 0) return 0; return 1; } -#define lsa_validate_sum_net(A,B) lsa_validate_sum(A,B) -#define lsa_validate_sum_rt(A,B) lsa_validate_sum(A,B) - -static int -lsa_validate_ext(struct ospf_lsa_header *lsa, struct ospf_lsa_ext *body) -{ - if (lsa->length < (HDRLEN + sizeof(struct ospf_lsa_ext))) - return 0; - - /* First field should have TOS = 0, we ignore other TOS fields */ - if ((body->metric & LSA_EXT_TOS) != 0) - return 0; - - return 1; -} - -#else /* OSPFv3 */ static inline int pxlen(u32 *buf) @@ -504,7 +604,7 @@ pxlen(u32 *buf) } static int -lsa_validate_sum_net(struct ospf_lsa_header *lsa, struct ospf_lsa_sum3_net *body) +lsa_validate_sum3_net(struct ospf_lsa_header *lsa, struct ospf_lsa_sum3_net *body) { if (lsa->length < (HDRLEN + sizeof(struct ospf_lsa_sum3_net) + 4)) return 0; @@ -520,9 +620,8 @@ lsa_validate_sum_net(struct ospf_lsa_header *lsa, struct ospf_lsa_sum3_net *body return 1; } - static int -lsa_validate_sum_rt(struct ospf_lsa_header *lsa, struct ospf_lsa_sum3_rt *body) +lsa_validate_sum3_rt(struct ospf_lsa_header *lsa, struct ospf_lsa_sum3_rt *body) { if (lsa->length != (HDRLEN + sizeof(struct ospf_lsa_sum3_rt))) return 0; @@ -531,7 +630,20 @@ lsa_validate_sum_rt(struct ospf_lsa_header *lsa, struct ospf_lsa_sum3_rt *body) } static int -lsa_validate_ext(struct ospf_lsa_header *lsa, struct ospf_lsa_ext3 *body) +lsa_validate_ext2(struct ospf_lsa_header *lsa, struct ospf_lsa_ext2 *body) +{ + if (lsa->length < (HDRLEN + sizeof(struct ospf_lsa_ext2))) + return 0; + + /* First field should have TOS = 0, we ignore other TOS fields */ + if ((body->metric & LSA_EXT2_TOS) != 0) + return 0; + + return 1; +} + +static int +lsa_validate_ext3(struct ospf_lsa_header *lsa, struct ospf_lsa_ext3 *body) { if (lsa->length < (HDRLEN + sizeof(struct ospf_lsa_ext3) + 4)) return 0; @@ -596,8 +708,6 @@ lsa_validate_prefix(struct ospf_lsa_header *lsa, struct ospf_lsa_prefix *body) return lsa_validate_pxlist(lsa, body->pxcount, sizeof(struct ospf_lsa_prefix), (u8 *) body); } -#endif - /** * lsa_validate - check whether given LSA is valid @@ -609,31 +719,50 @@ lsa_validate_prefix(struct ospf_lsa_header *lsa, struct ospf_lsa_prefix *body) */ int -lsa_validate(struct ospf_lsa_header *lsa, void *body) +lsa_validate(struct ospf_lsa_header *lsa, u32 lsa_type, int ospf2, void *body) { - switch (lsa->type) + if (ospf2) + { + switch (lsa_type) { case LSA_T_RT: - return lsa_validate_rt(lsa, body); + return lsa_validate_rt2(lsa, body); case LSA_T_NET: return lsa_validate_net(lsa, body); case LSA_T_SUM_NET: - return lsa_validate_sum_net(lsa, body); + return lsa_validate_sum2(lsa, body); case LSA_T_SUM_RT: - return lsa_validate_sum_rt(lsa, body); + return lsa_validate_sum2(lsa, body); case LSA_T_EXT: case LSA_T_NSSA: - return lsa_validate_ext(lsa, body); + return lsa_validate_ext2(lsa, body); + default: + return 0; /* Should not happen, unknown LSAs are already rejected */ + } + } + else + { + switch (lsa_type) + { + case LSA_T_RT: + return lsa_validate_rt3(lsa, body); + case LSA_T_NET: + return lsa_validate_net(lsa, body); + case LSA_T_SUM_NET: + return lsa_validate_sum3_net(lsa, body); + case LSA_T_SUM_RT: + return lsa_validate_sum3_rt(lsa, body); + case LSA_T_EXT: + case LSA_T_NSSA: + return lsa_validate_ext3(lsa, body); case LSA_T_LINK: return lsa_validate_link(lsa, body); case LSA_T_PREFIX: return lsa_validate_prefix(lsa, body); default: - /* In OSPFv3, unknown LSAs are OK, - In OSPFv2, unknown LSAs are already rejected - */ - return 1; + return 1; /* Unknown LSAs are OK in OSPFv3 */ } + } } /** diff --git a/proto/ospf/lsalib.h b/proto/ospf/lsalib.h index 3bdd814f..5bad1ceb 100644 --- a/proto/ospf/lsalib.h +++ b/proto/ospf/lsalib.h @@ -11,19 +11,19 @@ #define _BIRD_OSPF_LSALIB_H_ #ifdef CPU_BIG_ENDIAN -static inline void htonlsah(struct ospf_lsa_header *h, struct ospf_lsa_header *n) { *n = *h; }; -static inline void ntohlsah(struct ospf_lsa_header *n, struct ospf_lsa_header *h) { *h = *n; }; -static inline void htonlsab(void *h, void *n, u16 len) { ASSERT(h != n); memcpy(n, h, len); }; -static inline void ntohlsab(void *n, void *h, u16 len) { ASSERT(n != h); memcpy(h, n, len); }; -static inline void htonlsab1(void *h, u16 len) { }; -static inline void ntohlsab1(void *n, u16 len) { }; +static inline void lsa_hton_hdr(struct ospf_lsa_header *h, struct ospf_lsa_header *n) { *n = *h; }; +static inline void lsa_ntoh_hdr(struct ospf_lsa_header *n, struct ospf_lsa_header *h) { *h = *n; }; +static inline void lsa_hton_body(void *h, void *n, u16 len) { ASSERT(h != n); memcpy(n, h, len); }; +static inline void lsa_ntoh_body(void *n, void *h, u16 len) { ASSERT(n != h); memcpy(h, n, len); }; +static inline void lsa_hton_body1(void *h, u16 len) { }; +static inline void lsa_ntoh_body1(void *n, u16 len) { }; #else -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, u16 len); -void ntohlsab(void *n, void *h, u16 len); -static inline void htonlsab1(void *h, u16 len) { htonlsab(h, h, len); }; -static inline void ntohlsab1(void *n, u16 len) { ntohlsab(n, n, len); }; +void lsa_hton_hdr(struct ospf_lsa_header *h, struct ospf_lsa_header *n); +void lsa_ntoh_hdr(struct ospf_lsa_header *n, struct ospf_lsa_header *h); +void lsa_hton_body(void *h, void *n, u16 len); +void lsa_ntoh_body(void *n, void *h, u16 len); +static inline void lsa_hton_body1(void *h, u16 len) { lsa_hton_body(h, h, len); }; +static inline void lsa_ntoh_body1(void *n, u16 len) { lsa_ntoh_body(n, n, len); }; #endif struct ospf_lsa_rt_walk { @@ -34,6 +34,11 @@ struct ospf_lsa_rt_walk { u32 id, data, lif, nif; }; +static inline u32 lsa_get_type(struct proto_ospf *po, u32 type_raw) +{ return ospf_is_v2(po) ? (type_raw & LSA_T_V2_MASK) : type_raw; } + +int lsa_flooding_allowed(u32 type, u32 domain, struct ospf_iface *ifa); +void lsa_xxxxtype(u32 itype, struct ospf_iface *ifa, u32 *otype, u32 *domain); void lsasum_calculate(struct ospf_lsa_header *header, void *body); u16 lsasum_check(struct ospf_lsa_header *h, void *body); #define CMP_NEWER 1 @@ -45,7 +50,7 @@ int lsa_walk_rt(struct ospf_lsa_rt_walk *rt); void lsa_parse_sum_net(struct top_hash_entry *en, int ospf2, ip_addr *ip, int *pxlen, u8 *pxopts, u32 *metric); void lsa_parse_sum_rt(struct top_hash_entry *en, int ospf2, u32 *drid, u32 *metric, u32 *options); void lsa_parse_ext(struct top_hash_entry *en, int ospf2, struct ospf_lsa_ext_local *rt); -int lsa_validate(struct ospf_lsa_header *lsa, void *body); +int lsa_validate(struct ospf_lsa_header *lsa, u32 lsa_type, int ospf2, void *body); 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 ae9e7e41..721e0379 100644 --- a/proto/ospf/lsreq.c +++ b/proto/ospf/lsreq.c @@ -19,7 +19,7 @@ struct ospf_lsreq_packet }; */ -static void +static inline void ospf_lsreq_body(struct proto_ospf *po, struct ospf_packet *pkt, unsigned plen, struct ospf_lsreq_header **body, unsigned *count) { @@ -71,9 +71,10 @@ ospf_lsreq_send(struct ospf_neighbor *n) { en = (struct top_hash_entry *) sn; DBG("Requesting %uth LSA: Type: %u, ID: %R, RT: %R, SN: 0x%x, Age %u\n", - i, en->lsa.type, en->lsa.id, en->lsa.rt, en->lsa.sn, en->lsa.age); + i, en->lsa_type, en->lsa.id, en->lsa.rt, en->lsa.sn, en->lsa.age); - lsrs[i].type = htonl(en->lsa.type); + u32 rtype = lsa_get_type(po, en->lsa.type_raw); + lsrs[i].type = htonl(rtype); lsrs[i].rt = htonl(en->lsa.rt); lsrs[i].id = htonl(en->lsa.id); @@ -97,7 +98,9 @@ ospf_lsreq_receive(struct ospf_packet *pkt, struct ospf_iface *ifa, struct proto_ospf *po = ifa->oa->po; struct ospf_lsreq_header *lsrs; unsigned i, lsr_count; - list uplist; + + struct ospf_lsreq_item *lsr_head, *lsr; + struct ospf_lsreq_item **lsr_pos = &lsr_head; slab *upslab; @@ -111,35 +114,39 @@ ospf_lsreq_receive(struct ospf_packet *pkt, struct ospf_iface *ifa, ospf_neigh_sm(n, INM_HELLOREC); /* Not in RFC */ - init_list(&uplist); - upslab = sl_new(n->pool, sizeof(struct l_lsr_head)); + upslab = sl_new(n->pool, sizeof(struct ospf_lsreq_item)); ospf_lsreq_body(po, pkt, ntohs(pkt->length), &lsrs, &lsr_count); for (i = 0; i < lsr_count; i++) { - u32 hid = ntohl(lsrs[i].id); - u32 hrt = ntohl(lsrs[i].rt); - u32 htype = ntohl(lsrs[i].type); - u32 dom = ospf_lsa_domain(htype, ifa); - // XXXX check - DBG("Processing requested LSA: Type: %u, ID: %R, RT: %R\n", htype, hid, hrt); + u32 id, rt, type, dom; - if (ospf_hash_find(po->gr, dom, hid, hrt, htype) == NULL) + id = ntohl(lsrs[i].id); + rt = ntohl(lsrs[i].rt); + lsa_xxxxtype(ntohl(lsrs[i].type), ifa, &type, &dom); + + DBG("Processing requested LSA: Type: %04x, Id: %R, Rt: %R\n", type, id, rt); + + if (ospf_hash_find(po->gr, dom, id, rt, type) == NULL) { log(L_WARN "Received bad LSREQ from %I: Type: %04x, Id: %R, Rt: %R", - n->ip, htype, hid, hrt); + n->ip, type, id, rt); ospf_neigh_sm(n, INM_BADLSREQ); rfree(upslab); return; } - struct l_lsr_head *llsh = sl_alloc(upslab); - llsh->lsh.id = hid; - llsh->lsh.rt = hrt; - llsh->lsh.type = htype; - add_tail(&uplist, NODE llsh); - } + lsr = sl_alloc(upslab); + lsr->domain = dom; + lsr->type = type; + lsr->id = id; + lsr->rt = rt; - ospf_lsupd_send_list(n, &uplist); + *lsr_pos = lsr; + lsr_pos = &(lsr->next); + } + *lsr_pos = NULL; + + ospf_lsupd_send_list(n, lsr_head); rfree(upslab); } diff --git a/proto/ospf/lsupd.c b/proto/ospf/lsupd.c index 9255785e..80c9b0b2 100644 --- a/proto/ospf/lsupd.c +++ b/proto/ospf/lsupd.c @@ -9,21 +9,29 @@ #include "ospf.h" +/* struct ospf_lsupd_packet { - struct ospf_packet ospf_packet; - u32 lsano; /* Number of LSA's */ + struct ospf_packet hdr; + // union ospf_auth auth; + + u32 lsa_count; + void lsas[]; }; +*/ /* Beware of unaligned access */ void ospf_dump_lsahdr(struct proto_ospf *po, struct ospf_lsa_header *lsa_n) { struct ospf_lsa_header lsa; - ntohlsah(lsa_n, &lsa); + u32 lsa_type; + + lsa_ntoh_hdr(lsa_n, &lsa); + lsa_type = lsa_get_type(po, lsa.type_raw); log(L_TRACE "%s: LSA Type: %04x, Id: %R, Rt: %R, Age: %u, Seq: %08x, Sum: %04x", - po->proto.name, lsa.type, lsa.id, lsa.rt, lsa.age, lsa.sn, lsa.checksum); + po->proto.name, lsa_type, lsa.id, lsa.rt, lsa.age, lsa.sn, lsa.checksum); } void ospf_dump_common(struct proto_ospf *po, struct ospf_packet *pkt) @@ -33,22 +41,38 @@ void ospf_dump_common(struct proto_ospf *po, struct ospf_packet *pkt) log(L_TRACE "%s: router %R", p->name, ntohl(pkt->routerid)); } -static void ospf_dump_lsupd(struct proto_ospf *po, struct ospf_lsupd_packet *pkt) +static inline unsigned +ospf_lsupd_hdrlen(struct proto_ospf *po) +{ + return ospf_pkt_hdrlen(po) + 4; /* + u32 lsa count field */ +} + +static inline u32 * +ospf_lsupd_lsa_count(struct ospf_packet *pkt, unsigned hdrlen) +{ return ((void *) pkt) + hdrlen - 4; } + +static inline void +ospf_lsupd_body(struct proto_ospf *po, struct ospf_packet *pkt, + unsigned *offset, unsigned *bound, unsigned *lsa_count) +{ + unsigned hlen = ospf_lsupd_hdrlen(po); + *offset = hlen; + *bound = ntohs(pkt->length) - sizeof(struct ospf_lsa_header); + *lsa_count = ntohl(*ospf_lsupd_lsa_count(pkt, hlen)); +} + +static void ospf_lsupd_dump(struct proto_ospf *po, struct ospf_packet *pkt) { struct proto *p = &po->proto; - struct ospf_packet *op = &pkt->ospf_packet; - ASSERT(op->type == LSUPD_P); - ospf_dump_common(po, op); + ASSERT(pkt->type == LSUPD_P); + ospf_dump_common(po, pkt); - /* We know that ntohs(op->length) >= sizeof(struct ospf_lsa_header) */ - u8 *pbuf= (u8 *) pkt; - unsigned int offset = sizeof(struct ospf_lsupd_packet); - unsigned int bound = ntohs(op->length) - sizeof(struct ospf_lsa_header); - unsigned int i, j, lsalen; + /* We know that ntohs(pkt->length) >= sizeof(struct ospf_lsa_header) */ + unsigned offset, bound, i, lsa_count, lsalen; + ospf_lsupd_body(po, pkt, &offset, &bound, &lsa_count); - j = ntohl(pkt->lsano); - for (i = 0; i < j; i++) + for (i = 0; i < lsa_count; i++) { if (offset > bound) { @@ -56,8 +80,8 @@ static void ospf_dump_lsupd(struct proto_ospf *po, struct ospf_lsupd_packet *pkt return; } - struct ospf_lsa_header *lsa = (void *) (pbuf + offset); - ospf_dump_lsahdr(p, lsa); + struct ospf_lsa_header *lsa = ((void *) pkt) + offset; + ospf_dump_lsahdr(po, lsa); lsalen = ntohs(lsa->length); offset += lsalen; @@ -70,77 +94,6 @@ static void ospf_dump_lsupd(struct proto_ospf *po, 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 (!oa_is_ext(ifa->oa)) - return 0; - return 1; - } - else - return ifa->oa->areaid == domain; -} - -#else /* OSPFv3 */ - -static int -unknown_lsa_type(struct ospf_lsa_header *lsa) -{ - switch (lsa->type) - { - case LSA_T_RT: - case LSA_T_NET: - case LSA_T_SUM_NET: - case LSA_T_SUM_RT: - case LSA_T_EXT: - case LSA_T_NSSA: - case LSA_T_LINK: - case LSA_T_PREFIX: - return 0; - - default: - return 1; - } -} - -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_lsa_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 (!oa_is_ext(ifa->oa)) - 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 @@ -271,17 +224,16 @@ ospf_lsupd_flood(struct proto_ospf *po, { u16 len, age; - struct ospf_lsupd_packet *pk; - struct ospf_packet *op; + unsigned hlen; + struct ospf_packet *pkt; struct ospf_lsa_header *lh; - pk = ospf_tx_buffer(ifa); - op = &pk->ospf_packet; + pkt = ospf_tx_buffer(ifa); + hlen = ospf_lsupd_hdrlen(po); - ospf_pkt_fill_hdr(ifa, pk, LSUPD_P); - pk->lsano = htonl(1); - - lh = (struct ospf_lsa_header *) (pk + 1); + ospf_pkt_fill_hdr(ifa, pkt, LSUPD_P); + *ospf_lsupd_lsa_count(pkt, hlen) = htonl(1); + lh = (((void *) pkt) + hlen); /* Copy LSA into the packet */ if (hn) @@ -293,33 +245,30 @@ ospf_lsupd_flood(struct proto_ospf *po, u8 *help; struct top_hash_entry *en; - htonlsah(hh, lh); + lsa_hton_hdr(hh, lh); help = (u8 *) (lh + 1); en = ospf_hash_find_header(po->gr, domain, hh); - htonlsab(en->lsa_body, help, hh->length - sizeof(struct ospf_lsa_header)); + lsa_hton_body(en->lsa_body, help, hh->length - sizeof(struct ospf_lsa_header)); } - len = sizeof(struct ospf_lsupd_packet) + ntohs(lh->length); - age = ntohs(lh->age); age += ifa->inftransdelay; if (age > LSA_MAXAGE) age = LSA_MAXAGE; lh->age = htons(age); - op->length = htons(len); + len = hlen + ntohs(lh->length); + pkt->length = htons(len); - OSPF_PACKET(ospf_dump_lsupd, pk, "LSUPD packet flooded via %s", ifa->iface->name); + OSPF_PACKET(ospf_lsupd_dump, pkt, "LSUPD packet flooded via %s", ifa->iface->name); switch (ifa->type) { case OSPF_IT_BCAST: if ((ifa->state == OSPF_IS_BACKUP) || (ifa->state == OSPF_IS_DR)) ospf_send_to_all(ifa); - else if (ifa->cf->real_bcast) - ospf_send_to_bdr(ifa); else - ospf_send_to(ifa, AllDRouters); + ospf_send_to_des(ifa); break; case OSPF_IT_NBMA: @@ -350,99 +299,96 @@ ospf_lsupd_flood(struct proto_ospf *po, } void /* I send all I received in LSREQ */ -ospf_lsupd_send_list(struct ospf_neighbor *n, list * l) +ospf_lsupd_send_list(struct ospf_neighbor *n, struct ospf_lsreq_item *lsr) { struct ospf_area *oa = n->ifa->oa; struct proto_ospf *po = oa->po; - struct l_lsr_head *lsr; struct top_hash_entry *en; - struct ospf_lsupd_packet *pkt; - u32 len, len2, lsano; - char *buf; + struct ospf_packet *pkt; + unsigned hlen, pos, pos2, maxsize, lsano; pkt = ospf_tx_buffer(n->ifa); - buf = (void *) pkt; + hlen = ospf_lsupd_hdrlen(po); + maxsize = ospf_pkt_maxsize(n->ifa); - lsr = HEAD(*l); - while(NODE_NEXT(lsr)) + while (lsr) { /* Prepare the packet */ ospf_pkt_fill_hdr(n->ifa, pkt, LSUPD_P); - len = sizeof(struct ospf_lsupd_packet); + pos = hlen; lsano = 0; /* Fill the packet with LSAs */ - while(NODE_NEXT(lsr)) + while (lsr) { - u32 domain = ospf_lsa_domain(lsr->lsh.type, n->ifa); - en = ospf_hash_find(oa->po->gr, domain, lsr->lsh.id, lsr->lsh.rt, lsr->lsh.type); - if (en == NULL) + en = ospf_hash_find(oa->po->gr, lsr->domain, lsr->id, lsr->rt, lsr->type); + if (!en) { /* Probably flushed LSA, this should not happen */ log(L_WARN "OSPF: LSA disappeared (Type: %04x, Id: %R, Rt: %R)", - lsr->lsh.type, lsr->lsh.id, lsr->lsh.rt); - lsr = NODE_NEXT(lsr); - continue; + lsr->type, lsr->id, lsr->rt); + lsr = lsr->next; + continue; } - len2 = len + en->lsa.length; - if (len2 > ospf_pkt_maxsize(n->ifa)) + pos2 = pos + en->lsa.length; + if (pos2 > maxsize) { /* The packet if full, stop adding LSAs and sent it */ if (lsano > 0) break; /* LSA is larger than MTU, check buffer size */ - if (len2 > ospf_pkt_bufsize(n->ifa)) + if (pos2 > ospf_pkt_bufsize(n->ifa)) { /* Cannot fit in a tx buffer, skip that */ log(L_WARN "OSPF: LSA too large to send (Type: %04x, Id: %R, Rt: %R)", - lsr->lsh.type, lsr->lsh.id, lsr->lsh.rt); - lsr = NODE_NEXT(lsr); + lsr->type, lsr->id, lsr->rt); + lsr = lsr->next; continue; } } /* Copy the LSA to the packet */ - htonlsah(&(en->lsa), (struct ospf_lsa_header *) (buf + len)); - htonlsab(en->lsa_body, buf + len + sizeof(struct ospf_lsa_header), - en->lsa.length - sizeof(struct ospf_lsa_header)); - len = len2; + void *lsabuf = ((void *) pkt) + pos; + lsa_hton_hdr(&(en->lsa), (struct ospf_lsa_header *) lsabuf); + lsa_hton_body(en->lsa_body, lsabuf + sizeof(struct ospf_lsa_header), + en->lsa.length - sizeof(struct ospf_lsa_header)); + pos = pos2; lsano++; - lsr = NODE_NEXT(lsr); + lsr = lsr->next; } if (lsano == 0) break; /* Send the packet */ - pkt->lsano = htonl(lsano); - pkt->ospf_packet.length = htons(len); - OSPF_PACKET(ospf_dump_lsupd, pkt, "LSUPD packet sent to %I via %s", + pkt->length = htons(pos); + *ospf_lsupd_lsa_count(pkt, hlen) = htonl(lsano); + OSPF_PACKET(ospf_lsupd_dump, pkt, "LSUPD packet sent to %I via %s", n->ip, n->ifa->iface->name); ospf_send_to(n->ifa, n->ip); } } void -ospf_lsupd_receive(struct ospf_packet *ps_i, struct ospf_iface *ifa, +ospf_lsupd_receive(struct ospf_packet *pkt, struct ospf_iface *ifa, struct ospf_neighbor *n) { struct ospf_neighbor *ntmp; struct proto_ospf *po = ifa->oa->po; struct proto *p = &po->proto; - unsigned int i, max, sendreq = 1; + unsigned sendreq = 1; - unsigned int size = ntohs(ps_i->length); - if (size < (sizeof(struct ospf_lsupd_packet) + sizeof(struct ospf_lsa_header))) + unsigned plen = ntohs(pkt->length); + if (plen < (ospf_lsupd_hdrlen(po) + sizeof(struct ospf_lsa_header))) { - log(L_ERR "OSPF: Bad LSUPD packet from %I - too short (%u B)", n->ip, size); + log(L_ERR "OSPF: Bad LSUPD packet from %I - too short (%u B)", n->ip, plen); return; } - struct ospf_lsupd_packet *ps = (void *) ps_i; - OSPF_PACKET(ospf_dump_lsupd, ps, "LSUPD packet received from %I via %s", n->ip, ifa->iface->name); + OSPF_PACKET(ospf_lsupd_dump, pkt, "LSUPD packet received from %I via %s", n->ip, ifa->iface->name); if (n->state < NEIGHBOR_EXCHANGE) { @@ -452,30 +398,29 @@ ospf_lsupd_receive(struct ospf_packet *ps_i, struct ospf_iface *ifa, ospf_neigh_sm(n, INM_HELLOREC); /* Questionable */ - unsigned int offset = sizeof(struct ospf_lsupd_packet); - unsigned int bound = size - sizeof(struct ospf_lsa_header); + unsigned offset, bound, i, lsa_count; + ospf_lsupd_body(po, pkt, &offset, &bound, &lsa_count); - max = ntohl(ps->lsano); - for (i = 0; i < max; i++) + for (i = 0; i < lsa_count; i++) { struct ospf_lsa_header lsatmp; struct top_hash_entry *lsadb; if (offset > bound) { - log(L_WARN "Received lsupd from %I is too short!", n->ip); + log(L_WARN "OSPF: Received LSUPD from %I is too short", n->ip); ospf_neigh_sm(n, INM_BADLSREQ); return; } - struct ospf_lsa_header *lsa = (void *) (((u8 *) ps) + offset); + struct ospf_lsa_header *lsa = ((void *) pkt) + offset; unsigned int lsalen = ntohs(lsa->length); offset += lsalen; - if ((offset > size) || ((lsalen % 4) != 0) || + if ((offset > plen) || ((lsalen % 4) != 0) || (lsalen <= sizeof(struct ospf_lsa_header))) { - log(L_WARN "Received LSA from %I with bad length", n->ip); + log(L_WARN "OSPF: Received LSA from %I with bad length", n->ip); ospf_neigh_sm(n, INM_BADLSREQ); break; } @@ -484,55 +429,45 @@ ospf_lsupd_receive(struct ospf_packet *ps_i, struct ospf_iface *ifa, u16 chsum = lsa->checksum; if (chsum != lsasum_check(lsa, NULL)) { - log(L_WARN "Received bad lsa checksum from %I: %x %x", n->ip, chsum, lsa->checksum); + log(L_WARN "OSPF: Received LSA from %I with bad checskum: %x %x", + n->ip, chsum, lsa->checksum); continue; } - u16 lsa_type = ntohs(lsa->type_raw); - lsa_type = xxxx(lsa_type); // XXXX finish -#ifdef OSPFv2 + u32 lsa_type, lsa_domain; + lsa_ntoh_hdr(lsa, &lsatmp); + lsa_xxxxtype(lsatmp.type_raw, ifa, &lsa_type, &lsa_domain); + /* pg 143 (2) */ - if ((lsa->type == 0) || (lsa->type == 6) || (lsa->type > LSA_T_NSSA)) + if (!lsa_type) { - log(L_WARN "Unknown LSA type from %I", n->ip); + log(L_WARN "OSPF: Received unknown LSA type from %I", n->ip); continue; } - /* pg 143 (3) */ - if ((lsa_type == LSA_T_EXT) && !oa_is_ext(ifa->oa)) - { - log(L_WARN "Received External LSA in stub area from %I", n->ip); - continue; - } -#else /* OSPFv3 */ /* 4.5.1 (2) */ if ((LSA_SCOPE(lsa_type) == LSA_SCOPE_AS) && !oa_is_ext(ifa->oa)) { - log(L_WARN "Received LSA with AS scope in stub area from %I", n->ip); + log(L_WARN "OSPF: Received LSA with AS scope in stub area from %I", n->ip); continue; } /* 4.5.1 (3) */ - if ((LSA_SCOPE(lsa_type) == LSA_SCOPE_RES)) + if (LSA_SCOPE(lsa_type) == LSA_SCOPE_RES) { - log(L_WARN "Received LSA with invalid scope from %I", n->ip); + log(L_WARN "OSPF: 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", + DBG("Update Type: %04x, Id: %R, Rt: %R, Sn: 0x%08x, Age: %u, Sum: %u\n", lsa_type, lsatmp.id, lsatmp.rt, lsatmp.sn, lsatmp.age, lsatmp.checksum); - /* FIXME domain should be link id for unknown LSA types with zero Ubit */ - u32 domain = ospf_lsa_domain(lsa_type, ifa); - lsadb = ospf_hash_find_header(po->gr, domain, &lsatmp); + lsadb = ospf_hash_find(po->gr, lsa_domain, lsatmp.id, lsatmp.rt, lsa_type); #ifdef LOCAL_DEBUG if (lsadb) - DBG("I have Type: %u ID: %R RT: %R, Sn: 0x%08x Age: %u, Sum: %u\n", - lsadb->lsa.type, lsadb->lsa.id, lsadb->lsa.rt, + DBG("I have Type: %04x, Id: %R, Rt: %R, Sn: 0x%08x, Age: %u, Sum: %u\n", + lsadb->lsa_type, lsadb->lsa.id, lsadb->lsa.rt, lsadb->lsa.sn, lsadb->lsa.age, lsadb->lsa.checksum); #endif @@ -589,7 +524,7 @@ ospf_lsupd_receive(struct ospf_packet *ps_i, struct ospf_iface *ifa, lsadb->inst_t = now; lsadb->ini_age = 0; lsasum_calculate(&lsadb->lsa, lsadb->lsa_body); - ospf_lsupd_flood(po, NULL, NULL, &lsadb->lsa, domain, 1); + ospf_lsupd_flood(po, NULL, NULL, &lsadb->lsa, lsa_domain, 1); } else { @@ -600,7 +535,7 @@ ospf_lsupd_receive(struct ospf_packet *ps_i, struct ospf_iface *ifa, lsa->sn = htonl(LSA_MAXSEQNO); lsasum_check(lsa, (lsa + 1)); /* It also calculates chsum! */ lsatmp.checksum = ntohs(lsa->checksum); - ospf_lsupd_flood(po, NULL, lsa, &lsatmp, domain, 0); + ospf_lsupd_flood(po, NULL, lsa, &lsatmp, lsa_domain, 0); } continue; } @@ -622,7 +557,7 @@ ospf_lsupd_receive(struct ospf_packet *ps_i, struct ospf_iface *ifa, { struct top_hash_entry *en; if (ntmp->state > NEIGHBOR_EXSTART) - if ((en = ospf_hash_find_header(ntmp->lsrth, domain, &lsadb->lsa)) != NULL) + if ((en = ospf_hash_find_header(ntmp->lsrth, lsa_domain, &lsadb->lsa)) != NULL) { s_rem_node(SNODE en); ospf_hash_delete(ntmp->lsrth, en); @@ -630,7 +565,7 @@ ospf_lsupd_receive(struct ospf_packet *ps_i, struct ospf_iface *ifa, } /* pg 144 (5b) */ - if (ospf_lsupd_flood(po, n, lsa, &lsatmp, domain, 1) == 0) + if (ospf_lsupd_flood(po, n, lsa, &lsatmp, lsa_domain, 1) == 0) { DBG("Wasn't flooded back\n"); /* ps 144(5e), pg 153 */ if (ifa->state == OSPF_IS_BACKUP) @@ -652,26 +587,24 @@ ospf_lsupd_receive(struct ospf_packet *ps_i, struct ospf_iface *ifa, /* pg 144 (5d) */ void *body = mb_alloc(p->pool, lsatmp.length - sizeof(struct ospf_lsa_header)); - ntohlsab(lsa + 1, body, lsatmp.length - sizeof(struct ospf_lsa_header)); + lsa_ntoh_body(lsa + 1, body, lsatmp.length - sizeof(struct ospf_lsa_header)); /* We will do validation check after flooding and acknowledging given LSA to minimize problems when communicating with non-validating peer */ - if (lsa_validate(&lsatmp, body) == 0) + if (lsa_validate(&lsatmp, lsa_type, ospf_is_v2(po), body) == 0) { log(L_WARN "Received invalid LSA from %I", n->ip); mb_free(body); continue; } - lsadb = lsa_install_new(po, &lsatmp, domain, body); + lsadb = lsa_install_new(po, &lsatmp, lsa_domain, body); DBG("New LSA installed in DB\n"); -#ifdef OSPFv3 /* Events 6,7 from RFC5340 4.4.3. */ if ((lsa_type == LSA_T_LINK) && (ifa->state == OSPF_IS_DR)) schedule_net_lsa(ifa); -#endif continue; } @@ -710,16 +643,13 @@ ospf_lsupd_receive(struct ospf_packet *ps_i, struct ospf_iface *ifa, continue; } - { - list l; - struct l_lsr_head ll; - init_list(&l); - ll.lsh.id = lsadb->lsa.id; - ll.lsh.rt = lsadb->lsa.rt; - ll.lsh.type = lsadb->lsa.type; - add_tail(&l, NODE & ll); - ospf_lsupd_send_list(n, &l); - } + struct ospf_lsreq_item lsr = { + .domain = lsadb->domain, + .type = lsadb->lsa_type, + .id = lsadb->lsa.id, + .rt = lsadb->lsa.rt + }; + ospf_lsupd_send_list(n, &lsr); } /* Send direct LSAs */ diff --git a/proto/ospf/lsupd.h b/proto/ospf/lsupd.h index 29ea491f..476775e2 100644 --- a/proto/ospf/lsupd.h +++ b/proto/ospf/lsupd.h @@ -12,7 +12,7 @@ void ospf_dump_lsahdr(struct proto_ospf *po, struct ospf_lsa_header *lsa_n); void ospf_dump_common(struct proto_ospf *po, struct ospf_packet *pkt); -void ospf_lsupd_send_list(struct ospf_neighbor *n, list * l); +void ospf_lsupd_send_list(struct ospf_neighbor *n, struct ospf_lsreq_item *lsr); void ospf_lsupd_receive(struct ospf_packet *ps_i, struct ospf_iface *ifa, struct ospf_neighbor *n); int ospf_lsupd_flood(struct proto_ospf *po, diff --git a/proto/ospf/neighbor.c b/proto/ospf/neighbor.c index 2c55f58c..118919d4 100644 --- a/proto/ospf/neighbor.c +++ b/proto/ospf/neighbor.c @@ -26,8 +26,8 @@ const char *ospf_inm[] = }; static void neigh_chstate(struct ospf_neighbor *n, u8 state); -static struct ospf_neighbor *electbdr(list nl); -static struct ospf_neighbor *electdr(list nl); +static struct ospf_neighbor *electbdr(struct proto_ospf *, list nl); +static struct ospf_neighbor *electdr(struct proto_ospf *, list nl); static void neighbor_timer_hook(timer * timer); static void rxmt_timer_hook(timer * timer); static void ackd_timer_hook(timer * t); @@ -37,11 +37,9 @@ init_lists(struct ospf_neighbor *n) { s_init_list(&(n->lsrql)); n->lsrqh = ospf_top_new(n->pool); - s_init(&(n->lsrqi), &(n->lsrql)); s_init_list(&(n->lsrtl)); n->lsrth = ospf_top_new(n->pool); - s_init(&(n->lsrti), &(n->lsrtl)); } /* Resets LSA request and retransmit lists. @@ -163,8 +161,11 @@ neigh_chstate(struct ospf_neighbor *n, u8 state) } } +static inline u32 neigh_get_id(struct proto_ospf *po, struct ospf_neighbor *n) +{ return ospf_is_v2(po) ? ipa_to_u32(n->ip) : n->rid; } + static struct ospf_neighbor * -electbdr(list nl) +electbdr(struct proto_ospf *po, list nl) { struct ospf_neighbor *neigh, *n1, *n2; u32 nid; @@ -173,11 +174,7 @@ electbdr(list nl) n2 = NULL; WALK_LIST(neigh, nl) /* First try those decl. themselves */ { -#ifdef OSPFv2 - nid = ipa_to_u32(neigh->ip); -#else /* OSPFv3 */ - nid = neigh->rid; -#endif + nid = neigh_get_id(po, neigh); if (neigh->state >= NEIGHBOR_2WAY) /* Higher than 2WAY */ if (neigh->priority > 0) /* Eligible */ @@ -222,7 +219,7 @@ electbdr(list nl) } static struct ospf_neighbor * -electdr(list nl) +electdr(struct proto_ospf *po, list nl) { struct ospf_neighbor *neigh, *n; u32 nid; @@ -230,11 +227,7 @@ electdr(list nl) n = NULL; WALK_LIST(neigh, nl) /* And now DR */ { -#ifdef OSPFv2 - nid = ipa_to_u32(neigh->ip); -#else /* OSPFv3 */ - nid = neigh->rid; -#endif + nid = neigh_get_id(po, neigh); if (neigh->state >= NEIGHBOR_2WAY) /* Higher than 2WAY */ if (neigh->priority > 0) /* Eligible */ @@ -449,19 +442,14 @@ bdr_election(struct ospf_iface *ifa) me.priority = ifa->priority; me.ip = ifa->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.dr = ospf_is_v2(po) ? ipa_to_u32(ifa->drip) : ifa->drid; + me.bdr = ospf_is_v2(po) ? ipa_to_u32(ifa->bdrip) : ifa->bdrid; me.iface_id = ifa->iface->index; -#endif add_tail(&ifa->neigh_list, NODE & me); - nbdr = electbdr(ifa->neigh_list); - ndr = electdr(ifa->neigh_list); + nbdr = electbdr(po, ifa->neigh_list); + ndr = electdr(po, ifa->neigh_list); if (ndr == NULL) ndr = nbdr; @@ -472,16 +460,11 @@ bdr_election(struct ospf_iface *ifa) || ((ifa->bdrid == myid) && (nbdr != &me)) || ((ifa->bdrid != myid) && (nbdr == &me))) { -#ifdef OSPFv2 - me.dr = ndr ? ipa_to_u32(ndr->ip) : 0; - me.bdr = nbdr ? ipa_to_u32(nbdr->ip) : 0; -#else /* OSPFv3 */ - me.dr = ndr ? ndr->rid : 0; - me.bdr = nbdr ? nbdr->rid : 0; -#endif + me.dr = ndr ? neigh_get_id(po, ndr) : 0; + me.bdr = nbdr ? neigh_get_id(po, nbdr) : 0; - nbdr = electbdr(ifa->neigh_list); - ndr = electdr(ifa->neigh_list); + nbdr = electbdr(po, ifa->neigh_list); + ndr = electdr(po, ifa->neigh_list); if (ndr == NULL) ndr = nbdr; @@ -492,13 +475,11 @@ bdr_election(struct ospf_iface *ifa) ifa->drid = ndr ? ndr->rid : 0; ifa->drip = ndr ? ndr->ip : IPA_NONE; + ifa->dr_iface_id = ndr ? ndr->iface_id : 0; + 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)); @@ -640,26 +621,28 @@ rxmt_timer_hook(timer * timer) { if (!EMPTY_SLIST(n->lsrtl)) /* FULL */ { - list uplist; - slab *upslab; - struct l_lsr_head *llsh; + struct ospf_lsreq_item *lsr_head, *lsr; + struct ospf_lsreq_item **lsr_pos = &lsr_head; - init_list(&uplist); - upslab = sl_new(n->pool, sizeof(struct l_lsr_head)); + slab *upslab = sl_new(n->pool, sizeof(struct ospf_lsreq_item)); WALK_SLIST(en, n->lsrtl) { if ((SNODE en)->next == (SNODE en)) bug("RTList is cycled"); - llsh = sl_alloc(upslab); - llsh->lsh.id = en->lsa.id; - llsh->lsh.rt = en->lsa.rt; - llsh->lsh.type = en->lsa.type; - DBG("Working on ID: %R, RT: %R, Type: %u\n", - en->lsa.id, en->lsa.rt, en->lsa.type); - add_tail(&uplist, NODE llsh); + + lsr = sl_alloc(upslab); + lsr->domain = en->domain; + lsr->type = en->lsa_type; + lsr->id = en->lsa.id; + lsr->rt = en->lsa.rt; + + *lsr_pos = lsr; + lsr_pos = &(lsr->next); } - ospf_lsupd_send_list(n, &uplist); + *lsr_pos = NULL; + + ospf_lsupd_send_list(n, lsr_head); rfree(upslab); } } diff --git a/proto/ospf/ospf.c b/proto/ospf/ospf.c index 556e5484..d8296b9e 100644 --- a/proto/ospf/ospf.c +++ b/proto/ospf/ospf.c @@ -164,11 +164,7 @@ ospf_area_add(struct proto_ospf *po, struct ospf_area_config *ac, int reconf) if (oa->areaid == 0) po->backbone = oa; -#ifdef OSPFv2 - oa->options = ac->type; -#else /* OSPFv3 */ - oa->options = OPT_R | ac->type | OPT_V6; -#endif + oa->options = ospf_is_v2(po) ? ac->type : (OPT_R | ac->type | OPT_V6); /* * Set E-bit for NSSA ABR routers. No need to explicitly call @@ -383,7 +379,6 @@ schedule_net_lsa(struct ospf_iface *ifa) ifa->orignet = 1; } -#ifdef OSPFv3 void schedule_link_lsa(struct ospf_iface *ifa) { @@ -392,7 +387,6 @@ schedule_link_lsa(struct ospf_iface *ifa) OSPF_TRACE(D_EVENTS, "Scheduling link-LSA origination for iface %s", ifa->iface->name); ifa->origlink = 1; } -#endif void schedule_rt_lsa(struct ospf_area *oa) @@ -589,7 +583,7 @@ ospf_rt_notify(struct proto *p, rtable *tbl UNUSED, net * n, rte * new, rte * ol // FIXME check for gw should be per ifa, not per iface if ((new->attrs->dest == RTD_ROUTER) && ipa_nonzero(new->attrs->gw) && - !ipa_has_link_scope(new->attrs->gw) && + !ipa_is_link_local(new->attrs->gw) && (ospf_iface_find((struct proto_ospf *) p, new->attrs->iface) != NULL)) gw = new->attrs->gw; @@ -682,11 +676,8 @@ ospf_area_reconfigure(struct ospf_area *oa, struct ospf_area_config *nac) oa->ac = nac; // FIXME better area type reconfiguration -#ifdef OSPFv2 - oa->options = nac->type; -#else /* OSPFv3 */ - oa->options = OPT_R | nac->type | OPT_V6; -#endif + oa->options = ospf_is_v2(oa->po) ? nac->type : (OPT_R | nac->type | OPT_V6); + if (oa_is_nssa(oa) && (oa->po->areano > 1)) oa->po->ebit = 1; @@ -986,7 +977,7 @@ lsa_compare_for_state(const void *p1, const void *p2) if (nt1) { #ifdef OSPFv3 - /* In OSPFv3, neworks are named base on ID of DR */ + /* In OSPFv3, networks are named based on ID of DR */ if (lsa1->rt != lsa2->rt) return lsa1->rt - lsa2->rt; #endif @@ -1488,17 +1479,17 @@ ospf_sh_lsadb(struct lsadb_show_data *ld) case LSA_SCOPE_AS: cli_msg(-1017, "Global"); break; + case LSA_SCOPE_AREA: cli_msg(-1017, "Area %R", hea[i]->domain); break; -#ifdef OSPFv3 + case LSA_SCOPE_LINK: { struct iface *ifa = if_find_by_index(hea[i]->domain); cli_msg(-1017, "Link %s", (ifa != NULL) ? ifa->name : "?"); } break; -#endif } cli_msg(-1017, ""); cli_msg(-1017," Type LS ID Router Age Sequence Checksum"); @@ -1507,7 +1498,6 @@ ospf_sh_lsadb(struct lsadb_show_data *ld) last_domain = hea[i]->domain; } - cli_msg(-1017," %04x %-15R %-15R %5u %08x %04x", lsa->type, lsa->id, lsa->rt, lsa->age, lsa->sn, lsa->checksum); } diff --git a/proto/ospf/ospf.h b/proto/ospf/ospf.h index 4d4cf675..0c12a506 100644 --- a/proto/ospf/ospf.h +++ b/proto/ospf/ospf.h @@ -65,11 +65,10 @@ do { if ((po->proto.debug & D_PACKETS) || OSPF_FORCE_DEBUG) \ #define MINLSARRIVAL 1 #define LSINFINITY 0xffffff -#define DEFAULT_OSPFTICK 1 -#define DEFAULT_RFC1583 0 /* compatibility with rfc1583 */ -#define DEFAULT_STUB_COST 1000 -#define DEFAULT_ECMP_LIMIT 16 -#define DEFAULT_TRANSINT 40 +#define OSPF_DEFAULT_TICK 1 +#define OSPF_DEFAULT_STUB_COST 1000 +#define OSPF_DEFAULT_ECMP_LIMIT 16 +#define OSPF_DEFAULT_TRANSINT 40 struct ospf_config @@ -202,11 +201,12 @@ struct ospf_iface u16 autype; u32 csn; /* Last used crypt seq number */ bird_clock_t csn_use; /* Last time when packet with that CSN was sent */ - ip_addr all_routers; /* */ - ip_addr drip; /* Designated router */ - ip_addr bdrip; /* Backup DR */ - u32 drid; - u32 bdrid; + ip_addr all_routers; /* XXXX */ + ip_addr des_routers; /* XXXX */ + ip_addr drip; /* Designated router IP */ + ip_addr bdrip; /* Backup DR IP */ + u32 drid; /* DR Router ID */ + u32 bdrid; /* BDR Router ID */ s16 rt_pos_beg; /* Position of iface in Router-LSA, begin, inclusive */ s16 rt_pos_end; /* Position of iface in Router-LSA, end, exclusive */ s16 px_pos_beg; /* Position of iface in Rt Prefix-LSA, begin, inclusive */ @@ -244,7 +244,7 @@ struct ospf_iface #define OSPF_I_OK 0 /* Everything OK */ #define OSPF_I_SK 1 /* Socket open failed */ #define OSPF_I_LL 2 /* Missing link-local address (OSPFv3) */ - u8 sk_dr; /* Socket is a member of DRouters group */ + u8 sk_dr; /* Socket is a member of designated routers group */ u8 marked; /* Used in OSPF reconfigure */ u16 rxbuf; /* Buffer size */ u8 check_link; /* Whether iface link change is used */ @@ -276,7 +276,6 @@ union ospf_auth /* Area IDs */ #define BACKBONE 0 - #define DBDES_I 4 /* Init bit */ #define DBDES_M 2 /* More bit */ #define DBDES_MS 1 /* Master/Slave bit */ @@ -284,7 +283,6 @@ union ospf_auth - /* * There is slight difference in OSPF packet header between v2 and v3 * in vdep field. For OSPFv2, vdep is u16 authentication type and @@ -303,6 +301,18 @@ struct ospf_packet u16 vdep; }; +static inline u16 ospf_pkt_get_autype(struct ospf_packet *pkt) +{ return ntohs(pkt->vdep); } + +static inline void ospf_pkt_set_autype(struct ospf_packet *pkt, u16 val) +{ pkt->vdep = htons(val); } + +static inline u8 ospf_pkt_get_instance_id(struct ospf_packet *pkt) +{ return ntohs(pkt->vdep) >> 8; } + +static inline void ospf_pkt_set_instance_id(struct ospf_packet *pkt, u16 val) +{ pkt->vdep = htons(val << 8); } + // XXXX /* @@ -323,6 +333,8 @@ struct ospf_packet #define LSA_T_LINK 0x0008 #define LSA_T_PREFIX 0x2009 +#define LSA_T_V2_MASK 0x00ff + #define LSA_UBIT 0x8000 #define LSA_SCOPE_LINK 0x0000 @@ -330,7 +342,7 @@ struct ospf_packet #define LSA_SCOPE_AS 0x4000 #define LSA_SCOPE_RES 0x6000 #define LSA_SCOPE_MASK 0x6000 -#define LSA_SCOPE(lsa) ((lsa) & LSA_SCOPE_MASK) +#define LSA_SCOPE(type) ((type) & LSA_SCOPE_MASK) #define LSA_MAXAGE 3600 /* 1 hour */ @@ -346,6 +358,8 @@ struct ospf_packet #define LSART_STUB 3 #define LSART_VLNK 4 +#define LSA_RT2_LINKS 0x0000FFFF + #define LSA_SUM2_TOS 0xFF000000 #define LSA_EXT2_TOS 0x7F000000 @@ -399,6 +413,19 @@ struct ospf_lsa_rt2_link #endif }; +struct ospf_lsa_rt2_tos +{ +#ifdef CPU_BIG_ENDIAN + u8 tos; + u8 padding; + u16 metric; +#else + u16 metric; + u8 padding; + u8 tos; +#endif +}; + struct ospf_lsa_rt3_link { #ifdef CPU_BIG_ENDIAN @@ -486,27 +513,6 @@ struct ospf_lsa_prefix }; - - -#ifdef OSPFv2 - - -/* Endianity swap for lsa->type */ -#define ntoht(x) x -#define htont(x) x - - -#else /* OSPFv3 */ - - - - -/* Endianity swap for lsa->type */ -#define ntoht(x) ntohs(x) -#define htont(x) htons(x) - -#endif - #define METRIC_MASK 0x00FFFFFF #define OPTIONS_MASK 0x00FFFFFF @@ -519,8 +525,6 @@ lsa_net_count(struct ospf_lsa_header *lsa) } -#ifdef OSPFv3 - #define IPV6_PREFIX_SPACE(x) ((((x) + 63) / 32) * 4) #define IPV6_PREFIX_WORDS(x) (((x) + 63) / 32) @@ -581,21 +585,21 @@ put_ipv6_addr(u32 *buf, ip_addr addr) return buf + 4; } -#endif - - struct ospf_lsreq_header { u32 type; u32 id; - u32 rt; /* Advertising router */ + u32 rt; }; -struct l_lsr_head +struct ospf_lsreq_item { - node n; - struct ospf_lsreq_header lsh; + struct ospf_lsreq_item *next; + u32 domain; + u32 type; + u32 id; + u32 rt; }; @@ -625,19 +629,30 @@ struct ospf_neighbor 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 */ + /* Entries dr and bdr store IP addresses in OSPFv2 and router IDs in + * OSPFv3, we use the same type to simplify handling + */ u32 dr; /* Neigbour's idea of DR */ u32 bdr; /* Neigbour's idea of BDR */ u32 iface_id; /* ID of Neighbour's iface connected to common network */ - siterator dbsi; /* Database summary list iterator */ - slist lsrql; /* Link state request */ - struct top_graph *lsrqh; /* LSA graph */ - siterator lsrqi; - slist lsrtl; /* Link state retransmission list */ - siterator lsrti; + /* Database summary list iterator, controls initial dbdes exchange. + * Advances in the LSA list as dbdes packets are sent. + */ + siterator dbsi; /* iterator of po->lsal */ + + /* Link state request list, controls initial LSA exchange. + * Entries added when received in dbdes packets, removed as sent in lsreq packets. + */ + slist lsrql; /* slist of struct top_hash_entry from n->lsrqh */ + struct top_graph *lsrqh; + + /* Link state retransmission list, controls LSA retransmission during flood. + * Entries added as sent in lsupd packets, removed when received in lsack packets. + */ + slist lsrtl; /* slist of struct top_hash_entry from n->lsrth */ struct top_graph *lsrth; + void *ldbdes; /* Last database description packet */ timer *rxmt_timer; /* RXMT timer */ list ackl[2]; diff --git a/proto/ospf/packet.c b/proto/ospf/packet.c index f42f6a10..c097a467 100644 --- a/proto/ospf/packet.c +++ b/proto/ospf/packet.c @@ -24,16 +24,12 @@ ospf_pkt_fill_hdr(struct ospf_iface *ifa, void *buf, u8 h_type) pkt->routerid = htonl(po->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; + + if (ospf_is_v2(po)) + ospf_pkt_set_autype(pkt, ifa->autype); + else + ospf_pkt_set_instance_id(pkt, ifa->instance_id); } unsigned @@ -42,47 +38,48 @@ ospf_pkt_maxsize(struct ospf_iface *ifa) unsigned mtu = (ifa->type == OSPF_IT_VLINK) ? OSPF_VLINK_MTU : ifa->iface->mtu; unsigned headers = SIZE_OF_IP_HEADER; -#ifdef OSPFv2 + /* For OSPFv2 */ if (ifa->autype == OSPF_AUTH_CRYPT) headers += OSPF_AUTH_CRYPT_SIZE; -#endif return mtu - headers; } -#ifdef OSPFv2 +/* We assume OSPFv2 in ospf_pkt_finalize() */ static void ospf_pkt_finalize(struct ospf_iface *ifa, struct ospf_packet *pkt) { struct password_item *passwd = NULL; - void *tail; - struct MD5Context ctxt; - char password[OSPF_AUTH_CRYPT_SIZE]; + union ospf_auth *auth = (void *) (pkt + 1); + unsigned plen = ntohs(pkt->length); pkt->checksum = 0; - pkt->autype = htons(ifa->autype); - bzero(&pkt->u, sizeof(union ospf_auth)); + ospf_pkt_set_autype(pkt, ifa->autype); + bzero(auth, sizeof(union ospf_auth)); - /* Compatibility note: pkt->u may contain anything if autype is + /* Compatibility note: auth may contain anything if autype is none, but nonzero values do not work with Mikrotik OSPF */ - switch(ifa->autype) + switch (ifa->autype) { case OSPF_AUTH_SIMPLE: passwd = password_find(ifa->passwords, 1); if (!passwd) { - log( L_ERR "No suitable password found for authentication" ); + log(L_ERR "No suitable password found for authentication"); return; } - password_cpy(pkt->u.password, passwd->password, sizeof(union ospf_auth)); + password_cpy(auth->password, passwd->password, sizeof(union ospf_auth)); + case OSPF_AUTH_NONE: - pkt->checksum = ipsum_calculate(pkt, sizeof(struct ospf_packet) - - sizeof(union ospf_auth), (pkt + 1), - ntohs(pkt->length) - - sizeof(struct ospf_packet), NULL); + { + void *body = (void *) (auth + 1); + unsigned blen = plen - sizeof(struct ospf_packet) - sizeof(union ospf_auth); + pkt->checksum = ipsum_calculate(pkt, sizeof(struct ospf_packet), body, blen, NULL); + } break; + case OSPF_AUTH_CRYPT: passwd = password_find(ifa->passwords, 0); if (!passwd) @@ -106,45 +103,53 @@ ospf_pkt_finalize(struct ospf_iface *ifa, struct ospf_packet *pkt) ifa->csn_use = now; - pkt->u.md5.keyid = passwd->id; - pkt->u.md5.len = OSPF_AUTH_CRYPT_SIZE; - pkt->u.md5.zero = 0; - pkt->u.md5.csn = htonl(ifa->csn); - tail = ((void *)pkt) + ntohs(pkt->length); - MD5Init(&ctxt); - MD5Update(&ctxt, (char *) pkt, ntohs(pkt->length)); - password_cpy(password, passwd->password, OSPF_AUTH_CRYPT_SIZE); - MD5Update(&ctxt, password, OSPF_AUTH_CRYPT_SIZE); - MD5Final(tail, &ctxt); + auth->md5.zero = 0; + auth->md5.keyid = passwd->id; + auth->md5.len = OSPF_AUTH_CRYPT_SIZE; + auth->md5.csn = htonl(ifa->csn); + + { + void *tail = ((void *) pkt) + plen; + char password[OSPF_AUTH_CRYPT_SIZE]; + password_cpy(password, passwd->password, OSPF_AUTH_CRYPT_SIZE); + + struct MD5Context ctxt; + MD5Init(&ctxt); + MD5Update(&ctxt, (char *) pkt, plen); + MD5Update(&ctxt, password, OSPF_AUTH_CRYPT_SIZE); + MD5Final(tail, &ctxt); + } break; + default: bug("Unknown authentication type"); } } +/* We assume OSPFv2 in ospf_pkt_checkauth() */ static int ospf_pkt_checkauth(struct ospf_neighbor *n, struct ospf_iface *ifa, struct ospf_packet *pkt, int size) { struct proto_ospf *po = ifa->oa->po; - struct proto *p = &po->proto; + union ospf_auth *auth = (void *) (pkt + 1); struct password_item *pass = NULL, *ptmp; - void *tail; - char md5sum[OSPF_AUTH_CRYPT_SIZE]; char password[OSPF_AUTH_CRYPT_SIZE]; - struct MD5Context ctxt; + unsigned plen = ntohs(pkt->length); + u16 autype = ospf_pkt_get_autype(pkt); - if (pkt->autype != htons(ifa->autype)) + if (autype != ifa->autype) { - OSPF_TRACE(D_PACKETS, "OSPF_auth: Method differs (%d)", ntohs(pkt->autype)); + OSPF_TRACE(D_PACKETS, "OSPF_auth: Method differs (%d)", autype); return 0; } - switch(ifa->autype) + switch (autype) { case OSPF_AUTH_NONE: return 1; break; + case OSPF_AUTH_SIMPLE: pass = password_find(ifa->passwords, 1); if (!pass) @@ -154,37 +159,48 @@ ospf_pkt_checkauth(struct ospf_neighbor *n, struct ospf_iface *ifa, struct ospf_ } password_cpy(password, pass->password, sizeof(union ospf_auth)); - if (memcmp(pkt->u.password, password, sizeof(union ospf_auth))) + if (memcmp(auth->password, password, sizeof(union ospf_auth))) { char ppass[sizeof(union ospf_auth) + 1]; bzero(ppass, (sizeof(union ospf_auth) + 1)); - memcpy(ppass, pkt->u.password, sizeof(union ospf_auth)); + memcpy(ppass, auth->password, sizeof(union ospf_auth)); OSPF_TRACE(D_PACKETS, "OSPF_auth: different passwords (%s)", ppass); return 0; } return 1; break; + case OSPF_AUTH_CRYPT: - if (pkt->u.md5.len != OSPF_AUTH_CRYPT_SIZE) + if (auth->md5.len != OSPF_AUTH_CRYPT_SIZE) { OSPF_TRACE(D_PACKETS, "OSPF_auth: wrong size of md5 digest"); return 0; } - if (ntohs(pkt->length) + OSPF_AUTH_CRYPT_SIZE > size) + if (plen + OSPF_AUTH_CRYPT_SIZE > size) { OSPF_TRACE(D_PACKETS, "OSPF_auth: size mismatch (%d vs %d)", - ntohs(pkt->length) + OSPF_AUTH_CRYPT_SIZE, size); + plen + OSPF_AUTH_CRYPT_SIZE, size); return 0; } - tail = ((void *)pkt) + ntohs(pkt->length); + if (n) + { + u32 rcv_csn = ntohl(auth->md5.csn); + if(rcv_csn < n->csn) + { + OSPF_TRACE(D_PACKETS, "OSPF_auth: lower sequence number (rcv %d, old %d)", rcv_csn, n->csn); + return 0; + } + + n->csn = rcv_csn; + } if (ifa->passwords) { WALK_LIST(ptmp, *(ifa->passwords)) { - if (pkt->u.md5.keyid != ptmp->id) continue; + if (auth->md5.keyid != ptmp->id) continue; if ((ptmp->accfrom > now_real) || (ptmp->accto < now_real)) continue; pass = ptmp; break; @@ -197,50 +213,32 @@ ospf_pkt_checkauth(struct ospf_neighbor *n, struct ospf_iface *ifa, struct ospf_ return 0; } - if (n) + password_cpy(password, pass->password, OSPF_AUTH_CRYPT_SIZE); + { - u32 rcv_csn = ntohl(pkt->u.md5.csn); - if(rcv_csn < n->csn) + void *tail = ((void *) pkt) + plen; + char md5sum[OSPF_AUTH_CRYPT_SIZE]; + + struct MD5Context ctxt; + MD5Init(&ctxt); + MD5Update(&ctxt, (char *) pkt, plen); + MD5Update(&ctxt, password, OSPF_AUTH_CRYPT_SIZE); + MD5Final(md5sum, &ctxt); + if (memcmp(md5sum, tail, OSPF_AUTH_CRYPT_SIZE)) { - OSPF_TRACE(D_PACKETS, "OSPF_auth: lower sequence number (rcv %d, old %d)", rcv_csn, n->csn); + OSPF_TRACE(D_PACKETS, "OSPF_auth: wrong md5 digest"); return 0; } - - n->csn = rcv_csn; - } - - MD5Init(&ctxt); - MD5Update(&ctxt, (char *) pkt, ntohs(pkt->length)); - password_cpy(password, pass->password, OSPF_AUTH_CRYPT_SIZE); - MD5Update(&ctxt, password, OSPF_AUTH_CRYPT_SIZE); - MD5Final(md5sum, &ctxt); - if (memcmp(md5sum, tail, OSPF_AUTH_CRYPT_SIZE)) - { - OSPF_TRACE(D_PACKETS, "OSPF_auth: wrong md5 digest"); - return 0; } return 1; break; + default: OSPF_TRACE(D_PACKETS, "OSPF_auth: unknown auth type"); return 0; } } -#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 @@ -273,37 +271,39 @@ ospf_rx_hook(sock *sk, int size) int src_local, dst_local UNUSED, dst_mcast; src_local = ipa_in_net(sk->faddr, ifa->addr->prefix, ifa->addr->pxlen); dst_local = ipa_equal(sk->laddr, ifa->addr->ip); - dst_mcast = ipa_equal(sk->laddr, ifa->all_routers) || ipa_equal(sk->laddr, AllDRouters); + dst_mcast = ipa_equal(sk->laddr, ifa->all_routers) || ipa_equal(sk->laddr, ifa->des_routers); -#ifdef OSPFv2 - /* First, we eliminate packets with strange address combinations. - * In OSPFv2, they might be for other ospf_ifaces (with different IP - * prefix) on the same real iface, so we don't log it. We enforce - * that (src_local || dst_local), therefore we are eliminating all - * such cases. - */ - if (dst_mcast && !src_local) - return 1; - if (!dst_mcast && !dst_local) - return 1; + if (ospf_is_v2(po)) + { + /* First, we eliminate packets with strange address combinations. + * In OSPFv2, they might be for other ospf_ifaces (with different IP + * prefix) on the same real iface, so we don't log it. We enforce + * that (src_local || dst_local), therefore we are eliminating all + * such cases. + */ + if (dst_mcast && !src_local) + return 1; + if (!dst_mcast && !dst_local) + return 1; - /* Ignore my own broadcast packets */ - if (ifa->cf->real_bcast && ipa_equal(sk->faddr, ifa->addr->ip)) - return 1; -#else /* OSPFv3 */ - - /* In OSPFv3, src_local and dst_local mean link-local. - * RFC 5340 says that local (non-vlink) packets use - * link-local src address, but does not enforce it. Strange. - */ - if (dst_mcast && !src_local) - log(L_WARN "OSPF: Received multicast packet from %I (not link-local)", sk->faddr); -#endif + /* Ignore my own broadcast packets */ + if (ifa->cf->real_bcast && ipa_equal(sk->faddr, ifa->addr->ip)) + return 1; + } + else + { + /* In OSPFv3, src_local and dst_local mean link-local. + * RFC 5340 says that local (non-vlink) packets use + * link-local src address, but does not enforce it. Strange. + */ + if (dst_mcast && !src_local) + log(L_WARN "OSPF: Received multicast packet from %I (not link-local)", sk->faddr); + } /* Second, we check packet size, checksum, and the protocol version */ - struct ospf_packet *ps = (struct ospf_packet *) ip_skip_header(sk->rbuf, &size); + struct ospf_packet *pkt = (struct ospf_packet *) ip_skip_header(sk->rbuf, &size); - if (ps == NULL) + if (pkt == NULL) { log(L_ERR "%s%I - bad IP header", mesg, sk->faddr); return 1; @@ -315,16 +315,16 @@ ospf_rx_hook(sock *sk, int size) return 1; } - int osize = ntohs(ps->length); - if ((unsigned) osize < sizeof(struct ospf_packet)) + unsigned plen = ntohs(pkt->length); + if (plen < sizeof(struct ospf_packet)) { - log(L_ERR "%s%I - too low value in size field (%u bytes)", mesg, sk->faddr, osize); + log(L_ERR "%s%I - too low value in size field (%u bytes)", mesg, sk->faddr, plen); return 1; } - if ((osize > size) || ((osize % 4) != 0)) + if ((plen > size) || ((plen % 4) != 0)) { - log(L_ERR "%s%I - size field does not match (%d/%d)", mesg, sk->faddr, osize, size); + log(L_ERR "%s%I - size field does not match (%d/%d)", mesg, sk->faddr, plen, size); return 1; } @@ -334,50 +334,47 @@ ospf_rx_hook(sock *sk, int size) return 1; } - if (ps->version != OSPF_VERSION) + if (pkt->version != OSPF_VERSION) { - log(L_ERR "%s%I - version %u", mesg, sk->faddr, ps->version); + log(L_ERR "%s%I - version %u", mesg, sk->faddr, pkt->version); return 1; } -#ifdef OSPFv2 - if ((ps->autype != htons(OSPF_AUTH_CRYPT)) && - (!ipsum_verify(ps, 16, (void *) ps + sizeof(struct ospf_packet), - osize - sizeof(struct ospf_packet), NULL))) + if (ospf_is_v2(po) && ospf_pkt_get_autype(pkt) != OSPF_AUTH_CRYPT) { - log(L_ERR "%s%I - bad checksum", mesg, sk->faddr); - return 1; - } -#endif + unsigned hlen = sizeof(struct ospf_packet) - sizeof(union ospf_auth); + unsigned blen = plen - hlen; + void *body = ((void *) pkt) + hlen; + if (! ipsum_verify(pkt, sizeof(struct ospf_packet), body, blen, NULL)) + { + log(L_ERR "%s%I - bad checksum", mesg, sk->faddr); + return 1; + } + } /* Third, we resolve associated iface and handle vlinks. */ - u32 areaid = ntohl(ps->areaid); - u32 rid = ntohl(ps->routerid); + u32 areaid = ntohl(pkt->areaid); + u32 rid = ntohl(pkt->routerid); + u8 instance_id = ospf_is_v2(po) ? 0 : ospf_pkt_get_instance_id(pkt); - if ((areaid == ifa->oa->areaid) -#ifdef OSPFv3 - && (ps->instance_id == ifa->instance_id) -#endif - ) + if ((areaid == ifa->oa->areaid) && + (instance_id == ifa->instance_id)) { /* It is real iface, source should be local (in OSPFv2) */ -#ifdef OSPFv2 - if (!src_local) + if (ospf_is_v2(po) && !src_local) return 1; -#endif } else if (dst_mcast || (areaid != 0)) { /* Obvious mismatch */ -#ifdef OSPFv2 - /* We ignore mismatch in OSPFv3, because there might be - other instance with different instance ID */ - log(L_ERR "%s%I - area does not match (%R vs %R)", - mesg, sk->faddr, areaid, ifa->oa->areaid); -#endif + /* We ignore mismatch in OSPFv3 when there might be + another instance with a different instance ID */ + if (instance_id == ifa->instance_id) + log(L_ERR "%s%I - area does not match (%R vs %R)", + mesg, sk->faddr, areaid, ifa->oa->areaid); return 1; } else @@ -389,9 +386,7 @@ ospf_rx_hook(sock *sk, int size) { if ((iff->type == OSPF_IT_VLINK) && (iff->voa == ifa->oa) && -#ifdef OSPFv3 - (iff->instance_id == ps->instance_id) && -#endif + (iff->instance_id == instance_id) && (iff->vid == rid)) { /* Vlink should be UP */ @@ -403,9 +398,10 @@ ospf_rx_hook(sock *sk, int size) } } -#ifdef OSPFv2 - log(L_WARN "OSPF: Received packet for unknown vlink (ID %R, IP %I)", rid, sk->faddr); -#endif + /* FIXME: this warning is strange - NBMA could trigger it too */ + if (ospf_is_v2(po)) + log(L_WARN "OSPF: Received packet for unknown vlink (ID %R, IP %I)", rid, sk->faddr); + return 1; } @@ -413,7 +409,7 @@ ospf_rx_hook(sock *sk, int size) if (ifa->stub) /* This shouldn't happen */ return 1; - if (ipa_equal(sk->laddr, AllDRouters) && (ifa->sk_dr == 0)) + if (ipa_equal(sk->laddr, ifa->des_routers) && (ifa->sk_dr == 0)) return 1; if (rid == po->router_id) @@ -428,25 +424,22 @@ ospf_rx_hook(sock *sk, int size) return 1; } -#ifdef OSPFv2 /* In OSPFv2, neighbors are identified by either IP or Router ID, base on network type */ + unsigned t = ifa->type; struct ospf_neighbor *n; - if ((ifa->type == OSPF_IT_BCAST) || (ifa->type == OSPF_IT_NBMA) || (ifa->type == OSPF_IT_PTMP)) + if (ospf_is_v2(po) && ((t == OSPF_IT_BCAST) || (t == OSPF_IT_NBMA) || (t == OSPF_IT_PTMP))) n = find_neigh_by_ip(ifa, sk->faddr); else n = find_neigh(ifa, rid); -#else - struct ospf_neighbor *n = find_neigh(ifa, rid); -#endif - if (!n && (ps->type != HELLO_P)) + if (!n && (pkt->type != HELLO_P)) { log(L_WARN "OSPF: Received non-hello packet from unknown neighbor (src %I, iface %s)", sk->faddr, ifa->iface->name); return 1; } - if (!ospf_pkt_checkauth(n, ifa, ps, size)) + if (ospf_is_v2(po) && ! ospf_pkt_checkauth(n, ifa, pkt, size)) { log(L_ERR "%s%I - authentication failed", mesg, sk->faddr); return 1; @@ -454,36 +447,36 @@ ospf_rx_hook(sock *sk, int size) /* Dump packet pu8=(u8 *)(sk->rbuf+5*4); - for(i=0;ilength);i+=4) + for(i=0;ilength);i+=4) DBG("%s: received %u,%u,%u,%u\n",p->name, pu8[i+0], pu8[i+1], pu8[i+2], pu8[i+3]); DBG("%s: received size: %u\n",p->name,size); */ - switch (ps->type) + switch (pkt->type) { case HELLO_P: DBG("%s: Hello received.\n", p->name); - ospf_hello_receive(ps, ifa, n, sk->faddr); + ospf_hello_receive(pkt, ifa, n, sk->faddr); break; case DBDES_P: DBG("%s: Database description received.\n", p->name); - ospf_dbdes_receive(ps, ifa, n); + ospf_dbdes_receive(pkt, ifa, n); break; case LSREQ_P: DBG("%s: Link state request received.\n", p->name); - ospf_lsreq_receive(ps, ifa, n); + ospf_lsreq_receive(pkt, ifa, n); break; case LSUPD_P: DBG("%s: Link state update received.\n", p->name); - ospf_lsupd_receive(ps, ifa, n); + ospf_lsupd_receive(pkt, ifa, n); break; case LSACK_P: DBG("%s: Link state ack received.\n", p->name); - ospf_lsack_receive(ps, ifa, n); + ospf_lsack_receive(pkt, ifa, n); break; default: - log(L_ERR "%s%I - wrong type %u", mesg, sk->faddr, ps->type); + log(L_ERR "%s%I - wrong type %u", mesg, sk->faddr, pkt->type); return 1; }; return 1; @@ -505,6 +498,27 @@ ospf_err_hook(sock * sk, int err) log(L_ERR "OSPF: Socket error on %s: %M", ifa->iface->name, err); } +void +ospf_send_to(struct ospf_iface *ifa, ip_addr dst) +{ + sock *sk = ifa->sk; + struct ospf_packet *pkt = (struct ospf_packet *) sk->tbuf; + int plen = ntohs(pkt->length); + + if (sk->tbuf != sk->tpos) + log(L_ERR "Aiee, old packet was overwritten in TX buffer"); + + if (ospf_is_v2(ifa->oa->po)) + { + if (ifa->autype == OSPF_AUTH_CRYPT) + plen += OSPF_AUTH_CRYPT_SIZE; + + ospf_pkt_finalize(ifa, pkt); + } + + sk_send_to(sk, plen, dst, 0); +} + void ospf_send_to_agt(struct ospf_iface *ifa, u8 state) { @@ -518,28 +532,8 @@ ospf_send_to_agt(struct ospf_iface *ifa, u8 state) void ospf_send_to_bdr(struct ospf_iface *ifa) { - if (!ipa_equal(ifa->drip, IPA_NONE)) + if (ipa_nonzero(ifa->drip)) ospf_send_to(ifa, ifa->drip); - if (!ipa_equal(ifa->bdrip, IPA_NONE)) + if (ipa_nonzero(ifa->bdrip)) ospf_send_to(ifa, ifa->bdrip); } - -void -ospf_send_to(struct ospf_iface *ifa, ip_addr dst) -{ - sock *sk = ifa->sk; - struct ospf_packet *pkt = (struct ospf_packet *) sk->tbuf; - 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 overwritten in TX buffer"); - - sk_send_to(sk, len, dst, 0); -} - diff --git a/proto/ospf/packet.h b/proto/ospf/packet.h index fbcb4288..863a0293 100644 --- a/proto/ospf/packet.h +++ b/proto/ospf/packet.h @@ -15,24 +15,32 @@ unsigned ospf_pkt_maxsize(struct ospf_iface *ifa); int ospf_rx_hook(sock * sk, int size); void ospf_tx_hook(sock * sk); void ospf_err_hook(sock * sk, int err); -void ospf_send_to_agt(struct ospf_iface *ifa, u8 state); -void ospf_send_to_bdr(struct ospf_iface *ifa); void ospf_send_to(struct ospf_iface *ifa, ip_addr ip); -static inline void ospf_send_to_all(struct ospf_iface *ifa) { ospf_send_to(ifa, ifa->all_routers); } +void ospf_send_to_agt(struct ospf_iface *ifa, u8 state); +void ospf_send_to_bdr(struct ospf_iface *ifa); + +static inline void ospf_send_to_all(struct ospf_iface *ifa) +{ + ospf_send_to(ifa, ifa->all_routers); +} + +static inline void ospf_send_to_des(struct ospf_iface *ifa) +{ + if (ipa_nonzero(ifa->des_routers)) + ospf_send_to(ifa, ifa->des_routers); + else + ospf_send_to_bdr(ifa); +} static inline void * ospf_tx_buffer(struct ospf_iface *ifa) { return ifa->sk->tbuf; } static inline unsigned ospf_pkt_bufsize(struct ospf_iface *ifa) { -#ifdef OSPFv2 - unsigned headers = (ifa->autype == OSPF_AUTH_CRYPT) ? OSPF_AUTH_CRYPT_SIZE : 0; -#else - unsigned headers = 0; -#endif - - return ifa->sk->tbsize - headers; + /* Reserve buffer space for authentication footer */ + return ifa->sk->tbsize - + (ifa->autype == OSPF_AUTH_CRYPT) ? OSPF_AUTH_CRYPT_SIZE : 0; } diff --git a/proto/ospf/rt.c b/proto/ospf/rt.c index 40de6561..68a577bd 100644 --- a/proto/ospf/rt.c +++ b/proto/ospf/rt.c @@ -15,12 +15,8 @@ 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 address */ -#ifdef OSPFv2 -#define ipa_from_rid(x) _MI(x) -#else /* OSPFv3 */ -#define ipa_from_rid(x) _MI6(0,0,0,x) -#endif +#define ipa_from_rid(x) ipa_from_u32(x) static inline void reset_ri(ort *ort) { @@ -311,7 +307,7 @@ spfa_process_rt(struct ospf_area *oa, struct top_hash_entry *act) struct ospf_lsa_rt_walk rtl; struct top_hash_entry *tmp; ip_addr prefix; - int pxlen; + int pxlen, i; if (rt->options & OPT_RT_V) oa->trcap = 1; @@ -339,8 +335,7 @@ spfa_process_rt(struct ospf_area *oa, struct top_hash_entry *act) } /* Now process Rt links */ - lsa_walk_rt_init(po, act, &rtl); - while (lsa_walk_rt(&rtl)) + for (lsa_walk_rt_init(po, act, &rtl), i = 0; lsa_walk_rt(&rtl); i++) { tmp = NULL; diff --git a/proto/ospf/topology.c b/proto/ospf/topology.c index 7e625493..fd4e9cd8 100644 --- a/proto/ospf/topology.c +++ b/proto/ospf/topology.c @@ -31,12 +31,11 @@ void flush_prefix_net_lsa(struct ospf_iface *ifa); #endif -#ifdef OSPFv2 static inline u32 fibnode_to_lsaid(struct proto_ospf *po, struct fib_node *fn) { - /* We have to map IP prefixes to u32 in such manner that resulting - u32 interpreted as IP address is a member of given + /* In OSPFv2, We have to map IP prefixes to u32 in such manner + that resulting u32 interpreted as IP address is a member of given prefix. Therefore, /32 prefix have to be mapped on itself. All received prefixes have to be mapped on different u32s. @@ -63,7 +62,18 @@ fibnode_to_lsaid(struct proto_ospf *po, struct fib_node *fn) possible to have both reliably and the suggested algorithm was unnecessary complicated and it does crazy things like changing LSA ID for a network because different network appeared, we - choose a different way. */ + choose a different way. + + In OSPFv3, it is simpler. There is not a requirement for + membership of the result in the input network, so we just use a + hash-based unique ID of a routing table entry for a route that + originated given LSA. For ext-LSA, it is an imported route in the + nest's routing table (p->table). For summary-LSA, it is a + 'source' route in the protocol internal routing table (po->rtf). + */ + + if (ospf_is_v3(po)) + return fn->uid; u32 id = _I(fn->prefix); @@ -76,24 +86,6 @@ fibnode_to_lsaid(struct proto_ospf *po, struct fib_node *fn) return id | ~u32_mkmask(fn->pxlen); } -#else /* OSPFv3 */ - -static inline u32 -fibnode_to_lsaid(struct proto_ospf *po, struct fib_node *fn) -{ - /* - * In OSPFv3, it is simpler. There is not a requirement for - * membership of the result in the input network, so we just use a - * hash-based unique ID of a routing table entry for a route that - * originated given LSA. For ext-LSA, it is an imported route in the - * nest's routing table (p->table). For summary-LSA, it is a - * 'source' route in the protocol internal routing table (po->rtf). - */ - return fn->uid; -} - -#endif - static void * lsab_alloc(struct proto_ospf *po, unsigned size) @@ -1611,7 +1603,7 @@ ospf_top_rehash(struct top_graph *f, int step) while (e) { x = e->next; - n = newt + ospf_top_hash(f, e->domain, 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; @@ -1620,35 +1612,6 @@ ospf_top_rehash(struct top_graph *f, int step) ospf_top_ht_free(oldt); } -#ifdef OSPFv2 - -u32 -ospf_lsa_domain(u32 type, struct ospf_iface *ifa) -{ - return (type == LSA_T_EXT) ? 0 : ifa->oa->areaid; -} - -#else /* OSPFv3 */ - -u32 -ospf_lsa_domain(u32 type, struct ospf_iface *ifa) -{ - switch (type & LSA_SCOPE_MASK) - { - case LSA_SCOPE_LINK: - return ifa->iface->index; - - case LSA_SCOPE_AREA: - return ifa->oa->areaid; - - case LSA_SCOPE_AS: - default: - return 0; - } -} - -#endif - struct top_hash_entry * ospf_hash_find_header(struct top_graph *f, u32 domain, struct ospf_lsa_header *h) { @@ -1667,7 +1630,8 @@ ospf_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, domain, lsa, rtr, type)]; - while (e && (e->lsa.id != lsa || e->lsa.type != type || e->lsa.rt != rtr || e->domain != domain)) + while (e && (e->lsa.id != lsa || e->lsa.rt != rtr || + e->lsa_type != type || e->domain != domain)) e = e->next; return e; @@ -1749,7 +1713,8 @@ ospf_hash_get(struct top_graph *f, u32 domain, u32 lsa, u32 rtr, u32 type) ee = f->hash_table + ospf_top_hash(f, domain, lsa, rtr, type); e = *ee; - while (e && (e->lsa.id != lsa || e->lsa.rt != rtr || e->lsa.type != type || e->domain != domain)) + while (e && (e->lsa.id != lsa || e->lsa.rt != rtr || + e->lsa_type != type || e->domain != domain)) e = e->next; if (e) @@ -1762,8 +1727,9 @@ ospf_hash_get(struct top_graph *f, u32 domain, u32 lsa, u32 rtr, u32 type) e->lb = IPA_NONE; e->lsa.id = lsa; e->lsa.rt = rtr; - e->lsa.type = type; + e->lsa.type = type; e->lsa_body = NULL; + e->lsa_type = type; e->domain = domain; e->next = *ee; *ee = e; @@ -1776,7 +1742,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->domain, 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) { diff --git a/proto/ospf/topology.h b/proto/ospf/topology.h index 909f9d30..4d7a1756 100644 --- a/proto/ospf/topology.h +++ b/proto/ospf/topology.h @@ -23,9 +23,7 @@ struct top_hash_entry bird_clock_t inst_t; /* Time of installation into DB */ struct mpnh *nhs; /* Computed nexthops - valid only in ospf_rt_spf() */ ip_addr lb; /* In OSPFv2, link back address. In OSPFv3, any global address in the area useful for vlinks */ -#ifdef OSPFv3 u32 lb_id; /* Interface ID of link back iface (for bcast or NBMA networks) */ -#endif u32 dist; /* Distance from the root */ u16 ini_age; u8 color; @@ -51,16 +49,14 @@ 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 *); -u32 ospf_lsa_domain(u32 type, struct ospf_iface *ifa); + struct top_hash_entry *ospf_hash_find_header(struct top_graph *f, u32 domain, struct ospf_lsa_header *h); struct top_hash_entry *ospf_hash_get_header(struct top_graph *f, u32 domain, struct ospf_lsa_header *h); -struct top_hash_entry *ospf_hash_find(struct top_graph *, u32 domain, u32 lsa, u32 rtr, - u32 type); -struct top_hash_entry *ospf_hash_get(struct top_graph *, u32 domain, u32 lsa, u32 rtr, - u32 type); +struct top_hash_entry *ospf_hash_find(struct top_graph *, u32 domain, u32 lsa, u32 rtr, u32 type); +struct top_hash_entry *ospf_hash_get(struct top_graph *, u32 domain, u32 lsa, u32 rtr, u32 type); void ospf_hash_delete(struct top_graph *, struct top_hash_entry *); void originate_rt_lsa(struct ospf_area *oa); void update_rt_lsa(struct ospf_area *oa);