Commit 99ffc3e7 authored by Michael S. Tsirkin's avatar Michael S. Tsirkin Committed by David S. Miller

macvlan: don't touch promisc without passthrough

commit df8ef8f3
"macvlan: add FDB bridge ops and macvlan flags"
added a way to control NOPROMISC macvlan flag through netlink.

However, with a non passthrough device we never set promisc on open,
even if NOPROMISC is off.  As a result:

If userspace clears NOPROMISC on open, then does not clear it on a
netlink command, promisc counter is not decremented on stop and there
will be no way to clear it once macvlan is detached.

If userspace does not clear NOPROMISC on open, then sets NOPROMISC on a
netlink command, promisc counter will be decremented from 0 and overflow
to fffffffff with no way to clear promisc.

To fix, simply ignore NOPROMISC flag in a netlink command for
non-passthrough devices, same as we do at open/close.

Since we touch this code anyway - check dev_set_promiscuity return code
and pass it to users (though an error here is unlikely).

Cc: "David S. Miller" <davem@davemloft.net>
Reviewed-by: default avatarJohn Fastabend <john.r.fastabend@intel.com>
Signed-off-by: default avatarMichael S. Tsirkin <mst@redhat.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 26e04462
...@@ -853,18 +853,24 @@ static int macvlan_changelink(struct net_device *dev, ...@@ -853,18 +853,24 @@ static int macvlan_changelink(struct net_device *dev,
struct nlattr *tb[], struct nlattr *data[]) struct nlattr *tb[], struct nlattr *data[])
{ {
struct macvlan_dev *vlan = netdev_priv(dev); struct macvlan_dev *vlan = netdev_priv(dev);
if (data && data[IFLA_MACVLAN_MODE])
vlan->mode = nla_get_u32(data[IFLA_MACVLAN_MODE]);
if (data && data[IFLA_MACVLAN_FLAGS]) { if (data && data[IFLA_MACVLAN_FLAGS]) {
__u16 flags = nla_get_u16(data[IFLA_MACVLAN_FLAGS]); __u16 flags = nla_get_u16(data[IFLA_MACVLAN_FLAGS]);
bool promisc = (flags ^ vlan->flags) & MACVLAN_FLAG_NOPROMISC; bool promisc = (flags ^ vlan->flags) & MACVLAN_FLAG_NOPROMISC;
if (vlan->port->passthru && promisc) {
int err;
if (promisc && (flags & MACVLAN_FLAG_NOPROMISC)) if (flags & MACVLAN_FLAG_NOPROMISC)
dev_set_promiscuity(vlan->lowerdev, -1); err = dev_set_promiscuity(vlan->lowerdev, -1);
else if (promisc && !(flags & MACVLAN_FLAG_NOPROMISC)) else
dev_set_promiscuity(vlan->lowerdev, 1); err = dev_set_promiscuity(vlan->lowerdev, 1);
if (err < 0)
return err;
}
vlan->flags = flags; vlan->flags = flags;
} }
if (data && data[IFLA_MACVLAN_MODE])
vlan->mode = nla_get_u32(data[IFLA_MACVLAN_MODE]);
return 0; return 0;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment