Line data Source code
1 : /* SPDX-License-Identifier: Apache-2.0
2 : * Copyright(c) 2022 Cisco Systems, Inc.
3 : */
4 :
5 : #include <vlib/vlib.h>
6 : #include <vlib/unix/unix.h>
7 : #include <vlib/stats/stats.h>
8 :
9 : enum
10 : {
11 : NODE_CLOCKS,
12 : NODE_VECTORS,
13 : NODE_CALLS,
14 : NODE_SUSPENDS,
15 : N_NODE_COUNTERS
16 : };
17 :
18 : struct
19 : {
20 : u32 entry_index;
21 : char *name;
22 : } node_counters[] = {
23 : [NODE_CLOCKS] = { .name = "clocks" },
24 : [NODE_VECTORS] = { .name = "vectors" },
25 : [NODE_CALLS] = { .name = "calls" },
26 : [NODE_SUSPENDS] = { .name = "suspends" },
27 : };
28 :
29 : static struct
30 : {
31 : u8 *name;
32 : u32 symlinks[N_NODE_COUNTERS];
33 : } *node_data = 0;
34 :
35 : static vlib_stats_string_vector_t node_names = 0;
36 :
37 : static inline void
38 147 : update_node_counters (vlib_stats_segment_t *sm)
39 : {
40 147 : clib_bitmap_t *bmp = 0;
41 147 : vlib_main_t **stat_vms = 0;
42 147 : vlib_node_t ***node_dups = 0;
43 : u32 n_nodes;
44 : int i, j;
45 :
46 147 : vlib_node_get_nodes (0 /* vm, for barrier sync */,
47 : (u32) ~0 /* all threads */, 1 /* include stats */,
48 : 0 /* barrier sync */, &node_dups, &stat_vms);
49 :
50 147 : n_nodes = vec_len (node_dups[0]);
51 :
52 147 : vec_validate (node_data, n_nodes - 1);
53 :
54 107137 : for (i = 0; i < n_nodes; i++)
55 106990 : if (vec_is_equal (node_data[i].name, node_dups[0][i]->name) == 0)
56 756 : bmp = clib_bitmap_set (bmp, i, 1);
57 :
58 147 : if (bmp)
59 : {
60 5 : u32 last_thread = vlib_get_n_threads ();
61 5 : vlib_stats_segment_lock ();
62 761 : clib_bitmap_foreach (i, bmp)
63 : {
64 756 : if (node_data[i].name)
65 : {
66 24 : vec_free (node_data[i].name);
67 120 : for (j = 0; j < ARRAY_LEN (node_data->symlinks); j++)
68 96 : vlib_stats_remove_entry (node_data[i].symlinks[j]);
69 : }
70 : }
71 : /* We can't merge the loops because a node index corresponding to a given
72 : * node name can change between 2 updates. Otherwise, we could add
73 : * already existing symlinks or delete valid ones.
74 : */
75 761 : clib_bitmap_foreach (i, bmp)
76 : {
77 756 : vlib_node_t *n = node_dups[0][i];
78 756 : node_data[i].name = vec_dup (n->name);
79 756 : vlib_stats_set_string_vector (&node_names, n->index, "%v", n->name);
80 :
81 3780 : for (int j = 0; j < ARRAY_LEN (node_counters); j++)
82 : {
83 3024 : vlib_stats_validate (node_counters[j].entry_index, last_thread,
84 : n_nodes - 1);
85 3024 : node_data[i].symlinks[j] = vlib_stats_add_symlink (
86 : node_counters[j].entry_index, n->index, "/nodes/%U/%s",
87 : format_vlib_stats_symlink, n->name, node_counters[j].name);
88 3024 : ASSERT (node_data[i].symlinks[j] != CLIB_U32_MAX);
89 : }
90 : }
91 5 : vlib_stats_segment_unlock ();
92 5 : vec_free (bmp);
93 : }
94 :
95 294 : for (j = 0; j < vec_len (node_dups); j++)
96 : {
97 147 : vlib_node_t **nodes = node_dups[j];
98 :
99 107137 : for (i = 0; i < vec_len (nodes); i++)
100 : {
101 : counter_t **counters;
102 : counter_t *c;
103 106990 : vlib_node_t *n = nodes[i];
104 :
105 106990 : counters = vlib_stats_get_entry_data_pointer (
106 : node_counters[NODE_CLOCKS].entry_index);
107 106990 : c = counters[j];
108 106990 : c[n->index] = n->stats_total.clocks - n->stats_last_clear.clocks;
109 :
110 106990 : counters = vlib_stats_get_entry_data_pointer (
111 : node_counters[NODE_VECTORS].entry_index);
112 106990 : c = counters[j];
113 106990 : c[n->index] = n->stats_total.vectors - n->stats_last_clear.vectors;
114 :
115 106990 : counters = vlib_stats_get_entry_data_pointer (
116 : node_counters[NODE_CALLS].entry_index);
117 106990 : c = counters[j];
118 106990 : c[n->index] = n->stats_total.calls - n->stats_last_clear.calls;
119 :
120 106990 : counters = vlib_stats_get_entry_data_pointer (
121 : node_counters[NODE_SUSPENDS].entry_index);
122 106990 : c = counters[j];
123 106990 : c[n->index] = n->stats_total.suspends - n->stats_last_clear.suspends;
124 : }
125 147 : vec_free (node_dups[j]);
126 : }
127 147 : vec_free (node_dups);
128 147 : vec_free (stat_vms);
129 147 : }
130 :
131 : static void
132 1203 : do_stat_segment_updates (vlib_main_t *vm, vlib_stats_segment_t *sm)
133 : {
134 1203 : if (sm->node_counters_enabled)
135 147 : update_node_counters (sm);
136 :
137 : vlib_stats_collector_t *c;
138 9674 : pool_foreach (c, sm->collectors)
139 : {
140 8471 : vlib_stats_collector_data_t data = {
141 8471 : .entry_index = c->entry_index,
142 8471 : .vector_index = c->vector_index,
143 8471 : .private_data = c->private_data,
144 8471 : .entry = sm->directory_vector + c->entry_index,
145 : };
146 8471 : c->fn (&data);
147 : }
148 :
149 : /* Heartbeat, so clients detect we're still here */
150 1203 : sm->directory_vector[STAT_COUNTER_HEARTBEAT].value++;
151 1203 : }
152 :
153 : static uword
154 559 : stat_segment_collector_process (vlib_main_t *vm, vlib_node_runtime_t *rt,
155 : vlib_frame_t *f)
156 : {
157 559 : vlib_stats_segment_t *sm = vlib_stats_get_segment ();
158 :
159 559 : if (sm->node_counters_enabled)
160 : {
161 1 : node_names = vlib_stats_add_string_vector ("/sys/node/names");
162 1 : ASSERT (node_names);
163 :
164 5 : for (int x = 0; x < ARRAY_LEN (node_counters); x++)
165 : {
166 4 : node_counters[x].entry_index = vlib_stats_add_counter_vector (
167 : "/sys/node/%s", node_counters[x].name);
168 4 : ASSERT (node_counters[x].entry_index != CLIB_U32_MAX);
169 : }
170 : }
171 :
172 559 : sm->directory_vector[STAT_COUNTER_BOOTTIME].value = unix_time_now ();
173 :
174 : while (1)
175 : {
176 1203 : do_stat_segment_updates (vm, sm);
177 1203 : vlib_process_suspend (vm, sm->update_interval);
178 : }
179 : return 0; /* or not */
180 : }
181 :
182 178120 : VLIB_REGISTER_NODE (stat_segment_collector, static) = {
183 : .function = stat_segment_collector_process,
184 : .name = "statseg-collector-process",
185 : .type = VLIB_NODE_TYPE_PROCESS,
186 : };
|