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