Commit 41b612c3 authored by Ondřej Zajíček's avatar Ondřej Zajíček

OSPF NSSA support, part one.

parent 9008579b
...@@ -56,8 +56,8 @@ ospf_iface_finish(void) ...@@ -56,8 +56,8 @@ ospf_iface_finish(void)
static void static void
ospf_area_finish(void) ospf_area_finish(void)
{ {
if ((this_area->areaid == 0) && (this_area->stub != 0)) if ((this_area->areaid == 0) && (this_area->type != OPT_E))
cf_error( "Backbone area cannot be stub"); cf_error( "Backbone area cannot be stub/NSSA");
} }
static void static void
...@@ -89,7 +89,7 @@ ospf_proto_finish(void) ...@@ -89,7 +89,7 @@ ospf_proto_finish(void)
} }
if (!cf->abr && !EMPTY_LIST(cf->vlink_list)) 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 CF_DECLS
...@@ -101,7 +101,7 @@ CF_KEYWORDS(NONBROADCAST, NBMA, POINTOPOINT, PTP, POINTOMULTIPOINT, PTMP) ...@@ -101,7 +101,7 @@ CF_KEYWORDS(NONBROADCAST, NBMA, POINTOPOINT, PTP, POINTOMULTIPOINT, PTMP)
CF_KEYWORDS(NONE, SIMPLE, AUTHENTICATION, STRICT, CRYPTOGRAPHIC) CF_KEYWORDS(NONE, SIMPLE, AUTHENTICATION, STRICT, CRYPTOGRAPHIC)
CF_KEYWORDS(ELIGIBLE, POLL, NETWORKS, HIDDEN, VIRTUAL, CHECK, LINK) 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)
CF_KEYWORDS(WAIT, DELAY, LSADB, ECMP, LIMIT, WEIGHT) CF_KEYWORDS(WAIT, DELAY, LSADB, ECMP, LIMIT, WEIGHT, NSSA)
%type <t> opttext %type <t> opttext
...@@ -137,7 +137,9 @@ ospf_area_start: AREA idval { ...@@ -137,7 +137,9 @@ ospf_area_start: AREA idval {
this_area = cfg_allocz(sizeof(struct ospf_area_config)); this_area = cfg_allocz(sizeof(struct ospf_area_config));
add_tail(&OSPF_CFG->area_list, NODE this_area); add_tail(&OSPF_CFG->area_list, NODE this_area);
this_area->areaid = $2; 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->patt_list);
init_list(&this_area->net_list); init_list(&this_area->net_list);
init_list(&this_area->stubnet_list); init_list(&this_area->stubnet_list);
...@@ -153,8 +155,10 @@ ospf_area_opts: ...@@ -153,8 +155,10 @@ ospf_area_opts:
; ;
ospf_area_item: ospf_area_item:
STUB COST expr { this_area->stub = $3 ; if($3<=0) cf_error("Stub cost must be greater than zero"); } STUB COST expr { this_area->stub_cost = $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 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 '}' | NETWORKS '{' pref_list '}'
| STUBNET ospf_stubnet | STUBNET ospf_stubnet
| INTERFACE ospf_iface | INTERFACE ospf_iface
......
...@@ -94,10 +94,10 @@ ospf_hello_receive(struct ospf_packet *ps_i, struct ospf_iface *ifa, ...@@ -94,10 +94,10 @@ ospf_hello_receive(struct ospf_packet *ps_i, struct ospf_iface *ifa,
return; return;
} }
tmp = !(ps->options & OPT_E); /* Check whether bits E, N match */
if (tmp != !!ifa->oa->stub) 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; return;
} }
......
...@@ -490,6 +490,7 @@ lsa_validate(struct ospf_lsa_header *lsa, void *body) ...@@ -490,6 +490,7 @@ lsa_validate(struct ospf_lsa_header *lsa, void *body)
case LSA_T_SUM_RT: case LSA_T_SUM_RT:
return lsa_validate_sum_rt(lsa, body); return lsa_validate_sum_rt(lsa, body);
case LSA_T_EXT: case LSA_T_EXT:
case LSA_T_NSSA:
return lsa_validate_ext(lsa, body); return lsa_validate_ext(lsa, body);
#ifdef OSPFv3 #ifdef OSPFv3
case LSA_T_LINK: case LSA_T_LINK:
......
...@@ -77,7 +77,7 @@ ospf_lsa_flooding_allowed(struct ospf_lsa_header *lsa, u32 domain, struct ospf_i ...@@ -77,7 +77,7 @@ ospf_lsa_flooding_allowed(struct ospf_lsa_header *lsa, u32 domain, struct ospf_i
{ {
if (ifa->type == OSPF_IT_VLINK) if (ifa->type == OSPF_IT_VLINK)
return 0; return 0;
if (ifa->oa->stub) if (!oa_is_ext(ifa->oa))
return 0; return 0;
return 1; return 1;
} }
...@@ -97,6 +97,7 @@ unknown_lsa_type(struct ospf_lsa_header *lsa) ...@@ -97,6 +97,7 @@ unknown_lsa_type(struct ospf_lsa_header *lsa)
case LSA_T_SUM_NET: case LSA_T_SUM_NET:
case LSA_T_SUM_RT: case LSA_T_SUM_RT:
case LSA_T_EXT: case LSA_T_EXT:
case LSA_T_NSSA:
case LSA_T_LINK: case LSA_T_LINK:
case LSA_T_PREFIX: case LSA_T_PREFIX:
return 0; return 0;
...@@ -486,21 +487,21 @@ ospf_lsupd_receive(struct ospf_packet *ps_i, struct ospf_iface *ifa, ...@@ -486,21 +487,21 @@ ospf_lsupd_receive(struct ospf_packet *ps_i, struct ospf_iface *ifa,
#ifdef OSPFv2 #ifdef OSPFv2
/* pg 143 (2) */ /* 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); log(L_WARN "Unknown LSA type from %I", n->ip);
continue; continue;
} }
/* pg 143 (3) */ /* 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); log(L_WARN "Received External LSA in stub area from %I", n->ip);
continue; continue;
} }
#else /* OSPFv3 */ #else /* OSPFv3 */
/* 4.5.1 (2) */ /* 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); log(L_WARN "Received LSA with AS scope in stub area from %I", n->ip);
continue; continue;
......
...@@ -147,7 +147,6 @@ ospf_area_add(struct proto_ospf *po, struct ospf_area_config *ac, int reconf) ...@@ -147,7 +147,6 @@ ospf_area_add(struct proto_ospf *po, struct ospf_area_config *ac, int reconf)
po->areano++; po->areano++;
oa->ac = ac; oa->ac = ac;
oa->stub = ac->stub;
oa->areaid = ac->areaid; oa->areaid = ac->areaid;
oa->rt = NULL; oa->rt = NULL;
oa->po = po; oa->po = po;
...@@ -158,9 +157,9 @@ ospf_area_add(struct proto_ospf *po, struct ospf_area_config *ac, int reconf) ...@@ -158,9 +157,9 @@ ospf_area_add(struct proto_ospf *po, struct ospf_area_config *ac, int reconf)
po->backbone = oa; po->backbone = oa;
#ifdef OSPFv2 #ifdef OSPFv2
oa->options = (oa->stub ? 0 : OPT_E); oa->options = ac->type;
#else /* OSPFv3 */ #else /* OSPFv3 */
oa->options = OPT_R | (oa->stub ? 0 : OPT_E) | OPT_V6; oa->options = OPT_R | ac->type | OPT_V6;
#endif #endif
if (reconf) if (reconf)
...@@ -480,11 +479,15 @@ int ...@@ -480,11 +479,15 @@ int
ospf_import_control(struct proto *p, rte ** new, ea_list ** attrs, ospf_import_control(struct proto *p, rte ** new, ea_list ** attrs,
struct linpool *pool) struct linpool *pool)
{ {
struct ospf_area *oa = ospf_main_area((struct proto_ospf *) p);
rte *e = *new; rte *e = *new;
if (p == e->attrs->proto) if (p == e->attrs->proto)
return -1; /* Reject our own routes */ 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); eattr *ea = ea_find(e->attrs->eattrs, EA_GEN_IGP_METRIC);
u32 m1 = (ea && (ea->u.data < LSINFINITY)) ? ea->u.data : LSINFINITY; u32 m1 = (ea && (ea->u.data < LSINFINITY)) ? ea->u.data : LSINFINITY;
...@@ -543,6 +546,7 @@ static void ...@@ -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) 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 proto_ospf *po = (struct proto_ospf *) p;
struct ospf_area *oa = ospf_main_area(po);
/* Temporarily down write anything /* Temporarily down write anything
OSPF_TRACE(D_EVENTS, "Got route %I/%d %s", p->name, n->n.prefix, 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 ...@@ -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 */ if (new) /* Got some new route */
originate_ext_lsa(n, new, po, attrs); originate_ext_lsa(oa, n, new, attrs);
else else
flush_ext_lsa(n, po); flush_ext_lsa(oa, n);
} }
static void static void
...@@ -605,7 +609,7 @@ ospf_get_route_info(rte * rte, byte * buf, ea_list * attrs UNUSED) ...@@ -605,7 +609,7 @@ ospf_get_route_info(rte * rte, byte * buf, ea_list * attrs UNUSED)
if (rte->attrs->source == RTS_OSPF_EXT2) if (rte->attrs->source == RTS_OSPF_EXT2)
buf += bsprintf(buf, "/%d", rte->u.ospf.metric2); buf += bsprintf(buf, "/%d", rte->u.ospf.metric2);
buf += bsprintf(buf, ")"); 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); buf += bsprintf(buf, " [%x]", rte->u.ospf.tag);
} }
...@@ -639,7 +643,7 @@ static void ...@@ -639,7 +643,7 @@ static void
ospf_area_reconfigure(struct ospf_area *oa, struct ospf_area_config *nac) ospf_area_reconfigure(struct ospf_area *oa, struct ospf_area_config *nac)
{ {
oa->ac = nac; oa->ac = nac;
oa->stub = nac->stub; // FIXME NSSA check type
ospf_ifaces_reconfigure(oa, nac); ospf_ifaces_reconfigure(oa, nac);
...@@ -797,7 +801,8 @@ ospf_sh(struct proto *p) ...@@ -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\tTransit:\t%s", oa->trcap ? "Yes" : "No");
cli_msg(-1014, "\t\tNumber of interfaces:\t%u", ifano); 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 neighbors:\t%u", nno);
...@@ -1096,7 +1101,8 @@ show_lsa_external(struct top_hash_entry *he) ...@@ -1096,7 +1101,8 @@ show_lsa_external(struct top_hash_entry *he)
int pxlen, ebit, rt_fwaddr_valid; int pxlen, ebit, rt_fwaddr_valid;
u32 rt_tag, rt_metric; 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; rt_metric = ext->metric & METRIC_MASK;
ebit = ext->metric & LSA_EXT_EBIT; ebit = ext->metric & LSA_EXT_EBIT;
...@@ -1130,8 +1136,9 @@ show_lsa_external(struct top_hash_entry *he) ...@@ -1130,8 +1136,9 @@ show_lsa_external(struct top_hash_entry *he)
if (rt_tag) if (rt_tag)
bsprintf(str_tag, " tag %08x", rt_tag); bsprintf(str_tag, " tag %08x", rt_tag);
cli_msg(-1016, "\t\texternal %I/%d metric%s %u%s%s", ip, pxlen, cli_msg(-1016, "\t\t%s %I/%d metric%s %u%s%s",
ebit ? "2" : "", rt_metric, str_via, str_tag); (he->lsa.type == LSA_T_NSSA) ? "nssa-ext" : "external",
ip, pxlen, ebit ? "2" : "", rt_metric, str_via, str_tag);
} }
#ifdef OSPFv3 #ifdef OSPFv3
...@@ -1206,6 +1213,7 @@ ospf_sh_state(struct proto *p, int verbose, int reachable) ...@@ -1206,6 +1213,7 @@ ospf_sh_state(struct proto *p, int verbose, int reachable)
case LSA_T_SUM_NET: case LSA_T_SUM_NET:
case LSA_T_SUM_RT: case LSA_T_SUM_RT:
case LSA_T_NSSA:
#ifdef OSPFv3 #ifdef OSPFv3
case LSA_T_PREFIX: case LSA_T_PREFIX:
#endif #endif
...@@ -1307,6 +1315,7 @@ ospf_sh_state(struct proto *p, int verbose, int reachable) ...@@ -1307,6 +1315,7 @@ ospf_sh_state(struct proto *p, int verbose, int reachable)
#endif #endif
case LSA_T_EXT: case LSA_T_EXT:
case LSA_T_NSSA:
show_lsa_external(he); show_lsa_external(he);
break; break;
} }
......
...@@ -123,7 +123,10 @@ struct ospf_area_config ...@@ -123,7 +123,10 @@ struct ospf_area_config
{ {
node n; node n;
u32 areaid; 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 patt_list;
list net_list; /* List of aggregate networks for that area */ list net_list; /* List of aggregate networks for that area */
list stubnet_list; /* List of stub networks added to Router LSA */ list stubnet_list; /* List of stub networks added to Router LSA */
...@@ -137,12 +140,14 @@ struct ospf_area_config ...@@ -137,12 +140,14 @@ struct ospf_area_config
#define OPT_DC 0x20 #define OPT_DC 0x20
#ifdef OSPFv2 #ifdef OSPFv2
#define OPT_P 0x08 /* flags P and N share position, see NSSA RFC */
#define OPT_EA 0x10 #define OPT_EA 0x10
/* VEB flags are are stored independently in 'u16 options' */ /* VEB flags are are stored independently in 'u16 options' */
#define OPT_RT_B (0x01 << 8) #define OPT_RT_B (0x01 << 8)
#define OPT_RT_E (0x02 << 8) #define OPT_RT_E (0x02 << 8)
#define OPT_RT_V (0x04 << 8) #define OPT_RT_V (0x04 << 8)
#define OPT_RT_NT (0x10 << 8)
#endif #endif
#ifdef OSPFv3 #ifdef OSPFv3
...@@ -363,6 +368,7 @@ struct ospf_lsa_header ...@@ -363,6 +368,7 @@ struct ospf_lsa_header
#define LSA_T_SUM_NET 3 #define LSA_T_SUM_NET 3
#define LSA_T_SUM_RT 4 #define LSA_T_SUM_RT 4
#define LSA_T_EXT 5 #define LSA_T_EXT 5
#define LSA_T_NSSA 7
#define LSA_SCOPE_AREA 0x2000 #define LSA_SCOPE_AREA 0x2000
#define LSA_SCOPE_AS 0x4000 #define LSA_SCOPE_AS 0x4000
...@@ -377,6 +383,7 @@ struct ospf_lsa_header ...@@ -377,6 +383,7 @@ struct ospf_lsa_header
#define LSA_T_SUM_NET 0x2003 #define LSA_T_SUM_NET 0x2003
#define LSA_T_SUM_RT 0x2004 #define LSA_T_SUM_RT 0x2004
#define LSA_T_EXT 0x4005 #define LSA_T_EXT 0x4005
#define LSA_T_NSSA 0x2007
#define LSA_T_LINK 0x0008 #define LSA_T_LINK 0x0008
#define LSA_T_PREFIX 0x2009 #define LSA_T_PREFIX 0x2009
...@@ -720,12 +727,11 @@ struct ospf_area ...@@ -720,12 +727,11 @@ struct ospf_area
{ {
node n; node n;
u32 areaid; 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 *rt; /* My own router LSA */
struct top_hash_entry *pxr_lsa; /* Originated prefix LSA */ struct top_hash_entry *pxr_lsa; /* Originated prefix LSA */
list cand; /* List of candidates for RT calc. */ list cand; /* List of candidates for RT calc. */
struct fib net_fib; /* Networks to advertise or not */ struct fib net_fib; /* Networks to advertise or not */
u32 stub; /* 0 or stub area cost */
u32 options; /* Optional features */ u32 options; /* Optional features */
byte origrt; /* Rt lsa origination scheduled? */ byte origrt; /* Rt lsa origination scheduled? */
byte trcap; /* Transit capability? */ byte trcap; /* Transit capability? */
...@@ -796,7 +802,6 @@ struct ospf_iface_patt ...@@ -796,7 +802,6 @@ struct ospf_iface_patt
#endif #endif
}; };
int ospf_import_control(struct proto *p, rte **new, ea_list **attrs, int ospf_import_control(struct proto *p, rte **new, ea_list **attrs,
struct linpool *pool); struct linpool *pool);
struct ea_list *ospf_make_tmp_attrs(struct rte *rt, 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); ...@@ -806,6 +811,16 @@ void schedule_rtcalc(struct proto_ospf *po);
void schedule_net_lsa(struct ospf_iface *ifa); void schedule_net_lsa(struct ospf_iface *ifa);
struct ospf_area *ospf_find_area(struct proto_ospf *po, u32 aid); 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 #ifdef OSPFv3
void schedule_link_lsa(struct ospf_iface *ifa); void schedule_link_lsa(struct ospf_iface *ifa);
......
...@@ -172,6 +172,8 @@ ri_better_ext(struct proto_ospf *po, orta *new, orta *old) ...@@ -172,6 +172,8 @@ ri_better_ext(struct proto_ospf *po, orta *new, orta *old)
if (new->metric1 > old->metric1) if (new->metric1 > old->metric1)
return 0; return 0;
/* RFC 3103, 2.5. (6e) - missing, is this necessary? */
return 0; return 0;
} }
...@@ -826,7 +828,8 @@ ospf_rt_sum_tr(struct ospf_area *oa) ...@@ -826,7 +828,8 @@ ospf_rt_sum_tr(struct ospf_area *oa)
static int static int
decide_anet_lsa(struct ospf_area *oa, struct area_net *anet, struct ospf_area *anet_oa) 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; return 0;
if (oa == anet_oa) if (oa == anet_oa)
...@@ -843,8 +846,8 @@ decide_anet_lsa(struct ospf_area *oa, struct area_net *anet, struct ospf_area *a ...@@ -843,8 +846,8 @@ decide_anet_lsa(struct ospf_area *oa, struct area_net *anet, struct ospf_area *a
static int static int
decide_sum_lsa(struct ospf_area *oa, ort *nf, int dest) 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 */ /* 12.4.3.1. - for stub/NSSA areas, originating summary routes is configurable */
if (oa->stub) if (!oa_is_ext(oa) && !oa->ac->summary)
return 0; return 0;
/* Invalid field - no route */ /* Invalid field - no route */
...@@ -872,7 +875,7 @@ decide_sum_lsa(struct ospf_area *oa, ort *nf, int dest) ...@@ -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) */ /* We call decide_sum_lsa() on preferred ASBR entries, no need for 16.4. (3) */
/* 12.4.3 p1 */ /* 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 */ /* 12.4.3 p7 - inter-area route */
...@@ -1048,21 +1051,25 @@ ospf_rt_abr(struct proto_ospf *po) ...@@ -1048,21 +1051,25 @@ ospf_rt_abr(struct proto_ospf *po)
WALK_LIST(oa, po->area_list) WALK_LIST(oa, po->area_list)
{ {
/* 12.4.3.1. - originate or flush default summary LSA for stub areas */ /* 12.4.3.1. - originate or flush default route for stub/NSSA areas */
if (oa->stub) if (oa_is_stub(oa) || (oa_is_nssa(oa) && !oa->ac->summary))
originate_sum_net_lsa(oa, &default_nf->fn, oa->stub); originate_sum_net_lsa(oa, &default_nf->fn, oa->ac->stub_cost);
else else
flush_sum_lsa(oa, &default_nf->fn, ORT_NET); 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 */ /* RFC 2328 16.4. (3) - precompute preferred ASBR entries */
FIB_WALK(&oa->rtr, nftmp) if (oa_is_ext(oa))
{ {
nf = (ort *) nftmp; FIB_WALK(&oa->rtr, nftmp)
if (nf->n.options & ORTA_ASBR) {
ri_install_asbr(po, &nf->fn.prefix, &nf->n); 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) ...@@ -1105,7 +1112,7 @@ ospf_ext_spf(struct proto_ospf *po)
struct top_hash_entry *en; struct top_hash_entry *en;
struct proto *p = &po->proto; struct proto *p = &po->proto;
struct ospf_lsa_ext *le; 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; ip_addr ip, rtid, rt_fwaddr;
u32 br_metric, rt_metric, rt_tag; u32 br_metric, rt_metric, rt_tag;
struct ospf_area *atmp; struct ospf_area *atmp;
...@@ -1116,7 +1123,7 @@ ospf_ext_spf(struct proto_ospf *po) ...@@ -1116,7 +1123,7 @@ ospf_ext_spf(struct proto_ospf *po)
WALK_SLIST(en, po->lsal) WALK_SLIST(en, po->lsal)
{ {
/* 16.4. (1) */ /* 16.4. (1) */
if (en->lsa.type != LSA_T_EXT) if ((en->lsa.type != LSA_T_EXT) && (en->lsa.type != LSA_T_NSSA))
continue; continue;
if (en->lsa.age == LSA_MAXAGE) if (en->lsa.age == LSA_MAXAGE)
...@@ -1143,6 +1150,7 @@ ospf_ext_spf(struct proto_ospf *po) ...@@ -1143,6 +1150,7 @@ ospf_ext_spf(struct proto_ospf *po)
rt_fwaddr = le->fwaddr; rt_fwaddr = le->fwaddr;
rt_fwaddr_valid = !ipa_equal(rt_fwaddr, IPA_NONE); rt_fwaddr_valid = !ipa_equal(rt_fwaddr, IPA_NONE);
rt_tag = le->tag; rt_tag = le->tag;
rt_propagate = en->lsa.options & OPT_P;
#else /* OSPFv3 */ #else /* OSPFv3 */
u8 pxopts; u8 pxopts;
u16 rest; u16 rest;
...@@ -1162,6 +1170,8 @@ ospf_ext_spf(struct proto_ospf *po) ...@@ -1162,6 +1170,8 @@ ospf_ext_spf(struct proto_ospf *po)
rt_tag = *buf++; rt_tag = *buf++;
else else
rt_tag = 0; rt_tag = 0;
rt_propagate = pxopts & OPT_PX_P;
#endif #endif
if (pxlen < 0 || pxlen > MAX_PREFIX_LENGTH) if (pxlen < 0 || pxlen > MAX_PREFIX_LENGTH)
...@@ -1171,10 +1181,19 @@ ospf_ext_spf(struct proto_ospf *po) ...@@ -1171,10 +1181,19 @@ ospf_ext_spf(struct proto_ospf *po)
continue; continue;
} }
/* 16.4. (3) */ /* 16.4. (3) */
/* If there are more areas, we already precomputed preferred ASBR entries /* If there are more areas, we already precomputed preferred ASBR
in ospf_asbr_spf() and stored them in the backbone table */ entries in ospf_rt_abr() and stored them in the backbone
atmp = (po->areano > 1) ? po->backbone : HEAD(po->area_list); 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); rtid = ipa_from_rid(en->lsa.rt);
nf1 = fib_find(&atmp->rtr, &rtid, MAX_PREFIX_LENGTH); nf1 = fib_find(&atmp->rtr, &rtid, MAX_PREFIX_LENGTH);
...@@ -1184,6 +1203,12 @@ ospf_ext_spf(struct proto_ospf *po) ...@@ -1184,6 +1203,12 @@ ospf_ext_spf(struct proto_ospf *po)
if (!(nf1->n.options & ORTA_ASBR)) if (!(nf1->n.options & ORTA_ASBR))
continue; /* It is not 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) if (!rt_fwaddr_valid)
{ {
nf2 = nf1; nf2 = nf1;
...@@ -1196,8 +1221,18 @@ ospf_ext_spf(struct proto_ospf *po) ...@@ -1196,8 +1221,18 @@ ospf_ext_spf(struct proto_ospf *po)
if (!nf2) if (!nf2)
continue; continue;
if ((nf2->n.type != RTS_OSPF) && (nf2->n.type != RTS_OSPF_IA)) if (en->lsa.type == LSA_T_EXT)
continue; {
/* 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 */ /* Next-hop is a part of a configured stubnet */
if (!nf2->n.nhs) if (!nf2->n.nhs)
...@@ -1317,10 +1352,7 @@ ospf_rt_spf(struct proto_ospf *po) ...@@ -1317,10 +1352,7 @@ ospf_rt_spf(struct proto_ospf *po)
ospf_rt_spfa(oa); ospf_rt_spfa(oa);
/* 16. (3) */ /* 16. (3) */
if (po->areano == 1) ospf_rt_sum(ospf_main_area(po));
ospf_rt_sum(HEAD(po->area_list));
else
ospf_rt_sum(po->backbone);
/* 16. (4) */ /* 16. (4) */
WALK_LIST(oa, po->area_list) WALK_LIST(oa, po->area_list)
......
...@@ -222,7 +222,7 @@ originate_rt_lsa_body(struct ospf_area *oa, u16 *length) ...@@ -222,7 +222,7 @@ originate_rt_lsa_body(struct ospf_area *oa, u16 *length)
if (po->areano > 1) if (po->areano > 1)
rt->options |= OPT_RT_B; rt->options |= OPT_RT_B;
if ((po->ebit) && (!oa->stub)) if (po->ebit && !oa_is_stub(oa))
rt->options |= OPT_RT_E; rt->options |= OPT_RT_E;
rt = NULL; /* buffer might be reallocated later */ rt = NULL; /* buffer might be reallocated later */
...@@ -388,7 +388,7 @@ originate_rt_lsa_body(struct ospf_area *oa, u16 *length) ...@@ -388,7 +388,7 @@ originate_rt_lsa_body(struct ospf_area *oa, u16 *length)
if (po->areano > 1) if (po->areano > 1)
rt->options |= OPT_RT_B; rt->options |= OPT_RT_B;
if ((po->ebit) && (!oa->stub)) if (po->ebit && !oa_is_stub(oa))
rt->options |= OPT_RT_E; rt->options |= OPT_RT_E;
rt = NULL; /* buffer might be reallocated later */ 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 ...@@ -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 * originate_ext_lsa - new route received from nest and filters
* @oa: ospf_area for which LSA is originated
* @n: network prefix and mask * @n: network prefix and mask
* @e: rte * @e: rte
* @po: current instance of OSPF
* @attrs: list of extended attributes * @attrs: list of extended attributes