On Wed, 2009-01-07 at 11:06 -0700, Alex Williamson wrote:
> virtio_net: Enable setting MAC, promisc, and allmulti mode
> 
> Signed-off-by: Alex Williamson <alex.william...@hp.com>
> ---
> 
>  drivers/net/virtio_net.c   |   79 
> ++++++++++++++++++++++++++++++++++++++++----
>  include/linux/virtio_net.h |   11 ++++++
>  2 files changed, 82 insertions(+), 8 deletions(-)
> 
> 
> diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c
> index 3af5e33..f502edd 100644
> --- a/drivers/net/virtio_net.c
> +++ b/drivers/net/virtio_net.c
> @@ -41,7 +41,14 @@ struct virtnet_info
>       struct virtqueue *rvq, *svq;
>       struct net_device *dev;
>       struct napi_struct napi;
> -     unsigned int status;
> +     union {
> +             u16 raw;
> +             struct {
> +                     u16 link:1;
> +                     u16 promisc:1;
> +                     u16 allmulti:1;
> +             } bits;
> +     } status; 
>  
>       /* The skb we couldn't send because buffers were full. */
>       struct sk_buff *last_xmit_skb;
> @@ -476,6 +483,54 @@ static int virtnet_set_tx_csum(struct net_device *dev, 
> u32 data)
>       return ethtool_op_set_tx_hw_csum(dev, data);
>  }
>  
> +static int virtnet_set_mac_address(struct net_device *dev, void *p)
> +{
> +     struct virtnet_info *vi = netdev_priv(dev);
> +     struct virtio_device *vdev = vi->vdev;
> +     struct sockaddr *addr = p;
> +
> +     if (!is_valid_ether_addr(addr->sa_data))
> +             return -EADDRNOTAVAIL;
> +
> +     memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);

Should just use eth_mac_addr() here.

> +
> +     vdev->config->set(vdev, offsetof(struct virtio_net_config, mac),
> +                       dev->dev_addr, dev->addr_len);
> +
> +     return 0;
> +}
> +
> +static void virtnet_set_rx_mode(struct net_device *dev)
> +{

Not sure, but it might have been more appropriate to implement
change_rx_flags() for this ... but set_rx_mode() is probably correct
given the next patch.

> +     struct virtnet_info *vi = netdev_priv(dev);
> +     struct virtio_device *vdev = vi->vdev;
> +     u16 status = vi->status.raw;
> +
> +     if (!virtio_has_feature(vi->vdev, VIRTIO_NET_F_STATUS))
> +             return;
> +
> +     if (dev->flags & IFF_PROMISC)
> +             status |= VIRTIO_NET_S_PROMISC;
> +     else
> +             status &= ~VIRTIO_NET_S_PROMISC;
> +
> +     if (dev->flags & IFF_ALLMULTI)
> +             status |= VIRTIO_NET_S_ALLMULTI;
> +     else
> +             status &= ~VIRTIO_NET_S_ALLMULTI;
> +             
> +     if (dev->uc_count)
> +             status |= VIRTIO_NET_S_PROMISC;
> +     if (dev->mc_count)
> +             status |= VIRTIO_NET_S_ALLMULTI;
> +
> +     if (status != vi->status.raw) {
> +             vi->status.raw = status;
> +             vdev->config->set(vdev, offsetof(struct virtio_net_config,
> +                               status), &vi->status, sizeof(vi->status));
> +     }
> +}
> +
>  static struct ethtool_ops virtnet_ethtool_ops = {
>       .set_tx_csum = virtnet_set_tx_csum,
>       .set_sg = ethtool_op_set_sg,
> @@ -494,14 +549,15 @@ static void virtnet_update_status(struct virtnet_info 
> *vi)
>                                &v, sizeof(v));
>  
>       /* Ignore unknown (future) status bits */
> -     v &= VIRTIO_NET_S_LINK_UP;
> +     v &= VIRTIO_NET_S_LINK_UP | VIRTIO_NET_S_PROMISC |
> +             VIRTIO_NET_S_ALLMULTI;
>  
> -     if (vi->status == v)
> +     if (vi->status.raw == v)
>               return;
>  
> -     vi->status = v;
> +     vi->status.raw = v;
>  
> -     if (vi->status & VIRTIO_NET_S_LINK_UP) {
> +     if (vi->status.bits.link) {
>               netif_carrier_on(vi->dev);
>               netif_wake_queue(vi->dev);
>       } else {
> @@ -563,8 +619,17 @@ static int virtnet_probe(struct virtio_device *vdev)
>               vdev->config->get(vdev,
>                                 offsetof(struct virtio_net_config, mac),
>                                 dev->dev_addr, dev->addr_len);
> -     } else
> +     } else {
> +             struct sockaddr addr;
> +
>               random_ether_addr(dev->dev_addr);
> +             memset(&addr, 0, sizeof(addr));
> +             memcpy(&addr.sa_data, dev->dev_addr, dev->addr_len);
> +             virtnet_set_mac_address(dev, &addr);

I'd prefer just to vdev->config->set() directly here. set_mac_address()
isn't really appropriate.

> +     }
> +
> +     dev->set_mac_address = virtnet_set_mac_address;
> +     dev->set_rx_mode = virtnet_set_rx_mode;
>  
>       /* Set up our device-specific information */
>       vi = netdev_priv(dev);
> @@ -621,7 +686,7 @@ static int virtnet_probe(struct virtio_device *vdev)
>               goto unregister;
>       }
>  
> -     vi->status = VIRTIO_NET_S_LINK_UP;
> +     vi->status.raw = VIRTIO_NET_S_LINK_UP;
>       virtnet_update_status(vi);
>  
>       pr_debug("virtnet: registered device %s\n", dev->name);
> diff --git a/include/linux/virtio_net.h b/include/linux/virtio_net.h
> index d9174be..5a70edb 100644
> --- a/include/linux/virtio_net.h
> +++ b/include/linux/virtio_net.h
> @@ -23,6 +23,8 @@
>  #define VIRTIO_NET_F_STATUS  16      /* virtio_net_config.status available */
>  
>  #define VIRTIO_NET_S_LINK_UP 1       /* Link is up */
> +#define VIRTIO_NET_S_PROMISC 2       /* Promiscuous mode */

The current behaviour is PROMISC, right?

So, by not setting this flag you get PROMISC anyway?

Does that suggest we need a feature flag for this, or make zero reflect
the current host behaviour ... i.e. change the bit to S_CHASTE ?

(Chaste is the antonym to promiscuous, apparently :-)

> +#define VIRTIO_NET_S_ALLMULTI        4       /* All-multicast mode */

An issue here is that the LINK_UP bit is controlled by the host, but the
PROMISC and ALLMULTI are controlled by the guest - i.e. they can race.

Suggest giving the top 8 bits to the guest and keeping the bottom 8 bits
for the host.

>  struct virtio_net_config
>  {
> @@ -30,7 +32,14 @@ struct virtio_net_config
>       __u8 mac[6];
>       /* Status supplied by host; see VIRTIO_NET_F_STATUS and VIRTIO_NET_S_*
>        * bits above */
> -     __u16 status;
> +     union {
> +             __u16 raw;
> +             struct {
> +                     __u16 link:1;
> +                     __u16 promisc:1;
> +                     __u16 allmulti:1;
> +             } bits;
> +       } status;

Agree with Anthony on this, much rather we continued using the #defines.

Cheers,
Mark.

--
To unsubscribe from this list: send the line "unsubscribe kvm" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to