Patchwork [RFC] net: add a flag to disable mac/vlan filtering

login
register
mail settings
Submitter Michael S. Tsirkin
Date March 9, 2010, 1:15 p.m.
Message ID <20100309131544.GA15319@redhat.com>
Download mbox | patch
Permalink /patch/47160/
State New
Headers show

Comments

Michael S. Tsirkin - March 9, 2010, 1:15 p.m.
New bridge in linux 2.6.34 adds IGMP snooping support,
after which bridge should not normally flood any packets.
While we still need mac table to arm forwarding tables
after migration, we can thus ignore it for rx datapath.

For vlan, it's possible to do filtering down the
stack simply by using bridge per guest and binding said bridge
to vlan device, which some people do.

Since qemu has no easy way to check IGMP snooping
support in bridge or how it's connected, add options
to disable rx filtering, so that management can set it
as appropriate.
Use these options to optimise virtio-net rx path.
We still ask guest for the list of vlans/macs for
migration.

Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
Cc: Alex Williamson <alex.williamson@hp.com>
Cc: Andreas Plesner Jacobsen <apj@mutt.dk>
---
 hw/virtio-net.c |   10 +++++++++-
 net.h           |   12 +++++++++++-
 2 files changed, 20 insertions(+), 2 deletions(-)
Anthony Liguori - March 9, 2010, 2:43 p.m.
On 03/09/2010 07:15 AM, Michael S. Tsirkin wrote:
> New bridge in linux 2.6.34 adds IGMP snooping support,
> after which bridge should not normally flood any packets.
> While we still need mac table to arm forwarding tables
> after migration, we can thus ignore it for rx datapath.
>
> For vlan, it's possible to do filtering down the
> stack simply by using bridge per guest and binding said bridge
> to vlan device, which some people do.
>
> Since qemu has no easy way to check IGMP snooping
> support in bridge or how it's connected, add options
> to disable rx filtering, so that management can set it
> as appropriate.
> Use these options to optimise virtio-net rx path.
> We still ask guest for the list of vlans/macs for
> migration.
>
> Signed-off-by: Michael S. Tsirkin<mst@redhat.com>
>    

Can't this be achieved by just disabling the feature bits?  IOW,

ctrl_vq=0,ctrl_vlan=0?

Regards,

Anthony Liguori

