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