Skip to content

Commit df8ef8f

Browse files
John Fastabenddavem330
authored andcommitted
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 <[email protected]> CC: Michael S. Tsirkin <[email protected]> Signed-off-by: John Fastabend <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 2b20271 commit df8ef8f

File tree

3 files changed

+71
-6
lines changed

3 files changed

+71
-6
lines changed

drivers/net/macvlan.c

Lines changed: 67 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -312,7 +312,8 @@ static int macvlan_open(struct net_device *dev)
312312
int err;
313313

314314
if (vlan->port->passthru) {
315-
dev_set_promiscuity(lowerdev, 1);
315+
if (!(vlan->flags & MACVLAN_FLAG_NOPROMISC))
316+
dev_set_promiscuity(lowerdev, 1);
316317
goto hash_add;
317318
}
318319

@@ -344,12 +345,15 @@ static int macvlan_stop(struct net_device *dev)
344345
struct macvlan_dev *vlan = netdev_priv(dev);
345346
struct net_device *lowerdev = vlan->lowerdev;
346347

348+
dev_uc_unsync(lowerdev, dev);
349+
dev_mc_unsync(lowerdev, dev);
350+
347351
if (vlan->port->passthru) {
348-
dev_set_promiscuity(lowerdev, -1);
352+
if (!(vlan->flags & MACVLAN_FLAG_NOPROMISC))
353+
dev_set_promiscuity(lowerdev, -1);
349354
goto hash_del;
350355
}
351356

352-
dev_mc_unsync(lowerdev, dev);
353357
if (dev->flags & IFF_ALLMULTI)
354358
dev_set_allmulti(lowerdev, -1);
355359

@@ -399,10 +403,11 @@ static void macvlan_change_rx_flags(struct net_device *dev, int change)
399403
dev_set_allmulti(lowerdev, dev->flags & IFF_ALLMULTI ? 1 : -1);
400404
}
401405

402-
static void macvlan_set_multicast_list(struct net_device *dev)
406+
static void macvlan_set_mac_lists(struct net_device *dev)
403407
{
404408
struct macvlan_dev *vlan = netdev_priv(dev);
405409

410+
dev_uc_sync(vlan->lowerdev, dev);
406411
dev_mc_sync(vlan->lowerdev, dev);
407412
}
408413

@@ -542,6 +547,43 @@ static int macvlan_vlan_rx_kill_vid(struct net_device *dev,
542547
return 0;
543548
}
544549

