Commit eb06acdc85585f28864261f28659157848762ee4

Authored by Sridhar Samudrala
Committed by David S. Miller
1 parent e5700c740d

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>

Showing 2 changed files with 33 additions and 1 deletions Side-by-side Diff

drivers/net/macvlan.c
... ... @@ -38,6 +38,7 @@
38 38 struct hlist_head vlan_hash[MACVLAN_HASH_SIZE];
39 39 struct list_head vlans;
40 40 struct rcu_head rcu;
  41 + bool passthru;
41 42 };
42 43  
43 44 #define macvlan_port_get_rcu(dev) \
... ... @@ -169,6 +170,7 @@
169 170 macvlan_broadcast(skb, port, NULL,
170 171 MACVLAN_MODE_PRIVATE |
171 172 MACVLAN_MODE_VEPA |
  173 + MACVLAN_MODE_PASSTHRU|
172 174 MACVLAN_MODE_BRIDGE);
173 175 else if (src->mode == MACVLAN_MODE_VEPA)
174 176 /* flood to everyone except source */
... ... @@ -185,7 +187,10 @@
185 187 return skb;
186 188 }
187 189  
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);
189 194 if (vlan == NULL)
190 195 return skb;
191 196  
... ... @@ -288,6 +293,11 @@
288 293 struct net_device *lowerdev = vlan->lowerdev;
289 294 int err;
290 295  
  296 + if (vlan->port->passthru) {
  297 + dev_set_promiscuity(lowerdev, 1);
  298 + goto hash_add;
  299 + }
  300 +
291 301 err = -EBUSY;
292 302 if (macvlan_addr_busy(vlan->port, dev->dev_addr))
293 303 goto out;
... ... @@ -300,6 +310,8 @@
300 310 if (err < 0)
301 311 goto del_unicast;
302 312 }
  313 +
  314 +hash_add:
303 315 macvlan_hash_add(vlan);
304 316 return 0;
305 317  
306 318  
... ... @@ -314,12 +326,18 @@
314 326 struct macvlan_dev *vlan = netdev_priv(dev);
315 327 struct net_device *lowerdev = vlan->lowerdev;
316 328  
  329 + if (vlan->port->passthru) {
  330 + dev_set_promiscuity(lowerdev, -1);
  331 + goto hash_del;
  332 + }
  333 +
317 334 dev_mc_unsync(lowerdev, dev);
318 335 if (dev->flags & IFF_ALLMULTI)
319 336 dev_set_allmulti(lowerdev, -1);
320 337  
321 338 dev_uc_del(lowerdev, dev->dev_addr);
322 339  
  340 +hash_del:
323 341 macvlan_hash_del(vlan);
324 342 return 0;
325 343 }
... ... @@ -559,6 +577,7 @@
559 577 if (port == NULL)
560 578 return -ENOMEM;
561 579  
  580 + port->passthru = false;
562 581 port->dev = dev;
563 582 INIT_LIST_HEAD(&port->vlans);
564 583 for (i = 0; i < MACVLAN_HASH_SIZE; i++)
... ... @@ -603,6 +622,7 @@
603 622 case MACVLAN_MODE_PRIVATE:
604 623 case MACVLAN_MODE_VEPA:
605 624 case MACVLAN_MODE_BRIDGE:
  625 + case MACVLAN_MODE_PASSTHRU:
606 626 break;
607 627 default:
608 628 return -EINVAL;
... ... @@ -652,6 +672,10 @@
652 672 }
653 673 port = macvlan_port_get(lowerdev);
654 674  
  675 + /* Only 1 macvlan device can be created in passthru mode */
  676 + if (port->passthru)
  677 + return -EINVAL;
  678 +
655 679 vlan->lowerdev = lowerdev;
656 680 vlan->dev = dev;
657 681 vlan->port = port;
... ... @@ -661,6 +685,13 @@
661 685 vlan->mode = MACVLAN_MODE_VEPA;
662 686 if (data && data[IFLA_MACVLAN_MODE])
663 687 vlan->mode = nla_get_u32(data[IFLA_MACVLAN_MODE]);
  688 +
  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 + }
664 695  
665 696 err = register_netdevice(dev);
666 697 if (err < 0)
include/linux/if_link.h
... ... @@ -259,6 +259,7 @@
259 259 MACVLAN_MODE_PRIVATE = 1, /* don't talk to other macvlans */
260 260 MACVLAN_MODE_VEPA = 2, /* talk to other ports through ext bridge */
261 261 MACVLAN_MODE_BRIDGE = 4, /* talk to bridge ports directly */
  262 + MACVLAN_MODE_PASSTHRU = 8,/* take over the underlying device */
262 263 };
263 264  
264 265 /* SR-IOV virtual function management section */