reassembly: feature/concurrency
This change makes ip reassembly an interface feature, while adding concurrency support. Due to this, punt is no longer needed to test reassembly. Change-Id: I467669514ec33283ce935be0f1dd08f07684f0c7 Signed-off-by: Klement Sekera <ksekera@cisco.com>
This commit is contained in:

committed by
Damjan Marion

parent
2303cb181b
commit
4c53313cd7
@ -161,15 +161,24 @@ typedef struct
|
||||
} icmp;
|
||||
|
||||
/* reassembly */
|
||||
struct
|
||||
union
|
||||
{
|
||||
u16 fragment_first;
|
||||
u16 fragment_last;
|
||||
u16 range_first;
|
||||
u16 range_last;
|
||||
u32 next_range_bi;
|
||||
u16 ip6_frag_hdr_offset;
|
||||
u16 estimated_mtu;
|
||||
/* in/out variables */
|
||||
struct
|
||||
{
|
||||
u32 next_index; /* index of next node - ignored if "feature" node */
|
||||
u16 estimated_mtu; /* estimated MTU calculated during reassembly */
|
||||
};
|
||||
/* internal variables used during reassembly */
|
||||
struct
|
||||
{
|
||||
u16 fragment_first;
|
||||
u16 fragment_last;
|
||||
u16 range_first;
|
||||
u16 range_last;
|
||||
u32 next_range_bi;
|
||||
u16 ip6_frag_hdr_offset;
|
||||
};
|
||||
} reass;
|
||||
};
|
||||
|
||||
|
@ -910,6 +910,22 @@ define ip_reassembly_get_reply
|
||||
u8 is_ip6;
|
||||
};
|
||||
|
||||
/** \brief Enable/disable reassembly feature
|
||||
@param client_index - opaque cookie to identify the sender
|
||||
@param context - sender context, to match reply w/ request
|
||||
@param sw_if_index - interface to enable/disable feature on
|
||||
@param enable_ip4 - enable ip4 reassembly if non-zero, disable if 0
|
||||
@param enable_ip6 - enable ip6 reassembly if non-zero, disable if 0
|
||||
*/
|
||||
autoreply define ip_reassembly_enable_disable
|
||||
{
|
||||
u32 client_index;
|
||||
u32 context;
|
||||
u32 sw_if_index;
|
||||
u8 enable_ip4;
|
||||
u8 enable_ip6;
|
||||
};
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* eval: (c-set-style "gnu")
|
||||
|
@ -38,6 +38,8 @@
|
||||
*/
|
||||
|
||||
#include <vnet/ip/ip.h>
|
||||
#include <vnet/ip/ip4_reassembly.h>
|
||||
#include <vnet/ip/ip6_reassembly.h>
|
||||
|
||||
/**
|
||||
* @file
|
||||
@ -218,6 +220,87 @@ VLIB_CLI_COMMAND (set_interface_ip_address_command, static) = {
|
||||
};
|
||||
/* *INDENT-ON* */
|
||||
|
||||
static clib_error_t *
|
||||
set_reassembly_command_fn (vlib_main_t * vm,
|
||||
unformat_input_t * input, vlib_cli_command_t * cmd)
|
||||
{
|
||||
vnet_main_t *vnm = vnet_get_main ();
|
||||
unformat_input_t _line_input, *line_input = &_line_input;
|
||||
u32 sw_if_index = ~0;
|
||||
u8 ip4_on = 0;
|
||||
u8 ip6_on = 0;
|
||||
|
||||
/* Get a line of input. */
|
||||
if (!unformat_user (input, unformat_line_input, line_input))
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!unformat (input, "%U", unformat_vnet_sw_interface, vnm, &sw_if_index))
|
||||
{
|
||||
return clib_error_return (0, "Invalid interface name");
|
||||
}
|
||||
|
||||
if (unformat (input, "on"))
|
||||
{
|
||||
ip4_on = 1;
|
||||
ip6_on = 1;
|
||||
}
|
||||
else if (unformat (input, "off"))
|
||||
{
|
||||
ip4_on = 0;
|
||||
ip6_on = 0;
|
||||
}
|
||||
else if (unformat (input, "ip4"))
|
||||
{
|
||||
ip4_on = 1;
|
||||
ip6_on = 0;
|
||||
}
|
||||
else if (unformat (input, "ip6"))
|
||||
{
|
||||
ip4_on = 0;
|
||||
ip6_on = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
return clib_error_return (0, "Unknown input `%U'",
|
||||
format_unformat_error, line_input);
|
||||
}
|
||||
|
||||
|
||||
vnet_api_error_t rv4 = ip4_reass_enable_disable (sw_if_index, ip4_on);
|
||||
vnet_api_error_t rv6 = ip6_reass_enable_disable (sw_if_index, ip6_on);
|
||||
if (rv4 && rv6)
|
||||
{
|
||||
return clib_error_return (0,
|
||||
"`ip4_reass_enable_disable' API call failed, rv=%d:%U, "
|
||||
"`ip6_reass_enable_disable' API call failed, rv=%d:%U",
|
||||
(int) rv4, format_vnet_api_errno, rv4,
|
||||
(int) rv6, format_vnet_api_errno, rv6);
|
||||
}
|
||||
else if (rv4)
|
||||
{
|
||||
return clib_error_return (0,
|
||||
"`ip4_reass_enable_disable' API call failed, rv=%d:%U",
|
||||
(int) rv4, format_vnet_api_errno, rv4);
|
||||
}
|
||||
else if (rv6)
|
||||
{
|
||||
return clib_error_return (0,
|
||||
"`ip6_reass_enable_disable' API call failed, rv=%d:%U",
|
||||
(int) rv6, format_vnet_api_errno, rv6);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* *INDENT-OFF* */
|
||||
VLIB_CLI_COMMAND (set_reassembly_command, static) = {
|
||||
.path = "set interface reassembly",
|
||||
.short_help = "set interface reassembly <interface-name> [on|off|ip4|ip6]",
|
||||
.function = set_reassembly_command_fn,
|
||||
};
|
||||
/* *INDENT-ON* */
|
||||
|
||||
/* Dummy init function to get us linked in. */
|
||||
static clib_error_t *
|
||||
ip4_cli_init (vlib_main_t * vm)
|
||||
|
@ -1217,14 +1217,8 @@ ip4_local_inline (vlib_main_t * vm,
|
||||
sw_if_index0 = vnet_buffer (p0)->sw_if_index[VLIB_RX];
|
||||
sw_if_index1 = vnet_buffer (p1)->sw_if_index[VLIB_RX];
|
||||
|
||||
/* Treat IP frag packets as "experimental" protocol for now
|
||||
until support of IP frag reassembly is implemented */
|
||||
proto0 =
|
||||
ip4_is_fragment (ip0) ? IP_PROTOCOL_VPP_FRAGMENTATION :
|
||||
ip0->protocol;
|
||||
proto1 =
|
||||
ip4_is_fragment (ip1) ? IP_PROTOCOL_VPP_FRAGMENTATION :
|
||||
ip1->protocol;
|
||||
proto0 = ip0->protocol;
|
||||
proto1 = ip1->protocol;
|
||||
|
||||
if (head_of_feature_arc == 0)
|
||||
goto skip_checks;
|
||||
@ -1387,11 +1381,7 @@ ip4_local_inline (vlib_main_t * vm,
|
||||
vnet_buffer (p0)->l3_hdr_offset = p0->current_data;
|
||||
sw_if_index0 = vnet_buffer (p0)->sw_if_index[VLIB_RX];
|
||||
|
||||
/* Treat IP frag packets as "experimental" protocol for now
|
||||
until support of IP frag reassembly is implemented */
|
||||
proto0 =
|
||||
ip4_is_fragment (ip0) ? IP_PROTOCOL_VPP_FRAGMENTATION :
|
||||
ip0->protocol;
|
||||
proto0 = ip0->protocol;
|
||||
|
||||
if (head_of_feature_arc == 0 || p0->flags & VNET_BUFFER_F_IS_NATED)
|
||||
goto skip_check;
|
||||
@ -1482,7 +1472,6 @@ VLIB_REGISTER_NODE (ip4_local_node) =
|
||||
[IP_LOCAL_NEXT_PUNT] = "ip4-punt",
|
||||
[IP_LOCAL_NEXT_UDP_LOOKUP] = "ip4-udp-lookup",
|
||||
[IP_LOCAL_NEXT_ICMP] = "ip4-icmp-input",
|
||||
[IP_LOCAL_NEXT_REASSEMBLY] = "ip4-reassembly",
|
||||
},
|
||||
};
|
||||
/* *INDENT-ON* */
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -38,6 +38,9 @@ vnet_api_error_t ip4_reass_set (u32 timeout_ms, u32 max_reassemblies,
|
||||
vnet_api_error_t ip4_reass_get (u32 * timeout_ms, u32 * max_reassemblies,
|
||||
u32 * expire_walk_interval_ms);
|
||||
|
||||
vnet_api_error_t ip4_reass_enable_disable (u32 sw_if_index,
|
||||
u8 enable_disable);
|
||||
|
||||
#endif /* __included_ip4_reassembly_h */
|
||||
|
||||
/*
|
||||
|
@ -1352,7 +1352,6 @@ VLIB_REGISTER_NODE (ip6_local_node, static) =
|
||||
[IP_LOCAL_NEXT_PUNT] = "ip6-punt",
|
||||
[IP_LOCAL_NEXT_UDP_LOOKUP] = "ip6-udp-lookup",
|
||||
[IP_LOCAL_NEXT_ICMP] = "ip6-icmp-input",
|
||||
[IP_LOCAL_NEXT_REASSEMBLY] = "ip6-reassembly",
|
||||
},
|
||||
};
|
||||
/* *INDENT-ON* */
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -38,6 +38,9 @@ vnet_api_error_t ip6_reass_set (u32 timeout_ms, u32 max_reassemblies,
|
||||
vnet_api_error_t ip6_reass_get (u32 * timeout_ms, u32 * max_reassemblies,
|
||||
u32 * expire_walk_interval_ms);
|
||||
|
||||
vnet_api_error_t ip6_reass_enable_disable (u32 sw_if_index,
|
||||
u8 enable_disable);
|
||||
|
||||
#endif /* __included_ip6_reassembly_h */
|
||||
|
||||
/*
|
||||
|
@ -103,7 +103,8 @@ _(IP_SOURCE_AND_PORT_RANGE_CHECK_ADD_DEL, \
|
||||
_(IP_SOURCE_AND_PORT_RANGE_CHECK_INTERFACE_ADD_DEL, \
|
||||
ip_source_and_port_range_check_interface_add_del) \
|
||||
_(IP_REASSEMBLY_SET, ip_reassembly_set) \
|
||||
_(IP_REASSEMBLY_GET, ip_reassembly_get)
|
||||
_(IP_REASSEMBLY_GET, ip_reassembly_get) \
|
||||
_(IP_REASSEMBLY_ENABLE_DISABLE, ip_reassembly_enable_disable)
|
||||
|
||||
extern void stats_dslock_with_hint (int hint, int tag);
|
||||
extern void stats_dsunlock (void);
|
||||
@ -2904,6 +2905,23 @@ vl_api_ip_reassembly_get_t_handler (vl_api_ip_reassembly_get_t * mp)
|
||||
vl_msg_api_send_shmem (q, (u8 *) & rmp);
|
||||
}
|
||||
|
||||
void
|
||||
vl_api_ip_reassembly_enable_disable_t_handler
|
||||
(vl_api_ip_reassembly_enable_disable_t * mp)
|
||||
{
|
||||
vl_api_ip_reassembly_enable_disable_reply_t *rmp;
|
||||
int rv = 0;
|
||||
rv = ip4_reass_enable_disable (clib_net_to_host_u32 (mp->sw_if_index),
|
||||
mp->enable_ip4);
|
||||
if (0 == rv)
|
||||
{
|
||||
rv = ip6_reass_enable_disable (clib_net_to_host_u32 (mp->sw_if_index),
|
||||
mp->enable_ip6);
|
||||
}
|
||||
|
||||
REPLY_MACRO (VL_API_IP_REASSEMBLY_SET_REPLY);
|
||||
}
|
||||
|
||||
#define vl_msg_name_crc_list
|
||||
#include <vnet/ip/ip.api.h>
|
||||
#undef vl_msg_name_crc_list
|
||||
|
@ -230,8 +230,6 @@ ip_lookup_init (ip_lookup_main_t * lm, u32 is_ip6)
|
||||
}
|
||||
|
||||
lm->local_next_by_ip_protocol[IP_PROTOCOL_UDP] = IP_LOCAL_NEXT_UDP_LOOKUP;
|
||||
lm->local_next_by_ip_protocol[IP_PROTOCOL_VPP_FRAGMENTATION] =
|
||||
IP_LOCAL_NEXT_REASSEMBLY;
|
||||
lm->local_next_by_ip_protocol[is_ip6 ? IP_PROTOCOL_ICMP6 :
|
||||
IP_PROTOCOL_ICMP] = IP_LOCAL_NEXT_ICMP;
|
||||
lm->builtin_protocol_by_ip_protocol[IP_PROTOCOL_UDP] =
|
||||
|
@ -111,7 +111,6 @@ typedef enum
|
||||
IP_LOCAL_NEXT_PUNT,
|
||||
IP_LOCAL_NEXT_UDP_LOOKUP,
|
||||
IP_LOCAL_NEXT_ICMP,
|
||||
IP_LOCAL_NEXT_REASSEMBLY,
|
||||
IP_LOCAL_N_NEXT,
|
||||
} ip_local_next_t;
|
||||
|
||||
|
@ -377,6 +377,10 @@ class VppTestCase(unittest.TestCase):
|
||||
try:
|
||||
cls.vapi.connect()
|
||||
except:
|
||||
try:
|
||||
cls.vapi.disconnect()
|
||||
except:
|
||||
pass
|
||||
if cls.debug_gdbserver:
|
||||
print(colorize("You're running VPP inside gdbserver but "
|
||||
"VPP-API connection failed, did you forget "
|
||||
|
@ -1,68 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
file="$1"
|
||||
|
||||
usage(){
|
||||
echo "Usage: $0 <requirements file>"
|
||||
}
|
||||
|
||||
if [ "$file" == "" ]
|
||||
then
|
||||
echo "Invalid parameters specified."
|
||||
usage
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ ! -f $file ]
|
||||
then
|
||||
echo "File '$file' does not exist."
|
||||
usage
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if test "$DOCKER_TEST" = "True"
|
||||
then
|
||||
echo "=============================================================================="
|
||||
echo "DOCKER_TEST is set to '$DOCKER_TEST'."
|
||||
echo "Skipping verification of some system parameters."
|
||||
echo "Make sure these are set properly, otherwise tests might fail."
|
||||
echo "Required values/criteria are in '`readlink -e $file`'."
|
||||
echo "=============================================================================="
|
||||
exit 0
|
||||
fi
|
||||
|
||||
cat $file | grep -v -e '^#.*$' | grep -v -e '^ *$' | while read line
|
||||
do
|
||||
value_file=`echo $line | awk '{print $1}'`
|
||||
operator=`echo $line | awk '{print $2}'`
|
||||
value=`echo $line | awk '{print $3}'`
|
||||
set_value=`echo $line | awk '{print $4}'`
|
||||
if [[ "$value_file" == "" || "$operator" == "" || "$value" == "" || "$set_value" == "" ]]
|
||||
then
|
||||
echo "Syntax error in requirements file."
|
||||
exit 1
|
||||
fi
|
||||
current_value=`cat $value_file`
|
||||
if test "$current_value" $operator "$value"
|
||||
then
|
||||
if test "$V" = "2"
|
||||
then
|
||||
echo "Requirement '$value_file $operator $value' satisfied."
|
||||
fi
|
||||
else
|
||||
echo "Requirement '$value_file $operator $value' not satisfied."
|
||||
echo "Writing '$set_value' to '$value_file'."
|
||||
echo "$set_value" | tee "$value_file" > /dev/null
|
||||
if ! test "`cat $value_file`" = "$set_value"
|
||||
then
|
||||
echo "Repeating the write using sudo..."
|
||||
echo "$set_value" | sudo -n tee "$value_file" > /dev/null
|
||||
if ! test "`cat $value_file`" = "$set_value"
|
||||
then
|
||||
echo "Couldn't set the required value. Is that value allowed? Is sudo working?"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
echo "Succesfully wrote '$set_value' to '$value_file'."
|
||||
fi
|
||||
done
|
@ -1,18 +0,0 @@
|
||||
# test framework system requirements
|
||||
# format of this file is
|
||||
# <path> <operator> <comparison-value> <set-value>
|
||||
#
|
||||
# path - path to value e.g. in /proc which needs to be checked
|
||||
# operator - test operator (e.g. -gt)
|
||||
# comparison-value - value, against which the value read from <path> is compared
|
||||
# set-value - value, to which the path is set if the test fails
|
||||
#
|
||||
# the comparison is done using `test' command
|
||||
|
||||
|
||||
# test_reassembly.py
|
||||
# needed by test_reassembly which uses udp punt via unix domain sockets
|
||||
# to ensure that all data which vpp might produce in a burst fits into
|
||||
# the socket send buffer
|
||||
/proc/sys/net/core/wmem_max -ge 4636252 4636252
|
||||
/proc/sys/net/core/wmem_default -ge 4636252 4636252
|
File diff suppressed because it is too large
Load Diff
@ -3203,6 +3203,15 @@ class VppPapiProvider(object):
|
||||
""" Get IP reassembly parameters """
|
||||
return self.api(self.papi.ip_reassembly_get, {'is_ip6': is_ip6})
|
||||
|
||||
def ip_reassembly_enable_disable(self, sw_if_index, enable_ip4=False,
|
||||
enable_ip6=False):
|
||||
""" Enable/disable IP reassembly """
|
||||
return self.api(self.papi.ip_reassembly_enable_disable,
|
||||
{'sw_if_index': sw_if_index,
|
||||
'enable_ip4': 1 if enable_ip4 else 0,
|
||||
'enable_ip6': 1 if enable_ip6 else 0,
|
||||
})
|
||||
|
||||
def gbp_endpoint_add_del(self, is_add, sw_if_index, addr, is_ip6, epg):
|
||||
""" GBP endpoint Add/Del """
|
||||
return self.api(self.papi.gbp_endpoint_add_del,
|
||||
|
@ -1,75 +0,0 @@
|
||||
from socket import socket, AF_UNIX, SOCK_DGRAM
|
||||
from select import select
|
||||
from time import time
|
||||
from struct import unpack, calcsize
|
||||
from util import ppc
|
||||
from scapy.layers.l2 import Ether
|
||||
|
||||
client_uds_socket_name = "client-uds-socket"
|
||||
vpp_uds_socket_name = "vpp-uds-socket"
|
||||
|
||||
VPP_PUNT_HEADER_FMT = '=Ii'
|
||||
VPP_PUNT_HEADER_SIZE = calcsize(VPP_PUNT_HEADER_FMT)
|
||||
|
||||
|
||||
class VppPuntAction:
|
||||
PUNT_L2 = 0
|
||||
PUNT_IP4_ROUTED = 1
|
||||
PUNT_IP6_ROUTED = 2
|
||||
|
||||
|
||||
class VppUDSPuntSocket(object):
|
||||
def __init__(self, testcase, port, is_ip4=1, l4_protocol=0x11):
|
||||
client_path = '%s/%s-%s-%s' % (testcase.tempdir,
|
||||
client_uds_socket_name,
|
||||
"4" if is_ip4 else "6", port)
|
||||
testcase.vapi.punt_socket_register(
|
||||
port, client_path, is_ip4=is_ip4, l4_protocol=l4_protocol)
|
||||
self.testcase = testcase
|
||||
self.uds = socket(AF_UNIX, SOCK_DGRAM)
|
||||
self.uds.bind(client_path)
|
||||
self.uds.connect(testcase.punt_socket_path)
|
||||
|
||||
def wait_for_packets(self, count, timeout=1):
|
||||
packets = []
|
||||
now = time()
|
||||
deadline = now + timeout
|
||||
while len(packets) < count and now < deadline:
|
||||
r, w, e = select([self.uds], [], [self.uds], deadline - now)
|
||||
if self.uds in r:
|
||||
x = self.uds.recv(1024 * 1024)
|
||||
sw_if_index, punt_action = unpack(
|
||||
VPP_PUNT_HEADER_FMT, x[:VPP_PUNT_HEADER_SIZE])
|
||||
packets.append({'sw_if_index': sw_if_index,
|
||||
'punt_action': punt_action,
|
||||
'packet': x[VPP_PUNT_HEADER_SIZE:]})
|
||||
|
||||
if self.uds in e:
|
||||
raise Exception("select() indicates error on UDS socket")
|
||||
now = time()
|
||||
|
||||
if len(packets) != count:
|
||||
raise Exception("Unexpected packet count received, got %s packets,"
|
||||
" expected %s packets" % (len(packets), count))
|
||||
self.testcase.logger.debug(
|
||||
"Got %s packets via punt socket" % len(packets))
|
||||
return packets
|
||||
|
||||
def assert_nothing_captured(self, timeout=.25):
|
||||
packets = []
|
||||
now = time()
|
||||
deadline = now + timeout
|
||||
while now < deadline:
|
||||
r, w, e = select([self.uds], [], [self.uds], deadline - now)
|
||||
if self.uds in r:
|
||||
x = self.uds.recv(1024 * 1024)
|
||||
packets.append(Ether(x[VPP_PUNT_HEADER_SIZE:]))
|
||||
if self.uds in e:
|
||||
raise Exception("select() indicates error on UDS socket")
|
||||
now = time()
|
||||
|
||||
if len(packets) > 0:
|
||||
self.testcase.logger.error(
|
||||
ppc("Unexpected packets captured:", packets))
|
||||
raise Exception("Unexpected packet count received, got %s packets,"
|
||||
" expected no packets" % len(packets))
|
Reference in New Issue
Block a user