diff mbox

Send a RARP packet after migration.

Message ID 1255650835.4550.14849.camel@voxel
State New
Headers show

Commit Message

Nolan Oct. 15, 2009, 11:53 p.m. UTC
Currently, after a migration qemu sends a broadcast packet to update
switches' MAC->port mappings.

Unfortunately, it picks a random (constant) ethertype and crosses its
fingers that no one else is using it.

This patch causes it to send a RARP packet instead.  RARP was chosen for
2 reasons.  One, it is always harmless, and will continue to be so even
as new ethertypes are allocated.  Two, it is what VMware ESX sends, so
people who write filtering rules for switches already know about it.
    
I also changed the code to send SELF_ANNOUNCE_ROUNDS packets, instead of
SELF_ANNOUNCE_ROUNDS + 1, and added a simple backoff scheme.

Signed-off-by: Nolan Leake <nolan <at> sigbus.net>
diff mbox

Patch

diff --git a/savevm.c b/savevm.c
index 181c088..60bd199 100644
--- a/savevm.c
+++ b/savevm.c
@@ -95,25 +95,37 @@ 
 static BlockDriverState *bs_snapshots;
 
 #define SELF_ANNOUNCE_ROUNDS 5
-#define ETH_P_EXPERIMENTAL 0x01F1 /* just a number */
-//#define ETH_P_EXPERIMENTAL 0x0012 /* make it the size of the packet */
-#define EXPERIMENTAL_MAGIC 0xf1f23f4f
 
-static int announce_self_create(uint8_t *buf, 
+#ifndef ETH_P_RARP
+#define ETH_P_RARP 0x0835
+#endif
+#define ARP_HTYPE_ETH 0x0001
+#define ARP_PTYPE_IP 0x0800
+#define ARP_OP_REQUEST_REV 0x3
+
+static int announce_self_create(uint8_t *buf,
 				uint8_t *mac_addr)
 {
-    uint32_t magic = EXPERIMENTAL_MAGIC;
-    uint16_t proto = htons(ETH_P_EXPERIMENTAL);
-
-    /* FIXME: should we send a different packet (arp/rarp/ping)? */
-
-    memset(buf, 0, 64);
-    memset(buf, 0xff, 6);         /* h_dst */
-    memcpy(buf + 6, mac_addr, 6); /* h_src */
-    memcpy(buf + 12, &proto, 2);  /* h_proto */
-    memcpy(buf + 14, &magic, 4);  /* magic */
-
-    return 64; /* len */
+    /* Ethernet header. */
+    memset(buf, 0xff, 6);         /* destination MAC addr */
+    memcpy(buf + 6, mac_addr, 6); /* source MAC addr */
+    *(uint16_t *)(buf + 12) = htons(ETH_P_RARP); /* ethertype */
+
+    /* RARP header. */
+    *(uint16_t *)(buf + 14) = htons(ARP_HTYPE_ETH); /* hardware addr space */
+    *(uint16_t *)(buf + 16) = htons(ARP_PTYPE_IP); /* protocol addr space */
+    *(buf + 18) = 6; /* hardware addr length (ethernet) */
+    *(buf + 19) = 4; /* protocol addr length (IPv4) */
+    *(uint16_t *)(buf + 20) = htons(ARP_OP_REQUEST_REV); /* opcode */
+    memcpy(buf + 22, mac_addr, 6); /* source hw addr */
+    memset(buf + 28, 0x00, 4);     /* source protocol addr */
+    memcpy(buf + 32, mac_addr, 6); /* target hw addr */
+    memset(buf + 38, 0x00, 4);     /* target protocol addr */
+
+    /* Padding to get up to 60 bytes (ethernet min packet size, minus FCS). */
+    memset(buf + 42, 0x00, 18);
+
+    return 60; /* len (FCS will be added by hardware) */
 }
 
 static void qemu_announce_self_once(void *opaque)
@@ -121,7 +133,7 @@  static void qemu_announce_self_once(void *opaque)
     int i, len;
     VLANState *vlan;
     VLANClientState *vc;
-    uint8_t buf[256];
+    uint8_t buf[60];
     static int count = SELF_ANNOUNCE_ROUNDS;
     QEMUTimer *timer = *(QEMUTimer **)opaque;
 
@@ -134,8 +146,10 @@  static void qemu_announce_self_once(void *opaque)
             vc->receive(vc, buf, len);
         }
     }
-    if (count--) {
-	    qemu_mod_timer(timer, qemu_get_clock(rt_clock) + 100);
+    if (--count) {
+        /* delay 50ms, 150ms, 250ms, ... */
+        qemu_mod_timer(timer, qemu_get_clock(rt_clock) +
+                       50 + (SELF_ANNOUNCE_ROUNDS - count - 1) * 100);
     } else {
 	    qemu_del_timer(timer);
 	    qemu_free_timer(timer);