]> git.ipfire.org Git - thirdparty/bird.git/commitdiff
OSPF: Opaque LSAs and Router Information LSA
authorOndrej Zajicek (work) <santiago@crfreenet.org>
Thu, 24 Jan 2019 21:34:33 +0000 (22:34 +0100)
committerOndrej Zajicek (work) <santiago@crfreenet.org>
Thu, 24 Jan 2019 21:45:27 +0000 (22:45 +0100)
Add support for OSPFv2 Opaque LSAs (RFC 5250) and for Router Information
LSA (RFC 7770). The second part is here mainly for testing opaque LSAs.

lib/birdlib.h
proto/ospf/dbdes.c
proto/ospf/lsalib.c
proto/ospf/lsalib.h
proto/ospf/lsreq.c
proto/ospf/lsupd.c
proto/ospf/ospf.c
proto/ospf/ospf.h
proto/ospf/topology.c

index 428b3209ff8c542ad4c8a1d39de79cfd00c3d776..7cd78032fbc37423d693415aae14a733f342fd47 100644 (file)
@@ -56,6 +56,13 @@ static inline int u64_cmp(u64 i1, u64 i2)
 #define BIT32_CLR(b,p)         ((b)[(p)/32] &= ~BIT32_VAL(p))
 #define BIT32_ZERO(b,l)                memset((b), 0, (l)/8)
 
+/* The same, but counting bits from MSB */
+#define BIT32R_VAL(p)          ((((u32) 1) << 31) >> ((p) % 32))
+#define BIT32R_TEST(b,p)       ((b)[(p)/32] & BIT32R_VAL(p))
+#define BIT32R_SET(b,p)                ((b)[(p)/32] |= BIT32R_VAL(p))
+#define BIT32R_CLR(b,p)                ((b)[(p)/32] &= ~BIT32R_VAL(p))
+#define BIT32R_ZERO(b,l)       memset((b), 0, (l)/8)
+
 #ifndef NULL
 #define NULL ((void *) 0)
 #endif
index 019aff047e21fa0e7209f7114947df11f4d77a76..34665dad8539864796e50cfb0b0db5e76167cc6e 100644 (file)
@@ -127,7 +127,7 @@ ospf_prepare_dbdes(struct ospf_proto *p, struct ospf_neighbor *n)
   {
     struct ospf_dbdes2_packet *ps = (void *) pkt;
     ps->iface_mtu = htons(iface_mtu);
-    ps->options = ifa->oa->options;
+    ps->options = ifa->oa->options | OPT_O;
     ps->imms = 0;      /* Will be set later */
     ps->ddseq = htonl(n->dds);
     length = sizeof(struct ospf_dbdes2_packet);
@@ -162,7 +162,8 @@ ospf_prepare_dbdes(struct ospf_proto *p, struct ospf_neighbor *n)
       }
 
       if ((en->lsa.age < LSA_MAXAGE) &&
-         lsa_flooding_allowed(en->lsa_type, en->domain, ifa))
+         lsa_flooding_allowed(en->lsa_type, en->domain, ifa) &&
+         lsa_is_acceptable(en->lsa_type, n, p))
       {
        lsa_hton_hdr(&(en->lsa), lsas + i);
        i++;
index fbfd8d295189e37b89d15fd9aae00332b649d53b..e66d3dc05be78c2e05449a5a4134334520be2cb0 100644 (file)
@@ -91,6 +91,30 @@ lsa_flooding_allowed(u32 type, u32 domain, struct ospf_iface *ifa)
   }
 }
 
+int
+lsa_is_acceptable(u32 type, struct ospf_neighbor *n, struct ospf_proto *p)
+{
+  if (ospf_is_v2(p))
+  {
+    if (type == LSA_T_NSSA)
+      return !!(n->options & OPT_N);
+
+    if (lsa_is_opaque(type))
+      return !!(n->options & OPT_O);
+
+    return 1;
+  }
+  else
+  {
+    /*
+     * There should be check whether receiving router understands that type
+     * of LSA (for LSA types with U-bit == 0). But as we do not support any
+     * optional LSA types, this is not needed yet.
+     */
+
+    return 1;
+  }
+}
 
 static int
 unknown_lsa_type(u32 type)
