Re: [Qemu-devel] [PATCH v7 12/17] net_pkt: Extend packet abstraction as required by e1000e functionality

2016-06-01 Thread Dmitry Fleytman

> On 1 Jun 2016, at 07:25 AM, Jason Wang  wrote:
> 
> 
> 
> On 2016年05月31日 15:20, Dmitry Fleytman wrote:
>> From: Dmitry Fleytman 
>> 
>> This patch extends the TX/RX packet abstractions with features that will
>> be used by the e1000e device implementation.
>> 
>> Changes are:
>> 
>>   1. Support iovec lists for RX buffers
>>   2. Deeper RX packets parsing
>>   3. Loopback option for TX packets
>>   4. Extended VLAN headers handling
>>   5. RSS processing for RX packets
>> 
>> Signed-off-by: Dmitry Fleytman 
>> Signed-off-by: Leonid Bloch 
>> ---
>>  hw/net/net_rx_pkt.c| 473 
>> +
>>  hw/net/net_rx_pkt.h| 193 +++-
>>  hw/net/net_tx_pkt.c| 204 +
>>  hw/net/net_tx_pkt.h|  60 ++-
>>  include/net/checksum.h |   4 +-
>>  include/net/eth.h  | 153 +++-
>>  net/checksum.c |   7 +-
>>  net/eth.c  | 410 +-
>>  trace-events   |  40 +
>>  9 files changed, 1336 insertions(+), 208 deletions(-)
> 
> [...]
> 
>>  struct udp_hdr {
>>uint16_t uh_sport;   /* source port */
>>uint16_t uh_dport;   /* destination port */
>> @@ -169,19 +194,22 @@ struct tcp_hdr {
>>  #define PKT_GET_IP_HDR(p) \
>>  ((struct ip_header *)(((uint8_t *)(p)) + eth_get_l2_hdr_length(p)))
>>  #define IP_HDR_GET_LEN(p) \
>> -struct ip_header *)p)->ip_ver_len & 0x0F) << 2)
>> +struct ip_header *)(p))->ip_ver_len & 0x0F) << 2)
>>  #define PKT_GET_IP_HDR_LEN(p) \
>>  (IP_HDR_GET_LEN(PKT_GET_IP_HDR(p)))
>>  #define PKT_GET_IP6_HDR(p)\
>>  ((struct ip6_header *) (((uint8_t *)(p)) + eth_get_l2_hdr_length(p)))
>>  #define IP_HEADER_VERSION(ip) \
>> -((ip->ip_ver_len >> 4)&0xf)
>> +(((ip)->ip_ver_len >> 4) & 0xf)
>> +#define IP4_IS_FRAGMENT(ip) \
>> +((be16_to_cpu((ip)->ip_off) & (IP_OFFMASK | IP_MF)) != 0)
>>#define ETH_P_IP  (0x0800)  /* Internet Protocol 
>> packet  */
>>  #define ETH_P_ARP (0x0806)  /* Address Resolution 
>> packet */
>>  #define ETH_P_IPV6(0x86dd)
>>  #define ETH_P_VLAN(0x8100)
>>  #define ETH_P_DVLAN   (0x88a8)
>> +#define ETH_P_UNKNOWN (0x)
>>  #define VLAN_VID_MASK 0x0fff
>>  #define IP_HEADER_VERSION_4   (4)
>>  #define IP_HEADER_VERSION_6   (6)
>> @@ -258,15 +286,25 @@ get_eth_packet_type(const struct eth_header *ehdr)
>>  }
>>static inline uint32_t
>> -eth_get_l2_hdr_length(const void *p)
>> +eth_get_l2_hdr_length(const struct iovec *iov, int iovcnt)
>>  {
> 
> Looks like this changes breaks the above PKT_GET_IP_HDR and PKT_GET_IP6_HDR. 
> This will be a problem e.g ENET series depends on this.
> 
> A solution is keeping current eth_get_l2_hdr_length() and call it in a new 
> helper e.g eth_get_l2_hdr_length_iov().

Right, sending fixed series.
Thanks!

> 
>> -uint16_t proto = be16_to_cpu(PKT_GET_ETH_HDR(p)->h_proto);
>> -struct vlan_header *hvlan = PKT_GET_VLAN_HDR(p);
>> +uint8_t p[sizeof(struct eth_header) + sizeof(struct vlan_header)];
>> +size_t copied = iov_to_buf(iov, iovcnt, 0, p, ARRAY_SIZE(p));
>> +uint16_t proto;
>> +struct vlan_header *hvlan;
>> +
>> +if (copied < ARRAY_SIZE(p)) {
>> +return copied;
>> +}
>> +
>> +proto = be16_to_cpu(PKT_GET_ETH_HDR(p)->h_proto);
>> +hvlan = PKT_GET_VLAN_HDR(p);
>> +
>>  switch (proto) {
>>  case ETH_P_VLAN:
>>  return sizeof(struct eth_header) + sizeof(struct vlan_header);
>>  case ETH_P_DVLAN:
>> -if (hvlan->h_proto == ETH_P_VLAN) {
>> +if (be16_to_cpu(hvlan->h_proto) == ETH_P_VLAN) {
>>  return sizeof(struct eth_header) + 2 * sizeof(struct 
>> vlan_header);
>>  } else {
>>  return sizeof(struct eth_header) + sizeof(struct vlan_header);
>> @@ -290,51 +328,67 @@ eth_get_pkt_tci(const void *p)
>>  }
>>  }
>>  
> 
> [...]




Re: [Qemu-devel] [PATCH v7 12/17] net_pkt: Extend packet abstraction as required by e1000e functionality

2016-05-31 Thread Jason Wang



On 2016年05月31日 15:20, Dmitry Fleytman wrote:

From: Dmitry Fleytman 

This patch extends the TX/RX packet abstractions with features that will
be used by the e1000e device implementation.

Changes are:

   1. Support iovec lists for RX buffers
   2. Deeper RX packets parsing
   3. Loopback option for TX packets
   4. Extended VLAN headers handling
   5. RSS processing for RX packets

Signed-off-by: Dmitry Fleytman 
Signed-off-by: Leonid Bloch 
---
  hw/net/net_rx_pkt.c| 473 +
  hw/net/net_rx_pkt.h| 193 +++-
  hw/net/net_tx_pkt.c| 204 +
  hw/net/net_tx_pkt.h|  60 ++-
  include/net/checksum.h |   4 +-
  include/net/eth.h  | 153 +++-
  net/checksum.c |   7 +-
  net/eth.c  | 410 +-
  trace-events   |  40 +
  9 files changed, 1336 insertions(+), 208 deletions(-)


[...]


  struct udp_hdr {
uint16_t uh_sport;   /* source port */
uint16_t uh_dport;   /* destination port */
@@ -169,19 +194,22 @@ struct tcp_hdr {
  #define PKT_GET_IP_HDR(p) \
  ((struct ip_header *)(((uint8_t *)(p)) + eth_get_l2_hdr_length(p)))
  #define IP_HDR_GET_LEN(p) \
-struct ip_header *)p)->ip_ver_len & 0x0F) << 2)
+struct ip_header *)(p))->ip_ver_len & 0x0F) << 2)
  #define PKT_GET_IP_HDR_LEN(p) \
  (IP_HDR_GET_LEN(PKT_GET_IP_HDR(p)))
  #define PKT_GET_IP6_HDR(p)\
  ((struct ip6_header *) (((uint8_t *)(p)) + eth_get_l2_hdr_length(p)))
  #define IP_HEADER_VERSION(ip) \
