summaryrefslogtreecommitdiffstats
path: root/test/test_gbp.py
diff options
context:
space:
mode:
authorStephen Hemminger <stephen@networkplumber.org>2018-10-11 17:04:13 -0700
committerDamjan Marion <dmarion@me.com>2018-10-15 11:29:17 +0000
commit3901a038edf47a35665c57961e6620efdd01dbbd (patch)
tree080e2cfd4a3390c37551b05cb46242191003ac04 /test/test_gbp.py
parent59a829533c1345945dc1b6decc3afe29494e85cd (diff)
dpdk: only look at PCI information on PCI devices
The rte_device is use as a base type of all DPDK devices. It is not valid to use container_of to find PCI information unless the bus of the rte_device is pci. Otherwise, the pointer is looking at some other data, which may or may not be zero. This change introduces a helper function to get rte_pci_device pointer. If device is on PCI bus it returns pointer to rte_pci_device info, otherwise it returns NULL. Change-Id: Ia7446006bb93a7a54844969f3b3dd3b918890dfd Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
Diffstat (limited to 'test/test_gbp.py')
0 files changed, 0 insertions, 0 deletions
href='#n139'>139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228
/*
 * vrrp_periodic.c - vrrp plug-in periodic function
 *
 * Copyright 2019-2020 Rubicon Communications, LLC (Netgate)
 *
 * SPDX-License-Identifier: Apache-2.0
 *
 */

#include <vlib/vlib.h>
#include <vppinfra/error.h>
#include <vrrp/vrrp.h>
#include <vrrp/vrrp_packet.h>

static int
vrrp_vr_timer_compare (const void *v1, const void *v2)
{
  vrrp_main_t *vmp = &vrrp_main;
  const u32 *idx1, *idx2;
  vrrp_vr_timer_t *timer1, *timer2;

  idx1 = v1;
  idx2 = v2;

  timer1 = pool_elt_at_index (vmp->vr_timers, *idx1);
  timer2 = pool_elt_at_index (vmp->vr_timers, *idx2);

  /* don't check equality, they are unlikely to be exactly equal and
   * if it occurs, it won't matter what order they were in.
   * sort the list in reverse so we can pick the next timer off the end */
  if (timer1->expire_time > timer2->expire_time)
    return -1;
  else
    return 1;
}

static u32
vrrp_vr_timer_get_next (void)
{
  vrrp_main_t *vmp = &vrrp_main;
  int n_timers;

  n_timers = vec_len (vmp->pending_timers);

  if (!n_timers)
    return ~0;

  return vec_elt (vmp->pending_timers, n_timers - 1);
}

/* cancel an existing timer. This could happen because:
 * - adv timer expired on master. another adv should be scheduled.
 * - a shutdown event is received
 * - a master is preempted by a higher priority master
 * - adv received on backup. master down timer should be rescheduled.
 */
void
vrrp_vr_timer_cancel (vrrp_vr_t * vr)
{
  vrrp_main_t *vmp = &vrrp_main;
  u32 *t;

  /* don't search for a timer that was already canceled or never set */
  if (vr->runtime.timer_index == ~0)
    return;

  /* timers stored in descending order, start at the end of the list */
  /* vec_foreach_backwards does not deal with 0 pointers, check first */
  if (vmp->pending_timers)
    vec_foreach_backwards (t, vmp->pending_timers)
    {
      if (*t == vr->runtime.timer_index)
	{
	  vec_delete (vmp->pending_timers, 1, t - vmp->pending_timers);
	  break;
	}
    }

  if (!pool_is_free_index (vmp->vr_timers, vr->runtime.timer_index))
    pool_put_index (vmp->vr_timers, vr->runtime.timer_index);

  vr->runtime.timer_index = ~0;

  vlib_process_signal_event (vmp->vlib_main, vrrp_periodic_node.index,
			     VRRP_EVENT_VR_TIMER_UPDATE, 0);
}

