Commit 1a2ad348 authored by Ondrej Zajicek (work)'s avatar Ondrej Zajicek (work)
Browse files

OSPF: Support for graceful restart

Implement OSPFv2 (RFC 3623) and OSPFv3 (RFC 5187) graceful restart,
for both restarting and helper sides. Graceful restart is initiated
by 'graceful down' command.
parent 8a68316e
Loading
Loading
Loading
Loading
+6 −0
Original line number Diff line number Diff line
@@ -200,6 +200,7 @@ 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, VPN, PE)
CF_KEYWORDS(GRACEFUL, RESTART, AWARE, TIME)

%type <ld> lsadb_args
%type <i> ospf_variant ospf_af_mc nbma_eligible
@@ -226,6 +227,8 @@ ospf_proto_start: proto_start ospf_variant
  OSPF_CFG->tick = OSPF_DEFAULT_TICK;
  OSPF_CFG->ospf2 = $2;
  OSPF_CFG->af_ext = !$2;
  OSPF_CFG->gr_mode = OSPF_GR_AWARE;
  OSPF_CFG->gr_time = OSPF_DEFAULT_GR_TIME;
};

ospf_proto:
@@ -258,6 +261,9 @@ ospf_proto_item:
 | 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; }
 | GRACEFUL RESTART bool { OSPF_CFG->gr_mode = $3; }
 | GRACEFUL RESTART AWARE { OSPF_CFG->gr_mode = OSPF_GR_AWARE; }
 | GRACEFUL RESTART TIME expr { OSPF_CFG->gr_time = $4; if (($4 < 1) || ($4 > 1800)) cf_error("Graceful restart time must be in range 1-1800"); }
 | ECMP bool { OSPF_CFG->ecmp = $2 ? OSPF_DEFAULT_ECMP_LIMIT : 0; }
 | ECMP bool LIMIT expr { OSPF_CFG->ecmp = $2 ? $4 : 0; }
 | MERGE EXTERNAL bool { OSPF_CFG->merge_external = $3; }
+5 −1
Original line number Diff line number Diff line
@@ -215,7 +215,7 @@ ospf_send_dbdes(struct ospf_proto *p, struct ospf_neighbor *n)

  ASSERT((n->state == NEIGHBOR_EXSTART) || (n->state == NEIGHBOR_EXCHANGE));

  if (n->ifa->oa->rt == NULL)
  if (!n->ifa->oa->rt && !p->gr_recovery)
    return;

  ospf_prepare_dbdes(p, n);
