]> git.ipfire.org Git - thirdparty/bird.git/commitdiff
OSPF: Basic support for DN-bit handling (RFC 4576)
authorOndrej Zajicek (work) <santiago@crfreenet.org>
Wed, 13 Feb 2019 14:40:22 +0000 (15:40 +0100)
committerOndrej Zajicek (work) <santiago@crfreenet.org>
Wed, 13 Feb 2019 14:53:36 +0000 (15:53 +0100)
External LSAs originated by OSPF routers with VPN-PE behavior enabled are
marked by DN flag and they are ignored by other OSPF routers with VPN-PE
enabled.

proto/ospf/config.Y
proto/ospf/lsalib.c
proto/ospf/ospf.c
proto/ospf/ospf.h
proto/ospf/rt.c
proto/ospf/topology.c
proto/ospf/topology.h

index 2ec9babeb86e73aacf90697955fcc2f832f30490..36fbd5f1fc9fa24b00a66300aa45ac334f39e3f8 100644 (file)
@@ -199,7 +199,7 @@ CF_KEYWORDS(ELIGIBLE, POLL, NETWORKS, HIDDEN, VIRTUAL, CHECK, LINK, ONLY, BFD)
 CF_KEYWORDS(RX, BUFFER, LARGE, NORMAL, STUBNET, HIDDEN, SUMMARY, TAG, EXTERNAL)
 CF_KEYWORDS(WAIT, DELAY, LSADB, ECMP, LIMIT, WEIGHT, NSSA, TRANSLATOR, STABILITY)
 CF_KEYWORDS(GLOBAL, LSID, ROUTER, SELF, INSTANCE, REAL, NETMASK, TX, PRIORITY, LENGTH)
-CF_KEYWORDS(MERGE, LSA, SUPPRESSION, MULTICAST, RFC5838)
+CF_KEYWORDS(MERGE, LSA, SUPPRESSION, MULTICAST, RFC5838, VPN, PE)
 
 %type <ld> lsadb_args
 %type <i> ospf_variant ospf_af_mc nbma_eligible
@@ -256,6 +256,7 @@ ospf_proto_item:
  | ospf_channel { this_proto->net_type = $1->net_type; }
  | RFC1583COMPAT bool { OSPF_CFG->rfc1583 = $2; }
  | RFC5838 bool { OSPF_CFG->af_ext = $2; if (!ospf_cfg_is_v3()) cf_error("RFC5838 option requires OSPFv3"); }
+ | VPN PE bool { OSPF_CFG->vpn_pe = $3; }
  | STUB ROUTER bool { OSPF_CFG->stub_router = $3; }
  | ECMP bool { OSPF_CFG->ecmp = $2 ? OSPF_DEFAULT_ECMP_LIMIT : 0; }
  | ECMP bool LIMIT expr { OSPF_CFG->ecmp = $2 ? $4 : 0; }