void
vrrp_vr_timer_set (vrrp_vr_t * vr, vrrp_vr_timer_type_t type)
{
  vrrp_main_t *vmp = &vrrp_main;
  vlib_main_t *vm = vlib_get_main ();
  vrrp_vr_timer_t *timer;
  f64 now;

  /* Each VR should be waiting on at most 1 timer at any given time.
   * If there is already a timer set for this VR, cancel it.
   */
  if (vr->runtime.timer_index != ~0)
    vrrp_vr_timer_cancel (vr);

  pool_get (vmp->vr_timers, timer);
  vr->runtime.timer_index = timer - vmp->vr_timers;

  timer->vr_index = vr - vmp->vrs;
  timer->type = type;

  now = vlib_time_now (vm);

  /* RFC 5798 specifies that timers are in centiseconds, so x / 100.0 */
  switch (type)
    {
    case VRRP_VR_TIMER_ADV:
      timer->expire_time = now + (vr->config.adv_interval / 100.0);
      break;
    case VRRP_VR_TIMER_MASTER_DOWN:
      timer->expire_time = now + (vr->runtime.master_down_int / 100.0);
      break;
    default:
      /* should never reach here */
      clib_warning ("Unrecognized VRRP timer type (%d)", type);
      return;
    }

  vec_add1 (vmp->pending_timers, vr->runtime.timer_index);

  vec_sort_with_function (vmp->pending_timers, vrrp_vr_timer_compare);

  vlib_process_signal_event (vmp->vlib_main, vrrp_periodic_node.index,
			     VRRP_EVENT_VR_TIMER_UPDATE, 0);
}

void
vrrp_vr_timer_timeout (u32 timer_index)
{
  vrrp_main_t *vmp = &vrrp_main;
  vrrp_vr_timer_t *timer;
  vrrp_vr_t *vr;

  if (pool_is_free_index (vmp->vr_timers, timer_index))
    {
      clib_warning ("Timeout on free timer index %u", timer_index);
      return;
    }

  timer = pool_elt_at_index (vmp->vr_timers, timer_index);
  vr = pool_elt_at_index (vmp->vrs, timer->vr_index);

  switch (timer->type)
    {
    case VRRP_VR_TIMER_ADV:
      vrrp_adv_send (vr, 0);
      vrrp_vr_timer_set (vr, VRRP_VR_TIMER_ADV);
      break;
    case VRRP_VR_TIMER_MASTER_DOWN:
      vrrp_vr_transition (vr, VRRP_VR_STATE_MASTER, NULL);
      break;
    default:
      clib_warning ("Unrecognized timer type %d", timer->type);
      return;
    }

}

static uword
vrrp_periodic_process (vlib_main_t * vm,
		       vlib_node_runtime_t * rt, vlib_frame_t * f)
{
  vrrp_main_t *pm = &vrrp_main;
  f64 now;
  f64 timeout = 10.0;
  uword *event_data = 0;
  uword event_type;
  u32 next_timer = ~0;
  vrrp_vr_timer_t *timer;

  while (1)
    {
      now = vlib_time_now (vm);

      if (next_timer == ~0)
	{
	  vlib_process_wait_for_event (vm);
	}
      else
	{
	  timer = pool_elt_at_index (pm->vr_timers, next_timer);
	  timeout = timer->expire_time - now;

	  vlib_process_wait_for_event_or_clock (vm, timeout);
	}

      event_type = vlib_process_get_events (vm, (uword **) & event_data);

      switch (event_type)
	{
	  /* Handle VRRP_EVENT_VR_TIMER_UPDATE */
	case VRRP_EVENT_VR_TIMER_UPDATE:
	  next_timer = vrrp_vr_timer_get_next ();
	  break;

	  /* Handle periodic timeouts */
	case ~0:
	  vrrp_vr_timer_timeout (next_timer);
	  next_timer = vrrp_vr_timer_get_next ();
	  break;
	}
      vec_reset_length (event_data);
    }
  return 0;
}

/* *INDENT-OFF* */
VLIB_REGISTER_NODE (vrrp_periodic_node) = {
  .function = vrrp_periodic_process,
  .type = VLIB_NODE_TYPE_PROCESS,
  .name = "vrrp-periodic-process",
  .process_log2_n_stack_bytes = 17,
};
/* *INDENT-ON* */

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