summaryrefslogtreecommitdiffstats
path: root/drivers/net/macvlan.c
diff options
context:
space:
mode:
authorJohn Fastabend <john.r.fastabend@intel.com>2013-11-06 12:54:46 -0500
committerDavid S. Miller <davem@davemloft.net>2013-11-07 19:11:41 -0500
commita6cc0cfa72e0b6d9f2c8fd858aacc32313c4f272 (patch)
tree310baaaa6df9798431aeb75ab6df1f13feee81c2 /drivers/net/macvlan.c
parent1ec4864b10171b0691ee196d7006ae56d2c153f2 (diff)
net: Add layer 2 hardware acceleration operations for macvlan devices
Add a operations structure that allows a network interface to export the fact that it supports package forwarding in hardware between physical interfaces and other mac layer devices assigned to it (such as macvlans). This operaions structure can be used by virtual mac devices to bypass software switching so that forwarding can be done in hardware more efficiently. Signed-off-by: John Fastabend <john.r.fastabend@intel.com> Signed-off-by: Neil Horman <nhorman@tuxdriver.com> CC: Andy Gospodarek <andy@greyhouse.net> CC: "David S. Miller" <davem@davemloft.net> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/macvlan.c')
-rw-r--r--drivers/net/macvlan.c36
1 files changed, 35 insertions, 1 deletions
diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c
index cc9845ec91c1..af4aaa5893ff 100644
--- a/drivers/net/macvlan.c
+++ b/drivers/net/macvlan.c
@@ -297,7 +297,13 @@ netdev_tx_t macvlan_start_xmit(struct sk_buff *skb,
297 int ret; 297 int ret;
298 const struct macvlan_dev *vlan = netdev_priv(dev); 298 const struct macvlan_dev *vlan = netdev_priv(dev);
299 299
300 ret = macvlan_queue_xmit(skb, dev); 300 if (vlan->fwd_priv) {
301 skb->dev = vlan->lowerdev;
302 ret = dev_hard_start_xmit(skb, skb->dev, NULL, vlan->fwd_priv);
303 } else {
304 ret = macvlan_queue_xmit(skb, dev);
305 }
306
301 if (likely(ret == NET_XMIT_SUCCESS || ret == NET_XMIT_CN)) { 307 if (likely(ret == NET_XMIT_SUCCESS || ret == NET_XMIT_CN)) {
302 struct macvlan_pcpu_stats *pcpu_stats; 308 struct macvlan_pcpu_stats *pcpu_stats;
303 309
@@ -347,6 +353,21 @@ static int macvlan_open(struct net_device *dev)
347 goto hash_add; 353 goto hash_add;
348 } 354 }
349 355
356 if (lowerdev->features & NETIF_F_HW_L2FW_DOFFLOAD) {
357 vlan->fwd_priv =
358 lowerdev->netdev_ops->ndo_dfwd_add_station(lowerdev, dev);
359
360 /* If we get a NULL pointer back, or if we get an error
361 * then we should just fall through to the non accelerated path
362 */
363 if (IS_ERR_OR_NULL(vlan->fwd_priv)) {
364 vlan->fwd_priv = NULL;
365 } else {
366 dev->features &= ~NETIF_F_LLTX;
367 return 0;
368 }
369 }
370
350 err = -EBUSY; 371 err = -EBUSY;
351 if (macvlan_addr_busy(vlan->port, dev->dev_addr)) 372 if (macvlan_addr_busy(vlan->port, dev->dev_addr))
352 goto out; 373 goto out;
@@ -367,6 +388,11 @@ hash_add:
367del_unicast: 388del_unicast:
368 dev_uc_del(lowerdev, dev->dev_addr); 389 dev_uc_del(lowerdev, dev->dev_addr);
369out: 390out:
391 if (vlan->fwd_priv) {
392 lowerdev->netdev_ops->ndo_dfwd_del_station(lowerdev,
393 vlan->fwd_priv);
394 vlan->fwd_priv = NULL;
395 }
370 return err; 396 return err;
371} 397}
372 398
@@ -375,6 +401,13 @@ static int macvlan_stop(struct net_device *dev)
375 struct macvlan_dev *vlan = netdev_priv(dev); 401 struct macvlan_dev *vlan = netdev_priv(dev);
376 struct net_device *lowerdev = vlan->lowerdev; 402 struct net_device *lowerdev = vlan->lowerdev;
377 403
404 if (vlan->fwd_priv) {
405 lowerdev->netdev_ops->ndo_dfwd_del_station(lowerdev,
406 vlan->fwd_priv);
407 vlan->fwd_priv = NULL;
408 return 0;
409 }
410
378 dev_uc_unsync(lowerdev, dev); 411 dev_uc_unsync(lowerdev, dev);
379 dev_mc_unsync(lowerdev, dev); 412 dev_mc_unsync(lowerdev, dev);
380 413
@@ -833,6 +866,7 @@ int macvlan_common_newlink(struct net *src_net, struct net_device *dev,
833 if (err < 0) 866 if (err < 0)
834 goto destroy_port; 867 goto destroy_port;
835 868
869 dev->priv_flags |= IFF_MACVLAN;
836 err = netdev_upper_dev_link(lowerdev, dev); 870 err = netdev_upper_dev_link(lowerdev, dev);
837 if (err) 871 if (err)
838 goto destroy_port; 872 goto destroy_port;