aboutsummaryrefslogtreecommitdiffstats
path: root/test/vpp_lo_interface.py
AgeCommit message (Collapse)AuthorFilesLines
2018-06-24Revert "Revert "make test: fix broken interfaces""Klement Sekera1-5/+3
This reverts commit c8efa29b6f9a91381897b54f1147daf922ed7164. Change-Id: I1d5c5773d5f86a63073e255336bd9de628e26179 Signed-off-by: Klement Sekera <ksekera@cisco.com>
2018-06-22Revert "make test: fix broken interfaces"Ole Troan1-3/+5
This reverts commit d5c60b96a3fd93916fc4af5c8d6d25625c28242e. Change-Id: I3632b9c3f76c615aee897f28f76d094e7031e689 Signed-off-by: Ole Troan <ot@cisco.com>
2018-06-22make test: fix broken interfacesKlement Sekera1-5/+3
Change-Id: I2e092774f81503e04b53cc6c6b5d357fe3fc52ab Signed-off-by: Klement Sekera <ksekera@cisco.com>
2018-02-01IPv4/6 reassemblyKlement Sekera1-12/+0
Change-Id: Ic5dcadd13c88b8a5e7896dab82404509c081614a Signed-off-by: Klement Sekera <ksekera@cisco.com>
2017-09-08ACL-plugin MACIP ACLs testsPavel Kotucek1-1/+1
Change-Id: Ie40c837358454cfe9475cb2c14fdf20b24fa6602 Signed-off-by: Pavel Kotucek <pkotucek@cisco.com>
2017-01-09make test: Loopback interface CRUD testMatej Klotton1-4/+26
Change-Id: I0581da7a682bfe4dd6520ecf1b2ea6bd8c20b1b3 Signed-off-by: Matej Klotton <mklotton@cisco.com>
2016-11-24Remove postinit from make-test interfacesMatej Klotton1-4/+3
Change-Id: I1eb0f735c5d025e6096d5760eb01419a1c58530a Signed-off-by: Matej Klotton <mklotton@cisco.com>
2016-11-15Update test documentation.Matej Klotton1-3/+1
- update IRB, IPv4, ipv6 doc - revert 778c2765c8ea5c6628f6d668847f0b9ae06dbf3d Change-Id: I9af5ed9329ce5fe01392cf28d5bf321cfc647e48 Signed-off-by: Matej Klotton <mklotton@cisco.com>
2016-11-11Add IRB testMatej Klotton1-0/+16
- JIRA: CSIT-255 - create loopback interfaces - move pg-interface specific arp and neighbor discovery from vpp_interface to vpp_pg_interface - base configuration of IRB tests - IP test scenario Change-Id: I9945a188163652a4e22325877aef008c4d029557 Signed-off-by: Matej Klotton <mklotton@cisco.com>
'>270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311
/*
 *------------------------------------------------------------------
 * 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 <igmp/igmp_query.h>
#include <igmp/igmp_pkt.h>

static f64
igmp_get_random_resp_delay (const igmp_header_t * header)
{
  u32 seed;

  seed = vlib_time_now (vlib_get_main ());

  return ((random_f64 (&seed) * igmp_header_get_max_resp_time (header)));

}

static ip46_address_t *
igmp_query_mk_source_list (const igmp_membership_query_v3_t * q)
{
  ip46_address_t *srcs = NULL;
  const ip4_address_t *s;
  u16 ii, n;

  /*
   * we validated this packet when we accepted it in the DP, so
   * this number is safe to use
   */
  n = clib_net_to_host_u16 (q->n_src_addresses);

  if (0 == n)
    return (NULL);

  vec_validate (srcs, n - 1);
  s = q->src_addresses;

  for (ii = 0; ii < n; ii++)
    {
      srcs[ii].ip4 = *s;
      s++;
    }

  return (srcs);
}

static void
igmp_send_group_report_v3 (u32 obj, void *data)
{
  igmp_pkt_build_report_t br;
  igmp_config_t *config;
  ip46_address_t *srcs;
  igmp_group_t *group;
  igmp_main_t *im;

  im = &igmp_main;
  srcs = data;
  group = pool_elt_at_index (im->groups, obj);
  config = pool_elt_at_index (im->configs, group->config);

  igmp_pkt_build_report_init (&br, config->sw_if_index);
  ASSERT (group->timers[IGMP_GROUP_TIMER_QUERY_REPLY] !=
	  IGMP_TIMER_ID_INVALID);

  IGMP_DBG ("send-group-report: %U",
	    format_vnet_sw_if_index_name,
	    vnet_get_main (), config->sw_if_index);

  if (NULL == srcs)
    {
      /*
       * there were no sources specified, so this is a group-specific query.
       * We should respond with all our sources
       */
      igmp_pkt_report_v3_add_group (&br, group,
				    IGMP_MEMBERSHIP_GROUP_mode_is_include);
    }
  else
    {
      /*
       * the sources stored in the timer object are the combined set of sources
       * to be required. We need to respond only to those queried, not our full set.
       */
      ip46_address_t *intersect;

      intersect = igmp_group_new_intersect_present (group,
						    IGMP_FILTER_MODE_INCLUDE,
						    srcs);

      if (vec_len (intersect))
	{
	  igmp_pkt_report_v3_add_report (&br,
					 group->key,
					 intersect,
					 IGMP_MEMBERSHIP_GROUP_mode_is_include);
	  vec_free (intersect);
	}
    }

  igmp_pkt_report_v3_send (&br);

  igmp_timer_retire (&group->timers[IGMP_GROUP_TIMER_QUERY_REPLY]);
  vec_free (srcs);
}

