diff options
| author | Harout Hedeshian <harouth@codeaurora.org> | 2015-03-11 18:13:30 -0600 |
|---|---|---|
| committer | David Keitel <dkeitel@codeaurora.org> | 2016-03-22 11:05:32 -0700 |
| commit | 2a0b78fa70845aa0ff6a619bfaa23e5e1ce44d11 (patch) | |
| tree | 68998d5c73f4fe0732fac23b706219c2afbc0064 /net/rmnet_data/rmnet_map_data.c | |
| parent | 037cd9a5952c3637908374c894d036ec5d28ad9e (diff) | |
net: rmnet_data: use memcpy() during deaggration of MAP frames
Using skb_clone() to deaggregate frames results in multiple side effects.
First side effect is that skb->truesize will reflect the total
aggregation buffer size for each 1500-byte frame charged to a socket.
Hence, the socket thinks it is using more memory than it actually is
resulting in unnecessary packet drops.
Second side effect is that GRO will not work correctly since the cloned
SKBs share the same shinfo struct. GRO uses the gso_segs field here
and will get confused when the packets have bad values here.
The new algorithm removes skb_clone altogether. Instead a new empty
skb is allocated with alloc_skb() and a manual memcpy is performed to
move the data. This guarantees that there are no shared segments
between SKBs.
Change-Id: I1f1b69a22ed4726c31b8d3295622a604af95d008
Signed-off-by: Harout Hedeshian <harouth@codeaurora.org>
Diffstat (limited to 'net/rmnet_data/rmnet_map_data.c')
| -rw-r--r-- | net/rmnet_data/rmnet_map_data.c | 21 |
1 files changed, 12 insertions, 9 deletions
diff --git a/net/rmnet_data/rmnet_map_data.c b/net/rmnet_data/rmnet_map_data.c index 27e32c13fe39..f5e5ba3aa8ab 100644 --- a/net/rmnet_data/rmnet_map_data.c +++ b/net/rmnet_data/rmnet_map_data.c @@ -55,6 +55,8 @@ struct agg_work { struct rmnet_phys_ep_conf_s *config; }; +#define RMNET_MAP_DEAGGR_SPACING 64 +#define RMNET_MAP_DEAGGR_HEADROOM (RMNET_MAP_DEAGGR_SPACING/2) /******************************************************************************/ /** @@ -108,10 +110,10 @@ struct rmnet_map_header_s *rmnet_map_add_map_header(struct sk_buff *skb, * @skb: Source socket buffer containing multiple MAP frames * @config: Physical endpoint configuration of the ingress device * - * Source skb is cloned with skb_clone(). The new skb data and tail pointers are - * modified to contain a single MAP frame. Clone happens with GFP_ATOMIC flags - * set. User should keep calling deaggregate() on the source skb until 0 is - * returned, indicating that there are no more packets to deaggregate. + * A whole new buffer is allocated for each portion of an aggregated frame. + * Caller should keep calling deaggregate() on the source skb until 0 is + * returned, indicating that there are no more packets to deaggregate. Caller + * is responsible for freeing the original skb. * * Return: * - Pointer to new skb @@ -136,15 +138,16 @@ struct sk_buff *rmnet_map_deaggregate(struct sk_buff *skb, return 0; } - skbn = skb_clone(skb, GFP_ATOMIC); + skbn = alloc_skb(packet_len + RMNET_MAP_DEAGGR_SPACING, GFP_ATOMIC); if (!skbn) return 0; - LOGD("Trimming to %d bytes", packet_len); - LOGD("before skbn->len = %d", skbn->len); - skb_trim(skbn, packet_len); + skbn->dev = skb->dev; + skb_reserve(skbn, RMNET_MAP_DEAGGR_HEADROOM); + skb_put(skbn, packet_len); + memcpy(skbn->data, skb->data, packet_len); skb_pull(skb, packet_len); - LOGD("after skbn->len = %d", skbn->len); + /* Some hardware can send us empty frames. Catch them */ if (ntohs(maph->pkt_len) == 0) { |
