From edf31cbb1502481da181a09148adb33e12599185 Mon Sep 17 00:00:00 2001 From: Xin Long Date: Wed, 6 Nov 2019 17:01:06 +0800 Subject: [PATCH] lwtunnel: add options setting and dumping for vxlan Based on the code framework built on the last patch, to support setting and dumping for vxlan, we only need to add ip_tun_parse_opts_vxlan() for .build_state and ip_tun_fill_encap_opts_vxlan() for .fill_encap and if (tun_flags & TUNNEL_VXLAN_OPT) for .get_encap_size. Signed-off-by: Xin Long Signed-off-by: David S. Miller --- include/uapi/linux/lwtunnel.h | 9 ++++++ net/ipv4/ip_tunnel_core.c | 67 +++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 74 insertions(+), 2 deletions(-) diff --git a/include/uapi/linux/lwtunnel.h b/include/uapi/linux/lwtunnel.h index b595ab2..638b7b1 100644 --- a/include/uapi/linux/lwtunnel.h +++ b/include/uapi/linux/lwtunnel.h @@ -51,6 +51,7 @@ enum lwtunnel_ip6_t { enum { LWTUNNEL_IP_OPTS_UNSPEC, LWTUNNEL_IP_OPTS_GENEVE, + LWTUNNEL_IP_OPTS_VXLAN, __LWTUNNEL_IP_OPTS_MAX, }; @@ -67,6 +68,14 @@ enum { #define LWTUNNEL_IP_OPT_GENEVE_MAX (__LWTUNNEL_IP_OPT_GENEVE_MAX - 1) enum { + LWTUNNEL_IP_OPT_VXLAN_UNSPEC, + LWTUNNEL_IP_OPT_VXLAN_GBP, + __LWTUNNEL_IP_OPT_VXLAN_MAX, +}; + +#define LWTUNNEL_IP_OPT_VXLAN_MAX (__LWTUNNEL_IP_OPT_VXLAN_MAX - 1) + +enum { LWT_BPF_PROG_UNSPEC, LWT_BPF_PROG_FD, LWT_BPF_PROG_NAME, diff --git a/net/ipv4/ip_tunnel_core.c b/net/ipv4/ip_tunnel_core.c index 1ec9d94..61be2e0 100644 --- a/net/ipv4/ip_tunnel_core.c +++ b/net/ipv4/ip_tunnel_core.c @@ -35,6 +35,7 @@ #include #include #include +#include const struct ip_tunnel_encap_ops __rcu * iptun_encaps[MAX_IPTUN_ENCAP_OPS] __read_mostly; @@ -224,6 +225,7 @@ static const struct nla_policy ip_tun_policy[LWTUNNEL_IP_MAX + 1] = { static const struct nla_policy ip_opts_policy[LWTUNNEL_IP_OPTS_MAX + 1] = { [LWTUNNEL_IP_OPTS_GENEVE] = { .type = NLA_NESTED }, + [LWTUNNEL_IP_OPTS_VXLAN] = { .type = NLA_NESTED }, }; static const struct nla_policy @@ -233,6 +235,11 @@ geneve_opt_policy[LWTUNNEL_IP_OPT_GENEVE_MAX + 1] = { [LWTUNNEL_IP_OPT_GENEVE_DATA] = { .type = NLA_BINARY, .len = 128 }, }; +static const struct nla_policy +vxlan_opt_policy[LWTUNNEL_IP_OPT_VXLAN_MAX + 1] = { + [LWTUNNEL_IP_OPT_VXLAN_GBP] = { .type = NLA_U32 }, +}; + static int ip_tun_parse_opts_geneve(struct nlattr *attr, struct ip_tunnel_info *info, struct netlink_ext_ack *extack) @@ -270,6 +277,32 @@ static int ip_tun_parse_opts_geneve(struct nlattr *attr, return sizeof(struct geneve_opt) + data_len; } +static int ip_tun_parse_opts_vxlan(struct nlattr *attr, + struct ip_tunnel_info *info, + struct netlink_ext_ack *extack) +{ + struct nlattr *tb[LWTUNNEL_IP_OPT_VXLAN_MAX + 1]; + int err; + + err = nla_parse_nested_deprecated(tb, LWTUNNEL_IP_OPT_VXLAN_MAX, + attr, vxlan_opt_policy, extack); + if (err) + return err; + + if (!tb[LWTUNNEL_IP_OPT_VXLAN_GBP]) + return -EINVAL; + + if (info) { + struct vxlan_metadata *md = ip_tunnel_info_opts(info); + + attr = tb[LWTUNNEL_IP_OPT_VXLAN_GBP]; + md->gbp = nla_get_u32(attr); + info->key.tun_flags |= TUNNEL_VXLAN_OPT; + } + + return sizeof(struct vxlan_metadata); +} + static int ip_tun_parse_opts(struct nlattr *attr, struct ip_tunnel_info *info, struct netlink_ext_ack *extack) { @@ -287,6 +320,9 @@ static int ip_tun_parse_opts(struct nlattr *attr, struct ip_tunnel_info *info, if (tb[LWTUNNEL_IP_OPTS_GENEVE]) err = ip_tun_parse_opts_geneve(tb[LWTUNNEL_IP_OPTS_GENEVE], info, extack); + else if (tb[LWTUNNEL_IP_OPTS_VXLAN]) + err = ip_tun_parse_opts_vxlan(tb[LWTUNNEL_IP_OPTS_VXLAN], + info, extack); else err = -EINVAL; @@ -404,13 +440,34 @@ static int ip_tun_fill_encap_opts_geneve(struct sk_buff *skb, return 0; } +static int ip_tun_fill_encap_opts_vxlan(struct sk_buff *skb, + struct ip_tunnel_info *tun_info) +{ + struct vxlan_metadata *md; + struct nlattr *nest; + + nest = nla_nest_start_noflag(skb, LWTUNNEL_IP_OPTS_VXLAN); + if (!nest) + return -ENOMEM; + + md = ip_tunnel_info_opts(tun_info); + if (nla_put_u32(skb, LWTUNNEL_IP_OPT_VXLAN_GBP, md->gbp)) { + nla_nest_cancel(skb, nest); + return -ENOMEM; + } + + nla_nest_end(skb, nest); + return 0; +} + static int ip_tun_fill_encap_opts(struct sk_buff *skb, int type, struct ip_tunnel_info *tun_info) { struct nlattr *nest; int err = 0; - if (!(tun_info->key.tun_flags & TUNNEL_GENEVE_OPT)) + if (!(tun_info->key.tun_flags & + (TUNNEL_GENEVE_OPT | TUNNEL_VXLAN_OPT))) return 0; nest = nla_nest_start_noflag(skb, type); @@ -419,6 +476,8 @@ static int ip_tun_fill_encap_opts(struct sk_buff *skb, int type, if (tun_info->key.tun_flags & TUNNEL_GENEVE_OPT) err = ip_tun_fill_encap_opts_geneve(skb, tun_info); + else if (tun_info->key.tun_flags & TUNNEL_VXLAN_OPT) + err = ip_tun_fill_encap_opts_vxlan(skb, tun_info); if (err) { nla_nest_cancel(skb, nest); @@ -451,7 +510,8 @@ static int ip_tun_opts_nlsize(struct ip_tunnel_info *info) { int opt_len; - if (!(info->key.tun_flags & TUNNEL_GENEVE_OPT)) + if (!(info->key.tun_flags & + (TUNNEL_GENEVE_OPT | TUNNEL_VXLAN_OPT))) return 0; opt_len = nla_total_size(0); /* LWTUNNEL_IP_OPTS */ @@ -463,6 +523,9 @@ static int ip_tun_opts_nlsize(struct ip_tunnel_info *info) + nla_total_size(1) /* OPT_GENEVE_TYPE */ + nla_total_size(opt->length * 4); /* OPT_GENEVE_DATA */ + } else if (info->key.tun_flags & TUNNEL_VXLAN_OPT) { + opt_len += nla_total_size(0) /* LWTUNNEL_IP_OPTS_VXLAN */ + + nla_total_size(4); /* OPT_VXLAN_GBP */ } return opt_len; -- 2.7.4