FD.io VPP  v19.04.4-rc0-5-ge88582fac
Vector Packet Processing
cj.c
Go to the documentation of this file.
1 /*
2  *------------------------------------------------------------------
3  * cj.c
4  *
5  * Copyright (c) 2013 Cisco and/or its affiliates.
6  * Licensed under the Apache License, Version 2.0 (the "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at:
9  *
10  * http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  *------------------------------------------------------------------
18  */
19 
20 /**
21  * @file
22  * Circular journal diagnostic mechanism.
23  *
24  * The @c cj thread-safe circular log buffer scheme is occasionally useful
25  * when chasing bugs. Calls to it should not be checked in.
26  */
27 /*? %%clicmd:group_label Circular Journal %% ?*/
28 /*? %%syscfg:group_label Circular Journal %% ?*/
29 
30 #include <stdio.h>
31 #include <vlib/vlib.h>
32 
33 #include <vlib/unix/cj.h>
34 
36 
37 void
38 cj_log (u32 type, void *data0, void *data1)
39 {
40  u64 new_tail;
41  cj_main_t *cjm = &cj_main;
42  cj_record_t *r;
43 
44  if (cjm->enable == 0)
45  return;
46 
47  new_tail = clib_atomic_add_fetch (&cjm->tail, 1);
48 
49  r = (cj_record_t *) & (cjm->records[new_tail & (cjm->num_records - 1)]);
50  r->time = vlib_time_now (cjm->vlib_main);
52  r->type = type;
53  r->data[0] = pointer_to_uword (data0);
54  r->data[1] = pointer_to_uword (data1);
55 }
56 
57 void
58 cj_stop (void)
59 {
60  cj_main_t *cjm = &cj_main;
61 
62  cjm->enable = 0;
63 }
64 
65 
68 {
69  cj_main_t *cjm = &cj_main;
70 
71  cjm->vlib_main = vm;
72  return 0;
73 }
74 
76 
77 static clib_error_t *
79 {
80  cj_main_t *cjm = &cj_main;
81  int matched = 0;
82  int enable = 0;
83 
85  {
86  if (unformat (input, "records %d", &cjm->num_records))
87  matched = 1;
88  else if (unformat (input, "on"))
89  enable = 1;
90  else
91  return clib_error_return (0, "cj_config: unknown input '%U'",
92  format_unformat_error, input);
93  }
94 
95  if (matched == 0)
96  return 0;
97 
98  cjm->num_records = max_pow2 (cjm->num_records);
99  vec_validate (cjm->records, cjm->num_records - 1);
100  clib_memset (cjm->records, 0xff, cjm->num_records * sizeof (cj_record_t));
101  cjm->tail = ~0;
102  cjm->enable = enable;
103 
104  return 0;
105 }
106 
107 /*?
108  * Configure the circular journal diagnostic mechanism. This is only useful
109  * if you, the developer, have written code to make use of the circular
110  * journal.
111  *
112  * @cfgcmd{records, &lt;number&gt;}
113  * Configure the number of records to allocate for the circular journal.
114  *
115  * @cfgcmd{on}
116  * Enable the collection of records in the circular journal at the
117  * earliest opportunity.
118 ?*/
120 
121 void
122 cj_enable_disable (int is_enable)
123 {
124  cj_main_t *cjm = &cj_main;
125 
126  if (cjm->num_records)
127  cjm->enable = is_enable;
128  else
129  vlib_cli_output (cjm->vlib_main, "CJ not configured...");
130 }
131 
132 static inline void
134 {
135  fprintf (stderr, "[%d]: %10.6f T%02d %llx %llx\n",
136  r->thread_index, r->time, r->type,
137  (long long unsigned int) r->data[0],
138  (long long unsigned int) r->data[1]);
139 }
140 
141 static void
142 cj_dump_internal (u8 filter0_enable, u64 filter0,
143  u8 filter1_enable, u64 filter1)
144 {
145  cj_main_t *cjm = &cj_main;
146  cj_record_t *r;
147  u32 i, index;
148 
149  if (cjm->num_records == 0)
150  {
151  fprintf (stderr, "CJ not configured...\n");
152  return;
153  }
154 
155  if (cjm->tail == (u64) ~ 0)
156  {
157  fprintf (stderr, "No data collected...\n");
158  return;
159  }
160 
161  /* Has the trace wrapped? */
162  index = (cjm->tail + 1) & (cjm->num_records - 1);
163  r = &(cjm->records[index]);
164 
165  if (r->thread_index != (u32) ~ 0)
166  {
167  /* Yes, dump from tail + 1 to the end */
168  for (i = index; i < cjm->num_records; i++)
169  {
170  if (filter0_enable && (r->data[0] != filter0))
171  goto skip;
172  if (filter1_enable && (r->data[1] != filter1))
173  goto skip;
174  cj_dump_one_record (r);
175  skip:
176  r++;
177  }
178  }
179  /* dump from the beginning through the final tail */
180  r = cjm->records;
181  for (i = 0; i < index; i++)
182  {
183  if (filter0_enable && (r->data[0] != filter0))
184  goto skip2;
185  if (filter1_enable && (r->data[1] != filter1))
186  goto skip2;
187  cj_dump_one_record (r);
188  skip2:
189  r++;
190  }
191 }
192 
193 void
194 cj_dump (void)
195 {
196  cj_dump_internal (0, 0, 0, 0);
197 }
198 
199 void
201 {
202  cj_dump_internal (1 /* enable f0 */ , filter0, 0, 0);
203 }
204 
205 void
207 {
208  cj_dump_internal (0, 0, 1 /* enable f1 */ , filter1);
209 }
210 
211 void
212 cj_dump_filter_data12 (u64 filter0, u64 filter1)
213 {
214  cj_dump_internal (1, filter0, 1, filter1);
215 }
216 
217 static clib_error_t *
219  unformat_input_t * input, vlib_cli_command_t * cmd)
220 {
221  int is_enable = -1;
222  int is_dump = -1;
223  unformat_input_t _line_input, *line_input = &_line_input;
224  clib_error_t *error = NULL;
225 
226  /* Get a line of input. */
227  if (!unformat_user (input, unformat_line_input, line_input))
228  return clib_error_return (0, "expected enable | disable | dump");
229 
230  while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
231  {
232  if (unformat (line_input, "enable") || unformat (line_input, "on"))
233  is_enable = 1;
234  else if (unformat (line_input, "disable")
235  || unformat (line_input, "off"))
236  is_enable = 0;
237  else if (unformat (line_input, "dump"))
238  is_dump = 1;
239  else
240  {
241  error = clib_error_return (0, "unknown input `%U'",
242  format_unformat_error, line_input);
243  goto done;
244  }
245  }
246 
247  if (is_enable >= 0)
248  cj_enable_disable (is_enable);
249 
250  if (is_dump > 0)
251  cj_dump ();
252 
253 done:
254  unformat_free (line_input);
255  return error;
256 }
257 
258 /*?
259  * Enable, disable the collection of diagnostic data into a
260  * circular journal or dump the circular journal diagnostic data.
261  * This is only useful if you, the developer, have written code to make
262  * use of the circular journal.
263  *
264  * When dumping the data it is formatted and sent to @c stderr of the
265  * VPP process; when running VPP in <code>unix interactive</code> mode
266  * this is typically the same place as the Debug CLI.
267 ?*/
268 
269 /* *INDENT-OFF* */
270 VLIB_CLI_COMMAND (cj_command,static) = {
271  .path = "cj",
272  .short_help = "cj <enable | disable | dump>",
273  .function = cj_command_fn,
274 };
275 /* *INDENT-ON* */
276 
277 
278 /*
279  * fd.io coding-style-patch-verification: ON
280  *
281  * Local Variables:
282  * eval: (c-set-style "gnu")
283  * End:
284  */
void cj_dump_filter_data12(u64 filter0, u64 filter1)
Definition: cj.c:212
#define vec_validate(V, I)
Make sure vector is long enough for given index (no header, unspecified alignment) ...
Definition: vec.h:439
#define clib_atomic_add_fetch(a, b)
Definition: atomics.h:30
unsigned long u64
Definition: types.h:89
#define NULL
Definition: clib.h:58
clib_memset(h->entries, 0, sizeof(h->entries[0]) *entries)
static f64 vlib_time_now(vlib_main_t *vm)
Definition: main.h:255
Definition: cj.h:31
static clib_error_t * cj_command_fn(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
Definition: cj.c:218
int i
volatile u32 enable
Definition: cj.h:36
uword unformat_user(unformat_input_t *input, unformat_function_t *func,...)
Definition: unformat.c:983
volatile u64 tail
Definition: cj.h:33
unsigned char u8
Definition: types.h:56
void cj_dump_filter_data1(u64 filter1)
Definition: cj.c:206
void cj_stop(void)
Definition: cj.c:58
void cj_enable_disable(int is_enable)
Definition: cj.c:122
#define VLIB_INIT_FUNCTION(x)
Definition: init.h:163
f64 time
Definition: cj.h:25
#define clib_error_return(e, args...)
Definition: error.h:99
unsigned int u32
Definition: types.h:88
void cj_log(u32 type, void *data0, void *data1)
Definition: cj.c:38
u32 thread_index
Definition: cj.h:26
unformat_function_t unformat_line_input
Definition: format.h:282
struct _unformat_input_t unformat_input_t
cj_main_t cj_main
Definition: cj.c:35
#define VLIB_CONFIG_FUNCTION(x, n,...)
Definition: init.h:172
vlib_main_t * vlib_main
Definition: cj.h:38
#define UNFORMAT_END_OF_INPUT
Definition: format.h:144
static void cj_dump_one_record(cj_record_t *r)
Definition: cj.c:133
static_always_inline uword vlib_get_thread_index(void)
Definition: threads.h:212
vlib_main_t * vm
Definition: buffer.c:312
static uword max_pow2(uword x)
Definition: clib.h:226
#define VLIB_CLI_COMMAND(x,...)
Definition: cli.h:155
void cj_dump_filter_data0(u64 filter0)
Definition: cj.c:200
clib_error_t * cj_init(vlib_main_t *vm)
Definition: cj.c:67
u64 data[2]
Definition: cj.h:28
Definition: cj.h:23
static uword pointer_to_uword(const void *p)
Definition: types.h:131
u32 type
Definition: cj.h:27
static void unformat_free(unformat_input_t *i)
Definition: format.h:162
u8 * format_unformat_error(u8 *s, va_list *va)
Definition: unformat.c:91
static void cj_dump_internal(u8 filter0_enable, u64 filter0, u8 filter1_enable, u64 filter1)
Definition: cj.c:142
u32 num_records
Definition: cj.h:35
cj_record_t * records
Definition: cj.h:34
void cj_dump(void)
Definition: cj.c:194
void vlib_cli_output(vlib_main_t *vm, char *fmt,...)
Definition: cli.c:762
static clib_error_t * cj_config(vlib_main_t *vm, unformat_input_t *input)
Definition: cj.c:78
uword unformat(unformat_input_t *i, const char *fmt,...)
Definition: unformat.c:972
static uword unformat_check_input(unformat_input_t *i)
Definition: format.h:170