History

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.

Xin Long committed 6 years ago

Commit e20d4ff1 parent fca3f912 files · +134 −0Browse files

Unified · Split

2 files
  1. include/uapi/linux/tc_act/tc_tunnel_key.h +16 −0
  2. net/sched/act_tunnel_key.c +118 −0
include/uapi/linux/tc_act/tc_tunnel_key.h+16−0
@@ -54,6 +54,10 @@ enum { · 53 unmodified lines
54 * TCA_TUNNEL_KEY_ENC_OPTS_54 * TCA_TUNNEL_KEY_ENC_OPTS_
55 * attributes55 * attributes
56 */56 */
57 TCA_TUNNEL_KEY_ENC_OPTS_ERSPAN, /* Nested
58 * TCA_TUNNEL_KEY_ENC_OPTS_
59 * attributes
60 */
57 __TCA_TUNNEL_KEY_ENC_OPTS_MAX,61 __TCA_TUNNEL_KEY_ENC_OPTS_MAX,
58};62};
59 63
@@ -80,4 +84,16 @@ enum { · 20 unmodified lines
80#define TCA_TUNNEL_KEY_ENC_OPT_VXLAN_MAX \84#define TCA_TUNNEL_KEY_ENC_OPT_VXLAN_MAX \
81 (__TCA_TUNNEL_KEY_ENC_OPT_VXLAN_MAX - 1)85 (__TCA_TUNNEL_KEY_ENC_OPT_VXLAN_MAX - 1)
82 86
87enum {
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
83#endif99#endif
net/sched/act_tunnel_key.c+118−0
@@ -11,6 +11,7 @@ · 10 unmodified lines
11#include <linux/rtnetlink.h>11#include <linux/rtnetlink.h>
12#include <net/geneve.h>12#include <net/geneve.h>
13#include <net/vxlan.h>13#include <net/vxlan.h>
14#include <net/erspan.h>
14#include <net/netlink.h>15#include <net/netlink.h>
15#include <net/pkt_sched.h>16#include <net/pkt_sched.h>
16#include <net/dst.h>17#include <net/dst.h>
@@ -58,6 +59,7 @@ enc_opts_policy[TCA_TUNNEL_KEY_ENC_OPTS_MAX + 1] = { · 41 unmodified lines
58 .strict_start_type = TCA_TUNNEL_KEY_ENC_OPTS_VXLAN },59 .strict_start_type = TCA_TUNNEL_KEY_ENC_OPTS_VXLAN },
59 [TCA_TUNNEL_KEY_ENC_OPTS_GENEVE] = { .type = NLA_NESTED },60 [TCA_TUNNEL_KEY_ENC_OPTS_GENEVE] = { .type = NLA_NESTED },
60 [TCA_TUNNEL_KEY_ENC_OPTS_VXLAN] = { .type = NLA_NESTED },61 [TCA_TUNNEL_KEY_ENC_OPTS_VXLAN] = { .type = NLA_NESTED },
62 [TCA_TUNNEL_KEY_ENC_OPTS_ERSPAN] = { .type = NLA_NESTED },
61};63};
62 64
63static const struct nla_policy65static const struct nla_policy
@@ -73,6 +75,14 @@ vxlan_opt_policy[TCA_TUNNEL_KEY_ENC_OPT_VXLAN_MAX + 1] = { · 9 unmodified lines
73 [TCA_TUNNEL_KEY_ENC_OPT_VXLAN_GBP] = { .type = NLA_U32 },75 [TCA_TUNNEL_KEY_ENC_OPT_VXLAN_GBP] = { .type = NLA_U32 },
74};76};
75 77
78static const struct nla_policy
79erspan_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
76static int86static int
77tunnel_key_copy_geneve_opt(const struct nlattr *nla, void *dst, int dst_len,87tunnel_key_copy_geneve_opt(const struct nlattr *nla, void *dst, int dst_len,
78 struct netlink_ext_ack *extack)88 struct netlink_ext_ack *extack)
@@ -151,6 +161,59 @@ tunnel_key_copy_vxlan_opt(const struct nlattr *nla, void *dst, int dst_len, · 72 unmodified lines
151 return sizeof(struct vxlan_metadata);161 return sizeof(struct vxlan_metadata);
152}162}
153 163
164static int
165tunnel_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
154static int tunnel_key_copy_opts(const struct nlattr *nla, u8 *dst,217static int tunnel_key_copy_opts(const struct nlattr *nla, u8 *dst,
155 int dst_len, struct netlink_ext_ack *extack)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, · 35 unmodified lines
192 opts_len += opt_len;255 opts_len += opt_len;
193 type = TUNNEL_VXLAN_OPT;256 type = TUNNEL_VXLAN_OPT;
194 break;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, · 36 unmodified lines
234 opts_len, extack);309 opts_len, extack);
235#else310#else
236 return -EAFNOSUPPORT;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#endif320#endif
238 default:321 default:
239 NL_SET_ERR_MSG(extack, "Cannot set tunnel options for unknown tunnel type");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, · 290 unmodified lines
530 return 0;613 return 0;
531}614}
532 615
616static 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;
642err:
643 nla_nest_cancel(skb, start);
644 return -EMSGSIZE;
645}
646
533static int tunnel_key_opts_dump(struct sk_buff *skb,647static int tunnel_key_opts_dump(struct sk_buff *skb,
534 const struct ip_tunnel_info *info)648 const struct ip_tunnel_info *info)
535{649{
@@ -551,6 +665,10 @@ static int tunnel_key_opts_dump(struct sk_buff *skb, · 15 unmodified lines
551 err = tunnel_key_vxlan_opts_dump(skb, info);665 err = tunnel_key_vxlan_opts_dump(skb, info);
552 if (err)666 if (err)
553 goto err_out;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 } else {672 } else {
555err_out:673err_out:
556 nla_nest_cancel(skb, start);674 nla_nest_cancel(skb, start);