Add the "-delay" option to configure network delay in milliseconds

When using UML to test networking code, it would be helpful if the
switch daemon could provide configurable delay, in order to simulate
ordinary network delay.  This patch provides that feature by storing
scheduled packets in a linked list, and using the poll() timeout
parameter to pop items from the list at the appropriate time.

Presently, the size of the backlog is unbounded, but I think this is
acceptable for a testing/debugging feature.

PS: I could not find a public SCM with the most recent development
version of the utilities.
--- 
diff -ur tools-20070815/uml_switch/port.c tools-20070815.my/uml_switch/port.c
--- tools-20070815/uml_switch/port.c    2006-02-27 22:02:45.000000000 +0100
+++ tools-20070815.my/uml_switch/port.c 2010-11-25 18:32:20.597950521 +0100
@@ -8,6 +8,8 @@
 #include "hash.h"
 #include "port.h"
 
+typedef void (*sender_t)(int fd, void *packet, int len, void *data);
+
 struct packet {
   struct {
     unsigned char dest[ETH_ALEN];
@@ -24,15 +26,57 @@
   void *data;
   int data_len;
   unsigned char src[ETH_ALEN];
-  void (*sender)(int fd, void *packet, int len, void *data);
+  sender_t sender;
 };
 
 static struct port *head = NULL;
 
+struct queued_packet {
+  struct queued_packet *next;
+
+  struct timeval delivery_time;
+
+  sender_t sender;
+  void *data;
+
+  int fd;
+  int len;
+  struct sockaddr_un sock;
+
+  char packet[1];
+};
+
+static struct queued_packet *first_packet = NULL;
+static struct queued_packet *last_packet = NULL;
+
+extern int simulated_delay;
+
 #define IS_BROADCAST(addr) ((addr[0] & 1) == 1)
 
 static void free_port(struct port *port)
 {
+  struct queued_packet *qp, *prev = 0, *next;
+
+  /* Remove queued packets belonging to `port' */
+  qp = first_packet;
+
+  while (qp) {
+    if (qp->fd == port->control) {
+      next = qp->next;
+      if (prev)
+       prev->next = next;
+      else
+       first_packet = next;
+      free (qp);
+      qp = next;
+    } else {
+      prev = qp;
+      qp = qp->next;
+    }
+  }
+
+  last_packet = prev;
+
   if(port->prev) port->prev->next = port->next;
   else head = port->next;
   if(port->next) port->next->prev = port->prev;
@@ -83,6 +127,76 @@
   update_entry_time(p->header.src);
 }
 
+static void send_dst_packet(sender_t sender, int fd, void *packet, int len, 
void *data)
+{
+  struct queued_packet *qp;
+  if (!simulated_delay) {
+    sender(fd, data, len, data);
+  } else {
+    qp = malloc(sizeof(*qp) - sizeof(qp->packet) + len);
+
+    if(qp == NULL) {
+      perror("malloc");
+      return;
+    }
+
+    qp->next = 0;
+
+    gettimeofday(&qp->delivery_time, 0);
+
+    qp->delivery_time.tv_usec += simulated_delay * 1000;
+
+    if (qp->delivery_time.tv_usec > 1000000) {
+      qp->delivery_time.tv_sec += qp->delivery_time.tv_usec / 1000000;
+      qp->delivery_time.tv_usec %= 1000000;
+    }
+
+    qp->sender = sender;
+    qp->data = data;
+
+    qp->fd = fd;
+    qp->len = len;
+    memcpy(qp->packet, packet, len);
+
+    if (!first_packet)
+      first_packet = qp;
+    else
+      last_packet->next = qp;
+
+    last_packet = qp;
+  }
+}
+
+void process_queued_packets()
+{
+  struct queued_packet *qp;
+  struct timeval now;
+  int err;
+
+  if (!first_packet)
+    return;
+
+  gettimeofday(&now, 0);
+
+  while (first_packet)
+    {
+      if (first_packet->delivery_time.tv_sec > now.tv_sec
+         || (first_packet->delivery_time.tv_sec == now.tv_sec
+             && first_packet->delivery_time.tv_usec > now.tv_usec))
+       break;
+
+      qp = first_packet;
+
+      if (qp == last_packet)
+       last_packet = 0;
+      first_packet = qp->next;
+
+      (*qp->sender)(qp->fd, qp->packet, qp->len, qp->data);
+
+      free(qp);
+    }
+}
+
 static void send_dst(struct port *port, struct packet *packet, int len, 
                     int hub)
 {
@@ -104,10 +218,11 @@
       /* don't send it back the port it came in */
       if(p == port) continue;
 
-      (*p->sender)(p->control, packet, len, p->data);
+      send_dst_packet(p->sender, p->control, packet, len, p->data);  
     }
   }
