Skip to content

Commit

Permalink
e1000x: Fix BPRC and MPRC
Browse files Browse the repository at this point in the history
Before this change, e1000 and the common code updated BPRC and MPRC
depending on the matched filter, but e1000e and igb decided to update
those counters by deriving the packet type independently. This
inconsistency caused a multicast packet to be counted twice.

Updating BPRC and MPRC depending on are fundamentally flawed anyway as
a filter can be used for different types of packets. For example, it is
possible to filter broadcast packets with MTA.

Always determine what counters to update by inspecting the packets.

Fixes: 3b27430 ("e1000: Implementing various counters")
Signed-off-by: Akihiko Odaki <akihiko.odaki@daynix.com>
Reviewed-by: Sriram Yagnaraman <sriram.yagnaraman@est.tech>
Signed-off-by: Jason Wang <jasowang@redhat.com>
(cherry picked from commit f3f9b72)
Signed-off-by: Michael Tokarev <mjt@tls.msk.ru>
(Mjt: removed hw/net/igb_core.c bits: igb introduced past 7.2)
  • Loading branch information
akihikodaki authored and Michael Tokarev committed May 24, 2023
1 parent b121ebe commit 8766b97
Show file tree
Hide file tree
Showing 4 changed files with 28 additions and 28 deletions.
6 changes: 3 additions & 3 deletions hw/net/e1000.c
Original file line number Diff line number Diff line change
Expand Up @@ -818,12 +818,10 @@ receive_filter(E1000State *s, const uint8_t *buf, int size)
}

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;
}

Expand Down Expand Up @@ -914,6 +912,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;
Expand Down Expand Up @@ -963,6 +962,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);
Expand Down Expand Up @@ -1028,7 +1028,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])
Expand Down
20 changes: 3 additions & 17 deletions hw/net/e1000e_core.c
Original file line number Diff line number Diff line change
Expand Up @@ -1470,24 +1470,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
Expand Down
25 changes: 19 additions & 6 deletions hw/net/e1000x_common.c
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,6 @@ bool e1000x_rx_group_filter(uint32_t *mac, const uint8_t *buf)
f = mta_shift[(rctl >> E1000_RCTL_MO_SHIFT) & 3];
f = (((buf[5] << 8) | buf[4]) >> f) & 0xfff;
if (mac[MTA + (f >> 5)] & (1 << (f & 0x1f))) {
e1000x_inc_reg_if_not_full(mac, MPRC);
return true;
}

Expand Down Expand Up @@ -209,22 +208,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);
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);
e1000x_grow_8reg_if_not_full(mac, GORCL, data_size + 4);
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
Expand Down
5 changes: 3 additions & 2 deletions hw/net/e1000x_common.h
Original file line number Diff line number Diff line change
Expand Up @@ -165,8 +165,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,
Expand Down

0 comments on commit 8766b97

Please sign in to comment.