From 23ff515ae3dab4cad2f1893b5e142259fc02e80d Mon Sep 17 00:00:00 2001 From: =?utf8?q?Imre=20Vad=C3=A1sz?= Date: Mon, 26 Oct 2015 00:11:30 +0100 Subject: [PATCH] if_vtnet: Use SetMacAddress feature; Add some new feature flags. * If the VTNET_FLAG_CTRL_MAC and VTNET_FLAG_CTRL_RX features are available, we should set the MAC address via a control message. * Add VIRTIO_NET_F_GUEST_ANNOUNCE feature flag. * Add VIRTIO_CONFIG_STATUS_DEVICE_NEEDS_RESET device status bit. * Do some reordering of function declarations/implementations to reduce differences to FreeBSD's code a bit. Taken-From: FreeBSD --- sys/dev/virtual/virtio/net/if_vtnet.c | 98 ++++++++++++++++++++----- sys/dev/virtual/virtio/net/virtio_net.h | 2 + sys/dev/virtual/virtio/virtio/virtio.h | 11 +-- 3 files changed, 88 insertions(+), 23 deletions(-) diff --git a/sys/dev/virtual/virtio/net/if_vtnet.c b/sys/dev/virtual/virtio/net/if_vtnet.c index 9c4de99423..68419bd319 100644 --- a/sys/dev/virtual/virtio/net/if_vtnet.c +++ b/sys/dev/virtual/virtio/net/if_vtnet.c @@ -98,12 +98,14 @@ struct vtnet_softc { uint32_t vtnet_flags; #define VTNET_FLAG_LINK 0x0001 #define VTNET_FLAG_SUSPENDED 0x0002 -#define VTNET_FLAG_CTRL_VQ 0x0004 -#define VTNET_FLAG_CTRL_RX 0x0008 -#define VTNET_FLAG_VLAN_FILTER 0x0010 -#define VTNET_FLAG_TSO_ECN 0x0020 -#define VTNET_FLAG_MRG_RXBUFS 0x0040 -#define VTNET_FLAG_LRO_NOMRG 0x0080 +#define VTNET_FLAG_MAC 0x0004 +#define VTNET_FLAG_CTRL_VQ 0x0008 +#define VTNET_FLAG_CTRL_RX 0x0010 +#define VTNET_FLAG_CTRL_MAC 0x0020 +#define VTNET_FLAG_VLAN_FILTER 0x0040 +#define VTNET_FLAG_TSO_ECN 0x0080 +#define VTNET_FLAG_MRG_RXBUFS 0x0100 +#define VTNET_FLAG_LRO_NOMRG 0x0200 struct virtqueue *vtnet_rx_vq; struct virtqueue *vtnet_tx_vq; @@ -211,6 +213,7 @@ struct vtnet_mac_filter { VIRTIO_NET_F_STATUS | \ VIRTIO_NET_F_CTRL_VQ | \ VIRTIO_NET_F_CTRL_RX | \ + VIRTIO_NET_F_CTRL_MAC_ADDR | \ VIRTIO_NET_F_CTRL_VLAN | \ VIRTIO_NET_F_CSUM | \ VIRTIO_NET_F_HOST_TSO4 | \ @@ -329,10 +332,11 @@ static void vtnet_init(void *); static void vtnet_exec_ctrl_cmd(struct vtnet_softc *, void *, struct sglist *, int, int); -static void vtnet_rx_filter(struct vtnet_softc *sc); +static int vtnet_ctrl_mac_cmd(struct vtnet_softc *, uint8_t *); static int vtnet_ctrl_rx_cmd(struct vtnet_softc *, int, int); static int vtnet_set_promisc(struct vtnet_softc *, int); static int vtnet_set_allmulti(struct vtnet_softc *, int); +static void vtnet_rx_filter(struct vtnet_softc *sc); static void vtnet_rx_filter_mac(struct vtnet_softc *); static int vtnet_exec_vlan_filter(struct vtnet_softc *, int, uint16_t); @@ -388,7 +392,9 @@ static struct virtio_feature_desc vtnet_feature_desc[] = { { VIRTIO_NET_F_CTRL_RX, "RxMode" }, { VIRTIO_NET_F_CTRL_VLAN, "VLanFilter" }, { VIRTIO_NET_F_CTRL_RX_EXTRA, "RxModeExtra" }, + { VIRTIO_NET_F_GUEST_ANNOUNCE, "GuestAnnounce" }, { VIRTIO_NET_F_MQ, "RFS" }, + { VIRTIO_NET_F_CTRL_MAC_ADDR, "SetMacAddress" }, { 0, NULL } }; @@ -476,6 +482,11 @@ vtnet_attach(device_t dev) virtio_set_feature_desc(dev, vtnet_feature_desc); vtnet_negotiate_features(sc); + if (virtio_with_feature(dev, VIRTIO_NET_F_MAC)) { + /* This feature should always be negotiated. */ + sc->vtnet_flags |= VTNET_FLAG_MAC; + } + if (virtio_with_feature(dev, VIRTIO_NET_F_MRG_RXBUF)) { sc->vtnet_flags |= VTNET_FLAG_MRG_RXBUFS; sc->vtnet_hdr_size = sizeof(struct virtio_net_hdr_mrg_rxbuf); @@ -493,8 +504,12 @@ vtnet_attach(device_t dev) sc->vtnet_flags |= VTNET_FLAG_CTRL_RX; if (virtio_with_feature(dev, VIRTIO_NET_F_CTRL_VLAN)) sc->vtnet_flags |= VTNET_FLAG_VLAN_FILTER; + if (virtio_with_feature(dev, VIRTIO_NET_F_CTRL_MAC_ADDR) && + virtio_with_feature(dev, VIRTIO_NET_F_CTRL_RX)) + sc->vtnet_flags |= VTNET_FLAG_CTRL_MAC; } + /* Read (or generate) the MAC address for the adapter. */ vtnet_get_hwaddr(sc); error = vtnet_alloc_virtqueues(sc); @@ -817,33 +832,45 @@ vtnet_alloc_virtqueues(struct vtnet_softc *sc) } static void -vtnet_get_hwaddr(struct vtnet_softc *sc) +vtnet_set_hwaddr(struct vtnet_softc *sc) { device_t dev; dev = sc->vtnet_dev; - if (virtio_with_feature(dev, VIRTIO_NET_F_MAC)) { - virtio_read_device_config(dev, + if ((sc->vtnet_flags & VTNET_FLAG_CTRL_MAC) && + (sc->vtnet_flags & VTNET_FLAG_CTRL_RX)) { + if (vtnet_ctrl_mac_cmd(sc, sc->vtnet_hwaddr) != 0) + device_printf(dev, "unable to set MAC address\n"); + } else if (sc->vtnet_flags & VTNET_FLAG_MAC) { + virtio_write_device_config(dev, offsetof(struct virtio_net_config, mac), sc->vtnet_hwaddr, ETHER_ADDR_LEN); - } else { - /* Generate random locally administered unicast address. */ - sc->vtnet_hwaddr[0] = 0xB2; - karc4rand(&sc->vtnet_hwaddr[1], ETHER_ADDR_LEN - 1); - - vtnet_set_hwaddr(sc); } } static void -vtnet_set_hwaddr(struct vtnet_softc *sc) +vtnet_get_hwaddr(struct vtnet_softc *sc) { device_t dev; dev = sc->vtnet_dev; - virtio_write_device_config(dev, + if ((sc->vtnet_flags & VTNET_FLAG_MAC) == 0) { + /* + * Generate a random locally administered unicast address. + * + * It would be nice to generate the same MAC address across + * reboots, but it seems all the hosts currently available + * support the MAC feature, so this isn't too important. + */ + sc->vtnet_hwaddr[0] = 0xB2; + karc4rand(&sc->vtnet_hwaddr[1], ETHER_ADDR_LEN - 1); + vtnet_set_hwaddr(sc); + return; + } + + virtio_read_device_config(dev, offsetof(struct virtio_net_config, mac), sc->vtnet_hwaddr, ETHER_ADDR_LEN); } @@ -2265,6 +2292,41 @@ vtnet_exec_ctrl_cmd(struct vtnet_softc *sc, void *cookie, KASSERT(c == cookie, ("unexpected control command response")); } +static int +vtnet_ctrl_mac_cmd(struct vtnet_softc *sc, uint8_t *hwaddr) +{ + struct { + struct virtio_net_ctrl_hdr hdr __aligned(2); + uint8_t pad1; + char aligned_hwaddr[ETHER_ADDR_LEN] __aligned(8); + uint8_t pad2; + uint8_t ack; + } s; + struct sglist_seg segs[3]; + struct sglist sg; + int error; + + s.hdr.class = VIRTIO_NET_CTRL_MAC; + s.hdr.cmd = VIRTIO_NET_CTRL_MAC_ADDR_SET; + s.ack = VIRTIO_NET_ERR; + + /* Copy the mac address into physically contiguous memory */ + memcpy(s.aligned_hwaddr, hwaddr, ETHER_ADDR_LEN); + + sglist_init(&sg, 3, segs); + error = 0; + error |= sglist_append(&sg, &s.hdr, + sizeof(struct virtio_net_ctrl_hdr)); + error |= sglist_append(&sg, s.aligned_hwaddr, ETHER_ADDR_LEN); + error |= sglist_append(&sg, &s.ack, sizeof(uint8_t)); + KASSERT(error == 0 && sg.sg_nseg == 3, + ("%s: error %d adding set MAC msg to sglist", __func__, error)); + + vtnet_exec_ctrl_cmd(sc, &s.ack, &sg, sg.sg_nseg - 1, 1); + + return (s.ack == VIRTIO_NET_OK ? 0 : EIO); +} + static void vtnet_rx_filter(struct vtnet_softc *sc) { diff --git a/sys/dev/virtual/virtio/net/virtio_net.h b/sys/dev/virtual/virtio/net/virtio_net.h index b7b1b5d05c..a48738bf94 100644 --- a/sys/dev/virtual/virtio/net/virtio_net.h +++ b/sys/dev/virtual/virtio/net/virtio_net.h @@ -33,6 +33,7 @@ * network */ #define VIRTIO_NET_F_MQ 0x400000 /* Device supports Receive Flow * Steering */ +#define VIRTIO_NET_F_CTRL_MAC_ADDR 0x800000 /* Set MAC address */ #define VIRTIO_NET_S_LINK_UP 1 /* Link is up */ #define VIRTIO_NET_S_ANNOUNCE 2 /* Announcement is needed */ @@ -131,6 +132,7 @@ struct virtio_net_ctrl_mac { #define VIRTIO_NET_CTRL_MAC 1 #define VIRTIO_NET_CTRL_MAC_TABLE_SET 0 +#define VIRTIO_NET_CTRL_MAC_ADDR_SET 1 /* * Control VLAN filtering diff --git a/sys/dev/virtual/virtio/virtio/virtio.h b/sys/dev/virtual/virtio/virtio/virtio.h index 75ac848f86..5d24aa4efa 100644 --- a/sys/dev/virtual/virtio/virtio/virtio.h +++ b/sys/dev/virtual/virtio/virtio/virtio.h @@ -46,11 +46,12 @@ struct vq_alloc_info; #define VIRTIO_ID_9P 0x09 /* Status byte for guest to report progress. */ -#define VIRTIO_CONFIG_STATUS_RESET 0x00 -#define VIRTIO_CONFIG_STATUS_ACK 0x01 -#define VIRTIO_CONFIG_STATUS_DRIVER 0x02 -#define VIRTIO_CONFIG_STATUS_DRIVER_OK 0x04 -#define VIRTIO_CONFIG_STATUS_FAILED 0x80 +#define VIRTIO_CONFIG_STATUS_RESET 0x00 +#define VIRTIO_CONFIG_STATUS_ACK 0x01 +#define VIRTIO_CONFIG_STATUS_DRIVER 0x02 +#define VIRTIO_CONFIG_STATUS_DRIVER_OK 0x04 +#define VIRTIO_CONFIG_STATUS_DEVICE_NEEDS_RESET 0x40 +#define VIRTIO_CONFIG_STATUS_FAILED 0x80 /* * Generate interrupt when the virtqueue ring is -- 2.41.0