aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2017-12-15 12:34:01 -0500
committerDavid S. Miller <davem@davemloft.net>2017-12-15 12:34:01 -0500
commit9463b2f72eadf93132815e7ee8e54b4f46e39be9 (patch)
treef1cf7a172a8410fcd1c4be1f4389830ed8f200d9
parent4650b7514c06a9f66829d877b19d896d49d1116e (diff)
parentac80c2a165af02a0cca3d17d534a85d37fdc1271 (diff)
Merge branch 'erspan-version-2'
William Tu says: ==================== ERSPAN version 2 (type III) support ERSPAN has two versions, v1 (type II) and v2 (type III). This patch series add support for erspan v2 based on existing erspan v1 implementation. The first patch refactors the existing erspan v1's header structure, making it extensible to put additional v2's header. The second and third patch introduces erspan v2's implementation to ipv4 and ipv6 erspan, for both native mode and collect metadata mode. Finally, test cases are added under the samples/bpf. Note: ERSPAN version 2 has many features and this patch does not implement all. One major use case of version 2 over version 1 is its timestamp and direction. So the traffic collector is able to distinguish the mirrorred traffic better. Other features such as SGT (security group tag), FT (frame type) for carrying non-ethernet packet, and optional subheader are not implemented yet. Example commandline for ERSPAN version 2: ip link add dev ip6erspan11 type ip6erspan seq key 102 \ local fc00:100::2 remote fc00:100::1 \ erspan_ver 2 erspan_dir 1 erspan_hwid 17 The corresponding iproute2 patch: https://marc.info/?l=linux-netdev&m=151321141525106&w=2 William Tu (4): net: erspan: refactor existing erspan code net: erspan: introduce erspan v2 for ip_gre ip6_gre: add erspan v2 support samples/bpf: add erspan v2 sample code include/net/erspan.h | 152 ++++++++++++++++++++++++++++++++++++++--- include/net/ip6_tunnel.h | 3 + include/net/ip_tunnels.h | 5 +- include/uapi/linux/if_ether.h | 1 + include/uapi/linux/if_tunnel.h | 3 + net/ipv4/ip_gre.c | 124 +++++++++++++++++++++++++++------ net/ipv6/ip6_gre.c | 139 +++++++++++++++++++++++++++++++------ net/openvswitch/flow_netlink.c | 8 +-- samples/bpf/tcbpf2_kern.c | 77 ++++++++++++++++++--- samples/bpf/test_tunnel_bpf.sh | 38 ++++++++--- 10 files changed, 472 insertions(+), 78 deletions(-) -- A simple script to test it: set -ex function cleanup() { set +ex ip netns del ns0 ip link del ip6erspan11 ip link del veth1 } function main() { trap cleanup 0 2 3 9 ip netns add ns0 ip link add veth0 type veth peer name veth1 ip link set veth0 netns ns0 # non-namespace ip addr add dev veth1 fc00:100::2/96 if [ "$1" == "v1" ]; then echo "create IP6 ERSPAN v1 tunnel" ip link add dev ip6erspan11 type ip6erspan seq key 102 \ local fc00:100::2 remote fc00:100::1 \ erspan 123 erspan_ver 1 else echo "create IP6 ERSPAN v2 tunnel" ip link add dev ip6erspan11 type ip6erspan seq key 102 \ local fc00:100::2 remote fc00:100::1 \ erspan_ver 2 erspan_dir 1 erspan_hwid 17 fi ip addr add dev ip6erspan11 fc00:200::2/96 ip addr add dev ip6erspan11 10.10.200.2/24 # namespace: ns0 ip netns exec ns0 ip addr add fc00:100::1/96 dev veth0 if [ "$1" == "v1" ]; then ip netns exec ns0 \ ip link add dev ip6erspan00 type ip6erspan seq key 102 \ local fc00:100::1 remote fc00:100::2 \ erspan 123 erspan_ver 1 else ip netns exec ns0 \ ip link add dev ip6erspan00 type ip6erspan seq key 102 \ local fc00:100::1 remote fc00:100::2 \ erspan_ver 2 erspan_dir 1 erspan_hwid 7 fi ip netns exec ns0 ip addr add dev ip6erspan00 fc00:200::1/96 ip netns exec ns0 ip addr add dev ip6erspan00 10.10.200.1/24 ip link set dev veth1 up ip link set dev ip6erspan11 up ip netns exec ns0 ip link set dev ip6erspan00 up ip netns exec ns0 ip link set dev veth0 up } main $1 ping6 -c 1 fc00:100::1 || true ping -c 3 10.10.200.1 exit 0 ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--include/net/erspan.h152
-rw-r--r--include/net/ip6_tunnel.h3
-rw-r--r--include/net/ip_tunnels.h5
-rw-r--r--include/uapi/linux/if_ether.h1
-rw-r--r--include/uapi/linux/if_tunnel.h3
-rw-r--r--net/ipv4/ip_gre.c124
-rw-r--r--net/ipv6/ip6_gre.c139
-rw-r--r--net/openvswitch/flow_netlink.c8
-rw-r--r--samples/bpf/tcbpf2_kern.c77
-rwxr-xr-xsamples/bpf/test_tunnel_bpf.sh38
10 files changed, 472 insertions, 78 deletions
diff --git a/include/net/erspan.h b/include/net/erspan.h
index 6e758d08c9ee..acdf6843095d 100644
--- a/include/net/erspan.h
+++ b/include/net/erspan.h
@@ -15,7 +15,7 @@
15 * s, Recur, Flags, Version fields only S (bit 03) is set to 1. The 15 * s, Recur, Flags, Version fields only S (bit 03) is set to 1. The
16 * other fields are set to zero, so only a sequence number follows. 16 * other fields are set to zero, so only a sequence number follows.
17 * 17 *
18 * ERSPAN Type II header (8 octets [42:49]) 18 * ERSPAN Version 1 (Type II) header (8 octets [42:49])
19 * 0 1 2 3 19 * 0 1 2 3
20 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 20 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
21 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 21 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
@@ -24,11 +24,29 @@
24 * | Reserved | Index | 24 * | Reserved | Index |
25 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 25 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
26 * 26 *
27 *
28 * ERSPAN Version 2 (Type III) header (12 octets [42:49])
29 * 0 1 2 3
30 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
31 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
32 * | Ver | VLAN | COS |BSO|T| Session ID |
33 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
34 * | Timestamp |
35 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
36 * | SGT |P| FT | Hw ID |D|Gra|O|
37 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
38 *
39 * Platform Specific SubHeader (8 octets, optional)
40 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
41 * | Platf ID | Platform Specific Info |
42 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
43 * | Platform Specific Info |
44 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
45 *
27 * GRE proto ERSPAN type II = 0x88BE, type III = 0x22EB 46 * GRE proto ERSPAN type II = 0x88BE, type III = 0x22EB
28 */ 47 */
29 48
30#define ERSPAN_VERSION 0x1 49#define ERSPAN_VERSION 0x1 /* ERSPAN type II */
31
32#define VER_MASK 0xf000 50#define VER_MASK 0xf000
33#define VLAN_MASK 0x0fff 51#define VLAN_MASK 0x0fff
34#define COS_MASK 0xe000 52#define COS_MASK 0xe000
@@ -37,6 +55,28 @@
37#define ID_MASK 0x03ff 55#define ID_MASK 0x03ff
38#define INDEX_MASK 0xfffff 56#define INDEX_MASK 0xfffff
39 57
58#define ERSPAN_VERSION2 0x2 /* ERSPAN type III*/
59#define BSO_MASK EN_MASK
60#define SGT_MASK 0xffff0000
61#define P_MASK 0x8000
62#define FT_MASK 0x7c00
63#define HWID_MASK 0x03f0
64#define DIR_MASK 0x0008
65#define GRA_MASK 0x0006
66#define O_MASK 0x0001
67
68/* ERSPAN version 2 metadata header */
69struct erspan_md2 {
70 __be32 timestamp;
71 __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
78};
79
40enum erspan_encap_type { 80enum erspan_encap_type {
41 ERSPAN_ENCAP_NOVLAN = 0x0, /* originally without VLAN tag */ 81 ERSPAN_ENCAP_NOVLAN = 0x0, /* originally without VLAN tag */
42 ERSPAN_ENCAP_ISL = 0x1, /* originally ISL encapsulated */ 82 ERSPAN_ENCAP_ISL = 0x1, /* originally ISL encapsulated */
@@ -44,20 +84,32 @@ enum erspan_encap_type {
44 ERSPAN_ENCAP_INFRAME = 0x3, /* VLAN tag perserved in frame */ 84 ERSPAN_ENCAP_INFRAME = 0x3, /* VLAN tag perserved in frame */
45}; 85};
46 86
87#define ERSPAN_V1_MDSIZE 4
88#define ERSPAN_V2_MDSIZE 8
47struct erspan_metadata { 89struct erspan_metadata {
48 __be32 index; /* type II */ 90 union {
91 __be32 index; /* Version 1 (type II)*/
92 struct erspan_md2 md2; /* Version 2 (type III) */
93 } u;
94 int version;
49}; 95};
50 96
51struct erspanhdr { 97struct erspan_base_hdr {
52 __be16 ver_vlan; 98 __be16 ver_vlan;
53#define VER_OFFSET 12 99#define VER_OFFSET 12
54 __be16 session_id; 100 __be16 session_id;
55#define COS_OFFSET 13 101#define COS_OFFSET 13
56#define EN_OFFSET 11 102#define EN_OFFSET 11
103#define BSO_OFFSET EN_OFFSET
57#define T_OFFSET 10 104#define T_OFFSET 10
58 struct erspan_metadata md;
59}; 105};
60 106
107static inline int erspan_hdr_len(int version)
108{
109 return sizeof(struct erspan_base_hdr) +
110 (version == 1 ? ERSPAN_V1_MDSIZE : ERSPAN_V2_MDSIZE);
111}
112
61static inline u8 tos_to_cos(u8 tos) 113static inline u8 tos_to_cos(u8 tos)
62{ 114{
63 u8 dscp, cos; 115 u8 dscp, cos;
@@ -73,7 +125,8 @@ static inline void erspan_build_header(struct sk_buff *skb,
73{ 125{
74 struct ethhdr *eth = eth_hdr(skb); 126 struct ethhdr *eth = eth_hdr(skb);
75 enum erspan_encap_type enc_type; 127 enum erspan_encap_type enc_type;
76 struct erspanhdr *ershdr; 128 struct erspan_base_hdr *ershdr;
129 struct erspan_metadata *ersmd;
77 struct qtag_prefix { 130 struct qtag_prefix {
78 __be16 eth_type; 131 __be16 eth_type;
79 __be16 tci; 132 __be16 tci;
@@ -96,17 +149,94 @@ static inline void erspan_build_header(struct sk_buff *skb,
96 enc_type = ERSPAN_ENCAP_INFRAME; 149 enc_type = ERSPAN_ENCAP_INFRAME;
97 } 150 }
98 151
99 skb_push(skb, sizeof(*ershdr)); 152 skb_push(skb, sizeof(*ershdr) + ERSPAN_V1_MDSIZE);
100 ershdr = (struct erspanhdr *)skb->data; 153 ershdr = (struct erspan_base_hdr *)skb->data;
101 memset(ershdr, 0, sizeof(*ershdr)); 154 memset(ershdr, 0, sizeof(*ershdr) + ERSPAN_V1_MDSIZE);
102 155
156 /* Build base header */
103 ershdr->ver_vlan = htons((vlan_tci & VLAN_MASK) | 157 ershdr->ver_vlan = htons((vlan_tci & VLAN_MASK) |
104 (ERSPAN_VERSION << VER_OFFSET)); 158 (ERSPAN_VERSION << VER_OFFSET));
105 ershdr->session_id = htons((u16)(ntohl(id) & ID_MASK) | 159 ershdr->session_id = htons((u16)(ntohl(id) & ID_MASK) |
106 ((tos_to_cos(tos) << COS_OFFSET) & COS_MASK) | 160 ((tos_to_cos(tos) << COS_OFFSET) & COS_MASK) |
107 (enc_type << EN_OFFSET & EN_MASK) | 161 (enc_type << EN_OFFSET & EN_MASK) |
108 ((truncate << T_OFFSET) & T_MASK)); 162 ((truncate << T_OFFSET) & T_MASK));
109 ershdr->md.index = htonl(index & INDEX_MASK); 163
164 /* Build metadata */
165 ersmd = (struct erspan_metadata *)(ershdr + 1);
166 ersmd->u.index = htonl(index & INDEX_MASK);
167}
168
169/* ERSPAN GRA: timestamp granularity
170 * 00b --> granularity = 100 microseconds
171 * 01b --> granularity = 100 nanoseconds
172 * 10b --> granularity = IEEE 1588
173 * Here we only support 100 microseconds.
174 */
175static inline __be32 erspan_get_timestamp(void)
176{
177 u64 h_usecs;
178 ktime_t kt;
179
180 kt = ktime_get_real();
181 h_usecs = ktime_divns(kt, 100 * NSEC_PER_USEC);
182
183 /* ERSPAN base header only has 32-bit,
184 * so it wraps around 4 days.
185 */
186 return htonl((u32)h_usecs);
187}
188
189static inline void erspan_build_header_v2(struct sk_buff *skb,
190 __be32 id, u8 direction, u16 hwid,
191 bool truncate, bool is_ipv4)
192{
193 struct ethhdr *eth = eth_hdr(skb);
194 struct erspan_base_hdr *ershdr;
195 struct erspan_metadata *md;
196 struct qtag_prefix {
197 __be16 eth_type;
198 __be16 tci;
199 } *qp;
200 u16 vlan_tci = 0;
201 u16 session_id;
202 u8 gra = 0; /* 100 usec */
203 u8 bso = 0; /* Bad/Short/Oversized */
204 u8 sgt = 0;
205 u8 tos;
206
207 tos = is_ipv4 ? ip_hdr(skb)->tos :
208 (ipv6_hdr(skb)->priority << 4) +
209 (ipv6_hdr(skb)->flow_lbl[0] >> 4);
210
211 /* Unlike v1, v2 does not have En field,
212 * so only extract vlan tci field.
213 */
214 if (eth->h_proto == htons(ETH_P_8021Q)) {
215 qp = (struct qtag_prefix *)(skb->data + 2 * ETH_ALEN);
216 vlan_tci = ntohs(qp->tci);
217 }
218
219 skb_push(skb, sizeof(*ershdr) + ERSPAN_V2_MDSIZE);
220 ershdr = (struct erspan_base_hdr *)skb->data;
221 memset(ershdr, 0, sizeof(*ershdr) + ERSPAN_V2_MDSIZE);
222
223 /* Build base header */
224 ershdr->ver_vlan = htons((vlan_tci & VLAN_MASK) |
225 (ERSPAN_VERSION2 << VER_OFFSET));
226 session_id = (u16)(ntohl(id) & ID_MASK) |
227 ((tos_to_cos(tos) << COS_OFFSET) & COS_MASK) |
228 (bso << BSO_OFFSET & BSO_MASK) |
229 ((truncate << T_OFFSET) & T_MASK);
230 ershdr->session_id = htons(session_id);
231
232 /* Build metadata */
233 md = (struct erspan_metadata *)(ershdr + 1);
234 md->u.md2.timestamp = erspan_get_timestamp();
235 md->u.md2.sgt = htons(sgt);
236 md->u.md2.flags = htons(((1 << P_OFFSET) & P_MASK) |
237 ((hwid << HWID_OFFSET) & HWID_MASK) |
238 ((direction << DIR_OFFSET) & DIR_MASK) |
239 ((gra << GRA_OFFSET) & GRA_MASK));
110} 240}
111 241
112#endif 242#endif
diff --git a/include/net/ip6_tunnel.h b/include/net/ip6_tunnel.h
index 109a5a8877ef..236e40ba06bf 100644
--- a/include/net/ip6_tunnel.h
+++ b/include/net/ip6_tunnel.h
@@ -37,6 +37,9 @@ struct __ip6_tnl_parm {
37 37
38 __u32 fwmark; 38 __u32 fwmark;
39 __u32 index; /* ERSPAN type II index */ 39 __u32 index; /* ERSPAN type II index */
40 __u8 erspan_ver; /* ERSPAN version */
41 __u8 dir; /* direction */
42 __u16 hwid; /* hwid */
40}; 43};
41 44
42/* IPv6 tunnel */ 45/* IPv6 tunnel */
diff --git a/include/net/ip_tunnels.h b/include/net/ip_tunnels.h
index 24628f6b09bf..1f16773cfd76 100644
--- a/include/net/ip_tunnels.h
+++ b/include/net/ip_tunnels.h
@@ -116,8 +116,11 @@ struct ip_tunnel {
116 u32 o_seqno; /* The last output seqno */ 116 u32 o_seqno; /* The last output seqno */
117 int tun_hlen; /* Precalculated header length */ 117 int tun_hlen; /* Precalculated header length */
118 118
119 /* This field used only by ERSPAN */ 119 /* These four fields used only by ERSPAN */
120 u32 index; /* ERSPAN type II index */ 120 u32 index; /* ERSPAN type II index */
121 u8 erspan_ver; /* ERSPAN version */
122 u8 dir; /* ERSPAN direction */
123 u16 hwid; /* ERSPAN hardware ID */
121 124
122 struct dst_cache dst_cache; 125 struct dst_cache dst_cache;
123 126
diff --git a/include/uapi/linux/if_ether.h b/include/uapi/linux/if_ether.h
index 3ee3bf7c8526..87b7529fcdfe 100644
--- a/include/uapi/linux/if_ether.h
+++ b/include/uapi/linux/if_ether.h
@@ -47,6 +47,7 @@
47#define ETH_P_PUP 0x0200 /* Xerox PUP packet */ 47#define ETH_P_PUP 0x0200 /* Xerox PUP packet */
48#define ETH_P_PUPAT 0x0201 /* Xerox PUP Addr Trans packet */ 48#define ETH_P_PUPAT 0x0201 /* Xerox PUP Addr Trans packet */
49#define ETH_P_TSN 0x22F0 /* TSN (IEEE 1722) packet */ 49#define ETH_P_TSN 0x22F0 /* TSN (IEEE 1722) packet */
50#define ETH_P_ERSPAN2 0x22EB /* ERSPAN version 2 (type III) */
50#define ETH_P_IP 0x0800 /* Internet Protocol packet */ 51#define ETH_P_IP 0x0800 /* Internet Protocol packet */
51#define ETH_P_X25 0x0805 /* CCITT X.25 */ 52#define ETH_P_X25 0x0805 /* CCITT X.25 */
52#define ETH_P_ARP 0x0806 /* Address Resolution packet */ 53#define ETH_P_ARP 0x0806 /* Address Resolution packet */
diff --git a/include/uapi/linux/if_tunnel.h b/include/uapi/linux/if_tunnel.h
index e68dadbd6d45..1b3d148c4560 100644
--- a/include/uapi/linux/if_tunnel.h
+++ b/include/uapi/linux/if_tunnel.h
@@ -137,6 +137,9 @@ enum {
137 IFLA_GRE_IGNORE_DF, 137 IFLA_GRE_IGNORE_DF,
138 IFLA_GRE_FWMARK, 138 IFLA_GRE_FWMARK,
139 IFLA_GRE_ERSPAN_INDEX, 139 IFLA_GRE_ERSPAN_INDEX,
140 IFLA_GRE_ERSPAN_VER,
141 IFLA_GRE_ERSPAN_DIR,
142 IFLA_GRE_ERSPAN_HWID,
140 __IFLA_GRE_MAX, 143 __IFLA_GRE_MAX,
141}; 144};
142 145
diff --git a/net/ipv4/ip_gre.c b/net/ipv4/ip_gre.c
index d828821d88d7..004800b923c6 100644
--- a/net/ipv4/ip_gre.c
+++ b/net/ipv4/ip_gre.c
@@ -256,34 +256,41 @@ static int erspan_rcv(struct sk_buff *skb, struct tnl_ptk_info *tpi,
256{ 256{
257 struct net *net = dev_net(skb->dev); 257 struct net *net = dev_net(skb->dev);
258 struct metadata_dst *tun_dst = NULL; 258 struct metadata_dst *tun_dst = NULL;
259 struct erspan_base_hdr *ershdr;
260 struct erspan_metadata *pkt_md;
259 struct ip_tunnel_net *itn; 261 struct ip_tunnel_net *itn;
260 struct ip_tunnel *tunnel; 262 struct ip_tunnel *tunnel;
261 struct erspanhdr *ershdr;
262 const struct iphdr *iph; 263 const struct iphdr *iph;
263 __be32 index; 264 int ver;
264 int len; 265 int len;
265 266
266 itn = net_generic(net, erspan_net_id); 267 itn = net_generic(net, erspan_net_id);
267 len = gre_hdr_len + sizeof(*ershdr); 268 len = gre_hdr_len + sizeof(*ershdr);
268 269
270 /* Check based hdr len */
269 if (unlikely(!pskb_may_pull(skb, len))) 271 if (unlikely(!pskb_may_pull(skb, len)))
270 return -ENOMEM; 272 return -ENOMEM;
271 273
272 iph = ip_hdr(skb); 274 iph = ip_hdr(skb);
273 ershdr = (struct erspanhdr *)(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;
274 277
275 /* The original GRE header does not have key field, 278 /* The original GRE header does not have key field,
276 * Use ERSPAN 10-bit session ID as key. 279 * Use ERSPAN 10-bit session ID as key.
277 */ 280 */
278 tpi->key = cpu_to_be32(ntohs(ershdr->session_id) & ID_MASK); 281 tpi->key = cpu_to_be32(ntohs(ershdr->session_id) & ID_MASK);
279 index = ershdr->md.index; 282 pkt_md = (struct erspan_metadata *)(ershdr + 1);
280 tunnel = ip_tunnel_lookup(itn, skb->dev->ifindex, 283 tunnel = ip_tunnel_lookup(itn, skb->dev->ifindex,
281 tpi->flags | TUNNEL_KEY, 284 tpi->flags | TUNNEL_KEY,
282 iph->saddr, iph->daddr, tpi->key); 285 iph->saddr, iph->daddr, tpi->key);
283 286
284 if (tunnel) { 287 if (tunnel) {
288 len = gre_hdr_len + erspan_hdr_len(ver);
289 if (unlikely(!pskb_may_pull(skb, len)))
290 return -ENOMEM;
291
285 if (__iptunnel_pull_header(skb, 292 if (__iptunnel_pull_header(skb,
286 gre_hdr_len + sizeof(*ershdr), 293 len,
287 htons(ETH_P_TEB), 294 htons(ETH_P_TEB),
288 false, false) < 0) 295 false, false) < 0)
289 goto drop; 296 goto drop;
@@ -307,12 +314,27 @@ static int erspan_rcv(struct sk_buff *skb, struct tnl_ptk_info *tpi,
307 if (!md) 314 if (!md)
308 return PACKET_REJECT; 315 return PACKET_REJECT;
309 316
310 md->index = index; 317 memcpy(md, pkt_md, sizeof(*md));
318 md->version = ver;
319
311 info = &tun_dst->u.tun_info; 320 info = &tun_dst->u.tun_info;
312 info->key.tun_flags |= TUNNEL_ERSPAN_OPT; 321 info->key.tun_flags |= TUNNEL_ERSPAN_OPT;
313 info->options_len = sizeof(*md); 322 info->options_len = sizeof(*md);
314 } else { 323 } else {
315 tunnel->index = ntohl(index); 324 tunnel->erspan_ver = ver;
325 if (ver == 1) {
326 tunnel->index = ntohl(pkt_md->u.index);
327 } else {
328 u16 md2_flags;
329 u16 dir, hwid;
330
331 md2_flags = ntohs(pkt_md->u.md2.flags);
332 dir = (md2_flags & DIR_MASK) >> DIR_OFFSET;
333 hwid = (md2_flags & HWID_MASK) >> HWID_OFFSET;
334 tunnel->dir = dir;
335 tunnel->hwid = hwid;
336 }
337
316 } 338 }
317 339
318 skb_reset_mac_header(skb); 340 skb_reset_mac_header(skb);
@@ -406,7 +428,8 @@ static int gre_rcv(struct sk_buff *skb)
406 if (hdr_len < 0) 428 if (hdr_len < 0)
407 goto drop; 429 goto drop;
408 430
409 if (unlikely(tpi.proto == htons(ETH_P_ERSPAN))) { 431 if (unlikely(tpi.proto == htons(ETH_P_ERSPAN) ||
432 tpi.proto == htons(ETH_P_ERSPAN2))) {
410 if (erspan_rcv(skb, &tpi, hdr_len) == PACKET_RCVD) 433 if (erspan_rcv(skb, &tpi, hdr_len) == PACKET_RCVD)
411 return 0; 434 return 0;
412 } 435 }
@@ -561,6 +584,7 @@ static void erspan_fb_xmit(struct sk_buff *skb, struct net_device *dev,
561 bool truncate = false; 584 bool truncate = false;
562 struct flowi4 fl; 585 struct flowi4 fl;
563 int tunnel_hlen; 586 int tunnel_hlen;
587 int version;
564 __be16 df; 588 __be16 df;
565 589
566 tun_info = skb_tunnel_info(skb); 590 tun_info = skb_tunnel_info(skb);
@@ -569,9 +593,13 @@ static void erspan_fb_xmit(struct sk_buff *skb, struct net_device *dev,
569 goto err_free_skb; 593 goto err_free_skb;
570 594
571 key = &tun_info->key; 595 key = &tun_info->key;
596 md = ip_tunnel_info_opts(tun_info);
597 if (!md)
598 goto err_free_rt;
572 599
573 /* ERSPAN has fixed 8 byte GRE header */ 600 /* ERSPAN has fixed 8 byte GRE header */
574 tunnel_hlen = 8 + sizeof(struct erspanhdr); 601 version = md->version;
602 tunnel_hlen = 8 + erspan_hdr_len(version);
575 603
576 rt = prepare_fb_xmit(skb, dev, &fl, tunnel_hlen); 604 rt = prepare_fb_xmit(skb, dev, &fl, tunnel_hlen);
577 if (!rt) 605 if (!rt)
@@ -585,12 +613,23 @@ static void erspan_fb_xmit(struct sk_buff *skb, struct net_device *dev,
585 truncate = true; 613 truncate = true;
586 } 614 }
587 615
588 md = ip_tunnel_info_opts(tun_info); 616 if (version == 1) {
589 if (!md) 617 erspan_build_header(skb, tunnel_id_to_key32(key->tun_id),
590 goto err_free_rt; 618 ntohl(md->u.index), truncate, true);
619 } else if (version == 2) {
620 u16 md2_flags;
621 u8 direction;
622 u16 hwid;
623
624 md2_flags = ntohs(md->u.md2.flags);
625 direction = (md2_flags & DIR_MASK) >> DIR_OFFSET;
626 hwid = (md2_flags & HWID_MASK) >> HWID_OFFSET;
591 627
592 erspan_build_header(skb, tunnel_id_to_key32(key->tun_id), 628 erspan_build_header_v2(skb, tunnel_id_to_key32(key->tun_id),
593 ntohl(md->index), truncate, true); 629 direction, hwid, truncate, true);
630 } else {
631 goto err_free_rt;
632 }
594 633
595 gre_build_header(skb, 8, TUNNEL_SEQ, 634 gre_build_header(skb, 8, TUNNEL_SEQ,
596 htons(ETH_P_ERSPAN), 0, htonl(tunnel->o_seqno++)); 635 htons(ETH_P_ERSPAN), 0, htonl(tunnel->o_seqno++));
@@ -692,8 +731,14 @@ static netdev_tx_t erspan_xmit(struct sk_buff *skb,
692 } 731 }
693 732
694 /* Push ERSPAN header */ 733 /* Push ERSPAN header */
695 erspan_build_header(skb, tunnel->parms.o_key, tunnel->index, 734 if (tunnel->erspan_ver == 1)
696 truncate, true); 735 erspan_build_header(skb, tunnel->parms.o_key, tunnel->index,
736 truncate, true);
737 else
738 erspan_build_header_v2(skb, tunnel->parms.o_key,
739 tunnel->dir, tunnel->hwid,
740 truncate, true);
741
697 tunnel->parms.o_flags &= ~TUNNEL_KEY; 742 tunnel->parms.o_flags &= ~TUNNEL_KEY;
698 __gre_xmit(skb, dev, &tunnel->parms.iph, htons(ETH_P_ERSPAN)); 743 __gre_xmit(skb, dev, &tunnel->parms.iph, htons(ETH_P_ERSPAN));
699 return NETDEV_TX_OK; 744 return NETDEV_TX_OK;
@@ -1165,13 +1210,32 @@ static int ipgre_netlink_parms(struct net_device *dev,
1165 if (data[IFLA_GRE_FWMARK]) 1210 if (data[IFLA_GRE_FWMARK])
1166 *fwmark = nla_get_u32(data[IFLA_GRE_FWMARK]); 1211 *fwmark = nla_get_u32(data[IFLA_GRE_FWMARK]);
1167 1212
1168 if (data[IFLA_GRE_ERSPAN_INDEX]) { 1213 if (data[IFLA_GRE_ERSPAN_VER]) {
1169 t->index = nla_get_u32(data[IFLA_GRE_ERSPAN_INDEX]); 1214 t->erspan_ver = nla_get_u8(data[IFLA_GRE_ERSPAN_VER]);
1170 1215
1171 if (t->index & ~INDEX_MASK) 1216 if (t->erspan_ver != 1 && t->erspan_ver != 2)
1172 return -EINVAL; 1217 return -EINVAL;
1173 } 1218 }
1174 1219
1220 if (t->erspan_ver == 1) {
1221 if (data[IFLA_GRE_ERSPAN_INDEX]) {
1222 t->index = nla_get_u32(data[IFLA_GRE_ERSPAN_INDEX]);
1223 if (t->index & ~INDEX_MASK)
1224 return -EINVAL;
1225 }
1226 } else if (t->erspan_ver == 2) {
1227 if (data[IFLA_GRE_ERSPAN_DIR]) {
1228 t->dir = nla_get_u8(data[IFLA_GRE_ERSPAN_DIR]);
1229 if (t->dir & ~(DIR_MASK >> DIR_OFFSET))
1230 return -EINVAL;
1231 }
1232 if (data[IFLA_GRE_ERSPAN_HWID]) {
1233 t->hwid = nla_get_u16(data[IFLA_GRE_ERSPAN_HWID]);
1234 if (t->hwid & ~(HWID_MASK >> HWID_OFFSET))
1235 return -EINVAL;
1236 }
1237 }
1238
1175 return 0; 1239 return 0;
1176} 1240}
1177 1241
@@ -1238,7 +1302,7 @@ static int erspan_tunnel_init(struct net_device *dev)
1238 tunnel->tun_hlen = 8; 1302 tunnel->tun_hlen = 8;
1239 tunnel->parms.iph.protocol = IPPROTO_GRE; 1303 tunnel->parms.iph.protocol = IPPROTO_GRE;
1240 tunnel->hlen = tunnel->tun_hlen + tunnel->encap_hlen + 1304 tunnel->hlen = tunnel->tun_hlen + tunnel->encap_hlen +
1241 sizeof(struct erspanhdr); 1305 erspan_hdr_len(tunnel->erspan_ver);
1242 t_hlen = tunnel->hlen + sizeof(struct iphdr); 1306 t_hlen = tunnel->hlen + sizeof(struct iphdr);
1243 1307
1244 dev->needed_headroom = LL_MAX_HEADER + t_hlen + 4; 1308 dev->needed_headroom = LL_MAX_HEADER + t_hlen + 4;
@@ -1368,6 +1432,12 @@ static size_t ipgre_get_size(const struct net_device *dev)
1368 nla_total_size(4) + 1432 nla_total_size(4) +
1369 /* IFLA_GRE_ERSPAN_INDEX */ 1433 /* IFLA_GRE_ERSPAN_INDEX */
1370 nla_total_size(4) + 1434 nla_total_size(4) +
1435 /* IFLA_GRE_ERSPAN_VER */
1436 nla_total_size(1) +
1437 /* IFLA_GRE_ERSPAN_DIR */
1438 nla_total_size(1) +
1439 /* IFLA_GRE_ERSPAN_HWID */
1440 nla_total_size(2) +
1371 0; 1441 0;
1372} 1442}
1373 1443
@@ -1410,9 +1480,18 @@ static int ipgre_fill_info(struct sk_buff *skb, const struct net_device *dev)
1410 goto nla_put_failure; 1480 goto nla_put_failure;
1411 } 1481 }
1412 1482
1413 if (t->index) 1483 if (nla_put_u8(skb, IFLA_GRE_ERSPAN_VER, t->erspan_ver))
1484 goto nla_put_failure;
1485
1486 if (t->erspan_ver == 1) {
1414 if (nla_put_u32(skb, IFLA_GRE_ERSPAN_INDEX, t->index)) 1487 if (nla_put_u32(skb, IFLA_GRE_ERSPAN_INDEX, t->index))
1415 goto nla_put_failure; 1488 goto nla_put_failure;
1489 } else if (t->erspan_ver == 2) {
1490 if (nla_put_u8(skb, IFLA_GRE_ERSPAN_DIR, t->dir))
1491 goto nla_put_failure;
1492 if (nla_put_u16(skb, IFLA_GRE_ERSPAN_HWID, t->hwid))
1493 goto nla_put_failure;
1494 }
1416 1495
1417 return 0; 1496 return 0;
1418 1497
@@ -1448,6 +1527,9 @@ static const struct nla_policy ipgre_policy[IFLA_GRE_MAX + 1] = {
1448 [IFLA_GRE_IGNORE_DF] = { .type = NLA_U8 }, 1527 [IFLA_GRE_IGNORE_DF] = { .type = NLA_U8 },
1449 [IFLA_GRE_FWMARK] = { .type = NLA_U32 }, 1528 [IFLA_GRE_FWMARK] = { .type = NLA_U32 },
1450 [IFLA_GRE_ERSPAN_INDEX] = { .type = NLA_U32 }, 1529 [IFLA_GRE_ERSPAN_INDEX] = { .type = NLA_U32 },
1530 [IFLA_GRE_ERSPAN_VER] = { .type = NLA_U8 },
1531 [IFLA_GRE_ERSPAN_DIR] = { .type = NLA_U8 },
1532 [IFLA_GRE_ERSPAN_HWID] = { .type = NLA_U16 },
1451}; 1533};
1452 1534
1453static struct rtnl_link_ops ipgre_link_ops __read_mostly = { 1535static struct rtnl_link_ops ipgre_link_ops __read_mostly = {
diff --git a/net/ipv6/ip6_gre.c b/net/ipv6/ip6_gre.c
index 4562579797d1..5c9c65f1d5c2 100644
--- a/net/ipv6/ip6_gre.c
+++ b/net/ipv6/ip6_gre.c
@@ -501,25 +501,32 @@ static int ip6gre_rcv(struct sk_buff *skb, const struct tnl_ptk_info *tpi)
501static int ip6erspan_rcv(struct sk_buff *skb, int gre_hdr_len, 501static int ip6erspan_rcv(struct sk_buff *skb, int gre_hdr_len,
502 struct tnl_ptk_info *tpi) 502 struct tnl_ptk_info *tpi)
503{ 503{
504 struct erspan_base_hdr *ershdr;
505 struct erspan_metadata *pkt_md;
504 const struct ipv6hdr *ipv6h; 506 const struct ipv6hdr *ipv6h;
505 struct erspanhdr *ershdr;
506 struct ip6_tnl *tunnel; 507 struct ip6_tnl *tunnel;
507 __be32 index; 508 u8 ver;
508 509
509 ipv6h = ipv6_hdr(skb); 510 ipv6h = ipv6_hdr(skb);
510 ershdr = (struct erspanhdr *)skb->data; 511 ershdr = (struct erspan_base_hdr *)skb->data;
511 512
512 if (unlikely(!pskb_may_pull(skb, sizeof(*ershdr)))) 513 if (unlikely(!pskb_may_pull(skb, sizeof(*ershdr))))
513 return PACKET_REJECT; 514 return PACKET_REJECT;
514 515
516 ver = (ntohs(ershdr->ver_vlan) & VER_MASK) >> VER_OFFSET;
515 tpi->key = cpu_to_be32(ntohs(ershdr->session_id) & ID_MASK); 517 tpi->key = cpu_to_be32(ntohs(ershdr->session_id) & ID_MASK);
516 index = ershdr->md.index; 518 pkt_md = (struct erspan_metadata *)(ershdr + 1);
517 519
518 tunnel = ip6gre_tunnel_lookup(skb->dev, 520 tunnel = ip6gre_tunnel_lookup(skb->dev,
519 &ipv6h->saddr, &ipv6h->daddr, tpi->key, 521 &ipv6h->saddr, &ipv6h->daddr, tpi->key,
520 tpi->proto); 522 tpi->proto);
521 if (tunnel) { 523 if (tunnel) {
522 if (__iptunnel_pull_header(skb, sizeof(*ershdr), 524 int len = erspan_hdr_len(ver);
525
526 if (unlikely(!pskb_may_pull(skb, len)))
527 return -ENOMEM;
528
529 if (__iptunnel_pull_header(skb, len,
523 htons(ETH_P_TEB), 530 htons(ETH_P_TEB),
524 false, false) < 0) 531 false, false) < 0)
525 return PACKET_REJECT; 532 return PACKET_REJECT;
@@ -545,14 +552,29 @@ static int ip6erspan_rcv(struct sk_buff *skb, int gre_hdr_len,
545 if (!md) 552 if (!md)
546 return PACKET_REJECT; 553 return PACKET_REJECT;
547 554
548 md->index = index; 555 memcpy(md, pkt_md, sizeof(*md));
556 md->version = ver;
549 info->key.tun_flags |= TUNNEL_ERSPAN_OPT; 557 info->key.tun_flags |= TUNNEL_ERSPAN_OPT;
550 info->options_len = sizeof(*md); 558 info->options_len = sizeof(*md);
551 559
552 ip6_tnl_rcv(tunnel, skb, tpi, tun_dst, log_ecn_error); 560 ip6_tnl_rcv(tunnel, skb, tpi, tun_dst, log_ecn_error);
553 561
554 } else { 562 } else {
555 tunnel->parms.index = ntohl(index); 563 tunnel->parms.erspan_ver = ver;
564
565 if (ver == 1) {
566 tunnel->parms.index = ntohl(pkt_md->u.index);
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;
576 }
577
556 ip6_tnl_rcv(tunnel, skb, tpi, NULL, log_ecn_error); 578 ip6_tnl_rcv(tunnel, skb, tpi, NULL, log_ecn_error);
557 } 579 }
558 580
@@ -575,7 +597,8 @@ static int gre_rcv(struct sk_buff *skb)
575 if (iptunnel_pull_header(skb, hdr_len, tpi.proto, false)) 597 if (iptunnel_pull_header(skb, hdr_len, tpi.proto, false))
576 goto drop; 598 goto drop;
577 599
578 if (unlikely(tpi.proto == htons(ETH_P_ERSPAN))) { 600 if (unlikely(tpi.proto == htons(ETH_P_ERSPAN) ||
601 tpi.proto == htons(ETH_P_ERSPAN2))) {
579 if (ip6erspan_rcv(skb, hdr_len, &tpi) == PACKET_RCVD) 602 if (ip6erspan_rcv(skb, hdr_len, &tpi) == PACKET_RCVD)
580 return 0; 603 return 0;
581 goto drop; 604 goto drop;
@@ -920,9 +943,24 @@ static netdev_tx_t ip6erspan_tunnel_xmit(struct sk_buff *skb,
920 if (!md) 943 if (!md)
921 goto tx_err; 944 goto tx_err;
922 945
923 erspan_build_header(skb, tunnel_id_to_key32(key->tun_id), 946 if (md->version == 1) {
924 ntohl(md->index), truncate, false); 947 erspan_build_header(skb,
925 948 tunnel_id_to_key32(key->tun_id),
949 ntohl(md->u.index), truncate,
950 false);
951 } else if (md->version == 2) {
952 u16 md2_flags;
953 u16 dir, hwid;
954
955 md2_flags = ntohs(md->u.md2.flags);
956 dir = (md2_flags & DIR_MASK) >> DIR_OFFSET;
957 hwid = (md2_flags & HWID_MASK) >> HWID_OFFSET;
958
959 erspan_build_header_v2(skb,
960 tunnel_id_to_key32(key->tun_id),
961 dir, hwid, truncate,
962 false);
963 }
926 } else { 964 } else {
927 switch (skb->protocol) { 965 switch (skb->protocol) {
928 case htons(ETH_P_IP): 966 case htons(ETH_P_IP):
@@ -942,8 +980,15 @@ static netdev_tx_t ip6erspan_tunnel_xmit(struct sk_buff *skb,
942 break; 980 break;
943 } 981 }
944 982
945 erspan_build_header(skb, t->parms.o_key, t->parms.index, 983 if (t->parms.erspan_ver == 1)
946 truncate, false); 984 erspan_build_header(skb, t->parms.o_key,
985 t->parms.index,
986 truncate, false);
987 else
988 erspan_build_header_v2(skb, t->parms.o_key,
989 t->parms.dir,
990 t->parms.hwid,
991 truncate, false);
947 fl6.daddr = t->parms.raddr; 992 fl6.daddr = t->parms.raddr;
948 } 993 }
949 994
@@ -1507,7 +1552,7 @@ static int ip6erspan_tap_validate(struct nlattr *tb[], struct nlattr *data[],
1507 struct netlink_ext_ack *extack) 1552 struct netlink_ext_ack *extack)
1508{ 1553{
1509 __be16 flags = 0; 1554 __be16 flags = 0;
1510 int ret; 1555 int ret, ver = 0;
1511 1556
1512 if (!data) 1557 if (!data)
1513 return 0; 1558 return 0;
@@ -1536,12 +1581,35 @@ static int ip6erspan_tap_validate(struct nlattr *tb[], struct nlattr *data[],
1536 (ntohl(nla_get_be32(data[IFLA_GRE_OKEY])) & ~ID_MASK)) 1581 (ntohl(nla_get_be32(data[IFLA_GRE_OKEY])) & ~ID_MASK))
1537 return -EINVAL; 1582 return -EINVAL;
1538 1583
1539 if (data[IFLA_GRE_ERSPAN_INDEX]) { 1584 if (data[IFLA_GRE_ERSPAN_VER]) {
1540 u32 index = nla_get_u32(data[IFLA_GRE_ERSPAN_INDEX]); 1585 ver = nla_get_u8(data[IFLA_GRE_ERSPAN_VER]);
1541 1586 if (ver != 1 && ver != 2)
1542 if (index & ~INDEX_MASK)
1543 return -EINVAL; 1587 return -EINVAL;
1544 } 1588 }
1589
1590 if (ver == 1) {
1591 if (data[IFLA_GRE_ERSPAN_INDEX]) {
1592 u32 index = nla_get_u32(data[IFLA_GRE_ERSPAN_INDEX]);
1593
1594 if (index & ~INDEX_MASK)
1595 return -EINVAL;
1596 }
1597 } else if (ver == 2) {
1598 if (data[IFLA_GRE_ERSPAN_DIR]) {
1599 u16 dir = nla_get_u8(data[IFLA_GRE_ERSPAN_DIR]);
1600
1601 if (dir & ~(DIR_MASK >> DIR_OFFSET))
1602 return -EINVAL;
1603 }
1604
1605 if (data[IFLA_GRE_ERSPAN_HWID]) {
1606 u16 hwid = nla_get_u16(data[IFLA_GRE_ERSPAN_HWID]);
1607
1608 if (hwid & ~(HWID_MASK >> HWID_OFFSET))
1609 return -EINVAL;
1610 }
1611 }
1612
1545 return 0; 1613 return 0;
1546} 1614}
1547 1615
@@ -1591,11 +1659,21 @@ static void ip6gre_netlink_parms(struct nlattr *data[],
1591 if (data[IFLA_GRE_FWMARK]) 1659 if (data[IFLA_GRE_FWMARK])
1592 parms->fwmark = nla_get_u32(data[IFLA_GRE_FWMARK]); 1660 parms->fwmark = nla_get_u32(data[IFLA_GRE_FWMARK]);
1593 1661
1594 if (data[IFLA_GRE_ERSPAN_INDEX])
1595 parms->index = nla_get_u32(data[IFLA_GRE_ERSPAN_INDEX]);
1596
1597 if (data[IFLA_GRE_COLLECT_METADATA]) 1662 if (data[IFLA_GRE_COLLECT_METADATA])
1598 parms->collect_md = true; 1663 parms->collect_md = true;
1664
1665 if (data[IFLA_GRE_ERSPAN_VER])
1666 parms->erspan_ver = nla_get_u8(data[IFLA_GRE_ERSPAN_VER]);
1667
1668 if (parms->erspan_ver == 1) {
1669 if (data[IFLA_GRE_ERSPAN_INDEX])
1670 parms->index = nla_get_u32(data[IFLA_GRE_ERSPAN_INDEX]);
1671 } else if (parms->erspan_ver == 2) {
1672 if (data[IFLA_GRE_ERSPAN_DIR])
1673 parms->dir = nla_get_u8(data[IFLA_GRE_ERSPAN_DIR]);
1674 if (data[IFLA_GRE_ERSPAN_HWID])
1675 parms->hwid = nla_get_u16(data[IFLA_GRE_ERSPAN_HWID]);
1676 }
1599} 1677}
1600 1678
1601static int ip6gre_tap_init(struct net_device *dev) 1679static int ip6gre_tap_init(struct net_device *dev)
@@ -1657,7 +1735,7 @@ static int ip6erspan_tap_init(struct net_device *dev)
1657 1735
1658 tunnel->tun_hlen = 8; 1736 tunnel->tun_hlen = 8;
1659 tunnel->hlen = tunnel->tun_hlen + tunnel->encap_hlen + 1737 tunnel->hlen = tunnel->tun_hlen + tunnel->encap_hlen +
1660 sizeof(struct erspanhdr); 1738 erspan_hdr_len(tunnel->parms.erspan_ver);
1661 t_hlen = tunnel->hlen + sizeof(struct ipv6hdr); 1739 t_hlen = tunnel->hlen + sizeof(struct ipv6hdr);
1662 1740
1663 dev->hard_header_len = LL_MAX_HEADER + t_hlen; 1741 dev->hard_header_len = LL_MAX_HEADER + t_hlen;
@@ -1925,6 +2003,19 @@ static int ip6gre_fill_info(struct sk_buff *skb, const struct net_device *dev)
1925 goto nla_put_failure; 2003 goto nla_put_failure;
1926 } 2004 }
1927 2005
2006 if (nla_put_u8(skb, IFLA_GRE_ERSPAN_VER, p->erspan_ver))
2007 goto nla_put_failure;
2008
2009 if (p->erspan_ver == 1) {
2010 if (nla_put_u32(skb, IFLA_GRE_ERSPAN_INDEX, p->index))
2011 goto nla_put_failure;
2012 } else if (p->erspan_ver == 2) {
2013 if (nla_put_u8(skb, IFLA_GRE_ERSPAN_DIR, p->dir))
2014 goto nla_put_failure;
2015 if (nla_put_u16(skb, IFLA_GRE_ERSPAN_HWID, p->hwid))
2016 goto nla_put_failure;
2017 }
2018
1928 return 0; 2019 return 0;
1929 2020
1930nla_put_failure: 2021nla_put_failure:
@@ -1950,6 +2041,9 @@ static const struct nla_policy ip6gre_policy[IFLA_GRE_MAX + 1] = {
1950 [IFLA_GRE_COLLECT_METADATA] = { .type = NLA_FLAG }, 2041 [IFLA_GRE_COLLECT_METADATA] = { .type = NLA_FLAG },
1951 [IFLA_GRE_FWMARK] = { .type = NLA_U32 }, 2042 [IFLA_GRE_FWMARK] = { .type = NLA_U32 },
1952 [IFLA_GRE_ERSPAN_INDEX] = { .type = NLA_U32 }, 2043 [IFLA_GRE_ERSPAN_INDEX] = { .type = NLA_U32 },
2044 [IFLA_GRE_ERSPAN_VER] = { .type = NLA_U8 },
2045 [IFLA_GRE_ERSPAN_DIR] = { .type = NLA_U8 },
2046 [IFLA_GRE_ERSPAN_HWID] = { .type = NLA_U16 },
1953}; 2047};
1954 2048
1955static void ip6erspan_tap_setup(struct net_device *dev) 2049static void ip6erspan_tap_setup(struct net_device *dev)
@@ -2071,4 +2165,5 @@ MODULE_AUTHOR("D. Kozlov (xeb@mail.ru)");
2071MODULE_DESCRIPTION("GRE over IPv6 tunneling device"); 2165MODULE_DESCRIPTION("GRE over IPv6 tunneling device");
2072MODULE_ALIAS_RTNL_LINK("ip6gre"); 2166MODULE_ALIAS_RTNL_LINK("ip6gre");
2073MODULE_ALIAS_RTNL_LINK("ip6gretap"); 2167MODULE_ALIAS_RTNL_LINK("ip6gretap");
2168MODULE_ALIAS_RTNL_LINK("ip6erspan");
2074MODULE_ALIAS_NETDEV("ip6gre0"); 2169MODULE_ALIAS_NETDEV("ip6gre0");
diff --git a/net/openvswitch/flow_netlink.c b/net/openvswitch/flow_netlink.c
index 624ea74353dd..bce1f78b0de5 100644
--- a/net/openvswitch/flow_netlink.c
+++ b/net/openvswitch/flow_netlink.c
@@ -644,12 +644,12 @@ static int erspan_tun_opt_from_nlattr(const struct nlattr *attr,
644 BUILD_BUG_ON(sizeof(opts) > sizeof(match->key->tun_opts)); 644 BUILD_BUG_ON(sizeof(opts) > sizeof(match->key->tun_opts));
645 645
646 memset(&opts, 0, sizeof(opts)); 646 memset(&opts, 0, sizeof(opts));
647 opts.index = nla_get_be32(attr); 647 opts.u.index = nla_get_be32(attr);
648 648
649 /* Index has only 20-bit */ 649 /* Index has only 20-bit */
650 if (ntohl(opts.index) & ~INDEX_MASK) { 650 if (ntohl(opts.u.index) & ~INDEX_MASK) {
651 OVS_NLERR(log, "ERSPAN index number %x too large.", 651 OVS_NLERR(log, "ERSPAN index number %x too large.",
652 ntohl(opts.index)); 652 ntohl(opts.u.index));
653 return -EINVAL; 653 return -EINVAL;
654 } 654 }
655 655
@@ -907,7 +907,7 @@ static int __ip_tun_to_nlattr(struct sk_buff *skb,
907 return -EMSGSIZE; 907 return -EMSGSIZE;
908 else if (output->tun_flags & TUNNEL_ERSPAN_OPT && 908 else if (output->tun_flags & TUNNEL_ERSPAN_OPT &&
909 nla_put_be32(skb, OVS_TUNNEL_KEY_ATTR_ERSPAN_OPTS, 909 nla_put_be32(skb, OVS_TUNNEL_KEY_ATTR_ERSPAN_OPTS,
910 ((struct erspan_metadata *)tun_opts)->index)) 910 ((struct erspan_metadata *)tun_opts)->u.index))
911 return -EMSGSIZE; 911 return -EMSGSIZE;
912 } 912 }
913 913
diff --git a/samples/bpf/tcbpf2_kern.c b/samples/bpf/tcbpf2_kern.c
index 79ad061079dd..f6bbf8f50da3 100644
--- a/samples/bpf/tcbpf2_kern.c
+++ b/samples/bpf/tcbpf2_kern.c
@@ -35,12 +35,22 @@ struct geneve_opt {
35 u8 opt_data[8]; /* hard-coded to 8 byte */ 35 u8 opt_data[8]; /* hard-coded to 8 byte */
36}; 36};
37 37
38struct erspan_md2 {
39 __be32 timestamp;
40 __be16 sgt;
41 __be16 flags;
42};
43
38struct vxlan_metadata { 44struct vxlan_metadata {
39 u32 gbp; 45 u32 gbp;
40}; 46};
41 47
42struct erspan_metadata { 48struct erspan_metadata {
43 __be32 index; 49 union {
50 __be32 index;
51 struct erspan_md2 md2;
52 } u;
53 int version;
44}; 54};
45 55
46SEC("gre_set_tunnel") 56SEC("gre_set_tunnel")
@@ -143,7 +153,18 @@ int _erspan_set_tunnel(struct __sk_buff *skb)
143 return TC_ACT_SHOT; 153 return TC_ACT_SHOT;
144 } 154 }
145 155
146 md.index = htonl(123); 156 __builtin_memset(&md, 0, sizeof(md));
157#ifdef ERSPAN_V1
158 md.version = 1;
159 md.u.index = htonl(123);
160#else
161 u8 direction = 1;
162 u16 hwid = 7;
163
164 md.version = 2;
165 md.u.md2.flags = htons((direction << 3) | (hwid << 4));
166#endif
167
147 ret = bpf_skb_set_tunnel_opt(skb, &md, sizeof(md)); 168 ret = bpf_skb_set_tunnel_opt(skb, &md, sizeof(md));
148 if (ret < 0) { 169 if (ret < 0) {
149 ERROR(ret); 170 ERROR(ret);
@@ -156,7 +177,7 @@ int _erspan_set_tunnel(struct __sk_buff *skb)
156SEC("erspan_get_tunnel") 177SEC("erspan_get_tunnel")
157int _erspan_get_tunnel(struct __sk_buff *skb) 178int _erspan_get_tunnel(struct __sk_buff *skb)
158{ 179{
159 char fmt[] = "key %d remote ip 0x%x erspan index 0x%x\n"; 180 char fmt[] = "key %d remote ip 0x%x erspan version %d\n";
160 struct bpf_tunnel_key key; 181 struct bpf_tunnel_key key;
161 struct erspan_metadata md; 182 struct erspan_metadata md;
162 u32 index; 183 u32 index;
@@ -174,9 +195,22 @@ int _erspan_get_tunnel(struct __sk_buff *skb)
174 return TC_ACT_SHOT; 195 return TC_ACT_SHOT;
175 } 196 }
176 197
177 index = bpf_ntohl(md.index);
178 bpf_trace_printk(fmt, sizeof(fmt), 198 bpf_trace_printk(fmt, sizeof(fmt),
179 key.tunnel_id, key.remote_ipv4, index); 199 key.tunnel_id, key.remote_ipv4, md.version);
200
201#ifdef ERSPAN_V1
202 char fmt2[] = "\tindex %x\n";
203
204 index = bpf_ntohl(md.u.index);
205 bpf_trace_printk(fmt2, sizeof(fmt2), index);
206#else
207 char fmt2[] = "\tdirection %d hwid %x timestamp %u\n";
208
209 bpf_trace_printk(fmt2, sizeof(fmt2),
210 (ntohs(md.u.md2.flags) >> 3) & 0x1,
211 (ntohs(md.u.md2.flags) >> 4) & 0x3f,
212 bpf_ntohl(md.u.md2.timestamp));
213#endif
180 214
181 return TC_ACT_OK; 215 return TC_ACT_OK;
182} 216}
@@ -201,7 +235,19 @@ int _ip4ip6erspan_set_tunnel(struct __sk_buff *skb)
201 return TC_ACT_SHOT; 235 return TC_ACT_SHOT;
202 } 236 }
203 237
204 md.index = htonl(123); 238 __builtin_memset(&md, 0, sizeof(md));
239
240#ifdef ERSPAN_V1
241 md.u.index = htonl(123);
242 md.version = 1;
243#else
244 u8 direction = 0;
245 u16 hwid = 17;
246
247 md.version = 2;
248 md.u.md2.flags = htons((direction << 3) | (hwid << 4));
249#endif
250
205 ret = bpf_skb_set_tunnel_opt(skb, &md, sizeof(md)); 251 ret = bpf_skb_set_tunnel_opt(skb, &md, sizeof(md));
206 if (ret < 0) { 252 if (ret < 0) {
207 ERROR(ret); 253 ERROR(ret);
@@ -214,7 +260,7 @@ int _ip4ip6erspan_set_tunnel(struct __sk_buff *skb)
214SEC("ip4ip6erspan_get_tunnel") 260SEC("ip4ip6erspan_get_tunnel")
215int _ip4ip6erspan_get_tunnel(struct __sk_buff *skb) 261int _ip4ip6erspan_get_tunnel(struct __sk_buff *skb)
216{ 262{
217 char fmt[] = "key %d remote ip6 ::%x erspan index 0x%x\n"; 263 char fmt[] = "ip6erspan get key %d remote ip6 ::%x erspan version %d\n";
218 struct bpf_tunnel_key key; 264 struct bpf_tunnel_key key;
219 struct erspan_metadata md; 265 struct erspan_metadata md;
220 u32 index; 266 u32 index;
@@ -232,9 +278,22 @@ int _ip4ip6erspan_get_tunnel(struct __sk_buff *skb)
232 return TC_ACT_SHOT; 278 return TC_ACT_SHOT;
233 } 279 }
234 280
235 index = bpf_ntohl(md.index);
236 bpf_trace_printk(fmt, sizeof(fmt), 281 bpf_trace_printk(fmt, sizeof(fmt),
237 key.tunnel_id, key.remote_ipv6[0], index); 282 key.tunnel_id, key.remote_ipv4, md.version);
283
284#ifdef ERSPAN_V1
285 char fmt2[] = "\tindex %x\n";
286
287 index = bpf_ntohl(md.u.index);
288 bpf_trace_printk(fmt2, sizeof(fmt2), index);
289#else
290 char fmt2[] = "\tdirection %d hwid %x timestamp %u\n";
291
292 bpf_trace_printk(fmt2, sizeof(fmt2),
293 (ntohs(md.u.md2.flags) >> 3) & 0x1,
294 (ntohs(md.u.md2.flags) >> 4) & 0x3f,
295 bpf_ntohl(md.u.md2.timestamp));
296#endif
238 297
239 return TC_ACT_OK; 298 return TC_ACT_OK;
240} 299}
diff --git a/samples/bpf/test_tunnel_bpf.sh b/samples/bpf/test_tunnel_bpf.sh
index f53efb62f699..ae7f7c38309b 100755
--- a/samples/bpf/test_tunnel_bpf.sh
+++ b/samples/bpf/test_tunnel_bpf.sh
@@ -59,8 +59,17 @@ function add_ip6gretap_tunnel {
59 59
60function add_erspan_tunnel { 60function add_erspan_tunnel {
61 # in namespace 61 # in namespace
62 ip netns exec at_ns0 \ 62 if [ "$1" == "v1" ]; then
63 ip link add dev $DEV_NS type $TYPE seq key 2 local 172.16.1.100 remote 172.16.1.200 erspan 123 63 ip netns exec at_ns0 \
64 ip link add dev $DEV_NS type $TYPE seq key 2 \
65 local 172.16.1.100 remote 172.16.1.200 \
66 erspan_ver 1 erspan 123
67 else
68 ip netns exec at_ns0 \
69 ip link add dev $DEV_NS type $TYPE seq key 2 \
70 local 172.16.1.100 remote 172.16.1.200 \
71 erspan_ver 2 erspan_dir 1 erspan_hwid 3
72 fi
64 ip netns exec at_ns0 ip link set dev $DEV_NS up 73 ip netns exec at_ns0 ip link set dev $DEV_NS up
65 ip netns exec at_ns0 ip addr add dev $DEV_NS 10.1.1.100/24 74 ip netns exec at_ns0 ip addr add dev $DEV_NS 10.1.1.100/24
66 75
@@ -79,10 +88,17 @@ function add_ip6erspan_tunnel {
79 ip link set dev veth1 up 88 ip link set dev veth1 up
80 89
81 # in namespace 90 # in namespace
82 ip netns exec at_ns0 \ 91 if [ "$1" == "v1" ]; then
83 ip link add dev $DEV_NS type $TYPE seq key 2 erspan 123 \ 92 ip netns exec at_ns0 \
84 local ::11 remote ::22 93 ip link add dev $DEV_NS type $TYPE seq key 2 \
85 94 local ::11 remote ::22 \
95 erspan_ver 1 erspan 123
96 else
97 ip netns exec at_ns0 \
98 ip link add dev $DEV_NS type $TYPE seq key 2 \
99 local ::11 remote ::22 \
100 erspan_ver 2 erspan_dir 1 erspan_hwid 7
101 fi
86 ip netns exec at_ns0 ip addr add dev $DEV_NS 10.1.1.100/24 102 ip netns exec at_ns0 ip addr add dev $DEV_NS 10.1.1.100/24
87 ip netns exec at_ns0 ip link set dev $DEV_NS up 103 ip netns exec at_ns0 ip link set dev $DEV_NS up
88 104
@@ -199,7 +215,7 @@ function test_erspan {
199 DEV_NS=erspan00 215 DEV_NS=erspan00
200 DEV=erspan11 216 DEV=erspan11
201 config_device 217 config_device
202 add_erspan_tunnel 218 add_erspan_tunnel $1
203 attach_bpf $DEV erspan_set_tunnel erspan_get_tunnel 219 attach_bpf $DEV erspan_set_tunnel erspan_get_tunnel
204 ping -c 1 10.1.1.100 220 ping -c 1 10.1.1.100
205 ip netns exec at_ns0 ping -c 1 10.1.1.200 221 ip netns exec at_ns0 ping -c 1 10.1.1.200
@@ -211,7 +227,7 @@ function test_ip6erspan {
211 DEV_NS=ip6erspan00 227 DEV_NS=ip6erspan00
212 DEV=ip6erspan11 228 DEV=ip6erspan11
213 config_device 229 config_device
214 add_ip6erspan_tunnel 230 add_ip6erspan_tunnel $1
215 attach_bpf $DEV ip4ip6erspan_set_tunnel ip4ip6erspan_get_tunnel 231 attach_bpf $DEV ip4ip6erspan_set_tunnel ip4ip6erspan_get_tunnel
216 ping6 -c 3 ::11 232 ping6 -c 3 ::11
217 ip netns exec at_ns0 ping -c 1 10.1.1.200 233 ip netns exec at_ns0 ping -c 1 10.1.1.200
@@ -288,9 +304,11 @@ test_ip6gre
288echo "Testing IP6GRETAP tunnel..." 304echo "Testing IP6GRETAP tunnel..."
289test_ip6gretap 305test_ip6gretap
290echo "Testing ERSPAN tunnel..." 306echo "Testing ERSPAN tunnel..."
291test_erspan 307test_erspan v1
308test_erspan v2
292echo "Testing IP6ERSPAN tunnel..." 309echo "Testing IP6ERSPAN tunnel..."
293test_ip6erspan 310test_ip6erspan v1
311test_ip6erspan v2
294echo "Testing VXLAN tunnel..." 312echo "Testing VXLAN tunnel..."
295test_vxlan 313test_vxlan
296echo "Testing GENEVE tunnel..." 314echo "Testing GENEVE tunnel..."