Skip to content

Commit a6cc0cf

Browse files
John Fastabenddavem330
authored andcommitted
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 <[email protected]> Signed-off-by: Neil Horman <[email protected]> CC: Andy Gospodarek <[email protected]> CC: "David S. Miller" <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 1ec4864 commit a6cc0cf

File tree

8 files changed

+89
-8
lines changed

8 files changed

+89
-8
lines changed

drivers/net/macvlan.c

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -297,7 +297,13 @@ netdev_tx_t macvlan_start_xmit(struct sk_buff *skb,
297297
int ret;
298298
const struct macvlan_dev *vlan = netdev_priv(dev);
299299

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+
301307
if (likely(ret == NET_XMIT_SUCCESS || ret == NET_XMIT_CN)) {
302308
struct macvlan_pcpu_stats *pcpu_stats;
303309

@@ -347,6 +353,21 @@ static int macvlan_open(struct net_device *dev)
347353
goto hash_add;
348354
}
349355

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+
350371
err = -EBUSY;
351372
if (macvlan_addr_busy(vlan->port, dev->dev_addr))
352373
goto out;
@@ -367,6 +388,11 @@ static int macvlan_open(struct net_device *dev)
367388
del_unicast:
368389
dev_uc_del(lowerdev, dev->dev_addr);
369390
out:
391+
if (vlan->fwd_priv) {
392+
lowerdev->netdev_ops->ndo_dfwd_del_station(lowerdev,
393+
vlan->fwd_priv);
394+
vlan->fwd_priv = NULL;
395+
}
370396
return err;
371397
}
372398

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

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+
378411
dev_uc_unsync(lowerdev, dev);
379412
dev_mc_unsync(lowerdev, dev);
380413

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

869+
dev->priv_flags |= IFF_MACVLAN;
836870
err = netdev_upper_dev_link(lowerdev, dev);
837871
if (err)
838872
goto destroy_port;