@@ -105,6 +129,9 @@ unknown_lsa_type(u32 type)
   case LSA_T_NSSA:
   case LSA_T_LINK:
   case LSA_T_PREFIX:
+  case LSA_T_RI_LINK:
+  case LSA_T_RI_AREA:
+  case LSA_T_RI_AS:
     return 0;
 
   default:
@@ -112,28 +139,47 @@ unknown_lsa_type(u32 type)
   }
 }
 
-#define LSA_V2_TMAX 8
-static const u16 lsa_v2_types[LSA_V2_TMAX] =
-  {0, LSA_T_RT, LSA_T_NET, LSA_T_SUM_NET, LSA_T_SUM_RT, LSA_T_EXT, 0, LSA_T_NSSA};
+/* Maps OSPFv2 types to OSPFv3 types */
+static const u16 lsa_v2_types[] = {
+  0, LSA_T_RT, LSA_T_NET, LSA_T_SUM_NET, LSA_T_SUM_RT, LSA_T_EXT, 0, LSA_T_NSSA,
+  0, LSA_T_OPAQUE_LINK, LSA_T_OPAQUE_AREA, LSA_T_OPAQUE_AS
+};
+
+/* Maps OSPFv2 opaque types to OSPFv3 function codes */
+static const u16 opaque_lsa_types[] = {
+  [LSA_OT_RI] = LSA_T_RI_,
+};
+
+/* Maps (subset of) OSPFv3 function codes to OSPFv2 opaque types */
+static const u8 opaque_lsa_types_inv[] = {
+  [LSA_T_RI_] = LSA_OT_RI,
+};
+
+#define LOOKUP(a, i) ({ uint _i = (i); (_i < ARRAY_SIZE(a)) ? a[_i] : 0; })
 
 void
-lsa_get_type_domain_(u32 itype, struct ospf_iface *ifa, u32 *otype, u32 *domain)
+lsa_get_type_domain_(u32 type, u32 id, struct ospf_iface *ifa, u32 *otype, u32 *domain)
 {
   if (ospf_is_v2(ifa->oa->po))
   {
-    itype = itype & LSA_T_V2_MASK;
-    itype = (itype < LSA_V2_TMAX) ? lsa_v2_types[itype] : 0;
+    type = type & LSA_T_V2_MASK;
+    type = LOOKUP(lsa_v2_types, type);
+
+    uint code;
+    if (LSA_FUNCTION(type) == LSA_T_OPAQUE_)
+      if (code = LOOKUP(opaque_lsa_types, id >> 24))
+       type = code | LSA_UBIT | LSA_SCOPE(type);
   }
   else
   {
     /* For unkown LSAs without U-bit change scope to LSA_SCOPE_LINK */
-    if (unknown_lsa_type(itype) && !(itype & LSA_UBIT))
-      itype = itype & ~LSA_SCOPE_MASK;
+    if (unknown_lsa_type(type) && !(type & LSA_UBIT))
+      type = type & ~LSA_SCOPE_MASK;
   }
 
-  *otype = itype;
+  *otype = type;
 
-  switch (LSA_SCOPE(itype))
+  switch (LSA_SCOPE(type))
   {
   case LSA_SCOPE_LINK:
     *domain = ifa->iface_id;
@@ -150,6 +196,12 @@ lsa_get_type_domain_(u32 itype, struct ospf_iface *ifa, u32 *otype, u32 *domain)
   }
 }
 
+u32
+lsa_get_opaque_type(u32 type)
+{
+  return LOOKUP(opaque_lsa_types_inv, LSA_FUNCTION(type));
+}
+
 
 void
 lsa_generate_checksum(struct ospf_lsa_header *lsa, const u8 *body)
@@ -548,6 +600,17 @@ lsa_validate_prefix(struct ospf_lsa_header *lsa, struct ospf_lsa_prefix *body)
   return lsa_validate_pxlist(lsa, body->pxcount, sizeof(struct ospf_lsa_prefix), (u8 *) body);
 }
 
