Allow user space to configure tunnel flows with IPv6 addresses. For now, let all tunnel vports refuse such addresses.
Signed-off-by: Jiri Benc <[email protected]> --- include/uapi/linux/openvswitch.h | 2 + net/openvswitch/flow.h | 17 ++++--- net/openvswitch/flow_netlink.c | 96 ++++++++++++++++++++++++++++------------ net/openvswitch/vport-geneve.c | 2 +- net/openvswitch/vport-gre.c | 4 +- net/openvswitch/vport-vxlan.c | 2 +- net/openvswitch/vport.c | 2 +- net/openvswitch/vport.h | 5 ++- 8 files changed, 90 insertions(+), 40 deletions(-) diff --git a/include/uapi/linux/openvswitch.h b/include/uapi/linux/openvswitch.h index bbd49a0c46c7..4d26da40b01f 100644 --- a/include/uapi/linux/openvswitch.h +++ b/include/uapi/linux/openvswitch.h @@ -339,6 +339,8 @@ enum ovs_tunnel_key_attr { OVS_TUNNEL_KEY_ATTR_TP_SRC, /* be16 src Transport Port. */ OVS_TUNNEL_KEY_ATTR_TP_DST, /* be16 dst Transport Port. */ OVS_TUNNEL_KEY_ATTR_VXLAN_OPTS, /* Nested OVS_VXLAN_EXT_* */ + OVS_TUNNEL_KEY_ATTR_IPV6_SRC, /* struct in6_addr src IPv6 address. */ + OVS_TUNNEL_KEY_ATTR_IPV6_DST, /* struct in6_addr dst IPv6 address. */ __OVS_TUNNEL_KEY_ATTR_MAX }; diff --git a/net/openvswitch/flow.h b/net/openvswitch/flow.h index 2af6ffbf2f2e..78e96a120120 100644 --- a/net/openvswitch/flow.h +++ b/net/openvswitch/flow.h @@ -35,15 +35,17 @@ struct sk_buff; -/* Used to memset ovs_key_ipv4_tunnel padding (if there is any). */ +/* Used to memset ovs_key_ip_tunnel padding (if there is any). */ #define OVS_TUNNEL_KEY_SIZE \ - (offsetof(struct ovs_key_ipv4_tunnel, tp_dst) + \ - FIELD_SIZEOF(struct ovs_key_ipv4_tunnel, tp_dst)) + (offsetof(struct ovs_key_ip_tunnel, tp_dst) + \ + FIELD_SIZEOF(struct ovs_key_ip_tunnel, tp_dst)) -struct ovs_key_ipv4_tunnel { +struct ovs_key_ip_tunnel { __be64 tun_id; __be32 ipv4_src; __be32 ipv4_dst; + struct in6_addr ipv6_src; + struct in6_addr ipv6_dst; __be16 tun_flags; u8 ipv4_tos; u8 ipv4_ttl; @@ -52,7 +54,7 @@ struct ovs_key_ipv4_tunnel { }; struct ovs_tunnel_info { - struct ovs_key_ipv4_tunnel tunnel; + struct ovs_key_ip_tunnel tunnel; const void *options; u8 options_len; }; @@ -79,6 +81,9 @@ static inline void __ovs_flow_tun_info_init(struct ovs_tunnel_info *tun_info, tun_info->tunnel.tun_id = tun_id; tun_info->tunnel.ipv4_src = saddr; tun_info->tunnel.ipv4_dst = daddr; + memset(&tun_info->tunnel.ipv6_src, 0, + offsetof(struct ovs_key_ip_tunnel, tun_flags) - + offsetof(struct ovs_key_ip_tunnel, ipv6_src)); tun_info->tunnel.ipv4_tos = tos; tun_info->tunnel.ipv4_ttl = ttl; tun_info->tunnel.tun_flags = tun_flags; @@ -122,7 +127,7 @@ static inline void ovs_flow_tun_info_init(struct ovs_tunnel_info *tun_info, struct sw_flow_key { u8 tun_opts[255]; u8 tun_opts_len; - struct ovs_key_ipv4_tunnel tun_key; /* Encapsulating tunnel key. */ + struct ovs_key_ip_tunnel tun_key; /* Encapsulating tunnel key. */ struct { u32 priority; /* Packet QoS priority. */ u32 skb_mark; /* SKB mark. */ diff --git a/net/openvswitch/flow_netlink.c b/net/openvswitch/flow_netlink.c index 624e41c4267f..890a6cf4ec67 100644 --- a/net/openvswitch/flow_netlink.c +++ b/net/openvswitch/flow_netlink.c @@ -273,7 +273,10 @@ size_t ovs_tun_key_attr_size(void) * OVS_TUNNEL_KEY_ATTR_GENEVE_OPTS and covered by it. */ + nla_total_size(2) /* OVS_TUNNEL_KEY_ATTR_TP_SRC */ - + nla_total_size(2); /* OVS_TUNNEL_KEY_ATTR_TP_DST */ + + nla_total_size(2) /* OVS_TUNNEL_KEY_ATTR_TP_DST */ + + nla_total_size(16) /* OVS_TUNNEL_KEY_ATTR_IPV6_SRC */ + + nla_total_size(16) /* OVS_TUNNEL_KEY_ATTR_IPV6_DST */ + ; } size_t ovs_key_attr_size(void) @@ -313,6 +316,8 @@ static const struct ovs_len_tbl ovs_tunnel_key_lens[OVS_TUNNEL_KEY_ATTR_MAX + 1] [OVS_TUNNEL_KEY_ATTR_OAM] = { .len = 0 }, [OVS_TUNNEL_KEY_ATTR_GENEVE_OPTS] = { .len = OVS_ATTR_NESTED }, [OVS_TUNNEL_KEY_ATTR_VXLAN_OPTS] = { .len = OVS_ATTR_NESTED }, + [OVS_TUNNEL_KEY_ATTR_IPV6_SRC] = { .len = sizeof(struct in6_addr) }, + [OVS_TUNNEL_KEY_ATTR_IPV6_DST] = { .len = sizeof(struct in6_addr) }, }; /* The size of the argument for each %OVS_KEY_ATTR_* Netlink attribute. */ @@ -500,13 +505,13 @@ static int vxlan_tun_opt_from_nlattr(const struct nlattr *a, return 0; } -static int ipv4_tun_from_nlattr(const struct nlattr *attr, - struct sw_flow_match *match, bool is_mask, - bool log) +static int ip_tun_from_nlattr(const struct nlattr *attr, + struct sw_flow_match *match, bool is_mask, + bool log) { struct nlattr *a; int rem; - bool ttl = false; + bool ttl = false, ipv4 = false, ipv6 = false; __be16 tun_flags = 0; int opts_type = 0; @@ -536,10 +541,22 @@ static int ipv4_tun_from_nlattr(const struct nlattr *attr, case OVS_TUNNEL_KEY_ATTR_IPV4_SRC: SW_FLOW_KEY_PUT(match, tun_key.ipv4_src, nla_get_in_addr(a), is_mask); + ipv4 = true; break; case OVS_TUNNEL_KEY_ATTR_IPV4_DST: SW_FLOW_KEY_PUT(match, tun_key.ipv4_dst, nla_get_in_addr(a), is_mask); + ipv4 = true; + break; + case OVS_TUNNEL_KEY_ATTR_IPV6_SRC: + SW_FLOW_KEY_PUT(match, tun_key.ipv6_src, + nla_get_in6_addr(a), is_mask); + ipv6 = true; + break; + case OVS_TUNNEL_KEY_ATTR_IPV6_DST: + SW_FLOW_KEY_PUT(match, tun_key.ipv6_dst, + nla_get_in6_addr(a), is_mask); + ipv6 = true; break; case OVS_TUNNEL_KEY_ATTR_TOS: SW_FLOW_KEY_PUT(match, tun_key.ipv4_tos, @@ -594,7 +611,7 @@ static int ipv4_tun_from_nlattr(const struct nlattr *attr, opts_type = type; break; default: - OVS_NLERR(log, "Unknown IPv4 tunnel attribute %d", + OVS_NLERR(log, "Unknown IP tunnel attribute %d", type); return -EINVAL; } @@ -603,19 +620,32 @@ static int ipv4_tun_from_nlattr(const struct nlattr *attr, SW_FLOW_KEY_PUT(match, tun_key.tun_flags, tun_flags, is_mask); if (rem > 0) { - OVS_NLERR(log, "IPv4 tunnel attribute has %d unknown bytes.", + OVS_NLERR(log, "IP tunnel attribute has %d unknown bytes.", rem); return -EINVAL; } + if (ipv4 && ipv6) { + OVS_NLERR(log, "Mixed IPv4 and IPv6 tunnel attributes"); + return -EINVAL; + } + if (!is_mask) { - if (!match->key->tun_key.ipv4_dst) { + if (!ipv4 && !ipv6) { + OVS_NLERR(log, "IP tunnel dst address not specified"); + return -EINVAL; + } + if (ipv4 && !match->key->tun_key.ipv4_dst) { OVS_NLERR(log, "IPv4 tunnel dst address is zero"); return -EINVAL; } + if (ipv6 && ipv6_addr_any(&match->key->tun_key.ipv6_dst)) { + OVS_NLERR(log, "IPv6 tunnel dst address is zero"); + return -EINVAL; + } if (!ttl) { - OVS_NLERR(log, "IPv4 tunnel TTL not specified."); + OVS_NLERR(log, "IP tunnel TTL not specified."); return -EINVAL; } } @@ -640,9 +670,9 @@ static int vxlan_opt_to_nlattr(struct sk_buff *skb, return 0; } -static int __ipv4_tun_to_nlattr(struct sk_buff *skb, - const struct ovs_key_ipv4_tunnel *output, - const void *tun_opts, int swkey_tun_opts_len) +static int __ip_tun_to_nlattr(struct sk_buff *skb, + const struct ovs_key_ip_tunnel *output, + const void *tun_opts, int swkey_tun_opts_len) { if (output->tun_flags & TUNNEL_KEY && nla_put_be64(skb, OVS_TUNNEL_KEY_ATTR_ID, output->tun_id)) @@ -655,6 +685,14 @@ static int __ipv4_tun_to_nlattr(struct sk_buff *skb, nla_put_in_addr(skb, OVS_TUNNEL_KEY_ATTR_IPV4_DST, output->ipv4_dst)) return -EMSGSIZE; + if (!ipv6_addr_any(&output->ipv6_src) && + nla_put_in6_addr(skb, OVS_TUNNEL_KEY_ATTR_IPV6_SRC, + &output->ipv6_src)) + return -EMSGSIZE; + if (!ipv6_addr_any(&output->ipv6_dst) && + nla_put_in6_addr(skb, OVS_TUNNEL_KEY_ATTR_IPV6_DST, + &output->ipv6_dst)) + return -EMSGSIZE; if (output->ipv4_tos && nla_put_u8(skb, OVS_TUNNEL_KEY_ATTR_TOS, output->ipv4_tos)) return -EMSGSIZE; @@ -688,9 +726,9 @@ static int __ipv4_tun_to_nlattr(struct sk_buff *skb, return 0; } -static int ipv4_tun_to_nlattr(struct sk_buff *skb, - const struct ovs_key_ipv4_tunnel *output, - const void *tun_opts, int swkey_tun_opts_len) +static int ip_tun_to_nlattr(struct sk_buff *skb, + const struct ovs_key_ip_tunnel *output, + const void *tun_opts, int swkey_tun_opts_len) { struct nlattr *nla; int err; @@ -699,7 +737,7 @@ static int ipv4_tun_to_nlattr(struct sk_buff *skb, if (!nla) return -EMSGSIZE; - err = __ipv4_tun_to_nlattr(skb, output, tun_opts, swkey_tun_opts_len); + err = __ip_tun_to_nlattr(skb, output, tun_opts, swkey_tun_opts_len); if (err) return err; @@ -710,9 +748,9 @@ static int ipv4_tun_to_nlattr(struct sk_buff *skb, int ovs_nla_put_egress_tunnel_key(struct sk_buff *skb, const struct ovs_tunnel_info *egress_tun_info) { - return __ipv4_tun_to_nlattr(skb, &egress_tun_info->tunnel, - egress_tun_info->options, - egress_tun_info->options_len); + return __ip_tun_to_nlattr(skb, &egress_tun_info->tunnel, + egress_tun_info->options, + egress_tun_info->options_len); } static int metadata_from_nlattrs(struct sw_flow_match *match, u64 *attrs, @@ -763,8 +801,8 @@ static int metadata_from_nlattrs(struct sw_flow_match *match, u64 *attrs, *attrs &= ~(1 << OVS_KEY_ATTR_SKB_MARK); } if (*attrs & (1 << OVS_KEY_ATTR_TUNNEL)) { - if (ipv4_tun_from_nlattr(a[OVS_KEY_ATTR_TUNNEL], match, - is_mask, log) < 0) + if (ip_tun_from_nlattr(a[OVS_KEY_ATTR_TUNNEL], match, + is_mask, log) < 0) return -EINVAL; *attrs &= ~(1 << OVS_KEY_ATTR_TUNNEL); } @@ -1287,14 +1325,16 @@ static int __ovs_nla_put_key(const struct sw_flow_key *swkey, if (nla_put_u32(skb, OVS_KEY_ATTR_PRIORITY, output->phy.priority)) goto nla_put_failure; - if ((swkey->tun_key.ipv4_dst || is_mask)) { + if (swkey->tun_key.ipv4_dst || + !ipv6_addr_any(&swkey->tun_key.ipv6_dst) || + is_mask) { const void *opts = NULL; if (output->tun_key.tun_flags & TUNNEL_OPTIONS_PRESENT) opts = TUN_METADATA_OPTS(output, swkey->tun_opts_len); - if (ipv4_tun_to_nlattr(skb, &output->tun_key, opts, - swkey->tun_opts_len)) + if (ip_tun_to_nlattr(skb, &output->tun_key, opts, + swkey->tun_opts_len)) goto nla_put_failure; } @@ -1751,7 +1791,7 @@ static int validate_and_copy_set_tun(const struct nlattr *attr, int err = 0, start, opts_type; ovs_match_init(&match, &key, NULL); - opts_type = ipv4_tun_from_nlattr(nla_data(attr), &match, false, log); + opts_type = ip_tun_from_nlattr(nla_data(attr), &match, false, log); if (opts_type < 0) return opts_type; @@ -2233,10 +2273,10 @@ static int set_action_to_attr(const struct nlattr *a, struct sk_buff *skb) if (!start) return -EMSGSIZE; - err = ipv4_tun_to_nlattr(skb, &tun_info->tunnel, - tun_info->options_len ? + err = ip_tun_to_nlattr(skb, &tun_info->tunnel, + tun_info->options_len ? tun_info->options : NULL, - tun_info->options_len); + tun_info->options_len); if (err) return err; nla_nest_end(skb, start); diff --git a/net/openvswitch/vport-geneve.c b/net/openvswitch/vport-geneve.c index 208c576bd1b6..2e5bf299ac4c 100644 --- a/net/openvswitch/vport-geneve.c +++ b/net/openvswitch/vport-geneve.c @@ -165,7 +165,7 @@ error: static int geneve_tnl_send(struct vport *vport, struct sk_buff *skb) { - const struct ovs_key_ipv4_tunnel *tun_key; + const struct ovs_key_ip_tunnel *tun_key; struct ovs_tunnel_info *tun_info; struct net *net = ovs_dp_get_net(vport->dp); struct geneve_port *geneve_port = geneve_vport(vport); diff --git a/net/openvswitch/vport-gre.c b/net/openvswitch/vport-gre.c index f17ac9642f4e..715bd1bc3328 100644 --- a/net/openvswitch/vport-gre.c +++ b/net/openvswitch/vport-gre.c @@ -67,7 +67,7 @@ static struct sk_buff *__build_header(struct sk_buff *skb, int tunnel_hlen) { struct tnl_ptk_info tpi; - const struct ovs_key_ipv4_tunnel *tun_key; + const struct ovs_key_ip_tunnel *tun_key; tun_key = &OVS_CB(skb)->egress_tun_info->tunnel; @@ -134,7 +134,7 @@ static int gre_err(struct sk_buff *skb, u32 info, static int gre_tnl_send(struct vport *vport, struct sk_buff *skb) { struct net *net = ovs_dp_get_net(vport->dp); - const struct ovs_key_ipv4_tunnel *tun_key; + const struct ovs_key_ip_tunnel *tun_key; struct flowi4 fl; struct rtable *rt; int min_headroom; diff --git a/net/openvswitch/vport-vxlan.c b/net/openvswitch/vport-vxlan.c index 6d39766e7828..c7e5e61779d4 100644 --- a/net/openvswitch/vport-vxlan.c +++ b/net/openvswitch/vport-vxlan.c @@ -224,7 +224,7 @@ static int vxlan_tnl_send(struct vport *vport, struct sk_buff *skb) struct vxlan_port *vxlan_port = vxlan_vport(vport); struct sock *sk = vxlan_port->vs->sock->sk; __be16 dst_port = inet_sk(sk)->inet_sport; - const struct ovs_key_ipv4_tunnel *tun_key; + const struct ovs_key_ip_tunnel *tun_key; struct vxlan_metadata md = {0}; struct rtable *rt; struct flowi4 fl; diff --git a/net/openvswitch/vport.c b/net/openvswitch/vport.c index 067a3fff1d2c..83668f7f073b 100644 --- a/net/openvswitch/vport.c +++ b/net/openvswitch/vport.c @@ -580,7 +580,7 @@ int ovs_tunnel_get_egress_info(struct ovs_tunnel_info *egress_tun_info, __be16 tp_src, __be16 tp_dst) { - const struct ovs_key_ipv4_tunnel *tun_key; + const struct ovs_key_ip_tunnel *tun_key; struct rtable *rt; struct flowi4 fl; diff --git a/net/openvswitch/vport.h b/net/openvswitch/vport.h index bc85331a6c60..a28b15df190b 100644 --- a/net/openvswitch/vport.h +++ b/net/openvswitch/vport.h @@ -239,13 +239,16 @@ int ovs_vport_ops_register(struct vport_ops *ops); void ovs_vport_ops_unregister(struct vport_ops *ops); static inline struct rtable *ovs_tunnel_route_lookup(struct net *net, - const struct ovs_key_ipv4_tunnel *key, + const struct ovs_key_ip_tunnel *key, u32 mark, struct flowi4 *fl, u8 protocol) { struct rtable *rt; + if (!key->ipv4_dst) + return ERR_PTR(-EAFNOSUPPORT); + memset(fl, 0, sizeof(*fl)); fl->daddr = key->ipv4_dst; fl->saddr = key->ipv4_src; -- 1.8.3.1 _______________________________________________ dev mailing list [email protected] http://openvswitch.org/mailman/listinfo/dev
