Commit e5f7e211 authored by Davide Caratti's avatar Davide Caratti Committed by David S. Miller

ip6gre: avoid tx_error when sending MLD/DAD on external tunnels

similarly to what has been done with commit 9d149045 ("geneve: change
from tx_error to tx_dropped on missing metadata"), avoid reporting errors
to userspace in case the kernel doesn't find any tunnel information for a
skb that is going to be transmitted: an increase of tx_dropped is enough.

tested with the following script:

 # for t in ip6gre ip6gretap ip6erspan; do
 > ip link add dev gre6-test0 type $t external
 > ip address add dev gre6-test0 2001:db8::1/64
 > ip link set dev gre6-test0 up
 > sleep 30
 > ip -s -j link show dev gre6-test0 | jq \
 > '.[0].stats64.tx | {"errors": .errors, "dropped": .dropped}'
 > ip link del dev gre6-test0
 > done
Reported-by: default avatarJianlin Shi <jishi@redhat.com>
Signed-off-by: default avatarDavide Caratti <dcaratti@redhat.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent be589d04
...@@ -707,6 +707,17 @@ static int prepare_ip6gre_xmit_ipv6(struct sk_buff *skb, ...@@ -707,6 +707,17 @@ static int prepare_ip6gre_xmit_ipv6(struct sk_buff *skb,
return 0; return 0;
} }
static struct ip_tunnel_info *skb_tunnel_info_txcheck(struct sk_buff *skb)
{
struct ip_tunnel_info *tun_info;
tun_info = skb_tunnel_info(skb);
if (unlikely(!tun_info || !(tun_info->mode & IP_TUNNEL_INFO_TX)))
return ERR_PTR(-EINVAL);
return tun_info;
}
static netdev_tx_t __gre6_xmit(struct sk_buff *skb, static netdev_tx_t __gre6_xmit(struct sk_buff *skb,
struct net_device *dev, __u8 dsfield, struct net_device *dev, __u8 dsfield,
struct flowi6 *fl6, int encap_limit, struct flowi6 *fl6, int encap_limit,
...@@ -734,10 +745,9 @@ static netdev_tx_t __gre6_xmit(struct sk_buff *skb, ...@@ -734,10 +745,9 @@ static netdev_tx_t __gre6_xmit(struct sk_buff *skb,
const struct ip_tunnel_key *key; const struct ip_tunnel_key *key;
__be16 flags; __be16 flags;
tun_info = skb_tunnel_info(skb); tun_info = skb_tunnel_info_txcheck(skb);
if (unlikely(!tun_info || if (IS_ERR(tun_info) ||
!(tun_info->mode & IP_TUNNEL_INFO_TX) || unlikely(ip_tunnel_info_af(tun_info) != AF_INET6))
ip_tunnel_info_af(tun_info) != AF_INET6))
return -EINVAL; return -EINVAL;
key = &tun_info->key; key = &tun_info->key;
...@@ -908,7 +918,8 @@ static netdev_tx_t ip6gre_tunnel_xmit(struct sk_buff *skb, ...@@ -908,7 +918,8 @@ static netdev_tx_t ip6gre_tunnel_xmit(struct sk_buff *skb,
return NETDEV_TX_OK; return NETDEV_TX_OK;
tx_err: tx_err:
stats->tx_errors++; if (!t->parms.collect_md || !IS_ERR(skb_tunnel_info_txcheck(skb)))
stats->tx_errors++;
stats->tx_dropped++; stats->tx_dropped++;
kfree_skb(skb); kfree_skb(skb);
return NETDEV_TX_OK; return NETDEV_TX_OK;
...@@ -917,6 +928,7 @@ static netdev_tx_t ip6gre_tunnel_xmit(struct sk_buff *skb, ...@@ -917,6 +928,7 @@ static netdev_tx_t ip6gre_tunnel_xmit(struct sk_buff *skb,
static netdev_tx_t ip6erspan_tunnel_xmit(struct sk_buff *skb, static netdev_tx_t ip6erspan_tunnel_xmit(struct sk_buff *skb,
struct net_device *dev) struct net_device *dev)
{ {
struct ip_tunnel_info *tun_info = NULL;
struct ip6_tnl *t = netdev_priv(dev); struct ip6_tnl *t = netdev_priv(dev);
struct dst_entry *dst = skb_dst(skb); struct dst_entry *dst = skb_dst(skb);
struct net_device_stats *stats; struct net_device_stats *stats;
...@@ -964,15 +976,13 @@ static netdev_tx_t ip6erspan_tunnel_xmit(struct sk_buff *skb, ...@@ -964,15 +976,13 @@ static netdev_tx_t ip6erspan_tunnel_xmit(struct sk_buff *skb,
* for native mode, call prepare_ip6gre_xmit_{ipv4,ipv6}. * for native mode, call prepare_ip6gre_xmit_{ipv4,ipv6}.
*/ */
if (t->parms.collect_md) { if (t->parms.collect_md) {
struct ip_tunnel_info *tun_info;
const struct ip_tunnel_key *key; const struct ip_tunnel_key *key;
struct erspan_metadata *md; struct erspan_metadata *md;
__be32 tun_id; __be32 tun_id;
tun_info = skb_tunnel_info(skb); tun_info = skb_tunnel_info_txcheck(skb);
if (unlikely(!tun_info || if (IS_ERR(tun_info) ||
!(tun_info->mode & IP_TUNNEL_INFO_TX) || unlikely(ip_tunnel_info_af(tun_info) != AF_INET6))
ip_tunnel_info_af(tun_info) != AF_INET6))
goto tx_err; goto tx_err;
key = &tun_info->key; key = &tun_info->key;
...@@ -1065,7 +1075,8 @@ static netdev_tx_t ip6erspan_tunnel_xmit(struct sk_buff *skb, ...@@ -1065,7 +1075,8 @@ static netdev_tx_t ip6erspan_tunnel_xmit(struct sk_buff *skb,
tx_err: tx_err:
stats = &t->dev->stats; stats = &t->dev->stats;
stats->tx_errors++; if (!IS_ERR(tun_info))
stats->tx_errors++;
stats->tx_dropped++; stats->tx_dropped++;
kfree_skb(skb); kfree_skb(skb);
return NETDEV_TX_OK; return NETDEV_TX_OK;
......
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