+static int
+lsa_validate_ri(struct ospf_lsa_header *lsa UNUSED, struct ospf_lsa_net *body UNUSED)
+{
+  /*
+   * There should be proper validation. But we do not really process RI LSAs, so
+   * we can just accept them like another unknown opaque LSAs.
+   */
+
+  return 1;
+}
+
 
 /**
  * lsa_validate - check whether given LSA is valid
@@ -577,6 +640,14 @@ lsa_validate(struct ospf_lsa_header *lsa, u32 lsa_type, int ospf2, void *body)
     case LSA_T_EXT:
     case LSA_T_NSSA:
       return lsa_validate_ext2(lsa, body);
+    case LSA_T_RI_LINK:
+    case LSA_T_RI_AREA:
+    case LSA_T_RI_AS:
+      return lsa_validate_ri(lsa, body);
+    case LSA_T_OPAQUE_LINK:
+    case LSA_T_OPAQUE_AREA:
+    case LSA_T_OPAQUE_AS:
+      return 1;        /* Unknown Opaque LSAs */
     default:
       return 0;        /* Should not happen, unknown LSAs are already rejected */
     }
@@ -600,6 +671,10 @@ lsa_validate(struct ospf_lsa_header *lsa, u32 lsa_type, int ospf2, void *body)
       return lsa_validate_link(lsa, body);
     case LSA_T_PREFIX:
       return lsa_validate_prefix(lsa, body);
+    case LSA_T_RI_LINK:
+    case LSA_T_RI_AREA:
+    case LSA_T_RI_AS:
+      return lsa_validate_ri(lsa, body);
     default:
       return 1;        /* Unknown LSAs are OK in OSPFv3 */
     }
index fca7faec78bd5ef9f3944a25903b23a55f683980..af8901cebe17789f9ccf92f3bd7ba9dd013e20d0 100644 (file)
@@ -36,16 +36,21 @@ struct ospf_lsa_rt_walk {
 };
 
 
-void lsa_get_type_domain_(u32 itype, struct ospf_iface *ifa, u32 *otype, u32 *domain);
+void lsa_get_type_domain_(u32 type, u32 id, struct ospf_iface *ifa, u32 *otype, u32 *domain);
 
 static inline void lsa_get_type_domain(struct ospf_lsa_header *lsa, struct ospf_iface *ifa, u32 *otype, u32 *domain)
-{ lsa_get_type_domain_(lsa->type_raw, ifa, otype, domain); }
+{ lsa_get_type_domain_(lsa->type_raw, lsa->id, ifa, otype, domain); }
 
 static inline u32 lsa_get_etype(struct ospf_lsa_header *h, struct ospf_proto *p)
 { return ospf_is_v2(p) ? (h->type_raw & LSA_T_V2_MASK) : h->type_raw; }
 
+/* Assuming OSPFv2 - All U-bit LSAs are mapped to Opaque LSAs */
+static inline int lsa_is_opaque(u32 type)
+{ return !!(type & LSA_UBIT); }
 
+u32 lsa_get_opaque_type(u32 type);
 int lsa_flooding_allowed(u32 type, u32 domain, struct ospf_iface *ifa);
+int lsa_is_acceptable(u32 type, struct ospf_neighbor *n, struct ospf_proto *p);
 void lsa_generate_checksum(struct ospf_lsa_header *lsa, const u8 *body);
 u16 lsa_verify_checksum(const void *lsa_n, int lsa_len);
 
