@@ -343,6 +343,15 @@ static int virtio_net_handle_mac(VirtIONet *n, uint8_t cmd,
n->mac_table.multi_overflow = 1;
}
}
+ if (n->nic->nc.peer && n->nic->nc.peer->info->set_rx_filter) {
+ n->nic->nc.peer->info->set_rx_filter(n->nic->nc.peer,
+ n->promisc,
+ n->allmulti,
+ n->nobcast,
+ n->mac,
+ n->mac_table.in_use,
+ n->mac_table.macs);
+ }
return VIRTIO_NET_OK;
}
@@ -42,6 +42,8 @@ typedef ssize_t (NetReceive)(VLANClientState *, const uint8_t *, size_t);
typedef ssize_t (NetReceiveIOV)(VLANClientState *, const struct iovec *, int);
typedef void (NetCleanup) (VLANClientState *);
typedef void (LinkStatusChanged)(VLANClientState *);
+typedef int (NetRXFilter)(VLANClientState *, bool allmulti, bool promisc,
+ bool nobcast, uint8_t *, int , uint8_t *);
typedef struct NetClientInfo {
net_client_type type;
@@ -50,6 +52,7 @@ typedef struct NetClientInfo {
NetReceive *receive_raw;
NetReceiveIOV *receive_iov;
NetCanReceive *can_receive;
+ NetRXFilter *set_rx_filter;
NetCleanup *cleanup;
LinkStatusChanged *link_status_changed;
NetPoll *poll;
@@ -59,3 +59,9 @@ void tap_fd_set_offload(int fd, int csum, int tso4,
int tso6, int ecn, int ufo)
{
}
+
+int tap_fd_set_rx_filter(int fd, bool allmulti, bool promisc, bool nobcast,
+ uint8_t *mac, int count, uint8_t *macs)
+{
+ return -1;
+}
@@ -125,3 +125,9 @@ void tap_fd_set_offload(int fd, int csum, int tso4,
int tso6, int ecn, int ufo)
{
}
+
+int tap_fd_set_rx_filter(int fd, bool allmulti, bool promisc, bool nobcast,
+ uint8_t *mac, int count, uint8_t *macs)
+{
+ return -1;
+}
@@ -59,3 +59,9 @@ void tap_fd_set_offload(int fd, int csum, int tso4,
int tso6, int ecn, int ufo)
{
}
+
+int tap_fd_set_rx_filter(int fd, bool allmulti, bool promisc, bool nobcast,
+ uint8_t *mac, int count, uint8_t *macs)
+{
+ return -1;
+}
@@ -188,3 +188,41 @@ void tap_fd_set_offload(int fd, int csum, int tso4,
}
}
}
+
+int tap_fd_set_rx_filter(int fd, bool allmulti, bool promisc, bool nobcast,
+ uint8_t *mac, int count, uint8_t *list)
+{
+ struct tun_filter *filter;
+ int ret;
+ int len = TAP_LINUX_ETH_ALEN * (promisc ? 0 : (count + 2));
+
+ filter = qemu_mallocz(offsetof(struct tun_filter, addr) + len);
+ if (!filter) {
+ return -1;
+ }
+
+ if (!promisc) {
+ memcpy(filter->addr, mac, TAP_LINUX_ETH_ALEN);
+ filter->count += 1;
+
+ memcpy(&filter->addr[filter->count], list, count * TAP_LINUX_ETH_ALEN);
+ filter->count += count;
+ }
+
+ if (!promisc && !allmulti && !nobcast) {
+ /* If enabled and not included implicitly by promisc or all multicast
+ * mode, add all ones - the broadcast address. */
+ memset(&filter->addr[filter->count], 0xff, TAP_LINUX_ETH_ALEN);
+ filter->count += 1;
+ }
+
+ if (allmulti) {
+ filter->flags |= TUN_FLT_ALLMULTI;
+ }
+
+ ret = ioctl(fd, TUNSETTXFILTER, filter);
+
+ qemu_free(filter);
+
+ return ret;
+}
@@ -25,6 +25,7 @@
#define TUNSETIFF _IOW('T', 202, int)
#define TUNGETFEATURES _IOR('T', 207, unsigned int)
#define TUNSETOFFLOAD _IOW('T', 208, unsigned int)
+#define TUNSETTXFILTER _IOW('T', 209, unsigned int)
#define TUNGETIFF _IOR('T', 210, unsigned int)
#define TUNSETSNDBUF _IOW('T', 212, int)
#define TUNGETVNETHDRSZ _IOR('T', 215, int)
@@ -44,6 +45,24 @@
#define TUN_F_TSO_ECN 0x08 /* I can handle TSO with ECN bits. */
#define TUN_F_UFO 0x10 /* I can handle UFO packets */
+/*
+ * Filter spec (used for SETXXFILTER ioctls)
+ * This stuff is applicable only to the TAP (Ethernet) devices.
+ * If the count is zero the filter is disabled and the driver accepts
+ * all packets (promisc mode).
+ * If the filter is enabled in order to accept broadcast packets
+ * broadcast addr must be explicitly included in the addr list.
+ */
+#define TUN_FLT_ALLMULTI 0x0001 /* Accept all multicast packets */
+
+#define TAP_LINUX_ETH_ALEN 6
+
+struct tun_filter {
+ uint16_t flags; /* TUN_FLT_ flags see above */
+ uint16_t count; /* Number of addresses */
+ uint8_t addr[0][TAP_LINUX_ETH_ALEN];
+};
+
struct virtio_net_hdr
{
uint8_t flags;
@@ -225,3 +225,9 @@ void tap_fd_set_offload(int fd, int csum, int tso4,
int tso6, int ecn, int ufo)
{
}
+
+int tap_fd_set_rx_filter(int fd, bool allmulti, bool promisc, bool nobcast,
+ uint8_t *mac, int count, uint8_t *macs)
+{
+ return -1;
+}
@@ -749,3 +749,9 @@ struct vhost_net *tap_get_vhost_net(VLANClientState *nc)
{
return NULL;
}
+
+int tap_fd_set_rx_filter(int fd, bool allmulti, bool promisc, bool nobcast,
+ uint8_t *mac, int count, uint8_t *macs)
+{
+ return -1;
+}
@@ -310,6 +310,13 @@ int tap_get_fd(VLANClientState *nc)
return s->fd;
}
+static int tap_set_rx_filter(VLANClientState *nc, bool allmulti, bool promisc,
+ bool nobcast, uint8_t *mac, int count, uint8_t *list)
+{
+ TAPState *s = DO_UPCAST(TAPState, nc, nc);
+ return tap_fd_set_rx_filter(s->fd, allmulti, promisc, nobcast, mac, count, list);
+}
+
/* fd support */
static NetClientInfo net_tap_info = {
@@ -318,6 +325,7 @@ static NetClientInfo net_tap_info = {
.receive = tap_receive,
.receive_raw = tap_receive_raw,
.receive_iov = tap_receive_iov,
+ .set_rx_filter = tap_set_rx_filter,
.poll = tap_poll,
.cleanup = tap_cleanup,
};
@@ -51,6 +51,8 @@ int tap_probe_vnet_hdr_len(int fd, int len);
int tap_probe_has_ufo(int fd);
void tap_fd_set_offload(int fd, int csum, int tso4, int tso6, int ecn, int ufo);
void tap_fd_set_vnet_hdr_len(int fd, int len);
+int tap_fd_set_rx_filter(int fd, bool allmulti, bool promisc, bool nobcast,
+ uint8_t *, int , uint8_t *);
int tap_get_fd(VLANClientState *vc);