The current implementation does many copies of the sk_buff for increasing headroom which are not necessary.
This patch increases the headroom in the maclayer for a worst case scenario of (sizeof(struct ipv6hdr) + sizeof(struct udphdr)). Signed-off-by: Alexander Aring <alex.ar...@gmail.com> --- net/ieee802154/6lowpan.c | 86 +++++++++--------------------------------------- net/mac802154/wpan.c | 4 ++- 2 files changed, 19 insertions(+), 71 deletions(-) diff --git a/net/ieee802154/6lowpan.c b/net/ieee802154/6lowpan.c index 6a4efad..9c077a4 100644 --- a/net/ieee802154/6lowpan.c +++ b/net/ieee802154/6lowpan.c @@ -706,21 +706,15 @@ static int lowpan_header_create(struct sk_buff *skb, static int lowpan_give_skb_to_devices(struct sk_buff *skb) { struct lowpan_dev_record *entry; - struct sk_buff *skb_cp; int stat = NET_RX_SUCCESS; rcu_read_lock(); - list_for_each_entry_rcu(entry, &lowpan_devices, list) + list_for_each_entry_rcu(entry, &lowpan_devices, list) { if (lowpan_dev_info(entry->ldev)->real_dev == skb->dev) { - skb_cp = skb_copy(skb, GFP_ATOMIC); - if (!skb_cp) { - stat = -ENOMEM; - break; - } - - skb_cp->dev = entry->ldev; - stat = netif_rx(skb_cp); + skb->dev = entry->ldev; + stat = netif_rx(skb); } + } rcu_read_unlock(); return stat; @@ -728,28 +722,15 @@ static int lowpan_give_skb_to_devices(struct sk_buff *skb) static int lowpan_skb_deliver(struct sk_buff *skb, struct ipv6hdr *hdr) { - struct sk_buff *new; - int stat = NET_RX_SUCCESS; + skb_push(skb, sizeof(struct ipv6hdr)); + skb_reset_network_header(skb); + skb_set_transport_header(skb, sizeof(struct ipv6hdr)); + skb_copy_to_linear_data(skb, hdr, sizeof(struct ipv6hdr)); - new = skb_copy_expand(skb, sizeof(struct ipv6hdr), skb_tailroom(skb), - GFP_ATOMIC); - kfree_skb(skb); + skb->protocol = htons(ETH_P_IPV6); + skb->pkt_type = PACKET_HOST; - if (!new) - return -ENOMEM; - - skb_push(new, sizeof(struct ipv6hdr)); - skb_reset_network_header(new); - skb_copy_to_linear_data(new, hdr, sizeof(struct ipv6hdr)); - - new->protocol = htons(ETH_P_IPV6); - new->pkt_type = PACKET_HOST; - - stat = lowpan_give_skb_to_devices(new); - - kfree_skb(new); - - return stat; + return lowpan_give_skb_to_devices(skb); } static void lowpan_fragment_timer_expired(unsigned long entry_addr) @@ -1044,23 +1025,9 @@ lowpan_process_data(struct sk_buff *skb) /* UDP data uncompression */ if (iphc0 & LOWPAN_IPHC_NH_C) { struct udphdr uh; - struct sk_buff *new; if (lowpan_uncompress_udp_header(skb, &uh)) goto drop; - /* - * replace the compressed UDP head by the uncompressed UDP - * header - */ - new = skb_copy_expand(skb, sizeof(struct udphdr), - skb_tailroom(skb), GFP_ATOMIC); - kfree_skb(skb); - - if (!new) - return -ENOMEM; - - skb = new; - skb_push(skb, sizeof(struct udphdr)); skb_reset_transport_header(skb); skb_copy_to_linear_data(skb, &uh, sizeof(struct udphdr)); @@ -1293,8 +1260,6 @@ static int lowpan_validate(struct nlattr *tb[], struct nlattr *data[]) static int lowpan_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt, struct net_device *orig_dev) { - struct sk_buff *local_skb; - if (!netif_running(dev)) goto drop; @@ -1303,37 +1268,18 @@ static int lowpan_rcv(struct sk_buff *skb, struct net_device *dev, /* check that it's our buffer */ if (skb->data[0] == LOWPAN_DISPATCH_IPV6) { - /* Copy the packet so that the IPv6 header is - * properly aligned. - */ - local_skb = skb_copy_expand(skb, NET_SKB_PAD - 1, - skb_tailroom(skb), GFP_ATOMIC); - if (!local_skb) - goto drop; - - local_skb->protocol = htons(ETH_P_IPV6); - local_skb->pkt_type = PACKET_HOST; - /* Pull off the 1-byte of 6lowpan header. */ - skb_pull(local_skb, 1); - skb_reset_network_header(local_skb); - skb_set_transport_header(local_skb, sizeof(struct ipv6hdr)); + skb_pull(skb, 1); + skb_reset_network_header(skb); + skb_set_transport_header(skb, sizeof(struct ipv6hdr)); - lowpan_give_skb_to_devices(local_skb); - - kfree_skb(local_skb); - kfree_skb(skb); + lowpan_give_skb_to_devices(skb); } else { switch (skb->data[0] & 0xe0) { case LOWPAN_DISPATCH_IPHC: /* ipv6 datagram */ case LOWPAN_DISPATCH_FRAG1: /* first fragment header */ case LOWPAN_DISPATCH_FRAGN: /* next fragments headers */ - local_skb = skb_clone(skb, GFP_ATOMIC); - if (!local_skb) - goto drop; - lowpan_process_data(local_skb); - - kfree_skb(skb); + lowpan_process_data(skb); break; default: break; diff --git a/net/mac802154/wpan.c b/net/mac802154/wpan.c index e24bcf9..b787887 100644 --- a/net/mac802154/wpan.c +++ b/net/mac802154/wpan.c @@ -32,6 +32,7 @@ #include <net/ieee802154_netdev.h> #include <net/ieee802154.h> #include <net/wpan-phy.h> +#include <net/ipv6.h> #include "mac802154.h" @@ -552,7 +553,8 @@ void mac802154_wpans_rx(struct mac802154_priv *priv, struct sk_buff *skb) if (sdata->type != IEEE802154_DEV_WPAN) continue; - sskb = skb_clone(skb, GFP_ATOMIC); + sskb = skb_realloc_headroom(skb, sizeof(struct ipv6hdr) + + sizeof(struct udphdr)); if (sskb) mac802154_subif_frame(sdata, sskb); } -- 1.8.4 ------------------------------------------------------------------------------ October Webinars: Code for Performance Free Intel webinars can help you accelerate application performance. Explore tips for MPI, OpenMP, advanced profiling, and more. Get the most from the latest Intel processors and coprocessors. See abstracts and register > http://pubads.g.doubleclick.net/gampad/clk?id=60134071&iu=/4140/ostg.clktrk _______________________________________________ Linux-zigbee-devel mailing list Linux-zigbee-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/linux-zigbee-devel