]> git.ipfire.org Git - thirdparty/bird.git/commitdiff
BGP: Add support for flowspec (RFC 5575)
authorOndrej Zajicek (work) <santiago@crfreenet.org>
Wed, 7 Dec 2016 17:28:07 +0000 (18:28 +0100)
committerOndrej Zajicek (work) <santiago@crfreenet.org>
Wed, 7 Dec 2016 17:29:34 +0000 (18:29 +0100)
lib/flowspec.h
proto/bgp/attrs.c
proto/bgp/bgp.c
proto/bgp/bgp.h
proto/bgp/config.Y
proto/bgp/packets.c

index 57809becb3e13a68c9bd9a83de1e15633fb9b6c9..aa9735f413645bdb1628d1442a01801923f64fc0 100644 (file)
@@ -42,6 +42,9 @@ const char *flow_type_str(enum flow_type type, int ipv6);
 
 uint flow_write_length(byte *data, u16 len);
 
+static inline u16 flow_hdr_length(const byte *data)
+{ return ((*data & 0xf0) == 0xf0) ? 2 : 1; }
+
 static inline u16 flow_read_length(const byte *data)
 { return ((*data & 0xf0) == 0xf0) ? get_u16(data) & 0x0fff : *data; }
 
index 52b56efa429daf1ce7ec8e00d7a907d7332771ee..227ddadc1fc270528af8082c00d604d560b17ce6 100644 (file)
@@ -1221,8 +1221,8 @@ bgp_init_prefix_table(struct bgp_channel *c)
 {
   HASH_INIT(c->prefix_hash, c->pool, 8);
 
-  c->prefix_slab = sl_new(c->pool, sizeof(struct bgp_prefix) +
-                         net_addr_length[c->c.net_type]);
+  uint alen = net_addr_length[c->c.net_type];
+  c->prefix_slab = alen ? sl_new(c->pool, sizeof(struct bgp_prefix) + alen) : NULL;
 }
 
 static struct bgp_prefix *
@@ -1237,7 +1237,11 @@ bgp_get_prefix(struct bgp_channel *c, net_addr *net, u32 path_id)
     return px;
   }
 
-  px = sl_alloc(c->prefix_slab);
+  if (c->prefix_slab)
+    px = sl_alloc(c->prefix_slab);
+  else
+    px = mb_alloc(c->pool, sizeof(struct bgp_prefix) + net->length);
+
   px->buck_node.next = NULL;
   px->buck_node.prev = NULL;
   px->hash = hash;
@@ -1254,7 +1258,11 @@ bgp_free_prefix(struct bgp_channel *c, struct bgp_prefix *px)
 {
   rem_node(&px->buck_node);
   HASH_REMOVE2(c->prefix_hash, PXH, c->pool, px);
-  sl_free(c->prefix_slab, px);
+
+  if (c->prefix_slab)
+    sl_free(c->prefix_slab, px);
+  else
+    mb_free(px);
 }
 
 
index 2ca153ab28d6d62b439333e8305752956fa018c0..b7229429c665fe0dd96dcf2d735c51cc1587eda2 100644 (file)
@@ -1846,7 +1846,7 @@ struct protocol proto_bgp = {
   .template =          "bgp%d",
   .attr_class =        EAP_BGP,
   .preference =        DEF_PREF_BGP,
-  .channel_mask =      NB_IP,
+  .channel_mask =      NB_IP | NB_FLOW4 | NB_FLOW6,
   .proto_size =                sizeof(struct bgp_proto),
   .config_size =       sizeof(struct bgp_config),
   .postconfig =                bgp_postconfig,
index 4ecb86a0bb6644aa525c5039a820118023472b2a..db9ee8ea0d95a469ee0468fc8df279009490e8b1 100644 (file)
@@ -31,6 +31,7 @@ struct eattr;
 
 #define BGP_SAFI_UNICAST       1
 #define BGP_SAFI_MULTICAST     2
+#define BGP_SAFI_FLOW          133
 
 /* Internal AF codes */
 
@@ -42,6 +43,8 @@ struct eattr;
 #define BGP_AF_IPV6            BGP_AF( BGP_AFI_IPV6, BGP_SAFI_UNICAST )
 #define BGP_AF_IPV4_MC         BGP_AF( BGP_AFI_IPV4, BGP_SAFI_MULTICAST )
 #define BGP_AF_IPV6_MC         BGP_AF( BGP_AFI_IPV6, BGP_SAFI_MULTICAST )
+#define BGP_AF_FLOW4           BGP_AF( BGP_AFI_IPV4, BGP_SAFI_FLOW )
+#define BGP_AF_FLOW6           BGP_AF( BGP_AFI_IPV6, BGP_SAFI_FLOW )
 
 
 struct bgp_write_state;
index 10a338d831a6a855bd2a91d5827104cc1f38ab51..2a54db17e8cfc07a5b0e4cc2d9f04954c564235d 100644 (file)
@@ -28,7 +28,7 @@ CF_KEYWORDS(BGP, LOCAL, NEIGHBOR, AS, HOLD, TIME, CONNECT, RETRY, KEEPALIVE,
        BGP_CLUSTER_LIST, IGP, TABLE, GATEWAY, DIRECT, RECURSIVE, MED, TTL,
        SECURITY, DETERMINISTIC, SECONDARY, ALLOW, BFD, ADD, PATHS, RX, TX,
        GRACEFUL, RESTART, AWARE, CHECK, LINK, PORT, EXTENDED, MESSAGES, SETKEY,
-       STRICT, BIND, CONFEDERATION, MEMBER, MULTICAST)
+       STRICT, BIND, CONFEDERATION, MEMBER, MULTICAST, FLOW4, FLOW6)
 
 %type <i32> bgp_afi
 
