summaryrefslogtreecommitdiff
path: root/proto
diff options
context:
space:
mode:
authorOndrej Zajicek <santiago@crfreenet.org>2011-08-08 01:45:31 +0200
committerOndrej Zajicek <santiago@crfreenet.org>2011-08-08 01:45:31 +0200
commited317862c2958303cf541fe63f4ea26d00918a9a (patch)
tree2dd59479e17a3f6107f5e77d459942fe53991ecb /proto
parentaca0e79faa391a2841134dac78a499dfdca68bd9 (diff)
OSPF NSSA support, inter-area LSA translation.
Diffstat (limited to 'proto')
-rw-r--r--proto/ospf/config.Y33
-rw-r--r--proto/ospf/ospf.c73
-rw-r--r--proto/ospf/ospf.h5
-rw-r--r--proto/ospf/rt.c242
-rw-r--r--proto/ospf/rt.h19
-rw-r--r--proto/ospf/topology.c46
-rw-r--r--proto/ospf/topology.h5
7 files changed, 328 insertions, 95 deletions
diff --git a/proto/ospf/config.Y b/proto/ospf/config.Y
index 1099b729..e48f4602 100644
--- a/proto/ospf/config.Y
+++ b/proto/ospf/config.Y
@@ -17,6 +17,7 @@ CF_DEFINES
static struct ospf_area_config *this_area;
static struct nbma_node *this_nbma;
+static list *this_nets;
static struct area_net_config *this_pref;
static struct ospf_stubnet_config *this_stubnet;
@@ -85,6 +86,7 @@ ospf_proto_finish(void)
add_head(&cf->area_list, NODE ac);
init_list(&ac->patt_list);
init_list(&ac->net_list);
+ init_list(&ac->enet_list);
init_list(&ac->stubnet_list);
}
@@ -100,7 +102,7 @@ CF_KEYWORDS(HELLO, TRANSMIT, PRIORITY, DEAD, TYPE, BROADCAST, BCAST)
CF_KEYWORDS(NONBROADCAST, NBMA, POINTOPOINT, PTP, POINTOMULTIPOINT, PTMP)
CF_KEYWORDS(NONE, SIMPLE, AUTHENTICATION, STRICT, CRYPTOGRAPHIC)
CF_KEYWORDS(ELIGIBLE, POLL, NETWORKS, HIDDEN, VIRTUAL, CHECK, LINK)
-CF_KEYWORDS(RX, BUFFER, LARGE, NORMAL, STUBNET, HIDDEN, SUMMARY)
+CF_KEYWORDS(RX, BUFFER, LARGE, NORMAL, STUBNET, HIDDEN, SUMMARY, TAG, EXTERNAL)
CF_KEYWORDS(WAIT, DELAY, LSADB, ECMP, LIMIT, WEIGHT, NSSA, TRANSLATOR, STABILITY)
%type <t> opttext
@@ -139,9 +141,11 @@ ospf_area_start: AREA idval {
this_area->areaid = $2;
this_area->stub_cost = DEFAULT_STUB_COST;
this_area->type = OPT_E;
+ this_area->transint = DEFAULT_TRANSINT;
init_list(&this_area->patt_list);
init_list(&this_area->net_list);
+ init_list(&this_area->enet_list);
init_list(&this_area->stubnet_list);
}
;
@@ -160,8 +164,9 @@ ospf_area_item:
| NSSA { this_area->type = OPT_N; }
| SUMMARY bool { this_area->summary = $2; }
| TRANSLATOR bool { this_area->translator = $2; }
- | TRANSLATOR STABILITY bool { this_area->transint = $3; }
- | NETWORKS '{' pref_list '}'
+ | TRANSLATOR STABILITY expr { this_area->transint = $3; }
+ | NETWORKS { this_nets = &this_area->net_list; } '{' pref_list '}'
+ | EXTERNAL { this_nets = &this_area->enet_list; } '{' pref_list '}'
| STUBNET ospf_stubnet
| INTERFACE ospf_iface
| ospf_vlink
@@ -273,28 +278,22 @@ pref_list:
| pref_list pref_item
;
-pref_item:
- pref_el
- | pref_hid;
+pref_item: pref_base pref_opt ';' ;
-pref_el: prefix ';'
+pref_base: prefix
{
this_pref = cfg_allocz(sizeof(struct area_net_config));
- add_tail(&this_area->net_list, NODE this_pref);
+ add_tail(this_nets, NODE this_pref);
this_pref->px.addr = $1.addr;
this_pref->px.len = $1.len;
}
;
-pref_hid: prefix HIDDEN ';'
- {
- this_pref = cfg_allocz(sizeof(struct area_net_config));
- add_tail(&this_area->net_list, NODE this_pref);
- this_pref->px.addr = $1.addr;
- this_pref->px.len = $1.len;
- this_pref->hidden = 1;
- }
-;
+pref_opt:
+ /* empty */
+ | HIDDEN { this_pref->hidden = 1; }
+ | TAG expr { this_pref->tag = $2; }
+ ;
ipa_list:
/* empty */
diff --git a/proto/ospf/ospf.c b/proto/ospf/ospf.c
index 83bcad75..ed49a599 100644
--- a/proto/ospf/ospf.c
+++ b/proto/ospf/ospf.c
@@ -126,11 +126,19 @@ add_area_nets(struct ospf_area *oa, struct ospf_area_config *ac)
struct area_net *an;
fib_init(&oa->net_fib, po->proto.pool, sizeof(struct area_net), 0, ospf_area_initfib);
+ fib_init(&oa->enet_fib, po->proto.pool, sizeof(struct area_net), 0, ospf_area_initfib);
WALK_LIST(anc, ac->net_list)
{
an = (struct area_net *) fib_get(&oa->net_fib, &anc->px.addr, anc->px.len);
- an->hidden = an->hidden;
+ an->hidden = anc->hidden;
+ }
+
+ WALK_LIST(anc, ac->enet_list)
+ {
+ an = (struct area_net *) fib_get(&oa->enet_fib, &anc->px.addr, anc->px.len);
+ an->hidden = anc->hidden;
+ an->tag = anc->tag;
}
}
@@ -177,6 +185,7 @@ ospf_area_remove(struct ospf_area *oa)
fib_free(&oa->rtr);
fib_free(&oa->net_fib);
+ fib_free(&oa->enet_fib);
if (oa->translator_timer)
rfree(oa->translator_timer);
@@ -550,16 +559,35 @@ ospf_rt_notify(struct proto *p, rtable *tbl UNUSED, net * n, rte * new, rte * ol
{
struct proto_ospf *po = (struct proto_ospf *) p;
struct ospf_area *oa = ospf_main_area(po);
+ ort *nf = (ort *) fib_get(&po->rtf, &n->n.prefix, n->n.pxlen);
+ struct fib_node *fn = &nf->fn;
-/* Temporarily down write anything
- OSPF_TRACE(D_EVENTS, "Got route %I/%d %s", p->name, n->n.prefix,
- n->n.pxlen, new ? "up" : "down");
-*/
+ if (!new)
+ {
+ if (fn->x1 != EXT_EXPORT)
+ return;
- if (new) /* Got some new route */
- originate_ext_lsa(oa, n, new, attrs);
- else
- flush_ext_lsa(oa, n);
+ flush_ext_lsa(oa, fn);
+
+ /* Old external route might blocked some NSSA translation */
+ if (po->areano > 1)
+ schedule_rtcalc(po);
+ }
+
+ /* Get route attributes */
+ u32 m1 = ea_get_int(attrs, EA_OSPF_METRIC1, LSINFINITY);
+ u32 m2 = ea_get_int(attrs, EA_OSPF_METRIC2, 10000);
+ u32 metric = (m1 != LSINFINITY) ? m1 : (m2 | LSA_EXT_EBIT);
+ u32 tag = ea_get_int(attrs, EA_OSPF_TAG, 0);
+ ip_addr gw = IPA_NONE;
+ // FIXME check for gw should be per ifa, not per iface
+ if ((new->attrs->dest == RTD_ROUTER) &&
+ ipa_nonzero(new->attrs->gw) &&
+ !ipa_has_link_scope(new->attrs->gw) &&
+ (ospf_iface_find((struct proto_ospf *) p, new->attrs->iface) != NULL))
+ gw = new->attrs->gw;
+
+ originate_ext_lsa(oa, fn, EXT_EXPORT, metric, gw, tag);
}
static void
@@ -652,6 +680,7 @@ ospf_area_reconfigure(struct ospf_area *oa, struct ospf_area_config *nac)
/* Handle net_list */
fib_free(&oa->net_fib);
+ fib_free(&oa->enet_fib);
add_area_nets(oa, nac);
/* No need to handle stubnet_list */
@@ -804,11 +833,14 @@ ospf_sh(struct proto *p)
}
}
}
- // FIXME NSSA:
- // cli_msg(-1014, "\t\tStub:\t%s", oa->stub ? "Yes" : "No");
- cli_msg(-1014, "\t\tNSSA translation:\t%s%s", oa->translate ? "Yes" : "No",
- oa->translate == TRANS_WAIT ? " (run down)" : "");
+
+ cli_msg(-1014, "\t\tStub:\t%s", oa_is_stub(oa) ? "Yes" : "No");
+ cli_msg(-1014, "\t\tNSSA:\t%s", oa_is_nssa(oa) ? "Yes" : "No");
cli_msg(-1014, "\t\tTransit:\t%s", oa->trcap ? "Yes" : "No");
+
+ if (oa_is_nssa(oa))
+ cli_msg(-1014, "\t\tNSSA translation:\t%s%s", oa->translate ? "Yes" : "No",
+ oa->translate == TRANS_WAIT ? " (run down)" : "");
cli_msg(-1014, "\t\tNumber of interfaces:\t%u", ifano);
cli_msg(-1014, "\t\tNumber of neighbors:\t%u", nno);
cli_msg(-1014, "\t\tNumber of adjacent neighbors:\t%u", adjno);
@@ -826,6 +858,21 @@ ospf_sh(struct proto *p)
anet->hidden ? "Hidden" : "Advertise", anet->active ? "Active" : "");
}
FIB_WALK_END;
+
+ firstfib = 1;
+ FIB_WALK(&oa->enet_fib, nftmp)
+ {
+ anet = (struct area_net *) nftmp;
+ if(firstfib)
+ {
+ cli_msg(-1014, "\t\tArea external networks:");
+ firstfib = 0;
+ }
+ cli_msg(-1014, "\t\t\t%1I/%u\t%s\t%s", anet->fn.prefix, anet->fn.pxlen,
+ anet->hidden ? "Hidden" : "Advertise", anet->active ? "Active" : "");
+ }
+ FIB_WALK_END;
+
}
cli_msg(0, "");
}
diff --git a/proto/ospf/ospf.h b/proto/ospf/ospf.h
index 68c19424..2a7d3c1f 100644
--- a/proto/ospf/ospf.h
+++ b/proto/ospf/ospf.h
@@ -75,6 +75,7 @@ do { if ((p->debug & D_PACKETS) || OSPF_FORCE_DEBUG) \
#define DEFAULT_RFC1583 0 /* compatibility with rfc1583 */
#define DEFAULT_STUB_COST 1000
#define DEFAULT_ECMP_LIMIT 16
+#define DEFAULT_TRANSINT 40
struct ospf_config
@@ -101,6 +102,7 @@ struct area_net_config
node n;
struct prefix px;
int hidden;
+ u32 tag;
};
struct area_net
@@ -109,6 +111,7 @@ struct area_net
int hidden;
int active;
u32 metric;
+ u32 tag;
};
struct ospf_stubnet_config
@@ -131,6 +134,7 @@ struct ospf_area_config
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 */
};
@@ -734,6 +738,7 @@ struct ospf_area
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 */
byte origrt; /* Rt lsa origination scheduled? */
byte trcap; /* Transit capability? */
diff --git a/proto/ospf/rt.c b/proto/ospf/rt.c
index 71acd8be..22638527 100644
--- a/proto/ospf/rt.c
+++ b/proto/ospf/rt.c
@@ -33,7 +33,7 @@ ospf_rt_initort(struct fib_node *fn)
ort *ri = (ort *) fn;
reset_ri(ri);
ri->old_rta = NULL;
- ri->fn.x0 = 0;
+ ri->fn.x0 = ri->fn.x1 = 0;
}
static inline int
@@ -128,6 +128,23 @@ ri_better_asbr(struct proto_ospf *po, orta *new, orta *old)
return 0;
}
+static int
+orta_prio(orta *nf)
+{
+ /* RFC 3103 2.5 (6e) priorities */
+ u32 opts = nf->options & (ORTA_NSSA | ORTA_PROP);
+
+ /* A Type-7 LSA with the P-bit set */
+ if (opts == (ORTA_NSSA | ORTA_PROP))
+ return 2;
+
+ /* A Type-5 LSA */
+ if (opts == 0)
+ return 1;
+
+ return 0;
+}
+
/* 16.4. (6), return 1 if new is better */
static int
ri_better_ext(struct proto_ospf *po, orta *new, orta *old)
@@ -172,7 +189,19 @@ ri_better_ext(struct proto_ospf *po, orta *new, orta *old)
if (new->metric1 > old->metric1)
return 0;
- /* RFC 3103, 2.5. (6e) - missing, is this necessary? */
+ /* RFC 3103, 2.5. (6e) */
+ int new_prio = orta_prio(new);
+ int old_prio = orta_prio(old);
+
+ if (new_prio > old_prio)
+ return 1;
+
+ if (old_prio > new_prio)
+ return 0;
+
+ /* make it more deterministic */
+ if (new->rid > old->rid)
+ return 1;
return 0;
}
@@ -949,6 +978,96 @@ check_sum_rt_lsa(struct proto_ospf *po, ort *nf)
}
}
+static inline int
+decide_nssa_lsa(ort *nf, u32 *rt_metric, ip_addr *rt_fwaddr, u32 *rt_tag)
+{
+ struct ospf_area *oa = nf->n.oa;
+ struct top_hash_entry *en = nf->n.en;
+ int propagate;
+
+ if (!rt_is_nssa(nf) || !oa->translate)
+ return 0;
+
+ /* Condensed area network found */
+ if (fib_route(&oa->enet_fib, nf->fn.prefix, nf->fn.pxlen))
+ return 0;
+
+ if (!en || (en->lsa.type != LSA_T_NSSA))
+ return 0;
+
+ /* We do not store needed data in struct orta, we have to parse the LSA */
+ struct ospf_lsa_ext *le = en->lsa_body;
+
+#ifdef OSPFv2
+ *rt_fwaddr = le->fwaddr;
+ *rt_tag = le->tag;
+ propagate = en->lsa.options & OPT_P;
+#else /* OSPFv3 */
+ u32 *buf = le->rest;
+ u8 pxlen = (*buf >> 24);
+ u8 pxopts = (*buf >> 16);
+ buf += IPV6_PREFIX_WORDS(pxlen); /* Skip the IP prefix */
+
+ if (pxopts & OPT_PX_NU)
+ return 0;
+
+ if (le->metric & LSA_EXT_FBIT)
+ buf = lsa_get_ipv6_addr(buf, rt_fwaddr);
+ else
+ *rt_fwaddr = IPA_NONE;
+
+ if (le->metric & LSA_EXT_TBIT)
+ *rt_tag = *buf++;
+ else
+ *rt_tag = 0;
+
+ propagate = pxopts & OPT_PX_P;
+#endif
+
+ if (!propagate || ipa_zero(*rt_fwaddr))
+ return 0;
+
+ *rt_metric = le->metric & (METRIC_MASK | LSA_EXT_EBIT);
+ return 1;
+}
+
+/* RFC 3103 3.2 - translating Type-7 LSAs into Type-5 LSAs */
+static inline void
+check_nssa_lsa(struct proto_ospf *po, ort *nf)
+{
+ struct fib_node *fn = &nf->fn;
+ struct area_net *anet = NULL;
+ struct ospf_area *oa = NULL;
+ u32 rt_metric, rt_tag;
+ ip_addr rt_fwaddr;
+
+ /* Do not translate LSA if there is already the external LSA from route export */
+ if (fn->x1 == EXT_EXPORT)
+ return;
+
+ /* RT entry marked as area network */
+ if (fn->x0)
+ {
+ /* Find that area network */
+ WALK_LIST(oa, po->area_list)
+ {
+ anet = (struct area_net *) fib_find(&oa->enet_fib, &fn->prefix, fn->pxlen);
+ if (anet)
+ break;
+ }
+ }
+
+ /* RFC 3103 3.2 (3) - originate the aggregated address range */
+ if (anet && anet->active && !anet->hidden && oa->translate)
+ originate_ext_lsa(po->backbone, fn, EXT_NSSA, anet->metric, IPA_NONE, anet->tag);
+
+ /* RFC 3103 3.2 (2) - originate the same network */
+ else if (decide_nssa_lsa(nf, &rt_metric, &rt_fwaddr, &rt_tag))
+ originate_ext_lsa(po->backbone, fn, EXT_NSSA, rt_metric, rt_fwaddr, rt_tag);
+
+ else if (fn->x1 == EXT_NSSA)
+ flush_ext_lsa(po->backbone, fn);
+}
/* RFC 2328 16.7. p2 - find new/lost vlink endpoints */
static void
@@ -1000,26 +1119,13 @@ ospf_check_vlinks(struct proto_ospf *po)
}
}
-static void
-translator_timer_hook(timer *timer)
-{
- struct ospf_area *oa = timer->data;
-
- if (oa->translate != TRANS_WAIT)
- return;
-
- oa->translate = TRANS_OFF;
- schedule_rtcalc(oa->po);
-}
-
/* Miscellaneous route processing that needs to be done by ABRs */
static void
-ospf_rt_abr(struct proto_ospf *po)
+ospf_rt_abr1(struct proto_ospf *po)
{
- struct top_hash_entry *en;
struct area_net *anet;
- ort *nf, *nf2, *default_nf;
+ ort *nf, *default_nf;
FIB_WALK(&po->rtf, nftmp)
{
@@ -1087,8 +1193,41 @@ ospf_rt_abr(struct proto_ospf *po)
}
+ /* Originate or flush ASBR summary LSAs */
+ FIB_WALK(&po->backbone->rtr, nftmp)
+ {
+ check_sum_rt_lsa(po, (ort *) nftmp);
+ }
+ FIB_WALK_END;
+
+
+ /* RFC 2328 16.7. p2 - find new/lost vlink endpoints */
+ ospf_check_vlinks(po);
+}
+
+
+static void
+translator_timer_hook(timer *timer)
+{
+ struct ospf_area *oa = timer->data;
+
+ if (oa->translate != TRANS_WAIT)
+ return;
+
+ oa->translate = TRANS_OFF;
+ schedule_rtcalc(oa->po);
+}
+
+static void
+ospf_rt_abr2(struct proto_ospf *po)
+{
+ struct ospf_area *oa;
+ struct top_hash_entry *en;
+ ort *nf, *nf2;
+
+
/* RFC 3103 3.1 - type-7 translator election */
- struct ospf_area *bb = oa->po->backbone;
+ struct ospf_area *bb = po->backbone;
WALK_LIST(oa, po->area_list)
if (oa_is_nssa(oa))
{
@@ -1143,18 +1282,48 @@ ospf_rt_abr(struct proto_ospf *po)
}
- /* Originate or flush ASBR summary LSAs */
- FIB_WALK(&po->backbone->rtr, nftmp)
+ /* Compute condensed external networks */
+ FIB_WALK(&po->rtf, nftmp)
{
- check_sum_rt_lsa(po, (ort *) nftmp);
+ nf = (ort *) nftmp;
+ if (rt_is_nssa(nf))
+ {
+ struct area_net *anet = (struct area_net *)
+ fib_route(&nf->n.oa->enet_fib, nf->fn.prefix, nf->fn.pxlen);
+
+ if (anet)
+ {
+ if (!anet->active)
+ {
+ anet->active = 1;
+
+ /* Get a RT entry and mark it to know that it is an area network */
+ nf2 = (ort *) fib_get(&po->rtf, &anet->fn.prefix, anet->fn.pxlen);
+ nf2->fn.x0 = 1;
+ }
+
+ u32 metric = (nf->n.type == RTS_OSPF_EXT1) ?
+ nf->n.metric1 : ((nf->n.metric2 + 1) | LSA_EXT_EBIT);
+
+ if (anet->metric < metric)
+ anet->metric = metric;
+ }
+ }
}
FIB_WALK_END;
- /* RFC 2328 16.7. p2 - find new/lost vlink endpoints */
- ospf_check_vlinks(po);
+ FIB_WALK(&po->rtf, nftmp)
+ {
+ nf = (ort *) nftmp;
+
+ check_sum_net_lsa(po, nf);
+ check_nssa_lsa(po, nf);
+ }
+ FIB_WALK_END;
}
+
/* Like fib_route(), but ignores dummy rt entries */
static void *
ospf_fib_route(struct fib *f, ip_addr a, int len)
@@ -1254,7 +1423,7 @@ ospf_ext_spf(struct proto_ospf *po)
/* 16.4. (3) */
/* If there are more areas, we already precomputed preferred ASBR
- entries in ospf_rt_abr() and stored them in the backbone
+ entries in ospf_rt_abr1() and stored them in the backbone
table. For NSSA, we examine the area to which the LSA is assigned */
if (en->lsa.type == LSA_T_EXT)
atmp = ospf_main_area(po);
@@ -1333,12 +1502,17 @@ ospf_ext_spf(struct proto_ospf *po)
/* Whether the route is preferred in route selection according to 16.4.1 */
nfa.options = epath_preferred(&nf2->n) ? ORTA_PREF : 0;
+ if (en->lsa.type == LSA_T_NSSA)
+ nfa.options |= ORTA_NSSA;
+ if (rt_propagate)
+ nfa.options |= ORTA_PROP;
nfa.tag = rt_tag;
nfa.rid = en->lsa.rt;
- nfa.oa = nf1->n.oa; /* undefined in RFC 2328 */
+ nfa.oa = atmp; /* undefined in RFC 2328 */
nfa.voa = NULL;
nfa.nhs = nhs;
+ nfa.en = en; /* store LSA for later (NSSA processing) */
ri_install_ext(po, ip, pxlen, &nfa);
}
@@ -1391,6 +1565,14 @@ ospf_rt_reset(struct proto_ospf *po)
anet->metric = 0;
}
FIB_WALK_END;
+
+ FIB_WALK(&oa->enet_fib, nftmp)
+ {
+ anet = (struct area_net *) nftmp;
+ anet->active = 0;
+ anet->metric = 0;
+ }
+ FIB_WALK_END;
}
}
}
@@ -1430,11 +1612,14 @@ ospf_rt_spf(struct proto_ospf *po)
ospf_rt_sum_tr(oa);
if (po->areano > 1)
- ospf_rt_abr(po);
+ ospf_rt_abr1(po);
/* 16. (5) */
ospf_ext_spf(po);
+ if (po->areano > 1)
+ ospf_rt_abr2(po);
+
rt_sync(po);
lp_flush(po->nhpool);
@@ -1781,9 +1966,6 @@ again1:
}
}
- if (po->areano > 1)
- check_sum_net_lsa(po, nf);
-
/* Remove configured stubnets */
if (!nf->n.nhs)
reset_ri(nf);
@@ -1846,7 +2028,7 @@ again1:
}
/* Remove unused rt entry. Entries with fn.x0 == 1 are persistent. */
- if (!nf->n.type && !nf->fn.x0)
+ if (!nf->n.type && !nf->fn.x0 && !nf->fn.x1)
{
FIB_ITERATE_PUT(&fit, nftmp);
fib_delete(fib, nftmp);
diff --git a/proto/ospf/rt.h b/proto/ospf/rt.h
index bf234f58..cb4b652d 100644
--- a/proto/ospf/rt.h
+++ b/proto/ospf/rt.h
@@ -35,6 +35,9 @@ typedef struct orta
* intra-area (type == RTS_OSPF) and its area is not a backbone.
*/
#define ORTA_PREF 0x80000000
+#define ORTA_NSSA 0x40000000
+#define ORTA_PROP 0x20000000
+
u32 metric1;
u32 metric2;
u32 tag;
@@ -43,13 +46,10 @@ typedef struct orta
struct ospf_area *voa; /* Used when route is replaced in ospf_rt_sum_tr(),
NULL otherwise */
struct mpnh *nhs; /* Next hops computed during SPF */
+ struct top_hash_entry *en; /* LSA responsible for this orta */
}
orta;
-// struct ospf_iface *ifa; /* Outgoing interface */
-// ip_addr nh; /* Next hop */
-
-
typedef struct ort
{
/*
@@ -57,6 +57,10 @@ typedef struct ort
* LSAs that don't have 'proper' rt entry (area networks + default to stubs)
* to keep uid stable (used for LSA ID in OSPFv3 - see fibnode_to_lsaid()).
*
+ * We use fn.x1 to note whether the external route was originated
+ * from the route export (in ospf_rt_notify()) or from the NSSA
+ * route translation (in check_nssa_lsa()).
+ *
* 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 wasn not in the last update, in that
@@ -69,6 +73,13 @@ typedef struct ort
}
ort;
+static inline int rt_is_nssa(ort *nf)
+{ return nf->n.options & ORTA_NSSA; }
+
+
+#define EXT_EXPORT 1
+#define EXT_NSSA 2
+
/*
* Invariants for structs top_hash_entry (nodes of LSA db)
* enforced by SPF calculation for final nodes (color == INSPF):
diff --git a/proto/ospf/topology.c b/proto/ospf/topology.c
index f5f041eb..8df71b03 100644
--- a/proto/ospf/topology.c
+++ b/proto/ospf/topology.c
@@ -884,14 +884,14 @@ flush_sum_lsa(struct ospf_area *oa, struct fib_node *fn, int type)
#ifdef OSPFv2
static inline void *
-originate_ext_lsa_body(struct proto_ospf *po, u16 *length, net *n,
+originate_ext_lsa_body(struct proto_ospf *po, u16 *length, struct fib_node *fn,
u32 metric, ip_addr fwaddr, u32 tag)
{
struct ospf_lsa_ext *ext = mb_alloc(po->proto.pool, sizeof(struct ospf_lsa_ext));
*length = sizeof(struct ospf_lsa_header) + sizeof(struct ospf_lsa_ext);
ext->metric = metric;
- ext->netmask = ipa_mkmask(n->n.pxlen);
+ ext->netmask = ipa_mkmask(fn->pxlen);
ext->fwaddr = fwaddr;
ext->tag = tag;
@@ -928,7 +928,7 @@ check_ext_lsa(struct top_hash_entry *en, struct fib_node *fn, u32 metric, ip_add
#else /* OSPFv3 */
static inline void *
-originate_ext_lsa_body(struct proto_ospf *po, u16 *length, net *n,
+originate_ext_lsa_body(struct proto_ospf *po, u16 *length, struct fib_node *fn,
u32 metric, ip_addr fwaddr, u32 tag)
{
int size = sizeof(struct ospf_lsa_ext)
@@ -942,7 +942,7 @@ originate_ext_lsa_body(struct proto_ospf *po, u16 *length, net *n,
ext->metric = metric;
u32 *buf = ext->rest;
- buf = put_ipv6_prefix(buf, n->n.prefix, n->n.pxlen, 0, 0);
+ buf = put_ipv6_prefix(buf, fn->prefix, fn->pxlen, 0, 0);
if (ipa_nonzero(fwaddr))
{
@@ -996,30 +996,32 @@ check_ext_lsa(struct top_hash_entry *en, struct fib_node *fn, u32 metric, ip_add
/**
* originate_ext_lsa - new route received from nest and filters
* @oa: ospf_area for which LSA is originated
- * @n: network prefix and mask
- * @e: rte
- * @attrs: list of extended attributes
+ * @fn: network prefix and mask
+ * @type: the reason for origination of the LSA (EXT_EXPORT/EXT_NSSA)
+ * @metric: the metric of a route
+ * @fwaddr: the forwarding address
+ * @tag: the route tag
*
* 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 stub area.
+ * @oa should not be a stub area.
*
* The function also sets flag ebit. If it's the first time, the new router lsa
* origination is necessary.
*/
void
-originate_ext_lsa(struct ospf_area *oa, net *n, rte *e, struct ea_list *attrs)
+originate_ext_lsa(struct ospf_area *oa, struct fib_node *fn, int type,
+ u32 metric, ip_addr fwaddr, u32 tag)
{
struct proto_ospf *po = oa->po;
struct proto *p = &po->proto;
- struct fib_node *fn = &n->n;
struct ospf_lsa_header lsa;
struct top_hash_entry *en = NULL;
void *body;
int nssa = oa_is_nssa(oa);
u32 dom = nssa ? oa->areaid : 0;
- // FIXME NSSA - handle P bit
+ // FIXME NSSA - handle P bit, currently always set (from oa->options)
OSPF_TRACE(D_EVENTS, "Originating %s-LSA for %I/%d",
nssa ? "NSSA" : "AS-external", fn->prefix, fn->pxlen);
@@ -1032,19 +1034,6 @@ originate_ext_lsa(struct ospf_area *oa, net *n, rte *e, struct ea_list *attrs)
lsa.id = fibnode_to_lsaid(po, fn);
lsa.rt = po->router_id;
- /* Compute LSA content */
- u32 m1 = ea_get_int(attrs, EA_OSPF_METRIC1, LSINFINITY);
- u32 m2 = ea_get_int(attrs, EA_OSPF_METRIC2, 10000);
- u32 metric = (m1 != LSINFINITY) ? m1 : (m2 | LSA_EXT_EBIT);
- u32 tag = ea_get_int(attrs, EA_OSPF_TAG, 0);
- ip_addr gw = IPA_NONE;
- // FIXME check for gw should be per ifa, not per iface
- if ((e->attrs->dest == RTD_ROUTER) &&
- ipa_nonzero(e->attrs->gw) &&
- !ipa_has_link_scope(e->attrs->gw) &&
- (ospf_iface_find((struct proto_ospf *) p, e->attrs->iface) != NULL))
- gw = e->attrs->gw;
-
if (nssa)
{
// FIXME NSSA Add check for gw, update option
@@ -1052,7 +1041,7 @@ originate_ext_lsa(struct ospf_area *oa, net *n, rte *e, struct ea_list *attrs)
if ((en = ospf_hash_find_header(po->gr, dom, &lsa)) != NULL)
{
- int rv = check_ext_lsa(en, fn, metric, gw, tag);
+ int rv = check_ext_lsa(en, fn, metric, fwaddr, tag);
if (rv < 0)
{
log(L_ERR, "%s: LSAID collision for %I/%d",
@@ -1065,9 +1054,10 @@ originate_ext_lsa(struct ospf_area *oa, net *n, rte *e, struct ea_list *attrs)
}
lsa.sn = get_seqnum(en);
- body = originate_ext_lsa_body(po, &lsa.length, n, metric, gw, tag);
+ body = originate_ext_lsa_body(po, &lsa.length, fn, metric, fwaddr, tag);
lsasum_calculate(&lsa, body);
+ fn->x1 = type;
en = lsa_install_new(po, &lsa, dom, body);
ospf_lsupd_flood(po, NULL, NULL, &lsa, dom, 1);
@@ -1082,11 +1072,10 @@ originate_ext_lsa(struct ospf_area *oa, net *n, rte *e, struct ea_list *attrs)
}
void
-flush_ext_lsa(struct ospf_area *oa, net *n)
+flush_ext_lsa(struct ospf_area *oa, struct fib_node *fn)
{
struct proto_ospf *po = oa->po;
struct proto *p = &po->proto;
- struct fib_node *fn = &n->n;
struct top_hash_entry *en;
int nssa = oa_is_nssa(oa);
@@ -1106,6 +1095,7 @@ flush_ext_lsa(struct ospf_area *oa, net *n)
return;
}
+ fn->x1 = 0;
ospf_lsupd_flush_nlsa(po, en);
}
}
diff --git a/proto/ospf/topology.h b/proto/ospf/topology.h
index 137f1fd9..a1c0cbfe 100644
--- a/proto/ospf/topology.h
+++ b/proto/ospf/topology.h
@@ -71,9 +71,8 @@ int can_flush_lsa(struct proto_ospf *po);
void originate_sum_net_lsa(struct ospf_area *oa, struct fib_node *fn, int metric);
void originate_sum_rt_lsa(struct ospf_area *oa, struct fib_node *fn, int metric, u32 options UNUSED);
void flush_sum_lsa(struct ospf_area *oa, struct fib_node *fn, int type);
-
-void originate_ext_lsa(struct ospf_area *oa, net *n, rte *e, struct ea_list *attrs);
-void flush_ext_lsa(struct ospf_area *oa, net *n);
+void originate_ext_lsa(struct ospf_area *oa, struct fib_node *fn, int type, u32 metric, ip_addr fwaddr, u32 tag);
+void flush_ext_lsa(struct ospf_area *oa, struct fib_node *fn);
#ifdef OSPFv2