2 * mss_clamp.c - TCP MSS clamping plug-in
4 * Copyright (c) 2018 Cisco and/or its affiliates
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at:
9 * http://www.apache.org/licenses/LICENSE-2.0
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
18 #include <vnet/vnet.h>
19 #include <vnet/plugin/plugin.h>
20 #include <mss_clamp/mss_clamp.h>
21 #include <mss_clamp/mss_clamp.api_types.h>
23 mssc_main_t mssc_main;
25 /* Action function shared between message handler and debug CLI */
28 mssc_enable_disable_feat (u32 sw_if_index, u8 dir4, u8 dir6, int enable)
30 if (dir4 == MSS_CLAMP_DIR_NONE && dir6 == MSS_CLAMP_DIR_NONE)
34 if ((dir4 & MSS_CLAMP_DIR_RX) != MSS_CLAMP_DIR_NONE)
35 vnet_feature_enable_disable ("ip4-unicast", "tcp-mss-clamping-ip4-in",
36 sw_if_index, enable, 0, 0);
37 if ((dir4 & MSS_CLAMP_DIR_TX) != MSS_CLAMP_DIR_NONE)
38 vnet_feature_enable_disable ("ip4-output", "tcp-mss-clamping-ip4-out",
39 sw_if_index, enable, 0, 0);
41 if ((dir6 & MSS_CLAMP_DIR_RX) != MSS_CLAMP_DIR_NONE)
42 vnet_feature_enable_disable ("ip6-unicast", "tcp-mss-clamping-ip6-in",
43 sw_if_index, enable, 0, 0);
44 if ((dir6 & MSS_CLAMP_DIR_TX) != MSS_CLAMP_DIR_NONE)
45 vnet_feature_enable_disable ("ip6-output", "tcp-mss-clamping-ip6-out",
46 sw_if_index, enable, 0, 0);
50 mssc_enable_disable (u32 sw_if_index, u8 dir4, u8 dir6, u16 mss4, u16 mss6)
52 mssc_main_t *cm = &mssc_main;
53 u8 *dir_enabled4, *dir_enabled6;
56 if (dir4 == MSS_CLAMP_DIR_NONE)
57 mss4 = MSS_CLAMP_UNSET;
58 if (dir6 == MSS_CLAMP_DIR_NONE)
59 mss6 = MSS_CLAMP_UNSET;
61 vec_validate_init_empty (cm->dir_enabled4, sw_if_index, MSS_CLAMP_DIR_NONE);
62 vec_validate_init_empty (cm->dir_enabled6, sw_if_index, MSS_CLAMP_DIR_NONE);
63 vec_validate_init_empty (cm->max_mss4, sw_if_index, MSS_CLAMP_UNSET);
64 vec_validate_init_empty (cm->max_mss6, sw_if_index, MSS_CLAMP_UNSET);
66 cm->max_mss4[sw_if_index] = mss4;
67 cm->max_mss6[sw_if_index] = mss6;
68 dir_enabled4 = &cm->dir_enabled4[sw_if_index];
69 dir_enabled6 = &cm->dir_enabled6[sw_if_index];
71 // Disable the directions that are no longer needed
72 mssc_enable_disable_feat (sw_if_index, (*dir_enabled4) & ~dir4,
73 (*dir_enabled6) & ~dir6, 0);
74 // Enable the new directions
75 mssc_enable_disable_feat (sw_if_index, ~(*dir_enabled4) & dir4,
76 ~(*dir_enabled6) & dir6, 1);
85 mssc_get_mss (u32 sw_if_index, u8 *dir4, u8 *dir6, u16 *mss4, u16 *mss6)
87 mssc_main_t *cm = &mssc_main;
88 int rv = VNET_API_ERROR_FEATURE_DISABLED;
90 if (vec_len (cm->dir_enabled4) > sw_if_index &&
91 MSS_CLAMP_DIR_NONE != cm->dir_enabled4[sw_if_index])
93 *mss4 = cm->max_mss4[sw_if_index];
94 *dir4 = cm->dir_enabled4[sw_if_index];
99 *mss4 = MSS_CLAMP_DIR_NONE;
103 if (vec_len (cm->dir_enabled6) > sw_if_index &&
104 MSS_CLAMP_DIR_NONE != cm->dir_enabled6[sw_if_index])
106 *mss6 = cm->max_mss6[sw_if_index];
107 *dir6 = cm->dir_enabled6[sw_if_index];
112 *mss6 = MSS_CLAMP_DIR_NONE;
119 unformat_mssc_dir (unformat_input_t *input, va_list *args)
121 u8 *result = va_arg (*args, u8 *);
122 u8 dir = MSS_CLAMP_DIR_RX | MSS_CLAMP_DIR_TX;
124 if (unformat (input, "disable"))
125 dir = MSS_CLAMP_DIR_NONE;
126 else if (unformat (input, "enable"))
127 dir = MSS_CLAMP_DIR_RX | MSS_CLAMP_DIR_TX;
128 else if (unformat (input, "rx"))
129 dir = MSS_CLAMP_DIR_RX;
130 else if (unformat (input, "tx"))
131 dir = MSS_CLAMP_DIR_TX;
139 static clib_error_t *
140 mssc_enable_command_fn (vlib_main_t *vm, unformat_input_t *input,
141 vlib_cli_command_t *cmd)
143 u32 sw_if_index = ~0;
144 u8 dir4 = ~0, dir6 = ~0;
145 u32 mss4 = ~0, mss6 = ~0;
148 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
150 if (unformat (input, "ip4 %U", unformat_mssc_dir, &dir4))
152 else if (unformat (input, "ip6 %U", unformat_mssc_dir, &dir6))
154 else if (unformat (input, "ip4-mss %d", &mss4))
156 else if (unformat (input, "ip6-mss %d", &mss6))
158 else if (unformat (input, "%U", unformat_vnet_sw_interface,
159 vnet_get_main (), &sw_if_index))
165 if (sw_if_index == ~0)
166 return clib_error_return (0, "Please specify an interface");
168 if (dir4 == (u8) ~0 || dir6 == (u8) ~0)
169 return clib_error_return (
170 0, "Please specify the MSS clamping direction for ip4 and ip6");
172 if (dir4 != MSS_CLAMP_DIR_NONE)
175 return clib_error_return (
176 0, "Please specify the Max Segment Size for ip4");
177 if (mss4 >= MSS_CLAMP_UNSET)
178 return clib_error_return (0, "Invalid Max Segment Size");
180 if (dir6 != MSS_CLAMP_DIR_NONE)
183 return clib_error_return (
184 0, "Please specify the Max Segment Size for ip6");
185 if (mss6 >= MSS_CLAMP_UNSET)
186 return clib_error_return (0, "Invalid Max Segment Size");
189 rv = mssc_enable_disable (sw_if_index, dir4, dir6, mss4, mss6);
192 return clib_error_return (0, "Failed: %d = %U", rv, format_vnet_api_errno,
198 VLIB_CLI_COMMAND (mssc_enable_disable_command, static) = {
199 .path = "set interface tcp-mss-clamp",
200 .short_help = "set interface tcp-mss-clamp <interface-name> "
201 "ip4 [enable|disable|rx|tx] ip4-mss <size> "
202 "ip6 [enable|disable|rx|tx] ip6-mss <size>",
203 .function = mssc_enable_command_fn,
207 format_mssc_clamping (u8 *s, va_list *args)
209 u8 dir = va_arg (*args, u32);
210 u16 mss = va_arg (*args, u32);
212 (((d) == (MSS_CLAMP_DIR_RX | MSS_CLAMP_DIR_TX)) ? \
214 (((d) == MSS_CLAMP_DIR_RX) ? " [RX]" : " [TX]"))
216 if (MSS_CLAMP_DIR_NONE == dir)
218 return format (s, "disabled");
221 return format (s, "%d%s", mss_u32, DIR2S (dir));
224 static clib_error_t *
225 mssc_show_command_fn (vlib_main_t *vm, unformat_input_t *input,
226 vlib_cli_command_t *cmd)
228 mssc_main_t *cm = &mssc_main;
229 u32 sw_if_index = ~0;
232 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
234 if (unformat (input, "%U", unformat_vnet_sw_interface, vnet_get_main (),
241 if (sw_if_index == ~0)
243 vec_foreach_index (ii, cm->dir_enabled4)
245 u8 dir4 = cm->dir_enabled4[ii];
246 u8 dir6 = cm->dir_enabled6[ii];
247 if (MSS_CLAMP_DIR_NONE != dir4 || MSS_CLAMP_DIR_NONE != dir6)
249 u16 mss4 = cm->max_mss4[ii];
250 u16 mss6 = cm->max_mss6[ii];
251 vlib_cli_output (vm, "%U: ip4: %U ip6: %U",
252 format_vnet_sw_if_index_name, vnet_get_main (),
253 ii, format_mssc_clamping, dir4, mss4,
254 format_mssc_clamping, dir6, mss6);
262 mssc_get_mss (sw_if_index, &dir4, &dir6, &mss4, &mss6);
263 vlib_cli_output (vm, "%U: ip4: %U ip6: %U", format_vnet_sw_if_index_name,
264 vnet_get_main (), sw_if_index, format_mssc_clamping,
265 dir4, mss4, format_mssc_clamping, dir6, mss6);
271 VLIB_CLI_COMMAND (mssc_show_command, static) = {
272 .path = "show interface tcp-mss-clamp",
273 .short_help = "show interface tcp-mss-clamp [interface-name]",
274 .long_help = "show TCP MSS clamping configurations",
275 .function = mssc_show_command_fn,
278 static clib_error_t *
279 mssc_init (vlib_main_t *vm)
284 VLIB_INIT_FUNCTION (mssc_init);
287 * fd.io coding-style-patch-verification: ON
290 * eval: (c-set-style "gnu")