550+
static int macvlan_fdb_add(struct ndmsg *ndm,
551+
struct net_device *dev,
552+
unsigned char *addr,
553+
u16 flags)
554+
{
555+
struct macvlan_dev *vlan = netdev_priv(dev);
556+
int err = -EINVAL;
557+
558+
if (!vlan->port->passthru)
559+
return -EOPNOTSUPP;
560+
561+
if (is_unicast_ether_addr(addr))
562+
err = dev_uc_add_excl(dev, addr);
563+
else if (is_multicast_ether_addr(addr))
564+
err = dev_mc_add_excl(dev, addr);
565+
566+
return err;
567+
}
568+
569+
static int macvlan_fdb_del(struct ndmsg *ndm,
570+
struct net_device *dev,
571+
unsigned char *addr)
572+
{
573+
struct macvlan_dev *vlan = netdev_priv(dev);
574+
int err = -EINVAL;
575+
576+
if (!vlan->port->passthru)
577+
return -EOPNOTSUPP;
578+
579+
if (is_unicast_ether_addr(addr))
580+
err = dev_uc_del(dev, addr);
581+
else if (is_multicast_ether_addr(addr))
582+
err = dev_mc_del(dev, addr);
583+
584+
return err;
585+
}
586+
545587
static void macvlan_ethtool_get_drvinfo(struct net_device *dev,
546588
struct ethtool_drvinfo *drvinfo)
547589
{
@@ -572,11 +614,14 @@ static const struct net_device_ops macvlan_netdev_ops = {
572614
.ndo_change_mtu = macvlan_change_mtu,
573615
.ndo_change_rx_flags = macvlan_change_rx_flags,
574616
.ndo_set_mac_address = macvlan_set_mac_address,
575-
.ndo_set_rx_mode = macvlan_set_multicast_list,
617+
.ndo_set_rx_mode = macvlan_set_mac_lists,
576618
.ndo_get_stats64 = macvlan_dev_get_stats64,
577619
.ndo_validate_addr = eth_validate_addr,
578620
.ndo_vlan_rx_add_vid = macvlan_vlan_rx_add_vid,
579621
.ndo_vlan_rx_kill_vid = macvlan_vlan_rx_kill_vid,
622+
.ndo_fdb_add = macvlan_fdb_add,
623+
.ndo_fdb_del = macvlan_fdb_del,
624+
.ndo_fdb_dump = ndo_dflt_fdb_dump,
580625
};
581626

582627
void macvlan_common_setup(struct net_device *dev)
@@ -711,6 +756,9 @@ int macvlan_common_newlink(struct net *src_net, struct net_device *dev,
711756
if (data && data[IFLA_MACVLAN_MODE])
712757
vlan->mode = nla_get_u32(data[IFLA_MACVLAN_MODE]);
713758

759+
if (data && data[IFLA_MACVLAN_FLAGS])
760+
vlan->flags = nla_get_u16(data[IFLA_MACVLAN_FLAGS]);
761+
714762
if (vlan->mode == MACVLAN_MODE_PASSTHRU) {
715763
if (port->count)
716764
return -EINVAL;
@@ -760,6 +808,16 @@ static int macvlan_changelink(struct net_device *dev,
760808
struct macvlan_dev *vlan = netdev_priv(dev);
761809
if (data && data[IFLA_MACVLAN_MODE])
762810
vlan->mode = nla_get_u32(data[IFLA_MACVLAN_MODE]);
811+
if (data && data[IFLA_MACVLAN_FLAGS]) {
812+
__u16 flags = nla_get_u16(data[IFLA_MACVLAN_FLAGS]);
813+
bool promisc = (flags ^ vlan->flags) & MACVLAN_FLAG_NOPROMISC;
814+
815+
if (promisc && (flags & MACVLAN_FLAG_NOPROMISC))
816+
dev_set_promiscuity(vlan->lowerdev, -1);
817+
else if (promisc && !(flags & MACVLAN_FLAG_NOPROMISC))
818+
dev_set_promiscuity(vlan->lowerdev, 1);
819+
vlan->flags = flags;
820+
}
763821
return 0;
764822
}
765823

@@ -775,14 +833,17 @@ static int macvlan_fill_info(struct sk_buff *skb,
775833

776834
if (nla_put_u32(skb, IFLA_MACVLAN_MODE, vlan->mode))
777835
goto nla_put_failure;
836+
if (nla_put_u16(skb, IFLA_MACVLAN_FLAGS, vlan->flags))
837+
goto nla_put_failure;
778838
return 0;
779839

780840
nla_put_failure:
781841
return -EMSGSIZE;
782842
}
783843

784844
static const struct nla_policy macvlan_policy[IFLA_MACVLAN_MAX + 1] = {
785-
[IFLA_MACVLAN_MODE] = { .type = NLA_U32 },
845+
[IFLA_MACVLAN_MODE] = { .type = NLA_U32 },
846+
[IFLA_MACVLAN_FLAGS] = { .type = NLA_U16 },
786847
};
787848

788849
int macvlan_link_register(struct rtnl_link_ops *ops)

include/linux/if_link.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -255,6 +255,7 @@ struct ifla_vlan_qos_mapping {
255255
enum {
256256
IFLA_MACVLAN_UNSPEC,
257257
IFLA_MACVLAN_MODE,
258+
IFLA_MACVLAN_FLAGS,
258259
__IFLA_MACVLAN_MAX,
259260
};
260261

@@ -267,6 +268,8 @@ enum macvlan_mode {
267268
MACVLAN_MODE_PASSTHRU = 8,/* take over the underlying device */
268269
};
269270

271+
#define MACVLAN_FLAG_NOPROMISC 1
272+
270273
/* SR-IOV virtual function management section */
271274

272275
enum {

include/linux/if_macvlan.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ struct macvlan_dev {
6060
struct net_device *lowerdev;
6161
struct macvlan_pcpu_stats __percpu *pcpu_stats;
6262
enum macvlan_mode mode;
63+
u16 flags;
6364
int (*receive)(struct sk_buff *skb);
6465
int (*forward)(struct net_device *dev, struct sk_buff *skb);
6566
struct macvtap_queue *taps[MAX_MACVTAP_QUEUES];

0 commit comments

Comments
 (0)