[ovs-dev] [PATCH] Avoid skb-clone in upcall

Pravin Shelar pshelar at nicira.com
Thu Sep 29 15:41:33 PDT 2011


There is not need to clone skb while sending packet to user-space.
Since data is only read from packet skb.

Signed-off-by: Pravin Shelar <pshelar at nicira.com>
---
 datapath/actions.c  |    4 ---
 datapath/datapath.c |   63 +++++++++++++++++++++-----------------------------
 2 files changed, 27 insertions(+), 40 deletions(-)

diff --git a/datapath/actions.c b/datapath/actions.c
index cba12e6..36437a4 100644
--- a/datapath/actions.c
+++ b/datapath/actions.c
@@ -248,10 +248,6 @@ static int output_userspace(struct datapath *dp, struct sk_buff *skb, u64 arg)
 {
 	struct dp_upcall_info upcall;
 
-	skb = skb_clone(skb, GFP_ATOMIC);
-	if (!skb)
-		return -ENOMEM;
-
 	upcall.cmd = OVS_PACKET_CMD_ACTION;
 	upcall.key = &OVS_CB(skb)->flow->key;
 	upcall.userdata = arg;
diff --git a/datapath/datapath.c b/datapath/datapath.c
index 63a3932..83c147b 100644
--- a/datapath/datapath.c
+++ b/datapath/datapath.c
@@ -311,6 +311,7 @@ void dp_process_received_packet(struct vport *p, struct sk_buff *skb)
 			upcall.cmd = OVS_PACKET_CMD_MISS;
 			upcall.key = &key;
 			dp_upcall(dp, skb, &upcall);
+                	kfree_skb(skb);
 			stats_counter_off = offsetof(struct dp_stats_percpu, n_missed);
 			goto out;
 		}
@@ -357,8 +358,10 @@ static struct genl_family dp_packet_genl_family = {
 	.maxattr = OVS_PACKET_ATTR_MAX
 };
 
-int dp_upcall(struct datapath *dp, struct sk_buff *skb, const struct dp_upcall_info *upcall_info)
+int dp_upcall(struct datapath *dp, struct sk_buff *skb,
+	      const struct dp_upcall_info *upcall_info)
 {
+	struct sk_buff *nskb = NULL;
 	struct dp_stats_percpu *stats;
 	u32 pid;
 	int err;
@@ -370,7 +373,6 @@ int dp_upcall(struct datapath *dp, struct sk_buff *skb, const struct dp_upcall_i
 
 	if (pid == 0) {
 		err = -ENOTCONN;
-		kfree_skb(skb);
 		goto err;
 	}
 
@@ -379,18 +381,25 @@ int dp_upcall(struct datapath *dp, struct sk_buff *skb, const struct dp_upcall_i
 	/* Break apart GSO packets into their component pieces.  Otherwise
 	 * userspace may try to stuff a 64kB packet into a 1500-byte MTU. */
 	if (skb_is_gso(skb)) {
-		struct sk_buff *nskb = skb_gso_segment(skb, NETIF_F_SG | NETIF_F_HW_CSUM);
+		nskb = skb_gso_segment(skb, NETIF_F_SG | NETIF_F_HW_CSUM);
 		
 		if (IS_ERR(nskb)) {
-			kfree_skb(skb);
 			err = PTR_ERR(nskb);
 			goto err;
 		}
-		consume_skb(skb);
 		skb = nskb;
 	}
 
 	err = queue_userspace_packets(dp, pid, skb, upcall_info);
+	if (nskb) {
+		struct sk_buff *next;
+		/* Free GSO-segments */
+	        do {
+                	next = nskb->next;
+                	kfree_skb(nskb);
+        	} while ((nskb = next) != NULL);
+	}
+
 	if (err)
 		goto err;
 
@@ -418,33 +427,24 @@ static int queue_userspace_packets(struct datapath *dp, u32 pid,
 				   const struct dp_upcall_info *upcall_info)
 {
 	int dp_ifindex;
-	struct sk_buff *nskb;
-	int err;
 
 	dp_ifindex = get_dpifindex(dp);
-	if (!dp_ifindex) {
-		err = -ENODEV;
-		nskb = skb->next;
-		goto err_kfree_skbs;
-	}
+	if (!dp_ifindex)
+		return -ENODEV;
 
 	do {
 		struct ovs_header *upcall;
 		struct sk_buff *user_skb; /* to be queued to userspace */
 		struct nlattr *nla;
 		unsigned int len;
-
-		nskb = skb->next;
-		skb->next = NULL;
+		int err;
 
 		err = vlan_deaccel_tag(skb);
 		if (unlikely(err))
-			goto err_kfree_skbs;
+			return err;
 
-		if (nla_attr_size(skb->len) > USHRT_MAX) {
-			err = -EFBIG;
-			goto err_kfree_skbs;
-		}
+		if (nla_attr_size(skb->len) > USHRT_MAX)
+			return -EFBIG;
 
 		len = sizeof(struct ovs_header);
 		len += nla_total_size(skb->len);
@@ -453,12 +453,11 @@ static int queue_userspace_packets(struct datapath *dp, u32 pid,
 			len += nla_total_size(8);
 
 		user_skb = genlmsg_new(len, GFP_ATOMIC);
-		if (!user_skb) {
-			err = -ENOMEM;
-			goto err_kfree_skbs;
-		}
+		if (!user_skb)
+			return -ENOMEM;
 
-		upcall = genlmsg_put(user_skb, 0, 0, &dp_packet_genl_family, 0, upcall_info->cmd);
+		upcall = genlmsg_put(user_skb, 0, 0, &dp_packet_genl_family,
+					 0, upcall_info->cmd);
 		upcall->dp_ifindex = dp_ifindex;
 
 		nla = nla_nest_start(user_skb, OVS_PACKET_ATTR_KEY);
@@ -477,20 +476,12 @@ static int queue_userspace_packets(struct datapath *dp, u32 pid,
 
 		err = genlmsg_unicast(&init_net, user_skb, pid);
 		if (err)
-			goto err_kfree_skbs;
+			return err;
 
-		consume_skb(skb);
-		skb = nskb;
+		skb = skb->next;
 	} while (skb);
-	return 0;
 
-err_kfree_skbs:
-	kfree_skb(skb);
-	while ((skb = nskb) != NULL) {
-		nskb = skb->next;
-		kfree_skb(skb);
-	}
-	return err;
+	return 0;
 }
 
 /* Called with genl_mutex. */
-- 
1.7.1




More information about the dev mailing list