Skip to content

Commit eb06acd

Browse files
Sridhar Samudraladavem330
authored andcommitted
macvlan: Introduce 'passthru' mode to takeover the underlying device
With the current default 'vepa' mode, a KVM guest using virtio with macvtap backend has the following limitations. - cannot change/add a mac address on the guest virtio-net - cannot create a vlan device on the guest virtio-net - cannot enable promiscuous mode on guest virtio-net To address these limitations, this patch introduces a new mode called 'passthru' when creating a macvlan device which allows takeover of the underlying device and passing it to a guest using virtio with macvtap backend. Only one macvlan device is allowed in passthru mode and it inherits the mac address from the underlying device and sets it in promiscuous mode to receive and forward all the packets. Signed-off-by: Sridhar Samudrala <sri@us.ibm.com> ------------------------------------------------------------------------- Signed-off-by: David S. Miller <davem@davemloft.net>
1 parent e5700c7 commit eb06acd

File tree

2 files changed

+33
-1
lines changed

2 files changed

+33
-1
lines changed

drivers/net/macvlan.c

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ struct macvlan_port {
3838
struct hlist_head vlan_hash[MACVLAN_HASH_SIZE];
3939
struct list_head vlans;
4040
struct rcu_head rcu;
41+
bool passthru;
4142
};
4243

4344
#define macvlan_port_get_rcu(dev) \
@@ -169,6 +170,7 @@ static struct sk_buff *macvlan_handle_frame(struct sk_buff *skb)
169170
macvlan_broadcast(skb, port, NULL,
170171
MACVLAN_MODE_PRIVATE |
171172
MACVLAN_MODE_VEPA |
173+
MACVLAN_MODE_PASSTHRU|
172174
MACVLAN_MODE_BRIDGE);
173175
else if (src->mode == MACVLAN_MODE_VEPA)
174176
/* flood to everyone except source */
@@ -185,7 +187,10 @@ static struct sk_buff *macvlan_handle_frame(struct sk_buff *skb)
185187
return skb;
186188
}
187189

188-
vlan = macvlan_hash_lookup(port, eth->h_dest);
190+
if (port->passthru)
191+
vlan = list_first_entry(&port->vlans, struct macvlan_dev, list);
192+
else
193+
vlan = macvlan_hash_lookup(port, eth->h_dest);
189194
if (vlan == NULL)
190195
return skb;
191196

@@ -288,6 +293,11 @@ static int macvlan_open(struct net_device *dev)
288293
struct net_device *lowerdev = vlan->lowerdev;
289294
int err;
290295

296+
if (vlan->port->passthru) {
297+
dev_set_promiscuity(lowerdev, 1);
298+
goto hash_add;
299+
}
300+
291301
err = -EBUSY;
292302
if (macvlan_addr_busy(vlan->port, dev->dev_addr))
293303
goto out;
@@ -300,6 +310,8 @@ static int macvlan_open(struct net_device *dev)
300310
if (err < 0)
301311
goto del_unicast;
302312
}
313+
314+
hash_add:
303315
macvlan_hash_add(vlan);
304316
return 0;
305317

@@ -314,12 +326,18 @@ static int macvlan_stop(struct net_device *dev)
314326
struct macvlan_dev *vlan = netdev_priv(dev);
315327
struct net_device *lowerdev = vlan->lowerdev;
316328

329+
if (vlan->port->passthru) {
330+
dev_set_promiscuity(lowerdev, -1);
331+
goto hash_del;
332+
}
333+
317334
dev_mc_unsync(lowerdev, dev);
318335
if (dev->flags & IFF_ALLMULTI)
319336
dev_set_allmulti(lowerdev, -1);
320337

321338
dev_uc_del(lowerdev, dev->dev_addr);
322339

340+
hash_del:
323341
macvlan_hash_del(vlan);
324342
return 0;
325343
}
@@ -559,6 +577,7 @@ static int macvlan_port_create(struct net_device *dev)
559577
if (port == NULL)
560578
return -ENOMEM;
561579

580+
port->passthru = false;
562581
port->dev = dev;
563582
INIT_LIST_HEAD(&port->vlans);
564583
for (i = 0; i < MACVLAN_HASH_SIZE; i++)
@@ -603,6 +622,7 @@ static int macvlan_validate(struct nlattr *tb[], struct nlattr *data[])
603622
case MACVLAN_MODE_PRIVATE:
604623
case MACVLAN_MODE_VEPA:
605624
case MACVLAN_MODE_BRIDGE:
625+
case MACVLAN_MODE_PASSTHRU:
606626
break;
607627
default:
608628
return -EINVAL;
@@ -652,6 +672,10 @@ int macvlan_common_newlink(struct net *src_net, struct net_device *dev,
652672
}
653673
port = macvlan_port_get(lowerdev);
654674

675+
/* Only 1 macvlan device can be created in passthru mode */
676+
if (port->passthru)
677+
return -EINVAL;
678+
655679
vlan->lowerdev = lowerdev;
656680
vlan->dev = dev;
657681
vlan->port = port;
@@ -662,6 +686,13 @@ int macvlan_common_newlink(struct net *src_net, struct net_device *dev,
662686
if (data && data[IFLA_MACVLAN_MODE])
663687
vlan->mode = nla_get_u32(data[IFLA_MACVLAN_MODE]);
664688

689+
if (vlan->mode == MACVLAN_MODE_PASSTHRU) {
690+
if (!list_empty(&port->vlans))
691+
return -EINVAL;
692+
port->passthru = true;
693+
memcpy(dev->dev_addr, lowerdev->dev_addr, ETH_ALEN);
694+
}
695+
665696
err = register_netdevice(dev);
666697
if (err < 0)
667698
goto destroy_port;

include/linux/if_link.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -259,6 +259,7 @@ enum macvlan_mode {
259259
MACVLAN_MODE_PRIVATE = 1, /* don't talk to other macvlans */
260260
MACVLAN_MODE_VEPA = 2, /* talk to other ports through ext bridge */
261261
MACVLAN_MODE_BRIDGE = 4, /* talk to bridge ports directly */
262+
MACVLAN_MODE_PASSTHRU = 8,/* take over the underlying device */
262263
};
263264

264265
/* SR-IOV virtual function management section */

0 commit comments

Comments
 (0)