From: Ondrej Zajicek Date: Sun, 5 Aug 2012 20:32:06 +0000 (+0200) Subject: Temporary integrated commit (OSPF), unfinished. X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=a7b7b2bd0f8dd2a1249074255308181876125f79;p=thirdparty%2Fbird.git Temporary integrated commit (OSPF), unfinished. --- diff --git a/filter/filter.h b/filter/filter.h index 2386fc959..e2f3d09f4 100644 --- a/filter/filter.h +++ b/filter/filter.h @@ -14,6 +14,9 @@ #include "nest/route.h" #include "nest/attrs.h" + +#define IPV6 1 // XXXX temporary + struct f_inst { /* Instruction */ struct f_inst *next; /* Structure is 16 bytes, anyway */ u16 code; diff --git a/lib/ip.h b/lib/ip.h index b62937ef4..056207f9c 100644 --- a/lib/ip.h +++ b/lib/ip.h @@ -15,13 +15,30 @@ #include "lib/unaligned.h" -#ifdef DEBUGGING + +#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 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 IP4_NONE _MI4(0) +#define IP6_NONE _MI6(0,0,0,0) +#define IPA_NONE IP6_NONE + /* * Use the structural representation when you want to make sure * nobody unauthorized attempts to handle ip_addr as number. */ +#ifdef DEBUGGING + typedef struct ip4_addr { u32 addr; } ip4_addr; @@ -54,11 +71,6 @@ typedef ip6_addr ip_addr; -#define IPA_NONE IP6_NONE -#define IP4_NONE _MI4(0) -#define IP6_NONE _MI6(0,0,0,0) - - /* * ip_classify() returns either a negative number for invalid addresses * or scope OR'ed together with address type. @@ -123,9 +135,11 @@ static inline ip6_addr ip6_not(ip6_addr a) #define ipa_from_ip4(x) _MI6(0,0,0xffff,_I(x)) #define ipa_from_ip6(x) x +#define ipa_from_u32(x) ipa_from_ip4(ip4_from_u32(x)) #define ipa_to_ip4(x) _I3(x) #define ipa_to_ip6(x) x +#define ipa_to_u32(x) ip4_to_u32(ipa_to_ip4(x)) #define ip4_from_u32(x) _MI4(x) #define ip4_to_u32(x) _I(x) diff --git a/nest/iface.c b/nest/iface.c index eea3d3b1a..7f756e5c8 100644 --- a/nest/iface.c +++ b/nest/iface.c @@ -534,10 +534,8 @@ ifa_update(struct ifa *a) break; } -#ifndef IPV6 - if ((i->flags & IF_BROADCAST) && !ipa_nonzero(a->brd)) - log(L_ERR "Missing broadcast address for interface %s", i->name); -#endif + if (ipa_is_ip4(a->ip) && (i->flags & IF_BROADCAST) && !ipa_nonzero(a->brd)) + log(L_WARN "Missing broadcast address for interface %s", i->name); b = mb_alloc(if_pool, sizeof(struct ifa)); memcpy(b, a, sizeof(struct ifa)); @@ -583,10 +581,13 @@ ifa_delete(struct ifa *a) } } + static void auto_router_id(void) { -#ifndef IPV6 +// XXXX check this +#if 0 + struct iface *i, *j; j = NULL; diff --git a/nest/neighbor.c b/nest/neighbor.c index 506d9bdee..bbd21330e 100644 --- a/nest/neighbor.c +++ b/nest/neighbor.c @@ -75,12 +75,11 @@ if_connected(ip_addr *a, struct iface *i) /* -1=error, 1=match, 0=no match */ { if (ipa_in_net(*a, b->prefix, b->pxlen)) { -#ifndef IPV6 + // XXXX what about this ? if ((b->pxlen < (BITS_PER_IP_ADDRESS - 1)) && (ipa_equal(*a, b->prefix) || /* Network address */ ipa_equal(*a, b->brd))) /* Broadcast */ return -1; -#endif return b->scope; } diff --git a/proto/ospf/config.Y b/proto/ospf/config.Y index 67b0785f5..40d3f1f14 100644 --- a/proto/ospf/config.Y +++ b/proto/ospf/config.Y @@ -335,7 +335,7 @@ ipa_item: ipa_el | ipa_ne; -ipa_el: IPA ';' +ipa_el: ipa ';' { this_nbma = cfg_allocz(sizeof(struct nbma_node)); add_tail(&OSPF_PATT->nbma_list, NODE this_nbma); @@ -344,7 +344,7 @@ ipa_el: IPA ';' } ; -ipa_ne: IPA ELIGIBLE ';' +ipa_ne: ipa ELIGIBLE ';' { this_nbma = cfg_allocz(sizeof(struct nbma_node)); add_tail(&OSPF_PATT->nbma_list, NODE this_nbma); diff --git a/proto/ospf/dbdes.c b/proto/ospf/dbdes.c index 75ecf24c7..e1e0e81f9 100644 --- a/proto/ospf/dbdes.c +++ b/proto/ospf/dbdes.c @@ -9,47 +9,77 @@ #include "ospf.h" -#ifdef OSPFv2 -struct ospf_dbdes_packet +struct ospf_dbdes2_packet { - struct ospf_packet ospf_packet; + struct ospf_packet hdr; + union ospf_auth auth; + u16 iface_mtu; u8 options; - union imms imms; /* I, M, MS bits */ + u8 imms; /* I, M, MS bits */ u32 ddseq; -}; - -#define hton_opt(X) X -#define ntoh_opt(X) X -#endif + struct ospf_lsa_header lsas[]; +}; -#ifdef OSPFv3 -struct ospf_dbdes_packet +struct ospf_dbdes3_packet { - struct ospf_packet ospf_packet; + struct ospf_packet hdr; + u32 options; u16 iface_mtu; u8 padding; - union imms imms; /* I, M, MS bits */ + u8 imms; /* I, M, MS bits */ u32 ddseq; + + struct ospf_lsa_header lsas[]; }; + + +#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) +{ + return ospf_is_v2(po) ? + sizeof(struct ospf_dbdes2_packet) : + sizeof(struct ospf_dbdes3_packet); +} + +static void +ospf_dbdes_body(struct proto_ospf *po, struct ospf_packet *pkt, unsigned plen, + struct ospf_lsa_header **body, unsigned *count) +{ + unsigned hdrlen = ospf_dbdes_hdrlen(po); + *body = ((void *) pkt) + hdrlen; + *count = (plen - hdrlen) / sizeof(struct ospf_lsa_header); +} -static void ospf_dump_dbdes(struct proto *p, struct ospf_dbdes_packet *pkt) +static void ospf_dbdes_dump(struct proto_ospf *po, struct ospf_packet *pkt) { - struct ospf_packet *op = &pkt->ospf_packet; - - ASSERT(op->type == DBDES_P); - ospf_dump_common(p, op); - log(L_TRACE "%s: imms %s%s%s", - p->name, pkt->imms.bit.ms ? "MS " : "", - pkt->imms.bit.m ? "M " : "", - pkt->imms.bit.i ? "I " : "" ); + struct proto *p = &po->proto; + struct ospf_lsa_header *lsas; + unsigned i, lsa_count; + + 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)); struct ospf_lsa_header *plsa = (void *) (pkt + 1); @@ -59,7 +89,7 @@ static void ospf_dump_dbdes(struct proto *p, struct ospf_dbdes_packet *pkt) sizeof(struct ospf_lsa_header); for (i = 0; i < j; i++) - ospf_dump_lsahdr(p, plsa + i); + ospf_dump_lsahdr(p, &lsas[i]); } @@ -77,12 +107,12 @@ static void ospf_dump_dbdes(struct proto *p, struct ospf_dbdes_packet *pkt) void ospf_dbdes_send(struct ospf_neighbor *n, int next) { - struct ospf_dbdes_packet *pkt; - struct ospf_packet *op; struct ospf_iface *ifa = n->ifa; struct ospf_area *oa = ifa->oa; struct proto_ospf *po = oa->po; - struct proto *p = &po->proto; + + struct ospf_dbdes_packet *pkt; + struct ospf_packet *op; u16 length, i, j; /* FIXME ??? */ @@ -92,7 +122,7 @@ ospf_dbdes_send(struct ospf_neighbor *n, int next) switch (n->state) { case NEIGHBOR_EXSTART: /* Send empty packets */ - n->myimms.bit.i = 1; + n->myimms |= DBDES_I; pkt = ospf_tx_buffer(ifa); op = &pkt->ospf_packet; ospf_pkt_fill_hdr(ifa, pkt, DBDES_P); @@ -108,7 +138,7 @@ ospf_dbdes_send(struct ospf_neighbor *n, int next) break; case NEIGHBOR_EXCHANGE: - n->myimms.bit.i = 0; + n->myimms &= ~DBDES_I; if (next) { @@ -126,7 +156,7 @@ ospf_dbdes_send(struct ospf_neighbor *n, int next) 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.bit.m) + if (n->myimms & DBDES_M) { sn = s_get(&(n->dbsi)); @@ -158,13 +188,13 @@ ospf_dbdes_send(struct ospf_neighbor *n, int next) { DBG("Number of LSA NOT sent: %d\n", i); DBG("M bit unset.\n"); - n->myimms.bit.m = 0; /* Unset more bit */ + n->myimms &= ~DBDES_M; /* Unset more bit */ } s_put(&(n->dbsi), sn); } - pkt->imms.byte = n->myimms.byte; + pkt->imms = n->myimms; length = (j - i) * sizeof(struct ospf_lsa_header) + sizeof(struct ospf_dbdes_packet); @@ -191,11 +221,13 @@ ospf_dbdes_send(struct ospf_neighbor *n, int next) OSPF_PACKET(ospf_dump_dbdes, pkt, "DBDES packet sent to %I via %s", n->ip, ifa->iface->name); ospf_send_to(ifa, n->ip); - if(n->myimms.bit.ms) tm_start(n->rxmt_timer, n->ifa->rxmtint); /* Restart timer */ + if (n->myimms & DBDES_MS) + tm_start(n->rxmt_timer, n->ifa->rxmtint); /* Restart timer */ - if (!n->myimms.bit.ms) + if (!(n->myimms & DBDES_MS)) { - if ((n->myimms.bit.m == 0) && (n->imms.bit.m == 0) && + if (!(n->myimms & DBDES_M) && + !(n->imms & DBDES_M) && (n->state == NEIGHBOR_EXCHANGE)) { ospf_neigh_sm(n, INM_EXDONE); @@ -244,11 +276,15 @@ ospf_dbdes_reqladd(struct ospf_dbdes_packet *ps, struct ospf_neighbor *n) } void -ospf_dbdes_receive(struct ospf_packet *ps_i, struct ospf_iface *ifa, +ospf_dbdes_receive(struct ospf_packet *pkt, struct ospf_iface *ifa, struct ospf_neighbor *n) { struct proto_ospf *po = ifa->oa->po; - struct proto *p = &po->proto; + + u32 rcv_ddseq, rcv_options; + u16 rcv_iface_mtu; + u8 rcv_imms; + unsigned int size = ntohs(ps_i->length); if (size < sizeof(struct ospf_dbdes_packet)) @@ -257,12 +293,24 @@ ospf_dbdes_receive(struct ospf_packet *ps_i, struct ospf_iface *ifa, return; } - struct ospf_dbdes_packet *ps = (void *) ps_i; - u32 ps_ddseq = ntohl(ps->ddseq); - u32 ps_options = ntoh_opt(ps->options); - u16 ps_iface_mtu = ntohs(ps->iface_mtu); + if (ospf_is_v2(po)) + { + struct ospf_dbdes2_packet *ps = (void *) pkt; + rcv_iface_mtu = ntohs(ps->iface_mtu); + rcv_options = ps->options; + rcv_imms = ps->imms; + rcv_ddseq = ntohl(ps->ddseq); + } + else /* OSPFv3 */ + { + struct ospf_dbdes3_packet *ps = (void *) pkt; + rcv_options = ntohl(ps->options); + rcv_iface_mtu = ntohs(ps->iface_mtu); + rcv_imms = ps->imms; + rcv_ddseq = ntohl(ps->ddseq); + } - OSPF_PACKET(ospf_dump_dbdes, ps, "DBDES packet received from %I via %s", n->ip, ifa->iface->name); + OSPF_PACKET(ospf_dbdes_dump, ps, "DBDES packet received from %I via %s", n->ip, ifa->iface->name); ospf_neigh_sm(n, INM_HELLOREC); @@ -272,56 +320,62 @@ ospf_dbdes_receive(struct ospf_packet *ps_i, struct ospf_iface *ifa, case NEIGHBOR_ATTEMPT: case NEIGHBOR_2WAY: return; - break; + case NEIGHBOR_INIT: ospf_neigh_sm(n, INM_2WAYREC); if (n->state != NEIGHBOR_EXSTART) return; - case NEIGHBOR_EXSTART: - if ((ps_iface_mtu != ifa->iface->mtu) && (ifa->type != OSPF_IT_VLINK) - && (ps_iface_mtu != 0) && (ifa->iface->mtu != 0)) + case NEIGHBOR_EXSTART: + if ((rcv_iface_mtu != ifa->iface->mtu) && + (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)", - n->ip, ifa->iface->name, ps_iface_mtu, ifa->iface->mtu); + n->ip, ifa->iface->name, rcv_iface_mtu, ifa->iface->mtu); - if ((ps->imms.bit.m && ps->imms.bit.ms && ps->imms.bit.i) - && (n->rid > po->router_id) && (size == sizeof(struct ospf_dbdes_packet))) + if ((rcv_imms == DBDES_IMMS) && + (n->rid > po->router_id) && + (size == sizeof(struct ospf_dbdes_packet))) { /* I'm slave! */ - n->dds = ps_ddseq; - n->ddr = ps_ddseq; - n->options = ps_options; - n->myimms.bit.ms = 0; - n->imms.byte = ps->imms.byte; - OSPF_TRACE(D_PACKETS, "I'm slave to %I.", n->ip); + n->dds = rcv_ddseq; + n->ddr = rcv_ddseq; + n->options = rcv_options; + n->myimms &= ~DBDES_MS; + n->imms = rcv_imms; + OSPF_TRACE(D_PACKETS, "I'm slave to %I", n->ip); ospf_neigh_sm(n, INM_NEGDONE); ospf_dbdes_send(n, 1); break; } - if (((ps->imms.bit.i == 0) && (ps->imms.bit.ms == 0)) && - (n->rid < po->router_id) && (n->dds == ps_ddseq)) + if (!(rcv_imms & DBDES_I) && + !(rcv_imms & DBDES_MS) && + (n->rid < po->router_id) && + (n->dds == rcv_ddseq)) { /* I'm master! */ - n->options = ps_options; - n->ddr = ps_ddseq - 1; /* It will be set corectly a few lines down */ - n->imms.byte = ps->imms.byte; - OSPF_TRACE(D_PACKETS, "I'm master to %I.", n->ip); + n->options = rcv_options; + n->ddr = rcv_ddseq - 1; /* It will be set corectly a few lines down */ + n->imms = rcv_imms; + OSPF_TRACE(D_PACKETS, "I'm master to %I", n->ip); ospf_neigh_sm(n, INM_NEGDONE); } else { - DBG("%s: Nothing happend to %I (imms=%u)\n", p->name, n->ip, - ps->imms.byte); + DBG("%s: Nothing happend to %I (imms=%d)\n", p->name, n->ip, rcv_imms); break; } + case NEIGHBOR_EXCHANGE: - if ((ps->imms.byte == n->imms.byte) && (ps_options == n->options) && - (ps_ddseq == n->ddr)) + if ((rcv_imms == n->imms) && + (rcv_options == n->options) && + (rcv_ddseq == n->ddr)) { /* Duplicate packet */ OSPF_TRACE(D_PACKETS, "Received duplicate dbdes from %I.", n->ip); - if (n->myimms.bit.ms == 0) + if (!(n->myimms & DBDES_MS)) { /* Slave should retransmit dbdes packet */ ospf_dbdes_send(n, 0); @@ -329,47 +383,43 @@ ospf_dbdes_receive(struct ospf_packet *ps_i, struct ospf_iface *ifa, return; } - n->ddr = ps_ddseq; - - if (ps->imms.bit.ms != n->imms.bit.ms) /* M/S bit differs */ + if ((rcv_imms & DBDES_MS) != (n->imms & DBDES_MS)) /* M/S bit differs */ { - OSPF_TRACE(D_PACKETS, "dbdes - sequence mismatch neighbor %I (bit MS)", - n->ip); + OSPF_TRACE(D_PACKETS, "dbdes - sequence mismatch neighbor %I (bit MS)", n->ip); ospf_neigh_sm(n, INM_SEQMIS); break; } - if (ps->imms.bit.i) /* I bit is set */ + if (rcv_imms & DBDES_I) /* I bit is set */ { - OSPF_TRACE(D_PACKETS, "dbdes - sequence mismatch neighbor %I (bit I)", - n->ip); + OSPF_TRACE(D_PACKETS, "dbdes - sequence mismatch neighbor %I (bit I)", n->ip); ospf_neigh_sm(n, INM_SEQMIS); break; } - n->imms.byte = ps->imms.byte; - - if (ps_options != n->options) /* Options differs */ + if (rcv_options != n->options) /* Options differs */ { - OSPF_TRACE(D_PACKETS, "dbdes - sequence mismatch neighbor %I (options)", - n->ip); + OSPF_TRACE(D_PACKETS, "dbdes - sequence mismatch neighbor %I (options)", n->ip); ospf_neigh_sm(n, INM_SEQMIS); break; } - if (n->myimms.bit.ms) + n->ddr = rcv_ddseq; + n->imms = rcv_imms; + + if (n->myimms & DBDES_MS) { - if (ps_ddseq != n->dds) /* MASTER */ + if (rcv_ddseq != n->dds) /* MASTER */ { - OSPF_TRACE(D_PACKETS, - "dbdes - sequence mismatch neighbor %I (master)", n->ip); + OSPF_TRACE(D_PACKETS, "dbdes - sequence mismatch neighbor %I (master)", n->ip); ospf_neigh_sm(n, INM_SEQMIS); break; } n->dds++; DBG("Incrementing dds\n"); ospf_dbdes_reqladd(ps, n); - if ((n->myimms.bit.m == 0) && (ps->imms.bit.m == 0)) + if (!(n->myimms & DBDES_M) && + !(rcv_imms & DBDES_M)) { ospf_neigh_sm(n, INM_EXDONE); } @@ -381,28 +431,28 @@ ospf_dbdes_receive(struct ospf_packet *ps_i, struct ospf_iface *ifa, } else { - if (ps_ddseq != (n->dds + 1)) /* SLAVE */ + if (rcv_ddseq != (n->dds + 1)) /* SLAVE */ { - OSPF_TRACE(D_PACKETS, "dbdes - sequence mismatch neighbor %I (slave)", - n->ip); + OSPF_TRACE(D_PACKETS, "dbdes - sequence mismatch neighbor %I (slave)", n->ip); ospf_neigh_sm(n, INM_SEQMIS); break; } - n->ddr = ps_ddseq; - n->dds = ps_ddseq; + n->ddr = rcv_ddseq; + n->dds = rcv_ddseq; ospf_dbdes_reqladd(ps, n); ospf_dbdes_send(n, 1); } - break; + case NEIGHBOR_LOADING: case NEIGHBOR_FULL: - if ((ps->imms.byte == n->imms.byte) && (ps_options == n->options) - && (ps_ddseq == n->ddr)) + if ((rcv_imms == n->imms) && + (rcv_options == n->options) && + (rcv_ddseq == n->ddr)) /* Only duplicate are accepted */ { OSPF_TRACE(D_PACKETS, "Received duplicate dbdes from %I.", n->ip); - if (n->myimms.bit.ms == 0) + if (!(n->myimms & DBDES_MS)) { /* Slave should retransmit dbdes packet */ ospf_dbdes_send(n, 0); @@ -411,9 +461,8 @@ ospf_dbdes_receive(struct ospf_packet *ps_i, struct ospf_iface *ifa, } else { - OSPF_TRACE(D_PACKETS, "dbdes - sequence mismatch neighbor %I (full)", - n->ip); - DBG("PS=%u, DDR=%u, DDS=%u\n", ps_ddseq, n->ddr, n->dds); + OSPF_TRACE(D_PACKETS, "dbdes - sequence mismatch neighbor %I (full)", n->ip); + DBG("PS=%u, DDR=%u, DDS=%u\n", rcv_ddseq, n->ddr, n->dds); ospf_neigh_sm(n, INM_SEQMIS); } break; diff --git a/proto/ospf/hello.c b/proto/ospf/hello.c index f9ba28f65..b699dd7e5 100644 --- a/proto/ospf/hello.c +++ b/proto/ospf/hello.c @@ -9,25 +9,26 @@ #include "ospf.h" -#ifdef OSPFv2 -struct ospf_hello_packet +struct ospf_hello2_packet { - struct ospf_packet ospf_packet; - ip_addr netmask; + struct ospf_packet hdr; + union ospf_auth auth; + + u32 netmask; u16 helloint; u8 options; u8 priority; u32 deadint; u32 dr; u32 bdr; -}; -#endif + u32 neighbors[]; +}; -#ifdef OSPFv3 -struct ospf_hello_packet +struct ospf_hello3_packet { - struct ospf_packet ospf_packet; + struct ospf_packet hdr; + u32 iface_id; u8 priority; u8 options3; @@ -37,67 +38,100 @@ struct ospf_hello_packet u16 deadint; u32 dr; u32 bdr; + + u32 neighbors[]; }; -#endif void -ospf_hello_receive(struct ospf_packet *ps_i, struct ospf_iface *ifa, +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, twoway, peers; - u32 tmp; - u32 *pnrid; + unsigned int size, i, two_way; - size = ntohs(ps_i->length); - if (size < sizeof(struct ospf_hello_packet)) - { - log(L_ERR "%s%I - too short (%u B)", beg, faddr, size); - return; - } + u32 rcv_iface_id, rcv_helloint, rcv_deadint, rcv_dr, rcv_bdr; + u8 rcv_options, rcv_priority; + + u32 *neighbors; + u32 neigh_count; - struct ospf_hello_packet *ps = (void *) ps_i; OSPF_TRACE(D_PACKETS, "HELLO packet received from %I via %s%s", faddr, - (ifa->type == OSPF_IT_VLINK ? "vlink-" : ""), ifa->iface->name); - -#ifdef OSPFv2 - ip_addr mask = ps->netmask; - ipa_ntoh(mask); - if ((ifa->type != OSPF_IT_VLINK) && - (ifa->type != OSPF_IT_PTP) && - !ipa_equal(mask, ipa_mkmask(ifa->addr->pxlen))) + (ifa->type == OSPF_IT_VLINK ? "vlink-" : ""), ifa->iface->name); + + size = ntohs(pkt->length); + + if (ospf_is_v2(po)) { - log(L_ERR "%s%I - netmask mismatch (%I)", beg, faddr, mask); - return; + struct ospf_hello2_packet *ps = (void *) pkt; + + if (size < sizeof(struct ospf_hello2_packet)) + { + log(L_ERR "%s%I - too short (%u B)", beg, faddr, size); + return; + } + + rcv_iface_id = 0; + rcv_helloint = ntohs(ps->helloint); + rcv_deadint = ntohl(ps->deadint); + rcv_dr = ntohl(ps->dr); + rcv_bdr = ntohl(ps->bdr); + rcv_options = ps->options; + rcv_priority = ps->priority; + + int pxlen = u32_masklen(ntohl(ps->netmask)); + if ((ifa->type != OSPF_IT_VLINK) && + (ifa->type != OSPF_IT_PTP) && + (pxlen != ifa->addr->pxlen)) + { + log(L_ERR "%s%I - prefix length mismatch (%d)", beg, faddr, pxlen); + return; + } + + neighbors = ps->neighbors; + neigh_count = (size - sizeof(struct ospf_hello2_packet)) / sizeof(u32); + } + else /* OSPFv3 */ + { + struct ospf_hello3_packet *ps = (void *) pkt; + + if (size < sizeof(struct ospf_hello3_packet)) + { + log(L_ERR "%s%I - too short (%u B)", beg, faddr, size); + return; + } + + rcv_iface_id = ntohl(ps->iface_id); + rcv_helloint = ntohs(ps->helloint); + rcv_deadint = ntohs(ps->deadint); + rcv_dr = ntohl(ps->dr); + rcv_bdr = ntohl(ps->bdr); + rcv_options = ps->options; + rcv_priority = ps->priority; + + neighbors = ps->neighbors; + neigh_count = (size - sizeof(struct ospf_hello3_packet)) / sizeof(u32); } -#endif - tmp = ntohs(ps->helloint); - if (tmp != ifa->helloint) + if (rcv_helloint != ifa->helloint) { - log(L_ERR "%s%I - hello interval mismatch (%d)", beg, faddr, tmp); + log(L_ERR "%s%I - hello interval mismatch (%d)", beg, faddr, rcv_helloint); return; } -#ifdef OSPFv2 - tmp = ntohl(ps->deadint); -#else /* OSPFv3 */ - tmp = ntohs(ps->deadint); -#endif - if (tmp != ifa->deadint) + if (rcv_deadint != ifa->deadint) { - log(L_ERR "%s%I - dead interval mismatch (%d)", beg, faddr, tmp); + log(L_ERR "%s%I - dead interval mismatch (%d)", beg, faddr, rcv_deadint); return; } /* Check whether bits E, N match */ - if ((ps->options ^ ifa->oa->options) & (OPT_E | OPT_N)) + if ((rcv_options ^ ifa->oa->options) & (OPT_E | OPT_N)) { - log(L_ERR "%s%I - area type mismatch (%x)", beg, faddr, ps->options); + log(L_ERR "%s%I - area type mismatch (%x)", beg, faddr, rcv_options); return; } @@ -115,8 +149,8 @@ ospf_hello_receive(struct ospf_packet *ps_i, struct ospf_iface *ifa, } if (nn && (ifa->type == OSPF_IT_NBMA) && - (((ps->priority == 0) && nn->eligible) || - ((ps->priority > 0) && !nn->eligible))) + (((rcv_priority == 0) && nn->eligible) || + ((rcv_priority > 0) && !nn->eligible))) { log(L_ERR "Eligibility mismatch for neighbor: %I on %s", faddr, ifa->iface->name); @@ -132,85 +166,67 @@ ospf_hello_receive(struct ospf_packet *ps_i, struct ospf_iface *ifa, n = ospf_neighbor_new(ifa); - n->rid = ntohl(((struct ospf_packet *) ps)->routerid); + n->rid = ntohl(pkt->routerid); n->ip = faddr; - n->dr = ntohl(ps->dr); - n->bdr = ntohl(ps->bdr); - n->priority = ps->priority; -#ifdef OSPFv3 - n->iface_id = ntohl(ps->iface_id); -#endif + n->dr = rcv_dr; + n->bdr = rcv_bdr; + n->priority = rcv_priority; + n->iface_id = rcv_iface_id; } ospf_neigh_sm(n, INM_HELLOREC); - pnrid = (u32 *) ((struct ospf_hello_packet *) (ps + 1)); - - peers = (size - sizeof(struct ospf_hello_packet))/ sizeof(u32); - - twoway = 0; - for (i = 0; i < peers; i++) + two_way = 0; + for (i = 0; i < neigh_count; i++) { - if (ntohl(pnrid[i]) == po->router_id) + if (ntohl(neighbors[i]) == po->router_id) { DBG("%s: Twoway received from %I\n", p->name, faddr); ospf_neigh_sm(n, INM_2WAYREC); - twoway = 1; + two_way = 1; break; } } - - if (!twoway) + if (!two_way) ospf_neigh_sm(n, INM_1WAYREC); - u32 olddr = n->dr; - u32 oldbdr = n->bdr; - u32 oldpriority = n->priority; -#ifdef OSPFv3 - u32 oldiface_id = n->iface_id; -#endif - - n->dr = ntohl(ps->dr); - n->bdr = ntohl(ps->bdr); - n->priority = ps->priority; -#ifdef OSPFv3 - n->iface_id = ntohl(ps->iface_id); -#endif + u32 old_dr = n->dr; + u32 old_bdr = n->bdr; + u32 old_priority = n->priority; + u32 old_iface_id = n->iface_id; + n->dr = rcv_dr; + n->bdr = rcv_bdr; + n->priority = rcv_priority; + n->iface_id = rcv_iface_id; /* Check priority change */ if (n->state >= NEIGHBOR_2WAY) { -#ifdef OSPFv2 - u32 neigh = ipa_to_u32(n->ip); -#else /* OSPFv3 */ - u32 neigh = n->rid; -#endif + u32 n_id = ospf_is_v2(po) ? ipa_to_u32(n->ip) : n->rid; - if (n->priority != oldpriority) + if (n->priority != old_priority) ospf_iface_sm(ifa, ISM_NEICH); -#ifdef OSPFv3 - if (n->iface_id != oldiface_id) + if (n->iface_id != old_iface_id) ospf_iface_sm(ifa, ISM_NEICH); -#endif /* Neighbor is declaring itself ad DR and there is no BDR */ - if ((n->dr == neigh) && (n->bdr == 0) + if ((n->dr == n_id) && (n->bdr == 0) && (n->state != NEIGHBOR_FULL)) ospf_iface_sm(ifa, ISM_BACKS); /* Neighbor is declaring itself as BDR */ - if ((n->bdr == neigh) && (n->state != NEIGHBOR_FULL)) + if ((n->bdr == n_id) && (n->state != NEIGHBOR_FULL)) ospf_iface_sm(ifa, ISM_BACKS); /* Neighbor is newly declaring itself as DR or BDR */ - if (((n->dr == neigh) && (n->dr != olddr)) - || ((n->bdr == neigh) && (n->bdr != oldbdr))) + if (((n->dr == n_id) && (n->dr != old_dr)) + || ((n->bdr == n_id) && (n->bdr != old_bdr))) ospf_iface_sm(ifa, ISM_NEICH); /* Neighbor is no more declaring itself as DR or BDR */ - if (((olddr == neigh) && (n->dr != olddr)) - || ((oldbdr == neigh) && (n->bdr != oldbdr))) + if (((old_dr == n_id) && (n->dr != old_dr)) + || ((old_bdr == n_id) && (n->bdr != old_bdr))) ospf_iface_sm(ifa, ISM_NEICH); } @@ -225,13 +241,14 @@ ospf_hello_receive(struct ospf_packet *ps_i, struct ospf_iface *ifa, void ospf_hello_send(struct ospf_iface *ifa, int kind, struct ospf_neighbor *dirn) { - struct ospf_hello_packet *pkt; - struct ospf_packet *op; - struct proto *p; + struct proto_ospf *po = ifa->oa->po; + struct proto *p = &po->proto; + struct ospf_packet *pkt; struct ospf_neighbor *neigh, *n1; - u16 length; - int i; struct nbma_node *nb; + u32 *neighbors; + u16 length; + int i, max; if (ifa->state <= OSPF_IS_LOOP) return; @@ -239,65 +256,69 @@ ospf_hello_send(struct ospf_iface *ifa, int kind, struct ospf_neighbor *dirn) if (ifa->stub) return; /* Don't send any packet on stub iface */ - p = (struct proto *) (ifa->oa->po); DBG("%s: Hello/Poll timer fired on interface %s with IP %I\n", p->name, ifa->iface->name, ifa->addr->ip); - /* Now we should send a hello packet */ pkt = ospf_tx_buffer(ifa); - op = &pkt->ospf_packet; - - /* Now fill ospf_hello header */ ospf_pkt_fill_hdr(ifa, pkt, HELLO_P); -#ifdef OSPFv2 - pkt->netmask = ipa_mkmask(ifa->addr->pxlen); - ipa_hton(pkt->netmask); - if ((ifa->type == OSPF_IT_VLINK) || (ifa->type == OSPF_IT_PTP)) - pkt->netmask = IPA_NONE; -#endif - - pkt->helloint = ntohs(ifa->helloint); - pkt->priority = ifa->priority; - -#ifdef OSPFv3 - pkt->iface_id = htonl(ifa->iface->index); - - pkt->options3 = ifa->oa->options >> 16; - pkt->options2 = ifa->oa->options >> 8; -#endif - pkt->options = ifa->oa->options; - -#ifdef OSPFv2 - pkt->deadint = htonl(ifa->deadint); - pkt->dr = htonl(ipa_to_u32(ifa->drip)); - pkt->bdr = htonl(ipa_to_u32(ifa->bdrip)); -#else /* OSPFv3 */ - pkt->deadint = htons(ifa->deadint); - pkt->dr = htonl(ifa->drid); - pkt->bdr = htonl(ifa->bdrid); -#endif + if (ospf_is_v2(po)) + { + struct ospf_hello2_packet *ps = (void *) pkt; + + ps->netmask = htonl(u32_mkmask(ifa->addr->pxlen)); + + if ((ifa->type == OSPF_IT_VLINK) || (ifa->type == OSPF_IT_PTP)) + ps->netmask = 0; + + ps->helloint = ntohs(ifa->helloint); + ps->options = ifa->oa->options; + ps->priority = ifa->priority; + ps->deadint = htonl(ifa->deadint); + ps->dr = htonl(ipa_to_u32(ifa->drip)); + ps->bdr = htonl(ipa_to_u32(ifa->bdrip)); + + length = sizeof(struct ospf_hello2_packet); + neighbors = ps->neighbors; + } + else + { + struct ospf_hello3_packet *ps = (void *) pkt; + + ps->iface_id = htonl(ifa->iface->index); + ps->priority = ifa->priority; + ps->options3 = ifa->oa->options >> 16; + ps->options2 = ifa->oa->options >> 8; + ps->options = ifa->oa->options; + ps->helloint = ntohs(ifa->helloint); + ps->deadint = htons(ifa->deadint); + ps->dr = htonl(ifa->drid); + ps->bdr = htonl(ifa->bdrid); + + length = sizeof(struct ospf_hello3_packet); + neighbors = ps->neighbors; + } - /* Fill all neighbors */ i = 0; + max = (ospf_pkt_bufsize(ifa) - length) / sizeof(u32); + /* Fill all neighbors */ if (kind != OHS_SHUTDOWN) { - u32 *pp = (u32 *) (((u8 *) pkt) + sizeof(struct ospf_hello_packet)); WALK_LIST(neigh, ifa->neigh_list) { - if ((i+1) * sizeof(u32) + sizeof(struct ospf_hello_packet) > ospf_pkt_bufsize(ifa)) + if (i == max) { log(L_WARN "%s: Too many neighbors on interface %s", p->name, ifa->iface->name); break; } - *(pp + i) = htonl(neigh->rid); + neighbors[i] = htonl(neigh->rid); i++; } } - length = sizeof(struct ospf_hello_packet) + i * sizeof(u32); - op->length = htons(length); + length += i * sizeof(u32); + pkt->length = htons(length); switch(ifa->type) { diff --git a/proto/ospf/iface.c b/proto/ospf/iface.c index a6a0c6c11..e004c05e7 100644 --- a/proto/ospf/iface.c +++ b/proto/ospf/iface.c @@ -34,7 +34,7 @@ static void wait_timer_hook(timer * timer) { struct ospf_iface *ifa = (struct ospf_iface *) timer->data; - struct proto *p = &ifa->oa->po->proto; + struct proto_ospf *po = ifa->oa->po; OSPF_TRACE(D_EVENTS, "Wait timer fired on interface %s.", ifa->iface->name); ospf_iface_sm(ifa, ISM_WAITF); @@ -172,9 +172,8 @@ ospf_sk_leave_dr(struct ospf_iface *ifa) static void ospf_iface_down(struct ospf_iface *ifa) { - struct ospf_neighbor *n, *nx; struct proto_ospf *po = ifa->oa->po; - struct proto *p = &po->proto; + struct ospf_neighbor *n, *nx; struct ospf_iface *iff; if (ifa->type != OSPF_IT_VLINK) @@ -232,7 +231,8 @@ ospf_iface_down(struct ospf_iface *ifa) void ospf_iface_remove(struct ospf_iface *ifa) { - struct proto *p = &ifa->oa->po->proto; + struct proto_ospf *po = ifa->oa->po; + if (ifa->type == OSPF_IT_VLINK) OSPF_TRACE(D_EVENTS, "Removing vlink to %R via area %R", ifa->vid, ifa->voa->areaid); @@ -261,7 +261,6 @@ void ospf_iface_chstate(struct ospf_iface *ifa, u8 state) { struct proto_ospf *po = ifa->oa->po; - struct proto *p = &po->proto; u8 oldstate = ifa->state; if (oldstate == state) @@ -490,7 +489,7 @@ ospf_iface_stubby(struct ospf_iface_patt *ip, struct ifa *addr) void ospf_iface_new(struct ospf_area *oa, struct ifa *addr, struct ospf_iface_patt *ip) { - struct proto *p = &oa->po->proto; + struct proto_ospf *po = oa->po; struct iface *iface = addr ? addr->iface : NULL; struct pool *pool; @@ -511,7 +510,7 @@ ospf_iface_new(struct ospf_area *oa, struct ifa *addr, struct ospf_iface_patt *i #endif } - pool = rp_new(p->pool, "OSPF Interface"); + pool = rp_new(po->proto.pool, "OSPF Interface"); ifa = mb_allocz(pool, sizeof(struct ospf_iface)); ifa->iface = iface; ifa->addr = addr; @@ -625,7 +624,7 @@ ospf_iface_change_timer(timer *tm, unsigned val) int ospf_iface_reconfigure(struct ospf_iface *ifa, struct ospf_iface_patt *new) { - struct proto *p = &ifa->oa->po->proto; + struct proto_ospf *po = ifa->oa->po; struct nbma_node *nb, *nbx; char *ifname = (ifa->type != OSPF_IT_VLINK) ? ifa->iface->name : "vlink"; @@ -1047,7 +1046,6 @@ ospf_ifaces_reconfigure(struct ospf_area *oa, struct ospf_area_config *nac) static void ospf_iface_change_mtu(struct proto_ospf *po, struct ospf_iface *ifa) { - struct proto *p = &po->proto; struct ospf_packet *op; struct ospf_neighbor *n; OSPF_TRACE(D_EVENTS, "Changing MTU on interface %s", ifa->iface->name); diff --git a/proto/ospf/lsack.c b/proto/ospf/lsack.c index 00c50cafb..dc59dde08 100644 --- a/proto/ospf/lsack.c +++ b/proto/ospf/lsack.c @@ -9,29 +9,38 @@ #include "ospf.h" +/* struct ospf_lsack_packet { - struct ospf_packet ospf_packet; - struct ospf_lsa_header lsh[]; -}; + struct ospf_packet hdr; + // union ospf_auth auth; - -char *s_queue[] = { "direct", "delayed" }; + struct ospf_lsa_header lsas[]; +}; +*/ -static void ospf_dump_lsack(struct proto *p, struct ospf_lsack_packet *pkt) +static void +ospf_lsack_body(struct proto_ospf *po, struct ospf_packet *pkt, unsigned plen, + struct ospf_lsa_header **body, unsigned *count) { - struct ospf_packet *op = &pkt->ospf_packet; + unsigned hdrlen = ospf_pkt_hdrlen(po); + *body = ((void *) pkt) + hdrlen; + *count = (plen - hdrlen) / sizeof(struct ospf_lsa_header); +} - ASSERT(op->type == LSACK_P); - ospf_dump_common(p, op); +static void +ospf_lsack_dump(struct proto_ospf *po, struct ospf_packet *pkt) +{ + struct ospf_lsa_header *lsas; + unsigned i, lsa_count; - unsigned int i, j; - j = (ntohs(op->length) - sizeof(struct ospf_lsack_packet)) / - sizeof(struct ospf_lsa_header); + ASSERT(pkt->type == LSACK_P); + ospf_dump_common(po, pkt); - for (i = 0; i < j; i++) - ospf_dump_lsahdr(p, pkt->lsh + i); + ospf_lsack_body(po, pkt, ntohs(pkt->length), &lsas, &lsa_count); + for (i = 0; i < lsa_count; i++) + ospf_dump_lsahdr(po, lsas + i); } @@ -42,87 +51,47 @@ static void ospf_dump_lsack(struct proto *p, struct ospf_lsack_packet *pkt) */ void -ospf_lsack_enqueue(struct ospf_neighbor *n, struct ospf_lsa_header *h, - int queue) +ospf_lsack_enqueue(struct ospf_neighbor *n, struct ospf_lsa_header *h, int queue) { struct lsah_n *no = mb_alloc(n->pool, sizeof(struct lsah_n)); memcpy(&no->lsa, h, sizeof(struct ospf_lsa_header)); add_tail(&n->ackl[queue], NODE no); - DBG("Adding (%s) ack for %R, ID: %R, RT: %R, Type: %u\n", s_queue[queue], + DBG("Adding (%s) ack for %R, ID: %R, RT: %R, Type: %u\n", + (queue == ACKL_DIRECT) ? "direct" : "delayed", n->rid, ntohl(h->id), ntohl(h->rt), h->type); } -void -ospf_lsack_send(struct ospf_neighbor *n, int queue) +static inline void +ospf_lsack_send_one(struct ospf_neighbor *n, int queue) { - struct ospf_packet *op; - struct ospf_lsack_packet *pk; - u16 len, i = 0; - struct ospf_lsa_header *h; - struct lsah_n *no; struct ospf_iface *ifa = n->ifa; - struct proto *p = &n->ifa->oa->po->proto; - - if (EMPTY_LIST(n->ackl[queue])) - return; + struct proto_ospf *po = ifa->oa->po; + struct ospf_lsa_header *lsas; + struct ospf_packet *pkt; + struct lsah_n *no; + unsigned i, lsa_max, length; - pk = ospf_tx_buffer(ifa); - op = &pk->ospf_packet; - ospf_pkt_fill_hdr(n->ifa, pk, LSACK_P); - h = pk->lsh; + pkt = ospf_tx_buffer(ifa); + ospf_pkt_fill_hdr(ifa, pkt, LSACK_P); + ospf_lsack_body(po, pkt, ospf_pkt_maxsize(ifa), &lsas, &lsa_max); - while (!EMPTY_LIST(n->ackl[queue])) + for (i = 0; i < lsa_max && !EMPTY_LIST(n->ackl[queue]); i++) { no = (struct lsah_n *) HEAD(n->ackl[queue]); - memcpy(h + i, &no->lsa, sizeof(struct ospf_lsa_header)); - DBG("Iter %u ID: %R, RT: %R, Type: %04x\n", i, ntohl((h + i)->id), - ntohl((h + i)->rt), (h + i)->type); - i++; + memcpy(&lsas[i], &no->lsa, sizeof(struct ospf_lsa_header)); + DBG("Iter %u ID: %R, RT: %R, Type: %04x\n", + i, ntohl(lsas[i].id), ntohl(lsas[i].rt), lsas[i].type); rem_node(NODE no); mb_free(no); - if ((i * sizeof(struct ospf_lsa_header) + - sizeof(struct ospf_lsack_packet)) > ospf_pkt_maxsize(n->ifa)) - { - if (!EMPTY_LIST(n->ackl[queue])) - { - len = - sizeof(struct ospf_lsack_packet) + - i * sizeof(struct ospf_lsa_header); - op->length = htons(len); - DBG("Sending and continuing! Len=%u\n", len); - - OSPF_PACKET(ospf_dump_lsack, pk, "LSACK packet sent via %s", ifa->iface->name); - - if (ifa->type == OSPF_IT_BCAST) - { - 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); - } - else - { - if ((ifa->state == OSPF_IS_DR) || (ifa->state == OSPF_IS_BACKUP)) - ospf_send_to_agt(ifa, NEIGHBOR_EXCHANGE); - else - ospf_send_to_bdr(ifa); - } - - ospf_pkt_fill_hdr(n->ifa, pk, LSACK_P); - i = 0; - } - } } - len = sizeof(struct ospf_lsack_packet) + i * sizeof(struct ospf_lsa_header); - op->length = htons(len); - DBG("Sending! Len=%u\n", len); + length = ospf_pkt_hdrlen(po) + i * sizeof(struct ospf_lsa_header); + pkt->length = htons(length); - OSPF_PACKET(ospf_dump_lsack, pk, "LSACK packet sent via %s", ifa->iface->name); + OSPF_PACKET(ospf_lsack_dump, pkt, "LSACK packet sent via %s", ifa->iface->name); + /* XXXX this is very strange */ if (ifa->type == OSPF_IT_BCAST) { if ((ifa->state == OSPF_IS_DR) || (ifa->state == OSPF_IS_BACKUP)) @@ -134,37 +103,46 @@ ospf_lsack_send(struct ospf_neighbor *n, int queue) } else ospf_send_to_agt(ifa, NEIGHBOR_EXCHANGE); + + /* + if ((ifa->state == OSPF_IS_DR) || (ifa->state == OSPF_IS_BACKUP)) + ospf_send_to_agt(ifa, NEIGHBOR_EXCHANGE); + else + ospf_send_to_bdr(ifa); + */ +} + +void +ospf_lsack_send(struct ospf_neighbor *n, int queue) +{ + while (!EMPTY_LIST(n->ackl[queue])) + ospf_lsack_send_one(n, queue); } void -ospf_lsack_receive(struct ospf_packet *ps_i, struct ospf_iface *ifa, +ospf_lsack_receive(struct ospf_packet *pkt, struct ospf_iface *ifa, struct ospf_neighbor *n) { - struct proto *p = &ifa->oa->po->proto; - struct ospf_lsa_header lsa; + struct proto_ospf *po = ifa->oa->po; + struct ospf_lsa_header lsa, *lsas; struct top_hash_entry *en; - unsigned int i, lsano; + unsigned i, lsa_count; - unsigned int size = ntohs(ps_i->length); - if (size < sizeof(struct ospf_lsack_packet)) - { - log(L_ERR "Bad OSPF LSACK packet from %I - too short (%u B)", n->ip, size); - return; - } - struct ospf_lsack_packet *ps = (void *) ps_i; - OSPF_PACKET(ospf_dump_lsack, ps, "LSACK packet received from %I via %s", n->ip, ifa->iface->name); + /* No need to check length, lsack has only basic header */ - ospf_neigh_sm(n, INM_HELLOREC); + OSPF_PACKET(ospf_lsack_dump, pkt, "LSACK packet received from %I via %s", + n->ip, ifa->iface->name); if (n->state < NEIGHBOR_EXCHANGE) return; - lsano = (size - sizeof(struct ospf_lsack_packet)) / - sizeof(struct ospf_lsa_header); - for (i = 0; i < lsano; i++) + ospf_neigh_sm(n, INM_HELLOREC); /* Not in RFC */ + + ospf_lsack_body(po, pkt, ntohs(pkt->length), &lsas, &lsa_count); + for (i = 0; i < lsa_count; i++) { - ntohlsah(ps->lsh + i, &lsa); + ntohlsah(&lsas[i], &lsa); u32 dom = ospf_lsa_domain(lsa.type, n->ifa); if ((en = ospf_hash_find_header(n->lsrth, dom, &lsa)) == NULL) continue; /* pg 155 */ diff --git a/proto/ospf/lsalib.c b/proto/ospf/lsalib.c index bcf7bcddd..00dd2893a 100644 --- a/proto/ospf/lsalib.c +++ b/proto/ospf/lsalib.c @@ -11,11 +11,9 @@ void flush_lsa(struct top_hash_entry *en, struct proto_ospf *po) { - struct proto *p = &po->proto; - OSPF_TRACE(D_EVENTS, "Going to remove LSA Type: %04x, Id: %R, Rt: %R, Age: %u, Seqno: 0x%x", - en->lsa.type, en->lsa.id, en->lsa.rt, en->lsa.age, en->lsa.sn); + en->lsa_type, en->lsa.id, en->lsa.rt, en->lsa.age, en->lsa.sn); s_rem_node(SNODE en); if (en->lsa_body != NULL) mb_free(en->lsa_body); @@ -30,7 +28,7 @@ ospf_flush_area(struct proto_ospf *po, u32 areaid) WALK_SLIST_DELSAFE(en, nxt, po->lsal) { - if ((LSA_SCOPE(&en->lsa) == LSA_SCOPE_AREA) && (en->domain == areaid)) + if ((LSA_SCOPE(en->lsa_type) == LSA_SCOPE_AREA) && (en->domain == areaid)) flush_lsa(en, po); } } @@ -53,7 +51,6 @@ ospf_flush_area(struct proto_ospf *po, u32 areaid) void ospf_age(struct proto_ospf *po) { - struct proto *p = &po->proto; struct top_hash_entry *en, *nxt; int flush = can_flush_lsa(po); @@ -68,7 +65,7 @@ ospf_age(struct proto_ospf *po) if ((en->lsa.rt == po->router_id) && (en->lsa.age >= LSREFRESHTIME)) { OSPF_TRACE(D_EVENTS, "Refreshing my LSA: Type: %u, Id: %R, Rt: %R", - en->lsa.type, en->lsa.id, en->lsa.rt); + en->lsa_type, en->lsa.id, en->lsa.rt); en->lsa.sn++; en->lsa.age = 0; en->inst_t = now; @@ -95,10 +92,7 @@ void htonlsah(struct ospf_lsa_header *h, struct ospf_lsa_header *n) { n->age = htons(h->age); -#ifdef OSPFv2 - n->options = h->options; -#endif - n->type = htont(h->type); + n->type_raw = htont(h->type_raw); n->id = htonl(h->id); n->rt = htonl(h->rt); n->sn = htonl(h->sn); @@ -110,10 +104,7 @@ void ntohlsah(struct ospf_lsa_header *n, struct ospf_lsa_header *h) { h->age = ntohs(n->age); -#ifdef OSPFv2 - h->options = n->options; -#endif - h->type = ntoht(n->type); + h->type_raw = ntoht(n->type_raw); h->id = ntohl(n->id); h->rt = ntohl(n->rt); h->sn = ntohl(n->sn); @@ -292,6 +283,147 @@ lsa_comp(struct ospf_lsa_header *l1, struct ospf_lsa_header *l2) return CMP_SAME; } + +static inline int +lsa_walk_rt2(struct ospf_lsa_rt_walk *rt) +{ + if (rt->buf >= rt->bufend) + return 0; + + struct ospf_lsa_rt2_link *l = rt->buf; + rt->buf += sizeof(struct ospf_lsa_rt2_link) + l->no_tos * sizeof(struct ospf_lsa_rt2_tos); + + rt->type = l->type; + rt->metric = l->metric; + rt->id = l->id; + rt->data = l->data; + return 1; +} + +static inline int +lsa_walk_rt3(struct ospf_lsa_rt_walk *rt) +{ + while (rt->buf >= rt->bufend) + { + rt->en = ospf_hash_find_rt_next(rt->en); + if (!rt->en) + return 0; + + rt->buf = rt->en->lsa_body; + rt->bufend = rt->buf + rt->en->lsa.length - sizeof(struct ospf_lsa_header); + rt->buf += sizeof(struct ospf_lsa_rt); + } + + struct ospf_lsa_rt3_link *l = rt->buf; + rt->buf += sizeof(struct ospf_lsa_rt3_link); + + rt->type = l->type; + rt->metric = l->metric; + rt->lif = l->lif; + rt->nif = l->nif; + rt->id = l->id; + return 1; +} + +void +lsa_walk_rt_init(struct proto_ospf *po, struct top_hash_entry *act, struct ospf_lsa_rt_walk *rt) +{ + rt->ospf2 = ospf_is_v2(po); + rt->id = rt->data = rt->lif = rt->nif = 0; + + if (rt->ospf2) + rt->en = act; + else + rt->en = ospf_hash_find_rt_first(po->gr, act->domain, act->lsa.rt); + + rt->buf = rt->en->lsa_body; + rt->bufend = rt->buf + rt->en->lsa.length - sizeof(struct ospf_lsa_header); + rt->buf += sizeof(struct ospf_lsa_rt); +} + +int +lsa_walk_rt(struct ospf_lsa_rt_walk *rt) +{ + return rt->ospf2 ? lsa_walk_rt2(rt) : lsa_walk_rt3(rt); +} + + +void +lsa_parse_sum_net(struct top_hash_entry *en, int ospf2, ip_addr *ip, int *pxlen, u8 *pxopts, u32 *metric) +{ + if (ospf2) + { + struct ospf_lsa_sum2 *ls = en->lsa_body; + *ip = ipa_from_u32(en->lsa.id & ls->netmask); + *pxlen = u32_masklen(ls->netmask); + *pxopts = 0; + *metric = ls->metric & METRIC_MASK; + } + else + { + struct ospf_lsa_sum3_net *ls = en->lsa_body; + u16 rest; + lsa_get_ipv6_prefix(ls->prefix, ip, pxlen, pxopts, &rest); + *metric = ls->metric & METRIC_MASK; + } +} + +void +lsa_parse_sum_rt(struct top_hash_entry *en, int ospf2, u32 *drid, u32 *metric, u32 *options) +{ + if (ospf2) + { + struct ospf_lsa_sum2 *ls = en->lsa_body; + *drid = en->lsa.id; + *metric = ls->metric & METRIC_MASK; + *options = 0; + } + else + { + struct ospf_lsa_sum3_rt *ls = en->lsa_body; + *drid = ls->drid; + *metric = ls->metric & METRIC_MASK; + *options = ls->options & OPTIONS_MASK; + } +} + +void +lsa_parse_ext(struct top_hash_entry *en, int ospf2, struct ospf_lsa_ext_local *rt) +{ + if (ospf2) + { + struct ospf_lsa_ext2 *ext = en->lsa_body; + rt->ip = ipa_from_u32(en->lsa.id & ext->netmask); + rt->pxlen = u32_masklen(ext->netmask); + rt->pxopts = 0; + rt->metric = ext->metric & METRIC_MASK; + rt->ebit = ext->metric & LSA_EXT2_EBIT; + + rt->fbit = ip4_nonzero(ext->fwaddr); + rt->fwaddr = ipa_from_ip4(ext->fwaddr); + + rt->tag = ext->tag; + rt->propagate = lsa_get_options(&en->lsa) & OPT_P; + } + else + { + struct ospf_lsa_ext3 *ext = en->lsa_body; + u16 rest; + u32 *buf = lsa_get_ipv6_prefix(ext->rest, &rt->ip, &rt->pxlen, &rt->pxopts, &rest); + rt->metric = ext->metric & METRIC_MASK; + rt->ebit = ext->metric & LSA_EXT3_EBIT; + + rt->fbit = ext->metric & LSA_EXT3_FBIT; + if (rt->fbit) + buf = lsa_get_ipv6_addr(buf, &rt->fwaddr); + else + rt->fwaddr = IPA_NONE; + + rt->tag = (ext->metric & LSA_EXT3_TBIT) ? *buf++ : 0; + rt->propagate = rt->pxopts & OPT_PX_P; + } +} + #define HDRLEN sizeof(struct ospf_lsa_header) static int @@ -372,16 +504,16 @@ pxlen(u32 *buf) } static int -lsa_validate_sum_net(struct ospf_lsa_header *lsa, struct ospf_lsa_sum_net *body) +lsa_validate_sum_net(struct ospf_lsa_header *lsa, struct ospf_lsa_sum3_net *body) { - if (lsa->length < (HDRLEN + sizeof(struct ospf_lsa_sum_net) + 4)) + if (lsa->length < (HDRLEN + sizeof(struct ospf_lsa_sum3_net) + 4)) return 0; u8 pxl = pxlen(body->prefix); if (pxl > MAX_PREFIX_LENGTH) return 0; - if (lsa->length != (HDRLEN + sizeof(struct ospf_lsa_sum_net) + + if (lsa->length != (HDRLEN + sizeof(struct ospf_lsa_sum3_net) + IPV6_PREFIX_SPACE(pxl))) return 0; @@ -390,18 +522,18 @@ lsa_validate_sum_net(struct ospf_lsa_header *lsa, struct ospf_lsa_sum_net *body) static int -lsa_validate_sum_rt(struct ospf_lsa_header *lsa, struct ospf_lsa_sum_rt *body) +lsa_validate_sum_rt(struct ospf_lsa_header *lsa, struct ospf_lsa_sum3_rt *body) { - if (lsa->length != (HDRLEN + sizeof(struct ospf_lsa_sum_rt))) + if (lsa->length != (HDRLEN + sizeof(struct ospf_lsa_sum3_rt))) return 0; return 1; } static int -lsa_validate_ext(struct ospf_lsa_header *lsa, struct ospf_lsa_ext *body) +lsa_validate_ext(struct ospf_lsa_header *lsa, struct ospf_lsa_ext3 *body) { - if (lsa->length < (HDRLEN + sizeof(struct ospf_lsa_ext) + 4)) + if (lsa->length < (HDRLEN + sizeof(struct ospf_lsa_ext3) + 4)) return 0; u8 pxl = pxlen(body->rest); @@ -409,14 +541,14 @@ lsa_validate_ext(struct ospf_lsa_header *lsa, struct ospf_lsa_ext *body) return 0; int len = IPV6_PREFIX_SPACE(pxl); - if (body->metric & LSA_EXT_FBIT) // forwardinf address + if (body->metric & LSA_EXT3_FBIT) // forwardinf address len += 16; - if (body->metric & LSA_EXT_TBIT) // route tag + if (body->metric & LSA_EXT3_TBIT) // route tag len += 4; if (*body->rest & 0xFFFF) // referenced LS type field len += 4; - if (lsa->length != (HDRLEN + sizeof(struct ospf_lsa_ext) + len)) + if (lsa->length != (HDRLEN + sizeof(struct ospf_lsa_ext3) + len)) return 0; return 1; @@ -492,12 +624,10 @@ lsa_validate(struct ospf_lsa_header *lsa, void *body) case LSA_T_EXT: case LSA_T_NSSA: return lsa_validate_ext(lsa, body); -#ifdef OSPFv3 case LSA_T_LINK: return lsa_validate_link(lsa, body); case LSA_T_PREFIX: return lsa_validate_prefix(lsa, body); -#endif default: /* In OSPFv3, unknown LSAs are OK, In OSPFv2, unknown LSAs are already rejected diff --git a/proto/ospf/lsalib.h b/proto/ospf/lsalib.h index 0b556ec5e..3bdd814f6 100644 --- a/proto/ospf/lsalib.h +++ b/proto/ospf/lsalib.h @@ -26,12 +26,25 @@ static inline void htonlsab1(void *h, u16 len) { htonlsab(h, h, len); }; static inline void ntohlsab1(void *n, u16 len) { ntohlsab(n, n, len); }; #endif +struct ospf_lsa_rt_walk { + struct top_hash_entry *en; + void *buf, *bufend; + int ospf2; + u16 type, metric; + u32 id, data, lif, nif; +}; + void lsasum_calculate(struct ospf_lsa_header *header, void *body); u16 lsasum_check(struct ospf_lsa_header *h, void *body); #define CMP_NEWER 1 #define CMP_SAME 0 #define CMP_OLDER -1 int lsa_comp(struct ospf_lsa_header *l1, struct ospf_lsa_header *l2); +void lsa_walk_rt_init(struct proto_ospf *po, struct top_hash_entry *act, struct ospf_lsa_rt_walk *rt); +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); 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); diff --git a/proto/ospf/lsreq.c b/proto/ospf/lsreq.c index 1ba4fff93..ae9e7e411 100644 --- a/proto/ospf/lsreq.c +++ b/proto/ospf/lsreq.c @@ -9,47 +9,52 @@ #include "ospf.h" +/* struct ospf_lsreq_packet { - struct ospf_packet ospf_packet; - struct ospf_lsreq_header lsh[]; -}; + struct ospf_packet hdr; + // union ospf_auth auth; + struct ospf_lsreq_header lsrs[]; +}; +*/ -static void ospf_dump_lsreq(struct proto *p, struct ospf_lsreq_packet *pkt) +static void +ospf_lsreq_body(struct proto_ospf *po, struct ospf_packet *pkt, unsigned plen, + struct ospf_lsreq_header **body, unsigned *count) { - struct ospf_packet *op = &pkt->ospf_packet; + unsigned hdrlen = ospf_pkt_hdrlen(po); + *body = ((void *) pkt) + hdrlen; + *count = (plen - hdrlen) / sizeof(struct ospf_lsreq_header); +} - ASSERT(op->type == LSREQ_P); - ospf_dump_common(p, op); +static void +ospf_lsreq_dump(struct proto_ospf *po, struct ospf_packet *pkt) +{ + struct ospf_lsreq_header *lsrs; + unsigned i, lsr_count; - unsigned int i, j; - j = (ntohs(op->length) - sizeof(struct ospf_lsreq_packet)) / - sizeof(struct ospf_lsreq_header); + ASSERT(pkt->type == LSREQ_P); + ospf_dump_common(po, pkt); - for (i = 0; i < j; i++) - log(L_TRACE "%s: LSR Type: %04x, Id: %R, Rt: %R", p->name, - htonl(pkt->lsh[i].type), htonl(pkt->lsh[i].id), htonl(pkt->lsh[i].rt)); + ospf_lsreq_body(po, pkt, ntohs(pkt->length), &lsrs, &lsr_count); + for (i = 0; i < lsr_count; i++) + log(L_TRACE "%s: LSR Type: %04x, Id: %R, Rt: %R", po->proto.name, + ntohl(lsrs[i].type), ntohl(lsrs[i].id), ntohl(lsrs[i].rt)); } void ospf_lsreq_send(struct ospf_neighbor *n) { - snode *sn; + struct ospf_iface *ifa = n->ifa; + struct proto_ospf *po = ifa->oa->po; + struct ospf_lsreq_header *lsrs; struct top_hash_entry *en; - struct ospf_lsreq_packet *pk; - struct ospf_packet *op; - struct ospf_lsreq_header *lsh; - u16 length; - int i, j; - struct proto *p = &n->ifa->oa->po->proto; - - pk = ospf_tx_buffer(n->ifa); - op = &pk->ospf_packet; + struct ospf_packet *pkt; + unsigned i, lsh_max, length; + snode *sn; - ospf_pkt_fill_hdr(n->ifa, pk, LSREQ_P); - sn = SHEAD(n->lsrql); if (EMPTY_SLIST(n->lsrql)) { if (n->state == NEIGHBOR_LOADING) @@ -57,81 +62,68 @@ ospf_lsreq_send(struct ospf_neighbor *n) return; } - i = j = (ospf_pkt_maxsize(n->ifa) - sizeof(struct ospf_lsreq_packet)) / - sizeof(struct ospf_lsreq_header); - lsh = pk->lsh; + pkt = ospf_tx_buffer(ifa); + ospf_pkt_fill_hdr(ifa, pkt, LSREQ_P); + ospf_lsreq_body(po, pkt, ospf_pkt_maxsize(ifa), &lsrs, &lsh_max); - for (; i > 0; i--) + sn = SHEAD(n->lsrql); + for (i = 0; i < lsh_max; i++) { en = (struct top_hash_entry *) sn; - lsh->type = htonl(en->lsa.type); - lsh->rt = htonl(en->lsa.rt); - lsh->id = htonl(en->lsa.id); DBG("Requesting %uth LSA: Type: %u, ID: %R, RT: %R, SN: 0x%x, Age %u\n", i, en->lsa.type, en->lsa.id, en->lsa.rt, en->lsa.sn, en->lsa.age); - lsh++; + + lsrs[i].type = htonl(en->lsa.type); + lsrs[i].rt = htonl(en->lsa.rt); + lsrs[i].id = htonl(en->lsa.id); + if (sn == STAIL(n->lsrql)) break; sn = sn->next; } - if (i != 0) - i--; - length = - sizeof(struct ospf_lsreq_packet) + (j - - i) * sizeof(struct ospf_lsreq_header); - op->length = htons(length); + length = ospf_pkt_hdrlen(po) + i * sizeof(struct ospf_lsreq_header); + pkt->length = htons(length); - OSPF_PACKET(ospf_dump_lsreq, pk, "LSREQ packet sent to %I via %s", n->ip, n->ifa->iface->name); - ospf_send_to(n->ifa, n->ip); + OSPF_PACKET(ospf_lsreq_dump, pkt, "LSREQ packet sent to %I via %s", + n->ip, ifa->iface->name); + ospf_send_to(ifa, n->ip); } void -ospf_lsreq_receive(struct ospf_packet *ps_i, struct ospf_iface *ifa, +ospf_lsreq_receive(struct ospf_packet *pkt, struct ospf_iface *ifa, struct ospf_neighbor *n) { - struct ospf_area *oa = ifa->oa; - struct proto_ospf *po = oa->po; - struct proto *p = &po->proto; - struct ospf_lsreq_header *lsh; - struct l_lsr_head *llsh; + struct proto_ospf *po = ifa->oa->po; + struct ospf_lsreq_header *lsrs; + unsigned i, lsr_count; list uplist; slab *upslab; - int i, lsano; - unsigned int size = ntohs(ps_i->length); - if (size < sizeof(struct ospf_lsreq_packet)) - { - log(L_ERR "Bad OSPF LSREQ packet from %I - too short (%u B)", n->ip, size); - return; - } - struct ospf_lsreq_packet *ps = (void *) ps_i; - OSPF_PACKET(ospf_dump_lsreq, ps, "LSREQ packet received from %I via %s", n->ip, ifa->iface->name); + /* No need to check length, lsreq has only basic header */ + + OSPF_PACKET(ospf_lsreq_dump, pkt, "LSREQ packet received from %I via %s", + n->ip, ifa->iface->name); if (n->state < NEIGHBOR_EXCHANGE) return; - ospf_neigh_sm(n, INM_HELLOREC); + ospf_neigh_sm(n, INM_HELLOREC); /* Not in RFC */ - lsh = ps->lsh; init_list(&uplist); upslab = sl_new(n->pool, sizeof(struct l_lsr_head)); - lsano = (size - sizeof(struct ospf_lsreq_packet)) / - sizeof(struct ospf_lsreq_header); - for (i = 0; i < lsano; lsh++, i++) + ospf_lsreq_body(po, pkt, ntohs(pkt->length), &lsrs, &lsr_count); + for (i = 0; i < lsr_count; i++) { - u32 hid = ntohl(lsh->id); - u32 hrt = ntohl(lsh->rt); - u32 htype = ntohl(lsh->type); + 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); - DBG("Processing requested LSA: Type: %u, ID: %R, RT: %R\n", lsh->type, hid, hrt); - llsh = sl_alloc(upslab); - llsh->lsh.id = hid; - llsh->lsh.rt = hrt; - llsh->lsh.type = htype; - add_tail(&uplist, NODE llsh); + // XXXX check + DBG("Processing requested LSA: Type: %u, ID: %R, RT: %R\n", htype, hid, hrt); + if (ospf_hash_find(po->gr, dom, hid, hrt, htype) == NULL) { log(L_WARN "Received bad LSREQ from %I: Type: %04x, Id: %R, Rt: %R", @@ -140,7 +132,14 @@ ospf_lsreq_receive(struct ospf_packet *ps_i, struct ospf_iface *ifa, 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); } + ospf_lsupd_send_list(n, &uplist); rfree(upslab); } diff --git a/proto/ospf/lsupd.c b/proto/ospf/lsupd.c index f71c72d1d..9255785e0 100644 --- a/proto/ospf/lsupd.c +++ b/proto/ospf/lsupd.c @@ -17,27 +17,29 @@ struct ospf_lsupd_packet /* Beware of unaligned access */ -void ospf_dump_lsahdr(struct proto *p, struct ospf_lsa_header *lsa_n) +void ospf_dump_lsahdr(struct proto_ospf *po, struct ospf_lsa_header *lsa_n) { struct ospf_lsa_header lsa; ntohlsah(lsa_n, &lsa); log(L_TRACE "%s: LSA Type: %04x, Id: %R, Rt: %R, Age: %u, Seq: %08x, Sum: %04x", - p->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 *p, struct ospf_packet *op) +void ospf_dump_common(struct proto_ospf *po, struct ospf_packet *pkt) { - log(L_TRACE "%s: length %d", p->name, ntohs(op->length)); - log(L_TRACE "%s: router %R", p->name, ntohl(op->routerid)); + struct proto *p = &po->proto; + log(L_TRACE "%s: length %d", p->name, ntohs(pkt->length)); + log(L_TRACE "%s: router %R", p->name, ntohl(pkt->routerid)); } -static void ospf_dump_lsupd(struct proto *p, struct ospf_lsupd_packet *pkt) +static void ospf_dump_lsupd(struct proto_ospf *po, struct ospf_lsupd_packet *pkt) { + struct proto *p = &po->proto; struct ospf_packet *op = &pkt->ospf_packet; ASSERT(op->type == LSUPD_P); - ospf_dump_common(p, op); + ospf_dump_common(po, op); /* We know that ntohs(op->length) >= sizeof(struct ospf_lsa_header) */ u8 *pbuf= (u8 *) pkt; @@ -160,7 +162,6 @@ ospf_lsupd_flood(struct proto_ospf *po, struct ospf_iface *ifa; struct ospf_neighbor *nn; struct top_hash_entry *en; - struct proto *p = &po->proto; int ret, retval = 0; /* pg 148 */ @@ -352,7 +353,7 @@ void /* I send all I received in LSREQ */ ospf_lsupd_send_list(struct ospf_neighbor *n, list * l) { struct ospf_area *oa = n->ifa->oa; - struct proto *p = &oa->po->proto; + struct proto_ospf *po = oa->po; struct l_lsr_head *lsr; struct top_hash_entry *en; struct ospf_lsupd_packet *pkt; @@ -487,6 +488,8 @@ ospf_lsupd_receive(struct ospf_packet *ps_i, struct ospf_iface *ifa, continue; } + u16 lsa_type = ntohs(lsa->type_raw); + lsa_type = xxxx(lsa_type); // XXXX finish #ifdef OSPFv2 /* pg 143 (2) */ if ((lsa->type == 0) || (lsa->type == 6) || (lsa->type > LSA_T_NSSA)) @@ -496,21 +499,21 @@ ospf_lsupd_receive(struct ospf_packet *ps_i, struct ospf_iface *ifa, } /* pg 143 (3) */ - if ((lsa->type == LSA_T_EXT) && !oa_is_ext(ifa->oa)) + 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) == LSA_SCOPE_AS) && !oa_is_ext(ifa->oa)) + 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); continue; } /* 4.5.1 (3) */ - if ((LSA_SCOPE(lsa) == LSA_SCOPE_RES)) + if ((LSA_SCOPE(lsa_type) == LSA_SCOPE_RES)) { log(L_WARN "Received LSA with invalid scope from %I", n->ip); continue; @@ -520,10 +523,10 @@ ospf_lsupd_receive(struct ospf_packet *ps_i, struct ospf_iface *ifa, ntohlsah(lsa, &lsatmp); DBG("Update Type: %u ID: %R RT: %R, Sn: 0x%08x Age: %u, Sum: %u\n", - lsatmp.type, lsatmp.id, lsatmp.rt, lsatmp.sn, lsatmp.age, lsatmp.checksum); + 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(lsatmp.type, ifa); + u32 domain = ospf_lsa_domain(lsa_type, ifa); lsadb = ospf_hash_find_header(po->gr, domain, &lsatmp); #ifdef LOCAL_DEBUG @@ -550,7 +553,7 @@ ospf_lsupd_receive(struct ospf_packet *ps_i, struct ospf_iface *ifa, #ifdef OSPFv2 /* 13.4 - check self-originated LSAs of NET type */ - if ((!self) && (lsatmp.type == LSA_T_NET)) + if ((!self) && (lsa_type == LSA_T_NET)) { struct ospf_iface *nifa; WALK_LIST(nifa, po->iface_list) @@ -576,7 +579,7 @@ ospf_lsupd_receive(struct ospf_packet *ps_i, struct ospf_iface *ifa, } OSPF_TRACE(D_EVENTS, "Received old self-originated LSA (Type: %04x, Id: %R, Rt: %R)", - lsatmp.type, lsatmp.id, lsatmp.rt); + lsa_type, lsatmp.id, lsatmp.rt); if (lsadb) { @@ -666,8 +669,7 @@ ospf_lsupd_receive(struct ospf_packet *ps_i, struct ospf_iface *ifa, #ifdef OSPFv3 /* Events 6,7 from RFC5340 4.4.3. */ - if ((lsatmp.type == LSA_T_LINK) && - (ifa->state == OSPF_IS_DR)) + if ((lsa_type == LSA_T_LINK) && (ifa->state == OSPF_IS_DR)) schedule_net_lsa(ifa); #endif @@ -733,12 +735,11 @@ void ospf_lsupd_flush_nlsa(struct proto_ospf *po, struct top_hash_entry *en) { struct ospf_lsa_header *lsa = &en->lsa; - struct proto *p = &po->proto; lsa->age = LSA_MAXAGE; lsa->sn = LSA_MAXSEQNO; lsasum_calculate(lsa, en->lsa_body); OSPF_TRACE(D_EVENTS, "Premature aging self originated lsa!"); - OSPF_TRACE(D_EVENTS, "Type: %04x, Id: %R, Rt: %R", lsa->type, lsa->id, lsa->rt); + OSPF_TRACE(D_EVENTS, "Type: %04x, Id: %R, Rt: %R", en->lsa_type, lsa->id, lsa->rt); ospf_lsupd_flood(po, NULL, NULL, lsa, en->domain, 0); } diff --git a/proto/ospf/lsupd.h b/proto/ospf/lsupd.h index 8bacfe655..29ea491f4 100644 --- a/proto/ospf/lsupd.h +++ b/proto/ospf/lsupd.h @@ -10,8 +10,8 @@ #ifndef _BIRD_OSPF_LSUPD_H_ #define _BIRD_OSPF_LSUPD_H_ -void ospf_dump_lsahdr(struct proto *p, struct ospf_lsa_header *lsa_n); -void ospf_dump_common(struct proto *p, struct ospf_packet *op); +void ospf_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_receive(struct ospf_packet *ps_i, struct ospf_iface *ifa, struct ospf_neighbor *n); diff --git a/proto/ospf/neighbor.c b/proto/ospf/neighbor.c index 642365b35..2c55f58c4 100644 --- a/proto/ospf/neighbor.c +++ b/proto/ospf/neighbor.c @@ -123,7 +123,6 @@ neigh_chstate(struct ospf_neighbor *n, u8 state) { struct ospf_iface *ifa = n->ifa; struct proto_ospf *po = ifa->oa->po; - struct proto *p = &po->proto; n->state = state; @@ -157,13 +156,10 @@ neigh_chstate(struct ospf_neighbor *n, u8 state) n->dds = random_u32(); } n->dds++; - n->myimms.byte = 0; - n->myimms.bit.ms = 1; - n->myimms.bit.m = 1; - n->myimms.bit.i = 1; + n->myimms = DBDES_IMMS; } if (state > NEIGHBOR_EXSTART) - n->myimms.bit.i = 0; + n->myimms &= ~DBDES_I; } } @@ -554,7 +550,7 @@ neighbor_timer_hook(timer * timer) { struct ospf_neighbor *n = (struct ospf_neighbor *) timer->data; struct ospf_iface *ifa = n->ifa; - struct proto *p = &ifa->oa->po->proto; + struct proto_ospf *po = ifa->oa->po; OSPF_TRACE(D_EVENTS, "Inactivity timer fired on interface %s for neighbor %I.", @@ -566,7 +562,8 @@ void ospf_neigh_remove(struct ospf_neighbor *n) { struct ospf_iface *ifa = n->ifa; - struct proto *p = &ifa->oa->po->proto; + struct proto_ospf *po = ifa->oa->po; + u32 rid = n->rid; if ((ifa->type == OSPF_IT_NBMA) || (ifa->type == OSPF_IT_PTMP)) { @@ -579,7 +576,7 @@ ospf_neigh_remove(struct ospf_neighbor *n) neigh_chstate(n, NEIGHBOR_DOWN); rem_node(NODE n); rfree(n->pool); - OSPF_TRACE(D_EVENTS, "Deleting neigbor."); + OSPF_TRACE(D_EVENTS, "Deleting neigbor %R", rid); } void @@ -633,7 +630,7 @@ rxmt_timer_hook(timer * timer) return; } - if ((n->state == NEIGHBOR_EXCHANGE) && n->myimms.bit.ms) /* I'm master */ + if ((n->state == NEIGHBOR_EXCHANGE) && (n->myimms & DBDES_MS)) /* I'm master */ ospf_dbdes_send(n, 0); diff --git a/proto/ospf/ospf.c b/proto/ospf/ospf.c index 44dd7fef1..556e54842 100644 --- a/proto/ospf/ospf.c +++ b/proto/ospf/ospf.c @@ -185,11 +185,11 @@ ospf_area_add(struct proto_ospf *po, struct ospf_area_config *ac, int reconf) static void ospf_area_remove(struct ospf_area *oa) { - struct proto *p = &oa->po->proto; + struct proto_ospf *po = oa->po; OSPF_TRACE(D_EVENTS, "Removing area %R", oa->areaid); /* We suppose that interfaces are already removed */ - ospf_flush_area(oa->po, oa->areaid); + ospf_flush_area(po, oa->areaid); fib_free(&oa->rtr); fib_free(&oa->net_fib); @@ -198,7 +198,7 @@ ospf_area_remove(struct ospf_area *oa) if (oa->translator_timer) rfree(oa->translator_timer); - oa->po->areano--; + po->areano--; rem_node(NODE oa); mb_free(oa); } @@ -377,7 +377,7 @@ ospf_build_attrs(ea_list * next, struct linpool *pool, u32 m1, u32 m2, void schedule_net_lsa(struct ospf_iface *ifa) { - struct proto *p = &ifa->oa->po->proto; + struct proto_ospf *po = ifa->oa->po; OSPF_TRACE(D_EVENTS, "Scheduling network-LSA origination for iface %s", ifa->iface->name); ifa->orignet = 1; @@ -387,7 +387,7 @@ schedule_net_lsa(struct ospf_iface *ifa) void schedule_link_lsa(struct ospf_iface *ifa) { - struct proto *p = &ifa->oa->po->proto; + struct proto_ospf *po = ifa->oa->po; OSPF_TRACE(D_EVENTS, "Scheduling link-LSA origination for iface %s", ifa->iface->name); ifa->origlink = 1; @@ -397,7 +397,7 @@ schedule_link_lsa(struct ospf_iface *ifa) void schedule_rt_lsa(struct ospf_area *oa) { - struct proto *p = &oa->po->proto; + struct proto_ospf *po = oa->po; OSPF_TRACE(D_EVENTS, "Scheduling router-LSA origination for area %R", oa->areaid); oa->origrt = 1; @@ -406,8 +406,6 @@ schedule_rt_lsa(struct ospf_area *oa) void schedule_rtcalc(struct proto_ospf *po) { - struct proto *p = &po->proto; - if (po->calcrt) return; @@ -449,11 +447,9 @@ area_disp(struct ospf_area *oa) /* Now try to originate network LSA's */ WALK_LIST(ifa, po->iface_list) { -#ifdef OSPFv3 /* Link LSA should be originated before Network LSA */ - if (ifa->origlink && (ifa->oa == oa)) + if (ospf_is_v3(po) && ifa->origlink && (ifa->oa == oa)) update_link_lsa(ifa); -#endif if (ifa->orignet && (ifa->oa == oa)) update_net_lsa(ifa); @@ -945,32 +941,44 @@ fake_lsa_from_prefix_lsa(struct ospf_lsa_header *dst, struct ospf_lsa_header *sr #endif +static int lsa_compare_ospf3; // XXXX fixme + static int lsa_compare_for_state(const void *p1, const void *p2) { - struct top_hash_entry * he1 = * (struct top_hash_entry **) p1; - struct top_hash_entry * he2 = * (struct top_hash_entry **) p2; + struct top_hash_entry *he1 = * (struct top_hash_entry **) p1; + struct top_hash_entry *he2 = * (struct top_hash_entry **) p2; struct ospf_lsa_header *lsa1 = &(he1->lsa); struct ospf_lsa_header *lsa2 = &(he2->lsa); + struct ospf_lsa_header lsatmp1, lsatmp2; + u16 lsa1_type = he1->lsa_type; + u16 lsa2_type = he2->lsa_type; + int px1 = 0; + int px2 = 0; if (he1->domain != he2->domain) return he1->domain - he2->domain; -#ifdef OSPFv3 - struct ospf_lsa_header lsatmp1, lsatmp2; + if (lsa_compare_ospf3) + { + px1 = (lsa1_type == LSA_T_PREFIX); + px2 = (lsa2_type == LSA_T_PREFIX); + xxxx(); - int px1 = (lsa1->type == LSA_T_PREFIX); - int px2 = (lsa2->type == LSA_T_PREFIX); + if (px1) + { + lsa1 = fake_lsa_from_prefix_lsa(&lsatmp1, lsa1, he1->lsa_body); + lsa1_type = lsa1->type; + px1 = 1; + } - if (px1) - lsa1 = fake_lsa_from_prefix_lsa(&lsatmp1, lsa1, he1->lsa_body); + if (px2) + lsa2 = fake_lsa_from_prefix_lsa(&lsatmp2, lsa2, he2->lsa_body); + } - if (px2) - lsa2 = fake_lsa_from_prefix_lsa(&lsatmp2, lsa2, he2->lsa_body); -#endif - int nt1 = (lsa1->type == LSA_T_NET); - int nt2 = (lsa2->type == LSA_T_NET); + int nt1 = (lsa1_type == LSA_T_NET); + int nt2 = (lsa2_type == LSA_T_NET); if (nt1 != nt2) return nt1 - nt2; @@ -988,10 +996,8 @@ lsa_compare_for_state(const void *p1, const void *p2) if (lsa1->id != lsa2->id) return lsa1->id - lsa2->id; -#ifdef OSPFv3 if (px1 != px2) return px1 - px2; -#endif return lsa1->sn - lsa2->sn; } @@ -1000,16 +1006,14 @@ lsa_compare_for_state(const void *p1, const void *p2) if (lsa1->rt != lsa2->rt) return lsa1->rt - lsa2->rt; - if (lsa1->type != lsa2->type) - return lsa1->type - lsa2->type; + if (lsa1_type != lsa2_type) + return lsa1_type - lsa2_type; if (lsa1->id != lsa2->id) return lsa1->id - lsa2->id; -#ifdef OSPFv3 if (px1 != px2) return px1 - px2; -#endif return lsa1->sn - lsa2->sn; } @@ -1042,79 +1046,77 @@ show_lsa_distance(struct top_hash_entry *he) } static inline void -show_lsa_router(struct proto_ospf *po, struct top_hash_entry *he, int first, int verbose) +show_lsa_router(struct proto_ospf *po, struct top_hash_entry *he, int verbose) { - struct ospf_lsa_header *lsa = &(he->lsa); - struct ospf_lsa_rt *rt = he->lsa_body; - struct ospf_lsa_rt_link *rr = (struct ospf_lsa_rt_link *) (rt + 1); - int max = lsa_rt_count(lsa); - int i; - - if (first) - { - cli_msg(-1016, ""); - cli_msg(-1016, "\trouter %R", he->lsa.rt); - show_lsa_distance(he); - } + struct ospf_lsa_rt_walk rtl; + cli_msg(-1016, ""); + cli_msg(-1016, "\trouter %R", he->lsa.rt); + show_lsa_distance(he); - for (i = 0; i < max; i++) - if (rr[i].type == LSART_VLNK) - cli_msg(-1016, "\t\tvlink %R metric %u", rr[i].id, rr[i].metric); + lsa_walk_rt_init(po, he, &rtl); + while (lsa_walk_rt(&rtl)) + if (rtl.type == LSART_VLNK) + cli_msg(-1016, "\t\tvlink %R metric %u", rtl.id, rtl.metric); - for (i = 0; i < max; i++) - if (rr[i].type == LSART_PTP) - cli_msg(-1016, "\t\trouter %R metric %u", rr[i].id, rr[i].metric); + lsa_walk_rt_init(po, he, &rtl); + while (lsa_walk_rt(&rtl)) + if (rtl.type == LSART_PTP) + cli_msg(-1016, "\t\trouter %R metric %u", rtl.id, rtl.metric); - for (i = 0; i < max; i++) - if (rr[i].type == LSART_NET) + lsa_walk_rt_init(po, he, &rtl); + while (lsa_walk_rt(&rtl)) + if (rtl.type == LSART_NET) { -#ifdef OSPFv2 - struct top_hash_entry *net_he = ospf_hash_find_net(po->gr, he->domain, rr[i].id); - - if (net_he) + if (ospf_is_v2(po)) { - struct ospf_lsa_header *net_lsa = &(net_he->lsa); - struct ospf_lsa_net *net_ln = net_he->lsa_body; + /* In OSPFv2, we try to find network-LSA to get prefix/pxlen */ + struct top_hash_entry *net_he = ospf_hash_find_net(po->gr, he->domain, rtl.id, 0); + + if (net_he) + { + struct ospf_lsa_header *net_lsa = &(net_he->lsa); + struct ospf_lsa_net *net_ln = net_he->lsa_body; - cli_msg(-1016, "\t\tnetwork %I/%d metric %u", - ipa_and(ipa_from_u32(net_lsa->id), net_ln->netmask), - ipa_mklen(net_ln->netmask), rr[i].metric); + cli_msg(-1016, "\t\tnetwork %I/%d metric %u", + ipa_from_u32(net_lsa->id & net_ln->optx), + u32_masklen(net_ln->optx), rtl.metric); + } + else + cli_msg(-1016, "\t\tnetwork [%R] metric %u", rtl.id, rtl.metric); } else - cli_msg(-1016, "\t\tnetwork [%R] metric %u", rr[i].id, rr[i].metric); - -#else /* OSPFv3 */ - cli_msg(-1016, "\t\tnetwork [%R-%u] metric %u", rr[i].id, rr[i].nif, rr[i].metric); -#endif + cli_msg(-1016, "\t\tnetwork [%R-%u] metric %u", rtl.id, rtl.nif, rtl.metric); } -#ifdef OSPFv2 - if (!verbose) - return; - - for (i = 0; i < max; i++) - if (rr[i].type == LSART_STUB) - cli_msg(-1016, "\t\tstubnet %I/%d metric %u", ipa_from_u32(rr[i].id), - ipa_mklen(ipa_from_u32(rr[i].data)), rr[i].metric); -#endif + if (ospf_is_v2(po) && verbose) + { + lsa_walk_rt_init(po, he, &rtl); + while (lsa_walk_rt(&rtl)) + if (rtl.type == LSART_STUB) + cli_msg(-1016, "\t\tstubnet %I/%d metric %u", + ipa_from_u32(rtl.id), u32_masklen(rtl.data), rtl.metric); + } } static inline void -show_lsa_network(struct top_hash_entry *he) +show_lsa_network(struct top_hash_entry *he, int ospf2) { struct ospf_lsa_header *lsa = &(he->lsa); struct ospf_lsa_net *ln = he->lsa_body; u32 i; -#ifdef OSPFv2 - cli_msg(-1016, ""); - cli_msg(-1016, "\tnetwork %I/%d", ipa_and(ipa_from_u32(lsa->id), ln->netmask), ipa_mklen(ln->netmask)); - cli_msg(-1016, "\t\tdr %R", lsa->rt); -#else /* OSPFv3 */ - cli_msg(-1016, ""); - cli_msg(-1016, "\tnetwork [%R-%u]", lsa->rt, lsa->id); -#endif + if (ospf2) + { + cli_msg(-1016, ""); + cli_msg(-1016, "\tnetwork %I/%d", ipa_from_u32(lsa->id & ln->optx), u32_masklen(ln->optx)); + cli_msg(-1016, "\t\tdr %R", lsa->rt); + } + else + { + cli_msg(-1016, ""); + cli_msg(-1016, "\tnetwork [%R-%u]", lsa->rt, lsa->id); + } show_lsa_distance(he); @@ -1123,95 +1125,52 @@ show_lsa_network(struct top_hash_entry *he) } static inline void -show_lsa_sum_net(struct top_hash_entry *he) +show_lsa_sum_net(struct top_hash_entry *he, int ospf2) { ip_addr ip; int pxlen; - -#ifdef OSPFv2 - struct ospf_lsa_sum *ls = he->lsa_body; - pxlen = ipa_mklen(ls->netmask); - ip = ipa_and(ipa_from_u32(he->lsa.id), ls->netmask); -#else /* OSPFv3 */ u8 pxopts; - u16 rest; - struct ospf_lsa_sum_net *ls = he->lsa_body; - lsa_get_ipv6_prefix(ls->prefix, &ip, &pxlen, &pxopts, &rest); -#endif + u32 metric; - cli_msg(-1016, "\t\txnetwork %I/%d metric %u", ip, pxlen, ls->metric); + lsa_parse_sum_net(he, ospf2, &ip, &pxlen, &pxopts, &metric); + cli_msg(-1016, "\t\txnetwork %I/%d metric %u", ip, pxlen, metric); } static inline void -show_lsa_sum_rt(struct top_hash_entry *he) +show_lsa_sum_rt(struct top_hash_entry *he, int ospf2) { + u32 metric; u32 dst_rid; + u32 options; -#ifdef OSPFv2 - struct ospf_lsa_sum *ls = he->lsa_body; - dst_rid = he->lsa.id; - // options = 0; -#else /* OSPFv3 */ - struct ospf_lsa_sum_rt *ls = he->lsa_body; - dst_rid = ls->drid; - // options = ls->options & OPTIONS_MASK; -#endif - - cli_msg(-1016, "\t\txrouter %R metric %u", dst_rid, ls->metric); + lsa_parse_sum_rt(he, ospf2, &dst_rid, &metric, &options); + cli_msg(-1016, "\t\txrouter %R metric %u", dst_rid, metric); } static inline void -show_lsa_external(struct top_hash_entry *he) +show_lsa_external(struct top_hash_entry *he, int ospf2) { - struct ospf_lsa_ext *ext = he->lsa_body; + struct ospf_lsa_ext_local rt; char str_via[STD_ADDRESS_P_LENGTH + 8] = ""; char str_tag[16] = ""; - ip_addr ip, rt_fwaddr; - int pxlen, ebit, rt_fwaddr_valid; - u32 rt_tag, rt_metric; - if (he->lsa.type == LSA_T_EXT) + if (he->lsa_type == LSA_T_EXT) he->domain = 0; /* Unmark the LSA */ - rt_metric = ext->metric & METRIC_MASK; - ebit = ext->metric & LSA_EXT_EBIT; -#ifdef OSPFv2 - ip = ipa_and(ipa_from_u32(he->lsa.id), ext->netmask); - pxlen = ipa_mklen(ext->netmask); - rt_fwaddr = ext->fwaddr; - rt_fwaddr_valid = !ipa_equal(rt_fwaddr, IPA_NONE); - rt_tag = ext->tag; -#else /* OSPFv3 */ - u8 pxopts; - u16 rest; - u32 *buf = ext->rest; - buf = lsa_get_ipv6_prefix(buf, &ip, &pxlen, &pxopts, &rest); - - rt_fwaddr_valid = ext->metric & LSA_EXT_FBIT; - if (rt_fwaddr_valid) - buf = lsa_get_ipv6_addr(buf, &rt_fwaddr); - else - rt_fwaddr = IPA_NONE; - - if (ext->metric & LSA_EXT_TBIT) - rt_tag = *buf++; - else - rt_tag = 0; -#endif + lsa_parse_ext(he, ospf2, &rt); - if (rt_fwaddr_valid) - bsprintf(str_via, " via %I", rt_fwaddr); + if (rt.fbit) + bsprintf(str_via, " via %I", rt.fwaddr); - if (rt_tag) - bsprintf(str_tag, " tag %08x", rt_tag); + if (rt.tag) + bsprintf(str_tag, " tag %08x", rt.tag); cli_msg(-1016, "\t\t%s %I/%d metric%s %u%s%s", - (he->lsa.type == LSA_T_NSSA) ? "nssa-ext" : "external", - ip, pxlen, ebit ? "2" : "", rt_metric, str_via, str_tag); + (he->lsa_type == LSA_T_NSSA) ? "nssa-ext" : "external", + rt.ip, rt.pxlen, rt.ebit ? "2" : "", rt.metric, str_via, str_tag); } -#ifdef OSPFv3 static inline void show_lsa_prefix(struct top_hash_entry *he, struct ospf_lsa_header *cnode) { @@ -1224,7 +1183,7 @@ show_lsa_prefix(struct top_hash_entry *he, struct ospf_lsa_header *cnode) int i; /* We check whether given prefix-LSA is related to the current node */ - if ((px->ref_type != cnode->type) || (px->ref_rt != cnode->rt)) + if ((px->ref_type != cnode->type_raw) || (px->ref_rt != cnode->rt)) return; if ((px->ref_type == LSA_T_RT) && (px->ref_id != 0)) @@ -1244,13 +1203,13 @@ show_lsa_prefix(struct top_hash_entry *he, struct ospf_lsa_header *cnode) cli_msg(-1016, "\t\taddress %I/%d", pxa, pxlen); } } -#endif void ospf_sh_state(struct proto *p, int verbose, int reachable) { struct proto_ospf *po = (struct proto_ospf *) p; struct ospf_lsa_header *cnode = NULL; + int ospf2 = ospf_is_v2(po); int num = po->gr->hash_entries; unsigned int i, ix, j1, j2, jx; u32 last_area = 0xFFFFFFFF; @@ -1274,7 +1233,7 @@ ospf_sh_state(struct proto *p, int verbose, int reachable) { int accept; - switch (he->lsa.type) + switch (he->lsa_type) { case LSA_T_RT: case LSA_T_NET: @@ -1284,9 +1243,7 @@ ospf_sh_state(struct proto *p, int verbose, int reachable) case LSA_T_SUM_NET: case LSA_T_SUM_RT: case LSA_T_NSSA: -#ifdef OSPFv3 case LSA_T_PREFIX: -#endif accept = verbose; break; @@ -1339,7 +1296,7 @@ ospf_sh_state(struct proto *p, int verbose, int reachable) /* If there is no opened node, we open the LSA (if appropriate) or skip to the next one */ if (!cnode) { - if (((he->lsa.type == LSA_T_RT) || (he->lsa.type == LSA_T_NET)) + if (((he->lsa_type == LSA_T_RT) || (he->lsa_type == LSA_T_NET)) && ((he->color == INSPF) || !reachable)) { cnode = &(he->lsa); @@ -1358,35 +1315,34 @@ ospf_sh_state(struct proto *p, int verbose, int reachable) ASSERT(cnode && (he->domain == last_area) && (he->lsa.rt == cnode->rt)); - switch (he->lsa.type) + switch (he->lsa_type) { case LSA_T_RT: - show_lsa_router(po, he, he->lsa.id == cnode->id, verbose); + if (he->lsa.id == cnode->id) + show_lsa_router(po, he, verbose); break; case LSA_T_NET: - show_lsa_network(he); + show_lsa_network(he, ospf2); break; case LSA_T_SUM_NET: if (cnode->type == LSA_T_RT) - show_lsa_sum_net(he); + show_lsa_sum_net(he, ospf2); break; case LSA_T_SUM_RT: if (cnode->type == LSA_T_RT) - show_lsa_sum_rt(he); + show_lsa_sum_rt(he, ospf2); break; -#ifdef OSPFv3 - case LSA_T_PREFIX: - show_lsa_prefix(he, cnode); - break; -#endif - case LSA_T_EXT: case LSA_T_NSSA: - show_lsa_external(he); + show_lsa_external(he, ospf2); + break; + + case LSA_T_PREFIX: + show_lsa_prefix(he, cnode); break; } @@ -1394,13 +1350,13 @@ ospf_sh_state(struct proto *p, int verbose, int reachable) if ((i+1 == j1) || (hea[i+1]->domain != last_area) || (hea[i+1]->lsa.rt != cnode->rt) - || (hea[i+1]->lsa.type == LSA_T_NET)) + || (hea[i+1]->lsa_type == LSA_T_NET)) { while ((ix < jx) && (hex[ix]->lsa.rt < cnode->rt)) ix++; while ((ix < jx) && (hex[ix]->lsa.rt == cnode->rt)) - show_lsa_external(hex[ix++]); + show_lsa_external(hex[ix++], ospf2); cnode = NULL; } @@ -1434,7 +1390,7 @@ ospf_sh_state(struct proto *p, int verbose, int reachable) last_rt = he->lsa.rt; } - show_lsa_external(he); + show_lsa_external(he, ospf2); } } @@ -1449,8 +1405,8 @@ lsa_compare_for_lsadb(const void *p1, const void *p2) struct top_hash_entry * he2 = * (struct top_hash_entry **) p2; struct ospf_lsa_header *lsa1 = &(he1->lsa); struct ospf_lsa_header *lsa2 = &(he2->lsa); - int sc1 = LSA_SCOPE(lsa1); - int sc2 = LSA_SCOPE(lsa2); + int sc1 = LSA_SCOPE(he1->lsa_type); + int sc2 = LSA_SCOPE(he2->lsa_type); if (sc1 != sc2) return sc2 - sc1; @@ -1464,8 +1420,8 @@ lsa_compare_for_lsadb(const void *p1, const void *p2) if (lsa1->id != lsa2->id) return lsa1->id - lsa2->id; - if (lsa1->type != lsa2->type) - return lsa1->type - lsa2->type; + if (he1->lsa_type != he2->lsa_type) + return he1->lsa_type - he2->lsa_type; return lsa1->sn - lsa2->sn; } @@ -1505,7 +1461,7 @@ ospf_sh_lsadb(struct lsadb_show_data *ld) for (i = 0; i < j; i++) { struct ospf_lsa_header *lsa = &(hea[i]->lsa); - int dscope = LSA_SCOPE(lsa); + int dscope = LSA_SCOPE(hea[i]->lsa_type); if (ld->scope && (dscope != (ld->scope & 0xf000))) continue; @@ -1514,6 +1470,7 @@ ospf_sh_lsadb(struct lsadb_show_data *ld) continue; /* Ignore high nibble */ + // XXXX check if (ld->type && ((lsa->type & 0x0fff) != (ld->type & 0x0fff))) continue; diff --git a/proto/ospf/ospf.h b/proto/ospf/ospf.h index 3bffaf91c..4d4cf6754 100644 --- a/proto/ospf/ospf.h +++ b/proto/ospf/ospf.h @@ -9,7 +9,7 @@ #ifndef _BIRD_OSPF_H_ #define _BIRD_OSPF_H_ -#define MAXNETS 10 + #define OSPF_MAX_PKT_SIZE 65535 /* * RFC 2328 says, maximum packet size is 65535 (IP packet size @@ -24,12 +24,14 @@ #else #define OSPF_FORCE_DEBUG 0 #endif -#define OSPF_TRACE(flags, msg, args...) do { if ((p->debug & flags) || OSPF_FORCE_DEBUG) \ - log(L_TRACE "%s: " msg, p->name , ## args ); } while(0) + +#define OSPF_TRACE(flags, msg, args...) \ +do { if ((po->proto.debug & flags) || OSPF_FORCE_DEBUG) \ + log(L_TRACE "%s: " msg, po->proto.name , ## args ); } while(0) #define OSPF_PACKET(dumpfn, buffer, msg, args...) \ -do { if ((p->debug & D_PACKETS) || OSPF_FORCE_DEBUG) \ -{ log(L_TRACE "%s: " msg, p->name, ## args ); dumpfn(p, buffer); } } while(0) +do { if ((po->proto.debug & D_PACKETS) || OSPF_FORCE_DEBUG) \ +{ log(L_TRACE "%s: " msg, po->proto.name, ## args ); dumpfn(po, buffer); } } while(0) #include "nest/bird.h" @@ -51,19 +53,11 @@ do { if ((p->debug & D_PACKETS) || OSPF_FORCE_DEBUG) \ #define OSPF_PROTO 89 -#ifndef IPV6 -#define OSPFv2 1 -#define OSPF_VERSION 2 -#define OSPF_VLINK_MTU 576 /* RFC 2328 A.1 */ -#define AllSPFRouters ipa_from_u32(0xe0000005) /* 224.0.0.5 */ -#define AllDRouters ipa_from_u32(0xe0000006) /* 224.0.0.6 */ -#else + +// XXXX #define OSPFv3 1 #define OSPF_VERSION 3 -#define OSPF_VLINK_MTU 1280 /* RFC 5340 A.1 */ -#define AllSPFRouters _MI(0xFF020000, 0, 0, 5) /* FF02::5 */ -#define AllDRouters _MI(0xFF020000, 0, 0, 6) /* FF02::6 */ -#endif + #define LSREFRESHTIME 1800 /* 30 minutes */ @@ -140,38 +134,45 @@ struct ospf_area_config }; -/* Option flags */ +/* Generic option flags */ +#define OPT_V6 0x01 /* OSPFv3, LSA relevant for IPv6 routing calculation */ +#define OPT_E 0x02 /* Related to AS-external LSAs */ +#define OPT_MC 0x04 /* Related to MOSPF, not used and obsolete */ +#define OPT_N 0x08 /* Related to NSSA */ +#define OPT_P 0x08 /* OSPFv2, flags P and N share position, see NSSA RFC */ +#define OPT_EA 0x10 /* OSPFv2, external attributes, not used and obsolete */ +#define OPT_R 0x10 /* OSPFv3, originator is active router */ +#define OPT_DC 0x20 /* Related to demand circuits, not used */ -#define OPT_E 0x02 -#define OPT_N 0x08 -#define OPT_DC 0x20 - -#ifdef OSPFv2 -#define OPT_P 0x08 /* flags P and N share position, see NSSA RFC */ -#define OPT_EA 0x10 - -/* VEB flags are are stored independently in 'u16 options' */ -#define OPT_RT_B (0x01 << 8) -#define OPT_RT_E (0x02 << 8) -#define OPT_RT_V (0x04 << 8) -#define OPT_RT_NT (0x10 << 8) -#endif - -#ifdef OSPFv3 -#define OPT_V6 0x01 -#define OPT_R 0x10 - -/* VEB flags are are stored together with options in 'u32 options' */ +/* Router-LSA VEB flags are are stored together with links (OSPFv2) or options (OSPFv3) */ #define OPT_RT_B (0x01 << 24) #define OPT_RT_E (0x02 << 24) #define OPT_RT_V (0x04 << 24) #define OPT_RT_NT (0x10 << 24) +/* Prefix flags, specific for OSPFv3 */ #define OPT_PX_NU 0x01 #define OPT_PX_LA 0x02 #define OPT_PX_P 0x08 #define OPT_PX_DN 0x10 -#endif + + +/* OSPF interface types */ +#define OSPF_IT_BCAST 0 +#define OSPF_IT_NBMA 1 +#define OSPF_IT_PTP 2 +#define OSPF_IT_PTMP 3 +#define OSPF_IT_VLINK 4 +#define OSPF_IT_UNDEF 5 + +/* OSPF interface states */ +#define OSPF_IS_DOWN 0 /* Not active */ +#define OSPF_IS_LOOP 1 /* Iface with no link */ +#define OSPF_IS_WAITING 2 /* Waiting for Wait timer */ +#define OSPF_IS_PTP 3 /* PTP operational */ +#define OSPF_IS_DROTHER 4 /* I'm on BCAST or NBMA and I'm not DR */ +#define OSPF_IS_BACKUP 5 /* I'm BDR */ +#define OSPF_IS_DR 6 /* I'm DR */ struct ospf_iface @@ -197,14 +198,10 @@ struct ospf_iface transmit a Link State Update Packet over this interface. LSAs contained in the update */ u16 helloint; /* number of seconds between hello sending */ - -#ifdef OSPFv2 list *passwords; u16 autype; u32 csn; /* Last used crypt seq number */ bird_clock_t csn_use; /* Last time when packet with that CSN was sent */ -#endif - ip_addr all_routers; /* */ ip_addr drip; /* Designated router */ ip_addr bdrip; /* Backup DR */ @@ -212,33 +209,15 @@ struct ospf_iface u32 bdrid; s16 rt_pos_beg; /* Position of iface in Router-LSA, begin, inclusive */ s16 rt_pos_end; /* Position of iface in Router-LSA, end, exclusive */ - -#ifdef OSPFv3 s16 px_pos_beg; /* Position of iface in Rt Prefix-LSA, begin, inclusive */ s16 px_pos_end; /* Position of iface in Rt Prefix-LSA, end, exclusive */ - u32 dr_iface_id; /* if drid is valid, this is iface_id of DR (for connecting network) */ u8 instance_id; /* Used to differentiate between more OSPF instances on one interface */ -#endif - - u8 type; /* OSPF view of type */ -#define OSPF_IT_BCAST 0 -#define OSPF_IT_NBMA 1 -#define OSPF_IT_PTP 2 -#define OSPF_IT_PTMP 3 -#define OSPF_IT_VLINK 4 -#define OSPF_IT_UNDEF 5 + u8 type; /* OSPF view of type (OSPF_IT_*) */ u8 strictnbma; /* Can I talk with unknown neighbors? */ u8 stub; /* Inactive interface */ - u8 state; /* Interface state machine */ -#define OSPF_IS_DOWN 0 /* Not working */ -#define OSPF_IS_LOOP 1 /* Iface with no link */ -#define OSPF_IS_WAITING 2 /* Waiting for Wait timer */ -#define OSPF_IS_PTP 3 /* PTP operational */ -#define OSPF_IS_DROTHER 4 /* I'm on BCAST or NBMA and I'm not DR */ -#define OSPF_IS_BACKUP 5 /* I'm BDR */ -#define OSPF_IS_DR 6 /* I'm DR */ + u8 state; /* Interface state machine (OSPF_IS_*) */ timer *wait_timer; /* WAIT timer */ timer *hello_timer; /* HELLOINT timer */ timer *poll_timer; /* Poll Interval - for NBMA */ @@ -255,11 +234,9 @@ struct ospf_iface struct top_hash_entry *net_lsa; /* Originated network LSA */ int orignet; /* Schedule network LSA origination */ -#ifdef OSPFv3 int origlink; /* Schedule link LSA origination */ struct top_hash_entry *link_lsa; /* Originated link LSA */ struct top_hash_entry *pxn_lsa; /* Originated prefix LSA */ -#endif int fadj; /* Number of full adjacent neigh */ list nbma_list; u8 priority; /* A router priority for DR election */ @@ -290,57 +267,30 @@ union ospf_auth /* Packet types */ -#define HELLO_P 1 /* Hello */ -#define DBDES_P 2 /* Database description */ -#define LSREQ_P 3 /* Link state request */ -#define LSUPD_P 4 /* Link state update */ -#define LSACK_P 5 /* Link state acknowledgement */ +#define HELLO_P 1 /* Hello */ +#define DBDES_P 2 /* Database description */ +#define LSREQ_P 3 /* Link state request */ +#define LSUPD_P 4 /* Link state update */ +#define LSACK_P 5 /* Link state acknowledgement */ /* Area IDs */ -#define BACKBONE 0 - - -struct immsb -{ -#ifdef CPU_BIG_ENDIAN - u8 padding:5; - u8 i:1; - u8 m:1; - u8 ms:1; -#else - u8 ms:1; - u8 m:1; - u8 i:1; - u8 padding:5; -#endif -}; +#define BACKBONE 0 -union imms -{ - u8 byte; - struct immsb bit; -}; -#define DBDES_MS 1 -#define DBDES_M 2 -#define DBDES_I 4 +#define DBDES_I 4 /* Init bit */ +#define DBDES_M 2 /* More bit */ +#define DBDES_MS 1 /* Master/Slave bit */ +#define DBDES_IMMS (DBDES_I | DBDES_M | DBDES_MS) -#ifdef OSPFv2 -struct ospf_packet -{ - u8 version; - u8 type; - u16 length; - u32 routerid; - u32 areaid; - u16 checksum; - u16 autype; - union ospf_auth u; -}; -#else /* OSPFv3 packet descriptions */ +/* + * There is slight difference in OSPF packet header between v2 and v3 + * in vdep field. For OSPFv2, vdep is u16 authentication type and + * ospf_header is followed by union ospf_auth. For OSPFv3, higher byte + * of vdep is instance ID and lower byte is zero. + */ struct ospf_packet { @@ -350,41 +300,19 @@ struct ospf_packet u32 routerid; u32 areaid; u16 checksum; - u8 instance_id; - u8 zero; + u16 vdep; }; -#endif - - - - -struct ospf_lsa_header -{ - u16 age; /* LS Age */ -#define LSA_MAXAGE 3600 /* 1 hour */ -#define LSA_CHECKAGE 300 /* 5 minutes */ -#define LSA_MAXAGEDIFF 900 /* 15 minutes */ - -#ifdef OSPFv2 - u8 options; - u8 type; - +// XXXX +/* #define LSA_T_RT 1 #define LSA_T_NET 2 #define LSA_T_SUM_NET 3 #define LSA_T_SUM_RT 4 #define LSA_T_EXT 5 #define LSA_T_NSSA 7 - -#define LSA_SCOPE_AREA 0x2000 -#define LSA_SCOPE_AS 0x4000 - -#define LSA_SCOPE(lsa) (((lsa)->type == LSA_T_EXT) ? LSA_SCOPE_AS : LSA_SCOPE_AREA) - -#else /* OSPFv3 */ - u16 type; +*/ #define LSA_T_RT 0x2001 #define LSA_T_NET 0x2002 @@ -402,91 +330,76 @@ struct ospf_lsa_header #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(lsa) ((lsa)->type & LSA_SCOPE_MASK) -#endif + +#define LSA_MAXAGE 3600 /* 1 hour */ +#define LSA_CHECKAGE 300 /* 5 minutes */ +#define LSA_MAXAGEDIFF 900 /* 15 minutes */ + +#define LSA_INITSEQNO ((s32) 0x80000001) +#define LSA_MAXSEQNO ((s32) 0x7fffffff) + + +#define LSART_PTP 1 +#define LSART_NET 2 +#define LSART_STUB 3 +#define LSART_VLNK 4 + +#define LSA_SUM2_TOS 0xFF000000 + +#define LSA_EXT2_TOS 0x7F000000 +#define LSA_EXT2_EBIT 0x80000000 + +#define LSA_EXT3_EBIT 0x4000000 +#define LSA_EXT3_FBIT 0x2000000 +#define LSA_EXT3_TBIT 0x1000000 + +// XXXX remove +#define LSA_EXT_EBIT 0x4000000 + + +struct ospf_lsa_header +{ + u16 age; /* LS Age */ + u16 type_raw; /* Type, mixed with options on OSPFv2 */ u32 id; u32 rt; /* Advertising router */ s32 sn; /* LS Sequence number */ -#define LSA_INITSEQNO ((s32) 0x80000001) -#define LSA_MAXSEQNO ((s32) 0x7fffffff) u16 checksum; u16 length; }; +/* In OSPFv2, options are embedded in higher half of type_raw */ +static inline u8 lsa_get_options(struct ospf_lsa_header *lsa) +{ return lsa->type_raw >> 8; } -#define LSART_PTP 1 -#define LSART_NET 2 -#define LSART_STUB 3 -#define LSART_VLNK 4 +static inline void lsa_set_options(struct ospf_lsa_header *lsa, u16 options) +{ lsa->type_raw = (lsa->type_raw & 0xff) | (options << 8); } -#ifdef OSPFv2 - struct ospf_lsa_rt { -#ifdef CPU_BIG_ENDIAN - u16 options; /* VEB flags only */ - u16 links; -#else - u16 links; - u16 options; /* VEB flags only */ -#endif + u32 options; /* VEB flags, mixed with link count for OSPFv2 and options for OSPFv3 */ }; -struct ospf_lsa_rt_link +struct ospf_lsa_rt2_link { u32 id; u32 data; #ifdef CPU_BIG_ENDIAN u8 type; - u8 padding; + u8 no_tos; u16 metric; #else u16 metric; - u8 padding; + u8 no_tos; u8 type; #endif }; -struct ospf_lsa_net -{ - ip_addr netmask; - u32 routers[]; -}; - -struct ospf_lsa_sum -{ - ip_addr netmask; - u32 metric; -}; - -struct ospf_lsa_ext -{ - ip_addr netmask; - u32 metric; - ip_addr fwaddr; - u32 tag; -}; - -#define LSA_SUM_TOS 0xFF000000 -#define LSA_EXT_TOS 0x7F000000 -#define LSA_EXT_EBIT 0x80000000 - -/* Endianity swap for lsa->type */ -#define ntoht(x) x -#define htont(x) x - - -#else /* OSPFv3 */ - -struct ospf_lsa_rt -{ - u32 options; -}; - -struct ospf_lsa_rt_link +struct ospf_lsa_rt3_link { #ifdef CPU_BIG_ENDIAN u8 type; @@ -502,35 +415,58 @@ struct ospf_lsa_rt_link u32 id; /* Neighbor router ID */ }; + struct ospf_lsa_net { - u32 options; + u32 optx; /* Netmask for OSPFv2, options for OSPFv3 */ u32 routers[]; }; -struct ospf_lsa_sum_net +struct ospf_lsa_sum2 +{ + ip4_addr netmask; + u32 metric; +}; + +struct ospf_lsa_sum3_net { u32 metric; u32 prefix[]; }; -struct ospf_lsa_sum_rt +struct ospf_lsa_sum3_rt { u32 options; u32 metric; u32 drid; }; -struct ospf_lsa_ext +struct ospf_lsa_ext2 +{ + ip4_addr netmask; + u32 metric; + ip4_addr fwaddr; + u32 tag; +}; + +struct ospf_lsa_ext3 { u32 metric; u32 rest[]; }; +struct ospf_lsa_ext_local +{ + ip_addr ip, fwaddr; + int pxlen; + u32 metric, ebit, fbit, tag, propagate; + u8 pxopts; +}; + struct ospf_lsa_link { u32 options; - ip_addr lladdr; + ip6_addr lladdr; u32 pxcount; u32 rest[]; }; @@ -549,9 +485,21 @@ struct ospf_lsa_prefix u32 rest[]; }; -#define LSA_EXT_EBIT 0x4000000 -#define LSA_EXT_FBIT 0x2000000 -#define LSA_EXT_TBIT 0x1000000 + + + +#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) @@ -562,12 +510,6 @@ struct ospf_lsa_prefix #define METRIC_MASK 0x00FFFFFF #define OPTIONS_MASK 0x00FFFFFF -static inline unsigned -lsa_rt_count(struct ospf_lsa_header *lsa) -{ - return (lsa->length - sizeof(struct ospf_lsa_header) - sizeof(struct ospf_lsa_rt)) - / sizeof(struct ospf_lsa_rt_link); -} static inline unsigned lsa_net_count(struct ospf_lsa_header *lsa) @@ -672,10 +614,11 @@ struct ospf_neighbor #define NEIGHBOR_LOADING 6 #define NEIGHBOR_FULL 7 timer *inactim; /* Inactivity timer */ - union imms imms; /* I, M, Master/slave received */ + u8 imms; /* I, M, Master/slave received */ + u8 myimms; /* I, M Master/slave */ u32 dds; /* DD Sequence number being sent */ u32 ddr; /* last Dat Des packet received */ - union imms myimms; /* I, M Master/slave */ + u32 rid; /* Router ID */ ip_addr ip; /* IP of it's interface */ u8 priority; /* Priority */ @@ -686,10 +629,7 @@ struct ospf_neighbor we use the same type to simplify handling */ u32 dr; /* Neigbour's idea of DR */ u32 bdr; /* Neigbour's idea of BDR */ - -#ifdef OSPFv3 u32 iface_id; /* ID of Neighbour's iface connected to common network */ -#endif siterator dbsi; /* Database summary list iterator */ slist lsrql; /* Link state request */ @@ -808,14 +748,8 @@ struct ospf_iface_patt u8 check_link; u8 ecmp_weight; u8 real_bcast; /* Not really used in OSPFv3 */ - -#ifdef OSPFv2 list *passwords; -#endif - -#ifdef OSPFv3 u8 instance_id; -#endif }; int ospf_import_control(struct proto *p, rte **new, ea_list **attrs, @@ -826,6 +760,14 @@ void schedule_rt_lsa(struct ospf_area *oa); void schedule_rtcalc(struct proto_ospf *po); void schedule_net_lsa(struct ospf_iface *ifa); +static inline int ospf_is_v2(struct proto_ospf *po) +{ return 0; } // XXXX fixme +static inline int ospf_is_v3(struct proto_ospf *po) +{ return 1; } // XXXX fixme + +static inline void lsa_fix_options(struct proto_ospf *po, struct ospf_lsa_header *lsa, u8 options) +{ if (ospf_is_v2(po)) lsa_set_options(lsa, options); } + struct ospf_area *ospf_find_area(struct proto_ospf *po, u32 aid); static inline struct ospf_area *ospf_main_area(struct proto_ospf *po) { return (po->areano == 1) ? HEAD(po->area_list) : po->backbone; } @@ -838,11 +780,8 @@ static inline int oa_is_nssa(struct ospf_area *oa) { return oa->options & OPT_N; } -#ifdef OSPFv3 -void schedule_link_lsa(struct ospf_iface *ifa); -#else -static inline void schedule_link_lsa(struct ospf_iface *ifa UNUSED) {} -#endif + +void schedule_link_lsa(struct ospf_iface *ifa); // XXXX caller ?? void ospf_sh_neigh(struct proto *p, char *iff); void ospf_sh(struct proto *p); diff --git a/proto/ospf/packet.c b/proto/ospf/packet.c index 241a58f73..f42f6a10b 100644 --- a/proto/ospf/packet.c +++ b/proto/ospf/packet.c @@ -439,7 +439,7 @@ ospf_rx_hook(sock *sk, int size) struct ospf_neighbor *n = find_neigh(ifa, rid); #endif - if(!n && (ps->type != HELLO_P)) + if (!n && (ps->type != HELLO_P)) { log(L_WARN "OSPF: Received non-hello packet from unknown neighbor (src %I, iface %s)", sk->faddr, ifa->iface->name); diff --git a/proto/ospf/rt.c b/proto/ospf/rt.c index 4ef8f416d..40de6561e 100644 --- a/proto/ospf/rt.c +++ b/proto/ospf/rt.c @@ -18,7 +18,7 @@ static void rt_sync(struct proto_ospf *po); #ifdef OSPFv2 #define ipa_from_rid(x) _MI(x) #else /* OSPFv3 */ -#define ipa_from_rid(x) _MI(0,0,0,x) +#define ipa_from_rid(x) _MI6(0,0,0,x) #endif @@ -249,7 +249,6 @@ rt_pos_to_ifa(struct ospf_area *oa, int pos) return NULL; } -#ifdef OSPFv3 static inline struct ospf_iface * px_pos_to_ifa(struct ospf_area *oa, int pos) { @@ -259,12 +258,13 @@ px_pos_to_ifa(struct ospf_area *oa, int pos) return ifa; return NULL; } -#endif static void add_network(struct ospf_area *oa, ip_addr px, int pxlen, int metric, struct top_hash_entry *en, int pos) { + struct proto_ospf *po = oa->po; + orta nf = { .type = RTS_OSPF, .options = 0, @@ -279,7 +279,7 @@ add_network(struct ospf_area *oa, ip_addr px, int pxlen, int metric, struct top_ if (pxlen < 0 || pxlen > MAX_PREFIX_LENGTH) { log(L_WARN "%s: Invalid prefix in LSA (Type: %04x, Id: %R, Rt: %R)", - oa->po->proto.name, en->lsa.type, en->lsa.id, en->lsa.rt); + po->proto.name, en->lsa_type, en->lsa.id, en->lsa.rt); return; } @@ -294,21 +294,115 @@ add_network(struct ospf_area *oa, ip_addr px, int pxlen, int metric, struct top_ */ struct ospf_iface *ifa; -#ifdef OSPFv2 - ifa = rt_pos_to_ifa(oa, pos); -#else /* OSPFv3 */ - ifa = px_pos_to_ifa(oa, pos); -#endif + ifa = ospf_is_v2(po) ? rt_pos_to_ifa(oa, pos) : px_pos_to_ifa(oa, pos); + nf.nhs = ifa ? new_nexthop(po, IPA_NONE, ifa->iface, ifa->ecmp_weight) : NULL; + } + + ri_install_net(po, px, pxlen, &nf); +} + + + +static inline void +spfa_process_rt(struct ospf_area *oa, struct top_hash_entry *act) +{ + struct proto_ospf *po = oa->po; + struct ospf_lsa_rt *rt = act->lsa_body; + struct ospf_lsa_rt_walk rtl; + struct top_hash_entry *tmp; + ip_addr prefix; + int pxlen; + + if (rt->options & OPT_RT_V) + oa->trcap = 1; - nf.nhs = ifa ? new_nexthop(oa->po, IPA_NONE, ifa->iface, ifa->ecmp_weight) : NULL; + /* + * In OSPFv3, all routers are added to per-area routing + * tables. But we use it just for ASBRs and ABRs. For the + * purpose of the last step in SPF - prefix-LSA processing in + * spfa_process_prefixes(), we use information stored in LSA db. + */ + if (((rt->options & OPT_RT_E) || (rt->options & OPT_RT_B)) + && (act->lsa.rt != po->router_id)) + { + orta nf = { + .type = RTS_OSPF, + .options = rt->options, + .metric1 = act->dist, + .metric2 = LSINFINITY, + .tag = 0, + .rid = act->lsa.rt, + .oa = oa, + .nhs = act->nhs + }; + ri_install_rt(oa, act->lsa.rt, &nf); } - ri_install_net(oa->po, px, pxlen, &nf); + /* Now process Rt links */ + lsa_walk_rt_init(po, act, &rtl); + while (lsa_walk_rt(&rtl)) + { + tmp = NULL; + + switch (rtl.type) + { + case LSART_STUB: + + /* Should not happen, LSART_STUB is not defined in OSPFv3 */ + if (ospf_is_v3(po)) + break; + + /* + * RFC 2328 in 16.1. (2a) says to handle stub networks in an + * second phase after the SPF for an area is calculated. We get + * the same result by handing them here because add_network() + * will keep the best (not the first) found route. + */ + prefix = ipa_from_u32(rtl.id & rtl.data); + pxlen = u32_masklen(rtl.data); + add_network(oa, prefix, pxlen, act->dist + rtl.metric, act, i); + break; + + case LSART_NET: + tmp = ospf_hash_find_net(po->gr, oa->areaid, rtl.id, rtl.nif); + break; + + case LSART_VLNK: + case LSART_PTP: + tmp = ospf_hash_find_rt(po->gr, oa->areaid, rtl.id); + break; + } + + add_cand(&oa->cand, tmp, act, act->dist + rtl.metric, oa, i); + } } -#ifdef OSPFv3 -static void -process_prefixes(struct ospf_area *oa) +static inline void +spfa_process_net(struct ospf_area *oa, struct top_hash_entry *act) +{ + struct proto_ospf *po = oa->po; + struct ospf_lsa_net *ln = act->lsa_body; + struct top_hash_entry *tmp; + ip_addr prefix; + int pxlen, i, cnt; + + if (ospf_is_v2(po)) + { + prefix = ipa_from_u32(act->lsa.id & ln->optx); + pxlen = u32_masklen(ln->optx); + add_network(oa, prefix, pxlen, act->dist, act, -1); + } + + cnt = lsa_net_count(&act->lsa); + for (i = 0; i < cnt; i++) + { + tmp = ospf_hash_find_rt(po->gr, oa->areaid, ln->routers[i]); + add_cand(&oa->cand, tmp, act, act->dist, oa, -1); + } +} + +static inline void +spfa_process_prefixes(struct ospf_area *oa) { struct proto_ospf *po = oa->po; // struct proto *p = &po->proto; @@ -323,7 +417,7 @@ process_prefixes(struct ospf_area *oa) WALK_SLIST(en, po->lsal) { - if (en->lsa.type != LSA_T_PREFIX) + if (en->lsa_type != LSA_T_PREFIX) continue; if (en->domain != oa->areaid) @@ -347,7 +441,7 @@ process_prefixes(struct ospf_area *oa) if (src->color != INSPF) continue; - if ((src->lsa.type != LSA_T_RT) && (src->lsa.type != LSA_T_NET)) + if ((src->lsa_type != LSA_T_RT) && (src->lsa_type != LSA_T_NET)) continue; buf = px->rest; @@ -366,80 +460,14 @@ process_prefixes(struct ospf_area *oa) } } } -#endif - - -static void -ospf_rt_spfa_rtlinks(struct ospf_area *oa, struct top_hash_entry *act, struct top_hash_entry *en) -{ - // struct proto *p = &oa->po->proto; - struct proto_ospf *po = oa->po; - ip_addr prefix UNUSED; - int pxlen UNUSED, i; - - struct ospf_lsa_rt *rt = en->lsa_body; - struct ospf_lsa_rt_link *rr = (struct ospf_lsa_rt_link *) (rt + 1); - - for (i = 0; i < lsa_rt_count(&en->lsa); i++) - { - struct ospf_lsa_rt_link *rtl = rr + i; - struct top_hash_entry *tmp = NULL; - - DBG(" Working on link: %R (type: %u) ", rtl->id, rtl->type); - switch (rtl->type) - { -#ifdef OSPFv2 - case LSART_STUB: - /* - * RFC 2328 in 16.1. (2a) says to handle stub networks in an - * second phase after the SPF for an area is calculated. We get - * the same result by handing them here because add_network() - * will keep the best (not the first) found route. - */ - prefix = ipa_from_u32(rtl->id & rtl->data); - pxlen = ipa_mklen(ipa_from_u32(rtl->data)); - add_network(oa, prefix, pxlen, act->dist + rtl->metric, act, i); - break; -#endif - - case LSART_NET: -#ifdef OSPFv2 - /* In OSPFv2, rtl->id is IP addres of DR, Router ID is not known */ - tmp = ospf_hash_find_net(po->gr, oa->areaid, rtl->id); -#else /* OSPFv3 */ - tmp = ospf_hash_find(po->gr, oa->areaid, rtl->nif, rtl->id, LSA_T_NET); -#endif - break; - - case LSART_VLNK: - case LSART_PTP: - tmp = ospf_hash_find_rt(po->gr, oa->areaid, rtl->id); - break; - - default: - log("Unknown link type in router lsa. (rid = %R)", act->lsa.id); - break; - } - - if (tmp) - DBG("Going to add cand, Mydist: %u, Req: %u\n", - tmp->dist, act->dist + rtl->metric); - add_cand(&oa->cand, tmp, act, act->dist + rtl->metric, oa, i); - } -} /* RFC 2328 16.1. calculating shortest paths for an area */ static void ospf_rt_spfa(struct ospf_area *oa) { - struct proto *p = &oa->po->proto; struct proto_ospf *po = oa->po; - struct ospf_lsa_rt *rt; - struct ospf_lsa_net *ln; - struct top_hash_entry *act, *tmp; - ip_addr prefix UNUSED; - int pxlen UNUSED; - u32 i, *rts; + struct proto *p = &po->proto; + struct top_hash_entry *act; node *n; if (oa->rt == NULL) @@ -457,7 +485,7 @@ ospf_rt_spfa(struct ospf_area *oa) oa->rt->color = CANDIDATE; add_head(&oa->cand, &oa->rt->cn); DBG("RT LSA: rt: %R, id: %R, type: %u\n", - oa->rt->lsa.rt, oa->rt->lsa.id, oa->rt->lsa.type); + oa->rt->lsa.rt, oa->rt->lsa.id, oa->rt->lsa_type); while (!EMPTY_LIST(oa->cand)) { @@ -466,85 +494,37 @@ ospf_rt_spfa(struct ospf_area *oa) rem_node(n); DBG("Working on LSA: rt: %R, id: %R, type: %u\n", - act->lsa.rt, act->lsa.id, act->lsa.type); + act->lsa.rt, act->lsa.id, act->lsa_type); act->color = INSPF; - switch (act->lsa.type) + switch (act->lsa_type) { case LSA_T_RT: - rt = (struct ospf_lsa_rt *) act->lsa_body; - if (rt->options & OPT_RT_V) - oa->trcap = 1; - - /* - * In OSPFv3, all routers are added to per-area routing - * tables. But we use it just for ASBRs and ABRs. For the - * purpose of the last step in SPF - prefix-LSA processing in - * process_prefixes(), we use information stored in LSA db. - */ - if (((rt->options & OPT_RT_E) || (rt->options & OPT_RT_B)) - && (act->lsa.rt != po->router_id)) - { - orta nf = { - .type = RTS_OSPF, - .options = rt->options, - .metric1 = act->dist, - .metric2 = LSINFINITY, - .tag = 0, - .rid = act->lsa.rt, - .oa = oa, - .nhs = act->nhs - }; - ri_install_rt(oa, act->lsa.rt, &nf); - } - -#ifdef OSPFv2 - ospf_rt_spfa_rtlinks(oa, act, act); -#else /* OSPFv3 */ - for (tmp = ospf_hash_find_rt_first(po->gr, act->domain, act->lsa.rt); - tmp; tmp = ospf_hash_find_rt_next(tmp)) - ospf_rt_spfa_rtlinks(oa, act, tmp); -#endif - + spfa_process_rt(oa, act); break; - case LSA_T_NET: - ln = act->lsa_body; -#ifdef OSPFv2 - prefix = ipa_and(ipa_from_u32(act->lsa.id), ln->netmask); - pxlen = ipa_mklen(ln->netmask); - add_network(oa, prefix, pxlen, act->dist, act, -1); -#endif - - rts = (u32 *) (ln + 1); - for (i = 0; i < lsa_net_count(&act->lsa); i++) - { - DBG(" Working on router %R ", rts[i]); - tmp = ospf_hash_find_rt(po->gr, oa->areaid, rts[i]); - if (tmp != NULL) - DBG("Found :-)\n"); - else - DBG("Not found!\n"); - add_cand(&oa->cand, tmp, act, act->dist, oa, -1); - } + case LSA_T_NET: + spfa_process_net(oa, act); break; + + default: + log(L_WARN "%s: Unknown LSA type in SPF: %d", p->name, act->lsa_type); } } -#ifdef OSPFv3 - process_prefixes(oa); -#endif + if (ospf_is_v3(po)) + spfa_process_prefixes(oa); } static int link_back(struct ospf_area *oa, struct top_hash_entry *en, struct top_hash_entry *par) { - u32 i, *rts; - struct ospf_lsa_net *ln; - struct ospf_lsa_rt *rt; - struct ospf_lsa_rt_link *rtl, *rr; - struct top_hash_entry *tmp; struct proto_ospf *po = oa->po; + struct proto *p = &po->proto; + struct ospf_lsa_rt_walk rtl; + struct top_hash_entry *tmp; + struct ospf_lsa_net *ln; + u32 i, cnt; if (!en || !par) return 0; @@ -559,65 +539,56 @@ link_back(struct ospf_area *oa, struct top_hash_entry *en, struct top_hash_entry it is set in process_prefixes() to any global addres in the area */ en->lb = IPA_NONE; -#ifdef OSPFv3 en->lb_id = 0; -#endif - switch (en->lsa.type) + + switch (en->lsa_type) { case LSA_T_RT: - rt = (struct ospf_lsa_rt *) en->lsa_body; - rr = (struct ospf_lsa_rt_link *) (rt + 1); - for (i = 0; i < lsa_rt_count(&en->lsa); i++) + lsa_walk_rt_init(po, en, &rtl); + while (lsa_walk_rt(&rtl)) { - rtl = (rr + i); - switch (rtl->type) + switch (rtl.type) { case LSART_STUB: break; + case LSART_NET: -#ifdef OSPFv2 - /* In OSPFv2, rtl->id is IP addres of DR, Router ID is not known */ - tmp = ospf_hash_find_net(po->gr, oa->areaid, rtl->id); -#else /* OSPFv3 */ - tmp = ospf_hash_find(po->gr, oa->areaid, rtl->nif, rtl->id, LSA_T_NET); -#endif + tmp = ospf_hash_find_net(po->gr, oa->areaid, rtl.id, rtl.nif); if (tmp == par) { -#ifdef OSPFv2 - en->lb = ipa_from_u32(rtl->data); -#else /* OSPFv3 */ - en->lb_id = rtl->lif; -#endif + if (ospf_is_v2(po)) + en->lb = ipa_from_u32(rtl.data); + else + en->lb_id = rtl.lif; + return 1; } - break; + case LSART_VLNK: case LSART_PTP: /* Not necessary the same link, see RFC 2328 [23] */ - tmp = ospf_hash_find_rt(po->gr, oa->areaid, rtl->id); + tmp = ospf_hash_find_rt(po->gr, oa->areaid, rtl.id); if (tmp == par) return 1; - - break; - default: - log(L_WARN "Unknown link type in router lsa. (rid = %R)", en->lsa.rt); break; } } break; + case LSA_T_NET: ln = en->lsa_body; - rts = (u32 *) (ln + 1); - for (i = 0; i < lsa_net_count(&en->lsa); i++) + cnt = lsa_net_count(&en->lsa); + for (i = 0; i < cnt; i++) { - tmp = ospf_hash_find_rt(po->gr, oa->areaid, rts[i]); + tmp = ospf_hash_find_rt(po->gr, oa->areaid, ln->routers[i]); if (tmp == par) return 1; } break; + default: - bug("Unknown lsa type %x.", en->lsa.type); + log(L_WARN "%s: Unknown LSA type in SPF: %d", p->name, en->lsa_type); } return 0; } @@ -630,17 +601,18 @@ ospf_rt_sum(struct ospf_area *oa) struct proto_ospf *po = oa->po; struct proto *p = &po->proto; struct top_hash_entry *en; - ip_addr ip = IPA_NONE; - u32 dst_rid = 0; - u32 metric, options; + ip_addr ip, abrip; + u32 dst_rid, metric, options; ort *abr; int pxlen = -1, type = -1; + u8 pxopts; + OSPF_TRACE(D_EVENTS, "Starting routing table calculation for inter-area (area %R)", oa->areaid); WALK_SLIST(en, po->lsal) { - if ((en->lsa.type != LSA_T_SUM_RT) && (en->lsa.type != LSA_T_SUM_NET)) + if ((en->lsa_type != LSA_T_SUM_RT) && (en->lsa_type != LSA_T_SUM_NET)) continue; if (en->domain != oa->areaid) @@ -656,50 +628,31 @@ ospf_rt_sum(struct ospf_area *oa) /* 16.2. (3) is handled later in ospf_rt_abr() by resetting such rt entry */ - if (en->lsa.type == LSA_T_SUM_NET) + if (en->lsa_type == LSA_T_SUM_NET) { -#ifdef OSPFv2 - struct ospf_lsa_sum *ls = en->lsa_body; - ip = ipa_and(ipa_from_u32(en->lsa.id), ls->netmask); - pxlen = ipa_mklen(ls->netmask); -#else /* OSPFv3 */ - u8 pxopts; - u16 rest; - struct ospf_lsa_sum_net *ls = en->lsa_body; - lsa_get_ipv6_prefix(ls->prefix, &ip, &pxlen, &pxopts, &rest); + lsa_parse_sum_net(en, ospf_is_v2(po), &ip, &pxlen, &pxopts, &metric); if (pxopts & OPT_PX_NU) continue; -#endif if (pxlen < 0 || pxlen > MAX_PREFIX_LENGTH) { log(L_WARN "%s: Invalid prefix in LSA (Type: %04x, Id: %R, Rt: %R)", - p->name, en->lsa.type, en->lsa.id, en->lsa.rt); + p->name, en->lsa_type, en->lsa.id, en->lsa.rt); continue; } - metric = ls->metric & METRIC_MASK; options = 0; type = ORT_NET; } else /* LSA_T_SUM_RT */ { -#ifdef OSPFv2 - struct ospf_lsa_sum *ls = en->lsa_body; - dst_rid = en->lsa.id; - options = 0; -#else /* OSPFv3 */ - struct ospf_lsa_sum_rt *ls = en->lsa_body; - dst_rid = ls->drid; - options = ls->options & OPTIONS_MASK; -#endif + lsa_parse_sum_rt(en, ospf_is_v2(po), &dst_rid, &metric, &options); /* We don't want local router in ASBR routing table */ if (dst_rid == po->router_id) continue; - metric = ls->metric & METRIC_MASK; options |= ORTA_ASBR; type = ORT_ROUTER; } @@ -709,7 +662,7 @@ ospf_rt_sum(struct ospf_area *oa) continue; /* 16.2. (4) */ - ip_addr abrip = ipa_from_rid(en->lsa.rt); + abrip = ipa_from_rid(en->lsa.rt); abr = (ort *) fib_find(&oa->rtr, &abrip, MAX_PREFIX_LENGTH); if (!abr || !abr->n.type) continue; @@ -744,20 +697,23 @@ ospf_rt_sum(struct ospf_area *oa) static void ospf_rt_sum_tr(struct ospf_area *oa) { - struct proto *p = &oa->po->proto; struct proto_ospf *po = oa->po; + struct proto *p = &po->proto; struct ospf_area *bb = po->backbone; - ip_addr abrip; struct top_hash_entry *en; - u32 dst_rid, metric; - ort *re = NULL, *abr; + ort *re, *abr; + ip_addr ip, abrip; + u32 dst_rid, metric, options; + int pxlen; + u8 pxopts; - if (!bb) return; + if (!bb) + return; WALK_SLIST(en, po->lsal) { - if ((en->lsa.type != LSA_T_SUM_RT) && (en->lsa.type != LSA_T_SUM_NET)) + if ((en->lsa_type != LSA_T_SUM_RT) && (en->lsa_type != LSA_T_SUM_NET)) continue; if (en->domain != oa->areaid) @@ -771,46 +727,27 @@ ospf_rt_sum_tr(struct ospf_area *oa) if (en->lsa.rt == po->router_id) continue; - if (en->lsa.type == LSA_T_SUM_NET) + if (en->lsa_type == LSA_T_SUM_NET) { - ip_addr ip; - int pxlen; -#ifdef OSPFv2 - struct ospf_lsa_sum *ls = en->lsa_body; - ip = ipa_and(ipa_from_u32(en->lsa.id), ls->netmask); - pxlen = ipa_mklen(ls->netmask); -#else /* OSPFv3 */ - u8 pxopts; - u16 rest; - struct ospf_lsa_sum_net *ls = en->lsa_body; - lsa_get_ipv6_prefix(ls->prefix, &ip, &pxlen, &pxopts, &rest); + lsa_parse_sum_net(en, ospf_is_v2(po), &ip, &pxlen, &pxopts, &metric); if (pxopts & OPT_PX_NU) continue; -#endif if (pxlen < 0 || pxlen > MAX_PREFIX_LENGTH) { log(L_WARN "%s: Invalid prefix in LSA (Type: %04x, Id: %R, Rt: %R)", - p->name, en->lsa.type, en->lsa.id, en->lsa.rt); + p->name, en->lsa_type, en->lsa.id, en->lsa.rt); continue; } - metric = ls->metric & METRIC_MASK; re = fib_find(&po->rtf, &ip, pxlen); } - else // en->lsa.type == LSA_T_SUM_RT + else // en->lsa_type == LSA_T_SUM_RT { -#ifdef OSPFv2 - struct ospf_lsa_sum *ls = en->lsa_body; - dst_rid = en->lsa.id; -#else /* OSPFv3 */ - struct ospf_lsa_sum_rt *ls = en->lsa_body; - dst_rid = ls->drid; -#endif + lsa_parse_sum_rt(en, ospf_is_v2(po), &dst_rid, &metric, &options); - metric = ls->metric & METRIC_MASK; - ip_addr ip = ipa_from_rid(dst_rid); + ip = ipa_from_rid(dst_rid); re = fib_find(&bb->rtr, &ip, MAX_PREFIX_LENGTH); } @@ -979,11 +916,11 @@ check_sum_rt_lsa(struct proto_ospf *po, ort *nf) } static inline int -decide_nssa_lsa(ort *nf, u32 *rt_metric, ip_addr *rt_fwaddr, u32 *rt_tag) +decide_nssa_lsa(struct proto_ospf *po, ort *nf, u32 *rt_metric, ip_addr *rt_fwaddr, u32 *rt_tag) { struct ospf_area *oa = nf->n.oa; struct top_hash_entry *en = nf->n.en; - int propagate; + struct ospf_lsa_ext_local rt; if (!rt_is_nssa(nf) || !oa->translate) return 0; @@ -992,42 +929,21 @@ decide_nssa_lsa(ort *nf, u32 *rt_metric, ip_addr *rt_fwaddr, u32 *rt_tag) if (fib_route(&oa->enet_fib, &nf->fn.prefix, nf->fn.pxlen)) return 0; - if (!en || (en->lsa.type != LSA_T_NSSA)) + if (!en || (en->lsa_type != LSA_T_NSSA)) return 0; /* We do not store needed data in struct orta, we have to parse the LSA */ - struct ospf_lsa_ext *le = en->lsa_body; - -#ifdef OSPFv2 - *rt_fwaddr = le->fwaddr; - *rt_tag = le->tag; - propagate = en->lsa.options & OPT_P; -#else /* OSPFv3 */ - u32 *buf = le->rest; - u8 pxlen = (*buf >> 24); - u8 pxopts = (*buf >> 16); - buf += IPV6_PREFIX_WORDS(pxlen); /* Skip the IP prefix */ - - if (pxopts & OPT_PX_NU) + lsa_parse_ext(en, ospf_is_v2(po), &rt); + + if (rt.pxopts & OPT_PX_NU) return 0; - if (le->metric & LSA_EXT_FBIT) - buf = lsa_get_ipv6_addr(buf, rt_fwaddr); - else - *rt_fwaddr = IPA_NONE; - - if (le->metric & LSA_EXT_TBIT) - *rt_tag = *buf++; - else - *rt_tag = 0; - - propagate = pxopts & OPT_PX_P; -#endif - - if (!propagate || ipa_zero(*rt_fwaddr)) + if (!rt.propagate || ipa_zero(rt.fwaddr)) return 0; - *rt_metric = le->metric & (METRIC_MASK | LSA_EXT_EBIT); + *rt_metric = rt.metric | rt.ebit; + *rt_fwaddr = rt.fwaddr; + *rt_tag = rt.tag; return 1; } @@ -1062,7 +978,7 @@ check_nssa_lsa(struct proto_ospf *po, ort *nf) originate_ext_lsa(po->backbone, fn, EXT_NSSA, anet->metric, IPA_NONE, anet->tag, 0); /* RFC 3103 3.2 (2) - originate the same network */ - else if (decide_nssa_lsa(nf, &rt_metric, &rt_fwaddr, &rt_tag)) + else if (decide_nssa_lsa(po, nf, &rt_metric, &rt_fwaddr, &rt_tag)) originate_ext_lsa(po->backbone, fn, EXT_NSSA, rt_metric, rt_fwaddr, rt_tag, 0); else if (fn->flags & OSPF_RT_NSSA) @@ -1073,8 +989,6 @@ check_nssa_lsa(struct proto_ospf *po, ort *nf) static void ospf_check_vlinks(struct proto_ospf *po) { - struct proto *p = &po->proto; - struct ospf_iface *iface; WALK_LIST(iface, po->iface_list) { @@ -1358,14 +1272,13 @@ ospf_fib_route(struct fib *f, ip_addr a, int len) static void ospf_ext_spf(struct proto_ospf *po) { + struct proto *p = &po->proto; + struct top_hash_entry *en; + struct ospf_lsa_ext_local rt; ort *nf1, *nf2; orta nfa; - struct top_hash_entry *en; - struct proto *p = &po->proto; - struct ospf_lsa_ext *le; - int pxlen, ebit, rt_fwaddr_valid, rt_propagate; - ip_addr ip, rtid, rt_fwaddr; - u32 br_metric, rt_metric, rt_tag; + ip_addr rtid; + u32 br_metric; struct ospf_area *atmp; struct mpnh* nhs = NULL; @@ -1374,7 +1287,7 @@ ospf_ext_spf(struct proto_ospf *po) WALK_SLIST(en, po->lsal) { /* 16.4. (1) */ - if ((en->lsa.type != LSA_T_EXT) && (en->lsa.type != LSA_T_NSSA)) + if ((en->lsa_type != LSA_T_EXT) && (en->lsa_type != LSA_T_NSSA)) continue; if (en->lsa.age == LSA_MAXAGE) @@ -1385,50 +1298,20 @@ ospf_ext_spf(struct proto_ospf *po) continue; DBG("%s: Working on LSA. ID: %R, RT: %R, Type: %u\n", - p->name, en->lsa.id, en->lsa.rt, en->lsa.type); - - le = en->lsa_body; + p->name, en->lsa.id, en->lsa.rt, en->lsa_type); - rt_metric = le->metric & METRIC_MASK; - ebit = le->metric & LSA_EXT_EBIT; + lsa_parse_ext(en, ospf_is_v2(po), &rt); - if (rt_metric == LSINFINITY) + if (rt.metric == LSINFINITY) continue; -#ifdef OSPFv2 - ip = ipa_and(ipa_from_u32(en->lsa.id), le->netmask); - pxlen = ipa_mklen(le->netmask); - rt_fwaddr = le->fwaddr; - rt_fwaddr_valid = !ipa_equal(rt_fwaddr, IPA_NONE); - rt_tag = le->tag; - rt_propagate = en->lsa.options & OPT_P; -#else /* OSPFv3 */ - u8 pxopts; - u16 rest; - u32 *buf = le->rest; - buf = lsa_get_ipv6_prefix(buf, &ip, &pxlen, &pxopts, &rest); - - if (pxopts & OPT_PX_NU) + if (rt.pxopts & OPT_PX_NU) continue; - rt_fwaddr_valid = le->metric & LSA_EXT_FBIT; - if (rt_fwaddr_valid) - buf = lsa_get_ipv6_addr(buf, &rt_fwaddr); - else - rt_fwaddr = IPA_NONE; - - if (le->metric & LSA_EXT_TBIT) - rt_tag = *buf++; - else - rt_tag = 0; - - rt_propagate = pxopts & OPT_PX_P; -#endif - - if (pxlen < 0 || pxlen > MAX_PREFIX_LENGTH) + if (rt.pxlen < 0 || rt.pxlen > MAX_PREFIX_LENGTH) { log(L_WARN "%s: Invalid prefix in LSA (Type: %04x, Id: %R, Rt: %R)", - p->name, en->lsa.type, en->lsa.id, en->lsa.rt); + p->name, en->lsa_type, en->lsa.id, en->lsa.rt); continue; } @@ -1437,7 +1320,7 @@ ospf_ext_spf(struct proto_ospf *po) /* If there are more areas, we already precomputed preferred ASBR entries in ospf_rt_abr1() and stored them in the backbone table. For NSSA, we examine the area to which the LSA is assigned */ - if (en->lsa.type == LSA_T_EXT) + if (en->lsa_type == LSA_T_EXT) atmp = ospf_main_area(po); else /* NSSA */ atmp = ospf_find_area(po, en->domain); @@ -1456,11 +1339,11 @@ ospf_ext_spf(struct proto_ospf *po) /* 16.4. (3) NSSA - special rule for default routes */ /* ABR should use default only if P-bit is set and summaries are active */ - if ((en->lsa.type == LSA_T_NSSA) && ipa_zero(ip) && (pxlen == 0) && - (po->areano > 1) && !(rt_propagate && atmp->ac->summary)) + if ((en->lsa_type == LSA_T_NSSA) && ipa_zero(rt.ip) && (rt.pxlen == 0) && + (po->areano > 1) && !(rt.propagate && atmp->ac->summary)) continue; - if (!rt_fwaddr_valid) + if (!rt.fbit) { nf2 = nf1; nhs = nf1->n.nhs; @@ -1468,11 +1351,11 @@ ospf_ext_spf(struct proto_ospf *po) } else { - nf2 = ospf_fib_route(&po->rtf, rt_fwaddr, MAX_PREFIX_LENGTH); + nf2 = ospf_fib_route(&po->rtf, rt.fwaddr, MAX_PREFIX_LENGTH); if (!nf2) continue; - if (en->lsa.type == LSA_T_EXT) + if (en->lsa_type == LSA_T_EXT) { /* For ext routes, we accept intra-area or inter-area routes */ if ((nf2->n.type != RTS_OSPF) && (nf2->n.type != RTS_OSPF_IA)) @@ -1492,20 +1375,20 @@ ospf_ext_spf(struct proto_ospf *po) nhs = nf2->n.nhs; /* If gw is zero, it is a device route */ if (ipa_zero(nhs->gw)) - nhs = new_nexthop(po, rt_fwaddr, nhs->iface, nhs->weight); + nhs = new_nexthop(po, rt.fwaddr, nhs->iface, nhs->weight); br_metric = nf2->n.metric1; } - if (ebit) + if (rt.ebit) { nfa.type = RTS_OSPF_EXT2; nfa.metric1 = br_metric; - nfa.metric2 = rt_metric; + nfa.metric2 = rt.metric; } else { nfa.type = RTS_OSPF_EXT1; - nfa.metric1 = br_metric + rt_metric; + nfa.metric1 = br_metric + rt.metric; nfa.metric2 = LSINFINITY; } @@ -1514,21 +1397,21 @@ ospf_ext_spf(struct proto_ospf *po) /* Whether the route is preferred in route selection according to 16.4.1 */ nfa.options = epath_preferred(&nf2->n) ? ORTA_PREF : 0; - if (en->lsa.type == LSA_T_NSSA) + if (en->lsa_type == LSA_T_NSSA) { nfa.options |= ORTA_NSSA; - if (rt_propagate) + if (rt.propagate) nfa.options |= ORTA_PROP; } - nfa.tag = rt_tag; + nfa.tag = rt.tag; nfa.rid = en->lsa.rt; nfa.oa = atmp; /* undefined in RFC 2328 */ nfa.voa = NULL; nfa.nhs = nhs; nfa.en = en; /* store LSA for later (NSSA processing) */ - ri_install_ext(po, ip, pxlen, &nfa); + ri_install_ext(po, rt.ip, rt.pxlen, &nfa); } } @@ -1602,7 +1485,6 @@ ospf_rt_reset(struct proto_ospf *po) void ospf_rt_spf(struct proto_ospf *po) { - struct proto *p = &po->proto; struct ospf_area *oa; if (po->areano == 0) @@ -1660,7 +1542,7 @@ calc_next_hop(struct ospf_area *oa, struct top_hash_entry *en, /* 16.1.1. The next hop calculation */ DBG(" Next hop calculating for id: %R rt: %R type: %u\n", - en->lsa.id, en->lsa.rt, en->lsa.type); + en->lsa.id, en->lsa.rt, en->lsa_type); /* Usually, we inherit parent nexthops */ if (inherit_nexthops(pn)) @@ -1674,7 +1556,7 @@ calc_next_hop(struct ospf_area *oa, struct top_hash_entry *en, */ /* The first case - local network */ - if ((en->lsa.type == LSA_T_NET) && (par == oa->rt)) + if ((en->lsa_type == LSA_T_NET) && (par == oa->rt)) { ifa = rt_pos_to_ifa(oa, pos); if (!ifa) @@ -1684,7 +1566,7 @@ calc_next_hop(struct ospf_area *oa, struct top_hash_entry *en, } /* The second case - ptp or ptmp neighbor */ - if ((en->lsa.type == LSA_T_RT) && (par == oa->rt)) + if ((en->lsa_type == LSA_T_RT) && (par == oa->rt)) { ifa = rt_pos_to_ifa(oa, pos); if (!ifa) @@ -1701,40 +1583,42 @@ calc_next_hop(struct ospf_area *oa, struct top_hash_entry *en, } /* The third case - bcast or nbma neighbor */ - if ((en->lsa.type == LSA_T_RT) && (par->lsa.type == LSA_T_NET)) + if ((en->lsa_type == LSA_T_RT) && (par->lsa_type == LSA_T_NET)) { /* par->nhi should be defined from parent's calc_next_hop() */ if (!pn) goto bad; -#ifdef OSPFv2 - /* - * In this case, next-hop is the same as link-back, which is - * already computed in link_back(). - */ - if (ipa_zero(en->lb)) - goto bad; - - return new_nexthop(po, en->lb, pn->iface, pn->weight); + if (ospf_is_v2(po)) + { + /* + * In this case, next-hop is the same as link-back, which is + * already computed in link_back(). + */ + if (ipa_zero(en->lb)) + goto bad; -#else /* OSPFv3 */ - /* - * Next-hop is taken from lladdr field of Link-LSA, en->lb_id - * is computed in link_back(). - */ - struct top_hash_entry *lhe; - lhe = ospf_hash_find(po->gr, pn->iface->index, en->lb_id, rid, LSA_T_LINK); + return new_nexthop(po, en->lb, pn->iface, pn->weight); + } + else /* OSPFv3 */ + { + /* + * Next-hop is taken from lladdr field of Link-LSA, en->lb_id + * is computed in link_back(). + */ + struct top_hash_entry *lhe; + lhe = ospf_hash_find(po->gr, pn->iface->index, en->lb_id, rid, LSA_T_LINK); - if (!lhe) - return NULL; + if (!lhe) + return NULL; - struct ospf_lsa_link *llsa = lhe->lsa_body; + struct ospf_lsa_link *llsa = lhe->lsa_body; - if (ipa_zero(llsa->lladdr)) - return NULL; + if (ipa_zero(llsa->lladdr)) + return NULL; - return new_nexthop(po, llsa->lladdr, pn->iface, pn->weight); -#endif + return new_nexthop(po, llsa->lladdr, pn->iface, pn->weight); + } } bad: @@ -1835,14 +1719,13 @@ add_cand(list * l, struct top_hash_entry *en, struct top_hash_entry *par, if (en->lsa.age == LSA_MAXAGE) return; -#ifdef OSPFv3 - if (en->lsa.type == LSA_T_RT) + if (ospf_is_v3(po) && (en->lsa_type == LSA_T_RT)) { + /* In OSPFv3, check V6 and R flags */ struct ospf_lsa_rt *rt = en->lsa_body; if (!(rt->options & OPT_V6) || !(rt->options & OPT_R)) return; } -#endif /* 16.1. (2c) */ if (en->color == INSPF) @@ -1860,7 +1743,7 @@ add_cand(list * l, struct top_hash_entry *en, struct top_hash_entry *par, if (!nhs) { log(L_WARN "Cannot find next hop for LSA (Type: %04x, Id: %R, Rt: %R)", - en->lsa.type, en->lsa.id, en->lsa.rt); + en->lsa_type, en->lsa.id, en->lsa.rt); return; } @@ -1892,7 +1775,7 @@ add_cand(list * l, struct top_hash_entry *en, struct top_hash_entry *par, } DBG(" Adding candidate: rt: %R, id: %R, type: %u\n", - en->lsa.rt, en->lsa.id, en->lsa.type); + en->lsa.rt, en->lsa.id, en->lsa_type); if (en->color == CANDIDATE) { /* We found a shorter path */ @@ -1915,7 +1798,7 @@ add_cand(list * l, struct top_hash_entry *en, struct top_hash_entry *par, { act = SKIP_BACK(struct top_hash_entry, cn, n); if ((act->dist > dist) || - ((act->dist == dist) && (act->lsa.type == LSA_T_RT))) + ((act->dist == dist) && (act->lsa_type == LSA_T_RT))) { if (prev == NULL) add_head(l, &en->cn); diff --git a/proto/ospf/topology.c b/proto/ospf/topology.c index 9ae620fbc..7e625493f 100644 --- a/proto/ospf/topology.c +++ b/proto/ospf/topology.c @@ -146,7 +146,7 @@ get_seqnum(struct top_hash_entry *en) if (en->lsa.sn == LSA_MAXSEQNO) { log(L_WARN "OSPF: Premature origination of LSA (Type: %04x, Id: %R, Rt: %R)", - en->lsa.type, en->lsa.id, en->lsa.rt); + en->lsa_type, en->lsa.id, en->lsa.rt); return LSA_INITSEQNO; } @@ -154,6 +154,11 @@ get_seqnum(struct top_hash_entry *en) } +/* + * Router-LSA handling + * Type = LSA_T_RT + */ + static int configured_stubnet(struct ospf_area *oa, struct ifa *a) { @@ -201,34 +206,48 @@ bcast_net_active(struct ospf_iface *ifa) return 0; } +static inline u32 +get_rt_options(struct proto_ospf *po, struct ospf_area *oa, int bitv) +{ + u32 opts = 0; -#ifdef OSPFv2 + if (po->areano > 1) + opts |= OPT_RT_B; + + if ((po->areano > 1) && oa_is_nssa(oa) && oa->ac->translator) + opts |= OPT_RT_NT; + + if (po->ebit && !oa_is_stub(oa)) + opts |= OPT_RT_E; + + if (bitv) + opts |= OPT_RT_V; + + return opts; +} + +static inline void +add_rt2_lsa_link(struct proto_ospf *po, u8 type, u32 id, u32 data, u16 metric) +{ + struct ospf_lsa_rt2_link *ln = lsab_alloc(po, sizeof(struct ospf_lsa_rt2_link)); + ln->type = type; + ln->id = id; + ln->data = data; + ln->metric = metric; + ln->no_tos = 0; +} static void * -originate_rt_lsa_body(struct ospf_area *oa, u16 *length) +originate_rt2_lsa_body(struct ospf_area *oa, u16 *length) { struct proto_ospf *po = oa->po; struct ospf_iface *ifa; int i = 0, bitv = 0; - struct ospf_lsa_rt *rt; - struct ospf_lsa_rt_link *ln; struct ospf_neighbor *neigh; ASSERT(po->lsab_used == 0); - rt = lsab_allocz(po, sizeof(struct ospf_lsa_rt)); - - rt->options = 0; - - if (po->areano > 1) - rt->options |= OPT_RT_B; - - if ((po->areano > 1) && oa_is_nssa(oa) && oa->ac->translator) - rt->options |= OPT_RT_NT; - - if (po->ebit && !oa_is_stub(oa)) - rt->options |= OPT_RT_E; - - rt = NULL; /* buffer might be reallocated later */ + lsab_allocz(po, sizeof(struct ospf_lsa_rt)); + /* ospf_lsa_rt header will be filled later */ WALK_LIST(ifa, po->iface_list) { @@ -255,13 +274,8 @@ originate_rt_lsa_body(struct ospf_area *oa, u16 *length) WALK_LIST(neigh, ifa->neigh_list) if (neigh->state == NEIGHBOR_FULL) { - ln = lsab_alloc(po, sizeof(struct ospf_lsa_rt_link)); - ln->type = LSART_PTP; - ln->id = neigh->rid; - ln->data = (ifa->addr->flags & IA_PEER) ? - ifa->iface->index : ipa_to_u32(ifa->addr->ip); - ln->metric = ifa->cost; - ln->padding = 0; + u32 data = (ifa->addr->flags & IA_PEER) ? ifa->iface->index : ipa_to_u32(ifa->addr->ip); + add_rt2_lsa_link(po, LSART_PTP, neigh->rid, data, ifa->cost); i++; } break; @@ -270,12 +284,7 @@ originate_rt_lsa_body(struct ospf_area *oa, u16 *length) case OSPF_IT_NBMA: if (bcast_net_active(ifa)) { - ln = lsab_alloc(po, sizeof(struct ospf_lsa_rt_link)); - ln->type = LSART_NET; - ln->id = ipa_to_u32(ifa->drip); - ln->data = ipa_to_u32(ifa->addr->ip); - ln->metric = ifa->cost; - ln->padding = 0; + add_rt2_lsa_link(po, LSART_NET, ipa_to_u32(ifa->drip), ipa_to_u32(ifa->addr->ip), ifa->cost); i++; net_lsa = 1; } @@ -284,15 +293,7 @@ originate_rt_lsa_body(struct ospf_area *oa, u16 *length) case OSPF_IT_VLINK: neigh = (struct ospf_neighbor *) HEAD(ifa->neigh_list); if ((!EMPTY_LIST(ifa->neigh_list)) && (neigh->state == NEIGHBOR_FULL) && (ifa->cost <= 0xffff)) - { - ln = lsab_alloc(po, sizeof(struct ospf_lsa_rt_link)); - ln->type = LSART_VLNK; - ln->id = neigh->rid; - ln->data = ipa_to_u32(ifa->addr->ip); - ln->metric = ifa->cost; - ln->padding = 0; - i++; - } + add_rt2_lsa_link(po, LSART_VLNK, neigh->rid, ipa_to_u32(ifa->addr->ip), ifa->cost), i++; break; default: @@ -309,62 +310,36 @@ originate_rt_lsa_body(struct ospf_area *oa, u16 *length) configured_stubnet(oa, ifa->addr)) continue; - ln = lsab_alloc(po, sizeof(struct ospf_lsa_rt_link)); + /* Host or network stub entry */ if ((ifa->addr->flags & IA_HOST) || (ifa->state == OSPF_IS_LOOP) || (ifa->type == OSPF_IT_PTMP)) - { - /* Host stub entry */ - ln->type = LSART_STUB; - ln->id = ipa_to_u32(ifa->addr->ip); - ln->data = 0xffffffff; - ln->metric = 0; - ln->padding = 0; - } + add_rt2_lsa_link(po, LSART_STUB, ipa_to_u32(ifa->addr->ip), 0xffffffff, 0); else - { - /* Network stub entry */ - ln->type = LSART_STUB; - ln->id = ipa_to_u32(ifa->addr->prefix); - ln->data = ipa_to_u32(ipa_mkmask(ifa->addr->pxlen)); - ln->metric = ifa->cost; - ln->padding = 0; - } + add_rt2_lsa_link(po, LSART_STUB, ipa_to_u32(ifa->addr->prefix), u32_mkmask(ifa->addr->pxlen), ifa->cost); i++; ifa->rt_pos_end = i; } struct ospf_stubnet_config *sn; - if (oa->ac) + if (oa->ac) // XXXX ??? WALK_LIST(sn, oa->ac->stubnet_list) if (!sn->hidden) - { - ln = lsab_alloc(po, sizeof(struct ospf_lsa_rt_link)); - ln->type = LSART_STUB; - ln->id = ipa_to_u32(sn->px.addr); - ln->data = ipa_to_u32(ipa_mkmask(sn->px.len)); - ln->metric = sn->cost; - ln->padding = 0; - i++; - } - - rt = po->lsab; - rt->links = i; + add_rt2_lsa_link(po, LSART_STUB, ipa_to_u32(sn->px.addr), u32_mkmask(sn->px.len), sn->cost), i++; - if (bitv) - rt->options |= OPT_RT_V; + struct ospf_lsa_rt *rt = po->lsab; + /* Store number of links in lower half of options */ + rt->options = get_rt_options(po, oa, bitv) | (u16) i; - *length = po->lsab_used + sizeof(struct ospf_lsa_header); + *length = sizeof(struct ospf_lsa_header) + po->lsab_used; return lsab_flush(po); } -#else /* OSPFv3 */ - -static void -add_lsa_rt_link(struct proto_ospf *po, struct ospf_iface *ifa, u8 type, u32 nif, u32 id) +static inline void +add_rt3_lsa_link(struct proto_ospf *po, u8 type, struct ospf_iface *ifa, u32 nif, u32 id) { - struct ospf_lsa_rt_link *ln = lsab_alloc(po, sizeof(struct ospf_lsa_rt_link)); + struct ospf_lsa_rt3_link *ln = lsab_alloc(po, sizeof(struct ospf_lsa_rt3_link)); ln->type = type; ln->padding = 0; ln->metric = ifa->cost; @@ -374,30 +349,17 @@ add_lsa_rt_link(struct proto_ospf *po, struct ospf_iface *ifa, u8 type, u32 nif, } static void * -originate_rt_lsa_body(struct ospf_area *oa, u16 *length) +originate_rt3_lsa_body(struct ospf_area *oa, u16 *length) { struct proto_ospf *po = oa->po; struct ospf_iface *ifa; + struct ospf_neighbor *neigh; int bitv = 0; int i = 0; - struct ospf_lsa_rt *rt; - struct ospf_neighbor *neigh; ASSERT(po->lsab_used == 0); - rt = lsab_allocz(po, sizeof(struct ospf_lsa_rt)); - - rt->options = oa->options & OPTIONS_MASK; - - if (po->areano > 1) - rt->options |= OPT_RT_B; - - if ((po->areano > 1) && oa_is_nssa(oa) && oa->ac->translator) - rt->options |= OPT_RT_NT; - - if (po->ebit && !oa_is_stub(oa)) - rt->options |= OPT_RT_E; - - rt = NULL; /* buffer might be reallocated later */ + lsab_allocz(po, sizeof(struct ospf_lsa_rt)); + /* ospf_lsa_rt header will be filled later */ WALK_LIST(ifa, po->iface_list) { @@ -421,19 +383,19 @@ originate_rt_lsa_body(struct ospf_area *oa, u16 *length) case OSPF_IT_PTMP: WALK_LIST(neigh, ifa->neigh_list) if (neigh->state == NEIGHBOR_FULL) - add_lsa_rt_link(po, ifa, LSART_PTP, neigh->iface_id, neigh->rid), i++; + add_rt3_lsa_link(po, LSART_PTP, ifa, neigh->iface_id, neigh->rid), i++; break; case OSPF_IT_BCAST: case OSPF_IT_NBMA: if (bcast_net_active(ifa)) - add_lsa_rt_link(po, ifa, LSART_NET, ifa->dr_iface_id, ifa->drid), i++; + add_rt3_lsa_link(po, LSART_NET, ifa, ifa->dr_iface_id, ifa->drid), i++; break; case OSPF_IT_VLINK: neigh = (struct ospf_neighbor *) HEAD(ifa->neigh_list); if ((!EMPTY_LIST(ifa->neigh_list)) && (neigh->state == NEIGHBOR_FULL) && (ifa->cost <= 0xffff)) - add_lsa_rt_link(po, ifa, LSART_VLNK, neigh->iface_id, neigh->rid), i++; + add_rt3_lsa_link(po, LSART_VLNK, ifa, neigh->iface_id, neigh->rid), i++; break; default: @@ -444,17 +406,20 @@ originate_rt_lsa_body(struct ospf_area *oa, u16 *length) ifa->rt_pos_end = i; } - if (bitv) - { - rt = po->lsab; - rt->options |= OPT_RT_V; - } + struct ospf_lsa_rt *rt = po->lsab; + rt->options = get_rt_options(po, oa, bitv) | (oa->options & OPTIONS_MASK); *length = po->lsab_used + sizeof(struct ospf_lsa_header); return lsab_flush(po); } -#endif +static inline void * +originate_rt_lsa_body(struct proto_ospf *po, struct ospf_area *oa, u16 *length) +{ + return ospf_is_v2(po) ? + originate_rt2_lsa_body(oa, length) : + originate_rt3_lsa_body(oa, length); +} /** * originate_rt_lsa - build new instance of router LSA @@ -468,28 +433,21 @@ originate_rt_lsa_body(struct ospf_area *oa, u16 *length) void originate_rt_lsa(struct ospf_area *oa) { - struct ospf_lsa_header lsa; struct proto_ospf *po = oa->po; - struct proto *p = &po->proto; + struct ospf_lsa_header lsa; + u32 dom = oa->areaid; void *body; OSPF_TRACE(D_EVENTS, "Originating router-LSA for area %R", oa->areaid); lsa.age = 0; - lsa.type = LSA_T_RT; - -#ifdef OSPFv2 - lsa.options = oa->options; - lsa.id = po->router_id; -#else /* OSPFv3 */ - lsa.id = 0; -#endif - + lsa.type_raw = LSA_T_RT; + lsa.id = ospf_is_v2(po) ? po->router_id : 0; lsa.rt = po->router_id; lsa.sn = get_seqnum(oa->rt); - u32 dom = oa->areaid; + lsa_fix_options(po, &lsa, oa->options); - body = originate_rt_lsa_body(oa, &lsa.length); + body = originate_rt_lsa_body(po, oa, &lsa.length); lsasum_calculate(&lsa, body); oa->rt = lsa_install_new(po, &lsa, dom, body); ospf_lsupd_flood(po, NULL, NULL, &lsa, dom, 1); @@ -509,35 +467,58 @@ update_rt_lsa(struct ospf_area *oa) */ originate_rt_lsa(oa); -#ifdef OSPFv3 - originate_prefix_rt_lsa(oa); -#endif + if (ospf_is_v3(po)) + originate_prefix_rt_lsa(oa); schedule_rtcalc(po); oa->origrt = 0; } + +/* + * Net-LSA handling + * Type = LSA_T_NET + */ + static void * -originate_net_lsa_body(struct ospf_iface *ifa, u16 *length, - struct proto_ospf *po) +originate_net2_lsa_body(struct proto_ospf *po, struct ospf_iface *ifa, u16 *length) { - u16 i = 1; struct ospf_neighbor *n; - struct ospf_lsa_net *net; int nodes = ifa->fadj + 1; + int bsize = sizeof(struct ospf_lsa_net) + nodes * sizeof(u32); + u16 i = 1; - net = mb_alloc(po->proto.pool, sizeof(struct ospf_lsa_net) - + nodes * sizeof(u32)); + struct ospf_lsa_net *net = mb_alloc(po->proto.pool, bsize); + *length = sizeof(struct ospf_lsa_header) + bsize; -#ifdef OSPFv2 - net->netmask = ipa_mkmask(ifa->addr->pxlen); -#endif + net->optx = u32_mkmask(ifa->addr->pxlen); + net->routers[0] = po->router_id; -#ifdef OSPFv3 - /* In OSPFv3, we would like to merge options from Link LSAs of added neighbors */ + WALK_LIST(n, ifa->neigh_list) + { + if (n->state == NEIGHBOR_FULL) + { + net->routers[i] = n->rid; + i++; + } + } + ASSERT(i == nodes); + + return net; +} + +static void * +originate_net3_lsa_body(struct proto_ospf *po, struct ospf_iface *ifa, u16 *length) +{ struct top_hash_entry *en; + struct ospf_neighbor *n; + int nodes = ifa->fadj + 1; + int bsize = sizeof(struct ospf_lsa_net) + nodes * sizeof(u32); u32 options = 0; -#endif + u16 i = 1; + + struct ospf_lsa_net *net = mb_alloc(po->proto.pool, bsize); + *length = sizeof(struct ospf_lsa_header) + bsize; net->routers[0] = po->router_id; @@ -545,11 +526,10 @@ originate_net_lsa_body(struct ospf_iface *ifa, u16 *length, { if (n->state == NEIGHBOR_FULL) { -#ifdef OSPFv3 + /* In OSPFv3, we would like to merge options from Link LSAs of added neighbors */ en = ospf_hash_find(po->gr, ifa->iface->index, n->iface_id, n->rid, LSA_T_LINK); if (en) options |= ((struct ospf_lsa_link *) en->lsa_body)->options; -#endif net->routers[i] = n->rid; i++; @@ -557,15 +537,19 @@ originate_net_lsa_body(struct ospf_iface *ifa, u16 *length, } ASSERT(i == nodes); -#ifdef OSPFv3 - net->options = options & OPTIONS_MASK; -#endif + net->optx = options & OPTIONS_MASK; - *length = sizeof(struct ospf_lsa_header) + sizeof(struct ospf_lsa_net) - + nodes * sizeof(u32); return net; } +static inline void * +originate_net_lsa_body(struct proto_ospf *po, struct ospf_iface *ifa, u16 *length) +{ + return ospf_is_v2(po) ? + originate_net2_lsa_body(po, ifa, length) : + originate_net3_lsa_body(po, ifa, length); +} + /** * originate_net_lsa - originates of deletes network LSA @@ -580,29 +564,21 @@ void originate_net_lsa(struct ospf_iface *ifa) { struct proto_ospf *po = ifa->oa->po; - struct proto *p = &po->proto; struct ospf_lsa_header lsa; u32 dom = ifa->oa->areaid; - void *body; OSPF_TRACE(D_EVENTS, "Originating network-LSA for iface %s", ifa->iface->name); lsa.age = 0; - lsa.type = LSA_T_NET; - -#ifdef OSPFv2 - lsa.options = ifa->oa->options; - lsa.id = ipa_to_u32(ifa->addr->ip); -#else /* OSPFv3 */ - lsa.id = ifa->iface->index; -#endif - + lsa.type_raw = LSA_T_NET; + lsa.id = ospf_is_v2(po) ? ipa_to_u32(ifa->addr->ip) : ifa->iface->index; lsa.rt = po->router_id; lsa.sn = get_seqnum(ifa->net_lsa); + lsa_fix_options(po, &lsa, ifa->oa->options); - body = originate_net_lsa_body(ifa, &lsa.length, po); + body = originate_net_lsa_body(po, ifa, &lsa.length); lsasum_calculate(&lsa, body); ifa->net_lsa = lsa_install_new(po, &lsa, dom, body); ospf_lsupd_flood(po, NULL, NULL, &lsa, dom, 1); @@ -612,7 +588,6 @@ void flush_net_lsa(struct ospf_iface *ifa) { struct proto_ospf *po = ifa->oa->po; - struct proto *p = &po->proto; u32 dom = ifa->oa->areaid; if (ifa->net_lsa == NULL) @@ -620,6 +595,7 @@ flush_net_lsa(struct ospf_iface *ifa) OSPF_TRACE(D_EVENTS, "Flushing network-LSA for iface %s", ifa->iface->name); + ifa->net_lsa->lsa.sn += 1; ifa->net_lsa->lsa.age = LSA_MAXAGE; lsasum_calculate(&ifa->net_lsa->lsa, ifa->net_lsa->lsa_body); @@ -643,131 +619,150 @@ update_net_lsa(struct ospf_iface *ifa) if ((ifa->state != OSPF_IS_DR) || (ifa->fadj == 0)) { flush_net_lsa(ifa); -#ifdef OSPFv3 - flush_prefix_net_lsa(ifa); -#endif + if (ospf_is_v3(po)) + flush_prefix_net_lsa(ifa); } else { originate_net_lsa(ifa); -#ifdef OSPFv3 - originate_prefix_net_lsa(ifa); -#endif + if (ospf_is_v3(po)) + originate_prefix_net_lsa(ifa); } schedule_rtcalc(po); ifa->orignet = 0; } -#ifdef OSPFv2 + +/* + * (Net|Rt)-summary-LSA handling + * (a.k.a. Inter-Area-(Prefix|Router)-LSA) + * Type = LSA_T_SUM_NET, LSA_T_SUM_RT + */ static inline void * -originate_sum_lsa_body(struct proto_ospf *po, u16 *length, u32 mlen, u32 metric) +originate_sum2_lsa_body(struct proto_ospf *po, u16 *length, u32 mlen, u32 metric) { - struct ospf_lsa_sum *sum = mb_alloc(po->proto.pool, sizeof(struct ospf_lsa_sum)); - *length = sizeof(struct ospf_lsa_header) + sizeof(struct ospf_lsa_sum); + struct ospf_lsa_sum2 *sum = mb_alloc(po->proto.pool, sizeof(struct ospf_lsa_sum2)); + *length = sizeof(struct ospf_lsa_header) + sizeof(struct ospf_lsa_sum2); - sum->netmask = ipa_mkmask(mlen); + sum->netmask = ip4_mkmask(mlen); sum->metric = metric; return sum; } -#define originate_sum_net_lsa_body(po,length,fn,metric) \ - originate_sum_lsa_body(po, length, (fn)->pxlen, metric) +static inline void * +originate_sum3_net_lsa_body(struct proto_ospf *po, u16 *length, struct fib_node *fn, u32 metric) +{ + int bsize = sizeof(struct ospf_lsa_sum3_net) + IPV6_PREFIX_SPACE(fn->pxlen); + struct ospf_lsa_sum3_net *sum = mb_alloc(po->proto.pool, bsize); + *length = sizeof(struct ospf_lsa_header) + bsize; -#define originate_sum_rt_lsa_body(po,length,drid,metric,options) \ - originate_sum_lsa_body(po, length, 0, metric) + sum->metric = metric; + put_ipv6_prefix(sum->prefix, fn->prefix, fn->pxlen, 0, 0); -static inline int -check_sum_net_lsaid_collision(struct fib_node *fn, struct top_hash_entry *en) -{ - struct ospf_lsa_sum *sum = en->lsa_body; - return fn->pxlen != ipa_mklen(sum->netmask); + return sum; } -static inline int -check_sum_lsa_same(struct top_hash_entry *en, u32 metric) +static inline void * +originate_sum3_rt_lsa_body(struct proto_ospf *po, u16 *length, u32 drid, u32 metric, u32 options) { - /* Netmask already checked in check_sum_net_lsaid_collision() */ - struct ospf_lsa_sum *sum = en->lsa_body; - return (en->lsa.sn != LSA_MAXSEQNO) && (sum->metric == metric); -} - -#define check_sum_net_lsa_same(en,metric) \ - check_sum_lsa_same(en, metric) - -#define check_sum_rt_lsa_same(en,drid,metric,options) \ - check_sum_lsa_same(en, metric) + struct ospf_lsa_sum3_rt *sum = mb_alloc(po->proto.pool, sizeof(struct ospf_lsa_sum3_rt)); + *length = sizeof(struct ospf_lsa_header) + sizeof(struct ospf_lsa_sum3_rt); + sum->options = options; + sum->metric = metric; + sum->drid = drid; -#else /* OSPFv3 */ + return sum; +} static inline void * originate_sum_net_lsa_body(struct proto_ospf *po, u16 *length, struct fib_node *fn, u32 metric) { - int size = sizeof(struct ospf_lsa_sum_net) + IPV6_PREFIX_SPACE(fn->pxlen); - struct ospf_lsa_sum_net *sum = mb_alloc(po->proto.pool, size); - *length = sizeof(struct ospf_lsa_header) + size; + return ospf_is_v2(po) ? + originate_sum2_lsa_body(po, length, fn->pxlen, metric) : + originate_sum3_net_lsa_body(po, length, fn, metric); +} - sum->metric = metric; - put_ipv6_prefix(sum->prefix, fn->prefix, fn->pxlen, 0, 0); +static inline void * +originate_sum_rt_lsa_body(struct proto_ospf *po, u16 *length, u32 drid, u32 metric, u32 options) +{ + return ospf_is_v2(po) ? + originate_sum2_lsa_body(po, length, 0, metric) : + originate_sum3_rt_lsa_body(po, length, drid, metric, options); +} - return sum; + +static inline int +check_sum2_net_lsa(struct top_hash_entry *en, struct fib_node *fn, u32 metric) +{ + struct ospf_lsa_sum2 *sum = en->lsa_body; + + /* LSAID collision */ + if (fn->pxlen != ip4_masklen(sum->netmask)) + return -1; + + return (en->lsa.sn != LSA_MAXSEQNO) && (sum->metric == metric); } static inline int -check_sum_net_lsaid_collision(struct fib_node *fn, struct top_hash_entry *en) +check_sum3_net_lsa(struct top_hash_entry *en, struct fib_node *fn, u32 metric) { - struct ospf_lsa_sum_net *sum = en->lsa_body; - ip_addr prefix; + struct ospf_lsa_sum3_net *sum = en->lsa_body; + ip6_addr prefix; int pxlen; u8 pxopts; u16 rest; - lsa_get_ipv6_prefix(sum->prefix, &prefix, &pxlen, &pxopts, &rest); - return (fn->pxlen != pxlen) || !ipa_equal(fn->prefix, prefix); -} -static inline int -check_sum_net_lsa_same(struct top_hash_entry *en, u32 metric) -{ - /* Prefix already checked in check_sum_net_lsaid_collision() */ - struct ospf_lsa_sum_net *sum = en->lsa_body; + /* LSAID collision */ + if ((fn->pxlen != pxlen) || !ip6_equal(fn->prefix, prefix)) + return -1; + return (en->lsa.sn != LSA_MAXSEQNO) && (sum->metric == metric); } -static inline void * -originate_sum_rt_lsa_body(struct proto_ospf *po, u16 *length, u32 drid, u32 metric, u32 options) +static int +check_sum_net_lsa(struct proto_ospf *po, struct top_hash_entry *en, struct fib_node *fn, u32 metric) { - struct ospf_lsa_sum_rt *sum = mb_alloc(po->proto.pool, sizeof(struct ospf_lsa_sum_rt)); - *length = sizeof(struct ospf_lsa_header) + sizeof(struct ospf_lsa_sum_rt); + int rv = ospf_is_v2(po) ? + check_sum2_net_lsa(en, fn, metric) : + check_sum3_net_lsa(en, fn, metric); - sum->options = options; - sum->metric = metric; - sum->drid = drid; + if (rv < 0) + log(L_ERR "%s: LSAID collision for %I/%d", po->proto.name, fn->prefix, fn->pxlen); - return sum; + return rv; } -static inline int -check_sum_rt_lsa_same(struct top_hash_entry *en, u32 drid, u32 metric, u32 options) +static int +check_sum_rt_lsa(struct proto_ospf *po, struct top_hash_entry *en, u32 drid, u32 metric, u32 options) { - struct ospf_lsa_sum_rt *sum = en->lsa_body; - return (en->lsa.sn != LSA_MAXSEQNO) && (sum->options == options) && - (sum->metric == metric) && (sum->drid == drid); + if (en->lsa.sn == LSA_MAXSEQNO) + return 0; + + if (ospf_is_v2(po)) + { + struct ospf_lsa_sum2 *sum = en->lsa_body; + return (sum->metric == metric); + } + else + { + struct ospf_lsa_sum3_rt *sum = en->lsa_body; + return (sum->options == options) && (sum->metric == metric) && (sum->drid == drid); + } } -#endif void originate_sum_net_lsa(struct ospf_area *oa, struct fib_node *fn, int metric) { struct proto_ospf *po = oa->po; - struct proto *p = &po->proto; + struct ospf_lsa_header lsa; struct top_hash_entry *en; u32 dom = oa->areaid; - struct ospf_lsa_header lsa; void *body; OSPF_TRACE(D_EVENTS, "Originating net-summary-LSA for %I/%d (metric %d)", @@ -775,25 +770,14 @@ originate_sum_net_lsa(struct ospf_area *oa, struct fib_node *fn, int metric) /* options argument is used in ORT_NET and OSPFv3 only */ lsa.age = 0; -#ifdef OSPFv2 - lsa.options = oa->options; -#endif - lsa.type = LSA_T_SUM_NET; + lsa.type_raw = LSA_T_SUM_NET; lsa.id = fibnode_to_lsaid(po, fn); lsa.rt = po->router_id; + lsa_fix_options(po, &lsa, oa->options); - if ((en = ospf_hash_find_header(po->gr, dom, &lsa)) != NULL) - { - if (check_sum_net_lsaid_collision(fn, en)) - { - log(L_ERR "%s: LSAID collision for %I/%d", - p->name, fn->prefix, fn->pxlen); - return; - } - - if (check_sum_net_lsa_same(en, metric)) - return; - } + en = ospf_hash_find_header(po->gr, dom, &lsa); + if (en && check_sum_net_lsa(po, en, fn, metric)) + return; lsa.sn = get_seqnum(en); body = originate_sum_net_lsa_body(po, &lsa.length, fn, metric); @@ -803,37 +787,32 @@ originate_sum_net_lsa(struct ospf_area *oa, struct fib_node *fn, int metric) } void -originate_sum_rt_lsa(struct ospf_area *oa, struct fib_node *fn, int metric, u32 options UNUSED) +originate_sum_rt_lsa(struct ospf_area *oa, struct fib_node *fn, int metric, u32 options) { struct proto_ospf *po = oa->po; - struct proto *p = &po->proto; + struct ospf_lsa_header lsa; struct top_hash_entry *en; - u32 dom = oa->areaid; u32 rid = ipa_to_rid(fn->prefix); - struct ospf_lsa_header lsa; + u32 dom = oa->areaid; void *body; OSPF_TRACE(D_EVENTS, "Originating rt-summary-LSA for %R (metric %d)", rid, metric); lsa.age = 0; -#ifdef OSPFv2 - lsa.options = oa->options; -#endif - lsa.type = LSA_T_SUM_RT; - /* In OSPFv3, LSA ID is meaningless, but we still use Router ID of ASBR */ - lsa.id = rid; + lsa.type_raw = LSA_T_SUM_RT; + lsa.id = rid; /* In OSPFv3, LSA ID is meaningless, but we still use Router ID of ASBR */ lsa.rt = po->router_id; + lsa_fix_options(po, &lsa, oa->options); options &= OPTIONS_MASK; - if ((en = ospf_hash_find_header(po->gr, dom, &lsa)) != NULL) - { - if (check_sum_rt_lsa_same(en, lsa.id, metric, options)) - return; - } + + en = ospf_hash_find_header(po->gr, dom, &lsa); + if (en && check_sum_rt_lsa(po, en, rid, metric, options)) + return; lsa.sn = get_seqnum(en); - body = originate_sum_rt_lsa_body(po, &lsa.length, lsa.id, metric, options); + body = originate_sum_rt_lsa_body(po, &lsa.length, rid, metric, options); lsasum_calculate(&lsa, body); lsa_install_new(po, &lsa, dom, body); ospf_lsupd_flood(po, NULL, NULL, &lsa, dom, 1); @@ -843,101 +822,73 @@ void flush_sum_lsa(struct ospf_area *oa, struct fib_node *fn, int type) { struct proto_ospf *po = oa->po; - struct proto *p = &po->proto; - struct top_hash_entry *en; struct ospf_lsa_header lsa; + struct top_hash_entry *en; + u32 dom = oa->areaid; lsa.rt = po->router_id; if (type == ORT_NET) { lsa.id = fibnode_to_lsaid(po, fn); - lsa.type = LSA_T_SUM_NET; + lsa.type_raw = LSA_T_SUM_NET; } else { /* In OSPFv3, LSA ID is meaningless, but we still use Router ID of ASBR */ lsa.id = ipa_to_rid(fn->prefix); - lsa.type = LSA_T_SUM_RT; + lsa.type_raw = LSA_T_SUM_RT; } - if ((en = ospf_hash_find_header(po->gr, oa->areaid, &lsa)) != NULL) + en = ospf_hash_find_header(po->gr, dom, &lsa); + if (en) { - if ((type == ORT_NET) && check_sum_net_lsaid_collision(fn, en)) - { - log(L_ERR "%s: LSAID collision for %I/%d", - p->name, fn->prefix, fn->pxlen); - return; - } + OSPF_TRACE(D_EVENTS, "Flushing summary-LSA (id=%R, type=%d)", + en->lsa.id, en->lsa.type_raw); + + if ((type == ORT_NET) && (check_sum_net_lsa(po, en, fn, 0) < 0)) + return; struct ospf_lsa_sum *sum = en->lsa_body; en->lsa.age = LSA_MAXAGE; en->lsa.sn = LSA_MAXSEQNO; lsasum_calculate(&en->lsa, sum); - - OSPF_TRACE(D_EVENTS, "Flushing summary-LSA (id=%R, type=%d)", - en->lsa.id, en->lsa.type); - ospf_lsupd_flood(po, NULL, NULL, &en->lsa, oa->areaid, 1); + ospf_lsupd_flood(po, NULL, NULL, &en->lsa, dom, 1); if (can_flush_lsa(po)) flush_lsa(en, po); } } -#ifdef OSPFv2 + +/* + * AS-external-LSA and NSSA-LSA handling + * Type = LSA_T_EXT, LSA_T_NSSA + */ static inline void * -originate_ext_lsa_body(struct proto_ospf *po, u16 *length, struct fib_node *fn, - u32 metric, ip_addr fwaddr, u32 tag, int pbit UNUSED) +originate_ext2_lsa_body(struct proto_ospf *po, u16 *length, struct fib_node *fn, + u32 metric, ip_addr fwaddr, u32 tag) { - struct ospf_lsa_ext *ext = mb_alloc(po->proto.pool, sizeof(struct ospf_lsa_ext)); - *length = sizeof(struct ospf_lsa_header) + sizeof(struct ospf_lsa_ext); + struct ospf_lsa_ext2 *ext = mb_alloc(po->proto.pool, sizeof(struct ospf_lsa_ext2)); + *length = sizeof(struct ospf_lsa_header) + sizeof(struct ospf_lsa_ext2); ext->metric = metric; - ext->netmask = ipa_mkmask(fn->pxlen); - ext->fwaddr = fwaddr; + ext->netmask = ip4_mkmask(fn->pxlen); + ext->fwaddr = ipa_to_ip4(fwaddr); ext->tag = tag; return ext; } -/* - * check_ext_lsa() combines functions of check_*_lsaid_collision() and - * check_*_lsa_same(). 'en' is existing ext LSA, and rest parameters - * are parameters of new ext route. Function returns -1 if there is - * LSAID collision, returns 1 if the existing LSA is the same and - * returns 0 otherwise (in that case, we need to originate a new LSA). - * - * Really, checking for the same parameters is not as important as in - * summary LSA origination, because in most cases the duplicate - * external route propagation would be stopped by the nest. But there - * are still some cases (route reload, the same route propagated through - * different protocol) so it is also done here. - */ - -static inline int -check_ext_lsa(struct top_hash_entry *en, struct fib_node *fn, u32 metric, ip_addr fwaddr, u32 tag) -{ - struct ospf_lsa_ext *ext = en->lsa_body; - - /* LSAID collision */ - if (fn->pxlen != ipa_mklen(ext->netmask)) - return -1; - - return (en->lsa.sn != LSA_MAXSEQNO) && (ext->metric == metric) && - (ext->tag == tag) && ipa_equal(ext->fwaddr,fwaddr); -} - -#else /* OSPFv3 */ - static inline void * -originate_ext_lsa_body(struct proto_ospf *po, u16 *length, struct fib_node *fn, - u32 metric, ip_addr fwaddr, u32 tag, int pbit) +originate_ext3_lsa_body(struct proto_ospf *po, u16 *length, struct fib_node *fn, + u32 metric, ip_addr fwaddr, u32 tag, int pbit) { - int size = sizeof(struct ospf_lsa_ext) + int bsize = sizeof(struct ospf_lsa_ext3) + IPV6_PREFIX_SPACE(fn->pxlen) + (ipa_nonzero(fwaddr) ? 16 : 0) + (tag ? 4 : 0); - struct ospf_lsa_ext *ext = mb_alloc(po->proto.pool, size); - *length = sizeof(struct ospf_lsa_header) + size; + struct ospf_lsa_ext3 *ext = mb_alloc(po->proto.pool, bsize); + *length = sizeof(struct ospf_lsa_header) + bsize; ext->metric = metric; @@ -946,23 +897,60 @@ originate_ext_lsa_body(struct proto_ospf *po, u16 *length, struct fib_node *fn, if (ipa_nonzero(fwaddr)) { - ext->metric |= LSA_EXT_FBIT; + ext->metric |= LSA_EXT3_FBIT; buf = put_ipv6_addr(buf, fwaddr); } if (tag) { - ext->metric |= LSA_EXT_TBIT; + ext->metric |= LSA_EXT3_TBIT; *buf++ = tag; } return ext; } +static inline void * +originate_ext_lsa_body(struct proto_ospf *po, u16 *length, struct fib_node *fn, + u32 metric, ip_addr fwaddr, u32 tag, int pbit) +{ + return ospf_is_v2(po) ? + originate_ext2_lsa_body(po, length, fn, metric, fwaddr, tag) : + originate_ext3_lsa_body(po, length, fn, metric, fwaddr, tag, pbit); +} + + +/* + * check_ext_lsa() combines functions of check_*_lsaid_collision() and + * check_*_lsa_same(). 'en' is existing ext LSA, and rest parameters + * are parameters of new ext route. Function returns -1 if there is + * LSAID collision, returns 1 if the existing LSA is the same and + * returns 0 otherwise (in that case, we need to originate a new LSA). + * + * Really, checking for the same parameters is not as important as in + * summary LSA origination, because in most cases the duplicate + * external route propagation would be stopped by the nest. But there + * are still some cases (route reload, the same route propagated through + * different protocol) so it is also done here. + */ + +static inline int +check_ext2_lsa(struct top_hash_entry *en, struct fib_node *fn, u32 metric, ip_addr fwaddr, u32 tag) +{ + struct ospf_lsa_ext2 *ext = en->lsa_body; + + /* LSAID collision */ + if (fn->pxlen != ip4_masklen(ext->netmask)) + return -1; + + return (en->lsa.sn != LSA_MAXSEQNO) && (ext->metric == metric) && + (ext->tag == tag) && ip4_equal(ext->fwaddr, ipa_to_ip4(fwaddr)); +} + static inline int -check_ext_lsa(struct top_hash_entry *en, struct fib_node *fn, u32 metric, ip_addr fwaddr, u32 tag) +check_ext3_lsa(struct top_hash_entry *en, struct fib_node *fn, u32 metric, ip_addr fwaddr, u32 tag) { - struct ospf_lsa_ext *ext = en->lsa_body; + struct ospf_lsa_ext3 *ext = en->lsa_body; ip_addr prefix; int pxlen; u8 pxopts; @@ -981,17 +969,29 @@ check_ext_lsa(struct top_hash_entry *en, struct fib_node *fn, u32 metric, ip_add ip_addr rt_fwaddr = IPA_NONE; u32 rt_tag = 0; - if (ext->metric & LSA_EXT_FBIT) + if (ext->metric & LSA_EXT3_FBIT) buf = lsa_get_ipv6_addr(buf, &rt_fwaddr); - if (ext->metric & LSA_EXT_TBIT) + if (ext->metric & LSA_EXT3_TBIT) rt_tag = *buf++; return (rt_metric == metric) && ipa_equal(rt_fwaddr, fwaddr) && (rt_tag == tag); } +static int +check_ext_lsa(struct proto_ospf *po, struct top_hash_entry *en, struct fib_node *fn, + u32 metric, ip_addr fwaddr, u32 tag) +{ + int rv = ospf_is_v2(po) ? + check_ext2_lsa(en, fn, metric, fwaddr, tag) : + check_ext3_lsa(en, fn, metric, fwaddr, tag); + + if (rv < 0) + log(L_ERR "%s: LSAID collision for %I/%d", po->proto.name, fn->prefix, fn->pxlen); + + return rv; +} -#endif static inline ip_addr find_surrogate_fwaddr(struct ospf_area *oa) @@ -1046,7 +1046,7 @@ find_surrogate_fwaddr(struct ospf_area *oa) * @oa: ospf_area for which LSA is originated * @fn: network prefix and mask * @src: the source of origination of the LSA (EXT_EXPORT/EXT_NSSA) - * @metric: the metric of a route + * @metric: the metric of a route (possibly with appropriate E-bit) * @fwaddr: the forwarding address * @tag: the route tag * @pbit: P-bit for NSSA LSAs, ignored for external LSAs @@ -1067,21 +1067,19 @@ originate_ext_lsa(struct ospf_area *oa, struct fib_node *fn, int src, struct proto_ospf *po = oa->po; struct proto *p = &po->proto; struct ospf_lsa_header lsa; - struct top_hash_entry *en = NULL; - void *body; + struct top_hash_entry *en; int nssa = oa_is_nssa(oa); u32 dom = nssa ? oa->areaid : 0; + void *body; OSPF_TRACE(D_EVENTS, "Originating %s-LSA for %I/%d", nssa ? "NSSA" : "AS-external", fn->prefix, fn->pxlen); lsa.age = 0; -#ifdef OSPFv2 - lsa.options = nssa ? (pbit ? OPT_P : 0) : OPT_E; -#endif - lsa.type = nssa ? LSA_T_NSSA : LSA_T_EXT; + lsa.type_raw = nssa ? LSA_T_NSSA : LSA_T_EXT; lsa.id = fibnode_to_lsaid(po, fn); lsa.rt = po->router_id; + lsa_fix_options(po, &lsa, nssa ? (pbit ? OPT_P : 0) : OPT_E); if (nssa && pbit && ipa_zero(fwaddr)) { @@ -1096,19 +1094,9 @@ originate_ext_lsa(struct ospf_area *oa, struct fib_node *fn, int src, } } - if ((en = ospf_hash_find_header(po->gr, dom, &lsa)) != NULL) - { - int rv = check_ext_lsa(en, fn, metric, fwaddr, tag); - if (rv < 0) - { - log(L_ERR "%s: LSAID collision for %I/%d", - p->name, fn->prefix, fn->pxlen); - return; - } - - if (rv > 0) - return; - } + en = ospf_hash_find_header(po->gr, dom, &lsa); + if (en && check_ext_lsa(po, en, fn, metric, fwaddr, tag)) + return; lsa.sn = get_seqnum(en); body = originate_ext_lsa_body(po, &lsa.length, fn, metric, fwaddr, tag, pbit); @@ -1140,17 +1128,17 @@ flush_ext_lsa(struct ospf_area *oa, struct fib_node *fn, int src) struct proto *p = &po->proto; struct top_hash_entry *en; int nssa = oa_is_nssa(oa); - - OSPF_TRACE(D_EVENTS, "Flushing %s-LSA for %I/%d", - nssa ? "NSSA" : "AS-external", fn->prefix, fn->pxlen); - u32 dom = nssa ? oa->areaid : 0; u32 type = nssa ? LSA_T_NSSA : LSA_T_EXT; u32 lsaid = fibnode_to_lsaid(po, fn); - if (en = ospf_hash_find(po->gr, dom, lsaid, po->router_id, type)) + en = ospf_hash_find(po->gr, dom, lsaid, po->router_id, type); + if (en) { - if (check_ext_lsa(en, fn, 0, IPA_NONE, 0) < 0) + OSPF_TRACE(D_EVENTS, "Flushing %s-LSA for %I/%d", + nssa ? "NSSA" : "AS-external", fn->prefix, fn->pxlen); + + if (check_ext_lsa(po, en, fn, 0, IPA_NONE, 0) < 0) { log(L_ERR "%s: LSAID collision for %I/%d", p->name, fn->prefix, fn->pxlen); @@ -1158,14 +1146,17 @@ flush_ext_lsa(struct ospf_area *oa, struct fib_node *fn, int src) } /* Clean up source bits */ - if (src) + if (src) // XXXX ??? fn->flags &= ~OSPF_RT_SRC; ospf_lsupd_flush_nlsa(po, en); } } -#ifdef OSPFv3 +/* + * Link-LSA handling (assume OSPFv3) + * Type = LSA_T_LINK + */ static void * originate_link_lsa_body(struct ospf_iface *ifa, u16 *length) @@ -1203,20 +1194,19 @@ originate_link_lsa_body(struct ospf_iface *ifa, u16 *length) void originate_link_lsa(struct ospf_iface *ifa) { - struct ospf_lsa_header lsa; struct proto_ospf *po = ifa->oa->po; - struct proto *p = &po->proto; + struct ospf_lsa_header lsa; + u32 dom = ifa->iface->index; void *body; /* FIXME check for vlink and skip that? */ OSPF_TRACE(D_EVENTS, "Originating link-LSA for iface %s", ifa->iface->name); lsa.age = 0; - lsa.type = LSA_T_LINK; + lsa.type_raw = LSA_T_LINK; lsa.id = ifa->iface->index; lsa.rt = po->router_id; lsa.sn = get_seqnum(ifa->link_lsa); - u32 dom = ifa->iface->index; body = originate_link_lsa_body(ifa, &lsa.length); lsasum_calculate(&lsa, body); @@ -1241,6 +1231,12 @@ update_link_lsa(struct ospf_iface *ifa) ifa->origlink = 0; } + +/* + * Prefix-Rt-LSA handling (assume OSPFv3) + * Type = LSA_T_PREFIX, referred type = LSA_T_RT + */ + static inline void lsa_put_prefix(struct proto_ospf *po, ip_addr prefix, u32 pxlen, u32 cost) { @@ -1337,18 +1333,17 @@ void originate_prefix_rt_lsa(struct ospf_area *oa) { struct proto_ospf *po = oa->po; - struct proto *p = &po->proto; struct ospf_lsa_header lsa; + u32 dom = oa->areaid; void *body; OSPF_TRACE(D_EVENTS, "Originating router prefix-LSA for area %R", oa->areaid); lsa.age = 0; - lsa.type = LSA_T_PREFIX; + lsa.type_raw = LSA_T_PREFIX; lsa.id = 0; lsa.rt = po->router_id; lsa.sn = get_seqnum(oa->pxr_lsa); - u32 dom = oa->areaid; body = originate_prefix_rt_lsa_body(oa, &lsa.length); lsasum_calculate(&lsa, body); @@ -1357,6 +1352,11 @@ originate_prefix_rt_lsa(struct ospf_area *oa) } +/* + * Prefix-Net-LSA handling (assume OSPFv3) + * Type = LSA_T_PREFIX, referred type = LSA_T_NET + */ + static inline int prefix_space(u32 *buf) { @@ -1429,7 +1429,6 @@ add_link_lsa(struct proto_ospf *po, struct top_hash_entry *en, int offset, int * } - static void * originate_prefix_net_lsa_body(struct ospf_iface *ifa, u16 *length) { @@ -1468,19 +1467,18 @@ void originate_prefix_net_lsa(struct ospf_iface *ifa) { struct proto_ospf *po = ifa->oa->po; - struct proto *p = &po->proto; struct ospf_lsa_header lsa; + u32 dom = ifa->oa->areaid; void *body; OSPF_TRACE(D_EVENTS, "Originating network prefix-LSA for iface %s", ifa->iface->name); lsa.age = 0; - lsa.type = LSA_T_PREFIX; + lsa.type_raw = LSA_T_PREFIX; lsa.id = ifa->iface->index; lsa.rt = po->router_id; lsa.sn = get_seqnum(ifa->pxn_lsa); - u32 dom = ifa->oa->areaid; body = originate_prefix_net_lsa_body(ifa, &lsa.length); lsasum_calculate(&lsa, body); @@ -1492,7 +1490,6 @@ void flush_prefix_net_lsa(struct ospf_iface *ifa) { struct proto_ospf *po = ifa->oa->po; - struct proto *p = &po->proto; struct top_hash_entry *en = ifa->pxn_lsa; u32 dom = ifa->oa->areaid; @@ -1511,9 +1508,6 @@ flush_prefix_net_lsa(struct ospf_iface *ifa) } -#endif - - static void ospf_top_ht_alloc(struct top_graph *f) { @@ -1549,7 +1543,7 @@ ospf_top_hash_u32(u32 a) return a; } -static inline unsigned +static unsigned ospf_top_hash(struct top_graph *f, u32 domain, u32 lsaid, u32 rtrid, u32 type) { /* In OSPFv2, we don't know Router ID when looking for network LSAs. @@ -1557,14 +1551,8 @@ ospf_top_hash(struct top_graph *f, u32 domain, u32 lsaid, u32 rtrid, u32 type) In both cases, there is (usually) just one (or small number) appropriate LSA, so we just clear unknown part of key. */ - return ( -#ifdef OSPFv2 - ((type == LSA_T_NET) ? 0 : ospf_top_hash_u32(rtrid)) + - ospf_top_hash_u32(lsaid) + -#else /* OSPFv3 */ - ospf_top_hash_u32(rtrid) + - ((type == LSA_T_RT) ? 0 : ospf_top_hash_u32(lsaid)) + -#endif + return (((f->ospf2 && (type == LSA_T_NET)) ? 0 : ospf_top_hash_u32(rtrid)) + + ((!f->ospf2 && (type == LSA_T_RT)) ? 0 : ospf_top_hash_u32(lsaid)) + type + domain) & f->hash_mask; /* @@ -1691,12 +1679,12 @@ ospf_hash_find(struct top_graph *f, u32 domain, u32 lsa, u32 rtr, u32 type) /* In OSPFv2, sometimes we don't know Router ID when looking for network LSAs. There should be just one, so we find any match. */ struct top_hash_entry * -ospf_hash_find_net(struct top_graph *f, u32 domain, u32 lsa) +ospf_hash_find_net(struct top_graph *f, u32 domain, u32 id, u32 nif) { struct top_hash_entry *e; - e = f->hash_table[ospf_top_hash(f, domain, lsa, 0, LSA_T_NET)]; + e = f->hash_table[ospf_top_hash(f, domain, id, 0, LSA_T_NET)]; - while (e && (e->lsa.id != lsa || e->lsa.type != LSA_T_NET || e->domain != domain)) + while (e && (e->lsa.id != id || e->lsa.type != LSA_T_NET || e->domain != domain)) e = e->next; return e; diff --git a/proto/ospf/topology.h b/proto/ospf/topology.h index 1e9544445..909f9d302 100644 --- a/proto/ospf/topology.h +++ b/proto/ospf/topology.h @@ -16,6 +16,7 @@ struct top_hash_entry in intra-area routing table calculation */ struct top_hash_entry *next; /* Next in hash chain */ struct ospf_lsa_header lsa; + u16 lsa_type; /* lsa.type processed and converted to common values */ u32 domain; /* Area ID for area-wide LSAs, Iface ID for link-wide LSAs */ // struct ospf_area *oa; void *lsa_body; @@ -76,7 +77,7 @@ void flush_ext_lsa(struct ospf_area *oa, struct fib_node *fn, int src); #ifdef OSPFv2 -struct top_hash_entry * ospf_hash_find_net(struct top_graph *f, u32 domain, u32 lsa); +struct top_hash_entry * ospf_hash_find_net(struct top_graph *f, u32 domain, u32 id, u32 nif); static inline struct top_hash_entry * ospf_hash_find_rt(struct top_graph *f, u32 domain, u32 rtr) @@ -85,6 +86,13 @@ ospf_hash_find_rt(struct top_graph *f, u32 domain, u32 rtr) } #else /* OSPFv3 */ +static inline struct top_hash_entry * +ospf_hash_find_net(struct top_graph *f, u32 domain, u32 id, u32 nif) +{ + return ospf_hash_find(f, domain, nif, id, LSA_T_NET); +} + + struct top_hash_entry * ospf_hash_find_rt(struct top_graph *f, u32 domain, u32 rtr); struct top_hash_entry * ospf_hash_find_rt_first(struct top_graph *f, u32 domain, u32 rtr); struct top_hash_entry * ospf_hash_find_rt_next(struct top_hash_entry *e); diff --git a/proto/radv/packets.c b/proto/radv/packets.c index a87b96891..6c5511e64 100644 --- a/proto/radv/packets.c +++ b/proto/radv/packets.c @@ -160,7 +160,7 @@ radv_send_ra(struct radv_iface *ifa, int shutdown) } RADV_TRACE(D_PACKETS, "Sending RA via %s", ifa->iface->name); - sk_send_to(ifa->sk, ifa->plen, AllNodes, 0); + sk_send_to(ifa->sk, ifa->plen, IP6_ALL_NODES, 0); } @@ -251,7 +251,7 @@ radv_sk_open(struct radv_iface *ifa) if (sk_setup_multicast(sk) < 0) goto err; - if (sk_join_group(sk, AllRouters) < 0) + if (sk_join_group(sk, IP6_ALL_ROUTERS) < 0) goto err; ifa->sk = sk; diff --git a/proto/radv/radv.h b/proto/radv/radv.h index 3f88eac88..bffdbda97 100644 --- a/proto/radv/radv.h +++ b/proto/radv/radv.h @@ -26,9 +26,6 @@ #define ICMPV6_PROTO 58 -#define AllNodes ipa_build6(0xFF020000, 0, 0, 1) /* FF02::1 */ -#define AllRouters ipa_build6(0xFF020000, 0, 0, 2) /* FF02::2 */ - #define ICMPV6_RS 133 #define ICMPV6_RA 134