BACKPORT: ipv6: Count interface receive statistics on the ingress netdev
The statistics such as InHdrErrors should be counted on the ingress netdev rather than on the dev from the dst, which is the egress. Change-Id: I9ccf2e5b36b516c94f387488b01f7bb15ea373fc Signed-off-by: Stephen Suryaputra <ssuryaextr@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
committed by
theshaenix
parent
ed1ea53dc2
commit
f4f4f0807d
@@ -330,6 +330,20 @@ static inline struct inet6_dev *__in6_dev_get(const struct net_device *dev)
|
||||
return rcu_dereference_rtnl(dev->ip6_ptr);
|
||||
}
|
||||
|
||||
/**
|
||||
* __in6_dev_get_safely - get inet6_dev pointer from netdevice
|
||||
* @dev: network device
|
||||
*
|
||||
* This is a safer version of __in6_dev_get
|
||||
*/
|
||||
static inline struct inet6_dev *__in6_dev_get_safely(const struct net_device *dev)
|
||||
{
|
||||
if (likely(dev))
|
||||
return rcu_dereference_rtnl(dev->ip6_ptr);
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* in6_dev_get - get inet6_dev pointer from netdevice
|
||||
* @dev: network device
|
||||
|
||||
@@ -282,6 +282,7 @@ static const struct tlvtype_proc tlvprocdestopt_lst[] = {
|
||||
|
||||
static int ipv6_destopt_rcv(struct sk_buff *skb)
|
||||
{
|
||||
struct inet6_dev *idev = __in6_dev_get(skb->dev);
|
||||
struct inet6_skb_parm *opt = IP6CB(skb);
|
||||
#if IS_ENABLED(CONFIG_IPV6_MIP6)
|
||||
__u16 dstbuf;
|
||||
@@ -293,7 +294,7 @@ static int ipv6_destopt_rcv(struct sk_buff *skb)
|
||||
if (!pskb_may_pull(skb, skb_transport_offset(skb) + 8) ||
|
||||
!pskb_may_pull(skb, (skb_transport_offset(skb) +
|
||||
((skb_transport_header(skb)[1] + 1) << 3)))) {
|
||||
__IP6_INC_STATS(dev_net(dst->dev), ip6_dst_idev(dst),
|
||||
__IP6_INC_STATS(dev_net(dst->dev), idev,
|
||||
IPSTATS_MIB_INHDRERRORS);
|
||||
fail_and_free:
|
||||
kfree_skb(skb);
|
||||
@@ -321,8 +322,7 @@ fail_and_free:
|
||||
return 1;
|
||||
}
|
||||
|
||||
__IP6_INC_STATS(dev_net(dst->dev),
|
||||
ip6_dst_idev(dst), IPSTATS_MIB_INHDRERRORS);
|
||||
__IP6_INC_STATS(net, idev, IPSTATS_MIB_INHDRERRORS);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -418,8 +418,7 @@ looped_back:
|
||||
}
|
||||
|
||||
if (hdr->segments_left >= (hdr->hdrlen >> 1)) {
|
||||
__IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)),
|
||||
IPSTATS_MIB_INHDRERRORS);
|
||||
__IP6_INC_STATS(net, idev, IPSTATS_MIB_INHDRERRORS);
|
||||
icmpv6_param_prob(skb, ICMPV6_HDR_FIELD,
|
||||
((&hdr->segments_left) -
|
||||
skb_network_header(skb)));
|
||||
@@ -458,8 +457,7 @@ looped_back:
|
||||
|
||||
if (skb_dst(skb)->dev->flags & IFF_LOOPBACK) {
|
||||
if (ipv6_hdr(skb)->hop_limit <= 1) {
|
||||
__IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)),
|
||||
IPSTATS_MIB_INHDRERRORS);
|
||||
__IP6_INC_STATS(net, idev, IPSTATS_MIB_INHDRERRORS);
|
||||
icmpv6_send(skb, ICMPV6_TIME_EXCEED,
|
||||
ICMPV6_EXC_HOPLIMIT, 0);
|
||||
kfree_skb(skb);
|
||||
@@ -483,10 +481,10 @@ looped_back:
|
||||
/* called with rcu_read_lock() */
|
||||
static int ipv6_rthdr_rcv(struct sk_buff *skb)
|
||||
{
|
||||
struct inet6_dev *idev = __in6_dev_get(skb->dev);
|
||||
struct inet6_skb_parm *opt = IP6CB(skb);
|
||||
struct in6_addr *addr = NULL;
|
||||
struct in6_addr daddr;
|
||||
struct inet6_dev *idev;
|
||||
int n, i;
|
||||
struct ipv6_rt_hdr *hdr;
|
||||
struct rt0_hdr *rthdr;
|
||||
@@ -500,8 +498,7 @@ static int ipv6_rthdr_rcv(struct sk_buff *skb)
|
||||
if (!pskb_may_pull(skb, skb_transport_offset(skb) + 8) ||
|
||||
!pskb_may_pull(skb, (skb_transport_offset(skb) +
|
||||
((skb_transport_header(skb)[1] + 1) << 3)))) {
|
||||
__IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)),
|
||||
IPSTATS_MIB_INHDRERRORS);
|
||||
__IP6_INC_STATS(net, idev, IPSTATS_MIB_INHDRERRORS);
|
||||
kfree_skb(skb);
|
||||
return -1;
|
||||
}
|
||||
@@ -510,8 +507,7 @@ static int ipv6_rthdr_rcv(struct sk_buff *skb)
|
||||
|
||||
if (ipv6_addr_is_multicast(&ipv6_hdr(skb)->daddr) ||
|
||||
skb->pkt_type != PACKET_HOST) {
|
||||
__IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)),
|
||||
IPSTATS_MIB_INADDRERRORS);
|
||||
__IP6_INC_STATS(net, idev, IPSTATS_MIB_INADDRERRORS);
|
||||
kfree_skb(skb);
|
||||
return -1;
|
||||
}
|
||||
@@ -529,7 +525,7 @@ looped_back:
|
||||
* processed by own
|
||||
*/
|
||||
if (!addr) {
|
||||
__IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)),
|
||||
__IP6_INC_STATS(net, idev,
|
||||
IPSTATS_MIB_INADDRERRORS);
|
||||
kfree_skb(skb);
|
||||
return -1;
|
||||
@@ -555,8 +551,7 @@ looped_back:
|
||||
goto unknown_rh;
|
||||
/* Silently discard invalid RTH type 2 */
|
||||
if (hdr->hdrlen != 2 || hdr->segments_left != 1) {
|
||||
__IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)),
|
||||
IPSTATS_MIB_INHDRERRORS);
|
||||
__IP6_INC_STATS(net, idev, IPSTATS_MIB_INHDRERRORS);
|
||||
kfree_skb(skb);
|
||||
return -1;
|
||||
}
|
||||
@@ -574,8 +569,7 @@ looped_back:
|
||||
n = hdr->hdrlen >> 1;
|
||||
|
||||
if (hdr->segments_left > n) {
|
||||
__IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)),
|
||||
IPSTATS_MIB_INHDRERRORS);
|
||||
__IP6_INC_STATS(net, idev, IPSTATS_MIB_INHDRERRORS);
|
||||
icmpv6_param_prob(skb, ICMPV6_HDR_FIELD,
|
||||
((&hdr->segments_left) -
|
||||
skb_network_header(skb)));
|
||||
@@ -611,14 +605,12 @@ looped_back:
|
||||
if (xfrm6_input_addr(skb, (xfrm_address_t *)addr,
|
||||
(xfrm_address_t *)&ipv6_hdr(skb)->saddr,
|
||||
IPPROTO_ROUTING) < 0) {
|
||||
__IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)),
|
||||
IPSTATS_MIB_INADDRERRORS);
|
||||
__IP6_INC_STATS(net, idev, IPSTATS_MIB_INADDRERRORS);
|
||||
kfree_skb(skb);
|
||||
return -1;
|
||||
}
|
||||
if (!ipv6_chk_home_addr(dev_net(skb_dst(skb)->dev), addr)) {
|
||||
__IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)),
|
||||
IPSTATS_MIB_INADDRERRORS);
|
||||
__IP6_INC_STATS(net, idev, IPSTATS_MIB_INADDRERRORS);
|
||||
kfree_skb(skb);
|
||||
return -1;
|
||||
}
|
||||
@@ -629,8 +621,7 @@ looped_back:
|
||||
}
|
||||
|
||||
if (ipv6_addr_is_multicast(addr)) {
|
||||
__IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)),
|
||||
IPSTATS_MIB_INADDRERRORS);
|
||||
__IP6_INC_STATS(net, idev, IPSTATS_MIB_INADDRERRORS);
|
||||
kfree_skb(skb);
|
||||
return -1;
|
||||
}
|
||||
@@ -649,8 +640,7 @@ looped_back:
|
||||
|
||||
if (skb_dst(skb)->dev->flags&IFF_LOOPBACK) {
|
||||
if (ipv6_hdr(skb)->hop_limit <= 1) {
|
||||
__IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)),
|
||||
IPSTATS_MIB_INHDRERRORS);
|
||||
__IP6_INC_STATS(net, idev, IPSTATS_MIB_INHDRERRORS);
|
||||
icmpv6_send(skb, ICMPV6_TIME_EXCEED, ICMPV6_EXC_HOPLIMIT,
|
||||
0);
|
||||
kfree_skb(skb);
|
||||
@@ -665,7 +655,7 @@ looped_back:
|
||||
return -1;
|
||||
|
||||
unknown_rh:
|
||||
__IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)), IPSTATS_MIB_INHDRERRORS);
|
||||
__IP6_INC_STATS(net, idev, IPSTATS_MIB_INHDRERRORS);
|
||||
icmpv6_param_prob(skb, ICMPV6_HDR_FIELD,
|
||||
(&hdr->type) - skb_network_header(skb));
|
||||
return -1;
|
||||
@@ -757,34 +747,31 @@ static bool ipv6_hop_ra(struct sk_buff *skb, int optoff)
|
||||
static bool ipv6_hop_jumbo(struct sk_buff *skb, int optoff)
|
||||
{
|
||||
const unsigned char *nh = skb_network_header(skb);
|
||||
struct inet6_dev *idev = __in6_dev_get_safely(skb->dev);
|
||||
struct net *net = ipv6_skb_net(skb);
|
||||
u32 pkt_len;
|
||||
|
||||
if (nh[optoff + 1] != 4 || (optoff & 3) != 2) {
|
||||
net_dbg_ratelimited("ipv6_hop_jumbo: wrong jumbo opt length/alignment %d\n",
|
||||
nh[optoff+1]);
|
||||
__IP6_INC_STATS(net, ipv6_skb_idev(skb),
|
||||
IPSTATS_MIB_INHDRERRORS);
|
||||
__IP6_INC_STATS(net, idev, IPSTATS_MIB_INHDRERRORS);
|
||||
goto drop;
|
||||
}
|
||||
|
||||
pkt_len = ntohl(*(__be32 *)(nh + optoff + 2));
|
||||
if (pkt_len <= IPV6_MAXPLEN) {
|
||||
__IP6_INC_STATS(net, ipv6_skb_idev(skb),
|
||||
IPSTATS_MIB_INHDRERRORS);
|
||||
__IP6_INC_STATS(net, idev, IPSTATS_MIB_INHDRERRORS);
|
||||
icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, optoff+2);
|
||||
return false;
|
||||
}
|
||||
if (ipv6_hdr(skb)->payload_len) {
|
||||
__IP6_INC_STATS(net, ipv6_skb_idev(skb),
|
||||
IPSTATS_MIB_INHDRERRORS);
|
||||
__IP6_INC_STATS(net, idev, IPSTATS_MIB_INHDRERRORS);
|
||||
icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, optoff);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (pkt_len > skb->len - sizeof(struct ipv6hdr)) {
|
||||
__IP6_INC_STATS(net, ipv6_skb_idev(skb),
|
||||
IPSTATS_MIB_INTRUNCATEDPKTS);
|
||||
__IP6_INC_STATS(net, idev, IPSTATS_MIB_INTRUNCATEDPKTS);
|
||||
goto drop;
|
||||
}
|
||||
|
||||
|
||||
@@ -347,7 +347,7 @@ int ip6_mc_input(struct sk_buff *skb)
|
||||
bool deliver;
|
||||
|
||||
__IP6_UPD_PO_STATS(dev_net(skb_dst(skb)->dev),
|
||||
ip6_dst_idev(skb_dst(skb)), IPSTATS_MIB_INMCAST,
|
||||
__in6_dev_get_safely(skb->dev), IPSTATS_MIB_INMCAST,
|
||||
skb->len);
|
||||
|
||||
hdr = ipv6_hdr(skb);
|
||||
|
||||
@@ -445,6 +445,7 @@ static bool ip6_pkt_too_big(const struct sk_buff *skb, unsigned int mtu)
|
||||
|
||||
int ip6_forward(struct sk_buff *skb)
|
||||
{
|
||||
struct inet6_dev *idev = __in6_dev_get_safely(skb->dev);
|
||||
struct dst_entry *dst = skb_dst(skb);
|
||||
struct ipv6hdr *hdr = ipv6_hdr(skb);
|
||||
struct inet6_skb_parm *opt = IP6CB(skb);
|
||||
@@ -464,8 +465,7 @@ int ip6_forward(struct sk_buff *skb)
|
||||
goto drop;
|
||||
|
||||
if (!xfrm6_policy_check(NULL, XFRM_POLICY_FWD, skb)) {
|
||||
__IP6_INC_STATS(net, ip6_dst_idev(dst),
|
||||
IPSTATS_MIB_INDISCARDS);
|
||||
__IP6_INC_STATS(net, idev, IPSTATS_MIB_INDISCARDS);
|
||||
goto drop;
|
||||
}
|
||||
|
||||
@@ -496,8 +496,7 @@ int ip6_forward(struct sk_buff *skb)
|
||||
/* Force OUTPUT device used as source address */
|
||||
skb->dev = dst->dev;
|
||||
icmpv6_send(skb, ICMPV6_TIME_EXCEED, ICMPV6_EXC_HOPLIMIT, 0);
|
||||
__IP6_INC_STATS(net, ip6_dst_idev(dst),
|
||||
IPSTATS_MIB_INHDRERRORS);
|
||||
__IP6_INC_STATS(net, idev, IPSTATS_MIB_INHDRERRORS);
|
||||
|
||||
kfree_skb(skb);
|
||||
return -ETIMEDOUT;
|
||||
@@ -510,15 +509,13 @@ int ip6_forward(struct sk_buff *skb)
|
||||
if (proxied > 0)
|
||||
return ip6_input(skb);
|
||||
else if (proxied < 0) {
|
||||
__IP6_INC_STATS(net, ip6_dst_idev(dst),
|
||||
IPSTATS_MIB_INDISCARDS);
|
||||
__IP6_INC_STATS(net, idev, IPSTATS_MIB_INDISCARDS);
|
||||
goto drop;
|
||||
}
|
||||
}
|
||||
|
||||
if (!xfrm6_route_forward(skb)) {
|
||||
__IP6_INC_STATS(net, ip6_dst_idev(dst),
|
||||
IPSTATS_MIB_INDISCARDS);
|
||||
__IP6_INC_STATS(net, idev, IPSTATS_MIB_INDISCARDS);
|
||||
goto drop;
|
||||
}
|
||||
dst = skb_dst(skb);
|
||||
@@ -575,8 +572,7 @@ int ip6_forward(struct sk_buff *skb)
|
||||
/* Again, force OUTPUT device used as source address */
|
||||
skb->dev = dst->dev;
|
||||
icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu);
|
||||
__IP6_INC_STATS(net, ip6_dst_idev(dst),
|
||||
IPSTATS_MIB_INTOOBIGERRORS);
|
||||
__IP6_INC_STATS(net, idev, IPSTATS_MIB_INTOOBIGERRORS);
|
||||
__IP6_INC_STATS(net, ip6_dst_idev(dst),
|
||||
IPSTATS_MIB_FRAGFAILS);
|
||||
kfree_skb(skb);
|
||||
@@ -600,7 +596,7 @@ int ip6_forward(struct sk_buff *skb)
|
||||
ip6_forward_finish);
|
||||
|
||||
error:
|
||||
__IP6_INC_STATS(net, ip6_dst_idev(dst), IPSTATS_MIB_INADDRERRORS);
|
||||
__IP6_INC_STATS(net, idev, IPSTATS_MIB_INADDRERRORS);
|
||||
drop:
|
||||
kfree_skb(skb);
|
||||
return -EINVAL;
|
||||
|
||||
@@ -375,7 +375,7 @@ static int ipv6_frag_rcv(struct sk_buff *skb)
|
||||
spin_unlock(&fq->q.lock);
|
||||
inet_frag_put(&fq->q);
|
||||
if (prob_offset) {
|
||||
__IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)),
|
||||
__IP6_INC_STATS(net, __in6_dev_get_safely(skb->dev),
|
||||
IPSTATS_MIB_INHDRERRORS);
|
||||
/* icmpv6_param_prob() calls kfree_skb(skb) */
|
||||
icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, prob_offset);
|
||||
@@ -388,7 +388,7 @@ static int ipv6_frag_rcv(struct sk_buff *skb)
|
||||
return -1;
|
||||
|
||||
fail_hdr:
|
||||
__IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)),
|
||||
__IP6_INC_STATS(net, __in6_dev_get_safely(skb->dev),
|
||||
IPSTATS_MIB_INHDRERRORS);
|
||||
icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, skb_network_header_len(skb));
|
||||
return -1;
|
||||
|
||||
@@ -3645,7 +3645,8 @@ static int ip6_pkt_drop(struct sk_buff *skb, u8 code, int ipstats_mib_noroutes)
|
||||
case IPSTATS_MIB_INNOROUTES:
|
||||
type = ipv6_addr_type(&ipv6_hdr(skb)->daddr);
|
||||
if (type == IPV6_ADDR_ANY) {
|
||||
IP6_INC_STATS(dev_net(dst->dev), ip6_dst_idev(dst),
|
||||
IP6_INC_STATS(dev_net(dst->dev),
|
||||
__in6_dev_get_safely(skb->dev),
|
||||
IPSTATS_MIB_INADDRERRORS);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -266,12 +266,13 @@ static inline bool decrement_ttl(struct netns_ipvs *ipvs,
|
||||
|
||||
/* check and decrement ttl */
|
||||
if (ipv6_hdr(skb)->hop_limit <= 1) {
|
||||
struct inet6_dev *idev = __in6_dev_get_safely(skb->dev);
|
||||
|
||||
/* Force OUTPUT device used as source address */
|
||||
skb->dev = dst->dev;
|
||||
icmpv6_send(skb, ICMPV6_TIME_EXCEED,
|
||||
ICMPV6_EXC_HOPLIMIT, 0);
|
||||
IP6_INC_STATS(net, ip6_dst_idev(dst),
|
||||
IPSTATS_MIB_INHDRERRORS);
|
||||
IP6_INC_STATS(net, idev, IPSTATS_MIB_INHDRERRORS);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user