[Qemu-devel] [PATCH 1/3] rtl8139: use TARGET_FMT_plx in debug messages

2011-04-20 Thread Benjamin Poirier
Prevents a compilation failure when DEBUG_RTL8139 is defined:

CClibhw32/rtl8139.o
cc1: warnings being treated as errors
hw/rtl8139.c: In function ‘rtl8139_cplus_transmit_one’:
hw/rtl8139.c:1960: error: format ‘%8lx’ expects type ‘long unsigned int’, but 
argument 5 has type ‘target_phys_addr_t’
make[1]: *** [rtl8139.o] Error 1

Signed-off-by: Benjamin Poirier benjamin.poir...@gmail.com
Cc: Igor V. Kovalenko igor.v.kovale...@gmail.com
---
 hw/rtl8139.c |   15 +--
 1 files changed, 9 insertions(+), 6 deletions(-)

diff --git a/hw/rtl8139.c b/hw/rtl8139.c
index d545933..9a759e7 100644
--- a/hw/rtl8139.c
+++ b/hw/rtl8139.c
@@ -978,8 +978,9 @@ static ssize_t rtl8139_do_receive(VLANClientState *nc, 
const uint8_t *buf, size_
 cplus_rx_ring_desc = rtl8139_addr64(s-RxRingAddrLO, s-RxRingAddrHI);
 cplus_rx_ring_desc += 16 * descriptor;
 
-DEBUG_PRINT((RTL8139: +++ C+ mode reading RX descriptor %d from host 
memory at %08x %08x = %016 PRIx64 \n,
-   descriptor, s-RxRingAddrHI, s-RxRingAddrLO, 
(uint64_t)cplus_rx_ring_desc));
+DEBUG_PRINT((RTL8139: +++ C+ mode reading RX descriptor %d from 
+host memory at %08x %08x =  TARGET_FMT_plx \n, descriptor,
+s-RxRingAddrHI, s-RxRingAddrLO, cplus_rx_ring_desc));
 
 uint32_t val, rxdw0,rxdw1,rxbufLO,rxbufHI;
 
@@ -1957,8 +1958,9 @@ static int rtl8139_cplus_transmit_one(RTL8139State *s)
 /* Normal priority ring */
 cplus_tx_ring_desc += 16 * descriptor;
 
-DEBUG_PRINT((RTL8139: +++ C+ mode reading TX descriptor %d from host 
memory at %08x0x%08x = 0x%8lx\n,
-   descriptor, s-TxAddr[1], s-TxAddr[0], cplus_tx_ring_desc));
+DEBUG_PRINT((RTL8139: +++ C+ mode reading TX descriptor %d from host 
+memory at %08x0x%08x = 0x TARGET_FMT_plx \n, descriptor,
+s-TxAddr[1], s-TxAddr[0], cplus_tx_ring_desc));
 
 uint32_t val, txdw0,txdw1,txbufLO,txbufHI;
 
@@ -2069,8 +2071,9 @@ static int rtl8139_cplus_transmit_one(RTL8139State *s)
 
 /* append more data to the packet */
 
-DEBUG_PRINT((RTL8139: +++ C+ mode transmit reading %d bytes from host 
memory at %016 PRIx64  to offset %d\n,
- txsize, (uint64_t)tx_addr, s-cplus_txbuffer_offset));
+DEBUG_PRINT((RTL8139: +++ C+ mode transmit reading %d bytes from host 
+memory at  TARGET_FMT_plx  to offset %d\n, txsize, tx_addr,
+s-cplus_txbuffer_offset));
 
 cpu_physical_memory_read(tx_addr, s-cplus_txbuffer + 
s-cplus_txbuffer_offset, txsize);
 s-cplus_txbuffer_offset += txsize;
-- 
1.7.4.1




[Qemu-devel] [PATCH 3/3] rtl8139: add format attribute to DPRINTF

2011-04-20 Thread Benjamin Poirier
gcc can check the format string for correctness even when debugging output is
not enabled.
Have to make sure arguments are always available. They are optimized out if
unneeded.

Signed-off-by: Benjamin Poirier benjamin.poir...@gmail.com
Cc: Igor V. Kovalenko igor.v.kovale...@gmail.com
---
 hw/rtl8139.c |9 ++---
 1 files changed, 6 insertions(+), 3 deletions(-)

diff --git a/hw/rtl8139.c b/hw/rtl8139.c
index 16ccd1e..15698ce 100644
--- a/hw/rtl8139.c
+++ b/hw/rtl8139.c
@@ -88,7 +88,11 @@
 #  define DPRINTF(fmt, ...) \
 do { fprintf(stderr, RTL8139:  fmt, ## __VA_ARGS__); } while (0)
 #else
-#  define DPRINTF(fmt, ...) do { } while (0)
+static inline __attribute__ ((format (printf, 1, 2)))
+int DPRINTF(const char *fmt, ...)
+{
+return 0;
+}
 #endif
 
 /* Symbolic offsets to registers. */
@@ -2201,9 +2205,8 @@ static int rtl8139_cplus_transmit_one(RTL8139State *s)
 
 if ((txdw0  CP_TX_LGSEN)  ip_protocol == IP_PROTO_TCP)
 {
-#if defined (DEBUG_RTL8139)
 int large_send_mss = (txdw0  16)  CP_TC_LGSEN_MSS_MASK;
-#endif
+
 DPRINTF(+++ C+ mode offloaded task TSO MTU=%d IP data %d 
 frame data %d specified MSS=%d\n, ETH_MTU,
 ip_data_len, saved_size - ETH_HLEN, large_send_mss);
-- 
1.7.4.1




[Qemu-devel] Re: [regression] configure: add opengl detection

2011-04-07 Thread Benjamin Poirier
On 07/04/11 05:35 PM, Michael Walle wrote:
 Am Mittwoch 06 April 2011, 16:13:58 schrieb Benjamin Poirier:
 Works as usual.
 The problem I'm facing stems from linking to libGL and memory
 protection issues. The particular system I ran this on has the binary
 nvidia driver and its companion libGL.so.260.19.44. As such I'd take
 no offense if we wave it off as a problem in the unsupported binary
 drivers and I'll be satisfied configuring with no opengl on that
 system.
 
 I would also be happy with opengl disabled by default. It is only used for 
 one 
 hardware model (milkymist-tmu2.c) atm. I don't think its worth that this 
 potentially breaks qemu for lots of users. What do you think?
 

I also have a system with binary ati drivers and it's ok. Perhaps other
people with the binary nvidia driver could comment?



[Qemu-devel] Re: [regression] configure: add opengl detection

2011-04-06 Thread Benjamin Poirier
On Mon, Apr 4, 2011 at 6:13 PM, Michael Walle mich...@walle.cc wrote:
 Hi Benjamin,

 Let me know if you need more info.

 what happens if you configure with

 ./configure --target-list=x86_64-softmmu --disable-opengl


Works as usual.
The problem I'm facing stems from linking to libGL and memory
protection issues. The particular system I ran this on has the binary
nvidia driver and its companion libGL.so.260.19.44. As such I'd take
no offense if we wave it off as a problem in the unsupported binary
drivers and I'll be satisfied configuring with no opengl on that
system.

Nevertheless, I did investigate about what's happening a little
further to clearly show that the problem is on nvidia's side.
1) as stated earlier, qemu segfaults when linked with the opengl libraries.

2) if I start qemu under gdb and configure it not to stop on SIGUSR2
(as I had omitted before; handle SIGUSR2 nostop noprint), qemu runs
ok. Same goes for strace.

3) if we enable /proc/sys/debug/exception-trace, the kernel printks:
qemu-system-x86[15693]: segfault at 10c7820 ip 010c7820 sp
7fff71e334c8 error 15

10c7820 is the faulting address. Looking at the core file, we see that
10c7820 is the famous code_gen_prologue:

Program terminated with signal 11, Segmentation fault.
#0  0x010c7820 in code_gen_prologue ()

(gdb) x /20i code_gen_prologue
= 0x10c7820 code_gen_prologue:   push   %rbp
   0x10c7821 code_gen_prologue+1: push   %rbx
   0x10c7822 code_gen_prologue+2: push   %r12
   0x10c7824 code_gen_prologue+4: push   %r13
[...]

By adding some debug code to map_exec() and adding a sigsegv handler
(that prints /proc/self/maps) I can see that code_gen_prologue is
adequately mprotect()'ed PROT_EXEC. Come time to jump into it from
cpu_exec(), that map is no longer there, the page is not executable,
and qemu crashes with a segfault.

Here is my debug output:
[...]
0091a000-01125000 rw-p  00:00 0
[...]
Will now map_exec 0x10c7820
Running mprotect 0x10c7000
Result: 0
[...]
0091a000-010c7000 rw-p  00:00 0
010c7000-010c8000 rwxp  00:00 0
010c8000-01125000 rw-p  00:00 0
[...]
Got SIGSEGV at address: 0x10c7820
[...]
0091a000-01125000 rw-p  00:00 0

I suspect that the nvidia libraries are messing with memory
protection. A look at objdump -R /usr/lib/libGL.so.1 indicates it does
need the symbol mprotect(). I tried to confirm this. Using a kernel
tracer (ftrace, perf or lttng), I can see that there are usually over
500 mprotect system calls before qemu crashes, including this
interesting combination (ftrace output):
 qemu-system-x86-21216 [002] 87794.633373: sys_mprotect(start:
10c7000, len: 1000, prot: 7)
 qemu-system-x86-21216 [000] 87794.806065: sys_mprotect(start: 40,
len: 2f1000, prot: 7)
 qemu-system-x86-21216 [000] 87794.806079: sys_mprotect(start: 8f,
len: 835000, prot: 3)

With prot: 3 (read, write) it is essentially undoing what was done
100+ ms. earlier. In order to track down exactly where that call comes
from I tried using an LD_PRELOAD wrapper around glibc's mprotect() -
source for the wrapper here: https://gist.github.com/905600
When I do that, qemu doesn't crash anymore. ftrace reports the number
of mprotect calls is down to 123 and the odd combination is no longer
present. I can put the wrapper code within qemu itself and forgo
LD_PRELOAD, result is the same - no crash.

I would've like to show the weird mprotect call coming out of libGL or
libnvidia-whatever so we could point the finger to nvidia, but alas.
I'm at a loss as to why it doesn't crash under gdb, strace or with a
wrapper. If anyone has thoughts on that, I'm all ears.

Thanks,
-Ben


 --
  Michael




[Qemu-devel] [regression] configure: add opengl detection

2011-04-04 Thread Benjamin Poirier
Hello,

commit 20ff075bb3340c5278a0da38ad1f4d602565aa06
Author: Michael Walle mich...@walle.cc
Date:   Mon Mar 7 23:32:39 2011 +0100

configure: add opengl detection

This patch introduce a new config option CONFIG_OPENGL.

Signed-off-by: Michael Walle mich...@walle.cc
Signed-off-by: Edgar E. Iglesias edgar.igles...@gmail.com

introduces a segfault for me with following backtrace:

Starting program:
/home/ben/local/src/qemu/x86_64-softmmu/qemu-system-x86_64 -m 1G -net
none -drive file=/home/ben/diskImages/debian_squeeze_amd64.qcow2,snapshot=on
-nographic
[Thread debugging using libthread_db enabled]
[New Thread 0x7fff9ee07700 (LWP 19445)]

Program received signal SIGUSR2, User defined signal 2.
0x75624ff3 in select () from /lib/libc.so.6
(gdb) info stack
#0  0x75624ff3 in select () from /lib/libc.so.6
#1  0x0042edfa in qemu_aio_wait () at aio.c:193
#2  0x0042dd65 in bdrv_read_em (bs=0x11277c0, sector_num=0,
buf=0x7fffd9d0 \353c\220\020\216м, nb_sectors=1)
at block.c:2660
#3  0x0042b790 in guess_disk_lchs (bs=0x11277c0,
pcylinders=0x7fffdc2c, pheads=0x7fffdc28,
psectors=0x7fffdc24) at block.c:1203
#4  0x0042b90f in bdrv_guess_geometry (bs=0x11277c0,
pcyls=0x7fffdc7c, pheads=0x7fffdc78,
psecs=0x7fffdc74) at block.c:1250
#5  0x005707c1 in ide_init_drive (s=0x1c936f0, bs=0x11277c0,
version=0x0, serial=0x0)
at /home/ben/local/src/qemu/hw/ide/core.c:2522
#6  0x00573762 in ide_drive_initfn (dev=0x15afb20) at
/home/ben/local/src/qemu/hw/ide/qdev.c:137
#7  0x00480328 in qdev_init (dev=0xa) at
/home/ben/local/src/qemu/hw/qdev.c:281
#8  0x0048039a in qdev_init_nofail (dev=0xa) at
/home/ben/local/src/qemu/hw/qdev.c:372
#9  0x005739fc in ide_create_drive (bus=value optimized out,
unit=0, drive=0x1127720)
at /home/ben/local/src/qemu/hw/ide/qdev.c:104
#10 0x00574206 in pci_ide_create_devs (dev=0x1c93410,
hd_table=value optimized out)
at /home/ben/local/src/qemu/hw/ide/pci.c:438
#11 0x0057489b in pci_piix3_ide_init (bus=value optimized
out, hd_table=0x7fffdda0,
devfn=value optimized out) at /home/ben/local/src/qemu/hw/ide/piix.c:177
#12 0x005aaf84 in pc_init1 (ram_size=value optimized out,
boot_device=value optimized out,
kernel_filename=value optimized out, kernel_cmdline=value
optimized out,
initrd_filename=0x18 Address 0x18 out of bounds,
cpu_model=value optimized out, pci_enabled=1, kvmclock_enabled=1)
at /home/ben/local/src/qemu/hw/pc_piix.c:143
#13 0x005ab208 in pc_init_pci (ram_size=10,
boot_device=0x7fffd890 , kernel_filename=0x7fffd810 ,
kernel_cmdline=0x Address 0x out
of bounds, initrd_filename=0x0,
cpu_model=0x4bf2 Address 0x4bf2 out of bounds) at
/home/ben/local/src/qemu/hw/pc_piix.c:199
#14 0x00546d8b in main (argc=value optimized out,
argv=0x7fffe1a8, envp=value optimized out)
at /home/ben/local/src/qemu/vl.c:3057

