[ovs-dev] [PATCH] datapath: Orphan frags in skb_zerocopy and handle errors
Zoltan Kiss
zoltan.kiss at citrix.com
Wed Apr 9 16:21:34 UTC 2014
I don't know if Kyle posted this already, but I needed it anyway, so I
sent in my version.
Zoli
On 09/04/14 17:20, Zoltan Kiss wrote:
> This is the ported version of commit 36d5fe6a with the same name from net-next.
> Apart from the small datapath.c changes it adjust the compat layer files as
> well. This is the original commit message:
>
> "skb_zerocopy can copy elements of the frags array between skbs, but it doesn't
> orphan them. Also, it doesn't handle errors, so this patch takes care of that
> as well, and modify the callers accordingly. skb_tx_error() is also added to
> the callers so they will signal the failed delivery towards the creator of the
> skb."
>
> Signed-off-by: Zoltan Kiss <zoltan.kiss at citrix.com>
> ---
> diff --git a/datapath/datapath.c b/datapath/datapath.c
> index 25edd7d..5e5aa71 100644
> --- a/datapath/datapath.c
> +++ b/datapath/datapath.c
> @@ -485,7 +485,9 @@ static int queue_userspace_packet(struct datapath *dp, struct sk_buff *skb,
> }
> nla->nla_len = nla_attr_size(skb->len);
>
> - skb_zerocopy(user_skb, skb, skb->len, hlen);
> + err = skb_zerocopy(user_skb, skb, skb->len, hlen);
> + if (err)
> + goto out;
>
> /* Pad OVS_PACKET_ATTR_PACKET if linear copy was performed */
> if (!(dp->user_features & OVS_DP_F_UNALIGNED)) {
> @@ -499,6 +501,8 @@ static int queue_userspace_packet(struct datapath *dp, struct sk_buff *skb,
>
> err = genlmsg_unicast(ovs_dp_get_net(dp), user_skb, upcall_info->portid);
> out:
> + if (err)
> + skb_tx_error(skb);
> kfree_skb(nskb);
> return err;
> }
> diff --git a/datapath/linux/compat/include/linux/skbuff.h b/datapath/linux/compat/include/linux/skbuff.h
> index de0c56a..c709aca 100644
> --- a/datapath/linux/compat/include/linux/skbuff.h
> +++ b/datapath/linux/compat/include/linux/skbuff.h
> @@ -260,7 +260,7 @@ static inline __u32 skb_get_rxhash(struct sk_buff *skb)
>
> #if LINUX_VERSION_CODE < KERNEL_VERSION(3,14,0)
> unsigned int skb_zerocopy_headlen(const struct sk_buff *from);
> -void skb_zerocopy(struct sk_buff *to, const struct sk_buff *from, int len,
> +int skb_zerocopy(struct sk_buff *to, struct sk_buff *from, int len,
> int hlen);
> #endif
>
> diff --git a/datapath/linux/compat/skbuff-openvswitch.c b/datapath/linux/compat/skbuff-openvswitch.c
> index ddd7bc8..96c27d0 100644
> --- a/datapath/linux/compat/skbuff-openvswitch.c
> +++ b/datapath/linux/compat/skbuff-openvswitch.c
> @@ -61,25 +61,31 @@ skb_zerocopy_headlen(const struct sk_buff *from)
> *
> * The `hlen` as calculated by skb_zerocopy_headlen() specifies the
> * headroom in the `to` buffer.
> + *
> + * Return value:
> + * 0: everything is OK
> + * -ENOMEM: couldn't orphan frags of @from due to lack of memory
> + * -EFAULT: skb_copy_bits() found some problem with skb geometry
> */
> -void
> -skb_zerocopy(struct sk_buff *to, const struct sk_buff *from, int len, int hlen)
> +int
> +skb_zerocopy(struct sk_buff *to, struct sk_buff *from, int len, int hlen)
> {
> int i, j = 0;
> int plen = 0; /* length of skb->head fragment */
> + int ret;
> struct page *page;
> unsigned int offset;
>
> BUG_ON(!head_frag(from) && !hlen);
>
> /* dont bother with small payloads */
> - if (len <= skb_tailroom(to)) {
> - skb_copy_bits(from, 0, skb_put(to, len), len);
> - return;
> - }
> + if (len <= skb_tailroom(to))
> + return skb_copy_bits(from, 0, skb_put(to, len), len);
>
> if (hlen) {
> - skb_copy_bits(from, 0, skb_put(to, hlen), hlen);
> + ret = skb_copy_bits(from, 0, skb_put(to, hlen), hlen);
> + if (unlikely(ret))
> + return ret;
> len -= hlen;
> } else {
> plen = min_t(int, skb_headlen(from), len);
> @@ -97,6 +103,11 @@ skb_zerocopy(struct sk_buff *to, const struct sk_buff *from, int len, int hlen)
> to->len += len + plen;
> to->data_len += len + plen;
>
> + if (unlikely(skb_orphan_frags(from, GFP_ATOMIC))) {
> + skb_tx_error(from);
> + return -ENOMEM;
> + }
> +
> for (i = 0; i < skb_shinfo(from)->nr_frags; i++) {
> if (!len)
> break;
> @@ -107,5 +118,7 @@ skb_zerocopy(struct sk_buff *to, const struct sk_buff *from, int len, int hlen)
> j++;
> }
> skb_shinfo(to)->nr_frags = j;
> +
> + return 0;
> }
> #endif
>
More information about the dev
mailing list