]> git.ipfire.org Git - thirdparty/bird.git/commitdiff
OSPF NSSA support, inter-area LSA translation.
authorOndrej Zajicek <santiago@crfreenet.org>
Sun, 7 Aug 2011 23:45:31 +0000 (01:45 +0200)
committerOndrej Zajicek <santiago@crfreenet.org>
Sun, 7 Aug 2011 23:45:31 +0000 (01:45 +0200)
proto/ospf/config.Y
proto/ospf/ospf.c
proto/ospf/ospf.h
proto/ospf/rt.c
proto/ospf/rt.h
proto/ospf/topology.c
proto/ospf/topology.h

index 1099b729388aa825178cbd0e7c7d794f284d777c..e48f46029fbc257585240eb5f41f650f7b34a524 100644 (file)
@@ -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 */
index 83bcad75d370a0c4df4c2ec408ce6e93f930fc2d..ed49a599468147d7d49ab38b738569a522363fa4 100644 (file)
@@ -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, "");
 }
index 68c19424dea00211b73f3849ab41d5f00915b304..2a7d3c1f9f5315ce2c66a416b421d2c286c10a78 100644 (file)
@@ -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? */
index 71acd8be88137ec175dbaac39347adcc1d3b27de..22638527f903b60a6cc7a265e1ea1e69fa44917a 100644 (file)
@@ -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);
index bf234f589af5830e414648c1c5789aeb31725463..cb4b652dff3b5646b31aa3c4ed515422cd1ded70 100644 (file)
@@ -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):
index f5f041eb254cb744c04d248c057b3a961d5d44b3..8df71b03f2b862ecfe373b765103291a9ad932fb 100644 (file)
@@ -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 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);
     }
 }
index 137f1fd96aa0a80819a0d9b83d0619d3ab279436..a1c0cbfe2b63471577d0861ba0736acc8aba2a8a 100644 (file)
@@ -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