Here goes v0.2 for my patch :-)
Changes
- now the option is a separate command line switch:
  -net capture,vlan=2,file=test.pcap
- it is also available from the monitor
- added some more constants / defines to avoid repeating portions of the code




      __________________________________________________________
Sent from Yahoo! Mail - a smarter inbox http://uk.mail.yahoo.com
Index: vl.c
===================================================================
RCS file: /sources/qemu/qemu/vl.c,v
retrieving revision 1.377
diff -u -r1.377 vl.c
--- vl.c	6 Dec 2007 22:11:20 -0000	1.377
+++ vl.c	10 Dec 2007 10:28:35 -0000
@@ -237,6 +237,17 @@
 static CPUState *next_cpu;
 static int event_pending;
 
+/* File header which needs to be written at the start of each PCAP file*/
+static const PCAPHeader pcap_file_header = {
+    0xa1b2c3d4,
+    2,
+    4,
+    0,
+    0,
+    MAX_CAPTURED_PACKET_SIZE,
+    1	/* Ethernet */
+};
+
 #define TFR(expr) do { if ((expr) != -1) break; } while (errno == EINTR)
 
 /***********************************************************/
@@ -3588,6 +3599,8 @@
         return NULL;
     vlan->id = id;
     vlan->next = NULL;
+    vlan->pcap_fh = -1;
+    vlan->last_packet_time = 0;
     pvlan = &first_vlan;
     while (*pvlan != NULL)
         pvlan = &(*pvlan)->next;
@@ -3635,6 +3648,22 @@
 {
     VLANState *vlan = vc1->vlan;
     VLANClientState *vc;
+    
+    if (vlan->pcap_fh >= 0) {
+        vlan->packet_header.timestamp_sec = time(NULL);
+        if (vlan->packet_header.timestamp_sec == vlan->last_packet_time) {
+            if (vlan->packet_header.timestamp_usec < 1000000)
+            	++vlan->packet_header.timestamp_usec;
+        } else {
+        	vlan->packet_header.timestamp_usec = 0;
+        	vlan->last_packet_time = vlan->packet_header.timestamp_sec;
+        }
+        
+        vlan->packet_header.orig_len = size;
+        vlan->packet_header.saved_len = (size > MAX_CAPTURED_PACKET_SIZE) ? MAX_CAPTURED_PACKET_SIZE : size;
+        write(vlan->pcap_fh, &vlan->packet_header, sizeof(PCAPPacketHeader));
+        write(vlan->pcap_fh, buf, vlan->packet_header.saved_len);
+    }    
 
 #if 0
     printf("vlan %d send:\n", vlan->id);
@@ -4641,7 +4670,8 @@
     char device[64];
     char buf[1024];
     int vlan_id, ret;
-    VLANState *vlan;
+    VLANState *vlan;    
+    const char *capture_file_name;
 
     p = str;
     q = device;
@@ -4761,6 +4791,27 @@
         }
         vlan->nb_host_devs++;
     } else
+    if (!strcmp(device, "capture")) {
+        if (vlan->pcap_fh >= 0) {
+       	    fprintf(stderr, "vlan %d has already a capture file defined! "
+       	        "Can't have multiple capture files for the same vlan\n", vlan->id);
+       	    return -1;
+        }
+        
+        capture_file_name = DEFAULT_CAPTURE_FILENAME;
+        if (get_param_value(buf, sizeof(buf), "file", p))
+            capture_file_name = buf;
+            
+        vlan->pcap_fh = open(capture_file_name, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0644);
+    	if (vlan->pcap_fh < 0) {
+    		fprintf(stderr, "Failed to open capture file \"%s\": %d\n", capture_file_name, errno);
+    		return -1;
+    	}
+    	
+    	write(vlan->pcap_fh, &pcap_file_header, sizeof(pcap_file_header));
+    	
+    	ret = 0;
+    } else
     {
         fprintf(stderr, "Unknown network device: %s\n", device);
         return -1;
@@ -4784,6 +4835,59 @@
     }
 }
 
