aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/net/macvlan.c33
-rw-r--r--include/linux/if_link.h1
2 files changed, 33 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;
diff --git a/include/linux/if_link.h b/include/linux/if_link.h
index 2e02e4d7b11e..6485d2a89bec 100644
--- a/include/linux/if_link.h
+++ b/include/linux/if_link.h
@@ -259,6 +259,7 @@ enum macvlan_mode {
259 MACVLAN_MODE_PRIVATE = 1, /* don't talk to other macvlans */ 259 MACVLAN_MODE_PRIVATE = 1, /* don't talk to other macvlans */
260 MACVLAN_MODE_VEPA = 2, /* talk to other ports through ext bridge */ 260 MACVLAN_MODE_VEPA = 2, /* talk to other ports through ext bridge */
261 MACVLAN_MODE_BRIDGE = 4, /* talk to bridge ports directly */ 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/* SR-IOV virtual function management section */ 265/* SR-IOV virtual function management section */