0
0
mirror of https://gitlab.nic.cz/labs/bird.git synced 2024-12-22 09:41:54 +00:00

BGP: Add support for flowspec (RFC 5575)

This commit is contained in:
Ondrej Zajicek (work) 2016-12-07 18:28:07 +01:00
parent b7605d5c95
commit ac3ad139f6
6 changed files with 247 additions and 6 deletions

View File

@ -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; }

View File

@ -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);
} }

View File

@ -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,

View File

@ -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;

View 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, 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

View File

@ -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 *