Re: [Qemu-devel] [PATCH v7 12/17] net_pkt: Extend packet abstraction as required by e1000e functionality
> On 1 Jun 2016, at 07:25 AM, Jason Wangwrote: > > > > 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
On 2016年05月31日 15:20, Dmitry Fleytman wrote: From: Dmitry FleytmanThis 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
From: Dmitry FleytmanThis 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); -