summaryrefslogtreecommitdiffstats
path: root/proto
diff options
context:
space:
mode:
authorOndrej Zajicek <santiago@crfreenet.org>2011-07-20 23:40:20 +0200
committerOndrej Zajicek <santiago@crfreenet.org>2011-07-20 23:48:06 +0200
commit41b612c31be05409e69e7365db82b3d1aefc4ca3 (patch)
treef6ab1441f244fd5e80a816ded38310c4489c97fe /proto
parent9008579b97239564e1dcac855cf726fa9ab7dabd (diff)
downloadbird-41b612c31be05409e69e7365db82b3d1aefc4ca3.tar
bird-41b612c31be05409e69e7365db82b3d1aefc4ca3.zip
OSPF NSSA support, part one.
Diffstat (limited to 'proto')
-rw-r--r--proto/ospf/config.Y18
-rw-r--r--proto/ospf/hello.c6
-rw-r--r--proto/ospf/lsalib.c1
-rw-r--r--proto/ospf/lsupd.c9
-rw-r--r--proto/ospf/ospf.c31
-rw-r--r--proto/ospf/ospf.h23
-rw-r--r--proto/ospf/rt.c78
-rw-r--r--proto/ospf/topology.c49
-rw-r--r--proto/ospf/topology.h5
9 files changed, 147 insertions, 73 deletions
diff --git a/proto/ospf/config.Y b/proto/ospf/config.Y
index f3a87d6..35060aa 100644
--- a/proto/ospf/config.Y
+++ b/proto/ospf/config.Y
@@ -56,8 +56,8 @@ ospf_iface_finish(void)
static void
ospf_area_finish(void)
{
- if ((this_area->areaid == 0) && (this_area->stub != 0))
- cf_error( "Backbone area cannot be stub");
+ if ((this_area->areaid == 0) && (this_area->type != OPT_E))
+ cf_error( "Backbone area cannot be stub/NSSA");
}
static void
@@ -89,7 +89,7 @@ ospf_proto_finish(void)
}
if (!cf->abr && !EMPTY_LIST(cf->vlink_list))
- cf_error( "No configured areas in OSPF");
+ cf_error( "Vlinks cannot be used on single area router");
}
CF_DECLS
@@ -101,7 +101,7 @@ 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(WAIT, DELAY, LSADB, ECMP, LIMIT, WEIGHT)
+CF_KEYWORDS(WAIT, DELAY, LSADB, ECMP, LIMIT, WEIGHT, NSSA)
%type <t> opttext
@@ -137,7 +137,9 @@ ospf_area_start: AREA idval {
this_area = cfg_allocz(sizeof(struct ospf_area_config));
add_tail(&OSPF_CFG->area_list, NODE this_area);
this_area->areaid = $2;
- this_area->stub = 0;
+ this_area->stub_cost = DEFAULT_STUB_COST;
+ this_area->type = OPT_E;
+
init_list(&this_area->patt_list);
init_list(&this_area->net_list);
init_list(&this_area->stubnet_list);
@@ -153,8 +155,10 @@ ospf_area_opts:
;
ospf_area_item:
- STUB COST expr { this_area->stub = $3 ; if($3<=0) cf_error("Stub cost must be greater than zero"); }
- | STUB bool {if($2) { if(!this_area->stub) this_area->stub=DEFAULT_STUB_COST;}else{ this_area->stub=0;}}
+ STUB COST expr { this_area->stub_cost = $3 ; if($3<=0) cf_error("Stub cost must be greater than zero"); }
+ | STUB bool { this_area->type = $2 ? 0 : OPT_E; /* We should remove the option */ }
+ | NSSA { this_area->type = OPT_N; }
+ | SUMMARY bool { this_area->summary = $2; }
| NETWORKS '{' pref_list '}'
| STUBNET ospf_stubnet
| INTERFACE ospf_iface
diff --git a/proto/ospf/hello.c b/proto/ospf/hello.c
index 0a94e4c..d04cb54 100644
--- a/proto/ospf/hello.c
+++ b/proto/ospf/hello.c
@@ -94,10 +94,10 @@ ospf_hello_receive(struct ospf_packet *ps_i, struct ospf_iface *ifa,
return;
}
- tmp = !(ps->options & OPT_E);
- if (tmp != !!ifa->oa->stub)
+ /* Check whether bits E, N match */
+ if ((ps->options ^ ifa->oa->options) & (OPT_E | OPT_N))
{
- log(L_ERR "%s%I - stub area flag mismatch (%d)", beg, faddr, tmp);
+ log(L_ERR "%s%I - area type mismatch (%x)", beg, faddr, ps->options);
return;
}
diff --git a/proto/ospf/lsalib.c b/proto/ospf/lsalib.c
index 5e227da..538a730 100644
--- a/proto/ospf/lsalib.c
+++ b/proto/ospf/lsalib.c
@@ -490,6 +490,7 @@ lsa_validate(struct ospf_lsa_header *lsa, void *body)
case LSA_T_SUM_RT:
return lsa_validate_sum_rt(lsa, body);
case LSA_T_EXT:
+ case LSA_T_NSSA:
return lsa_validate_ext(lsa, body);
#ifdef OSPFv3
case LSA_T_LINK:
diff --git a/proto/ospf/lsupd.c b/proto/ospf/lsupd.c
index b69d861..948f458 100644
--- a/proto/ospf/lsupd.c
+++ b/proto/ospf/lsupd.c
@@ -77,7 +77,7 @@ ospf_lsa_flooding_allowed(struct ospf_lsa_header *lsa, u32 domain, struct ospf_i
{
if (ifa->type == OSPF_IT_VLINK)
return 0;
- if (ifa->oa->stub)
+ if (!oa_is_ext(ifa->oa))
return 0;
return 1;
}
@@ -97,6 +97,7 @@ unknown_lsa_type(struct ospf_lsa_header *lsa)
case LSA_T_SUM_NET:
case LSA_T_SUM_RT:
case LSA_T_EXT:
+ case LSA_T_NSSA:
case LSA_T_LINK:
case LSA_T_PREFIX:
return 0;
@@ -486,21 +487,21 @@ ospf_lsupd_receive(struct ospf_packet *ps_i, struct ospf_iface *ifa,
#ifdef OSPFv2
/* pg 143 (2) */
- if ((lsa->type < LSA_T_RT) || (lsa->type > LSA_T_EXT))
+ if ((lsa->type == 0) || (lsa->type == 6) || (lsa->type > LSA_T_NSSA))
{
log(L_WARN "Unknown LSA type from %I", n->ip);
continue;
}
/* pg 143 (3) */
- if ((lsa->type == LSA_T_EXT) && ifa->oa->stub)
+ if ((lsa->type == LSA_T_EXT) && !oa_is_ext(ifa->oa))
{
log(L_WARN "Received External LSA in stub area from %I", n->ip);
continue;
}
#else /* OSPFv3 */
/* 4.5.1 (2) */
- if ((LSA_SCOPE(lsa) == LSA_SCOPE_AS) && ifa->oa->stub)
+ if ((LSA_SCOPE(lsa) == LSA_SCOPE_AS) && !oa_is_ext(ifa->oa))
{
log(L_WARN "Received LSA with AS scope in stub area from %I", n->ip);
continue;
diff --git a/proto/ospf/ospf.c b/proto/ospf/ospf.c
index ce913f7..320f457 100644
--- a/proto/ospf/ospf.c
+++ b/proto/ospf/ospf.c
@@ -147,7 +147,6 @@ ospf_area_add(struct proto_ospf *po, struct ospf_area_config *ac, int reconf)
po->areano++;
oa->ac = ac;
- oa->stub = ac->stub;
oa->areaid = ac->areaid;
oa->rt = NULL;
oa->po = po;
@@ -158,9 +157,9 @@ ospf_area_add(struct proto_ospf *po, struct ospf_area_config *ac, int reconf)
po->backbone = oa;
#ifdef OSPFv2
- oa->options = (oa->stub ? 0 : OPT_E);
+ oa->options = ac->type;
#else /* OSPFv3 */
- oa->options = OPT_R | (oa->stub ? 0 : OPT_E) | OPT_V6;
+ oa->options = OPT_R | ac->type | OPT_V6;
#endif
if (reconf)
@@ -480,11 +479,15 @@ int
ospf_import_control(struct proto *p, rte ** new, ea_list ** attrs,
struct linpool *pool)
{
+ struct ospf_area *oa = ospf_main_area((struct proto_ospf *) p);
rte *e = *new;
if (p == e->attrs->proto)
return -1; /* Reject our own routes */
+ if (oa_is_stub(oa))
+ return -1; /* Do not export routes to stub areas */
+
eattr *ea = ea_find(e->attrs->eattrs, EA_GEN_IGP_METRIC);
u32 m1 = (ea && (ea->u.data < LSINFINITY)) ? ea->u.data : LSINFINITY;
@@ -543,6 +546,7 @@ static void
ospf_rt_notify(struct proto *p, rtable *tbl UNUSED, net * n, rte * new, rte * old UNUSED, ea_list * attrs)
{
struct proto_ospf *po = (struct proto_ospf *) p;
+ struct ospf_area *oa = ospf_main_area(po);
/* Temporarily down write anything
OSPF_TRACE(D_EVENTS, "Got route %I/%d %s", p->name, n->n.prefix,
@@ -550,9 +554,9 @@ ospf_rt_notify(struct proto *p, rtable *tbl UNUSED, net * n, rte * new, rte * ol
*/
if (new) /* Got some new route */
- originate_ext_lsa(n, new, po, attrs);
+ originate_ext_lsa(oa, n, new, attrs);
else
- flush_ext_lsa(n, po);
+ flush_ext_lsa(oa, n);
}
static void
@@ -605,7 +609,7 @@ ospf_get_route_info(rte * rte, byte * buf, ea_list * attrs UNUSED)
if (rte->attrs->source == RTS_OSPF_EXT2)
buf += bsprintf(buf, "/%d", rte->u.ospf.metric2);
buf += bsprintf(buf, ")");
- if ((rte->attrs->source == RTS_OSPF_EXT2 || rte->attrs->source == RTS_OSPF_EXT1) && rte->u.ospf.tag)
+ if ((rte->attrs->source == RTS_OSPF_EXT1 || rte->attrs->source == RTS_OSPF_EXT2) && rte->u.ospf.tag)
{
buf += bsprintf(buf, " [%x]", rte->u.ospf.tag);
}
@@ -639,7 +643,7 @@ static void
ospf_area_reconfigure(struct ospf_area *oa, struct ospf_area_config *nac)
{
oa->ac = nac;
- oa->stub = nac->stub;
+ // FIXME NSSA check type
ospf_ifaces_reconfigure(oa, nac);
@@ -797,7 +801,8 @@ ospf_sh(struct proto *p)
}
}
}
- cli_msg(-1014, "\t\tStub:\t%s", oa->stub ? "Yes" : "No");
+ // FIXME NSSA:
+ // cli_msg(-1014, "\t\tStub:\t%s", oa->stub ? "Yes" : "No");
cli_msg(-1014, "\t\tTransit:\t%s", oa->trcap ? "Yes" : "No");
cli_msg(-1014, "\t\tNumber of interfaces:\t%u", ifano);
cli_msg(-1014, "\t\tNumber of neighbors:\t%u", nno);
@@ -1096,7 +1101,8 @@ show_lsa_external(struct top_hash_entry *he)
int pxlen, ebit, rt_fwaddr_valid;
u32 rt_tag, rt_metric;
- he->domain = 0; /* Unmark the LSA */
+ if (he->lsa.type == LSA_T_EXT)
+ he->domain = 0; /* Unmark the LSA */
rt_metric = ext->metric & METRIC_MASK;
ebit = ext->metric & LSA_EXT_EBIT;
@@ -1130,8 +1136,9 @@ show_lsa_external(struct top_hash_entry *he)
if (rt_tag)
bsprintf(str_tag, " tag %08x", rt_tag);
- cli_msg(-1016, "\t\texternal %I/%d metric%s %u%s%s", ip, pxlen,
- ebit ? "2" : "", rt_metric, str_via, str_tag);
+ cli_msg(-1016, "\t\t%s %I/%d metric%s %u%s%s",
+ (he->lsa.type == LSA_T_NSSA) ? "nssa-ext" : "external",
+ ip, pxlen, ebit ? "2" : "", rt_metric, str_via, str_tag);
}
#ifdef OSPFv3
@@ -1206,6 +1213,7 @@ ospf_sh_state(struct proto *p, int verbose, int reachable)
case LSA_T_SUM_NET:
case LSA_T_SUM_RT:
+ case LSA_T_NSSA:
#ifdef OSPFv3
case LSA_T_PREFIX:
#endif
@@ -1307,6 +1315,7 @@ ospf_sh_state(struct proto *p, int verbose, int reachable)
#endif
case LSA_T_EXT:
+ case LSA_T_NSSA:
show_lsa_external(he);
break;
}
diff --git a/proto/ospf/ospf.h b/proto/ospf/ospf.h
index 664bc48..a8b4a98 100644
--- a/proto/ospf/ospf.h
+++ b/proto/ospf/ospf.h
@@ -123,7 +123,10 @@ struct ospf_area_config
{
node n;
u32 areaid;
- u32 stub;
+ u32 stub_cost; /* Cost of default route for stub areas */
+ u8 type; /* Area type (standard, stub, NSSA), represented
+ by option flags (OPT_E, OPT_N) */
+ u8 summary; /* Import summaries to this stub/NSSA area, valid for ABR */
list patt_list;
list net_list; /* List of aggregate networks for that area */
list stubnet_list; /* List of stub networks added to Router LSA */
@@ -137,12 +140,14 @@ struct ospf_area_config
#define OPT_DC 0x20
#ifdef OSPFv2
+#define OPT_P 0x08 /* flags P and N share position, see NSSA RFC */
#define OPT_EA 0x10
/* VEB flags are are stored independently in 'u16 options' */
#define OPT_RT_B (0x01 << 8)
#define OPT_RT_E (0x02 << 8)
#define OPT_RT_V (0x04 << 8)
+#define OPT_RT_NT (0x10 << 8)
#endif
#ifdef OSPFv3
@@ -363,6 +368,7 @@ struct ospf_lsa_header
#define LSA_T_SUM_NET 3
#define LSA_T_SUM_RT 4
#define LSA_T_EXT 5
+#define LSA_T_NSSA 7
#define LSA_SCOPE_AREA 0x2000
#define LSA_SCOPE_AS 0x4000
@@ -377,6 +383,7 @@ struct ospf_lsa_header
#define LSA_T_SUM_NET 0x2003
#define LSA_T_SUM_RT 0x2004
#define LSA_T_EXT 0x4005
+#define LSA_T_NSSA 0x2007
#define LSA_T_LINK 0x0008
#define LSA_T_PREFIX 0x2009
@@ -720,12 +727,11 @@ struct ospf_area
{
node n;
u32 areaid;
- struct ospf_area_config *ac; /* Related area config, might be NULL */
+ struct ospf_area_config *ac; /* Related area config */
struct top_hash_entry *rt; /* My own router LSA */
struct top_hash_entry *pxr_lsa; /* Originated prefix LSA */
list cand; /* List of candidates for RT calc. */
struct fib net_fib; /* Networks to advertise or not */
- u32 stub; /* 0 or stub area cost */
u32 options; /* Optional features */
byte origrt; /* Rt lsa origination scheduled? */
byte trcap; /* Transit capability? */
@@ -796,7 +802,6 @@ struct ospf_iface_patt
#endif
};
-
int ospf_import_control(struct proto *p, rte **new, ea_list **attrs,
struct linpool *pool);
struct ea_list *ospf_make_tmp_attrs(struct rte *rt, struct linpool *pool);
@@ -806,6 +811,16 @@ void schedule_rtcalc(struct proto_ospf *po);
void schedule_net_lsa(struct ospf_iface *ifa);
struct ospf_area *ospf_find_area(struct proto_ospf *po, u32 aid);
+static inline struct ospf_area *ospf_main_area(struct proto_ospf *po)
+{ return (po->areano == 1) ? HEAD(po->area_list) : po->backbone; }
+
+static inline int oa_is_stub(struct ospf_area *oa)
+{ return (oa->options & (OPT_E | OPT_N)) == 0; }
+static inline int oa_is_ext(struct ospf_area *oa)
+{ return oa->options & OPT_E; }
+static inline int oa_is_nssa(struct ospf_area *oa)
+{ return oa->options & OPT_N; }
+
#ifdef OSPFv3
void schedule_link_lsa(struct ospf_iface *ifa);
diff --git a/proto/ospf/rt.c b/proto/ospf/rt.c
index 78b1ebe..e8d661c 100644
--- a/proto/ospf/rt.c
+++ b/proto/ospf/rt.c
@@ -172,6 +172,8 @@ 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? */
+
return 0;
}
@@ -826,7 +828,8 @@ ospf_rt_sum_tr(struct ospf_area *oa)
static int
decide_anet_lsa(struct ospf_area *oa, struct area_net *anet, struct ospf_area *anet_oa)
{
- if (oa->stub)
+ /* 12.4.3.1. - for stub/NSSA areas, originating summary routes is configurable */
+ if (!oa_is_ext(oa) && !oa->ac->summary)
return 0;
if (oa == anet_oa)
@@ -843,8 +846,8 @@ decide_anet_lsa(struct ospf_area *oa, struct area_net *anet, struct ospf_area *a
static int
decide_sum_lsa(struct ospf_area *oa, ort *nf, int dest)
{
- /* 12.4.3.1. - do not send summary into stub areas, we send just default route */
- if (oa->stub)
+ /* 12.4.3.1. - for stub/NSSA areas, originating summary routes is configurable */
+ if (!oa_is_ext(oa) && !oa->ac->summary)
return 0;
/* Invalid field - no route */
@@ -872,7 +875,7 @@ decide_sum_lsa(struct ospf_area *oa, ort *nf, int dest)
{
/* We call decide_sum_lsa() on preferred ASBR entries, no need for 16.4. (3) */
/* 12.4.3 p1 */
- return (nf->n.options & ORTA_ASBR);
+ return oa_is_ext(oa) && (nf->n.options & ORTA_ASBR);
}
/* 12.4.3 p7 - inter-area route */
@@ -1048,21 +1051,25 @@ ospf_rt_abr(struct proto_ospf *po)
WALK_LIST(oa, po->area_list)
{
- /* 12.4.3.1. - originate or flush default summary LSA for stub areas */
- if (oa->stub)
- originate_sum_net_lsa(oa, &default_nf->fn, oa->stub);
+ /* 12.4.3.1. - originate or flush default route for stub/NSSA areas */
+ if (oa_is_stub(oa) || (oa_is_nssa(oa) && !oa->ac->summary))
+ originate_sum_net_lsa(oa, &default_nf->fn, oa->ac->stub_cost);
else
flush_sum_lsa(oa, &default_nf->fn, ORT_NET);
+ // FIXME NSSA add support for type 7 default route ?
/* RFC 2328 16.4. (3) - precompute preferred ASBR entries */
- FIB_WALK(&oa->rtr, nftmp)
+ if (oa_is_ext(oa))
{
- nf = (ort *) nftmp;
- if (nf->n.options & ORTA_ASBR)
- ri_install_asbr(po, &nf->fn.prefix, &nf->n);
+ FIB_WALK(&oa->rtr, nftmp)
+ {
+ nf = (ort *) nftmp;
+ if (nf->n.options & ORTA_ASBR)
+ ri_install_asbr(po, &nf->fn.prefix, &nf->n);
+ }
+ FIB_WALK_END;
}
- FIB_WALK_END;
}
@@ -1105,7 +1112,7 @@ ospf_ext_spf(struct proto_ospf *po)
struct top_hash_entry *en;
struct proto *p = &po->proto;
struct ospf_lsa_ext *le;
- int pxlen, ebit, rt_fwaddr_valid;
+ int pxlen, ebit, rt_fwaddr_valid, rt_propagate;
ip_addr ip, rtid, rt_fwaddr;
u32 br_metric, rt_metric, rt_tag;
struct ospf_area *atmp;
@@ -1116,7 +1123,7 @@ ospf_ext_spf(struct proto_ospf *po)
WALK_SLIST(en, po->lsal)
{
/* 16.4. (1) */
- if (en->lsa.type != LSA_T_EXT)
+ if ((en->lsa.type != LSA_T_EXT) && (en->lsa.type != LSA_T_NSSA))
continue;
if (en->lsa.age == LSA_MAXAGE)
@@ -1143,6 +1150,7 @@ ospf_ext_spf(struct proto_ospf *po)
rt_fwaddr = le->fwaddr;
rt_fwaddr_valid = !ipa_equal(rt_fwaddr, IPA_NONE);
rt_tag = le->tag;
+ rt_propagate = en->lsa.options & OPT_P;
#else /* OSPFv3 */
u8 pxopts;
u16 rest;
@@ -1162,6 +1170,8 @@ ospf_ext_spf(struct proto_ospf *po)
rt_tag = *buf++;
else
rt_tag = 0;
+
+ rt_propagate = pxopts & OPT_PX_P;
#endif
if (pxlen < 0 || pxlen > MAX_PREFIX_LENGTH)
@@ -1171,10 +1181,19 @@ ospf_ext_spf(struct proto_ospf *po)
continue;
}
+
/* 16.4. (3) */
- /* If there are more areas, we already precomputed preferred ASBR entries
- in ospf_asbr_spf() and stored them in the backbone table */
- atmp = (po->areano > 1) ? po->backbone : HEAD(po->area_list);
+ /* If there are more areas, we already precomputed preferred ASBR
+ entries in ospf_rt_abr() 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);
+ else /* NSSA */
+ atmp = ospf_find_area(po, en->domain);
+
+ if (!atmp)
+ continue; /* Should not happen */
+
rtid = ipa_from_rid(en->lsa.rt);
nf1 = fib_find(&atmp->rtr, &rtid, MAX_PREFIX_LENGTH);
@@ -1184,6 +1203,12 @@ ospf_ext_spf(struct proto_ospf *po)
if (!(nf1->n.options & ORTA_ASBR))
continue; /* It is not ASBR */
+ /* 16.4. (3) NSSA - special rule for default routes */
+ /* ABR should use default only if P-bit is set and summaries are active */
+ if ((en->lsa.type == LSA_T_NSSA) && ipa_zero(ip) && (pxlen == 0) &&
+ (po->areano > 1) && !(rt_propagate && atmp->ac->summary))
+ continue;
+
if (!rt_fwaddr_valid)
{
nf2 = nf1;
@@ -1196,8 +1221,18 @@ ospf_ext_spf(struct proto_ospf *po)
if (!nf2)
continue;
- if ((nf2->n.type != RTS_OSPF) && (nf2->n.type != RTS_OSPF_IA))
- continue;
+ if (en->lsa.type == LSA_T_EXT)
+ {
+ /* For ext routes, we accept intra-area or inter-area routes */
+ if ((nf2->n.type != RTS_OSPF) && (nf2->n.type != RTS_OSPF_IA))
+ continue;
+ }
+ else /* NSSA */
+ {
+ /* For NSSA routes, we accept just intra-area in the same area */
+ if ((nf2->n.type != RTS_OSPF) || (nf2->n.oa != atmp))
+ continue;
+ }
/* Next-hop is a part of a configured stubnet */
if (!nf2->n.nhs)
@@ -1317,10 +1352,7 @@ ospf_rt_spf(struct proto_ospf *po)
ospf_rt_spfa(oa);
/* 16. (3) */
- if (po->areano == 1)
- ospf_rt_sum(HEAD(po->area_list));
- else
- ospf_rt_sum(po->backbone);
+ ospf_rt_sum(ospf_main_area(po));
/* 16. (4) */
WALK_LIST(oa, po->area_list)
diff --git a/proto/ospf/topology.c b/proto/ospf/topology.c
index 78d8859..54bc09c 100644
--- a/proto/ospf/topology.c
+++ b/proto/ospf/topology.c
@@ -222,7 +222,7 @@ originate_rt_lsa_body(struct ospf_area *oa, u16 *length)
if (po->areano > 1)
rt->options |= OPT_RT_B;
- if ((po->ebit) && (!oa->stub))
+ if (po->ebit && !oa_is_stub(oa))
rt->options |= OPT_RT_E;
rt = NULL; /* buffer might be reallocated later */
@@ -388,7 +388,7 @@ originate_rt_lsa_body(struct ospf_area *oa, u16 *length)
if (po->areano > 1)
rt->options |= OPT_RT_B;
- if ((po->ebit) && (!oa->stub))
+ if (po->ebit && !oa_is_stub(oa))
rt->options |= OPT_RT_E;
rt = NULL; /* buffer might be reallocated later */
@@ -989,36 +989,40 @@ 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
- * @po: current instance of OSPF
* @attrs: list of extended attributes
*
* If I receive a message that new route is installed, I try to originate an
- * external LSA.
+ * external LSA. If @oa is an NSSA area, NSSA-LSA is originated instead.
+ * @oa should not be 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(net * n, rte * e, struct proto_ospf *po,
- struct ea_list *attrs)
+originate_ext_lsa(struct ospf_area *oa, net *n, rte *e, struct ea_list *attrs)
{
+ 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;
- struct ospf_area *oa;
+ int nssa = oa_is_nssa(oa);
+ u32 dom = nssa ? oa->areaid : 0;
+
+ // FIXME NSSA - handle P bit
- OSPF_TRACE(D_EVENTS, "Originating AS-external-LSA for %I/%d",
- fn->prefix, fn->pxlen);
+ OSPF_TRACE(D_EVENTS, "Originating %s-LSA for %I/%d",
+ nssa ? "NSSA" : "AS-external", fn->prefix, fn->pxlen);
lsa.age = 0;
#ifdef OSPFv2
- lsa.options = 0; /* or oa->options ? */
+ lsa.options = oa->options;
#endif
- lsa.type = LSA_T_EXT;
+ lsa.type = nssa ? LSA_T_NSSA : LSA_T_EXT;
lsa.id = fibnode_to_lsaid(po, fn);
lsa.rt = po->router_id;
@@ -1035,7 +1039,12 @@ originate_ext_lsa(net * n, rte * e, struct proto_ospf *po,
(ospf_iface_find((struct proto_ospf *) p, e->attrs->iface) != NULL))
gw = e->attrs->gw;
- if ((en = ospf_hash_find_header(po->gr, 0, &lsa)) != NULL)
+ if (nssa)
+ {
+ // FIXME NSSA Add check for gw, update option
+ }
+
+ if ((en = ospf_hash_find_header(po->gr, dom, &lsa)) != NULL)
{
int rv = check_ext_lsa(en, fn, metric, gw, tag);
if (rv < 0)
@@ -1053,8 +1062,8 @@ originate_ext_lsa(net * n, rte * e, struct proto_ospf *po,
body = originate_ext_lsa_body(po, &lsa.length, n, metric, gw, tag);
lsasum_calculate(&lsa, body);
- en = lsa_install_new(po, &lsa, 0, body);
- ospf_lsupd_flood(po, NULL, NULL, &lsa, 0, 1);
+ en = lsa_install_new(po, &lsa, dom, body);
+ ospf_lsupd_flood(po, NULL, NULL, &lsa, dom, 1);
if (po->ebit == 0)
{
@@ -1067,18 +1076,22 @@ originate_ext_lsa(net * n, rte * e, struct proto_ospf *po,
}
void
-flush_ext_lsa(net *n, struct proto_ospf *po)
+flush_ext_lsa(struct ospf_area *oa, net *n)
{
+ 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);
- OSPF_TRACE(D_EVENTS, "Flushing AS-external-LSA for %I/%d",
- fn->prefix, fn->pxlen);
+ OSPF_TRACE(D_EVENTS, "Flushing %s-LSA for %I/%d",
+ nssa ? "NSSA" : "AS-external", fn->prefix, fn->pxlen);
+ u32 dom = nssa ? oa->areaid : 0;
+ u32 type = nssa ? LSA_T_NSSA : LSA_T_EXT;
u32 lsaid = fibnode_to_lsaid(po, fn);
- if (en = ospf_hash_find(po->gr, 0, lsaid, po->router_id, LSA_T_EXT))
+ if (en = ospf_hash_find(po->gr, dom, lsaid, po->router_id, type))
{
if (check_ext_lsa(en, fn, 0, IPA_NONE, 0) < 0)
{
diff --git a/proto/ospf/topology.h b/proto/ospf/topology.h
index 9521e3e..137f1fd 100644
--- a/proto/ospf/topology.h
+++ b/proto/ospf/topology.h
@@ -72,9 +72,8 @@ 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(net * n, rte * e, struct proto_ospf *po,
- struct ea_list *attrs);
-void flush_ext_lsa(net *n, struct proto_ospf *po);
+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);
#ifdef OSPFv2