Skip to content

Commit 1d7e2ed

Browse files
williamtudavem330
authored andcommitted
net: erspan: refactor existing erspan code
The patch refactors the existing erspan implementation in order to support erspan version 2, which has additional metadata. So, in stead of having one 'struct erspanhdr' holding erspan version 1, breaks it into 'struct erspan_base_hdr' and 'struct erspan_metadata'. Signed-off-by: William Tu <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 4650b75 commit 1d7e2ed

File tree

4 files changed

+61
-33
lines changed

4 files changed

+61
-33
lines changed

include/net/erspan.h

Lines changed: 24 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
* s, Recur, Flags, Version fields only S (bit 03) is set to 1. The
1616
* other fields are set to zero, so only a sequence number follows.
1717
*
18-
* ERSPAN Type II header (8 octets [42:49])
18+
* ERSPAN Version 1 (Type II) header (8 octets [42:49])
1919
* 0 1 2 3
2020
* 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
2121
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
@@ -27,7 +27,7 @@
2727
* GRE proto ERSPAN type II = 0x88BE, type III = 0x22EB
2828
*/
2929

30-
#define ERSPAN_VERSION 0x1
30+
#define ERSPAN_VERSION 0x1 /* ERSPAN type II */
3131

3232
#define VER_MASK 0xf000
3333
#define VLAN_MASK 0x0fff
@@ -44,20 +44,29 @@ enum erspan_encap_type {
4444
ERSPAN_ENCAP_INFRAME = 0x3, /* VLAN tag perserved in frame */
4545
};
4646

47+
#define ERSPAN_V1_MDSIZE 4
48+
#define ERSPAN_V2_MDSIZE 8
4749
struct erspan_metadata {
48-
__be32 index; /* type II */
50+
union {
51+
__be32 index; /* Version 1 (type II)*/
52+
} u;
4953
};
5054

