18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Data gathering module for Linux-VM Monitor Stream, Stage 1.
48c2ecf20Sopenharmony_ci * Collects accumulated network statistics (Packets received/transmitted,
58c2ecf20Sopenharmony_ci * dropped, errors, ...).
68c2ecf20Sopenharmony_ci *
78c2ecf20Sopenharmony_ci * Copyright IBM Corp. 2003, 2006
88c2ecf20Sopenharmony_ci *
98c2ecf20Sopenharmony_ci * Author: Gerald Schaefer <gerald.schaefer@de.ibm.com>
108c2ecf20Sopenharmony_ci */
118c2ecf20Sopenharmony_ci
128c2ecf20Sopenharmony_ci#include <linux/module.h>
138c2ecf20Sopenharmony_ci#include <linux/init.h>
148c2ecf20Sopenharmony_ci#include <linux/errno.h>
158c2ecf20Sopenharmony_ci#include <linux/kernel_stat.h>
168c2ecf20Sopenharmony_ci#include <linux/netdevice.h>
178c2ecf20Sopenharmony_ci#include <net/net_namespace.h>
188c2ecf20Sopenharmony_ci
198c2ecf20Sopenharmony_ci#include "appldata.h"
208c2ecf20Sopenharmony_ci
218c2ecf20Sopenharmony_ci
228c2ecf20Sopenharmony_ci/*
238c2ecf20Sopenharmony_ci * Network data
248c2ecf20Sopenharmony_ci *
258c2ecf20Sopenharmony_ci * This is accessed as binary data by z/VM. If changes to it can't be avoided,
268c2ecf20Sopenharmony_ci * the structure version (product ID, see appldata_base.c) needs to be changed
278c2ecf20Sopenharmony_ci * as well and all documentation and z/VM applications using it must be updated.
288c2ecf20Sopenharmony_ci */
298c2ecf20Sopenharmony_cistruct appldata_net_sum_data {
308c2ecf20Sopenharmony_ci	u64 timestamp;
318c2ecf20Sopenharmony_ci	u32 sync_count_1;	/* after VM collected the record data, */
328c2ecf20Sopenharmony_ci	u32 sync_count_2;	/* sync_count_1 and sync_count_2 should be the
338c2ecf20Sopenharmony_ci				   same. If not, the record has been updated on
348c2ecf20Sopenharmony_ci				   the Linux side while VM was collecting the
358c2ecf20Sopenharmony_ci				   (possibly corrupt) data */
368c2ecf20Sopenharmony_ci
378c2ecf20Sopenharmony_ci	u32 nr_interfaces;	/* nr. of network interfaces being monitored */
388c2ecf20Sopenharmony_ci
398c2ecf20Sopenharmony_ci	u32 padding;		/* next value is 64-bit aligned, so these */
408c2ecf20Sopenharmony_ci				/* 4 byte would be padded out by compiler */
418c2ecf20Sopenharmony_ci
428c2ecf20Sopenharmony_ci	u64 rx_packets;		/* total packets received        */
438c2ecf20Sopenharmony_ci	u64 tx_packets;		/* total packets transmitted     */
448c2ecf20Sopenharmony_ci	u64 rx_bytes;		/* total bytes received          */
458c2ecf20Sopenharmony_ci	u64 tx_bytes;		/* total bytes transmitted       */
468c2ecf20Sopenharmony_ci	u64 rx_errors;		/* bad packets received          */
478c2ecf20Sopenharmony_ci	u64 tx_errors;		/* packet transmit problems      */
488c2ecf20Sopenharmony_ci	u64 rx_dropped;		/* no space in linux buffers     */
498c2ecf20Sopenharmony_ci	u64 tx_dropped;		/* no space available in linux   */
508c2ecf20Sopenharmony_ci	u64 collisions;		/* collisions while transmitting */
518c2ecf20Sopenharmony_ci} __packed;
528c2ecf20Sopenharmony_ci
538c2ecf20Sopenharmony_ci
548c2ecf20Sopenharmony_ci/*
558c2ecf20Sopenharmony_ci * appldata_get_net_sum_data()
568c2ecf20Sopenharmony_ci *
578c2ecf20Sopenharmony_ci * gather accumulated network statistics
588c2ecf20Sopenharmony_ci */
598c2ecf20Sopenharmony_cistatic void appldata_get_net_sum_data(void *data)
608c2ecf20Sopenharmony_ci{
618c2ecf20Sopenharmony_ci	int i;
628c2ecf20Sopenharmony_ci	struct appldata_net_sum_data *net_data;
638c2ecf20Sopenharmony_ci	struct net_device *dev;
648c2ecf20Sopenharmony_ci	unsigned long rx_packets, tx_packets, rx_bytes, tx_bytes, rx_errors,
658c2ecf20Sopenharmony_ci			tx_errors, rx_dropped, tx_dropped, collisions;
668c2ecf20Sopenharmony_ci
678c2ecf20Sopenharmony_ci	net_data = data;
688c2ecf20Sopenharmony_ci	net_data->sync_count_1++;
698c2ecf20Sopenharmony_ci
708c2ecf20Sopenharmony_ci	i = 0;
718c2ecf20Sopenharmony_ci	rx_packets = 0;
728c2ecf20Sopenharmony_ci	tx_packets = 0;
738c2ecf20Sopenharmony_ci	rx_bytes   = 0;
748c2ecf20Sopenharmony_ci	tx_bytes   = 0;
758c2ecf20Sopenharmony_ci	rx_errors  = 0;
768c2ecf20Sopenharmony_ci	tx_errors  = 0;
778c2ecf20Sopenharmony_ci	rx_dropped = 0;
788c2ecf20Sopenharmony_ci	tx_dropped = 0;
798c2ecf20Sopenharmony_ci	collisions = 0;
808c2ecf20Sopenharmony_ci
818c2ecf20Sopenharmony_ci	rcu_read_lock();
828c2ecf20Sopenharmony_ci	for_each_netdev_rcu(&init_net, dev) {
838c2ecf20Sopenharmony_ci		const struct rtnl_link_stats64 *stats;
848c2ecf20Sopenharmony_ci		struct rtnl_link_stats64 temp;
858c2ecf20Sopenharmony_ci
868c2ecf20Sopenharmony_ci		stats = dev_get_stats(dev, &temp);
878c2ecf20Sopenharmony_ci		rx_packets += stats->rx_packets;
888c2ecf20Sopenharmony_ci		tx_packets += stats->tx_packets;
898c2ecf20Sopenharmony_ci		rx_bytes   += stats->rx_bytes;
908c2ecf20Sopenharmony_ci		tx_bytes   += stats->tx_bytes;
918c2ecf20Sopenharmony_ci		rx_errors  += stats->rx_errors;
928c2ecf20Sopenharmony_ci		tx_errors  += stats->tx_errors;
938c2ecf20Sopenharmony_ci		rx_dropped += stats->rx_dropped;
948c2ecf20Sopenharmony_ci		tx_dropped += stats->tx_dropped;
958c2ecf20Sopenharmony_ci		collisions += stats->collisions;
968c2ecf20Sopenharmony_ci		i++;
978c2ecf20Sopenharmony_ci	}
988c2ecf20Sopenharmony_ci	rcu_read_unlock();
998c2ecf20Sopenharmony_ci
1008c2ecf20Sopenharmony_ci	net_data->nr_interfaces = i;
1018c2ecf20Sopenharmony_ci	net_data->rx_packets = rx_packets;
1028c2ecf20Sopenharmony_ci	net_data->tx_packets = tx_packets;
1038c2ecf20Sopenharmony_ci	net_data->rx_bytes   = rx_bytes;
1048c2ecf20Sopenharmony_ci	net_data->tx_bytes   = tx_bytes;
1058c2ecf20Sopenharmony_ci	net_data->rx_errors  = rx_errors;
1068c2ecf20Sopenharmony_ci	net_data->tx_errors  = tx_errors;
1078c2ecf20Sopenharmony_ci	net_data->rx_dropped = rx_dropped;
1088c2ecf20Sopenharmony_ci	net_data->tx_dropped = tx_dropped;
1098c2ecf20Sopenharmony_ci	net_data->collisions = collisions;
1108c2ecf20Sopenharmony_ci
1118c2ecf20Sopenharmony_ci	net_data->timestamp = get_tod_clock();
1128c2ecf20Sopenharmony_ci	net_data->sync_count_2++;
1138c2ecf20Sopenharmony_ci}
1148c2ecf20Sopenharmony_ci
1158c2ecf20Sopenharmony_ci
1168c2ecf20Sopenharmony_cistatic struct appldata_ops ops = {
1178c2ecf20Sopenharmony_ci	.name	   = "net_sum",
1188c2ecf20Sopenharmony_ci	.record_nr = APPLDATA_RECORD_NET_SUM_ID,
1198c2ecf20Sopenharmony_ci	.size	   = sizeof(struct appldata_net_sum_data),
1208c2ecf20Sopenharmony_ci	.callback  = &appldata_get_net_sum_data,
1218c2ecf20Sopenharmony_ci	.owner     = THIS_MODULE,
1228c2ecf20Sopenharmony_ci	.mod_lvl   = {0xF0, 0xF0},		/* EBCDIC "00" */
1238c2ecf20Sopenharmony_ci};
1248c2ecf20Sopenharmony_ci
1258c2ecf20Sopenharmony_ci
1268c2ecf20Sopenharmony_ci/*
1278c2ecf20Sopenharmony_ci * appldata_net_init()
1288c2ecf20Sopenharmony_ci *
1298c2ecf20Sopenharmony_ci * init data, register ops
1308c2ecf20Sopenharmony_ci */
1318c2ecf20Sopenharmony_cistatic int __init appldata_net_init(void)
1328c2ecf20Sopenharmony_ci{
1338c2ecf20Sopenharmony_ci	int ret;
1348c2ecf20Sopenharmony_ci
1358c2ecf20Sopenharmony_ci	ops.data = kzalloc(sizeof(struct appldata_net_sum_data), GFP_KERNEL);
1368c2ecf20Sopenharmony_ci	if (!ops.data)
1378c2ecf20Sopenharmony_ci		return -ENOMEM;
1388c2ecf20Sopenharmony_ci
1398c2ecf20Sopenharmony_ci	ret = appldata_register_ops(&ops);
1408c2ecf20Sopenharmony_ci	if (ret)
1418c2ecf20Sopenharmony_ci		kfree(ops.data);
1428c2ecf20Sopenharmony_ci
1438c2ecf20Sopenharmony_ci	return ret;
1448c2ecf20Sopenharmony_ci}
1458c2ecf20Sopenharmony_ci
1468c2ecf20Sopenharmony_ci/*
1478c2ecf20Sopenharmony_ci * appldata_net_exit()
1488c2ecf20Sopenharmony_ci *
1498c2ecf20Sopenharmony_ci * unregister ops
1508c2ecf20Sopenharmony_ci */
1518c2ecf20Sopenharmony_cistatic void __exit appldata_net_exit(void)
1528c2ecf20Sopenharmony_ci{
1538c2ecf20Sopenharmony_ci	appldata_unregister_ops(&ops);
1548c2ecf20Sopenharmony_ci	kfree(ops.data);
1558c2ecf20Sopenharmony_ci}
1568c2ecf20Sopenharmony_ci
1578c2ecf20Sopenharmony_ci
1588c2ecf20Sopenharmony_cimodule_init(appldata_net_init);
1598c2ecf20Sopenharmony_cimodule_exit(appldata_net_exit);
1608c2ecf20Sopenharmony_ci
1618c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL");
1628c2ecf20Sopenharmony_ciMODULE_AUTHOR("Gerald Schaefer");
1638c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Linux-VM Monitor Stream, accumulated network statistics");
164