11
11
#include <linux/rtnetlink.h>
12
12
#include <net/geneve.h>
13
13
#include <net/vxlan.h>
14
+ #include <net/erspan.h>
14
15
#include <net/netlink.h>
15
16
#include <net/pkt_sched.h>
16
17
#include <net/dst.h>
@@ -58,6 +59,7 @@ enc_opts_policy[TCA_TUNNEL_KEY_ENC_OPTS_MAX + 1] = {
58
59
.strict_start_type = TCA_TUNNEL_KEY_ENC_OPTS_VXLAN },
59
60
[TCA_TUNNEL_KEY_ENC_OPTS_GENEVE ] = { .type = NLA_NESTED },
60
61
[TCA_TUNNEL_KEY_ENC_OPTS_VXLAN ] = { .type = NLA_NESTED },
62
+ [TCA_TUNNEL_KEY_ENC_OPTS_ERSPAN ] = { .type = NLA_NESTED },
61
63
};
62
64
63
65
static const struct nla_policy
@@ -73,6 +75,14 @@ vxlan_opt_policy[TCA_TUNNEL_KEY_ENC_OPT_VXLAN_MAX + 1] = {
73
75
[TCA_TUNNEL_KEY_ENC_OPT_VXLAN_GBP ] = { .type = NLA_U32 },
74
76
};
75
77
78
+ static const struct nla_policy
79
+ erspan_opt_policy [TCA_TUNNEL_KEY_ENC_OPT_ERSPAN_MAX + 1 ] = {
80
+ [TCA_TUNNEL_KEY_ENC_OPT_ERSPAN_VER ] = { .type = NLA_U8 },
81
+ [TCA_TUNNEL_KEY_ENC_OPT_ERSPAN_INDEX ] = { .type = NLA_U32 },
82
+ [TCA_TUNNEL_KEY_ENC_OPT_ERSPAN_DIR ] = { .type = NLA_U8 },
83
+ [TCA_TUNNEL_KEY_ENC_OPT_ERSPAN_HWID ] = { .type = NLA_U8 },
84
+ };
85
+
76
86
static int
77
87
tunnel_key_copy_geneve_opt (const struct nlattr * nla , void * dst , int dst_len ,
78
88
struct netlink_ext_ack * extack )
@@ -151,6 +161,59 @@ tunnel_key_copy_vxlan_opt(const struct nlattr *nla, void *dst, int dst_len,
151
161
return sizeof (struct vxlan_metadata );
152
162
}
153
163
164
+ static int
165
+ tunnel_key_copy_erspan_opt (const struct nlattr * nla , void * dst , int dst_len ,
166
+ struct netlink_ext_ack * extack )
167
+ {
168
+ struct nlattr * tb [TCA_TUNNEL_KEY_ENC_OPT_ERSPAN_MAX + 1 ];
169
+ int err ;
170
+ u8 ver ;
171
+
172
+ err = nla_parse_nested (tb , TCA_TUNNEL_KEY_ENC_OPT_ERSPAN_MAX , nla ,
173
+ erspan_opt_policy , extack );
174
+ if (err < 0 )
175
+ return err ;
176
+
177
+ if (!tb [TCA_TUNNEL_KEY_ENC_OPT_ERSPAN_VER ]) {
178
+ NL_SET_ERR_MSG (extack , "Missing tunnel key erspan option ver" );
179
+ return - EINVAL ;
180
+ }
181
+
182
+ ver = nla_get_u8 (tb [TCA_TUNNEL_KEY_ENC_OPT_ERSPAN_VER ]);
183
+ if (ver == 1 ) {
184
+ if (!tb [TCA_TUNNEL_KEY_ENC_OPT_ERSPAN_INDEX ]) {
185
+ NL_SET_ERR_MSG (extack , "Missing tunnel key erspan option index" );
186
+ return - EINVAL ;
187
+ }
188
+ } else if (ver == 2 ) {
189
+ if (!tb [TCA_TUNNEL_KEY_ENC_OPT_ERSPAN_DIR ] ||
190
+ !tb [TCA_TUNNEL_KEY_ENC_OPT_ERSPAN_HWID ]) {
191
+ NL_SET_ERR_MSG (extack , "Missing tunnel key erspan option dir or hwid" );
192
+ return - EINVAL ;
193
+ }
194
+ } else {
195
+ NL_SET_ERR_MSG (extack , "Tunnel key erspan option ver is incorrect" );
196
+ return - EINVAL ;
197
+ }
198
+
199
+ if (dst ) {
200
+ struct erspan_metadata * md = dst ;
201
+
202
+ md -> version = ver ;
203
+ if (ver == 1 ) {
204
+ nla = tb [TCA_TUNNEL_KEY_ENC_OPT_ERSPAN_INDEX ];
205
+ md -> u .index = nla_get_be32 (nla );
206
+ } else {
207
+ nla = tb [TCA_TUNNEL_KEY_ENC_OPT_ERSPAN_DIR ];
208
+ md -> u .md2 .dir = nla_get_u8 (nla );
209
+ nla = tb [TCA_TUNNEL_KEY_ENC_OPT_ERSPAN_HWID ];
210
+ set_hwid (& md -> u .md2 , nla_get_u8 (nla ));
211
+ }
212
+ }
213
+
214
+ return sizeof (struct erspan_metadata );
215
+ }
216
+
154
217
static int tunnel_key_copy_opts (const struct nlattr * nla , u8 * dst ,
155
218
int dst_len , struct netlink_ext_ack * extack )
156
219
{
@@ -192,6 +255,18 @@ static int tunnel_key_copy_opts(const struct nlattr *nla, u8 *dst,
192
255
opts_len += opt_len ;
193
256
type = TUNNEL_VXLAN_OPT ;
194
257
break ;
258
+ case TCA_TUNNEL_KEY_ENC_OPTS_ERSPAN :
259
+ if (type ) {
260
+ NL_SET_ERR_MSG (extack , "Duplicate type for erspan options" );
261
+ return - EINVAL ;
262
+ }
263
+ opt_len = tunnel_key_copy_erspan_opt (attr , dst ,
264
+ dst_len , extack );
265
+ if (opt_len < 0 )
266
+ return opt_len ;
267
+ opts_len += opt_len ;
268
+ type = TUNNEL_ERSPAN_OPT ;
269
+ break ;
195
270
}
196
271
}
197
272
@@ -234,6 +309,14 @@ static int tunnel_key_opts_set(struct nlattr *nla, struct ip_tunnel_info *info,
234
309
opts_len , extack );
235
310
#else
236
311
return - EAFNOSUPPORT ;
312
+ #endif
313
+ case TCA_TUNNEL_KEY_ENC_OPTS_ERSPAN :
314
+ #if IS_ENABLED (CONFIG_INET )
315
+ info -> key .tun_flags |= TUNNEL_ERSPAN_OPT ;
316
+ return tunnel_key_copy_opts (nla , ip_tunnel_info_opts (info ),
317
+ opts_len , extack );
318
+ #else
319
+ return - EAFNOSUPPORT ;
237
320
#endif
238
321
default :
239
322
NL_SET_ERR_MSG (extack , "Cannot set tunnel options for unknown tunnel type" );
@@ -530,6 +613,37 @@ static int tunnel_key_vxlan_opts_dump(struct sk_buff *skb,
530
613
return 0 ;
531
614
}
532
615
616
+ static int tunnel_key_erspan_opts_dump (struct sk_buff * skb ,
617
+ const struct ip_tunnel_info * info )
618
+ {
619
+ struct erspan_metadata * md = (struct erspan_metadata * )(info + 1 );
620
+ struct nlattr * start ;
621
+
622
+ start = nla_nest_start_noflag (skb , TCA_TUNNEL_KEY_ENC_OPTS_ERSPAN );
623
+ if (!start )
624
+ return - EMSGSIZE ;
625
+
626
+ if (nla_put_u8 (skb , TCA_TUNNEL_KEY_ENC_OPT_ERSPAN_VER , md -> version ))
627
+ goto err ;
628
+
629
+ if (md -> version == 1 &&
630
+ nla_put_be32 (skb , TCA_TUNNEL_KEY_ENC_OPT_ERSPAN_INDEX , md -> u .index ))
631
+ goto err ;
632
+
633
+ if (md -> version == 2 &&
634
+ (nla_put_u8 (skb , TCA_TUNNEL_KEY_ENC_OPT_ERSPAN_DIR ,
635
+ md -> u .md2 .dir ) ||
636
+ nla_put_u8 (skb , TCA_TUNNEL_KEY_ENC_OPT_ERSPAN_HWID ,
637
+ get_hwid (& md -> u .md2 ))))
638
+ goto err ;
639
+
640
+ nla_nest_end (skb , start );
641
+ return 0 ;
642
+ err :
643
+ nla_nest_cancel (skb , start );
644
+ return - EMSGSIZE ;
645
+ }
646
+
533
647
static int tunnel_key_opts_dump (struct sk_buff * skb ,
534
648
const struct ip_tunnel_info * info )
535
649
{
@@ -551,6 +665,10 @@ static int tunnel_key_opts_dump(struct sk_buff *skb,
551
665
err = tunnel_key_vxlan_opts_dump (skb , info );
552
666
if (err )
553
667
goto err_out ;
668
+ } else if (info -> key .tun_flags & TUNNEL_ERSPAN_OPT ) {
669
+ err = tunnel_key_erspan_opts_dump (skb , info );
670
+ if (err )
671
+ goto err_out ;
554
672
} else {
555
673
err_out :
556
674
nla_nest_cancel (skb , start );
0 commit comments