OSPF NSSA support, part one.
This commit is contained in:
parent
9008579b97
commit
41b612c31b
9 changed files with 147 additions and 73 deletions
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
||||||
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)
|
||||||
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 {
|
||||||
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:
|
||||||
;
|
;
|
||||||
|
|
||||||
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,
|
||||||
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)
|
||||||
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
|
||||||
{
|
{
|
||||||
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)
|
||||||
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,
|
||||||
|
|
||||||
#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)
|
||||||
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)
|
||||||
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
|
||||||
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
|
||||||
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
|
||||||
*/
|
*/
|
||||||
|
|
||||||
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)
|
||||||
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
|
||||||
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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
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,6 +1101,7 @@ 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;
|
||||||
|
|
||||||
|
if (he->lsa.type == LSA_T_EXT)
|
||||||
he->domain = 0; /* Unmark the LSA */
|
he->domain = 0; /* Unmark the LSA */
|
||||||
|
|
||||||
rt_metric = ext->metric & METRIC_MASK;
|
rt_metric = ext->metric & METRIC_MASK;
|
||||||
|
@ -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)
|
||||||
|
|
||||||
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)
|
||||||
#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
|
||||||
{
|
{
|
||||||
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
|
||||||
#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
|
||||||
#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
|
||||||
#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
|
||||||
{
|
{
|
||||||
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
|
||||||
#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);
|
||||||
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)
|
||||||
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)
|
||||||
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
|
||||||
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)
|
||||||
{
|
{
|
||||||
/* 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,14 +1051,17 @@ 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 */
|
||||||
|
if (oa_is_ext(oa))
|
||||||
|
{
|
||||||
FIB_WALK(&oa->rtr, nftmp)
|
FIB_WALK(&oa->rtr, nftmp)
|
||||||
{
|
{
|
||||||
nf = (ort *) nftmp;
|
nf = (ort *) nftmp;
|
||||||
|
@ -1064,6 +1070,7 @@ ospf_rt_abr(struct proto_ospf *po)
|
||||||
}
|
}
|
||||||
FIB_WALK_END;
|
FIB_WALK_END;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Originate or flush ASBR summary LSAs */
|
/* Originate or flush ASBR summary LSAs */
|
||||||
|
@ -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)
|
||||||
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)
|
||||||
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)
|
||||||
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)
|
||||||
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)
|
||||||
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)
|
||||||
if (!nf2)
|
if (!nf2)
|
||||||
continue;
|
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))
|
if ((nf2->n.type != RTS_OSPF) && (nf2->n.type != RTS_OSPF_IA))
|
||||||
continue;
|
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)
|
||||||
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)
|
||||||
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)
|
||||||
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
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 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
|
||||||
*
|
*
|
||||||
* If I receive a message that new route is installed, I try to originate an
|
* If I receive a message that new route is installed, I try to originate an
|
||||||
* external LSA.
|
* 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
|
* The function also sets flag ebit. If it's the first time, the new router lsa
|
||||||
* origination is necessary.
|
* origination is necessary.
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
originate_ext_lsa(net * n, rte * e, struct proto_ospf *po,
|
originate_ext_lsa(struct ospf_area *oa, net *n, rte *e, struct ea_list *attrs)
|
||||||
struct ea_list *attrs)
|
|
||||||
{
|
{
|
||||||
|
struct proto_ospf *po = oa->po;
|
||||||
struct proto *p = &po->proto;
|
struct proto *p = &po->proto;
|
||||||
struct fib_node *fn = &n->n;
|
struct fib_node *fn = &n->n;
|
||||||
struct ospf_lsa_header lsa;
|
struct ospf_lsa_header lsa;
|
||||||
struct top_hash_entry *en = NULL;
|
struct top_hash_entry *en = NULL;
|
||||||
void *body;
|
void *body;
|
||||||
struct ospf_area *oa;
|
int nssa = oa_is_nssa(oa);
|
||||||
|
u32 dom = nssa ? oa->areaid : 0;
|
||||||
|
|
||||||
OSPF_TRACE(D_EVENTS, "Originating AS-external-LSA for %I/%d",
|
// FIXME NSSA - handle P bit
|
||||||
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;
|
lsa.age = 0;
|
||||||
#ifdef OSPFv2
|
#ifdef OSPFv2
|
||||||
lsa.options = 0; /* or oa->options ? */
|
lsa.options = oa->options;
|
||||||
#endif
|
#endif
|
||||||
lsa.type = LSA_T_EXT;
|
lsa.type = nssa ? LSA_T_NSSA : LSA_T_EXT;
|
||||||
lsa.id = fibnode_to_lsaid(po, fn);
|
lsa.id = fibnode_to_lsaid(po, fn);
|
||||||
lsa.rt = po->router_id;
|
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))
|
(ospf_iface_find((struct proto_ospf *) p, e->attrs->iface) != NULL))
|
||||||
gw = e->attrs->gw;
|
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);
|
int rv = check_ext_lsa(en, fn, metric, gw, tag);
|
||||||
if (rv < 0)
|
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);
|
body = originate_ext_lsa_body(po, &lsa.length, n, metric, gw, tag);
|
||||||
lsasum_calculate(&lsa, body);
|
lsasum_calculate(&lsa, body);
|
||||||
|
|
||||||
en = lsa_install_new(po, &lsa, 0, body);
|
en = lsa_install_new(po, &lsa, dom, body);
|
||||||
ospf_lsupd_flood(po, NULL, NULL, &lsa, 0, 1);
|
ospf_lsupd_flood(po, NULL, NULL, &lsa, dom, 1);
|
||||||
|
|
||||||
if (po->ebit == 0)
|
if (po->ebit == 0)
|
||||||
{
|
{
|
||||||
|
@ -1067,18 +1076,22 @@ originate_ext_lsa(net * n, rte * e, struct proto_ospf *po,
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
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 proto *p = &po->proto;
|
||||||
struct fib_node *fn = &n->n;
|
struct fib_node *fn = &n->n;
|
||||||
struct top_hash_entry *en;
|
struct top_hash_entry *en;
|
||||||
|
int nssa = oa_is_nssa(oa);
|
||||||
|
|
||||||
OSPF_TRACE(D_EVENTS, "Flushing AS-external-LSA for %I/%d",
|
OSPF_TRACE(D_EVENTS, "Flushing %s-LSA for %I/%d",
|
||||||
fn->prefix, fn->pxlen);
|
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);
|
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)
|
if (check_ext_lsa(en, fn, 0, IPA_NONE, 0) < 0)
|
||||||
{
|
{
|
||||||
|
|
|
@ -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 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 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,
|
void originate_ext_lsa(struct ospf_area *oa, net *n, rte *e, struct ea_list *attrs);
|
||||||
struct ea_list *attrs);
|
void flush_ext_lsa(struct ospf_area *oa, net *n);
|
||||||
void flush_ext_lsa(net *n, struct proto_ospf *po);
|
|
||||||
|
|
||||||
|
|
||||||
#ifdef OSPFv2
|
#ifdef OSPFv2
|
||||||
|
|
Loading…
Reference in a new issue