-----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:
commit
00f76608a6
@ -2237,6 +2237,7 @@ F: tests/qtest/fuzz-megasas-test.c
|
||||
|
||||
Network packet abstractions
|
||||
M: Dmitry Fleytman <dmitry.fleytman@gmail.com>
|
||||
R: Akihiko Odaki <akihiko.odaki@daynix.com>
|
||||
S: Maintained
|
||||
F: include/net/eth.h
|
||||
F: net/eth.c
|
||||
@ -2279,7 +2280,7 @@ R: Sriram Yagnaraman <sriram.yagnaraman@est.tech>
|
||||
S: Maintained
|
||||
F: docs/system/devices/igb.rst
|
||||
F: hw/net/igb*
|
||||
F: tests/avocado/igb.py
|
||||
F: tests/avocado/netdev-ethtool.py
|
||||
F: tests/qtest/igb-test.c
|
||||
F: tests/qtest/libqos/igb.c
|
||||
|
||||
|
@ -14,7 +14,8 @@ Limitations
|
||||
===========
|
||||
|
||||
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
|
||||
|
||||
@ -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
|
||||
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
|
||||
functionalities not covered by the tests.
|
||||
with a different operating system other than DPDK, Linux, and Windows or if you
|
||||
try functionalities not covered by the tests.
|
||||
|
||||
Using igb
|
||||
=========
|
||||
@ -32,7 +33,7 @@ Using igb should be nothing different from using another network device. See
|
||||
:ref:`Network_emulation` in general.
|
||||
|
||||
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
|
||||
==============
|
||||
@ -60,7 +61,7 @@ Avocado test and can be ran with the following command:
|
||||
|
||||
.. code:: shell
|
||||
|
||||
make check-avocado AVOCADO_TESTS=tests/avocado/igb.py
|
||||
make check-avocado AVOCADO_TESTS=tests/avocado/netdev-ethtool.py
|
||||
|
||||
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
|
||||
.. [2] https://github.com/linux-test-project/ltp
|
||||
.. [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
|
||||
|
@ -56,7 +56,7 @@ config RTL8139_PCI
|
||||
|
||||
config VMXNET3_PCI
|
||||
bool
|
||||
default y if PCI_DEVICES && PC_PCI
|
||||
default y if PCI_DEVICES
|
||||
depends on PCI
|
||||
|
||||
config SMC91C111
|
||||
|
@ -637,9 +637,8 @@ xmit_seg(E1000State *s)
|
||||
|
||||
e1000x_inc_reg_if_not_full(s->mac_reg, TPT);
|
||||
e1000x_grow_8reg_if_not_full(s->mac_reg, TOTL, s->tx.size + 4);
|
||||
s->mac_reg[GPTC] = s->mac_reg[TPT];
|
||||
s->mac_reg[GOTCL] = s->mac_reg[TOTL];
|
||||
s->mac_reg[GOTCH] = s->mac_reg[TOTH];
|
||||
e1000x_inc_reg_if_not_full(s->mac_reg, GPTC);
|
||||
e1000x_grow_8reg_if_not_full(s->mac_reg, GOTCL, s->tx.size + 4);
|
||||
}
|
||||
|
||||
static void
|
||||
@ -805,38 +804,11 @@ start_xmit(E1000State *s)
|
||||
}
|
||||
|
||||
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];
|
||||
int isbcast = is_broadcast_ether_addr(buf);
|
||||
int ismcast = is_multicast_ether_addr(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);
|
||||
return (!e1000x_is_vlan_packet(buf, s->mac_reg[VET]) ||
|
||||
e1000x_rx_vlan_filter(s->mac_reg, PKT_GET_VLAN_HDR(buf))) &&
|
||||
e1000x_rx_group_filter(s->mac_reg, buf);
|
||||
}
|
||||
|
||||
static void
|
||||
@ -923,6 +895,7 @@ e1000_receive_iov(NetClientState *nc, const struct iovec *iov, int iovcnt)
|
||||
size_t desc_offset;
|
||||
size_t desc_size;
|
||||
size_t total_size;
|
||||
eth_pkt_types_e pkt_type;
|
||||
|
||||
if (!e1000x_hw_rx_enabled(s->mac_reg)) {
|
||||
return -1;
|
||||
@ -951,7 +924,7 @@ e1000_receive_iov(NetClientState *nc, const struct iovec *iov, int iovcnt)
|
||||
return size;
|
||||
}
|
||||
|
||||
if (!receive_filter(s, filter_buf, size)) {
|
||||
if (!receive_filter(s, filter_buf)) {
|
||||
return size;
|
||||
}
|
||||
|
||||
@ -972,6 +945,7 @@ e1000_receive_iov(NetClientState *nc, const struct iovec *iov, int iovcnt)
|
||||
size -= 4;
|
||||
}
|
||||
|
||||
pkt_type = get_eth_packet_type(PKT_GET_ETH_HDR(filter_buf));
|
||||
rdh_start = s->mac_reg[RDH];
|
||||
desc_offset = 0;
|
||||
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);
|
||||
|
||||
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;
|
||||
if ((rdt = s->mac_reg[RDT]) < s->mac_reg[RDH])
|
||||
|
@ -165,14 +165,14 @@ e1000e_intrmgr_on_throttling_timer(void *opaque)
|
||||
|
||||
timer->running = false;
|
||||
|
||||
if (msi_enabled(timer->core->owner)) {
|
||||
trace_e1000e_irq_msi_notify_postponed();
|
||||
/* Clear msi_causes_pending to fire MSI eventually */
|
||||
timer->core->msi_causes_pending = 0;
|
||||
e1000e_set_interrupt_cause(timer->core, 0);
|
||||
} else {
|
||||
trace_e1000e_irq_legacy_notify_postponed();
|
||||
e1000e_set_interrupt_cause(timer->core, 0);
|
||||
if (timer->core->mac[IMS] & timer->core->mac[ICR]) {
|
||||
if (msi_enabled(timer->core->owner)) {
|
||||
trace_e1000e_irq_msi_notify_postponed();
|
||||
msi_notify(timer->core->owner, 0);
|
||||
} else {
|
||||
trace_e1000e_irq_legacy_notify_postponed();
|
||||
e1000e_raise_legacy_irq(timer->core);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -366,10 +366,6 @@ static void
|
||||
e1000e_intrmgr_fire_all_timers(E1000ECore *core)
|
||||
{
|
||||
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) {
|
||||
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_src_valid,
|
||||
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_IPV6(core->mac[MRQC]));
|
||||
|
||||
@ -546,8 +542,8 @@ e1000e_rss_get_hash_type(E1000ECore *core, struct NetRxPkt *pkt)
|
||||
ip6info->rss_ex_src_valid))) {
|
||||
|
||||
if (l4hdr_proto == ETH_L4_HDR_PROTO_TCP &&
|
||||
E1000_MRQC_EN_TCPIPV6(core->mac[MRQC])) {
|
||||
return E1000_MRQ_RSS_TYPE_IPV6TCP;
|
||||
E1000_MRQC_EN_TCPIPV6EX(core->mac[MRQC])) {
|
||||
return E1000_MRQ_RSS_TYPE_IPV6TCPEX;
|
||||
}
|
||||
|
||||
if (E1000_MRQC_EN_IPV6EX(core->mac[MRQC])) {
|
||||
@ -581,7 +577,7 @@ e1000e_rss_calc_hash(E1000ECore *core,
|
||||
case E1000_MRQ_RSS_TYPE_IPV4TCP:
|
||||
type = NetPktRssIpV4Tcp;
|
||||
break;
|
||||
case E1000_MRQ_RSS_TYPE_IPV6TCP:
|
||||
case E1000_MRQ_RSS_TYPE_IPV6TCPEX:
|
||||
type = NetPktRssIpV6TcpEx;
|
||||
break;
|
||||
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();
|
||||
}
|
||||
|
||||
core->mac[GPTC] = core->mac[TPT];
|
||||
core->mac[GOTCL] = core->mac[TOTL];
|
||||
core->mac[GOTCH] = core->mac[TOTH];
|
||||
e1000x_inc_reg_if_not_full(core->mac, GPTC);
|
||||
e1000x_grow_8reg_if_not_full(core->mac, GOTCL, tot_len);
|
||||
}
|
||||
|
||||
static void
|
||||
@ -747,7 +742,8 @@ e1000e_process_tx_desc(E1000ECore *core,
|
||||
addr = le64_to_cpu(dp->buffer_addr);
|
||||
|
||||
if (!tx->skip_cp) {
|
||||
if (!net_tx_pkt_add_raw_fragment(tx->tx_pkt, addr, split_size)) {
|
||||
if (!net_tx_pkt_add_raw_fragment_pci(tx->tx_pkt, core->owner,
|
||||
addr, split_size)) {
|
||||
tx->skip_cp = true;
|
||||
}
|
||||
}
|
||||
@ -765,7 +761,7 @@ e1000e_process_tx_desc(E1000ECore *core,
|
||||
}
|
||||
|
||||
tx->skip_cp = false;
|
||||
net_tx_pkt_reset(tx->tx_pkt, core->owner);
|
||||
net_tx_pkt_reset(tx->tx_pkt, net_tx_pkt_unmap_frag_pci, core->owner);
|
||||
|
||||
tx->sum_needed = 0;
|
||||
tx->cptse = 0;
|
||||
@ -959,6 +955,8 @@ e1000e_start_xmit(E1000ECore *core, const E1000E_TxRing *txr)
|
||||
if (!ide || !e1000e_intrmgr_delay_tx_causes(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
|
||||
@ -1034,48 +1032,11 @@ e1000e_rx_l4_cso_enabled(E1000ECore *core)
|
||||
}
|
||||
|
||||
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];
|
||||
|
||||
if (e1000x_is_vlan_packet(buf, core->mac[VET]) &&
|
||||
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);
|
||||
return (!e1000x_is_vlan_packet(buf, core->mac[VET]) ||
|
||||
e1000x_rx_vlan_filter(core->mac, PKT_GET_VLAN_HDR(buf))) &&
|
||||
e1000x_rx_group_filter(core->mac, buf);
|
||||
}
|
||||
|
||||
static inline void
|
||||
@ -1149,6 +1110,11 @@ e1000e_verify_csum_in_sw(E1000ECore *core,
|
||||
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)) {
|
||||
trace_e1000e_rx_metadata_l4_csum_validation_failed();
|
||||
return;
|
||||
@ -1281,9 +1247,8 @@ e1000e_build_rx_metadata(E1000ECore *core,
|
||||
trace_e1000e_rx_metadata_l4_cso_disabled();
|
||||
}
|
||||
|
||||
trace_e1000e_rx_metadata_status_flags(*status_flags);
|
||||
|
||||
func_exit:
|
||||
trace_e1000e_rx_metadata_status_flags(*status_flags);
|
||||
*status_flags = cpu_to_le32(*status_flags);
|
||||
}
|
||||
|
||||
@ -1488,24 +1453,10 @@ e1000e_write_to_rx_buffers(E1000ECore *core,
|
||||
}
|
||||
|
||||
static void
|
||||
e1000e_update_rx_stats(E1000ECore *core,
|
||||
size_t data_size,
|
||||
size_t data_fcs_size)
|
||||
e1000e_update_rx_stats(E1000ECore *core, size_t pkt_size, size_t pkt_fcs_size)
|
||||
{
|
||||
e1000x_update_rx_total_stats(core->mac, data_size, data_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;
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
||||
static inline bool
|
||||
@ -1700,12 +1651,9 @@ static ssize_t
|
||||
e1000e_receive_internal(E1000ECore *core, const struct iovec *iov, int iovcnt,
|
||||
bool has_vnet)
|
||||
{
|
||||
static const int maximum_ethernet_hdr_len = (ETH_HLEN + 4);
|
||||
|
||||
uint32_t n = 0;
|
||||
uint8_t min_buf[ETH_ZLEN];
|
||||
uint32_t causes = 0;
|
||||
uint8_t buf[ETH_ZLEN];
|
||||
struct iovec min_iov;
|
||||
uint8_t *filter_buf;
|
||||
size_t size, orig_size;
|
||||
size_t iov_ofs = 0;
|
||||
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);
|
||||
}
|
||||
|
||||
filter_buf = iov->iov_base + iov_ofs;
|
||||
orig_size = iov_size(iov, iovcnt);
|
||||
size = orig_size - iov_ofs;
|
||||
|
||||
/* Pad to minimum Ethernet frame length */
|
||||
if (size < sizeof(min_buf)) {
|
||||
iov_to_buf(iov, iovcnt, iov_ofs, min_buf, size);
|
||||
memset(&min_buf[size], 0, sizeof(min_buf) - size);
|
||||
if (size < sizeof(buf)) {
|
||||
iov_to_buf(iov, iovcnt, iov_ofs, buf, size);
|
||||
memset(&buf[size], 0, sizeof(buf) - size);
|
||||
e1000x_inc_reg_if_not_full(core->mac, RUC);
|
||||
min_iov.iov_base = filter_buf = min_buf;
|
||||
min_iov.iov_len = size = sizeof(min_buf);
|
||||
min_iov.iov_base = buf;
|
||||
min_iov.iov_len = size = sizeof(buf);
|
||||
iovcnt = 1;
|
||||
iov = &min_iov;
|
||||
iov_ofs = 0;
|
||||
} else if (iov->iov_len < maximum_ethernet_hdr_len) {
|
||||
/* This is very unlikely, but may happen. */
|
||||
iov_to_buf(iov, iovcnt, iov_ofs, min_buf, maximum_ethernet_hdr_len);
|
||||
filter_buf = min_buf;
|
||||
} else {
|
||||
iov_to_buf(iov, iovcnt, iov_ofs, buf, ETH_HLEN + 4);
|
||||
}
|
||||
|
||||
/* 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,
|
||||
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();
|
||||
return orig_size;
|
||||
}
|
||||
|
||||
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_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) */
|
||||
if (total_size < core->mac[RSRPD]) {
|
||||
n |= E1000_ICS_SRPD;
|
||||
causes |= E1000_ICS_SRPD;
|
||||
}
|
||||
|
||||
/* Perform ACK receive detection */
|
||||
if (!(core->mac[RFCTL] & E1000_RFCTL_ACK_DIS) &&
|
||||
(e1000e_is_tcp_ack(core, core->rx_pkt))) {
|
||||
n |= E1000_ICS_ACK;
|
||||
causes |= E1000_ICS_ACK;
|
||||
}
|
||||
|
||||
/* Check if receive descriptor minimum threshold hit */
|
||||
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);
|
||||
} else {
|
||||
n |= E1000_ICS_RXO;
|
||||
causes |= E1000_ICS_RXO;
|
||||
retval = 0;
|
||||
|
||||
trace_e1000e_rx_not_written_to_guest(rxr.i->idx);
|
||||
}
|
||||
|
||||
if (!e1000e_intrmgr_delay_rx_causes(core, &n)) {
|
||||
trace_e1000e_rx_interrupt_set(n);
|
||||
e1000e_set_interrupt_cause(core, n);
|
||||
if (!e1000e_intrmgr_delay_rx_causes(core, &causes)) {
|
||||
trace_e1000e_rx_interrupt_set(causes);
|
||||
e1000e_set_interrupt_cause(core, causes);
|
||||
} else {
|
||||
trace_e1000e_rx_interrupt_delayed(n);
|
||||
trace_e1000e_rx_interrupt_delayed(causes);
|
||||
}
|
||||
|
||||
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
|
||||
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;
|
||||
|
||||
core->mac[ICR] &= ~effective_eiac;
|
||||
core->msi_causes_pending &= ~effective_eiac;
|
||||
|
||||
if (!(core->mac[CTRL_EXT] & E1000_CTRL_EXT_IAME)) {
|
||||
core->mac[IMS] &= ~effective_eiac;
|
||||
@ -2180,33 +2118,17 @@ e1000e_fix_icr_asserted(E1000ECore *core)
|
||||
trace_e1000e_irq_fix_icr_asserted(core->mac[ICR]);
|
||||
}
|
||||
|
||||
static void
|
||||
e1000e_send_msi(E1000ECore *core, bool msix)
|
||||
static void e1000e_raise_interrupts(E1000ECore *core,
|
||||
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);
|
||||
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 */
|
||||
if (is_msix) {
|
||||
@ -2228,40 +2150,58 @@ e1000e_update_interrupt_state(E1000ECore *core)
|
||||
*/
|
||||
core->mac[ICS] = core->mac[ICR];
|
||||
|
||||
interrupts_pending = (core->mac[IMS] & core->mac[ICR]) ? true : false;
|
||||
if (!interrupts_pending) {
|
||||
core->msi_causes_pending = 0;
|
||||
trace_e1000e_irq_pending_interrupts(core->mac[ICR] & core->mac[IMS],
|
||||
core->mac[ICR], core->mac[IMS]);
|
||||
|
||||
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],
|
||||
core->mac[ICR], core->mac[IMS]);
|
||||
|
||||
if (is_msix || msi_enabled(core->owner)) {
|
||||
if (interrupts_pending) {
|
||||
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);
|
||||
}
|
||||
if (!(core->mac[IMS] & core->mac[ICR]) &&
|
||||
!msix_enabled(core->owner) && !msi_enabled(core->owner)) {
|
||||
e1000e_lower_legacy_irq(core);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
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);
|
||||
core->mac[ICR] |= val;
|
||||
|
||||
trace_e1000e_irq_set_cause_exit(val, core->mac[ICR]);
|
||||
|
||||
e1000e_update_interrupt_state(core);
|
||||
e1000e_raise_interrupts(core, ICR, val);
|
||||
}
|
||||
|
||||
static inline void
|
||||
@ -2527,30 +2467,27 @@ e1000e_set_ics(E1000ECore *core, int index, uint32_t val)
|
||||
static void
|
||||
e1000e_set_icr(E1000ECore *core, int index, uint32_t val)
|
||||
{
|
||||
uint32_t icr = 0;
|
||||
if ((core->mac[ICR] & E1000_ICR_ASSERTED) &&
|
||||
(core->mac[CTRL_EXT] & E1000_CTRL_EXT_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
|
||||
* ones to be cleared when the "Other" bit (#24) is cleared.
|
||||
*/
|
||||
icr = (val & E1000_ICR_OTHER) ? (icr & ~E1000_ICR_OTHER_CAUSES) : icr;
|
||||
trace_e1000e_irq_icr_write(val, core->mac[ICR], icr);
|
||||
core->mac[ICR] = icr;
|
||||
e1000e_update_interrupt_state(core);
|
||||
if (val & E1000_ICR_OTHER) {
|
||||
val |= E1000_ICR_OTHER_CAUSES;
|
||||
}
|
||||
e1000e_lower_interrupts(core, ICR, val);
|
||||
}
|
||||
|
||||
static void
|
||||
e1000e_set_imc(E1000ECore *core, int index, uint32_t val)
|
||||
{
|
||||
trace_e1000e_irq_ims_clear_set_imc(val);
|
||||
e1000e_clear_ims_bits(core, val);
|
||||
e1000e_update_interrupt_state(core);
|
||||
e1000e_lower_interrupts(core, IMS, val);
|
||||
}
|
||||
|
||||
static void
|
||||
@ -2571,9 +2508,6 @@ e1000e_set_ims(E1000ECore *core, int index, uint32_t val)
|
||||
|
||||
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) &&
|
||||
(core->mac[CTRL_EXT] & E1000_CTRL_EXT_PBA_CLR) &&
|
||||
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_update_interrupt_state(core);
|
||||
e1000e_raise_interrupts(core, IMS, valid_val);
|
||||
}
|
||||
|
||||
static void
|
||||
@ -2659,28 +2593,25 @@ static uint32_t
|
||||
e1000e_mac_icr_read(E1000ECore *core, int index)
|
||||
{
|
||||
uint32_t ret = core->mac[ICR];
|
||||
trace_e1000e_irq_icr_read_entry(ret);
|
||||
|
||||
if (core->mac[IMS] == 0) {
|
||||
trace_e1000e_irq_icr_clear_zero_ims();
|
||||
core->mac[ICR] = 0;
|
||||
e1000e_lower_interrupts(core, ICR, 0xffffffff);
|
||||
}
|
||||
|
||||
if (!msix_enabled(core->owner)) {
|
||||
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) &&
|
||||
(core->mac[CTRL_EXT] & E1000_CTRL_EXT_IAME)) {
|
||||
trace_e1000e_irq_icr_clear_iame();
|
||||
core->mac[ICR] = 0;
|
||||
e1000e_lower_interrupts(core, ICR, 0xffffffff);
|
||||
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;
|
||||
}
|
||||
|
||||
@ -3422,7 +3353,7 @@ e1000e_core_pci_realize(E1000ECore *core,
|
||||
qemu_add_vm_change_state_handler(e1000e_vm_state_change, core);
|
||||
|
||||
for (i = 0; i < E1000E_NUM_QUEUES; i++) {
|
||||
net_tx_pkt_init(&core->tx[i].tx_pkt, core->owner, E1000E_MAX_TX_FRAGS);
|
||||
net_tx_pkt_init(&core->tx[i].tx_pkt, E1000E_MAX_TX_FRAGS);
|
||||
}
|
||||
|
||||
net_rx_pkt_init(&core->rx_pkt);
|
||||
@ -3447,7 +3378,6 @@ e1000e_core_pci_uninit(E1000ECore *core)
|
||||
qemu_del_vm_change_state_handler(core->vmstate);
|
||||
|
||||
for (i = 0; i < E1000E_NUM_QUEUES; i++) {
|
||||
net_tx_pkt_reset(core->tx[i].tx_pkt, core->owner);
|
||||
net_tx_pkt_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);
|
||||
|
||||
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));
|
||||
core->tx[i].skip_cp = false;
|
||||
}
|
||||
|
@ -111,8 +111,6 @@ struct E1000Core {
|
||||
PCIDevice *owner;
|
||||
void (*owner_start_recv)(PCIDevice *d);
|
||||
|
||||
uint32_t msi_causes_pending;
|
||||
|
||||
int64_t timadj;
|
||||
};
|
||||
|
||||
|
@ -58,33 +58,64 @@ bool e1000x_is_vlan_packet(const void *buf, uint16_t vet)
|
||||
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 };
|
||||
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) {
|
||||
if (!(rp[1] & E1000_RAH_AV)) {
|
||||
continue;
|
||||
}
|
||||
ra[0] = cpu_to_le32(rp[0]);
|
||||
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,
|
||||
MAC_ARG(buf));
|
||||
MAC_ARG(ehdr->h_dest));
|
||||
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 = (((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))) {
|
||||
e1000x_inc_reg_if_not_full(mac, MPRC);
|
||||
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,
|
||||
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)
|
||||
{
|
||||
size_t header_size = sizeof(struct eth_header) + sizeof(struct vlan_header);
|
||||
/* this is the size past which hardware will
|
||||
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
|
||||
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 ||
|
||||
(size > maximum_ethernet_vlan_size
|
||||
&& !(mac[RCTL] & E1000_RCTL_LPE)))
|
||||
if ((size > maximum_large_size ||
|
||||
(size > maximum_short_size && !(mac[RCTL] & E1000_RCTL_LPE)))
|
||||
&& !(mac[RCTL] & E1000_RCTL_SBP)) {
|
||||
e1000x_inc_reg_if_not_full(mac, ROC);
|
||||
trace_e1000x_rx_oversized(size);
|
||||
@ -212,23 +243,36 @@ e1000x_rxbufsize(uint32_t rctl)
|
||||
|
||||
void
|
||||
e1000x_update_rx_total_stats(uint32_t *mac,
|
||||
size_t data_size,
|
||||
size_t data_fcs_size)
|
||||
eth_pkt_types_e pkt_type,
|
||||
size_t pkt_size,
|
||||
size_t pkt_fcs_size)
|
||||
{
|
||||
static const int PRCregs[6] = { PRC64, PRC127, PRC255, PRC511,
|
||||
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);
|
||||
mac[GPRC] = mac[TPR];
|
||||
e1000x_inc_reg_if_not_full(mac, GPRC);
|
||||
/* TOR - Total Octets Received:
|
||||
* This register includes bytes received in a packet from the <Destination
|
||||
* Address> field through the <CRC> field, inclusively.
|
||||
* Always include FCS length (4) in size.
|
||||
*/
|
||||
e1000x_grow_8reg_if_not_full(mac, TORL, data_size + 4);
|
||||
mac[GORCL] = mac[TORL];
|
||||
mac[GORCH] = mac[TORH];
|
||||
e1000x_grow_8reg_if_not_full(mac, TORL, pkt_size + 4);
|
||||
e1000x_grow_8reg_if_not_full(mac, GORCL, pkt_size + 4);
|
||||
|
||||
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
|
||||
|
@ -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,
|
||||
size_t data_size,
|
||||
size_t data_fcs_size);
|
||||
eth_pkt_types_e pkt_type,
|
||||
size_t pkt_size,
|
||||
size_t pkt_fcs_size);
|
||||
|
||||
void e1000x_core_prepare_eeprom(uint16_t *eeprom,
|
||||
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_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);
|
||||
|
||||
|
@ -290,18 +290,18 @@
|
||||
#define E1000_RETA_IDX(hash) ((hash) & (BIT(7) - 1))
|
||||
#define E1000_RETA_VAL(reta, hash) (((uint8_t *)(reta))[E1000_RETA_IDX(hash)])
|
||||
|
||||
#define E1000_MRQC_EN_TCPIPV4(mrqc) ((mrqc) & BIT(16))
|
||||
#define E1000_MRQC_EN_IPV4(mrqc) ((mrqc) & BIT(17))
|
||||
#define E1000_MRQC_EN_TCPIPV6(mrqc) ((mrqc) & BIT(18))
|
||||
#define E1000_MRQC_EN_IPV6EX(mrqc) ((mrqc) & BIT(19))
|
||||
#define E1000_MRQC_EN_IPV6(mrqc) ((mrqc) & BIT(20))
|
||||
#define E1000_MRQC_EN_TCPIPV4(mrqc) ((mrqc) & BIT(16))
|
||||
#define E1000_MRQC_EN_IPV4(mrqc) ((mrqc) & BIT(17))
|
||||
#define E1000_MRQC_EN_TCPIPV6EX(mrqc) ((mrqc) & BIT(18))
|
||||
#define E1000_MRQC_EN_IPV6EX(mrqc) ((mrqc) & BIT(19))
|
||||
#define E1000_MRQC_EN_IPV6(mrqc) ((mrqc) & BIT(20))
|
||||
|
||||
#define E1000_MRQ_RSS_TYPE_NONE (0)
|
||||
#define E1000_MRQ_RSS_TYPE_IPV4TCP (1)
|
||||
#define E1000_MRQ_RSS_TYPE_IPV4 (2)
|
||||
#define E1000_MRQ_RSS_TYPE_IPV6TCP (3)
|
||||
#define E1000_MRQ_RSS_TYPE_IPV6EX (4)
|
||||
#define E1000_MRQ_RSS_TYPE_IPV6 (5)
|
||||
#define E1000_MRQ_RSS_TYPE_NONE (0)
|
||||
#define E1000_MRQ_RSS_TYPE_IPV4TCP (1)
|
||||
#define E1000_MRQ_RSS_TYPE_IPV4 (2)
|
||||
#define E1000_MRQ_RSS_TYPE_IPV6TCPEX (3)
|
||||
#define E1000_MRQ_RSS_TYPE_IPV6EX (4)
|
||||
#define E1000_MRQ_RSS_TYPE_IPV6 (5)
|
||||
|
||||
#define E1000_ICR_ASSERTED BIT(31)
|
||||
#define E1000_EIAC_MASK 0x01F00000
|
||||
|
10
hw/net/igb.c
10
hw/net/igb.c
@ -433,16 +433,16 @@ static void igb_pci_realize(PCIDevice *pci_dev, Error **errp)
|
||||
|
||||
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_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,
|
||||
16 * KiB);
|
||||
pcie_sriov_pf_init_vf_bar(pci_dev, 3,
|
||||
IGBVF_MMIO_SIZE);
|
||||
pcie_sriov_pf_init_vf_bar(pci_dev, IGBVF_MSIX_BAR_IDX,
|
||||
PCI_BASE_ADDRESS_MEM_TYPE_64 | PCI_BASE_ADDRESS_MEM_PREFETCH,
|
||||
16 * KiB);
|
||||
IGBVF_MSIX_SIZE);
|
||||
|
||||
igb_init_net_peer(s, pci_dev, macaddr);
|
||||
|
||||
|
@ -28,6 +28,14 @@
|
||||
|
||||
#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_indexed(x, i) x##i = (E1000_##x(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, 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, 4), defreg_indexed(x, 5), \
|
||||
defreg_indexed(x, 6), defreg_indexed(x, 7)
|
||||
@ -114,6 +122,8 @@ enum {
|
||||
defreg(EICS), defreg(EIMS), defreg(EIMC), defreg(EIAM),
|
||||
defreg(EICR), defreg(IVAR_MISC), defreg(GPIE),
|
||||
|
||||
defreg(TSYNCRXCFG), defreg8(ETQF),
|
||||
|
||||
defreg(RXPBS), defregd(RDBAL), defregd(RDBAH), defregd(RDLEN),
|
||||
defregd(SRRCTL), defregd(RDH), defregd(RDT),
|
||||
defregd(RXDCTL), defregd(RXCTL), defregd(RQDPC), defreg(RA2),
|
||||
@ -125,15 +135,15 @@ enum {
|
||||
|
||||
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(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),
|
||||
defregv(PVTEIAC), defregv(PVTEIAM), defregv(PVTEICR), defregv(PVFGPRC),
|
||||
defregv(PVFGPTC), defregv(PVFGORC), defregv(PVFGOTC), defregv(PVFMPRC),
|
||||
defregv(PVFGPRLBC), defregv(PVFGPTLBC), defregv(PVFGORLBC), defregv(PVFGOTLBC),
|
||||
defreg8(PVTCTRL), defreg8(PVTEICS), defreg8(PVTEIMS), defreg8(PVTEIMC),
|
||||
defreg8(PVTEIAC), defreg8(PVTEIAM), defreg8(PVTEICR), defreg8(PVFGPRC),
|
||||
defreg8(PVFGPTC), defreg8(PVFGORC), defreg8(PVFGOTC), defreg8(PVFMPRC),
|
||||
defreg8(PVFGPRLBC), defreg8(PVFGPTLBC), defreg8(PVFGORLBC), defreg8(PVFGOTLBC),
|
||||
|
||||
defreg(MTA_A),
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -42,11 +42,6 @@ union e1000_adv_tx_desc {
|
||||
} 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_TXSM 0x00000200 /* Insert TCP/UDP Checksum */
|
||||
|
||||
@ -151,6 +146,10 @@ union e1000_adv_rx_desc {
|
||||
#define IGB_82576_VF_DEV_ID 0x10CA
|
||||
#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 */
|
||||
|
||||
#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_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 */
|
||||
#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_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_VLAN_SPOOF_MASK 0x0000FF00 /* Per VF VLAN spoof control */
|
||||
#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 */
|
||||
#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 */
|
||||
#define E1000_GCR_CMPL_TMOUT_MASK 0x0000F000
|
||||
#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_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_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_MRQ_RSS_TYPE_IPV4UDP 7
|
||||
#define E1000_MRQ_RSS_TYPE_IPV6UDP 8
|
||||
|
||||
#define E1000_STATUS_IOV_MODE 0x00040000
|
||||
|
||||
#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)
|
||||
{
|
||||
return i < 8 ? i * 4 : (i - 8) * 4 + 2;
|
||||
|
@ -50,15 +50,8 @@
|
||||
#include "trace.h"
|
||||
#include "qapi/error.h"
|
||||
|
||||
#define TYPE_IGBVF "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 {
|
||||
PCIDevice parent_obj;
|
||||
|
||||
|
@ -16,6 +16,7 @@
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "qemu/crc32c.h"
|
||||
#include "trace.h"
|
||||
#include "net_rx_pkt.h"
|
||||
#include "net/checksum.h"
|
||||
@ -23,7 +24,10 @@
|
||||
|
||||
struct NetRxPkt {
|
||||
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;
|
||||
uint16_t vec_len_total;
|
||||
uint16_t vec_len;
|
||||
@ -89,7 +93,7 @@ net_rx_pkt_pull_data(struct NetRxPkt *pkt,
|
||||
if (pkt->ehdr_buf_len) {
|
||||
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->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);
|
||||
}
|
||||
|
||||
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->ip6hdr_info, &pkt->ip4hdr_info, &pkt->l4hdr_info);
|
||||
|
||||
@ -120,7 +124,7 @@ void net_rx_pkt_attach_iovec(struct NetRxPkt *pkt,
|
||||
assert(pkt);
|
||||
|
||||
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);
|
||||
} else {
|
||||
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,
|
||||
const struct iovec *iov, int iovcnt,
|
||||
size_t iovoff, bool strip_vlan,
|
||||
uint16_t vet)
|
||||
size_t iovoff, int strip_vlan_index,
|
||||
uint16_t vet, uint16_t vet_ext)
|
||||
{
|
||||
uint16_t tci = 0;
|
||||
uint16_t ploff = iovoff;
|
||||
assert(pkt);
|
||||
|
||||
if (strip_vlan) {
|
||||
pkt->ehdr_buf_len = eth_strip_vlan_ex(iov, iovcnt, iovoff, vet,
|
||||
pkt->ehdr_buf,
|
||||
&ploff, &tci);
|
||||
} else {
|
||||
pkt->ehdr_buf_len = 0;
|
||||
}
|
||||
pkt->ehdr_buf_len = eth_strip_vlan_ex(iov, iovcnt, iovoff,
|
||||
strip_vlan_index, vet, vet_ext,
|
||||
&pkt->ehdr_buf,
|
||||
&ploff, &tci);
|
||||
|
||||
pkt->tci = tci;
|
||||
|
||||
@ -186,17 +187,13 @@ size_t net_rx_pkt_get_total_len(struct NetRxPkt *pkt)
|
||||
return pkt->tot_len;
|
||||
}
|
||||
|
||||
void net_rx_pkt_set_protocols(struct NetRxPkt *pkt, const void *data,
|
||||
size_t len)
|
||||
void net_rx_pkt_set_protocols(struct NetRxPkt *pkt,
|
||||
const struct iovec *iov, size_t iovcnt,
|
||||
size_t iovoff)
|
||||
{
|
||||
const struct iovec iov = {
|
||||
.iov_base = (void *)data,
|
||||
.iov_len = len
|
||||
};
|
||||
|
||||
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->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;
|
||||
}
|
||||
|
||||
eth_l4_hdr_info *net_rx_pkt_get_l4_info(struct NetRxPkt *pkt)
|
||||
{
|
||||
return &pkt->l4hdr_info;
|
||||
}
|
||||
|
||||
static inline void
|
||||
_net_rx_rss_add_chunk(uint8_t *rss_input, size_t *bytes_written,
|
||||
void *ptr, size_t size)
|
||||
@ -560,32 +552,73 @@ _net_rx_pkt_calc_l4_csum(struct NetRxPkt *pkt)
|
||||
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)
|
||||
{
|
||||
uint16_t csum;
|
||||
uint32_t csum;
|
||||
|
||||
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) {
|
||||
trace_net_rx_pkt_l4_csum_validate_ip4_fragment();
|
||||
return false;
|
||||
}
|
||||
|
||||
csum = _net_rx_pkt_calc_l4_csum(pkt);
|
||||
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_valid = ((csum == 0) || (csum == 0xFFFF));
|
||||
break;
|
||||
|
||||
*csum_valid = ((csum == 0) || (csum == 0xFFFF));
|
||||
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);
|
||||
|
||||
|
@ -55,12 +55,14 @@ size_t net_rx_pkt_get_total_len(struct NetRxPkt *pkt);
|
||||
* parse and set packet analysis results
|
||||
*
|
||||
* @pkt: packet
|
||||
* @data: pointer to the data buffer to be parsed
|
||||
* @len: data length
|
||||
* @iov: received data scatter-gather list
|
||||
* @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,
|
||||
size_t len);
|
||||
void net_rx_pkt_set_protocols(struct NetRxPkt *pkt,
|
||||
const struct iovec *iov, size_t iovcnt,
|
||||
size_t iovoff);
|
||||
|
||||
/**
|
||||
* 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);
|
||||
|
||||
/**
|
||||
* 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 {
|
||||
NetPktRssIpV4,
|
||||
NetPktRssIpV4Tcp,
|
||||
@ -230,18 +223,19 @@ void net_rx_pkt_attach_iovec(struct NetRxPkt *pkt,
|
||||
/**
|
||||
* attach scatter-gather data to rx packet
|
||||
*
|
||||
* @pkt: packet
|
||||
* @iov: received data scatter-gather list
|
||||
* @iovcnt number of elements in iov
|
||||
* @iovoff data start offset in the iov
|
||||
* @strip_vlan: should the module strip vlan from data
|
||||
* @vet: VLAN tag Ethernet type
|
||||
* @pkt: packet
|
||||
* @iov: received data scatter-gather list
|
||||
* @iovcnt: number of elements in iov
|
||||
* @iovoff: data start offset in the iov
|
||||
* @strip_vlan_index: index of Q tag if it is to be stripped. negative otherwise.
|
||||
* @vet: VLAN tag Ethernet type
|
||||
* @vet_ext: outer VLAN tag Ethernet type
|
||||
*
|
||||
*/
|
||||
void net_rx_pkt_attach_iovec_ex(struct NetRxPkt *pkt,
|
||||
const struct iovec *iov, int iovcnt,
|
||||
size_t iovoff, bool strip_vlan,
|
||||
uint16_t vet);
|
||||
const struct iovec *iov, int iovcnt,
|
||||
size_t iovoff, int strip_vlan_index,
|
||||
uint16_t vet, uint16_t vet_ext);
|
||||
|
||||
/**
|
||||
* attach data to rx packet
|
||||
|
@ -16,12 +16,13 @@
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "net_tx_pkt.h"
|
||||
#include "qemu/crc32c.h"
|
||||
#include "net/eth.h"
|
||||
#include "net/checksum.h"
|
||||
#include "net/tap.h"
|
||||
#include "net/net.h"
|
||||
#include "hw/pci/pci_device.h"
|
||||
#include "net_tx_pkt.h"
|
||||
|
||||
enum {
|
||||
NET_TX_PKT_VHDR_FRAG = 0,
|
||||
@ -32,8 +33,6 @@ enum {
|
||||
|
||||
/* TX packet private context */
|
||||
struct NetTxPkt {
|
||||
PCIDevice *pci_dev;
|
||||
|
||||
struct virtio_net_hdr virt_hdr;
|
||||
|
||||
struct iovec *raw;
|
||||
@ -42,7 +41,10 @@ struct NetTxPkt {
|
||||
|
||||
struct iovec *vec;
|
||||
|
||||
uint8_t l2_hdr[ETH_MAX_L2_HDR_LEN];
|
||||
struct {
|
||||
struct eth_header eth;
|
||||
struct vlan_header vlan[3];
|
||||
} l2_hdr;
|
||||
union {
|
||||
struct ip_header ip;
|
||||
struct ip6_header ip6;
|
||||
@ -59,13 +61,10 @@ struct NetTxPkt {
|
||||
uint8_t l4proto;
|
||||
};
|
||||
|
||||
void net_tx_pkt_init(struct NetTxPkt **pkt, PCIDevice *pci_dev,
|
||||
uint32_t max_frags)
|
||||
void net_tx_pkt_init(struct NetTxPkt **pkt, uint32_t max_frags)
|
||||
{
|
||||
struct NetTxPkt *p = g_malloc0(sizeof *p);
|
||||
|
||||
p->pci_dev = pci_dev;
|
||||
|
||||
p->vec = g_new(struct iovec, max_frags + NET_TX_PKT_PL_START_FRAG);
|
||||
|
||||
p->raw = g_new(struct iovec, max_frags);
|
||||
@ -137,6 +136,23 @@ void net_tx_pkt_update_ip_checksums(struct NetTxPkt *pkt)
|
||||
pkt->virt_hdr.csum_offset, &csum, sizeof(csum));
|
||||
}
|
||||
|
||||
bool net_tx_pkt_update_sctp_checksum(struct NetTxPkt *pkt)
|
||||
{
|
||||
uint32_t csum = 0;
|
||||
struct iovec *pl_start_frag = pkt->vec + NET_TX_PKT_PL_START_FRAG;
|
||||
|
||||
if (iov_from_buf(pl_start_frag, pkt->payload_frags, 8, &csum, sizeof(csum)) < sizeof(csum)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
csum = cpu_to_le32(iov_crc32c(0xffffffff, pl_start_frag, pkt->payload_frags));
|
||||
if (iov_from_buf(pl_start_frag, pkt->payload_frags, 8, &csum, sizeof(csum)) < sizeof(csum)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void net_tx_pkt_calculate_hdr_len(struct NetTxPkt *pkt)
|
||||
{
|
||||
pkt->hdr_len = pkt->vec[NET_TX_PKT_L2HDR_FRAG].iov_len +
|
||||
@ -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,
|
||||
uint16_t vlan, uint16_t vlan_ethtype)
|
||||
{
|
||||
bool is_new;
|
||||
assert(pkt);
|
||||
|
||||
eth_setup_vlan_headers_ex(pkt->vec[NET_TX_PKT_L2HDR_FRAG].iov_base,
|
||||
vlan, vlan_ethtype, &is_new);
|
||||
eth_setup_vlan_headers(pkt->vec[NET_TX_PKT_L2HDR_FRAG].iov_base,
|
||||
&pkt->vec[NET_TX_PKT_L2HDR_FRAG].iov_len,
|
||||
vlan, vlan_ethtype);
|
||||
|
||||
/* update l2hdrlen */
|
||||
if (is_new) {
|
||||
pkt->hdr_len += sizeof(struct vlan_header);
|
||||
pkt->vec[NET_TX_PKT_L2HDR_FRAG].iov_len +=
|
||||
sizeof(struct vlan_header);
|
||||
}
|
||||
pkt->hdr_len += sizeof(struct vlan_header);
|
||||
}
|
||||
|
||||
bool net_tx_pkt_add_raw_fragment(struct NetTxPkt *pkt, hwaddr pa,
|
||||
size_t len)
|
||||
bool net_tx_pkt_add_raw_fragment(struct NetTxPkt *pkt, void *base, size_t len)
|
||||
{
|
||||
hwaddr mapped_len = 0;
|
||||
struct iovec *ventry;
|
||||
assert(pkt);
|
||||
|
||||
@ -395,23 +404,12 @@ bool net_tx_pkt_add_raw_fragment(struct NetTxPkt *pkt, hwaddr pa,
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!len) {
|
||||
return true;
|
||||
}
|
||||
|
||||
ventry = &pkt->raw[pkt->raw_frags];
|
||||
mapped_len = len;
|
||||
ventry->iov_base = base;
|
||||
ventry->iov_len = len;
|
||||
pkt->raw_frags++;
|
||||
|
||||
ventry->iov_base = pci_dma_map(pkt->pci_dev, pa,
|
||||
&mapped_len, DMA_DIRECTION_TO_DEVICE);
|
||||
|
||||
if ((ventry->iov_base != NULL) && (len == mapped_len)) {
|
||||
ventry->iov_len = mapped_len;
|
||||
pkt->raw_frags++;
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool net_tx_pkt_has_fragments(struct NetTxPkt *pkt)
|
||||
@ -445,7 +443,8 @@ void net_tx_pkt_dump(struct NetTxPkt *pkt)
|
||||
#endif
|
||||
}
|
||||
|
||||
void net_tx_pkt_reset(struct NetTxPkt *pkt, PCIDevice *pci_dev)
|
||||
void net_tx_pkt_reset(struct NetTxPkt *pkt,
|
||||
NetTxPktFreeFrag callback, void *context)
|
||||
{
|
||||
int i;
|
||||
|
||||
@ -465,17 +464,37 @@ void net_tx_pkt_reset(struct NetTxPkt *pkt, PCIDevice *pci_dev)
|
||||
assert(pkt->raw);
|
||||
for (i = 0; i < pkt->raw_frags; i++) {
|
||||
assert(pkt->raw[i].iov_base);
|
||||
pci_dma_unmap(pkt->pci_dev, pkt->raw[i].iov_base,
|
||||
pkt->raw[i].iov_len, DMA_DIRECTION_TO_DEVICE, 0);
|
||||
callback(context, pkt->raw[i].iov_base, pkt->raw[i].iov_len);
|
||||
}
|
||||
}
|
||||
pkt->pci_dev = pci_dev;
|
||||
pkt->raw_frags = 0;
|
||||
|
||||
pkt->hdr_len = 0;
|
||||
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,
|
||||
struct iovec *iov, uint32_t iov_len,
|
||||
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,
|
||||
NetTxPktCallback callback,
|
||||
NetTxPktSend callback,
|
||||
void *context)
|
||||
{
|
||||
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,
|
||||
NetTxPktCallback callback, void *context)
|
||||
NetTxPktSend callback, void *context)
|
||||
{
|
||||
assert(pkt);
|
||||
|
||||
|
@ -26,17 +26,16 @@
|
||||
|
||||
struct NetTxPkt;
|
||||
|
||||
typedef void (* NetTxPktCallback)(void *, const struct iovec *, int, const struct iovec *, int);
|
||||
typedef void (*NetTxPktFreeFrag)(void *, void *, size_t);
|
||||
typedef void (*NetTxPktSend)(void *, const struct iovec *, int, const struct iovec *, int);
|
||||
|
||||
/**
|
||||
* Init function for tx packet functionality
|
||||
*
|
||||
* @pkt: packet pointer
|
||||
* @pci_dev: PCI device processing this packet
|
||||
* @max_frags: max tx ip fragments
|
||||
*/
|
||||
void net_tx_pkt_init(struct NetTxPkt **pkt, PCIDevice *pci_dev,
|
||||
uint32_t max_frags);
|
||||
void net_tx_pkt_init(struct NetTxPkt **pkt, uint32_t max_frags);
|
||||
|
||||
/**
|
||||
* Clean all tx packet resources.
|
||||
@ -95,12 +94,11 @@ net_tx_pkt_setup_vlan_header(struct NetTxPkt *pkt, uint16_t vlan)
|
||||
* populate data fragment into pkt context.
|
||||
*
|
||||
* @pkt: packet
|
||||
* @pa: physical address of fragment
|
||||
* @base: pointer to fragment
|
||||
* @len: length of fragment
|
||||
*
|
||||
*/
|
||||
bool net_tx_pkt_add_raw_fragment(struct NetTxPkt *pkt, hwaddr pa,
|
||||
size_t len);
|
||||
bool net_tx_pkt_add_raw_fragment(struct NetTxPkt *pkt, void *base, size_t len);
|
||||
|
||||
/**
|
||||
* Fix ip header fields and calculate IP header and pseudo header checksums.
|
||||
@ -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);
|
||||
|
||||
/**
|
||||
* Calculate the SCTP checksum.
|
||||
*
|
||||
* @pkt: packet
|
||||
*
|
||||
*/
|
||||
bool net_tx_pkt_update_sctp_checksum(struct NetTxPkt *pkt);
|
||||
|
||||
/**
|
||||
* 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)
|
||||
*
|
||||
* @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.
|
||||
@ -173,7 +199,7 @@ bool net_tx_pkt_send(struct NetTxPkt *pkt, NetClientState *nc);
|
||||
* @ret: operation result
|
||||
*/
|
||||
bool net_tx_pkt_send_custom(struct NetTxPkt *pkt, bool offload,
|
||||
NetTxPktCallback callback, void *context);
|
||||
NetTxPktSend callback, void *context);
|
||||
|
||||
/**
|
||||
* parse raw packet data and analyze offload requirements.
|
||||
|
@ -2154,6 +2154,9 @@ static int rtl8139_cplus_transmit_one(RTL8139State *s)
|
||||
|
||||
int large_send_mss = (txdw0 >> CP_TC_LGSEN_MSS_SHIFT) &
|
||||
CP_TC_LGSEN_MSS_MASK;
|
||||
if (large_send_mss == 0) {
|
||||
goto skip_offload;
|
||||
}
|
||||
|
||||
DPRINTF("+++ C+ mode offloaded task TSO IP data %d "
|
||||
"frame data %d specified MSS=%d\n",
|
||||
|
@ -106,6 +106,8 @@ e1000_receiver_overrun(size_t s, uint32_t rdh, uint32_t rdt) "Receiver overrun:
|
||||
# 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_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_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"
|
||||
@ -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_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_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_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]"
|
||||
@ -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_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(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_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_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_clear_ims(uint32_t bits, uint32_t old_ims, uint32_t new_ims) "Clearing IMS bits 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_clear(uint32_t offset, uint32_t old, uint32_t new) "Clearing interrupt register 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_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_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_icr_process_iame(void) "Clearing IMS bits due to IAME"
|
||||
e1000e_irq_read_ics(uint32_t ics) "Current ICS: 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_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_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"
|
||||
@ -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_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_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_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_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_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_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_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"
|
||||
|
@ -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_EX
|
||||
};
|
||||
struct iovec iov = {
|
||||
.iov_base = (void *)buf,
|
||||
.iov_len = size
|
||||
};
|
||||
|
||||
net_rx_pkt_set_protocols(pkt, buf + n->host_hdr_len,
|
||||
size - n->host_hdr_len);
|
||||
net_rx_pkt_set_protocols(pkt, &iov, 1, n->host_hdr_len);
|
||||
net_rx_pkt_get_protocols(pkt, &hasip4, &hasip6, &l4hdr_proto);
|
||||
net_hash_type = virtio_net_get_hash_type(hasip4, hasip6, l4hdr_proto,
|
||||
n->rss_data.hash_types);
|
||||
|
@ -651,9 +651,8 @@ static void vmxnet3_process_tx_queue(VMXNET3State *s, int qidx)
|
||||
data_len = (txd.len > 0) ? txd.len : VMXNET3_MAX_TX_BUF_SIZE;
|
||||
data_pa = txd.addr;
|
||||
|
||||
if (!net_tx_pkt_add_raw_fragment(s->tx_pkt,
|
||||
data_pa,
|
||||
data_len)) {
|
||||
if (!net_tx_pkt_add_raw_fragment_pci(s->tx_pkt, PCI_DEVICE(s),
|
||||
data_pa, data_len)) {
|
||||
s->skip_current_tx_pkt = true;
|
||||
}
|
||||
}
|
||||
@ -678,9 +677,12 @@ static void vmxnet3_process_tx_queue(VMXNET3State *s, int qidx)
|
||||
vmxnet3_complete_packet(s, qidx, txd_idx);
|
||||
s->tx_sop = true;
|
||||
s->skip_current_tx_pkt = false;
|
||||
net_tx_pkt_reset(s->tx_pkt, PCI_DEVICE(s));
|
||||
net_tx_pkt_reset(s->tx_pkt,
|
||||
net_tx_pkt_unmap_frag_pci, PCI_DEVICE(s));
|
||||
}
|
||||
}
|
||||
|
||||
net_tx_pkt_reset(s->tx_pkt, net_tx_pkt_unmap_frag_pci, PCI_DEVICE(s));
|
||||
}
|
||||
|
||||
static inline void
|
||||
@ -1159,7 +1161,6 @@ static void vmxnet3_deactivate_device(VMXNET3State *s)
|
||||
{
|
||||
if (s->device_active) {
|
||||
VMW_CBPRN("Deactivating vmxnet3...");
|
||||
net_tx_pkt_reset(s->tx_pkt, PCI_DEVICE(s));
|
||||
net_tx_pkt_uninit(s->tx_pkt);
|
||||
net_rx_pkt_uninit(s->rx_pkt);
|
||||
s->device_active = false;
|
||||
@ -1519,7 +1520,7 @@ static void vmxnet3_activate_device(VMXNET3State *s)
|
||||
|
||||
/* Preallocate TX packet wrapper */
|
||||
VMW_CFPRN("Max TX fragments is %u", s->max_tx_frags);
|
||||
net_tx_pkt_init(&s->tx_pkt, PCI_DEVICE(s), s->max_tx_frags);
|
||||
net_tx_pkt_init(&s->tx_pkt, s->max_tx_frags);
|
||||
net_rx_pkt_init(&s->rx_pkt);
|
||||
|
||||
/* Read rings memory locations for RX queues */
|
||||
@ -2001,7 +2002,12 @@ vmxnet3_receive(NetClientState *nc, const uint8_t *buf, size_t size)
|
||||
get_eth_packet_type(PKT_GET_ETH_HDR(buf)));
|
||||
|
||||
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);
|
||||
net_rx_pkt_attach_data(s->rx_pkt, buf, size, s->rx_vlan_stripping);
|
||||
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;
|
||||
|
||||
net_tx_pkt_init(&s->tx_pkt, PCI_DEVICE(s), s->max_tx_frags);
|
||||
net_tx_pkt_init(&s->tx_pkt, s->max_tx_frags);
|
||||
net_rx_pkt_init(&s->rx_pkt);
|
||||
|
||||
if (s->msix_used) {
|
||||
|
@ -32,6 +32,8 @@
|
||||
#define ETH_ALEN 6
|
||||
#define ETH_HLEN 14
|
||||
#define ETH_ZLEN 60 /* Min. octets in frame without FCS */
|
||||
#define ETH_FCS_LEN 4
|
||||
#define ETH_MTU 1500
|
||||
|
||||
struct eth_header {
|
||||
uint8_t h_dest[ETH_ALEN]; /* destination eth addr */
|
||||
@ -222,6 +224,7 @@ struct tcp_hdr {
|
||||
#define IP_HEADER_VERSION_6 (6)
|
||||
#define IP_PROTO_TCP (6)
|
||||
#define IP_PROTO_UDP (17)
|
||||
#define IP_PROTO_SCTP (132)
|
||||
#define IPTOS_ECN_MASK 0x03
|
||||
#define IPTOS_ECN(x) ((x) & IPTOS_ECN_MASK)
|
||||
#define IPTOS_ECN_CE 0x03
|
||||
@ -312,10 +315,10 @@ eth_get_l2_hdr_length(const void *p)
|
||||
}
|
||||
|
||||
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)];
|
||||
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)) {
|
||||
return copied;
|
||||
@ -340,26 +343,19 @@ eth_get_pkt_tci(const void *p)
|
||||
|
||||
size_t
|
||||
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);
|
||||
|
||||
size_t
|
||||
eth_strip_vlan_ex(const struct iovec *iov, int iovcnt, size_t iovoff,
|
||||
uint16_t vet, uint8_t *new_ehdr_buf,
|
||||
eth_strip_vlan_ex(const struct iovec *iov, int iovcnt, size_t iovoff, int index,
|
||||
uint16_t vet, uint16_t vet_ext, void *new_ehdr_buf,
|
||||
uint16_t *payload_offset, uint16_t *tci);
|
||||
|
||||
uint16_t
|
||||
eth_get_l3_proto(const struct iovec *l2hdr_iov, int iovcnt, size_t l2hdr_len);
|
||||
|
||||
void eth_setup_vlan_headers_ex(struct eth_header *ehdr, uint16_t vlan_tag,
|
||||
uint16_t vlan_ethtype, bool *is_new);
|
||||
|
||||
static inline void
|
||||
eth_setup_vlan_headers(struct eth_header *ehdr, uint16_t vlan_tag,
|
||||
bool *is_new)
|
||||
{
|
||||
eth_setup_vlan_headers_ex(ehdr, vlan_tag, ETH_P_VLAN, is_new);
|
||||
}
|
||||
void eth_setup_vlan_headers(struct eth_header *ehdr, size_t *ehdr_size,
|
||||
uint16_t vlan_tag, uint16_t vlan_ethtype);
|
||||
|
||||
|
||||
uint8_t eth_get_gso_type(uint16_t l3_proto, uint8_t *l3_hdr, uint8_t l4proto);
|
||||
@ -384,7 +380,8 @@ typedef struct eth_ip4_hdr_info_st {
|
||||
typedef enum EthL4HdrProto {
|
||||
ETH_L4_HDR_PROTO_INVALID,
|
||||
ETH_L4_HDR_PROTO_TCP,
|
||||
ETH_L4_HDR_PROTO_UDP
|
||||
ETH_L4_HDR_PROTO_UDP,
|
||||
ETH_L4_HDR_PROTO_SCTP
|
||||
} EthL4HdrProto;
|
||||
|
||||
typedef struct eth_l4_hdr_info_st {
|
||||
@ -397,7 +394,7 @@ typedef struct eth_l4_hdr_info_st {
|
||||
bool has_tcp_data;
|
||||
} 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,
|
||||
size_t *l3hdr_off,
|
||||
size_t *l4hdr_off,
|
||||
|
@ -30,5 +30,6 @@
|
||||
|
||||
|
||||
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
|
||||
|
102
net/eth.c
102
net/eth.c
@ -21,26 +21,16 @@
|
||||
#include "net/checksum.h"
|
||||
#include "net/tap.h"
|
||||
|
||||
void eth_setup_vlan_headers_ex(struct eth_header *ehdr, uint16_t vlan_tag,
|
||||
uint16_t vlan_ethtype, bool *is_new)
|
||||
void eth_setup_vlan_headers(struct eth_header *ehdr, size_t *ehdr_size,
|
||||
uint16_t vlan_tag, uint16_t vlan_ethtype)
|
||||
{
|
||||
struct vlan_header *vhdr = PKT_GET_VLAN_HDR(ehdr);
|
||||
|
||||
switch (be16_to_cpu(ehdr->h_proto)) {
|
||||
case ETH_P_VLAN:
|
||||
case ETH_P_DVLAN:
|
||||
/* vlan hdr exists */
|
||||
*is_new = false;
|
||||
break;
|
||||
|
||||
default:
|
||||
/* No VLAN header, put a new one */
|
||||
vhdr->h_proto = ehdr->h_proto;
|
||||
ehdr->h_proto = cpu_to_be16(vlan_ethtype);
|
||||
*is_new = true;
|
||||
break;
|
||||
}
|
||||
memmove(vhdr + 1, vhdr, *ehdr_size - ETH_HLEN);
|
||||
vhdr->h_tci = cpu_to_be16(vlan_tag);
|
||||
vhdr->h_proto = ehdr->h_proto;
|
||||
ehdr->h_proto = cpu_to_be16(vlan_ethtype);
|
||||
*ehdr_size += sizeof(*vhdr);
|
||||
}
|
||||
|
||||
uint8_t
|
||||
@ -136,7 +126,7 @@ _eth_tcp_has_data(bool is_ip4,
|
||||
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,
|
||||
size_t *l3hdr_off,
|
||||
size_t *l4hdr_off,
|
||||
@ -147,26 +137,24 @@ void eth_get_protocols(const struct iovec *iov, int iovcnt,
|
||||
{
|
||||
int proto;
|
||||
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 copied;
|
||||
uint8_t ip_p;
|
||||
|
||||
*hasip4 = *hasip6 = false;
|
||||
*l3hdr_off = iovoff + eth_get_l2_hdr_length_iov(iov, iovcnt, iovoff);
|
||||
l4hdr_info->proto = ETH_L4_HDR_PROTO_INVALID;
|
||||
|
||||
proto = eth_get_l3_proto(iov, iovcnt, l2hdr_len);
|
||||
|
||||
*l3hdr_off = l2hdr_len;
|
||||
proto = eth_get_l3_proto(iov, iovcnt, *l3hdr_off);
|
||||
|
||||
if (proto == ETH_P_IP) {
|
||||
struct ip_header *iphdr = &ip4hdr_info->ip4_hdr;
|
||||
|
||||
if (input_size < l2hdr_len) {
|
||||
if (input_size < *l3hdr_off) {
|
||||
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) ||
|
||||
IP_HEADER_VERSION(iphdr) != IP_HEADER_VERSION_4) {
|
||||
return;
|
||||
@ -175,17 +163,17 @@ void eth_get_protocols(const struct iovec *iov, int iovcnt,
|
||||
*hasip4 = true;
|
||||
ip_p = iphdr->ip_p;
|
||||
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;
|
||||
} 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;
|
||||
}
|
||||
|
||||
*hasip6 = true;
|
||||
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;
|
||||
} else {
|
||||
return;
|
||||
@ -223,16 +211,20 @@ void eth_get_protocols(const struct iovec *iov, int iovcnt,
|
||||
*l5hdr_off = *l4hdr_off + sizeof(l4hdr_info->hdr.udp);
|
||||
}
|
||||
break;
|
||||
|
||||
case IP_PROTO_SCTP:
|
||||
l4hdr_info->proto = ETH_L4_HDR_PROTO_SCTP;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
size_t
|
||||
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)
|
||||
{
|
||||
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,
|
||||
new_ehdr, sizeof(*new_ehdr));
|
||||
@ -277,36 +269,50 @@ eth_strip_vlan(const struct iovec *iov, int iovcnt, size_t iovoff,
|
||||
}
|
||||
|
||||
size_t
|
||||
eth_strip_vlan_ex(const struct iovec *iov, int iovcnt, size_t iovoff,
|
||||
uint16_t vet, uint8_t *new_ehdr_buf,
|
||||
eth_strip_vlan_ex(const struct iovec *iov, int iovcnt, size_t iovoff, int index,
|
||||
uint16_t vet, uint16_t vet_ext, void *new_ehdr_buf,
|
||||
uint16_t *payload_offset, uint16_t *tci)
|
||||
{
|
||||
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,
|
||||
new_ehdr, sizeof(*new_ehdr));
|
||||
switch (index) {
|
||||
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;
|
||||
}
|
||||
|
||||
if (be16_to_cpu(new_ehdr->h_proto) == vet) {
|
||||
copied = iov_to_buf(iov, iovcnt, iovoff + sizeof(*new_ehdr),
|
||||
&vlan_hdr, sizeof(vlan_hdr));
|
||||
|
||||
if (copied < sizeof(vlan_hdr)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
new_ehdr->h_proto = vlan_hdr.h_proto;
|
||||
|
||||
*tci = be16_to_cpu(vlan_hdr.h_tci);
|
||||
*payload_offset = iovoff + sizeof(*new_ehdr) + sizeof(vlan_hdr);
|
||||
return sizeof(struct eth_header);
|
||||
if (copied < new_ehdr_size || be16_to_cpu(*new_ehdr_proto) != vet) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
copied = iov_to_buf(iov, iovcnt, iovoff + new_ehdr_size,
|
||||
&vlan_hdr, sizeof(vlan_hdr));
|
||||
if (copied < sizeof(vlan_hdr)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
*new_ehdr_proto = vlan_hdr.h_proto;
|
||||
*payload_offset = iovoff + new_ehdr_size + sizeof(vlan_hdr);
|
||||
*tci = be16_to_cpu(vlan_hdr.h_tci);
|
||||
|
||||
return new_ehdr_size;
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -30,7 +30,8 @@ make get-vm-images
|
||||
tests/avocado/cpu_queries.py:QueryCPUModelExpansion.test \
|
||||
tests/avocado/empty_cpu_model.py:EmptyCPUModel.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/intel_iommu.py:IntelIOMMU.test_intel_iommu \
|
||||
tests/avocado/intel_iommu.py:IntelIOMMU.test_intel_iommu_pt \
|
||||
|
@ -7,7 +7,6 @@
|
||||
|
||||
from avocado import skip
|
||||
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
|
||||
|
||||
class NetDevEthtool(QemuSystemTest):
|
||||
@ -30,7 +29,7 @@ class NetDevEthtool(QemuSystemTest):
|
||||
# URL into a unique one
|
||||
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
|
||||
# devices we can emulate in QEMU
|
||||
@ -58,9 +57,6 @@ class NetDevEthtool(QemuSystemTest):
|
||||
'-drive', drive,
|
||||
'-device', netdev)
|
||||
|
||||
if kvm:
|
||||
self.vm.add_args('-accel', 'kvm')
|
||||
|
||||
self.vm.set_console(console_index=0)
|
||||
self.vm.launch()
|
||||
|
||||
@ -71,10 +67,6 @@ class NetDevEthtool(QemuSystemTest):
|
||||
# no need to gracefully shutdown, just finish
|
||||
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):
|
||||
"""
|
||||
:avocado: tags=device:igb
|
||||
@ -87,13 +79,6 @@ class NetDevEthtool(QemuSystemTest):
|
||||
"""
|
||||
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
|
||||
# the pattern test with:
|
||||
#
|
||||
|
@ -114,6 +114,7 @@ static void igb_pci_start_hw(QOSGraphObject *obj)
|
||||
e1000e_macreg_write(&d->e1000e, E1000_RCTL, E1000_RCTL_EN);
|
||||
|
||||
/* 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_EIMS, 0xFFFFFFFF);
|
||||
|
||||
|
@ -113,3 +113,11 @@ uint32_t crc32c(uint32_t crc, const uint8_t *data, unsigned int length)
|
||||
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;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user