@@ -139,6 +139,8 @@ bgp_afi:
  | IPV6 { $$ = BGP_AF_IPV6; }
  | IPV4 MULTICAST { $$ = BGP_AF_IPV4_MC; }
  | IPV6 MULTICAST { $$ = BGP_AF_IPV6_MC; }
+ | FLOW4 { $$ = BGP_AF_FLOW4; }
+ | FLOW6 { $$ = BGP_AF_FLOW6; }
  ;
 
 bgp_channel_start: bgp_afi
index 66561ee4a0c5ab3bd79af5331242e8ab6b38f3b5..1ae75a644e05cf764c5130a4abc85521ca457048 100644 (file)
@@ -20,6 +20,7 @@
 #include "nest/mrtdump.h"
 #include "conf/conf.h"
 #include "lib/unaligned.h"
+#include "lib/flowspec.h"
 #include "lib/socket.h"
 
 #include "nest/cli.h"
@@ -793,6 +794,26 @@ bgp_update_next_hop_ip(struct bgp_export_state *s, eattr *a, ea_list **to)
     WITHDRAW(BAD_NEXT_HOP);
 }
 
+static uint
+bgp_encode_next_hop_none(struct bgp_write_state *s UNUSED, eattr *a UNUSED, byte *buf UNUSED, uint size UNUSED)
+{
+  // FIXME
+  return 0;
+}
+
+static void
+bgp_decode_next_hop_none(struct bgp_parse_state *s UNUSED, byte *data UNUSED, uint len UNUSED, rta *a UNUSED)
+{
+  // FIXME
+  return;
+}
+
+static void
+bgp_update_next_hop_none(struct bgp_export_state *s UNUSED, eattr *a UNUSED, ea_list **to UNUSED)
+{
+  // FIXME
+}
+
 
 /*
  *     UPDATE
@@ -1066,6 +1087,190 @@ bgp_decode_next_hop_ip6(struct bgp_parse_state *s, byte *data, uint len, rta *a)
 }
 
 
+static uint
+bgp_encode_nlri_flow4(struct bgp_write_state *s, struct bgp_bucket *buck, byte *buf, uint size)
+{
+  byte *pos = buf;
+
+  while (!EMPTY_LIST(buck->prefixes) && (size >= 4))
+  {
+    struct bgp_prefix *px = HEAD(buck->prefixes);
+    struct net_addr_flow4 *net = (void *) px->net;
+    uint flen = net->length - sizeof(net_addr_flow4);
+
+    /* Encode path ID */
+    if (s->add_path)
+    {
+      put_u32(pos, px->path_id);
+      ADVANCE(pos, size, 4);
+    }
+
+    if (flen > size)
+      break;
+
+    /* Copy whole flow data including length */
+    memcpy(pos, net->data, flen);
+    ADVANCE(pos, size, flen);
+
+    bgp_free_prefix(s->channel, px);
+  }
+
+  return pos - buf;
+}
+
+static void
+bgp_decode_nlri_flow4(struct bgp_parse_state *s, byte *pos, uint len, rta *a)
+{
+  while (len)
+  {
+    u32 path_id = 0;
+
+    /* Decode path ID */
+    if (s->add_path)
+    {
+      if (len < 4)
+       bgp_parse_error(s, 1);
+
+      path_id = get_u32(pos);
+      ADVANCE(pos, len, 4);
+    }
+
+    if (len < 2)
+      bgp_parse_error(s, 1);
+
+    /* Decode flow length */
+    uint hlen = flow_hdr_length(pos);
+    uint dlen = flow_read_length(pos);
+    uint flen = hlen + dlen;
+    byte *data = pos + hlen;
+
+    if (len < flen)
+      bgp_parse_error(s, 1);
+
+    /* Validate flow data */
+    enum flow_validated_state r = flow4_validate(data, dlen);
+    if (r != FLOW_ST_VALID)
+    {
+      log(L_REMOTE "%s: Invalid flow route: %s", s->proto->p.name, flow_validated_state_str(r));
+      bgp_parse_error(s, 1);
+    }
+
+    if (data[0] != FLOW_TYPE_DST_PREFIX)
+    {
+      log(L_REMOTE "%s: No dst prefix at first pos", s->proto->p.name);
+      bgp_parse_error(s, 1);
+    }
+
+    /* Decode dst prefix */
+    ip4_addr px = IP4_NONE;
+    uint pxlen = data[1];
+
+    // FIXME: Use some generic function
+    memcpy(&px, data, BYTES(pxlen));
+    px = ip4_and(px, ip4_mkmask(pxlen));
+
+    /* Prepare the flow */
+    net_addr *n = alloca(sizeof(struct net_addr_flow4) + flen);
+    net_fill_flow4(n, px, pxlen, pos, flen);
+    ADVANCE(pos, len, flen);
+
+    bgp_rte_update(s, n, path_id, a);
+  }
+}
+
+
+static uint
+bgp_encode_nlri_flow6(struct bgp_write_state *s, struct bgp_bucket *buck, byte *buf, uint size)
+{
+  byte *pos = buf;
+
+  while (!EMPTY_LIST(buck->prefixes) && (size >= 4))
+  {
+    struct bgp_prefix *px = HEAD(buck->prefixes);
+    struct net_addr_flow6 *net = (void *) px->net;
+    uint flen = net->length - sizeof(net_addr_flow6);
+
+    /* Encode path ID */
+    if (s->add_path)
+    {
+      put_u32(pos, px->path_id);
+      ADVANCE(pos, size, 4);
+    }
+
+    if (flen > size)
+      break;
+
+    /* Copy whole flow data including length */
+    memcpy(pos, net->data, flen);
+    ADVANCE(pos, size, flen);
+
+    bgp_free_prefix(s->channel, px);
+  }
+
+  return pos - buf;
+}
+
+static void
+bgp_decode_nlri_flow6(struct bgp_parse_state *s, byte *pos, uint len, rta *a)
+{
+  while (len)
+  {
+    u32 path_id = 0;
+
+    /* Decode path ID */
+    if (s->add_path)
+    {
+      if (len < 4)
+       bgp_parse_error(s, 1);
+
+      path_id = get_u32(pos);
+      ADVANCE(pos, len, 4);
+    }
+
+    if (len < 2)
+      bgp_parse_error(s, 1);
+
+    /* Decode flow length */
+    uint hlen = flow_hdr_length(pos);
+    uint dlen = flow_read_length(pos);
+    uint flen = hlen + dlen;
+    byte *data = pos + hlen;
+
+    if (len < flen)
+      bgp_parse_error(s, 1);
+
+    /* Validate flow data */
+    enum flow_validated_state r = flow6_validate(data, dlen);
+    if (r != FLOW_ST_VALID)
+    {
+      log(L_REMOTE "%s: Invalid flow route: %s", s->proto->p.name, flow_validated_state_str(r));
+      bgp_parse_error(s, 1);
+    }
+
+    if (data[0] != FLOW_TYPE_DST_PREFIX)
+    {
+      log(L_REMOTE "%s: No dst prefix at first pos", s->proto->p.name);
+      bgp_parse_error(s, 1);
+    }
+
+    /* Decode dst prefix */
+    ip6_addr px = IP6_NONE;
+    uint pxlen = data[1];
+
+    // FIXME: Use some generic function
+    memcpy(&px, data, BYTES(pxlen));
+    px = ip6_and(px, ip6_mkmask(pxlen));
+
+    /* Prepare the flow */
+    net_addr *n = alloca(sizeof(struct net_addr_flow6) + flen);
+    net_fill_flow6(n, px, pxlen, pos, flen);
+    ADVANCE(pos, len, flen);
+
+    bgp_rte_update(s, n, path_id, a);
+  }
+}
+
+
 static const struct bgp_af_desc bgp_af_table[] = {
   {
     .afi = BGP_AF_IPV4,
@@ -1087,6 +1292,16 @@ static const struct bgp_af_desc bgp_af_table[] = {
     .decode_next_hop = bgp_decode_next_hop_ip4,
     .update_next_hop = bgp_update_next_hop_ip,
   },
+  {
+    .afi = BGP_AF_FLOW4,
+    .net = NET_FLOW4,
+    .name = "flow4",
+    .encode_nlri = bgp_encode_nlri_flow4,
+    .decode_nlri = bgp_decode_nlri_flow4,
+    .encode_next_hop = bgp_encode_next_hop_none,
+    .decode_next_hop = bgp_decode_next_hop_none,
+    .update_next_hop = bgp_update_next_hop_none,
+  },
   {
     .afi = BGP_AF_IPV6,
     .net = NET_IP6,
@@ -1107,6 +1322,16 @@ static const struct bgp_af_desc bgp_af_table[] = {
     .decode_next_hop = bgp_decode_next_hop_ip6,
     .update_next_hop = bgp_update_next_hop_ip,
   },
+  {
+    .afi = BGP_AF_FLOW6,
+    .net = NET_FLOW6,
+    .name = "flow6",
+    .encode_nlri = bgp_encode_nlri_flow6,
+    .decode_nlri = bgp_decode_nlri_flow6,
+    .encode_next_hop = bgp_encode_next_hop_none,
+    .decode_next_hop = bgp_decode_next_hop_none,
+    .update_next_hop = bgp_update_next_hop_none,
+  },
 };
 
 const struct bgp_af_desc *