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