Commit df8ef8f3 authored by John Fastabend's avatar John Fastabend Committed by David S. Miller

macvlan: add FDB bridge ops and macvlan flags

This adds FDB bridge ops to the macvlan device passthru mode.
Additionally a flags field was added and a NOPROMISC bit to
allow users to use passthru mode without the driver calling
dev_set_promiscuity(). The flags field is a u16 placed in a
4 byte hole (consuming 2 bytes) of the macvlan_dev struct.

We want to do this so that the macvlan driver or stack
above the macvlan driver does not have to process every
packet. For the use case where we know all the MAC addresses
of the endstations above us this works well.

This patch is a result of Roopa Prabhu's work. Follow up
patches are needed for VEPA and VEB macvlan modes.

v2: Change from distinct nopromisc mode to a flags field to
    configure this. This avoids the tendency to add a new
    mode every time we need some slightly different behavior.
v3: fix error in dev_set_promiscuity and add change and get
    link attributes for flags.

CC: Roopa Prabhu <roprabhu@cisco.com>
CC: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: default avatarJohn Fastabend <john.r.fastabend@intel.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 2b202712
...@@ -312,7 +312,8 @@ static int macvlan_open(struct net_device *dev) ...@@ -312,7 +312,8 @@ static int macvlan_open(struct net_device *dev)
int err; int err;
if (vlan->port->passthru) { if (vlan->port->passthru) {
dev_set_promiscuity(lowerdev, 1); if (!(vlan->flags & MACVLAN_FLAG_NOPROMISC))
dev_set_promiscuity(lowerdev, 1);
goto hash_add; goto hash_add;
} }
...@@ -344,12 +345,15 @@ static int macvlan_stop(struct net_device *dev) ...@@ -344,12 +345,15 @@ static int macvlan_stop(struct net_device *dev)
struct macvlan_dev *vlan = netdev_priv(dev); struct macvlan_dev *vlan = netdev_priv(dev);
struct net_device *lowerdev = vlan->lowerdev; struct net_device *lowerdev = vlan->lowerdev;
dev_uc_unsync(lowerdev, dev);
dev_mc_unsync(lowerdev, dev);
if (vlan->port->passthru) { if (vlan->port->passthru) {
dev_set_promiscuity(lowerdev, -1); if (!(vlan->flags & MACVLAN_FLAG_NOPROMISC))
dev_set_promiscuity(lowerdev, -1);
goto hash_del; goto hash_del;
} }
dev_mc_unsync(lowerdev, dev);
if (dev->flags & IFF_ALLMULTI) if (dev->flags & IFF_ALLMULTI)
dev_set_allmulti(lowerdev, -1); dev_set_allmulti(lowerdev, -1);
...@@ -399,10 +403,11 @@ static void macvlan_change_rx_flags(struct net_device *dev, int change) ...@@ -399,10 +403,11 @@ static void macvlan_change_rx_flags(struct net_device *dev, int change)
dev_set_allmulti(lowerdev, dev->flags & IFF_ALLMULTI ? 1 : -1); dev_set_allmulti(lowerdev, dev->flags & IFF_ALLMULTI ? 1 : -1);
} }
static void macvlan_set_multicast_list(struct net_device *dev) static void macvlan_set_mac_lists(struct net_device *dev)
{ {
struct macvlan_dev *vlan = netdev_priv(dev); struct macvlan_dev *vlan = netdev_priv(dev);
dev_uc_sync(vlan->lowerdev, dev);
dev_mc_sync(vlan->lowerdev, dev); dev_mc_sync(vlan->lowerdev, dev);
} }
...@@ -542,6 +547,43 @@ static int macvlan_vlan_rx_kill_vid(struct net_device *dev, ...@@ -542,6 +547,43 @@ static int macvlan_vlan_rx_kill_vid(struct net_device *dev,
return 0; return 0;
} }
static int macvlan_fdb_add(struct ndmsg *ndm,
struct net_device *dev,
unsigned char *addr,
u16 flags)
{
struct macvlan_dev *vlan = netdev_priv(dev);
int err = -EINVAL;
if (!vlan->port->passthru)
return -EOPNOTSUPP;
if (is_unicast_ether_addr(addr))
err = dev_uc_add_excl(dev, addr);
else if (is_multicast_ether_addr(addr))
err = dev_mc_add_excl(dev, addr);
return err;
}
static int macvlan_fdb_del(struct ndmsg *ndm,
struct net_device *dev,
unsigned char *addr)
{
struct macvlan_dev *vlan = netdev_priv(dev);
int err = -EINVAL;
if (!vlan->port->passthru)
return -EOPNOTSUPP;
if (is_unicast_ether_addr(addr))
err = dev_uc_del(dev, addr);
else if (is_multicast_ether_addr(addr))
err = dev_mc_del(dev, addr);
return err;
}
static void macvlan_ethtool_get_drvinfo(struct net_device *dev, static void macvlan_ethtool_get_drvinfo(struct net_device *dev,
struct ethtool_drvinfo *drvinfo) struct ethtool_drvinfo *drvinfo)
{ {
...@@ -572,11 +614,14 @@ static const struct net_device_ops macvlan_netdev_ops = { ...@@ -572,11 +614,14 @@ static const struct net_device_ops macvlan_netdev_ops = {
.ndo_change_mtu = macvlan_change_mtu, .ndo_change_mtu = macvlan_change_mtu,
.ndo_change_rx_flags = macvlan_change_rx_flags, .ndo_change_rx_flags = macvlan_change_rx_flags,
.ndo_set_mac_address = macvlan_set_mac_address, .ndo_set_mac_address = macvlan_set_mac_address,
.ndo_set_rx_mode = macvlan_set_multicast_list, .ndo_set_rx_mode = macvlan_set_mac_lists,
.ndo_get_stats64 = macvlan_dev_get_stats64, .ndo_get_stats64 = macvlan_dev_get_stats64,
.ndo_validate_addr = eth_validate_addr, .ndo_validate_addr = eth_validate_addr,
.ndo_vlan_rx_add_vid = macvlan_vlan_rx_add_vid, .ndo_vlan_rx_add_vid = macvlan_vlan_rx_add_vid,
.ndo_vlan_rx_kill_vid = macvlan_vlan_rx_kill_vid, .ndo_vlan_rx_kill_vid = macvlan_vlan_rx_kill_vid,
.ndo_fdb_add = macvlan_fdb_add,
.ndo_fdb_del = macvlan_fdb_del,
.ndo_fdb_dump = ndo_dflt_fdb_dump,
}; };
void macvlan_common_setup(struct net_device *dev) void macvlan_common_setup(struct net_device *dev)
...@@ -711,6 +756,9 @@ int macvlan_common_newlink(struct net *src_net, struct net_device *dev, ...@@ -711,6 +756,9 @@ int macvlan_common_newlink(struct net *src_net, struct net_device *dev,
if (data && data[IFLA_MACVLAN_MODE]) if (data && data[IFLA_MACVLAN_MODE])
vlan->mode = nla_get_u32(data[IFLA_MACVLAN_MODE]); vlan->mode = nla_get_u32(data[IFLA_MACVLAN_MODE]);
if (data && data[IFLA_MACVLAN_FLAGS])
vlan->flags = nla_get_u16(data[IFLA_MACVLAN_FLAGS]);
if (vlan->mode == MACVLAN_MODE_PASSTHRU) { if (vlan->mode == MACVLAN_MODE_PASSTHRU) {
if (port->count) if (port->count)
return -EINVAL; return -EINVAL;
...@@ -760,6 +808,16 @@ static int macvlan_changelink(struct net_device *dev, ...@@ -760,6 +808,16 @@ static int macvlan_changelink(struct net_device *dev,
struct macvlan_dev *vlan = netdev_priv(dev); struct macvlan_dev *vlan = netdev_priv(dev);
if (data && data[IFLA_MACVLAN_MODE]) if (data && data[IFLA_MACVLAN_MODE])
vlan->mode = nla_get_u32(data[IFLA_MACVLAN_MODE]); vlan->mode = nla_get_u32(data[IFLA_MACVLAN_MODE]);
if (data && data[IFLA_MACVLAN_FLAGS]) {
__u16 flags = nla_get_u16(data[IFLA_MACVLAN_FLAGS]);
bool promisc = (flags ^ vlan->flags) & MACVLAN_FLAG_NOPROMISC;
if (promisc && (flags & MACVLAN_FLAG_NOPROMISC))
dev_set_promiscuity(vlan->lowerdev, -1);
else if (promisc && !(flags & MACVLAN_FLAG_NOPROMISC))
dev_set_promiscuity(vlan->lowerdev, 1);
vlan->flags = flags;
}
return 0; return 0;
} }
...@@ -775,6 +833,8 @@ static int macvlan_fill_info(struct sk_buff *skb, ...@@ -775,6 +833,8 @@ static int macvlan_fill_info(struct sk_buff *skb,
if (nla_put_u32(skb, IFLA_MACVLAN_MODE, vlan->mode)) if (nla_put_u32(skb, IFLA_MACVLAN_MODE, vlan->mode))
goto nla_put_failure; goto nla_put_failure;
if (nla_put_u16(skb, IFLA_MACVLAN_FLAGS, vlan->flags))
goto nla_put_failure;
return 0; return 0;
nla_put_failure: nla_put_failure:
...@@ -782,7 +842,8 @@ static int macvlan_fill_info(struct sk_buff *skb, ...@@ -782,7 +842,8 @@ static int macvlan_fill_info(struct sk_buff *skb,
} }
static const struct nla_policy macvlan_policy[IFLA_MACVLAN_MAX + 1] = { static const struct nla_policy macvlan_policy[IFLA_MACVLAN_MAX + 1] = {
[IFLA_MACVLAN_MODE] = { .type = NLA_U32 }, [IFLA_MACVLAN_MODE] = { .type = NLA_U32 },
[IFLA_MACVLAN_FLAGS] = { .type = NLA_U16 },
}; };
int macvlan_link_register(struct rtnl_link_ops *ops) int macvlan_link_register(struct rtnl_link_ops *ops)
......
...@@ -255,6 +255,7 @@ struct ifla_vlan_qos_mapping { ...@@ -255,6 +255,7 @@ struct ifla_vlan_qos_mapping {
enum { enum {
IFLA_MACVLAN_UNSPEC, IFLA_MACVLAN_UNSPEC,
IFLA_MACVLAN_MODE, IFLA_MACVLAN_MODE,
IFLA_MACVLAN_FLAGS,
__IFLA_MACVLAN_MAX, __IFLA_MACVLAN_MAX,
}; };
...@@ -267,6 +268,8 @@ enum macvlan_mode { ...@@ -267,6 +268,8 @@ enum macvlan_mode {
MACVLAN_MODE_PASSTHRU = 8,/* take over the underlying device */ MACVLAN_MODE_PASSTHRU = 8,/* take over the underlying device */
}; };
#define MACVLAN_FLAG_NOPROMISC 1
/* SR-IOV virtual function management section */ /* SR-IOV virtual function management section */
enum { enum {
......
...@@ -60,6 +60,7 @@ struct macvlan_dev { ...@@ -60,6 +60,7 @@ struct macvlan_dev {
struct net_device *lowerdev; struct net_device *lowerdev;
struct macvlan_pcpu_stats __percpu *pcpu_stats; struct macvlan_pcpu_stats __percpu *pcpu_stats;
enum macvlan_mode mode; enum macvlan_mode mode;
u16 flags;
int (*receive)(struct sk_buff *skb); int (*receive)(struct sk_buff *skb);
int (*forward)(struct net_device *dev, struct sk_buff *skb); int (*forward)(struct net_device *dev, struct sk_buff *skb);
struct macvtap_queue *taps[MAX_MACVTAP_QUEUES]; struct macvtap_queue *taps[MAX_MACVTAP_QUEUES];
......
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