]> git.ipfire.org Git - thirdparty/bird.git/commitdiff
Merge branch 'master' into int-new
authorOndrej Zajicek (work) <santiago@crfreenet.org>
Wed, 8 Feb 2017 13:34:48 +0000 (14:34 +0100)
committerOndrej Zajicek (work) <santiago@crfreenet.org>
Wed, 8 Feb 2017 13:34:48 +0000 (14:34 +0100)
12 files changed:
1  2 
NEWS
filter/filter.c
lib/hash.h
nest/a-set.c
nest/attrs.h
proto/bgp/attrs.c
proto/bgp/bgp.c
proto/ospf/rt.c
proto/ospf/rt.h
sysdep/bsd/sysio.h
sysdep/linux/netlink.c
sysdep/unix/io.c

diff --cc NEWS
index 9669392d7ca4b6c3230adf4757247f01bf2fd0cb,a9bd6a72bb48aa0b0afae0ccfb4d1ca794ee8edb..6281c8a39dbd8c351430c87985e6188fb48df194
--- 1/NEWS
--- 2/NEWS
+++ b/NEWS
@@@ -1,19 -1,10 +1,26 @@@
 +Version 2.0.0-pre0 (2016-12-07)
 +  o Integrated IPv4 + IPv6 design
 +  o Major BGP protocol redesign
 +  o BGP multicast support (SAFI 2)
 +  o BGP flowspec support (RFC 5575)
 +  o New RPKI-Router protocol
 +  o New build system
 +  o Unit tests
 +
 +  Notes:
 +
 +  Protocols and tables are now connected using explicit channels, most related
 +  protocol options (table, import, export, ...) are now channel options. See
 +  doc/bird.conf.example2 for configuration examples.
 +
 +
+ Version 1.6.3 (2016-12-21)
+   o Large BGP communities
+   o BFD authentication (MD5, SHA1)
+   o SHA1 and SHA2 authentication for RIP and OSPF
+   o Improved documentation
+   o Several bug fixes
  Version 1.6.2 (2016-09-29)
    o Fixes serious bug introduced in the previous version
  
