Files

2202 lines
56 KiB
C
Raw Permalink Normal View History

/*
* BIRD -- OSPF Topological Database
*
2004-06-25 16:39:53 +00:00
* (c) 1999 Martin Mares <[email protected]>
* (c) 1999--2004 Ondrej Filip <[email protected]>
2014-06-26 11:58:57 +02:00
* (c) 2009--2014 Ondrej Zajicek <[email protected]>
* (c) 2009--2014 CZ.NIC z.s.p.o.
*
* Can be freely distributed and used under the terms of the GNU GPL.
*/
#include "nest/bird.h"
#include "lib/string.h"
#include "ospf.h"
2014-06-26 11:58:57 +02:00
2000-06-08 12:04:57 +00:00
#define HASH_DEF_ORDER 6
#define HASH_HI_MARK *4
#define HASH_HI_STEP 2
#define HASH_HI_MAX 16
#define HASH_LO_MARK /5
#define HASH_LO_STEP 2
#define HASH_LO_MIN 8
2014-06-26 11:58:57 +02:00
static inline void * lsab_flush(struct ospf_proto *p);
static inline void lsab_reset(struct ospf_proto *p);
2009-08-25 16:42:14 +02:00
2014-06-26 11:58:57 +02:00
/**
* ospf_install_lsa - install new LSA into database
* @p: OSPF protocol instance
* @lsa: LSA header
2014-07-19 17:28:38 +02:00
* @type: type of LSA
2014-06-26 11:58:57 +02:00
* @domain: domain of LSA
* @body: pointer to LSA body
*
* This function ensures installing new LSA received in LS update into LSA
* database. Old instance is replaced. Several actions are taken to detect if
* 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
* installed by ospf_originate_lsa().
2014-07-18 18:24:12 +02:00
*
* The LSA body in @body is expected to be mb_allocated by the caller and its
* ownership is transferred to the LSA entry structure.
2014-06-26 11:58:57 +02:00
*/
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 *en;
int change = 0;
2009-10-07 21:10:29 +01:00
2014-06-26 11:58:57 +02:00
en = ospf_hash_get(p->gr, domain, lsa->id, lsa->rt, type);
2009-10-07 21:10:29 +01:00
2014-06-26 11:58:57 +02:00
if (!SNODE_VALID(en))
s_add_tail(&p->lsal, SNODE en);
if ((en->lsa_body == NULL) || /* No old LSA */
(en->lsa.length != lsa->length) ||
(en->lsa.type_raw != lsa->type_raw) || /* Check for OSPFv2 options */
(en->lsa.age == LSA_MAXAGE) ||
(lsa->age == LSA_MAXAGE) ||
memcmp(en->lsa_body, body, lsa->length - sizeof(struct ospf_lsa_header)))
change = 1;
2014-07-18 18:24:12 +02:00
if ((en->lsa.age == LSA_MAXAGE) && (lsa->age == LSA_MAXAGE))
change = 0;
2014-06-26 11:58:57 +02:00
mb_free(en->lsa_body);
en->lsa_body = body;
en->lsa = *lsa;
en->init_age = en->lsa.age;
2017-06-20 18:03:06 +02:00
en->inst_time = current_time();
en->gr_dirty = p->gr_recovery && (lsa->rt == p->router_id);
2014-06-26 11:58:57 +02:00
2014-07-18 18:24:12 +02:00
/*
* 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);
2014-06-26 11:58:57 +02:00
if (change)
2019-06-30 20:12:59 +02:00
{
ospf_neigh_lsadb_changed(p, en);
2014-07-18 18:24:12 +02:00
ospf_schedule_rtcalc(p);
2019-06-30 20:12:59 +02:00
}
2014-06-26 11:58:57 +02:00
return en;
}
2014-07-18 18:24:12 +02:00
/**
* ospf_advance_lsa - handle received unexpected self-originated LSA
* @p: OSPF protocol instance
* @en: current LSA entry or NULL
* @lsa: new LSA header
2014-07-19 17:28:38 +02:00
* @type: type of LSA
2014-07-18 18:24:12 +02:00
* @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.
*/
2014-06-26 11:58:57 +02:00
void
ospf_advance_lsa(struct ospf_proto *p, struct top_hash_entry *en, struct ospf_lsa_header *lsa, u32 type, u32 domain, void *body)
{
2014-07-18 18:24:12 +02:00
/* RFC 2328 13.4 */
2014-06-26 11:58:57 +02:00
if (en && (en->lsa.age < LSA_MAXAGE))
{
if (lsa->sn != LSA_MAXSEQNO)
{
/*
* We simply advance current LSA to have higher seqnum than received LSA.
* The received LSA is ignored and the advanced LSA is propagated instead.
*
* Although this is an origination of distinct LSA instance and therefore
* should be limited by MinLSInterval, we do not enforce it here. Fast
* reaction is needed and we are already limited by MinLSArrival.
*/
mb_free(body);
en->lsa.sn = lsa->sn + 1;
en->lsa.age = 0;
en->init_age = 0;
2017-06-20 18:03:06 +02:00
en->inst_time = current_time();
2015-05-01 14:40:56 +02:00
lsa_generate_checksum(&en->lsa, en->lsa_body);
2014-07-18 18:24:12 +02:00
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);
2014-06-26 11:58:57 +02:00
}
else
{
2014-07-19 17:28:38 +02:00
/*
2014-06-26 11:58:57 +02:00
* Received LSA has maximal sequence number, so we cannot simply override
* it. We have to install it to the database, immediately flush it to
* implement sequence number wrapping, and schedule our current LSA to be
* originated after the received instance is flushed.
*/
if (en->next_lsa_body == NULL)
{
/* Schedule current LSA */
en->next_lsa_blen = en->lsa.length - sizeof(struct ospf_lsa_header);
en->next_lsa_body = en->lsa_body;
en->next_lsa_opts = ospf_is_v2(p) ? lsa_get_options(&en->lsa) : 0;
}
else
{
/* There is already scheduled LSA, so we just free current one */
mb_free(en->lsa_body);
}
en->lsa_body = body;
en->lsa = *lsa;
en->lsa.age = LSA_MAXAGE;
en->init_age = lsa->age;
2017-06-20 18:03:06 +02:00
en->inst_time = current_time();
2014-07-18 18:24:12 +02:00
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);
2014-06-26 11:58:57 +02:00
}
}
2009-10-07 21:10:29 +01:00
else
2014-06-26 11:58:57 +02:00
{
/*
* 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
* retransmissions. Note that the received LSA may already be MaxAge.
2014-07-18 18:24:12 +02:00
* Also note that en->next_lsa_* may be defined.
2014-06-26 11:58:57 +02:00
*/
lsa->age = LSA_MAXAGE;
en = ospf_install_lsa(p, lsa, type, domain, body);
}
2014-07-19 17:28:38 +02:00
/*
2014-06-26 11:58:57 +02:00
* We flood the updated LSA. Although in some cases the to-be-flooded LSA is
* the same as the received LSA, and therefore we should propagate it as
2014-07-19 17:28:38 +02:00
* regular received LSA (send the acknowledgement instead of the update to
2014-06-26 11:58:57 +02:00
* the neighbor we received it from), we cheat a bit here.
*/
2014-07-18 18:24:12 +02:00
ospf_flood_lsa(p, en, NULL);
2009-10-07 21:10:29 +01:00
}
2014-06-26 11:58:57 +02:00
static int
ospf_do_originate_lsa(struct ospf_proto *p, struct top_hash_entry *en, void *lsa_body, u16 lsa_blen, u16 lsa_opts)
2009-10-07 21:10:29 +01:00
{
2014-06-26 11:58:57 +02:00
/* Enforce MinLSInterval */
2017-06-20 18:03:06 +02:00
if (!en->init_age && en->inst_time && (lsa_inst_age(en) < MINLSINTERVAL))
2014-06-26 11:58:57 +02:00
return 0;
/* Handle wrapping sequence number */
if (en->lsa.sn == LSA_MAXSEQNO)
{
/* Prepare to flush old LSA */
if (en->lsa.age != LSA_MAXAGE)
{
2014-07-18 18:24:12 +02:00
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);
2014-06-26 11:58:57 +02:00
en->lsa.age = LSA_MAXAGE;
2014-07-18 18:24:12 +02:00
ospf_flood_lsa(p, en, NULL);
2014-06-26 11:58:57 +02:00
return 0;
}
/* Already flushing */
if ((p->padj != 0) || (en->ret_count != 0))
return 0;
/* Flush done, just clean up seqnum, lsa_body is freed below */
en->lsa.sn = LSA_ZEROSEQNO;
}
/*
2014-06-26 11:58:57 +02:00
* 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
* old type is just new type masked by 0xff. That holds for most OSPFv2 types,
* but we have to fix it for opaque LSAs.
*/
2014-06-26 11:58:57 +02:00
if (ospf_is_v2(p))
{
if (lsa_is_opaque(en->lsa_type))
en->lsa.type_raw = LSA_T_V2_OPAQUE_ + LSA_SCOPE_ORDER(en->lsa_type);
2014-06-26 11:58:57 +02:00
lsa_set_options(&en->lsa, lsa_opts);
}
2014-06-26 11:58:57 +02:00
mb_free(en->lsa_body);
en->lsa_body = lsa_body;
en->lsa.length = sizeof(struct ospf_lsa_header) + lsa_blen;
en->lsa.sn++;
en->lsa.age = 0;
en->init_age = 0;
2017-06-20 18:03:06 +02:00
en->inst_time = current_time();
en->gr_dirty = 0;
2015-05-01 14:40:56 +02:00
lsa_generate_checksum(&en->lsa, en->lsa_body);
2014-06-26 11:58:57 +02:00
2014-07-18 18:24:12 +02:00
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)
2019-06-30 20:12:59 +02:00
{
ospf_neigh_lsadb_changed(p, en);
2014-07-18 18:24:12 +02:00
ospf_schedule_rtcalc(p);
2019-06-30 20:12:59 +02:00
}
2014-06-26 11:58:57 +02:00
return 1;
2009-10-07 21:10:29 +01:00
}
2014-06-26 11:58:57 +02:00
/**
* ospf_originate_lsa - originate new LSA
* @p: OSPF protocol instance
* @lsa: New LSA specification
*
* This function prepares a new LSA, installs it into the LSA database and
* floods it. If the new LSA cannot be originated now (because the old instance
* was originated within MinLSInterval, or because the LSA seqnum is currently
* wrapping), the origination is instead scheduled for later. If the new LSA is
* equivalent to the current LSA, the origination is skipped. In all cases, the
* corresponding LSA entry is returned. The new LSA is based on the LSA
* specification (@lsa) and the LSA body from lsab buffer of @p, which is
* emptied after the call. The opposite of this function is ospf_flush_lsa().
*/
struct top_hash_entry *
ospf_originate_lsa(struct ospf_proto *p, struct ospf_new_lsa *lsa)
{
2019-07-09 15:57:46 +02:00
struct top_hash_entry *en = NULL;
2014-06-26 11:58:57 +02:00
void *lsa_body = p->lsab;
u16 lsa_blen = p->lsab_used;
u16 lsa_length = sizeof(struct ospf_lsa_header) + lsa_blen;
2009-08-25 16:42:14 +02:00
2019-07-09 15:57:46 +02:00
/* RFC 3623 2 (1) - do not originate topology LSAs during graceful restart */
if (p->gr_recovery && (LSA_FUNCTION(lsa->type) <= LSA_FUNCTION(LSA_T_NSSA)))
goto drop;
/* For OSPFv2 Opaque LSAs, LS ID consists of Opaque Type and Opaque ID */
if (ospf_is_v2(p) && lsa_is_opaque(lsa->type))
lsa->id |= (u32) lsa_get_opaque_type(lsa->type) << 24;
2014-06-26 11:58:57 +02:00
en = ospf_hash_get(p->gr, lsa->dom, lsa->id, p->router_id, lsa->type);
2009-08-25 16:42:14 +02:00
2014-06-26 11:58:57 +02:00
if (!SNODE_VALID(en))
s_add_tail(&p->lsal, SNODE en);
if (!en->nf || !en->lsa_body)
2014-06-26 11:58:57 +02:00
en->nf = lsa->nf;
if (en->nf != lsa->nf)
{
2015-11-05 12:48:52 +01:00
log(L_ERR "%s: LSA ID collision for %N",
p->p.name, lsa->nf->fn.addr);
2014-07-18 18:24:12 +02:00
en = NULL;
2014-06-26 11:58:57 +02:00
goto drop;
}
2014-07-18 18:24:12 +02:00
if (en->mode != lsa->mode)
en->mode = lsa->mode;
2014-06-26 11:58:57 +02:00
if (en->next_lsa_body)
{
/* Ignore the new LSA if it is the same as the scheduled one */
2014-07-18 18:24:12 +02:00
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)))
2014-06-26 11:58:57 +02:00
goto drop;
/* Free scheduled LSA */
mb_free(en->next_lsa_body);
en->next_lsa_body = NULL;
en->next_lsa_blen = 0;
en->next_lsa_opts = 0;
}
/* The static analyzer complains here that en->lsa_body may be NULL.
* Yes, it may if ospf_hash_get() creates a new struct top_hash_entry.
* In this case, also en->lsa.length must be 0 and lsa_length is never
* equal to 0 while sizeof(struct ospf_lsa_header) is non-zero.
* Therefore memcmp() is never executed with NULL here.
* */
2020-08-31 15:41:39 +02:00
ASSUME(en->lsa.age >= LSA_MAXAGE || (en->lsa.length == 0) == (en->lsa_body == NULL));
2014-06-26 11:58:57 +02:00
/* Ignore the the new LSA if is the same as the current one */
2014-07-18 18:24:12 +02:00
if ((en->lsa.age < LSA_MAXAGE) &&
(lsa_length == en->lsa.length) &&
!memcmp(lsa_body, en->lsa_body, lsa_blen) &&
2019-06-30 20:12:59 +02:00
(!ospf_is_v2(p) || (lsa->opts == lsa_get_options(&en->lsa))) &&
!en->gr_dirty)
2014-06-26 11:58:57 +02:00
goto drop;
lsa_body = lsab_flush(p);
if (! ospf_do_originate_lsa(p, en, lsa_body, lsa_blen, lsa->opts))
{
2014-07-18 18:24:12 +02:00
OSPF_TRACE(D_EVENTS, "Postponing LSA: Type: %04x, Id: %R, Rt: %R",
en->lsa_type, en->lsa.id, en->lsa.rt);
2014-06-26 11:58:57 +02:00
en->next_lsa_body = lsa_body;
en->next_lsa_blen = lsa_blen;
en->next_lsa_opts = lsa->opts;
}
return en;
drop:
lsab_reset(p);
return en;
}
static void
ospf_originate_next_lsa(struct ospf_proto *p, struct top_hash_entry *en)
{
2014-06-26 11:58:57 +02:00
/* Called by ospf_update_lsadb() to handle scheduled origination */
if (! ospf_do_originate_lsa(p, en, en->next_lsa_body, en->next_lsa_blen, en->next_lsa_opts))
return;
2014-07-19 17:28:38 +02:00
2014-06-26 11:58:57 +02:00
en->next_lsa_body = NULL;
en->next_lsa_blen = 0;
en->next_lsa_opts = 0;
}
static void
ospf_refresh_lsa(struct ospf_proto *p, struct top_hash_entry *en)
{
/*
* Called by ospf_update_lsadb() for periodic LSA refresh.
*
* We know that lsa.age < LSA_MAXAGE and lsa.rt is our router ID. We can also
* assume that there is no scheduled LSA, because inst_time is deep in past,
* therefore ospf_originate_next_lsa() called before would either succeed or
* switched lsa.age to LSA_MAXAGE.
*/
2014-07-18 18:24:12 +02:00
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.sn);
2014-06-26 11:58:57 +02:00
ASSERT(en->next_lsa_body == NULL);
/* Handle wrapping sequence number */
if (en->lsa.sn == LSA_MAXSEQNO)
{
/* Copy LSA body as next LSA to get automatic origination after flush is finished */
en->next_lsa_blen = en->lsa.length - sizeof(struct ospf_lsa_header);
en->next_lsa_body = mb_alloc(p->p.pool, en->next_lsa_blen);
memcpy(en->next_lsa_body, en->lsa_body, en->next_lsa_blen);
en->next_lsa_opts = ospf_is_v2(p) ? lsa_get_options(&en->lsa) : 0;
en->lsa.age = LSA_MAXAGE;
2014-07-18 18:24:12 +02:00
ospf_flood_lsa(p, en, NULL);
2014-06-26 11:58:57 +02:00
return;
}
en->lsa.sn++;
en->lsa.age = 0;
en->init_age = 0;
2017-06-20 18:03:06 +02:00
en->inst_time = current_time();
2015-05-01 14:40:56 +02:00
lsa_generate_checksum(&en->lsa, en->lsa_body);
2014-07-18 18:24:12 +02:00
ospf_flood_lsa(p, en, NULL);
2014-06-26 11:58:57 +02:00
}
/**
* ospf_flush_lsa - flush LSA from OSPF domain
* @p: OSPF protocol instance
* @en: LSA entry to flush
*
* This function flushes @en from the OSPF domain by setting its age to
* %LSA_MAXAGE and flooding it. That also triggers subsequent events in LSA
* lifecycle leading to removal of the LSA from the LSA database (e.g. the LSA
* content is freed when flushing is acknowledged by neighbors). The function
* does nothing if the LSA is already being flushed. LSA entries are not
* 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()
* and is supposed to do the right thing even in cases of postponed
2014-07-18 18:24:12 +02:00
* origination.
2014-06-26 11:58:57 +02:00
*/
void
ospf_flush_lsa(struct ospf_proto *p, struct top_hash_entry *en)
{
2018-12-17 17:01:08 +01:00
en->nf = NULL;
en->gr_dirty = 0;
2018-12-17 17:01:08 +01:00
2014-06-26 11:58:57 +02:00
if (en->next_lsa_body)
{
mb_free(en->next_lsa_body);
en->next_lsa_body = NULL;
en->next_lsa_blen = 0;
en->next_lsa_opts = 0;
}
if (en->lsa.age == LSA_MAXAGE)
return;
2014-11-03 10:42:55 +01:00
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.sn);
2014-06-26 11:58:57 +02:00
en->lsa.age = LSA_MAXAGE;
2014-07-18 18:24:12 +02:00
ospf_flood_lsa(p, en, NULL);
if (en->mode == LSA_M_BASIC)
2019-06-30 20:12:59 +02:00
{
ospf_neigh_lsadb_changed(p, en);
2014-07-18 18:24:12 +02:00
ospf_schedule_rtcalc(p);
2019-06-30 20:12:59 +02:00
}
2014-07-18 18:24:12 +02:00
en->mode = LSA_M_BASIC;
2014-06-26 11:58:57 +02:00
}
static void
ospf_clear_lsa(struct ospf_proto *p, struct top_hash_entry *en)
{
/*
* Called by ospf_update_lsadb() as part of LSA flushing process.
* Flushed LSA was acknowledged by neighbors and we can free its content.
2014-11-03 10:42:55 +01:00
* The log message is for 'remove' - we hide empty LSAs from users.
2014-06-26 11:58:57 +02:00
*/
2014-11-03 10:42:55 +01:00
OSPF_TRACE(D_EVENTS, "Removing LSA: Type: %04x, Id: %R, Rt: %R, Seq: %08x",
en->lsa_type, en->lsa.id, en->lsa.rt, en->lsa.sn);
2014-06-26 11:58:57 +02:00
if (en->lsa.sn == LSA_MAXSEQNO)
en->lsa.sn = LSA_ZEROSEQNO;
mb_free(en->lsa_body);
en->lsa_body = NULL;
}
static void
ospf_remove_lsa(struct ospf_proto *p, struct top_hash_entry *en)
{
/*
* Called by ospf_update_lsadb() as part of LSA flushing process.
* Both lsa_body and next_lsa_body are NULL.
*/
s_rem_node(SNODE en);
ospf_hash_delete(p->gr, en);
}
/**
* ospf_update_lsadb - update LSA database
* @p: OSPF protocol instance
*
* This function is periodicaly invoked from ospf_disp(). It does some periodic
* or postponed processing related to LSA entries. It originates postponed LSAs
* scheduled by ospf_originate_lsa(), It continues in flushing processes started
* by ospf_flush_lsa(). It also periodically refreshs locally originated LSAs --
* when the current instance is older %LSREFRESHTIME, a new instance is originated.
* Finally, it also ages stored LSAs and flushes ones that reached %LSA_MAXAGE.
*
* The RFC 2328 says that a router should periodically check checksums of all
* stored LSAs to detect hardware problems. This is not implemented.
*/
void
ospf_update_lsadb(struct ospf_proto *p)
{
struct top_hash_entry *en, *nxt;
2017-06-20 18:03:06 +02:00
btime now_ = current_time();
int real_age;
2014-06-26 11:58:57 +02:00
WALK_SLIST_DELSAFE(en, nxt, p->lsal)
{
if (en->next_lsa_body)
ospf_originate_next_lsa(p, en);
2017-06-20 18:03:06 +02:00
real_age = en->init_age + (now_ - en->inst_time) TO_S;
2014-06-26 11:58:57 +02:00
if (en->lsa.age == LSA_MAXAGE)
{
if (en->lsa_body && (p->padj == 0) && (en->ret_count == 0))
ospf_clear_lsa(p, en);
if ((en->lsa_body == NULL) && (en->next_lsa_body == NULL) &&
((en->lsa.rt != p->router_id) || (real_age >= LSA_MAXAGE)))
ospf_remove_lsa(p, en);
continue;
}
if ((en->lsa.rt == p->router_id) && (real_age >= LSREFRESHTIME))
{
ospf_refresh_lsa(p, en);
continue;
}
if (real_age >= LSA_MAXAGE)
{
2014-06-26 11:58:57 +02:00
ospf_flush_lsa(p, en);
continue;
}
2014-06-26 11:58:57 +02:00
en->lsa.age = real_age;
}
}
2019-06-30 20:12:59 +02:00
void
ospf_feed_begin(struct channel *C, int initial UNUSED)
2019-06-30 20:12:59 +02:00
{
struct ospf_proto *p = (struct ospf_proto *) C->proto;
2019-06-30 20:12:59 +02:00
struct top_hash_entry *en;
/* Mark all external LSAs as stale */
2019-06-30 20:12:59 +02:00
WALK_SLIST(en, p->lsal)
if (en->mode == LSA_M_EXPORT)
en->mode = LSA_M_EXPORT_STALE;
}
void
ospf_feed_end(struct channel *C)
{
struct ospf_proto *p = (struct ospf_proto *) C->proto;
struct top_hash_entry *en;
/* Flush stale LSAs */
WALK_SLIST(en, p->lsal)
if (en->mode == LSA_M_EXPORT_STALE)
ospf_flush_lsa(p, en);
2019-06-30 20:12:59 +02:00
}
2014-06-26 11:58:57 +02:00
static u32
2014-06-26 11:58:57 +02:00
ort_to_lsaid(struct ospf_proto *p, ort *nf)
{
/*
* In OSPFv2, We have to map IP prefixes to u32 in such manner that resulting
* u32 interpreted as IP address is a member of given prefix. Therefore, /32
2015-11-05 12:48:52 +01:00
* prefix has to be mapped on itself. All received prefixes have to be mapped
* on different u32s.
2014-06-26 11:58:57 +02:00
*
* We have an assumption that if there is nontrivial (non-/32) network prefix,
* then there is not /32 prefix for the first and the last IP address of the
* network (these are usually reserved, therefore it is not an important
* restriction). The network prefix is mapped to the first or the last IP
* address in the manner that disallow collisions - we use the IP address that
* cannot be used by the parent prefix.
*
* For example:
* 192.168.0.0/24 maps to 192.168.0.255
* 192.168.1.0/24 maps to 192.168.1.0
* because 192.168.0.0 and 192.168.1.255 might be used by 192.168.0.0/23 .
*
* Appendig E of RFC 2328 suggests different algorithm, that tries to maximize
* both compatibility and subnetting. But as it is not possible to have both
* reliably and the suggested algorithm was unnecessary complicated and it
* does crazy things like changing LSA ID for a network because different
* network appeared, we choose a different way.
*
* In OSPFv3, it is simpler. There is not a requirement for membership of the
* result in the input network, so we just allocate a unique ID from ID map
* and store it in nf->lsa_id for further reference.
2014-06-26 11:58:57 +02:00
*/
if (ospf_is_v3(p))
{
if (!nf->lsa_id)
nf->lsa_id = idm_alloc(&p->idm);
return nf->lsa_id;
}
2014-06-26 11:58:57 +02:00
2015-11-05 12:48:52 +01:00
net_addr_ip4 *net = (void *) nf->fn.addr;
u32 id = ip4_to_u32(net->prefix);
int pxlen = net->pxlen;
2014-06-26 11:58:57 +02:00
if ((pxlen == 0) || (pxlen == 32))
return id;
if (id & (1 << (32 - pxlen)))
return id;
else
return id | ~u32_mkmask(pxlen);
}
static void *
2014-07-18 18:24:12 +02:00
lsab_alloc(struct ospf_proto *p, uint size)
2014-06-26 11:58:57 +02:00
{
2014-07-18 18:24:12 +02:00
uint offset = p->lsab_used;
2014-06-26 11:58:57 +02:00
p->lsab_used += size;
if (p->lsab_used > p->lsab_size)
{
p->lsab_size = MAX(p->lsab_used, 2 * p->lsab_size);
p->lsab = p->lsab ? mb_realloc(p->lsab, p->lsab_size):
mb_alloc(p->p.pool, p->lsab_size);
}
return ((byte *) p->lsab) + offset;
}
static inline void *
2014-07-18 18:24:12 +02:00
lsab_allocz(struct ospf_proto *p, uint size)
{
2014-06-26 11:58:57 +02:00
void *r = lsab_alloc(p, size);
bzero(r, size);
return r;
}
static inline void *
2014-06-26 11:58:57 +02:00
lsab_flush(struct ospf_proto *p)
{
2014-06-26 11:58:57 +02:00
void *r = mb_alloc(p->p.pool, p->lsab_used);
memcpy(r, p->lsab, p->lsab_used);
p->lsab_used = 0;
return r;
}
2014-06-26 11:58:57 +02:00
static inline void
lsab_reset(struct ospf_proto *p)
2009-08-21 09:27:52 +02:00
{
2014-06-26 11:58:57 +02:00
p->lsab_used = 0;
2009-08-21 09:27:52 +02:00
}
static inline void *
2014-07-18 18:24:12 +02:00
lsab_offset(struct ospf_proto *p, uint offset)
2009-08-21 09:27:52 +02:00
{
2014-06-26 11:58:57 +02:00
return ((byte *) p->lsab) + offset;
2009-08-21 09:27:52 +02:00
}
static inline void * UNUSED
2014-06-26 11:58:57 +02:00
lsab_end(struct ospf_proto *p)
{
2014-06-26 11:58:57 +02:00
return ((byte *) p->lsab) + p->lsab_used;
}
2009-08-21 09:27:52 +02:00
2014-06-26 11:58:57 +02:00
/*
* Router-LSA handling
* Type = LSA_T_RT
*/
static int
configured_stubnet(struct ospf_area *oa, struct ifa *a)
{
2011-03-28 22:46:18 +02:00
/* Does not work for IA_PEER addresses, but it is not called on these */
struct ospf_stubnet_config *sn;
WALK_LIST(sn, oa->ac->stubnet_list)
2014-06-26 11:58:57 +02:00
{
if (sn->summary)
{
2015-11-12 02:03:59 +01:00
if (net_in_netX(&a->prefix, &sn->prefix))
2014-06-26 11:58:57 +02:00
return 1;
}
2014-06-26 11:58:57 +02:00
else
{
2015-11-12 02:03:59 +01:00
if (net_equal(&a->prefix, &sn->prefix))
2014-06-26 11:58:57 +02:00
return 1;
}
}
return 0;
}
2014-06-26 11:58:57 +02:00
static int
2009-08-21 09:27:52 +02:00
bcast_net_active(struct ospf_iface *ifa)
{
struct ospf_neighbor *neigh;
if (ifa->state == OSPF_IS_WAITING)
return 0;
WALK_LIST(neigh, ifa->neigh_list)
2014-06-26 11:58:57 +02:00
{
if (neigh->state == NEIGHBOR_FULL)
2009-08-21 09:27:52 +02:00
{
2014-06-26 11:58:57 +02:00
if (neigh->rid == ifa->drid)
return 1;
2009-08-21 09:27:52 +02:00
2014-06-26 11:58:57 +02:00
if (ifa->state == OSPF_IS_DR)
return 1;
2009-08-21 09:27:52 +02:00
}
2014-06-26 11:58:57 +02:00
}
2009-08-21 09:27:52 +02:00
return 0;
}
2014-06-26 11:58:57 +02:00
static inline u32
get_rt_options(struct ospf_proto *p, struct ospf_area *oa, int bitv)
{
u32 opts = 0;
2009-08-21 09:27:52 +02:00
2014-06-26 11:58:57 +02:00
if (p->areano > 1)
opts |= OPT_RT_B;
2009-08-21 09:27:52 +02:00
2014-06-26 11:58:57 +02:00
if ((p->areano > 1) && oa_is_nssa(oa) && oa->ac->translator)
opts |= OPT_RT_NT;
2014-06-26 11:58:57 +02:00
if (p->asbr && !oa_is_stub(oa))
opts |= OPT_RT_E;
2009-08-21 09:27:52 +02:00
2014-06-26 11:58:57 +02:00
if (bitv)
opts |= OPT_RT_V;
2009-08-21 09:27:52 +02:00
2014-06-26 11:58:57 +02:00
return opts;
}
2009-08-21 09:27:52 +02:00
2014-06-26 11:58:57 +02:00
static inline void
add_rt2_lsa_link(struct ospf_proto *p, u8 type, u32 id, u32 data, u16 metric)
{
struct ospf_lsa_rt2_link *ln = lsab_alloc(p, sizeof(struct ospf_lsa_rt2_link));
ln->type = type;
ln->id = id;
ln->data = data;
ln->metric = metric;
ln->no_tos = 0;
}
2011-07-22 20:00:24 +02:00
2014-06-26 11:58:57 +02:00
static void
prepare_rt2_lsa_body(struct ospf_proto *p, struct ospf_area *oa)
{
struct ospf_iface *ifa;
int i = 0, bitv = 0;
struct ospf_neighbor *neigh;
2009-08-21 09:27:52 +02:00
2014-06-26 11:58:57 +02:00
ASSERT(p->lsab_used == 0);
lsab_allocz(p, sizeof(struct ospf_lsa_rt));
/* ospf_lsa_rt header will be filled later */
2004-06-06 08:55:33 +00:00
2014-06-26 11:58:57 +02:00
WALK_LIST(ifa, p->iface_list)
{
2010-02-11 10:23:35 +01:00
int net_lsa = 0;
2014-06-26 11:58:57 +02:00
u32 link_cost = p->stub_router ? 0xffff : ifa->cost;
if ((ifa->type == OSPF_IT_VLINK) && (ifa->voa == oa) &&
(!EMPTY_LIST(ifa->neigh_list)))
{
neigh = (struct ospf_neighbor *) HEAD(ifa->neigh_list);
if ((neigh->state == NEIGHBOR_FULL) && (ifa->cost <= 0xffff))
bitv = 1;
}
2004-07-14 21:46:20 +00:00
if ((ifa->oa != oa) || (ifa->state == OSPF_IS_DOWN))
2004-06-06 08:55:33 +00:00
continue;
2000-06-05 20:57:53 +00:00
ifa->rt_pos_beg = i;
2014-06-26 11:58:57 +02:00
/* RFC 2328 - 12.4.1.1-4 */
switch (ifa->type)
2014-06-26 11:58:57 +02:00
{
case OSPF_IT_PTP:
case OSPF_IT_PTMP:
WALK_LIST(neigh, ifa->neigh_list)
if (neigh->state == NEIGHBOR_FULL)
2004-06-25 16:39:53 +00:00
{
2014-06-26 11:58:57 +02:00
/*
2020-05-26 18:21:43 +02:00
* ln->data field should be ifa->iface_id for unnumbered PtP links,
* IP address otherwise (see RFC 2328 12.4.1.1). This is controlled
* by ifa->ptp_address field.
2014-06-26 11:58:57 +02:00
*/
2020-05-26 18:21:43 +02:00
add_rt2_lsa_link(p, LSART_PTP, neigh->rid, ospf_iface_get_data(ifa), link_cost);
i++;
2014-06-26 11:58:57 +02:00
}
break;
2014-06-26 11:58:57 +02:00
case OSPF_IT_BCAST:
case OSPF_IT_NBMA:
if (bcast_net_active(ifa))
{
add_rt2_lsa_link(p, LSART_NET, ipa_to_u32(ifa->drip), ipa_to_u32(ifa->addr->ip), link_cost);
i++;
net_lsa = 1;
}
2014-06-26 11:58:57 +02:00
break;
case OSPF_IT_VLINK:
neigh = (struct ospf_neighbor *) HEAD(ifa->neigh_list);
if ((!EMPTY_LIST(ifa->neigh_list)) && (neigh->state == NEIGHBOR_FULL) && (ifa->cost <= 0xffff))
add_rt2_lsa_link(p, LSART_VLNK, neigh->rid, ipa_to_u32(ifa->addr->ip), link_cost), i++;
break;
default:
2014-10-24 10:27:21 +02:00
log(L_BUG "OSPF: Unknown interface type");
2014-06-26 11:58:57 +02:00
break;
}
ifa->rt_pos_end = i;
2010-03-14 16:36:59 +01:00
/* Now we will originate stub area if there is no primary */
if (net_lsa ||
(ifa->type == OSPF_IT_VLINK) ||
((ifa->addr->flags & IA_PEER) && ! ifa->cf->stub) ||
2010-03-14 16:36:59 +01:00
configured_stubnet(oa, ifa->addr))
continue;
2014-06-26 11:58:57 +02:00
/* Host or network stub entry */
2011-03-28 22:46:18 +02:00
if ((ifa->addr->flags & IA_HOST) ||
(ifa->state == OSPF_IS_LOOP) ||
(ifa->type == OSPF_IT_PTMP))
2014-06-26 11:58:57 +02:00
add_rt2_lsa_link(p, LSART_STUB, ipa_to_u32(ifa->addr->ip), 0xffffffff, 0);
2014-07-19 17:28:38 +02:00
else
2015-11-12 02:03:59 +01:00
add_rt2_lsa_link(p, LSART_STUB, ip4_to_u32(net4_prefix(&ifa->addr->prefix)),
u32_mkmask(net4_pxlen(&ifa->addr->prefix)), ifa->cost);
2010-03-14 16:36:59 +01:00
i++;
ifa->rt_pos_end = i;
}
struct ospf_stubnet_config *sn;
2014-06-26 11:58:57 +02:00
WALK_LIST(sn, oa->ac->stubnet_list)
if (!sn->hidden)
2015-11-12 02:03:59 +01:00
add_rt2_lsa_link(p, LSART_STUB, ip4_to_u32(net4_prefix(&sn->prefix)),
u32_mkmask(net4_pxlen(&sn->prefix)), sn->cost), i++;
2009-08-21 09:27:52 +02:00
2014-06-26 11:58:57 +02:00
struct ospf_lsa_rt *rt = p->lsab;
2014-07-19 17:28:38 +02:00
/* Store number of links in lower half of options */
2014-06-26 11:58:57 +02:00
rt->options = get_rt_options(p, oa, bitv) | (u16) i;
}
2000-05-02 22:19:41 +00:00
2014-06-26 11:58:57 +02:00
static inline void
add_rt3_lsa_link(struct ospf_proto *p, u8 type, struct ospf_iface *ifa, u32 nif, u32 id)
2009-08-21 09:27:52 +02:00
{
2014-06-26 11:58:57 +02:00
struct ospf_lsa_rt3_link *ln = lsab_alloc(p, sizeof(struct ospf_lsa_rt3_link));
2009-08-21 09:27:52 +02:00
ln->type = type;
ln->padding = 0;
ln->metric = ifa->cost;
2012-10-31 17:14:35 +01:00
ln->lif = ifa->iface_id;
2009-08-21 09:27:52 +02:00
ln->nif = nif;
ln->id = id;
}
2014-06-26 11:58:57 +02:00
static void
prepare_rt3_lsa_body(struct ospf_proto *p, struct ospf_area *oa)
2009-08-21 09:27:52 +02:00
{
struct ospf_iface *ifa;
2014-06-26 11:58:57 +02:00
struct ospf_neighbor *neigh;
2009-08-25 16:42:14 +02:00
int bitv = 0;
int i = 0;
2011-07-22 20:00:24 +02:00
2014-06-26 11:58:57 +02:00
ASSERT(p->lsab_used == 0);
lsab_allocz(p, sizeof(struct ospf_lsa_rt));
/* ospf_lsa_rt header will be filled later */
2009-08-21 09:27:52 +02:00
2014-06-26 11:58:57 +02:00
WALK_LIST(ifa, p->iface_list)
2009-08-21 09:27:52 +02:00
{
if ((ifa->type == OSPF_IT_VLINK) && (ifa->voa == oa) &&
(!EMPTY_LIST(ifa->neigh_list)))
{
neigh = (struct ospf_neighbor *) HEAD(ifa->neigh_list);
if ((neigh->state == NEIGHBOR_FULL) && (ifa->cost <= 0xffff))
bitv = 1;
}
if ((ifa->oa != oa) || (ifa->state == OSPF_IS_DOWN))
continue;
ifa->rt_pos_beg = i;
2014-06-26 11:58:57 +02:00
/* RFC 5340 - 4.4.3.2 */
2009-08-21 09:27:52 +02:00
switch (ifa->type)
2014-06-26 11:58:57 +02:00
{
case OSPF_IT_PTP:
case OSPF_IT_PTMP:
WALK_LIST(neigh, ifa->neigh_list)
if (neigh->state == NEIGHBOR_FULL)
add_rt3_lsa_link(p, LSART_PTP, ifa, neigh->iface_id, neigh->rid), i++;
break;
2014-06-26 11:58:57 +02:00
case OSPF_IT_BCAST:
case OSPF_IT_NBMA:
if (bcast_net_active(ifa))
add_rt3_lsa_link(p, LSART_NET, ifa, ifa->dr_iface_id, ifa->drid), i++;
break;
2009-08-21 09:27:52 +02:00
2014-06-26 11:58:57 +02:00
case OSPF_IT_VLINK:
neigh = (struct ospf_neighbor *) HEAD(ifa->neigh_list);
if ((!EMPTY_LIST(ifa->neigh_list)) && (neigh->state == NEIGHBOR_FULL) && (ifa->cost <= 0xffff))
add_rt3_lsa_link(p, LSART_VLNK, ifa, neigh->iface_id, neigh->rid), i++;
break;
default:
2014-10-24 10:27:21 +02:00
log(L_BUG "OSPF: Unknown interface type");
2014-06-26 11:58:57 +02:00
break;
2009-08-21 09:27:52 +02:00
}
2014-06-26 11:58:57 +02:00
ifa->rt_pos_end = i;
}
2009-08-21 09:27:52 +02:00
2014-06-26 11:58:57 +02:00
struct ospf_lsa_rt *rt = p->lsab;
rt->options = get_rt_options(p, oa, bitv) | (oa->options & LSA_OPTIONS_MASK);
}
2009-08-21 09:27:52 +02:00
2014-06-26 11:58:57 +02:00
static void
ospf_originate_rt_lsa(struct ospf_proto *p, struct ospf_area *oa)
{
2014-06-26 11:58:57 +02:00
struct ospf_new_lsa lsa = {
.type = LSA_T_RT,
.dom = oa->areaid,
.id = ospf_is_v2(p) ? p->router_id : 0,
.opts = oa->options
};
2014-07-18 18:24:12 +02:00
OSPF_TRACE(D_EVENTS, "Updating router state for area %R", oa->areaid);
2014-06-26 11:58:57 +02:00
if (ospf_is_v2(p))
prepare_rt2_lsa_body(p, oa);
else
prepare_rt3_lsa_body(p, oa);
2004-06-06 08:55:33 +00:00
2014-06-26 11:58:57 +02:00
oa->rt = ospf_originate_lsa(p, &lsa);
}
2010-01-03 12:17:52 +01:00
2009-08-21 09:27:52 +02:00
2014-06-26 11:58:57 +02:00
/*
* Net-LSA handling
* Type = LSA_T_NET
*/
2009-08-25 16:42:14 +02:00
2014-06-26 11:58:57 +02:00
static void
prepare_net2_lsa_body(struct ospf_proto *p, struct ospf_iface *ifa)
2009-08-25 16:42:14 +02:00
{
2014-06-26 11:58:57 +02:00
struct ospf_lsa_net *net;
struct ospf_neighbor *n;
int nodes = ifa->fadj + 1;
u16 i = 1;
2009-08-25 16:42:14 +02:00
2014-06-26 11:58:57 +02:00
ASSERT(p->lsab_used == 0);
net = lsab_alloc(p, sizeof(struct ospf_lsa_net) + 4 * nodes);
2009-08-25 16:42:14 +02:00
2015-11-12 02:03:59 +01:00
net->optx = u32_mkmask(ifa->addr->prefix.pxlen);
2014-06-26 11:58:57 +02:00
net->routers[0] = p->router_id;
2009-08-25 16:42:14 +02:00
2014-06-26 11:58:57 +02:00
WALK_LIST(n, ifa->neigh_list)
{
if (n->state == NEIGHBOR_FULL)
{
net->routers[i] = n->rid;
i++;
}
}
ASSERT(i == nodes);
}
2014-06-26 11:58:57 +02:00
static void
prepare_net3_lsa_body(struct ospf_proto *p, struct ospf_iface *ifa)
2000-05-02 23:09:44 +00:00
{
2000-05-04 01:23:03 +00:00
struct ospf_lsa_net *net;
2009-08-21 09:27:52 +02:00
int nodes = ifa->fadj + 1;
u32 options = 0;
2014-06-26 11:58:57 +02:00
u16 i = 1;
ASSERT(p->lsab_used == 0);
net = lsab_alloc(p, sizeof(struct ospf_lsa_net) + 4 * nodes);
2009-08-21 09:27:52 +02:00
2014-06-26 11:58:57 +02:00
net->routers[0] = p->router_id;
2000-05-04 01:23:03 +00:00
2014-06-26 11:58:57 +02:00
struct ospf_neighbor *n;
2004-06-06 08:55:33 +00:00
WALK_LIST(n, ifa->neigh_list)
2000-05-02 23:09:44 +00:00
{
2004-06-06 08:55:33 +00:00
if (n->state == NEIGHBOR_FULL)
2000-05-02 23:09:44 +00:00
{
2014-06-26 11:58:57 +02:00
/* In OSPFv3, we would like to merge options from Link LSAs of added neighbors */
struct top_hash_entry *en =
ospf_hash_find(p->gr, ifa->iface_id, n->iface_id, n->rid, LSA_T_LINK);
2009-08-21 09:27:52 +02:00
if (en)
options |= ((struct ospf_lsa_link *) en->lsa_body)->options;
net->routers[i] = n->rid;
2000-05-02 23:09:44 +00:00
i++;
}
}
2009-08-21 09:27:52 +02:00
ASSERT(i == nodes);
2014-06-26 11:58:57 +02:00
net->optx = options & LSA_OPTIONS_MASK;
2000-05-02 23:09:44 +00:00
}
2014-06-26 11:58:57 +02:00
static void
ospf_originate_net_lsa(struct ospf_proto *p, struct ospf_iface *ifa)
{
struct ospf_new_lsa lsa = {
.type = LSA_T_NET,
.dom = ifa->oa->areaid,
.id = ospf_is_v2(p) ? ipa_to_u32(ifa->addr->ip) : ifa->iface_id,
.opts = ifa->oa->options,
.ifa = ifa
};
2014-07-18 18:24:12 +02:00
OSPF_TRACE(D_EVENTS, "Updating network state for %s (Id: %R)", ifa->ifname, lsa.id);
2014-06-26 11:58:57 +02:00
if (ospf_is_v2(p))
prepare_net2_lsa_body(p, ifa);
2009-08-25 16:42:14 +02:00
else
2014-06-26 11:58:57 +02:00
prepare_net3_lsa_body(p, ifa);
2014-06-26 11:58:57 +02:00
ifa->net_lsa = ospf_originate_lsa(p, &lsa);
}
2014-06-26 11:58:57 +02:00
/*
* (Net|Rt)-summary-LSA handling
* (a.k.a. Inter-Area-(Prefix|Router)-LSA)
* Type = LSA_T_SUM_NET, LSA_T_SUM_RT
*/
2014-06-26 11:58:57 +02:00
static inline void
prepare_sum2_lsa_body(struct ospf_proto *p, uint pxlen, u32 metric)
{
2014-06-26 11:58:57 +02:00
struct ospf_lsa_sum2 *sum;
2009-08-21 09:27:52 +02:00
2014-06-26 11:58:57 +02:00
sum = lsab_allocz(p, sizeof(struct ospf_lsa_sum2));
sum->netmask = u32_mkmask(pxlen);
2009-08-21 09:27:52 +02:00
sum->metric = metric;
}
2014-06-26 11:58:57 +02:00
static inline void
prepare_sum3_net_lsa_body(struct ospf_proto *p, ort *nf, u32 metric)
{
2014-06-26 11:58:57 +02:00
struct ospf_lsa_sum3_net *sum;
2015-11-05 12:48:52 +01:00
sum = lsab_allocz(p, sizeof(struct ospf_lsa_sum3_net) +
IPV6_PREFIX_SPACE(nf->fn.addr->pxlen));
2014-06-26 11:58:57 +02:00
sum->metric = metric;
2017-10-09 01:16:29 +02:00
ospf3_put_prefix(sum->prefix, nf->fn.addr, 0, 0);
}
2014-06-26 11:58:57 +02:00
static inline void
prepare_sum3_rt_lsa_body(struct ospf_proto *p, u32 drid, u32 metric, u32 options)
2009-08-21 09:27:52 +02:00
{
2014-06-26 11:58:57 +02:00
struct ospf_lsa_sum3_rt *sum;
2009-08-21 09:27:52 +02:00
2014-06-26 11:58:57 +02:00
sum = lsab_allocz(p, sizeof(struct ospf_lsa_sum3_rt));
sum->options = options;
2009-08-21 09:27:52 +02:00
sum->metric = metric;
sum->drid = drid;
}
2004-06-25 16:39:53 +00:00
void
2014-06-26 11:58:57 +02:00
ospf_originate_sum_net_lsa(struct ospf_proto *p, struct ospf_area *oa, ort *nf, int metric)
2004-06-25 16:39:53 +00:00
{
2014-06-26 11:58:57 +02:00
struct ospf_new_lsa lsa = {
.type = LSA_T_SUM_NET,
2014-07-18 18:24:12 +02:00
.mode = LSA_M_RTCALC,
2014-06-26 11:58:57 +02:00
.dom = oa->areaid,
.id = ort_to_lsaid(p, nf),
.opts = oa->options,
.nf = nf
};
2014-06-26 11:58:57 +02:00
if (ospf_is_v2(p))
2015-11-05 12:48:52 +01:00
prepare_sum2_lsa_body(p, nf->fn.addr->pxlen, metric);
2014-06-26 11:58:57 +02:00
else
prepare_sum3_net_lsa_body(p, nf, metric);
2009-08-21 09:27:52 +02:00
2014-07-18 18:24:12 +02:00
ospf_originate_lsa(p, &lsa);
}
2009-08-21 09:27:52 +02:00
void
2015-11-05 12:48:52 +01:00
ospf_originate_sum_rt_lsa(struct ospf_proto *p, struct ospf_area *oa, u32 drid, int metric, u32 options)
{
2014-06-26 11:58:57 +02:00
struct ospf_new_lsa lsa = {
.type = LSA_T_SUM_RT,
2014-07-18 18:24:12 +02:00
.mode = LSA_M_RTCALC,
2014-06-26 11:58:57 +02:00
.dom = oa->areaid,
2015-11-05 12:48:52 +01:00
.id = drid, /* Router ID of ASBR, irrelevant for OSPFv3 */
2014-06-26 11:58:57 +02:00
.opts = oa->options
};
2004-06-25 16:39:53 +00:00
2014-06-26 11:58:57 +02:00
if (ospf_is_v2(p))
prepare_sum2_lsa_body(p, 0, metric);
2009-08-21 09:27:52 +02:00
else
2015-11-05 12:48:52 +01:00
prepare_sum3_rt_lsa_body(p, drid, metric, options & LSA_OPTIONS_MASK);
2014-07-18 18:24:12 +02:00
ospf_originate_lsa(p, &lsa);
2004-06-25 16:39:53 +00:00
}
2009-08-21 09:27:52 +02:00
/*
2014-06-26 11:58:57 +02:00
* AS-external-LSA and NSSA-LSA handling
* Type = LSA_T_EXT, LSA_T_NSSA
*/
2009-08-21 09:27:52 +02:00
2014-06-26 11:58:57 +02:00
static inline void
prepare_ext2_lsa_body(struct ospf_proto *p, uint pxlen,
u32 metric, u32 ebit, ip_addr fwaddr, u32 tag)
{
2014-06-26 11:58:57 +02:00
struct ospf_lsa_ext2 *ext;
2014-06-26 11:58:57 +02:00
ext = lsab_allocz(p, sizeof(struct ospf_lsa_ext2));
ext->metric = metric & LSA_METRIC_MASK;
ext->netmask = u32_mkmask(pxlen);
ext->fwaddr = ipa_to_u32(fwaddr);
ext->tag = tag;
2014-06-26 11:58:57 +02:00
if (ebit)
ext->metric |= LSA_EXT2_EBIT;
}
2009-08-21 09:27:52 +02:00
2014-06-26 11:58:57 +02:00
static inline void
prepare_ext3_lsa_body(struct ospf_proto *p, ort *nf,
u32 metric, u32 ebit, ip_addr fwaddr, u32 tag, int pbit, int dn)
{
2014-06-26 11:58:57 +02:00
struct ospf_lsa_ext3 *ext;
int bsize = sizeof(struct ospf_lsa_ext3)
2015-11-05 12:48:52 +01:00
+ IPV6_PREFIX_SPACE(nf->fn.addr->pxlen)
+ (ipa_nonzero(fwaddr) ? 16 : 0)
+ (tag ? 4 : 0);
2014-06-26 11:58:57 +02:00
ext = lsab_allocz(p, bsize);
ext->metric = metric & LSA_METRIC_MASK;
u32 *buf = ext->rest;
uint flags = (pbit ? OPT_PX_P : 0) | (dn ? OPT_PX_DN : 0);
buf = ospf3_put_prefix(buf, nf->fn.addr, flags, 0);
2014-06-26 11:58:57 +02:00
if (ebit)
ext->metric |= LSA_EXT3_EBIT;
2009-08-21 09:27:52 +02:00
if (ipa_nonzero(fwaddr))
{
2014-06-26 11:58:57 +02:00
ext->metric |= LSA_EXT3_FBIT;
2017-10-09 01:16:29 +02:00
buf = ospf3_put_addr(buf, fwaddr);
}
2009-08-21 09:27:52 +02:00
if (tag)
{
2014-06-26 11:58:57 +02:00
ext->metric |= LSA_EXT3_TBIT;
*buf++ = tag;
}
2009-08-21 09:27:52 +02:00
}
2014-06-26 11:58:57 +02:00
/**
* originate_ext_lsa - new route received from nest and filters
2014-07-18 18:24:12 +02:00
* @p: OSPF protocol instance
2014-06-26 11:58:57 +02:00
* @oa: ospf_area for which LSA is originated
* @nf: network prefix and mask
2014-07-18 18:24:12 +02:00
* @mode: the mode of the LSA (LSA_M_EXPORT or LSA_M_RTCALC)
* @metric: the metric of a route
* @ebit: E-bit for route metric (bool)
2014-06-26 11:58:57 +02:00
* @fwaddr: the forwarding address
* @tag: the route tag
2014-07-18 18:24:12 +02:00
* @pbit: P-bit for NSSA LSAs (bool), ignored for external LSAs
2014-06-26 11:58:57 +02:00
*
* 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.
* @oa should not be a stub area. @src does not specify whether the LSA
2014-07-19 17:28:38 +02:00
* is external or NSSA, but it specifies the source of origination -
2014-06-26 11:58:57 +02:00
* the export from ospf_rt_notify(), or the NSSA-EXT translation.
*/
void
2014-07-18 18:24:12 +02:00
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, int dn)
{
2014-06-26 11:58:57 +02:00
struct ospf_new_lsa lsa = {
.type = oa ? LSA_T_NSSA : LSA_T_EXT,
2014-07-18 18:24:12 +02:00
.mode = mode, /* LSA_M_EXPORT or LSA_M_RTCALC */
2014-06-26 11:58:57 +02:00
.dom = oa ? oa->areaid : 0,
.id = ort_to_lsaid(p, nf),
.opts = (oa ? (pbit ? OPT_P : 0) : OPT_E) | (dn ? OPT_DN : 0),
2014-06-26 11:58:57 +02:00
.nf = nf
};
2014-06-26 11:58:57 +02:00
if (ospf_is_v2(p))
2015-11-05 12:48:52 +01:00
prepare_ext2_lsa_body(p, nf->fn.addr->pxlen, metric, ebit, fwaddr, tag);
2014-06-26 11:58:57 +02:00
else
prepare_ext3_lsa_body(p, nf, metric, ebit, fwaddr, tag, oa && pbit, dn);
2014-07-18 18:24:12 +02:00
ospf_originate_lsa(p, &lsa);
2014-06-26 11:58:57 +02:00
}
2014-11-03 10:42:55 +01:00
static struct top_hash_entry *
ospf_hash_find_(struct top_graph *f, u32 domain, u32 lsa, u32 rtr, u32 type);
2014-06-26 11:58:57 +02:00
static void
ospf_flush_ext_lsa(struct ospf_proto *p, struct ospf_area *oa, ort *nf)
{
struct top_hash_entry *en;
2010-07-31 11:37:30 +02:00
2014-06-26 11:58:57 +02:00
u32 type = oa ? LSA_T_NSSA : LSA_T_EXT;
u32 dom = oa ? oa->areaid : 0;
u32 id = ort_to_lsaid(p, nf);
2014-11-03 10:42:55 +01:00
en = ospf_hash_find_(p->gr, dom, id, p->router_id, type);
2014-06-26 11:58:57 +02:00
if (!en || (en->nf != nf))
return;
2014-06-26 11:58:57 +02:00
ospf_flush_lsa(p, en);
}
2014-06-26 11:58:57 +02:00
static inline int
use_gw_for_fwaddr(struct ospf_proto *p, ip_addr gw, struct iface *iface)
{
struct ospf_iface *ifa;
if (ipa_zero(gw) || ipa_is_link_local(gw))
return 0;
2014-06-26 11:58:57 +02:00
WALK_LIST(ifa, p->iface_list)
if ((ifa->iface == iface) &&
2015-11-12 02:03:59 +01:00
(!ospf_is_v2(p) || ipa_in_netX(gw, &ifa->addr->prefix)))
2014-06-26 11:58:57 +02:00
return 1;
return 0;
}
2011-09-03 21:31:26 +02:00
static inline ip_addr
2014-06-26 11:58:57 +02:00
find_surrogate_fwaddr(struct ospf_proto *p, struct ospf_area *oa)
2011-09-03 21:31:26 +02:00
{
struct ospf_iface *ifa;
struct ifa *a, *cur_addr = NULL;
int np, cur_np = 0;
2014-06-26 11:58:57 +02:00
/* RFC 3101 2.3 - surrogate forwarding address selection */
WALK_LIST(ifa, p->iface_list)
2011-09-03 21:31:26 +02:00
{
if ((ifa->oa != oa) ||
(ifa->type == OSPF_IT_VLINK))
continue;
2014-06-26 11:58:57 +02:00
if (ospf_is_v2(p))
2011-09-03 21:31:26 +02:00
{
2014-06-26 11:58:57 +02:00
a = ifa->addr;
if (a->flags & IA_PEER)
2011-09-03 21:31:26 +02:00
continue;
2014-06-26 11:58:57 +02:00
np = (a->flags & IA_HOST) ? 3 : (ifa->stub ? 2 : 1);
2011-09-03 21:31:26 +02:00
if (np > cur_np)
{
cur_addr = a;
cur_np = np;
}
}
2014-06-26 11:58:57 +02:00
else /* OSPFv3 */
{
WALK_LIST(a, ifa->iface->addrs)
{
2017-10-09 01:16:29 +02:00
if ((a->prefix.type != ospf_get_af(p)) ||
2015-11-12 02:03:59 +01:00
(a->flags & IA_SECONDARY) ||
2014-06-26 11:58:57 +02:00
(a->flags & IA_PEER) ||
(a->scope <= SCOPE_LINK))
continue;
np = (a->flags & IA_HOST) ? 3 : (ifa->stub ? 2 : 1);
if (np > cur_np)
{
cur_addr = a;
cur_np = np;
}
}
}
2011-09-03 21:31:26 +02:00
}
return cur_addr ? cur_addr->ip : IPA_NONE;
}
2000-05-27 14:17:35 +00:00
void
ospf_rt_notify(struct proto *P, struct channel *ch UNUSED, net *n, rte *new, rte *old UNUSED)
2000-05-27 14:17:35 +00:00
{
2014-06-26 11:58:57 +02:00
struct ospf_proto *p = (struct ospf_proto *) P;
struct ospf_area *oa = NULL; /* non-NULL for NSSA-LSA */
ort *nf;
2011-07-20 23:40:20 +02:00
2014-06-26 11:58:57 +02:00
/*
* There are several posibilities:
* 1) router in regular area - originate external LSA with global scope
* 2) router in NSSA area - originate area-specific NSSA-LSA
* 3) router in stub area - cannot export routes
* 4) area border router - same as (1), it is attached to backbone
*/
2004-06-06 08:55:33 +00:00
2014-06-26 11:58:57 +02:00
if ((p->areano == 1) && oa_is_nssa(HEAD(p->area_list)))
oa = HEAD(p->area_list);
2014-06-26 11:58:57 +02:00
if (!new)
2011-07-20 23:40:20 +02:00
{
2015-11-05 12:48:52 +01:00
nf = fib_find(&p->rtf, n->n.addr);
2011-09-03 21:31:26 +02:00
2014-06-26 11:58:57 +02:00
if (!nf || !nf->external_rte)
2011-09-03 21:31:26 +02:00
return;
2011-07-20 23:40:20 +02:00
2014-06-26 11:58:57 +02:00
ospf_flush_ext_lsa(p, oa, nf);
nf->external_rte = 0;
2014-06-26 11:58:57 +02:00
/* Old external route might blocked some NSSA translation */
if ((p->areano > 1) && rt_is_nssa(nf) && nf->n.oa->translate)
2014-07-18 18:24:12 +02:00
ospf_schedule_rtcalc(p);
2014-06-26 11:58:57 +02:00
return;
}
2009-08-21 09:27:52 +02:00
2014-06-26 11:58:57 +02:00
ASSERT(p->asbr);
2011-09-03 21:31:26 +02:00
2014-06-26 11:58:57 +02:00
/* Get route attributes */
rta *a = new->attrs;
2018-07-19 20:48:13 +02:00
eattr *m1a = ea_find(a->eattrs, EA_OSPF_METRIC1);
eattr *m2a = ea_find(a->eattrs, EA_OSPF_METRIC2);
uint m1 = m1a ? m1a->u.data : 0;
uint m2 = m2a ? m2a->u.data : 10000;
if (m1 > LSINFINITY)
{
log(L_WARN "%s: Invalid ospf_metric1 value %u for route %N",
p->p.name, m1, n->n.addr);
m1 = LSINFINITY;
}
2000-05-27 14:17:35 +00:00
if (m2 > LSINFINITY)
{
log(L_WARN "%s: Invalid ospf_metric2 value %u for route %N",
p->p.name, m2, n->n.addr);
m2 = LSINFINITY;
}
/* Ensure monotonicity of metric if both m1 and m2 are used */
if ((m1 > 0) && (m2 < LSINFINITY))
m2++;
uint ebit = m2a || !m1a;
uint metric = ebit ? m2 : m1;
2018-07-19 20:48:13 +02:00
uint tag = ea_get_int(a->eattrs, EA_OSPF_TAG, 0);
ip_addr fwd = IPA_NONE;
if ((a->dest == RTD_UNICAST) && use_gw_for_fwaddr(p, a->nh.gw, a->nh.iface))
fwd = a->nh.gw;
2009-09-08 13:45:02 +02:00
2014-06-26 11:58:57 +02:00
/* NSSA-LSA with P-bit set must have non-zero forwarding address */
if (oa && ipa_zero(fwd))
{
fwd = find_surrogate_fwaddr(p, oa);
2009-08-21 09:27:52 +02:00
2014-06-26 11:58:57 +02:00
if (ipa_zero(fwd))
2009-08-21 09:27:52 +02:00
{
2015-11-05 12:48:52 +01:00
log(L_ERR "%s: Cannot find forwarding address for NSSA-LSA %N",
p->p.name, n->n.addr);
2014-06-26 11:58:57 +02:00
return;
2009-08-21 09:27:52 +02:00
}
2014-06-26 11:58:57 +02:00
}
2015-11-05 12:48:52 +01:00
nf = fib_get(&p->rtf, n->n.addr);
ospf_originate_ext_lsa(p, oa, nf, LSA_M_EXPORT, metric, ebit, fwd, tag, 1, p->vpn_pe);
2014-06-26 11:58:57 +02:00
nf->external_rte = 1;
2009-08-21 09:27:52 +02:00
}
2014-06-26 11:58:57 +02:00
/*
* Link-LSA handling (assume OSPFv3)
* Type = LSA_T_LINK
*/
2009-08-21 09:27:52 +02:00
2014-06-26 11:58:57 +02:00
static inline void
2017-10-09 01:16:29 +02:00
lsab_put_prefix(struct ospf_proto *p, net_addr *n, u32 cost)
2014-06-26 11:58:57 +02:00
{
2017-10-09 01:16:29 +02:00
void *buf = lsab_alloc(p, IPV6_PREFIX_SPACE(net_pxlen(n)));
uint max = (n->type == NET_IP4) ? IP4_MAX_PREFIX_LENGTH : IP6_MAX_PREFIX_LENGTH;
u8 flags = (net_pxlen(n) < max) ? 0 : OPT_PX_LA;
ospf3_put_prefix(buf, n, flags, cost);
2014-06-26 11:58:57 +02:00
}
static void
prepare_link_lsa_body(struct ospf_proto *p, struct ospf_iface *ifa)
2009-08-21 09:27:52 +02:00
{
2017-10-09 01:16:29 +02:00
ip_addr nh = ospf_is_ip4(p) ? IPA_NONE : ifa->addr->ip;
2009-08-21 09:27:52 +02:00
int i = 0;
2017-10-09 01:16:29 +02:00
/* Preallocating space for header */
2014-06-26 11:58:57 +02:00
ASSERT(p->lsab_used == 0);
2017-10-09 01:16:29 +02:00
lsab_allocz(p, sizeof(struct ospf_lsa_link));
2009-08-21 09:27:52 +02:00
struct ifa *a;
WALK_LIST(a, ifa->iface->addrs)
2014-06-26 11:58:57 +02:00
{
2017-10-09 01:16:29 +02:00
if ((a->prefix.type != ospf_get_af(p)) ||
2015-11-12 02:03:59 +01:00
(a->flags & IA_SECONDARY) ||
(a->scope <= SCOPE_LINK))
2014-06-26 11:58:57 +02:00
continue;
2009-08-21 09:27:52 +02:00
2017-10-09 01:16:29 +02:00
if (ospf_is_ip4(p) && ipa_zero(nh))
nh = a->ip;
2015-11-12 02:03:59 +01:00
lsab_put_prefix(p, &a->prefix, 0);
2014-06-26 11:58:57 +02:00
i++;
}
2009-08-21 09:27:52 +02:00
2017-10-09 01:16:29 +02:00
/* Filling the preallocated header */
struct ospf_lsa_link *ll = p->lsab;
ll->options = ifa->oa->options | (ifa->priority << 24);
ll->lladdr = ospf_is_ip4(p) ? ospf3_4to6(ipa_to_ip4(nh)) : ipa_to_ip6(nh);
2009-08-21 09:27:52 +02:00
ll->pxcount = i;
2017-10-09 01:16:29 +02:00
if (ipa_zero(nh))
log(L_ERR "%s: Cannot find next hop address for %s", p->p.name, ifa->ifname);
2009-08-21 09:27:52 +02:00
}
2014-06-26 11:58:57 +02:00
static void
ospf_originate_link_lsa(struct ospf_proto *p, struct ospf_iface *ifa)
2009-08-21 09:27:52 +02:00
{
2014-06-26 11:58:57 +02:00
if (ospf_is_v2(p))
return;
2014-06-26 11:58:57 +02:00
struct ospf_new_lsa lsa = {
.type = LSA_T_LINK,
.dom = ifa->iface_id,
.id = ifa->iface_id,
.ifa = ifa
};
2009-08-21 09:27:52 +02:00
2014-07-18 18:24:12 +02:00
OSPF_TRACE(D_EVENTS, "Updating link state for %s (Id: %R)", ifa->ifname, lsa.id);
2014-06-26 11:58:57 +02:00
prepare_link_lsa_body(p, ifa);
2009-09-08 13:45:02 +02:00
2014-06-26 11:58:57 +02:00
ifa->link_lsa = ospf_originate_lsa(p, &lsa);
/* RFC 5340 4.4.3 Events 6+7 - new Link LSA is locally originated */
ospf_notify_net_lsa(ifa);
2009-08-21 09:27:52 +02:00
}
2014-06-26 11:58:57 +02:00
/*
* Prefix-Rt-LSA handling (assume OSPFv3)
* Type = LSA_T_PREFIX, referred type = LSA_T_RT
*/
2014-06-26 11:58:57 +02:00
static void
prepare_prefix_rt_lsa_body(struct ospf_proto *p, struct ospf_area *oa)
2009-08-21 09:27:52 +02:00
{
2014-06-26 11:58:57 +02:00
struct ospf_config *cf = (struct ospf_config *) (p->p.cf);
2009-08-21 09:27:52 +02:00
struct ospf_iface *ifa;
struct ospf_lsa_prefix *lp;
uint max = ospf_is_ip4(p) ? IP4_MAX_PREFIX_LENGTH : IP6_MAX_PREFIX_LENGTH;
int host_addr = 0;
2009-08-21 09:27:52 +02:00
int net_lsa;
int i = 0;
2014-06-26 11:58:57 +02:00
ASSERT(p->lsab_used == 0);
lp = lsab_allocz(p, sizeof(struct ospf_lsa_prefix));
2009-08-21 09:27:52 +02:00
lp->ref_type = LSA_T_RT;
lp->ref_id = 0;
2014-06-26 11:58:57 +02:00
lp->ref_rt = p->router_id;
2009-08-21 09:27:52 +02:00
lp = NULL; /* buffer might be reallocated later */
2014-06-26 11:58:57 +02:00
WALK_LIST(ifa, p->iface_list)
2009-08-21 09:27:52 +02:00
{
if ((ifa->oa != oa) || (ifa->type == OSPF_IT_VLINK) || (ifa->state == OSPF_IS_DOWN))
2009-08-21 09:27:52 +02:00
continue;
ifa->px_pos_beg = i;
2009-08-21 09:27:52 +02:00
if ((ifa->type == OSPF_IT_BCAST) ||
(ifa->type == OSPF_IT_NBMA))
net_lsa = bcast_net_active(ifa);
else
net_lsa = 0;
struct ifa *a;
WALK_LIST(a, ifa->iface->addrs)
2014-06-26 11:58:57 +02:00
{
2017-10-09 01:16:29 +02:00
if ((a->prefix.type != ospf_get_af(p)) ||
2015-11-12 02:03:59 +01:00
(a->flags & IA_SECONDARY) ||
2014-06-26 11:58:57 +02:00
(a->flags & IA_PEER) ||
(a->scope <= SCOPE_LINK))
continue;
if (((a->prefix.pxlen < max) && net_lsa) ||
2014-06-26 11:58:57 +02:00
configured_stubnet(oa, a))
continue;
2009-08-21 09:27:52 +02:00
2014-06-26 11:58:57 +02:00
if ((a->flags & IA_HOST) ||
(ifa->state == OSPF_IS_LOOP) ||
(ifa->type == OSPF_IT_PTMP))
{
net_addr net;
if (a->prefix.type == NET_IP4)
net_fill_ip4(&net, ipa_to_ip4(a->ip), IP4_MAX_PREFIX_LENGTH);
else
net_fill_ip6(&net, ipa_to_ip6(a->ip), IP6_MAX_PREFIX_LENGTH);
lsab_put_prefix(p, &net, 0);
2014-06-26 11:58:57 +02:00
host_addr = 1;
2009-08-21 09:27:52 +02:00
}
2014-06-26 11:58:57 +02:00
else
2015-11-12 02:03:59 +01:00
lsab_put_prefix(p, &a->prefix, ifa->cost);
2014-06-26 11:58:57 +02:00
i++;
}
ifa->px_pos_end = i;
2009-08-21 09:27:52 +02:00
}
struct ospf_stubnet_config *sn;
2014-06-26 11:58:57 +02:00
WALK_LIST(sn, oa->ac->stubnet_list)
if (!sn->hidden)
{
2015-11-12 02:03:59 +01:00
lsab_put_prefix(p, &sn->prefix, sn->cost);
if (sn->prefix.pxlen == max)
2014-06-26 11:58:57 +02:00
host_addr = 1;
i++;
}
/* If there are some configured vlinks, find some global address
(even from another area), which will be used as a vlink endpoint. */
2017-10-09 01:16:29 +02:00
if (!EMPTY_LIST(cf->vlink_list) && !host_addr && ospf_is_ip6(p))
{
2014-06-26 11:58:57 +02:00
WALK_LIST(ifa, p->iface_list)
{
if ((ifa->type == OSPF_IT_VLINK) || (ifa->state == OSPF_IS_DOWN))
continue;
struct ifa *a;
WALK_LIST(a, ifa->iface->addrs)
{
2015-11-12 02:03:59 +01:00
if ((a->prefix.type != NET_IP6) ||
(a->flags & IA_SECONDARY) ||
(a->scope <= SCOPE_LINK))
continue;
/* Found some IP */
2015-11-12 02:03:59 +01:00
net_addr_ip6 net = NET_ADDR_IP6(a->ip, IP6_MAX_PREFIX_LENGTH);
lsab_put_prefix(p, (net_addr *) &net, 0);
2009-08-21 09:27:52 +02:00
i++;
goto done;
2009-08-21 09:27:52 +02:00
}
}
}
2009-08-21 09:27:52 +02:00
done:
2014-06-26 11:58:57 +02:00
lp = p->lsab;
2009-08-21 09:27:52 +02:00
lp->pxcount = i;
}
2014-06-26 11:58:57 +02:00
static void
ospf_originate_prefix_rt_lsa(struct ospf_proto *p, struct ospf_area *oa)
2009-08-21 09:27:52 +02:00
{
2014-06-26 11:58:57 +02:00
if (ospf_is_v2(p))
return;
2009-08-21 09:27:52 +02:00
2014-06-26 11:58:57 +02:00
struct ospf_new_lsa lsa = {
.type = LSA_T_PREFIX,
.dom = oa->areaid,
.id = 0
};
2009-09-08 13:45:02 +02:00
2014-06-26 11:58:57 +02:00
prepare_prefix_rt_lsa_body(p, oa);
2009-08-21 09:27:52 +02:00
2014-06-26 11:58:57 +02:00
ospf_originate_lsa(p, &lsa);
2009-08-21 09:27:52 +02:00
}
2014-06-26 11:58:57 +02:00
/*
* Prefix-Net-LSA handling (assume OSPFv3)
* Type = LSA_T_PREFIX, referred type = LSA_T_NET
*/
2009-08-21 09:27:52 +02:00
static inline int
prefix_space(u32 *buf)
{
int pxl = *buf >> 24;
return IPV6_PREFIX_SPACE(pxl);
}
static inline int
prefix_same(u32 *b1, u32 *b2)
{
int pxl1 = *b1 >> 24;
int pxl2 = *b2 >> 24;
int pxs, i;
2014-07-19 17:28:38 +02:00
2009-08-21 09:27:52 +02:00
if (pxl1 != pxl2)
return 0;
pxs = IPV6_PREFIX_WORDS(pxl1);
for (i = 1; i < pxs; i++)
if (b1[i] != b2[i])
return 0;
return 1;
}
static inline u32 *
prefix_advance(u32 *buf)
{
2009-09-08 13:45:02 +02:00
int pxl = *buf >> 24;
return buf + IPV6_PREFIX_WORDS(pxl);
2009-08-21 09:27:52 +02:00
}
2011-09-03 21:31:26 +02:00
/* FIXME eliminate items with LA bit set? see 4.4.3.9 */
2009-08-21 09:27:52 +02:00
static void
2014-06-26 11:58:57 +02:00
add_prefix(struct ospf_proto *p, u32 *px, int offset, int *pxc)
2009-08-21 09:27:52 +02:00
{
2014-06-26 11:58:57 +02:00
u32 *pxl = lsab_offset(p, offset);
2009-08-21 09:27:52 +02:00
int i;
for (i = 0; i < *pxc; pxl = prefix_advance(pxl), i++)
if (prefix_same(px, pxl))
2009-08-21 09:27:52 +02:00
{
/* Options should be logically OR'ed together */
*pxl |= (*px & 0x00FF0000);
return;
2009-08-21 09:27:52 +02:00
}
2014-06-26 11:58:57 +02:00
ASSERT(pxl == lsab_end(p));
2009-08-21 09:27:52 +02:00
int pxspace = prefix_space(px);
2014-06-26 11:58:57 +02:00
pxl = lsab_alloc(p, pxspace);
2009-08-21 09:27:52 +02:00
memcpy(pxl, px, pxspace);
*pxl &= 0xFFFF0000; /* Set metric to zero */
2009-08-21 09:27:52 +02:00
(*pxc)++;
}
2009-09-08 13:45:02 +02:00
static void
2014-06-26 11:58:57 +02:00
add_link_lsa(struct ospf_proto *p, struct ospf_lsa_link *ll, int offset, int *pxc)
2009-09-08 13:45:02 +02:00
{
u32 *pxb = ll->rest;
uint j;
2009-09-08 13:45:02 +02:00
for (j = 0; j < ll->pxcount; pxb = prefix_advance(pxb), j++)
{
u8 pxlen = (pxb[0] >> 24);
u8 pxopts = (pxb[0] >> 16);
/* Skip NU or LA prefixes */
if (pxopts & (OPT_PX_NU | OPT_PX_LA))
continue;
/* Skip link-local prefixes */
2017-10-09 01:16:29 +02:00
if (ospf_is_ip6(p) && (pxlen >= 10) && ((pxb[1] & 0xffc00000) == 0xfe800000))
continue;
2014-06-26 11:58:57 +02:00
add_prefix(p, pxb, offset, pxc);
}
2009-09-08 13:45:02 +02:00
}
2014-06-26 11:58:57 +02:00
static void
prepare_prefix_net_lsa_body(struct ospf_proto *p, struct ospf_iface *ifa)
2009-08-21 09:27:52 +02:00
{
struct ospf_lsa_prefix *lp;
struct ospf_neighbor *n;
struct top_hash_entry *en;
2009-09-08 13:45:02 +02:00
int pxc, offset;
2009-08-21 09:27:52 +02:00
2014-06-26 11:58:57 +02:00
ASSERT(p->lsab_used == 0);
lp = lsab_allocz(p, sizeof(struct ospf_lsa_prefix));
2009-08-21 09:27:52 +02:00
lp->ref_type = LSA_T_NET;
lp->ref_id = ifa->net_lsa->lsa.id;
2014-06-26 11:58:57 +02:00
lp->ref_rt = p->router_id;
2009-08-21 09:27:52 +02:00
lp = NULL; /* buffer might be reallocated later */
2009-09-08 13:45:02 +02:00
pxc = 0;
2014-06-26 11:58:57 +02:00
offset = p->lsab_used;
2009-08-21 09:27:52 +02:00
2009-09-08 13:45:02 +02:00
/* Find all Link LSAs associated with the link and merge their prefixes */
2014-06-26 11:58:57 +02:00
if (en = ifa->link_lsa)
add_link_lsa(p, en->next_lsa_body ?: en->lsa_body, offset, &pxc);
2009-09-08 13:45:02 +02:00
2009-08-21 09:27:52 +02:00
WALK_LIST(n, ifa->neigh_list)
if ((n->state == NEIGHBOR_FULL) &&
2014-07-19 17:28:38 +02:00
(en = ospf_hash_find(p->gr, ifa->iface_id, n->iface_id, n->rid, LSA_T_LINK)))
2014-06-26 11:58:57 +02:00
add_link_lsa(p, en->lsa_body, offset, &pxc);
2009-08-21 09:27:52 +02:00
2014-06-26 11:58:57 +02:00
lp = p->lsab;
2009-09-08 13:45:02 +02:00
lp->pxcount = pxc;
2009-08-21 09:27:52 +02:00
}
2014-06-26 11:58:57 +02:00
static void
ospf_originate_prefix_net_lsa(struct ospf_proto *p, struct ospf_iface *ifa)
2009-08-21 09:27:52 +02:00
{
2014-06-26 11:58:57 +02:00
if (ospf_is_v2(p))
return;
2009-08-21 09:27:52 +02:00
2014-06-26 11:58:57 +02:00
struct ospf_new_lsa lsa = {
.type = LSA_T_PREFIX,
.dom = ifa->oa->areaid,
.id = ifa->iface_id,
.ifa = ifa
};
2009-09-08 13:45:02 +02:00
2014-06-26 11:58:57 +02:00
prepare_prefix_net_lsa_body(p, ifa);
2009-08-21 09:27:52 +02:00
2014-06-26 11:58:57 +02:00
ifa->pxn_lsa = ospf_originate_lsa(p, &lsa);
2009-08-21 09:27:52 +02:00
}
2019-06-30 20:12:59 +02:00
/*
* Grace LSA handling
* Type = LSA_T_GR, opaque type = LSA_OT_GR
*/
static inline void
ospf_add_gr_period_tlv(struct ospf_proto *p, uint period)
{
struct ospf_tlv *tlv = lsab_allocz(p, sizeof(struct ospf_tlv) + sizeof(u32));
tlv->type = LSA_GR_PERIOD;
tlv->length = 4;
tlv->data[0] = period;
}
static inline void
ospf_add_gr_reason_tlv(struct ospf_proto *p, uint reason)
{
struct ospf_tlv *tlv = lsab_allocz(p, sizeof(struct ospf_tlv) + sizeof(u32));
tlv->type = LSA_GR_REASON;
tlv->length = 1;
tlv->data[0] = reason << 24;
}
static inline void
ospf_add_gr_address_tlv(struct ospf_proto *p, ip4_addr addr)
{
struct ospf_tlv *tlv = lsab_allocz(p, sizeof(struct ospf_tlv) + sizeof(u32));
tlv->type = LSA_GR_ADDRESS;
tlv->length = 4;
tlv->data[0] = ip4_to_u32(addr);
}
void
ospf_originate_gr_lsa(struct ospf_proto *p, struct ospf_iface *ifa)
{
struct ospf_new_lsa lsa = {
.type = LSA_T_GR,
.dom = ifa->iface_id,
.id = ospf_is_v2(p) ? 0 : ifa->iface_id,
.ifa = ifa
};
ospf_add_gr_period_tlv(p, p->gr_time);
ospf_add_gr_reason_tlv(p, 0);
uint t = ifa->type;
if (ospf_is_v2(p) && ((t == OSPF_IT_BCAST) || (t == OSPF_IT_NBMA) || (t == OSPF_IT_PTMP)))
ospf_add_gr_address_tlv(p, ipa_to_ip4(ifa->addr->ip));
ospf_originate_lsa(p, &lsa);
}
/*
* Router Information LSA handling
* Type = LSA_T_RI_AREA, opaque type = LSA_OT_RI
*/
void
ospf_add_ric_tlv(struct ospf_proto *p)
{
struct ospf_tlv *ri = lsab_allocz(p, sizeof(struct ospf_tlv) + sizeof(u32));
ri->type = LSA_RI_RIC;
ri->length = sizeof(struct ospf_tlv) + sizeof(u32);
BIT32R_SET(ri->data, LSA_RIC_STUB_ROUTER);
}
void
ospf_originate_ri_lsa(struct ospf_proto *p, struct ospf_area *oa)
{
struct ospf_new_lsa lsa = {
.type = LSA_T_RI_AREA,
.dom = oa->areaid,
.id = p->instance_id
};
ospf_add_ric_tlv(p);
ospf_originate_lsa(p, &lsa);
}
/*
* Generic topology code
*/
2014-07-18 18:24:12 +02:00
static inline int breaks_minlsinterval(struct top_hash_entry *en)
2017-06-20 18:03:06 +02:00
{ return en && (en->lsa.age < LSA_MAXAGE) && (lsa_inst_age(en) < MINLSINTERVAL); }
2014-06-26 11:58:57 +02:00
2009-08-27 18:25:46 +02:00
void
2014-06-26 11:58:57 +02:00
ospf_update_topology(struct ospf_proto *p)
2009-08-27 18:25:46 +02:00
{
2014-06-26 11:58:57 +02:00
struct ospf_area *oa;
struct ospf_iface *ifa;
2009-08-27 18:25:46 +02:00
2019-06-30 20:12:59 +02:00
/* No LSA reorigination during GR recovery */
if (p->gr_recovery)
return;
2014-06-26 11:58:57 +02:00
WALK_LIST(oa, p->area_list)
{
if (oa->update_rt_lsa)
{
2014-07-18 18:24:12 +02:00
/*
* 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;
2014-06-26 11:58:57 +02:00
ospf_originate_rt_lsa(p, oa);
ospf_originate_prefix_rt_lsa(p, oa);
// ospf_originate_ri_lsa(p, oa);
2014-06-26 11:58:57 +02:00
oa->update_rt_lsa = 0;
}
}
2009-08-27 18:25:46 +02:00
2014-06-26 11:58:57 +02:00
WALK_LIST(ifa, p->iface_list)
{
if (ifa->type == OSPF_IT_VLINK)
continue;
2009-09-08 13:45:02 +02:00
2014-06-26 11:58:57 +02:00
if (ifa->update_link_lsa)
{
if ((ifa->state > OSPF_IS_LOOP) && !ifa->link_lsa_suppression)
ospf_originate_link_lsa(p, ifa);
else
ospf_flush2_lsa(p, &ifa->link_lsa);
2009-08-27 18:25:46 +02:00
2014-06-26 11:58:57 +02:00
ifa->update_link_lsa = 0;
}
2009-08-27 18:25:46 +02:00
2014-06-26 11:58:57 +02:00
if (ifa->update_net_lsa)
{
if ((ifa->state == OSPF_IS_DR) && (ifa->fadj > 0))
{
ospf_originate_net_lsa(p, ifa);
ospf_originate_prefix_net_lsa(p, ifa);
}
else
{
ospf_flush2_lsa(p, &ifa->net_lsa);
ospf_flush2_lsa(p, &ifa->pxn_lsa);
}
ifa->update_net_lsa = 0;
}
}
}
2000-05-27 14:17:35 +00:00
2009-08-25 16:42:14 +02:00
static void
ospf_top_ht_alloc(struct top_graph *f)
{
f->hash_size = 1 << f->hash_order;
f->hash_mask = f->hash_size - 1;
if (f->hash_order > HASH_HI_MAX - HASH_HI_STEP)
f->hash_entries_max = ~0;
else
f->hash_entries_max = f->hash_size HASH_HI_MARK;
if (f->hash_order < HASH_LO_MIN + HASH_LO_STEP)
f->hash_entries_min = 0;
else
f->hash_entries_min = f->hash_size HASH_LO_MARK;
DBG("Allocating OSPF hash of order %d: %d hash_entries, %d low, %d high\n",
f->hash_order, f->hash_size, f->hash_entries_min, f->hash_entries_max);
2004-06-06 08:55:33 +00:00
f->hash_table =
mb_alloc(f->pool, f->hash_size * sizeof(struct top_hash_entry *));
bzero(f->hash_table, f->hash_size * sizeof(struct top_hash_entry *));
}
static inline void
ospf_top_ht_free(struct top_hash_entry **h)
{
mb_free(h);
}
static inline u32
ospf_top_hash_u32(u32 a)
{
/* Shamelessly stolen from IP address hashing in ipv4.h */
a ^= a >> 16;
a ^= a << 10;
return a;
}
2014-07-18 18:24:12 +02:00
static uint
2009-08-21 09:27:52 +02:00
ospf_top_hash(struct top_graph *f, u32 domain, u32 lsaid, u32 rtrid, u32 type)
{
2009-09-08 13:45:02 +02:00
/* In OSPFv2, we don't know Router ID when looking for network LSAs.
2009-09-17 12:18:03 +02:00
In OSPFv3, we don't know LSA ID when looking for router LSAs.
In both cases, there is (usually) just one (or small number)
appropriate LSA, so we just clear unknown part of key. */
2009-08-21 09:27:52 +02:00
2014-06-26 11:58:57 +02:00
return (((f->ospf2 && (type == LSA_T_NET)) ? 0 : ospf_top_hash_u32(rtrid)) +
((!f->ospf2 && (type == LSA_T_RT)) ? 0 : ospf_top_hash_u32(lsaid)) +
2009-09-17 12:18:03 +02:00
type + domain) & f->hash_mask;
2009-08-21 09:27:52 +02:00
/*
2004-06-06 08:55:33 +00:00
return (ospf_top_hash_u32(lsaid) + ospf_top_hash_u32(rtrid) +
type + areaid) & f->hash_mask;
2009-08-21 09:27:52 +02:00
*/
}
/**
* ospf_top_new - allocated new topology database
2014-06-26 11:58:57 +02:00
* @p: OSPF protocol instance
2014-07-18 18:24:12 +02:00
* @pool: pool for allocation
*
2014-07-18 18:24:12 +02:00
* This dynamically hashed structure is used for keeping LSAs. Mainly it is used
* for the LSA database of the OSPF protocol, but also for LSA retransmission
* and request lists of OSPF neighbors.
*/
struct top_graph *
2014-07-18 18:24:12 +02:00
ospf_top_new(struct ospf_proto *p, pool *pool)
{
struct top_graph *f;
f = mb_allocz(pool, sizeof(struct top_graph));
f->pool = pool;
f->hash_slab = sl_new(f->pool, sizeof(struct top_hash_entry));
f->hash_order = HASH_DEF_ORDER;
ospf_top_ht_alloc(f);
f->hash_entries = 0;
f->hash_entries_min = 0;
2014-07-18 18:24:12 +02:00
f->ospf2 = ospf_is_v2(p);
return f;
}
void
ospf_top_free(struct top_graph *f)
{
rfree(f->hash_slab);
ospf_top_ht_free(f->hash_table);
mb_free(f);
}
static void
ospf_top_rehash(struct top_graph *f, int step)
{
struct top_hash_entry **n, **oldt, **newt, *e, *x;
2014-07-18 18:24:12 +02:00
uint oldn, oldh;
oldn = f->hash_size;
oldt = f->hash_table;
2009-08-25 16:42:14 +02:00
DBG("re-hashing topology hash from order %d to %d\n", f->hash_order,
2004-06-06 08:55:33 +00:00
f->hash_order + step);
f->hash_order += step;
ospf_top_ht_alloc(f);
newt = f->hash_table;
2004-06-06 08:55:33 +00:00
for (oldh = 0; oldh < oldn; oldh++)
{
e = oldt[oldh];
while (e)
{
2004-06-06 08:55:33 +00:00
x = e->next;
2014-06-26 11:58:57 +02:00
n = newt + ospf_top_hash(f, e->domain, e->lsa.id, e->lsa.rt, e->lsa_type);
2004-06-06 08:55:33 +00:00
e->next = *n;
*n = e;
e = x;
}
2004-06-06 08:55:33 +00:00
}
ospf_top_ht_free(oldt);
}
2014-11-03 10:42:55 +01:00
static struct top_hash_entry *
ospf_hash_find_(struct top_graph *f, u32 domain, u32 lsa, u32 rtr, u32 type)
{
struct top_hash_entry *e;
2009-08-21 09:27:52 +02:00
e = f->hash_table[ospf_top_hash(f, domain, lsa, rtr, type)];
2014-06-26 11:58:57 +02:00
while (e && (e->lsa.id != lsa || e->lsa.rt != rtr ||
e->lsa_type != type || e->domain != domain))
2009-09-17 12:18:03 +02:00
e = e->next;
2014-11-03 10:42:55 +01:00
return e;
}
struct top_hash_entry *
ospf_hash_find(struct top_graph *f, u32 domain, u32 lsa, u32 rtr, u32 type)
{
struct top_hash_entry *e = ospf_hash_find_(f, domain, lsa, rtr, type);
2014-06-26 11:58:57 +02:00
/* Hide hash entry with empty lsa_body */
2014-07-18 18:24:12 +02:00
return (e && e->lsa_body) ? e : NULL;
2009-09-17 12:18:03 +02:00
}
2014-06-26 11:58:57 +02:00
/* In OSPFv2, lsa.id is the same as lsa.rt for router LSA. In OSPFv3, we don't know
lsa.id when looking for router LSAs. We return matching LSA with smallest lsa.id. */
2009-09-17 12:18:03 +02:00
struct top_hash_entry *
ospf_hash_find_rt(struct top_graph *f, u32 domain, u32 rtr)
{
struct top_hash_entry *rv = NULL;
struct top_hash_entry *e;
2014-06-26 11:58:57 +02:00
/* We can put rtr for lsa.id to hash fn, it is ignored in OSPFv3 */
e = f->hash_table[ospf_top_hash(f, domain, rtr, rtr, LSA_T_RT)];
2009-09-17 12:18:03 +02:00
while (e)
2014-06-26 11:58:57 +02:00
{
if (e->lsa.rt == rtr && e->lsa_type == LSA_T_RT && e->domain == domain && e->lsa_body)
2009-09-17 12:18:03 +02:00
{
2014-06-26 11:58:57 +02:00
if (f->ospf2 && (e->lsa.id == rtr))
return e;
if (!f->ospf2 && (!rv || e->lsa.id < rv->lsa.id))
rv = e;
2009-09-17 12:18:03 +02:00
}
2014-06-26 11:58:57 +02:00
e = e->next;
}
2009-09-17 12:18:03 +02:00
return rv;
}
2014-07-18 18:24:12 +02:00
/*
* 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.
*/
2009-09-17 12:18:03 +02:00
static inline struct top_hash_entry *
2014-06-26 11:58:57 +02:00
find_matching_rt3(struct top_hash_entry *e, u32 domain, u32 rtr)
2009-09-17 12:18:03 +02:00
{
2014-06-26 11:58:57 +02:00
while (e && (e->lsa.rt != rtr || e->lsa_type != LSA_T_RT ||
2014-07-18 18:24:12 +02:00
e->domain != domain || e->lsa.age == LSA_MAXAGE))
2009-09-17 12:18:03 +02:00
e = e->next;
return e;
}
2009-09-17 12:18:03 +02:00
struct top_hash_entry *
2014-06-26 11:58:57 +02:00
ospf_hash_find_rt3_first(struct top_graph *f, u32 domain, u32 rtr)
2009-09-17 12:18:03 +02:00
{
struct top_hash_entry *e;
e = f->hash_table[ospf_top_hash(f, domain, 0, rtr, LSA_T_RT)];
2014-06-26 11:58:57 +02:00
return find_matching_rt3(e, domain, rtr);
2009-09-17 12:18:03 +02:00
}
struct top_hash_entry *
2014-06-26 11:58:57 +02:00
ospf_hash_find_rt3_next(struct top_hash_entry *e)
2009-09-17 12:18:03 +02:00
{
2014-06-26 11:58:57 +02:00
return find_matching_rt3(e->next, e->domain, e->lsa.rt);
2009-09-17 12:18:03 +02:00
}
2014-06-26 11:58:57 +02:00
/* In OSPFv2, we don't know Router ID when looking for network LSAs.
There should be just one, so we find any match. */
struct top_hash_entry *
ospf_hash_find_net2(struct top_graph *f, u32 domain, u32 id)
{
struct top_hash_entry *e;
e = f->hash_table[ospf_top_hash(f, domain, id, 0, LSA_T_NET)];
while (e && (e->lsa.id != id || e->lsa_type != LSA_T_NET ||
e->domain != domain || e->lsa_body == NULL))
e = e->next;
return e;
}
2009-09-17 12:18:03 +02:00
struct top_hash_entry *
2009-08-25 16:42:14 +02:00
ospf_hash_get(struct top_graph *f, u32 domain, u32 lsa, u32 rtr, u32 type)
{
struct top_hash_entry **ee;
struct top_hash_entry *e;
2009-08-21 09:27:52 +02:00
ee = f->hash_table + ospf_top_hash(f, domain, lsa, rtr, type);
e = *ee;
2014-07-19 17:28:38 +02:00
while (e && (e->lsa.id != lsa || e->lsa.rt != rtr ||
2014-06-26 11:58:57 +02:00
e->lsa_type != type || e->domain != domain))
2009-08-21 09:27:52 +02:00
e = e->next;
if (e)
return e;
2004-06-06 16:14:57 +00:00
2020-11-24 03:21:44 +01:00
e = sl_allocz(f->hash_slab);
2004-06-06 16:14:57 +00:00
e->color = OUTSPF;
e->dist = LSINFINITY;
2014-06-26 11:58:57 +02:00
e->lsa.type_raw = type;
e->lsa.id = lsa;
e->lsa.rt = rtr;
2014-06-26 11:58:57 +02:00
e->lsa.sn = LSA_ZEROSEQNO;
e->lsa_type = type;
2009-08-21 09:27:52 +02:00
e->domain = domain;
2004-06-06 16:14:57 +00:00
e->next = *ee;
2004-06-06 08:55:33 +00:00
*ee = e;
if (f->hash_entries++ > f->hash_entries_max)
ospf_top_rehash(f, HASH_HI_STEP);
return e;
}
void
ospf_hash_delete(struct top_graph *f, struct top_hash_entry *e)
{
2014-07-19 17:28:38 +02:00
struct top_hash_entry **ee = f->hash_table +
2014-06-26 11:58:57 +02:00
ospf_top_hash(f, e->domain, e->lsa.id, e->lsa.rt, e->lsa_type);
while (*ee)
2004-06-06 08:55:33 +00:00
{
if (*ee == e)
{
2004-06-06 08:55:33 +00:00
*ee = e->next;
sl_free(e);
2004-06-06 08:55:33 +00:00
if (f->hash_entries-- < f->hash_entries_min)
ospf_top_rehash(f, -HASH_LO_STEP);
return;
}
2004-06-06 08:55:33 +00:00
ee = &((*ee)->next);
}
bug("ospf_hash_delete() called for invalid node");
}
/*
2008-08-25 12:51:06 +00:00
static void
ospf_dump_lsa(struct top_hash_entry *he, struct proto *p)
{
2008-08-25 12:51:06 +00:00
struct ospf_lsa_rt *rt = NULL;
struct ospf_lsa_rt_link *rr = NULL;
struct ospf_lsa_net *ln = NULL;
u32 *rts = NULL;
u32 i, max;
2009-07-23 16:51:28 +02:00
OSPF_TRACE(D_EVENTS, "- %1x %-1R %-1R %4u 0x%08x 0x%04x %-1R",
he->lsa.type, he->lsa.id, he->lsa.rt, he->lsa.age, he->lsa.sn,
2009-08-21 09:27:52 +02:00
he->lsa.checksum, he->domain);
2008-08-25 12:51:06 +00:00
2009-08-25 16:42:14 +02:00
2008-08-25 12:51:06 +00:00
switch (he->lsa.type)
{
case LSA_T_RT:
rt = he->lsa_body;
rr = (struct ospf_lsa_rt_link *) (rt + 1);
2009-08-21 09:27:52 +02:00
for (i = 0; i < lsa_rt_items(&he->lsa); i++)
2014-07-19 17:28:38 +02:00
OSPF_TRACE(D_EVENTS, " - %1x %-1R %-1R %5u",
2009-07-23 16:51:28 +02:00
rr[i].type, rr[i].id, rr[i].data, rr[i].metric);
2008-08-25 12:51:06 +00:00
break;
case LSA_T_NET:
ln = he->lsa_body;
rts = (u32 *) (ln + 1);
2009-08-21 09:27:52 +02:00
for (i = 0; i < lsa_net_items(&he->lsa); i++)
2014-07-19 17:28:38 +02:00
OSPF_TRACE(D_EVENTS, " - %-1R", rts[i]);
2008-08-25 12:51:06 +00:00
break;
default:
break;
}
}
void
2000-06-06 02:27:08 +00:00
ospf_top_dump(struct top_graph *f, struct proto *p)
{
2014-07-18 18:24:12 +02:00
uint i;
2000-06-06 02:27:08 +00:00
OSPF_TRACE(D_EVENTS, "Hash entries: %d", f->hash_entries);
2004-06-06 08:55:33 +00:00
for (i = 0; i < f->hash_size; i++)
{
2008-08-25 12:51:06 +00:00
struct top_hash_entry *e;
for (e = f->hash_table[i]; e != NULL; e = e->next)
ospf_dump_lsa(e, p);
2004-06-06 08:55:33 +00:00
}
}
*/