Originally the erspan fields are defined as a group into a __be16 field,
and use mask and offset to access each field.  This is more costly due to
calling ntohs/htons.  The patch changes it to use bitfields.

Signed-off-by: William Tu <u9012...@gmail.com>
---
 include/net/erspan.h | 127 ++++++++++++++++++++++++++++++++++++++-------------
 net/ipv4/ip_gre.c    |  38 ++++++---------
 net/ipv6/ip6_gre.c   |  36 ++++++---------
 3 files changed, 121 insertions(+), 80 deletions(-)

diff --git a/include/net/erspan.h b/include/net/erspan.h
index acdf6843095d..2b75821e2ebe 100644
--- a/include/net/erspan.h
+++ b/include/net/erspan.h
@@ -65,16 +65,30 @@
 #define GRA_MASK       0x0006
 #define O_MASK         0x0001
 
+#define HWID_OFFSET    4
+#define DIR_OFFSET     3
+
 /* ERSPAN version 2 metadata header */
 struct erspan_md2 {
        __be32 timestamp;
        __be16 sgt;     /* security group tag */
-       __be16 flags;
-#define P_OFFSET       15
-#define FT_OFFSET      10
-#define HWID_OFFSET    4
-#define DIR_OFFSET     3
-#define GRA_OFFSET     1
+#if defined(__LITTLE_ENDIAN_BITFIELD)
+       __u8    hwid_upper:2,
+               ft:5,
+               p:1;
+       __u8    o:1,
+               gra:2,
+               dir:1,
+               hwid:4;
+#elif defined(__BIG_ENDIAN_BITFIELD)
+       __u8    p:1,
+               ft:5,
+               hwid_upper:2;
+       __u8    hwid:4,
+               dir:1,
+               gra:2,
+               o:1;
+#endif
 };
 
 enum erspan_encap_type {
@@ -95,15 +109,62 @@ struct erspan_metadata {
 };
 
 struct erspan_base_hdr {
-       __be16 ver_vlan;
-#define VER_OFFSET  12
-       __be16 session_id;
-#define COS_OFFSET  13
-#define EN_OFFSET   11
-#define BSO_OFFSET  EN_OFFSET
-#define T_OFFSET    10
+#if defined(__LITTLE_ENDIAN_BITFIELD)
+       __u8    vlan_upper:4,
+               ver:4;
+       __u8    vlan:8;
+       __u8    session_id_upper:2,
+               t:1,
+               en:2,
+               cos:3;
+       __u8    session_id:8;
+#elif defined(__BIG_ENDIAN_BITFIELD)
+       __u8    ver: 4,
+               vlan_upper:4;
+       __u8    vlan:8;
+       __u8    cos:3,
+               en:2,
+               t:1,
+               session_id_upper:2;
+       __u8    session_id:8;
+#else
+#error "Please fix <asm/byteorder.h>"
+#endif
 };
 
+static inline void set_session_id(struct erspan_base_hdr *ershdr, u16 id)
+{
+       ershdr->session_id = id & 0xff;
+       ershdr->session_id_upper = (id >> 8) & 0x3;
+}
+
+static inline u16 get_session_id(const struct erspan_base_hdr *ershdr)
+{
+       return (ershdr->session_id_upper << 8) + ershdr->session_id;
+}
+
+static inline void set_vlan(struct erspan_base_hdr *ershdr, u16 vlan)
+{
+       ershdr->vlan = vlan & 0xff;
+       ershdr->vlan_upper = (vlan >> 8) & 0xf;
+}
+
+static inline u16 get_vlan(const struct erspan_base_hdr *ershdr)
+{
+       return (ershdr->vlan_upper << 8) + ershdr->vlan;
+}
+
+static inline void set_hwid(struct erspan_md2 *md2, u8 hwid)
+{
+       md2->hwid = hwid & 0xf;
+       md2->hwid_upper = (hwid >> 4) & 0x3;
+}
+
+static inline u8 get_hwid(const struct erspan_md2 *md2)
+{
+       return (md2->hwid_upper << 4) + md2->hwid;
+}
+
 static inline int erspan_hdr_len(int version)
 {
        return sizeof(struct erspan_base_hdr) +
@@ -120,7 +181,7 @@ static inline u8 tos_to_cos(u8 tos)
 }
 
 static inline void erspan_build_header(struct sk_buff *skb,
-                               __be32 id, u32 index,
+                               u32 id, u32 index,
                                bool truncate, bool is_ipv4)
 {
        struct ethhdr *eth = eth_hdr(skb);
@@ -154,12 +215,12 @@ static inline void erspan_build_header(struct sk_buff 
*skb,
        memset(ershdr, 0, sizeof(*ershdr) + ERSPAN_V1_MDSIZE);
 
        /* Build base header */
-       ershdr->ver_vlan = htons((vlan_tci & VLAN_MASK) |
-                                (ERSPAN_VERSION << VER_OFFSET));
-       ershdr->session_id = htons((u16)(ntohl(id) & ID_MASK) |
-                          ((tos_to_cos(tos) << COS_OFFSET) & COS_MASK) |
-                          (enc_type << EN_OFFSET & EN_MASK) |
-                          ((truncate << T_OFFSET) & T_MASK));
+       ershdr->ver = ERSPAN_VERSION;
+       ershdr->cos = tos_to_cos(tos);
+       ershdr->en = enc_type;
+       ershdr->t = truncate;
+       set_vlan(ershdr, vlan_tci);
+       set_session_id(ershdr, id);
 
        /* Build metadata */
        ersmd = (struct erspan_metadata *)(ershdr + 1);
@@ -187,7 +248,7 @@ static inline __be32 erspan_get_timestamp(void)
 }
 
 static inline void erspan_build_header_v2(struct sk_buff *skb,
-                                         __be32 id, u8 direction, u16 hwid,
+                                         u32 id, u8 direction, u16 hwid,
                                          bool truncate, bool is_ipv4)
 {
        struct ethhdr *eth = eth_hdr(skb);
@@ -198,7 +259,6 @@ static inline void erspan_build_header_v2(struct sk_buff 
*skb,
                __be16 tci;
        } *qp;
        u16 vlan_tci = 0;
-       u16 session_id;
        u8 gra = 0; /* 100 usec */
        u8 bso = 0; /* Bad/Short/Oversized */
        u8 sgt = 0;
@@ -221,22 +281,23 @@ static inline void erspan_build_header_v2(struct sk_buff 
*skb,
        memset(ershdr, 0, sizeof(*ershdr) + ERSPAN_V2_MDSIZE);
 
        /* Build base header */
-       ershdr->ver_vlan = htons((vlan_tci & VLAN_MASK) |
-                                (ERSPAN_VERSION2 << VER_OFFSET));
-       session_id = (u16)(ntohl(id) & ID_MASK) |
-                    ((tos_to_cos(tos) << COS_OFFSET) & COS_MASK) |
-                    (bso << BSO_OFFSET & BSO_MASK) |
-                    ((truncate << T_OFFSET) & T_MASK);
-       ershdr->session_id = htons(session_id);
+       ershdr->ver = ERSPAN_VERSION2;
+       ershdr->cos = tos_to_cos(tos);
+       ershdr->en = bso;
+       ershdr->t = truncate;
+       set_vlan(ershdr, vlan_tci);
+       set_session_id(ershdr, id);
 
        /* Build metadata */
        md = (struct erspan_metadata *)(ershdr + 1);
        md->u.md2.timestamp = erspan_get_timestamp();
        md->u.md2.sgt = htons(sgt);
-       md->u.md2.flags = htons(((1 << P_OFFSET) & P_MASK) |
-                               ((hwid << HWID_OFFSET) & HWID_MASK) |
-                               ((direction << DIR_OFFSET) & DIR_MASK) |
-                               ((gra << GRA_OFFSET) & GRA_MASK));
+       md->u.md2.p = 1;
+       md->u.md2.ft = 0;
+       md->u.md2.dir = direction;
+       md->u.md2.gra = gra;
+       md->u.md2.o = 0;
+       set_hwid(&md->u.md2, hwid);
 }
 
 #endif
diff --git a/net/ipv4/ip_gre.c b/net/ipv4/ip_gre.c
index b61f2285816d..6ec670fbbbdd 100644
--- a/net/ipv4/ip_gre.c
+++ b/net/ipv4/ip_gre.c
@@ -114,7 +114,7 @@ MODULE_PARM_DESC(log_ecn_error, "Log packets received with 
corrupted ECN");
 static struct rtnl_link_ops ipgre_link_ops __read_mostly;
 static int ipgre_tunnel_init(struct net_device *dev);
 static void erspan_build_header(struct sk_buff *skb,
-                               __be32 id, u32 index,
+                               u32 id, u32 index,
                                bool truncate, bool is_ipv4);
 
 static unsigned int ipgre_net_id __read_mostly;
@@ -273,12 +273,12 @@ static int erspan_rcv(struct sk_buff *skb, struct 
tnl_ptk_info *tpi,
 
        iph = ip_hdr(skb);
        ershdr = (struct erspan_base_hdr *)(skb->data + gre_hdr_len);
-       ver = (ntohs(ershdr->ver_vlan) & VER_MASK) >> VER_OFFSET;
+       ver = ershdr->ver;
 
        /* The original GRE header does not have key field,
         * Use ERSPAN 10-bit session ID as key.
         */
-       tpi->key = cpu_to_be32(ntohs(ershdr->session_id) & ID_MASK);
+       tpi->key = cpu_to_be32(get_session_id(ershdr));
        tunnel = ip_tunnel_lookup(itn, skb->dev->ifindex,
                                  tpi->flags | TUNNEL_KEY,
                                  iph->saddr, iph->daddr, tpi->key);
@@ -324,14 +324,8 @@ static int erspan_rcv(struct sk_buff *skb, struct 
tnl_ptk_info *tpi,
                        if (ver == 1) {
                                tunnel->index = ntohl(pkt_md->u.index);
                        } else {
-                               u16 md2_flags;
-                               u16 dir, hwid;
-
-                               md2_flags = ntohs(pkt_md->u.md2.flags);
-                               dir = (md2_flags & DIR_MASK) >> DIR_OFFSET;
-                               hwid = (md2_flags & HWID_MASK) >> HWID_OFFSET;
-                               tunnel->dir = dir;
-                               tunnel->hwid = hwid;
+                               tunnel->dir = pkt_md->u.md2.dir;
+                               tunnel->hwid = get_hwid(&pkt_md->u.md2);
                        }
 
                }
@@ -615,19 +609,14 @@ static void erspan_fb_xmit(struct sk_buff *skb, struct 
net_device *dev,
        }
 
        if (version == 1) {
-               erspan_build_header(skb, tunnel_id_to_key32(key->tun_id),
+               erspan_build_header(skb, ntohl(tunnel_id_to_key32(key->tun_id)),
                                    ntohl(md->u.index), truncate, true);
        } else if (version == 2) {
-               u16 md2_flags;
-               u8 direction;
-               u16 hwid;
-
-               md2_flags = ntohs(md->u.md2.flags);
-               direction = (md2_flags & DIR_MASK) >> DIR_OFFSET;
-               hwid = (md2_flags & HWID_MASK) >> HWID_OFFSET;
-
-               erspan_build_header_v2(skb, tunnel_id_to_key32(key->tun_id),
-                                      direction, hwid, truncate, true);
+               erspan_build_header_v2(skb,
+                                      ntohl(tunnel_id_to_key32(key->tun_id)),
+                                      md->u.md2.dir,
+                                      get_hwid(&md->u.md2),
+                                      truncate, true);
        } else {
                goto err_free_rt;
        }
@@ -733,10 +722,11 @@ static netdev_tx_t erspan_xmit(struct sk_buff *skb,
 
        /* Push ERSPAN header */
        if (tunnel->erspan_ver == 1)
-               erspan_build_header(skb, tunnel->parms.o_key, tunnel->index,
+               erspan_build_header(skb, ntohl(tunnel->parms.o_key),
+                                   tunnel->index,
                                    truncate, true);
        else
-               erspan_build_header_v2(skb, tunnel->parms.o_key,
+               erspan_build_header_v2(skb, ntohl(tunnel->parms.o_key),
                                       tunnel->dir, tunnel->hwid,
                                       truncate, true);
 
diff --git a/net/ipv6/ip6_gre.c b/net/ipv6/ip6_gre.c
index db99446e0276..9f35087f93bc 100644
--- a/net/ipv6/ip6_gre.c
+++ b/net/ipv6/ip6_gre.c
@@ -512,8 +512,8 @@ static int ip6erspan_rcv(struct sk_buff *skb, int 
gre_hdr_len,
 
        ipv6h = ipv6_hdr(skb);
        ershdr = (struct erspan_base_hdr *)skb->data;
-       ver = (ntohs(ershdr->ver_vlan) & VER_MASK) >> VER_OFFSET;
-       tpi->key = cpu_to_be32(ntohs(ershdr->session_id) & ID_MASK);
+       ver = ershdr->ver;
+       tpi->key = cpu_to_be32(get_session_id(ershdr));
 
        tunnel = ip6gre_tunnel_lookup(skb->dev,
                                      &ipv6h->saddr, &ipv6h->daddr, tpi->key,
@@ -564,14 +564,8 @@ static int ip6erspan_rcv(struct sk_buff *skb, int 
gre_hdr_len,
                        if (ver == 1) {
                                tunnel->parms.index = ntohl(pkt_md->u.index);
                        } else {
-                               u16 md2_flags;
-                               u16 dir, hwid;
-
-                               md2_flags = ntohs(pkt_md->u.md2.flags);
-                               dir = (md2_flags & DIR_MASK) >> DIR_OFFSET;
-                               hwid = (md2_flags & HWID_MASK) >> HWID_OFFSET;
-                               tunnel->parms.dir = dir;
-                               tunnel->parms.hwid = hwid;
+                               tunnel->parms.dir = pkt_md->u.md2.dir;
+                               tunnel->parms.hwid = get_hwid(&pkt_md->u.md2);
                        }
 
                        ip6_tnl_rcv(tunnel, skb, tpi, NULL, log_ecn_error);
@@ -924,6 +918,7 @@ static netdev_tx_t ip6erspan_tunnel_xmit(struct sk_buff 
*skb,
                struct ip_tunnel_info *tun_info;
                const struct ip_tunnel_key *key;
                struct erspan_metadata *md;
+               __be32 tun_id;
 
                tun_info = skb_tunnel_info(skb);
                if (unlikely(!tun_info ||
@@ -943,23 +938,18 @@ static netdev_tx_t ip6erspan_tunnel_xmit(struct sk_buff 
*skb,
                if (!md)
                        goto tx_err;
 
+               tun_id = tunnel_id_to_key32(key->tun_id);
                if (md->version == 1) {
                        erspan_build_header(skb,
-                                           tunnel_id_to_key32(key->tun_id),
+                                           ntohl(tun_id),
                                            ntohl(md->u.index), truncate,
                                            false);
                } else if (md->version == 2) {
-                       u16 md2_flags;
-                       u16 dir, hwid;
-
-                       md2_flags = ntohs(md->u.md2.flags);
-                       dir = (md2_flags & DIR_MASK) >> DIR_OFFSET;
-                       hwid = (md2_flags & HWID_MASK) >> HWID_OFFSET;
-
                        erspan_build_header_v2(skb,
-                                              tunnel_id_to_key32(key->tun_id),
-                                              dir, hwid, truncate,
-                                              false);
+                                              ntohl(tun_id),
+                                              md->u.md2.dir,
+                                              get_hwid(&md->u.md2),
+                                              truncate, false);
                }
        } else {
                switch (skb->protocol) {
@@ -981,11 +971,11 @@ static netdev_tx_t ip6erspan_tunnel_xmit(struct sk_buff 
*skb,
                }
 
                if (t->parms.erspan_ver == 1)
-                       erspan_build_header(skb, t->parms.o_key,
+                       erspan_build_header(skb, ntohl(t->parms.o_key),
                                            t->parms.index,
                                            truncate, false);
                else
-                       erspan_build_header_v2(skb, t->parms.o_key,
+                       erspan_build_header_v2(skb, ntohl(t->parms.o_key),
                                               t->parms.dir,
                                               t->parms.hwid,
                                               truncate, false);
-- 
2.7.4

Reply via email to