Skip to content

Commit 8a35747

Browse files
herbertxdavem330
authored andcommitted
macvtap: Limit packet queue length
Mark Wagner reported OOM symptoms when sending UDP traffic over a macvtap link to a kvm receiver. This appears to be caused by the fact that macvtap packet queues are unlimited in length. This means that if the receiver can't keep up with the rate of flow, then we will hit OOM. Of course it gets worse if the OOM killer then decides to kill the receiver. This patch imposes a cap on the packet queue length, in the same way as the tuntap driver, using the device TX queue length. Please note that macvtap currently has no way of giving congestion notification, that means the software device TX queue cannot be used and packets will always be dropped once the macvtap driver queue fills up. This shouldn't be a great problem for the scenario where macvtap is used to feed a kvm receiver, as the traffic is most likely external in origin so congestion notification can't be applied anyway. Of course, if anybody decides to complain about guest-to-guest UDP packet loss down the track, then we may have to revisit this. Incidentally, this patch also fixes a real memory leak when macvtap_get_queue fails. Chris Wright noticed that for this patch to work, we need a non-zero TX queue length. This patch includes his work to change the default macvtap TX queue length to 500. Reported-by: Mark Wagner <[email protected]> Signed-off-by: Herbert Xu <[email protected]> Acked-by: Chris Wright <[email protected]> Acked-by: Arnd Bergmann <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent bded64a commit 8a35747

File tree

3 files changed

+26
-4
lines changed

3 files changed

+26
-4
lines changed

drivers/net/macvlan.c

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -499,7 +499,7 @@ static const struct net_device_ops macvlan_netdev_ops = {
499499
.ndo_validate_addr = eth_validate_addr,
500500
};
501501

502-
static void macvlan_setup(struct net_device *dev)
502+
void macvlan_common_setup(struct net_device *dev)
503503
{
504504
ether_setup(dev);
505505

@@ -508,6 +508,12 @@ static void macvlan_setup(struct net_device *dev)
508508
dev->destructor = free_netdev;
509509
dev->header_ops = &macvlan_hard_header_ops,
510510
dev->ethtool_ops = &macvlan_ethtool_ops;
511+
}
512+
EXPORT_SYMBOL_GPL(macvlan_common_setup);
513+
514+
static void macvlan_setup(struct net_device *dev)
515+
{
516+
macvlan_common_setup(dev);
511517
dev->tx_queue_len = 0;
512518
}
513519

@@ -705,7 +711,6 @@ int macvlan_link_register(struct rtnl_link_ops *ops)
705711
/* common fields */
706712
ops->priv_size = sizeof(struct macvlan_dev);
707713
ops->get_tx_queues = macvlan_get_tx_queues;
708-
ops->setup = macvlan_setup;
709714
ops->validate = macvlan_validate;
710715
ops->maxtype = IFLA_MACVLAN_MAX;
711716
ops->policy = macvlan_policy;
@@ -719,6 +724,7 @@ EXPORT_SYMBOL_GPL(macvlan_link_register);
719724

720725
static struct rtnl_link_ops macvlan_link_ops = {
721726
.kind = "macvlan",
727+
.setup = macvlan_setup,
722728
.newlink = macvlan_newlink,
723729
.dellink = macvlan_dellink,
724730
};

drivers/net/macvtap.c

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -180,11 +180,18 @@ static int macvtap_forward(struct net_device *dev, struct sk_buff *skb)
180180
{
181181
struct macvtap_queue *q = macvtap_get_queue(dev, skb);
182182
if (!q)
183-
return -ENOLINK;
183+
goto drop;
184+
185+
if (skb_queue_len(&q->sk.sk_receive_queue) >= dev->tx_queue_len)
186+
goto drop;
184187

185188
skb_queue_tail(&q->sk.sk_receive_queue, skb);
186189
wake_up_interruptible_poll(sk_sleep(&q->sk), POLLIN | POLLRDNORM | POLLRDBAND);
187-
return 0;
190+
return NET_RX_SUCCESS;
191+
192+
drop:
193+
kfree_skb(skb);
194+
return NET_RX_DROP;
188195
}
189196

190197
/*
@@ -235,8 +242,15 @@ static void macvtap_dellink(struct net_device *dev,
235242
macvlan_dellink(dev, head);
236243
}
237244

245+
static void macvtap_setup(struct net_device *dev)
246+
{
247+
macvlan_common_setup(dev);
248+
dev->tx_queue_len = TUN_READQ_SIZE;
249+
}
250+
238251
static struct rtnl_link_ops macvtap_link_ops __read_mostly = {
239252
.kind = "macvtap",
253+
.setup = macvtap_setup,
240254
.newlink = macvtap_newlink,
241255
.dellink = macvtap_dellink,
242256
};

include/linux/if_macvlan.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,8 @@ static inline void macvlan_count_rx(const struct macvlan_dev *vlan,
6767
}
6868
}
6969

70+
extern void macvlan_common_setup(struct net_device *dev);
71+
7072
extern int macvlan_common_newlink(struct net *src_net, struct net_device *dev,
7173
struct nlattr *tb[], struct nlattr *data[],
7274
int (*receive)(struct sk_buff *skb),

0 commit comments

Comments
 (0)