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>
This commit is contained in:
+65
-13
@@ -11018,21 +11018,45 @@ api_gre_add_del_tunnel (vat_main_t * vam)
|
||||
unformat_input_t *line_input = vam->input;
|
||||
vl_api_gre_add_del_tunnel_t *mp;
|
||||
ip4_address_t src4, dst4;
|
||||
ip6_address_t src6, dst6;
|
||||
u8 is_add = 1;
|
||||
u8 ipv4_set = 0;
|
||||
u8 ipv6_set = 0;
|
||||
u8 teb = 0;
|
||||
u8 src_set = 0;
|
||||
u8 dst_set = 0;
|
||||
u32 outer_fib_id = 0;
|
||||
int ret;
|
||||
|
||||
memset (&src4, 0, sizeof src4);
|
||||
memset (&dst4, 0, sizeof dst4);
|
||||
memset (&src6, 0, sizeof src6);
|
||||
memset (&dst6, 0, sizeof dst6);
|
||||
|
||||
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, &src4))
|
||||
src_set = 1;
|
||||
{
|
||||
src_set = 1;
|
||||
ipv4_set = 1;
|
||||
}
|
||||
else if (unformat (line_input, "dst %U", unformat_ip4_address, &dst4))
|
||||
dst_set = 1;
|
||||
{
|
||||
dst_set = 1;
|
||||
ipv4_set = 1;
|
||||
}
|
||||
else if (unformat (line_input, "src %U", unformat_ip6_address, &src6))
|
||||
{
|
||||
src_set = 1;
|
||||
ipv6_set = 1;
|
||||
}
|
||||
else if (unformat (line_input, "dst %U", unformat_ip6_address, &dst6))
|
||||
{
|
||||
dst_set = 1;
|
||||
ipv6_set = 1;
|
||||
}
|
||||
else if (unformat (line_input, "outer-fib-id %d", &outer_fib_id))
|
||||
;
|
||||
else if (unformat (line_input, "teb"))
|
||||
@@ -11054,15 +11078,29 @@ api_gre_add_del_tunnel (vat_main_t * vam)
|
||||
errmsg ("tunnel dst address not specified");
|
||||
return -99;
|
||||
}
|
||||
if (ipv4_set && ipv6_set)
|
||||
{
|
||||
errmsg ("both IPv4 and IPv6 addresses specified");
|
||||
return -99;
|
||||
}
|
||||
|
||||
|
||||
M (GRE_ADD_DEL_TUNNEL, mp);
|
||||
|
||||
clib_memcpy (&mp->src_address, &src4, sizeof (src4));
|
||||
clib_memcpy (&mp->dst_address, &dst4, sizeof (dst4));
|
||||
if (ipv4_set)
|
||||
{
|
||||
clib_memcpy (&mp->src_address, &src4, 4);
|
||||
clib_memcpy (&mp->dst_address, &dst4, 4);
|
||||
}
|
||||
else
|
||||
{
|
||||
clib_memcpy (&mp->src_address, &src6, 16);
|
||||
clib_memcpy (&mp->dst_address, &dst6, 16);
|
||||
}
|
||||
mp->outer_fib_id = ntohl (outer_fib_id);
|
||||
mp->is_add = is_add;
|
||||
mp->teb = teb;
|
||||
mp->is_ipv6 = ipv6_set;
|
||||
|
||||
S (mp);
|
||||
W (ret);
|
||||
@@ -11073,11 +11111,13 @@ static void vl_api_gre_tunnel_details_t_handler
|
||||
(vl_api_gre_tunnel_details_t * mp)
|
||||
{
|
||||
vat_main_t *vam = &vat_main;
|
||||
ip46_address_t src = to_ip46 (mp->is_ipv6, mp->src_address);
|
||||
ip46_address_t dst = to_ip46 (mp->is_ipv6, mp->dst_address);
|
||||
|
||||
print (vam->ofp, "%11d%15U%15U%6d%14d",
|
||||
print (vam->ofp, "%11d%24U%24U%6d%14d",
|
||||
ntohl (mp->sw_if_index),
|
||||
format_ip4_address, &mp->src_address,
|
||||
format_ip4_address, &mp->dst_address,
|
||||
format_ip46_address, &src, IP46_TYPE_ANY,
|
||||
format_ip46_address, &dst, IP46_TYPE_ANY,
|
||||
mp->teb, ntohl (mp->outer_fib_id));
|
||||
}
|
||||
|
||||
@@ -11087,6 +11127,7 @@ static void vl_api_gre_tunnel_details_t_handler_json
|
||||
vat_main_t *vam = &vat_main;
|
||||
vat_json_node_t *node = NULL;
|
||||
struct in_addr ip4;
|
||||
struct in6_addr ip6;
|
||||
|
||||
if (VAT_JSON_ARRAY != vam->json_tree.type)
|
||||
{
|
||||
@@ -11097,12 +11138,23 @@ static void vl_api_gre_tunnel_details_t_handler_json
|
||||
|
||||
vat_json_init_object (node);
|
||||
vat_json_object_add_uint (node, "sw_if_index", ntohl (mp->sw_if_index));
|
||||
clib_memcpy (&ip4, &mp->src_address, sizeof (ip4));
|
||||
vat_json_object_add_ip4 (node, "src_address", ip4);
|
||||
clib_memcpy (&ip4, &mp->dst_address, sizeof (ip4));
|
||||
vat_json_object_add_ip4 (node, "dst_address", ip4);
|
||||
if (!mp->is_ipv6)
|
||||
{
|
||||
clib_memcpy (&ip4, &mp->src_address, sizeof (ip4));
|
||||
vat_json_object_add_ip4 (node, "src_address", ip4);
|
||||
clib_memcpy (&ip4, &mp->dst_address, sizeof (ip4));
|
||||
vat_json_object_add_ip4 (node, "dst_address", ip4);
|
||||
}
|
||||
else
|
||||
{
|
||||
clib_memcpy (&ip6, &mp->src_address, sizeof (ip6));
|
||||
vat_json_object_add_ip6 (node, "src_address", ip6);
|
||||
clib_memcpy (&ip6, &mp->dst_address, sizeof (ip6));
|
||||
vat_json_object_add_ip6 (node, "dst_address", ip6);
|
||||
}
|
||||
vat_json_object_add_uint (node, "teb", mp->teb);
|
||||
vat_json_object_add_uint (node, "outer_fib_id", ntohl (mp->outer_fib_id));
|
||||
vat_json_object_add_uint (node, "is_ipv6", mp->is_ipv6);
|
||||
}
|
||||
|
||||
static int
|
||||
@@ -11131,7 +11183,7 @@ api_gre_tunnel_dump (vat_main_t * vam)
|
||||
|
||||
if (!vam->json_output)
|
||||
{
|
||||
print (vam->ofp, "%11s%15s%15s%6s%14s",
|
||||
print (vam->ofp, "%11s%24s%24s%6s%14s",
|
||||
"sw_if_index", "src_address", "dst_address", "teb",
|
||||
"outer_fib_id");
|
||||
}
|
||||
@@ -18612,7 +18664,7 @@ _(vxlan_add_del_tunnel, \
|
||||
"vni <vni> [encap-vrf-id <nn>] [decap-next <l2|nn>] [del]") \
|
||||
_(vxlan_tunnel_dump, "[<intfc> | sw_if_index <nn>]") \
|
||||
_(gre_add_del_tunnel, \
|
||||
"src <ip4-addr> dst <ip4-addr> [outer-fib-id <nn>] [teb] [del]\n") \
|
||||
"src <ip-addr> dst <ip-addr> [outer-fib-id <nn>] [teb] [del]\n") \
|
||||
_(gre_tunnel_dump, "[<intfc> | sw_if_index <nn>]") \
|
||||
_(l2_fib_clear_table, "") \
|
||||
_(l2_interface_efp_filter, "sw_if_index <nn> enable | disable") \
|
||||
|
||||
+86
-24
@@ -28,6 +28,13 @@ typedef struct {
|
||||
};
|
||||
} ip4_and_gre_union_t;
|
||||
|
||||
typedef struct {
|
||||
union {
|
||||
ip6_and_gre_header_t ip6_and_gre;
|
||||
u64 as_u64[3];
|
||||
};
|
||||
} ip6_and_gre_union_t;
|
||||
|
||||
|
||||
/* Packet trace structure */
|
||||
typedef struct {
|
||||
@@ -37,9 +44,9 @@ typedef struct {
|
||||
/* pkt length */
|
||||
u32 length;
|
||||
|
||||
/* tunnel ip4 addresses */
|
||||
ip4_address_t src;
|
||||
ip4_address_t dst;
|
||||
/* tunnel ip addresses */
|
||||
ip46_address_t src;
|
||||
ip46_address_t dst;
|
||||
} gre_tx_trace_t;
|
||||
|
||||
u8 * format_gre_tx_trace (u8 * s, va_list * args)
|
||||
@@ -50,8 +57,8 @@ u8 * format_gre_tx_trace (u8 * s, va_list * args)
|
||||
|
||||
s = format (s, "GRE: tunnel %d len %d src %U dst %U",
|
||||
t->tunnel_id, clib_net_to_host_u16 (t->length),
|
||||
format_ip4_address, &t->src.as_u8,
|
||||
format_ip4_address, &t->dst.as_u8);
|
||||
format_ip46_address, &t->src, IP46_TYPE_ANY,
|
||||
format_ip46_address, &t->dst, IP46_TYPE_ANY);
|
||||
return s;
|
||||
}
|
||||
|
||||
@@ -192,10 +199,12 @@ gre_build_rewrite (vnet_main_t * vnm,
|
||||
const void *dst_address)
|
||||
{
|
||||
gre_main_t * gm = &gre_main;
|
||||
ip4_and_gre_header_t * h;
|
||||
ip4_and_gre_header_t * h4;
|
||||
ip6_and_gre_header_t * h6;
|
||||
u8* rewrite = NULL;
|
||||
gre_tunnel_t *t;
|
||||
u32 ti;
|
||||
u8 is_ipv6;
|
||||
|
||||
ti = gm->tunnel_index_by_sw_if_index[sw_if_index];
|
||||
|
||||
@@ -205,23 +214,45 @@ gre_build_rewrite (vnet_main_t * vnm,
|
||||
|
||||
t = pool_elt_at_index(gm->tunnels, ti);
|
||||
|
||||
vec_validate(rewrite, sizeof(*h)-1);
|
||||
h = (ip4_and_gre_header_t*)rewrite;
|
||||
h->gre.protocol = clib_host_to_net_u16(gre_proto_from_vnet_link(link_type));
|
||||
is_ipv6 = t->tunnel_dst.fp_proto == FIB_PROTOCOL_IP6 ? 1 : 0;
|
||||
|
||||
h->ip4.ip_version_and_header_length = 0x45;
|
||||
h->ip4.ttl = 254;
|
||||
h->ip4.protocol = IP_PROTOCOL_GRE;
|
||||
/* fixup ip4 header length and checksum after-the-fact */
|
||||
h->ip4.src_address.as_u32 = t->tunnel_src.as_u32;
|
||||
h->ip4.dst_address.as_u32 = t->tunnel_dst.as_u32;
|
||||
h->ip4.checksum = ip4_header_checksum (&h->ip4);
|
||||
if (!is_ipv6)
|
||||
{
|
||||
vec_validate(rewrite, sizeof(*h4)-1);
|
||||
h4 = (ip4_and_gre_header_t*)rewrite;
|
||||
h4->gre.protocol = clib_host_to_net_u16(gre_proto_from_vnet_link(link_type));
|
||||
|
||||
h4->ip4.ip_version_and_header_length = 0x45;
|
||||
h4->ip4.ttl = 254;
|
||||
h4->ip4.protocol = IP_PROTOCOL_GRE;
|
||||
/* fixup ip4 header length and checksum after-the-fact */
|
||||
h4->ip4.src_address.as_u32 = t->tunnel_src.ip4.as_u32;
|
||||
h4->ip4.dst_address.as_u32 = t->tunnel_dst.fp_addr.ip4.as_u32;
|
||||
h4->ip4.checksum = ip4_header_checksum (&h4->ip4);
|
||||
}
|
||||
else
|
||||
{
|
||||
vec_validate(rewrite, sizeof(*h6)-1);
|
||||
h6 = (ip6_and_gre_header_t*)rewrite;
|
||||
h6->gre.protocol = clib_host_to_net_u16(gre_proto_from_vnet_link(link_type));
|
||||
|
||||
h6->ip6.ip_version_traffic_class_and_flow_label = clib_host_to_net_u32(6 << 28);
|
||||
h6->ip6.hop_limit = 255;
|
||||
h6->ip6.protocol = IP_PROTOCOL_GRE;
|
||||
/* fixup ip6 header length and checksum after-the-fact */
|
||||
h6->ip6.src_address.as_u64[0] = t->tunnel_src.ip6.as_u64[0];
|
||||
h6->ip6.src_address.as_u64[1] = t->tunnel_src.ip6.as_u64[1];
|
||||
h6->ip6.dst_address.as_u64[0] = t->tunnel_dst.fp_addr.ip6.as_u64[0];
|
||||
h6->ip6.dst_address.as_u64[1] = t->tunnel_dst.fp_addr.ip6.as_u64[1];
|
||||
}
|
||||
|
||||
return (rewrite);
|
||||
}
|
||||
|
||||
#define is_v4_packet(_h) ((*(u8*) _h) & 0xF0) == 0x40
|
||||
|
||||
void
|
||||
gre_fixup (vlib_main_t *vm,
|
||||
gre4_fixup (vlib_main_t *vm,
|
||||
ip_adjacency_t *adj,
|
||||
vlib_buffer_t *b0)
|
||||
{
|
||||
@@ -235,12 +266,37 @@ gre_fixup (vlib_main_t *vm,
|
||||
ip0->checksum = ip4_header_checksum (ip0);
|
||||
}
|
||||
|
||||
void
|
||||
gre6_fixup (vlib_main_t *vm,
|
||||
ip_adjacency_t *adj,
|
||||
vlib_buffer_t *b0)
|
||||
{
|
||||
ip6_header_t * ip0;
|
||||
|
||||
ip0 = vlib_buffer_get_current (b0);
|
||||
|
||||
/* Fixup the payload length field in the GRE tunnel encap that was applied
|
||||
* at the midchain node */
|
||||
ip0->payload_length =
|
||||
clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, b0))
|
||||
- sizeof(*ip0);
|
||||
}
|
||||
|
||||
void
|
||||
gre_update_adj (vnet_main_t * vnm,
|
||||
u32 sw_if_index,
|
||||
adj_index_t ai)
|
||||
{
|
||||
adj_nbr_midchain_update_rewrite (ai, gre_fixup,
|
||||
gre_main_t * gm = &gre_main;
|
||||
gre_tunnel_t *t;
|
||||
u32 ti;
|
||||
u8 is_ipv6;
|
||||
|
||||
ti = gm->tunnel_index_by_sw_if_index[sw_if_index];
|
||||
t = pool_elt_at_index(gm->tunnels, ti);
|
||||
is_ipv6 = t->tunnel_dst.fp_proto == FIB_PROTOCOL_IP6 ? 1 : 0;
|
||||
|
||||
adj_nbr_midchain_update_rewrite (ai, !is_ipv6 ? gre4_fixup : gre6_fixup,
|
||||
(VNET_LINK_ETHERNET == adj_get_link_type (ai) ?
|
||||
ADJ_FLAG_MIDCHAIN_NO_COUNT :
|
||||
ADJ_FLAG_NONE),
|
||||
@@ -264,6 +320,7 @@ gre_interface_tx_inline (vlib_main_t * vm,
|
||||
u32 * from, * to_next, n_left_from, n_left_to_next;
|
||||
vnet_interface_output_runtime_t * rd = (void *) node->runtime_data;
|
||||
const gre_tunnel_t *gt = pool_elt_at_index (gm->tunnels, rd->dev_instance);
|
||||
u8 is_ipv6 = gt->tunnel_dst.fp_proto == FIB_PROTOCOL_IP6 ? 1 : 0;
|
||||
|
||||
/* Vector of buffer / pkt indices we're supposed to process */
|
||||
from = vlib_frame_vector_args (frame);
|
||||
@@ -303,10 +360,10 @@ gre_interface_tx_inline (vlib_main_t * vm,
|
||||
{
|
||||
gre_tx_trace_t *tr = vlib_add_trace (vm, node,
|
||||
b0, sizeof (*tr));
|
||||
tr->tunnel_id = gt - gm->tunnels;
|
||||
tr->length = vlib_buffer_length_in_chain (vm, b0);
|
||||
tr->src.as_u32 = gt->tunnel_src.as_u32;
|
||||
tr->dst.as_u32 = gt->tunnel_src.as_u32;
|
||||
tr->tunnel_id = gt - gm->tunnels;
|
||||
tr->src = gt->tunnel_src;
|
||||
tr->dst = gt->tunnel_src;
|
||||
tr->length = vlib_buffer_length_in_chain (vm, b0);
|
||||
}
|
||||
|
||||
vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
|
||||
@@ -317,7 +374,8 @@ gre_interface_tx_inline (vlib_main_t * vm,
|
||||
vlib_put_next_frame (vm, node, next_index, n_left_to_next);
|
||||
}
|
||||
|
||||
vlib_node_increment_counter (vm, gre_input_node.index,
|
||||
vlib_node_increment_counter (vm, !is_ipv6 ? gre4_input_node.index :
|
||||
gre6_input_node.index,
|
||||
GRE_ERROR_PKTS_ENCAP, frame->n_vectors);
|
||||
|
||||
return frame->n_vectors;
|
||||
@@ -434,6 +492,9 @@ static clib_error_t * gre_init (vlib_main_t * vm)
|
||||
if ((error = vlib_call_init_function (vm, ip4_lookup_init)))
|
||||
return error;
|
||||
|
||||
if ((error = vlib_call_init_function (vm, ip6_lookup_init)))
|
||||
return error;
|
||||
|
||||
/* Set up the ip packet generator */
|
||||
pi = ip_get_protocol_info (im, IP_PROTOCOL_GRE);
|
||||
pi->format_header = format_gre_header;
|
||||
@@ -441,7 +502,8 @@ static clib_error_t * gre_init (vlib_main_t * vm)
|
||||
|
||||
gm->protocol_info_by_name = hash_create_string (0, sizeof (uword));
|
||||
gm->protocol_info_by_protocol = hash_create (0, sizeof (uword));
|
||||
gm->tunnel_by_key = hash_create (0, sizeof (uword));
|
||||
gm->tunnel_by_key4 = hash_create (0, sizeof (uword));
|
||||
gm->tunnel_by_key6 = hash_create_mem (0, sizeof(u64[4]), sizeof (uword));
|
||||
|
||||
#define _(n,s) add_protocol (gm, GRE_PROTOCOL_##s, #s);
|
||||
foreach_gre_protocol
|
||||
|
||||
+22
-8
@@ -21,8 +21,6 @@
|
||||
#include <vnet/vnet.h>
|
||||
#include <vnet/gre/packet.h>
|
||||
#include <vnet/ip/ip.h>
|
||||
#include <vnet/ip/ip4.h>
|
||||
#include <vnet/ip/ip4_packet.h>
|
||||
#include <vnet/pg/pg.h>
|
||||
#include <vnet/ip/format.h>
|
||||
#include <vnet/adj/adj_types.h>
|
||||
@@ -87,11 +85,11 @@ typedef struct {
|
||||
/**
|
||||
* The tunnel's source/local address
|
||||
*/
|
||||
ip4_address_t tunnel_src;
|
||||
ip46_address_t tunnel_src;
|
||||
/**
|
||||
* The tunnel's destination/remote address
|
||||
*/
|
||||
ip4_address_t tunnel_dst;
|
||||
fib_prefix_t tunnel_dst;
|
||||
/**
|
||||
* The FIB in which the src.dst address are present
|
||||
*/
|
||||
@@ -142,10 +140,16 @@ typedef struct {
|
||||
* Hash tables mapping name/protocol to protocol info index.
|
||||
*/
|
||||
uword * protocol_info_by_name, * protocol_info_by_protocol;
|
||||
|
||||
/**
|
||||
* Hash mapping src/dst addr pair to tunnel
|
||||
* Hash mapping ipv4 src/dst addr pair to tunnel
|
||||
*/
|
||||
uword * tunnel_by_key;
|
||||
uword * tunnel_by_key4;
|
||||
|
||||
/**
|
||||
* Hash mapping ipv6 src/dst addr pair to tunnel
|
||||
*/
|
||||
uword * tunnel_by_key6;
|
||||
|
||||
/**
|
||||
* Free vlib hw_if_indices.
|
||||
@@ -176,6 +180,14 @@ typedef CLIB_PACKED (struct {
|
||||
gre_header_t gre;
|
||||
}) ip4_and_gre_header_t;
|
||||
|
||||
/**
|
||||
* @brief IPv6 and GRE header.
|
||||
*/
|
||||
typedef CLIB_PACKED (struct {
|
||||
ip6_header_t ip6;
|
||||
gre_header_t gre;
|
||||
}) ip6_and_gre_header_t;
|
||||
|
||||
always_inline gre_protocol_info_t *
|
||||
gre_get_protocol_info (gre_main_t * em, gre_protocol_t protocol)
|
||||
{
|
||||
@@ -204,7 +216,8 @@ format_function_t format_gre_protocol;
|
||||
format_function_t format_gre_header;
|
||||
format_function_t format_gre_header_with_length;
|
||||
|
||||
extern vlib_node_registration_t gre_input_node;
|
||||
extern vlib_node_registration_t gre4_input_node;
|
||||
extern vlib_node_registration_t gre6_input_node;
|
||||
extern vnet_device_class_t gre_device_class;
|
||||
extern vnet_device_class_t gre_device_teb_class;
|
||||
|
||||
@@ -228,7 +241,8 @@ gre_register_input_protocol (vlib_main_t * vm,
|
||||
typedef struct {
|
||||
u8 is_add;
|
||||
|
||||
ip4_address_t src, dst;
|
||||
ip46_address_t src, dst;
|
||||
u8 is_ipv6;
|
||||
u32 outer_fib_id;
|
||||
u8 teb;
|
||||
} vnet_gre_add_del_tunnel_args_t;
|
||||
|
||||
+33
-11
@@ -55,17 +55,17 @@ static void vl_api_gre_add_del_tunnel_t_handler
|
||||
int rv = 0;
|
||||
vnet_gre_add_del_tunnel_args_t _a, *a = &_a;
|
||||
u32 outer_fib_id;
|
||||
uword *p;
|
||||
ip4_main_t *im = &ip4_main;
|
||||
u32 p;
|
||||
u32 sw_if_index = ~0;
|
||||
|
||||
p = hash_get (im->fib_index_by_table_id, ntohl (mp->outer_fib_id));
|
||||
if (!p)
|
||||
p = fib_table_find (!mp->is_ipv6 ? FIB_PROTOCOL_IP4 : FIB_PROTOCOL_IP6,
|
||||
ntohl (mp->outer_fib_id));
|
||||
if (p == ~0)
|
||||
{
|
||||
rv = VNET_API_ERROR_NO_SUCH_FIB;
|
||||
goto out;
|
||||
}
|
||||
outer_fib_id = p[0];
|
||||
outer_fib_id = p;
|
||||
|
||||
/* Check src & dst are different */
|
||||
if ((mp->is_ipv6 && memcmp (mp->src_address, mp->dst_address, 16) == 0) ||
|
||||
@@ -78,10 +78,19 @@ static void vl_api_gre_add_del_tunnel_t_handler
|
||||
|
||||
a->is_add = mp->is_add;
|
||||
a->teb = mp->teb;
|
||||
a->is_ipv6 = mp->is_ipv6;
|
||||
|
||||
/* ip addresses sent in network byte order */
|
||||
clib_memcpy (&(a->src), mp->src_address, 4);
|
||||
clib_memcpy (&(a->dst), mp->dst_address, 4);
|
||||
if (!mp->is_ipv6)
|
||||
{
|
||||
clib_memcpy (&(a->src.ip4), mp->src_address, 4);
|
||||
clib_memcpy (&(a->dst.ip4), mp->dst_address, 4);
|
||||
}
|
||||
else
|
||||
{
|
||||
clib_memcpy (&(a->src.ip6), mp->src_address, 16);
|
||||
clib_memcpy (&(a->dst.ip6), mp->dst_address, 16);
|
||||
}
|
||||
|
||||
a->outer_fib_id = outer_fib_id;
|
||||
rv = vnet_gre_add_del_tunnel (a, &sw_if_index);
|
||||
@@ -99,17 +108,30 @@ static void send_gre_tunnel_details
|
||||
(gre_tunnel_t * t, unix_shared_memory_queue_t * q, u32 context)
|
||||
{
|
||||
vl_api_gre_tunnel_details_t *rmp;
|
||||
ip4_main_t *im = &ip4_main;
|
||||
u8 is_ipv6 = t->tunnel_dst.fp_proto == FIB_PROTOCOL_IP6 ? 1 : 0;
|
||||
fib_table_t *ft;
|
||||
|
||||
rmp = vl_msg_api_alloc (sizeof (*rmp));
|
||||
memset (rmp, 0, sizeof (*rmp));
|
||||
rmp->_vl_msg_id = ntohs (VL_API_GRE_TUNNEL_DETAILS);
|
||||
clib_memcpy (rmp->src_address, &(t->tunnel_src), 4);
|
||||
clib_memcpy (rmp->dst_address, &(t->tunnel_dst), 4);
|
||||
rmp->outer_fib_id = htonl (im->fibs[t->outer_fib_index].ft_table_id);
|
||||
if (!is_ipv6)
|
||||
{
|
||||
clib_memcpy (rmp->src_address, &(t->tunnel_src.ip4.as_u8), 4);
|
||||
clib_memcpy (rmp->dst_address, &(t->tunnel_dst.fp_addr.ip4.as_u8), 4);
|
||||
ft = fib_table_get (t->outer_fib_index, FIB_PROTOCOL_IP4);
|
||||
rmp->outer_fib_id = ft->ft_table_id;
|
||||
}
|
||||
else
|
||||
{
|
||||
clib_memcpy (rmp->src_address, &(t->tunnel_src.ip6.as_u8), 16);
|
||||
clib_memcpy (rmp->dst_address, &(t->tunnel_dst.fp_addr.ip6.as_u8), 16);
|
||||
ft = fib_table_get (t->outer_fib_index, FIB_PROTOCOL_IP6);
|
||||
rmp->outer_fib_id = ft->ft_table_id;
|
||||
}
|
||||
rmp->teb = (GRE_TUNNEL_TYPE_TEB == t->type);
|
||||
rmp->sw_if_index = htonl (t->sw_if_index);
|
||||
rmp->context = context;
|
||||
rmp->is_ipv6 = is_ipv6;
|
||||
|
||||
vl_msg_api_send_shmem (q, (u8 *) & rmp);
|
||||
}
|
||||
|
||||
+139
-53
File diff suppressed because it is too large
Load Diff
+249
-65
File diff suppressed because it is too large
Load Diff
+12
-12
@@ -92,6 +92,8 @@ ipsec_gre_input (vlib_main_t * vm,
|
||||
u32 n_left_from, next_index, * from, * to_next;
|
||||
u64 cached_tunnel_key = (u64) ~0;
|
||||
u32 cached_tunnel_sw_if_index = 0, tunnel_sw_if_index;
|
||||
u32 tun_src0, tun_dst0;
|
||||
u32 tun_src1, tun_dst1;
|
||||
|
||||
from = vlib_frame_vector_args (from_frame);
|
||||
n_left_from = from_frame->n_vectors;
|
||||
@@ -146,10 +148,10 @@ ipsec_gre_input (vlib_main_t * vm,
|
||||
ip1 = vlib_buffer_get_current (b1);
|
||||
|
||||
/* Save src + dst ip4 address */
|
||||
vnet_buffer(b0)->gre.src = ip0->src_address.as_u32;
|
||||
vnet_buffer(b0)->gre.dst = ip0->dst_address.as_u32;
|
||||
vnet_buffer(b1)->gre.src = ip1->src_address.as_u32;
|
||||
vnet_buffer(b1)->gre.dst = ip1->dst_address.as_u32;
|
||||
tun_src0 = ip0->src_address.as_u32;
|
||||
tun_dst0 = ip0->dst_address.as_u32;
|
||||
tun_src1 = ip1->src_address.as_u32;
|
||||
tun_dst1 = ip1->dst_address.as_u32;
|
||||
|
||||
vlib_buffer_advance (b0, sizeof (*ip0));
|
||||
vlib_buffer_advance (b1, sizeof (*ip1));
|
||||
@@ -197,8 +199,7 @@ ipsec_gre_input (vlib_main_t * vm,
|
||||
/* For L2 payload set input sw_if_index to GRE tunnel for learning */
|
||||
if (PREDICT_TRUE(next0 == IPSEC_GRE_INPUT_NEXT_L2_INPUT))
|
||||
{
|
||||
u64 key = ((u64)(vnet_buffer(b0)->gre.dst) << 32) |
|
||||
(u64)(vnet_buffer(b0)->gre.src);
|
||||
u64 key = ((u64)(tun_dst0) << 32) | (u64)(tun_src0);
|
||||
|
||||
if (cached_tunnel_key != key)
|
||||
{
|
||||
@@ -230,8 +231,7 @@ drop0:
|
||||
/* For L2 payload set input sw_if_index to GRE tunnel for learning */
|
||||
if (PREDICT_TRUE(next1 == IPSEC_GRE_INPUT_NEXT_L2_INPUT))
|
||||
{
|
||||
u64 key = ((u64)(vnet_buffer(b1)->gre.dst) << 32) |
|
||||
(u64)(vnet_buffer(b1)->gre.src);
|
||||
u64 key = ((u64)(tun_dst1) << 32) | (u64)(tun_src1);
|
||||
|
||||
if (cached_tunnel_key != key)
|
||||
{
|
||||
@@ -297,6 +297,7 @@ drop1:
|
||||
u16 version0, protocol0;
|
||||
int verr0;
|
||||
u32 next0;
|
||||
u32 tun_src0, tun_dst0;
|
||||
|
||||
bi0 = from[0];
|
||||
to_next[0] = bi0;
|
||||
@@ -308,8 +309,8 @@ drop1:
|
||||
b0 = vlib_get_buffer (vm, bi0);
|
||||
ip0 = vlib_buffer_get_current (b0);
|
||||
|
||||
vnet_buffer(b0)->gre.src = ip0->src_address.as_u32;
|
||||
vnet_buffer(b0)->gre.dst = ip0->dst_address.as_u32;
|
||||
tun_src0 = ip0->src_address.as_u32;
|
||||
tun_dst0 = ip0->dst_address.as_u32;
|
||||
|
||||
vlib_buffer_advance (b0, sizeof (*ip0));
|
||||
|
||||
@@ -337,8 +338,7 @@ drop1:
|
||||
/* For L2 payload set input sw_if_index to GRE tunnel for learning */
|
||||
if (PREDICT_FALSE(next0 == IPSEC_GRE_INPUT_NEXT_L2_INPUT))
|
||||
{
|
||||
u64 key = ((u64)(vnet_buffer(b0)->gre.dst) << 32) |
|
||||
(u64)(vnet_buffer(b0)->gre.src);
|
||||
u64 key = ((u64)(tun_dst0) << 32) | (u64)(tun_src0);
|
||||
|
||||
if (cached_tunnel_key != key)
|
||||
{
|
||||
|
||||
+142
-7
@@ -5,7 +5,7 @@ from logging import *
|
||||
|
||||
from framework import VppTestCase, VppTestRunner
|
||||
from vpp_sub_interface import VppDot1QSubint
|
||||
from vpp_gre_interface import VppGreInterface
|
||||
from vpp_gre_interface import VppGreInterface, VppGre6Interface
|
||||
from vpp_ip_route import VppIpRoute, VppRoutePath
|
||||
from vpp_papi_provider import L2_VTR_OP
|
||||
|
||||
@@ -28,14 +28,19 @@ class TestGRE(VppTestCase):
|
||||
def setUp(self):
|
||||
super(TestGRE, self).setUp()
|
||||
|
||||
# create 2 pg interfaces - set one in a non-default table.
|
||||
self.create_pg_interfaces(range(2))
|
||||
|
||||
# create 3 pg interfaces - set one in a non-default table.
|
||||
self.create_pg_interfaces(range(3))
|
||||
self.pg1.set_table_ip4(1)
|
||||
|
||||
for i in self.pg_interfaces:
|
||||
i.admin_up()
|
||||
i.config_ip4()
|
||||
i.resolve_arp()
|
||||
|
||||
self.pg0.config_ip4()
|
||||
self.pg0.resolve_arp()
|
||||
self.pg1.config_ip4()
|
||||
self.pg1.resolve_arp()
|
||||
self.pg2.config_ip6()
|
||||
self.pg2.resolve_ndp()
|
||||
|
||||
def tearDown(self):
|
||||
super(TestGRE, self).tearDown()
|
||||
@@ -57,6 +62,19 @@ class TestGRE(VppTestCase):
|
||||
pkts.append(p)
|
||||
return pkts
|
||||
|
||||
def create_stream_ip6(self, src_if, src_ip, dst_ip):
|
||||
pkts = []
|
||||
for i in range(0, 257):
|
||||
info = self.create_packet_info(src_if, src_if)
|
||||
payload = self.info_to_payload(info)
|
||||
p = (Ether(dst=src_if.local_mac, src=src_if.remote_mac) /
|
||||
IPv6(src=src_ip, dst=dst_ip) /
|
||||
UDP(sport=1234, dport=1234) /
|
||||
Raw(payload))
|
||||
info.data = p.copy()
|
||||
pkts.append(p)
|
||||
return pkts
|
||||
|
||||
def create_tunnel_stream_4o4(self, src_if,
|
||||
tunnel_src, tunnel_dst,
|
||||
src_ip, dst_ip):
|
||||
@@ -91,6 +109,23 @@ class TestGRE(VppTestCase):
|
||||
pkts.append(p)
|
||||
return pkts
|
||||
|
||||
def create_tunnel_stream_6o6(self, src_if,
|
||||
tunnel_src, tunnel_dst,
|
||||
src_ip, dst_ip):
|
||||
pkts = []
|
||||
for i in range(0, 257):
|
||||
info = self.create_packet_info(src_if, src_if)
|
||||
payload = self.info_to_payload(info)
|
||||
p = (Ether(dst=src_if.local_mac, src=src_if.remote_mac) /
|
||||
IPv6(src=tunnel_src, dst=tunnel_dst) /
|
||||
GRE() /
|
||||
IPv6(src=src_ip, dst=dst_ip) /
|
||||
UDP(sport=1234, dport=1234) /
|
||||
Raw(payload))
|
||||
info.data = p.copy()
|
||||
pkts.append(p)
|
||||
return pkts
|
||||
|
||||
def create_tunnel_stream_l2o4(self, src_if,
|
||||
tunnel_src, tunnel_dst):
|
||||
pkts = []
|
||||
@@ -157,6 +192,33 @@ class TestGRE(VppTestCase):
|
||||
self.logger.error(ppp("Tx:", tx))
|
||||
raise
|
||||
|
||||
def verify_tunneled_6o6(self, src_if, capture, sent,
|
||||
tunnel_src, tunnel_dst):
|
||||
|
||||
self.assertEqual(len(capture), len(sent))
|
||||
|
||||
for i in range(len(capture)):
|
||||
try:
|
||||
tx = sent[i]
|
||||
rx = capture[i]
|
||||
|
||||
tx_ip = tx[IPv6]
|
||||
rx_ip = rx[IPv6]
|
||||
|
||||
self.assertEqual(rx_ip.src, tunnel_src)
|
||||
self.assertEqual(rx_ip.dst, tunnel_dst)
|
||||
|
||||
rx_gre = GRE(str(rx_ip[IPv6].payload))
|
||||
rx_ip = rx_gre[IPv6]
|
||||
|
||||
self.assertEqual(rx_ip.src, tx_ip.src)
|
||||
self.assertEqual(rx_ip.dst, tx_ip.dst)
|
||||
|
||||
except:
|
||||
self.logger.error(ppp("Rx:", rx))
|
||||
self.logger.error(ppp("Tx:", tx))
|
||||
raise
|
||||
|
||||
def verify_tunneled_l2o4(self, src_if, capture, sent,
|
||||
tunnel_src, tunnel_dst):
|
||||
self.assertEqual(len(capture), len(sent))
|
||||
@@ -275,7 +337,7 @@ class TestGRE(VppTestCase):
|
||||
raise
|
||||
|
||||
def test_gre(self):
|
||||
""" GRE tunnel Tests """
|
||||
""" GRE IPv4 tunnel Tests """
|
||||
|
||||
#
|
||||
# Create an L3 GRE tunnel.
|
||||
@@ -438,6 +500,79 @@ class TestGRE(VppTestCase):
|
||||
|
||||
self.pg0.unconfig_ip6()
|
||||
|
||||
def test_gre6(self):
|
||||
""" GRE IPv6 tunnel Tests """
|
||||
|
||||
#
|
||||
# Create an L3 GRE tunnel.
|
||||
# - set it admin up
|
||||
# - assign an IP Address
|
||||
# - Add a route via the tunnel
|
||||
#
|
||||
gre_if = VppGre6Interface(self,
|
||||
self.pg2.local_ip6,
|
||||
"1002::1")
|
||||
gre_if.add_vpp_config()
|
||||
gre_if.admin_up()
|
||||
gre_if.config_ip6()
|
||||
|
||||
route_via_tun = VppIpRoute(self, "4004::1", 128,
|
||||
[VppRoutePath("0::0",
|
||||
gre_if.sw_if_index,
|
||||
is_ip6=1)],
|
||||
is_ip6=1)
|
||||
|
||||
route_via_tun.add_vpp_config()
|
||||
|
||||
#
|
||||
# Send a packet stream that is routed into the tunnel
|
||||
# - they are all dropped since the tunnel's desintation IP
|
||||
# is unresolved - or resolves via the default route - which
|
||||
# which is a drop.
|
||||
#
|
||||
tx = self.create_stream_ip6(self.pg2, "5005::1", "4004::1")
|
||||
self.pg2.add_stream(tx)
|
||||
|
||||
self.pg_enable_capture(self.pg_interfaces)
|
||||
self.pg_start()
|
||||
|
||||
self.pg2.assert_nothing_captured(
|
||||
remark="GRE packets forwarded without DIP resolved")
|
||||
|
||||
#
|
||||
# Add a route that resolves the tunnel's destination
|
||||
#
|
||||
route_tun_dst = VppIpRoute(self, "1002::1", 128,
|
||||
[VppRoutePath(self.pg2.remote_ip6,
|
||||
self.pg2.sw_if_index,
|
||||
is_ip6=1)],
|
||||
is_ip6=1)
|
||||
route_tun_dst.add_vpp_config()
|
||||
|
||||
#
|
||||
# Send a packet stream that is routed into the tunnel
|
||||
# - packets are GRE encapped
|
||||
#
|
||||
self.vapi.cli("clear trace")
|
||||
tx = self.create_stream_ip6(self.pg2, "5005::1", "4004::1")
|
||||
self.pg2.add_stream(tx)
|
||||
|
||||
self.pg_enable_capture(self.pg_interfaces)
|
||||
self.pg_start()
|
||||
|
||||
rx = self.pg2.get_capture(len(tx))
|
||||
self.verify_tunneled_6o6(self.pg2, rx, tx,
|
||||
self.pg2.local_ip6, "1002::1")
|
||||
|
||||
#
|
||||
# test case cleanup
|
||||
#
|
||||
route_tun_dst.remove_vpp_config()
|
||||
route_via_tun.remove_vpp_config()
|
||||
gre_if.remove_vpp_config()
|
||||
|
||||
self.pg2.unconfig_ip6()
|
||||
|
||||
def test_gre_vrf(self):
|
||||
""" GRE tunnel VRF Tests """
|
||||
|
||||
|
||||
@@ -34,3 +34,38 @@ class VppGreInterface(VppInterface):
|
||||
r = self.test.vapi.gre_tunnel_add_del(s, d,
|
||||
outer_fib_id=self.t_outer_fib,
|
||||
is_add=0)
|
||||
|
||||
|
||||
class VppGre6Interface(VppInterface):
|
||||
"""
|
||||
VPP GRE IPv6 interface
|
||||
"""
|
||||
|
||||
def __init__(self, test, src_ip, dst_ip, outer_fib_id=0, is_teb=0):
|
||||
""" Create VPP loopback interface """
|
||||
self._sw_if_index = 0
|
||||
super(VppGre6Interface, self).__init__(test)
|
||||
self._test = test
|
||||
self.t_src = src_ip
|
||||
self.t_dst = dst_ip
|
||||
self.t_outer_fib = outer_fib_id
|
||||
self.t_is_teb = is_teb
|
||||
|
||||
def add_vpp_config(self):
|
||||
s = socket.inet_pton(socket.AF_INET6, self.t_src)
|
||||
d = socket.inet_pton(socket.AF_INET6, self.t_dst)
|
||||
r = self.test.vapi.gre_tunnel_add_del(s, d,
|
||||
outer_fib_id=self.t_outer_fib,
|
||||
is_teb=self.t_is_teb,
|
||||
is_ip6=1)
|
||||
self._sw_if_index = r.sw_if_index
|
||||
self.generate_remote_hosts()
|
||||
|
||||
def remove_vpp_config(self):
|
||||
s = socket.inet_pton(socket.AF_INET6, self.t_src)
|
||||
d = socket.inet_pton(socket.AF_INET6, self.t_dst)
|
||||
self.unconfig()
|
||||
r = self.test.vapi.gre_tunnel_add_del(s, d,
|
||||
outer_fib_id=self.t_outer_fib,
|
||||
is_add=0,
|
||||
is_ip6=1)
|
||||
|
||||
Reference in New Issue
Block a user