diff --git a/include/net/ip6_tunnel.h b/include/net/ip6_tunnel.h
index b99805ee2fd1..95f6d12254df 100644
--- a/include/net/ip6_tunnel.h
+++ b/include/net/ip6_tunnel.h
@@ -143,7 +143,8 @@ int ip6_tnl_rcv(struct ip6_tnl *tunnel, struct sk_buff *skb,
int ip6_tnl_xmit_ctl(struct ip6_tnl *t, const struct in6_addr *laddr,
const struct in6_addr *raddr);
int ip6_tnl_xmit(struct sk_buff *skb, struct net_device *dev, __u8 dsfield,
- struct flowi6 *fl6, int encap_limit, __u32 *pmtu, __u8 proto);
+ struct flowi6 *fl6, int encap_limit, __u32 *pmtu, __u8 proto,
+ enum skb_drop_reason *reason);
__u16 ip6_tnl_parse_tlv_enc_lim(struct sk_buff *skb, __u8 *raw);
__u32 ip6_tnl_get_cap(struct ip6_tnl *t, const struct in6_addr *laddr,
const struct in6_addr *raddr);
diff --git a/net/ipv6/ip6_gre.c b/net/ipv6/ip6_gre.c
index 047c4f57a828..a510be5ad702 100644
--- a/net/ipv6/ip6_gre.c
+++ b/net/ipv6/ip6_gre.c
@@ -734,7 +734,8 @@ static struct ip_tunnel_info *skb_tunnel_info_txcheck(struct sk_buff *skb)
static netdev_tx_t __gre6_xmit(struct sk_buff *skb,
struct net_device *dev, __u8 dsfield,
struct flowi6 *fl6, int encap_limit,
- __u32 *pmtu, __be16 proto)
+ __u32 *pmtu, __be16 proto,
+ enum skb_drop_reason *reason)
{
struct ip6_tnl *tunnel = netdev_priv(dev);
IP_TUNNEL_DECLARE_FLAGS(flags);@@ -758,8 +759,10 @@ static netdev_tx_t __gre6_xmit(struct sk_buff *skb,
tun_info = skb_tunnel_info_txcheck(skb);
if (IS_ERR(tun_info) ||
- unlikely(ip_tunnel_info_af(tun_info) != AF_INET6))
+ unlikely(ip_tunnel_info_af(tun_info) != AF_INET6)) {
+ *reason = SKB_DROP_REASON_TUNNEL_TXINFO;
return -EINVAL;
+ }
key = &tun_info->key;
memset(fl6, 0, sizeof(*fl6));@@ -777,8 +780,11 @@ static netdev_tx_t __gre6_xmit(struct sk_buff *skb,
ip_tunnel_flags_and(flags, flags, key->tun_flags);
tun_hlen = gre_calc_hlen(flags);
- if (skb_cow_head(skb, dev->needed_headroom ?: tun_hlen + tunnel->encap_hlen))
+ if (skb_cow_head(skb, dev->needed_headroom ?:
+ tun_hlen + tunnel->encap_hlen)) {
+ *reason = SKB_DROP_REASON_NOMEM;
return -ENOMEM;
+ }
gre_build_header(skb, tun_hlen,
flags, protocol,@@ -788,8 +794,10 @@ static netdev_tx_t __gre6_xmit(struct sk_buff *skb,
0);
} else {
- if (skb_cow_head(skb, dev->needed_headroom ?: tunnel->hlen))
+ if (skb_cow_head(skb, dev->needed_headroom ?: tunnel->hlen)) {
+ *reason = SKB_DROP_REASON_NOMEM;
return -ENOMEM;
+ }
ip_tunnel_flags_copy(flags, tunnel->parms.o_flags);
@@ -801,10 +809,11 @@ static netdev_tx_t __gre6_xmit(struct sk_buff *skb,
}
return ip6_tnl_xmit(skb, dev, dsfield, fl6, encap_limit, pmtu,
- NEXTHDR_GRE);
+ NEXTHDR_GRE, reason);
}
-static inline int ip6gre_xmit_ipv4(struct sk_buff *skb, struct net_device *dev)
+static inline int ip6gre_xmit_ipv4(struct sk_buff *skb, struct net_device *dev,
+ enum skb_drop_reason *reason)
{
struct ip6_tnl *t = netdev_priv(dev);
int encap_limit = -1;@@ -821,11 +830,13 @@ static inline int ip6gre_xmit_ipv4(struct sk_buff *skb, struct net_device *dev)
err = gre_handle_offloads(skb, test_bit(IP_TUNNEL_CSUM_BIT,
t->parms.o_flags));
- if (err)
+ if (err) {
+ *reason = SKB_DROP_REASON_NOMEM;
return -1;
+ }
err = __gre6_xmit(skb, dev, dsfield, &fl6, encap_limit, &mtu,
- skb->protocol);
+ skb->protocol, reason);
if (err != 0) {
/* XXX: send ICMP error even if DF is not set. */
if (err == -EMSGSIZE)@@ -837,7 +848,8 @@ static inline int ip6gre_xmit_ipv4(struct sk_buff *skb, struct net_device *dev)
return 0;
}
-static inline int ip6gre_xmit_ipv6(struct sk_buff *skb, struct net_device *dev)
+static inline int ip6gre_xmit_ipv6(struct sk_buff *skb, struct net_device *dev,
+ enum skb_drop_reason *reason)
{
struct ip6_tnl *t = netdev_priv(dev);
struct ipv6hdr *ipv6h = ipv6_hdr(skb);@@ -847,19 +859,25 @@ static inline int ip6gre_xmit_ipv6(struct sk_buff *skb, struct net_device *dev)
__u32 mtu;
int err;
- if (ipv6_addr_equal(&t->parms.raddr, &ipv6h->saddr))
+ if (ipv6_addr_equal(&t->parms.raddr, &ipv6h->saddr)) {
+ *reason = SKB_DROP_REASON_RECURSION_LIMIT;
return -1;
+ }
if (!t->parms.collect_md &&
- prepare_ip6gre_xmit_ipv6(skb, dev, &fl6, &dsfield, &encap_limit))
+ prepare_ip6gre_xmit_ipv6(skb, dev, &fl6, &dsfield, &encap_limit)) {
+ *reason = SKB_DROP_REASON_IPV6_BAD_EXTHDR;
return -1;
+ }
if (gre_handle_offloads(skb, test_bit(IP_TUNNEL_CSUM_BIT,
- t->parms.o_flags)))
+ t->parms.o_flags))) {
+ *reason = SKB_DROP_REASON_NOMEM;
return -1;
+ }
err = __gre6_xmit(skb, dev, dsfield, &fl6, encap_limit,
- &mtu, skb->protocol);
+ &mtu, skb->protocol, reason);
if (err != 0) {
if (err == -EMSGSIZE)
icmpv6_ndo_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu);@@ -869,7 +887,8 @@ static inline int ip6gre_xmit_ipv6(struct sk_buff *skb, struct net_device *dev)
return 0;
}
-static int ip6gre_xmit_other(struct sk_buff *skb, struct net_device *dev)
+static int ip6gre_xmit_other(struct sk_buff *skb, struct net_device *dev,
+ enum skb_drop_reason *reason)
{
struct ip6_tnl *t = netdev_priv(dev);
int encap_limit = -1;@@ -879,14 +898,19 @@ static int ip6gre_xmit_other(struct sk_buff *skb, struct net_device *dev)
int err;
if (!t->parms.collect_md &&
- prepare_ip6gre_xmit_other(skb, dev, &fl6, &dsfield, &encap_limit))
+ prepare_ip6gre_xmit_other(skb, dev, &fl6, &dsfield, &encap_limit)) {
+ *reason = SKB_DROP_REASON_IPV6_BAD_EXTHDR;
return -1;
+ }
err = gre_handle_offloads(skb, test_bit(IP_TUNNEL_CSUM_BIT,
t->parms.o_flags));
- if (err)
+ if (err) {
+ *reason = SKB_DROP_REASON_NOMEM;
return err;
- err = __gre6_xmit(skb, dev, dsfield, &fl6, encap_limit, &mtu, skb->protocol);
+ }
+ err = __gre6_xmit(skb, dev, dsfield, &fl6, encap_limit, &mtu,
+ skb->protocol, reason);
return err;
}@@ -894,16 +918,20 @@ static int ip6gre_xmit_other(struct sk_buff *skb, struct net_device *dev)
static netdev_tx_t ip6gre_tunnel_xmit(struct sk_buff *skb,
struct net_device *dev)
{
+ enum skb_drop_reason reason = SKB_DROP_REASON_NOT_SPECIFIED;
struct ip_tunnel_info *tun_info = NULL;
struct ip6_tnl *t = netdev_priv(dev);
__be16 payload_protocol;
int ret;
- if (!pskb_inet_may_pull(skb))
+ reason = pskb_inet_may_pull_reason(skb);
+ if (reason)
goto tx_err;
- if (!ip6_tnl_xmit_ctl(t, &t->parms.laddr, &t->parms.raddr))
+ if (!ip6_tnl_xmit_ctl(t, &t->parms.laddr, &t->parms.raddr)) {
+ reason = SKB_DROP_REASON_DEV_READY;
goto tx_err;
+ }
if (t->parms.collect_md)
tun_info = skb_tunnel_info_txcheck(skb);@@ -911,13 +939,13 @@ static netdev_tx_t ip6gre_tunnel_xmit(struct sk_buff *skb,
payload_protocol = skb_protocol(skb, true);
switch (payload_protocol) {
case htons(ETH_P_IP):
- ret = ip6gre_xmit_ipv4(skb, dev);
+ ret = ip6gre_xmit_ipv4(skb, dev, &reason);
break;
case htons(ETH_P_IPV6):
- ret = ip6gre_xmit_ipv6(skb, dev);
+ ret = ip6gre_xmit_ipv6(skb, dev, &reason);
break;
default:
- ret = ip6gre_xmit_other(skb, dev);
+ ret = ip6gre_xmit_other(skb, dev, &reason);
break;
}
@@ -930,13 +958,14 @@ static netdev_tx_t ip6gre_tunnel_xmit(struct sk_buff *skb,
if (!IS_ERR(tun_info))
DEV_STATS_INC(dev, tx_errors);
DEV_STATS_INC(dev, tx_dropped);
- kfree_skb(skb);
+ kfree_skb_reason(skb, reason);
return NETDEV_TX_OK;
}
static netdev_tx_t ip6erspan_tunnel_xmit(struct sk_buff *skb,
struct net_device *dev)
{
+ enum skb_drop_reason reason = SKB_DROP_REASON_NOT_SPECIFIED;
struct ip_tunnel_info *tun_info = NULL;
struct ip6_tnl *t = netdev_priv(dev);
struct dst_entry *dst = skb_dst(skb);@@ -950,18 +979,25 @@ static netdev_tx_t ip6erspan_tunnel_xmit(struct sk_buff *skb,
__u32 mtu;
int nhoff;
- if (!pskb_inet_may_pull(skb))
+ reason = pskb_inet_may_pull_reason(skb);
+ if (reason)
goto tx_err;
- if (!ip6_tnl_xmit_ctl(t, &t->parms.laddr, &t->parms.raddr))
+ if (!ip6_tnl_xmit_ctl(t, &t->parms.laddr, &t->parms.raddr)) {
+ reason = SKB_DROP_REASON_DEV_READY;
goto tx_err;
+ }
- if (gre_handle_offloads(skb, false))
+ if (gre_handle_offloads(skb, false)) {
+ reason = SKB_DROP_REASON_NOMEM;
goto tx_err;
+ }
if (skb->len > dev->mtu + dev->hard_header_len) {
- if (pskb_trim(skb, dev->mtu + dev->hard_header_len))
+ if (pskb_trim(skb, dev->mtu + dev->hard_header_len)) {
+ reason = SKB_DROP_REASON_NOMEM;
goto tx_err;
+ }
truncate = true;
}
@@ -981,8 +1017,10 @@ static netdev_tx_t ip6erspan_tunnel_xmit(struct sk_buff *skb,
truncate = true;
}
- if (skb_cow_head(skb, dev->needed_headroom ?: t->hlen))
+ if (skb_cow_head(skb, dev->needed_headroom ?: t->hlen)) {
+ reason = SKB_DROP_REASON_NOMEM;
goto tx_err;
+ }
IPCB(skb)->flags = 0;
@@ -996,8 +1034,10 @@ static netdev_tx_t ip6erspan_tunnel_xmit(struct sk_buff *skb,
tun_info = skb_tunnel_info_txcheck(skb);
if (IS_ERR(tun_info) ||
- unlikely(ip_tunnel_info_af(tun_info) != AF_INET6))
+ unlikely(ip_tunnel_info_af(tun_info) != AF_INET6)) {
+ reason = SKB_DROP_REASON_TUNNEL_TXINFO;
goto tx_err;
+ }
key = &tun_info->key;
memset(&fl6, 0, sizeof(fl6));@@ -1009,10 +1049,14 @@ static netdev_tx_t ip6erspan_tunnel_xmit(struct sk_buff *skb,
dsfield = key->tos;
if (!test_bit(IP_TUNNEL_ERSPAN_OPT_BIT,
- tun_info->key.tun_flags))
+ tun_info->key.tun_flags)) {
+ reason = SKB_DROP_REASON_TUNNEL_TXINFO;
goto tx_err;
- if (tun_info->options_len < sizeof(*md))
+ }
+ if (tun_info->options_len < sizeof(*md)) {
+ reason = SKB_DROP_REASON_TUNNEL_TXINFO;
goto tx_err;
+ }
md = ip_tunnel_info_opts(tun_info);
tun_id = tunnel_id_to_key32(key->tun_id);@@ -1030,6 +1074,7 @@ static netdev_tx_t ip6erspan_tunnel_xmit(struct sk_buff *skb,
truncate, false);
proto = htons(ETH_P_ERSPAN2);
} else {
+ reason = SKB_DROP_REASON_UNHANDLED_PROTO;
goto tx_err;
}
} else {@@ -1040,11 +1085,16 @@ static netdev_tx_t ip6erspan_tunnel_xmit(struct sk_buff *skb,
&dsfield, &encap_limit);
break;
case htons(ETH_P_IPV6):
- if (ipv6_addr_equal(&t->parms.raddr, &ipv6_hdr(skb)->saddr))
+ if (ipv6_addr_equal(&t->parms.raddr,
+ &ipv6_hdr(skb)->saddr)) {
+ reason = SKB_DROP_REASON_RECURSION_LIMIT;
goto tx_err;
+ }
if (prepare_ip6gre_xmit_ipv6(skb, dev, &fl6,
- &dsfield, &encap_limit))
+ &dsfield, &encap_limit)) {
+ reason = SKB_DROP_REASON_IPV6_BAD_EXTHDR;
goto tx_err;
+ }
break;
default:
memcpy(&fl6, &t->fl.u.ip6, sizeof(fl6));@@ -1063,6 +1113,7 @@ static netdev_tx_t ip6erspan_tunnel_xmit(struct sk_buff *skb,
truncate, false);
proto = htons(ETH_P_ERSPAN2);
} else {
+ reason = SKB_DROP_REASON_UNHANDLED_PROTO;
goto tx_err;
}
@@ -1081,7 +1132,7 @@ static netdev_tx_t ip6erspan_tunnel_xmit(struct sk_buff *skb,
dst->ops->update_pmtu(dst, NULL, skb, mtu, false);
}
err = ip6_tnl_xmit(skb, dev, dsfield, &fl6, encap_limit, &mtu,
- NEXTHDR_GRE);
+ NEXTHDR_GRE, &reason);
if (err != 0) {
/* XXX: send ICMP error even if DF is not set. */
if (err == -EMSGSIZE) {@@ -1100,7 +1151,7 @@ static netdev_tx_t ip6erspan_tunnel_xmit(struct sk_buff *skb,
if (!IS_ERR(tun_info))
DEV_STATS_INC(dev, tx_errors);
DEV_STATS_INC(dev, tx_dropped);
- kfree_skb(skb);
+ kfree_skb_reason(skb, reason);
return NETDEV_TX_OK;
}
diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c
index 458ce328311b..d804c67c4be3 100644
--- a/net/ipv6/ip6_tunnel.c
+++ b/net/ipv6/ip6_tunnel.c
@@ -1097,6 +1097,7 @@ EXPORT_SYMBOL_GPL(ip6_tnl_xmit_ctl);
* @encap_limit: encapsulation limit
* @pmtu: Path MTU is stored if packet is too big
* @proto: next header value
+ * @reason: drop reason, only written when the packet is dropped
*
* Description:
* Build new header and do some sanity checks on the packet before sending
@@ -1110,7 +1111,7 @@ EXPORT_SYMBOL_GPL(ip6_tnl_xmit_ctl);
int ip6_tnl_xmit(struct sk_buff *skb, struct net_device *dev, __u8 dsfield,
struct flowi6 *fl6, int encap_limit, __u32 *pmtu,
- __u8 proto)
+ __u8 proto, enum skb_drop_reason *reason)
{
struct ip6_tnl *t = netdev_priv(dev);
struct net *net = t->net;@@ -1143,13 +1144,17 @@ int ip6_tnl_xmit(struct sk_buff *skb, struct net_device *dev, __u8 dsfield,
struct neighbour *neigh;
int addr_type;
- if (!skb_dst(skb))
+ if (!skb_dst(skb)) {
+ *reason = SKB_DROP_REASON_NO_TX_TARGET;
goto tx_err_link_failure;
+ }
neigh = dst_neigh_lookup(skb_dst(skb),
&ipv6_hdr(skb)->daddr);
- if (!neigh)
+ if (!neigh) {
+ *reason = SKB_DROP_REASON_NEIGH_CREATEFAIL;
goto tx_err_link_failure;
+ }
addr6 = (struct in6_addr *)&neigh->primary_key;
addr_type = ipv6_addr_type(addr6);@@ -1162,8 +1167,10 @@ int ip6_tnl_xmit(struct sk_buff *skb, struct net_device *dev, __u8 dsfield,
} else if (payload_protocol == htons(ETH_P_IP)) {
const struct rtable *rt = skb_rtable(skb);
- if (!rt)
+ if (!rt) {
+ *reason = SKB_DROP_REASON_IP_OUTNOROUTES;
goto tx_err_link_failure;
+ }
if (rt->rt_gw_family == AF_INET6)
memcpy(&fl6->daddr, &rt->rt_gw6, sizeof(fl6->daddr));@@ -1180,8 +1187,10 @@ int ip6_tnl_xmit(struct sk_buff *skb, struct net_device *dev, __u8 dsfield,
if (use_cache)
dst = dst_cache_get(&t->dst_cache);
- if (!ip6_tnl_xmit_ctl(t, &fl6->saddr, &fl6->daddr))
+ if (!ip6_tnl_xmit_ctl(t, &fl6->saddr, &fl6->daddr)) {
+ *reason = SKB_DROP_REASON_DEV_READY;
goto tx_err_link_failure;
+ }
if (!dst) {
route_lookup:@@ -1190,18 +1199,23 @@ int ip6_tnl_xmit(struct sk_buff *skb, struct net_device *dev, __u8 dsfield,
dst = ip6_route_output(net, NULL, fl6);
- if (dst->error)
+ if (dst->error) {
+ *reason = SKB_DROP_REASON_IP_OUTNOROUTES;
goto tx_err_link_failure;
+ }
dst = xfrm_lookup(net, dst, flowi6_to_flowi(fl6), NULL, 0);
if (IS_ERR(dst)) {
err = PTR_ERR(dst);
dst = NULL;
+ *reason = SKB_DROP_REASON_IP_OUTNOROUTES;
goto tx_err_link_failure;
}
if (t->parms.collect_md && ipv6_addr_any(&fl6->saddr) &&
ipv6_dev_get_saddr(net, ip6_dst_idev(dst)->dev,
- &fl6->daddr, 0, &fl6->saddr))
+ &fl6->daddr, 0, &fl6->saddr)) {
+ *reason = SKB_DROP_REASON_NO_TX_TARGET;
goto tx_err_link_failure;
+ }
ndst = dst;
}
@@ -1211,6 +1225,7 @@ int ip6_tnl_xmit(struct sk_buff *skb, struct net_device *dev, __u8 dsfield,
DEV_STATS_INC(dev, collisions);
net_warn_ratelimited("%s: Local routing loop detected!\n",
t->parms.name);
+ *reason = SKB_DROP_REASON_RECURSION_LIMIT;
goto tx_err_dst_release;
}
mtu = dst6_mtu(dst) - eth_hlen - psh_hlen - t->tun_hlen;@@ -1225,6 +1240,7 @@ int ip6_tnl_xmit(struct sk_buff *skb, struct net_device *dev, __u8 dsfield,
if (skb->len - t->tun_hlen - eth_hlen > mtu && !skb_is_gso(skb)) {
*pmtu = mtu;
err = -EMSGSIZE;
+ *reason = SKB_DROP_REASON_PKT_TOO_BIG;
goto tx_err_dst_release;
}
@@ -1247,12 +1263,16 @@ int ip6_tnl_xmit(struct sk_buff *skb, struct net_device *dev, __u8 dsfield,
*/
max_headroom += LL_RESERVED_SPACE(tdev);
- if (skb_cow_head(skb, max_headroom))
+ if (skb_cow_head(skb, max_headroom)) {
+ *reason = SKB_DROP_REASON_NOMEM;
goto tx_err_dst_release;
+ }
if (t->parms.collect_md) {
- if (t->encap.type != TUNNEL_ENCAP_NONE)
+ if (t->encap.type != TUNNEL_ENCAP_NONE) {
+ *reason = SKB_DROP_REASON_TNL_ENCAP;
goto tx_err_dst_release;
+ }
} else {
if (use_cache && ndst)
dst_cache_set_ip6(&t->dst_cache, ndst, &fl6->saddr);@@ -1276,8 +1296,10 @@ int ip6_tnl_xmit(struct sk_buff *skb, struct net_device *dev, __u8 dsfield,
ip_tunnel_adj_headroom(dev, max_headroom);
err = ip6_tnl_encap(skb, t, &proto, fl6);
- if (err)
+ if (err) {
+ *reason = SKB_DROP_REASON_TNL_ENCAP;
return err;
+ }
if (encap_limit >= 0) {
init_tel_txopt(&opt, encap_limit);@@ -1306,7 +1328,7 @@ EXPORT_SYMBOL(ip6_tnl_xmit);
static inline int
ipxip6_tnl_xmit(struct sk_buff *skb, struct net_device *dev,
- u8 protocol)
+ u8 protocol, enum skb_drop_reason *reason)
{
struct ip6_tnl *t = netdev_priv(dev);
struct ipv6hdr *ipv6h;@@ -1320,8 +1342,10 @@ ipxip6_tnl_xmit(struct sk_buff *skb, struct net_device *dev,
int err;
tproto = READ_ONCE(t->parms.proto);
- if (tproto != protocol && tproto != 0)
+ if (tproto != protocol && tproto != 0) {
+ *reason = SKB_DROP_REASON_UNHANDLED_PROTO;
return -1;
+ }
if (t->parms.collect_md) {
struct ip_tunnel_info *tun_info;@@ -1329,8 +1353,10 @@ ipxip6_tnl_xmit(struct sk_buff *skb, struct net_device *dev,
tun_info = skb_tunnel_info(skb);
if (unlikely(!tun_info || !(tun_info->mode & IP_TUNNEL_INFO_TX) ||
- ip_tunnel_info_af(tun_info) != AF_INET6))
+ ip_tunnel_info_af(tun_info) != AF_INET6)) {
+ *reason = SKB_DROP_REASON_TUNNEL_TXINFO;
return -1;
+ }
key = &tun_info->key;
memset(&fl6, 0, sizeof(fl6));
fl6.flowi6_proto = protocol;@@ -1367,6 +1393,7 @@ ipxip6_tnl_xmit(struct sk_buff *skb, struct net_device *dev,
if (tel->encap_limit == 0) {
icmpv6_ndo_send(skb, ICMPV6_PARAMPROB,
ICMPV6_HDR_FIELD, offset + 2);
+ *reason = SKB_DROP_REASON_IPV6_BAD_EXTHDR;
return -1;
}
encap_limit = tel->encap_limit - 1;@@ -1408,13 +1435,15 @@ ipxip6_tnl_xmit(struct sk_buff *skb, struct net_device *dev,
fl6.flowi6_uid = sock_net_uid(dev_net(dev), NULL);
dsfield = INET_ECN_encapsulate(dsfield, orig_dsfield);
- if (iptunnel_handle_offloads(skb, SKB_GSO_IPXIP6))
+ if (iptunnel_handle_offloads(skb, SKB_GSO_IPXIP6)) {
+ *reason = SKB_DROP_REASON_NOMEM;
return -1;
+ }
skb_set_inner_ipproto(skb, protocol);
err = ip6_tnl_xmit(skb, dev, dsfield, &fl6, encap_limit, &mtu,
- protocol);
+ protocol, reason);
if (err != 0) {
/* XXX: send ICMP error even if DF is not set. */
if (err == -EMSGSIZE)@@ -1429,6 +1458,7 @@ ipxip6_tnl_xmit(struct sk_buff *skb, struct net_device *dev,
default:
break;
}
+ *reason = SKB_DROP_REASON_PKT_TOO_BIG;
return -1;
}
@@ -1438,11 +1468,13 @@ ipxip6_tnl_xmit(struct sk_buff *skb, struct net_device *dev,
static netdev_tx_t
ip6_tnl_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
+ enum skb_drop_reason reason = SKB_DROP_REASON_NOT_SPECIFIED;
struct ip6_tnl *t = netdev_priv(dev);
u8 ipproto;
int ret;
- if (!pskb_inet_may_pull(skb))
+ reason = pskb_inet_may_pull_reason(skb);
+ if (reason)
goto tx_err;
switch (skb->protocol) {@@ -1450,18 +1482,21 @@ ip6_tnl_start_xmit(struct sk_buff *skb, struct net_device *dev)
ipproto = IPPROTO_IPIP;
break;
case htons(ETH_P_IPV6):
- if (ip6_tnl_addr_conflict(t, ipv6_hdr(skb)))
+ if (ip6_tnl_addr_conflict(t, ipv6_hdr(skb))) {
+ reason = SKB_DROP_REASON_RECURSION_LIMIT;
goto tx_err;
+ }
ipproto = IPPROTO_IPV6;
break;
case htons(ETH_P_MPLS_UC):
ipproto = IPPROTO_MPLS;
break;
default:
+ reason = SKB_DROP_REASON_UNHANDLED_PROTO;
goto tx_err;
}
- ret = ipxip6_tnl_xmit(skb, dev, ipproto);
+ ret = ipxip6_tnl_xmit(skb, dev, ipproto, &reason);
if (ret < 0)
goto tx_err;
@@ -1470,7 +1505,7 @@ ip6_tnl_start_xmit(struct sk_buff *skb, struct net_device *dev)
tx_err:
DEV_STATS_INC(dev, tx_errors);
DEV_STATS_INC(dev, tx_dropped);
- kfree_skb(skb);
+ kfree_skb_reason(skb, reason);
return NETDEV_TX_OK;
}
--
2.47.3