aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorWilliam Tu <u9012063@gmail.com>2017-12-13 19:38:56 -0500
committerDavid S. Miller <davem@davemloft.net>2017-12-15 12:34:00 -0500
commitf551c91de262ba36b20c3ac19538afb4f4507441 (patch)
treeb8f61c416c07b251d64e0780999243482b2b7b99
parent1d7e2ed22f8d9171fa8b629754022f22115b3f03 (diff)
net: erspan: introduce erspan v2 for ip_gre
The patch adds support for erspan version 2. Not all features are supported in this patch. The SGT (security group tag), GRA (timestamp granularity), FT (frame type) are set to fixed value. Only hardware ID and direction are configurable. Optional subheader is also not supported. Signed-off-by: William Tu <u9012063@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--include/net/erspan.h120
-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.c105
5 files changed, 216 insertions, 18 deletions
diff --git a/include/net/erspan.h b/include/net/erspan.h
index 70c40c7c75b2..acdf6843095d 100644
--- a/include/net/erspan.h
+++ b/include/net/erspan.h
@@ -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 /* ERSPAN type II */ 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 */
@@ -48,8 +88,10 @@ enum erspan_encap_type {
48#define ERSPAN_V2_MDSIZE 8 88#define ERSPAN_V2_MDSIZE 8
49struct erspan_metadata { 89struct erspan_metadata {
50 union { 90 union {
51 __be32 index; /* Version 1 (type II)*/ 91 __be32 index; /* Version 1 (type II)*/
92 struct erspan_md2 md2; /* Version 2 (type III) */
52 } u; 93 } u;
94 int version;
53}; 95};
54 96
55struct erspan_base_hdr { 97struct erspan_base_hdr {
@@ -58,6 +100,7 @@ struct erspan_base_hdr {
58 __be16 session_id; 100 __be16 session_id;
59#define COS_OFFSET 13 101#define COS_OFFSET 13
60#define EN_OFFSET 11 102#define EN_OFFSET 11
103#define BSO_OFFSET EN_OFFSET
61#define T_OFFSET 10 104#define T_OFFSET 10
62}; 105};
63 106
@@ -123,4 +166,77 @@ static inline void erspan_build_header(struct sk_buff *skb,
123 ersmd->u.index = htonl(index & INDEX_MASK); 166 ersmd->u.index = htonl(index & INDEX_MASK);
124} 167}
125 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));
240}
241
126#endif 242#endif
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 3e37402147f3..004800b923c6 100644
--- a/net/ipv4/ip_gre.c
+++ b/net/ipv4/ip_gre.c
@@ -315,11 +315,26 @@ static int erspan_rcv(struct sk_buff *skb, struct tnl_ptk_info *tpi,
315 return PACKET_REJECT; 315 return PACKET_REJECT;
316 316
317 memcpy(md, pkt_md, sizeof(*md)); 317 memcpy(md, pkt_md, sizeof(*md));
318 md->version = ver;
319
318 info = &tun_dst->u.tun_info; 320 info = &tun_dst->u.tun_info;
319 info->key.tun_flags |= TUNNEL_ERSPAN_OPT; 321 info->key.tun_flags |= TUNNEL_ERSPAN_OPT;
320 info->options_len = sizeof(*md); 322 info->options_len = sizeof(*md);
321 } else { 323 } else {
322 tunnel->index = ntohl(pkt_md->u.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
323 } 338 }
324 339
325 skb_reset_mac_header(skb); 340 skb_reset_mac_header(skb);
@@ -413,7 +428,8 @@ static int gre_rcv(struct sk_buff *skb)
413 if (hdr_len < 0) 428 if (hdr_len < 0)
414 goto drop; 429 goto drop;
415 430
416 if (unlikely(tpi.proto == htons(ETH_P_ERSPAN))) { 431 if (unlikely(tpi.proto == htons(ETH_P_ERSPAN) ||
432 tpi.proto == htons(ETH_P_ERSPAN2))) {
417 if (erspan_rcv(skb, &tpi, hdr_len) == PACKET_RCVD) 433 if (erspan_rcv(skb, &tpi, hdr_len) == PACKET_RCVD)
418 return 0; 434 return 0;
419 } 435 }
@@ -568,6 +584,7 @@ static void erspan_fb_xmit(struct sk_buff *skb, struct net_device *dev,
568 bool truncate = false; 584 bool truncate = false;
569 struct flowi4 fl; 585 struct flowi4 fl;
570 int tunnel_hlen; 586 int tunnel_hlen;
587 int version;
571 __be16 df; 588 __be16 df;
572 589
573 tun_info = skb_tunnel_info(skb); 590 tun_info = skb_tunnel_info(skb);
@@ -576,9 +593,13 @@ static void erspan_fb_xmit(struct sk_buff *skb, struct net_device *dev,
576 goto err_free_skb; 593 goto err_free_skb;
577 594
578 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;
579 599
580 /* ERSPAN has fixed 8 byte GRE header */ 600 /* ERSPAN has fixed 8 byte GRE header */
581 tunnel_hlen = 8 + sizeof(struct erspan_base_hdr) + ERSPAN_V1_MDSIZE; 601 version = md->version;
602 tunnel_hlen = 8 + erspan_hdr_len(version);
582 603
583 rt = prepare_fb_xmit(skb, dev, &fl, tunnel_hlen); 604 rt = prepare_fb_xmit(skb, dev, &fl, tunnel_hlen);
584 if (!rt) 605 if (!rt)
@@ -592,12 +613,23 @@ static void erspan_fb_xmit(struct sk_buff *skb, struct net_device *dev,
592 truncate = true; 613 truncate = true;
593 } 614 }
594 615
595 md = ip_tunnel_info_opts(tun_info); 616 if (version == 1) {
596 if (!md) 617 erspan_build_header(skb, tunnel_id_to_key32(key->tun_id),
597 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;
598 623
599 erspan_build_header(skb, tunnel_id_to_key32(key->tun_id), 624 md2_flags = ntohs(md->u.md2.flags);
600 ntohl(md->u.index), truncate, true); 625 direction = (md2_flags & DIR_MASK) >> DIR_OFFSET;
626 hwid = (md2_flags & HWID_MASK) >> HWID_OFFSET;
627
628 erspan_build_header_v2(skb, tunnel_id_to_key32(key->tun_id),
629 direction, hwid, truncate, true);
630 } else {
631 goto err_free_rt;
632 }
601 633
602 gre_build_header(skb, 8, TUNNEL_SEQ, 634 gre_build_header(skb, 8, TUNNEL_SEQ,
603 htons(ETH_P_ERSPAN), 0, htonl(tunnel->o_seqno++)); 635 htons(ETH_P_ERSPAN), 0, htonl(tunnel->o_seqno++));
@@ -699,8 +731,14 @@ static netdev_tx_t erspan_xmit(struct sk_buff *skb,
699 } 731 }
700 732
701 /* Push ERSPAN header */ 733 /* Push ERSPAN header */
702 erspan_build_header(skb, tunnel->parms.o_key, tunnel->index, 734 if (tunnel->erspan_ver == 1)
703 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
704 tunnel->parms.o_flags &= ~TUNNEL_KEY; 742 tunnel->parms.o_flags &= ~TUNNEL_KEY;
705 __gre_xmit(skb, dev, &tunnel->parms.iph, htons(ETH_P_ERSPAN)); 743 __gre_xmit(skb, dev, &tunnel->parms.iph, htons(ETH_P_ERSPAN));
706 return NETDEV_TX_OK; 744 return NETDEV_TX_OK;
@@ -1172,13 +1210,32 @@ static int ipgre_netlink_parms(struct net_device *dev,
1172 if (data[IFLA_GRE_FWMARK]) 1210 if (data[IFLA_GRE_FWMARK])
1173 *fwmark = nla_get_u32(data[IFLA_GRE_FWMARK]); 1211 *fwmark = nla_get_u32(data[IFLA_GRE_FWMARK]);
1174 1212
1175 if (data[IFLA_GRE_ERSPAN_INDEX]) { 1213 if (data[IFLA_GRE_ERSPAN_VER]) {
1176 t->index = nla_get_u32(data[IFLA_GRE_ERSPAN_INDEX]); 1214 t->erspan_ver = nla_get_u8(data[IFLA_GRE_ERSPAN_VER]);
1177 1215
1178 if (t->index & ~INDEX_MASK) 1216 if (t->erspan_ver != 1 && t->erspan_ver != 2)
1179 return -EINVAL; 1217 return -EINVAL;
1180 } 1218 }
1181 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
1182 return 0; 1239 return 0;
1183} 1240}
1184 1241
@@ -1245,7 +1302,7 @@ static int erspan_tunnel_init(struct net_device *dev)
1245 tunnel->tun_hlen = 8; 1302 tunnel->tun_hlen = 8;
1246 tunnel->parms.iph.protocol = IPPROTO_GRE; 1303 tunnel->parms.iph.protocol = IPPROTO_GRE;
1247 tunnel->hlen = tunnel->tun_hlen + tunnel->encap_hlen + 1304 tunnel->hlen = tunnel->tun_hlen + tunnel->encap_hlen +
1248 sizeof(struct erspan_base_hdr) + ERSPAN_V1_MDSIZE; 1305 erspan_hdr_len(tunnel->erspan_ver);
1249 t_hlen = tunnel->hlen + sizeof(struct iphdr); 1306 t_hlen = tunnel->hlen + sizeof(struct iphdr);
1250 1307
1251 dev->needed_headroom = LL_MAX_HEADER + t_hlen + 4; 1308 dev->needed_headroom = LL_MAX_HEADER + t_hlen + 4;
@@ -1375,6 +1432,12 @@ static size_t ipgre_get_size(const struct net_device *dev)
1375 nla_total_size(4) + 1432 nla_total_size(4) +
1376 /* IFLA_GRE_ERSPAN_INDEX */ 1433 /* IFLA_GRE_ERSPAN_INDEX */
1377 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) +
1378 0; 1441 0;
1379} 1442}
1380 1443
@@ -1417,9 +1480,18 @@ static int ipgre_fill_info(struct sk_buff *skb, const struct net_device *dev)
1417 goto nla_put_failure; 1480 goto nla_put_failure;
1418 } 1481 }
1419 1482
1420 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) {
1421 if (nla_put_u32(skb, IFLA_GRE_ERSPAN_INDEX, t->index)) 1487 if (nla_put_u32(skb, IFLA_GRE_ERSPAN_INDEX, t->index))
1422 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 }
1423 1495
1424 return 0; 1496 return 0;
1425 1497
@@ -1455,6 +1527,9 @@ static const struct nla_policy ipgre_policy[IFLA_GRE_MAX + 1] = {
1455 [IFLA_GRE_IGNORE_DF] = { .type = NLA_U8 }, 1527 [IFLA_GRE_IGNORE_DF] = { .type = NLA_U8 },
1456 [IFLA_GRE_FWMARK] = { .type = NLA_U32 }, 1528 [IFLA_GRE_FWMARK] = { .type = NLA_U32 },
1457 [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 },
1458}; 1533};
1459 1534
1460static struct rtnl_link_ops ipgre_link_ops __read_mostly = { 1535static struct rtnl_link_ops ipgre_link_ops __read_mostly = {