Commit eb06acdc85585f28864261f28659157848762ee4
Committed by
David S. Miller
1 parent
e5700c740d
Exists in
master
and in
4 other branches
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 */ |