I configured with `./configure --target-list=x86_64-softmmu` and had
following output:
Install prefix/usr/local
BIOS directory/usr/local/share/qemu
binary directory  /usr/local/bin
config directory  /usr/local/etc
Manual directory  /usr/local/share/man
ELF interp prefix /usr/gnemul/qemu-%M
Source path   /home/ben/local/src/qemu
C compilergcc
Host C compiler   gcc
CFLAGS-O2 -g
QEMU_CFLAGS   -Werror -m64 -D_FORTIFY_SOURCE=2 -D_GNU_SOURCE
-D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE -Wstrict-prototypes
-Wredundant-decls -Wall -Wundef -Wendif-labels -Wwrite-strings
-Wmissing-prototypes -fno-strict-aliasing  -fstack-protector-all
-Wmissing-include-dirs -Wempty-body -Wnested-externs -Wformat-security
-Wformat-y2k -Winit-self -Wignored-qualifiers -Wold-style-declaration
-Wold-style-definition -Wtype-limits
LDFLAGS   -Wl,--warn-common -m64 -g
make  make
install   install
host CPU  x86_64
host big endian   no
target list   x86_64-softmmu
tcg debug enabled no
Mon debug enabled no
gprof enabled no
sparse enabledno
strip binariesyes
profiler  no
static build  no
-Werror enabled   yes
SDL support   yes
curses supportyes
curl support  yes
check support no
mingw32 support   no
Audio drivers oss
Extra audio cards ac97 es1370 sb16 hda
Block whitelist
Mixer emulation   no
VNC support   yes
VNC TLS support   yes
VNC SASL support  no
VNC JPEG support  yes
VNC PNG support   yes
VNC threadno
xen support   no
brlapi supportno
bluez  supportno
Documentation yes
NPTL support  yes
GUEST_BASEyes
PIE user targets  no
vde support   no
IO thread no
Linux AIO support yes
ATTR/XATTR support yes
Install blobs yes
KVM support   yes
fdt support   no
preadv supportyes
fdatasync yes
madvise   yes
posix_madvise yes
uuid support  yes
vhost-net support no
Trace 

[Qemu-devel] [PATCH v7 1/3] rtl8139: cleanup FCS calculation

2011-03-22 Thread Benjamin Poirier
clean out ifdef's around ethernet checksum calculation

Signed-off-by: Benjamin Poirier benjamin.poir...@gmail.com
Acked-by: Igor V. Kovalenko igor.v.kovale...@gmail.com
Cc: Jason Wang jasow...@redhat.com
Cc: Michael S. Tsirkin m...@redhat.com
Cc: Blue Swirl blauwir...@gmail.com
---
 hw/rtl8139.c |   20 +++-
 1 files changed, 3 insertions(+), 17 deletions(-)

diff --git a/hw/rtl8139.c b/hw/rtl8139.c
index 0ba51fc..d843aa0 100644
--- a/hw/rtl8139.c
+++ b/hw/rtl8139.c
@@ -47,6 +47,9 @@
  *  Darwin)
  */
 
+/* For crc32 */
+#include zlib.h
+
 #include hw.h
 #include pci.h
 #include qemu-timer.h
@@ -62,14 +65,6 @@
 /* debug RTL8139 card C+ mode only */
 //#define DEBUG_RTL8139CP 1
 
-/* Calculate CRCs properly on Rx packets */
-#define RTL8139_CALCULATE_RXCRC 1
-
-#if defined(RTL8139_CALCULATE_RXCRC)
-/* For crc32 */
-#include zlib.h
-#endif
-
 #define SET_MASKED(input, mask, curr) \
 ( ( (input)  ~(mask) ) | ( (curr)  (mask) ) )
 
@@ -1030,11 +1025,7 @@ static ssize_t rtl8139_do_receive(VLANClientState *nc, 
const uint8_t *buf, size_
 }
 
 /* write checksum */
-#if defined (RTL8139_CALCULATE_RXCRC)
 val = cpu_to_le32(crc32(0, buf, size));
-#else
-val = 0;
-#endif
 cpu_physical_memory_write( rx_addr+size, (uint8_t *)val, 4);
 
 /* first segment of received packet flag */
@@ -1136,12 +1127,7 @@ static ssize_t rtl8139_do_receive(VLANClientState *nc, 
const uint8_t *buf, size_
 rtl8139_write_buffer(s, buf, size);
 
 /* write checksum */
-#if defined (RTL8139_CALCULATE_RXCRC)
 val = cpu_to_le32(crc32(0, buf, size));
-#else
-val = 0;
-#endif
-
 rtl8139_write_buffer(s, (uint8_t *)val, 4);
 
 /* correct buffer write pointer */
-- 
1.7.4.1




[Qemu-devel] [PATCH v7] rtl8139: add vlan support

2011-03-22 Thread Benjamin Poirier
Hello,

Here is version 7 of my patchset to add vlan support to the emulated rtl8139
nic.

Changes since v6:
* added check against guest requesting tagging on frames with len  12
* simplified tag extraction in receive function. dot1q_buf arg removed
  from rtl8139_do_receive(). Frame is linearized in transfer_frame()
  when loopback mode is on.
* added an entry to file header

I've ran the same tests as usual on linux and this time also freebsd 8.2, with
and without vlanhwtso in the latter case. Jason, you're right that loopback
mode is seldom used! It seems the bsd driver only uses it at probe time to
identify a defect in some 8169 [1,2] and even then, that check has been
disabled [3]. The linux driver doesn't support loopback mode (unless it's well
hidden.)

[1] 
http://lists.freebsd.org/pipermail/freebsd-emulation/2006-May/thread.html#2055
[2] 
http://www.freebsd.org/cgi/cvsweb.cgi/src/sys/dev/re/if_re.c?rev=1.196;content-type=text%2Fplain
[3] http://www.freebsd.org/cgi/cvsweb.cgi/src/sys/dev/re/if_re.c#rev1.68

Changes since v5:
* moved all receive changes to add vlan tag extraction
* fixed checkpatch.pl style issues
* fixed bugs in receive case related to small buffers and loopback
  mode. Moved too small buffer code back where it used to be, though
  it is changed in content.

Changes since v4:
* removed alloca(), for real. Thanks to the reviewers for their
  patience. This patchset now has more versions than the vlan header
  has bytes!
* corrected the unlikely, debug printf and long lines, as per comments
* cleaned out ifdef's pertaining to ethernet checksum calculation.
  According to a comment since removed they were related to an
  optimization:
   RTL8139 provides frame CRC with received packet, this feature
   seems to be ignored by most drivers, disabled by default
  see commit ccf1d14

I've tested v5 using x86_64 host/guest with the usual procedure. I've also ran
the clang analyzer on the qemu code base, just for fun.

Changes since v3:
* removed alloca() and #include net/ethernet.h as per comments
* reordered patches to put extraction before insertion. Extraction
  touches only the receive path but insertion touches both. The two
  patches are now needed to have vlan functionnality.

I've tested v4 with x86_64 host/guest. I used the same testing procedure as
before. I've tested a plain configuration as well as one with tso + vlan
offload, successfully.

I had to hack around the Linux 8139cp driver to be able to enable tso on vlan
which leads me to wonder, can someone with access to the C+ spec or a real
card confirm that it can do tso and vlan offload at the same time? The patch
I used for the kernel is at https://gist.github.com/851895.

Changes since v2:
insertion:
* moved insertion later in the process, to handle tso
* use qemu_sendv_packet() to insert the tag for us
* added dot1q_buf parameter to rtl8139_do_receive() to avoid some
  memcpy() in loopback mode. Note that the code path through that
  function is unchanged when dot1q_buf is NULL.

extraction:
* reduced the amount of copying by moving the frame too short logic
  after the removal of the vlan tag (as is done in e1000.c for
  example). Unfortunately, that logic can no longer be shared betwen
  C+ and C mode.

I've posted v2 of these patches back in November
http://article.gmane.org/gmane.comp.emulators.qemu/84252

I've tested v3 on the following combinations of guest and hosts:
host: x86_64, guest: x86_64
host: x86_64, guest: ppc32
host: ppc32, guest: ppc32

Testing on the x86_64 host used '-net tap' and consisted of:
* making an http transfert on the untagged interface.
* ping -s 0-1472 to another host on a vlan.
* making an scp upload to another host on a vlan.

Testing on the ppc32 host used '-net socket' connected to an x86_64 qemu-kvm
running the virtio nic and consisted of:
* establishing an ssh connection between the two using an untagged interface.
* ping -s 0-1472 between the two using a vlan.
* making an scp transfer in both directions using a vlan.

All that was successful. Nevertheless, it doesn't exercise all code paths so
care is in order.

Please note that the lack of vlan support in rtl8139 has taken a few people
aback:
https://bugzilla.redhat.com/show_bug.cgi?id=516587
http://article.gmane.org/gmane.linux.network.general/14266

Thanks,
-Ben



[Qemu-devel] [PATCH v7 2/3] rtl8139: add vlan tag extraction

2011-03-22 Thread Benjamin Poirier
Add support to the emulated hardware to extract vlan tags in packets
going from the network to the guest.

Signed-off-by: Benjamin Poirier benjamin.poir...@gmail.com
Cc: Igor V. Kovalenko igor.v.kovale...@gmail.com
Cc: Jason Wang jasow...@redhat.com
Cc: Michael S. Tsirkin m...@redhat.com
Cc: Blue Swirl blauwir...@gmail.com

--

AFAIK, extraction is optional to get vlans working. The driver
requests rx detagging but should not assume that it was done. Under
Linux, the mac layer will catch the vlan ethertype. I only added this
part for completeness (to emulate the hardware more truthfully...)
---
 hw/rtl8139.c |   66 +
 1 files changed, 52 insertions(+), 14 deletions(-)

diff --git a/hw/rtl8139.c b/hw/rtl8139.c
index d843aa0..5b2f489 100644
--- a/hw/rtl8139.c
+++ b/hw/rtl8139.c
@@ -72,6 +72,16 @@
 #define MOD2(input, size) \
 ( ( input )  ( size - 1 )  )
 
+#define ETHER_ADDR_LEN 6
+#define ETHER_TYPE_LEN 2
+#define ETH_HLEN (ETHER_ADDR_LEN * 2 + ETHER_TYPE_LEN)
+#define ETH_P_IP0x0800  /* Internet Protocol packet */
+#define ETH_P_8021Q 0x8100  /* 802.1Q VLAN Extended Header  */
+#define ETH_MTU 1500
+
+#define VLAN_TCI_LEN 2
+#define VLAN_HLEN (ETHER_TYPE_LEN + VLAN_TCI_LEN)
+
 #if defined (DEBUG_RTL8139)
 #  define DEBUG_PRINT(x) do { printf x ; } while (0)
 #else
