#define IP4_MIN_MTU 576 /* RFC 2328 A.1 */
#define IP6_MIN_MTU 1280 /* RFC 5340 A.1 */
-#define IP4_ALL_SPF_ROUTERS ipa_build4(224, 0, 0, 5)
-#define IP4_ALL_D_ROUTERS ipa_build4(224, 0, 0, 6)
+#define IP4_OSPF_ALL_ROUTERS ipa_build4(224, 0, 0, 5)
+#define IP4_OSPF_DES_ROUTERS ipa_build4(224, 0, 0, 6)
-#define IP6_All_NODES ipa_build6(0xFF020000, 0, 0, 1)
+#define IP6_ALL_NODES ipa_build6(0xFF020000, 0, 0, 1)
#define IP6_ALL_ROUTERS ipa_build6(0xFF020000, 0, 0, 2)
-#define IP6_ALL_OSPF_ROUTERS ipa_build6(0xFF020000, 0, 0, 5)
-#define IP6_ALL_OSPF_D_ROUTERS ipa_build6(0xFF020000, 0, 0, 6)
+#define IP6_OSPF_ALL_ROUTERS ipa_build6(0xFF020000, 0, 0, 5)
+#define IP6_OSPF_DES_ROUTERS ipa_build6(0xFF020000, 0, 0, 6)
#define IP4_NONE _MI4(0)
#define IP6_NONE _MI6(0,0,0,0)
this_proto = proto_config_new(&proto_ospf, sizeof(struct ospf_config), $1);
init_list(&OSPF_CFG->area_list);
init_list(&OSPF_CFG->vlink_list);
- OSPF_CFG->rfc1583 = DEFAULT_RFC1583;
- OSPF_CFG->tick = DEFAULT_OSPFTICK;
+ OSPF_CFG->tick = OSPF_DEFAULT_TICK;
}
;
this_area = cfg_allocz(sizeof(struct ospf_area_config));
add_tail(&OSPF_CFG->area_list, NODE this_area);
this_area->areaid = $2;
- this_area->default_cost = DEFAULT_STUB_COST;
+ this_area->default_cost = OSPF_DEFAULT_STUB_COST;
this_area->type = OPT_E;
- this_area->transint = DEFAULT_TRANSINT;
+ this_area->transint = OSPF_DEFAULT_TRANSINT;
init_list(&this_area->patt_list);
init_list(&this_area->net_list);
};
-
-#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)
{
static void ospf_dbdes_dump(struct proto_ospf *po, struct ospf_packet *pkt)
{
- struct proto *p = &po->proto;
struct ospf_lsa_header *lsas;
unsigned i, lsa_count;
+ u32 pkt_ddseq;
+ u16 pkt_iface_mtu;
+ u8 pkt_imms;
ASSERT(pkt->type == DBDES_P);
ospf_dump_common(po, pkt);
- log(L_TRACE "%s: imms %s%s%s", p->name,
- (imms & DBDES_I) ? "I " : "",
- (imms & DBDES_M) ? "M " : "",
- (imms & DBDES_MS) ? "MS" : "");
- log(L_TRACE "%s: ddseq %u", p->name, ntohl(pkt->ddseq));
-
- struct ospf_lsa_header *plsa = (void *) (pkt + 1);
- unsigned int i, j;
+ if (ospf_is_v2(po))
+ {
+ struct ospf_dbdes2_packet *ps = (void *) pkt;
+ pkt_iface_mtu = ntohs(ps->iface_mtu);
+ pkt_imms = ps->imms;
+ pkt_ddseq = ntohl(ps->ddseq);
+ }
+ else /* OSPFv3 */
+ {
+ struct ospf_dbdes3_packet *ps = (void *) pkt;
+ pkt_iface_mtu = ntohs(ps->iface_mtu);
+ pkt_imms = ps->imms;
+ pkt_ddseq = ntohl(ps->ddseq);
+ }
- j = (ntohs(op->length) - sizeof(struct ospf_dbdes_packet)) /
- sizeof(struct ospf_lsa_header);
+ log(L_TRACE "%s: mtu %u", po->proto.name, pkt_iface_mtu);
+ log(L_TRACE "%s: imms %s%s%s", po->proto.name,
+ (pkt_imms & DBDES_I) ? "I " : "",
+ (pkt_imms & DBDES_M) ? "M " : "",
+ (pkt_imms & DBDES_MS) ? "MS" : "");
+ log(L_TRACE "%s: ddseq %u", po->proto.name, pkt_ddseq);
- for (i = 0; i < j; i++)
- ospf_dump_lsahdr(p, &lsas[i]);
+ ospf_dbdes_body(po, pkt, ntohs(pkt->length), &lsas, &lsa_count);
+ for (i = 0; i < lsa_count; i++)
+ ospf_dump_lsahdr(po, lsas + i);
}
+static void
+ospf_dbdes_prepare(struct ospf_neighbor *n, struct ospf_packet *pkt, int lsdb)
+{
+ struct ospf_iface *ifa = n->ifa;
+ struct proto_ospf *po = ifa->oa->po;
+ int i = 0;
+
+ ospf_pkt_fill_hdr(ifa, pkt, DBDES_P);
+
+ if (lsdb && (n->myimms & DBDES_M))
+ {
+ struct ospf_lsa_header *lsas;
+ unsigned lsa_max;
+ snode *sn;
+
+ ospf_dbdes_body(po, pkt, ospf_pkt_maxsize(ifa), &lsas, &lsa_max);
+ sn = s_get(&(n->dbsi));
+
+ while (i < lsa_max)
+ {
+ struct top_hash_entry *en = (struct top_hash_entry *) sn;
+
+ if (lsa_flooding_allowed(en->lsa_type, en->domain, ifa))
+ {
+ lsa_hton_hdr(&(en->lsa), lsas + i);
+ i++;
+ }
+
+ if (sn == STAIL(po->lsal))
+ {
+ n->myimms &= ~DBDES_M; /* Unset more bit */
+ break;
+ }
+
+ sn = sn->next;
+ }
+
+ s_put(&(n->dbsi), sn);
+ }
+
+ u16 iface_mtu = (ifa->type == OSPF_IT_VLINK) ? 0 : ifa->iface->mtu;
+ unsigned length;
+
+ if (ospf_is_v2(po))
+ {
+ struct ospf_dbdes2_packet *ps = (void *) pkt;
+
+ ps->iface_mtu = htons(iface_mtu);
+ ps->options = ifa->oa->options;
+ ps->imms = n->myimms;
+ ps->ddseq = htonl(n->dds);
+
+ length = sizeof(struct ospf_dbdes2_packet);
+ }
+ else /* OSPFv3 */
+ {
+ struct ospf_dbdes3_packet *ps = (void *) pkt;
+
+ ps->options = htonl(ifa->oa->options);
+ ps->iface_mtu = htons(iface_mtu);
+ ps->imms = n->myimms;
+ ps->ddseq = htonl(n->dds);
+
+ length = sizeof(struct ospf_dbdes3_packet);
+ }
+
+ length += i * sizeof(struct ospf_lsa_header);
+ pkt->length = htons(length);
+}
+
/**
* ospf_dbdes_send - transmit database description packet
* @n: neighbor
struct ospf_iface *ifa = n->ifa;
struct ospf_area *oa = ifa->oa;
struct proto_ospf *po = oa->po;
-
- struct ospf_dbdes_packet *pkt;
- struct ospf_packet *op;
- u16 length, i, j;
+ struct ospf_packet *pkt;
+ unsigned length;
/* FIXME ??? */
if ((oa->rt == NULL) || (EMPTY_LIST(po->lsal)))
switch (n->state)
{
- case NEIGHBOR_EXSTART: /* Send empty packets */
+ case NEIGHBOR_EXSTART:
n->myimms |= DBDES_I;
+
+ /* Send empty packets */
pkt = ospf_tx_buffer(ifa);
- op = &pkt->ospf_packet;
- ospf_pkt_fill_hdr(ifa, pkt, DBDES_P);
- pkt->iface_mtu = (ifa->type == OSPF_IT_VLINK) ? 0 : htons(ifa->iface->mtu);
- pkt->options = hton_opt(oa->options);
- pkt->imms = n->myimms;
- pkt->ddseq = htonl(n->dds);
- length = sizeof(struct ospf_dbdes_packet);
- op->length = htons(length);
-
- OSPF_PACKET(ospf_dump_dbdes, pkt, "DBDES packet sent to %I via %s", n->ip, ifa->iface->name);
+ ospf_dbdes_prepare(n, pkt, 0);
+ OSPF_PACKET(ospf_dbdes_dump, pkt, "DBDES packet sent to %I via %s", n->ip, ifa->iface->name);
ospf_send_to(ifa, n->ip);
break;
n->myimms &= ~DBDES_I;
if (next)
- {
- snode *sn;
- struct ospf_lsa_header *lsa;
-
- pkt = n->ldbdes;
- op = (struct ospf_packet *) pkt;
-
- ospf_pkt_fill_hdr(ifa, pkt, DBDES_P);
- pkt->iface_mtu = (ifa->type == OSPF_IT_VLINK) ? 0 : htons(ifa->iface->mtu);
- pkt->ddseq = htonl(n->dds);
- pkt->options = hton_opt(oa->options);
-
- j = i = (ospf_pkt_maxsize(ifa) - sizeof(struct ospf_dbdes_packet)) / sizeof(struct ospf_lsa_header); /* Number of possible lsaheaders to send */
- lsa = (n->ldbdes + sizeof(struct ospf_dbdes_packet));
-
- if (n->myimms & DBDES_M)
- {
- sn = s_get(&(n->dbsi));
-
- DBG("Number of LSA: %d\n", j);
- for (; i > 0; i--)
- {
- struct top_hash_entry *en= (struct top_hash_entry *) sn;
-
- if (ospf_lsa_flooding_allowed(&en->lsa, en->domain, ifa))
- {
- htonlsah(&(en->lsa), lsa);
- DBG("Working on: %d\n", i);
- DBG("\tX%01x %-1R %-1R %p\n", en->lsa.type, en->lsa.id, en->lsa.rt, en->lsa_body);
-
- lsa++;
- }
- else i++; /* No lsa added */
-
- if (sn == STAIL(po->lsal))
- {
- i--;
- break;
- }
-
- sn = sn->next;
- }
-
- if (sn == STAIL(po->lsal))
- {
- DBG("Number of LSA NOT sent: %d\n", i);
- DBG("M bit unset.\n");
- n->myimms &= ~DBDES_M; /* Unset more bit */
- }
-
- s_put(&(n->dbsi), sn);
- }
-
- pkt->imms = n->myimms;
-
- length = (j - i) * sizeof(struct ospf_lsa_header) +
- sizeof(struct ospf_dbdes_packet);
- op->length = htons(length);
-
- DBG("%s: DB_DES (M) prepared for %I.\n", p->name, n->ip);
- }
+ ospf_dbdes_prepare(n, n->ldbdes, 1);
case NEIGHBOR_LOADING:
case NEIGHBOR_FULL:
- length = ntohs(((struct ospf_packet *) n->ldbdes)->length);
+ length = ntohs(((struct ospf_packet *) n->ldbdes)->length);
if (!length)
{
OSPF_TRACE(D_PACKETS, "No packet in my buffer for repeating");
pkt = ospf_tx_buffer(ifa);
memcpy(pkt, n->ldbdes, length);
- OSPF_PACKET(ospf_dump_dbdes, pkt, "DBDES packet sent to %I via %s", n->ip, ifa->iface->name);
+ OSPF_PACKET(ospf_dbdes_dump, pkt, "DBDES packet sent to %I via %s", n->ip, ifa->iface->name);
ospf_send_to(ifa, n->ip);
+ /* XXXX remove this? */
if (n->myimms & DBDES_MS)
tm_start(n->rxmt_timer, n->ifa->rxmtint); /* Restart timer */
if (!(n->myimms & DBDES_MS))
- {
if (!(n->myimms & DBDES_M) &&
!(n->imms & DBDES_M) &&
(n->state == NEIGHBOR_EXCHANGE))
- {
ospf_neigh_sm(n, INM_EXDONE);
- }
- }
+
break;
default: /* Ignore it */
}
static void
-ospf_dbdes_reqladd(struct ospf_dbdes_packet *ps, struct ospf_neighbor *n)
+ospf_dbdes_process(struct ospf_neighbor *n, struct ospf_packet *pkt, unsigned plen)
{
- struct ospf_lsa_header *plsa, lsa;
- struct top_hash_entry *he, *sn;
- struct ospf_area *oa = n->ifa->oa;
- struct top_graph *gr = oa->po->gr;
- struct ospf_packet *op;
- int i, j;
+ struct ospf_iface *ifa = n->ifa;
+ struct proto_ospf *po = ifa->oa->po;
+ struct ospf_lsa_header *lsas;
+ unsigned i, lsa_count;
+
+ ospf_dbdes_body(po, pkt, plen, &lsas, &lsa_count);
- op = (struct ospf_packet *) ps;
+ for (i = 0; i < lsa_count; i++)
+ {
+ struct top_hash_entry *en, *req;
+ struct ospf_lsa_header lsa;
+ u32 lsa_type, lsa_domain;
- plsa = (void *) (ps + 1);
+ lsa_ntoh_hdr(lsas + i, &lsa);
+ lsa_xxxxtype(lsa.type_raw, ifa, &lsa_type, &lsa_domain);
- j = (ntohs(op->length) - sizeof(struct ospf_dbdes_packet)) /
- sizeof(struct ospf_lsa_header);
+ /* XXXX: Add check for 0-type or flooding_allowed */
- for (i = 0; i < j; i++)
- {
- ntohlsah(plsa + i, &lsa);
- u32 dom = ospf_lsa_domain(lsa.type, n->ifa);
- if (((he = ospf_hash_find_header(gr, dom, &lsa)) == NULL) ||
- (lsa_comp(&lsa, &(he->lsa)) == 1))
+ en = ospf_hash_find(po->gr, lsa_domain, lsa.id, lsa.rt, lsa_type);
+ if (!en || (lsa_comp(&lsa, &(en->lsa)) == CMP_NEWER))
{
- /* Is this condition necessary? */
- if (ospf_hash_find_header(n->lsrqh, dom, &lsa) == NULL)
- {
- sn = ospf_hash_get_header(n->lsrqh, dom, &lsa);
- ntohlsah(plsa + i, &(sn->lsa));
- s_add_tail(&(n->lsrql), SNODE sn);
- }
+ req = ospf_hash_get(n->lsrqh, lsa_domain, lsa.id, lsa.rt, lsa_type);
+
+ if (ospf_hash_is_new(req))
+ s_add_tail(&(n->lsrql), SNODE req);
+
+ en->lsa = lsa;
}
}
}
struct ospf_neighbor *n)
{
struct proto_ospf *po = ifa->oa->po;
-
u32 rcv_ddseq, rcv_options;
u16 rcv_iface_mtu;
u8 rcv_imms;
+ unsigned plen;
-
- unsigned int size = ntohs(ps_i->length);
- if (size < sizeof(struct ospf_dbdes_packet))
+ plen = ntohs(pkt->length);
+ if (plen < ospf_dbdes_hdrlen(po))
{
- log(L_ERR "Bad OSPF DBDES packet from %I - too short (%u B)", n->ip, size);
+ log(L_ERR "OSPF: Bad DBDES packet from %I - too short (%u B)", n->ip, plen);
return;
}
+ OSPF_PACKET(ospf_dbdes_dump, pkt, "DBDES packet received from %I via %s", n->ip, ifa->iface->name);
+
+ ospf_neigh_sm(n, INM_HELLOREC);
+
if (ospf_is_v2(po))
{
struct ospf_dbdes2_packet *ps = (void *) pkt;
rcv_ddseq = ntohl(ps->ddseq);
}
- OSPF_PACKET(ospf_dbdes_dump, ps, "DBDES packet received from %I via %s", n->ip, ifa->iface->name);
-
- ospf_neigh_sm(n, INM_HELLOREC);
-
switch (n->state)
{
case NEIGHBOR_DOWN:
(rcv_iface_mtu != 0) &&
(ifa->iface->mtu != 0) &&
(ifa->type != OSPF_IT_VLINK))
- log(L_WARN "OSPF: MTU mismatch with neighbour %I on interface %s (remote %d, local %d)",
+ log(L_WARN "OSPF: MTU mismatch with neighbor %I on interface %s (remote %d, local %d)",
n->ip, ifa->iface->name, rcv_iface_mtu, ifa->iface->mtu);
if ((rcv_imms == DBDES_IMMS) &&
(n->rid > po->router_id) &&
- (size == sizeof(struct ospf_dbdes_packet)))
+ (plen == ospf_dbdes_hdrlen(po)))
{
/* I'm slave! */
n->dds = rcv_ddseq;
(rcv_ddseq == n->ddr))
{
/* Duplicate packet */
- OSPF_TRACE(D_PACKETS, "Received duplicate dbdes from %I.", n->ip);
+ OSPF_TRACE(D_PACKETS, "Received duplicate dbdes from %I", n->ip);
if (!(n->myimms & DBDES_MS))
{
/* Slave should retransmit dbdes packet */
}
n->dds++;
DBG("Incrementing dds\n");
- ospf_dbdes_reqladd(ps, n);
+ ospf_dbdes_process(n, pkt, plen);
if (!(n->myimms & DBDES_M) &&
!(rcv_imms & DBDES_M))
{
}
n->ddr = rcv_ddseq;
n->dds = rcv_ddseq;
- ospf_dbdes_reqladd(ps, n);
+ ospf_dbdes_process(n, pkt, plen);
ospf_dbdes_send(n, 1);
}
break;
(rcv_ddseq == n->ddr))
/* Only duplicate are accepted */
{
- OSPF_TRACE(D_PACKETS, "Received duplicate dbdes from %I.", n->ip);
+ OSPF_TRACE(D_PACKETS, "Received duplicate dbdes from %I", n->ip);
if (!(n->myimms & DBDES_MS))
{
/* Slave should retransmit dbdes packet */
struct ospf_neighbor *n, ip_addr faddr)
{
struct proto_ospf *po = ifa->oa->po;
- struct proto *p = &po->proto;
char *beg = "OSPF: Bad HELLO packet from ";
unsigned int size, i, two_way;
static int
ospf_sk_open(struct ospf_iface *ifa)
{
+ struct proto_ospf *po = ifa->oa->po;
+
sock *sk = sk_new(ifa->pool);
sk->type = SK_IP;
sk->dport = OSPF_PROTO;
if (sk_open(sk) != 0)
goto err;
-#ifdef OSPFv3
- /* 12 is an offset of the checksum in an OSPF packet */
- if (sk_set_ipv6_checksum(sk, 12) < 0)
- goto err;
-#endif
+ /* 12 is an offset of the checksum in an OSPFv3 packet */
+ if (ospf_is_v3(po))
+ if (sk_set_ipv6_checksum(sk, 12) < 0)
+ goto err;
/*
* For OSPFv2: When sending a packet, it is important to have a
if (ifa->cf->real_bcast)
{
ifa->all_routers = ifa->addr->brd;
+ ifa->des_routers = IPA_NONE;
if (sk_set_broadcast(sk, 1) < 0)
goto err;
}
else
{
- ifa->all_routers = AllSPFRouters;
- sk->ttl = 1; /* Hack, this will affect just multicast packets */
+ ifa->all_routers = ospf_is_v2(po) ? IP4_OSPF_ALL_ROUTERS : IP6_OSPF_ALL_ROUTERS;
+ ifa->des_routers = ospf_is_v2(po) ? IP4_OSPF_DES_ROUTERS : IP6_OSPF_DES_ROUTERS;
+ sk->ttl = 1; /* Hack, this will affect just the multicast packets */
if (sk_setup_multicast(sk) < 0)
goto err;
if (ifa->sk_dr)
return;
- sk_join_group(ifa->sk, AllDRouters);
+ sk_join_group(ifa->sk, ifa->des_routers);
ifa->sk_dr = 1;
}
if (!ifa->sk_dr)
return;
- sk_leave_group(ifa->sk, AllDRouters);
+ sk_leave_group(ifa->sk, ifa->des_routers);
ifa->sk_dr = 0;
}
if (ifa->type != OSPF_IT_VLINK)
{
-#ifdef OSPFv2
- OSPF_TRACE(D_EVENTS, "Removing interface %s (%I/%d) from area %R",
- ifa->iface->name, ifa->addr->prefix, ifa->addr->pxlen, ifa->oa->areaid);
-#else
- OSPF_TRACE(D_EVENTS, "Removing interface %s (IID %d) from area %R",
- ifa->iface->name, ifa->instance_id, ifa->oa->areaid);
-#endif
+ if (ospf_is_v3(ifa->oa->po))
+ OSPF_TRACE(D_EVENTS, "Removing interface %s (IID %d) from area %R",
+ ifa->iface->name, ifa->instance_id, ifa->oa->areaid);
+ else if (ifa->addr->flags & IA_PEER)
+ OSPF_TRACE(D_EVENTS, "Removing interface %s (peer %I) from area %R",
+ ifa->iface->name, ifa->addr->opposite, ifa->oa->areaid);
+ else
+ OSPF_TRACE(D_EVENTS, "Removing interface %s (%I/%d) from area %R",
+ ifa->iface->name, ifa->addr->prefix, ifa->addr->pxlen, ifa->oa->areaid);
/* First of all kill all the related vlinks */
WALK_LIST(iff, po->iface_list)
ifa->rt_pos_beg = 0;
ifa->rt_pos_end = 0;
-#ifdef OSPFv3
ifa->px_pos_beg = 0;
ifa->px_pos_end = 0;
-#endif
}
OSPF_TRACE(D_EVENTS, "Changing state of iface %s from %s to %s",
ifa->iface->name, ospf_is[oldstate], ospf_is[state]);
- if ((ifa->type == OSPF_IT_BCAST) && !ifa->cf->real_bcast && ifa->sk)
+ if ((ifa->type == OSPF_IT_BCAST) && ipa_nonzero(ifa->des_routers) && ifa->sk)
{
if ((state == OSPF_IS_BACKUP) || (state == OSPF_IS_DR))
ospf_sk_join_dr(ifa);
if (ip->type == OSPF_IT_VLINK)
OSPF_TRACE(D_EVENTS, "Adding vlink to %R via area %R", ip->vid, ip->voa);
+ else if (ospf_is_v3(po))
+ OSPF_TRACE(D_EVENTS, "Adding interface %s (IID %d) to area %R",
+ iface->name, ip->instance_id, oa->areaid);
+ else if (ifa->addr->flags & IA_PEER)
+ OSPF_TRACE(D_EVENTS, "Adding interface %s (peer %I) to area %R",
+ iface->name, addr->opposite, oa->areaid);
else
- {
-#ifdef OSPFv2
OSPF_TRACE(D_EVENTS, "Adding interface %s (%I/%d) to area %R",
iface->name, addr->prefix, addr->pxlen, oa->areaid);
-#else
- OSPF_TRACE(D_EVENTS, "Adding interface %s (IID %d) to area %R",
- iface->name, ip->instance_id, oa->areaid);
-#endif
- }
pool = rp_new(po->proto.pool, "OSPF Interface");
ifa = mb_allocz(pool, sizeof(struct ospf_iface));
ifa->rxbuf = ip->rxbuf;
ifa->check_link = ip->check_link;
ifa->ecmp_weight = ip->ecmp_weight;
-
-#ifdef OSPFv2
ifa->autype = ip->autype;
ifa->passwords = ip->passwords;
-#endif
-
-#ifdef OSPFv3
ifa->instance_id = ip->instance_id;
-#endif
ifa->type = ospf_iface_classify(ip->type, addr);
int old_type = ifa->type;
u32 if_multi_flag = ip->real_bcast ? IF_BROADCAST : IF_MULTICAST;
-#ifdef OSPFv2
- if ((ifa->type == OSPF_IT_BCAST) && (addr->flags & IA_PEER))
+ if (ospf_is_v2(po) && (ifa->type == OSPF_IT_BCAST) && (addr->flags & IA_PEER))
ifa->type = OSPF_IT_PTP;
- if ((ifa->type == OSPF_IT_NBMA) && (addr->flags & IA_PEER))
+ if (ospf_is_v2(po) && (ifa->type == OSPF_IT_NBMA) && (addr->flags & IA_PEER))
ifa->type = OSPF_IT_PTMP;
-#endif
if ((ifa->type == OSPF_IT_BCAST) && !(iface->flags & if_multi_flag))
ifa->type = OSPF_IT_NBMA;
if (ifa->type != old_type)
log(L_WARN "%s: Cannot use interface %s as %s, forcing %s",
- p->name, iface->name, ospf_it[old_type], ospf_it[ifa->type]);
+ po->proto.name, iface->name, ospf_it[old_type], ospf_it[ifa->type]);
init_list(&ifa->neigh_list);
*/
lock = olock_new(pool);
-#ifdef OSPFv2
- lock->addr = ifa->addr->prefix;
-#else /* OSPFv3 */
- lock->addr = _MI(0,0,0,ifa->instance_id);
-#endif
+ lock->addr = ospf_is_v2(po) ? ifa->addr->prefix : _MI6(0,0,0,ifa->instance_id);
lock->type = OBJLOCK_IP;
lock->port = OSPF_PROTO;
lock->iface = iface;
ifa->inftransdelay = new->inftransdelay;
}
-#ifdef OSPFv2
/* AUTHENTICATION */
if (ifa->autype != new->autype)
{
/* Update passwords */
ifa->passwords = new->passwords;
-#endif
/* Remaining options are just for proper interfaces */
if (ifa->type == OSPF_IT_VLINK)
}
else
{
-#ifdef OSPFv2
- if (ifa->addr->flags & IA_PEER)
+ if (ospf_is_v3(ifa->oa->po))
+ cli_msg(-1015, "Interface %s (IID %d)", ifa->iface->name, ifa->instance_id);
+ else if (ifa->addr->flags & IA_PEER)
cli_msg(-1015, "Interface %s (peer %I)", ifa->iface->name, ifa->addr->opposite);
else
cli_msg(-1015, "Interface %s (%I/%d)", ifa->iface->name, ifa->addr->prefix, ifa->addr->pxlen);
-#else /* OSPFv3 */
- cli_msg(-1015, "Interface %s (IID %d)", ifa->iface->name, ifa->instance_id);
-#endif
+
cli_msg(-1015, "\tType: %s%s", ospf_it[ifa->type], more);
cli_msg(-1015, "\tArea: %R (%u)", ifa->oa->areaid, ifa->oa->areaid);
}
{
if ((ifa->state == OSPF_IS_DR) || (ifa->state == OSPF_IS_BACKUP))
ospf_send_to_all(ifa);
- else if (ifa->cf->real_bcast)
- ospf_send_to_bdr(ifa);
else
- ospf_send_to(ifa, AllDRouters);
+ ospf_send_to_des(ifa);
}
else
ospf_send_to_agt(ifa, NEIGHBOR_EXCHANGE);
struct ospf_lsa_header lsa, *lsas;
struct top_hash_entry *en;
unsigned i, lsa_count;
+ u32 lsa_dom, lsa_type;
/* No need to check length, lsack has only basic header */
ospf_lsack_body(po, pkt, ntohs(pkt->length), &lsas, &lsa_count);
for (i = 0; i < lsa_count; i++)
{
- ntohlsah(&lsas[i], &lsa);
- u32 dom = ospf_lsa_domain(lsa.type, n->ifa);
- if ((en = ospf_hash_find_header(n->lsrth, dom, &lsa)) == NULL)
+ lsa_ntoh_hdr(&lsas[i], &lsa);
+ lsa_xxxxtype(lsa.type_raw, n->ifa, &lsa_type, &lsa_dom);
+
+ en = ospf_hash_find(n->lsrth, lsa_dom, lsa.id, lsa.rt, lsa_type);
+ if (!en)
continue; /* pg 155 */
if (lsa_comp(&lsa, &en->lsa) != CMP_SAME) /* pg 156 */
OSPF_TRACE(D_PACKETS, "Strange LSACK from %I", n->ip);
OSPF_TRACE(D_PACKETS, "Type: %04x, Id: %R, Rt: %R",
- lsa.type, lsa.id, lsa.rt);
+ lsa_type, lsa.id, lsa.rt);
OSPF_TRACE(D_PACKETS, "I have: Age: %4u, Seq: %08x, Sum: %04x",
en->lsa.age, en->lsa.sn, en->lsa.checksum);
OSPF_TRACE(D_PACKETS, "He has: Age: %4u, Seq: %08x, Sum: %04x",
continue;
}
- DBG("Deleting LS Id: %R RT: %R Type: %u from LS Retl for neighbor %R\n",
- lsa.id, lsa.rt, lsa.type, n->rid);
+ DBG("Deleting LSA (Type: %04x Id: %R Rt: %R) from lsrtl for neighbor %R\n",
+ lsa_type, lsa.id, lsa.rt, n->rid);
s_rem_node(SNODE en);
ospf_hash_delete(n->lsrth, en);
}
#ifndef CPU_BIG_ENDIAN
void
-htonlsah(struct ospf_lsa_header *h, struct ospf_lsa_header *n)
+lsa_hton_hdr(struct ospf_lsa_header *h, struct ospf_lsa_header *n)
{
n->age = htons(h->age);
- n->type_raw = htont(h->type_raw);
+ n->type_raw = htons(h->type_raw);
n->id = htonl(h->id);
n->rt = htonl(h->rt);
n->sn = htonl(h->sn);
}
void
-ntohlsah(struct ospf_lsa_header *n, struct ospf_lsa_header *h)
+lsa_ntoh_hdr(struct ospf_lsa_header *n, struct ospf_lsa_header *h)
{
h->age = ntohs(n->age);
- h->type_raw = ntoht(n->type_raw);
+ h->type_raw = ntohs(n->type_raw);
h->id = ntohl(n->id);
h->rt = ntohl(n->rt);
h->sn = ntohl(n->sn);
}
void
-htonlsab(void *h, void *n, u16 len)
+lsa_hton_body(void *h, void *n, u16 len)
{
u32 *hid = h;
u32 *nid = n;
}
void
-ntohlsab(void *n, void *h, u16 len)
+lsa_ntoh_body(void *n, void *h, u16 len)
{
u32 *nid = n;
u32 *hid = h;
}
#endif /* little endian */
+
+
+int
+lsa_flooding_allowed(u32 type, u32 domain, struct ospf_iface *ifa)
+{
+ /* 4.5.2 (Case 2) */
+
+ switch (LSA_SCOPE(type))
+ {
+ case LSA_SCOPE_LINK:
+ return ifa->iface->index == domain;
+
+ case LSA_SCOPE_AREA:
+ return ifa->oa->areaid == domain;
+
+ case LSA_SCOPE_AS:
+ if (ifa->type == OSPF_IT_VLINK)
+ return 0;
+ if (!oa_is_ext(ifa->oa))
+ return 0;
+ return 1;
+
+ default:
+ log(L_ERR "OSPF: LSA with invalid scope");
+ return 0;
+ }
+}
+
+
+static int
+unknown_lsa_type(u32 type)
+{
+ switch (type)
+ {
+ case LSA_T_RT:
+ case LSA_T_NET:
+ case LSA_T_SUM_NET:
+ case LSA_T_SUM_RT:
+ case LSA_T_EXT:
+ case LSA_T_NSSA:
+ case LSA_T_LINK:
+ case LSA_T_PREFIX:
+ return 0;
+
+ default:
+ return 1;
+ }
+}
+
+#define LSA_V2_TMAX 8
+static const u16 lsa_v2_types[LSA_V2_TMAX] =
+ {0, LSA_T_RT, LSA_T_NET, LSA_T_SUM_NET, LSA_T_SUM_RT, LSA_T_EXT, 0, LSA_T_NSSA};
+
+void
+lsa_xxxxtype(u32 itype, struct ospf_iface *ifa, u32 *otype, u32 *domain)
+{
+ if (ospf_is_v2(ifa->oa->po))
+ {
+ itype = itype & LSA_T_V2_MASK;
+ itype = (itype < LSA_V2_TMAX) ? lsa_v2_types[itype] : 0;
+ }
+ else
+ {
+ /* For unkown LSAs without U-bit change scope to LSA_SCOPE_LINK */
+ if (unknown_lsa_type(itype) && !(itype & LSA_UBIT))
+ itype = itype & ~LSA_SCOPE_MASK;
+ }
+
+ *otype = itype;
+
+ switch (LSA_SCOPE(itype))
+ {
+ case LSA_SCOPE_LINK:
+ *domain = ifa->iface->index;
+ return;
+
+ case LSA_SCOPE_AREA:
+ *domain = ifa->oa->areaid;
+ return;
+
+ case LSA_SCOPE_AS:
+ default:
+ *domain = 0;
+ return;
+ }
+}
+
+
+
/*
void
buf_dump(const char *hdr, const byte *buf, int blen)
u16 length = h->length;
// log(L_WARN "Checksum %R %R %d start (len %d)", h->id, h->rt, h->type, length);
- htonlsah(h, h);
- htonlsab1(body, length - sizeof(struct ospf_lsa_header));
+ lsa_hton_hdr(h, h);
+ lsa_hton_body1(body, length - sizeof(struct ospf_lsa_header));
/*
char buf[1024];
// log(L_WARN "Checksum result %4x", h->checksum);
- ntohlsah(h, h);
- ntohlsab1(body, length - sizeof(struct ospf_lsa_header));
+ lsa_ntoh_hdr(h, h);
+ lsa_ntoh_body1(body, length - sizeof(struct ospf_lsa_header));
}
/*
#define HDRLEN sizeof(struct ospf_lsa_header)
static int
-lsa_validate_rt(struct ospf_lsa_header *lsa, struct ospf_lsa_rt *body)
+lsa_validate_rt2(struct ospf_lsa_header *lsa, struct ospf_lsa_rt *body)
{
- unsigned int i, max;
-
if (lsa->length < (HDRLEN + sizeof(struct ospf_lsa_rt)))
return 0;
- struct ospf_lsa_rt_link *rtl = (struct ospf_lsa_rt_link *) (body + 1);
- max = lsa_rt_count(lsa);
-
-#ifdef OSPFv2
- if (body->links != max)
- return 0;
-#endif
+ unsigned i = 0;
+ void *buf = body;
+ void *bufend = buf + lsa->length - HDRLEN;
+ buf += sizeof(struct ospf_lsa_rt);
- for (i = 0; i < max; i++)
+ while (buf < bufend)
{
- u8 type = rtl[i].type;
- if (!((type == LSART_PTP) ||
- (type == LSART_NET) ||
-#ifdef OSPFv2
- (type == LSART_STUB) ||
-#endif
- (type == LSART_VLNK)))
+ struct ospf_lsa_rt2_link *l = buf;
+ buf += sizeof(struct ospf_lsa_rt2_link) + l->no_tos * sizeof(struct ospf_lsa_rt2_tos);
+ i++;
+
+ if (buf > bufend)
+ return 0;
+
+ if (!((l->type == LSART_PTP) ||
+ (l->type == LSART_NET) ||
+ (l->type == LSART_STUB) ||
+ (l->type == LSART_VLNK)))
return 0;
}
+
+ if ((body->options & LSA_RT2_LINKS) != i)
+ return 0;
+
return 1;
}
+
static int
-lsa_validate_net(struct ospf_lsa_header *lsa, struct ospf_lsa_net *body UNUSED)
+lsa_validate_rt3(struct ospf_lsa_header *lsa, struct ospf_lsa_rt *body)
{
- if (lsa->length < (HDRLEN + sizeof(struct ospf_lsa_net)))
+ if (lsa->length < (HDRLEN + sizeof(struct ospf_lsa_rt)))
return 0;
+ void *buf = body;
+ void *bufend = buf + lsa->length - HDRLEN;
+ buf += sizeof(struct ospf_lsa_rt);
+
+ while (buf < bufend)
+ {
+ struct ospf_lsa_rt3_link *l = buf;
+ buf += sizeof(struct ospf_lsa_rt3_link);
+
+ if (buf > bufend)
+ return 0;
+
+ if (!((l->type == LSART_PTP) ||
+ (l->type == LSART_NET) ||
+ (l->type == LSART_VLNK)))
+ return 0;
+ }
return 1;
}
-#ifdef OSPFv2
-
static int
-lsa_validate_sum(struct ospf_lsa_header *lsa, struct ospf_lsa_sum *body)
+lsa_validate_net(struct ospf_lsa_header *lsa, struct ospf_lsa_net *body UNUSED)
{
- if (lsa->length < (HDRLEN + sizeof(struct ospf_lsa_sum)))
- return 0;
-
- /* First field should have TOS = 0, we ignore other TOS fields */
- if ((body->metric & LSA_SUM_TOS) != 0)
+ if (lsa->length < (HDRLEN + sizeof(struct ospf_lsa_net)))
return 0;
return 1;
}
-#define lsa_validate_sum_net(A,B) lsa_validate_sum(A,B)
-#define lsa_validate_sum_rt(A,B) lsa_validate_sum(A,B)
static int
-lsa_validate_ext(struct ospf_lsa_header *lsa, struct ospf_lsa_ext *body)
+lsa_validate_sum2(struct ospf_lsa_header *lsa, struct ospf_lsa_sum2 *body)
{
- if (lsa->length < (HDRLEN + sizeof(struct ospf_lsa_ext)))
+ if (lsa->length < (HDRLEN + sizeof(struct ospf_lsa_sum2)))
return 0;
/* First field should have TOS = 0, we ignore other TOS fields */
- if ((body->metric & LSA_EXT_TOS) != 0)
+ if ((body->metric & LSA_SUM2_TOS) != 0)
return 0;
return 1;
}
-#else /* OSPFv3 */
-
static inline int
pxlen(u32 *buf)
{
}
static int
-lsa_validate_sum_net(struct ospf_lsa_header *lsa, struct ospf_lsa_sum3_net *body)
+lsa_validate_sum3_net(struct ospf_lsa_header *lsa, struct ospf_lsa_sum3_net *body)
{
if (lsa->length < (HDRLEN + sizeof(struct ospf_lsa_sum3_net) + 4))
return 0;
return 1;
}
-
static int
-lsa_validate_sum_rt(struct ospf_lsa_header *lsa, struct ospf_lsa_sum3_rt *body)
+lsa_validate_sum3_rt(struct ospf_lsa_header *lsa, struct ospf_lsa_sum3_rt *body)
{
if (lsa->length != (HDRLEN + sizeof(struct ospf_lsa_sum3_rt)))
return 0;
}
static int
-lsa_validate_ext(struct ospf_lsa_header *lsa, struct ospf_lsa_ext3 *body)
+lsa_validate_ext2(struct ospf_lsa_header *lsa, struct ospf_lsa_ext2 *body)
+{
+ if (lsa->length < (HDRLEN + sizeof(struct ospf_lsa_ext2)))
+ return 0;
+
+ /* First field should have TOS = 0, we ignore other TOS fields */
+ if ((body->metric & LSA_EXT2_TOS) != 0)
+ return 0;
+
+ return 1;
+}
+
+static int
+lsa_validate_ext3(struct ospf_lsa_header *lsa, struct ospf_lsa_ext3 *body)
{
if (lsa->length < (HDRLEN + sizeof(struct ospf_lsa_ext3) + 4))
return 0;
return lsa_validate_pxlist(lsa, body->pxcount, sizeof(struct ospf_lsa_prefix), (u8 *) body);
}
-#endif
-
/**
* lsa_validate - check whether given LSA is valid
*/
int
-lsa_validate(struct ospf_lsa_header *lsa, void *body)
+lsa_validate(struct ospf_lsa_header *lsa, u32 lsa_type, int ospf2, void *body)
{
- switch (lsa->type)
+ if (ospf2)
+ {
+ switch (lsa_type)
+ {
+ case LSA_T_RT:
+ return lsa_validate_rt2(lsa, body);
+ case LSA_T_NET:
+ return lsa_validate_net(lsa, body);
+ case LSA_T_SUM_NET:
+ return lsa_validate_sum2(lsa, body);
+ case LSA_T_SUM_RT:
+ return lsa_validate_sum2(lsa, body);
+ case LSA_T_EXT:
+ case LSA_T_NSSA:
+ return lsa_validate_ext2(lsa, body);
+ default:
+ return 0; /* Should not happen, unknown LSAs are already rejected */
+ }
+ }
+ else
+ {
+ switch (lsa_type)
{
case LSA_T_RT:
- return lsa_validate_rt(lsa, body);
+ return lsa_validate_rt3(lsa, body);
case LSA_T_NET:
return lsa_validate_net(lsa, body);
case LSA_T_SUM_NET:
- return lsa_validate_sum_net(lsa, body);
+ return lsa_validate_sum3_net(lsa, body);
case LSA_T_SUM_RT:
- return lsa_validate_sum_rt(lsa, body);
+ return lsa_validate_sum3_rt(lsa, body);
case LSA_T_EXT:
case LSA_T_NSSA:
- return lsa_validate_ext(lsa, body);
+ return lsa_validate_ext3(lsa, body);
case LSA_T_LINK:
return lsa_validate_link(lsa, body);
case LSA_T_PREFIX:
return lsa_validate_prefix(lsa, body);
default:
- /* In OSPFv3, unknown LSAs are OK,
- In OSPFv2, unknown LSAs are already rejected
- */
- return 1;
+ return 1; /* Unknown LSAs are OK in OSPFv3 */
}
+ }
}
/**
#define _BIRD_OSPF_LSALIB_H_
#ifdef CPU_BIG_ENDIAN
-static inline void htonlsah(struct ospf_lsa_header *h, struct ospf_lsa_header *n) { *n = *h; };
-static inline void ntohlsah(struct ospf_lsa_header *n, struct ospf_lsa_header *h) { *h = *n; };
-static inline void htonlsab(void *h, void *n, u16 len) { ASSERT(h != n); memcpy(n, h, len); };
-static inline void ntohlsab(void *n, void *h, u16 len) { ASSERT(n != h); memcpy(h, n, len); };
-static inline void htonlsab1(void *h, u16 len) { };
-static inline void ntohlsab1(void *n, u16 len) { };
+static inline void lsa_hton_hdr(struct ospf_lsa_header *h, struct ospf_lsa_header *n) { *n = *h; };
+static inline void lsa_ntoh_hdr(struct ospf_lsa_header *n, struct ospf_lsa_header *h) { *h = *n; };
+static inline void lsa_hton_body(void *h, void *n, u16 len) { ASSERT(h != n); memcpy(n, h, len); };
+static inline void lsa_ntoh_body(void *n, void *h, u16 len) { ASSERT(n != h); memcpy(h, n, len); };
+static inline void lsa_hton_body1(void *h, u16 len) { };
+static inline void lsa_ntoh_body1(void *n, u16 len) { };
#else
-void htonlsah(struct ospf_lsa_header *h, struct ospf_lsa_header *n);
-void ntohlsah(struct ospf_lsa_header *n, struct ospf_lsa_header *h);
-void htonlsab(void *h, void *n, u16 len);
-void ntohlsab(void *n, void *h, u16 len);
-static inline void htonlsab1(void *h, u16 len) { htonlsab(h, h, len); };
-static inline void ntohlsab1(void *n, u16 len) { ntohlsab(n, n, len); };
+void lsa_hton_hdr(struct ospf_lsa_header *h, struct ospf_lsa_header *n);
+void lsa_ntoh_hdr(struct ospf_lsa_header *n, struct ospf_lsa_header *h);
+void lsa_hton_body(void *h, void *n, u16 len);
+void lsa_ntoh_body(void *n, void *h, u16 len);
+static inline void lsa_hton_body1(void *h, u16 len) { lsa_hton_body(h, h, len); };
+static inline void lsa_ntoh_body1(void *n, u16 len) { lsa_ntoh_body(n, n, len); };
#endif
struct ospf_lsa_rt_walk {
u32 id, data, lif, nif;
};
+static inline u32 lsa_get_type(struct proto_ospf *po, u32 type_raw)
+{ return ospf_is_v2(po) ? (type_raw & LSA_T_V2_MASK) : type_raw; }
+
+int lsa_flooding_allowed(u32 type, u32 domain, struct ospf_iface *ifa);
+void lsa_xxxxtype(u32 itype, struct ospf_iface *ifa, u32 *otype, u32 *domain);
void lsasum_calculate(struct ospf_lsa_header *header, void *body);
u16 lsasum_check(struct ospf_lsa_header *h, void *body);
#define CMP_NEWER 1
void lsa_parse_sum_net(struct top_hash_entry *en, int ospf2, ip_addr *ip, int *pxlen, u8 *pxopts, u32 *metric);
void lsa_parse_sum_rt(struct top_hash_entry *en, int ospf2, u32 *drid, u32 *metric, u32 *options);
void lsa_parse_ext(struct top_hash_entry *en, int ospf2, struct ospf_lsa_ext_local *rt);
-int lsa_validate(struct ospf_lsa_header *lsa, void *body);
+int lsa_validate(struct ospf_lsa_header *lsa, u32 lsa_type, int ospf2, void *body);
struct top_hash_entry * lsa_install_new(struct proto_ospf *po, struct ospf_lsa_header *lsa, u32 domain, void *body);
void ospf_age(struct proto_ospf *po);
void flush_lsa(struct top_hash_entry *en, struct proto_ospf *po);
};
*/
-static void
+static inline void
ospf_lsreq_body(struct proto_ospf *po, struct ospf_packet *pkt, unsigned plen,
struct ospf_lsreq_header **body, unsigned *count)
{
{
en = (struct top_hash_entry *) sn;
DBG("Requesting %uth LSA: Type: %u, ID: %R, RT: %R, SN: 0x%x, Age %u\n",
- i, en->lsa.type, en->lsa.id, en->lsa.rt, en->lsa.sn, en->lsa.age);
+ i, en->lsa_type, en->lsa.id, en->lsa.rt, en->lsa.sn, en->lsa.age);
- lsrs[i].type = htonl(en->lsa.type);
+ u32 rtype = lsa_get_type(po, en->lsa.type_raw);
+ lsrs[i].type = htonl(rtype);
lsrs[i].rt = htonl(en->lsa.rt);
lsrs[i].id = htonl(en->lsa.id);
struct proto_ospf *po = ifa->oa->po;
struct ospf_lsreq_header *lsrs;
unsigned i, lsr_count;
- list uplist;
+
+ struct ospf_lsreq_item *lsr_head, *lsr;
+ struct ospf_lsreq_item **lsr_pos = &lsr_head;
slab *upslab;
ospf_neigh_sm(n, INM_HELLOREC); /* Not in RFC */
- init_list(&uplist);
- upslab = sl_new(n->pool, sizeof(struct l_lsr_head));
+ upslab = sl_new(n->pool, sizeof(struct ospf_lsreq_item));
ospf_lsreq_body(po, pkt, ntohs(pkt->length), &lsrs, &lsr_count);
for (i = 0; i < lsr_count; i++)
{
- u32 hid = ntohl(lsrs[i].id);
- u32 hrt = ntohl(lsrs[i].rt);
- u32 htype = ntohl(lsrs[i].type);
- u32 dom = ospf_lsa_domain(htype, ifa);
- // XXXX check
- DBG("Processing requested LSA: Type: %u, ID: %R, RT: %R\n", htype, hid, hrt);
-
- if (ospf_hash_find(po->gr, dom, hid, hrt, htype) == NULL)
+ u32 id, rt, type, dom;
+
+ id = ntohl(lsrs[i].id);
+ rt = ntohl(lsrs[i].rt);
+ lsa_xxxxtype(ntohl(lsrs[i].type), ifa, &type, &dom);
+
+ DBG("Processing requested LSA: Type: %04x, Id: %R, Rt: %R\n", type, id, rt);
+
+ if (ospf_hash_find(po->gr, dom, id, rt, type) == NULL)
{
log(L_WARN "Received bad LSREQ from %I: Type: %04x, Id: %R, Rt: %R",
- n->ip, htype, hid, hrt);
+ n->ip, type, id, rt);
ospf_neigh_sm(n, INM_BADLSREQ);
rfree(upslab);
return;
}
- struct l_lsr_head *llsh = sl_alloc(upslab);
- llsh->lsh.id = hid;
- llsh->lsh.rt = hrt;
- llsh->lsh.type = htype;
- add_tail(&uplist, NODE llsh);
+ lsr = sl_alloc(upslab);
+ lsr->domain = dom;
+ lsr->type = type;
+ lsr->id = id;
+ lsr->rt = rt;
+
+ *lsr_pos = lsr;
+ lsr_pos = &(lsr->next);
}
+ *lsr_pos = NULL;
- ospf_lsupd_send_list(n, &uplist);
+ ospf_lsupd_send_list(n, lsr_head);
rfree(upslab);
}
#include "ospf.h"
+/*
struct ospf_lsupd_packet
{
- struct ospf_packet ospf_packet;
- u32 lsano; /* Number of LSA's */
+ struct ospf_packet hdr;
+ // union ospf_auth auth;
+
+ u32 lsa_count;
+ void lsas[];
};
+*/
/* Beware of unaligned access */
void ospf_dump_lsahdr(struct proto_ospf *po, struct ospf_lsa_header *lsa_n)
{
struct ospf_lsa_header lsa;
- ntohlsah(lsa_n, &lsa);
+ u32 lsa_type;
+
+ lsa_ntoh_hdr(lsa_n, &lsa);
+ lsa_type = lsa_get_type(po, lsa.type_raw);
log(L_TRACE "%s: LSA Type: %04x, Id: %R, Rt: %R, Age: %u, Seq: %08x, Sum: %04x",
- po->proto.name, lsa.type, lsa.id, lsa.rt, lsa.age, lsa.sn, lsa.checksum);
+ po->proto.name, lsa_type, lsa.id, lsa.rt, lsa.age, lsa.sn, lsa.checksum);
}
void ospf_dump_common(struct proto_ospf *po, struct ospf_packet *pkt)
log(L_TRACE "%s: router %R", p->name, ntohl(pkt->routerid));
}
-static void ospf_dump_lsupd(struct proto_ospf *po, struct ospf_lsupd_packet *pkt)
+static inline unsigned
+ospf_lsupd_hdrlen(struct proto_ospf *po)
+{
+ return ospf_pkt_hdrlen(po) + 4; /* + u32 lsa count field */
+}
+
+static inline u32 *
+ospf_lsupd_lsa_count(struct ospf_packet *pkt, unsigned hdrlen)
+{ return ((void *) pkt) + hdrlen - 4; }
+
+static inline void
+ospf_lsupd_body(struct proto_ospf *po, struct ospf_packet *pkt,
+ unsigned *offset, unsigned *bound, unsigned *lsa_count)
+{
+ unsigned hlen = ospf_lsupd_hdrlen(po);
+ *offset = hlen;
+ *bound = ntohs(pkt->length) - sizeof(struct ospf_lsa_header);
+ *lsa_count = ntohl(*ospf_lsupd_lsa_count(pkt, hlen));
+}
+
+static void ospf_lsupd_dump(struct proto_ospf *po, struct ospf_packet *pkt)
{
struct proto *p = &po->proto;
- struct ospf_packet *op = &pkt->ospf_packet;
- ASSERT(op->type == LSUPD_P);
- ospf_dump_common(po, op);
+ ASSERT(pkt->type == LSUPD_P);
+ ospf_dump_common(po, pkt);
- /* We know that ntohs(op->length) >= sizeof(struct ospf_lsa_header) */
- u8 *pbuf= (u8 *) pkt;
- unsigned int offset = sizeof(struct ospf_lsupd_packet);
- unsigned int bound = ntohs(op->length) - sizeof(struct ospf_lsa_header);
- unsigned int i, j, lsalen;
+ /* We know that ntohs(pkt->length) >= sizeof(struct ospf_lsa_header) */
+ unsigned offset, bound, i, lsa_count, lsalen;
+ ospf_lsupd_body(po, pkt, &offset, &bound, &lsa_count);
- j = ntohl(pkt->lsano);
- for (i = 0; i < j; i++)
+ for (i = 0; i < lsa_count; i++)
{
if (offset > bound)
{
return;
}
- struct ospf_lsa_header *lsa = (void *) (pbuf + offset);
- ospf_dump_lsahdr(p, lsa);
+ struct ospf_lsa_header *lsa = ((void *) pkt) + offset;
+ ospf_dump_lsahdr(po, lsa);
lsalen = ntohs(lsa->length);
offset += lsalen;
}
-#ifdef OSPFv2
-
-int
-ospf_lsa_flooding_allowed(struct ospf_lsa_header *lsa, u32 domain, struct ospf_iface *ifa)
-{
- if (lsa->type == LSA_T_EXT)
- {
- if (ifa->type == OSPF_IT_VLINK)
- return 0;
- if (!oa_is_ext(ifa->oa))
- return 0;
- return 1;
- }
- else
- return ifa->oa->areaid == domain;
-}
-
-#else /* OSPFv3 */
-
-static int
-unknown_lsa_type(struct ospf_lsa_header *lsa)
-{
- switch (lsa->type)
- {
- case LSA_T_RT:
- case LSA_T_NET:
- case LSA_T_SUM_NET:
- case LSA_T_SUM_RT:
- case LSA_T_EXT:
- case LSA_T_NSSA:
- case LSA_T_LINK:
- case LSA_T_PREFIX:
- return 0;
-
- default:
- return 1;
- }
-}
-
-int
-ospf_lsa_flooding_allowed(struct ospf_lsa_header *lsa, u32 domain, struct ospf_iface *ifa)
-{
- u32 scope = LSA_SCOPE(lsa);
-
- /* 4.5.2 (Case 2) */
- if (unknown_lsa_type(lsa) && !(lsa->type & LSA_UBIT))
- scope = LSA_SCOPE_LINK;
-
- switch (scope)
- {
- case LSA_SCOPE_LINK:
- return ifa->iface->index == domain;
-
- case LSA_SCOPE_AREA:
- return ifa->oa->areaid == domain;
-
- case LSA_SCOPE_AS:
- if (ifa->type == OSPF_IT_VLINK)
- return 0;
- if (!oa_is_ext(ifa->oa))
- return 0;
- return 1;
-
- default:
- log(L_ERR "LSA with invalid scope");
- return 0;
- }
-}
-
-#endif
-
/**
* ospf_lsupd_flood - send received or generated lsa to the neighbors
* @po: OSPF protocol
{
u16 len, age;
- struct ospf_lsupd_packet *pk;
- struct ospf_packet *op;
+ unsigned hlen;
+ struct ospf_packet *pkt;
struct ospf_lsa_header *lh;
- pk = ospf_tx_buffer(ifa);
- op = &pk->ospf_packet;
+ pkt = ospf_tx_buffer(ifa);
+ hlen = ospf_lsupd_hdrlen(po);
- ospf_pkt_fill_hdr(ifa, pk, LSUPD_P);
- pk->lsano = htonl(1);
-
- lh = (struct ospf_lsa_header *) (pk + 1);
+ ospf_pkt_fill_hdr(ifa, pkt, LSUPD_P);
+ *ospf_lsupd_lsa_count(pkt, hlen) = htonl(1);
+ lh = (((void *) pkt) + hlen);
/* Copy LSA into the packet */
if (hn)
u8 *help;
struct top_hash_entry *en;
- htonlsah(hh, lh);
+ lsa_hton_hdr(hh, lh);
help = (u8 *) (lh + 1);
en = ospf_hash_find_header(po->gr, domain, hh);
- htonlsab(en->lsa_body, help, hh->length - sizeof(struct ospf_lsa_header));
+ lsa_hton_body(en->lsa_body, help, hh->length - sizeof(struct ospf_lsa_header));
}
- len = sizeof(struct ospf_lsupd_packet) + ntohs(lh->length);
-
age = ntohs(lh->age);
age += ifa->inftransdelay;
if (age > LSA_MAXAGE)
age = LSA_MAXAGE;
lh->age = htons(age);
- op->length = htons(len);
+ len = hlen + ntohs(lh->length);
+ pkt->length = htons(len);
- OSPF_PACKET(ospf_dump_lsupd, pk, "LSUPD packet flooded via %s", ifa->iface->name);
+ OSPF_PACKET(ospf_lsupd_dump, pkt, "LSUPD packet flooded via %s", ifa->iface->name);
switch (ifa->type)
{
case OSPF_IT_BCAST:
if ((ifa->state == OSPF_IS_BACKUP) || (ifa->state == OSPF_IS_DR))
ospf_send_to_all(ifa);
- else if (ifa->cf->real_bcast)
- ospf_send_to_bdr(ifa);
else
- ospf_send_to(ifa, AllDRouters);
+ ospf_send_to_des(ifa);
break;
case OSPF_IT_NBMA:
}
void /* I send all I received in LSREQ */
-ospf_lsupd_send_list(struct ospf_neighbor *n, list * l)
+ospf_lsupd_send_list(struct ospf_neighbor *n, struct ospf_lsreq_item *lsr)
{
struct ospf_area *oa = n->ifa->oa;
struct proto_ospf *po = oa->po;
- struct l_lsr_head *lsr;
struct top_hash_entry *en;
- struct ospf_lsupd_packet *pkt;
- u32 len, len2, lsano;
- char *buf;
+ struct ospf_packet *pkt;
+ unsigned hlen, pos, pos2, maxsize, lsano;
pkt = ospf_tx_buffer(n->ifa);
- buf = (void *) pkt;
+ hlen = ospf_lsupd_hdrlen(po);
+ maxsize = ospf_pkt_maxsize(n->ifa);
- lsr = HEAD(*l);
- while(NODE_NEXT(lsr))
+ while (lsr)
{
/* Prepare the packet */
ospf_pkt_fill_hdr(n->ifa, pkt, LSUPD_P);
- len = sizeof(struct ospf_lsupd_packet);
+ pos = hlen;
lsano = 0;
/* Fill the packet with LSAs */
- while(NODE_NEXT(lsr))
+ while (lsr)
{
- u32 domain = ospf_lsa_domain(lsr->lsh.type, n->ifa);
- en = ospf_hash_find(oa->po->gr, domain, lsr->lsh.id, lsr->lsh.rt, lsr->lsh.type);
- if (en == NULL)
+ en = ospf_hash_find(oa->po->gr, lsr->domain, lsr->id, lsr->rt, lsr->type);
+ if (!en)
{
/* Probably flushed LSA, this should not happen */
log(L_WARN "OSPF: LSA disappeared (Type: %04x, Id: %R, Rt: %R)",
- lsr->lsh.type, lsr->lsh.id, lsr->lsh.rt);
- lsr = NODE_NEXT(lsr);
- continue;
+ lsr->type, lsr->id, lsr->rt);
+ lsr = lsr->next;
+ continue;
}
- len2 = len + en->lsa.length;
- if (len2 > ospf_pkt_maxsize(n->ifa))
+ pos2 = pos + en->lsa.length;
+ if (pos2 > maxsize)
{
/* The packet if full, stop adding LSAs and sent it */
if (lsano > 0)
break;
/* LSA is larger than MTU, check buffer size */
- if (len2 > ospf_pkt_bufsize(n->ifa))
+ if (pos2 > ospf_pkt_bufsize(n->ifa))
{
/* Cannot fit in a tx buffer, skip that */
log(L_WARN "OSPF: LSA too large to send (Type: %04x, Id: %R, Rt: %R)",
- lsr->lsh.type, lsr->lsh.id, lsr->lsh.rt);
- lsr = NODE_NEXT(lsr);
+ lsr->type, lsr->id, lsr->rt);
+ lsr = lsr->next;
continue;
}
}
/* Copy the LSA to the packet */
- htonlsah(&(en->lsa), (struct ospf_lsa_header *) (buf + len));
- htonlsab(en->lsa_body, buf + len + sizeof(struct ospf_lsa_header),
- en->lsa.length - sizeof(struct ospf_lsa_header));
- len = len2;
+ void *lsabuf = ((void *) pkt) + pos;
+ lsa_hton_hdr(&(en->lsa), (struct ospf_lsa_header *) lsabuf);
+ lsa_hton_body(en->lsa_body, lsabuf + sizeof(struct ospf_lsa_header),
+ en->lsa.length - sizeof(struct ospf_lsa_header));
+ pos = pos2;
lsano++;
- lsr = NODE_NEXT(lsr);
+ lsr = lsr->next;
}
if (lsano == 0)
break;
/* Send the packet */
- pkt->lsano = htonl(lsano);
- pkt->ospf_packet.length = htons(len);
- OSPF_PACKET(ospf_dump_lsupd, pkt, "LSUPD packet sent to %I via %s",
+ pkt->length = htons(pos);
+ *ospf_lsupd_lsa_count(pkt, hlen) = htonl(lsano);
+ OSPF_PACKET(ospf_lsupd_dump, pkt, "LSUPD packet sent to %I via %s",
n->ip, n->ifa->iface->name);
ospf_send_to(n->ifa, n->ip);
}
}
void
-ospf_lsupd_receive(struct ospf_packet *ps_i, struct ospf_iface *ifa,
+ospf_lsupd_receive(struct ospf_packet *pkt, struct ospf_iface *ifa,
struct ospf_neighbor *n)
{
struct ospf_neighbor *ntmp;
struct proto_ospf *po = ifa->oa->po;
struct proto *p = &po->proto;
- unsigned int i, max, sendreq = 1;
+ unsigned sendreq = 1;
- unsigned int size = ntohs(ps_i->length);
- if (size < (sizeof(struct ospf_lsupd_packet) + sizeof(struct ospf_lsa_header)))
+ unsigned plen = ntohs(pkt->length);
+ if (plen < (ospf_lsupd_hdrlen(po) + sizeof(struct ospf_lsa_header)))
{
- log(L_ERR "OSPF: Bad LSUPD packet from %I - too short (%u B)", n->ip, size);
+ log(L_ERR "OSPF: Bad LSUPD packet from %I - too short (%u B)", n->ip, plen);
return;
}
- struct ospf_lsupd_packet *ps = (void *) ps_i;
- OSPF_PACKET(ospf_dump_lsupd, ps, "LSUPD packet received from %I via %s", n->ip, ifa->iface->name);
+ OSPF_PACKET(ospf_lsupd_dump, pkt, "LSUPD packet received from %I via %s", n->ip, ifa->iface->name);
if (n->state < NEIGHBOR_EXCHANGE)
{
ospf_neigh_sm(n, INM_HELLOREC); /* Questionable */
- unsigned int offset = sizeof(struct ospf_lsupd_packet);
- unsigned int bound = size - sizeof(struct ospf_lsa_header);
+ unsigned offset, bound, i, lsa_count;
+ ospf_lsupd_body(po, pkt, &offset, &bound, &lsa_count);
- max = ntohl(ps->lsano);
- for (i = 0; i < max; i++)
+ for (i = 0; i < lsa_count; i++)
{
struct ospf_lsa_header lsatmp;
struct top_hash_entry *lsadb;
if (offset > bound)
{
- log(L_WARN "Received lsupd from %I is too short!", n->ip);
+ log(L_WARN "OSPF: Received LSUPD from %I is too short", n->ip);
ospf_neigh_sm(n, INM_BADLSREQ);
return;
}
- struct ospf_lsa_header *lsa = (void *) (((u8 *) ps) + offset);
+ struct ospf_lsa_header *lsa = ((void *) pkt) + offset;
unsigned int lsalen = ntohs(lsa->length);
offset += lsalen;
- if ((offset > size) || ((lsalen % 4) != 0) ||
+ if ((offset > plen) || ((lsalen % 4) != 0) ||
(lsalen <= sizeof(struct ospf_lsa_header)))
{
- log(L_WARN "Received LSA from %I with bad length", n->ip);
+ log(L_WARN "OSPF: Received LSA from %I with bad length", n->ip);
ospf_neigh_sm(n, INM_BADLSREQ);
break;
}
u16 chsum = lsa->checksum;
if (chsum != lsasum_check(lsa, NULL))
{
- log(L_WARN "Received bad lsa checksum from %I: %x %x", n->ip, chsum, lsa->checksum);
+ log(L_WARN "OSPF: Received LSA from %I with bad checskum: %x %x",
+ n->ip, chsum, lsa->checksum);
continue;
}
- u16 lsa_type = ntohs(lsa->type_raw);
- lsa_type = xxxx(lsa_type); // XXXX finish
-#ifdef OSPFv2
+ u32 lsa_type, lsa_domain;
+ lsa_ntoh_hdr(lsa, &lsatmp);
+ lsa_xxxxtype(lsatmp.type_raw, ifa, &lsa_type, &lsa_domain);
+
/* pg 143 (2) */
- if ((lsa->type == 0) || (lsa->type == 6) || (lsa->type > LSA_T_NSSA))
+ if (!lsa_type)
{
- log(L_WARN "Unknown LSA type from %I", n->ip);
+ log(L_WARN "OSPF: Received unknown LSA type from %I", n->ip);
continue;
}
- /* pg 143 (3) */
- if ((lsa_type == LSA_T_EXT) && !oa_is_ext(ifa->oa))
- {
- log(L_WARN "Received External LSA in stub area from %I", n->ip);
- continue;
- }
-#else /* OSPFv3 */
/* 4.5.1 (2) */
if ((LSA_SCOPE(lsa_type) == LSA_SCOPE_AS) && !oa_is_ext(ifa->oa))
{
- log(L_WARN "Received LSA with AS scope in stub area from %I", n->ip);
+ log(L_WARN "OSPF: Received LSA with AS scope in stub area from %I", n->ip);
continue;
}
/* 4.5.1 (3) */
- if ((LSA_SCOPE(lsa_type) == LSA_SCOPE_RES))
+ if (LSA_SCOPE(lsa_type) == LSA_SCOPE_RES)
{
- log(L_WARN "Received LSA with invalid scope from %I", n->ip);
+ log(L_WARN "OSPF: Received LSA with invalid scope from %I", n->ip);
continue;
}
-#endif
-
- ntohlsah(lsa, &lsatmp);
- DBG("Update Type: %u ID: %R RT: %R, Sn: 0x%08x Age: %u, Sum: %u\n",
+ DBG("Update Type: %04x, Id: %R, Rt: %R, Sn: 0x%08x, Age: %u, Sum: %u\n",
lsa_type, lsatmp.id, lsatmp.rt, lsatmp.sn, lsatmp.age, lsatmp.checksum);
- /* FIXME domain should be link id for unknown LSA types with zero Ubit */
- u32 domain = ospf_lsa_domain(lsa_type, ifa);
- lsadb = ospf_hash_find_header(po->gr, domain, &lsatmp);
+ lsadb = ospf_hash_find(po->gr, lsa_domain, lsatmp.id, lsatmp.rt, lsa_type);
#ifdef LOCAL_DEBUG
if (lsadb)
- DBG("I have Type: %u ID: %R RT: %R, Sn: 0x%08x Age: %u, Sum: %u\n",
- lsadb->lsa.type, lsadb->lsa.id, lsadb->lsa.rt,
+ DBG("I have Type: %04x, Id: %R, Rt: %R, Sn: 0x%08x, Age: %u, Sum: %u\n",
+ lsadb->lsa_type, lsadb->lsa.id, lsadb->lsa.rt,
lsadb->lsa.sn, lsadb->lsa.age, lsadb->lsa.checksum);
#endif
lsadb->inst_t = now;
lsadb->ini_age = 0;
lsasum_calculate(&lsadb->lsa, lsadb->lsa_body);
- ospf_lsupd_flood(po, NULL, NULL, &lsadb->lsa, domain, 1);
+ ospf_lsupd_flood(po, NULL, NULL, &lsadb->lsa, lsa_domain, 1);
}
else
{
lsa->sn = htonl(LSA_MAXSEQNO);
lsasum_check(lsa, (lsa + 1)); /* It also calculates chsum! */
lsatmp.checksum = ntohs(lsa->checksum);
- ospf_lsupd_flood(po, NULL, lsa, &lsatmp, domain, 0);
+ ospf_lsupd_flood(po, NULL, lsa, &lsatmp, lsa_domain, 0);
}
continue;
}
{
struct top_hash_entry *en;
if (ntmp->state > NEIGHBOR_EXSTART)
- if ((en = ospf_hash_find_header(ntmp->lsrth, domain, &lsadb->lsa)) != NULL)
+ if ((en = ospf_hash_find_header(ntmp->lsrth, lsa_domain, &lsadb->lsa)) != NULL)
{
s_rem_node(SNODE en);
ospf_hash_delete(ntmp->lsrth, en);
}
/* pg 144 (5b) */
- if (ospf_lsupd_flood(po, n, lsa, &lsatmp, domain, 1) == 0)
+ if (ospf_lsupd_flood(po, n, lsa, &lsatmp, lsa_domain, 1) == 0)
{
DBG("Wasn't flooded back\n"); /* ps 144(5e), pg 153 */
if (ifa->state == OSPF_IS_BACKUP)
/* pg 144 (5d) */
void *body = mb_alloc(p->pool, lsatmp.length - sizeof(struct ospf_lsa_header));
- ntohlsab(lsa + 1, body, lsatmp.length - sizeof(struct ospf_lsa_header));
+ lsa_ntoh_body(lsa + 1, body, lsatmp.length - sizeof(struct ospf_lsa_header));
/* We will do validation check after flooding and
acknowledging given LSA to minimize problems
when communicating with non-validating peer */
- if (lsa_validate(&lsatmp, body) == 0)
+ if (lsa_validate(&lsatmp, lsa_type, ospf_is_v2(po), body) == 0)
{
log(L_WARN "Received invalid LSA from %I", n->ip);
mb_free(body);
continue;
}
- lsadb = lsa_install_new(po, &lsatmp, domain, body);
+ lsadb = lsa_install_new(po, &lsatmp, lsa_domain, body);
DBG("New LSA installed in DB\n");
-#ifdef OSPFv3
/* Events 6,7 from RFC5340 4.4.3. */
if ((lsa_type == LSA_T_LINK) && (ifa->state == OSPF_IS_DR))
schedule_net_lsa(ifa);
-#endif
continue;
}
continue;
}
- {
- list l;
- struct l_lsr_head ll;
- init_list(&l);
- ll.lsh.id = lsadb->lsa.id;
- ll.lsh.rt = lsadb->lsa.rt;
- ll.lsh.type = lsadb->lsa.type;
- add_tail(&l, NODE & ll);
- ospf_lsupd_send_list(n, &l);
- }
+ struct ospf_lsreq_item lsr = {
+ .domain = lsadb->domain,
+ .type = lsadb->lsa_type,
+ .id = lsadb->lsa.id,
+ .rt = lsadb->lsa.rt
+ };
+ ospf_lsupd_send_list(n, &lsr);
}
/* Send direct LSAs */
void ospf_dump_lsahdr(struct proto_ospf *po, struct ospf_lsa_header *lsa_n);
void ospf_dump_common(struct proto_ospf *po, struct ospf_packet *pkt);
-void ospf_lsupd_send_list(struct ospf_neighbor *n, list * l);
+void ospf_lsupd_send_list(struct ospf_neighbor *n, struct ospf_lsreq_item *lsr);
void ospf_lsupd_receive(struct ospf_packet *ps_i,
struct ospf_iface *ifa, struct ospf_neighbor *n);
int ospf_lsupd_flood(struct proto_ospf *po,
};
static void neigh_chstate(struct ospf_neighbor *n, u8 state);
-static struct ospf_neighbor *electbdr(list nl);
-static struct ospf_neighbor *electdr(list nl);
+static struct ospf_neighbor *electbdr(struct proto_ospf *, list nl);
+static struct ospf_neighbor *electdr(struct proto_ospf *, list nl);
static void neighbor_timer_hook(timer * timer);
static void rxmt_timer_hook(timer * timer);
static void ackd_timer_hook(timer * t);
{
s_init_list(&(n->lsrql));
n->lsrqh = ospf_top_new(n->pool);
- s_init(&(n->lsrqi), &(n->lsrql));
s_init_list(&(n->lsrtl));
n->lsrth = ospf_top_new(n->pool);
- s_init(&(n->lsrti), &(n->lsrtl));
}
/* Resets LSA request and retransmit lists.
}
}
+static inline u32 neigh_get_id(struct proto_ospf *po, struct ospf_neighbor *n)
+{ return ospf_is_v2(po) ? ipa_to_u32(n->ip) : n->rid; }
+
static struct ospf_neighbor *
-electbdr(list nl)
+electbdr(struct proto_ospf *po, list nl)
{
struct ospf_neighbor *neigh, *n1, *n2;
u32 nid;
n2 = NULL;
WALK_LIST(neigh, nl) /* First try those decl. themselves */
{
-#ifdef OSPFv2
- nid = ipa_to_u32(neigh->ip);
-#else /* OSPFv3 */
- nid = neigh->rid;
-#endif
+ nid = neigh_get_id(po, neigh);
if (neigh->state >= NEIGHBOR_2WAY) /* Higher than 2WAY */
if (neigh->priority > 0) /* Eligible */
}
static struct ospf_neighbor *
-electdr(list nl)
+electdr(struct proto_ospf *po, list nl)
{
struct ospf_neighbor *neigh, *n;
u32 nid;
n = NULL;
WALK_LIST(neigh, nl) /* And now DR */
{
-#ifdef OSPFv2
- nid = ipa_to_u32(neigh->ip);
-#else /* OSPFv3 */
- nid = neigh->rid;
-#endif
+ nid = neigh_get_id(po, neigh);
if (neigh->state >= NEIGHBOR_2WAY) /* Higher than 2WAY */
if (neigh->priority > 0) /* Eligible */
me.priority = ifa->priority;
me.ip = ifa->addr->ip;
-#ifdef OSPFv2
- me.dr = ipa_to_u32(ifa->drip);
- me.bdr = ipa_to_u32(ifa->bdrip);
-#else /* OSPFv3 */
- me.dr = ifa->drid;
- me.bdr = ifa->bdrid;
+ me.dr = ospf_is_v2(po) ? ipa_to_u32(ifa->drip) : ifa->drid;
+ me.bdr = ospf_is_v2(po) ? ipa_to_u32(ifa->bdrip) : ifa->bdrid;
me.iface_id = ifa->iface->index;
-#endif
add_tail(&ifa->neigh_list, NODE & me);
- nbdr = electbdr(ifa->neigh_list);
- ndr = electdr(ifa->neigh_list);
+ nbdr = electbdr(po, ifa->neigh_list);
+ ndr = electdr(po, ifa->neigh_list);
if (ndr == NULL)
ndr = nbdr;
|| ((ifa->bdrid == myid) && (nbdr != &me))
|| ((ifa->bdrid != myid) && (nbdr == &me)))
{
-#ifdef OSPFv2
- me.dr = ndr ? ipa_to_u32(ndr->ip) : 0;
- me.bdr = nbdr ? ipa_to_u32(nbdr->ip) : 0;
-#else /* OSPFv3 */
- me.dr = ndr ? ndr->rid : 0;
- me.bdr = nbdr ? nbdr->rid : 0;
-#endif
+ me.dr = ndr ? neigh_get_id(po, ndr) : 0;
+ me.bdr = nbdr ? neigh_get_id(po, nbdr) : 0;
- nbdr = electbdr(ifa->neigh_list);
- ndr = electdr(ifa->neigh_list);
+ nbdr = electbdr(po, ifa->neigh_list);
+ ndr = electdr(po, ifa->neigh_list);
if (ndr == NULL)
ndr = nbdr;
ifa->drid = ndr ? ndr->rid : 0;
ifa->drip = ndr ? ndr->ip : IPA_NONE;
+ ifa->dr_iface_id = ndr ? ndr->iface_id : 0;
+
ifa->bdrid = nbdr ? nbdr->rid : 0;
ifa->bdrip = nbdr ? nbdr->ip : IPA_NONE;
-#ifdef OSPFv3
- ifa->dr_iface_id = ndr ? ndr->iface_id : 0;
-#endif
-
DBG("DR=%R, BDR=%R\n", ifa->drid, ifa->bdrid);
doadj = ((ifa->drid != odrid) || (ifa->bdrid != obdrid));
{
if (!EMPTY_SLIST(n->lsrtl)) /* FULL */
{
- list uplist;
- slab *upslab;
- struct l_lsr_head *llsh;
+ struct ospf_lsreq_item *lsr_head, *lsr;
+ struct ospf_lsreq_item **lsr_pos = &lsr_head;
- init_list(&uplist);
- upslab = sl_new(n->pool, sizeof(struct l_lsr_head));
+ slab *upslab = sl_new(n->pool, sizeof(struct ospf_lsreq_item));
WALK_SLIST(en, n->lsrtl)
{
if ((SNODE en)->next == (SNODE en))
bug("RTList is cycled");
- llsh = sl_alloc(upslab);
- llsh->lsh.id = en->lsa.id;
- llsh->lsh.rt = en->lsa.rt;
- llsh->lsh.type = en->lsa.type;
- DBG("Working on ID: %R, RT: %R, Type: %u\n",
- en->lsa.id, en->lsa.rt, en->lsa.type);
- add_tail(&uplist, NODE llsh);
+
+ lsr = sl_alloc(upslab);
+ lsr->domain = en->domain;
+ lsr->type = en->lsa_type;
+ lsr->id = en->lsa.id;
+ lsr->rt = en->lsa.rt;
+
+ *lsr_pos = lsr;
+ lsr_pos = &(lsr->next);
}
- ospf_lsupd_send_list(n, &uplist);
+ *lsr_pos = NULL;
+
+ ospf_lsupd_send_list(n, lsr_head);
rfree(upslab);
}
}
if (oa->areaid == 0)
po->backbone = oa;
-#ifdef OSPFv2
- oa->options = ac->type;
-#else /* OSPFv3 */
- oa->options = OPT_R | ac->type | OPT_V6;
-#endif
+ oa->options = ospf_is_v2(po) ? ac->type : (OPT_R | ac->type | OPT_V6);
/*
* Set E-bit for NSSA ABR routers. No need to explicitly call
ifa->orignet = 1;
}
-#ifdef OSPFv3
void
schedule_link_lsa(struct ospf_iface *ifa)
{
OSPF_TRACE(D_EVENTS, "Scheduling link-LSA origination for iface %s", ifa->iface->name);
ifa->origlink = 1;
}
-#endif
void
schedule_rt_lsa(struct ospf_area *oa)
// FIXME check for gw should be per ifa, not per iface
if ((new->attrs->dest == RTD_ROUTER) &&
ipa_nonzero(new->attrs->gw) &&
- !ipa_has_link_scope(new->attrs->gw) &&
+ !ipa_is_link_local(new->attrs->gw) &&
(ospf_iface_find((struct proto_ospf *) p, new->attrs->iface) != NULL))
gw = new->attrs->gw;
oa->ac = nac;
// FIXME better area type reconfiguration
-#ifdef OSPFv2
- oa->options = nac->type;
-#else /* OSPFv3 */
- oa->options = OPT_R | nac->type | OPT_V6;
-#endif
+ oa->options = ospf_is_v2(oa->po) ? nac->type : (OPT_R | nac->type | OPT_V6);
+
if (oa_is_nssa(oa) && (oa->po->areano > 1))
oa->po->ebit = 1;
if (nt1)
{
#ifdef OSPFv3
- /* In OSPFv3, neworks are named base on ID of DR */
+ /* In OSPFv3, networks are named based on ID of DR */
if (lsa1->rt != lsa2->rt)
return lsa1->rt - lsa2->rt;
#endif
case LSA_SCOPE_AS:
cli_msg(-1017, "Global");
break;
+
case LSA_SCOPE_AREA:
cli_msg(-1017, "Area %R", hea[i]->domain);
break;
-#ifdef OSPFv3
+
case LSA_SCOPE_LINK:
{
struct iface *ifa = if_find_by_index(hea[i]->domain);
cli_msg(-1017, "Link %s", (ifa != NULL) ? ifa->name : "?");
}
break;
-#endif
}
cli_msg(-1017, "");
cli_msg(-1017," Type LS ID Router Age Sequence Checksum");
last_domain = hea[i]->domain;
}
-
cli_msg(-1017," %04x %-15R %-15R %5u %08x %04x",
lsa->type, lsa->id, lsa->rt, lsa->age, lsa->sn, lsa->checksum);
}
#define MINLSARRIVAL 1
#define LSINFINITY 0xffffff
-#define DEFAULT_OSPFTICK 1
-#define DEFAULT_RFC1583 0 /* compatibility with rfc1583 */
-#define DEFAULT_STUB_COST 1000
-#define DEFAULT_ECMP_LIMIT 16
-#define DEFAULT_TRANSINT 40
+#define OSPF_DEFAULT_TICK 1
+#define OSPF_DEFAULT_STUB_COST 1000
+#define OSPF_DEFAULT_ECMP_LIMIT 16
+#define OSPF_DEFAULT_TRANSINT 40
struct ospf_config
u16 autype;
u32 csn; /* Last used crypt seq number */
bird_clock_t csn_use; /* Last time when packet with that CSN was sent */
- ip_addr all_routers; /* */
- ip_addr drip; /* Designated router */
- ip_addr bdrip; /* Backup DR */
- u32 drid;
- u32 bdrid;
+ ip_addr all_routers; /* XXXX */
+ ip_addr des_routers; /* XXXX */
+ ip_addr drip; /* Designated router IP */
+ ip_addr bdrip; /* Backup DR IP */
+ u32 drid; /* DR Router ID */
+ u32 bdrid; /* BDR Router ID */
s16 rt_pos_beg; /* Position of iface in Router-LSA, begin, inclusive */
s16 rt_pos_end; /* Position of iface in Router-LSA, end, exclusive */
s16 px_pos_beg; /* Position of iface in Rt Prefix-LSA, begin, inclusive */
#define OSPF_I_OK 0 /* Everything OK */
#define OSPF_I_SK 1 /* Socket open failed */
#define OSPF_I_LL 2 /* Missing link-local address (OSPFv3) */
- u8 sk_dr; /* Socket is a member of DRouters group */
+ u8 sk_dr; /* Socket is a member of designated routers group */
u8 marked; /* Used in OSPF reconfigure */
u16 rxbuf; /* Buffer size */
u8 check_link; /* Whether iface link change is used */
/* Area IDs */
#define BACKBONE 0
-
#define DBDES_I 4 /* Init bit */
#define DBDES_M 2 /* More bit */
#define DBDES_MS 1 /* Master/Slave bit */
-
/*
* There is slight difference in OSPF packet header between v2 and v3
* in vdep field. For OSPFv2, vdep is u16 authentication type and
u16 vdep;
};
+static inline u16 ospf_pkt_get_autype(struct ospf_packet *pkt)
+{ return ntohs(pkt->vdep); }
+
+static inline void ospf_pkt_set_autype(struct ospf_packet *pkt, u16 val)
+{ pkt->vdep = htons(val); }
+
+static inline u8 ospf_pkt_get_instance_id(struct ospf_packet *pkt)
+{ return ntohs(pkt->vdep) >> 8; }
+
+static inline void ospf_pkt_set_instance_id(struct ospf_packet *pkt, u16 val)
+{ pkt->vdep = htons(val << 8); }
+
// XXXX
/*
#define LSA_T_LINK 0x0008
#define LSA_T_PREFIX 0x2009
+#define LSA_T_V2_MASK 0x00ff
+
#define LSA_UBIT 0x8000
#define LSA_SCOPE_LINK 0x0000
#define LSA_SCOPE_AS 0x4000
#define LSA_SCOPE_RES 0x6000
#define LSA_SCOPE_MASK 0x6000
-#define LSA_SCOPE(lsa) ((lsa) & LSA_SCOPE_MASK)
+#define LSA_SCOPE(type) ((type) & LSA_SCOPE_MASK)
#define LSA_MAXAGE 3600 /* 1 hour */
#define LSART_STUB 3
#define LSART_VLNK 4
+#define LSA_RT2_LINKS 0x0000FFFF
+
#define LSA_SUM2_TOS 0xFF000000
#define LSA_EXT2_TOS 0x7F000000
#endif
};
+struct ospf_lsa_rt2_tos
+{
+#ifdef CPU_BIG_ENDIAN
+ u8 tos;
+ u8 padding;
+ u16 metric;
+#else
+ u16 metric;
+ u8 padding;
+ u8 tos;
+#endif
+};
+
struct ospf_lsa_rt3_link
{
#ifdef CPU_BIG_ENDIAN
};
-
-
-#ifdef OSPFv2
-
-
-/* Endianity swap for lsa->type */
-#define ntoht(x) x
-#define htont(x) x
-
-
-#else /* OSPFv3 */
-
-
-
-
-/* Endianity swap for lsa->type */
-#define ntoht(x) ntohs(x)
-#define htont(x) htons(x)
-
-#endif
-
#define METRIC_MASK 0x00FFFFFF
#define OPTIONS_MASK 0x00FFFFFF
}
-#ifdef OSPFv3
-
#define IPV6_PREFIX_SPACE(x) ((((x) + 63) / 32) * 4)
#define IPV6_PREFIX_WORDS(x) (((x) + 63) / 32)
return buf + 4;
}
-#endif
-
-
struct ospf_lsreq_header
{
u32 type;
u32 id;
- u32 rt; /* Advertising router */
+ u32 rt;
};
-struct l_lsr_head
+struct ospf_lsreq_item
{
- node n;
- struct ospf_lsreq_header lsh;
+ struct ospf_lsreq_item *next;
+ u32 domain;
+ u32 type;
+ u32 id;
+ u32 rt;
};
u8 adj; /* built adjacency? */
u32 options; /* Options received */
- /* dr and bdr store IP address in OSPFv2 and router ID in OSPFv3,
- we use the same type to simplify handling */
+ /* Entries dr and bdr store IP addresses in OSPFv2 and router IDs in
+ * OSPFv3, we use the same type to simplify handling
+ */
u32 dr; /* Neigbour's idea of DR */
u32 bdr; /* Neigbour's idea of BDR */
u32 iface_id; /* ID of Neighbour's iface connected to common network */
- siterator dbsi; /* Database summary list iterator */
- slist lsrql; /* Link state request */
- struct top_graph *lsrqh; /* LSA graph */
- siterator lsrqi;
- slist lsrtl; /* Link state retransmission list */
- siterator lsrti;
+ /* Database summary list iterator, controls initial dbdes exchange.
+ * Advances in the LSA list as dbdes packets are sent.
+ */
+ siterator dbsi; /* iterator of po->lsal */
+
+ /* Link state request list, controls initial LSA exchange.
+ * Entries added when received in dbdes packets, removed as sent in lsreq packets.
+ */
+ slist lsrql; /* slist of struct top_hash_entry from n->lsrqh */
+ struct top_graph *lsrqh;
+
+ /* Link state retransmission list, controls LSA retransmission during flood.
+ * Entries added as sent in lsupd packets, removed when received in lsack packets.
+ */
+ slist lsrtl; /* slist of struct top_hash_entry from n->lsrth */
struct top_graph *lsrth;
+
void *ldbdes; /* Last database description packet */
timer *rxmt_timer; /* RXMT timer */
list ackl[2];
pkt->routerid = htonl(po->router_id);
pkt->areaid = htonl(ifa->oa->areaid);
-
-#ifdef OSPFv3
- pkt->instance_id = ifa->instance_id;
-#endif
-
-#ifdef OSPFv2
- pkt->autype = htons(ifa->autype);
-#endif
-
pkt->checksum = 0;
+
+ if (ospf_is_v2(po))
+ ospf_pkt_set_autype(pkt, ifa->autype);
+ else
+ ospf_pkt_set_instance_id(pkt, ifa->instance_id);
}
unsigned
unsigned mtu = (ifa->type == OSPF_IT_VLINK) ? OSPF_VLINK_MTU : ifa->iface->mtu;
unsigned headers = SIZE_OF_IP_HEADER;
-#ifdef OSPFv2
+ /* For OSPFv2 */
if (ifa->autype == OSPF_AUTH_CRYPT)
headers += OSPF_AUTH_CRYPT_SIZE;
-#endif
return mtu - headers;
}
-#ifdef OSPFv2
+/* We assume OSPFv2 in ospf_pkt_finalize() */
static void
ospf_pkt_finalize(struct ospf_iface *ifa, struct ospf_packet *pkt)
{
struct password_item *passwd = NULL;
- void *tail;
- struct MD5Context ctxt;
- char password[OSPF_AUTH_CRYPT_SIZE];
+ union ospf_auth *auth = (void *) (pkt + 1);
+ unsigned plen = ntohs(pkt->length);
pkt->checksum = 0;
- pkt->autype = htons(ifa->autype);
- bzero(&pkt->u, sizeof(union ospf_auth));
+ ospf_pkt_set_autype(pkt, ifa->autype);
+ bzero(auth, sizeof(union ospf_auth));
- /* Compatibility note: pkt->u may contain anything if autype is
+ /* Compatibility note: auth may contain anything if autype is
none, but nonzero values do not work with Mikrotik OSPF */
- switch(ifa->autype)
+ switch (ifa->autype)
{
case OSPF_AUTH_SIMPLE:
passwd = password_find(ifa->passwords, 1);
if (!passwd)
{
- log( L_ERR "No suitable password found for authentication" );
+ log(L_ERR "No suitable password found for authentication");
return;
}
- password_cpy(pkt->u.password, passwd->password, sizeof(union ospf_auth));
+ password_cpy(auth->password, passwd->password, sizeof(union ospf_auth));
+
case OSPF_AUTH_NONE:
- pkt->checksum = ipsum_calculate(pkt, sizeof(struct ospf_packet) -
- sizeof(union ospf_auth), (pkt + 1),
- ntohs(pkt->length) -
- sizeof(struct ospf_packet), NULL);
+ {
+ void *body = (void *) (auth + 1);
+ unsigned blen = plen - sizeof(struct ospf_packet) - sizeof(union ospf_auth);
+ pkt->checksum = ipsum_calculate(pkt, sizeof(struct ospf_packet), body, blen, NULL);
+ }
break;
+
case OSPF_AUTH_CRYPT:
passwd = password_find(ifa->passwords, 0);
if (!passwd)
ifa->csn_use = now;
- pkt->u.md5.keyid = passwd->id;
- pkt->u.md5.len = OSPF_AUTH_CRYPT_SIZE;
- pkt->u.md5.zero = 0;
- pkt->u.md5.csn = htonl(ifa->csn);
- tail = ((void *)pkt) + ntohs(pkt->length);
- MD5Init(&ctxt);
- MD5Update(&ctxt, (char *) pkt, ntohs(pkt->length));
- password_cpy(password, passwd->password, OSPF_AUTH_CRYPT_SIZE);
- MD5Update(&ctxt, password, OSPF_AUTH_CRYPT_SIZE);
- MD5Final(tail, &ctxt);
+ auth->md5.zero = 0;
+ auth->md5.keyid = passwd->id;
+ auth->md5.len = OSPF_AUTH_CRYPT_SIZE;
+ auth->md5.csn = htonl(ifa->csn);
+
+ {
+ void *tail = ((void *) pkt) + plen;
+ char password[OSPF_AUTH_CRYPT_SIZE];
+ password_cpy(password, passwd->password, OSPF_AUTH_CRYPT_SIZE);
+
+ struct MD5Context ctxt;
+ MD5Init(&ctxt);
+ MD5Update(&ctxt, (char *) pkt, plen);
+ MD5Update(&ctxt, password, OSPF_AUTH_CRYPT_SIZE);
+ MD5Final(tail, &ctxt);
+ }
break;
+
default:
bug("Unknown authentication type");
}
}
+/* We assume OSPFv2 in ospf_pkt_checkauth() */
static int
ospf_pkt_checkauth(struct ospf_neighbor *n, struct ospf_iface *ifa, struct ospf_packet *pkt, int size)
{
struct proto_ospf *po = ifa->oa->po;
- struct proto *p = &po->proto;
+ union ospf_auth *auth = (void *) (pkt + 1);
struct password_item *pass = NULL, *ptmp;
- void *tail;
- char md5sum[OSPF_AUTH_CRYPT_SIZE];
char password[OSPF_AUTH_CRYPT_SIZE];
- struct MD5Context ctxt;
+ unsigned plen = ntohs(pkt->length);
+ u16 autype = ospf_pkt_get_autype(pkt);
- if (pkt->autype != htons(ifa->autype))
+ if (autype != ifa->autype)
{
- OSPF_TRACE(D_PACKETS, "OSPF_auth: Method differs (%d)", ntohs(pkt->autype));
+ OSPF_TRACE(D_PACKETS, "OSPF_auth: Method differs (%d)", autype);
return 0;
}
- switch(ifa->autype)
+ switch (autype)
{
case OSPF_AUTH_NONE:
return 1;
break;
+
case OSPF_AUTH_SIMPLE:
pass = password_find(ifa->passwords, 1);
if (!pass)
}
password_cpy(password, pass->password, sizeof(union ospf_auth));
- if (memcmp(pkt->u.password, password, sizeof(union ospf_auth)))
+ if (memcmp(auth->password, password, sizeof(union ospf_auth)))
{
char ppass[sizeof(union ospf_auth) + 1];
bzero(ppass, (sizeof(union ospf_auth) + 1));
- memcpy(ppass, pkt->u.password, sizeof(union ospf_auth));
+ memcpy(ppass, auth->password, sizeof(union ospf_auth));
OSPF_TRACE(D_PACKETS, "OSPF_auth: different passwords (%s)", ppass);
return 0;
}
return 1;
break;
+
case OSPF_AUTH_CRYPT:
- if (pkt->u.md5.len != OSPF_AUTH_CRYPT_SIZE)
+ if (auth->md5.len != OSPF_AUTH_CRYPT_SIZE)
{
OSPF_TRACE(D_PACKETS, "OSPF_auth: wrong size of md5 digest");
return 0;
}
- if (ntohs(pkt->length) + OSPF_AUTH_CRYPT_SIZE > size)
+ if (plen + OSPF_AUTH_CRYPT_SIZE > size)
{
OSPF_TRACE(D_PACKETS, "OSPF_auth: size mismatch (%d vs %d)",
- ntohs(pkt->length) + OSPF_AUTH_CRYPT_SIZE, size);
+ plen + OSPF_AUTH_CRYPT_SIZE, size);
return 0;
}
- tail = ((void *)pkt) + ntohs(pkt->length);
+ if (n)
+ {
+ u32 rcv_csn = ntohl(auth->md5.csn);
+ if(rcv_csn < n->csn)
+ {
+ OSPF_TRACE(D_PACKETS, "OSPF_auth: lower sequence number (rcv %d, old %d)", rcv_csn, n->csn);
+ return 0;
+ }
+
+ n->csn = rcv_csn;
+ }
if (ifa->passwords)
{
WALK_LIST(ptmp, *(ifa->passwords))
{
- if (pkt->u.md5.keyid != ptmp->id) continue;
+ if (auth->md5.keyid != ptmp->id) continue;
if ((ptmp->accfrom > now_real) || (ptmp->accto < now_real)) continue;
pass = ptmp;
break;
return 0;
}
- if (n)
+ password_cpy(password, pass->password, OSPF_AUTH_CRYPT_SIZE);
+
{
- u32 rcv_csn = ntohl(pkt->u.md5.csn);
- if(rcv_csn < n->csn)
+ void *tail = ((void *) pkt) + plen;
+ char md5sum[OSPF_AUTH_CRYPT_SIZE];
+
+ struct MD5Context ctxt;
+ MD5Init(&ctxt);
+ MD5Update(&ctxt, (char *) pkt, plen);
+ MD5Update(&ctxt, password, OSPF_AUTH_CRYPT_SIZE);
+ MD5Final(md5sum, &ctxt);
+ if (memcmp(md5sum, tail, OSPF_AUTH_CRYPT_SIZE))
{
- OSPF_TRACE(D_PACKETS, "OSPF_auth: lower sequence number (rcv %d, old %d)", rcv_csn, n->csn);
+ OSPF_TRACE(D_PACKETS, "OSPF_auth: wrong md5 digest");
return 0;
}
-
- n->csn = rcv_csn;
- }
-
- MD5Init(&ctxt);
- MD5Update(&ctxt, (char *) pkt, ntohs(pkt->length));
- password_cpy(password, pass->password, OSPF_AUTH_CRYPT_SIZE);
- MD5Update(&ctxt, password, OSPF_AUTH_CRYPT_SIZE);
- MD5Final(md5sum, &ctxt);
- if (memcmp(md5sum, tail, OSPF_AUTH_CRYPT_SIZE))
- {
- OSPF_TRACE(D_PACKETS, "OSPF_auth: wrong md5 digest");
- return 0;
}
return 1;
break;
+
default:
OSPF_TRACE(D_PACKETS, "OSPF_auth: unknown auth type");
return 0;
}
}
-#else
-
-/* OSPFv3 authentication not yet supported */
-
-static inline void
-ospf_pkt_finalize(struct ospf_iface *ifa, struct ospf_packet *pkt)
-{ }
-
-static int
-ospf_pkt_checkauth(struct ospf_neighbor *n, struct ospf_iface *ifa, struct ospf_packet *pkt, int size)
-{ return 1; }
-
-#endif
-
/**
* ospf_rx_hook
int src_local, dst_local UNUSED, dst_mcast;
src_local = ipa_in_net(sk->faddr, ifa->addr->prefix, ifa->addr->pxlen);
dst_local = ipa_equal(sk->laddr, ifa->addr->ip);
- dst_mcast = ipa_equal(sk->laddr, ifa->all_routers) || ipa_equal(sk->laddr, AllDRouters);
-
-#ifdef OSPFv2
- /* First, we eliminate packets with strange address combinations.
- * In OSPFv2, they might be for other ospf_ifaces (with different IP
- * prefix) on the same real iface, so we don't log it. We enforce
- * that (src_local || dst_local), therefore we are eliminating all
- * such cases.
- */
- if (dst_mcast && !src_local)
- return 1;
- if (!dst_mcast && !dst_local)
- return 1;
+ dst_mcast = ipa_equal(sk->laddr, ifa->all_routers) || ipa_equal(sk->laddr, ifa->des_routers);
- /* Ignore my own broadcast packets */
- if (ifa->cf->real_bcast && ipa_equal(sk->faddr, ifa->addr->ip))
- return 1;
-#else /* OSPFv3 */
+ if (ospf_is_v2(po))
+ {
+ /* First, we eliminate packets with strange address combinations.
+ * In OSPFv2, they might be for other ospf_ifaces (with different IP
+ * prefix) on the same real iface, so we don't log it. We enforce
+ * that (src_local || dst_local), therefore we are eliminating all
+ * such cases.
+ */
+ if (dst_mcast && !src_local)
+ return 1;
+ if (!dst_mcast && !dst_local)
+ return 1;
- /* In OSPFv3, src_local and dst_local mean link-local.
- * RFC 5340 says that local (non-vlink) packets use
- * link-local src address, but does not enforce it. Strange.
- */
- if (dst_mcast && !src_local)
- log(L_WARN "OSPF: Received multicast packet from %I (not link-local)", sk->faddr);
-#endif
+ /* Ignore my own broadcast packets */
+ if (ifa->cf->real_bcast && ipa_equal(sk->faddr, ifa->addr->ip))
+ return 1;
+ }
+ else
+ {
+ /* In OSPFv3, src_local and dst_local mean link-local.
+ * RFC 5340 says that local (non-vlink) packets use
+ * link-local src address, but does not enforce it. Strange.
+ */
+ if (dst_mcast && !src_local)
+ log(L_WARN "OSPF: Received multicast packet from %I (not link-local)", sk->faddr);
+ }
/* Second, we check packet size, checksum, and the protocol version */
- struct ospf_packet *ps = (struct ospf_packet *) ip_skip_header(sk->rbuf, &size);
+ struct ospf_packet *pkt = (struct ospf_packet *) ip_skip_header(sk->rbuf, &size);
- if (ps == NULL)
+ if (pkt == NULL)
{
log(L_ERR "%s%I - bad IP header", mesg, sk->faddr);
return 1;
return 1;
}
- int osize = ntohs(ps->length);
- if ((unsigned) osize < sizeof(struct ospf_packet))
+ unsigned plen = ntohs(pkt->length);
+ if (plen < sizeof(struct ospf_packet))
{
- log(L_ERR "%s%I - too low value in size field (%u bytes)", mesg, sk->faddr, osize);
+ log(L_ERR "%s%I - too low value in size field (%u bytes)", mesg, sk->faddr, plen);
return 1;
}
- if ((osize > size) || ((osize % 4) != 0))
+ if ((plen > size) || ((plen % 4) != 0))
{
- log(L_ERR "%s%I - size field does not match (%d/%d)", mesg, sk->faddr, osize, size);
+ log(L_ERR "%s%I - size field does not match (%d/%d)", mesg, sk->faddr, plen, size);
return 1;
}
return 1;
}
- if (ps->version != OSPF_VERSION)
+ if (pkt->version != OSPF_VERSION)
{
- log(L_ERR "%s%I - version %u", mesg, sk->faddr, ps->version);
+ log(L_ERR "%s%I - version %u", mesg, sk->faddr, pkt->version);
return 1;
}
-#ifdef OSPFv2
- if ((ps->autype != htons(OSPF_AUTH_CRYPT)) &&
- (!ipsum_verify(ps, 16, (void *) ps + sizeof(struct ospf_packet),
- osize - sizeof(struct ospf_packet), NULL)))
+ if (ospf_is_v2(po) && ospf_pkt_get_autype(pkt) != OSPF_AUTH_CRYPT)
{
- log(L_ERR "%s%I - bad checksum", mesg, sk->faddr);
- return 1;
- }
-#endif
+ unsigned hlen = sizeof(struct ospf_packet) - sizeof(union ospf_auth);
+ unsigned blen = plen - hlen;
+ void *body = ((void *) pkt) + hlen;
+ if (! ipsum_verify(pkt, sizeof(struct ospf_packet), body, blen, NULL))
+ {
+ log(L_ERR "%s%I - bad checksum", mesg, sk->faddr);
+ return 1;
+ }
+ }
/* Third, we resolve associated iface and handle vlinks. */
- u32 areaid = ntohl(ps->areaid);
- u32 rid = ntohl(ps->routerid);
+ u32 areaid = ntohl(pkt->areaid);
+ u32 rid = ntohl(pkt->routerid);
+ u8 instance_id = ospf_is_v2(po) ? 0 : ospf_pkt_get_instance_id(pkt);
- if ((areaid == ifa->oa->areaid)
-#ifdef OSPFv3
- && (ps->instance_id == ifa->instance_id)
-#endif
- )
+ if ((areaid == ifa->oa->areaid) &&
+ (instance_id == ifa->instance_id))
{
/* It is real iface, source should be local (in OSPFv2) */
-#ifdef OSPFv2
- if (!src_local)
+ if (ospf_is_v2(po) && !src_local)
return 1;
-#endif
}
else if (dst_mcast || (areaid != 0))
{
/* Obvious mismatch */
-#ifdef OSPFv2
- /* We ignore mismatch in OSPFv3, because there might be
- other instance with different instance ID */
- log(L_ERR "%s%I - area does not match (%R vs %R)",
- mesg, sk->faddr, areaid, ifa->oa->areaid);
-#endif
+ /* We ignore mismatch in OSPFv3 when there might be
+ another instance with a different instance ID */
+ if (instance_id == ifa->instance_id)
+ log(L_ERR "%s%I - area does not match (%R vs %R)",
+ mesg, sk->faddr, areaid, ifa->oa->areaid);
return 1;
}
else
{
if ((iff->type == OSPF_IT_VLINK) &&
(iff->voa == ifa->oa) &&
-#ifdef OSPFv3
- (iff->instance_id == ps->instance_id) &&
-#endif
+ (iff->instance_id == instance_id) &&
(iff->vid == rid))
{
/* Vlink should be UP */
}
}
-#ifdef OSPFv2
- log(L_WARN "OSPF: Received packet for unknown vlink (ID %R, IP %I)", rid, sk->faddr);
-#endif
+ /* FIXME: this warning is strange - NBMA could trigger it too */
+ if (ospf_is_v2(po))
+ log(L_WARN "OSPF: Received packet for unknown vlink (ID %R, IP %I)", rid, sk->faddr);
+
return 1;
}
if (ifa->stub) /* This shouldn't happen */
return 1;
- if (ipa_equal(sk->laddr, AllDRouters) && (ifa->sk_dr == 0))
+ if (ipa_equal(sk->laddr, ifa->des_routers) && (ifa->sk_dr == 0))
return 1;
if (rid == po->router_id)
return 1;
}
-#ifdef OSPFv2
/* In OSPFv2, neighbors are identified by either IP or Router ID, base on network type */
+ unsigned t = ifa->type;
struct ospf_neighbor *n;
- if ((ifa->type == OSPF_IT_BCAST) || (ifa->type == OSPF_IT_NBMA) || (ifa->type == OSPF_IT_PTMP))
+ if (ospf_is_v2(po) && ((t == OSPF_IT_BCAST) || (t == OSPF_IT_NBMA) || (t == OSPF_IT_PTMP)))
n = find_neigh_by_ip(ifa, sk->faddr);
else
n = find_neigh(ifa, rid);
-#else
- struct ospf_neighbor *n = find_neigh(ifa, rid);
-#endif
- if (!n && (ps->type != HELLO_P))
+ if (!n && (pkt->type != HELLO_P))
{
log(L_WARN "OSPF: Received non-hello packet from unknown neighbor (src %I, iface %s)",
sk->faddr, ifa->iface->name);
return 1;
}
- if (!ospf_pkt_checkauth(n, ifa, ps, size))
+ if (ospf_is_v2(po) && ! ospf_pkt_checkauth(n, ifa, pkt, size))
{
log(L_ERR "%s%I - authentication failed", mesg, sk->faddr);
return 1;
/* Dump packet
pu8=(u8 *)(sk->rbuf+5*4);
- for(i=0;i<ntohs(ps->length);i+=4)
+ for(i=0;i<ntohs(pkt->length);i+=4)
DBG("%s: received %u,%u,%u,%u\n",p->name, pu8[i+0], pu8[i+1], pu8[i+2],
pu8[i+3]);
DBG("%s: received size: %u\n",p->name,size);
*/
- switch (ps->type)
+ switch (pkt->type)
{
case HELLO_P:
DBG("%s: Hello received.\n", p->name);
- ospf_hello_receive(ps, ifa, n, sk->faddr);
+ ospf_hello_receive(pkt, ifa, n, sk->faddr);
break;
case DBDES_P:
DBG("%s: Database description received.\n", p->name);
- ospf_dbdes_receive(ps, ifa, n);
+ ospf_dbdes_receive(pkt, ifa, n);
break;
case LSREQ_P:
DBG("%s: Link state request received.\n", p->name);
- ospf_lsreq_receive(ps, ifa, n);
+ ospf_lsreq_receive(pkt, ifa, n);
break;
case LSUPD_P:
DBG("%s: Link state update received.\n", p->name);
- ospf_lsupd_receive(ps, ifa, n);
+ ospf_lsupd_receive(pkt, ifa, n);
break;
case LSACK_P:
DBG("%s: Link state ack received.\n", p->name);
- ospf_lsack_receive(ps, ifa, n);
+ ospf_lsack_receive(pkt, ifa, n);
break;
default:
- log(L_ERR "%s%I - wrong type %u", mesg, sk->faddr, ps->type);
+ log(L_ERR "%s%I - wrong type %u", mesg, sk->faddr, pkt->type);
return 1;
};
return 1;
log(L_ERR "OSPF: Socket error on %s: %M", ifa->iface->name, err);
}
+void
+ospf_send_to(struct ospf_iface *ifa, ip_addr dst)
+{
+ sock *sk = ifa->sk;
+ struct ospf_packet *pkt = (struct ospf_packet *) sk->tbuf;
+ int plen = ntohs(pkt->length);
+
+ if (sk->tbuf != sk->tpos)
+ log(L_ERR "Aiee, old packet was overwritten in TX buffer");
+
+ if (ospf_is_v2(ifa->oa->po))
+ {
+ if (ifa->autype == OSPF_AUTH_CRYPT)
+ plen += OSPF_AUTH_CRYPT_SIZE;
+
+ ospf_pkt_finalize(ifa, pkt);
+ }
+
+ sk_send_to(sk, plen, dst, 0);
+}
+
void
ospf_send_to_agt(struct ospf_iface *ifa, u8 state)
{
void
ospf_send_to_bdr(struct ospf_iface *ifa)
{
- if (!ipa_equal(ifa->drip, IPA_NONE))
+ if (ipa_nonzero(ifa->drip))
ospf_send_to(ifa, ifa->drip);
- if (!ipa_equal(ifa->bdrip, IPA_NONE))
+ if (ipa_nonzero(ifa->bdrip))
ospf_send_to(ifa, ifa->bdrip);
}
-
-void
-ospf_send_to(struct ospf_iface *ifa, ip_addr dst)
-{
- sock *sk = ifa->sk;
- struct ospf_packet *pkt = (struct ospf_packet *) sk->tbuf;
- int len = ntohs(pkt->length);
-
-#ifdef OSPFv2
- if (ifa->autype == OSPF_AUTH_CRYPT)
- len += OSPF_AUTH_CRYPT_SIZE;
-#endif
-
- ospf_pkt_finalize(ifa, pkt);
- if (sk->tbuf != sk->tpos)
- log(L_ERR "Aiee, old packet was overwritten in TX buffer");
-
- sk_send_to(sk, len, dst, 0);
-}
-
int ospf_rx_hook(sock * sk, int size);
void ospf_tx_hook(sock * sk);
void ospf_err_hook(sock * sk, int err);
+void ospf_send_to(struct ospf_iface *ifa, ip_addr ip);
+
void ospf_send_to_agt(struct ospf_iface *ifa, u8 state);
void ospf_send_to_bdr(struct ospf_iface *ifa);
-void ospf_send_to(struct ospf_iface *ifa, ip_addr ip);
-static inline void ospf_send_to_all(struct ospf_iface *ifa) { ospf_send_to(ifa, ifa->all_routers); }
+static inline void ospf_send_to_all(struct ospf_iface *ifa)
+{
+ ospf_send_to(ifa, ifa->all_routers);
+}
+
+static inline void ospf_send_to_des(struct ospf_iface *ifa)
+{
+ if (ipa_nonzero(ifa->des_routers))
+ ospf_send_to(ifa, ifa->des_routers);
+ else
+ ospf_send_to_bdr(ifa);
+}
static inline void * ospf_tx_buffer(struct ospf_iface *ifa) { return ifa->sk->tbuf; }
static inline unsigned
ospf_pkt_bufsize(struct ospf_iface *ifa)
{
-#ifdef OSPFv2
- unsigned headers = (ifa->autype == OSPF_AUTH_CRYPT) ? OSPF_AUTH_CRYPT_SIZE : 0;
-#else
- unsigned headers = 0;
-#endif
-
- return ifa->sk->tbsize - headers;
+ /* Reserve buffer space for authentication footer */
+ return ifa->sk->tbsize -
+ (ifa->autype == OSPF_AUTH_CRYPT) ? OSPF_AUTH_CRYPT_SIZE : 0;
}
/* In ospf_area->rtr we store paths to routers, but we use RID (and not IP address)
as index, so we need to encapsulate RID to IP address */
-#ifdef OSPFv2
-#define ipa_from_rid(x) _MI(x)
-#else /* OSPFv3 */
-#define ipa_from_rid(x) _MI6(0,0,0,x)
-#endif
+#define ipa_from_rid(x) ipa_from_u32(x)
static inline void reset_ri(ort *ort)
{
struct ospf_lsa_rt_walk rtl;
struct top_hash_entry *tmp;
ip_addr prefix;
- int pxlen;
+ int pxlen, i;
if (rt->options & OPT_RT_V)
oa->trcap = 1;
}
/* Now process Rt links */
- lsa_walk_rt_init(po, act, &rtl);
- while (lsa_walk_rt(&rtl))
+ for (lsa_walk_rt_init(po, act, &rtl), i = 0; lsa_walk_rt(&rtl); i++)
{
tmp = NULL;
#endif
-#ifdef OSPFv2
static inline u32
fibnode_to_lsaid(struct proto_ospf *po, struct fib_node *fn)
{
- /* We have to map IP prefixes to u32 in such manner that resulting
- u32 interpreted as IP address is a member of given
+ /* In OSPFv2, We have to map IP prefixes to u32 in such manner
+ that resulting u32 interpreted as IP address is a member of given
prefix. Therefore, /32 prefix have to be mapped on itself.
All received prefixes have to be mapped on different u32s.
possible to have both reliably and the suggested algorithm was
unnecessary complicated and it does crazy things like changing
LSA ID for a network because different network appeared, we
- choose a different way. */
+ choose a different way.
+
+ In OSPFv3, it is simpler. There is not a requirement for
+ membership of the result in the input network, so we just use a
+ hash-based unique ID of a routing table entry for a route that
+ originated given LSA. For ext-LSA, it is an imported route in the
+ nest's routing table (p->table). For summary-LSA, it is a
+ 'source' route in the protocol internal routing table (po->rtf).
+ */
+
+ if (ospf_is_v3(po))
+ return fn->uid;
u32 id = _I(fn->prefix);
return id | ~u32_mkmask(fn->pxlen);
}
-#else /* OSPFv3 */
-
-static inline u32
-fibnode_to_lsaid(struct proto_ospf *po, struct fib_node *fn)
-{
- /*
- * In OSPFv3, it is simpler. There is not a requirement for
- * membership of the result in the input network, so we just use a
- * hash-based unique ID of a routing table entry for a route that
- * originated given LSA. For ext-LSA, it is an imported route in the
- * nest's routing table (p->table). For summary-LSA, it is a
- * 'source' route in the protocol internal routing table (po->rtf).
- */
- return fn->uid;
-}
-
-#endif
-
static void *
lsab_alloc(struct proto_ospf *po, unsigned size)
while (e)
{
x = e->next;
- n = newt + ospf_top_hash(f, e->domain, e->lsa.id, e->lsa.rt, e->lsa.type);
+ n = newt + ospf_top_hash(f, e->domain, e->lsa.id, e->lsa.rt, e->lsa_type);
e->next = *n;
*n = e;
e = x;
ospf_top_ht_free(oldt);
}
-#ifdef OSPFv2
-
-u32
-ospf_lsa_domain(u32 type, struct ospf_iface *ifa)
-{
- return (type == LSA_T_EXT) ? 0 : ifa->oa->areaid;
-}
-
-#else /* OSPFv3 */
-
-u32
-ospf_lsa_domain(u32 type, struct ospf_iface *ifa)
-{
- switch (type & LSA_SCOPE_MASK)
- {
- case LSA_SCOPE_LINK:
- return ifa->iface->index;
-
- case LSA_SCOPE_AREA:
- return ifa->oa->areaid;
-
- case LSA_SCOPE_AS:
- default:
- return 0;
- }
-}
-
-#endif
-
struct top_hash_entry *
ospf_hash_find_header(struct top_graph *f, u32 domain, struct ospf_lsa_header *h)
{
struct top_hash_entry *e;
e = f->hash_table[ospf_top_hash(f, domain, lsa, rtr, type)];
- while (e && (e->lsa.id != lsa || e->lsa.type != type || e->lsa.rt != rtr || e->domain != domain))
+ while (e && (e->lsa.id != lsa || e->lsa.rt != rtr ||
+ e->lsa_type != type || e->domain != domain))
e = e->next;
return e;
ee = f->hash_table + ospf_top_hash(f, domain, lsa, rtr, type);
e = *ee;
- while (e && (e->lsa.id != lsa || e->lsa.rt != rtr || e->lsa.type != type || e->domain != domain))
+ while (e && (e->lsa.id != lsa || e->lsa.rt != rtr ||
+ e->lsa_type != type || e->domain != domain))
e = e->next;
if (e)
e->lb = IPA_NONE;
e->lsa.id = lsa;
e->lsa.rt = rtr;
- e->lsa.type = type;
+ e->lsa.type = type;
e->lsa_body = NULL;
+ e->lsa_type = type;
e->domain = domain;
e->next = *ee;
*ee = e;
ospf_hash_delete(struct top_graph *f, struct top_hash_entry *e)
{
struct top_hash_entry **ee = f->hash_table +
- ospf_top_hash(f, e->domain, e->lsa.id, e->lsa.rt, e->lsa.type);
+ ospf_top_hash(f, e->domain, e->lsa.id, e->lsa.rt, e->lsa_type);
while (*ee)
{
bird_clock_t inst_t; /* Time of installation into DB */
struct mpnh *nhs; /* Computed nexthops - valid only in ospf_rt_spf() */
ip_addr lb; /* In OSPFv2, link back address. In OSPFv3, any global address in the area useful for vlinks */
-#ifdef OSPFv3
u32 lb_id; /* Interface ID of link back iface (for bcast or NBMA networks) */
-#endif
u32 dist; /* Distance from the root */
u16 ini_age;
u8 color;
struct top_graph *ospf_top_new(pool *);
void ospf_top_free(struct top_graph *);
void ospf_top_dump(struct top_graph *, struct proto *);
-u32 ospf_lsa_domain(u32 type, struct ospf_iface *ifa);
+
struct top_hash_entry *ospf_hash_find_header(struct top_graph *f, u32 domain,
struct ospf_lsa_header *h);
struct top_hash_entry *ospf_hash_get_header(struct top_graph *f, u32 domain,
struct ospf_lsa_header *h);
-struct top_hash_entry *ospf_hash_find(struct top_graph *, u32 domain, u32 lsa, u32 rtr,
- u32 type);
-struct top_hash_entry *ospf_hash_get(struct top_graph *, u32 domain, u32 lsa, u32 rtr,
- u32 type);
+struct top_hash_entry *ospf_hash_find(struct top_graph *, u32 domain, u32 lsa, u32 rtr, u32 type);
+struct top_hash_entry *ospf_hash_get(struct top_graph *, u32 domain, u32 lsa, u32 rtr, u32 type);
void ospf_hash_delete(struct top_graph *, struct top_hash_entry *);
void originate_rt_lsa(struct ospf_area *oa);
void update_rt_lsa(struct ospf_area *oa);