Line data Source code
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 :
23 : mssc_main_t mssc_main;
24 :
25 : /* Action function shared between message handler and debug CLI */
26 :
27 : static void
28 32 : mssc_enable_disable_feat (u32 sw_if_index, u8 dir4, u8 dir6, int enable)
29 : {
30 32 : if (dir4 == MSS_CLAMP_DIR_NONE && dir6 == MSS_CLAMP_DIR_NONE)
31 12 : return;
32 :
33 : // ip4
34 20 : if ((dir4 & MSS_CLAMP_DIR_RX) != MSS_CLAMP_DIR_NONE)
35 6 : vnet_feature_enable_disable ("ip4-unicast", "tcp-mss-clamping-ip4-in",
36 : sw_if_index, enable, 0, 0);
37 20 : if ((dir4 & MSS_CLAMP_DIR_TX) != MSS_CLAMP_DIR_NONE)
38 6 : vnet_feature_enable_disable ("ip4-output", "tcp-mss-clamping-ip4-out",
39 : sw_if_index, enable, 0, 0);
40 : // ip6
41 20 : if ((dir6 & MSS_CLAMP_DIR_RX) != MSS_CLAMP_DIR_NONE)
42 6 : vnet_feature_enable_disable ("ip6-unicast", "tcp-mss-clamping-ip6-in",
43 : sw_if_index, enable, 0, 0);
44 20 : if ((dir6 & MSS_CLAMP_DIR_TX) != MSS_CLAMP_DIR_NONE)
45 6 : vnet_feature_enable_disable ("ip6-output", "tcp-mss-clamping-ip6-out",
46 : sw_if_index, enable, 0, 0);
47 : }
48 :
49 : int
50 16 : mssc_enable_disable (u32 sw_if_index, u8 dir4, u8 dir6, u16 mss4, u16 mss6)
51 : {
52 16 : mssc_main_t *cm = &mssc_main;
53 : u8 *dir_enabled4, *dir_enabled6;
54 16 : int rv = 0;
55 :
56 16 : if (dir4 == MSS_CLAMP_DIR_NONE)
57 10 : mss4 = MSS_CLAMP_UNSET;
58 16 : if (dir6 == MSS_CLAMP_DIR_NONE)
59 10 : mss6 = MSS_CLAMP_UNSET;
60 :
61 19 : vec_validate_init_empty (cm->dir_enabled4, sw_if_index, MSS_CLAMP_DIR_NONE);
62 19 : vec_validate_init_empty (cm->dir_enabled6, sw_if_index, MSS_CLAMP_DIR_NONE);
63 19 : vec_validate_init_empty (cm->max_mss4, sw_if_index, MSS_CLAMP_UNSET);
64 19 : vec_validate_init_empty (cm->max_mss6, sw_if_index, MSS_CLAMP_UNSET);
65 :
66 16 : cm->max_mss4[sw_if_index] = mss4;
67 16 : cm->max_mss6[sw_if_index] = mss6;
68 16 : dir_enabled4 = &cm->dir_enabled4[sw_if_index];
69 16 : dir_enabled6 = &cm->dir_enabled6[sw_if_index];
70 :
71 : // Disable the directions that are no longer needed
72 16 : mssc_enable_disable_feat (sw_if_index, (*dir_enabled4) & ~dir4,
73 16 : (*dir_enabled6) & ~dir6, 0);
74 : // Enable the new directions
75 16 : mssc_enable_disable_feat (sw_if_index, ~(*dir_enabled4) & dir4,
76 16 : ~(*dir_enabled6) & dir6, 1);
77 :
78 16 : *dir_enabled4 = dir4;
79 16 : *dir_enabled6 = dir6;
80 :
81 16 : return rv;
82 : }
83 :
84 : int
85 4 : mssc_get_mss (u32 sw_if_index, u8 *dir4, u8 *dir6, u16 *mss4, u16 *mss6)
86 : {
87 4 : mssc_main_t *cm = &mssc_main;
88 4 : int rv = VNET_API_ERROR_FEATURE_DISABLED;
89 :
90 4 : if (vec_len (cm->dir_enabled4) > sw_if_index &&
91 4 : MSS_CLAMP_DIR_NONE != cm->dir_enabled4[sw_if_index])
92 : {
93 2 : *mss4 = cm->max_mss4[sw_if_index];
94 2 : *dir4 = cm->dir_enabled4[sw_if_index];
95 2 : rv = 0;
96 : }
97 : else
98 : {
99 2 : *mss4 = MSS_CLAMP_DIR_NONE;
100 2 : *dir4 = 0;
101 : }
102 :
103 4 : if (vec_len (cm->dir_enabled6) > sw_if_index &&
104 4 : MSS_CLAMP_DIR_NONE != cm->dir_enabled6[sw_if_index])
105 : {
106 2 : *mss6 = cm->max_mss6[sw_if_index];
107 2 : *dir6 = cm->dir_enabled6[sw_if_index];
108 2 : rv = 0;
109 : }
110 : else
111 : {
112 2 : *mss6 = MSS_CLAMP_DIR_NONE;
113 2 : *dir6 = 0;
114 : }
115 4 : return rv;
116 : }
117 :
118 : static uword
119 0 : unformat_mssc_dir (unformat_input_t *input, va_list *args)
120 : {
121 0 : u8 *result = va_arg (*args, u8 *);
122 0 : u8 dir = MSS_CLAMP_DIR_RX | MSS_CLAMP_DIR_TX;
123 :
124 0 : if (unformat (input, "disable"))
125 0 : dir = MSS_CLAMP_DIR_NONE;
126 0 : else if (unformat (input, "enable"))
127 0 : dir = MSS_CLAMP_DIR_RX | MSS_CLAMP_DIR_TX;
128 0 : else if (unformat (input, "rx"))
129 0 : dir = MSS_CLAMP_DIR_RX;
130 0 : else if (unformat (input, "tx"))
131 0 : dir = MSS_CLAMP_DIR_TX;
132 : else
133 0 : return 0;
134 :
135 0 : *result = dir;
136 0 : return 1;
137 : }
138 :
139 : static clib_error_t *
140 0 : mssc_enable_command_fn (vlib_main_t *vm, unformat_input_t *input,
141 : vlib_cli_command_t *cmd)
142 : {
143 0 : u32 sw_if_index = ~0;
144 0 : u8 dir4 = ~0, dir6 = ~0;
145 0 : u32 mss4 = ~0, mss6 = ~0;
146 : int rv;
147 :
148 0 : while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
149 : {
150 0 : if (unformat (input, "ip4 %U", unformat_mssc_dir, &dir4))
151 : ;
152 0 : else if (unformat (input, "ip6 %U", unformat_mssc_dir, &dir6))
153 : ;
154 0 : else if (unformat (input, "ip4-mss %d", &mss4))
155 : ;
156 0 : else if (unformat (input, "ip6-mss %d", &mss6))
157 : ;
158 0 : else if (unformat (input, "%U", unformat_vnet_sw_interface,
159 : vnet_get_main (), &sw_if_index))
160 : ;
161 : else
162 0 : break;
163 : }
164 :
165 0 : if (sw_if_index == ~0)
166 0 : return clib_error_return (0, "Please specify an interface");
167 :
168 0 : if (dir4 == (u8) ~0 || dir6 == (u8) ~0)
169 0 : return clib_error_return (
170 : 0, "Please specify the MSS clamping direction for ip4 and ip6");
171 :
172 0 : if (dir4 != MSS_CLAMP_DIR_NONE)
173 : {
174 0 : if (mss4 == ~0)
175 0 : return clib_error_return (
176 : 0, "Please specify the Max Segment Size for ip4");
177 0 : if (mss4 >= MSS_CLAMP_UNSET)
178 0 : return clib_error_return (0, "Invalid Max Segment Size");
179 : }
180 0 : if (dir6 != MSS_CLAMP_DIR_NONE)
181 : {
182 0 : if (mss6 == ~0)
183 0 : return clib_error_return (
184 : 0, "Please specify the Max Segment Size for ip6");
185 0 : if (mss6 >= MSS_CLAMP_UNSET)
186 0 : return clib_error_return (0, "Invalid Max Segment Size");
187 : }
188 :
189 0 : rv = mssc_enable_disable (sw_if_index, dir4, dir6, mss4, mss6);
190 :
191 0 : if (rv)
192 0 : return clib_error_return (0, "Failed: %d = %U", rv, format_vnet_api_errno,
193 : rv);
194 :
195 0 : return (NULL);
196 : }
197 :
198 99829 : 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 0 : format_mssc_clamping (u8 *s, va_list *args)
208 : {
209 0 : u8 dir = va_arg (*args, u32);
210 0 : 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 0 : if (MSS_CLAMP_DIR_NONE == dir)
217 : {
218 0 : return format (s, "disabled");
219 : }
220 0 : u32 mss_u32 = mss;
221 0 : return format (s, "%d%s", mss_u32, DIR2S (dir));
222 : }
223 :
224 : static clib_error_t *
225 0 : mssc_show_command_fn (vlib_main_t *vm, unformat_input_t *input,
226 : vlib_cli_command_t *cmd)
227 : {
228 0 : mssc_main_t *cm = &mssc_main;
229 0 : u32 sw_if_index = ~0;
230 : u32 ii;
231 :
232 0 : while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
233 : {
234 0 : if (unformat (input, "%U", unformat_vnet_sw_interface, vnet_get_main (),
235 : &sw_if_index))
236 : ;
237 : else
238 0 : break;
239 : }
240 :
241 0 : if (sw_if_index == ~0)
242 : {
243 0 : vec_foreach_index (ii, cm->dir_enabled4)
244 : {
245 0 : u8 dir4 = cm->dir_enabled4[ii];
246 0 : u8 dir6 = cm->dir_enabled6[ii];
247 0 : if (MSS_CLAMP_DIR_NONE != dir4 || MSS_CLAMP_DIR_NONE != dir6)
248 : {
249 0 : u16 mss4 = cm->max_mss4[ii];
250 0 : u16 mss6 = cm->max_mss6[ii];
251 0 : 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);
255 : }
256 : }
257 : }
258 : else
259 : {
260 : u16 mss4, mss6;
261 : u8 dir4, dir6;
262 0 : mssc_get_mss (sw_if_index, &dir4, &dir6, &mss4, &mss6);
263 0 : 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 0 : return (NULL);
269 : }
270 :
271 99829 : 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 *
279 559 : mssc_init (vlib_main_t *vm)
280 : {
281 559 : return NULL;
282 : }
283 :
284 1119 : VLIB_INIT_FUNCTION (mssc_init);
285 :
286 : /*
287 : * fd.io coding-style-patch-verification: ON
288 : *
289 : * Local Variables:
290 : * eval: (c-set-style "gnu")
291 : * End:
292 : */
|