aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/macvlan.c
diff options
context:
space:
mode:
authorSridhar Samudrala <sri@us.ibm.com>2010-10-28 09:10:50 -0400
committerDavid S. Miller <davem@davemloft.net>2010-11-22 11:24:29 -0500
commiteb06acdc85585f28864261f28659157848762ee4 (patch)
tree8db786f687bfb8b969d00bb2695454938ea41f1d /drivers/net/macvlan.c
parente5700c740da2cb9f5a3aa978cd1fa3a79916ba04 (diff)
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>
Diffstat (limited to 'drivers/net/macvlan.c')
-rw-r--r--drivers/net/macvlan.c33
1 files changed, 32 insertions, 1 deletions
diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c
index 93f0ba25c808..6ed577b065df 100644
--- a/drivers/net/macvlan.c
+++ b/drivers/net/macvlan.c
@@ -38,6 +38,7 @@ struct macvlan_port {
38 struct hlist_head vlan_hash[MACVLAN_HASH_SIZE]; 38 struct hlist_head vlan_hash[MACVLAN_HASH_SIZE];
39 struct list_head vlans; 39 struct list_head vlans;
40 struct rcu_head rcu; 40 struct rcu_head rcu;
41 bool passthru;
41}; 42};
42 43
43#define macvlan_port_get_rcu(dev) \ 44#define macvlan_port_get_rcu(dev) \
@@ -169,6 +170,7 @@ static struct sk_buff *macvlan_handle_frame(struct sk_buff *skb)
169 macvlan_broadcast(skb, port, NULL, 170 macvlan_broadcast(skb, port, NULL,
170 MACVLAN_MODE_PRIVATE | 171 MACVLAN_MODE_PRIVATE |
171 MACVLAN_MODE_VEPA | 172 MACVLAN_MODE_VEPA |
173 MACVLAN_MODE_PASSTHRU|
172 MACVLAN_MODE_BRIDGE); 174 MACVLAN_MODE_BRIDGE);
173 else if (src->mode == MACVLAN_MODE_VEPA) 175 else if (src->mode == MACVLAN_MODE_VEPA)
174 /* flood to everyone except source */ 176 /* flood to everyone except source */
@@ -185,7 +187,10 @@ static struct sk_buff *macvlan_handle_frame(struct sk_buff *skb)
185 return skb; 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 if (vlan == NULL) 194 if (vlan == NULL)
190 return skb; 195 return skb;
191 196
@@ -288,6 +293,11 @@ static int macvlan_open(struct net_device *dev)
288 struct net_device *lowerdev = vlan->lowerdev; 293 struct net_device *lowerdev = vlan->lowerdev;
289 int err; 294 int err;
290 295
296 if (vlan->port->passthru) {
297 dev_set_promiscuity(lowerdev, 1);
298 goto hash_add;
299 }
300
291 err = -EBUSY; 301 err = -EBUSY;
292 if (macvlan_addr_busy(vlan->port, dev->dev_addr)) 302 if (macvlan_addr_busy(vlan->port, dev->dev_addr))
293 goto out; 303 goto out;
@@ -300,6 +310,8 @@ static int macvlan_open(struct net_device *dev)
300 if (err < 0) 310 if (err < 0)
301 goto del_unicast; 311 goto del_unicast;
302 } 312 }
313
314hash_add:
303 macvlan_hash_add(vlan); 315 macvlan_hash_add(vlan);
304 return 0; 316 return 0;
305 317
@@ -314,12 +326,18 @@ static int macvlan_stop(struct net_device *dev)
314 struct macvlan_dev *vlan = netdev_priv(dev); 326 struct macvlan_dev *vlan = netdev_priv(dev);
315 struct net_device *lowerdev = vlan->lowerdev; 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 dev_mc_unsync(lowerdev, dev); 334 dev_mc_unsync(lowerdev, dev);
318 if (dev->flags & IFF_ALLMULTI) 335 if (dev->flags & IFF_ALLMULTI)
319 dev_set_allmulti(lowerdev, -1); 336 dev_set_allmulti(lowerdev, -1);
320 337
321 dev_uc_del(lowerdev, dev->dev_addr); 338 dev_uc_del(lowerdev, dev->dev_addr);
322 339
340hash_del:
323 macvlan_hash_del(vlan); 341 macvlan_hash_del(vlan);
324 return 0; 342 return 0;
325} 343}
@@ -559,6 +577,7 @@ static int macvlan_port_create(struct net_device *dev)
559 if (port == NULL) 577 if (port == NULL)
560 return -ENOMEM; 578 return -ENOMEM;
561 579
580 port->passthru = false;
562 port->dev = dev; 581 port->dev = dev;
563 INIT_LIST_HEAD(&port->vlans); 582 INIT_LIST_HEAD(&port->vlans);
564 for (i = 0; i < MACVLAN_HASH_SIZE; i++) 583 for (i = 0; i < MACVLAN_HASH_SIZE; i++)
@@ -603,6 +622,7 @@ static int macvlan_validate(struct nlattr *tb[], struct nlattr *data[])
603 case MACVLAN_MODE_PRIVATE: 622 case MACVLAN_MODE_PRIVATE:
604 case MACVLAN_MODE_VEPA: 623 case MACVLAN_MODE_VEPA:
605 case MACVLAN_MODE_BRIDGE: 624 case MACVLAN_MODE_BRIDGE:
625 case MACVLAN_MODE_PASSTHRU:
606 break; 626 break;
607 default: 627 default:
608 return -EINVAL; 628 return -EINVAL;
@@ -652,6 +672,10 @@ int macvlan_common_newlink(struct net *src_net, struct net_device *dev,
652 } 672 }
653 port = macvlan_port_get(lowerdev); 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 vlan->lowerdev = lowerdev; 679 vlan->lowerdev = lowerdev;
656 vlan->dev = dev; 680 vlan->dev = dev;
657 vlan->port = port; 681 vlan->port = port;
@@ -662,6 +686,13 @@ int macvlan_common_newlink(struct net *src_net, struct net_device *dev,
662 if (data && data[IFLA_MACVLAN_MODE]) 686 if (data && data[IFLA_MACVLAN_MODE])
663 vlan->mode = nla_get_u32(data[IFLA_MACVLAN_MODE]); 687 vlan->mode = nla_get_u32(data[IFLA_MACVLAN_MODE]);
664 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 }
695
665 err = register_netdevice(dev); 696 err = register_netdevice(dev);
666 if (err < 0) 697 if (err < 0)
667 goto destroy_port; 698 goto destroy_port;