]> git.ipfire.org Git - thirdparty/bird.git/commitdiff
OSPF NSSA support, part one.
authorOndrej Zajicek <santiago@crfreenet.org>
Wed, 20 Jul 2011 21:40:20 +0000 (23:40 +0200)
committerOndrej Zajicek <santiago@crfreenet.org>
Wed, 20 Jul 2011 21:48:06 +0000 (23:48 +0200)
proto/ospf/config.Y
proto/ospf/hello.c
proto/ospf/lsalib.c
proto/ospf/lsupd.c
proto/ospf/ospf.c
proto/ospf/ospf.h
proto/ospf/rt.c
proto/ospf/topology.c
proto/ospf/topology.h

index f3a87d66b4902021cc14fadbd8cc575ea443bca5..35060aa74b6d9c06efe29949bb6b8b7446677782 100644 (file)
@@ -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
index 0a94e4cb405484b123a47724e507cf350fd7770b..d04cb54c097410e29ae9e46eb369be3ab77455f4 100644 (file)
@@ -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;
   }
 
index 5e227da532c47ca66fb5a2f7486a072b10847455..538a73033012ac4aeb4491c698f137e91d04b325 100644 (file)
@@ -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:
index b69d861d3860362a49466cbc0c57fee281c2d0e3..948f45812cc6064aba462757843b1dd16b80e463 100644 (file)
@@ -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;
index ce913f7b4f51e5b5aeb809419a2b6a5ab1db0387..320f45774f134e76963192b01f23d6d1c733cc98 100644 (file)
@@ -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;
     }
index 664bc48fc3964be68027ce14b7bc33a181b42a61..a8b4a980cf733c7c02e8cc3f5525dffb0fd985bd 100644 (file)
@@ -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);
index 78b1ebecdd815d91242d09aa4f7d24795b55c773..e8d661cdf13bd4542a5cc479af7fd24db04202bc 100644 (file)
@@ -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)
index 78d88592538f596ecd4e54cbc336eb3bc447a0b3..54bc09cb6e0950963a64d4f9076ffbb8ef4b27f7 100644 (file)
@@ -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)
        {
index 9521e3eb322ed8621856191b796730070694b1c0..137f1fd96aa0a80819a0d9b83d0619d3ab279436 100644 (file)
@@ -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