diff --cc filter/filter.c
Simple merge
diff --cc lib/hash.h
Simple merge
diff --cc nest/a-set.c
Simple merge
diff --cc nest/attrs.h
Simple merge
index d5bf2add9847875775f3e4ba2a0f5e9b20c6cf8f,9d23374a43a948a2edfb31bf7af99016c8279ee8..73318c6af7a38d93e0ea30faa36595d80b34eff5
@@@ -1216,40 -927,39 +1216,49 @@@ bgp_withdraw_bucket(struct bgp_channel 
  HASH_DEFINE_REHASH_FN(PXH, struct bgp_prefix)
  
  void
 -bgp_init_prefix_table(struct bgp_proto *p, u32 order)
 +bgp_init_prefix_table(struct bgp_channel *c)
  {
 -  HASH_INIT(p->prefix_hash, p->p.pool, order);
 +  HASH_INIT(c->prefix_hash, c->pool, 8);
  
 -  p->prefix_slab = sl_new(p->p.pool, sizeof(struct bgp_prefix));
 +  uint alen = net_addr_length[c->c.net_type];
 +  c->prefix_slab = alen ? sl_new(c->pool, sizeof(struct bgp_prefix) + alen) : NULL;
  }
  
 -bgp_free_prefix_table(struct bgp_proto *p)
+ void
 -  HASH_FREE(p->prefix_hash);
++bgp_free_prefix_table(struct bgp_channel *c)
+ {
 -  rfree(p->prefix_slab);
 -  p->prefix_slab = NULL;
++  HASH_FREE(c->prefix_hash);
++  rfree(c->prefix_slab);
++  c->prefix_slab = NULL;
+ }
  static struct bgp_prefix *
 -bgp_get_prefix(struct bgp_proto *p, ip_addr prefix, int pxlen, u32 path_id)
 +bgp_get_prefix(struct bgp_channel *c, net_addr *net, u32 path_id)
  {
 -  struct bgp_prefix *bp = HASH_FIND(p->prefix_hash, PXH, prefix, pxlen, path_id);
 +  u32 hash = net_hash(net) ^ u32_hash(path_id);
 +  struct bgp_prefix *px = HASH_FIND(c->prefix_hash, PXH, net, path_id, hash);
 +
 +  if (px)
 +  {
 +    rem_node(&px->buck_node);
 +    return px;
 +  }
  
 -  if (bp)
 -    return bp;
 +  if (c->prefix_slab)
 +    px = sl_alloc(c->prefix_slab);
 +  else
 +    px = mb_alloc(c->pool, sizeof(struct bgp_prefix) + net->length);
  
 -  bp = sl_alloc(p->prefix_slab);
 -  bp->n.prefix = prefix;
 -  bp->n.pxlen = pxlen;
 -  bp->path_id = path_id;
 -  bp->bucket_node.next = NULL;
 +  px->buck_node.next = NULL;
 +  px->buck_node.prev = NULL;
 +  px->hash = hash;
 +  px->path_id = path_id;
 +  net_copy(px->net, net);
  
 -  HASH_INSERT2(p->prefix_hash, PXH, p->p.pool, bp);
 +  HASH_INSERT2(c->prefix_hash, PXH, c->pool, px);
  
 -  return bp;
 +  return px;
  }
  
  void
@@@ -1265,205 -970,248 +1274,206 @@@ bgp_free_prefix(struct bgp_channel *c, 
  }
  
  
 -void
 -bgp_rt_notify(struct proto *P, rtable *tbl UNUSED, net *n, rte *new, rte *old UNUSED, ea_list *attrs)
 +/*
 + *    BGP protocol glue
 + */
 +
 +int
 +bgp_import_control(struct proto *P, rte **new, ea_list **attrs UNUSED, struct linpool *pool UNUSED)
  {
 +  rte *e = *new;
 +  struct proto *SRC = e->attrs->src->proto;
    struct bgp_proto *p = (struct bgp_proto *) P;
 -  struct bgp_bucket *buck;
 -  struct bgp_prefix *px;
 -  rte *key;
 -  u32 path_id;
 +  struct bgp_proto *src = (SRC->proto == &proto_bgp) ? (struct bgp_proto *) SRC : NULL;
  
 -  DBG("BGP: Got route %I/%d %s\n", n->n.prefix, n->n.pxlen, new ? "up" : "down");
 +  /* Reject our routes */
 +  if (src == p)
 +    return -1;
  
 -  if (new)
 -    {
 -      key = new;
 -      buck = bgp_get_bucket(p, n, attrs, new->attrs->source != RTS_BGP);
 -      if (!buck)                      /* Inconsistent attribute list */
 -      return;
 -    }
 -  else
 -    {
 -      key = old;
 -      if (!(buck = p->withdraw_bucket))
 -      {
 -        buck = p->withdraw_bucket = mb_alloc(P->pool, sizeof(struct bgp_bucket));
 -        init_list(&buck->prefixes);
 -      }
 -    }
 -  path_id = p->add_path_tx ? key->attrs->src->global_id : 0;
 -  px = bgp_get_prefix(p, n->n.prefix, n->n.pxlen, path_id);
 -  if (px->bucket_node.next)
 -    {
 -      DBG("\tRemoving old entry.\n");
 -      rem_node(&px->bucket_node);
 -    }
 -  add_tail(&buck->prefixes, &px->bucket_node);
 -  bgp_schedule_packet(p->conn, PKT_UPDATE);
 -}
 +  /* Accept non-BGP routes */
 +  if (src == NULL)
 +    return 0;
  
 -static int
 -bgp_create_attrs(struct bgp_proto *p, rte *e, ea_list **attrs, struct linpool *pool)
 -{
 -  ea_list *ea = lp_alloc(pool, sizeof(ea_list) + 4*sizeof(eattr));
 -  rta *rta = e->attrs;
 -  byte *z;
 +  // XXXX: Check next hop AF
  
 -  ea->next = *attrs;
 -  *attrs = ea;
 -  ea->flags = EALF_SORTED;
 -  ea->count = 4;
 +  /* IBGP route reflection, RFC 4456 */
 +  if (p->is_internal && src->is_internal && (p->local_as == src->local_as))
 +  {
 +    /* Rejected unless configured as route reflector */
 +    if (!p->rr_client && !src->rr_client)
 +      return -1;
 +
 +    /* Generally, this should be handled when path is received, but we check it
 +       also here as rr_cluster_id may be undefined or different in src. */
 +    if (p->rr_cluster_id && bgp_cluster_list_loopy(p, e->attrs->eattrs))
 +      return -1;
 +  }
  
 -  bgp_set_attr(ea->attrs, BA_ORIGIN,
 -       ((rta->source == RTS_OSPF_EXT1) || (rta->source == RTS_OSPF_EXT2)) ? ORIGIN_INCOMPLETE : ORIGIN_IGP);
 +  /* Handle well-known communities, RFC 1997 */
 +  struct eattr *c;
 +  if (p->cf->interpret_communities &&
 +      (c = ea_find(e->attrs->eattrs, EA_CODE(EAP_BGP, BA_COMMUNITY))))
 +  {
 +    struct adata *d = c->u.ptr;
  
 -  if (p->is_internal)
 -    bgp_set_attr_wa(ea->attrs+1, pool, BA_AS_PATH, 0);
 -  else
 -    {
 -      z = bgp_set_attr_wa(ea->attrs+1, pool, BA_AS_PATH, 6);
 -      z[0] = AS_PATH_SEQUENCE;
 -      z[1] = 1;                               /* 1 AS */
 -      put_u32(z+2, p->local_as);
 -    }
 +    /* Do not export anywhere */
 +    if (int_set_contains(d, BGP_COMM_NO_ADVERTISE))
 +      return -1;
  
 -  /* iBGP -> use gw, eBGP multi-hop -> use source_addr,
 -     eBGP single-hop -> use gw if on the same iface */
 -  z = bgp_set_attr_wa(ea->attrs+2, pool, BA_NEXT_HOP, NEXT_HOP_LENGTH);
 -  if (p->cf->next_hop_self ||
 -      rta->dest != RTD_ROUTER ||
 -      ipa_equal(rta->gw, IPA_NONE) ||
 -      ipa_is_link_local(rta->gw) ||
 -      (!p->is_internal && !p->cf->next_hop_keep &&
 -       (!p->neigh || (rta->iface != p->neigh->iface))))
 -    set_next_hop(z, p->source_addr);
 -  else
 -    set_next_hop(z, rta->gw);
 +    /* Do not export outside of AS (or member-AS) */
 +    if (!p->is_internal && int_set_contains(d, BGP_COMM_NO_EXPORT_SUBCONFED))
 +      return -1;
  
 -  bgp_set_attr(ea->attrs+3, BA_LOCAL_PREF, p->cf->default_local_pref);
 +    /* Do not export outside of AS (or confederation) */
 +    if (!p->is_interior && int_set_contains(d, BGP_COMM_NO_EXPORT))
 +      return -1;
 +  }
  
 -  return 0;                           /* Leave decision to the filters */
 +  return 0;
  }
  
 -static inline int
 -bgp_as_path_loopy(struct bgp_proto *p, rta *a)
 -{
 -  int num = p->cf->allow_local_as + 1;
 -  eattr *e = ea_find(a->eattrs, EA_CODE(EAP_BGP, BA_AS_PATH));
 -  return (e && (num > 0) && as_path_contains(e->u.ptr, p->local_as, num));
 -}
 -
 -static inline int
 -bgp_originator_id_loopy(struct bgp_proto *p, rta *a)
 -{
 -  eattr *e = ea_find(a->eattrs, EA_CODE(EAP_BGP, BA_ORIGINATOR_ID));
 -  return (e && (e->u.data == p->local_id));
 -}
 +static adata null_adata;      /* adata of length 0 */
  
 -static inline int
 -bgp_cluster_list_loopy(struct bgp_proto *p, rta *a)
 +static ea_list *
 +bgp_update_attrs(struct bgp_proto *p, struct bgp_channel *c, rte *e, ea_list *attrs0, struct linpool *pool)
  {
 -  eattr *e = ea_find(a->eattrs, EA_CODE(EAP_BGP, BA_CLUSTER_LIST));
 -  return (e && p->rr_client && int_set_contains(e->u.ptr, p->rr_cluster_id));
 -}
 +  struct proto *SRC = e->attrs->src->proto;
 +  struct bgp_proto *src = (SRC->proto == &proto_bgp) ? (void *) SRC : NULL;
 +  struct bgp_export_state s = { .proto = p, .channel =c, .pool = pool, .src = src, .route = e };
 +  ea_list *attrs = attrs0;
 +  eattr *a;
 +  adata *ad;
  
 +  /* ORIGIN attribute - mandatory, attach if missing */
 +  if (! bgp_find_attr(attrs0, BA_ORIGIN))
 +    bgp_set_attr_u32(&attrs, pool, BA_ORIGIN, 0, src ? ORIGIN_INCOMPLETE : ORIGIN_IGP);
  
 -static inline void
 -bgp_path_prepend(rte *e, ea_list **attrs, struct linpool *pool, u32 as)
 -{
 -  eattr *a = ea_find(e->attrs->eattrs, EA_CODE(EAP_BGP, BA_AS_PATH));
 -  bgp_attach_attr(attrs, pool, BA_AS_PATH, (uintptr_t) as_path_prepend(pool, a->u.ptr, as));
 -}
 +  /* AS_PATH attribute - mandatory */
 +  a = bgp_find_attr(attrs0, BA_AS_PATH);
 +  ad = a ? a->u.ptr : &null_adata;
  
 -static inline void
 -bgp_cluster_list_prepend(rte *e, ea_list **attrs, struct linpool *pool, u32 cid)
 -{
 -  eattr *a = ea_find(e->attrs->eattrs, EA_CODE(EAP_BGP, BA_CLUSTER_LIST));
 -  bgp_attach_attr(attrs, pool, BA_CLUSTER_LIST, (uintptr_t) int_set_prepend(pool, a ? a->u.ptr : NULL, cid));
 -}
 +  /* AS_PATH attribute - strip AS_CONFED* segments outside confederation */
 +  if ((!p->cf->confederation || !p->is_interior) && as_path_contains_confed(ad))
 +    ad = as_path_strip_confed(pool, ad);
  
 -static int
 -bgp_update_attrs(struct bgp_proto *p, rte *e, ea_list **attrs, struct linpool *pool, int rr)
 -{
 -  eattr *a;
 +  /* AS_PATH attribute - keep or prepend ASN */
 +  if (p->is_internal ||
 +      (p->rs_client && src && src->rs_client))
 +  {
 +    /* IBGP or route server -> just ensure there is one */
 +    if (!a)
 +      bgp_set_attr_ptr(&attrs, pool, BA_AS_PATH, 0, &null_adata);
 +  }
 +  else if (p->is_interior)
 +  {
 +    /* Confederation -> prepend ASN as AS_CONFED_SEQUENCE */
 +    ad = as_path_prepend2(pool, ad, AS_PATH_CONFED_SEQUENCE, p->public_as);
 +    bgp_set_attr_ptr(&attrs, pool, BA_AS_PATH, 0, ad);
 +  }
 +  else /* Regular EBGP (no RS, no confederation) */
 +  {
 +    /* Regular EBGP -> prepend ASN as regular sequence */
 +    ad = as_path_prepend2(pool, ad, AS_PATH_SEQUENCE, p->public_as);
 +    bgp_set_attr_ptr(&attrs, pool, BA_AS_PATH, 0, ad);
 +
 +    /* MULTI_EXIT_DESC attribute - accept only if set in export filter */
 +    a = bgp_find_attr(attrs0, BA_MULTI_EXIT_DISC);
 +    if (a && !(a->type & EAF_FRESH))
 +      bgp_unset_attr(&attrs, pool, BA_MULTI_EXIT_DISC);
 +  }
  
 -  if (!p->is_internal && !p->rs_client)
 -    {
 -      bgp_path_prepend(e, attrs, pool, p->local_as);
 -
 -      /* The MULTI_EXIT_DISC attribute received from a neighboring AS MUST NOT be
 -       * propagated to other neighboring ASes.
 -       * Perhaps it would be better to undefine it.
 -       */
 -      a = ea_find(e->attrs->eattrs, EA_CODE(EAP_BGP, BA_MULTI_EXIT_DISC));
 -      if (a)
 -      bgp_attach_attr(attrs, pool, BA_MULTI_EXIT_DISC, 0);
 -    }
 +  /* NEXT_HOP attribute - delegated to AF-specific hook */
 +  a = bgp_find_attr(attrs0, BA_NEXT_HOP);
 +  bgp_update_next_hop(&s, a, &attrs);
  
 -  /* iBGP -> keep next_hop, eBGP multi-hop -> use source_addr,
 -   * eBGP single-hop -> keep next_hop if on the same iface.
 -   * If the next_hop is zero (i.e. link-local), keep only if on the same iface.
 -   *
 -   * Note that same-iface-check uses iface from route, which is based on gw.
 -   */
 -  a = ea_find(e->attrs->eattrs, EA_CODE(EAP_BGP, BA_NEXT_HOP));
 -  if (a && !p->cf->next_hop_self && 
 -      (p->cf->next_hop_keep ||
 -       (p->is_internal && ipa_nonzero(*((ip_addr *) a->u.ptr->data))) ||
 -       (p->neigh && (e->attrs->iface == p->neigh->iface))))
 -    {
 -      /* Leave the original next hop attribute, will check later where does it point */
 -    }
 -  else
 -    {
 -      /* Need to create new one */
 -      byte *b = bgp_attach_attr_wa(attrs, pool, BA_NEXT_HOP, NEXT_HOP_LENGTH);
 -      set_next_hop(b, p->source_addr);
 -    }
 +  /* LOCAL_PREF attribute - required for IBGP, attach if missing */
 +  if (p->is_interior && ! bgp_find_attr(attrs0, BA_LOCAL_PREF))
 +    bgp_set_attr_u32(&attrs, pool, BA_LOCAL_PREF, 0, p->cf->default_local_pref);
  
 -  if (rr)
 -    {
 -      /* Handling route reflection, RFC 4456 */
 -      struct bgp_proto *src = (struct bgp_proto *) e->attrs->src->proto;
 +  /* IBGP route reflection, RFC 4456 */
 +  if (src && src->is_internal && p->is_internal && (src->local_as == p->local_as))
 +  {
 +    /* ORIGINATOR_ID attribute - attach if not already set */
 +    if (! bgp_find_attr(attrs0, BA_ORIGINATOR_ID))
 +      bgp_set_attr_u32(&attrs, pool, BA_ORIGINATOR_ID, 0, src->remote_id);
  
 -      a = ea_find(e->attrs->eattrs, EA_CODE(EAP_BGP, BA_ORIGINATOR_ID));
 -      if (!a)
 -      bgp_attach_attr(attrs, pool, BA_ORIGINATOR_ID, src->remote_id);
 +    /* CLUSTER_LIST attribute - prepend cluster ID */
 +    a = bgp_find_attr(attrs0, BA_CLUSTER_LIST);
 +    ad = a ? a->u.ptr : NULL;
  
 -      /* We attach proper cluster ID according to whether the route is entering or leaving the cluster */
 -      bgp_cluster_list_prepend(e, attrs, pool, src->rr_client ? src->rr_cluster_id : p->rr_cluster_id);
 +    /* Prepend src cluster ID */
 +    if (src->rr_cluster_id)
-       ad = int_set_add(pool, ad, src->rr_cluster_id);
++      ad = int_set_prepend(pool, ad, src->rr_cluster_id);
  
 -      /* Two RR clients with different cluster ID, hmmm */
 -      if (src->rr_client && p->rr_client && (src->rr_cluster_id != p->rr_cluster_id))
 -      bgp_cluster_list_prepend(e, attrs, pool, p->rr_cluster_id);
 -    }
 +    /* Prepend dst cluster ID if src and dst clusters are different */
 +    if (p->rr_cluster_id && (src->rr_cluster_id != p->rr_cluster_id))
-       ad = int_set_add(pool, ad, p->rr_cluster_id);
++      ad = int_set_prepend(pool, ad, p->rr_cluster_id);
  
 -  return 0;                           /* Leave decision to the filters */
 -}
 +    /* Should be at least one prepended cluster ID */
 +    bgp_set_attr_ptr(&attrs, pool, BA_CLUSTER_LIST, 0, ad);
 +  }
  
 -static int
 -bgp_community_filter(struct bgp_proto *p, rte *e)
 -{
 -  eattr *a;
 -  struct adata *d;
 +  /* AS4_* transition attributes, RFC 6793 4.2.2 */
 +  if (! p->as4_session)
 +  {
 +    a = bgp_find_attr(attrs, BA_AS_PATH);
 +    if (a && as_path_contains_as4(a->u.ptr))
 +    {
 +      bgp_set_attr_ptr(&attrs, pool, BA_AS_PATH, 0, as_path_to_old(pool, a->u.ptr));
 +      bgp_set_attr_ptr(&attrs, pool, BA_AS4_PATH, 0, as_path_strip_confed(pool, a->u.ptr));
 +    }
  
 -  /* Check if we aren't forbidden to export the route by communities */
 -  a = ea_find(e->attrs->eattrs, EA_CODE(EAP_BGP, BA_COMMUNITY));
 -  if (a)
 +    a = bgp_find_attr(attrs, BA_AGGREGATOR);
 +    if (a && aggregator_contains_as4(a->u.ptr))
      {
 -      d = a->u.ptr;
 -      if (int_set_contains(d, BGP_COMM_NO_ADVERTISE))
 -      {
 -        DBG("\tNO_ADVERTISE\n");
 -        return 1;
 -      }
 -      if (!p->is_internal &&
 -        (int_set_contains(d, BGP_COMM_NO_EXPORT) ||
 -         int_set_contains(d, BGP_COMM_NO_EXPORT_SUBCONFED)))
 -      {
 -        DBG("\tNO_EXPORT\n");
 -        return 1;
 -      }
 +      bgp_set_attr_ptr(&attrs, pool, BA_AGGREGATOR, 0, aggregator_to_old(pool, a->u.ptr));
 +      bgp_set_attr_ptr(&attrs, pool, BA_AS4_AGGREGATOR, 0, a->u.ptr);
      }
 +  }
  
 -  return 0;
 +  /*
 +   * Presence of mandatory attributes ORIGIN and AS_PATH is ensured by above
 +   * conditions. Presence and validity of quasi-mandatory NEXT_HOP attribute
 +   * should be checked in AF-specific hooks.
 +   */
 +
 +  /* Apply per-attribute export hooks for validatation and normalization */
 +  return bgp_export_attrs(&s, attrs);
  }
  
 -int
 -bgp_import_control(struct proto *P, rte **new, ea_list **attrs, struct linpool *pool)
 +void
 +bgp_rt_notify(struct proto *P, struct channel *C, net *n, rte *new, rte *old, ea_list *attrs)
  {
 -  rte *e = *new;
 -  struct bgp_proto *p = (struct bgp_proto *) P;
 -  struct bgp_proto *new_bgp = (e->attrs->src->proto->proto == &proto_bgp) ?
 -    (struct bgp_proto *) e->attrs->src->proto : NULL;
 +  struct bgp_proto *p = (void *) P;
 +  struct bgp_channel *c = (void *) C;
 +  struct bgp_bucket *buck;
 +  struct bgp_prefix *px;
 +  u32 path;
  
 -  if (p == new_bgp)                   /* Poison reverse updates */
 -    return -1;
 -  if (new_bgp)
 -    {
 -      /* We should check here for cluster list loop, because the receiving BGP instance
 -       might have different cluster ID  */
 -      if (bgp_cluster_list_loopy(p, e->attrs))
 -      return -1;
 -
 -      if (p->cf->interpret_communities && bgp_community_filter(p, e))
 -      return -1;
 -
 -      if (p->local_as == new_bgp->local_as && p->is_internal && new_bgp->is_internal)
 -      {
 -        /* Redistribution of internal routes with IBGP */
 -        if (p->rr_client || new_bgp->rr_client)
 -          /* Route reflection, RFC 4456 */
 -          return bgp_update_attrs(p, e, attrs, pool, 1);
 -        else
 -          return -1;
 -      }
 -      else
 -      return bgp_update_attrs(p, e, attrs, pool, 0);
 -    }
 +  if (new)
 +  {
 +    attrs = bgp_update_attrs(p, c, new, attrs, bgp_linpool);
 +
 +    /* If attributes are invalid, we fail back to withdraw */
 +    buck = attrs ? bgp_get_bucket(c, attrs) : bgp_get_withdraw_bucket(c);
 +    path = new->attrs->src->global_id;
 +
 +    lp_flush(bgp_linpool);
 +  }
    else
 -    return bgp_create_attrs(p, e, attrs, pool);
 +  {
 +    buck = bgp_get_withdraw_bucket(c);
 +    path = old->attrs->src->global_id;
 +  }
 +
 +  px = bgp_get_prefix(c, n->n.addr, c->add_path_tx ? path : 0);
 +  add_tail(&buck->prefixes, &px->buck_node);
 +
 +  bgp_schedule_packet(p->conn, c, PKT_UPDATE);
  }
  
 +
  static inline u32
  bgp_get_neighbor(rte *r)
  {
diff --cc proto/bgp/bgp.c
index 61d24f42be0c91c566f6ea7941d3ea46cf86eb36,0f1c9446ded8c48f9365cf1b96855df896655bc9..5e95e6b4158c311164eba70e10ff6be10b7836b9
@@@ -559,6 -416,9 +559,10 @@@ bgp_conn_leave_established_state(struc
    BGP_TRACE(D_EVENTS, "BGP session closed");
    p->conn = NULL;
  
 -  bgp_free_prefix_table(p);
 -  bgp_free_bucket_table(p);
++  // XXXX free these tables to avoid memory leak during graceful restart
++  // bgp_free_prefix_table(p);
++  // bgp_free_bucket_table(p);
    if (p->p.proto_state == PS_UP)
      bgp_stop(p, 0);
  }
diff --cc proto/ospf/rt.c
index 054841caa58e70e22306b75ad90fbd463dbda7aa,368e3d05257498238cafa5207f25d54bc288423f..49167cebc2ea6d429c096bc624db6cc71df9cb62
@@@ -1429,7 -1405,7 +1428,6 @@@ ospf_ext_spf(struct ospf_proto *p
    struct top_hash_entry *en;
    struct ospf_lsa_ext_local rt;
    ort *nf1, *nf2;
-   orta nfa = {};
 -  ip_addr rtid;
    u32 br_metric;
    struct ospf_area *atmp;
  
@@@ -1573,11 -1552,15 +1573,12 @@@ ospf_rt_reset(struct ospf_proto *p
  {
    struct ospf_area *oa;
    struct top_hash_entry *en;
 -  struct area_net *anet;
 -  ort *ri;
  
    /* Reset old routing table */
 -  FIB_WALK(&p->rtf, nftmp)
 +  FIB_WALK(&p->rtf, ort, ri)
    {
 -    ri = (ort *) nftmp;
      ri->area_net = 0;
+     ri->keep = 0;
      reset_ri(ri);
    }
    FIB_WALK_END;
@@@ -1999,13 -1995,10 +2003,13 @@@ again1
      }
  
      /* Remove unused rt entry, some special entries are persistent */
-     if (!nf->n.type && !nf->external_rte && !nf->area_net)
+     if (!nf->n.type && !nf->external_rte && !nf->area_net && !nf->keep)
      {
 -      FIB_ITERATE_PUT(&fit, nftmp);
 -      fib_delete(fib, nftmp);
 +      if (nf->lsa_id)
 +      idm_free(&p->idm, nf->lsa_id);
 +
 +      FIB_ITERATE_PUT(&fit);
 +      fib_delete(fib, nf);
        goto again1;
      }
    }
diff --cc proto/ospf/rt.h
index 959d12e95382a17c21ecdccc1e1622d59fd75983,73b28375c79525f3816a4a7c6bbbbe6fbf381cf2..118d09b723dacafec2c0f917be42a487d65a30ad
@@@ -81,11 -81,10 +81,12 @@@ typedef struct or
    orta n;
    u32 old_metric1, old_metric2, old_tag, old_rid;
    rta *old_rta;
 +  u32 lsa_id;
    u8 external_rte;
    u8 area_net;
+   u8 keep;
 +
 +  struct fib_node fn;
  }
  ort;
  
Simple merge
Simple merge
Simple merge