Skip to content

Commit e20d4ff

Browse files
lxindavem330
authored andcommitted
net: sched: add erspan option support to act_tunnel_key
This patch is to allow setting erspan options using the act_tunnel_key action. Different from geneve options, only one option can be set. And also, geneve options, vxlan options or erspan options can't be set at the same time. Options are expressed as ver:index:dir:hwid, when ver is set to 1, index will be applied while dir and hwid will be ignored, and when ver is set to 2, dir and hwid will be used while index will be ignored. # ip link add name erspan1 type erspan external # tc qdisc add dev eth0 ingress # tc filter add dev eth0 protocol ip parent ffff: \ flower indev eth0 \ ip_proto udp \ action tunnel_key \ set src_ip 10.0.99.192 \ dst_ip 10.0.99.193 \ dst_port 6081 \ id 11 \ erspan_opts 1:2:0:0 \ action mirred egress redirect dev erspan1 v1->v2: - do the validation when dst is not yet allocated as Jakub suggested. - use Duplicate instead of Wrong in err msg for extack. Signed-off-by: Xin Long <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent fca3f91 commit e20d4ff

File tree

2 files changed

+134
-0
lines changed

2 files changed

+134
-0
lines changed

include/uapi/linux/tc_act/tc_tunnel_key.h

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,10 @@ enum {
5454
* TCA_TUNNEL_KEY_ENC_OPTS_
5555
* attributes
5656
*/
57+
TCA_TUNNEL_KEY_ENC_OPTS_ERSPAN, /* Nested
58+
* TCA_TUNNEL_KEY_ENC_OPTS_
59+
* attributes
60+
*/
5761
__TCA_TUNNEL_KEY_ENC_OPTS_MAX,
5862
};
5963

@@ -80,4 +84,16 @@ enum {
8084
#define TCA_TUNNEL_KEY_ENC_OPT_VXLAN_MAX \
8185
(__TCA_TUNNEL_KEY_ENC_OPT_VXLAN_MAX - 1)
8286

87+
enum {
88+
TCA_TUNNEL_KEY_ENC_OPT_ERSPAN_UNSPEC,
89+
TCA_TUNNEL_KEY_ENC_OPT_ERSPAN_VER, /* u8 */
90+
TCA_TUNNEL_KEY_ENC_OPT_ERSPAN_INDEX, /* be32 */
91+
TCA_TUNNEL_KEY_ENC_OPT_ERSPAN_DIR, /* u8 */
92+
TCA_TUNNEL_KEY_ENC_OPT_ERSPAN_HWID, /* u8 */
93+
__TCA_TUNNEL_KEY_ENC_OPT_ERSPAN_MAX,
94+
};
95+
96+
#define TCA_TUNNEL_KEY_ENC_OPT_ERSPAN_MAX \
97+
(__TCA_TUNNEL_KEY_ENC_OPT_ERSPAN_MAX - 1)
98+
8399
#endif

net/sched/act_tunnel_key.c

Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
#include <linux/rtnetlink.h>
1212
#include <net/geneve.h>
1313
#include <net/vxlan.h>
14+
#include <net/erspan.h>
1415
#include <net/netlink.h>
1516
#include <net/pkt_sched.h>
1617
#include <net/dst.h>
@@ -58,6 +59,7 @@ enc_opts_policy[TCA_TUNNEL_KEY_ENC_OPTS_MAX + 1] = {
5859
.strict_start_type = TCA_TUNNEL_KEY_ENC_OPTS_VXLAN },
5960
[TCA_TUNNEL_KEY_ENC_OPTS_GENEVE] = { .type = NLA_NESTED },
6061
[TCA_TUNNEL_KEY_ENC_OPTS_VXLAN] = { .type = NLA_NESTED },
62+
[TCA_TUNNEL_KEY_ENC_OPTS_ERSPAN] = { .type = NLA_NESTED },
6163
};
6264

6365
static const struct nla_policy
@@ -73,6 +75,14 @@ vxlan_opt_policy[TCA_TUNNEL_KEY_ENC_OPT_VXLAN_MAX + 1] = {
7375
[TCA_TUNNEL_KEY_ENC_OPT_VXLAN_GBP] = { .type = NLA_U32 },
7476
};
7577

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+
7686
static int
7787
tunnel_key_copy_geneve_opt(const struct nlattr *nla, void *dst, int dst_len,
7888
struct netlink_ext_ack *extack)
@@ -151,6 +161,59 @@ tunnel_key_copy_vxlan_opt(const struct nlattr *nla, void *dst, int dst_len,
151161
return sizeof(struct vxlan_metadata);
152162
}
153163

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+
154217
static int tunnel_key_copy_opts(const struct nlattr *nla, u8 *dst,
155218
int dst_len, struct netlink_ext_ack *extack)
156219
{
@@ -192,6 +255,18 @@ static int tunnel_key_copy_opts(const struct nlattr *nla, u8 *dst,
192255
opts_len += opt_len;
193256
type = TUNNEL_VXLAN_OPT;
194257
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;
195270
}
196271
}
197272

@@ -234,6 +309,14 @@ static int tunnel_key_opts_set(struct nlattr *nla, struct ip_tunnel_info *info,
234309
opts_len, extack);
235310
#else
236311
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;
237320
#endif
238321
default:
239322
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,
530613
return 0;
531614
}
532615

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+
533647
static int tunnel_key_opts_dump(struct sk_buff *skb,
534648
const struct ip_tunnel_info *info)
535649
{
@@ -551,6 +665,10 @@ static int tunnel_key_opts_dump(struct sk_buff *skb,
551665
err = tunnel_key_vxlan_opts_dump(skb, info);
552666
if (err)
553667
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;
554672
} else {
555673
err_out:
556674
nla_nest_cancel(skb, start);

0 commit comments

Comments
 (0)