include/linux/if_macvlan.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ struct macvlan_dev {
6161
struct hlist_node hlist;
6262
struct macvlan_port *port;
6363
struct net_device *lowerdev;
64+
void *fwd_priv;
6465
struct macvlan_pcpu_stats __percpu *pcpu_stats;
6566

6667
DECLARE_BITMAP(mc_filter, MACVLAN_MC_FILTER_SZ);

include/linux/netdev_features.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ enum {
6262
NETIF_F_HW_VLAN_STAG_TX_BIT, /* Transmit VLAN STAG HW acceleration */
6363
NETIF_F_HW_VLAN_STAG_RX_BIT, /* Receive VLAN STAG HW acceleration */
6464
NETIF_F_HW_VLAN_STAG_FILTER_BIT,/* Receive filtering on VLAN STAGs */
65+
NETIF_F_HW_L2FW_DOFFLOAD_BIT, /* Allow L2 Forwarding in Hardware */
6566

6667
/*
6768
* Add your fresh new feature above and remember to update
@@ -116,6 +117,7 @@ enum {
116117
#define NETIF_F_HW_VLAN_STAG_FILTER __NETIF_F(HW_VLAN_STAG_FILTER)
117118
#define NETIF_F_HW_VLAN_STAG_RX __NETIF_F(HW_VLAN_STAG_RX)
118119
#define NETIF_F_HW_VLAN_STAG_TX __NETIF_F(HW_VLAN_STAG_TX)
120+
#define NETIF_F_HW_L2FW_DOFFLOAD __NETIF_F(HW_L2FW_DOFFLOAD)
119121

120122
/* Features valid for ethtool to change */
121123
/* = all defined minus driver/device-class-related */

include/linux/netdevice.h

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -962,6 +962,25 @@ struct netdev_phys_port_id {
962962
* Called by vxlan to notify the driver about a UDP port and socket
963963
* address family that vxlan is not listening to anymore. The operation
964964
* is protected by the vxlan_net->sock_lock.
965+
*
966+
* void* (*ndo_dfwd_add_station)(struct net_device *pdev,
967+
* struct net_device *dev)
968+
* Called by upper layer devices to accelerate switching or other
969+
* station functionality into hardware. 'pdev is the lowerdev
970+
* to use for the offload and 'dev' is the net device that will
971+
* back the offload. Returns a pointer to the private structure
972+
* the upper layer will maintain.
973+
* void (*ndo_dfwd_del_station)(struct net_device *pdev, void *priv)
974+
* Called by upper layer device to delete the station created
975+
* by 'ndo_dfwd_add_station'. 'pdev' is the net device backing
976+
* the station and priv is the structure returned by the add
977+
* operation.
978+
* netdev_tx_t (*ndo_dfwd_start_xmit)(struct sk_buff *skb,
979+
* struct net_device *dev,
980+
* void *priv);
981+
* Callback to use for xmit over the accelerated station. This
982+
* is used in place of ndo_start_xmit on accelerated net
983+
* devices.
965984
*/
966985
struct net_device_ops {
967986
int (*ndo_init)(struct net_device *dev);
@@ -1098,6 +1117,15 @@ struct net_device_ops {
10981117
void (*ndo_del_vxlan_port)(struct net_device *dev,
10991118
sa_family_t sa_family,
11001119
__be16 port);
1120+
1121+
void* (*ndo_dfwd_add_station)(struct net_device *pdev,
1122+
struct net_device *dev);
1123+
void (*ndo_dfwd_del_station)(struct net_device *pdev,
1124+
void *priv);
1125+
1126+
netdev_tx_t (*ndo_dfwd_start_xmit) (struct sk_buff *skb,
1127+
struct net_device *dev,
1128+
void *priv);
11011129
};
11021130

11031131
/*
@@ -1195,6 +1223,7 @@ struct net_device {
11951223
/* Management operations */
11961224
const struct net_device_ops *netdev_ops;
11971225
const struct ethtool_ops *ethtool_ops;
1226+
const struct forwarding_accel_ops *fwd_ops;
11981227

11991228
/* Hardware header description */
12001229
const struct header_ops *header_ops;
@@ -2388,7 +2417,7 @@ int dev_change_carrier(struct net_device *, bool new_carrier);
23882417
int dev_get_phys_port_id(struct net_device *dev,
23892418
struct netdev_phys_port_id *ppid);
23902419
int dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev,
2391-
struct netdev_queue *txq);
2420+
struct netdev_queue *txq, void *accel_priv);
23922421
int dev_forward_skb(struct net_device *dev, struct sk_buff *skb);
23932422

23942423
extern int netdev_budget;
@@ -2967,6 +2996,11 @@ static inline void netif_set_gso_max_size(struct net_device *dev,
29672996
dev->gso_max_size = size;
29682997
}
29692998

2999+
static inline bool netif_is_macvlan(struct net_device *dev)
3000+
{
3001+
return dev->priv_flags & IFF_MACVLAN;
3002+
}
3003+
29703004
static inline bool netif_is_bond_master(struct net_device *dev)
29713005
{
29723006
return dev->flags & IFF_MASTER && dev->priv_flags & IFF_BONDING;

include/uapi/linux/if.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@
8383
#define IFF_SUPP_NOFCS 0x80000 /* device supports sending custom FCS */
8484
#define IFF_LIVE_ADDR_CHANGE 0x100000 /* device supports hardware address
8585
* change when it's running */
86+
#define IFF_MACVLAN 0x200000 /* Macvlan device */
8687

8788

8889
#define IF_GET_IFACE 0x0001 /* for querying only */

net/core/dev.c

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2538,7 +2538,7 @@ static inline int skb_needs_linearize(struct sk_buff *skb,
25382538
}
25392539

25402540
int dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev,
2541-
struct netdev_queue *txq)
2541+
struct netdev_queue *txq, void *accel_priv)
25422542
{
25432543
const struct net_device_ops *ops = dev->netdev_ops;
25442544
int rc = NETDEV_TX_OK;
@@ -2604,9 +2604,13 @@ int dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev,
26042604
dev_queue_xmit_nit(skb, dev);
26052605

26062606
skb_len = skb->len;
2607-
rc = ops->ndo_start_xmit(skb, dev);
2607+
if (accel_priv)
2608+
rc = ops->ndo_dfwd_start_xmit(skb, dev, accel_priv);
2609+
else
2610+
rc = ops->ndo_start_xmit(skb, dev);
2611+
26082612
trace_net_dev_xmit(skb, rc, dev, skb_len);
2609-
if (rc == NETDEV_TX_OK)
2613+
if (rc == NETDEV_TX_OK && txq)
26102614
txq_trans_update(txq);
26112615
return rc;
26122616
}
@@ -2622,7 +2626,10 @@ int dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev,
26222626
dev_queue_xmit_nit(nskb, dev);
26232627

26242628
skb_len = nskb->len;
2625-
rc = ops->ndo_start_xmit(nskb, dev);
2629+
if (accel_priv)
2630+
rc = ops->ndo_dfwd_start_xmit(nskb, dev, accel_priv);
2631+
else
2632+
rc = ops->ndo_start_xmit(nskb, dev);
26262633
trace_net_dev_xmit(nskb, rc, dev, skb_len);
26272634
if (unlikely(rc != NETDEV_TX_OK)) {
26282635
if (rc & ~NETDEV_TX_MASK)
@@ -2647,6 +2654,7 @@ int dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev,
26472654
out:
26482655
return rc;
26492656
}
2657+
EXPORT_SYMBOL_GPL(dev_hard_start_xmit);
26502658

26512659
static void qdisc_pkt_len_init(struct sk_buff *skb)
26522660
{
@@ -2854,7 +2862,7 @@ int dev_queue_xmit(struct sk_buff *skb)
28542862

28552863
if (!netif_xmit_stopped(txq)) {
28562864
__this_cpu_inc(xmit_recursion);
2857-
rc = dev_hard_start_xmit(skb, dev, txq);
2865+
rc = dev_hard_start_xmit(skb, dev, txq, NULL);
28582866
__this_cpu_dec(xmit_recursion);
28592867
if (dev_xmit_complete(rc)) {
28602868
HARD_TX_UNLOCK(dev, txq);

net/core/ethtool.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,7 @@ static const char netdev_features_strings[NETDEV_FEATURE_COUNT][ETH_GSTRING_LEN]
9696
[NETIF_F_LOOPBACK_BIT] = "loopback",
9797
[NETIF_F_RXFCS_BIT] = "rx-fcs",
9898
[NETIF_F_RXALL_BIT] = "rx-all",
99+
[NETIF_F_HW_L2FW_DOFFLOAD_BIT] = "l2-fwd-offload",
99100
};
100101

101102
static int ethtool_get_features(struct net_device *dev, void __user *useraddr)

net/sched/sch_generic.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,7 @@ int sch_direct_xmit(struct sk_buff *skb, struct Qdisc *q,
126126

127127
HARD_TX_LOCK(dev, txq, smp_processor_id());
128128
if (!netif_xmit_frozen_or_stopped(txq))
129-
ret = dev_hard_start_xmit(skb, dev, txq);
129+
ret = dev_hard_start_xmit(skb, dev, txq, NULL);
130130

131131
HARD_TX_UNLOCK(dev, txq);
132132

0 commit comments

Comments
 (0)