Line data Source code
1 : #include "fd_neigh4_probe.h"
2 : #include "../../tango/tempo/fd_tempo.h" /* fd_tempo_tick_per_ns */
3 :
4 : #include <errno.h>
5 : #include <sys/socket.h> /* socket(2) */
6 : #include <netinet/in.h> /* IPPROTO_IP */
7 : #include <unistd.h> /* close(2) */
8 :
9 : void
10 : fd_neigh4_prober_init( fd_neigh4_prober_t * prober,
11 : float max_probes_per_second,
12 : ulong max_probe_burst,
13 0 : float probe_delay_seconds ) {
14 :
15 0 : int sock_fd = socket( AF_INET, SOCK_DGRAM, 0 );
16 0 : if( FD_UNLIKELY( sock_fd<0 ) ) {
17 0 : FD_LOG_ERR(( "socket(AF_INET,SOCK_DGRAM,0) failed (%i-%s)",
18 0 : errno, fd_io_strerror( errno ) ));
19 0 : }
20 :
21 : /* IP_TTL=1 is the lowest permitted value:
22 : https://github.com/torvalds/linux/blob/v6.13/net/ipv4/ip_sockglue.c#L300 */
23 0 : int ip_ttl = 1;
24 0 : if( FD_UNLIKELY( 0!=setsockopt( sock_fd, IPPROTO_IP, IP_TTL, &ip_ttl, sizeof(int) ) ) ) {
25 0 : (void)close( sock_fd );
26 0 : FD_LOG_ERR(( "setsockopt(%i,IPPROTO_IP,IP_TTL,1) failed (%i-%s)",
27 0 : sock_fd, errno, fd_io_strerror( errno ) ));
28 0 : }
29 :
30 : /* Only need to send probe packets to Ethernet neighbors */
31 0 : int dontroute = 1;
32 0 : if( FD_UNLIKELY( 0!=setsockopt( sock_fd, SOL_SOCKET, SO_DONTROUTE, &dontroute, sizeof(int) ) ) ) {
33 0 : (void)close( sock_fd );
34 0 : FD_LOG_ERR(( "setsockopt(%i,SOL_SOCKET,SO_DONTROUTE,1) failed (%i-%s)",
35 0 : sock_fd, errno, fd_io_strerror( errno ) ));
36 0 : }
37 :
38 0 : float tick_per_ns = (float)fd_tempo_tick_per_ns( NULL );
39 :
40 0 : *prober = (fd_neigh4_prober_t) {
41 0 : .sock_fd = sock_fd,
42 0 : .probe_delay = (long)( tick_per_ns * probe_delay_seconds * 1e9f ),
43 0 : .rate_limit = (fd_token_bucket_t) {
44 0 : .ts = fd_tickcount(),
45 0 : .rate = tick_per_ns * (max_probes_per_second / 1e9f),
46 0 : .burst = (float)max_probe_burst,
47 0 : .balance = 0.f
48 0 : },
49 0 : .local_rate_limited_cnt = 0UL,
50 0 : .global_rate_limited_cnt = 0UL
51 0 : };
52 0 : }
53 :
54 : void
55 0 : fd_neigh4_prober_fini( fd_neigh4_prober_t * prober ) {
56 0 : if( FD_UNLIKELY( 0!=close( prober->sock_fd ) ) ) {
57 0 : FD_LOG_ERR(( "close(%i) failed (%i-%s)",
58 0 : prober->sock_fd, errno, fd_io_strerror( errno ) ));
59 0 : }
60 0 : prober->sock_fd = -1;
61 0 : }
62 :
63 : int
64 : fd_neigh4_probe( fd_neigh4_prober_t * prober,
65 : fd_neigh4_entry_t * entry,
66 : uint ip4_addr,
67 0 : long now ) {
68 :
69 0 : struct sockaddr_in dst = {
70 0 : .sin_family = AF_INET,
71 0 : .sin_port = (ushort)0xFFFF,
72 0 : .sin_addr = { .s_addr = ip4_addr }
73 0 : };
74 0 : if( FD_UNLIKELY( sendto( prober->sock_fd, NULL, 0UL, MSG_DONTWAIT, fd_type_pun_const( &dst ), sizeof(struct sockaddr_in) )<0 ) ) {
75 0 : return errno;
76 0 : }
77 :
78 0 : entry->probe_suppress_until = now + prober->probe_delay;
79 :
80 0 : return 0;
81 0 : }
|