From 73ceb049af1b391cdbb4b3bbedc2e8ef8fe399f2 Mon Sep 17 00:00:00 2001 From: liqinhui Date: Mon, 4 Dec 2023 14:21:45 +0800 Subject: [PATCH] virtio-net: Support for setting MAC addresses of the virtio-net interfaces. Refers to https://docs.oasis-open.org/virtio/virtio/v1.2/cs01/virtio-v1.2-cs01.html#x1-2230004 A driver SHOULD negotiate VIRTIO_NET_F_MAC if the device offers it. If the driver negotiates the VIRTIO_NET_F_MAC feature, the driver MUST set the physical address of the NIC to mac. Otherwise, it SHOULD use a locally-administered MAC address. Signed-off-by: liqinhui --- drivers/virtio/virtio-net.c | 60 ++++++++++++++++++++++++++++++++++++- 1 file changed, 59 insertions(+), 1 deletion(-) diff --git a/drivers/virtio/virtio-net.c b/drivers/virtio/virtio-net.c index 5384d6798c..c1908e7dc7 100644 --- a/drivers/virtio/virtio-net.c +++ b/drivers/virtio/virtio-net.c @@ -39,6 +39,8 @@ * Pre-processor Definitions ****************************************************************************/ +#define VIRTIO_NET_F_MAC 5 + /* Virtio net header size and packet buffer size */ #define VIRTIO_NET_HDRSIZE (sizeof(struct virtio_net_hdr_s)) @@ -74,6 +76,24 @@ begin_packed_struct struct virtio_net_hdr_s uint16_t csum_offset; } end_packed_struct; +/* The definition of the struct virtio_net_config refers to the link + * https://docs.oasis-open.org/virtio/virtio/v1.2/cs01/ + * virtio-v1.2-cs01.html#x1-2230004. + */ + +begin_packed_struct struct virtio_net_config_s +{ + uint8_t mac[IFHWADDRLEN]; /* VIRTIO_NET_F_MAC */ + uint16_t status; /* VIRTIO_NET_F_STATUS */ + uint16_t max_virtqueue_pairs; /* VIRTIO_NET_F_MQ */ + uint16_t mtu; /* VIRTIO_NET_F_MTU */ + uint32_t speed; /* VIRTIO_NET_F_SPEED_DUPLEX */ + uint8_t duplex; + uint8_t rss_max_key_size; /* VIRTIO_NET_F_RSS */ + uint16_t rss_max_indirection_table_length; + uint32_t supported_hash_types; +} end_packed_struct; + struct virtio_net_priv_s { /* This holds the information visible to the NuttX network */ @@ -487,7 +507,7 @@ static int virtio_net_init(FAR struct virtio_net_priv_s *priv, /* Initialize the virtio device */ virtio_set_status(vdev, VIRTIO_CONFIG_STATUS_DRIVER); - virtio_set_features(vdev, 0); + virtio_negotiate_features(vdev, 1 << VIRTIO_NET_F_MAC); virtio_set_status(vdev, VIRTIO_CONFIG_FEATURES_OK); vqnames[VIRTIO_NET_RX] = "virtio_net_rx"; @@ -520,6 +540,42 @@ static int virtio_net_init(FAR struct virtio_net_priv_s *priv, return OK; } +static void virtio_net_set_macaddr(FAR struct virtio_net_priv_s *priv) +{ + FAR struct net_driver_s *dev = &priv->lower.netdev; + FAR struct virtio_device *vdev = priv->vdev; + FAR uint8_t *mac = dev->d_mac.ether.ether_addr_octet; + + if (virtio_has_feature(vdev, VIRTIO_NET_F_MAC)) + { + virtio_read_config(vdev, offsetof(struct virtio_net_config_s, mac), + mac, IFHWADDRLEN); + } + else + { + /* Assign a random locally-created MAC address. + * + * TODO: The generated MAC address should be checked to see if it + * conflicts with something else on the network. + */ + + srand(time(NULL) + +#ifdef CONFIG_NETDEV_IFINDEX + dev->d_ifindex +#else + dev % 256 +#endif + ); + + mac[0] = 0x42; + mac[1] = rand() % 256; + mac[2] = rand() % 256; + mac[3] = rand() % 256; + mac[4] = rand() % 256; + mac[5] = rand() % 256; + } +} + /**************************************************************************** * Name: virtio_net_probe ****************************************************************************/ @@ -560,6 +616,8 @@ static int virtio_net_probe(FAR struct virtio_device *vdev) goto err_with_virtqueues; } + virtio_net_set_macaddr(priv); + return ret; err_with_virtqueues: