summaryrefslogtreecommitdiffstats
path: root/drivers/net/macvlan.c
diff options
context:
space:
mode:
authorHerbert Xu <herbert@gondor.apana.org.au>2014-04-17 01:45:59 -0400
committerDavid S. Miller <davem@davemloft.net>2014-04-20 18:18:55 -0400
commit412ca1550cbecb2cbed6086df51af08aa3452c86 (patch)
tree8f7b15d976f7e68e36e8b787154e3943fbc39192 /drivers/net/macvlan.c
parenta0265d28b3a5877b5b8edd14eb12a2ccb60ab1f3 (diff)
macvlan: Move broadcasts into a work queue
Currently broadcasts are handled in network RX context, where the packets are sent through netif_rx. This means that the number of macvlans will be constrained by the capacity of netif_rx. For example, setting up 4096 macvlans practically causes all broadcast packets to be dropped as the default netif_rx queue size simply can't handle 4096 skbs being stuffed into it all at once. Fundamentally, we need to ensure that the amount of work handled in each netif_rx backlog run is constrained. As broadcasts are anything but constrained, it either needs to be limited per run or moved to process context. This patch picks the second option and moves all broadcast handling bar the trivial case of packets going to a single interface into a work queue. Obviously there also needs to be a limit on how many broadcast packets we postpone in this way. I've arbitrarily chosen tx_queue_len of the master device as the limit (act_mirred also happens to use this parameter in a similar way). In order to ensure we don't exceed the backlog queue we will use netif_rx_ni instead of netif_rx for broadcast packets. Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au> Thanks, Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/macvlan.c')
-rw-r--r--drivers/net/macvlan.c116
1 files changed, 93 insertions, 23 deletions
diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c
index 753a8c23d15d..8b8220fcdd3d 100644
--- a/drivers/net/macvlan.c
+++ b/drivers/net/macvlan.c
@@ -30,6 +30,7 @@
30#include <linux/if_link.h> 30#include <linux/if_link.h>
31#include <linux/if_macvlan.h> 31#include <linux/if_macvlan.h>
32#include <linux/hash.h> 32#include <linux/hash.h>
33#include <linux/workqueue.h>
33#include <net/rtnetlink.h> 34#include <net/rtnetlink.h>
34#include <net/xfrm.h> 35#include <net/xfrm.h>
35 36
@@ -40,10 +41,18 @@ struct macvlan_port {
40 struct hlist_head vlan_hash[MACVLAN_HASH_SIZE]; 41 struct hlist_head vlan_hash[MACVLAN_HASH_SIZE];
41 struct list_head vlans; 42 struct list_head vlans;
42 struct rcu_head rcu; 43 struct rcu_head rcu;
44 struct sk_buff_head bc_queue;
45 struct work_struct bc_work;
43 bool passthru; 46 bool passthru;
44 int count; 47 int count;
45}; 48};
46 49
50struct macvlan_skb_cb {
51 const struct macvlan_dev *src;
52};
53
54#define MACVLAN_SKB_CB(__skb) ((struct macvlan_skb_cb *)&((__skb)->cb[0]))
55
47static void macvlan_port_destroy(struct net_device *dev); 56static void macvlan_port_destroy(struct net_device *dev);
48 57
49static struct macvlan_port *macvlan_port_get_rcu(const struct net_device *dev) 58static struct macvlan_port *macvlan_port_get_rcu(const struct net_device *dev)
@@ -120,7 +129,7 @@ static int macvlan_broadcast_one(struct sk_buff *skb,
120 struct net_device *dev = vlan->dev; 129 struct net_device *dev = vlan->dev;
121 130
122 if (local) 131 if (local)
123 return dev_forward_skb(dev, skb); 132 return __dev_forward_skb(dev, skb);
124 133
125 skb->dev = dev; 134 skb->dev = dev;
126 if (ether_addr_equal_64bits(eth->h_dest, dev->broadcast)) 135 if (ether_addr_equal_64bits(eth->h_dest, dev->broadcast))
@@ -128,7 +137,7 @@ static int macvlan_broadcast_one(struct sk_buff *skb,
128 else 137 else
129 skb->pkt_type = PACKET_MULTICAST; 138 skb->pkt_type = PACKET_MULTICAST;
130 139
131 return netif_rx(skb); 140 return 0;
132} 141}
133 142
134static u32 macvlan_hash_mix(const struct macvlan_dev *vlan) 143static u32 macvlan_hash_mix(const struct macvlan_dev *vlan)
@@ -175,32 +184,32 @@ static void macvlan_broadcast(struct sk_buff *skb,
175 if (likely(nskb)) 184 if (likely(nskb))
176 err = macvlan_broadcast_one( 185 err = macvlan_broadcast_one(
177 nskb, vlan, eth, 186 nskb, vlan, eth,
178 mode == MACVLAN_MODE_BRIDGE); 187 mode == MACVLAN_MODE_BRIDGE) ?:
188 netif_rx_ni(nskb);
179 macvlan_count_rx(vlan, skb->len + ETH_HLEN, 189 macvlan_count_rx(vlan, skb->len + ETH_HLEN,
180 err == NET_RX_SUCCESS, 1); 190 err == NET_RX_SUCCESS, 1);
181 } 191 }
182 } 192 }
183} 193}
184 194
185/* called under rcu_read_lock() from netif_receive_skb */ 195static void macvlan_process_broadcast(struct work_struct *w)
186static rx_handler_result_t macvlan_handle_frame(struct sk_buff **pskb)
187{ 196{
188 struct macvlan_port *port; 197 struct macvlan_port *port = container_of(w, struct macvlan_port,
189 struct sk_buff *skb = *pskb; 198 bc_work);
190 const struct ethhdr *eth = eth_hdr(skb); 199 struct sk_buff *skb;
191 const struct macvlan_dev *vlan; 200 struct sk_buff_head list;
192 const struct macvlan_dev *src; 201
193 struct net_device *dev; 202 skb_queue_head_init(&list);
194 unsigned int len = 0; 203
195 int ret = NET_RX_DROP; 204 spin_lock_bh(&port->bc_queue.lock);
205 skb_queue_splice_tail_init(&port->bc_queue, &list);
206 spin_unlock_bh(&port->bc_queue.lock);
207
208 while ((skb = __skb_dequeue(&list))) {
209 const struct macvlan_dev *src = MACVLAN_SKB_CB(skb)->src;
210
211 rcu_read_lock();
196 212
197 port = macvlan_port_get_rcu(skb->dev);
198 if (is_multicast_ether_addr(eth->h_dest)) {
199 skb = ip_check_defrag(skb, IP_DEFRAG_MACVLAN);
200 if (!skb)
201 return RX_HANDLER_CONSUMED;
202 eth = eth_hdr(skb);
203 src = macvlan_hash_lookup(port, eth->h_source);
204 if (!src) 213 if (!src)
205 /* frame comes from an external address */ 214 /* frame comes from an external address */
206 macvlan_broadcast(skb, port, NULL, 215 macvlan_broadcast(skb, port, NULL,
@@ -213,20 +222,77 @@ static rx_handler_result_t macvlan_handle_frame(struct sk_buff **pskb)
213 macvlan_broadcast(skb, port, src->dev, 222 macvlan_broadcast(skb, port, src->dev,
214 MACVLAN_MODE_VEPA | 223 MACVLAN_MODE_VEPA |
215 MACVLAN_MODE_BRIDGE); 224 MACVLAN_MODE_BRIDGE);
216 else if (src->mode == MACVLAN_MODE_BRIDGE) 225 else
217 /* 226 /*
218 * flood only to VEPA ports, bridge ports 227 * flood only to VEPA ports, bridge ports
219 * already saw the frame on the way out. 228 * already saw the frame on the way out.
220 */ 229 */
221 macvlan_broadcast(skb, port, src->dev, 230 macvlan_broadcast(skb, port, src->dev,
222 MACVLAN_MODE_VEPA); 231 MACVLAN_MODE_VEPA);
223 else { 232
233 rcu_read_unlock();
234
235 kfree_skb(skb);
236 }
237}
238
239static void macvlan_broadcast_enqueue(struct macvlan_port *port,
240 struct sk_buff *skb)
241{
242 int err = -ENOMEM;
243
244 skb = skb_clone(skb, GFP_ATOMIC);
245 if (!skb)
246 goto err;
247
248 spin_lock(&port->bc_queue.lock);
249 if (skb_queue_len(&port->bc_queue) < skb->dev->tx_queue_len) {
250 __skb_queue_tail(&port->bc_queue, skb);
251 err = 0;
252 }
253 spin_unlock(&port->bc_queue.lock);
254
255 if (err)
256 goto err;
257
258 schedule_work(&port->bc_work);
259 return;
260
261err:
262 atomic_long_inc(&skb->dev->rx_dropped);
263}
264
265/* called under rcu_read_lock() from netif_receive_skb */
266static rx_handler_result_t macvlan_handle_frame(struct sk_buff **pskb)
267{
268 struct macvlan_port *port;
269 struct sk_buff *skb = *pskb;
270 const struct ethhdr *eth = eth_hdr(skb);
271 const struct macvlan_dev *vlan;
272 const struct macvlan_dev *src;
273 struct net_device *dev;
274 unsigned int len = 0;
275 int ret = NET_RX_DROP;
276
277 port = macvlan_port_get_rcu(skb->dev);
278 if (is_multicast_ether_addr(eth->h_dest)) {
279 skb = ip_check_defrag(skb, IP_DEFRAG_MACVLAN);
280 if (!skb)
281 return RX_HANDLER_CONSUMED;
282 eth = eth_hdr(skb);
283 src = macvlan_hash_lookup(port, eth->h_source);
284 if (src && src->mode != MACVLAN_MODE_VEPA &&
285 src->mode != MACVLAN_MODE_BRIDGE) {
224 /* forward to original port. */ 286 /* forward to original port. */
225 vlan = src; 287 vlan = src;
226 ret = macvlan_broadcast_one(skb, vlan, eth, 0); 288 ret = macvlan_broadcast_one(skb, vlan, eth, 0) ?:
289 netif_rx(skb);
227 goto out; 290 goto out;
228 } 291 }
229 292
293 MACVLAN_SKB_CB(skb)->src = src;
294 macvlan_broadcast_enqueue(port, skb);
295
230 return RX_HANDLER_PASS; 296 return RX_HANDLER_PASS;
231 } 297 }
232 298
@@ -764,6 +830,9 @@ static int macvlan_port_create(struct net_device *dev)
764 for (i = 0; i < MACVLAN_HASH_SIZE; i++) 830 for (i = 0; i < MACVLAN_HASH_SIZE; i++)
765 INIT_HLIST_HEAD(&port->vlan_hash[i]); 831 INIT_HLIST_HEAD(&port->vlan_hash[i]);
766 832
833 skb_queue_head_init(&port->bc_queue);
834 INIT_WORK(&port->bc_work, macvlan_process_broadcast);
835
767 err = netdev_rx_handler_register(dev, macvlan_handle_frame, port); 836 err = netdev_rx_handler_register(dev, macvlan_handle_frame, port);
768 if (err) 837 if (err)
769 kfree(port); 838 kfree(port);
@@ -776,6 +845,7 @@ static void macvlan_port_destroy(struct net_device *dev)
776{ 845{
777 struct macvlan_port *port = macvlan_port_get_rtnl(dev); 846 struct macvlan_port *port = macvlan_port_get_rtnl(dev);
778 847
848 cancel_work_sync(&port->bc_work);
779 dev->priv_flags &= ~IFF_MACVLAN_PORT; 849 dev->priv_flags &= ~IFF_MACVLAN_PORT;
780 netdev_rx_handler_unregister(dev); 850 netdev_rx_handler_unregister(dev);
781 kfree_rcu(port, rcu); 851 kfree_rcu(port, rcu);