162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Data gathering module for Linux-VM Monitor Stream, Stage 1. 462306a36Sopenharmony_ci * Collects accumulated network statistics (Packets received/transmitted, 562306a36Sopenharmony_ci * dropped, errors, ...). 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * Copyright IBM Corp. 2003, 2006 862306a36Sopenharmony_ci * 962306a36Sopenharmony_ci * Author: Gerald Schaefer <gerald.schaefer@de.ibm.com> 1062306a36Sopenharmony_ci */ 1162306a36Sopenharmony_ci 1262306a36Sopenharmony_ci#include <linux/module.h> 1362306a36Sopenharmony_ci#include <linux/init.h> 1462306a36Sopenharmony_ci#include <linux/errno.h> 1562306a36Sopenharmony_ci#include <linux/kernel_stat.h> 1662306a36Sopenharmony_ci#include <linux/netdevice.h> 1762306a36Sopenharmony_ci#include <net/net_namespace.h> 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_ci#include "appldata.h" 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_ci/* 2362306a36Sopenharmony_ci * Network data 2462306a36Sopenharmony_ci * 2562306a36Sopenharmony_ci * This is accessed as binary data by z/VM. If changes to it can't be avoided, 2662306a36Sopenharmony_ci * the structure version (product ID, see appldata_base.c) needs to be changed 2762306a36Sopenharmony_ci * as well and all documentation and z/VM applications using it must be updated. 2862306a36Sopenharmony_ci */ 2962306a36Sopenharmony_cistruct appldata_net_sum_data { 3062306a36Sopenharmony_ci u64 timestamp; 3162306a36Sopenharmony_ci u32 sync_count_1; /* after VM collected the record data, */ 3262306a36Sopenharmony_ci u32 sync_count_2; /* sync_count_1 and sync_count_2 should be the 3362306a36Sopenharmony_ci same. If not, the record has been updated on 3462306a36Sopenharmony_ci the Linux side while VM was collecting the 3562306a36Sopenharmony_ci (possibly corrupt) data */ 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_ci u32 nr_interfaces; /* nr. of network interfaces being monitored */ 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_ci u32 padding; /* next value is 64-bit aligned, so these */ 4062306a36Sopenharmony_ci /* 4 byte would be padded out by compiler */ 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_ci u64 rx_packets; /* total packets received */ 4362306a36Sopenharmony_ci u64 tx_packets; /* total packets transmitted */ 4462306a36Sopenharmony_ci u64 rx_bytes; /* total bytes received */ 4562306a36Sopenharmony_ci u64 tx_bytes; /* total bytes transmitted */ 4662306a36Sopenharmony_ci u64 rx_errors; /* bad packets received */ 4762306a36Sopenharmony_ci u64 tx_errors; /* packet transmit problems */ 4862306a36Sopenharmony_ci u64 rx_dropped; /* no space in linux buffers */ 4962306a36Sopenharmony_ci u64 tx_dropped; /* no space available in linux */ 5062306a36Sopenharmony_ci u64 collisions; /* collisions while transmitting */ 5162306a36Sopenharmony_ci} __packed; 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_ci/* 5562306a36Sopenharmony_ci * appldata_get_net_sum_data() 5662306a36Sopenharmony_ci * 5762306a36Sopenharmony_ci * gather accumulated network statistics 5862306a36Sopenharmony_ci */ 5962306a36Sopenharmony_cistatic void appldata_get_net_sum_data(void *data) 6062306a36Sopenharmony_ci{ 6162306a36Sopenharmony_ci int i; 6262306a36Sopenharmony_ci struct appldata_net_sum_data *net_data; 6362306a36Sopenharmony_ci struct net_device *dev; 6462306a36Sopenharmony_ci unsigned long rx_packets, tx_packets, rx_bytes, tx_bytes, rx_errors, 6562306a36Sopenharmony_ci tx_errors, rx_dropped, tx_dropped, collisions; 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_ci net_data = data; 6862306a36Sopenharmony_ci net_data->sync_count_1++; 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_ci i = 0; 7162306a36Sopenharmony_ci rx_packets = 0; 7262306a36Sopenharmony_ci tx_packets = 0; 7362306a36Sopenharmony_ci rx_bytes = 0; 7462306a36Sopenharmony_ci tx_bytes = 0; 7562306a36Sopenharmony_ci rx_errors = 0; 7662306a36Sopenharmony_ci tx_errors = 0; 7762306a36Sopenharmony_ci rx_dropped = 0; 7862306a36Sopenharmony_ci tx_dropped = 0; 7962306a36Sopenharmony_ci collisions = 0; 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_ci rcu_read_lock(); 8262306a36Sopenharmony_ci for_each_netdev_rcu(&init_net, dev) { 8362306a36Sopenharmony_ci const struct rtnl_link_stats64 *stats; 8462306a36Sopenharmony_ci struct rtnl_link_stats64 temp; 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_ci stats = dev_get_stats(dev, &temp); 8762306a36Sopenharmony_ci rx_packets += stats->rx_packets; 8862306a36Sopenharmony_ci tx_packets += stats->tx_packets; 8962306a36Sopenharmony_ci rx_bytes += stats->rx_bytes; 9062306a36Sopenharmony_ci tx_bytes += stats->tx_bytes; 9162306a36Sopenharmony_ci rx_errors += stats->rx_errors; 9262306a36Sopenharmony_ci tx_errors += stats->tx_errors; 9362306a36Sopenharmony_ci rx_dropped += stats->rx_dropped; 9462306a36Sopenharmony_ci tx_dropped += stats->tx_dropped; 9562306a36Sopenharmony_ci collisions += stats->collisions; 9662306a36Sopenharmony_ci i++; 9762306a36Sopenharmony_ci } 9862306a36Sopenharmony_ci rcu_read_unlock(); 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_ci net_data->nr_interfaces = i; 10162306a36Sopenharmony_ci net_data->rx_packets = rx_packets; 10262306a36Sopenharmony_ci net_data->tx_packets = tx_packets; 10362306a36Sopenharmony_ci net_data->rx_bytes = rx_bytes; 10462306a36Sopenharmony_ci net_data->tx_bytes = tx_bytes; 10562306a36Sopenharmony_ci net_data->rx_errors = rx_errors; 10662306a36Sopenharmony_ci net_data->tx_errors = tx_errors; 10762306a36Sopenharmony_ci net_data->rx_dropped = rx_dropped; 10862306a36Sopenharmony_ci net_data->tx_dropped = tx_dropped; 10962306a36Sopenharmony_ci net_data->collisions = collisions; 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_ci net_data->timestamp = get_tod_clock(); 11262306a36Sopenharmony_ci net_data->sync_count_2++; 11362306a36Sopenharmony_ci} 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_cistatic struct appldata_ops ops = { 11762306a36Sopenharmony_ci .name = "net_sum", 11862306a36Sopenharmony_ci .record_nr = APPLDATA_RECORD_NET_SUM_ID, 11962306a36Sopenharmony_ci .size = sizeof(struct appldata_net_sum_data), 12062306a36Sopenharmony_ci .callback = &appldata_get_net_sum_data, 12162306a36Sopenharmony_ci .owner = THIS_MODULE, 12262306a36Sopenharmony_ci .mod_lvl = {0xF0, 0xF0}, /* EBCDIC "00" */ 12362306a36Sopenharmony_ci}; 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_ci/* 12762306a36Sopenharmony_ci * appldata_net_init() 12862306a36Sopenharmony_ci * 12962306a36Sopenharmony_ci * init data, register ops 13062306a36Sopenharmony_ci */ 13162306a36Sopenharmony_cistatic int __init appldata_net_init(void) 13262306a36Sopenharmony_ci{ 13362306a36Sopenharmony_ci int ret; 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_ci ops.data = kzalloc(sizeof(struct appldata_net_sum_data), GFP_KERNEL); 13662306a36Sopenharmony_ci if (!ops.data) 13762306a36Sopenharmony_ci return -ENOMEM; 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_ci ret = appldata_register_ops(&ops); 14062306a36Sopenharmony_ci if (ret) 14162306a36Sopenharmony_ci kfree(ops.data); 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_ci return ret; 14462306a36Sopenharmony_ci} 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_ci/* 14762306a36Sopenharmony_ci * appldata_net_exit() 14862306a36Sopenharmony_ci * 14962306a36Sopenharmony_ci * unregister ops 15062306a36Sopenharmony_ci */ 15162306a36Sopenharmony_cistatic void __exit appldata_net_exit(void) 15262306a36Sopenharmony_ci{ 15362306a36Sopenharmony_ci appldata_unregister_ops(&ops); 15462306a36Sopenharmony_ci kfree(ops.data); 15562306a36Sopenharmony_ci} 15662306a36Sopenharmony_ci 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_cimodule_init(appldata_net_init); 15962306a36Sopenharmony_cimodule_exit(appldata_net_exit); 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 16262306a36Sopenharmony_ciMODULE_AUTHOR("Gerald Schaefer"); 16362306a36Sopenharmony_ciMODULE_DESCRIPTION("Linux-VM Monitor Stream, accumulated network statistics"); 164