summaryrefslogtreecommitdiffstats
path: root/src/vnet/dev/counters.c
blob: 0a1e0a7419d1bac2164a0bfb50df86e9f5b8a2c2 (plain)
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
121
122
123
124
125
126
127
128
129
130
131
132
/* SPDX-License-Identifier: Apache-2.0
 * Copyright (c) 2023 Cisco Systems, Inc.
 */

#include <vnet/vnet.h>
#include <vnet/ethernet/ethernet.h>
#include <vnet/dev/dev.h>
#include <vnet/dev/counters.h>
#include <vnet/dev/log.h>
#include <vnet/interface/rx_queue_funcs.h>

VLIB_REGISTER_LOG_CLASS (dev_log, static) = {
  .class_name = "dev",
  .subclass_name = "counters",
};

vnet_dev_counter_main_t *
vnet_dev_counters_alloc (vlib_main_t *vm, vnet_dev_counter_t *counters,
			 u16 n_counters, char *fmt, ...)
{
  vnet_dev_counter_t *c;
  vnet_dev_counter_main_t *cm;
  u32 alloc_sz;

  alloc_sz = sizeof (*cm) + n_counters * sizeof (*c);
  cm = clib_mem_alloc_aligned (alloc_sz, CLIB_CACHE_LINE_BYTES);
  clib_memset (cm, 0, sizeof (*cm));
  cm->n_counters = n_counters;

  if (fmt && strlen (fmt))
    {
      va_list va;
      va_start (va, fmt);
      cm->desc = va_format (0, fmt, &va);
      va_end (va);
    }

  for (u32 i = 0; i < n_counters; i++)
    {
      cm->counters[i] = counters[i];
      cm->counters[i].index = i;
    }

  vec_validate_aligned (cm->counter_data, n_counters - 1,
			CLIB_CACHE_LINE_BYTES);
  vec_validate_aligned (cm->counter_start, n_counters - 1,
			CLIB_CACHE_LINE_BYTES);

  return cm;
}

void
vnet_dev_counters_clear (vlib_main_t *vm, vnet_dev_counter_main_t *cm)
{
  for (int i = 0; i < cm->n_counters; i++)
    {
      cm->counter_start[i] = cm->counter_data[i];
      cm->counter_data[i] = 0;
    }
}

void
vnet_dev_counters_free (vlib_main_t *vm, vnet_dev_counter_main_t *cm)
{
  vec_free (cm->desc);
  vec_free (cm->counter_data);
  vec_free (cm->counter_start);
  clib_mem_free (cm);
}

u8 *
format_vnet_dev_counter_name (u8 *s, va_list *va)
{
  vnet_dev_counter_t *c = va_arg (*va, vnet_dev_counter_t *);

  char *std_counters[] = {
    [VNET_DEV_CTR_TYPE_RX_BYTES] = "total bytes received",
    [VNET_DEV_CTR_TYPE_TX_BYTES] = "total bytes transmitted",
    [VNET_DEV_CTR_TYPE_RX_PACKETS] = "total packets received",
    [VNET_DEV_CTR_TYPE_TX_PACKETS] = "total packets transmitted",
    [VNET_DEV_CTR_TYPE_RX_DROPS] = "total drops received",
    [VNET_DEV_CTR_TYPE_TX_DROPS] = "total drops transmitted",
  };

  char *directions[] = {
    [VNET_DEV_CTR_DIR_RX] = "received",
    [VNET_DEV_CTR_DIR_TX] = "sent",
  };
  char *units[] = {
    [VNET_DEV_CTR_UNIT_BYTES] = "bytes",
    [VNET_DEV_CTR_UNIT_PACKETS] = "packets",
  };

  if (c->type == VNET_DEV_CTR_TYPE_VENDOR)
    {
      s = format (s, "%s", c->name);

      if (c->unit < ARRAY_LEN (units) && units[c->unit])
	s = format (s, " %s", units[c->unit]);

      if (c->dir < ARRAY_LEN (directions) && directions[c->dir])
	s = format (s, " %s", directions[c->dir]);
    }
  else if (c->type < ARRAY_LEN (std_counters) && std_counters[c->type])
    s = format (s, "%s", std_counters[c->type]);
  else
    ASSERT (0);

  return s;
}

u8 *
format_vnet_dev_counters (u8 *s, va_list *va)
{
  vnet_dev_format_args_t *a = va_arg (*va, vnet_dev_format_args_t *);
  vnet_dev_counter_main_t *cm = va_arg (*va, vnet_dev_counter_main_t *);
  u32 line = 0, indent = format_get_indent (s);

  foreach_vnet_dev_counter (c, cm)
    {
      if (a->show_zero_counters == 0 && cm->counter_data[c->index] == 0)
	continue;

      if (line++)
	s = format (s, "\n%U", format_white_space, indent);

      s = format (s, "%-45U%lu", format_vnet_dev_counter_name, c,
		  cm->counter_data[c->index]);
    }

  return s;
}