index 657c024785bb634289c28dca7ed88ec8d73f5d3e..45af7533c39a6a5279a9402f6fca1636a3f59d66 100644 (file)
@@ -125,7 +125,7 @@ ospf_receive_lsreq(struct ospf_packet *pkt, struct ospf_iface *ifa,
 
     id = ntohl(lsrs[i].id);
     rt = ntohl(lsrs[i].rt);
-    lsa_get_type_domain_(ntohl(lsrs[i].type), ifa, &type, &domain);
+    lsa_get_type_domain_(ntohl(lsrs[i].type), id, ifa, &type, &domain);
 
     DBG("Processing requested LSA: Type: %04x, Id: %R, Rt: %R\n", type, id, rt);
 
index a98c909820fd34d8e78cedd0e8b10a1cfc295a5b..7318b7512b40b834bf97395d27d9c76f8ad291f4 100644 (file)
@@ -171,7 +171,8 @@ ospf_add_flushed_to_lsrt(struct ospf_proto *p, struct ospf_neighbor *n)
 
   WALK_SLIST(en, p->lsal)
     if ((en->lsa.age == LSA_MAXAGE) && (en->lsa_body != NULL) &&
-       lsa_flooding_allowed(en->lsa_type, en->domain, n->ifa))
+       lsa_flooding_allowed(en->lsa_type, en->domain, n->ifa) &&
+        lsa_is_acceptable(en->lsa_type, n, p))
       ospf_lsa_lsrt_up(en, n);
 
   /* If we found any flushed LSA, we send them ASAP */
