// SPDX-License-Identifier: GPL-2.0
#include <inttypes.h>
#include <pthread.h>
#include <stdio.h>
#include "../../../../../include/linux/compiler.h"
#include "../../../../../include/linux/kernel.h"
#include "aolib.h"
struct netstat_counter {
uint64_t val;
char *name;
};
struct netstat {
char *header_name;
struct netstat *next;
size_t counters_nr;
struct netstat_counter *counters;
};
static struct netstat *lookup_type(struct netstat *ns,
const char *type, size_t len)
{
while (ns != NULL) {
size_t cmp = max(len, strlen(ns->header_name));
if (!strncmp(ns->header_name, type, cmp))
return ns;
ns = ns->next;
}
return NULL;
}
static struct netstat *lookup_get(struct netstat *ns,
const char *type, const size_t len)
{
struct netstat *ret;
ret = lookup_type(ns, type, len);
if (ret != NULL)
return ret;
ret = malloc(sizeof (struct netstat));
if (!ret)
test_error("malloc()" );
ret->header_name = strndup(type, len);
if (ret->header_name == NULL)
test_error("strndup()" );
ret->next = ns;
ret->counters_nr = 0 ;
ret->counters = NULL;
return ret;
}
static struct netstat *lookup_get_column(struct netstat *ns, const char *line)
{
char *column;
column = strchr(line, ':' );
if (!column)
test_error("can't parse netstat file" );
return lookup_get(ns, line, column - line);
}
static void netstat_read_type(FILE *fnetstat, struct netstat **dest, char *line)
{
struct netstat *type = lookup_get_column(*dest, line);
const char *pos = line;
size_t i, nr_elems = 0 ;
char tmp;
while ((pos = strchr(pos, ' ' ))) {
nr_elems++;
pos++;
}
*dest = type;
type->counters = reallocarray(type->counters,
type->counters_nr + nr_elems,
sizeof (struct netstat_counter));
if (!type->counters)
test_error("reallocarray()" );
pos = strchr(line, ' ' ) + 1 ;
if (fscanf(fnetstat, "%[^ :]" , type->header_name) == EOF)
test_error("fscanf(%s)" , type->header_name);
if (fread(&tmp, 1 , 1 , fnetstat) != 1 || tmp != ':' )
test_error("Unexpected netstat format (%c)" , tmp);
for (i = type->counters_nr; i < type->counters_nr + nr_elems; i++) {
struct netstat_counter *nc = &type->counters[i];
const char *new_pos = strchr(pos, ' ' );
const char *fmt = " %" PRIu64;
if (new_pos == NULL)
new_pos = strchr(pos, '\n' );
nc->name = strndup(pos, new_pos - pos);
if (nc->name == NULL)
test_error("strndup()" );
if (unlikely(!strcmp(nc->name, "MaxConn" )))
fmt = " %" PRId64; /* MaxConn is signed, RFC 2012 */
if (fscanf(fnetstat, fmt, &nc->val) != 1 )
test_error("fscanf(%s)" , nc->name);
pos = new_pos + 1 ;
}
type->counters_nr += nr_elems;
if (fread(&tmp, 1 , 1 , fnetstat) != 1 || tmp != '\n' )
test_error("Unexpected netstat format" );
}
static const char *snmp6_name = "Snmp6" ;
static void snmp6_read(FILE *fnetstat, struct netstat **dest)
{
struct netstat *type = lookup_get(*dest, snmp6_name, strlen(snmp6_name));
char *counter_name;
size_t i;
for (i = type->counters_nr;; i++) {
struct netstat_counter *nc;
uint64_t counter;
if (fscanf(fnetstat, "%ms" , &counter_name) == EOF)
break ;
if (fscanf(fnetstat, "%" PRIu64, &counter) == EOF)
test_error("Unexpected snmp6 format" );
type->counters = reallocarray(type->counters, i + 1 ,
sizeof (struct netstat_counter));
if (!type->counters)
test_error("reallocarray()" );
nc = &type->counters[i];
nc->name = counter_name;
nc->val = counter;
}
type->counters_nr = i;
*dest = type;
}
struct netstat *netstat_read(void )
{
struct netstat *ret = 0 ;
size_t line_sz = 0 ;
char *line = NULL;
FILE *fnetstat;
/*
* Opening thread - self instead of / proc / net / . . . as the latter
* points to / proc / self / net / which instantiates thread - leader ' s
* net - ns , see :
* commit 155134 fef2b6 ( " Revert " proc : Point / proc / { mounts , net } at . . " )
*/
errno = 0 ;
fnetstat = fopen("/proc/thread-self/net/netstat" , "r" );
if (fnetstat == NULL)
test_error("failed to open /proc/net/netstat" );
while (getline(&line, &line_sz, fnetstat) != -1 )
netstat_read_type(fnetstat, &ret, line);
fclose(fnetstat);
errno = 0 ;
fnetstat = fopen("/proc/thread-self/net/snmp" , "r" );
if (fnetstat == NULL)
test_error("failed to open /proc/net/snmp" );
while (getline(&line, &line_sz, fnetstat) != -1 )
netstat_read_type(fnetstat, &ret, line);
fclose(fnetstat);
errno = 0 ;
fnetstat = fopen("/proc/thread-self/net/snmp6" , "r" );
if (fnetstat == NULL)
test_error("failed to open /proc/net/snmp6" );
snmp6_read(fnetstat, &ret);
fclose(fnetstat);
free(line);
return ret;
}
void netstat_free(struct netstat *ns)
{
while (ns != NULL) {
struct netstat *prev = ns;
size_t i;
free(ns->header_name);
for (i = 0 ; i < ns->counters_nr; i++)
free(ns->counters[i].name);
free(ns->counters);
ns = ns->next;
free(prev);
}
}
static inline void
__netstat_print_diff(uint64_t a, struct netstat *nsb, size_t i)
{
if (unlikely(!strcmp(nsb->header_name, "MaxConn" ))) {
test_print("%8s %25s: %" PRId64 " => %" PRId64,
nsb->header_name, nsb->counters[i].name,
a, nsb->counters[i].val);
return ;
}
test_print("%8s %25s: %" PRIu64 " => %" PRIu64, nsb->header_name,
nsb->counters[i].name, a, nsb->counters[i].val);
}
void netstat_print_diff(struct netstat *nsa, struct netstat *nsb)
{
size_t i, j;
while (nsb != NULL) {
if (unlikely(strcmp(nsb->header_name, nsa->header_name))) {
for (i = 0 ; i < nsb->counters_nr; i++)
__netstat_print_diff(0 , nsb, i);
nsb = nsb->next;
continue ;
}
if (nsb->counters_nr < nsa->counters_nr)
test_error("Unexpected: some counters disappeared!" );
for (j = 0 , i = 0 ; i < nsb->counters_nr; i++) {
if (strcmp(nsb->counters[i].name, nsa->counters[j].name)) {
__netstat_print_diff(0 , nsb, i);
continue ;
}
if (nsa->counters[j].val == nsb->counters[i].val) {
j++;
continue ;
}
__netstat_print_diff(nsa->counters[j].val, nsb, i);
j++;
}
if (j != nsa->counters_nr)
test_error("Unexpected: some counters disappeared!" );
nsb = nsb->next;
nsa = nsa->next;
}
}
uint64_t netstat_get(struct netstat *ns, const char *name, bool *not_found)
{
if (not_found)
*not_found = false ;
while (ns != NULL) {
size_t i;
for (i = 0 ; i < ns->counters_nr; i++) {
if (!strcmp(name, ns->counters[i].name))
return ns->counters[i].val;
}
ns = ns->next;
}
if (not_found)
*not_found = true ;
return 0 ;
}
Messung V0.5 in Prozent C=98 H=91 G=94
¤ Dauer der Verarbeitung: 0.5 Sekunden
¤
*© Formatika GbR, Deutschland