2
0
mirror of https://github.com/openvswitch/ovs synced 2025-10-07 13:40:45 +00:00

datapath: Avoid skb-clone in upcall

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@nicira.com>
Acked-by: Jesse Gross <jesse@nicira.com>
This commit is contained in:
Pravin Shelar
2011-09-29 16:33:06 -07:00
parent 6ecf431e1d
commit 36ce148c6d
2 changed files with 30 additions and 44 deletions

View File

@@ -248,10 +248,6 @@ static int output_userspace(struct datapath *dp, struct sk_buff *skb, u64 arg)
{ {
struct dp_upcall_info upcall; struct dp_upcall_info upcall;
skb = skb_clone(skb, GFP_ATOMIC);
if (!skb)
return -ENOMEM;
upcall.cmd = OVS_PACKET_CMD_ACTION; upcall.cmd = OVS_PACKET_CMD_ACTION;
upcall.key = &OVS_CB(skb)->flow->key; upcall.key = &OVS_CB(skb)->flow->key;
upcall.userdata = arg; upcall.userdata = arg;

View File

@@ -311,6 +311,7 @@ void dp_process_received_packet(struct vport *p, struct sk_buff *skb)
upcall.cmd = OVS_PACKET_CMD_MISS; upcall.cmd = OVS_PACKET_CMD_MISS;
upcall.key = &key; upcall.key = &key;
dp_upcall(dp, skb, &upcall); dp_upcall(dp, skb, &upcall);
kfree_skb(skb);
stats_counter_off = offsetof(struct dp_stats_percpu, n_missed); stats_counter_off = offsetof(struct dp_stats_percpu, n_missed);
goto out; goto out;
} }
@@ -357,8 +358,10 @@ static struct genl_family dp_packet_genl_family = {
.maxattr = OVS_PACKET_ATTR_MAX .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 *segs = NULL;
struct dp_stats_percpu *stats; struct dp_stats_percpu *stats;
u32 pid; u32 pid;
int err; int err;
@@ -370,7 +373,6 @@ int dp_upcall(struct datapath *dp, struct sk_buff *skb, const struct dp_upcall_i
if (pid == 0) { if (pid == 0) {
err = -ENOTCONN; err = -ENOTCONN;
kfree_skb(skb);
goto err; 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 /* Break apart GSO packets into their component pieces. Otherwise
* userspace may try to stuff a 64kB packet into a 1500-byte MTU. */ * userspace may try to stuff a 64kB packet into a 1500-byte MTU. */
if (skb_is_gso(skb)) { if (skb_is_gso(skb)) {
struct sk_buff *nskb = skb_gso_segment(skb, NETIF_F_SG | NETIF_F_HW_CSUM); segs = skb_gso_segment(skb, NETIF_F_SG | NETIF_F_HW_CSUM);
if (IS_ERR(nskb)) { if (IS_ERR(segs)) {
kfree_skb(skb); err = PTR_ERR(segs);
err = PTR_ERR(nskb);
goto err; goto err;
} }
consume_skb(skb); skb = segs;
skb = nskb;
} }
err = queue_userspace_packets(dp, pid, skb, upcall_info); err = queue_userspace_packets(dp, pid, skb, upcall_info);
if (segs) {
struct sk_buff *next;
/* Free GSO-segments */
do {
next = segs->next;
kfree_skb(segs);
} while ((segs = next) != NULL);
}
if (err) if (err)
goto err; goto err;
@@ -418,33 +427,24 @@ static int queue_userspace_packets(struct datapath *dp, u32 pid,
const struct dp_upcall_info *upcall_info) const struct dp_upcall_info *upcall_info)
{ {
int dp_ifindex; int dp_ifindex;
struct sk_buff *nskb;
int err;
dp_ifindex = get_dpifindex(dp); dp_ifindex = get_dpifindex(dp);
if (!dp_ifindex) { if (!dp_ifindex)
err = -ENODEV; return -ENODEV;
nskb = skb->next;
goto err_kfree_skbs;
}
do { do {
struct ovs_header *upcall; struct ovs_header *upcall;
struct sk_buff *user_skb; /* to be queued to userspace */ struct sk_buff *user_skb; /* to be queued to userspace */
struct nlattr *nla; struct nlattr *nla;
unsigned int len; unsigned int len;
int err;
nskb = skb->next;
skb->next = NULL;
err = vlan_deaccel_tag(skb); err = vlan_deaccel_tag(skb);
if (unlikely(err)) if (unlikely(err))
goto err_kfree_skbs; return err;
if (nla_attr_size(skb->len) > USHRT_MAX) { if (nla_attr_size(skb->len) > USHRT_MAX)
err = -EFBIG; return -EFBIG;
goto err_kfree_skbs;
}
len = sizeof(struct ovs_header); len = sizeof(struct ovs_header);
len += nla_total_size(skb->len); 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); len += nla_total_size(8);
user_skb = genlmsg_new(len, GFP_ATOMIC); user_skb = genlmsg_new(len, GFP_ATOMIC);
if (!user_skb) { if (!user_skb)
err = -ENOMEM; return -ENOMEM;
goto err_kfree_skbs;
}
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; upcall->dp_ifindex = dp_ifindex;
nla = nla_nest_start(user_skb, OVS_PACKET_ATTR_KEY); nla = nla_nest_start(user_skb, OVS_PACKET_ATTR_KEY);
@@ -477,20 +476,11 @@ static int queue_userspace_packets(struct datapath *dp, u32 pid,
err = genlmsg_unicast(&init_net, user_skb, pid); err = genlmsg_unicast(&init_net, user_skb, pid);
if (err) if (err)
goto err_kfree_skbs;
consume_skb(skb);
skb = nskb;
} while (skb);
return 0;
err_kfree_skbs:
kfree_skb(skb);
while ((skb = nskb) != NULL) {
nskb = skb->next;
kfree_skb(skb);
}
return err; return err;
} while ((skb = skb->next));
return 0;
} }
/* Called with genl_mutex. */ /* Called with genl_mutex. */