hw/virtio-net.c: set config size using host features
Currently, the config size for virtio devices is hard coded. When a new feature is added that changes the config size, drivers that assume a static config size will break. For purposes of backward compatibility, there needs to be a way to inform drivers of the config size needed to accommodate the set of features enabled. aliguori: merged in - hw/virtio-net: use existing macros to implement endof - hw/virtio-net: fix config_size data type Signed-off-by: Jesse Larrew <jlarrew@linux.vnet.ibm.com> Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
This commit is contained in:
		
							parent
							
								
									1e89ad5b00
								
							
						
					
					
						commit
						14f9b664b3
					
				@ -73,8 +73,31 @@ typedef struct VirtIONet
 | 
				
			|||||||
    int multiqueue;
 | 
					    int multiqueue;
 | 
				
			||||||
    uint16_t max_queues;
 | 
					    uint16_t max_queues;
 | 
				
			||||||
    uint16_t curr_queues;
 | 
					    uint16_t curr_queues;
 | 
				
			||||||
 | 
					    size_t config_size;
 | 
				
			||||||
} VirtIONet;
 | 
					} VirtIONet;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Calculate the number of bytes up to and including the given 'field' of
 | 
				
			||||||
 | 
					 * 'container'.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					#define endof(container, field) \
 | 
				
			||||||
 | 
					    (offsetof(container, field) + sizeof(((container *)0)->field))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					typedef struct VirtIOFeature {
 | 
				
			||||||
 | 
					    uint32_t flags;
 | 
				
			||||||
 | 
					    size_t end;
 | 
				
			||||||
 | 
					} VirtIOFeature;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static VirtIOFeature feature_sizes[] = {
 | 
				
			||||||
 | 
					    {.flags = 1 << VIRTIO_NET_F_MAC,
 | 
				
			||||||
 | 
					     .end = endof(struct virtio_net_config, mac)},
 | 
				
			||||||
 | 
					    {.flags = 1 << VIRTIO_NET_F_STATUS,
 | 
				
			||||||
 | 
					     .end = endof(struct virtio_net_config, status)},
 | 
				
			||||||
 | 
					    {.flags = 1 << VIRTIO_NET_F_MQ,
 | 
				
			||||||
 | 
					     .end = endof(struct virtio_net_config, max_virtqueue_pairs)},
 | 
				
			||||||
 | 
					    {}
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static VirtIONetQueue *virtio_net_get_subqueue(NetClientState *nc)
 | 
					static VirtIONetQueue *virtio_net_get_subqueue(NetClientState *nc)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    VirtIONet *n = qemu_get_nic_opaque(nc);
 | 
					    VirtIONet *n = qemu_get_nic_opaque(nc);
 | 
				
			||||||
@ -104,15 +127,15 @@ static void virtio_net_get_config(VirtIODevice *vdev, uint8_t *config)
 | 
				
			|||||||
    stw_p(&netcfg.status, n->status);
 | 
					    stw_p(&netcfg.status, n->status);
 | 
				
			||||||
    stw_p(&netcfg.max_virtqueue_pairs, n->max_queues);
 | 
					    stw_p(&netcfg.max_virtqueue_pairs, n->max_queues);
 | 
				
			||||||
    memcpy(netcfg.mac, n->mac, ETH_ALEN);
 | 
					    memcpy(netcfg.mac, n->mac, ETH_ALEN);
 | 
				
			||||||
    memcpy(config, &netcfg, sizeof(netcfg));
 | 
					    memcpy(config, &netcfg, n->config_size);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void virtio_net_set_config(VirtIODevice *vdev, const uint8_t *config)
 | 
					static void virtio_net_set_config(VirtIODevice *vdev, const uint8_t *config)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    VirtIONet *n = to_virtio_net(vdev);
 | 
					    VirtIONet *n = to_virtio_net(vdev);
 | 
				
			||||||
    struct virtio_net_config netcfg;
 | 
					    struct virtio_net_config netcfg = {};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    memcpy(&netcfg, config, sizeof(netcfg));
 | 
					    memcpy(&netcfg, config, n->config_size);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (!(n->vdev.guest_features >> VIRTIO_NET_F_CTRL_MAC_ADDR & 1) &&
 | 
					    if (!(n->vdev.guest_features >> VIRTIO_NET_F_CTRL_MAC_ADDR & 1) &&
 | 
				
			||||||
        memcmp(netcfg.mac, n->mac, ETH_ALEN)) {
 | 
					        memcmp(netcfg.mac, n->mac, ETH_ALEN)) {
 | 
				
			||||||
@ -1279,16 +1302,21 @@ static void virtio_net_guest_notifier_mask(VirtIODevice *vdev, int idx,
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
VirtIODevice *virtio_net_init(DeviceState *dev, NICConf *conf,
 | 
					VirtIODevice *virtio_net_init(DeviceState *dev, NICConf *conf,
 | 
				
			||||||
                              virtio_net_conf *net,
 | 
					                              virtio_net_conf *net, uint32_t host_features)
 | 
				
			||||||
                              uint32_t host_features)
 | 
					 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    VirtIONet *n;
 | 
					    VirtIONet *n;
 | 
				
			||||||
    int i;
 | 
					    int i, config_size = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for (i = 0; feature_sizes[i].flags != 0; i++) {
 | 
				
			||||||
 | 
					        if (host_features & feature_sizes[i].flags) {
 | 
				
			||||||
 | 
					            config_size = MAX(feature_sizes[i].end, config_size);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    n = (VirtIONet *)virtio_common_init("virtio-net", VIRTIO_ID_NET,
 | 
					    n = (VirtIONet *)virtio_common_init("virtio-net", VIRTIO_ID_NET,
 | 
				
			||||||
                                        sizeof(struct virtio_net_config),
 | 
					                                        config_size, sizeof(VirtIONet));
 | 
				
			||||||
                                        sizeof(VirtIONet));
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    n->config_size = config_size;
 | 
				
			||||||
    n->vdev.get_config = virtio_net_get_config;
 | 
					    n->vdev.get_config = virtio_net_get_config;
 | 
				
			||||||
    n->vdev.set_config = virtio_net_set_config;
 | 
					    n->vdev.set_config = virtio_net_set_config;
 | 
				
			||||||
    n->vdev.get_features = virtio_net_get_features;
 | 
					    n->vdev.get_features = virtio_net_get_features;
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user