sunshine_huang<e 阅读(85) 评论(0)

简介

本文只讲述网卡的statistics数据注册和获取流程,典型的如:
/sys/class/net/eth0/statistics/rx_packets
/sys/class/net/eth0/statistics/tx_packets
/sys/class/net/eth0/statistics/rx_bytes
/sys/class/net/eth0/statistics/tx_bytes
/sys/class/net/eth0/statistics/rx_dropped
/sys/class/net/eth0/statistics/tx_dropped

或者通过# ifconfig eth0查看到的数据

设备节点的创建

注册

在网卡加入到kernel的时候都必须通过register_netdevice()进行注册,该函数通过调用netdev_register_kobject()函数来设置相关信息并注册对应的设备节点。

点击(此处)折叠或打开

  1. /* Create sysfs entries for network device. */
  2. int netdev_register_kobject(struct net_device *ndev){
  3.     struct device *dev = &(ndev->dev);
  4.     const struct attribute_group **groups = ndev->sysfs_groups;
  5.     ...
  6.     dev->groups = groups;
  7.     ...
  8.     *groups++ = &netstat_group;
  9.     ...
  10.     device_add(dev);
  11. }
device_add()->device_add_attrs()->device_add_groups(dev->groups)->sysfs_create_groups()

netstat_group定义

点击(此处)折叠或打开

  1. #define NETSTAT_ENTRY(name)                        \
  2. static ssize_t name##_show(struct device *d,                \
  3.              struct device_attribute *attr, char *buf)     \
  4. {                                    \
  5.     return netstat_show(d, attr, buf,                \
  6.              offsetof(struct rtnl_link_stats64, name));    \
  7. }                                    \
  8. static DEVICE_ATTR_RO(name)

  9. NETSTAT_ENTRY(rx_packets);
  10. NETSTAT_ENTRY(tx_packets);
  11. NETSTAT_ENTRY(rx_bytes);
  12. NETSTAT_ENTRY(tx_bytes);
  13. NETSTAT_ENTRY(rx_errors);
  14. NETSTAT_ENTRY(tx_errors);
  15. NETSTAT_ENTRY(rx_dropped);
  16. NETSTAT_ENTRY(tx_dropped);
  17. NETSTAT_ENTRY(multicast);
  18. NETSTAT_ENTRY(collisions);
  19. NETSTAT_ENTRY(rx_length_errors);
  20. NETSTAT_ENTRY(rx_over_errors);
  21. NETSTAT_ENTRY(rx_crc_errors);
  22. NETSTAT_ENTRY(rx_frame_errors);
  23. NETSTAT_ENTRY(rx_fifo_errors);
  24. NETSTAT_ENTRY(rx_missed_errors);
  25. NETSTAT_ENTRY(tx_aborted_errors);
  26. NETSTAT_ENTRY(tx_carrier_errors);
  27. NETSTAT_ENTRY(tx_fifo_errors);
  28. NETSTAT_ENTRY(tx_heartbeat_errors);
  29. NETSTAT_ENTRY(tx_window_errors);
  30. NETSTAT_ENTRY(rx_compressed);
  31. NETSTAT_ENTRY(tx_compressed);
  32. NETSTAT_ENTRY(rx_nohandler);

  33. static struct attribute *netstat_attrs[] = {
  34.     &dev_attr_rx_packets.attr,
  35.     &dev_attr_tx_packets.attr,
  36.     &dev_attr_rx_bytes.attr,
  37.     &dev_attr_tx_bytes.attr,
  38.     &dev_attr_rx_errors.attr,
  39.     &dev_attr_tx_errors.attr,
  40.     &dev_attr_rx_dropped.attr,
  41.     &dev_attr_tx_dropped.attr,
  42.     &dev_attr_multicast.attr,
  43.     &dev_attr_collisions.attr,
  44.     &dev_attr_rx_length_errors.attr,
  45.     &dev_attr_rx_over_errors.attr,
  46.     &dev_attr_rx_crc_errors.attr,
  47.     &dev_attr_rx_frame_errors.attr,
  48.     &dev_attr_rx_fifo_errors.attr,
  49.     &dev_attr_rx_missed_errors.attr,
  50.     &dev_attr_tx_aborted_errors.attr,
  51.     &dev_attr_tx_carrier_errors.attr,
  52.     &dev_attr_tx_fifo_errors.attr,
  53.     &dev_attr_tx_heartbeat_errors.attr,
  54.     &dev_attr_tx_window_errors.attr,
  55.     &dev_attr_rx_compressed.attr,
  56.     &dev_attr_tx_compressed.attr,
  57.     &dev_attr_rx_nohandler.attr,
  58.     NULL
  59. };

  60. static struct attribute_group netstat_group = {
  61.     .name = "statistics",
  62.     .attrs = netstat_attrs,
  63. };

netstat_show函数

点击(此处)折叠或打开

  1. #define __stringify_1(x...)    #x
  2. #define __stringify(x...)    __stringify_1(x)

  3. #define __ATTR_RO(_name) {                        \
  4.     .attr    = { .name = __stringify(_name), .mode = S_IRUGO },    \
  5.     .show    = _name##_show,                        \
  6. }

  7. #define DEVICE_ATTR_RO(_name) \
  8.     struct device_attribute dev_attr_##_name = __ATTR_RO(_name)

  9. struct rtnl_link_stats64 *dev_get_stats(struct net_device *dev,
  10.                     struct rtnl_link_stats64 *storage)
  11. {
  12.     const struct net_device_ops *ops = dev->netdev_ops;

  13.     if (ops->ndo_get_stats64) {
  14.         memset(storage, 0, sizeof(*storage));
  15.         ops->ndo_get_stats64(dev, storage);
  16.     } else if (ops->ndo_get_stats) {
  17.         netdev_stats_to_stats64(storage, ops->ndo_get_stats(dev));
  18.     } else {
  19.         netdev_stats_to_stats64(storage, &dev->stats);
  20.     }
  21.     storage->rx_dropped += atomic_long_read(&dev->rx_dropped);
  22.     storage->tx_dropped += atomic_long_read(&dev->tx_dropped);
  23.     storage->rx_nohandler += atomic_long_read(&dev->rx_nohandler);
  24.     return storage;
  25. }
  26. static ssize_t netstat_show(const struct device *d,
  27.              struct device_attribute *attr, char *buf,
  28.              unsigned long offset)
  29. {
  30.     struct net_device *dev = to_net_dev(d);
  31.     ssize_t ret = -EINVAL;

  32.     WARN_ON(offset > sizeof(struct rtnl_link_stats64) ||
  33.             offset % sizeof(u64) != 0);

  34.     read_lock(&dev_base_lock);
  35.     if (dev_isalive(dev)) {
  36.         struct rtnl_link_stats64 temp;
  37.         const struct rtnl_link_stats64 *stats = dev_get_stats(dev, &temp);

  38.         ret = sprintf(buf, fmt_u64, *(u64 *)(((u8 *) stats) + offset));
  39.     }
  40.     read_unlock(&dev_base_lock);
  41.     return ret;
  42. }

dev_get_stats

通过dev_get_stats()函数可以知道,如果网卡有注册ndo_get_stats64()函数或者ndo_get_stats()函数,则通过网卡驱动获取stats数据,否则直接通过dev->stats获取。

其他

net/core/dev.c
register_netdevice
net/core/net-sysfs.c
netdev_register_kobject()->
dev->groups = groups;
*groups++ = &netstat_group;
device_add()->device_add_attrs()->device_add_groups(dev->groups)->sysfs_create_groups()