8519009d13949b8cea3a3423e7758074dd536a9e
[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 #include <vppinfra/types.h>
16 #include <vlibmemory/api.h>
17 #include <vlib/vlib.h>
18 #include <vlib/buffer.h>
19 #include <vnet/ip/format.h>
20 #include <vnet/ethernet/packet.h>
21 #include <vnet/ip/udp_packet.h>
22 #include <vnet/ip/lookup.h>
23 #include <vnet/ip/icmp46_packet.h>
24 #include <vnet/ip/ip4.h>
25 #include <vnet/ip/ip6.h>
26 #include <vnet/ip/udp.h>
27 #include <vnet/ip/ip6_packet.h>
28 #include <vnet/adj/adj.h>
29 #include <vnet/adj/adj_nbr.h>
30 #include <vnet/bfd/bfd_debug.h>
31 #include <vnet/bfd/bfd_udp.h>
32 #include <vnet/bfd/bfd_main.h>
33 #include <vnet/bfd/bfd_api.h>
34
35 typedef struct
36 {
37   bfd_main_t *bfd_main;
38   /* hashmap - bfd session index by bfd key - used for CLI/API lookup, where
39    * discriminator is unknown */
40   mhash_t bfd_session_idx_by_bfd_key;
41 } bfd_udp_main_t;
42
43 static vlib_node_registration_t bfd_udp4_input_node;
44 static vlib_node_registration_t bfd_udp6_input_node;
45 static vlib_node_registration_t bfd_udp_echo4_input_node;
46 static vlib_node_registration_t bfd_udp_echo6_input_node;
47
48 bfd_udp_main_t bfd_udp_main;
49
50 static u16
51 bfd_udp_bs_idx_to_sport (u32 bs_idx)
52 {
53   /* The source port MUST be in the range 49152 through 65535. The same UDP
54    * source port number MUST be used for all BFD Control packets associated
55    * with a particular session.  The source port number SHOULD be unique among
56    * all BFD sessions on the system. If more than 16384 BFD sessions are
57    * simultaneously active, UDP source port numbers MAY be reused on
58    * multiple sessions, but the number of distinct uses of the same UDP
59    * source port number SHOULD be minimized.
60    */
61   return 49152 + bs_idx % (65535 - 49152 + 1);
62 }
63
64 void
65 bfd_add_udp4_transport (vlib_main_t * vm, vlib_buffer_t * b,
66                         const bfd_session_t * bs)
67 {
68   const bfd_udp_session_t *bus = &bs->udp;
69   const bfd_udp_key_t *key = &bus->key;
70
71   b->flags |= VNET_BUFFER_LOCALLY_ORIGINATED;
72   vnet_buffer (b)->ip.adj_index[VLIB_RX] = bus->adj_index;
73   vnet_buffer (b)->ip.adj_index[VLIB_TX] = bus->adj_index;
74   typedef struct
75   {
76     ip4_header_t ip4;
77     udp_header_t udp;
78   } ip4_udp_headers;
79   ip4_udp_headers *headers = NULL;
80   vlib_buffer_advance (b, -sizeof (*headers));
81   headers = vlib_buffer_get_current (b);
82   memset (headers, 0, sizeof (*headers));
83   headers->ip4.ip_version_and_header_length = 0x45;
84   headers->ip4.ttl = 255;
85   headers->ip4.protocol = IP_PROTOCOL_UDP;
86   headers->ip4.src_address.as_u32 = key->local_addr.ip4.as_u32;
87   headers->ip4.dst_address.as_u32 = key->peer_addr.ip4.as_u32;
88
89   headers->udp.src_port =
90     clib_host_to_net_u16 (bfd_udp_bs_idx_to_sport (bs->bs_idx));
91   headers->udp.dst_port = clib_host_to_net_u16 (UDP_DST_PORT_bfd4);
92
93   /* fix ip length, checksum and udp length */
94   const u16 ip_length = vlib_buffer_length_in_chain (vm, b);
95
96   headers->ip4.length = clib_host_to_net_u16 (ip_length);
97   headers->ip4.checksum = ip4_header_checksum (&headers->ip4);
98
99   const u16 udp_length = ip_length - (sizeof (headers->ip4));
100   headers->udp.length = clib_host_to_net_u16 (udp_length);
101 }
102
103 void
104 bfd_add_udp6_transport (vlib_main_t * vm, vlib_buffer_t * b,
105                         const bfd_session_t * bs)
106 {
107   const bfd_udp_session_t *bus = &bs->udp;
108   const bfd_udp_key_t *key = &bus->key;
109
110   b->flags |= VNET_BUFFER_LOCALLY_ORIGINATED;
111   vnet_buffer (b)->ip.adj_index[VLIB_RX] = bus->adj_index;
112   vnet_buffer (b)->ip.adj_index[VLIB_TX] = bus->adj_index;
113   typedef struct
114   {
115     ip6_header_t ip6;
116     udp_header_t udp;
117   } ip6_udp_headers;
118   ip6_udp_headers *headers = NULL;
119   vlib_buffer_advance (b, -sizeof (*headers));
120   headers = vlib_buffer_get_current (b);
121   memset (headers, 0, sizeof (*headers));
122   headers->ip6.ip_version_traffic_class_and_flow_label =
123     clib_host_to_net_u32 (0x6 << 28);
124   headers->ip6.hop_limit = 255;
125   headers->ip6.protocol = IP_PROTOCOL_UDP;
126   clib_memcpy (&headers->ip6.src_address, &key->local_addr.ip6,
127                sizeof (headers->ip6.src_address));
128   clib_memcpy (&headers->ip6.dst_address, &key->peer_addr.ip6,
129                sizeof (headers->ip6.dst_address));
130
131   headers->udp.src_port =
132     clib_host_to_net_u16 (bfd_udp_bs_idx_to_sport (bs->bs_idx));
133   headers->udp.dst_port = clib_host_to_net_u16 (UDP_DST_PORT_bfd6);
134
135   /* fix ip payload length and udp length */
136   const u16 udp_length =
137     vlib_buffer_length_in_chain (vm, b) - (sizeof (headers->ip6));
138   headers->udp.length = clib_host_to_net_u16 (udp_length);
139   headers->ip6.payload_length = headers->udp.length;
140
141   /* IPv6 UDP checksum is mandatory */
142   int bogus = 0;
143   headers->udp.checksum =
144     ip6_tcp_udp_icmp_compute_checksum (vm, b, &headers->ip6, &bogus);
145   ASSERT (bogus == 0);
146   if (headers->udp.checksum == 0)
147     {
148       headers->udp.checksum = 0xffff;
149     }
150 }
151
152 static bfd_session_t *
153 bfd_lookup_session (bfd_udp_main_t * bum, const bfd_udp_key_t * key)
154 {
155   uword *p = mhash_get (&bum->bfd_session_idx_by_bfd_key, key);
156   if (p)
157     {
158       return bfd_find_session_by_idx (bum->bfd_main, *p);
159     }
160   return 0;
161 }
162
163 static void
164 bfd_udp_key_init (bfd_udp_key_t * key, u32 sw_if_index,
165                   const ip46_address_t * local_addr,
166                   const ip46_address_t * peer_addr)
167 {
168   memset (key, 0, sizeof (*key));
169   key->sw_if_index = sw_if_index;
170   key->local_addr.as_u64[0] = local_addr->as_u64[0];
171   key->local_addr.as_u64[1] = local_addr->as_u64[1];
172   key->peer_addr.as_u64[0] = peer_addr->as_u64[0];
173   key->peer_addr.as_u64[1] = peer_addr->as_u64[1];
174 }
175
176 static vnet_api_error_t
177 bfd_udp_add_session_internal (bfd_udp_main_t * bum, u32 sw_if_index,
178                               u32 desired_min_tx_usec,
179                               u32 required_min_rx_usec, u8 detect_mult,
180                               const ip46_address_t * local_addr,
181                               const ip46_address_t * peer_addr,
182                               bfd_session_t ** bs_out)
183 {
184   /* get a pool entry and if we end up not needing it, give it back */
185   bfd_transport_t t = BFD_TRANSPORT_UDP4;
186   if (!ip46_address_is_ip4 (local_addr))
187     {
188       t = BFD_TRANSPORT_UDP6;
189     }
190   bfd_session_t *bs = bfd_get_session (bum->bfd_main, t);
191   bfd_udp_session_t *bus = &bs->udp;
192   memset (bus, 0, sizeof (*bus));
193   bfd_udp_key_t *key = &bus->key;
194   bfd_udp_key_init (key, sw_if_index, local_addr, peer_addr);
195   const bfd_session_t *tmp = bfd_lookup_session (bum, key);
196   if (tmp)
197     {
198       clib_warning ("duplicate bfd-udp session, existing bs_idx=%d",
199                     tmp->bs_idx);
200       bfd_put_session (bum->bfd_main, bs);
201       return VNET_API_ERROR_BFD_EEXIST;
202     }
203   mhash_set (&bum->bfd_session_idx_by_bfd_key, key, bs->bs_idx, NULL);
204   BFD_DBG ("session created, bs_idx=%u, sw_if_index=%d, local=%U, peer=%U",
205            bs->bs_idx, key->sw_if_index, format_ip46_address,
206            &key->local_addr, IP46_TYPE_ANY, format_ip46_address,
207            &key->peer_addr, IP46_TYPE_ANY);
208   if (BFD_TRANSPORT_UDP4 == t)
209     {
210       bus->adj_index = adj_nbr_add_or_lock (FIB_PROTOCOL_IP4, VNET_LINK_IP4,
211                                             &key->peer_addr,
212                                             key->sw_if_index);
213       BFD_DBG ("adj_nbr_add_or_lock(FIB_PROTOCOL_IP4, VNET_LINK_IP4, %U, %d) "
214                "returns %d", format_ip46_address, &key->peer_addr,
215                IP46_TYPE_ANY, key->sw_if_index, bus->adj_index);
216     }
217   else
218     {
219       bus->adj_index = adj_nbr_add_or_lock (FIB_PROTOCOL_IP6, VNET_LINK_IP6,
220                                             &key->peer_addr,
221                                             key->sw_if_index);
222       BFD_DBG ("adj_nbr_add_or_lock(FIB_PROTOCOL_IP6, VNET_LINK_IP6, %U, %d) "
223                "returns %d", format_ip46_address, &key->peer_addr,
224                IP46_TYPE_ANY, key->sw_if_index, bus->adj_index);
225     }
226   *bs_out = bs;
227   return bfd_session_set_params (bum->bfd_main, bs, desired_min_tx_usec,
228                                  required_min_rx_usec, detect_mult);
229 }
230
231 static vnet_api_error_t
232 bfd_udp_validate_api_input (u32 sw_if_index,
233                             const ip46_address_t * local_addr,
234                             const ip46_address_t * peer_addr)
235 {
236   vnet_sw_interface_t *sw_if =
237     vnet_get_sw_interface (vnet_get_main (), sw_if_index);
238   u8 local_ip_valid = 0;
239   ip_interface_address_t *ia = NULL;
240   if (!sw_if)
241     {
242       clib_warning ("got NULL sw_if");
243       return VNET_API_ERROR_INVALID_SW_IF_INDEX;
244     }
245   if (ip46_address_is_ip4 (local_addr))
246     {
247       if (!ip46_address_is_ip4 (peer_addr))
248         {
249           clib_warning ("IP family mismatch");
250           return VNET_API_ERROR_INVALID_ARGUMENT;
251         }
252       ip4_main_t *im = &ip4_main;
253
254       /* *INDENT-OFF* */
255       foreach_ip_interface_address (
256           &im->lookup_main, ia, sw_if_index, 0 /* honor unnumbered */, ({
257             ip4_address_t *x =
258                 ip_interface_address_get_address (&im->lookup_main, ia);
259             if (x->as_u32 == local_addr->ip4.as_u32)
260               {
261                 /* valid address for this interface */
262                 local_ip_valid = 1;
263                 break;
264               }
265           }));
266       /* *INDENT-ON* */
267     }
268   else
269     {
270       if (ip46_address_is_ip4 (peer_addr))
271         {
272           clib_warning ("IP family mismatch");
273           return VNET_API_ERROR_INVALID_ARGUMENT;
274         }
275       ip6_main_t *im = &ip6_main;
276       /* *INDENT-OFF* */
277       foreach_ip_interface_address (
278           &im->lookup_main, ia, sw_if_index, 0 /* honor unnumbered */, ({
279             ip6_address_t *x =
280                 ip_interface_address_get_address (&im->lookup_main, ia);
281             if (local_addr->ip6.as_u64[0] == x->as_u64[0] &&
282                 local_addr->ip6.as_u64[1] == x->as_u64[1])
283               {
284                 /* valid address for this interface */
285                 local_ip_valid = 1;
286                 break;
287               }
288           }));
289       /* *INDENT-ON* */
290     }
291
292   if (!local_ip_valid)
293     {
294       clib_warning ("address not found on interface");
295       return VNET_API_ERROR_ADDRESS_NOT_FOUND_FOR_INTERFACE;
296     }
297
298   return 0;
299 }
300
301 static vnet_api_error_t
302 bfd_udp_find_session_by_api_input (u32 sw_if_index,
303                                    const ip46_address_t * local_addr,
304                                    const ip46_address_t * peer_addr,
305                                    bfd_session_t ** bs_out)
306 {
307   vnet_api_error_t rv =
308     bfd_udp_validate_api_input (sw_if_index, local_addr, peer_addr);
309   if (!rv)
310     {
311       bfd_udp_main_t *bum = &bfd_udp_main;
312       bfd_udp_key_t key;
313       bfd_udp_key_init (&key, sw_if_index, local_addr, peer_addr);
314       bfd_session_t *bs = bfd_lookup_session (bum, &key);
315       if (bs)
316         {
317           *bs_out = bs;
318         }
319       else
320         {
321           clib_warning
322             ("BFD session not found (sw_if_index=%u, local=%U, peer=%U",
323              sw_if_index, format_ip46_address, local_addr, IP46_TYPE_ANY,
324              format_ip46_address, peer_addr, IP46_TYPE_ANY);
325           return VNET_API_ERROR_BFD_ENOENT;
326         }
327     }
328   return rv;
329 }
330
331 static vnet_api_error_t
332 bfd_api_verify_common (u32 sw_if_index, u32 desired_min_tx_usec,
333                        u32 required_min_rx_usec, u8 detect_mult,
334                        const ip46_address_t * local_addr,
335                        const ip46_address_t * peer_addr)
336 {
337   vnet_api_error_t rv =
338     bfd_udp_validate_api_input (sw_if_index, local_addr, peer_addr);
339   if (rv)
340     {
341       return rv;
342     }
343   if (detect_mult < 1)
344     {
345       clib_warning ("detect_mult < 1");
346       return VNET_API_ERROR_INVALID_ARGUMENT;
347     }
348   if (desired_min_tx_usec < 1)
349     {
350       clib_warning ("desired_min_tx_usec < 1");
351       return VNET_API_ERROR_INVALID_ARGUMENT;
352     }
353   return 0;
354 }
355
356 static void
357 bfd_udp_del_session_internal (bfd_session_t * bs)
358 {
359   bfd_udp_main_t *bum = &bfd_udp_main;
360   BFD_DBG ("free bfd-udp session, bs_idx=%d", bs->bs_idx);
361   mhash_unset (&bum->bfd_session_idx_by_bfd_key, &bs->udp.key, NULL);
362   adj_unlock (bs->udp.adj_index);
363   bfd_put_session (bum->bfd_main, bs);
364 }
365
366 vnet_api_error_t
367 bfd_udp_add_session (u32 sw_if_index, const ip46_address_t * local_addr,
368                      const ip46_address_t * peer_addr,
369                      u32 desired_min_tx_usec, u32 required_min_rx_usec,
370                      u8 detect_mult, u8 is_authenticated, u32 conf_key_id,
371                      u8 bfd_key_id)
372 {
373   vnet_api_error_t rv =
374     bfd_api_verify_common (sw_if_index, desired_min_tx_usec,
375                            required_min_rx_usec, detect_mult,
376                            local_addr, peer_addr);
377   bfd_session_t *bs = NULL;
378   if (!rv)
379     {
380       rv =
381         bfd_udp_add_session_internal (&bfd_udp_main, sw_if_index,
382                                       desired_min_tx_usec,
383                                       required_min_rx_usec, detect_mult,
384                                       local_addr, peer_addr, &bs);
385     }
386   if (!rv && is_authenticated)
387     {
388 #if WITH_LIBSSL > 0
389       rv = bfd_auth_activate (bs, conf_key_id, bfd_key_id,
390                               0 /* is not delayed */ );
391 #else
392       clib_warning ("SSL missing, cannot add authenticated BFD session");
393       rv = VNET_API_ERROR_BFD_NOTSUPP;
394 #endif
395       if (rv)
396         {
397           bfd_udp_del_session_internal (bs);
398         }
399     }
400   if (!rv)
401     {
402       bfd_session_start (bfd_udp_main.bfd_main, bs);
403     }
404
405   return rv;
406 }
407
408 vnet_api_error_t
409 bfd_udp_mod_session (u32 sw_if_index,
410                      const ip46_address_t * local_addr,
411                      const ip46_address_t * peer_addr,
412                      u32 desired_min_tx_usec,
413                      u32 required_min_rx_usec, u8 detect_mult)
414 {
415   bfd_session_t *bs = NULL;
416   vnet_api_error_t rv =
417     bfd_udp_find_session_by_api_input (sw_if_index, local_addr, peer_addr,
418                                        &bs);
419   if (rv)
420     {
421       return rv;
422     }
423
424   return bfd_session_set_params (bfd_udp_main.bfd_main, bs,
425                                  desired_min_tx_usec, required_min_rx_usec,
426                                  detect_mult);
427 }
428
429 vnet_api_error_t
430 bfd_udp_del_session (u32 sw_if_index,
431                      const ip46_address_t * local_addr,
432                      const ip46_address_t * peer_addr)
433 {
434   bfd_session_t *bs = NULL;
435   vnet_api_error_t rv =
436     bfd_udp_find_session_by_api_input (sw_if_index, local_addr, peer_addr,
437                                        &bs);
438   if (rv)
439     {
440       return rv;
441     }
442   bfd_udp_del_session_internal (bs);
443   return 0;
444 }
445
446 vnet_api_error_t
447 bfd_udp_session_set_flags (u32 sw_if_index,
448                            const ip46_address_t * local_addr,
449                            const ip46_address_t * peer_addr, u8 admin_up_down)
450 {
451   bfd_session_t *bs = NULL;
452   vnet_api_error_t rv =
453     bfd_udp_find_session_by_api_input (sw_if_index, local_addr, peer_addr,
454                                        &bs);
455   if (rv)
456     {
457       return rv;
458     }
459   bfd_session_set_flags (bs, admin_up_down);
460   return 0;
461 }
462
463 vnet_api_error_t
464 bfd_auth_set_key (u32 conf_key_id, u8 auth_type, u8 key_len,
465                   const u8 * key_data)
466 {
467 #if WITH_LIBSSL > 0
468   bfd_auth_key_t *auth_key = NULL;
469   if (!key_len || key_len > bfd_max_len_for_auth_type (auth_type))
470     {
471       clib_warning ("Invalid authentication key length for auth_type=%d:%s "
472                     "(key_len=%u, must be "
473                     "non-zero, expected max=%u)",
474                     auth_type, bfd_auth_type_str (auth_type), key_len,
475                     (u32) bfd_max_len_for_auth_type (auth_type));
476       return VNET_API_ERROR_INVALID_VALUE;
477     }
478   if (!bfd_auth_type_supported (auth_type))
479     {
480       clib_warning ("Unsupported auth type=%d:%s", auth_type,
481                     bfd_auth_type_str (auth_type));
482       return VNET_API_ERROR_BFD_NOTSUPP;
483     }
484   bfd_main_t *bm = bfd_udp_main.bfd_main;
485   uword *key_idx_p = hash_get (bm->auth_key_by_conf_key_id, conf_key_id);
486   if (key_idx_p)
487     {
488       /* modifying existing key - must not be used */
489       const uword key_idx = *key_idx_p;
490       auth_key = pool_elt_at_index (bm->auth_keys, key_idx);
491       if (auth_key->use_count > 0)
492         {
493           clib_warning ("Authentication key with conf ID %u in use by %u BFD "
494                         "sessions - cannot modify",
495                         conf_key_id, auth_key->use_count);
496           return VNET_API_ERROR_BFD_EINUSE;
497         }
498     }
499   else
500     {
501       /* adding new key */
502       pool_get (bm->auth_keys, auth_key);
503       auth_key->conf_key_id = conf_key_id;
504       hash_set (bm->auth_key_by_conf_key_id, conf_key_id,
505                 auth_key - bm->auth_keys);
506     }
507   auth_key->auth_type = auth_type;
508   memset (auth_key->key, 0, sizeof (auth_key->key));
509   clib_memcpy (auth_key->key, key_data, key_len);
510   return 0;
511 #else
512   clib_warning ("SSL missing, cannot manipulate authentication keys");
513   return VNET_API_ERROR_BFD_NOTSUPP;
514 #endif
515 }
516
517 vnet_api_error_t
518 bfd_auth_del_key (u32 conf_key_id)
519 {
520 #if WITH_LIBSSL > 0
521   bfd_auth_key_t *auth_key = NULL;
522   bfd_main_t *bm = bfd_udp_main.bfd_main;
523   uword *key_idx_p = hash_get (bm->auth_key_by_conf_key_id, conf_key_id);
524   if (key_idx_p)
525     {
526       /* deleting existing key - must not be used */
527       const uword key_idx = *key_idx_p;
528       auth_key = pool_elt_at_index (bm->auth_keys, key_idx);
529       if (auth_key->use_count > 0)
530         {
531           clib_warning ("Authentication key with conf ID %u in use by %u BFD "
532                         "sessions - cannot delete",
533                         conf_key_id, auth_key->use_count);
534           return VNET_API_ERROR_BFD_EINUSE;
535         }
536       hash_unset (bm->auth_key_by_conf_key_id, conf_key_id);
537       memset (auth_key, 0, sizeof (*auth_key));
538       pool_put (bm->auth_keys, auth_key);
539     }
540   else
541     {
542       /* no such key */
543       clib_warning ("Authentication key with conf ID %u does not exist",
544                     conf_key_id);
545       return VNET_API_ERROR_BFD_ENOENT;
546     }
547   return 0;
548 #else
549   clib_warning ("SSL missing, cannot manipulate authentication keys");
550   return VNET_API_ERROR_BFD_NOTSUPP;
551 #endif
552 }
553
554 vnet_api_error_t
555 bfd_udp_auth_activate (u32 sw_if_index,
556                        const ip46_address_t * local_addr,
557                        const ip46_address_t * peer_addr,
558                        u32 conf_key_id, u8 key_id, u8 is_delayed)
559 {
560 #if WITH_LIBSSL > 0
561   bfd_session_t *bs = NULL;
562   vnet_api_error_t rv =
563     bfd_udp_find_session_by_api_input (sw_if_index, local_addr, peer_addr,
564                                        &bs);
565   if (rv)
566     {
567       return rv;
568     }
569   return bfd_auth_activate (bs, conf_key_id, key_id, is_delayed);
570 #else
571   clib_warning ("SSL missing, cannot activate BFD authentication");
572   return VNET_API_ERROR_BFD_NOTSUPP;
573 #endif
574 }
575
576 vnet_api_error_t
577 bfd_udp_auth_deactivate (u32 sw_if_index,
578                          const ip46_address_t * local_addr,
579                          const ip46_address_t * peer_addr, u8 is_delayed)
580 {
581   bfd_session_t *bs = NULL;
582   vnet_api_error_t rv =
583     bfd_udp_find_session_by_api_input (sw_if_index, local_addr, peer_addr,
584                                        &bs);
585   if (rv)
586     {
587       return rv;
588     }
589   return bfd_auth_deactivate (bs, is_delayed);
590 }
591
592 typedef enum
593 {
594   BFD_UDP_INPUT_NEXT_NORMAL,
595   BFD_UDP_INPUT_NEXT_REPLY,
596   BFD_UDP_INPUT_N_NEXT,
597 } bfd_udp_input_next_t;
598
599 /* Packet counters - BFD control frames */
600 #define foreach_bfd_udp_error(F)           \
601   F (NONE, "good bfd packets (processed)") \
602   F (BAD, "invalid bfd packets")
603
604 #define F(sym, string) static char BFD_UDP_ERR_##sym##_STR[] = string;
605 foreach_bfd_udp_error (F);
606 #undef F
607
608 static char *bfd_udp_error_strings[] = {
609 #define F(sym, string) BFD_UDP_ERR_##sym##_STR,
610   foreach_bfd_udp_error (F)
611 #undef F
612 };
613
614 typedef enum
615 {
616 #define F(sym, str) BFD_UDP_ERROR_##sym,
617   foreach_bfd_udp_error (F)
618 #undef F
619     BFD_UDP_N_ERROR,
620 } bfd_udp_error_t;
621
622 /* Packet counters - BFD ECHO packets */
623 #define foreach_bfd_udp_echo_error(F)           \
624   F (NONE, "good bfd echo packets (processed)") \
625   F (BAD, "invalid bfd echo packets")
626
627 #define F(sym, string) static char BFD_UDP_ECHO_ERR_##sym##_STR[] = string;
628 foreach_bfd_udp_echo_error (F);
629 #undef F
630
631 static char *bfd_udp_echo_error_strings[] = {
632 #define F(sym, string) BFD_UDP_ECHO_ERR_##sym##_STR,
633   foreach_bfd_udp_echo_error (F)
634 #undef F
635 };
636
637 typedef enum
638 {
639 #define F(sym, str) BFD_UDP_ECHO_ERROR_##sym,
640   foreach_bfd_udp_echo_error (F)
641 #undef F
642     BFD_UDP_ECHO_N_ERROR,
643 } bfd_udp_echo_error_t;
644
645 static void
646 bfd_udp4_find_headers (vlib_buffer_t * b, ip4_header_t ** ip4,
647                        udp_header_t ** udp)
648 {
649   /* sanity check first */
650   const i32 start = vnet_buffer (b)->ip.start_of_ip_header;
651   if (start < 0 && start < sizeof (b->pre_data))
652     {
653       BFD_ERR ("Start of ip header is before pre_data, ignoring");
654       *ip4 = NULL;
655       *udp = NULL;
656       return;
657     }
658   *ip4 = (ip4_header_t *) (b->data + start);
659   if ((u8 *) * ip4 > (u8 *) vlib_buffer_get_current (b))
660     {
661       BFD_ERR ("Start of ip header is beyond current data, ignoring");
662       *ip4 = NULL;
663       *udp = NULL;
664       return;
665     }
666   *udp = (udp_header_t *) ((*ip4) + 1);
667 }
668
669 static bfd_udp_error_t
670 bfd_udp4_verify_transport (const ip4_header_t * ip4,
671                            const udp_header_t * udp, const bfd_session_t * bs)
672 {
673   const bfd_udp_session_t *bus = &bs->udp;
674   const bfd_udp_key_t *key = &bus->key;
675   if (ip4->src_address.as_u32 != key->peer_addr.ip4.as_u32)
676     {
677       BFD_ERR ("IPv4 src addr mismatch, got %U, expected %U",
678                format_ip4_address, ip4->src_address.as_u8, format_ip4_address,
679                key->peer_addr.ip4.as_u8);
680       return BFD_UDP_ERROR_BAD;
681     }
682   if (ip4->dst_address.as_u32 != key->local_addr.ip4.as_u32)
683     {
684       BFD_ERR ("IPv4 dst addr mismatch, got %U, expected %U",
685                format_ip4_address, ip4->dst_address.as_u8, format_ip4_address,
686                key->local_addr.ip4.as_u8);
687       return BFD_UDP_ERROR_BAD;
688     }
689   const u8 expected_ttl = 255;
690   if (ip4->ttl != expected_ttl)
691     {
692       BFD_ERR ("IPv4 unexpected TTL value %u, expected %u", ip4->ttl,
693                expected_ttl);
694       return BFD_UDP_ERROR_BAD;
695     }
696   if (clib_net_to_host_u16 (udp->src_port) < 49152)
697     {
698       BFD_ERR ("Invalid UDP src port %u, out of range <49152,65535>",
699                udp->src_port);
700     }
701   return BFD_UDP_ERROR_NONE;
702 }
703
704 typedef struct
705 {
706   u32 bs_idx;
707   bfd_pkt_t pkt;
708 } bfd_rpc_update_t;
709
710 static void
711 bfd_rpc_update_session_cb (const bfd_rpc_update_t * a)
712 {
713   bfd_consume_pkt (bfd_udp_main.bfd_main, &a->pkt, a->bs_idx);
714 }
715
716 static void
717 bfd_rpc_update_session (u32 bs_idx, const bfd_pkt_t * pkt)
718 {
719   /* packet length was already verified to be correct by the caller */
720   const u32 data_size = sizeof (bfd_rpc_update_t) -
721     STRUCT_SIZE_OF (bfd_rpc_update_t, pkt) + pkt->head.length;
722   u8 data[data_size];
723   bfd_rpc_update_t *update = (bfd_rpc_update_t *) data;
724   update->bs_idx = bs_idx;
725   clib_memcpy (&update->pkt, pkt, pkt->head.length);
726   vl_api_rpc_call_main_thread (bfd_rpc_update_session_cb, data, data_size);
727 }
728
729 static bfd_udp_error_t
730 bfd_udp4_scan (vlib_main_t * vm, vlib_node_runtime_t * rt,
731                vlib_buffer_t * b, bfd_session_t ** bs_out)
732 {
733   const bfd_pkt_t *pkt = vlib_buffer_get_current (b);
734   if (sizeof (*pkt) > b->current_length)
735     {
736       BFD_ERR
737         ("Payload size %d too small to hold bfd packet of minimum size %d",
738          b->current_length, sizeof (*pkt));
739       return BFD_UDP_ERROR_BAD;
740     }
741   ip4_header_t *ip4;
742   udp_header_t *udp;
743   bfd_udp4_find_headers (b, &ip4, &udp);
744   if (!ip4 || !udp)
745     {
746       BFD_ERR ("Couldn't find ip4 or udp header");
747       return BFD_UDP_ERROR_BAD;
748     }
749   const u32 udp_payload_length = udp->length - sizeof (*udp);
750   if (pkt->head.length > udp_payload_length)
751     {
752       BFD_ERR
753         ("BFD packet length is larger than udp payload length (%u > %u)",
754          pkt->head.length, udp_payload_length);
755       return BFD_UDP_ERROR_BAD;
756     }
757   if (!bfd_verify_pkt_common (pkt))
758     {
759       return BFD_UDP_ERROR_BAD;
760     }
761   bfd_session_t *bs = NULL;
762   if (pkt->your_disc)
763     {
764       BFD_DBG ("Looking up BFD session using discriminator %u",
765                pkt->your_disc);
766       bs = bfd_find_session_by_disc (bfd_udp_main.bfd_main, pkt->your_disc);
767     }
768   else
769     {
770       bfd_udp_key_t key;
771       memset (&key, 0, sizeof (key));
772       key.sw_if_index = vnet_buffer (b)->sw_if_index[VLIB_RX];
773       key.local_addr.ip4.as_u32 = ip4->dst_address.as_u32;
774       key.peer_addr.ip4.as_u32 = ip4->src_address.as_u32;
775       BFD_DBG ("Looking up BFD session using key (sw_if_index=%u, local=%U, "
776                "peer=%U)",
777                key.sw_if_index, format_ip4_address, key.local_addr.ip4.as_u8,
778                format_ip4_address, key.peer_addr.ip4.as_u8);
779       bs = bfd_lookup_session (&bfd_udp_main, &key);
780     }
781   if (!bs)
782     {
783       BFD_ERR ("BFD session lookup failed - no session matches BFD pkt");
784       return BFD_UDP_ERROR_BAD;
785     }
786   BFD_DBG ("BFD session found, bs_idx=%u", bs->bs_idx);
787   if (!bfd_verify_pkt_auth (pkt, b->current_length, bs))
788     {
789       BFD_ERR ("Packet verification failed, dropping packet");
790       return BFD_UDP_ERROR_BAD;
791     }
792   bfd_udp_error_t err;
793   if (BFD_UDP_ERROR_NONE != (err = bfd_udp4_verify_transport (ip4, udp, bs)))
794     {
795       return err;
796     }
797   bfd_rpc_update_session (bs->bs_idx, pkt);
798   *bs_out = bs;
799   return BFD_UDP_ERROR_NONE;
800 }
801
802 static void
803 bfd_udp6_find_headers (vlib_buffer_t * b, ip6_header_t ** ip6,
804                        udp_header_t ** udp)
805 {
806   /* sanity check first */
807   const i32 start = vnet_buffer (b)->ip.start_of_ip_header;
808   if (start < 0 && start < sizeof (b->pre_data))
809     {
810       BFD_ERR ("Start of ip header is before pre_data, ignoring");
811       *ip6 = NULL;
812       *udp = NULL;
813       return;
814     }
815   *ip6 = (ip6_header_t *) (b->data + start);
816   if ((u8 *) * ip6 > (u8 *) vlib_buffer_get_current (b))
817     {
818       BFD_ERR ("Start of ip header is beyond current data, ignoring");
819       *ip6 = NULL;
820       *udp = NULL;
821       return;
822     }
823   if ((*ip6)->protocol != IP_PROTOCOL_UDP)
824     {
825       BFD_ERR ("Unexpected protocol in IPv6 header '%u', expected '%u' (== "
826                "IP_PROTOCOL_UDP)", (*ip6)->protocol, IP_PROTOCOL_UDP);
827       *ip6 = NULL;
828       *udp = NULL;
829       return;
830     }
831   *udp = (udp_header_t *) ((*ip6) + 1);
832 }
833
834 static bfd_udp_error_t
835 bfd_udp6_verify_transport (const ip6_header_t * ip6,
836                            const udp_header_t * udp, const bfd_session_t * bs)
837 {
838   const bfd_udp_session_t *bus = &bs->udp;
839   const bfd_udp_key_t *key = &bus->key;
840   if (ip6->src_address.as_u64[0] != key->peer_addr.ip6.as_u64[0] &&
841       ip6->src_address.as_u64[1] != key->peer_addr.ip6.as_u64[1])
842     {
843       BFD_ERR ("IP src addr mismatch, got %U, expected %U",
844                format_ip6_address, ip6, format_ip6_address,
845                &key->peer_addr.ip6);
846       return BFD_UDP_ERROR_BAD;
847     }
848   if (ip6->dst_address.as_u64[0] != key->local_addr.ip6.as_u64[0] &&
849       ip6->dst_address.as_u64[1] != key->local_addr.ip6.as_u64[1])
850     {
851       BFD_ERR ("IP dst addr mismatch, got %U, expected %U",
852                format_ip6_address, ip6, format_ip6_address,
853                &key->local_addr.ip6);
854       return BFD_UDP_ERROR_BAD;
855     }
856   const u8 expected_hop_limit = 255;
857   if (ip6->hop_limit != expected_hop_limit)
858     {
859       BFD_ERR ("IPv6 unexpected hop-limit value %u, expected %u",
860                ip6->hop_limit, expected_hop_limit);
861       return BFD_UDP_ERROR_BAD;
862     }
863   if (clib_net_to_host_u16 (udp->src_port) < 49152)
864     {
865       BFD_ERR ("Invalid UDP src port %u, out of range <49152,65535>",
866                udp->src_port);
867     }
868   return BFD_UDP_ERROR_NONE;
869 }
870
871 static bfd_udp_error_t
872 bfd_udp6_scan (vlib_main_t * vm, vlib_node_runtime_t * rt,
873                vlib_buffer_t * b, bfd_session_t ** bs_out)
874 {
875   const bfd_pkt_t *pkt = vlib_buffer_get_current (b);
876   if (sizeof (*pkt) > b->current_length)
877     {
878       BFD_ERR
879         ("Payload size %d too small to hold bfd packet of minimum size %d",
880          b->current_length, sizeof (*pkt));
881       return BFD_UDP_ERROR_BAD;
882     }
883   ip6_header_t *ip6;
884   udp_header_t *udp;
885   bfd_udp6_find_headers (b, &ip6, &udp);
886   if (!ip6 || !udp)
887     {
888       BFD_ERR ("Couldn't find ip6 or udp header");
889       return BFD_UDP_ERROR_BAD;
890     }
891   const u32 udp_payload_length = udp->length - sizeof (*udp);
892   if (pkt->head.length > udp_payload_length)
893     {
894       BFD_ERR
895         ("BFD packet length is larger than udp payload length (%u > %u)",
896          pkt->head.length, udp_payload_length);
897       return BFD_UDP_ERROR_BAD;
898     }
899   if (!bfd_verify_pkt_common (pkt))
900     {
901       return BFD_UDP_ERROR_BAD;
902     }
903   bfd_session_t *bs = NULL;
904   if (pkt->your_disc)
905     {
906       BFD_DBG ("Looking up BFD session using discriminator %u",
907                pkt->your_disc);
908       bs = bfd_find_session_by_disc (bfd_udp_main.bfd_main, pkt->your_disc);
909     }
910   else
911     {
912       bfd_udp_key_t key;
913       memset (&key, 0, sizeof (key));
914       key.sw_if_index = vnet_buffer (b)->sw_if_index[VLIB_RX];
915       key.local_addr.ip6.as_u64[0] = ip6->dst_address.as_u64[0];
916       key.local_addr.ip6.as_u64[1] = ip6->dst_address.as_u64[1];
917       key.peer_addr.ip6.as_u64[0] = ip6->src_address.as_u64[0];
918       key.peer_addr.ip6.as_u64[1] = ip6->src_address.as_u64[1];
919       BFD_DBG ("Looking up BFD session using key (sw_if_index=%u, local=%U, "
920                "peer=%U)",
921                key.sw_if_index, format_ip6_address, &key.local_addr,
922                format_ip6_address, &key.peer_addr);
923       bs = bfd_lookup_session (&bfd_udp_main, &key);
924     }
925   if (!bs)
926     {
927       BFD_ERR ("BFD session lookup failed - no session matches BFD pkt");
928       return BFD_UDP_ERROR_BAD;
929     }
930   BFD_DBG ("BFD session found, bs_idx=%u", bs->bs_idx);
931   if (!bfd_verify_pkt_auth (pkt, b->current_length, bs))
932     {
933       BFD_ERR ("Packet verification failed, dropping packet");
934       return BFD_UDP_ERROR_BAD;
935     }
936   bfd_udp_error_t err;
937   if (BFD_UDP_ERROR_NONE != (err = bfd_udp6_verify_transport (ip6, udp, bs)))
938     {
939       return err;
940     }
941   bfd_rpc_update_session (bs->bs_idx, pkt);
942   *bs_out = bs;
943   return BFD_UDP_ERROR_NONE;
944 }
945
946 /*
947  * Process a frame of bfd packets
948  * Expect 1 packet / frame
949  */
950 static uword
951 bfd_udp_input (vlib_main_t * vm, vlib_node_runtime_t * rt,
952                vlib_frame_t * f, int is_ipv6)
953 {
954   u32 n_left_from, *from;
955   bfd_input_trace_t *t0;
956
957   from = vlib_frame_vector_args (f);    /* array of buffer indices */
958   n_left_from = f->n_vectors;   /* number of buffer indices */
959
960   while (n_left_from > 0)
961     {
962       u32 bi0;
963       vlib_buffer_t *b0;
964       u32 next0, error0;
965
966       bi0 = from[0];
967       b0 = vlib_get_buffer (vm, bi0);
968
969       bfd_session_t *bs = NULL;
970
971       /* If this pkt is traced, snapshot the data */
972       if (b0->flags & VLIB_BUFFER_IS_TRACED)
973         {
974           int len;
975           t0 = vlib_add_trace (vm, rt, b0, sizeof (*t0));
976           len = (b0->current_length < sizeof (t0->data)) ? b0->current_length
977             : sizeof (t0->data);
978           t0->len = len;
979           clib_memcpy (t0->data, vlib_buffer_get_current (b0), len);
980         }
981
982       /* scan this bfd pkt. error0 is the counter index to bmp */
983       if (is_ipv6)
984         {
985           error0 = bfd_udp6_scan (vm, rt, b0, &bs);
986         }
987       else
988         {
989           error0 = bfd_udp4_scan (vm, rt, b0, &bs);
990         }
991       b0->error = rt->errors[error0];
992
993       next0 = BFD_UDP_INPUT_NEXT_NORMAL;
994       if (BFD_UDP_ERROR_NONE == error0)
995         {
996           /*
997            *  if everything went fine, check for poll bit, if present, re-use
998            *  the buffer and based on (now updated) session parameters, send
999            *  the final packet back
1000            */
1001           const bfd_pkt_t *pkt = vlib_buffer_get_current (b0);
1002           if (bfd_pkt_get_poll (pkt))
1003             {
1004               bfd_init_final_control_frame (vm, b0, bs);
1005               if (is_ipv6)
1006                 {
1007                   vlib_node_increment_counter (vm, bfd_udp6_input_node.index,
1008                                                b0->error, 1);
1009                 }
1010               else
1011                 {
1012                   vlib_node_increment_counter (vm, bfd_udp4_input_node.index,
1013                                                b0->error, 1);
1014                 }
1015               next0 = BFD_UDP_INPUT_NEXT_REPLY;
1016             }
1017         }
1018       vlib_set_next_frame_buffer (vm, rt, next0, bi0);
1019
1020       from += 1;
1021       n_left_from -= 1;
1022     }
1023
1024   return f->n_vectors;
1025 }
1026
1027 static uword
1028 bfd_udp4_input (vlib_main_t * vm, vlib_node_runtime_t * rt, vlib_frame_t * f)
1029 {
1030   return bfd_udp_input (vm, rt, f, 0);
1031 }
1032
1033 /*
1034  * bfd input graph node declaration
1035  */
1036 /* *INDENT-OFF* */
1037 VLIB_REGISTER_NODE (bfd_udp4_input_node, static) = {
1038   .function = bfd_udp4_input,
1039   .name = "bfd-udp4-input",
1040   .vector_size = sizeof (u32),
1041   .type = VLIB_NODE_TYPE_INTERNAL,
1042
1043   .n_errors = BFD_UDP_N_ERROR,
1044   .error_strings = bfd_udp_error_strings,
1045
1046   .format_trace = bfd_input_format_trace,
1047
1048   .n_next_nodes = BFD_UDP_INPUT_N_NEXT,
1049   .next_nodes =
1050       {
1051               [BFD_UDP_INPUT_NEXT_NORMAL] = "error-drop",
1052               [BFD_UDP_INPUT_NEXT_REPLY] = "ip4-lookup",
1053       },
1054 };
1055 /* *INDENT-ON* */
1056
1057 static uword
1058 bfd_udp6_input (vlib_main_t * vm, vlib_node_runtime_t * rt, vlib_frame_t * f)
1059 {
1060   return bfd_udp_input (vm, rt, f, 1);
1061 }
1062
1063 /* *INDENT-OFF* */
1064 VLIB_REGISTER_NODE (bfd_udp6_input_node, static) = {
1065   .function = bfd_udp6_input,
1066   .name = "bfd-udp6-input",
1067   .vector_size = sizeof (u32),
1068   .type = VLIB_NODE_TYPE_INTERNAL,
1069
1070   .n_errors = BFD_UDP_N_ERROR,
1071   .error_strings = bfd_udp_error_strings,
1072
1073   .format_trace = bfd_input_format_trace,
1074
1075   .n_next_nodes = BFD_UDP_INPUT_N_NEXT,
1076   .next_nodes =
1077       {
1078               [BFD_UDP_INPUT_NEXT_NORMAL] = "error-drop",
1079               [BFD_UDP_INPUT_NEXT_REPLY] = "ip6-lookup",
1080       },
1081 };
1082 /* *INDENT-ON* */
1083
1084 /**
1085  * @brief swap the source and destination IP addresses in the packet
1086  */
1087 static int
1088 bfd_echo_address_swap (vlib_buffer_t * b, int is_ipv6)
1089 {
1090   udp_header_t *dummy = NULL;
1091   if (is_ipv6)
1092     {
1093       ip6_header_t *ip6 = NULL;
1094       bfd_udp6_find_headers (b, &ip6, &dummy);
1095       if (!ip6)
1096         {
1097           return 0;
1098         }
1099       ip6_address_t tmp = ip6->dst_address;
1100       ip6->dst_address = ip6->src_address;
1101       ip6->src_address = tmp;
1102       vlib_buffer_advance (b,
1103                            (u8 *) ip6 - (u8 *) vlib_buffer_get_current (b));
1104     }
1105   else
1106     {
1107       ip4_header_t *ip4 = NULL;
1108       bfd_udp4_find_headers (b, &ip4, &dummy);
1109       if (!ip4)
1110         {
1111           return 0;
1112         }
1113       ip4_address_t tmp = ip4->dst_address;
1114       ip4->dst_address = ip4->src_address;
1115       ip4->src_address = tmp;
1116       vlib_buffer_advance (b,
1117                            (u8 *) ip4 - (u8 *) vlib_buffer_get_current (b));
1118     }
1119   return 1;
1120 }
1121
1122 /*
1123  * Process a frame of bfd echo packets
1124  * Expect 1 packet / frame
1125  */
1126 static uword
1127 bfd_udp_echo_input (vlib_main_t * vm, vlib_node_runtime_t * rt,
1128                     vlib_frame_t * f, int is_ipv6)
1129 {
1130   u32 n_left_from, *from;
1131   bfd_input_trace_t *t0;
1132
1133   from = vlib_frame_vector_args (f);    /* array of buffer indices */
1134   n_left_from = f->n_vectors;   /* number of buffer indices */
1135
1136   while (n_left_from > 0)
1137     {
1138       u32 bi0;
1139       vlib_buffer_t *b0;
1140       u32 next0;
1141
1142       bi0 = from[0];
1143       b0 = vlib_get_buffer (vm, bi0);
1144
1145       /* If this pkt is traced, snapshot the data */
1146       if (b0->flags & VLIB_BUFFER_IS_TRACED)
1147         {
1148           int len;
1149           t0 = vlib_add_trace (vm, rt, b0, sizeof (*t0));
1150           len = (b0->current_length < sizeof (t0->data)) ? b0->current_length
1151             : sizeof (t0->data);
1152           t0->len = len;
1153           clib_memcpy (t0->data, vlib_buffer_get_current (b0), len);
1154         }
1155
1156       if (bfd_echo_address_swap (b0, is_ipv6))
1157         {
1158           /* loop back the packet */
1159           b0->error = rt->errors[BFD_UDP_ERROR_NONE];
1160           if (is_ipv6)
1161             {
1162               vlib_node_increment_counter (vm, bfd_udp_echo6_input_node.index,
1163                                            b0->error, 1);
1164             }
1165           else
1166             {
1167               vlib_node_increment_counter (vm, bfd_udp_echo4_input_node.index,
1168                                            b0->error, 1);
1169             }
1170           next0 = BFD_UDP_INPUT_NEXT_REPLY;
1171         }
1172       else
1173         {
1174           b0->error = rt->errors[BFD_UDP_ERROR_BAD];
1175           next0 = BFD_UDP_INPUT_NEXT_NORMAL;
1176         }
1177
1178       vlib_set_next_frame_buffer (vm, rt, next0, bi0);
1179
1180       from += 1;
1181       n_left_from -= 1;
1182     }
1183
1184   return f->n_vectors;
1185 }
1186
1187 static uword
1188 bfd_udp_echo4_input (vlib_main_t * vm, vlib_node_runtime_t * rt,
1189                      vlib_frame_t * f)
1190 {
1191   return bfd_udp_echo_input (vm, rt, f, 0);
1192 }
1193
1194 u8 *
1195 bfd_echo_input_format_trace (u8 * s, va_list * args)
1196 {
1197   CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
1198   CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
1199   const bfd_udp_echo_input_trace_t *t =
1200     va_arg (*args, bfd_udp_echo_input_trace_t *);
1201   if (t->len > STRUCT_SIZE_OF (bfd_pkt_t, head))
1202     {
1203       s = format (s, "BFD ECHO:\n");
1204       s = format (s, "    data: %U", format_hexdump, t->data, t->len);
1205     }
1206
1207   return s;
1208 }
1209
1210 /*
1211  * bfd input graph node declaration
1212  */
1213 /* *INDENT-OFF* */
1214 VLIB_REGISTER_NODE (bfd_udp_echo4_input_node, static) = {
1215   .function = bfd_udp_echo4_input,
1216   .name = "bfd-udp-echo4-input",
1217   .vector_size = sizeof (u32),
1218   .type = VLIB_NODE_TYPE_INTERNAL,
1219
1220   .n_errors = BFD_UDP_ECHO_N_ERROR,
1221   .error_strings = bfd_udp_error_strings,
1222
1223   .format_trace = bfd_echo_input_format_trace,
1224
1225   .n_next_nodes = BFD_UDP_INPUT_N_NEXT,
1226   .next_nodes =
1227       {
1228               [BFD_UDP_INPUT_NEXT_NORMAL] = "error-drop",
1229               [BFD_UDP_INPUT_NEXT_REPLY] = "ip4-lookup",
1230       },
1231 };
1232 /* *INDENT-ON* */
1233
1234 static uword
1235 bfd_udp_echo6_input (vlib_main_t * vm, vlib_node_runtime_t * rt,
1236                      vlib_frame_t * f)
1237 {
1238   return bfd_udp_echo_input (vm, rt, f, 1);
1239 }
1240
1241 /* *INDENT-OFF* */
1242 VLIB_REGISTER_NODE (bfd_udp_echo6_input_node, static) = {
1243   .function = bfd_udp_echo6_input,
1244   .name = "bfd-udp-echo6-input",
1245   .vector_size = sizeof (u32),
1246   .type = VLIB_NODE_TYPE_INTERNAL,
1247
1248   .n_errors = BFD_UDP_ECHO_N_ERROR,
1249   .error_strings = bfd_udp_echo_error_strings,
1250
1251   .format_trace = bfd_echo_input_format_trace,
1252
1253   .n_next_nodes = BFD_UDP_INPUT_N_NEXT,
1254   .next_nodes =
1255       {
1256               [BFD_UDP_INPUT_NEXT_NORMAL] = "error-drop",
1257               [BFD_UDP_INPUT_NEXT_REPLY] = "ip6-lookup",
1258       },
1259 };
1260
1261 /* *INDENT-ON* */
1262
1263 static clib_error_t *
1264 bfd_sw_interface_up_down (vnet_main_t * vnm, u32 sw_if_index, u32 flags)
1265 {
1266   // vnet_hw_interface_t *hi = vnet_get_sup_hw_interface (vnm, sw_if_index);
1267   if (!(flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP))
1268     {
1269       /* TODO */
1270     }
1271   return 0;
1272 }
1273
1274 VNET_SW_INTERFACE_ADMIN_UP_DOWN_FUNCTION (bfd_sw_interface_up_down);
1275
1276 static clib_error_t *
1277 bfd_hw_interface_up_down (vnet_main_t * vnm, u32 hw_if_index, u32 flags)
1278 {
1279   if (flags & VNET_HW_INTERFACE_FLAG_LINK_UP)
1280     {
1281       /* TODO */
1282     }
1283   return 0;
1284 }
1285
1286 VNET_HW_INTERFACE_LINK_UP_DOWN_FUNCTION (bfd_hw_interface_up_down);
1287
1288 /*
1289  * setup function
1290  */
1291 static clib_error_t *
1292 bfd_udp_init (vlib_main_t * vm)
1293 {
1294   mhash_init (&bfd_udp_main.bfd_session_idx_by_bfd_key, sizeof (uword),
1295               sizeof (bfd_udp_key_t));
1296   bfd_udp_main.bfd_main = &bfd_main;
1297   udp_register_dst_port (vm, UDP_DST_PORT_bfd4, bfd_udp4_input_node.index, 1);
1298   udp_register_dst_port (vm, UDP_DST_PORT_bfd6, bfd_udp6_input_node.index, 0);
1299   udp_register_dst_port (vm, UDP_DST_PORT_bfd_echo4,
1300                          bfd_udp_echo4_input_node.index, 1);
1301   udp_register_dst_port (vm, UDP_DST_PORT_bfd_echo6,
1302                          bfd_udp_echo6_input_node.index, 0);
1303   return 0;
1304 }
1305
1306 VLIB_INIT_FUNCTION (bfd_udp_init);
1307
1308 /*
1309  * fd.io coding-style-patch-verification: ON
1310  *
1311  * Local Variables:
1312  * eval: (c-set-style "gnu")
1313  * End:
1314  */