mirror of
https://gitlab.nic.cz/labs/bird.git
synced 2024-11-09 12:48:43 +00:00
OSPF NSSA support, inter-area LSA translation.
This commit is contained in:
parent
aca0e79faa
commit
ed317862c2
@ -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 */
|
||||
|
@ -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, "");
|
||||
}
|
||||
|
@ -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? */
|
||||
|
242
proto/ospf/rt.c
242
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);
|
||||
|
@ -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):
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user