51-
struct erspanhdr {
55+
struct erspan_base_hdr {
5256
__be16 ver_vlan;
5357
#define VER_OFFSET 12
5458
__be16 session_id;
5559
#define COS_OFFSET 13
5660
#define EN_OFFSET 11
5761
#define T_OFFSET 10
58-
struct erspan_metadata md;
5962
};
6063

64+
static inline int erspan_hdr_len(int version)
65+
{
66+
return sizeof(struct erspan_base_hdr) +
67+
(version == 1 ? ERSPAN_V1_MDSIZE : ERSPAN_V2_MDSIZE);
68+
}
69+
6170
static inline u8 tos_to_cos(u8 tos)
6271
{
6372
u8 dscp, cos;
@@ -73,7 +82,8 @@ static inline void erspan_build_header(struct sk_buff *skb,
7382
{
7483
struct ethhdr *eth = eth_hdr(skb);
7584
enum erspan_encap_type enc_type;
76-
struct erspanhdr *ershdr;
85+
struct erspan_base_hdr *ershdr;
86+
struct erspan_metadata *ersmd;
7787
struct qtag_prefix {
7888
__be16 eth_type;
7989
__be16 tci;
@@ -96,17 +106,21 @@ static inline void erspan_build_header(struct sk_buff *skb,
96106
enc_type = ERSPAN_ENCAP_INFRAME;
97107
}
98108

99-
skb_push(skb, sizeof(*ershdr));
100-
ershdr = (struct erspanhdr *)skb->data;
101-
memset(ershdr, 0, sizeof(*ershdr));
109+
skb_push(skb, sizeof(*ershdr) + ERSPAN_V1_MDSIZE);
110+
ershdr = (struct erspan_base_hdr *)skb->data;
111+
memset(ershdr, 0, sizeof(*ershdr) + ERSPAN_V1_MDSIZE);
102112

113+
/* Build base header */
103114
ershdr->ver_vlan = htons((vlan_tci & VLAN_MASK) |
104115
(ERSPAN_VERSION << VER_OFFSET));
105116
ershdr->session_id = htons((u16)(ntohl(id) & ID_MASK) |
106117
((tos_to_cos(tos) << COS_OFFSET) & COS_MASK) |
107118
(enc_type << EN_OFFSET & EN_MASK) |
108119
((truncate << T_OFFSET) & T_MASK));
109-
ershdr->md.index = htonl(index & INDEX_MASK);
120+
121+
/* Build metadata */
122+
ersmd = (struct erspan_metadata *)(ershdr + 1);
123+
ersmd->u.index = htonl(index & INDEX_MASK);
110124
}
111125

112126
#endif

net/ipv4/ip_gre.c

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -256,34 +256,41 @@ static int erspan_rcv(struct sk_buff *skb, struct tnl_ptk_info *tpi,
256256
{
257257
struct net *net = dev_net(skb->dev);
258258
struct metadata_dst *tun_dst = NULL;
259+
struct erspan_base_hdr *ershdr;
260+
struct erspan_metadata *pkt_md;
259261
struct ip_tunnel_net *itn;
260262
struct ip_tunnel *tunnel;
261-
struct erspanhdr *ershdr;
262263
const struct iphdr *iph;
263-
__be32 index;
264+
int ver;
264265
int len;
265266

266267
itn = net_generic(net, erspan_net_id);
267268
len = gre_hdr_len + sizeof(*ershdr);
268269

270+
/* Check based hdr len */
269271
if (unlikely(!pskb_may_pull(skb, len)))
270272
return -ENOMEM;
271273

272274
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;
274277

275278
/* The original GRE header does not have key field,
276279
* Use ERSPAN 10-bit session ID as key.
277280
*/
278281
tpi->key = cpu_to_be32(ntohs(ershdr->session_id) & ID_MASK);
279-
index = ershdr->md.index;
282+
pkt_md = (struct erspan_metadata *)(ershdr + 1);
280283
tunnel = ip_tunnel_lookup(itn, skb->dev->ifindex,
281284
tpi->flags | TUNNEL_KEY,
282285
iph->saddr, iph->daddr, tpi->key);
283286

284287
if (tunnel) {
288+
len = gre_hdr_len + erspan_hdr_len(ver);
289+
if (unlikely(!pskb_may_pull(skb, len)))
290+
return -ENOMEM;
291+
285292
if (__iptunnel_pull_header(skb,
286-
gre_hdr_len + sizeof(*ershdr),
293+
len,
287294
htons(ETH_P_TEB),
288295
false, false) < 0)
289296
goto drop;
@@ -307,12 +314,12 @@ static int erspan_rcv(struct sk_buff *skb, struct tnl_ptk_info *tpi,
307314
if (!md)
308315
return PACKET_REJECT;
309316

310-
md->index = index;
317+
memcpy(md, pkt_md, sizeof(*md));
311318
info = &tun_dst->u.tun_info;
312319
info->key.tun_flags |= TUNNEL_ERSPAN_OPT;
313320
info->options_len = sizeof(*md);
314321
} else {
315-
tunnel->index = ntohl(index);
322+
tunnel->index = ntohl(pkt_md->u.index);
316323
}
317324

318325
skb_reset_mac_header(skb);
@@ -571,7 +578,7 @@ static void erspan_fb_xmit(struct sk_buff *skb, struct net_device *dev,
571578
key = &tun_info->key;
572579

573580
/* ERSPAN has fixed 8 byte GRE header */
574-
tunnel_hlen = 8 + sizeof(struct erspanhdr);
581+
tunnel_hlen = 8 + sizeof(struct erspan_base_hdr) + ERSPAN_V1_MDSIZE;
575582

576583
rt = prepare_fb_xmit(skb, dev, &fl, tunnel_hlen);
577584
if (!rt)
@@ -590,7 +597,7 @@ static void erspan_fb_xmit(struct sk_buff *skb, struct net_device *dev,
590597
goto err_free_rt;
591598

592599
erspan_build_header(skb, tunnel_id_to_key32(key->tun_id),
593-
ntohl(md->index), truncate, true);
600+
ntohl(md->u.index), truncate, true);
594601

595602
gre_build_header(skb, 8, TUNNEL_SEQ,
596603
htons(ETH_P_ERSPAN), 0, htonl(tunnel->o_seqno++));
@@ -1238,7 +1245,7 @@ static int erspan_tunnel_init(struct net_device *dev)
12381245
tunnel->tun_hlen = 8;
12391246
tunnel->parms.iph.protocol = IPPROTO_GRE;
12401247
tunnel->hlen = tunnel->tun_hlen + tunnel->encap_hlen +
1241-
sizeof(struct erspanhdr);
1248+
sizeof(struct erspan_base_hdr) + ERSPAN_V1_MDSIZE;
12421249
t_hlen = tunnel->hlen + sizeof(struct iphdr);
12431250

12441251
dev->needed_headroom = LL_MAX_HEADER + t_hlen + 4;

net/ipv6/ip6_gre.c

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -501,25 +501,32 @@ static int ip6gre_rcv(struct sk_buff *skb, const struct tnl_ptk_info *tpi)
501501
static int ip6erspan_rcv(struct sk_buff *skb, int gre_hdr_len,
502502
struct tnl_ptk_info *tpi)
503503
{
504+
struct erspan_base_hdr *ershdr;
505+
struct erspan_metadata *pkt_md;
504506
const struct ipv6hdr *ipv6h;
505-
struct erspanhdr *ershdr;
506507
struct ip6_tnl *tunnel;
507-
__be32 index;
508+
u8 ver;
508509

509510
ipv6h = ipv6_hdr(skb);
510-
ershdr = (struct erspanhdr *)skb->data;
511+
ershdr = (struct erspan_base_hdr *)skb->data;
511512

512513
if (unlikely(!pskb_may_pull(skb, sizeof(*ershdr))))
513514
return PACKET_REJECT;
514515

516+
ver = (ntohs(ershdr->ver_vlan) & VER_MASK) >> VER_OFFSET;
515517
tpi->key = cpu_to_be32(ntohs(ershdr->session_id) & ID_MASK);
516-
index = ershdr->md.index;
518+
pkt_md = (struct erspan_metadata *)(ershdr + 1);
517519

518520
tunnel = ip6gre_tunnel_lookup(skb->dev,
519521
&ipv6h->saddr, &ipv6h->daddr, tpi->key,
520522
tpi->proto);
521523
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,
523530
htons(ETH_P_TEB),
524531
false, false) < 0)
525532
return PACKET_REJECT;
@@ -545,14 +552,14 @@ static int ip6erspan_rcv(struct sk_buff *skb, int gre_hdr_len,
545552
if (!md)
546553
return PACKET_REJECT;
547554

548-
md->index = index;
555+
memcpy(md, pkt_md, sizeof(*md));
549556
info->key.tun_flags |= TUNNEL_ERSPAN_OPT;
550557
info->options_len = sizeof(*md);
551558

552559
ip6_tnl_rcv(tunnel, skb, tpi, tun_dst, log_ecn_error);
553560

554561
} else {
555-
tunnel->parms.index = ntohl(index);
562+
tunnel->parms.index = ntohl(pkt_md->u.index);
556563
ip6_tnl_rcv(tunnel, skb, tpi, NULL, log_ecn_error);
557564
}
558565

@@ -921,7 +928,7 @@ static netdev_tx_t ip6erspan_tunnel_xmit(struct sk_buff *skb,
921928
goto tx_err;
922929

923930
erspan_build_header(skb, tunnel_id_to_key32(key->tun_id),
924-
ntohl(md->index), truncate, false);
931+
ntohl(md->u.index), truncate, false);
925932

926933
} else {
927934
switch (skb->protocol) {
@@ -1657,7 +1664,7 @@ static int ip6erspan_tap_init(struct net_device *dev)
16571664

16581665
tunnel->tun_hlen = 8;
16591666
tunnel->hlen = tunnel->tun_hlen + tunnel->encap_hlen +
1660-
sizeof(struct erspanhdr);
1667+
sizeof(struct erspan_base_hdr) + ERSPAN_V1_MDSIZE;
16611668
t_hlen = tunnel->hlen + sizeof(struct ipv6hdr);
16621669

16631670
dev->hard_header_len = LL_MAX_HEADER + t_hlen;

net/openvswitch/flow_netlink.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -644,12 +644,12 @@ static int erspan_tun_opt_from_nlattr(const struct nlattr *attr,
644644
BUILD_BUG_ON(sizeof(opts) > sizeof(match->key->tun_opts));
645645

646646
memset(&opts, 0, sizeof(opts));
647-
opts.index = nla_get_be32(attr);
647+
opts.u.index = nla_get_be32(attr);
648648

649649
/* Index has only 20-bit */
650-
if (ntohl(opts.index) & ~INDEX_MASK) {
650+
if (ntohl(opts.u.index) & ~INDEX_MASK) {
651651
OVS_NLERR(log, "ERSPAN index number %x too large.",
652-
ntohl(opts.index));
652+
ntohl(opts.u.index));
653653
return -EINVAL;
654654
}
655655

@@ -907,7 +907,7 @@ static int __ip_tun_to_nlattr(struct sk_buff *skb,
907907
return -EMSGSIZE;
908908
else if (output->tun_flags & TUNNEL_ERSPAN_OPT &&
909909
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))
911911
return -EMSGSIZE;
912912
}
913913

0 commit comments

Comments
 (0)