summaryrefslogtreecommitdiffstats
path: root/test/test_session.py
AgeCommit message (Expand)AuthorFilesLines
2021-01-22tests: add generalized tags for tests, use them for run-solo testsAndrew Yourtchenko1-4/+2
2020-11-24tests: remove bond, pipe, session and api_namespace from vpp_papi_providerJakub Grajciar1-4/+4
2020-08-27tests: "force solo" testcase supportAndrew Yourtchenko1-0/+4
2020-03-05session: API cleanupJakub Grajciar1-2/+2
2019-11-05misc: Fix python scripts shebang lineRenato Botelho do Couto1-1/+1
2019-04-19svm: move fifo tests to a separate fileFlorin Coras1-0/+26
2019-04-10Tests Cleanup: Fix missing calls to setUpClass/tearDownClass.Paul Vinciguerra1-0/+12
2019-03-11VPP-1508: Tests: Fix vpp_api struct.error under py3.Paul Vinciguerra1-2/+2
2019-03-11Tests: use self.assertNotIn().Paul Vinciguerra1-3/+3
2019-03-04test framework: Fix wrapper functions to match API message names.Ole Troan1-4/+4
2018-10-28session: extend connect api for internal appsFlorin Coras1-8/+20
2018-06-24Revert "Revert "make test: fix broken interfaces""Klement Sekera1-1/+1
2018-06-22Revert "make test: fix broken interfaces"Ole Troan1-1/+1
2018-06-22make test: fix broken interfacesKlement Sekera1-1/+1
2018-02-14session: support local sessions and deprecate redirectsFlorin Coras1-0/+3
2018-02-05session: segment manager refactorFlorin Coras1-1/+63
2017-12-12tcp/session: add make testsFlorin Coras1-0/+31
344'>344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374
/*
 * Copyright (c) 2015 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.
 */
/*
 * srp_interface.c: srp interfaces
 *
 * Copyright (c) 2008 Eliot Dresselhaus
 *
 * Permission is hereby granted, free of charge, to any person obtaining
 * a copy of this software and associated documentation files (the
 * "Software"), to deal in the Software without restriction, including
 * without limitation the rights to use, copy, modify, merge, publish,
 * distribute, sublicense, and/or sell copies of the Software, and to
 * permit persons to whom the Software is furnished to do so, subject to
 * the following conditions:
 *
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 *
 *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 *  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 *  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 *  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
 *  LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
 *  OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
 *  WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include <vnet/vnet.h>
#include <vnet/pg/pg.h>
#include <vnet/srp/srp.h>

static u8*
srp_build_rewrite (vnet_main_t * vnm,
		   u32 sw_if_index,
		   vnet_link_t link_type,
		   const void * dst_address)
{
  vnet_hw_interface_t * hw = vnet_get_sup_hw_interface (vnm, sw_if_index);
  srp_main_t * sm = &srp_main;
  srp_and_ethernet_header_t * h;
  u8* rewrite = NULL;
  u16 type;
  uword n_bytes = sizeof (h[0]);

  switch (link_type) {
#define _(a,b) case VNET_LINK_##a: type = ETHERNET_TYPE_##b; break
    _ (IP4, IP4);
    _ (IP6, IP6);
    _ (MPLS, MPLS);
    _ (ARP, ARP);
#undef _
  default:
      return (NULL);
  }

  vec_validate(rewrite, n_bytes-1);
  h = (srp_and_ethernet_header_t *)rewrite;

  clib_memcpy (h->ethernet.src_address, hw->hw_address, sizeof (h->ethernet.src_address));
  if (dst_address)
    clib_memcpy (h->ethernet.dst_address, dst_address, sizeof (h->ethernet.dst_address));
  else
    clib_memset (h->ethernet.dst_address, ~0, sizeof (h->ethernet.dst_address)); /* broadcast */

  h->ethernet.type = clib_host_to_net_u16 (type);

  h->srp.as_u16 = 0;
  h->srp.mode = SRP_MODE_data;
  h->srp.ttl = sm->default_data_ttl;
  srp_header_compute_parity (&h->srp);

  return (rewrite);
}

static void srp_register_interface_helper (u32 * hw_if_indices_by_side, u32 redistribute);

void serialize_srp_main (serialize_main_t * m, va_list * va)
{
  srp_main_t * sm = &srp_main;
  srp_interface_t * si;

  serialize_integer (m, pool_elts (sm->interface_pool), sizeof (u32));
  pool_foreach (si, sm->interface_pool)  {
    serialize_integer (m, si->rings[SRP_RING_OUTER].hw_if_index, sizeof (u32));
    serialize_integer (m, si->rings[SRP_RING_INNER].hw_if_index, sizeof (u32));
  }
}

