X-Git-Url: https://gerrit.fd.io/r/gitweb?a=blobdiff_plain;f=src%2Fvnet%2Fgre%2Finterface.c;h=ae5da93e0f01bc8746e0da9e29b29923a9159d77;hb=630b9741659b9a4b68c64ebbeb675761c6f26842;hp=d624587d8e9d0612a30d2f2389154974854651bd;hpb=7cd468a3d7dee7d6c92f69a0bb7061ae208ec727;p=vpp.git diff --git a/src/vnet/gre/interface.c b/src/vnet/gre/interface.c index d624587d8e9..ae5da93e0f0 100644 --- a/src/vnet/gre/interface.c +++ b/src/vnet/gre/interface.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -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; + u64 key4, key6[4]; - key = gre_mk_key(src, dst, out_fib_index); - - 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,28 +105,55 @@ 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 * gre_tunnel_from_fib_node (fib_node_t *node) { -#if (CLIB_DEBUG > 0) ASSERT(FIB_NODE_TYPE_GRE_TUNNEL == node->fn_type); -#endif return ((gre_tunnel_t*) (((char*)node) - STRUCT_OFFSET_OF(gre_tunnel_t, node))); } @@ -230,26 +279,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,51 +390,50 @@ 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); + FIB_ENTRY_FLAG_NONE); t->sibling_index = fib_entry_child_add(t->fib_entry_index, 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 +446,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 +455,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,13 +537,16 @@ 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; u32 num_m_args = 0; 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)) @@ -499,31 +555,67 @@ 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; else - return clib_error_return (0, "unknown input `%U'", - format_unformat_error, input); + { + error = clib_error_return (0, "unknown input `%U'", + format_unformat_error, line_input); + goto done; + } } - unformat_free (line_input); if (num_m_args < 2) - return clib_error_return (0, "mandatory argument(s) missing"); + { + error = clib_error_return (0, "mandatory argument(s) missing"); + goto done; + } - if (memcmp (&src, &dst, sizeof(src)) == 0) - return clib_error_return (0, "src and dst are identical"); + 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); @@ -536,15 +628,21 @@ create_gre_tunnel_command_fn (vlib_main_t * vm, vlib_cli_output(vm, "%U\n", format_vnet_sw_if_index_name, vnet_get_main(), sw_if_index); break; case VNET_API_ERROR_INVALID_VALUE: - return clib_error_return (0, "GRE tunnel already exists..."); + error = clib_error_return (0, "GRE tunnel already exists..."); + goto done; case VNET_API_ERROR_NO_SUCH_FIB: - return clib_error_return (0, "outer fib ID %d doesn't exist\n", - outer_fib_id); + error = clib_error_return (0, "outer fib ID %d doesn't exist\n", + outer_fib_id); + goto done; default: - return clib_error_return (0, "vnet_gre_add_del_tunnel returned %d", rv); + error = clib_error_return (0, "vnet_gre_add_del_tunnel returned %d", rv); + goto done; } - return 0; +done: + unformat_free (line_input); + + return error; } VLIB_CLI_COMMAND (create_gre_tunnel_command, static) = {