Add GTP-U plugin. VPP-694
Basic GTP-U feature Change-Id: I31226f890a92c5303ac06e112ed7820cae52d9bd Signed-off-by: Hongjun Ni <hongjun.ni@intel.com>
This commit is contained in:
@ -147,6 +147,7 @@ AC_SUBST(AR_FLAGS)
|
||||
PLUGIN_ENABLED(acl)
|
||||
PLUGIN_ENABLED(dpdk)
|
||||
PLUGIN_ENABLED(flowperpkt)
|
||||
PLUGIN_ENABLED(gtpu)
|
||||
PLUGIN_ENABLED(ila)
|
||||
PLUGIN_ENABLED(ioam)
|
||||
PLUGIN_ENABLED(ixge)
|
||||
|
@ -41,6 +41,11 @@ if ENABLE_FLOWPERPKT_PLUGIN
|
||||
include flowperpkt.am
|
||||
endif
|
||||
|
||||
|
||||
if ENABLE_GTPU_PLUGIN
|
||||
include gtpu.am
|
||||
endif
|
||||
|
||||
if ENABLE_ILA_PLUGIN
|
||||
include ila.am
|
||||
endif
|
||||
|
38
src/plugins/gtpu.am
Normal file
38
src/plugins/gtpu.am
Normal file
@ -0,0 +1,38 @@
|
||||
# Copyright (c) 2016 Intel 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.
|
||||
|
||||
vppapitestplugins_LTLIBRARIES += gtpu_test_plugin.la
|
||||
vppplugins_LTLIBRARIES += gtpu_plugin.la
|
||||
|
||||
gtpu_plugin_la_SOURCES = \
|
||||
gtpu/gtpu_decap.c \
|
||||
gtpu/gtpu_encap.c \
|
||||
gtpu/gtpu.c \
|
||||
gtpu/gtpu_api.c
|
||||
|
||||
BUILT_SOURCES += \
|
||||
gtpu/gtpu.api.h \
|
||||
gtpu/gtpu.api.json
|
||||
|
||||
API_FILES += gtpu/gtpu.api
|
||||
|
||||
noinst_HEADERS += \
|
||||
gtpu/gtpu_all_api_h.h \
|
||||
gtpu/gtpu_msg_enum.h \
|
||||
gtpu/gtpu.api.h
|
||||
|
||||
gtpu_test_plugin_la_SOURCES = \
|
||||
gtpu/gtpu_test.c \
|
||||
gtpu/gtpu_plugin.api.h
|
||||
|
||||
# vi:syntax=automake
|
120
src/plugins/gtpu/gtpu.api
Normal file
120
src/plugins/gtpu/gtpu.api
Normal file
@ -0,0 +1,120 @@
|
||||
/*
|
||||
* Copyright (c) 2017 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.
|
||||
*/
|
||||
|
||||
/** \brief /** \brief Set or delete an GTPU tunnel
|
||||
@param client_index - opaque cookie to identify the sender
|
||||
@param context - sender context, to match reply w/ request
|
||||
@param is_add - add address if non-zero, else delete
|
||||
@param is_ipv6 - src_address and dst_address is ipv6 or not
|
||||
@param src_address - GTPU tunnel's source address.
|
||||
@param dst_address - GTPU tunnel's destination address.
|
||||
@param mcast_sw_if_index - version, O-bit and C-bit (see nsh_packet.h)
|
||||
@param encap_vrf_id - fib identifier used for outgoing encapsulated packets
|
||||
@param decap_next_index - the index of the next node if success
|
||||
@param teid - Local Tunnel Endpoint Identifier
|
||||
*/
|
||||
define gtpu_add_del_tunnel
|
||||
{
|
||||
u32 client_index;
|
||||
u32 context;
|
||||
u8 is_add;
|
||||
u8 is_ipv6;
|
||||
u8 src_address[16];
|
||||
u8 dst_address[16];
|
||||
u32 mcast_sw_if_index;
|
||||
u32 encap_vrf_id;
|
||||
u32 decap_next_index;
|
||||
u32 teid;
|
||||
};
|
||||
|
||||
/** \brief reply for set or delete an GTPU tunnel
|
||||
@param context - sender context, to match reply w/ request
|
||||
@param retval - return code
|
||||
@param sw_if_index - software index of the interface
|
||||
*/
|
||||
define gtpu_add_del_tunnel_reply
|
||||
{
|
||||
u32 context;
|
||||
i32 retval;
|
||||
u32 sw_if_index;
|
||||
};
|
||||
|
||||
/** \brief Dump GTPU tunnel
|
||||
@param client_index - opaque cookie to identify the sender
|
||||
@param context - sender context, to match reply w/ request
|
||||
@param sw_if_index - software index of the interface
|
||||
*/
|
||||
define gtpu_tunnel_dump
|
||||
{
|
||||
u32 client_index;
|
||||
u32 context;
|
||||
u32 sw_if_index;
|
||||
};
|
||||
|
||||
/** \brief /** \brief dump details of an GTPU tunnel
|
||||
@param context - sender context, to match reply w/ request
|
||||
@param sw_if_index - software index of the interface
|
||||
@param is_ipv6 - src_address and dst_address is ipv6 or not
|
||||
@param src_address - GTPU tunnel's source address.
|
||||
@param dst_address - GTPU tunnel's destination address.
|
||||
@param mcast_sw_if_index - version, O-bit and C-bit (see nsh_packet.h)
|
||||
@param encap_vrf_id - fib identifier used for outgoing encapsulated packets
|
||||
@param decap_next_index - the index of the next node if success
|
||||
@param teid - Local Tunnel Endpoint Identifier
|
||||
*/
|
||||
define gtpu_tunnel_details
|
||||
{
|
||||
u32 context;
|
||||
u32 sw_if_index;
|
||||
u8 is_ipv6;
|
||||
u8 src_address[16];
|
||||
u8 dst_address[16];
|
||||
u32 mcast_sw_if_index;
|
||||
u32 encap_vrf_id;
|
||||
u32 decap_next_index;
|
||||
u32 teid;
|
||||
};
|
||||
|
||||
/** \brief Interface set gtpu-bypass request
|
||||
@param client_index - opaque cookie to identify the sender
|
||||
@param context - sender context, to match reply w/ request
|
||||
@param sw_if_index - interface used to reach neighbor
|
||||
@param is_ipv6 - if non-zero, enable ipv6-gtpu-bypass, else ipv4-gtpu-bypass
|
||||
@param enable - if non-zero enable, else disable
|
||||
*/
|
||||
define sw_interface_set_gtpu_bypass
|
||||
{
|
||||
u32 client_index;
|
||||
u32 context;
|
||||
u32 sw_if_index;
|
||||
u8 is_ipv6;
|
||||
u8 enable;
|
||||
};
|
||||
|
||||
/** \brief Interface set gtpu-bypass response
|
||||
@param context - sender context, to match reply w/ request
|
||||
@param retval - return code for the request
|
||||
*/
|
||||
define sw_interface_set_gtpu_bypass_reply
|
||||
{
|
||||
u32 context;
|
||||
i32 retval;
|
||||
};
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* eval: (c-set-style "gnu")
|
||||
* End:
|
||||
*/
|
1128
src/plugins/gtpu/gtpu.c
Normal file
1128
src/plugins/gtpu/gtpu.c
Normal file
File diff suppressed because it is too large
Load Diff
262
src/plugins/gtpu/gtpu.h
Normal file
262
src/plugins/gtpu/gtpu.h
Normal file
@ -0,0 +1,262 @@
|
||||
/*
|
||||
*------------------------------------------------------------------
|
||||
* Copyright (c) 2016 Intel 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_vnet_gtpu_h
|
||||
#define included_vnet_gtpu_h
|
||||
|
||||
#include <vppinfra/lock.h>
|
||||
#include <vppinfra/error.h>
|
||||
#include <vppinfra/hash.h>
|
||||
#include <vnet/vnet.h>
|
||||
#include <vnet/ip/ip.h>
|
||||
#include <vnet/l2/l2_input.h>
|
||||
#include <vnet/l2/l2_output.h>
|
||||
#include <vnet/l2/l2_bd.h>
|
||||
#include <vnet/ethernet/ethernet.h>
|
||||
#include <vnet/ip/ip4_packet.h>
|
||||
#include <vnet/ip/ip6_packet.h>
|
||||
#include <vnet/udp/udp.h>
|
||||
#include <vnet/dpo/dpo.h>
|
||||
#include <vnet/adj/adj_types.h>
|
||||
#include <vnet/fib/fib_table.h>
|
||||
|
||||
/**
|
||||
* Bits
|
||||
* Octets 8 7 6 5 4 3 2 1
|
||||
* 1 Version PT (*) E S PN
|
||||
* 2 Message Type
|
||||
* 3 Length (1st Octet)
|
||||
* 4 Length (2nd Octet)
|
||||
* 5 Tunnel Endpoint Identifier (1st Octet)
|
||||
* 6 Tunnel Endpoint Identifier (2nd Octet)
|
||||
* 7 Tunnel Endpoint Identifier (3rd Octet)
|
||||
* 8 Tunnel Endpoint Identifier (4th Octet)
|
||||
* 9 Sequence Number (1st Octet)1) 4)
|
||||
* 10 Sequence Number (2nd Octet)1) 4)
|
||||
* 11 N-PDU Number2) 4)
|
||||
* 12 Next Extension Header Type3) 4)
|
||||
**/
|
||||
|
||||
typedef struct
|
||||
{
|
||||
u8 ver_flags;
|
||||
u8 type;
|
||||
u16 length; /* length in octets of the payload */
|
||||
u32 teid;
|
||||
u16 sequence;
|
||||
u8 pdu_number;
|
||||
u8 next_ext_type;
|
||||
} gtpu_header_t;
|
||||
|
||||
#define GTPU_VER_MASK (7<<5)
|
||||
#define GTPU_PT_BIT (1<<4)
|
||||
#define GTPU_E_BIT (1<<2)
|
||||
#define GTPU_S_BIT (1<<1)
|
||||
#define GTPU_PN_BIT (1<<0)
|
||||
#define GTPU_E_S_PN_BIT (7<<0)
|
||||
|
||||
#define GTPU_V1_VER (1<<5)
|
||||
|
||||
#define GTPU_PT_GTP (1<<4)
|
||||
#define GTPU_TYPE_GTPU 255
|
||||
|
||||
/* *INDENT-OFF* */
|
||||
typedef CLIB_PACKED(struct
|
||||
{
|
||||
ip4_header_t ip4; /* 20 bytes */
|
||||
udp_header_t udp; /* 8 bytes */
|
||||
gtpu_header_t gtpu; /* 8 bytes */
|
||||
}) ip4_gtpu_header_t;
|
||||
/* *INDENT-ON* */
|
||||
|
||||
/* *INDENT-OFF* */
|
||||
typedef CLIB_PACKED(struct
|
||||
{
|
||||
ip6_header_t ip6; /* 40 bytes */
|
||||
udp_header_t udp; /* 8 bytes */
|
||||
gtpu_header_t gtpu; /* 8 bytes */
|
||||
}) ip6_gtpu_header_t;
|
||||
/* *INDENT-ON* */
|
||||
|
||||
/* *INDENT-OFF* */
|
||||
typedef CLIB_PACKED
|
||||
(struct {
|
||||
/*
|
||||
* Key fields: ip src and gtpu teid on incoming gtpu packet
|
||||
* all fields in NET byte order
|
||||
*/
|
||||
union {
|
||||
struct {
|
||||
u32 src;
|
||||
u32 teid;
|
||||
};
|
||||
u64 as_u64;
|
||||
};
|
||||
}) gtpu4_tunnel_key_t;
|
||||
/* *INDENT-ON* */
|
||||
|
||||
/* *INDENT-OFF* */
|
||||
typedef CLIB_PACKED
|
||||
(struct {
|
||||
/*
|
||||
* Key fields: ip src and gtpu teid on incoming gtpu packet
|
||||
* all fields in NET byte order
|
||||
*/
|
||||
ip6_address_t src;
|
||||
u32 teid;
|
||||
}) gtpu6_tunnel_key_t;
|
||||
/* *INDENT-ON* */
|
||||
|
||||
typedef struct
|
||||
{
|
||||
/* Rewrite string */
|
||||
u8 *rewrite;
|
||||
|
||||
/* FIB DPO for IP forwarding of gtpu encap packet */
|
||||
dpo_id_t next_dpo;
|
||||
|
||||
/* gtpu teid in HOST byte order */
|
||||
u32 teid;
|
||||
|
||||
/* tunnel src and dst addresses */
|
||||
ip46_address_t src;
|
||||
ip46_address_t dst;
|
||||
|
||||
/* mcast packet output intf index (used only if dst is mcast) */
|
||||
u32 mcast_sw_if_index;
|
||||
|
||||
/* decap next index */
|
||||
u32 decap_next_index;
|
||||
|
||||
/* The FIB index for src/dst addresses */
|
||||
u32 encap_fib_index;
|
||||
|
||||
/* vnet intfc index */
|
||||
u32 sw_if_index;
|
||||
u32 hw_if_index;
|
||||
|
||||
/**
|
||||
* Linkage into the FIB object graph
|
||||
*/
|
||||
fib_node_t node;
|
||||
|
||||
/*
|
||||
* The FIB entry for (depending on gtpu tunnel is unicast or mcast)
|
||||
* sending unicast gtpu encap packets or receiving mcast gtpu packets
|
||||
*/
|
||||
fib_node_index_t fib_entry_index;
|
||||
adj_index_t mcast_adj_index;
|
||||
|
||||
/**
|
||||
* The tunnel is a child of the FIB entry for its destination. This is
|
||||
* so it receives updates when the forwarding information for that entry
|
||||
* changes.
|
||||
* The tunnels sibling index on the FIB entry's dependency list.
|
||||
*/
|
||||
u32 sibling_index;
|
||||
} gtpu_tunnel_t;
|
||||
|
||||
#define foreach_gtpu_input_next \
|
||||
_(DROP, "error-drop") \
|
||||
_(L2_INPUT, "l2-input")
|
||||
|
||||
typedef enum
|
||||
{
|
||||
#define _(s,n) GTPU_INPUT_NEXT_##s,
|
||||
foreach_gtpu_input_next
|
||||
#undef _
|
||||
GTPU_INPUT_N_NEXT,
|
||||
} gtpu_input_next_t;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
#define gtpu_error(n,s) GTPU_ERROR_##n,
|
||||
#include <gtpu/gtpu_error.def>
|
||||
#undef gtpu_error
|
||||
GTPU_N_ERROR,
|
||||
} gtpu_input_error_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
/* vector of encap tunnel instances */
|
||||
gtpu_tunnel_t *tunnels;
|
||||
|
||||
/* lookup tunnel by key */
|
||||
uword *gtpu4_tunnel_by_key; /* keyed on ipv4.dst + teid */
|
||||
uword *gtpu6_tunnel_by_key; /* keyed on ipv6.dst + teid */
|
||||
|
||||
/* local VTEP IPs ref count used by gtpu-bypass node to check if
|
||||
received gtpu packet DIP matches any local VTEP address */
|
||||
uword *vtep4; /* local ip4 VTEPs keyed on their ip4 addr */
|
||||
uword *vtep6; /* local ip6 VTEPs keyed on their ip6 addr */
|
||||
|
||||
/* mcast shared info */
|
||||
uword *mcast_shared; /* keyed on mcast ip46 addr */
|
||||
|
||||
/* Free vlib hw_if_indices */
|
||||
u32 *free_gtpu_tunnel_hw_if_indices;
|
||||
|
||||
/* Mapping from sw_if_index to tunnel index */
|
||||
u32 *tunnel_index_by_sw_if_index;
|
||||
|
||||
/**
|
||||
* Node type for registering to fib changes.
|
||||
*/
|
||||
fib_node_type_t fib_node_type;
|
||||
|
||||
/* API message ID base */
|
||||
u16 msg_id_base;
|
||||
|
||||
/* convenience */
|
||||
vlib_main_t *vlib_main;
|
||||
vnet_main_t *vnet_main;
|
||||
} gtpu_main_t;
|
||||
|
||||
gtpu_main_t gtpu_main;
|
||||
|
||||
extern vlib_node_registration_t gtpu4_input_node;
|
||||
extern vlib_node_registration_t gtpu6_input_node;
|
||||
extern vlib_node_registration_t gtpu4_encap_node;
|
||||
extern vlib_node_registration_t gtpu6_encap_node;
|
||||
|
||||
u8 *format_gtpu_encap_trace (u8 * s, va_list * args);
|
||||
|
||||
typedef struct
|
||||
{
|
||||
u8 is_add;
|
||||
u8 is_ip6;
|
||||
ip46_address_t src, dst;
|
||||
u32 mcast_sw_if_index;
|
||||
u32 encap_fib_index;
|
||||
u32 decap_next_index;
|
||||
u32 teid;
|
||||
} vnet_gtpu_add_del_tunnel_args_t;
|
||||
|
||||
int vnet_gtpu_add_del_tunnel
|
||||
(vnet_gtpu_add_del_tunnel_args_t * a, u32 * sw_if_indexp);
|
||||
|
||||
void vnet_int_gtpu_bypass_mode (u32 sw_if_index, u8 is_ip6, u8 is_enable);
|
||||
#endif /* included_vnet_gtpu_h */
|
||||
|
||||
|
||||
/*
|
||||
* fd.io coding-style-patch-verification: ON
|
||||
*
|
||||
* Local Variables:
|
||||
* eval: (c-set-style "gnu")
|
||||
* End:
|
||||
*/
|
18
src/plugins/gtpu/gtpu_all_api_h.h
Normal file
18
src/plugins/gtpu/gtpu_all_api_h.h
Normal file
@ -0,0 +1,18 @@
|
||||
/*
|
||||
* gtpu_all_api_h.h - plug-in api #include file
|
||||
*
|
||||
* Copyright (c) Intel 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 <gtpu/gtpu.api.h>
|
256
src/plugins/gtpu/gtpu_api.c
Normal file
256
src/plugins/gtpu/gtpu_api.c
Normal file
@ -0,0 +1,256 @@
|
||||
/*
|
||||
*------------------------------------------------------------------
|
||||
* gtpu_api.c - gtpu api
|
||||
*
|
||||
* 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 <vnet/interface.h>
|
||||
#include <vnet/api_errno.h>
|
||||
#include <vnet/feature/feature.h>
|
||||
#include <vnet/fib/fib_table.h>
|
||||
|
||||
#include <vppinfra/byte_order.h>
|
||||
#include <vlibmemory/api.h>
|
||||
#include <vlibsocket/api.h>
|
||||
|
||||
#include <gtpu/gtpu.h>
|
||||
|
||||
|
||||
#define vl_msg_id(n,h) n,
|
||||
typedef enum
|
||||
{
|
||||
#include <gtpu/gtpu.api.h>
|
||||
/* We'll want to know how many messages IDs we need... */
|
||||
VL_MSG_FIRST_AVAILABLE,
|
||||
} vl_msg_id_t;
|
||||
#undef vl_msg_id
|
||||
|
||||
/* define message structures */
|
||||
#define vl_typedefs
|
||||
#include <gtpu/gtpu.api.h>
|
||||
#undef vl_typedefs
|
||||
|
||||
/* define generated endian-swappers */
|
||||
#define vl_endianfun
|
||||
#include <gtpu/gtpu.api.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 <gtpu/gtpu.api.h>
|
||||
#undef vl_printfun
|
||||
|
||||
/* Get the API version number */
|
||||
#define vl_api_version(n,v) static u32 api_version=(v);
|
||||
#include <gtpu/gtpu.api.h>
|
||||
#undef vl_api_version
|
||||
|
||||
#define vl_msg_name_crc_list
|
||||
#include <gtpu/gtpu.api.h>
|
||||
#undef vl_msg_name_crc_list
|
||||
|
||||
#define REPLY_MSG_ID_BASE gtm->msg_id_base
|
||||
#include <vlibapi/api_helper_macros.h>
|
||||
|
||||
static void
|
||||
setup_message_id_table (gtpu_main_t * gtm, api_main_t * am)
|
||||
{
|
||||
#define _(id,n,crc) \
|
||||
vl_msg_api_add_msg_name_crc (am, #n "_" #crc, id + gtm->msg_id_base);
|
||||
foreach_vl_msg_name_crc_gtpu;
|
||||
#undef _
|
||||
}
|
||||
|
||||
#define foreach_gtpu_plugin_api_msg \
|
||||
_(SW_INTERFACE_SET_GTPU_BYPASS, sw_interface_set_gtpu_bypass) \
|
||||
_(GTPU_ADD_DEL_TUNNEL, gtpu_add_del_tunnel) \
|
||||
_(GTPU_TUNNEL_DUMP, gtpu_tunnel_dump)
|
||||
|
||||
static void
|
||||
vl_api_sw_interface_set_gtpu_bypass_t_handler
|
||||
(vl_api_sw_interface_set_gtpu_bypass_t * mp)
|
||||
{
|
||||
vl_api_sw_interface_set_gtpu_bypass_reply_t *rmp;
|
||||
int rv = 0;
|
||||
u32 sw_if_index = ntohl (mp->sw_if_index);
|
||||
gtpu_main_t *gtm = >pu_main;
|
||||
|
||||
VALIDATE_SW_IF_INDEX (mp);
|
||||
|
||||
vnet_int_gtpu_bypass_mode (sw_if_index, mp->is_ipv6, mp->enable);
|
||||
BAD_SW_IF_INDEX_LABEL;
|
||||
|
||||
REPLY_MACRO (VL_API_SW_INTERFACE_SET_GTPU_BYPASS_REPLY);
|
||||
}
|
||||
|
||||
static void vl_api_gtpu_add_del_tunnel_t_handler
|
||||
(vl_api_gtpu_add_del_tunnel_t * mp)
|
||||
{
|
||||
vl_api_gtpu_add_del_tunnel_reply_t *rmp;
|
||||
int rv = 0;
|
||||
ip4_main_t *im = &ip4_main;
|
||||
gtpu_main_t *gtm = >pu_main;
|
||||
|
||||
uword *p = hash_get (im->fib_index_by_table_id, ntohl (mp->encap_vrf_id));
|
||||
if (!p)
|
||||
{
|
||||
rv = VNET_API_ERROR_NO_SUCH_FIB;
|
||||
goto out;
|
||||
}
|
||||
|
||||
vnet_gtpu_add_del_tunnel_args_t a = {
|
||||
.is_add = mp->is_add,
|
||||
.is_ip6 = mp->is_ipv6,
|
||||
.mcast_sw_if_index = ntohl (mp->mcast_sw_if_index),
|
||||
.encap_fib_index = p[0],
|
||||
.decap_next_index = ntohl (mp->decap_next_index),
|
||||
.teid = ntohl (mp->teid),
|
||||
.dst = to_ip46 (mp->is_ipv6, mp->dst_address),
|
||||
.src = to_ip46 (mp->is_ipv6, mp->src_address),
|
||||
};
|
||||
|
||||
/* Check src & dst are different */
|
||||
if (ip46_address_cmp (&a.dst, &a.src) == 0)
|
||||
{
|
||||
rv = VNET_API_ERROR_SAME_SRC_DST;
|
||||
goto out;
|
||||
}
|
||||
if (ip46_address_is_multicast (&a.dst) &&
|
||||
!vnet_sw_if_index_is_api_valid (a.mcast_sw_if_index))
|
||||
{
|
||||
rv = VNET_API_ERROR_INVALID_SW_IF_INDEX;
|
||||
goto out;
|
||||
}
|
||||
|
||||
u32 sw_if_index = ~0;
|
||||
rv = vnet_gtpu_add_del_tunnel (&a, &sw_if_index);
|
||||
|
||||
out:
|
||||
/* *INDENT-OFF* */
|
||||
REPLY_MACRO2(VL_API_GTPU_ADD_DEL_TUNNEL_REPLY,
|
||||
({
|
||||
rmp->sw_if_index = ntohl (sw_if_index);
|
||||
}));
|
||||
/* *INDENT-ON* */
|
||||
}
|
||||
|
||||
static void send_gtpu_tunnel_details
|
||||
(gtpu_tunnel_t * t, unix_shared_memory_queue_t * q, u32 context)
|
||||
{
|
||||
vl_api_gtpu_tunnel_details_t *rmp;
|
||||
ip4_main_t *im4 = &ip4_main;
|
||||
ip6_main_t *im6 = &ip6_main;
|
||||
u8 is_ipv6 = !ip46_address_is_ip4 (&t->dst);
|
||||
|
||||
rmp = vl_msg_api_alloc (sizeof (*rmp));
|
||||
memset (rmp, 0, sizeof (*rmp));
|
||||
rmp->_vl_msg_id = ntohs (VL_API_GTPU_TUNNEL_DETAILS);
|
||||
if (is_ipv6)
|
||||
{
|
||||
memcpy (rmp->src_address, t->src.ip6.as_u8, 16);
|
||||
memcpy (rmp->dst_address, t->dst.ip6.as_u8, 16);
|
||||
rmp->encap_vrf_id = htonl (im6->fibs[t->encap_fib_index].ft_table_id);
|
||||
}
|
||||
else
|
||||
{
|
||||
memcpy (rmp->src_address, t->src.ip4.as_u8, 4);
|
||||
memcpy (rmp->dst_address, t->dst.ip4.as_u8, 4);
|
||||
rmp->encap_vrf_id = htonl (im4->fibs[t->encap_fib_index].ft_table_id);
|
||||
}
|
||||
rmp->mcast_sw_if_index = htonl (t->mcast_sw_if_index);
|
||||
rmp->teid = htonl (t->teid);
|
||||
rmp->decap_next_index = htonl (t->decap_next_index);
|
||||
rmp->sw_if_index = htonl (t->sw_if_index);
|
||||
rmp->is_ipv6 = is_ipv6;
|
||||
rmp->context = context;
|
||||
|
||||
vl_msg_api_send_shmem (q, (u8 *) & rmp);
|
||||
}
|
||||
|
||||
static void
|
||||
vl_api_gtpu_tunnel_dump_t_handler (vl_api_gtpu_tunnel_dump_t * mp)
|
||||
{
|
||||
unix_shared_memory_queue_t *q;
|
||||
gtpu_main_t *gtm = >pu_main;
|
||||
gtpu_tunnel_t *t;
|
||||
u32 sw_if_index;
|
||||
|
||||
q = vl_api_client_index_to_input_queue (mp->client_index);
|
||||
if (q == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
sw_if_index = ntohl (mp->sw_if_index);
|
||||
|
||||
if (~0 == sw_if_index)
|
||||
{
|
||||
/* *INDENT-OFF* */
|
||||
pool_foreach (t, gtm->tunnels,
|
||||
({
|
||||
send_gtpu_tunnel_details(t, q, mp->context);
|
||||
}));
|
||||
/* *INDENT-ON* */
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((sw_if_index >= vec_len (gtm->tunnel_index_by_sw_if_index)) ||
|
||||
(~0 == gtm->tunnel_index_by_sw_if_index[sw_if_index]))
|
||||
{
|
||||
return;
|
||||
}
|
||||
t = >m->tunnels[gtm->tunnel_index_by_sw_if_index[sw_if_index]];
|
||||
send_gtpu_tunnel_details (t, q, mp->context);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static clib_error_t *
|
||||
gtpu_api_hookup (vlib_main_t * vm)
|
||||
{
|
||||
gtpu_main_t *gtm = >pu_main;
|
||||
|
||||
u8 *name = format (0, "gtpu_%08x%c", api_version, 0);
|
||||
gtm->msg_id_base = vl_msg_api_get_msg_ids
|
||||
((char *) name, VL_MSG_FIRST_AVAILABLE);
|
||||
|
||||
#define _(N,n) \
|
||||
vl_msg_api_set_handlers((VL_API_##N + gtm->msg_id_base), \
|
||||
#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_gtpu_plugin_api_msg;
|
||||
#undef _
|
||||
|
||||
/* Add our API messages to the global name_crc hash table */
|
||||
setup_message_id_table (gtm, &api_main);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
VLIB_API_INIT_FUNCTION (gtpu_api_hookup);
|
||||
|
||||
/*
|
||||
* fd.io coding-style-patch-verification: ON
|
||||
*
|
||||
* Local Variables:
|
||||
* eval: (c-set-style "gnu")
|
||||
* End:
|
||||
*/
|
1305
src/plugins/gtpu/gtpu_decap.c
Normal file
1305
src/plugins/gtpu/gtpu_decap.c
Normal file
File diff suppressed because it is too large
Load Diff
569
src/plugins/gtpu/gtpu_encap.c
Normal file
569
src/plugins/gtpu/gtpu_encap.c
Normal file
File diff suppressed because it is too large
Load Diff
18
src/plugins/gtpu/gtpu_error.def
Normal file
18
src/plugins/gtpu/gtpu_error.def
Normal file
@ -0,0 +1,18 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
gtpu_error (DECAPSULATED, "good packets decapsulated")
|
||||
gtpu_error (NO_SUCH_TUNNEL, "no such tunnel packets")
|
||||
gtpu_error (BAD_VER, "packets with bad version in gtpu header")
|
||||
gtpu_error (BAD_FLAGS, "packets with bad flags field in gtpu header")
|
31
src/plugins/gtpu/gtpu_msg_enum.h
Normal file
31
src/plugins/gtpu/gtpu_msg_enum.h
Normal file
@ -0,0 +1,31 @@
|
||||
/*
|
||||
* gtpu_msg_enum.h - vpp engine plug-in message enumeration
|
||||
*
|
||||
* Copyright (c) <current-year> <your-organization>
|
||||
* 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_gtpu_msg_enum_h
|
||||
#define included_gtpu_msg_enum_h
|
||||
|
||||
#include <vppinfra/byte_order.h>
|
||||
|
||||
#define vl_msg_id(n,h) n,
|
||||
typedef enum
|
||||
{
|
||||
#include <gtpu/gtpu_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 /* included_gtpu_msg_enum_h */
|
498
src/plugins/gtpu/gtpu_test.c
Normal file
498
src/plugins/gtpu/gtpu_test.c
Normal file
File diff suppressed because it is too large
Load Diff
@ -167,6 +167,7 @@ typedef enum mfib_source_t_
|
||||
MFIB_SOURCE_DHCP,
|
||||
MFIB_SOURCE_SRv6,
|
||||
MFIB_SOURCE_DEFAULT_ROUTE,
|
||||
MFIB_SOURCE_GTPU,
|
||||
} mfib_source_t;
|
||||
|
||||
#define MFIB_SOURCE_NAMES { \
|
||||
@ -177,6 +178,7 @@ typedef enum mfib_source_t_
|
||||
[MFIB_SOURCE_VXLAN] = "VXLAN", \
|
||||
[MFIB_SOURCE_SRv6] = "SRv6", \
|
||||
[MFIB_SOURCE_DEFAULT_ROUTE] = "Default Route", \
|
||||
[MFIB_SOURCE_GTPU] = "GTPU", \
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -81,6 +81,7 @@ typedef enum
|
||||
_ (67, dhcp_to_server) \
|
||||
_ (68, dhcp_to_client) \
|
||||
_ (500, ikev2) \
|
||||
_ (2152, GTPU) \
|
||||
_ (3784, bfd4) \
|
||||
_ (3785, bfd_echo4) \
|
||||
_ (4341, lisp_gpe) \
|
||||
@ -95,6 +96,7 @@ _ (6633, vpath_3)
|
||||
#define foreach_udp6_dst_port \
|
||||
_ (547, dhcpv6_to_server) \
|
||||
_ (546, dhcpv6_to_client) \
|
||||
_ (2152, GTPU6) \
|
||||
_ (3784, bfd6) \
|
||||
_ (3785, bfd_echo6) \
|
||||
_ (4341, lisp_gpe6) \
|
||||
|
@ -128,6 +128,26 @@ jvpp-acl/io_fd_vpp_jvpp_acl_JVppAclImpl.h: $(jvpp_registry_ok) $(jvpp_acl_json_f
|
||||
$(call japigen,acl,JVppAclImpl)
|
||||
endif
|
||||
|
||||
#
|
||||
# GTPU Plugin
|
||||
#
|
||||
if ENABLE_GTPU_PLUGIN
|
||||
noinst_LTLIBRARIES += libjvpp_gtpu.la
|
||||
libjvpp_gtpu_la_SOURCES = jvpp-gtpu/jvpp_gtpu.c
|
||||
libjvpp_gtpu_la_CPPFLAGS = -Ijvpp-gtpu
|
||||
libjvpp_gtpu_la_LIBADD = $(JVPP_LIBS)
|
||||
libjvpp_gtpu_la_DEPENDENCIES = libjvpp_common.la
|
||||
|
||||
BUILT_SOURCES += jvpp-gtpu/io_fd_vpp_jvpp_gtpu_JVppGtpuImpl.h
|
||||
JAR_FILES += jvpp-gtpu-$(PACKAGE_VERSION).jar
|
||||
CLEANDIRS += jvpp-gtpu/target
|
||||
|
||||
jvpp_gtpu_json_files = @top_builddir@/plugins/gtpu/gtpu.api.json
|
||||
|
||||
jvpp-gtpu/io_fd_vpp_jvpp_gtpu_JVppGtpuImpl.h: $(jvpp_registry_ok) $(jvpp_gtpu_json_files)
|
||||
$(call japigen,gtpu,JVppGtpuImpl)
|
||||
endif
|
||||
|
||||
#
|
||||
# SNAT Plugin
|
||||
#
|
||||
|
107
src/vpp-api/java/jvpp-gtpu/jvpp_gtpu.c
Normal file
107
src/vpp-api/java/jvpp-gtpu/jvpp_gtpu.c
Normal file
@ -0,0 +1,107 @@
|
||||
/*
|
||||
* 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 <vnet/vnet.h>
|
||||
|
||||
#include <gtpu/gtpu_msg_enum.h>
|
||||
#define vl_typedefs /* define message structures */
|
||||
#include <gtpu/gtpu_all_api_h.h>
|
||||
#undef vl_typedefs
|
||||
|
||||
#include <vnet/api_errno.h>
|
||||
#include <vlibapi/api.h>
|
||||
#include <vlibmemory/api.h>
|
||||
|
||||
#if VPPJNI_DEBUG == 1
|
||||
#define DEBUG_LOG(...) clib_warning(__VA_ARGS__)
|
||||
#else
|
||||
#define DEBUG_LOG(...)
|
||||
#endif
|
||||
|
||||
#include <jvpp-common/jvpp_common.h>
|
||||
|
||||
#include "jvpp-gtpu/io_fd_vpp_jvpp_gtpu_JVppGtpuImpl.h"
|
||||
#include "jvpp_gtpu.h"
|
||||
#include "jvpp-gtpu/jvpp_gtpu_gen.h"
|
||||
|
||||
/*
|
||||
* Class: io_fd_vpp_jvpp_gtpu_JVppgtpuImpl
|
||||
* Method: init0
|
||||
* Signature: (JI)V
|
||||
*/
|
||||
JNIEXPORT void JNICALL Java_io_fd_vpp_jvpp_gtpu_JVppGtpuImpl_init0
|
||||
(JNIEnv *env, jclass clazz, jobject callback, jlong queue_address, jint my_client_index) {
|
||||
gtpu_main_t * plugin_main = >pu_main;
|
||||
clib_warning ("Java_io_fd_vpp_jvpp_gtpu_JVppGtpuImpl_init0");
|
||||
|
||||
plugin_main->my_client_index = my_client_index;
|
||||
plugin_main->vl_input_queue = (unix_shared_memory_queue_t *)queue_address;
|
||||
|
||||
plugin_main->callbackObject = (*env)->NewGlobalRef(env, callback);
|
||||
plugin_main->callbackClass = (jclass)(*env)->NewGlobalRef(env, (*env)->GetObjectClass(env, callback));
|
||||
|
||||
// verify API has not changed since jar generation
|
||||
#define _(N) \
|
||||
get_message_id(env, #N); \
|
||||
foreach_supported_api_message;
|
||||
#undef _
|
||||
|
||||
#define _(N,n) \
|
||||
vl_msg_api_set_handlers(get_message_id(env, #N), #n, \
|
||||
vl_api_##n##_t_handler, \
|
||||
vl_noop_handler, \
|
||||
vl_noop_handler, \
|
||||
vl_noop_handler, \
|
||||
sizeof(vl_api_##n##_t), 1);
|
||||
foreach_api_reply_handler;
|
||||
#undef _
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL Java_io_fd_vpp_jvpp_gtpu_JVppGtpuImpl_close0
|
||||
(JNIEnv *env, jclass clazz) {
|
||||
gtpu_main_t * plugin_main = >pu_main;
|
||||
|
||||
// cleanup:
|
||||
(*env)->DeleteGlobalRef(env, plugin_main->callbackClass);
|
||||
(*env)->DeleteGlobalRef(env, plugin_main->callbackObject);
|
||||
|
||||
plugin_main->callbackClass = NULL;
|
||||
plugin_main->callbackObject = NULL;
|
||||
}
|
||||
|
||||
/* Attach thread to JVM and cache class references when initiating JVPP ACL */
|
||||
jint JNI_OnLoad(JavaVM *vm, void *reserved) {
|
||||
JNIEnv* env;
|
||||
|
||||
if ((*vm)->GetEnv(vm, (void**) &env, JNI_VERSION_1_8) != JNI_OK) {
|
||||
return JNI_EVERSION;
|
||||
}
|
||||
|
||||
if (cache_class_references(env) != 0) {
|
||||
clib_warning ("Failed to cache class references\n");
|
||||
return JNI_ERR;
|
||||
}
|
||||
|
||||
return JNI_VERSION_1_8;
|
||||
}
|
||||
|
||||
/* Clean up cached references when disposing JVPP ACL */
|
||||
void JNI_OnUnload(JavaVM *vm, void *reserved) {
|
||||
JNIEnv* env;
|
||||
if ((*vm)->GetEnv(vm, (void**) &env, JNI_VERSION_1_8) != JNI_OK) {
|
||||
return;
|
||||
}
|
||||
delete_class_references(env);
|
||||
}
|
42
src/vpp-api/java/jvpp-gtpu/jvpp_gtpu.h
Normal file
42
src/vpp-api/java/jvpp-gtpu/jvpp_gtpu.h
Normal file
@ -0,0 +1,42 @@
|
||||
/*
|
||||
* 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_jvpp_gtpu_h__
|
||||
#define __included_jvpp_gtpu_h__
|
||||
|
||||
#include <vnet/vnet.h>
|
||||
#include <vnet/ip/ip.h>
|
||||
#include <vnet/api_errno.h>
|
||||
#include <vlibapi/api.h>
|
||||
#include <vlibmemory/api.h>
|
||||
#include <jni.h>
|
||||
|
||||
/* Global state for JVPP-gtpu */
|
||||
typedef struct {
|
||||
/* Pointer to shared memory queue */
|
||||
unix_shared_memory_queue_t * vl_input_queue;
|
||||
|
||||
/* VPP api client index */
|
||||
u32 my_client_index;
|
||||
|
||||
/* Callback object and class references enabling asynchronous Java calls */
|
||||
jobject callbackObject;
|
||||
jclass callbackClass;
|
||||
|
||||
} gtpu_main_t;
|
||||
|
||||
gtpu_main_t gtpu_main __attribute__((aligned (64)));
|
||||
|
||||
|
||||
#endif /* __included_jvpp_gtpu_h__ */
|
289
test/test_gtpu.py
Normal file
289
test/test_gtpu.py
Normal file
@ -0,0 +1,289 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
import socket
|
||||
from util import ip4n_range
|
||||
import unittest
|
||||
from framework import VppTestCase, VppTestRunner
|
||||
from template_bd import BridgeDomain
|
||||
|
||||
from scapy.layers.l2 import Ether, Raw
|
||||
from scapy.layers.inet import IP, UDP
|
||||
from scapy.contrib.gtp import GTP_U_Header
|
||||
from scapy.utils import atol
|
||||
|
||||
|
||||
class TestGtpu(BridgeDomain, VppTestCase):
|
||||
""" GTPU Test Case """
|
||||
|
||||
def __init__(self, *args):
|
||||
BridgeDomain.__init__(self)
|
||||
VppTestCase.__init__(self, *args)
|
||||
|
||||
def encapsulate(self, pkt, vni):
|
||||
"""
|
||||
Encapsulate the original payload frame by adding GTPU header with its
|
||||
UDP, IP and Ethernet fields
|
||||
"""
|
||||
return (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
|
||||
IP(src=self.pg0.remote_ip4, dst=self.pg0.local_ip4) /
|
||||
UDP(sport=self.dport, dport=self.dport, chksum=0) /
|
||||
GTP_U_Header(TEID=vni, gtp_type=self.gtp_type, length=150) /
|
||||
pkt)
|
||||
|
||||
def encap_mcast(self, pkt, src_ip, src_mac, vni):
|
||||
"""
|
||||
Encapsulate the original payload frame by adding GTPU header with its
|
||||
UDP, IP and Ethernet fields
|
||||
"""
|
||||
return (Ether(src=src_mac, dst=self.mcast_mac) /
|
||||
IP(src=src_ip, dst=self.mcast_ip4) /
|
||||
UDP(sport=self.dport, dport=self.dport, chksum=0) /
|
||||
GTP_U_Header(TEID=vni, gtp_type=self.gtp_type, length=150) /
|
||||
pkt)
|
||||
|
||||
def decapsulate(self, pkt):
|
||||
"""
|
||||
Decapsulate the original payload frame by removing GTPU header
|
||||
"""
|
||||
return pkt[GTP_U_Header].payload
|
||||
|
||||
# Method for checking GTPU encapsulation.
|
||||
#
|
||||
def check_encapsulation(self, pkt, vni, local_only=False, mcast_pkt=False):
|
||||
# Verify source MAC is VPP_MAC and destination MAC is MY_MAC resolved
|
||||
# by VPP using ARP.
|
||||
self.assertEqual(pkt[Ether].src, self.pg0.local_mac)
|
||||
if not local_only:
|
||||
if not mcast_pkt:
|
||||
self.assertEqual(pkt[Ether].dst, self.pg0.remote_mac)
|
||||
else:
|
||||
self.assertEqual(pkt[Ether].dst, type(self).mcast_mac)
|
||||
# Verify GTPU tunnel source IP is VPP_IP and destination IP is MY_IP.
|
||||
self.assertEqual(pkt[IP].src, self.pg0.local_ip4)
|
||||
if not local_only:
|
||||
if not mcast_pkt:
|
||||
self.assertEqual(pkt[IP].dst, self.pg0.remote_ip4)
|
||||
else:
|
||||
self.assertEqual(pkt[IP].dst, type(self).mcast_ip4)
|
||||
# Verify UDP destination port is GTPU 2152, source UDP port could be
|
||||
# arbitrary.
|
||||
self.assertEqual(pkt[UDP].dport, type(self).dport)
|
||||
# Verify TEID
|
||||
self.assertEqual(pkt[GTP_U_Header].TEID, vni)
|
||||
|
||||
def test_encap(self):
|
||||
""" Encapsulation test
|
||||
Send frames from pg1
|
||||
Verify receipt of encapsulated frames on pg0
|
||||
"""
|
||||
self.pg1.add_stream([self.frame_reply])
|
||||
|
||||
self.pg0.enable_capture()
|
||||
|
||||
self.pg_start()
|
||||
|
||||
# Pick first received frame and check if it's corectly encapsulated.
|
||||
out = self.pg0.get_capture(1)
|
||||
pkt = out[0]
|
||||
self.check_encapsulation(pkt, self.single_tunnel_bd)
|
||||
|
||||
# payload = self.decapsulate(pkt)
|
||||
# self.assert_eq_pkts(payload, self.frame_reply)
|
||||
|
||||
def test_ucast_flood(self):
|
||||
""" Unicast flood test
|
||||
Send frames from pg3
|
||||
Verify receipt of encapsulated frames on pg0
|
||||
"""
|
||||
self.pg3.add_stream([self.frame_reply])
|
||||
|
||||
self.pg0.enable_capture()
|
||||
|
||||
self.pg_start()
|
||||
|
||||
# Get packet from each tunnel and assert it's corectly encapsulated.
|
||||
out = self.pg0.get_capture(self.n_ucast_tunnels)
|
||||
for pkt in out:
|
||||
self.check_encapsulation(pkt, self.ucast_flood_bd, True)
|
||||
# payload = self.decapsulate(pkt)
|
||||
# self.assert_eq_pkts(payload, self.frame_reply)
|
||||
|
||||
def test_mcast_flood(self):
|
||||
""" Multicast flood test
|
||||
Send frames from pg2
|
||||
Verify receipt of encapsulated frames on pg0
|
||||
"""
|
||||
self.pg2.add_stream([self.frame_reply])
|
||||
|
||||
self.pg0.enable_capture()
|
||||
|
||||
self.pg_start()
|
||||
|
||||
# Pick first received frame and check if it's corectly encapsulated.
|
||||
out = self.pg0.get_capture(1)
|
||||
pkt = out[0]
|
||||
self.check_encapsulation(pkt, self.mcast_flood_bd,
|
||||
local_only=False, mcast_pkt=True)
|
||||
|
||||
# payload = self.decapsulate(pkt)
|
||||
# self.assert_eq_pkts(payload, self.frame_reply)
|
||||
|
||||
@classmethod
|
||||
def create_gtpu_flood_test_bd(cls, teid, n_ucast_tunnels):
|
||||
# Create 10 ucast gtpu tunnels under bd
|
||||
ip_range_start = 10
|
||||
ip_range_end = ip_range_start + n_ucast_tunnels
|
||||
next_hop_address = cls.pg0.remote_ip4n
|
||||
for dest_ip4n in ip4n_range(next_hop_address, ip_range_start,
|
||||
ip_range_end):
|
||||
# add host route so dest_ip4n will not be resolved
|
||||
cls.vapi.ip_add_del_route(dest_ip4n, 32, next_hop_address)
|
||||
r = cls.vapi.gtpu_add_del_tunnel(
|
||||
src_addr=cls.pg0.local_ip4n,
|
||||
dst_addr=dest_ip4n,
|
||||
teid=teid)
|
||||
cls.vapi.sw_interface_set_l2_bridge(r.sw_if_index, bd_id=teid)
|
||||
|
||||
@classmethod
|
||||
def add_del_shared_mcast_dst_load(cls, is_add):
|
||||
"""
|
||||
add or del tunnels sharing the same mcast dst
|
||||
to test gtpu ref_count mechanism
|
||||
"""
|
||||
n_shared_dst_tunnels = 20
|
||||
teid_start = 1000
|
||||
teid_end = teid_start + n_shared_dst_tunnels
|
||||
for teid in range(teid_start, teid_end):
|
||||
r = cls.vapi.gtpu_add_del_tunnel(
|
||||
src_addr=cls.pg0.local_ip4n,
|
||||
dst_addr=cls.mcast_ip4n,
|
||||
mcast_sw_if_index=1,
|
||||
teid=teid,
|
||||
is_add=is_add)
|
||||
if r.sw_if_index == 0xffffffff:
|
||||
raise "bad sw_if_index"
|
||||
|
||||
@classmethod
|
||||
def add_shared_mcast_dst_load(cls):
|
||||
cls.add_del_shared_mcast_dst_load(is_add=1)
|
||||
|
||||
@classmethod
|
||||
def del_shared_mcast_dst_load(cls):
|
||||
cls.add_del_shared_mcast_dst_load(is_add=0)
|
||||
|
||||
@classmethod
|
||||
def add_del_mcast_tunnels_load(cls, is_add):
|
||||
"""
|
||||
add or del tunnels to test gtpu stability
|
||||
"""
|
||||
n_distinct_dst_tunnels = 20
|
||||
ip_range_start = 10
|
||||
ip_range_end = ip_range_start + n_distinct_dst_tunnels
|
||||
for dest_ip4n in ip4n_range(cls.mcast_ip4n, ip_range_start,
|
||||
ip_range_end):
|
||||
teid = bytearray(dest_ip4n)[3]
|
||||
cls.vapi.gtpu_add_del_tunnel(
|
||||
src_addr=cls.pg0.local_ip4n,
|
||||
dst_addr=dest_ip4n,
|
||||
mcast_sw_if_index=1,
|
||||
teid=teid,
|
||||
is_add=is_add)
|
||||
|
||||
@classmethod
|
||||
def add_mcast_tunnels_load(cls):
|
||||
cls.add_del_mcast_tunnels_load(is_add=1)
|
||||
|
||||
@classmethod
|
||||
def del_mcast_tunnels_load(cls):
|
||||
cls.add_del_mcast_tunnels_load(is_add=0)
|
||||
|
||||
# Class method to start the GTPU test case.
|
||||
# Overrides setUpClass method in VppTestCase class.
|
||||
# Python try..except statement is used to ensure that the tear down of
|
||||
# the class will be executed even if exception is raised.
|
||||
# @param cls The class pointer.
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
super(TestGtpu, cls).setUpClass()
|
||||
|
||||
try:
|
||||
cls.dport = 2152
|
||||
cls.gtp_type = 0xff
|
||||
|
||||
# Create 2 pg interfaces.
|
||||
cls.create_pg_interfaces(range(4))
|
||||
for pg in cls.pg_interfaces:
|
||||
pg.admin_up()
|
||||
|
||||
# Configure IPv4 addresses on VPP pg0.
|
||||
cls.pg0.config_ip4()
|
||||
|
||||
# Resolve MAC address for VPP's IP address on pg0.
|
||||
cls.pg0.resolve_arp()
|
||||
|
||||
# Our Multicast address
|
||||
cls.mcast_ip4 = '239.1.1.1'
|
||||
cls.mcast_ip4n = socket.inet_pton(socket.AF_INET, cls.mcast_ip4)
|
||||
iplong = atol(cls.mcast_ip4)
|
||||
cls.mcast_mac = "01:00:5e:%02x:%02x:%02x" % (
|
||||
(iplong >> 16) & 0x7F, (iplong >> 8) & 0xFF, iplong & 0xFF)
|
||||
|
||||
# Create GTPU VTEP on VPP pg0, and put gtpu_tunnel0 and pg1
|
||||
# into BD.
|
||||
cls.single_tunnel_bd = 11
|
||||
r = cls.vapi.gtpu_add_del_tunnel(
|
||||
src_addr=cls.pg0.local_ip4n,
|
||||
dst_addr=cls.pg0.remote_ip4n,
|
||||
teid=cls.single_tunnel_bd)
|
||||
cls.vapi.sw_interface_set_l2_bridge(r.sw_if_index,
|
||||
bd_id=cls.single_tunnel_bd)
|
||||
cls.vapi.sw_interface_set_l2_bridge(cls.pg1.sw_if_index,
|
||||
bd_id=cls.single_tunnel_bd)
|
||||
|
||||
# Setup teid 2 to test multicast flooding
|
||||
cls.n_ucast_tunnels = 10
|
||||
cls.mcast_flood_bd = 12
|
||||
cls.create_gtpu_flood_test_bd(cls.mcast_flood_bd,
|
||||
cls.n_ucast_tunnels)
|
||||
r = cls.vapi.gtpu_add_del_tunnel(
|
||||
src_addr=cls.pg0.local_ip4n,
|
||||
dst_addr=cls.mcast_ip4n,
|
||||
mcast_sw_if_index=1,
|
||||
teid=cls.mcast_flood_bd)
|
||||
cls.vapi.sw_interface_set_l2_bridge(r.sw_if_index,
|
||||
bd_id=cls.mcast_flood_bd)
|
||||
cls.vapi.sw_interface_set_l2_bridge(cls.pg2.sw_if_index,
|
||||
bd_id=cls.mcast_flood_bd)
|
||||
|
||||
# Add and delete mcast tunnels to check stability
|
||||
cls.add_shared_mcast_dst_load()
|
||||
cls.add_mcast_tunnels_load()
|
||||
cls.del_shared_mcast_dst_load()
|
||||
cls.del_mcast_tunnels_load()
|
||||
|
||||
# Setup teid 3 to test unicast flooding
|
||||
cls.ucast_flood_bd = 13
|
||||
cls.create_gtpu_flood_test_bd(cls.ucast_flood_bd,
|
||||
cls.n_ucast_tunnels)
|
||||
cls.vapi.sw_interface_set_l2_bridge(cls.pg3.sw_if_index,
|
||||
bd_id=cls.ucast_flood_bd)
|
||||
except Exception:
|
||||
super(TestGtpu, cls).tearDownClass()
|
||||
raise
|
||||
|
||||
# Method to define VPP actions before tear down of the test case.
|
||||
# Overrides tearDown method in VppTestCase class.
|
||||
# @param self The object pointer.
|
||||
def tearDown(self):
|
||||
super(TestGtpu, self).tearDown()
|
||||
if not self.vpp_dead:
|
||||
self.logger.info(self.vapi.cli("show bridge-domain 11 detail"))
|
||||
self.logger.info(self.vapi.cli("show bridge-domain 12 detail"))
|
||||
self.logger.info(self.vapi.cli("show bridge-domain 13 detail"))
|
||||
self.logger.info(self.vapi.cli("show int"))
|
||||
self.logger.info(self.vapi.cli("show gtpu tunnel"))
|
||||
self.logger.info(self.vapi.cli("show trace"))
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main(testRunner=VppTestRunner)
|
@ -1775,3 +1775,35 @@ class VppPapiProvider(object):
|
||||
'is_translation': is_translation,
|
||||
'mtu': mtu
|
||||
})
|
||||
|
||||
def gtpu_add_del_tunnel(
|
||||
self,
|
||||
src_addr,
|
||||
dst_addr,
|
||||
is_add=1,
|
||||
is_ipv6=0,
|
||||
mcast_sw_if_index=0xFFFFFFFF,
|
||||
encap_vrf_id=0,
|
||||
decap_next_index=0xFFFFFFFF,
|
||||
teid=0):
|
||||
"""
|
||||
|
||||
:param is_add: (Default value = 1)
|
||||
:param is_ipv6: (Default value = 0)
|
||||
:param src_addr:
|
||||
:param dst_addr:
|
||||
:param mcast_sw_if_index: (Default value = 0xFFFFFFFF)
|
||||
:param encap_vrf_id: (Default value = 0)
|
||||
:param decap_next_index: (Default value = 0xFFFFFFFF)
|
||||
:param teid: (Default value = 0)
|
||||
|
||||
"""
|
||||
return self.api(self.papi.gtpu_add_del_tunnel,
|
||||
{'is_add': is_add,
|
||||
'is_ipv6': is_ipv6,
|
||||
'src_address': src_addr,
|
||||
'dst_address': dst_addr,
|
||||
'mcast_sw_if_index': mcast_sw_if_index,
|
||||
'encap_vrf_id': encap_vrf_id,
|
||||
'decap_next_index': decap_next_index,
|
||||
'teid': teid})
|
||||
|
Reference in New Issue
Block a user