File: statistics.c

package info (click to toggle)
batctl 2025.5-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 840 kB
  • sloc: ansic: 12,083; makefile: 155; sh: 21
file content (120 lines) | stat: -rw-r--r-- 2,692 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
// SPDX-License-Identifier: GPL-2.0
/* Copyright (C) B.A.T.M.A.N. contributors:
 *
 * Marek Lindner <marek.lindner@mailbox.org>
 *
 * License-Filename: LICENSES/preferred/GPL-2.0
 */

#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <net/if.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <linux/sockios.h>
#include <linux/ethtool.h>
#include <stdint.h>

#include "main.h"

void check_root_or_die(const char *cmd);

/* code borrowed from ethtool */
static int statistics_custom_get(int fd, struct ifreq *ifr)
{
	struct ethtool_gstrings *strings = NULL;
	struct ethtool_stats *stats = NULL;
	struct ethtool_drvinfo drvinfo;
	int ret = EXIT_FAILURE;
	unsigned int sz_stats;
	unsigned int n_stats;
	unsigned int sz_str;
	unsigned int i;
	int err;

	drvinfo.cmd = ETHTOOL_GDRVINFO;
	ifr->ifr_data = (void *)&drvinfo;
	err = ioctl(fd, SIOCETHTOOL, ifr);
	if (err < 0) {
		perror("Error - can't open driver information");
		goto out;
	}

	n_stats = drvinfo.n_stats;
	if (n_stats < 1)
		goto success;

	sz_str = n_stats * ETH_GSTRING_LEN;
	sz_stats = n_stats * sizeof(uint64_t);

	strings = calloc(1, sz_str + sizeof(struct ethtool_gstrings));
	stats = calloc(1, sz_stats + sizeof(struct ethtool_stats));
	if (!strings || !stats) {
		fprintf(stderr, "Error - out of memory\n");
		goto out;
	}

	strings->cmd = ETHTOOL_GSTRINGS;
	strings->string_set = ETH_SS_STATS;
	strings->len = n_stats;
	ifr->ifr_data = (void *)strings;
	err = ioctl(fd, SIOCETHTOOL, ifr);
	if (err < 0) {
		perror("Error - can't get stats strings information");
		goto out;
	}

	stats->cmd = ETHTOOL_GSTATS;
	stats->n_stats = n_stats;
	ifr->ifr_data = (void *)stats;
	err = ioctl(fd, SIOCETHTOOL, ifr);
	if (err < 0) {
		perror("Error - can't get stats information");
		goto out;
	}

	for (i = 0; i < n_stats; i++) {
		printf("\t%.*s: %llu\n", ETH_GSTRING_LEN,
		       &strings->data[i * ETH_GSTRING_LEN], stats->data[i]);
	}

success:
	ret = EXIT_SUCCESS;

out:
	free(strings);
	free(stats);
	return ret;
}

static int statistics(struct state *state, int argc __maybe_unused,
		      char **argv __maybe_unused)
{
	int ret = EXIT_FAILURE;
	struct ifreq ifr;
	int fd = -1;

	memset(&ifr, 0, sizeof(ifr));
	strncpy(ifr.ifr_name, state->mesh_iface, sizeof(ifr.ifr_name));
	ifr.ifr_name[sizeof(ifr.ifr_name) - 1] = '\0';

	fd = socket(AF_INET, SOCK_DGRAM, 0);
	if (fd < 0) {
		perror("Error - can't open socket");
		goto out;
	}

	ret = statistics_custom_get(fd, &ifr);

out:
	if (fd >= 0)
		close(fd);
	return ret;
}

COMMAND(SUBCOMMAND_MIF, statistics, "s", COMMAND_FLAG_MESH_IFACE, NULL,
	"                  \tprint mesh statistics");