FD.io VPP  v17.01.1-3-gc6833f8
Vector Packet Processing
bfd_main.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2011-2016 Cisco and/or its affiliates.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at:
6  *
7  * http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 /**
16  * @file
17  * @brief BFD nodes implementation
18  */
19 
20 #include <vppinfra/random.h>
21 #include <vppinfra/error.h>
22 #include <vppinfra/hash.h>
23 #include <vnet/ethernet/ethernet.h>
24 #include <vnet/ethernet/packet.h>
25 #include <vnet/bfd/bfd_debug.h>
26 #include <vnet/bfd/bfd_protocol.h>
27 #include <vnet/bfd/bfd_main.h>
28 
29 static u64
31 {
32  return bm->cpu_cps * ((f64) us / USEC_PER_SECOND);
33 }
34 
36 
37 typedef enum
38 {
39 #define F(t, n) BFD_OUTPUT_##t,
41 #undef F
42  BFD_OUTPUT_N_NEXT,
44 
45 static u32 bfd_next_index_by_transport[] = {
46 #define F(t, n) [BFD_TRANSPORT_##t] = BFD_OUTPUT_##t,
48 #undef F
49 };
50 
51 /*
52  * We actually send all bfd pkts to the "error" node after scanning
53  * them, so the graph node has only one next-index. The "error-drop"
54  * node automatically bumps our per-node packet counters for us.
55  */
56 typedef enum
57 {
61 
62 static void bfd_on_state_change (bfd_main_t * bm, bfd_session_t * bs, u64 now,
63  int handling_wakeup);
64 
65 static void
67 {
68  bs->local_state = BFD_STATE_down;
69  bs->local_diag = BFD_DIAG_CODE_no_diag;
70  bs->remote_state = BFD_STATE_down;
71  bs->local_demand = 0;
72  bs->remote_discr = 0;
75  bs->remote_min_rx_us = 1;
76  bs->remote_demand = 0;
77 }
78 
79 static void
81 {
82  if (bs->local_diag != code)
83  {
84  BFD_DBG ("set local_diag, bs_idx=%d: '%d:%s'", bs->bs_idx, code,
85  bfd_diag_code_string (code));
86  bs->local_diag = code;
87  }
88 }
89 
90 static void
92  bfd_state_e new_state, int handling_wakeup)
93 {
94  if (bs->local_state != new_state)
95  {
96  BFD_DBG ("Change state, bs_idx=%d: %s->%s", bs->bs_idx,
98  bfd_state_string (new_state));
99  bs->local_state = new_state;
100  bfd_on_state_change (bm, bs, clib_cpu_time_now (), handling_wakeup);
101  }
102 }
103 
104 static void
106 {
107  if (!bs->local_demand)
108  {
111  }
112  else
113  {
114  /* TODO */
115  }
116  BFD_DBG ("Recalculated transmit interval %lu clocks/%.2fs",
119 }
120 
121 static void
123 {
124  if (!bs->local_demand)
125  {
126  if (bs->local_detect_mult > 1)
127  {
128  /* common case - 75-100% of transmit interval */
129  bs->tx_timeout_clocks = now +
130  (1 - .25 * (random_f64 (&bm->random_seed))) *
132  if (bs->tx_timeout_clocks < now)
133  {
134  /* huh, we've missed it already, skip the missed events */
135  const u64 missed =
137  BFD_ERR ("Missed %lu transmit events (now is %lu, calc "
138  "tx_timeout is %lu)!",
139  missed, now, bs->tx_timeout_clocks);
140  bs->tx_timeout_clocks +=
141  (missed + 1) * bs->transmit_interval_clocks;
142  }
143  }
144  else
145  {
146  /* special case - 75-90% of transmit interval */
147  bs->tx_timeout_clocks =
148  now +
149  (.9 - .15 * (random_f64 (&bm->random_seed))) *
151  if (bs->tx_timeout_clocks < now)
152  {
153  /* huh, we've missed it already, skip the missed events */
154  const u64 missed =
156  BFD_ERR ("Missed %lu transmit events (now is %lu, calc "
157  "tx_timeout is %lu)!",
158  missed, now, bs->tx_timeout_clocks);
159  bs->tx_timeout_clocks +=
160  (missed + 1) * bs->transmit_interval_clocks;
161  }
162  }
163  }
164  else
165  {
166  /* TODO */
167  }
168  if (bs->tx_timeout_clocks)
169  {
170  BFD_DBG ("Next transmit in %lu clocks/%.02fs@%lu",
171  bs->tx_timeout_clocks - now,
172  (bs->tx_timeout_clocks - now) / bm->cpu_cps,
173  bs->tx_timeout_clocks);
174  }
175 }
176 
177 static void
179 {
180  if (!bs->local_demand)
181  {
183  bs->remote_detect_mult *
186  }
187  else
188  {
190  bs->local_detect_mult *
191  bfd_us_to_clocks (bm,
193  bs->remote_min_rx_us));
194  }
195  BFD_DBG ("Recalculated detection time %lu clocks/%.2fs",
197  bs->detection_time_clocks / bm->cpu_cps);
198 }
199 
200 static void
202  int handling_wakeup)
203 {
204  u64 next = 0;
205  u64 rx_timeout = 0;
206  if (BFD_STATE_up == bs->local_state)
207  {
208  rx_timeout = bs->last_rx_clocks + bs->detection_time_clocks;
209  }
210  if (bs->tx_timeout_clocks && rx_timeout)
211  {
212  next = clib_min (bs->tx_timeout_clocks, rx_timeout);
213  }
214  else if (bs->tx_timeout_clocks)
215  {
216  next = bs->tx_timeout_clocks;
217  }
218  else if (rx_timeout)
219  {
220  next = rx_timeout;
221  }
222  BFD_DBG ("bs_idx=%u, tx_timeout=%lu, rx_timeout=%lu, next=%s", bs->bs_idx,
223  bs->tx_timeout_clocks, rx_timeout,
224  next == bs->tx_timeout_clocks ? "tx" : "rx");
225  /* sometimes the wheel expires an event a bit sooner than requested, account
226  for that here */
227  if (next && (now + bm->wheel_inaccuracy > bs->wheel_time_clocks ||
228  next < bs->wheel_time_clocks || !bs->wheel_time_clocks))
229  {
230  bs->wheel_time_clocks = next;
231  BFD_DBG ("timing_wheel_insert(%p, %lu (%ld clocks/%.2fs in the "
232  "future), %u);",
233  &bm->wheel, bs->wheel_time_clocks,
236  bm->cpu_cps, bs->bs_idx);
238  if (!handling_wakeup)
239  {
243  }
244  }
245 }
246 
247 static void
249  u32 desired_min_tx_us, int handling_wakeup)
250 {
251  bs->desired_min_tx_us = desired_min_tx_us;
253  BFD_DBG ("Set desired min tx to %uus/%lu clocks/%.2fs",
255  bs->desired_min_tx_clocks / bm->cpu_cps);
256  bfd_recalc_detection_time (bm, bs);
257  bfd_recalc_tx_interval (bm, bs);
258  bfd_calc_next_tx (bm, bs, now);
259  bfd_set_timer (bm, bs, now, handling_wakeup);
260 }
261 
262 static void
264  u64 now,
265  u32 remote_required_min_rx_us,
266  int handling_wakeup)
267 {
268  bs->remote_min_rx_us = remote_required_min_rx_us;
270  BFD_DBG ("Set remote min rx to %uus/%lu clocks/%.2fs", bs->remote_min_rx_us,
272  bfd_recalc_detection_time (bm, bs);
273  bfd_recalc_tx_interval (bm, bs);
274  bfd_calc_next_tx (bm, bs, now);
275  bfd_set_timer (bm, bs, now, handling_wakeup);
276 }
277 
278 void
280 {
281  BFD_DBG ("%U", format_bfd_session, bs);
282  bfd_recalc_tx_interval (bm, bs);
285 }
286 
289 {
290  const bfd_main_t *bm = &bfd_main;
291  if (!pool_is_free_index (bm->sessions, bs_idx))
292  {
293  bfd_session_t *bs = pool_elt_at_index (bm->sessions, bs_idx);
294  pool_put (bm->sessions, bs);
295  return 0;
296  }
297  else
298  {
299  BFD_ERR ("no such session");
300  return VNET_API_ERROR_BFD_NOENT;
301  }
302  return 0;
303 }
304 
305 const char *
307 {
308 #define F(n, t, s) \
309  case BFD_DIAG_CODE_NAME (t): \
310  return s;
311  switch (diag)
312  {
314  return "UNKNOWN";
315 #undef F
316 }
317 
318 const char *
320 {
321 #define F(n, t, s) \
322  case BFD_STATE_NAME (t): \
323  return s;
324  switch (state)
325  {
327  return "UNKNOWN";
328 #undef F
329 }
330 
332 bfd_session_set_flags (u32 bs_idx, u8 admin_up_down)
333 {
334  bfd_main_t *bm = &bfd_main;
335  if (pool_is_free_index (bm->sessions, bs_idx))
336  {
337  BFD_ERR ("invalid bs_idx=%u", bs_idx);
338  return VNET_API_ERROR_BFD_NOENT;
339  }
340  bfd_session_t *bs = pool_elt_at_index (bm->sessions, bs_idx);
341  if (admin_up_down)
342  {
343  bfd_set_state (bm, bs, BFD_STATE_down, 0);
344  }
345  else
346  {
347  bfd_set_diag (bs, BFD_DIAG_CODE_neighbor_sig_down);
348  bfd_set_state (bm, bs, BFD_STATE_admin_down, 0);
349  }
350  return 0;
351 }
352 
353 u8 *
354 bfd_input_format_trace (u8 * s, va_list * args)
355 {
356  CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
357  CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
358  const bfd_input_trace_t *t = va_arg (*args, bfd_input_trace_t *);
359  const bfd_pkt_t *pkt = (bfd_pkt_t *) t->data;
360  if (t->len > STRUCT_SIZE_OF (bfd_pkt_t, head))
361  {
362  s = format (s, "BFD v%u, diag=%u(%s), state=%u(%s),\n"
363  " flags=(P:%u, F:%u, C:%u, A:%u, D:%u, M:%u), detect_mult=%u, "
364  "length=%u\n",
367  bfd_pkt_get_state (pkt),
369  bfd_pkt_get_poll (pkt), bfd_pkt_get_final (pkt),
372  bfd_pkt_get_multipoint (pkt), pkt->head.detect_mult,
373  pkt->head.length);
374  if (t->len >= sizeof (bfd_pkt_t)
375  && pkt->head.length >= sizeof (bfd_pkt_t))
376  {
377  s = format (s, " my discriminator: %u\n", pkt->my_disc);
378  s = format (s, " your discriminator: %u\n", pkt->your_disc);
379  s = format (s, " desired min tx interval: %u\n",
380  clib_net_to_host_u32 (pkt->des_min_tx));
381  s = format (s, " required min rx interval: %u\n",
382  clib_net_to_host_u32 (pkt->req_min_rx));
383  s = format (s, " required min echo rx interval: %u\n",
384  clib_net_to_host_u32 (pkt->req_min_echo_rx));
385  }
386  }
387 
388  return s;
389 }
390 
391 static void
393  int handling_wakeup)
394 {
395  BFD_DBG ("State changed: %U", format_bfd_session, bs);
396  bfd_event (bm, bs);
397  switch (bs->local_state)
398  {
399  case BFD_STATE_admin_down:
400  bfd_set_desired_min_tx (bm, bs, now,
403  handling_wakeup);
404  break;
405  case BFD_STATE_down:
406  bfd_set_desired_min_tx (bm, bs, now,
409  handling_wakeup);
410  break;
411  case BFD_STATE_init:
412  bfd_set_desired_min_tx (bm, bs, now,
415  handling_wakeup);
416  break;
417  case BFD_STATE_up:
419  handling_wakeup);
420  break;
421  }
422 }
423 
424 static void
426  bfd_session_t * bs)
427 {
428  switch (bs->transport)
429  {
430  case BFD_TRANSPORT_UDP4:
431  /* fallthrough */
432  case BFD_TRANSPORT_UDP6:
433  BFD_DBG ("Transport bfd via udp, bs_idx=%u", bs->bs_idx);
434  bfd_add_udp_transport (vm, b, &bs->udp);
435  break;
436  }
437 }
438 
439 static vlib_buffer_t *
441  bfd_session_t * bs)
442 {
443  u32 bi;
444  if (vlib_buffer_alloc (vm, &bi, 1) != 1)
445  {
446  clib_warning ("buffer allocation failure");
447  return NULL;
448  }
449 
450  vlib_buffer_t *b = vlib_get_buffer (vm, bi);
451  ASSERT (b->current_data == 0);
452 
453  u32 *to_next;
454  u32 n_left_to_next;
455 
456  vlib_get_next_frame (vm, rt, bfd_next_index_by_transport[bs->transport],
457  to_next, n_left_to_next);
458 
459  to_next[0] = bi;
460  n_left_to_next -= 1;
461 
462  vlib_put_next_frame (vm, rt, bfd_next_index_by_transport[bs->transport],
463  n_left_to_next);
464  return b;
465 }
466 
467 static void
469 {
470  bfd_pkt_t *pkt = vlib_buffer_get_current (b);
471  const u32 bfd_length = 24;
472  memset (pkt, 0, sizeof (*pkt));
473 
474  bfd_pkt_set_version (pkt, 1);
476  bfd_pkt_set_state (pkt, bs->local_state);
477  if (bs->local_demand && BFD_STATE_up == bs->local_state &&
478  BFD_STATE_up == bs->remote_state)
479  {
480  bfd_pkt_set_demand (pkt);
481  }
482  pkt->head.detect_mult = bs->local_detect_mult;
483  pkt->head.length = clib_host_to_net_u32 (bfd_length);
484  pkt->my_disc = bs->local_discr;
485  pkt->your_disc = bs->remote_discr;
486  pkt->des_min_tx = clib_host_to_net_u32 (bs->desired_min_tx_us);
487  pkt->req_min_rx = clib_host_to_net_u32 (bs->required_min_rx_us);
488  pkt->req_min_echo_rx = clib_host_to_net_u32 (0); /* FIXME */
489  b->current_length = bfd_length;
490 }
491 
492 static void
494  bfd_main_t * bm, bfd_session_t * bs, u64 now,
495  int handling_wakeup)
496 {
497  if (!bs->remote_min_rx_us)
498  {
499  BFD_DBG
500  ("bfd.RemoteMinRxInterval is zero, not sending periodic control "
501  "frame");
502  return;
503  }
504  /* FIXME
505  A system MUST NOT periodically transmit BFD Control packets if Demand
506  mode is active on the remote system (bfd.RemoteDemandMode is 1,
507  bfd.SessionState is Up, and bfd.RemoteSessionState is Up) and a Poll
508  Sequence is not being transmitted.
509  */
510  /* sometimes the wheel expires an event a bit sooner than requested, account
511  for that here */
512  if (now + bm->wheel_inaccuracy >= bs->tx_timeout_clocks)
513  {
514  BFD_DBG ("Send periodic control frame for bs_idx=%lu", bs->bs_idx);
515  vlib_buffer_t *b = bfd_create_frame (vm, rt, bs);
516  if (!b)
517  {
518  return;
519  }
520  bfd_init_control_frame (b, bs);
521  bfd_add_transport_layer (vm, b, bs);
522  bfd_calc_next_tx (bm, bs, now);
523  }
524  else
525  {
526  BFD_DBG
527  ("No need to send control frame now, now is %lu, tx_timeout is %lu",
528  now, bs->tx_timeout_clocks);
529  }
530  bfd_set_timer (bm, bs, now, handling_wakeup);
531 }
532 
533 void
535 {
536  BFD_DBG ("Send final control frame for bs_idx=%lu", bs->bs_idx);
537  bfd_init_control_frame (b, bs);
539  bfd_add_transport_layer (vm, b, bs);
540 }
541 
542 static void
544  int handling_wakeup)
545 {
546  /* sometimes the wheel expires an event a bit sooner than requested, account
547  for that here */
548  if (bs->last_rx_clocks + bs->detection_time_clocks <=
549  now + bm->wheel_inaccuracy)
550  {
551  BFD_DBG ("Rx timeout, session goes down");
552  bfd_set_diag (bs, BFD_DIAG_CODE_det_time_exp);
553  bfd_set_state (bm, bs, BFD_STATE_down, handling_wakeup);
554  }
555 }
556 
557 void
559  bfd_session_t * bs, u64 now)
560 {
561  BFD_DBG ("Timeout for bs_idx=%lu", bs->bs_idx);
562  switch (bs->local_state)
563  {
564  case BFD_STATE_admin_down:
565  BFD_ERR ("Unexpected timeout when in %s state",
567  abort ();
568  break;
569  case BFD_STATE_down:
570  bfd_send_periodic (vm, rt, bm, bs, now, 1);
571  break;
572  case BFD_STATE_init:
573  BFD_ERR ("Unexpected timeout when in %s state",
575  abort ();
576  break;
577  case BFD_STATE_up:
578  bfd_check_rx_timeout (bm, bs, now, 1);
579  bfd_send_periodic (vm, rt, bm, bs, now, 1);
580  break;
581  }
582 }
583 
584 /*
585  * bfd process node function
586  */
587 static uword
589 {
590  bfd_main_t *bm = &bfd_main;
591  u32 *expired = 0;
592  uword event_type, *event_data = 0;
593 
594  /* So we can send events to the bfd process */
595  bm->bfd_process_node_index = bfd_process_node.index;
596 
597  while (1)
598  {
599  u64 now = clib_cpu_time_now ();
600  u64 next_expire = timing_wheel_next_expiring_elt_time (&bm->wheel);
601  BFD_DBG ("timing_wheel_next_expiring_elt_time(%p) returns %lu",
602  &bm->wheel, next_expire);
603  if ((i64) next_expire < 0)
604  {
605  BFD_DBG ("wait for event without timeout");
606  (void) vlib_process_wait_for_event (vm);
607  event_type = vlib_process_get_events (vm, &event_data);
608  }
609  else
610  {
611  f64 timeout = ((i64) next_expire - (i64) now) / bm->cpu_cps;
612  BFD_DBG ("wait for event with timeout %.02f", timeout);
613  if (timeout < 0)
614  {
615  BFD_DBG ("negative timeout, already expired, skipping wait");
616  event_type = ~0;
617  }
618  else
619  {
620  (void) vlib_process_wait_for_event_or_clock (vm, timeout);
621  event_type = vlib_process_get_events (vm, &event_data);
622  }
623  }
624  now = clib_cpu_time_now ();
625  switch (event_type)
626  {
627  case ~0: /* no events => timeout */
628  /* nothing to do here */
629  break;
631  /* nothing to do here - reschedule is done automatically after
632  * each event or timeout */
633  break;
635  do
636  {
637  bfd_session_t *bs =
638  pool_elt_at_index (bm->sessions, *event_data);
639  bfd_send_periodic (vm, rt, bm, bs, now, 1);
640  }
641  while (0);
642  break;
643  default:
644  clib_warning ("BUG: event type 0x%wx", event_type);
645  break;
646  }
647  BFD_DBG ("advancing wheel, now is %lu", now);
648  BFD_DBG ("timing_wheel_advance (%p, %lu, %p, 0);", &bm->wheel, now,
649  expired);
650  expired = timing_wheel_advance (&bm->wheel, now, expired, 0);
651  BFD_DBG ("Expired %d elements", vec_len (expired));
652  u32 *p = NULL;
653  vec_foreach (p, expired)
654  {
655  const u32 bs_idx = *p;
656  if (!pool_is_free_index (bm->sessions, bs_idx))
657  {
658  bfd_session_t *bs = pool_elt_at_index (bm->sessions, bs_idx);
659  bfd_on_timeout (vm, rt, bm, bs, now);
660  }
661  }
662  if (expired)
663  {
664  _vec_len (expired) = 0;
665  }
666  if (event_data)
667  {
668  _vec_len (event_data) = 0;
669  }
670  }
671 
672  return 0;
673 }
674 
675 /*
676  * bfd process node declaration
677  */
678 /* *INDENT-OFF* */
679 VLIB_REGISTER_NODE (bfd_process_node, static) = {
680  .function = bfd_process,
681  .type = VLIB_NODE_TYPE_PROCESS,
682  .name = "bfd-process",
683  .n_next_nodes = BFD_OUTPUT_N_NEXT,
684  .next_nodes =
685  {
686 #define F(t, n) [BFD_OUTPUT_##t] = n,
688 #undef F
689  },
690 };
691 /* *INDENT-ON* */
692 
693 static clib_error_t *
695 {
696  // bfd_main_t *bm = &bfd_main;
697  // vnet_hw_interface_t *hi = vnet_get_sup_hw_interface (vnm, sw_if_index);
698  if (!(flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP))
699  {
700  /* TODO */
701  }
702  return 0;
703 }
704 
706 
707 static clib_error_t *
709 {
710  // bfd_main_t *bm = &bfd_main;
711  if (flags & VNET_HW_INTERFACE_FLAG_LINK_UP)
712  {
713  /* TODO */
714  }
715  return 0;
716 }
717 
719 
720 /*
721  * setup function
722  */
723 static clib_error_t *
725 {
726  bfd_main_t *bm = &bfd_main;
728  bm->vlib_main = vm;
729  bm->vnet_main = vnet_get_main ();
730  memset (&bm->wheel, 0, sizeof (bm->wheel));
731  bm->cpu_cps = 2590000000; // vm->clib_time.clocks_per_second;
732  BFD_DBG ("cps is %.2f", bm->cpu_cps);
733  const u64 now = clib_cpu_time_now ();
734  timing_wheel_init (&bm->wheel, now, bm->cpu_cps);
736 
737  return 0;
738 }
739 
741 
744 {
745  bfd_session_t *result;
746  pool_get (bm->sessions, result);
747  memset (result, 0, sizeof (*result));
748  result->bs_idx = result - bm->sessions;
749  result->transport = t;
750  result->local_discr = random_u32 (&bm->random_seed);
751  bfd_set_defaults (bm, result);
752  hash_set (bm->session_by_disc, result->local_discr, result->bs_idx);
753  return result;
754 }
755 
756 void
758 {
760  pool_put (bm->sessions, bs);
761 }
762 
765 {
766  if (!pool_is_free_index (bm->sessions, bs_idx))
767  {
768  return pool_elt_at_index (bm->sessions, bs_idx);
769  }
770  return NULL;
771 }
772 
775 {
776  uword *p = hash_get (bfd_main.session_by_disc, disc);
777  if (p)
778  {
779  return pool_elt_at_index (bfd_main.sessions, *p);
780  }
781  return NULL;
782 }
783 
784 /**
785  * @brief verify bfd packet - common checks
786  *
787  * @param pkt
788  *
789  * @return 1 if bfd packet is valid
790  */
791 int
792 bfd_verify_pkt_common (const bfd_pkt_t * pkt)
793 {
794  if (1 != bfd_pkt_get_version (pkt))
795  {
796  BFD_ERR ("BFD verification failed - unexpected version: '%d'",
797  bfd_pkt_get_version (pkt));
798  return 0;
799  }
800  if (pkt->head.length < sizeof (bfd_pkt_t) ||
801  (bfd_pkt_get_auth_present (pkt) &&
802  pkt->head.length < sizeof (bfd_pkt_with_auth_t)))
803  {
804  BFD_ERR ("BFD verification failed - unexpected length: '%d' (auth "
805  "present: %d)",
806  pkt->head.length, bfd_pkt_get_auth_present (pkt));
807  return 0;
808  }
809  if (!pkt->head.detect_mult)
810  {
811  BFD_ERR ("BFD verification failed - unexpected detect-mult: '%d'",
812  pkt->head.detect_mult);
813  return 0;
814  }
815  if (bfd_pkt_get_multipoint (pkt))
816  {
817  BFD_ERR ("BFD verification failed - unexpected multipoint: '%d'",
818  bfd_pkt_get_multipoint (pkt));
819  return 0;
820  }
821  if (!pkt->my_disc)
822  {
823  BFD_ERR ("BFD verification failed - unexpected my-disc: '%d'",
824  pkt->my_disc);
825  return 0;
826  }
827  if (!pkt->your_disc)
828  {
829  const u8 pkt_state = bfd_pkt_get_state (pkt);
830  if (pkt_state != BFD_STATE_down && pkt_state != BFD_STATE_admin_down)
831  {
832  BFD_ERR ("BFD verification failed - unexpected state: '%s' "
833  "(your-disc is zero)", bfd_state_string (pkt_state));
834  return 0;
835  }
836  }
837  return 1;
838 }
839 
840 /**
841  * @brief verify bfd packet - authentication
842  *
843  * @param pkt
844  *
845  * @return 1 if bfd packet is valid
846  */
847 int
848 bfd_verify_pkt_session (const bfd_pkt_t * pkt, u16 pkt_size,
849  const bfd_session_t * bs)
850 {
851  const bfd_pkt_with_auth_t *with_auth = (bfd_pkt_with_auth_t *) pkt;
852  if (!bfd_pkt_get_auth_present (pkt))
853  {
854  if (pkt_size > sizeof (*pkt))
855  {
856  BFD_ERR ("BFD verification failed - unexpected packet size '%d' "
857  "(auth not present)", pkt_size);
858  return 0;
859  }
860  }
861  else
862  {
863  if (!with_auth->auth.type)
864  {
865  BFD_ERR ("BFD verification failed - unexpected auth type: '%d'",
866  with_auth->auth.type);
867  return 0;
868  }
869  /* TODO FIXME - implement the actual verification */
870  }
871  return 1;
872 }
873 
874 void
875 bfd_consume_pkt (bfd_main_t * bm, const bfd_pkt_t * pkt, u32 bs_idx)
876 {
877  bfd_session_t *bs = bfd_find_session_by_idx (bm, bs_idx);
878  if (!bs)
879  {
880  return;
881  }
882  BFD_DBG ("Scanning bfd packet, bs_idx=%d", bs->bs_idx);
883  bs->remote_discr = pkt->my_disc;
884  bs->remote_state = bfd_pkt_get_state (pkt);
885  bs->remote_demand = bfd_pkt_get_demand (pkt);
886  u64 now = clib_cpu_time_now ();
887  bs->last_rx_clocks = now;
888  bs->remote_desired_min_tx_us = clib_net_to_host_u32 (pkt->des_min_tx);
889  bs->remote_detect_mult = pkt->head.detect_mult;
890  bfd_set_remote_required_min_rx (bm, bs, now,
891  clib_net_to_host_u32 (pkt->req_min_rx), 0);
892  /* FIXME
893  If the Required Min Echo RX Interval field is zero, the
894  transmission of Echo packets, if any, MUST cease.
895 
896  If a Poll Sequence is being transmitted by the local system and
897  the Final (F) bit in the received packet is set, the Poll Sequence
898  MUST be terminated.
899  */
900  /* FIXME 6.8.2 */
901  /* FIXME 6.8.4 */
902  if (BFD_STATE_admin_down == bs->local_state)
903  return;
904  if (BFD_STATE_admin_down == bs->remote_state)
905  {
906  bfd_set_diag (bs, BFD_DIAG_CODE_neighbor_sig_down);
907  bfd_set_state (bm, bs, BFD_STATE_down, 0);
908  }
909  else if (BFD_STATE_down == bs->local_state)
910  {
911  if (BFD_STATE_down == bs->remote_state)
912  {
913  bfd_set_state (bm, bs, BFD_STATE_init, 0);
914  }
915  else if (BFD_STATE_init == bs->remote_state)
916  {
917  bfd_set_state (bm, bs, BFD_STATE_up, 0);
918  }
919  }
920  else if (BFD_STATE_init == bs->local_state)
921  {
922  if (BFD_STATE_up == bs->remote_state ||
923  BFD_STATE_init == bs->remote_state)
924  {
925  bfd_set_state (bm, bs, BFD_STATE_up, 0);
926  }
927  }
928  else /* BFD_STATE_up == bs->local_state */
929  {
930  if (BFD_STATE_down == bs->remote_state)
931  {
932  bfd_set_diag (bs, BFD_DIAG_CODE_neighbor_sig_down);
933  bfd_set_state (bm, bs, BFD_STATE_down, 0);
934  }
935  }
936 }
937 
938 u8 *
939 format_bfd_session (u8 * s, va_list * args)
940 {
941  const bfd_session_t *bs = va_arg (*args, bfd_session_t *);
942  return format (s, "BFD(%u): bfd.SessionState=%s, "
943  "bfd.RemoteSessionState=%s, "
944  "bfd.LocalDiscr=%u, "
945  "bfd.RemoteDiscr=%u, "
946  "bfd.LocalDiag=%s, "
947  "bfd.DesiredMinTxInterval=%u, "
948  "bfd.RequiredMinRxInterval=%u, "
949  "bfd.RemoteMinRxInterval=%u, "
950  "bfd.DemandMode=%s, "
951  "bfd.RemoteDemandMode=%s, "
952  "bfd.DetectMult=%u, ",
957  bs->remote_min_rx_us, (bs->local_demand ? "yes" : "no"),
958  (bs->remote_demand ? "yes" : "no"), bs->local_detect_mult);
959 }
960 
962 
963 /*
964  * fd.io coding-style-patch-verification: ON
965  *
966  * Local Variables:
967  * eval: (c-set-style "gnu")
968  * End:
969  */
void vlib_put_next_frame(vlib_main_t *vm, vlib_node_runtime_t *r, u32 next_index, u32 n_vectors_left)
Release pointer to next frame vector data.
Definition: main.c:459
VNET_HW_INTERFACE_LINK_UP_DOWN_FUNCTION(bfd_hw_interface_up_down)
u8 bfd_pkt_get_auth_present(const bfd_pkt_t *pkt)
Definition: bfd_protocol.c:55
static void bfd_on_state_change(bfd_main_t *bm, bfd_session_t *bs, u64 now, int handling_wakeup)
Definition: bfd_main.c:392
vnet_api_error_t
Definition: api_errno.h:97
#define hash_set(h, key, value)
Definition: hash.h:254
void bfd_consume_pkt(bfd_main_t *bm, const bfd_pkt_t *pkt, u32 bs_idx)
Definition: bfd_main.c:875
#define clib_min(x, y)
Definition: clib.h:326
#define CLIB_UNUSED(x)
Definition: clib.h:79
static uword random_default_seed(void)
Default random seed (unix/linux user-mode)
Definition: random.h:91
static f64 vlib_process_wait_for_event_or_clock(vlib_main_t *vm, f64 dt)
Suspend a cooperative multi-tasking thread Waits for an event, or for the indicated number of seconds...
Definition: node_funcs.h:684
#define hash_unset(h, key)
Definition: hash.h:260
static uword * vlib_process_wait_for_event(vlib_main_t *vm)
Definition: node_funcs.h:604
const char * bfd_state_string(bfd_state_e state)
Definition: bfd_main.c:319
bfd_main_t bfd_main
Definition: bfd_main.c:961
u8 remote_demand
Definition: bfd_main.h:94
void bfd_on_timeout(vlib_main_t *vm, vlib_node_runtime_t *rt, bfd_main_t *bm, bfd_session_t *bs, u64 now)
Definition: bfd_main.c:558
#define BFD_ERR(...)
Definition: bfd_debug.h:68
void timing_wheel_init(timing_wheel_t *w, u64 current_cpu_time, f64 cpu_clocks_per_second)
Definition: timing_wheel.c:21
u8 bfd_pkt_get_diag_code(const bfd_pkt_t *pkt)
Definition: bfd_protocol.c:14
static uword bfd_process(vlib_main_t *vm, vlib_node_runtime_t *rt, vlib_frame_t *f)
Definition: bfd_main.c:588
bfd_session_t * bfd_find_session_by_disc(bfd_main_t *bm, u32 disc)
Definition: bfd_main.c:774
u64 timing_wheel_next_expiring_elt_time(timing_wheel_t *w)
Definition: timing_wheel.c:340
#define NULL
Definition: clib.h:55
int bfd_verify_pkt_common(const bfd_pkt_t *pkt)
verify bfd packet - common checks
Definition: bfd_main.c:792
static void bfd_set_state(bfd_main_t *bm, bfd_session_t *bs, bfd_state_e new_state, int handling_wakeup)
Definition: bfd_main.c:91
static u64 clib_cpu_time_now(void)
Definition: time.h:73
struct _vlib_node_registration vlib_node_registration_t
static void bfd_set_desired_min_tx(bfd_main_t *bm, bfd_session_t *bs, u64 now, u32 desired_min_tx_us, int handling_wakeup)
Definition: bfd_main.c:248
u8 local_demand
Definition: bfd_main.h:91
void bfd_put_session(bfd_main_t *bm, bfd_session_t *bs)
Definition: bfd_main.c:757
u32 config_desired_min_tx_us
Definition: bfd_main.h:70
static u64 bfd_us_to_clocks(bfd_main_t *bm, u64 us)
Definition: bfd_main.c:30
#define VNET_HW_INTERFACE_FLAG_LINK_UP
Definition: interface.h:377
bfd_diag_code_e
Definition: bfd_protocol.h:119
u32 bfd_process_node_index
Definition: bfd_main.h:147
u8 bfd_pkt_get_version(const bfd_pkt_t *pkt)
Definition: bfd_protocol.c:3
void timing_wheel_insert(timing_wheel_t *w, u64 insert_cpu_time, u32 user_data)
Definition: timing_wheel.c:292
#define pool_get(P, E)
Allocate an object E from a pool P (unspecified alignment).
Definition: pool.h:200
u32 remote_desired_min_tx_us
Definition: bfd_main.h:88
u64 last_rx_clocks
Definition: bfd_main.h:112
u64 tx_timeout_clocks
Definition: bfd_main.h:109
timing_wheel_t wheel
Definition: bfd_main.h:138
u32 local_discr
Definition: bfd_main.h:64
bfd_transport_t transport
Definition: bfd_main.h:118
vnet_main_t * vnet_get_main(void)
Definition: misc.c:46
i16 current_data
signed offset in data[], pre_data[] that we are currently processing.
Definition: buffer.h:78
static vlib_buffer_t * bfd_create_frame(vlib_main_t *vm, vlib_node_runtime_t *rt, bfd_session_t *bs)
Definition: bfd_main.c:440
u32 random_seed
Definition: bfd_main.h:157
#define VLIB_INIT_FUNCTION(x)
Definition: init.h:111
static uword vlib_process_get_events(vlib_main_t *vm, uword **data_vector)
Return the first event type which has occurred and a vector of per-event data of that type...
Definition: node_funcs.h:527
static void * vlib_buffer_get_current(vlib_buffer_t *b)
Get pointer to current data to process.
Definition: buffer.h:194
u64 transmit_interval_clocks
Definition: bfd_main.h:106
void bfd_send_final(vlib_main_t *vm, vlib_buffer_t *b, bfd_session_t *bs)
Definition: bfd_main.c:534
#define clib_warning(format, args...)
Definition: error.h:59
unsigned long u64
Definition: types.h:89
static vlib_node_registration_t bfd_process_node
(constructor) VLIB_REGISTER_NODE (bfd_process_node)
Definition: bfd_main.c:35
static void bfd_add_transport_layer(vlib_main_t *vm, vlib_buffer_t *b, bfd_session_t *bs)
Definition: bfd_main.c:425
static void bfd_set_remote_required_min_rx(bfd_main_t *bm, bfd_session_t *bs, u64 now, u32 remote_required_min_rx_us, int handling_wakeup)
Definition: bfd_main.c:263
void bfd_event(bfd_main_t *bm, bfd_session_t *bs)
Definition: api.c:6889
bfd_session_t * bfd_find_session_by_idx(bfd_main_t *bm, uword bs_idx)
Definition: bfd_main.c:764
bfd_session_t * sessions
Definition: bfd_main.h:135
#define hash_get(h, key)
Definition: hash.h:248
bfd_state_e remote_state
Definition: bfd_main.h:61
#define pool_elt_at_index(p, i)
Returns pointer to element at given index.
Definition: pool.h:369
static clib_error_t * bfd_sw_interface_up_down(vnet_main_t *vnm, u32 sw_if_index, u32 flags)
Definition: bfd_main.c:694
u16 current_length
Nbytes between current data and the end of this buffer.
Definition: buffer.h:82
static void vlib_process_signal_event(vlib_main_t *vm, uword node_index, uword type_opaque, uword data)
Definition: node_funcs.h:931
u8 bfd_pkt_get_control_plane_independent(const bfd_pkt_t *pkt)
Definition: bfd_protocol.c:48
f64 cpu_cps
Definition: bfd_main.h:154
BFD global declarations.
#define pool_put(P, E)
Free an object E in pool P.
Definition: pool.h:214
static void bfd_set_diag(bfd_session_t *bs, bfd_diag_code_e code)
Definition: bfd_main.c:80
vnet_api_error_t bfd_del_session(uword bs_idx)
Definition: bfd_main.c:288
u8 remote_detect_mult
Definition: bfd_main.h:100
#define vlib_get_next_frame(vm, node, next_index, vectors, n_vectors_left)
Get pointer to next frame vector data by (vlib_node_runtime_t, next_index).
Definition: node_funcs.h:350
long i64
Definition: types.h:82
u8 bfd_pkt_get_final(const bfd_pkt_t *pkt)
Definition: bfd_protocol.c:42
static void bfd_init_control_frame(vlib_buffer_t *b, bfd_session_t *bs)
Definition: bfd_main.c:468
void bfd_pkt_set_final(bfd_pkt_t *pkt)
Definition: bfd_protocol.c:40
void bfd_session_start(bfd_main_t *bm, bfd_session_t *bs)
Definition: bfd_main.c:279
vnet_main_t * vnet_main
Definition: bfd_main.h:151
u8 bfd_pkt_get_multipoint(const bfd_pkt_t *pkt)
Definition: bfd_protocol.c:69
u64 wheel_time_clocks
Definition: bfd_main.h:103
void bfd_pkt_set_demand(bfd_pkt_t *pkt)
Definition: bfd_protocol.c:67
static void bfd_recalc_tx_interval(bfd_main_t *bm, bfd_session_t *bs)
Definition: bfd_main.c:105
u32 remote_discr
Definition: bfd_main.h:67
BFD protocol declarations.
bfd_input_next_t
Definition: bfd_main.c:56
static void bfd_calc_next_tx(bfd_main_t *bm, bfd_session_t *bs, u64 now)
Definition: bfd_main.c:122
u8 * format_bfd_session(u8 *s, va_list *args)
Definition: bfd_main.c:939
u32 * timing_wheel_advance(timing_wheel_t *w, u64 advance_cpu_time, u32 *expired_user_data, u64 *next_expiring_element_cpu_time)
Definition: timing_wheel.c:588
u8 bfd_pkt_get_demand(const bfd_pkt_t *pkt)
Definition: bfd_protocol.c:62
BFD global declarations.
#define pool_is_free_index(P, I)
Use free bitmap to query whether given index is free.
Definition: pool.h:211
bfd_state_e
Definition: bfd_protocol.h:137
u8 * bfd_input_format_trace(u8 *s, va_list *args)
Definition: bfd_main.c:354
#define BFD_DBG(...)
Definition: bfd_debug.h:67
u32 remote_min_rx_us
Definition: bfd_main.h:82
void bfd_pkt_set_version(bfd_pkt_t *pkt, int version)
Definition: bfd_protocol.c:8
#define VNET_SW_INTERFACE_FLAG_ADMIN_UP
Definition: interface.h:528
#define ASSERT(truth)
void bfd_add_udp_transport(vlib_main_t *vm, vlib_buffer_t *b, bfd_udp_session_t *bus)
Definition: bfd_udp.c:75
static void bfd_recalc_detection_time(bfd_main_t *bm, bfd_session_t *bs)
Definition: bfd_main.c:178
unsigned int u32
Definition: types.h:88
bfd_state_e local_state
Definition: bfd_main.h:55
static void bfd_send_periodic(vlib_main_t *vm, vlib_node_runtime_t *rt, bfd_main_t *bm, bfd_session_t *bs, u64 now, int handling_wakeup)
Definition: bfd_main.c:493
vhost_vring_state_t state
Definition: vhost-user.h:80
u8 bfd_pkt_get_state(const bfd_pkt_t *pkt)
Definition: bfd_protocol.c:25
static f64 random_f64(u32 *seed)
Generate f64 random number in the interval [0,1].
Definition: random.h:145
u32 desired_min_tx_us
Definition: bfd_main.h:73
u32 vlib_buffer_alloc(vlib_main_t *vm, u32 *buffers, u32 n_buffers)
Allocate buffers into supplied array.
bfd_transport_t
Definition: bfd_main.h:31
u64 desired_min_tx_clocks
Definition: bfd_main.h:76
vlib_main_t * vlib_main
Definition: bfd_main.h:150
#define clib_max(x, y)
Definition: clib.h:319
u32 * session_by_disc
Definition: bfd_main.h:144
u64 uword
Definition: types.h:112
u32 required_min_rx_us
Definition: bfd_main.h:79
unsigned short u16
Definition: types.h:57
static void bfd_set_timer(bfd_main_t *bm, bfd_session_t *bs, u64 now, int handling_wakeup)
Definition: bfd_main.c:201
bfd_diag_code_e local_diag
Definition: bfd_main.h:58
#define vec_len(v)
Number of elements in vector (rvalue-only, NULL tolerant)
double f64
Definition: types.h:142
unsigned char u8
Definition: types.h:56
static void bfd_set_defaults(bfd_main_t *bm, bfd_session_t *bs)
Definition: bfd_main.c:66
#define F(t, n)
Definition: bfd_main.c:39
u8 bfd_pkt_get_poll(const bfd_pkt_t *pkt)
Definition: bfd_protocol.c:35
Linear Congruential Random Number Generator.
static u32 random_u32(u32 *seed)
32-bit random number generator
Definition: random.h:69
#define VLIB_REGISTER_NODE(x,...)
Definition: node.h:143
u8 * format(u8 *s, const char *fmt,...)
Definition: format.c:418
bfd_output_next_t
Definition: bfd_main.c:37
#define STRUCT_SIZE_OF(t, f)
Definition: clib.h:64
u64 detection_time_clocks
Definition: bfd_main.h:115
#define vec_foreach(var, vec)
Vector iterator.
u64 remote_min_rx_clocks
Definition: bfd_main.h:85
u8 local_detect_mult
Definition: bfd_main.h:97
#define BFD_DEFAULT_DESIRED_MIN_TX_US
Definition: bfd_main.h:210
#define USEC_PER_SECOND
Definition: bfd_main.h:207
const char * bfd_diag_code_string(bfd_diag_code_e diag)
Definition: bfd_main.c:306
u32 flags
Definition: vhost-user.h:75
bfd_session_t * bfd_get_session(bfd_main_t *bm, bfd_transport_t t)
Definition: bfd_main.c:743
bfd_udp_session_t udp
Definition: bfd_main.h:122
void bfd_pkt_set_state(bfd_pkt_t *pkt, int value)
Definition: bfd_protocol.c:30
static clib_error_t * bfd_hw_interface_up_down(vnet_main_t *vnm, u32 hw_if_index, u32 flags)
Definition: bfd_main.c:708
static vlib_buffer_t * vlib_get_buffer(vlib_main_t *vm, u32 buffer_index)
Translate buffer index into buffer pointer.
Definition: buffer_funcs.h:57
int bfd_verify_pkt_session(const bfd_pkt_t *pkt, u16 pkt_size, const bfd_session_t *bs)
verify bfd packet - authentication
Definition: bfd_main.c:848
void bfd_pkt_set_diag_code(bfd_pkt_t *pkt, int value)
Definition: bfd_protocol.c:19
static clib_error_t * bfd_main_init(vlib_main_t *vm)
Definition: bfd_main.c:724
vnet_api_error_t bfd_session_set_flags(u32 bs_idx, u8 admin_up_down)
Definition: bfd_main.c:332
u64 wheel_inaccuracy
Definition: bfd_main.h:141
VNET_SW_INTERFACE_ADMIN_UP_DOWN_FUNCTION(bfd_sw_interface_up_down)
static void bfd_check_rx_timeout(bfd_main_t *bm, bfd_session_t *bs, u64 now, int handling_wakeup)
Definition: bfd_main.c:543