-----BEGIN PGP SIGNATURE-----

Version: GnuPG v1
 
 iQEcBAABAgAGBQJkbGmXAAoJEO8Ells5jWIR4ogH/R5+IgkZi1dwN/IxCpzTIc5H
 l5ncKK6TCqKCfgpFnFFLNKhcDqDczq4LhO42s/vnuOF8vIXcUVhLAz0HULARb46o
 p/7Ufn1k8Zg/HGtWwIW+9CcTkymsHzTOwFcTRFiCjpdkjaW1Wprb2q968f0Px8eS
 cKqC5xln8U+s02KWQMHlJili6BTPuw1ZNnYV3iq/81Me96WOtPd8c8ZSF4aVR2AB
 Kqah+BBOnk4p4kg9Gs0OvM4TffEBrsab8iu4s6SSQGA6ymCWY6GeCX0Ik4u9P1yE
 6NtKLixBPO4fqLwWxWuKVJmaLKmuEd/FjZXWwITx9EPNtDuBuGLDKuvW8fJxkhw=
 =dw2I
 -----END PGP SIGNATURE-----

Merge tag 'net-pull-request' of https://github.com/jasowang/qemu into staging

# -----BEGIN PGP SIGNATURE-----
# Version: GnuPG v1
#
# iQEcBAABAgAGBQJkbGmXAAoJEO8Ells5jWIR4ogH/R5+IgkZi1dwN/IxCpzTIc5H
# l5ncKK6TCqKCfgpFnFFLNKhcDqDczq4LhO42s/vnuOF8vIXcUVhLAz0HULARb46o
# p/7Ufn1k8Zg/HGtWwIW+9CcTkymsHzTOwFcTRFiCjpdkjaW1Wprb2q968f0Px8eS
# cKqC5xln8U+s02KWQMHlJili6BTPuw1ZNnYV3iq/81Me96WOtPd8c8ZSF4aVR2AB
# Kqah+BBOnk4p4kg9Gs0OvM4TffEBrsab8iu4s6SSQGA6ymCWY6GeCX0Ik4u9P1yE
# 6NtKLixBPO4fqLwWxWuKVJmaLKmuEd/FjZXWwITx9EPNtDuBuGLDKuvW8fJxkhw=
# =dw2I
# -----END PGP SIGNATURE-----
# gpg: Signature made Tue 23 May 2023 12:21:59 AM PDT
# gpg:                using RSA key EF04965B398D6211
# gpg: Good signature from "Jason Wang (Jason Wang on RedHat) <jasowang@redhat.com>" [undefined]
# gpg: WARNING: This key is not certified with a trusted signature!
# gpg:          There is no indication that the signature belongs to the owner.
# Primary key fingerprint: 215D 46F4 8246 689E C77F  3562 EF04 965B 398D 6211

* tag 'net-pull-request' of https://github.com/jasowang/qemu: (50 commits)
  rtl8139: fix large_send_mss divide-by-zero
  docs/system/devices/igb: Note igb is tested for DPDK
  MAINTAINERS: Add a reviewer for network packet abstractions
  vmxnet3: Do not depend on PC
  igb: Clear-on-read ICR when ICR.INTA is set
  igb: Notify only new interrupts
  e1000e: Notify only new interrupts
  igb: Implement Tx timestamp
  igb: Implement Rx PTP2 timestamp
  igb: Implement igb-specific oversize check
  igb: Filter with the second VLAN tag for extended VLAN
  igb: Strip the second VLAN tag for extended VLAN
  igb: Implement Tx SCTP CSO
  igb: Implement Rx SCTP CSO
  igb: Use UDP for RSS hash
  igb: Implement MSI-X single vector mode
  tests/qtest/libqos/igb: Set GPIE.Multiple_MSIX
  hw/net/net_rx_pkt: Enforce alignment for eth_header
  net/eth: Always add VLAN tag
  net/eth: Use void pointers
  ...

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
This commit is contained in:
Richard Henderson 2023-05-23 06:22:12 -07:00
commit 00f76608a6
29 changed files with 986 additions and 839 deletions

View File

@ -2237,6 +2237,7 @@ F: tests/qtest/fuzz-megasas-test.c
Network packet abstractions Network packet abstractions
M: Dmitry Fleytman <dmitry.fleytman@gmail.com> M: Dmitry Fleytman <dmitry.fleytman@gmail.com>
R: Akihiko Odaki <akihiko.odaki@daynix.com>
S: Maintained S: Maintained
F: include/net/eth.h F: include/net/eth.h
F: net/eth.c F: net/eth.c
@ -2279,7 +2280,7 @@ R: Sriram Yagnaraman <sriram.yagnaraman@est.tech>
S: Maintained S: Maintained
F: docs/system/devices/igb.rst F: docs/system/devices/igb.rst
F: hw/net/igb* F: hw/net/igb*
F: tests/avocado/igb.py F: tests/avocado/netdev-ethtool.py
F: tests/qtest/igb-test.c F: tests/qtest/igb-test.c
F: tests/qtest/libqos/igb.c F: tests/qtest/libqos/igb.c

View File

@ -14,7 +14,8 @@ Limitations
=========== ===========
This igb implementation was tested with Linux Test Project [2]_ and Windows HLK This igb implementation was tested with Linux Test Project [2]_ and Windows HLK
[3]_ during the initial development. The command used when testing with LTP is: [3]_ during the initial development. Later it was also tested with DPDK Test
Suite [4]_. The command used when testing with LTP is:
.. code-block:: shell .. code-block:: shell
@ -22,8 +23,8 @@ This igb implementation was tested with Linux Test Project [2]_ and Windows HLK
Be aware that this implementation lacks many functionalities available with the Be aware that this implementation lacks many functionalities available with the
actual hardware, and you may experience various failures if you try to use it actual hardware, and you may experience various failures if you try to use it
with a different operating system other than Linux and Windows or if you try with a different operating system other than DPDK, Linux, and Windows or if you
functionalities not covered by the tests. try functionalities not covered by the tests.
Using igb Using igb
========= =========
@ -32,7 +33,7 @@ Using igb should be nothing different from using another network device. See
:ref:`Network_emulation` in general. :ref:`Network_emulation` in general.
However, you may also need to perform additional steps to activate SR-IOV However, you may also need to perform additional steps to activate SR-IOV
feature on your guest. For Linux, refer to [4]_. feature on your guest. For Linux, refer to [5]_.
Developing igb Developing igb
============== ==============
@ -60,7 +61,7 @@ Avocado test and can be ran with the following command:
.. code:: shell .. code:: shell
make check-avocado AVOCADO_TESTS=tests/avocado/igb.py make check-avocado AVOCADO_TESTS=tests/avocado/netdev-ethtool.py
References References
========== ==========
@ -68,4 +69,5 @@ References
.. [1] https://www.intel.com/content/dam/www/public/us/en/documents/datasheets/82576eb-gigabit-ethernet-controller-datasheet.pdf .. [1] https://www.intel.com/content/dam/www/public/us/en/documents/datasheets/82576eb-gigabit-ethernet-controller-datasheet.pdf
.. [2] https://github.com/linux-test-project/ltp .. [2] https://github.com/linux-test-project/ltp
.. [3] https://learn.microsoft.com/en-us/windows-hardware/test/hlk/ .. [3] https://learn.microsoft.com/en-us/windows-hardware/test/hlk/
.. [4] https://docs.kernel.org/PCI/pci-iov-howto.html .. [4] https://doc.dpdk.org/dts/gsg/
.. [5] https://docs.kernel.org/PCI/pci-iov-howto.html

View File

@ -56,7 +56,7 @@ config RTL8139_PCI
config VMXNET3_PCI config VMXNET3_PCI
bool bool
default y if PCI_DEVICES && PC_PCI default y if PCI_DEVICES
depends on PCI depends on PCI
config SMC91C111 config SMC91C111

View File

@ -637,9 +637,8 @@ xmit_seg(E1000State *s)
e1000x_inc_reg_if_not_full(s->mac_reg, TPT); e1000x_inc_reg_if_not_full(s->mac_reg, TPT);
e1000x_grow_8reg_if_not_full(s->mac_reg, TOTL, s->tx.size + 4); e1000x_grow_8reg_if_not_full(s->mac_reg, TOTL, s->tx.size + 4);
s->mac_reg[GPTC] = s->mac_reg[TPT]; e1000x_inc_reg_if_not_full(s->mac_reg, GPTC);
s->mac_reg[GOTCL] = s->mac_reg[TOTL]; e1000x_grow_8reg_if_not_full(s->mac_reg, GOTCL, s->tx.size + 4);
s->mac_reg[GOTCH] = s->mac_reg[TOTH];
} }
static void static void
@ -805,38 +804,11 @@ start_xmit(E1000State *s)
} }
static int static int
receive_filter(E1000State *s, const uint8_t *buf, int size) receive_filter(E1000State *s, const void *buf)
{ {
uint32_t rctl = s->mac_reg[RCTL]; return (!e1000x_is_vlan_packet(buf, s->mac_reg[VET]) ||
int isbcast = is_broadcast_ether_addr(buf); e1000x_rx_vlan_filter(s->mac_reg, PKT_GET_VLAN_HDR(buf))) &&
int ismcast = is_multicast_ether_addr(buf); e1000x_rx_group_filter(s->mac_reg, buf);
if (e1000x_is_vlan_packet(buf, le16_to_cpu(s->mac_reg[VET])) &&
e1000x_vlan_rx_filter_enabled(s->mac_reg)) {
uint16_t vid = lduw_be_p(&PKT_GET_VLAN_HDR(buf)->h_tci);
uint32_t vfta =
ldl_le_p((uint32_t *)(s->mac_reg + VFTA) +
((vid >> E1000_VFTA_ENTRY_SHIFT) & E1000_VFTA_ENTRY_MASK));
if ((vfta & (1 << (vid & E1000_VFTA_ENTRY_BIT_SHIFT_MASK))) == 0) {
return 0;
}
}
if (!isbcast && !ismcast && (rctl & E1000_RCTL_UPE)) { /* promiscuous ucast */
return 1;
}
if (ismcast && (rctl & E1000_RCTL_MPE)) { /* promiscuous mcast */
e1000x_inc_reg_if_not_full(s->mac_reg, MPRC);
return 1;
}
if (isbcast && (rctl & E1000_RCTL_BAM)) { /* broadcast enabled */
e1000x_inc_reg_if_not_full(s->mac_reg, BPRC);
return 1;
}
return e1000x_rx_group_filter(s->mac_reg, buf);
} }
static void static void
@ -923,6 +895,7 @@ e1000_receive_iov(NetClientState *nc, const struct iovec *iov, int iovcnt)
size_t desc_offset; size_t desc_offset;
size_t desc_size; size_t desc_size;
size_t total_size; size_t total_size;
eth_pkt_types_e pkt_type;
if (!e1000x_hw_rx_enabled(s->mac_reg)) { if (!e1000x_hw_rx_enabled(s->mac_reg)) {
return -1; return -1;
@ -951,7 +924,7 @@ e1000_receive_iov(NetClientState *nc, const struct iovec *iov, int iovcnt)
return size; return size;
} }
if (!receive_filter(s, filter_buf, size)) { if (!receive_filter(s, filter_buf)) {
return size; return size;
} }
@ -972,6 +945,7 @@ e1000_receive_iov(NetClientState *nc, const struct iovec *iov, int iovcnt)
size -= 4; size -= 4;
} }
pkt_type = get_eth_packet_type(PKT_GET_ETH_HDR(filter_buf));
rdh_start = s->mac_reg[RDH]; rdh_start = s->mac_reg[RDH];
desc_offset = 0; desc_offset = 0;
total_size = size + e1000x_fcs_len(s->mac_reg); total_size = size + e1000x_fcs_len(s->mac_reg);
@ -1037,7 +1011,7 @@ e1000_receive_iov(NetClientState *nc, const struct iovec *iov, int iovcnt)
} }
} while (desc_offset < total_size); } while (desc_offset < total_size);
e1000x_update_rx_total_stats(s->mac_reg, size, total_size); e1000x_update_rx_total_stats(s->mac_reg, pkt_type, size, total_size);
n = E1000_ICS_RXT0; n = E1000_ICS_RXT0;
if ((rdt = s->mac_reg[RDT]) < s->mac_reg[RDH]) if ((rdt = s->mac_reg[RDT]) < s->mac_reg[RDH])

View File

