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 3c1c92a..2e7f288 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 0d7575e..b971cb7 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 e2ccf97..8d858fb 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);