docs: clean up make docs job
[vpp.git] / src / plugins / mdata / mdata.c
1 /*
2  * mdata.c - Buffer metadata change tracker
3  *
4  * Copyright (c) 2019 Cisco and/or its affiliates.
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at:
8  *
9  *     http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */
17
18 #include <vnet/vnet.h>
19 #include <vnet/plugin/plugin.h>
20 #include <mdata/mdata.h>
21
22 #include <vlibapi/api.h>
23 #include <vlibmemory/api.h>
24 #include <vpp/app/version.h>
25 #include <stdbool.h>
26
27 #include <mdata/mdata.api_enum.h>
28 #include <mdata/mdata.api_types.h>
29
30 #define REPLY_MSG_ID_BASE mmp->msg_id_base
31 #include <vlibapi/api_helper_macros.h>
32
33 mdata_main_t mdata_main;
34
35 /** @file mdata.c
36  * buffer metadata change tracker
37  */
38
39 static mdata_t mdata_none;
40
41 /** Metadata tracking callback
42     before_or_after: 0 => before, 1=> after
43 */
44 static void
45 mdata_trace_callback (vlib_main_t * vm, u64 * c0, u64 * c1,
46                       vlib_node_runtime_t * node,
47                       vlib_frame_t * frame, int before_or_after)
48 {
49   int i;
50   mdata_main_t *mm = &mdata_main;
51   vlib_buffer_t *bufs[VLIB_FRAME_SIZE], **b;
52   u32 *from;
53   u32 n_left_from;
54   mdata_t *before, *modifies;
55   u8 *after;
56
57   /* Input nodes don't have frames, etc. */
58   if (frame == 0)
59     return;
60
61   n_left_from = frame->n_vectors;
62
63   if (n_left_from == 0)
64     return;
65
66   from = vlib_frame_vector_args (frame);
67
68   vlib_get_buffers (vm, from, bufs, n_left_from);
69   b = bufs;
70
71   if (before_or_after == 1 /* after */ )
72     goto after_pass;
73
74   /* Resize the per-thread "before" vector to cover the current frame */
75   vec_reset_length (mm->before_per_thread[vm->thread_index]);
76   vec_validate (mm->before_per_thread[vm->thread_index], n_left_from - 1);
77   before = mm->before_per_thread[vm->thread_index];
78   before->node_index = ~0;
79
80   /* Before we call the dispatch fn, copy metadata. */
81   while (n_left_from > 0)
82     {
83       clib_memcpy_fast (before->mdata, b[0], sizeof (before->mdata));
84       b++;
85       before++;
86       n_left_from--;
87     }
88   return;
89
90 after_pass:
91
92   /* Recover the metadata copy we saved a moment ago */
93   before = mm->before_per_thread[vm->thread_index];
94
95   /* We'd better have the same number of buffers... */
96   ASSERT (n_left_from == vec_len (before));
97   ASSERT (node->node_index);
98
99   clib_spinlock_lock_if_init (&mm->modify_lock);
100
101   /*
102    * Resize the per-node accumulator vector as needed
103    * Paint the "no data" patter across any nodes we haven't seen yet
104    */
105   vec_validate_init_empty (mm->modifies, node->node_index, mdata_none);
106   modifies = vec_elt_at_index (mm->modifies, node->node_index);
107   modifies->node_index = node->node_index;
108   before = mm->before_per_thread[vm->thread_index];
109
110   /* Walk the frame */
111   while (n_left_from > 0)
112     {
113       after = (u8 *) b[0];
114
115       /* Compare metadata before and after node dispatch fn */
116       for (i = 0; i < ARRAY_LEN (before->mdata); i++)
117         {
118           /* Mark mdata octet changed */
119           if (before->mdata[i] != after[i])
120             modifies->mdata[i] = 0xff;
121         }
122
123       b++;
124       before++;
125       n_left_from--;
126     }
127
128   clib_spinlock_unlock_if_init (&mm->modify_lock);
129 }
130
131 int
132 mdata_enable_disable (mdata_main_t * mmp, int enable_disable)
133 {
134   int rv = 0;
135   vlib_thread_main_t *thread_main = vlib_get_thread_main ();
136   int i;
137
138   if (mmp->modify_lock == 0 && thread_main->n_vlib_mains > 1)
139     clib_spinlock_init (&mmp->modify_lock);
140
141   if (vec_len (mmp->before_per_thread) == 0)
142     {
143       mdata_none.node_index = ~0;
144       vec_validate (mmp->before_per_thread, vec_len (vlib_mains) - 1);
145     }
146
147   /* Reset the per-node accumulator, see vec_validate_init_empty above */
148   vec_reset_length (mmp->modifies);
149
150   for (i = 0; i < vec_len (vlib_mains); i++)
151     {
152       if (vlib_mains[i] == 0)
153         continue;
154
155       clib_callback_enable_disable
156         (vlib_mains[i]->vlib_node_runtime_perf_counter_cbs,
157          vlib_mains[i]->vlib_node_runtime_perf_counter_cb_tmp,
158          vlib_mains[i]->worker_thread_main_loop_callback_lock,
159          (void *) mdata_trace_callback, enable_disable);
160     }
161
162   return rv;
163 }
164
165 static clib_error_t *
166 mdata_enable_disable_command_fn (vlib_main_t * vm,
167                                  unformat_input_t * input,
168                                  vlib_cli_command_t * cmd)
169 {
170   mdata_main_t *mmp = &mdata_main;
171   int enable_disable = 1;
172
173   int rv;
174
175   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
176     {
177       if (unformat (input, "disable") || unformat (input, "off"))
178         enable_disable = 0;
179       if (unformat (input, "enable") || unformat (input, "on"))
180         enable_disable = 1;
181       else
182         break;
183     }
184
185   rv = mdata_enable_disable (mmp, enable_disable);
186
187   switch (rv)
188     {
189     case 0:
190       break;
191
192     default:
193       return clib_error_return (0, "mdata_enable_disable returned %d", rv);
194     }
195   return 0;
196 }
197
198 /*?
199  * This command enables or disables buffer metadata change tracking
200  *
201  *@cliexpar
202  * To enable buffer metadata change tracking:
203  *@cliexstart{buffer metadata tracking on}
204  * Tracking enabled
205  *@cliexend
206  *
207  *@cliexstart{buffer metadata tracking off}
208  * Tracking disabled
209  *@cliexend
210 ?*/
211
212 /* *INDENT-OFF* */
213 VLIB_CLI_COMMAND (mdata_enable_disable_command, static) =
214 {
215   .path = "buffer metadata tracking",
216   .short_help = "buffer metadata tracking [on][off]",
217   .function = mdata_enable_disable_command_fn,
218 };
219 /* *INDENT-ON* */
220
221 /* API message handler */
222 static void vl_api_mdata_enable_disable_t_handler
223   (vl_api_mdata_enable_disable_t * mp)
224 {
225   vl_api_mdata_enable_disable_reply_t *rmp;
226   mdata_main_t *mmp = &mdata_main;
227   int rv;
228
229   rv = mdata_enable_disable (mmp, (int) (mp->enable_disable));
230
231   REPLY_MACRO (VL_API_MDATA_ENABLE_DISABLE_REPLY);
232 }
233
234 /* API definitions */
235 #include <mdata/mdata.api.c>
236
237 static clib_error_t *
238 mdata_init (vlib_main_t * vm)
239 {
240   mdata_main_t *mmp = &mdata_main;
241   clib_error_t *error = 0;
242
243   mmp->vlib_main = vm;
244   mmp->vnet_main = vnet_get_main ();
245
246   /* Add our API messages to the global name_crc hash table */
247   mmp->msg_id_base = setup_message_id_table ();
248
249   return error;
250 }
251
252 VLIB_INIT_FUNCTION (mdata_init);
253
254 /* *INDENT-OFF* */
255 VLIB_PLUGIN_REGISTER () =
256 {
257   .version = VPP_BUILD_VER,
258   .description = "Buffer metadata change tracker."
259 };
260 /* *INDENT-ON* */
261
262
263 #define foreach_primary_metadata_field          \
264 _(current_data)                                 \
265 _(current_length)                               \
266 _(flags)                                        \
267 _(flow_id)                                      \
268 _(ref_count)                                    \
269 _(buffer_pool_index)                            \
270 _(error)                                        \
271 _(next_buffer)                                  \
272 _(current_config_index)                         \
273 _(punt_reason)
274
275 #define foreach_opaque_metadata_field           \
276 _(sw_if_index[0])                               \
277 _(sw_if_index[1])                               \
278 _(l2_hdr_offset)                                \
279 _(l3_hdr_offset)                                \
280 _(l4_hdr_offset)                                \
281 _(feature_arc_index)                            \
282 _(ip.adj_index[0])                              \
283 _(ip.adj_index[1])                              \
284 _(ip.flow_hash)                                 \
285 _(ip.save_protocol)                             \
286 _(ip.fib_index)                                 \
287 _(ip.icmp.type)                                 \
288 _(ip.icmp.code)                                 \
289 _(ip.icmp.data)                                 \
290 _(ip.reass.next_index)                          \
291 _(ip.reass.error_next_index)                    \
292 _(ip.reass.owner_thread_index)                  \
293 _(ip.reass.ip_proto)                            \
294 _(ip.reass.l4_src_port)                         \
295 _(ip.reass.l4_dst_port)                         \
296 _(ip.reass.estimated_mtu)                       \
297 _(ip.reass.fragment_first)                      \
298 _(ip.reass.fragment_last)                       \
299 _(ip.reass.range_first)                         \
300 _(ip.reass.range_last)                          \
301 _(ip.reass.next_range_bi)                       \
302 _(ip.reass.ip6_frag_hdr_offset)                 \
303 _(mpls.ttl)                                     \
304 _(mpls.exp)                                     \
305 _(mpls.first)                                   \
306 _(mpls.save_rewrite_length)                     \
307 _(mpls.mpls_hdr_length)                         \
308 _(mpls.bier.n_bytes)                            \
309 _(l2.feature_bitmap)                            \
310 _(l2.bd_index)                                  \
311 _(l2.l2fib_sn)                                  \
312 _(l2.l2_len)                                    \
313 _(l2.shg)                                       \
314 _(l2.bd_age)                                    \
315 _(l2t.next_index)                               \
316 _(l2t.session_index)                            \
317 _(l2_classify.table_index)                      \
318 _(l2_classify.opaque_index)                     \
319 _(l2_classify.hash)                             \
320 _(policer.index)                                \
321 _(ipsec.sad_index)                              \
322 _(ipsec.protect_index)                          \
323 _(map.mtu)                                      \
324 _(map_t.map_domain_index)                       \
325 _(map_t.v6.saddr)                               \
326 _(map_t.v6.daddr)                               \
327 _(map_t.v6.frag_offset)                         \
328 _(map_t.v6.l4_offset)                           \
329 _(map_t.v6.l4_protocol)                         \
330 _(map_t.checksum_offset)                        \
331 _(map_t.mtu)                                    \
332 _(ip_frag.mtu)                                  \
333 _(ip_frag.next_index)                           \
334 _(ip_frag.flags)                                \
335 _(cop.current_config_index)                     \
336 _(lisp.overlay_afi)                             \
337 _(tcp.connection_index)                         \
338 _(tcp.seq_number)                               \
339 _(tcp.next_node_opaque)                         \
340 _(tcp.seq_end)                                  \
341 _(tcp.ack_number)                               \
342 _(tcp.hdr_offset)                               \
343 _(tcp.data_offset)                              \
344 _(tcp.data_len)                                 \
345 _(tcp.flags)                                    \
346 _(snat.flags)
347
348 #define foreach_opaque2_metadata_field          \
349 _(qos.bits)                                     \
350 _(qos.source)                                   \
351 _(loop_counter)                                 \
352 _(gbp.flags)                                    \
353 _(gbp.sclass)                                   \
354 _(gso_size)                                     \
355 _(gso_l4_hdr_sz)                                \
356 _(pg_replay_timestamp)
357
358 static u8 *
359 format_buffer_metadata_changes (u8 * s, va_list * args)
360 {
361   mdata_main_t *mm = va_arg (*args, mdata_main_t *);
362   int verbose = va_arg (*args, int);
363   mdata_t *modifies;
364   vlib_buffer_t *b;
365   vnet_buffer_opaque_t *o;
366   vnet_buffer_opaque2_t *o2;
367   vlib_node_t *node;
368   int i, j;
369   int printed;
370
371   clib_spinlock_lock_if_init (&mm->modify_lock);
372
373   for (i = 0; i < vec_len (mm->modifies); i++)
374     {
375       modifies = vec_elt_at_index (mm->modifies, i);
376       node = vlib_get_node (mm->vlib_main, i);
377
378       /* No data for this node? */
379       if (modifies->node_index == ~0)
380         {
381           if (verbose)
382             s = format (s, "\n%v: no data\n", node->name);
383           continue;
384         }
385
386       /* We visited the node, but it may not have changed any metadata... */
387       for (j = 0; j < ARRAY_LEN (modifies->mdata); j++)
388         {
389           if (modifies->mdata[j])
390             goto found;
391         }
392       s = format (s, "\n%v: no metadata changes\n", node->name);
393       continue;
394
395     found:
396       /* Fields which the node modifies will be non-zero */
397       b = (vlib_buffer_t *) (modifies->mdata);
398
399       /* Dump primary metadata changes */
400       s = format (s, "\n%v: ", node->name);
401
402       printed = 0;
403 #define _(n) if (b->n) {s = format (s, "%s ", #n); printed = 1;}
404       foreach_primary_metadata_field;
405 #undef _
406
407       if (printed == 0)
408         s = format (s, "no vlib_buffer_t metadata changes");
409
410       vec_add1 (s, '\n');
411
412       /*
413        * Dump opaque union changes.
414        * Hopefully this will give folks a clue about opaque
415        * union data conflicts. That's the point of the exercise...
416        */
417       o = vnet_buffer (b);
418       printed = 0;
419       s = format (s, "  vnet_buffer_t: ");
420
421 #define _(n) if (o->n) {s = format (s, "%s ", #n); printed = 1;}
422       foreach_opaque_metadata_field;
423 #undef _
424
425       if (printed == 0)
426         s = format (s, "no changes");
427
428       vec_add1 (s, '\n');
429
430       o2 = vnet_buffer2 (b);
431       printed = 0;
432       s = format (s, "  vnet_buffer2_t: ");
433
434 #define _(n) if (o2->n) {s = format (s, "%s ", #n); printed = 1;}
435       foreach_opaque2_metadata_field;
436 #undef _
437       if (printed == 0)
438         s = format (s, "no changes");
439
440       vec_add1 (s, '\n');
441
442     }
443
444   clib_spinlock_unlock_if_init (&mm->modify_lock);
445
446   return s;
447 }
448
449 static clib_error_t *
450 show_metadata_command_fn (vlib_main_t * vm,
451                           unformat_input_t * input, vlib_cli_command_t * cmd)
452 {
453   int verbose = 0;
454
455   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
456     {
457       if (unformat (input, "verbose %=", &verbose, 1))
458         ;
459       else
460         break;
461     }
462
463   vlib_cli_output (vm, "%U", format_buffer_metadata_changes, &mdata_main,
464                    verbose);
465   return 0;
466 }
467
468 /*?
469  * This command displays buffer metadata change information
470  *@cliexpar
471  * How to display buffer metadata change information
472  *@cliexstart{show buffer metadata}
473  * ethernet-input: current_data current_length flags error
474  * vnet_buffer_t: l2_hdr_offset l3_hdr_offset
475  * vnet_buffer2_t: no changes
476  *@cliexend
477 ?*/
478
479 /* *INDENT-OFF* */
480 VLIB_CLI_COMMAND (show_metadata_command, static) =
481 {
482   .path = "show buffer metadata",
483   .short_help = "show buffer metadata",
484   .function = show_metadata_command_fn,
485 };
486 /* *INDENT-OFF* */
487
488 /*
489  * fd.io coding-style-patch-verification: ON
490  *
491  * Local Variables:
492  * eval: (c-set-style "gnu")
493  * End:
494  */