blob: 37bb102d2d9eaa8af1a37cbe846d679eb2281c62 [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;
Damjan Marion07a38572018-01-21 06:44:18 -080057 /* log class */
58 vlib_log_class_t log_class;
Klement Sekera88aec652019-03-11 14:04:19 +010059 /* number of active udp4 sessions */
60 u32 udp4_sessions_count;
Klement Sekeracdaf0d82022-02-14 20:20:22 +000061 u32 udp4_sessions_count_stat_seg_entry;
Klement Sekera88aec652019-03-11 14:04:19 +010062 /* number of active udp6 sessions */
63 u32 udp6_sessions_count;
Klement Sekeracdaf0d82022-02-14 20:20:22 +000064 u32 udp6_sessions_count_stat_seg_entry;
Klement Sekera0e3c0de2016-09-29 14:43:44 +020065} bfd_udp_main_t;
66
Klement Sekerae4504c62016-12-08 10:16:41 +010067static vlib_node_registration_t bfd_udp4_input_node;
68static vlib_node_registration_t bfd_udp6_input_node;
Klement Sekeraaeeac3b2017-02-14 07:11:52 +010069static vlib_node_registration_t bfd_udp_echo4_input_node;
70static vlib_node_registration_t bfd_udp_echo6_input_node;
Klement Sekerae4504c62016-12-08 10:16:41 +010071
Klement Sekera0e3c0de2016-09-29 14:43:44 +020072bfd_udp_main_t bfd_udp_main;
73
Klement Sekeracdaf0d82022-02-14 20:20:22 +000074void
75bfd_udp_update_stat_segment_entry (u32 entry, u64 value)
76{
Damjan Marion8973b072022-03-01 15:51:18 +010077 vlib_stats_segment_lock ();
78 vlib_stats_set_gauge (entry, value);
79 vlib_stats_segment_unlock ();
Klement Sekeracdaf0d82022-02-14 20:20:22 +000080}
81
Klement Sekera239790f2017-02-16 10:53:53 +010082vnet_api_error_t
83bfd_udp_set_echo_source (u32 sw_if_index)
84{
85 vnet_sw_interface_t *sw_if =
Dave Barach3940de32019-07-23 16:28:36 -040086 vnet_get_sw_interface_or_null (bfd_udp_main.vnet_main, sw_if_index);
Klement Sekera239790f2017-02-16 10:53:53 +010087 if (sw_if)
88 {
89 bfd_udp_main.echo_source_sw_if_index = sw_if_index;
90 bfd_udp_main.echo_source_is_set = 1;
91 return 0;
92 }
93 return VNET_API_ERROR_BFD_ENOENT;
94}
95
96vnet_api_error_t
Klement Sekeracdaf0d82022-02-14 20:20:22 +000097bfd_udp_del_echo_source ()
Klement Sekera239790f2017-02-16 10:53:53 +010098{
99 bfd_udp_main.echo_source_sw_if_index = ~0;
100 bfd_udp_main.echo_source_is_set = 0;
101 return 0;
102}
103
104int
105bfd_udp_is_echo_available (bfd_transport_e transport)
106{
107 if (!bfd_udp_main.echo_source_is_set)
108 {
Klement Sekera73884482017-02-23 09:26:30 +0100109 BFD_DBG ("UDP echo source not set - echo not available");
Klement Sekera239790f2017-02-16 10:53:53 +0100110 return 0;
111 }
112 /*
113 * for the echo to work, we need a loopback interface with at least one
114 * address with netmask length at most 31 (ip4) or 127 (ip6) so that we can
115 * pick an unused address from that subnet
116 */
117 vnet_sw_interface_t *sw_if =
Dave Barach3940de32019-07-23 16:28:36 -0400118 vnet_get_sw_interface_or_null (bfd_udp_main.vnet_main,
119 bfd_udp_main.echo_source_sw_if_index);
Klement Sekera239790f2017-02-16 10:53:53 +0100120 if (sw_if && sw_if->flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP)
121 {
122 if (BFD_TRANSPORT_UDP4 == transport)
123 {
124 ip4_main_t *im = &ip4_main;
125 ip_interface_address_t *ia = NULL;
126 /* *INDENT-OFF* */
127 foreach_ip_interface_address (&im->lookup_main, ia,
128 bfd_udp_main.echo_source_sw_if_index,
129 0 /* honor unnumbered */, ({
130 if (ia->address_length <= 31)
131 {
132 return 1;
133 }
134 }));
135 /* *INDENT-ON* */
136 }
137 else if (BFD_TRANSPORT_UDP6 == transport)
138 {
139 ip6_main_t *im = &ip6_main;
140 ip_interface_address_t *ia = NULL;
141 /* *INDENT-OFF* */
142 foreach_ip_interface_address (&im->lookup_main, ia,
143 bfd_udp_main.echo_source_sw_if_index,
144 0 /* honor unnumbered */, ({
145 if (ia->address_length <= 127)
146 {
147 return 1;
148 }
149 }));
150 /* *INDENT-ON* */
151 }
152 }
Klement Sekera73884482017-02-23 09:26:30 +0100153 BFD_DBG ("No usable IP address for UDP echo - echo not available");
Klement Sekera239790f2017-02-16 10:53:53 +0100154 return 0;
155}
156
Klement Sekera2bce0332017-02-09 06:03:46 +0100157static u16
158bfd_udp_bs_idx_to_sport (u32 bs_idx)
159{
160 /* The source port MUST be in the range 49152 through 65535. The same UDP
161 * source port number MUST be used for all BFD Control packets associated
162 * with a particular session. The source port number SHOULD be unique among
163 * all BFD sessions on the system. If more than 16384 BFD sessions are
164 * simultaneously active, UDP source port numbers MAY be reused on
165 * multiple sessions, but the number of distinct uses of the same UDP
166 * source port number SHOULD be minimized.
167 */
168 return 49152 + bs_idx % (65535 - 49152 + 1);
169}
170
Klement Sekera239790f2017-02-16 10:53:53 +0100171int
172bfd_udp_get_echo_src_ip4 (ip4_address_t * addr)
173{
174 if (!bfd_udp_main.echo_source_is_set)
175 {
176 BFD_ERR ("cannot find ip4 address, echo source not set");
177 return 0;
178 }
179 ip_interface_address_t *ia = NULL;
180 ip4_main_t *im = &ip4_main;
181
182 /* *INDENT-OFF* */
183 foreach_ip_interface_address (
184 &im->lookup_main, ia, bfd_udp_main.echo_source_sw_if_index,
185 0 /* honor unnumbered */, ({
186 ip4_address_t *x =
187 ip_interface_address_get_address (&im->lookup_main, ia);
188 if (ia->address_length <= 31)
189 {
190 addr->as_u32 = clib_host_to_net_u32 (x->as_u32);
Klement Sekeraf3bcdbf2017-05-02 07:38:01 +0200191 /*
192 * flip the last bit to get a different address, might be network,
193 * we don't care ...
194 */
195 addr->as_u32 ^= 1;
Klement Sekera239790f2017-02-16 10:53:53 +0100196 addr->as_u32 = clib_net_to_host_u32 (addr->as_u32);
197 return 1;
198 }
199 }));
200 /* *INDENT-ON* */
201 BFD_ERR ("cannot find ip4 address, no usable address found");
202 return 0;
203}
204
205int
206bfd_udp_get_echo_src_ip6 (ip6_address_t * addr)
207{
208 if (!bfd_udp_main.echo_source_is_set)
209 {
210 BFD_ERR ("cannot find ip6 address, echo source not set");
211 return 0;
212 }
213 ip_interface_address_t *ia = NULL;
214 ip6_main_t *im = &ip6_main;
215
216 /* *INDENT-OFF* */
217 foreach_ip_interface_address (
218 &im->lookup_main, ia, bfd_udp_main.echo_source_sw_if_index,
219 0 /* honor unnumbered */, ({
220 ip6_address_t *x =
221 ip_interface_address_get_address (&im->lookup_main, ia);
222 if (ia->address_length <= 127)
223 {
224 *addr = *x;
225 addr->as_u8[15] ^= 1; /* flip the last bit of the address */
Klement Sekera239790f2017-02-16 10:53:53 +0100226 return 1;
227 }
228 }));
229 /* *INDENT-ON* */
230 BFD_ERR ("cannot find ip6 address, no usable address found");
231 return 0;
232}
233
Klement Sekera73884482017-02-23 09:26:30 +0100234void
Klement Sekeraf3bcdbf2017-05-02 07:38:01 +0200235bfd_udp_get_echo_source (int *is_set, u32 * sw_if_index,
236 int *have_usable_ip4, ip4_address_t * ip4,
237 int *have_usable_ip6, ip6_address_t * ip6)
Klement Sekera73884482017-02-23 09:26:30 +0100238{
239 if (bfd_udp_main.echo_source_is_set)
240 {
241 *is_set = 1;
242 *sw_if_index = bfd_udp_main.echo_source_sw_if_index;
243 *have_usable_ip4 = bfd_udp_get_echo_src_ip4 (ip4);
244 *have_usable_ip6 = bfd_udp_get_echo_src_ip6 (ip6);
245 }
246 else
247 {
248 *is_set = 0;
249 }
250}
251
Klement Sekera239790f2017-02-16 10:53:53 +0100252int
Klement Sekeraf3bcdbf2017-05-02 07:38:01 +0200253bfd_add_udp4_transport (vlib_main_t * vm, u32 bi, const bfd_session_t * bs,
254 int is_echo)
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200255{
Klement Sekera2bce0332017-02-09 06:03:46 +0100256 const bfd_udp_session_t *bus = &bs->udp;
Klement Sekera46a87ad2017-01-02 08:22:23 +0100257 const bfd_udp_key_t *key = &bus->key;
Klement Sekerae50e8562017-04-04 16:19:48 +0200258 vlib_buffer_t *b = vlib_get_buffer (vm, bi);
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200259
Damjan Marion213b5aa2017-07-13 21:19:27 +0200260 b->flags |= VNET_BUFFER_F_LOCALLY_ORIGINATED;
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200261 vnet_buffer (b)->ip.adj_index[VLIB_RX] = bus->adj_index;
262 vnet_buffer (b)->ip.adj_index[VLIB_TX] = bus->adj_index;
Klement Sekerae50e8562017-04-04 16:19:48 +0200263 vnet_buffer (b)->sw_if_index[VLIB_RX] = 0;
264 vnet_buffer (b)->sw_if_index[VLIB_TX] = ~0;
Klement Sekera402ed312017-01-18 09:44:36 +0100265 typedef struct
266 {
267 ip4_header_t ip4;
268 udp_header_t udp;
269 } ip4_udp_headers;
Klement Sekerab17dd962017-01-09 07:43:48 +0100270 ip4_udp_headers *headers = NULL;
Klement Sekera402ed312017-01-18 09:44:36 +0100271 vlib_buffer_advance (b, -sizeof (*headers));
272 headers = vlib_buffer_get_current (b);
Dave Barachb7b92992018-10-17 10:38:51 -0400273 clib_memset (headers, 0, sizeof (*headers));
Klement Sekera402ed312017-01-18 09:44:36 +0100274 headers->ip4.ip_version_and_header_length = 0x45;
275 headers->ip4.ttl = 255;
276 headers->ip4.protocol = IP_PROTOCOL_UDP;
Klement Sekera2bce0332017-02-09 06:03:46 +0100277 headers->udp.src_port =
278 clib_host_to_net_u16 (bfd_udp_bs_idx_to_sport (bs->bs_idx));
Klement Sekera239790f2017-02-16 10:53:53 +0100279 if (is_echo)
280 {
281 int rv;
282 if (!(rv = bfd_udp_get_echo_src_ip4 (&headers->ip4.src_address)))
283 {
284 return rv;
285 }
286 headers->ip4.dst_address.as_u32 = key->local_addr.ip4.as_u32;
287 headers->udp.dst_port = clib_host_to_net_u16 (UDP_DST_PORT_bfd_echo4);
288 }
289 else
290 {
291 headers->ip4.src_address.as_u32 = key->local_addr.ip4.as_u32;
292 headers->ip4.dst_address.as_u32 = key->peer_addr.ip4.as_u32;
293 headers->udp.dst_port = clib_host_to_net_u16 (UDP_DST_PORT_bfd4);
294 }
Klement Sekera46a87ad2017-01-02 08:22:23 +0100295
296 /* fix ip length, checksum and udp length */
297 const u16 ip_length = vlib_buffer_length_in_chain (vm, b);
298
Klement Sekera402ed312017-01-18 09:44:36 +0100299 headers->ip4.length = clib_host_to_net_u16 (ip_length);
300 headers->ip4.checksum = ip4_header_checksum (&headers->ip4);
Klement Sekera46a87ad2017-01-02 08:22:23 +0100301
Klement Sekera402ed312017-01-18 09:44:36 +0100302 const u16 udp_length = ip_length - (sizeof (headers->ip4));
303 headers->udp.length = clib_host_to_net_u16 (udp_length);
Klement Sekera239790f2017-02-16 10:53:53 +0100304 return 1;
Klement Sekera46a87ad2017-01-02 08:22:23 +0100305}
306
Klement Sekera239790f2017-02-16 10:53:53 +0100307int
Klement Sekeraf3bcdbf2017-05-02 07:38:01 +0200308bfd_add_udp6_transport (vlib_main_t * vm, u32 bi, const bfd_session_t * bs,
309 int is_echo)
Klement Sekera46a87ad2017-01-02 08:22:23 +0100310{
Klement Sekera2bce0332017-02-09 06:03:46 +0100311 const bfd_udp_session_t *bus = &bs->udp;
Klement Sekera46a87ad2017-01-02 08:22:23 +0100312 const bfd_udp_key_t *key = &bus->key;
Klement Sekerae50e8562017-04-04 16:19:48 +0200313 vlib_buffer_t *b = vlib_get_buffer (vm, bi);
Klement Sekera46a87ad2017-01-02 08:22:23 +0100314
Damjan Marion213b5aa2017-07-13 21:19:27 +0200315 b->flags |= VNET_BUFFER_F_LOCALLY_ORIGINATED;
Klement Sekera46a87ad2017-01-02 08:22:23 +0100316 vnet_buffer (b)->ip.adj_index[VLIB_RX] = bus->adj_index;
317 vnet_buffer (b)->ip.adj_index[VLIB_TX] = bus->adj_index;
Klement Sekerae50e8562017-04-04 16:19:48 +0200318 vnet_buffer (b)->sw_if_index[VLIB_RX] = 0;
319 vnet_buffer (b)->sw_if_index[VLIB_TX] = 0;
Klement Sekera402ed312017-01-18 09:44:36 +0100320 typedef struct
321 {
322 ip6_header_t ip6;
323 udp_header_t udp;
324 } ip6_udp_headers;
Klement Sekerab17dd962017-01-09 07:43:48 +0100325 ip6_udp_headers *headers = NULL;
326 vlib_buffer_advance (b, -sizeof (*headers));
327 headers = vlib_buffer_get_current (b);
Dave Barachb7b92992018-10-17 10:38:51 -0400328 clib_memset (headers, 0, sizeof (*headers));
Klement Sekera402ed312017-01-18 09:44:36 +0100329 headers->ip6.ip_version_traffic_class_and_flow_label =
Klement Sekerac5fccc02017-01-18 09:56:00 +0100330 clib_host_to_net_u32 (0x6 << 28);
Klement Sekera402ed312017-01-18 09:44:36 +0100331 headers->ip6.hop_limit = 255;
332 headers->ip6.protocol = IP_PROTOCOL_UDP;
Klement Sekera2bce0332017-02-09 06:03:46 +0100333 headers->udp.src_port =
334 clib_host_to_net_u16 (bfd_udp_bs_idx_to_sport (bs->bs_idx));
Klement Sekera239790f2017-02-16 10:53:53 +0100335 if (is_echo)
336 {
337 int rv;
338 if (!(rv = bfd_udp_get_echo_src_ip6 (&headers->ip6.src_address)))
339 {
340 return rv;
341 }
Dave Barach178cf492018-11-13 16:34:13 -0500342 clib_memcpy_fast (&headers->ip6.dst_address, &key->local_addr.ip6,
343 sizeof (headers->ip6.dst_address));
Klement Sekera239790f2017-02-16 10:53:53 +0100344
345 headers->udp.dst_port = clib_host_to_net_u16 (UDP_DST_PORT_bfd_echo6);
346 }
347 else
348 {
Dave Barach178cf492018-11-13 16:34:13 -0500349 clib_memcpy_fast (&headers->ip6.src_address, &key->local_addr.ip6,
350 sizeof (headers->ip6.src_address));
351 clib_memcpy_fast (&headers->ip6.dst_address, &key->peer_addr.ip6,
352 sizeof (headers->ip6.dst_address));
Klement Sekera239790f2017-02-16 10:53:53 +0100353 headers->udp.dst_port = clib_host_to_net_u16 (UDP_DST_PORT_bfd6);
354 }
Klement Sekera46a87ad2017-01-02 08:22:23 +0100355
356 /* fix ip payload length and udp length */
Klement Sekerac5fccc02017-01-18 09:56:00 +0100357 const u16 udp_length =
Klement Sekera402ed312017-01-18 09:44:36 +0100358 vlib_buffer_length_in_chain (vm, b) - (sizeof (headers->ip6));
359 headers->udp.length = clib_host_to_net_u16 (udp_length);
360 headers->ip6.payload_length = headers->udp.length;
Klement Sekera46a87ad2017-01-02 08:22:23 +0100361
362 /* IPv6 UDP checksum is mandatory */
363 int bogus = 0;
Klement Sekera402ed312017-01-18 09:44:36 +0100364 headers->udp.checksum =
365 ip6_tcp_udp_icmp_compute_checksum (vm, b, &headers->ip6, &bogus);
Klement Sekera46a87ad2017-01-02 08:22:23 +0100366 ASSERT (bogus == 0);
Klement Sekera402ed312017-01-18 09:44:36 +0100367 if (headers->udp.checksum == 0)
Klement Sekera46a87ad2017-01-02 08:22:23 +0100368 {
Klement Sekera402ed312017-01-18 09:44:36 +0100369 headers->udp.checksum = 0xffff;
Klement Sekera46a87ad2017-01-02 08:22:23 +0100370 }
Klement Sekera239790f2017-02-16 10:53:53 +0100371 return 1;
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200372}
373
Klement Sekerae50e8562017-04-04 16:19:48 +0200374static void
Klement Sekera617d4292022-09-20 15:10:10 +0200375bfd_create_frame_to_next_node (vlib_main_t *vm, vlib_node_runtime_t *rt,
376 u32 bi, const bfd_session_t *bs, u32 next,
Klement Sekeracdaf0d82022-02-14 20:20:22 +0000377 vlib_combined_counter_main_t *tx_counter)
Klement Sekerae50e8562017-04-04 16:19:48 +0200378{
Klement Sekera617d4292022-09-20 15:10:10 +0200379 vlib_buffer_t *b = vlib_get_buffer (vm, bi);
380 vlib_node_t *from_node = vlib_get_node (vm, rt->node_index);
381 ASSERT (next < vec_len (from_node->next_nodes));
382 u32 to_node_index = from_node->next_nodes[next];
383 vlib_frame_t *f = vlib_get_frame_to_node (vm, to_node_index);
Klement Sekerae50e8562017-04-04 16:19:48 +0200384 u32 *to_next = vlib_frame_vector_args (f);
385 to_next[0] = bi;
386 f->n_vectors = 1;
Klement Sekera617d4292022-09-20 15:10:10 +0200387 if (b->flags & VLIB_BUFFER_IS_TRACED)
388 {
389 f->frame_flags |= VLIB_NODE_FLAG_TRACE;
390 }
391 vlib_put_frame_to_node (vm, to_node_index, f);
Klement Sekeracdaf0d82022-02-14 20:20:22 +0000392 vlib_increment_combined_counter (tx_counter, vm->thread_index, bs->bs_idx, 1,
393 vlib_buffer_length_in_chain (vm, b));
Klement Sekerae50e8562017-04-04 16:19:48 +0200394}
395
396int
397bfd_udp_calc_next_node (const struct bfd_session_s *bs, u32 * next_node)
398{
Matthew G Smith2f260142019-05-22 14:49:24 -0500399 vnet_main_t *vnm = vnet_get_main ();
Klement Sekerae50e8562017-04-04 16:19:48 +0200400 const bfd_udp_session_t *bus = &bs->udp;
401 ip_adjacency_t *adj = adj_get (bus->adj_index);
Matthew G Smith2f260142019-05-22 14:49:24 -0500402
403 /* don't try to send the buffer if the interface is not up */
404 if (!vnet_sw_interface_is_up (vnm, bus->key.sw_if_index))
405 return 0;
406
Klement Sekerae50e8562017-04-04 16:19:48 +0200407 switch (adj->lookup_next_index)
408 {
409 case IP_LOOKUP_NEXT_ARP:
410 switch (bs->transport)
411 {
412 case BFD_TRANSPORT_UDP4:
Klement Sekera617d4292022-09-20 15:10:10 +0200413 *next_node = BFD_TX_IP4_ARP;
Klement Sekerae50e8562017-04-04 16:19:48 +0200414 return 1;
415 case BFD_TRANSPORT_UDP6:
Klement Sekera617d4292022-09-20 15:10:10 +0200416 *next_node = BFD_TX_IP6_NDP;
Klement Sekerae50e8562017-04-04 16:19:48 +0200417 return 1;
418 }
419 break;
420 case IP_LOOKUP_NEXT_REWRITE:
421 switch (bs->transport)
422 {
423 case BFD_TRANSPORT_UDP4:
Klement Sekera617d4292022-09-20 15:10:10 +0200424 *next_node = BFD_TX_IP4_REWRITE;
Klement Sekerae50e8562017-04-04 16:19:48 +0200425 return 1;
426 case BFD_TRANSPORT_UDP6:
Klement Sekera617d4292022-09-20 15:10:10 +0200427 *next_node = BFD_TX_IP6_REWRITE;
Klement Sekerae50e8562017-04-04 16:19:48 +0200428 return 1;
429 }
430 break;
Matthew G Smith2f260142019-05-22 14:49:24 -0500431 case IP_LOOKUP_NEXT_MIDCHAIN:
432 switch (bs->transport)
433 {
434 case BFD_TRANSPORT_UDP4:
Klement Sekera617d4292022-09-20 15:10:10 +0200435 *next_node = BFD_TX_IP4_MIDCHAIN;
Matthew G Smith2f260142019-05-22 14:49:24 -0500436 return 1;
437 case BFD_TRANSPORT_UDP6:
Klement Sekera617d4292022-09-20 15:10:10 +0200438 *next_node = BFD_TX_IP6_MIDCHAIN;
Matthew G Smith2f260142019-05-22 14:49:24 -0500439 return 1;
440 }
441 break;
Klement Sekerae50e8562017-04-04 16:19:48 +0200442 default:
443 /* drop */
444 break;
445 }
446 return 0;
447}
448
449int
Klement Sekera617d4292022-09-20 15:10:10 +0200450bfd_transport_udp4 (vlib_main_t *vm, vlib_node_runtime_t *rt, u32 bi,
451 const struct bfd_session_s *bs, int is_echo)
Klement Sekerae50e8562017-04-04 16:19:48 +0200452{
453 u32 next_node;
454 int rv = bfd_udp_calc_next_node (bs, &next_node);
Klement Sekeracdaf0d82022-02-14 20:20:22 +0000455 bfd_main_t *bm = bfd_udp_main.bfd_main;
Klement Sekerae50e8562017-04-04 16:19:48 +0200456 if (rv)
457 {
Klement Sekera617d4292022-09-20 15:10:10 +0200458 bfd_create_frame_to_next_node (vm, rt, bi, bs, next_node,
Klement Sekeracdaf0d82022-02-14 20:20:22 +0000459 is_echo ? &bm->tx_echo_counter :
Klement Sekera617d4292022-09-20 15:10:10 +0200460 &bm->tx_counter);
Klement Sekerae50e8562017-04-04 16:19:48 +0200461 }
462 return rv;
463}
464
465int
Klement Sekera617d4292022-09-20 15:10:10 +0200466bfd_transport_udp6 (vlib_main_t *vm, vlib_node_runtime_t *rt, u32 bi,
467 const struct bfd_session_s *bs, int is_echo)
Klement Sekerae50e8562017-04-04 16:19:48 +0200468{
469 u32 next_node;
470 int rv = bfd_udp_calc_next_node (bs, &next_node);
Klement Sekeracdaf0d82022-02-14 20:20:22 +0000471 bfd_main_t *bm = bfd_udp_main.bfd_main;
Klement Sekerae50e8562017-04-04 16:19:48 +0200472 if (rv)
473 {
Klement Sekera617d4292022-09-20 15:10:10 +0200474 bfd_create_frame_to_next_node (vm, rt, bi, bs, next_node,
475 is_echo ? &bm->tx_echo_counter :
476 &bm->tx_counter);
Klement Sekerae50e8562017-04-04 16:19:48 +0200477 }
478 return 1;
479}
480
Klement Sekerac5fccc02017-01-18 09:56:00 +0100481static bfd_session_t *
482bfd_lookup_session (bfd_udp_main_t * bum, const bfd_udp_key_t * key)
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200483{
484 uword *p = mhash_get (&bum->bfd_session_idx_by_bfd_key, key);
485 if (p)
486 {
487 return bfd_find_session_by_idx (bum->bfd_main, *p);
488 }
489 return 0;
490}
491
Klement Sekerab17dd962017-01-09 07:43:48 +0100492static void
493bfd_udp_key_init (bfd_udp_key_t * key, u32 sw_if_index,
494 const ip46_address_t * local_addr,
495 const ip46_address_t * peer_addr)
496{
Dave Barachb7b92992018-10-17 10:38:51 -0400497 clib_memset (key, 0, sizeof (*key));
Klement Sekerab17dd962017-01-09 07:43:48 +0100498 key->sw_if_index = sw_if_index;
499 key->local_addr.as_u64[0] = local_addr->as_u64[0];
500 key->local_addr.as_u64[1] = local_addr->as_u64[1];
501 key->peer_addr.as_u64[0] = peer_addr->as_u64[0];
502 key->peer_addr.as_u64[1] = peer_addr->as_u64[1];
503}
504
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200505static vnet_api_error_t
Klement Sekera88aec652019-03-11 14:04:19 +0100506bfd_udp_add_session_internal (vlib_main_t * vm, bfd_udp_main_t * bum,
507 u32 sw_if_index, u32 desired_min_tx_usec,
Klement Sekeraa57a9702017-02-02 06:58:07 +0100508 u32 required_min_rx_usec, u8 detect_mult,
Klement Sekerac5fccc02017-01-18 09:56:00 +0100509 const ip46_address_t * local_addr,
510 const ip46_address_t * peer_addr,
Klement Sekerab17dd962017-01-09 07:43:48 +0100511 bfd_session_t ** bs_out)
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200512{
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200513 /* get a pool entry and if we end up not needing it, give it back */
Klement Sekera239790f2017-02-16 10:53:53 +0100514 bfd_transport_e t = BFD_TRANSPORT_UDP4;
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200515 if (!ip46_address_is_ip4 (local_addr))
516 {
517 t = BFD_TRANSPORT_UDP6;
518 }
519 bfd_session_t *bs = bfd_get_session (bum->bfd_main, t);
Klement Sekera239790f2017-02-16 10:53:53 +0100520 if (!bs)
521 {
Klement Sekera239790f2017-02-16 10:53:53 +0100522 return VNET_API_ERROR_BFD_EAGAIN;
523 }
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200524 bfd_udp_session_t *bus = &bs->udp;
Dave Barachb7b92992018-10-17 10:38:51 -0400525 clib_memset (bus, 0, sizeof (*bus));
Neale Ranns32fd89b2022-02-15 08:28:19 +0000526 bus->adj_index = ADJ_INDEX_INVALID;
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200527 bfd_udp_key_t *key = &bus->key;
Klement Sekerab17dd962017-01-09 07:43:48 +0100528 bfd_udp_key_init (key, sw_if_index, local_addr, peer_addr);
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200529 const bfd_session_t *tmp = bfd_lookup_session (bum, key);
530 if (tmp)
531 {
Damjan Marion07a38572018-01-21 06:44:18 -0800532 vlib_log_err (bum->log_class,
533 "duplicate bfd-udp session, existing bs_idx=%d",
Klement Sekerab17dd962017-01-09 07:43:48 +0100534 tmp->bs_idx);
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200535 bfd_put_session (bum->bfd_main, bs);
536 return VNET_API_ERROR_BFD_EEXIST;
537 }
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200538 mhash_set (&bum->bfd_session_idx_by_bfd_key, key, bs->bs_idx, NULL);
539 BFD_DBG ("session created, bs_idx=%u, sw_if_index=%d, local=%U, peer=%U",
Klement Sekerac5fccc02017-01-18 09:56:00 +0100540 bs->bs_idx, key->sw_if_index, format_ip46_address,
541 &key->local_addr, IP46_TYPE_ANY, format_ip46_address,
542 &key->peer_addr, IP46_TYPE_ANY);
Damjan Marion07a38572018-01-21 06:44:18 -0800543 vlib_log_info (bum->log_class, "create BFD session: %U",
544 format_bfd_session, bs);
Neale Ranns558a3542022-02-15 08:24:48 +0000545 const ip46_address_t *peer =
546 (vnet_sw_interface_is_p2p (vnet_get_main (), key->sw_if_index) ?
547 &zero_addr :
548 &key->peer_addr);
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200549 if (BFD_TRANSPORT_UDP4 == t)
550 {
551 bus->adj_index = adj_nbr_add_or_lock (FIB_PROTOCOL_IP4, VNET_LINK_IP4,
Neale Ranns558a3542022-02-15 08:24:48 +0000552 peer, key->sw_if_index);
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200553 BFD_DBG ("adj_nbr_add_or_lock(FIB_PROTOCOL_IP4, VNET_LINK_IP4, %U, %d) "
Neale Ranns558a3542022-02-15 08:24:48 +0000554 "returns %d",
555 format_ip46_address, peer, IP46_TYPE_ANY, key->sw_if_index,
556 bus->adj_index);
Klement Sekera88aec652019-03-11 14:04:19 +0100557 ++bum->udp4_sessions_count;
Klement Sekeracdaf0d82022-02-14 20:20:22 +0000558 bfd_udp_update_stat_segment_entry (
559 bum->udp4_sessions_count_stat_seg_entry, bum->udp4_sessions_count);
Klement Sekera88aec652019-03-11 14:04:19 +0100560 if (1 == bum->udp4_sessions_count)
561 {
562 udp_register_dst_port (vm, UDP_DST_PORT_bfd4,
563 bfd_udp4_input_node.index, 1);
564 udp_register_dst_port (vm, UDP_DST_PORT_bfd_echo4,
565 bfd_udp_echo4_input_node.index, 1);
566 }
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200567 }
568 else
569 {
570 bus->adj_index = adj_nbr_add_or_lock (FIB_PROTOCOL_IP6, VNET_LINK_IP6,
Neale Ranns558a3542022-02-15 08:24:48 +0000571 peer, key->sw_if_index);
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200572 BFD_DBG ("adj_nbr_add_or_lock(FIB_PROTOCOL_IP6, VNET_LINK_IP6, %U, %d) "
Neale Ranns558a3542022-02-15 08:24:48 +0000573 "returns %d",
574 format_ip46_address, peer, IP46_TYPE_ANY, key->sw_if_index,
575 bus->adj_index);
Klement Sekera88aec652019-03-11 14:04:19 +0100576 ++bum->udp6_sessions_count;
Klement Sekeracdaf0d82022-02-14 20:20:22 +0000577 bfd_udp_update_stat_segment_entry (
578 bum->udp6_sessions_count_stat_seg_entry, bum->udp6_sessions_count);
Klement Sekera88aec652019-03-11 14:04:19 +0100579 if (1 == bum->udp6_sessions_count)
580 {
581 udp_register_dst_port (vm, UDP_DST_PORT_bfd6,
582 bfd_udp6_input_node.index, 0);
583 udp_register_dst_port (vm, UDP_DST_PORT_bfd_echo6,
584 bfd_udp_echo6_input_node.index, 0);
585 }
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200586 }
Klement Sekerab17dd962017-01-09 07:43:48 +0100587 *bs_out = bs;
Klement Sekeraa57a9702017-02-02 06:58:07 +0100588 return bfd_session_set_params (bum->bfd_main, bs, desired_min_tx_usec,
589 required_min_rx_usec, detect_mult);
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200590}
591
592static vnet_api_error_t
Klement Sekerac5fccc02017-01-18 09:56:00 +0100593bfd_udp_validate_api_input (u32 sw_if_index,
594 const ip46_address_t * local_addr,
595 const ip46_address_t * peer_addr)
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200596{
Damjan Marion07a38572018-01-21 06:44:18 -0800597 bfd_udp_main_t *bum = &bfd_udp_main;
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200598 vnet_sw_interface_t *sw_if =
Dave Barach3940de32019-07-23 16:28:36 -0400599 vnet_get_sw_interface_or_null (bfd_udp_main.vnet_main, sw_if_index);
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200600 if (!sw_if)
601 {
Damjan Marion07a38572018-01-21 06:44:18 -0800602 vlib_log_err (bum->log_class,
603 "got NULL sw_if when getting interface by index %u",
604 sw_if_index);
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200605 return VNET_API_ERROR_INVALID_SW_IF_INDEX;
606 }
607 if (ip46_address_is_ip4 (local_addr))
608 {
609 if (!ip46_address_is_ip4 (peer_addr))
Klement Sekerac5fccc02017-01-18 09:56:00 +0100610 {
Damjan Marion07a38572018-01-21 06:44:18 -0800611 vlib_log_err (bum->log_class,
612 "IP family mismatch (local is ipv4, peer is ipv6)");
Klement Sekerac5fccc02017-01-18 09:56:00 +0100613 return VNET_API_ERROR_INVALID_ARGUMENT;
614 }
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200615 }
616 else
617 {
618 if (ip46_address_is_ip4 (peer_addr))
Klement Sekerac5fccc02017-01-18 09:56:00 +0100619 {
Damjan Marion07a38572018-01-21 06:44:18 -0800620 vlib_log_err (bum->log_class,
621 "IP family mismatch (local is ipv6, peer is ipv4)");
Klement Sekerac5fccc02017-01-18 09:56:00 +0100622 return VNET_API_ERROR_INVALID_ARGUMENT;
623 }
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200624 }
625
626 return 0;
627}
628
Klement Sekerab17dd962017-01-09 07:43:48 +0100629static vnet_api_error_t
630bfd_udp_find_session_by_api_input (u32 sw_if_index,
631 const ip46_address_t * local_addr,
632 const ip46_address_t * peer_addr,
633 bfd_session_t ** bs_out)
634{
635 vnet_api_error_t rv =
636 bfd_udp_validate_api_input (sw_if_index, local_addr, peer_addr);
637 if (!rv)
638 {
639 bfd_udp_main_t *bum = &bfd_udp_main;
640 bfd_udp_key_t key;
641 bfd_udp_key_init (&key, sw_if_index, local_addr, peer_addr);
642 bfd_session_t *bs = bfd_lookup_session (bum, &key);
643 if (bs)
644 {
645 *bs_out = bs;
646 }
647 else
648 {
Damjan Marion07a38572018-01-21 06:44:18 -0800649 vlib_log_err (bum->log_class,
650 "BFD session not found, sw_if_index=%u, local=%U, peer=%U",
651 sw_if_index, format_ip46_address, local_addr,
652 IP46_TYPE_ANY, format_ip46_address, peer_addr,
653 IP46_TYPE_ANY);
Klement Sekerab17dd962017-01-09 07:43:48 +0100654 return VNET_API_ERROR_BFD_ENOENT;
655 }
656 }
657 return rv;
658}
659
660static vnet_api_error_t
Klement Sekeraa57a9702017-02-02 06:58:07 +0100661bfd_api_verify_common (u32 sw_if_index, u32 desired_min_tx_usec,
Klement Sekerab59f63b2022-02-14 20:19:28 +0000662 u8 detect_mult, const ip46_address_t *local_addr,
663 const ip46_address_t *peer_addr)
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200664{
Damjan Marion07a38572018-01-21 06:44:18 -0800665 bfd_udp_main_t *bum = &bfd_udp_main;
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200666 vnet_api_error_t rv =
Klement Sekerac5fccc02017-01-18 09:56:00 +0100667 bfd_udp_validate_api_input (sw_if_index, local_addr, peer_addr);
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200668 if (rv)
669 {
670 return rv;
671 }
672 if (detect_mult < 1)
673 {
Damjan Marion07a38572018-01-21 06:44:18 -0800674 vlib_log_err (bum->log_class, "detect_mult < 1");
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200675 return VNET_API_ERROR_INVALID_ARGUMENT;
676 }
Klement Sekeraa57a9702017-02-02 06:58:07 +0100677 if (desired_min_tx_usec < 1)
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200678 {
Damjan Marion07a38572018-01-21 06:44:18 -0800679 vlib_log_err (bum->log_class, "desired_min_tx_usec < 1");
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200680 return VNET_API_ERROR_INVALID_ARGUMENT;
681 }
Klement Sekerab17dd962017-01-09 07:43:48 +0100682 return 0;
683}
684
685static void
Klement Sekera88aec652019-03-11 14:04:19 +0100686bfd_udp_del_session_internal (vlib_main_t * vm, bfd_session_t * bs)
Klement Sekerab17dd962017-01-09 07:43:48 +0100687{
688 bfd_udp_main_t *bum = &bfd_udp_main;
689 BFD_DBG ("free bfd-udp session, bs_idx=%d", bs->bs_idx);
Neale Ranns32fd89b2022-02-15 08:28:19 +0000690 bfd_session_stop (bum->bfd_main, bs);
Klement Sekerab17dd962017-01-09 07:43:48 +0100691 mhash_unset (&bum->bfd_session_idx_by_bfd_key, &bs->udp.key, NULL);
692 adj_unlock (bs->udp.adj_index);
Klement Sekera88aec652019-03-11 14:04:19 +0100693 switch (bs->transport)
694 {
695 case BFD_TRANSPORT_UDP4:
696 --bum->udp4_sessions_count;
Klement Sekeracdaf0d82022-02-14 20:20:22 +0000697 bfd_udp_update_stat_segment_entry (
698 bum->udp4_sessions_count_stat_seg_entry, bum->udp4_sessions_count);
Klement Sekera88aec652019-03-11 14:04:19 +0100699 if (!bum->udp4_sessions_count)
700 {
701 udp_unregister_dst_port (vm, UDP_DST_PORT_bfd4, 1);
702 udp_unregister_dst_port (vm, UDP_DST_PORT_bfd_echo4, 1);
703 }
704 break;
705 case BFD_TRANSPORT_UDP6:
706 --bum->udp6_sessions_count;
Klement Sekeracdaf0d82022-02-14 20:20:22 +0000707 bfd_udp_update_stat_segment_entry (
708 bum->udp6_sessions_count_stat_seg_entry, bum->udp6_sessions_count);
Klement Sekera88aec652019-03-11 14:04:19 +0100709 if (!bum->udp6_sessions_count)
710 {
711 udp_unregister_dst_port (vm, UDP_DST_PORT_bfd6, 0);
712 udp_unregister_dst_port (vm, UDP_DST_PORT_bfd_echo6, 0);
713 }
714 break;
715 }
Klement Sekerab17dd962017-01-09 07:43:48 +0100716 bfd_put_session (bum->bfd_main, bs);
717}
718
Neale Ranns63f2c7d2022-02-09 13:47:29 +0000719static vnet_api_error_t
720bfd_udp_add_and_start_session (u32 sw_if_index,
721 const ip46_address_t *local_addr,
722 const ip46_address_t *peer_addr,
723 u32 desired_min_tx_usec,
724 u32 required_min_rx_usec, u8 detect_mult,
725 u8 is_authenticated, u32 conf_key_id,
726 u8 bfd_key_id)
727{
728 bfd_session_t *bs = NULL;
729 vnet_api_error_t rv;
730
731 rv = bfd_udp_add_session_internal (
732 vlib_get_main (), &bfd_udp_main, sw_if_index, desired_min_tx_usec,
733 required_min_rx_usec, detect_mult, local_addr, peer_addr, &bs);
734
735 if (!rv && is_authenticated)
736 {
737 rv = bfd_auth_activate (bs, conf_key_id, bfd_key_id,
738 0 /* is not delayed */);
739 if (rv)
740 {
741 bfd_udp_del_session_internal (vlib_get_main (), bs);
742 }
743 }
744 if (!rv)
745 {
746 bfd_session_start (bfd_udp_main.bfd_main, bs);
747 }
748
749 return rv;
750}
751
Klement Sekerab17dd962017-01-09 07:43:48 +0100752vnet_api_error_t
753bfd_udp_add_session (u32 sw_if_index, const ip46_address_t * local_addr,
Klement Sekeraa57a9702017-02-02 06:58:07 +0100754 const ip46_address_t * peer_addr,
755 u32 desired_min_tx_usec, u32 required_min_rx_usec,
756 u8 detect_mult, u8 is_authenticated, u32 conf_key_id,
757 u8 bfd_key_id)
Klement Sekerab17dd962017-01-09 07:43:48 +0100758{
Dave Barach1e3417f2018-07-25 08:30:27 -0400759 bfd_main_t *bm = &bfd_main;
760 bfd_lock (bm);
761
Klement Sekerab59f63b2022-02-14 20:19:28 +0000762 vnet_api_error_t rv = bfd_api_verify_common (
763 sw_if_index, desired_min_tx_usec, detect_mult, local_addr, peer_addr);
Neale Ranns63f2c7d2022-02-09 13:47:29 +0000764
765 if (!rv)
766 rv = bfd_udp_add_and_start_session (
767 sw_if_index, local_addr, peer_addr, desired_min_tx_usec,
768 required_min_rx_usec, detect_mult, is_authenticated, conf_key_id,
769 bfd_key_id);
770
771 bfd_unlock (bm);
772 return rv;
773}
774
775vnet_api_error_t
776bfd_udp_upd_session (u32 sw_if_index, const ip46_address_t *local_addr,
777 const ip46_address_t *peer_addr, u32 desired_min_tx_usec,
778 u32 required_min_rx_usec, u8 detect_mult,
779 u8 is_authenticated, u32 conf_key_id, u8 bfd_key_id)
780{
781 bfd_main_t *bm = &bfd_main;
782 bfd_lock (bm);
783
784 vnet_api_error_t rv = bfd_api_verify_common (
Klement Sekerab59f63b2022-02-14 20:19:28 +0000785 sw_if_index, desired_min_tx_usec, detect_mult, local_addr, peer_addr);
Klement Sekerab17dd962017-01-09 07:43:48 +0100786 if (!rv)
787 {
Neale Ranns63f2c7d2022-02-09 13:47:29 +0000788 bfd_session_t *bs = NULL;
789
790 rv = bfd_udp_find_session_by_api_input (sw_if_index, local_addr,
791 peer_addr, &bs);
792 if (VNET_API_ERROR_BFD_ENOENT == rv)
793 rv = bfd_udp_add_and_start_session (
794 sw_if_index, local_addr, peer_addr, desired_min_tx_usec,
795 required_min_rx_usec, detect_mult, is_authenticated, conf_key_id,
796 bfd_key_id);
797 else
798 rv = bfd_session_set_params (bfd_udp_main.bfd_main, bs,
799 desired_min_tx_usec, required_min_rx_usec,
800 detect_mult);
Klement Sekerab17dd962017-01-09 07:43:48 +0100801 }
802
Dave Barach1e3417f2018-07-25 08:30:27 -0400803 bfd_unlock (bm);
Klement Sekerab17dd962017-01-09 07:43:48 +0100804 return rv;
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200805}
806
Klement Sekerac5fccc02017-01-18 09:56:00 +0100807vnet_api_error_t
Neale Ranns63f2c7d2022-02-09 13:47:29 +0000808bfd_udp_mod_session (u32 sw_if_index, const ip46_address_t *local_addr,
809 const ip46_address_t *peer_addr, u32 desired_min_tx_usec,
Klement Sekeraa57a9702017-02-02 06:58:07 +0100810 u32 required_min_rx_usec, u8 detect_mult)
811{
812 bfd_session_t *bs = NULL;
Dave Barach1e3417f2018-07-25 08:30:27 -0400813 bfd_main_t *bm = &bfd_main;
814 vnet_api_error_t error;
815 bfd_lock (bm);
Klement Sekeraa57a9702017-02-02 06:58:07 +0100816 vnet_api_error_t rv =
817 bfd_udp_find_session_by_api_input (sw_if_index, local_addr, peer_addr,
818 &bs);
819 if (rv)
820 {
Dave Barach1e3417f2018-07-25 08:30:27 -0400821 bfd_unlock (bm);
Klement Sekeraa57a9702017-02-02 06:58:07 +0100822 return rv;
823 }
824
Dave Barach1e3417f2018-07-25 08:30:27 -0400825 error = bfd_session_set_params (bfd_udp_main.bfd_main, bs,
826 desired_min_tx_usec, required_min_rx_usec,
827 detect_mult);
828 bfd_unlock (bm);
829 return error;
Klement Sekeraa57a9702017-02-02 06:58:07 +0100830}
831
832vnet_api_error_t
Klement Sekerac5fccc02017-01-18 09:56:00 +0100833bfd_udp_del_session (u32 sw_if_index,
834 const ip46_address_t * local_addr,
835 const ip46_address_t * peer_addr)
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200836{
Klement Sekerab17dd962017-01-09 07:43:48 +0100837 bfd_session_t *bs = NULL;
Dave Barach1e3417f2018-07-25 08:30:27 -0400838 bfd_main_t *bm = &bfd_main;
839 bfd_lock (bm);
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200840 vnet_api_error_t rv =
Klement Sekerab17dd962017-01-09 07:43:48 +0100841 bfd_udp_find_session_by_api_input (sw_if_index, local_addr, peer_addr,
842 &bs);
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200843 if (rv)
844 {
Dave Barach1e3417f2018-07-25 08:30:27 -0400845 bfd_unlock (bm);
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200846 return rv;
847 }
Klement Sekera88aec652019-03-11 14:04:19 +0100848 bfd_udp_del_session_internal (vlib_get_main (), bs);
Dave Barach1e3417f2018-07-25 08:30:27 -0400849 bfd_unlock (bm);
Klement Sekerab17dd962017-01-09 07:43:48 +0100850 return 0;
851}
852
853vnet_api_error_t
Klement Sekeraa3167442020-02-10 11:49:52 +0000854bfd_udp_session_set_flags (vlib_main_t * vm, u32 sw_if_index,
Klement Sekerab17dd962017-01-09 07:43:48 +0100855 const ip46_address_t * local_addr,
856 const ip46_address_t * peer_addr, u8 admin_up_down)
857{
858 bfd_session_t *bs = NULL;
Dave Barach1e3417f2018-07-25 08:30:27 -0400859 bfd_main_t *bm = &bfd_main;
860 bfd_lock (bm);
Klement Sekerab17dd962017-01-09 07:43:48 +0100861 vnet_api_error_t rv =
862 bfd_udp_find_session_by_api_input (sw_if_index, local_addr, peer_addr,
863 &bs);
864 if (rv)
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200865 {
Dave Barach1e3417f2018-07-25 08:30:27 -0400866 bfd_unlock (bm);
Klement Sekerab17dd962017-01-09 07:43:48 +0100867 return rv;
868 }
Klement Sekeraa3167442020-02-10 11:49:52 +0000869 bfd_session_set_flags (vm, bs, admin_up_down);
Dave Barach1e3417f2018-07-25 08:30:27 -0400870 bfd_unlock (bm);
Klement Sekerab17dd962017-01-09 07:43:48 +0100871 return 0;
872}
873
874vnet_api_error_t
Klement Sekerab17dd962017-01-09 07:43:48 +0100875bfd_udp_auth_activate (u32 sw_if_index,
876 const ip46_address_t * local_addr,
877 const ip46_address_t * peer_addr,
878 u32 conf_key_id, u8 key_id, u8 is_delayed)
879{
Dave Barach1e3417f2018-07-25 08:30:27 -0400880 bfd_main_t *bm = &bfd_main;
881 bfd_lock (bm);
882 vnet_api_error_t error;
883
Klement Sekerab17dd962017-01-09 07:43:48 +0100884 bfd_session_t *bs = NULL;
885 vnet_api_error_t rv =
886 bfd_udp_find_session_by_api_input (sw_if_index, local_addr, peer_addr,
887 &bs);
888 if (rv)
889 {
Dave Barach1e3417f2018-07-25 08:30:27 -0400890 bfd_unlock (bm);
Klement Sekerab17dd962017-01-09 07:43:48 +0100891 return rv;
892 }
Dave Barach1e3417f2018-07-25 08:30:27 -0400893 error = bfd_auth_activate (bs, conf_key_id, key_id, is_delayed);
894 bfd_unlock (bm);
895 return error;
Klement Sekerab17dd962017-01-09 07:43:48 +0100896}
897
898vnet_api_error_t
899bfd_udp_auth_deactivate (u32 sw_if_index,
900 const ip46_address_t * local_addr,
901 const ip46_address_t * peer_addr, u8 is_delayed)
902{
Dave Barach1e3417f2018-07-25 08:30:27 -0400903 bfd_main_t *bm = &bfd_main;
904 vnet_api_error_t error;
905 bfd_lock (bm);
Klement Sekerab17dd962017-01-09 07:43:48 +0100906 bfd_session_t *bs = NULL;
907 vnet_api_error_t rv =
908 bfd_udp_find_session_by_api_input (sw_if_index, local_addr, peer_addr,
909 &bs);
910 if (rv)
911 {
Dave Barach1e3417f2018-07-25 08:30:27 -0400912 bfd_unlock (bm);
Klement Sekerab17dd962017-01-09 07:43:48 +0100913 return rv;
914 }
Dave Barach1e3417f2018-07-25 08:30:27 -0400915 error = bfd_auth_deactivate (bs, is_delayed);
916 bfd_unlock (bm);
917 return error;
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200918}
919
Klement Sekerac5fccc02017-01-18 09:56:00 +0100920typedef enum
921{
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200922 BFD_UDP_INPUT_NEXT_NORMAL,
Klement Sekerae50e8562017-04-04 16:19:48 +0200923 BFD_UDP_INPUT_NEXT_REPLY_ARP,
924 BFD_UDP_INPUT_NEXT_REPLY_REWRITE,
Matthew G Smith2f260142019-05-22 14:49:24 -0500925 BFD_UDP_INPUT_NEXT_REPLY_MIDCHAIN,
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200926 BFD_UDP_INPUT_N_NEXT,
927} bfd_udp_input_next_t;
928
Matthew G Smith2f260142019-05-22 14:49:24 -0500929typedef enum
930{
931 BFD_UDP_ECHO_INPUT_NEXT_NORMAL,
932 BFD_UDP_ECHO_INPUT_NEXT_REPLY_ARP,
933 BFD_UDP_ECHO_INPUT_NEXT_REPLY_REWRITE,
934 BFD_UDP_ECHO_INPUT_N_NEXT,
935} bfd_udp_echo_input_next_t;
936
Neale Ranns5c7e5792022-08-09 00:03:17 +0000937static_always_inline vl_counter_bfd_udp_enum_t
Neale Ranns0c50dbb2022-08-05 03:40:43 +0000938bfd_error_to_udp (bfd_error_t e)
939{
940 /* The UDP error is a super set of the proto independent errors */
Neale Ranns5c7e5792022-08-09 00:03:17 +0000941 return ((vl_counter_bfd_udp_enum_t) e);
Neale Ranns0c50dbb2022-08-05 03:40:43 +0000942}
943
Klement Sekerac5fccc02017-01-18 09:56:00 +0100944static void
Klement Sekeraaeeac3b2017-02-14 07:11:52 +0100945bfd_udp4_find_headers (vlib_buffer_t * b, ip4_header_t ** ip4,
946 udp_header_t ** udp)
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200947{
Klement Sekera0c1519b2016-12-08 05:03:32 +0100948 /* sanity check first */
Damjan Marion072401e2017-07-13 18:53:27 +0200949 const i32 start = vnet_buffer (b)->l3_hdr_offset;
Klement Sekerab59f63b2022-02-14 20:19:28 +0000950 if (start < -(signed) sizeof (b->pre_data))
Klement Sekera0c1519b2016-12-08 05:03:32 +0100951 {
952 BFD_ERR ("Start of ip header is before pre_data, ignoring");
953 *ip4 = NULL;
954 *udp = NULL;
955 return;
956 }
Klement Sekerac5fccc02017-01-18 09:56:00 +0100957 *ip4 = (ip4_header_t *) (b->data + start);
958 if ((u8 *) * ip4 > (u8 *) vlib_buffer_get_current (b))
Klement Sekera0c1519b2016-12-08 05:03:32 +0100959 {
960 BFD_ERR ("Start of ip header is beyond current data, ignoring");
961 *ip4 = NULL;
962 *udp = NULL;
963 return;
964 }
Klement Sekerac5fccc02017-01-18 09:56:00 +0100965 *udp = (udp_header_t *) ((*ip4) + 1);
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200966}
967
Neale Ranns5c7e5792022-08-09 00:03:17 +0000968static vl_counter_bfd_udp_enum_t
969bfd_udp4_verify_transport (const ip4_header_t *ip4, const udp_header_t *udp,
970 const bfd_session_t *bs)
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200971{
972 const bfd_udp_session_t *bus = &bs->udp;
973 const bfd_udp_key_t *key = &bus->key;
974 if (ip4->src_address.as_u32 != key->peer_addr.ip4.as_u32)
975 {
Klement Sekera46a87ad2017-01-02 08:22:23 +0100976 BFD_ERR ("IPv4 src addr mismatch, got %U, expected %U",
Klement Sekerac5fccc02017-01-18 09:56:00 +0100977 format_ip4_address, ip4->src_address.as_u8, format_ip4_address,
978 key->peer_addr.ip4.as_u8);
Neale Ranns0c50dbb2022-08-05 03:40:43 +0000979 return BFD_UDP_ERROR_SRC_MISMATCH;
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200980 }
981 if (ip4->dst_address.as_u32 != key->local_addr.ip4.as_u32)
982 {
Klement Sekera46a87ad2017-01-02 08:22:23 +0100983 BFD_ERR ("IPv4 dst addr mismatch, got %U, expected %U",
Klement Sekerac5fccc02017-01-18 09:56:00 +0100984 format_ip4_address, ip4->dst_address.as_u8, format_ip4_address,
985 key->local_addr.ip4.as_u8);
Neale Ranns0c50dbb2022-08-05 03:40:43 +0000986 return BFD_UDP_ERROR_DST_MISMATCH;
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200987 }
988 const u8 expected_ttl = 255;
989 if (ip4->ttl != expected_ttl)
990 {
Klement Sekera46a87ad2017-01-02 08:22:23 +0100991 BFD_ERR ("IPv4 unexpected TTL value %u, expected %u", ip4->ttl,
Klement Sekerac5fccc02017-01-18 09:56:00 +0100992 expected_ttl);
Neale Ranns0c50dbb2022-08-05 03:40:43 +0000993 return BFD_UDP_ERROR_TTL;
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200994 }
Klement Sekera6f966492017-02-08 07:42:08 +0100995 if (clib_net_to_host_u16 (udp->src_port) < 49152)
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200996 {
Klement Sekera46a87ad2017-01-02 08:22:23 +0100997 BFD_ERR ("Invalid UDP src port %u, out of range <49152,65535>",
Klement Sekerac5fccc02017-01-18 09:56:00 +0100998 udp->src_port);
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200999 }
1000 return BFD_UDP_ERROR_NONE;
1001}
1002
1003typedef struct
1004{
1005 u32 bs_idx;
1006 bfd_pkt_t pkt;
1007} bfd_rpc_update_t;
1008
Neale Ranns0c50dbb2022-08-05 03:40:43 +00001009static bfd_error_t
1010bfd_rpc_update_session (vlib_main_t *vm, u32 bs_idx, const bfd_pkt_t *pkt)
Klement Sekera0e3c0de2016-09-29 14:43:44 +02001011{
Dave Barach1e3417f2018-07-25 08:30:27 -04001012 bfd_main_t *bm = &bfd_main;
Neale Ranns0c50dbb2022-08-05 03:40:43 +00001013 bfd_error_t err;
Dave Barach1e3417f2018-07-25 08:30:27 -04001014 bfd_lock (bm);
Neale Ranns0c50dbb2022-08-05 03:40:43 +00001015 err = bfd_consume_pkt (vm, bm, pkt, bs_idx);
Dave Barach1e3417f2018-07-25 08:30:27 -04001016 bfd_unlock (bm);
Neale Ranns0c50dbb2022-08-05 03:40:43 +00001017
1018 return err;
Klement Sekera0e3c0de2016-09-29 14:43:44 +02001019}
1020
Neale Ranns5c7e5792022-08-09 00:03:17 +00001021static vl_counter_bfd_udp_enum_t
Klement Sekerab59f63b2022-02-14 20:19:28 +00001022bfd_udp4_scan (vlib_main_t *vm, vlib_buffer_t *b, bfd_session_t **bs_out)
Klement Sekera0e3c0de2016-09-29 14:43:44 +02001023{
1024 const bfd_pkt_t *pkt = vlib_buffer_get_current (b);
1025 if (sizeof (*pkt) > b->current_length)
1026 {
Klement Sekerac5fccc02017-01-18 09:56:00 +01001027 BFD_ERR
1028 ("Payload size %d too small to hold bfd packet of minimum size %d",
1029 b->current_length, sizeof (*pkt));
Klement Sekera0e3c0de2016-09-29 14:43:44 +02001030 return BFD_UDP_ERROR_BAD;
1031 }
Klement Sekeraaeeac3b2017-02-14 07:11:52 +01001032 ip4_header_t *ip4;
1033 udp_header_t *udp;
Klement Sekera0e3c0de2016-09-29 14:43:44 +02001034 bfd_udp4_find_headers (b, &ip4, &udp);
1035 if (!ip4 || !udp)
1036 {
1037 BFD_ERR ("Couldn't find ip4 or udp header");
1038 return BFD_UDP_ERROR_BAD;
1039 }
Klement Sekerab17dd962017-01-09 07:43:48 +01001040 const u32 udp_payload_length = udp->length - sizeof (*udp);
1041 if (pkt->head.length > udp_payload_length)
1042 {
1043 BFD_ERR
1044 ("BFD packet length is larger than udp payload length (%u > %u)",
1045 pkt->head.length, udp_payload_length);
Neale Ranns0c50dbb2022-08-05 03:40:43 +00001046 return BFD_UDP_ERROR_LENGTH;
Klement Sekerab17dd962017-01-09 07:43:48 +01001047 }
Neale Ranns5c7e5792022-08-09 00:03:17 +00001048 vl_counter_bfd_udp_enum_t err;
Neale Ranns0c50dbb2022-08-05 03:40:43 +00001049 if (BFD_UDP_ERROR_NONE !=
1050 (err = bfd_error_to_udp (bfd_verify_pkt_common (pkt))))
Klement Sekera0e3c0de2016-09-29 14:43:44 +02001051 {
Neale Ranns0c50dbb2022-08-05 03:40:43 +00001052 return err;
Klement Sekera0e3c0de2016-09-29 14:43:44 +02001053 }
1054 bfd_session_t *bs = NULL;
1055 if (pkt->your_disc)
1056 {
1057 BFD_DBG ("Looking up BFD session using discriminator %u",
Klement Sekerac5fccc02017-01-18 09:56:00 +01001058 pkt->your_disc);
Klement Sekera0e3c0de2016-09-29 14:43:44 +02001059 bs = bfd_find_session_by_disc (bfd_udp_main.bfd_main, pkt->your_disc);
1060 }
1061 else
1062 {
1063 bfd_udp_key_t key;
Dave Barachb7b92992018-10-17 10:38:51 -04001064 clib_memset (&key, 0, sizeof (key));
Klement Sekera0e3c0de2016-09-29 14:43:44 +02001065 key.sw_if_index = vnet_buffer (b)->sw_if_index[VLIB_RX];
1066 key.local_addr.ip4.as_u32 = ip4->dst_address.as_u32;
1067 key.peer_addr.ip4.as_u32 = ip4->src_address.as_u32;
1068 BFD_DBG ("Looking up BFD session using key (sw_if_index=%u, local=%U, "
Klement Sekerac5fccc02017-01-18 09:56:00 +01001069 "peer=%U)",
1070 key.sw_if_index, format_ip4_address, key.local_addr.ip4.as_u8,
1071 format_ip4_address, key.peer_addr.ip4.as_u8);
Klement Sekera0e3c0de2016-09-29 14:43:44 +02001072 bs = bfd_lookup_session (&bfd_udp_main, &key);
1073 }
1074 if (!bs)
1075 {
1076 BFD_ERR ("BFD session lookup failed - no session matches BFD pkt");
Neale Ranns0c50dbb2022-08-05 03:40:43 +00001077 return BFD_UDP_ERROR_NO_SESSION;
Klement Sekera0e3c0de2016-09-29 14:43:44 +02001078 }
Klement Sekera637b9c42016-12-08 05:19:14 +01001079 BFD_DBG ("BFD session found, bs_idx=%u", bs->bs_idx);
Klement Sekeraa3167442020-02-10 11:49:52 +00001080 if (!bfd_verify_pkt_auth (vm, pkt, b->current_length, bs))
Klement Sekera0e3c0de2016-09-29 14:43:44 +02001081 {
Klement Sekerab17dd962017-01-09 07:43:48 +01001082 BFD_ERR ("Packet verification failed, dropping packet");
Neale Ranns0c50dbb2022-08-05 03:40:43 +00001083 return BFD_UDP_ERROR_FAILED_VERIFICATION;
Klement Sekera0e3c0de2016-09-29 14:43:44 +02001084 }
Klement Sekera0e3c0de2016-09-29 14:43:44 +02001085 if (BFD_UDP_ERROR_NONE != (err = bfd_udp4_verify_transport (ip4, udp, bs)))
1086 {
1087 return err;
1088 }
Neale Ranns0c50dbb2022-08-05 03:40:43 +00001089 err = bfd_error_to_udp (bfd_rpc_update_session (vm, bs->bs_idx, pkt));
Klement Sekera0e3c0de2016-09-29 14:43:44 +02001090 *bs_out = bs;
Neale Ranns0c50dbb2022-08-05 03:40:43 +00001091 return err;
Klement Sekera0e3c0de2016-09-29 14:43:44 +02001092}
1093
Klement Sekerac5fccc02017-01-18 09:56:00 +01001094static void
Klement Sekeraaeeac3b2017-02-14 07:11:52 +01001095bfd_udp6_find_headers (vlib_buffer_t * b, ip6_header_t ** ip6,
1096 udp_header_t ** udp)
Klement Sekera0e3c0de2016-09-29 14:43:44 +02001097{
Klement Sekera46a87ad2017-01-02 08:22:23 +01001098 /* sanity check first */
Damjan Marion072401e2017-07-13 18:53:27 +02001099 const i32 start = vnet_buffer (b)->l3_hdr_offset;
Klement Sekerab59f63b2022-02-14 20:19:28 +00001100 if (start < -(signed) sizeof (b->pre_data))
Klement Sekera46a87ad2017-01-02 08:22:23 +01001101 {
1102 BFD_ERR ("Start of ip header is before pre_data, ignoring");
1103 *ip6 = NULL;
1104 *udp = NULL;
1105 return;
1106 }
Klement Sekerac5fccc02017-01-18 09:56:00 +01001107 *ip6 = (ip6_header_t *) (b->data + start);
1108 if ((u8 *) * ip6 > (u8 *) vlib_buffer_get_current (b))
Klement Sekera46a87ad2017-01-02 08:22:23 +01001109 {
1110 BFD_ERR ("Start of ip header is beyond current data, ignoring");
1111 *ip6 = NULL;
1112 *udp = NULL;
1113 return;
1114 }
Klement Sekera402ed312017-01-18 09:44:36 +01001115 if ((*ip6)->protocol != IP_PROTOCOL_UDP)
1116 {
1117 BFD_ERR ("Unexpected protocol in IPv6 header '%u', expected '%u' (== "
Klement Sekerab17dd962017-01-09 07:43:48 +01001118 "IP_PROTOCOL_UDP)", (*ip6)->protocol, IP_PROTOCOL_UDP);
Klement Sekera402ed312017-01-18 09:44:36 +01001119 *ip6 = NULL;
1120 *udp = NULL;
1121 return;
1122 }
Klement Sekerac5fccc02017-01-18 09:56:00 +01001123 *udp = (udp_header_t *) ((*ip6) + 1);
Klement Sekera46a87ad2017-01-02 08:22:23 +01001124}
1125
Neale Ranns5c7e5792022-08-09 00:03:17 +00001126static vl_counter_bfd_udp_enum_t
1127bfd_udp6_verify_transport (const ip6_header_t *ip6, const udp_header_t *udp,
1128 const bfd_session_t *bs)
Klement Sekera46a87ad2017-01-02 08:22:23 +01001129{
1130 const bfd_udp_session_t *bus = &bs->udp;
1131 const bfd_udp_key_t *key = &bus->key;
1132 if (ip6->src_address.as_u64[0] != key->peer_addr.ip6.as_u64[0] &&
1133 ip6->src_address.as_u64[1] != key->peer_addr.ip6.as_u64[1])
1134 {
Klement Sekerac5fccc02017-01-18 09:56:00 +01001135 BFD_ERR ("IP src addr mismatch, got %U, expected %U",
1136 format_ip6_address, ip6, format_ip6_address,
1137 &key->peer_addr.ip6);
Neale Ranns0c50dbb2022-08-05 03:40:43 +00001138 return BFD_UDP_ERROR_SRC_MISMATCH;
Klement Sekera46a87ad2017-01-02 08:22:23 +01001139 }
1140 if (ip6->dst_address.as_u64[0] != key->local_addr.ip6.as_u64[0] &&
1141 ip6->dst_address.as_u64[1] != key->local_addr.ip6.as_u64[1])
1142 {
Klement Sekerac5fccc02017-01-18 09:56:00 +01001143 BFD_ERR ("IP dst addr mismatch, got %U, expected %U",
1144 format_ip6_address, ip6, format_ip6_address,
1145 &key->local_addr.ip6);
Neale Ranns0c50dbb2022-08-05 03:40:43 +00001146 return BFD_UDP_ERROR_DST_MISMATCH;
Klement Sekera46a87ad2017-01-02 08:22:23 +01001147 }
1148 const u8 expected_hop_limit = 255;
1149 if (ip6->hop_limit != expected_hop_limit)
1150 {
1151 BFD_ERR ("IPv6 unexpected hop-limit value %u, expected %u",
Klement Sekerac5fccc02017-01-18 09:56:00 +01001152 ip6->hop_limit, expected_hop_limit);
Neale Ranns0c50dbb2022-08-05 03:40:43 +00001153 return BFD_UDP_ERROR_TTL;
Klement Sekera46a87ad2017-01-02 08:22:23 +01001154 }
Klement Sekera6f966492017-02-08 07:42:08 +01001155 if (clib_net_to_host_u16 (udp->src_port) < 49152)
Klement Sekera46a87ad2017-01-02 08:22:23 +01001156 {
1157 BFD_ERR ("Invalid UDP src port %u, out of range <49152,65535>",
Klement Sekerac5fccc02017-01-18 09:56:00 +01001158 udp->src_port);
Klement Sekera46a87ad2017-01-02 08:22:23 +01001159 }
1160 return BFD_UDP_ERROR_NONE;
1161}
1162
Neale Ranns5c7e5792022-08-09 00:03:17 +00001163static vl_counter_bfd_udp_enum_t
Klement Sekerab59f63b2022-02-14 20:19:28 +00001164bfd_udp6_scan (vlib_main_t *vm, vlib_buffer_t *b, bfd_session_t **bs_out)
Klement Sekera46a87ad2017-01-02 08:22:23 +01001165{
1166 const bfd_pkt_t *pkt = vlib_buffer_get_current (b);
1167 if (sizeof (*pkt) > b->current_length)
1168 {
Klement Sekerac5fccc02017-01-18 09:56:00 +01001169 BFD_ERR
1170 ("Payload size %d too small to hold bfd packet of minimum size %d",
1171 b->current_length, sizeof (*pkt));
Klement Sekera46a87ad2017-01-02 08:22:23 +01001172 return BFD_UDP_ERROR_BAD;
1173 }
Klement Sekeraaeeac3b2017-02-14 07:11:52 +01001174 ip6_header_t *ip6;
1175 udp_header_t *udp;
Klement Sekera46a87ad2017-01-02 08:22:23 +01001176 bfd_udp6_find_headers (b, &ip6, &udp);
1177 if (!ip6 || !udp)
1178 {
1179 BFD_ERR ("Couldn't find ip6 or udp header");
1180 return BFD_UDP_ERROR_BAD;
1181 }
Klement Sekerab17dd962017-01-09 07:43:48 +01001182 const u32 udp_payload_length = udp->length - sizeof (*udp);
1183 if (pkt->head.length > udp_payload_length)
1184 {
1185 BFD_ERR
1186 ("BFD packet length is larger than udp payload length (%u > %u)",
1187 pkt->head.length, udp_payload_length);
1188 return BFD_UDP_ERROR_BAD;
1189 }
Neale Ranns5c7e5792022-08-09 00:03:17 +00001190 vl_counter_bfd_udp_enum_t err;
Neale Ranns0c50dbb2022-08-05 03:40:43 +00001191 if (BFD_UDP_ERROR_NONE !=
1192 (err = bfd_error_to_udp (bfd_verify_pkt_common (pkt))))
Klement Sekera46a87ad2017-01-02 08:22:23 +01001193 {
Neale Ranns0c50dbb2022-08-05 03:40:43 +00001194 return err;
Klement Sekera46a87ad2017-01-02 08:22:23 +01001195 }
1196 bfd_session_t *bs = NULL;
1197 if (pkt->your_disc)
1198 {
1199 BFD_DBG ("Looking up BFD session using discriminator %u",
Klement Sekerac5fccc02017-01-18 09:56:00 +01001200 pkt->your_disc);
Klement Sekera46a87ad2017-01-02 08:22:23 +01001201 bs = bfd_find_session_by_disc (bfd_udp_main.bfd_main, pkt->your_disc);
1202 }
1203 else
1204 {
1205 bfd_udp_key_t key;
Dave Barachb7b92992018-10-17 10:38:51 -04001206 clib_memset (&key, 0, sizeof (key));
Klement Sekera46a87ad2017-01-02 08:22:23 +01001207 key.sw_if_index = vnet_buffer (b)->sw_if_index[VLIB_RX];
1208 key.local_addr.ip6.as_u64[0] = ip6->dst_address.as_u64[0];
1209 key.local_addr.ip6.as_u64[1] = ip6->dst_address.as_u64[1];
1210 key.peer_addr.ip6.as_u64[0] = ip6->src_address.as_u64[0];
1211 key.peer_addr.ip6.as_u64[1] = ip6->src_address.as_u64[1];
1212 BFD_DBG ("Looking up BFD session using key (sw_if_index=%u, local=%U, "
Klement Sekerab17dd962017-01-09 07:43:48 +01001213 "peer=%U)",
1214 key.sw_if_index, format_ip6_address, &key.local_addr,
1215 format_ip6_address, &key.peer_addr);
Klement Sekera46a87ad2017-01-02 08:22:23 +01001216 bs = bfd_lookup_session (&bfd_udp_main, &key);
1217 }
1218 if (!bs)
1219 {
1220 BFD_ERR ("BFD session lookup failed - no session matches BFD pkt");
Neale Ranns0c50dbb2022-08-05 03:40:43 +00001221 return BFD_UDP_ERROR_NO_SESSION;
Klement Sekera46a87ad2017-01-02 08:22:23 +01001222 }
1223 BFD_DBG ("BFD session found, bs_idx=%u", bs->bs_idx);
Klement Sekeraa3167442020-02-10 11:49:52 +00001224 if (!bfd_verify_pkt_auth (vm, pkt, b->current_length, bs))
Klement Sekera46a87ad2017-01-02 08:22:23 +01001225 {
Klement Sekerab17dd962017-01-09 07:43:48 +01001226 BFD_ERR ("Packet verification failed, dropping packet");
Neale Ranns0c50dbb2022-08-05 03:40:43 +00001227 return BFD_UDP_ERROR_FAILED_VERIFICATION;
Klement Sekera46a87ad2017-01-02 08:22:23 +01001228 }
Klement Sekera46a87ad2017-01-02 08:22:23 +01001229 if (BFD_UDP_ERROR_NONE != (err = bfd_udp6_verify_transport (ip6, udp, bs)))
1230 {
1231 return err;
1232 }
Neale Ranns0c50dbb2022-08-05 03:40:43 +00001233 err = bfd_error_to_udp (bfd_rpc_update_session (vm, bs->bs_idx, pkt));
Klement Sekera46a87ad2017-01-02 08:22:23 +01001234 *bs_out = bs;
Neale Ranns0c50dbb2022-08-05 03:40:43 +00001235 return err;
Klement Sekera0e3c0de2016-09-29 14:43:44 +02001236}
1237
1238/*
1239 * Process a frame of bfd packets
1240 * Expect 1 packet / frame
1241 */
Klement Sekerac5fccc02017-01-18 09:56:00 +01001242static uword
1243bfd_udp_input (vlib_main_t * vm, vlib_node_runtime_t * rt,
1244 vlib_frame_t * f, int is_ipv6)
Klement Sekera0e3c0de2016-09-29 14:43:44 +02001245{
1246 u32 n_left_from, *from;
1247 bfd_input_trace_t *t0;
Dave Barach1e3417f2018-07-25 08:30:27 -04001248 bfd_main_t *bm = &bfd_main;
Klement Sekera0e3c0de2016-09-29 14:43:44 +02001249
Klement Sekerac5fccc02017-01-18 09:56:00 +01001250 from = vlib_frame_vector_args (f); /* array of buffer indices */
1251 n_left_from = f->n_vectors; /* number of buffer indices */
Klement Sekera0e3c0de2016-09-29 14:43:44 +02001252
1253 while (n_left_from > 0)
1254 {
1255 u32 bi0;
1256 vlib_buffer_t *b0;
1257 u32 next0, error0;
1258
1259 bi0 = from[0];
1260 b0 = vlib_get_buffer (vm, bi0);
1261
1262 bfd_session_t *bs = NULL;
1263
1264 /* If this pkt is traced, snapshot the data */
1265 if (b0->flags & VLIB_BUFFER_IS_TRACED)
Klement Sekerac5fccc02017-01-18 09:56:00 +01001266 {
Klement Sekerab59f63b2022-02-14 20:19:28 +00001267 u64 len;
Klement Sekerac5fccc02017-01-18 09:56:00 +01001268 t0 = vlib_add_trace (vm, rt, b0, sizeof (*t0));
1269 len = (b0->current_length < sizeof (t0->data)) ? b0->current_length
1270 : sizeof (t0->data);
1271 t0->len = len;
Dave Barach178cf492018-11-13 16:34:13 -05001272 clib_memcpy_fast (t0->data, vlib_buffer_get_current (b0), len);
Klement Sekerac5fccc02017-01-18 09:56:00 +01001273 }
Klement Sekera0e3c0de2016-09-29 14:43:44 +02001274
1275 /* scan this bfd pkt. error0 is the counter index to bmp */
Dave Barach1e3417f2018-07-25 08:30:27 -04001276 bfd_lock (bm);
Klement Sekera0e3c0de2016-09-29 14:43:44 +02001277 if (is_ipv6)
Klement Sekerac5fccc02017-01-18 09:56:00 +01001278 {
Klement Sekerab59f63b2022-02-14 20:19:28 +00001279 error0 = bfd_udp6_scan (vm, b0, &bs);
Klement Sekerac5fccc02017-01-18 09:56:00 +01001280 }
Klement Sekera0e3c0de2016-09-29 14:43:44 +02001281 else
Klement Sekerac5fccc02017-01-18 09:56:00 +01001282 {
Klement Sekerab59f63b2022-02-14 20:19:28 +00001283 error0 = bfd_udp4_scan (vm, b0, &bs);
Klement Sekerac5fccc02017-01-18 09:56:00 +01001284 }
Klement Sekera0e3c0de2016-09-29 14:43:44 +02001285 b0->error = rt->errors[error0];
1286
1287 next0 = BFD_UDP_INPUT_NEXT_NORMAL;
1288 if (BFD_UDP_ERROR_NONE == error0)
Klement Sekerac5fccc02017-01-18 09:56:00 +01001289 {
Klement Sekeracdaf0d82022-02-14 20:20:22 +00001290 vlib_increment_combined_counter (
1291 &bm->rx_counter, vm->thread_index, bs->bs_idx, 1,
1292 vlib_buffer_length_in_chain (vm, b0));
Klement Sekera402ed312017-01-18 09:44:36 +01001293 /*
1294 * if everything went fine, check for poll bit, if present, re-use
1295 * the buffer and based on (now updated) session parameters, send
1296 * the final packet back
1297 */
Klement Sekerac5fccc02017-01-18 09:56:00 +01001298 const bfd_pkt_t *pkt = vlib_buffer_get_current (b0);
1299 if (bfd_pkt_get_poll (pkt))
1300 {
Klement Sekerae50e8562017-04-04 16:19:48 +02001301 b0->current_data = 0;
1302 b0->current_length = 0;
Klement Sekerab59f63b2022-02-14 20:19:28 +00001303 bfd_init_final_control_frame (vm, b0, bs);
Klement Sekerac5fccc02017-01-18 09:56:00 +01001304 if (is_ipv6)
1305 {
1306 vlib_node_increment_counter (vm, bfd_udp6_input_node.index,
Paul Atkins0d032842022-03-24 11:26:16 +00001307 error0, 1);
Klement Sekerac5fccc02017-01-18 09:56:00 +01001308 }
1309 else
1310 {
1311 vlib_node_increment_counter (vm, bfd_udp4_input_node.index,
Paul Atkins0d032842022-03-24 11:26:16 +00001312 error0, 1);
Klement Sekerac5fccc02017-01-18 09:56:00 +01001313 }
Klement Sekerae50e8562017-04-04 16:19:48 +02001314 const bfd_udp_session_t *bus = &bs->udp;
1315 ip_adjacency_t *adj = adj_get (bus->adj_index);
1316 switch (adj->lookup_next_index)
1317 {
1318 case IP_LOOKUP_NEXT_ARP:
1319 next0 = BFD_UDP_INPUT_NEXT_REPLY_ARP;
1320 break;
1321 case IP_LOOKUP_NEXT_REWRITE:
1322 next0 = BFD_UDP_INPUT_NEXT_REPLY_REWRITE;
1323 break;
Matthew G Smith2f260142019-05-22 14:49:24 -05001324 case IP_LOOKUP_NEXT_MIDCHAIN:
1325 next0 = BFD_UDP_INPUT_NEXT_REPLY_MIDCHAIN;
1326 break;
Klement Sekerae50e8562017-04-04 16:19:48 +02001327 default:
1328 /* drop */
1329 break;
1330 }
Klement Sekerac5fccc02017-01-18 09:56:00 +01001331 }
1332 }
Dave Barach1e3417f2018-07-25 08:30:27 -04001333 bfd_unlock (bm);
Klement Sekera0e3c0de2016-09-29 14:43:44 +02001334 vlib_set_next_frame_buffer (vm, rt, next0, bi0);
1335
1336 from += 1;
1337 n_left_from -= 1;
1338 }
1339
1340 return f->n_vectors;
1341}
1342
Klement Sekerac5fccc02017-01-18 09:56:00 +01001343static uword
1344bfd_udp4_input (vlib_main_t * vm, vlib_node_runtime_t * rt, vlib_frame_t * f)
Klement Sekera0e3c0de2016-09-29 14:43:44 +02001345{
1346 return bfd_udp_input (vm, rt, f, 0);
1347}
1348
1349/*
1350 * bfd input graph node declaration
1351 */
1352/* *INDENT-OFF* */
1353VLIB_REGISTER_NODE (bfd_udp4_input_node, static) = {
1354 .function = bfd_udp4_input,
1355 .name = "bfd-udp4-input",
1356 .vector_size = sizeof (u32),
1357 .type = VLIB_NODE_TYPE_INTERNAL,
1358
1359 .n_errors = BFD_UDP_N_ERROR,
Neale Ranns5c7e5792022-08-09 00:03:17 +00001360 .error_counters = bfd_udp_error_counters,
Klement Sekera0e3c0de2016-09-29 14:43:44 +02001361
1362 .format_trace = bfd_input_format_trace,
1363
1364 .n_next_nodes = BFD_UDP_INPUT_N_NEXT,
1365 .next_nodes =
1366 {
1367 [BFD_UDP_INPUT_NEXT_NORMAL] = "error-drop",
Klement Sekerae50e8562017-04-04 16:19:48 +02001368 [BFD_UDP_INPUT_NEXT_REPLY_ARP] = "ip4-arp",
1369 [BFD_UDP_INPUT_NEXT_REPLY_REWRITE] = "ip4-lookup",
Matthew G Smith2f260142019-05-22 14:49:24 -05001370 [BFD_UDP_INPUT_NEXT_REPLY_MIDCHAIN] = "ip4-midchain",
Klement Sekera0e3c0de2016-09-29 14:43:44 +02001371 },
1372};
1373/* *INDENT-ON* */
1374
Klement Sekerac5fccc02017-01-18 09:56:00 +01001375static uword
1376bfd_udp6_input (vlib_main_t * vm, vlib_node_runtime_t * rt, vlib_frame_t * f)
Klement Sekera0e3c0de2016-09-29 14:43:44 +02001377{
1378 return bfd_udp_input (vm, rt, f, 1);
1379}
1380
1381/* *INDENT-OFF* */
1382VLIB_REGISTER_NODE (bfd_udp6_input_node, static) = {
1383 .function = bfd_udp6_input,
1384 .name = "bfd-udp6-input",
1385 .vector_size = sizeof (u32),
1386 .type = VLIB_NODE_TYPE_INTERNAL,
1387
1388 .n_errors = BFD_UDP_N_ERROR,
Neale Ranns5c7e5792022-08-09 00:03:17 +00001389 .error_counters = bfd_udp_error_counters,
Klement Sekera0e3c0de2016-09-29 14:43:44 +02001390
1391 .format_trace = bfd_input_format_trace,
1392
1393 .n_next_nodes = BFD_UDP_INPUT_N_NEXT,
1394 .next_nodes =
1395 {
1396 [BFD_UDP_INPUT_NEXT_NORMAL] = "error-drop",
Klement Sekerae50e8562017-04-04 16:19:48 +02001397 [BFD_UDP_INPUT_NEXT_REPLY_ARP] = "ip6-discover-neighbor",
1398 [BFD_UDP_INPUT_NEXT_REPLY_REWRITE] = "ip6-lookup",
Matthew G Smith2f260142019-05-22 14:49:24 -05001399 [BFD_UDP_INPUT_NEXT_REPLY_MIDCHAIN] = "ip6-midchain",
Klement Sekera0e3c0de2016-09-29 14:43:44 +02001400 },
1401};
1402/* *INDENT-ON* */
1403
Klement Sekeraaeeac3b2017-02-14 07:11:52 +01001404/*
1405 * Process a frame of bfd echo packets
1406 * Expect 1 packet / frame
1407 */
1408static uword
1409bfd_udp_echo_input (vlib_main_t * vm, vlib_node_runtime_t * rt,
1410 vlib_frame_t * f, int is_ipv6)
1411{
1412 u32 n_left_from, *from;
1413 bfd_input_trace_t *t0;
Dave Barach1e3417f2018-07-25 08:30:27 -04001414 bfd_main_t *bm = &bfd_main;
Klement Sekeraaeeac3b2017-02-14 07:11:52 +01001415
1416 from = vlib_frame_vector_args (f); /* array of buffer indices */
1417 n_left_from = f->n_vectors; /* number of buffer indices */
1418
1419 while (n_left_from > 0)
1420 {
1421 u32 bi0;
1422 vlib_buffer_t *b0;
1423 u32 next0;
1424
1425 bi0 = from[0];
1426 b0 = vlib_get_buffer (vm, bi0);
1427
1428 /* If this pkt is traced, snapshot the data */
1429 if (b0->flags & VLIB_BUFFER_IS_TRACED)
1430 {
Klement Sekerab59f63b2022-02-14 20:19:28 +00001431 u64 len;
Klement Sekeraaeeac3b2017-02-14 07:11:52 +01001432 t0 = vlib_add_trace (vm, rt, b0, sizeof (*t0));
1433 len = (b0->current_length < sizeof (t0->data)) ? b0->current_length
1434 : sizeof (t0->data);
1435 t0->len = len;
Dave Barach178cf492018-11-13 16:34:13 -05001436 clib_memcpy_fast (t0->data, vlib_buffer_get_current (b0), len);
Klement Sekeraaeeac3b2017-02-14 07:11:52 +01001437 }
1438
Klement Sekeracdaf0d82022-02-14 20:20:22 +00001439 bfd_session_t *bs = NULL;
Dave Barach1e3417f2018-07-25 08:30:27 -04001440 bfd_lock (bm);
Klement Sekeracdaf0d82022-02-14 20:20:22 +00001441 if ((bs = bfd_consume_echo_pkt (vm, bfd_udp_main.bfd_main, b0)))
Klement Sekera239790f2017-02-16 10:53:53 +01001442 {
1443 b0->error = rt->errors[BFD_UDP_ERROR_NONE];
Matthew G Smith2f260142019-05-22 14:49:24 -05001444 next0 = BFD_UDP_ECHO_INPUT_NEXT_NORMAL;
Klement Sekera239790f2017-02-16 10:53:53 +01001445 }
1446 else
Klement Sekeraaeeac3b2017-02-14 07:11:52 +01001447 {
1448 /* loop back the packet */
1449 b0->error = rt->errors[BFD_UDP_ERROR_NONE];
1450 if (is_ipv6)
1451 {
1452 vlib_node_increment_counter (vm, bfd_udp_echo6_input_node.index,
Paul Atkins0d032842022-03-24 11:26:16 +00001453 BFD_UDP_ERROR_NONE, 1);
Klement Sekeraaeeac3b2017-02-14 07:11:52 +01001454 }
1455 else
1456 {
1457 vlib_node_increment_counter (vm, bfd_udp_echo4_input_node.index,
Paul Atkins0d032842022-03-24 11:26:16 +00001458 BFD_UDP_ERROR_NONE, 1);
Klement Sekeraaeeac3b2017-02-14 07:11:52 +01001459 }
Matthew G Smith2f260142019-05-22 14:49:24 -05001460 next0 = BFD_UDP_ECHO_INPUT_NEXT_REPLY_REWRITE;
Klement Sekeraaeeac3b2017-02-14 07:11:52 +01001461 }
Klement Sekeraaeeac3b2017-02-14 07:11:52 +01001462
Dave Barach1e3417f2018-07-25 08:30:27 -04001463 bfd_unlock (bm);
Klement Sekeracdaf0d82022-02-14 20:20:22 +00001464
1465 if (bs)
1466 {
1467 vlib_increment_combined_counter (
1468 &bm->rx_echo_counter, vm->thread_index, bs->bs_idx, 1,
1469 vlib_buffer_length_in_chain (vm, b0));
1470 }
1471
Klement Sekeraaeeac3b2017-02-14 07:11:52 +01001472 vlib_set_next_frame_buffer (vm, rt, next0, bi0);
1473
1474 from += 1;
1475 n_left_from -= 1;
1476 }
1477
1478 return f->n_vectors;
1479}
1480
1481static uword
1482bfd_udp_echo4_input (vlib_main_t * vm, vlib_node_runtime_t * rt,
1483 vlib_frame_t * f)
1484{
1485 return bfd_udp_echo_input (vm, rt, f, 0);
1486}
1487
1488u8 *
1489bfd_echo_input_format_trace (u8 * s, va_list * args)
1490{
1491 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
1492 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
1493 const bfd_udp_echo_input_trace_t *t =
1494 va_arg (*args, bfd_udp_echo_input_trace_t *);
1495 if (t->len > STRUCT_SIZE_OF (bfd_pkt_t, head))
1496 {
1497 s = format (s, "BFD ECHO:\n");
1498 s = format (s, " data: %U", format_hexdump, t->data, t->len);
1499 }
1500
1501 return s;
1502}
1503
1504/*
1505 * bfd input graph node declaration
1506 */
1507/* *INDENT-OFF* */
1508VLIB_REGISTER_NODE (bfd_udp_echo4_input_node, static) = {
1509 .function = bfd_udp_echo4_input,
1510 .name = "bfd-udp-echo4-input",
1511 .vector_size = sizeof (u32),
1512 .type = VLIB_NODE_TYPE_INTERNAL,
1513
Neale Ranns5c7e5792022-08-09 00:03:17 +00001514 .n_errors = BFD_UDP_N_ERROR,
1515 .error_counters = bfd_udp_error_counters,
Klement Sekeraaeeac3b2017-02-14 07:11:52 +01001516
1517 .format_trace = bfd_echo_input_format_trace,
1518
Matthew G Smith2f260142019-05-22 14:49:24 -05001519 .n_next_nodes = BFD_UDP_ECHO_INPUT_N_NEXT,
Klement Sekeraaeeac3b2017-02-14 07:11:52 +01001520 .next_nodes =
1521 {
Matthew G Smith2f260142019-05-22 14:49:24 -05001522 [BFD_UDP_ECHO_INPUT_NEXT_NORMAL] = "error-drop",
1523 [BFD_UDP_ECHO_INPUT_NEXT_REPLY_ARP] = "ip4-arp",
1524 [BFD_UDP_ECHO_INPUT_NEXT_REPLY_REWRITE] = "ip4-lookup",
Klement Sekeraaeeac3b2017-02-14 07:11:52 +01001525 },
1526};
1527/* *INDENT-ON* */
1528
1529static uword
1530bfd_udp_echo6_input (vlib_main_t * vm, vlib_node_runtime_t * rt,
1531 vlib_frame_t * f)
1532{
1533 return bfd_udp_echo_input (vm, rt, f, 1);
1534}
1535
1536/* *INDENT-OFF* */
1537VLIB_REGISTER_NODE (bfd_udp_echo6_input_node, static) = {
1538 .function = bfd_udp_echo6_input,
1539 .name = "bfd-udp-echo6-input",
1540 .vector_size = sizeof (u32),
1541 .type = VLIB_NODE_TYPE_INTERNAL,
1542
Neale Ranns5c7e5792022-08-09 00:03:17 +00001543 .n_errors = BFD_UDP_N_ERROR,
1544 .error_counters = bfd_udp_error_counters,
Klement Sekeraaeeac3b2017-02-14 07:11:52 +01001545
1546 .format_trace = bfd_echo_input_format_trace,
1547
Matthew G Smith2f260142019-05-22 14:49:24 -05001548 .n_next_nodes = BFD_UDP_ECHO_INPUT_N_NEXT,
Klement Sekeraaeeac3b2017-02-14 07:11:52 +01001549 .next_nodes =
1550 {
Matthew G Smith2f260142019-05-22 14:49:24 -05001551 [BFD_UDP_ECHO_INPUT_NEXT_NORMAL] = "error-drop",
1552 [BFD_UDP_ECHO_INPUT_NEXT_REPLY_ARP] = "ip6-discover-neighbor",
1553 [BFD_UDP_ECHO_INPUT_NEXT_REPLY_REWRITE] = "ip6-lookup",
Klement Sekeraaeeac3b2017-02-14 07:11:52 +01001554 },
1555};
1556
1557/* *INDENT-ON* */
1558
Klement Sekerac5fccc02017-01-18 09:56:00 +01001559static clib_error_t *
Klement Sekerab59f63b2022-02-14 20:19:28 +00001560bfd_udp_sw_if_add_del (CLIB_UNUSED (vnet_main_t *vnm), u32 sw_if_index,
1561 u32 is_create)
Klement Sekera0e3c0de2016-09-29 14:43:44 +02001562{
Klement Sekerab59f63b2022-02-14 20:19:28 +00001563 u32 *to_be_freed = NULL;
Damjan Marion07a38572018-01-21 06:44:18 -08001564 bfd_udp_main_t *bum = &bfd_udp_main;
Klement Sekeraf3bcdbf2017-05-02 07:38:01 +02001565 BFD_DBG ("sw_if_add_del called, sw_if_index=%u, is_create=%u", sw_if_index,
1566 is_create);
1567 if (!is_create)
Klement Sekera0e3c0de2016-09-29 14:43:44 +02001568 {
Klement Sekeraf3bcdbf2017-05-02 07:38:01 +02001569 bfd_session_t *bs;
Klement Sekerab59f63b2022-02-14 20:19:28 +00001570 pool_foreach (bs, bum->bfd_main->sessions)
1571 {
1572 if (bs->transport != BFD_TRANSPORT_UDP4 &&
1573 bs->transport != BFD_TRANSPORT_UDP6)
1574 {
1575 continue;
1576 }
1577 if (bs->udp.key.sw_if_index != sw_if_index)
1578 {
1579 continue;
1580 }
1581 vec_add1 (to_be_freed, bs->bs_idx);
1582 }
Klement Sekera0e3c0de2016-09-29 14:43:44 +02001583 }
Klement Sekerab59f63b2022-02-14 20:19:28 +00001584 u32 *bs_idx;
1585 vec_foreach (bs_idx, to_be_freed)
1586 {
1587 bfd_session_t *bs = pool_elt_at_index (bum->bfd_main->sessions, *bs_idx);
1588 vlib_log_notice (bum->log_class,
1589 "removal of sw_if_index=%u forces removal of bfd "
1590 "session with bs_idx=%u",
1591 sw_if_index, bs->bs_idx);
1592 bfd_session_set_flags (vlib_get_main (), bs, 0);
1593 bfd_udp_del_session_internal (vlib_get_main (), bs);
1594 }
Klement Sekera0e3c0de2016-09-29 14:43:44 +02001595 return 0;
1596}
1597
Klement Sekeraf3bcdbf2017-05-02 07:38:01 +02001598VNET_SW_INTERFACE_ADD_DEL_FUNCTION (bfd_udp_sw_if_add_del);
Klement Sekera0e3c0de2016-09-29 14:43:44 +02001599
Klement Sekeracdaf0d82022-02-14 20:20:22 +00001600clib_error_t *
1601bfd_udp_stats_init (bfd_udp_main_t *bum)
1602{
1603 const char *name4 = "/bfd/udp4/sessions";
Damjan Marion8973b072022-03-01 15:51:18 +01001604 bum->udp4_sessions_count_stat_seg_entry = vlib_stats_add_gauge ("%s", name4);
Klement Sekeracdaf0d82022-02-14 20:20:22 +00001605
Damjan Marion8973b072022-03-01 15:51:18 +01001606 vlib_stats_set_gauge (bum->udp4_sessions_count_stat_seg_entry, 0);
Klement Sekeracdaf0d82022-02-14 20:20:22 +00001607 if (~0 == bum->udp4_sessions_count_stat_seg_entry)
1608 {
1609 return clib_error_return (
1610 0, "Could not create stat segment entry for %s", name4);
1611 }
1612 const char *name6 = "/bfd/udp6/sessions";
Damjan Marion8973b072022-03-01 15:51:18 +01001613 bum->udp6_sessions_count_stat_seg_entry = vlib_stats_add_gauge ("%s", name6);
Klement Sekeracdaf0d82022-02-14 20:20:22 +00001614
Damjan Marion8973b072022-03-01 15:51:18 +01001615 vlib_stats_set_gauge (bum->udp6_sessions_count_stat_seg_entry, 0);
Klement Sekeracdaf0d82022-02-14 20:20:22 +00001616 if (~0 == bum->udp6_sessions_count_stat_seg_entry)
1617 {
1618 return clib_error_return (
1619 0, "Could not create stat segment entry for %s", name6);
1620 }
1621
1622 return 0;
1623}
1624
Klement Sekera0e3c0de2016-09-29 14:43:44 +02001625/*
1626 * setup function
1627 */
Klement Sekerac5fccc02017-01-18 09:56:00 +01001628static clib_error_t *
1629bfd_udp_init (vlib_main_t * vm)
Klement Sekera0e3c0de2016-09-29 14:43:44 +02001630{
Klement Sekera88aec652019-03-11 14:04:19 +01001631 bfd_udp_main.udp4_sessions_count = 0;
1632 bfd_udp_main.udp6_sessions_count = 0;
Klement Sekera0e3c0de2016-09-29 14:43:44 +02001633 mhash_init (&bfd_udp_main.bfd_session_idx_by_bfd_key, sizeof (uword),
Klement Sekerac5fccc02017-01-18 09:56:00 +01001634 sizeof (bfd_udp_key_t));
Klement Sekera0e3c0de2016-09-29 14:43:44 +02001635 bfd_udp_main.bfd_main = &bfd_main;
Klement Sekera239790f2017-02-16 10:53:53 +01001636 bfd_udp_main.vnet_main = vnet_get_main ();
Klement Sekeracdaf0d82022-02-14 20:20:22 +00001637 bfd_udp_stats_init (&bfd_udp_main);
1638
Damjan Marion07a38572018-01-21 06:44:18 -08001639 bfd_udp_main.log_class = vlib_log_register_class ("bfd", "udp");
1640 vlib_log_debug (bfd_udp_main.log_class, "initialized");
Klement Sekera0e3c0de2016-09-29 14:43:44 +02001641 return 0;
1642}
1643
1644VLIB_INIT_FUNCTION (bfd_udp_init);
Klement Sekerac5fccc02017-01-18 09:56:00 +01001645
1646/*
1647 * fd.io coding-style-patch-verification: ON
1648 *
1649 * Local Variables:
1650 * eval: (c-set-style "gnu")
1651 * End:
1652 */