IPIP: Add IP{v4,v6} over IP{v4,v6} configured tunnel support.

Change-Id: I166301c9e2388bae5f70ec0179d663a2703e27f5
Signed-off-by: Ole Troan <ot@cisco.com>
This commit is contained in:
Ole Troan
2018-03-08 12:30:43 +01:00
committed by Neale Ranns
parent 1c5ddbb22b
commit 298c69510f
23 changed files with 2491 additions and 1142 deletions
+4 -5
View File
@@ -139,16 +139,15 @@ M: Andrew Yourtchenko <ayourtch@gmail.com>
F: src/plugins/acl/
F: src/plugins/acl.am
VNET IPIP
M: Ole Troan <otroan@employees.org>
F: src/vnet/ipip/
Plugin - flowprobe
M: Ole Troan <otroan@employees.org>
F: src/plugins/flowprobe/
F: src/plugins/flowprobe.am
Plugin - SIXRD
M: Ole Troan <ot@cisco.com>
F: src/plugins/sixrd/
F: src/plugins/sixrd.am
Plugin - GTPU
M: Hongjun Ni <hongjun.ni@intel.com>
F: src/plugins/gtpu/
-1
View File
@@ -226,7 +226,6 @@ PLUGIN_ENABLED(marvell)
PLUGIN_ENABLED(memif)
PLUGIN_ENABLED(pppoe)
PLUGIN_ENABLED(nat)
PLUGIN_ENABLED(sixrd)
PLUGIN_ENABLED(srv6ad)
PLUGIN_ENABLED(srv6am)
PLUGIN_ENABLED(srv6as)
-4
View File
@@ -83,10 +83,6 @@ if ENABLE_PPPOE_PLUGIN
include pppoe.am
endif
if ENABLE_SIXRD_PLUGIN
include sixrd.am
endif
if ENABLE_SRV6AD_PLUGIN
include srv6_ad.am
endif
-27
View File
@@ -1,27 +0,0 @@
# Copyright (c) 2015 Cisco and/or its affiliates.
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at:
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
libsixrd_plugin_la_SOURCES = \
sixrd/sixrd.c \
sixrd/ip4_sixrd.c
noinst_HEADERS += \
sixrd/sixrd.h \
sixrd/sixrd_all_api_h.h \
sixrd/sixrd_msg_enum.h
vppplugins_LTLIBRARIES += libsixrd_plugin.la
API_FILES += sixrd/sixrd.api
# vi:syntax=automake
-165
View File
@@ -1,165 +0,0 @@
/*---------------------------------------------------------------------------
* Copyright (c) 2009-2014 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*---------------------------------------------------------------------------
*/
#include "sixrd.h"
vlib_node_registration_t ip4_sixrd_node;
typedef enum {
IP4_SIXRD_NEXT_IP6_LOOKUP,
IP4_SIXRD_NEXT_DROP,
IP4_SIXRD_N_NEXT,
} ip4_sixrd_next_t;
typedef struct {
u32 tunnel_id;
u32 length;
ip4_address_t src;
ip4_address_t dst;
} sixrd_rx_trace_t;
u8 *
format_sixrd_rx_trace (u8 * s, va_list * args)
{
CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
sixrd_rx_trace_t *t = va_arg (*args, sixrd_rx_trace_t *);
s = format (s, "6RD: tunnel %d len %d src %U dst %U",
t->tunnel_id, clib_net_to_host_u16 (t->length),
format_ip4_address, &t->src, format_ip4_address, &t->dst);
return s;
}
/*
* ip4_sixrd_sec_check
*/
static_always_inline void
ip4_sixrd_sec_check(sixrd_tunnel_t *t, ip4_address_t sa4,
ip6_address_t sa6, u8 *error) {
if (PREDICT_FALSE(sixrd_get_addr_net(t, sa6.as_u64[0]) != sa4.as_u32))
*error = SIXRD_ERROR_SEC_CHECK;
}
/*
* ip4_sixrd
*/
uword ip4_sixrd(vlib_main_t *vm, vlib_node_runtime_t *node,
vlib_frame_t *frame) {
u32 n_left_from, *from, next_index, *to_next, n_left_to_next;
vlib_node_runtime_t *error_node = vlib_node_get_runtime(vm, ip4_sixrd_node.index);
vnet_interface_main_t * im = &vnet_get_main()->interface_main;
u32 thread_index = vlib_get_thread_index ();
from = vlib_frame_vector_args(frame);
n_left_from = frame->n_vectors;
next_index = node->cached_next_index;
while (n_left_from > 0) {
vlib_get_next_frame(vm, node, next_index, to_next, n_left_to_next);
/* Single loop */
while (n_left_from > 0 && n_left_to_next > 0) {
u32 pi0;
vlib_buffer_t *p0;
u8 error0 = SIXRD_ERROR_NONE;
sixrd_tunnel_t *t0 = 0;
ip4_header_t *ip40;
ip6_header_t *ip60;
u32 tunnel_sw_if_index = ~0;
u32 next0 = IP4_SIXRD_NEXT_DROP;
pi0 = to_next[0] = from[0];
from += 1;
n_left_from -= 1;
to_next += 1;
n_left_to_next -= 1;
p0 = vlib_get_buffer(vm, pi0);
ip40 = vlib_buffer_get_current(p0);
/* Throw away anything that isn't IP in IP. */
if (PREDICT_TRUE(ip40->protocol == IP_PROTOCOL_IPV6 && clib_net_to_host_u16(ip40->length) >= 60)) {
vlib_buffer_advance(p0, sizeof(ip4_header_t));
t0 = ip4_sixrd_get_tunnel(vnet_buffer(p0)->ip.adj_index[VLIB_TX], (ip4_address_t *)&ip40->dst_address, &error0);
} else {
error0 = SIXRD_ERROR_BAD_PROTOCOL;
}
if (!t0) {
error0 = SIXRD_ERROR_NO_TUNNEL;
goto error;
}
tunnel_sw_if_index = t0->sw_if_index;
/* SIXRD inbound security check */
if (t0->security_check) {
ip60 = vlib_buffer_get_current(p0);
ip4_sixrd_sec_check(t0, ip40->src_address, ip60->src_address, &error0);
}
next0 = error0 == SIXRD_ERROR_NONE ? IP4_SIXRD_NEXT_IP6_LOOKUP
: IP4_SIXRD_NEXT_DROP;
if (PREDICT_FALSE(p0->flags & VLIB_BUFFER_IS_TRACED)) {
sixrd_rx_trace_t *tr = vlib_add_trace(vm, node, p0, sizeof(*tr));
tr->tunnel_id = tunnel_sw_if_index;
tr->length = ip40->length;
tr->src.as_u32 = ip40->src_address.as_u32;
tr->dst.as_u32 = ip40->dst_address.as_u32;
}
error:
if (PREDICT_TRUE(error0 == SIXRD_ERROR_NONE)) {
u32 len = vlib_buffer_length_in_chain (vm, p0);
vlib_increment_combined_counter (im->combined_sw_if_counters
+ VNET_INTERFACE_COUNTER_RX,
thread_index,
tunnel_sw_if_index,
1 /* packets */ ,
len /* bytes */ );
vnet_buffer (p0)->sw_if_index[VLIB_RX] = tunnel_sw_if_index;
} else {
p0->error = error_node->errors[error0];
}
vlib_validate_buffer_enqueue_x1(vm, node, next_index, to_next,
n_left_to_next, pi0, next0);
}
vlib_put_next_frame(vm, node, next_index, n_left_to_next);
}
return frame->n_vectors;
}
static char *sixrd_error_strings[] = {
#define _(sym, string) string,
foreach_sixrd_error
#undef _
};
VLIB_REGISTER_NODE(ip4_sixrd_node) = {
.function = ip4_sixrd,
.name = "ip4-sixrd",
.vector_size = sizeof(u32),
.format_trace = format_sixrd_rx_trace,
.n_errors = SIXRD_N_ERROR,
.error_strings = sixrd_error_strings,
.n_next_nodes = IP4_SIXRD_N_NEXT,
.next_nodes =
{
[IP4_SIXRD_NEXT_IP6_LOOKUP] = "ip6-lookup",
[IP4_SIXRD_NEXT_DROP] = "error-drop",
},
};
-44
View File
@@ -1,44 +0,0 @@
/*
* Copyright (c) 2018 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
option version = "2.0.0";
define sixrd_add_tunnel
{
u32 client_index;
u32 context;
u32 fib_index;
u8 ip6_prefix[16];
u8 ip4_prefix[4];
u8 ip4_src[4];
u8 ip6_prefix_len;
u8 ip4_prefix_len;
u16 mtu;
u8 security_check;
};
define sixrd_add_tunnel_reply
{
u32 context;
u32 sw_if_index;
i32 retval;
};
autoreply define sixrd_del_tunnel
{
u32 client_index;
u32 context;
u32 sw_if_index;
};
File diff suppressed because it is too large Load Diff
-16
View File
@@ -1,16 +0,0 @@
/*
* Copyright (c) 2016 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/* Include the generated file, see BUILT_SOURCES in Makefile.am */
#include <sixrd/sixrd.api.h>
-28
View File
@@ -1,28 +0,0 @@
/*
* Copyright (c) 2016 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef included_sixrd_msg_enum_h
#define included_sixrd_msg_enum_h
#include <vppinfra/byte_order.h>
#define vl_msg_id(n,h) n,
typedef enum {
#include <sixrd/sixrd_all_api_h.h>
/* We'll want to know how many messages IDs we need... */
VL_MSG_FIRST_AVAILABLE,
} vl_msg_id_t;
#undef vl_msg_id
#endif
+15
View File
@@ -567,6 +567,21 @@ nobase_include_HEADERS += \
API_FILES += vnet/gre/gre.api
########################################
# Tunnel protocol: ipip
########################################
libvnet_la_SOURCES += \
vnet/ipip/ipip.c \
vnet/ipip/node.c \
vnet/ipip/sixrd.c \
vnet/ipip/ipip_api.c \
vnet/ipip/ipip_cli.c
nobase_include_HEADERS += \
vnet/ipip/ipip.h
API_FILES += vnet/ipip/ipip.api
########################################
# Tunnel protocol: l2tpv3
########################################
+1
View File
@@ -81,6 +81,7 @@ typedef CLIB_PACKED (union {
#define ip46_address_is_zero(ip46) (((ip46)->as_u64[0] == 0) && ((ip46)->as_u64[1] == 0))
#define ip46_address_is_equal(a1, a2) (((a1)->as_u64[0] == (a2)->as_u64[0]) \
&& ((a1)->as_u64[1] == (a2)->as_u64[1]))
#define ip46_address_initializer {{{ 0 }}}
always_inline ip46_address_t
to_ip46 (u32 is_ipv6, u8 * buf)
+101
View File
@@ -0,0 +1,101 @@
/*
* Copyright (c) 2018 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
option version = "1.0.0";
/** \brief Create or delete an IPIP tunnel
@param client_index - opaque cookie to identify the sender
@param context - sender context, to match reply w/ request
@param is_ipv6 - Use 0 for IPv4, 1 for IPv6
@param instance - optional unique custom device instance, else ~0.
@param src_address - Source IP address
@param dst_address - Destination IP address, can be multicast
@param fib_index - Encap FIB table ID
*/
define ipip_add_tunnel
{
u32 client_index;
u32 context;
u8 is_ipv6;
u32 instance; /* If non-~0, specifies a custom dev instance */
u8 src_address[16];
u8 dst_address[16];
u32 fib_index;
};
define ipip_add_tunnel_reply
{
u32 context;
i32 retval;
u32 sw_if_index;
};
autoreply define ipip_del_tunnel
{
u32 client_index;
u32 context;
u32 sw_if_index;
};
define ipip_6rd_add_tunnel
{
u32 client_index;
u32 context;
u32 fib_index;
u8 ip6_prefix[16];
u8 ip4_prefix[4];
u8 ip4_src[4];
u8 ip6_prefix_len;
u8 ip4_prefix_len;
u8 security_check;
};
define ipip_6rd_add_tunnel_reply
{
u32 context;
i32 retval;
u32 sw_if_index;
};
autoreply define ipip_6rd_del_tunnel
{
u32 client_index;
u32 context;
u32 sw_if_index;
};
define ipip_tunnel_dump
{
u32 client_index;
u32 context;
u32 sw_if_index;
};
define ipip_tunnel_details
{
u32 context;
u32 sw_if_index;
u32 instance;
u8 is_ipv6;
u8 src_address[16];
u8 dst_address[16];
u32 fib_index;
};
/*
* Local Variables:
* eval: (c-set-style "gnu")
* End:
*/
File diff suppressed because it is too large Load Diff
+168
View File
@@ -0,0 +1,168 @@
/*
* ipip.h: types/functions for ipip.
*
* Copyright (c) 2018 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or aipiped to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef included_ipip_h
#define included_ipip_h
#include <vnet/adj/adj_types.h>
#include <vnet/ip/ip6_packet.h>
#include <vnet/ip/format.h>
#include <vnet/ip/ip.h>
#include <vnet/vnet.h>
extern vnet_hw_interface_class_t ipip_hw_interface_class;
#define foreach_ipip_error \
/* Must be first. */ \
_(DECAP_PKTS, "packets decapsulated") \
_(BAD_PROTOCOL, "bad protocol") \
_(NO_TUNNEL, "no tunnel")
typedef enum
{
#define _(sym, str) IPIP_ERROR_##sym,
foreach_ipip_error
#undef _
IPIP_N_ERROR,
} ipip_error_t;
/**
* @brief IPIP Tunnel key
*/
typedef enum
{
IPIP_TRANSPORT_IP4,
IPIP_TRANSPORT_IP6,
} ipip_transport_t;
typedef struct
{
ipip_transport_t transport;
u32 fib_index;
ip46_address_t src;
ip46_address_t dst;
} __attribute__ ((packed)) ipip_tunnel_key_t;
typedef enum
{
IPIP_MODE_P2P = 0,
IPIP_MODE_6RD,
} ipip_mode_t;
/**
* @brief A representation of a IPIP tunnel
*/
typedef struct
{
ipip_mode_t mode;
ipip_transport_t transport;
ipip_tunnel_key_t *key;
ip46_address_t tunnel_src;
ip46_address_t tunnel_dst;
u32 fib_index;
u32 hw_if_index;
u32 sw_if_index;
u32 dev_instance; /* Real device instance in tunnel vector */
u32 user_instance; /* Instance name being shown to user */
union
{
struct
{
fib_node_t node;
fib_node_index_t fib_entry_index;
u32 sibling_index;
} p2p;
struct
{
ip6_address_t ip6_prefix;
ip4_address_t ip4_prefix;
u8 ip6_prefix_len;
u8 ip4_prefix_len;
u8 shift;
bool security_check;
} sixrd;
};
} ipip_tunnel_t;
typedef struct
{
ipip_tunnel_t *tunnels;
uword *tunnel_by_key;
u32 *tunnel_index_by_sw_if_index;
fib_node_type_t fib_node_type;
/* convenience */
vlib_main_t *vlib_main;
vnet_main_t *vnet_main;
/* Record used instances */
uword *instance_used;
bool ip4_protocol_registered;
bool ip6_protocol_registered;
} ipip_main_t;
extern ipip_main_t ipip_main;
extern vlib_node_registration_t ipip4_input_node;
extern vlib_node_registration_t ipip6_input_node;
/*
* sixrd_get_addr_net
*/
static_always_inline u32
sixrd_get_addr_net (const ipip_tunnel_t * t, u64 dal)
{
/* 1:1 mode */
if (t->sixrd.ip4_prefix_len == 32)
return (t->sixrd.ip4_prefix.as_u32);
dal = clib_net_to_host_u64 (dal);
/* Grab 32 - ip4_prefix_len bits out of IPv6 address from offset
* ip6_prefix_len */
u32 mask = ~(~0ULL << (32 - t->sixrd.ip4_prefix_len));
u32 ip4 =
clib_net_to_host_u32 (t->sixrd.
ip4_prefix.as_u32) | ((u32) (dal >> t->sixrd.
shift) & mask);
return clib_host_to_net_u32 (ip4);
}
int ipip_add_tunnel (ipip_transport_t transport, u32 instance,
ip46_address_t * src, ip46_address_t * dst,
u32 fib_index, u32 * sw_if_indexp);
int ipip_del_tunnel (u32 sw_if_index);
int sixrd_add_tunnel (ip6_address_t * ip6_prefix, u8 ip6_prefix_len,
ip4_address_t * ip4_prefix, u8 ip4_prefix_len,
ip4_address_t * ip4_src, bool security_check,
u32 fib_index, u32 * sw_if_index);
int sixrd_del_tunnel (u32 sw_if_index);
void ipip_tunnel_db_add (ipip_tunnel_t * t, ipip_tunnel_key_t * key);
void ipip_tunnel_db_remove (ipip_tunnel_t * t);
ipip_tunnel_t *ipip_tunnel_db_find (ipip_tunnel_key_t * key);
ipip_tunnel_t *ipip_tunnel_db_find_by_sw_if_index (u32 sw_if_index);
#endif
/*
* fd.io coding-style-patch-verification: ON
*
* Local Variables:
* eval: (c-set-style "gnu")
* End:
*/
+230
View File
@@ -0,0 +1,230 @@
/*
* ipip_api.c - ipip api
*
* Copyright (c) 2018 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <vlibmemory/api.h>
#include <vnet/api_errno.h>
#include <vnet/fib/fib_table.h>
#include <vnet/interface.h>
#include <vnet/ipip/ipip.h>
#include <vnet/vnet.h>
#include <vnet/vnet_msg_enum.h>
#define vl_typedefs /* define message structures */
#include <vnet/vnet_all_api_h.h>
#undef vl_typedefs
#define vl_endianfun /* define message structures */
#include <vnet/vnet_all_api_h.h>
#undef vl_endianfun
/* instantiate all the print functions we know about */
#define vl_print(handle, ...) vlib_cli_output(handle, __VA_ARGS__)
#define vl_printfun
#include <vnet/vnet_all_api_h.h>
#undef vl_printfun
#include <vlibapi/api_helper_macros.h>
#define foreach_vpe_api_msg \
_(IPIP_ADD_TUNNEL, ipip_add_tunnel) \
_(IPIP_DEL_TUNNEL, ipip_del_tunnel) \
_(IPIP_6RD_ADD_TUNNEL, ipip_6rd_add_tunnel) \
_(IPIP_6RD_DEL_TUNNEL, ipip_6rd_del_tunnel) \
_(IPIP_TUNNEL_DUMP, ipip_tunnel_dump)
static void
vl_api_ipip_add_tunnel_t_handler (vl_api_ipip_add_tunnel_t * mp)
{
vl_api_ipip_add_tunnel_reply_t *rmp;
int rv = 0;
u32 sw_if_index = ~0;
ip46_address_t src = ip46_address_initializer, dst =
ip46_address_initializer;
/* ip addresses sent in network byte order */
if (mp->is_ipv6)
{
clib_memcpy (&src.ip6, mp->src_address, 16);
clib_memcpy (&dst.ip6, mp->dst_address, 16);
}
else
{
clib_memcpy (&src.ip4, mp->src_address, 4);
clib_memcpy (&dst.ip4, mp->dst_address, 4);
}
rv = ipip_add_tunnel (mp->is_ipv6 ? IPIP_TRANSPORT_IP6 : IPIP_TRANSPORT_IP4,
ntohl (mp->instance), &src, &dst,
ntohl (mp->fib_index), &sw_if_index);
/* *INDENT-OFF* */
REPLY_MACRO2(VL_API_IPIP_ADD_TUNNEL_REPLY,
({ rmp->sw_if_index = ntohl(sw_if_index); }));
/* *INDENT-ON* */
}
static void
vl_api_ipip_del_tunnel_t_handler (vl_api_ipip_del_tunnel_t * mp)
{
vl_api_ipip_del_tunnel_reply_t *rmp;
int rv = ipip_del_tunnel (ntohl (mp->sw_if_index));
REPLY_MACRO (VL_API_IPIP_DEL_TUNNEL_REPLY);
}
static void
send_ipip_tunnel_details (ipip_tunnel_t * t,
vl_api_registration_t * reg, u32 context)
{
vl_api_ipip_tunnel_details_t *rmp;
bool is_ipv6 = t->transport == IPIP_TRANSPORT_IP6 ? true : false;
fib_table_t *ft;
rmp = vl_msg_api_alloc (sizeof (*rmp));
memset (rmp, 0, sizeof (*rmp));
rmp->_vl_msg_id = htons (VL_API_IPIP_TUNNEL_DETAILS);
if (is_ipv6)
{
clib_memcpy (rmp->src_address, &t->tunnel_src.ip6.as_u8, 16);
clib_memcpy (rmp->dst_address, &t->tunnel_dst.ip6.as_u8, 16);
ft = fib_table_get (t->fib_index, FIB_PROTOCOL_IP6);
rmp->fib_index = htonl (ft->ft_table_id);
}
else
{
clib_memcpy (rmp->src_address, &t->tunnel_src.ip4.as_u8, 4);
clib_memcpy (rmp->dst_address, &t->tunnel_dst.ip4.as_u8, 4);
ft = fib_table_get (t->fib_index, FIB_PROTOCOL_IP4);
rmp->fib_index = htonl (ft->ft_table_id);
}
rmp->instance = htonl (t->user_instance);
rmp->sw_if_index = htonl (t->sw_if_index);
rmp->context = context;
rmp->is_ipv6 = is_ipv6;
vl_api_send_msg (reg, (u8 *) rmp);
}
static void
vl_api_ipip_tunnel_dump_t_handler (vl_api_ipip_tunnel_dump_t * mp)
{
vl_api_registration_t *reg;
ipip_main_t *gm = &ipip_main;
ipip_tunnel_t *t;
u32 sw_if_index;
reg = vl_api_client_index_to_registration (mp->client_index);
if (!reg)
return;
sw_if_index = ntohl (mp->sw_if_index);
if (sw_if_index == ~0)
{
/* *INDENT-OFF* */
pool_foreach(t, gm->tunnels,
({ send_ipip_tunnel_details(t, reg, mp->context); }));
/* *INDENT-ON* */
}
else
{
t = ipip_tunnel_db_find_by_sw_if_index (sw_if_index);
if (t)
send_ipip_tunnel_details (t, reg, mp->context);
}
}
static void
vl_api_ipip_6rd_add_tunnel_t_handler (vl_api_ipip_6rd_add_tunnel_t * mp)
{
vl_api_ipip_6rd_add_tunnel_reply_t *rmp;
u32 sixrd_tunnel_index;
int rv = sixrd_add_tunnel ((ip6_address_t *) & mp->ip6_prefix,
mp->ip6_prefix_len,
(ip4_address_t *) & mp->ip4_prefix,
mp->ip4_prefix_len,
(ip4_address_t *) & mp->ip4_src,
mp->security_check,
ntohl (mp->fib_index), &sixrd_tunnel_index);
REPLY_MACRO2 (VL_API_IPIP_6RD_ADD_TUNNEL_REPLY, (
{
rmp->sw_if_index =
htonl
(sixrd_tunnel_index);}));
}
static void
vl_api_ipip_6rd_del_tunnel_t_handler (vl_api_ipip_6rd_del_tunnel_t * mp)
{
vl_api_ipip_6rd_del_tunnel_reply_t *rmp;
int rv = sixrd_del_tunnel (ntohl (mp->sw_if_index));
REPLY_MACRO (VL_API_IPIP_6RD_DEL_TUNNEL_REPLY);
}
/*
* ipip_api_hookup
* Add vpe's API message handlers to the table.
* vlib has alread mapped shared memory and
* added the client registration handlers.
* See .../vlib-api/vlibmemory/memclnt_vlib.c:memclnt_process()
*/
#define vl_msg_name_crc_list
#include <vnet/vnet_all_api_h.h>
#undef vl_msg_name_crc_list
static void
setup_message_id_table (api_main_t * am)
{
#define _(id, n, crc) vl_msg_api_add_msg_name_crc(am, #n "_" #crc, id);
foreach_vl_msg_name_crc_ipip;
#undef _
}
static clib_error_t *
ipip_api_hookup (vlib_main_t * vm)
{
api_main_t *am = &api_main;
#define _(N, n) \
vl_msg_api_set_handlers(VL_API_##N, #n, vl_api_##n##_t_handler, \
vl_noop_handler, vl_api_##n##_t_endian, \
vl_api_##n##_t_print, sizeof(vl_api_##n##_t), 1);
foreach_vpe_api_msg;
#undef _
/*
* Set up the (msg_name, crc, message-id) table
*/
setup_message_id_table (am);
return 0;
}
VLIB_API_INIT_FUNCTION (ipip_api_hookup);
/*
* fd.io coding-style-patch-verification: ON
*
* Local Variables:
* eval: (c-set-style "gnu")
* End:
*/
File diff suppressed because it is too large Load Diff
+268
View File
@@ -0,0 +1,268 @@
/*
* node.c: ipip packet processing
*
* Copyright (c) 2018 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or aipiped to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <vlib/vlib.h>
#include <vnet/ipip/ipip.h>
#include <vnet/ip/ip6_packet.h>
#include <vnet/mpls/mpls.h>
#include <vnet/pg/pg.h>
#include <vppinfra/sparse_vec.h>
#define foreach_ipip_input_next \
_(PUNT, "error-punt") \
_(DROP, "error-drop") \
_(IP4_INPUT, "ip4-input") \
_(IP6_INPUT, "ip6-input")
typedef enum
{
#define _(s, n) IPIP_INPUT_NEXT_##s,
foreach_ipip_input_next
#undef _
IPIP_INPUT_N_NEXT,
} ipip_input_next_t;
typedef struct
{
u32 tunnel_id;
u32 length;
ip46_address_t src;
ip46_address_t dst;
u8 is_ipv6;
} ipip_rx_trace_t;
u8 *
format_ipip_rx_trace (u8 * s, va_list * args)
{
CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
ipip_rx_trace_t *t = va_arg (*args, ipip_rx_trace_t *);
s = format (s, "IPIP: tunnel %d len %d src %U dst %U", t->tunnel_id,
clib_net_to_host_u16 (t->length), format_ip46_address, &t->src,
IP46_TYPE_ANY, format_ip46_address, &t->dst, IP46_TYPE_ANY);
return s;
}
always_inline uword
ipip_input (vlib_main_t * vm, vlib_node_runtime_t * node,
vlib_frame_t * from_frame, bool is_ipv6)
{
ipip_main_t *gm = &ipip_main;
u32 n_left_from, next_index, *from, *to_next, n_left_to_next;
u32 tunnel_sw_if_index = ~0;
u32 thread_index = vlib_get_thread_index ();
u32 len;
vnet_interface_main_t *im = &gm->vnet_main->interface_main;
from = vlib_frame_vector_args (from_frame);
n_left_from = from_frame->n_vectors;
next_index = node->cached_next_index;
while (n_left_from > 0)
{
vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
while (n_left_from > 0 && n_left_to_next > 0)
{
u32 bi0;
vlib_buffer_t *b0;
ip4_header_t *ip40;
ip6_header_t *ip60;
u32 next0 = IPIP_INPUT_NEXT_DROP;
ip46_address_t src0 = ip46_address_initializer, dst0 =
ip46_address_initializer;
ipip_transport_t transport0;
u8 inner_protocol0;
bi0 = to_next[0] = from[0];
from += 1;
n_left_from -= 1;
to_next += 1;
n_left_to_next -= 1;
b0 = vlib_get_buffer (vm, bi0);
if (is_ipv6)
{
ip60 = vlib_buffer_get_current (b0);
vlib_buffer_advance (b0, sizeof (*ip60));
ip_set (&src0, &ip60->src_address, false);
ip_set (&dst0, &ip60->dst_address, false);
inner_protocol0 = ip60->protocol;
transport0 = IPIP_TRANSPORT_IP6;
}
else
{
ip40 = vlib_buffer_get_current (b0);
vlib_buffer_advance (b0, sizeof (*ip40));
ip_set (&src0, &ip40->src_address, true);
ip_set (&dst0, &ip40->dst_address, true);
inner_protocol0 = ip40->protocol;
transport0 = IPIP_TRANSPORT_IP4;
}
/*
* Find tunnel. First a lookup for P2P tunnels, then a lookup
* for multipoint tunnels
*/
ipip_tunnel_key_t key0 = {.transport = transport0,
.fib_index = vnet_buffer (b0)->ip.fib_index,
.src = dst0,
.dst = src0
};
ipip_tunnel_t *t0 = ipip_tunnel_db_find (&key0);
if (!t0)
{
ip46_address_reset (&key0.dst);
t0 = ipip_tunnel_db_find (&key0);
if (!t0)
{
next0 = IPIP_INPUT_NEXT_DROP;
b0->error = node->errors[IPIP_ERROR_NO_TUNNEL];
goto drop;
}
}
tunnel_sw_if_index = t0->sw_if_index;
len = vlib_buffer_length_in_chain (vm, b0);
vnet_buffer (b0)->sw_if_index[VLIB_RX] = tunnel_sw_if_index;
if (inner_protocol0 == IP_PROTOCOL_IPV6)
next0 = IPIP_INPUT_NEXT_IP6_INPUT;
else if (inner_protocol0 == IP_PROTOCOL_IP_IN_IP)
next0 = IPIP_INPUT_NEXT_IP4_INPUT;
if (!is_ipv6 && t0->mode == IPIP_MODE_6RD
&& t0->sixrd.security_check)
{
ip6_header_t *inner_ip60 = vlib_buffer_get_current (b0);
if (sixrd_get_addr_net (t0, inner_ip60->src_address.as_u64[0])
!= ip40->src_address.as_u32)
{
next0 = IPIP_INPUT_NEXT_DROP;
b0->error = node->errors[IPIP_ERROR_NO_TUNNEL];
goto drop;
}
}
vlib_increment_combined_counter (im->combined_sw_if_counters +
VNET_INTERFACE_COUNTER_RX,
thread_index, tunnel_sw_if_index,
1 /* packets */ ,
len /* bytes */ );
drop:
if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
{
ipip_rx_trace_t *tr =
vlib_add_trace (vm, node, b0, sizeof (*tr));
tr->tunnel_id = tunnel_sw_if_index;
if (is_ipv6)
{
tr->length = ip60->payload_length;
tr->src.ip6.as_u64[0] = ip60->src_address.as_u64[0];
tr->src.ip6.as_u64[1] = ip60->src_address.as_u64[1];
tr->dst.ip6.as_u64[0] = ip60->dst_address.as_u64[0];
tr->dst.ip6.as_u64[1] = ip60->dst_address.as_u64[1];
}
else
{
tr->length = ip40->length;
tr->src.ip4.as_u32 = ip40->src_address.as_u32;
tr->dst.ip4.as_u32 = ip40->dst_address.as_u32;
}
}
vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
n_left_to_next, bi0, next0);
}
vlib_put_next_frame (vm, node, next_index, n_left_to_next);
}
vlib_node_increment_counter (vm,
!is_ipv6 ? ipip4_input_node.index :
ipip6_input_node.index, IPIP_ERROR_DECAP_PKTS,
from_frame->n_vectors);
return from_frame->n_vectors;
}
static uword
ipip4_input (vlib_main_t * vm, vlib_node_runtime_t * node,
vlib_frame_t * from_frame)
{
return ipip_input (vm, node, from_frame, /* is_ip6 */ false);
}
static uword
ipip6_input (vlib_main_t * vm, vlib_node_runtime_t * node,
vlib_frame_t * from_frame)
{
return ipip_input (vm, node, from_frame, /* is_ip6 */ true);
}
static char *ipip_error_strings[] = {
#define _(sym,string) string,
foreach_ipip_error
#undef _
};
/* *INDENT-OFF* */
VLIB_REGISTER_NODE(ipip4_input_node) = {
.function = ipip4_input,
.name = "ipip4-input",
/* Takes a vector of packets. */
.vector_size = sizeof(u32),
.n_errors = IPIP_N_ERROR,
.error_strings = ipip_error_strings,
.n_next_nodes = IPIP_INPUT_N_NEXT,
.next_nodes =
{
#define _(s, n) [IPIP_INPUT_NEXT_##s] = n,
foreach_ipip_input_next
#undef _
},
.format_trace = format_ipip_rx_trace,
};
VLIB_REGISTER_NODE(ipip6_input_node) = {
.function = ipip6_input,
.name = "ipip6-input",
/* Takes a vector of packets. */
.vector_size = sizeof(u32),
.n_errors = IPIP_N_ERROR,
.error_strings = ipip_error_strings,
.n_next_nodes = IPIP_INPUT_N_NEXT,
.next_nodes =
{
#define _(s, n) [IPIP_INPUT_NEXT_##s] = n,
foreach_ipip_input_next
#undef _
},
.format_trace = format_ipip_rx_trace,
};
VLIB_NODE_FUNCTION_MULTIARCH(ipip4_input_node, ipip4_input)
VLIB_NODE_FUNCTION_MULTIARCH(ipip6_input_node, ipip6_input)
/* *INDENT-ON* */
/*
* fd.io coding-style-patch-verification: ON
*
* Local Variables:
* eval: (c-set-style "gnu")
* End:
*/
File diff suppressed because it is too large Load Diff
@@ -16,41 +16,12 @@
#include <stdbool.h>
#include <vnet/fib/ip6_fib.h>
#include <vnet/ip/ip.h>
#include <vnet/ipip/ipip.h>
#include <vnet/vnet.h>
#include <vppinfra/error.h>
#define SIXRD_DEFAULT_MTU 1480 /* 1500 - IPv4 header */
typedef struct
{
u32 fib_index;
u32 hw_if_index;
u32 sw_if_index;
u32 tunnel_index;
ip6_address_t ip6_prefix;
ip4_address_t ip4_prefix;
ip4_address_t ip4_src;
u8 ip6_prefix_len;
u8 ip4_prefix_len;
/* helpers */
u8 shift;
u16 mtu;
bool security_check;
} sixrd_tunnel_t;
typedef struct
{
u16 msg_id_base;
/* pool of SIXRD domains */
sixrd_tunnel_t *tunnels;
u32 *tunnel_index_by_sw_if_index;
uword *tunnel_by_ip;
} sixrd_main_t;
#define foreach_sixrd_error \
/* Must be first. */ \
_(NONE, "valid SIXRD packets") \
@@ -69,28 +40,6 @@ typedef enum
extern sixrd_main_t sixrd_main;
/*
* sixrd_get_addr
*/
static_always_inline u32
sixrd_get_addr_net (const sixrd_tunnel_t * t, u64 dal)
{
/* 1:1 mode */
if (t->ip4_prefix_len == 32)
return (t->ip4_prefix.as_u32);
dal = clib_net_to_host_u64 (dal);
/* Grab 32 - ip4_prefix_len bits out of IPv6 address from offset
* ip6_prefix_len */
u32 mask = ~(~0ULL << (32 - t->ip4_prefix_len));
u32 ip4 =
clib_net_to_host_u32 (t->
ip4_prefix.as_u32) | ((u32) (dal >> t->
shift) & mask);
return clib_host_to_net_u32 (ip4);
}
static_always_inline sixrd_tunnel_t *
find_tunnel_by_ip4_address (ip4_address_t * ip)
{
+1
View File
@@ -34,6 +34,7 @@
#include <vnet/devices/virtio/vhost_user.api.h>
#include <vnet/devices/tap/tapv2.api.h>
#include <vnet/gre/gre.api.h>
#include <vnet/ipip/ipip.api.h>
#include <vnet/interface.api.h>
#include <vnet/map/map.api.h>
#include <vnet/l2/l2.api.h>
+248
View File
@@ -0,0 +1,248 @@
#
# IP{4,6} over IP{v,6} tunnel functional tests
#
import unittest
from scapy.layers.inet import IP, UDP, ICMP
from scapy.layers.inet6 import IPv6
from scapy.layers.l2 import Ether, GRE
from scapy.packet import Raw
from framework import VppTestCase
from vpp_ip_route import VppIpRoute, VppRoutePath, DpoProto
from util import ppp
from ipaddress import *
""" Testipip is a subclass of VPPTestCase classes.
IPIP tests.
"""
class TestIPIP(VppTestCase):
""" IPIP Test Case """
@classmethod
def setUpClass(cls):
super(TestIPIP, cls).setUpClass()
try:
cls.create_pg_interfaces(range(2))
cls.interfaces = list(cls.pg_interfaces)
except Exception:
super(TestIPIP, cls).tearDownClass()
raise
def setUp(cls):
super(TestIPIP, cls).setUp()
try:
for i in cls.interfaces:
i.admin_up()
i.config_ip4()
i.config_ip6()
i.disable_ipv6_ra()
i.resolve_arp()
i.resolve_ndp()
except Exception:
super(TestIPIP, cls).tearDown()
raise
def tearDown(self):
super(TestIPIP, self).tearDown()
if not self.vpp_dead:
self.vapi.cli("show hardware")
for i in self.pg_interfaces:
i.unconfig_ip4()
i.unconfig_ip6()
i.admin_down()
self.vapi.cli("show error")
def validate(self, rx, expected):
expected = expected.__class__(str(expected))
if rx != expected:
print('RX packet:')
print(rx.show())
print('EXPECTED packet:')
print(expected.show())
self.assertDictEqual(rx, expected)
def payload(self, len):
return 'x' * len
def test_ipip4(self):
""" ip{v4,v6} over ip4 test """
p_ether = Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
p_ip6 = IPv6(src="1::1", dst="DEAD::1", nh='UDP')
p_ip4 = IP(src="1.2.3.4", dst="130.67.0.1")
p_payload = UDP(sport=1234, dport=1234)
# IPv4 transport
rv = self.vapi.ipip_add_tunnel(
src_address=str(ip_address(self.pg0.local_ip4).packed),
dst_address=str(ip_address(self.pg1.remote_ip4).packed),
is_ipv6=0)
self.assertEqual(rv.retval, 0)
sw_if_index = rv.sw_if_index
# Set interface up and enable IP on it
rv = self.vapi.sw_interface_set_flags(sw_if_index, 1)
self.assertEqual(rv.retval, 0)
rv = self.vapi.sw_interface_set_unnumbered(
ip_sw_if_index=self.pg0.sw_if_index,
sw_if_index=sw_if_index)
self.assertEqual(rv.retval, 0)
# Add IPv4 and IPv6 routes via tunnel interface
ip4_via_tunnel = VppIpRoute(
self, "130.67.0.0", 16,
[VppRoutePath("0.0.0.0",
sw_if_index,
proto=DpoProto.DPO_PROTO_IP4)], is_ip6=0)
ip4_via_tunnel.add_vpp_config()
ip6_via_tunnel = VppIpRoute(
self, "dead::", 16,
[VppRoutePath("::",
sw_if_index,
proto=DpoProto.DPO_PROTO_IP6)], is_ip6=1)
ip6_via_tunnel.add_vpp_config()
# IPv6 in to IPv4 tunnel
p6 = (p_ether / p_ip6 / p_payload)
p_inner_ip6 = p_ip6
p_inner_ip6.hlim -= 1
p6_reply = (IP(src=self.pg0.local_ip4, dst=self.pg1.remote_ip4,
proto='ipv6', id=0) / p_inner_ip6 / p_payload)
p6_reply.ttl -= 1
rx = self.send_and_expect(self.pg0, p6*10, self.pg1)
for p in rx:
self.validate(p[1], p6_reply)
# IPv4 in to IPv4 tunnel
p4 = (p_ether / p_ip4 / p_payload)
p_ip4_inner = p_ip4
p_ip4_inner.ttl -= 1
p4_reply = (IP(src=self.pg0.local_ip4,
dst=self.pg1.remote_ip4) / p_ip4_inner / p_payload)
p4_reply.ttl -= 1
p4_reply.id = 0
rx = self.send_and_expect(self.pg0, p4*10, self.pg1)
for p in rx:
self.validate(p[1], p4_reply)
# Decapsulation
p_ether = Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac)
# IPv4 tunnel to IPv4
p_ip4 = IP(src="1.2.3.4", dst=self.pg0.remote_ip4)
p4 = (p_ether / IP(src=self.pg1.remote_ip4,
dst=self.pg0.local_ip4) / p_ip4 / p_payload)
p4_reply = (p_ip4 / p_payload)
p4_reply.ttl -= 1
rx = self.send_and_expect(self.pg1, p4*10, self.pg0)
for p in rx:
self.validate(p[1], p4_reply)
# IPv4 tunnel to IPv6
p_ip6 = IPv6(src="1:2:3::4", dst=self.pg0.remote_ip6)
p6 = (p_ether / IP(src=self.pg1.remote_ip4,
dst=self.pg0.local_ip4) / p_ip6 / p_payload)
p6_reply = (p_ip6 / p_payload)
p6_reply.hlim = 63
rx = self.send_and_expect(self.pg1, p6*10, self.pg0)
for p in rx:
self.validate(p[1], p6_reply)
def test_ipip6(self):
""" ip{v4,v6} over ip6 test """
p_ether = Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
p_ip6 = IPv6(src="1::1", dst="DEAD::1", nh='UDP')
p_ip4 = IP(src="1.2.3.4", dst="130.67.0.1")
p_payload = UDP(sport=1234, dport=1234)
# IPv6 transport
rv = self.vapi.ipip_add_tunnel(
src_address=str(ip_address(self.pg0.local_ip6).packed),
dst_address=str(ip_address(self.pg1.remote_ip6).packed))
self.assertEqual(rv.retval, 0)
sw_if_index = rv.sw_if_index
rv = self.vapi.sw_interface_set_flags(sw_if_index, 1)
self.assertEqual(rv.retval, 0)
rv = self.vapi.sw_interface_set_unnumbered(
ip_sw_if_index=self.pg0.sw_if_index, sw_if_index=sw_if_index)
self.assertEqual(rv.retval, 0)
# Add IPv4 and IPv6 routes via tunnel interface
ip4_via_tunnel = VppIpRoute(
self, "130.67.0.0", 16,
[VppRoutePath("0.0.0.0",
sw_if_index,
proto=DpoProto.DPO_PROTO_IP4)], is_ip6=0)
ip4_via_tunnel.add_vpp_config()
ip6_via_tunnel = VppIpRoute(
self, "dead::", 16,
[VppRoutePath("::",
sw_if_index,
proto=DpoProto.DPO_PROTO_IP6)], is_ip6=1)
ip6_via_tunnel.add_vpp_config()
# Encapsulation
# IPv6 in to IPv6 tunnel
p6 = (p_ether / p_ip6 / p_payload)
p6_reply = (IPv6(src=self.pg0.local_ip6,
dst=self.pg1.remote_ip6, hlim=63) / p_ip6 / p_payload)
p6_reply[1].hlim -= 1
rx = self.send_and_expect(self.pg0, p6*10, self.pg1)
for p in rx:
self.validate(p[1], p6_reply)
# IPv4 in to IPv6 tunnel
p4 = (p_ether / p_ip4 / p_payload)
p4_reply = (IPv6(src=self.pg0.local_ip6,
dst=self.pg1.remote_ip6, hlim=63) / p_ip4 / p_payload)
p4_reply[1].ttl -= 1
rx = self.send_and_expect(self.pg0, p4*10, self.pg1)
for p in rx:
self.validate(p[1], p4_reply)
# Decapsulation
p_ether = Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac)
# IPv6 tunnel to IPv4
p_ip4 = IP(src="1.2.3.4", dst=self.pg0.remote_ip4)
p4 = (p_ether / IPv6(src=self.pg1.remote_ip6,
dst=self.pg0.local_ip6) / p_ip4 / p_payload)
p4_reply = (p_ip4 / p_payload)
p4_reply.ttl -= 1
rx = self.send_and_expect(self.pg1, p4*10, self.pg0)
for p in rx:
self.validate(p[1], p4_reply)
# IPv6 tunnel to IPv6
p_ip6 = IPv6(src="1:2:3::4", dst=self.pg0.remote_ip6)
p6 = (p_ether / IPv6(src=self.pg1.remote_ip6,
dst=self.pg0.local_ip6) / p_ip6 / p_payload)
p6_reply = (p_ip6 / p_payload)
p6_reply.hlim = 63
rx = self.send_and_expect(self.pg1, p6*10, self.pg0)
for p in rx:
self.validate(p[1], p6_reply)
def test_ipip_create(self):
""" ipip create / delete interface test """
rv = self.vapi.ipip_add_tunnel(
src_address=str(ip_address('1.2.3.4').packed),
dst_address=str(ip_address('2.3.4.5').packed), is_ipv6=0)
self.assertEqual(rv.retval, 0)
sw_if_index = rv.sw_if_index
rv = self.vapi.ipip_del_tunnel(sw_if_index)
self.assertEqual(rv.retval, 0)
if __name__ == '__main__':
unittest.main(testRunner=VppTestRunner)
+30 -18
View File
@@ -57,9 +57,11 @@ class Test6RD(VppTestCase):
i.admin_down()
if type(self.tunnel_index) is list:
for sw_if_index in self.tunnel_index:
self.vapi.sixrd_del_tunnel(sw_if_index)
rv = self.vapi.ipip_6rd_del_tunnel(sw_if_index)
self.assertEqual(rv.retval, 0)
else:
self.vapi.sixrd_del_tunnel(self.tunnel_index)
rv = self.vapi.ipip_6rd_del_tunnel(self.tunnel_index)
self.assertEqual(rv.retval, 0)
self.vapi.cli("show error")
def validate_6in4(self, rx, expected):
@@ -92,13 +94,14 @@ class Test6RD(VppTestCase):
p_ether = Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
p_ip6 = IPv6(src="1::1", dst="2002:AC10:0202::1", nh='UDP')
rv = self.vapi.sixrd_add_tunnel(
rv = self.vapi.ipip_6rd_add_tunnel(
0, str(ip_address('2002::').packed), 16,
str(ip_address('0.0.0.0').packed), 0,
str(ip_address(self.pg0.local_ip4).packed), 0, True)
str(ip_address(self.pg0.local_ip4).packed), True)
self.assertEqual(rv.retval, 0)
self.tunnel_index = rv.sw_if_index
self.vapi.cli("show ip6 fib")
p_payload = UDP(sport=1234, dport=1234)
p = (p_ether / p_ip6 / p_payload)
@@ -124,13 +127,21 @@ class Test6RD(VppTestCase):
def test_6rd_ip4_to_ip6(self):
""" ip4 -> ip6 (decap) 6rd test """
rv = self.vapi.sixrd_add_tunnel(
rv = self.vapi.ipip_6rd_add_tunnel(
0, str(ip_address('2002::').packed),
16, str(ip_address('0.0.0.0').packed),
0, str(ip_address(self.pg0.local_ip4).packed), 0, True)
0, str(ip_address(self.pg0.local_ip4).packed), True)
self.assertEqual(rv.retval, 0)
self.tunnel_index = rv.sw_if_index
self.vapi.cli("show ip6 fib")
rv = self.vapi.ipip_6rd_del_tunnel(rv.sw_if_index)
self.assertEqual(rv.retval, 0)
rv = self.vapi.ipip_6rd_add_tunnel(
0, str(ip_address('2002::').packed),
16, str(ip_address('0.0.0.0').packed),
0, str(ip_address(self.pg0.local_ip4).packed), True)
self.tunnel_index = rv.sw_if_index
self.assertEqual(rv.retval, 0)
p_ip6 = (IPv6(src="2002:AC10:0202::1", dst=self.pg1.remote_ip6) /
UDP(sport=1234, dport=1234))
@@ -149,18 +160,18 @@ class Test6RD(VppTestCase):
""" ip4 -> ip6 (decap) 6rd test """
self.tunnel_index = []
rv = self.vapi.sixrd_add_tunnel(
rv = self.vapi.ipip_6rd_add_tunnel(
0, str(ip_address('2002::').packed),
16, str(ip_address('0.0.0.0').packed),
0, str(ip_address(self.pg0.local_ip4).packed), 0, True)
0, str(ip_address(self.pg0.local_ip4).packed), True)
self.assertEqual(rv.retval, 0)
self.tunnel_index.append(rv.sw_if_index)
rv = self.vapi.sixrd_add_tunnel(
rv = self.vapi.ipip_6rd_add_tunnel(
0, str(ip_address('2003::').packed),
16, str(ip_address('0.0.0.0').packed),
0, str(ip_address(self.pg1.local_ip4).packed), 0, True)
0, str(ip_address(self.pg1.local_ip4).packed), True)
self.assertEqual(rv.retval, 0)
self.tunnel_index.append(rv.sw_if_index)
self.vapi.cli("show ip6 fib")
@@ -184,10 +195,10 @@ class Test6RD(VppTestCase):
def test_6rd_ip4_to_ip6_suffix(self):
""" ip4 -> ip6 (decap) 6rd test """
rv = self.vapi.sixrd_add_tunnel(
rv = self.vapi.ipip_6rd_add_tunnel(
0, str(ip_address('2002::').packed), 16,
str(ip_address('172.0.0.0').packed), 8,
str(ip_address(self.pg0.local_ip4).packed), 0, True)
str(ip_address(self.pg0.local_ip4).packed), True)
self.assertEqual(rv.retval, 0)
self.tunnel_index = rv.sw_if_index
@@ -206,12 +217,13 @@ class Test6RD(VppTestCase):
def test_6rd_ip4_to_ip6_sec_check(self):
""" ip4 -> ip6 (decap) security check 6rd test """
rv = self.vapi.sixrd_add_tunnel(
rv = self.vapi.ipip_6rd_add_tunnel(
0, str(ip_address('2002::').packed),
16, str(ip_address('0.0.0.0').packed),
0, str(ip_address(self.pg0.local_ip4).packed), 0, True)
0, str(ip_address(self.pg0.local_ip4).packed), True)
self.assertEqual(rv.retval, 0)
self.tunnel_index = rv.sw_if_index
self.vapi.cli("show ip6 fib")
p_ip6 = (IPv6(src="2002:AC10:0202::1", dst=self.pg1.remote_ip6) /
UDP(sport=1234, dport=1234))
@@ -238,10 +250,10 @@ class Test6RD(VppTestCase):
def test_6rd_bgp_tunnel(self):
""" 6rd BGP tunnel """
rv = self.vapi.sixrd_add_tunnel(
rv = self.vapi.ipip_6rd_add_tunnel(
0, str(ip_address('2002::').packed),
16, str(ip_address('0.0.0.0').packed),
0, str(ip_address(self.pg0.local_ip4).packed), 0, False)
0, str(ip_address(self.pg0.local_ip4).packed), False)
self.assertEqual(rv.retval, 0)
self.tunnel_index = rv.sw_if_index
+21 -7
View File
@@ -3202,21 +3202,35 @@ class VppPapiProvider(object):
""" GBP contract Dump """
return self.api(self.papi.gbp_contract_dump, {})
def sixrd_add_tunnel(self, fib_index, ip6_prefix, ip6_prefix_len,
ip4_prefix, ip4_prefix_len, ip4_src, mtu,
security_check):
def ipip_6rd_add_tunnel(self, fib_index, ip6_prefix, ip6_prefix_len,
ip4_prefix, ip4_prefix_len, ip4_src,
security_check):
""" 6RD tunnel Add """
return self.api(self.papi.sixrd_add_tunnel,
return self.api(self.papi.ipip_6rd_add_tunnel,
{'fib_index': fib_index,
'ip6_prefix': ip6_prefix,
'ip6_prefix_len': ip6_prefix_len,
'ip4_prefix': ip4_prefix,
'ip4_prefix_len': ip4_prefix_len,
'ip4_src': ip4_src,
'mtu': mtu,
'security_check': security_check})
def sixrd_del_tunnel(self, sw_if_index):
def ipip_6rd_del_tunnel(self, sw_if_index):
""" 6RD tunnel Delete """
return self.api(self.papi.sixrd_del_tunnel,
return self.api(self.papi.ipip_6rd_del_tunnel,
{'sw_if_index': sw_if_index})
def ipip_add_tunnel(self, src_address, dst_address, is_ipv6=1,
instance=0xFFFFFFFF, fib_index=0):
""" IPIP tunnel Add/Del """
return self.api(self.papi.ipip_add_tunnel,
{'is_ipv6': is_ipv6,
'instance': instance,
'src_address': src_address,
'dst_address': dst_address,
'fib_index': fib_index})
def ipip_del_tunnel(self, sw_if_index):
""" IPIP tunnel Delete """
return self.api(self.papi.ipip_del_tunnel,
{'sw_if_index': sw_if_index})