aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2013-12-12 13:38:46 -0500
committerDavid S. Miller <davem@davemloft.net>2013-12-12 13:38:46 -0500
commita46dc748caea185d4d0978280a1af0112bf6a8f8 (patch)
tree80d2a3c5c9396bdd07c751eaa2ccfd42cd9c87c2
parent70f5613271744c8375d5d20a6685a58a9fdcaf8a (diff)
parent2f6a1b6607fd6b0eb9501843a40e0c7555f37b4a (diff)
Merge branch 'macvtap_capture'
Vlad Yasevich says: ==================== Add packet capture support on macvtap device Change from RFC: - moved to the rx_handler approach. This series adds support for packet capturing on macvtap device. The initial approach was to simply export the capturing code as a function from the core network. While simple, it was not a very architecturally clean approach. The new appraoch is to provide macvtap with its rx_handler which can is attached to the macvtap device itself. Macvlan will simply requeue the packet with an updated skb->dev. BTW, macvlan layer already does this for macvlan devices. So, now macvtap and macvlan have almost the same exact input path. I've toyed with short-circuting the input path for macvtap by returning RX_HANDLER_ANOTHER, but that just made the code more complicated and didn't provide any kind of measurable gain (at least according to netperf and perf runs on the host). To see if there was a performance regression, I ran 1, 2 and 4 netperf STREAM and MAERTS tests agains the VM from both remote host and another guest on the same system. The command ran was netperf -H $host -t $test -l 20 -i 10 -I 95 -c -C The numbers I was getting with the new code were consistently very slightly (1-2%) better then the old code. I don't consider this an improvement, but it's not a regression! :) Running 'perf record' on the host didn't show any new hot spots and cpu utilization stayed about the same. This was better then I expected from simply looking at the code. ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--drivers/net/macvlan.c17
-rw-r--r--drivers/net/macvtap.c60
-rw-r--r--include/linux/if_macvlan.h7
3 files changed, 38 insertions, 46 deletions
diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c
index cfb91570cddd..24ea994b6274 100644
--- a/drivers/net/macvlan.c
+++ b/drivers/net/macvlan.c
@@ -120,7 +120,7 @@ static int macvlan_broadcast_one(struct sk_buff *skb,
120 struct net_device *dev = vlan->dev; 120 struct net_device *dev = vlan->dev;
121 121
122 if (local) 122 if (local)
123 return vlan->forward(dev, skb); 123 return dev_forward_skb(dev, skb);
124 124
125 skb->dev = dev; 125 skb->dev = dev;
126 if (ether_addr_equal_64bits(eth->h_dest, dev->broadcast)) 126 if (ether_addr_equal_64bits(eth->h_dest, dev->broadcast))
@@ -128,7 +128,7 @@ static int macvlan_broadcast_one(struct sk_buff *skb,
128 else 128 else
129 skb->pkt_type = PACKET_MULTICAST; 129 skb->pkt_type = PACKET_MULTICAST;
130 130
131 return vlan->receive(skb); 131 return netif_rx(skb);
132} 132}
133 133
134static u32 macvlan_hash_mix(const struct macvlan_dev *vlan) 134static u32 macvlan_hash_mix(const struct macvlan_dev *vlan)
@@ -251,7 +251,7 @@ static rx_handler_result_t macvlan_handle_frame(struct sk_buff **pskb)
251 skb->dev = dev; 251 skb->dev = dev;
252 skb->pkt_type = PACKET_HOST; 252 skb->pkt_type = PACKET_HOST;
253 253
254 ret = vlan->receive(skb); 254 ret = netif_rx(skb);
255 255
256out: 256out:
257 macvlan_count_rx(vlan, len, ret == NET_RX_SUCCESS, 0); 257 macvlan_count_rx(vlan, len, ret == NET_RX_SUCCESS, 0);
@@ -803,10 +803,7 @@ static int macvlan_validate(struct nlattr *tb[], struct nlattr *data[])
803} 803}
804 804
805int macvlan_common_newlink(struct net *src_net, struct net_device *dev, 805int macvlan_common_newlink(struct net *src_net, struct net_device *dev,
806 struct nlattr *tb[], struct nlattr *data[], 806 struct nlattr *tb[], struct nlattr *data[])
807 int (*receive)(struct sk_buff *skb),
808 int (*forward)(struct net_device *dev,
809 struct sk_buff *skb))
810{ 807{
811 struct macvlan_dev *vlan = netdev_priv(dev); 808 struct macvlan_dev *vlan = netdev_priv(dev);
812 struct macvlan_port *port; 809 struct macvlan_port *port;
@@ -848,8 +845,6 @@ int macvlan_common_newlink(struct net *src_net, struct net_device *dev,
848 vlan->lowerdev = lowerdev; 845 vlan->lowerdev = lowerdev;
849 vlan->dev = dev; 846 vlan->dev = dev;
850 vlan->port = port; 847 vlan->port = port;
851 vlan->receive = receive;
852 vlan->forward = forward;
853 vlan->set_features = MACVLAN_FEATURES; 848 vlan->set_features = MACVLAN_FEATURES;
854 849
855 vlan->mode = MACVLAN_MODE_VEPA; 850 vlan->mode = MACVLAN_MODE_VEPA;
@@ -894,9 +889,7 @@ EXPORT_SYMBOL_GPL(macvlan_common_newlink);
894static int macvlan_newlink(struct net *src_net, struct net_device *dev, 889static int macvlan_newlink(struct net *src_net, struct net_device *dev,
895 struct nlattr *tb[], struct nlattr *data[]) 890 struct nlattr *tb[], struct nlattr *data[])
896{ 891{
897 return macvlan_common_newlink(src_net, dev, tb, data, 892 return macvlan_common_newlink(src_net, dev, tb, data);
898 netif_rx,
899 dev_forward_skb);
900} 893}
901 894
902void macvlan_dellink(struct net_device *dev, struct list_head *head) 895void macvlan_dellink(struct net_device *dev, struct list_head *head)
diff --git a/drivers/net/macvtap.c b/drivers/net/macvtap.c
index 4a34bcb6549f..64409af0da31 100644
--- a/drivers/net/macvtap.c
+++ b/drivers/net/macvtap.c
@@ -70,6 +70,11 @@ static const struct proto_ops macvtap_socket_ops;
70#define RX_OFFLOADS (NETIF_F_GRO | NETIF_F_LRO) 70#define RX_OFFLOADS (NETIF_F_GRO | NETIF_F_LRO)
71#define TAP_FEATURES (NETIF_F_GSO | NETIF_F_SG) 71#define TAP_FEATURES (NETIF_F_GSO | NETIF_F_SG)
72 72
73static struct macvlan_dev *macvtap_get_vlan_rcu(const struct net_device *dev)
74{
75 return rcu_dereference(dev->rx_handler_data);
76}
77
73/* 78/*
74 * RCU usage: 79 * RCU usage:
75 * The macvtap_queue and the macvlan_dev are loosely coupled, the 80 * The macvtap_queue and the macvlan_dev are loosely coupled, the
@@ -271,24 +276,27 @@ static void macvtap_del_queues(struct net_device *dev)
271 sock_put(&qlist[j]->sk); 276 sock_put(&qlist[j]->sk);
272} 277}
273 278
274/* 279static rx_handler_result_t macvtap_handle_frame(struct sk_buff **pskb)
275 * Forward happens for data that gets sent from one macvlan
276 * endpoint to another one in bridge mode. We just take
277 * the skb and put it into the receive queue.
278 */
279static int macvtap_forward(struct net_device *dev, struct sk_buff *skb)
280{ 280{
281 struct macvlan_dev *vlan = netdev_priv(dev); 281 struct sk_buff *skb = *pskb;
282 struct macvtap_queue *q = macvtap_get_queue(dev, skb); 282 struct net_device *dev = skb->dev;
283 struct macvlan_dev *vlan;
284 struct macvtap_queue *q;
283 netdev_features_t features = TAP_FEATURES; 285 netdev_features_t features = TAP_FEATURES;
284 286
287 vlan = macvtap_get_vlan_rcu(dev);
288 if (!vlan)
289 return RX_HANDLER_PASS;
290
291 q = macvtap_get_queue(dev, skb);
285 if (!q) 292 if (!q)
286 goto drop; 293 return RX_HANDLER_PASS;
287 294
288 if (skb_queue_len(&q->sk.sk_receive_queue) >= dev->tx_queue_len) 295 if (skb_queue_len(&q->sk.sk_receive_queue) >= dev->tx_queue_len)
289 goto drop; 296 goto drop;
290 297
291 skb->dev = dev; 298 skb_push(skb, ETH_HLEN);
299
292 /* Apply the forward feature mask so that we perform segmentation 300 /* Apply the forward feature mask so that we perform segmentation
293 * according to users wishes. This only works if VNET_HDR is 301 * according to users wishes. This only works if VNET_HDR is
294 * enabled. 302 * enabled.
@@ -320,22 +328,13 @@ static int macvtap_forward(struct net_device *dev, struct sk_buff *skb)
320 328
321wake_up: 329wake_up:
322 wake_up_interruptible_poll(sk_sleep(&q->sk), POLLIN | POLLRDNORM | POLLRDBAND); 330 wake_up_interruptible_poll(sk_sleep(&q->sk), POLLIN | POLLRDNORM | POLLRDBAND);
323 return NET_RX_SUCCESS; 331 return RX_HANDLER_CONSUMED;
324 332
325drop: 333drop:
334 /* Count errors/drops only here, thus don't care about args. */
335 macvlan_count_rx(vlan, 0, 0, 0);
326 kfree_skb(skb); 336 kfree_skb(skb);
327 return NET_RX_DROP; 337 return RX_HANDLER_CONSUMED;
328}
329
330/*
331 * Receive is for data from the external interface (lowerdev),
332 * in case of macvtap, we can treat that the same way as
333 * forward, which macvlan cannot.
334 */
335static int macvtap_receive(struct sk_buff *skb)
336{
337 skb_push(skb, ETH_HLEN);
338 return macvtap_forward(skb->dev, skb);
339} 338}
340 339
341static int macvtap_get_minor(struct macvlan_dev *vlan) 340static int macvtap_get_minor(struct macvlan_dev *vlan)
@@ -385,6 +384,8 @@ static int macvtap_newlink(struct net *src_net,
385 struct nlattr *data[]) 384 struct nlattr *data[])
386{ 385{
387 struct macvlan_dev *vlan = netdev_priv(dev); 386 struct macvlan_dev *vlan = netdev_priv(dev);
387 int err;
388
388 INIT_LIST_HEAD(&vlan->queue_list); 389 INIT_LIST_HEAD(&vlan->queue_list);
389 390
390 /* Since macvlan supports all offloads by default, make 391 /* Since macvlan supports all offloads by default, make
@@ -392,16 +393,20 @@ static int macvtap_newlink(struct net *src_net,
392 */ 393 */
393 vlan->tap_features = TUN_OFFLOADS; 394 vlan->tap_features = TUN_OFFLOADS;
394 395
396 err = netdev_rx_handler_register(dev, macvtap_handle_frame, vlan);
397 if (err)
398 return err;
399
395 /* Don't put anything that may fail after macvlan_common_newlink 400 /* Don't put anything that may fail after macvlan_common_newlink
396 * because we can't undo what it does. 401 * because we can't undo what it does.
397 */ 402 */
398 return macvlan_common_newlink(src_net, dev, tb, data, 403 return macvlan_common_newlink(src_net, dev, tb, data);
399 macvtap_receive, macvtap_forward);
400} 404}
401 405
402static void macvtap_dellink(struct net_device *dev, 406static void macvtap_dellink(struct net_device *dev,
403 struct list_head *head) 407 struct list_head *head)
404{ 408{
409 netdev_rx_handler_unregister(dev);
405 macvtap_del_queues(dev); 410 macvtap_del_queues(dev);
406 macvlan_dellink(dev, head); 411 macvlan_dellink(dev, head);
407} 412}
@@ -725,9 +730,8 @@ static ssize_t macvtap_get_user(struct macvtap_queue *q, struct msghdr *m,
725 skb_shinfo(skb)->tx_flags |= SKBTX_SHARED_FRAG; 730 skb_shinfo(skb)->tx_flags |= SKBTX_SHARED_FRAG;
726 } 731 }
727 if (vlan) { 732 if (vlan) {
728 local_bh_disable(); 733 skb->dev = vlan->dev;
729 macvlan_start_xmit(skb, vlan->dev); 734 dev_queue_xmit(skb);
730 local_bh_enable();
731 } else { 735 } else {
732 kfree_skb(skb); 736 kfree_skb(skb);
733 } 737 }
diff --git a/include/linux/if_macvlan.h b/include/linux/if_macvlan.h
index 84ba5ac39e03..ea22721ba269 100644
--- a/include/linux/if_macvlan.h
+++ b/include/linux/if_macvlan.h
@@ -69,8 +69,6 @@ struct macvlan_dev {
69 netdev_features_t set_features; 69 netdev_features_t set_features;
70 enum macvlan_mode mode; 70 enum macvlan_mode mode;
71 u16 flags; 71 u16 flags;
72 int (*receive)(struct sk_buff *skb);
73 int (*forward)(struct net_device *dev, struct sk_buff *skb);
74 /* This array tracks active taps. */ 72 /* This array tracks active taps. */
75 struct macvtap_queue __rcu *taps[MAX_MACVTAP_QUEUES]; 73 struct macvtap_queue __rcu *taps[MAX_MACVTAP_QUEUES];
76 /* This list tracks all taps (both enabled and disabled) */ 74 /* This list tracks all taps (both enabled and disabled) */
@@ -103,10 +101,7 @@ static inline void macvlan_count_rx(const struct macvlan_dev *vlan,
103extern void macvlan_common_setup(struct net_device *dev); 101extern void macvlan_common_setup(struct net_device *dev);
104 102
105extern int macvlan_common_newlink(struct net *src_net, struct net_device *dev, 103extern int macvlan_common_newlink(struct net *src_net, struct net_device *dev,
106 struct nlattr *tb[], struct nlattr *data[], 104 struct nlattr *tb[], struct nlattr *data[]);
107 int (*receive)(struct sk_buff *skb),
108 int (*forward)(struct net_device *dev,
109 struct sk_buff *skb));
110 105
111extern void macvlan_count_rx(const struct macvlan_dev *vlan, 106extern void macvlan_count_rx(const struct macvlan_dev *vlan,
112 unsigned int len, bool success, 107 unsigned int len, bool success,