Temporary integrated OSPF commit.
This commit is contained in:
parent
70945cb645
commit
a7a7372aa7
15 changed files with 779 additions and 691 deletions
10
nest/locks.c
10
nest/locks.c
|
@ -22,10 +22,11 @@
|
||||||
* or some other non-shareable resource, it asks the core to lock it and it doesn't
|
* or some other non-shareable resource, it asks the core to lock it and it doesn't
|
||||||
* use the resource until it's notified that it has acquired the lock.
|
* use the resource until it's notified that it has acquired the lock.
|
||||||
*
|
*
|
||||||
* Object locks are represented by &object_lock structures which are in turn a kind of
|
* Object locks are represented by &object_lock structures which are in turn a
|
||||||
* resource. Lockable resources are uniquely determined by resource type
|
* kind of resource. Lockable resources are uniquely determined by resource type
|
||||||
* (%OBJLOCK_UDP for a UDP port etc.), IP address (usually a broadcast or
|
* (%OBJLOCK_UDP for a UDP port etc.), IP address (usually a broadcast or
|
||||||
* multicast address the port is bound to), port number and interface.
|
* multicast address the port is bound to), port number, interface and optional
|
||||||
|
* instance ID.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#undef LOCAL_DEBUG
|
#undef LOCAL_DEBUG
|
||||||
|
@ -45,6 +46,7 @@ olock_same(struct object_lock *x, struct object_lock *y)
|
||||||
x->type == y->type &&
|
x->type == y->type &&
|
||||||
x->iface == y->iface &&
|
x->iface == y->iface &&
|
||||||
x->port == y->port &&
|
x->port == y->port &&
|
||||||
|
x->inst == y->inst &&
|
||||||
ipa_equal(x->addr, y->addr);
|
ipa_equal(x->addr, y->addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -88,7 +90,7 @@ olock_dump(resource *r)
|
||||||
struct object_lock *l = (struct object_lock *) r;
|
struct object_lock *l = (struct object_lock *) r;
|
||||||
static char *olock_states[] = { "free", "locked", "waiting", "event" };
|
static char *olock_states[] = { "free", "locked", "waiting", "event" };
|
||||||
|
|
||||||
debug("(%d:%s:%I:%d) [%s]\n", l->type, (l->iface ? l->iface->name : "?"), l->addr, l->port, olock_states[l->state]);
|
debug("(%d:%s:%I:%d:%d) [%s]\n", l->type, (l->iface ? l->iface->name : "?"), l->addr, l->port, l->inst, olock_states[l->state]);
|
||||||
if (!EMPTY_LIST(l->waiters))
|
if (!EMPTY_LIST(l->waiters))
|
||||||
debug(" [wanted]\n");
|
debug(" [wanted]\n");
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,9 +26,10 @@
|
||||||
struct object_lock {
|
struct object_lock {
|
||||||
resource r;
|
resource r;
|
||||||
ip_addr addr; /* Identification of a object: IP address */
|
ip_addr addr; /* Identification of a object: IP address */
|
||||||
unsigned int type; /* ... object type (OBJLOCK_xxx) */
|
uint type; /* ... object type (OBJLOCK_xxx) */
|
||||||
|
uint port; /* ... port number */
|
||||||
|
uint inst; /* ... instance ID */
|
||||||
struct iface *iface; /* ... interface */
|
struct iface *iface; /* ... interface */
|
||||||
unsigned int port; /* ... port number */
|
|
||||||
void (*hook)(struct object_lock *); /* Called when the lock succeeds */
|
void (*hook)(struct object_lock *); /* Called when the lock succeeds */
|
||||||
void *data; /* User data */
|
void *data; /* User data */
|
||||||
/* ... internal to lock manager, don't touch ... */
|
/* ... internal to lock manager, don't touch ... */
|
||||||
|
|
|
@ -200,15 +200,11 @@ ospf_do_send_dbdes(struct ospf_proto *p, struct ospf_neighbor *n)
|
||||||
* of the buffer.
|
* of the buffer.
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
ospf_send_dbdes(struct ospf_neighbor *n, int next)
|
ospf_send_dbdes(struct ospf_proto *p, struct ospf_neighbor *n, int next)
|
||||||
{
|
{
|
||||||
struct ospf_iface *ifa = n->ifa;
|
|
||||||
struct ospf_area *oa = ifa->oa;
|
|
||||||
struct ospf_proto *p = oa->po;
|
|
||||||
|
|
||||||
/* RFC 2328 10.8 */
|
/* RFC 2328 10.8 */
|
||||||
|
|
||||||
if (oa->rt == NULL)
|
if (n->ifa->oa->rt == NULL)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
switch (n->state)
|
switch (n->state)
|
||||||
|
@ -312,6 +308,7 @@ ospf_process_dbdes(struct ospf_proto *p, struct ospf_packet *pkt, struct ospf_ne
|
||||||
s_add_tail(&n->lsrql, SNODE req);
|
s_add_tail(&n->lsrql, SNODE req);
|
||||||
|
|
||||||
req->lsa = lsa;
|
req->lsa = lsa;
|
||||||
|
req->lsa_body = LSA_BODY_DUMMY;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -394,7 +391,7 @@ ospf_receive_dbdes(struct ospf_packet *pkt, struct ospf_iface *ifa,
|
||||||
n->imms = rcv_imms;
|
n->imms = rcv_imms;
|
||||||
OSPF_TRACE(D_PACKETS, "I'm slave to %I", n->ip);
|
OSPF_TRACE(D_PACKETS, "I'm slave to %I", n->ip);
|
||||||
ospf_neigh_sm(n, INM_NEGDONE);
|
ospf_neigh_sm(n, INM_NEGDONE);
|
||||||
ospf_send_dbdes(n, 1);
|
ospf_send_dbdes(p, n, 1);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -426,7 +423,7 @@ ospf_receive_dbdes(struct ospf_packet *pkt, struct ospf_iface *ifa,
|
||||||
if (!(n->myimms & DBDES_MS))
|
if (!(n->myimms & DBDES_MS))
|
||||||
{
|
{
|
||||||
/* Slave should retransmit dbdes packet */
|
/* Slave should retransmit dbdes packet */
|
||||||
ospf_send_dbdes(n, 0);
|
ospf_send_dbdes(p, n, 0);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -472,7 +469,7 @@ ospf_receive_dbdes(struct ospf_packet *pkt, struct ospf_iface *ifa,
|
||||||
if (!(n->myimms & DBDES_M) && !(n->imms & DBDES_M))
|
if (!(n->myimms & DBDES_M) && !(n->imms & DBDES_M))
|
||||||
ospf_neigh_sm(n, INM_EXDONE);
|
ospf_neigh_sm(n, INM_EXDONE);
|
||||||
else
|
else
|
||||||
ospf_send_dbdes(n, 1);
|
ospf_send_dbdes(p, n, 1);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -489,7 +486,7 @@ ospf_receive_dbdes(struct ospf_packet *pkt, struct ospf_iface *ifa,
|
||||||
if (ospf_process_dbdes(p, pkt, n) < 0)
|
if (ospf_process_dbdes(p, pkt, n) < 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
ospf_send_dbdes(n, 1);
|
ospf_send_dbdes(p, n, 1);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -504,7 +501,7 @@ ospf_receive_dbdes(struct ospf_packet *pkt, struct ospf_iface *ifa,
|
||||||
if (!(n->myimms & DBDES_MS))
|
if (!(n->myimms & DBDES_MS))
|
||||||
{
|
{
|
||||||
/* Slave should retransmit dbdes packet */
|
/* Slave should retransmit dbdes packet */
|
||||||
ospf_send_dbdes(n, 0);
|
ospf_send_dbdes(p, n, 0);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -275,7 +275,7 @@ ospf_receive_hello(struct ospf_packet *pkt, struct ospf_iface *ifa,
|
||||||
/* Check consistency of existing neighbor entry */
|
/* Check consistency of existing neighbor entry */
|
||||||
if (n)
|
if (n)
|
||||||
{
|
{
|
||||||
unsigned t = ifa->type;
|
uint t = ifa->type;
|
||||||
if (ospf_is_v2(p) && ((t == OSPF_IT_BCAST) || (t == OSPF_IT_NBMA) || (t == OSPF_IT_PTMP)))
|
if (ospf_is_v2(p) && ((t == OSPF_IT_BCAST) || (t == OSPF_IT_NBMA) || (t == OSPF_IT_PTMP)))
|
||||||
{
|
{
|
||||||
/* Neighbor identified by IP address; Router ID may change */
|
/* Neighbor identified by IP address; Router ID may change */
|
||||||
|
|
|
@ -620,18 +620,11 @@ ospf_iface_new(struct ospf_area *oa, struct ifa *addr, struct ospf_iface_patt *i
|
||||||
|
|
||||||
add_tail(&oa->po->iface_list, NODE ifa);
|
add_tail(&oa->po->iface_list, NODE ifa);
|
||||||
|
|
||||||
/*
|
|
||||||
* In some cases we allow more ospf_ifaces on one physical iface.
|
|
||||||
* In OSPFv2, if they use different IP address prefix.
|
|
||||||
* In OSPFv3, if they use different instance_id.
|
|
||||||
* Therefore, we store such info to lock->addr field.
|
|
||||||
*/
|
|
||||||
|
|
||||||
// XXXX review
|
|
||||||
struct object_lock *lock = olock_new(pool);
|
struct object_lock *lock = olock_new(pool);
|
||||||
lock->addr = ospf_is_v2(p) ? ifa->addr->prefix : _MI6(0,0,0,ifa->instance_id);
|
lock->addr = ospf_is_v2(p) ? ifa->addr->prefix : IPA_NONE;
|
||||||
lock->type = OBJLOCK_IP;
|
lock->type = OBJLOCK_IP;
|
||||||
lock->port = OSPF_PROTO;
|
lock->port = OSPF_PROTO;
|
||||||
|
lock->inst = ifa->instance_id;
|
||||||
lock->iface = iface;
|
lock->iface = iface;
|
||||||
lock->data = ifa;
|
lock->data = ifa;
|
||||||
lock->hook = ospf_iface_add;
|
lock->hook = ospf_iface_add;
|
||||||
|
@ -997,7 +990,7 @@ ospf_walk_matching_iface_patts(struct ospf_proto *p, struct ospf_mip_walk *s)
|
||||||
BIT32_SET(s->ignore, id);
|
BIT32_SET(s->ignore, id);
|
||||||
|
|
||||||
/* If we already found it in previous areas, ignore it and add warning */
|
/* If we already found it in previous areas, ignore it and add warning */
|
||||||
if (!BIT32_TEST(s->active, id))
|
if (BIT32_TEST(s->active, id))
|
||||||
{ s->warn = 1; continue; }
|
{ s->warn = 1; continue; }
|
||||||
|
|
||||||
BIT32_SET(s->active, id);
|
BIT32_SET(s->active, id);
|
||||||
|
@ -1046,7 +1039,7 @@ ospf_ifa_notify2(struct proto *P, uint flags, struct ifa *a)
|
||||||
{
|
{
|
||||||
struct ospf_mip_walk s = { .iface = a->iface, .a = a };
|
struct ospf_mip_walk s = { .iface = a->iface, .a = a };
|
||||||
while (ospf_walk_matching_iface_patts(p, &s))
|
while (ospf_walk_matching_iface_patts(p, &s))
|
||||||
ospf_iface_new(s.oa, s.a, s.ip);
|
ospf_iface_new(s.oa, a, s.ip);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (flags & IF_CHANGE_DOWN)
|
if (flags & IF_CHANGE_DOWN)
|
||||||
|
@ -1078,7 +1071,7 @@ ospf_ifa_notify3(struct proto *P, uint flags, struct ifa *a)
|
||||||
{
|
{
|
||||||
struct ospf_mip_walk s = { .iface = a->iface };
|
struct ospf_mip_walk s = { .iface = a->iface };
|
||||||
while (ospf_walk_matching_iface_patts(p, &s))
|
while (ospf_walk_matching_iface_patts(p, &s))
|
||||||
ospf_iface_new(s.oa, s.a, s.ip);
|
ospf_iface_new(s.oa, a, s.ip);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (flags & IF_CHANGE_DOWN)
|
if (flags & IF_CHANGE_DOWN)
|
||||||
|
|
|
@ -79,10 +79,9 @@ ospf_reset_lsack_queue(struct ospf_neighbor *n)
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void
|
static inline void
|
||||||
ospf_send_lsack(struct ospf_neighbor *n, int queue)
|
ospf_send_lsack_(struct ospf_proto *p, struct ospf_neighbor *n, int queue)
|
||||||
{
|
{
|
||||||
struct ospf_iface *ifa = n->ifa;
|
struct ospf_iface *ifa = n->ifa;
|
||||||
struct ospf_proto *p = ifa->oa->po;
|
|
||||||
struct ospf_lsa_header *lsas;
|
struct ospf_lsa_header *lsas;
|
||||||
struct ospf_packet *pkt;
|
struct ospf_packet *pkt;
|
||||||
struct lsa_node *no;
|
struct lsa_node *no;
|
||||||
|
@ -121,10 +120,10 @@ ospf_send_lsack(struct ospf_neighbor *n, int queue)
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
ospf_lsack_send(struct ospf_neighbor *n, int queue)
|
ospf_send_lsack(struct ospf_proto *p, struct ospf_neighbor *n, int queue)
|
||||||
{
|
{
|
||||||
while (!EMPTY_LIST(n->ackl[queue]))
|
while (!EMPTY_LIST(n->ackl[queue]))
|
||||||
ospf_send_lsack(n, queue);
|
ospf_send_lsack_(p, n, queue);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -160,9 +159,6 @@ ospf_receive_lsack(struct ospf_packet *pkt, struct ospf_iface *ifa,
|
||||||
|
|
||||||
if (lsa_comp(&lsa, &ret->lsa) != CMP_SAME)
|
if (lsa_comp(&lsa, &ret->lsa) != CMP_SAME)
|
||||||
{
|
{
|
||||||
if ((lsa.sn == LSA_MAXSEQNO) && (lsa.age == LSA_MAXAGE))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
OSPF_TRACE(D_PACKETS, "Strange LSACK from %I", n->ip);
|
OSPF_TRACE(D_PACKETS, "Strange LSACK from %I", n->ip);
|
||||||
OSPF_TRACE(D_PACKETS, "Type: %04x, Id: %R, Rt: %R",
|
OSPF_TRACE(D_PACKETS, "Type: %04x, Id: %R, Rt: %R",
|
||||||
lsa_type, lsa.id, lsa.rt);
|
lsa_type, lsa.id, lsa.rt);
|
||||||
|
|
|
@ -71,7 +71,8 @@ ospf_send_lsreq(struct ospf_proto *p, struct ospf_neighbor *n)
|
||||||
ospf_pkt_fill_hdr(ifa, pkt, LSREQ_P);
|
ospf_pkt_fill_hdr(ifa, pkt, LSREQ_P);
|
||||||
ospf_lsreq_body(p, pkt, &lsrs, &lsr_max);
|
ospf_lsreq_body(p, pkt, &lsrs, &lsr_max);
|
||||||
|
|
||||||
// for (i = 0; i < lsr_max; i++)
|
/* We send smaller LSREQ to prevent multiple LSACKs as answer */
|
||||||
|
lsr_max = lsr_max / 4;
|
||||||
|
|
||||||
i = 0;
|
i = 0;
|
||||||
WALK_SLIST(en, n->lsrql)
|
WALK_SLIST(en, n->lsrql)
|
||||||
|
|
|
@ -115,7 +115,8 @@ ospf_lsa_lsrt_up(struct top_hash_entry *en, struct ospf_neighbor *n)
|
||||||
s_add_tail(&n->lsrtl, SNODE ret);
|
s_add_tail(&n->lsrtl, SNODE ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
memcpy(&ret->lsa, &en->lsa, sizeof(struct ospf_lsa_header));
|
ret->lsa = en->lsa;
|
||||||
|
ret->lsa_body = LSA_BODY_DUMMY;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int
|
static inline int
|
||||||
|
@ -134,25 +135,37 @@ ospf_lsa_lsrt_down(struct top_hash_entry *en, struct ospf_neighbor *n)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
ospf_add_flushed_to_lsrt(struct ospf_proto *p, struct ospf_neighbor *n)
|
||||||
|
{
|
||||||
|
struct top_hash_entry *en;
|
||||||
|
|
||||||
static void ospf_lsupd_flood_ifa(struct ospf_proto *p, struct ospf_iface *ifa, struct top_hash_entry *en);
|
WALK_SLIST(en, p->lsal)
|
||||||
|
if ((en->lsa.age == LSA_MAXAGE) && (en->lsa_body != NULL) &&
|
||||||
|
lsa_flooding_allowed(en->lsa_type, en->domain, n->ifa))
|
||||||
|
ospf_lsa_lsrt_up(en, n);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void ospf_send_lsupd_to_ifa(struct ospf_proto *p, struct top_hash_entry *en, struct ospf_iface *ifa);
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ospf_lsupd_flood - send received or generated LSA to the neighbors
|
* ospf_flood_lsa - send LSA to the neighbors
|
||||||
* @p: OSPF protocol
|
* @p: OSPF protocol instance
|
||||||
* @en: LSA entry
|
* @en: LSA entry
|
||||||
* @from: neighbor than sent this LSA (or NULL if LSA is local)
|
* @from: neighbor than sent this LSA (or NULL if LSA is local)
|
||||||
*
|
*
|
||||||
* return value - was the LSA flooded back?
|
* return value - was the LSA flooded back?
|
||||||
*/
|
*/
|
||||||
|
|
||||||
int
|
int
|
||||||
ospf_lsupd_flood(struct ospf_proto *p, struct top_hash_entry *en, struct ospf_neighbor *from)
|
ospf_flood_lsa(struct ospf_proto *p, struct top_hash_entry *en, struct ospf_neighbor *from)
|
||||||
{
|
{
|
||||||
struct ospf_iface *ifa;
|
struct ospf_iface *ifa;
|
||||||
struct ospf_neighbor *n;
|
struct ospf_neighbor *n;
|
||||||
|
|
||||||
|
/* RFC 2328 13.3 */
|
||||||
|
|
||||||
int back = 0;
|
int back = 0;
|
||||||
WALK_LIST(ifa, p->iface_list)
|
WALK_LIST(ifa, p->iface_list)
|
||||||
{
|
{
|
||||||
|
@ -185,6 +198,8 @@ ospf_lsupd_flood(struct ospf_proto *p, struct top_hash_entry *en, struct ospf_ne
|
||||||
{
|
{
|
||||||
s_rem_node(SNODE req);
|
s_rem_node(SNODE req);
|
||||||
ospf_hash_delete(n->lsrqh, req);
|
ospf_hash_delete(n->lsrqh, req);
|
||||||
|
n->want_lsreq = 1;
|
||||||
|
|
||||||
if ((EMPTY_SLIST(n->lsrql)) && (n->state == NEIGHBOR_LOADING))
|
if ((EMPTY_SLIST(n->lsrql)) && (n->state == NEIGHBOR_LOADING))
|
||||||
ospf_neigh_sm(n, INM_LOADDONE);
|
ospf_neigh_sm(n, INM_LOADDONE);
|
||||||
}
|
}
|
||||||
|
@ -227,7 +242,7 @@ ospf_lsupd_flood(struct ospf_proto *p, struct top_hash_entry *en, struct ospf_ne
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 13.3 (5) - finally flood the packet */
|
/* 13.3 (5) - finally flood the packet */
|
||||||
ospf_lsupd_flood_ifa(p, ifa, en);
|
ospf_send_lsupd_to_ifa(p, en, ifa);
|
||||||
}
|
}
|
||||||
|
|
||||||
return back;
|
return back;
|
||||||
|
@ -288,7 +303,7 @@ ospf_prepare_lsupd(struct ospf_proto *p, struct ospf_iface *ifa,
|
||||||
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
ospf_lsupd_flood_ifa(struct ospf_proto *p, struct ospf_iface *ifa, struct top_hash_entry *en)
|
ospf_send_lsupd_to_ifa(struct ospf_proto *p, struct top_hash_entry *en, struct ospf_iface *ifa)
|
||||||
{
|
{
|
||||||
uint c = ospf_prepare_lsupd(p, ifa, &en, 1);
|
uint c = ospf_prepare_lsupd(p, ifa, &en, 1);
|
||||||
|
|
||||||
|
@ -384,7 +399,8 @@ ospf_receive_lsupd(struct ospf_packet *pkt, struct ospf_iface *ifa,
|
||||||
|
|
||||||
/* RFC 2328 13. */
|
/* RFC 2328 13. */
|
||||||
|
|
||||||
int sendreq = 1; /* XXXX: review sendreq */
|
int skip_lsreq = 0;
|
||||||
|
n->want_lsreq = 0;
|
||||||
|
|
||||||
uint plen = ntohs(pkt->length);
|
uint plen = ntohs(pkt->length);
|
||||||
if (plen < (ospf_lsupd_hdrlen(p) + sizeof(struct ospf_lsa_header)))
|
if (plen < (ospf_lsupd_hdrlen(p) + sizeof(struct ospf_lsa_header)))
|
||||||
|
@ -436,7 +452,7 @@ ospf_receive_lsupd(struct ospf_packet *pkt, struct ospf_iface *ifa,
|
||||||
u16 chsum = lsa_n->checksum;
|
u16 chsum = lsa_n->checksum;
|
||||||
if (chsum != lsasum_check(lsa_n, NULL))
|
if (chsum != lsasum_check(lsa_n, NULL))
|
||||||
{
|
{
|
||||||
log(L_WARN "%s: Received LSA from %I with bad checskum: %x %x",
|
log(L_WARN "%s: Received LSA from %I with bad checksum: %x %x",
|
||||||
p->p.name, n->ip, chsum, lsa_n->checksum);
|
p->p.name, n->ip, chsum, lsa_n->checksum);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -501,7 +517,7 @@ ospf_receive_lsupd(struct ospf_packet *pkt, struct ospf_iface *ifa,
|
||||||
if (en && ((now - en->inst_time) < MINLSARRIVAL))
|
if (en && ((now - en->inst_time) < MINLSARRIVAL))
|
||||||
{
|
{
|
||||||
OSPF_TRACE(D_EVENTS, "Skipping LSA received in less that MinLSArrival");
|
OSPF_TRACE(D_EVENTS, "Skipping LSA received in less that MinLSArrival");
|
||||||
sendreq = 0;
|
skip_lsreq = 1;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -514,7 +530,6 @@ ospf_receive_lsupd(struct ospf_packet *pkt, struct ospf_iface *ifa,
|
||||||
{
|
{
|
||||||
log(L_WARN "%s: Received invalid LSA from %I", p->p.name, n->ip);
|
log(L_WARN "%s: Received invalid LSA from %I", p->p.name, n->ip);
|
||||||
mb_free(body);
|
mb_free(body);
|
||||||
sendreq = 0;
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -528,22 +543,27 @@ ospf_receive_lsupd(struct ospf_packet *pkt, struct ospf_iface *ifa,
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 13. (5c) - remove old LSA from all retransmission lists */
|
/* 13. (5c) - remove old LSA from all retransmission lists */
|
||||||
/* Must be done before (5b), otherwise it also removes the new entries from (5b) */
|
/*
|
||||||
|
* We only need to remove it from the retransmission list of the neighbor
|
||||||
|
* that send us the new LSA. The old LSA is automatically replaced in
|
||||||
|
* retransmission lists by the new LSA.
|
||||||
|
*/
|
||||||
if (en)
|
if (en)
|
||||||
ospf_lsa_lsrt_down(en, n);
|
ospf_lsa_lsrt_down(en, n);
|
||||||
|
|
||||||
|
#if 0
|
||||||
/*
|
/*
|
||||||
{
|
* Old code for removing LSA from all retransmission lists. Must be done
|
||||||
struct ospf_iface *ifi;
|
* before (5b), otherwise it also removes the new entries from (5b).
|
||||||
struct ospf_neighbor *ni;
|
*/
|
||||||
|
struct ospf_iface *ifi;
|
||||||
|
struct ospf_neighbor *ni;
|
||||||
|
|
||||||
WALK_LIST(ifi, p->iface_list)
|
WALK_LIST(ifi, p->iface_list)
|
||||||
WALK_LIST(ni, ifi->neigh_list)
|
WALK_LIST(ni, ifi->neigh_list)
|
||||||
if (ni->state > NEIGHBOR_EXSTART)
|
if (ni->state > NEIGHBOR_EXSTART)
|
||||||
ospf_lsa_lsrt_down(en, ni);
|
ospf_lsa_lsrt_down(en, ni);
|
||||||
}
|
#endif
|
||||||
*/
|
|
||||||
|
|
||||||
/* 13. (5d) - install new LSA into database */
|
/* 13. (5d) - install new LSA into database */
|
||||||
en = ospf_install_lsa(p, &lsa, lsa_type, lsa_domain, body);
|
en = ospf_install_lsa(p, &lsa, lsa_type, lsa_domain, body);
|
||||||
|
@ -553,7 +573,7 @@ ospf_receive_lsupd(struct ospf_packet *pkt, struct ospf_iface *ifa,
|
||||||
ospf_notify_net_lsa(ifa);
|
ospf_notify_net_lsa(ifa);
|
||||||
|
|
||||||
/* 13. (5b) - flood new LSA */
|
/* 13. (5b) - flood new LSA */
|
||||||
int flood_back = ospf_lsupd_flood(p, en, n);
|
int flood_back = ospf_flood_lsa(p, en, n);
|
||||||
|
|
||||||
/* 13.5. - schedule ACKs (tbl 19, cases 1+2) */
|
/* 13.5. - schedule ACKs (tbl 19, cases 1+2) */
|
||||||
if (! flood_back)
|
if (! flood_back)
|
||||||
|
@ -582,7 +602,7 @@ ospf_receive_lsupd(struct ospf_packet *pkt, struct ospf_iface *ifa,
|
||||||
else
|
else
|
||||||
ospf_enqueue_lsack(n, lsa_n, ACKL_DIRECT);
|
ospf_enqueue_lsack(n, lsa_n, ACKL_DIRECT);
|
||||||
|
|
||||||
sendreq = 0;
|
skip_lsreq = 1;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -598,11 +618,17 @@ ospf_receive_lsupd(struct ospf_packet *pkt, struct ospf_iface *ifa,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Send direct LSAs */
|
/* Send direct LSACKs */
|
||||||
ospf_lsack_send(n, ACKL_DIRECT);
|
ospf_send_lsack(p, n, ACKL_DIRECT);
|
||||||
|
|
||||||
/* If loading, ask for another part of neighbor's database */
|
/*
|
||||||
if (sendreq && (n->state == NEIGHBOR_LOADING))
|
* In loading state, we should ask for another batch of LSAs. This is only
|
||||||
|
* vaguely mentioned in RFC 2328. We send a new LSREQ only if the current
|
||||||
|
* LSUPD actually removed some entries from LSA request list (want_lsreq) and
|
||||||
|
* did not contain duplicate or early LSAs (skip_lsreq). The first condition
|
||||||
|
* prevents endless floods, the second condition helps with flow control.
|
||||||
|
*/
|
||||||
|
if ((n->state == NEIGHBOR_LOADING) && n->want_lsreq && !skip_lsreq)
|
||||||
ospf_send_lsreq(p, n);
|
ospf_send_lsreq(p, n);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -33,13 +33,26 @@ static void rxmt_timer_hook(timer * timer);
|
||||||
static void ackd_timer_hook(timer * t);
|
static void ackd_timer_hook(timer * t);
|
||||||
|
|
||||||
static void
|
static void
|
||||||
init_lists(struct ospf_neighbor *n)
|
init_lists(struct ospf_proto *p, struct ospf_neighbor *n)
|
||||||
{
|
{
|
||||||
s_init_list(&(n->lsrql));
|
s_init_list(&(n->lsrql));
|
||||||
n->lsrqh = ospf_top_new(n->pool);
|
n->lsrqh = ospf_top_new(p, n->pool);
|
||||||
|
|
||||||
s_init_list(&(n->lsrtl));
|
s_init_list(&(n->lsrtl));
|
||||||
n->lsrth = ospf_top_new(n->pool);
|
n->lsrth = ospf_top_new(p, n->pool);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
release_lsrtl(struct ospf_proto *p, struct ospf_neighbor *n)
|
||||||
|
{
|
||||||
|
struct top_hash_entry *ret, *en;
|
||||||
|
|
||||||
|
WALK_SLIST(ret, n->lsrtl)
|
||||||
|
{
|
||||||
|
en = ospf_hash_find_entry(p->gr, ret);
|
||||||
|
if (en)
|
||||||
|
en->ret_count--;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Resets LSA request and retransmit lists.
|
/* Resets LSA request and retransmit lists.
|
||||||
|
@ -47,11 +60,12 @@ init_lists(struct ospf_neighbor *n)
|
||||||
* it is reset during entering EXCHANGE state.
|
* it is reset during entering EXCHANGE state.
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
reset_lists(struct ospf_neighbor *n)
|
reset_lists(struct ospf_proto *p, struct ospf_neighbor *n)
|
||||||
{
|
{
|
||||||
|
release_lsrtl(p,n);
|
||||||
ospf_top_free(n->lsrqh);
|
ospf_top_free(n->lsrqh);
|
||||||
ospf_top_free(n->lsrth);
|
ospf_top_free(n->lsrth);
|
||||||
init_lists(n);
|
init_lists(p, n);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct ospf_neighbor *
|
struct ospf_neighbor *
|
||||||
|
@ -68,7 +82,7 @@ ospf_neighbor_new(struct ospf_iface *ifa)
|
||||||
n->csn = 0;
|
n->csn = 0;
|
||||||
n->state = NEIGHBOR_DOWN;
|
n->state = NEIGHBOR_DOWN;
|
||||||
|
|
||||||
init_lists(n);
|
init_lists(p, n);
|
||||||
s_init(&(n->dbsi), &(p->lsal));
|
s_init(&(n->dbsi), &(p->lsal));
|
||||||
|
|
||||||
n->inactim = tm_new(pool);
|
n->inactim = tm_new(pool);
|
||||||
|
@ -360,6 +374,10 @@ ospf_neigh_sm(struct ospf_neighbor *n, int event)
|
||||||
s_get(&(n->dbsi));
|
s_get(&(n->dbsi));
|
||||||
s_init(&(n->dbsi), &p->lsal);
|
s_init(&(n->dbsi), &p->lsal);
|
||||||
|
|
||||||
|
/* Add MaxAge LSA entries to retransmission list */
|
||||||
|
ospf_add_flushed_to_lsrt(p, n);
|
||||||
|
|
||||||
|
/* FIXME: Why is this here ? */
|
||||||
ospf_reset_lsack_queue(n);
|
ospf_reset_lsack_queue(n);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -388,7 +406,7 @@ ospf_neigh_sm(struct ospf_neighbor *n, int event)
|
||||||
if (n->state >= NEIGHBOR_EXSTART)
|
if (n->state >= NEIGHBOR_EXSTART)
|
||||||
if (!can_do_adj(n))
|
if (!can_do_adj(n))
|
||||||
{
|
{
|
||||||
reset_lists(n);
|
reset_lists(p,n);
|
||||||
neigh_chstate(n, NEIGHBOR_2WAY);
|
neigh_chstate(n, NEIGHBOR_2WAY);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -399,7 +417,7 @@ ospf_neigh_sm(struct ospf_neighbor *n, int event)
|
||||||
case INM_BADLSREQ:
|
case INM_BADLSREQ:
|
||||||
if (n->state >= NEIGHBOR_EXCHANGE)
|
if (n->state >= NEIGHBOR_EXCHANGE)
|
||||||
{
|
{
|
||||||
reset_lists(n);
|
reset_lists(p, n);
|
||||||
neigh_chstate(n, NEIGHBOR_EXSTART);
|
neigh_chstate(n, NEIGHBOR_EXSTART);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -407,12 +425,12 @@ ospf_neigh_sm(struct ospf_neighbor *n, int event)
|
||||||
case INM_KILLNBR:
|
case INM_KILLNBR:
|
||||||
case INM_LLDOWN:
|
case INM_LLDOWN:
|
||||||
case INM_INACTTIM:
|
case INM_INACTTIM:
|
||||||
reset_lists(n);
|
reset_lists(p, n);
|
||||||
neigh_chstate(n, NEIGHBOR_DOWN);
|
neigh_chstate(n, NEIGHBOR_DOWN);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case INM_1WAYREC:
|
case INM_1WAYREC:
|
||||||
reset_lists(n);
|
reset_lists(p, n);
|
||||||
neigh_chstate(n, NEIGHBOR_INIT);
|
neigh_chstate(n, NEIGHBOR_INIT);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -552,8 +570,10 @@ ospf_neigh_remove(struct ospf_neighbor *n)
|
||||||
nn->found = 0;
|
nn->found = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
s_get(&(n->dbsi));
|
|
||||||
neigh_chstate(n, NEIGHBOR_DOWN);
|
neigh_chstate(n, NEIGHBOR_DOWN);
|
||||||
|
|
||||||
|
s_get(&(n->dbsi));
|
||||||
|
release_lsrtl(p, n);
|
||||||
rem_node(NODE n);
|
rem_node(NODE n);
|
||||||
rfree(n->pool);
|
rfree(n->pool);
|
||||||
OSPF_TRACE(D_EVENTS, "Deleting neigbor %R", n->rid);
|
OSPF_TRACE(D_EVENTS, "Deleting neigbor %R", n->rid);
|
||||||
|
@ -620,9 +640,9 @@ ospf_sh_neigh_info(struct ospf_neighbor *n)
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
rxmt_timer_hook(timer * timer)
|
rxmt_timer_hook(timer *t)
|
||||||
{
|
{
|
||||||
struct ospf_neighbor *n = (struct ospf_neighbor *) timer->data;
|
struct ospf_neighbor *n = t->data;
|
||||||
struct ospf_proto *p = n->ifa->oa->po;
|
struct ospf_proto *p = n->ifa->oa->po;
|
||||||
|
|
||||||
DBG("%s: RXMT timer fired on interface %s for neigh %I\n",
|
DBG("%s: RXMT timer fired on interface %s for neigh %I\n",
|
||||||
|
@ -631,12 +651,12 @@ rxmt_timer_hook(timer * timer)
|
||||||
switch (n->state)
|
switch (n->state)
|
||||||
{
|
{
|
||||||
case NEIGHBOR_EXSTART:
|
case NEIGHBOR_EXSTART:
|
||||||
ospf_send_dbdes(n, 1);
|
ospf_send_dbdes(p, n, 1);
|
||||||
return;
|
return;
|
||||||
|
|
||||||
case NEIGHBOR_EXCHANGE:
|
case NEIGHBOR_EXCHANGE:
|
||||||
if (n->myimms & DBDES_MS)
|
if (n->myimms & DBDES_MS)
|
||||||
ospf_send_dbdes(n, 0);
|
ospf_send_dbdes(p, n, 0);
|
||||||
case NEIGHBOR_LOADING:
|
case NEIGHBOR_LOADING:
|
||||||
ospf_send_lsreq(p, n);
|
ospf_send_lsreq(p, n);
|
||||||
return;
|
return;
|
||||||
|
@ -653,8 +673,13 @@ rxmt_timer_hook(timer * timer)
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
ackd_timer_hook(timer * t)
|
ackd_timer_hook(timer *t)
|
||||||
{
|
{
|
||||||
struct ospf_neighbor *n = t->data;
|
struct ospf_neighbor *n = t->data;
|
||||||
ospf_lsack_send(n, ACKL_DELAY);
|
struct ospf_proto *p = n->ifa->oa->po;
|
||||||
|
|
||||||
|
DBG("%s: ACKD timer fired on interface %s for neigh %I\n",
|
||||||
|
p->p.name, n->ifa->ifname, n->ip);
|
||||||
|
|
||||||
|
ospf_send_lsack(p, n, ACKL_DELAY);
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,93 +11,81 @@
|
||||||
/**
|
/**
|
||||||
* DOC: Open Shortest Path First (OSPF)
|
* DOC: Open Shortest Path First (OSPF)
|
||||||
*
|
*
|
||||||
* The OSPF protocol is quite complicated and its complex implemenation is
|
* The OSPF protocol is quite complicated and its complex implemenation is split
|
||||||
* split to many files. In |ospf.c|, you will find mainly the interface
|
* to many files. In |ospf.c|, you will find mainly the interface for
|
||||||
* for communication with the core (e.g., reconfiguration hooks, shutdown
|
* communication with the core (e.g., reconfiguration hooks, shutdown and
|
||||||
* and initialisation and so on). In |packet.c|, you will find various
|
* initialisation and so on). File |iface.c| contains the interface state
|
||||||
* functions for sending and receiving generic OSPF packets. There are
|
* machine and functions for allocation and deallocation of OSPF's interface
|
||||||
* also routines for authentication and checksumming. File |iface.c| contains
|
* data structures. Source |neighbor.c| includes the neighbor state machine and
|
||||||
* the interface state machine and functions for allocation and deallocation of OSPF's
|
* functions for election of Designated Router and Backup Designated router. In
|
||||||
* interface data structures. Source |neighbor.c| includes the neighbor state
|
* |packet.c|, you will find various functions for sending and receiving generic
|
||||||
* machine and functions for election of Designated Router and Backup
|
* OSPF packets. There are also routines for authentication and checksumming.
|
||||||
* Designated router. In |hello.c|, there are routines for sending
|
* In |hello.c|, there are routines for sending and receiving of hello packets
|
||||||
* and receiving of hello packets as well as functions for maintaining
|
* as well as functions for maintaining wait times and the inactivity timer.
|
||||||
* wait times and the inactivity timer. Files |lsreq.c|, |lsack.c|, |dbdes.c|
|
* Files |lsreq.c|, |lsack.c|, |dbdes.c| contain functions for sending and
|
||||||
* contain functions for sending and receiving of link-state requests,
|
* receiving of link-state requests, link-state acknowledgements and database
|
||||||
* link-state acknowledgements and database descriptions respectively.
|
* descriptions respectively. In |lsupd.c|, there are functions for sending and
|
||||||
* In |lsupd.c|, there are functions for sending and receiving
|
* receiving of link-state updates and also the flooding algorithm. Source
|
||||||
* of link-state updates and also the flooding algorithm. Source |topology.c| is
|
* |topology.c| is a place where routines for searching LSAs in the link-state
|
||||||
* a place where routines for searching LSAs in the link-state database,
|
* database, adding and deleting them reside, there also are functions for
|
||||||
* adding and deleting them reside, there also are functions for originating
|
* originating of various types of LSAs (router LSA, net LSA, external LSA).
|
||||||
* of various types of LSAs (router LSA, net LSA, external LSA). File |rt.c|
|
* File |rt.c| contains routines for calculating the routing table. |lsalib.c|
|
||||||
* contains routines for calculating the routing table. |lsalib.c| is a set
|
* is a set of various functions for working with the LSAs (endianity
|
||||||
* of various functions for working with the LSAs (endianity conversions,
|
* conversions, calculation of checksum etc.).
|
||||||
* calculation of checksum etc.).
|
|
||||||
*
|
*
|
||||||
* One instance of the protocol is able to hold LSA databases for
|
* One instance of the protocol is able to hold LSA databases for multiple OSPF
|
||||||
* multiple OSPF areas, to exchange routing information between
|
* areas, to exchange routing information between multiple neighbors and to
|
||||||
* multiple neighbors and to calculate the routing tables. The core
|
* calculate the routing tables. The core structure is &ospf_proto to which
|
||||||
* structure is &ospf_proto to which multiple &ospf_area and
|
* multiple &ospf_area and &ospf_iface structures are connected. &ospf_proto is
|
||||||
* &ospf_iface structures are connected. &ospf_area is also connected to
|
* also connected to &top_hash_graph which is a dynamic hashing structure that
|
||||||
* &top_hash_graph which is a dynamic hashing structure that
|
* describes the link-state database. It allows fast search, addition and
|
||||||
* describes the link-state database. It allows fast search, addition
|
* deletion. Each LSA is kept in two pieces: header and body. Both of them are
|
||||||
* and deletion. Each LSA is kept in two pieces: header and body. Both of them are
|
|
||||||
* kept in the endianity of the CPU.
|
* kept in the endianity of the CPU.
|
||||||
*
|
*
|
||||||
* In OSPFv2 specification, it is implied that there is one IP prefix
|
* In OSPFv2 specification, it is implied that there is one IP prefix for each
|
||||||
* for each physical network/interface (unless it is an ptp link). But
|
* physical network/interface (unless it is an ptp link). But in modern systems,
|
||||||
* in modern systems, there might be more independent IP prefixes
|
* there might be more independent IP prefixes associated with an interface. To
|
||||||
* associated with an interface. To handle this situation, we have
|
* handle this situation, we have one &ospf_iface for each active IP prefix
|
||||||
* one &ospf_iface for each active IP prefix (instead for each active
|
* (instead for each active iface); This behaves like virtual interface for the
|
||||||
* iface); This behaves like virtual interface for the purpose of OSPF.
|
* purpose of OSPF. If we receive packet, we associate it with a proper virtual
|
||||||
* If we receive packet, we associate it with a proper virtual interface
|
* interface mainly according to its source address.
|
||||||
* mainly according to its source address.
|
|
||||||
*
|
*
|
||||||
* OSPF keeps one socket per &ospf_iface. This allows us (compared to
|
* OSPF keeps one socket per &ospf_iface. This allows us (compared to one socket
|
||||||
* one socket approach) to evade problems with a limit of multicast
|
* approach) to evade problems with a limit of multicast groups per socket and
|
||||||
* groups per socket and with sending multicast packets to appropriate
|
* with sending multicast packets to appropriate interface in a portable way.
|
||||||
* interface in a portable way. The socket is associated with
|
* The socket is associated with underlying physical iface and should not
|
||||||
* underlying physical iface and should not receive packets received
|
* receive packets received on other ifaces (unfortunately, this is not true on
|
||||||
* on other ifaces (unfortunately, this is not true on
|
* BSD). Generally, one packet can be received by more sockets (for example, if
|
||||||
* BSD). Generally, one packet can be received by more sockets (for
|
* there are more &ospf_iface on one physical iface), therefore we explicitly
|
||||||
* example, if there are more &ospf_iface on one physical iface),
|
* filter received packets according to src/dst IP address and received iface.
|
||||||
* therefore we explicitly filter received packets according to
|
|
||||||
* src/dst IP address and received iface.
|
|
||||||
*
|
*
|
||||||
* Vlinks are implemented using particularly degenerate form of
|
* Vlinks are implemented using particularly degenerate form of &ospf_iface,
|
||||||
* &ospf_iface, which has several exceptions: it does not have its
|
* which has several exceptions: it does not have its iface or socket (it copies
|
||||||
* iface or socket (it copies these from 'parent' &ospf_iface) and it
|
* these from 'parent' &ospf_iface) and it is present in iface list even when
|
||||||
* is present in iface list even when down (it is not freed in
|
* down (it is not freed in ospf_iface_down()).
|
||||||
* ospf_iface_down()).
|
|
||||||
*
|
*
|
||||||
* The heart beat of ospf is ospf_disp(). It is called at regular intervals
|
* The heart beat of ospf is ospf_disp(). It is called at regular intervals
|
||||||
* (&ospf_proto->tick). It is responsible for aging and flushing of LSAs in
|
* (&ospf_proto->tick). It is responsible for aging and flushing of LSAs in the
|
||||||
* the database, for routing table calculaction and it call area_disp() of every
|
* database, updating topology information in LSAs and for routing table
|
||||||
* ospf_area.
|
* calculation.
|
||||||
*
|
*
|
||||||
* The function area_disp() is
|
* To every &ospf_iface, we connect one or more &ospf_neighbor's -- a structure
|
||||||
* responsible for late originating of router LSA and network LSA
|
* containing many timers and queues for building adjacency and for exchange of
|
||||||
* and for cleanup before routing table calculation process in
|
* routing messages.
|
||||||
* the area.
|
|
||||||
* To every &ospf_iface, we connect one or more
|
|
||||||
* &ospf_neighbor's -- a structure containing many timers and queues
|
|
||||||
* for building adjacency and for exchange of routing messages.
|
|
||||||
*
|
*
|
||||||
* BIRD's OSPF implementation respects RFC2328 in every detail, but
|
* BIRD's OSPF implementation respects RFC2328 in every detail, but some of
|
||||||
* some of internal algorithms do differ. The RFC recommends making a snapshot
|
* internal algorithms do differ. The RFC recommends making a snapshot of the
|
||||||
* of the link-state database when a new adjacency is forming and sending
|
* link-state database when a new adjacency is forming and sending the database
|
||||||
* the database description packets based on the information in this
|
* description packets based on the information in this snapshot. The database
|
||||||
* snapshot. The database can be quite large in some networks, so
|
* can be quite large in some networks, so rather we walk through a &slist
|
||||||
* rather we walk through a &slist structure which allows us to
|
* structure which allows us to continue even if the actual LSA we were working
|
||||||
* continue even if the actual LSA we were working with is deleted. New
|
* with is deleted. New LSAs are added at the tail of this &slist.
|
||||||
* LSAs are added at the tail of this &slist.
|
|
||||||
*
|
*
|
||||||
* We also don't keep a separate OSPF routing table, because the core
|
* We also do not keep a separate OSPF routing table, because the core helps us
|
||||||
* helps us by being able to recognize when a route is updated
|
* by being able to recognize when a route is updated to an identical one and it
|
||||||
* to an identical one and it suppresses the update automatically.
|
* suppresses the update automatically. Due to this, we can flush all the routes
|
||||||
* Due to this, we can flush all the routes we've recalculated and
|
* we have recalculated and also those we have deleted to the core's routing
|
||||||
* also those we've deleted to the core's routing table and the
|
* table and the core will take care of the rest. This simplifies the process
|
||||||
* core will take care of the rest. This simplifies the process
|
|
||||||
* and conserves memory.
|
* and conserves memory.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@ -145,7 +133,7 @@ add_area_nets(struct ospf_area *oa, struct ospf_area_config *ac)
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
ospf_area_add(struct ospf_proto *p, struct ospf_area_config *ac, int reconf)
|
ospf_area_add(struct ospf_proto *p, struct ospf_area_config *ac)
|
||||||
{
|
{
|
||||||
struct ospf_area *oa;
|
struct ospf_area *oa;
|
||||||
|
|
||||||
|
@ -169,6 +157,8 @@ ospf_area_add(struct ospf_proto *p, struct ospf_area_config *ac, int reconf)
|
||||||
oa->options = ac->type;
|
oa->options = ac->type;
|
||||||
else
|
else
|
||||||
oa->options = ac->type | OPT_V6 | (p->stub_router ? 0 : OPT_R);
|
oa->options = ac->type | OPT_V6 | (p->stub_router ? 0 : OPT_R);
|
||||||
|
|
||||||
|
ospf_notify_rt_lsa(oa);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -252,11 +242,11 @@ ospf_start(struct proto *P)
|
||||||
init_list(&(p->area_list));
|
init_list(&(p->area_list));
|
||||||
fib_init(&p->rtf, P->pool, sizeof(ort), 0, ospf_rt_initort);
|
fib_init(&p->rtf, P->pool, sizeof(ort), 0, ospf_rt_initort);
|
||||||
p->areano = 0;
|
p->areano = 0;
|
||||||
p->gr = ospf_top_new(P->pool);
|
p->gr = ospf_top_new(p, P->pool);
|
||||||
s_init_list(&(p->lsal));
|
s_init_list(&(p->lsal));
|
||||||
|
|
||||||
WALK_LIST(ac, c->area_list)
|
WALK_LIST(ac, c->area_list)
|
||||||
ospf_area_add(p, ac, 0);
|
ospf_area_add(p, ac);
|
||||||
|
|
||||||
if (c->abr)
|
if (c->abr)
|
||||||
ospf_open_vlink_sk(p);
|
ospf_open_vlink_sk(p);
|
||||||
|
@ -382,7 +372,7 @@ ospf_build_attrs(ea_list * next, struct linpool *pool, u32 m1, u32 m2,
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
schedule_rtcalc(struct ospf_proto *p)
|
ospf_schedule_rtcalc(struct ospf_proto *p)
|
||||||
{
|
{
|
||||||
if (p->calcrt)
|
if (p->calcrt)
|
||||||
return;
|
return;
|
||||||
|
@ -418,7 +408,7 @@ ospf_disp(timer * timer)
|
||||||
/* Originate or flush local topology LSAs */
|
/* Originate or flush local topology LSAs */
|
||||||
ospf_update_topology(p);
|
ospf_update_topology(p);
|
||||||
|
|
||||||
/* Age LSA DB */
|
/* Process LSA DB */
|
||||||
ospf_update_lsadb(p);
|
ospf_update_lsadb(p);
|
||||||
|
|
||||||
/* Calculate routing table */
|
/* Calculate routing table */
|
||||||
|
@ -429,7 +419,7 @@ ospf_disp(timer * timer)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ospf_import_control - accept or reject new route from nest's routing table
|
* ospf_import_control - accept or reject new route from nest's routing table
|
||||||
* @p: current instance of protocol
|
* @P: OSPF protocol instance
|
||||||
* @new: the new route
|
* @new: the new route
|
||||||
* @attrs: list of attributes
|
* @attrs: list of attributes
|
||||||
* @pool: pool for allocation of attributes
|
* @pool: pool for allocation of attributes
|
||||||
|
@ -475,7 +465,7 @@ ospf_store_tmp_attrs(struct rte *rt, struct ea_list *attrs)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ospf_shutdown - Finish of OSPF instance
|
* ospf_shutdown - Finish of OSPF instance
|
||||||
* @p: current instance of protocol
|
* @P: OSPF protocol instance
|
||||||
*
|
*
|
||||||
* RFC does not define any action that should be taken before router
|
* RFC does not define any action that should be taken before router
|
||||||
* shutdown. To make my neighbors react as fast as possible, I send
|
* shutdown. To make my neighbors react as fast as possible, I send
|
||||||
|
@ -619,7 +609,7 @@ ospf_area_reconfigure(struct ospf_area *oa, struct ospf_area_config *nac)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ospf_reconfigure - reconfiguration hook
|
* ospf_reconfigure - reconfiguration hook
|
||||||
* @p: current instance of protocol (with old configuration)
|
* @P: current instance of protocol (with old configuration)
|
||||||
* @c: new configuration requested by user
|
* @c: new configuration requested by user
|
||||||
*
|
*
|
||||||
* This hook tries to be a little bit intelligent. Instance of OSPF
|
* This hook tries to be a little bit intelligent. Instance of OSPF
|
||||||
|
@ -669,7 +659,7 @@ ospf_reconfigure(struct proto *P, struct proto_config *c)
|
||||||
if (oa)
|
if (oa)
|
||||||
ospf_area_reconfigure(oa, nac);
|
ospf_area_reconfigure(oa, nac);
|
||||||
else
|
else
|
||||||
ospf_area_add(p, nac, 1);
|
ospf_area_add(p, nac);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Add and update interfaces */
|
/* Add and update interfaces */
|
||||||
|
@ -697,7 +687,7 @@ ospf_reconfigure(struct proto *P, struct proto_config *c)
|
||||||
if (oa->marked)
|
if (oa->marked)
|
||||||
ospf_area_remove(oa);
|
ospf_area_remove(oa);
|
||||||
|
|
||||||
schedule_rtcalc(p);
|
ospf_schedule_rtcalc(p);
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
@ -1009,7 +999,7 @@ show_lsa_router(struct ospf_proto *p, struct top_hash_entry *he, int verbose)
|
||||||
/* In OSPFv2, we try to find network-LSA to get prefix/pxlen */
|
/* In OSPFv2, we try to find network-LSA to get prefix/pxlen */
|
||||||
struct top_hash_entry *net_he = ospf_hash_find_net2(p->gr, he->domain, rtl.id);
|
struct top_hash_entry *net_he = ospf_hash_find_net2(p->gr, he->domain, rtl.id);
|
||||||
|
|
||||||
if (net_he)
|
if (net_he && (net_he->lsa.age < LSA_MAXAGE))
|
||||||
{
|
{
|
||||||
struct ospf_lsa_header *net_lsa = &(net_he->lsa);
|
struct ospf_lsa_header *net_lsa = &(net_he->lsa);
|
||||||
struct ospf_lsa_net *net_ln = net_he->lsa_body;
|
struct ospf_lsa_net *net_ln = net_he->lsa_body;
|
||||||
|
@ -1367,8 +1357,8 @@ void
|
||||||
ospf_sh_lsadb(struct lsadb_show_data *ld)
|
ospf_sh_lsadb(struct lsadb_show_data *ld)
|
||||||
{
|
{
|
||||||
struct ospf_proto *p = (struct ospf_proto *) proto_get_named(ld->name, &proto_ospf);
|
struct ospf_proto *p = (struct ospf_proto *) proto_get_named(ld->name, &proto_ospf);
|
||||||
int num = p->gr->hash_entries;
|
uint num = p->gr->hash_entries;
|
||||||
unsigned int i, j;
|
uint i, j;
|
||||||
int last_dscope = -1;
|
int last_dscope = -1;
|
||||||
u32 last_domain = 0;
|
u32 last_domain = 0;
|
||||||
u16 type_mask = ospf_is_v2(p) ? 0x00ff : 0xffff; /* see lsa_etype() */
|
u16 type_mask = ospf_is_v2(p) ? 0x00ff : 0xffff; /* see lsa_etype() */
|
||||||
|
|
|
@ -102,7 +102,7 @@ do { if ((p->p.debug & D_PACKETS) || OSPF_FORCE_DEBUG) \
|
||||||
struct ospf_config
|
struct ospf_config
|
||||||
{
|
{
|
||||||
struct proto_config c;
|
struct proto_config c;
|
||||||
unsigned tick;
|
uint tick;
|
||||||
byte ospf2;
|
byte ospf2;
|
||||||
byte rfc1583;
|
byte rfc1583;
|
||||||
byte stub_router;
|
byte stub_router;
|
||||||
|
@ -110,16 +110,26 @@ struct ospf_config
|
||||||
byte abr;
|
byte abr;
|
||||||
byte asbr;
|
byte asbr;
|
||||||
int ecmp;
|
int ecmp;
|
||||||
list area_list; /* list of struct ospf_area_config */
|
list area_list; /* list of area configs (struct ospf_area_config) */
|
||||||
list vlink_list; /* list of struct ospf_iface_patt */
|
list vlink_list; /* list of configured vlinks (struct ospf_iface_patt) */
|
||||||
};
|
};
|
||||||
|
|
||||||
struct nbma_node
|
struct ospf_area_config
|
||||||
{
|
{
|
||||||
node n;
|
node n;
|
||||||
ip_addr ip;
|
u32 areaid;
|
||||||
byte eligible;
|
u32 default_cost; /* Cost of default route for stub areas
|
||||||
byte found;
|
(With possible LSA_EXT3_EBIT for NSSA areas) */
|
||||||
|
u8 type; /* Area type (standard, stub, NSSA), represented
|
||||||
|
by option flags (OPT_E, OPT_N) */
|
||||||
|
u8 summary; /* Import summaries to this stub/NSSA area, valid for ABR */
|
||||||
|
u8 default_nssa; /* Generate default NSSA route for NSSA+summary area */
|
||||||
|
u8 translator; /* Translator role, for NSSA ABR */
|
||||||
|
u32 transint; /* Translator stability interval */
|
||||||
|
list patt_list; /* List of iface configs (struct ospf_iface_patt) */
|
||||||
|
list net_list; /* List of aggregate networks for that area */
|
||||||
|
list enet_list; /* List of aggregate external (NSSA) networks */
|
||||||
|
list stubnet_list; /* List of stub networks added to Router LSA */
|
||||||
};
|
};
|
||||||
|
|
||||||
struct area_net_config
|
struct area_net_config
|
||||||
|
@ -148,65 +158,54 @@ struct ospf_stubnet_config
|
||||||
u8 summary;
|
u8 summary;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ospf_area_config
|
struct nbma_node
|
||||||
{
|
{
|
||||||
node n;
|
node n;
|
||||||
u32 areaid;
|
ip_addr ip;
|
||||||
u32 default_cost; /* Cost of default route for stub areas
|
byte eligible;
|
||||||
(With possible LSA_EXT3_EBIT for NSSA areas) */
|
byte found;
|
||||||
u8 type; /* Area type (standard, stub, NSSA), represented
|
|
||||||
by option flags (OPT_E, OPT_N) */
|
|
||||||
u8 summary; /* Import summaries to this stub/NSSA area, valid for ABR */
|
|
||||||
u8 default_nssa; /* Generate default NSSA route for NSSA+summary area */
|
|
||||||
u8 translator; /* Translator role, for NSSA ABR */
|
|
||||||
u32 transint; /* Translator stability interval */
|
|
||||||
list patt_list;
|
|
||||||
list net_list; /* List of aggregate networks for that area */
|
|
||||||
list enet_list; /* List of aggregate external (NSSA) networks */
|
|
||||||
list stubnet_list; /* List of stub networks added to Router LSA */
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct ospf_iface_patt
|
||||||
|
{
|
||||||
|
struct iface_patt i;
|
||||||
|
u32 type;
|
||||||
|
u32 stub;
|
||||||
|
u32 cost;
|
||||||
|
u32 helloint;
|
||||||
|
u32 rxmtint;
|
||||||
|
u32 pollint;
|
||||||
|
u32 waitint;
|
||||||
|
u32 deadc;
|
||||||
|
u32 deadint;
|
||||||
|
u32 inftransdelay;
|
||||||
|
list nbma_list;
|
||||||
|
u32 priority;
|
||||||
|
u32 voa;
|
||||||
|
u32 vid;
|
||||||
|
int tx_tos;
|
||||||
|
int tx_priority;
|
||||||
|
u16 tx_length;
|
||||||
|
u16 rx_buffer;
|
||||||
|
|
||||||
/* Generic option flags */
|
#define OSPF_RXBUF_MINSIZE 256 /* Minimal allowed size */
|
||||||
#define OPT_V6 0x01 /* OSPFv3, LSA relevant for IPv6 routing calculation */
|
u8 instance_id;
|
||||||
#define OPT_E 0x02 /* Related to AS-external LSAs */
|
u8 autype; /* Not really used in OSPFv3 */
|
||||||
#define OPT_MC 0x04 /* Related to MOSPF, not used and obsolete */
|
#define OSPF_AUTH_NONE 0
|
||||||
#define OPT_N 0x08 /* Related to NSSA */
|
#define OSPF_AUTH_SIMPLE 1
|
||||||
#define OPT_P 0x08 /* OSPFv2, flags P and N share position, see NSSA RFC */
|
#define OSPF_AUTH_CRYPT 2
|
||||||
#define OPT_EA 0x10 /* OSPFv2, external attributes, not used and obsolete */
|
#define OSPF_AUTH_CRYPT_SIZE 16
|
||||||
#define OPT_R 0x10 /* OSPFv3, originator is active router */
|
u8 strictnbma;
|
||||||
#define OPT_DC 0x20 /* Related to demand circuits, not used */
|
u8 check_link;
|
||||||
|
u8 ecmp_weight;
|
||||||
/* Router-LSA VEB flags are are stored together with links (OSPFv2) or options (OSPFv3) */
|
u8 link_lsa_suppression;
|
||||||
#define OPT_RT_B (0x01 << 24)
|
u8 real_bcast; /* Not really used in OSPFv3 */
|
||||||
#define OPT_RT_E (0x02 << 24)
|
u8 ptp_netmask; /* bool + 2 for unspecified */
|
||||||
#define OPT_RT_V (0x04 << 24)
|
u8 ttl_security; /* bool + 2 for TX only */
|
||||||
#define OPT_RT_NT (0x10 << 24)
|
u8 bfd;
|
||||||
|
u8 bsd_secondary;
|
||||||
/* Prefix flags, specific for OSPFv3 */
|
list *passwords;
|
||||||
#define OPT_PX_NU 0x01
|
};
|
||||||
#define OPT_PX_LA 0x02
|
|
||||||
#define OPT_PX_P 0x08
|
|
||||||
#define OPT_PX_DN 0x10
|
|
||||||
|
|
||||||
|
|
||||||
/* OSPF interface types */
|
|
||||||
#define OSPF_IT_BCAST 0
|
|
||||||
#define OSPF_IT_NBMA 1
|
|
||||||
#define OSPF_IT_PTP 2
|
|
||||||
#define OSPF_IT_PTMP 3
|
|
||||||
#define OSPF_IT_VLINK 4
|
|
||||||
#define OSPF_IT_UNDEF 5
|
|
||||||
|
|
||||||
/* OSPF interface states */
|
|
||||||
#define OSPF_IS_DOWN 0 /* Not active */
|
|
||||||
#define OSPF_IS_LOOP 1 /* Iface with no link */
|
|
||||||
#define OSPF_IS_WAITING 2 /* Waiting for Wait timer */
|
|
||||||
#define OSPF_IS_PTP 3 /* PTP operational */
|
|
||||||
#define OSPF_IS_DROTHER 4 /* I'm on BCAST or NBMA and I'm not DR */
|
|
||||||
#define OSPF_IS_BACKUP 5 /* I'm BDR */
|
|
||||||
#define OSPF_IS_DR 6 /* I'm DR */
|
|
||||||
|
|
||||||
|
|
||||||
/* Default values for interface parameters */
|
/* Default values for interface parameters */
|
||||||
#define COST_D 10
|
#define COST_D 10
|
||||||
|
@ -220,6 +219,58 @@ struct ospf_area_config
|
||||||
/* Value of Wait timer - not found it in RFC * - using 4*HELLO */
|
/* Value of Wait timer - not found it in RFC * - using 4*HELLO */
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
struct ospf_proto
|
||||||
|
{
|
||||||
|
struct proto p;
|
||||||
|
timer *disp_timer; /* OSPF proto dispatcher */
|
||||||
|
uint tick;
|
||||||
|
struct top_graph *gr; /* LSA graph */
|
||||||
|
slist lsal; /* List of all LSA's */
|
||||||
|
int calcrt; /* Routing table calculation scheduled?
|
||||||
|
0=no, 1=normal, 2=forced reload */
|
||||||
|
list iface_list; /* List of OSPF interfaces (struct ospf_iface) */
|
||||||
|
list area_list; /* List of OSPF areas (struct ospf_area) */
|
||||||
|
int areano; /* Number of area I belong to */
|
||||||
|
int padj; /* Number of neighbors in Exchange or Loading state */
|
||||||
|
struct fib rtf; /* Routing table */
|
||||||
|
byte ospf2; /* OSPF v2 or v3 */
|
||||||
|
byte rfc1583; /* RFC1583 compatibility */
|
||||||
|
byte stub_router; /* Do not forward transit traffic */
|
||||||
|
byte merge_external; /* Should i merge external routes? */
|
||||||
|
byte asbr; /* May i originate any ext/NSSA lsa? */
|
||||||
|
byte ecmp; /* Maximal number of nexthops in ECMP route, or 0 */
|
||||||
|
struct ospf_area *backbone; /* If exists */
|
||||||
|
void *lsab; /* LSA buffer used when originating router LSAs */
|
||||||
|
int lsab_size, lsab_used;
|
||||||
|
linpool *nhpool; /* Linpool used for next hops computed in SPF */
|
||||||
|
sock *vlink_sk; /* IP socket used for vlink TX */
|
||||||
|
u32 router_id;
|
||||||
|
u32 last_vlink_id; /* Interface IDs for vlinks (starts at 0x80000000) */
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ospf_area
|
||||||
|
{
|
||||||
|
node n;
|
||||||
|
u32 areaid;
|
||||||
|
struct ospf_area_config *ac; /* Related area config */
|
||||||
|
struct top_hash_entry *rt; /* My own router LSA */
|
||||||
|
struct top_hash_entry *pxr_lsa; /* Originated prefix LSA */
|
||||||
|
list cand; /* List of candidates for RT calc. */
|
||||||
|
struct fib net_fib; /* Networks to advertise or not */
|
||||||
|
struct fib enet_fib; /* External networks for NSSAs */
|
||||||
|
u32 options; /* Optional features */
|
||||||
|
u8 update_rt_lsa; /* Rt lsa origination scheduled? */
|
||||||
|
u8 trcap; /* Transit capability? */
|
||||||
|
u8 marked; /* Used in OSPF reconfigure */
|
||||||
|
u8 translate; /* Translator state (TRANS_*), for NSSA ABR */
|
||||||
|
timer *translator_timer; /* For NSSA translator switch */
|
||||||
|
struct ospf_proto *po;
|
||||||
|
struct fib rtr; /* Routing tables for routers */
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
struct ospf_iface
|
struct ospf_iface
|
||||||
{
|
{
|
||||||
node n;
|
node n;
|
||||||
|
@ -231,7 +282,7 @@ struct ospf_iface
|
||||||
|
|
||||||
pool *pool;
|
pool *pool;
|
||||||
sock *sk; /* IP socket */
|
sock *sk; /* IP socket */
|
||||||
list neigh_list; /* List of neigbours */
|
list neigh_list; /* List of neigbours (struct ospf_neighbor) */
|
||||||
u32 cost; /* Cost of iface */
|
u32 cost; /* Cost of iface */
|
||||||
u32 waitint; /* number of sec before changing state from wait */
|
u32 waitint; /* number of sec before changing state from wait */
|
||||||
u32 rxmtint; /* number of seconds between LSA retransmissions */
|
u32 rxmtint; /* number of seconds between LSA retransmissions */
|
||||||
|
@ -295,6 +346,153 @@ struct ospf_iface
|
||||||
u8 bfd; /* Use BFD on iface */
|
u8 bfd; /* Use BFD on iface */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct ospf_neighbor
|
||||||
|
{
|
||||||
|
node n;
|
||||||
|
pool *pool;
|
||||||
|
struct ospf_iface *ifa;
|
||||||
|
u8 state;
|
||||||
|
timer *inactim; /* Inactivity timer */
|
||||||
|
u8 imms; /* I, M, Master/slave received */
|
||||||
|
u8 myimms; /* I, M Master/slave */
|
||||||
|
u32 dds; /* DD Sequence number being sent */
|
||||||
|
u32 ddr; /* last Dat Des packet received */
|
||||||
|
|
||||||
|
u32 rid; /* Router ID */
|
||||||
|
ip_addr ip; /* IP of it's interface */
|
||||||
|
u8 priority; /* Priority */
|
||||||
|
u8 adj; /* built adjacency? */
|
||||||
|
u8 want_lsreq; /* Set to 1 when lsrql was shortened during LSUPD */
|
||||||
|
u32 options; /* Options received */
|
||||||
|
|
||||||
|
/* 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 */
|
||||||
|
|
||||||
|
/* 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.
|
||||||
|
* These entries hold ret_count in appropriate LSA entries.
|
||||||
|
*/
|
||||||
|
slist lsrtl; /* slist of struct top_hash_entry from n->lsrth */
|
||||||
|
struct top_graph *lsrth;
|
||||||
|
timer *rxmt_timer; /* RXMT timer */
|
||||||
|
list ackl[2];
|
||||||
|
#define ACKL_DIRECT 0
|
||||||
|
#define ACKL_DELAY 1
|
||||||
|
timer *ackd_timer; /* Delayed ack timer */
|
||||||
|
struct bfd_request *bfd_req; /* BFD request, if BFD is used */
|
||||||
|
void *ldd_buffer; /* Last database description packet */
|
||||||
|
u32 ldd_bsize; /* Buffer size for ldd_buffer */
|
||||||
|
u32 csn; /* Last received crypt seq number (for MD5) */
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/* OSPF interface types */
|
||||||
|
#define OSPF_IT_BCAST 0
|
||||||
|
#define OSPF_IT_NBMA 1
|
||||||
|
#define OSPF_IT_PTP 2
|
||||||
|
#define OSPF_IT_PTMP 3
|
||||||
|
#define OSPF_IT_VLINK 4
|
||||||
|
#define OSPF_IT_UNDEF 5
|
||||||
|
|
||||||
|
/* OSPF interface states */
|
||||||
|
#define OSPF_IS_DOWN 0 /* Not active */
|
||||||
|
#define OSPF_IS_LOOP 1 /* Iface with no link */
|
||||||
|
#define OSPF_IS_WAITING 2 /* Waiting for Wait timer */
|
||||||
|
#define OSPF_IS_PTP 3 /* PTP operational */
|
||||||
|
#define OSPF_IS_DROTHER 4 /* I'm on BCAST or NBMA and I'm not DR */
|
||||||
|
#define OSPF_IS_BACKUP 5 /* I'm BDR */
|
||||||
|
#define OSPF_IS_DR 6 /* I'm DR */
|
||||||
|
|
||||||
|
/* Definitions for interface state machine */
|
||||||
|
#define ISM_UP 0 /* Interface Up */
|
||||||
|
#define ISM_WAITF 1 /* Wait timer fired */
|
||||||
|
#define ISM_BACKS 2 /* Backup seen */
|
||||||
|
#define ISM_NEICH 3 /* Neighbor change */
|
||||||
|
#define ISM_LOOP 4 /* Link down */
|
||||||
|
#define ISM_UNLOOP 5 /* Link up */
|
||||||
|
#define ISM_DOWN 6 /* Interface down */
|
||||||
|
|
||||||
|
|
||||||
|
/* OSPF neighbor states */
|
||||||
|
#define NEIGHBOR_DOWN 0
|
||||||
|
#define NEIGHBOR_ATTEMPT 1
|
||||||
|
#define NEIGHBOR_INIT 2
|
||||||
|
#define NEIGHBOR_2WAY 3
|
||||||
|
#define NEIGHBOR_EXSTART 4
|
||||||
|
#define NEIGHBOR_EXCHANGE 5
|
||||||
|
#define NEIGHBOR_LOADING 6
|
||||||
|
#define NEIGHBOR_FULL 7
|
||||||
|
|
||||||
|
/* Definitions for neighbor state machine */
|
||||||
|
#define INM_HELLOREC 0 /* Hello Received */
|
||||||
|
#define INM_START 1 /* Neighbor start - for NBMA */
|
||||||
|
#define INM_2WAYREC 2 /* 2-Way received */
|
||||||
|
#define INM_NEGDONE 3 /* Negotiation done */
|
||||||
|
#define INM_EXDONE 4 /* Exchange done */
|
||||||
|
#define INM_BADLSREQ 5 /* Bad LS Request */
|
||||||
|
#define INM_LOADDONE 6 /* Load done */
|
||||||
|
#define INM_ADJOK 7 /* AdjOK? */
|
||||||
|
#define INM_SEQMIS 8 /* Sequence number mismatch */
|
||||||
|
#define INM_1WAYREC 9 /* 1-Way */
|
||||||
|
#define INM_KILLNBR 10 /* Kill Neighbor */
|
||||||
|
#define INM_INACTTIM 11 /* Inactivity timer */
|
||||||
|
#define INM_LLDOWN 12 /* Line down */
|
||||||
|
|
||||||
|
#define TRANS_OFF 0
|
||||||
|
#define TRANS_ON 1
|
||||||
|
#define TRANS_WAIT 2 /* Waiting before the end of translation */
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* Generic option flags */
|
||||||
|
#define OPT_V6 0x01 /* OSPFv3, LSA relevant for IPv6 routing calculation */
|
||||||
|
#define OPT_E 0x02 /* Related to AS-external LSAs */
|
||||||
|
#define OPT_MC 0x04 /* Related to MOSPF, not used and obsolete */
|
||||||
|
#define OPT_N 0x08 /* Related to NSSA */
|
||||||
|
#define OPT_P 0x08 /* OSPFv2, flags P and N share position, see NSSA RFC */
|
||||||
|
#define OPT_EA 0x10 /* OSPFv2, external attributes, not used and obsolete */
|
||||||
|
#define OPT_R 0x10 /* OSPFv3, originator is active router */
|
||||||
|
#define OPT_DC 0x20 /* Related to demand circuits, not used */
|
||||||
|
|
||||||
|
/* Router-LSA VEB flags are are stored together with links (OSPFv2) or options (OSPFv3) */
|
||||||
|
#define OPT_RT_B (0x01 << 24)
|
||||||
|
#define OPT_RT_E (0x02 << 24)
|
||||||
|
#define OPT_RT_V (0x04 << 24)
|
||||||
|
#define OPT_RT_NT (0x10 << 24)
|
||||||
|
|
||||||
|
/* Prefix flags, specific for OSPFv3 */
|
||||||
|
#define OPT_PX_NU 0x01
|
||||||
|
#define OPT_PX_LA 0x02
|
||||||
|
#define OPT_PX_P 0x08
|
||||||
|
#define OPT_PX_DN 0x10
|
||||||
|
|
||||||
|
|
||||||
|
struct ospf_packet
|
||||||
|
{
|
||||||
|
u8 version;
|
||||||
|
u8 type;
|
||||||
|
u16 length;
|
||||||
|
u32 routerid;
|
||||||
|
u32 areaid;
|
||||||
|
u16 checksum;
|
||||||
|
u8 instance_id; /* See RFC 6549 */
|
||||||
|
u8 autype; /* Undefined for OSPFv3 */
|
||||||
|
};
|
||||||
|
|
||||||
struct ospf_md5
|
struct ospf_md5
|
||||||
{
|
{
|
||||||
u16 zero;
|
u16 zero;
|
||||||
|
@ -309,7 +507,6 @@ union ospf_auth
|
||||||
struct ospf_md5 md5;
|
struct ospf_md5 md5;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
/* Packet types */
|
/* Packet types */
|
||||||
#define HELLO_P 1 /* Hello */
|
#define HELLO_P 1 /* Hello */
|
||||||
#define DBDES_P 2 /* Database description */
|
#define DBDES_P 2 /* Database description */
|
||||||
|
@ -317,8 +514,6 @@ union ospf_auth
|
||||||
#define LSUPD_P 4 /* Link state update */
|
#define LSUPD_P 4 /* Link state update */
|
||||||
#define LSACK_P 5 /* Link state acknowledgement */
|
#define LSACK_P 5 /* Link state acknowledgement */
|
||||||
|
|
||||||
/* Area IDs */
|
|
||||||
#define BACKBONE 0
|
|
||||||
|
|
||||||
#define DBDES_I 4 /* Init bit */
|
#define DBDES_I 4 /* Init bit */
|
||||||
#define DBDES_M 2 /* More bit */
|
#define DBDES_M 2 /* More bit */
|
||||||
|
@ -326,19 +521,6 @@ union ospf_auth
|
||||||
#define DBDES_IMMS (DBDES_I | DBDES_M | DBDES_MS)
|
#define DBDES_IMMS (DBDES_I | DBDES_M | DBDES_MS)
|
||||||
|
|
||||||
|
|
||||||
struct ospf_packet
|
|
||||||
{
|
|
||||||
u8 version;
|
|
||||||
u8 type;
|
|
||||||
u16 length;
|
|
||||||
u32 routerid;
|
|
||||||
u32 areaid;
|
|
||||||
u16 checksum;
|
|
||||||
u8 instance_id; /* See RFC 6549 */
|
|
||||||
u8 autype; /* Undefined for OSPFv3 */
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
#define LSA_T_RT 0x2001
|
#define LSA_T_RT 0x2001
|
||||||
#define LSA_T_NET 0x2002
|
#define LSA_T_NET 0x2002
|
||||||
#define LSA_T_SUM_NET 0x2003
|
#define LSA_T_SUM_NET 0x2003
|
||||||
|
@ -530,7 +712,7 @@ struct ospf_lsa_prefix
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
static inline unsigned
|
static inline uint
|
||||||
lsa_net_count(struct ospf_lsa_header *lsa)
|
lsa_net_count(struct ospf_lsa_header *lsa)
|
||||||
{
|
{
|
||||||
return (lsa->length - sizeof(struct ospf_lsa_header) - sizeof(struct ospf_lsa_net))
|
return (lsa->length - sizeof(struct ospf_lsa_header) - sizeof(struct ospf_lsa_net))
|
||||||
|
@ -558,6 +740,7 @@ lsa_get_ipv6_prefix(u32 *buf, ip_addr *addr, int *pxlen, u8 *pxopts, u16 *rest)
|
||||||
|
|
||||||
*addr = IPA_NONE;
|
*addr = IPA_NONE;
|
||||||
|
|
||||||
|
#ifdef IPV6
|
||||||
if (pxl > 0)
|
if (pxl > 0)
|
||||||
_I0(*addr) = *buf++;
|
_I0(*addr) = *buf++;
|
||||||
if (pxl > 32)
|
if (pxl > 32)
|
||||||
|
@ -570,6 +753,7 @@ lsa_get_ipv6_prefix(u32 *buf, ip_addr *addr, int *pxlen, u8 *pxopts, u16 *rest)
|
||||||
/* Clean up remaining bits */
|
/* Clean up remaining bits */
|
||||||
if (pxl < 128)
|
if (pxl < 128)
|
||||||
addr->addr[pxl / 32] &= u32_mkmask(pxl % 32);
|
addr->addr[pxl / 32] &= u32_mkmask(pxl % 32);
|
||||||
|
#endif
|
||||||
|
|
||||||
return buf;
|
return buf;
|
||||||
}
|
}
|
||||||
|
@ -613,183 +797,6 @@ struct ospf_lsreq_header
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
struct ospf_neighbor
|
|
||||||
{
|
|
||||||
node n;
|
|
||||||
pool *pool;
|
|
||||||
struct ospf_iface *ifa;
|
|
||||||
u8 state;
|
|
||||||
#define NEIGHBOR_DOWN 0
|
|
||||||
#define NEIGHBOR_ATTEMPT 1
|
|
||||||
#define NEIGHBOR_INIT 2
|
|
||||||
#define NEIGHBOR_2WAY 3
|
|
||||||
#define NEIGHBOR_EXSTART 4
|
|
||||||
#define NEIGHBOR_EXCHANGE 5
|
|
||||||
#define NEIGHBOR_LOADING 6
|
|
||||||
#define NEIGHBOR_FULL 7
|
|
||||||
timer *inactim; /* Inactivity timer */
|
|
||||||
u8 imms; /* I, M, Master/slave received */
|
|
||||||
u8 myimms; /* I, M Master/slave */
|
|
||||||
u32 dds; /* DD Sequence number being sent */
|
|
||||||
u32 ddr; /* last Dat Des packet received */
|
|
||||||
|
|
||||||
u32 rid; /* Router ID */
|
|
||||||
ip_addr ip; /* IP of it's interface */
|
|
||||||
u8 priority; /* Priority */
|
|
||||||
u8 adj; /* built adjacency? */
|
|
||||||
u32 options; /* Options received */
|
|
||||||
|
|
||||||
/* 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 */
|
|
||||||
|
|
||||||
/* 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;
|
|
||||||
timer *rxmt_timer; /* RXMT timer */
|
|
||||||
list ackl[2];
|
|
||||||
#define ACKL_DIRECT 0
|
|
||||||
#define ACKL_DELAY 1
|
|
||||||
timer *ackd_timer; /* Delayed ack timer */
|
|
||||||
struct bfd_request *bfd_req; /* BFD request, if BFD is used */
|
|
||||||
void *ldd_buffer; /* Last database description packet */
|
|
||||||
u32 ldd_bsize; /* Buffer size for ldd_buffer */
|
|
||||||
u32 csn; /* Last received crypt seq number (for MD5) */
|
|
||||||
};
|
|
||||||
|
|
||||||
/* Definitions for interface state machine */
|
|
||||||
#define ISM_UP 0 /* Interface Up */
|
|
||||||
#define ISM_WAITF 1 /* Wait timer fired */
|
|
||||||
#define ISM_BACKS 2 /* Backup seen */
|
|
||||||
#define ISM_NEICH 3 /* Neighbor change */
|
|
||||||
#define ISM_LOOP 4 /* Link down */
|
|
||||||
#define ISM_UNLOOP 5 /* Link up */
|
|
||||||
#define ISM_DOWN 6 /* Interface down */
|
|
||||||
|
|
||||||
/* Definitions for neighbor state machine */
|
|
||||||
#define INM_HELLOREC 0 /* Hello Received */
|
|
||||||
#define INM_START 1 /* Neighbor start - for NBMA */
|
|
||||||
#define INM_2WAYREC 2 /* 2-Way received */
|
|
||||||
#define INM_NEGDONE 3 /* Negotiation done */
|
|
||||||
#define INM_EXDONE 4 /* Exchange done */
|
|
||||||
#define INM_BADLSREQ 5 /* Bad LS Request */
|
|
||||||
#define INM_LOADDONE 6 /* Load done */
|
|
||||||
#define INM_ADJOK 7 /* AdjOK? */
|
|
||||||
#define INM_SEQMIS 8 /* Sequence number mismatch */
|
|
||||||
#define INM_1WAYREC 9 /* 1-Way */
|
|
||||||
#define INM_KILLNBR 10 /* Kill Neighbor */
|
|
||||||
#define INM_INACTTIM 11 /* Inactivity timer */
|
|
||||||
#define INM_LLDOWN 12 /* Line down */
|
|
||||||
|
|
||||||
struct ospf_area
|
|
||||||
{
|
|
||||||
node n;
|
|
||||||
u32 areaid;
|
|
||||||
struct ospf_area_config *ac; /* Related area config */
|
|
||||||
struct top_hash_entry *rt; /* My own router LSA */
|
|
||||||
struct top_hash_entry *pxr_lsa; /* Originated prefix LSA */
|
|
||||||
list cand; /* List of candidates for RT calc. */
|
|
||||||
struct fib net_fib; /* Networks to advertise or not */
|
|
||||||
struct fib enet_fib; /* External networks for NSSAs */
|
|
||||||
u32 options; /* Optional features */
|
|
||||||
u8 update_rt_lsa; /* Rt lsa origination scheduled? */
|
|
||||||
u8 trcap; /* Transit capability? */
|
|
||||||
u8 marked; /* Used in OSPF reconfigure */
|
|
||||||
u8 translate; /* Translator state (TRANS_*), for NSSA ABR */
|
|
||||||
timer *translator_timer; /* For NSSA translator switch */
|
|
||||||
struct ospf_proto *po;
|
|
||||||
struct fib rtr; /* Routing tables for routers */
|
|
||||||
};
|
|
||||||
|
|
||||||
#define TRANS_OFF 0
|
|
||||||
#define TRANS_ON 1
|
|
||||||
#define TRANS_WAIT 2 /* Waiting before the end of translation */
|
|
||||||
|
|
||||||
struct ospf_proto
|
|
||||||
{
|
|
||||||
struct proto p;
|
|
||||||
timer *disp_timer; /* OSPF proto dispatcher */
|
|
||||||
unsigned tick;
|
|
||||||
struct top_graph *gr; /* LSA graph */
|
|
||||||
slist lsal; /* List of all LSA's */
|
|
||||||
int calcrt; /* Routing table calculation scheduled?
|
|
||||||
0=no, 1=normal, 2=forced reload */
|
|
||||||
list iface_list; /* Interfaces we really use */
|
|
||||||
list area_list;
|
|
||||||
int areano; /* Number of area I belong to */
|
|
||||||
int padj; /* Number of neighbors in Exchange or Loading state */
|
|
||||||
struct fib rtf; /* Routing table */
|
|
||||||
byte ospf2; /* OSPF v2 or v3 */
|
|
||||||
byte rfc1583; /* RFC1583 compatibility */
|
|
||||||
byte stub_router; /* Do not forward transit traffic */
|
|
||||||
byte merge_external; /* Should i merge external routes? */
|
|
||||||
byte asbr; /* May i originate any ext/NSSA lsa? */
|
|
||||||
byte ecmp; /* Maximal number of nexthops in ECMP route, or 0 */
|
|
||||||
struct ospf_area *backbone; /* If exists */
|
|
||||||
void *lsab; /* LSA buffer used when originating router LSAs */
|
|
||||||
int lsab_size, lsab_used;
|
|
||||||
linpool *nhpool; /* Linpool used for next hops computed in SPF */
|
|
||||||
sock *vlink_sk; /* IP socket used for vlink TX */
|
|
||||||
u32 router_id;
|
|
||||||
u32 last_vlink_id; /* Interface IDs for vlinks (starts at 0x80000000) */
|
|
||||||
};
|
|
||||||
|
|
||||||
struct ospf_iface_patt
|
|
||||||
{
|
|
||||||
struct iface_patt i;
|
|
||||||
u32 type;
|
|
||||||
u32 stub;
|
|
||||||
u32 cost;
|
|
||||||
u32 helloint;
|
|
||||||
u32 rxmtint;
|
|
||||||
u32 pollint;
|
|
||||||
u32 waitint;
|
|
||||||
u32 deadc;
|
|
||||||
u32 deadint;
|
|
||||||
u32 inftransdelay;
|
|
||||||
list nbma_list;
|
|
||||||
u32 priority;
|
|
||||||
u32 voa;
|
|
||||||
u32 vid;
|
|
||||||
int tx_tos;
|
|
||||||
int tx_priority;
|
|
||||||
u16 tx_length;
|
|
||||||
u16 rx_buffer;
|
|
||||||
|
|
||||||
#define OSPF_RXBUF_MINSIZE 256 /* Minimal allowed size */
|
|
||||||
u8 instance_id;
|
|
||||||
u8 autype; /* Not really used in OSPFv3 */
|
|
||||||
#define OSPF_AUTH_NONE 0
|
|
||||||
#define OSPF_AUTH_SIMPLE 1
|
|
||||||
#define OSPF_AUTH_CRYPT 2
|
|
||||||
#define OSPF_AUTH_CRYPT_SIZE 16
|
|
||||||
u8 strictnbma;
|
|
||||||
u8 check_link;
|
|
||||||
u8 ecmp_weight;
|
|
||||||
u8 link_lsa_suppression;
|
|
||||||
u8 real_bcast; /* Not really used in OSPFv3 */
|
|
||||||
u8 ptp_netmask; /* bool + 2 for unspecified */
|
|
||||||
u8 ttl_security; /* bool + 2 for TX only */
|
|
||||||
u8 bfd;
|
|
||||||
u8 bsd_secondary;
|
|
||||||
list *passwords;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
#define SH_ROUTER_SELF 0xffffffff
|
#define SH_ROUTER_SELF 0xffffffff
|
||||||
|
|
||||||
|
@ -810,7 +817,7 @@ struct lsadb_show_data {
|
||||||
|
|
||||||
|
|
||||||
/* ospf.c */
|
/* ospf.c */
|
||||||
void schedule_rtcalc(struct ospf_proto *p);
|
void ospf_schedule_rtcalc(struct ospf_proto *p);
|
||||||
|
|
||||||
static inline void ospf_notify_rt_lsa(struct ospf_area *oa)
|
static inline void ospf_notify_rt_lsa(struct ospf_area *oa)
|
||||||
{ oa->update_rt_lsa = 1; }
|
{ oa->update_rt_lsa = 1; }
|
||||||
|
@ -822,12 +829,15 @@ static inline void ospf_notify_link_lsa(struct ospf_iface *ifa)
|
||||||
{ ifa->update_link_lsa = 1; }
|
{ ifa->update_link_lsa = 1; }
|
||||||
|
|
||||||
|
|
||||||
|
#define ospf_is_v2(X) OSPF_IS_V2
|
||||||
|
#define ospf_is_v3(X) (!OSPF_IS_V2)
|
||||||
|
/*
|
||||||
static inline int ospf_is_v2(struct ospf_proto *p)
|
static inline int ospf_is_v2(struct ospf_proto *p)
|
||||||
{ return p->ospf2; }
|
{ return p->ospf2; }
|
||||||
|
|
||||||
static inline int ospf_is_v3(struct ospf_proto *p)
|
static inline int ospf_is_v3(struct ospf_proto *p)
|
||||||
{ return ! p->ospf2; }
|
{ return ! p->ospf2; }
|
||||||
|
*/
|
||||||
static inline int ospf_get_version(struct ospf_proto *p)
|
static inline int ospf_get_version(struct ospf_proto *p)
|
||||||
{ return ospf_is_v2(p) ? 2 : 3; }
|
{ return ospf_is_v2(p) ? 2 : 3; }
|
||||||
|
|
||||||
|
@ -920,7 +930,7 @@ void ospf_send_hello(struct ospf_iface *ifa, int kind, struct ospf_neighbor *dir
|
||||||
void ospf_receive_hello(struct ospf_packet *pkt, struct ospf_iface *ifa, struct ospf_neighbor *n, ip_addr faddr);
|
void ospf_receive_hello(struct ospf_packet *pkt, struct ospf_iface *ifa, struct ospf_neighbor *n, ip_addr faddr);
|
||||||
|
|
||||||
/* dbdes.c */
|
/* dbdes.c */
|
||||||
void ospf_send_dbdes(struct ospf_neighbor *n, int next);
|
void ospf_send_dbdes(struct ospf_proto *p, struct ospf_neighbor *n, int next);
|
||||||
void ospf_receive_dbdes(struct ospf_packet *pkt, struct ospf_iface *ifa, struct ospf_neighbor *n);
|
void ospf_receive_dbdes(struct ospf_packet *pkt, struct ospf_iface *ifa, struct ospf_neighbor *n);
|
||||||
|
|
||||||
/* lsreq.c */
|
/* lsreq.c */
|
||||||
|
@ -930,7 +940,8 @@ void ospf_receive_lsreq(struct ospf_packet *pkt, struct ospf_iface *ifa, struct
|
||||||
/* lsupd.c */
|
/* lsupd.c */
|
||||||
void ospf_dump_lsahdr(struct ospf_proto *p, struct ospf_lsa_header *lsa_n);
|
void ospf_dump_lsahdr(struct ospf_proto *p, struct ospf_lsa_header *lsa_n);
|
||||||
void ospf_dump_common(struct ospf_proto *p, struct ospf_packet *pkt);
|
void ospf_dump_common(struct ospf_proto *p, struct ospf_packet *pkt);
|
||||||
int ospf_lsupd_flood(struct ospf_proto *p, struct top_hash_entry *en, struct ospf_neighbor *from);
|
void ospf_add_flushed_to_lsrt(struct ospf_proto *p, struct ospf_neighbor *n);
|
||||||
|
int ospf_flood_lsa(struct ospf_proto *p, struct top_hash_entry *en, struct ospf_neighbor *from);
|
||||||
int ospf_send_lsupd(struct ospf_proto *p, struct top_hash_entry **lsa_list, uint lsa_count, struct ospf_neighbor *n);
|
int ospf_send_lsupd(struct ospf_proto *p, struct top_hash_entry **lsa_list, uint lsa_count, struct ospf_neighbor *n);
|
||||||
void ospf_rxmt_lsupd(struct ospf_proto *p, struct ospf_neighbor *n);
|
void ospf_rxmt_lsupd(struct ospf_proto *p, struct ospf_neighbor *n);
|
||||||
void ospf_receive_lsupd(struct ospf_packet *pkt, struct ospf_iface *ifa, struct ospf_neighbor *n);
|
void ospf_receive_lsupd(struct ospf_packet *pkt, struct ospf_iface *ifa, struct ospf_neighbor *n);
|
||||||
|
@ -938,7 +949,7 @@ void ospf_receive_lsupd(struct ospf_packet *pkt, struct ospf_iface *ifa, struct
|
||||||
/* lsack.c */
|
/* lsack.c */
|
||||||
void ospf_enqueue_lsack(struct ospf_neighbor *n, struct ospf_lsa_header *h_n, int queue);
|
void ospf_enqueue_lsack(struct ospf_neighbor *n, struct ospf_lsa_header *h_n, int queue);
|
||||||
void ospf_reset_lsack_queue(struct ospf_neighbor *n);
|
void ospf_reset_lsack_queue(struct ospf_neighbor *n);
|
||||||
void ospf_lsack_send(struct ospf_neighbor *n, int queue);
|
void ospf_send_lsack(struct ospf_proto *p, struct ospf_neighbor *n, int queue);
|
||||||
void ospf_receive_lsack(struct ospf_packet *pkt, struct ospf_iface *ifa, struct ospf_neighbor *n);
|
void ospf_receive_lsack(struct ospf_packet *pkt, struct ospf_iface *ifa, struct ospf_neighbor *n);
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -557,7 +557,7 @@ spfa_process_rt(struct ospf_proto *p, struct ospf_area *oa, struct top_hash_entr
|
||||||
|
|
||||||
/* Errata 2078 to RFC 5340 4.8.1 - skip links from non-routing nodes */
|
/* Errata 2078 to RFC 5340 4.8.1 - skip links from non-routing nodes */
|
||||||
if (ospf_is_v3(p) && (act != oa->rt) && !(rt->options & OPT_R))
|
if (ospf_is_v3(p) && (act != oa->rt) && !(rt->options & OPT_R))
|
||||||
break;
|
return;
|
||||||
|
|
||||||
/* Now process Rt links */
|
/* Now process Rt links */
|
||||||
for (lsa_walk_rt_init(p, act, &rtl), i = 0; lsa_walk_rt(&rtl); i++)
|
for (lsa_walk_rt_init(p, act, &rtl), i = 0; lsa_walk_rt(&rtl); i++)
|
||||||
|
@ -688,6 +688,8 @@ ospf_rt_spfa(struct ospf_area *oa)
|
||||||
|
|
||||||
if (oa->rt == NULL)
|
if (oa->rt == NULL)
|
||||||
return;
|
return;
|
||||||
|
if (oa->rt->lsa.age == LSA_MAXAGE)
|
||||||
|
return;
|
||||||
|
|
||||||
OSPF_TRACE(D_EVENTS, "Starting routing table calculation for area %R", oa->areaid);
|
OSPF_TRACE(D_EVENTS, "Starting routing table calculation for area %R", oa->areaid);
|
||||||
|
|
||||||
|
@ -1087,8 +1089,7 @@ check_sum_net_lsa(struct ospf_proto *p, ort *nf)
|
||||||
struct area_net *anet = NULL;
|
struct area_net *anet = NULL;
|
||||||
struct ospf_area *anet_oa = NULL;
|
struct ospf_area *anet_oa = NULL;
|
||||||
|
|
||||||
/* RT entry marked as area network */
|
if (nf->area_net)
|
||||||
if (nf->fn.flags & OSPF_RT_PERSISTENT)
|
|
||||||
{
|
{
|
||||||
/* It is a default route for stub areas, handled entirely in ospf_rt_abr() */
|
/* It is a default route for stub areas, handled entirely in ospf_rt_abr() */
|
||||||
if (nf->fn.pxlen == 0)
|
if (nf->fn.pxlen == 0)
|
||||||
|
@ -1162,8 +1163,7 @@ check_nssa_lsa(struct ospf_proto *p, ort *nf)
|
||||||
if (nf->external_rte)
|
if (nf->external_rte)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/* RT entry marked as area network */
|
if (nf->area_net)
|
||||||
if (nf->fn.flags & OSPF_RT_PERSISTENT)
|
|
||||||
{
|
{
|
||||||
/* Find that area network */
|
/* Find that area network */
|
||||||
WALK_LIST(oa, p->area_list)
|
WALK_LIST(oa, p->area_list)
|
||||||
|
@ -1176,12 +1176,12 @@ check_nssa_lsa(struct ospf_proto *p, ort *nf)
|
||||||
|
|
||||||
/* RFC 3103 3.2 (3) - originate the aggregated address range */
|
/* RFC 3103 3.2 (3) - originate the aggregated address range */
|
||||||
if (anet && anet->active && !anet->hidden && oa->translate)
|
if (anet && anet->active && !anet->hidden && oa->translate)
|
||||||
ospf_originate_ext_lsa(p, NULL, nf, LSA_RTCALC, anet->metric,
|
ospf_originate_ext_lsa(p, NULL, nf, LSA_M_RTCALC, anet->metric,
|
||||||
(anet->metric & LSA_EXT3_EBIT), IPA_NONE, anet->tag, 0);
|
(anet->metric & LSA_EXT3_EBIT), IPA_NONE, anet->tag, 0);
|
||||||
|
|
||||||
/* RFC 3103 3.2 (2) - originate the same network */
|
/* RFC 3103 3.2 (2) - originate the same network */
|
||||||
else if (decide_nssa_lsa(p, nf, &rt))
|
else if (decide_nssa_lsa(p, nf, &rt))
|
||||||
ospf_originate_ext_lsa(p, NULL, nf, LSA_RTCALC, rt.metric, rt.ebit, rt.fwaddr, rt.tag, 0);
|
ospf_originate_ext_lsa(p, NULL, nf, LSA_M_RTCALC, rt.metric, rt.ebit, rt.fwaddr, rt.tag, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* RFC 2328 16.7. p2 - find new/lost vlink endpoints */
|
/* RFC 2328 16.7. p2 - find new/lost vlink endpoints */
|
||||||
|
@ -1273,7 +1273,7 @@ ospf_rt_abr1(struct ospf_proto *p)
|
||||||
|
|
||||||
/* Get a RT entry and mark it to know that it is an area network */
|
/* Get a RT entry and mark it to know that it is an area network */
|
||||||
ort *nfi = (ort *) fib_get(&p->rtf, &anet->fn.prefix, anet->fn.pxlen);
|
ort *nfi = (ort *) fib_get(&p->rtf, &anet->fn.prefix, anet->fn.pxlen);
|
||||||
nfi->fn.flags |= OSPF_RT_PERSISTENT; /* mark persistent, to have stable UID */
|
nfi->area_net = 1;
|
||||||
|
|
||||||
/* 16.2. (3) */
|
/* 16.2. (3) */
|
||||||
if (nfi->n.type == RTS_OSPF_IA)
|
if (nfi->n.type == RTS_OSPF_IA)
|
||||||
|
@ -1289,7 +1289,7 @@ ospf_rt_abr1(struct ospf_proto *p)
|
||||||
|
|
||||||
ip_addr addr = IPA_NONE;
|
ip_addr addr = IPA_NONE;
|
||||||
default_nf = (ort *) fib_get(&p->rtf, &addr, 0);
|
default_nf = (ort *) fib_get(&p->rtf, &addr, 0);
|
||||||
default_nf->fn.flags |= OSPF_RT_PERSISTENT; /* keep persistent */
|
default_nf->area_net = 1;
|
||||||
|
|
||||||
struct ospf_area *oa;
|
struct ospf_area *oa;
|
||||||
WALK_LIST(oa, p->area_list)
|
WALK_LIST(oa, p->area_list)
|
||||||
|
@ -1309,7 +1309,7 @@ ospf_rt_abr1(struct ospf_proto *p)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (oa_is_nssa(oa) && oa->ac->default_nssa)
|
if (oa_is_nssa(oa) && oa->ac->default_nssa)
|
||||||
ospf_originate_ext_lsa(p, oa, default_nf, LSA_RTCALC, oa->ac->default_cost,
|
ospf_originate_ext_lsa(p, oa, default_nf, LSA_M_RTCALC, oa->ac->default_cost,
|
||||||
(oa->ac->default_cost & LSA_EXT3_EBIT), IPA_NONE, 0, 0);
|
(oa->ac->default_cost & LSA_EXT3_EBIT), IPA_NONE, 0, 0);
|
||||||
|
|
||||||
/* RFC 2328 16.4. (3) - precompute preferred ASBR entries */
|
/* RFC 2328 16.4. (3) - precompute preferred ASBR entries */
|
||||||
|
@ -1348,7 +1348,7 @@ translator_timer_hook(timer *timer)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
oa->translate = TRANS_OFF;
|
oa->translate = TRANS_OFF;
|
||||||
schedule_rtcalc(oa->po);
|
ospf_schedule_rtcalc(oa->po);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -1431,7 +1431,7 @@ ospf_rt_abr2(struct ospf_proto *p)
|
||||||
|
|
||||||
/* Get a RT entry and mark it to know that it is an area network */
|
/* Get a RT entry and mark it to know that it is an area network */
|
||||||
nf2 = (ort *) fib_get(&p->rtf, &anet->fn.prefix, anet->fn.pxlen);
|
nf2 = (ort *) fib_get(&p->rtf, &anet->fn.prefix, anet->fn.pxlen);
|
||||||
nf2->fn.flags |= OSPF_RT_PERSISTENT; /* keep persistent */
|
nf2->area_net = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 metric = (nf->n.type == RTS_OSPF_EXT1) ?
|
u32 metric = (nf->n.type == RTS_OSPF_EXT1) ?
|
||||||
|
@ -1634,7 +1634,7 @@ ospf_rt_reset(struct ospf_proto *p)
|
||||||
FIB_WALK(&p->rtf, nftmp)
|
FIB_WALK(&p->rtf, nftmp)
|
||||||
{
|
{
|
||||||
ri = (ort *) nftmp;
|
ri = (ort *) nftmp;
|
||||||
ri->fn.flags &= ~OSPF_RT_PERSISTENT;
|
ri->area_net = 0;
|
||||||
reset_ri(ri);
|
reset_ri(ri);
|
||||||
}
|
}
|
||||||
FIB_WALK_END;
|
FIB_WALK_END;
|
||||||
|
@ -1647,8 +1647,8 @@ ospf_rt_reset(struct ospf_proto *p)
|
||||||
en->nhs = NULL;
|
en->nhs = NULL;
|
||||||
en->lb = IPA_NONE;
|
en->lb = IPA_NONE;
|
||||||
|
|
||||||
if (en->rtcalc == LSA_RTCALC)
|
if (en->mode == LSA_M_RTCALC)
|
||||||
en->rtcalc = LSA_STALE;
|
en->mode = LSA_M_STALE;
|
||||||
}
|
}
|
||||||
|
|
||||||
WALK_LIST(oa, p->area_list)
|
WALK_LIST(oa, p->area_list)
|
||||||
|
@ -1683,14 +1683,9 @@ ospf_rt_reset(struct ospf_proto *p)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
|
||||||
ospf_flush_stale(struct ospf_proto *p)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ospf_rt_spf - calculate internal routes
|
* ospf_rt_spf - calculate internal routes
|
||||||
* @p: OSPF protocol
|
* @p: OSPF protocol instance
|
||||||
*
|
*
|
||||||
* Calculation of internal paths in an area is described in 16.1 of RFC 2328.
|
* Calculation of internal paths in an area is described in 16.1 of RFC 2328.
|
||||||
* It's based on Dijkstra's shortest path tree algorithms.
|
* It's based on Dijkstra's shortest path tree algorithms.
|
||||||
|
@ -2064,8 +2059,8 @@ again1:
|
||||||
rte_update(&p->p, ne, NULL);
|
rte_update(&p->p, ne, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Remove unused rt entry. Entries with any flags are persistent. */
|
/* Remove unused rt entry, some special entries are persistent */
|
||||||
if (!nf->n.type && !nf->external_rte) // XXXX
|
if (!nf->n.type && !nf->external_rte && !nf->area_net)
|
||||||
{
|
{
|
||||||
FIB_ITERATE_PUT(&fit, nftmp);
|
FIB_ITERATE_PUT(&fit, nftmp);
|
||||||
fib_delete(fib, nftmp);
|
fib_delete(fib, nftmp);
|
||||||
|
@ -2096,6 +2091,6 @@ again2:
|
||||||
|
|
||||||
/* Cleanup stale LSAs */
|
/* Cleanup stale LSAs */
|
||||||
WALK_SLIST(en, p->lsal)
|
WALK_SLIST(en, p->lsal)
|
||||||
if (en->rtcalc == LSA_STALE)
|
if (en->mode == LSA_M_STALE)
|
||||||
ospf_flush_lsa(p, en);
|
ospf_flush_lsa(p, en);
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,9 +2,10 @@
|
||||||
* BIRD -- OSPF
|
* BIRD -- OSPF
|
||||||
*
|
*
|
||||||
* (c) 2000--2004 Ondrej Filip <feela@network.cz>
|
* (c) 2000--2004 Ondrej Filip <feela@network.cz>
|
||||||
|
* (c) 2009--2014 Ondrej Zajicek <santiago@crfreenet.org>
|
||||||
|
* (c) 2009--2014 CZ.NIC z.s.p.o.
|
||||||
*
|
*
|
||||||
* Can be freely distributed and used under the terms of the GNU GPL.
|
* Can be freely distributed and used under the terms of the GNU GPL.
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef _BIRD_OSPF_RT_H_
|
#ifndef _BIRD_OSPF_RT_H_
|
||||||
|
@ -28,12 +29,17 @@ typedef struct orta
|
||||||
#define ORTA_ASBR OPT_RT_E
|
#define ORTA_ASBR OPT_RT_E
|
||||||
#define ORTA_ABR OPT_RT_B
|
#define ORTA_ABR OPT_RT_B
|
||||||
/*
|
/*
|
||||||
* For ORT_NET routes, the field is almost unused with one
|
* For ORT_NET routes, there are just several flags for external routes:
|
||||||
* exception: ORTA_PREF for external routes means that the route is
|
*
|
||||||
* preferred in AS external route selection according to 16.4.1. -
|
* ORTA_PREF for external routes means that the route is preferred in AS
|
||||||
* it is intra-area path using non-backbone area. In other words,
|
* external route selection according to 16.4.1. - it is intra-area path using
|
||||||
* the forwarding address (or ASBR if forwarding address is zero) is
|
* non-backbone area. In other words, the forwarding address (or ASBR if
|
||||||
* intra-area (type == RTS_OSPF) and its area is not a backbone.
|
* forwarding address is zero) is intra-area (type == RTS_OSPF) and its area
|
||||||
|
* is not a backbone.
|
||||||
|
*
|
||||||
|
* ORTA_NSSA means that the entry represents an NSSA route, and ORTA_PROP
|
||||||
|
* means that the NSSA route has propagate-bit set. These flags are used in
|
||||||
|
* NSSA translation.
|
||||||
*/
|
*/
|
||||||
#define ORTA_PREF 0x80000000
|
#define ORTA_PREF 0x80000000
|
||||||
#define ORTA_NSSA 0x40000000
|
#define ORTA_NSSA 0x40000000
|
||||||
|
@ -51,41 +57,38 @@ typedef struct orta
|
||||||
}
|
}
|
||||||
orta;
|
orta;
|
||||||
|
|
||||||
|
|
||||||
/* Values for fn.flags in struct ort */
|
|
||||||
#define OSPF_RT_PERSISTENT 0x01
|
|
||||||
|
|
||||||
typedef struct ort
|
typedef struct ort
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* We use OSPF_RT_PERSISTENT to mark persistent rt entries, that are
|
* Most OSPF routing table entries are for computed OSPF routes, these have
|
||||||
* needed for summary LSAs that don't have 'proper' rt entry (area
|
* defined n.type. There are also few other cases: entries for configured area
|
||||||
* networks + default to stubs) to keep uid stable (used for LSA ID
|
* networks (these have area_net field set) and entries for external routes
|
||||||
* in OSPFv3 - see fibnode_to_lsaid()).
|
* exported to OSPF (these have external_rte field set). These entries are
|
||||||
|
* kept even if they do not contain 'proper' rt entry. That is needed to keep
|
||||||
|
* allocated stable UID numbers (fn.uid), which are used as LSA IDs in OSPFv3
|
||||||
|
* (see fibnode_to_lsaid()) for related LSAs (network summary LSAs in the
|
||||||
|
* first case, external or NSSA LSAs in the second case). Entries for external
|
||||||
|
* routes also have a second purpose - to prevent NSSA translation of received
|
||||||
|
* NSSA routes if regular external routes were already originated for the same
|
||||||
|
* network (see check_nssa_lsa()).
|
||||||
*
|
*
|
||||||
* We use ORT_RT_EXPORT and ORT_RT_NSSA to note whether the
|
* old_* values are here to represent the last route update. old_rta is cached
|
||||||
* external/NSSA route was originated from the route export (in
|
* (we keep reference), mainly for multipath nexthops. old_rta == NULL means
|
||||||
* ospf_rt_notify()) or from the NSSA route translation (in
|
* route was not in the last update, in that case other old_* values are not
|
||||||
* check_nssa_lsa()).
|
* valid.
|
||||||
*
|
|
||||||
* old_* values are here to represent the last route update. old_rta
|
|
||||||
* is cached (we keep reference), mainly for multipath nexthops.
|
|
||||||
* old_rta == NULL means route was not in the last update, in that
|
|
||||||
* case other old_* values are not valid.
|
|
||||||
*/
|
*/
|
||||||
struct fib_node fn;
|
struct fib_node fn;
|
||||||
orta n;
|
orta n;
|
||||||
u32 old_metric1, old_metric2, old_tag, old_rid;
|
u32 old_metric1, old_metric2, old_tag, old_rid;
|
||||||
rta *old_rta;
|
rta *old_rta;
|
||||||
u8 external_rte;
|
u8 external_rte;
|
||||||
|
u8 area_net;
|
||||||
}
|
}
|
||||||
ort;
|
ort;
|
||||||
|
|
||||||
static inline int rt_is_nssa(ort *nf)
|
static inline int rt_is_nssa(ort *nf)
|
||||||
{ return nf->n.options & ORTA_NSSA; }
|
{ return nf->n.options & ORTA_NSSA; }
|
||||||
|
|
||||||
#define EXT_EXPORT 1
|
|
||||||
#define EXT_NSSA 2
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Invariants for structs top_hash_entry (nodes of LSA db)
|
* Invariants for structs top_hash_entry (nodes of LSA db)
|
||||||
|
@ -97,7 +100,7 @@ static inline int rt_is_nssa(ort *nf)
|
||||||
* - beware, nhs is not valid after SPF calculation
|
* - beware, nhs is not valid after SPF calculation
|
||||||
*
|
*
|
||||||
* Invariants for structs orta nodes of fib tables po->rtf, oa->rtr:
|
* Invariants for structs orta nodes of fib tables po->rtf, oa->rtr:
|
||||||
* - nodes may be invalid (fn.type == 0), in that case other invariants don't hold
|
* - nodes may be invalid (n.type == 0), in that case other invariants don't hold
|
||||||
* - n.metric1 may be at most a small multiple of LSINFINITY,
|
* - n.metric1 may be at most a small multiple of LSINFINITY,
|
||||||
* therefore sums do not overflow
|
* therefore sums do not overflow
|
||||||
* - n.oa is always non-NULL
|
* - n.oa is always non-NULL
|
||||||
|
|
|
@ -40,11 +40,13 @@ static inline void lsab_reset(struct ospf_proto *p);
|
||||||
* new routing table calculation is necessary. This is described in 13.2 of RFC
|
* new routing table calculation is necessary. This is described in 13.2 of RFC
|
||||||
* 2328. This function is for received LSA only, locally originated LSAs are
|
* 2328. This function is for received LSA only, locally originated LSAs are
|
||||||
* installed by ospf_originate_lsa().
|
* installed by ospf_originate_lsa().
|
||||||
|
*
|
||||||
|
* The LSA body in @body is expected to be mb_allocated by the caller and its
|
||||||
|
* ownership is transferred to the LSA entry structure.
|
||||||
*/
|
*/
|
||||||
struct top_hash_entry *
|
struct top_hash_entry *
|
||||||
ospf_install_lsa(struct ospf_proto *p, struct ospf_lsa_header *lsa, u32 type, u32 domain, void *body)
|
ospf_install_lsa(struct ospf_proto *p, struct ospf_lsa_header *lsa, u32 type, u32 domain, void *body)
|
||||||
{
|
{
|
||||||
/* LSA can be temporary, but body must be mb_allocated. */
|
|
||||||
struct top_hash_entry *en;
|
struct top_hash_entry *en;
|
||||||
int change = 0;
|
int change = 0;
|
||||||
|
|
||||||
|
@ -61,8 +63,8 @@ ospf_install_lsa(struct ospf_proto *p, struct ospf_lsa_header *lsa, u32 type, u3
|
||||||
memcmp(en->lsa_body, body, lsa->length - sizeof(struct ospf_lsa_header)))
|
memcmp(en->lsa_body, body, lsa->length - sizeof(struct ospf_lsa_header)))
|
||||||
change = 1;
|
change = 1;
|
||||||
|
|
||||||
DBG("Inst lsa: Id: %R, Rt: %R, Type: %u, Age: %u, Sum: %u, Sn: 0x%x\n",
|
if ((en->lsa.age == LSA_MAXAGE) && (lsa->age == LSA_MAXAGE))
|
||||||
lsa->id, lsa->rt, lsa->type, lsa->age, lsa->checksum, lsa->sn);
|
change = 0;
|
||||||
|
|
||||||
mb_free(en->lsa_body);
|
mb_free(en->lsa_body);
|
||||||
en->lsa_body = body;
|
en->lsa_body = body;
|
||||||
|
@ -70,16 +72,43 @@ ospf_install_lsa(struct ospf_proto *p, struct ospf_lsa_header *lsa, u32 type, u3
|
||||||
en->init_age = en->lsa.age;
|
en->init_age = en->lsa.age;
|
||||||
en->inst_time = now;
|
en->inst_time = now;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We do not set en->mode. It is either default LSA_M_BASIC, or in a special
|
||||||
|
* case when en is local but flushed, there is postponed LSA, self-originated
|
||||||
|
* LSA is received and ospf_install_lsa() is called from ospf_advance_lse(),
|
||||||
|
* then we have en->mode from the postponed LSA origination.
|
||||||
|
*/
|
||||||
|
|
||||||
|
OSPF_TRACE(D_EVENTS, "Installing LSA: Type: %04x, Id: %R, Rt: %R, Seq: %08x, Age: %u",
|
||||||
|
en->lsa_type, en->lsa.id, en->lsa.rt, en->lsa.sn, en->lsa.age);
|
||||||
|
|
||||||
if (change)
|
if (change)
|
||||||
schedule_rtcalc(p);
|
ospf_schedule_rtcalc(p);
|
||||||
|
|
||||||
return en;
|
return en;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ospf_advance_lsa - handle received unexpected self-originated LSA
|
||||||
|
* @p: OSPF protocol instance
|
||||||
|
* @en: current LSA entry or NULL
|
||||||
|
* @lsa: new LSA header
|
||||||
|
* @type: type of LSA
|
||||||
|
* @domain: domain of LSA
|
||||||
|
* @body: pointer to LSA body
|
||||||
|
*
|
||||||
|
* This function handles received unexpected self-originated LSA (@lsa, @body)
|
||||||
|
* by either advancing sequence number of the local LSA instance (@en) and
|
||||||
|
* propagating it, or installing the received LSA and immediately flushing it
|
||||||
|
* (if there is no local LSA; i.e., @en is NULL or MaxAge).
|
||||||
|
*
|
||||||
|
* The LSA body in @body is expected to be mb_allocated by the caller and its
|
||||||
|
* ownership is transferred to the LSA entry structure or it is freed.
|
||||||
|
*/
|
||||||
void
|
void
|
||||||
ospf_advance_lsa(struct ospf_proto *p, struct top_hash_entry *en, struct ospf_lsa_header *lsa, u32 type, u32 domain, void *body)
|
ospf_advance_lsa(struct ospf_proto *p, struct top_hash_entry *en, struct ospf_lsa_header *lsa, u32 type, u32 domain, void *body)
|
||||||
{
|
{
|
||||||
// OSPF_TRACE(D_EVENTS, "Reflooding new self-originated LSA with newer sequence number");
|
/* RFC 2328 13.4 */
|
||||||
|
|
||||||
if (en && (en->lsa.age < LSA_MAXAGE))
|
if (en && (en->lsa.age < LSA_MAXAGE))
|
||||||
{
|
{
|
||||||
|
@ -101,6 +130,9 @@ ospf_advance_lsa(struct ospf_proto *p, struct top_hash_entry *en, struct ospf_ls
|
||||||
en->init_age = 0;
|
en->init_age = 0;
|
||||||
en->inst_time = now;
|
en->inst_time = now;
|
||||||
lsasum_calculate(&en->lsa, en->lsa_body);
|
lsasum_calculate(&en->lsa, en->lsa_body);
|
||||||
|
|
||||||
|
OSPF_TRACE(D_EVENTS, "Advancing LSA: Type: %04x, Id: %R, Rt: %R, Seq: %08x",
|
||||||
|
en->lsa_type, en->lsa.id, en->lsa.rt, en->lsa.sn);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -129,6 +161,11 @@ ospf_advance_lsa(struct ospf_proto *p, struct top_hash_entry *en, struct ospf_ls
|
||||||
en->lsa.age = LSA_MAXAGE;
|
en->lsa.age = LSA_MAXAGE;
|
||||||
en->init_age = lsa->age;
|
en->init_age = lsa->age;
|
||||||
en->inst_time = now;
|
en->inst_time = now;
|
||||||
|
|
||||||
|
OSPF_TRACE(D_EVENTS, "Resetting LSA: Type: %04x, Id: %R, Rt: %R, Seq: %08x",
|
||||||
|
en->lsa_type, en->lsa.id, en->lsa.rt, en->lsa.sn);
|
||||||
|
OSPF_TRACE(D_EVENTS, "Postponing LSA: Type: %04x, Id: %R, Rt: %R",
|
||||||
|
en->lsa_type, en->lsa.id, en->lsa.rt);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -137,6 +174,7 @@ ospf_advance_lsa(struct ospf_proto *p, struct top_hash_entry *en, struct ospf_ls
|
||||||
* We do not have received LSA in the database. We have to flush the
|
* We do not have received LSA in the database. We have to flush the
|
||||||
* received LSA. It has to be installed in the database to secure
|
* received LSA. It has to be installed in the database to secure
|
||||||
* retransmissions. Note that the received LSA may already be MaxAge.
|
* retransmissions. Note that the received LSA may already be MaxAge.
|
||||||
|
* Also note that en->next_lsa_* may be defined.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
lsa->age = LSA_MAXAGE;
|
lsa->age = LSA_MAXAGE;
|
||||||
|
@ -150,7 +188,7 @@ ospf_advance_lsa(struct ospf_proto *p, struct top_hash_entry *en, struct ospf_ls
|
||||||
* the neighbor we received it from), we cheat a bit here.
|
* the neighbor we received it from), we cheat a bit here.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
ospf_lsupd_flood(p, en, NULL);
|
ospf_flood_lsa(p, en, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -167,11 +205,11 @@ ospf_do_originate_lsa(struct ospf_proto *p, struct top_hash_entry *en, void *lsa
|
||||||
/* Prepare to flush old LSA */
|
/* Prepare to flush old LSA */
|
||||||
if (en->lsa.age != LSA_MAXAGE)
|
if (en->lsa.age != LSA_MAXAGE)
|
||||||
{
|
{
|
||||||
OSPF_TRACE(D_EVENTS, "Resetting LSA: Type: %04x, Id: %R, Rt: %R",
|
OSPF_TRACE(D_EVENTS, "Resetting LSA: Type: %04x, Id: %R, Rt: %R, Seq: %08x",
|
||||||
en->lsa_type, en->lsa.id, en->lsa.rt);
|
en->lsa_type, en->lsa.id, en->lsa.rt, en->lsa.sn);
|
||||||
|
|
||||||
en->lsa.age = LSA_MAXAGE;
|
en->lsa.age = LSA_MAXAGE;
|
||||||
ospf_lsupd_flood(p, en, NULL);
|
ospf_flood_lsa(p, en, NULL);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -183,9 +221,6 @@ ospf_do_originate_lsa(struct ospf_proto *p, struct top_hash_entry *en, void *lsa
|
||||||
en->lsa.sn = LSA_ZEROSEQNO;
|
en->lsa.sn = LSA_ZEROSEQNO;
|
||||||
}
|
}
|
||||||
|
|
||||||
OSPF_TRACE(D_EVENTS, "Originating LSA: Type: %04x, Id: %R, Rt: %R",
|
|
||||||
en->lsa_type, en->lsa.id, en->lsa.rt);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* lsa.type_raw is initialized by ospf_hash_get() to OSPFv3 LSA type.
|
* lsa.type_raw is initialized by ospf_hash_get() to OSPFv3 LSA type.
|
||||||
* lsa_set_options() implicitly converts it to OSPFv2 LSA type, assuming that
|
* lsa_set_options() implicitly converts it to OSPFv2 LSA type, assuming that
|
||||||
|
@ -205,7 +240,13 @@ ospf_do_originate_lsa(struct ospf_proto *p, struct top_hash_entry *en, void *lsa
|
||||||
en->inst_time = now;
|
en->inst_time = now;
|
||||||
lsasum_calculate(&en->lsa, en->lsa_body);
|
lsasum_calculate(&en->lsa, en->lsa_body);
|
||||||
|
|
||||||
ospf_lsupd_flood(p, en, NULL);
|
OSPF_TRACE(D_EVENTS, "Originating LSA: Type: %04x, Id: %R, Rt: %R, Seq: %08x",
|
||||||
|
en->lsa_type, en->lsa.id, en->lsa.rt, en->lsa.sn);
|
||||||
|
|
||||||
|
ospf_flood_lsa(p, en, NULL);
|
||||||
|
|
||||||
|
if (en->mode == LSA_M_BASIC)
|
||||||
|
ospf_schedule_rtcalc(p);
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
@ -244,15 +285,20 @@ ospf_originate_lsa(struct ospf_proto *p, struct ospf_new_lsa *lsa)
|
||||||
{
|
{
|
||||||
log(L_ERR "%s: LSA ID collision for %I/%d",
|
log(L_ERR "%s: LSA ID collision for %I/%d",
|
||||||
p->p.name, lsa->nf->fn.prefix, lsa->nf->fn.pxlen);
|
p->p.name, lsa->nf->fn.prefix, lsa->nf->fn.pxlen);
|
||||||
|
|
||||||
|
en = NULL;
|
||||||
goto drop;
|
goto drop;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* XXXX check for maxage or opts change */
|
if (en->mode != lsa->mode)
|
||||||
|
en->mode = lsa->mode;
|
||||||
|
|
||||||
if (en->next_lsa_body)
|
if (en->next_lsa_body)
|
||||||
{
|
{
|
||||||
/* Ignore the new LSA if it is the same as the scheduled one */
|
/* Ignore the new LSA if it is the same as the scheduled one */
|
||||||
if ((lsa_blen == en->next_lsa_blen) && !memcmp(lsa_body, en->next_lsa_body, lsa_blen))
|
if ((lsa_blen == en->next_lsa_blen) &&
|
||||||
|
!memcmp(lsa_body, en->next_lsa_body, lsa_blen) &&
|
||||||
|
(!ospf_is_v2(p) || (lsa->opts == en->next_lsa_opts)))
|
||||||
goto drop;
|
goto drop;
|
||||||
|
|
||||||
/* Free scheduled LSA */
|
/* Free scheduled LSA */
|
||||||
|
@ -263,13 +309,19 @@ ospf_originate_lsa(struct ospf_proto *p, struct ospf_new_lsa *lsa)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Ignore the the new LSA if is the same as the current one */
|
/* Ignore the the new LSA if is the same as the current one */
|
||||||
if ((lsa_length == en->lsa.length) && !memcmp(lsa_body, en->lsa_body, lsa_blen))
|
if ((en->lsa.age < LSA_MAXAGE) &&
|
||||||
|
(lsa_length == en->lsa.length) &&
|
||||||
|
!memcmp(lsa_body, en->lsa_body, lsa_blen) &&
|
||||||
|
(!ospf_is_v2(p) || (lsa->opts == lsa_get_options(&en->lsa))))
|
||||||
goto drop;
|
goto drop;
|
||||||
|
|
||||||
lsa_body = lsab_flush(p);
|
lsa_body = lsab_flush(p);
|
||||||
|
|
||||||
if (! ospf_do_originate_lsa(p, en, lsa_body, lsa_blen, lsa->opts))
|
if (! ospf_do_originate_lsa(p, en, lsa_body, lsa_blen, lsa->opts))
|
||||||
{
|
{
|
||||||
|
OSPF_TRACE(D_EVENTS, "Postponing LSA: Type: %04x, Id: %R, Rt: %R",
|
||||||
|
en->lsa_type, en->lsa.id, en->lsa.rt);
|
||||||
|
|
||||||
en->next_lsa_body = lsa_body;
|
en->next_lsa_body = lsa_body;
|
||||||
en->next_lsa_blen = lsa_blen;
|
en->next_lsa_blen = lsa_blen;
|
||||||
en->next_lsa_opts = lsa->opts;
|
en->next_lsa_opts = lsa->opts;
|
||||||
|
@ -293,8 +345,6 @@ ospf_originate_next_lsa(struct ospf_proto *p, struct top_hash_entry *en)
|
||||||
en->next_lsa_body = NULL;
|
en->next_lsa_body = NULL;
|
||||||
en->next_lsa_blen = 0;
|
en->next_lsa_blen = 0;
|
||||||
en->next_lsa_opts = 0;
|
en->next_lsa_opts = 0;
|
||||||
|
|
||||||
// XXXX: schedule_rtcalc(p);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -309,8 +359,8 @@ ospf_refresh_lsa(struct ospf_proto *p, struct top_hash_entry *en)
|
||||||
* switched lsa.age to LSA_MAXAGE.
|
* switched lsa.age to LSA_MAXAGE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
OSPF_TRACE(D_EVENTS, "Refreshing LSA: Type: %04x, Id: %R, Rt: %R",
|
OSPF_TRACE(D_EVENTS, "Refreshing LSA: Type: %04x, Id: %R, Rt: %R, Seq: %08x",
|
||||||
en->lsa_type, en->lsa.id, en->lsa.rt);
|
en->lsa_type, en->lsa.id, en->lsa.rt, en->lsa.sn);
|
||||||
|
|
||||||
ASSERT(en->next_lsa_body == NULL);
|
ASSERT(en->next_lsa_body == NULL);
|
||||||
|
|
||||||
|
@ -324,7 +374,7 @@ ospf_refresh_lsa(struct ospf_proto *p, struct top_hash_entry *en)
|
||||||
en->next_lsa_opts = ospf_is_v2(p) ? lsa_get_options(&en->lsa) : 0;
|
en->next_lsa_opts = ospf_is_v2(p) ? lsa_get_options(&en->lsa) : 0;
|
||||||
|
|
||||||
en->lsa.age = LSA_MAXAGE;
|
en->lsa.age = LSA_MAXAGE;
|
||||||
ospf_lsupd_flood(p, en, NULL);
|
ospf_flood_lsa(p, en, NULL);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -333,7 +383,7 @@ ospf_refresh_lsa(struct ospf_proto *p, struct top_hash_entry *en)
|
||||||
en->init_age = 0;
|
en->init_age = 0;
|
||||||
en->inst_time = now;
|
en->inst_time = now;
|
||||||
lsasum_calculate(&en->lsa, en->lsa_body);
|
lsasum_calculate(&en->lsa, en->lsa_body);
|
||||||
ospf_lsupd_flood(p, en, NULL);
|
ospf_flood_lsa(p, en, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -349,16 +399,13 @@ ospf_refresh_lsa(struct ospf_proto *p, struct top_hash_entry *en)
|
||||||
* immediately removed when being flushed, the caller may assume that @en still
|
* immediately removed when being flushed, the caller may assume that @en still
|
||||||
* exists after the call. The function is the opposite of ospf_originate_lsa()
|
* exists after the call. The function is the opposite of ospf_originate_lsa()
|
||||||
* and is supposed to do the right thing even in cases of postponed
|
* and is supposed to do the right thing even in cases of postponed
|
||||||
* origination. Note that this function do not schedule routing table
|
* origination.
|
||||||
* calculation, the caller is responsible to do it if necessary.
|
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
ospf_flush_lsa(struct ospf_proto *p, struct top_hash_entry *en)
|
ospf_flush_lsa(struct ospf_proto *p, struct top_hash_entry *en)
|
||||||
{
|
{
|
||||||
OSPF_TRACE(D_EVENTS, "Flushing LSA: Type: %04x, Id: %R, Rt: %R",
|
OSPF_TRACE(D_EVENTS, "Flushing LSA: Type: %04x, Id: %R, Rt: %R, Seq: %08x",
|
||||||
en->lsa_type, en->lsa.id, en->lsa.rt);
|
en->lsa_type, en->lsa.id, en->lsa.rt, en->lsa.sn);
|
||||||
|
|
||||||
en->rtcalc = 0;
|
|
||||||
|
|
||||||
if (en->next_lsa_body)
|
if (en->next_lsa_body)
|
||||||
{
|
{
|
||||||
|
@ -372,7 +419,12 @@ ospf_flush_lsa(struct ospf_proto *p, struct top_hash_entry *en)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
en->lsa.age = LSA_MAXAGE;
|
en->lsa.age = LSA_MAXAGE;
|
||||||
ospf_lsupd_flood(p, en, NULL);
|
ospf_flood_lsa(p, en, NULL);
|
||||||
|
|
||||||
|
if (en->mode == LSA_M_BASIC)
|
||||||
|
ospf_schedule_rtcalc(p);
|
||||||
|
|
||||||
|
en->mode = LSA_M_BASIC;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -450,7 +502,6 @@ ospf_update_lsadb(struct ospf_proto *p)
|
||||||
if (real_age >= LSA_MAXAGE)
|
if (real_age >= LSA_MAXAGE)
|
||||||
{
|
{
|
||||||
ospf_flush_lsa(p, en);
|
ospf_flush_lsa(p, en);
|
||||||
schedule_rtcalc(p);
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -510,9 +561,9 @@ ort_to_lsaid(struct ospf_proto *p, ort *nf)
|
||||||
|
|
||||||
|
|
||||||
static void *
|
static void *
|
||||||
lsab_alloc(struct ospf_proto *p, unsigned size)
|
lsab_alloc(struct ospf_proto *p, uint size)
|
||||||
{
|
{
|
||||||
unsigned offset = p->lsab_used;
|
uint offset = p->lsab_used;
|
||||||
p->lsab_used += size;
|
p->lsab_used += size;
|
||||||
if (p->lsab_used > p->lsab_size)
|
if (p->lsab_used > p->lsab_size)
|
||||||
{
|
{
|
||||||
|
@ -524,7 +575,7 @@ lsab_alloc(struct ospf_proto *p, unsigned size)
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void *
|
static inline void *
|
||||||
lsab_allocz(struct ospf_proto *p, unsigned size)
|
lsab_allocz(struct ospf_proto *p, uint size)
|
||||||
{
|
{
|
||||||
void *r = lsab_alloc(p, size);
|
void *r = lsab_alloc(p, size);
|
||||||
bzero(r, size);
|
bzero(r, size);
|
||||||
|
@ -547,7 +598,7 @@ lsab_reset(struct ospf_proto *p)
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void *
|
static inline void *
|
||||||
lsab_offset(struct ospf_proto *p, unsigned offset)
|
lsab_offset(struct ospf_proto *p, uint offset)
|
||||||
{
|
{
|
||||||
return ((byte *) p->lsab) + offset;
|
return ((byte *) p->lsab) + offset;
|
||||||
}
|
}
|
||||||
|
@ -815,15 +866,6 @@ prepare_rt3_lsa_body(struct ospf_proto *p, struct ospf_area *oa)
|
||||||
rt->options = get_rt_options(p, oa, bitv) | (oa->options & LSA_OPTIONS_MASK);
|
rt->options = get_rt_options(p, oa, bitv) | (oa->options & LSA_OPTIONS_MASK);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* ospf_originate_rt_lsa - build new instance of router LSA
|
|
||||||
* @oa: ospf_area which is LSA built to
|
|
||||||
*
|
|
||||||
* It builds router LSA walking through all OSPF interfaces in
|
|
||||||
* specified OSPF area. This function is mostly called from
|
|
||||||
* area_disp(). Builds new LSA, increases sequence number (if old
|
|
||||||
* instance exists) and sets age of LSA to zero.
|
|
||||||
*/
|
|
||||||
static void
|
static void
|
||||||
ospf_originate_rt_lsa(struct ospf_proto *p, struct ospf_area *oa)
|
ospf_originate_rt_lsa(struct ospf_proto *p, struct ospf_area *oa)
|
||||||
{
|
{
|
||||||
|
@ -834,6 +876,8 @@ ospf_originate_rt_lsa(struct ospf_proto *p, struct ospf_area *oa)
|
||||||
.opts = oa->options
|
.opts = oa->options
|
||||||
};
|
};
|
||||||
|
|
||||||
|
OSPF_TRACE(D_EVENTS, "Updating router state for area %R", oa->areaid);
|
||||||
|
|
||||||
if (ospf_is_v2(p))
|
if (ospf_is_v2(p))
|
||||||
prepare_rt2_lsa_body(p, oa);
|
prepare_rt2_lsa_body(p, oa);
|
||||||
else
|
else
|
||||||
|
@ -908,15 +952,6 @@ prepare_net3_lsa_body(struct ospf_proto *p, struct ospf_iface *ifa)
|
||||||
net->optx = options & LSA_OPTIONS_MASK;
|
net->optx = options & LSA_OPTIONS_MASK;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* ospf_originate_net_lsa - originates of deletes network LSA
|
|
||||||
* @ifa: interface which is LSA originated for
|
|
||||||
*
|
|
||||||
* Interface counts number of adjacent neighbors. If this number is
|
|
||||||
* lower than one or interface is not in state %OSPF_IS_DR it deletes
|
|
||||||
* and premature ages instance of network LSA for specified interface.
|
|
||||||
* In other case, new instance of network LSA is originated.
|
|
||||||
*/
|
|
||||||
static void
|
static void
|
||||||
ospf_originate_net_lsa(struct ospf_proto *p, struct ospf_iface *ifa)
|
ospf_originate_net_lsa(struct ospf_proto *p, struct ospf_iface *ifa)
|
||||||
{
|
{
|
||||||
|
@ -928,6 +963,8 @@ ospf_originate_net_lsa(struct ospf_proto *p, struct ospf_iface *ifa)
|
||||||
.ifa = ifa
|
.ifa = ifa
|
||||||
};
|
};
|
||||||
|
|
||||||
|
OSPF_TRACE(D_EVENTS, "Updating network state for %s (Id: %R)", ifa->ifname, lsa.id);
|
||||||
|
|
||||||
if (ospf_is_v2(p))
|
if (ospf_is_v2(p))
|
||||||
prepare_net2_lsa_body(p, ifa);
|
prepare_net2_lsa_body(p, ifa);
|
||||||
else
|
else
|
||||||
|
@ -977,10 +1014,9 @@ prepare_sum3_rt_lsa_body(struct ospf_proto *p, u32 drid, u32 metric, u32 options
|
||||||
void
|
void
|
||||||
ospf_originate_sum_net_lsa(struct ospf_proto *p, struct ospf_area *oa, ort *nf, int metric)
|
ospf_originate_sum_net_lsa(struct ospf_proto *p, struct ospf_area *oa, ort *nf, int metric)
|
||||||
{
|
{
|
||||||
struct top_hash_entry *en;
|
|
||||||
|
|
||||||
struct ospf_new_lsa lsa = {
|
struct ospf_new_lsa lsa = {
|
||||||
.type = LSA_T_SUM_NET,
|
.type = LSA_T_SUM_NET,
|
||||||
|
.mode = LSA_M_RTCALC,
|
||||||
.dom = oa->areaid,
|
.dom = oa->areaid,
|
||||||
.id = ort_to_lsaid(p, nf),
|
.id = ort_to_lsaid(p, nf),
|
||||||
.opts = oa->options,
|
.opts = oa->options,
|
||||||
|
@ -992,32 +1028,26 @@ ospf_originate_sum_net_lsa(struct ospf_proto *p, struct ospf_area *oa, ort *nf,
|
||||||
else
|
else
|
||||||
prepare_sum3_net_lsa_body(p, nf, metric);
|
prepare_sum3_net_lsa_body(p, nf, metric);
|
||||||
|
|
||||||
en = ospf_originate_lsa(p, &lsa);
|
ospf_originate_lsa(p, &lsa);
|
||||||
en->rtcalc = LSA_RTCALC;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
ospf_originate_sum_rt_lsa(struct ospf_proto *p, struct ospf_area *oa, ort *nf, int metric, u32 options)
|
ospf_originate_sum_rt_lsa(struct ospf_proto *p, struct ospf_area *oa, ort *nf, int metric, u32 options)
|
||||||
{
|
{
|
||||||
struct top_hash_entry *en;
|
|
||||||
u32 rid = ipa_to_rid(nf->fn.prefix);
|
|
||||||
|
|
||||||
/* In OSPFv3, LSA ID is meaningless, but we still use Router ID of ASBR */
|
|
||||||
|
|
||||||
struct ospf_new_lsa lsa = {
|
struct ospf_new_lsa lsa = {
|
||||||
.type = LSA_T_SUM_RT,
|
.type = LSA_T_SUM_RT,
|
||||||
|
.mode = LSA_M_RTCALC,
|
||||||
.dom = oa->areaid,
|
.dom = oa->areaid,
|
||||||
.id = rid,
|
.id = ipa_to_rid(nf->fn.prefix), /* Router ID of ASBR, irrelevant for OSPFv3 */
|
||||||
.opts = oa->options
|
.opts = oa->options
|
||||||
};
|
};
|
||||||
|
|
||||||
if (ospf_is_v2(p))
|
if (ospf_is_v2(p))
|
||||||
prepare_sum2_lsa_body(p, 0, metric);
|
prepare_sum2_lsa_body(p, 0, metric);
|
||||||
else
|
else
|
||||||
prepare_sum3_rt_lsa_body(p, rid, metric, options & LSA_OPTIONS_MASK);
|
prepare_sum3_rt_lsa_body(p, lsa.id, metric, options & LSA_OPTIONS_MASK);
|
||||||
|
|
||||||
en = ospf_originate_lsa(p, &lsa);
|
ospf_originate_lsa(p, &lsa);
|
||||||
en->rtcalc = LSA_RTCALC;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1076,13 +1106,15 @@ prepare_ext3_lsa_body(struct ospf_proto *p, ort *nf,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* originate_ext_lsa - new route received from nest and filters
|
* originate_ext_lsa - new route received from nest and filters
|
||||||
|
* @p: OSPF protocol instance
|
||||||
* @oa: ospf_area for which LSA is originated
|
* @oa: ospf_area for which LSA is originated
|
||||||
* @nf: network prefix and mask
|
* @nf: network prefix and mask
|
||||||
* @src: the source of origination of the LSA (EXT_EXPORT/EXT_NSSA)
|
* @mode: the mode of the LSA (LSA_M_EXPORT or LSA_M_RTCALC)
|
||||||
* @metric: the metric of a route (possibly with appropriate E-bit)
|
* @metric: the metric of a route
|
||||||
|
* @ebit: E-bit for route metric (bool)
|
||||||
* @fwaddr: the forwarding address
|
* @fwaddr: the forwarding address
|
||||||
* @tag: the route tag
|
* @tag: the route tag
|
||||||
* @pbit: P-bit for NSSA LSAs, ignored for external LSAs
|
* @pbit: P-bit for NSSA LSAs (bool), ignored for external LSAs
|
||||||
*
|
*
|
||||||
* If I receive a message that new route is installed, I try to originate an
|
* If I receive a message that new route is installed, I try to originate an
|
||||||
* external LSA. If @oa is an NSSA area, NSSA-LSA is originated instead.
|
* external LSA. If @oa is an NSSA area, NSSA-LSA is originated instead.
|
||||||
|
@ -1091,13 +1123,12 @@ prepare_ext3_lsa_body(struct ospf_proto *p, ort *nf,
|
||||||
* the export from ospf_rt_notify(), or the NSSA-EXT translation.
|
* the export from ospf_rt_notify(), or the NSSA-EXT translation.
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
ospf_originate_ext_lsa(struct ospf_proto *p, struct ospf_area *oa, ort *nf, u8 rtcalc,
|
ospf_originate_ext_lsa(struct ospf_proto *p, struct ospf_area *oa, ort *nf, u8 mode,
|
||||||
u32 metric, u32 ebit, ip_addr fwaddr, u32 tag, int pbit)
|
u32 metric, u32 ebit, ip_addr fwaddr, u32 tag, int pbit)
|
||||||
{
|
{
|
||||||
struct top_hash_entry *en;
|
|
||||||
|
|
||||||
struct ospf_new_lsa lsa = {
|
struct ospf_new_lsa lsa = {
|
||||||
.type = oa ? LSA_T_NSSA : LSA_T_EXT,
|
.type = oa ? LSA_T_NSSA : LSA_T_EXT,
|
||||||
|
.mode = mode, /* LSA_M_EXPORT or LSA_M_RTCALC */
|
||||||
.dom = oa ? oa->areaid : 0,
|
.dom = oa ? oa->areaid : 0,
|
||||||
.id = ort_to_lsaid(p, nf),
|
.id = ort_to_lsaid(p, nf),
|
||||||
.opts = oa ? (pbit ? OPT_P : 0) : OPT_E,
|
.opts = oa ? (pbit ? OPT_P : 0) : OPT_E,
|
||||||
|
@ -1109,8 +1140,7 @@ ospf_originate_ext_lsa(struct ospf_proto *p, struct ospf_area *oa, ort *nf, u8 r
|
||||||
else
|
else
|
||||||
prepare_ext3_lsa_body(p, nf, metric, ebit, fwaddr, tag, oa && pbit);
|
prepare_ext3_lsa_body(p, nf, metric, ebit, fwaddr, tag, oa && pbit);
|
||||||
|
|
||||||
en = ospf_originate_lsa(p, &lsa);
|
ospf_originate_lsa(p, &lsa);
|
||||||
en->rtcalc = rtcalc;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -1228,7 +1258,7 @@ ospf_rt_notify(struct proto *P, rtable *tbl UNUSED, net *n, rte *new, rte *old U
|
||||||
|
|
||||||
/* Old external route might blocked some NSSA translation */
|
/* Old external route might blocked some NSSA translation */
|
||||||
if ((p->areano > 1) && rt_is_nssa(nf) && nf->n.oa->translate)
|
if ((p->areano > 1) && rt_is_nssa(nf) && nf->n.oa->translate)
|
||||||
schedule_rtcalc(p);
|
ospf_schedule_rtcalc(p);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -1262,7 +1292,7 @@ ospf_rt_notify(struct proto *P, rtable *tbl UNUSED, net *n, rte *new, rte *old U
|
||||||
}
|
}
|
||||||
|
|
||||||
nf = (ort *) fib_get(&p->rtf, &n->n.prefix, n->n.pxlen);
|
nf = (ort *) fib_get(&p->rtf, &n->n.prefix, n->n.pxlen);
|
||||||
ospf_originate_ext_lsa(p, oa, nf, 0, metric, ebit, fwd, tag, 1);
|
ospf_originate_ext_lsa(p, oa, nf, LSA_M_EXPORT, metric, ebit, fwd, tag, 1);
|
||||||
nf->external_rte = 1;
|
nf->external_rte = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1320,6 +1350,8 @@ ospf_originate_link_lsa(struct ospf_proto *p, struct ospf_iface *ifa)
|
||||||
.ifa = ifa
|
.ifa = ifa
|
||||||
};
|
};
|
||||||
|
|
||||||
|
OSPF_TRACE(D_EVENTS, "Updating link state for %s (Id: %R)", ifa->ifname, lsa.id);
|
||||||
|
|
||||||
prepare_link_lsa_body(p, ifa);
|
prepare_link_lsa_body(p, ifa);
|
||||||
|
|
||||||
ifa->link_lsa = ospf_originate_lsa(p, &lsa);
|
ifa->link_lsa = ospf_originate_lsa(p, &lsa);
|
||||||
|
@ -1576,6 +1608,8 @@ ospf_originate_prefix_net_lsa(struct ospf_proto *p, struct ospf_iface *ifa)
|
||||||
ifa->pxn_lsa = ospf_originate_lsa(p, &lsa);
|
ifa->pxn_lsa = ospf_originate_lsa(p, &lsa);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline int breaks_minlsinterval(struct top_hash_entry *en)
|
||||||
|
{ return en && (en->lsa.age < LSA_MAXAGE) && ((en->inst_time + MINLSINTERVAL) > now); }
|
||||||
|
|
||||||
void
|
void
|
||||||
ospf_update_topology(struct ospf_proto *p)
|
ospf_update_topology(struct ospf_proto *p)
|
||||||
|
@ -1587,6 +1621,25 @@ ospf_update_topology(struct ospf_proto *p)
|
||||||
{
|
{
|
||||||
if (oa->update_rt_lsa)
|
if (oa->update_rt_lsa)
|
||||||
{
|
{
|
||||||
|
/*
|
||||||
|
* Generally, MinLSInterval is enforced in ospf_do_originate_lsa(), but
|
||||||
|
* origination of (prefix) router LSA is a special case. We do not want to
|
||||||
|
* prepare a new router LSA body and then postpone it in en->next_lsa_body
|
||||||
|
* for later origination, because there are side effects (updates of
|
||||||
|
* rt_pos_* and px_pos_* in ospf_iface structures) during that, which may
|
||||||
|
* confuse routing table calculation if executed after LSA body
|
||||||
|
* preparation but before final LSA origination (as rtcalc would use
|
||||||
|
* current rt_pos_* indexes but the old router LSA body).
|
||||||
|
*
|
||||||
|
* Here, we ensure that MinLSInterval is observed and we do not even try
|
||||||
|
* to originate these LSAs if it is not. Therefore, origination, when
|
||||||
|
* requested, will succeed unless there is also a seqnum wrapping, which
|
||||||
|
* is not a problem because in that case rtcalc is blocked by MaxAge.
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (breaks_minlsinterval(oa->rt) || breaks_minlsinterval(oa->pxr_lsa))
|
||||||
|
continue;
|
||||||
|
|
||||||
ospf_originate_rt_lsa(p, oa);
|
ospf_originate_rt_lsa(p, oa);
|
||||||
ospf_originate_prefix_rt_lsa(p, oa);
|
ospf_originate_prefix_rt_lsa(p, oa);
|
||||||
oa->update_rt_lsa = 0;
|
oa->update_rt_lsa = 0;
|
||||||
|
@ -1624,8 +1677,6 @@ ospf_update_topology(struct ospf_proto *p)
|
||||||
ifa->update_net_lsa = 0;
|
ifa->update_net_lsa = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// XXXX schedule_rtcalc(p);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1664,7 +1715,7 @@ ospf_top_hash_u32(u32 a)
|
||||||
return a;
|
return a;
|
||||||
}
|
}
|
||||||
|
|
||||||
static unsigned
|
static uint
|
||||||
ospf_top_hash(struct top_graph *f, u32 domain, u32 lsaid, u32 rtrid, u32 type)
|
ospf_top_hash(struct top_graph *f, u32 domain, u32 lsaid, u32 rtrid, u32 type)
|
||||||
{
|
{
|
||||||
/* In OSPFv2, we don't know Router ID when looking for network LSAs.
|
/* In OSPFv2, we don't know Router ID when looking for network LSAs.
|
||||||
|
@ -1685,12 +1736,14 @@ ospf_top_hash(struct top_graph *f, u32 domain, u32 lsaid, u32 rtrid, u32 type)
|
||||||
/**
|
/**
|
||||||
* ospf_top_new - allocated new topology database
|
* ospf_top_new - allocated new topology database
|
||||||
* @p: OSPF protocol instance
|
* @p: OSPF protocol instance
|
||||||
|
* @pool: pool for allocation
|
||||||
*
|
*
|
||||||
* this dynamically hashed structure is often used for keeping lsas. mainly
|
* This dynamically hashed structure is used for keeping LSAs. Mainly it is used
|
||||||
* its used in @ospf_area structure.
|
* for the LSA database of the OSPF protocol, but also for LSA retransmission
|
||||||
|
* and request lists of OSPF neighbors.
|
||||||
*/
|
*/
|
||||||
struct top_graph *
|
struct top_graph *
|
||||||
ospf_top_new(pool *pool)
|
ospf_top_new(struct ospf_proto *p, pool *pool)
|
||||||
{
|
{
|
||||||
struct top_graph *f;
|
struct top_graph *f;
|
||||||
|
|
||||||
|
@ -1701,6 +1754,7 @@ ospf_top_new(pool *pool)
|
||||||
ospf_top_ht_alloc(f);
|
ospf_top_ht_alloc(f);
|
||||||
f->hash_entries = 0;
|
f->hash_entries = 0;
|
||||||
f->hash_entries_min = 0;
|
f->hash_entries_min = 0;
|
||||||
|
f->ospf2 = ospf_is_v2(p);
|
||||||
return f;
|
return f;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1715,8 +1769,8 @@ ospf_top_free(struct top_graph *f)
|
||||||
static void
|
static void
|
||||||
ospf_top_rehash(struct top_graph *f, int step)
|
ospf_top_rehash(struct top_graph *f, int step)
|
||||||
{
|
{
|
||||||
unsigned int oldn, oldh;
|
|
||||||
struct top_hash_entry **n, **oldt, **newt, *e, *x;
|
struct top_hash_entry **n, **oldt, **newt, *e, *x;
|
||||||
|
uint oldn, oldh;
|
||||||
|
|
||||||
oldn = f->hash_size;
|
oldn = f->hash_size;
|
||||||
oldt = f->hash_table;
|
oldt = f->hash_table;
|
||||||
|
@ -1752,7 +1806,7 @@ ospf_hash_find(struct top_graph *f, u32 domain, u32 lsa, u32 rtr, u32 type)
|
||||||
e = e->next;
|
e = e->next;
|
||||||
|
|
||||||
/* Hide hash entry with empty lsa_body */
|
/* Hide hash entry with empty lsa_body */
|
||||||
return e->lsa_body ? e : NULL;
|
return (e && e->lsa_body) ? e : NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* In OSPFv2, lsa.id is the same as lsa.rt for router LSA. In OSPFv3, we don't know
|
/* In OSPFv2, lsa.id is the same as lsa.rt for router LSA. In OSPFv3, we don't know
|
||||||
|
@ -1780,11 +1834,15 @@ ospf_hash_find_rt(struct top_graph *f, u32 domain, u32 rtr)
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ospf_hash_find_rt3_first() and ospf_hash_find_rt3_next() are used exclusively
|
||||||
|
* for lsa_walk_rt_init(), lsa_walk_rt(), therefore they skip MaxAge entries.
|
||||||
|
*/
|
||||||
static inline struct top_hash_entry *
|
static inline struct top_hash_entry *
|
||||||
find_matching_rt3(struct top_hash_entry *e, u32 domain, u32 rtr)
|
find_matching_rt3(struct top_hash_entry *e, u32 domain, u32 rtr)
|
||||||
{
|
{
|
||||||
while (e && (e->lsa.rt != rtr || e->lsa_type != LSA_T_RT ||
|
while (e && (e->lsa.rt != rtr || e->lsa_type != LSA_T_RT ||
|
||||||
e->domain != domain || e->lsa_body == NULL))
|
e->domain != domain || e->lsa.age == LSA_MAXAGE))
|
||||||
e = e->next;
|
e = e->next;
|
||||||
return e;
|
return e;
|
||||||
}
|
}
|
||||||
|
@ -1917,7 +1975,7 @@ ospf_dump_lsa(struct top_hash_entry *he, struct proto *p)
|
||||||
void
|
void
|
||||||
ospf_top_dump(struct top_graph *f, struct proto *p)
|
ospf_top_dump(struct top_graph *f, struct proto *p)
|
||||||
{
|
{
|
||||||
unsigned int i;
|
uint i;
|
||||||
OSPF_TRACE(D_EVENTS, "Hash entries: %d", f->hash_entries);
|
OSPF_TRACE(D_EVENTS, "Hash entries: %d", f->hash_entries);
|
||||||
|
|
||||||
for (i = 0; i < f->hash_size; i++)
|
for (i = 0; i < f->hash_size; i++)
|
||||||
|
@ -1928,115 +1986,3 @@ ospf_top_dump(struct top_graph *f, struct proto *p)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#if 0
|
|
||||||
|
|
||||||
void
|
|
||||||
update_rt_lsa(struct ospf_area *oa)
|
|
||||||
{
|
|
||||||
struct ospf_proto *po = oa->po;
|
|
||||||
|
|
||||||
if ((oa->rt) && ((oa->rt->inst_t + MINLSINTERVAL)) > now)
|
|
||||||
return;
|
|
||||||
|
|
||||||
originate_rt_lsa(oa);
|
|
||||||
if (ospf_is_v3(p))
|
|
||||||
originate_prefix_rt_lsa(oa);
|
|
||||||
|
|
||||||
schedule_rtcalc(p);
|
|
||||||
oa->origrt = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
static inline int
|
|
||||||
check_sum2_net_lsa(struct top_hash_entry *en, struct fib_node *fn, u32 metric)
|
|
||||||
{
|
|
||||||
struct ospf_lsa_sum2 *sum = en->lsa_body;
|
|
||||||
|
|
||||||
if (fn->pxlen != ip4_masklen(sum->netmask))
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
return (en->lsa.sn != LSA_MAXSEQNO) && (sum->metric == metric);
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int
|
|
||||||
check_sum3_net_lsa(struct top_hash_entry *en, struct fib_node *fn, u32 metric)
|
|
||||||
{
|
|
||||||
struct ospf_lsa_sum3_net *sum = en->lsa_body;
|
|
||||||
ip6_addr prefix;
|
|
||||||
int pxlen;
|
|
||||||
u8 pxopts;
|
|
||||||
u16 rest;
|
|
||||||
lsa_get_ipv6_prefix(sum->prefix, &prefix, &pxlen, &pxopts, &rest);
|
|
||||||
|
|
||||||
|
|
||||||
if ((fn->pxlen != pxlen) || !ip6_equal(fn->prefix, prefix))
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
return (en->lsa.sn != LSA_MAXSEQNO) && (sum->metric == metric);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static int
|
|
||||||
check_sum_net_lsa(struct ospf_proto *po, struct top_hash_entry *en, struct fib_node *fn, u32 metric)
|
|
||||||
{
|
|
||||||
int rv = ospf_is_v2(po) ?
|
|
||||||
check_sum2_net_lsa(en, fn, metric) :
|
|
||||||
check_sum3_net_lsa(en, fn, metric);
|
|
||||||
|
|
||||||
if (rv < 0)
|
|
||||||
log(L_ERR "%s: LSAID collision for %I/%d", p->p.name, fn->prefix, fn->pxlen);
|
|
||||||
|
|
||||||
return rv;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
check_sum_rt_lsa(struct ospf_proto *po, struct top_hash_entry *en, u32 drid, u32 metric, u32 options)
|
|
||||||
{
|
|
||||||
if (en->lsa.sn == LSA_MAXSEQNO)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
if (ospf_is_v2(po))
|
|
||||||
{
|
|
||||||
struct ospf_lsa_sum2 *sum = en->lsa_body;
|
|
||||||
return (sum->metric == metric);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
struct ospf_lsa_sum3_rt *sum = en->lsa_body;
|
|
||||||
return (sum->options == options) && (sum->metric == metric) && (sum->drid == drid);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
OSPF_TRACE(D_EVENTS, "Originating router-LSA for area %R", oa->areaid);
|
|
||||||
OSPF_TRACE(D_EVENTS, "Originating network-LSA for iface %s", ifa->ifname);
|
|
||||||
OSPF_TRACE(D_EVENTS, "Originating net-summary-LSA for %I/%d (metric %d)", fn->prefix, fn->pxlen, metric);
|
|
||||||
OSPF_TRACE(D_EVENTS, "Originating rt-summary-LSA for %R (metric %d)", rid, metric);
|
|
||||||
OSPF_TRACE(D_EVENTS, "Originating %s-LSA for %I/%d",
|
|
||||||
nssa ? "NSSA" : "AS-external", fn->prefix, fn->pxlen);
|
|
||||||
OSPF_TRACE(D_EVENTS, "Originating link-LSA for iface %s", ifa->ifname);
|
|
||||||
OSPF_TRACE(D_EVENTS, "Originating router prefix-LSA for area %R", oa->areaid);
|
|
||||||
OSPF_TRACE(D_EVENTS, "Originating network prefix-LSA for iface %s", ifa->ifname);
|
|
||||||
|
|
||||||
|
|
||||||
en = ospf_hash_find(po->gr, lsa.dom, lsa.id, po->router_id, lsa.type);
|
|
||||||
if (en && check_ext_lsa(po, en, fn, metric, fwaddr, tag))
|
|
||||||
return;
|
|
||||||
|
|
||||||
*length = sizeof(struct ospf_lsa_header) + po->lsab_used;
|
|
||||||
return lsab_flush(po);
|
|
||||||
|
|
||||||
*length = po->lsab_used + sizeof(struct ospf_lsa_header);
|
|
||||||
return lsab_flush(po);
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
|
@ -18,7 +18,7 @@ struct top_hash_entry
|
||||||
in intra-area routing table calculation */
|
in intra-area routing table calculation */
|
||||||
struct top_hash_entry *next; /* Next in hash chain */
|
struct top_hash_entry *next; /* Next in hash chain */
|
||||||
struct ospf_lsa_header lsa;
|
struct ospf_lsa_header lsa;
|
||||||
u16 lsa_type; /* lsa.type processed and converted to common values */
|
u16 lsa_type; /* lsa.type processed and converted to common values (LSA_T_*) */
|
||||||
u16 init_age; /* Initial value for lsa.age during inst_time */
|
u16 init_age; /* Initial value for lsa.age during inst_time */
|
||||||
u32 domain; /* Area ID for area-wide LSAs, Iface ID for link-wide LSAs */
|
u32 domain; /* Area ID for area-wide LSAs, Iface ID for link-wide LSAs */
|
||||||
// struct ospf_area *oa;
|
// struct ospf_area *oa;
|
||||||
|
@ -37,13 +37,115 @@ struct top_hash_entry
|
||||||
#define OUTSPF 0
|
#define OUTSPF 0
|
||||||
#define CANDIDATE 1
|
#define CANDIDATE 1
|
||||||
#define INSPF 2
|
#define INSPF 2
|
||||||
u8 rtcalc; /* LSA generated during RT calculation (LSA_RTCALC or LSA_STALE)*/
|
u8 mode; /* LSA generated during RT calculation (LSA_RTCALC or LSA_STALE)*/
|
||||||
u8 nhs_reuse; /* Whether nhs nodes can be reused during merging.
|
u8 nhs_reuse; /* Whether nhs nodes can be reused during merging.
|
||||||
See a note in rt.c:merge_nexthops() */
|
See a note in rt.c:merge_nexthops() */
|
||||||
};
|
};
|
||||||
|
|
||||||
#define LSA_RTCALC 1
|
|
||||||
#define LSA_STALE 2
|
/* Prevents ospf_hash_find() to ignore the entry, for p->lsrqh and p->lsrth */
|
||||||
|
#define LSA_BODY_DUMMY ((void *) 1)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* LSA entry life cycle
|
||||||
|
*
|
||||||
|
* LSA entries are created by ospf_originate_lsa() (for locally originated LSAs)
|
||||||
|
* or ospf_install_lsa() (for LSAs received from neighbors). A regular (like
|
||||||
|
* newly originated) LSA entry has defined lsa_body nad lsa.age < %LSA_MAXAGE.
|
||||||
|
* When the LSA is requested to be flushed by ospf_flush_lsa(), the lsa.age is
|
||||||
|
* set to %LSA_MAXAGE and flooded. Flush process is finished asynchronously,
|
||||||
|
* when (at least) flooding is acknowledged by neighbors. This is detected in
|
||||||
|
* ospf_update_lsadb(), then ospf_clear_lsa() is called to free the LSA body but
|
||||||
|
* the LSA entry is kept. Such LSA does not formally exist, we keep an empty
|
||||||
|
* entry (until regular timeout) to know inst_time and lsa.sn in the case of
|
||||||
|
* later reorigination. After the timeout, LSA is removed by ospf_remove_lsa().
|
||||||
|
*
|
||||||
|
* When LSA origination is requested (by ospf_originate_lsa()). but it is not
|
||||||
|
* possible to do that immediately (because of MinLSInterval or because the
|
||||||
|
* sequence number is wrapping), The new LSA is scheduled for later origination
|
||||||
|
* in next_lsa_* fields of the LSA entry. The later origination is handled by
|
||||||
|
* ospf_originate_next_lsa() called from ospf_update_lsadb(). We can see that
|
||||||
|
* both real origination and final flush is asynchronous to ospf_originate_lsa()
|
||||||
|
* and ospf_flush_lsa().
|
||||||
|
*
|
||||||
|
* LSA entry therefore could be in three basic states:
|
||||||
|
* R - regular (lsa.age < %LSA_MAXAGE, lsa_body != NULL)
|
||||||
|
* F - flushing (lsa.age == %LSA_MAXAGE, lsa_body != NULL)
|
||||||
|
* E - empty (lsa.age == %LSA_MAXAGE, lsa_body == NULL)
|
||||||
|
*
|
||||||
|
* And these states are doubled based on whether the next LSA is scheduled
|
||||||
|
* (next_lsa_body != NULL, -n suffix) or not (next_lsa_body == NULL). We also
|
||||||
|
* use X for a state of non-existentce. We have this basic state graph
|
||||||
|
* (transitions from any state to R are omitted for clarity):
|
||||||
|
*
|
||||||
|
* X --> R ---> F ---> E --> X
|
||||||
|
* | \ / | |
|
||||||
|
* | \/ | |
|
||||||
|
* | /\ | |
|
||||||
|
* | / \ | |
|
||||||
|
* Rn --> Fn --> En
|
||||||
|
*
|
||||||
|
* The transitions are:
|
||||||
|
*
|
||||||
|
* any state -> R - new LSA origination requested and executed
|
||||||
|
* R -> Rn, F -> Fn, E -> En - new LSA origination requested and postponed
|
||||||
|
* R -> Fn - new LSA origination requested, seqnum wrapping
|
||||||
|
* Rn,Fn,En -> R - postponed LSA finally originated
|
||||||
|
* R -> R - LSA refresh done
|
||||||
|
* R -> Fn - LSA refresh with seqnum wrapping
|
||||||
|
* R -> F, Rn -> Fn - LSA age timeout
|
||||||
|
* R,Rn,Fn -> F, En -> E - LSA flush requested
|
||||||
|
* F -> E, Fn -> En - LSA flush done (acknowledged)
|
||||||
|
* E -> X - LSA real age timeout (or immediate for received LSA)
|
||||||
|
*
|
||||||
|
* The 'origination requested' and 'flush requested' transitions are triggered
|
||||||
|
* and done by ospf_originate_lsa() and ospf_flush_lsa(), the rest is handled
|
||||||
|
* asynchronously by ospf_update_lsadb().
|
||||||
|
*
|
||||||
|
* The situation is significantly simpler for non-local (received) LSAs - there
|
||||||
|
* is no postponed origination and after flushing is done, LSAs are immediately
|
||||||
|
* removed, so it is just X -> R -> F -> X, or X -> F -> X (when MaxAge LSA is
|
||||||
|
* received).
|
||||||
|
*
|
||||||
|
* There are also some special cases related to handling of received unknown
|
||||||
|
* self-originated LSAs in ospf_advance_lsa():
|
||||||
|
* X -> F - LSA is received and immediately flushed
|
||||||
|
* R,Rn -> Fn - LSA with MaxSeqNo received and flushed, current LSA scheduled
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#define LSA_M_BASIC 0
|
||||||
|
#define LSA_M_EXPORT 1
|
||||||
|
#define LSA_M_RTCALC 2
|
||||||
|
#define LSA_M_STALE 3
|
||||||
|
|
||||||
|
/*
|
||||||
|
* LSA entry modes:
|
||||||
|
*
|
||||||
|
* LSA_M_BASIC - The LSA is explicitly originated using ospf_originate_lsa() and
|
||||||
|
* explicitly flushed using ospf_flush_lsa(). When the LSA is changed, the
|
||||||
|
* routing table calculation is scheduled. This is also the mode used for LSAs
|
||||||
|
* received from neighbors. Example: Router-LSAs, Network-LSAs.
|
||||||
|
*
|
||||||
|
* LSA_M_EXPORT - like LSA_M_BASIC, but the routing table calculation does not
|
||||||
|
* depend on the LSA. Therefore, the calculation is not scheduled when the LSA
|
||||||
|
* is changed. Example: AS-external-LSAs for exported routes.
|
||||||
|
*
|
||||||
|
* LSA_M_RTCALC - The LSA has to be requested using ospf_originate_lsa() during
|
||||||
|
* each routing table calculation, otherwise it is flushed automatically at the
|
||||||
|
* end of the calculation. The LSA is a result of the calculation and not a
|
||||||
|
* source for it. Therefore, the calculation is not scheduled when the LSA is
|
||||||
|
* changed. Example: Summary-LSAs.
|
||||||
|
*
|
||||||
|
* LSA_M_STALE - Temporary state for LSA_M_RTCALC that is not requested during
|
||||||
|
* the current routing table calculation.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* Note that we do not schedule the routing table calculation when the age of
|
||||||
|
* LSA_M_BASIC LSA is changed to MaxAge because of the sequence number wrapping,
|
||||||
|
* As it will be switched back to a regular one ASAP.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
struct top_graph
|
struct top_graph
|
||||||
{
|
{
|
||||||
|
@ -61,6 +163,7 @@ struct top_graph
|
||||||
struct ospf_new_lsa
|
struct ospf_new_lsa
|
||||||
{
|
{
|
||||||
u16 type;
|
u16 type;
|
||||||
|
u8 mode;
|
||||||
u32 dom;
|
u32 dom;
|
||||||
u32 id;
|
u32 id;
|
||||||
u16 opts;
|
u16 opts;
|
||||||
|
@ -69,9 +172,8 @@ struct ospf_new_lsa
|
||||||
struct ort *nf;
|
struct ort *nf;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct top_graph *ospf_top_new(pool *);
|
struct top_graph *ospf_top_new(struct ospf_proto *p, pool *pool);
|
||||||
void ospf_top_free(struct top_graph *);
|
void ospf_top_free(struct top_graph *f);
|
||||||
void ospf_top_dump(struct top_graph *, struct proto *);
|
|
||||||
|
|
||||||
struct top_hash_entry * ospf_install_lsa(struct ospf_proto *p, struct ospf_lsa_header *lsa, u32 type, u32 domain, void *body);
|
struct top_hash_entry * ospf_install_lsa(struct ospf_proto *p, struct ospf_lsa_header *lsa, u32 type, u32 domain, void *body);
|
||||||
struct top_hash_entry * ospf_originate_lsa(struct ospf_proto *p, struct ospf_new_lsa *lsa);
|
struct top_hash_entry * ospf_originate_lsa(struct ospf_proto *p, struct ospf_new_lsa *lsa);
|
||||||
|
@ -84,7 +186,7 @@ static inline void ospf_flush2_lsa(struct ospf_proto *p, struct top_hash_entry *
|
||||||
|
|
||||||
void ospf_originate_sum_net_lsa(struct ospf_proto *p, struct ospf_area *oa, ort *nf, int metric);
|
void ospf_originate_sum_net_lsa(struct ospf_proto *p, struct ospf_area *oa, ort *nf, int metric);
|
||||||
void ospf_originate_sum_rt_lsa(struct ospf_proto *p, struct ospf_area *oa, ort *nf, int metric, u32 options);
|
void ospf_originate_sum_rt_lsa(struct ospf_proto *p, struct ospf_area *oa, ort *nf, int metric, u32 options);
|
||||||
void ospf_originate_ext_lsa(struct ospf_proto *p, struct ospf_area *oa, ort *nf, u8 rtcalc, u32 metric, u32 ebit, ip_addr fwaddr, u32 tag, int pbit);
|
void ospf_originate_ext_lsa(struct ospf_proto *p, struct ospf_area *oa, ort *nf, u8 mode, u32 metric, u32 ebit, ip_addr fwaddr, u32 tag, int pbit);
|
||||||
|
|
||||||
void ospf_rt_notify(struct proto *P, rtable *tbl, net *n, rte *new, rte *old, ea_list *attrs);
|
void ospf_rt_notify(struct proto *P, rtable *tbl, net *n, rte *new, rte *old, ea_list *attrs);
|
||||||
void ospf_update_topology(struct ospf_proto *p);
|
void ospf_update_topology(struct ospf_proto *p);
|
||||||
|
|
Loading…
Reference in a new issue