1 /*
2 * Copyright (C) 2012-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 <errno.h>
13 #include <netdb.h>
14 #include <string.h>
15 #include <pthread.h>
16
17 #include "netutils.h"
18 #include "internals.h"
19 #include "logging.h"
20 #include "links.h"
21 #include "transports.h"
22 #include "host.h"
23 #include "threads_common.h"
24 #include "links_acl.h"
25 #include <ifaddrs.h>
26 #include <net/if.h>
27
28 static int find_ifindex(struct sockaddr_storage *addr)
29 {
30 struct ifaddrs *ifrs, *ifa;
31
32 if (getifaddrs(&ifrs) == 0) {
33 for (ifa = ifrs; ifa != NULL; ifa = ifa->ifa_next) {
34 if (ifa->ifa_addr && cmpaddr(addr, (struct sockaddr_storage *)ifa->ifa_addr) == 0) {
35 int ifindex = if_nametoindex(ifa->ifa_name);
36 freeifaddrs(ifrs);
37 return ifindex;
38 }
39 }
40 freeifaddrs(ifrs);
41 }
42 return -1;
43 }
44
45 int _link_updown(knet_handle_t knet_h, knet_node_id_t host_id, uint8_t link_id,
46 unsigned int enabled, unsigned int connected, unsigned int lock_stats)
47 {
48 struct knet_host *host = knet_h->host_index[host_id];
49 struct knet_link *link = &host->link[link_id];
50 int savederrno = 0;
51
52 if ((link->status.enabled == enabled) &&
53 (link->status.connected == connected))
54 return 0;
55
56 link->status.enabled = enabled;
57 link->status.connected = connected;
58
59 _host_dstcache_update_async(knet_h, knet_h->host_index[host_id]);
60
61 if ((link->status.dynconnected) &&
62 (!link->status.connected)) {
63 link->status.dynconnected = 0;
64 }
65
66 if (!connected) {
67 transport_link_is_down(knet_h, link);
68 } else {
69 /* Reset MTU in case new link can't use full line MTU */
70 log_info(knet_h, KNET_SUB_LINK, "Resetting MTU for link %u because host %u joined", link_id, host_id);
71 force_pmtud_run(knet_h, KNET_SUB_LINK, 1, 1);
72 }
73
74 if (lock_stats) {
75 savederrno = pthread_mutex_lock(&link->link_stats_mutex);
76 if (savederrno) {
77 log_err(knet_h, KNET_SUB_LINK, "Unable to get stats mutex lock for host %u link %u: %s",
78 host_id, link_id, strerror(savederrno));
79 errno = savederrno;
80 return -1;
81 }
82 }
83
84 if (connected) {
85 time(&link->status.stats.last_up_times[link->status.stats.last_up_time_index]);
86 link->status.stats.up_count++;
87 if (++link->status.stats.last_up_time_index >= MAX_LINK_EVENTS) {
88 link->status.stats.last_up_time_index = 0;
89 }
90 knet_h->knet_transport_fd_tracker[link->outsock].ifindex = find_ifindex(&link->src_addr);
91 } else {
92 time(&link->status.stats.last_down_times[link->status.stats.last_down_time_index]);
93 link->status.stats.down_count++;
94 if (++link->status.stats.last_down_time_index >= MAX_LINK_EVENTS) {
95 link->status.stats.last_down_time_index = 0;
96 }
97 }
98
99 if (lock_stats) {
100 pthread_mutex_unlock(&link->link_stats_mutex);
101 }
102 return 0;
103 }
104
105 void _link_clear_stats(knet_handle_t knet_h)
106 {
107 struct knet_host *host;
108 struct knet_link *link;
109 uint32_t host_id;
110 uint8_t link_id;
111
112 for (host_id = 0; host_id < KNET_MAX_HOST; host_id++) {
113 host = knet_h->host_index[host_id];
114 if (!host) {
115 continue;
116 }
117 for (link_id = 0; link_id < KNET_MAX_LINK; link_id++) {
118 link = &host->link[link_id];
119 memset(&link->status.stats, 0, sizeof(struct knet_link_stats));
120 }
121 }
122 }
123
124 int knet_link_set_config(knet_handle_t knet_h, knet_node_id_t host_id, uint8_t link_id,
125 uint8_t transport,
126 struct sockaddr_storage *src_addr,
127 struct sockaddr_storage *dst_addr,
128 uint64_t flags)
129 {
130 int savederrno = 0, err = 0, i, wipelink = 0, link_idx;
131 struct knet_host *host, *tmp_host;
132 struct knet_link *link = NULL;
133
134 if (!_is_valid_handle(knet_h)) {
135 return -1;
136 }
137
138 if (link_id >= KNET_MAX_LINK) {
139 errno = EINVAL;
140 return -1;
141 }
142
143 if (!src_addr) {
144 errno = EINVAL;
145 return -1;
146 }
147
148 if (dst_addr && (src_addr->ss_family != dst_addr->ss_family)) {
149 log_err(knet_h, KNET_SUB_LINK, "Source address family does not match destination address family");
150 errno = EINVAL;
151 return -1;
152 }
153
154 if (transport >= KNET_MAX_TRANSPORTS) {
155 errno = EINVAL;
156 return -1;
157 }
158
159 savederrno = get_global_wrlock(knet_h);
160 if (savederrno) {
161 log_err(knet_h, KNET_SUB_LINK, "Unable to get write lock: %s",
162 strerror(savederrno));
163 errno = savederrno;
164 return -1;
165 }
166
167 if (transport == KNET_TRANSPORT_LOOPBACK && knet_h->host_id != host_id) {
168 log_err(knet_h, KNET_SUB_LINK, "Cannot create loopback link to remote node");
169 err = -1;
170 savederrno = EINVAL;
171 goto exit_unlock;
172 }
173
174 if (knet_h->host_id == host_id && knet_h->has_loop_link) {
175 log_err(knet_h, KNET_SUB_LINK, "Cannot create more than 1 link when loopback is active");
176 err = -1;
177 savederrno = EINVAL;
178 goto exit_unlock;
179 }
180
181 host = knet_h->host_index[host_id];
182 if (!host) {
183 err = -1;
184 savederrno = EINVAL;
185 log_err(knet_h, KNET_SUB_LINK, "Unable to find host %u: %s",
186 host_id, strerror(savederrno));
187 goto exit_unlock;
188 }
189
190 if (transport == KNET_TRANSPORT_LOOPBACK && knet_h->host_id == host_id) {
191 for (i=0; i<KNET_MAX_LINK; i++) {
192 if (host->link[i].configured) {
193 log_err(knet_h, KNET_SUB_LINK, "Cannot add loopback link when other links are already configured.");
194 err = -1;
195 savederrno = EINVAL;
196 goto exit_unlock;
197 }
198 }
199 }
200
201 link = &host->link[link_id];
202
203 if (link->configured != 0) {
204 err =-1;
205 savederrno = EBUSY;
206 log_err(knet_h, KNET_SUB_LINK, "Host %u link %u is currently configured: %s",
207 host_id, link_id, strerror(savederrno));
208 goto exit_unlock;
209 }
210
211 if (link->status.enabled != 0) {
212 err =-1;
213 savederrno = EBUSY;
214 log_err(knet_h, KNET_SUB_LINK, "Host %u link %u is currently in use: %s",
215 host_id, link_id, strerror(savederrno));
216 goto exit_unlock;
217 }
218
219 /*
220 * errors happening after this point should trigger
221 * a memset of the link
222 */
223 wipelink = 1;
224
225 copy_sockaddr(&link->src_addr, src_addr);
226
227 err = knet_addrtostr(src_addr, sizeof(struct sockaddr_storage),
228 link->status.src_ipaddr, KNET_MAX_HOST_LEN,
229 link->status.src_port, KNET_MAX_PORT_LEN);
230 if (err) {
231 if (err == EAI_SYSTEM) {
232 savederrno = errno;
233 log_warn(knet_h, KNET_SUB_LINK,
234 "Unable to resolve host: %u link: %u source addr/port: %s",
235 host_id, link_id, strerror(savederrno));
236 } else {
237 savederrno = EINVAL;
238 log_warn(knet_h, KNET_SUB_LINK,
239 "Unable to resolve host: %u link: %u source addr/port: %s",
240 host_id, link_id, gai_strerror(err));
241 }
242 err = -1;
243 goto exit_unlock;
244 }
245
246 if (!dst_addr) {
247 link->dynamic = KNET_LINK_DYNIP;
248 } else {
249
250 link->dynamic = KNET_LINK_STATIC;
251
252 copy_sockaddr(&link->dst_addr, dst_addr);
253 err = knet_addrtostr(dst_addr, sizeof(struct sockaddr_storage),
254 link->status.dst_ipaddr, KNET_MAX_HOST_LEN,
255 link->status.dst_port, KNET_MAX_PORT_LEN);
256 if (err) {
257 if (err == EAI_SYSTEM) {
258 savederrno = errno;
259 log_warn(knet_h, KNET_SUB_LINK,
260 "Unable to resolve host: %u link: %u destination addr/port: %s",
261 host_id, link_id, strerror(savederrno));
262 } else {
263 savederrno = EINVAL;
264 log_warn(knet_h, KNET_SUB_LINK,
265 "Unable to resolve host: %u link: %u destination addr/port: %s",
266 host_id, link_id, gai_strerror(err));
267 }
268 err = -1;
269 goto exit_unlock;
270 }
271 }
272
273 link->pmtud_crypto_timeout_multiplier = KNET_LINK_PMTUD_CRYPTO_TIMEOUT_MULTIPLIER_MIN;
274 link->pong_count = KNET_LINK_DEFAULT_PONG_COUNT;
275 link->has_valid_mtu = 0;
276 link->ping_interval = KNET_LINK_DEFAULT_PING_INTERVAL * 1000; /* microseconds */
277 link->pong_timeout = KNET_LINK_DEFAULT_PING_TIMEOUT * 1000; /* microseconds */
278 link->pong_timeout_backoff = KNET_LINK_PONG_TIMEOUT_BACKOFF;
279 link->pong_timeout_adj = link->pong_timeout * link->pong_timeout_backoff; /* microseconds */
280 link->latency_max_samples = KNET_LINK_DEFAULT_PING_PRECISION;
281 link->latency_cur_samples = 0;
282 link->flags = flags;
283
284 /*
285 * check for DYNIP vs STATIC collisions.
286 * example: link0 is static, user attempts to configure link1 as dynamic with the same source
287 * address/port.
288 * This configuration is invalid and would cause ACL collisions.
289 */
290 for (tmp_host = knet_h->host_head; tmp_host != NULL; tmp_host = tmp_host->next) {
291 for (link_idx = 0; link_idx < KNET_MAX_LINK; link_idx++) {
292 if (&tmp_host->link[link_idx] == link)
293 continue;
294
295 if ((!memcmp(&tmp_host->link[link_idx].src_addr, &link->src_addr, sizeof(struct sockaddr_storage))) &&
296 (tmp_host->link[link_idx].dynamic != link->dynamic)) {
297 savederrno = EINVAL;
298 err = -1;
299 log_err(knet_h, KNET_SUB_LINK, "Failed to configure host %u link %u dyn %u. Conflicts with host %u link %u dyn %u: %s",
300 host_id, link_id, link->dynamic, tmp_host->host_id, link_idx, tmp_host->link[link_idx].dynamic, strerror(savederrno));
301 goto exit_unlock;
302 }
303 }
304 }
305
306 savederrno = pthread_mutex_init(&link->link_stats_mutex, NULL);
307 if (savederrno) {
308 log_err(knet_h, KNET_SUB_LINK, "Unable to initialize link stats mutex: %s", strerror(savederrno));
309 err = -1;
310 goto exit_unlock;
311 }
312
313 if (transport_link_set_config(knet_h, link, transport) < 0) {
314 savederrno = errno;
315 err = -1;
316 goto exit_transport_err;
317 }
318
319 /*
320 * we can only configure default access lists if we know both endpoints
321 * and the protocol uses GENERIC_ACL, otherwise the protocol has
322 * to setup their own access lists above in transport_link_set_config.
323 */
324 if ((transport_get_acl_type(knet_h, transport) == USE_GENERIC_ACL) &&
325 (link->dynamic == KNET_LINK_STATIC)) {
326 log_debug(knet_h, KNET_SUB_LINK, "Configuring default access lists for host: %u link: %u socket: %d",
327 host_id, link_id, link->outsock);
328 if ((check_add(knet_h, link, -1,
329 &link->dst_addr, &link->dst_addr,
330 CHECK_TYPE_ADDRESS, CHECK_ACCEPT) < 0) && (errno != EEXIST)) {
331 log_warn(knet_h, KNET_SUB_LINK, "Failed to configure default access lists for host: %u link: %u", host_id, link_id);
332 savederrno = errno;
333 err = -1;
334 goto exit_acl_error;
335 }
336 }
337
338 /*
339 * no errors should happen after link is configured
340 */
341 link->configured = 1;
342 log_debug(knet_h, KNET_SUB_LINK, "host: %u link: %u is configured",
343 host_id, link_id);
344
345 if (transport == KNET_TRANSPORT_LOOPBACK) {
346 knet_h->has_loop_link = 1;
347 knet_h->loop_link = link_id;
348 host->status.reachable = 1;
349 link->status.mtu = KNET_PMTUD_SIZE_V6;
350 } else {
351 /*
352 * calculate the minimum MTU that is safe to use,
353 * based on RFCs and that each network device should
354 * be able to support without any troubles
355 */
356 if (link->dynamic == KNET_LINK_STATIC) {
357 /*
358 * with static link we can be more precise than using
359 * the generic calc_min_mtu()
360 */
361 switch (link->dst_addr.ss_family) {
362 case AF_INET6:
363 link->status.mtu = calc_max_data_outlen(knet_h, KNET_PMTUD_MIN_MTU_V6 - (KNET_PMTUD_OVERHEAD_V6 + link->proto_overhead));
364 break;
365 case AF_INET:
366 link->status.mtu = calc_max_data_outlen(knet_h, KNET_PMTUD_MIN_MTU_V4 - (KNET_PMTUD_OVERHEAD_V4 + link->proto_overhead));
367 break;
368 }
369 } else {
370 /*
371 * for dynamic links we start with the minimum MTU
372 * possible and PMTUd will kick in immediately
373 * after connection status is 1
374 */
375 link->status.mtu = calc_min_mtu(knet_h);
376 }
377 link->has_valid_mtu = 1;
378 }
379
380 exit_acl_error:
381 /*
382 * if creating access lists has error, we only need to clean
383 * the transport and the stuff below.
384 */
385 if (err < 0) {
386 if ((transport_link_clear_config(knet_h, link) < 0) &&
387 (errno != EBUSY)) {
388 log_warn(knet_h, KNET_SUB_LINK, "Failed to deconfigure transport for host %u link %u: %s", host_id, link_id, strerror(errno));
389 }
390 }
391 exit_transport_err:
392 /*
393 * if transport has errors, transport will clean after itself
394 * and we only need to clean the mutex
395 */
396 if (err < 0) {
397 pthread_mutex_destroy(&link->link_stats_mutex);
398 }
399 exit_unlock:
400 /*
401 * re-init the link on error
402 */
403 if ((err < 0) && (wipelink)) {
404 memset(link, 0, sizeof(struct knet_link));
405 link->link_id = link_id;
406 }
407 pthread_rwlock_unlock(&knet_h->global_rwlock);
408 errno = err ? savederrno : 0;
409 return err;
410 }
411
412 int knet_link_get_config(knet_handle_t knet_h, knet_node_id_t host_id, uint8_t link_id,
413 uint8_t *transport,
414 struct sockaddr_storage *src_addr,
415 struct sockaddr_storage *dst_addr,
416 uint8_t *dynamic,
417 uint64_t *flags)
418 {
419 int savederrno = 0, err = 0;
420 struct knet_host *host;
421 struct knet_link *link;
422
423 if (!_is_valid_handle(knet_h)) {
424 return -1;
425 }
426
427 if (link_id >= KNET_MAX_LINK) {
428 errno = EINVAL;
429 return -1;
430 }
431
432 if (!src_addr) {
433 errno = EINVAL;
434 return -1;
435 }
436
437 if (!dynamic) {
438 errno = EINVAL;
439 return -1;
440 }
441
442 if (!transport) {
443 errno = EINVAL;
444 return -1;
445 }
446
447 if (!flags) {
448 errno = EINVAL;
449 return -1;
450 }
451
452 savederrno = pthread_rwlock_rdlock(&knet_h->global_rwlock);
453 if (savederrno) {
454 log_err(knet_h, KNET_SUB_LINK, "Unable to get read lock: %s",
455 strerror(savederrno));
456 errno = savederrno;
457 return -1;
458 }
459
460 host = knet_h->host_index[host_id];
461 if (!host) {
462 err = -1;
463 savederrno = EINVAL;
464 log_err(knet_h, KNET_SUB_LINK, "Unable to find host %u: %s",
465 host_id, strerror(savederrno));
466 goto exit_unlock;
467 }
468
469 link = &host->link[link_id];
470
471 if (!link->configured) {
472 err = -1;
473 savederrno = EINVAL;
474 log_err(knet_h, KNET_SUB_LINK, "host %u link %u is not configured: %s",
475 host_id, link_id, strerror(savederrno));
476 goto exit_unlock;
477 }
478
479 if ((link->dynamic == KNET_LINK_STATIC) && (!dst_addr)) {
480 savederrno = EINVAL;
481 err = -1;
482 goto exit_unlock;
483 }
484
485 memmove(src_addr, &link->src_addr, sizeof(struct sockaddr_storage));
486
487 *transport = link->transport;
488 *flags = link->flags;
489
490 if (link->dynamic == KNET_LINK_STATIC) {
491 *dynamic = 0;
492 memmove(dst_addr, &link->dst_addr, sizeof(struct sockaddr_storage));
493 } else {
494 *dynamic = 1;
495 }
496
497 exit_unlock:
498 pthread_rwlock_unlock(&knet_h->global_rwlock);
499 errno = err ? savederrno : 0;
500 return err;
501 }
502
503 int knet_link_clear_config(knet_handle_t knet_h, knet_node_id_t host_id, uint8_t link_id)
504 {
505 int savederrno = 0, err = 0;
506 struct knet_host *host;
507 struct knet_link *link;
508 int sock;
509 uint8_t transport;
510
511 if (!_is_valid_handle(knet_h)) {
512 return -1;
513 }
514
515 if (link_id >= KNET_MAX_LINK) {
516 errno = EINVAL;
517 return -1;
518 }
519
520 savederrno = get_global_wrlock(knet_h);
521 if (savederrno) {
522 log_err(knet_h, KNET_SUB_LINK, "Unable to get write lock: %s",
523 strerror(savederrno));
524 errno = savederrno;
525 return -1;
526 }
527
528 host = knet_h->host_index[host_id];
529 if (!host) {
530 err = -1;
531 savederrno = EINVAL;
532 log_err(knet_h, KNET_SUB_LINK, "Unable to find host %u: %s",
533 host_id, strerror(savederrno));
534 goto exit_unlock;
535 }
536
537 link = &host->link[link_id];
538
539 if (link->configured != 1) {
540 err = -1;
541 savederrno = EINVAL;
542 log_err(knet_h, KNET_SUB_LINK, "Host %u link %u is not configured: %s",
543 host_id, link_id, strerror(savederrno));
544 goto exit_unlock;
545 }
546
547 if (link->status.enabled != 0) {
548 err = -1;
549 savederrno = EBUSY;
550 log_err(knet_h, KNET_SUB_LINK, "Host %u link %u is currently in use: %s",
551 host_id, link_id, strerror(savederrno));
552 goto exit_unlock;
553 }
554
555 /*
556 * remove well known access lists here.
557 * After the transport has done clearing the config,
558 * then we can remove any leftover access lists if the link
559 * is no longer in use.
560 */
561 if ((transport_get_acl_type(knet_h, link->transport) == USE_GENERIC_ACL) &&
562 (link->dynamic == KNET_LINK_STATIC)) {
563 if ((check_rm(knet_h, link,
564 &link->dst_addr, &link->dst_addr,
565 CHECK_TYPE_ADDRESS, CHECK_ACCEPT) < 0) && (errno != ENOENT)) {
566 err = -1;
567 savederrno = errno;
568 log_err(knet_h, KNET_SUB_LINK, "Host %u link %u: unable to remove default access list",
569 host_id, link_id);
570 goto exit_unlock;
571 }
572 }
573
574 /*
575 * cache it for later as we don't know if the transport
576 * will clear link info during clear_config.
577 */
578 sock = link->outsock;
579 transport = link->transport;
580
581 if ((transport_link_clear_config(knet_h, link) < 0) &&
582 (errno != EBUSY)) {
583 savederrno = errno;
584 err = -1;
585 goto exit_unlock;
586 }
587
588 /*
589 * remove any other access lists when the socket is no
590 * longer in use by the transport.
591 */
592 if ((transport_get_acl_type(knet_h, transport) == USE_GENERIC_ACL) &&
593 (knet_h->knet_transport_fd_tracker[sock].transport == KNET_MAX_TRANSPORTS)) {
594 check_rmall(knet_h, link);
595 }
596
597 pthread_mutex_destroy(&link->link_stats_mutex);
598
599 memset(link, 0, sizeof(struct knet_link));
600 link->link_id = link_id;
601
602 if (knet_h->has_loop_link && host_id == knet_h->host_id && link_id == knet_h->loop_link) {
603 knet_h->has_loop_link = 0;
604 if (host->active_link_entries == 0) {
605 host->status.reachable = 0;
606 }
607 }
608
609 log_debug(knet_h, KNET_SUB_LINK, "host: %u link: %u config has been wiped",
610 host_id, link_id);
611
612 exit_unlock:
613 pthread_rwlock_unlock(&knet_h->global_rwlock);
614 errno = err ? savederrno : 0;
615 return err;
616 }
617
618 int knet_link_set_enable(knet_handle_t knet_h, knet_node_id_t host_id, uint8_t link_id,
619 unsigned int enabled)
620 {
621 int savederrno = 0, err = 0;
622 struct knet_host *host;
623 struct knet_link *link;
624
625 if (!_is_valid_handle(knet_h)) {
626 return -1;
627 }
628
629 if (link_id >= KNET_MAX_LINK) {
630 errno = EINVAL;
631 return -1;
632 }
633
634 if (enabled > 1) {
635 errno = EINVAL;
636 return -1;
637 }
638
639 savederrno = get_global_wrlock(knet_h);
640 if (savederrno) {
641 log_err(knet_h, KNET_SUB_LINK, "Unable to get read lock: %s",
642 strerror(savederrno));
643 errno = savederrno;
644 return -1;
645 }
646
647 host = knet_h->host_index[host_id];
648 if (!host) {
649 err = -1;
650 savederrno = EINVAL;
651 log_err(knet_h, KNET_SUB_LINK, "Unable to find host %u: %s",
652 host_id, strerror(savederrno));
653 goto exit_unlock;
654 }
655
656 link = &host->link[link_id];
657
658 if (!link->configured) {
659 err = -1;
660 savederrno = EINVAL;
661 log_err(knet_h, KNET_SUB_LINK, "host %u link %u is not configured: %s",
662 host_id, link_id, strerror(savederrno));
663 goto exit_unlock;
664 }
665
666 if (link->status.enabled == enabled) {
667 err = 0;
668 goto exit_unlock;
669 }
670
671 err = _link_updown(knet_h, host_id, link_id, enabled, link->status.connected, 0);
672 savederrno = errno;
673
674 if (enabled) {
675 goto exit_unlock;
676 }
677
678 log_debug(knet_h, KNET_SUB_LINK, "host: %u link: %u is disabled",
679 host_id, link_id);
680
681 exit_unlock:
682 pthread_rwlock_unlock(&knet_h->global_rwlock);
683 errno = err ? savederrno : 0;
684 return err;
685 }
686
687 int knet_link_get_enable(knet_handle_t knet_h, knet_node_id_t host_id, uint8_t link_id,
688 unsigned int *enabled)
689 {
690 int savederrno = 0, err = 0;
691 struct knet_host *host;
692 struct knet_link *link;
693
694 if (!_is_valid_handle(knet_h)) {
695 return -1;
696 }
697
698 if (link_id >= KNET_MAX_LINK) {
699 errno = EINVAL;
700 return -1;
701 }
702
703 if (!enabled) {
704 errno = EINVAL;
705 return -1;
706 }
707
708 savederrno = pthread_rwlock_rdlock(&knet_h->global_rwlock);
709 if (savederrno) {
710 log_err(knet_h, KNET_SUB_LINK, "Unable to get read lock: %s",
711 strerror(savederrno));
712 errno = savederrno;
713 return -1;
714 }
715
716 host = knet_h->host_index[host_id];
717 if (!host) {
718 err = -1;
719 savederrno = EINVAL;
720 log_err(knet_h, KNET_SUB_LINK, "Unable to find host %u: %s",
721 host_id, strerror(savederrno));
722 goto exit_unlock;
723 }
724
725 link = &host->link[link_id];
726
727 if (!link->configured) {
728 err = -1;
729 savederrno = EINVAL;
730 log_err(knet_h, KNET_SUB_LINK, "host %u link %u is not configured: %s",
731 host_id, link_id, strerror(savederrno));
732 goto exit_unlock;
733 }
734
735 *enabled = link->status.enabled;
736
737 exit_unlock:
738 pthread_rwlock_unlock(&knet_h->global_rwlock);
739 errno = err ? savederrno : 0;
740 return err;
741 }
742
743 int knet_link_set_pong_count(knet_handle_t knet_h, knet_node_id_t host_id, uint8_t link_id,
744 uint8_t pong_count)
745 {
746 int savederrno = 0, err = 0;
747 struct knet_host *host;
748 struct knet_link *link;
749
750 if (!_is_valid_handle(knet_h)) {
751 return -1;
752 }
753
754 if (link_id >= KNET_MAX_LINK) {
755 errno = EINVAL;
756 return -1;
757 }
758
759 if (pong_count < 1) {
760 errno = EINVAL;
761 return -1;
762 }
763
764 savederrno = get_global_wrlock(knet_h);
765 if (savederrno) {
766 log_err(knet_h, KNET_SUB_LINK, "Unable to get write lock: %s",
767 strerror(savederrno));
768 errno = savederrno;
769 return -1;
770 }
771
772 host = knet_h->host_index[host_id];
773 if (!host) {
774 err = -1;
775 savederrno = EINVAL;
776 log_err(knet_h, KNET_SUB_LINK, "Unable to find host %u: %s",
777 host_id, strerror(savederrno));
778 goto exit_unlock;
779 }
780
781 link = &host->link[link_id];
782
783 if (!link->configured) {
784 err = -1;
785 savederrno = EINVAL;
786 log_err(knet_h, KNET_SUB_LINK, "host %u link %u is not configured: %s",
787 host_id, link_id, strerror(savederrno));
788 goto exit_unlock;
789 }
790
791 link->pong_count = pong_count;
792
793 log_debug(knet_h, KNET_SUB_LINK,
794 "host: %u link: %u pong count update: %u",
795 host_id, link_id, link->pong_count);
796
797 exit_unlock:
798 pthread_rwlock_unlock(&knet_h->global_rwlock);
799 errno = err ? savederrno : 0;
800 return err;
801 }
802
803 int knet_link_get_pong_count(knet_handle_t knet_h, knet_node_id_t host_id, uint8_t link_id,
804 uint8_t *pong_count)
805 {
806 int savederrno = 0, err = 0;
807 struct knet_host *host;
808 struct knet_link *link;
809
810 if (!_is_valid_handle(knet_h)) {
811 return -1;
812 }
813
814 if (link_id >= KNET_MAX_LINK) {
815 errno = EINVAL;
816 return -1;
817 }
818
819 if (!pong_count) {
820 errno = EINVAL;
821 return -1;
822 }
823
824 savederrno = pthread_rwlock_rdlock(&knet_h->global_rwlock);
825 if (savederrno) {
826 log_err(knet_h, KNET_SUB_LINK, "Unable to get read lock: %s",
827 strerror(savederrno));
828 errno = savederrno;
829 return -1;
830 }
831
832 host = knet_h->host_index[host_id];
833 if (!host) {
834 err = -1;
835 savederrno = EINVAL;
836 log_err(knet_h, KNET_SUB_LINK, "Unable to find host %u: %s",
837 host_id, strerror(savederrno));
838 goto exit_unlock;
839 }
840
841 link = &host->link[link_id];
842
843 if (!link->configured) {
844 err = -1;
845 savederrno = EINVAL;
846 log_err(knet_h, KNET_SUB_LINK, "host %u link %u is not configured: %s",
847 host_id, link_id, strerror(savederrno));
848 goto exit_unlock;
849 }
850
851 *pong_count = link->pong_count;
852
853 exit_unlock:
854 pthread_rwlock_unlock(&knet_h->global_rwlock);
855 errno = err ? savederrno : 0;
856 return err;
857 }
858
859 int knet_link_set_ping_timers(knet_handle_t knet_h, knet_node_id_t host_id, uint8_t link_id,
860 time_t interval, time_t timeout, unsigned int precision)
861 {
862 int savederrno = 0, err = 0;
863 struct knet_host *host;
864 struct knet_link *link;
865 unsigned long long ping_interval, pong_timeout;
866
867 if (!_is_valid_handle(knet_h)) {
868 return -1;
869 }
870
871 if (link_id >= KNET_MAX_LINK) {
872 errno = EINVAL;
873 return -1;
874 }
875
876 if (interval <= 0) {
877 errno = EINVAL;
878 return -1;
879 }
880
881 if (timeout <= 0) {
882 errno = ENOSYS;
883 return -1;
884 }
885
886 if (!precision) {
887 errno = EINVAL;
888 return -1;
889 }
890
891 savederrno = get_global_wrlock(knet_h);
892 if (savederrno) {
893 log_err(knet_h, KNET_SUB_LINK, "Unable to get write lock: %s",
894 strerror(savederrno));
895 errno = savederrno;
896 return -1;
897 }
898
899 host = knet_h->host_index[host_id];
900 if (!host) {
901 err = -1;
902 savederrno = EINVAL;
903 log_err(knet_h, KNET_SUB_LINK, "Unable to find host %u: %s",
904 host_id, strerror(savederrno));
905 goto exit_unlock;
906 }
907
908 link = &host->link[link_id];
909
910 if (!link->configured) {
911 err = -1;
912 savederrno = EINVAL;
913 log_err(knet_h, KNET_SUB_LINK, "host %u link %u is not configured: %s",
914 host_id, link_id, strerror(savederrno));
915 goto exit_unlock;
916 }
917
918 ping_interval = (unsigned long long)interval * 1000; /* microseconds */
919 if (ping_interval < KNET_THREADS_TIMERES) {
920 log_warn(knet_h, KNET_SUB_LINK,
921 "host: %u link: %u interval: %llu too small (%s). interval lower than thread_timer_res (%u ms) has no effect",
922 host_id, link_id, (unsigned long long)interval, strerror(savederrno), (KNET_THREADS_TIMERES / 1000));
923 }
924
925 pong_timeout = (unsigned long long)timeout * 1000; /* microseconds */
926 if (pong_timeout < KNET_THREADS_TIMERES) {
927 err = -1;
928 savederrno = EINVAL;
929 log_err(knet_h, KNET_SUB_LINK,
930 "host: %u link: %u pong timeout: %llu too small (%s). timeout cannot be less than thread_timer_res (%u ms)",
931 host_id, link_id, (unsigned long long)timeout, strerror(savederrno), (KNET_THREADS_TIMERES / 1000));
932 goto exit_unlock;
933 }
934
935 link->ping_interval = ping_interval;
936 link->pong_timeout = pong_timeout;
937 link->latency_max_samples = precision;
938
939 log_debug(knet_h, KNET_SUB_LINK,
940 "host: %u link: %u timeout update - interval: %llu timeout: %llu precision: %u",
941 host_id, link_id, link->ping_interval, link->pong_timeout, precision);
942
943 exit_unlock:
944 pthread_rwlock_unlock(&knet_h->global_rwlock);
945 errno = err ? savederrno : 0;
946 return err;
947 }
948
949 int knet_link_get_ping_timers(knet_handle_t knet_h, knet_node_id_t host_id, uint8_t link_id,
950 time_t *interval, time_t *timeout, unsigned int *precision)
951 {
952 int savederrno = 0, err = 0;
953 struct knet_host *host;
954 struct knet_link *link;
955
956 if (!_is_valid_handle(knet_h)) {
957 return -1;
958 }
959
960 if (link_id >= KNET_MAX_LINK) {
961 errno = EINVAL;
962 return -1;
963 }
964
965 if (!interval) {
966 errno = EINVAL;
967 return -1;
968 }
969
970 if (!timeout) {
971 errno = EINVAL;
972 return -1;
973 }
974
975 if (!precision) {
976 errno = EINVAL;
977 return -1;
978 }
979
980 savederrno = pthread_rwlock_rdlock(&knet_h->global_rwlock);
981 if (savederrno) {
982 log_err(knet_h, KNET_SUB_LINK, "Unable to get read lock: %s",
983 strerror(savederrno));
984 errno = savederrno;
985 return -1;
986 }
987
988 host = knet_h->host_index[host_id];
989 if (!host) {
990 err = -1;
991 savederrno = EINVAL;
992 log_err(knet_h, KNET_SUB_LINK, "Unable to find host %u: %s",
993 host_id, strerror(savederrno));
994 goto exit_unlock;
995 }
996
997 link = &host->link[link_id];
998
999 if (!link->configured) {
1000 err = -1;
1001 savederrno = EINVAL;
1002 log_err(knet_h, KNET_SUB_LINK, "host %u link %u is not configured: %s",
1003 host_id, link_id, strerror(savederrno));
1004 goto exit_unlock;
1005 }
1006
1007 *interval = link->ping_interval / 1000; /* microseconds */
1008 *timeout = link->pong_timeout / 1000;
1009 *precision = link->latency_max_samples;
1010
1011 exit_unlock:
1012 pthread_rwlock_unlock(&knet_h->global_rwlock);
1013 errno = err ? savederrno : 0;
1014 return err;
1015 }
1016
1017 int knet_link_set_priority(knet_handle_t knet_h, knet_node_id_t host_id, uint8_t link_id,
1018 uint8_t priority)
1019 {
1020 int savederrno = 0, err = 0;
1021 struct knet_host *host;
1022 struct knet_link *link;
1023 uint8_t old_priority;
1024
1025 if (!_is_valid_handle(knet_h)) {
1026 return -1;
1027 }
1028
1029 if (link_id >= KNET_MAX_LINK) {
1030 errno = EINVAL;
1031 return -1;
1032 }
1033
1034 savederrno = get_global_wrlock(knet_h);
1035 if (savederrno) {
1036 log_err(knet_h, KNET_SUB_LINK, "Unable to get write lock: %s",
1037 strerror(savederrno));
1038 errno = savederrno;
1039 return -1;
1040 }
1041
1042 host = knet_h->host_index[host_id];
1043 if (!host) {
1044 err = -1;
1045 savederrno = EINVAL;
1046 log_err(knet_h, KNET_SUB_LINK, "Unable to find host %u: %s",
1047 host_id, strerror(savederrno));
1048 goto exit_unlock;
1049 }
1050
1051 link = &host->link[link_id];
1052
1053 if (!link->configured) {
1054 err = -1;
1055 savederrno = EINVAL;
1056 log_err(knet_h, KNET_SUB_LINK, "host %u link %u is not configured: %s",
1057 host_id, link_id, strerror(savederrno));
1058 goto exit_unlock;
1059 }
1060
1061 old_priority = link->priority;
1062
1063 if (link->priority == priority) {
1064 err = 0;
1065 goto exit_unlock;
1066 }
1067
1068 link->priority = priority;
1069
1070 if (_host_dstcache_update_sync(knet_h, host)) {
1071 savederrno = errno;
1072 log_debug(knet_h, KNET_SUB_LINK,
1073 "Unable to update link priority (host: %u link: %u priority: %u): %s",
1074 host_id, link_id, link->priority, strerror(savederrno));
1075 link->priority = old_priority;
1076 err = -1;
1077 goto exit_unlock;
1078 }
1079
1080 log_debug(knet_h, KNET_SUB_LINK,
1081 "host: %u link: %u priority set to: %u",
1082 host_id, link_id, link->priority);
1083
1084 exit_unlock:
1085 pthread_rwlock_unlock(&knet_h->global_rwlock);
1086 errno = err ? savederrno : 0;
1087 return err;
1088 }
1089
1090 int knet_link_get_priority(knet_handle_t knet_h, knet_node_id_t host_id, uint8_t link_id,
1091 uint8_t *priority)
1092 {
1093 int savederrno = 0, err = 0;
1094 struct knet_host *host;
1095 struct knet_link *link;
1096
1097 if (!_is_valid_handle(knet_h)) {
1098 return -1;
1099 }
1100
1101 if (link_id >= KNET_MAX_LINK) {
1102 errno = EINVAL;
1103 return -1;
1104 }
1105
1106 if (!priority) {
1107 errno = EINVAL;
1108 return -1;
1109 }
1110
1111 savederrno = pthread_rwlock_rdlock(&knet_h->global_rwlock);
1112 if (savederrno) {
1113 log_err(knet_h, KNET_SUB_LINK, "Unable to get read lock: %s",
1114 strerror(savederrno));
1115 errno = savederrno;
1116 return -1;
1117 }
1118
1119 host = knet_h->host_index[host_id];
1120 if (!host) {
1121 err = -1;
1122 savederrno = EINVAL;
1123 log_err(knet_h, KNET_SUB_LINK, "Unable to find host %u: %s",
1124 host_id, strerror(savederrno));
1125 goto exit_unlock;
1126 }
1127
1128 link = &host->link[link_id];
1129
1130 if (!link->configured) {
1131 err = -1;
1132 savederrno = EINVAL;
1133 log_err(knet_h, KNET_SUB_LINK, "host %u link %u is not configured: %s",
1134 host_id, link_id, strerror(savederrno));
1135 goto exit_unlock;
1136 }
1137
1138 *priority = link->priority;
1139
1140 exit_unlock:
1141 pthread_rwlock_unlock(&knet_h->global_rwlock);
1142 errno = err ? savederrno : 0;
1143 return err;
1144 }
1145
1146 int knet_link_get_link_list(knet_handle_t knet_h, knet_node_id_t host_id,
1147 uint8_t *link_ids, size_t *link_ids_entries)
1148 {
1149 int savederrno = 0, err = 0, i, count = 0;
1150 struct knet_host *host;
1151 struct knet_link *link;
1152
1153 if (!_is_valid_handle(knet_h)) {
1154 return -1;
1155 }
1156
1157 if (!link_ids) {
1158 errno = EINVAL;
1159 return -1;
1160 }
1161
1162 if (!link_ids_entries) {
1163 errno = EINVAL;
1164 return -1;
1165 }
1166
1167 savederrno = pthread_rwlock_rdlock(&knet_h->global_rwlock);
1168 if (savederrno) {
1169 log_err(knet_h, KNET_SUB_LINK, "Unable to get read lock: %s",
1170 strerror(savederrno));
1171 errno = savederrno;
1172 return -1;
1173 }
1174
1175 host = knet_h->host_index[host_id];
1176 if (!host) {
1177 err = -1;
1178 savederrno = EINVAL;
1179 log_err(knet_h, KNET_SUB_LINK, "Unable to find host %u: %s",
1180 host_id, strerror(savederrno));
1181 goto exit_unlock;
1182 }
1183
1184 for (i = 0; i < KNET_MAX_LINK; i++) {
1185 link = &host->link[i];
1186 if (!link->configured) {
1187 continue;
1188 }
1189 link_ids[count] = i;
1190 count++;
1191 }
1192
1193 *link_ids_entries = count;
1194
1195 exit_unlock:
1196 pthread_rwlock_unlock(&knet_h->global_rwlock);
1197 errno = err ? savederrno : 0;
1198 return err;
1199 }
1200
1201 int knet_link_get_status(knet_handle_t knet_h, knet_node_id_t host_id, uint8_t link_id,
1202 struct knet_link_status *status, size_t struct_size)
1203 {
1204 int savederrno = 0, err = 0;
1205 struct knet_host *host;
1206 struct knet_link *link;
1207
1208 if (!_is_valid_handle(knet_h)) {
1209 return -1;
1210 }
1211
1212 if (link_id >= KNET_MAX_LINK) {
1213 errno = EINVAL;
1214 return -1;
1215 }
1216
1217 if (!status) {
1218 errno = EINVAL;
1219 return -1;
1220 }
1221
1222 savederrno = pthread_rwlock_rdlock(&knet_h->global_rwlock);
1223 if (savederrno) {
1224 log_err(knet_h, KNET_SUB_LINK, "Unable to get read lock: %s",
1225 strerror(savederrno));
1226 errno = savederrno;
1227 return -1;
1228 }
1229
1230 host = knet_h->host_index[host_id];
1231 if (!host) {
1232 err = -1;
1233 savederrno = EINVAL;
1234 log_err(knet_h, KNET_SUB_LINK, "Unable to find host %u: %s",
1235 host_id, strerror(savederrno));
1236 goto exit_unlock;
1237 }
1238
1239 link = &host->link[link_id];
1240
1241 if (!link->configured) {
1242 err = -1;
1243 savederrno = EINVAL;
1244 log_err(knet_h, KNET_SUB_LINK, "host %u link %u is not configured: %s",
1245 host_id, link_id, strerror(savederrno));
1246 goto exit_unlock;
1247 }
1248
1249 savederrno = pthread_mutex_lock(&link->link_stats_mutex);
1250 if (savederrno) {
1251 log_err(knet_h, KNET_SUB_LINK, "Unable to get stats mutex lock for host %u link %u: %s",
1252 host_id, link_id, strerror(savederrno));
1253 err = -1;
1254 goto exit_unlock;
1255 }
1256
1257 memmove(status, &link->status, struct_size);
1258
1259 pthread_mutex_unlock(&link->link_stats_mutex);
1260
1261 /* Calculate totals - no point in doing this on-the-fly */
1262 status->stats.rx_total_packets =
1263 status->stats.rx_data_packets +
1264 status->stats.rx_ping_packets +
1265 status->stats.rx_pong_packets +
1266 status->stats.rx_pmtu_packets;
1267 status->stats.tx_total_packets =
1268 status->stats.tx_data_packets +
1269 status->stats.tx_ping_packets +
1270 status->stats.tx_pong_packets +
1271 status->stats.tx_pmtu_packets;
1272 status->stats.rx_total_bytes =
1273 status->stats.rx_data_bytes +
1274 status->stats.rx_ping_bytes +
1275 status->stats.rx_pong_bytes +
1276 status->stats.rx_pmtu_bytes;
1277 status->stats.tx_total_bytes =
1278 status->stats.tx_data_bytes +
1279 status->stats.tx_ping_bytes +
1280 status->stats.tx_pong_bytes +
1281 status->stats.tx_pmtu_bytes;
1282 status->stats.tx_total_errors =
1283 status->stats.tx_data_errors +
1284 status->stats.tx_ping_errors +
1285 status->stats.tx_pong_errors +
1286 status->stats.tx_pmtu_errors;
1287 status->stats.tx_total_retries =
1288 status->stats.tx_data_retries +
1289 status->stats.tx_ping_retries +
1290 status->stats.tx_pong_retries +
1291 status->stats.tx_pmtu_retries;
1292
1293 /* Tell the caller our full size in case they have an old version */
1294 status->size = sizeof(struct knet_link_status);
1295
1296 exit_unlock:
1297 pthread_rwlock_unlock(&knet_h->global_rwlock);
1298 errno = err ? savederrno : 0;
1299 return err;
1300 }
1301
1302 int knet_link_insert_acl(knet_handle_t knet_h, knet_node_id_t host_id, uint8_t link_id,
1303 int index,
1304 struct sockaddr_storage *ss1,
1305 struct sockaddr_storage *ss2,
1306 check_type_t type, check_acceptreject_t acceptreject)
1307 {
1308 int savederrno = 0, err = 0;
1309 struct knet_host *host;
1310 struct knet_link *link;
1311
1312 if (!_is_valid_handle(knet_h)) {
1313 return -1;
1314 }
1315
1316 if (!ss1) {
1317 errno = EINVAL;
1318 return -1;
1319 }
1320
1321 if ((type != CHECK_TYPE_ADDRESS) &&
1322 (type != CHECK_TYPE_MASK) &&
1323 (type != CHECK_TYPE_RANGE)) {
1324 errno = EINVAL;
1325 return -1;
1326 }
1327
1328 if ((acceptreject != CHECK_ACCEPT) &&
1329 (acceptreject != CHECK_REJECT)) {
1330 errno = EINVAL;
1331 return -1;
1332 }
1333
1334 if ((type != CHECK_TYPE_ADDRESS) && (!ss2)) {
1335 errno = EINVAL;
1336 return -1;
1337 }
1338
1339 if ((type == CHECK_TYPE_RANGE) &&
1340 (ss1->ss_family != ss2->ss_family)) {
1341 errno = EINVAL;
1342 return -1;
1343 }
1344
1345 if (link_id >= KNET_MAX_LINK) {
1346 errno = EINVAL;
1347 return -1;
1348 }
1349
1350 savederrno = get_global_wrlock(knet_h);
1351 if (savederrno) {
1352 log_err(knet_h, KNET_SUB_LINK, "Unable to get write lock: %s",
1353 strerror(savederrno));
1354 errno = savederrno;
1355 return -1;
1356 }
1357
1358 host = knet_h->host_index[host_id];
1359 if (!host) {
1360 err = -1;
1361 savederrno = EINVAL;
1362 log_err(knet_h, KNET_SUB_LINK, "Unable to find host %u: %s",
1363 host_id, strerror(savederrno));
1364 goto exit_unlock;
1365 }
1366
1367 link = &host->link[link_id];
1368
1369 if (!link->configured) {
1370 err = -1;
1371 savederrno = EINVAL;
1372 log_err(knet_h, KNET_SUB_LINK, "host %u link %u is not configured: %s",
1373 host_id, link_id, strerror(savederrno));
1374 goto exit_unlock;
1375 }
1376
1377 if (link->dynamic != KNET_LINK_DYNIP) {
1378 err = -1;
1379 savederrno = EINVAL;
1380 log_err(knet_h, KNET_SUB_LINK, "host %u link %u is a point to point connection: %s",
1381 host_id, link_id, strerror(savederrno));
1382 goto exit_unlock;
1383 }
1384
1385 err = check_add(knet_h, link, index,
1386 ss1, ss2, type, acceptreject);
1387 savederrno = errno;
1388
1389 exit_unlock:
1390 pthread_rwlock_unlock(&knet_h->global_rwlock);
1391
1392 errno = savederrno;
1393 return err;
1394 }
1395
1396 int knet_link_add_acl(knet_handle_t knet_h, knet_node_id_t host_id, uint8_t link_id,
1397 struct sockaddr_storage *ss1,
1398 struct sockaddr_storage *ss2,
1399 check_type_t type, check_acceptreject_t acceptreject)
1400 {
1401 return knet_link_insert_acl(knet_h, host_id, link_id, -1, ss1, ss2, type, acceptreject);
1402 }
1403
1404
1405 int knet_link_rm_acl(knet_handle_t knet_h, knet_node_id_t host_id, uint8_t link_id,
1406 struct sockaddr_storage *ss1,
1407 struct sockaddr_storage *ss2,
1408 check_type_t type, check_acceptreject_t acceptreject)
1409 {
1410 int savederrno = 0, err = 0;
1411 struct knet_host *host;
1412 struct knet_link *link;
1413
1414 if (!_is_valid_handle(knet_h)) {
1415 return -1;
1416 }
1417
1418 if (!ss1) {
1419 errno = EINVAL;
1420 return -1;
1421 }
1422
1423 if ((type != CHECK_TYPE_ADDRESS) &&
1424 (type != CHECK_TYPE_MASK) &&
1425 (type != CHECK_TYPE_RANGE)) {
1426 errno = EINVAL;
1427 return -1;
1428 }
1429
1430 if ((acceptreject != CHECK_ACCEPT) &&
1431 (acceptreject != CHECK_REJECT)) {
1432 errno = EINVAL;
1433 return -1;
1434 }
1435
1436 if ((type != CHECK_TYPE_ADDRESS) && (!ss2)) {
1437 errno = EINVAL;
1438 return -1;
1439 }
1440
1441 if ((type == CHECK_TYPE_RANGE) &&
1442 (ss1->ss_family != ss2->ss_family)) {
1443 errno = EINVAL;
1444 return -1;
1445 }
1446
1447 if (link_id >= KNET_MAX_LINK) {
1448 errno = EINVAL;
1449 return -1;
1450 }
1451
1452 savederrno = get_global_wrlock(knet_h);
1453 if (savederrno) {
1454 log_err(knet_h, KNET_SUB_LINK, "Unable to get write lock: %s",
1455 strerror(savederrno));
1456 errno = savederrno;
1457 return -1;
1458 }
1459
1460 host = knet_h->host_index[host_id];
1461 if (!host) {
1462 err = -1;
1463 savederrno = EINVAL;
1464 log_err(knet_h, KNET_SUB_LINK, "Unable to find host %u: %s",
1465 host_id, strerror(savederrno));
1466 goto exit_unlock;
1467 }
1468
1469 link = &host->link[link_id];
1470
1471 if (!link->configured) {
1472 err = -1;
1473 savederrno = EINVAL;
1474 log_err(knet_h, KNET_SUB_LINK, "host %u link %u is not configured: %s",
1475 host_id, link_id, strerror(savederrno));
1476 goto exit_unlock;
1477 }
1478
1479 if (link->dynamic != KNET_LINK_DYNIP) {
1480 err = -1;
1481 savederrno = EINVAL;
1482 log_err(knet_h, KNET_SUB_LINK, "host %u link %u is a point to point connection: %s",
1483 host_id, link_id, strerror(savederrno));
1484 goto exit_unlock;
1485 }
1486
1487 err = check_rm(knet_h, link,
1488 ss1, ss2, type, acceptreject);
1489 savederrno = errno;
1490
1491 exit_unlock:
1492 pthread_rwlock_unlock(&knet_h->global_rwlock);
1493
1494 errno = savederrno;
1495 return err;
1496 }
1497
1498 int knet_link_clear_acl(knet_handle_t knet_h, knet_node_id_t host_id, uint8_t link_id)
1499 {
1500 int savederrno = 0, err = 0;
1501 struct knet_host *host;
1502 struct knet_link *link;
1503
1504 if (!_is_valid_handle(knet_h)) {
1505 return -1;
1506 }
1507
1508 if (link_id >= KNET_MAX_LINK) {
1509 errno = EINVAL;
1510 return -1;
1511 }
1512
1513 savederrno = get_global_wrlock(knet_h);
1514 if (savederrno) {
1515 log_err(knet_h, KNET_SUB_LINK, "Unable to get write lock: %s",
1516 strerror(savederrno));
1517 errno = savederrno;
1518 return -1;
1519 }
1520
1521 host = knet_h->host_index[host_id];
1522 if (!host) {
1523 err = -1;
1524 savederrno = EINVAL;
1525 log_err(knet_h, KNET_SUB_LINK, "Unable to find host %u: %s",
1526 host_id, strerror(savederrno));
1527 goto exit_unlock;
1528 }
1529
1530 link = &host->link[link_id];
1531
1532 if (!link->configured) {
1533 err = -1;
1534 savederrno = EINVAL;
1535 log_err(knet_h, KNET_SUB_LINK, "host %u link %u is not configured: %s",
1536 host_id, link_id, strerror(savederrno));
1537 goto exit_unlock;
1538 }
1539
1540 if (link->dynamic != KNET_LINK_DYNIP) {
1541 err = -1;
1542 savederrno = EINVAL;
1543 log_err(knet_h, KNET_SUB_LINK, "host %u link %u is a point to point connection: %s",
1544 host_id, link_id, strerror(savederrno));
1545 goto exit_unlock;
1546 }
1547
1548 check_rmall(knet_h, link);
1549
1550 exit_unlock:
1551 pthread_rwlock_unlock(&knet_h->global_rwlock);
1552
1553 errno = savederrno;
1554 return err;
1555 }
1556