From: Jason A. Donenfeld
Date: Thu Nov 05 2015 - 20:32:56 EST

Hi folks,

I'm still facing some considerable problems. Please see below.

On Thu, Nov 5, 2015 at 5:28 PM, Jason A. Donenfeld <Jason@xxxxxxxxx> wrote:
> As mentioned, I receive packets on ndo_start_xmit, "do something to
> them with function magic()", and then push them out of a UDP socket
> using udp_tunnel_xmit_skb. There appears to be significant overhead
> from calling udp_tunnel_xmit_skb over and over. What I'd really like
> to do is pass the NETIF_F_GSO_SOFTWARE-provided super packet directly
> to udp_tunnel_xmit_skb, but in fact the magic() function mentioned
> above needs to work on an entire MTU-sized IP packet, not a a super
> packet. So, instead, what it's looking like is:
> 1. Set NETIF_F_GSO_SOFTWARE to receive super packets.
> 2. For each super packet, break it down using skb_gso_segment().
> 2a. For each segmented packet, "do my magic() function"
> 3. After having done the magic() to each of the segmented packets, I
> *repack the results* into a new super packet. I then pass that super
> packet to udp_tunnel_xmit_skb().
> Is this approach a real possibility?
> If so, it seems like the best way to get GSO-like qualities out of
> udp_tunnel_xmit_skb. I've successfully done (1) and (2), following the
> example of validate_xmit_skb() from net/core/dev.c. Now I need to
> figure out how to do (3). Hopefully I'll find some nice convenience
> functions for this...

So far implementing (3) is failing miserably. Is there anything wrong
with my general idea that might make this a priori impossible? For
example, will udp_tunnel_xmit_skb not accept super-packets? Or, am I
just not making use of whatever nice convenience functions are
available for constructing super-packets, and thus am doing something

Currently, I'm doing essentially what follows below. It seems like it
ought to be working, but it's not.

gso_segs = DIV_ROUND_UP(skb->len, skb_shinfo(skb)->gso_size);
segs = skb_gso_segment(skb, 0);
if (IS_ERR(segs)) {
return PTR_ERR(segs);

gso_size = magic_len(segs->len);
len = gso_size * gso_segs;

outgoing = alloc_skb(len, GFP_ATOMIC);
if (!outgoing) {
return -ENOMEM;
skb_shinfo(outgoing)->gso_type = SKB_GSO_UDP;
skb_shinfo(outgoing)->gso_size = gso_size;
skb_shinfo(outgoing)->gso_segs = 0;
outgoing->ip_summed = CHECKSUM_PARTIAL;

src = segs;
while (src) {
next = src->next;
dst_buffer = skb_put(outgoing, magic_len(src->len));
ret = do_magic(dst_buffer, src);
if (ret) {
return ret;
src = next;
return eventually_udp_tunnel_xmit_skb(outgoing);

Let me know if there is something fundamentally wrong with this
approach. Or if you have any other pointers...

To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at
Please read the FAQ at