@@ -812,11 +822,13 @@ static int rtl8139_can_receive(VLANClientState *nc)
 static ssize_t rtl8139_do_receive(VLANClientState *nc, const uint8_t *buf, 
size_t size_, int do_interrupt)
 {
 RTL8139State *s = DO_UPCAST(NICState, nc, nc)-opaque;
+/* size is the length of the buffer passed to the driver */
 int size = size_;
+const uint8_t *dot1q_buf = NULL;
 
 uint32_t packet_header = 0;
 
-uint8_t buf1[60];
+uint8_t buf1[MIN_BUF_SIZE + VLAN_HLEN];
 static const uint8_t broadcast_macaddr[6] =
 { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
 
@@ -928,12 +940,15 @@ static ssize_t rtl8139_do_receive(VLANClientState *nc, 
const uint8_t *buf, size_
 }
 }
 
-/* if too small buffer, then expand it */
-if (size  MIN_BUF_SIZE) {
+/* if too small buffer, then expand it
+ * Include some tailroom in case a vlan tag is later removed. */
+if (size  MIN_BUF_SIZE + VLAN_HLEN) {
 memcpy(buf1, buf, size);
-memset(buf1 + size, 0, MIN_BUF_SIZE - size);
+memset(buf1 + size, 0, MIN_BUF_SIZE + VLAN_HLEN - size);
 buf = buf1;
-size = MIN_BUF_SIZE;
+if (size  MIN_BUF_SIZE) {
+size = MIN_BUF_SIZE;
+}
 }
 
 if (rtl8139_cp_receiver_enabled(s))
@@ -996,6 +1011,29 @@ static ssize_t rtl8139_do_receive(VLANClientState *nc, 
const uint8_t *buf, size_
 
 uint32_t rx_space = rxdw0  CP_RX_BUFFER_SIZE_MASK;
 
+/* write VLAN info to descriptor variables. */
+if (s-CpCmd  CPlusRxVLAN  be16_to_cpup((uint16_t *)
+buf[ETHER_ADDR_LEN * 2]) == ETH_P_8021Q) {
+dot1q_buf = buf[ETHER_ADDR_LEN * 2];
+size -= VLAN_HLEN;
+/* if too small buffer, use the tailroom added duing expansion */
+if (size  MIN_BUF_SIZE) {
+size = MIN_BUF_SIZE;
+}
+
+rxdw1 = ~CP_RX_VLAN_TAG_MASK;
+/* BE + ~le_to_cpu()~ + cpu_to_le() = BE */
+rxdw1 |= CP_RX_TAVA | le16_to_cpup((uint16_t *)
+dot1q_buf[ETHER_TYPE_LEN]);
+
+DEBUG_PRINT((RTL8139: C+ Rx mode : extracted vlan tag with tci: 
+%u\n, be16_to_cpup((uint16_t *)
+dot1q_buf[ETHER_TYPE_LEN])));
+} else {
+/* reset VLAN tag flag */
+rxdw1 = ~CP_RX_TAVA;
+}
+
 /* TODO: scatter the packet over available receive ring descriptors 
space */
 
 if (size+4  rx_space)
@@ -1017,7 +1055,14 @@ static ssize_t rtl8139_do_receive(VLANClientState *nc, 
const uint8_t *buf, size_
 target_phys_addr_t rx_addr = rtl8139_addr64(rxbufLO, rxbufHI);
 
 /* receive/copy to target memory */
-cpu_physical_memory_write( rx_addr, buf, size );
+if (dot1q_buf) {
+cpu_physical_memory_write(rx_addr, buf, 2 * ETHER_ADDR_LEN);
+cpu_physical_memory_write(rx_addr + 2 * ETHER_ADDR_LEN,
+buf + 2 * ETHER_ADDR_LEN + VLAN_HLEN,
+size - 2 * ETHER_ADDR_LEN);
+} else {
+cpu_physical_memory_write(rx_addr, buf, size);
+}
 
 if (s-CpCmd  CPlusRxChkSum)
 {
@@ -1025,7 +1070,7 @@ static ssize_t rtl8139_do_receive(VLANClientState *nc, 
const uint8_t *buf, size_
 }
 
 /* write checksum */
-val = cpu_to_le32(crc32(0, buf, size));
+val = cpu_to_le32(crc32(0, buf, size_));
 cpu_physical_memory_write( rx_addr+size, (uint8_t *)val, 4);
 
 /* first segment of received packet flag */
@@ -1070,9 +1115,6 @@ static ssize_t rtl8139_do_receive(VLANClientState *nc, 
const uint8_t

[Qemu-devel] [PATCH v7 3/3] rtl8139: add vlan tag insertion

2011-03-22 Thread Benjamin Poirier
Add support to the emulated hardware to insert vlan tags in packets
going from the guest to the network.

Signed-off-by: Benjamin Poirier benjamin.poir...@gmail.com
Cc: Igor V. Kovalenko igor.v.kovale...@gmail.com
Cc: Jason Wang jasow...@redhat.com
Cc: Michael S. Tsirkin m...@redhat.com
Cc: Blue Swirl blauwir...@gmail.com
---
 hw/rtl8139.c |   75 ++---
 1 files changed, 60 insertions(+), 15 deletions(-)

diff --git a/hw/rtl8139.c b/hw/rtl8139.c
index 5b2f489..d545933 100644
--- a/hw/rtl8139.c
+++ b/hw/rtl8139.c
@@ -45,6 +45,7 @@
  *  2010-Feb-04  Frediano Ziglio:   Rewrote timer support using QEMU timer only
  *  when strictly needed (required for for
  *  Darwin)
+ *  2011-Mar-22  Benjamin Poirier:  Implemented VLAN offloading
  */
 
 /* For crc32 */
@@ -56,6 +57,7 @@
 #include net.h
 #include loader.h
 #include sysemu.h
+#include iov.h
 
 /* debug RTL8139 card */
 //#define DEBUG_RTL8139 1
@@ -1756,22 +1758,52 @@ static uint32_t rtl8139_RxConfig_read(RTL8139State *s)
 return ret;
 }
 
-static void rtl8139_transfer_frame(RTL8139State *s, const uint8_t *buf, int 
size, int do_interrupt)
+static void rtl8139_transfer_frame(RTL8139State *s, uint8_t *buf, int size,
+int do_interrupt, const uint8_t *dot1q_buf)
 {
+struct iovec *iov = NULL;
+
 if (!size)
 {
 DEBUG_PRINT((RTL8139: +++ empty ethernet frame\n));
 return;
 }
 
+if (dot1q_buf  size = ETHER_ADDR_LEN * 2) {
+iov = (struct iovec[3]) {
+{ .iov_base = buf, .iov_len = ETHER_ADDR_LEN * 2 },
+{ .iov_base = (void *) dot1q_buf, .iov_len = VLAN_HLEN },
+{ .iov_base = buf + ETHER_ADDR_LEN * 2,
+.iov_len = size - ETHER_ADDR_LEN * 2 },
+};
+}
+
 if (TxLoopBack == (s-TxConfig  TxLoopBack))
 {
+size_t buf2_size;
+uint8_t *buf2;
+
+if (iov) {
+buf2_size = iov_size(iov, 3);
+buf2 = qemu_malloc(buf2_size);
+iov_to_buf(iov, 3, buf2, 0, buf2_size);
+buf = buf2;
+}
+
 DEBUG_PRINT((RTL8139: +++ transmit loopback mode\n));
 rtl8139_do_receive(s-nic-nc, buf, size, do_interrupt);
+
+if (iov) {
+qemu_free(buf2);
+}
 }
 else
 {
-qemu_send_packet(s-nic-nc, buf, size);
+if (iov) {
+qemu_sendv_packet(s-nic-nc, iov, 3);
+} else {
+qemu_send_packet(s-nic-nc, buf, size);
+}
 }
 }
 
@@ -1805,7 +1837,7 @@ static int rtl8139_transmit_one(RTL8139State *s, int 
descriptor)
 s-TxStatus[descriptor] |= TxHostOwns;
 s-TxStatus[descriptor] |= TxStatOK;
 
-rtl8139_transfer_frame(s, txbuffer, txsize, 0);
+rtl8139_transfer_frame(s, txbuffer, txsize, 0, NULL);
 
 DEBUG_PRINT((RTL8139: +++ transmitted %d bytes from descriptor %d\n, 
txsize, descriptor));
 
@@ -1932,7 +1964,6 @@ static int rtl8139_cplus_transmit_one(RTL8139State *s)
 
 cpu_physical_memory_read(cplus_tx_ring_desc,(uint8_t *)val, 4);
 txdw0 = le32_to_cpu(val);
-/* TODO: implement VLAN tagging support, VLAN tag data is read to txdw1 */
 cpu_physical_memory_read(cplus_tx_ring_desc+4,  (uint8_t *)val, 4);
 txdw1 = le32_to_cpu(val);
 cpu_physical_memory_read(cplus_tx_ring_desc+8,  (uint8_t *)val, 4);
@@ -1944,9 +1975,6 @@ static int rtl8139_cplus_transmit_one(RTL8139State *s)
descriptor,
txdw0, txdw1, txbufLO, txbufHI));
 
-/* TODO: the following discard cast should clean clang analyzer output */
-(void)txdw1;
-
 /* w0 ownership flag */
 #define CP_TX_OWN (131)
 /* w0 end of ring flag */
@@ -1970,9 +1998,9 @@ static int rtl8139_cplus_transmit_one(RTL8139State *s)
 /* w0 bits 0...15 : buffer size */
 #define CP_TX_BUFFER_SIZE (116)
 #define CP_TX_BUFFER_SIZE_MASK (CP_TX_BUFFER_SIZE - 1)
-/* w1 tag available flag */
-#define CP_RX_TAGC (117)
-/* w1 bits 0...15 : VLAN tag */
+/* w1 add tag flag */
+#define CP_TX_TAGC (117)
+/* w1 bits 0...15 : VLAN tag (big endian) */
 #define CP_TX_VLAN_TAG_MASK ((116) - 1)
 /* w2 low  32bit of Rx buffer ptr */
 /* w3 high 32bit of Rx buffer ptr */
@@ -2072,13 +2100,13 @@ static int rtl8139_cplus_transmit_one(RTL8139State *s)
 /* update ring data */
 val = cpu_to_le32(txdw0);
 cpu_physical_memory_write(cplus_tx_ring_desc,(uint8_t *)val, 4);
-/* TODO: implement VLAN tagging support, VLAN tag data is read to txdw1 */
-//val = cpu_to_le32(txdw1);
-//cpu_physical_memory_write(cplus_tx_ring_desc+4,  val, 4);
 
 /* Now decide if descriptor being processed is holding the last segment of 
packet */
 if (txdw0  CP_TX_LS)
 {
+uint8_t dot1q_buffer_space[VLAN_HLEN];
+uint16_t *dot1q_buffer;
+
 DEBUG_PRINT((RTL8139: +++ C+ Tx mode : descriptor %d is last segment 
descriptor\n, descriptor));
 
 /* can transfer fully assembled packet

[Qemu-devel] [PATCH v6 1/3] rtl8139: cleanup FCS calculation

2011-03-10 Thread Benjamin Poirier
clean out ifdef's around ethernet checksum calculation

Signed-off-by: Benjamin Poirier benjamin.poir...@gmail.com
Cc: Igor V. Kovalenko igor.v.kovale...@gmail.com
Cc: Jason Wang jasow...@redhat.com
Cc: Michael S. Tsirkin m...@redhat.com
Cc: Blue Swirl blauwir...@gmail.com
---
 hw/rtl8139.c |   20 +++-
 1 files changed, 3 insertions(+), 17 deletions(-)

diff --git a/hw/rtl8139.c b/hw/rtl8139.c
index a22530c..3772ac1 100644
--- a/hw/rtl8139.c
+++ b/hw/rtl8139.c
@@ -47,6 +47,9 @@
  *  Darwin)
  */
 
+/* For crc32 */
+#include zlib.h
+
 #include hw.h
 #include pci.h
 #include qemu-timer.h
@@ -62,14 +65,6 @@
 /* debug RTL8139 card C+ mode only */
 //#define DEBUG_RTL8139CP 1
 
-/* Calculate CRCs properly on Rx packets */
-#define RTL8139_CALCULATE_RXCRC 1
-
-#if defined(RTL8139_CALCULATE_RXCRC)
-/* For crc32 */
-#include zlib.h
-#endif
-
 #define SET_MASKED(input, mask, curr) \
 ( ( (input)  ~(mask) ) | ( (curr)  (mask) ) )
 
@@ -1030,11 +1025,7 @@ static ssize_t rtl8139_do_receive(VLANClientState *nc, 
const uint8_t *buf, size_
 }
 
 /* write checksum */
-#if defined (RTL8139_CALCULATE_RXCRC)
 val = cpu_to_le32(crc32(0, buf, size));
-#else
-val = 0;
-#endif
 cpu_physical_memory_write( rx_addr+size, (uint8_t *)val, 4);
 
 /* first segment of received packet flag */
@@ -1136,12 +1127,7 @@ static ssize_t rtl8139_do_receive(VLANClientState *nc, 
const uint8_t *buf, size_
 rtl8139_write_buffer(s, buf, size);
 
 /* write checksum */
-#if defined (RTL8139_CALCULATE_RXCRC)
 val = cpu_to_le32(crc32(0, buf, size));
-#else
-val = 0;
-#endif
-
 rtl8139_write_buffer(s, (uint8_t *)val, 4);
 
 /* correct buffer write pointer */
-- 
1.7.2.3




[Qemu-devel] [PATCH v6] rtl8139: add vlan support

2011-03-10 Thread Benjamin Poirier
Here is version 6 of my patchset to add vlan support to the emulated rtl8139
nic.

Changes since v5:
* moved all receive changes to add vlan tag extraction
* fixed checkpatch.pl style issues
* fixed bugs in receive case related to small buffers and loopback
  mode. Moved too small buffer code back where it used to be, though
  it is changed in content.

Changes since v4:
* removed alloca(), for real. Thanks to the reviewers for their
  patience. This patchset now has more versions than the vlan header
  has bytes!
* corrected the unlikely, debug printf and long lines, as per comments
* cleaned out ifdef's pertaining to ethernet checksum calculation.
  According to a comment since removed they were related to an
  optimization:
   RTL8139 provides frame CRC with received packet, this feature
   seems to be ignored by most drivers, disabled by default
  see commit ccf1d14

I've tested v5 using x86_64 host/guest with the usual procedure. I've also ran
the clang analyzer on the qemu code base, just for fun.

Changes since v3:
* removed alloca() and #include net/ethernet.h as per comments
* reordered patches to put extraction before insertion. Extraction
  touches only the receive path but insertion touches both. The two
  patches are now needed to have vlan functionnality.

I've tested v4 with x86_64 host/guest. I used the same testing procedure as
before. I've tested a plain configuration as well as one with tso + vlan
offload, successfully.

I had to hack around the Linux 8139cp driver to be able to enable tso on vlan
which leads me to wonder, can someone with access to the C+ spec or a real
card confirm that it can do tso and vlan offload at the same time? The patch
I used for the kernel is at https://gist.github.com/851895.

Changes since v2:
insertion:
* moved insertion later in the process, to handle tso
* use qemu_sendv_packet() to insert the tag for us
* added dot1q_buf parameter to rtl8139_do_receive() to avoid some
  memcpy() in loopback mode. Note that the code path through that
  function is unchanged when dot1q_buf is NULL.

extraction:
* reduced the amount of copying by moving the frame too short logic
  after the removal of the vlan tag (as is done in e1000.c for
  example). Unfortunately, that logic can no longer be shared betwen
  C+ and C mode.

I've posted v2 of these patches back in November
http://article.gmane.org/gmane.comp.emulators.qemu/84252

I've tested v3 on the following combinations of guest and hosts:
host: x86_64, guest: x86_64
host: x86_64, guest: ppc32
host: ppc32, guest: ppc32

Testing on the x86_64 host used '-net tap' and consisted of:
* making an http transfert on the untagged interface.
* ping -s 0-1472 to another host on a vlan.
* making an scp upload to another host on a vlan.

Testing on the ppc32 host used '-net socket' connected to an x86_64 qemu-kvm
running the virtio nic and consisted of:
* establishing an ssh connection between the two using an untagged interface.
* ping -s 0-1472 between the two using a vlan.
* making an scp transfer in both directions using a vlan.

All that was successful. Nevertheless, it doesn't exercise all code paths so
care is in order.

Please note that the lack of vlan support in rtl8139 has taken a few people
aback:
https://bugzilla.redhat.com/show_bug.cgi?id=516587
http://article.gmane.org/gmane.linux.network.general/14266

Thanks,
-Ben



[Qemu-devel] [PATCH v6 3/3] rtl8139: add vlan tag insertion

2011-03-10 Thread Benjamin Poirier
Add support to the emulated hardware to insert vlan tags in packets
going from the guest to the network.

Signed-off-by: Benjamin Poirier benjamin.poir...@gmail.com
Cc: Igor V. Kovalenko igor.v.kovale...@gmail.com
Cc: Jason Wang jasow...@redhat.com
Cc: Michael S. Tsirkin m...@redhat.com
Cc: Blue Swirl blauwir...@gmail.com
---
 hw/rtl8139.c |   57 +
 1 files changed, 41 insertions(+), 16 deletions(-)

diff --git a/hw/rtl8139.c b/hw/rtl8139.c
index 312d362..11034fb 100644
--- a/hw/rtl8139.c
+++ b/hw/rtl8139.c
@@ -1821,7 +1821,8 @@ static uint32_t rtl8139_RxConfig_read(RTL8139State *s)
 return ret;
 }
 
-static void rtl8139_transfer_frame(RTL8139State *s, const uint8_t *buf, int 
size, int do_interrupt)
+static void rtl8139_transfer_frame(RTL8139State *s, uint8_t *buf, int size,
+int do_interrupt, const uint8_t *dot1q_buf)
 {
 if (!size)
 {
@@ -1832,11 +1833,22 @@ static void rtl8139_transfer_frame(RTL8139State *s, 
const uint8_t *buf, int size
 if (TxLoopBack == (s-TxConfig  TxLoopBack))
 {
 DEBUG_PRINT((RTL8139: +++ transmit loopback mode\n));
-rtl8139_do_receive(s-nic-nc, buf, size, do_interrupt, NULL);
+rtl8139_do_receive(s-nic-nc, buf, size, do_interrupt, dot1q_buf);
 }
 else
 {
-qemu_send_packet(s-nic-nc, buf, size);
+if (dot1q_buf) {
+struct iovec iov[] = {
+{ .iov_base = buf, .iov_len = ETHER_ADDR_LEN * 2 },
+{ .iov_base = (void *) dot1q_buf, .iov_len = VLAN_HLEN },
+{ .iov_base = buf + ETHER_ADDR_LEN * 2,
+.iov_len = size - ETHER_ADDR_LEN * 2 },
+};
+
+qemu_sendv_packet(s-nic-nc, iov, ARRAY_SIZE(iov));
+} else {
+qemu_send_packet(s-nic-nc, buf, size);
+}
 }
 }
 
@@ -1870,7 +1882,7 @@ static int rtl8139_transmit_one(RTL8139State *s, int 
descriptor)
 s-TxStatus[descriptor] |= TxHostOwns;
 s-TxStatus[descriptor] |= TxStatOK;
 
-rtl8139_transfer_frame(s, txbuffer, txsize, 0);
+rtl8139_transfer_frame(s, txbuffer, txsize, 0, NULL);
 
 DEBUG_PRINT((RTL8139: +++ transmitted %d bytes from descriptor %d\n, 
txsize, descriptor));
 
@@ -1997,7 +2009,6 @@ static int rtl8139_cplus_transmit_one(RTL8139State *s)
 
 cpu_physical_memory_read(cplus_tx_ring_desc,(uint8_t *)val, 4);
 txdw0 = le32_to_cpu(val);
-/* TODO: implement VLAN tagging support, VLAN tag data is read to txdw1 */
 cpu_physical_memory_read(cplus_tx_ring_desc+4,  (uint8_t *)val, 4);
 txdw1 = le32_to_cpu(val);
 cpu_physical_memory_read(cplus_tx_ring_desc+8,  (uint8_t *)val, 4);
@@ -2009,9 +2020,6 @@ static int rtl8139_cplus_transmit_one(RTL8139State *s)
descriptor,
txdw0, txdw1, txbufLO, txbufHI));
 
-/* TODO: the following discard cast should clean clang analyzer output */
-(void)txdw1;
-
 /* w0 ownership flag */
 #define CP_TX_OWN (131)
 /* w0 end of ring flag */
@@ -2035,9 +2043,9 @@ static int rtl8139_cplus_transmit_one(RTL8139State *s)
 /* w0 bits 0...15 : buffer size */
 #define CP_TX_BUFFER_SIZE (116)
 #define CP_TX_BUFFER_SIZE_MASK (CP_TX_BUFFER_SIZE - 1)
-/* w1 tag available flag */
-#define CP_RX_TAGC (117)
-/* w1 bits 0...15 : VLAN tag */
+/* w1 add tag flag */
+#define CP_TX_TAGC (117)
+/* w1 bits 0...15 : VLAN tag (big endian) */
 #define CP_TX_VLAN_TAG_MASK ((116) - 1)
 /* w2 low  32bit of Rx buffer ptr */
 /* w3 high 32bit of Rx buffer ptr */
@@ -2137,13 +2145,13 @@ static int rtl8139_cplus_transmit_one(RTL8139State *s)
 /* update ring data */
 val = cpu_to_le32(txdw0);
 cpu_physical_memory_write(cplus_tx_ring_desc,(uint8_t *)val, 4);
-/* TODO: implement VLAN tagging support, VLAN tag data is read to txdw1 */
-//val = cpu_to_le32(txdw1);
-//cpu_physical_memory_write(cplus_tx_ring_desc+4,  val, 4);
 
 /* Now decide if descriptor being processed is holding the last segment of 
packet */
 if (txdw0  CP_TX_LS)
 {
+uint8_t dot1q_buffer_space[VLAN_HLEN];
+uint16_t *dot1q_buffer;
+
 DEBUG_PRINT((RTL8139: +++ C+ Tx mode : descriptor %d is last segment 
descriptor\n, descriptor));
 
 /* can transfer fully assembled packet */
@@ -2152,6 +2160,21 @@ static int rtl8139_cplus_transmit_one(RTL8139State *s)
 int  saved_size= s-cplus_txbuffer_offset;
 int  saved_buffer_len = s-cplus_txbuffer_len;
 
+/* create vlan tag */
+if (txdw1  CP_TX_TAGC) {
+/* the vlan tag is in BE byte order in the descriptor
+ * BE + le_to_cpu() + ~swap()~ = cpu */
+DEBUG_PRINT((RTL8139: +++ C+ Tx mode : inserting vlan tag with 
+tci: %u\n, bswap16(txdw1  CP_TX_VLAN_TAG_MASK)));
+
+dot1q_buffer = (uint16_t *) dot1q_buffer_space;
+dot1q_buffer[0] = cpu_to_be16(ETH_P_8021Q);
+/* BE + le_to_cpu() + ~cpu_to_le

[Qemu-devel] [PATCH v6 2/3] rtl8139: add vlan tag extraction

2011-03-10 Thread Benjamin Poirier
Add support to the emulated hardware to extract vlan tags in packets
going from the network to the guest.

Signed-off-by: Benjamin Poirier benjamin.poir...@gmail.com
Cc: Igor V. Kovalenko igor.v.kovale...@gmail.com
Cc: Jason Wang jasow...@redhat.com
Cc: Michael S. Tsirkin m...@redhat.com
Cc: Blue Swirl blauwir...@gmail.com

--

AFAIK, extraction is optional to get vlans working. The driver
requests rx detagging but should not assume that it was done. Under
Linux, the mac layer will catch the vlan ethertype. I only added this
part for completeness (to emulate the hardware more truthfully...)
---
 hw/rtl8139.c |  125 ++
 1 files changed, 108 insertions(+), 17 deletions(-)

diff --git a/hw/rtl8139.c b/hw/rtl8139.c
index 3772ac1..312d362 100644
--- a/hw/rtl8139.c
+++ b/hw/rtl8139.c
@@ -72,6 +72,22 @@
 #define MOD2(input, size) \
 ( ( input )  ( size - 1 )  )
 
+#define min(x, y) ({\
+typeof(x) _min1 = (x);  \
+typeof(y) _min2 = (y);  \
+(void) (_min1 == _min2);  \
+_min1  _min2 ? _min1 : _min2; })
+
+#define ETHER_ADDR_LEN 6
+#define ETHER_TYPE_LEN 2
+#define ETH_HLEN (ETHER_ADDR_LEN * 2 + ETHER_TYPE_LEN)
+#define ETH_P_IP0x0800  /* Internet Protocol packet */
+#define ETH_P_8021Q 0x8100  /* 802.1Q VLAN Extended Header  */
+#define ETH_MTU 1500
+
+#define VLAN_TCI_LEN 2
+#define VLAN_HLEN (ETHER_TYPE_LEN + VLAN_TCI_LEN)
+
 #if defined (DEBUG_RTL8139)
 #  define DEBUG_PRINT(x) do { printf x ; } while (0)
 #else
@@ -777,6 +793,14 @@ static void rtl8139_write_buffer(RTL8139State *s, const 
void *buf, int size)
 s-RxBufAddr += size;
 }
 
+static unsigned long rtl8139_write_buffer_crc(RTL8139State *s, const void
+*buf, int size, unsigned long crc)
+{
+rtl8139_write_buffer(s, buf, size);
+return crc32(crc, buf, size);
+}
+
+
 #define MIN_BUF_SIZE 60
 static inline target_phys_addr_t rtl8139_addr64(uint32_t low, uint32_t high)
 {
@@ -809,14 +833,20 @@ static int rtl8139_can_receive(VLANClientState *nc)
 }
 }
 
-static ssize_t rtl8139_do_receive(VLANClientState *nc, const uint8_t *buf, 
size_t size_, int do_interrupt)
+static ssize_t rtl8139_do_receive(VLANClientState *nc, const uint8_t *buf,
+size_t buf_size, int do_interrupt, const uint8_t *dot1q_buf)
 {
 RTL8139State *s = DO_UPCAST(NICState, nc, nc)-opaque;
+/* size_ is the total length of argument buffers */
+const int size_ = buf_size + (dot1q_buf ? VLAN_HLEN : 0);
+/* size is the length of the buffer passed to the driver */
 int size = size_;
+const uint8_t *next_part;
+size_t next_part_size;
 
 uint32_t packet_header = 0;
 
-uint8_t buf1[60];
+uint8_t buf1[MIN_BUF_SIZE];
 static const uint8_t broadcast_macaddr[6] =
 { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
 
@@ -930,10 +960,28 @@ static ssize_t rtl8139_do_receive(VLANClientState *nc, 
const uint8_t *buf, size_
 
 /* if too small buffer, then expand it */
 if (size  MIN_BUF_SIZE) {
-memcpy(buf1, buf, size);
-memset(buf1 + size, 0, MIN_BUF_SIZE - size);
+size_t copied_size;
+
+copied_size = min((size_t) ETHER_ADDR_LEN * 2, buf_size);
+memcpy(buf1, buf, copied_size);
+buf_size -= copied_size;
+
+if (dot1q_buf) {
+if (copied_size = ETHER_ADDR_LEN * 2) {
+memcpy(buf1 + copied_size, dot1q_buf, VLAN_HLEN);
+copied_size += VLAN_HLEN;
+}
+dot1q_buf = NULL;
+}
+
+if (buf_size  0) {
+memcpy(buf1 + copied_size, buf[ETHER_ADDR_LEN * 2], buf_size);
+copied_size += buf_size;
+}
+memset(buf1 + copied_size, 0, MIN_BUF_SIZE - copied_size);
 buf = buf1;
 size = MIN_BUF_SIZE;
+buf_size = MIN_BUF_SIZE;
 }
 
 if (rtl8139_cp_receiver_enabled(s))
@@ -996,6 +1044,37 @@ static ssize_t rtl8139_do_receive(VLANClientState *nc, 
const uint8_t *buf, size_
 
 uint32_t rx_space = rxdw0  CP_RX_BUFFER_SIZE_MASK;
 
+/* write VLAN info to descriptor variables.
+ * The logical packet is formed of:
+ * * buf[0..12[,
+ * * dot1q_buf (if offloading is enabled and tag is present or
+ *   dot1q_buf is passed in argument),
+ * * next_part[0..next_part_size[.
+ */
+next_part = buf[ETHER_ADDR_LEN * 2];
+if (s-CpCmd  CPlusRxVLAN  (dot1q_buf || be16_to_cpup((uint16_t *)
+next_part) == ETH_P_8021Q)) {
+if (!dot1q_buf) {
+/* the tag is in the buffer */
+dot1q_buf = next_part;
+next_part += VLAN_HLEN;
+}
+size -= VLAN_HLEN;
+
+rxdw1 = ~CP_RX_VLAN_TAG_MASK;
+/* BE + ~le_to_cpu()~ + cpu_to_le() = BE */
+rxdw1 |= CP_RX_TAVA | le16_to_cpup((uint16_t *)
+dot1q_buf[ETHER_TYPE_LEN]);
+
+DEBUG_PRINT((RTL8139

[Qemu-devel] [PATCH v5] rtl8139: add vlan support

2011-03-07 Thread Benjamin Poirier
Here is version 5 of my patchset to add vlan support to the emulated rtl8139
nic.

Changes since v4:
* removed alloca(), for real. Thanks to the reviewers for their
  patience. This patchset now has more versions than the vlan header
  has bytes!
* corrected the unlikely, debug printf and long lines, as per comments
* cleaned out ifdef's pertaining to ethernet checksum calculation.
  According to a comment since removed they were related to an
  optimization:
   RTL8139 provides frame CRC with received packet, this feature
   seems to be ignored by most drivers, disabled by default
  see commit ccf1d14

I've tested v5 using x86_64 host/guest with the usual procedure. I've also ran
the clang analyzer on the qemu code base, just for fun.

Changes since v3:
* removed alloca() and #include net/ethernet.h as per comments
* reordered patches to put extraction before insertion. Extraction
  touches only the receive path but insertion touches both. The two
  patches are now needed to have vlan functionnality.

I've tested v4 with x86_64 host/guest. I used the same testing procedure as
before. I've tested a plain configuration as well as one with tso + vlan
offload, successfully.

I had to hack around the Linux 8139cp driver to be able to enable tso on vlan
which leads me to wonder, can someone with access to the C+ spec or a real
card confirm that it can do tso and vlan offload at the same time? The patch
I used for the kernel is at https://gist.github.com/851895.

Changes since v2:
insertion:
* moved insertion later in the process, to handle tso
* use qemu_sendv_packet() to insert the tag for us
* added dot1q_buf parameter to rtl8139_do_receive() to avoid some
  memcpy() in loopback mode. Note that the code path through that
  function is unchanged when dot1q_buf is NULL.

extraction:
* reduced the amount of copying by moving the frame too short logic
  after the removal of the vlan tag (as is done in e1000.c for
  example). Unfortunately, that logic can no longer be shared betwen
  C+ and C mode.

I've posted v2 of these patches back in November
http://article.gmane.org/gmane.comp.emulators.qemu/84252

I've tested v3 on the following combinations of guest and hosts:
host: x86_64, guest: x86_64
host: x86_64, guest: ppc32
host: ppc32, guest: ppc32

Testing on the x86_64 host used '-net tap' and consisted of:
* making an http transfert on the untagged interface.
* ping -s 0-1472 to another host on a vlan.
* making an scp upload to another host on a vlan.

Testing on the ppc32 host used '-net socket' connected to an x86_64 qemu-kvm
running the virtio nic and consisted of:
* establishing an ssh connection between the two using an untagged interface.
* ping -s 0-1472 between the two using a vlan.
* making an scp transfer in both directions using a vlan.

All that was successful. Nevertheless, it doesn't exercise all code paths so
care is in order.

Please note that the lack of vlan support in rtl8139 has taken a few people
aback:
https://bugzilla.redhat.com/show_bug.cgi?id=516587
http://article.gmane.org/gmane.linux.network.general/14266

Thanks,
-Ben



[Qemu-devel] [PATCH v4] rtl8139: add vlan support

2011-03-02 Thread Benjamin Poirier
I've tested v4 with x86_64 host/guest. I used the same testing procedure as
before. I've tested a plain configuration as well as one with tso + vlan
offload, successfully.

I had to hack around the Linux 8139cp driver to be able to enable tso on vlan
which leads me to wonder, can someone with access to the C+ spec or a real
card confirm that it can do tso and vlan offload at the same time? The patch
I used for the kernel is at https://gist.github.com/851895.

Changes since v2:
insertion:
* moved insertion later in the process, to handle tso
* use qemu_sendv_packet() to insert the tag for us
* added dot1q_buf parameter to rtl8139_do_receive() to avoid some
  memcpy() in loopback mode. Note that the code path through that
  function is unchanged when dot1q_buf is NULL.

extraction:
* reduced the amount of copying by moving the frame too short logic
  after the removal of the vlan tag (as is done in e1000.c for
  example). Unfortunately, that logic can no longer be shared betwen
  C+ and C mode.

I've posted v2 of these patches back in November
http://article.gmane.org/gmane.comp.emulators.qemu/84252

I've tested v3 on the following combinations of guest and hosts:
host: x86_64, guest: x86_64
host: x86_64, guest: ppc32
host: ppc32, guest: ppc32

Testing on the x86_64 host used '-net tap' and consisted of:
* making an http transfert on the untagged interface.
* ping -s 0-1472 to another host on a vlan.
* making an scp upload to another host on a vlan.

Testing on the ppc32 host used '-net socket' connected to an x86_64 qemu-kvm
running the virtio nic and consisted of:
* establishing an ssh connection between the two using an untagged interface.
* ping -s 0-1472 between the two using a vlan.
* making an scp transfer in both directions using a vlan.

All that was successful. Nevertheless, it doesn't exercise all code paths so
care is in order.

Please note that the lack of vlan support in rtl8139 has taken a few people
aback:
https://bugzilla.redhat.com/show_bug.cgi?id=516587
http://article.gmane.org/gmane.linux.network.general/14266

Thanks,
-Ben



[Qemu-devel] [PATCH v4 2/2] rtl8139: add vlan tag insertion

2011-03-02 Thread Benjamin Poirier
Add support to the emulated hardware to insert vlan tags in packets
going from the guest to the network.

Signed-off-by: Benjamin Poirier benjamin.poir...@gmail.com
Cc: Igor V. Kovalenko igor.v.kovale...@gmail.com
Cc: Jason Wang jasow...@redhat.com
Cc: Michael S. Tsirkin m...@redhat.com
---
 hw/rtl8139.c |  102 ++
 1 files changed, 74 insertions(+), 28 deletions(-)

diff --git a/hw/rtl8139.c b/hw/rtl8139.c
index 6e770bd..0ea79e4 100644
--- a/hw/rtl8139.c
+++ b/hw/rtl8139.c
@@ -832,11 +832,14 @@ static int rtl8139_can_receive(VLANClientState *nc)
 }
 }
 
-static ssize_t rtl8139_do_receive(VLANClientState *nc, const uint8_t *buf, 
size_t size_, int do_interrupt)
+static ssize_t rtl8139_do_receive(VLANClientState *nc, const uint8_t *buf,
+size_t buf_size, int do_interrupt, const uint8_t *dot1q_buf)
 {
 RTL8139State *s = DO_UPCAST(NICState, nc, nc)-opaque;
+/* size_ is the total length of argument buffers */
+int size_ = buf_size + (dot1q_buf ? VLAN_HDR_LEN : 0);
+/* size is the length of the buffer passed to the driver */
 int size = size_;
-const uint8_t *dot1q_buf;
 const uint8_t *next_part;
 size_t next_part_size;
 
@@ -1018,10 +1021,13 @@ static ssize_t rtl8139_do_receive(VLANClientState *nc, 
const uint8_t *buf, size_
 /* next_part starts right after the vlan header (if any), at the
  * ethertype for the payload */
 next_part = buf[ETHER_ADDR_LEN * 2];
-if (s-CpCmd  CPlusRxVLAN  be16_to_cpup((uint16_t *)
-buf[ETHER_ADDR_LEN * 2]) == ETHERTYPE_VLAN) {
-dot1q_buf = buf[ETHER_ADDR_LEN * 2];
-next_part += VLAN_HDR_LEN;
+if (s-CpCmd  CPlusRxVLAN  (dot1q_buf || be16_to_cpup((uint16_t *)
+buf[ETHER_ADDR_LEN * 2]) == ETHERTYPE_VLAN)) {
+if (!dot1q_buf) {
+/* the tag is in the buffer */
+dot1q_buf = buf[ETHER_ADDR_LEN * 2];
+next_part += VLAN_HDR_LEN;
+}
 size -= VLAN_HDR_LEN;
 
 rxdw1 = ~CP_RX_VLAN_TAG_MASK;
@@ -1034,9 +1040,8 @@ static ssize_t rtl8139_do_receive(VLANClientState *nc, 
const uint8_t *buf, size_
 } else {
 /* reset VLAN tag flag */
 rxdw1 = ~CP_RX_TAVA;
-dot1q_buf = NULL;
 }
-next_part_size = buf + size_ - next_part;
+next_part_size = buf + buf_size - next_part;
 
 /* if too small buffer, then expand it */
 if (size  MIN_BUF_SIZE) {
@@ -1164,10 +1169,18 @@ static ssize_t rtl8139_do_receive(VLANClientState *nc, 
const uint8_t *buf, size_
 
 /* if too small buffer, then expand it */
 if (size  MIN_BUF_SIZE) {
-memcpy(buf1, buf, size);
+if (unlikely(dot1q_buf)) {
+memcpy(buf1, buf, 2 * ETHER_ADDR_LEN);
+memcpy(buf1 + 2 * ETHER_ADDR_LEN, dot1q_buf, VLAN_HDR_LEN);
+memcpy(buf1 + 2 * ETHER_ADDR_LEN + VLAN_HDR_LEN, buf + 2 *
+ETHER_ADDR_LEN, buf_size - 2 * ETHER_ADDR_LEN);
+} else {
+memcpy(buf1, buf, size);
+}
 memset(buf1 + size, 0, MIN_BUF_SIZE - size);
 buf = buf1;
 size = MIN_BUF_SIZE;
+dot1q_buf = NULL;
 }
 
 /* begin ring receiver mode */
@@ -1196,8 +1209,19 @@ static ssize_t rtl8139_do_receive(VLANClientState *nc, 
const uint8_t *buf, size_
 rtl8139_write_buffer(s, (uint8_t *)val, 4);
 
 /* receive/copy to target memory */
-rtl8139_write_buffer(s, buf, size);
-val = rtl8139_crc32(0, buf, size);
+if (unlikely(dot1q_buf)) {
+rtl8139_write_buffer(s, buf, 2 * ETHER_ADDR_LEN);
+val = rtl8139_crc32(0, buf, 2 * ETHER_ADDR_LEN);
+rtl8139_write_buffer(s, dot1q_buf, VLAN_HDR_LEN);
+val = rtl8139_crc32(val, dot1q_buf, VLAN_HDR_LEN);
+rtl8139_write_buffer(s, buf + 2 * ETHER_ADDR_LEN, buf_size - 2 *
+ETHER_ADDR_LEN);
+val = rtl8139_crc32(val, buf + 2 * ETHER_ADDR_LEN, buf_size - 2 *
+ETHER_ADDR_LEN);
+} else {
+rtl8139_write_buffer(s, buf, size);
+val = rtl8139_crc32(0, buf, size);
+}
 
 /* write checksum */
 #if defined (RTL8139_CALCULATE_RXCRC)
@@ -1227,7 +1251,7 @@ static ssize_t rtl8139_do_receive(VLANClientState *nc, 
const uint8_t *buf, size_
 
 static ssize_t rtl8139_receive(VLANClientState *nc, const uint8_t *buf, size_t 
size)
 {
-return rtl8139_do_receive(nc, buf, size, 1);
+return rtl8139_do_receive(nc, buf, size, 1, NULL);
 }
 
 static void rtl8139_reset_rxring(RTL8139State *s, uint32_t bufferSize)
@@ -1802,7 +1826,8 @@ static uint32_t rtl8139_RxConfig_read(RTL8139State *s)
 return ret;
 }
 
-static void rtl8139_transfer_frame(RTL8139State *s, const uint8_t *buf, int 
size, int do_interrupt)
+static void

[Qemu-devel] [PATCH v4 1/2] rtl8139: add vlan tag extraction

2011-03-02 Thread Benjamin Poirier
Add support to the emulated hardware to extract vlan tags in packets
going from the network to the guest.

Signed-off-by: Benjamin Poirier benjamin.poir...@gmail.com
Cc: Igor V. Kovalenko igor.v.kovale...@gmail.com
Cc: Jason Wang jasow...@redhat.com
Cc: Michael S. Tsirkin m...@redhat.com

--

AFAIK, extraction is optional to get vlans working. The driver
requests rx detagging but should not assume that it was done. Under
Linux, the mac layer will catch the vlan ethertype. I only added this
part for completeness (to emulate the hardware more truthfully...)
---
 hw/rtl8139.c |  100 +++---
 1 files changed, 81 insertions(+), 19 deletions(-)

diff --git a/hw/rtl8139.c b/hw/rtl8139.c
index a22530c..6e770bd 100644
--- a/hw/rtl8139.c
+++ b/hw/rtl8139.c
@@ -68,6 +68,16 @@
 #if defined(RTL8139_CALCULATE_RXCRC)
 /* For crc32 */
 #include zlib.h
+
+static inline uLong rtl8139_crc32(uLong crc, const Bytef *buf, uInt len)
+{
+return crc32(crc, buf, len);
+}
+#else
+static inline uLong rtl8139_crc32(uLong crc, const Bytef *buf, uInt len)
+{
+return 0;
+}
 #endif
 
 #define SET_MASKED(input, mask, curr) \
@@ -77,6 +87,14 @@
 #define MOD2(input, size) \
 ( ( input )  ( size - 1 )  )
 
+#define ETHER_ADDR_LEN 6
+#define ETHER_TYPE_LEN 2
+#define ETHER_HDR_LEN (ETHER_ADDR_LEN * 2 + ETHER_TYPE_LEN)
+#define ETHERTYPE_VLAN 0x8100
+
+#define VLAN_TCI_LEN 2
+#define VLAN_HDR_LEN (ETHER_TYPE_LEN + VLAN_TCI_LEN)
+
 #if defined (DEBUG_RTL8139)
 #  define DEBUG_PRINT(x) do { printf x ; } while (0)
 #else
@@ -818,10 +836,13 @@ static ssize_t rtl8139_do_receive(VLANClientState *nc, 
const uint8_t *buf, size_
 {
 RTL8139State *s = DO_UPCAST(NICState, nc, nc)-opaque;
 int size = size_;
+const uint8_t *dot1q_buf;
+const uint8_t *next_part;
+size_t next_part_size;
 
 uint32_t packet_header = 0;
 
-uint8_t buf1[60];
+uint8_t buf1[MIN_BUF_SIZE];
 static const uint8_t broadcast_macaddr[6] =
 { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
 
@@ -933,14 +954,6 @@ static ssize_t rtl8139_do_receive(VLANClientState *nc, 
const uint8_t *buf, size_
 }
 }
 
-/* if too small buffer, then expand it */
-if (size  MIN_BUF_SIZE) {
-memcpy(buf1, buf, size);
-memset(buf1 + size, 0, MIN_BUF_SIZE - size);
-buf = buf1;
-size = MIN_BUF_SIZE;
-}
-
 if (rtl8139_cp_receiver_enabled(s))
 {
 DEBUG_PRINT((RTL8139: in C+ Rx mode \n));
@@ -1001,6 +1014,41 @@ static ssize_t rtl8139_do_receive(VLANClientState *nc, 
const uint8_t *buf, size_
 
 uint32_t rx_space = rxdw0  CP_RX_BUFFER_SIZE_MASK;
 
+/* write VLAN info to descriptor variables */
+/* next_part starts right after the vlan header (if any), at the
+ * ethertype for the payload */
+next_part = buf[ETHER_ADDR_LEN * 2];
+if (s-CpCmd  CPlusRxVLAN  be16_to_cpup((uint16_t *)
+buf[ETHER_ADDR_LEN * 2]) == ETHERTYPE_VLAN) {
+dot1q_buf = buf[ETHER_ADDR_LEN * 2];
+next_part += VLAN_HDR_LEN;
+size -= VLAN_HDR_LEN;
+
+rxdw1 = ~CP_RX_VLAN_TAG_MASK;
+/* BE + ~le_to_cpu()~ + cpu_to_le() = BE */
+rxdw1 |= CP_RX_TAVA | le16_to_cpup((uint16_t *)
+buf[ETHER_HDR_LEN]);
+
+DEBUG_PRINT((RTL8139: C+ Rx mode : extracted vlan tag with tci: 
+%u\n, be16_to_cpup((uint16_t *) buf[ETHER_HDR_LEN])));
+} else {
+/* reset VLAN tag flag */
+rxdw1 = ~CP_RX_TAVA;
+dot1q_buf = NULL;
+}
+next_part_size = buf + size_ - next_part;
+
+/* if too small buffer, then expand it */
+if (size  MIN_BUF_SIZE) {
+size_t tmp_size = MIN_BUF_SIZE - ETHER_ADDR_LEN * 2;
+
+memcpy(buf1, next_part, next_part_size);
+memset(buf1 + next_part_size, 0, tmp_size - next_part_size);
+next_part = buf1;
+next_part_size = tmp_size;
+size = MIN_BUF_SIZE;
+}
+
 /* TODO: scatter the packet over available receive ring descriptors 
space */
 
 if (size+4  rx_space)
@@ -1022,7 +1070,18 @@ static ssize_t rtl8139_do_receive(VLANClientState *nc, 
const uint8_t *buf, size_
 target_phys_addr_t rx_addr = rtl8139_addr64(rxbufLO, rxbufHI);
 
 /* receive/copy to target memory */
-cpu_physical_memory_write( rx_addr, buf, size );
+if (unlikely(dot1q_buf)) {
+cpu_physical_memory_write(rx_addr, buf, 2 * ETHER_ADDR_LEN);
+val = rtl8139_crc32(0, buf, 2 * ETHER_ADDR_LEN);
+val = rtl8139_crc32(val, dot1q_buf, VLAN_HDR_LEN);
+cpu_physical_memory_write(rx_addr + 2 * ETHER_ADDR_LEN, next_part,
+next_part_size);
+val = rtl8139_crc32(val, buf + 2 * ETHER_ADDR_LEN,
+next_part_size);
+} else {
+cpu_physical_memory_write(rx_addr

[Qemu-devel] [PATCH v3] rtl8139: add vlan support

2011-02-25 Thread Benjamin Poirier
I've posted v2 of these patches back in november
http://article.gmane.org/gmane.comp.emulators.qemu/84252

Changes since v2:

insertion:
* moved insertion later in the process, to handle tso
* use qemu_sendv_packet() to insert the tag for us
* added dot1q_buf parameter to rtl8139_do_receive() to avoid some
  memcpy() in loopback mode. Note that the code path through that
  function is unchanged when dot1q_buf is NULL.

extraction:
* reduced the amount of copying by moving the frame too short logic
  after the removal of the vlan tag (as is done in e1000.c for
  example). Unfortunately, that logic can no longer be shared betwen
  C+ and C mode.

I've tested on the following combinations of guest and hosts:
host: x86_64, guest: x86_64
host: x86_64, guest: ppc32
host: ppc32, guest: ppc32

Testing on the x86_64 host used '-net tap' and consisted of:
* making an http transfert on the untagged interface.
* ping -s 0-1472 to another host on a vlan.
* making an scp upload to another host on a vlan.

Testing on the ppc32 host used '-net socket' connected to an x86_64 qemu-kvm
running the virtio nic and consisted of:
* establishing an ssh connection between the two using an untagged interface.
* ping -s 0-1472 to the ppc32 using a vlan.
* making an scp transfer in both directions using a vlan.

All that was successful. Nevertheless, it doesn't exercise all code paths so
care is in order.

Please note that the lack of vlan support in rtl8139 has taken a few people
aback:
https://bugzilla.redhat.com/show_bug.cgi?id=516587
http://article.gmane.org/gmane.linux.network.general/14266

Thanks,
-Ben



[Qemu-devel] [PATCH v3 1/2] rtl8139: add vlan tag insertion

2011-02-25 Thread Benjamin Poirier
Add support to the emulated hardware to insert vlan tags in packets
going from the guest to the network.

Signed-off-by: Benjamin Poirier benjamin.poir...@gmail.com
Cc: Igor V. Kovalenko igor.v.kovale...@gmail.com
Cc: Jason Wang jasow...@redhat.com
Cc: Michael S. Tsirkin m...@redhat.com
---
 hw/rtl8139.c |  123 +-
 1 files changed, 96 insertions(+), 27 deletions(-)

diff --git a/hw/rtl8139.c b/hw/rtl8139.c
index a22530c..35ccd3d 100644
--- a/hw/rtl8139.c
+++ b/hw/rtl8139.c
@@ -47,6 +47,8 @@
  *  Darwin)
  */
 
+#include net/ethernet.h
+
 #include hw.h
 #include pci.h
 #include qemu-timer.h
@@ -68,6 +70,16 @@
 #if defined(RTL8139_CALCULATE_RXCRC)
 /* For crc32 */
 #include zlib.h
+
+static inline uLong rtl8139_crc32(uLong crc, const Bytef *buf, uInt len)
+{
+return crc32(crc, buf, len);
+}
+#else
+static inline uLong rtl8139_crc32(uLong crc, const Bytef *buf, uInt len)
+{
+return 0;
+}
 #endif
 
 #define SET_MASKED(input, mask, curr) \
@@ -77,6 +89,9 @@
 #define MOD2(input, size) \
 ( ( input )  ( size - 1 )  )
 
+#define VLAN_TCI_LEN 2
+#define VLAN_HDR_LEN (ETHER_TYPE_LEN + VLAN_TCI_LEN)
+
 #if defined (DEBUG_RTL8139)
 #  define DEBUG_PRINT(x) do { printf x ; } while (0)
 #else
@@ -814,9 +829,11 @@ static int rtl8139_can_receive(VLANClientState *nc)
 }
 }
 
-static ssize_t rtl8139_do_receive(VLANClientState *nc, const uint8_t *buf, 
size_t size_, int do_interrupt)
+static ssize_t rtl8139_do_receive(VLANClientState *nc, const uint8_t *buf,
+size_t buf_size, int do_interrupt, const uint8_t *dot1q_buf)
 {
 RTL8139State *s = DO_UPCAST(NICState, nc, nc)-opaque;
+int size_ = buf_size + (dot1q_buf ? VLAN_HDR_LEN : 0);
 int size = size_;
 
 uint32_t packet_header = 0;
@@ -935,7 +952,14 @@ static ssize_t rtl8139_do_receive(VLANClientState *nc, 
const uint8_t *buf, size_
 
 /* if too small buffer, then expand it */
 if (size  MIN_BUF_SIZE) {
-memcpy(buf1, buf, size);
+if (unlikely(dot1q_buf)) {
+memcpy(buf1, buf, 2 * ETHER_ADDR_LEN);
+memcpy(buf1 + 2 * ETHER_ADDR_LEN, dot1q_buf, VLAN_HDR_LEN);
+memcpy(buf1 + 2 * ETHER_ADDR_LEN + VLAN_HDR_LEN, buf + 2 *
+ETHER_ADDR_LEN, buf_size - 2 * ETHER_ADDR_LEN);
+} else {
+memcpy(buf1, buf, size);
+}
 memset(buf1 + size, 0, MIN_BUF_SIZE - size);
 buf = buf1;
 size = MIN_BUF_SIZE;
@@ -1022,7 +1046,21 @@ static ssize_t rtl8139_do_receive(VLANClientState *nc, 
const uint8_t *buf, size_
 target_phys_addr_t rx_addr = rtl8139_addr64(rxbufLO, rxbufHI);
 
 /* receive/copy to target memory */
-cpu_physical_memory_write( rx_addr, buf, size );
+if (unlikely(dot1q_buf)) {
+cpu_physical_memory_write(rx_addr, buf, 2 * ETHER_ADDR_LEN);
+val = rtl8139_crc32(0, buf, 2 * ETHER_ADDR_LEN);
+cpu_physical_memory_write(rx_addr + 2 * ETHER_ADDR_LEN, dot1q_buf,
+VLAN_HDR_LEN);
+val = rtl8139_crc32(val, dot1q_buf, VLAN_HDR_LEN);
+cpu_physical_memory_write(rx_addr + 2 * ETHER_ADDR_LEN +
+VLAN_HDR_LEN, buf + 2 * ETHER_ADDR_LEN, buf_size - 2 *
+ETHER_ADDR_LEN);
+val = rtl8139_crc32(val, buf + 2 * ETHER_ADDR_LEN, buf_size - 2 *
+ETHER_ADDR_LEN);
+} else {
+cpu_physical_memory_write(rx_addr, buf, size);
+val = rtl8139_crc32(0, buf, size);
+}
 
 if (s-CpCmd  CPlusRxChkSum)
 {
@@ -1031,9 +1069,7 @@ static ssize_t rtl8139_do_receive(VLANClientState *nc, 
const uint8_t *buf, size_
 
 /* write checksum */
 #if defined (RTL8139_CALCULATE_RXCRC)
-val = cpu_to_le32(crc32(0, buf, size));
-#else
-val = 0;
+val = cpu_to_le32(val);
 #endif
 cpu_physical_memory_write( rx_addr+size, (uint8_t *)val, 4);
 
@@ -1133,13 +1169,24 @@ static ssize_t rtl8139_do_receive(VLANClientState *nc, 
const uint8_t *buf, size_
 
 rtl8139_write_buffer(s, (uint8_t *)val, 4);
 
-rtl8139_write_buffer(s, buf, size);
+/* receive/copy to target memory */
+if (unlikely(dot1q_buf)) {
+rtl8139_write_buffer(s, buf, 2 * ETHER_ADDR_LEN);
+val = rtl8139_crc32(0, buf, 2 * ETHER_ADDR_LEN);
+rtl8139_write_buffer(s, dot1q_buf, VLAN_HDR_LEN);
+val = rtl8139_crc32(val, dot1q_buf, VLAN_HDR_LEN);
+rtl8139_write_buffer(s, buf + 2 * ETHER_ADDR_LEN, buf_size - 2 *
+ETHER_ADDR_LEN);
+val = rtl8139_crc32(val, buf + 2 * ETHER_ADDR_LEN, buf_size - 2 *
+ETHER_ADDR_LEN);
+} else {
+rtl8139_write_buffer(s, buf, size);
+val = rtl8139_crc32(0, buf, size);
+}
 
 /* write checksum */
 #if defined (RTL8139_CALCULATE_RXCRC)
-val = cpu_to_le32(crc32(0, buf, size));
-#else

[Qemu-devel] [PATCH v3 2/2] rtl8139: add vlan tag extraction

2011-02-25 Thread Benjamin Poirier
Add support to the emulated hardware to extract vlan tags in packets
going from the network to the guest.

Signed-off-by: Benjamin Poirier benjamin.poir...@gmail.com
Cc: Igor V. Kovalenko igor.v.kovale...@gmail.com
Cc: Jason Wang jasow...@redhat.com
Cc: Michael S. Tsirkin m...@redhat.com

--

AFAIK, extraction is optional to get vlans working. The driver
requests rx detagging but should not assume that it was done. Under
Linux, the mac layer will catch the vlan ethertype. I only added this
part for completeness (to emulate the hardware more truthfully.)
---
 hw/rtl8139.c |   89 +-
 1 files changed, 63 insertions(+), 26 deletions(-)

diff --git a/hw/rtl8139.c b/hw/rtl8139.c
index 35ccd3d..f3aaebc 100644
--- a/hw/rtl8139.c
+++ b/hw/rtl8139.c
@@ -835,10 +835,11 @@ static ssize_t rtl8139_do_receive(VLANClientState *nc, 
const uint8_t *buf,
 RTL8139State *s = DO_UPCAST(NICState, nc, nc)-opaque;
 int size_ = buf_size + (dot1q_buf ? VLAN_HDR_LEN : 0);
 int size = size_;
+const uint8_t *next_part;
+size_t next_part_size;
 
 uint32_t packet_header = 0;
 
-uint8_t buf1[60];
 static const uint8_t broadcast_macaddr[6] =
 { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
 
@@ -950,21 +951,6 @@ static ssize_t rtl8139_do_receive(VLANClientState *nc, 
const uint8_t *buf,
 }
 }
 
-/* if too small buffer, then expand it */
-if (size  MIN_BUF_SIZE) {
-if (unlikely(dot1q_buf)) {
-memcpy(buf1, buf, 2 * ETHER_ADDR_LEN);
-memcpy(buf1 + 2 * ETHER_ADDR_LEN, dot1q_buf, VLAN_HDR_LEN);
-memcpy(buf1 + 2 * ETHER_ADDR_LEN + VLAN_HDR_LEN, buf + 2 *
-ETHER_ADDR_LEN, buf_size - 2 * ETHER_ADDR_LEN);
-} else {
-memcpy(buf1, buf, size);
-}
-memset(buf1 + size, 0, MIN_BUF_SIZE - size);
-buf = buf1;
-size = MIN_BUF_SIZE;
-}
-
 if (rtl8139_cp_receiver_enabled(s))
 {
 DEBUG_PRINT((RTL8139: in C+ Rx mode \n));
@@ -1025,6 +1011,44 @@ static ssize_t rtl8139_do_receive(VLANClientState *nc, 
const uint8_t *buf,
 
 uint32_t rx_space = rxdw0  CP_RX_BUFFER_SIZE_MASK;
 
+/* write VLAN info to descriptor variables */
+/* next_part starts right after the vlan header (if any), at the
+ * ethertype for the payload */
+next_part = buf[ETHER_ADDR_LEN * 2];
+if (s-CpCmd  CPlusRxVLAN  (dot1q_buf || be16_to_cpup((uint16_t *)
+buf[ETHER_ADDR_LEN * 2]) == ETHERTYPE_VLAN)) {
+if (!dot1q_buf) {
+/* the tag is in the buffer */
+dot1q_buf = buf[ETHER_ADDR_LEN * 2];
+next_part += VLAN_HDR_LEN;
+}
+size -= VLAN_HDR_LEN;
+
+rxdw1 = ~CP_RX_VLAN_TAG_MASK;
+/* BE + ~le_to_cpu()~ + cpu_to_le() = BE */
+rxdw1 |= CP_RX_TAVA | le16_to_cpup((uint16_t *)
+buf[ETHER_HDR_LEN]);
+
+DEBUG_PRINT((RTL8139: C+ Rx mode : extracted vlan tag with tci: 
+%u\n, be16_to_cpup((uint16_t *) buf[ETHER_HDR_LEN])));
+} else {
+/* reset VLAN tag flag */
+rxdw1 = ~CP_RX_TAVA;
+}
+next_part_size = buf + buf_size - next_part;
+
+/* if too small buffer, then expand it */
+if (size  MIN_BUF_SIZE) {
+size_t tmp_size = MIN_BUF_SIZE - ETHER_ADDR_LEN * 2;
+uint8_t *tmp = alloca(tmp_size);
+
+memcpy(tmp, next_part, next_part_size);
+memset(tmp + next_part_size, 0, tmp_size - next_part_size);
+next_part = tmp;
+next_part_size = tmp_size;
+size = MIN_BUF_SIZE;
+}
+
 /* TODO: scatter the packet over available receive ring descriptors 
space */
 
 if (size+4  rx_space)
@@ -1049,14 +1073,11 @@ static ssize_t rtl8139_do_receive(VLANClientState *nc, 
const uint8_t *buf,
 if (unlikely(dot1q_buf)) {
 cpu_physical_memory_write(rx_addr, buf, 2 * ETHER_ADDR_LEN);
 val = rtl8139_crc32(0, buf, 2 * ETHER_ADDR_LEN);
-cpu_physical_memory_write(rx_addr + 2 * ETHER_ADDR_LEN, dot1q_buf,
-VLAN_HDR_LEN);
 val = rtl8139_crc32(val, dot1q_buf, VLAN_HDR_LEN);
-cpu_physical_memory_write(rx_addr + 2 * ETHER_ADDR_LEN +
-VLAN_HDR_LEN, buf + 2 * ETHER_ADDR_LEN, buf_size - 2 *
-ETHER_ADDR_LEN);
-val = rtl8139_crc32(val, buf + 2 * ETHER_ADDR_LEN, buf_size - 2 *
-ETHER_ADDR_LEN);
+cpu_physical_memory_write(rx_addr + 2 * ETHER_ADDR_LEN, next_part,
+next_part_size);
+val = rtl8139_crc32(val, buf + 2 * ETHER_ADDR_LEN,
+next_part_size);
 } else {
 cpu_physical_memory_write(rx_addr, buf, size);
 val = rtl8139_crc32(0, buf, size);
@@ -1115,9 +1136,6 @@ static ssize_t

[Qemu-devel] [PATCH] net: Use iov helper functions

2011-02-23 Thread Benjamin Poirier
Signed-off-by: Benjamin Poirier benjamin.poir...@gmail.com
---
 net.c |   28 ++--
 1 files changed, 6 insertions(+), 22 deletions(-)

diff --git a/net.c b/net.c
index ec4745d..15ed40b 100644
--- a/net.c
+++ b/net.c
@@ -36,6 +36,7 @@
 #include qemu-common.h
 #include qemu_socket.h
 #include hw/qdev.h
+#include iov.h
 
 static QTAILQ_HEAD(, VLANState) vlans;
 static QTAILQ_HEAD(, VLANClientState) non_vlan_clients;
@@ -572,30 +573,13 @@ static ssize_t vc_sendv_compat(VLANClientState *vc, const 
struct iovec *iov,
int iovcnt)
 {
 uint8_t buffer[4096];
-size_t offset = 0;
-int i;
-
-for (i = 0; i  iovcnt; i++) {
-size_t len;
+size_t offset;
 
-len = MIN(sizeof(buffer) - offset, iov[i].iov_len);
-memcpy(buffer + offset, iov[i].iov_base, len);
-offset += len;
-}
+offset = iov_to_buf(iov, iovcnt, buffer, 0, sizeof(buffer));
 
 return vc-info-receive(vc, buffer, offset);
 }
 
-static ssize_t calc_iov_length(const struct iovec *iov, int iovcnt)
-{
-size_t offset = 0;
-int i;
-
-for (i = 0; i  iovcnt; i++)
-offset += iov[i].iov_len;
-return offset;
-}
-
 static ssize_t qemu_deliver_packet_iov(VLANClientState *sender,
unsigned flags,
const struct iovec *iov,
@@ -605,7 +589,7 @@ static ssize_t qemu_deliver_packet_iov(VLANClientState 
*sender,
 VLANClientState *vc = opaque;
 
 if (vc-link_down) {
-return calc_iov_length(iov, iovcnt);
+return iov_size(iov, iovcnt);
 }
 
 if (vc-info-receive_iov) {
@@ -633,7 +617,7 @@ static ssize_t qemu_vlan_deliver_packet_iov(VLANClientState 
*sender,
 }
 
 if (vc-link_down) {
-ret = calc_iov_length(iov, iovcnt);
+ret = iov_size(iov, iovcnt);
 continue;
 }
 
@@ -658,7 +642,7 @@ ssize_t qemu_sendv_packet_async(VLANClientState *sender,
 NetQueue *queue;
 
 if (sender-link_down || (!sender-peer  !sender-vlan)) {
-return calc_iov_length(iov, iovcnt);
+return iov_size(iov, iovcnt);
 }
 
 if (sender-peer) {
-- 
1.7.2.3




Re: [Qemu-devel] [PATCH v2 1/2] rtl8139: add vlan tag insertion

2010-11-16 Thread Benjamin Poirier
On 16/11/10 03:06 PM, Anthony Liguori wrote:
 On 11/08/2010 07:46 PM, Benjamin Poirier wrote:
 Add support to the emulated hardware to add vlan tags in packets going
 from the guest to the network.

 Signed-off-by: Benjamin Poirierbenjamin.poir...@polymtl.ca
 Cc: Igor V. Kovalenkoigor.v.kovale...@gmail.com
 ---
 Changes since v1:
 * moved the debug print statement inside the if block and reworded
accordingly. (as suggested by Igor)

   hw/rtl8139.c |   45 ++---
   1 files changed, 34 insertions(+), 11 deletions(-)

 diff --git a/hw/rtl8139.c b/hw/rtl8139.c
 index d92981d..b599945 100644
 --- a/hw/rtl8139.c
 +++ b/hw/rtl8139.c
 @@ -47,6 +47,8 @@
*  Darwin)
*/

 +#includenet/ethernet.h
 +
   #include hw.h
   #include pci.h
   #include qemu-timer.h
 @@ -58,6 +60,10 @@

   #define PCI_FREQUENCY 3300L

 +/* bytes in VLAN tag */
 +#define VLAN_TCI_LEN 2
 +#define VLAN_HDR_LEN (ETHER_TYPE_LEN + VLAN_TCI_LEN)
 +
   /* debug RTL8139 card C+ mode only */
   //#define DEBUG_RTL8139CP 1

 @@ -1913,7 +1919,6 @@ static int
 rtl8139_cplus_transmit_one(RTL8139State *s)

   cpu_physical_memory_read(cplus_tx_ring_desc,(uint8_t *)val,
 4);
   txdw0 = le32_to_cpu(val);
 -/* TODO: implement VLAN tagging support, VLAN tag data is read to
 txdw1 */
   cpu_physical_memory_read(cplus_tx_ring_desc+4,  (uint8_t *)val,
 4);
   txdw1 = le32_to_cpu(val);
   cpu_physical_memory_read(cplus_tx_ring_desc+8,  (uint8_t *)val,
 4);
 @@ -1925,9 +1930,6 @@ static int
 rtl8139_cplus_transmit_one(RTL8139State *s)
  descriptor,
  txdw0, txdw1, txbufLO, txbufHI));

 -/* TODO: the following discard cast should clean clang analyzer
 output */
 -(void)txdw1;
 -
   /* w0 ownership flag */
   #define CP_TX_OWN (131)
   /* w0 end of ring flag */
 @@ -1951,8 +1953,8 @@ static int
 rtl8139_cplus_transmit_one(RTL8139State *s)
   /* w0 bits 0...15 : buffer size */
   #define CP_TX_BUFFER_SIZE (116)
   #define CP_TX_BUFFER_SIZE_MASK (CP_TX_BUFFER_SIZE - 1)
 -/* w1 tag available flag */
 -#define CP_RX_TAGC (117)
 +/* w1 add tag flag */
 +#define CP_TX_TAGC (117)
   /* w1 bits 0...15 : VLAN tag */
   #define CP_TX_VLAN_TAG_MASK ((116) - 1)
   /* w2 low  32bit of Rx buffer ptr */
 @@ -1978,12 +1980,21 @@ static int
 rtl8139_cplus_transmit_one(RTL8139State *s)

   DEBUG_PRINT((RTL8139: +++ C+ Tx mode : transmitting from
 descriptor %d\n, descriptor));

 +int vlan_extra_size = 0;
   if (txdw0  CP_TX_FS)
   {
   DEBUG_PRINT((RTL8139: +++ C+ Tx mode : descriptor %d is
 first segment descriptor\n, descriptor));

   /* reset internal buffer offset */
   s-cplus_txbuffer_offset = 0;
 +
 +if (txdw1  CP_TX_TAGC)
 +{
 +vlan_extra_size = VLAN_HDR_LEN;
 +
 +DEBUG_PRINT((RTL8139: +++ C+ Tx mode : inserting vlan
 tag with 
 +tci: %u\n, bswap16(txdw1  CP_TX_VLAN_TAG_MASK)));
 +}
   }

   int txsize = txdw0  CP_TX_BUFFER_SIZE_MASK;
 @@ -1992,14 +2003,15 @@ static int
 rtl8139_cplus_transmit_one(RTL8139State *s)
   /* make sure we have enough space to assemble the packet */
   if (!s-cplus_txbuffer)
   {
 -s-cplus_txbuffer_len = CP_TX_BUFFER_SIZE;
 +s-cplus_txbuffer_len = CP_TX_BUFFER_SIZE + VLAN_HDR_LEN;
   s-cplus_txbuffer = qemu_malloc(s-cplus_txbuffer_len);
   s-cplus_txbuffer_offset = 0;

   DEBUG_PRINT((RTL8139: +++ C+ mode transmission buffer
 allocated space %d\n, s-cplus_txbuffer_len));
   }

 -while (s-cplus_txbuffer  s-cplus_txbuffer_offset + txsize=
 s-cplus_txbuffer_len)
 +while (s-cplus_txbuffer  s-cplus_txbuffer_offset + txsize +
 +vlan_extra_size= s-cplus_txbuffer_len)
   {
   s-cplus_txbuffer_len += CP_TX_BUFFER_SIZE;
   s-cplus_txbuffer = qemu_realloc(s-cplus_txbuffer,
 s-cplus_txbuffer_len);
 @@ -2025,6 +2037,20 @@ static int
 rtl8139_cplus_transmit_one(RTL8139State *s)
   DEBUG_PRINT((RTL8139: +++ C+ mode transmit reading %d bytes
 from host memory at %016 PRIx64  to offset %d\n,
txsize, (uint64_t)tx_addr, s-cplus_txbuffer_offset));

 +if (vlan_extra_size  txsize= 2 * ETHER_ADDR_LEN)
 +{
 +/* copy addresses */
 +cpu_physical_memory_read(tx_addr, s-cplus_txbuffer, 2 *
 +ETHER_ADDR_LEN);
 +tx_addr += 2 * ETHER_ADDR_LEN;
 +txsize -= 2 * ETHER_ADDR_LEN;
 +/* insert vlan tag */
 +*(uint16_t *)(s-cplus_txbuffer + 2 * ETHER_ADDR_LEN) =
 +cpu_to_be16(ETHERTYPE_VLAN);
 +*(uint16_t *)(s-cplus_txbuffer + 2 * ETHER_ADDR_LEN +
 ETHER_TYPE_LEN)
 += cpu_to_le16(txdw1  CP_TX_VLAN_TAG_MASK);

 
 This looks wrong.  You check for txsize = 2 * ETHER_ADDR_LEN but then
 you assign at 2 * ETHER_ADDR_LEN.  This is a potential overflow, no?
 

No, the check is to protect the read. Concerning the writes

Re: [Qemu-devel] [PATCH 1/2] rtl8139: add vlan tag insertion

2010-11-08 Thread Benjamin Poirier
On 08/11/10 11:34 AM, Stefan Hajnoczi wrote:
 On Sun, Nov 7, 2010 at 9:25 PM, Benjamin Poirier
 benjamin.poir...@polymtl.ca wrote:
 Add support to the emulated hardware to add vlan tags in packets going
 from the guest to the network.

 Signed-off-by: Benjamin Poirier benjamin.poir...@polymtl.ca
 Cc: Igor V. Kovalenko igor.v.kovale...@gmail.com
 ---
  hw/rtl8139.c |   46 +++---
  1 files changed, 35 insertions(+), 11 deletions(-)

 diff --git a/hw/rtl8139.c b/hw/rtl8139.c
 index d92981d..ac294da 100644
 --- a/hw/rtl8139.c
 +++ b/hw/rtl8139.c
 @@ -47,6 +47,8 @@
  *  Darwin)
  */

 +#include net/ethernet.h
 +
  #include hw.h
  #include pci.h
  #include qemu-timer.h
 @@ -58,6 +60,10 @@

  #define PCI_FREQUENCY 3300L

 +/* bytes in VLAN tag */
 +#define VLAN_TCI_LEN 2
 +#define VLAN_HDR_LEN (ETHER_TYPE_LEN + VLAN_TCI_LEN)
 +
  /* debug RTL8139 card C+ mode only */
  //#define DEBUG_RTL8139CP 1

 @@ -1913,7 +1919,6 @@ static int rtl8139_cplus_transmit_one(RTL8139State *s)

 cpu_physical_memory_read(cplus_tx_ring_desc,(uint8_t *)val, 4);
 txdw0 = le32_to_cpu(val);
 -/* TODO: implement VLAN tagging support, VLAN tag data is read to txdw1 
 */
 cpu_physical_memory_read(cplus_tx_ring_desc+4,  (uint8_t *)val, 4);
 txdw1 = le32_to_cpu(val);
 cpu_physical_memory_read(cplus_tx_ring_desc+8,  (uint8_t *)val, 4);
 @@ -1925,9 +1930,6 @@ static int rtl8139_cplus_transmit_one(RTL8139State *s)
descriptor,
txdw0, txdw1, txbufLO, txbufHI));

 -/* TODO: the following discard cast should clean clang analyzer output 
 */
 -(void)txdw1;
 -
  /* w0 ownership flag */
  #define CP_TX_OWN (131)
  /* w0 end of ring flag */
 @@ -1951,8 +1953,8 @@ static int rtl8139_cplus_transmit_one(RTL8139State *s)
  /* w0 bits 0...15 : buffer size */
  #define CP_TX_BUFFER_SIZE (116)
  #define CP_TX_BUFFER_SIZE_MASK (CP_TX_BUFFER_SIZE - 1)
 -/* w1 tag available flag */
 -#define CP_RX_TAGC (117)
 +/* w1 add tag flag */
 +#define CP_TX_TAGC (117)
  /* w1 bits 0...15 : VLAN tag */
  #define CP_TX_VLAN_TAG_MASK ((116) - 1)
  /* w2 low  32bit of Rx buffer ptr */
 @@ -1978,12 +1980,22 @@ static int rtl8139_cplus_transmit_one(RTL8139State 
 *s)

 DEBUG_PRINT((RTL8139: +++ C+ Tx mode : transmitting from descriptor 
 %d\n, descriptor));

 +int vlan_extra_size = 0;
 if (txdw0  CP_TX_FS)
 {
 DEBUG_PRINT((RTL8139: +++ C+ Tx mode : descriptor %d is first 
 segment descriptor\n, descriptor));

 +DEBUG_PRINT((RTL8139: +++ C+ Tx mode : add vlan tag: %u tci: %u\n,
 +!!(txdw1  CP_TX_TAGC), bswap16(txdw1 
 +CP_TX_VLAN_TAG_MASK)));
 
 Please use leXX_to_cpu() and cpu_to_leXX() instead of bswapXX() for
 little-endian conversion.  This is more explicit than unconditional
 byteswapping and work on both big- and little-endian QEMU host
 architectures.

I believe the use of flat out swapping is warranted here. The data has
been adjusted for host-endianness when the register was read:
txdw1 = le32_to_cpu(val);
We have to mask and swap to accomodate the format used by the card's
registers, which is always the same regardless of machine endianness.

txdw1 is extracted from a 32 bit register like such (when the descriptor
specifies tx tagging), in increasing address order:
tci8-15 tci0-7 0x01 0x00

-Ben

 
 Stefan
 




[Qemu-devel] [PATCH v2 1/2] rtl8139: add vlan tag insertion

2010-11-08 Thread Benjamin Poirier
Add support to the emulated hardware to add vlan tags in packets going
from the guest to the network.

Signed-off-by: Benjamin Poirier benjamin.poir...@polymtl.ca
Cc: Igor V. Kovalenko igor.v.kovale...@gmail.com
---
Changes since v1:
* moved the debug print statement inside the if block and reworded
  accordingly. (as suggested by Igor)

 hw/rtl8139.c |   45 ++---
 1 files changed, 34 insertions(+), 11 deletions(-)

diff --git a/hw/rtl8139.c b/hw/rtl8139.c
index d92981d..b599945 100644
--- a/hw/rtl8139.c
+++ b/hw/rtl8139.c
@@ -47,6 +47,8 @@
  *  Darwin)
  */
 
+#include net/ethernet.h
+
 #include hw.h
 #include pci.h
 #include qemu-timer.h
@@ -58,6 +60,10 @@
 
 #define PCI_FREQUENCY 3300L
 
+/* bytes in VLAN tag */
+#define VLAN_TCI_LEN 2
+#define VLAN_HDR_LEN (ETHER_TYPE_LEN + VLAN_TCI_LEN)
+
 /* debug RTL8139 card C+ mode only */
 //#define DEBUG_RTL8139CP 1
 
@@ -1913,7 +1919,6 @@ static int rtl8139_cplus_transmit_one(RTL8139State *s)
 
 cpu_physical_memory_read(cplus_tx_ring_desc,(uint8_t *)val, 4);
 txdw0 = le32_to_cpu(val);
-/* TODO: implement VLAN tagging support, VLAN tag data is read to txdw1 */
 cpu_physical_memory_read(cplus_tx_ring_desc+4,  (uint8_t *)val, 4);
 txdw1 = le32_to_cpu(val);
 cpu_physical_memory_read(cplus_tx_ring_desc+8,  (uint8_t *)val, 4);
@@ -1925,9 +1930,6 @@ static int rtl8139_cplus_transmit_one(RTL8139State *s)
descriptor,
txdw0, txdw1, txbufLO, txbufHI));
 
-/* TODO: the following discard cast should clean clang analyzer output */
-(void)txdw1;
-
 /* w0 ownership flag */
 #define CP_TX_OWN (131)
 /* w0 end of ring flag */
@@ -1951,8 +1953,8 @@ static int rtl8139_cplus_transmit_one(RTL8139State *s)
 /* w0 bits 0...15 : buffer size */
 #define CP_TX_BUFFER_SIZE (116)
 #define CP_TX_BUFFER_SIZE_MASK (CP_TX_BUFFER_SIZE - 1)
-/* w1 tag available flag */
-#define CP_RX_TAGC (117)
+/* w1 add tag flag */
+#define CP_TX_TAGC (117)
 /* w1 bits 0...15 : VLAN tag */
 #define CP_TX_VLAN_TAG_MASK ((116) - 1)
 /* w2 low  32bit of Rx buffer ptr */
@@ -1978,12 +1980,21 @@ static int rtl8139_cplus_transmit_one(RTL8139State *s)
 
 DEBUG_PRINT((RTL8139: +++ C+ Tx mode : transmitting from descriptor 
%d\n, descriptor));
 
+int vlan_extra_size = 0;
 if (txdw0  CP_TX_FS)
 {
 DEBUG_PRINT((RTL8139: +++ C+ Tx mode : descriptor %d is first segment 
descriptor\n, descriptor));
 
 /* reset internal buffer offset */
 s-cplus_txbuffer_offset = 0;
+
+if (txdw1  CP_TX_TAGC)
+{
+vlan_extra_size = VLAN_HDR_LEN;
+
+DEBUG_PRINT((RTL8139: +++ C+ Tx mode : inserting vlan tag with 
+tci: %u\n, bswap16(txdw1  CP_TX_VLAN_TAG_MASK)));
+}
 }
 
 int txsize = txdw0  CP_TX_BUFFER_SIZE_MASK;
@@ -1992,14 +2003,15 @@ static int rtl8139_cplus_transmit_one(RTL8139State *s)
 /* make sure we have enough space to assemble the packet */
 if (!s-cplus_txbuffer)
 {
-s-cplus_txbuffer_len = CP_TX_BUFFER_SIZE;
+s-cplus_txbuffer_len = CP_TX_BUFFER_SIZE + VLAN_HDR_LEN;
 s-cplus_txbuffer = qemu_malloc(s-cplus_txbuffer_len);
 s-cplus_txbuffer_offset = 0;
 
 DEBUG_PRINT((RTL8139: +++ C+ mode transmission buffer allocated space 
%d\n, s-cplus_txbuffer_len));
 }
 
-while (s-cplus_txbuffer  s-cplus_txbuffer_offset + txsize = 
s-cplus_txbuffer_len)
+while (s-cplus_txbuffer  s-cplus_txbuffer_offset + txsize +
+vlan_extra_size = s-cplus_txbuffer_len)
 {
 s-cplus_txbuffer_len += CP_TX_BUFFER_SIZE;
 s-cplus_txbuffer = qemu_realloc(s-cplus_txbuffer, 
s-cplus_txbuffer_len);
@@ -2025,6 +2037,20 @@ static int rtl8139_cplus_transmit_one(RTL8139State *s)
 DEBUG_PRINT((RTL8139: +++ C+ mode transmit reading %d bytes from host 
memory at %016 PRIx64  to offset %d\n,
  txsize, (uint64_t)tx_addr, s-cplus_txbuffer_offset));
 
+if (vlan_extra_size  txsize = 2 * ETHER_ADDR_LEN)
+{
+/* copy addresses */
+cpu_physical_memory_read(tx_addr, s-cplus_txbuffer, 2 *
+ETHER_ADDR_LEN);
+tx_addr += 2 * ETHER_ADDR_LEN;
+txsize -= 2 * ETHER_ADDR_LEN;
+/* insert vlan tag */
+*(uint16_t *)(s-cplus_txbuffer + 2 * ETHER_ADDR_LEN) =
+cpu_to_be16(ETHERTYPE_VLAN);
+*(uint16_t *)(s-cplus_txbuffer + 2 * ETHER_ADDR_LEN + ETHER_TYPE_LEN)
+= cpu_to_le16(txdw1  CP_TX_VLAN_TAG_MASK);
+s-cplus_txbuffer_offset += 2 * ETHER_ADDR_LEN + VLAN_HDR_LEN;
+}
 cpu_physical_memory_read(tx_addr, s-cplus_txbuffer + 
s-cplus_txbuffer_offset, txsize);
 s-cplus_txbuffer_offset += txsize;
 
@@ -2053,9 +2079,6 @@ static int rtl8139_cplus_transmit_one(RTL8139State *s)
 /* update ring data */
 val = cpu_to_le32(txdw0);
 cpu_physical_memory_write(cplus_tx_ring_desc,(uint8_t *)val, 4);
-/* TODO: implement VLAN

[Qemu-devel] [PATCH v2 2/2] rtl8139: add vlan tag extraction

2010-11-08 Thread Benjamin Poirier
Add support to the emulated hardware to remove vlan tags in packets
going from the network to the guest.

Signed-off-by: Benjamin Poirier benjamin.poir...@polymtl.ca
Cc: Igor V. Kovalenko igor.v.kovale...@gmail.com

---
Changes since v1:
* moved the debug print statement inside the if block and reworded
  accordingly. (as suggested by Igor)

AFAIK, extraction is optional to get vlans working. The driver
requests rx detagging but should not assume that it was done. Under
Linux, the mac layer will catch the vlan ethertype. I only added this
part for completeness (to emulate the hardware more truthfully..?).

 hw/rtl8139.c |   40 +---
 1 files changed, 37 insertions(+), 3 deletions(-)

diff --git a/hw/rtl8139.c b/hw/rtl8139.c
index b599945..7762dbb 100644
--- a/hw/rtl8139.c
+++ b/hw/rtl8139.c
@@ -1024,6 +1024,43 @@ static ssize_t rtl8139_do_receive(VLANClientState *nc, 
const uint8_t *buf, size_
 
 target_phys_addr_t rx_addr = rtl8139_addr64(rxbufLO, rxbufHI);
 
+if (s-CpCmd  CPlusRxVLAN  size = ETHER_ADDR_LEN * 2 +
+VLAN_HDR_LEN  be16_to_cpup((uint16_t *) buf[ETHER_ADDR_LEN *
+2]) == ETHERTYPE_VLAN)
+{
+size_t new_size = size - VLAN_HDR_LEN;
+
+rxdw1 = ~CP_RX_VLAN_TAG_MASK;
+rxdw1 |= CP_RX_TAVA |
+le16_to_cpup((uint16_t *)buf[ETHER_HDR_LEN]);
+
+if (buf == buf1 || new_size  MIN_BUF_SIZE)
+{
+/* move the end and pad */
+memmove((uint8_t *)buf + ETHER_ADDR_LEN * 2, buf +
+ETHER_ADDR_LEN * 2 + VLAN_HDR_LEN, new_size -
+ETHER_ADDR_LEN * 2);
+memset((uint8_t *)buf + new_size, 0, MIN_BUF_SIZE - new_size);
+size = MIN_BUF_SIZE;
+}
+else
+{
+/* move the beginning */
+memmove((uint8_t *)buf + VLAN_HDR_LEN, buf, ETHER_ADDR_LEN *
+2);
+buf += VLAN_HDR_LEN;
+size = new_size;
+}
+
+DEBUG_PRINT((RTL8139: C+ Rx mode : extracted vlan tag with tci: 
+%u\n, bswap16(rxdw1  CP_RX_VLAN_TAG_MASK)));
+}
+else
+{
+/* reset VLAN tag flag */
+rxdw1 = ~CP_RX_TAVA;
+}
+
 /* receive/copy to target memory */
 cpu_physical_memory_write( rx_addr, buf, size );
 
@@ -1082,9 +1119,6 @@ static ssize_t rtl8139_do_receive(VLANClientState *nc, 
const uint8_t *buf, size_
 rxdw0 = ~CP_RX_BUFFER_SIZE_MASK;
 rxdw0 |= (size+4);
 
-/* reset VLAN tag flag */
-rxdw1 = ~CP_RX_TAVA;
-
 /* update ring data */
 val = cpu_to_le32(rxdw0);
 cpu_physical_memory_write(cplus_rx_ring_desc,(uint8_t *)val, 4);
-- 
1.7.2.3




[Qemu-devel] [PATCH 1/2] rtl8139: add vlan tag insertion

2010-11-07 Thread Benjamin Poirier
Add support to the emulated hardware to add vlan tags in packets going
from the guest to the network.

Signed-off-by: Benjamin Poirier benjamin.poir...@polymtl.ca
Cc: Igor V. Kovalenko igor.v.kovale...@gmail.com
---
 hw/rtl8139.c |   46 +++---
 1 files changed, 35 insertions(+), 11 deletions(-)

diff --git a/hw/rtl8139.c b/hw/rtl8139.c
index d92981d..ac294da 100644
--- a/hw/rtl8139.c
+++ b/hw/rtl8139.c
@@ -47,6 +47,8 @@
  *  Darwin)
  */
 
+#include net/ethernet.h
+
 #include hw.h
 #include pci.h
 #include qemu-timer.h
@@ -58,6 +60,10 @@
 
 #define PCI_FREQUENCY 3300L
 
+/* bytes in VLAN tag */
+#define VLAN_TCI_LEN 2
+#define VLAN_HDR_LEN (ETHER_TYPE_LEN + VLAN_TCI_LEN)
+
 /* debug RTL8139 card C+ mode only */
 //#define DEBUG_RTL8139CP 1
 
@@ -1913,7 +1919,6 @@ static int rtl8139_cplus_transmit_one(RTL8139State *s)
 
 cpu_physical_memory_read(cplus_tx_ring_desc,(uint8_t *)val, 4);
 txdw0 = le32_to_cpu(val);
-/* TODO: implement VLAN tagging support, VLAN tag data is read to txdw1 */
 cpu_physical_memory_read(cplus_tx_ring_desc+4,  (uint8_t *)val, 4);
 txdw1 = le32_to_cpu(val);
 cpu_physical_memory_read(cplus_tx_ring_desc+8,  (uint8_t *)val, 4);
@@ -1925,9 +1930,6 @@ static int rtl8139_cplus_transmit_one(RTL8139State *s)
descriptor,
txdw0, txdw1, txbufLO, txbufHI));
 
-/* TODO: the following discard cast should clean clang analyzer output */
-(void)txdw1;
-
 /* w0 ownership flag */
 #define CP_TX_OWN (131)
 /* w0 end of ring flag */
@@ -1951,8 +1953,8 @@ static int rtl8139_cplus_transmit_one(RTL8139State *s)
 /* w0 bits 0...15 : buffer size */
 #define CP_TX_BUFFER_SIZE (116)
 #define CP_TX_BUFFER_SIZE_MASK (CP_TX_BUFFER_SIZE - 1)
-/* w1 tag available flag */
-#define CP_RX_TAGC (117)
+/* w1 add tag flag */
+#define CP_TX_TAGC (117)
 /* w1 bits 0...15 : VLAN tag */
 #define CP_TX_VLAN_TAG_MASK ((116) - 1)
 /* w2 low  32bit of Rx buffer ptr */
@@ -1978,12 +1980,22 @@ static int rtl8139_cplus_transmit_one(RTL8139State *s)
 
 DEBUG_PRINT((RTL8139: +++ C+ Tx mode : transmitting from descriptor 
%d\n, descriptor));
 
+int vlan_extra_size = 0;
 if (txdw0  CP_TX_FS)
 {
 DEBUG_PRINT((RTL8139: +++ C+ Tx mode : descriptor %d is first segment 
descriptor\n, descriptor));
 
+DEBUG_PRINT((RTL8139: +++ C+ Tx mode : add vlan tag: %u tci: %u\n,
+!!(txdw1  CP_TX_TAGC), bswap16(txdw1 
+CP_TX_VLAN_TAG_MASK)));
+
 /* reset internal buffer offset */
 s-cplus_txbuffer_offset = 0;
+
+if (txdw1  CP_TX_TAGC)
+{
+vlan_extra_size = VLAN_HDR_LEN;
+}
 }
 
 int txsize = txdw0  CP_TX_BUFFER_SIZE_MASK;
@@ -1992,14 +2004,15 @@ static int rtl8139_cplus_transmit_one(RTL8139State *s)
 /* make sure we have enough space to assemble the packet */
 if (!s-cplus_txbuffer)
 {
-s-cplus_txbuffer_len = CP_TX_BUFFER_SIZE;
+s-cplus_txbuffer_len = CP_TX_BUFFER_SIZE + VLAN_HDR_LEN;
 s-cplus_txbuffer = qemu_malloc(s-cplus_txbuffer_len);
 s-cplus_txbuffer_offset = 0;
 
 DEBUG_PRINT((RTL8139: +++ C+ mode transmission buffer allocated space 
%d\n, s-cplus_txbuffer_len));
 }
 
-while (s-cplus_txbuffer  s-cplus_txbuffer_offset + txsize = 
s-cplus_txbuffer_len)
+while (s-cplus_txbuffer  s-cplus_txbuffer_offset + txsize +
+vlan_extra_size = s-cplus_txbuffer_len)
 {
 s-cplus_txbuffer_len += CP_TX_BUFFER_SIZE;
 s-cplus_txbuffer = qemu_realloc(s-cplus_txbuffer, 
s-cplus_txbuffer_len);
@@ -2025,6 +2038,20 @@ static int rtl8139_cplus_transmit_one(RTL8139State *s)
 DEBUG_PRINT((RTL8139: +++ C+ mode transmit reading %d bytes from host 
memory at %016 PRIx64  to offset %d\n,
  txsize, (uint64_t)tx_addr, s-cplus_txbuffer_offset));
 
+if (vlan_extra_size  txsize = 2 * ETHER_ADDR_LEN)
+{
+/* copy addresses */
+cpu_physical_memory_read(tx_addr, s-cplus_txbuffer, 2 *
+ETHER_ADDR_LEN);
+tx_addr += 2 * ETHER_ADDR_LEN;
+txsize -= 2 * ETHER_ADDR_LEN;
+/* insert vlan tag */
+*(uint16_t *)(s-cplus_txbuffer + 2 * ETHER_ADDR_LEN) =
+cpu_to_be16(ETHERTYPE_VLAN);
+*(uint16_t *)(s-cplus_txbuffer + 2 * ETHER_ADDR_LEN + ETHER_TYPE_LEN)
+= cpu_to_le16(txdw1  CP_TX_VLAN_TAG_MASK);
+s-cplus_txbuffer_offset += 2 * ETHER_ADDR_LEN + VLAN_HDR_LEN;
+}
 cpu_physical_memory_read(tx_addr, s-cplus_txbuffer + 
s-cplus_txbuffer_offset, txsize);
 s-cplus_txbuffer_offset += txsize;
 
@@ -2053,9 +2080,6 @@ static int rtl8139_cplus_transmit_one(RTL8139State *s)
 /* update ring data */
 val = cpu_to_le32(txdw0);
 cpu_physical_memory_write(cplus_tx_ring_desc,(uint8_t *)val, 4);
-/* TODO: implement VLAN tagging support, VLAN tag data is read to txdw1 */
-//val = cpu_to_le32(txdw1

[Qemu-devel] [PATCH 2/2] rtl8139: add vlan tag extraction

2010-11-07 Thread Benjamin Poirier
Add support to the emulated hardware to remove vlan tags in packets
going from the network to the guest.

Signed-off-by: Benjamin Poirier benjamin.poir...@polymtl.ca
Cc: Igor V. Kovalenko igor.v.kovale...@gmail.com

--

AFAIK, extraction is optional to get vlans working. The driver
requests rx detagging but should not assume that it was done. Under
Linux, the mac layer will catch the vlan ethertype. I only added this
part for completeness (to emulate the hardware more truthfully..?).
---
 hw/rtl8139.c |   41 ++---
 1 files changed, 38 insertions(+), 3 deletions(-)

diff --git a/hw/rtl8139.c b/hw/rtl8139.c
index ac294da..557a460 100644
--- a/hw/rtl8139.c
+++ b/hw/rtl8139.c
@@ -1024,6 +1024,44 @@ static ssize_t rtl8139_do_receive(VLANClientState *nc, 
const uint8_t *buf, size_
 
 target_phys_addr_t rx_addr = rtl8139_addr64(rxbufLO, rxbufHI);
 
+if (s-CpCmd  CPlusRxVLAN  size = ETHER_ADDR_LEN * 2 +
+VLAN_HDR_LEN  be16_to_cpup((uint16_t *) buf[ETHER_ADDR_LEN *
+2]) == ETHERTYPE_VLAN)
+{
+size_t new_size = size - VLAN_HDR_LEN;
+
+rxdw1 = ~CP_RX_VLAN_TAG_MASK;
+rxdw1 |= CP_RX_TAVA |
+le16_to_cpup((uint16_t *)buf[ETHER_HDR_LEN]);
+
+if (buf == buf1 || new_size  MIN_BUF_SIZE)
+{
+/* move the end and pad */
+memmove((uint8_t *)buf + ETHER_ADDR_LEN * 2, buf +
+ETHER_ADDR_LEN * 2 + VLAN_HDR_LEN, new_size -
+ETHER_ADDR_LEN * 2);
+memset((uint8_t *)buf + new_size, 0, MIN_BUF_SIZE - new_size);
+size = MIN_BUF_SIZE;
+}
+else
+{
+/* move the beginning */
+memmove((uint8_t *)buf + VLAN_HDR_LEN, buf, ETHER_ADDR_LEN *
+2);
+buf += VLAN_HDR_LEN;
+size = new_size;
+}
+}
+else
+{
+/* reset VLAN tag flag */
+rxdw1 = ~CP_RX_TAVA;
+}
+
+DEBUG_PRINT((RTL8139: C+ Rx mode : removed vlan tag: %u tci: %u\n,
+!!(rxdw1  CP_RX_TAVA), bswap16(rxdw1 
+CP_RX_VLAN_TAG_MASK)));
+
 /* receive/copy to target memory */
 cpu_physical_memory_write( rx_addr, buf, size );
 
@@ -1082,9 +1120,6 @@ static ssize_t rtl8139_do_receive(VLANClientState *nc, 
const uint8_t *buf, size_
 rxdw0 = ~CP_RX_BUFFER_SIZE_MASK;
 rxdw0 |= (size+4);
 
-/* reset VLAN tag flag */
-rxdw1 = ~CP_RX_TAVA;
-
 /* update ring data */
 val = cpu_to_le32(rxdw0);
 cpu_physical_memory_write(cplus_rx_ring_desc,(uint8_t *)val, 4);
-- 
1.7.2.3