Skip to content

Commit

Permalink
net: Add layer 2 hardware acceleration operations for macvlan devices
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
John Fastabend authored and David S. Miller committed Nov 8, 2013
1 parent 1ec4864 commit a6cc0cf
Show file tree
Hide file tree
Showing 8 changed files with 89 additions and 8 deletions.
36 changes: 35 additions & 1 deletion drivers/net/macvlan.c
Original file line number Diff line number Diff line change
Expand Up @@ -297,7 +297,13 @@ netdev_tx_t macvlan_start_xmit(struct sk_buff *skb,
int ret;
const struct macvlan_dev *vlan = netdev_priv(dev);

ret = macvlan_queue_xmit(skb, dev);
if (vlan->fwd_priv) {
skb->dev = vlan->lowerdev;
ret = dev_hard_start_xmit(skb, skb->dev, NULL, vlan->fwd_priv);
} else {
ret = macvlan_queue_xmit(skb, dev);
}

if (likely(ret == NET_XMIT_SUCCESS || ret == NET_XMIT_CN)) {
struct macvlan_pcpu_stats *pcpu_stats;

Expand Down Expand Up @@ -347,6 +353,21 @@ static int macvlan_open(struct net_device *dev)
goto hash_add;
}

if (lowerdev->features & NETIF_F_HW_L2FW_DOFFLOAD) {
vlan->fwd_priv =
lowerdev->netdev_ops->ndo_dfwd_add_station(lowerdev, dev);

/* If we get a NULL pointer back, or if we get an error
* then we should just fall through to the non accelerated path
*/
if (IS_ERR_OR_NULL(vlan->fwd_priv)) {
vlan->fwd_priv = NULL;
} else {
dev->features &= ~NETIF_F_LLTX;
return 0;
}
}

err = -EBUSY;
if (macvlan_addr_busy(vlan->port, dev->dev_addr))
goto out;
Expand All @@ -367,6 +388,11 @@ static int macvlan_open(struct net_device *dev)
del_unicast:
dev_uc_del(lowerdev, dev->dev_addr);
out:
if (vlan->fwd_priv) {
lowerdev->netdev_ops->ndo_dfwd_del_station(lowerdev,
vlan->fwd_priv);
vlan->fwd_priv = NULL;
}
return err;
}

Expand All @@ -375,6 +401,13 @@ static int macvlan_stop(struct net_device *dev)
struct macvlan_dev *vlan = netdev_priv(dev);
struct net_device *lowerdev = vlan->lowerdev;

if (vlan->fwd_priv) {
lowerdev->netdev_ops->ndo_dfwd_del_station(lowerdev,
vlan->fwd_priv);
vlan->fwd_priv = NULL;
return 0;
}

dev_uc_unsync(lowerdev, dev);
dev_mc_unsync(lowerdev, dev);

