aboutsummaryrefslogtreecommitdiffstats
path: root/src/vnet/gre/interface.c
diff options
context:
space:
mode:
authorCiara Loftus <ciara.loftus@intel.com>2016-09-30 15:47:03 +0100
committerCiara Loftus <ciara.loftus@intel.com>2017-04-05 09:06:23 +0100
commit7eac916e1b00d6a3393a09925e1634d71bf30568 (patch)
tree94a3167a1abf03e62a2207f28905263a2b09229e /src/vnet/gre/interface.c
parent63d5bae6401049debadfa9fcc3f18d8118b80441 (diff)
GRE over IPv6
Refactors the GRE node to work with both IPv4 and IPv6 transports. Note that this changes the binary configuration API to support both address families; each address uses the same memory for either address type and a flag to indicate which is in use. The CLI and VAT syntax remains unchanged; the code detects whether an IPv4 or an IPv6 address was given. Configuration examples: IPv4 CLI: create gre tunnel src 192.168.1.1 dst 192.168.1.2 IPv6 CLI: create gre tunnel src 2620:124:9000::1 dst 2620:124:9000::2 IPv4 VAT: gre_add_del_tunnel src 192.168.1.1 dst 192.168.1.2 IPv6 VAT: gre_add_del_tunnel src 2620:124:9000::1 dst 2620:124:9000::2 Change-Id: Ica8ee775dc101047fb8cd41617ddc8fafc2741b0 Signed-off-by: Ciara Loftus <ciara.loftus@intel.com>
Diffstat (limited to 'src/vnet/gre/interface.c')
-rw-r--r--src/vnet/gre/interface.c194
1 files changed, 140 insertions, 54 deletions
diff --git a/src/vnet/gre/interface.c b/src/vnet/gre/interface.c
index d4476ac4682..91a3899ff53 100644
--- a/src/vnet/gre/interface.c
+++ b/src/vnet/gre/interface.c
@@ -20,6 +20,7 @@
#include <vnet/gre/gre.h>
#include <vnet/ip/format.h>
#include <vnet/fib/ip4_fib.h>
+#include <vnet/fib/ip6_fib.h>
#include <vnet/adj/adj_midchain.h>
#include <vnet/adj/adj_nbr.h>
#include <vnet/mpls/mpls.h>
@@ -27,7 +28,7 @@
static const char *gre_tunnel_type_names[] = GRE_TUNNEL_TYPE_NAMES;
static inline u64
-gre_mk_key (const ip4_address_t *src,
+gre4_mk_key (const ip4_address_t *src,
const ip4_address_t *dst,
u32 out_fib_index)
{
@@ -48,30 +49,51 @@ format_gre_tunnel (u8 * s, va_list * args)
{
gre_tunnel_t * t = va_arg (*args, gre_tunnel_t *);
gre_main_t * gm = &gre_main;
-
- s = format (s,
- "[%d] %U (src) %U (dst) payload %U outer_fib_index %d",
- t - gm->tunnels,
- format_ip4_address, &t->tunnel_src,
- format_ip4_address, &t->tunnel_dst,
- format_gre_tunnel_type, t->type,
- t->outer_fib_index);
+ u8 is_ipv6 = t->tunnel_dst.fp_proto == FIB_PROTOCOL_IP6 ? 1 : 0;
+
+ if (!is_ipv6)
+ s = format (s,
+ "[%d] %U (src) %U (dst) payload %U outer_fib_index %d",
+ t - gm->tunnels,
+ format_ip4_address, &t->tunnel_src.ip4,
+ format_ip4_address, &t->tunnel_dst.fp_addr.ip4,
+ format_gre_tunnel_type, t->type,
+ t->outer_fib_index);
+ else
+ s = format (s,
+ "[%d] %U (src) %U (dst) payload %U outer_fib_index %d",
+ t - gm->tunnels,
+ format_ip6_address, &t->tunnel_src.ip6,
+ format_ip6_address, &t->tunnel_dst.fp_addr.ip6,
+ format_gre_tunnel_type, t->type,
+ t->outer_fib_index);
return s;
}
static gre_tunnel_t *
-gre_tunnel_db_find (const ip4_address_t *src,
- const ip4_address_t *dst,
- u32 out_fib_index)
+gre_tunnel_db_find (const ip46_address_t *src,
+ const ip46_address_t *dst,
+ u32 out_fib_index,
+ u8 is_ipv6)
{
gre_main_t * gm = &gre_main;
uword * p;
- u64 key;
-
- key = gre_mk_key(src, dst, out_fib_index);
+ u64 key4, key6[4];
- p = hash_get (gm->tunnel_by_key, key);
+ if (!is_ipv6)
+ {
+ key4 = gre4_mk_key(&src->ip4, &dst->ip4, out_fib_index);
+ p = hash_get (gm->tunnel_by_key4, key4);
+ }
+ else
+ {
+ key6[0] = src->ip6.as_u64[0];
+ key6[1] = src->ip6.as_u64[1];
+ key6[2] = dst->ip6.as_u64[0];
+ key6[3] = dst->ip6.as_u64[1];
+ p = hash_get_mem (gm->tunnel_by_key6, key6);
+ }
if (NULL == p)
return (NULL);
@@ -83,20 +105,49 @@ static void
gre_tunnel_db_add (const gre_tunnel_t *t)
{
gre_main_t * gm = &gre_main;
- u64 key;
+ u64 key4, key6[4], *key6_copy;
+ u8 is_ipv6 = t->tunnel_dst.fp_proto == FIB_PROTOCOL_IP6 ? 1 : 0;
- key = gre_mk_key(&t->tunnel_src, &t->tunnel_dst, t->outer_fib_index);
- hash_set (gm->tunnel_by_key, key, t - gm->tunnels);
+ if (!is_ipv6)
+ {
+ key4 = gre4_mk_key(&t->tunnel_src.ip4, &t->tunnel_dst.fp_addr.ip4,
+ t->outer_fib_index);
+ hash_set (gm->tunnel_by_key4, key4, t - gm->tunnels);
+ }
+ else
+ {
+ key6[0] = t->tunnel_src.ip6.as_u64[0];
+ key6[1] = t->tunnel_src.ip6.as_u64[1];
+ key6[2] = t->tunnel_dst.fp_addr.ip6.as_u64[0];
+ key6[3] = t->tunnel_dst.fp_addr.ip6.as_u64[1];
+ key6_copy = clib_mem_alloc (sizeof (key6));
+ clib_memcpy (key6_copy, key6, sizeof (key6));
+ hash_set_mem (gm->tunnel_by_key6, key6_copy, t - gm->tunnels);
+ }
}
static void
gre_tunnel_db_remove (const gre_tunnel_t *t)
{
gre_main_t * gm = &gre_main;
- u64 key;
+ u64 key4, key6[4];
+ u8 is_ipv6 = t->tunnel_dst.fp_proto == FIB_PROTOCOL_IP6 ? 1 : 0;
+
+ if (!is_ipv6)
+ {
+ key4 = gre4_mk_key(&t->tunnel_src.ip4, &t->tunnel_dst.fp_addr.ip4,
+ t->outer_fib_index);
+ hash_unset (gm->tunnel_by_key4, key4);
+ }
+ else
+ {
+ key6[0] = t->tunnel_src.ip6.as_u64[0];
+ key6[1] = t->tunnel_src.ip6.as_u64[1];
+ key6[2] = t->tunnel_dst.fp_addr.ip6.as_u64[0];
+ key6[3] = t->tunnel_dst.fp_addr.ip6.as_u64[1];
+ hash_unset_mem (gm->tunnel_by_key6, key6);
+ }
- key = gre_mk_key(&t->tunnel_src, &t->tunnel_dst, t->outer_fib_index);
- hash_unset (gm->tunnel_by_key, key);
}
static gre_tunnel_t *
@@ -230,26 +281,31 @@ const static fib_node_vft_t gre_vft = {
.fnv_back_walk = gre_tunnel_back_walk,
};
-static int
+static int
vnet_gre_tunnel_add (vnet_gre_add_del_tunnel_args_t *a,
u32 * sw_if_indexp)
{
gre_main_t * gm = &gre_main;
vnet_main_t * vnm = gm->vnet_main;
- ip4_main_t * im = &ip4_main;
+ ip4_main_t * im4 = &ip4_main;
+ ip6_main_t * im6 = &ip6_main;
gre_tunnel_t * t;
vnet_hw_interface_t * hi;
u32 hw_if_index, sw_if_index;
u32 outer_fib_index;
u8 address[6];
clib_error_t *error;
+ u8 is_ipv6 = a->is_ipv6;
- outer_fib_index = ip4_fib_index_from_table_id(a->outer_fib_id);
+ if (!is_ipv6)
+ outer_fib_index = ip4_fib_index_from_table_id(a->outer_fib_id);
+ else
+ outer_fib_index = ip6_fib_index_from_table_id(a->outer_fib_id);
if (~0 == outer_fib_index)
return VNET_API_ERROR_NO_SUCH_FIB;
- t = gre_tunnel_db_find(&a->src, &a->dst, a->outer_fib_id);
+ t = gre_tunnel_db_find(&a->src, &a->dst, a->outer_fib_id, a->is_ipv6);
if (NULL != t)
return VNET_API_ERROR_INVALID_VALUE;
@@ -336,37 +392,40 @@ vnet_gre_tunnel_add (vnet_gre_add_del_tunnel_args_t *a,
vec_validate_init_empty (gm->tunnel_index_by_sw_if_index, sw_if_index, ~0);
gm->tunnel_index_by_sw_if_index[sw_if_index] = t - gm->tunnels;
- vec_validate (im->fib_index_by_sw_if_index, sw_if_index);
+ if (!is_ipv6)
+ {
+ vec_validate (im4->fib_index_by_sw_if_index, sw_if_index);
+ hi->min_packet_bytes = 64 + sizeof (gre_header_t) + sizeof (ip4_header_t);
+ }
+ else
+ {
+ vec_validate (im6->fib_index_by_sw_if_index, sw_if_index);
+ hi->min_packet_bytes = 64 + sizeof (gre_header_t) + sizeof (ip6_header_t);
+ }
- hi->min_packet_bytes = 64 + sizeof (gre_header_t) + sizeof (ip4_header_t);
hi->per_packet_overhead_bytes =
/* preamble */ 8 + /* inter frame gap */ 12;
/* Standard default gre MTU. */
hi->max_l3_packet_bytes[VLIB_RX] = hi->max_l3_packet_bytes[VLIB_TX] = 9000;
- clib_memcpy (&t->tunnel_src, &a->src, sizeof (t->tunnel_src));
- clib_memcpy (&t->tunnel_dst, &a->dst, sizeof (t->tunnel_dst));
-
- gre_tunnel_db_add(t);
-
/*
* source the FIB entry for the tunnel's destination
* and become a child thereof. The tunnel will then get poked
* when the forwarding for the entry updates, and the tunnel can
* re-stack accordingly
*/
- const fib_prefix_t tun_dst_pfx = {
- .fp_len = 32,
- .fp_proto = FIB_PROTOCOL_IP4,
- .fp_addr = {
- .ip4 = t->tunnel_dst,
- }
- };
+
+ clib_memcpy (&t->tunnel_src, &a->src, sizeof (t->tunnel_src));
+ t->tunnel_dst.fp_len = !is_ipv6 ? 32 : 128;
+ t->tunnel_dst.fp_proto = !is_ipv6 ? FIB_PROTOCOL_IP4 : FIB_PROTOCOL_IP6;
+ t->tunnel_dst.fp_addr = a->dst;
+
+ gre_tunnel_db_add(t);
t->fib_entry_index =
fib_table_entry_special_add(outer_fib_index,
- &tun_dst_pfx,
+ &t->tunnel_dst,
FIB_SOURCE_RR,
FIB_ENTRY_FLAG_NONE,
ADJ_INDEX_INVALID);
@@ -375,12 +434,9 @@ vnet_gre_tunnel_add (vnet_gre_add_del_tunnel_args_t *a,
FIB_NODE_TYPE_GRE_TUNNEL,
t - gm->tunnels);
- clib_memcpy (&t->tunnel_src, &a->src, sizeof (t->tunnel_src));
- clib_memcpy (&t->tunnel_dst, &a->dst, sizeof (t->tunnel_dst));
-
if (GRE_TUNNEL_TYPE_TEB == t->type)
{
- t->l2_adj_index = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
+ t->l2_adj_index = adj_nbr_add_or_lock(t->tunnel_dst.fp_proto,
VNET_LINK_ETHERNET,
&zero_addr,
sw_if_index);
@@ -393,7 +449,7 @@ vnet_gre_tunnel_add (vnet_gre_add_del_tunnel_args_t *a,
return 0;
}
-static int
+static int
vnet_gre_tunnel_delete (vnet_gre_add_del_tunnel_args_t *a,
u32 * sw_if_indexp)
{
@@ -402,7 +458,7 @@ vnet_gre_tunnel_delete (vnet_gre_add_del_tunnel_args_t *a,
gre_tunnel_t * t;
u32 sw_if_index;
- t = gre_tunnel_db_find(&a->src, &a->dst, a->outer_fib_id);
+ t = gre_tunnel_db_find(&a->src, &a->dst, a->outer_fib_id, a->is_ipv6);
if (NULL == t)
return VNET_API_ERROR_NO_SUCH_ENTRY;
@@ -484,7 +540,7 @@ create_gre_tunnel_command_fn (vlib_main_t * vm,
{
unformat_input_t _line_input, * line_input = &_line_input;
vnet_gre_add_del_tunnel_args_t _a, * a = &_a;
- ip4_address_t src, dst;
+ ip46_address_t src, dst;
u32 outer_fib_id = 0;
u8 teb = 0;
int rv;
@@ -492,6 +548,8 @@ create_gre_tunnel_command_fn (vlib_main_t * vm,
u8 is_add = 1;
u32 sw_if_index;
clib_error_t *error = NULL;
+ u8 ipv4_set = 0;
+ u8 ipv6_set = 0;
/* Get a line of input. */
if (! unformat_user (input, unformat_line_input, line_input))
@@ -500,11 +558,19 @@ create_gre_tunnel_command_fn (vlib_main_t * vm,
while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT) {
if (unformat (line_input, "del"))
is_add = 0;
- else if (unformat (line_input, "src %U", unformat_ip4_address, &src))
+ else if (unformat (line_input, "src %U", unformat_ip4_address, &src.ip4)) {
num_m_args++;
- else if (unformat (line_input, "dst %U", unformat_ip4_address, &dst))
+ ipv4_set = 1;
+ } else if (unformat (line_input, "dst %U", unformat_ip4_address, &dst.ip4)) {
num_m_args++;
- else if (unformat (line_input, "outer-fib-id %d", &outer_fib_id))
+ ipv4_set = 1;
+ } else if (unformat (line_input, "src %U", unformat_ip6_address, &src.ip6)) {
+ num_m_args++;
+ ipv6_set = 1;
+ } else if (unformat (line_input, "dst %U", unformat_ip6_address, &dst.ip6)) {
+ num_m_args++;
+ ipv6_set = 1;
+ } else if (unformat (line_input, "outer-fib-id %d", &outer_fib_id))
;
else if (unformat (line_input, "teb"))
teb = 1;
@@ -522,17 +588,37 @@ create_gre_tunnel_command_fn (vlib_main_t * vm,
goto done;
}
- if (memcmp (&src, &dst, sizeof(src)) == 0)
+ if ((ipv4_set && memcmp (&src.ip4, &dst.ip4, sizeof(src.ip4)) == 0) ||
+ (ipv6_set && memcmp (&src.ip6, &dst.ip6, sizeof(src.ip6)) == 0))
{
error = clib_error_return (0, "src and dst are identical");
goto done;
}
+ if (ipv4_set && ipv6_set)
+ return clib_error_return (0, "both IPv4 and IPv6 addresses specified");
+
+ if ((ipv4_set && memcmp (&dst.ip4, &zero_addr.ip4, sizeof(dst.ip4)) == 0) ||
+ (ipv6_set && memcmp (&dst.ip6, &zero_addr.ip6, sizeof(dst.ip6)) == 0))
+ {
+ error = clib_error_return (0, "dst address cannot be zero");
+ goto done;
+ }
+
memset (a, 0, sizeof (*a));
a->outer_fib_id = outer_fib_id;
a->teb = teb;
- clib_memcpy(&a->src, &src, sizeof(src));
- clib_memcpy(&a->dst, &dst, sizeof(dst));
+ a->is_ipv6 = ipv6_set;
+ if (!ipv6_set)
+ {
+ clib_memcpy(&a->src.ip4, &src.ip4, sizeof(src.ip4));
+ clib_memcpy(&a->dst.ip4, &dst.ip4, sizeof(dst.ip4));
+ }
+ else
+ {
+ clib_memcpy(&a->src.ip6, &src.ip6, sizeof(src.ip6));
+ clib_memcpy(&a->dst.ip6, &dst.ip6, sizeof(dst.ip6));
+ }
if (is_add)
rv = vnet_gre_tunnel_add(a, &sw_if_index);