Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

net: sched: add vxlan option support to act_tunnel_key

This patch is to allow setting vxlan options using the
act_tunnel_key action. Different from geneve options,
only one option can be set. And also, geneve options
and vxlan options can't be set at the same time.

gbp is the only param for vxlan options:

# ip link add name vxlan0 type vxlan dstport 0 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 \
vxlan_opts 01020304 \
action mirred egress redirect dev vxlan0

v1->v2:
- add .strict_start_type for enc_opts_policy as Jakub noticed.
- use Duplicate instead of Wrong in err msg for extack as Jakub
suggested.

Signed-off-by: Xin Long <lucien.xin@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

Xin Long and committed by
David S. Miller
fca3f91c 0617aa98

+97 -1
+13
include/uapi/linux/tc_act/tc_tunnel_key.h
··· 50 50 * TCA_TUNNEL_KEY_ENC_OPTS_ 51 51 * attributes 52 52 */ 53 + TCA_TUNNEL_KEY_ENC_OPTS_VXLAN, /* Nested 54 + * TCA_TUNNEL_KEY_ENC_OPTS_ 55 + * attributes 56 + */ 53 57 __TCA_TUNNEL_KEY_ENC_OPTS_MAX, 54 58 }; 55 59 ··· 70 66 71 67 #define TCA_TUNNEL_KEY_ENC_OPT_GENEVE_MAX \ 72 68 (__TCA_TUNNEL_KEY_ENC_OPT_GENEVE_MAX - 1) 69 + 70 + enum { 71 + TCA_TUNNEL_KEY_ENC_OPT_VXLAN_UNSPEC, 72 + TCA_TUNNEL_KEY_ENC_OPT_VXLAN_GBP, /* u32 */ 73 + __TCA_TUNNEL_KEY_ENC_OPT_VXLAN_MAX, 74 + }; 75 + 76 + #define TCA_TUNNEL_KEY_ENC_OPT_VXLAN_MAX \ 77 + (__TCA_TUNNEL_KEY_ENC_OPT_VXLAN_MAX - 1) 73 78 74 79 #endif
+84 -1
net/sched/act_tunnel_key.c
··· 10 10 #include <linux/skbuff.h> 11 11 #include <linux/rtnetlink.h> 12 12 #include <net/geneve.h> 13 + #include <net/vxlan.h> 13 14 #include <net/netlink.h> 14 15 #include <net/pkt_sched.h> 15 16 #include <net/dst.h> ··· 54 53 55 54 static const struct nla_policy 56 55 enc_opts_policy[TCA_TUNNEL_KEY_ENC_OPTS_MAX + 1] = { 56 + [TCA_TUNNEL_KEY_ENC_OPTS_UNSPEC] = { 57 + .strict_start_type = TCA_TUNNEL_KEY_ENC_OPTS_VXLAN }, 57 58 [TCA_TUNNEL_KEY_ENC_OPTS_GENEVE] = { .type = NLA_NESTED }, 59 + [TCA_TUNNEL_KEY_ENC_OPTS_VXLAN] = { .type = NLA_NESTED }, 58 60 }; 59 61 60 62 static const struct nla_policy ··· 66 62 [TCA_TUNNEL_KEY_ENC_OPT_GENEVE_TYPE] = { .type = NLA_U8 }, 67 63 [TCA_TUNNEL_KEY_ENC_OPT_GENEVE_DATA] = { .type = NLA_BINARY, 68 64 .len = 128 }, 65 + }; 66 + 67 + static const struct nla_policy 68 + vxlan_opt_policy[TCA_TUNNEL_KEY_ENC_OPT_VXLAN_MAX + 1] = { 69 + [TCA_TUNNEL_KEY_ENC_OPT_VXLAN_GBP] = { .type = NLA_U32 }, 69 70 }; 70 71 71 72 static int ··· 125 116 return opt_len; 126 117 } 127 118 119 + static int 120 + tunnel_key_copy_vxlan_opt(const struct nlattr *nla, void *dst, int dst_len, 121 + struct netlink_ext_ack *extack) 122 + { 123 + struct nlattr *tb[TCA_TUNNEL_KEY_ENC_OPT_VXLAN_MAX + 1]; 124 + int err; 125 + 126 + err = nla_parse_nested(tb, TCA_TUNNEL_KEY_ENC_OPT_VXLAN_MAX, nla, 127 + vxlan_opt_policy, extack); 128 + if (err < 0) 129 + return err; 130 + 131 + if (!tb[TCA_TUNNEL_KEY_ENC_OPT_VXLAN_GBP]) { 132 + NL_SET_ERR_MSG(extack, "Missing tunnel key vxlan option gbp"); 133 + return -EINVAL; 134 + } 135 + 136 + if (dst) { 137 + struct vxlan_metadata *md = dst; 138 + 139 + md->gbp = nla_get_u32(tb[TCA_TUNNEL_KEY_ENC_OPT_VXLAN_GBP]); 140 + } 141 + 142 + return sizeof(struct vxlan_metadata); 143 + } 144 + 128 145 static int tunnel_key_copy_opts(const struct nlattr *nla, u8 *dst, 129 146 int dst_len, struct netlink_ext_ack *extack) 130 147 { 131 - int err, rem, opt_len, len = nla_len(nla), opts_len = 0; 148 + int err, rem, opt_len, len = nla_len(nla), opts_len = 0, type = 0; 132 149 const struct nlattr *attr, *head = nla_data(nla); 133 150 134 151 err = nla_validate_deprecated(head, len, TCA_TUNNEL_KEY_ENC_OPTS_MAX, ··· 165 130 nla_for_each_attr(attr, head, len, rem) { 166 131 switch (nla_type(attr)) { 167 132 case TCA_TUNNEL_KEY_ENC_OPTS_GENEVE: 133 + if (type && type != TUNNEL_GENEVE_OPT) { 134 + NL_SET_ERR_MSG(extack, "Duplicate type for geneve options"); 135 + return -EINVAL; 136 + } 168 137 opt_len = tunnel_key_copy_geneve_opt(attr, dst, 169 138 dst_len, extack); 170 139 if (opt_len < 0) ··· 178 139 dst_len -= opt_len; 179 140 dst += opt_len; 180 141 } 142 + type = TUNNEL_GENEVE_OPT; 143 + break; 144 + case TCA_TUNNEL_KEY_ENC_OPTS_VXLAN: 145 + if (type) { 146 + NL_SET_ERR_MSG(extack, "Duplicate type for vxlan options"); 147 + return -EINVAL; 148 + } 149 + opt_len = tunnel_key_copy_vxlan_opt(attr, dst, 150 + dst_len, extack); 151 + if (opt_len < 0) 152 + return opt_len; 153 + opts_len += opt_len; 154 + type = TUNNEL_VXLAN_OPT; 181 155 break; 182 156 } 183 157 } ··· 222 170 case TCA_TUNNEL_KEY_ENC_OPTS_GENEVE: 223 171 #if IS_ENABLED(CONFIG_INET) 224 172 info->key.tun_flags |= TUNNEL_GENEVE_OPT; 173 + return tunnel_key_copy_opts(nla, ip_tunnel_info_opts(info), 174 + opts_len, extack); 175 + #else 176 + return -EAFNOSUPPORT; 177 + #endif 178 + case TCA_TUNNEL_KEY_ENC_OPTS_VXLAN: 179 + #if IS_ENABLED(CONFIG_INET) 180 + info->key.tun_flags |= TUNNEL_VXLAN_OPT; 225 181 return tunnel_key_copy_opts(nla, ip_tunnel_info_opts(info), 226 182 opts_len, extack); 227 183 #else ··· 511 451 return 0; 512 452 } 513 453 454 + static int tunnel_key_vxlan_opts_dump(struct sk_buff *skb, 455 + const struct ip_tunnel_info *info) 456 + { 457 + struct vxlan_metadata *md = (struct vxlan_metadata *)(info + 1); 458 + struct nlattr *start; 459 + 460 + start = nla_nest_start_noflag(skb, TCA_TUNNEL_KEY_ENC_OPTS_VXLAN); 461 + if (!start) 462 + return -EMSGSIZE; 463 + 464 + if (nla_put_u32(skb, TCA_TUNNEL_KEY_ENC_OPT_VXLAN_GBP, md->gbp)) { 465 + nla_nest_cancel(skb, start); 466 + return -EMSGSIZE; 467 + } 468 + 469 + nla_nest_end(skb, start); 470 + return 0; 471 + } 472 + 514 473 static int tunnel_key_opts_dump(struct sk_buff *skb, 515 474 const struct ip_tunnel_info *info) 516 475 { ··· 545 466 546 467 if (info->key.tun_flags & TUNNEL_GENEVE_OPT) { 547 468 err = tunnel_key_geneve_opts_dump(skb, info); 469 + if (err) 470 + goto err_out; 471 + } else if (info->key.tun_flags & TUNNEL_VXLAN_OPT) { 472 + err = tunnel_key_vxlan_opts_dump(skb, info); 548 473 if (err) 549 474 goto err_out; 550 475 } else {