LCOV - code coverage report
Current view: top level - plugins/mss_clamp - mss_clamp.c (source / functions) Hit Total Coverage
Test: coverage-filtered.info Lines: 56 123 45.5 %
Date: 2023-07-05 22:20:52 Functions: 10 14 71.4 %

          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             :  */

Generated by: LCOV version 1.14