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);
|
||||
|
||||
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; }
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
if (c->prefix_slab)
|
||||
sl_free(c->prefix_slab, px);
|
||||
else
|
||||
mb_free(px);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 *
|
||||
|
|
Loading…
Reference in a new issue