bfd: On a point to point link use the all zeros address for the peer.
[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 <vpp/stats/stat_segment.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_stat_segment_lock ();
89   stat_segment_set_state_counter (entry, value);
90   vlib_stat_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   bfd_udp_key_t *key = &bus->key;
531   bfd_udp_key_init (key, sw_if_index, local_addr, peer_addr);
532   const bfd_session_t *tmp = bfd_lookup_session (bum, key);
533   if (tmp)
534     {
535       vlib_log_err (bum->log_class,
536                     "duplicate bfd-udp session, existing bs_idx=%d",
537                     tmp->bs_idx);
538       bfd_put_session (bum->bfd_main, bs);
539       return VNET_API_ERROR_BFD_EEXIST;
540     }
541   mhash_set (&bum->bfd_session_idx_by_bfd_key, key, bs->bs_idx, NULL);
542   BFD_DBG ("session created, bs_idx=%u, sw_if_index=%d, local=%U, peer=%U",
543            bs->bs_idx, key->sw_if_index, format_ip46_address,
544            &key->local_addr, IP46_TYPE_ANY, format_ip46_address,
545            &key->peer_addr, IP46_TYPE_ANY);
546   vlib_log_info (bum->log_class, "create BFD session: %U",
547                  format_bfd_session, bs);
548   const ip46_address_t *peer =
549     (vnet_sw_interface_is_p2p (vnet_get_main (), key->sw_if_index) ?
550        &zero_addr :
551        &key->peer_addr);
552   if (BFD_TRANSPORT_UDP4 == t)
553     {
554       bus->adj_index = adj_nbr_add_or_lock (FIB_PROTOCOL_IP4, VNET_LINK_IP4,
555                                             peer, key->sw_if_index);
556       BFD_DBG ("adj_nbr_add_or_lock(FIB_PROTOCOL_IP4, VNET_LINK_IP4, %U, %d) "
557                "returns %d",
558                format_ip46_address, peer, IP46_TYPE_ANY, key->sw_if_index,
559                bus->adj_index);
560       ++bum->udp4_sessions_count;
561       bfd_udp_update_stat_segment_entry (
562         bum->udp4_sessions_count_stat_seg_entry, bum->udp4_sessions_count);
563       if (1 == bum->udp4_sessions_count)
564         {
565           udp_register_dst_port (vm, UDP_DST_PORT_bfd4,
566                                  bfd_udp4_input_node.index, 1);
567           udp_register_dst_port (vm, UDP_DST_PORT_bfd_echo4,
568                                  bfd_udp_echo4_input_node.index, 1);
569         }
570     }
571   else
572     {
573       bus->adj_index = adj_nbr_add_or_lock (FIB_PROTOCOL_IP6, VNET_LINK_IP6,
574                                             peer, key->sw_if_index);
575       BFD_DBG ("adj_nbr_add_or_lock(FIB_PROTOCOL_IP6, VNET_LINK_IP6, %U, %d) "
576                "returns %d",
577                format_ip46_address, peer, IP46_TYPE_ANY, key->sw_if_index,
578                bus->adj_index);
579       ++bum->udp6_sessions_count;
580       bfd_udp_update_stat_segment_entry (
581         bum->udp6_sessions_count_stat_seg_entry, bum->udp6_sessions_count);
582       if (1 == bum->udp6_sessions_count)
583         {
584           udp_register_dst_port (vm, UDP_DST_PORT_bfd6,
585                                  bfd_udp6_input_node.index, 0);
586           udp_register_dst_port (vm, UDP_DST_PORT_bfd_echo6,
587                                  bfd_udp_echo6_input_node.index, 0);
588         }
589     }
590   *bs_out = bs;
591   return bfd_session_set_params (bum->bfd_main, bs, desired_min_tx_usec,
592                                  required_min_rx_usec, detect_mult);
593 }
594
595 static vnet_api_error_t
596 bfd_udp_validate_api_input (u32 sw_if_index,
597                             const ip46_address_t * local_addr,
598                             const ip46_address_t * peer_addr)
599 {
600   bfd_udp_main_t *bum = &bfd_udp_main;
601   vnet_sw_interface_t *sw_if =
602     vnet_get_sw_interface_or_null (bfd_udp_main.vnet_main, sw_if_index);
603   u8 local_ip_valid = 0;
604   ip_interface_address_t *ia = NULL;
605   if (!sw_if)
606     {
607       vlib_log_err (bum->log_class,
608                     "got NULL sw_if when getting interface by index %u",
609                     sw_if_index);
610       return VNET_API_ERROR_INVALID_SW_IF_INDEX;
611     }
612   if (ip46_address_is_ip4 (local_addr))
613     {
614       if (!ip46_address_is_ip4 (peer_addr))
615         {
616           vlib_log_err (bum->log_class,
617                         "IP family mismatch (local is ipv4, peer is ipv6)");
618           return VNET_API_ERROR_INVALID_ARGUMENT;
619         }
620       ip4_main_t *im = &ip4_main;
621
622       /* *INDENT-OFF* */
623       foreach_ip_interface_address (
624           &im->lookup_main, ia, sw_if_index, 0 /* honor unnumbered */, ({
625             ip4_address_t *x =
626                 ip_interface_address_get_address (&im->lookup_main, ia);
627             if (x->as_u32 == local_addr->ip4.as_u32)
628               {
629                 /* valid address for this interface */
630                 local_ip_valid = 1;
631                 break;
632               }
633           }));
634       /* *INDENT-ON* */
635     }
636   else
637     {
638       if (ip46_address_is_ip4 (peer_addr))
639         {
640           vlib_log_err (bum->log_class,
641                         "IP family mismatch (local is ipv6, peer is ipv4)");
642           return VNET_API_ERROR_INVALID_ARGUMENT;
643         }
644
645       if (ip6_address_is_link_local_unicast (&local_addr->ip6))
646         {
647           const ip6_address_t *ll_addr;
648           ll_addr = ip6_get_link_local_address (sw_if_index);
649           if (ll_addr && ip6_address_is_equal (ll_addr, &local_addr->ip6))
650             {
651               /* valid address for this interface */
652               local_ip_valid = 1;
653             }
654         }
655       else
656         {
657           ip6_main_t *im = &ip6_main;
658           /* *INDENT-OFF* */
659           foreach_ip_interface_address (
660               &im->lookup_main, ia, sw_if_index, 0 /* honor unnumbered */, ({
661                 ip6_address_t *x =
662                     ip_interface_address_get_address (&im->lookup_main, ia);
663                 if (local_addr->ip6.as_u64[0] == x->as_u64[0] &&
664                     local_addr->ip6.as_u64[1] == x->as_u64[1])
665                   {
666                     /* valid address for this interface */
667                     local_ip_valid = 1;
668                     break;
669                   }
670               }));
671           /* *INDENT-ON* */
672         }
673     }
674
675   if (!local_ip_valid)
676     {
677       vlib_log_err (bum->log_class,
678                     "local address %U not found on interface with index %u",
679                     format_ip46_address, local_addr, IP46_TYPE_ANY,
680                     sw_if_index);
681       return VNET_API_ERROR_ADDRESS_NOT_FOUND_FOR_INTERFACE;
682     }
683
684   return 0;
685 }
686
687 static vnet_api_error_t
688 bfd_udp_find_session_by_api_input (u32 sw_if_index,
689                                    const ip46_address_t * local_addr,
690                                    const ip46_address_t * peer_addr,
691                                    bfd_session_t ** bs_out)
692 {
693   vnet_api_error_t rv =
694     bfd_udp_validate_api_input (sw_if_index, local_addr, peer_addr);
695   if (!rv)
696     {
697       bfd_udp_main_t *bum = &bfd_udp_main;
698       bfd_udp_key_t key;
699       bfd_udp_key_init (&key, sw_if_index, local_addr, peer_addr);
700       bfd_session_t *bs = bfd_lookup_session (bum, &key);
701       if (bs)
702         {
703           *bs_out = bs;
704         }
705       else
706         {
707           vlib_log_err (bum->log_class,
708                         "BFD session not found, sw_if_index=%u, local=%U, peer=%U",
709                         sw_if_index, format_ip46_address, local_addr,
710                         IP46_TYPE_ANY, format_ip46_address, peer_addr,
711                         IP46_TYPE_ANY);
712           return VNET_API_ERROR_BFD_ENOENT;
713         }
714     }
715   return rv;
716 }
717
718 static vnet_api_error_t
719 bfd_api_verify_common (u32 sw_if_index, u32 desired_min_tx_usec,
720                        u8 detect_mult, const ip46_address_t *local_addr,
721                        const ip46_address_t *peer_addr)
722 {
723   bfd_udp_main_t *bum = &bfd_udp_main;
724   vnet_api_error_t rv =
725     bfd_udp_validate_api_input (sw_if_index, local_addr, peer_addr);
726   if (rv)
727     {
728       return rv;
729     }
730   if (detect_mult < 1)
731     {
732       vlib_log_err (bum->log_class, "detect_mult < 1");
733       return VNET_API_ERROR_INVALID_ARGUMENT;
734     }
735   if (desired_min_tx_usec < 1)
736     {
737       vlib_log_err (bum->log_class, "desired_min_tx_usec < 1");
738       return VNET_API_ERROR_INVALID_ARGUMENT;
739     }
740   return 0;
741 }
742
743 static void
744 bfd_udp_del_session_internal (vlib_main_t * vm, bfd_session_t * bs)
745 {
746   bfd_udp_main_t *bum = &bfd_udp_main;
747   BFD_DBG ("free bfd-udp session, bs_idx=%d", bs->bs_idx);
748   mhash_unset (&bum->bfd_session_idx_by_bfd_key, &bs->udp.key, NULL);
749   adj_unlock (bs->udp.adj_index);
750   switch (bs->transport)
751     {
752     case BFD_TRANSPORT_UDP4:
753       --bum->udp4_sessions_count;
754       bfd_udp_update_stat_segment_entry (
755         bum->udp4_sessions_count_stat_seg_entry, bum->udp4_sessions_count);
756       if (!bum->udp4_sessions_count)
757         {
758           udp_unregister_dst_port (vm, UDP_DST_PORT_bfd4, 1);
759           udp_unregister_dst_port (vm, UDP_DST_PORT_bfd_echo4, 1);
760         }
761       break;
762     case BFD_TRANSPORT_UDP6:
763       --bum->udp6_sessions_count;
764       bfd_udp_update_stat_segment_entry (
765         bum->udp6_sessions_count_stat_seg_entry, bum->udp6_sessions_count);
766       if (!bum->udp6_sessions_count)
767         {
768           udp_unregister_dst_port (vm, UDP_DST_PORT_bfd6, 0);
769           udp_unregister_dst_port (vm, UDP_DST_PORT_bfd_echo6, 0);
770         }
771       break;
772     }
773   bfd_put_session (bum->bfd_main, bs);
774 }
775
776 static vnet_api_error_t
777 bfd_udp_add_and_start_session (u32 sw_if_index,
778                                const ip46_address_t *local_addr,
779                                const ip46_address_t *peer_addr,
780                                u32 desired_min_tx_usec,
781                                u32 required_min_rx_usec, u8 detect_mult,
782                                u8 is_authenticated, u32 conf_key_id,
783                                u8 bfd_key_id)
784 {
785   bfd_session_t *bs = NULL;
786   vnet_api_error_t rv;
787
788   rv = bfd_udp_add_session_internal (
789     vlib_get_main (), &bfd_udp_main, sw_if_index, desired_min_tx_usec,
790     required_min_rx_usec, detect_mult, local_addr, peer_addr, &bs);
791
792   if (!rv && is_authenticated)
793     {
794       rv = bfd_auth_activate (bs, conf_key_id, bfd_key_id,
795                               0 /* is not delayed */);
796       if (rv)
797         {
798           bfd_udp_del_session_internal (vlib_get_main (), bs);
799         }
800     }
801   if (!rv)
802     {
803       bfd_session_start (bfd_udp_main.bfd_main, bs);
804     }
805
806   return rv;
807 }
808
809 vnet_api_error_t
810 bfd_udp_add_session (u32 sw_if_index, const ip46_address_t * local_addr,
811                      const ip46_address_t * peer_addr,
812                      u32 desired_min_tx_usec, u32 required_min_rx_usec,
813                      u8 detect_mult, u8 is_authenticated, u32 conf_key_id,
814                      u8 bfd_key_id)
815 {
816   bfd_main_t *bm = &bfd_main;
817   bfd_lock (bm);
818
819   vnet_api_error_t rv = bfd_api_verify_common (
820     sw_if_index, desired_min_tx_usec, detect_mult, local_addr, peer_addr);
821
822   if (!rv)
823     rv = bfd_udp_add_and_start_session (
824       sw_if_index, local_addr, peer_addr, desired_min_tx_usec,
825       required_min_rx_usec, detect_mult, is_authenticated, conf_key_id,
826       bfd_key_id);
827
828   bfd_unlock (bm);
829   return rv;
830 }
831
832 vnet_api_error_t
833 bfd_udp_upd_session (u32 sw_if_index, const ip46_address_t *local_addr,
834                      const ip46_address_t *peer_addr, u32 desired_min_tx_usec,
835                      u32 required_min_rx_usec, u8 detect_mult,
836                      u8 is_authenticated, u32 conf_key_id, u8 bfd_key_id)
837 {
838   bfd_main_t *bm = &bfd_main;
839   bfd_lock (bm);
840
841   vnet_api_error_t rv = bfd_api_verify_common (
842     sw_if_index, desired_min_tx_usec, detect_mult, local_addr, peer_addr);
843   if (!rv)
844     {
845       bfd_session_t *bs = NULL;
846
847       rv = bfd_udp_find_session_by_api_input (sw_if_index, local_addr,
848                                               peer_addr, &bs);
849       if (VNET_API_ERROR_BFD_ENOENT == rv)
850         rv = bfd_udp_add_and_start_session (
851           sw_if_index, local_addr, peer_addr, desired_min_tx_usec,
852           required_min_rx_usec, detect_mult, is_authenticated, conf_key_id,
853           bfd_key_id);
854       else
855         rv = bfd_session_set_params (bfd_udp_main.bfd_main, bs,
856                                      desired_min_tx_usec, required_min_rx_usec,
857                                      detect_mult);
858     }
859
860   bfd_unlock (bm);
861   return rv;
862 }
863
864 vnet_api_error_t
865 bfd_udp_mod_session (u32 sw_if_index, const ip46_address_t *local_addr,
866                      const ip46_address_t *peer_addr, u32 desired_min_tx_usec,
867                      u32 required_min_rx_usec, u8 detect_mult)
868 {
869   bfd_session_t *bs = NULL;
870   bfd_main_t *bm = &bfd_main;
871   vnet_api_error_t error;
872   bfd_lock (bm);
873   vnet_api_error_t rv =
874     bfd_udp_find_session_by_api_input (sw_if_index, local_addr, peer_addr,
875                                        &bs);
876   if (rv)
877     {
878       bfd_unlock (bm);
879       return rv;
880     }
881
882   error = bfd_session_set_params (bfd_udp_main.bfd_main, bs,
883                                   desired_min_tx_usec, required_min_rx_usec,
884                                   detect_mult);
885   bfd_unlock (bm);
886   return error;
887 }
888
889 vnet_api_error_t
890 bfd_udp_del_session (u32 sw_if_index,
891                      const ip46_address_t * local_addr,
892                      const ip46_address_t * peer_addr)
893 {
894   bfd_session_t *bs = NULL;
895   bfd_main_t *bm = &bfd_main;
896   bfd_lock (bm);
897   vnet_api_error_t rv =
898     bfd_udp_find_session_by_api_input (sw_if_index, local_addr, peer_addr,
899                                        &bs);
900   if (rv)
901     {
902       bfd_unlock (bm);
903       return rv;
904     }
905   bfd_udp_del_session_internal (vlib_get_main (), bs);
906   bfd_unlock (bm);
907   return 0;
908 }
909
910 vnet_api_error_t
911 bfd_udp_session_set_flags (vlib_main_t * vm, u32 sw_if_index,
912                            const ip46_address_t * local_addr,
913                            const ip46_address_t * peer_addr, u8 admin_up_down)
914 {
915   bfd_session_t *bs = NULL;
916   bfd_main_t *bm = &bfd_main;
917   bfd_lock (bm);
918   vnet_api_error_t rv =
919     bfd_udp_find_session_by_api_input (sw_if_index, local_addr, peer_addr,
920                                        &bs);
921   if (rv)
922     {
923       bfd_unlock (bm);
924       return rv;
925     }
926   bfd_session_set_flags (vm, bs, admin_up_down);
927   bfd_unlock (bm);
928   return 0;
929 }
930
931 vnet_api_error_t
932 bfd_udp_auth_activate (u32 sw_if_index,
933                        const ip46_address_t * local_addr,
934                        const ip46_address_t * peer_addr,
935                        u32 conf_key_id, u8 key_id, u8 is_delayed)
936 {
937   bfd_main_t *bm = &bfd_main;
938   bfd_lock (bm);
939   vnet_api_error_t error;
940
941   bfd_session_t *bs = NULL;
942   vnet_api_error_t rv =
943     bfd_udp_find_session_by_api_input (sw_if_index, local_addr, peer_addr,
944                                        &bs);
945   if (rv)
946     {
947       bfd_unlock (bm);
948       return rv;
949     }
950   error = bfd_auth_activate (bs, conf_key_id, key_id, is_delayed);
951   bfd_unlock (bm);
952   return error;
953 }
954
955 vnet_api_error_t
956 bfd_udp_auth_deactivate (u32 sw_if_index,
957                          const ip46_address_t * local_addr,
958                          const ip46_address_t * peer_addr, u8 is_delayed)
959 {
960   bfd_main_t *bm = &bfd_main;
961   vnet_api_error_t error;
962   bfd_lock (bm);
963   bfd_session_t *bs = NULL;
964   vnet_api_error_t rv =
965     bfd_udp_find_session_by_api_input (sw_if_index, local_addr, peer_addr,
966                                        &bs);
967   if (rv)
968     {
969       bfd_unlock (bm);
970       return rv;
971     }
972   error = bfd_auth_deactivate (bs, is_delayed);
973   bfd_unlock (bm);
974   return error;
975 }
976
977 typedef enum
978 {
979   BFD_UDP_INPUT_NEXT_NORMAL,
980   BFD_UDP_INPUT_NEXT_REPLY_ARP,
981   BFD_UDP_INPUT_NEXT_REPLY_REWRITE,
982   BFD_UDP_INPUT_NEXT_REPLY_MIDCHAIN,
983   BFD_UDP_INPUT_N_NEXT,
984 } bfd_udp_input_next_t;
985
986 /* Packet counters - BFD control frames */
987 #define foreach_bfd_udp_error(F)           \
988   F (NONE, "good bfd packets (processed)") \
989   F (BAD, "invalid bfd packets")
990
991 #define F(sym, string) static char BFD_UDP_ERR_##sym##_STR[] = string;
992 foreach_bfd_udp_error (F);
993 #undef F
994
995 static char *bfd_udp_error_strings[] = {
996 #define F(sym, string) BFD_UDP_ERR_##sym##_STR,
997   foreach_bfd_udp_error (F)
998 #undef F
999 };
1000
1001 typedef enum
1002 {
1003 #define F(sym, str) BFD_UDP_ERROR_##sym,
1004   foreach_bfd_udp_error (F)
1005 #undef F
1006     BFD_UDP_N_ERROR,
1007 } bfd_udp_error_t;
1008
1009 typedef enum
1010 {
1011   BFD_UDP_ECHO_INPUT_NEXT_NORMAL,
1012   BFD_UDP_ECHO_INPUT_NEXT_REPLY_ARP,
1013   BFD_UDP_ECHO_INPUT_NEXT_REPLY_REWRITE,
1014   BFD_UDP_ECHO_INPUT_N_NEXT,
1015 } bfd_udp_echo_input_next_t;
1016
1017 /* Packet counters - BFD ECHO packets */
1018 #define foreach_bfd_udp_echo_error(F)           \
1019   F (NONE, "good bfd echo packets (processed)") \
1020   F (BAD, "invalid bfd echo packets")
1021
1022 #define F(sym, string) static char BFD_UDP_ECHO_ERR_##sym##_STR[] = string;
1023 foreach_bfd_udp_echo_error (F);
1024 #undef F
1025
1026 static char *bfd_udp_echo_error_strings[] = {
1027 #define F(sym, string) BFD_UDP_ECHO_ERR_##sym##_STR,
1028   foreach_bfd_udp_echo_error (F)
1029 #undef F
1030 };
1031
1032 typedef enum
1033 {
1034 #define F(sym, str) BFD_UDP_ECHO_ERROR_##sym,
1035   foreach_bfd_udp_echo_error (F)
1036 #undef F
1037     BFD_UDP_ECHO_N_ERROR,
1038 } bfd_udp_echo_error_t;
1039
1040 static void
1041 bfd_udp4_find_headers (vlib_buffer_t * b, ip4_header_t ** ip4,
1042                        udp_header_t ** udp)
1043 {
1044   /* sanity check first */
1045   const i32 start = vnet_buffer (b)->l3_hdr_offset;
1046   if (start < -(signed) sizeof (b->pre_data))
1047     {
1048       BFD_ERR ("Start of ip header is before pre_data, ignoring");
1049       *ip4 = NULL;
1050       *udp = NULL;
1051       return;
1052     }
1053   *ip4 = (ip4_header_t *) (b->data + start);
1054   if ((u8 *) * ip4 > (u8 *) vlib_buffer_get_current (b))
1055     {
1056       BFD_ERR ("Start of ip header is beyond current data, ignoring");
1057       *ip4 = NULL;
1058       *udp = NULL;
1059       return;
1060     }
1061   *udp = (udp_header_t *) ((*ip4) + 1);
1062 }
1063
1064 static bfd_udp_error_t
1065 bfd_udp4_verify_transport (const ip4_header_t * ip4,
1066                            const udp_header_t * udp, const bfd_session_t * bs)
1067 {
1068   const bfd_udp_session_t *bus = &bs->udp;
1069   const bfd_udp_key_t *key = &bus->key;
1070   if (ip4->src_address.as_u32 != key->peer_addr.ip4.as_u32)
1071     {
1072       BFD_ERR ("IPv4 src addr mismatch, got %U, expected %U",
1073                format_ip4_address, ip4->src_address.as_u8, format_ip4_address,
1074                key->peer_addr.ip4.as_u8);
1075       return BFD_UDP_ERROR_BAD;
1076     }
1077   if (ip4->dst_address.as_u32 != key->local_addr.ip4.as_u32)
1078     {
1079       BFD_ERR ("IPv4 dst addr mismatch, got %U, expected %U",
1080                format_ip4_address, ip4->dst_address.as_u8, format_ip4_address,
1081                key->local_addr.ip4.as_u8);
1082       return BFD_UDP_ERROR_BAD;
1083     }
1084   const u8 expected_ttl = 255;
1085   if (ip4->ttl != expected_ttl)
1086     {
1087       BFD_ERR ("IPv4 unexpected TTL value %u, expected %u", ip4->ttl,
1088                expected_ttl);
1089       return BFD_UDP_ERROR_BAD;
1090     }
1091   if (clib_net_to_host_u16 (udp->src_port) < 49152)
1092     {
1093       BFD_ERR ("Invalid UDP src port %u, out of range <49152,65535>",
1094                udp->src_port);
1095     }
1096   return BFD_UDP_ERROR_NONE;
1097 }
1098
1099 typedef struct
1100 {
1101   u32 bs_idx;
1102   bfd_pkt_t pkt;
1103 } bfd_rpc_update_t;
1104
1105 static void
1106 bfd_rpc_update_session (vlib_main_t * vm, u32 bs_idx, const bfd_pkt_t * pkt)
1107 {
1108   bfd_main_t *bm = &bfd_main;
1109   bfd_lock (bm);
1110   bfd_consume_pkt (vm, bm, pkt, bs_idx);
1111   bfd_unlock (bm);
1112 }
1113
1114 static bfd_udp_error_t
1115 bfd_udp4_scan (vlib_main_t *vm, vlib_buffer_t *b, bfd_session_t **bs_out)
1116 {
1117   const bfd_pkt_t *pkt = vlib_buffer_get_current (b);
1118   if (sizeof (*pkt) > b->current_length)
1119     {
1120       BFD_ERR
1121         ("Payload size %d too small to hold bfd packet of minimum size %d",
1122          b->current_length, sizeof (*pkt));
1123       return BFD_UDP_ERROR_BAD;
1124     }
1125   ip4_header_t *ip4;
1126   udp_header_t *udp;
1127   bfd_udp4_find_headers (b, &ip4, &udp);
1128   if (!ip4 || !udp)
1129     {
1130       BFD_ERR ("Couldn't find ip4 or udp header");
1131       return BFD_UDP_ERROR_BAD;
1132     }
1133   const u32 udp_payload_length = udp->length - sizeof (*udp);
1134   if (pkt->head.length > udp_payload_length)
1135     {
1136       BFD_ERR
1137         ("BFD packet length is larger than udp payload length (%u > %u)",
1138          pkt->head.length, udp_payload_length);
1139       return BFD_UDP_ERROR_BAD;
1140     }
1141   if (!bfd_verify_pkt_common (pkt))
1142     {
1143       return BFD_UDP_ERROR_BAD;
1144     }
1145   bfd_session_t *bs = NULL;
1146   if (pkt->your_disc)
1147     {
1148       BFD_DBG ("Looking up BFD session using discriminator %u",
1149                pkt->your_disc);
1150       bs = bfd_find_session_by_disc (bfd_udp_main.bfd_main, pkt->your_disc);
1151     }
1152   else
1153     {
1154       bfd_udp_key_t key;
1155       clib_memset (&key, 0, sizeof (key));
1156       key.sw_if_index = vnet_buffer (b)->sw_if_index[VLIB_RX];
1157       key.local_addr.ip4.as_u32 = ip4->dst_address.as_u32;
1158       key.peer_addr.ip4.as_u32 = ip4->src_address.as_u32;
1159       BFD_DBG ("Looking up BFD session using key (sw_if_index=%u, local=%U, "
1160                "peer=%U)",
1161                key.sw_if_index, format_ip4_address, key.local_addr.ip4.as_u8,
1162                format_ip4_address, key.peer_addr.ip4.as_u8);
1163       bs = bfd_lookup_session (&bfd_udp_main, &key);
1164     }
1165   if (!bs)
1166     {
1167       BFD_ERR ("BFD session lookup failed - no session matches BFD pkt");
1168       return BFD_UDP_ERROR_BAD;
1169     }
1170   BFD_DBG ("BFD session found, bs_idx=%u", bs->bs_idx);
1171   if (!bfd_verify_pkt_auth (vm, pkt, b->current_length, bs))
1172     {
1173       BFD_ERR ("Packet verification failed, dropping packet");
1174       return BFD_UDP_ERROR_BAD;
1175     }
1176   bfd_udp_error_t err;
1177   if (BFD_UDP_ERROR_NONE != (err = bfd_udp4_verify_transport (ip4, udp, bs)))
1178     {
1179       return err;
1180     }
1181   bfd_rpc_update_session (vm, bs->bs_idx, pkt);
1182   *bs_out = bs;
1183   return BFD_UDP_ERROR_NONE;
1184 }
1185
1186 static void
1187 bfd_udp6_find_headers (vlib_buffer_t * b, ip6_header_t ** ip6,
1188                        udp_header_t ** udp)
1189 {
1190   /* sanity check first */
1191   const i32 start = vnet_buffer (b)->l3_hdr_offset;
1192   if (start < -(signed) sizeof (b->pre_data))
1193     {
1194       BFD_ERR ("Start of ip header is before pre_data, ignoring");
1195       *ip6 = NULL;
1196       *udp = NULL;
1197       return;
1198     }
1199   *ip6 = (ip6_header_t *) (b->data + start);
1200   if ((u8 *) * ip6 > (u8 *) vlib_buffer_get_current (b))
1201     {
1202       BFD_ERR ("Start of ip header is beyond current data, ignoring");
1203       *ip6 = NULL;
1204       *udp = NULL;
1205       return;
1206     }
1207   if ((*ip6)->protocol != IP_PROTOCOL_UDP)
1208     {
1209       BFD_ERR ("Unexpected protocol in IPv6 header '%u', expected '%u' (== "
1210                "IP_PROTOCOL_UDP)", (*ip6)->protocol, IP_PROTOCOL_UDP);
1211       *ip6 = NULL;
1212       *udp = NULL;
1213       return;
1214     }
1215   *udp = (udp_header_t *) ((*ip6) + 1);
1216 }
1217
1218 static bfd_udp_error_t
1219 bfd_udp6_verify_transport (const ip6_header_t * ip6,
1220                            const udp_header_t * udp, const bfd_session_t * bs)
1221 {
1222   const bfd_udp_session_t *bus = &bs->udp;
1223   const bfd_udp_key_t *key = &bus->key;
1224   if (ip6->src_address.as_u64[0] != key->peer_addr.ip6.as_u64[0] &&
1225       ip6->src_address.as_u64[1] != key->peer_addr.ip6.as_u64[1])
1226     {
1227       BFD_ERR ("IP src addr mismatch, got %U, expected %U",
1228                format_ip6_address, ip6, format_ip6_address,
1229                &key->peer_addr.ip6);
1230       return BFD_UDP_ERROR_BAD;
1231     }
1232   if (ip6->dst_address.as_u64[0] != key->local_addr.ip6.as_u64[0] &&
1233       ip6->dst_address.as_u64[1] != key->local_addr.ip6.as_u64[1])
1234     {
1235       BFD_ERR ("IP dst addr mismatch, got %U, expected %U",
1236                format_ip6_address, ip6, format_ip6_address,
1237                &key->local_addr.ip6);
1238       return BFD_UDP_ERROR_BAD;
1239     }
1240   const u8 expected_hop_limit = 255;
1241   if (ip6->hop_limit != expected_hop_limit)
1242     {
1243       BFD_ERR ("IPv6 unexpected hop-limit value %u, expected %u",
1244                ip6->hop_limit, expected_hop_limit);
1245       return BFD_UDP_ERROR_BAD;
1246     }
1247   if (clib_net_to_host_u16 (udp->src_port) < 49152)
1248     {
1249       BFD_ERR ("Invalid UDP src port %u, out of range <49152,65535>",
1250                udp->src_port);
1251     }
1252   return BFD_UDP_ERROR_NONE;
1253 }
1254
1255 static bfd_udp_error_t
1256 bfd_udp6_scan (vlib_main_t *vm, vlib_buffer_t *b, bfd_session_t **bs_out)
1257 {
1258   const bfd_pkt_t *pkt = vlib_buffer_get_current (b);
1259   if (sizeof (*pkt) > b->current_length)
1260     {
1261       BFD_ERR
1262         ("Payload size %d too small to hold bfd packet of minimum size %d",
1263          b->current_length, sizeof (*pkt));
1264       return BFD_UDP_ERROR_BAD;
1265     }
1266   ip6_header_t *ip6;
1267   udp_header_t *udp;
1268   bfd_udp6_find_headers (b, &ip6, &udp);
1269   if (!ip6 || !udp)
1270     {
1271       BFD_ERR ("Couldn't find ip6 or udp header");
1272       return BFD_UDP_ERROR_BAD;
1273     }
1274   const u32 udp_payload_length = udp->length - sizeof (*udp);
1275   if (pkt->head.length > udp_payload_length)
1276     {
1277       BFD_ERR
1278         ("BFD packet length is larger than udp payload length (%u > %u)",
1279          pkt->head.length, udp_payload_length);
1280       return BFD_UDP_ERROR_BAD;
1281     }
1282   if (!bfd_verify_pkt_common (pkt))
1283     {
1284       return BFD_UDP_ERROR_BAD;
1285     }
1286   bfd_session_t *bs = NULL;
1287   if (pkt->your_disc)
1288     {
1289       BFD_DBG ("Looking up BFD session using discriminator %u",
1290                pkt->your_disc);
1291       bs = bfd_find_session_by_disc (bfd_udp_main.bfd_main, pkt->your_disc);
1292     }
1293   else
1294     {
1295       bfd_udp_key_t key;
1296       clib_memset (&key, 0, sizeof (key));
1297       key.sw_if_index = vnet_buffer (b)->sw_if_index[VLIB_RX];
1298       key.local_addr.ip6.as_u64[0] = ip6->dst_address.as_u64[0];
1299       key.local_addr.ip6.as_u64[1] = ip6->dst_address.as_u64[1];
1300       key.peer_addr.ip6.as_u64[0] = ip6->src_address.as_u64[0];
1301       key.peer_addr.ip6.as_u64[1] = ip6->src_address.as_u64[1];
1302       BFD_DBG ("Looking up BFD session using key (sw_if_index=%u, local=%U, "
1303                "peer=%U)",
1304                key.sw_if_index, format_ip6_address, &key.local_addr,
1305                format_ip6_address, &key.peer_addr);
1306       bs = bfd_lookup_session (&bfd_udp_main, &key);
1307     }
1308   if (!bs)
1309     {
1310       BFD_ERR ("BFD session lookup failed - no session matches BFD pkt");
1311       return BFD_UDP_ERROR_BAD;
1312     }
1313   BFD_DBG ("BFD session found, bs_idx=%u", bs->bs_idx);
1314   if (!bfd_verify_pkt_auth (vm, pkt, b->current_length, bs))
1315     {
1316       BFD_ERR ("Packet verification failed, dropping packet");
1317       return BFD_UDP_ERROR_BAD;
1318     }
1319   bfd_udp_error_t err;
1320   if (BFD_UDP_ERROR_NONE != (err = bfd_udp6_verify_transport (ip6, udp, bs)))
1321     {
1322       return err;
1323     }
1324   bfd_rpc_update_session (vm, bs->bs_idx, pkt);
1325   *bs_out = bs;
1326   return BFD_UDP_ERROR_NONE;
1327 }
1328
1329 /*
1330  * Process a frame of bfd packets
1331  * Expect 1 packet / frame
1332  */
1333 static uword
1334 bfd_udp_input (vlib_main_t * vm, vlib_node_runtime_t * rt,
1335                vlib_frame_t * f, int is_ipv6)
1336 {
1337   u32 n_left_from, *from;
1338   bfd_input_trace_t *t0;
1339   bfd_main_t *bm = &bfd_main;
1340
1341   from = vlib_frame_vector_args (f);    /* array of buffer indices */
1342   n_left_from = f->n_vectors;   /* number of buffer indices */
1343
1344   while (n_left_from > 0)
1345     {
1346       u32 bi0;
1347       vlib_buffer_t *b0;
1348       u32 next0, error0;
1349
1350       bi0 = from[0];
1351       b0 = vlib_get_buffer (vm, bi0);
1352
1353       bfd_session_t *bs = NULL;
1354
1355       /* If this pkt is traced, snapshot the data */
1356       if (b0->flags & VLIB_BUFFER_IS_TRACED)
1357         {
1358           u64 len;
1359           t0 = vlib_add_trace (vm, rt, b0, sizeof (*t0));
1360           len = (b0->current_length < sizeof (t0->data)) ? b0->current_length
1361             : sizeof (t0->data);
1362           t0->len = len;
1363           clib_memcpy_fast (t0->data, vlib_buffer_get_current (b0), len);
1364         }
1365
1366       /* scan this bfd pkt. error0 is the counter index to bmp */
1367       bfd_lock (bm);
1368       if (is_ipv6)
1369         {
1370           error0 = bfd_udp6_scan (vm, b0, &bs);
1371         }
1372       else
1373         {
1374           error0 = bfd_udp4_scan (vm, b0, &bs);
1375         }
1376       b0->error = rt->errors[error0];
1377
1378       next0 = BFD_UDP_INPUT_NEXT_NORMAL;
1379       if (BFD_UDP_ERROR_NONE == error0)
1380         {
1381           vlib_increment_combined_counter (
1382             &bm->rx_counter, vm->thread_index, bs->bs_idx, 1,
1383             vlib_buffer_length_in_chain (vm, b0));
1384           /*
1385            *  if everything went fine, check for poll bit, if present, re-use
1386            *  the buffer and based on (now updated) session parameters, send
1387            *  the final packet back
1388            */
1389           const bfd_pkt_t *pkt = vlib_buffer_get_current (b0);
1390           if (bfd_pkt_get_poll (pkt))
1391             {
1392               b0->current_data = 0;
1393               b0->current_length = 0;
1394               bfd_init_final_control_frame (vm, b0, bs);
1395               if (is_ipv6)
1396                 {
1397                   vlib_node_increment_counter (vm, bfd_udp6_input_node.index,
1398                                                b0->error, 1);
1399                 }
1400               else
1401                 {
1402                   vlib_node_increment_counter (vm, bfd_udp4_input_node.index,
1403                                                b0->error, 1);
1404                 }
1405               const bfd_udp_session_t *bus = &bs->udp;
1406               ip_adjacency_t *adj = adj_get (bus->adj_index);
1407               switch (adj->lookup_next_index)
1408                 {
1409                 case IP_LOOKUP_NEXT_ARP:
1410                   next0 = BFD_UDP_INPUT_NEXT_REPLY_ARP;
1411                   break;
1412                 case IP_LOOKUP_NEXT_REWRITE:
1413                   next0 = BFD_UDP_INPUT_NEXT_REPLY_REWRITE;
1414                   break;
1415                 case IP_LOOKUP_NEXT_MIDCHAIN:
1416                   next0 = BFD_UDP_INPUT_NEXT_REPLY_MIDCHAIN;
1417                   break;
1418                 default:
1419                   /* drop */
1420                   break;
1421                 }
1422             }
1423         }
1424       bfd_unlock (bm);
1425       vlib_set_next_frame_buffer (vm, rt, next0, bi0);
1426
1427       from += 1;
1428       n_left_from -= 1;
1429     }
1430
1431   return f->n_vectors;
1432 }
1433
1434 static uword
1435 bfd_udp4_input (vlib_main_t * vm, vlib_node_runtime_t * rt, vlib_frame_t * f)
1436 {
1437   return bfd_udp_input (vm, rt, f, 0);
1438 }
1439
1440 /*
1441  * bfd input graph node declaration
1442  */
1443 /* *INDENT-OFF* */
1444 VLIB_REGISTER_NODE (bfd_udp4_input_node, static) = {
1445   .function = bfd_udp4_input,
1446   .name = "bfd-udp4-input",
1447   .vector_size = sizeof (u32),
1448   .type = VLIB_NODE_TYPE_INTERNAL,
1449
1450   .n_errors = BFD_UDP_N_ERROR,
1451   .error_strings = bfd_udp_error_strings,
1452
1453   .format_trace = bfd_input_format_trace,
1454
1455   .n_next_nodes = BFD_UDP_INPUT_N_NEXT,
1456   .next_nodes =
1457       {
1458               [BFD_UDP_INPUT_NEXT_NORMAL] = "error-drop",
1459               [BFD_UDP_INPUT_NEXT_REPLY_ARP] = "ip4-arp",
1460               [BFD_UDP_INPUT_NEXT_REPLY_REWRITE] = "ip4-lookup",
1461               [BFD_UDP_INPUT_NEXT_REPLY_MIDCHAIN] = "ip4-midchain",
1462       },
1463 };
1464 /* *INDENT-ON* */
1465
1466 static uword
1467 bfd_udp6_input (vlib_main_t * vm, vlib_node_runtime_t * rt, vlib_frame_t * f)
1468 {
1469   return bfd_udp_input (vm, rt, f, 1);
1470 }
1471
1472 /* *INDENT-OFF* */
1473 VLIB_REGISTER_NODE (bfd_udp6_input_node, static) = {
1474   .function = bfd_udp6_input,
1475   .name = "bfd-udp6-input",
1476   .vector_size = sizeof (u32),
1477   .type = VLIB_NODE_TYPE_INTERNAL,
1478
1479   .n_errors = BFD_UDP_N_ERROR,
1480   .error_strings = bfd_udp_error_strings,
1481
1482   .format_trace = bfd_input_format_trace,
1483
1484   .n_next_nodes = BFD_UDP_INPUT_N_NEXT,
1485   .next_nodes =
1486       {
1487               [BFD_UDP_INPUT_NEXT_NORMAL] = "error-drop",
1488               [BFD_UDP_INPUT_NEXT_REPLY_ARP] = "ip6-discover-neighbor",
1489               [BFD_UDP_INPUT_NEXT_REPLY_REWRITE] = "ip6-lookup",
1490               [BFD_UDP_INPUT_NEXT_REPLY_MIDCHAIN] = "ip6-midchain",
1491       },
1492 };
1493 /* *INDENT-ON* */
1494
1495 /*
1496  * Process a frame of bfd echo packets
1497  * Expect 1 packet / frame
1498  */
1499 static uword
1500 bfd_udp_echo_input (vlib_main_t * vm, vlib_node_runtime_t * rt,
1501                     vlib_frame_t * f, int is_ipv6)
1502 {
1503   u32 n_left_from, *from;
1504   bfd_input_trace_t *t0;
1505   bfd_main_t *bm = &bfd_main;
1506
1507   from = vlib_frame_vector_args (f);    /* array of buffer indices */
1508   n_left_from = f->n_vectors;   /* number of buffer indices */
1509
1510   while (n_left_from > 0)
1511     {
1512       u32 bi0;
1513       vlib_buffer_t *b0;
1514       u32 next0;
1515
1516       bi0 = from[0];
1517       b0 = vlib_get_buffer (vm, bi0);
1518
1519       /* If this pkt is traced, snapshot the data */
1520       if (b0->flags & VLIB_BUFFER_IS_TRACED)
1521         {
1522           u64 len;
1523           t0 = vlib_add_trace (vm, rt, b0, sizeof (*t0));
1524           len = (b0->current_length < sizeof (t0->data)) ? b0->current_length
1525             : sizeof (t0->data);
1526           t0->len = len;
1527           clib_memcpy_fast (t0->data, vlib_buffer_get_current (b0), len);
1528         }
1529
1530       bfd_session_t *bs = NULL;
1531       bfd_lock (bm);
1532       if ((bs = bfd_consume_echo_pkt (vm, bfd_udp_main.bfd_main, b0)))
1533         {
1534           b0->error = rt->errors[BFD_UDP_ERROR_NONE];
1535           next0 = BFD_UDP_ECHO_INPUT_NEXT_NORMAL;
1536         }
1537       else
1538         {
1539           /* loop back the packet */
1540           b0->error = rt->errors[BFD_UDP_ERROR_NONE];
1541           if (is_ipv6)
1542             {
1543               vlib_node_increment_counter (vm, bfd_udp_echo6_input_node.index,
1544                                            b0->error, 1);
1545             }
1546           else
1547             {
1548               vlib_node_increment_counter (vm, bfd_udp_echo4_input_node.index,
1549                                            b0->error, 1);
1550             }
1551           next0 = BFD_UDP_ECHO_INPUT_NEXT_REPLY_REWRITE;
1552         }
1553
1554       bfd_unlock (bm);
1555
1556       if (bs)
1557         {
1558           vlib_increment_combined_counter (
1559             &bm->rx_echo_counter, vm->thread_index, bs->bs_idx, 1,
1560             vlib_buffer_length_in_chain (vm, b0));
1561         }
1562
1563       vlib_set_next_frame_buffer (vm, rt, next0, bi0);
1564
1565       from += 1;
1566       n_left_from -= 1;
1567     }
1568
1569   return f->n_vectors;
1570 }
1571
1572 static uword
1573 bfd_udp_echo4_input (vlib_main_t * vm, vlib_node_runtime_t * rt,
1574                      vlib_frame_t * f)
1575 {
1576   return bfd_udp_echo_input (vm, rt, f, 0);
1577 }
1578
1579 u8 *
1580 bfd_echo_input_format_trace (u8 * s, va_list * args)
1581 {
1582   CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
1583   CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
1584   const bfd_udp_echo_input_trace_t *t =
1585     va_arg (*args, bfd_udp_echo_input_trace_t *);
1586   if (t->len > STRUCT_SIZE_OF (bfd_pkt_t, head))
1587     {
1588       s = format (s, "BFD ECHO:\n");
1589       s = format (s, "    data: %U", format_hexdump, t->data, t->len);
1590     }
1591
1592   return s;
1593 }
1594
1595 /*
1596  * bfd input graph node declaration
1597  */
1598 /* *INDENT-OFF* */
1599 VLIB_REGISTER_NODE (bfd_udp_echo4_input_node, static) = {
1600   .function = bfd_udp_echo4_input,
1601   .name = "bfd-udp-echo4-input",
1602   .vector_size = sizeof (u32),
1603   .type = VLIB_NODE_TYPE_INTERNAL,
1604
1605   .n_errors = BFD_UDP_ECHO_N_ERROR,
1606   .error_strings = bfd_udp_error_strings,
1607
1608   .format_trace = bfd_echo_input_format_trace,
1609
1610   .n_next_nodes = BFD_UDP_ECHO_INPUT_N_NEXT,
1611   .next_nodes =
1612       {
1613               [BFD_UDP_ECHO_INPUT_NEXT_NORMAL] = "error-drop",
1614               [BFD_UDP_ECHO_INPUT_NEXT_REPLY_ARP] = "ip4-arp",
1615               [BFD_UDP_ECHO_INPUT_NEXT_REPLY_REWRITE] = "ip4-lookup",
1616       },
1617 };
1618 /* *INDENT-ON* */
1619
1620 static uword
1621 bfd_udp_echo6_input (vlib_main_t * vm, vlib_node_runtime_t * rt,
1622                      vlib_frame_t * f)
1623 {
1624   return bfd_udp_echo_input (vm, rt, f, 1);
1625 }
1626
1627 /* *INDENT-OFF* */
1628 VLIB_REGISTER_NODE (bfd_udp_echo6_input_node, static) = {
1629   .function = bfd_udp_echo6_input,
1630   .name = "bfd-udp-echo6-input",
1631   .vector_size = sizeof (u32),
1632   .type = VLIB_NODE_TYPE_INTERNAL,
1633
1634   .n_errors = BFD_UDP_ECHO_N_ERROR,
1635   .error_strings = bfd_udp_echo_error_strings,
1636
1637   .format_trace = bfd_echo_input_format_trace,
1638
1639   .n_next_nodes = BFD_UDP_ECHO_INPUT_N_NEXT,
1640   .next_nodes =
1641       {
1642               [BFD_UDP_ECHO_INPUT_NEXT_NORMAL] = "error-drop",
1643               [BFD_UDP_ECHO_INPUT_NEXT_REPLY_ARP] = "ip6-discover-neighbor",
1644               [BFD_UDP_ECHO_INPUT_NEXT_REPLY_REWRITE] = "ip6-lookup",
1645       },
1646 };
1647
1648 /* *INDENT-ON* */
1649
1650 static clib_error_t *
1651 bfd_udp_sw_if_add_del (CLIB_UNUSED (vnet_main_t *vnm), u32 sw_if_index,
1652                        u32 is_create)
1653 {
1654   u32 *to_be_freed = NULL;
1655   bfd_udp_main_t *bum = &bfd_udp_main;
1656   BFD_DBG ("sw_if_add_del called, sw_if_index=%u, is_create=%u", sw_if_index,
1657            is_create);
1658   if (!is_create)
1659     {
1660       bfd_session_t *bs;
1661       pool_foreach (bs, bum->bfd_main->sessions)
1662         {
1663           if (bs->transport != BFD_TRANSPORT_UDP4 &&
1664               bs->transport != BFD_TRANSPORT_UDP6)
1665             {
1666               continue;
1667             }
1668           if (bs->udp.key.sw_if_index != sw_if_index)
1669             {
1670               continue;
1671             }
1672           vec_add1 (to_be_freed, bs->bs_idx);
1673         }
1674     }
1675   u32 *bs_idx;
1676   vec_foreach (bs_idx, to_be_freed)
1677     {
1678       bfd_session_t *bs = pool_elt_at_index (bum->bfd_main->sessions, *bs_idx);
1679       vlib_log_notice (bum->log_class,
1680                        "removal of sw_if_index=%u forces removal of bfd "
1681                        "session with bs_idx=%u",
1682                        sw_if_index, bs->bs_idx);
1683       bfd_session_set_flags (vlib_get_main (), bs, 0);
1684       bfd_udp_del_session_internal (vlib_get_main (), bs);
1685     }
1686   return 0;
1687 }
1688
1689 VNET_SW_INTERFACE_ADD_DEL_FUNCTION (bfd_udp_sw_if_add_del);
1690
1691 clib_error_t *
1692 bfd_udp_stats_init (bfd_udp_main_t *bum)
1693 {
1694   const char *name4 = "/bfd/udp4/sessions";
1695   bum->udp4_sessions_count_stat_seg_entry =
1696     stat_segment_new_entry ((u8 *) name4, STAT_DIR_TYPE_SCALAR_INDEX);
1697
1698   stat_segment_set_state_counter (bum->udp4_sessions_count_stat_seg_entry, 0);
1699   if (~0 == bum->udp4_sessions_count_stat_seg_entry)
1700     {
1701       return clib_error_return (
1702         0, "Could not create stat segment entry for %s", name4);
1703     }
1704   const char *name6 = "/bfd/udp6/sessions";
1705   bum->udp6_sessions_count_stat_seg_entry =
1706     stat_segment_new_entry ((u8 *) name6, STAT_DIR_TYPE_SCALAR_INDEX);
1707
1708   if (~0 == bum->udp6_sessions_count_stat_seg_entry)
1709     {
1710       return clib_error_return (
1711         0, "Could not create stat segment entry for %s", name6);
1712     }
1713
1714   return 0;
1715 }
1716
1717 /*
1718  * setup function
1719  */
1720 static clib_error_t *
1721 bfd_udp_init (vlib_main_t * vm)
1722 {
1723   bfd_udp_main.udp4_sessions_count = 0;
1724   bfd_udp_main.udp6_sessions_count = 0;
1725   mhash_init (&bfd_udp_main.bfd_session_idx_by_bfd_key, sizeof (uword),
1726               sizeof (bfd_udp_key_t));
1727   bfd_udp_main.bfd_main = &bfd_main;
1728   bfd_udp_main.vnet_main = vnet_get_main ();
1729   vlib_node_t *node = vlib_get_node_by_name (vm, (u8 *) "ip4-arp");
1730   ASSERT (node);
1731   bfd_udp_main.ip4_arp_idx = node->index;
1732   node = vlib_get_node_by_name (vm, (u8 *) "ip6-discover-neighbor");
1733   ASSERT (node);
1734   bfd_udp_main.ip6_ndp_idx = node->index;
1735   node = vlib_get_node_by_name (vm, (u8 *) "ip4-rewrite");
1736   ASSERT (node);
1737   bfd_udp_main.ip4_rewrite_idx = node->index;
1738   node = vlib_get_node_by_name (vm, (u8 *) "ip6-rewrite");
1739   ASSERT (node);
1740   bfd_udp_main.ip6_rewrite_idx = node->index;
1741   node = vlib_get_node_by_name (vm, (u8 *) "ip4-midchain");
1742   ASSERT (node);
1743   bfd_udp_main.ip4_midchain_idx = node->index;
1744   node = vlib_get_node_by_name (vm, (u8 *) "ip6-midchain");
1745   ASSERT (node);
1746   bfd_udp_main.ip6_midchain_idx = node->index;
1747
1748   bfd_udp_stats_init (&bfd_udp_main);
1749
1750   bfd_udp_main.log_class = vlib_log_register_class ("bfd", "udp");
1751   vlib_log_debug (bfd_udp_main.log_class, "initialized");
1752   return 0;
1753 }
1754
1755 VLIB_INIT_FUNCTION (bfd_udp_init);
1756
1757 /*
1758  * fd.io coding-style-patch-verification: ON
1759  *
1760  * Local Variables:
1761  * eval: (c-set-style "gnu")
1762  * End:
1763  */