summaryrefslogtreecommitdiff
path: root/proto/bgp
diff options
context:
space:
mode:
authorOndrej Zajicek (work) <santiago@crfreenet.org>2016-12-07 18:28:07 +0100
committerOndrej Zajicek (work) <santiago@crfreenet.org>2016-12-07 18:29:34 +0100
commitac3ad139f648184d44707ab145fde3a03ef5cb6e (patch)
tree789f16b88e0be380306f86ed1fdc4cc3cb4ae59c /proto/bgp
parentb7605d5c953902b461e5c9e87aa3dfa60ddce5bc (diff)
BGP: Add support for flowspec (RFC 5575)
Diffstat (limited to 'proto/bgp')
-rw-r--r--proto/bgp/attrs.c16
-rw-r--r--proto/bgp/bgp.c2
-rw-r--r--proto/bgp/bgp.h3
-rw-r--r--proto/bgp/config.Y4
-rw-r--r--proto/bgp/packets.c225
5 files changed, 244 insertions, 6 deletions
diff --git a/proto/bgp/attrs.c b/proto/bgp/attrs.c
index 52b56efa..227ddadc 100644
--- a/proto/bgp/attrs.c
+++ b/proto/bgp/attrs.c
@@ -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);
}
diff --git a/proto/bgp/bgp.c b/proto/bgp/bgp.c
index 2ca153ab..b7229429 100644
--- a/proto/bgp/bgp.c
+++ b/proto/bgp/bgp.c
@@ -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,
diff --git a/proto/bgp/bgp.h b/proto/bgp/bgp.h
index 4ecb86a0..db9ee8ea 100644
--- a/proto/bgp/bgp.h
+++ b/proto/bgp/bgp.h
@@ -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;
diff --git a/proto/bgp/config.Y b/proto/bgp/config.Y
index 10a338d8..2a54db17 100644
--- a/proto/bgp/config.Y
+++ b/proto/bgp/config.Y
@@ -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
diff --git a/proto/bgp/packets.c b/proto/bgp/packets.c
index 66561ee4..1ae75a64 100644
--- a/proto/bgp/packets.c
+++ b/proto/bgp/packets.c
@@ -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,
@@ -1088,6 +1293,16 @@ static const struct bgp_af_desc bgp_af_table[] = {
.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,
.name = "ipv6",
@@ -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 *