FD.io VPP  v21.06
Vector Packet Processing
mss_clamp.c
Go to the documentation of this file.
1 /*
2  * mss_clamp.c - TCP MSS clamping plug-in
3  *
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:
8  *
9  * http://www.apache.org/licenses/LICENSE-2.0
10  *
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.
16  */
17 
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>
22 
24 
25 /* Action function shared between message handler and debug CLI */
26 
27 static void
28 mssc_enable_disable_feat (u32 sw_if_index, u8 dir4, u8 dir6, int enable)
29 {
30  if (dir4 == MSS_CLAMP_DIR_NONE && dir6 == MSS_CLAMP_DIR_NONE)
31  return;
32 
33  // ip4
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);
40  // ip6
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);
47 }
48 
49 int
50 mssc_enable_disable (u32 sw_if_index, u8 dir4, u8 dir6, u16 mss4, u16 mss6)
51 {
53  u8 *dir_enabled4, *dir_enabled6;
54  int rv = 0;
55 
56  if (dir4 == MSS_CLAMP_DIR_NONE)
57  mss4 = MSS_CLAMP_UNSET;
58  if (dir6 == MSS_CLAMP_DIR_NONE)
59  mss6 = MSS_CLAMP_UNSET;
60 
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);
65 
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];
70 
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);
77 
78  *dir_enabled4 = dir4;
79  *dir_enabled6 = dir6;
80 
81  return rv;
82 }
83 
84 int
85 mssc_get_mss (u32 sw_if_index, u8 *dir4, u8 *dir6, u16 *mss4, u16 *mss6)
86 {
88  int rv = VNET_API_ERROR_FEATURE_DISABLED;
89 
90  if (vec_len (cm->dir_enabled4) > sw_if_index &&
91  MSS_CLAMP_DIR_NONE != cm->dir_enabled4[sw_if_index])
92  {
93  *mss4 = cm->max_mss4[sw_if_index];
94  *dir4 = cm->dir_enabled4[sw_if_index];
95  rv = 0;
96  }
97  else
98  {
99  *mss4 = MSS_CLAMP_DIR_NONE;
100  *dir4 = 0;
101  }
102 
103  if (vec_len (cm->dir_enabled6) > sw_if_index &&
104  MSS_CLAMP_DIR_NONE != cm->dir_enabled6[sw_if_index])
105  {
106  *mss6 = cm->max_mss6[sw_if_index];
107  *dir6 = cm->dir_enabled6[sw_if_index];
108  rv = 0;
109  }
110  else
111  {
112  *mss6 = MSS_CLAMP_DIR_NONE;
113  *dir6 = 0;
114  }
115  return rv;
116 }
117 
118 static uword
119 unformat_mssc_dir (unformat_input_t *input, va_list *args)
120 {
121  u8 *result = va_arg (*args, u8 *);
123 
124  if (unformat (input, "disable"))
125  dir = MSS_CLAMP_DIR_NONE;
126  else if (unformat (input, "enable"))
128  else if (unformat (input, "rx"))
129  dir = MSS_CLAMP_DIR_RX;
130  else if (unformat (input, "tx"))
131  dir = MSS_CLAMP_DIR_TX;
132  else
133  return 0;
134 
135  *result = dir;
136  return 1;
137 }
138 
139 static clib_error_t *
141  vlib_cli_command_t *cmd)
142 {
143  u32 sw_if_index = ~0;
144  u8 dir4 = ~0, dir6 = ~0;
145  u32 mss4 = ~0, mss6 = ~0;
146  int rv;
147 
149  {
150  if (unformat (input, "ip4 %U", unformat_mssc_dir, &dir4))
151  ;
152  else if (unformat (input, "ip6 %U", unformat_mssc_dir, &dir6))
153  ;
154  else if (unformat (input, "ip4-mss %d", &mss4))
155  ;
156  else if (unformat (input, "ip6-mss %d", &mss6))
157  ;
158  else if (unformat (input, "%U", unformat_vnet_sw_interface,
159  vnet_get_main (), &sw_if_index))
160  ;
161  else
162  break;
163  }
164 
165  if (sw_if_index == ~0)
166  return clib_error_return (0, "Please specify an interface");
167 
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");
171 
172  if (dir4 != MSS_CLAMP_DIR_NONE)
173  {
174  if (mss4 == ~0)
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");
179  }
180  if (dir6 != MSS_CLAMP_DIR_NONE)
181  {
182  if (mss6 == ~0)
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");
187  }
188 
189  rv = mssc_enable_disable (sw_if_index, dir4, dir6, mss4, mss6);
190 
191  if (rv)
192  return clib_error_return (0, "Failed: %d = %U", rv, format_vnet_api_errno,
193  rv);
194 
195  return (NULL);
196 }
197 
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,
204 };
205 
206 static u8 *
207 format_mssc_clamping (u8 *s, va_list *args)
208 {
209  u8 dir = va_arg (*args, u32);
210  u16 mss = va_arg (*args, u32);
211 #define DIR2S(d) \
212  (((d) == (MSS_CLAMP_DIR_RX | MSS_CLAMP_DIR_TX)) ? \
213  "" : \
214  (((d) == MSS_CLAMP_DIR_RX) ? " [RX]" : " [TX]"))
215 
216  if (MSS_CLAMP_DIR_NONE == dir)
217  {
218  return format (s, "disabled");
219  }
220  u32 mss_u32 = mss;
221  return format (s, "%d%s", mss_u32, DIR2S (dir));
222 }
223 
224 static clib_error_t *
226  vlib_cli_command_t *cmd)
227 {
229  u32 sw_if_index = ~0;
230  u32 ii;
231 
233  {
234  if (unformat (input, "%U", unformat_vnet_sw_interface, vnet_get_main (),
235  &sw_if_index))
236  ;
237  else
238  break;
239  }
240 
241  if (sw_if_index == ~0)
242  {
244  {
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)
248  {
249  u16 mss4 = cm->max_mss4[ii];
250  u16 mss6 = cm->max_mss6[ii];
251  vlib_cli_output (vm, "%U: ip4: %U ip6: %U",
253  ii, format_mssc_clamping, dir4, mss4,
254  format_mssc_clamping, dir6, mss6);
255  }
256  }
257  }
258  else
259  {
260  u16 mss4, mss6;
261  u8 dir4, dir6;
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);
266  }
267 
268  return (NULL);
269 }
270 
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,
276 };
277 
278 static clib_error_t *
280 {
281  return NULL;
282 }
283 
285 
286 /*
287  * fd.io coding-style-patch-verification: ON
288  *
289  * Local Variables:
290  * eval: (c-set-style "gnu")
291  * End:
292  */
#define vec_foreach_index(var, v)
Iterate over vector indices.
static void mssc_enable_disable_feat(u32 sw_if_index, u8 dir4, u8 dir6, int enable)
Definition: mss_clamp.c:28
enumflag MSS_CLAMP_DIR_TX
Definition: mss_clamp.api:25
vnet_feature_config_main_t * cm
static clib_error_t * mssc_init(vlib_main_t *vm)
Definition: mss_clamp.c:279
unformat_function_t unformat_vnet_sw_interface
format_function_t format_vnet_sw_if_index_name
unsigned char u8
Definition: types.h:56
unsigned int u32
Definition: types.h:88
int mssc_enable_disable(u32 sw_if_index, u8 dir4, u8 dir6, u16 mss4, u16 mss6)
Definition: mss_clamp.c:50
#define VLIB_INIT_FUNCTION(x)
Definition: init.h:172
description fragment has unexpected format
Definition: map.api:433
#define clib_error_return(e, args...)
Definition: error.h:99
vnet_main_t * vnet_get_main(void)
int __clib_unused rv
Definition: application.c:491
static uword unformat_mssc_dir(unformat_input_t *input, va_list *args)
Definition: mss_clamp.c:119
static clib_error_t * mssc_enable_command_fn(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
Definition: mss_clamp.c:140
vl_api_interface_index_t sw_if_index
Definition: wireguard.api:34
struct _unformat_input_t unformat_input_t
unsigned short u16
Definition: types.h:57
mssc_main_t mssc_main
Definition: mss_clamp.c:23
int vnet_feature_enable_disable(const char *arc_name, const char *node_name, u32 sw_if_index, int enable_disable, void *feature_config, u32 n_feature_config_bytes)
vlib_main_t * vm
X-connect all packets from the HOST to the PHY.
Definition: nat44_ei.c:3047
static u8 * format_vnet_api_errno(u8 *s, va_list *args)
Definition: api_errno.h:172
#define UNFORMAT_END_OF_INPUT
Definition: format.h:137
u8 * dir_enabled6
Definition: mss_clamp.h:37
int mssc_get_mss(u32 sw_if_index, u8 *dir4, u8 *dir6, u16 *mss4, u16 *mss6)
Definition: mss_clamp.c:85
u16 * max_mss6
Definition: mss_clamp.h:33
#define MSS_CLAMP_UNSET
Definition: mss_clamp.h:45
#define VLIB_CLI_COMMAND(x,...)
Definition: cli.h:163
u16 * max_mss4
Definition: mss_clamp.h:32
void vlib_cli_output(vlib_main_t *vm, char *fmt,...)
Definition: cli.c:716
static u8 * format_mssc_clamping(u8 *s, va_list *args)
Definition: mss_clamp.c:207
u8 * dir_enabled4
Definition: mss_clamp.h:36
static clib_error_t * mssc_show_command_fn(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
Definition: mss_clamp.c:225
enumflag MSS_CLAMP_DIR_RX
Definition: mss_clamp.api:24
#define vec_len(v)
Number of elements in vector (rvalue-only, NULL tolerant)
u64 uword
Definition: types.h:112
#define DIR2S(d)
#define vec_validate_init_empty(V, I, INIT)
Make sure vector is long enough for given index and initialize empty space (no header, unspecified alignment)
Definition: vec.h:571
uword unformat(unformat_input_t *i, const char *fmt,...)
Definition: unformat.c:978
static uword unformat_check_input(unformat_input_t *i)
Definition: format.h:163