c89dd7cfa4da223dd8619a655f067e22f001f170
[vpp.git] / src / vnet / bfd / bfd_udp.c
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_local.h>
26 #include <vnet/udp/udp_packet.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/ip/ip6_link.h>
33 #include <vnet/adj/adj.h>
34 #include <vnet/adj/adj_nbr.h>
35 #include <vnet/dpo/receive_dpo.h>
36 #include <vnet/fib/fib_entry.h>
37 #include <vnet/fib/fib_table.h>
38 #include <vlib/stats/stats.h>
39 #include <vnet/bfd/bfd_debug.h>
40 #include <vnet/bfd/bfd_udp.h>
41 #include <vnet/bfd/bfd_main.h>
42 #include <vnet/bfd/bfd_api.h>
43
44 typedef struct
45 {
46   bfd_main_t *bfd_main;
47   /* hashmap - bfd session index by bfd key - used for CLI/API lookup, where
48    * discriminator is unknown */
49   mhash_t bfd_session_idx_by_bfd_key;
50   /* convenience variable */
51   vnet_main_t *vnet_main;
52   /* flag indicating whether echo_source_sw_if_index holds a valid value */
53   int echo_source_is_set;
54   /* loopback interface used to get echo source ip */
55   u32 echo_source_sw_if_index;
56   /* node index of "ip4-arp" node */
57   u32 ip4_arp_idx;
58   /* node index of "ip6-discover-neighbor" node */
59   u32 ip6_ndp_idx;
60   /* node index of "ip4-rewrite" node */
61   u32 ip4_rewrite_idx;
62   /* node index of "ip6-rewrite" node */
63   u32 ip6_rewrite_idx;
64   /* node index of "ip4-midchain" node */
65   u32 ip4_midchain_idx;
66   /* node index of "ip6-midchain" node */
67   u32 ip6_midchain_idx;
68   /* log class */
69   vlib_log_class_t log_class;
70   /* number of active udp4 sessions */
71   u32 udp4_sessions_count;
72   u32 udp4_sessions_count_stat_seg_entry;
73   /* number of active udp6 sessions */
74   u32 udp6_sessions_count;
75   u32 udp6_sessions_count_stat_seg_entry;
76 } bfd_udp_main_t;
77
78 static vlib_node_registration_t bfd_udp4_input_node;
79 static vlib_node_registration_t bfd_udp6_input_node;
80 static vlib_node_registration_t bfd_udp_echo4_input_node;
81 static vlib_node_registration_t bfd_udp_echo6_input_node;
82
83 bfd_udp_main_t bfd_udp_main;
84
85 void
86 bfd_udp_update_stat_segment_entry (u32 entry, u64 value)
87 {
88   vlib_stats_segment_lock ();
89   vlib_stats_set_gauge (entry, value);
90   vlib_stats_segment_unlock ();
91 }
92
93 vnet_api_error_t
94 bfd_udp_set_echo_source (u32 sw_if_index)
95 {
96   vnet_sw_interface_t *sw_if =
97     vnet_get_sw_interface_or_null (bfd_udp_main.vnet_main, sw_if_index);
98   if (sw_if)
99     {
100       bfd_udp_main.echo_source_sw_if_index = sw_if_index;
101       bfd_udp_main.echo_source_is_set = 1;
102       return 0;
103     }
104   return VNET_API_ERROR_BFD_ENOENT;
105 }
106
107 vnet_api_error_t
108 bfd_udp_del_echo_source ()
109 {
110   bfd_udp_main.echo_source_sw_if_index = ~0;
111   bfd_udp_main.echo_source_is_set = 0;
112   return 0;
113 }
114
115 int
116 bfd_udp_is_echo_available (bfd_transport_e transport)
117 {
118   if (!bfd_udp_main.echo_source_is_set)
119     {
120       BFD_DBG ("UDP echo source not set - echo not available");
121       return 0;
122     }
123   /*
124    * for the echo to work, we need a loopback interface with at least one
125    * address with netmask length at most 31 (ip4) or 127 (ip6) so that we can
126    * pick an unused address from that subnet
127    */
128   vnet_sw_interface_t *sw_if =
129     vnet_get_sw_interface_or_null (bfd_udp_main.vnet_main,
130                                    bfd_udp_main.echo_source_sw_if_index);
131   if (sw_if && sw_if->flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP)
132     {
133       if (BFD_TRANSPORT_UDP4 == transport)
134         {
135           ip4_main_t *im = &ip4_main;
136           ip_interface_address_t *ia = NULL;
137           /* *INDENT-OFF* */
138           foreach_ip_interface_address (&im->lookup_main, ia,
139                                         bfd_udp_main.echo_source_sw_if_index,
140                                         0 /* honor unnumbered */, ({
141                                           if (ia->address_length <= 31)
142                                             {
143                                               return 1;
144                                             }
145                                         }));
146           /* *INDENT-ON* */
147         }
148       else if (BFD_TRANSPORT_UDP6 == transport)
149         {
150           ip6_main_t *im = &ip6_main;
151           ip_interface_address_t *ia = NULL;
152           /* *INDENT-OFF* */
153           foreach_ip_interface_address (&im->lookup_main, ia,
154                                         bfd_udp_main.echo_source_sw_if_index,
155                                         0 /* honor unnumbered */, ({
156                                           if (ia->address_length <= 127)
157                                             {
158                                               return 1;
159                                             }
160                                         }));
161           /* *INDENT-ON* */
162         }
163     }
164   BFD_DBG ("No usable IP address for UDP echo - echo not available");
165   return 0;
166 }
167
168 static u16
169 bfd_udp_bs_idx_to_sport (u32 bs_idx)
170 {
171   /* The source port MUST be in the range 49152 through 65535. The same UDP
172    * source port number MUST be used for all BFD Control packets associated
173    * with a particular session.  The source port number SHOULD be unique among
174    * all BFD sessions on the system. If more than 16384 BFD sessions are
175    * simultaneously active, UDP source port numbers MAY be reused on
176    * multiple sessions, but the number of distinct uses of the same UDP
177    * source port number SHOULD be minimized.
178    */
179   return 49152 + bs_idx % (65535 - 49152 + 1);
180 }
181
182 int
183 bfd_udp_get_echo_src_ip4 (ip4_address_t * addr)
184 {
185   if (!bfd_udp_main.echo_source_is_set)
186     {
187       BFD_ERR ("cannot find ip4 address, echo source not set");
188       return 0;
189     }
190   ip_interface_address_t *ia = NULL;
191   ip4_main_t *im = &ip4_main;
192
193   /* *INDENT-OFF* */
194   foreach_ip_interface_address (
195       &im->lookup_main, ia, bfd_udp_main.echo_source_sw_if_index,
196       0 /* honor unnumbered */, ({
197         ip4_address_t *x =
198             ip_interface_address_get_address (&im->lookup_main, ia);
199         if (ia->address_length <= 31)
200           {
201             addr->as_u32 = clib_host_to_net_u32 (x->as_u32);
202             /*
203              * flip the last bit to get a different address, might be network,
204              * we don't care ...
205              */
206             addr->as_u32 ^= 1;
207             addr->as_u32 = clib_net_to_host_u32 (addr->as_u32);
208             return 1;
209           }
210       }));
211   /* *INDENT-ON* */
212   BFD_ERR ("cannot find ip4 address, no usable address found");
213   return 0;
214 }
215
216 int
217 bfd_udp_get_echo_src_ip6 (ip6_address_t * addr)
218 {
219   if (!bfd_udp_main.echo_source_is_set)
220     {
221       BFD_ERR ("cannot find ip6 address, echo source not set");
222       return 0;
223     }
224   ip_interface_address_t *ia = NULL;
225   ip6_main_t *im = &ip6_main;
226
227   /* *INDENT-OFF* */
228   foreach_ip_interface_address (
229       &im->lookup_main, ia, bfd_udp_main.echo_source_sw_if_index,
230       0 /* honor unnumbered */, ({
231         ip6_address_t *x =
232             ip_interface_address_get_address (&im->lookup_main, ia);
233         if (ia->address_length <= 127)
234           {
235             *addr = *x;
236             addr->as_u8[15] ^= 1; /* flip the last bit of the address */
237             return 1;
238           }
239       }));
240   /* *INDENT-ON* */
241   BFD_ERR ("cannot find ip6 address, no usable address found");
242   return 0;
243 }
244
245 void
246 bfd_udp_get_echo_source (int *is_set, u32 * sw_if_index,
247                          int *have_usable_ip4, ip4_address_t * ip4,
248                          int *have_usable_ip6, ip6_address_t * ip6)
249 {
250   if (bfd_udp_main.echo_source_is_set)
251     {
252       *is_set = 1;
253       *sw_if_index = bfd_udp_main.echo_source_sw_if_index;
254       *have_usable_ip4 = bfd_udp_get_echo_src_ip4 (ip4);
255       *have_usable_ip6 = bfd_udp_get_echo_src_ip6 (ip6);
256     }
257   else
258     {
259       *is_set = 0;
260     }
261 }
262
263 int
264 bfd_add_udp4_transport (vlib_main_t * vm, u32 bi, const bfd_session_t * bs,
265                         int is_echo)
266 {
267   const bfd_udp_session_t *bus = &bs->udp;
268   const bfd_udp_key_t *key = &bus->key;
269   vlib_buffer_t *b = vlib_get_buffer (vm, bi);
270
271   b->flags |= VNET_BUFFER_F_LOCALLY_ORIGINATED;
272   vnet_buffer (b)->ip.adj_index[VLIB_RX] = bus->adj_index;
273   vnet_buffer (b)->ip.adj_index[VLIB_TX] = bus->adj_index;
274   vnet_buffer (b)->sw_if_index[VLIB_RX] = 0;
275   vnet_buffer (b)->sw_if_index[VLIB_TX] = ~0;
276   typedef struct
277   {
278     ip4_header_t ip4;
279     udp_header_t udp;
280   } ip4_udp_headers;
281   ip4_udp_headers *headers = NULL;
282   vlib_buffer_advance (b, -sizeof (*headers));
283   headers = vlib_buffer_get_current (b);
284   clib_memset (headers, 0, sizeof (*headers));
285   headers->ip4.ip_version_and_header_length = 0x45;
286   headers->ip4.ttl = 255;
287   headers->ip4.protocol = IP_PROTOCOL_UDP;
288   headers->udp.src_port =
289     clib_host_to_net_u16 (bfd_udp_bs_idx_to_sport (bs->bs_idx));
290   if (is_echo)
291     {
292       int rv;
293       if (!(rv = bfd_udp_get_echo_src_ip4 (&headers->ip4.src_address)))
294         {
295           return rv;
296         }
297       headers->ip4.dst_address.as_u32 = key->local_addr.ip4.as_u32;
298       headers->udp.dst_port = clib_host_to_net_u16 (UDP_DST_PORT_bfd_echo4);
299     }
300   else
301     {
302       headers->ip4.src_address.as_u32 = key->local_addr.ip4.as_u32;
303       headers->ip4.dst_address.as_u32 = key->peer_addr.ip4.as_u32;
304       headers->udp.dst_port = clib_host_to_net_u16 (UDP_DST_PORT_bfd4);
305     }
306
307   /* fix ip length, checksum and udp length */
308   const u16 ip_length = vlib_buffer_length_in_chain (vm, b);
309
310   headers->ip4.length = clib_host_to_net_u16 (ip_length);
311   headers->ip4.checksum = ip4_header_checksum (&headers->ip4);
312
313   const u16 udp_length = ip_length - (sizeof (headers->ip4));
314   headers->udp.length = clib_host_to_net_u16 (udp_length);
315   return 1;
316 }
317
318 int
319 bfd_add_udp6_transport (vlib_main_t * vm, u32 bi, const bfd_session_t * bs,
320                         int is_echo)
321 {
322   const bfd_udp_session_t *bus = &bs->udp;
323   const bfd_udp_key_t *key = &bus->key;
324   vlib_buffer_t *b = vlib_get_buffer (vm, bi);
325
326   b->flags |= VNET_BUFFER_F_LOCALLY_ORIGINATED;
327   vnet_buffer (b)->ip.adj_index[VLIB_RX] = bus->adj_index;
328   vnet_buffer (b)->ip.adj_index[VLIB_TX] = bus->adj_index;
329   vnet_buffer (b)->sw_if_index[VLIB_RX] = 0;
330   vnet_buffer (b)->sw_if_index[VLIB_TX] = 0;
331   typedef struct
332   {
333     ip6_header_t ip6;
334     udp_header_t udp;
335   } ip6_udp_headers;
336   ip6_udp_headers *headers = NULL;
337   vlib_buffer_advance (b, -sizeof (*headers));
338   headers = vlib_buffer_get_current (b);
339   clib_memset (headers, 0, sizeof (*headers));
340   headers->ip6.ip_version_traffic_class_and_flow_label =
341     clib_host_to_net_u32 (0x6 << 28);
342   headers->ip6.hop_limit = 255;
343   headers->ip6.protocol = IP_PROTOCOL_UDP;
344   headers->udp.src_port =
345     clib_host_to_net_u16 (bfd_udp_bs_idx_to_sport (bs->bs_idx));
346   if (is_echo)
347     {
348       int rv;
349       if (!(rv = bfd_udp_get_echo_src_ip6 (&headers->ip6.src_address)))
350         {
351           return rv;
352         }
353       clib_memcpy_fast (&headers->ip6.dst_address, &key->local_addr.ip6,
354                         sizeof (headers->ip6.dst_address));
355
356       headers->udp.dst_port = clib_host_to_net_u16 (UDP_DST_PORT_bfd_echo6);
357     }
358   else
359     {
360       clib_memcpy_fast (&headers->ip6.src_address, &key->local_addr.ip6,
361                         sizeof (headers->ip6.src_address));
362       clib_memcpy_fast (&headers->ip6.dst_address, &key->peer_addr.ip6,
363                         sizeof (headers->ip6.dst_address));
364       headers->udp.dst_port = clib_host_to_net_u16 (UDP_DST_PORT_bfd6);
365     }
366
367   /* fix ip payload length and udp length */
368   const u16 udp_length =
369     vlib_buffer_length_in_chain (vm, b) - (sizeof (headers->ip6));
370   headers->udp.length = clib_host_to_net_u16 (udp_length);
371   headers->ip6.payload_length = headers->udp.length;
372
373   /* IPv6 UDP checksum is mandatory */
374   int bogus = 0;
375   headers->udp.checksum =
376     ip6_tcp_udp_icmp_compute_checksum (vm, b, &headers->ip6, &bogus);
377   ASSERT (bogus == 0);
378   if (headers->udp.checksum == 0)
379     {
380       headers->udp.checksum = 0xffff;
381     }
382   return 1;
383 }
384
385 static void
386 bfd_create_frame_to_next_node (vlib_main_t *vm, bfd_main_t *bm,
387                                const bfd_session_t *bs, u32 bi, u32 next_node,
388                                vlib_combined_counter_main_t *tx_counter)
389 {
390   vlib_frame_t *f = vlib_get_frame_to_node (vm, next_node);
391   u32 *to_next = vlib_frame_vector_args (f);
392   to_next[0] = bi;
393   f->n_vectors = 1;
394   vlib_put_frame_to_node (vm, next_node, f);
395   vlib_buffer_t *b = vlib_get_buffer (vm, bi);
396   vlib_increment_combined_counter (tx_counter, vm->thread_index, bs->bs_idx, 1,
397                                    vlib_buffer_length_in_chain (vm, b));
398 }
399
400 int
401 bfd_udp_calc_next_node (const struct bfd_session_s *bs, u32 * next_node)
402 {
403   vnet_main_t *vnm = vnet_get_main ();
404   const bfd_udp_session_t *bus = &bs->udp;
405   ip_adjacency_t *adj = adj_get (bus->adj_index);
406
407   /* don't try to send the buffer if the interface is not up */
408   if (!vnet_sw_interface_is_up (vnm, bus->key.sw_if_index))
409     return 0;
410
411   switch (adj->lookup_next_index)
412     {
413     case IP_LOOKUP_NEXT_ARP:
414       switch (bs->transport)
415         {
416         case BFD_TRANSPORT_UDP4:
417           *next_node = bfd_udp_main.ip4_arp_idx;
418           return 1;
419         case BFD_TRANSPORT_UDP6:
420           *next_node = bfd_udp_main.ip6_ndp_idx;
421           return 1;
422         }
423       break;
424     case IP_LOOKUP_NEXT_REWRITE:
425       switch (bs->transport)
426         {
427         case BFD_TRANSPORT_UDP4:
428           *next_node = bfd_udp_main.ip4_rewrite_idx;
429           return 1;
430         case BFD_TRANSPORT_UDP6:
431           *next_node = bfd_udp_main.ip6_rewrite_idx;
432           return 1;
433         }
434       break;
435     case IP_LOOKUP_NEXT_MIDCHAIN:
436       switch (bs->transport)
437         {
438         case BFD_TRANSPORT_UDP4:
439           *next_node = bfd_udp_main.ip4_midchain_idx;
440           return 1;
441         case BFD_TRANSPORT_UDP6:
442           *next_node = bfd_udp_main.ip6_midchain_idx;
443           return 1;
444         }
445       break;
446     default:
447       /* drop */
448       break;
449     }
450   return 0;
451 }
452
453 int
454 bfd_transport_udp4 (vlib_main_t *vm, u32 bi, const struct bfd_session_s *bs,
455                     int is_echo)
456 {
457   u32 next_node;
458   int rv = bfd_udp_calc_next_node (bs, &next_node);
459   bfd_main_t *bm = bfd_udp_main.bfd_main;
460   if (rv)
461     {
462       bfd_create_frame_to_next_node (vm, bm, bs, bi, next_node,
463                                      is_echo ? &bm->tx_echo_counter :
464                                                &bm->tx_counter);
465     }
466   return rv;
467 }
468
469 int
470 bfd_transport_udp6 (vlib_main_t *vm, u32 bi, const struct bfd_session_s *bs,
471                     int is_echo)
472 {
473   u32 next_node;
474   int rv = bfd_udp_calc_next_node (bs, &next_node);
475   bfd_main_t *bm = bfd_udp_main.bfd_main;
476   if (rv)
477     {
478       bfd_create_frame_to_next_node (
479         vm, bfd_udp_main.bfd_main, bs, bi, next_node,
480         is_echo ? &bm->tx_echo_counter : &bm->tx_counter);
481     }
482   return 1;
483 }
484
485 static bfd_session_t *
486 bfd_lookup_session (bfd_udp_main_t * bum, const bfd_udp_key_t * key)
487 {
488   uword *p = mhash_get (&bum->bfd_session_idx_by_bfd_key, key);
489   if (p)
490     {
491       return bfd_find_session_by_idx (bum->bfd_main, *p);
492     }
493   return 0;
494 }
495
496 static void
497 bfd_udp_key_init (bfd_udp_key_t * key, u32 sw_if_index,
498                   const ip46_address_t * local_addr,
499                   const ip46_address_t * peer_addr)
500 {
501   clib_memset (key, 0, sizeof (*key));
502   key->sw_if_index = sw_if_index;
503   key->local_addr.as_u64[0] = local_addr->as_u64[0];
504   key->local_addr.as_u64[1] = local_addr->as_u64[1];
505   key->peer_addr.as_u64[0] = peer_addr->as_u64[0];
506   key->peer_addr.as_u64[1] = peer_addr->as_u64[1];
507 }
508
509 static vnet_api_error_t
510 bfd_udp_add_session_internal (vlib_main_t * vm, bfd_udp_main_t * bum,
511                               u32 sw_if_index, u32 desired_min_tx_usec,
512                               u32 required_min_rx_usec, u8 detect_mult,
513                               const ip46_address_t * local_addr,
514                               const ip46_address_t * peer_addr,
515                               bfd_session_t ** bs_out)
516 {
517   /* get a pool entry and if we end up not needing it, give it back */
518   bfd_transport_e t = BFD_TRANSPORT_UDP4;
519   if (!ip46_address_is_ip4 (local_addr))
520     {
521       t = BFD_TRANSPORT_UDP6;
522     }
523   bfd_session_t *bs = bfd_get_session (bum->bfd_main, t);
524   if (!bs)
525     {
526       return VNET_API_ERROR_BFD_EAGAIN;
527     }
528   bfd_udp_session_t *bus = &bs->udp;
529   clib_memset (bus, 0, sizeof (*bus));
530   bus->adj_index = ADJ_INDEX_INVALID;
531   bfd_udp_key_t *key = &bus->key;
532   bfd_udp_key_init (key, sw_if_index, local_addr, peer_addr);
533   const bfd_session_t *tmp = bfd_lookup_session (bum, key);
534   if (tmp)
535     {
536       vlib_log_err (bum->log_class,
537                     "duplicate bfd-udp session, existing bs_idx=%d",
538                     tmp->bs_idx);
539       bfd_put_session (bum->bfd_main, bs);
540       return VNET_API_ERROR_BFD_EEXIST;
541     }
542   mhash_set (&bum->bfd_session_idx_by_bfd_key, key, bs->bs_idx, NULL);
543   BFD_DBG ("session created, bs_idx=%u, sw_if_index=%d, local=%U, peer=%U",
544            bs->bs_idx, key->sw_if_index, format_ip46_address,
545            &key->local_addr, IP46_TYPE_ANY, format_ip46_address,
546            &key->peer_addr, IP46_TYPE_ANY);
547   vlib_log_info (bum->log_class, "create BFD session: %U",
548                  format_bfd_session, bs);
549   const ip46_address_t *peer =
550     (vnet_sw_interface_is_p2p (vnet_get_main (), key->sw_if_index) ?
551        &zero_addr :
552        &key->peer_addr);
553   if (BFD_TRANSPORT_UDP4 == t)
554     {
555       bus->adj_index = adj_nbr_add_or_lock (FIB_PROTOCOL_IP4, VNET_LINK_IP4,
556                                             peer, key->sw_if_index);
557       BFD_DBG ("adj_nbr_add_or_lock(FIB_PROTOCOL_IP4, VNET_LINK_IP4, %U, %d) "
558                "returns %d",
559                format_ip46_address, peer, IP46_TYPE_ANY, key->sw_if_index,
560                bus->adj_index);
561       ++bum->udp4_sessions_count;
562       bfd_udp_update_stat_segment_entry (
563         bum->udp4_sessions_count_stat_seg_entry, bum->udp4_sessions_count);
564       if (1 == bum->udp4_sessions_count)
565         {
566           udp_register_dst_port (vm, UDP_DST_PORT_bfd4,
567                                  bfd_udp4_input_node.index, 1);
568           udp_register_dst_port (vm, UDP_DST_PORT_bfd_echo4,
569                                  bfd_udp_echo4_input_node.index, 1);
570         }
571     }
572   else
573     {
574       bus->adj_index = adj_nbr_add_or_lock (FIB_PROTOCOL_IP6, VNET_LINK_IP6,
575                                             peer, key->sw_if_index);
576       BFD_DBG ("adj_nbr_add_or_lock(FIB_PROTOCOL_IP6, VNET_LINK_IP6, %U, %d) "
577                "returns %d",
578                format_ip46_address, peer, IP46_TYPE_ANY, key->sw_if_index,
579                bus->adj_index);
580       ++bum->udp6_sessions_count;
581       bfd_udp_update_stat_segment_entry (
582         bum->udp6_sessions_count_stat_seg_entry, bum->udp6_sessions_count);
583       if (1 == bum->udp6_sessions_count)
584         {
585           udp_register_dst_port (vm, UDP_DST_PORT_bfd6,
586                                  bfd_udp6_input_node.index, 0);
587           udp_register_dst_port (vm, UDP_DST_PORT_bfd_echo6,
588                                  bfd_udp_echo6_input_node.index, 0);
589         }
590     }
591   *bs_out = bs;
592   return bfd_session_set_params (bum->bfd_main, bs, desired_min_tx_usec,
593                                  required_min_rx_usec, detect_mult);
594 }
595
596 static vnet_api_error_t
597 bfd_udp_validate_api_input (u32 sw_if_index,
598                             const ip46_address_t * local_addr,
599                             const ip46_address_t * peer_addr)
600 {
601   bfd_udp_main_t *bum = &bfd_udp_main;
602   vnet_sw_interface_t *sw_if =
603     vnet_get_sw_interface_or_null (bfd_udp_main.vnet_main, sw_if_index);
604   u8 local_ip_valid = 0;
605   ip_interface_address_t *ia = NULL;
606   if (!sw_if)
607     {
608       vlib_log_err (bum->log_class,
609                     "got NULL sw_if when getting interface by index %u",
610                     sw_if_index);
611       return VNET_API_ERROR_INVALID_SW_IF_INDEX;
612     }
613   if (ip46_address_is_ip4 (local_addr))
614     {
615       if (!ip46_address_is_ip4 (peer_addr))
616         {
617           vlib_log_err (bum->log_class,
618                         "IP family mismatch (local is ipv4, peer is ipv6)");
619           return VNET_API_ERROR_INVALID_ARGUMENT;
620         }
621       ip4_main_t *im = &ip4_main;
622
623       /* *INDENT-OFF* */
624       foreach_ip_interface_address (
625           &im->lookup_main, ia, sw_if_index, 0 /* honor unnumbered */, ({
626             ip4_address_t *x =
627                 ip_interface_address_get_address (&im->lookup_main, ia);
628             if (x->as_u32 == local_addr->ip4.as_u32)
629               {
630                 /* valid address for this interface */
631                 local_ip_valid = 1;
632                 break;
633               }
634           }));
635       /* *INDENT-ON* */
636     }
637   else
638     {
639       if (ip46_address_is_ip4 (peer_addr))
640         {
641           vlib_log_err (bum->log_class,
642                         "IP family mismatch (local is ipv6, peer is ipv4)");
643           return VNET_API_ERROR_INVALID_ARGUMENT;
644         }
645
646       if (ip6_address_is_link_local_unicast (&local_addr->ip6))
647         {
648           const ip6_address_t *ll_addr;
649           ll_addr = ip6_get_link_local_address (sw_if_index);
650           if (ll_addr && ip6_address_is_equal (ll_addr, &local_addr->ip6))
651             {
652               /* valid address for this interface */
653               local_ip_valid = 1;
654             }
655         }
656       else
657         {
658           ip6_main_t *im = &ip6_main;
659           /* *INDENT-OFF* */
660           foreach_ip_interface_address (
661               &im->lookup_main, ia, sw_if_index, 0 /* honor unnumbered */, ({
662                 ip6_address_t *x =
663                     ip_interface_address_get_address (&im->lookup_main, ia);
664                 if (local_addr->ip6.as_u64[0] == x->as_u64[0] &&
665                     local_addr->ip6.as_u64[1] == x->as_u64[1])
666                   {
667                     /* valid address for this interface */
668                     local_ip_valid = 1;
669                     break;
670                   }
671               }));
672           /* *INDENT-ON* */
673         }
674     }
675
676   if (!local_ip_valid)
677     {
678       vlib_log_err (bum->log_class,
679                     "local address %U not found on interface with index %u",
680                     format_ip46_address, local_addr, IP46_TYPE_ANY,
681                     sw_if_index);
682       return VNET_API_ERROR_ADDRESS_NOT_FOUND_FOR_INTERFACE;
683     }
684
685   return 0;
686 }
687
688 static vnet_api_error_t
689 bfd_udp_find_session_by_api_input (u32 sw_if_index,
690                                    const ip46_address_t * local_addr,
691                                    const ip46_address_t * peer_addr,
692                                    bfd_session_t ** bs_out)
693 {
694   vnet_api_error_t rv =
695     bfd_udp_validate_api_input (sw_if_index, local_addr, peer_addr);
696   if (!rv)
697     {
698       bfd_udp_main_t *bum = &bfd_udp_main;
699       bfd_udp_key_t key;
700       bfd_udp_key_init (&key, sw_if_index, local_addr, peer_addr);
701       bfd_session_t *bs = bfd_lookup_session (bum, &key);
702       if (bs)
703         {
704           *bs_out = bs;
705         }
706       else
707         {
708           vlib_log_err (bum->log_class,
709                         "BFD session not found, sw_if_index=%u, local=%U, peer=%U",
710                         sw_if_index, format_ip46_address, local_addr,
711                         IP46_TYPE_ANY, format_ip46_address, peer_addr,
712                         IP46_TYPE_ANY);
713           return VNET_API_ERROR_BFD_ENOENT;
714         }
715     }
716   return rv;
717 }
718
719 static vnet_api_error_t
720 bfd_api_verify_common (u32 sw_if_index, u32 desired_min_tx_usec,
721                        u8 detect_mult, const ip46_address_t *local_addr,
722                        const ip46_address_t *peer_addr)
723 {
724   bfd_udp_main_t *bum = &bfd_udp_main;
725   vnet_api_error_t rv =
726     bfd_udp_validate_api_input (sw_if_index, local_addr, peer_addr);
727   if (rv)
728     {
729       return rv;
730     }
731   if (detect_mult < 1)
732     {
733       vlib_log_err (bum->log_class, "detect_mult < 1");
734       return VNET_API_ERROR_INVALID_ARGUMENT;
735     }
736   if (desired_min_tx_usec < 1)
737     {
738       vlib_log_err (bum->log_class, "desired_min_tx_usec < 1");
739       return VNET_API_ERROR_INVALID_ARGUMENT;
740     }
741   return 0;
742 }
743
744 static void
745 bfd_udp_del_session_internal (vlib_main_t * vm, bfd_session_t * bs)
746 {
747   bfd_udp_main_t *bum = &bfd_udp_main;
748   BFD_DBG ("free bfd-udp session, bs_idx=%d", bs->bs_idx);
749   bfd_session_stop (bum->bfd_main, bs);
750   mhash_unset (&bum->bfd_session_idx_by_bfd_key, &bs->udp.key, NULL);
751   adj_unlock (bs->udp.adj_index);
752   switch (bs->transport)
753     {
754     case BFD_TRANSPORT_UDP4:
755       --bum->udp4_sessions_count;
756       bfd_udp_update_stat_segment_entry (
757         bum->udp4_sessions_count_stat_seg_entry, bum->udp4_sessions_count);
758       if (!bum->udp4_sessions_count)
759         {
760           udp_unregister_dst_port (vm, UDP_DST_PORT_bfd4, 1);
761           udp_unregister_dst_port (vm, UDP_DST_PORT_bfd_echo4, 1);
762         }
763       break;
764     case BFD_TRANSPORT_UDP6:
765       --bum->udp6_sessions_count;
766       bfd_udp_update_stat_segment_entry (
767         bum->udp6_sessions_count_stat_seg_entry, bum->udp6_sessions_count);
768       if (!bum->udp6_sessions_count)
769         {
770           udp_unregister_dst_port (vm, UDP_DST_PORT_bfd6, 0);
771           udp_unregister_dst_port (vm, UDP_DST_PORT_bfd_echo6, 0);
772         }
773       break;
774     }
775   bfd_put_session (bum->bfd_main, bs);
776 }
777
778 static vnet_api_error_t
779 bfd_udp_add_and_start_session (u32 sw_if_index,
780                                const ip46_address_t *local_addr,
781                                const ip46_address_t *peer_addr,
782                                u32 desired_min_tx_usec,
783                                u32 required_min_rx_usec, u8 detect_mult,
784                                u8 is_authenticated, u32 conf_key_id,
785                                u8 bfd_key_id)
786 {
787   bfd_session_t *bs = NULL;
788   vnet_api_error_t rv;
789
790   rv = bfd_udp_add_session_internal (
791     vlib_get_main (), &bfd_udp_main, sw_if_index, desired_min_tx_usec,
792     required_min_rx_usec, detect_mult, local_addr, peer_addr, &bs);
793
794   if (!rv && is_authenticated)
795     {
796       rv = bfd_auth_activate (bs, conf_key_id, bfd_key_id,
797                               0 /* is not delayed */);
798       if (rv)
799         {
800           bfd_udp_del_session_internal (vlib_get_main (), bs);
801         }
802     }
803   if (!rv)
804     {
805       bfd_session_start (bfd_udp_main.bfd_main, bs);
806     }
807
808   return rv;
809 }
810
811 vnet_api_error_t
812 bfd_udp_add_session (u32 sw_if_index, const ip46_address_t * local_addr,
813                      const ip46_address_t * peer_addr,
814                      u32 desired_min_tx_usec, u32 required_min_rx_usec,
815                      u8 detect_mult, u8 is_authenticated, u32 conf_key_id,
816                      u8 bfd_key_id)
817 {
818   bfd_main_t *bm = &bfd_main;
819   bfd_lock (bm);
820
821   vnet_api_error_t rv = bfd_api_verify_common (
822     sw_if_index, desired_min_tx_usec, detect_mult, local_addr, peer_addr);
823
824   if (!rv)
825     rv = bfd_udp_add_and_start_session (
826       sw_if_index, local_addr, peer_addr, desired_min_tx_usec,
827       required_min_rx_usec, detect_mult, is_authenticated, conf_key_id,
828       bfd_key_id);
829
830   bfd_unlock (bm);
831   return rv;
832 }
833
834 vnet_api_error_t
835 bfd_udp_upd_session (u32 sw_if_index, const ip46_address_t *local_addr,
836                      const ip46_address_t *peer_addr, u32 desired_min_tx_usec,
837                      u32 required_min_rx_usec, u8 detect_mult,
838                      u8 is_authenticated, u32 conf_key_id, u8 bfd_key_id)
839 {
840   bfd_main_t *bm = &bfd_main;
841   bfd_lock (bm);
842
843   vnet_api_error_t rv = bfd_api_verify_common (
844     sw_if_index, desired_min_tx_usec, detect_mult, local_addr, peer_addr);
845   if (!rv)
846     {
847       bfd_session_t *bs = NULL;
848
849       rv = bfd_udp_find_session_by_api_input (sw_if_index, local_addr,
850                                               peer_addr, &bs);
851       if (VNET_API_ERROR_BFD_ENOENT == rv)
852         rv = bfd_udp_add_and_start_session (
853           sw_if_index, local_addr, peer_addr, desired_min_tx_usec,
854           required_min_rx_usec, detect_mult, is_authenticated, conf_key_id,
855           bfd_key_id);
856       else
857         rv = bfd_session_set_params (bfd_udp_main.bfd_main, bs,
858                                      desired_min_tx_usec, required_min_rx_usec,
859                                      detect_mult);
860     }
861
862   bfd_unlock (bm);
863   return rv;
864 }
865
866 vnet_api_error_t
867 bfd_udp_mod_session (u32 sw_if_index, const ip46_address_t *local_addr,
868                      const ip46_address_t *peer_addr, u32 desired_min_tx_usec,
869                      u32 required_min_rx_usec, u8 detect_mult)
870 {
871   bfd_session_t *bs = NULL;
872   bfd_main_t *bm = &bfd_main;
873   vnet_api_error_t error;
874   bfd_lock (bm);
875   vnet_api_error_t rv =
876     bfd_udp_find_session_by_api_input (sw_if_index, local_addr, peer_addr,
877                                        &bs);
878   if (rv)
879     {
880       bfd_unlock (bm);
881       return rv;
882     }
883
884   error = bfd_session_set_params (bfd_udp_main.bfd_main, bs,
885                                   desired_min_tx_usec, required_min_rx_usec,
886                                   detect_mult);
887   bfd_unlock (bm);
888   return error;
889 }
890
891 vnet_api_error_t
892 bfd_udp_del_session (u32 sw_if_index,
893                      const ip46_address_t * local_addr,
894                      const ip46_address_t * peer_addr)
895 {
896   bfd_session_t *bs = NULL;
897   bfd_main_t *bm = &bfd_main;
898   bfd_lock (bm);
899   vnet_api_error_t rv =
900     bfd_udp_find_session_by_api_input (sw_if_index, local_addr, peer_addr,
901                                        &bs);
902   if (rv)
903     {
904       bfd_unlock (bm);
905       return rv;
906     }
907   bfd_udp_del_session_internal (vlib_get_main (), bs);
908   bfd_unlock (bm);
909   return 0;
910 }
911
912 vnet_api_error_t
913 bfd_udp_session_set_flags (vlib_main_t * vm, u32 sw_if_index,
914                            const ip46_address_t * local_addr,
915                            const ip46_address_t * peer_addr, u8 admin_up_down)
916 {
917   bfd_session_t *bs = NULL;
918   bfd_main_t *bm = &bfd_main;
919   bfd_lock (bm);
920   vnet_api_error_t rv =
921     bfd_udp_find_session_by_api_input (sw_if_index, local_addr, peer_addr,
922                                        &bs);
923   if (rv)
924     {
925       bfd_unlock (bm);
926       return rv;
927     }
928   bfd_session_set_flags (vm, bs, admin_up_down);
929   bfd_unlock (bm);
930   return 0;
931 }
932
933 vnet_api_error_t
934 bfd_udp_auth_activate (u32 sw_if_index,
935                        const ip46_address_t * local_addr,
936                        const ip46_address_t * peer_addr,
937                        u32 conf_key_id, u8 key_id, u8 is_delayed)
938 {
939   bfd_main_t *bm = &bfd_main;
940   bfd_lock (bm);
941   vnet_api_error_t error;
942
943   bfd_session_t *bs = NULL;
944   vnet_api_error_t rv =
945     bfd_udp_find_session_by_api_input (sw_if_index, local_addr, peer_addr,
946                                        &bs);
947   if (rv)
948     {
949       bfd_unlock (bm);
950       return rv;
951     }
952   error = bfd_auth_activate (bs, conf_key_id, key_id, is_delayed);
953   bfd_unlock (bm);
954   return error;
955 }
956
957 vnet_api_error_t
958 bfd_udp_auth_deactivate (u32 sw_if_index,
959                          const ip46_address_t * local_addr,
960                          const ip46_address_t * peer_addr, u8 is_delayed)
961 {
962   bfd_main_t *bm = &bfd_main;
963   vnet_api_error_t error;
964   bfd_lock (bm);
965   bfd_session_t *bs = NULL;
966   vnet_api_error_t rv =
967     bfd_udp_find_session_by_api_input (sw_if_index, local_addr, peer_addr,
968                                        &bs);
969   if (rv)
970     {
971       bfd_unlock (bm);
972       return rv;
973     }
974   error = bfd_auth_deactivate (bs, is_delayed);
975   bfd_unlock (bm);
976   return error;
977 }
978
979 typedef enum
980 {
981   BFD_UDP_INPUT_NEXT_NORMAL,
982   BFD_UDP_INPUT_NEXT_REPLY_ARP,
983   BFD_UDP_INPUT_NEXT_REPLY_REWRITE,
984   BFD_UDP_INPUT_NEXT_REPLY_MIDCHAIN,
985   BFD_UDP_INPUT_N_NEXT,
986 } bfd_udp_input_next_t;
987
988 /* Packet counters - BFD control frames */
989 #define foreach_bfd_udp_error(F)           \
990   F (NONE, "good bfd packets (processed)") \
991   F (BAD, "invalid bfd packets")
992
993 #define F(sym, string) static char BFD_UDP_ERR_##sym##_STR[] = string;
994 foreach_bfd_udp_error (F);
995 #undef F
996
997 static char *bfd_udp_error_strings[] = {
998 #define F(sym, string) BFD_UDP_ERR_##sym##_STR,
999   foreach_bfd_udp_error (F)
1000 #undef F
1001 };
1002
1003 typedef enum
1004 {
1005 #define F(sym, str) BFD_UDP_ERROR_##sym,
1006   foreach_bfd_udp_error (F)
1007 #undef F
1008     BFD_UDP_N_ERROR,
1009 } bfd_udp_error_t;
1010
1011 typedef enum
1012 {
1013   BFD_UDP_ECHO_INPUT_NEXT_NORMAL,
1014   BFD_UDP_ECHO_INPUT_NEXT_REPLY_ARP,
1015   BFD_UDP_ECHO_INPUT_NEXT_REPLY_REWRITE,
1016   BFD_UDP_ECHO_INPUT_N_NEXT,
1017 } bfd_udp_echo_input_next_t;
1018
1019 /* Packet counters - BFD ECHO packets */
1020 #define foreach_bfd_udp_echo_error(F)           \
1021   F (NONE, "good bfd echo packets (processed)") \
1022   F (BAD, "invalid bfd echo packets")
1023
1024 #define F(sym, string) static char BFD_UDP_ECHO_ERR_##sym##_STR[] = string;
1025 foreach_bfd_udp_echo_error (F);
1026 #undef F
1027
1028 static char *bfd_udp_echo_error_strings[] = {
1029 #define F(sym, string) BFD_UDP_ECHO_ERR_##sym##_STR,
1030   foreach_bfd_udp_echo_error (F)
1031 #undef F
1032 };
1033
1034 typedef enum
1035 {
1036 #define F(sym, str) BFD_UDP_ECHO_ERROR_##sym,
1037   foreach_bfd_udp_echo_error (F)
1038 #undef F
1039     BFD_UDP_ECHO_N_ERROR,
1040 } bfd_udp_echo_error_t;
1041
1042 static void
1043 bfd_udp4_find_headers (vlib_buffer_t * b, ip4_header_t ** ip4,
1044                        udp_header_t ** udp)
1045 {
1046   /* sanity check first */
1047   const i32 start = vnet_buffer (b)->l3_hdr_offset;
1048   if (start < -(signed) sizeof (b->pre_data))
1049     {
1050       BFD_ERR ("Start of ip header is before pre_data, ignoring");
1051       *ip4 = NULL;
1052       *udp = NULL;
1053       return;
1054     }
1055   *ip4 = (ip4_header_t *) (b->data + start);
1056   if ((u8 *) * ip4 > (u8 *) vlib_buffer_get_current (b))
1057     {
1058       BFD_ERR ("Start of ip header is beyond current data, ignoring");
1059       *ip4 = NULL;
1060       *udp = NULL;
1061       return;
1062     }
1063   *udp = (udp_header_t *) ((*ip4) + 1);
1064 }
1065
1066 static bfd_udp_error_t
1067 bfd_udp4_verify_transport (const ip4_header_t * ip4,
1068                            const udp_header_t * udp, const bfd_session_t * bs)
1069 {
1070   const bfd_udp_session_t *bus = &bs->udp;
1071   const bfd_udp_key_t *key = &bus->key;
1072   if (ip4->src_address.as_u32 != key->peer_addr.ip4.as_u32)
1073     {
1074       BFD_ERR ("IPv4 src addr mismatch, got %U, expected %U",
1075                format_ip4_address, ip4->src_address.as_u8, format_ip4_address,
1076                key->peer_addr.ip4.as_u8);
1077       return BFD_UDP_ERROR_BAD;
1078     }
1079   if (ip4->dst_address.as_u32 != key->local_addr.ip4.as_u32)
1080     {
1081       BFD_ERR ("IPv4 dst addr mismatch, got %U, expected %U",
1082                format_ip4_address, ip4->dst_address.as_u8, format_ip4_address,
1083                key->local_addr.ip4.as_u8);
1084       return BFD_UDP_ERROR_BAD;
1085     }
1086   const u8 expected_ttl = 255;
1087   if (ip4->ttl != expected_ttl)
1088     {
1089       BFD_ERR ("IPv4 unexpected TTL value %u, expected %u", ip4->ttl,
1090                expected_ttl);
1091       return BFD_UDP_ERROR_BAD;
1092     }
1093   if (clib_net_to_host_u16 (udp->src_port) < 49152)
1094     {
1095       BFD_ERR ("Invalid UDP src port %u, out of range <49152,65535>",
1096                udp->src_port);
1097     }
1098   return BFD_UDP_ERROR_NONE;
1099 }
1100
1101 typedef struct
1102 {
1103   u32 bs_idx;
1104   bfd_pkt_t pkt;
1105 } bfd_rpc_update_t;
1106
1107 static void
1108 bfd_rpc_update_session (vlib_main_t * vm, u32 bs_idx, const bfd_pkt_t * pkt)
1109 {
1110   bfd_main_t *bm = &bfd_main;
1111   bfd_lock (bm);
1112   bfd_consume_pkt (vm, bm, pkt, bs_idx);
1113   bfd_unlock (bm);
1114 }
1115
1116 static bfd_udp_error_t
1117 bfd_udp4_scan (vlib_main_t *vm, vlib_buffer_t *b, bfd_session_t **bs_out)
1118 {
1119   const bfd_pkt_t *pkt = vlib_buffer_get_current (b);
1120   if (sizeof (*pkt) > b->current_length)
1121     {
1122       BFD_ERR
1123         ("Payload size %d too small to hold bfd packet of minimum size %d",
1124          b->current_length, sizeof (*pkt));
1125       return BFD_UDP_ERROR_BAD;
1126     }
1127   ip4_header_t *ip4;
1128   udp_header_t *udp;
1129   bfd_udp4_find_headers (b, &ip4, &udp);
1130   if (!ip4 || !udp)
1131     {
1132       BFD_ERR ("Couldn't find ip4 or udp header");
1133       return BFD_UDP_ERROR_BAD;
1134     }
1135   const u32 udp_payload_length = udp->length - sizeof (*udp);
1136   if (pkt->head.length > udp_payload_length)
1137     {
1138       BFD_ERR
1139         ("BFD packet length is larger than udp payload length (%u > %u)",
1140          pkt->head.length, udp_payload_length);
1141       return BFD_UDP_ERROR_BAD;
1142     }
1143   if (!bfd_verify_pkt_common (pkt))
1144     {
1145       return BFD_UDP_ERROR_BAD;
1146     }
1147   bfd_session_t *bs = NULL;
1148   if (pkt->your_disc)
1149     {
1150       BFD_DBG ("Looking up BFD session using discriminator %u",
1151                pkt->your_disc);
1152       bs = bfd_find_session_by_disc (bfd_udp_main.bfd_main, pkt->your_disc);
1153     }
1154   else
1155     {
1156       bfd_udp_key_t key;
1157       clib_memset (&key, 0, sizeof (key));
1158       key.sw_if_index = vnet_buffer (b)->sw_if_index[VLIB_RX];
1159       key.local_addr.ip4.as_u32 = ip4->dst_address.as_u32;
1160       key.peer_addr.ip4.as_u32 = ip4->src_address.as_u32;
1161       BFD_DBG ("Looking up BFD session using key (sw_if_index=%u, local=%U, "
1162                "peer=%U)",
1163                key.sw_if_index, format_ip4_address, key.local_addr.ip4.as_u8,
1164                format_ip4_address, key.peer_addr.ip4.as_u8);
1165       bs = bfd_lookup_session (&bfd_udp_main, &key);
1166     }
1167   if (!bs)
1168     {
1169       BFD_ERR ("BFD session lookup failed - no session matches BFD pkt");
1170       return BFD_UDP_ERROR_BAD;
1171     }
1172   BFD_DBG ("BFD session found, bs_idx=%u", bs->bs_idx);
1173   if (!bfd_verify_pkt_auth (vm, pkt, b->current_length, bs))
1174     {
1175       BFD_ERR ("Packet verification failed, dropping packet");
1176       return BFD_UDP_ERROR_BAD;
1177     }
1178   bfd_udp_error_t err;
1179   if (BFD_UDP_ERROR_NONE != (err = bfd_udp4_verify_transport (ip4, udp, bs)))
1180     {
1181       return err;
1182     }
1183   bfd_rpc_update_session (vm, bs->bs_idx, pkt);
1184   *bs_out = bs;
1185   return BFD_UDP_ERROR_NONE;
1186 }
1187
1188 static void
1189 bfd_udp6_find_headers (vlib_buffer_t * b, ip6_header_t ** ip6,
1190                        udp_header_t ** udp)
1191 {
1192   /* sanity check first */
1193   const i32 start = vnet_buffer (b)->l3_hdr_offset;
1194   if (start < -(signed) sizeof (b->pre_data))
1195     {
1196       BFD_ERR ("Start of ip header is before pre_data, ignoring");
1197       *ip6 = NULL;
1198       *udp = NULL;
1199       return;
1200     }
1201   *ip6 = (ip6_header_t *) (b->data + start);
1202   if ((u8 *) * ip6 > (u8 *) vlib_buffer_get_current (b))
1203     {
1204       BFD_ERR ("Start of ip header is beyond current data, ignoring");
1205       *ip6 = NULL;
1206       *udp = NULL;
1207       return;
1208     }
1209   if ((*ip6)->protocol != IP_PROTOCOL_UDP)
1210     {
1211       BFD_ERR ("Unexpected protocol in IPv6 header '%u', expected '%u' (== "
1212                "IP_PROTOCOL_UDP)", (*ip6)->protocol, IP_PROTOCOL_UDP);
1213       *ip6 = NULL;
1214       *udp = NULL;
1215       return;
1216     }
1217   *udp = (udp_header_t *) ((*ip6) + 1);
1218 }
1219
1220 static bfd_udp_error_t
1221 bfd_udp6_verify_transport (const ip6_header_t * ip6,
1222                            const udp_header_t * udp, const bfd_session_t * bs)
1223 {
1224   const bfd_udp_session_t *bus = &bs->udp;
1225   const bfd_udp_key_t *key = &bus->key;
1226   if (ip6->src_address.as_u64[0] != key->peer_addr.ip6.as_u64[0] &&
1227       ip6->src_address.as_u64[1] != key->peer_addr.ip6.as_u64[1])
1228     {
1229       BFD_ERR ("IP src addr mismatch, got %U, expected %U",
1230                format_ip6_address, ip6, format_ip6_address,
1231                &key->peer_addr.ip6);
1232       return BFD_UDP_ERROR_BAD;
1233     }
1234   if (ip6->dst_address.as_u64[0] != key->local_addr.ip6.as_u64[0] &&
1235       ip6->dst_address.as_u64[1] != key->local_addr.ip6.as_u64[1])
1236     {
1237       BFD_ERR ("IP dst addr mismatch, got %U, expected %U",
1238                format_ip6_address, ip6, format_ip6_address,
1239                &key->local_addr.ip6);
1240       return BFD_UDP_ERROR_BAD;
1241     }
1242   const u8 expected_hop_limit = 255;
1243   if (ip6->hop_limit != expected_hop_limit)
1244     {
1245       BFD_ERR ("IPv6 unexpected hop-limit value %u, expected %u",
1246                ip6->hop_limit, expected_hop_limit);
1247       return BFD_UDP_ERROR_BAD;
1248     }
1249   if (clib_net_to_host_u16 (udp->src_port) < 49152)
1250     {
1251       BFD_ERR ("Invalid UDP src port %u, out of range <49152,65535>",
1252                udp->src_port);
1253     }
1254   return BFD_UDP_ERROR_NONE;
1255 }
1256
1257 static bfd_udp_error_t
1258 bfd_udp6_scan (vlib_main_t *vm, vlib_buffer_t *b, bfd_session_t **bs_out)
1259 {
1260   const bfd_pkt_t *pkt = vlib_buffer_get_current (b);
1261   if (sizeof (*pkt) > b->current_length)
1262     {
1263       BFD_ERR
1264         ("Payload size %d too small to hold bfd packet of minimum size %d",
1265          b->current_length, sizeof (*pkt));
1266       return BFD_UDP_ERROR_BAD;
1267     }
1268   ip6_header_t *ip6;
1269   udp_header_t *udp;
1270   bfd_udp6_find_headers (b, &ip6, &udp);
1271   if (!ip6 || !udp)
1272     {
1273       BFD_ERR ("Couldn't find ip6 or udp header");
1274       return BFD_UDP_ERROR_BAD;
1275     }
1276   const u32 udp_payload_length = udp->length - sizeof (*udp);
1277   if (pkt->head.length > udp_payload_length)
1278     {
1279       BFD_ERR
1280         ("BFD packet length is larger than udp payload length (%u > %u)",
1281          pkt->head.length, udp_payload_length);
1282       return BFD_UDP_ERROR_BAD;
1283     }
1284   if (!bfd_verify_pkt_common (pkt))
1285     {
1286       return BFD_UDP_ERROR_BAD;
1287     }
1288   bfd_session_t *bs = NULL;
1289   if (pkt->your_disc)
1290     {
1291       BFD_DBG ("Looking up BFD session using discriminator %u",
1292                pkt->your_disc);
1293       bs = bfd_find_session_by_disc (bfd_udp_main.bfd_main, pkt->your_disc);
1294     }
1295   else
1296     {
1297       bfd_udp_key_t key;
1298       clib_memset (&key, 0, sizeof (key));
1299       key.sw_if_index = vnet_buffer (b)->sw_if_index[VLIB_RX];
1300       key.local_addr.ip6.as_u64[0] = ip6->dst_address.as_u64[0];
1301       key.local_addr.ip6.as_u64[1] = ip6->dst_address.as_u64[1];
1302       key.peer_addr.ip6.as_u64[0] = ip6->src_address.as_u64[0];
1303       key.peer_addr.ip6.as_u64[1] = ip6->src_address.as_u64[1];
1304       BFD_DBG ("Looking up BFD session using key (sw_if_index=%u, local=%U, "
1305                "peer=%U)",
1306                key.sw_if_index, format_ip6_address, &key.local_addr,
1307                format_ip6_address, &key.peer_addr);
1308       bs = bfd_lookup_session (&bfd_udp_main, &key);
1309     }
1310   if (!bs)
1311     {
1312       BFD_ERR ("BFD session lookup failed - no session matches BFD pkt");
1313       return BFD_UDP_ERROR_BAD;
1314     }
1315   BFD_DBG ("BFD session found, bs_idx=%u", bs->bs_idx);
1316   if (!bfd_verify_pkt_auth (vm, pkt, b->current_length, bs))
1317     {
1318       BFD_ERR ("Packet verification failed, dropping packet");
1319       return BFD_UDP_ERROR_BAD;
1320     }
1321   bfd_udp_error_t err;
1322   if (BFD_UDP_ERROR_NONE != (err = bfd_udp6_verify_transport (ip6, udp, bs)))
1323     {
1324       return err;
1325     }
1326   bfd_rpc_update_session (vm, bs->bs_idx, pkt);
1327   *bs_out = bs;
1328   return BFD_UDP_ERROR_NONE;
1329 }
1330
1331 /*
1332  * Process a frame of bfd packets
1333  * Expect 1 packet / frame
1334  */
1335 static uword
1336 bfd_udp_input (vlib_main_t * vm, vlib_node_runtime_t * rt,
1337                vlib_frame_t * f, int is_ipv6)
1338 {
1339   u32 n_left_from, *from;
1340   bfd_input_trace_t *t0;
1341   bfd_main_t *bm = &bfd_main;
1342
1343   from = vlib_frame_vector_args (f);    /* array of buffer indices */
1344   n_left_from = f->n_vectors;   /* number of buffer indices */
1345
1346   while (n_left_from > 0)
1347     {
1348       u32 bi0;
1349       vlib_buffer_t *b0;
1350       u32 next0, error0;
1351
1352       bi0 = from[0];
1353       b0 = vlib_get_buffer (vm, bi0);
1354
1355       bfd_session_t *bs = NULL;
1356
1357       /* If this pkt is traced, snapshot the data */
1358       if (b0->flags & VLIB_BUFFER_IS_TRACED)
1359         {
1360           u64 len;
1361           t0 = vlib_add_trace (vm, rt, b0, sizeof (*t0));
1362           len = (b0->current_length < sizeof (t0->data)) ? b0->current_length
1363             : sizeof (t0->data);
1364           t0->len = len;
1365           clib_memcpy_fast (t0->data, vlib_buffer_get_current (b0), len);
1366         }
1367
1368       /* scan this bfd pkt. error0 is the counter index to bmp */
1369       bfd_lock (bm);
1370       if (is_ipv6)
1371         {
1372           error0 = bfd_udp6_scan (vm, b0, &bs);
1373         }
1374       else
1375         {
1376           error0 = bfd_udp4_scan (vm, b0, &bs);
1377         }
1378       b0->error = rt->errors[error0];
1379
1380       next0 = BFD_UDP_INPUT_NEXT_NORMAL;
1381       if (BFD_UDP_ERROR_NONE == error0)
1382         {
1383           vlib_increment_combined_counter (
1384             &bm->rx_counter, vm->thread_index, bs->bs_idx, 1,
1385             vlib_buffer_length_in_chain (vm, b0));
1386           /*
1387            *  if everything went fine, check for poll bit, if present, re-use
1388            *  the buffer and based on (now updated) session parameters, send
1389            *  the final packet back
1390            */
1391           const bfd_pkt_t *pkt = vlib_buffer_get_current (b0);
1392           if (bfd_pkt_get_poll (pkt))
1393             {
1394               b0->current_data = 0;
1395               b0->current_length = 0;
1396               bfd_init_final_control_frame (vm, b0, bs);
1397               if (is_ipv6)
1398                 {
1399                   vlib_node_increment_counter (vm, bfd_udp6_input_node.index,
1400                                                b0->error, 1);
1401                 }
1402               else
1403                 {
1404                   vlib_node_increment_counter (vm, bfd_udp4_input_node.index,
1405                                                b0->error, 1);
1406                 }
1407               const bfd_udp_session_t *bus = &bs->udp;
1408               ip_adjacency_t *adj = adj_get (bus->adj_index);
1409               switch (adj->lookup_next_index)
1410                 {
1411                 case IP_LOOKUP_NEXT_ARP:
1412                   next0 = BFD_UDP_INPUT_NEXT_REPLY_ARP;
1413                   break;
1414                 case IP_LOOKUP_NEXT_REWRITE:
1415                   next0 = BFD_UDP_INPUT_NEXT_REPLY_REWRITE;
1416                   break;
1417                 case IP_LOOKUP_NEXT_MIDCHAIN:
1418                   next0 = BFD_UDP_INPUT_NEXT_REPLY_MIDCHAIN;
1419                   break;
1420                 default:
1421                   /* drop */
1422                   break;
1423                 }
1424             }
1425         }
1426       bfd_unlock (bm);
1427       vlib_set_next_frame_buffer (vm, rt, next0, bi0);
1428
1429       from += 1;
1430       n_left_from -= 1;
1431     }
1432
1433   return f->n_vectors;
1434 }
1435
1436 static uword
1437 bfd_udp4_input (vlib_main_t * vm, vlib_node_runtime_t * rt, vlib_frame_t * f)
1438 {
1439   return bfd_udp_input (vm, rt, f, 0);
1440 }
1441
1442 /*
1443  * bfd input graph node declaration
1444  */
1445 /* *INDENT-OFF* */
1446 VLIB_REGISTER_NODE (bfd_udp4_input_node, static) = {
1447   .function = bfd_udp4_input,
1448   .name = "bfd-udp4-input",
1449   .vector_size = sizeof (u32),
1450   .type = VLIB_NODE_TYPE_INTERNAL,
1451
1452   .n_errors = BFD_UDP_N_ERROR,
1453   .error_strings = bfd_udp_error_strings,
1454
1455   .format_trace = bfd_input_format_trace,
1456
1457   .n_next_nodes = BFD_UDP_INPUT_N_NEXT,
1458   .next_nodes =
1459       {
1460               [BFD_UDP_INPUT_NEXT_NORMAL] = "error-drop",
1461               [BFD_UDP_INPUT_NEXT_REPLY_ARP] = "ip4-arp",
1462               [BFD_UDP_INPUT_NEXT_REPLY_REWRITE] = "ip4-lookup",
1463               [BFD_UDP_INPUT_NEXT_REPLY_MIDCHAIN] = "ip4-midchain",
1464       },
1465 };
1466 /* *INDENT-ON* */
1467
1468 static uword
1469 bfd_udp6_input (vlib_main_t * vm, vlib_node_runtime_t * rt, vlib_frame_t * f)
1470 {
1471   return bfd_udp_input (vm, rt, f, 1);
1472 }
1473
1474 /* *INDENT-OFF* */
1475 VLIB_REGISTER_NODE (bfd_udp6_input_node, static) = {
1476   .function = bfd_udp6_input,
1477   .name = "bfd-udp6-input",
1478   .vector_size = sizeof (u32),
1479   .type = VLIB_NODE_TYPE_INTERNAL,
1480
1481   .n_errors = BFD_UDP_N_ERROR,
1482   .error_strings = bfd_udp_error_strings,
1483
1484   .format_trace = bfd_input_format_trace,
1485
1486   .n_next_nodes = BFD_UDP_INPUT_N_NEXT,
1487   .next_nodes =
1488       {
1489               [BFD_UDP_INPUT_NEXT_NORMAL] = "error-drop",
1490               [BFD_UDP_INPUT_NEXT_REPLY_ARP] = "ip6-discover-neighbor",
1491               [BFD_UDP_INPUT_NEXT_REPLY_REWRITE] = "ip6-lookup",
1492               [BFD_UDP_INPUT_NEXT_REPLY_MIDCHAIN] = "ip6-midchain",
1493       },
1494 };
1495 /* *INDENT-ON* */
1496
1497 /*
1498  * Process a frame of bfd echo packets
1499  * Expect 1 packet / frame
1500  */
1501 static uword
1502 bfd_udp_echo_input (vlib_main_t * vm, vlib_node_runtime_t * rt,
1503                     vlib_frame_t * f, int is_ipv6)
1504 {
1505   u32 n_left_from, *from;
1506   bfd_input_trace_t *t0;
1507   bfd_main_t *bm = &bfd_main;
1508
1509   from = vlib_frame_vector_args (f);    /* array of buffer indices */
1510   n_left_from = f->n_vectors;   /* number of buffer indices */
1511
1512   while (n_left_from > 0)
1513     {
1514       u32 bi0;
1515       vlib_buffer_t *b0;
1516       u32 next0;
1517
1518       bi0 = from[0];
1519       b0 = vlib_get_buffer (vm, bi0);
1520
1521       /* If this pkt is traced, snapshot the data */
1522       if (b0->flags & VLIB_BUFFER_IS_TRACED)
1523         {
1524           u64 len;
1525           t0 = vlib_add_trace (vm, rt, b0, sizeof (*t0));
1526           len = (b0->current_length < sizeof (t0->data)) ? b0->current_length
1527             : sizeof (t0->data);
1528           t0->len = len;
1529           clib_memcpy_fast (t0->data, vlib_buffer_get_current (b0), len);
1530         }
1531
1532       bfd_session_t *bs = NULL;
1533       bfd_lock (bm);
1534       if ((bs = bfd_consume_echo_pkt (vm, bfd_udp_main.bfd_main, b0)))
1535         {
1536           b0->error = rt->errors[BFD_UDP_ERROR_NONE];
1537           next0 = BFD_UDP_ECHO_INPUT_NEXT_NORMAL;
1538         }
1539       else
1540         {
1541           /* loop back the packet */
1542           b0->error = rt->errors[BFD_UDP_ERROR_NONE];
1543           if (is_ipv6)
1544             {
1545               vlib_node_increment_counter (vm, bfd_udp_echo6_input_node.index,
1546                                            b0->error, 1);
1547             }
1548           else
1549             {
1550               vlib_node_increment_counter (vm, bfd_udp_echo4_input_node.index,
1551                                            b0->error, 1);
1552             }
1553           next0 = BFD_UDP_ECHO_INPUT_NEXT_REPLY_REWRITE;
1554         }
1555
1556       bfd_unlock (bm);
1557
1558       if (bs)
1559         {
1560           vlib_increment_combined_counter (
1561             &bm->rx_echo_counter, vm->thread_index, bs->bs_idx, 1,
1562             vlib_buffer_length_in_chain (vm, b0));
1563         }
1564
1565       vlib_set_next_frame_buffer (vm, rt, next0, bi0);
1566
1567       from += 1;
1568       n_left_from -= 1;
1569     }
1570
1571   return f->n_vectors;
1572 }
1573
1574 static uword
1575 bfd_udp_echo4_input (vlib_main_t * vm, vlib_node_runtime_t * rt,
1576                      vlib_frame_t * f)
1577 {
1578   return bfd_udp_echo_input (vm, rt, f, 0);
1579 }
1580
1581 u8 *
1582 bfd_echo_input_format_trace (u8 * s, va_list * args)
1583 {
1584   CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
1585   CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
1586   const bfd_udp_echo_input_trace_t *t =
1587     va_arg (*args, bfd_udp_echo_input_trace_t *);
1588   if (t->len > STRUCT_SIZE_OF (bfd_pkt_t, head))
1589     {
1590       s = format (s, "BFD ECHO:\n");
1591       s = format (s, "    data: %U", format_hexdump, t->data, t->len);
1592     }
1593
1594   return s;
1595 }
1596
1597 /*
1598  * bfd input graph node declaration
1599  */
1600 /* *INDENT-OFF* */
1601 VLIB_REGISTER_NODE (bfd_udp_echo4_input_node, static) = {
1602   .function = bfd_udp_echo4_input,
1603   .name = "bfd-udp-echo4-input",
1604   .vector_size = sizeof (u32),
1605   .type = VLIB_NODE_TYPE_INTERNAL,
1606
1607   .n_errors = BFD_UDP_ECHO_N_ERROR,
1608   .error_strings = bfd_udp_error_strings,
1609
1610   .format_trace = bfd_echo_input_format_trace,
1611
1612   .n_next_nodes = BFD_UDP_ECHO_INPUT_N_NEXT,
1613   .next_nodes =
1614       {
1615               [BFD_UDP_ECHO_INPUT_NEXT_NORMAL] = "error-drop",
1616               [BFD_UDP_ECHO_INPUT_NEXT_REPLY_ARP] = "ip4-arp",
1617               [BFD_UDP_ECHO_INPUT_NEXT_REPLY_REWRITE] = "ip4-lookup",
1618       },
1619 };
1620 /* *INDENT-ON* */
1621
1622 static uword
1623 bfd_udp_echo6_input (vlib_main_t * vm, vlib_node_runtime_t * rt,
1624                      vlib_frame_t * f)
1625 {
1626   return bfd_udp_echo_input (vm, rt, f, 1);
1627 }
1628
1629 /* *INDENT-OFF* */
1630 VLIB_REGISTER_NODE (bfd_udp_echo6_input_node, static) = {
1631   .function = bfd_udp_echo6_input,
1632   .name = "bfd-udp-echo6-input",
1633   .vector_size = sizeof (u32),
1634   .type = VLIB_NODE_TYPE_INTERNAL,
1635
1636   .n_errors = BFD_UDP_ECHO_N_ERROR,
1637   .error_strings = bfd_udp_echo_error_strings,
1638
1639   .format_trace = bfd_echo_input_format_trace,
1640
1641   .n_next_nodes = BFD_UDP_ECHO_INPUT_N_NEXT,
1642   .next_nodes =
1643       {
1644               [BFD_UDP_ECHO_INPUT_NEXT_NORMAL] = "error-drop",
1645               [BFD_UDP_ECHO_INPUT_NEXT_REPLY_ARP] = "ip6-discover-neighbor",
1646               [BFD_UDP_ECHO_INPUT_NEXT_REPLY_REWRITE] = "ip6-lookup",
1647       },
1648 };
1649
1650 /* *INDENT-ON* */
1651
1652 static clib_error_t *
1653 bfd_udp_sw_if_add_del (CLIB_UNUSED (vnet_main_t *vnm), u32 sw_if_index,
1654                        u32 is_create)
1655 {
1656   u32 *to_be_freed = NULL;
1657   bfd_udp_main_t *bum = &bfd_udp_main;
1658   BFD_DBG ("sw_if_add_del called, sw_if_index=%u, is_create=%u", sw_if_index,
1659            is_create);
1660   if (!is_create)
1661     {
1662       bfd_session_t *bs;
1663       pool_foreach (bs, bum->bfd_main->sessions)
1664         {
1665           if (bs->transport != BFD_TRANSPORT_UDP4 &&
1666               bs->transport != BFD_TRANSPORT_UDP6)
1667             {
1668               continue;
1669             }
1670           if (bs->udp.key.sw_if_index != sw_if_index)
1671             {
1672               continue;
1673             }
1674           vec_add1 (to_be_freed, bs->bs_idx);
1675         }
1676     }
1677   u32 *bs_idx;
1678   vec_foreach (bs_idx, to_be_freed)
1679     {
1680       bfd_session_t *bs = pool_elt_at_index (bum->bfd_main->sessions, *bs_idx);
1681       vlib_log_notice (bum->log_class,
1682                        "removal of sw_if_index=%u forces removal of bfd "
1683                        "session with bs_idx=%u",
1684                        sw_if_index, bs->bs_idx);
1685       bfd_session_set_flags (vlib_get_main (), bs, 0);
1686       bfd_udp_del_session_internal (vlib_get_main (), bs);
1687     }
1688   return 0;
1689 }
1690
1691 VNET_SW_INTERFACE_ADD_DEL_FUNCTION (bfd_udp_sw_if_add_del);
1692
1693 clib_error_t *
1694 bfd_udp_stats_init (bfd_udp_main_t *bum)
1695 {
1696   const char *name4 = "/bfd/udp4/sessions";
1697   bum->udp4_sessions_count_stat_seg_entry = vlib_stats_add_gauge ("%s", name4);
1698
1699   vlib_stats_set_gauge (bum->udp4_sessions_count_stat_seg_entry, 0);
1700   if (~0 == bum->udp4_sessions_count_stat_seg_entry)
1701     {
1702       return clib_error_return (
1703         0, "Could not create stat segment entry for %s", name4);
1704     }
1705   const char *name6 = "/bfd/udp6/sessions";
1706   bum->udp6_sessions_count_stat_seg_entry = vlib_stats_add_gauge ("%s", name6);
1707
1708   vlib_stats_set_gauge (bum->udp6_sessions_count_stat_seg_entry, 0);
1709   if (~0 == bum->udp6_sessions_count_stat_seg_entry)
1710     {
1711       return clib_error_return (
1712         0, "Could not create stat segment entry for %s", name6);
1713     }
1714
1715   return 0;
1716 }
1717
1718 /*
1719  * setup function
1720  */
1721 static clib_error_t *
1722 bfd_udp_init (vlib_main_t * vm)
1723 {
1724   bfd_udp_main.udp4_sessions_count = 0;
1725   bfd_udp_main.udp6_sessions_count = 0;
1726   mhash_init (&bfd_udp_main.bfd_session_idx_by_bfd_key, sizeof (uword),
1727               sizeof (bfd_udp_key_t));
1728   bfd_udp_main.bfd_main = &bfd_main;
1729   bfd_udp_main.vnet_main = vnet_get_main ();
1730   vlib_node_t *node = vlib_get_node_by_name (vm, (u8 *) "ip4-arp");
1731   ASSERT (node);
1732   bfd_udp_main.ip4_arp_idx = node->index;
1733   node = vlib_get_node_by_name (vm, (u8 *) "ip6-discover-neighbor");
1734   ASSERT (node);
1735   bfd_udp_main.ip6_ndp_idx = node->index;
1736   node = vlib_get_node_by_name (vm, (u8 *) "ip4-rewrite");
1737   ASSERT (node);
1738   bfd_udp_main.ip4_rewrite_idx = node->index;
1739   node = vlib_get_node_by_name (vm, (u8 *) "ip6-rewrite");
1740   ASSERT (node);
1741   bfd_udp_main.ip6_rewrite_idx = node->index;
1742   node = vlib_get_node_by_name (vm, (u8 *) "ip4-midchain");
1743   ASSERT (node);
1744   bfd_udp_main.ip4_midchain_idx = node->index;
1745   node = vlib_get_node_by_name (vm, (u8 *) "ip6-midchain");
1746   ASSERT (node);
1747   bfd_udp_main.ip6_midchain_idx = node->index;
1748
1749   bfd_udp_stats_init (&bfd_udp_main);
1750
1751   bfd_udp_main.log_class = vlib_log_register_class ("bfd", "udp");
1752   vlib_log_debug (bfd_udp_main.log_class, "initialized");
1753   return 0;
1754 }
1755
1756 VLIB_INIT_FUNCTION (bfd_udp_init);
1757
1758 /*
1759  * fd.io coding-style-patch-verification: ON
1760  *
1761  * Local Variables:
1762  * eval: (c-set-style "gnu")
1763  * End:
1764  */