[SK_BUFF]: Use offsets for skb->{mac,network,transport}_header on 64bit architectures
authorArnaldo Carvalho de Melo <acme@redhat.com>
Wed, 11 Apr 2007 04:22:35 +0000 (21:22 -0700)
committerDavid S. Miller <davem@sunset.davemloft.net>
Thu, 26 Apr 2007 05:26:21 +0000 (22:26 -0700)
With this we save 8 bytes per network packet, leaving a 4 bytes hole to be used
in further shrinking work, likely with the offsetization of other pointers,
such as ->{data,tail,end}, at the cost of adds, that were minimized by the
usual practice of setting skb->{mac,nh,n}.raw to a local variable that is then
accessed multiple times in each function, it also is not more expensive than
before with regards to most of the handling of such headers, like setting one
of these headers to another (transport to network, etc), or subtracting, adding
to/from it, comparing them, etc.

Now we have this layout for sk_buff on a x86_64 machine:

[acme@mica net-2.6.22]$ pahole vmlinux sk_buff
struct sk_buff {
struct sk_buff *       next;             /*   0   8 */
struct sk_buff *       prev;             /*   8   8 */
struct rb_node         rb;               /*  16  24 */
struct sock *          sk;               /*  40   8 */
ktime_t                tstamp;           /*  48   8 */
struct net_device *    dev;              /*  56   8 */
/* --- cacheline 1 boundary (64 bytes) --- */
struct net_device *    input_dev;        /*  64   8 */
sk_buff_data_t         transport_header; /*  72   4 */
sk_buff_data_t         network_header;   /*  76   4 */
sk_buff_data_t         mac_header;       /*  80   4 */

/* XXX 4 bytes hole, try to pack */

struct dst_entry *     dst;              /*  88   8 */
struct sec_path *      sp;               /*  96   8 */
char                   cb[48];           /* 104  48 */
/* cacheline 2 boundary (128 bytes) was 24 bytes ago*/
unsigned int           len;              /* 152   4 */
unsigned int           data_len;         /* 156   4 */
unsigned int           mac_len;          /* 160   4 */
union {
__wsum         csum;             /*       4 */
__u32          csum_offset;      /*       4 */
};                                       /* 164   4 */
__u32                  priority;         /* 168   4 */
__u8                   local_df:1;       /* 172   1 */
__u8                   cloned:1;         /* 172   1 */
__u8                   ip_summed:2;      /* 172   1 */
__u8                   nohdr:1;          /* 172   1 */
__u8                   nfctinfo:3;       /* 172   1 */
__u8                   pkt_type:3;       /* 173   1 */
__u8                   fclone:2;         /* 173   1 */
__u8                   ipvs_property:1;  /* 173   1 */

/* XXX 2 bits hole, try to pack */

__be16                 protocol;         /* 174   2 */
void    (*destructor)(struct sk_buff *); /* 176   8 */
struct nf_conntrack *  nfct;             /* 184   8 */
/* --- cacheline 3 boundary (192 bytes) --- */
struct sk_buff *       nfct_reasm;       /* 192   8 */
struct nf_bridge_info *nf_bridge;        /* 200   8 */
__u16                  tc_index;         /* 208   2 */
__u16                  tc_verd;          /* 210   2 */
dma_cookie_t           dma_cookie;       /* 212   4 */
__u32                  secmark;          /* 216   4 */
__u32                  mark;             /* 220   4 */
unsigned int           truesize;         /* 224   4 */
atomic_t               users;            /* 228   4 */
unsigned char *        head;             /* 232   8 */
unsigned char *        data;             /* 240   8 */
unsigned char *        tail;             /* 248   8 */
/* --- cacheline 4 boundary (256 bytes) --- */
unsigned char *        end;              /* 256   8 */
}; /* size: 264, cachelines: 5 */
   /* sum members: 260, holes: 1, sum holes: 4 */
   /* bit holes: 1, sum bit holes: 2 bits */
   /* last cacheline: 8 bytes */

On 32 bits nothing changes, and pointers continue to be used with the compiler
turning all this abstraction layer into dust. But there are some sk_buff
validation tricks that are now possible, humm... :-)

Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
include/linux/skbuff.h
net/core/skbuff.c
net/ipv4/ipvs/ip_vs_xmit.c
net/sctp/input.c
net/sctp/ipv6.c

index c45ad126327195ced36f516652cca2ba83120423..2e740550062615f559387c122518f943f07899b6 100644 (file)
@@ -179,6 +179,16 @@ enum {
        SKB_GSO_TCPV6 = 1 << 4,
 };
 
