blob: e21b887c47e3b82532d41da4060e9aca6e9e4941 [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 }
640 if (clib_net_to_host_u16 (udp->src_port) < 49152 ||
641 clib_net_to_host_u16 (udp->src_port) > 65535)
642 {
Klement Sekera46a87ad2017-01-02 08:22:23 +0100643 BFD_ERR ("Invalid UDP src port %u, out of range <49152,65535>",
Klement Sekerac5fccc02017-01-18 09:56:00 +0100644 udp->src_port);
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200645 }
646 return BFD_UDP_ERROR_NONE;
647}
648
649typedef struct
650{
651 u32 bs_idx;
652 bfd_pkt_t pkt;
653} bfd_rpc_update_t;
654
Klement Sekerac5fccc02017-01-18 09:56:00 +0100655static void
656bfd_rpc_update_session_cb (const bfd_rpc_update_t * a)
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200657{
658 bfd_consume_pkt (bfd_udp_main.bfd_main, &a->pkt, a->bs_idx);
659}
660
Klement Sekerac5fccc02017-01-18 09:56:00 +0100661static void
662bfd_rpc_update_session (u32 bs_idx, const bfd_pkt_t * pkt)
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200663{
664 /* packet length was already verified to be correct by the caller */
665 const u32 data_size = sizeof (bfd_rpc_update_t) -
Klement Sekerac5fccc02017-01-18 09:56:00 +0100666 STRUCT_SIZE_OF (bfd_rpc_update_t, pkt) + pkt->head.length;
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200667 u8 data[data_size];
Klement Sekerac5fccc02017-01-18 09:56:00 +0100668 bfd_rpc_update_t *update = (bfd_rpc_update_t *) data;
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200669 update->bs_idx = bs_idx;
670 clib_memcpy (&update->pkt, pkt, pkt->head.length);
671 vl_api_rpc_call_main_thread (bfd_rpc_update_session_cb, data, data_size);
672}
673
Klement Sekerac5fccc02017-01-18 09:56:00 +0100674static bfd_udp_error_t
675bfd_udp4_scan (vlib_main_t * vm, vlib_node_runtime_t * rt,
676 vlib_buffer_t * b, bfd_session_t ** bs_out)
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200677{
678 const bfd_pkt_t *pkt = vlib_buffer_get_current (b);
679 if (sizeof (*pkt) > b->current_length)
680 {
Klement Sekerac5fccc02017-01-18 09:56:00 +0100681 BFD_ERR
682 ("Payload size %d too small to hold bfd packet of minimum size %d",
683 b->current_length, sizeof (*pkt));
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200684 return BFD_UDP_ERROR_BAD;
685 }
686 const ip4_header_t *ip4;
687 const udp_header_t *udp;
688 bfd_udp4_find_headers (b, &ip4, &udp);
689 if (!ip4 || !udp)
690 {
691 BFD_ERR ("Couldn't find ip4 or udp header");
692 return BFD_UDP_ERROR_BAD;
693 }
Klement Sekerab17dd962017-01-09 07:43:48 +0100694 const u32 udp_payload_length = udp->length - sizeof (*udp);
695 if (pkt->head.length > udp_payload_length)
696 {
697 BFD_ERR
698 ("BFD packet length is larger than udp payload length (%u > %u)",
699 pkt->head.length, udp_payload_length);
700 return BFD_UDP_ERROR_BAD;
701 }
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200702 if (!bfd_verify_pkt_common (pkt))
703 {
704 return BFD_UDP_ERROR_BAD;
705 }
706 bfd_session_t *bs = NULL;
707 if (pkt->your_disc)
708 {
709 BFD_DBG ("Looking up BFD session using discriminator %u",
Klement Sekerac5fccc02017-01-18 09:56:00 +0100710 pkt->your_disc);
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200711 bs = bfd_find_session_by_disc (bfd_udp_main.bfd_main, pkt->your_disc);
712 }
713 else
714 {
715 bfd_udp_key_t key;
716 memset (&key, 0, sizeof (key));
717 key.sw_if_index = vnet_buffer (b)->sw_if_index[VLIB_RX];
718 key.local_addr.ip4.as_u32 = ip4->dst_address.as_u32;
719 key.peer_addr.ip4.as_u32 = ip4->src_address.as_u32;
720 BFD_DBG ("Looking up BFD session using key (sw_if_index=%u, local=%U, "
Klement Sekerac5fccc02017-01-18 09:56:00 +0100721 "peer=%U)",
722 key.sw_if_index, format_ip4_address, key.local_addr.ip4.as_u8,
723 format_ip4_address, key.peer_addr.ip4.as_u8);
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200724 bs = bfd_lookup_session (&bfd_udp_main, &key);
725 }
726 if (!bs)
727 {
728 BFD_ERR ("BFD session lookup failed - no session matches BFD pkt");
729 return BFD_UDP_ERROR_BAD;
730 }
Klement Sekera637b9c42016-12-08 05:19:14 +0100731 BFD_DBG ("BFD session found, bs_idx=%u", bs->bs_idx);
Klement Sekerab17dd962017-01-09 07:43:48 +0100732 if (!bfd_verify_pkt_auth (pkt, b->current_length, bs))
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200733 {
Klement Sekerab17dd962017-01-09 07:43:48 +0100734 BFD_ERR ("Packet verification failed, dropping packet");
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200735 return BFD_UDP_ERROR_BAD;
736 }
737 bfd_udp_error_t err;
738 if (BFD_UDP_ERROR_NONE != (err = bfd_udp4_verify_transport (ip4, udp, bs)))
739 {
740 return err;
741 }
742 bfd_rpc_update_session (bs->bs_idx, pkt);
743 *bs_out = bs;
744 return BFD_UDP_ERROR_NONE;
745}
746
Klement Sekerac5fccc02017-01-18 09:56:00 +0100747static void
748bfd_udp6_find_headers (vlib_buffer_t * b, const ip6_header_t ** ip6,
749 const udp_header_t ** udp)
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200750{
Klement Sekera46a87ad2017-01-02 08:22:23 +0100751 /* sanity check first */
752 const i32 start = vnet_buffer (b)->ip.start_of_ip_header;
753 if (start < 0 && start < sizeof (b->pre_data))
754 {
755 BFD_ERR ("Start of ip header is before pre_data, ignoring");
756 *ip6 = NULL;
757 *udp = NULL;
758 return;
759 }
Klement Sekerac5fccc02017-01-18 09:56:00 +0100760 *ip6 = (ip6_header_t *) (b->data + start);
761 if ((u8 *) * ip6 > (u8 *) vlib_buffer_get_current (b))
Klement Sekera46a87ad2017-01-02 08:22:23 +0100762 {
763 BFD_ERR ("Start of ip header is beyond current data, ignoring");
764 *ip6 = NULL;
765 *udp = NULL;
766 return;
767 }
Klement Sekera402ed312017-01-18 09:44:36 +0100768 if ((*ip6)->protocol != IP_PROTOCOL_UDP)
769 {
770 BFD_ERR ("Unexpected protocol in IPv6 header '%u', expected '%u' (== "
Klement Sekerab17dd962017-01-09 07:43:48 +0100771 "IP_PROTOCOL_UDP)", (*ip6)->protocol, IP_PROTOCOL_UDP);
Klement Sekera402ed312017-01-18 09:44:36 +0100772 *ip6 = NULL;
773 *udp = NULL;
774 return;
775 }
Klement Sekerac5fccc02017-01-18 09:56:00 +0100776 *udp = (udp_header_t *) ((*ip6) + 1);
Klement Sekera46a87ad2017-01-02 08:22:23 +0100777}
778
Klement Sekerac5fccc02017-01-18 09:56:00 +0100779static bfd_udp_error_t
780bfd_udp6_verify_transport (const ip6_header_t * ip6,
781 const udp_header_t * udp, const bfd_session_t * bs)
Klement Sekera46a87ad2017-01-02 08:22:23 +0100782{
783 const bfd_udp_session_t *bus = &bs->udp;
784 const bfd_udp_key_t *key = &bus->key;
785 if (ip6->src_address.as_u64[0] != key->peer_addr.ip6.as_u64[0] &&
786 ip6->src_address.as_u64[1] != key->peer_addr.ip6.as_u64[1])
787 {
Klement Sekerac5fccc02017-01-18 09:56:00 +0100788 BFD_ERR ("IP src addr mismatch, got %U, expected %U",
789 format_ip6_address, ip6, format_ip6_address,
790 &key->peer_addr.ip6);
Klement Sekera46a87ad2017-01-02 08:22:23 +0100791 return BFD_UDP_ERROR_BAD;
792 }
793 if (ip6->dst_address.as_u64[0] != key->local_addr.ip6.as_u64[0] &&
794 ip6->dst_address.as_u64[1] != key->local_addr.ip6.as_u64[1])
795 {
Klement Sekerac5fccc02017-01-18 09:56:00 +0100796 BFD_ERR ("IP dst addr mismatch, got %U, expected %U",
797 format_ip6_address, ip6, format_ip6_address,
798 &key->local_addr.ip6);
Klement Sekera46a87ad2017-01-02 08:22:23 +0100799 return BFD_UDP_ERROR_BAD;
800 }
801 const u8 expected_hop_limit = 255;
802 if (ip6->hop_limit != expected_hop_limit)
803 {
804 BFD_ERR ("IPv6 unexpected hop-limit value %u, expected %u",
Klement Sekerac5fccc02017-01-18 09:56:00 +0100805 ip6->hop_limit, expected_hop_limit);
Klement Sekera46a87ad2017-01-02 08:22:23 +0100806 return BFD_UDP_ERROR_BAD;
807 }
808 if (clib_net_to_host_u16 (udp->src_port) < 49152 ||
809 clib_net_to_host_u16 (udp->src_port) > 65535)
810 {
811 BFD_ERR ("Invalid UDP src port %u, out of range <49152,65535>",
Klement Sekerac5fccc02017-01-18 09:56:00 +0100812 udp->src_port);
Klement Sekera46a87ad2017-01-02 08:22:23 +0100813 }
814 return BFD_UDP_ERROR_NONE;
815}
816
Klement Sekerac5fccc02017-01-18 09:56:00 +0100817static bfd_udp_error_t
818bfd_udp6_scan (vlib_main_t * vm, vlib_node_runtime_t * rt,
819 vlib_buffer_t * b, bfd_session_t ** bs_out)
Klement Sekera46a87ad2017-01-02 08:22:23 +0100820{
821 const bfd_pkt_t *pkt = vlib_buffer_get_current (b);
822 if (sizeof (*pkt) > b->current_length)
823 {
Klement Sekerac5fccc02017-01-18 09:56:00 +0100824 BFD_ERR
825 ("Payload size %d too small to hold bfd packet of minimum size %d",
826 b->current_length, sizeof (*pkt));
Klement Sekera46a87ad2017-01-02 08:22:23 +0100827 return BFD_UDP_ERROR_BAD;
828 }
829 const ip6_header_t *ip6;
830 const udp_header_t *udp;
831 bfd_udp6_find_headers (b, &ip6, &udp);
832 if (!ip6 || !udp)
833 {
834 BFD_ERR ("Couldn't find ip6 or udp header");
835 return BFD_UDP_ERROR_BAD;
836 }
Klement Sekerab17dd962017-01-09 07:43:48 +0100837 const u32 udp_payload_length = udp->length - sizeof (*udp);
838 if (pkt->head.length > udp_payload_length)
839 {
840 BFD_ERR
841 ("BFD packet length is larger than udp payload length (%u > %u)",
842 pkt->head.length, udp_payload_length);
843 return BFD_UDP_ERROR_BAD;
844 }
Klement Sekera46a87ad2017-01-02 08:22:23 +0100845 if (!bfd_verify_pkt_common (pkt))
846 {
847 return BFD_UDP_ERROR_BAD;
848 }
849 bfd_session_t *bs = NULL;
850 if (pkt->your_disc)
851 {
852 BFD_DBG ("Looking up BFD session using discriminator %u",
Klement Sekerac5fccc02017-01-18 09:56:00 +0100853 pkt->your_disc);
Klement Sekera46a87ad2017-01-02 08:22:23 +0100854 bs = bfd_find_session_by_disc (bfd_udp_main.bfd_main, pkt->your_disc);
855 }
856 else
857 {
858 bfd_udp_key_t key;
859 memset (&key, 0, sizeof (key));
860 key.sw_if_index = vnet_buffer (b)->sw_if_index[VLIB_RX];
861 key.local_addr.ip6.as_u64[0] = ip6->dst_address.as_u64[0];
862 key.local_addr.ip6.as_u64[1] = ip6->dst_address.as_u64[1];
863 key.peer_addr.ip6.as_u64[0] = ip6->src_address.as_u64[0];
864 key.peer_addr.ip6.as_u64[1] = ip6->src_address.as_u64[1];
865 BFD_DBG ("Looking up BFD session using key (sw_if_index=%u, local=%U, "
Klement Sekerab17dd962017-01-09 07:43:48 +0100866 "peer=%U)",
867 key.sw_if_index, format_ip6_address, &key.local_addr,
868 format_ip6_address, &key.peer_addr);
Klement Sekera46a87ad2017-01-02 08:22:23 +0100869 bs = bfd_lookup_session (&bfd_udp_main, &key);
870 }
871 if (!bs)
872 {
873 BFD_ERR ("BFD session lookup failed - no session matches BFD pkt");
874 return BFD_UDP_ERROR_BAD;
875 }
876 BFD_DBG ("BFD session found, bs_idx=%u", bs->bs_idx);
Klement Sekerab17dd962017-01-09 07:43:48 +0100877 if (!bfd_verify_pkt_auth (pkt, b->current_length, bs))
Klement Sekera46a87ad2017-01-02 08:22:23 +0100878 {
Klement Sekerab17dd962017-01-09 07:43:48 +0100879 BFD_ERR ("Packet verification failed, dropping packet");
Klement Sekera46a87ad2017-01-02 08:22:23 +0100880 return BFD_UDP_ERROR_BAD;
881 }
882 bfd_udp_error_t err;
883 if (BFD_UDP_ERROR_NONE != (err = bfd_udp6_verify_transport (ip6, udp, bs)))
884 {
885 return err;
886 }
887 bfd_rpc_update_session (bs->bs_idx, pkt);
888 *bs_out = bs;
889 return BFD_UDP_ERROR_NONE;
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200890}
891
892/*
893 * Process a frame of bfd packets
894 * Expect 1 packet / frame
895 */
Klement Sekerac5fccc02017-01-18 09:56:00 +0100896static uword
897bfd_udp_input (vlib_main_t * vm, vlib_node_runtime_t * rt,
898 vlib_frame_t * f, int is_ipv6)
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200899{
900 u32 n_left_from, *from;
901 bfd_input_trace_t *t0;
902
Klement Sekerac5fccc02017-01-18 09:56:00 +0100903 from = vlib_frame_vector_args (f); /* array of buffer indices */
904 n_left_from = f->n_vectors; /* number of buffer indices */
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200905
906 while (n_left_from > 0)
907 {
908 u32 bi0;
909 vlib_buffer_t *b0;
910 u32 next0, error0;
911
912 bi0 = from[0];
913 b0 = vlib_get_buffer (vm, bi0);
914
915 bfd_session_t *bs = NULL;
916
917 /* If this pkt is traced, snapshot the data */
918 if (b0->flags & VLIB_BUFFER_IS_TRACED)
Klement Sekerac5fccc02017-01-18 09:56:00 +0100919 {
920 int len;
921 t0 = vlib_add_trace (vm, rt, b0, sizeof (*t0));
922 len = (b0->current_length < sizeof (t0->data)) ? b0->current_length
923 : sizeof (t0->data);
924 t0->len = len;
925 clib_memcpy (t0->data, vlib_buffer_get_current (b0), len);
926 }
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200927
928 /* scan this bfd pkt. error0 is the counter index to bmp */
929 if (is_ipv6)
Klement Sekerac5fccc02017-01-18 09:56:00 +0100930 {
931 error0 = bfd_udp6_scan (vm, rt, b0, &bs);
932 }
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200933 else
Klement Sekerac5fccc02017-01-18 09:56:00 +0100934 {
935 error0 = bfd_udp4_scan (vm, rt, b0, &bs);
936 }
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200937 b0->error = rt->errors[error0];
938
939 next0 = BFD_UDP_INPUT_NEXT_NORMAL;
940 if (BFD_UDP_ERROR_NONE == error0)
Klement Sekerac5fccc02017-01-18 09:56:00 +0100941 {
Klement Sekera402ed312017-01-18 09:44:36 +0100942 /*
943 * if everything went fine, check for poll bit, if present, re-use
944 * the buffer and based on (now updated) session parameters, send
945 * the final packet back
946 */
Klement Sekerac5fccc02017-01-18 09:56:00 +0100947 const bfd_pkt_t *pkt = vlib_buffer_get_current (b0);
948 if (bfd_pkt_get_poll (pkt))
949 {
Klement Sekerab17dd962017-01-09 07:43:48 +0100950 bfd_init_final_control_frame (vm, b0, bs);
Klement Sekerac5fccc02017-01-18 09:56:00 +0100951 if (is_ipv6)
952 {
953 vlib_node_increment_counter (vm, bfd_udp6_input_node.index,
954 b0->error, 1);
955 }
956 else
957 {
958 vlib_node_increment_counter (vm, bfd_udp4_input_node.index,
959 b0->error, 1);
960 }
961 next0 = BFD_UDP_INPUT_NEXT_REPLY;
962 }
963 }
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200964 vlib_set_next_frame_buffer (vm, rt, next0, bi0);
965
966 from += 1;
967 n_left_from -= 1;
968 }
969
970 return f->n_vectors;
971}
972
Klement Sekerac5fccc02017-01-18 09:56:00 +0100973static uword
974bfd_udp4_input (vlib_main_t * vm, vlib_node_runtime_t * rt, vlib_frame_t * f)
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200975{
976 return bfd_udp_input (vm, rt, f, 0);
977}
978
979/*
980 * bfd input graph node declaration
981 */
982/* *INDENT-OFF* */
983VLIB_REGISTER_NODE (bfd_udp4_input_node, static) = {
984 .function = bfd_udp4_input,
985 .name = "bfd-udp4-input",
986 .vector_size = sizeof (u32),
987 .type = VLIB_NODE_TYPE_INTERNAL,
988
989 .n_errors = BFD_UDP_N_ERROR,
990 .error_strings = bfd_udp_error_strings,
991
992 .format_trace = bfd_input_format_trace,
993
994 .n_next_nodes = BFD_UDP_INPUT_N_NEXT,
995 .next_nodes =
996 {
997 [BFD_UDP_INPUT_NEXT_NORMAL] = "error-drop",
998 [BFD_UDP_INPUT_NEXT_REPLY] = "ip4-lookup",
999 },
1000};
1001/* *INDENT-ON* */
1002
Klement Sekerac5fccc02017-01-18 09:56:00 +01001003static uword
1004bfd_udp6_input (vlib_main_t * vm, vlib_node_runtime_t * rt, vlib_frame_t * f)
Klement Sekera0e3c0de2016-09-29 14:43:44 +02001005{
1006 return bfd_udp_input (vm, rt, f, 1);
1007}
1008
1009/* *INDENT-OFF* */
1010VLIB_REGISTER_NODE (bfd_udp6_input_node, static) = {
1011 .function = bfd_udp6_input,
1012 .name = "bfd-udp6-input",
1013 .vector_size = sizeof (u32),
1014 .type = VLIB_NODE_TYPE_INTERNAL,
1015
1016 .n_errors = BFD_UDP_N_ERROR,
1017 .error_strings = bfd_udp_error_strings,
1018
1019 .format_trace = bfd_input_format_trace,
1020
1021 .n_next_nodes = BFD_UDP_INPUT_N_NEXT,
1022 .next_nodes =
1023 {
1024 [BFD_UDP_INPUT_NEXT_NORMAL] = "error-drop",
1025 [BFD_UDP_INPUT_NEXT_REPLY] = "ip6-lookup",
1026 },
1027};
1028/* *INDENT-ON* */
1029
Klement Sekerac5fccc02017-01-18 09:56:00 +01001030static clib_error_t *
1031bfd_sw_interface_up_down (vnet_main_t * vnm, u32 sw_if_index, u32 flags)
Klement Sekera0e3c0de2016-09-29 14:43:44 +02001032{
1033 // vnet_hw_interface_t *hi = vnet_get_sup_hw_interface (vnm, sw_if_index);
1034 if (!(flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP))
1035 {
1036 /* TODO */
1037 }
1038 return 0;
1039}
1040
1041VNET_SW_INTERFACE_ADMIN_UP_DOWN_FUNCTION (bfd_sw_interface_up_down);
1042
Klement Sekerac5fccc02017-01-18 09:56:00 +01001043static clib_error_t *
1044bfd_hw_interface_up_down (vnet_main_t * vnm, u32 hw_if_index, u32 flags)
Klement Sekera0e3c0de2016-09-29 14:43:44 +02001045{
1046 if (flags & VNET_HW_INTERFACE_FLAG_LINK_UP)
1047 {
1048 /* TODO */
1049 }
1050 return 0;
1051}
1052
1053VNET_HW_INTERFACE_LINK_UP_DOWN_FUNCTION (bfd_hw_interface_up_down);
1054
1055/*
1056 * setup function
1057 */
Klement Sekerac5fccc02017-01-18 09:56:00 +01001058static clib_error_t *
1059bfd_udp_init (vlib_main_t * vm)
Klement Sekera0e3c0de2016-09-29 14:43:44 +02001060{
1061 mhash_init (&bfd_udp_main.bfd_session_idx_by_bfd_key, sizeof (uword),
Klement Sekerac5fccc02017-01-18 09:56:00 +01001062 sizeof (bfd_udp_key_t));
Klement Sekera0e3c0de2016-09-29 14:43:44 +02001063 bfd_udp_main.bfd_main = &bfd_main;
1064 udp_register_dst_port (vm, UDP_DST_PORT_bfd4, bfd_udp4_input_node.index, 1);
1065 udp_register_dst_port (vm, UDP_DST_PORT_bfd6, bfd_udp6_input_node.index, 0);
1066 return 0;
1067}
1068
1069VLIB_INIT_FUNCTION (bfd_udp_init);
Klement Sekerac5fccc02017-01-18 09:56:00 +01001070
1071/*
1072 * fd.io coding-style-patch-verification: ON
1073 *
1074 * Local Variables:
1075 * eval: (c-set-style "gnu")
1076 * End:
1077 */