> Cc: Alex Williamson<alex.williamson@hp.com>
> Cc: Andreas Plesner Jacobsen<apj@mutt.dk>
> ---
>   hw/virtio-net.c |   10 +++++++++-
>   net.h           |   12 +++++++++++-
>   2 files changed, 20 insertions(+), 2 deletions(-)
>
> diff --git a/hw/virtio-net.c b/hw/virtio-net.c
> index 5c0093e..01b45ed 100644
> --- a/hw/virtio-net.c
> +++ b/hw/virtio-net.c
> @@ -47,6 +47,7 @@ typedef struct VirtIONet
>       uint8_t nomulti;
>       uint8_t nouni;
>       uint8_t nobcast;
> +    uint32_t filtering;
>       struct {
>           int in_use;
>           int first_multi;
> @@ -475,12 +476,17 @@ static int receive_filter(VirtIONet *n, const uint8_t *buf, int size)
>           ptr += sizeof(struct virtio_net_hdr);
>       }
>
> -    if (!memcmp(&ptr[12], vlan, sizeof(vlan))) {
> +    if ((n->filtering&  (0x1<<  NICCONF_F_VLAN_FILTERING))&&
> +        !memcmp(&ptr[12], vlan, sizeof(vlan))) {
>           int vid = be16_to_cpup((uint16_t *)(ptr + 14))&  0xfff;
>           if (!(n->vlans[vid>>  5]&  (1U<<  (vid&  0x1f))))
>               return 0;
>       }
>
> +    if (!(n->filtering&  (0x1<<  NICCONF_F_MAC_FILTERING))) {
> +            return 1;
> +    }
> +
>       if (ptr[0]&  1) { // multicast
>           if (!memcmp(ptr, bcast, sizeof(bcast))) {
>               return !n->nobcast;
> @@ -863,6 +869,8 @@ VirtIODevice *virtio_net_init(DeviceState *dev, NICConf *conf)
>
>       n->mac_table.macs = qemu_mallocz(MAC_TABLE_ENTRIES * ETH_ALEN);
>
> +    n->filtering = conf->filtering;
> +
>       n->vlans = qemu_mallocz(MAX_VLAN>>  3);
>
>       register_savevm("virtio-net", virtio_net_id++, VIRTIO_NET_VM_VERSION,
> diff --git a/net.h b/net.h
> index 33a1eaf..459ede5 100644
> --- a/net.h
> +++ b/net.h
> @@ -18,12 +18,22 @@ typedef struct NICConf {
>       MACAddr macaddr;
>       VLANState *vlan;
>       VLANClientState *peer;
> +    uint32_t filtering;
>   } NICConf;
>
> +enum {
> +    NICCONF_F_MAC_FILTERING = 0,
> +    NICCONF_F_VLAN_FILTERING = 1
> +};
> +
>   #define DEFINE_NIC_PROPERTIES(_state, _conf)                            \
>       DEFINE_PROP_MACADDR("mac",   _state, _conf.macaddr),                \
>       DEFINE_PROP_VLAN("vlan",     _state, _conf.vlan),                   \
> -    DEFINE_PROP_NETDEV("netdev", _state, _conf.peer)
> +    DEFINE_PROP_NETDEV("netdev", _state, _conf.peer),                    \
> +    DEFINE_PROP_BIT("mac_filtering", _state, _conf.filtering,           \
> +                     NICCONF_F_MAC_FILTERING, true)                     \
> +    DEFINE_PROP_BIT("vlan_filtering", _state, _conf.filtering,          \
> +                     NICCONF_F_VLAN_FILTERING, true)                    \
>
>   /* VLANs support */
>
>
Alex Williamson - March 9, 2010, 3:09 p.m.
On Tue, 2010-03-09 at 08:43 -0600, Anthony Liguori wrote:
> On 03/09/2010 07:15 AM, Michael S. Tsirkin wrote:
> > New bridge in linux 2.6.34 adds IGMP snooping support,
> > after which bridge should not normally flood any packets.
> > While we still need mac table to arm forwarding tables
> > after migration, we can thus ignore it for rx datapath.
> >
> > For vlan, it's possible to do filtering down the
> > stack simply by using bridge per guest and binding said bridge
> > to vlan device, which some people do.
> >
> > Since qemu has no easy way to check IGMP snooping
> > support in bridge or how it's connected, add options
> > to disable rx filtering, so that management can set it
> > as appropriate.
> > Use these options to optimise virtio-net rx path.
> > We still ask guest for the list of vlans/macs for
> > migration.
> >
> > Signed-off-by: Michael S. Tsirkin<mst@redhat.com>
> >    
> 
> Can't this be achieved by just disabling the feature bits?  IOW,
> 
> ctrl_vq=0,ctrl_vlan=0?

Michael still wants the guest to populate the MAC filter table so that
we can use it to announce MACs on the bridge, especially after a
migration.

Alex
Michael S. Tsirkin - March 9, 2010, 3:10 p.m.
On Tue, Mar 09, 2010 at 08:43:12AM -0600, Anthony Liguori wrote:
> On 03/09/2010 07:15 AM, Michael S. Tsirkin wrote:
>> New bridge in linux 2.6.34 adds IGMP snooping support,
>> after which bridge should not normally flood any packets.
>> While we still need mac table to arm forwarding tables
>> after migration, we can thus ignore it for rx datapath.
>>
>> For vlan, it's possible to do filtering down the
>> stack simply by using bridge per guest and binding said bridge
>> to vlan device, which some people do.
>>
>> Since qemu has no easy way to check IGMP snooping
>> support in bridge or how it's connected, add options
>> to disable rx filtering, so that management can set it
>> as appropriate.
>> Use these options to optimise virtio-net rx path.
>> We still ask guest for the list of vlans/macs for
>> migration.
>>
>> Signed-off-by: Michael S. Tsirkin<mst@redhat.com>
>>    
>
> Can't this be achieved by just disabling the feature bits?  IOW,
>
> ctrl_vq=0,ctrl_vlan=0?
>
> Regards,
>
> Anthony Liguori

It can, but then we won't be able to migrate to a host
that does not do the filtering in host kernel.

>> Cc: Alex Williamson<alex.williamson@hp.com>
>> Cc: Andreas Plesner Jacobsen<apj@mutt.dk>
>> ---
>>   hw/virtio-net.c |   10 +++++++++-
>>   net.h           |   12 +++++++++++-
>>   2 files changed, 20 insertions(+), 2 deletions(-)
>>
>> diff --git a/hw/virtio-net.c b/hw/virtio-net.c
>> index 5c0093e..01b45ed 100644
>> --- a/hw/virtio-net.c
>> +++ b/hw/virtio-net.c
>> @@ -47,6 +47,7 @@ typedef struct VirtIONet
>>       uint8_t nomulti;
>>       uint8_t nouni;
>>       uint8_t nobcast;
>> +    uint32_t filtering;
>>       struct {
>>           int in_use;
>>           int first_multi;
>> @@ -475,12 +476,17 @@ static int receive_filter(VirtIONet *n, const uint8_t *buf, int size)
>>           ptr += sizeof(struct virtio_net_hdr);
>>       }
>>
>> -    if (!memcmp(&ptr[12], vlan, sizeof(vlan))) {
>> +    if ((n->filtering&  (0x1<<  NICCONF_F_VLAN_FILTERING))&&
>> +        !memcmp(&ptr[12], vlan, sizeof(vlan))) {
>>           int vid = be16_to_cpup((uint16_t *)(ptr + 14))&  0xfff;
>>           if (!(n->vlans[vid>>  5]&  (1U<<  (vid&  0x1f))))
>>               return 0;
>>       }
>>
>> +    if (!(n->filtering&  (0x1<<  NICCONF_F_MAC_FILTERING))) {
>> +            return 1;
>> +    }
>> +
>>       if (ptr[0]&  1) { // multicast
>>           if (!memcmp(ptr, bcast, sizeof(bcast))) {
>>               return !n->nobcast;
>> @@ -863,6 +869,8 @@ VirtIODevice *virtio_net_init(DeviceState *dev, NICConf *conf)
>>
>>       n->mac_table.macs = qemu_mallocz(MAC_TABLE_ENTRIES * ETH_ALEN);
>>
>> +    n->filtering = conf->filtering;
>> +
>>       n->vlans = qemu_mallocz(MAX_VLAN>>  3);
>>
>>       register_savevm("virtio-net", virtio_net_id++, VIRTIO_NET_VM_VERSION,
>> diff --git a/net.h b/net.h
>> index 33a1eaf..459ede5 100644
>> --- a/net.h
>> +++ b/net.h
>> @@ -18,12 +18,22 @@ typedef struct NICConf {
>>       MACAddr macaddr;
>>       VLANState *vlan;
>>       VLANClientState *peer;
>> +    uint32_t filtering;
>>   } NICConf;
>>
>> +enum {
>> +    NICCONF_F_MAC_FILTERING = 0,
>> +    NICCONF_F_VLAN_FILTERING = 1
>> +};
>> +
>>   #define DEFINE_NIC_PROPERTIES(_state, _conf)                            \
>>       DEFINE_PROP_MACADDR("mac",   _state, _conf.macaddr),                \
>>       DEFINE_PROP_VLAN("vlan",     _state, _conf.vlan),                   \
>> -    DEFINE_PROP_NETDEV("netdev", _state, _conf.peer)
>> +    DEFINE_PROP_NETDEV("netdev", _state, _conf.peer),                    \
>> +    DEFINE_PROP_BIT("mac_filtering", _state, _conf.filtering,           \
>> +                     NICCONF_F_MAC_FILTERING, true)                     \
>> +    DEFINE_PROP_BIT("vlan_filtering", _state, _conf.filtering,          \
>> +                     NICCONF_F_VLAN_FILTERING, true)                    \
>>
>>   /* VLANs support */
>>
>>
Alex Williamson - March 9, 2010, 3:19 p.m.
On Tue, 2010-03-09 at 15:15 +0200, Michael S. Tsirkin wrote:
> diff --git a/hw/virtio-net.c b/hw/virtio-net.c
> index 5c0093e..01b45ed 100644
> --- a/hw/virtio-net.c
> +++ b/hw/virtio-net.c
> @@ -47,6 +47,7 @@ typedef struct VirtIONet
>      uint8_t nomulti;
>      uint8_t nouni;
>      uint8_t nobcast;
> +    uint32_t filtering;
>      struct {
>          int in_use;
>          int first_multi;
> @@ -475,12 +476,17 @@ static int receive_filter(VirtIONet *n, const uint8_t *buf, int size)
>          ptr += sizeof(struct virtio_net_hdr);
>      }
>  
> -    if (!memcmp(&ptr[12], vlan, sizeof(vlan))) {
> +    if ((n->filtering & (0x1 << NICCONF_F_VLAN_FILTERING)) &&
> +        !memcmp(&ptr[12], vlan, sizeof(vlan))) {
>          int vid = be16_to_cpup((uint16_t *)(ptr + 14)) & 0xfff;
>          if (!(n->vlans[vid >> 5] & (1U << (vid & 0x1f))))
>              return 0;
>      }
>  
> +    if (!(n->filtering & (0x1 << NICCONF_F_MAC_FILTERING))) {
> +            return 1;
> +    }
> +

A filtering flags bitmap is a logical choice here, but I found the
overhead to be non-trivial, which is why we have separate variables for
the other filtering options.

>      if (ptr[0] & 1) { // multicast
>          if (!memcmp(ptr, bcast, sizeof(bcast))) {
>              return !n->nobcast;
> @@ -863,6 +869,8 @@ VirtIODevice *virtio_net_init(DeviceState *dev, NICConf *conf)
>  
>      n->mac_table.macs = qemu_mallocz(MAC_TABLE_ENTRIES * ETH_ALEN);
>  
> +    n->filtering = conf->filtering;
> +

Since we're not touching this in the savevm code, I assume the intention
is that we can transparently migrate between filtered bridges and
non-filtered bridges, right?  Thanks,

Alex
Michael S. Tsirkin - March 9, 2010, 3:30 p.m.
On Tue, Mar 09, 2010 at 08:19:12AM -0700, Alex Williamson wrote:
> On Tue, 2010-03-09 at 15:15 +0200, Michael S. Tsirkin wrote:
> > diff --git a/hw/virtio-net.c b/hw/virtio-net.c
> > index 5c0093e..01b45ed 100644
> > --- a/hw/virtio-net.c
> > +++ b/hw/virtio-net.c
> > @@ -47,6 +47,7 @@ typedef struct VirtIONet
> >      uint8_t nomulti;
> >      uint8_t nouni;
> >      uint8_t nobcast;
> > +    uint32_t filtering;
> >      struct {
> >          int in_use;
> >          int first_multi;
> > @@ -475,12 +476,17 @@ static int receive_filter(VirtIONet *n, const uint8_t *buf, int size)
> >          ptr += sizeof(struct virtio_net_hdr);
> >      }
> >  
> > -    if (!memcmp(&ptr[12], vlan, sizeof(vlan))) {
> > +    if ((n->filtering & (0x1 << NICCONF_F_VLAN_FILTERING)) &&
> > +        !memcmp(&ptr[12], vlan, sizeof(vlan))) {
> >          int vid = be16_to_cpup((uint16_t *)(ptr + 14)) & 0xfff;
> >          if (!(n->vlans[vid >> 5] & (1U << (vid & 0x1f))))
> >              return 0;
> >      }
> >  
> > +    if (!(n->filtering & (0x1 << NICCONF_F_MAC_FILTERING))) {
> > +            return 1;
> > +    }
> > +
> 
> A filtering flags bitmap is a logical choice here, but I found the
> overhead to be non-trivial, which is why we have separate variables for
> the other filtering options.

You suggest more flags for multicast etc?

> >      if (ptr[0] & 1) { // multicast
> >          if (!memcmp(ptr, bcast, sizeof(bcast))) {
> >              return !n->nobcast;
> > @@ -863,6 +869,8 @@ VirtIODevice *virtio_net_init(DeviceState *dev, NICConf *conf)
> >  
> >      n->mac_table.macs = qemu_mallocz(MAC_TABLE_ENTRIES * ETH_ALEN);
> >  
> > +    n->filtering = conf->filtering;
> > +
> 
> Since we're not touching this in the savevm code, I assume the intention
> is that we can transparently migrate between filtered bridges and
> non-filtered bridges, right?

Right.

>  Thanks,
> 
> Alex
Michael S. Tsirkin - March 9, 2010, 3:48 p.m.
On Tue, Mar 09, 2010 at 05:30:31PM +0200, Michael S. Tsirkin wrote:
> On Tue, Mar 09, 2010 at 08:19:12AM -0700, Alex Williamson wrote:
> > On Tue, 2010-03-09 at 15:15 +0200, Michael S. Tsirkin wrote:
> > > diff --git a/hw/virtio-net.c b/hw/virtio-net.c
> > > index 5c0093e..01b45ed 100644
> > > --- a/hw/virtio-net.c
> > > +++ b/hw/virtio-net.c
> > > @@ -47,6 +47,7 @@ typedef struct VirtIONet
> > >      uint8_t nomulti;
> > >      uint8_t nouni;
> > >      uint8_t nobcast;
> > > +    uint32_t filtering;
> > >      struct {
> > >          int in_use;
> > >          int first_multi;
> > > @@ -475,12 +476,17 @@ static int receive_filter(VirtIONet *n, const uint8_t *buf, int size)
> > >          ptr += sizeof(struct virtio_net_hdr);
> > >      }
> > >  
> > > -    if (!memcmp(&ptr[12], vlan, sizeof(vlan))) {
> > > +    if ((n->filtering & (0x1 << NICCONF_F_VLAN_FILTERING)) &&
> > > +        !memcmp(&ptr[12], vlan, sizeof(vlan))) {
> > >          int vid = be16_to_cpup((uint16_t *)(ptr + 14)) & 0xfff;
> > >          if (!(n->vlans[vid >> 5] & (1U << (vid & 0x1f))))
> > >              return 0;
> > >      }
> > >  
> > > +    if (!(n->filtering & (0x1 << NICCONF_F_MAC_FILTERING))) {
> > > +            return 1;
> > > +    }
> > > +
> > 
> > A filtering flags bitmap is a logical choice here, but I found the
> > overhead to be non-trivial, which is why we have separate variables for
> > the other filtering options.
> 
> You suggest more flags for multicast etc?

Might not be a bad idea: e.g. tap filtering table in kernel
is limited in size, so we might win from only downloading
necessary mac addresses there.

> > >      if (ptr[0] & 1) { // multicast
> > >          if (!memcmp(ptr, bcast, sizeof(bcast))) {
> > >              return !n->nobcast;
> > > @@ -863,6 +869,8 @@ VirtIODevice *virtio_net_init(DeviceState *dev, NICConf *conf)
> > >  
> > >      n->mac_table.macs = qemu_mallocz(MAC_TABLE_ENTRIES * ETH_ALEN);
> > >  
> > > +    n->filtering = conf->filtering;
> > > +
> > 
> > Since we're not touching this in the savevm code, I assume the intention
> > is that we can transparently migrate between filtered bridges and
> > non-filtered bridges, right?
> 
> Right.
> 
> >  Thanks,
> > 
> > Alex
Paul Brook - March 9, 2010, 3:54 p.m.
> > Can't this be achieved by just disabling the feature bits?  IOW,
> >
> > ctrl_vq=0,ctrl_vlan=0?
> 
> Michael still wants the guest to populate the MAC filter table so that
> we can use it to announce MACs on the bridge, especially after a
> migration.

We don't do that to start with.  We only set gratuitous ARPs for the MAC 
address of the emulated NIC.  I'm not convinced anything else is useful.

Paul
Alex Williamson - March 9, 2010, 4:11 p.m.
On Tue, 2010-03-09 at 17:30 +0200, Michael S. Tsirkin wrote:
> On Tue, Mar 09, 2010 at 08:19:12AM -0700, Alex Williamson wrote:
> > On Tue, 2010-03-09 at 15:15 +0200, Michael S. Tsirkin wrote:
> > > diff --git a/hw/virtio-net.c b/hw/virtio-net.c
> > > index 5c0093e..01b45ed 100644
> > > --- a/hw/virtio-net.c
> > > +++ b/hw/virtio-net.c
> > > @@ -47,6 +47,7 @@ typedef struct VirtIONet
> > >      uint8_t nomulti;
> > >      uint8_t nouni;
> > >      uint8_t nobcast;
> > > +    uint32_t filtering;
> > >      struct {
> > >          int in_use;
> > >          int first_multi;
> > > @@ -475,12 +476,17 @@ static int receive_filter(VirtIONet *n, const uint8_t *buf, int size)
> > >          ptr += sizeof(struct virtio_net_hdr);
> > >      }
> > >  
> > > -    if (!memcmp(&ptr[12], vlan, sizeof(vlan))) {
> > > +    if ((n->filtering & (0x1 << NICCONF_F_VLAN_FILTERING)) &&
> > > +        !memcmp(&ptr[12], vlan, sizeof(vlan))) {
> > >          int vid = be16_to_cpup((uint16_t *)(ptr + 14)) & 0xfff;
> > >          if (!(n->vlans[vid >> 5] & (1U << (vid & 0x1f))))
> > >              return 0;
> > >      }
> > >  
> > > +    if (!(n->filtering & (0x1 << NICCONF_F_MAC_FILTERING))) {
> > > +            return 1;
> > > +    }
> > > +
> > 
> > A filtering flags bitmap is a logical choice here, but I found the
> > overhead to be non-trivial, which is why we have separate variables for
> > the other filtering options.
> 
> You suggest more flags for multicast etc?

I'm suggesting we may get slightly better performance if we use separate
filter_mac and filter_vlan variable flags instead of a single
"filtering" flags bitmap.  However, a couple other ideas... Should we
call receive_filter() as a function pointer so we can make filter
specific versions or remove it completely?  Some overhead to calling it
as a pointer, but could still be a win.  Alternatively we could make
"effective" filter flags which are used by receive_filter(), but
maintained separately from the guest requested flags.  For instance:

virtio_net_handle_rx_mode(...)
{
...
n->alluni_effective = (n->filtering & (0x1 << NICCONF_F_MAC_FILTERING)) ? n->alluni : 1;
n->allmulti_effective = (n->filtering & (0x1 << NICCONF_F_MAC_FILTERING)) ? n->allmulti : 1;

These could be recreated on loadvm, so we still wouldn't need to save
them.  Question would be whether that creates a sufficiently fast path
through receive_filter().  We'd still need a new flag for vlan filtering
or maybe make the vlan header match bytes settable.

Alex
Michael S. Tsirkin - March 9, 2010, 4:18 p.m.
On Tue, Mar 09, 2010 at 09:11:33AM -0700, Alex Williamson wrote:
> On Tue, 2010-03-09 at 17:30 +0200, Michael S. Tsirkin wrote:
> > On Tue, Mar 09, 2010 at 08:19:12AM -0700, Alex Williamson wrote:
> > > On Tue, 2010-03-09 at 15:15 +0200, Michael S. Tsirkin wrote:
> > > > diff --git a/hw/virtio-net.c b/hw/virtio-net.c
> > > > index 5c0093e..01b45ed 100644
> > > > --- a/hw/virtio-net.c
> > > > +++ b/hw/virtio-net.c
> > > > @@ -47,6 +47,7 @@ typedef struct VirtIONet
> > > >      uint8_t nomulti;
> > > >      uint8_t nouni;
> > > >      uint8_t nobcast;
> > > > +    uint32_t filtering;
> > > >      struct {
> > > >          int in_use;
> > > >          int first_multi;
> > > > @@ -475,12 +476,17 @@ static int receive_filter(VirtIONet *n, const uint8_t *buf, int size)
> > > >          ptr += sizeof(struct virtio_net_hdr);
> > > >      }
> > > >  
> > > > -    if (!memcmp(&ptr[12], vlan, sizeof(vlan))) {
> > > > +    if ((n->filtering & (0x1 << NICCONF_F_VLAN_FILTERING)) &&
> > > > +        !memcmp(&ptr[12], vlan, sizeof(vlan))) {
> > > >          int vid = be16_to_cpup((uint16_t *)(ptr + 14)) & 0xfff;
> > > >          if (!(n->vlans[vid >> 5] & (1U << (vid & 0x1f))))
> > > >              return 0;
> > > >      }
> > > >  
> > > > +    if (!(n->filtering & (0x1 << NICCONF_F_MAC_FILTERING))) {
> > > > +            return 1;
> > > > +    }
> > > > +
> > > 
> > > A filtering flags bitmap is a logical choice here, but I found the
> > > overhead to be non-trivial, which is why we have separate variables for
> > > the other filtering options.
> > 
> > You suggest more flags for multicast etc?
> 
> I'm suggesting we may get slightly better performance if we use separate
> filter_mac and filter_vlan variable flags instead of a single
> "filtering" flags bitmap.

Why? It's a single operation anyway, and we use less cache.

>  However, a couple other ideas... Should we
> call receive_filter() as a function pointer so we can make filter
> specific versions or remove it completely?  Some overhead to calling it
> as a pointer, but could still be a win.  Alternatively we could make
> "effective" filter flags which are used by receive_filter(), but
> maintained separately from the guest requested flags.  For instance:
> 
> virtio_net_handle_rx_mode(...)
> {
> ...
> n->alluni_effective = (n->filtering & (0x1 << NICCONF_F_MAC_FILTERING)) ? n->alluni : 1;
> n->allmulti_effective = (n->filtering & (0x1 << NICCONF_F_MAC_FILTERING)) ? n->allmulti : 1;
> 
> These could be recreated on loadvm, so we still wouldn't need to save
> them.  Question would be whether that creates a sufficiently fast path
> through receive_filter().  We'd still need a new flag for vlan filtering
> or maybe make the vlan header match bytes settable.
> 
> Alex

I agree, merging flags set by guest and by host makes sense, this way we
don't need to test both. E.g. all filtering off is equivalent to promisc
mode, we test that already. More complex ideas would I guess need to be
benchmarked to be shown being worth it.  So I'll do the simple thing and
we can tweak it further later on.
Alex Williamson - March 9, 2010, 4:56 p.m.
On Tue, 2010-03-09 at 18:18 +0200, Michael S. Tsirkin wrote:
> On Tue, Mar 09, 2010 at 09:11:33AM -0700, Alex Williamson wrote:
> > On Tue, 2010-03-09 at 17:30 +0200, Michael S. Tsirkin wrote:
> > > On Tue, Mar 09, 2010 at 08:19:12AM -0700, Alex Williamson wrote:
> > > > A filtering flags bitmap is a logical choice here, but I found the
> > > > overhead to be non-trivial, which is why we have separate variables for
> > > > the other filtering options.
> > > 
> > > You suggest more flags for multicast etc?
> > 
> > I'm suggesting we may get slightly better performance if we use separate
> > filter_mac and filter_vlan variable flags instead of a single
> > "filtering" flags bitmap.
> 
> Why? It's a single operation anyway, and we use less cache.

Sorry, I must have been thinking of a runtime vs compile time shift.

Alex

Patch

diff --git a/hw/virtio-net.c b/hw/virtio-net.c
index 5c0093e..01b45ed 100644
--- a/hw/virtio-net.c
+++ b/hw/virtio-net.c
@@ -47,6 +47,7 @@  typedef struct VirtIONet
     uint8_t nomulti;
     uint8_t nouni;
     uint8_t nobcast;
+    uint32_t filtering;
     struct {
         int in_use;
         int first_multi;
@@ -475,12 +476,17 @@  static int receive_filter(VirtIONet *n, const uint8_t *buf, int size)
         ptr += sizeof(struct virtio_net_hdr);
     }
 
-    if (!memcmp(&ptr[12], vlan, sizeof(vlan))) {
+    if ((n->filtering & (0x1 << NICCONF_F_VLAN_FILTERING)) &&
+        !memcmp(&ptr[12], vlan, sizeof(vlan))) {
         int vid = be16_to_cpup((uint16_t *)(ptr + 14)) & 0xfff;
         if (!(n->vlans[vid >> 5] & (1U << (vid & 0x1f))))
             return 0;
     }
 
+    if (!(n->filtering & (0x1 << NICCONF_F_MAC_FILTERING))) {
+            return 1;
+    }
+
     if (ptr[0] & 1) { // multicast
         if (!memcmp(ptr, bcast, sizeof(bcast))) {
             return !n->nobcast;
@@ -863,6 +869,8 @@  VirtIODevice *virtio_net_init(DeviceState *dev, NICConf *conf)
 
     n->mac_table.macs = qemu_mallocz(MAC_TABLE_ENTRIES * ETH_ALEN);
 
+    n->filtering = conf->filtering;
+
     n->vlans = qemu_mallocz(MAX_VLAN >> 3);
 
     register_savevm("virtio-net", virtio_net_id++, VIRTIO_NET_VM_VERSION,
diff --git a/net.h b/net.h
index 33a1eaf..459ede5 100644
--- a/net.h
+++ b/net.h
@@ -18,12 +18,22 @@  typedef struct NICConf {
     MACAddr macaddr;
     VLANState *vlan;
     VLANClientState *peer;
+    uint32_t filtering;
 } NICConf;
 
+enum {
+    NICCONF_F_MAC_FILTERING = 0,
+    NICCONF_F_VLAN_FILTERING = 1
+};
+
 #define DEFINE_NIC_PROPERTIES(_state, _conf)                            \
     DEFINE_PROP_MACADDR("mac",   _state, _conf.macaddr),                \
     DEFINE_PROP_VLAN("vlan",     _state, _conf.vlan),                   \
-    DEFINE_PROP_NETDEV("netdev", _state, _conf.peer)
+    DEFINE_PROP_NETDEV("netdev", _state, _conf.peer),                    \
+    DEFINE_PROP_BIT("mac_filtering", _state, _conf.filtering,           \
+                     NICCONF_F_MAC_FILTERING, true)                     \
+    DEFINE_PROP_BIT("vlan_filtering", _state, _conf.filtering,          \
+                     NICCONF_F_VLAN_FILTERING, true)                    \
 
 /* VLANs support */