+#if BITS_PER_LONG > 32
+#define NET_SKBUFF_DATA_USES_OFFSET 1
+#endif
+
+#ifdef NET_SKBUFF_DATA_USES_OFFSET
+typedef unsigned int sk_buff_data_t;
+#else
+typedef unsigned char *sk_buff_data_t;
+#endif
+
 /** 
  *     struct sk_buff - socket buffer
  *     @next: Next buffer in list
@@ -236,9 +246,9 @@ struct sk_buff {
        int                     iif;
        /* 4 byte hole on 64 bit*/
 
-       unsigned char           *transport_header;
-       unsigned char           *network_header;
-       unsigned char           *mac_header;
+       sk_buff_data_t          transport_header;
+       sk_buff_data_t          network_header;
+       sk_buff_data_t          mac_header;
        struct  dst_entry       *dst;
        struct  sec_path        *sp;
 
@@ -942,50 +952,92 @@ static inline void skb_reserve(struct sk_buff *skb, int len)
        skb->tail += len;
 }
 
+#ifdef NET_SKBUFF_DATA_USES_OFFSET
 static inline unsigned char *skb_transport_header(const struct sk_buff *skb)
 {
-       return skb->transport_header;
+       return skb->head + skb->transport_header;
 }
 
 static inline void skb_reset_transport_header(struct sk_buff *skb)
 {
-       skb->transport_header = skb->data;
+       skb->transport_header = skb->data - skb->head;
 }
 
 static inline void skb_set_transport_header(struct sk_buff *skb,
                                            const int offset)
 {
-       skb->transport_header = skb->data + offset;
-}
-
-static inline int skb_transport_offset(const struct sk_buff *skb)
-{
-       return skb->transport_header - skb->data;
+       skb_reset_transport_header(skb);
+       skb->transport_header += offset;
 }
 
 static inline unsigned char *skb_network_header(const struct sk_buff *skb)
 {
-       return skb->network_header;
+       return skb->head + skb->network_header;
 }
 
 static inline void skb_reset_network_header(struct sk_buff *skb)
 {
-       skb->network_header = skb->data;
+       skb->network_header = skb->data - skb->head;
 }
 
 static inline void skb_set_network_header(struct sk_buff *skb, const int offset)
 {
-       skb->network_header = skb->data + offset;
+       skb_reset_network_header(skb);
+       skb->network_header += offset;
 }
 
-static inline int skb_network_offset(const struct sk_buff *skb)
+static inline unsigned char *skb_mac_header(const struct sk_buff *skb)
 {
-       return skb->network_header - skb->data;
+       return skb->head + skb->mac_header;
 }
 
-static inline u32 skb_network_header_len(const struct sk_buff *skb)
+static inline int skb_mac_header_was_set(const struct sk_buff *skb)
 {
-       return skb->transport_header - skb->network_header;
+       return skb->mac_header != ~0U;
+}
+
+static inline void skb_reset_mac_header(struct sk_buff *skb)
+{
+       skb->mac_header = skb->data - skb->head;
+}
+
+static inline void skb_set_mac_header(struct sk_buff *skb, const int offset)
+{
+       skb_reset_mac_header(skb);
+       skb->mac_header += offset;
+}
+
+#else /* NET_SKBUFF_DATA_USES_OFFSET */
+
+static inline unsigned char *skb_transport_header(const struct sk_buff *skb)
+{
+       return skb->transport_header;
+}
+
+static inline void skb_reset_transport_header(struct sk_buff *skb)
+{
+       skb->transport_header = skb->data;
+}
+
+static inline void skb_set_transport_header(struct sk_buff *skb,
+                                           const int offset)
+{
+       skb->transport_header = skb->data + offset;
+}
+
+static inline unsigned char *skb_network_header(const struct sk_buff *skb)
+{
+       return skb->network_header;
+}
+
+static inline void skb_reset_network_header(struct sk_buff *skb)
+{
+       skb->network_header = skb->data;
+}
+
+static inline void skb_set_network_header(struct sk_buff *skb, const int offset)
+{
+       skb->network_header = skb->data + offset;
 }
 
 static inline unsigned char *skb_mac_header(const struct sk_buff *skb)
@@ -1007,6 +1059,22 @@ static inline void skb_set_mac_header(struct sk_buff *skb, const int offset)
 {
        skb->mac_header = skb->data + offset;
 }
