Commit 5a50a989 authored by Ondrej Zajicek (work)'s avatar Ondrej Zajicek (work)
Browse files

OSPF: Opaque LSAs and Router Information LSA

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.
parent 3e60932a
Loading
Loading
Loading
Loading
+7 −0
Original line number Diff line number Diff line
@@ -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
+3 −2
Original line number Diff line number Diff line
@@ -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++;
+85 −10
Original line number Diff line number Diff line
@@ -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 */
    }
+7 −2
Original line number Diff line number Diff line
@@ -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);

+1 −1
Original line number Diff line number Diff line
@@ -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);

Loading