-  else (*target->sender)(target->control, packet, len, target->data);
+  else
+    send_dst_packet(target->sender, target->control, packet, len, 
target->data);  
 }
 
 static void handle_data(int fd, int hub, struct packet *packet, int len, 
@@ -148,8 +263,7 @@
   handle_data(fd, hub, &packet, len, NULL, match_tap);
 }
 
-int setup_port(int fd, void (*sender)(int fd, void *packet, int len, 
-                                     void *data), void *data, int data_len)
+int setup_port(int fd, sender_t sender)
 {
   struct port *port;
 
@@ -188,6 +302,25 @@
   }
 }
 
+int next_queued_packet()
+{
+  struct timeval now;
+  int result = -1;
+
+  if (first_packet)
+    {
+      gettimeofday(&now, 0);
+
+      result = (first_packet->delivery_time.tv_sec - now.tv_sec) * 1000
+       + (first_packet->delivery_time.tv_usec - now.tv_usec) / 1000;
+
+      if (result < 0)
+       result = 0;
+    }
+
+  return result;
+}
+
 static int match_sock(int port_fd, int data_fd, void *port_data, 
                      int port_data_len, void *data)
 {
diff -ur tools-20070815/uml_switch/port.h tools-20070815.my/uml_switch/port.h
--- tools-20070815/uml_switch/port.h    2002-04-10 15:07:02.000000000 +0200
+++ tools-20070815.my/uml_switch/port.h 2010-11-25 18:15:51.557625929 +0100
@@ -16,5 +16,7 @@
                      int data_len);
 extern void handle_tap_data(int fd, int hub);
 extern void handle_sock_data(int fd, int hub);
+extern int next_queued_packet();
+extern void process_queued_packets();
 
 #endif
diff -ur tools-20070815/uml_switch/uml_switch.c 
tools-20070815.my/uml_switch/uml_switch.c
--- tools-20070815/uml_switch/uml_switch.c      2006-02-27 22:02:36.000000000 
+0100
+++ tools-20070815.my/uml_switch/uml_switch.c   2010-11-25 18:15:51.545961139 
+0100
@@ -26,6 +26,7 @@
 
 static int hub = 0;
 static int compat_v0 = 0;
+int simulated_delay = 0;
 
 enum request_type { REQ_NEW_CONTROL };
 
@@ -392,9 +393,10 @@
   tap_str = "[ -tap tap-device ]";
 #endif
 
-  fprintf(stderr, "Usage : %s [ -unix control-socket ] [ -hub ] %s\n"
+  fprintf(stderr, "Usage : %s [ -unix control-socket ] [ -hub ] "
+         "[ -delay ms ] %s\n"
          "or : %s -compat-v0 [ -unix control-socket data-socket ] "
-         "[ -hub ] %s\n", prog, tap_str, prog, tap_str);
+         "[ -hub ] [ -delay ms ] %s\n", prog, tap_str, prog, tap_str);
 
   exit(1);
 }
@@ -455,6 +457,13 @@
       argc--;
       argv++;
     }
+    else if(!strcmp(argv[0], "-delay")){
+      if(argc < 2) 
+       Usage();
+      simulated_delay = atoi(argv[1]);
+      argv += 2;
+      argc -= 2;
+    }
     else Usage();
   }
 
@@ -521,7 +530,7 @@
   while(1){
     char buf[128];
 
-    n = poll(fds, nfds, -1);
+    n = poll(fds, nfds, next_queued_packet());
     if(n < 0){
       if(errno == EINTR) continue;
       perror("poll");
@@ -562,6 +571,8 @@
        else close_descriptor(fds[i].fd);
       }
     }
+
+    process_queued_packets();
   }
  out:
   cleanup();

------------------------------------------------------------------------------
Increase Visibility of Your 3D Game App & Earn a Chance To Win $500!
Tap into the largest installed PC base & get more eyes on your game by
optimizing for Intel(R) Graphics Technology. Get started today with the
Intel(R) Software Partner Program. Five $500 cash prizes are up for grabs.
http://p.sf.net/sfu/intelisp-dev2dev
_______________________________________________
User-mode-linux-devel mailing list
User-mode-linux-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/user-mode-linux-devel

Reply via email to