diff options
author | Matthieu Kermagoret <mkermagoret@merethis.com> | 2014-02-03 16:49:21 +0100 |
---|---|---|
committer | Holger Weiss <holger@zedat.fu-berlin.de> | 2014-11-28 16:23:27 +0100 |
commit | 5265fabeb98dc2af702a56f1a4b45627c3d4d93f (patch) | |
tree | 3b110e12f18d46e015a4b27fc09c3e117ce854b9 | |
parent | 8b272a7f7baa7d743841da713a27284b0479d0e1 (diff) | |
download | monitoring-plugins-5265fabeb98dc2af702a56f1a4b45627c3d4d93f.tar.gz |
Use kernel reception time on ICMP packets to compute rtt.
This commit uses the SO_TIMESTAMP feature of setsockopt to fetch
kernel reception time of ICMP packets. This avoids invalid
computations of rtt on machines with heavy load and/or heavy
network traffic.
-rw-r--r-- | plugins-root/check_icmp.c | 55 |
1 files changed, 48 insertions, 7 deletions
diff --git a/plugins-root/check_icmp.c b/plugins-root/check_icmp.c index 8b563e40..d2f637fd 100644 --- a/plugins-root/check_icmp.c +++ b/plugins-root/check_icmp.c | |||
@@ -184,7 +184,7 @@ static u_int get_timevar(const char *); | |||
184 | static u_int get_timevaldiff(struct timeval *, struct timeval *); | 184 | static u_int get_timevaldiff(struct timeval *, struct timeval *); |
185 | static in_addr_t get_ip_address(const char *); | 185 | static in_addr_t get_ip_address(const char *); |
186 | static int wait_for_reply(int, u_int); | 186 | static int wait_for_reply(int, u_int); |
187 | static int recvfrom_wto(int, void *, unsigned int, struct sockaddr *, u_int *); | 187 | static int recvfrom_wto(int, void *, unsigned int, struct sockaddr *, u_int *, struct timeval*); |
188 | static int send_icmp_ping(int, struct rta_host *); | 188 | static int send_icmp_ping(int, struct rta_host *); |
189 | static int get_threshold(char *str, threshold *th); | 189 | static int get_threshold(char *str, threshold *th); |
190 | static void run_checks(void); | 190 | static void run_checks(void); |
@@ -402,6 +402,12 @@ main(int argc, char **argv) | |||
402 | /* now drop privileges (no effect if not setsuid or geteuid() == 0) */ | 402 | /* now drop privileges (no effect if not setsuid or geteuid() == 0) */ |
403 | setuid(getuid()); | 403 | setuid(getuid()); |
404 | 404 | ||
405 | #ifdef SO_TIMESTAMP | ||
406 | int on = 1; | ||
407 | if(setsockopt(icmp_sock, SOL_SOCKET, SO_TIMESTAMP, &on, sizeof(on))) | ||
408 | if(debug) printf("Warning: no SO_TIMESTAMP support\n"); | ||
409 | #endif // SO_TIMESTAMP | ||
410 | |||
405 | /* POSIXLY_CORRECT might break things, so unset it (the portable way) */ | 411 | /* POSIXLY_CORRECT might break things, so unset it (the portable way) */ |
406 | environ = NULL; | 412 | environ = NULL; |
407 | 413 | ||
@@ -727,7 +733,7 @@ wait_for_reply(int sock, u_int t) | |||
727 | 733 | ||
728 | /* reap responses until we hit a timeout */ | 734 | /* reap responses until we hit a timeout */ |
729 | n = recvfrom_wto(sock, buf, sizeof(buf), | 735 | n = recvfrom_wto(sock, buf, sizeof(buf), |
730 | (struct sockaddr *)&resp_addr, &t); | 736 | (struct sockaddr *)&resp_addr, &t, &now); |
731 | if(!n) { | 737 | if(!n) { |
732 | if(debug > 1) { | 738 | if(debug > 1) { |
733 | printf("recvfrom_wto() timed out during a %u usecs wait\n", | 739 | printf("recvfrom_wto() timed out during a %u usecs wait\n", |
@@ -781,7 +787,6 @@ wait_for_reply(int sock, u_int t) | |||
781 | sizeof(data), ntohs(icp.icmp_id), ntohs(icp.icmp_seq), icp.icmp_cksum); | 787 | sizeof(data), ntohs(icp.icmp_id), ntohs(icp.icmp_seq), icp.icmp_cksum); |
782 | 788 | ||
783 | host = table[ntohs(icp.icmp_seq)/packets]; | 789 | host = table[ntohs(icp.icmp_seq)/packets]; |
784 | gettimeofday(&now, &tz); | ||
785 | tdiff = get_timevaldiff(&data.stime, &now); | 790 | tdiff = get_timevaldiff(&data.stime, &now); |
786 | 791 | ||
787 | host->time_waited += tdiff; | 792 | host->time_waited += tdiff; |
@@ -858,8 +863,17 @@ send_icmp_ping(int sock, struct rta_host *host) | |||
858 | printf("Sending ICMP echo-request of len %u, id %u, seq %u, cksum 0x%X to host %s\n", | 863 | printf("Sending ICMP echo-request of len %u, id %u, seq %u, cksum 0x%X to host %s\n", |
859 | sizeof(data), ntohs(packet.icp->icmp_id), ntohs(packet.icp->icmp_seq), packet.icp->icmp_cksum, host->name); | 864 | sizeof(data), ntohs(packet.icp->icmp_id), ntohs(packet.icp->icmp_seq), packet.icp->icmp_cksum, host->name); |
860 | 865 | ||
861 | len = sendto(sock, packet.buf, icmp_pkt_size, 0, (struct sockaddr *)addr, | 866 | struct msghdr hdr; |
862 | sizeof(struct sockaddr)); | 867 | memset(&hdr, 0, sizeof(hdr)); |
868 | hdr.msg_name = addr; | ||
869 | hdr.msg_namelen = sizeof(struct sockaddr); | ||
870 | struct iovec iov; | ||
871 | memset(&iov, 0, sizeof(iov)); | ||
872 | iov.iov_base = packet.buf; | ||
873 | iov.iov_len = icmp_pkt_size; | ||
874 | hdr.msg_iov = &iov; | ||
875 | hdr.msg_iovlen = 1; | ||
876 | len = sendmsg(sock, &hdr, MSG_CONFIRM); | ||
863 | 877 | ||
864 | if(len < 0 || (unsigned int)len != icmp_pkt_size) { | 878 | if(len < 0 || (unsigned int)len != icmp_pkt_size) { |
865 | if(debug) printf("Failed to send ping to %s\n", | 879 | if(debug) printf("Failed to send ping to %s\n", |
@@ -875,7 +889,7 @@ send_icmp_ping(int sock, struct rta_host *host) | |||
875 | 889 | ||
876 | static int | 890 | static int |
877 | recvfrom_wto(int sock, void *buf, unsigned int len, struct sockaddr *saddr, | 891 | recvfrom_wto(int sock, void *buf, unsigned int len, struct sockaddr *saddr, |
878 | u_int *timo) | 892 | u_int *timo, struct timeval* tv) |
879 | { | 893 | { |
880 | u_int slen; | 894 | u_int slen; |
881 | int n; | 895 | int n; |
@@ -904,7 +918,34 @@ recvfrom_wto(int sock, void *buf, unsigned int len, struct sockaddr *saddr, | |||
904 | 918 | ||
905 | slen = sizeof(struct sockaddr); | 919 | slen = sizeof(struct sockaddr); |
906 | 920 | ||
907 | return recvfrom(sock, buf, len, 0, saddr, &slen); | 921 | struct msghdr hdr; |
922 | memset(&hdr, 0, sizeof(hdr)); | ||
923 | hdr.msg_name = saddr; | ||
924 | hdr.msg_namelen = slen; | ||
925 | struct iovec iov; | ||
926 | memset(&iov, 0, sizeof(iov)); | ||
927 | iov.iov_base = buf; | ||
928 | iov.iov_len = len; | ||
929 | hdr.msg_iov = &iov; | ||
930 | hdr.msg_iovlen = 1; | ||
931 | char ans_data[4096]; | ||
932 | hdr.msg_control = ans_data; | ||
933 | hdr.msg_controllen = sizeof(ans_data); | ||
934 | int ret = recvmsg(sock, &hdr, 0); | ||
935 | #ifdef SO_TIMESTAMP | ||
936 | struct cmsghdr* chdr; | ||
937 | for(chdr = CMSG_FIRSTHDR(&hdr); chdr; chdr = CMSG_NXTHDR(&hdr, chdr)) { | ||
938 | if(chdr->cmsg_level == SOL_SOCKET | ||
939 | && chdr->cmsg_type == SO_TIMESTAMP | ||
940 | && chdr->cmsg_len >= CMSG_LEN(sizeof(struct timeval))) { | ||
941 | memcpy(tv, CMSG_DATA(chdr), sizeof(*tv)); | ||
942 | break ; | ||
943 | } | ||
944 | } | ||
945 | if (!chdr) | ||
946 | #endif // SO_TIMESTAMP | ||
947 | gettimeofday(tv, &tz); | ||
948 | return (ret); | ||
908 | } | 949 | } |
909 | 950 | ||
910 | static void | 951 | static void |