static igmp_membership_group_v3_type_t
igmp_filter_mode_to_report_type (igmp_filter_mode_t mode)
{
  switch (mode)
    {
    case IGMP_FILTER_MODE_INCLUDE:
      return (IGMP_MEMBERSHIP_GROUP_mode_is_include);
    case IGMP_FILTER_MODE_EXCLUDE:
      return (IGMP_MEMBERSHIP_GROUP_mode_is_exclude);
    }

  return (IGMP_MEMBERSHIP_GROUP_mode_is_include);
}

/**
 * Send igmp membership general report.
 */
static void
igmp_send_general_report_v3 (u32 obj, void *data)
{
  igmp_pkt_build_report_t br;
  igmp_config_t *config;
  igmp_group_t *group;
  igmp_main_t *im;

  im = &igmp_main;
  config = pool_elt_at_index (im->configs, obj);

  ASSERT (config->timers[IGMP_CONFIG_TIMER_GENERAL_REPORT] !=
	  IGMP_TIMER_ID_INVALID);

  igmp_timer_retire (&config->timers[IGMP_CONFIG_TIMER_GENERAL_REPORT]);

  IGMP_DBG ("send-general-report: %U",
	    format_vnet_sw_if_index_name,
	    vnet_get_main (), config->sw_if_index);

  igmp_pkt_build_report_init (&br, config->sw_if_index);

  /* *INDENT-OFF* */
  FOR_EACH_GROUP (group, config,
    ({
      igmp_pkt_report_v3_add_group
        (&br, group,
         igmp_filter_mode_to_report_type(group->router_filter_mode));
    }));
  /* *INDENT-ON* */

  igmp_pkt_report_v3_send (&br);
}

/**
 * Called from the main thread on reception of a Query message
 */
void
igmp_handle_query (const igmp_query_args_t * args)
{
  igmp_config_t *config;

  config = igmp_config_lookup (args->sw_if_index);

  if (!config)
    /*
     * no IGMP config on the interface. quit
     */
    return;

  if (IGMP_MODE_ROUTER == config->mode)
    {
      ASSERT (0);
      // code here for querier election */
    }

  IGMP_DBG ("query-rx: %U", format_vnet_sw_if_index_name,
	    vnet_get_main (), args->sw_if_index);


  /*
     Section 5.2
     "When a system receives a Query, it does not respond immediately.
     Instead, it delays its response by a random amount of time, bounded
     by the Max Resp Time value derived from the Max Resp Code in the
     received Query message.  A system may receive a variety of Queries on
     different interfaces and of different kinds (e.g., General Queries,
     Group-Specific Queries, and Group-and-Source-Specific Queries), each
     of which may require its own delayed response.
   */
  if (igmp_membership_query_v3_is_general (args->query))
    {
      IGMP_DBG ("...general-query-rx: %U", format_vnet_sw_if_index_name,
		vnet_get_main (), args->sw_if_index);

      /*
       * A general query has no info that needs saving from the response
       */
      if (IGMP_TIMER_ID_INVALID ==
	  config->timers[IGMP_CONFIG_TIMER_GENERAL_REPORT])
	{
	  f64 delay = igmp_get_random_resp_delay (&args->query[0].header);

	  IGMP_DBG ("...general-query-rx: %U schedule for %f",
		    format_vnet_sw_if_index_name, vnet_get_main (),
		    args->sw_if_index, delay);

	  /*
	   * no currently running timer, schedule a new one
	   */
	  config->timers[IGMP_CONFIG_TIMER_GENERAL_REPORT] =
	    igmp_timer_schedule (delay,
				 igmp_config_index (config),
				 igmp_send_general_report_v3, NULL);
	}
      /*
       * else
       *  don't reschedule timers, we'll reply soon enough..
       */
    }
  else
    {
      /*
       * G or SG query. we'll need to save the sources quered
       */
      igmp_key_t key = {
	.ip4 = args->query[0].group_address,
      };
      ip46_address_t *srcs;
      igmp_timer_id_t tid;
      igmp_group_t *group;

      group = igmp_group_lookup (config, &key);

      /*
       * If there is no group config, no worries, we can ignore this
       * query. If the group state does come soon, we'll send a
       * state-change report at that time.
       */
      if (!group)
	return;

      srcs = igmp_query_mk_source_list (args->query);
      tid = group->timers[IGMP_GROUP_TIMER_QUERY_REPLY];

      IGMP_DBG ("...group-query-rx: %U for (%U, %U)",
		format_vnet_sw_if_index_name,
		vnet_get_main (), args->sw_if_index,
		format_igmp_src_addr_list, srcs, format_igmp_key, &key);


      if (IGMP_TIMER_ID_INVALID != tid)
	{
	  /*
	   * There is a timer already running, merge the sources list
	   */
	  ip46_address_t *current, *s;

	  current = igmp_timer_get_data (tid);

	  vec_foreach (s, srcs)
	  {
	    if (~0 == vec_search_with_function (current, s,
						ip46_address_is_equal))
	      {
		vec_add1 (current, *s);
	      }
	  }

	  igmp_timer_set_data (tid, current);
	}
      else
	{
	  /*
	   * schedule a new G-specific query
	   */
	  f64 delay = igmp_get_random_resp_delay (&args->query[0].header);

	  IGMP_DBG ("...group-query-rx: schedule:%f", delay);

	  group->timers[IGMP_GROUP_TIMER_QUERY_REPLY] =
	    igmp_timer_schedule (delay,
				 igmp_group_index (group),
				 igmp_send_group_report_v3, srcs);
	}
    }
}


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