summaryrefslogtreecommitdiffstats
path: root/extras
AgeCommit message (Expand)AuthorFilesLines
2017-08-11Add VPP Communications Library (VCL)Dave Wallace3-0/+27
2017-08-08Create source rpm.Thomas F Herbert2-5/+21
2017-07-27Use relative path to vpp.service.Thomas F Herbert1-1/+1
2017-07-12Decrease steps necessary to upgrading RPM packages fixedKristina Nevolnikova1-16/+22
2017-07-05VPP-900: VPP is released under the Apache 2.0 License (ASL 2.0). Update RPM s...Billy McFall1-1/+1
2017-06-02Add debian 8 support in extras/vagrant/build.shkhers1-0/+9
2017-05-29Relocate Coverity scriptsChris Luke2-0/+106
2017-05-20Restore possibility to build vpp in debug mode for rpmsIgor Mikhailov (imichail)1-2/+6
2017-04-26Move scripts to extras/Damjan Marion3-0/+133
2017-04-24Move emacs stuff to extras/Damjan Marion26-0/+3250
2017-04-20Move vagrant stuff to extras/Damjan Marion10-0/+401
2017-04-19Fix "make dist" to include version number, docouple it from rpm packagingDamjan Marion3-0/+343
'>237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 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:
 */