void unserialize_srp_main (serialize_main_t * m, va_list * va)
{
  u32 i, n_ifs, hw_if_indices[SRP_N_RING];

  unserialize_integer (m, &n_ifs, sizeof (u32));
  for (i = 0; i < n_ifs; i++)
    {
      unserialize_integer (m, &hw_if_indices[SRP_RING_OUTER], sizeof (u32));
      unserialize_integer (m, &hw_if_indices[SRP_RING_INNER], sizeof (u32));
      srp_register_interface_helper (hw_if_indices, /* redistribute */ 0);
    }
}

static void srp_register_interface_helper (u32 * hw_if_indices_by_side, u32 redistribute)
{
  vnet_main_t * vnm = vnet_get_main();
  srp_main_t * sm = &srp_main;
  srp_interface_t * si;
  vnet_hw_interface_t * hws[SRP_N_RING];
  uword s, * p;

  /* Check if interface has already been registered. */
  p = hash_get (sm->interface_index_by_hw_if_index, hw_if_indices_by_side[0]);
  if (p)
    {
      si = pool_elt_at_index (sm->interface_pool, p[0]);
    }
  else
    {
      pool_get (sm->interface_pool, si);
      clib_memset (si, 0, sizeof (si[0]));
    }
  for (s = 0; s < SRP_N_SIDE; s++)
    {
      hws[s] = vnet_get_hw_interface (vnm, hw_if_indices_by_side[s]);
      si->rings[s].ring = s;
      si->rings[s].hw_if_index = hw_if_indices_by_side[s];
      si->rings[s].sw_if_index = hws[s]->sw_if_index;
      hash_set (sm->interface_index_by_hw_if_index, hw_if_indices_by_side[s], si - sm->interface_pool);
    }

  /* Inherit MAC address from outer ring. */
  clib_memcpy (si->my_address, hws[SRP_RING_OUTER]->hw_address,
	  vec_len (hws[SRP_RING_OUTER]->hw_address));

  /* Default time to wait to restore signal. */
  si->config.wait_to_restore_idle_delay = 60;
  si->config.ips_tx_interval = 1;
}

void srp_register_interface (u32 * hw_if_indices_by_side)
{
  srp_register_interface_helper (hw_if_indices_by_side, /* redistribute */ 1);
}

void srp_interface_set_hw_wrap_function (u32 hw_if_index, srp_hw_wrap_function_t * f)
{
  srp_interface_t * si = srp_get_interface_from_vnet_hw_interface (hw_if_index);
  si->hw_wrap_function = f;
}

void srp_interface_set_hw_enable_function (u32 hw_if_index, srp_hw_enable_function_t * f)
{
  srp_interface_t * si = srp_get_interface_from_vnet_hw_interface (hw_if_index);
  si->hw_enable_function = f;
}

void srp_interface_enable_ips (u32 hw_if_index)
{
  srp_main_t * sm = &srp_main;
  srp_interface_t * si = srp_get_interface_from_vnet_hw_interface (hw_if_index);

  si->ips_process_enable = 1;

  vlib_node_set_state (sm->vlib_main, srp_ips_process_node.index, VLIB_NODE_STATE_POLLING);
}

static uword
srp_is_valid_class_for_interface (vnet_main_t * vnm, u32 hw_if_index, u32 hw_class_index)
{
  srp_interface_t * si = srp_get_interface_from_vnet_hw_interface (hw_if_index);

  if (! si)
    return 0;

  /* Both sides must be admin down. */
  if (vnet_sw_interface_is_admin_up (vnm, si->rings[SRP_RING_OUTER].sw_if_index))
    return 0;
  if (vnet_sw_interface_is_admin_up (vnm, si->rings[SRP_RING_INNER].sw_if_index))
    return 0;
					 
  return 1;
}

static void
srp_interface_hw_class_change (vnet_main_t * vnm, u32 hw_if_index,
			       u32 old_hw_class_index, u32 new_hw_class_index)
{
  srp_main_t * sm = &srp_main;
  srp_interface_t * si = srp_get_interface_from_vnet_hw_interface (hw_if_index);
  vnet_hw_interface_t * hi;
  vnet_device_class_t * dc;
  u32 r, to_srp;

  if (!si) {
      clib_warning ("srp interface no set si = 0");
      return;
  }

  to_srp = new_hw_class_index == srp_hw_interface_class.index;

  /* Changing class on either outer or inner rings implies changing the class
     of the other. */
  for (r = 0; r < SRP_N_RING; r++)
    {
      srp_interface_ring_t * ir = &si->rings[r];

      hi = vnet_get_hw_interface (vnm, ir->hw_if_index);
      dc = vnet_get_device_class (vnm, hi->dev_class_index);

      /* hw_if_index itself will be handled by caller. */
      if (ir->hw_if_index != hw_if_index)
	{
	  vnet_hw_interface_init_for_class (vnm, ir->hw_if_index,
					    new_hw_class_index,
					    to_srp ? si - sm->interface_pool : ~0);

	  if (dc->hw_class_change)
	    dc->hw_class_change (vnm, ir->hw_if_index, new_hw_class_index);
	}
      else
	hi->hw_instance = to_srp ? si - sm->interface_pool : ~0;
    }

  if (si->hw_enable_function)
    si->hw_enable_function (si, /* enable */ to_srp);
}

