Code

Implement support for QoS / ToS fields.
authorVladimir Melnikov <wlad.w.m@gmail.com>
Tue, 26 Oct 2010 12:20:03 +0000 (14:20 +0200)
committerFlorian Forster <octo@leeloo.lan.home.verplant.org>
Tue, 26 Oct 2010 12:20:03 +0000 (14:20 +0200)
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

src/liboping.c
src/oping.c
src/oping.h

index 3c1c92a4a5a1ab7a86dac708f18eb83a2fe36267..2e7f2889ac13077ed4666211a352b15253eff155 100644 (file)
@@ -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);
index 0d7575e1bafb827ebfe8f49e7f7b1d5265be6bcb..b971cb71e1001bcdd85dba2e1544b3f26e9f8dc4 100644 (file)
@@ -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;
index e2ccf97ef3190632ca72c3472657b904b72fae13..8d858fbc9a5490200bfa84bf758e91ab95783074 100644 (file)
@@ -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);