+#endif /* NET_SKBUFF_DATA_USES_OFFSET */
+
+static inline int skb_transport_offset(const struct sk_buff *skb)
+{
+       return skb_transport_header(skb) - skb->data;
+}
+
+static inline u32 skb_network_header_len(const struct sk_buff *skb)
+{
+       return skb->transport_header - skb->network_header;
+}
+
+static inline int skb_network_offset(const struct sk_buff *skb)
+{
+       return skb_network_header(skb) - skb->data;
+}
 
 /*
  * CPUs often take a performance hit when accessing unaligned memory
index 1e71764be4a44bbaf858f40ab31ee198b668db51..a48b086812615cb2534231e52717c4fe560e4e6c 100644 (file)
@@ -448,11 +448,12 @@ struct sk_buff *skb_clone(struct sk_buff *skb, gfp_t gfp_mask)
 
 static void copy_skb_header(struct sk_buff *new, const struct sk_buff *old)
 {
+#ifndef NET_SKBUFF_DATA_USES_OFFSET
        /*
         *      Shift between the two data areas in bytes
         */
        unsigned long offset = new->data - old->data;
-
+#endif
        new->sk         = NULL;
        new->dev        = old->dev;
        new->priority   = old->priority;
@@ -461,9 +462,15 @@ static void copy_skb_header(struct sk_buff *new, const struct sk_buff *old)
 #ifdef CONFIG_INET
        new->sp         = secpath_get(old->sp);
 #endif
-       new->transport_header = old->transport_header + offset;
-       new->network_header   = old->network_header + offset;
-       new->mac_header       = old->mac_header + offset;
+       new->transport_header = old->transport_header;
+       new->network_header   = old->network_header;
+       new->mac_header       = old->mac_header;
+#ifndef NET_SKBUFF_DATA_USES_OFFSET
+       /* {transport,network,mac}_header are relative to skb->head */
+       new->transport_header += offset;
+       new->network_header   += offset;
+       new->mac_header       += offset;
+#endif
        memcpy(new->cb, old->cb, sizeof(old->cb));
        new->local_df   = old->local_df;
        new->fclone     = SKB_FCLONE_UNAVAILABLE;
@@ -639,9 +646,12 @@ int pskb_expand_head(struct sk_buff *skb, int nhead, int ntail,
        skb->end      = data + size;
        skb->data    += off;
        skb->tail    += off;
+#ifndef NET_SKBUFF_DATA_USES_OFFSET
+       /* {transport,network,mac}_header are relative to skb->head */
        skb->transport_header += off;
        skb->network_header   += off;
        skb->mac_header       += off;
+#endif
        skb->cloned   = 0;
        skb->nohdr    = 0;
        atomic_set(&skb_shinfo(skb)->dataref, 1);
index fded9b2f227cf704a456a15aefb1abe4ef2fcdf3..900ce29db38276a649661702b81d2711bd7891e4 100644 (file)
@@ -323,7 +323,7 @@ ip_vs_tunnel_xmit(struct sk_buff *skb, struct ip_vs_conn *cp,
        struct iphdr  *old_iph = ip_hdr(skb);
        u8     tos = old_iph->tos;
        __be16 df = old_iph->frag_off;
-       unsigned char *old_transport_header = skb->transport_header;
+       sk_buff_data_t old_transport_header = skb->transport_header;
        struct iphdr  *iph;                     /* Our new IP header */
        int    max_headroom;                    /* The extra header space needed */
        int    mtu;
index 87feee166da92d37a19fccd4365bbacca4362bc4..1ff47b18724a3e81f2ba9eb5b8aa95b0538e50dd 100644 (file)
@@ -513,7 +513,7 @@ void sctp_v4_err(struct sk_buff *skb, __u32 info)
        struct sctp_association *asoc = NULL;
        struct sctp_transport *transport;
        struct inet_sock *inet;
-       char *saveip, *savesctp;
+       sk_buff_data_t saveip, savesctp;
        int err;
 
        if (skb->len < ihlen + 8) {
@@ -527,7 +527,7 @@ void sctp_v4_err(struct sk_buff *skb, __u32 info)
        skb_reset_network_header(skb);
        skb_set_transport_header(skb, ihlen);
        sk = sctp_err_lookup(AF_INET, skb, sctp_hdr(skb), &asoc, &transport);
-       /* Put back, the original pointers. */
+       /* Put back, the original values. */
        skb->network_header = saveip;
        skb->transport_header = savesctp;
        if (!sk) {
index afcb0093c2901e0644f91a77ce0adb0f44956d61..5b0cdda4b44989ae74382174c5e8d9594f778c93 100644 (file)
@@ -126,7 +126,7 @@ SCTP_STATIC void sctp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
        struct sctp_association *asoc;
        struct sctp_transport *transport;
        struct ipv6_pinfo *np;
-       char *saveip, *savesctp;
+       sk_buff_data_t saveip, savesctp;
        int err;
 
        idev = in6_dev_get(skb->dev);