nvnet: Add unicast and multicast filtering

This commit is contained in:
Matt Borgerson 2023-10-17 23:34:39 -07:00 committed by mborgerson
parent ccb1211cd6
commit d6e5342f89
2 changed files with 69 additions and 0 deletions

View file

@ -25,6 +25,7 @@
#include "hw/pci/pci.h"
#include "hw/qdev-properties.h"
#include "net/net.h"
#include "qemu/bswap.h"
#include "qemu/iov.h"
#include "migration/vmstate.h"
#include "nvnet_regs.h"
@ -32,6 +33,8 @@
#define IOPORT_SIZE 0x8
#define MMIO_SIZE 0x400
static const uint8_t bcast[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
// #define DEBUG
#ifdef DEBUG
# define NVNET_DPRINTF(format, ...) printf(format, ## __VA_ARGS__)
@ -432,6 +435,58 @@ static bool nvnet_is_packet_oversized(size_t size)
return size > RX_ALLOC_BUFSIZE;
}
static bool receive_filter(NvNetState *s, const uint8_t *buf, int size)
{
if (size < 6) {
return false;
}
uint32_t rctl = nvnet_get_reg(s, NvRegPacketFilterFlags, 4);
int isbcast = !memcmp(buf, bcast, sizeof bcast);
/* Broadcast */
if (isbcast) {
/* FIXME: bcast filtering */
trace_nvnet_rx_filter_bcast_match();
return true;
}
if (!(rctl & NVREG_PFF_MYADDR)) {
/* FIXME: Confirm PFF_MYADDR filters mcast */
return true;
}
/* Multicast */
uint32_t addr[2];
addr[0] = cpu_to_le32(nvnet_get_reg(s, NvRegMulticastAddrA, 4));
addr[1] = cpu_to_le32(nvnet_get_reg(s, NvRegMulticastAddrB, 4));
if (memcmp(addr, bcast, sizeof bcast)) {
uint32_t dest_addr[2];
memcpy(dest_addr, buf, 6);
dest_addr[0] &= cpu_to_le32(nvnet_get_reg(s, NvRegMulticastMaskA, 4));
dest_addr[1] &= cpu_to_le32(nvnet_get_reg(s, NvRegMulticastMaskB, 4));
if (!memcmp(dest_addr, addr, 6)) {
trace_nvnet_rx_filter_mcast_match(MAC_ARG(dest_addr));
return true;
} else {
trace_nvnet_rx_filter_mcast_mismatch(MAC_ARG(dest_addr));
}
}
/* Unicast */
addr[0] = cpu_to_le32(nvnet_get_reg(s, NvRegMacAddrA, 4));
addr[1] = cpu_to_le32(nvnet_get_reg(s, NvRegMacAddrB, 4));
if (!memcmp(buf, addr, 6)) {
trace_nvnet_rx_filter_ucast_match(MAC_ARG(buf));
return true;
} else {
trace_nvnet_rx_filter_ucast_mismatch(MAC_ARG(buf));
}
return false;
}
static ssize_t nvnet_receive_iov(NetClientState *nc,
const struct iovec *iov, int iovcnt)
{
@ -443,10 +498,17 @@ static ssize_t nvnet_receive_iov(NetClientState *nc,
if (nvnet_is_packet_oversized(size)) {
/* Drop */
NVNET_DPRINTF("%s packet too large!\n", __func__);
trace_nvnet_rx_oversized(size);
return size;
}
iov_to_buf(iov, iovcnt, 0, s->rx_dma_buf, size);
if (!receive_filter(s, s->rx_dma_buf, size)) {
trace_nvnet_rx_filter_dropped();
return size;
}
#ifdef DEBUG
nvnet_hex_dump(s, s->rx_dma_buf, size);
#endif

View file

@ -7,3 +7,10 @@ nvnet_reg_read(uint32_t addr, const char *name, unsigned int size, uint64_t val)
nvnet_reg_write(uint32_t addr, const char *name, unsigned int size, uint64_t val) "addr 0x%"PRIx32" %s size %d val 0x%"PRIx64
nvnet_io_read(uint32_t addr, unsigned int size, uint64_t val) "addr 0x%"PRIx32" size %d val 0x%"PRIx64
nvnet_io_write(uint32_t addr, unsigned int size, uint64_t val) "addr 0x%"PRIx32" size %d val 0x%"PRIx64
nvnet_rx_filter_bcast_match(void) "broadcast match"
nvnet_rx_filter_mcast_match(uint8_t b0, uint8_t b1, uint8_t b2, uint8_t b3, uint8_t b4, uint8_t b5) "multicast match: %02x:%02x:%02x:%02x:%02x:%02x"
nvnet_rx_filter_mcast_mismatch(uint8_t b0, uint8_t b1, uint8_t b2, uint8_t b3, uint8_t b4, uint8_t b5) "multicast mismatch: %02x:%02x:%02x:%02x:%02x:%02x"
nvnet_rx_filter_ucast_match(uint8_t b0, uint8_t b1, uint8_t b2, uint8_t b3, uint8_t b4, uint8_t b5) "unicast match: %02x:%02x:%02x:%02x:%02x:%02x"
nvnet_rx_filter_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"
nvnet_rx_oversized(size_t size) "Received packet dropped because it was oversized (%zu bytes)"
nvnet_rx_filter_dropped(void) "Received packet dropped by RX filter"