aboutsummaryrefslogtreecommitdiffstats
path: root/src/plugins/perfmon
AgeCommit message (Expand)AuthorFilesLines
2019-05-03plugins: clean up plugin descriptionsDave Wallace1-1/+1
2019-05-01Add node, frame to vlib main loop perf analysis callback argumentsDave Barach1-1/+3
2019-03-26perfmon: fix pmc hw indices out-dated when multiple pmcSu Wang1-3/+15
2019-03-20perfmon: python to C parser for intel CPUsDamjan Marion24-445/+23854
2019-01-27Fix issue with cpu_id and numa_code captured too earlyDamjan Marion1-1/+1
2019-01-27perfmon: collect data on selected thread(s)Dave Barach3-18/+86
2019-01-24perfmon: enable pmc event before reading rdpmc indexDamjan Marion1-6/+6
2019-01-24perfmon plugin: 2-way parallel stat collectionDave Barach3-143/+228
2018-12-17Improve perfmon json table pickerDave Barach4-23/+341
2018-11-14Remove c-11 memcpy checks from perf-critical codeDave Barach1-1/+1
2018-10-25Add x86_64 perfmon tablesDave Barach3-20/+10
2018-10-23VPP-1474: fix coverity warningDave Barach1-0/+3
2018-10-23perfmon.c: Register additional cpuids.Paul Vinciguerra1-4/+7
2018-10-22X86_64 perf counter pluginDave Barach5-0/+1466
6 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351
/*
 * l2_bvi.c : layer 2 Bridged Virtual Interface
 *
 * Copyright (c) 2013 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 <vlib/vlib.h>
#include <vnet/vnet.h>
#include <vnet/l2/l2_fwd.h>
#include <vnet/l2/l2_flood.h>
#include <vnet/l2/l2_bvi.h>

/* Allocated BVI instances */
static uword *l2_bvi_instances;

/* Call the L2 nodes that need the ethertype mapping */
void
l2bvi_register_input_type (vlib_main_t * vm,
			   ethernet_type_t type, u32 node_index)
{
  l2fwd_register_input_type (vm, type, node_index);
  l2flood_register_input_type (vm, type, node_index);
}

static u8 *
format_bvi_name (u8 * s, va_list * args)
{
  u32 dev_instance = va_arg (*args, u32);
  return format (s, "bvi%d", dev_instance);
}

static clib_error_t *
bvi_admin_up_down (vnet_main_t * vnm, u32 hw_if_index, u32 flags)
{
  u32 hw_flags = (flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP) ?
    VNET_HW_INTERFACE_FLAG_LINK_UP : 0;
  vnet_hw_interface_set_flags (vnm, hw_if_index, hw_flags);
  return 0;
}

static clib_error_t *
bvi_mac_change (vnet_hw_interface_t * hi,
		const u8 * old_address, const u8 * mac_address)
{
  l2input_interface_mac_change (hi->sw_if_index, old_address, mac_address);

  return (NULL);
}

/* *INDENT-OFF* */
VNET_DEVICE_CLASS (bvi_device_class) = {
  .name = "BVI",
  .format_device_name = format_bvi_name,
  .admin_up_down_function = bvi_admin_up_down,
  .mac_addr_change_function = bvi_mac_change,
};
/* *INDENT-ON* */

/*
 * Maintain a bitmap of allocated bvi instance numbers.
 */
#define BVI_MAX_INSTANCE		(16 * 1024)

static u32
bvi_instance_alloc (u32 want)
{
  /*
   * Check for dynamically allocated instance number.
   */
  if (~0 == want)
    {
      u32 bit;

      bit = clib_bitmap_first_clear (l2_bvi_instances);
      if (bit >= BVI_MAX_INSTANCE)
	{
	  return ~0;
	}
      l2_bvi_instances = clib_bitmap_set (l2_bvi_instances, bit, 1);
      return bit;
    }

  /*
   * In range?
   */
  if (want >= BVI_MAX_INSTANCE)
    {
      return ~0;
    }

  /*
   * Already in use?
   */
  if (clib_bitmap_get (l2_bvi_instances, want))
    {
      return ~0;
    }

  /*
   * Grant allocation request.
   */
  l2_bvi_instances = clib_bitmap_set (l2_bvi_instances, want, 1);

  return want;
}

static int
bvi_instance_free (u32 instance)
{
  if (instance >= BVI_MAX_INSTANCE)
    {
      return -1;
    }

  if (clib_bitmap_get (l2_bvi_instances, instance) == 0)
    {
      return -1;
    }

  l2_bvi_instances = clib_bitmap_set (l2_bvi_instances, instance, 0);
  return 0;
}

