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