-((ip->ip_ver_len >> 4)&0xf)
+(((ip)->ip_ver_len >> 4) & 0xf)
+#define IP4_IS_FRAGMENT(ip) \
+((be16_to_cpu((ip)->ip_off) & (IP_OFFMASK | IP_MF)) != 0)
  
  #define ETH_P_IP  (0x0800)  /* Internet Protocol packet  */

  #define ETH_P_ARP (0x0806)  /* Address Resolution packet 
*/
  #define ETH_P_IPV6(0x86dd)
  #define ETH_P_VLAN(0x8100)
  #define ETH_P_DVLAN   (0x88a8)
+#define ETH_P_UNKNOWN (0x)
  #define VLAN_VID_MASK 0x0fff
  #define IP_HEADER_VERSION_4   (4)
  #define IP_HEADER_VERSION_6   (6)
@@ -258,15 +286,25 @@ get_eth_packet_type(const struct eth_header *ehdr)
  }
  
  static inline uint32_t

-eth_get_l2_hdr_length(const void *p)
+eth_get_l2_hdr_length(const struct iovec *iov, int iovcnt)
  {


Looks like this changes breaks the above PKT_GET_IP_HDR and 
PKT_GET_IP6_HDR. This will be a problem e.g ENET series depends on this.


A solution is keeping current eth_get_l2_hdr_length() and call it in a 
new helper e.g eth_get_l2_hdr_length_iov().



-uint16_t proto = be16_to_cpu(PKT_GET_ETH_HDR(p)->h_proto);
-struct vlan_header *hvlan = PKT_GET_VLAN_HDR(p);
+uint8_t p[sizeof(struct eth_header) + sizeof(struct vlan_header)];
+size_t copied = iov_to_buf(iov, iovcnt, 0, p, ARRAY_SIZE(p));
+uint16_t proto;
+struct vlan_header *hvlan;
+
+if (copied < ARRAY_SIZE(p)) {
+return copied;
+}
+
+proto = be16_to_cpu(PKT_GET_ETH_HDR(p)->h_proto);
+hvlan = PKT_GET_VLAN_HDR(p);
+
  switch (proto) {
  case ETH_P_VLAN:
  return sizeof(struct eth_header) + sizeof(struct vlan_header);
  case ETH_P_DVLAN:
-if (hvlan->h_proto == ETH_P_VLAN) {
+if (be16_to_cpu(hvlan->h_proto) == ETH_P_VLAN) {
  return sizeof(struct eth_header) + 2 * sizeof(struct vlan_header);
  } else {
  return sizeof(struct eth_header) + sizeof(struct vlan_header);
@@ -290,51 +328,67 @@ eth_get_pkt_tci(const void *p)
  }
  }
  


[...]



[Qemu-devel] [PATCH v7 12/17] net_pkt: Extend packet abstraction as required by e1000e functionality

2016-05-31 Thread Dmitry Fleytman
From: Dmitry Fleytman 

This patch extends the TX/RX packet abstractions with features that will
be used by the e1000e device implementation.

Changes are:

  1. Support iovec lists for RX buffers
  2. Deeper RX packets parsing
  3. Loopback option for TX packets
  4. Extended VLAN headers handling
  5. RSS processing for RX packets

Signed-off-by: Dmitry Fleytman 
Signed-off-by: Leonid Bloch 
---
 hw/net/net_rx_pkt.c| 473 +
 hw/net/net_rx_pkt.h| 193 +++-
 hw/net/net_tx_pkt.c| 204 +
 hw/net/net_tx_pkt.h|  60 ++-
 include/net/checksum.h |   4 +-
 include/net/eth.h  | 153 +++-
 net/checksum.c |   7 +-
 net/eth.c  | 410 +-
 trace-events   |  40 +
 9 files changed, 1336 insertions(+), 208 deletions(-)

diff --git a/hw/net/net_rx_pkt.c b/hw/net/net_rx_pkt.c
index 8a4f29f..1019b50 100644
--- a/hw/net/net_rx_pkt.c
+++ b/hw/net/net_rx_pkt.c
@@ -16,24 +16,16 @@
  */
 
 #include "qemu/osdep.h"
+#include "trace.h"
 #include "net_rx_pkt.h"
-#include "net/eth.h"
-#include "qemu-common.h"
-#include "qemu/iov.h"
 #include "net/checksum.h"
 #include "net/tap.h"
 
-/*
- * RX packet may contain up to 2 fragments - rebuilt eth header
- * in case of VLAN tag stripping
- * and payload received from QEMU - in any case
- */
-#define NET_MAX_RX_PACKET_FRAGMENTS (2)
-
 struct NetRxPkt {
 struct virtio_net_hdr virt_hdr;
-uint8_t ehdr_buf[ETH_MAX_L2_HDR_LEN];
-struct iovec vec[NET_MAX_RX_PACKET_FRAGMENTS];
+uint8_t ehdr_buf[sizeof(struct eth_header)];
+struct iovec *vec;
+uint16_t vec_len_total;
 uint16_t vec_len;
 uint32_t tot_len;
 uint16_t tci;
@@ -46,17 +38,31 @@ struct NetRxPkt {
 bool isip6;
 bool isudp;
 bool istcp;
+
+size_t l3hdr_off;
+size_t l4hdr_off;
+size_t l5hdr_off;
+
+eth_ip6_hdr_info ip6hdr_info;
+eth_ip4_hdr_info ip4hdr_info;
+eth_l4_hdr_info  l4hdr_info;
 };
 
 void net_rx_pkt_init(struct NetRxPkt **pkt, bool has_virt_hdr)
 {
 struct NetRxPkt *p = g_malloc0(sizeof *p);
 p->has_virt_hdr = has_virt_hdr;
+p->vec = NULL;
+p->vec_len_total = 0;
 *pkt = p;
 }
 
 void net_rx_pkt_uninit(struct NetRxPkt *pkt)
 {
+if (pkt->vec_len_total != 0) {
+g_free(pkt->vec);
+}
+
 g_free(pkt);
 }
 
@@ -66,33 +72,88 @@ struct virtio_net_hdr *net_rx_pkt_get_vhdr(struct NetRxPkt 
*pkt)
 return >virt_hdr;
 }
 
-void net_rx_pkt_attach_data(struct NetRxPkt *pkt, const void *data,
-   size_t len, bool strip_vlan)
+static inline void
+net_rx_pkt_iovec_realloc(struct NetRxPkt *pkt,
+int new_iov_len)
+{
+if (pkt->vec_len_total < new_iov_len) {
+g_free(pkt->vec);
+pkt->vec = g_malloc(sizeof(*pkt->vec) * new_iov_len);
+pkt->vec_len_total = new_iov_len;
+}
+}
+
+static void
+net_rx_pkt_pull_data(struct NetRxPkt *pkt,
+const struct iovec *iov, int iovcnt,
+size_t ploff)
+{
+if (pkt->vlan_stripped) {
+net_rx_pkt_iovec_realloc(pkt, iovcnt + 1);
+
+pkt->vec[0].iov_base = pkt->ehdr_buf;
+pkt->vec[0].iov_len = sizeof(pkt->ehdr_buf);
+
+pkt->tot_len =
+iov_size(iov, iovcnt) - ploff + sizeof(struct eth_header);
+
+pkt->vec_len = iov_copy(pkt->vec + 1, pkt->vec_len_total - 1,
+iov, iovcnt, ploff, pkt->tot_len);
+} else {
+net_rx_pkt_iovec_realloc(pkt, iovcnt);
+
+pkt->tot_len = iov_size(iov, iovcnt) - ploff;
+pkt->vec_len = iov_copy(pkt->vec, pkt->vec_len_total,
+iov, iovcnt, ploff, pkt->tot_len);
+}
+
+eth_get_protocols(pkt->vec, pkt->vec_len, >isip4, >isip6,
+  >isudp, >istcp,
+  >l3hdr_off, >l4hdr_off, >l5hdr_off,
+  >ip6hdr_info, >ip4hdr_info, >l4hdr_info);
+
+trace_net_rx_pkt_parsed(pkt->isip4, pkt->isip6, pkt->isudp, pkt->istcp,
+pkt->l3hdr_off, pkt->l4hdr_off, pkt->l5hdr_off);
+}
+
+void net_rx_pkt_attach_iovec(struct NetRxPkt *pkt,
+const struct iovec *iov, int iovcnt,
+size_t iovoff, bool strip_vlan)
 {
 uint16_t tci = 0;
-uint16_t ploff;
+uint16_t ploff = iovoff;
 assert(pkt);
 pkt->vlan_stripped = false;
 
 if (strip_vlan) {
-pkt->vlan_stripped = eth_strip_vlan(data, pkt->ehdr_buf, , );
+pkt->vlan_stripped = eth_strip_vlan(iov, iovcnt, iovoff, pkt->ehdr_buf,
+, );
 }
 
-if (pkt->vlan_stripped) {
-pkt->vec[0].iov_base = pkt->ehdr_buf;
-pkt->vec[0].iov_len = ploff - sizeof(struct vlan_header);
-