index e66d3dc05be78c2e05449a5a4134334520be2cb0..7ddf64e3c9353ba4574d643d97fdec505e9c73c2 100644 (file)
@@ -336,9 +336,10 @@ lsa_parse_sum_net(struct top_hash_entry *en, int ospf2, int af, net_addr *net, u
 {
   if (ospf2)
   {
+    uint opts = lsa_get_options(&en->lsa);
     struct ospf_lsa_sum2 *ls = en->lsa_body;
     net_fill_ip4(net, ip4_from_u32(en->lsa.id & ls->netmask), u32_masklen(ls->netmask));
-    *pxopts = 0;
+    *pxopts = (opts & OPT_DN) ? OPT_PX_DN : 0;
     *metric = ls->metric & LSA_METRIC_MASK;
   }
   else
@@ -386,6 +387,7 @@ lsa_parse_ext(struct top_hash_entry *en, int ospf2, int af, struct ospf_lsa_ext_
 
     rt->tag = ext->tag;
     rt->propagate = lsa_get_options(&en->lsa) & OPT_P;
+    rt->downwards = lsa_get_options(&en->lsa) & OPT_DN;
   }
   else
   {
@@ -402,6 +404,7 @@ lsa_parse_ext(struct top_hash_entry *en, int ospf2, int af, struct ospf_lsa_ext_
 
     rt->tag = (ext->metric & LSA_EXT3_TBIT) ? *buf++ : 0;
     rt->propagate = rt->pxopts & OPT_PX_P;
+    rt->downwards = rt->pxopts & OPT_PX_DN;
   }
 }
 
index 735006041e47001285e4e6712bd0380e3c3fb3c2..4fdcac58a2a6ddfd03ab9382e7f47e3aa277af0d 100644 (file)
@@ -92,6 +92,7 @@
  * - RFC 2328 - main OSPFv2 standard
  * - RFC 5340 - main OSPFv3 standard
  * - RFC 3101 - OSPFv2 NSSA areas
+ * - RFC 4576 - OSPFv2 VPN loop prevention
  * - RFC 5250 - OSPFv2 Opaque LSAs
  * - RFC 5709 - OSPFv2 HMAC-SHA Cryptographic Authentication
  * - RFC 5838 - OSPFv3 Support of Address Families
@@ -243,6 +244,7 @@ ospf_start(struct proto *P)
   p->merge_external = c->merge_external;
   p->instance_id = c->instance_id;
   p->asbr = c->asbr;
+  p->vpn_pe = c->vpn_pe;
   p->ecmp = c->ecmp;
   p->tick = c->tick;
   p->disp_timer = tm_new_init(P->pool, ospf_disp, p, p->tick S, 0);
@@ -657,6 +659,9 @@ ospf_reconfigure(struct proto *P, struct proto_config *CF)
   if (old->abr != new->abr)
     return 0;
 
+  if (old->vpn_pe != new->vpn_pe)
+    return 0;
+
   if ((p->af_ext != new->af_ext) || (p->af_mc != new->af_mc))
     return 0;
 
index d3f12738907d6815c87be7c04a1a620300360543..7fac47c8e4b908c36da29248fd3f8ea20ef333c6 100644 (file)
@@ -96,6 +96,7 @@ struct ospf_config
   u8 instance_id_set;
   u8 abr;
   u8 asbr;
+  u8 vpn_pe;
   int ecmp;
   list area_list;              /* list of area configs (struct ospf_area_config) */
   list vlink_list;             /* list of configured vlinks (struct ospf_iface_patt) */
@@ -225,6 +226,7 @@ struct ospf_proto
   u8 merge_external;           /* Should i merge external routes? */
   u8 instance_id;              /* Differentiate between more OSPF instances */
   u8 asbr;                     /* May i originate any ext/NSSA lsa? */
+  u8 vpn_pe;                   /* Should we do VPN PE specific behavior (RFC 4577)? */
   u8 ecmp;                     /* Maximal number of nexthops in ECMP route, or 0 */
   u64 csn64;                   /* Last used cryptographic sequence number */
   struct ospf_area *backbone;  /* If exists */
@@ -467,6 +469,7 @@ struct ospf_neighbor
 #define OPT_R          0x0010  /* OSPFv3, originator is active router */
 #define OPT_DC         0x0020  /* Related to demand circuits, not used */
 #define OPT_O          0x0040  /* OSPFv2 Opaque LSA (RFC 5250) */
+#define OPT_DN         0x0080  /* OSPFv2 VPN loop prevention (RFC 4576)*/
 #define OPT_AF         0x0100  /* OSPFv3 Address Families (RFC 5838) */
 #define OPT_L_V3       0x0200  /* OSPFv3, link-local signaling */
 #define OPT_AT          0x0400 /* OSPFv3, authentication trailer */
@@ -736,7 +739,7 @@ struct ospf_lsa_ext_local
 {
   net_addr net;
   ip_addr fwaddr;
-  u32 metric, ebit, fbit, tag, propagate;
+  u32 metric, ebit, fbit, tag, propagate, downwards;
   u8 pxopts;
 };
 
index 4549ce2a227e0203614c2643a36e97f49b345964..c580d06e51c436de30466df60900f31f75de6db0 100644 (file)
@@ -782,6 +782,10 @@ ospf_rt_sum(struct ospf_area *oa)
       if (pxopts & OPT_PX_NU)
        continue;
 
+      /* RFC 4576 4 - do not use LSAs with DN-bit on PE-routers */
+      if (p->vpn_pe && (pxopts & OPT_PX_DN))
+       continue;
+
       options = 0;
       type = ORT_NET;
     }
@@ -879,6 +883,10 @@ ospf_rt_sum_tr(struct ospf_area *oa)
       if (pxopts & OPT_PX_NU)
        continue;
 
+      /* RFC 4576 4 - do not use LSAs with DN-bit on PE-routers */
+      if (p->vpn_pe && (pxopts & OPT_PX_DN))
+       continue;
+
       re = fib_find(&p->rtf, &net);
     }
     else // en->lsa_type == LSA_T_SUM_RT
