Commit 655c3de1 authored by pravin shelar's avatar pravin shelar Committed by David S. Miller

vxlan: improve vxlan route lookup checks.

Move route sanity check to respective vxlan[4/6]_get_route functions.
This allows us to perform all sanity checks before caching the dst so
that we can avoid these checks on subsequent packets.
This give move accurate metadata information for packet from
fill_metadata_dst().
Signed-off-by: default avatarPravin B Shelar <pshelar@ovn.org>
Acked-by: default avatarJiri Benc <jbenc@redhat.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent c46b7897
...@@ -1791,7 +1791,8 @@ static int vxlan_build_skb(struct sk_buff *skb, struct dst_entry *dst, ...@@ -1791,7 +1791,8 @@ static int vxlan_build_skb(struct sk_buff *skb, struct dst_entry *dst,
return 0; return 0;
} }
static struct rtable *vxlan_get_route(struct vxlan_dev *vxlan, static struct rtable *vxlan_get_route(struct vxlan_dev *vxlan, struct net_device *dev,
struct vxlan_sock *sock4,
struct sk_buff *skb, int oif, u8 tos, struct sk_buff *skb, int oif, u8 tos,
__be32 daddr, __be32 *saddr, __be32 daddr, __be32 *saddr,
struct dst_cache *dst_cache, struct dst_cache *dst_cache,
...@@ -1801,6 +1802,9 @@ static struct rtable *vxlan_get_route(struct vxlan_dev *vxlan, ...@@ -1801,6 +1802,9 @@ static struct rtable *vxlan_get_route(struct vxlan_dev *vxlan,
struct rtable *rt = NULL; struct rtable *rt = NULL;
struct flowi4 fl4; struct flowi4 fl4;
if (!sock4)
return ERR_PTR(-EIO);
if (tos && !info) if (tos && !info)
use_cache = false; use_cache = false;
if (use_cache) { if (use_cache) {
...@@ -1818,16 +1822,26 @@ static struct rtable *vxlan_get_route(struct vxlan_dev *vxlan, ...@@ -1818,16 +1822,26 @@ static struct rtable *vxlan_get_route(struct vxlan_dev *vxlan,
fl4.saddr = *saddr; fl4.saddr = *saddr;
rt = ip_route_output_key(vxlan->net, &fl4); rt = ip_route_output_key(vxlan->net, &fl4);
if (!IS_ERR(rt)) { if (likely(!IS_ERR(rt))) {
if (rt->dst.dev == dev) {
netdev_dbg(dev, "circular route to %pI4\n", &daddr);
ip_rt_put(rt);
return ERR_PTR(-ELOOP);
}
*saddr = fl4.saddr; *saddr = fl4.saddr;
if (use_cache) if (use_cache)
dst_cache_set_ip4(dst_cache, &rt->dst, fl4.saddr); dst_cache_set_ip4(dst_cache, &rt->dst, fl4.saddr);
} else {
netdev_dbg(dev, "no route to %pI4\n", &daddr);
return ERR_PTR(-ENETUNREACH);
} }
return rt; return rt;
} }
#if IS_ENABLED(CONFIG_IPV6) #if IS_ENABLED(CONFIG_IPV6)
static struct dst_entry *vxlan6_get_route(struct vxlan_dev *vxlan, static struct dst_entry *vxlan6_get_route(struct vxlan_dev *vxlan,
struct net_device *dev,
struct vxlan_sock *sock6, struct vxlan_sock *sock6,
struct sk_buff *skb, int oif, u8 tos, struct sk_buff *skb, int oif, u8 tos,
__be32 label, __be32 label,
...@@ -1863,8 +1877,16 @@ static struct dst_entry *vxlan6_get_route(struct vxlan_dev *vxlan, ...@@ -1863,8 +1877,16 @@ static struct dst_entry *vxlan6_get_route(struct vxlan_dev *vxlan,
err = ipv6_stub->ipv6_dst_lookup(vxlan->net, err = ipv6_stub->ipv6_dst_lookup(vxlan->net,
sock6->sock->sk, sock6->sock->sk,
&ndst, &fl6); &ndst, &fl6);
if (err < 0) if (unlikely(err < 0)) {
return ERR_PTR(err); netdev_dbg(dev, "no route to %pI6\n", daddr);
return ERR_PTR(-ENETUNREACH);
}
if (unlikely(ndst->dev == dev)) {
netdev_dbg(dev, "circular route to %pI6\n", daddr);
dst_release(ndst);
return ERR_PTR(-ELOOP);
}
*saddr = fl6.saddr; *saddr = fl6.saddr;
if (use_cache) if (use_cache)
...@@ -1931,8 +1953,8 @@ static void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev, ...@@ -1931,8 +1953,8 @@ static void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev,
union vxlan_addr *src; union vxlan_addr *src;
struct vxlan_metadata _md; struct vxlan_metadata _md;
struct vxlan_metadata *md = &_md; struct vxlan_metadata *md = &_md;
struct dst_entry *ndst = NULL;
__be16 src_port = 0, dst_port; __be16 src_port = 0, dst_port;
struct dst_entry *ndst = NULL;
__be32 vni, label; __be32 vni, label;
__be16 df = 0; __be16 df = 0;
__u8 tos, ttl; __u8 tos, ttl;
...@@ -2009,29 +2031,14 @@ static void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev, ...@@ -2009,29 +2031,14 @@ static void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev,
struct vxlan_sock *sock4 = rcu_dereference(vxlan->vn4_sock); struct vxlan_sock *sock4 = rcu_dereference(vxlan->vn4_sock);
struct rtable *rt; struct rtable *rt;
if (!sock4) rt = vxlan_get_route(vxlan, dev, sock4, skb,
goto drop;
sk = sock4->sock->sk;
rt = vxlan_get_route(vxlan, skb,
rdst ? rdst->remote_ifindex : 0, tos, rdst ? rdst->remote_ifindex : 0, tos,
dst->sin.sin_addr.s_addr, dst->sin.sin_addr.s_addr,
&src->sin.sin_addr.s_addr, &src->sin.sin_addr.s_addr,
dst_cache, info); dst_cache, info);
if (IS_ERR(rt)) { if (IS_ERR(rt))
netdev_dbg(dev, "no route to %pI4\n",
&dst->sin.sin_addr.s_addr);
dev->stats.tx_carrier_errors++;
goto tx_error;
}
if (rt->dst.dev == dev) {
netdev_dbg(dev, "circular route to %pI4\n",
&dst->sin.sin_addr.s_addr);
dev->stats.collisions++;
ip_rt_put(rt);
goto tx_error; goto tx_error;
} sk = sock4->sock->sk;
/* Bypass encapsulation if the destination is local */ /* Bypass encapsulation if the destination is local */
if (!info && rt->rt_flags & RTCF_LOCAL && if (!info && rt->rt_flags & RTCF_LOCAL &&
...@@ -2069,27 +2076,17 @@ static void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev, ...@@ -2069,27 +2076,17 @@ static void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev,
struct vxlan_sock *sock6 = rcu_dereference(vxlan->vn6_sock); struct vxlan_sock *sock6 = rcu_dereference(vxlan->vn6_sock);
u32 rt6i_flags; u32 rt6i_flags;
ndst = vxlan6_get_route(vxlan, sock6, skb, ndst = vxlan6_get_route(vxlan, dev, sock6, skb,
rdst ? rdst->remote_ifindex : 0, tos, rdst ? rdst->remote_ifindex : 0, tos,
label, &dst->sin6.sin6_addr, label, &dst->sin6.sin6_addr,
&src->sin6.sin6_addr, &src->sin6.sin6_addr,
dst_cache, info); dst_cache, info);
if (IS_ERR(ndst)) { if (IS_ERR(ndst)) {
netdev_dbg(dev, "no route to %pI6\n",
&dst->sin6.sin6_addr);
dev->stats.tx_carrier_errors++;
ndst = NULL; ndst = NULL;
goto tx_error; goto tx_error;
} }
if (ndst->dev == dev) {
netdev_dbg(dev, "circular route to %pI6\n",
&dst->sin6.sin6_addr);
dev->stats.collisions++;
goto tx_error;
}
sk = sock6->sock->sk; sk = sock6->sock->sk;
/* Bypass encapsulation if the destination is local */ /* Bypass encapsulation if the destination is local */
rt6i_flags = ((struct rt6_info *)ndst)->rt6i_flags; rt6i_flags = ((struct rt6_info *)ndst)->rt6i_flags;
if (!info && rt6i_flags & RTF_LOCAL && if (!info && rt6i_flags & RTF_LOCAL &&
...@@ -2132,6 +2129,10 @@ static void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev, ...@@ -2132,6 +2129,10 @@ static void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev,
return; return;
tx_error: tx_error:
if (err == -ELOOP)
dev->stats.collisions++;
else if (err == -ENETUNREACH)
dev->stats.tx_carrier_errors++;
dst_release(ndst); dst_release(ndst);
dev->stats.tx_errors++; dev->stats.tx_errors++;
kfree_skb(skb); kfree_skb(skb);
...@@ -2413,9 +2414,7 @@ static int vxlan_fill_metadata_dst(struct net_device *dev, struct sk_buff *skb) ...@@ -2413,9 +2414,7 @@ static int vxlan_fill_metadata_dst(struct net_device *dev, struct sk_buff *skb)
struct vxlan_sock *sock4 = rcu_dereference(vxlan->vn4_sock); struct vxlan_sock *sock4 = rcu_dereference(vxlan->vn4_sock);
struct rtable *rt; struct rtable *rt;
if (!sock4) rt = vxlan_get_route(vxlan, dev, sock4, skb, 0, info->key.tos,
return -EINVAL;
rt = vxlan_get_route(vxlan, skb, 0, info->key.tos,
info->key.u.ipv4.dst, info->key.u.ipv4.dst,
&info->key.u.ipv4.src, NULL, info); &info->key.u.ipv4.src, NULL, info);
if (IS_ERR(rt)) if (IS_ERR(rt))
...@@ -2426,7 +2425,7 @@ static int vxlan_fill_metadata_dst(struct net_device *dev, struct sk_buff *skb) ...@@ -2426,7 +2425,7 @@ static int vxlan_fill_metadata_dst(struct net_device *dev, struct sk_buff *skb)
struct vxlan_sock *sock6 = rcu_dereference(vxlan->vn6_sock); struct vxlan_sock *sock6 = rcu_dereference(vxlan->vn6_sock);
struct dst_entry *ndst; struct dst_entry *ndst;
ndst = vxlan6_get_route(vxlan, sock6, skb, 0, info->key.tos, ndst = vxlan6_get_route(vxlan, dev, sock6, skb, 0, info->key.tos,
info->key.label, &info->key.u.ipv6.dst, info->key.label, &info->key.u.ipv6.dst,
&info->key.u.ipv6.src, NULL, info); &info->key.u.ipv6.src, NULL, info);
if (IS_ERR(ndst)) if (IS_ERR(ndst))
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment