diff options
author | William Tu <u9012063@gmail.com> | 2018-01-25 16:20:09 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2018-01-25 21:39:43 -0500 |
commit | c69de58ba84f480879de64571d9dae5102d10ed6 (patch) | |
tree | d8ba38bd0c49bc0409b91cc6583808ad4e171242 | |
parent | b89d06ce58f1ebd43d4c491da4a9a9f0f29787d6 (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.h | 127 | ||||
-rw-r--r-- | net/ipv4/ip_gre.c | 38 | ||||
-rw-r--r-- | 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 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 */ |
69 | struct erspan_md2 { | 72 | struct 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 | ||
80 | enum erspan_encap_type { | 94 | enum erspan_encap_type { |
@@ -95,15 +109,62 @@ struct erspan_metadata { | |||
95 | }; | 109 | }; |
96 | 110 | ||
97 | struct erspan_base_hdr { | 111 | struct 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 | ||
135 | static 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 | |||
141 | static inline u16 get_session_id(const struct erspan_base_hdr *ershdr) | ||
142 | { | ||
143 | return (ershdr->session_id_upper << 8) + ershdr->session_id; | ||
144 | } | ||
145 | |||
146 | static 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 | |||
152 | static inline u16 get_vlan(const struct erspan_base_hdr *ershdr) | ||
153 | { | ||
154 | return (ershdr->vlan_upper << 8) + ershdr->vlan; | ||
155 | } | ||
156 | |||
157 | static 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 | |||
163 | static inline u8 get_hwid(const struct erspan_md2 *md2) | ||
164 | { | ||
165 | return (md2->hwid_upper << 4) + md2->hwid; | ||
166 | } | ||
167 | |||
107 | static inline int erspan_hdr_len(int version) | 168 | static 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 | ||
122 | static inline void erspan_build_header(struct sk_buff *skb, | 183 | static 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 | ||
189 | static inline void erspan_build_header_v2(struct sk_buff *skb, | 250 | static 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"); | |||
114 | static struct rtnl_link_ops ipgre_link_ops __read_mostly; | 114 | static struct rtnl_link_ops ipgre_link_ops __read_mostly; |
115 | static int ipgre_tunnel_init(struct net_device *dev); | 115 | static int ipgre_tunnel_init(struct net_device *dev); |
116 | static void erspan_build_header(struct sk_buff *skb, | 116 | static 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 | ||
120 | static unsigned int ipgre_net_id __read_mostly; | 120 | 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, | |||
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); |