BGP: Add support for flowspec (RFC 5575)
This commit is contained in:
parent
b7605d5c95
commit
ac3ad139f6
6 changed files with 247 additions and 6 deletions
|
@ -42,6 +42,9 @@ const char *flow_type_str(enum flow_type type, int ipv6);
|
||||||
|
|
||||||
uint flow_write_length(byte *data, u16 len);
|
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)
|
static inline u16 flow_read_length(const byte *data)
|
||||||
{ return ((*data & 0xf0) == 0xf0) ? get_u16(data) & 0x0fff : *data; }
|
{ return ((*data & 0xf0) == 0xf0) ? get_u16(data) & 0x0fff : *data; }
|
||||||
|
|
||||||
|
|
|
@ -1221,8 +1221,8 @@ bgp_init_prefix_table(struct bgp_channel *c)
|
||||||
{
|
{
|
||||||
HASH_INIT(c->prefix_hash, c->pool, 8);
|
HASH_INIT(c->prefix_hash, c->pool, 8);
|
||||||
|
|
||||||
c->prefix_slab = sl_new(c->pool, sizeof(struct bgp_prefix) +
|
uint alen = net_addr_length[c->c.net_type];
|
||||||
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 *
|
static struct bgp_prefix *
|
||||||
|
@ -1237,7 +1237,11 @@ bgp_get_prefix(struct bgp_channel *c, net_addr *net, u32 path_id)
|
||||||
return px;
|
return px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (c->prefix_slab)
|
||||||
px = sl_alloc(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.next = NULL;
|
||||||
px->buck_node.prev = NULL;
|
px->buck_node.prev = NULL;
|
||||||
px->hash = hash;
|
px->hash = hash;
|
||||||
|
@ -1254,7 +1258,11 @@ bgp_free_prefix(struct bgp_channel *c, struct bgp_prefix *px)
|
||||||
{
|
{
|
||||||
rem_node(&px->buck_node);
|
rem_node(&px->buck_node);
|
||||||
HASH_REMOVE2(c->prefix_hash, PXH, c->pool, px);
|
HASH_REMOVE2(c->prefix_hash, PXH, c->pool, px);
|
||||||
|
|
||||||
|
if (c->prefix_slab)
|
||||||
sl_free(c->prefix_slab, px);
|
sl_free(c->prefix_slab, px);
|
||||||
|
else
|
||||||
|
mb_free(px);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1846,7 +1846,7 @@ struct protocol proto_bgp = {
|
||||||
.template = "bgp%d",
|
.template = "bgp%d",
|
||||||
.attr_class = EAP_BGP,
|
.attr_class = EAP_BGP,
|
||||||
.preference = DEF_PREF_BGP,
|
.preference = DEF_PREF_BGP,
|
||||||
.channel_mask = NB_IP,
|
.channel_mask = NB_IP | NB_FLOW4 | NB_FLOW6,
|
||||||
.proto_size = sizeof(struct bgp_proto),
|
.proto_size = sizeof(struct bgp_proto),
|
||||||
.config_size = sizeof(struct bgp_config),
|
.config_size = sizeof(struct bgp_config),
|
||||||
.postconfig = bgp_postconfig,
|
.postconfig = bgp_postconfig,
|
||||||
|
|
|
@ -31,6 +31,7 @@ struct eattr;
|
||||||
|
|
||||||
#define BGP_SAFI_UNICAST 1
|
#define BGP_SAFI_UNICAST 1
|
||||||
#define BGP_SAFI_MULTICAST 2
|
#define BGP_SAFI_MULTICAST 2
|
||||||
|
#define BGP_SAFI_FLOW 133
|
||||||
|
|
||||||
/* Internal AF codes */
|
/* Internal AF codes */
|
||||||
|
|
||||||
|
@ -42,6 +43,8 @@ struct eattr;
|
||||||
#define BGP_AF_IPV6 BGP_AF( BGP_AFI_IPV6, BGP_SAFI_UNICAST )
|
#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_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_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;
|
struct bgp_write_state;
|
||||||
|
|
|
@ -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,
|
BGP_CLUSTER_LIST, IGP, TABLE, GATEWAY, DIRECT, RECURSIVE, MED, TTL,
|
||||||
SECURITY, DETERMINISTIC, SECONDARY, ALLOW, BFD, ADD, PATHS, RX, TX,
|
SECURITY, DETERMINISTIC, SECONDARY, ALLOW, BFD, ADD, PATHS, RX, TX,
|
||||||
GRACEFUL, RESTART, AWARE, CHECK, LINK, PORT, EXTENDED, MESSAGES, SETKEY,
|
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
|
%type <i32> bgp_afi
|
||||||
|
|
||||||
|
@ -139,6 +139,8 @@ bgp_afi:
|
||||||
| IPV6 { $$ = BGP_AF_IPV6; }
|
| IPV6 { $$ = BGP_AF_IPV6; }
|
||||||
| IPV4 MULTICAST { $$ = BGP_AF_IPV4_MC; }
|
| IPV4 MULTICAST { $$ = BGP_AF_IPV4_MC; }
|
||||||
| IPV6 MULTICAST { $$ = BGP_AF_IPV6_MC; }
|
| IPV6 MULTICAST { $$ = BGP_AF_IPV6_MC; }
|
||||||
|
| FLOW4 { $$ = BGP_AF_FLOW4; }
|
||||||
|
| FLOW6 { $$ = BGP_AF_FLOW6; }
|
||||||
;
|
;
|
||||||
|
|
||||||
bgp_channel_start: bgp_afi
|
bgp_channel_start: bgp_afi
|
||||||
|
|
|
@ -20,6 +20,7 @@
|
||||||
#include "nest/mrtdump.h"
|
#include "nest/mrtdump.h"
|
||||||
#include "conf/conf.h"
|
#include "conf/conf.h"
|
||||||
#include "lib/unaligned.h"
|
#include "lib/unaligned.h"
|
||||||
|
#include "lib/flowspec.h"
|
||||||
#include "lib/socket.h"
|
#include "lib/socket.h"
|
||||||
|
|
||||||
#include "nest/cli.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);
|
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
|
* 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[] = {
|
static const struct bgp_af_desc bgp_af_table[] = {
|
||||||
{
|
{
|
||||||
.afi = BGP_AF_IPV4,
|
.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,
|
.decode_next_hop = bgp_decode_next_hop_ip4,
|
||||||
.update_next_hop = bgp_update_next_hop_ip,
|
.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,
|
.afi = BGP_AF_IPV6,
|
||||||
.net = NET_IP6,
|
.net = NET_IP6,
|
||||||
|
@ -1107,6 +1322,16 @@ static const struct bgp_af_desc bgp_af_table[] = {
|
||||||
.decode_next_hop = bgp_decode_next_hop_ip6,
|
.decode_next_hop = bgp_decode_next_hop_ip6,
|
||||||
.update_next_hop = bgp_update_next_hop_ip,
|
.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 *
|
const struct bgp_af_desc *
|
||||||
|
|
Loading…
Reference in a new issue