Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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.

Signed-off-by: Stephen Suryaputra <ssuryaextr@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

Stephen Suryaputra and committed by
David S. Miller
bdb7cc64 032234d8

+51 -52
+14
include/net/addrconf.h
··· 308 308 } 309 309 310 310 /** 311 + * __in6_dev_get_safely - get inet6_dev pointer from netdevice 312 + * @dev: network device 313 + * 314 + * This is a safer version of __in6_dev_get 315 + */ 316 + static inline struct inet6_dev *__in6_dev_get_safely(const struct net_device *dev) 317 + { 318 + if (likely(dev)) 319 + return rcu_dereference_rtnl(dev->ip6_ptr); 320 + else 321 + return NULL; 322 + } 323 + 324 + /** 311 325 * in6_dev_get - get inet6_dev pointer from netdevice 312 326 * @dev: network device 313 327 *
+21 -34
net/ipv6/exthdrs.c
··· 280 280 281 281 static int ipv6_destopt_rcv(struct sk_buff *skb) 282 282 { 283 + struct inet6_dev *idev = __in6_dev_get(skb->dev); 283 284 struct inet6_skb_parm *opt = IP6CB(skb); 284 285 #if IS_ENABLED(CONFIG_IPV6_MIP6) 285 286 __u16 dstbuf; ··· 292 291 if (!pskb_may_pull(skb, skb_transport_offset(skb) + 8) || 293 292 !pskb_may_pull(skb, (skb_transport_offset(skb) + 294 293 ((skb_transport_header(skb)[1] + 1) << 3)))) { 295 - __IP6_INC_STATS(dev_net(dst->dev), ip6_dst_idev(dst), 294 + __IP6_INC_STATS(dev_net(dst->dev), idev, 296 295 IPSTATS_MIB_INHDRERRORS); 297 296 fail_and_free: 298 297 kfree_skb(skb); ··· 320 319 return 1; 321 320 } 322 321 323 - __IP6_INC_STATS(dev_net(dst->dev), 324 - ip6_dst_idev(dst), IPSTATS_MIB_INHDRERRORS); 322 + __IP6_INC_STATS(net, idev, IPSTATS_MIB_INHDRERRORS); 325 323 return -1; 326 324 } 327 325 ··· 416 416 } 417 417 418 418 if (hdr->segments_left >= (hdr->hdrlen >> 1)) { 419 - __IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)), 420 - IPSTATS_MIB_INHDRERRORS); 419 + __IP6_INC_STATS(net, idev, IPSTATS_MIB_INHDRERRORS); 421 420 icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, 422 421 ((&hdr->segments_left) - 423 422 skb_network_header(skb))); ··· 455 456 456 457 if (skb_dst(skb)->dev->flags & IFF_LOOPBACK) { 457 458 if (ipv6_hdr(skb)->hop_limit <= 1) { 458 - __IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)), 459 - IPSTATS_MIB_INHDRERRORS); 459 + __IP6_INC_STATS(net, idev, IPSTATS_MIB_INHDRERRORS); 460 460 icmpv6_send(skb, ICMPV6_TIME_EXCEED, 461 461 ICMPV6_EXC_HOPLIMIT, 0); 462 462 kfree_skb(skb); ··· 479 481 /* called with rcu_read_lock() */ 480 482 static int ipv6_rthdr_rcv(struct sk_buff *skb) 481 483 { 484 + struct inet6_dev *idev = __in6_dev_get(skb->dev); 482 485 struct inet6_skb_parm *opt = IP6CB(skb); 483 486 struct in6_addr *addr = NULL; 484 487 struct in6_addr daddr; 485 - struct inet6_dev *idev; 486 488 int n, i; 487 489 struct ipv6_rt_hdr *hdr; 488 490 struct rt0_hdr *rthdr; ··· 496 498 if (!pskb_may_pull(skb, skb_transport_offset(skb) + 8) || 497 499 !pskb_may_pull(skb, (skb_transport_offset(skb) + 498 500 ((skb_transport_header(skb)[1] + 1) << 3)))) { 499 - __IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)), 500 - IPSTATS_MIB_INHDRERRORS); 501 + __IP6_INC_STATS(net, idev, IPSTATS_MIB_INHDRERRORS); 501 502 kfree_skb(skb); 502 503 return -1; 503 504 } ··· 505 508 506 509 if (ipv6_addr_is_multicast(&ipv6_hdr(skb)->daddr) || 507 510 skb->pkt_type != PACKET_HOST) { 508 - __IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)), 509 - IPSTATS_MIB_INADDRERRORS); 511 + __IP6_INC_STATS(net, idev, IPSTATS_MIB_INADDRERRORS); 510 512 kfree_skb(skb); 511 513 return -1; 512 514 } ··· 523 527 * processed by own 524 528 */ 525 529 if (!addr) { 526 - __IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)), 530 + __IP6_INC_STATS(net, idev, 527 531 IPSTATS_MIB_INADDRERRORS); 528 532 kfree_skb(skb); 529 533 return -1; ··· 549 553 goto unknown_rh; 550 554 /* Silently discard invalid RTH type 2 */ 551 555 if (hdr->hdrlen != 2 || hdr->segments_left != 1) { 552 - __IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)), 553 - IPSTATS_MIB_INHDRERRORS); 556 + __IP6_INC_STATS(net, idev, IPSTATS_MIB_INHDRERRORS); 554 557 kfree_skb(skb); 555 558 return -1; 556 559 } ··· 567 572 n = hdr->hdrlen >> 1; 568 573 569 574 if (hdr->segments_left > n) { 570 - __IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)), 571 - IPSTATS_MIB_INHDRERRORS); 575 + __IP6_INC_STATS(net, idev, IPSTATS_MIB_INHDRERRORS); 572 576 icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, 573 577 ((&hdr->segments_left) - 574 578 skb_network_header(skb))); ··· 603 609 if (xfrm6_input_addr(skb, (xfrm_address_t *)addr, 604 610 (xfrm_address_t *)&ipv6_hdr(skb)->saddr, 605 611 IPPROTO_ROUTING) < 0) { 606 - __IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)), 607 - IPSTATS_MIB_INADDRERRORS); 612 + __IP6_INC_STATS(net, idev, IPSTATS_MIB_INADDRERRORS); 608 613 kfree_skb(skb); 609 614 return -1; 610 615 } 611 616 if (!ipv6_chk_home_addr(dev_net(skb_dst(skb)->dev), addr)) { 612 - __IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)), 613 - IPSTATS_MIB_INADDRERRORS); 617 + __IP6_INC_STATS(net, idev, IPSTATS_MIB_INADDRERRORS); 614 618 kfree_skb(skb); 615 619 return -1; 616 620 } ··· 619 627 } 620 628 621 629 if (ipv6_addr_is_multicast(addr)) { 622 - __IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)), 623 - IPSTATS_MIB_INADDRERRORS); 630 + __IP6_INC_STATS(net, idev, IPSTATS_MIB_INADDRERRORS); 624 631 kfree_skb(skb); 625 632 return -1; 626 633 } ··· 638 647 639 648 if (skb_dst(skb)->dev->flags&IFF_LOOPBACK) { 640 649 if (ipv6_hdr(skb)->hop_limit <= 1) { 641 - __IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)), 642 - IPSTATS_MIB_INHDRERRORS); 650 + __IP6_INC_STATS(net, idev, IPSTATS_MIB_INHDRERRORS); 643 651 icmpv6_send(skb, ICMPV6_TIME_EXCEED, ICMPV6_EXC_HOPLIMIT, 644 652 0); 645 653 kfree_skb(skb); ··· 653 663 return -1; 654 664 655 665 unknown_rh: 656 - __IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)), IPSTATS_MIB_INHDRERRORS); 666 + __IP6_INC_STATS(net, idev, IPSTATS_MIB_INHDRERRORS); 657 667 icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, 658 668 (&hdr->type) - skb_network_header(skb)); 659 669 return -1; ··· 745 755 static bool ipv6_hop_jumbo(struct sk_buff *skb, int optoff) 746 756 { 747 757 const unsigned char *nh = skb_network_header(skb); 758 + struct inet6_dev *idev = __in6_dev_get_safely(skb->dev); 748 759 struct net *net = ipv6_skb_net(skb); 749 760 u32 pkt_len; 750 761 751 762 if (nh[optoff + 1] != 4 || (optoff & 3) != 2) { 752 763 net_dbg_ratelimited("ipv6_hop_jumbo: wrong jumbo opt length/alignment %d\n", 753 764 nh[optoff+1]); 754 - __IP6_INC_STATS(net, ipv6_skb_idev(skb), 755 - IPSTATS_MIB_INHDRERRORS); 765 + __IP6_INC_STATS(net, idev, IPSTATS_MIB_INHDRERRORS); 756 766 goto drop; 757 767 } 758 768 759 769 pkt_len = ntohl(*(__be32 *)(nh + optoff + 2)); 760 770 if (pkt_len <= IPV6_MAXPLEN) { 761 - __IP6_INC_STATS(net, ipv6_skb_idev(skb), 762 - IPSTATS_MIB_INHDRERRORS); 771 + __IP6_INC_STATS(net, idev, IPSTATS_MIB_INHDRERRORS); 763 772 icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, optoff+2); 764 773 return false; 765 774 } 766 775 if (ipv6_hdr(skb)->payload_len) { 767 - __IP6_INC_STATS(net, ipv6_skb_idev(skb), 768 - IPSTATS_MIB_INHDRERRORS); 776 + __IP6_INC_STATS(net, idev, IPSTATS_MIB_INHDRERRORS); 769 777 icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, optoff); 770 778 return false; 771 779 } 772 780 773 781 if (pkt_len > skb->len - sizeof(struct ipv6hdr)) { 774 - __IP6_INC_STATS(net, ipv6_skb_idev(skb), 775 - IPSTATS_MIB_INTRUNCATEDPKTS); 782 + __IP6_INC_STATS(net, idev, IPSTATS_MIB_INTRUNCATEDPKTS); 776 783 goto drop; 777 784 } 778 785
+1 -1
net/ipv6/ip6_input.c
··· 336 336 bool deliver; 337 337 338 338 __IP6_UPD_PO_STATS(dev_net(skb_dst(skb)->dev), 339 - ip6_dst_idev(skb_dst(skb)), IPSTATS_MIB_INMCAST, 339 + __in6_dev_get_safely(skb->dev), IPSTATS_MIB_INMCAST, 340 340 skb->len); 341 341 342 342 hdr = ipv6_hdr(skb);
+7 -11
net/ipv6/ip6_output.c
··· 425 425 426 426 int ip6_forward(struct sk_buff *skb) 427 427 { 428 + struct inet6_dev *idev = __in6_dev_get_safely(skb->dev); 428 429 struct dst_entry *dst = skb_dst(skb); 429 430 struct ipv6hdr *hdr = ipv6_hdr(skb); 430 431 struct inet6_skb_parm *opt = IP6CB(skb); ··· 445 444 goto drop; 446 445 447 446 if (!xfrm6_policy_check(NULL, XFRM_POLICY_FWD, skb)) { 448 - __IP6_INC_STATS(net, ip6_dst_idev(dst), 449 - IPSTATS_MIB_INDISCARDS); 447 + __IP6_INC_STATS(net, idev, IPSTATS_MIB_INDISCARDS); 450 448 goto drop; 451 449 } 452 450 ··· 476 476 /* Force OUTPUT device used as source address */ 477 477 skb->dev = dst->dev; 478 478 icmpv6_send(skb, ICMPV6_TIME_EXCEED, ICMPV6_EXC_HOPLIMIT, 0); 479 - __IP6_INC_STATS(net, ip6_dst_idev(dst), 480 - IPSTATS_MIB_INHDRERRORS); 479 + __IP6_INC_STATS(net, idev, IPSTATS_MIB_INHDRERRORS); 481 480 482 481 kfree_skb(skb); 483 482 return -ETIMEDOUT; ··· 489 490 if (proxied > 0) 490 491 return ip6_input(skb); 491 492 else if (proxied < 0) { 492 - __IP6_INC_STATS(net, ip6_dst_idev(dst), 493 - IPSTATS_MIB_INDISCARDS); 493 + __IP6_INC_STATS(net, idev, IPSTATS_MIB_INDISCARDS); 494 494 goto drop; 495 495 } 496 496 } 497 497 498 498 if (!xfrm6_route_forward(skb)) { 499 - __IP6_INC_STATS(net, ip6_dst_idev(dst), 500 - IPSTATS_MIB_INDISCARDS); 499 + __IP6_INC_STATS(net, idev, IPSTATS_MIB_INDISCARDS); 501 500 goto drop; 502 501 } 503 502 dst = skb_dst(skb); ··· 551 554 /* Again, force OUTPUT device used as source address */ 552 555 skb->dev = dst->dev; 553 556 icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu); 554 - __IP6_INC_STATS(net, ip6_dst_idev(dst), 555 - IPSTATS_MIB_INTOOBIGERRORS); 557 + __IP6_INC_STATS(net, idev, IPSTATS_MIB_INTOOBIGERRORS); 556 558 __IP6_INC_STATS(net, ip6_dst_idev(dst), 557 559 IPSTATS_MIB_FRAGFAILS); 558 560 kfree_skb(skb); ··· 575 579 ip6_forward_finish); 576 580 577 581 error: 578 - __IP6_INC_STATS(net, ip6_dst_idev(dst), IPSTATS_MIB_INADDRERRORS); 582 + __IP6_INC_STATS(net, idev, IPSTATS_MIB_INADDRERRORS); 579 583 drop: 580 584 kfree_skb(skb); 581 585 return -EINVAL;
+3 -3
net/ipv6/reassembly.c
··· 179 179 ((u8 *)(fhdr + 1) - (u8 *)(ipv6_hdr(skb) + 1))); 180 180 181 181 if ((unsigned int)end > IPV6_MAXPLEN) { 182 - __IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)), 182 + __IP6_INC_STATS(net, __in6_dev_get_safely(skb->dev), 183 183 IPSTATS_MIB_INHDRERRORS); 184 184 icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, 185 185 ((u8 *)&fhdr->frag_off - ··· 214 214 /* RFC2460 says always send parameter problem in 215 215 * this case. -DaveM 216 216 */ 217 - __IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)), 217 + __IP6_INC_STATS(net, __in6_dev_get_safely(skb->dev), 218 218 IPSTATS_MIB_INHDRERRORS); 219 219 icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, 220 220 offsetof(struct ipv6hdr, payload_len)); ··· 536 536 return -1; 537 537 538 538 fail_hdr: 539 - __IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)), 539 + __IP6_INC_STATS(net, __in6_dev_get_safely(skb->dev), 540 540 IPSTATS_MIB_INHDRERRORS); 541 541 icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, skb_network_header_len(skb)); 542 542 return -1;
+2 -1
net/ipv6/route.c
··· 3541 3541 case IPSTATS_MIB_INNOROUTES: 3542 3542 type = ipv6_addr_type(&ipv6_hdr(skb)->daddr); 3543 3543 if (type == IPV6_ADDR_ANY) { 3544 - IP6_INC_STATS(dev_net(dst->dev), ip6_dst_idev(dst), 3544 + IP6_INC_STATS(dev_net(dst->dev), 3545 + __in6_dev_get_safely(skb->dev), 3545 3546 IPSTATS_MIB_INADDRERRORS); 3546 3547 break; 3547 3548 }
+3 -2
net/netfilter/ipvs/ip_vs_xmit.c
··· 266 266 267 267 /* check and decrement ttl */ 268 268 if (ipv6_hdr(skb)->hop_limit <= 1) { 269 + struct inet6_dev *idev = __in6_dev_get_safely(skb->dev); 270 + 269 271 /* Force OUTPUT device used as source address */ 270 272 skb->dev = dst->dev; 271 273 icmpv6_send(skb, ICMPV6_TIME_EXCEED, 272 274 ICMPV6_EXC_HOPLIMIT, 0); 273 - __IP6_INC_STATS(net, ip6_dst_idev(dst), 274 - IPSTATS_MIB_INHDRERRORS); 275 + __IP6_INC_STATS(net, idev, IPSTATS_MIB_INHDRERRORS); 275 276 276 277 return false; 277 278 }