diff options
author | Ciara Loftus <ciara.loftus@intel.com> | 2016-09-30 15:47:03 +0100 |
---|---|---|
committer | Ciara Loftus <ciara.loftus@intel.com> | 2017-04-05 09:06:23 +0100 |
commit | 7eac916e1b00d6a3393a09925e1634d71bf30568 (patch) | |
tree | 94a3167a1abf03e62a2207f28905263a2b09229e /src/vnet/gre/interface.c | |
parent | 63d5bae6401049debadfa9fcc3f18d8118b80441 (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.c | 194 |
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); |