@@ -287,9 +288,9 @@ ospf_flood_lsa(struct ospf_proto *p, struct top_hash_entry *en, struct ospf_neig
       if (n == from)
        continue;
 
-      /* In OSPFv3, there should be check whether receiving router understand
-        that type of LSA (for LSA types with U-bit == 0). But as we do not support
-        any optional LSA types, this is not needed yet */
+      /* Check whether optional LSAs are supported by neighbor */
+      if (!lsa_is_acceptable(en->lsa_type, n, p))
+       continue;
 
       /* 13.3 (1d) - add LSA to the link state retransmission list */
       ospf_lsa_lsrt_up(en, n);
index a5e22269bf22e91b5f51e6178677a1b0a99b722a..735006041e47001285e4e6712bd0380e3c3fb3c2 100644 (file)
  * - RFC 2328 - main OSPFv2 standard
  * - RFC 5340 - main OSPFv3 standard
  * - RFC 3101 - OSPFv2 NSSA areas
+ * - RFC 5250 - OSPFv2 Opaque LSAs
  * - RFC 5709 - OSPFv2 HMAC-SHA Cryptographic Authentication
  * - RFC 5838 - OSPFv3 Support of Address Families
  * - RFC 6549 - OSPFv2 Multi-Instance Extensions
  * - RFC 6987 - OSPF Stub Router Advertisement
  * - RFC 7166 - OSPFv3 Authentication Trailer
+ * - RFC 7770 - OSPF Router Information LSA
  */
 
 #include <stdlib.h>
@@ -239,6 +241,7 @@ ospf_start(struct proto *P)
   p->rfc1583 = c->rfc1583;
   p->stub_router = c->stub_router;
   p->merge_external = c->merge_external;
+  p->instance_id = c->instance_id;
   p->asbr = c->asbr;
   p->ecmp = c->ecmp;
   p->tick = c->tick;
@@ -648,6 +651,9 @@ ospf_reconfigure(struct proto *P, struct proto_config *CF)
   if (p->rfc1583 != new->rfc1583)
     return 0;
 
+  if (p->instance_id != new->instance_id)
+    return 0;
+
   if (old->abr != new->abr)
     return 0;
 
index ff55621a467ad032764d4c4220275571fa1fa563..22b87ebe5cc39a42b6e9d547e0521fc0ca3516b0 100644 (file)
@@ -223,6 +223,7 @@ struct ospf_proto
   u8 rfc1583;                  /* RFC1583 compatibility */
   u8 stub_router;              /* Do not forward transit traffic */
   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 ecmp;                     /* Maximal number of nexthops in ECMP route, or 0 */
   u64 csn64;                   /* Last used cryptographic sequence number */
@@ -466,6 +467,7 @@ struct ospf_neighbor
 #define OPT_L_V2       0x0010  /* OSPFv2, link-local signaling, not used */
 #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_AF         0x0100  /* OSPFv3 Address Families (RFC 5838) */
 #define OPT_L_V3       0x0200  /* OSPFv3, link-local signaling */
 #define OPT_AT          0x0400 /* OSPFv3, authentication trailer */
@@ -541,25 +543,44 @@ struct ospf_auth3
 #define DBDES_IMMS     (DBDES_I | DBDES_M | DBDES_MS)
 
 
-#define LSA_T_RT       0x2001
-#define LSA_T_NET      0x2002
-#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
-
-#define LSA_T_V2_MASK  0x00ff
-
-#define LSA_UBIT       0x8000
-
-#define LSA_SCOPE_LINK 0x0000
-#define LSA_SCOPE_AREA 0x2000
-#define LSA_SCOPE_AS   0x4000
-#define LSA_SCOPE_RES  0x6000
-#define LSA_SCOPE_MASK 0x6000
-#define LSA_SCOPE(type)        ((type) & LSA_SCOPE_MASK)
+/* OSPFv3 LSA Types / LSA Function Codes */
+/* https://www.iana.org/assignments/ospfv3-parameters/ospfv3-parameters.xhtml#ospfv3-parameters-3 */
+#define LSA_T_RT               0x2001
+#define LSA_T_NET              0x2002
+#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
+#define LSA_T_RI_              0x000C
+#define LSA_T_RI_LINK          0x800C
+#define LSA_T_RI_AREA          0xA00C
+#define LSA_T_RI_AS            0xC00C
+#define LSA_T_OPAQUE_          0x1FFF
+#define LSA_T_OPAQUE_LINK      0x9FFF
+#define LSA_T_OPAQUE_AREA      0xBFFF
+#define LSA_T_OPAQUE_AS                0xDFFF
+
+#define LSA_T_V2_OPAQUE_       0x0009
+#define LSA_T_V2_MASK          0x00ff
+
+/* OSPFv2 Opaque LSA Types */
+/* https://www.iana.org/assignments/ospf-opaque-types/ospf-opaque-types.xhtml#ospf-opaque-types-2 */
+#define LSA_OT_RI              0x04
+
+#define LSA_FUNCTION_MASK      0x1FFF
+#define LSA_FUNCTION(type)     ((type) & LSA_FUNCTION_MASK)
+
+#define LSA_UBIT               0x8000
+
+#define LSA_SCOPE_LINK         0x0000
+#define LSA_SCOPE_AREA         0x2000
+#define LSA_SCOPE_AS           0x4000
+#define LSA_SCOPE_RES          0x6000
+#define LSA_SCOPE_MASK         0x6000
+#define LSA_SCOPE(type)                ((type) & LSA_SCOPE_MASK)
+#define LSA_SCOPE_ORDER(type)  (((type) >> 13) & 0x3)
 
 
 #define LSA_MAXAGE     3600    /* 1 hour */
@@ -586,9 +607,20 @@ struct ospf_auth3
 #define LSA_EXT2_TOS   0x7F000000
 #define LSA_EXT2_EBIT  0x80000000
 
-#define LSA_EXT3_EBIT  0x4000000
-#define LSA_EXT3_FBIT  0x2000000
-#define LSA_EXT3_TBIT  0x1000000
+#define LSA_EXT3_EBIT  0x04000000
+#define LSA_EXT3_FBIT  0x02000000
+#define LSA_EXT3_TBIT  0x01000000
+
+/* OSPF Router Information (RI) TLVs */
+/* https://www.iana.org/assignments/ospf-parameters/ospf-parameters.xhtml#ri-tlv */
+#define LSA_RI_RIC             1
+#define LSA_RI_RFC             2
+
+/* OSPF Router Informational Capability Bits */
+/* https://www.iana.org/assignments/ospf-parameters/ospf-parameters.xhtml#router-informational-capability */
+#define LSA_RIC_GR_CAPABLE     0
+#define LSA_RIC_GR_HELPER      1
+#define LSA_RIC_STUB_ROUTER    2
 
 
 struct ospf_lsa_header
@@ -731,6 +763,18 @@ struct ospf_lsa_prefix
   u32 rest[];
 };
 
