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