Expand Down Expand Up @@ -833,6 +866,7 @@ int macvlan_common_newlink(struct net *src_net, struct net_device *dev,
if (err < 0)
goto destroy_port;

dev->priv_flags |= IFF_MACVLAN;
err = netdev_upper_dev_link(lowerdev, dev);
if (err)
goto destroy_port;
Expand Down
1 change: 1 addition & 0 deletions include/linux/if_macvlan.h
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ struct macvlan_dev {
struct hlist_node hlist;
struct macvlan_port *port;
struct net_device *lowerdev;
void *fwd_priv;
struct macvlan_pcpu_stats __percpu *pcpu_stats;

DECLARE_BITMAP(mc_filter, MACVLAN_MC_FILTER_SZ);
Expand Down
2 changes: 2 additions & 0 deletions include/linux/netdev_features.h
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ enum {
NETIF_F_HW_VLAN_STAG_TX_BIT, /* Transmit VLAN STAG HW acceleration */
NETIF_F_HW_VLAN_STAG_RX_BIT, /* Receive VLAN STAG HW acceleration */
NETIF_F_HW_VLAN_STAG_FILTER_BIT,/* Receive filtering on VLAN STAGs */
NETIF_F_HW_L2FW_DOFFLOAD_BIT, /* Allow L2 Forwarding in Hardware */

/*
* Add your fresh new feature above and remember to update
Expand Down Expand Up @@ -116,6 +117,7 @@ enum {
#define NETIF_F_HW_VLAN_STAG_FILTER __NETIF_F(HW_VLAN_STAG_FILTER)
#define NETIF_F_HW_VLAN_STAG_RX __NETIF_F(HW_VLAN_STAG_RX)
#define NETIF_F_HW_VLAN_STAG_TX __NETIF_F(HW_VLAN_STAG_TX)
#define NETIF_F_HW_L2FW_DOFFLOAD __NETIF_F(HW_L2FW_DOFFLOAD)

/* Features valid for ethtool to change */
/* = all defined minus driver/device-class-related */
Expand Down
36 changes: 35 additions & 1 deletion include/linux/netdevice.h
Original file line number Diff line number Diff line change
Expand Up @@ -962,6 +962,25 @@ struct netdev_phys_port_id {
* Called by vxlan to notify the driver about a UDP port and socket
* address family that vxlan is not listening to anymore. The operation
* is protected by the vxlan_net->sock_lock.
*
* void* (*ndo_dfwd_add_station)(struct net_device *pdev,
* struct net_device *dev)
* Called by upper layer devices to accelerate switching or other
* station functionality into hardware. 'pdev is the lowerdev
* to use for the offload and 'dev' is the net device that will
* back the offload. Returns a pointer to the private structure
* the upper layer will maintain.
* void (*ndo_dfwd_del_station)(struct net_device *pdev, void *priv)
* Called by upper layer device to delete the station created
* by 'ndo_dfwd_add_station'. 'pdev' is the net device backing
* the station and priv is the structure returned by the add
* operation.
* netdev_tx_t (*ndo_dfwd_start_xmit)(struct sk_buff *skb,
* struct net_device *dev,
* void *priv);
* Callback to use for xmit over the accelerated station. This
* is used in place of ndo_start_xmit on accelerated net
* devices.
*/
struct net_device_ops {
int (*ndo_init)(struct net_device *dev);
Expand Down Expand Up @@ -1098,6 +1117,15 @@ struct net_device_ops {
void (*ndo_del_vxlan_port)(struct net_device *dev,
sa_family_t sa_family,
__be16 port);

void* (*ndo_dfwd_add_station)(struct net_device *pdev,
struct net_device *dev);
void (*ndo_dfwd_del_station)(struct net_device *pdev,
void *priv);

netdev_tx_t (*ndo_dfwd_start_xmit) (struct sk_buff *skb,
struct net_device *dev,
void *priv);
};

/*
Expand Down Expand Up @@ -1195,6 +1223,7 @@ struct net_device {
/* Management operations */
const struct net_device_ops *netdev_ops;
const struct ethtool_ops *ethtool_ops;
const struct forwarding_accel_ops *fwd_ops;

/* Hardware header description */
const struct header_ops *header_ops;
Expand Down Expand Up @@ -2388,7 +2417,7 @@ int dev_change_carrier(struct net_device *, bool new_carrier);
int dev_get_phys_port_id(struct net_device *dev,
struct netdev_phys_port_id *ppid);
int dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev,
struct netdev_queue *txq);
struct netdev_queue *txq, void *accel_priv);
int dev_forward_skb(struct net_device *dev, struct sk_buff *skb);

extern int netdev_budget;
Expand Down Expand Up @@ -2967,6 +2996,11 @@ static inline void netif_set_gso_max_size(struct net_device *dev,
dev->gso_max_size = size;
}

static inline bool netif_is_macvlan(struct net_device *dev)
{
return dev->priv_flags & IFF_MACVLAN;
}

static inline bool netif_is_bond_master(struct net_device *dev)
{
return dev->flags & IFF_MASTER && dev->priv_flags & IFF_BONDING;
Expand Down
1 change: 1 addition & 0 deletions include/uapi/linux/if.h
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@
#define IFF_SUPP_NOFCS 0x80000 /* device supports sending custom FCS */
#define IFF_LIVE_ADDR_CHANGE 0x100000 /* device supports hardware address
* change when it's running */
#define IFF_MACVLAN 0x200000 /* Macvlan device */


#define IF_GET_IFACE 0x0001 /* for querying only */
Expand Down
18 changes: 13 additions & 5 deletions net/core/dev.c
Original file line number Diff line number Diff line change
Expand Up @@ -2538,7 +2538,7 @@ static inline int skb_needs_linearize(struct sk_buff *skb,
}

int dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev,
struct netdev_queue *txq)
struct netdev_queue *txq, void *accel_priv)
{
const struct net_device_ops *ops = dev->netdev_ops;
int rc = NETDEV_TX_OK;
Expand Down Expand Up @@ -2604,9 +2604,13 @@ int dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev,
dev_queue_xmit_nit(skb, dev);

skb_len = skb->len;
rc = ops->ndo_start_xmit(skb, dev);
if (accel_priv)
rc = ops->ndo_dfwd_start_xmit(skb, dev, accel_priv);
else
rc = ops->ndo_start_xmit(skb, dev);

trace_net_dev_xmit(skb, rc, dev, skb_len);
if (rc == NETDEV_TX_OK)
if (rc == NETDEV_TX_OK && txq)
txq_trans_update(txq);
return rc;
}
Expand All @@ -2622,7 +2626,10 @@ int dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev,
dev_queue_xmit_nit(nskb, dev);

skb_len = nskb->len;
rc = ops->ndo_start_xmit(nskb, dev);
if (accel_priv)
rc = ops->ndo_dfwd_start_xmit(nskb, dev, accel_priv);
else
rc = ops->ndo_start_xmit(nskb, dev);
trace_net_dev_xmit(nskb, rc, dev, skb_len);
if (unlikely(rc != NETDEV_TX_OK)) {
if (rc & ~NETDEV_TX_MASK)
Expand All @@ -2647,6 +2654,7 @@ int dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev,
out:
return rc;
}
EXPORT_SYMBOL_GPL(dev_hard_start_xmit);

static void qdisc_pkt_len_init(struct sk_buff *skb)
{
Expand Down Expand Up @@ -2854,7 +2862,7 @@ int dev_queue_xmit(struct sk_buff *skb)

if (!netif_xmit_stopped(txq)) {
__this_cpu_inc(xmit_recursion);
rc = dev_hard_start_xmit(skb, dev, txq);
rc = dev_hard_start_xmit(skb, dev, txq, NULL);
__this_cpu_dec(xmit_recursion);
if (dev_xmit_complete(rc)) {
HARD_TX_UNLOCK(dev, txq);
Expand Down
1 change: 1 addition & 0 deletions net/core/ethtool.c
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@ static const char netdev_features_strings[NETDEV_FEATURE_COUNT][ETH_GSTRING_LEN]
[NETIF_F_LOOPBACK_BIT] = "loopback",
[NETIF_F_RXFCS_BIT] = "rx-fcs",
[NETIF_F_RXALL_BIT] = "rx-all",
[NETIF_F_HW_L2FW_DOFFLOAD_BIT] = "l2-fwd-offload",
};

static int ethtool_get_features(struct net_device *dev, void __user *useraddr)
Expand Down
2 changes: 1 addition & 1 deletion net/sched/sch_generic.c
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ int sch_direct_xmit(struct sk_buff *skb, struct Qdisc *q,

HARD_TX_LOCK(dev, txq, smp_processor_id());
if (!netif_xmit_frozen_or_stopped(txq))
ret = dev_hard_start_xmit(skb, dev, txq);
ret = dev_hard_start_xmit(skb, dev, txq, NULL);

HARD_TX_UNLOCK(dev, txq);

Expand Down

0 comments on commit a6cc0cf

Please sign in to comment.