+void do_net_capture (const char *path,
+                            int has_vlan, int vlan_id)
+{
+    VLANState *vlan;
+    
+    vlan_id = (has_vlan) ? vlan_id : 0;
+    vlan = qemu_find_vlan(vlan_id);
+    if (!vlan) {
+        term_printf("Failed to find vlan %d\n", vlan_id);
+        return;
+    }
+    
+    if (vlan->pcap_fh >= 0) {
+   	    term_printf("Vlan %d is already capturing!\n", vlan_id);
+   	    return;
+    }
+    
+    vlan->pcap_fh = open(path, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0644);
+	if (vlan->pcap_fh < 0) {
+		term_printf("Failed to open capture file \"%s\": %d\n", path, errno);
+		return;
+	}
+	
+	vlan->last_packet_time = 0;
+	write(vlan->pcap_fh, &pcap_file_header, sizeof(pcap_file_header));	    
+}                            
+
+void do_stop_net_capture(int has_vlan, int vlan_id)
+{
+    VLANState *vlan;
+    
+    if (has_vlan) {
+        vlan = qemu_find_vlan(vlan_id);
+        if (!vlan) {
+            term_printf("Failed to find vlan %d\n", vlan_id);
+            return;
+        }    
+        
+        if (vlan->pcap_fh < 0) {
+            term_printf("Vlan %d is not capturing!\n", vlan_id);
+            return;
+        }
+        
+        close(vlan->pcap_fh);
+        vlan->pcap_fh = -1;
+        vlan->last_packet_time = 0;
+    } else {
+        for(vlan = first_vlan; vlan != NULL; vlan = vlan->next)
+            if (vlan->pcap_fh >= 0)
+                close(vlan->pcap_fh);                
+    }
+}
+
 #define HD_ALIAS "file=\"%s\",index=%d,media=disk"
 #ifdef TARGET_PPC
 #define CDROM_ALIAS "index=1,media=cdrom"
@@ -7511,6 +7615,10 @@
            "                connect the vlan 'n' to another VLAN using a socket connection\n"
            "-net socket[,vlan=n][,fd=h][,mcast=maddr:port]\n"
            "                connect the vlan 'n' to multicast maddr and port\n"
+           "-net capture[,vlan=n][,file=filename]\n"
+           "                captures the traffic flowing through VLAN 'n' to the file\n"
+           "                'filename' in tcpdump format. In case filename is not specified,\n"
+           "                the capture will be saved to " DEFAULT_CAPTURE_FILENAME "\n"
            "-net none       use it alone to have zero network devices; if no -net option\n"
            "                is provided, the default is '-net nic -net user'\n"
            "\n"
@@ -8939,5 +9047,11 @@
     }
     }
 #endif
+
+    /* close capture files associated with any vlan */
+    for(vlan = first_vlan; vlan != NULL; vlan = vlan->next)
+        if (vlan->pcap_fh >= 0)
+            close(vlan->pcap_fh);
+            
     return 0;
 }
Index: net.h
===================================================================
RCS file: /sources/qemu/qemu/net.h,v
retrieving revision 1.1
diff -u -r1.1 net.h
--- net.h	17 Nov 2007 17:14:38 -0000	1.1
+++ net.h	10 Dec 2007 10:28:35 -0000
@@ -1,6 +1,28 @@
 #ifndef QEMU_NET_H
 #define QEMU_NET_H
 
+/* PCAP support */
+/* source: http://wiki.wireshark.org/Development/LibpcapFileFormat */
+typedef struct {
+    uint32_t magic_number;
+    uint16_t version_major;
+    uint16_t version_minor;
+    int32_t thiszone;
+    uint32_t sigfigs;
+    uint32_t snaplen;
+    uint32_t network;
+} PCAPHeader;
+
+#define MAX_CAPTURED_PACKET_SIZE 0xFFFF
+#define DEFAULT_CAPTURE_FILENAME "qemu.pcap"
+
+typedef struct {
+	uint32_t timestamp_sec;
+	uint32_t timestamp_usec;
+	uint32_t saved_len;
+	uint32_t orig_len;
+} PCAPPacketHeader;
+
 /* VLANs support */
 
 typedef struct VLANClientState VLANClientState;
@@ -21,6 +43,10 @@
     VLANClientState *first_client;
     struct VLANState *next;
     unsigned int nb_guest_devs, nb_host_devs;
+    /* Filehandle for the capture file */
+    int pcap_fh;    
+    time_t last_packet_time;
+    PCAPPacketHeader packet_header;
 };
 
 VLANState *qemu_find_vlan(int id);
@@ -34,6 +60,11 @@
 
 void do_info_network(void);
 
+void do_net_capture (const char *path,
+                     int has_vlan, int vlan_id);
+
+void do_stop_net_capture(int has_vlan, int vlan_id);                            
+
 /* NIC info */
 
 #define MAX_NICS 8
Index: monitor.c
===================================================================
RCS file: /sources/qemu/qemu/monitor.c,v
retrieving revision 1.91
diff -u -r1.91 monitor.c
--- monitor.c	3 Dec 2007 17:05:38 -0000	1.91
+++ monitor.c	10 Dec 2007 10:28:42 -0000
@@ -1326,6 +1326,10 @@
        "capture index", "stop capture" },
     { "memsave", "lis", do_memory_save,
       "addr size file", "save to disk virtual memory dump starting at 'addr' of size 'size'", },
+    { "netcapture", "si?", do_net_capture,
+      "path [vlan]", "saves the traffic flowing through the given vlan to the file" },
+    { "stopnetcapture", "i?", do_stop_net_capture,
+      "[vlan]", "stops the capture of the specified vlan. if no vlan specified, stops all the capture" },      
     { NULL, NULL, },
 };
 

Reply via email to