]> xenbits.xensource.com Git - xenclient/ioemu.git/commitdiff
pv-on-hvm-ioemu/ioemu-fixed-port-unplug
authorJean Guyader <jean.guyader@eu.citrix.com>
Mon, 13 Oct 2008 13:03:32 +0000 (14:03 +0100)
committerVincent Hanquez <vincent@snarc.org>
Fri, 31 Oct 2008 12:10:56 +0000 (12:10 +0000)
hw/xen_platform.c

index 83e9a49df53c685e472e266c4dc8888b1670b005..099978e5d111ed5a430df12c54b4823586643dcb 100644 (file)
 #include "exec-all.h"
 #include "qemu-xen.h"
 
+#include <assert.h>
 #include <xenguest.h>
 
+static int throttling_disabled;
 static char log_buffer[4096];
 static int log_buffer_off;
 
@@ -43,6 +45,88 @@ typedef struct PCIXenPlatformState
   uint64_t   vga_stolen_ram;
 } PCIXenPlatformState;
 
+/* We throttle access to dom0 syslog, to avoid DOS attacks.  This is
+   modelled as a token bucket, with one token for every byte of log.
+   The bucket size is 128KB (->1024 lines of 128 bytes each) and
+   refills at 256B/s.  It starts full.  The guest is blocked if no
+   tokens are available when it tries to generate a log message. */
+#define BUCKET_MAX_SIZE (128*1024)
+#define BUCKET_FILL_RATE 256
+
+static void throttle(unsigned count)
+{
+    static unsigned available;
+    static struct timespec last_refil;
+    static int started;
+    static int warned;
+
+    struct timespec waiting_for, now;
+    double delay;
+    struct timespec ts;
+
+    if (throttling_disabled)
+        return;
+
+    if (!started) {
+        clock_gettime(CLOCK_MONOTONIC, &last_refil);
+        available = BUCKET_MAX_SIZE;
+        started = 1;
+    }
+
+    if (count > BUCKET_MAX_SIZE) {
+        fprintf(logfile, "tried to get %d tokens, but bucket size is %d\n",
+                BUCKET_MAX_SIZE, count);
+        exit(1);
+    }
+
+    if (available < count) {
+        /* The bucket is empty.  Refil it */
+
+        /* When will it be full enough to handle this request? */
+        delay = (double)(count - available) / BUCKET_FILL_RATE;
+        waiting_for = last_refil;
+        waiting_for.tv_sec += delay;
+        waiting_for.tv_nsec += (delay - (int)delay) * 1e9;
+        if (waiting_for.tv_nsec >= 1000000000) {
+            waiting_for.tv_nsec -= 1000000000;
+            waiting_for.tv_sec++;
+        }
+
+        /* How long do we have to wait? (might be negative) */
+        clock_gettime(CLOCK_MONOTONIC, &now);
+        ts.tv_sec = waiting_for.tv_sec - now.tv_sec;
+        ts.tv_nsec = waiting_for.tv_nsec - now.tv_nsec;
+        if (ts.tv_nsec < 0) {
+            ts.tv_sec--;
+            ts.tv_nsec += 1000000000;
+        }
+
+        /* Wait for it. */
+        if (ts.tv_sec > 0 ||
+            (ts.tv_sec == 0 && ts.tv_nsec > 0)) {
+            if (!warned) {
+                fprintf(logfile, "throttling guest access to syslog");
+                warned = 1;
+            }
+            while (nanosleep(&ts, &ts) < 0 && errno == EINTR)
+                ;
+        }
+
+        /* Refil */
+        clock_gettime(CLOCK_MONOTONIC, &now);
+        delay = (now.tv_sec - last_refil.tv_sec) +
+            (now.tv_nsec - last_refil.tv_nsec) * 1.0e-9;
+        available += BUCKET_FILL_RATE * delay;
+        if (available > BUCKET_MAX_SIZE)
+            available = BUCKET_MAX_SIZE;
+        last_refil = now;
+    }
+
+    assert(available >= count);
+
+    available -= count;
+}
+
 static uint32_t xen_platform_ioport_readb(void *opaque, uint32_t addr)
 {
     PCIXenPlatformState *s = opaque;
@@ -75,6 +159,7 @@ static void xen_platform_ioport_writeb(void *opaque, uint32_t addr, uint32_t val
             if (val == '\n' || log_buffer_off == sizeof(log_buffer) - 1) {
                 /* Flush buffer */
                 log_buffer[log_buffer_off] = 0;
+                throttle(log_buffer_off);
                 fprintf(logfile, "%s\n", log_buffer);
                 log_buffer_off = 0;
                 break;
@@ -270,6 +355,7 @@ static void platform_fixed_ioport_write1(void *opaque, uint32_t addr, uint32_t v
         if (val == '\n' || log_buffer_off == sizeof(log_buffer) - 1) {
             /* Flush buffer */
             log_buffer[log_buffer_off] = 0;
+            throttle(log_buffer_off);
             fprintf(logfile, "%s\n", log_buffer);
             log_buffer_off = 0;
             break;
@@ -294,6 +380,7 @@ void pci_xen_platform_init(PCIBus *bus)
 {
     PCIXenPlatformState *d;
     struct pci_config_header *pch;
+    struct stat stbuf;
 
     printf("Register xen platform.\n");
     d = (PCIXenPlatformState *)pci_register_device(
@@ -329,4 +416,8 @@ void pci_xen_platform_init(PCIBus *bus)
     register_ioport_write(0x10, 16, 1, platform_fixed_ioport_write1, NULL);
     register_ioport_read(0x10, 16, 2, platform_fixed_ioport_read2, NULL);
     register_ioport_read(0x10, 16, 1, platform_fixed_ioport_read1, NULL);
+
+    if (stat("/etc/disable-guest-log-throttle", &stbuf) == 0)
+        throttling_disabled = 1;
+
 }