macvlan: add multiqueue capability
macvlan devices are currently not multi-queue capable. We can do that defining rtnl_link_ops method, get_tx_queues(), called from rtnl_create_link() This new method gets num_tx_queues/real_num_tx_queues from lower device. macvlan_get_tx_queues() is a copy of vlan_get_tx_queues(). Because macvlan_start_xmit() has to update netdev_queue stats only (and not dev->stats), I chose to change tx_errors/tx_aborted_errors accounting to tx_dropped, since netdev_queue structure doesnt define tx_errors / tx_aborted_errors. Signed-off-by: Eric Dumazet <eric.dumazet@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
Родитель
0fa0ee053a
Коммит
2c11455321
|
@ -187,6 +187,8 @@ static struct sk_buff *macvlan_handle_frame(struct sk_buff *skb)
|
||||||
static netdev_tx_t macvlan_start_xmit(struct sk_buff *skb,
|
static netdev_tx_t macvlan_start_xmit(struct sk_buff *skb,
|
||||||
struct net_device *dev)
|
struct net_device *dev)
|
||||||
{
|
{
|
||||||
|
int i = skb_get_queue_mapping(skb);
|
||||||
|
struct netdev_queue *txq = netdev_get_tx_queue(dev, i);
|
||||||
const struct macvlan_dev *vlan = netdev_priv(dev);
|
const struct macvlan_dev *vlan = netdev_priv(dev);
|
||||||
unsigned int len = skb->len;
|
unsigned int len = skb->len;
|
||||||
int ret;
|
int ret;
|
||||||
|
@ -195,12 +197,11 @@ static netdev_tx_t macvlan_start_xmit(struct sk_buff *skb,
|
||||||
ret = dev_queue_xmit(skb);
|
ret = dev_queue_xmit(skb);
|
||||||
|
|
||||||
if (likely(ret == NET_XMIT_SUCCESS)) {
|
if (likely(ret == NET_XMIT_SUCCESS)) {
|
||||||
dev->stats.tx_packets++;
|
txq->tx_packets++;
|
||||||
dev->stats.tx_bytes += len;
|
txq->tx_bytes += len;
|
||||||
} else {
|
} else
|
||||||
dev->stats.tx_errors++;
|
txq->tx_dropped++;
|
||||||
dev->stats.tx_aborted_errors++;
|
|
||||||
}
|
|
||||||
return NETDEV_TX_OK;
|
return NETDEV_TX_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -484,6 +485,25 @@ static int macvlan_validate(struct nlattr *tb[], struct nlattr *data[])
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int macvlan_get_tx_queues(struct net *net,
|
||||||
|
struct nlattr *tb[],
|
||||||
|
unsigned int *num_tx_queues,
|
||||||
|
unsigned int *real_num_tx_queues)
|
||||||
|
{
|
||||||
|
struct net_device *real_dev;
|
||||||
|
|
||||||
|
if (!tb[IFLA_LINK])
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
real_dev = __dev_get_by_index(net, nla_get_u32(tb[IFLA_LINK]));
|
||||||
|
if (!real_dev)
|
||||||
|
return -ENODEV;
|
||||||
|
|
||||||
|
*num_tx_queues = real_dev->num_tx_queues;
|
||||||
|
*real_num_tx_queues = real_dev->real_num_tx_queues;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int macvlan_newlink(struct net_device *dev,
|
static int macvlan_newlink(struct net_device *dev,
|
||||||
struct nlattr *tb[], struct nlattr *data[])
|
struct nlattr *tb[], struct nlattr *data[])
|
||||||
{
|
{
|
||||||
|
@ -550,6 +570,7 @@ static void macvlan_dellink(struct net_device *dev)
|
||||||
static struct rtnl_link_ops macvlan_link_ops __read_mostly = {
|
static struct rtnl_link_ops macvlan_link_ops __read_mostly = {
|
||||||
.kind = "macvlan",
|
.kind = "macvlan",
|
||||||
.priv_size = sizeof(struct macvlan_dev),
|
.priv_size = sizeof(struct macvlan_dev),
|
||||||
|
.get_tx_queues = macvlan_get_tx_queues,
|
||||||
.setup = macvlan_setup,
|
.setup = macvlan_setup,
|
||||||
.validate = macvlan_validate,
|
.validate = macvlan_validate,
|
||||||
.newlink = macvlan_newlink,
|
.newlink = macvlan_newlink,
|
||||||
|
|
Загрузка…
Ссылка в новой задаче