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

BMP: Remove duplicate functions for update encoding

Use existing BGP functions also for BMP update encoding.
parent cc1e4ab7
Loading
Loading
Loading
Loading
+1 −2
Original line number Diff line number Diff line
@@ -215,8 +215,7 @@ struct proto {
  void (*if_notify)(struct proto *, unsigned flags, struct iface *i);
  void (*ifa_notify)(struct proto *, unsigned flags, struct ifa *a);
  void (*rt_notify)(struct proto *, struct channel *, struct network *net, struct rte *new, struct rte *old);
  void (*rte_update_in_notify)(const struct proto *, const struct channel *,
    const net *net, const struct rte *new, const struct rte *old, const struct rte_src *src);
  void (*rte_update_in_notify)(struct channel *, const net_addr *, const struct rte *, const struct rte_src *);
  void (*neigh_notify)(struct neighbor *neigh);
  void (*make_tmp_attrs)(struct rte *rt, struct linpool *pool);
  void (*store_tmp_attrs)(struct rte *rt, struct linpool *pool);
+2 −12
Original line number Diff line number Diff line
@@ -2542,12 +2542,6 @@ rte_update_in(struct channel *c, const net_addr *n, rte *new, struct rte_src *sr
	if (old->flags & (REF_STALE | REF_DISCARD | REF_MODIFY))
	{
	  old->flags &= ~(REF_STALE | REF_DISCARD | REF_MODIFY);

    if (c->proto->rte_update_in_notify)
    {
      c->proto->rte_update_in_notify(c->proto, c, net, new, old, src);
    }

	  return 1;
	}

@@ -2572,9 +2566,7 @@ rte_update_in(struct channel *c, const net_addr *n, rte *new, struct rte_src *sr
      goto drop_withdraw;

    if (c->proto->rte_update_in_notify)
    {
      c->proto->rte_update_in_notify(c->proto, c, net, new, old, src);
    }
      c->proto->rte_update_in_notify(c, n, NULL, src);

    return 1;
  }
@@ -2606,9 +2598,7 @@ rte_update_in(struct channel *c, const net_addr *n, rte *new, struct rte_src *sr
  tab->rt_count++;

  if (c->proto->rte_update_in_notify)
  {
    c->proto->rte_update_in_notify(c->proto, c, net, new, old, src);
  }
    c->proto->rte_update_in_notify(c, n, e, src);

  return 1;

+2 −4
Original line number Diff line number Diff line
@@ -409,6 +409,7 @@ struct bgp_write_state {
  int as4_session;
  int add_path;
  int mpls;
  int sham;

  eattr *mp_next_hop;
  const adata *mpls_labels;
@@ -592,10 +593,7 @@ int bgp_rte_mergable(rte *pri, rte *sec);
int bgp_rte_recalculate(rtable *table, net *net, rte *new, rte *old, rte *old_best);
struct rte *bgp_rte_modify_stale(struct rte *r, struct linpool *pool);
void bgp_rt_notify(struct proto *P, struct channel *C, net *n, rte *new, rte *old);
void
bgp_rte_update_in_notify(const struct proto *P, const struct channel *C,
  const net *net, const struct rte *new, const struct rte *old,
  const struct rte_src *src);
void bgp_rte_update_in_notify(struct channel *C, const net_addr *n, const struct rte *new, const struct rte_src *src);
int bgp_preexport(struct proto *, struct rte **, struct linpool *);
int bgp_get_attr(const struct eattr *e, byte *buf, int buflen);
void bgp_get_route_info(struct rte *, byte *buf);
+89 −321
Original line number Diff line number Diff line
@@ -1471,7 +1471,10 @@ bgp_encode_nlri_ip4(struct bgp_write_state *s, struct bgp_bucket *buck, byte *bu
    memcpy(pos, &a, b);
    ADVANCE(pos, size, b);

    if (!s->sham)
      bgp_free_prefix(s->channel, px);
    else
      rem_node(&px->buck_node);
  }

  return pos - buf;
@@ -1556,7 +1559,10 @@ bgp_encode_nlri_ip6(struct bgp_write_state *s, struct bgp_bucket *buck, byte *bu
    memcpy(pos, &a, b);
    ADVANCE(pos, size, b);

    if (!s->sham)
      bgp_free_prefix(s->channel, px);
    else
      rem_node(&px->buck_node);
  }

  return pos - buf;
@@ -1644,7 +1650,10 @@ bgp_encode_nlri_vpn4(struct bgp_write_state *s, struct bgp_bucket *buck, byte *b
    memcpy(pos, &a, b);
    ADVANCE(pos, size, b);

    if (!s->sham)
      bgp_free_prefix(s->channel, px);
    else
      rem_node(&px->buck_node);
  }

  return pos - buf;
@@ -1741,7 +1750,10 @@ bgp_encode_nlri_vpn6(struct bgp_write_state *s, struct bgp_bucket *buck, byte *b
    memcpy(pos, &a, b);
    ADVANCE(pos, size, b);

    if (!s->sham)
      bgp_free_prefix(s->channel, px);
    else
      rem_node(&px->buck_node);
  }

  return pos - buf;
@@ -1828,7 +1840,10 @@ bgp_encode_nlri_flow4(struct bgp_write_state *s, struct bgp_bucket *buck, byte *
    memcpy(pos, net->data, flen);
    ADVANCE(pos, size, flen);

    if (!s->sham)
      bgp_free_prefix(s->channel, px);
    else
      rem_node(&px->buck_node);
  }

  return pos - buf;
@@ -1916,7 +1931,10 @@ bgp_encode_nlri_flow6(struct bgp_write_state *s, struct bgp_bucket *buck, byte *
    memcpy(pos, net->data, flen);
    ADVANCE(pos, size, flen);

    if (!s->sham)
      bgp_free_prefix(s->channel, px);
    else
      rem_node(&px->buck_node);
  }

  return pos - buf;
@@ -2139,224 +2157,6 @@ bgp_update_next_hop(struct bgp_export_state *s, eattr *a, ea_list **to)

#define MAX_ATTRS_LENGTH (end-buf+BGP_HEADER_LENGTH - 1024)

/**
 * Following functions starting with prefix bgp_bmp_* compose BGP UPDATE messages.
 * Their implementation has been adopted from relevant function without 'bmp_' part in 
 * their names.
 */

// Buffer @buf should be big enough. It means that there should be available at least 19 bytes
static byte *
bgp_bmp_prepare_bgp_hdr(byte *buf, const u16 msg_size, const u8 msg_type)
{
  if (!buf)
  {
    return NULL;
  }

  memset(buf + BGP_MSG_HDR_MARKER_POS, 0xff, BGP_MSG_HDR_MARKER_SIZE);
  put_u16(buf + BGP_MSG_HDR_LENGTH_POS, msg_size);
  put_u8(buf + BGP_MSG_HDR_TYPE_POS, msg_type);

  return buf + BGP_MSG_HDR_TYPE_POS + BGP_MSG_HDR_TYPE_SIZE;
}

static uint
bgp_bmp_encode_nlri_ip4(struct bgp_write_state *s, const net *n,
  const u32 path_id, byte *buf, uint size)
{
  const struct net_addr_ip4 *naddr = (net_addr_ip4 *)n->n.addr;

  byte *pos = buf;
  /* Encode path ID */
  if (s->add_path)
  {
    put_u32(pos, path_id);
    ADVANCE(pos, size, 4);
  }

  /* Encode prefix length */
  *pos = naddr->pxlen;
  ADVANCE(pos, size, 1);

  /* Encode MPLS labels */
  if (s->mpls)
  {
    bgp_encode_mpls_labels(s, s->mpls_labels, &pos, &size, pos - 1);
  }

  /* Encode prefix body */
  ip4_addr a = ip4_hton(naddr->prefix);
  uint b = (naddr->pxlen + 7) / 8;
  memcpy(pos, &a, b);
  ADVANCE(pos, size, b);

  return pos - buf;
}

static uint
bgp_bmp_encode_nlri_ip6(struct bgp_write_state *s, const net *n,
  const u32 path_id, byte *buf, uint size)
{
  if (size < BGP_NLRI_MAX)
  {
    return 0;
  }

  const struct net_addr_ip6 *naddr = (net_addr_ip6 *)n->n.addr;
  byte *pos = buf;
  /* Encode path ID */
  if (s->add_path)
  {
    put_u32(pos, path_id);
    ADVANCE(pos, size, 4);
  }

  /* Encode prefix length */
  *pos = naddr->pxlen;
  ADVANCE(pos, size, 1);

  /* Encode MPLS labels */
  if (s->mpls)
  {
    bgp_encode_mpls_labels(s, s->mpls_labels, &pos, &size, pos - 1);
  }

  /* Encode prefix body */
  ip6_addr a = ip6_hton(naddr->prefix);
  uint b = (naddr->pxlen + 7) / 8;
  memcpy(pos, &a, b);
  ADVANCE(pos, size, b);

  return pos - buf;
}

static byte *
bgp_bmp_create_ip_reach(struct bgp_write_state *s, const net *n,
  const struct rte *new, const struct rte *old, const u32 path_id,
  byte *buf, uint size)
{
  /*
   *	2 B	Withdrawn Routes Length (zero)
   *	---	IPv4 Withdrawn Routes NLRI (unused)
   *	2 B	Total Path Attribute Length
   *	var	Path Attributes
   *	var	IPv4 Network Layer Reachability Information
   */

  int lr, la; // Route length, attribute length
  ea_list *attrs = new ? new->attrs->eattrs : old->attrs->eattrs;
  bgp_fix_attr_flags(attrs);

  la = bgp_encode_attrs(s, attrs, buf + 2, buf + size - 2);
  if (la < 0)
  {
    /* Attribute list too long */
    log(L_ERR "Failed to encode UPDATE msg attributes");
    return NULL;
  }

  put_u16(buf, la);
  lr = bgp_bmp_encode_nlri_ip4(s, n, path_id, buf + 2 + la, size - (2 + la));

  return buf + 2 + la + lr;
}

static byte *
bgp_bmp_create_mp_reach(struct bgp_write_state *s, const net *n,
  const struct rte *new, const struct rte *old, const u32 path_id,
  byte *buf, uint size)
{
  /*
   *	2 B	IPv4 Withdrawn Routes Length (zero)
   *	---	IPv4 Withdrawn Routes NLRI (unused)
   *	2 B	Total Path Attribute Length
   *	1 B	MP_REACH_NLRI hdr - Attribute Flags
   *	1 B	MP_REACH_NLRI hdr - Attribute Type Code
   *	2 B	MP_REACH_NLRI hdr - Length of Attribute Data
   *	2 B	MP_REACH_NLRI data - Address Family Identifier
   *	1 B	MP_REACH_NLRI data - Subsequent Address Family Identifier
   *	1 B	MP_REACH_NLRI data - Length of Next Hop Network Address
   *	var	MP_REACH_NLRI data - Network Address of Next Hop
   *	1 B	MP_REACH_NLRI data - Reserved (zero)
   *	var	MP_REACH_NLRI data - Network Layer Reachability Information
   *	var	Rest of Path Attributes
   *	---	IPv4 Network Layer Reachability Information (unused)
   */

  int lh, lr, la;	/* Lengths of next hop, NLRI and attributes */

  /* Begin of MP_REACH_NLRI atribute */
  buf[4] = BAF_OPTIONAL | BAF_EXT_LEN;
  buf[5] = BA_MP_REACH_NLRI;
  put_u16(buf+6, 0);		/* Will be fixed later */
  put_af3(buf+8, s->channel->afi);
  byte *pos = buf+11;
  byte *end = buf + size;
  /* Encode attributes to temporary buffer */
  byte *abuf = alloca(MAX_ATTRS_LENGTH);

  ea_list *attrs = new ? new->attrs->eattrs : old->attrs->eattrs;
  bgp_fix_attr_flags(attrs);

  la = bgp_encode_attrs(s, attrs, abuf, abuf + MAX_ATTRS_LENGTH);
  if (la < 0)
  {
    /* Attribute list too long */
    log(L_ERR "Failed to encode UPDATE msg attributes");
    return NULL;
  }

  /* Encode the next hop */
  lh = bgp_encode_next_hop(s, s->mp_next_hop, pos+1);
  *pos = lh;
  pos += 1+lh;

  /* Reserved field */
  *pos++ = 0;

  /* Encode the NLRI */
  lr = bgp_bmp_encode_nlri_ip6(s, n, path_id, pos, end - (buf + la));
  pos += lr;

  /* End of MP_REACH_NLRI atribute, update data length */
  put_u16(buf+6, pos-buf-8);

  /* Copy remaining attributes */
  memcpy(pos, abuf, la);
  pos += la;

  /* Initial UPDATE fields */
  put_u16(buf+0, 0);
  put_u16(buf+2, pos-buf-4);

  return pos;
}

static byte *
bgp_bmp_create_ip_unreach(struct bgp_write_state *s, const net *n,
  const struct rte *new, const struct rte *old, const u32 path_id,
  byte *buf, uint size)
{
  /*
   *	2 B	Withdrawn Routes Length
   *	var	IPv4 Withdrawn Routes NLRI
   *	2 B	Total Path Attribute Length (zero)
   *	---	Path Attributes (unused)
   *	---	IPv4 Network Layer Reachability Information (unused)
   */

  uint len = 0;
  bool is_withdrawn = !new && old;
  if (is_withdrawn)
  {
    len = bgp_bmp_encode_nlri_ip4(s, n, path_id, buf + 2, size - 2);
  }

  put_u16(buf, len);
  return buf + 2 + len;
}

static byte *
bgp_create_ip_reach(struct bgp_write_state *s, struct bgp_bucket *buck, byte *buf, byte *end)
{
@@ -2374,6 +2174,7 @@ bgp_create_ip_reach(struct bgp_write_state *s, struct bgp_bucket *buck, byte *bu
  if (la < 0)
  {
    /* Attribute list too long */
    if (!s->sham)
      bgp_withdraw_bucket(s->channel, buck);
    return NULL;
  }
@@ -2421,6 +2222,7 @@ bgp_create_mp_reach(struct bgp_write_state *s, struct bgp_bucket *buck, byte *bu
  if (la < 0)
  {
    /* Attribute list too long */
    if (!s->sham)
      bgp_withdraw_bucket(s->channel, buck);
    return NULL;
  }
@@ -2503,53 +2305,11 @@ bgp_create_mp_unreach(struct bgp_write_state *s, struct bgp_bucket *buck, byte *
}

static byte *
bgp_bmp_create_mp_unreach(struct bgp_write_state *s, const net *n,
  const struct rte *new, const struct rte *old, const u32 path_id,
  byte *buf, uint size)
bgp_create_update_bmp(struct bgp_channel *c, byte *buf, struct bgp_bucket *buck, bool update)
{
  /*
   *	2 B	Withdrawn Routes Length (zero)
   *	---	IPv4 Withdrawn Routes NLRI (unused)
   *	2 B	Total Path Attribute Length
   *	1 B	MP_UNREACH_NLRI hdr - Attribute Flags
   *	1 B	MP_UNREACH_NLRI hdr - Attribute Type Code
   *	2 B	MP_UNREACH_NLRI hdr - Length of Attribute Data
   *	2 B	MP_UNREACH_NLRI data - Address Family Identifier
   *	1 B	MP_UNREACH_NLRI data - Subsequent Address Family Identifier
   *	var	MP_UNREACH_NLRI data - Network Layer Reachability Information
   *	---	IPv4 Network Layer Reachability Information (unused)
   */

  uint len = 0;
  bool is_withdrawn = !new && old;
  if (is_withdrawn)
  {
    len = bgp_bmp_encode_nlri_ip6(s, n, path_id, buf + 11, size);
  }

  put_u16(buf+0, 0);
  put_u16(buf+2, 7+len);

  /* Begin of MP_UNREACH_NLRI atribute */
  buf[4] = BAF_OPTIONAL | BAF_EXT_LEN;
  buf[5] = BA_MP_UNREACH_NLRI;

  put_u16(buf+6, 3+len);
  put_af3(buf+8, s->channel->afi);

  return buf+11+len;
}

void
bgp_rte_update_in_notify(const struct proto *P, const struct channel *C,
  const net *n, const struct rte *new, const struct rte *old,
  const struct rte_src *src)
{
  struct bgp_proto *p = (struct bgp_proto *)P;
  struct bgp_channel *c = (struct bgp_channel *)C;
  byte buf[BGP_MAX_EXT_MSG_LENGTH] = { 0x00 };
  byte *pkt = buf + BGP_HEADER_LENGTH;
  byte *end = pkt + (bgp_max_packet_length(p->conn) - BGP_HEADER_LENGTH);
  struct bgp_proto *p = (void *) c->c.proto;
  byte *end = buf + (BGP_MAX_EXT_MSG_LENGTH - BGP_HEADER_LENGTH);
  /* FIXME: must be a bit shorter */

  struct bgp_caps *peer = p->conn->remote_caps;
  const struct bgp_af_caps *rem = bgp_find_af_caps(peer, c->afi);
@@ -2557,65 +2317,73 @@ bgp_rte_update_in_notify(const struct proto *P, const struct channel *C,
    .proto = p,
    .channel = c,
    .pool = bgp_linpool,
    .mp_reach = (bgp_channel_is_ipv6(c) || rem->ext_next_hop),
    .as4_session = peer->as4_support,
    .mp_reach = (c->afi != BGP_AF_IPV4) || rem->ext_next_hop,
    .as4_session = 1,
    .add_path = c->add_path_rx,
    .mpls = c->desc->mpls,
    .sham = 1,
  };

  const u32 path_id = c->add_path_rx ? src->private_id : 0;
  byte *pos = pkt;
  if (!s.mp_reach)
  if (!update)
  {
    pos = bgp_bmp_create_ip_unreach(&s, n, new, old, path_id, pkt, end - pkt);
    if (!pos)
    {
      log(L_ERR "Failed to create unreachable field in UPDATE message");
      return;
    return !s.mp_reach ?
      bgp_create_ip_unreach(&s, buck, buf, end):
      bgp_create_mp_unreach(&s, buck, buf, end);
  }

    pos = bgp_bmp_create_ip_reach(&s, n, new, old, path_id, pos, end - pos);
    if (!pos)
  else
  {
      log(L_ERR "Failed to create reachable field in UPDATE message");
      return;
    return !s.mp_reach ?
      bgp_create_ip_reach(&s, buck, buf, end):
      bgp_create_mp_reach(&s, buck, buf, end);
  }

    bgp_bmp_prepare_bgp_hdr(buf, pos - buf, PKT_UPDATE);
    bmp_route_monitor_put_update_in_pre_msg(buf, pos - buf);
}
  else if (new) // && s.mp_reach
  {
    pos = s.mp_reach
            ? bgp_bmp_create_mp_reach(&s, n, new, old, path_id, pos, end - pos)
            : bgp_bmp_create_ip_reach(&s, n, new, old, path_id, pos, end - pos);
    if (!pos)

static byte *
bgp_bmp_prepare_bgp_hdr(byte *buf, const u16 msg_size, const u8 msg_type)
{
      log(L_ERR "Failed to create reachable field in UPDATE message");
      return;
    }
  memset(buf + BGP_MSG_HDR_MARKER_POS, 0xff, BGP_MSG_HDR_MARKER_SIZE);
  put_u16(buf + BGP_MSG_HDR_LENGTH_POS, msg_size);
  put_u8(buf + BGP_MSG_HDR_TYPE_POS, msg_type);

    bgp_bmp_prepare_bgp_hdr(buf, pos - buf, PKT_UPDATE);
    bmp_route_monitor_put_update_in_pre_msg(buf, pos - buf);
  return buf + BGP_MSG_HDR_TYPE_POS + BGP_MSG_HDR_TYPE_SIZE;
}

  if (!new && old)
  {
    bmp_route_monitor_update_in_pre_commit(p);
    bmp_route_monitor_update_in_pre_end();
    bmp_route_monitor_update_in_pre_begin();
    pkt = buf + BGP_HEADER_LENGTH;
    end = pkt + (bgp_max_packet_length(p->conn) - BGP_HEADER_LENGTH);
    pos = bgp_bmp_create_mp_unreach(&s, n, new, old, path_id, pkt, end - pkt);
    if (!pos)
void
bgp_rte_update_in_notify(struct channel *C, const net_addr *n,
			 const struct rte *new, const struct rte_src *src)
{
      log(L_ERR "Failed to create unreachable field in UPDATE message");
//  struct bgp_proto *p = (void *) C->proto;
  struct bgp_channel *c = (void *) C;

  byte buf[BGP_MAX_EXT_MSG_LENGTH];
  byte *pkt = buf + BGP_HEADER_LENGTH;

  ea_list *attrs = new ? new->attrs->eattrs : NULL;
  uint ea_size = new ? (sizeof(ea_list) + attrs->count * sizeof(eattr)) : 0;
  uint bucket_size = sizeof(struct bgp_bucket) + ea_size;
  uint prefix_size = sizeof(struct bgp_prefix) + n->length;

  /* Sham bucket */
  struct bgp_bucket *b = alloca(bucket_size);
  *b = (struct bgp_bucket) { };
  init_list(&b->prefixes);

  if (attrs)
    memcpy(b->eattrs, attrs, ea_size);

  /* Sham prefix */
  struct bgp_prefix *px = alloca(prefix_size);
  *px = (struct bgp_prefix) { };
  px->path_id = src->private_id;
  net_copy(px->net, n);
  add_tail(&b->prefixes, &px->buck_node);

  byte *end = bgp_create_update_bmp(c, pkt, b, !!new);
  if (!end)
    return;
    }

    bgp_bmp_prepare_bgp_hdr(buf, pos - buf, PKT_UPDATE);
    bmp_route_monitor_put_update_in_pre_msg(buf, pos - buf);
  }
  bgp_bmp_prepare_bgp_hdr(buf, end - buf, PKT_UPDATE);
  bmp_route_monitor_put_update_in_pre_msg(buf, end - buf);
}

static byte *
+4 −4
Original line number Diff line number Diff line
@@ -210,7 +210,7 @@ struct bmp_data_node {
};

static void
bmp_route_monitor_pre_policy_table_in_snapshot(const struct channel *C);
bmp_route_monitor_pre_policy_table_in_snapshot(struct channel *C);

static void
bmp_common_hdr_serialize(buffer *stream, const enum bmp_message_type type, const u32 data_size)
@@ -881,8 +881,8 @@ bmp_route_monitor_update_in_pre_end()
  }
}

void
bmp_route_monitor_pre_policy_table_in_snapshot(const struct channel *C)
static void
bmp_route_monitor_pre_policy_table_in_snapshot(struct channel *C)
{
  struct bmp_proto *p = g_bmp;

@@ -915,7 +915,7 @@ bmp_route_monitor_pre_policy_table_in_snapshot(const struct channel *C)
    rte *e;
    for (e = n->routes; e; e = e->next)
    {
      bgp_rte_update_in_notify(P, C, n, e, NULL, e->attrs->src);
      bgp_rte_update_in_notify(C, n->n.addr, e, e->attrs->src);
    }

    bmp_route_monitor_update_in_pre_commit((struct bgp_proto *) P);