FD.io VPP  v18.01-8-g0eacf49
Vector Packet Processing
bfd_udp.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 UDP transport layer implementation
18  */
19 #include <vppinfra/types.h>
20 #include <vlibmemory/api.h>
21 #include <vlib/vlib.h>
22 #include <vlib/buffer.h>
23 #include <vnet/ip/format.h>
24 #include <vnet/ethernet/packet.h>
25 #include <vnet/udp/udp_packet.h>
26 #include <vnet/udp/udp.h>
27 #include <vnet/ip/lookup.h>
28 #include <vnet/ip/icmp46_packet.h>
29 #include <vnet/ip/ip4.h>
30 #include <vnet/ip/ip6.h>
31 #include <vnet/ip/ip6_packet.h>
32 #include <vnet/adj/adj.h>
33 #include <vnet/adj/adj_nbr.h>
34 #include <vnet/dpo/receive_dpo.h>
35 #include <vnet/fib/fib_entry.h>
36 #include <vnet/fib/fib_table.h>
37 #include <vnet/bfd/bfd_debug.h>
38 #include <vnet/bfd/bfd_udp.h>
39 #include <vnet/bfd/bfd_main.h>
40 #include <vnet/bfd/bfd_api.h>
41 
42 typedef struct
43 {
45  /* hashmap - bfd session index by bfd key - used for CLI/API lookup, where
46  * discriminator is unknown */
48  /* convenience variable */
50  /* flag indicating whether echo_source_sw_if_index holds a valid value */
52  /* loopback interface used to get echo source ip */
54  /* node index of "ip4-arp" node */
56  /* node index of "ip6-discover-neighbor" node */
58  /* node index of "ip4-rewrite" node */
60  /* node index of "ip6-rewrite" node */
63 
68 
70 
73 {
74  vnet_sw_interface_t *sw_if =
75  vnet_get_sw_interface_safe (bfd_udp_main.vnet_main, sw_if_index);
76  if (sw_if)
77  {
78  bfd_udp_main.echo_source_sw_if_index = sw_if_index;
79  bfd_udp_main.echo_source_is_set = 1;
80  return 0;
81  }
82  return VNET_API_ERROR_BFD_ENOENT;
83 }
84 
87 {
88  bfd_udp_main.echo_source_sw_if_index = ~0;
89  bfd_udp_main.echo_source_is_set = 0;
90  return 0;
91 }
92 
93 int
95 {
96  if (!bfd_udp_main.echo_source_is_set)
97  {
98  BFD_DBG ("UDP echo source not set - echo not available");
99  return 0;
100  }
101  /*
102  * for the echo to work, we need a loopback interface with at least one
103  * address with netmask length at most 31 (ip4) or 127 (ip6) so that we can
104  * pick an unused address from that subnet
105  */
106  vnet_sw_interface_t *sw_if =
108  bfd_udp_main.echo_source_sw_if_index);
109  if (sw_if && sw_if->flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP)
110  {
111  if (BFD_TRANSPORT_UDP4 == transport)
112  {
113  ip4_main_t *im = &ip4_main;
115  /* *INDENT-OFF* */
117  bfd_udp_main.echo_source_sw_if_index,
118  0 /* honor unnumbered */, ({
119  if (ia->address_length <= 31)
120  {
121  return 1;
122  }
123  }));
124  /* *INDENT-ON* */
125  }
126  else if (BFD_TRANSPORT_UDP6 == transport)
127  {
128  ip6_main_t *im = &ip6_main;
130  /* *INDENT-OFF* */
132  bfd_udp_main.echo_source_sw_if_index,
133  0 /* honor unnumbered */, ({
134  if (ia->address_length <= 127)
135  {
136  return 1;
137  }
138  }));
139  /* *INDENT-ON* */
140  }
141  }
142  BFD_DBG ("No usable IP address for UDP echo - echo not available");
143  return 0;
144 }
145 
146 static u16
148 {
149  /* The source port MUST be in the range 49152 through 65535. The same UDP
150  * source port number MUST be used for all BFD Control packets associated
151  * with a particular session. The source port number SHOULD be unique among
152  * all BFD sessions on the system. If more than 16384 BFD sessions are
153  * simultaneously active, UDP source port numbers MAY be reused on
154  * multiple sessions, but the number of distinct uses of the same UDP
155  * source port number SHOULD be minimized.
156  */
157  return 49152 + bs_idx % (65535 - 49152 + 1);
158 }
159 
160 int
162 {
163  if (!bfd_udp_main.echo_source_is_set)
164  {
165  BFD_ERR ("cannot find ip4 address, echo source not set");
166  return 0;
167  }
169  ip4_main_t *im = &ip4_main;
170 
171  /* *INDENT-OFF* */
173  &im->lookup_main, ia, bfd_udp_main.echo_source_sw_if_index,
174  0 /* honor unnumbered */, ({
175  ip4_address_t *x =
176  ip_interface_address_get_address (&im->lookup_main, ia);
177  if (ia->address_length <= 31)
178  {
179  addr->as_u32 = clib_host_to_net_u32 (x->as_u32);
180  /*
181  * flip the last bit to get a different address, might be network,
182  * we don't care ...
183  */
184  addr->as_u32 ^= 1;
185  addr->as_u32 = clib_net_to_host_u32 (addr->as_u32);
186  return 1;
187  }
188  }));
189  /* *INDENT-ON* */
190  BFD_ERR ("cannot find ip4 address, no usable address found");
191  return 0;
192 }
193 
194 int
196 {
197  if (!bfd_udp_main.echo_source_is_set)
198  {
199  BFD_ERR ("cannot find ip6 address, echo source not set");
200  return 0;
201  }
203  ip6_main_t *im = &ip6_main;
204 
205  /* *INDENT-OFF* */
207  &im->lookup_main, ia, bfd_udp_main.echo_source_sw_if_index,
208  0 /* honor unnumbered */, ({
209  ip6_address_t *x =
210  ip_interface_address_get_address (&im->lookup_main, ia);
211  if (ia->address_length <= 127)
212  {
213  *addr = *x;
214  addr->as_u8[15] ^= 1; /* flip the last bit of the address */
215  return 1;
216  }
217  }));
218  /* *INDENT-ON* */
219  BFD_ERR ("cannot find ip6 address, no usable address found");
220  return 0;
221 }
222 
223 void
224 bfd_udp_get_echo_source (int *is_set, u32 * sw_if_index,
225  int *have_usable_ip4, ip4_address_t * ip4,
226  int *have_usable_ip6, ip6_address_t * ip6)
227 {
228  if (bfd_udp_main.echo_source_is_set)
229  {
230  *is_set = 1;
231  *sw_if_index = bfd_udp_main.echo_source_sw_if_index;
232  *have_usable_ip4 = bfd_udp_get_echo_src_ip4 (ip4);
233  *have_usable_ip6 = bfd_udp_get_echo_src_ip6 (ip6);
234  }
235  else
236  {
237  *is_set = 0;
238  }
239 }
240 
241 int
243  int is_echo)
244 {
245  const bfd_udp_session_t *bus = &bs->udp;
246  const bfd_udp_key_t *key = &bus->key;
247  vlib_buffer_t *b = vlib_get_buffer (vm, bi);
248 
249  b->flags |= VNET_BUFFER_F_LOCALLY_ORIGINATED;
250  vnet_buffer (b)->ip.adj_index[VLIB_RX] = bus->adj_index;
251  vnet_buffer (b)->ip.adj_index[VLIB_TX] = bus->adj_index;
252  vnet_buffer (b)->sw_if_index[VLIB_RX] = 0;
253  vnet_buffer (b)->sw_if_index[VLIB_TX] = ~0;
254  typedef struct
255  {
256  ip4_header_t ip4;
257  udp_header_t udp;
258  } ip4_udp_headers;
259  ip4_udp_headers *headers = NULL;
260  vlib_buffer_advance (b, -sizeof (*headers));
261  headers = vlib_buffer_get_current (b);
262  memset (headers, 0, sizeof (*headers));
263  headers->ip4.ip_version_and_header_length = 0x45;
264  headers->ip4.ttl = 255;
265  headers->ip4.protocol = IP_PROTOCOL_UDP;
266  headers->udp.src_port =
267  clib_host_to_net_u16 (bfd_udp_bs_idx_to_sport (bs->bs_idx));
268  if (is_echo)
269  {
270  int rv;
271  if (!(rv = bfd_udp_get_echo_src_ip4 (&headers->ip4.src_address)))
272  {
273  return rv;
274  }
275  headers->ip4.dst_address.as_u32 = key->local_addr.ip4.as_u32;
276  headers->udp.dst_port = clib_host_to_net_u16 (UDP_DST_PORT_bfd_echo4);
277  }
278  else
279  {
280  headers->ip4.src_address.as_u32 = key->local_addr.ip4.as_u32;
281  headers->ip4.dst_address.as_u32 = key->peer_addr.ip4.as_u32;
282  headers->udp.dst_port = clib_host_to_net_u16 (UDP_DST_PORT_bfd4);
283  }
284 
285  /* fix ip length, checksum and udp length */
286  const u16 ip_length = vlib_buffer_length_in_chain (vm, b);
287 
288  headers->ip4.length = clib_host_to_net_u16 (ip_length);
289  headers->ip4.checksum = ip4_header_checksum (&headers->ip4);
290 
291  const u16 udp_length = ip_length - (sizeof (headers->ip4));
292  headers->udp.length = clib_host_to_net_u16 (udp_length);
293  return 1;
294 }
295 
296 int
298  int is_echo)
299 {
300  const bfd_udp_session_t *bus = &bs->udp;
301  const bfd_udp_key_t *key = &bus->key;
302  vlib_buffer_t *b = vlib_get_buffer (vm, bi);
303 
304  b->flags |= VNET_BUFFER_F_LOCALLY_ORIGINATED;
305  vnet_buffer (b)->ip.adj_index[VLIB_RX] = bus->adj_index;
306  vnet_buffer (b)->ip.adj_index[VLIB_TX] = bus->adj_index;
307  vnet_buffer (b)->sw_if_index[VLIB_RX] = 0;
308  vnet_buffer (b)->sw_if_index[VLIB_TX] = 0;
309  typedef struct
310  {
311  ip6_header_t ip6;
312  udp_header_t udp;
313  } ip6_udp_headers;
314  ip6_udp_headers *headers = NULL;
315  vlib_buffer_advance (b, -sizeof (*headers));
316  headers = vlib_buffer_get_current (b);
317  memset (headers, 0, sizeof (*headers));
318  headers->ip6.ip_version_traffic_class_and_flow_label =
319  clib_host_to_net_u32 (0x6 << 28);
320  headers->ip6.hop_limit = 255;
321  headers->ip6.protocol = IP_PROTOCOL_UDP;
322  headers->udp.src_port =
323  clib_host_to_net_u16 (bfd_udp_bs_idx_to_sport (bs->bs_idx));
324  if (is_echo)
325  {
326  int rv;
327  if (!(rv = bfd_udp_get_echo_src_ip6 (&headers->ip6.src_address)))
328  {
329  return rv;
330  }
331  clib_memcpy (&headers->ip6.dst_address, &key->local_addr.ip6,
332  sizeof (headers->ip6.dst_address));
333 
334  headers->udp.dst_port = clib_host_to_net_u16 (UDP_DST_PORT_bfd_echo6);
335  }
336  else
337  {
338  clib_memcpy (&headers->ip6.src_address, &key->local_addr.ip6,
339  sizeof (headers->ip6.src_address));
340  clib_memcpy (&headers->ip6.dst_address, &key->peer_addr.ip6,
341  sizeof (headers->ip6.dst_address));
342  headers->udp.dst_port = clib_host_to_net_u16 (UDP_DST_PORT_bfd6);
343  }
344 
345  /* fix ip payload length and udp length */
346  const u16 udp_length =
347  vlib_buffer_length_in_chain (vm, b) - (sizeof (headers->ip6));
348  headers->udp.length = clib_host_to_net_u16 (udp_length);
349  headers->ip6.payload_length = headers->udp.length;
350 
351  /* IPv6 UDP checksum is mandatory */
352  int bogus = 0;
353  headers->udp.checksum =
354  ip6_tcp_udp_icmp_compute_checksum (vm, b, &headers->ip6, &bogus);
355  ASSERT (bogus == 0);
356  if (headers->udp.checksum == 0)
357  {
358  headers->udp.checksum = 0xffff;
359  }
360  return 1;
361 }
362 
363 static void
365 {
366  vlib_frame_t *f = vlib_get_frame_to_node (vm, next_node);
367  u32 *to_next = vlib_frame_vector_args (f);
368  to_next[0] = bi;
369  f->n_vectors = 1;
370  vlib_put_frame_to_node (vm, next_node, f);
371 }
372 
373 int
374 bfd_udp_calc_next_node (const struct bfd_session_s *bs, u32 * next_node)
375 {
376  const bfd_udp_session_t *bus = &bs->udp;
377  ip_adjacency_t *adj = adj_get (bus->adj_index);
378  switch (adj->lookup_next_index)
379  {
380  case IP_LOOKUP_NEXT_ARP:
381  switch (bs->transport)
382  {
383  case BFD_TRANSPORT_UDP4:
384  *next_node = bfd_udp_main.ip4_arp_idx;
385  return 1;
386  case BFD_TRANSPORT_UDP6:
387  *next_node = bfd_udp_main.ip6_ndp_idx;
388  return 1;
389  }
390  break;
392  switch (bs->transport)
393  {
394  case BFD_TRANSPORT_UDP4:
395  *next_node = bfd_udp_main.ip4_rewrite_idx;
396  return 1;
397  case BFD_TRANSPORT_UDP6:
398  *next_node = bfd_udp_main.ip6_rewrite_idx;
399  return 1;
400  }
401  break;
402  default:
403  /* drop */
404  break;
405  }
406  return 0;
407 }
408 
409 int
411 {
412  u32 next_node;
413  int rv = bfd_udp_calc_next_node (bs, &next_node);
414  if (rv)
415  {
416  bfd_create_frame_to_next_node (vm, bi, next_node);
417  }
418  return rv;
419 }
420 
421 int
423 {
424  u32 next_node;
425  int rv = bfd_udp_calc_next_node (bs, &next_node);
426  if (rv)
427  {
428  bfd_create_frame_to_next_node (vm, bi, next_node);
429  }
430  return 1;
431 }
432 
433 static bfd_session_t *
434 bfd_lookup_session (bfd_udp_main_t * bum, const bfd_udp_key_t * key)
435 {
436  uword *p = mhash_get (&bum->bfd_session_idx_by_bfd_key, key);
437  if (p)
438  {
439  return bfd_find_session_by_idx (bum->bfd_main, *p);
440  }
441  return 0;
442 }
443 
444 static void
445 bfd_udp_key_init (bfd_udp_key_t * key, u32 sw_if_index,
446  const ip46_address_t * local_addr,
447  const ip46_address_t * peer_addr)
448 {
449  memset (key, 0, sizeof (*key));
450  key->sw_if_index = sw_if_index;
451  key->local_addr.as_u64[0] = local_addr->as_u64[0];
452  key->local_addr.as_u64[1] = local_addr->as_u64[1];
453  key->peer_addr.as_u64[0] = peer_addr->as_u64[0];
454  key->peer_addr.as_u64[1] = peer_addr->as_u64[1];
455 }
456 
457 static vnet_api_error_t
459  u32 desired_min_tx_usec,
460  u32 required_min_rx_usec, u8 detect_mult,
461  const ip46_address_t * local_addr,
462  const ip46_address_t * peer_addr,
463  bfd_session_t ** bs_out)
464 {
465  /* get a pool entry and if we end up not needing it, give it back */
466  bfd_transport_e t = BFD_TRANSPORT_UDP4;
467  if (!ip46_address_is_ip4 (local_addr))
468  {
469  t = BFD_TRANSPORT_UDP6;
470  }
471  bfd_session_t *bs = bfd_get_session (bum->bfd_main, t);
472  if (!bs)
473  {
474  bfd_put_session (bum->bfd_main, bs);
475  return VNET_API_ERROR_BFD_EAGAIN;
476  }
477  bfd_udp_session_t *bus = &bs->udp;
478  memset (bus, 0, sizeof (*bus));
479  bfd_udp_key_t *key = &bus->key;
480  bfd_udp_key_init (key, sw_if_index, local_addr, peer_addr);
481  const bfd_session_t *tmp = bfd_lookup_session (bum, key);
482  if (tmp)
483  {
484  clib_warning ("duplicate bfd-udp session, existing bs_idx=%d",
485  tmp->bs_idx);
486  bfd_put_session (bum->bfd_main, bs);
487  return VNET_API_ERROR_BFD_EEXIST;
488  }
489  mhash_set (&bum->bfd_session_idx_by_bfd_key, key, bs->bs_idx, NULL);
490  BFD_DBG ("session created, bs_idx=%u, sw_if_index=%d, local=%U, peer=%U",
491  bs->bs_idx, key->sw_if_index, format_ip46_address,
492  &key->local_addr, IP46_TYPE_ANY, format_ip46_address,
493  &key->peer_addr, IP46_TYPE_ANY);
494  if (BFD_TRANSPORT_UDP4 == t)
495  {
497  &key->peer_addr,
498  key->sw_if_index);
499  BFD_DBG ("adj_nbr_add_or_lock(FIB_PROTOCOL_IP4, VNET_LINK_IP4, %U, %d) "
500  "returns %d", format_ip46_address, &key->peer_addr,
501  IP46_TYPE_ANY, key->sw_if_index, bus->adj_index);
502  }
503  else
504  {
506  &key->peer_addr,
507  key->sw_if_index);
508  BFD_DBG ("adj_nbr_add_or_lock(FIB_PROTOCOL_IP6, VNET_LINK_IP6, %U, %d) "
509  "returns %d", format_ip46_address, &key->peer_addr,
510  IP46_TYPE_ANY, key->sw_if_index, bus->adj_index);
511  }
512  *bs_out = bs;
513  return bfd_session_set_params (bum->bfd_main, bs, desired_min_tx_usec,
514  required_min_rx_usec, detect_mult);
515 }
516 
517 static vnet_api_error_t
519  const ip46_address_t * local_addr,
520  const ip46_address_t * peer_addr)
521 {
522  vnet_sw_interface_t *sw_if =
523  vnet_get_sw_interface_safe (bfd_udp_main.vnet_main, sw_if_index);
524  u8 local_ip_valid = 0;
526  if (!sw_if)
527  {
528  clib_warning ("got NULL sw_if");
529  return VNET_API_ERROR_INVALID_SW_IF_INDEX;
530  }
531  if (ip46_address_is_ip4 (local_addr))
532  {
533  if (!ip46_address_is_ip4 (peer_addr))
534  {
535  clib_warning ("IP family mismatch");
536  return VNET_API_ERROR_INVALID_ARGUMENT;
537  }
538  ip4_main_t *im = &ip4_main;
539 
540  /* *INDENT-OFF* */
542  &im->lookup_main, ia, sw_if_index, 0 /* honor unnumbered */, ({
543  ip4_address_t *x =
544  ip_interface_address_get_address (&im->lookup_main, ia);
545  if (x->as_u32 == local_addr->ip4.as_u32)
546  {
547  /* valid address for this interface */
548  local_ip_valid = 1;
549  break;
550  }
551  }));
552  /* *INDENT-ON* */
553  }
554  else
555  {
556  if (ip46_address_is_ip4 (peer_addr))
557  {
558  clib_warning ("IP family mismatch");
559  return VNET_API_ERROR_INVALID_ARGUMENT;
560  }
561  ip6_main_t *im = &ip6_main;
562  /* *INDENT-OFF* */
564  &im->lookup_main, ia, sw_if_index, 0 /* honor unnumbered */, ({
565  ip6_address_t *x =
566  ip_interface_address_get_address (&im->lookup_main, ia);
567  if (local_addr->ip6.as_u64[0] == x->as_u64[0] &&
568  local_addr->ip6.as_u64[1] == x->as_u64[1])
569  {
570  /* valid address for this interface */
571  local_ip_valid = 1;
572  break;
573  }
574  }));
575  /* *INDENT-ON* */
576  }
577 
578  if (!local_ip_valid)
579  {
580  clib_warning ("address not found on interface");
581  return VNET_API_ERROR_ADDRESS_NOT_FOUND_FOR_INTERFACE;
582  }
583 
584  return 0;
585 }
586 
587 static vnet_api_error_t
589  const ip46_address_t * local_addr,
590  const ip46_address_t * peer_addr,
591  bfd_session_t ** bs_out)
592 {
593  vnet_api_error_t rv =
594  bfd_udp_validate_api_input (sw_if_index, local_addr, peer_addr);
595  if (!rv)
596  {
598  bfd_udp_key_t key;
599  bfd_udp_key_init (&key, sw_if_index, local_addr, peer_addr);
600  bfd_session_t *bs = bfd_lookup_session (bum, &key);
601  if (bs)
602  {
603  *bs_out = bs;
604  }
605  else
606  {
608  ("BFD session not found (sw_if_index=%u, local=%U, peer=%U",
609  sw_if_index, format_ip46_address, local_addr, IP46_TYPE_ANY,
610  format_ip46_address, peer_addr, IP46_TYPE_ANY);
611  return VNET_API_ERROR_BFD_ENOENT;
612  }
613  }
614  return rv;
615 }
616 
617 static vnet_api_error_t
618 bfd_api_verify_common (u32 sw_if_index, u32 desired_min_tx_usec,
619  u32 required_min_rx_usec, u8 detect_mult,
620  const ip46_address_t * local_addr,
621  const ip46_address_t * peer_addr)
622 {
623  vnet_api_error_t rv =
624  bfd_udp_validate_api_input (sw_if_index, local_addr, peer_addr);
625  if (rv)
626  {
627  return rv;
628  }
629  if (detect_mult < 1)
630  {
631  clib_warning ("detect_mult < 1");
632  return VNET_API_ERROR_INVALID_ARGUMENT;
633  }
634  if (desired_min_tx_usec < 1)
635  {
636  clib_warning ("desired_min_tx_usec < 1");
637  return VNET_API_ERROR_INVALID_ARGUMENT;
638  }
639  return 0;
640 }
641 
642 static void
644 {
646  BFD_DBG ("free bfd-udp session, bs_idx=%d", bs->bs_idx);
648  adj_unlock (bs->udp.adj_index);
649  bfd_put_session (bum->bfd_main, bs);
650 }
651 
653 bfd_udp_add_session (u32 sw_if_index, const ip46_address_t * local_addr,
654  const ip46_address_t * peer_addr,
655  u32 desired_min_tx_usec, u32 required_min_rx_usec,
656  u8 detect_mult, u8 is_authenticated, u32 conf_key_id,
657  u8 bfd_key_id)
658 {
659  vnet_api_error_t rv =
660  bfd_api_verify_common (sw_if_index, desired_min_tx_usec,
661  required_min_rx_usec, detect_mult,
662  local_addr, peer_addr);
663  bfd_session_t *bs = NULL;
664  if (!rv)
665  {
666  rv =
667  bfd_udp_add_session_internal (&bfd_udp_main, sw_if_index,
668  desired_min_tx_usec,
669  required_min_rx_usec, detect_mult,
670  local_addr, peer_addr, &bs);
671  }
672  if (!rv && is_authenticated)
673  {
674 #if WITH_LIBSSL > 0
675  rv = bfd_auth_activate (bs, conf_key_id, bfd_key_id,
676  0 /* is not delayed */ );
677 #else
678  clib_warning ("SSL missing, cannot add authenticated BFD session");
679  rv = VNET_API_ERROR_BFD_NOTSUPP;
680 #endif
681  if (rv)
682  {
684  }
685  }
686  if (!rv)
687  {
688  bfd_session_start (bfd_udp_main.bfd_main, bs);
689  }
690 
691  return rv;
692 }
693 
696  const ip46_address_t * local_addr,
697  const ip46_address_t * peer_addr,
698  u32 desired_min_tx_usec,
699  u32 required_min_rx_usec, u8 detect_mult)
700 {
701  bfd_session_t *bs = NULL;
702  vnet_api_error_t rv =
703  bfd_udp_find_session_by_api_input (sw_if_index, local_addr, peer_addr,
704  &bs);
705  if (rv)
706  {
707  return rv;
708  }
709 
710  return bfd_session_set_params (bfd_udp_main.bfd_main, bs,
711  desired_min_tx_usec, required_min_rx_usec,
712  detect_mult);
713 }
714 
717  const ip46_address_t * local_addr,
718  const ip46_address_t * peer_addr)
719 {
720  bfd_session_t *bs = NULL;
721  vnet_api_error_t rv =
722  bfd_udp_find_session_by_api_input (sw_if_index, local_addr, peer_addr,
723  &bs);
724  if (rv)
725  {
726  return rv;
727  }
729  return 0;
730 }
731 
734  const ip46_address_t * local_addr,
735  const ip46_address_t * peer_addr, u8 admin_up_down)
736 {
737  bfd_session_t *bs = NULL;
738  vnet_api_error_t rv =
739  bfd_udp_find_session_by_api_input (sw_if_index, local_addr, peer_addr,
740  &bs);
741  if (rv)
742  {
743  return rv;
744  }
745  bfd_session_set_flags (bs, admin_up_down);
746  return 0;
747 }
748 
751  const ip46_address_t * local_addr,
752  const ip46_address_t * peer_addr,
753  u32 conf_key_id, u8 key_id, u8 is_delayed)
754 {
755 #if WITH_LIBSSL > 0
756  bfd_session_t *bs = NULL;
757  vnet_api_error_t rv =
758  bfd_udp_find_session_by_api_input (sw_if_index, local_addr, peer_addr,
759  &bs);
760  if (rv)
761  {
762  return rv;
763  }
764  return bfd_auth_activate (bs, conf_key_id, key_id, is_delayed);
765 #else
766  clib_warning ("SSL missing, cannot activate BFD authentication");
767  return VNET_API_ERROR_BFD_NOTSUPP;
768 #endif
769 }
770 
773  const ip46_address_t * local_addr,
774  const ip46_address_t * peer_addr, u8 is_delayed)
775 {
776  bfd_session_t *bs = NULL;
777  vnet_api_error_t rv =
778  bfd_udp_find_session_by_api_input (sw_if_index, local_addr, peer_addr,
779  &bs);
780  if (rv)
781  {
782  return rv;
783  }
784  return bfd_auth_deactivate (bs, is_delayed);
785 }
786 
787 typedef enum
788 {
794 
795 /* Packet counters - BFD control frames */
796 #define foreach_bfd_udp_error(F) \
797  F (NONE, "good bfd packets (processed)") \
798  F (BAD, "invalid bfd packets")
799 
800 #define F(sym, string) static char BFD_UDP_ERR_##sym##_STR[] = string;
802 #undef F
803 
804 static char *bfd_udp_error_strings[] = {
805 #define F(sym, string) BFD_UDP_ERR_##sym##_STR,
807 #undef F
808 };
809 
810 typedef enum
811 {
812 #define F(sym, str) BFD_UDP_ERROR_##sym,
814 #undef F
815  BFD_UDP_N_ERROR,
817 
818 /* Packet counters - BFD ECHO packets */
819 #define foreach_bfd_udp_echo_error(F) \
820  F (NONE, "good bfd echo packets (processed)") \
821  F (BAD, "invalid bfd echo packets")
822 
823 #define F(sym, string) static char BFD_UDP_ECHO_ERR_##sym##_STR[] = string;
825 #undef F
826 
827 static char *bfd_udp_echo_error_strings[] = {
828 #define F(sym, string) BFD_UDP_ECHO_ERR_##sym##_STR,
830 #undef F
831 };
832 
833 typedef enum
834 {
835 #define F(sym, str) BFD_UDP_ECHO_ERROR_##sym,
837 #undef F
838  BFD_UDP_ECHO_N_ERROR,
840 
841 static void
843  udp_header_t ** udp)
844 {
845  /* sanity check first */
846  const i32 start = vnet_buffer (b)->l3_hdr_offset;
847  if (start < 0 && start < sizeof (b->pre_data))
848  {
849  BFD_ERR ("Start of ip header is before pre_data, ignoring");
850  *ip4 = NULL;
851  *udp = NULL;
852  return;
853  }
854  *ip4 = (ip4_header_t *) (b->data + start);
855  if ((u8 *) * ip4 > (u8 *) vlib_buffer_get_current (b))
856  {
857  BFD_ERR ("Start of ip header is beyond current data, ignoring");
858  *ip4 = NULL;
859  *udp = NULL;
860  return;
861  }
862  *udp = (udp_header_t *) ((*ip4) + 1);
863 }
864 
865 static bfd_udp_error_t
867  const udp_header_t * udp, const bfd_session_t * bs)
868 {
869  const bfd_udp_session_t *bus = &bs->udp;
870  const bfd_udp_key_t *key = &bus->key;
871  if (ip4->src_address.as_u32 != key->peer_addr.ip4.as_u32)
872  {
873  BFD_ERR ("IPv4 src addr mismatch, got %U, expected %U",
875  key->peer_addr.ip4.as_u8);
876  return BFD_UDP_ERROR_BAD;
877  }
878  if (ip4->dst_address.as_u32 != key->local_addr.ip4.as_u32)
879  {
880  BFD_ERR ("IPv4 dst addr mismatch, got %U, expected %U",
882  key->local_addr.ip4.as_u8);
883  return BFD_UDP_ERROR_BAD;
884  }
885  const u8 expected_ttl = 255;
886  if (ip4->ttl != expected_ttl)
887  {
888  BFD_ERR ("IPv4 unexpected TTL value %u, expected %u", ip4->ttl,
889  expected_ttl);
890  return BFD_UDP_ERROR_BAD;
891  }
892  if (clib_net_to_host_u16 (udp->src_port) < 49152)
893  {
894  BFD_ERR ("Invalid UDP src port %u, out of range <49152,65535>",
895  udp->src_port);
896  }
897  return BFD_UDP_ERROR_NONE;
898 }
899 
900 typedef struct
901 {
903  bfd_pkt_t pkt;
905 
906 static void
908 {
909  bfd_consume_pkt (bfd_udp_main.bfd_main, &a->pkt, a->bs_idx);
910 }
911 
912 static void
913 bfd_rpc_update_session (u32 bs_idx, const bfd_pkt_t * pkt)
914 {
915  /* packet length was already verified to be correct by the caller */
916  const u32 data_size = sizeof (bfd_rpc_update_t) -
917  STRUCT_SIZE_OF (bfd_rpc_update_t, pkt) + pkt->head.length;
918  u8 data[data_size];
919  bfd_rpc_update_t *update = (bfd_rpc_update_t *) data;
920  update->bs_idx = bs_idx;
921  clib_memcpy (&update->pkt, pkt, pkt->head.length);
923 }
924 
925 static bfd_udp_error_t
927  vlib_buffer_t * b, bfd_session_t ** bs_out)
928 {
929  const bfd_pkt_t *pkt = vlib_buffer_get_current (b);
930  if (sizeof (*pkt) > b->current_length)
931  {
932  BFD_ERR
933  ("Payload size %d too small to hold bfd packet of minimum size %d",
934  b->current_length, sizeof (*pkt));
935  return BFD_UDP_ERROR_BAD;
936  }
937  ip4_header_t *ip4;
938  udp_header_t *udp;
939  bfd_udp4_find_headers (b, &ip4, &udp);
940  if (!ip4 || !udp)
941  {
942  BFD_ERR ("Couldn't find ip4 or udp header");
943  return BFD_UDP_ERROR_BAD;
944  }
945  const u32 udp_payload_length = udp->length - sizeof (*udp);
946  if (pkt->head.length > udp_payload_length)
947  {
948  BFD_ERR
949  ("BFD packet length is larger than udp payload length (%u > %u)",
950  pkt->head.length, udp_payload_length);
951  return BFD_UDP_ERROR_BAD;
952  }
953  if (!bfd_verify_pkt_common (pkt))
954  {
955  return BFD_UDP_ERROR_BAD;
956  }
957  bfd_session_t *bs = NULL;
958  if (pkt->your_disc)
959  {
960  BFD_DBG ("Looking up BFD session using discriminator %u",
961  pkt->your_disc);
962  bs = bfd_find_session_by_disc (bfd_udp_main.bfd_main, pkt->your_disc);
963  }
964  else
965  {
966  bfd_udp_key_t key;
967  memset (&key, 0, sizeof (key));
968  key.sw_if_index = vnet_buffer (b)->sw_if_index[VLIB_RX];
969  key.local_addr.ip4.as_u32 = ip4->dst_address.as_u32;
970  key.peer_addr.ip4.as_u32 = ip4->src_address.as_u32;
971  BFD_DBG ("Looking up BFD session using key (sw_if_index=%u, local=%U, "
972  "peer=%U)",
973  key.sw_if_index, format_ip4_address, key.local_addr.ip4.as_u8,
974  format_ip4_address, key.peer_addr.ip4.as_u8);
975  bs = bfd_lookup_session (&bfd_udp_main, &key);
976  }
977  if (!bs)
978  {
979  BFD_ERR ("BFD session lookup failed - no session matches BFD pkt");
980  return BFD_UDP_ERROR_BAD;
981  }
982  BFD_DBG ("BFD session found, bs_idx=%u", bs->bs_idx);
983  if (!bfd_verify_pkt_auth (pkt, b->current_length, bs))
984  {
985  BFD_ERR ("Packet verification failed, dropping packet");
986  return BFD_UDP_ERROR_BAD;
987  }
988  bfd_udp_error_t err;
989  if (BFD_UDP_ERROR_NONE != (err = bfd_udp4_verify_transport (ip4, udp, bs)))
990  {
991  return err;
992  }
993  bfd_rpc_update_session (bs->bs_idx, pkt);
994  *bs_out = bs;
995  return BFD_UDP_ERROR_NONE;
996 }
997 
998 static void
1000  udp_header_t ** udp)
1001 {
1002  /* sanity check first */
1003  const i32 start = vnet_buffer (b)->l3_hdr_offset;
1004  if (start < 0 && start < sizeof (b->pre_data))
1005  {
1006  BFD_ERR ("Start of ip header is before pre_data, ignoring");
1007  *ip6 = NULL;
1008  *udp = NULL;
1009  return;
1010  }
1011  *ip6 = (ip6_header_t *) (b->data + start);
1012  if ((u8 *) * ip6 > (u8 *) vlib_buffer_get_current (b))
1013  {
1014  BFD_ERR ("Start of ip header is beyond current data, ignoring");
1015  *ip6 = NULL;
1016  *udp = NULL;
1017  return;
1018  }
1019  if ((*ip6)->protocol != IP_PROTOCOL_UDP)
1020  {
1021  BFD_ERR ("Unexpected protocol in IPv6 header '%u', expected '%u' (== "
1022  "IP_PROTOCOL_UDP)", (*ip6)->protocol, IP_PROTOCOL_UDP);
1023  *ip6 = NULL;
1024  *udp = NULL;
1025  return;
1026  }
1027  *udp = (udp_header_t *) ((*ip6) + 1);
1028 }
1029 
1030 static bfd_udp_error_t
1032  const udp_header_t * udp, const bfd_session_t * bs)
1033 {
1034  const bfd_udp_session_t *bus = &bs->udp;
1035  const bfd_udp_key_t *key = &bus->key;
1036  if (ip6->src_address.as_u64[0] != key->peer_addr.ip6.as_u64[0] &&
1037  ip6->src_address.as_u64[1] != key->peer_addr.ip6.as_u64[1])
1038  {
1039  BFD_ERR ("IP src addr mismatch, got %U, expected %U",
1041  &key->peer_addr.ip6);
1042  return BFD_UDP_ERROR_BAD;
1043  }
1044  if (ip6->dst_address.as_u64[0] != key->local_addr.ip6.as_u64[0] &&
1045  ip6->dst_address.as_u64[1] != key->local_addr.ip6.as_u64[1])
1046  {
1047  BFD_ERR ("IP dst addr mismatch, got %U, expected %U",
1049  &key->local_addr.ip6);
1050  return BFD_UDP_ERROR_BAD;
1051  }
1052  const u8 expected_hop_limit = 255;
1053  if (ip6->hop_limit != expected_hop_limit)
1054  {
1055  BFD_ERR ("IPv6 unexpected hop-limit value %u, expected %u",
1056  ip6->hop_limit, expected_hop_limit);
1057  return BFD_UDP_ERROR_BAD;
1058  }
1059  if (clib_net_to_host_u16 (udp->src_port) < 49152)
1060  {
1061  BFD_ERR ("Invalid UDP src port %u, out of range <49152,65535>",
1062  udp->src_port);
1063  }
1064  return BFD_UDP_ERROR_NONE;
1065 }
1066 
1067 static bfd_udp_error_t
1069  vlib_buffer_t * b, bfd_session_t ** bs_out)
1070 {
1071  const bfd_pkt_t *pkt = vlib_buffer_get_current (b);
1072  if (sizeof (*pkt) > b->current_length)
1073  {
1074  BFD_ERR
1075  ("Payload size %d too small to hold bfd packet of minimum size %d",
1076  b->current_length, sizeof (*pkt));
1077  return BFD_UDP_ERROR_BAD;
1078  }
1079  ip6_header_t *ip6;
1080  udp_header_t *udp;
1081  bfd_udp6_find_headers (b, &ip6, &udp);
1082  if (!ip6 || !udp)
1083  {
1084  BFD_ERR ("Couldn't find ip6 or udp header");
1085  return BFD_UDP_ERROR_BAD;
1086  }
1087  const u32 udp_payload_length = udp->length - sizeof (*udp);
1088  if (pkt->head.length > udp_payload_length)
1089  {
1090  BFD_ERR
1091  ("BFD packet length is larger than udp payload length (%u > %u)",
1092  pkt->head.length, udp_payload_length);
1093  return BFD_UDP_ERROR_BAD;
1094  }
1095  if (!bfd_verify_pkt_common (pkt))
1096  {
1097  return BFD_UDP_ERROR_BAD;
1098  }
1099  bfd_session_t *bs = NULL;
1100  if (pkt->your_disc)
1101  {
1102  BFD_DBG ("Looking up BFD session using discriminator %u",
1103  pkt->your_disc);
1104  bs = bfd_find_session_by_disc (bfd_udp_main.bfd_main, pkt->your_disc);
1105  }
1106  else
1107  {
1108  bfd_udp_key_t key;
1109  memset (&key, 0, sizeof (key));
1110  key.sw_if_index = vnet_buffer (b)->sw_if_index[VLIB_RX];
1111  key.local_addr.ip6.as_u64[0] = ip6->dst_address.as_u64[0];
1112  key.local_addr.ip6.as_u64[1] = ip6->dst_address.as_u64[1];
1113  key.peer_addr.ip6.as_u64[0] = ip6->src_address.as_u64[0];
1114  key.peer_addr.ip6.as_u64[1] = ip6->src_address.as_u64[1];
1115  BFD_DBG ("Looking up BFD session using key (sw_if_index=%u, local=%U, "
1116  "peer=%U)",
1117  key.sw_if_index, format_ip6_address, &key.local_addr,
1118  format_ip6_address, &key.peer_addr);
1119  bs = bfd_lookup_session (&bfd_udp_main, &key);
1120  }
1121  if (!bs)
1122  {
1123  BFD_ERR ("BFD session lookup failed - no session matches BFD pkt");
1124  return BFD_UDP_ERROR_BAD;
1125  }
1126  BFD_DBG ("BFD session found, bs_idx=%u", bs->bs_idx);
1127  if (!bfd_verify_pkt_auth (pkt, b->current_length, bs))
1128  {
1129  BFD_ERR ("Packet verification failed, dropping packet");
1130  return BFD_UDP_ERROR_BAD;
1131  }
1132  bfd_udp_error_t err;
1133  if (BFD_UDP_ERROR_NONE != (err = bfd_udp6_verify_transport (ip6, udp, bs)))
1134  {
1135  return err;
1136  }
1137  bfd_rpc_update_session (bs->bs_idx, pkt);
1138  *bs_out = bs;
1139  return BFD_UDP_ERROR_NONE;
1140 }
1141 
1142 /*
1143  * Process a frame of bfd packets
1144  * Expect 1 packet / frame
1145  */
1146 static uword
1148  vlib_frame_t * f, int is_ipv6)
1149 {
1150  u32 n_left_from, *from;
1151  bfd_input_trace_t *t0;
1152 
1153  from = vlib_frame_vector_args (f); /* array of buffer indices */
1154  n_left_from = f->n_vectors; /* number of buffer indices */
1155 
1156  while (n_left_from > 0)
1157  {
1158  u32 bi0;
1159  vlib_buffer_t *b0;
1160  u32 next0, error0;
1161 
1162  bi0 = from[0];
1163  b0 = vlib_get_buffer (vm, bi0);
1164 
1165  bfd_session_t *bs = NULL;
1166 
1167  /* If this pkt is traced, snapshot the data */
1168  if (b0->flags & VLIB_BUFFER_IS_TRACED)
1169  {
1170  int len;
1171  t0 = vlib_add_trace (vm, rt, b0, sizeof (*t0));
1172  len = (b0->current_length < sizeof (t0->data)) ? b0->current_length
1173  : sizeof (t0->data);
1174  t0->len = len;
1175  clib_memcpy (t0->data, vlib_buffer_get_current (b0), len);
1176  }
1177 
1178  /* scan this bfd pkt. error0 is the counter index to bmp */
1179  if (is_ipv6)
1180  {
1181  error0 = bfd_udp6_scan (vm, rt, b0, &bs);
1182  }
1183  else
1184  {
1185  error0 = bfd_udp4_scan (vm, rt, b0, &bs);
1186  }
1187  b0->error = rt->errors[error0];
1188 
1189  next0 = BFD_UDP_INPUT_NEXT_NORMAL;
1190  if (BFD_UDP_ERROR_NONE == error0)
1191  {
1192  /*
1193  * if everything went fine, check for poll bit, if present, re-use
1194  * the buffer and based on (now updated) session parameters, send
1195  * the final packet back
1196  */
1197  const bfd_pkt_t *pkt = vlib_buffer_get_current (b0);
1198  if (bfd_pkt_get_poll (pkt))
1199  {
1200  b0->current_data = 0;
1201  b0->current_length = 0;
1202  memset (vnet_buffer (b0), 0, sizeof (*vnet_buffer (b0)));
1203  bfd_init_final_control_frame (vm, b0, bfd_udp_main.bfd_main, bs,
1204  0);
1205  if (is_ipv6)
1206  {
1208  b0->error, 1);
1209  }
1210  else
1211  {
1213  b0->error, 1);
1214  }
1215  const bfd_udp_session_t *bus = &bs->udp;
1216  ip_adjacency_t *adj = adj_get (bus->adj_index);
1217  switch (adj->lookup_next_index)
1218  {
1219  case IP_LOOKUP_NEXT_ARP:
1221  break;
1224  break;
1225  default:
1226  /* drop */
1227  break;
1228  }
1229  }
1230  }
1231  vlib_set_next_frame_buffer (vm, rt, next0, bi0);
1232 
1233  from += 1;
1234  n_left_from -= 1;
1235  }
1236 
1237  return f->n_vectors;
1238 }
1239 
1240 static uword
1242 {
1243  return bfd_udp_input (vm, rt, f, 0);
1244 }
1245 
1246 /*
1247  * bfd input graph node declaration
1248  */
1249 /* *INDENT-OFF* */
1251  .function = bfd_udp4_input,
1252  .name = "bfd-udp4-input",
1253  .vector_size = sizeof (u32),
1254  .type = VLIB_NODE_TYPE_INTERNAL,
1255 
1256  .n_errors = BFD_UDP_N_ERROR,
1257  .error_strings = bfd_udp_error_strings,
1258 
1259  .format_trace = bfd_input_format_trace,
1260 
1261  .n_next_nodes = BFD_UDP_INPUT_N_NEXT,
1262  .next_nodes =
1263  {
1264  [BFD_UDP_INPUT_NEXT_NORMAL] = "error-drop",
1265  [BFD_UDP_INPUT_NEXT_REPLY_ARP] = "ip4-arp",
1266  [BFD_UDP_INPUT_NEXT_REPLY_REWRITE] = "ip4-lookup",
1267  },
1268 };
1269 /* *INDENT-ON* */
1270 
1271 static uword
1273 {
1274  return bfd_udp_input (vm, rt, f, 1);
1275 }
1276 
1277 /* *INDENT-OFF* */
1279  .function = bfd_udp6_input,
1280  .name = "bfd-udp6-input",
1281  .vector_size = sizeof (u32),
1282  .type = VLIB_NODE_TYPE_INTERNAL,
1283 
1284  .n_errors = BFD_UDP_N_ERROR,
1285  .error_strings = bfd_udp_error_strings,
1286 
1287  .format_trace = bfd_input_format_trace,
1288 
1289  .n_next_nodes = BFD_UDP_INPUT_N_NEXT,
1290  .next_nodes =
1291  {
1292  [BFD_UDP_INPUT_NEXT_NORMAL] = "error-drop",
1293  [BFD_UDP_INPUT_NEXT_REPLY_ARP] = "ip6-discover-neighbor",
1294  [BFD_UDP_INPUT_NEXT_REPLY_REWRITE] = "ip6-lookup",
1295  },
1296 };
1297 /* *INDENT-ON* */
1298 
1299 /*
1300  * Process a frame of bfd echo packets
1301  * Expect 1 packet / frame
1302  */
1303 static uword
1305  vlib_frame_t * f, int is_ipv6)
1306 {
1307  u32 n_left_from, *from;
1308  bfd_input_trace_t *t0;
1309 
1310  from = vlib_frame_vector_args (f); /* array of buffer indices */
1311  n_left_from = f->n_vectors; /* number of buffer indices */
1312 
1313  while (n_left_from > 0)
1314  {
1315  u32 bi0;
1316  vlib_buffer_t *b0;
1317  u32 next0;
1318 
1319  bi0 = from[0];
1320  b0 = vlib_get_buffer (vm, bi0);
1321 
1322  /* If this pkt is traced, snapshot the data */
1323  if (b0->flags & VLIB_BUFFER_IS_TRACED)
1324  {
1325  int len;
1326  t0 = vlib_add_trace (vm, rt, b0, sizeof (*t0));
1327  len = (b0->current_length < sizeof (t0->data)) ? b0->current_length
1328  : sizeof (t0->data);
1329  t0->len = len;
1330  clib_memcpy (t0->data, vlib_buffer_get_current (b0), len);
1331  }
1332 
1333  if (bfd_consume_echo_pkt (bfd_udp_main.bfd_main, b0))
1334  {
1335  b0->error = rt->errors[BFD_UDP_ERROR_NONE];
1336  next0 = BFD_UDP_INPUT_NEXT_NORMAL;
1337  }
1338  else
1339  {
1340  /* loop back the packet */
1341  b0->error = rt->errors[BFD_UDP_ERROR_NONE];
1342  if (is_ipv6)
1343  {
1345  b0->error, 1);
1346  }
1347  else
1348  {
1350  b0->error, 1);
1351  }
1353  }
1354 
1355  vlib_set_next_frame_buffer (vm, rt, next0, bi0);
1356 
1357  from += 1;
1358  n_left_from -= 1;
1359  }
1360 
1361  return f->n_vectors;
1362 }
1363 
1364 static uword
1366  vlib_frame_t * f)
1367 {
1368  return bfd_udp_echo_input (vm, rt, f, 0);
1369 }
1370 
1371 u8 *
1372 bfd_echo_input_format_trace (u8 * s, va_list * args)
1373 {
1374  CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
1375  CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
1376  const bfd_udp_echo_input_trace_t *t =
1377  va_arg (*args, bfd_udp_echo_input_trace_t *);
1378  if (t->len > STRUCT_SIZE_OF (bfd_pkt_t, head))
1379  {
1380  s = format (s, "BFD ECHO:\n");
1381  s = format (s, " data: %U", format_hexdump, t->data, t->len);
1382  }
1383 
1384  return s;
1385 }
1386 
1387 /*
1388  * bfd input graph node declaration
1389  */
1390 /* *INDENT-OFF* */
1392  .function = bfd_udp_echo4_input,
1393  .name = "bfd-udp-echo4-input",
1394  .vector_size = sizeof (u32),
1395  .type = VLIB_NODE_TYPE_INTERNAL,
1396 
1397  .n_errors = BFD_UDP_ECHO_N_ERROR,
1398  .error_strings = bfd_udp_error_strings,
1399 
1400  .format_trace = bfd_echo_input_format_trace,
1401 
1402  .n_next_nodes = BFD_UDP_INPUT_N_NEXT,
1403  .next_nodes =
1404  {
1405  [BFD_UDP_INPUT_NEXT_NORMAL] = "error-drop",
1406  [BFD_UDP_INPUT_NEXT_REPLY_ARP] = "ip4-arp",
1407  [BFD_UDP_INPUT_NEXT_REPLY_REWRITE] = "ip4-lookup",
1408  },
1409 };
1410 /* *INDENT-ON* */
1411 
1412 static uword
1414  vlib_frame_t * f)
1415 {
1416  return bfd_udp_echo_input (vm, rt, f, 1);
1417 }
1418 
1419 /* *INDENT-OFF* */
1421  .function = bfd_udp_echo6_input,
1422  .name = "bfd-udp-echo6-input",
1423  .vector_size = sizeof (u32),
1424  .type = VLIB_NODE_TYPE_INTERNAL,
1425 
1426  .n_errors = BFD_UDP_ECHO_N_ERROR,
1427  .error_strings = bfd_udp_echo_error_strings,
1428 
1429  .format_trace = bfd_echo_input_format_trace,
1430 
1431  .n_next_nodes = BFD_UDP_INPUT_N_NEXT,
1432  .next_nodes =
1433  {
1434  [BFD_UDP_INPUT_NEXT_NORMAL] = "error-drop",
1435  [BFD_UDP_INPUT_NEXT_REPLY_ARP] = "ip6-discover-neighbor",
1436  [BFD_UDP_INPUT_NEXT_REPLY_REWRITE] = "ip6-lookup",
1437  },
1438 };
1439 
1440 /* *INDENT-ON* */
1441 
1442 static clib_error_t *
1443 bfd_udp_sw_if_add_del (vnet_main_t * vnm, u32 sw_if_index, u32 is_create)
1444 {
1445  bfd_session_t **to_be_freed = NULL;
1446  BFD_DBG ("sw_if_add_del called, sw_if_index=%u, is_create=%u", sw_if_index,
1447  is_create);
1448  if (!is_create)
1449  {
1450  bfd_session_t *bs;
1451  pool_foreach (bs, bfd_udp_main.bfd_main->sessions,
1452  {
1453  if (bs->transport != BFD_TRANSPORT_UDP4 &&
1454  bs->transport != BFD_TRANSPORT_UDP6)
1455  {
1456  continue;}
1457  if (bs->udp.key.sw_if_index != sw_if_index)
1458  {
1459  continue;}
1460  vec_add1 (to_be_freed, bs);}
1461  );
1462  }
1463  bfd_session_t **bs;
1464  vec_foreach (bs, to_be_freed)
1465  {
1466  clib_warning ("removal of sw_if_index=%u forces removal of bfd session "
1467  "with bs_idx=%u", sw_if_index, (*bs)->bs_idx);
1468  bfd_session_set_flags (*bs, 0);
1470  }
1471  return 0;
1472 }
1473 
1475 
1476 /*
1477  * setup function
1478  */
1479 static clib_error_t *
1481 {
1482  mhash_init (&bfd_udp_main.bfd_session_idx_by_bfd_key, sizeof (uword),
1483  sizeof (bfd_udp_key_t));
1484  bfd_udp_main.bfd_main = &bfd_main;
1485  bfd_udp_main.vnet_main = vnet_get_main ();
1486  udp_register_dst_port (vm, UDP_DST_PORT_bfd4, bfd_udp4_input_node.index, 1);
1487  udp_register_dst_port (vm, UDP_DST_PORT_bfd6, bfd_udp6_input_node.index, 0);
1488  udp_register_dst_port (vm, UDP_DST_PORT_bfd_echo4,
1489  bfd_udp_echo4_input_node.index, 1);
1490  udp_register_dst_port (vm, UDP_DST_PORT_bfd_echo6,
1491  bfd_udp_echo6_input_node.index, 0);
1492  vlib_node_t *node = vlib_get_node_by_name (vm, (u8 *) "ip4-arp");
1493  ASSERT (node);
1494  bfd_udp_main.ip4_arp_idx = node->index;
1495  node = vlib_get_node_by_name (vm, (u8 *) "ip6-discover-neighbor");
1496  ASSERT (node);
1497  bfd_udp_main.ip6_ndp_idx = node->index;
1498  node = vlib_get_node_by_name (vm, (u8 *) "ip4-rewrite");
1499  ASSERT (node);
1500  bfd_udp_main.ip4_rewrite_idx = node->index;
1501  node = vlib_get_node_by_name (vm, (u8 *) "ip6-rewrite");
1502  ASSERT (node);
1503  bfd_udp_main.ip6_rewrite_idx = node->index;
1504 
1505  return 0;
1506 }
1507 
1509 
1510 /*
1511  * fd.io coding-style-patch-verification: ON
1512  *
1513  * Local Variables:
1514  * eval: (c-set-style "gnu")
1515  * End:
1516  */
static clib_error_t * bfd_udp_init(vlib_main_t *vm)
Definition: bfd_udp.c:1480
vnet_api_error_t bfd_udp_auth_activate(u32 sw_if_index, const ip46_address_t *local_addr, const ip46_address_t *peer_addr, u32 conf_key_id, u8 key_id, u8 is_delayed)
activate authentication for existing session
Definition: bfd_udp.c:750
#define foreach_ip_interface_address(lm, a, sw_if_index, loop, body)
Definition: lookup.h:179
static uword bfd_udp_input(vlib_main_t *vm, vlib_node_runtime_t *rt, vlib_frame_t *f, int is_ipv6)
Definition: bfd_udp.c:1147
Definition: mhash.h:46
bfd_session_t * bfd_get_session(bfd_main_t *bm, bfd_transport_e t)
Definition: bfd_main.c:1175
static char * bfd_udp_echo_error_strings[]
Definition: bfd_udp.c:827
vnet_api_error_t
Definition: api_errno.h:139
static vnet_api_error_t bfd_api_verify_common(u32 sw_if_index, u32 desired_min_tx_usec, u32 required_min_rx_usec, u8 detect_mult, const ip46_address_t *local_addr, const ip46_address_t *peer_addr)
Definition: bfd_udp.c:618
vnet_main_t * vnet_main
Definition: bfd_udp.c:49
bfd_udp_echo_error_t
Definition: bfd_udp.c:833
void bfd_consume_pkt(bfd_main_t *bm, const bfd_pkt_t *pkt, u32 bs_idx)
Definition: bfd_main.c:1601
#define CLIB_UNUSED(x)
Definition: clib.h:79
bfd udp echo packet trace capture
Definition: bfd_udp.h:53
a
Definition: bitmap.h:516
ip4_address_t src_address
Definition: ip4_packet.h:164
static uword bfd_udp_echo6_input(vlib_main_t *vm, vlib_node_runtime_t *rt, vlib_frame_t *f)
Definition: bfd_udp.c:1413
bfd_main_t bfd_main
Definition: bfd_main.c:2050
static void vlib_set_next_frame_buffer(vlib_main_t *vm, vlib_node_runtime_t *node, u32 next_index, u32 buffer_index)
Definition: node_funcs.h:397
vnet_main_t * vnet_get_main(void)
Definition: misc.c:47
#define BFD_ERR(...)
Definition: bfd_debug.h:75
u64 as_u64[2]
Definition: ip6_packet.h:51
bfd_main_t * bfd_main
Definition: bfd_udp.c:44
bfd_session_t * bfd_find_session_by_disc(bfd_main_t *bm, u32 disc)
Definition: bfd_main.c:1229
Definitions for all things IP (v4|v6) unicast and multicast lookup related.
#define NULL
Definition: clib.h:55
uword mhash_unset(mhash_t *h, void *key, uword *old_value)
Definition: mhash.c:353
u32 index
Definition: node.h:237
IP unicast adjacency.
Definition: adj.h:174
int bfd_verify_pkt_common(const bfd_pkt_t *pkt)
verify bfd packet - common checks
Definition: bfd_main.c:1247
u32 ip4_arp_idx
Definition: bfd_udp.c:55
This packet is to be rewritten and forwarded to the next processing node.
Definition: adj.h:73
#define vec_add1(V, E)
Add 1 element to end of vector (unspecified alignment).
Definition: vec.h:518
static vlib_node_registration_t bfd_udp4_input_node
(constructor) VLIB_REGISTER_NODE (bfd_udp4_input_node)
Definition: bfd_udp.c:64
struct _vlib_node_registration vlib_node_registration_t
void bfd_put_session(bfd_main_t *bm, bfd_session_t *bs)
Definition: bfd_main.c:1203
format_function_t format_ip46_address
Definition: format.h:61
ip_lookup_main_t lookup_main
Definition: ip4.h:97
static vlib_node_registration_t bfd_udp6_input_node
(constructor) VLIB_REGISTER_NODE (bfd_udp6_input_node)
Definition: bfd_udp.c:65
u8 * format(u8 *s, const char *fmt,...)
Definition: format.c:419
static bfd_udp_error_t bfd_udp6_scan(vlib_main_t *vm, vlib_node_runtime_t *rt, vlib_buffer_t *b, bfd_session_t **bs_out)
Definition: bfd_udp.c:1068
#define foreach_bfd_udp_error(F)
Definition: bfd_udp.c:796
void bfd_init_final_control_frame(vlib_main_t *vm, vlib_buffer_t *b, bfd_main_t *bm, bfd_session_t *bs, int is_local)
Definition: bfd_main.c:894
VNET_SW_INTERFACE_ADD_DEL_FUNCTION(bfd_udp_sw_if_add_del)
static uword bfd_udp4_input(vlib_main_t *vm, vlib_node_runtime_t *rt, vlib_frame_t *f)
Definition: bfd_udp.c:1241
vlib_error_t * errors
Vector of errors for this node.
Definition: node.h:415
static uword vlib_buffer_length_in_chain(vlib_main_t *vm, vlib_buffer_t *b)
Get length in bytes of the buffer chain.
Definition: buffer_funcs.h:107
u32 echo_source_sw_if_index
Definition: bfd_udp.c:53
static vnet_api_error_t bfd_udp_validate_api_input(u32 sw_if_index, const ip46_address_t *local_addr, const ip46_address_t *peer_addr)
Definition: bfd_udp.c:518
ip6_address_t src_address
Definition: ip6_packet.h:341
static uword bfd_udp_echo_input(vlib_main_t *vm, vlib_node_runtime_t *rt, vlib_frame_t *f, int is_ipv6)
Definition: bfd_udp.c:1304
bfd_udp_error_t
Definition: bfd_udp.c:810
int bfd_add_udp4_transport(vlib_main_t *vm, u32 bi, const bfd_session_t *bs, int is_echo)
Definition: bfd_udp.c:242
#define foreach_bfd_udp_echo_error(F)
Definition: bfd_udp.c:819
void bfd_udp_get_echo_source(int *is_set, u32 *sw_if_index, int *have_usable_ip4, ip4_address_t *ip4, int *have_usable_ip6, ip6_address_t *ip6)
get echo source information - used by CLI
Definition: bfd_udp.c:224
vnet_api_error_t bfd_auth_deactivate(bfd_session_t *bs, u8 is_delayed)
Definition: bfd_main.c:1861
mhash_t bfd_session_idx_by_bfd_key
Definition: bfd_udp.c:47
format_function_t format_ip4_address
Definition: format.h:79
static ip_adjacency_t * adj_get(adj_index_t adj_index)
Get a pointer to an adjacency object from its index.
Definition: adj.h:365
vnet_api_error_t bfd_udp_del_echo_source(u32 sw_if_index)
Definition: bfd_udp.c:86
static char * bfd_udp_error_strings[]
Definition: bfd_udp.c:804
i16 current_data
signed offset in data[], pre_data[] that we are currently processing.
Definition: buffer.h:68
#define pool_foreach(VAR, POOL, BODY)
Iterate through pool.
Definition: pool.h:438
static void bfd_udp6_find_headers(vlib_buffer_t *b, ip6_header_t **ip6, udp_header_t **udp)
Definition: bfd_udp.c:999
#define VLIB_INIT_FUNCTION(x)
Definition: init.h:111
vnet_api_error_t bfd_udp_mod_session(u32 sw_if_index, const ip46_address_t *local_addr, const ip46_address_t *peer_addr, u32 desired_min_tx_usec, u32 required_min_rx_usec, u8 detect_mult)
modify existing session
Definition: bfd_udp.c:695
ip4_address_t dst_address
Definition: ip4_packet.h:164
static void bfd_udp4_find_headers(vlib_buffer_t *b, ip4_header_t **ip4, udp_header_t **udp)
Definition: bfd_udp.c:842
static bfd_session_t * bfd_lookup_session(bfd_udp_main_t *bum, const bfd_udp_key_t *key)
Definition: bfd_udp.c:434
int bfd_transport_udp4(vlib_main_t *vm, u32 bi, const struct bfd_session_s *bs)
transport packet over udpv4
Definition: bfd_udp.c:410
int i32
Definition: types.h:81
vlib_frame_t * vlib_get_frame_to_node(vlib_main_t *vm, u32 to_node_index)
Definition: main.c:182
UDP transport specific data embedded in bfd_session&#39;s union.
Definition: bfd_udp.h:44
u8 pre_data[VLIB_BUFFER_PRE_DATA_SIZE]
Space for inserting data before buffer start.
Definition: buffer.h:151
void adj_unlock(adj_index_t adj_index)
Release a reference counting lock on the adjacency.
Definition: adj.c:239
static void bfd_rpc_update_session_cb(const bfd_rpc_update_t *a)
Definition: bfd_udp.c:907
bfd_session_t * bfd_find_session_by_idx(bfd_main_t *bm, uword bs_idx)
Definition: bfd_main.c:1219
static vnet_api_error_t bfd_udp_find_session_by_api_input(u32 sw_if_index, const ip46_address_t *local_addr, const ip46_address_t *peer_addr, bfd_session_t **bs_out)
Definition: bfd_udp.c:588
bfd_session_t * sessions
pool of bfd sessions context data
Definition: bfd_main.h:263
bfd_udp_key_t key
key identifying this session
Definition: bfd_udp.h:47
bfd_transport_e transport
transport type for this session
Definition: bfd_main.h:231
bfd_pkt_t pkt
Definition: bfd_udp.c:903
u16 current_length
Nbytes between current data and the end of this buffer.
Definition: buffer.h:72
vnet_api_error_t bfd_udp_set_echo_source(u32 sw_if_index)
set echo-source interface
Definition: bfd_udp.c:72
void vlib_put_frame_to_node(vlib_main_t *vm, u32 to_node_index, vlib_frame_t *f)
Definition: main.c:191
static vlib_node_registration_t bfd_udp_echo4_input_node
(constructor) VLIB_REGISTER_NODE (bfd_udp_echo4_input_node)
Definition: bfd_udp.c:66
static void * vlib_buffer_get_current(vlib_buffer_t *b)
Get pointer to current data to process.
Definition: buffer.h:195
BFD global declarations.
u8 * bfd_echo_input_format_trace(u8 *s, va_list *args)
Definition: bfd_udp.c:1372
vnet_api_error_t bfd_udp_add_session(u32 sw_if_index, const ip46_address_t *local_addr, const ip46_address_t *peer_addr, u32 desired_min_tx_usec, u32 required_min_rx_usec, u8 detect_mult, u8 is_authenticated, u32 conf_key_id, u8 bfd_key_id)
create a new bfd session
Definition: bfd_udp.c:653
static uword mhash_set(mhash_t *h, void *key, uword new_value, uword *old_value)
Definition: mhash.h:117
static bfd_udp_error_t bfd_udp4_scan(vlib_main_t *vm, vlib_node_runtime_t *rt, vlib_buffer_t *b, bfd_session_t **bs_out)
Definition: bfd_udp.c:926
int bfd_transport_udp6(vlib_main_t *vm, u32 bi, const struct bfd_session_s *bs)
transport packet over udpv6
Definition: bfd_udp.c:422
bfd_udp_session_t udp
Definition: bfd_main.h:236
u32 ip6_rewrite_idx
Definition: bfd_udp.c:61
int bfd_add_udp6_transport(vlib_main_t *vm, u32 bi, const bfd_session_t *bs, int is_echo)
Definition: bfd_udp.c:297
vlib_error_t error
Error code for buffers to be enqueued to error handler.
Definition: buffer.h:113
static void vlib_node_increment_counter(vlib_main_t *vm, u32 node_index, u32 counter_index, u64 increment)
Definition: node_funcs.h:1158
void bfd_session_start(bfd_main_t *bm, bfd_session_t *bs)
Definition: bfd_main.c:403
#define ip46_address_is_ip4(ip46)
Definition: ip6_packet.h:76
int bfd_udp_get_echo_src_ip6(ip6_address_t *addr)
Definition: bfd_udp.c:195
This packet matches an "incomplete adjacency" and packets need to be passed to ARP to find rewrite st...
Definition: adj.h:63
u32 ip4_rewrite_idx
Definition: bfd_udp.c:59
#define F(sym, string)
Definition: bfd_udp.c:835
void mhash_init(mhash_t *h, uword n_value_bytes, uword n_key_bytes)
Definition: mhash.c:168
u16 n_vectors
Definition: node.h:344
bfd_udp_input_next_t
Definition: bfd_udp.c:787
format_function_t format_ip6_address
Definition: format.h:95
vlib_main_t * vm
Definition: buffer.c:283
static void bfd_create_frame_to_next_node(vlib_main_t *vm, u32 bi, u32 next_node)
Definition: bfd_udp.c:364
static uword bfd_udp6_input(vlib_main_t *vm, vlib_node_runtime_t *rt, vlib_frame_t *f)
Definition: bfd_udp.c:1272
#define clib_warning(format, args...)
Definition: error.h:59
#define VLIB_BUFFER_IS_TRACED
Definition: buffer.h:93
#define clib_memcpy(a, b, c)
Definition: string.h:75
static vnet_sw_interface_t * vnet_get_sw_interface_safe(vnet_main_t *vnm, u32 sw_if_index)
void vl_api_rpc_call_main_thread(void *fp, u8 *data, u32 data_length)
Definition: memory_vlib.c:1916
u8 * format_hexdump(u8 *s, va_list *va)
Definition: std-formats.c:281
vnet_api_error_t bfd_auth_activate(bfd_session_t *bs, u32 conf_key_id, u8 bfd_key_id, u8 is_delayed)
Definition: bfd_main.c:1815
BFD global declarations.
vlib_node_t * vlib_get_node_by_name(vlib_main_t *vm, u8 *name)
Definition: node.c:45
static clib_error_t * bfd_udp_sw_if_add_del(vnet_main_t *vnm, u32 sw_if_index, u32 is_create)
Definition: bfd_udp.c:1443
u8 * bfd_input_format_trace(u8 *s, va_list *args)
Definition: bfd_main.c:438
#define BFD_DBG(...)
Definition: bfd_debug.h:74
int bfd_udp_get_echo_src_ip4(ip4_address_t *addr)
Definition: bfd_udp.c:161
u16 ip6_tcp_udp_icmp_compute_checksum(vlib_main_t *vm, vlib_buffer_t *p0, ip6_header_t *ip0, int *bogus_lengthp)
Definition: ip6_forward.c:1133
vlib buffer structure definition and a few select access methods.
#define VNET_SW_INTERFACE_FLAG_ADMIN_UP
Definition: interface.h:576
static bfd_udp_error_t bfd_udp6_verify_transport(const ip6_header_t *ip6, const udp_header_t *udp, const bfd_session_t *bs)
Definition: bfd_udp.c:1031
#define ASSERT(truth)
int echo_source_is_set
Definition: bfd_udp.c:51
unsigned int u32
Definition: types.h:88
static uword * mhash_get(mhash_t *h, const void *key)
Definition: mhash.h:110
ip6_main_t ip6_main
Definition: ip6_forward.c:3009
ip_lookup_main_t lookup_main
Definition: ip6.h:158
int bfd_udp_is_echo_available(bfd_transport_e transport)
check if the bfd udp layer is echo-capable at this time
Definition: bfd_udp.c:94
IPv4 main type.
Definition: ip4.h:95
static bfd_udp_error_t bfd_udp4_verify_transport(const ip4_header_t *ip4, const udp_header_t *udp, const bfd_session_t *bs)
Definition: bfd_udp.c:866
adj_index_t adj_index
adjacency index returned from adj lock call
Definition: bfd_udp.h:49
static void vlib_buffer_advance(vlib_buffer_t *b, word l)
Advance current data pointer by the supplied (signed!) amount.
Definition: buffer.h:208
static vlib_node_registration_t bfd_udp_echo6_input_node
(constructor) VLIB_REGISTER_NODE (bfd_udp_echo6_input_node)
Definition: bfd_udp.c:67
bfd_udp_main_t bfd_udp_main
Definition: bfd_udp.c:69
static u16 bfd_udp_bs_idx_to_sport(u32 bs_idx)
Definition: bfd_udp.c:147
vnet_api_error_t bfd_udp_session_set_flags(u32 sw_if_index, const ip46_address_t *local_addr, const ip46_address_t *peer_addr, u8 admin_up_down)
set session admin down/up
Definition: bfd_udp.c:733
int bfd_consume_echo_pkt(bfd_main_t *bm, vlib_buffer_t *b)
Definition: bfd_main.c:1732
vnet_api_error_t bfd_session_set_params(bfd_main_t *bm, bfd_session_t *bs, u32 desired_min_tx_usec, u32 required_min_rx_usec, u8 detect_mult)
Definition: bfd_main.c:1899
u64 uword
Definition: types.h:112
static void * vlib_add_trace(vlib_main_t *vm, vlib_node_runtime_t *r, vlib_buffer_t *b, u32 n_data_bytes)
Definition: trace_funcs.h:55
static vnet_api_error_t bfd_udp_add_session_internal(bfd_udp_main_t *bum, u32 sw_if_index, u32 desired_min_tx_usec, u32 required_min_rx_usec, u8 detect_mult, const ip46_address_t *local_addr, const ip46_address_t *peer_addr, bfd_session_t **bs_out)
Definition: bfd_udp.c:458
Definition: defs.h:47
BFD UDP transport layer declarations.
unsigned short u16
Definition: types.h:57
unsigned char u8
Definition: types.h:56
BFD API declarations.
ip_lookup_next_t lookup_next_index
Next hop after ip4-lookup.
Definition: adj.h:189
int bfd_udp_calc_next_node(const struct bfd_session_s *bs, u32 *next_node)
Definition: bfd_udp.c:374
static void bfd_udp_del_session_internal(bfd_session_t *bs)
Definition: bfd_udp.c:643
static void * vlib_frame_vector_args(vlib_frame_t *f)
Get pointer to frame vector data.
Definition: node_funcs.h:267
vnet_api_error_t bfd_udp_del_session(u32 sw_if_index, const ip46_address_t *local_addr, const ip46_address_t *peer_addr)
delete existing session
Definition: bfd_udp.c:716
u8 bfd_pkt_get_poll(const bfd_pkt_t *pkt)
Definition: bfd_protocol.c:60
u32 bs_idx
index in bfd_main.sessions pool
Definition: bfd_main.h:86
#define vnet_buffer(b)
Definition: buffer.h:326
#define VLIB_REGISTER_NODE(x,...)
Definition: node.h:143
ip4_main_t ip4_main
Global ip4 main structure.
Definition: ip4_forward.c:1181
static void bfd_udp_key_init(bfd_udp_key_t *key, u32 sw_if_index, const ip46_address_t *local_addr, const ip46_address_t *peer_addr)
Definition: bfd_udp.c:445
#define STRUCT_SIZE_OF(t, f)
Definition: clib.h:64
u8 data[0]
Packet data.
Definition: buffer.h:159
adj_index_t adj_nbr_add_or_lock(fib_protocol_t nh_proto, vnet_link_t link_type, const ip46_address_t *nh_addr, u32 sw_if_index)
Neighbour Adjacency sub-type.
Definition: adj_nbr.c:214
#define vec_foreach(var, vec)
Vector iterator.
u32 ip6_ndp_idx
Definition: bfd_udp.c:57
bfd packet trace capture
Definition: bfd_main.h:320
int bfd_verify_pkt_auth(const bfd_pkt_t *pkt, u16 pkt_size, bfd_session_t *bs)
verify bfd packet - authentication
Definition: bfd_main.c:1523
vhost_vring_addr_t addr
Definition: vhost-user.h:83
void udp_register_dst_port(vlib_main_t *vm, udp_dst_port_t dst_port, u32 node_index, u8 is_ip4)
Definition: udp_local.c:492
static void bfd_rpc_update_session(u32 bs_idx, const bfd_pkt_t *pkt)
Definition: bfd_udp.c:913
u32 flags
buffer flags: VLIB_BUFFER_FREE_LIST_INDEX_MASK: bits used to store free list index, VLIB_BUFFER_IS_TRACED: trace this buffer.
Definition: buffer.h:75
vnet_api_error_t bfd_udp_auth_deactivate(u32 sw_if_index, const ip46_address_t *local_addr, const ip46_address_t *peer_addr, u8 is_delayed)
deactivate authentication for existing session
Definition: bfd_udp.c:772
static uword bfd_udp_echo4_input(vlib_main_t *vm, vlib_node_runtime_t *rt, vlib_frame_t *f)
Definition: bfd_udp.c:1365
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
static u16 ip4_header_checksum(ip4_header_t *i)
Definition: ip4_packet.h:239
Definition: defs.h:46
bfd_transport_e
Definition: bfd_api.h:30
ip6_address_t dst_address
Definition: ip6_packet.h:341
void bfd_session_set_flags(bfd_session_t *bs, u8 admin_up_down)
Definition: bfd_main.c:415