Return -EAFNOSUPPORT if the provided tunnel key has a different address family than the tunnel. Such configuration is invalid but we have no way to check this when the flow is configured (unless we want to interpret actions and lookup the destination vports), thus we have to check at run time.
Signed-off-by: Jiri Benc <[email protected]> --- net/openvswitch/vport-geneve.c | 1 + net/openvswitch/vport-gre.c | 1 + net/openvswitch/vport-vxlan.c | 1 + net/openvswitch/vport.c | 43 ++++++++++++++++++++++++++++-------------- net/openvswitch/vport.h | 30 +++++++++++++++++++++++++++++ 5 files changed, 62 insertions(+), 14 deletions(-) diff --git a/net/openvswitch/vport-geneve.c b/net/openvswitch/vport-geneve.c index 78c9e1f89d66..9d1392a30796 100644 --- a/net/openvswitch/vport-geneve.c +++ b/net/openvswitch/vport-geneve.c @@ -241,6 +241,7 @@ static int geneve_get_egress_tun_info(struct vport *vport, struct sk_buff *skb, */ return ovs_tunnel_get_egress_info(egress_tun_info, ovs_dp_get_net(vport->dp), + geneve_port->gs->sock->sk, OVS_CB(skb)->egress_tun_info, IPPROTO_UDP, skb->mark, sport, dport); } diff --git a/net/openvswitch/vport-gre.c b/net/openvswitch/vport-gre.c index 38f54797b45c..6d3068ede545 100644 --- a/net/openvswitch/vport-gre.c +++ b/net/openvswitch/vport-gre.c @@ -284,6 +284,7 @@ static int gre_get_egress_tun_info(struct vport *vport, struct sk_buff *skb, { return ovs_tunnel_get_egress_info(egress_tun_info, ovs_dp_get_net(vport->dp), + NULL, OVS_CB(skb)->egress_tun_info, IPPROTO_GRE, skb->mark, 0, 0); } diff --git a/net/openvswitch/vport-vxlan.c b/net/openvswitch/vport-vxlan.c index 6ff9f2befbac..5808a9344b59 100644 --- a/net/openvswitch/vport-vxlan.c +++ b/net/openvswitch/vport-vxlan.c @@ -287,6 +287,7 @@ static int vxlan_get_egress_tun_info(struct vport *vport, struct sk_buff *skb, src_port = udp_flow_src_port(net, skb, 0, 0, true); return ovs_tunnel_get_egress_info(egress_tun_info, net, + vxlan_port->vs->sock->sk, OVS_CB(skb)->egress_tun_info, IPPROTO_UDP, skb->mark, src_port, dst_port); diff --git a/net/openvswitch/vport.c b/net/openvswitch/vport.c index d21e3387916a..1797dbb0e139 100644 --- a/net/openvswitch/vport.c +++ b/net/openvswitch/vport.c @@ -27,6 +27,7 @@ #include <linux/rcupdate.h> #include <linux/rtnetlink.h> #include <linux/compat.h> +#include <net/addrconf.h> #include <net/net_namespace.h> #include <linux/module.h> @@ -574,6 +575,7 @@ EXPORT_SYMBOL_GPL(ovs_vport_deferred_free); int ovs_tunnel_get_egress_info(struct ovs_tunnel_info *egress_tun_info, struct net *net, + struct sock *sk, const struct ovs_tunnel_info *tun_info, u8 ipproto, u32 skb_mark, @@ -581,24 +583,12 @@ int ovs_tunnel_get_egress_info(struct ovs_tunnel_info *egress_tun_info, __be16 tp_dst) { const struct ovs_key_ip_tunnel *tun_key; - struct rtable *rt; - struct flowi4 fl; if (unlikely(!tun_info)) return -EINVAL; tun_key = &tun_info->tunnel; - /* Route lookup to get srouce IP address. - * The process may need to be changed if the corresponding process - * in vports ops changed. - */ - rt = ovs_tunnel_route_lookup(net, tun_key, skb_mark, &fl, ipproto); - if (IS_ERR(rt)) - return PTR_ERR(rt); - - ip_rt_put(rt); - /* Generate egress_tun_info based on tun_info, * saddr, tp_src and tp_dst */ @@ -610,8 +600,33 @@ int ovs_tunnel_get_egress_info(struct ovs_tunnel_info *egress_tun_info, tun_key->tun_flags, tun_info->options, tun_info->options_len); - __ovs_flow_tun_info_set_ipv4(egress_tun_info, - fl.saddr, tun_key->ipv4_dst); + + /* The process to get source IP address may need to be changed if + * the corresponding process in vports ops changed. + */ + if (tun_key->ipv4_dst) { + struct rtable *rt; + struct flowi4 fl; + + rt = ovs_tunnel_route_lookup(net, tun_key, skb_mark, &fl, + ipproto); + if (IS_ERR(rt)) + return PTR_ERR(rt); + ip_rt_put(rt); + __ovs_flow_tun_info_set_ipv4(egress_tun_info, + fl.saddr, tun_key->ipv4_dst); + } else { + struct dst_entry *ndst; + struct flowi6 fl6; + + ndst = ovs_tunnel6_route_lookup(sk, tun_key, skb_mark, &fl6, + ipproto); + if (IS_ERR(ndst)) + return PTR_ERR(ndst); + dst_release(ndst); + __ovs_flow_tun_info_set_ipv6(egress_tun_info, + &fl6.saddr, &tun_key->ipv6_dst); + } return 0; } diff --git a/net/openvswitch/vport.h b/net/openvswitch/vport.h index b22d45775eb5..ca9ebb9eb0f7 100644 --- a/net/openvswitch/vport.h +++ b/net/openvswitch/vport.h @@ -27,6 +27,8 @@ #include <linux/skbuff.h> #include <linux/spinlock.h> #include <linux/u64_stats_sync.h> +#include <net/addrconf.h> +#include <net/ipv6.h> #include "datapath.h" @@ -60,6 +62,7 @@ int ovs_vport_send(struct vport *, struct sk_buff *); int ovs_tunnel_get_egress_info(struct ovs_tunnel_info *egress_tun_info, struct net *net, + struct sock *sk, const struct ovs_tunnel_info *tun_info, u8 ipproto, u32 skb_mark, @@ -259,4 +262,31 @@ static inline struct rtable *ovs_tunnel_route_lookup(struct net *net, rt = ip_route_output_key(net, fl); return rt; } + +static inline struct dst_entry *ovs_tunnel6_route_lookup(struct sock *sk, + const struct ovs_key_ip_tunnel *key, + u32 mark, + struct flowi6 *fl6, + u8 protocol) +{ + struct dst_entry *dst; + int err; + + if (ipv6_addr_any(&key->ipv6_dst)) + return ERR_PTR(-EAFNOSUPPORT); + if (WARN_ON_ONCE(!sk)) + return ERR_PTR(-EAFNOSUPPORT); + + memset(fl6, 0, sizeof(*fl6)); + fl6->daddr = key->ipv6_dst; + fl6->saddr = key->ipv6_src; + fl6->flowi6_tos = RT_TOS(key->tos); + fl6->flowi6_mark = mark; + fl6->flowi6_proto = protocol; + + err = ipv6_stub->ipv6_dst_lookup(sk, &dst, fl6); + if (err) + return ERR_PTR(err); + return dst; +} #endif /* vport.h */ -- 1.8.3.1 _______________________________________________ dev mailing list [email protected] http://openvswitch.org/mailman/listinfo/dev