@@ -279,6 +279,10 @@ ospf_process_dbdes(struct ospf_proto *p, struct ospf_packet *pkt, struct ospf_ne
    if (LSA_SCOPE(lsa_type) == LSA_SCOPE_RES)
      DROP1("LSA with invalid scope");

    /* RFC 3623 2.2 (2) special case - check for my router-LSA (GR recovery) */
    if ((lsa_type == LSA_T_RT) && (lsa.rt == p->router_id))
      n->got_my_rt_lsa = 1;

    en = ospf_hash_find(p->gr, lsa_domain, lsa.id, lsa.rt, lsa_type);
    if (!en || (lsa_comp(&lsa, &(en->lsa)) == CMP_NEWER))
    {
+8 −0
Original line number Diff line number Diff line
@@ -772,6 +772,14 @@ ospf_iface_reconfigure(struct ospf_iface *ifa, struct ospf_iface_patt *new)
  ifa->cf = new;
  ifa->marked = 0;

  /* Cancel GR peers if GR is disabled */
  if (!p->gr_mode && p->gr_count)
  {
    struct ospf_neighbor *n, *nx;
    WALK_LIST_DELSAFE(n, nx, ifa->neigh_list)
      if (n->gr_active)
	ospf_neigh_cancel_graceful_restart(n);
  }

  /* HELLO TIMER */
  if (ifa->helloint != new->helloint)
+73 −2
Original line number Diff line number Diff line
@@ -12,6 +12,9 @@

#include "lib/fletcher16.h"

#define HDRLEN sizeof(struct ospf_lsa_header)


#ifndef CPU_BIG_ENDIAN
void
lsa_hton_hdr(struct ospf_lsa_header *h, struct ospf_lsa_header *n)
@@ -61,7 +64,6 @@ lsa_ntoh_body(void *n, void *h, u16 len)
#endif /* little endian */



int
lsa_flooding_allowed(u32 type, u32 domain, struct ospf_iface *ifa)
{
@@ -147,11 +149,13 @@ static const u16 lsa_v2_types[] = {

/* Maps OSPFv2 opaque types to OSPFv3 function codes */
static const u16 opaque_lsa_types[] = {
  [LSA_OT_GR] = LSA_T_GR,
  [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_GR] = LSA_OT_GR,
  [LSA_T_RI_] = LSA_OT_RI,
};

@@ -168,7 +172,13 @@ lsa_get_type_domain_(u32 type, u32 id, struct ospf_iface *ifa, u32 *otype, u32 *
    uint code;
    if (LSA_FUNCTION(type) == LSA_T_OPAQUE_)
      if (code = LOOKUP(opaque_lsa_types, id >> 24))
      {
	type = code | LSA_UBIT | LSA_SCOPE(type);

	/* Hack for Grace-LSA: It does not use U-bit for link-scoped LSAs */
	if (type == (LSA_T_GR | LSA_UBIT))
	  type = LSA_T_GR;
      }
  }
  else
  {
@@ -196,6 +206,13 @@ lsa_get_type_domain_(u32 type, u32 id, struct ospf_iface *ifa, u32 *otype, u32 *
  }
}

int
lsa_is_opaque(u32 type)
{
  u32 fn = LSA_FUNCTION(type);
  return LOOKUP(opaque_lsa_types_inv, fn) || (fn == LSA_T_OPAQUE_);
}

u32
lsa_get_opaque_type(u32 type)
{
@@ -267,6 +284,51 @@ lsa_comp(struct ospf_lsa_header *l1, struct ospf_lsa_header *l2)
}


#define LSA_TLV_LENGTH(tlv) \
  (sizeof(struct ospf_tlv) + BIRD_ALIGN((tlv)->length, 4))

#define LSA_NEXT_TLV(tlv) \
  ((struct ospf_tlv *) ((byte *) (tlv) + LSA_TLV_LENGTH(tlv)))

#define LSA_WALK_TLVS(tlv,buf,len)					\
  for(struct ospf_tlv *tlv = (void *) (buf);				\
      (byte *) tlv < (byte *) (buf) + (len);				\
      tlv = LSA_NEXT_TLV(tlv))

struct ospf_tlv *
lsa_get_tlv(struct top_hash_entry *en, uint type)
{
  LSA_WALK_TLVS(tlv, en->lsa_body, en->lsa.length - HDRLEN)
    if (tlv->type == type)
      return tlv;

  return NULL;
}

int
lsa_validate_tlvs(byte *buf, uint len)
{
  byte *pos = buf;
  byte *end = buf + len;

  while (pos < end)
  {
    if ((pos + sizeof(struct ospf_tlv)) > end)
      return 0;

    struct ospf_tlv *tlv = (void *) pos;
    uint len = LSA_TLV_LENGTH(tlv);

    if ((pos + len) > end)
      return 0;

    pos += len;
  }

  return 1;
}


static inline int
lsa_walk_rt2(struct ospf_lsa_rt_walk *rt)
{
@@ -408,7 +470,6 @@ lsa_parse_ext(struct top_hash_entry *en, int ospf2, int af, struct ospf_lsa_ext_
  }
}

#define HDRLEN sizeof(struct ospf_lsa_header)

static int
lsa_validate_rt2(struct ospf_lsa_header *lsa, struct ospf_lsa_rt *body)
@@ -603,6 +664,12 @@ 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_gr(struct ospf_lsa_header *lsa, void *body)
{
  return lsa_validate_tlvs(body, lsa->length - HDRLEN);
}

static int
lsa_validate_ri(struct ospf_lsa_header *lsa UNUSED, struct ospf_lsa_net *body UNUSED)
{
@@ -643,6 +710,8 @@ 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_GR:
      return lsa_validate_gr(lsa, body);
    case LSA_T_RI_LINK:
    case LSA_T_RI_AREA:
    case LSA_T_RI_AS:
@@ -674,6 +743,8 @@ 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_GR:
      return lsa_validate_gr(lsa, body);
    case LSA_T_RI_LINK:
    case LSA_T_RI_AREA:
    case LSA_T_RI_AS:
+11 −4
Original line number Diff line number Diff line
@@ -44,10 +44,7 @@ static inline void lsa_get_type_domain(struct ospf_lsa_header *lsa, struct ospf_
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); }

int lsa_is_opaque(u32 type);
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);
@@ -58,6 +55,16 @@ u16 lsa_verify_checksum(const void *lsa_n, int lsa_len);
#define CMP_SAME 0
#define CMP_OLDER -1
int lsa_comp(struct ospf_lsa_header *l1, struct ospf_lsa_header *l2);

struct ospf_tlv * lsa_get_tlv(struct top_hash_entry *en, uint type);

static inline u32
lsa_get_tlv_u32(struct top_hash_entry *en, uint type)
{
  struct ospf_tlv *tlv = lsa_get_tlv(en, type);
  return (tlv && (tlv->length == 4)) ? tlv->data[0] : 0;
}

void lsa_walk_rt_init(struct ospf_proto *po, struct top_hash_entry *act, struct ospf_lsa_rt_walk *rt);
int lsa_walk_rt(struct ospf_lsa_rt_walk *rt);
void lsa_parse_sum_net(struct top_hash_entry *en, int ospf2, int af, net_addr *net, u8 *pxopts, u32 *metric);
Loading