Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

net: erspan: use bitfield instead of mask and offset

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 <u9012063@gmail.com>
Acked-by: Pravin B Shelar <pshelar@ovn.org>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

William Tu and committed by
David S. Miller
c69de58b b89d06ce

+121 -80
+94 -33
include/net/erspan.h
··· 65 65 #define GRA_MASK 0x0006 66 66 #define O_MASK 0x0001 67 67 68 + #define HWID_OFFSET 4 69 + #define DIR_OFFSET 3 70 + 68 71 /* ERSPAN version 2 metadata header */ 69 72 struct erspan_md2 { 70 73 __be32 timestamp; 71 74 __be16 sgt; /* security group tag */ 72 - __be16 flags; 73 - #define P_OFFSET 15 74 - #define FT_OFFSET 10 75 - #define HWID_OFFSET 4 76 - #define DIR_OFFSET 3 77 - #define GRA_OFFSET 1 75 + #if defined(__LITTLE_ENDIAN_BITFIELD) 76 + __u8 hwid_upper:2, 77 + ft:5, 78 + p:1; 79 + __u8 o:1, 80 + gra:2, 81 + dir:1, 82 + hwid:4; 83 + #elif defined(__BIG_ENDIAN_BITFIELD) 84 + __u8 p:1, 85 + ft:5, 86 + hwid_upper:2; 87 + __u8 hwid:4, 88 + dir:1, 89 + gra:2, 90 + o:1; 91 + #endif 78 92 }; 79 93 80 94 enum erspan_encap_type { ··· 109 95 }; 110 96 111 97 struct erspan_base_hdr { 112 - __be16 ver_vlan; 113 - #define VER_OFFSET 12 114 - __be16 session_id; 115 - #define COS_OFFSET 13 116 - #define EN_OFFSET 11 117 - #define BSO_OFFSET EN_OFFSET 118 - #define T_OFFSET 10 98 + #if defined(__LITTLE_ENDIAN_BITFIELD) 99 + __u8 vlan_upper:4, 100 + ver:4; 101 + __u8 vlan:8; 102 + __u8 session_id_upper:2, 103 + t:1, 104 + en:2, 105 + cos:3; 106 + __u8 session_id:8; 107 + #elif defined(__BIG_ENDIAN_BITFIELD) 108 + __u8 ver: 4, 109 + vlan_upper:4; 110 + __u8 vlan:8; 111 + __u8 cos:3, 112 + en:2, 113 + t:1, 114 + session_id_upper:2; 115 + __u8 session_id:8; 116 + #else 117 + #error "Please fix <asm/byteorder.h>" 118 + #endif 119 119 }; 120 + 121 + static inline void set_session_id(struct erspan_base_hdr *ershdr, u16 id) 122 + { 123 + ershdr->session_id = id & 0xff; 124 + ershdr->session_id_upper = (id >> 8) & 0x3; 125 + } 126 + 127 + static inline u16 get_session_id(const struct erspan_base_hdr *ershdr) 128 + { 129 + return (ershdr->session_id_upper << 8) + ershdr->session_id; 130 + } 131 + 132 + static inline void set_vlan(struct erspan_base_hdr *ershdr, u16 vlan) 133 + { 134 + ershdr->vlan = vlan & 0xff; 135 + ershdr->vlan_upper = (vlan >> 8) & 0xf; 136 + } 137 + 138 + static inline u16 get_vlan(const struct erspan_base_hdr *ershdr) 139 + { 140 + return (ershdr->vlan_upper << 8) + ershdr->vlan; 141 + } 142 + 143 + static inline void set_hwid(struct erspan_md2 *md2, u8 hwid) 144 + { 145 + md2->hwid = hwid & 0xf; 146 + md2->hwid_upper = (hwid >> 4) & 0x3; 147 + } 148 + 149 + static inline u8 get_hwid(const struct erspan_md2 *md2) 150 + { 151 + return (md2->hwid_upper << 4) + md2->hwid; 152 + } 120 153 121 154 static inline int erspan_hdr_len(int version) 122 155 { ··· 181 120 } 182 121 183 122 static inline void erspan_build_header(struct sk_buff *skb, 184 - __be32 id, u32 index, 123 + u32 id, u32 index, 185 124 bool truncate, bool is_ipv4) 186 125 { 187 126 struct ethhdr *eth = (struct ethhdr *)skb->data; ··· 215 154 memset(ershdr, 0, sizeof(*ershdr) + ERSPAN_V1_MDSIZE); 216 155 217 156 /* Build base header */ 218 - ershdr->ver_vlan = htons((vlan_tci & VLAN_MASK) | 219 - (ERSPAN_VERSION << VER_OFFSET)); 220 - ershdr->session_id = htons((u16)(ntohl(id) & ID_MASK) | 221 - ((tos_to_cos(tos) << COS_OFFSET) & COS_MASK) | 222 - (enc_type << EN_OFFSET & EN_MASK) | 223 - ((truncate << T_OFFSET) & T_MASK)); 157 + ershdr->ver = ERSPAN_VERSION; 158 + ershdr->cos = tos_to_cos(tos); 159 + ershdr->en = enc_type; 160 + ershdr->t = truncate; 161 + set_vlan(ershdr, vlan_tci); 162 + set_session_id(ershdr, id); 224 163 225 164 /* Build metadata */ 226 165 ersmd = (struct erspan_metadata *)(ershdr + 1); ··· 248 187 } 249 188 250 189 static inline void erspan_build_header_v2(struct sk_buff *skb, 251 - __be32 id, u8 direction, u16 hwid, 190 + u32 id, u8 direction, u16 hwid, 252 191 bool truncate, bool is_ipv4) 253 192 { 254 193 struct ethhdr *eth = (struct ethhdr *)skb->data; ··· 259 198 __be16 tci; 260 199 } *qp; 261 200 u16 vlan_tci = 0; 262 - u16 session_id; 263 201 u8 gra = 0; /* 100 usec */ 264 202 u8 bso = 0; /* Bad/Short/Oversized */ 265 203 u8 sgt = 0; ··· 281 221 memset(ershdr, 0, sizeof(*ershdr) + ERSPAN_V2_MDSIZE); 282 222 283 223 /* Build base header */ 284 - ershdr->ver_vlan = htons((vlan_tci & VLAN_MASK) | 285 - (ERSPAN_VERSION2 << VER_OFFSET)); 286 - session_id = (u16)(ntohl(id) & ID_MASK) | 287 - ((tos_to_cos(tos) << COS_OFFSET) & COS_MASK) | 288 - (bso << BSO_OFFSET & BSO_MASK) | 289 - ((truncate << T_OFFSET) & T_MASK); 290 - ershdr->session_id = htons(session_id); 224 + ershdr->ver = ERSPAN_VERSION2; 225 + ershdr->cos = tos_to_cos(tos); 226 + ershdr->en = bso; 227 + ershdr->t = truncate; 228 + set_vlan(ershdr, vlan_tci); 229 + set_session_id(ershdr, id); 291 230 292 231 /* Build metadata */ 293 232 md = (struct erspan_metadata *)(ershdr + 1); 294 233 md->u.md2.timestamp = erspan_get_timestamp(); 295 234 md->u.md2.sgt = htons(sgt); 296 - md->u.md2.flags = htons(((1 << P_OFFSET) & P_MASK) | 297 - ((hwid << HWID_OFFSET) & HWID_MASK) | 298 - ((direction << DIR_OFFSET) & DIR_MASK) | 299 - ((gra << GRA_OFFSET) & GRA_MASK)); 235 + md->u.md2.p = 1; 236 + md->u.md2.ft = 0; 237 + md->u.md2.dir = direction; 238 + md->u.md2.gra = gra; 239 + md->u.md2.o = 0; 240 + set_hwid(&md->u.md2, hwid); 300 241 } 301 242 302 243 #endif
+14 -24
net/ipv4/ip_gre.c
··· 114 114 static struct rtnl_link_ops ipgre_link_ops __read_mostly; 115 115 static int ipgre_tunnel_init(struct net_device *dev); 116 116 static void erspan_build_header(struct sk_buff *skb, 117 - __be32 id, u32 index, 117 + u32 id, u32 index, 118 118 bool truncate, bool is_ipv4); 119 119 120 120 static unsigned int ipgre_net_id __read_mostly; ··· 273 273 274 274 iph = ip_hdr(skb); 275 275 ershdr = (struct erspan_base_hdr *)(skb->data + gre_hdr_len); 276 - ver = (ntohs(ershdr->ver_vlan) & VER_MASK) >> VER_OFFSET; 276 + ver = ershdr->ver; 277 277 278 278 /* The original GRE header does not have key field, 279 279 * Use ERSPAN 10-bit session ID as key. 280 280 */ 281 - tpi->key = cpu_to_be32(ntohs(ershdr->session_id) & ID_MASK); 281 + tpi->key = cpu_to_be32(get_session_id(ershdr)); 282 282 tunnel = ip_tunnel_lookup(itn, skb->dev->ifindex, 283 283 tpi->flags | TUNNEL_KEY, 284 284 iph->saddr, iph->daddr, tpi->key); ··· 324 324 if (ver == 1) { 325 325 tunnel->index = ntohl(pkt_md->u.index); 326 326 } else { 327 - u16 md2_flags; 328 - u16 dir, hwid; 329 - 330 - md2_flags = ntohs(pkt_md->u.md2.flags); 331 - dir = (md2_flags & DIR_MASK) >> DIR_OFFSET; 332 - hwid = (md2_flags & HWID_MASK) >> HWID_OFFSET; 333 - tunnel->dir = dir; 334 - tunnel->hwid = hwid; 327 + tunnel->dir = pkt_md->u.md2.dir; 328 + tunnel->hwid = get_hwid(&pkt_md->u.md2); 335 329 } 336 330 337 331 } ··· 609 615 } 610 616 611 617 if (version == 1) { 612 - erspan_build_header(skb, tunnel_id_to_key32(key->tun_id), 618 + erspan_build_header(skb, ntohl(tunnel_id_to_key32(key->tun_id)), 613 619 ntohl(md->u.index), truncate, true); 614 620 } else if (version == 2) { 615 - u16 md2_flags; 616 - u8 direction; 617 - u16 hwid; 618 - 619 - md2_flags = ntohs(md->u.md2.flags); 620 - direction = (md2_flags & DIR_MASK) >> DIR_OFFSET; 621 - hwid = (md2_flags & HWID_MASK) >> HWID_OFFSET; 622 - 623 - erspan_build_header_v2(skb, tunnel_id_to_key32(key->tun_id), 624 - direction, hwid, truncate, true); 621 + erspan_build_header_v2(skb, 622 + ntohl(tunnel_id_to_key32(key->tun_id)), 623 + md->u.md2.dir, 624 + get_hwid(&md->u.md2), 625 + truncate, true); 625 626 } else { 626 627 goto err_free_rt; 627 628 } ··· 722 733 723 734 /* Push ERSPAN header */ 724 735 if (tunnel->erspan_ver == 1) 725 - erspan_build_header(skb, tunnel->parms.o_key, tunnel->index, 736 + erspan_build_header(skb, ntohl(tunnel->parms.o_key), 737 + tunnel->index, 726 738 truncate, true); 727 739 else 728 - erspan_build_header_v2(skb, tunnel->parms.o_key, 740 + erspan_build_header_v2(skb, ntohl(tunnel->parms.o_key), 729 741 tunnel->dir, tunnel->hwid, 730 742 truncate, true); 731 743
+13 -23
net/ipv6/ip6_gre.c
··· 513 513 514 514 ipv6h = ipv6_hdr(skb); 515 515 ershdr = (struct erspan_base_hdr *)skb->data; 516 - ver = (ntohs(ershdr->ver_vlan) & VER_MASK) >> VER_OFFSET; 517 - tpi->key = cpu_to_be32(ntohs(ershdr->session_id) & ID_MASK); 516 + ver = ershdr->ver; 517 + tpi->key = cpu_to_be32(get_session_id(ershdr)); 518 518 519 519 tunnel = ip6gre_tunnel_lookup(skb->dev, 520 520 &ipv6h->saddr, &ipv6h->daddr, tpi->key, ··· 565 565 if (ver == 1) { 566 566 tunnel->parms.index = ntohl(pkt_md->u.index); 567 567 } else { 568 - u16 md2_flags; 569 - u16 dir, hwid; 570 - 571 - md2_flags = ntohs(pkt_md->u.md2.flags); 572 - dir = (md2_flags & DIR_MASK) >> DIR_OFFSET; 573 - hwid = (md2_flags & HWID_MASK) >> HWID_OFFSET; 574 - tunnel->parms.dir = dir; 575 - tunnel->parms.hwid = hwid; 568 + tunnel->parms.dir = pkt_md->u.md2.dir; 569 + tunnel->parms.hwid = get_hwid(&pkt_md->u.md2); 576 570 } 577 571 578 572 ip6_tnl_rcv(tunnel, skb, tpi, NULL, log_ecn_error); ··· 919 925 struct ip_tunnel_info *tun_info; 920 926 const struct ip_tunnel_key *key; 921 927 struct erspan_metadata *md; 928 + __be32 tun_id; 922 929 923 930 tun_info = skb_tunnel_info(skb); 924 931 if (unlikely(!tun_info || ··· 939 944 if (!md) 940 945 goto tx_err; 941 946 947 + tun_id = tunnel_id_to_key32(key->tun_id); 942 948 if (md->version == 1) { 943 949 erspan_build_header(skb, 944 - tunnel_id_to_key32(key->tun_id), 950 + ntohl(tun_id), 945 951 ntohl(md->u.index), truncate, 946 952 false); 947 953 } else if (md->version == 2) { 948 - u16 md2_flags; 949 - u16 dir, hwid; 950 - 951 - md2_flags = ntohs(md->u.md2.flags); 952 - dir = (md2_flags & DIR_MASK) >> DIR_OFFSET; 953 - hwid = (md2_flags & HWID_MASK) >> HWID_OFFSET; 954 - 955 954 erspan_build_header_v2(skb, 956 - tunnel_id_to_key32(key->tun_id), 957 - dir, hwid, truncate, 958 - false); 955 + ntohl(tun_id), 956 + md->u.md2.dir, 957 + get_hwid(&md->u.md2), 958 + truncate, false); 959 959 } 960 960 } else { 961 961 switch (skb->protocol) { ··· 972 982 } 973 983 974 984 if (t->parms.erspan_ver == 1) 975 - erspan_build_header(skb, t->parms.o_key, 985 + erspan_build_header(skb, ntohl(t->parms.o_key), 976 986 t->parms.index, 977 987 truncate, false); 978 988 else 979 - erspan_build_header_v2(skb, t->parms.o_key, 989 + erspan_build_header_v2(skb, ntohl(t->parms.o_key), 980 990 t->parms.dir, 981 991 t->parms.hwid, 982 992 truncate, false);