1 /*
2 * Copyright (C) 2015-2025 Red Hat, Inc. All rights reserved.
3 *
4 * Authors: Fabio M. Di Nitto <fabbione@kronosnet.org>
5 * Federico Simoncelli <fsimon@kronosnet.org>
6 *
7 * This software licensed under LGPL-2.0+
8 */
9
10 #include "config.h"
11
12 #include <unistd.h>
13 #include <string.h>
14 #include <errno.h>
15 #include <pthread.h>
16
17 #include "crypto.h"
18 #include "links.h"
19 #include "host.h"
20 #include "logging.h"
21 #include "transports.h"
22 #include "threads_common.h"
23 #include "threads_pmtud.h"
24
25 static int _calculate_manual_mtu(knet_handle_t knet_h, struct knet_link *dst_link)
26 {
27 size_t ipproto_overhead_len; /* onwire packet overhead (protocol based) */
28
29 switch (dst_link->dst_addr.ss_family) {
30 case AF_INET6:
31 ipproto_overhead_len = KNET_PMTUD_OVERHEAD_V6 + dst_link->proto_overhead;
32 break;
33 case AF_INET:
34 ipproto_overhead_len = KNET_PMTUD_OVERHEAD_V4 + dst_link->proto_overhead;
35 break;
36 default:
37 log_debug(knet_h, KNET_SUB_PMTUD, "unknown protocol");
38 return 0;
39 break;
40 }
41
42 dst_link->status.mtu = calc_max_data_outlen(knet_h, knet_h->manual_mtu - ipproto_overhead_len);
43
44 return 1;
45 }
46
47 static int _handle_check_link_pmtud(knet_handle_t knet_h, struct knet_host *dst_host, struct knet_link *dst_link)
48 {
49 int err, ret, savederrno, mutex_retry_limit, failsafe, use_kernel_mtu, warn_once;
50 uint32_t kernel_mtu; /* record kernel_mtu from EMSGSIZE */
51 size_t onwire_len; /* current packet onwire size */
52 size_t ipproto_overhead_len; /* onwire packet overhead (protocol based) */
53 size_t max_mtu_len; /* max mtu for protocol */
54 size_t data_len; /* how much data we can send in the packet
55 * generally would be onwire_len - ipproto_overhead_len
56 * needs to be adjusted for crypto
57 */
58 size_t app_mtu_len; /* real data that we can send onwire */
59 ssize_t len; /* len of what we were able to sendto onwire */
60
61 struct timespec ts, pmtud_crypto_start_ts, pmtud_crypto_stop_ts;
62 unsigned long long pong_timeout_adj_tmp, timediff;
63 int pmtud_crypto_reduce = 1;
64 unsigned char *outbuf = (unsigned char *)knet_h->pmtudbuf;
65
66 warn_once = 0;
67
68 mutex_retry_limit = 0;
69 failsafe = 0;
70
71 knet_h->pmtudbuf->khp_pmtud_link = dst_link->link_id;
72
73 switch (dst_link->dst_addr.ss_family) {
74 case AF_INET6:
75 max_mtu_len = KNET_PMTUD_SIZE_V6;
76 ipproto_overhead_len = KNET_PMTUD_OVERHEAD_V6 + dst_link->proto_overhead;
77 break;
78 case AF_INET:
79 max_mtu_len = KNET_PMTUD_SIZE_V4;
80 ipproto_overhead_len = KNET_PMTUD_OVERHEAD_V4 + dst_link->proto_overhead;
81 break;
82 default:
83 log_debug(knet_h, KNET_SUB_PMTUD, "PMTUD aborted, unknown protocol");
84 return -1;
85 break;
86 }
87
88 dst_link->last_bad_mtu = 0;
89 dst_link->last_good_mtu = dst_link->last_ping_size + ipproto_overhead_len;
90
91 /*
92 * discovery starts from the top because kernel will
93 * refuse to send packets > current iface mtu.
94 * this saves us some time and network bw.
95 */
96 onwire_len = max_mtu_len;
97
98 restart:
99
100 /*
101 * prevent a race when interface mtu is changed _exactly_ during
102 * the discovery process and it's complex to detect. Easier
103 * to wait the next loop.
104 * 30 is not an arbitrary value. To bisect from 576 to 128000 doesn't
105 * take more than 18/19 steps.
106 */
107
108 if (failsafe == 30) {
109 log_err(knet_h, KNET_SUB_PMTUD,
110 "Aborting PMTUD process: Too many attempts. MTU might have changed during discovery.");
111 return -1;
112 } else {
113 failsafe++;
114 }
115
116 /*
117 * common to all packets
118 */
119
120 /*
121 * calculate the application MTU based on current onwire_len minus ipproto_overhead_len
122 */
123
124 app_mtu_len = calc_max_data_outlen(knet_h, onwire_len - ipproto_overhead_len);
125
126 /*
127 * recalculate onwire len back that might be different based
128 * on data padding from crypto layer.
129 */
130
131 onwire_len = calc_data_outlen(knet_h, app_mtu_len + KNET_HEADER_ALL_SIZE) + ipproto_overhead_len;
132
133 /*
134 * calculate the size of what we need to send to sendto(2).
135 * see also onwire.c for packet format explanation.
136 */
137 data_len = app_mtu_len + knet_h->sec_hash_size + knet_h->sec_salt_size + KNET_HEADER_ALL_SIZE;
138
139 if (knet_h->crypto_in_use_config) {
140 if (data_len < (knet_h->sec_hash_size + knet_h->sec_salt_size) + 1) {
141 log_debug(knet_h, KNET_SUB_PMTUD, "Aborting PMTUD process: link mtu smaller than crypto header detected (link might have been disconnected)");
142 return -1;
143 }
144
145 knet_h->pmtudbuf->khp_pmtud_size = onwire_len;
146
147 if (crypto_encrypt_and_sign(knet_h,
148 (const unsigned char *)knet_h->pmtudbuf,
149 data_len - (knet_h->sec_hash_size + knet_h->sec_salt_size),
150 knet_h->pmtudbuf_crypt,
151 (ssize_t *)&data_len) < 0) {
152 log_debug(knet_h, KNET_SUB_PMTUD, "Unable to crypto pmtud packet");
153 return -1;
154 }
155
156 outbuf = knet_h->pmtudbuf_crypt;
157 if (pthread_mutex_lock(&knet_h->handle_stats_mutex) < 0) {
158 log_err(knet_h, KNET_SUB_PMTUD, "Unable to get mutex lock");
159 return -1;
160 }
161 knet_h->stats_extra.tx_crypt_pmtu_packets++;
162 pthread_mutex_unlock(&knet_h->handle_stats_mutex);
163 } else {
164 knet_h->pmtudbuf->khp_pmtud_size = onwire_len;
165 }
166
167 /* link has gone down, aborting pmtud */
168 if (dst_link->status.connected != 1) {
169 log_debug(knet_h, KNET_SUB_PMTUD, "PMTUD detected host (%u) link (%u) has been disconnected", dst_host->host_id, dst_link->link_id);
170 return -1;
171 }
172
173 if (dst_link->transport_connected != 1) {
174 log_debug(knet_h, KNET_SUB_PMTUD, "PMTUD detected host (%u) link (%u) has been disconnected", dst_host->host_id, dst_link->link_id);
175 return -1;
176 }
177
178 if (pthread_mutex_lock(&knet_h->pmtud_mutex) != 0) {
179 log_debug(knet_h, KNET_SUB_PMTUD, "Unable to get mutex lock");
180 return -1;
181 }
182
183 if (knet_h->pmtud_abort) {
184 pthread_mutex_unlock(&knet_h->pmtud_mutex);
185 errno = EDEADLK;
186 return -1;
187 }
188
189 savederrno = pthread_mutex_lock(&knet_h->tx_mutex);
190 if (savederrno) {
191 pthread_mutex_unlock(&knet_h->pmtud_mutex);
192 log_err(knet_h, KNET_SUB_PMTUD, "Unable to get TX mutex lock: %s", strerror(savederrno));
193 return -1;
194 }
195
196 savederrno = pthread_mutex_lock(&dst_link->link_stats_mutex);
197 if (savederrno) {
198 pthread_mutex_unlock(&knet_h->pmtud_mutex);
199 pthread_mutex_unlock(&knet_h->tx_mutex);
200 log_err(knet_h, KNET_SUB_PMTUD, "Unable to get stats mutex lock for host %u link %u: %s",
201 dst_host->host_id, dst_link->link_id, strerror(savederrno));
202 return -1;
203 }
204
205 retry:
206 if (transport_get_connection_oriented(knet_h, dst_link->transport) == TRANSPORT_PROTO_NOT_CONNECTION_ORIENTED) {
207 len = sendto(dst_link->outsock, outbuf, data_len, MSG_DONTWAIT | MSG_NOSIGNAL,
208 (struct sockaddr *) &dst_link->dst_addr,
209 knet_h->knet_transport_fd_tracker[dst_link->outsock].sockaddr_len);
210 } else {
211 len = sendto(dst_link->outsock, outbuf, data_len, MSG_DONTWAIT | MSG_NOSIGNAL, NULL, 0);
212 }
213 savederrno = errno;
214
215 /*
216 * we cannot hold a lock on kmtu_mutex between resetting
217 * knet_h->kernel_mtu here and below where it's used.
218 * use_kernel_mtu tells us if the knet_h->kernel_mtu was
219 * set to 0 and we can trust its value later.
220 */
221 use_kernel_mtu = 0;
222
223 if (pthread_mutex_lock(&knet_h->kmtu_mutex) == 0) {
224 use_kernel_mtu = 1;
225 knet_h->kernel_mtu = 0;
226 pthread_mutex_unlock(&knet_h->kmtu_mutex);
227 }
228
229 kernel_mtu = 0;
230
231 err = transport_tx_sock_error(knet_h, dst_link->transport, dst_link->outsock, KNET_SUB_PMTUD, len, savederrno);
232 switch(err) {
233 case -1: /* unrecoverable error */
234 log_debug(knet_h, KNET_SUB_PMTUD, "Unable to send pmtu packet (sendto): %d %s", savederrno, strerror(savederrno));
235 pthread_mutex_unlock(&knet_h->tx_mutex);
236 pthread_mutex_unlock(&knet_h->pmtud_mutex);
237 dst_link->status.stats.tx_pmtu_errors++;
238 pthread_mutex_unlock(&dst_link->link_stats_mutex);
239 return -1;
240 case 0: /* ignore error and continue */
241 break;
242 case 1: /* retry to send those same data */
243 dst_link->status.stats.tx_pmtu_retries++;
244 goto retry;
245 break;
246 }
247
248 pthread_mutex_unlock(&knet_h->tx_mutex);
249
250 if (len != (ssize_t )data_len) {
251 pthread_mutex_unlock(&dst_link->link_stats_mutex);
252 if (savederrno == EMSGSIZE || savederrno == EPERM) {
253 /*
254 * we cannot hold a lock on kmtu_mutex between resetting
255 * knet_h->kernel_mtu and here.
256 * use_kernel_mtu tells us if the knet_h->kernel_mtu was
257 * set to 0 previously and we can trust its value now.
258 */
259 if (use_kernel_mtu) {
260 use_kernel_mtu = 0;
261 if (pthread_mutex_lock(&knet_h->kmtu_mutex) == 0) {
262 kernel_mtu = knet_h->kernel_mtu;
263 pthread_mutex_unlock(&knet_h->kmtu_mutex);
264 }
265 }
266 if (kernel_mtu > 0) {
267 dst_link->last_bad_mtu = kernel_mtu + 1;
268 } else {
269 dst_link->last_bad_mtu = onwire_len;
270 }
271 } else {
272 log_debug(knet_h, KNET_SUB_PMTUD, "Unable to send pmtu packet len: %zu err: %s", onwire_len, strerror(savederrno));
273 }
274
275 } else {
276 dst_link->last_sent_mtu = onwire_len;
277 dst_link->last_recv_mtu = 0;
278 dst_link->status.stats.tx_pmtu_packets++;
279 dst_link->status.stats.tx_pmtu_bytes += data_len;
280 pthread_mutex_unlock(&dst_link->link_stats_mutex);
281
282 if (clock_gettime(CLOCK_REALTIME, &ts) < 0) {
283 log_debug(knet_h, KNET_SUB_PMTUD, "Unable to get current time: %s", strerror(errno));
284 pthread_mutex_unlock(&knet_h->pmtud_mutex);
285 return -1;
286 }
287
288 /*
289 * non fatal, we can wait the next round to reduce the
290 * multiplier
291 */
292 if (clock_gettime(CLOCK_MONOTONIC, &pmtud_crypto_start_ts) < 0) {
293 log_debug(knet_h, KNET_SUB_PMTUD, "Unable to get current time: %s", strerror(errno));
294 pmtud_crypto_reduce = 0;
295 }
296
297 /*
298 * set PMTUd reply timeout to match pong_timeout on a given link
299 *
300 * math: internally pong_timeout is expressed in microseconds, while
301 * the public API exports milliseconds. So careful with the 0's here.
302 * the loop is necessary because we are grabbing the current time just above
303 * and add values to it that could overflow into seconds.
304 */
305
306 if (pthread_mutex_lock(&knet_h->backoff_mutex)) {
307 log_debug(knet_h, KNET_SUB_PMTUD, "Unable to get backoff_mutex");
308 pthread_mutex_unlock(&knet_h->pmtud_mutex);
309 return -1;
310 }
311
312 if (knet_h->crypto_in_use_config) {
313 /*
314 * crypto, under pressure, is a royal PITA
315 */
316 pong_timeout_adj_tmp = dst_link->pong_timeout_adj * dst_link->pmtud_crypto_timeout_multiplier;
317 } else {
318 pong_timeout_adj_tmp = dst_link->pong_timeout_adj;
319 }
320
321 ts.tv_sec += pong_timeout_adj_tmp / 1000000;
322 ts.tv_nsec += (((pong_timeout_adj_tmp) % 1000000) * 1000);
323 while (ts.tv_nsec > 1000000000) {
324 ts.tv_sec += 1;
325 ts.tv_nsec -= 1000000000;
326 }
327
328 pthread_mutex_unlock(&knet_h->backoff_mutex);
329
330 knet_h->pmtud_waiting = 1;
331
332 ret = pthread_cond_timedwait(&knet_h->pmtud_cond, &knet_h->pmtud_mutex, &ts);
333
334 knet_h->pmtud_waiting = 0;
335
336 if (knet_h->pmtud_abort) {
337 pthread_mutex_unlock(&knet_h->pmtud_mutex);
338 errno = EDEADLK;
339 return -1;
340 }
341
342 /*
343 * we cannot use shutdown_in_progress in here because
344 * we already hold the read lock
345 */
346 if (knet_h->fini_in_progress) {
347 pthread_mutex_unlock(&knet_h->pmtud_mutex);
348 log_debug(knet_h, KNET_SUB_PMTUD, "PMTUD aborted. shutdown in progress");
349 return -1;
350 }
351
352 if (ret) {
353 if (ret == ETIMEDOUT) {
354 if ((knet_h->crypto_in_use_config) && (dst_link->pmtud_crypto_timeout_multiplier < KNET_LINK_PMTUD_CRYPTO_TIMEOUT_MULTIPLIER_MAX)) {
355 dst_link->pmtud_crypto_timeout_multiplier = dst_link->pmtud_crypto_timeout_multiplier * 2;
356 pmtud_crypto_reduce = 0;
357 log_debug(knet_h, KNET_SUB_PMTUD,
358 "Increasing PMTUd response timeout multiplier to (%u) for host %u link: %u",
359 dst_link->pmtud_crypto_timeout_multiplier,
360 dst_host->host_id,
361 dst_link->link_id);
362 pthread_mutex_unlock(&knet_h->pmtud_mutex);
363 goto restart;
364 }
365 if (!warn_once) {
366 log_warn(knet_h, KNET_SUB_PMTUD,
367 "possible MTU misconfiguration detected. "
368 "kernel is reporting MTU: %u bytes for "
369 "host %u link %u but the other node is "
370 "not acknowledging packets of this size. ",
371 dst_link->last_sent_mtu,
372 dst_host->host_id,
373 dst_link->link_id);
374 log_warn(knet_h, KNET_SUB_PMTUD,
375 "This can be caused by this node interface MTU "
376 "too big or a network device that does not "
377 "support or has been misconfigured to manage MTU "
378 "of this size, or packet loss. knet will continue "
379 "to run but performances might be affected.");
380 warn_once = 1;
381 }
382 } else {
383 pthread_mutex_unlock(&knet_h->pmtud_mutex);
384 if (mutex_retry_limit == 3) {
385 log_debug(knet_h, KNET_SUB_PMTUD, "PMTUD aborted, unable to get mutex lock");
386 return -1;
387 }
388 mutex_retry_limit++;
389 goto restart;
390 }
391 }
392
393 if ((knet_h->crypto_in_use_config) && (pmtud_crypto_reduce == 1) &&
394 (dst_link->pmtud_crypto_timeout_multiplier > KNET_LINK_PMTUD_CRYPTO_TIMEOUT_MULTIPLIER_MIN)) {
395 if (!clock_gettime(CLOCK_MONOTONIC, &pmtud_crypto_stop_ts)) {
396 timespec_diff(pmtud_crypto_start_ts, pmtud_crypto_stop_ts, &timediff);
397 if (((pong_timeout_adj_tmp * 1000) / 2) > timediff) {
398 dst_link->pmtud_crypto_timeout_multiplier = dst_link->pmtud_crypto_timeout_multiplier / 2;
399 log_debug(knet_h, KNET_SUB_PMTUD,
400 "Decreasing PMTUd response timeout multiplier to (%u) for host %u link: %u",
401 dst_link->pmtud_crypto_timeout_multiplier,
402 dst_host->host_id,
403 dst_link->link_id);
404 }
405 } else {
406 log_debug(knet_h, KNET_SUB_PMTUD, "Unable to get current time: %s", strerror(errno));
407 }
408 }
409
410 if ((dst_link->last_recv_mtu != onwire_len) || (ret)) {
411 dst_link->last_bad_mtu = onwire_len;
412 } else {
413 int found_mtu = 0;
414
415 if (knet_h->sec_block_size) {
416 if ((onwire_len + knet_h->sec_block_size >= max_mtu_len) ||
417 ((dst_link->last_bad_mtu) && (dst_link->last_bad_mtu <= (onwire_len + knet_h->sec_block_size)))) {
418 found_mtu = 1;
419 }
420 } else {
421 if ((onwire_len == max_mtu_len) ||
422 ((dst_link->last_bad_mtu) && (dst_link->last_bad_mtu == (onwire_len + 1))) ||
423 (dst_link->last_bad_mtu == dst_link->last_good_mtu)) {
424 found_mtu = 1;
425 }
426 }
427
428 if (found_mtu) {
429 /*
430 * account for IP overhead, knet headers and crypto in PMTU calculation
431 */
432 dst_link->status.mtu = calc_max_data_outlen(knet_h, onwire_len - ipproto_overhead_len);
433 pthread_mutex_unlock(&knet_h->pmtud_mutex);
434 return 0;
435 }
436
437 dst_link->last_good_mtu = onwire_len;
438 }
439 }
440
441 if (kernel_mtu) {
442 onwire_len = kernel_mtu;
443 } else {
444 onwire_len = (dst_link->last_good_mtu + dst_link->last_bad_mtu) / 2;
445 }
446
447 pthread_mutex_unlock(&knet_h->pmtud_mutex);
448
449 goto restart;
450 }
451
452 static int _handle_check_pmtud(knet_handle_t knet_h, struct knet_host *dst_host, struct knet_link *dst_link, int force_run)
453 {
454 uint8_t saved_valid_pmtud;
455 unsigned int saved_pmtud;
456 struct timespec clock_now;
457 unsigned long long diff_pmtud, interval;
458
459 if (clock_gettime(CLOCK_MONOTONIC, &clock_now) != 0) {
460 log_debug(knet_h, KNET_SUB_PMTUD, "Unable to get monotonic clock");
461 return 0;
462 }
463
464 if (!force_run) {
465 interval = knet_h->pmtud_interval * 1000000000llu; /* nanoseconds */
466
467 timespec_diff(dst_link->pmtud_last, clock_now, &diff_pmtud);
468
469 if (diff_pmtud < interval) {
470 return dst_link->has_valid_mtu;
471 }
472 }
473
474 /*
475 * status.proto_overhead should include all IP/(UDP|SCTP)/knet headers
476 *
477 * please note that it is not the same as link->proto_overhead that
478 * includes only either UDP or SCTP (at the moment) overhead.
479 */
480 switch (dst_link->dst_addr.ss_family) {
481 case AF_INET6:
482 dst_link->status.proto_overhead = KNET_PMTUD_OVERHEAD_V6 + dst_link->proto_overhead + KNET_HEADER_ALL_SIZE + knet_h->sec_hash_size + knet_h->sec_salt_size;
483 break;
484 case AF_INET:
485 dst_link->status.proto_overhead = KNET_PMTUD_OVERHEAD_V4 + dst_link->proto_overhead + KNET_HEADER_ALL_SIZE + knet_h->sec_hash_size + knet_h->sec_salt_size;
486 break;
487 }
488
489 saved_pmtud = dst_link->status.mtu;
490 saved_valid_pmtud = dst_link->has_valid_mtu;
491
492 log_debug(knet_h, KNET_SUB_PMTUD, "Starting PMTUD for host: %u link: %u", dst_host->host_id, dst_link->link_id);
493
494 errno = 0;
495 if (_handle_check_link_pmtud(knet_h, dst_host, dst_link) < 0) {
496 if (errno == EDEADLK) {
497 log_debug(knet_h, KNET_SUB_PMTUD, "PMTUD for host: %u link: %u has been rescheduled", dst_host->host_id, dst_link->link_id);
498 dst_link->status.mtu = saved_pmtud;
499 dst_link->has_valid_mtu = saved_valid_pmtud;
500 errno = EDEADLK;
501 return dst_link->has_valid_mtu;
502 }
503 dst_link->has_valid_mtu = 0;
504 } else {
505 if (dst_link->status.mtu < calc_min_mtu(knet_h)) {
506 log_info(knet_h, KNET_SUB_PMTUD,
507 "Invalid MTU detected for host: %u link: %u mtu: %u",
508 dst_host->host_id, dst_link->link_id, dst_link->status.mtu);
509 dst_link->has_valid_mtu = 0;
510 } else {
511 dst_link->has_valid_mtu = 1;
512 }
513 if (dst_link->has_valid_mtu) {
514 if ((saved_pmtud) && (saved_pmtud != dst_link->status.mtu)) {
515 log_info(knet_h, KNET_SUB_PMTUD, "PMTUD link change for host: %u link: %u from %u to %u",
516 dst_host->host_id, dst_link->link_id, saved_pmtud, dst_link->status.mtu);
517 }
518 log_debug(knet_h, KNET_SUB_PMTUD, "PMTUD completed for host: %u link: %u current link mtu: %u",
519 dst_host->host_id, dst_link->link_id, dst_link->status.mtu);
520
521 /*
522 * set pmtud_last, if we can, after we are done with the PMTUd process
523 * because it can take a very long time.
524 */
525 dst_link->pmtud_last = clock_now;
526 if (!clock_gettime(CLOCK_MONOTONIC, &clock_now)) {
527 dst_link->pmtud_last = clock_now;
528 }
529 }
530 }
531
532 if (saved_valid_pmtud != dst_link->has_valid_mtu) {
533 _host_dstcache_update_async(knet_h, dst_host);
534 }
535
536 return dst_link->has_valid_mtu;
537 }
538
539 void *_handle_pmtud_link_thread(void *data)
540 {
541 knet_handle_t knet_h = (knet_handle_t) data;
542 struct knet_host *dst_host;
543 struct knet_link *dst_link;
544 int link_idx;
545 unsigned int have_mtu;
546 unsigned int lower_mtu;
547 int link_has_mtu;
548 int force_run = 0;
549
550 set_thread_status(knet_h, KNET_THREAD_PMTUD, KNET_THREAD_STARTED);
551
552 knet_h->data_mtu = calc_min_mtu(knet_h);
553
554 /* preparing pmtu buffer */
555 knet_h->pmtudbuf->kh_version = KNET_HEADER_VERSION;
556 knet_h->pmtudbuf->kh_type = KNET_HEADER_TYPE_PMTUD;
557 knet_h->pmtudbuf->kh_node = htons(knet_h->host_id);
558
559 while (!shutdown_in_progress(knet_h)) {
560 usleep(KNET_THREADS_TIMERES);
561
562 if (pthread_mutex_lock(&knet_h->pmtud_mutex) != 0) {
563 log_debug(knet_h, KNET_SUB_PMTUD, "Unable to get mutex lock");
564 continue;
565 }
566 knet_h->pmtud_abort = 0;
567 knet_h->pmtud_running = 1;
568 force_run = knet_h->pmtud_forcerun;
569 knet_h->pmtud_forcerun = 0;
570 pthread_mutex_unlock(&knet_h->pmtud_mutex);
571
572 if (force_run) {
573 log_debug(knet_h, KNET_SUB_PMTUD, "PMTUd request to rerun has been received");
574 }
575
576 if (pthread_rwlock_rdlock(&knet_h->global_rwlock) != 0) {
577 log_debug(knet_h, KNET_SUB_PMTUD, "Unable to get read lock");
578 continue;
579 }
580
581 lower_mtu = KNET_PMTUD_SIZE_V4;
582 have_mtu = 0;
583
584 for (dst_host = knet_h->host_head; dst_host != NULL; dst_host = dst_host->next) {
585 for (link_idx = 0; link_idx < KNET_MAX_LINK; link_idx++) {
586 dst_link = &dst_host->link[link_idx];
587
588 if ((dst_link->status.enabled != 1) ||
589 (dst_link->status.connected != 1) ||
590 (dst_host->link[link_idx].transport == KNET_TRANSPORT_LOOPBACK) ||
591 (!dst_link->last_ping_size) ||
592 ((dst_link->dynamic == KNET_LINK_DYNIP) &&
593 (dst_link->status.dynconnected != 1)))
594 continue;
595
596 if (!knet_h->manual_mtu) {
597 link_has_mtu = _handle_check_pmtud(knet_h, dst_host, dst_link, force_run);
598 if (errno == EDEADLK) {
599 goto out_unlock;
600 }
601 if (link_has_mtu) {
602 have_mtu = 1;
603 if (dst_link->status.mtu < lower_mtu) {
604 lower_mtu = dst_link->status.mtu;
605 }
606 }
607 } else {
608 link_has_mtu = _calculate_manual_mtu(knet_h, dst_link);
609 if (link_has_mtu) {
610 have_mtu = 1;
611 if (dst_link->status.mtu < lower_mtu) {
612 lower_mtu = dst_link->status.mtu;
613 }
614 }
615 }
616 }
617 }
618
619 if (have_mtu) {
620 if (knet_h->data_mtu != lower_mtu) {
621 knet_h->data_mtu = lower_mtu;
622 log_info(knet_h, KNET_SUB_PMTUD, "Global data MTU changed to: %u", knet_h->data_mtu);
623
624 if (knet_h->pmtud_notify_fn) {
625 knet_h->pmtud_notify_fn(knet_h->pmtud_notify_fn_private_data,
626 knet_h->data_mtu);
627 }
628 }
629 }
630 out_unlock:
631 pthread_rwlock_unlock(&knet_h->global_rwlock);
632 if (pthread_mutex_lock(&knet_h->pmtud_mutex) != 0) {
633 log_debug(knet_h, KNET_SUB_PMTUD, "Unable to get mutex lock");
634 } else {
635 knet_h->pmtud_running = 0;
636 pthread_mutex_unlock(&knet_h->pmtud_mutex);
637 }
638 }
639
640 set_thread_status(knet_h, KNET_THREAD_PMTUD, KNET_THREAD_STOPPED);
641
642 return NULL;
643 }
644
645 int knet_handle_pmtud_getfreq(knet_handle_t knet_h, unsigned int *interval)
646 {
647 int savederrno = 0;
648
649 if (!_is_valid_handle(knet_h)) {
650 return -1;
651 }
652
653 if (!interval) {
654 errno = EINVAL;
655 return -1;
656 }
657
658 savederrno = pthread_rwlock_rdlock(&knet_h->global_rwlock);
659 if (savederrno) {
660 log_err(knet_h, KNET_SUB_HANDLE, "Unable to get read lock: %s",
661 strerror(savederrno));
662 errno = savederrno;
663 return -1;
664 }
665
666 *interval = knet_h->pmtud_interval;
667
668 pthread_rwlock_unlock(&knet_h->global_rwlock);
669
670 errno = 0;
671 return 0;
672 }
673
674 int knet_handle_pmtud_setfreq(knet_handle_t knet_h, unsigned int interval)
675 {
676 int savederrno = 0;
677
678 if (!_is_valid_handle(knet_h)) {
679 return -1;
680 }
681
682 if ((!interval) || (interval > 86400)) {
683 errno = EINVAL;
684 return -1;
685 }
686
687 savederrno = get_global_wrlock(knet_h);
688 if (savederrno) {
689 log_err(knet_h, KNET_SUB_HANDLE, "Unable to get write lock: %s",
690 strerror(savederrno));
691 errno = savederrno;
692 return -1;
693 }
694
695 knet_h->pmtud_interval = interval;
696 log_debug(knet_h, KNET_SUB_HANDLE, "PMTUd interval set to: %u seconds", interval);
697
698 pthread_rwlock_unlock(&knet_h->global_rwlock);
699
700 errno = 0;
701 return 0;
702 }
703
704 int knet_handle_enable_pmtud_notify(knet_handle_t knet_h,
705 void *pmtud_notify_fn_private_data,
706 void (*pmtud_notify_fn) (
707 void *private_data,
708 unsigned int data_mtu))
709 {
710 int savederrno = 0;
711
712 if (!_is_valid_handle(knet_h)) {
713 return -1;
714 }
715
716 savederrno = get_global_wrlock(knet_h);
717 if (savederrno) {
718 log_err(knet_h, KNET_SUB_HANDLE, "Unable to get write lock: %s",
719 strerror(savederrno));
720 errno = savederrno;
721 return -1;
722 }
723
724 knet_h->pmtud_notify_fn_private_data = pmtud_notify_fn_private_data;
725 knet_h->pmtud_notify_fn = pmtud_notify_fn;
726 if (knet_h->pmtud_notify_fn) {
727 log_debug(knet_h, KNET_SUB_HANDLE, "pmtud_notify_fn enabled");
728 } else {
729 log_debug(knet_h, KNET_SUB_HANDLE, "pmtud_notify_fn disabled");
730 }
731
732 pthread_rwlock_unlock(&knet_h->global_rwlock);
733
734 errno = 0;
735 return 0;
736 }
737
738 int knet_handle_pmtud_set(knet_handle_t knet_h,
739 unsigned int iface_mtu)
740 {
741 int savederrno = 0;
742
743 if (!_is_valid_handle(knet_h)) {
744 return -1;
745 }
746
747 if (iface_mtu > KNET_PMTUD_SIZE_V4) {
748 errno = EINVAL;
749 return -1;
750 }
751
752 savederrno = pthread_rwlock_rdlock(&knet_h->global_rwlock);
753 if (savederrno) {
754 log_err(knet_h, KNET_SUB_PMTUD, "Unable to get read lock: %s",
755 strerror(savederrno));
756 errno = savederrno;
757 return -1;
758 }
759
760 log_info(knet_h, KNET_SUB_PMTUD, "MTU manually set to: %u", iface_mtu);
761
762 knet_h->manual_mtu = iface_mtu;
763
764 force_pmtud_run(knet_h, KNET_SUB_PMTUD, 0, 0);
765
766 pthread_rwlock_unlock(&knet_h->global_rwlock);
767
768 errno = 0;
769 return 0;
770 }
771
772 int knet_handle_pmtud_get(knet_handle_t knet_h,
773 unsigned int *data_mtu)
774 {
775 int savederrno = 0;
776
777 if (!_is_valid_handle(knet_h)) {
778 return -1;
779 }
780
781 if (!data_mtu) {
782 errno = EINVAL;
783 return -1;
784 }
785
786 savederrno = pthread_rwlock_rdlock(&knet_h->global_rwlock);
787 if (savederrno) {
788 log_err(knet_h, KNET_SUB_HANDLE, "Unable to get read lock: %s",
789 strerror(savederrno));
790 errno = savederrno;
791 return -1;
792 }
793
794 *data_mtu = knet_h->data_mtu;
795
796 pthread_rwlock_unlock(&knet_h->global_rwlock);
797
798 errno = 0;
799 return 0;
800 }
801