From: Vladimir Melnikov Date: Tue, 26 Oct 2010 12:20:03 +0000 (+0200) Subject: Implement support for QoS / ToS fields. X-Git-Tag: liboping-1.5.0~3^2~18 X-Git-Url: https://git.octo.it/?p=liboping.git;a=commitdiff_plain;h=8d1c1159dc6f2a923f5c7f133c0fd07339456b90 Implement support for QoS / ToS fields. Hello Florian, I've made some functionality extension to debug QoS in the network - ability to set tos (present in most standard "pings") and to verify received tos field (didn't see any ping command with this feature). May be it will need to someone else. Best regards, Vladimir --- diff --git a/src/liboping.c b/src/liboping.c index 3c1c92a..2e7f288 100644 --- a/src/liboping.c +++ b/src/liboping.c @@ -117,6 +117,7 @@ struct pinghost double latency; uint32_t dropped; int recv_ttl; + unsigned recv_tos; char *data; void *context; @@ -129,6 +130,7 @@ struct pingobj double timeout; int ttl; int addrfamily; + unsigned tos; char *data; struct sockaddr *srcaddr; @@ -350,9 +352,10 @@ static pinghost_t *ping_receive_ipv4 (pingobj_t *obj, char *buffer, ident, seq); } - if (ptr != NULL) + if (ptr != NULL){ ptr->recv_ttl = ip_hdr->ip_ttl; - + ptr->recv_tos = ip_hdr->ip_tos; + } return (ptr); } @@ -450,6 +453,7 @@ static int ping_receive_one (pingobj_t *obj, const pinghost_t *ph, struct timeval diff; pinghost_t *host = NULL; int recv_ttl; + unsigned recv_tos; /* * Set up the receive buffer.. @@ -495,6 +499,7 @@ static int ping_receive_one (pingobj_t *obj, const pinghost_t *ph, /* Iterate over all auxiliary data in msghdr */ recv_ttl = -1; + recv_tos = 0xffff; for (cmsg = CMSG_FIRSTHDR (&msghdr); /* {{{ */ cmsg != NULL; cmsg = CMSG_NXTHDR (&msghdr, cmsg)) @@ -504,6 +509,12 @@ static int ping_receive_one (pingobj_t *obj, const pinghost_t *ph, if (cmsg->cmsg_level != IPPROTO_IP) continue; + if (cmsg->cmsg_type == IP_TOS) + { + memcpy (&recv_tos, CMSG_DATA (cmsg), + sizeof (recv_tos)); + dprintf ("TOSv4 = %u;\n", recv_tos); + } else if (cmsg->cmsg_type == IP_TTL) { memcpy (&recv_ttl, CMSG_DATA (cmsg), @@ -521,6 +532,12 @@ static int ping_receive_one (pingobj_t *obj, const pinghost_t *ph, if (cmsg->cmsg_level != IPPROTO_IPV6) continue; + if (cmsg->cmsg_type == IPV6_RECVTCLASS) + { + memcpy (&recv_tos, CMSG_DATA (cmsg), + sizeof (recv_tos)); + dprintf ("TOSv6 = %u;\n", recv_tos); + } else if (cmsg->cmsg_type == IPV6_HOPLIMIT) { memcpy (&recv_ttl, CMSG_DATA (cmsg), @@ -579,6 +596,8 @@ static int ping_receive_one (pingobj_t *obj, const pinghost_t *ph, if (recv_ttl >= 0) host->recv_ttl = recv_ttl; + if (recv_tos != 0xffff) + host->recv_tos = recv_tos; host->latency = ((double) diff.tv_usec) / 1000.0; host->latency += ((double) diff.tv_sec) * 1000.0; @@ -931,6 +950,29 @@ static int ping_set_ttl (pinghost_t *ph, int ttl) return (ret); } +/* + * Set the TOS of a socket protocol independently. + */ +static int ping_set_tos (pinghost_t *ph, unsigned tos) +{ + int ret = -2; + + if (ph->addrfamily == AF_INET) + { + dprintf ("Setting TP_TOS to %i\n", ttl); + ret = setsockopt (ph->fd, IPPROTO_IP, IP_TOS, + &tos, sizeof (tos)); + } + else if (ph->addrfamily == AF_INET6) + { + dprintf ("Setting IPV6_TCLASS to %i\n", ttl); + ret = setsockopt (ph->fd, IPPROTO_IPV6, IPV6_TCLASS, + &tos, sizeof (tos)); + } + + return (ret); +} + static int ping_get_ident (void) { int fd; @@ -1036,6 +1078,7 @@ pingobj_t *ping_construct (void) obj->ttl = PING_DEF_TTL; obj->addrfamily = PING_DEF_AF; obj->data = strdup (PING_DEF_DATA); + obj->tos = 0; return (obj); } @@ -1081,6 +1124,13 @@ int ping_setopt (pingobj_t *obj, int option, void *value) switch (option) { + case PING_OPT_TOS:{ + obj->tos=*(unsigned *)value; + pinghost_t *ph; + for (ph = obj->head; ph != NULL; ph = ph->next) + ping_set_tos (ph, obj->tos); + break; + } case PING_OPT_TIMEOUT: obj->timeout = *((double *) value); if (obj->timeout < 0.0) @@ -1484,6 +1534,7 @@ int ping_host_add (pingobj_t *obj, const char *host) } ping_set_ttl (ph, obj->ttl); + ping_set_tos (ph, obj->tos); return (0); } /* int ping_host_add */ @@ -1662,6 +1713,16 @@ int ping_iterator_get_info (pingobj_iter_t *iter, int info, *((int *) buffer) = iter->recv_ttl; ret = 0; break; + + case PING_INFO_TOS: + ret = ENOMEM; + if (*buffer_len>sizeof(unsigned)) *buffer_len=sizeof(unsigned); + if (!*buffer_len) *buffer_len=1; + if (orig_buffer_len < *buffer_len) + break; + memcpy(buffer,&iter->recv_tos,*buffer_len); + ret = 0; + break; } return (ret); diff --git a/src/oping.c b/src/oping.c index 0d7575e..b971cb7 100644 --- a/src/oping.c +++ b/src/oping.c @@ -103,6 +103,7 @@ static char *opt_device = NULL; static char *opt_filename = NULL; static int opt_count = -1; static int opt_send_ttl = 64; +static unsigned opt_send_tos = 0; static int host_num = 0; @@ -246,6 +247,7 @@ static void usage_exit (const char *name, int status) /* {{{ */ " -c count number of ICMP packets to send\n" " -i interval interval with which to send ICMP packets\n" " -t ttl time to live for each ICMP packet\n" + " -z tos Type-of-service/class-of-service for each ICMP packet\n" " -I srcaddr source address\n" " -D device outgoing interface name\n" " -f filename filename to read hosts from\n" @@ -263,7 +265,7 @@ static int read_options (int argc, char **argv) /* {{{ */ while (1) { - optchar = getopt (argc, argv, "46c:hi:I:t:f:D:"); + optchar = getopt (argc, argv, "46c:hi:I:t:z:f:D:"); if (optchar == -1) break; @@ -330,6 +332,18 @@ static int read_options (int argc, char **argv) /* {{{ */ break; } + case 'z': + { + int new_send_tos; + new_send_tos = atoi (optarg); + if ((new_send_tos > 0) && (new_send_tos < 256)) + opt_send_tos = new_send_tos; + else + fprintf (stderr, "Ignoring invalid TOS argument: %s\n", + optarg); + break; + } + case 'h': usage_exit (argv[0], 0); break; @@ -617,6 +631,7 @@ static void update_host_hook (pingobj_iter_t *iter, /* {{{ */ double latency; unsigned int sequence; int recv_ttl; + unsigned recv_tos; size_t buffer_len; size_t data_len; ping_context_t *context; @@ -636,6 +651,11 @@ static void update_host_hook (pingobj_iter_t *iter, /* {{{ */ ping_iterator_get_info (iter, PING_INFO_RECV_TTL, &recv_ttl, &buffer_len); + recv_tos = 0; + buffer_len = sizeof (recv_tos); + ping_iterator_get_info (iter, PING_INFO_TOS, + &recv_tos, &buffer_len); + data_len = 0; ping_iterator_get_info (iter, PING_INFO_DATA, NULL, &data_len); @@ -674,10 +694,10 @@ static void update_host_hook (pingobj_iter_t *iter, /* {{{ */ || (latency > (average + stddev))) color = OPING_YELLOW; - HOST_PRINTF ("%zu bytes from %s (%s): icmp_seq=%u ttl=%i " + HOST_PRINTF ("%zu bytes from %s (%s): icmp_seq=%u ttl=%i tos=%u " "time=", data_len, context->host, context->addr, - sequence, recv_ttl); + sequence, recv_ttl, recv_tos); wattron (main_win, COLOR_PAIR(color)); HOST_PRINTF ("%.2f", latency); wattroff (main_win, COLOR_PAIR(color)); @@ -686,11 +706,11 @@ static void update_host_hook (pingobj_iter_t *iter, /* {{{ */ else { #endif - HOST_PRINTF ("%zu bytes from %s (%s): icmp_seq=%u ttl=%i " + HOST_PRINTF ("%zu bytes from %s (%s): icmp_seq=%u ttl=%i tos=%u " "time=%.2f ms\n", data_len, context->host, context->addr, - sequence, recv_ttl, latency); + sequence, recv_ttl, recv_tos, latency); #if USE_NCURSES } #endif @@ -833,6 +853,12 @@ int main (int argc, char **argv) /* {{{ */ opt_send_ttl, ping_get_error (ping)); } + if (ping_setopt (ping, PING_OPT_TOS, &opt_send_tos) != 0) + { + fprintf (stderr, "Setting TOS to %i failed: %s\n", + opt_send_tos, ping_get_error (ping)); + } + { double temp_sec; double temp_nsec; diff --git a/src/oping.h b/src/oping.h index e2ccf97..8d858fb 100644 --- a/src/oping.h +++ b/src/oping.h @@ -52,6 +52,7 @@ typedef struct pingobj pingobj_t; #define PING_OPT_DATA 0x08 #define PING_OPT_SOURCE 0x10 #define PING_OPT_DEVICE 0x20 +#define PING_OPT_TOS 0x40 #define PING_DEF_TIMEOUT 1.0 #define PING_DEF_TTL 255 @@ -84,6 +85,7 @@ pingobj_iter_t *ping_iterator_next (pingobj_iter_t *iter); #define PING_INFO_USERNAME 8 #define PING_INFO_DROPPED 9 #define PING_INFO_RECV_TTL 10 +#define PING_INFO_TOS 11 int ping_iterator_get_info (pingobj_iter_t *iter, int info, void *buffer, size_t *buffer_len);