From 163246e1ce9607251ed52df1131af25d608de782 Mon Sep 17 00:00:00 2001 From: Akihiko Odaki Date: Tue, 23 May 2023 11:42:52 +0900 Subject: hw/net/net_tx_pkt: Decouple implementation from PCI This is intended to be followed by another change for the interface. It also fixes the leak of memory mapping when the specified memory is partially mapped. Fixes: e263cd49c7 ("Packet abstraction for VMWARE network devices") Signed-off-by: Akihiko Odaki Signed-off-by: Jason Wang --- hw/net/net_tx_pkt.c | 53 +++++++++++++++++++++++++++++++++-------------------- 1 file changed, 33 insertions(+), 20 deletions(-) (limited to 'hw/net/net_tx_pkt.c') diff --git a/hw/net/net_tx_pkt.c b/hw/net/net_tx_pkt.c index 8dc8568ba2..aca12ff035 100644 --- a/hw/net/net_tx_pkt.c +++ b/hw/net/net_tx_pkt.c @@ -384,10 +384,9 @@ void net_tx_pkt_setup_vlan_header_ex(struct NetTxPkt *pkt, } } -bool net_tx_pkt_add_raw_fragment(struct NetTxPkt *pkt, hwaddr pa, - size_t len) +static bool net_tx_pkt_add_raw_fragment_common(struct NetTxPkt *pkt, + void *base, size_t len) { - hwaddr mapped_len = 0; struct iovec *ventry; assert(pkt); @@ -395,23 +394,12 @@ bool net_tx_pkt_add_raw_fragment(struct NetTxPkt *pkt, hwaddr pa, return false; } - if (!len) { - return true; - } - ventry = &pkt->raw[pkt->raw_frags]; - mapped_len = len; + ventry->iov_base = base; + ventry->iov_len = len; + pkt->raw_frags++; - ventry->iov_base = pci_dma_map(pkt->pci_dev, pa, - &mapped_len, DMA_DIRECTION_TO_DEVICE); - - if ((ventry->iov_base != NULL) && (len == mapped_len)) { - ventry->iov_len = mapped_len; - pkt->raw_frags++; - return true; - } else { - return false; - } + return true; } bool net_tx_pkt_has_fragments(struct NetTxPkt *pkt) @@ -465,8 +453,9 @@ void net_tx_pkt_reset(struct NetTxPkt *pkt, PCIDevice *pci_dev) assert(pkt->raw); for (i = 0; i < pkt->raw_frags; i++) { assert(pkt->raw[i].iov_base); - pci_dma_unmap(pkt->pci_dev, pkt->raw[i].iov_base, - pkt->raw[i].iov_len, DMA_DIRECTION_TO_DEVICE, 0); + net_tx_pkt_unmap_frag_pci(pkt->pci_dev, + pkt->raw[i].iov_base, + pkt->raw[i].iov_len); } } pkt->pci_dev = pci_dev; @@ -476,6 +465,30 @@ void net_tx_pkt_reset(struct NetTxPkt *pkt, PCIDevice *pci_dev) pkt->l4proto = 0; } +void net_tx_pkt_unmap_frag_pci(void *context, void *base, size_t len) +{ + pci_dma_unmap(context, base, len, DMA_DIRECTION_TO_DEVICE, 0); +} + +bool net_tx_pkt_add_raw_fragment(struct NetTxPkt *pkt, hwaddr pa, + size_t len) +{ + dma_addr_t mapped_len = len; + void *base = pci_dma_map(pkt->pci_dev, pa, &mapped_len, + DMA_DIRECTION_TO_DEVICE); + if (!base) { + return false; + } + + if (mapped_len != len || + !net_tx_pkt_add_raw_fragment_common(pkt, base, len)) { + net_tx_pkt_unmap_frag_pci(pkt->pci_dev, base, mapped_len); + return false; + } + + return true; +} + static void net_tx_pkt_do_sw_csum(struct NetTxPkt *pkt, struct iovec *iov, uint32_t iov_len, uint16_t csl) -- cgit 1.4.1 From a51db5802744b274ab40385dd9fe8354722fcc4d Mon Sep 17 00:00:00 2001 From: Akihiko Odaki Date: Tue, 23 May 2023 11:42:53 +0900 Subject: hw/net/net_tx_pkt: Decouple interface from PCI This allows to use the network packet abstractions even if PCI is not used. Signed-off-by: Akihiko Odaki Signed-off-by: Jason Wang --- hw/net/e1000e_core.c | 13 ++++++++----- hw/net/igb_core.c | 13 ++++++------- hw/net/net_tx_pkt.c | 36 +++++++++++++----------------------- hw/net/net_tx_pkt.h | 31 ++++++++++++++++++++----------- hw/net/vmxnet3.c | 14 +++++++------- 5 files changed, 54 insertions(+), 53 deletions(-) (limited to 'hw/net/net_tx_pkt.c') diff --git a/hw/net/e1000e_core.c b/hw/net/e1000e_core.c index cfa3f55e96..15821a75e0 100644 --- a/hw/net/e1000e_core.c +++ b/hw/net/e1000e_core.c @@ -746,7 +746,8 @@ e1000e_process_tx_desc(E1000ECore *core, addr = le64_to_cpu(dp->buffer_addr); if (!tx->skip_cp) { - if (!net_tx_pkt_add_raw_fragment(tx->tx_pkt, addr, split_size)) { + if (!net_tx_pkt_add_raw_fragment_pci(tx->tx_pkt, core->owner, + addr, split_size)) { tx->skip_cp = true; } } @@ -764,7 +765,7 @@ e1000e_process_tx_desc(E1000ECore *core, } tx->skip_cp = false; - net_tx_pkt_reset(tx->tx_pkt, core->owner); + net_tx_pkt_reset(tx->tx_pkt, net_tx_pkt_unmap_frag_pci, core->owner); tx->sum_needed = 0; tx->cptse = 0; @@ -3421,7 +3422,7 @@ e1000e_core_pci_realize(E1000ECore *core, qemu_add_vm_change_state_handler(e1000e_vm_state_change, core); for (i = 0; i < E1000E_NUM_QUEUES; i++) { - net_tx_pkt_init(&core->tx[i].tx_pkt, core->owner, E1000E_MAX_TX_FRAGS); + net_tx_pkt_init(&core->tx[i].tx_pkt, E1000E_MAX_TX_FRAGS); } net_rx_pkt_init(&core->rx_pkt); @@ -3446,7 +3447,8 @@ e1000e_core_pci_uninit(E1000ECore *core) qemu_del_vm_change_state_handler(core->vmstate); for (i = 0; i < E1000E_NUM_QUEUES; i++) { - net_tx_pkt_reset(core->tx[i].tx_pkt, core->owner); + net_tx_pkt_reset(core->tx[i].tx_pkt, + net_tx_pkt_unmap_frag_pci, core->owner); net_tx_pkt_uninit(core->tx[i].tx_pkt); } @@ -3571,7 +3573,8 @@ static void e1000e_reset(E1000ECore *core, bool sw) e1000x_reset_mac_addr(core->owner_nic, core->mac, core->permanent_mac); for (i = 0; i < ARRAY_SIZE(core->tx); i++) { - net_tx_pkt_reset(core->tx[i].tx_pkt, core->owner); + net_tx_pkt_reset(core->tx[i].tx_pkt, + net_tx_pkt_unmap_frag_pci, core->owner); memset(&core->tx[i].props, 0, sizeof(core->tx[i].props)); core->tx[i].skip_cp = false; } diff --git a/hw/net/igb_core.c b/hw/net/igb_core.c index 826e7a6cf1..abfdce9aaf 100644 --- a/hw/net/igb_core.c +++ b/hw/net/igb_core.c @@ -597,7 +597,8 @@ igb_process_tx_desc(IGBCore *core, length = cmd_type_len & 0xFFFF; if (!tx->skip_cp) { - if (!net_tx_pkt_add_raw_fragment(tx->tx_pkt, buffer_addr, length)) { + if (!net_tx_pkt_add_raw_fragment_pci(tx->tx_pkt, dev, + buffer_addr, length)) { tx->skip_cp = true; } } @@ -616,7 +617,7 @@ igb_process_tx_desc(IGBCore *core, tx->first = true; tx->skip_cp = false; - net_tx_pkt_reset(tx->tx_pkt, dev); + net_tx_pkt_reset(tx->tx_pkt, net_tx_pkt_unmap_frag_pci, dev); } } @@ -842,8 +843,6 @@ igb_start_xmit(IGBCore *core, const IGB_TxRing *txr) d = core->owner; } - net_tx_pkt_reset(txr->tx->tx_pkt, d); - while (!igb_ring_empty(core, txi)) { base = igb_ring_head_descr(core, txi); @@ -861,6 +860,8 @@ igb_start_xmit(IGBCore *core, const IGB_TxRing *txr) core->mac[EICR] |= eic; igb_set_interrupt_cause(core, E1000_ICR_TXDW); } + + net_tx_pkt_reset(txr->tx->tx_pkt, net_tx_pkt_unmap_frag_pci, d); } static uint32_t @@ -3954,7 +3955,7 @@ igb_core_pci_realize(IGBCore *core, core->vmstate = qemu_add_vm_change_state_handler(igb_vm_state_change, core); for (i = 0; i < IGB_NUM_QUEUES; i++) { - net_tx_pkt_init(&core->tx[i].tx_pkt, NULL, E1000E_MAX_TX_FRAGS); + net_tx_pkt_init(&core->tx[i].tx_pkt, E1000E_MAX_TX_FRAGS); } net_rx_pkt_init(&core->rx_pkt); @@ -3979,7 +3980,6 @@ igb_core_pci_uninit(IGBCore *core) qemu_del_vm_change_state_handler(core->vmstate); for (i = 0; i < IGB_NUM_QUEUES; i++) { - net_tx_pkt_reset(core->tx[i].tx_pkt, NULL); net_tx_pkt_uninit(core->tx[i].tx_pkt); } @@ -4158,7 +4158,6 @@ static void igb_reset(IGBCore *core, bool sw) for (i = 0; i < ARRAY_SIZE(core->tx); i++) { tx = &core->tx[i]; - net_tx_pkt_reset(tx->tx_pkt, NULL); memset(tx->ctx, 0, sizeof(tx->ctx)); tx->first = true; tx->skip_cp = false; diff --git a/hw/net/net_tx_pkt.c b/hw/net/net_tx_pkt.c index aca12ff035..cc36750c9b 100644 --- a/hw/net/net_tx_pkt.c +++ b/hw/net/net_tx_pkt.c @@ -16,12 +16,12 @@ */ #include "qemu/osdep.h" -#include "net_tx_pkt.h" #include "net/eth.h" #include "net/checksum.h" #include "net/tap.h" #include "net/net.h" #include "hw/pci/pci_device.h" +#include "net_tx_pkt.h" enum { NET_TX_PKT_VHDR_FRAG = 0, @@ -32,8 +32,6 @@ enum { /* TX packet private context */ struct NetTxPkt { - PCIDevice *pci_dev; - struct virtio_net_hdr virt_hdr; struct iovec *raw; @@ -59,13 +57,10 @@ struct NetTxPkt { uint8_t l4proto; }; -void net_tx_pkt_init(struct NetTxPkt **pkt, PCIDevice *pci_dev, - uint32_t max_frags) +void net_tx_pkt_init(struct NetTxPkt **pkt, uint32_t max_frags) { struct NetTxPkt *p = g_malloc0(sizeof *p); - p->pci_dev = pci_dev; - p->vec = g_new(struct iovec, max_frags + NET_TX_PKT_PL_START_FRAG); p->raw = g_new(struct iovec, max_frags); @@ -384,8 +379,7 @@ void net_tx_pkt_setup_vlan_header_ex(struct NetTxPkt *pkt, } } -static bool net_tx_pkt_add_raw_fragment_common(struct NetTxPkt *pkt, - void *base, size_t len) +bool net_tx_pkt_add_raw_fragment(struct NetTxPkt *pkt, void *base, size_t len) { struct iovec *ventry; assert(pkt); @@ -433,7 +427,8 @@ void net_tx_pkt_dump(struct NetTxPkt *pkt) #endif } -void net_tx_pkt_reset(struct NetTxPkt *pkt, PCIDevice *pci_dev) +void net_tx_pkt_reset(struct NetTxPkt *pkt, + NetTxPktFreeFrag callback, void *context) { int i; @@ -453,12 +448,9 @@ void net_tx_pkt_reset(struct NetTxPkt *pkt, PCIDevice *pci_dev) assert(pkt->raw); for (i = 0; i < pkt->raw_frags; i++) { assert(pkt->raw[i].iov_base); - net_tx_pkt_unmap_frag_pci(pkt->pci_dev, - pkt->raw[i].iov_base, - pkt->raw[i].iov_len); + callback(context, pkt->raw[i].iov_base, pkt->raw[i].iov_len); } } - pkt->pci_dev = pci_dev; pkt->raw_frags = 0; pkt->hdr_len = 0; @@ -470,19 +462,17 @@ void net_tx_pkt_unmap_frag_pci(void *context, void *base, size_t len) pci_dma_unmap(context, base, len, DMA_DIRECTION_TO_DEVICE, 0); } -bool net_tx_pkt_add_raw_fragment(struct NetTxPkt *pkt, hwaddr pa, - size_t len) +bool net_tx_pkt_add_raw_fragment_pci(struct NetTxPkt *pkt, PCIDevice *pci_dev, + dma_addr_t pa, size_t len) { dma_addr_t mapped_len = len; - void *base = pci_dma_map(pkt->pci_dev, pa, &mapped_len, - DMA_DIRECTION_TO_DEVICE); + void *base = pci_dma_map(pci_dev, pa, &mapped_len, DMA_DIRECTION_TO_DEVICE); if (!base) { return false; } - if (mapped_len != len || - !net_tx_pkt_add_raw_fragment_common(pkt, base, len)) { - net_tx_pkt_unmap_frag_pci(pkt->pci_dev, base, mapped_len); + if (mapped_len != len || !net_tx_pkt_add_raw_fragment(pkt, base, len)) { + net_tx_pkt_unmap_frag_pci(pci_dev, base, mapped_len); return false; } @@ -710,7 +700,7 @@ static void net_tx_pkt_udp_fragment_fix(struct NetTxPkt *pkt, } static bool net_tx_pkt_do_sw_fragmentation(struct NetTxPkt *pkt, - NetTxPktCallback callback, + NetTxPktSend callback, void *context) { uint8_t gso_type = pkt->virt_hdr.gso_type & ~VIRTIO_NET_HDR_GSO_ECN; @@ -807,7 +797,7 @@ bool net_tx_pkt_send(struct NetTxPkt *pkt, NetClientState *nc) } bool net_tx_pkt_send_custom(struct NetTxPkt *pkt, bool offload, - NetTxPktCallback callback, void *context) + NetTxPktSend callback, void *context) { assert(pkt); diff --git a/hw/net/net_tx_pkt.h b/hw/net/net_tx_pkt.h index 5eb123ef90..4d7233e975 100644 --- a/hw/net/net_tx_pkt.h +++ b/hw/net/net_tx_pkt.h @@ -26,17 +26,16 @@ struct NetTxPkt; -typedef void (* NetTxPktCallback)(void *, const struct iovec *, int, const struct iovec *, int); +typedef void (*NetTxPktFreeFrag)(void *, void *, size_t); +typedef void (*NetTxPktSend)(void *, const struct iovec *, int, const struct iovec *, int); /** * Init function for tx packet functionality * * @pkt: packet pointer - * @pci_dev: PCI device processing this packet * @max_frags: max tx ip fragments */ -void net_tx_pkt_init(struct NetTxPkt **pkt, PCIDevice *pci_dev, - uint32_t max_frags); +void net_tx_pkt_init(struct NetTxPkt **pkt, uint32_t max_frags); /** * Clean all tx packet resources. @@ -95,12 +94,11 @@ net_tx_pkt_setup_vlan_header(struct NetTxPkt *pkt, uint16_t vlan) * populate data fragment into pkt context. * * @pkt: packet - * @pa: physical address of fragment + * @base: pointer to fragment * @len: length of fragment * */ -bool net_tx_pkt_add_raw_fragment(struct NetTxPkt *pkt, hwaddr pa, - size_t len); +bool net_tx_pkt_add_raw_fragment(struct NetTxPkt *pkt, void *base, size_t len); /** * Fix ip header fields and calculate IP header and pseudo header checksums. @@ -148,10 +146,11 @@ void net_tx_pkt_dump(struct NetTxPkt *pkt); * reset tx packet private context (needed to be called between packets) * * @pkt: packet - * @dev: PCI device processing the next packet - * + * @callback: function to free the fragments + * @context: pointer to be passed to the callback */ -void net_tx_pkt_reset(struct NetTxPkt *pkt, PCIDevice *dev); +void net_tx_pkt_reset(struct NetTxPkt *pkt, + NetTxPktFreeFrag callback, void *context); /** * Unmap a fragment mapped from a PCI device. @@ -162,6 +161,16 @@ void net_tx_pkt_reset(struct NetTxPkt *pkt, PCIDevice *dev); */ void net_tx_pkt_unmap_frag_pci(void *context, void *base, size_t len); +/** + * map data fragment from PCI device and populate it into pkt context. + * + * @pci_dev: PCI device owning fragment + * @pa: physical address of fragment + * @len: length of fragment + */ +bool net_tx_pkt_add_raw_fragment_pci(struct NetTxPkt *pkt, PCIDevice *pci_dev, + dma_addr_t pa, size_t len); + /** * Send packet to qemu. handles sw offloads if vhdr is not supported. * @@ -182,7 +191,7 @@ bool net_tx_pkt_send(struct NetTxPkt *pkt, NetClientState *nc); * @ret: operation result */ bool net_tx_pkt_send_custom(struct NetTxPkt *pkt, bool offload, - NetTxPktCallback callback, void *context); + NetTxPktSend callback, void *context); /** * parse raw packet data and analyze offload requirements. diff --git a/hw/net/vmxnet3.c b/hw/net/vmxnet3.c index f7b874c139..9acff310e7 100644 --- a/hw/net/vmxnet3.c +++ b/hw/net/vmxnet3.c @@ -651,9 +651,8 @@ static void vmxnet3_process_tx_queue(VMXNET3State *s, int qidx) data_len = (txd.len > 0) ? txd.len : VMXNET3_MAX_TX_BUF_SIZE; data_pa = txd.addr; - if (!net_tx_pkt_add_raw_fragment(s->tx_pkt, - data_pa, - data_len)) { + if (!net_tx_pkt_add_raw_fragment_pci(s->tx_pkt, PCI_DEVICE(s), + data_pa, data_len)) { s->skip_current_tx_pkt = true; } } @@ -678,7 +677,8 @@ static void vmxnet3_process_tx_queue(VMXNET3State *s, int qidx) vmxnet3_complete_packet(s, qidx, txd_idx); s->tx_sop = true; s->skip_current_tx_pkt = false; - net_tx_pkt_reset(s->tx_pkt, PCI_DEVICE(s)); + net_tx_pkt_reset(s->tx_pkt, + net_tx_pkt_unmap_frag_pci, PCI_DEVICE(s)); } } } @@ -1159,7 +1159,7 @@ static void vmxnet3_deactivate_device(VMXNET3State *s) { if (s->device_active) { VMW_CBPRN("Deactivating vmxnet3..."); - net_tx_pkt_reset(s->tx_pkt, PCI_DEVICE(s)); + net_tx_pkt_reset(s->tx_pkt, net_tx_pkt_unmap_frag_pci, PCI_DEVICE(s)); net_tx_pkt_uninit(s->tx_pkt); net_rx_pkt_uninit(s->rx_pkt); s->device_active = false; @@ -1519,7 +1519,7 @@ static void vmxnet3_activate_device(VMXNET3State *s) /* Preallocate TX packet wrapper */ VMW_CFPRN("Max TX fragments is %u", s->max_tx_frags); - net_tx_pkt_init(&s->tx_pkt, PCI_DEVICE(s), s->max_tx_frags); + net_tx_pkt_init(&s->tx_pkt, s->max_tx_frags); net_rx_pkt_init(&s->rx_pkt); /* Read rings memory locations for RX queues */ @@ -2399,7 +2399,7 @@ static int vmxnet3_post_load(void *opaque, int version_id) { VMXNET3State *s = opaque; - net_tx_pkt_init(&s->tx_pkt, PCI_DEVICE(s), s->max_tx_frags); + net_tx_pkt_init(&s->tx_pkt, s->max_tx_frags); net_rx_pkt_init(&s->rx_pkt); if (s->msix_used) { -- cgit 1.4.1 From 0b11783014a0876344b14872d05ad55b21838e12 Mon Sep 17 00:00:00 2001 From: Akihiko Odaki Date: Tue, 23 May 2023 11:43:05 +0900 Subject: net/eth: Rename eth_setup_vlan_headers_ex MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The old eth_setup_vlan_headers has no user so remove it and rename eth_setup_vlan_headers_ex. Signed-off-by: Akihiko Odaki Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Jason Wang --- hw/net/net_tx_pkt.c | 2 +- include/net/eth.h | 9 +-------- net/eth.c | 2 +- 3 files changed, 3 insertions(+), 10 deletions(-) (limited to 'hw/net/net_tx_pkt.c') diff --git a/hw/net/net_tx_pkt.c b/hw/net/net_tx_pkt.c index cc36750c9b..ce6b102391 100644 --- a/hw/net/net_tx_pkt.c +++ b/hw/net/net_tx_pkt.c @@ -368,7 +368,7 @@ void net_tx_pkt_setup_vlan_header_ex(struct NetTxPkt *pkt, bool is_new; assert(pkt); - eth_setup_vlan_headers_ex(pkt->vec[NET_TX_PKT_L2HDR_FRAG].iov_base, + eth_setup_vlan_headers(pkt->vec[NET_TX_PKT_L2HDR_FRAG].iov_base, vlan, vlan_ethtype, &is_new); /* update l2hdrlen */ diff --git a/include/net/eth.h b/include/net/eth.h index 9f19c3a695..e8af5742be 100644 --- a/include/net/eth.h +++ b/include/net/eth.h @@ -351,16 +351,9 @@ eth_strip_vlan_ex(const struct iovec *iov, int iovcnt, size_t iovoff, uint16_t eth_get_l3_proto(const struct iovec *l2hdr_iov, int iovcnt, size_t l2hdr_len); -void eth_setup_vlan_headers_ex(struct eth_header *ehdr, uint16_t vlan_tag, +void eth_setup_vlan_headers(struct eth_header *ehdr, uint16_t vlan_tag, uint16_t vlan_ethtype, bool *is_new); -static inline void -eth_setup_vlan_headers(struct eth_header *ehdr, uint16_t vlan_tag, - bool *is_new) -{ - eth_setup_vlan_headers_ex(ehdr, vlan_tag, ETH_P_VLAN, is_new); -} - uint8_t eth_get_gso_type(uint16_t l3_proto, uint8_t *l3_hdr, uint8_t l4proto); diff --git a/net/eth.c b/net/eth.c index d7b30df79f..b6ff89c460 100644 --- a/net/eth.c +++ b/net/eth.c @@ -21,7 +21,7 @@ #include "net/checksum.h" #include "net/tap.h" -void eth_setup_vlan_headers_ex(struct eth_header *ehdr, uint16_t vlan_tag, +void eth_setup_vlan_headers(struct eth_header *ehdr, uint16_t vlan_tag, uint16_t vlan_ethtype, bool *is_new) { struct vlan_header *vhdr = PKT_GET_VLAN_HDR(ehdr); -- cgit 1.4.1 From aaa8a15c96a8a7341a3667dcc932f8c5f227d6af Mon Sep 17 00:00:00 2001 From: Akihiko Odaki Date: Tue, 23 May 2023 11:43:22 +0900 Subject: net/eth: Always add VLAN tag It is possible to have another VLAN tag even if the packet is already tagged. Signed-off-by: Akihiko Odaki Signed-off-by: Jason Wang --- hw/net/net_tx_pkt.c | 16 +++++++--------- include/net/eth.h | 4 ++-- net/eth.c | 22 ++++++---------------- 3 files changed, 15 insertions(+), 27 deletions(-) (limited to 'hw/net/net_tx_pkt.c') diff --git a/hw/net/net_tx_pkt.c b/hw/net/net_tx_pkt.c index ce6b102391..af8f77a3f0 100644 --- a/hw/net/net_tx_pkt.c +++ b/hw/net/net_tx_pkt.c @@ -40,7 +40,10 @@ struct NetTxPkt { struct iovec *vec; - uint8_t l2_hdr[ETH_MAX_L2_HDR_LEN]; + struct { + struct eth_header eth; + struct vlan_header vlan[3]; + } l2_hdr; union { struct ip_header ip; struct ip6_header ip6; @@ -365,18 +368,13 @@ bool net_tx_pkt_build_vheader(struct NetTxPkt *pkt, bool tso_enable, void net_tx_pkt_setup_vlan_header_ex(struct NetTxPkt *pkt, uint16_t vlan, uint16_t vlan_ethtype) { - bool is_new; assert(pkt); eth_setup_vlan_headers(pkt->vec[NET_TX_PKT_L2HDR_FRAG].iov_base, - vlan, vlan_ethtype, &is_new); + &pkt->vec[NET_TX_PKT_L2HDR_FRAG].iov_len, + vlan, vlan_ethtype); - /* update l2hdrlen */ - if (is_new) { - pkt->hdr_len += sizeof(struct vlan_header); - pkt->vec[NET_TX_PKT_L2HDR_FRAG].iov_len += - sizeof(struct vlan_header); - } + pkt->hdr_len += sizeof(struct vlan_header); } bool net_tx_pkt_add_raw_fragment(struct NetTxPkt *pkt, void *base, size_t len) diff --git a/include/net/eth.h b/include/net/eth.h index 95ff24d6b8..048e434685 100644 --- a/include/net/eth.h +++ b/include/net/eth.h @@ -353,8 +353,8 @@ eth_strip_vlan_ex(const struct iovec *iov, int iovcnt, size_t iovoff, uint16_t eth_get_l3_proto(const struct iovec *l2hdr_iov, int iovcnt, size_t l2hdr_len); -void eth_setup_vlan_headers(struct eth_header *ehdr, uint16_t vlan_tag, - uint16_t vlan_ethtype, bool *is_new); +void eth_setup_vlan_headers(struct eth_header *ehdr, size_t *ehdr_size, + uint16_t vlan_tag, uint16_t vlan_ethtype); uint8_t eth_get_gso_type(uint16_t l3_proto, uint8_t *l3_hdr, uint8_t l4proto); diff --git a/net/eth.c b/net/eth.c index f7ffbda600..5307978486 100644 --- a/net/eth.c +++ b/net/eth.c @@ -21,26 +21,16 @@ #include "net/checksum.h" #include "net/tap.h" -void eth_setup_vlan_headers(struct eth_header *ehdr, uint16_t vlan_tag, - uint16_t vlan_ethtype, bool *is_new) +void eth_setup_vlan_headers(struct eth_header *ehdr, size_t *ehdr_size, + uint16_t vlan_tag, uint16_t vlan_ethtype) { struct vlan_header *vhdr = PKT_GET_VLAN_HDR(ehdr); - switch (be16_to_cpu(ehdr->h_proto)) { - case ETH_P_VLAN: - case ETH_P_DVLAN: - /* vlan hdr exists */ - *is_new = false; - break; - - default: - /* No VLAN header, put a new one */ - vhdr->h_proto = ehdr->h_proto; - ehdr->h_proto = cpu_to_be16(vlan_ethtype); - *is_new = true; - break; - } + memmove(vhdr + 1, vhdr, *ehdr_size - ETH_HLEN); vhdr->h_tci = cpu_to_be16(vlan_tag); + vhdr->h_proto = ehdr->h_proto; + ehdr->h_proto = cpu_to_be16(vlan_ethtype); + *ehdr_size += sizeof(*vhdr); } uint8_t -- cgit 1.4.1 From f199b13bc113c46eaddcf9f375d13f1e400b4e35 Mon Sep 17 00:00:00 2001 From: Akihiko Odaki Date: Tue, 23 May 2023 11:43:28 +0900 Subject: igb: Implement Tx SCTP CSO Signed-off-by: Akihiko Odaki Reviewed-by: Sriram Yagnaraman Signed-off-by: Jason Wang --- hw/net/igb_core.c | 12 +++++++----- hw/net/net_tx_pkt.c | 18 ++++++++++++++++++ hw/net/net_tx_pkt.h | 8 ++++++++ 3 files changed, 33 insertions(+), 5 deletions(-) (limited to 'hw/net/net_tx_pkt.c') diff --git a/hw/net/igb_core.c b/hw/net/igb_core.c index 95d46d6e6d..5eacf1cd8c 100644 --- a/hw/net/igb_core.c +++ b/hw/net/igb_core.c @@ -440,8 +440,9 @@ igb_tx_insert_vlan(IGBCore *core, uint16_t qn, struct igb_tx *tx, static bool igb_setup_tx_offloads(IGBCore *core, struct igb_tx *tx) { + uint32_t idx = (tx->first_olinfo_status >> 4) & 1; + if (tx->first_cmd_type_len & E1000_ADVTXD_DCMD_TSE) { - uint32_t idx = (tx->first_olinfo_status >> 4) & 1; uint32_t mss = tx->ctx[idx].mss_l4len_idx >> E1000_ADVTXD_MSS_SHIFT; if (!net_tx_pkt_build_vheader(tx->tx_pkt, true, true, mss)) { return false; @@ -452,10 +453,11 @@ igb_setup_tx_offloads(IGBCore *core, struct igb_tx *tx) return true; } - if (tx->first_olinfo_status & E1000_ADVTXD_POTS_TXSM) { - if (!net_tx_pkt_build_vheader(tx->tx_pkt, false, true, 0)) { - return false; - } + if ((tx->first_olinfo_status & E1000_ADVTXD_POTS_TXSM) && + !((tx->ctx[idx].type_tucmd_mlhl & E1000_ADVTXD_TUCMD_L4T_SCTP) ? + net_tx_pkt_update_sctp_checksum(tx->tx_pkt) : + net_tx_pkt_build_vheader(tx->tx_pkt, false, true, 0))) { + return false; } if (tx->first_olinfo_status & E1000_ADVTXD_POTS_IXSM) { diff --git a/hw/net/net_tx_pkt.c b/hw/net/net_tx_pkt.c index af8f77a3f0..2e5f58b3c9 100644 --- a/hw/net/net_tx_pkt.c +++ b/hw/net/net_tx_pkt.c @@ -16,6 +16,7 @@ */ #include "qemu/osdep.h" +#include "qemu/crc32c.h" #include "net/eth.h" #include "net/checksum.h" #include "net/tap.h" @@ -135,6 +136,23 @@ void net_tx_pkt_update_ip_checksums(struct NetTxPkt *pkt) pkt->virt_hdr.csum_offset, &csum, sizeof(csum)); } +bool net_tx_pkt_update_sctp_checksum(struct NetTxPkt *pkt) +{ + uint32_t csum = 0; + struct iovec *pl_start_frag = pkt->vec + NET_TX_PKT_PL_START_FRAG; + + if (iov_from_buf(pl_start_frag, pkt->payload_frags, 8, &csum, sizeof(csum)) < sizeof(csum)) { + return false; + } + + csum = cpu_to_le32(iov_crc32c(0xffffffff, pl_start_frag, pkt->payload_frags)); + if (iov_from_buf(pl_start_frag, pkt->payload_frags, 8, &csum, sizeof(csum)) < sizeof(csum)) { + return false; + } + + return true; +} + static void net_tx_pkt_calculate_hdr_len(struct NetTxPkt *pkt) { pkt->hdr_len = pkt->vec[NET_TX_PKT_L2HDR_FRAG].iov_len + diff --git a/hw/net/net_tx_pkt.h b/hw/net/net_tx_pkt.h index 4d7233e975..0a716e74a5 100644 --- a/hw/net/net_tx_pkt.h +++ b/hw/net/net_tx_pkt.h @@ -116,6 +116,14 @@ void net_tx_pkt_update_ip_checksums(struct NetTxPkt *pkt); */ void net_tx_pkt_update_ip_hdr_checksum(struct NetTxPkt *pkt); +/** + * Calculate the SCTP checksum. + * + * @pkt: packet + * + */ +bool net_tx_pkt_update_sctp_checksum(struct NetTxPkt *pkt); + /** * get length of all populated data. * -- cgit 1.4.1