Hi!This updated patch against current CVS implements TCP segmentation offloading for RTL8139 in C+ mode.I fixed a couple of problems in implementation (wrong sequence number calculation), and now TCP performance seem to be normal.
Dependency on slirp.h header is now gone.Again tested with linux (ethtool -K eth0 tx on sg on tso on); please apply.--Kind Regards,Igor V. Kovalenko
Index: hw/rtl8139.c
===
RCS file: /cvsroot/qemu/qemu/hw/rtl8139.c,v
retrieving revision 1.3
diff -u -r1.3 rtl8139.c
--- hw/rtl8139.c 4 Jul 2006 10:08:36 - 1.3
+++ hw/rtl8139.c 9 Jul 2006 09:14:00 -
@@ -33,13 +33,17 @@
* Implemented PCI timer interrupt (disabled by default)
* Implemented Tally Counters, increased VM load/save version
* Implemented IP/TCP/UDP checksum task offloading
+ *
+ * 2006-Jul-04 Igor Kovalenko : Implemented TCP segmentation offloading
+ * Fixed MTU=1500 for produced ethernet frames
+ *
+ * 2006-Jul-09 Igor Kovalenko : Fixed TCP header length calculation while processing
+ * segmentation offloading
+ * Removed slirp.h dependency
*/
#include vl.h
-/* XXX: such dependency must be suppressed */
-#include slirp/slirp.h
-
/* debug RTL8139 card */
//#define DEBUG_RTL8139 1
@@ -1732,6 +1736,25 @@
return ret;
}
+static void rtl8139_transfer_frame(RTL8139State *s, const uint8_t *buf, int size, int do_interrupt)
+{
+if (!size)
+{
+DEBUG_PRINT((RTL8139: +++ empty ethernet frame\n));
+return;
+}
+
+if (TxLoopBack == (s-TxConfig TxLoopBack))
+{
+DEBUG_PRINT((RTL8139: +++ transmit loopback mode\n));
+rtl8139_do_receive(s, buf, size, do_interrupt);
+}
+else
+{
+qemu_send_packet(s-vc, buf, size);
+}
+}
+
static int rtl8139_transmit_one(RTL8139State *s, int descriptor)
{
if (!rtl8139_transmitter_enabled(s))
@@ -1762,15 +1785,7 @@
s-TxStatus[descriptor] |= TxHostOwns;
s-TxStatus[descriptor] |= TxStatOK;
-if (TxLoopBack == (s-TxConfig TxLoopBack))
-{
-DEBUG_PRINT((RTL8139: +++ transmit loopback mode\n));
-rtl8139_do_receive(s, txbuffer, txsize, 0);
-}
-else
-{
-qemu_send_packet(s-vc, txbuffer, txsize);
-}
+rtl8139_transfer_frame(s, txbuffer, txsize, 0);
DEBUG_PRINT((RTL8139: +++ transmitted %d bytes from descriptor %d\n, txsize, descriptor));
@@ -1781,6 +1796,93 @@
return 1;
}
+/* structures and macros for task offloading */
+typedef struct ip_header
+{
+uint8_t ip_ver_len;/* version and header length */
+uint8_t ip_tos;/* type of service */
+uint16_t ip_len;/* total length */
+uint16_t ip_id; /* identification */
+uint16_t ip_off;/* fragment offset field */
+uint8_t ip_ttl;/* time to live */
+uint8_t ip_p; /* protocol */
+uint16_t ip_sum;/* checksum */
+uint32_t ip_src,ip_dst; /* source and dest address */
+} ip_header;
+
+#define IP_HEADER_VERSION_4 4
+#define IP_HEADER_VERSION(ip) ((ip-ip_ver_len 4)0xf)
+#define IP_HEADER_LENGTH(ip) (((ip-ip_ver_len)0xf) 2)
+
+typedef struct tcp_header
+{
+uint16_t th_sport; /* source port */
+uint16_t th_dport; /* destination port */
+uint32_t th_seq; /* sequence number */
+uint32_t th_ack; /* acknowledgement number */
+uint16_t th_offset_flags; /* data offset, reserved 6 bits, TCP protocol flags */
+uint16_t th_win; /* window */
+uint16_t th_sum; /* checksum */
+uint16_t th_urp; /* urgent pointer */
+} tcp_header;
+
+typedef struct udp_header
+{
+uint16_t uh_sport; /* source port */
+uint16_t uh_dport; /* destination port */
+uint16_t uh_ulen; /* udp length */
+uint16_t uh_sum; /* udp checksum */
+} udp_header;
+
+typedef struct ip_pseudo_header
+{
+uint32_t ip_src;
+uint32_t ip_dst;
+uint8_t zeros;
+uint8_t ip_proto;
+uint16_t ip_payload;
+} ip_pseudo_header;
+
+#define IP_PROTO_TCP 6
+#define IP_PROTO_UDP 17
+
+#define TCP_HEADER_DATA_OFFSET(tcp) (((be16_to_cpu(tcp-th_offset_flags) 12)0xf) 2)
+#define TCP_FLAGS_ONLY(flags) ((flags)0x3f)
+#define TCP_HEADER_FLAGS(tcp) TCP_FLAGS_ONLY(be16_to_cpu(tcp-th_offset_flags))
+
+#define TCP_HEADER_CLEAR_FLAGS(tcp, off) ((tcp)-th_offset_flags = cpu_to_be16(~TCP_FLAGS_ONLY(off)))
+
+#define TCP_FLAG_FIN 0x01
+#define TCP_FLAG_PUSH 0x08
+
+/* produces ones' complement sum of data */
+static uint16_t ones_complement_sum(uint8_t *data, size_t len)
+{
+uint32_t result = 0;
+
+for (; len 1; data+=2, len-=2)
+{
+result += *(uint16_t*)data;
+}
+
+/* add the remainder byte */
+if (len)
+{
+uint8_t odd[2] = {*data, 0};
+result += *(uint16_t*)odd;
+}
+
+