@@ -1104,11 +1112,11 @@ check_nssa_lsa(struct ospf_proto *p, ort *nf)
   /* RFC 3101 3.2 (3) - originate the aggregated address range */
   if (anet && anet->active && !anet->hidden && oa->translate)
     ospf_originate_ext_lsa(p, NULL, nf, LSA_M_RTCALC, anet->metric,
-                          (anet->metric & LSA_EXT3_EBIT), IPA_NONE, anet->tag, 0);
+                          (anet->metric & LSA_EXT3_EBIT), IPA_NONE, anet->tag, 0, 0);
 
   /* RFC 3101 3.2 (2) - originate the same network */
   else if (decide_nssa_lsa(p, nf, &rt))
-    ospf_originate_ext_lsa(p, NULL, nf, LSA_M_RTCALC, rt.metric, rt.ebit, rt.fwaddr, rt.tag, 0);
+    ospf_originate_ext_lsa(p, NULL, nf, LSA_M_RTCALC, rt.metric, rt.ebit, rt.fwaddr, rt.tag, 0, 0);
 }
 
 /* RFC 2328 16.7. p2 - find new/lost vlink endpoints */
@@ -1238,7 +1246,7 @@ ospf_rt_abr1(struct ospf_proto *p)
 
     if (oa_is_nssa(oa) && oa->ac->default_nssa)
       ospf_originate_ext_lsa(p, oa, default_nf, LSA_M_RTCALC, oa->ac->default_cost,
-                            (oa->ac->default_cost & LSA_EXT3_EBIT), IPA_NONE, 0, 0);
+                            (oa->ac->default_cost & LSA_EXT3_EBIT), IPA_NONE, 0, 0, 0);
 
     /* RFC 2328 16.4. (3) - precompute preferred ASBR entries */
     if (oa_is_ext(oa))
@@ -1474,6 +1482,10 @@ ospf_ext_spf(struct ospf_proto *p)
     if (rt.pxopts & OPT_PX_NU)
       continue;
 
