blob: 36ecdf1dbc9a9c989e67e461b34ef4b7046dff7d [file] [log] [blame]
Klement Sekera2bce0332017-02-09 06:03:46 +01001/*
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 */
Klement Sekerab16bfe32017-02-28 11:56:48 +010015/**
16 * @file
17 * @brief BFD UDP transport layer implementation
18 */
Klement Sekera0e3c0de2016-09-29 14:43:44 +020019#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>
Florin Corasb040f982020-10-20 14:59:43 -070025#include <vnet/udp/udp_local.h>
Dave Barach68b0fb02017-02-28 15:15:56 -050026#include <vnet/udp/udp_packet.h>
Klement Sekera0e3c0de2016-09-29 14:43:44 +020027#include <vnet/ip/lookup.h>
28#include <vnet/ip/icmp46_packet.h>
29#include <vnet/ip/ip4.h>
30#include <vnet/ip/ip6.h>
Klement Sekera0e3c0de2016-09-29 14:43:44 +020031#include <vnet/ip/ip6_packet.h>
Neale Rannscbe25aa2019-09-30 10:53:31 +000032#include <vnet/ip/ip6_link.h>
Klement Sekera0e3c0de2016-09-29 14:43:44 +020033#include <vnet/adj/adj.h>
34#include <vnet/adj/adj_nbr.h>
Klement Sekera239790f2017-02-16 10:53:53 +010035#include <vnet/dpo/receive_dpo.h>
36#include <vnet/fib/fib_entry.h>
37#include <vnet/fib/fib_table.h>
Damjan Marion8973b072022-03-01 15:51:18 +010038#include <vlib/stats/stats.h>
Klement Sekera0e3c0de2016-09-29 14:43:44 +020039#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>
Neale Ranns5c7e5792022-08-09 00:03:17 +000043#include <vnet/bfd/bfd.api_enum.h>
Klement Sekera0e3c0de2016-09-29 14:43:44 +020044
45typedef struct
46{
47 bfd_main_t *bfd_main;
48 /* hashmap - bfd session index by bfd key - used for CLI/API lookup, where
49 * discriminator is unknown */
50 mhash_t bfd_session_idx_by_bfd_key;
Klement Sekera239790f2017-02-16 10:53:53 +010051 /* convenience variable */
52 vnet_main_t *vnet_main;
53 /* flag indicating whether echo_source_sw_if_index holds a valid value */
54 int echo_source_is_set;
55 /* loopback interface used to get echo source ip */
56 u32 echo_source_sw_if_index;
Klement Sekerae50e8562017-04-04 16:19:48 +020057 /* node index of "ip4-arp" node */
58 u32 ip4_arp_idx;
59 /* node index of "ip6-discover-neighbor" node */
60 u32 ip6_ndp_idx;
61 /* node index of "ip4-rewrite" node */
62 u32 ip4_rewrite_idx;
63 /* node index of "ip6-rewrite" node */
64 u32 ip6_rewrite_idx;
Matthew G Smith2f260142019-05-22 14:49:24 -050065 /* node index of "ip4-midchain" node */
66 u32 ip4_midchain_idx;
67 /* node index of "ip6-midchain" node */
68 u32 ip6_midchain_idx;
Damjan Marion07a38572018-01-21 06:44:18 -080069 /* log class */
70 vlib_log_class_t log_class;
Klement Sekera88aec652019-03-11 14:04:19 +010071 /* number of active udp4 sessions */
72 u32 udp4_sessions_count;
Klement Sekeracdaf0d82022-02-14 20:20:22 +000073 u32 udp4_sessions_count_stat_seg_entry;
Klement Sekera88aec652019-03-11 14:04:19 +010074 /* number of active udp6 sessions */
75 u32 udp6_sessions_count;
Klement Sekeracdaf0d82022-02-14 20:20:22 +000076 u32 udp6_sessions_count_stat_seg_entry;
Klement Sekera0e3c0de2016-09-29 14:43:44 +020077} bfd_udp_main_t;
78
Klement Sekerae4504c62016-12-08 10:16:41 +010079static vlib_node_registration_t bfd_udp4_input_node;
80static vlib_node_registration_t bfd_udp6_input_node;
Klement Sekeraaeeac3b2017-02-14 07:11:52 +010081static vlib_node_registration_t bfd_udp_echo4_input_node;
82static vlib_node_registration_t bfd_udp_echo6_input_node;
Klement Sekerae4504c62016-12-08 10:16:41 +010083
Klement Sekera0e3c0de2016-09-29 14:43:44 +020084bfd_udp_main_t bfd_udp_main;
85
Klement Sekeracdaf0d82022-02-14 20:20:22 +000086void
87bfd_udp_update_stat_segment_entry (u32 entry, u64 value)
88{
Damjan Marion8973b072022-03-01 15:51:18 +010089 vlib_stats_segment_lock ();
90 vlib_stats_set_gauge (entry, value);
91 vlib_stats_segment_unlock ();
Klement Sekeracdaf0d82022-02-14 20:20:22 +000092}
93
Klement Sekera239790f2017-02-16 10:53:53 +010094vnet_api_error_t
95bfd_udp_set_echo_source (u32 sw_if_index)
96{
97 vnet_sw_interface_t *sw_if =
Dave Barach3940de32019-07-23 16:28:36 -040098 vnet_get_sw_interface_or_null (bfd_udp_main.vnet_main, sw_if_index);
Klement Sekera239790f2017-02-16 10:53:53 +010099 if (sw_if)
100 {
101 bfd_udp_main.echo_source_sw_if_index = sw_if_index;
102 bfd_udp_main.echo_source_is_set = 1;
103 return 0;
104 }
105 return VNET_API_ERROR_BFD_ENOENT;
106}
107
108vnet_api_error_t
Klement Sekeracdaf0d82022-02-14 20:20:22 +0000109bfd_udp_del_echo_source ()
Klement Sekera239790f2017-02-16 10:53:53 +0100110{
111 bfd_udp_main.echo_source_sw_if_index = ~0;
112 bfd_udp_main.echo_source_is_set = 0;
113 return 0;
114}
115
116int
117bfd_udp_is_echo_available (bfd_transport_e transport)
118{
119 if (!bfd_udp_main.echo_source_is_set)
120 {
Klement Sekera73884482017-02-23 09:26:30 +0100121 BFD_DBG ("UDP echo source not set - echo not available");
Klement Sekera239790f2017-02-16 10:53:53 +0100122 return 0;
123 }
124 /*
125 * for the echo to work, we need a loopback interface with at least one
126 * address with netmask length at most 31 (ip4) or 127 (ip6) so that we can
127 * pick an unused address from that subnet
128 */
129 vnet_sw_interface_t *sw_if =
Dave Barach3940de32019-07-23 16:28:36 -0400130 vnet_get_sw_interface_or_null (bfd_udp_main.vnet_main,
131 bfd_udp_main.echo_source_sw_if_index);
Klement Sekera239790f2017-02-16 10:53:53 +0100132 if (sw_if && sw_if->flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP)
133 {
134 if (BFD_TRANSPORT_UDP4 == transport)
135 {
136 ip4_main_t *im = &ip4_main;
137 ip_interface_address_t *ia = NULL;
138 /* *INDENT-OFF* */
139 foreach_ip_interface_address (&im->lookup_main, ia,
140 bfd_udp_main.echo_source_sw_if_index,
141 0 /* honor unnumbered */, ({
142 if (ia->address_length <= 31)
143 {
144 return 1;
145 }
146 }));
147 /* *INDENT-ON* */
148 }
149 else if (BFD_TRANSPORT_UDP6 == transport)
150 {
151 ip6_main_t *im = &ip6_main;
152 ip_interface_address_t *ia = NULL;
153 /* *INDENT-OFF* */
154 foreach_ip_interface_address (&im->lookup_main, ia,
155 bfd_udp_main.echo_source_sw_if_index,
156 0 /* honor unnumbered */, ({
157 if (ia->address_length <= 127)
158 {
159 return 1;
160 }
161 }));
162 /* *INDENT-ON* */
163 }
164 }
Klement Sekera73884482017-02-23 09:26:30 +0100165 BFD_DBG ("No usable IP address for UDP echo - echo not available");
Klement Sekera239790f2017-02-16 10:53:53 +0100166 return 0;
167}
168
Klement Sekera2bce0332017-02-09 06:03:46 +0100169static u16
170bfd_udp_bs_idx_to_sport (u32 bs_idx)
171{
172 /* The source port MUST be in the range 49152 through 65535. The same UDP
173 * source port number MUST be used for all BFD Control packets associated
174 * with a particular session. The source port number SHOULD be unique among
175 * all BFD sessions on the system. If more than 16384 BFD sessions are
176 * simultaneously active, UDP source port numbers MAY be reused on
177 * multiple sessions, but the number of distinct uses of the same UDP
178 * source port number SHOULD be minimized.
179 */
180 return 49152 + bs_idx % (65535 - 49152 + 1);
181}
182
Klement Sekera239790f2017-02-16 10:53:53 +0100183int
184bfd_udp_get_echo_src_ip4 (ip4_address_t * addr)
185{
186 if (!bfd_udp_main.echo_source_is_set)
187 {
188 BFD_ERR ("cannot find ip4 address, echo source not set");
189 return 0;
190 }
191 ip_interface_address_t *ia = NULL;
192 ip4_main_t *im = &ip4_main;
193
194 /* *INDENT-OFF* */
195 foreach_ip_interface_address (
196 &im->lookup_main, ia, bfd_udp_main.echo_source_sw_if_index,
197 0 /* honor unnumbered */, ({
198 ip4_address_t *x =
199 ip_interface_address_get_address (&im->lookup_main, ia);
200 if (ia->address_length <= 31)
201 {
202 addr->as_u32 = clib_host_to_net_u32 (x->as_u32);
Klement Sekeraf3bcdbf2017-05-02 07:38:01 +0200203 /*
204 * flip the last bit to get a different address, might be network,
205 * we don't care ...
206 */
207 addr->as_u32 ^= 1;
Klement Sekera239790f2017-02-16 10:53:53 +0100208 addr->as_u32 = clib_net_to_host_u32 (addr->as_u32);
209 return 1;
210 }
211 }));
212 /* *INDENT-ON* */
213 BFD_ERR ("cannot find ip4 address, no usable address found");
214 return 0;
215}
216
217int
218bfd_udp_get_echo_src_ip6 (ip6_address_t * addr)
219{
220 if (!bfd_udp_main.echo_source_is_set)
221 {
222 BFD_ERR ("cannot find ip6 address, echo source not set");
223 return 0;
224 }
225 ip_interface_address_t *ia = NULL;
226 ip6_main_t *im = &ip6_main;
227
228 /* *INDENT-OFF* */
229 foreach_ip_interface_address (
230 &im->lookup_main, ia, bfd_udp_main.echo_source_sw_if_index,
231 0 /* honor unnumbered */, ({
232 ip6_address_t *x =
233 ip_interface_address_get_address (&im->lookup_main, ia);
234 if (ia->address_length <= 127)
235 {
236 *addr = *x;
237 addr->as_u8[15] ^= 1; /* flip the last bit of the address */
Klement Sekera239790f2017-02-16 10:53:53 +0100238 return 1;
239 }
240 }));
241 /* *INDENT-ON* */
242 BFD_ERR ("cannot find ip6 address, no usable address found");
243 return 0;
244}
245
Klement Sekera73884482017-02-23 09:26:30 +0100246void
Klement Sekeraf3bcdbf2017-05-02 07:38:01 +0200247bfd_udp_get_echo_source (int *is_set, u32 * sw_if_index,
248 int *have_usable_ip4, ip4_address_t * ip4,
249 int *have_usable_ip6, ip6_address_t * ip6)
Klement Sekera73884482017-02-23 09:26:30 +0100250{
251 if (bfd_udp_main.echo_source_is_set)
252 {
253 *is_set = 1;
254 *sw_if_index = bfd_udp_main.echo_source_sw_if_index;
255 *have_usable_ip4 = bfd_udp_get_echo_src_ip4 (ip4);
256 *have_usable_ip6 = bfd_udp_get_echo_src_ip6 (ip6);
257 }
258 else
259 {
260 *is_set = 0;
261 }
262}
263
Klement Sekera239790f2017-02-16 10:53:53 +0100264int
Klement Sekeraf3bcdbf2017-05-02 07:38:01 +0200265bfd_add_udp4_transport (vlib_main_t * vm, u32 bi, const bfd_session_t * bs,
266 int is_echo)
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200267{
Klement Sekera2bce0332017-02-09 06:03:46 +0100268 const bfd_udp_session_t *bus = &bs->udp;
Klement Sekera46a87ad2017-01-02 08:22:23 +0100269 const bfd_udp_key_t *key = &bus->key;
Klement Sekerae50e8562017-04-04 16:19:48 +0200270 vlib_buffer_t *b = vlib_get_buffer (vm, bi);
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200271
Damjan Marion213b5aa2017-07-13 21:19:27 +0200272 b->flags |= VNET_BUFFER_F_LOCALLY_ORIGINATED;
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200273 vnet_buffer (b)->ip.adj_index[VLIB_RX] = bus->adj_index;
274 vnet_buffer (b)->ip.adj_index[VLIB_TX] = bus->adj_index;
Klement Sekerae50e8562017-04-04 16:19:48 +0200275 vnet_buffer (b)->sw_if_index[VLIB_RX] = 0;
276 vnet_buffer (b)->sw_if_index[VLIB_TX] = ~0;
Klement Sekera402ed312017-01-18 09:44:36 +0100277 typedef struct
278 {
279 ip4_header_t ip4;
280 udp_header_t udp;
281 } ip4_udp_headers;
Klement Sekerab17dd962017-01-09 07:43:48 +0100282 ip4_udp_headers *headers = NULL;
Klement Sekera402ed312017-01-18 09:44:36 +0100283 vlib_buffer_advance (b, -sizeof (*headers));
284 headers = vlib_buffer_get_current (b);
Dave Barachb7b92992018-10-17 10:38:51 -0400285 clib_memset (headers, 0, sizeof (*headers));
Klement Sekera402ed312017-01-18 09:44:36 +0100286 headers->ip4.ip_version_and_header_length = 0x45;
287 headers->ip4.ttl = 255;
288 headers->ip4.protocol = IP_PROTOCOL_UDP;
Klement Sekera2bce0332017-02-09 06:03:46 +0100289 headers->udp.src_port =
290 clib_host_to_net_u16 (bfd_udp_bs_idx_to_sport (bs->bs_idx));
Klement Sekera239790f2017-02-16 10:53:53 +0100291 if (is_echo)
292 {
293 int rv;
294 if (!(rv = bfd_udp_get_echo_src_ip4 (&headers->ip4.src_address)))
295 {
296 return rv;
297 }
298 headers->ip4.dst_address.as_u32 = key->local_addr.ip4.as_u32;
299 headers->udp.dst_port = clib_host_to_net_u16 (UDP_DST_PORT_bfd_echo4);
300 }
301 else
302 {
303 headers->ip4.src_address.as_u32 = key->local_addr.ip4.as_u32;
304 headers->ip4.dst_address.as_u32 = key->peer_addr.ip4.as_u32;
305 headers->udp.dst_port = clib_host_to_net_u16 (UDP_DST_PORT_bfd4);
306 }
Klement Sekera46a87ad2017-01-02 08:22:23 +0100307
308 /* fix ip length, checksum and udp length */
309 const u16 ip_length = vlib_buffer_length_in_chain (vm, b);
310
Klement Sekera402ed312017-01-18 09:44:36 +0100311 headers->ip4.length = clib_host_to_net_u16 (ip_length);
312 headers->ip4.checksum = ip4_header_checksum (&headers->ip4);
Klement Sekera46a87ad2017-01-02 08:22:23 +0100313
Klement Sekera402ed312017-01-18 09:44:36 +0100314 const u16 udp_length = ip_length - (sizeof (headers->ip4));
315 headers->udp.length = clib_host_to_net_u16 (udp_length);
Klement Sekera239790f2017-02-16 10:53:53 +0100316 return 1;
Klement Sekera46a87ad2017-01-02 08:22:23 +0100317}
318
Klement Sekera239790f2017-02-16 10:53:53 +0100319int
Klement Sekeraf3bcdbf2017-05-02 07:38:01 +0200320bfd_add_udp6_transport (vlib_main_t * vm, u32 bi, const bfd_session_t * bs,
321 int is_echo)
Klement Sekera46a87ad2017-01-02 08:22:23 +0100322{
Klement Sekera2bce0332017-02-09 06:03:46 +0100323 const bfd_udp_session_t *bus = &bs->udp;
Klement Sekera46a87ad2017-01-02 08:22:23 +0100324 const bfd_udp_key_t *key = &bus->key;
Klement Sekerae50e8562017-04-04 16:19:48 +0200325 vlib_buffer_t *b = vlib_get_buffer (vm, bi);
Klement Sekera46a87ad2017-01-02 08:22:23 +0100326
Damjan Marion213b5aa2017-07-13 21:19:27 +0200327 b->flags |= VNET_BUFFER_F_LOCALLY_ORIGINATED;
Klement Sekera46a87ad2017-01-02 08:22:23 +0100328 vnet_buffer (b)->ip.adj_index[VLIB_RX] = bus->adj_index;
329 vnet_buffer (b)->ip.adj_index[VLIB_TX] = bus->adj_index;
Klement Sekerae50e8562017-04-04 16:19:48 +0200330 vnet_buffer (b)->sw_if_index[VLIB_RX] = 0;
331 vnet_buffer (b)->sw_if_index[VLIB_TX] = 0;
Klement Sekera402ed312017-01-18 09:44:36 +0100332 typedef struct
333 {
334 ip6_header_t ip6;
335 udp_header_t udp;
336 } ip6_udp_headers;
Klement Sekerab17dd962017-01-09 07:43:48 +0100337 ip6_udp_headers *headers = NULL;
338 vlib_buffer_advance (b, -sizeof (*headers));
339 headers = vlib_buffer_get_current (b);
Dave Barachb7b92992018-10-17 10:38:51 -0400340 clib_memset (headers, 0, sizeof (*headers));
Klement Sekera402ed312017-01-18 09:44:36 +0100341 headers->ip6.ip_version_traffic_class_and_flow_label =
Klement Sekerac5fccc02017-01-18 09:56:00 +0100342 clib_host_to_net_u32 (0x6 << 28);
Klement Sekera402ed312017-01-18 09:44:36 +0100343 headers->ip6.hop_limit = 255;
344 headers->ip6.protocol = IP_PROTOCOL_UDP;
Klement Sekera2bce0332017-02-09 06:03:46 +0100345 headers->udp.src_port =
346 clib_host_to_net_u16 (bfd_udp_bs_idx_to_sport (bs->bs_idx));
Klement Sekera239790f2017-02-16 10:53:53 +0100347 if (is_echo)
348 {
349 int rv;
350 if (!(rv = bfd_udp_get_echo_src_ip6 (&headers->ip6.src_address)))
351 {
352 return rv;
353 }
Dave Barach178cf492018-11-13 16:34:13 -0500354 clib_memcpy_fast (&headers->ip6.dst_address, &key->local_addr.ip6,
355 sizeof (headers->ip6.dst_address));
Klement Sekera239790f2017-02-16 10:53:53 +0100356
357 headers->udp.dst_port = clib_host_to_net_u16 (UDP_DST_PORT_bfd_echo6);
358 }
359 else
360 {
Dave Barach178cf492018-11-13 16:34:13 -0500361 clib_memcpy_fast (&headers->ip6.src_address, &key->local_addr.ip6,
362 sizeof (headers->ip6.src_address));
363 clib_memcpy_fast (&headers->ip6.dst_address, &key->peer_addr.ip6,
364 sizeof (headers->ip6.dst_address));
Klement Sekera239790f2017-02-16 10:53:53 +0100365 headers->udp.dst_port = clib_host_to_net_u16 (UDP_DST_PORT_bfd6);
366 }
Klement Sekera46a87ad2017-01-02 08:22:23 +0100367
368 /* fix ip payload length and udp length */
Klement Sekerac5fccc02017-01-18 09:56:00 +0100369 const u16 udp_length =
Klement Sekera402ed312017-01-18 09:44:36 +0100370 vlib_buffer_length_in_chain (vm, b) - (sizeof (headers->ip6));
371 headers->udp.length = clib_host_to_net_u16 (udp_length);
372 headers->ip6.payload_length = headers->udp.length;
Klement Sekera46a87ad2017-01-02 08:22:23 +0100373
374 /* IPv6 UDP checksum is mandatory */
375 int bogus = 0;
Klement Sekera402ed312017-01-18 09:44:36 +0100376 headers->udp.checksum =
377 ip6_tcp_udp_icmp_compute_checksum (vm, b, &headers->ip6, &bogus);
Klement Sekera46a87ad2017-01-02 08:22:23 +0100378 ASSERT (bogus == 0);
Klement Sekera402ed312017-01-18 09:44:36 +0100379 if (headers->udp.checksum == 0)
Klement Sekera46a87ad2017-01-02 08:22:23 +0100380 {
Klement Sekera402ed312017-01-18 09:44:36 +0100381 headers->udp.checksum = 0xffff;
Klement Sekera46a87ad2017-01-02 08:22:23 +0100382 }
Klement Sekera239790f2017-02-16 10:53:53 +0100383 return 1;
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200384}
385
Klement Sekerae50e8562017-04-04 16:19:48 +0200386static void
Klement Sekeracdaf0d82022-02-14 20:20:22 +0000387bfd_create_frame_to_next_node (vlib_main_t *vm, bfd_main_t *bm,
388 const bfd_session_t *bs, u32 bi, u32 next_node,
389 vlib_combined_counter_main_t *tx_counter)
Klement Sekerae50e8562017-04-04 16:19:48 +0200390{
391 vlib_frame_t *f = vlib_get_frame_to_node (vm, next_node);
392 u32 *to_next = vlib_frame_vector_args (f);
393 to_next[0] = bi;
394 f->n_vectors = 1;
395 vlib_put_frame_to_node (vm, next_node, f);
Klement Sekeracdaf0d82022-02-14 20:20:22 +0000396 vlib_buffer_t *b = vlib_get_buffer (vm, bi);
397 vlib_increment_combined_counter (tx_counter, vm->thread_index, bs->bs_idx, 1,
398 vlib_buffer_length_in_chain (vm, b));
Klement Sekerae50e8562017-04-04 16:19:48 +0200399}
400
401int
402bfd_udp_calc_next_node (const struct bfd_session_s *bs, u32 * next_node)
403{
Matthew G Smith2f260142019-05-22 14:49:24 -0500404 vnet_main_t *vnm = vnet_get_main ();
Klement Sekerae50e8562017-04-04 16:19:48 +0200405 const bfd_udp_session_t *bus = &bs->udp;
406 ip_adjacency_t *adj = adj_get (bus->adj_index);
Matthew G Smith2f260142019-05-22 14:49:24 -0500407
408 /* don't try to send the buffer if the interface is not up */
409 if (!vnet_sw_interface_is_up (vnm, bus->key.sw_if_index))
410 return 0;
411
Klement Sekerae50e8562017-04-04 16:19:48 +0200412 switch (adj->lookup_next_index)
413 {
414 case IP_LOOKUP_NEXT_ARP:
415 switch (bs->transport)
416 {
417 case BFD_TRANSPORT_UDP4:
418 *next_node = bfd_udp_main.ip4_arp_idx;
419 return 1;
420 case BFD_TRANSPORT_UDP6:
421 *next_node = bfd_udp_main.ip6_ndp_idx;
422 return 1;
423 }
424 break;
425 case IP_LOOKUP_NEXT_REWRITE:
426 switch (bs->transport)
427 {
428 case BFD_TRANSPORT_UDP4:
429 *next_node = bfd_udp_main.ip4_rewrite_idx;
430 return 1;
431 case BFD_TRANSPORT_UDP6:
432 *next_node = bfd_udp_main.ip6_rewrite_idx;
433 return 1;
434 }
435 break;
Matthew G Smith2f260142019-05-22 14:49:24 -0500436 case IP_LOOKUP_NEXT_MIDCHAIN:
437 switch (bs->transport)
438 {
439 case BFD_TRANSPORT_UDP4:
440 *next_node = bfd_udp_main.ip4_midchain_idx;
441 return 1;
442 case BFD_TRANSPORT_UDP6:
443 *next_node = bfd_udp_main.ip6_midchain_idx;
444 return 1;
445 }
446 break;
Klement Sekerae50e8562017-04-04 16:19:48 +0200447 default:
448 /* drop */
449 break;
450 }
451 return 0;
452}
453
454int
Klement Sekeracdaf0d82022-02-14 20:20:22 +0000455bfd_transport_udp4 (vlib_main_t *vm, u32 bi, const struct bfd_session_s *bs,
456 int is_echo)
Klement Sekerae50e8562017-04-04 16:19:48 +0200457{
458 u32 next_node;
459 int rv = bfd_udp_calc_next_node (bs, &next_node);
Klement Sekeracdaf0d82022-02-14 20:20:22 +0000460 bfd_main_t *bm = bfd_udp_main.bfd_main;
Klement Sekerae50e8562017-04-04 16:19:48 +0200461 if (rv)
462 {
Klement Sekeracdaf0d82022-02-14 20:20:22 +0000463 bfd_create_frame_to_next_node (vm, bm, bs, bi, next_node,
464 is_echo ? &bm->tx_echo_counter :
465 &bm->tx_counter);
Klement Sekerae50e8562017-04-04 16:19:48 +0200466 }
467 return rv;
468}
469
470int
Klement Sekeracdaf0d82022-02-14 20:20:22 +0000471bfd_transport_udp6 (vlib_main_t *vm, u32 bi, const struct bfd_session_s *bs,
472 int is_echo)
Klement Sekerae50e8562017-04-04 16:19:48 +0200473{
474 u32 next_node;
475 int rv = bfd_udp_calc_next_node (bs, &next_node);
Klement Sekeracdaf0d82022-02-14 20:20:22 +0000476 bfd_main_t *bm = bfd_udp_main.bfd_main;
Klement Sekerae50e8562017-04-04 16:19:48 +0200477 if (rv)
478 {
Klement Sekeracdaf0d82022-02-14 20:20:22 +0000479 bfd_create_frame_to_next_node (
480 vm, bfd_udp_main.bfd_main, bs, bi, next_node,
481 is_echo ? &bm->tx_echo_counter : &bm->tx_counter);
Klement Sekerae50e8562017-04-04 16:19:48 +0200482 }
483 return 1;
484}
485
Klement Sekerac5fccc02017-01-18 09:56:00 +0100486static bfd_session_t *
487bfd_lookup_session (bfd_udp_main_t * bum, const bfd_udp_key_t * key)
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200488{
489 uword *p = mhash_get (&bum->bfd_session_idx_by_bfd_key, key);
490 if (p)
491 {
492 return bfd_find_session_by_idx (bum->bfd_main, *p);
493 }
494 return 0;
495}
496
Klement Sekerab17dd962017-01-09 07:43:48 +0100497static void
498bfd_udp_key_init (bfd_udp_key_t * key, u32 sw_if_index,
499 const ip46_address_t * local_addr,
500 const ip46_address_t * peer_addr)
501{
Dave Barachb7b92992018-10-17 10:38:51 -0400502 clib_memset (key, 0, sizeof (*key));
Klement Sekerab17dd962017-01-09 07:43:48 +0100503 key->sw_if_index = sw_if_index;
504 key->local_addr.as_u64[0] = local_addr->as_u64[0];
505 key->local_addr.as_u64[1] = local_addr->as_u64[1];
506 key->peer_addr.as_u64[0] = peer_addr->as_u64[0];
507 key->peer_addr.as_u64[1] = peer_addr->as_u64[1];
508}
509
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200510static vnet_api_error_t
Klement Sekera88aec652019-03-11 14:04:19 +0100511bfd_udp_add_session_internal (vlib_main_t * vm, bfd_udp_main_t * bum,
512 u32 sw_if_index, u32 desired_min_tx_usec,
Klement Sekeraa57a9702017-02-02 06:58:07 +0100513 u32 required_min_rx_usec, u8 detect_mult,
Klement Sekerac5fccc02017-01-18 09:56:00 +0100514 const ip46_address_t * local_addr,
515 const ip46_address_t * peer_addr,
Klement Sekerab17dd962017-01-09 07:43:48 +0100516 bfd_session_t ** bs_out)
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200517{
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200518 /* get a pool entry and if we end up not needing it, give it back */
Klement Sekera239790f2017-02-16 10:53:53 +0100519 bfd_transport_e t = BFD_TRANSPORT_UDP4;
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200520 if (!ip46_address_is_ip4 (local_addr))
521 {
522 t = BFD_TRANSPORT_UDP6;
523 }
524 bfd_session_t *bs = bfd_get_session (bum->bfd_main, t);
Klement Sekera239790f2017-02-16 10:53:53 +0100525 if (!bs)
526 {
Klement Sekera239790f2017-02-16 10:53:53 +0100527 return VNET_API_ERROR_BFD_EAGAIN;
528 }
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200529 bfd_udp_session_t *bus = &bs->udp;
Dave Barachb7b92992018-10-17 10:38:51 -0400530 clib_memset (bus, 0, sizeof (*bus));
Neale Ranns32fd89b2022-02-15 08:28:19 +0000531 bus->adj_index = ADJ_INDEX_INVALID;
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200532 bfd_udp_key_t *key = &bus->key;
Klement Sekerab17dd962017-01-09 07:43:48 +0100533 bfd_udp_key_init (key, sw_if_index, local_addr, peer_addr);
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200534 const bfd_session_t *tmp = bfd_lookup_session (bum, key);
535 if (tmp)
536 {
Damjan Marion07a38572018-01-21 06:44:18 -0800537 vlib_log_err (bum->log_class,
538 "duplicate bfd-udp session, existing bs_idx=%d",
Klement Sekerab17dd962017-01-09 07:43:48 +0100539 tmp->bs_idx);
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200540 bfd_put_session (bum->bfd_main, bs);
541 return VNET_API_ERROR_BFD_EEXIST;
542 }
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200543 mhash_set (&bum->bfd_session_idx_by_bfd_key, key, bs->bs_idx, NULL);
544 BFD_DBG ("session created, bs_idx=%u, sw_if_index=%d, local=%U, peer=%U",
Klement Sekerac5fccc02017-01-18 09:56:00 +0100545 bs->bs_idx, key->sw_if_index, format_ip46_address,
546 &key->local_addr, IP46_TYPE_ANY, format_ip46_address,
547 &key->peer_addr, IP46_TYPE_ANY);
Damjan Marion07a38572018-01-21 06:44:18 -0800548 vlib_log_info (bum->log_class, "create BFD session: %U",
549 format_bfd_session, bs);
Neale Ranns558a3542022-02-15 08:24:48 +0000550 const ip46_address_t *peer =
551 (vnet_sw_interface_is_p2p (vnet_get_main (), key->sw_if_index) ?
552 &zero_addr :
553 &key->peer_addr);
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200554 if (BFD_TRANSPORT_UDP4 == t)
555 {
556 bus->adj_index = adj_nbr_add_or_lock (FIB_PROTOCOL_IP4, VNET_LINK_IP4,
Neale Ranns558a3542022-02-15 08:24:48 +0000557 peer, key->sw_if_index);
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200558 BFD_DBG ("adj_nbr_add_or_lock(FIB_PROTOCOL_IP4, VNET_LINK_IP4, %U, %d) "
Neale Ranns558a3542022-02-15 08:24:48 +0000559 "returns %d",
560 format_ip46_address, peer, IP46_TYPE_ANY, key->sw_if_index,
561 bus->adj_index);
Klement Sekera88aec652019-03-11 14:04:19 +0100562 ++bum->udp4_sessions_count;
Klement Sekeracdaf0d82022-02-14 20:20:22 +0000563 bfd_udp_update_stat_segment_entry (
564 bum->udp4_sessions_count_stat_seg_entry, bum->udp4_sessions_count);
Klement Sekera88aec652019-03-11 14:04:19 +0100565 if (1 == bum->udp4_sessions_count)
566 {
567 udp_register_dst_port (vm, UDP_DST_PORT_bfd4,
568 bfd_udp4_input_node.index, 1);
569 udp_register_dst_port (vm, UDP_DST_PORT_bfd_echo4,
570 bfd_udp_echo4_input_node.index, 1);
571 }
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200572 }
573 else
574 {
575 bus->adj_index = adj_nbr_add_or_lock (FIB_PROTOCOL_IP6, VNET_LINK_IP6,
Neale Ranns558a3542022-02-15 08:24:48 +0000576 peer, key->sw_if_index);
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200577 BFD_DBG ("adj_nbr_add_or_lock(FIB_PROTOCOL_IP6, VNET_LINK_IP6, %U, %d) "
Neale Ranns558a3542022-02-15 08:24:48 +0000578 "returns %d",
579 format_ip46_address, peer, IP46_TYPE_ANY, key->sw_if_index,
580 bus->adj_index);
Klement Sekera88aec652019-03-11 14:04:19 +0100581 ++bum->udp6_sessions_count;
Klement Sekeracdaf0d82022-02-14 20:20:22 +0000582 bfd_udp_update_stat_segment_entry (
583 bum->udp6_sessions_count_stat_seg_entry, bum->udp6_sessions_count);
Klement Sekera88aec652019-03-11 14:04:19 +0100584 if (1 == bum->udp6_sessions_count)
585 {
586 udp_register_dst_port (vm, UDP_DST_PORT_bfd6,
587 bfd_udp6_input_node.index, 0);
588 udp_register_dst_port (vm, UDP_DST_PORT_bfd_echo6,
589 bfd_udp_echo6_input_node.index, 0);
590 }
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200591 }
Klement Sekerab17dd962017-01-09 07:43:48 +0100592 *bs_out = bs;
Klement Sekeraa57a9702017-02-02 06:58:07 +0100593 return bfd_session_set_params (bum->bfd_main, bs, desired_min_tx_usec,
594 required_min_rx_usec, detect_mult);
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200595}
596
597static vnet_api_error_t
Klement Sekerac5fccc02017-01-18 09:56:00 +0100598bfd_udp_validate_api_input (u32 sw_if_index,
599 const ip46_address_t * local_addr,
600 const ip46_address_t * peer_addr)
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200601{
Damjan Marion07a38572018-01-21 06:44:18 -0800602 bfd_udp_main_t *bum = &bfd_udp_main;
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200603 vnet_sw_interface_t *sw_if =
Dave Barach3940de32019-07-23 16:28:36 -0400604 vnet_get_sw_interface_or_null (bfd_udp_main.vnet_main, sw_if_index);
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200605 if (!sw_if)
606 {
Damjan Marion07a38572018-01-21 06:44:18 -0800607 vlib_log_err (bum->log_class,
608 "got NULL sw_if when getting interface by index %u",
609 sw_if_index);
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200610 return VNET_API_ERROR_INVALID_SW_IF_INDEX;
611 }
612 if (ip46_address_is_ip4 (local_addr))
613 {
614 if (!ip46_address_is_ip4 (peer_addr))
Klement Sekerac5fccc02017-01-18 09:56:00 +0100615 {
Damjan Marion07a38572018-01-21 06:44:18 -0800616 vlib_log_err (bum->log_class,
617 "IP family mismatch (local is ipv4, peer is ipv6)");
Klement Sekerac5fccc02017-01-18 09:56:00 +0100618 return VNET_API_ERROR_INVALID_ARGUMENT;
619 }
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200620 }
621 else
622 {
623 if (ip46_address_is_ip4 (peer_addr))
Klement Sekerac5fccc02017-01-18 09:56:00 +0100624 {
Damjan Marion07a38572018-01-21 06:44:18 -0800625 vlib_log_err (bum->log_class,
626 "IP family mismatch (local is ipv6, peer is ipv4)");
Klement Sekerac5fccc02017-01-18 09:56:00 +0100627 return VNET_API_ERROR_INVALID_ARGUMENT;
628 }
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200629 }
630
631 return 0;
632}
633
Klement Sekerab17dd962017-01-09 07:43:48 +0100634static vnet_api_error_t
635bfd_udp_find_session_by_api_input (u32 sw_if_index,
636 const ip46_address_t * local_addr,
637 const ip46_address_t * peer_addr,
638 bfd_session_t ** bs_out)
639{
640 vnet_api_error_t rv =
641 bfd_udp_validate_api_input (sw_if_index, local_addr, peer_addr);
642 if (!rv)
643 {
644 bfd_udp_main_t *bum = &bfd_udp_main;
645 bfd_udp_key_t key;
646 bfd_udp_key_init (&key, sw_if_index, local_addr, peer_addr);
647 bfd_session_t *bs = bfd_lookup_session (bum, &key);
648 if (bs)
649 {
650 *bs_out = bs;
651 }
652 else
653 {
Damjan Marion07a38572018-01-21 06:44:18 -0800654 vlib_log_err (bum->log_class,
655 "BFD session not found, sw_if_index=%u, local=%U, peer=%U",
656 sw_if_index, format_ip46_address, local_addr,
657 IP46_TYPE_ANY, format_ip46_address, peer_addr,
658 IP46_TYPE_ANY);
Klement Sekerab17dd962017-01-09 07:43:48 +0100659 return VNET_API_ERROR_BFD_ENOENT;
660 }
661 }
662 return rv;
663}
664
665static vnet_api_error_t
Klement Sekeraa57a9702017-02-02 06:58:07 +0100666bfd_api_verify_common (u32 sw_if_index, u32 desired_min_tx_usec,
Klement Sekerab59f63b2022-02-14 20:19:28 +0000667 u8 detect_mult, const ip46_address_t *local_addr,
668 const ip46_address_t *peer_addr)
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200669{
Damjan Marion07a38572018-01-21 06:44:18 -0800670 bfd_udp_main_t *bum = &bfd_udp_main;
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200671 vnet_api_error_t rv =
Klement Sekerac5fccc02017-01-18 09:56:00 +0100672 bfd_udp_validate_api_input (sw_if_index, local_addr, peer_addr);
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200673 if (rv)
674 {
675 return rv;
676 }
677 if (detect_mult < 1)
678 {
Damjan Marion07a38572018-01-21 06:44:18 -0800679 vlib_log_err (bum->log_class, "detect_mult < 1");
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200680 return VNET_API_ERROR_INVALID_ARGUMENT;
681 }
Klement Sekeraa57a9702017-02-02 06:58:07 +0100682 if (desired_min_tx_usec < 1)
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200683 {
Damjan Marion07a38572018-01-21 06:44:18 -0800684 vlib_log_err (bum->log_class, "desired_min_tx_usec < 1");
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200685 return VNET_API_ERROR_INVALID_ARGUMENT;
686 }
Klement Sekerab17dd962017-01-09 07:43:48 +0100687 return 0;
688}
689
690static void
Klement Sekera88aec652019-03-11 14:04:19 +0100691bfd_udp_del_session_internal (vlib_main_t * vm, bfd_session_t * bs)
Klement Sekerab17dd962017-01-09 07:43:48 +0100692{
693 bfd_udp_main_t *bum = &bfd_udp_main;
694 BFD_DBG ("free bfd-udp session, bs_idx=%d", bs->bs_idx);
Neale Ranns32fd89b2022-02-15 08:28:19 +0000695 bfd_session_stop (bum->bfd_main, bs);
Klement Sekerab17dd962017-01-09 07:43:48 +0100696 mhash_unset (&bum->bfd_session_idx_by_bfd_key, &bs->udp.key, NULL);
697 adj_unlock (bs->udp.adj_index);
Klement Sekera88aec652019-03-11 14:04:19 +0100698 switch (bs->transport)
699 {
700 case BFD_TRANSPORT_UDP4:
701 --bum->udp4_sessions_count;
Klement Sekeracdaf0d82022-02-14 20:20:22 +0000702 bfd_udp_update_stat_segment_entry (
703 bum->udp4_sessions_count_stat_seg_entry, bum->udp4_sessions_count);
Klement Sekera88aec652019-03-11 14:04:19 +0100704 if (!bum->udp4_sessions_count)
705 {
706 udp_unregister_dst_port (vm, UDP_DST_PORT_bfd4, 1);
707 udp_unregister_dst_port (vm, UDP_DST_PORT_bfd_echo4, 1);
708 }
709 break;
710 case BFD_TRANSPORT_UDP6:
711 --bum->udp6_sessions_count;
Klement Sekeracdaf0d82022-02-14 20:20:22 +0000712 bfd_udp_update_stat_segment_entry (
713 bum->udp6_sessions_count_stat_seg_entry, bum->udp6_sessions_count);
Klement Sekera88aec652019-03-11 14:04:19 +0100714 if (!bum->udp6_sessions_count)
715 {
716 udp_unregister_dst_port (vm, UDP_DST_PORT_bfd6, 0);
717 udp_unregister_dst_port (vm, UDP_DST_PORT_bfd_echo6, 0);
718 }
719 break;
720 }
Klement Sekerab17dd962017-01-09 07:43:48 +0100721 bfd_put_session (bum->bfd_main, bs);
722}
723
Neale Ranns63f2c7d2022-02-09 13:47:29 +0000724static vnet_api_error_t
725bfd_udp_add_and_start_session (u32 sw_if_index,
726 const ip46_address_t *local_addr,
727 const ip46_address_t *peer_addr,
728 u32 desired_min_tx_usec,
729 u32 required_min_rx_usec, u8 detect_mult,
730 u8 is_authenticated, u32 conf_key_id,
731 u8 bfd_key_id)
732{
733 bfd_session_t *bs = NULL;
734 vnet_api_error_t rv;
735
736 rv = bfd_udp_add_session_internal (
737 vlib_get_main (), &bfd_udp_main, sw_if_index, desired_min_tx_usec,
738 required_min_rx_usec, detect_mult, local_addr, peer_addr, &bs);
739
740 if (!rv && is_authenticated)
741 {
742 rv = bfd_auth_activate (bs, conf_key_id, bfd_key_id,
743 0 /* is not delayed */);
744 if (rv)
745 {
746 bfd_udp_del_session_internal (vlib_get_main (), bs);
747 }
748 }
749 if (!rv)
750 {
751 bfd_session_start (bfd_udp_main.bfd_main, bs);
752 }
753
754 return rv;
755}
756
Klement Sekerab17dd962017-01-09 07:43:48 +0100757vnet_api_error_t
758bfd_udp_add_session (u32 sw_if_index, const ip46_address_t * local_addr,
Klement Sekeraa57a9702017-02-02 06:58:07 +0100759 const ip46_address_t * peer_addr,
760 u32 desired_min_tx_usec, u32 required_min_rx_usec,
761 u8 detect_mult, u8 is_authenticated, u32 conf_key_id,
762 u8 bfd_key_id)
Klement Sekerab17dd962017-01-09 07:43:48 +0100763{
Dave Barach1e3417f2018-07-25 08:30:27 -0400764 bfd_main_t *bm = &bfd_main;
765 bfd_lock (bm);
766
Klement Sekerab59f63b2022-02-14 20:19:28 +0000767 vnet_api_error_t rv = bfd_api_verify_common (
768 sw_if_index, desired_min_tx_usec, detect_mult, local_addr, peer_addr);
Neale Ranns63f2c7d2022-02-09 13:47:29 +0000769
770 if (!rv)
771 rv = bfd_udp_add_and_start_session (
772 sw_if_index, local_addr, peer_addr, desired_min_tx_usec,
773 required_min_rx_usec, detect_mult, is_authenticated, conf_key_id,
774 bfd_key_id);
775
776 bfd_unlock (bm);
777 return rv;
778}
779
780vnet_api_error_t
781bfd_udp_upd_session (u32 sw_if_index, const ip46_address_t *local_addr,
782 const ip46_address_t *peer_addr, u32 desired_min_tx_usec,
783 u32 required_min_rx_usec, u8 detect_mult,
784 u8 is_authenticated, u32 conf_key_id, u8 bfd_key_id)
785{
786 bfd_main_t *bm = &bfd_main;
787 bfd_lock (bm);
788
789 vnet_api_error_t rv = bfd_api_verify_common (
Klement Sekerab59f63b2022-02-14 20:19:28 +0000790 sw_if_index, desired_min_tx_usec, detect_mult, local_addr, peer_addr);
Klement Sekerab17dd962017-01-09 07:43:48 +0100791 if (!rv)
792 {
Neale Ranns63f2c7d2022-02-09 13:47:29 +0000793 bfd_session_t *bs = NULL;
794
795 rv = bfd_udp_find_session_by_api_input (sw_if_index, local_addr,
796 peer_addr, &bs);
797 if (VNET_API_ERROR_BFD_ENOENT == rv)
798 rv = bfd_udp_add_and_start_session (
799 sw_if_index, local_addr, peer_addr, desired_min_tx_usec,
800 required_min_rx_usec, detect_mult, is_authenticated, conf_key_id,
801 bfd_key_id);
802 else
803 rv = bfd_session_set_params (bfd_udp_main.bfd_main, bs,
804 desired_min_tx_usec, required_min_rx_usec,
805 detect_mult);
Klement Sekerab17dd962017-01-09 07:43:48 +0100806 }
807
Dave Barach1e3417f2018-07-25 08:30:27 -0400808 bfd_unlock (bm);
Klement Sekerab17dd962017-01-09 07:43:48 +0100809 return rv;
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200810}
811
Klement Sekerac5fccc02017-01-18 09:56:00 +0100812vnet_api_error_t
Neale Ranns63f2c7d2022-02-09 13:47:29 +0000813bfd_udp_mod_session (u32 sw_if_index, const ip46_address_t *local_addr,
814 const ip46_address_t *peer_addr, u32 desired_min_tx_usec,
Klement Sekeraa57a9702017-02-02 06:58:07 +0100815 u32 required_min_rx_usec, u8 detect_mult)
816{
817 bfd_session_t *bs = NULL;
Dave Barach1e3417f2018-07-25 08:30:27 -0400818 bfd_main_t *bm = &bfd_main;
819 vnet_api_error_t error;
820 bfd_lock (bm);
Klement Sekeraa57a9702017-02-02 06:58:07 +0100821 vnet_api_error_t rv =
822 bfd_udp_find_session_by_api_input (sw_if_index, local_addr, peer_addr,
823 &bs);
824 if (rv)
825 {
Dave Barach1e3417f2018-07-25 08:30:27 -0400826 bfd_unlock (bm);
Klement Sekeraa57a9702017-02-02 06:58:07 +0100827 return rv;
828 }
829
Dave Barach1e3417f2018-07-25 08:30:27 -0400830 error = bfd_session_set_params (bfd_udp_main.bfd_main, bs,
831 desired_min_tx_usec, required_min_rx_usec,
832 detect_mult);
833 bfd_unlock (bm);
834 return error;
Klement Sekeraa57a9702017-02-02 06:58:07 +0100835}
836
837vnet_api_error_t
Klement Sekerac5fccc02017-01-18 09:56:00 +0100838bfd_udp_del_session (u32 sw_if_index,
839 const ip46_address_t * local_addr,
840 const ip46_address_t * peer_addr)
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200841{
Klement Sekerab17dd962017-01-09 07:43:48 +0100842 bfd_session_t *bs = NULL;
Dave Barach1e3417f2018-07-25 08:30:27 -0400843 bfd_main_t *bm = &bfd_main;
844 bfd_lock (bm);
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200845 vnet_api_error_t rv =
Klement Sekerab17dd962017-01-09 07:43:48 +0100846 bfd_udp_find_session_by_api_input (sw_if_index, local_addr, peer_addr,
847 &bs);
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200848 if (rv)
849 {
Dave Barach1e3417f2018-07-25 08:30:27 -0400850 bfd_unlock (bm);
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200851 return rv;
852 }
Klement Sekera88aec652019-03-11 14:04:19 +0100853 bfd_udp_del_session_internal (vlib_get_main (), bs);
Dave Barach1e3417f2018-07-25 08:30:27 -0400854 bfd_unlock (bm);
Klement Sekerab17dd962017-01-09 07:43:48 +0100855 return 0;
856}
857
858vnet_api_error_t
Klement Sekeraa3167442020-02-10 11:49:52 +0000859bfd_udp_session_set_flags (vlib_main_t * vm, u32 sw_if_index,
Klement Sekerab17dd962017-01-09 07:43:48 +0100860 const ip46_address_t * local_addr,
861 const ip46_address_t * peer_addr, u8 admin_up_down)
862{
863 bfd_session_t *bs = NULL;
Dave Barach1e3417f2018-07-25 08:30:27 -0400864 bfd_main_t *bm = &bfd_main;
865 bfd_lock (bm);
Klement Sekerab17dd962017-01-09 07:43:48 +0100866 vnet_api_error_t rv =
867 bfd_udp_find_session_by_api_input (sw_if_index, local_addr, peer_addr,
868 &bs);
869 if (rv)
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200870 {
Dave Barach1e3417f2018-07-25 08:30:27 -0400871 bfd_unlock (bm);
Klement Sekerab17dd962017-01-09 07:43:48 +0100872 return rv;
873 }
Klement Sekeraa3167442020-02-10 11:49:52 +0000874 bfd_session_set_flags (vm, bs, admin_up_down);
Dave Barach1e3417f2018-07-25 08:30:27 -0400875 bfd_unlock (bm);
Klement Sekerab17dd962017-01-09 07:43:48 +0100876 return 0;
877}
878
879vnet_api_error_t
Klement Sekerab17dd962017-01-09 07:43:48 +0100880bfd_udp_auth_activate (u32 sw_if_index,
881 const ip46_address_t * local_addr,
882 const ip46_address_t * peer_addr,
883 u32 conf_key_id, u8 key_id, u8 is_delayed)
884{
Dave Barach1e3417f2018-07-25 08:30:27 -0400885 bfd_main_t *bm = &bfd_main;
886 bfd_lock (bm);
887 vnet_api_error_t error;
888
Klement Sekerab17dd962017-01-09 07:43:48 +0100889 bfd_session_t *bs = NULL;
890 vnet_api_error_t rv =
891 bfd_udp_find_session_by_api_input (sw_if_index, local_addr, peer_addr,
892 &bs);
893 if (rv)
894 {
Dave Barach1e3417f2018-07-25 08:30:27 -0400895 bfd_unlock (bm);
Klement Sekerab17dd962017-01-09 07:43:48 +0100896 return rv;
897 }
Dave Barach1e3417f2018-07-25 08:30:27 -0400898 error = bfd_auth_activate (bs, conf_key_id, key_id, is_delayed);
899 bfd_unlock (bm);
900 return error;
Klement Sekerab17dd962017-01-09 07:43:48 +0100901}
902
903vnet_api_error_t
904bfd_udp_auth_deactivate (u32 sw_if_index,
905 const ip46_address_t * local_addr,
906 const ip46_address_t * peer_addr, u8 is_delayed)
907{
Dave Barach1e3417f2018-07-25 08:30:27 -0400908 bfd_main_t *bm = &bfd_main;
909 vnet_api_error_t error;
910 bfd_lock (bm);
Klement Sekerab17dd962017-01-09 07:43:48 +0100911 bfd_session_t *bs = NULL;
912 vnet_api_error_t rv =
913 bfd_udp_find_session_by_api_input (sw_if_index, local_addr, peer_addr,
914 &bs);
915 if (rv)
916 {
Dave Barach1e3417f2018-07-25 08:30:27 -0400917 bfd_unlock (bm);
Klement Sekerab17dd962017-01-09 07:43:48 +0100918 return rv;
919 }
Dave Barach1e3417f2018-07-25 08:30:27 -0400920 error = bfd_auth_deactivate (bs, is_delayed);
921 bfd_unlock (bm);
922 return error;
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200923}
924
Klement Sekerac5fccc02017-01-18 09:56:00 +0100925typedef enum
926{
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200927 BFD_UDP_INPUT_NEXT_NORMAL,
Klement Sekerae50e8562017-04-04 16:19:48 +0200928 BFD_UDP_INPUT_NEXT_REPLY_ARP,
929 BFD_UDP_INPUT_NEXT_REPLY_REWRITE,
Matthew G Smith2f260142019-05-22 14:49:24 -0500930 BFD_UDP_INPUT_NEXT_REPLY_MIDCHAIN,
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200931 BFD_UDP_INPUT_N_NEXT,
932} bfd_udp_input_next_t;
933
Matthew G Smith2f260142019-05-22 14:49:24 -0500934typedef enum
935{
936 BFD_UDP_ECHO_INPUT_NEXT_NORMAL,
937 BFD_UDP_ECHO_INPUT_NEXT_REPLY_ARP,
938 BFD_UDP_ECHO_INPUT_NEXT_REPLY_REWRITE,
939 BFD_UDP_ECHO_INPUT_N_NEXT,
940} bfd_udp_echo_input_next_t;
941
Neale Ranns5c7e5792022-08-09 00:03:17 +0000942static_always_inline vl_counter_bfd_udp_enum_t
Neale Ranns0c50dbb2022-08-05 03:40:43 +0000943bfd_error_to_udp (bfd_error_t e)
944{
945 /* The UDP error is a super set of the proto independent errors */
Neale Ranns5c7e5792022-08-09 00:03:17 +0000946 return ((vl_counter_bfd_udp_enum_t) e);
Neale Ranns0c50dbb2022-08-05 03:40:43 +0000947}
948
Klement Sekerac5fccc02017-01-18 09:56:00 +0100949static void
Klement Sekeraaeeac3b2017-02-14 07:11:52 +0100950bfd_udp4_find_headers (vlib_buffer_t * b, ip4_header_t ** ip4,
951 udp_header_t ** udp)
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200952{
Klement Sekera0c1519b2016-12-08 05:03:32 +0100953 /* sanity check first */
Damjan Marion072401e2017-07-13 18:53:27 +0200954 const i32 start = vnet_buffer (b)->l3_hdr_offset;
Klement Sekerab59f63b2022-02-14 20:19:28 +0000955 if (start < -(signed) sizeof (b->pre_data))
Klement Sekera0c1519b2016-12-08 05:03:32 +0100956 {
957 BFD_ERR ("Start of ip header is before pre_data, ignoring");
958 *ip4 = NULL;
959 *udp = NULL;
960 return;
961 }
Klement Sekerac5fccc02017-01-18 09:56:00 +0100962 *ip4 = (ip4_header_t *) (b->data + start);
963 if ((u8 *) * ip4 > (u8 *) vlib_buffer_get_current (b))
Klement Sekera0c1519b2016-12-08 05:03:32 +0100964 {
965 BFD_ERR ("Start of ip header is beyond current data, ignoring");
966 *ip4 = NULL;
967 *udp = NULL;
968 return;
969 }
Klement Sekerac5fccc02017-01-18 09:56:00 +0100970 *udp = (udp_header_t *) ((*ip4) + 1);
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200971}
972
Neale Ranns5c7e5792022-08-09 00:03:17 +0000973static vl_counter_bfd_udp_enum_t
974bfd_udp4_verify_transport (const ip4_header_t *ip4, const udp_header_t *udp,
975 const bfd_session_t *bs)
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200976{
977 const bfd_udp_session_t *bus = &bs->udp;
978 const bfd_udp_key_t *key = &bus->key;
979 if (ip4->src_address.as_u32 != key->peer_addr.ip4.as_u32)
980 {
Klement Sekera46a87ad2017-01-02 08:22:23 +0100981 BFD_ERR ("IPv4 src addr mismatch, got %U, expected %U",
Klement Sekerac5fccc02017-01-18 09:56:00 +0100982 format_ip4_address, ip4->src_address.as_u8, format_ip4_address,
983 key->peer_addr.ip4.as_u8);
Neale Ranns0c50dbb2022-08-05 03:40:43 +0000984 return BFD_UDP_ERROR_SRC_MISMATCH;
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200985 }
986 if (ip4->dst_address.as_u32 != key->local_addr.ip4.as_u32)
987 {
Klement Sekera46a87ad2017-01-02 08:22:23 +0100988 BFD_ERR ("IPv4 dst addr mismatch, got %U, expected %U",
Klement Sekerac5fccc02017-01-18 09:56:00 +0100989 format_ip4_address, ip4->dst_address.as_u8, format_ip4_address,
990 key->local_addr.ip4.as_u8);
Neale Ranns0c50dbb2022-08-05 03:40:43 +0000991 return BFD_UDP_ERROR_DST_MISMATCH;
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200992 }
993 const u8 expected_ttl = 255;
994 if (ip4->ttl != expected_ttl)
995 {
Klement Sekera46a87ad2017-01-02 08:22:23 +0100996 BFD_ERR ("IPv4 unexpected TTL value %u, expected %u", ip4->ttl,
Klement Sekerac5fccc02017-01-18 09:56:00 +0100997 expected_ttl);
Neale Ranns0c50dbb2022-08-05 03:40:43 +0000998 return BFD_UDP_ERROR_TTL;
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200999 }
Klement Sekera6f966492017-02-08 07:42:08 +01001000 if (clib_net_to_host_u16 (udp->src_port) < 49152)
Klement Sekera0e3c0de2016-09-29 14:43:44 +02001001 {
Klement Sekera46a87ad2017-01-02 08:22:23 +01001002 BFD_ERR ("Invalid UDP src port %u, out of range <49152,65535>",
Klement Sekerac5fccc02017-01-18 09:56:00 +01001003 udp->src_port);
Klement Sekera0e3c0de2016-09-29 14:43:44 +02001004 }
1005 return BFD_UDP_ERROR_NONE;
1006}
1007
1008typedef struct
1009{
1010 u32 bs_idx;
1011 bfd_pkt_t pkt;
1012} bfd_rpc_update_t;
1013
Neale Ranns0c50dbb2022-08-05 03:40:43 +00001014static bfd_error_t
1015bfd_rpc_update_session (vlib_main_t *vm, u32 bs_idx, const bfd_pkt_t *pkt)
Klement Sekera0e3c0de2016-09-29 14:43:44 +02001016{
Dave Barach1e3417f2018-07-25 08:30:27 -04001017 bfd_main_t *bm = &bfd_main;
Neale Ranns0c50dbb2022-08-05 03:40:43 +00001018 bfd_error_t err;
Dave Barach1e3417f2018-07-25 08:30:27 -04001019 bfd_lock (bm);
Neale Ranns0c50dbb2022-08-05 03:40:43 +00001020 err = bfd_consume_pkt (vm, bm, pkt, bs_idx);
Dave Barach1e3417f2018-07-25 08:30:27 -04001021 bfd_unlock (bm);
Neale Ranns0c50dbb2022-08-05 03:40:43 +00001022
1023 return err;
Klement Sekera0e3c0de2016-09-29 14:43:44 +02001024}
1025
Neale Ranns5c7e5792022-08-09 00:03:17 +00001026static vl_counter_bfd_udp_enum_t
Klement Sekerab59f63b2022-02-14 20:19:28 +00001027bfd_udp4_scan (vlib_main_t *vm, vlib_buffer_t *b, bfd_session_t **bs_out)
Klement Sekera0e3c0de2016-09-29 14:43:44 +02001028{
1029 const bfd_pkt_t *pkt = vlib_buffer_get_current (b);
1030 if (sizeof (*pkt) > b->current_length)
1031 {
Klement Sekerac5fccc02017-01-18 09:56:00 +01001032 BFD_ERR
1033 ("Payload size %d too small to hold bfd packet of minimum size %d",
1034 b->current_length, sizeof (*pkt));
Klement Sekera0e3c0de2016-09-29 14:43:44 +02001035 return BFD_UDP_ERROR_BAD;
1036 }
Klement Sekeraaeeac3b2017-02-14 07:11:52 +01001037 ip4_header_t *ip4;
1038 udp_header_t *udp;
Klement Sekera0e3c0de2016-09-29 14:43:44 +02001039 bfd_udp4_find_headers (b, &ip4, &udp);
1040 if (!ip4 || !udp)
1041 {
1042 BFD_ERR ("Couldn't find ip4 or udp header");
1043 return BFD_UDP_ERROR_BAD;
1044 }
Klement Sekerab17dd962017-01-09 07:43:48 +01001045 const u32 udp_payload_length = udp->length - sizeof (*udp);
1046 if (pkt->head.length > udp_payload_length)
1047 {
1048 BFD_ERR
1049 ("BFD packet length is larger than udp payload length (%u > %u)",
1050 pkt->head.length, udp_payload_length);
Neale Ranns0c50dbb2022-08-05 03:40:43 +00001051 return BFD_UDP_ERROR_LENGTH;
Klement Sekerab17dd962017-01-09 07:43:48 +01001052 }
Neale Ranns5c7e5792022-08-09 00:03:17 +00001053 vl_counter_bfd_udp_enum_t err;
Neale Ranns0c50dbb2022-08-05 03:40:43 +00001054 if (BFD_UDP_ERROR_NONE !=
1055 (err = bfd_error_to_udp (bfd_verify_pkt_common (pkt))))
Klement Sekera0e3c0de2016-09-29 14:43:44 +02001056 {
Neale Ranns0c50dbb2022-08-05 03:40:43 +00001057 return err;
Klement Sekera0e3c0de2016-09-29 14:43:44 +02001058 }
1059 bfd_session_t *bs = NULL;
1060 if (pkt->your_disc)
1061 {
1062 BFD_DBG ("Looking up BFD session using discriminator %u",
Klement Sekerac5fccc02017-01-18 09:56:00 +01001063 pkt->your_disc);
Klement Sekera0e3c0de2016-09-29 14:43:44 +02001064 bs = bfd_find_session_by_disc (bfd_udp_main.bfd_main, pkt->your_disc);
1065 }
1066 else
1067 {
1068 bfd_udp_key_t key;
Dave Barachb7b92992018-10-17 10:38:51 -04001069 clib_memset (&key, 0, sizeof (key));
Klement Sekera0e3c0de2016-09-29 14:43:44 +02001070 key.sw_if_index = vnet_buffer (b)->sw_if_index[VLIB_RX];
1071 key.local_addr.ip4.as_u32 = ip4->dst_address.as_u32;
1072 key.peer_addr.ip4.as_u32 = ip4->src_address.as_u32;
1073 BFD_DBG ("Looking up BFD session using key (sw_if_index=%u, local=%U, "
Klement Sekerac5fccc02017-01-18 09:56:00 +01001074 "peer=%U)",
1075 key.sw_if_index, format_ip4_address, key.local_addr.ip4.as_u8,
1076 format_ip4_address, key.peer_addr.ip4.as_u8);
Klement Sekera0e3c0de2016-09-29 14:43:44 +02001077 bs = bfd_lookup_session (&bfd_udp_main, &key);
1078 }
1079 if (!bs)
1080 {
1081 BFD_ERR ("BFD session lookup failed - no session matches BFD pkt");
Neale Ranns0c50dbb2022-08-05 03:40:43 +00001082 return BFD_UDP_ERROR_NO_SESSION;
Klement Sekera0e3c0de2016-09-29 14:43:44 +02001083 }
Klement Sekera637b9c42016-12-08 05:19:14 +01001084 BFD_DBG ("BFD session found, bs_idx=%u", bs->bs_idx);
Klement Sekeraa3167442020-02-10 11:49:52 +00001085 if (!bfd_verify_pkt_auth (vm, pkt, b->current_length, bs))
Klement Sekera0e3c0de2016-09-29 14:43:44 +02001086 {
Klement Sekerab17dd962017-01-09 07:43:48 +01001087 BFD_ERR ("Packet verification failed, dropping packet");
Neale Ranns0c50dbb2022-08-05 03:40:43 +00001088 return BFD_UDP_ERROR_FAILED_VERIFICATION;
Klement Sekera0e3c0de2016-09-29 14:43:44 +02001089 }
Klement Sekera0e3c0de2016-09-29 14:43:44 +02001090 if (BFD_UDP_ERROR_NONE != (err = bfd_udp4_verify_transport (ip4, udp, bs)))
1091 {
1092 return err;
1093 }
Neale Ranns0c50dbb2022-08-05 03:40:43 +00001094 err = bfd_error_to_udp (bfd_rpc_update_session (vm, bs->bs_idx, pkt));
Klement Sekera0e3c0de2016-09-29 14:43:44 +02001095 *bs_out = bs;
Neale Ranns0c50dbb2022-08-05 03:40:43 +00001096 return err;
Klement Sekera0e3c0de2016-09-29 14:43:44 +02001097}
1098
Klement Sekerac5fccc02017-01-18 09:56:00 +01001099static void
Klement Sekeraaeeac3b2017-02-14 07:11:52 +01001100bfd_udp6_find_headers (vlib_buffer_t * b, ip6_header_t ** ip6,
1101 udp_header_t ** udp)
Klement Sekera0e3c0de2016-09-29 14:43:44 +02001102{
Klement Sekera46a87ad2017-01-02 08:22:23 +01001103 /* sanity check first */
Damjan Marion072401e2017-07-13 18:53:27 +02001104 const i32 start = vnet_buffer (b)->l3_hdr_offset;
Klement Sekerab59f63b2022-02-14 20:19:28 +00001105 if (start < -(signed) sizeof (b->pre_data))
Klement Sekera46a87ad2017-01-02 08:22:23 +01001106 {
1107 BFD_ERR ("Start of ip header is before pre_data, ignoring");
1108 *ip6 = NULL;
1109 *udp = NULL;
1110 return;
1111 }
Klement Sekerac5fccc02017-01-18 09:56:00 +01001112 *ip6 = (ip6_header_t *) (b->data + start);
1113 if ((u8 *) * ip6 > (u8 *) vlib_buffer_get_current (b))
Klement Sekera46a87ad2017-01-02 08:22:23 +01001114 {
1115 BFD_ERR ("Start of ip header is beyond current data, ignoring");
1116 *ip6 = NULL;
1117 *udp = NULL;
1118 return;
1119 }
Klement Sekera402ed312017-01-18 09:44:36 +01001120 if ((*ip6)->protocol != IP_PROTOCOL_UDP)
1121 {
1122 BFD_ERR ("Unexpected protocol in IPv6 header '%u', expected '%u' (== "
Klement Sekerab17dd962017-01-09 07:43:48 +01001123 "IP_PROTOCOL_UDP)", (*ip6)->protocol, IP_PROTOCOL_UDP);
Klement Sekera402ed312017-01-18 09:44:36 +01001124 *ip6 = NULL;
1125 *udp = NULL;
1126 return;
1127 }
Klement Sekerac5fccc02017-01-18 09:56:00 +01001128 *udp = (udp_header_t *) ((*ip6) + 1);
Klement Sekera46a87ad2017-01-02 08:22:23 +01001129}
1130
Neale Ranns5c7e5792022-08-09 00:03:17 +00001131static vl_counter_bfd_udp_enum_t
1132bfd_udp6_verify_transport (const ip6_header_t *ip6, const udp_header_t *udp,
1133 const bfd_session_t *bs)
Klement Sekera46a87ad2017-01-02 08:22:23 +01001134{
1135 const bfd_udp_session_t *bus = &bs->udp;
1136 const bfd_udp_key_t *key = &bus->key;
1137 if (ip6->src_address.as_u64[0] != key->peer_addr.ip6.as_u64[0] &&
1138 ip6->src_address.as_u64[1] != key->peer_addr.ip6.as_u64[1])
1139 {
Klement Sekerac5fccc02017-01-18 09:56:00 +01001140 BFD_ERR ("IP src addr mismatch, got %U, expected %U",
1141 format_ip6_address, ip6, format_ip6_address,
1142 &key->peer_addr.ip6);
Neale Ranns0c50dbb2022-08-05 03:40:43 +00001143 return BFD_UDP_ERROR_SRC_MISMATCH;
Klement Sekera46a87ad2017-01-02 08:22:23 +01001144 }
1145 if (ip6->dst_address.as_u64[0] != key->local_addr.ip6.as_u64[0] &&
1146 ip6->dst_address.as_u64[1] != key->local_addr.ip6.as_u64[1])
1147 {
Klement Sekerac5fccc02017-01-18 09:56:00 +01001148 BFD_ERR ("IP dst addr mismatch, got %U, expected %U",
1149 format_ip6_address, ip6, format_ip6_address,
1150 &key->local_addr.ip6);
Neale Ranns0c50dbb2022-08-05 03:40:43 +00001151 return BFD_UDP_ERROR_DST_MISMATCH;
Klement Sekera46a87ad2017-01-02 08:22:23 +01001152 }
1153 const u8 expected_hop_limit = 255;
1154 if (ip6->hop_limit != expected_hop_limit)
1155 {
1156 BFD_ERR ("IPv6 unexpected hop-limit value %u, expected %u",
Klement Sekerac5fccc02017-01-18 09:56:00 +01001157 ip6->hop_limit, expected_hop_limit);
Neale Ranns0c50dbb2022-08-05 03:40:43 +00001158 return BFD_UDP_ERROR_TTL;
Klement Sekera46a87ad2017-01-02 08:22:23 +01001159 }
Klement Sekera6f966492017-02-08 07:42:08 +01001160 if (clib_net_to_host_u16 (udp->src_port) < 49152)
Klement Sekera46a87ad2017-01-02 08:22:23 +01001161 {
1162 BFD_ERR ("Invalid UDP src port %u, out of range <49152,65535>",
Klement Sekerac5fccc02017-01-18 09:56:00 +01001163 udp->src_port);
Klement Sekera46a87ad2017-01-02 08:22:23 +01001164 }
1165 return BFD_UDP_ERROR_NONE;
1166}
1167
Neale Ranns5c7e5792022-08-09 00:03:17 +00001168static vl_counter_bfd_udp_enum_t
Klement Sekerab59f63b2022-02-14 20:19:28 +00001169bfd_udp6_scan (vlib_main_t *vm, vlib_buffer_t *b, bfd_session_t **bs_out)
Klement Sekera46a87ad2017-01-02 08:22:23 +01001170{
1171 const bfd_pkt_t *pkt = vlib_buffer_get_current (b);
1172 if (sizeof (*pkt) > b->current_length)
1173 {
Klement Sekerac5fccc02017-01-18 09:56:00 +01001174 BFD_ERR
1175 ("Payload size %d too small to hold bfd packet of minimum size %d",
1176 b->current_length, sizeof (*pkt));
Klement Sekera46a87ad2017-01-02 08:22:23 +01001177 return BFD_UDP_ERROR_BAD;
1178 }
Klement Sekeraaeeac3b2017-02-14 07:11:52 +01001179 ip6_header_t *ip6;
1180 udp_header_t *udp;
Klement Sekera46a87ad2017-01-02 08:22:23 +01001181 bfd_udp6_find_headers (b, &ip6, &udp);
1182 if (!ip6 || !udp)
1183 {
1184 BFD_ERR ("Couldn't find ip6 or udp header");
1185 return BFD_UDP_ERROR_BAD;
1186 }
Klement Sekerab17dd962017-01-09 07:43:48 +01001187 const u32 udp_payload_length = udp->length - sizeof (*udp);
1188 if (pkt->head.length > udp_payload_length)
1189 {
1190 BFD_ERR
1191 ("BFD packet length is larger than udp payload length (%u > %u)",
1192 pkt->head.length, udp_payload_length);
1193 return BFD_UDP_ERROR_BAD;
1194 }
Neale Ranns5c7e5792022-08-09 00:03:17 +00001195 vl_counter_bfd_udp_enum_t err;
Neale Ranns0c50dbb2022-08-05 03:40:43 +00001196 if (BFD_UDP_ERROR_NONE !=
1197 (err = bfd_error_to_udp (bfd_verify_pkt_common (pkt))))
Klement Sekera46a87ad2017-01-02 08:22:23 +01001198 {
Neale Ranns0c50dbb2022-08-05 03:40:43 +00001199 return err;
Klement Sekera46a87ad2017-01-02 08:22:23 +01001200 }
1201 bfd_session_t *bs = NULL;
1202 if (pkt->your_disc)
1203 {
1204 BFD_DBG ("Looking up BFD session using discriminator %u",
Klement Sekerac5fccc02017-01-18 09:56:00 +01001205 pkt->your_disc);
Klement Sekera46a87ad2017-01-02 08:22:23 +01001206 bs = bfd_find_session_by_disc (bfd_udp_main.bfd_main, pkt->your_disc);
1207 }
1208 else
1209 {
1210 bfd_udp_key_t key;
Dave Barachb7b92992018-10-17 10:38:51 -04001211 clib_memset (&key, 0, sizeof (key));
Klement Sekera46a87ad2017-01-02 08:22:23 +01001212 key.sw_if_index = vnet_buffer (b)->sw_if_index[VLIB_RX];
1213 key.local_addr.ip6.as_u64[0] = ip6->dst_address.as_u64[0];
1214 key.local_addr.ip6.as_u64[1] = ip6->dst_address.as_u64[1];
1215 key.peer_addr.ip6.as_u64[0] = ip6->src_address.as_u64[0];
1216 key.peer_addr.ip6.as_u64[1] = ip6->src_address.as_u64[1];
1217 BFD_DBG ("Looking up BFD session using key (sw_if_index=%u, local=%U, "
Klement Sekerab17dd962017-01-09 07:43:48 +01001218 "peer=%U)",
1219 key.sw_if_index, format_ip6_address, &key.local_addr,
1220 format_ip6_address, &key.peer_addr);
Klement Sekera46a87ad2017-01-02 08:22:23 +01001221 bs = bfd_lookup_session (&bfd_udp_main, &key);
1222 }
1223 if (!bs)
1224 {
1225 BFD_ERR ("BFD session lookup failed - no session matches BFD pkt");
Neale Ranns0c50dbb2022-08-05 03:40:43 +00001226 return BFD_UDP_ERROR_NO_SESSION;
Klement Sekera46a87ad2017-01-02 08:22:23 +01001227 }
1228 BFD_DBG ("BFD session found, bs_idx=%u", bs->bs_idx);
Klement Sekeraa3167442020-02-10 11:49:52 +00001229 if (!bfd_verify_pkt_auth (vm, pkt, b->current_length, bs))
Klement Sekera46a87ad2017-01-02 08:22:23 +01001230 {
Klement Sekerab17dd962017-01-09 07:43:48 +01001231 BFD_ERR ("Packet verification failed, dropping packet");
Neale Ranns0c50dbb2022-08-05 03:40:43 +00001232 return BFD_UDP_ERROR_FAILED_VERIFICATION;
Klement Sekera46a87ad2017-01-02 08:22:23 +01001233 }
Klement Sekera46a87ad2017-01-02 08:22:23 +01001234 if (BFD_UDP_ERROR_NONE != (err = bfd_udp6_verify_transport (ip6, udp, bs)))
1235 {
1236 return err;
1237 }
Neale Ranns0c50dbb2022-08-05 03:40:43 +00001238 err = bfd_error_to_udp (bfd_rpc_update_session (vm, bs->bs_idx, pkt));
Klement Sekera46a87ad2017-01-02 08:22:23 +01001239 *bs_out = bs;
Neale Ranns0c50dbb2022-08-05 03:40:43 +00001240 return err;
Klement Sekera0e3c0de2016-09-29 14:43:44 +02001241}
1242
1243/*
1244 * Process a frame of bfd packets
1245 * Expect 1 packet / frame
1246 */
Klement Sekerac5fccc02017-01-18 09:56:00 +01001247static uword
1248bfd_udp_input (vlib_main_t * vm, vlib_node_runtime_t * rt,
1249 vlib_frame_t * f, int is_ipv6)
Klement Sekera0e3c0de2016-09-29 14:43:44 +02001250{
1251 u32 n_left_from, *from;
1252 bfd_input_trace_t *t0;
Dave Barach1e3417f2018-07-25 08:30:27 -04001253 bfd_main_t *bm = &bfd_main;
Klement Sekera0e3c0de2016-09-29 14:43:44 +02001254
Klement Sekerac5fccc02017-01-18 09:56:00 +01001255 from = vlib_frame_vector_args (f); /* array of buffer indices */
1256 n_left_from = f->n_vectors; /* number of buffer indices */
Klement Sekera0e3c0de2016-09-29 14:43:44 +02001257
1258 while (n_left_from > 0)
1259 {
1260 u32 bi0;
1261 vlib_buffer_t *b0;
1262 u32 next0, error0;
1263
1264 bi0 = from[0];
1265 b0 = vlib_get_buffer (vm, bi0);
1266
1267 bfd_session_t *bs = NULL;
1268
1269 /* If this pkt is traced, snapshot the data */
1270 if (b0->flags & VLIB_BUFFER_IS_TRACED)
Klement Sekerac5fccc02017-01-18 09:56:00 +01001271 {
Klement Sekerab59f63b2022-02-14 20:19:28 +00001272 u64 len;
Klement Sekerac5fccc02017-01-18 09:56:00 +01001273 t0 = vlib_add_trace (vm, rt, b0, sizeof (*t0));
1274 len = (b0->current_length < sizeof (t0->data)) ? b0->current_length
1275 : sizeof (t0->data);
1276 t0->len = len;
Dave Barach178cf492018-11-13 16:34:13 -05001277 clib_memcpy_fast (t0->data, vlib_buffer_get_current (b0), len);
Klement Sekerac5fccc02017-01-18 09:56:00 +01001278 }
Klement Sekera0e3c0de2016-09-29 14:43:44 +02001279
1280 /* scan this bfd pkt. error0 is the counter index to bmp */
Dave Barach1e3417f2018-07-25 08:30:27 -04001281 bfd_lock (bm);
Klement Sekera0e3c0de2016-09-29 14:43:44 +02001282 if (is_ipv6)
Klement Sekerac5fccc02017-01-18 09:56:00 +01001283 {
Klement Sekerab59f63b2022-02-14 20:19:28 +00001284 error0 = bfd_udp6_scan (vm, b0, &bs);
Klement Sekerac5fccc02017-01-18 09:56:00 +01001285 }
Klement Sekera0e3c0de2016-09-29 14:43:44 +02001286 else
Klement Sekerac5fccc02017-01-18 09:56:00 +01001287 {
Klement Sekerab59f63b2022-02-14 20:19:28 +00001288 error0 = bfd_udp4_scan (vm, b0, &bs);
Klement Sekerac5fccc02017-01-18 09:56:00 +01001289 }
Klement Sekera0e3c0de2016-09-29 14:43:44 +02001290 b0->error = rt->errors[error0];
1291
1292 next0 = BFD_UDP_INPUT_NEXT_NORMAL;
1293 if (BFD_UDP_ERROR_NONE == error0)
Klement Sekerac5fccc02017-01-18 09:56:00 +01001294 {
Klement Sekeracdaf0d82022-02-14 20:20:22 +00001295 vlib_increment_combined_counter (
1296 &bm->rx_counter, vm->thread_index, bs->bs_idx, 1,
1297 vlib_buffer_length_in_chain (vm, b0));
Klement Sekera402ed312017-01-18 09:44:36 +01001298 /*
1299 * if everything went fine, check for poll bit, if present, re-use
1300 * the buffer and based on (now updated) session parameters, send
1301 * the final packet back
1302 */
Klement Sekerac5fccc02017-01-18 09:56:00 +01001303 const bfd_pkt_t *pkt = vlib_buffer_get_current (b0);
1304 if (bfd_pkt_get_poll (pkt))
1305 {
Klement Sekerae50e8562017-04-04 16:19:48 +02001306 b0->current_data = 0;
1307 b0->current_length = 0;
Klement Sekerab59f63b2022-02-14 20:19:28 +00001308 bfd_init_final_control_frame (vm, b0, bs);
Klement Sekerac5fccc02017-01-18 09:56:00 +01001309 if (is_ipv6)
1310 {
1311 vlib_node_increment_counter (vm, bfd_udp6_input_node.index,
Paul Atkins0d032842022-03-24 11:26:16 +00001312 error0, 1);
Klement Sekerac5fccc02017-01-18 09:56:00 +01001313 }
1314 else
1315 {
1316 vlib_node_increment_counter (vm, bfd_udp4_input_node.index,
Paul Atkins0d032842022-03-24 11:26:16 +00001317 error0, 1);
Klement Sekerac5fccc02017-01-18 09:56:00 +01001318 }
Klement Sekerae50e8562017-04-04 16:19:48 +02001319 const bfd_udp_session_t *bus = &bs->udp;
1320 ip_adjacency_t *adj = adj_get (bus->adj_index);
1321 switch (adj->lookup_next_index)
1322 {
1323 case IP_LOOKUP_NEXT_ARP:
1324 next0 = BFD_UDP_INPUT_NEXT_REPLY_ARP;
1325 break;
1326 case IP_LOOKUP_NEXT_REWRITE:
1327 next0 = BFD_UDP_INPUT_NEXT_REPLY_REWRITE;
1328 break;
Matthew G Smith2f260142019-05-22 14:49:24 -05001329 case IP_LOOKUP_NEXT_MIDCHAIN:
1330 next0 = BFD_UDP_INPUT_NEXT_REPLY_MIDCHAIN;
1331 break;
Klement Sekerae50e8562017-04-04 16:19:48 +02001332 default:
1333 /* drop */
1334 break;
1335 }
Klement Sekerac5fccc02017-01-18 09:56:00 +01001336 }
1337 }
Dave Barach1e3417f2018-07-25 08:30:27 -04001338 bfd_unlock (bm);
Klement Sekera0e3c0de2016-09-29 14:43:44 +02001339 vlib_set_next_frame_buffer (vm, rt, next0, bi0);
1340
1341 from += 1;
1342 n_left_from -= 1;
1343 }
1344
1345 return f->n_vectors;
1346}
1347
Klement Sekerac5fccc02017-01-18 09:56:00 +01001348static uword
1349bfd_udp4_input (vlib_main_t * vm, vlib_node_runtime_t * rt, vlib_frame_t * f)
Klement Sekera0e3c0de2016-09-29 14:43:44 +02001350{
1351 return bfd_udp_input (vm, rt, f, 0);
1352}
1353
1354/*
1355 * bfd input graph node declaration
1356 */
1357/* *INDENT-OFF* */
1358VLIB_REGISTER_NODE (bfd_udp4_input_node, static) = {
1359 .function = bfd_udp4_input,
1360 .name = "bfd-udp4-input",
1361 .vector_size = sizeof (u32),
1362 .type = VLIB_NODE_TYPE_INTERNAL,
1363
1364 .n_errors = BFD_UDP_N_ERROR,
Neale Ranns5c7e5792022-08-09 00:03:17 +00001365 .error_counters = bfd_udp_error_counters,
Klement Sekera0e3c0de2016-09-29 14:43:44 +02001366
1367 .format_trace = bfd_input_format_trace,
1368
1369 .n_next_nodes = BFD_UDP_INPUT_N_NEXT,
1370 .next_nodes =
1371 {
1372 [BFD_UDP_INPUT_NEXT_NORMAL] = "error-drop",
Klement Sekerae50e8562017-04-04 16:19:48 +02001373 [BFD_UDP_INPUT_NEXT_REPLY_ARP] = "ip4-arp",
1374 [BFD_UDP_INPUT_NEXT_REPLY_REWRITE] = "ip4-lookup",
Matthew G Smith2f260142019-05-22 14:49:24 -05001375 [BFD_UDP_INPUT_NEXT_REPLY_MIDCHAIN] = "ip4-midchain",
Klement Sekera0e3c0de2016-09-29 14:43:44 +02001376 },
1377};
1378/* *INDENT-ON* */
1379
Klement Sekerac5fccc02017-01-18 09:56:00 +01001380static uword
1381bfd_udp6_input (vlib_main_t * vm, vlib_node_runtime_t * rt, vlib_frame_t * f)
Klement Sekera0e3c0de2016-09-29 14:43:44 +02001382{
1383 return bfd_udp_input (vm, rt, f, 1);
1384}
1385
1386/* *INDENT-OFF* */
1387VLIB_REGISTER_NODE (bfd_udp6_input_node, static) = {
1388 .function = bfd_udp6_input,
1389 .name = "bfd-udp6-input",
1390 .vector_size = sizeof (u32),
1391 .type = VLIB_NODE_TYPE_INTERNAL,
1392
1393 .n_errors = BFD_UDP_N_ERROR,
Neale Ranns5c7e5792022-08-09 00:03:17 +00001394 .error_counters = bfd_udp_error_counters,
Klement Sekera0e3c0de2016-09-29 14:43:44 +02001395
1396 .format_trace = bfd_input_format_trace,
1397
1398 .n_next_nodes = BFD_UDP_INPUT_N_NEXT,
1399 .next_nodes =
1400 {
1401 [BFD_UDP_INPUT_NEXT_NORMAL] = "error-drop",
Klement Sekerae50e8562017-04-04 16:19:48 +02001402 [BFD_UDP_INPUT_NEXT_REPLY_ARP] = "ip6-discover-neighbor",
1403 [BFD_UDP_INPUT_NEXT_REPLY_REWRITE] = "ip6-lookup",
Matthew G Smith2f260142019-05-22 14:49:24 -05001404 [BFD_UDP_INPUT_NEXT_REPLY_MIDCHAIN] = "ip6-midchain",
Klement Sekera0e3c0de2016-09-29 14:43:44 +02001405 },
1406};
1407/* *INDENT-ON* */
1408
Klement Sekeraaeeac3b2017-02-14 07:11:52 +01001409/*
1410 * Process a frame of bfd echo packets
1411 * Expect 1 packet / frame
1412 */
1413static uword
1414bfd_udp_echo_input (vlib_main_t * vm, vlib_node_runtime_t * rt,
1415 vlib_frame_t * f, int is_ipv6)
1416{
1417 u32 n_left_from, *from;
1418 bfd_input_trace_t *t0;
Dave Barach1e3417f2018-07-25 08:30:27 -04001419 bfd_main_t *bm = &bfd_main;
Klement Sekeraaeeac3b2017-02-14 07:11:52 +01001420
1421 from = vlib_frame_vector_args (f); /* array of buffer indices */
1422 n_left_from = f->n_vectors; /* number of buffer indices */
1423
1424 while (n_left_from > 0)
1425 {
1426 u32 bi0;
1427 vlib_buffer_t *b0;
1428 u32 next0;
1429
1430 bi0 = from[0];
1431 b0 = vlib_get_buffer (vm, bi0);
1432
1433 /* If this pkt is traced, snapshot the data */
1434 if (b0->flags & VLIB_BUFFER_IS_TRACED)
1435 {
Klement Sekerab59f63b2022-02-14 20:19:28 +00001436 u64 len;
Klement Sekeraaeeac3b2017-02-14 07:11:52 +01001437 t0 = vlib_add_trace (vm, rt, b0, sizeof (*t0));
1438 len = (b0->current_length < sizeof (t0->data)) ? b0->current_length
1439 : sizeof (t0->data);
1440 t0->len = len;
Dave Barach178cf492018-11-13 16:34:13 -05001441 clib_memcpy_fast (t0->data, vlib_buffer_get_current (b0), len);
Klement Sekeraaeeac3b2017-02-14 07:11:52 +01001442 }
1443
Klement Sekeracdaf0d82022-02-14 20:20:22 +00001444 bfd_session_t *bs = NULL;
Dave Barach1e3417f2018-07-25 08:30:27 -04001445 bfd_lock (bm);
Klement Sekeracdaf0d82022-02-14 20:20:22 +00001446 if ((bs = bfd_consume_echo_pkt (vm, bfd_udp_main.bfd_main, b0)))
Klement Sekera239790f2017-02-16 10:53:53 +01001447 {
1448 b0->error = rt->errors[BFD_UDP_ERROR_NONE];
Matthew G Smith2f260142019-05-22 14:49:24 -05001449 next0 = BFD_UDP_ECHO_INPUT_NEXT_NORMAL;
Klement Sekera239790f2017-02-16 10:53:53 +01001450 }
1451 else
Klement Sekeraaeeac3b2017-02-14 07:11:52 +01001452 {
1453 /* loop back the packet */
1454 b0->error = rt->errors[BFD_UDP_ERROR_NONE];
1455 if (is_ipv6)
1456 {
1457 vlib_node_increment_counter (vm, bfd_udp_echo6_input_node.index,
Paul Atkins0d032842022-03-24 11:26:16 +00001458 BFD_UDP_ERROR_NONE, 1);
Klement Sekeraaeeac3b2017-02-14 07:11:52 +01001459 }
1460 else
1461 {
1462 vlib_node_increment_counter (vm, bfd_udp_echo4_input_node.index,
Paul Atkins0d032842022-03-24 11:26:16 +00001463 BFD_UDP_ERROR_NONE, 1);
Klement Sekeraaeeac3b2017-02-14 07:11:52 +01001464 }
Matthew G Smith2f260142019-05-22 14:49:24 -05001465 next0 = BFD_UDP_ECHO_INPUT_NEXT_REPLY_REWRITE;
Klement Sekeraaeeac3b2017-02-14 07:11:52 +01001466 }
Klement Sekeraaeeac3b2017-02-14 07:11:52 +01001467
Dave Barach1e3417f2018-07-25 08:30:27 -04001468 bfd_unlock (bm);
Klement Sekeracdaf0d82022-02-14 20:20:22 +00001469
1470 if (bs)
1471 {
1472 vlib_increment_combined_counter (
1473 &bm->rx_echo_counter, vm->thread_index, bs->bs_idx, 1,
1474 vlib_buffer_length_in_chain (vm, b0));
1475 }
1476
Klement Sekeraaeeac3b2017-02-14 07:11:52 +01001477 vlib_set_next_frame_buffer (vm, rt, next0, bi0);
1478
1479 from += 1;
1480 n_left_from -= 1;
1481 }
1482
1483 return f->n_vectors;
1484}
1485
1486static uword
1487bfd_udp_echo4_input (vlib_main_t * vm, vlib_node_runtime_t * rt,
1488 vlib_frame_t * f)
1489{
1490 return bfd_udp_echo_input (vm, rt, f, 0);
1491}
1492
1493u8 *
1494bfd_echo_input_format_trace (u8 * s, va_list * args)
1495{
1496 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
1497 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
1498 const bfd_udp_echo_input_trace_t *t =
1499 va_arg (*args, bfd_udp_echo_input_trace_t *);
1500 if (t->len > STRUCT_SIZE_OF (bfd_pkt_t, head))
1501 {
1502 s = format (s, "BFD ECHO:\n");
1503 s = format (s, " data: %U", format_hexdump, t->data, t->len);
1504 }
1505
1506 return s;
1507}
1508
1509/*
1510 * bfd input graph node declaration
1511 */
1512/* *INDENT-OFF* */
1513VLIB_REGISTER_NODE (bfd_udp_echo4_input_node, static) = {
1514 .function = bfd_udp_echo4_input,
1515 .name = "bfd-udp-echo4-input",
1516 .vector_size = sizeof (u32),
1517 .type = VLIB_NODE_TYPE_INTERNAL,
1518
Neale Ranns5c7e5792022-08-09 00:03:17 +00001519 .n_errors = BFD_UDP_N_ERROR,
1520 .error_counters = bfd_udp_error_counters,
Klement Sekeraaeeac3b2017-02-14 07:11:52 +01001521
1522 .format_trace = bfd_echo_input_format_trace,
1523
Matthew G Smith2f260142019-05-22 14:49:24 -05001524 .n_next_nodes = BFD_UDP_ECHO_INPUT_N_NEXT,
Klement Sekeraaeeac3b2017-02-14 07:11:52 +01001525 .next_nodes =
1526 {
Matthew G Smith2f260142019-05-22 14:49:24 -05001527 [BFD_UDP_ECHO_INPUT_NEXT_NORMAL] = "error-drop",
1528 [BFD_UDP_ECHO_INPUT_NEXT_REPLY_ARP] = "ip4-arp",
1529 [BFD_UDP_ECHO_INPUT_NEXT_REPLY_REWRITE] = "ip4-lookup",
Klement Sekeraaeeac3b2017-02-14 07:11:52 +01001530 },
1531};
1532/* *INDENT-ON* */
1533
1534static uword
1535bfd_udp_echo6_input (vlib_main_t * vm, vlib_node_runtime_t * rt,
1536 vlib_frame_t * f)
1537{
1538 return bfd_udp_echo_input (vm, rt, f, 1);
1539}
1540
1541/* *INDENT-OFF* */
1542VLIB_REGISTER_NODE (bfd_udp_echo6_input_node, static) = {
1543 .function = bfd_udp_echo6_input,
1544 .name = "bfd-udp-echo6-input",
1545 .vector_size = sizeof (u32),
1546 .type = VLIB_NODE_TYPE_INTERNAL,
1547
Neale Ranns5c7e5792022-08-09 00:03:17 +00001548 .n_errors = BFD_UDP_N_ERROR,
1549 .error_counters = bfd_udp_error_counters,
Klement Sekeraaeeac3b2017-02-14 07:11:52 +01001550
1551 .format_trace = bfd_echo_input_format_trace,
1552
Matthew G Smith2f260142019-05-22 14:49:24 -05001553 .n_next_nodes = BFD_UDP_ECHO_INPUT_N_NEXT,
Klement Sekeraaeeac3b2017-02-14 07:11:52 +01001554 .next_nodes =
1555 {
Matthew G Smith2f260142019-05-22 14:49:24 -05001556 [BFD_UDP_ECHO_INPUT_NEXT_NORMAL] = "error-drop",
1557 [BFD_UDP_ECHO_INPUT_NEXT_REPLY_ARP] = "ip6-discover-neighbor",
1558 [BFD_UDP_ECHO_INPUT_NEXT_REPLY_REWRITE] = "ip6-lookup",
Klement Sekeraaeeac3b2017-02-14 07:11:52 +01001559 },
1560};
1561
1562/* *INDENT-ON* */
1563
Klement Sekerac5fccc02017-01-18 09:56:00 +01001564static clib_error_t *
Klement Sekerab59f63b2022-02-14 20:19:28 +00001565bfd_udp_sw_if_add_del (CLIB_UNUSED (vnet_main_t *vnm), u32 sw_if_index,
1566 u32 is_create)
Klement Sekera0e3c0de2016-09-29 14:43:44 +02001567{
Klement Sekerab59f63b2022-02-14 20:19:28 +00001568 u32 *to_be_freed = NULL;
Damjan Marion07a38572018-01-21 06:44:18 -08001569 bfd_udp_main_t *bum = &bfd_udp_main;
Klement Sekeraf3bcdbf2017-05-02 07:38:01 +02001570 BFD_DBG ("sw_if_add_del called, sw_if_index=%u, is_create=%u", sw_if_index,
1571 is_create);
1572 if (!is_create)
Klement Sekera0e3c0de2016-09-29 14:43:44 +02001573 {
Klement Sekeraf3bcdbf2017-05-02 07:38:01 +02001574 bfd_session_t *bs;
Klement Sekerab59f63b2022-02-14 20:19:28 +00001575 pool_foreach (bs, bum->bfd_main->sessions)
1576 {
1577 if (bs->transport != BFD_TRANSPORT_UDP4 &&
1578 bs->transport != BFD_TRANSPORT_UDP6)
1579 {
1580 continue;
1581 }
1582 if (bs->udp.key.sw_if_index != sw_if_index)
1583 {
1584 continue;
1585 }
1586 vec_add1 (to_be_freed, bs->bs_idx);
1587 }
Klement Sekera0e3c0de2016-09-29 14:43:44 +02001588 }
Klement Sekerab59f63b2022-02-14 20:19:28 +00001589 u32 *bs_idx;
1590 vec_foreach (bs_idx, to_be_freed)
1591 {
1592 bfd_session_t *bs = pool_elt_at_index (bum->bfd_main->sessions, *bs_idx);
1593 vlib_log_notice (bum->log_class,
1594 "removal of sw_if_index=%u forces removal of bfd "
1595 "session with bs_idx=%u",
1596 sw_if_index, bs->bs_idx);
1597 bfd_session_set_flags (vlib_get_main (), bs, 0);
1598 bfd_udp_del_session_internal (vlib_get_main (), bs);
1599 }
Klement Sekera0e3c0de2016-09-29 14:43:44 +02001600 return 0;
1601}
1602
Klement Sekeraf3bcdbf2017-05-02 07:38:01 +02001603VNET_SW_INTERFACE_ADD_DEL_FUNCTION (bfd_udp_sw_if_add_del);
Klement Sekera0e3c0de2016-09-29 14:43:44 +02001604
Klement Sekeracdaf0d82022-02-14 20:20:22 +00001605clib_error_t *
1606bfd_udp_stats_init (bfd_udp_main_t *bum)
1607{
1608 const char *name4 = "/bfd/udp4/sessions";
Damjan Marion8973b072022-03-01 15:51:18 +01001609 bum->udp4_sessions_count_stat_seg_entry = vlib_stats_add_gauge ("%s", name4);
Klement Sekeracdaf0d82022-02-14 20:20:22 +00001610
Damjan Marion8973b072022-03-01 15:51:18 +01001611 vlib_stats_set_gauge (bum->udp4_sessions_count_stat_seg_entry, 0);
Klement Sekeracdaf0d82022-02-14 20:20:22 +00001612 if (~0 == bum->udp4_sessions_count_stat_seg_entry)
1613 {
1614 return clib_error_return (
1615 0, "Could not create stat segment entry for %s", name4);
1616 }
1617 const char *name6 = "/bfd/udp6/sessions";
Damjan Marion8973b072022-03-01 15:51:18 +01001618 bum->udp6_sessions_count_stat_seg_entry = vlib_stats_add_gauge ("%s", name6);
Klement Sekeracdaf0d82022-02-14 20:20:22 +00001619
Damjan Marion8973b072022-03-01 15:51:18 +01001620 vlib_stats_set_gauge (bum->udp6_sessions_count_stat_seg_entry, 0);
Klement Sekeracdaf0d82022-02-14 20:20:22 +00001621 if (~0 == bum->udp6_sessions_count_stat_seg_entry)
1622 {
1623 return clib_error_return (
1624 0, "Could not create stat segment entry for %s", name6);
1625 }
1626
1627 return 0;
1628}
1629
Klement Sekera0e3c0de2016-09-29 14:43:44 +02001630/*
1631 * setup function
1632 */
Klement Sekerac5fccc02017-01-18 09:56:00 +01001633static clib_error_t *
1634bfd_udp_init (vlib_main_t * vm)
Klement Sekera0e3c0de2016-09-29 14:43:44 +02001635{
Klement Sekera88aec652019-03-11 14:04:19 +01001636 bfd_udp_main.udp4_sessions_count = 0;
1637 bfd_udp_main.udp6_sessions_count = 0;
Klement Sekera0e3c0de2016-09-29 14:43:44 +02001638 mhash_init (&bfd_udp_main.bfd_session_idx_by_bfd_key, sizeof (uword),
Klement Sekerac5fccc02017-01-18 09:56:00 +01001639 sizeof (bfd_udp_key_t));
Klement Sekera0e3c0de2016-09-29 14:43:44 +02001640 bfd_udp_main.bfd_main = &bfd_main;
Klement Sekera239790f2017-02-16 10:53:53 +01001641 bfd_udp_main.vnet_main = vnet_get_main ();
Klement Sekerae50e8562017-04-04 16:19:48 +02001642 vlib_node_t *node = vlib_get_node_by_name (vm, (u8 *) "ip4-arp");
1643 ASSERT (node);
1644 bfd_udp_main.ip4_arp_idx = node->index;
1645 node = vlib_get_node_by_name (vm, (u8 *) "ip6-discover-neighbor");
1646 ASSERT (node);
1647 bfd_udp_main.ip6_ndp_idx = node->index;
1648 node = vlib_get_node_by_name (vm, (u8 *) "ip4-rewrite");
1649 ASSERT (node);
1650 bfd_udp_main.ip4_rewrite_idx = node->index;
1651 node = vlib_get_node_by_name (vm, (u8 *) "ip6-rewrite");
1652 ASSERT (node);
1653 bfd_udp_main.ip6_rewrite_idx = node->index;
Matthew G Smith2f260142019-05-22 14:49:24 -05001654 node = vlib_get_node_by_name (vm, (u8 *) "ip4-midchain");
1655 ASSERT (node);
1656 bfd_udp_main.ip4_midchain_idx = node->index;
1657 node = vlib_get_node_by_name (vm, (u8 *) "ip6-midchain");
1658 ASSERT (node);
1659 bfd_udp_main.ip6_midchain_idx = node->index;
Klement Sekerae50e8562017-04-04 16:19:48 +02001660
Klement Sekeracdaf0d82022-02-14 20:20:22 +00001661 bfd_udp_stats_init (&bfd_udp_main);
1662
Damjan Marion07a38572018-01-21 06:44:18 -08001663 bfd_udp_main.log_class = vlib_log_register_class ("bfd", "udp");
1664 vlib_log_debug (bfd_udp_main.log_class, "initialized");
Klement Sekera0e3c0de2016-09-29 14:43:44 +02001665 return 0;
1666}
1667
1668VLIB_INIT_FUNCTION (bfd_udp_init);
Klement Sekerac5fccc02017-01-18 09:56:00 +01001669
1670/*
1671 * fd.io coding-style-patch-verification: ON
1672 *
1673 * Local Variables:
1674 * eval: (c-set-style "gnu")
1675 * End:
1676 */