[monitoring-plugins] Use kernel reception time on ICMP packets to ...

Holger Weiss git at monitoring-plugins.org
Fri Nov 28 16:30:08 CET 2014


    Module: monitoring-plugins
    Branch: master
    Commit: 5265fabeb98dc2af702a56f1a4b45627c3d4d93f
    Author: Matthieu Kermagoret <mkermagoret at merethis.com>
 Committer: Holger Weiss <holger at zedat.fu-berlin.de>
      Date: Mon Feb  3 16:49:21 2014 +0100
       URL: https://www.monitoring-plugins.org/repositories/monitoring-plugins/commit/?id=5265fab

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.

---

 plugins-root/check_icmp.c | 55 +++++++++++++++++++++++++++++++++++++++++------
 1 file changed, 48 insertions(+), 7 deletions(-)

diff --git a/plugins-root/check_icmp.c b/plugins-root/check_icmp.c
index 8b563e4..d2f637f 100644
--- a/plugins-root/check_icmp.c
+++ b/plugins-root/check_icmp.c
@@ -184,7 +184,7 @@ static u_int get_timevar(const char *);
 static u_int get_timevaldiff(struct timeval *, struct timeval *);
 static in_addr_t get_ip_address(const char *);
 static int wait_for_reply(int, u_int);
-static int recvfrom_wto(int, void *, unsigned int, struct sockaddr *, u_int *);
+static int recvfrom_wto(int, void *, unsigned int, struct sockaddr *, u_int *, struct timeval*);
 static int send_icmp_ping(int, struct rta_host *);
 static int get_threshold(char *str, threshold *th);
 static void run_checks(void);
@@ -402,6 +402,12 @@ main(int argc, char **argv)
 	/* now drop privileges (no effect if not setsuid or geteuid() == 0) */
 	setuid(getuid());
 
+#ifdef SO_TIMESTAMP
+	int on = 1;
+	if(setsockopt(icmp_sock, SOL_SOCKET, SO_TIMESTAMP, &on, sizeof(on)))
+	  if(debug) printf("Warning: no SO_TIMESTAMP support\n");
+#endif // SO_TIMESTAMP
+
 	/* POSIXLY_CORRECT might break things, so unset it (the portable way) */
 	environ = NULL;
 
@@ -727,7 +733,7 @@ wait_for_reply(int sock, u_int t)
 
 		/* reap responses until we hit a timeout */
 		n = recvfrom_wto(sock, buf, sizeof(buf),
-						 (struct sockaddr *)&resp_addr, &t);
+						 (struct sockaddr *)&resp_addr, &t, &now);
 		if(!n) {
 			if(debug > 1) {
 				printf("recvfrom_wto() timed out during a %u usecs wait\n",
@@ -781,7 +787,6 @@ wait_for_reply(int sock, u_int t)
 			       sizeof(data), ntohs(icp.icmp_id), ntohs(icp.icmp_seq), icp.icmp_cksum);
 
 		host = table[ntohs(icp.icmp_seq)/packets];
-		gettimeofday(&now, &tz);
 		tdiff = get_timevaldiff(&data.stime, &now);
 
 		host->time_waited += tdiff;
@@ -858,8 +863,17 @@ send_icmp_ping(int sock, struct rta_host *host)
 		printf("Sending ICMP echo-request of len %u, id %u, seq %u, cksum 0x%X to host %s\n",
 		       sizeof(data), ntohs(packet.icp->icmp_id), ntohs(packet.icp->icmp_seq), packet.icp->icmp_cksum, host->name);
 
-	len = sendto(sock, packet.buf, icmp_pkt_size, 0, (struct sockaddr *)addr,
-				 sizeof(struct sockaddr));
+	struct msghdr hdr;
+	memset(&hdr, 0, sizeof(hdr));
+	hdr.msg_name = addr;
+	hdr.msg_namelen = sizeof(struct sockaddr);
+	struct iovec iov;
+	memset(&iov, 0, sizeof(iov));
+	iov.iov_base = packet.buf;
+	iov.iov_len = icmp_pkt_size;
+	hdr.msg_iov = &iov;
+	hdr.msg_iovlen = 1;
+	len = sendmsg(sock, &hdr, MSG_CONFIRM);
 
 	if(len < 0 || (unsigned int)len != icmp_pkt_size) {
 		if(debug) printf("Failed to send ping to %s\n",
@@ -875,7 +889,7 @@ send_icmp_ping(int sock, struct rta_host *host)
 
 static int
 recvfrom_wto(int sock, void *buf, unsigned int len, struct sockaddr *saddr,
-			 u_int *timo)
+			 u_int *timo, struct timeval* tv)
 {
 	u_int slen;
 	int n;
@@ -904,7 +918,34 @@ recvfrom_wto(int sock, void *buf, unsigned int len, struct sockaddr *saddr,
 
 	slen = sizeof(struct sockaddr);
 
-	return recvfrom(sock, buf, len, 0, saddr, &slen);
+	struct msghdr hdr;
+	memset(&hdr, 0, sizeof(hdr));
+	hdr.msg_name = saddr;
+	hdr.msg_namelen = slen;
+	struct iovec iov;
+	memset(&iov, 0, sizeof(iov));
+	iov.iov_base = buf;
+	iov.iov_len = len;
+	hdr.msg_iov = &iov;
+	hdr.msg_iovlen = 1;
+	char ans_data[4096];
+	hdr.msg_control = ans_data;
+	hdr.msg_controllen = sizeof(ans_data);
+	int ret = recvmsg(sock, &hdr, 0);
+#ifdef SO_TIMESTAMP
+	struct cmsghdr* chdr;
+	for(chdr = CMSG_FIRSTHDR(&hdr); chdr; chdr = CMSG_NXTHDR(&hdr, chdr)) {
+		if(chdr->cmsg_level == SOL_SOCKET
+		   && chdr->cmsg_type == SO_TIMESTAMP
+		   && chdr->cmsg_len >= CMSG_LEN(sizeof(struct timeval))) {
+			memcpy(tv, CMSG_DATA(chdr), sizeof(*tv));
+			break ;
+		}
+	}
+	if (!chdr)
+#endif // SO_TIMESTAMP
+		gettimeofday(tv, &tz);
+	return (ret);
 }
 
 static void



More information about the Commits mailing list