+    /* RFC 4576 4 - do not use LSAs with DN-bit on PE-routers */
+    if (p->vpn_pe && rt.downwards)
+      continue;
+
     /* 16.4. (3) */
     /* If there are more areas, we already precomputed preferred ASBR
        entries in ospf_rt_abr1() and stored them in the backbone
index 40b511deeac2d099ce008542c596b1d6b7fffb30..7d5deca01099ab747248405c842da27855a2b79a 100644 (file)
@@ -1097,7 +1097,7 @@ prepare_ext2_lsa_body(struct ospf_proto *p, uint pxlen,
 
 static inline void
 prepare_ext3_lsa_body(struct ospf_proto *p, ort *nf,
-                     u32 metric, u32 ebit, ip_addr fwaddr, u32 tag, int pbit)
+                     u32 metric, u32 ebit, ip_addr fwaddr, u32 tag, int pbit, int dn)
 {
   struct ospf_lsa_ext3 *ext;
   int bsize = sizeof(struct ospf_lsa_ext3)
@@ -1109,7 +1109,8 @@ prepare_ext3_lsa_body(struct ospf_proto *p, ort *nf,
   ext->metric = metric & LSA_METRIC_MASK;
   u32 *buf = ext->rest;
 
-  buf = ospf3_put_prefix(buf, nf->fn.addr, pbit ? OPT_PX_P : 0, 0);
+  uint flags = (pbit ? OPT_PX_P : 0) | (dn ? OPT_PX_DN : 0);
+  buf = ospf3_put_prefix(buf, nf->fn.addr, flags, 0);
 
   if (ebit)
     ext->metric |= LSA_EXT3_EBIT;
@@ -1147,21 +1148,21 @@ prepare_ext3_lsa_body(struct ospf_proto *p, ort *nf,
  */
 void
 ospf_originate_ext_lsa(struct ospf_proto *p, struct ospf_area *oa, ort *nf, u8 mode,
-                      u32 metric, u32 ebit, ip_addr fwaddr, u32 tag, int pbit)
+                      u32 metric, u32 ebit, ip_addr fwaddr, u32 tag, int pbit, int dn)
 {
   struct ospf_new_lsa lsa = {
     .type = oa ? LSA_T_NSSA : LSA_T_EXT,
     .mode = mode, /* LSA_M_EXPORT or LSA_M_RTCALC */
     .dom  = oa ? oa->areaid : 0,
     .id   = ort_to_lsaid(p, nf),
-    .opts = oa ? (pbit ? OPT_P : 0) : OPT_E,
+    .opts = (oa ? (pbit ? OPT_P : 0) : OPT_E) | (dn ? OPT_DN : 0),
     .nf   = nf
   };
 
   if (ospf_is_v2(p))
     prepare_ext2_lsa_body(p, nf->fn.addr->pxlen, metric, ebit, fwaddr, tag);
   else
-    prepare_ext3_lsa_body(p, nf, metric, ebit, fwaddr, tag, oa && pbit);
+    prepare_ext3_lsa_body(p, nf, metric, ebit, fwaddr, tag, oa && pbit, dn);
 
   ospf_originate_lsa(p, &lsa);
 }
@@ -1337,7 +1338,7 @@ ospf_rt_notify(struct proto *P, struct channel *ch UNUSED, net *n, rte *new, rte
   }
 
   nf = fib_get(&p->rtf, n->n.addr);
-  ospf_originate_ext_lsa(p, oa, nf, LSA_M_EXPORT, metric, ebit, fwd, tag, 1);
+  ospf_originate_ext_lsa(p, oa, nf, LSA_M_EXPORT, metric, ebit, fwd, tag, 1, p->vpn_pe);
   nf->external_rte = 1;
 }
 
index 54ec9ccffccc61ce0658090cc8392a586515d748..fd70239da98a5ffbbe0535dae740a84a2efcf4b3 100644 (file)
@@ -186,7 +186,7 @@ static inline void ospf_flush2_lsa(struct ospf_proto *p, struct top_hash_entry *
 
 void ospf_originate_sum_net_lsa(struct ospf_proto *p, struct ospf_area *oa, ort *nf, int metric);
 void ospf_originate_sum_rt_lsa(struct ospf_proto *p, struct ospf_area *oa, u32 drid, int metric, u32 options);
-void ospf_originate_ext_lsa(struct ospf_proto *p, struct ospf_area *oa, ort *nf, u8 mode, u32 metric, u32 ebit, ip_addr fwaddr, u32 tag, int pbit);
+void ospf_originate_ext_lsa(struct ospf_proto *p, struct ospf_area *oa, ort *nf, u8 mode, u32 metric, u32 ebit, ip_addr fwaddr, u32 tag, int pbit, int dn);
 
 void ospf_rt_notify(struct proto *P, struct channel *ch, net *n, rte *new, rte *old);
 void ospf_update_topology(struct ospf_proto *p);