int
l2_bvi_create (u32 user_instance,
	       const mac_address_t * mac_in, u32 * sw_if_indexp)
{
  vnet_main_t *vnm = vnet_get_main ();
  vlib_main_t *vm = vlib_get_main ();
  u32 instance, hw_if_index, slot;
  vnet_hw_interface_t *hw_if;
  clib_error_t *error;
  mac_address_t mac;

  int rv = 0;

  ASSERT (sw_if_indexp);

  *sw_if_indexp = (u32) ~ 0;

  /*
   * Allocate a bvi instance.  Either select on dynamically
   * or try to use the desired user_instance number.
   */
  instance = bvi_instance_alloc (user_instance);
  if (instance == ~0)
    {
      return VNET_API_ERROR_INVALID_REGISTRATION;
    }

  /*
   * Default MAC address (b0b0:0000:0000 + instance) is allocated
   * if zero mac_address is configured. Otherwise, user-configurable MAC
   * address is programmed on the bvi interface.
   */
  if (mac_address_is_zero (mac_in))
    {
      u8 bytes[6] = {
	[0] = 0xb0,
	[1] = 0xb0,
	[5] = instance,
      };
      mac_address_from_bytes (&mac, bytes);
    }
  else
    {
      mac_address_copy (&mac, mac_in);
    }

  error = ethernet_register_interface (vnm,
				       bvi_device_class.index,
				       instance, mac.bytes, &hw_if_index,
				       /* flag change */ 0);

  if (error)
    {
      rv = VNET_API_ERROR_INVALID_REGISTRATION;
      clib_error_report (error);
      return rv;
    }

  hw_if = vnet_get_hw_interface (vnm, hw_if_index);

  slot = vlib_node_add_named_next_with_slot (vm, hw_if->tx_node_index,
					     "l2-input", 0);
  ASSERT (slot == 0);

  {
    vnet_sw_interface_t *si = vnet_get_hw_sw_interface (vnm, hw_if_index);
    *sw_if_indexp = si->sw_if_index;

    si->flood_class = VNET_FLOOD_CLASS_BVI;
  }

  return 0;
}

int
l2_bvi_delete (u32 sw_if_index)
{
  vnet_main_t *vnm = vnet_get_main ();

  if (pool_is_free_index (vnm->interface_main.sw_interfaces, sw_if_index))
    return VNET_API_ERROR_INVALID_SW_IF_INDEX;

  vnet_hw_interface_t *hw = vnet_get_sup_hw_interface (vnm, sw_if_index);
  if (hw == 0 || hw->dev_class_index != bvi_device_class.index)
    return VNET_API_ERROR_INVALID_SW_IF_INDEX;

  if (bvi_instance_free (hw->dev_instance) < 0)
    return VNET_API_ERROR_INVALID_SW_IF_INDEX;

  ethernet_delete_interface (vnm, hw->hw_if_index);

  return 0;
}

static clib_error_t *
l2_bvi_create_cli (vlib_main_t * vm,
		   unformat_input_t * input, vlib_cli_command_t * cmd)
{
  unformat_input_t _line_input, *line_input = &_line_input;
  u32 instance, sw_if_index;
  clib_error_t *error;
  mac_address_t mac;
  int rv;

  error = NULL;
  instance = sw_if_index = ~0;
  mac_address_set_zero (&mac);

  if (unformat_user (input, unformat_line_input, line_input))
    {
      while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
	{
	  if (unformat (line_input, "mac %U", unformat_mac_address_t, &mac))
	    ;
	  else if (unformat (line_input, "instance %d", &instance))
	    ;
	  else
	    {
	      error = clib_error_return (0, "unknown input: %U",
					 format_unformat_error, line_input);
	      break;
	    }
	}

      unformat_free (line_input);

      if (error)
	return error;
    }

  rv = l2_bvi_create (instance, &mac, &sw_if_index);

  if (rv)
    return clib_error_return (0, "BVI create failed");

  vlib_cli_output (vm, "%U\n", format_vnet_sw_if_index_name, vnet_get_main (),
		   sw_if_index);
  return 0;
}

/*?
 * Create a BVI interface. Optionally, a MAC Address can be
 * provided. If not provided, 0b:0b::00:00:00:<instance> will be used.
 *
 * @cliexpar
 * The following two command syntaxes are equivalent:
 * @cliexcmd{bvi create [mac <mac-addr>] [instance <instance>]}
 * Example of how to create a bvi interface:
 * @cliexcmd{bvi create}
?*/
/* *INDENT-OFF* */
VLIB_CLI_COMMAND (l2_bvi_create_command, static) = {
  .path = "bvi create",
  .short_help = "bvi create [mac <mac-addr>] [instance <instance>]",
  .function = l2_bvi_create_cli,
};
/* *INDENT-ON* */

static clib_error_t *
l2_bvi_delete_cli (vlib_main_t * vm,
		   unformat_input_t * input, vlib_cli_command_t * cmd)
{
  vnet_main_t *vnm;
  u32 sw_if_index;
  int rv;

  vnm = vnet_get_main ();
  sw_if_index = ~0;

  while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
    {
      if (unformat
	  (input, "%U", unformat_vnet_sw_interface, vnm, &sw_if_index))
	;
      else
	break;
    }

  if (~0 != sw_if_index)
    {
      rv = l2_bvi_delete (sw_if_index);

      if (rv)
	return clib_error_return (0, "BVI delete failed");
    }
  else
    return clib_error_return (0, "no such interface: %U",
			      format_unformat_error, input);

  return 0;
}

/*?
 * Delete a BVI interface.
 *
 * @cliexpar
 * The following two command syntaxes are equivalent:
 * @cliexcmd{bvi delete <interface>}
 * Example of how to create a bvi interface:
 * @cliexcmd{bvi delete bvi0}
?*/
/* *INDENT-OFF* */
VLIB_CLI_COMMAND (l2_bvi_delete_command, static) = {
  .path = "bvi delete",
  .short_help = "bvi delete <interface>",
  .function = l2_bvi_delete_cli,
};
/* *INDENT-ON* */


/*
 * fd.io coding-style-patch-verification: ON
 *
 * Local Variables:
 * eval: (c-set-style "gnu")
 * End:
 */