VNET_HW_INTERFACE_CLASS (srp_hw_interface_class) = {
  .name = "SRP",
  .format_address = format_ethernet_address,
  .format_header = format_srp_header_with_length,
  .format_device = format_srp_device,
  .unformat_hw_address = unformat_ethernet_address,
  .unformat_header = unformat_srp_header,
  .build_rewrite = srp_build_rewrite,
  .update_adjacency = ethernet_update_adjacency,
  .is_valid_class_for_interface = srp_is_valid_class_for_interface,
  .hw_class_change = srp_interface_hw_class_change,
};

void srp_interface_get_interface_config (u32 hw_if_index, srp_interface_config_t * c)
{
  srp_interface_t * si = srp_get_interface_from_vnet_hw_interface (hw_if_index);
  ASSERT (si != 0);
  c[0] = si->config;
}

void srp_interface_set_interface_config (u32 hw_if_index, srp_interface_config_t * c)
{
  srp_interface_t * si = srp_get_interface_from_vnet_hw_interface (hw_if_index);
  ASSERT (si != 0);
  if (memcmp (&si->config, &c[0], sizeof (c[0])))
    {
      si->config = c[0];
    }
}

#if DEBUG > 0

#define VNET_SIMULATED_SRP_TX_NEXT_SRP_INPUT VNET_INTERFACE_TX_N_NEXT
/* Echo packets back to srp input. */
static uword
simulated_srp_interface_tx (vlib_main_t * vm,
			    vlib_node_runtime_t * node,
			    vlib_frame_t * frame)
{
  u32 n_left_from, n_left_to_next, n_copy, * from, * to_next;
  u32 next_index = VNET_SIMULATED_SRP_TX_NEXT_SRP_INPUT;
  u32 i;
  vlib_buffer_t * b;

  n_left_from = frame->n_vectors;
  from = vlib_frame_vector_args (frame);

  while (n_left_from > 0)
    {
      vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);

      n_copy = clib_min (n_left_from, n_left_to_next);

      clib_memcpy_fast (to_next, from, n_copy * sizeof (from[0]));
      n_left_to_next -= n_copy;
      n_left_from -= n_copy;
      for (i = 0; i < n_copy; i++)
	{
	  b = vlib_get_buffer (vm, from[i]);
	  /* TX interface will be fake eth; copy to RX for benefit of srp-input. */
	  b->sw_if_index[VLIB_RX] = b->sw_if_index[VLIB_TX];
	}

      vlib_put_next_frame (vm, node, next_index, n_left_to_next);
    }

  return n_left_from;
}

static u8 * format_simulated_srp_name (u8 * s, va_list * args)
{
  u32 dev_instance = va_arg (*args, u32);
  return format (s, "fake-srp%d", dev_instance);
}

VNET_DEVICE_CLASS (srp_simulated_device_class,static) = {
  .name = "Simulated srp",
  .format_device_name = format_simulated_srp_name,
  .tx_function = simulated_srp_interface_tx,
};

static clib_error_t *
create_simulated_srp_interfaces (vlib_main_t * vm,
				 unformat_input_t * input,
				 vlib_cli_command_t * cmd)
{
  vnet_main_t * vnm = vnet_get_main();
  u8 address[6];
  u32 hw_if_index;
  vnet_hw_interface_t * hi;
  static u32 instance;

  if (! unformat_user (input, unformat_ethernet_address, &address))
    {
      clib_memset (address, 0, sizeof (address));
      address[0] = 0xde;
      address[1] = 0xad;
      address[5] = instance;
    }

  hw_if_index = vnet_register_interface (vnm,
					 srp_simulated_device_class.index,
					 instance++,
					 srp_hw_interface_class.index, 0);

  hi = vnet_get_hw_interface (vnm, hw_if_index);

  srp_setup_node (vm, hi->output_node_index);

  hi->min_packet_bytes = 40 + 16;

  /* Standard default ethernet MTU. */
  vnet_sw_interface_set_mtu (vnm, sw_if_index, 1500);

  vec_free (hi->hw_address);
  vec_add (hi->hw_address, address, sizeof (address));

  {
    uword slot;

    slot = vlib_node_add_named_next_with_slot
      (vm, hi->tx_node_index,
       "srp-input",
       VNET_SIMULATED_SRP_TX_NEXT_SRP_INPUT);
    ASSERT (slot == VNET_SIMULATED_SRP_TX_NEXT_SRP_INPUT);
  }

  return /* no error */ 0;
}

static VLIB_CLI_COMMAND (create_simulated_srp_interface_command) = {
  .path = "srp create-interfaces",
  .short_help = "Create simulated srp interface",
  .function = create_simulated_srp_interfaces,
};
#endif