@ -165,14 +165,14 @@ e1000e_intrmgr_on_throttling_timer(void *opaque)
timer->running = false; timer->running = false;
if (timer->core->mac[IMS] & timer->core->mac[ICR]) {
if (msi_enabled(timer->core->owner)) { if (msi_enabled(timer->core->owner)) {
trace_e1000e_irq_msi_notify_postponed(); trace_e1000e_irq_msi_notify_postponed();
/* Clear msi_causes_pending to fire MSI eventually */ msi_notify(timer->core->owner, 0);
timer->core->msi_causes_pending = 0;
e1000e_set_interrupt_cause(timer->core, 0);
} else { } else {
trace_e1000e_irq_legacy_notify_postponed(); trace_e1000e_irq_legacy_notify_postponed();
e1000e_set_interrupt_cause(timer->core, 0); e1000e_raise_legacy_irq(timer->core);
}
} }
} }
@ -366,10 +366,6 @@ static void
e1000e_intrmgr_fire_all_timers(E1000ECore *core) e1000e_intrmgr_fire_all_timers(E1000ECore *core)
{ {
int i; int i;
uint32_t val = e1000e_intmgr_collect_delayed_causes(core);
trace_e1000e_irq_adding_delayed_causes(val, core->mac[ICR]);
core->mac[ICR] |= val;
if (core->itr.running) { if (core->itr.running) {
timer_del(core->itr.timer); timer_del(core->itr.timer);
@ -537,7 +533,7 @@ e1000e_rss_get_hash_type(E1000ECore *core, struct NetRxPkt *pkt)
ip6info->rss_ex_dst_valid, ip6info->rss_ex_dst_valid,
ip6info->rss_ex_src_valid, ip6info->rss_ex_src_valid,
core->mac[MRQC], core->mac[MRQC],
E1000_MRQC_EN_TCPIPV6(core->mac[MRQC]), E1000_MRQC_EN_TCPIPV6EX(core->mac[MRQC]),
E1000_MRQC_EN_IPV6EX(core->mac[MRQC]), E1000_MRQC_EN_IPV6EX(core->mac[MRQC]),
E1000_MRQC_EN_IPV6(core->mac[MRQC])); E1000_MRQC_EN_IPV6(core->mac[MRQC]));
@ -546,8 +542,8 @@ e1000e_rss_get_hash_type(E1000ECore *core, struct NetRxPkt *pkt)
ip6info->rss_ex_src_valid))) { ip6info->rss_ex_src_valid))) {
if (l4hdr_proto == ETH_L4_HDR_PROTO_TCP && if (l4hdr_proto == ETH_L4_HDR_PROTO_TCP &&
E1000_MRQC_EN_TCPIPV6(core->mac[MRQC])) { E1000_MRQC_EN_TCPIPV6EX(core->mac[MRQC])) {
return E1000_MRQ_RSS_TYPE_IPV6TCP; return E1000_MRQ_RSS_TYPE_IPV6TCPEX;
} }
if (E1000_MRQC_EN_IPV6EX(core->mac[MRQC])) { if (E1000_MRQC_EN_IPV6EX(core->mac[MRQC])) {
@ -581,7 +577,7 @@ e1000e_rss_calc_hash(E1000ECore *core,
case E1000_MRQ_RSS_TYPE_IPV4TCP: case E1000_MRQ_RSS_TYPE_IPV4TCP:
type = NetPktRssIpV4Tcp; type = NetPktRssIpV4Tcp;
break; break;
case E1000_MRQ_RSS_TYPE_IPV6TCP: case E1000_MRQ_RSS_TYPE_IPV6TCPEX:
type = NetPktRssIpV6TcpEx; type = NetPktRssIpV6TcpEx;
break; break;
case E1000_MRQ_RSS_TYPE_IPV6: case E1000_MRQ_RSS_TYPE_IPV6:
@ -711,9 +707,8 @@ e1000e_on_tx_done_update_stats(E1000ECore *core, struct NetTxPkt *tx_pkt)
g_assert_not_reached(); g_assert_not_reached();
} }
core->mac[GPTC] = core->mac[TPT]; e1000x_inc_reg_if_not_full(core->mac, GPTC);
core->mac[GOTCL] = core->mac[TOTL]; e1000x_grow_8reg_if_not_full(core->mac, GOTCL, tot_len);
core->mac[GOTCH] = core->mac[TOTH];
} }
static void static void
@ -747,7 +742,8 @@ e1000e_process_tx_desc(E1000ECore *core,
addr = le64_to_cpu(dp->buffer_addr); addr = le64_to_cpu(dp->buffer_addr);
if (!tx->skip_cp) { 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; tx->skip_cp = true;
} }
} }
@ -765,7 +761,7 @@ e1000e_process_tx_desc(E1000ECore *core,
} }
tx->skip_cp = false; 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->sum_needed = 0;
tx->cptse = 0; tx->cptse = 0;
@ -959,6 +955,8 @@ e1000e_start_xmit(E1000ECore *core, const E1000E_TxRing *txr)
if (!ide || !e1000e_intrmgr_delay_tx_causes(core, &cause)) { if (!ide || !e1000e_intrmgr_delay_tx_causes(core, &cause)) {
e1000e_set_interrupt_cause(core, cause); e1000e_set_interrupt_cause(core, cause);
} }
net_tx_pkt_reset(txr->tx->tx_pkt, net_tx_pkt_unmap_frag_pci, core->owner);
} }
static bool static bool
@ -1034,48 +1032,11 @@ e1000e_rx_l4_cso_enabled(E1000ECore *core)
} }
static bool static bool
e1000e_receive_filter(E1000ECore *core, const uint8_t *buf, int size) e1000e_receive_filter(E1000ECore *core, const void *buf)
{ {
uint32_t rctl = core->mac[RCTL]; return (!e1000x_is_vlan_packet(buf, core->mac[VET]) ||
e1000x_rx_vlan_filter(core->mac, PKT_GET_VLAN_HDR(buf))) &&
if (e1000x_is_vlan_packet(buf, core->mac[VET]) && e1000x_rx_group_filter(core->mac, buf);
e1000x_vlan_rx_filter_enabled(core->mac)) {
uint16_t vid = lduw_be_p(&PKT_GET_VLAN_HDR(buf)->h_tci);
uint32_t vfta =
ldl_le_p((uint32_t *)(core->mac + VFTA) +
((vid >> E1000_VFTA_ENTRY_SHIFT) & E1000_VFTA_ENTRY_MASK));
if ((vfta & (1 << (vid & E1000_VFTA_ENTRY_BIT_SHIFT_MASK))) == 0) {
trace_e1000e_rx_flt_vlan_mismatch(vid);
return false;
} else {
trace_e1000e_rx_flt_vlan_match(vid);
}
}
switch (net_rx_pkt_get_packet_type(core->rx_pkt)) {
case ETH_PKT_UCAST:
if (rctl & E1000_RCTL_UPE) {
return true; /* promiscuous ucast */
}
break;
case ETH_PKT_BCAST:
if (rctl & E1000_RCTL_BAM) {
return true; /* broadcast enabled */
}
break;
case ETH_PKT_MCAST:
if (rctl & E1000_RCTL_MPE) {
return true; /* promiscuous mcast */
}
break;
default:
g_assert_not_reached();
}
return e1000x_rx_group_filter(core->mac, buf);
} }
static inline void static inline void
@ -1149,6 +1110,11 @@ e1000e_verify_csum_in_sw(E1000ECore *core,
return; return;
} }
if (l4hdr_proto != ETH_L4_HDR_PROTO_TCP &&
l4hdr_proto != ETH_L4_HDR_PROTO_UDP) {
return;
}
if (!net_rx_pkt_validate_l4_csum(pkt, &csum_valid)) { if (!net_rx_pkt_validate_l4_csum(pkt, &csum_valid)) {
trace_e1000e_rx_metadata_l4_csum_validation_failed(); trace_e1000e_rx_metadata_l4_csum_validation_failed();
return; return;
@ -1281,9 +1247,8 @@ e1000e_build_rx_metadata(E1000ECore *core,
trace_e1000e_rx_metadata_l4_cso_disabled(); trace_e1000e_rx_metadata_l4_cso_disabled();
} }
trace_e1000e_rx_metadata_status_flags(*status_flags);
func_exit: func_exit:
trace_e1000e_rx_metadata_status_flags(*status_flags);
*status_flags = cpu_to_le32(*status_flags); *status_flags = cpu_to_le32(*status_flags);
} }
@ -1488,24 +1453,10 @@ e1000e_write_to_rx_buffers(E1000ECore *core,
} }
static void static void
e1000e_update_rx_stats(E1000ECore *core, e1000e_update_rx_stats(E1000ECore *core, size_t pkt_size, size_t pkt_fcs_size)
size_t data_size,
size_t data_fcs_size)
{ {
e1000x_update_rx_total_stats(core->mac, data_size, data_fcs_size); eth_pkt_types_e pkt_type = net_rx_pkt_get_packet_type(core->rx_pkt);
e1000x_update_rx_total_stats(core->mac, pkt_type, pkt_size, pkt_fcs_size);
switch (net_rx_pkt_get_packet_type(core->rx_pkt)) {
case ETH_PKT_BCAST:
e1000x_inc_reg_if_not_full(core->mac, BPRC);
break;
case ETH_PKT_MCAST:
e1000x_inc_reg_if_not_full(core->mac, MPRC);
break;
default:
break;
}
} }
static inline bool static inline bool
@ -1700,12 +1651,9 @@ static ssize_t
e1000e_receive_internal(E1000ECore *core, const struct iovec *iov, int iovcnt, e1000e_receive_internal(E1000ECore *core, const struct iovec *iov, int iovcnt,
bool has_vnet) bool has_vnet)
{ {
static const int maximum_ethernet_hdr_len = (ETH_HLEN + 4); uint32_t causes = 0;
uint8_t buf[ETH_ZLEN];
uint32_t n = 0;
uint8_t min_buf[ETH_ZLEN];
struct iovec min_iov; struct iovec min_iov;
uint8_t *filter_buf;
size_t size, orig_size; size_t size, orig_size;
size_t iov_ofs = 0; size_t iov_ofs = 0;
E1000E_RxRing rxr; E1000E_RxRing rxr;
@ -1728,24 +1676,21 @@ e1000e_receive_internal(E1000ECore *core, const struct iovec *iov, int iovcnt,
net_rx_pkt_unset_vhdr(core->rx_pkt); net_rx_pkt_unset_vhdr(core->rx_pkt);
} }
filter_buf = iov->iov_base + iov_ofs;
orig_size = iov_size(iov, iovcnt); orig_size = iov_size(iov, iovcnt);
size = orig_size - iov_ofs; size = orig_size - iov_ofs;
/* Pad to minimum Ethernet frame length */ /* Pad to minimum Ethernet frame length */
if (size < sizeof(min_buf)) { if (size < sizeof(buf)) {
iov_to_buf(iov, iovcnt, iov_ofs, min_buf, size); iov_to_buf(iov, iovcnt, iov_ofs, buf, size);
memset(&min_buf[size], 0, sizeof(min_buf) - size); memset(&buf[size], 0, sizeof(buf) - size);
e1000x_inc_reg_if_not_full(core->mac, RUC); e1000x_inc_reg_if_not_full(core->mac, RUC);
min_iov.iov_base = filter_buf = min_buf; min_iov.iov_base = buf;
min_iov.iov_len = size = sizeof(min_buf); min_iov.iov_len = size = sizeof(buf);
iovcnt = 1; iovcnt = 1;
iov = &min_iov; iov = &min_iov;
iov_ofs = 0; iov_ofs = 0;
} else if (iov->iov_len < maximum_ethernet_hdr_len) { } else {
/* This is very unlikely, but may happen. */ iov_to_buf(iov, iovcnt, iov_ofs, buf, ETH_HLEN + 4);
iov_to_buf(iov, iovcnt, iov_ofs, min_buf, maximum_ethernet_hdr_len);
filter_buf = min_buf;
} }
/* Discard oversized packets if !LPE and !SBP. */ /* Discard oversized packets if !LPE and !SBP. */
@ -1754,15 +1699,16 @@ e1000e_receive_internal(E1000ECore *core, const struct iovec *iov, int iovcnt,
} }
net_rx_pkt_set_packet_type(core->rx_pkt, net_rx_pkt_set_packet_type(core->rx_pkt,
get_eth_packet_type(PKT_GET_ETH_HDR(filter_buf))); get_eth_packet_type(PKT_GET_ETH_HDR(buf)));
if (!e1000e_receive_filter(core, filter_buf, size)) { if (!e1000e_receive_filter(core, buf)) {
trace_e1000e_rx_flt_dropped(); trace_e1000e_rx_flt_dropped();
return orig_size; return orig_size;
} }
net_rx_pkt_attach_iovec_ex(core->rx_pkt, iov, iovcnt, iov_ofs, net_rx_pkt_attach_iovec_ex(core->rx_pkt, iov, iovcnt, iov_ofs,
e1000x_vlan_enabled(core->mac), core->mac[VET]); e1000x_vlan_enabled(core->mac) ? 0 : -1,
core->mac[VET], 0);
e1000e_rss_parse_packet(core, core->rx_pkt, &rss_info); e1000e_rss_parse_packet(core, core->rx_pkt, &rss_info);
e1000e_rx_ring_init(core, &rxr, rss_info.queue); e1000e_rx_ring_init(core, &rxr, rss_info.queue);
@ -1779,32 +1725,32 @@ e1000e_receive_internal(E1000ECore *core, const struct iovec *iov, int iovcnt,
/* Perform small receive detection (RSRPD) */ /* Perform small receive detection (RSRPD) */
if (total_size < core->mac[RSRPD]) { if (total_size < core->mac[RSRPD]) {
n |= E1000_ICS_SRPD; causes |= E1000_ICS_SRPD;
} }
/* Perform ACK receive detection */ /* Perform ACK receive detection */
if (!(core->mac[RFCTL] & E1000_RFCTL_ACK_DIS) && if (!(core->mac[RFCTL] & E1000_RFCTL_ACK_DIS) &&
(e1000e_is_tcp_ack(core, core->rx_pkt))) { (e1000e_is_tcp_ack(core, core->rx_pkt))) {
n |= E1000_ICS_ACK; causes |= E1000_ICS_ACK;
} }
/* Check if receive descriptor minimum threshold hit */ /* Check if receive descriptor minimum threshold hit */
rdmts_hit = e1000e_rx_descr_threshold_hit(core, rxr.i); rdmts_hit = e1000e_rx_descr_threshold_hit(core, rxr.i);
n |= e1000e_rx_wb_interrupt_cause(core, rxr.i->idx, rdmts_hit); causes |= e1000e_rx_wb_interrupt_cause(core, rxr.i->idx, rdmts_hit);
trace_e1000e_rx_written_to_guest(rxr.i->idx); trace_e1000e_rx_written_to_guest(rxr.i->idx);
} else { } else {
n |= E1000_ICS_RXO; causes |= E1000_ICS_RXO;
retval = 0; retval = 0;
trace_e1000e_rx_not_written_to_guest(rxr.i->idx); trace_e1000e_rx_not_written_to_guest(rxr.i->idx);
} }
if (!e1000e_intrmgr_delay_rx_causes(core, &n)) { if (!e1000e_intrmgr_delay_rx_causes(core, &causes)) {
trace_e1000e_rx_interrupt_set(n); trace_e1000e_rx_interrupt_set(causes);
e1000e_set_interrupt_cause(core, n); e1000e_set_interrupt_cause(core, causes);
} else { } else {
trace_e1000e_rx_interrupt_delayed(n); trace_e1000e_rx_interrupt_delayed(causes);
} }
return retval; return retval;
@ -2024,13 +1970,6 @@ void(*e1000e_phyreg_writeops[E1000E_PHY_PAGES][E1000E_PHY_PAGE_SIZE])
} }
}; };
static inline void
e1000e_clear_ims_bits(E1000ECore *core, uint32_t bits)
{
trace_e1000e_irq_clear_ims(bits, core->mac[IMS], core->mac[IMS] & ~bits);
core->mac[IMS] &= ~bits;
}
static inline bool static inline bool
e1000e_postpone_interrupt(E1000IntrDelayTimer *timer) e1000e_postpone_interrupt(E1000IntrDelayTimer *timer)
{ {
@ -2088,7 +2027,6 @@ e1000e_msix_notify_one(E1000ECore *core, uint32_t cause, uint32_t int_cfg)
effective_eiac = core->mac[EIAC] & cause; effective_eiac = core->mac[EIAC] & cause;
core->mac[ICR] &= ~effective_eiac; core->mac[ICR] &= ~effective_eiac;
core->msi_causes_pending &= ~effective_eiac;
if (!(core->mac[CTRL_EXT] & E1000_CTRL_EXT_IAME)) { if (!(core->mac[CTRL_EXT] & E1000_CTRL_EXT_IAME)) {
core->mac[IMS] &= ~effective_eiac; core->mac[IMS] &= ~effective_eiac;
@ -2180,33 +2118,17 @@ e1000e_fix_icr_asserted(E1000ECore *core)
trace_e1000e_irq_fix_icr_asserted(core->mac[ICR]); trace_e1000e_irq_fix_icr_asserted(core->mac[ICR]);
} }
static void static void e1000e_raise_interrupts(E1000ECore *core,
e1000e_send_msi(E1000ECore *core, bool msix) size_t index, uint32_t causes)
{ {
uint32_t causes = core->mac[ICR] & core->mac[IMS] & ~E1000_ICR_ASSERTED;
core->msi_causes_pending &= causes;
causes ^= core->msi_causes_pending;
if (causes == 0) {
return;
}
core->msi_causes_pending |= causes;
if (msix) {
e1000e_msix_notify(core, causes);
} else {
if (!e1000e_itr_should_postpone(core)) {
trace_e1000e_irq_msi_notify(causes);
msi_notify(core->owner, 0);
}
}
}
static void
e1000e_update_interrupt_state(E1000ECore *core)
{
bool interrupts_pending;
bool is_msix = msix_enabled(core->owner); bool is_msix = msix_enabled(core->owner);
uint32_t old_causes = core->mac[IMS] & core->mac[ICR];
uint32_t raised_causes;
trace_e1000e_irq_set(index << 2,
core->mac[index], core->mac[index] | causes);
core->mac[index] |= causes;
/* Set ICR[OTHER] for MSI-X */ /* Set ICR[OTHER] for MSI-X */
if (is_msix) { if (is_msix) {
@ -2228,40 +2150,58 @@ e1000e_update_interrupt_state(E1000ECore *core)
*/ */
core->mac[ICS] = core->mac[ICR]; core->mac[ICS] = core->mac[ICR];
interrupts_pending = (core->mac[IMS] & core->mac[ICR]) ? true : false; trace_e1000e_irq_pending_interrupts(core->mac[ICR] & core->mac[IMS],
if (!interrupts_pending) { core->mac[ICR], core->mac[IMS]);
core->msi_causes_pending = 0;
raised_causes = core->mac[IMS] & core->mac[ICR] & ~old_causes;
if (!raised_causes) {
return;
} }
if (is_msix) {
e1000e_msix_notify(core, raised_causes & ~E1000_ICR_ASSERTED);
} else if (!e1000e_itr_should_postpone(core)) {
if (msi_enabled(core->owner)) {
trace_e1000e_irq_msi_notify(raised_causes);
msi_notify(core->owner, 0);
} else {
e1000e_raise_legacy_irq(core);
}
}
}
static void e1000e_lower_interrupts(E1000ECore *core,
size_t index, uint32_t causes)
{
trace_e1000e_irq_clear(index << 2,
core->mac[index], core->mac[index] & ~causes);
core->mac[index] &= ~causes;
/*
* Make sure ICR and ICS registers have the same value.
* The spec says that the ICS register is write-only. However in practice,
* on real hardware ICS is readable, and for reads it has the same value as
* ICR (except that ICS does not have the clear on read behaviour of ICR).
*
* The VxWorks PRO/1000 driver uses this behaviour.
*/
core->mac[ICS] = core->mac[ICR];
trace_e1000e_irq_pending_interrupts(core->mac[ICR] & core->mac[IMS], trace_e1000e_irq_pending_interrupts(core->mac[ICR] & core->mac[IMS],
core->mac[ICR], core->mac[IMS]); core->mac[ICR], core->mac[IMS]);
if (is_msix || msi_enabled(core->owner)) { if (!(core->mac[IMS] & core->mac[ICR]) &&
if (interrupts_pending) { !msix_enabled(core->owner) && !msi_enabled(core->owner)) {
e1000e_send_msi(core, is_msix);
}
} else {
if (interrupts_pending) {
if (!e1000e_itr_should_postpone(core)) {
e1000e_raise_legacy_irq(core);
}
} else {
e1000e_lower_legacy_irq(core); e1000e_lower_legacy_irq(core);
} }
} }
}
static void static void
e1000e_set_interrupt_cause(E1000ECore *core, uint32_t val) e1000e_set_interrupt_cause(E1000ECore *core, uint32_t val)
{ {
trace_e1000e_irq_set_cause_entry(val, core->mac[ICR]);
val |= e1000e_intmgr_collect_delayed_causes(core); val |= e1000e_intmgr_collect_delayed_causes(core);
core->mac[ICR] |= val; e1000e_raise_interrupts(core, ICR, val);
trace_e1000e_irq_set_cause_exit(val, core->mac[ICR]);
e1000e_update_interrupt_state(core);
} }
static inline void static inline void
@ -2527,30 +2467,27 @@ e1000e_set_ics(E1000ECore *core, int index, uint32_t val)
static void static void
e1000e_set_icr(E1000ECore *core, int index, uint32_t val) e1000e_set_icr(E1000ECore *core, int index, uint32_t val)
{ {
uint32_t icr = 0;
if ((core->mac[ICR] & E1000_ICR_ASSERTED) && if ((core->mac[ICR] & E1000_ICR_ASSERTED) &&
(core->mac[CTRL_EXT] & E1000_CTRL_EXT_IAME)) { (core->mac[CTRL_EXT] & E1000_CTRL_EXT_IAME)) {
trace_e1000e_irq_icr_process_iame(); trace_e1000e_irq_icr_process_iame();
e1000e_clear_ims_bits(core, core->mac[IAM]); e1000e_lower_interrupts(core, IMS, core->mac[IAM]);
} }
icr = core->mac[ICR] & ~val;
/* /*
* Windows driver expects that the "receive overrun" bit and other * Windows driver expects that the "receive overrun" bit and other
* ones to be cleared when the "Other" bit (#24) is cleared. * ones to be cleared when the "Other" bit (#24) is cleared.
*/ */
icr = (val & E1000_ICR_OTHER) ? (icr & ~E1000_ICR_OTHER_CAUSES) : icr; if (val & E1000_ICR_OTHER) {
trace_e1000e_irq_icr_write(val, core->mac[ICR], icr); val |= E1000_ICR_OTHER_CAUSES;
core->mac[ICR] = icr; }
e1000e_update_interrupt_state(core); e1000e_lower_interrupts(core, ICR, val);
} }
static void static void
e1000e_set_imc(E1000ECore *core, int index, uint32_t val) e1000e_set_imc(E1000ECore *core, int index, uint32_t val)
{ {
trace_e1000e_irq_ims_clear_set_imc(val); trace_e1000e_irq_ims_clear_set_imc(val);
e1000e_clear_ims_bits(core, val); e1000e_lower_interrupts(core, IMS, val);
e1000e_update_interrupt_state(core);
} }
static void static void
@ -2571,9 +2508,6 @@ e1000e_set_ims(E1000ECore *core, int index, uint32_t val)
uint32_t valid_val = val & ims_valid_mask; uint32_t valid_val = val & ims_valid_mask;
trace_e1000e_irq_set_ims(val, core->mac[IMS], core->mac[IMS] | valid_val);
core->mac[IMS] |= valid_val;
if ((valid_val & ims_ext_mask) && if ((valid_val & ims_ext_mask) &&
(core->mac[CTRL_EXT] & E1000_CTRL_EXT_PBA_CLR) && (core->mac[CTRL_EXT] & E1000_CTRL_EXT_PBA_CLR) &&
msix_enabled(core->owner)) { msix_enabled(core->owner)) {
@ -2586,7 +2520,7 @@ e1000e_set_ims(E1000ECore *core, int index, uint32_t val)
e1000e_intrmgr_fire_all_timers(core); e1000e_intrmgr_fire_all_timers(core);
} }
e1000e_update_interrupt_state(core); e1000e_raise_interrupts(core, IMS, valid_val);
} }
static void static void
@ -2659,28 +2593,25 @@ static uint32_t
e1000e_mac_icr_read(E1000ECore *core, int index) e1000e_mac_icr_read(E1000ECore *core, int index)
{ {
uint32_t ret = core->mac[ICR]; uint32_t ret = core->mac[ICR];
trace_e1000e_irq_icr_read_entry(ret);
if (core->mac[IMS] == 0) { if (core->mac[IMS] == 0) {
trace_e1000e_irq_icr_clear_zero_ims(); trace_e1000e_irq_icr_clear_zero_ims();
core->mac[ICR] = 0; e1000e_lower_interrupts(core, ICR, 0xffffffff);
} }
if (!msix_enabled(core->owner)) { if (!msix_enabled(core->owner)) {
trace_e1000e_irq_icr_clear_nonmsix_icr_read(); trace_e1000e_irq_icr_clear_nonmsix_icr_read();
core->mac[ICR] = 0; e1000e_lower_interrupts(core, ICR, 0xffffffff);
} }
if ((core->mac[ICR] & E1000_ICR_ASSERTED) && if ((core->mac[ICR] & E1000_ICR_ASSERTED) &&
(core->mac[CTRL_EXT] & E1000_CTRL_EXT_IAME)) { (core->mac[CTRL_EXT] & E1000_CTRL_EXT_IAME)) {
trace_e1000e_irq_icr_clear_iame(); trace_e1000e_irq_icr_clear_iame();
core->mac[ICR] = 0; e1000e_lower_interrupts(core, ICR, 0xffffffff);
trace_e1000e_irq_icr_process_iame(); trace_e1000e_irq_icr_process_iame();
e1000e_clear_ims_bits(core, core->mac[IAM]); e1000e_lower_interrupts(core, IMS, core->mac[IAM]);
} }
trace_e1000e_irq_icr_read_exit(core->mac[ICR]);
e1000e_update_interrupt_state(core);
return ret; return ret;
} }
@ -3422,7 +3353,7 @@ e1000e_core_pci_realize(E1000ECore *core,
qemu_add_vm_change_state_handler(e1000e_vm_state_change, core); qemu_add_vm_change_state_handler(e1000e_vm_state_change, core);
for (i = 0; i < E1000E_NUM_QUEUES; i++) { 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); net_rx_pkt_init(&core->rx_pkt);
@ -3447,7 +3378,6 @@ e1000e_core_pci_uninit(E1000ECore *core)
qemu_del_vm_change_state_handler(core->vmstate); qemu_del_vm_change_state_handler(core->vmstate);
for (i = 0; i < E1000E_NUM_QUEUES; i++) { for (i = 0; i < E1000E_NUM_QUEUES; i++) {
net_tx_pkt_reset(core->tx[i].tx_pkt, core->owner);
net_tx_pkt_uninit(core->tx[i].tx_pkt); net_tx_pkt_uninit(core->tx[i].tx_pkt);
} }
@ -3572,7 +3502,6 @@ static void e1000e_reset(E1000ECore *core, bool sw)
e1000x_reset_mac_addr(core->owner_nic, core->mac, core->permanent_mac); e1000x_reset_mac_addr(core->owner_nic, core->mac, core->permanent_mac);
for (i = 0; i < ARRAY_SIZE(core->tx); i++) { for (i = 0; i < ARRAY_SIZE(core->tx); i++) {
net_tx_pkt_reset(core->tx[i].tx_pkt, core->owner);
memset(&core->tx[i].props, 0, sizeof(core->tx[i].props)); memset(&core->tx[i].props, 0, sizeof(core->tx[i].props));
core->tx[i].skip_cp = false; core->tx[i].skip_cp = false;
} }

View File

@ -111,8 +111,6 @@ struct E1000Core {
PCIDevice *owner; PCIDevice *owner;
void (*owner_start_recv)(PCIDevice *d); void (*owner_start_recv)(PCIDevice *d);
uint32_t msi_causes_pending;
int64_t timadj; int64_t timadj;
}; };

View File

@ -58,33 +58,64 @@ bool e1000x_is_vlan_packet(const void *buf, uint16_t vet)
return res; return res;
} }
bool e1000x_rx_group_filter(uint32_t *mac, const uint8_t *buf) bool e1000x_rx_vlan_filter(uint32_t *mac, const struct vlan_header *vhdr)
{
if (e1000x_vlan_rx_filter_enabled(mac)) {
uint16_t vid = lduw_be_p(&vhdr->h_tci);
uint32_t vfta =
ldl_le_p((uint32_t *)(mac + VFTA) +
((vid >> E1000_VFTA_ENTRY_SHIFT) & E1000_VFTA_ENTRY_MASK));
if ((vfta & (1 << (vid & E1000_VFTA_ENTRY_BIT_SHIFT_MASK))) == 0) {
trace_e1000x_rx_flt_vlan_mismatch(vid);
return false;
}
trace_e1000x_rx_flt_vlan_match(vid);
}
return true;
}
bool e1000x_rx_group_filter(uint32_t *mac, const struct eth_header *ehdr)
{ {
static const int mta_shift[] = { 4, 3, 2, 0 }; static const int mta_shift[] = { 4, 3, 2, 0 };
uint32_t f, ra[2], *rp, rctl = mac[RCTL]; uint32_t f, ra[2], *rp, rctl = mac[RCTL];
if (is_broadcast_ether_addr(ehdr->h_dest)) {
if (rctl & E1000_RCTL_BAM) {
return true;
}
} else if (is_multicast_ether_addr(ehdr->h_dest)) {
if (rctl & E1000_RCTL_MPE) {
return true;
}
} else {
if (rctl & E1000_RCTL_UPE) {
return true;
}
}
for (rp = mac + RA; rp < mac + RA + 32; rp += 2) { for (rp = mac + RA; rp < mac + RA + 32; rp += 2) {
if (!(rp[1] & E1000_RAH_AV)) { if (!(rp[1] & E1000_RAH_AV)) {
continue; continue;
} }
ra[0] = cpu_to_le32(rp[0]); ra[0] = cpu_to_le32(rp[0]);
ra[1] = cpu_to_le32(rp[1]); ra[1] = cpu_to_le32(rp[1]);
if (!memcmp(buf, (uint8_t *)ra, ETH_ALEN)) { if (!memcmp(ehdr->h_dest, (uint8_t *)ra, ETH_ALEN)) {
trace_e1000x_rx_flt_ucast_match((int)(rp - mac - RA) / 2, trace_e1000x_rx_flt_ucast_match((int)(rp - mac - RA) / 2,
MAC_ARG(buf)); MAC_ARG(ehdr->h_dest));
return true; return true;
} }
} }
trace_e1000x_rx_flt_ucast_mismatch(MAC_ARG(buf)); trace_e1000x_rx_flt_ucast_mismatch(MAC_ARG(ehdr->h_dest));
f = mta_shift[(rctl >> E1000_RCTL_MO_SHIFT) & 3]; f = mta_shift[(rctl >> E1000_RCTL_MO_SHIFT) & 3];
f = (((buf[5] << 8) | buf[4]) >> f) & 0xfff; f = (((ehdr->h_dest[5] << 8) | ehdr->h_dest[4]) >> f) & 0xfff;
if (mac[MTA + (f >> 5)] & (1 << (f & 0x1f))) { if (mac[MTA + (f >> 5)] & (1 << (f & 0x1f))) {
e1000x_inc_reg_if_not_full(mac, MPRC);
return true; return true;
} }
trace_e1000x_rx_flt_inexact_mismatch(MAC_ARG(buf), trace_e1000x_rx_flt_inexact_mismatch(MAC_ARG(ehdr->h_dest),
(rctl >> E1000_RCTL_MO_SHIFT) & 3, (rctl >> E1000_RCTL_MO_SHIFT) & 3,
f >> 5, f >> 5,
mac[MTA + (f >> 5)]); mac[MTA + (f >> 5)]);
@ -109,16 +140,16 @@ bool e1000x_hw_rx_enabled(uint32_t *mac)
bool e1000x_is_oversized(uint32_t *mac, size_t size) bool e1000x_is_oversized(uint32_t *mac, size_t size)
{ {
size_t header_size = sizeof(struct eth_header) + sizeof(struct vlan_header);
/* this is the size past which hardware will /* this is the size past which hardware will
drop packets when setting LPE=0 */ drop packets when setting LPE=0 */
static const int maximum_ethernet_vlan_size = 1522; size_t maximum_short_size = header_size + ETH_MTU;
/* this is the size past which hardware will /* this is the size past which hardware will
drop packets when setting LPE=1 */ drop packets when setting LPE=1 */
static const int maximum_ethernet_lpe_size = 16 * KiB; size_t maximum_large_size = 16 * KiB - ETH_FCS_LEN;
if ((size > maximum_ethernet_lpe_size || if ((size > maximum_large_size ||
(size > maximum_ethernet_vlan_size (size > maximum_short_size && !(mac[RCTL] & E1000_RCTL_LPE)))
&& !(mac[RCTL] & E1000_RCTL_LPE)))
&& !(mac[RCTL] & E1000_RCTL_SBP)) { && !(mac[RCTL] & E1000_RCTL_SBP)) {
e1000x_inc_reg_if_not_full(mac, ROC); e1000x_inc_reg_if_not_full(mac, ROC);
trace_e1000x_rx_oversized(size); trace_e1000x_rx_oversized(size);
@ -212,23 +243,36 @@ e1000x_rxbufsize(uint32_t rctl)
void void
e1000x_update_rx_total_stats(uint32_t *mac, e1000x_update_rx_total_stats(uint32_t *mac,
size_t data_size, eth_pkt_types_e pkt_type,
size_t data_fcs_size) size_t pkt_size,
size_t pkt_fcs_size)
{ {
static const int PRCregs[6] = { PRC64, PRC127, PRC255, PRC511, static const int PRCregs[6] = { PRC64, PRC127, PRC255, PRC511,
PRC1023, PRC1522 }; PRC1023, PRC1522 };
e1000x_increase_size_stats(mac, PRCregs, data_fcs_size); e1000x_increase_size_stats(mac, PRCregs, pkt_fcs_size);
e1000x_inc_reg_if_not_full(mac, TPR); e1000x_inc_reg_if_not_full(mac, TPR);
mac[GPRC] = mac[TPR]; e1000x_inc_reg_if_not_full(mac, GPRC);
/* TOR - Total Octets Received: /* TOR - Total Octets Received:
* This register includes bytes received in a packet from the <Destination * This register includes bytes received in a packet from the <Destination
* Address> field through the <CRC> field, inclusively. * Address> field through the <CRC> field, inclusively.
* Always include FCS length (4) in size. * Always include FCS length (4) in size.
*/ */
e1000x_grow_8reg_if_not_full(mac, TORL, data_size + 4); e1000x_grow_8reg_if_not_full(mac, TORL, pkt_size + 4);
mac[GORCL] = mac[TORL]; e1000x_grow_8reg_if_not_full(mac, GORCL, pkt_size + 4);
mac[GORCH] = mac[TORH];
switch (pkt_type) {
case ETH_PKT_BCAST:
e1000x_inc_reg_if_not_full(mac, BPRC);
break;
case ETH_PKT_MCAST:
e1000x_inc_reg_if_not_full(mac, MPRC);
break;
default:
break;
}
} }
void void

View File

@ -91,8 +91,9 @@ e1000x_update_regs_on_link_up(uint32_t *mac, uint16_t *phy)
} }
void e1000x_update_rx_total_stats(uint32_t *mac, void e1000x_update_rx_total_stats(uint32_t *mac,
size_t data_size, eth_pkt_types_e pkt_type,
size_t data_fcs_size); size_t pkt_size,
size_t pkt_fcs_size);
void e1000x_core_prepare_eeprom(uint16_t *eeprom, void e1000x_core_prepare_eeprom(uint16_t *eeprom,
const uint16_t *templ, const uint16_t *templ,
@ -106,7 +107,9 @@ bool e1000x_rx_ready(PCIDevice *d, uint32_t *mac);
bool e1000x_is_vlan_packet(const void *buf, uint16_t vet); bool e1000x_is_vlan_packet(const void *buf, uint16_t vet);
bool e1000x_rx_group_filter(uint32_t *mac, const uint8_t *buf); bool e1000x_rx_vlan_filter(uint32_t *mac, const struct vlan_header *vhdr);
bool e1000x_rx_group_filter(uint32_t *mac, const struct eth_header *ehdr);
bool e1000x_hw_rx_enabled(uint32_t *mac); bool e1000x_hw_rx_enabled(uint32_t *mac);

View File

@ -292,14 +292,14 @@
#define E1000_MRQC_EN_TCPIPV4(mrqc) ((mrqc) & BIT(16)) #define E1000_MRQC_EN_TCPIPV4(mrqc) ((mrqc) & BIT(16))
#define E1000_MRQC_EN_IPV4(mrqc) ((mrqc) & BIT(17)) #define E1000_MRQC_EN_IPV4(mrqc) ((mrqc) & BIT(17))
#define E1000_MRQC_EN_TCPIPV6(mrqc) ((mrqc) & BIT(18)) #define E1000_MRQC_EN_TCPIPV6EX(mrqc) ((mrqc) & BIT(18))
#define E1000_MRQC_EN_IPV6EX(mrqc) ((mrqc) & BIT(19)) #define E1000_MRQC_EN_IPV6EX(mrqc) ((mrqc) & BIT(19))
#define E1000_MRQC_EN_IPV6(mrqc) ((mrqc) & BIT(20)) #define E1000_MRQC_EN_IPV6(mrqc) ((mrqc) & BIT(20))
#define E1000_MRQ_RSS_TYPE_NONE (0) #define E1000_MRQ_RSS_TYPE_NONE (0)
#define E1000_MRQ_RSS_TYPE_IPV4TCP (1) #define E1000_MRQ_RSS_TYPE_IPV4TCP (1)
#define E1000_MRQ_RSS_TYPE_IPV4 (2) #define E1000_MRQ_RSS_TYPE_IPV4 (2)
#define E1000_MRQ_RSS_TYPE_IPV6TCP (3) #define E1000_MRQ_RSS_TYPE_IPV6TCPEX (3)
#define E1000_MRQ_RSS_TYPE_IPV6EX (4) #define E1000_MRQ_RSS_TYPE_IPV6EX (4)
#define E1000_MRQ_RSS_TYPE_IPV6 (5) #define E1000_MRQ_RSS_TYPE_IPV6 (5)

View File

@ -433,16 +433,16 @@ static void igb_pci_realize(PCIDevice *pci_dev, Error **errp)
pcie_ari_init(pci_dev, 0x150, 1); pcie_ari_init(pci_dev, 0x150, 1);
pcie_sriov_pf_init(pci_dev, IGB_CAP_SRIOV_OFFSET, "igbvf", pcie_sriov_pf_init(pci_dev, IGB_CAP_SRIOV_OFFSET, TYPE_IGBVF,
IGB_82576_VF_DEV_ID, IGB_MAX_VF_FUNCTIONS, IGB_MAX_VF_FUNCTIONS, IGB_82576_VF_DEV_ID, IGB_MAX_VF_FUNCTIONS, IGB_MAX_VF_FUNCTIONS,
IGB_VF_OFFSET, IGB_VF_STRIDE); IGB_VF_OFFSET, IGB_VF_STRIDE);
pcie_sriov_pf_init_vf_bar(pci_dev, 0, pcie_sriov_pf_init_vf_bar(pci_dev, IGBVF_MMIO_BAR_IDX,
PCI_BASE_ADDRESS_MEM_TYPE_64 | PCI_BASE_ADDRESS_MEM_PREFETCH, PCI_BASE_ADDRESS_MEM_TYPE_64 | PCI_BASE_ADDRESS_MEM_PREFETCH,
16 * KiB); IGBVF_MMIO_SIZE);
pcie_sriov_pf_init_vf_bar(pci_dev, 3, pcie_sriov_pf_init_vf_bar(pci_dev, IGBVF_MSIX_BAR_IDX,
PCI_BASE_ADDRESS_MEM_TYPE_64 | PCI_BASE_ADDRESS_MEM_PREFETCH, PCI_BASE_ADDRESS_MEM_TYPE_64 | PCI_BASE_ADDRESS_MEM_PREFETCH,
16 * KiB); IGBVF_MSIX_SIZE);
igb_init_net_peer(s, pci_dev, macaddr); igb_init_net_peer(s, pci_dev, macaddr);

View File

@ -28,6 +28,14 @@
#include "igb_regs.h" #include "igb_regs.h"
#define TYPE_IGBVF "igbvf"
#define IGBVF_MMIO_BAR_IDX (0)
#define IGBVF_MSIX_BAR_IDX (3)
#define IGBVF_MMIO_SIZE (16 * 1024)
#define IGBVF_MSIX_SIZE (16 * 1024)
#define defreg(x) x = (E1000_##x >> 2) #define defreg(x) x = (E1000_##x >> 2)
#define defreg_indexed(x, i) x##i = (E1000_##x(i) >> 2) #define defreg_indexed(x, i) x##i = (E1000_##x(i) >> 2)
#define defreg_indexeda(x, i) x##i##_A = (E1000_##x##_A(i) >> 2) #define defreg_indexeda(x, i) x##i##_A = (E1000_##x##_A(i) >> 2)
@ -43,7 +51,7 @@
defreg_indexeda(x, 0), defreg_indexeda(x, 1), \ defreg_indexeda(x, 0), defreg_indexeda(x, 1), \
defreg_indexeda(x, 2), defreg_indexeda(x, 3) defreg_indexeda(x, 2), defreg_indexeda(x, 3)
#define defregv(x) defreg_indexed(x, 0), defreg_indexed(x, 1), \ #define defreg8(x) defreg_indexed(x, 0), defreg_indexed(x, 1), \
defreg_indexed(x, 2), defreg_indexed(x, 3), \ defreg_indexed(x, 2), defreg_indexed(x, 3), \
defreg_indexed(x, 4), defreg_indexed(x, 5), \ defreg_indexed(x, 4), defreg_indexed(x, 5), \
defreg_indexed(x, 6), defreg_indexed(x, 7) defreg_indexed(x, 6), defreg_indexed(x, 7)
@ -114,6 +122,8 @@ enum {
defreg(EICS), defreg(EIMS), defreg(EIMC), defreg(EIAM), defreg(EICS), defreg(EIMS), defreg(EIMC), defreg(EIAM),
defreg(EICR), defreg(IVAR_MISC), defreg(GPIE), defreg(EICR), defreg(IVAR_MISC), defreg(GPIE),
defreg(TSYNCRXCFG), defreg8(ETQF),
defreg(RXPBS), defregd(RDBAL), defregd(RDBAH), defregd(RDLEN), defreg(RXPBS), defregd(RDBAL), defregd(RDBAH), defregd(RDLEN),
defregd(SRRCTL), defregd(RDH), defregd(RDT), defregd(SRRCTL), defregd(RDH), defregd(RDT),
defregd(RXDCTL), defregd(RXCTL), defregd(RQDPC), defreg(RA2), defregd(RXDCTL), defregd(RXCTL), defregd(RQDPC), defreg(RA2),
@ -125,15 +135,15 @@ enum {
defreg(VT_CTL), defreg(VT_CTL),
defregv(P2VMAILBOX), defregv(V2PMAILBOX), defreg(MBVFICR), defreg(MBVFIMR), defreg8(P2VMAILBOX), defreg8(V2PMAILBOX), defreg(MBVFICR), defreg(MBVFIMR),
defreg(VFLRE), defreg(VFRE), defreg(VFTE), defreg(WVBR), defreg(VFLRE), defreg(VFRE), defreg(VFTE), defreg(WVBR),
defreg(QDE), defreg(DTXSWC), defreg_indexed(VLVF, 0), defreg(QDE), defreg(DTXSWC), defreg_indexed(VLVF, 0),
defregv(VMOLR), defreg(RPLOLR), defregv(VMBMEM), defregv(VMVIR), defreg8(VMOLR), defreg(RPLOLR), defreg8(VMBMEM), defreg8(VMVIR),
defregv(PVTCTRL), defregv(PVTEICS), defregv(PVTEIMS), defregv(PVTEIMC), defreg8(PVTCTRL), defreg8(PVTEICS), defreg8(PVTEIMS), defreg8(PVTEIMC),
defregv(PVTEIAC), defregv(PVTEIAM), defregv(PVTEICR), defregv(PVFGPRC), defreg8(PVTEIAC), defreg8(PVTEIAM), defreg8(PVTEICR), defreg8(PVFGPRC),
defregv(PVFGPTC), defregv(PVFGORC), defregv(PVFGOTC), defregv(PVFMPRC), defreg8(PVFGPTC), defreg8(PVFGORC), defreg8(PVFGOTC), defreg8(PVFMPRC),
defregv(PVFGPRLBC), defregv(PVFGPTLBC), defregv(PVFGORLBC), defregv(PVFGOTLBC), defreg8(PVFGPRLBC), defreg8(PVFGPTLBC), defreg8(PVFGORLBC), defreg8(PVFGOTLBC),
defreg(MTA_A), defreg(MTA_A),

File diff suppressed because it is too large Load Diff

View File

@ -42,11 +42,6 @@ union e1000_adv_tx_desc {
} wb; } wb;
}; };
#define E1000_ADVTXD_DTYP_CTXT 0x00200000 /* Advanced Context Descriptor */
#define E1000_ADVTXD_DTYP_DATA 0x00300000 /* Advanced Data Descriptor */
#define E1000_ADVTXD_DCMD_DEXT 0x20000000 /* Descriptor Extension (1=Adv) */
#define E1000_ADVTXD_DCMD_TSE 0x80000000 /* TCP/UDP Segmentation Enable */
#define E1000_ADVTXD_POTS_IXSM 0x00000100 /* Insert TCP/UDP Checksum */ #define E1000_ADVTXD_POTS_IXSM 0x00000100 /* Insert TCP/UDP Checksum */
#define E1000_ADVTXD_POTS_TXSM 0x00000200 /* Insert TCP/UDP Checksum */ #define E1000_ADVTXD_POTS_TXSM 0x00000200 /* Insert TCP/UDP Checksum */
@ -151,6 +146,10 @@ union e1000_adv_rx_desc {
#define IGB_82576_VF_DEV_ID 0x10CA #define IGB_82576_VF_DEV_ID 0x10CA
#define IGB_I350_VF_DEV_ID 0x1520 #define IGB_I350_VF_DEV_ID 0x1520
/* VLAN info */
#define IGB_TX_FLAGS_VLAN_MASK 0xffff0000
#define IGB_TX_FLAGS_VLAN_SHIFT 16
/* from igb/e1000_82575.h */ /* from igb/e1000_82575.h */
#define E1000_MRQC_ENABLE_RSS_MQ 0x00000002 #define E1000_MRQC_ENABLE_RSS_MQ 0x00000002
@ -160,6 +159,29 @@ union e1000_adv_rx_desc {
#define E1000_MRQC_RSS_FIELD_IPV6_UDP 0x00800000 #define E1000_MRQC_RSS_FIELD_IPV6_UDP 0x00800000
#define E1000_MRQC_RSS_FIELD_IPV6_UDP_EX 0x01000000 #define E1000_MRQC_RSS_FIELD_IPV6_UDP_EX 0x01000000
/* Adv Transmit Descriptor Config Masks */
#define E1000_ADVTXD_MAC_TSTAMP 0x00080000 /* IEEE1588 Timestamp packet */
#define E1000_ADVTXD_DTYP_CTXT 0x00200000 /* Advanced Context Descriptor */
#define E1000_ADVTXD_DTYP_DATA 0x00300000 /* Advanced Data Descriptor */
#define E1000_ADVTXD_DCMD_EOP 0x01000000 /* End of Packet */
#define E1000_ADVTXD_DCMD_IFCS 0x02000000 /* Insert FCS (Ethernet CRC) */
#define E1000_ADVTXD_DCMD_RS 0x08000000 /* Report Status */
#define E1000_ADVTXD_DCMD_DEXT 0x20000000 /* Descriptor extension (1=Adv) */
#define E1000_ADVTXD_DCMD_VLE 0x40000000 /* VLAN pkt enable */
#define E1000_ADVTXD_DCMD_TSE 0x80000000 /* TCP Seg enable */
#define E1000_ADVTXD_PAYLEN_SHIFT 14 /* Adv desc PAYLEN shift */
#define E1000_ADVTXD_MACLEN_SHIFT 9 /* Adv ctxt desc mac len shift */
#define E1000_ADVTXD_TUCMD_L4T_UDP 0x00000000 /* L4 Packet TYPE of UDP */
#define E1000_ADVTXD_TUCMD_IPV4 0x00000400 /* IP Packet Type: 1=IPv4 */
#define E1000_ADVTXD_TUCMD_L4T_TCP 0x00000800 /* L4 Packet TYPE of TCP */
#define E1000_ADVTXD_TUCMD_L4T_SCTP 0x00001000 /* L4 packet TYPE of SCTP */
/* IPSec Encrypt Enable for ESP */
#define E1000_ADVTXD_L4LEN_SHIFT 8 /* Adv ctxt L4LEN shift */
#define E1000_ADVTXD_MSS_SHIFT 16 /* Adv ctxt MSS shift */
/* Adv ctxt IPSec SA IDX mask */
/* Adv ctxt IPSec ESP len mask */
/* Additional Transmit Descriptor Control definitions */ /* Additional Transmit Descriptor Control definitions */
#define E1000_TXDCTL_QUEUE_ENABLE 0x02000000 /* Enable specific Tx Queue */ #define E1000_TXDCTL_QUEUE_ENABLE 0x02000000 /* Enable specific Tx Queue */
@ -188,6 +210,15 @@ union e1000_adv_rx_desc {
#define E1000_DCA_TXCTRL_CPUID_SHIFT 24 /* Tx CPUID now in the last byte */ #define E1000_DCA_TXCTRL_CPUID_SHIFT 24 /* Tx CPUID now in the last byte */
#define E1000_DCA_RXCTRL_CPUID_SHIFT 24 /* Rx CPUID now in the last byte */ #define E1000_DCA_RXCTRL_CPUID_SHIFT 24 /* Rx CPUID now in the last byte */
/* ETQF register bit definitions */
#define E1000_ETQF_FILTER_ENABLE BIT(26)
#define E1000_ETQF_1588 BIT(30)
#define E1000_ETQF_IMM_INT BIT(29)
#define E1000_ETQF_QUEUE_ENABLE BIT(31)
#define E1000_ETQF_QUEUE_SHIFT 16
#define E1000_ETQF_QUEUE_MASK 0x00070000
#define E1000_ETQF_ETYPE_MASK 0x0000FFFF
#define E1000_DTXSWC_MAC_SPOOF_MASK 0x000000FF /* Per VF MAC spoof control */ #define E1000_DTXSWC_MAC_SPOOF_MASK 0x000000FF /* Per VF MAC spoof control */
#define E1000_DTXSWC_VLAN_SPOOF_MASK 0x0000FF00 /* Per VF VLAN spoof control */ #define E1000_DTXSWC_VLAN_SPOOF_MASK 0x0000FF00 /* Per VF VLAN spoof control */
#define E1000_DTXSWC_LLE_MASK 0x00FF0000 /* Per VF Local LB enables */ #define E1000_DTXSWC_LLE_MASK 0x00FF0000 /* Per VF Local LB enables */
@ -291,6 +322,9 @@ union e1000_adv_rx_desc {
/* E1000_EITR_CNT_IGNR is only for 82576 and newer */ /* E1000_EITR_CNT_IGNR is only for 82576 and newer */
#define E1000_EITR_CNT_IGNR 0x80000000 /* Don't reset counters on write */ #define E1000_EITR_CNT_IGNR 0x80000000 /* Don't reset counters on write */
#define E1000_TSYNCTXCTL_VALID 0x00000001 /* tx timestamp valid */
#define E1000_TSYNCTXCTL_ENABLED 0x00000010 /* enable tx timestampping */
/* PCI Express Control */ /* PCI Express Control */
#define E1000_GCR_CMPL_TMOUT_MASK 0x0000F000 #define E1000_GCR_CMPL_TMOUT_MASK 0x0000F000
#define E1000_GCR_CMPL_TMOUT_10ms 0x00001000 #define E1000_GCR_CMPL_TMOUT_10ms 0x00001000
@ -362,6 +396,20 @@ union e1000_adv_rx_desc {
#define E1000_FRTIMER 0x01048 /* Free Running Timer - RW */ #define E1000_FRTIMER 0x01048 /* Free Running Timer - RW */
#define E1000_FCRTV 0x02460 /* Flow Control Refresh Timer Value - RW */ #define E1000_FCRTV 0x02460 /* Flow Control Refresh Timer Value - RW */
#define E1000_TSYNCRXCFG 0x05F50 /* Time Sync Rx Configuration - RW */
/* Filtering Registers */
#define E1000_SAQF(_n) (0x5980 + 4 * (_n))
#define E1000_DAQF(_n) (0x59A0 + 4 * (_n))
#define E1000_SPQF(_n) (0x59C0 + 4 * (_n))
#define E1000_FTQF(_n) (0x59E0 + 4 * (_n))
#define E1000_SAQF0 E1000_SAQF(0)
#define E1000_DAQF0 E1000_DAQF(0)
#define E1000_SPQF0 E1000_SPQF(0)
#define E1000_FTQF0 E1000_FTQF(0)
#define E1000_SYNQF(_n) (0x055FC + (4 * (_n))) /* SYN Packet Queue Fltr */
#define E1000_ETQF(_n) (0x05CB0 + (4 * (_n))) /* EType Queue Fltr */
#define E1000_RQDPC(_n) (0x0C030 + ((_n) * 0x40)) #define E1000_RQDPC(_n) (0x0C030 + ((_n) * 0x40))
#define E1000_RXPBS 0x02404 /* Rx Packet Buffer Size - RW */ #define E1000_RXPBS 0x02404 /* Rx Packet Buffer Size - RW */
@ -637,10 +685,19 @@ union e1000_adv_rx_desc {
#define E1000_RSS_QUEUE(reta, hash) (E1000_RETA_VAL(reta, hash) & 0x0F) #define E1000_RSS_QUEUE(reta, hash) (E1000_RETA_VAL(reta, hash) & 0x0F)
#define E1000_MRQ_RSS_TYPE_IPV4UDP 7
#define E1000_MRQ_RSS_TYPE_IPV6UDP 8
#define E1000_STATUS_IOV_MODE 0x00040000 #define E1000_STATUS_IOV_MODE 0x00040000
#define E1000_STATUS_NUM_VFS_SHIFT 14 #define E1000_STATUS_NUM_VFS_SHIFT 14
#define E1000_ADVRXD_PKT_IP4 BIT(4)
#define E1000_ADVRXD_PKT_IP6 BIT(6)
#define E1000_ADVRXD_PKT_TCP BIT(8)
#define E1000_ADVRXD_PKT_UDP BIT(9)
#define E1000_ADVRXD_PKT_SCTP BIT(10)
static inline uint8_t igb_ivar_entry_rx(uint8_t i) static inline uint8_t igb_ivar_entry_rx(uint8_t i)
{ {
return i < 8 ? i * 4 : (i - 8) * 4 + 2; return i < 8 ? i * 4 : (i - 8) * 4 + 2;

View File

@ -50,15 +50,8 @@
#include "trace.h" #include "trace.h"
#include "qapi/error.h" #include "qapi/error.h"
#define TYPE_IGBVF "igbvf"
OBJECT_DECLARE_SIMPLE_TYPE(IgbVfState, IGBVF) OBJECT_DECLARE_SIMPLE_TYPE(IgbVfState, IGBVF)
#define IGBVF_MMIO_BAR_IDX (0)
#define IGBVF_MSIX_BAR_IDX (3)
#define IGBVF_MMIO_SIZE (16 * 1024)
#define IGBVF_MSIX_SIZE (16 * 1024)
struct IgbVfState { struct IgbVfState {
PCIDevice parent_obj; PCIDevice parent_obj;

View File

@ -16,6 +16,7 @@
*/ */
#include "qemu/osdep.h" #include "qemu/osdep.h"
#include "qemu/crc32c.h"
#include "trace.h" #include "trace.h"
#include "net_rx_pkt.h" #include "net_rx_pkt.h"
#include "net/checksum.h" #include "net/checksum.h"
@ -23,7 +24,10 @@
struct NetRxPkt { struct NetRxPkt {
struct virtio_net_hdr virt_hdr; struct virtio_net_hdr virt_hdr;
uint8_t ehdr_buf[sizeof(struct eth_header) + sizeof(struct vlan_header)]; struct {
struct eth_header eth;
struct vlan_header vlan;
} ehdr_buf;
struct iovec *vec; struct iovec *vec;
uint16_t vec_len_total; uint16_t vec_len_total;
uint16_t vec_len; uint16_t vec_len;
@ -89,7 +93,7 @@ net_rx_pkt_pull_data(struct NetRxPkt *pkt,
if (pkt->ehdr_buf_len) { if (pkt->ehdr_buf_len) {
net_rx_pkt_iovec_realloc(pkt, iovcnt + 1); net_rx_pkt_iovec_realloc(pkt, iovcnt + 1);
pkt->vec[0].iov_base = pkt->ehdr_buf; pkt->vec[0].iov_base = &pkt->ehdr_buf;
pkt->vec[0].iov_len = pkt->ehdr_buf_len; pkt->vec[0].iov_len = pkt->ehdr_buf_len;
pkt->tot_len = pllen + pkt->ehdr_buf_len; pkt->tot_len = pllen + pkt->ehdr_buf_len;
@ -103,7 +107,7 @@ net_rx_pkt_pull_data(struct NetRxPkt *pkt,
iov, iovcnt, ploff, pkt->tot_len); iov, iovcnt, ploff, pkt->tot_len);
} }
eth_get_protocols(pkt->vec, pkt->vec_len, &pkt->hasip4, &pkt->hasip6, eth_get_protocols(pkt->vec, pkt->vec_len, 0, &pkt->hasip4, &pkt->hasip6,
&pkt->l3hdr_off, &pkt->l4hdr_off, &pkt->l5hdr_off, &pkt->l3hdr_off, &pkt->l4hdr_off, &pkt->l5hdr_off,
&pkt->ip6hdr_info, &pkt->ip4hdr_info, &pkt->l4hdr_info); &pkt->ip6hdr_info, &pkt->ip4hdr_info, &pkt->l4hdr_info);
@ -120,7 +124,7 @@ void net_rx_pkt_attach_iovec(struct NetRxPkt *pkt,
assert(pkt); assert(pkt);
if (strip_vlan) { if (strip_vlan) {
pkt->ehdr_buf_len = eth_strip_vlan(iov, iovcnt, iovoff, pkt->ehdr_buf, pkt->ehdr_buf_len = eth_strip_vlan(iov, iovcnt, iovoff, &pkt->ehdr_buf,
&ploff, &tci); &ploff, &tci);
} else { } else {
pkt->ehdr_buf_len = 0; pkt->ehdr_buf_len = 0;
@ -133,20 +137,17 @@ void net_rx_pkt_attach_iovec(struct NetRxPkt *pkt,
void net_rx_pkt_attach_iovec_ex(struct NetRxPkt *pkt, void net_rx_pkt_attach_iovec_ex(struct NetRxPkt *pkt,
const struct iovec *iov, int iovcnt, const struct iovec *iov, int iovcnt,
size_t iovoff, bool strip_vlan, size_t iovoff, int strip_vlan_index,
uint16_t vet) uint16_t vet, uint16_t vet_ext)
{ {
uint16_t tci = 0; uint16_t tci = 0;
uint16_t ploff = iovoff; uint16_t ploff = iovoff;
assert(pkt); assert(pkt);
if (strip_vlan) { pkt->ehdr_buf_len = eth_strip_vlan_ex(iov, iovcnt, iovoff,
pkt->ehdr_buf_len = eth_strip_vlan_ex(iov, iovcnt, iovoff, vet, strip_vlan_index, vet, vet_ext,
pkt->ehdr_buf, &pkt->ehdr_buf,
&ploff, &tci); &ploff, &tci);
} else {
pkt->ehdr_buf_len = 0;
}
pkt->tci = tci; pkt->tci = tci;
@ -186,17 +187,13 @@ size_t net_rx_pkt_get_total_len(struct NetRxPkt *pkt)
return pkt->tot_len; return pkt->tot_len;
} }
void net_rx_pkt_set_protocols(struct NetRxPkt *pkt, const void *data, void net_rx_pkt_set_protocols(struct NetRxPkt *pkt,
size_t len) const struct iovec *iov, size_t iovcnt,
size_t iovoff)
{ {
const struct iovec iov = {
.iov_base = (void *)data,
.iov_len = len
};
assert(pkt); assert(pkt);
eth_get_protocols(&iov, 1, &pkt->hasip4, &pkt->hasip6, eth_get_protocols(iov, iovcnt, iovoff, &pkt->hasip4, &pkt->hasip6,
&pkt->l3hdr_off, &pkt->l4hdr_off, &pkt->l5hdr_off, &pkt->l3hdr_off, &pkt->l4hdr_off, &pkt->l5hdr_off,
&pkt->ip6hdr_info, &pkt->ip4hdr_info, &pkt->l4hdr_info); &pkt->ip6hdr_info, &pkt->ip4hdr_info, &pkt->l4hdr_info);
} }
@ -240,11 +237,6 @@ eth_ip4_hdr_info *net_rx_pkt_get_ip4_info(struct NetRxPkt *pkt)
return &pkt->ip4hdr_info; return &pkt->ip4hdr_info;
} }
eth_l4_hdr_info *net_rx_pkt_get_l4_info(struct NetRxPkt *pkt)
{
return &pkt->l4hdr_info;
}
static inline void static inline void
_net_rx_rss_add_chunk(uint8_t *rss_input, size_t *bytes_written, _net_rx_rss_add_chunk(uint8_t *rss_input, size_t *bytes_written,
void *ptr, size_t size) void *ptr, size_t size)
@ -560,32 +552,73 @@ _net_rx_pkt_calc_l4_csum(struct NetRxPkt *pkt)
return csum; return csum;
} }
static bool
_net_rx_pkt_validate_sctp_sum(struct NetRxPkt *pkt)
{
size_t csum_off;
size_t off = pkt->l4hdr_off;
size_t vec_len = pkt->vec_len;
struct iovec *vec;
uint32_t calculated = 0;
uint32_t original;
bool valid;
for (vec = pkt->vec; vec->iov_len < off; vec++) {
off -= vec->iov_len;
vec_len--;
}
csum_off = off + 8;
if (!iov_to_buf(vec, vec_len, csum_off, &original, sizeof(original))) {
return false;
}
if (!iov_from_buf(vec, vec_len, csum_off,
&calculated, sizeof(calculated))) {
return false;
}
calculated = crc32c(0xffffffff,
(uint8_t *)vec->iov_base + off, vec->iov_len - off);
calculated = iov_crc32c(calculated ^ 0xffffffff, vec + 1, vec_len - 1);
valid = calculated == le32_to_cpu(original);
iov_from_buf(vec, vec_len, csum_off, &original, sizeof(original));
return valid;
}
bool net_rx_pkt_validate_l4_csum(struct NetRxPkt *pkt, bool *csum_valid) bool net_rx_pkt_validate_l4_csum(struct NetRxPkt *pkt, bool *csum_valid)
{ {
uint16_t csum; uint32_t csum;
trace_net_rx_pkt_l4_csum_validate_entry(); trace_net_rx_pkt_l4_csum_validate_entry();
if (pkt->l4hdr_info.proto != ETH_L4_HDR_PROTO_TCP &&
pkt->l4hdr_info.proto != ETH_L4_HDR_PROTO_UDP) {
trace_net_rx_pkt_l4_csum_validate_not_xxp();
return false;
}
if (pkt->l4hdr_info.proto == ETH_L4_HDR_PROTO_UDP &&
pkt->l4hdr_info.hdr.udp.uh_sum == 0) {
trace_net_rx_pkt_l4_csum_validate_udp_with_no_checksum();
return false;
}
if (pkt->hasip4 && pkt->ip4hdr_info.fragment) { if (pkt->hasip4 && pkt->ip4hdr_info.fragment) {
trace_net_rx_pkt_l4_csum_validate_ip4_fragment(); trace_net_rx_pkt_l4_csum_validate_ip4_fragment();
return false; return false;
} }
switch (pkt->l4hdr_info.proto) {
case ETH_L4_HDR_PROTO_UDP:
if (pkt->l4hdr_info.hdr.udp.uh_sum == 0) {
trace_net_rx_pkt_l4_csum_validate_udp_with_no_checksum();
return false;
}
/* fall through */
case ETH_L4_HDR_PROTO_TCP:
csum = _net_rx_pkt_calc_l4_csum(pkt); csum = _net_rx_pkt_calc_l4_csum(pkt);
*csum_valid = ((csum == 0) || (csum == 0xFFFF)); *csum_valid = ((csum == 0) || (csum == 0xFFFF));
break;
case ETH_L4_HDR_PROTO_SCTP:
*csum_valid = _net_rx_pkt_validate_sctp_sum(pkt);
break;
default:
trace_net_rx_pkt_l4_csum_validate_not_xxp();
return false;
}
trace_net_rx_pkt_l4_csum_validate_csum(*csum_valid); trace_net_rx_pkt_l4_csum_validate_csum(*csum_valid);

View File

@ -55,12 +55,14 @@ size_t net_rx_pkt_get_total_len(struct NetRxPkt *pkt);
* parse and set packet analysis results * parse and set packet analysis results
* *
* @pkt: packet * @pkt: packet
* @data: pointer to the data buffer to be parsed * @iov: received data scatter-gather list
* @len: data length * @iovcnt: number of elements in iov
* @iovoff: data start offset in the iov
* *
*/ */
void net_rx_pkt_set_protocols(struct NetRxPkt *pkt, const void *data, void net_rx_pkt_set_protocols(struct NetRxPkt *pkt,
size_t len); const struct iovec *iov, size_t iovcnt,
size_t iovoff);
/** /**
* fetches packet analysis results * fetches packet analysis results
@ -117,15 +119,6 @@ eth_ip6_hdr_info *net_rx_pkt_get_ip6_info(struct NetRxPkt *pkt);
*/ */
eth_ip4_hdr_info *net_rx_pkt_get_ip4_info(struct NetRxPkt *pkt); eth_ip4_hdr_info *net_rx_pkt_get_ip4_info(struct NetRxPkt *pkt);
/**
* fetches L4 header analysis results
*
* Return: pointer to analysis results structure which is stored in internal
* packet area.
*
*/
eth_l4_hdr_info *net_rx_pkt_get_l4_info(struct NetRxPkt *pkt);
typedef enum { typedef enum {
NetPktRssIpV4, NetPktRssIpV4,
NetPktRssIpV4Tcp, NetPktRssIpV4Tcp,
@ -232,16 +225,17 @@ void net_rx_pkt_attach_iovec(struct NetRxPkt *pkt,
* *
* @pkt: packet * @pkt: packet
* @iov: received data scatter-gather list * @iov: received data scatter-gather list
* @iovcnt number of elements in iov * @iovcnt: number of elements in iov
* @iovoff data start offset in the iov * @iovoff: data start offset in the iov
* @strip_vlan: should the module strip vlan from data * @strip_vlan_index: index of Q tag if it is to be stripped. negative otherwise.
* @vet: VLAN tag Ethernet type * @vet: VLAN tag Ethernet type
* @vet_ext: outer VLAN tag Ethernet type
* *
*/ */
void net_rx_pkt_attach_iovec_ex(struct NetRxPkt *pkt, void net_rx_pkt_attach_iovec_ex(struct NetRxPkt *pkt,
const struct iovec *iov, int iovcnt, const struct iovec *iov, int iovcnt,
size_t iovoff, bool strip_vlan, size_t iovoff, int strip_vlan_index,
uint16_t vet); uint16_t vet, uint16_t vet_ext);
/** /**
* attach data to rx packet * attach data to rx packet

View File

@ -16,12 +16,13 @@
*/ */
#include "qemu/osdep.h" #include "qemu/osdep.h"
#include "net_tx_pkt.h" #include "qemu/crc32c.h"
#include "net/eth.h" #include "net/eth.h"
#include "net/checksum.h" #include "net/checksum.h"
#include "net/tap.h" #include "net/tap.h"
#include "net/net.h" #include "net/net.h"
#include "hw/pci/pci_device.h" #include "hw/pci/pci_device.h"
#include "net_tx_pkt.h"
enum { enum {
NET_TX_PKT_VHDR_FRAG = 0, NET_TX_PKT_VHDR_FRAG = 0,
@ -32,8 +33,6 @@ enum {
/* TX packet private context */ /* TX packet private context */
struct NetTxPkt { struct NetTxPkt {
PCIDevice *pci_dev;
struct virtio_net_hdr virt_hdr; struct virtio_net_hdr virt_hdr;
struct iovec *raw; struct iovec *raw;
@ -42,7 +41,10 @@ struct NetTxPkt {
struct iovec *vec; 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 { union {
struct ip_header ip; struct ip_header ip;
struct ip6_header ip6; struct ip6_header ip6;
@ -59,13 +61,10 @@ struct NetTxPkt {
uint8_t l4proto; uint8_t l4proto;
}; };
void net_tx_pkt_init(struct NetTxPkt **pkt, PCIDevice *pci_dev, void net_tx_pkt_init(struct NetTxPkt **pkt, uint32_t max_frags)
uint32_t max_frags)
{ {
struct NetTxPkt *p = g_malloc0(sizeof *p); 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->vec = g_new(struct iovec, max_frags + NET_TX_PKT_PL_START_FRAG);
p->raw = g_new(struct iovec, max_frags); p->raw = g_new(struct iovec, max_frags);
@ -137,6 +136,23 @@ void net_tx_pkt_update_ip_checksums(struct NetTxPkt *pkt)
pkt->virt_hdr.csum_offset, &csum, sizeof(csum)); 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) static void net_tx_pkt_calculate_hdr_len(struct NetTxPkt *pkt)
{ {
pkt->hdr_len = pkt->vec[NET_TX_PKT_L2HDR_FRAG].iov_len + pkt->hdr_len = pkt->vec[NET_TX_PKT_L2HDR_FRAG].iov_len +
@ -370,24 +386,17 @@ bool net_tx_pkt_build_vheader(struct NetTxPkt *pkt, bool tso_enable,
void net_tx_pkt_setup_vlan_header_ex(struct NetTxPkt *pkt, void net_tx_pkt_setup_vlan_header_ex(struct NetTxPkt *pkt,
uint16_t vlan, uint16_t vlan_ethtype) uint16_t vlan, uint16_t vlan_ethtype)
{ {
bool is_new;
assert(pkt); 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); &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->hdr_len += sizeof(struct vlan_header);
pkt->vec[NET_TX_PKT_L2HDR_FRAG].iov_len +=
sizeof(struct vlan_header);
}
} }
bool net_tx_pkt_add_raw_fragment(struct NetTxPkt *pkt, hwaddr pa, bool net_tx_pkt_add_raw_fragment(struct NetTxPkt *pkt, void *base, size_t len)
size_t len)
{ {
hwaddr mapped_len = 0;
struct iovec *ventry; struct iovec *ventry;
assert(pkt); assert(pkt);
@ -395,23 +404,12 @@ bool net_tx_pkt_add_raw_fragment(struct NetTxPkt *pkt, hwaddr pa,
return false; return false;
} }
if (!len) {
return true;
}
ventry = &pkt->raw[pkt->raw_frags]; ventry = &pkt->raw[pkt->raw_frags];
mapped_len = len; ventry->iov_base = base;
ventry->iov_len = len;
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++; pkt->raw_frags++;
return true; return true;
} else {
return false;
}
} }
bool net_tx_pkt_has_fragments(struct NetTxPkt *pkt) bool net_tx_pkt_has_fragments(struct NetTxPkt *pkt)
@ -445,7 +443,8 @@ void net_tx_pkt_dump(struct NetTxPkt *pkt)
#endif #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; int i;
@ -465,17 +464,37 @@ void net_tx_pkt_reset(struct NetTxPkt *pkt, PCIDevice *pci_dev)
assert(pkt->raw); assert(pkt->raw);
for (i = 0; i < pkt->raw_frags; i++) { for (i = 0; i < pkt->raw_frags; i++) {
assert(pkt->raw[i].iov_base); assert(pkt->raw[i].iov_base);
pci_dma_unmap(pkt->pci_dev, pkt->raw[i].iov_base, callback(context, pkt->raw[i].iov_base, pkt->raw[i].iov_len);
pkt->raw[i].iov_len, DMA_DIRECTION_TO_DEVICE, 0);
} }
} }
pkt->pci_dev = pci_dev;
pkt->raw_frags = 0; pkt->raw_frags = 0;
pkt->hdr_len = 0; pkt->hdr_len = 0;
pkt->l4proto = 0; 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_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(pci_dev, pa, &mapped_len, DMA_DIRECTION_TO_DEVICE);
if (!base) {
return false;
}
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;
}
return true;
}
static void net_tx_pkt_do_sw_csum(struct NetTxPkt *pkt, static void net_tx_pkt_do_sw_csum(struct NetTxPkt *pkt,
struct iovec *iov, uint32_t iov_len, struct iovec *iov, uint32_t iov_len,
uint16_t csl) uint16_t csl)
@ -697,7 +716,7 @@ static void net_tx_pkt_udp_fragment_fix(struct NetTxPkt *pkt,
} }
static bool net_tx_pkt_do_sw_fragmentation(struct NetTxPkt *pkt, static bool net_tx_pkt_do_sw_fragmentation(struct NetTxPkt *pkt,
NetTxPktCallback callback, NetTxPktSend callback,
void *context) void *context)
{ {
uint8_t gso_type = pkt->virt_hdr.gso_type & ~VIRTIO_NET_HDR_GSO_ECN; uint8_t gso_type = pkt->virt_hdr.gso_type & ~VIRTIO_NET_HDR_GSO_ECN;
@ -794,7 +813,7 @@ bool net_tx_pkt_send(struct NetTxPkt *pkt, NetClientState *nc)
} }
bool net_tx_pkt_send_custom(struct NetTxPkt *pkt, bool offload, bool net_tx_pkt_send_custom(struct NetTxPkt *pkt, bool offload,
NetTxPktCallback callback, void *context) NetTxPktSend callback, void *context)
{ {
assert(pkt); assert(pkt);

View File

@ -26,17 +26,16 @@
struct NetTxPkt; 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 * Init function for tx packet functionality
* *
* @pkt: packet pointer * @pkt: packet pointer
* @pci_dev: PCI device processing this packet
* @max_frags: max tx ip fragments * @max_frags: max tx ip fragments
*/ */
void net_tx_pkt_init(struct NetTxPkt **pkt, PCIDevice *pci_dev, void net_tx_pkt_init(struct NetTxPkt **pkt, uint32_t max_frags);
uint32_t max_frags);
/** /**
* Clean all tx packet resources. * 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. * populate data fragment into pkt context.
* *
* @pkt: packet * @pkt: packet
* @pa: physical address of fragment * @base: pointer to fragment
* @len: length of fragment * @len: length of fragment
* *
*/ */
bool net_tx_pkt_add_raw_fragment(struct NetTxPkt *pkt, hwaddr pa, bool net_tx_pkt_add_raw_fragment(struct NetTxPkt *pkt, void *base, size_t len);
size_t len);
/** /**
* Fix ip header fields and calculate IP header and pseudo header checksums. * Fix ip header fields and calculate IP header and pseudo header checksums.
@ -118,6 +116,14 @@ void net_tx_pkt_update_ip_checksums(struct NetTxPkt *pkt);
*/ */
void net_tx_pkt_update_ip_hdr_checksum(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. * get length of all populated data.
* *
@ -148,10 +154,30 @@ void net_tx_pkt_dump(struct NetTxPkt *pkt);
* reset tx packet private context (needed to be called between packets) * reset tx packet private context (needed to be called between packets)
* *
* @pkt: packet * @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.
*
* @context: PCI device owning fragment
* @base: pointer to fragment
* @len: length of fragment
*/
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. * Send packet to qemu. handles sw offloads if vhdr is not supported.
@ -173,7 +199,7 @@ bool net_tx_pkt_send(struct NetTxPkt *pkt, NetClientState *nc);
* @ret: operation result * @ret: operation result
*/ */
bool net_tx_pkt_send_custom(struct NetTxPkt *pkt, bool offload, 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. * parse raw packet data and analyze offload requirements.

View File

@ -2154,6 +2154,9 @@ static int rtl8139_cplus_transmit_one(RTL8139State *s)
int large_send_mss = (txdw0 >> CP_TC_LGSEN_MSS_SHIFT) & int large_send_mss = (txdw0 >> CP_TC_LGSEN_MSS_SHIFT) &
CP_TC_LGSEN_MSS_MASK; CP_TC_LGSEN_MSS_MASK;
if (large_send_mss == 0) {
goto skip_offload;
}
DPRINTF("+++ C+ mode offloaded task TSO IP data %d " DPRINTF("+++ C+ mode offloaded task TSO IP data %d "
"frame data %d specified MSS=%d\n", "frame data %d specified MSS=%d\n",

View File

@ -106,6 +106,8 @@ e1000_receiver_overrun(size_t s, uint32_t rdh, uint32_t rdt) "Receiver overrun:
# e1000x_common.c # e1000x_common.c
e1000x_rx_can_recv_disabled(bool link_up, bool rx_enabled, bool pci_master) "link_up: %d, rx_enabled %d, pci_master %d" e1000x_rx_can_recv_disabled(bool link_up, bool rx_enabled, bool pci_master) "link_up: %d, rx_enabled %d, pci_master %d"
e1000x_vlan_is_vlan_pkt(bool is_vlan_pkt, uint16_t eth_proto, uint16_t vet) "Is VLAN packet: %d, ETH proto: 0x%X, VET: 0x%X" e1000x_vlan_is_vlan_pkt(bool is_vlan_pkt, uint16_t eth_proto, uint16_t vet) "Is VLAN packet: %d, ETH proto: 0x%X, VET: 0x%X"
e1000x_rx_flt_vlan_mismatch(uint16_t vid) "VID mismatch: 0x%X"
e1000x_rx_flt_vlan_match(uint16_t vid) "VID match: 0x%X"
e1000x_rx_flt_ucast_match(uint32_t idx, uint8_t b0, uint8_t b1, uint8_t b2, uint8_t b3, uint8_t b4, uint8_t b5) "unicast match[%d]: %02x:%02x:%02x:%02x:%02x:%02x" e1000x_rx_flt_ucast_match(uint32_t idx, uint8_t b0, uint8_t b1, uint8_t b2, uint8_t b3, uint8_t b4, uint8_t b5) "unicast match[%d]: %02x:%02x:%02x:%02x:%02x:%02x"
e1000x_rx_flt_ucast_mismatch(uint8_t b0, uint8_t b1, uint8_t b2, uint8_t b3, uint8_t b4, uint8_t b5) "unicast mismatch: %02x:%02x:%02x:%02x:%02x:%02x" e1000x_rx_flt_ucast_mismatch(uint8_t b0, uint8_t b1, uint8_t b2, uint8_t b3, uint8_t b4, uint8_t b5) "unicast mismatch: %02x:%02x:%02x:%02x:%02x:%02x"
e1000x_rx_flt_inexact_mismatch(uint8_t b0, uint8_t b1, uint8_t b2, uint8_t b3, uint8_t b4, uint8_t b5, uint32_t mo, uint32_t mta, uint32_t mta_val) "inexact mismatch: %02x:%02x:%02x:%02x:%02x:%02x MO %d MTA[%d] 0x%x" e1000x_rx_flt_inexact_mismatch(uint8_t b0, uint8_t b1, uint8_t b2, uint8_t b3, uint8_t b4, uint8_t b5, uint32_t mo, uint32_t mta, uint32_t mta_val) "inexact mismatch: %02x:%02x:%02x:%02x:%02x:%02x MO %d MTA[%d] 0x%x"
@ -154,8 +156,6 @@ e1000e_rx_can_recv_rings_full(void) "Cannot receive: all rings are full"
e1000e_rx_can_recv(void) "Can receive" e1000e_rx_can_recv(void) "Can receive"
e1000e_rx_has_buffers(int ridx, uint32_t free_desc, size_t total_size, uint32_t desc_buf_size) "ring #%d: free descr: %u, packet size %zu, descr buffer size %u" e1000e_rx_has_buffers(int ridx, uint32_t free_desc, size_t total_size, uint32_t desc_buf_size) "ring #%d: free descr: %u, packet size %zu, descr buffer size %u"
e1000e_rx_null_descriptor(void) "Null RX descriptor!!" e1000e_rx_null_descriptor(void) "Null RX descriptor!!"
e1000e_rx_flt_vlan_mismatch(uint16_t vid) "VID mismatch: 0x%X"
e1000e_rx_flt_vlan_match(uint16_t vid) "VID match: 0x%X"
e1000e_rx_desc_ps_read(uint64_t a0, uint64_t a1, uint64_t a2, uint64_t a3) "buffers: [0x%"PRIx64", 0x%"PRIx64", 0x%"PRIx64", 0x%"PRIx64"]" e1000e_rx_desc_ps_read(uint64_t a0, uint64_t a1, uint64_t a2, uint64_t a3) "buffers: [0x%"PRIx64", 0x%"PRIx64", 0x%"PRIx64", 0x%"PRIx64"]"
e1000e_rx_desc_ps_write(uint16_t a0, uint16_t a1, uint16_t a2, uint16_t a3) "bytes written: [%u, %u, %u, %u]" e1000e_rx_desc_ps_write(uint16_t a0, uint16_t a1, uint16_t a2, uint16_t a3) "bytes written: [%u, %u, %u, %u]"
e1000e_rx_desc_buff_sizes(uint32_t b0, uint32_t b1, uint32_t b2, uint32_t b3) "buffer sizes: [%u, %u, %u, %u]" e1000e_rx_desc_buff_sizes(uint32_t b0, uint32_t b1, uint32_t b2, uint32_t b3) "buffer sizes: [%u, %u, %u, %u]"
@ -179,7 +179,7 @@ e1000e_rx_rss_disabled(void) "RSS is disabled"
e1000e_rx_rss_type(uint32_t type) "RSS type is %u" e1000e_rx_rss_type(uint32_t type) "RSS type is %u"
e1000e_rx_rss_ip4(int l4hdr_proto, uint32_t mrqc, bool tcpipv4_enabled, bool ipv4_enabled) "RSS IPv4: L4 header protocol %d, mrqc 0x%X, tcpipv4 enabled %d, ipv4 enabled %d" e1000e_rx_rss_ip4(int l4hdr_proto, uint32_t mrqc, bool tcpipv4_enabled, bool ipv4_enabled) "RSS IPv4: L4 header protocol %d, mrqc 0x%X, tcpipv4 enabled %d, ipv4 enabled %d"
e1000e_rx_rss_ip6_rfctl(uint32_t rfctl) "RSS IPv6: rfctl 0x%X" e1000e_rx_rss_ip6_rfctl(uint32_t rfctl) "RSS IPv6: rfctl 0x%X"
e1000e_rx_rss_ip6(bool ex_dis, bool new_ex_dis, int l4hdr_proto, bool has_ext_headers, bool ex_dst_valid, bool ex_src_valid, uint32_t mrqc, bool tcpipv6_enabled, bool ipv6ex_enabled, bool ipv6_enabled) "RSS IPv6: ex_dis: %d, new_ex_dis: %d, L4 header protocol %d, has_ext_headers %d, ex_dst_valid %d, ex_src_valid %d, mrqc 0x%X, tcpipv6 enabled %d, ipv6ex enabled %d, ipv6 enabled %d" e1000e_rx_rss_ip6(bool ex_dis, bool new_ex_dis, int l4hdr_proto, bool has_ext_headers, bool ex_dst_valid, bool ex_src_valid, uint32_t mrqc, bool tcpipv6ex_enabled, bool ipv6ex_enabled, bool ipv6_enabled) "RSS IPv6: ex_dis: %d, new_ex_dis: %d, L4 header protocol %d, has_ext_headers %d, ex_dst_valid %d, ex_src_valid %d, mrqc 0x%X, tcpipv6ex enabled %d, ipv6ex enabled %d, ipv6 enabled %d"
e1000e_rx_metadata_protocols(bool hasip4, bool hasip6, int l4hdr_protocol) "protocols: ip4: %d, ip6: %d, l4hdr: %d" e1000e_rx_metadata_protocols(bool hasip4, bool hasip6, int l4hdr_protocol) "protocols: ip4: %d, ip6: %d, l4hdr: %d"
e1000e_rx_metadata_vlan(uint16_t vlan_tag) "VLAN tag is 0x%X" e1000e_rx_metadata_vlan(uint16_t vlan_tag) "VLAN tag is 0x%X"
@ -205,21 +205,16 @@ e1000e_irq_msix_notify_postponed_vec(int idx) "Sending MSI-X postponed by EITR[%
e1000e_irq_legacy_notify(bool level) "IRQ line state: %d" e1000e_irq_legacy_notify(bool level) "IRQ line state: %d"
e1000e_irq_msix_notify_vec(uint32_t vector) "MSI-X notify vector 0x%x" e1000e_irq_msix_notify_vec(uint32_t vector) "MSI-X notify vector 0x%x"
e1000e_irq_postponed_by_xitr(uint32_t reg) "Interrupt postponed by [E]ITR register 0x%x" e1000e_irq_postponed_by_xitr(uint32_t reg) "Interrupt postponed by [E]ITR register 0x%x"
e1000e_irq_clear_ims(uint32_t bits, uint32_t old_ims, uint32_t new_ims) "Clearing IMS bits 0x%x: 0x%x --> 0x%x" e1000e_irq_clear(uint32_t offset, uint32_t old, uint32_t new) "Clearing interrupt register 0x%x: 0x%x --> 0x%x"
e1000e_irq_set_ims(uint32_t bits, uint32_t old_ims, uint32_t new_ims) "Setting IMS bits 0x%x: 0x%x --> 0x%x" e1000e_irq_set(uint32_t offset, uint32_t old, uint32_t new) "Setting interrupt register 0x%x: 0x%x --> 0x%x"
e1000e_irq_fix_icr_asserted(uint32_t new_val) "ICR_ASSERTED bit fixed: 0x%x" e1000e_irq_fix_icr_asserted(uint32_t new_val) "ICR_ASSERTED bit fixed: 0x%x"
e1000e_irq_add_msi_other(uint32_t new_val) "ICR_OTHER bit added: 0x%x" e1000e_irq_add_msi_other(uint32_t new_val) "ICR_OTHER bit added: 0x%x"
e1000e_irq_pending_interrupts(uint32_t pending, uint32_t icr, uint32_t ims) "ICR PENDING: 0x%x (ICR: 0x%x, IMS: 0x%x)" e1000e_irq_pending_interrupts(uint32_t pending, uint32_t icr, uint32_t ims) "ICR PENDING: 0x%x (ICR: 0x%x, IMS: 0x%x)"
e1000e_irq_set_cause_entry(uint32_t val, uint32_t icr) "Going to set IRQ cause 0x%x, ICR: 0x%x"
e1000e_irq_set_cause_exit(uint32_t val, uint32_t icr) "Set IRQ cause 0x%x, ICR: 0x%x"
e1000e_irq_icr_write(uint32_t bits, uint32_t old_icr, uint32_t new_icr) "Clearing ICR bits 0x%x: 0x%x --> 0x%x"
e1000e_irq_write_ics(uint32_t val) "Adding ICR bits 0x%x" e1000e_irq_write_ics(uint32_t val) "Adding ICR bits 0x%x"
e1000e_irq_icr_process_iame(void) "Clearing IMS bits due to IAME" e1000e_irq_icr_process_iame(void) "Clearing IMS bits due to IAME"
e1000e_irq_read_ics(uint32_t ics) "Current ICS: 0x%x" e1000e_irq_read_ics(uint32_t ics) "Current ICS: 0x%x"
e1000e_irq_read_ims(uint32_t ims) "Current IMS: 0x%x" e1000e_irq_read_ims(uint32_t ims) "Current IMS: 0x%x"
e1000e_irq_icr_clear_nonmsix_icr_read(void) "Clearing ICR on read due to non MSI-X int" e1000e_irq_icr_clear_nonmsix_icr_read(void) "Clearing ICR on read due to non MSI-X int"
e1000e_irq_icr_read_entry(uint32_t icr) "Starting ICR read. Current ICR: 0x%x"
e1000e_irq_icr_read_exit(uint32_t icr) "Ending ICR read. Current ICR: 0x%x"
e1000e_irq_icr_clear_zero_ims(void) "Clearing ICR on read due to zero IMS" e1000e_irq_icr_clear_zero_ims(void) "Clearing ICR on read due to zero IMS"
e1000e_irq_icr_clear_iame(void) "Clearing ICR on read due to IAME" e1000e_irq_icr_clear_iame(void) "Clearing ICR on read due to IAME"
e1000e_irq_iam_clear_eiame(uint32_t iam, uint32_t cause) "Clearing IMS due to EIAME, IAM: 0x%X, cause: 0x%X" e1000e_irq_iam_clear_eiame(uint32_t iam, uint32_t cause) "Clearing IMS due to EIAME, IAM: 0x%X, cause: 0x%X"
@ -235,7 +230,6 @@ e1000e_irq_tidv_fpd_not_running(void) "FPD written while TIDV was not running"
e1000e_irq_eitr_set(uint32_t eitr_num, uint32_t val) "EITR[%u] = %u" e1000e_irq_eitr_set(uint32_t eitr_num, uint32_t val) "EITR[%u] = %u"
e1000e_irq_itr_set(uint32_t val) "ITR = %u" e1000e_irq_itr_set(uint32_t val) "ITR = %u"
e1000e_irq_fire_all_timers(uint32_t val) "Firing all delay/throttling timers on all interrupts enable (0x%X written to IMS)" e1000e_irq_fire_all_timers(uint32_t val) "Firing all delay/throttling timers on all interrupts enable (0x%X written to IMS)"
e1000e_irq_adding_delayed_causes(uint32_t val, uint32_t icr) "Merging delayed causes 0x%X to ICR 0x%X"
e1000e_irq_msix_pending_clearing(uint32_t cause, uint32_t int_cfg, uint32_t vec) "Clearing MSI-X pending bit for cause 0x%x, IVAR config 0x%x, vector %u" e1000e_irq_msix_pending_clearing(uint32_t cause, uint32_t int_cfg, uint32_t vec) "Clearing MSI-X pending bit for cause 0x%x, IVAR config 0x%x, vector %u"
e1000e_wrn_msix_vec_wrong(uint32_t cause, uint32_t cfg) "Invalid configuration for cause 0x%x: 0x%x" e1000e_wrn_msix_vec_wrong(uint32_t cause, uint32_t cfg) "Invalid configuration for cause 0x%x: 0x%x"
@ -288,12 +282,11 @@ igb_rx_desc_buff_write(uint64_t addr, uint16_t offset, const void* source, uint3
igb_rx_metadata_rss(uint32_t rss) "RSS data: 0x%X" igb_rx_metadata_rss(uint32_t rss) "RSS data: 0x%X"
igb_irq_icr_clear_gpie_nsicr(void) "Clearing ICR on read due to GPIE.NSICR enabled" igb_irq_icr_clear_gpie_nsicr(void) "Clearing ICR on read due to GPIE.NSICR enabled"
igb_irq_icr_write(uint32_t bits, uint32_t old_icr, uint32_t new_icr) "Clearing ICR bits 0x%x: 0x%x --> 0x%x"
igb_irq_set_iam(uint32_t icr) "Update IAM: 0x%x" igb_irq_set_iam(uint32_t icr) "Update IAM: 0x%x"
igb_irq_read_iam(uint32_t icr) "Current IAM: 0x%x" igb_irq_read_iam(uint32_t icr) "Current IAM: 0x%x"
igb_irq_write_eics(uint32_t val, bool msix) "Update EICS: 0x%x MSI-X: %d" igb_irq_write_eics(uint32_t val, bool msix) "Update EICS: 0x%x MSI-X: %d"
igb_irq_write_eims(uint32_t val, bool msix) "Update EIMS: 0x%x MSI-X: %d" igb_irq_write_eims(uint32_t val, bool msix) "Update EIMS: 0x%x MSI-X: %d"
igb_irq_write_eimc(uint32_t val, uint32_t eims, bool msix) "Update EIMC: 0x%x EIMS: 0x%x MSI-X: %d" igb_irq_write_eimc(uint32_t val, bool msix) "Update EIMC: 0x%x MSI-X: %d"
igb_irq_write_eiac(uint32_t val) "Update EIAC: 0x%x" igb_irq_write_eiac(uint32_t val) "Update EIAC: 0x%x"
igb_irq_write_eiam(uint32_t val, bool msix) "Update EIAM: 0x%x MSI-X: %d" igb_irq_write_eiam(uint32_t val, bool msix) "Update EIAM: 0x%x MSI-X: %d"
igb_irq_write_eicr(uint32_t val, bool msix) "Update EICR: 0x%x MSI-X: %d" igb_irq_write_eicr(uint32_t val, bool msix) "Update EICR: 0x%x MSI-X: %d"

View File

@ -1834,9 +1834,12 @@ static int virtio_net_process_rss(NetClientState *nc, const uint8_t *buf,
VIRTIO_NET_HASH_REPORT_UDPv6, VIRTIO_NET_HASH_REPORT_UDPv6,
VIRTIO_NET_HASH_REPORT_UDPv6_EX VIRTIO_NET_HASH_REPORT_UDPv6_EX
}; };
struct iovec iov = {
.iov_base = (void *)buf,
.iov_len = size
};
net_rx_pkt_set_protocols(pkt, buf + n->host_hdr_len, net_rx_pkt_set_protocols(pkt, &iov, 1, n->host_hdr_len);
size - n->host_hdr_len);
net_rx_pkt_get_protocols(pkt, &hasip4, &hasip6, &l4hdr_proto); net_rx_pkt_get_protocols(pkt, &hasip4, &hasip6, &l4hdr_proto);
net_hash_type = virtio_net_get_hash_type(hasip4, hasip6, l4hdr_proto, net_hash_type = virtio_net_get_hash_type(hasip4, hasip6, l4hdr_proto,
n->rss_data.hash_types); n->rss_data.hash_types);

View File

@ -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_len = (txd.len > 0) ? txd.len : VMXNET3_MAX_TX_BUF_SIZE;
data_pa = txd.addr; data_pa = txd.addr;
if (!net_tx_pkt_add_raw_fragment(s->tx_pkt, if (!net_tx_pkt_add_raw_fragment_pci(s->tx_pkt, PCI_DEVICE(s),
data_pa, data_pa, data_len)) {
data_len)) {
s->skip_current_tx_pkt = true; s->skip_current_tx_pkt = true;
} }
} }
@ -678,9 +677,12 @@ static void vmxnet3_process_tx_queue(VMXNET3State *s, int qidx)
vmxnet3_complete_packet(s, qidx, txd_idx); vmxnet3_complete_packet(s, qidx, txd_idx);
s->tx_sop = true; s->tx_sop = true;
s->skip_current_tx_pkt = false; 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));
} }
} }
net_tx_pkt_reset(s->tx_pkt, net_tx_pkt_unmap_frag_pci, PCI_DEVICE(s));
} }
static inline void static inline void
@ -1159,7 +1161,6 @@ static void vmxnet3_deactivate_device(VMXNET3State *s)
{ {
if (s->device_active) { if (s->device_active) {
VMW_CBPRN("Deactivating vmxnet3..."); VMW_CBPRN("Deactivating vmxnet3...");
net_tx_pkt_reset(s->tx_pkt, PCI_DEVICE(s));
net_tx_pkt_uninit(s->tx_pkt); net_tx_pkt_uninit(s->tx_pkt);
net_rx_pkt_uninit(s->rx_pkt); net_rx_pkt_uninit(s->rx_pkt);
s->device_active = false; s->device_active = false;
@ -1519,7 +1520,7 @@ static void vmxnet3_activate_device(VMXNET3State *s)
/* Preallocate TX packet wrapper */ /* Preallocate TX packet wrapper */
VMW_CFPRN("Max TX fragments is %u", s->max_tx_frags); 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); net_rx_pkt_init(&s->rx_pkt);
/* Read rings memory locations for RX queues */ /* Read rings memory locations for RX queues */
@ -2001,7 +2002,12 @@ vmxnet3_receive(NetClientState *nc, const uint8_t *buf, size_t size)
get_eth_packet_type(PKT_GET_ETH_HDR(buf))); get_eth_packet_type(PKT_GET_ETH_HDR(buf)));
if (vmxnet3_rx_filter_may_indicate(s, buf, size)) { if (vmxnet3_rx_filter_may_indicate(s, buf, size)) {
net_rx_pkt_set_protocols(s->rx_pkt, buf, size); struct iovec iov = {
.iov_base = (void *)buf,
.iov_len = size
};
net_rx_pkt_set_protocols(s->rx_pkt, &iov, 1, 0);
vmxnet3_rx_need_csum_calculate(s->rx_pkt, buf, size); vmxnet3_rx_need_csum_calculate(s->rx_pkt, buf, size);
net_rx_pkt_attach_data(s->rx_pkt, buf, size, s->rx_vlan_stripping); net_rx_pkt_attach_data(s->rx_pkt, buf, size, s->rx_vlan_stripping);
bytes_indicated = vmxnet3_indicate_packet(s) ? size : -1; bytes_indicated = vmxnet3_indicate_packet(s) ? size : -1;
@ -2399,7 +2405,7 @@ static int vmxnet3_post_load(void *opaque, int version_id)
{ {
VMXNET3State *s = opaque; 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); net_rx_pkt_init(&s->rx_pkt);
if (s->msix_used) { if (s->msix_used) {

View File

@ -32,6 +32,8 @@
#define ETH_ALEN 6 #define ETH_ALEN 6
#define ETH_HLEN 14 #define ETH_HLEN 14
#define ETH_ZLEN 60 /* Min. octets in frame without FCS */ #define ETH_ZLEN 60 /* Min. octets in frame without FCS */
#define ETH_FCS_LEN 4
#define ETH_MTU 1500
struct eth_header { struct eth_header {
uint8_t h_dest[ETH_ALEN]; /* destination eth addr */ uint8_t h_dest[ETH_ALEN]; /* destination eth addr */
@ -222,6 +224,7 @@ struct tcp_hdr {
#define IP_HEADER_VERSION_6 (6) #define IP_HEADER_VERSION_6 (6)
#define IP_PROTO_TCP (6) #define IP_PROTO_TCP (6)
#define IP_PROTO_UDP (17) #define IP_PROTO_UDP (17)
#define IP_PROTO_SCTP (132)
#define IPTOS_ECN_MASK 0x03 #define IPTOS_ECN_MASK 0x03
#define IPTOS_ECN(x) ((x) & IPTOS_ECN_MASK) #define IPTOS_ECN(x) ((x) & IPTOS_ECN_MASK)
#define IPTOS_ECN_CE 0x03 #define IPTOS_ECN_CE 0x03
@ -312,10 +315,10 @@ eth_get_l2_hdr_length(const void *p)
} }
static inline uint32_t static inline uint32_t
eth_get_l2_hdr_length_iov(const struct iovec *iov, int iovcnt) eth_get_l2_hdr_length_iov(const struct iovec *iov, size_t iovcnt, size_t iovoff)
{ {
uint8_t p[sizeof(struct eth_header) + sizeof(struct vlan_header)]; uint8_t p[sizeof(struct eth_header) + sizeof(struct vlan_header)];
size_t copied = iov_to_buf(iov, iovcnt, 0, p, ARRAY_SIZE(p)); size_t copied = iov_to_buf(iov, iovcnt, iovoff, p, ARRAY_SIZE(p));
if (copied < ARRAY_SIZE(p)) { if (copied < ARRAY_SIZE(p)) {
return copied; return copied;
@ -340,26 +343,19 @@ eth_get_pkt_tci(const void *p)
size_t size_t
eth_strip_vlan(const struct iovec *iov, int iovcnt, size_t iovoff, eth_strip_vlan(const struct iovec *iov, int iovcnt, size_t iovoff,
uint8_t *new_ehdr_buf, void *new_ehdr_buf,
uint16_t *payload_offset, uint16_t *tci); uint16_t *payload_offset, uint16_t *tci);
size_t size_t
eth_strip_vlan_ex(const struct iovec *iov, int iovcnt, size_t iovoff, eth_strip_vlan_ex(const struct iovec *iov, int iovcnt, size_t iovoff, int index,
uint16_t vet, uint8_t *new_ehdr_buf, uint16_t vet, uint16_t vet_ext, void *new_ehdr_buf,
uint16_t *payload_offset, uint16_t *tci); uint16_t *payload_offset, uint16_t *tci);
uint16_t uint16_t
eth_get_l3_proto(const struct iovec *l2hdr_iov, int iovcnt, size_t l2hdr_len); 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, size_t *ehdr_size,
uint16_t vlan_ethtype, bool *is_new); uint16_t vlan_tag, uint16_t vlan_ethtype);
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); uint8_t eth_get_gso_type(uint16_t l3_proto, uint8_t *l3_hdr, uint8_t l4proto);
@ -384,7 +380,8 @@ typedef struct eth_ip4_hdr_info_st {
typedef enum EthL4HdrProto { typedef enum EthL4HdrProto {
ETH_L4_HDR_PROTO_INVALID, ETH_L4_HDR_PROTO_INVALID,
ETH_L4_HDR_PROTO_TCP, ETH_L4_HDR_PROTO_TCP,
ETH_L4_HDR_PROTO_UDP ETH_L4_HDR_PROTO_UDP,
ETH_L4_HDR_PROTO_SCTP
} EthL4HdrProto; } EthL4HdrProto;
typedef struct eth_l4_hdr_info_st { typedef struct eth_l4_hdr_info_st {
@ -397,7 +394,7 @@ typedef struct eth_l4_hdr_info_st {
bool has_tcp_data; bool has_tcp_data;
} eth_l4_hdr_info; } eth_l4_hdr_info;
void eth_get_protocols(const struct iovec *iov, int iovcnt, void eth_get_protocols(const struct iovec *iov, size_t iovcnt, size_t iovoff,
bool *hasip4, bool *hasip6, bool *hasip4, bool *hasip6,
size_t *l3hdr_off, size_t *l3hdr_off,
size_t *l4hdr_off, size_t *l4hdr_off,

View File

@ -30,5 +30,6 @@
uint32_t crc32c(uint32_t crc, const uint8_t *data, unsigned int length); uint32_t crc32c(uint32_t crc, const uint8_t *data, unsigned int length);
uint32_t iov_crc32c(uint32_t crc, const struct iovec *iov, size_t iov_cnt);
#endif #endif

View File

@ -21,26 +21,16 @@
#include "net/checksum.h" #include "net/checksum.h"
#include "net/tap.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, size_t *ehdr_size,
uint16_t vlan_ethtype, bool *is_new) uint16_t vlan_tag, uint16_t vlan_ethtype)
{ {
struct vlan_header *vhdr = PKT_GET_VLAN_HDR(ehdr); struct vlan_header *vhdr = PKT_GET_VLAN_HDR(ehdr);
switch (be16_to_cpu(ehdr->h_proto)) { memmove(vhdr + 1, vhdr, *ehdr_size - ETH_HLEN);
case ETH_P_VLAN: vhdr->h_tci = cpu_to_be16(vlan_tag);
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; vhdr->h_proto = ehdr->h_proto;
ehdr->h_proto = cpu_to_be16(vlan_ethtype); ehdr->h_proto = cpu_to_be16(vlan_ethtype);
*is_new = true; *ehdr_size += sizeof(*vhdr);
break;
}
vhdr->h_tci = cpu_to_be16(vlan_tag);
} }
uint8_t uint8_t
@ -136,7 +126,7 @@ _eth_tcp_has_data(bool is_ip4,
return l4len > TCP_HEADER_DATA_OFFSET(tcp); return l4len > TCP_HEADER_DATA_OFFSET(tcp);
} }
void eth_get_protocols(const struct iovec *iov, int iovcnt, void eth_get_protocols(const struct iovec *iov, size_t iovcnt, size_t iovoff,
bool *hasip4, bool *hasip6, bool *hasip4, bool *hasip6,
size_t *l3hdr_off, size_t *l3hdr_off,
size_t *l4hdr_off, size_t *l4hdr_off,
@ -147,26 +137,24 @@ void eth_get_protocols(const struct iovec *iov, int iovcnt,
{ {
int proto; int proto;
bool fragment = false; bool fragment = false;
size_t l2hdr_len = eth_get_l2_hdr_length_iov(iov, iovcnt);
size_t input_size = iov_size(iov, iovcnt); size_t input_size = iov_size(iov, iovcnt);
size_t copied; size_t copied;
uint8_t ip_p; uint8_t ip_p;
*hasip4 = *hasip6 = false; *hasip4 = *hasip6 = false;
*l3hdr_off = iovoff + eth_get_l2_hdr_length_iov(iov, iovcnt, iovoff);
l4hdr_info->proto = ETH_L4_HDR_PROTO_INVALID; l4hdr_info->proto = ETH_L4_HDR_PROTO_INVALID;
proto = eth_get_l3_proto(iov, iovcnt, l2hdr_len); proto = eth_get_l3_proto(iov, iovcnt, *l3hdr_off);
*l3hdr_off = l2hdr_len;
if (proto == ETH_P_IP) { if (proto == ETH_P_IP) {
struct ip_header *iphdr = &ip4hdr_info->ip4_hdr; struct ip_header *iphdr = &ip4hdr_info->ip4_hdr;
if (input_size < l2hdr_len) { if (input_size < *l3hdr_off) {
return; return;
} }
copied = iov_to_buf(iov, iovcnt, l2hdr_len, iphdr, sizeof(*iphdr)); copied = iov_to_buf(iov, iovcnt, *l3hdr_off, iphdr, sizeof(*iphdr));
if (copied < sizeof(*iphdr) || if (copied < sizeof(*iphdr) ||
IP_HEADER_VERSION(iphdr) != IP_HEADER_VERSION_4) { IP_HEADER_VERSION(iphdr) != IP_HEADER_VERSION_4) {
return; return;
@ -175,17 +163,17 @@ void eth_get_protocols(const struct iovec *iov, int iovcnt,
*hasip4 = true; *hasip4 = true;
ip_p = iphdr->ip_p; ip_p = iphdr->ip_p;
ip4hdr_info->fragment = IP4_IS_FRAGMENT(iphdr); ip4hdr_info->fragment = IP4_IS_FRAGMENT(iphdr);
*l4hdr_off = l2hdr_len + IP_HDR_GET_LEN(iphdr); *l4hdr_off = *l3hdr_off + IP_HDR_GET_LEN(iphdr);
fragment = ip4hdr_info->fragment; fragment = ip4hdr_info->fragment;
} else if (proto == ETH_P_IPV6) { } else if (proto == ETH_P_IPV6) {
if (!eth_parse_ipv6_hdr(iov, iovcnt, l2hdr_len, ip6hdr_info)) { if (!eth_parse_ipv6_hdr(iov, iovcnt, *l3hdr_off, ip6hdr_info)) {
return; return;
} }
*hasip6 = true; *hasip6 = true;
ip_p = ip6hdr_info->l4proto; ip_p = ip6hdr_info->l4proto;
*l4hdr_off = l2hdr_len + ip6hdr_info->full_hdr_len; *l4hdr_off = *l3hdr_off + ip6hdr_info->full_hdr_len;
fragment = ip6hdr_info->fragment; fragment = ip6hdr_info->fragment;
} else { } else {
return; return;
@ -223,16 +211,20 @@ void eth_get_protocols(const struct iovec *iov, int iovcnt,
*l5hdr_off = *l4hdr_off + sizeof(l4hdr_info->hdr.udp); *l5hdr_off = *l4hdr_off + sizeof(l4hdr_info->hdr.udp);
} }
break; break;
case IP_PROTO_SCTP:
l4hdr_info->proto = ETH_L4_HDR_PROTO_SCTP;
break;
} }
} }
size_t size_t
eth_strip_vlan(const struct iovec *iov, int iovcnt, size_t iovoff, eth_strip_vlan(const struct iovec *iov, int iovcnt, size_t iovoff,
uint8_t *new_ehdr_buf, void *new_ehdr_buf,
uint16_t *payload_offset, uint16_t *tci) uint16_t *payload_offset, uint16_t *tci)
{ {
struct vlan_header vlan_hdr; struct vlan_header vlan_hdr;
struct eth_header *new_ehdr = (struct eth_header *) new_ehdr_buf; struct eth_header *new_ehdr = new_ehdr_buf;
size_t copied = iov_to_buf(iov, iovcnt, iovoff, size_t copied = iov_to_buf(iov, iovcnt, iovoff,
new_ehdr, sizeof(*new_ehdr)); new_ehdr, sizeof(*new_ehdr));
@ -277,36 +269,50 @@ eth_strip_vlan(const struct iovec *iov, int iovcnt, size_t iovoff,
} }
size_t size_t
eth_strip_vlan_ex(const struct iovec *iov, int iovcnt, size_t iovoff, eth_strip_vlan_ex(const struct iovec *iov, int iovcnt, size_t iovoff, int index,
uint16_t vet, uint8_t *new_ehdr_buf, uint16_t vet, uint16_t vet_ext, void *new_ehdr_buf,
uint16_t *payload_offset, uint16_t *tci) uint16_t *payload_offset, uint16_t *tci)
{ {
struct vlan_header vlan_hdr; struct vlan_header vlan_hdr;
struct eth_header *new_ehdr = (struct eth_header *) new_ehdr_buf; uint16_t *new_ehdr_proto;
size_t new_ehdr_size;
size_t copied;
size_t copied = iov_to_buf(iov, iovcnt, iovoff, switch (index) {
new_ehdr, sizeof(*new_ehdr)); case 0:
new_ehdr_proto = &PKT_GET_ETH_HDR(new_ehdr_buf)->h_proto;
new_ehdr_size = sizeof(struct eth_header);
copied = iov_to_buf(iov, iovcnt, iovoff, new_ehdr_buf, new_ehdr_size);
break;
if (copied < sizeof(*new_ehdr)) { case 1:
new_ehdr_proto = &PKT_GET_VLAN_HDR(new_ehdr_buf)->h_proto;
new_ehdr_size = sizeof(struct eth_header) + sizeof(struct vlan_header);
copied = iov_to_buf(iov, iovcnt, iovoff, new_ehdr_buf, new_ehdr_size);
if (be16_to_cpu(PKT_GET_ETH_HDR(new_ehdr_buf)->h_proto) != vet_ext) {
return 0;
}
break;
default:
return 0; return 0;
} }
if (be16_to_cpu(new_ehdr->h_proto) == vet) { if (copied < new_ehdr_size || be16_to_cpu(*new_ehdr_proto) != vet) {
copied = iov_to_buf(iov, iovcnt, iovoff + sizeof(*new_ehdr), return 0;
&vlan_hdr, sizeof(vlan_hdr)); }
copied = iov_to_buf(iov, iovcnt, iovoff + new_ehdr_size,
&vlan_hdr, sizeof(vlan_hdr));
if (copied < sizeof(vlan_hdr)) { if (copied < sizeof(vlan_hdr)) {
return 0; return 0;
} }
new_ehdr->h_proto = vlan_hdr.h_proto; *new_ehdr_proto = vlan_hdr.h_proto;
*payload_offset = iovoff + new_ehdr_size + sizeof(vlan_hdr);
*tci = be16_to_cpu(vlan_hdr.h_tci); *tci = be16_to_cpu(vlan_hdr.h_tci);
*payload_offset = iovoff + sizeof(*new_ehdr) + sizeof(vlan_hdr);
return sizeof(struct eth_header);
}
return 0; return new_ehdr_size;
} }
void void

View File

@ -30,7 +30,8 @@ make get-vm-images
tests/avocado/cpu_queries.py:QueryCPUModelExpansion.test \ tests/avocado/cpu_queries.py:QueryCPUModelExpansion.test \
tests/avocado/empty_cpu_model.py:EmptyCPUModel.test \ tests/avocado/empty_cpu_model.py:EmptyCPUModel.test \
tests/avocado/hotplug_cpu.py:HotPlugCPU.test \ tests/avocado/hotplug_cpu.py:HotPlugCPU.test \
tests/avocado/igb.py:IGB.test \ tests/avocado/netdev-ethtool.py:NetDevEthtool.test_igb \
tests/avocado/netdev-ethtool.py:NetDevEthtool.test_igb_nomsi \
tests/avocado/info_usernet.py:InfoUsernet.test_hostfwd \ tests/avocado/info_usernet.py:InfoUsernet.test_hostfwd \
tests/avocado/intel_iommu.py:IntelIOMMU.test_intel_iommu \ tests/avocado/intel_iommu.py:IntelIOMMU.test_intel_iommu \
tests/avocado/intel_iommu.py:IntelIOMMU.test_intel_iommu_pt \ tests/avocado/intel_iommu.py:IntelIOMMU.test_intel_iommu_pt \

View File

@ -7,7 +7,6 @@
from avocado import skip from avocado import skip
from avocado_qemu import QemuSystemTest from avocado_qemu import QemuSystemTest
from avocado_qemu import exec_command, exec_command_and_wait_for_pattern
from avocado_qemu import wait_for_console_pattern from avocado_qemu import wait_for_console_pattern
class NetDevEthtool(QemuSystemTest): class NetDevEthtool(QemuSystemTest):
@ -30,7 +29,7 @@ class NetDevEthtool(QemuSystemTest):
# URL into a unique one # URL into a unique one
return self.fetch_asset(name=name, locations=(url), asset_hash=sha1) return self.fetch_asset(name=name, locations=(url), asset_hash=sha1)
def common_test_code(self, netdev, extra_args=None, kvm=False): def common_test_code(self, netdev, extra_args=None):
# This custom kernel has drivers for all the supported network # This custom kernel has drivers for all the supported network
# devices we can emulate in QEMU # devices we can emulate in QEMU
@ -58,9 +57,6 @@ class NetDevEthtool(QemuSystemTest):
'-drive', drive, '-drive', drive,
'-device', netdev) '-device', netdev)
if kvm:
self.vm.add_args('-accel', 'kvm')
self.vm.set_console(console_index=0) self.vm.set_console(console_index=0)
self.vm.launch() self.vm.launch()
@ -71,10 +67,6 @@ class NetDevEthtool(QemuSystemTest):
# no need to gracefully shutdown, just finish # no need to gracefully shutdown, just finish
self.vm.kill() self.vm.kill()
# Skip testing for MSI for now. Allegedly it was fixed by:
# 28e96556ba (igb: Allocate MSI-X vector when testing)
# but I'm seeing oops in the kernel
@skip("Kernel bug with MSI enabled")
def test_igb(self): def test_igb(self):
""" """
:avocado: tags=device:igb :avocado: tags=device:igb
@ -87,13 +79,6 @@ class NetDevEthtool(QemuSystemTest):
""" """
self.common_test_code("igb", "pci=nomsi") self.common_test_code("igb", "pci=nomsi")
def test_igb_nomsi_kvm(self):
"""
:avocado: tags=device:igb
"""
self.require_accelerator('kvm')
self.common_test_code("igb", "pci=nomsi", True)
# It seems the other popular cards we model in QEMU currently fail # It seems the other popular cards we model in QEMU currently fail
# the pattern test with: # the pattern test with:
# #

View File

@ -114,6 +114,7 @@ static void igb_pci_start_hw(QOSGraphObject *obj)
e1000e_macreg_write(&d->e1000e, E1000_RCTL, E1000_RCTL_EN); e1000e_macreg_write(&d->e1000e, E1000_RCTL, E1000_RCTL_EN);
/* Enable all interrupts */ /* Enable all interrupts */
e1000e_macreg_write(&d->e1000e, E1000_GPIE, E1000_GPIE_MSIX_MODE);
e1000e_macreg_write(&d->e1000e, E1000_IMS, 0xFFFFFFFF); e1000e_macreg_write(&d->e1000e, E1000_IMS, 0xFFFFFFFF);
e1000e_macreg_write(&d->e1000e, E1000_EIMS, 0xFFFFFFFF); e1000e_macreg_write(&d->e1000e, E1000_EIMS, 0xFFFFFFFF);

View File

@ -113,3 +113,11 @@ uint32_t crc32c(uint32_t crc, const uint8_t *data, unsigned int length)
return crc^0xffffffff; return crc^0xffffffff;
} }
uint32_t iov_crc32c(uint32_t crc, const struct iovec *iov, size_t iov_cnt)
{
while (iov_cnt--) {
crc = crc32c(crc, iov->iov_base, iov->iov_len) ^ 0xffffffff;
iov++;
}
return crc ^ 0xffffffff;
}