+struct ospf_tlv
+{
+#ifdef CPU_BIG_ENDIAN
+  u16 type;
+  u16 length;
+#else
+  u16 length;
+  u16 type;
+#endif
+  u32 data[];
+};
+
 
 static inline uint
 lsa_net_count(struct ospf_lsa_header *lsa)
index e58f13753038df73e078693dd2500b563d6a6f7b..f9ca7bfcfd074fe6dd0fc0ac934bcdcedad6e9a2 100644 (file)
@@ -224,12 +224,17 @@ ospf_do_originate_lsa(struct ospf_proto *p, struct top_hash_entry *en, void *lsa
   /*
    * lsa.type_raw is initialized by ospf_hash_get() to OSPFv3 LSA type.
    * lsa_set_options() implicitly converts it to OSPFv2 LSA type, assuming that
-   * old type is just new type masked by 0xff.  That is not universally true,
-   * but it holds for all OSPFv2 types currently supported by BIRD.
+   * old type is just new type masked by 0xff. That holds for most OSPFv2 types,
+   * but we have to fix it for opaque LSAs.
    */
 
   if (ospf_is_v2(p))
+  {
+    if (lsa_is_opaque(en->lsa_type))
+      en->lsa.type_raw = LSA_T_V2_OPAQUE_ + LSA_SCOPE_ORDER(en->lsa_type);
+
     lsa_set_options(&en->lsa, lsa_opts);
+  }
 
   mb_free(en->lsa_body);
   en->lsa_body = lsa_body;
@@ -273,6 +278,10 @@ ospf_originate_lsa(struct ospf_proto *p, struct ospf_new_lsa *lsa)
   u16 lsa_blen = p->lsab_used;
   u16 lsa_length = sizeof(struct ospf_lsa_header) + lsa_blen;
 
+  /* For OSPFv2 Opaque LSAs, LS ID consists of Opaque Type and Opaque ID */
+  if (ospf_is_v2(p) && lsa_is_opaque(lsa->type))
+    lsa->id |= (u32) lsa_get_opaque_type(lsa->type) << 24;
+
   en = ospf_hash_get(p->gr, lsa->dom, lsa->id, p->router_id, lsa->type);
 
   if (!SNODE_VALID(en))
@@ -1658,6 +1667,41 @@ ospf_originate_prefix_net_lsa(struct ospf_proto *p, struct ospf_iface *ifa)
   ifa->pxn_lsa = ospf_originate_lsa(p, &lsa);
 }
 
+
+/*
+ *     Router Information LSA handling
+ *     Type = LSA_T_RI_AREA, opaque type = LSA_OT_RI
+ */
+
+void
+ospf_add_ric_tlv(struct ospf_proto *p)
+{
+  struct ospf_tlv *ri = lsab_allocz(p, sizeof(struct ospf_tlv) + sizeof(u32));
+  ri->type = LSA_RI_RIC;
+  ri->length = sizeof(struct ospf_tlv) + sizeof(u32);
+
+  BIT32R_SET(ri->data, LSA_RIC_STUB_ROUTER);
+}
+
+void
+ospf_originate_ri_lsa(struct ospf_proto *p, struct ospf_area *oa)
+{
+  struct ospf_new_lsa lsa = {
+    .type = LSA_T_RI_AREA,
+    .dom  = oa->areaid,
+    .id   = p->instance_id
+  };
+
+  ospf_add_ric_tlv(p);
+
+  ospf_originate_lsa(p, &lsa);
+}
+
+
+/*
+ *     Generic topology code
+ */
+
 static inline int breaks_minlsinterval(struct top_hash_entry *en)
 { return en && (en->lsa.age < LSA_MAXAGE) && (lsa_inst_age(en) < MINLSINTERVAL); }
 
@@ -1692,6 +1736,7 @@ ospf_update_topology(struct ospf_proto *p)
 
       ospf_originate_rt_lsa(p, oa);
       ospf_originate_prefix_rt_lsa(p, oa);
+      ospf_originate_ri_lsa(p, oa);
       oa->update_rt_lsa = 0;
     }
   }