Skip to content

Commit

Permalink
ipv6: Count interface receive statistics on the ingress netdev
Browse files Browse the repository at this point in the history
The statistics such as InHdrErrors should be counted on the ingress
netdev rather than on the dev from the dst, which is the egress.

Signed-off-by: Stephen Suryaputra <ssuryaextr@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
Stephen Suryaputra authored and David S. Miller committed Apr 17, 2018
1 parent 032234d commit bdb7cc6
Show file tree
Hide file tree
Showing 7 changed files with 51 additions and 52 deletions.
14 changes: 14 additions & 0 deletions include/net/addrconf.h
Original file line number Diff line number Diff line change
Expand Up @@ -307,6 +307,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
Expand Down
55 changes: 21 additions & 34 deletions net/ipv6/exthdrs.c
Original file line number Diff line number Diff line change
Expand Up @@ -280,6 +280,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;
Expand All @@ -291,7 +292,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);
Expand Down Expand Up @@ -319,8 +320,7 @@ static int ipv6_destopt_rcv(struct sk_buff *skb)
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;
}

Expand Down Expand Up @@ -416,8 +416,7 @@ static int ipv6_srh_rcv(struct sk_buff *skb)
}

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)));
Expand Down Expand Up @@ -456,8 +455,7 @@ static int ipv6_srh_rcv(struct sk_buff *skb)

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);
Expand All @@ -481,10 +479,10 @@ static int ipv6_srh_rcv(struct sk_buff *skb)
/* 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;
Expand All @@ -498,8 +496,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;
}
Expand All @@ -508,8 +505,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;
}
Expand All @@ -527,7 +523,7 @@ static int ipv6_rthdr_rcv(struct sk_buff *skb)
* 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;
Expand All @@ -553,8 +549,7 @@ static int ipv6_rthdr_rcv(struct sk_buff *skb)
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;
}
Expand All @@ -572,8 +567,7 @@ static int ipv6_rthdr_rcv(struct sk_buff *skb)
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)));
Expand Down Expand Up @@ -609,14 +603,12 @@ static int ipv6_rthdr_rcv(struct sk_buff *skb)
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;
}
Expand All @@ -627,8 +619,7 @@ static int ipv6_rthdr_rcv(struct sk_buff *skb)
}

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;
}
Expand All @@ -647,8 +638,7 @@ static int ipv6_rthdr_rcv(struct sk_buff *skb)

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);
Expand All @@ -663,7 +653,7 @@ static int ipv6_rthdr_rcv(struct sk_buff *skb)
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;
Expand Down Expand Up @@ -755,34 +745,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;
}

Expand Down
2 changes: 1 addition & 1 deletion net/ipv6/ip6_input.c
Original file line number Diff line number Diff line change
Expand Up @@ -336,7 +336,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);
Expand Down
18 changes: 7 additions & 11 deletions net/ipv6/ip6_output.c
Original file line number Diff line number Diff line change
Expand Up @@ -425,6 +425,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);
Expand All @@ -444,8 +445,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;
}

Expand Down Expand Up @@ -476,8 +476,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;
Expand All @@ -490,15 +489,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);
Expand Down Expand Up @@ -554,8 +551,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);
Expand All @@ -579,7 +575,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;
Expand Down
6 changes: 3 additions & 3 deletions net/ipv6/reassembly.c
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,7 @@ static int ip6_frag_queue(struct frag_queue *fq, struct sk_buff *skb,
((u8 *)(fhdr + 1) - (u8 *)(ipv6_hdr(skb) + 1)));

if ((unsigned int)end > IPV6_MAXPLEN) {
__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,
((u8 *)&fhdr->frag_off -
Expand Down Expand Up @@ -214,7 +214,7 @@ static int ip6_frag_queue(struct frag_queue *fq, struct sk_buff *skb,
/* RFC2460 says always send parameter problem in
* this case. -DaveM
*/
__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,
offsetof(struct ipv6hdr, payload_len));
Expand Down Expand Up @@ -536,7 +536,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;
Expand Down
3 changes: 2 additions & 1 deletion net/ipv6/route.c
Original file line number Diff line number Diff line change
Expand Up @@ -3541,7 +3541,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;
}
Expand Down
5 changes: 3 additions & 2 deletions net/netfilter/ipvs/ip_vs_xmit.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down

0 comments on commit bdb7cc6

Please sign in to comment.