mss_clamp: TCP MSS clamping plugin
Type: feature Configure TCP MSS clamping on an interface as follows: set interface tcp-mss-clamp [rx|tx] <interface-name> ip4 [enable|disable|rx|tx] ip4-mss <size> ip6 [enable|disable|rx|tx] ip6-mss <size> Change-Id: I45b04e50a0b70a33e14a9066f981c651292ebffb Signed-off-by: Neale Ranns <neale.ranns@cisco.com> Signed-off-by: Paul Vinciguerra <pvinci@vinciconsulting.com> Signed-off-by: Miklos Tirpak <miklos.tirpak@gmail.com> Signed-off-by: Matthew Smith <mgsmith@netgate.com>
This commit is contained in:
committed by
Damjan Marion
parent
ab9f57355f
commit
bf55e9931c
@@ -512,6 +512,11 @@ M: Hongjun Ni <hongjun.ni@intel.com>
|
||||
M: Vengada <venggovi@cisco.com>
|
||||
F: src/plugins/nsh/
|
||||
|
||||
Plugin - TCP MSS Clamping
|
||||
I: mss_clamp
|
||||
M: Miklos Tirpak <miklos.tirpak@emnify.com>
|
||||
F: src/plugins/mss_clamp/
|
||||
|
||||
Plugin - Time-based MAC filter
|
||||
I: mactime
|
||||
Y: src/plugins/mactime/FEATURE.yaml
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
|
||||
# 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.
|
||||
|
||||
add_vpp_plugin(mss_clamp
|
||||
SOURCES
|
||||
mss_clamp.c
|
||||
mss_clamp_api.c
|
||||
mss_clamp_node.c
|
||||
|
||||
|
||||
MULTIARCH_SOURCES
|
||||
mss_clamp_node.c
|
||||
|
||||
API_FILES
|
||||
mss_clamp.api
|
||||
|
||||
INSTALL_HEADERS
|
||||
mss_clamp.h
|
||||
)
|
||||
@@ -0,0 +1,112 @@
|
||||
/* Hey Emacs use -*- mode: C -*- */
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
option version = "1.0.0";
|
||||
import "vnet/interface_types.api";
|
||||
|
||||
/** \brief TCP MSS Clamping direction flag
|
||||
*/
|
||||
enumflag mss_clamp_dir : u8 {
|
||||
MSS_CLAMP_DIR_NONE = 0x0,
|
||||
MSS_CLAMP_DIR_RX = 0x1,
|
||||
MSS_CLAMP_DIR_TX = 0x2,
|
||||
};
|
||||
|
||||
/** \brief Enable/Disable TCP MSS Clamping feature on an interface
|
||||
@param client_index - opaque cookie to identify the sender
|
||||
@param context - sender context, to match reply w/ request
|
||||
@param sw_if_index - interface index on which clamping will be applied
|
||||
@param ipv4_mss - Maximum Segment Size for IPv4/TCP
|
||||
@param ipv6_mss - Maximum Segment Size for IPv6/TCP
|
||||
@param ipv4_direction - Direction clamping is enabled on (IPv4/TCP)
|
||||
@param ipv6_direction - Direction clamping is enabled on (IPv6/TCP)
|
||||
*/
|
||||
autoreply define mss_clamp_enable_disable {
|
||||
u32 client_index;
|
||||
u32 context;
|
||||
vl_api_interface_index_t sw_if_index;
|
||||
u16 ipv4_mss;
|
||||
u16 ipv6_mss;
|
||||
vl_api_mss_clamp_dir_t ipv4_direction;
|
||||
vl_api_mss_clamp_dir_t ipv6_direction;
|
||||
};
|
||||
|
||||
|
||||
/** \brief Get the list of configured mss values
|
||||
@param client_index - opaque cookie to identify the sender
|
||||
*/
|
||||
service {
|
||||
rpc mss_clamp_get returns mss_clamp_get_reply
|
||||
stream mss_clamp_details;
|
||||
};
|
||||
|
||||
/** \brief Get the TCP MSS Clamping feature settings
|
||||
@param client_index - opaque cookie to identify the sender
|
||||
@param context - sender context, to match reply w/ request
|
||||
@param cursor - cursor to continue when there is more to read
|
||||
@param sw_if_index - interface index to filter the result,
|
||||
~0 means no filter
|
||||
*/
|
||||
define mss_clamp_get {
|
||||
u32 client_index;
|
||||
u32 context;
|
||||
u32 cursor;
|
||||
vl_api_interface_index_t sw_if_index;
|
||||
};
|
||||
|
||||
/** \brief Reply for get TCP MSS Clamping feature settings request
|
||||
@param context - returned sender context, to match reply w/ request
|
||||
@param retval - return code
|
||||
@param cursor - cursor to continue when there is more to read
|
||||
*/
|
||||
define mss_clamp_get_reply {
|
||||
u32 context;
|
||||
i32 retval;
|
||||
u32 cursor;
|
||||
};
|
||||
|
||||
/** \brief Configured MSS values on an interface
|
||||
@param context - returned sender context, to match reply w/ request
|
||||
@param sw_if_index - interface index on which clamping is applied
|
||||
@param ipv4_mss - Maximum Segment Size for IPv4/TCP
|
||||
@param ipv6_mss - Maximum Segment Size for IPv6/TCP
|
||||
@param ipv4_direction - Direction clamping is enabled on (IPv4/TCP)
|
||||
@param ipv6_direction - Direction clamping is enabled on (IPv6/TCP)
|
||||
*/
|
||||
define mss_clamp_details {
|
||||
u32 context;
|
||||
vl_api_interface_index_t sw_if_index;
|
||||
u16 ipv4_mss;
|
||||
u16 ipv6_mss;
|
||||
vl_api_mss_clamp_dir_t ipv4_direction;
|
||||
vl_api_mss_clamp_dir_t ipv6_direction;
|
||||
};
|
||||
|
||||
counters mss_clamp {
|
||||
clamped {
|
||||
severity info;
|
||||
type counter64;
|
||||
units "packets";
|
||||
description "packets clamped";
|
||||
};
|
||||
};
|
||||
paths {
|
||||
"/err/tcp-mss-clamping-ip4-in" "mss-clamp";
|
||||
"/err/tcp-mss-clamping-ip4-out" "mss-clamp";
|
||||
"/err/tcp-mss-clamping-ip6-in" "mss-clamp";
|
||||
"/err/tcp-mss-clamping-ip6-out" "mss-clamp";
|
||||
};
|
||||
|
||||
@@ -0,0 +1,292 @@
|
||||
/*
|
||||
* mss_clamp.c - TCP MSS clamping plug-in
|
||||
*
|
||||
* 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 <vnet/vnet.h>
|
||||
#include <vnet/plugin/plugin.h>
|
||||
#include <mss_clamp/mss_clamp.h>
|
||||
#include <mss_clamp/mss_clamp.api_types.h>
|
||||
|
||||
mssc_main_t mssc_main;
|
||||
|
||||
/* Action function shared between message handler and debug CLI */
|
||||
|
||||
static void
|
||||
mssc_enable_disable_feat (u32 sw_if_index, u8 dir4, u8 dir6, int enable)
|
||||
{
|
||||
if (dir4 == MSS_CLAMP_DIR_NONE && dir6 == MSS_CLAMP_DIR_NONE)
|
||||
return;
|
||||
|
||||
// ip4
|
||||
if ((dir4 & MSS_CLAMP_DIR_RX) != MSS_CLAMP_DIR_NONE)
|
||||
vnet_feature_enable_disable ("ip4-unicast", "tcp-mss-clamping-ip4-in",
|
||||
sw_if_index, enable, 0, 0);
|
||||
if ((dir4 & MSS_CLAMP_DIR_TX) != MSS_CLAMP_DIR_NONE)
|
||||
vnet_feature_enable_disable ("ip4-output", "tcp-mss-clamping-ip4-out",
|
||||
sw_if_index, enable, 0, 0);
|
||||
// ip6
|
||||
if ((dir6 & MSS_CLAMP_DIR_RX) != MSS_CLAMP_DIR_NONE)
|
||||
vnet_feature_enable_disable ("ip6-unicast", "tcp-mss-clamping-ip6-in",
|
||||
sw_if_index, enable, 0, 0);
|
||||
if ((dir6 & MSS_CLAMP_DIR_TX) != MSS_CLAMP_DIR_NONE)
|
||||
vnet_feature_enable_disable ("ip6-output", "tcp-mss-clamping-ip6-out",
|
||||
sw_if_index, enable, 0, 0);
|
||||
}
|
||||
|
||||
int
|
||||
mssc_enable_disable (u32 sw_if_index, u8 dir4, u8 dir6, u16 mss4, u16 mss6)
|
||||
{
|
||||
mssc_main_t *cm = &mssc_main;
|
||||
u8 *dir_enabled4, *dir_enabled6;
|
||||
int rv = 0;
|
||||
|
||||
if (dir4 == MSS_CLAMP_DIR_NONE)
|
||||
mss4 = MSS_CLAMP_UNSET;
|
||||
if (dir6 == MSS_CLAMP_DIR_NONE)
|
||||
mss6 = MSS_CLAMP_UNSET;
|
||||
|
||||
vec_validate_init_empty (cm->dir_enabled4, sw_if_index, MSS_CLAMP_DIR_NONE);
|
||||
vec_validate_init_empty (cm->dir_enabled6, sw_if_index, MSS_CLAMP_DIR_NONE);
|
||||
vec_validate_init_empty (cm->max_mss4, sw_if_index, MSS_CLAMP_UNSET);
|
||||
vec_validate_init_empty (cm->max_mss6, sw_if_index, MSS_CLAMP_UNSET);
|
||||
|
||||
cm->max_mss4[sw_if_index] = mss4;
|
||||
cm->max_mss6[sw_if_index] = mss6;
|
||||
dir_enabled4 = &cm->dir_enabled4[sw_if_index];
|
||||
dir_enabled6 = &cm->dir_enabled6[sw_if_index];
|
||||
|
||||
// Disable the directions that are no longer needed
|
||||
mssc_enable_disable_feat (sw_if_index, (*dir_enabled4) & ~dir4,
|
||||
(*dir_enabled6) & ~dir6, 0);
|
||||
// Enable the new directions
|
||||
mssc_enable_disable_feat (sw_if_index, ~(*dir_enabled4) & dir4,
|
||||
~(*dir_enabled6) & dir6, 1);
|
||||
|
||||
*dir_enabled4 = dir4;
|
||||
*dir_enabled6 = dir6;
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
int
|
||||
mssc_get_mss (u32 sw_if_index, u8 *dir4, u8 *dir6, u16 *mss4, u16 *mss6)
|
||||
{
|
||||
mssc_main_t *cm = &mssc_main;
|
||||
int rv = VNET_API_ERROR_FEATURE_DISABLED;
|
||||
|
||||
if (vec_len (cm->dir_enabled4) > sw_if_index &&
|
||||
MSS_CLAMP_DIR_NONE != cm->dir_enabled4[sw_if_index])
|
||||
{
|
||||
*mss4 = cm->max_mss4[sw_if_index];
|
||||
*dir4 = cm->dir_enabled4[sw_if_index];
|
||||
rv = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
*mss4 = MSS_CLAMP_DIR_NONE;
|
||||
*dir4 = 0;
|
||||
}
|
||||
|
||||
if (vec_len (cm->dir_enabled6) > sw_if_index &&
|
||||
MSS_CLAMP_DIR_NONE != cm->dir_enabled6[sw_if_index])
|
||||
{
|
||||
*mss6 = cm->max_mss6[sw_if_index];
|
||||
*dir6 = cm->dir_enabled6[sw_if_index];
|
||||
rv = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
*mss6 = MSS_CLAMP_DIR_NONE;
|
||||
*dir6 = 0;
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
static uword
|
||||
unformat_mssc_dir (unformat_input_t *input, va_list *args)
|
||||
{
|
||||
u8 *result = va_arg (*args, u8 *);
|
||||
u8 dir = MSS_CLAMP_DIR_RX | MSS_CLAMP_DIR_TX;
|
||||
|
||||
if (unformat (input, "disable"))
|
||||
dir = MSS_CLAMP_DIR_NONE;
|
||||
else if (unformat (input, "enable"))
|
||||
dir = MSS_CLAMP_DIR_RX | MSS_CLAMP_DIR_TX;
|
||||
else if (unformat (input, "rx"))
|
||||
dir = MSS_CLAMP_DIR_RX;
|
||||
else if (unformat (input, "tx"))
|
||||
dir = MSS_CLAMP_DIR_TX;
|
||||
else
|
||||
return 0;
|
||||
|
||||
*result = dir;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static clib_error_t *
|
||||
mssc_enable_command_fn (vlib_main_t *vm, unformat_input_t *input,
|
||||
vlib_cli_command_t *cmd)
|
||||
{
|
||||
u32 sw_if_index = ~0;
|
||||
u8 dir4 = ~0, dir6 = ~0;
|
||||
u32 mss4 = ~0, mss6 = ~0;
|
||||
int rv;
|
||||
|
||||
while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
|
||||
{
|
||||
if (unformat (input, "ip4 %U", unformat_mssc_dir, &dir4))
|
||||
;
|
||||
else if (unformat (input, "ip6 %U", unformat_mssc_dir, &dir6))
|
||||
;
|
||||
else if (unformat (input, "ip4-mss %d", &mss4))
|
||||
;
|
||||
else if (unformat (input, "ip6-mss %d", &mss6))
|
||||
;
|
||||
else if (unformat (input, "%U", unformat_vnet_sw_interface,
|
||||
vnet_get_main (), &sw_if_index))
|
||||
;
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
if (sw_if_index == ~0)
|
||||
return clib_error_return (0, "Please specify an interface");
|
||||
|
||||
if (dir4 == (u8) ~0 || dir6 == (u8) ~0)
|
||||
return clib_error_return (
|
||||
0, "Please specify the MSS clamping direction for ip4 and ip6");
|
||||
|
||||
if (dir4 != MSS_CLAMP_DIR_NONE)
|
||||
{
|
||||
if (mss4 == ~0)
|
||||
return clib_error_return (
|
||||
0, "Please specify the Max Segment Size for ip4");
|
||||
if (mss4 >= MSS_CLAMP_UNSET)
|
||||
return clib_error_return (0, "Invalid Max Segment Size");
|
||||
}
|
||||
if (dir6 != MSS_CLAMP_DIR_NONE)
|
||||
{
|
||||
if (mss6 == ~0)
|
||||
return clib_error_return (
|
||||
0, "Please specify the Max Segment Size for ip6");
|
||||
if (mss6 >= MSS_CLAMP_UNSET)
|
||||
return clib_error_return (0, "Invalid Max Segment Size");
|
||||
}
|
||||
|
||||
rv = mssc_enable_disable (sw_if_index, dir4, dir6, mss4, mss6);
|
||||
|
||||
if (rv)
|
||||
return clib_error_return (0, "Failed: %d = %U", rv, format_vnet_api_errno,
|
||||
rv);
|
||||
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
VLIB_CLI_COMMAND (mssc_enable_disable_command, static) = {
|
||||
.path = "set interface tcp-mss-clamp",
|
||||
.short_help = "set interface tcp-mss-clamp <interface-name> "
|
||||
"ip4 [enable|disable|rx|tx] ip4-mss <size> "
|
||||
"ip6 [enable|disable|rx|tx] ip6-mss <size>",
|
||||
.function = mssc_enable_command_fn,
|
||||
};
|
||||
|
||||
static u8 *
|
||||
format_mssc_clamping (u8 *s, va_list *args)
|
||||
{
|
||||
u8 dir = va_arg (*args, u32);
|
||||
u16 mss = va_arg (*args, u32);
|
||||
#define DIR2S(d) \
|
||||
(((d) == (MSS_CLAMP_DIR_RX | MSS_CLAMP_DIR_TX)) ? \
|
||||
"" : \
|
||||
(((d) == MSS_CLAMP_DIR_RX) ? " [RX]" : " [TX]"))
|
||||
|
||||
if (MSS_CLAMP_DIR_NONE == dir)
|
||||
{
|
||||
return format (s, "disabled");
|
||||
}
|
||||
u32 mss_u32 = mss;
|
||||
return format (s, "%d%s", mss_u32, DIR2S (dir));
|
||||
}
|
||||
|
||||
static clib_error_t *
|
||||
mssc_show_command_fn (vlib_main_t *vm, unformat_input_t *input,
|
||||
vlib_cli_command_t *cmd)
|
||||
{
|
||||
mssc_main_t *cm = &mssc_main;
|
||||
u32 sw_if_index = ~0;
|
||||
u32 ii;
|
||||
|
||||
while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
|
||||
{
|
||||
if (unformat (input, "%U", unformat_vnet_sw_interface, vnet_get_main (),
|
||||
&sw_if_index))
|
||||
;
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
if (sw_if_index == ~0)
|
||||
{
|
||||
vec_foreach_index (ii, cm->dir_enabled4)
|
||||
{
|
||||
u8 dir4 = cm->dir_enabled4[ii];
|
||||
u8 dir6 = cm->dir_enabled6[ii];
|
||||
if (MSS_CLAMP_DIR_NONE != dir4 || MSS_CLAMP_DIR_NONE != dir6)
|
||||
{
|
||||
u16 mss4 = cm->max_mss4[ii];
|
||||
u16 mss6 = cm->max_mss6[ii];
|
||||
vlib_cli_output (vm, "%U: ip4: %U ip6: %U",
|
||||
format_vnet_sw_if_index_name, vnet_get_main (),
|
||||
ii, format_mssc_clamping, dir4, mss4,
|
||||
format_mssc_clamping, dir6, mss6);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
u16 mss4, mss6;
|
||||
u8 dir4, dir6;
|
||||
mssc_get_mss (sw_if_index, &dir4, &dir6, &mss4, &mss6);
|
||||
vlib_cli_output (vm, "%U: ip4: %U ip6: %U", format_vnet_sw_if_index_name,
|
||||
vnet_get_main (), sw_if_index, format_mssc_clamping,
|
||||
dir4, mss4, format_mssc_clamping, dir6, mss6);
|
||||
}
|
||||
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
VLIB_CLI_COMMAND (mssc_show_command, static) = {
|
||||
.path = "show interface tcp-mss-clamp",
|
||||
.short_help = "show interface tcp-mss-clamp [interface-name]",
|
||||
.long_help = "show TCP MSS clamping configurations",
|
||||
.function = mssc_show_command_fn,
|
||||
};
|
||||
|
||||
static clib_error_t *
|
||||
mssc_init (vlib_main_t *vm)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
VLIB_INIT_FUNCTION (mssc_init);
|
||||
|
||||
/*
|
||||
* fd.io coding-style-patch-verification: ON
|
||||
*
|
||||
* Local Variables:
|
||||
* eval: (c-set-style "gnu")
|
||||
* End:
|
||||
*/
|
||||
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* mss_clamp.h - TCP MSS clamping plug-in header file
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef __included_mss_clamp_h__
|
||||
#define __included_mss_clamp_h__
|
||||
|
||||
#include <stdbool.h> /* for bool in .api */
|
||||
#include <vnet/vnet.h>
|
||||
|
||||
extern int mssc_enable_disable (u32 sw_if_index, u8 dir4, u8 dir6, u16 mss4,
|
||||
u16 mss6);
|
||||
extern int mssc_get_mss (u32 sw_if_index, u8 *dir4, u8 *dir6, u16 *mss4,
|
||||
u16 *mss6);
|
||||
|
||||
typedef struct
|
||||
{
|
||||
/* Maximum segment size per interface for IPv4/IPv6 */
|
||||
u16 *max_mss4;
|
||||
u16 *max_mss6;
|
||||
|
||||
/* Direction the feature is enabled for IPv4/IPv6 (rx, tx, both) */
|
||||
u8 *dir_enabled4;
|
||||
u8 *dir_enabled6;
|
||||
|
||||
/* API message ID base */
|
||||
u16 msg_id_base;
|
||||
} mssc_main_t;
|
||||
|
||||
extern mssc_main_t mssc_main;
|
||||
|
||||
#define MSS_CLAMP_UNSET 0xffff
|
||||
|
||||
#endif /* __included_mss_clamp_h__ */
|
||||
|
||||
/*
|
||||
* fd.io coding-style-patch-verification: ON
|
||||
*
|
||||
* Local Variables:
|
||||
* eval: (c-set-style "gnu")
|
||||
* End:
|
||||
*/
|
||||
@@ -0,0 +1,136 @@
|
||||
/*
|
||||
* mss_clamp_api.c - TCP MSS clamping plug-in
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <vnet/vnet.h>
|
||||
#include <vnet/plugin/plugin.h> /* VLIB_PLUGIN_REGISTER */
|
||||
#include <mss_clamp/mss_clamp.h>
|
||||
#include <mss_clamp/mss_clamp.api_enum.h>
|
||||
#include <mss_clamp/mss_clamp.api_types.h>
|
||||
#include <vlibapi/api.h>
|
||||
#include <vlibmemory/api.h>
|
||||
#include <vpp/app/version.h> /* VPP_BUILD_VER */
|
||||
|
||||
#define REPLY_MSG_ID_BASE cm->msg_id_base
|
||||
#include <vlibapi/api_helper_macros.h>
|
||||
|
||||
/* API message handler */
|
||||
static void
|
||||
vl_api_mss_clamp_enable_disable_t_handler (
|
||||
vl_api_mss_clamp_enable_disable_t *mp)
|
||||
{
|
||||
mssc_main_t *cm = &mssc_main;
|
||||
vl_api_mss_clamp_enable_disable_reply_t *rmp;
|
||||
int rv;
|
||||
|
||||
VALIDATE_SW_IF_INDEX (mp);
|
||||
|
||||
rv = mssc_enable_disable (ntohl (mp->sw_if_index), mp->ipv4_direction,
|
||||
mp->ipv6_direction, ntohs (mp->ipv4_mss),
|
||||
ntohs (mp->ipv6_mss));
|
||||
|
||||
BAD_SW_IF_INDEX_LABEL;
|
||||
REPLY_MACRO (VL_API_MSS_CLAMP_ENABLE_DISABLE_REPLY);
|
||||
}
|
||||
|
||||
static void
|
||||
send_mss_clamp_details (u32 sw_if_index, vl_api_registration_t *rp,
|
||||
u32 context)
|
||||
{
|
||||
mssc_main_t *cm = &mssc_main;
|
||||
vl_api_mss_clamp_details_t *rmp;
|
||||
u16 mss4, mss6;
|
||||
u8 dir4, dir6;
|
||||
int rv;
|
||||
|
||||
mss4 = mss6 = 0;
|
||||
dir4 = dir6 = MSS_CLAMP_DIR_NONE;
|
||||
rv = mssc_get_mss (sw_if_index, &dir4, &dir6, &mss4, &mss6);
|
||||
if (rv == VNET_API_ERROR_FEATURE_DISABLED)
|
||||
return;
|
||||
|
||||
REPLY_MACRO_DETAILS4 (VL_API_MSS_CLAMP_DETAILS, rp, context, ({
|
||||
rmp->sw_if_index = htonl (sw_if_index);
|
||||
rmp->ipv4_mss = htons (mss4);
|
||||
rmp->ipv6_mss = htons (mss6);
|
||||
rmp->ipv4_direction = dir4;
|
||||
rmp->ipv6_direction = dir6;
|
||||
}));
|
||||
}
|
||||
|
||||
static void
|
||||
vl_api_mss_clamp_get_t_handler (vl_api_mss_clamp_get_t *mp)
|
||||
{
|
||||
mssc_main_t *cm = &mssc_main;
|
||||
vl_api_mss_clamp_get_reply_t *rmp;
|
||||
int rv = 0;
|
||||
u32 sw_if_index = ntohl (mp->sw_if_index);
|
||||
vl_api_registration_t *reg;
|
||||
|
||||
reg = vl_api_client_index_to_registration (mp->client_index);
|
||||
if (!reg)
|
||||
return;
|
||||
|
||||
if (sw_if_index == ~0)
|
||||
{
|
||||
if (vec_len (cm->dir_enabled4) == 0)
|
||||
{
|
||||
REPLY_MACRO2 (VL_API_MSS_CLAMP_GET_REPLY, ({ rmp->cursor = ~0; }));
|
||||
return;
|
||||
}
|
||||
|
||||
REPLY_AND_DETAILS_MACRO (
|
||||
VL_API_MSS_CLAMP_GET_REPLY, cm->dir_enabled4,
|
||||
({ send_mss_clamp_details (cursor, reg, mp->context); }));
|
||||
}
|
||||
else
|
||||
{
|
||||
VALIDATE_SW_IF_INDEX (mp);
|
||||
send_mss_clamp_details (sw_if_index, reg, mp->context);
|
||||
|
||||
BAD_SW_IF_INDEX_LABEL;
|
||||
REPLY_MACRO2 (VL_API_MSS_CLAMP_GET_REPLY, ({ rmp->cursor = ~0; }));
|
||||
}
|
||||
}
|
||||
|
||||
/* API definitions */
|
||||
#include <vnet/format_fns.h>
|
||||
#include <mss_clamp/mss_clamp.api.c>
|
||||
|
||||
/* Set up the API message handling tables */
|
||||
static clib_error_t *
|
||||
mssc_api_hookup (vlib_main_t *vm)
|
||||
{
|
||||
mssc_main_t *cm = &mssc_main;
|
||||
|
||||
cm->msg_id_base = setup_message_id_table ();
|
||||
return 0;
|
||||
}
|
||||
|
||||
VLIB_API_INIT_FUNCTION (mssc_api_hookup);
|
||||
|
||||
VLIB_PLUGIN_REGISTER () = {
|
||||
.version = VPP_BUILD_VER,
|
||||
.description = "TCP MSS clamping plugin",
|
||||
};
|
||||
|
||||
/*
|
||||
* 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
@@ -0,0 +1,295 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import unittest
|
||||
|
||||
from framework import VppTestCase, VppTestRunner
|
||||
|
||||
from scapy.layers.inet import IP, TCP
|
||||
from scapy.layers.inet6 import IPv6
|
||||
from scapy.layers.l2 import Ether
|
||||
from scapy.packet import Raw
|
||||
|
||||
|
||||
class TestMSSClamp(VppTestCase):
|
||||
""" TCP MSS Clamping Test Case """
|
||||
|
||||
def setUp(self):
|
||||
super(TestMSSClamp, self).setUp()
|
||||
|
||||
# create 2 pg interfaces
|
||||
self.create_pg_interfaces(range(2))
|
||||
|
||||
for i in self.pg_interfaces:
|
||||
i.admin_up()
|
||||
i.config_ip4()
|
||||
i.resolve_arp()
|
||||
i.config_ip6()
|
||||
i.resolve_ndp()
|
||||
|
||||
def tearDown(self):
|
||||
for i in self.pg_interfaces:
|
||||
i.unconfig_ip4()
|
||||
i.unconfig_ip6()
|
||||
i.admin_down()
|
||||
super(TestMSSClamp, self).tearDown()
|
||||
|
||||
def verify_pkt(self, rx, expected_mss):
|
||||
# check that the MSS size equals the expected value
|
||||
# and the IP and TCP checksums are correct
|
||||
tcp = rx[TCP]
|
||||
tcp_csum = tcp.chksum
|
||||
del tcp.chksum
|
||||
ip_csum = 0
|
||||
if (rx.haslayer(IP)):
|
||||
ip_csum = rx[IP].chksum
|
||||
del rx[IP].chksum
|
||||
|
||||
opt = tcp.options
|
||||
self.assertEqual(opt[0][0], 'MSS')
|
||||
self.assertEqual(opt[0][1], expected_mss)
|
||||
# recalculate checksums
|
||||
rx = rx.__class__(bytes(rx))
|
||||
tcp = rx[TCP]
|
||||
self.assertEqual(tcp_csum, tcp.chksum)
|
||||
if (rx.haslayer(IP)):
|
||||
self.assertEqual(ip_csum, rx[IP].chksum)
|
||||
|
||||
def send_and_verify_ip4(self, src_pg, dst_pg, mss, expected_mss):
|
||||
# IPv4 TCP packet with the requested MSS option.
|
||||
# from a host on src_pg to a host on dst_pg.
|
||||
p = (Ether(dst=src_pg.local_mac,
|
||||
src=src_pg.remote_mac) /
|
||||
IP(src=src_pg.remote_ip4,
|
||||
dst=dst_pg.remote_ip4) /
|
||||
TCP(sport=1234, dport=1234,
|
||||
flags="S",
|
||||
options=[('MSS', (mss)), ('EOL', None)]) /
|
||||
Raw('\xa5' * 100))
|
||||
|
||||
rxs = self.send_and_expect(src_pg, p * 65, dst_pg)
|
||||
|
||||
for rx in rxs:
|
||||
self.verify_pkt(rx, expected_mss)
|
||||
|
||||
def send_and_verify_ip6(self, src_pg, dst_pg, mss, expected_mss):
|
||||
#
|
||||
# IPv6 TCP packet with the requested MSS option.
|
||||
# from a host on src_pg to a host on dst_pg.
|
||||
#
|
||||
p = (Ether(dst=src_pg.local_mac,
|
||||
src=src_pg.remote_mac) /
|
||||
IPv6(src=src_pg.remote_ip6,
|
||||
dst=dst_pg.remote_ip6) /
|
||||
TCP(sport=1234, dport=1234,
|
||||
flags="S",
|
||||
options=[('MSS', (mss)), ('EOL', None)]) /
|
||||
Raw('\xa5' * 100))
|
||||
|
||||
rxs = self.send_and_expect(src_pg, p * 65, dst_pg)
|
||||
|
||||
for rx in rxs:
|
||||
self.verify_pkt(rx, expected_mss)
|
||||
|
||||
def test_tcp_mss_clamping_ip4_tx(self):
|
||||
""" IP4 TCP MSS Clamping TX """
|
||||
|
||||
# enable the TCP MSS clamping feature to lower the MSS to 1424.
|
||||
self.vapi.mss_clamp_enable_disable(self.pg1.sw_if_index,
|
||||
ipv4_mss=1424, ipv6_mss=0,
|
||||
ipv4_direction=3, ipv6_direction=0)
|
||||
|
||||
# Verify that the feature is enabled.
|
||||
rv, reply = self.vapi.mss_clamp_get(sw_if_index=self.pg1.sw_if_index)
|
||||
self.assertEqual(reply[0].ipv4_mss, 1424)
|
||||
self.assertEqual(reply[0].ipv4_direction, 3)
|
||||
|
||||
# Send syn packets and verify that the MSS value is lowered.
|
||||
self.send_and_verify_ip4(self.pg0, self.pg1, 1460, 1424)
|
||||
|
||||
# check the stats
|
||||
stats = self.statistics.get_counter(
|
||||
'/err/tcp-mss-clamping-ip4-out/clamped')
|
||||
self.assertEqual(sum(stats), 65)
|
||||
|
||||
# Send syn packets with small enough MSS values and verify they are
|
||||
# unchanged.
|
||||
self.send_and_verify_ip4(self.pg0, self.pg1, 1400, 1400)
|
||||
|
||||
# enable the the feature only in TX direction
|
||||
# and change the max MSS value
|
||||
self.vapi.mss_clamp_enable_disable(self.pg1.sw_if_index,
|
||||
ipv4_mss=1420, ipv6_mss=0,
|
||||
ipv4_direction=2, ipv6_direction=0)
|
||||
|
||||
# Send syn packets and verify that the MSS value is lowered.
|
||||
self.send_and_verify_ip4(self.pg0, self.pg1, 1460, 1420)
|
||||
|
||||
# enable the the feature only in RX direction
|
||||
self.vapi.mss_clamp_enable_disable(self.pg1.sw_if_index,
|
||||
ipv4_mss=1424, ipv6_mss=0,
|
||||
ipv4_direction=1, ipv6_direction=0)
|
||||
|
||||
# Send the packets again and ensure they are unchanged.
|
||||
self.send_and_verify_ip4(self.pg0, self.pg1, 1460, 1460)
|
||||
|
||||
# disable the feature
|
||||
self.vapi.mss_clamp_enable_disable(self.pg1.sw_if_index,
|
||||
ipv4_mss=0, ipv6_mss=0,
|
||||
ipv4_direction=0, ipv6_direction=0)
|
||||
|
||||
# Send the packets again and ensure they are unchanged.
|
||||
self.send_and_verify_ip4(self.pg0, self.pg1, 1460, 1460)
|
||||
|
||||
def test_tcp_mss_clamping_ip4_rx(self):
|
||||
""" IP4 TCP MSS Clamping RX """
|
||||
|
||||
# enable the TCP MSS clamping feature to lower the MSS to 1424.
|
||||
self.vapi.mss_clamp_enable_disable(self.pg1.sw_if_index,
|
||||
ipv4_mss=1424, ipv6_mss=0,
|
||||
ipv4_direction=3, ipv6_direction=0)
|
||||
|
||||
# Verify that the feature is enabled.
|
||||
rv, reply = self.vapi.mss_clamp_get(sw_if_index=self.pg1.sw_if_index)
|
||||
self.assertEqual(reply[0].ipv4_mss, 1424)
|
||||
self.assertEqual(reply[0].ipv4_direction, 3)
|
||||
|
||||
# Send syn packets and verify that the MSS value is lowered.
|
||||
self.send_and_verify_ip4(self.pg1, self.pg0, 1460, 1424)
|
||||
|
||||
# check the stats
|
||||
stats = self.statistics.get_counter(
|
||||
'/err/tcp-mss-clamping-ip4-in/clamped')
|
||||
self.assertEqual(sum(stats), 65)
|
||||
|
||||
# Send syn packets with small enough MSS values and verify they are
|
||||
# unchanged.
|
||||
self.send_and_verify_ip4(self.pg1, self.pg0, 1400, 1400)
|
||||
|
||||
# enable the the feature only in RX direction
|
||||
# and change the max MSS value
|
||||
self.vapi.mss_clamp_enable_disable(self.pg1.sw_if_index,
|
||||
ipv4_mss=1420, ipv6_mss=0,
|
||||
ipv4_direction=1, ipv6_direction=0)
|
||||
|
||||
# Send syn packets and verify that the MSS value is lowered.
|
||||
self.send_and_verify_ip4(self.pg1, self.pg0, 1460, 1420)
|
||||
|
||||
# enable the the feature only in TX direction
|
||||
self.vapi.mss_clamp_enable_disable(self.pg1.sw_if_index,
|
||||
ipv4_mss=1424, ipv6_mss=0,
|
||||
ipv4_direction=2, ipv6_direction=0)
|
||||
|
||||
# Send the packets again and ensure they are unchanged.
|
||||
self.send_and_verify_ip4(self.pg1, self.pg0, 1460, 1460)
|
||||
|
||||
# disable the feature
|
||||
self.vapi.mss_clamp_enable_disable(self.pg1.sw_if_index,
|
||||
ipv4_mss=0, ipv6_mss=0,
|
||||
ipv4_direction=0, ipv6_direction=0)
|
||||
|
||||
# Send the packets again and ensure they are unchanged.
|
||||
self.send_and_verify_ip4(self.pg1, self.pg0, 1460, 1460)
|
||||
|
||||
def test_tcp_mss_clamping_ip6_tx(self):
|
||||
""" IP6 TCP MSS Clamping TX """
|
||||
|
||||
# enable the TCP MSS clamping feature to lower the MSS to 1424.
|
||||
self.vapi.mss_clamp_enable_disable(self.pg1.sw_if_index,
|
||||
ipv4_mss=0, ipv6_mss=1424,
|
||||
ipv4_direction=0, ipv6_direction=3)
|
||||
|
||||
# Verify that the feature is enabled.
|
||||
rv, reply = self.vapi.mss_clamp_get(sw_if_index=self.pg1.sw_if_index)
|
||||
self.assertEqual(reply[0].ipv6_mss, 1424)
|
||||
self.assertEqual(reply[0].ipv6_direction, 3)
|
||||
|
||||
# Send syn packets and verify that the MSS value is lowered.
|
||||
self.send_and_verify_ip6(self.pg0, self.pg1, 1460, 1424)
|
||||
|
||||
# check the stats
|
||||
stats = self.statistics.get_counter(
|
||||
'/err/tcp-mss-clamping-ip6-out/clamped')
|
||||
self.assertEqual(sum(stats), 65)
|
||||
|
||||
# Send syn packets with small enough MSS values and verify they are
|
||||
# unchanged.
|
||||
self.send_and_verify_ip6(self.pg0, self.pg1, 1400, 1400)
|
||||
|
||||
# enable the the feature only in TX direction
|
||||
# and change the max MSS value
|
||||
self.vapi.mss_clamp_enable_disable(self.pg1.sw_if_index,
|
||||
ipv4_mss=0, ipv6_mss=1420,
|
||||
ipv4_direction=0, ipv6_direction=2)
|
||||
|
||||
# Send syn packets and verify that the MSS value is lowered.
|
||||
self.send_and_verify_ip6(self.pg0, self.pg1, 1460, 1420)
|
||||
|
||||
# enable the the feature only in RX direction
|
||||
self.vapi.mss_clamp_enable_disable(self.pg1.sw_if_index,
|
||||
ipv4_mss=0, ipv6_mss=1424,
|
||||
ipv4_direction=0, ipv6_direction=1)
|
||||
|
||||
# Send the packets again and ensure they are unchanged.
|
||||
self.send_and_verify_ip6(self.pg0, self.pg1, 1460, 1460)
|
||||
|
||||
# disable the feature
|
||||
self.vapi.mss_clamp_enable_disable(self.pg1.sw_if_index,
|
||||
ipv4_mss=0, ipv6_mss=0,
|
||||
ipv4_direction=0, ipv6_direction=0)
|
||||
|
||||
# Send the packets again and ensure they are unchanged.
|
||||
self.send_and_verify_ip6(self.pg0, self.pg1, 1460, 1460)
|
||||
|
||||
def test_tcp_mss_clamping_ip6_rx(self):
|
||||
""" IP6 TCP MSS Clamping RX """
|
||||
|
||||
# enable the TCP MSS clamping feature to lower the MSS to 1424.
|
||||
self.vapi.mss_clamp_enable_disable(self.pg1.sw_if_index,
|
||||
ipv4_mss=0, ipv6_mss=1424,
|
||||
ipv4_direction=0, ipv6_direction=3)
|
||||
|
||||
# Verify that the feature is enabled.
|
||||
rv, reply = self.vapi.mss_clamp_get(sw_if_index=self.pg1.sw_if_index)
|
||||
self.assertEqual(reply[0].ipv6_mss, 1424)
|
||||
self.assertEqual(reply[0].ipv6_direction, 3)
|
||||
|
||||
# Send syn packets and verify that the MSS value is lowered.
|
||||
self.send_and_verify_ip6(self.pg1, self.pg0, 1460, 1424)
|
||||
|
||||
# check the stats
|
||||
stats = self.statistics.get_counter(
|
||||
'/err/tcp-mss-clamping-ip6-in/clamped')
|
||||
self.assertEqual(sum(stats), 65)
|
||||
|
||||
# Send syn packets with small enough MSS values and verify they are
|
||||
# unchanged.
|
||||
self.send_and_verify_ip6(self.pg1, self.pg0, 1400, 1400)
|
||||
|
||||
# enable the the feature only in RX direction
|
||||
# and change the max MSS value
|
||||
self.vapi.mss_clamp_enable_disable(self.pg1.sw_if_index,
|
||||
ipv4_mss=0, ipv6_mss=1420,
|
||||
ipv4_direction=0, ipv6_direction=1)
|
||||
|
||||
# Send syn packets and verify that the MSS value is lowered.
|
||||
self.send_and_verify_ip6(self.pg1, self.pg0, 1460, 1420)
|
||||
|
||||
# enable the the feature only in TX direction
|
||||
self.vapi.mss_clamp_enable_disable(self.pg1.sw_if_index,
|
||||
ipv4_mss=0, ipv6_mss=1424,
|
||||
ipv4_direction=0, ipv6_direction=2)
|
||||
|
||||
# Send the packets again and ensure they are unchanged.
|
||||
self.send_and_verify_ip6(self.pg1, self.pg0, 1460, 1460)
|
||||
|
||||
# disable the feature
|
||||
self.vapi.mss_clamp_enable_disable(self.pg1.sw_if_index,
|
||||
ipv4_mss=0, ipv6_mss=0,
|
||||
ipv4_direction=0, ipv6_direction=0)
|
||||
|
||||
# Send the packets again and ensure they are unchanged.
|
||||
self.send_and_verify_ip6(self.pg1, self.pg0, 1460, 1460)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main(testRunner=VppTestRunner)
|
||||
Reference in New Issue
Block a user