blob: e1ff8a9d887ad7980a0c484973446ae6dc6ba606 [file] [log] [blame]
Klement Sekera0e3c0de2016-09-29 14:43:44 +02001#include <vppinfra/types.h>
2#include <vlibmemory/api.h>
3#include <vlib/vlib.h>
4#include <vlib/buffer.h>
5#include <vnet/ip/format.h>
6#include <vnet/ethernet/packet.h>
7#include <vnet/ip/udp_packet.h>
8#include <vnet/ip/lookup.h>
9#include <vnet/ip/icmp46_packet.h>
10#include <vnet/ip/ip4.h>
11#include <vnet/ip/ip6.h>
12#include <vnet/ip/udp.h>
13#include <vnet/ip/ip6_packet.h>
14#include <vnet/adj/adj.h>
15#include <vnet/adj/adj_nbr.h>
16#include <vnet/bfd/bfd_debug.h>
17#include <vnet/bfd/bfd_udp.h>
18#include <vnet/bfd/bfd_main.h>
19#include <vnet/bfd/bfd_api.h>
20
21typedef struct
22{
23 bfd_main_t *bfd_main;
24 /* hashmap - bfd session index by bfd key - used for CLI/API lookup, where
25 * discriminator is unknown */
26 mhash_t bfd_session_idx_by_bfd_key;
27} bfd_udp_main_t;
28
Klement Sekerae4504c62016-12-08 10:16:41 +010029static vlib_node_registration_t bfd_udp4_input_node;
30static vlib_node_registration_t bfd_udp6_input_node;
31
Klement Sekera0e3c0de2016-09-29 14:43:44 +020032bfd_udp_main_t bfd_udp_main;
33
Klement Sekerac5fccc02017-01-18 09:56:00 +010034void
35bfd_add_udp4_transport (vlib_main_t * vm, vlib_buffer_t * b,
36 bfd_udp_session_t * bus)
Klement Sekera0e3c0de2016-09-29 14:43:44 +020037{
Klement Sekera46a87ad2017-01-02 08:22:23 +010038 const bfd_udp_key_t *key = &bus->key;
Klement Sekera0e3c0de2016-09-29 14:43:44 +020039
40 b->flags |= VNET_BUFFER_LOCALLY_ORIGINATED;
Klement Sekera0e3c0de2016-09-29 14:43:44 +020041 vnet_buffer (b)->ip.adj_index[VLIB_RX] = bus->adj_index;
42 vnet_buffer (b)->ip.adj_index[VLIB_TX] = bus->adj_index;
Klement Sekera402ed312017-01-18 09:44:36 +010043 typedef struct
44 {
45 ip4_header_t ip4;
46 udp_header_t udp;
47 } ip4_udp_headers;
Klement Sekerab17dd962017-01-09 07:43:48 +010048 ip4_udp_headers *headers = NULL;
Klement Sekera402ed312017-01-18 09:44:36 +010049 vlib_buffer_advance (b, -sizeof (*headers));
50 headers = vlib_buffer_get_current (b);
51 memset (headers, 0, sizeof (*headers));
52 headers->ip4.ip_version_and_header_length = 0x45;
53 headers->ip4.ttl = 255;
54 headers->ip4.protocol = IP_PROTOCOL_UDP;
55 headers->ip4.src_address.as_u32 = key->local_addr.ip4.as_u32;
56 headers->ip4.dst_address.as_u32 = key->peer_addr.ip4.as_u32;
Klement Sekera46a87ad2017-01-02 08:22:23 +010057
Klement Sekera402ed312017-01-18 09:44:36 +010058 headers->udp.src_port = clib_host_to_net_u16 (50000); /* FIXME */
59 headers->udp.dst_port = clib_host_to_net_u16 (UDP_DST_PORT_bfd4);
Klement Sekera46a87ad2017-01-02 08:22:23 +010060
61 /* fix ip length, checksum and udp length */
62 const u16 ip_length = vlib_buffer_length_in_chain (vm, b);
63
Klement Sekera402ed312017-01-18 09:44:36 +010064 headers->ip4.length = clib_host_to_net_u16 (ip_length);
65 headers->ip4.checksum = ip4_header_checksum (&headers->ip4);
Klement Sekera46a87ad2017-01-02 08:22:23 +010066
Klement Sekera402ed312017-01-18 09:44:36 +010067 const u16 udp_length = ip_length - (sizeof (headers->ip4));
68 headers->udp.length = clib_host_to_net_u16 (udp_length);
Klement Sekera46a87ad2017-01-02 08:22:23 +010069}
70
Klement Sekerac5fccc02017-01-18 09:56:00 +010071void
72bfd_add_udp6_transport (vlib_main_t * vm, vlib_buffer_t * b,
73 bfd_udp_session_t * bus)
Klement Sekera46a87ad2017-01-02 08:22:23 +010074{
Klement Sekera46a87ad2017-01-02 08:22:23 +010075 const bfd_udp_key_t *key = &bus->key;
76
77 b->flags |= VNET_BUFFER_LOCALLY_ORIGINATED;
78 vnet_buffer (b)->ip.adj_index[VLIB_RX] = bus->adj_index;
79 vnet_buffer (b)->ip.adj_index[VLIB_TX] = bus->adj_index;
Klement Sekera402ed312017-01-18 09:44:36 +010080 typedef struct
81 {
82 ip6_header_t ip6;
83 udp_header_t udp;
84 } ip6_udp_headers;
Klement Sekerab17dd962017-01-09 07:43:48 +010085 ip6_udp_headers *headers = NULL;
86 vlib_buffer_advance (b, -sizeof (*headers));
87 headers = vlib_buffer_get_current (b);
Klement Sekera402ed312017-01-18 09:44:36 +010088 memset (headers, 0, sizeof (*headers));
89 headers->ip6.ip_version_traffic_class_and_flow_label =
Klement Sekerac5fccc02017-01-18 09:56:00 +010090 clib_host_to_net_u32 (0x6 << 28);
Klement Sekera402ed312017-01-18 09:44:36 +010091 headers->ip6.hop_limit = 255;
92 headers->ip6.protocol = IP_PROTOCOL_UDP;
93 clib_memcpy (&headers->ip6.src_address, &key->local_addr.ip6,
94 sizeof (headers->ip6.src_address));
95 clib_memcpy (&headers->ip6.dst_address, &key->peer_addr.ip6,
96 sizeof (headers->ip6.dst_address));
Klement Sekera46a87ad2017-01-02 08:22:23 +010097
Klement Sekera402ed312017-01-18 09:44:36 +010098 headers->udp.src_port = clib_host_to_net_u16 (50000); /* FIXME */
99 headers->udp.dst_port = clib_host_to_net_u16 (UDP_DST_PORT_bfd6);
Klement Sekera46a87ad2017-01-02 08:22:23 +0100100
101 /* fix ip payload length and udp length */
Klement Sekerac5fccc02017-01-18 09:56:00 +0100102 const u16 udp_length =
Klement Sekera402ed312017-01-18 09:44:36 +0100103 vlib_buffer_length_in_chain (vm, b) - (sizeof (headers->ip6));
104 headers->udp.length = clib_host_to_net_u16 (udp_length);
105 headers->ip6.payload_length = headers->udp.length;
Klement Sekera46a87ad2017-01-02 08:22:23 +0100106
107 /* IPv6 UDP checksum is mandatory */
108 int bogus = 0;
Klement Sekera402ed312017-01-18 09:44:36 +0100109 headers->udp.checksum =
110 ip6_tcp_udp_icmp_compute_checksum (vm, b, &headers->ip6, &bogus);
Klement Sekera46a87ad2017-01-02 08:22:23 +0100111 ASSERT (bogus == 0);
Klement Sekera402ed312017-01-18 09:44:36 +0100112 if (headers->udp.checksum == 0)
Klement Sekera46a87ad2017-01-02 08:22:23 +0100113 {
Klement Sekera402ed312017-01-18 09:44:36 +0100114 headers->udp.checksum = 0xffff;
Klement Sekera46a87ad2017-01-02 08:22:23 +0100115 }
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200116}
117
Klement Sekerac5fccc02017-01-18 09:56:00 +0100118static bfd_session_t *
119bfd_lookup_session (bfd_udp_main_t * bum, const bfd_udp_key_t * key)
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200120{
121 uword *p = mhash_get (&bum->bfd_session_idx_by_bfd_key, key);
122 if (p)
123 {
124 return bfd_find_session_by_idx (bum->bfd_main, *p);
125 }
126 return 0;
127}
128
Klement Sekerab17dd962017-01-09 07:43:48 +0100129static void
130bfd_udp_key_init (bfd_udp_key_t * key, u32 sw_if_index,
131 const ip46_address_t * local_addr,
132 const ip46_address_t * peer_addr)
133{
134 memset (key, 0, sizeof (*key));
135 key->sw_if_index = sw_if_index;
136 key->local_addr.as_u64[0] = local_addr->as_u64[0];
137 key->local_addr.as_u64[1] = local_addr->as_u64[1];
138 key->peer_addr.as_u64[0] = peer_addr->as_u64[0];
139 key->peer_addr.as_u64[1] = peer_addr->as_u64[1];
140}
141
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200142static vnet_api_error_t
Klement Sekerac5fccc02017-01-18 09:56:00 +0100143bfd_udp_add_session_internal (bfd_udp_main_t * bum, u32 sw_if_index,
Klement Sekeraa57a9702017-02-02 06:58:07 +0100144 u32 desired_min_tx_usec,
145 u32 required_min_rx_usec, u8 detect_mult,
Klement Sekerac5fccc02017-01-18 09:56:00 +0100146 const ip46_address_t * local_addr,
147 const ip46_address_t * peer_addr,
Klement Sekerab17dd962017-01-09 07:43:48 +0100148 bfd_session_t ** bs_out)
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200149{
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200150 /* get a pool entry and if we end up not needing it, give it back */
151 bfd_transport_t t = BFD_TRANSPORT_UDP4;
152 if (!ip46_address_is_ip4 (local_addr))
153 {
154 t = BFD_TRANSPORT_UDP6;
155 }
156 bfd_session_t *bs = bfd_get_session (bum->bfd_main, t);
157 bfd_udp_session_t *bus = &bs->udp;
158 memset (bus, 0, sizeof (*bus));
159 bfd_udp_key_t *key = &bus->key;
Klement Sekerab17dd962017-01-09 07:43:48 +0100160 bfd_udp_key_init (key, sw_if_index, local_addr, peer_addr);
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200161 const bfd_session_t *tmp = bfd_lookup_session (bum, key);
162 if (tmp)
163 {
Klement Sekerab17dd962017-01-09 07:43:48 +0100164 clib_warning ("duplicate bfd-udp session, existing bs_idx=%d",
165 tmp->bs_idx);
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200166 bfd_put_session (bum->bfd_main, bs);
167 return VNET_API_ERROR_BFD_EEXIST;
168 }
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200169 mhash_set (&bum->bfd_session_idx_by_bfd_key, key, bs->bs_idx, NULL);
170 BFD_DBG ("session created, bs_idx=%u, sw_if_index=%d, local=%U, peer=%U",
Klement Sekerac5fccc02017-01-18 09:56:00 +0100171 bs->bs_idx, key->sw_if_index, format_ip46_address,
172 &key->local_addr, IP46_TYPE_ANY, format_ip46_address,
173 &key->peer_addr, IP46_TYPE_ANY);
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200174 if (BFD_TRANSPORT_UDP4 == t)
175 {
176 bus->adj_index = adj_nbr_add_or_lock (FIB_PROTOCOL_IP4, VNET_LINK_IP4,
Klement Sekerac5fccc02017-01-18 09:56:00 +0100177 &key->peer_addr,
178 key->sw_if_index);
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200179 BFD_DBG ("adj_nbr_add_or_lock(FIB_PROTOCOL_IP4, VNET_LINK_IP4, %U, %d) "
Klement Sekerac5fccc02017-01-18 09:56:00 +0100180 "returns %d", format_ip46_address, &key->peer_addr,
181 IP46_TYPE_ANY, key->sw_if_index, bus->adj_index);
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200182 }
183 else
184 {
185 bus->adj_index = adj_nbr_add_or_lock (FIB_PROTOCOL_IP6, VNET_LINK_IP6,
Klement Sekerac5fccc02017-01-18 09:56:00 +0100186 &key->peer_addr,
187 key->sw_if_index);
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200188 BFD_DBG ("adj_nbr_add_or_lock(FIB_PROTOCOL_IP6, VNET_LINK_IP6, %U, %d) "
Klement Sekerac5fccc02017-01-18 09:56:00 +0100189 "returns %d", format_ip46_address, &key->peer_addr,
190 IP46_TYPE_ANY, key->sw_if_index, bus->adj_index);
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200191 }
Klement Sekerab17dd962017-01-09 07:43:48 +0100192 *bs_out = bs;
Klement Sekeraa57a9702017-02-02 06:58:07 +0100193 return bfd_session_set_params (bum->bfd_main, bs, desired_min_tx_usec,
194 required_min_rx_usec, detect_mult);
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200195}
196
197static vnet_api_error_t
Klement Sekerac5fccc02017-01-18 09:56:00 +0100198bfd_udp_validate_api_input (u32 sw_if_index,
199 const ip46_address_t * local_addr,
200 const ip46_address_t * peer_addr)
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200201{
202 vnet_sw_interface_t *sw_if =
Klement Sekerac5fccc02017-01-18 09:56:00 +0100203 vnet_get_sw_interface (vnet_get_main (), sw_if_index);
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200204 u8 local_ip_valid = 0;
205 ip_interface_address_t *ia = NULL;
206 if (!sw_if)
207 {
Klement Sekerab17dd962017-01-09 07:43:48 +0100208 clib_warning ("got NULL sw_if");
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200209 return VNET_API_ERROR_INVALID_SW_IF_INDEX;
210 }
211 if (ip46_address_is_ip4 (local_addr))
212 {
213 if (!ip46_address_is_ip4 (peer_addr))
Klement Sekerac5fccc02017-01-18 09:56:00 +0100214 {
Klement Sekerab17dd962017-01-09 07:43:48 +0100215 clib_warning ("IP family mismatch");
Klement Sekerac5fccc02017-01-18 09:56:00 +0100216 return VNET_API_ERROR_INVALID_ARGUMENT;
217 }
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200218 ip4_main_t *im = &ip4_main;
219
220 /* *INDENT-OFF* */
221 foreach_ip_interface_address (
222 &im->lookup_main, ia, sw_if_index, 0 /* honor unnumbered */, ({
223 ip4_address_t *x =
224 ip_interface_address_get_address (&im->lookup_main, ia);
225 if (x->as_u32 == local_addr->ip4.as_u32)
226 {
227 /* valid address for this interface */
228 local_ip_valid = 1;
229 break;
230 }
231 }));
232 /* *INDENT-ON* */
233 }
234 else
235 {
236 if (ip46_address_is_ip4 (peer_addr))
Klement Sekerac5fccc02017-01-18 09:56:00 +0100237 {
Klement Sekerab17dd962017-01-09 07:43:48 +0100238 clib_warning ("IP family mismatch");
Klement Sekerac5fccc02017-01-18 09:56:00 +0100239 return VNET_API_ERROR_INVALID_ARGUMENT;
240 }
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200241 ip6_main_t *im = &ip6_main;
242 /* *INDENT-OFF* */
243 foreach_ip_interface_address (
244 &im->lookup_main, ia, sw_if_index, 0 /* honor unnumbered */, ({
245 ip6_address_t *x =
246 ip_interface_address_get_address (&im->lookup_main, ia);
247 if (local_addr->ip6.as_u64[0] == x->as_u64[0] &&
Klement Sekerab17dd962017-01-09 07:43:48 +0100248 local_addr->ip6.as_u64[1] == x->as_u64[1])
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200249 {
250 /* valid address for this interface */
251 local_ip_valid = 1;
252 break;
253 }
254 }));
255 /* *INDENT-ON* */
256 }
257
258 if (!local_ip_valid)
259 {
Klement Sekerab17dd962017-01-09 07:43:48 +0100260 clib_warning ("address not found on interface");
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200261 return VNET_API_ERROR_ADDRESS_NOT_FOUND_FOR_INTERFACE;
262 }
263
264 return 0;
265}
266
Klement Sekerab17dd962017-01-09 07:43:48 +0100267static vnet_api_error_t
268bfd_udp_find_session_by_api_input (u32 sw_if_index,
269 const ip46_address_t * local_addr,
270 const ip46_address_t * peer_addr,
271 bfd_session_t ** bs_out)
272{
273 vnet_api_error_t rv =
274 bfd_udp_validate_api_input (sw_if_index, local_addr, peer_addr);
275 if (!rv)
276 {
277 bfd_udp_main_t *bum = &bfd_udp_main;
278 bfd_udp_key_t key;
279 bfd_udp_key_init (&key, sw_if_index, local_addr, peer_addr);
280 bfd_session_t *bs = bfd_lookup_session (bum, &key);
281 if (bs)
282 {
283 *bs_out = bs;
284 }
285 else
286 {
287 clib_warning
288 ("BFD session not found (sw_if_index=%u, local=%U, peer=%U",
289 sw_if_index, format_ip46_address, local_addr, IP46_TYPE_ANY,
290 format_ip46_address, peer_addr, IP46_TYPE_ANY);
291 return VNET_API_ERROR_BFD_ENOENT;
292 }
293 }
294 return rv;
295}
296
297static vnet_api_error_t
Klement Sekeraa57a9702017-02-02 06:58:07 +0100298bfd_api_verify_common (u32 sw_if_index, u32 desired_min_tx_usec,
299 u32 required_min_rx_usec, u8 detect_mult,
Klement Sekerab17dd962017-01-09 07:43:48 +0100300 const ip46_address_t * local_addr,
301 const ip46_address_t * peer_addr)
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200302{
303 vnet_api_error_t rv =
Klement Sekerac5fccc02017-01-18 09:56:00 +0100304 bfd_udp_validate_api_input (sw_if_index, local_addr, peer_addr);
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200305 if (rv)
306 {
307 return rv;
308 }
309 if (detect_mult < 1)
310 {
Klement Sekerab17dd962017-01-09 07:43:48 +0100311 clib_warning ("detect_mult < 1");
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200312 return VNET_API_ERROR_INVALID_ARGUMENT;
313 }
Klement Sekeraa57a9702017-02-02 06:58:07 +0100314 if (desired_min_tx_usec < 1)
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200315 {
Klement Sekeraa57a9702017-02-02 06:58:07 +0100316 clib_warning ("desired_min_tx_usec < 1");
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200317 return VNET_API_ERROR_INVALID_ARGUMENT;
318 }
Klement Sekerab17dd962017-01-09 07:43:48 +0100319 return 0;
320}
321
322static void
323bfd_udp_del_session_internal (bfd_session_t * bs)
324{
325 bfd_udp_main_t *bum = &bfd_udp_main;
326 BFD_DBG ("free bfd-udp session, bs_idx=%d", bs->bs_idx);
327 mhash_unset (&bum->bfd_session_idx_by_bfd_key, &bs->udp.key, NULL);
328 adj_unlock (bs->udp.adj_index);
329 bfd_put_session (bum->bfd_main, bs);
330}
331
332vnet_api_error_t
333bfd_udp_add_session (u32 sw_if_index, const ip46_address_t * local_addr,
Klement Sekeraa57a9702017-02-02 06:58:07 +0100334 const ip46_address_t * peer_addr,
335 u32 desired_min_tx_usec, u32 required_min_rx_usec,
336 u8 detect_mult, u8 is_authenticated, u32 conf_key_id,
337 u8 bfd_key_id)
Klement Sekerab17dd962017-01-09 07:43:48 +0100338{
Klement Sekeraa57a9702017-02-02 06:58:07 +0100339 vnet_api_error_t rv =
340 bfd_api_verify_common (sw_if_index, desired_min_tx_usec,
341 required_min_rx_usec, detect_mult,
342 local_addr, peer_addr);
Klement Sekerab17dd962017-01-09 07:43:48 +0100343 bfd_session_t *bs = NULL;
344 if (!rv)
345 {
346 rv =
347 bfd_udp_add_session_internal (&bfd_udp_main, sw_if_index,
Klement Sekeraa57a9702017-02-02 06:58:07 +0100348 desired_min_tx_usec,
349 required_min_rx_usec, detect_mult,
350 local_addr, peer_addr, &bs);
Klement Sekerab17dd962017-01-09 07:43:48 +0100351 }
352 if (!rv && is_authenticated)
353 {
354#if WITH_LIBSSL > 0
355 rv = bfd_auth_activate (bs, conf_key_id, bfd_key_id,
356 0 /* is not delayed */ );
357#else
358 clib_warning ("SSL missing, cannot add authenticated BFD session");
359 rv = VNET_API_ERROR_BFD_NOTSUPP;
360#endif
361 if (rv)
362 {
363 bfd_udp_del_session_internal (bs);
364 }
365 }
366 if (!rv)
367 {
368 bfd_session_start (bfd_udp_main.bfd_main, bs);
369 }
370
371 return rv;
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200372}
373
Klement Sekerac5fccc02017-01-18 09:56:00 +0100374vnet_api_error_t
Klement Sekeraa57a9702017-02-02 06:58:07 +0100375bfd_udp_mod_session (u32 sw_if_index,
376 const ip46_address_t * local_addr,
377 const ip46_address_t * peer_addr,
378 u32 desired_min_tx_usec,
379 u32 required_min_rx_usec, u8 detect_mult)
380{
381 bfd_session_t *bs = NULL;
382 vnet_api_error_t rv =
383 bfd_udp_find_session_by_api_input (sw_if_index, local_addr, peer_addr,
384 &bs);
385 if (rv)
386 {
387 return rv;
388 }
389
390 return bfd_session_set_params (bfd_udp_main.bfd_main, bs,
391 desired_min_tx_usec, required_min_rx_usec,
392 detect_mult);
393}
394
395vnet_api_error_t
Klement Sekerac5fccc02017-01-18 09:56:00 +0100396bfd_udp_del_session (u32 sw_if_index,
397 const ip46_address_t * local_addr,
398 const ip46_address_t * peer_addr)
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200399{
Klement Sekerab17dd962017-01-09 07:43:48 +0100400 bfd_session_t *bs = NULL;
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200401 vnet_api_error_t rv =
Klement Sekerab17dd962017-01-09 07:43:48 +0100402 bfd_udp_find_session_by_api_input (sw_if_index, local_addr, peer_addr,
403 &bs);
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200404 if (rv)
405 {
406 return rv;
407 }
Klement Sekerab17dd962017-01-09 07:43:48 +0100408 bfd_udp_del_session_internal (bs);
409 return 0;
410}
411
412vnet_api_error_t
413bfd_udp_session_set_flags (u32 sw_if_index,
414 const ip46_address_t * local_addr,
415 const ip46_address_t * peer_addr, u8 admin_up_down)
416{
417 bfd_session_t *bs = NULL;
418 vnet_api_error_t rv =
419 bfd_udp_find_session_by_api_input (sw_if_index, local_addr, peer_addr,
420 &bs);
421 if (rv)
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200422 {
Klement Sekerab17dd962017-01-09 07:43:48 +0100423 return rv;
424 }
425 bfd_session_set_flags (bs, admin_up_down);
426 return 0;
427}
428
429vnet_api_error_t
430bfd_auth_set_key (u32 conf_key_id, u8 auth_type, u8 key_len,
431 const u8 * key_data)
432{
433#if WITH_LIBSSL > 0
434 bfd_auth_key_t *auth_key = NULL;
435 if (!key_len || key_len > bfd_max_len_for_auth_type (auth_type))
436 {
437 clib_warning ("Invalid authentication key length for auth_type=%d:%s "
438 "(key_len=%u, must be "
439 "non-zero, expected max=%u)",
440 auth_type, bfd_auth_type_str (auth_type), key_len,
441 (u32) bfd_max_len_for_auth_type (auth_type));
442 return VNET_API_ERROR_INVALID_VALUE;
443 }
444 if (!bfd_auth_type_supported (auth_type))
445 {
446 clib_warning ("Unsupported auth type=%d:%s", auth_type,
447 bfd_auth_type_str (auth_type));
448 return VNET_API_ERROR_BFD_NOTSUPP;
449 }
450 bfd_main_t *bm = bfd_udp_main.bfd_main;
451 uword *key_idx_p = hash_get (bm->auth_key_by_conf_key_id, conf_key_id);
452 if (key_idx_p)
453 {
454 /* modifying existing key - must not be used */
455 const uword key_idx = *key_idx_p;
456 auth_key = pool_elt_at_index (bm->auth_keys, key_idx);
457 if (auth_key->use_count > 0)
458 {
459 clib_warning ("Authentication key with conf ID %u in use by %u BFD "
460 "sessions - cannot modify",
461 conf_key_id, auth_key->use_count);
462 return VNET_API_ERROR_BFD_EINUSE;
463 }
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200464 }
465 else
466 {
Klement Sekerab17dd962017-01-09 07:43:48 +0100467 /* adding new key */
468 pool_get (bm->auth_keys, auth_key);
469 auth_key->conf_key_id = conf_key_id;
470 hash_set (bm->auth_key_by_conf_key_id, conf_key_id,
471 auth_key - bm->auth_keys);
472 }
473 auth_key->auth_type = auth_type;
474 memset (auth_key->key, 0, sizeof (auth_key->key));
475 clib_memcpy (auth_key->key, key_data, key_len);
476 return 0;
477#else
478 clib_warning ("SSL missing, cannot manipulate authentication keys");
479 return VNET_API_ERROR_BFD_NOTSUPP;
480#endif
481}
482
483vnet_api_error_t
484bfd_auth_del_key (u32 conf_key_id)
485{
486#if WITH_LIBSSL > 0
487 bfd_auth_key_t *auth_key = NULL;
488 bfd_main_t *bm = bfd_udp_main.bfd_main;
489 uword *key_idx_p = hash_get (bm->auth_key_by_conf_key_id, conf_key_id);
490 if (key_idx_p)
491 {
492 /* deleting existing key - must not be used */
493 const uword key_idx = *key_idx_p;
494 auth_key = pool_elt_at_index (bm->auth_keys, key_idx);
495 if (auth_key->use_count > 0)
496 {
497 clib_warning ("Authentication key with conf ID %u in use by %u BFD "
498 "sessions - cannot delete",
499 conf_key_id, auth_key->use_count);
500 return VNET_API_ERROR_BFD_EINUSE;
501 }
502 hash_unset (bm->auth_key_by_conf_key_id, conf_key_id);
503 memset (auth_key, 0, sizeof (*auth_key));
504 pool_put (bm->auth_keys, auth_key);
505 }
506 else
507 {
508 /* no such key */
509 clib_warning ("Authentication key with conf ID %u does not exist",
510 conf_key_id);
511 return VNET_API_ERROR_BFD_ENOENT;
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200512 }
513 return 0;
Klement Sekerab17dd962017-01-09 07:43:48 +0100514#else
515 clib_warning ("SSL missing, cannot manipulate authentication keys");
516 return VNET_API_ERROR_BFD_NOTSUPP;
517#endif
518}
519
520vnet_api_error_t
521bfd_udp_auth_activate (u32 sw_if_index,
522 const ip46_address_t * local_addr,
523 const ip46_address_t * peer_addr,
524 u32 conf_key_id, u8 key_id, u8 is_delayed)
525{
526#if WITH_LIBSSL > 0
527 bfd_session_t *bs = NULL;
528 vnet_api_error_t rv =
529 bfd_udp_find_session_by_api_input (sw_if_index, local_addr, peer_addr,
530 &bs);
531 if (rv)
532 {
533 return rv;
534 }
535 return bfd_auth_activate (bs, conf_key_id, key_id, is_delayed);
536#else
537 clib_warning ("SSL missing, cannot activate BFD authentication");
538 return VNET_API_ERROR_BFD_NOTSUPP;
539#endif
540}
541
542vnet_api_error_t
543bfd_udp_auth_deactivate (u32 sw_if_index,
544 const ip46_address_t * local_addr,
545 const ip46_address_t * peer_addr, u8 is_delayed)
546{
547 bfd_session_t *bs = NULL;
548 vnet_api_error_t rv =
549 bfd_udp_find_session_by_api_input (sw_if_index, local_addr, peer_addr,
550 &bs);
551 if (rv)
552 {
553 return rv;
554 }
555 return bfd_auth_deactivate (bs, is_delayed);
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200556}
557
Klement Sekerac5fccc02017-01-18 09:56:00 +0100558typedef enum
559{
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200560 BFD_UDP_INPUT_NEXT_NORMAL,
561 BFD_UDP_INPUT_NEXT_REPLY,
562 BFD_UDP_INPUT_N_NEXT,
563} bfd_udp_input_next_t;
564
565/* Packet counters */
566#define foreach_bfd_udp_error(F) \
567 F (NONE, "good bfd packets (processed)") \
568 F (BAD, "invalid bfd packets") \
569 F (DISABLED, "bfd packets received on disabled interfaces")
570
571#define F(sym, string) static char BFD_UDP_ERR_##sym##_STR[] = string;
572foreach_bfd_udp_error (F);
573#undef F
574
575static char *bfd_udp_error_strings[] = {
576#define F(sym, string) BFD_UDP_ERR_##sym##_STR,
577 foreach_bfd_udp_error (F)
578#undef F
579};
580
Klement Sekerac5fccc02017-01-18 09:56:00 +0100581typedef enum
582{
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200583#define F(sym, str) BFD_UDP_ERROR_##sym,
584 foreach_bfd_udp_error (F)
585#undef F
Klement Sekerac5fccc02017-01-18 09:56:00 +0100586 BFD_UDP_N_ERROR,
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200587} bfd_udp_error_t;
588
Klement Sekerac5fccc02017-01-18 09:56:00 +0100589static void
590bfd_udp4_find_headers (vlib_buffer_t * b, const ip4_header_t ** ip4,
591 const udp_header_t ** udp)
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200592{
Klement Sekera0c1519b2016-12-08 05:03:32 +0100593 /* sanity check first */
594 const i32 start = vnet_buffer (b)->ip.start_of_ip_header;
595 if (start < 0 && start < sizeof (b->pre_data))
596 {
597 BFD_ERR ("Start of ip header is before pre_data, ignoring");
598 *ip4 = NULL;
599 *udp = NULL;
600 return;
601 }
Klement Sekerac5fccc02017-01-18 09:56:00 +0100602 *ip4 = (ip4_header_t *) (b->data + start);
603 if ((u8 *) * ip4 > (u8 *) vlib_buffer_get_current (b))
Klement Sekera0c1519b2016-12-08 05:03:32 +0100604 {
605 BFD_ERR ("Start of ip header is beyond current data, ignoring");
606 *ip4 = NULL;
607 *udp = NULL;
608 return;
609 }
Klement Sekerac5fccc02017-01-18 09:56:00 +0100610 *udp = (udp_header_t *) ((*ip4) + 1);
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200611}
612
Klement Sekerac5fccc02017-01-18 09:56:00 +0100613static bfd_udp_error_t
614bfd_udp4_verify_transport (const ip4_header_t * ip4,
615 const udp_header_t * udp, const bfd_session_t * bs)
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200616{
617 const bfd_udp_session_t *bus = &bs->udp;
618 const bfd_udp_key_t *key = &bus->key;
619 if (ip4->src_address.as_u32 != key->peer_addr.ip4.as_u32)
620 {
Klement Sekera46a87ad2017-01-02 08:22:23 +0100621 BFD_ERR ("IPv4 src addr mismatch, got %U, expected %U",
Klement Sekerac5fccc02017-01-18 09:56:00 +0100622 format_ip4_address, ip4->src_address.as_u8, format_ip4_address,
623 key->peer_addr.ip4.as_u8);
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200624 return BFD_UDP_ERROR_BAD;
625 }
626 if (ip4->dst_address.as_u32 != key->local_addr.ip4.as_u32)
627 {
Klement Sekera46a87ad2017-01-02 08:22:23 +0100628 BFD_ERR ("IPv4 dst addr mismatch, got %U, expected %U",
Klement Sekerac5fccc02017-01-18 09:56:00 +0100629 format_ip4_address, ip4->dst_address.as_u8, format_ip4_address,
630 key->local_addr.ip4.as_u8);
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200631 return BFD_UDP_ERROR_BAD;
632 }
633 const u8 expected_ttl = 255;
634 if (ip4->ttl != expected_ttl)
635 {
Klement Sekera46a87ad2017-01-02 08:22:23 +0100636 BFD_ERR ("IPv4 unexpected TTL value %u, expected %u", ip4->ttl,
Klement Sekerac5fccc02017-01-18 09:56:00 +0100637 expected_ttl);
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200638 return BFD_UDP_ERROR_BAD;
639 }
Klement Sekera6f966492017-02-08 07:42:08 +0100640 if (clib_net_to_host_u16 (udp->src_port) < 49152)
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200641 {
Klement Sekera46a87ad2017-01-02 08:22:23 +0100642 BFD_ERR ("Invalid UDP src port %u, out of range <49152,65535>",
Klement Sekerac5fccc02017-01-18 09:56:00 +0100643 udp->src_port);
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200644 }
645 return BFD_UDP_ERROR_NONE;
646}
647
648typedef struct
649{
650 u32 bs_idx;
651 bfd_pkt_t pkt;
652} bfd_rpc_update_t;
653
Klement Sekerac5fccc02017-01-18 09:56:00 +0100654static void
655bfd_rpc_update_session_cb (const bfd_rpc_update_t * a)
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200656{
657 bfd_consume_pkt (bfd_udp_main.bfd_main, &a->pkt, a->bs_idx);
658}
659
Klement Sekerac5fccc02017-01-18 09:56:00 +0100660static void
661bfd_rpc_update_session (u32 bs_idx, const bfd_pkt_t * pkt)
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200662{
663 /* packet length was already verified to be correct by the caller */
664 const u32 data_size = sizeof (bfd_rpc_update_t) -
Klement Sekerac5fccc02017-01-18 09:56:00 +0100665 STRUCT_SIZE_OF (bfd_rpc_update_t, pkt) + pkt->head.length;
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200666 u8 data[data_size];
Klement Sekerac5fccc02017-01-18 09:56:00 +0100667 bfd_rpc_update_t *update = (bfd_rpc_update_t *) data;
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200668 update->bs_idx = bs_idx;
669 clib_memcpy (&update->pkt, pkt, pkt->head.length);
670 vl_api_rpc_call_main_thread (bfd_rpc_update_session_cb, data, data_size);
671}
672
Klement Sekerac5fccc02017-01-18 09:56:00 +0100673static bfd_udp_error_t
674bfd_udp4_scan (vlib_main_t * vm, vlib_node_runtime_t * rt,
675 vlib_buffer_t * b, bfd_session_t ** bs_out)
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200676{
677 const bfd_pkt_t *pkt = vlib_buffer_get_current (b);
678 if (sizeof (*pkt) > b->current_length)
679 {
Klement Sekerac5fccc02017-01-18 09:56:00 +0100680 BFD_ERR
681 ("Payload size %d too small to hold bfd packet of minimum size %d",
682 b->current_length, sizeof (*pkt));
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200683 return BFD_UDP_ERROR_BAD;
684 }
685 const ip4_header_t *ip4;
686 const udp_header_t *udp;
687 bfd_udp4_find_headers (b, &ip4, &udp);
688 if (!ip4 || !udp)
689 {
690 BFD_ERR ("Couldn't find ip4 or udp header");
691 return BFD_UDP_ERROR_BAD;
692 }
Klement Sekerab17dd962017-01-09 07:43:48 +0100693 const u32 udp_payload_length = udp->length - sizeof (*udp);
694 if (pkt->head.length > udp_payload_length)
695 {
696 BFD_ERR
697 ("BFD packet length is larger than udp payload length (%u > %u)",
698 pkt->head.length, udp_payload_length);
699 return BFD_UDP_ERROR_BAD;
700 }
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200701 if (!bfd_verify_pkt_common (pkt))
702 {
703 return BFD_UDP_ERROR_BAD;
704 }
705 bfd_session_t *bs = NULL;
706 if (pkt->your_disc)
707 {
708 BFD_DBG ("Looking up BFD session using discriminator %u",
Klement Sekerac5fccc02017-01-18 09:56:00 +0100709 pkt->your_disc);
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200710 bs = bfd_find_session_by_disc (bfd_udp_main.bfd_main, pkt->your_disc);
711 }
712 else
713 {
714 bfd_udp_key_t key;
715 memset (&key, 0, sizeof (key));
716 key.sw_if_index = vnet_buffer (b)->sw_if_index[VLIB_RX];
717 key.local_addr.ip4.as_u32 = ip4->dst_address.as_u32;
718 key.peer_addr.ip4.as_u32 = ip4->src_address.as_u32;
719 BFD_DBG ("Looking up BFD session using key (sw_if_index=%u, local=%U, "
Klement Sekerac5fccc02017-01-18 09:56:00 +0100720 "peer=%U)",
721 key.sw_if_index, format_ip4_address, key.local_addr.ip4.as_u8,
722 format_ip4_address, key.peer_addr.ip4.as_u8);
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200723 bs = bfd_lookup_session (&bfd_udp_main, &key);
724 }
725 if (!bs)
726 {
727 BFD_ERR ("BFD session lookup failed - no session matches BFD pkt");
728 return BFD_UDP_ERROR_BAD;
729 }
Klement Sekera637b9c42016-12-08 05:19:14 +0100730 BFD_DBG ("BFD session found, bs_idx=%u", bs->bs_idx);
Klement Sekerab17dd962017-01-09 07:43:48 +0100731 if (!bfd_verify_pkt_auth (pkt, b->current_length, bs))
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200732 {
Klement Sekerab17dd962017-01-09 07:43:48 +0100733 BFD_ERR ("Packet verification failed, dropping packet");
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200734 return BFD_UDP_ERROR_BAD;
735 }
736 bfd_udp_error_t err;
737 if (BFD_UDP_ERROR_NONE != (err = bfd_udp4_verify_transport (ip4, udp, bs)))
738 {
739 return err;
740 }
741 bfd_rpc_update_session (bs->bs_idx, pkt);
742 *bs_out = bs;
743 return BFD_UDP_ERROR_NONE;
744}
745
Klement Sekerac5fccc02017-01-18 09:56:00 +0100746static void
747bfd_udp6_find_headers (vlib_buffer_t * b, const ip6_header_t ** ip6,
748 const udp_header_t ** udp)
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200749{
Klement Sekera46a87ad2017-01-02 08:22:23 +0100750 /* sanity check first */
751 const i32 start = vnet_buffer (b)->ip.start_of_ip_header;
752 if (start < 0 && start < sizeof (b->pre_data))
753 {
754 BFD_ERR ("Start of ip header is before pre_data, ignoring");
755 *ip6 = NULL;
756 *udp = NULL;
757 return;
758 }
Klement Sekerac5fccc02017-01-18 09:56:00 +0100759 *ip6 = (ip6_header_t *) (b->data + start);
760 if ((u8 *) * ip6 > (u8 *) vlib_buffer_get_current (b))
Klement Sekera46a87ad2017-01-02 08:22:23 +0100761 {
762 BFD_ERR ("Start of ip header is beyond current data, ignoring");
763 *ip6 = NULL;
764 *udp = NULL;
765 return;
766 }
Klement Sekera402ed312017-01-18 09:44:36 +0100767 if ((*ip6)->protocol != IP_PROTOCOL_UDP)
768 {
769 BFD_ERR ("Unexpected protocol in IPv6 header '%u', expected '%u' (== "
Klement Sekerab17dd962017-01-09 07:43:48 +0100770 "IP_PROTOCOL_UDP)", (*ip6)->protocol, IP_PROTOCOL_UDP);
Klement Sekera402ed312017-01-18 09:44:36 +0100771 *ip6 = NULL;
772 *udp = NULL;
773 return;
774 }
Klement Sekerac5fccc02017-01-18 09:56:00 +0100775 *udp = (udp_header_t *) ((*ip6) + 1);
Klement Sekera46a87ad2017-01-02 08:22:23 +0100776}
777
Klement Sekerac5fccc02017-01-18 09:56:00 +0100778static bfd_udp_error_t
779bfd_udp6_verify_transport (const ip6_header_t * ip6,
780 const udp_header_t * udp, const bfd_session_t * bs)
Klement Sekera46a87ad2017-01-02 08:22:23 +0100781{
782 const bfd_udp_session_t *bus = &bs->udp;
783 const bfd_udp_key_t *key = &bus->key;
784 if (ip6->src_address.as_u64[0] != key->peer_addr.ip6.as_u64[0] &&
785 ip6->src_address.as_u64[1] != key->peer_addr.ip6.as_u64[1])
786 {
Klement Sekerac5fccc02017-01-18 09:56:00 +0100787 BFD_ERR ("IP src addr mismatch, got %U, expected %U",
788 format_ip6_address, ip6, format_ip6_address,
789 &key->peer_addr.ip6);
Klement Sekera46a87ad2017-01-02 08:22:23 +0100790 return BFD_UDP_ERROR_BAD;
791 }
792 if (ip6->dst_address.as_u64[0] != key->local_addr.ip6.as_u64[0] &&
793 ip6->dst_address.as_u64[1] != key->local_addr.ip6.as_u64[1])
794 {
Klement Sekerac5fccc02017-01-18 09:56:00 +0100795 BFD_ERR ("IP dst addr mismatch, got %U, expected %U",
796 format_ip6_address, ip6, format_ip6_address,
797 &key->local_addr.ip6);
Klement Sekera46a87ad2017-01-02 08:22:23 +0100798 return BFD_UDP_ERROR_BAD;
799 }
800 const u8 expected_hop_limit = 255;
801 if (ip6->hop_limit != expected_hop_limit)
802 {
803 BFD_ERR ("IPv6 unexpected hop-limit value %u, expected %u",
Klement Sekerac5fccc02017-01-18 09:56:00 +0100804 ip6->hop_limit, expected_hop_limit);
Klement Sekera46a87ad2017-01-02 08:22:23 +0100805 return BFD_UDP_ERROR_BAD;
806 }
Klement Sekera6f966492017-02-08 07:42:08 +0100807 if (clib_net_to_host_u16 (udp->src_port) < 49152)
Klement Sekera46a87ad2017-01-02 08:22:23 +0100808 {
809 BFD_ERR ("Invalid UDP src port %u, out of range <49152,65535>",
Klement Sekerac5fccc02017-01-18 09:56:00 +0100810 udp->src_port);
Klement Sekera46a87ad2017-01-02 08:22:23 +0100811 }
812 return BFD_UDP_ERROR_NONE;
813}
814
Klement Sekerac5fccc02017-01-18 09:56:00 +0100815static bfd_udp_error_t
816bfd_udp6_scan (vlib_main_t * vm, vlib_node_runtime_t * rt,
817 vlib_buffer_t * b, bfd_session_t ** bs_out)
Klement Sekera46a87ad2017-01-02 08:22:23 +0100818{
819 const bfd_pkt_t *pkt = vlib_buffer_get_current (b);
820 if (sizeof (*pkt) > b->current_length)
821 {
Klement Sekerac5fccc02017-01-18 09:56:00 +0100822 BFD_ERR
823 ("Payload size %d too small to hold bfd packet of minimum size %d",
824 b->current_length, sizeof (*pkt));
Klement Sekera46a87ad2017-01-02 08:22:23 +0100825 return BFD_UDP_ERROR_BAD;
826 }
827 const ip6_header_t *ip6;
828 const udp_header_t *udp;
829 bfd_udp6_find_headers (b, &ip6, &udp);
830 if (!ip6 || !udp)
831 {
832 BFD_ERR ("Couldn't find ip6 or udp header");
833 return BFD_UDP_ERROR_BAD;
834 }
Klement Sekerab17dd962017-01-09 07:43:48 +0100835 const u32 udp_payload_length = udp->length - sizeof (*udp);
836 if (pkt->head.length > udp_payload_length)
837 {
838 BFD_ERR
839 ("BFD packet length is larger than udp payload length (%u > %u)",
840 pkt->head.length, udp_payload_length);
841 return BFD_UDP_ERROR_BAD;
842 }
Klement Sekera46a87ad2017-01-02 08:22:23 +0100843 if (!bfd_verify_pkt_common (pkt))
844 {
845 return BFD_UDP_ERROR_BAD;
846 }
847 bfd_session_t *bs = NULL;
848 if (pkt->your_disc)
849 {
850 BFD_DBG ("Looking up BFD session using discriminator %u",
Klement Sekerac5fccc02017-01-18 09:56:00 +0100851 pkt->your_disc);
Klement Sekera46a87ad2017-01-02 08:22:23 +0100852 bs = bfd_find_session_by_disc (bfd_udp_main.bfd_main, pkt->your_disc);
853 }
854 else
855 {
856 bfd_udp_key_t key;
857 memset (&key, 0, sizeof (key));
858 key.sw_if_index = vnet_buffer (b)->sw_if_index[VLIB_RX];
859 key.local_addr.ip6.as_u64[0] = ip6->dst_address.as_u64[0];
860 key.local_addr.ip6.as_u64[1] = ip6->dst_address.as_u64[1];
861 key.peer_addr.ip6.as_u64[0] = ip6->src_address.as_u64[0];
862 key.peer_addr.ip6.as_u64[1] = ip6->src_address.as_u64[1];
863 BFD_DBG ("Looking up BFD session using key (sw_if_index=%u, local=%U, "
Klement Sekerab17dd962017-01-09 07:43:48 +0100864 "peer=%U)",
865 key.sw_if_index, format_ip6_address, &key.local_addr,
866 format_ip6_address, &key.peer_addr);
Klement Sekera46a87ad2017-01-02 08:22:23 +0100867 bs = bfd_lookup_session (&bfd_udp_main, &key);
868 }
869 if (!bs)
870 {
871 BFD_ERR ("BFD session lookup failed - no session matches BFD pkt");
872 return BFD_UDP_ERROR_BAD;
873 }
874 BFD_DBG ("BFD session found, bs_idx=%u", bs->bs_idx);
Klement Sekerab17dd962017-01-09 07:43:48 +0100875 if (!bfd_verify_pkt_auth (pkt, b->current_length, bs))
Klement Sekera46a87ad2017-01-02 08:22:23 +0100876 {
Klement Sekerab17dd962017-01-09 07:43:48 +0100877 BFD_ERR ("Packet verification failed, dropping packet");
Klement Sekera46a87ad2017-01-02 08:22:23 +0100878 return BFD_UDP_ERROR_BAD;
879 }
880 bfd_udp_error_t err;
881 if (BFD_UDP_ERROR_NONE != (err = bfd_udp6_verify_transport (ip6, udp, bs)))
882 {
883 return err;
884 }
885 bfd_rpc_update_session (bs->bs_idx, pkt);
886 *bs_out = bs;
887 return BFD_UDP_ERROR_NONE;
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200888}
889
890/*
891 * Process a frame of bfd packets
892 * Expect 1 packet / frame
893 */
Klement Sekerac5fccc02017-01-18 09:56:00 +0100894static uword
895bfd_udp_input (vlib_main_t * vm, vlib_node_runtime_t * rt,
896 vlib_frame_t * f, int is_ipv6)
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200897{
898 u32 n_left_from, *from;
899 bfd_input_trace_t *t0;
900
Klement Sekerac5fccc02017-01-18 09:56:00 +0100901 from = vlib_frame_vector_args (f); /* array of buffer indices */
902 n_left_from = f->n_vectors; /* number of buffer indices */
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200903
904 while (n_left_from > 0)
905 {
906 u32 bi0;
907 vlib_buffer_t *b0;
908 u32 next0, error0;
909
910 bi0 = from[0];
911 b0 = vlib_get_buffer (vm, bi0);
912
913 bfd_session_t *bs = NULL;
914
915 /* If this pkt is traced, snapshot the data */
916 if (b0->flags & VLIB_BUFFER_IS_TRACED)
Klement Sekerac5fccc02017-01-18 09:56:00 +0100917 {
918 int len;
919 t0 = vlib_add_trace (vm, rt, b0, sizeof (*t0));
920 len = (b0->current_length < sizeof (t0->data)) ? b0->current_length
921 : sizeof (t0->data);
922 t0->len = len;
923 clib_memcpy (t0->data, vlib_buffer_get_current (b0), len);
924 }
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200925
926 /* scan this bfd pkt. error0 is the counter index to bmp */
927 if (is_ipv6)
Klement Sekerac5fccc02017-01-18 09:56:00 +0100928 {
929 error0 = bfd_udp6_scan (vm, rt, b0, &bs);
930 }
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200931 else
Klement Sekerac5fccc02017-01-18 09:56:00 +0100932 {
933 error0 = bfd_udp4_scan (vm, rt, b0, &bs);
934 }
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200935 b0->error = rt->errors[error0];
936
937 next0 = BFD_UDP_INPUT_NEXT_NORMAL;
938 if (BFD_UDP_ERROR_NONE == error0)
Klement Sekerac5fccc02017-01-18 09:56:00 +0100939 {
Klement Sekera402ed312017-01-18 09:44:36 +0100940 /*
941 * if everything went fine, check for poll bit, if present, re-use
942 * the buffer and based on (now updated) session parameters, send
943 * the final packet back
944 */
Klement Sekerac5fccc02017-01-18 09:56:00 +0100945 const bfd_pkt_t *pkt = vlib_buffer_get_current (b0);
946 if (bfd_pkt_get_poll (pkt))
947 {
Klement Sekerab17dd962017-01-09 07:43:48 +0100948 bfd_init_final_control_frame (vm, b0, bs);
Klement Sekerac5fccc02017-01-18 09:56:00 +0100949 if (is_ipv6)
950 {
951 vlib_node_increment_counter (vm, bfd_udp6_input_node.index,
952 b0->error, 1);
953 }
954 else
955 {
956 vlib_node_increment_counter (vm, bfd_udp4_input_node.index,
957 b0->error, 1);
958 }
959 next0 = BFD_UDP_INPUT_NEXT_REPLY;
960 }
961 }
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200962 vlib_set_next_frame_buffer (vm, rt, next0, bi0);
963
964 from += 1;
965 n_left_from -= 1;
966 }
967
968 return f->n_vectors;
969}
970
Klement Sekerac5fccc02017-01-18 09:56:00 +0100971static uword
972bfd_udp4_input (vlib_main_t * vm, vlib_node_runtime_t * rt, vlib_frame_t * f)
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200973{
974 return bfd_udp_input (vm, rt, f, 0);
975}
976
977/*
978 * bfd input graph node declaration
979 */
980/* *INDENT-OFF* */
981VLIB_REGISTER_NODE (bfd_udp4_input_node, static) = {
982 .function = bfd_udp4_input,
983 .name = "bfd-udp4-input",
984 .vector_size = sizeof (u32),
985 .type = VLIB_NODE_TYPE_INTERNAL,
986
987 .n_errors = BFD_UDP_N_ERROR,
988 .error_strings = bfd_udp_error_strings,
989
990 .format_trace = bfd_input_format_trace,
991
992 .n_next_nodes = BFD_UDP_INPUT_N_NEXT,
993 .next_nodes =
994 {
995 [BFD_UDP_INPUT_NEXT_NORMAL] = "error-drop",
996 [BFD_UDP_INPUT_NEXT_REPLY] = "ip4-lookup",
997 },
998};
999/* *INDENT-ON* */
1000
Klement Sekerac5fccc02017-01-18 09:56:00 +01001001static uword
1002bfd_udp6_input (vlib_main_t * vm, vlib_node_runtime_t * rt, vlib_frame_t * f)
Klement Sekera0e3c0de2016-09-29 14:43:44 +02001003{
1004 return bfd_udp_input (vm, rt, f, 1);
1005}
1006
1007/* *INDENT-OFF* */
1008VLIB_REGISTER_NODE (bfd_udp6_input_node, static) = {
1009 .function = bfd_udp6_input,
1010 .name = "bfd-udp6-input",
1011 .vector_size = sizeof (u32),
1012 .type = VLIB_NODE_TYPE_INTERNAL,
1013
1014 .n_errors = BFD_UDP_N_ERROR,
1015 .error_strings = bfd_udp_error_strings,
1016
1017 .format_trace = bfd_input_format_trace,
1018
1019 .n_next_nodes = BFD_UDP_INPUT_N_NEXT,
1020 .next_nodes =
1021 {
1022 [BFD_UDP_INPUT_NEXT_NORMAL] = "error-drop",
1023 [BFD_UDP_INPUT_NEXT_REPLY] = "ip6-lookup",
1024 },
1025};
1026/* *INDENT-ON* */
1027
Klement Sekerac5fccc02017-01-18 09:56:00 +01001028static clib_error_t *
1029bfd_sw_interface_up_down (vnet_main_t * vnm, u32 sw_if_index, u32 flags)
Klement Sekera0e3c0de2016-09-29 14:43:44 +02001030{
1031 // vnet_hw_interface_t *hi = vnet_get_sup_hw_interface (vnm, sw_if_index);
1032 if (!(flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP))
1033 {
1034 /* TODO */
1035 }
1036 return 0;
1037}
1038
1039VNET_SW_INTERFACE_ADMIN_UP_DOWN_FUNCTION (bfd_sw_interface_up_down);
1040
Klement Sekerac5fccc02017-01-18 09:56:00 +01001041static clib_error_t *
1042bfd_hw_interface_up_down (vnet_main_t * vnm, u32 hw_if_index, u32 flags)
Klement Sekera0e3c0de2016-09-29 14:43:44 +02001043{
1044 if (flags & VNET_HW_INTERFACE_FLAG_LINK_UP)
1045 {
1046 /* TODO */
1047 }
1048 return 0;
1049}
1050
1051VNET_HW_INTERFACE_LINK_UP_DOWN_FUNCTION (bfd_hw_interface_up_down);
1052
1053/*
1054 * setup function
1055 */
Klement Sekerac5fccc02017-01-18 09:56:00 +01001056static clib_error_t *
1057bfd_udp_init (vlib_main_t * vm)
Klement Sekera0e3c0de2016-09-29 14:43:44 +02001058{
1059 mhash_init (&bfd_udp_main.bfd_session_idx_by_bfd_key, sizeof (uword),
Klement Sekerac5fccc02017-01-18 09:56:00 +01001060 sizeof (bfd_udp_key_t));
Klement Sekera0e3c0de2016-09-29 14:43:44 +02001061 bfd_udp_main.bfd_main = &bfd_main;
1062 udp_register_dst_port (vm, UDP_DST_PORT_bfd4, bfd_udp4_input_node.index, 1);
1063 udp_register_dst_port (vm, UDP_DST_PORT_bfd6, bfd_udp6_input_node.index, 0);
1064 return 0;
1065}
1066
1067VLIB_INIT_FUNCTION (bfd_udp_init);
Klement Sekerac5fccc02017-01-18 09:56:00 +01001068
1069/*
1070 * fd.io coding-style-patch-verification: ON
1071 *
1072 * Local Variables:
1073 * eval: (c-set-style "gnu")
1074 * End:
1075 */