]> git.proxmox.com Git - ovs.git/blame - ofproto/ofproto-dpif-trace.c
ofp-actions: Add action "debug_slow" for testing slow-path.
[ovs.git] / ofproto / ofproto-dpif-trace.c
CommitLineData
d13ee228 1/*
2d9b49dd 2 * Copyright (c) 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017 Nicira, Inc.
d13ee228
BP
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at:
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include <config.h>
18
19#include "ofproto-dpif-trace.h"
20
0f2f05bb 21#include "conntrack.h"
d13ee228
BP
22#include "dpif.h"
23#include "ofproto-dpif-xlate.h"
24#include "openvswitch/ofp-parse.h"
25#include "unixctl.h"
26
e6bc8e74 27static void ofproto_trace(struct ofproto_dpif *, const struct flow *,
d13ee228
BP
28 const struct dp_packet *packet,
29 const struct ofpact[], size_t ofpacts_len,
0f2f05bb 30 struct ovs_list *next_ct_states,
d13ee228 31 struct ds *);
2d9b49dd
BP
32static void oftrace_node_destroy(struct oftrace_node *);
33
34/* Creates a new oftrace_node, populates it with the given 'type' and a copy of
35 * 'text', and appends it to list 'super'. The caller retains ownership of
36 * 'text'. */
37struct oftrace_node *
38oftrace_report(struct ovs_list *super, enum oftrace_node_type type,
39 const char *text)
d13ee228 40{
2d9b49dd
BP
41 struct oftrace_node *node = xmalloc(sizeof *node);
42 ovs_list_push_back(super, &node->node);
43 node->type = type;
44 node->text = xstrdup(text);
45 ovs_list_init(&node->subs);
d13ee228 46
2d9b49dd 47 return node;
d13ee228
BP
48}
49
2d9b49dd
BP
50static bool
51oftrace_node_type_is_terminal(enum oftrace_node_type type)
d13ee228 52{
2d9b49dd
BP
53 switch (type) {
54 case OFT_ACTION:
55 case OFT_DETAIL:
56 case OFT_WARN:
57 case OFT_ERROR:
58 return true;
59
60 case OFT_BRIDGE:
61 case OFT_TABLE:
62 case OFT_THAW:
63 return false;
d13ee228 64 }
2d9b49dd
BP
65
66 OVS_NOT_REACHED();
d13ee228
BP
67}
68
69static void
2d9b49dd 70oftrace_node_list_destroy(struct ovs_list *nodes)
d13ee228 71{
2d9b49dd
BP
72 if (nodes) {
73 struct oftrace_node *node, *next;
74 LIST_FOR_EACH_SAFE (node, next, node, nodes) {
75 ovs_list_remove(&node->node);
76 oftrace_node_destroy(node);
77 }
d13ee228 78 }
d13ee228
BP
79}
80
81static void
2d9b49dd 82oftrace_node_destroy(struct oftrace_node *node)
d13ee228 83{
2d9b49dd
BP
84 if (node) {
85 oftrace_node_list_destroy(&node->subs);
86 free(node->text);
87 free(node);
88 }
d13ee228
BP
89}
90
e6bc8e74
YHW
91bool
92oftrace_add_recirc_node(struct ovs_list *recirc_queue,
93 enum oftrace_recirc_type type, const struct flow *flow,
5fdd80cc
YHW
94 const struct dp_packet *packet, uint32_t recirc_id,
95 const uint16_t zone)
e6bc8e74
YHW
96{
97 if (!recirc_id_node_find_and_ref(recirc_id)) {
98 return false;
99 }
100
101 struct oftrace_recirc_node *node = xmalloc(sizeof *node);
102 ovs_list_push_back(recirc_queue, &node->node);
103
104 node->type = type;
105 node->recirc_id = recirc_id;
106 node->flow = *flow;
107 node->flow.recirc_id = recirc_id;
5fdd80cc 108 node->flow.ct_zone = zone;
e6bc8e74
YHW
109 node->packet = packet ? dp_packet_clone(packet) : NULL;
110
111 return true;
112}
113
114static void
115oftrace_recirc_node_destroy(struct oftrace_recirc_node *node)
116{
117 if (node) {
118 recirc_free_id(node->recirc_id);
119 dp_packet_delete(node->packet);
120 free(node);
121 }
122}
123
0f2f05bb
YHW
124static void
125oftrace_push_ct_state(struct ovs_list *next_ct_states, uint32_t ct_state)
126{
127 struct oftrace_next_ct_state *next_ct_state =
128 xmalloc(sizeof *next_ct_state);
129 next_ct_state->state = ct_state;
130 ovs_list_push_back(next_ct_states, &next_ct_state->node);
131}
132
133static uint32_t
134oftrace_pop_ct_state(struct ovs_list *next_ct_states)
135{
136 struct oftrace_next_ct_state *s;
137 LIST_FOR_EACH_POP (s, node, next_ct_states) {
36e67140
YHW
138 uint32_t state = s->state;
139 free(s);
140 return state;
0f2f05bb
YHW
141 }
142 OVS_NOT_REACHED();
143}
144
d13ee228 145static void
2d9b49dd
BP
146oftrace_node_print_details(struct ds *output,
147 const struct ovs_list *nodes, int level)
d13ee228 148{
2d9b49dd
BP
149 const struct oftrace_node *sub;
150 LIST_FOR_EACH (sub, node, nodes) {
151 if (sub->type == OFT_BRIDGE) {
152 ds_put_char(output, '\n');
153 }
d13ee228 154
2d9b49dd
BP
155 bool more = (sub->node.next != nodes
156 || oftrace_node_type_is_terminal(sub->type));
157
158 ds_put_char_multiple(output, ' ', (level + more) * 4);
159 switch (sub->type) {
160 case OFT_DETAIL:
161 ds_put_format(output, " -> %s\n", sub->text);
162 break;
163 case OFT_WARN:
164 ds_put_format(output, " >> %s\n", sub->text);
165 break;
166 case OFT_ERROR:
167 ds_put_format(output, " >>>> %s <<<<\n", sub->text);
168 break;
169 case OFT_BRIDGE:
170 ds_put_format(output, "%s\n", sub->text);
171 ds_put_char_multiple(output, ' ', (level + more) * 4);
172 ds_put_char_multiple(output, '-', strlen(sub->text));
173 ds_put_char(output, '\n');
174 break;
175 case OFT_TABLE:
176 case OFT_THAW:
177 case OFT_ACTION:
178 ds_put_format(output, "%s\n", sub->text);
179 break;
d13ee228 180 }
d13ee228 181
2d9b49dd 182 oftrace_node_print_details(output, &sub->subs, level + more + more);
d13ee228 183 }
d13ee228
BP
184}
185
0f2f05bb
YHW
186static char * OVS_WARN_UNUSED_RESULT
187parse_oftrace_options(int argc, const char *argv[],
188 struct ovs_list *next_ct_states)
189{
190 int k;
191 struct ds ds = DS_EMPTY_INITIALIZER;
192
193 for (k = 0; k < argc; k++) {
194 if (!strncmp(argv[k], "--ct-next", 9)) {
195 if (k + 1 > argc) {
196 return xasprintf("Missing argument for option %s", argv[k]);
197 }
198
199 uint32_t ct_state;
200 if (!parse_ct_state(argv[++k], 0, &ct_state, &ds)) {
201 return ds_steal_cstr(&ds);
202 }
203 if (!validate_ct_state(ct_state, &ds)) {
204 return ds_steal_cstr(&ds);
205 }
206 oftrace_push_ct_state(next_ct_states, ct_state);
207 } else {
208 return xasprintf("Invalid option %s", argv[k]);
209 }
210 }
211
212 ds_destroy(&ds);
213 return NULL;
214}
215
d13ee228
BP
216/* Parses the 'argc' elements of 'argv', ignoring argv[0]. The following
217 * forms are supported:
218 *
0f2f05bb
YHW
219 * - [dpname] odp_flow [OPTIONS] [-generate | packet]
220 * - bridge br_flow [OPTIONS] [-generate | packet]
d13ee228
BP
221 *
222 * On success, initializes '*ofprotop' and 'flow' and returns NULL. On failure
223 * returns a nonnull malloced error message. */
224static char * OVS_WARN_UNUSED_RESULT
225parse_flow_and_packet(int argc, const char *argv[],
226 struct ofproto_dpif **ofprotop, struct flow *flow,
0f2f05bb
YHW
227 struct dp_packet **packetp,
228 struct ovs_list *next_ct_states)
d13ee228
BP
229{
230 const struct dpif_backer *backer = NULL;
231 const char *error = NULL;
232 char *m_err = NULL;
233 struct simap port_names = SIMAP_INITIALIZER(&port_names);
234 struct dp_packet *packet;
235 struct ofpbuf odp_key;
236 struct ofpbuf odp_mask;
0f2f05bb 237 int first_option;
d13ee228
BP
238
239 ofpbuf_init(&odp_key, 0);
240 ofpbuf_init(&odp_mask, 0);
241
242 /* Handle "-generate" or a hex string as the last argument. */
243 if (!strcmp(argv[argc - 1], "-generate")) {
244 packet = dp_packet_new(0);
245 argc--;
246 } else {
247 error = eth_from_hex(argv[argc - 1], &packet);
248 if (!error) {
249 argc--;
250 } else if (argc == 4) {
251 /* The 3-argument form must end in "-generate' or a hex string. */
252 goto exit;
253 }
254 error = NULL;
255 }
256
0f2f05bb
YHW
257 /* Parse options. */
258 if (argc >= 4) {
259 if (!strncmp(argv[2], "--", 2)) {
260 first_option = 2;
261 } else if (!strncmp(argv[3], "--", 2)) {
262 first_option = 3;
263 } else {
264 error = "Syntax error: invalid option";
265 goto exit;
266 }
267
268 m_err = parse_oftrace_options(argc - first_option, argv + first_option,
269 next_ct_states);
270 if (m_err) {
271 goto exit;
272 }
273 argc = first_option;
274 }
275
d13ee228
BP
276 /* odp_flow can have its in_port specified as a name instead of port no.
277 * We do not yet know whether a given flow is a odp_flow or a br_flow.
278 * But, to know whether a flow is odp_flow through odp_flow_from_string(),
279 * we need to create a simap of name to port no. */
280 if (argc == 3) {
281 const char *dp_type;
282 if (!strncmp(argv[1], "ovs-", 4)) {
283 dp_type = argv[1] + 4;
284 } else {
285 dp_type = argv[1];
286 }
287 backer = shash_find_data(&all_dpif_backers, dp_type);
288 } else if (argc == 2) {
289 struct shash_node *node;
290 if (shash_count(&all_dpif_backers) == 1) {
291 node = shash_first(&all_dpif_backers);
292 backer = node->data;
293 }
294 } else {
295 error = "Syntax error";
296 goto exit;
297 }
298 if (backer && backer->dpif) {
299 struct dpif_port dpif_port;
300 struct dpif_port_dump port_dump;
301 DPIF_PORT_FOR_EACH (&dpif_port, &port_dump, backer->dpif) {
302 simap_put(&port_names, dpif_port.name,
303 odp_to_u32(dpif_port.port_no));
304 }
305 }
306
307 /* Parse the flow and determine whether a datapath or
308 * bridge is specified. If function odp_flow_key_from_string()
309 * returns 0, the flow is a odp_flow. If function
310 * parse_ofp_exact_flow() returns NULL, the flow is a br_flow. */
311 if (!odp_flow_from_string(argv[argc - 1], &port_names,
312 &odp_key, &odp_mask)) {
313 if (!backer) {
314 error = "Cannot find the datapath";
315 goto exit;
316 }
317
318 if (odp_flow_key_to_flow(odp_key.data, odp_key.size, flow) == ODP_FIT_ERROR) {
319 error = "Failed to parse datapath flow key";
320 goto exit;
321 }
322
323 *ofprotop = xlate_lookup_ofproto(backer, flow,
324 &flow->in_port.ofp_port);
325 if (*ofprotop == NULL) {
326 error = "Invalid datapath flow";
327 goto exit;
328 }
329
330 flow->tunnel.metadata.tab = ofproto_get_tun_tab(&(*ofprotop)->up);
331
332 /* Convert Geneve options to OpenFlow format now. This isn't actually
333 * required in order to get the right results since the ofproto xlate
334 * actions will handle this for us. However, converting now ensures
335 * that our formatting code will always be able to consistently print
336 * in OpenFlow format, which is what we use here. */
337 if (flow->tunnel.flags & FLOW_TNL_F_UDPIF) {
338 struct flow_tnl tnl;
339 int err;
340
341 memcpy(&tnl, &flow->tunnel, sizeof tnl);
342 err = tun_metadata_from_geneve_udpif(flow->tunnel.metadata.tab,
343 &tnl, &tnl, &flow->tunnel);
344 if (err) {
345 error = "Failed to parse Geneve options";
346 goto exit;
347 }
348 }
349 } else {
350 char *err;
351
352 if (argc != 3) {
353 error = "Must specify bridge name";
354 goto exit;
355 }
356
911b4a7e 357 *ofprotop = ofproto_dpif_lookup_by_name(argv[1]);
d13ee228
BP
358 if (!*ofprotop) {
359 error = "Unknown bridge name";
360 goto exit;
361 }
362
50f96b10
BP
363 struct ofputil_port_map map = OFPUTIL_PORT_MAP_INITIALIZER(&map);
364 const struct ofport *ofport;
365 HMAP_FOR_EACH (ofport, hmap_node, &(*ofprotop)->up.ports) {
366 ofputil_port_map_put(&map, ofport->ofp_port,
367 netdev_get_name(ofport->netdev));
368 }
d13ee228
BP
369 err = parse_ofp_exact_flow(flow, NULL,
370 ofproto_get_tun_tab(&(*ofprotop)->up),
50f96b10
BP
371 argv[argc - 1], &map);
372 ofputil_port_map_destroy(&map);
d13ee228
BP
373 if (err) {
374 m_err = xasprintf("Bad openflow flow syntax: %s", err);
375 free(err);
376 goto exit;
377 }
378 }
379
380 /* Generate a packet, if requested. */
381 if (packet) {
382 if (!dp_packet_size(packet)) {
bc0f5176 383 flow_compose(packet, flow, 0);
d13ee228
BP
384 } else {
385 /* Use the metadata from the flow and the packet argument
386 * to reconstruct the flow. */
387 pkt_metadata_from_flow(&packet->md, flow);
388 flow_extract(packet, flow);
389 }
390 }
391
392exit:
393 if (error && !m_err) {
394 m_err = xstrdup(error);
395 }
396 if (m_err) {
397 dp_packet_delete(packet);
398 packet = NULL;
399 }
400 *packetp = packet;
401 ofpbuf_uninit(&odp_key);
402 ofpbuf_uninit(&odp_mask);
403 simap_destroy(&port_names);
404 return m_err;
405}
406
0f2f05bb
YHW
407static void
408free_ct_states(struct ovs_list *ct_states)
409{
410 while (!ovs_list_is_empty(ct_states)) {
411 oftrace_pop_ct_state(ct_states);
412 }
413}
414
d13ee228
BP
415static void
416ofproto_unixctl_trace(struct unixctl_conn *conn, int argc, const char *argv[],
417 void *aux OVS_UNUSED)
418{
419 struct ofproto_dpif *ofproto;
420 struct dp_packet *packet;
421 char *error;
422 struct flow flow;
0f2f05bb 423 struct ovs_list next_ct_states = OVS_LIST_INITIALIZER(&next_ct_states);
d13ee228 424
0f2f05bb
YHW
425 error = parse_flow_and_packet(argc, argv, &ofproto, &flow, &packet,
426 &next_ct_states);
d13ee228
BP
427 if (!error) {
428 struct ds result;
429
430 ds_init(&result);
0f2f05bb
YHW
431 ofproto_trace(ofproto, &flow, packet, NULL, 0, &next_ct_states,
432 &result);
d13ee228
BP
433 unixctl_command_reply(conn, ds_cstr(&result));
434 ds_destroy(&result);
435 dp_packet_delete(packet);
436 } else {
437 unixctl_command_reply_error(conn, error);
438 free(error);
439 }
0f2f05bb 440 free_ct_states(&next_ct_states);
d13ee228
BP
441}
442
443static void
444ofproto_unixctl_trace_actions(struct unixctl_conn *conn, int argc,
445 const char *argv[], void *aux OVS_UNUSED)
446{
447 enum ofputil_protocol usable_protocols;
448 struct ofproto_dpif *ofproto;
449 bool enforce_consistency;
450 struct ofpbuf ofpacts;
451 struct dp_packet *packet;
452 struct ds result;
67210a55 453 struct match match;
d13ee228 454 uint16_t in_port;
0f2f05bb 455 struct ovs_list next_ct_states = OVS_LIST_INITIALIZER(&next_ct_states);
d13ee228
BP
456
457 /* Three kinds of error return values! */
458 enum ofperr retval;
459 char *error;
460
461 packet = NULL;
462 ds_init(&result);
463 ofpbuf_init(&ofpacts, 0);
464
465 /* Parse actions. */
50f96b10
BP
466 error = ofpacts_parse_actions(argv[--argc], NULL,
467 &ofpacts, &usable_protocols);
d13ee228
BP
468 if (error) {
469 unixctl_command_reply_error(conn, error);
470 free(error);
471 goto exit;
472 }
473
474 /* OpenFlow 1.1 and later suggest that the switch enforces certain forms of
475 * consistency between the flow and the actions. With -consistent, we
476 * enforce consistency even for a flow supported in OpenFlow 1.0. */
477 if (!strcmp(argv[1], "-consistent")) {
478 enforce_consistency = true;
479 argv++;
480 argc--;
481 } else {
482 enforce_consistency = false;
483 }
484
0f2f05bb
YHW
485 error = parse_flow_and_packet(argc, argv, &ofproto, &match.flow, &packet,
486 &next_ct_states);
d13ee228
BP
487 if (error) {
488 unixctl_command_reply_error(conn, error);
489 free(error);
490 goto exit;
491 }
67210a55 492 match_wc_init(&match, &match.flow);
d13ee228
BP
493
494 /* Do the same checks as handle_packet_out() in ofproto.c.
495 *
496 * We pass a 'table_id' of 0 to ofpacts_check(), which isn't
497 * strictly correct because these actions aren't in any table, but it's OK
498 * because it 'table_id' is used only to check goto_table instructions, but
499 * packet-outs take a list of actions and therefore it can't include
500 * instructions.
501 *
502 * We skip the "meter" check here because meter is an instruction, not an
503 * action, and thus cannot appear in ofpacts. */
67210a55 504 in_port = ofp_to_u16(match.flow.in_port.ofp_port);
d13ee228
BP
505 if (in_port >= ofproto->up.max_ports && in_port < ofp_to_u16(OFPP_MAX)) {
506 unixctl_command_reply_error(conn, "invalid in_port");
507 goto exit;
508 }
509 if (enforce_consistency) {
67210a55 510 retval = ofpacts_check_consistency(ofpacts.data, ofpacts.size, &match,
d13ee228
BP
511 u16_to_ofp(ofproto->up.max_ports),
512 0, ofproto->up.n_tables,
513 usable_protocols);
514 } else {
67210a55 515 retval = ofpacts_check(ofpacts.data, ofpacts.size, &match,
d13ee228
BP
516 u16_to_ofp(ofproto->up.max_ports), 0,
517 ofproto->up.n_tables, &usable_protocols);
518 }
519 if (!retval) {
d61973d6 520 ovs_mutex_lock(&ofproto_mutex);
d13ee228
BP
521 retval = ofproto_check_ofpacts(&ofproto->up, ofpacts.data,
522 ofpacts.size);
d61973d6 523 ovs_mutex_unlock(&ofproto_mutex);
d13ee228
BP
524 }
525
526 if (retval) {
527 ds_clear(&result);
528 ds_put_format(&result, "Bad actions: %s", ofperr_to_string(retval));
529 unixctl_command_reply_error(conn, ds_cstr(&result));
530 goto exit;
531 }
532
67210a55 533 ofproto_trace(ofproto, &match.flow, packet,
0f2f05bb 534 ofpacts.data, ofpacts.size, &next_ct_states, &result);
d13ee228
BP
535 unixctl_command_reply(conn, ds_cstr(&result));
536
537exit:
538 ds_destroy(&result);
539 dp_packet_delete(packet);
540 ofpbuf_uninit(&ofpacts);
0f2f05bb 541 free_ct_states(&next_ct_states);
d13ee228
BP
542}
543
d13ee228 544static void
e6bc8e74
YHW
545ofproto_trace__(struct ofproto_dpif *ofproto, const struct flow *flow,
546 const struct dp_packet *packet, struct ovs_list *recirc_queue,
547 const struct ofpact ofpacts[], size_t ofpacts_len,
548 struct ds *output)
d13ee228 549{
2d9b49dd
BP
550 struct ofpbuf odp_actions;
551 ofpbuf_init(&odp_actions, 0);
d13ee228 552
2d9b49dd
BP
553 struct xlate_in xin;
554 struct flow_wildcards wc;
555 struct ovs_list trace = OVS_LIST_INITIALIZER(&trace);
556 xlate_in_init(&xin, ofproto,
d13ee228
BP
557 ofproto_dpif_get_tables_version(ofproto), flow,
558 flow->in_port.ofp_port, NULL, ntohs(flow->tcp_flags),
2d9b49dd
BP
559 packet, &wc, &odp_actions);
560 xin.ofpacts = ofpacts;
561 xin.ofpacts_len = ofpacts_len;
562 xin.trace = &trace;
e6bc8e74 563 xin.recirc_queue = recirc_queue;
2d9b49dd
BP
564
565 /* Copy initial flow out of xin.flow. It differs from '*flow' because
566 * xlate_in_init() initializes actset_output to OFPP_UNSET. */
567 struct flow initial_flow = xin.flow;
568 ds_put_cstr(output, "Flow: ");
50f96b10 569 flow_format(output, &initial_flow, NULL);
2d9b49dd
BP
570 ds_put_char(output, '\n');
571
572 struct xlate_out xout;
573 enum xlate_error error = xlate_actions(&xin, &xout);
574
575 oftrace_node_print_details(output, &trace, 0);
576
577 ds_put_cstr(output, "\nFinal flow: ");
578 if (flow_equal(&initial_flow, &xin.flow)) {
579 ds_put_cstr(output, "unchanged");
580 } else {
50f96b10 581 flow_format(output, &xin.flow, NULL);
2d9b49dd
BP
582 }
583 ds_put_char(output, '\n');
d13ee228 584
2d9b49dd
BP
585 ds_put_cstr(output, "Megaflow: ");
586 struct match match;
587 match_init(&match, flow, &wc);
50f96b10 588 match_format(&match, NULL, output, OFP_DEFAULT_PRIORITY);
2d9b49dd 589 ds_put_char(output, '\n');
d13ee228 590
2d9b49dd 591 ds_put_cstr(output, "Datapath actions: ");
0722f341 592 format_odp_actions(output, odp_actions.data, odp_actions.size, NULL);
d13ee228
BP
593
594 if (error != XLATE_OK) {
2d9b49dd
BP
595 ds_put_format(output,
596 "\nTranslation failed (%s), packet is dropped.\n",
d13ee228 597 xlate_strerror(error));
2d9b49dd 598 } else if (xout.slow) {
d13ee228
BP
599 enum slow_path_reason slow;
600
2d9b49dd 601 ds_put_cstr(output, "\nThis flow is handled by the userspace "
d13ee228
BP
602 "slow path because it:");
603
2d9b49dd 604 slow = xout.slow;
d13ee228
BP
605 while (slow) {
606 enum slow_path_reason bit = rightmost_1bit(slow);
607
2d9b49dd 608 ds_put_format(output, "\n\t- %s.",
d13ee228
BP
609 slow_path_reason_to_explanation(bit));
610
611 slow &= ~bit;
612 }
613 }
614
2d9b49dd
BP
615 xlate_out_uninit(&xout);
616 ofpbuf_uninit(&odp_actions);
617 oftrace_node_list_destroy(&trace);
d13ee228
BP
618}
619
e6bc8e74
YHW
620/* Implements a "trace" through 'ofproto''s flow table, appending a textual
621 * description of the results to 'output'.
622 *
623 * The trace follows a packet with the specified 'flow' through the flow
624 * table. 'packet' may be nonnull to trace an actual packet, with consequent
625 * side effects (if it is nonnull then its flow must be 'flow').
626 *
627 * If 'ofpacts' is nonnull then its 'ofpacts_len' bytes specify the actions to
628 * trace, otherwise the actions are determined by a flow table lookup. */
629static void
630ofproto_trace(struct ofproto_dpif *ofproto, const struct flow *flow,
631 const struct dp_packet *packet,
632 const struct ofpact ofpacts[], size_t ofpacts_len,
0f2f05bb 633 struct ovs_list *next_ct_states, struct ds *output)
e6bc8e74
YHW
634{
635 struct ovs_list recirc_queue = OVS_LIST_INITIALIZER(&recirc_queue);
636 ofproto_trace__(ofproto, flow, packet, &recirc_queue,
637 ofpacts, ofpacts_len, output);
638
639 struct oftrace_recirc_node *recirc_node;
640 LIST_FOR_EACH_POP (recirc_node, node, &recirc_queue) {
641 ds_put_cstr(output, "\n\n");
642 ds_put_char_multiple(output, '=', 79);
643 ds_put_format(output, "\nrecirc(%#"PRIx32")",
644 recirc_node->recirc_id);
0f2f05bb 645
e6bc8e74 646 if (recirc_node->type == OFT_RECIRC_CONNTRACK) {
0f2f05bb
YHW
647 uint32_t ct_state;
648 if (ovs_list_is_empty(next_ct_states)) {
649 ct_state = CS_TRACKED | CS_NEW;
650 ds_put_cstr(output, " - resume conntrack with default "
651 "ct_state=trk|new (use --ct-next to customize)");
652 } else {
653 ct_state = oftrace_pop_ct_state(next_ct_states);
654 struct ds s = DS_EMPTY_INITIALIZER;
655 format_flags(&s, ct_state_to_string, ct_state, '|');
656 ds_put_format(output, " - resume conntrack with ct_state=%s",
657 ds_cstr(&s));
658 ds_destroy(&s);
659 }
660 recirc_node->flow.ct_state = ct_state;
e6bc8e74
YHW
661 }
662 ds_put_char(output, '\n');
663 ds_put_char_multiple(output, '=', 79);
664 ds_put_cstr(output, "\n\n");
665
666 ofproto_trace__(ofproto, &recirc_node->flow, recirc_node->packet,
667 &recirc_queue, ofpacts, ofpacts_len, output);
668 oftrace_recirc_node_destroy(recirc_node);
669 }
670}
671
d13ee228
BP
672void
673ofproto_dpif_trace_init(void)
674{
675 static bool registered;
676 if (registered) {
677 return;
678 }
679 registered = true;
680
681 unixctl_command_register(
682 "ofproto/trace",
0f2f05bb
YHW
683 "{[dp_name] odp_flow | bridge br_flow} [OPTIONS...] "
684 "[-generate|packet]", 1, INT_MAX, ofproto_unixctl_trace, NULL);
d13ee228
BP
685 unixctl_command_register(
686 "ofproto/trace-packet-out",
0f2f05bb
YHW
687 "[-consistent] {[dp_name] odp_flow | bridge br_flow} [OPTIONS...] "
688 "[-generate|packet] actions",
689 2, INT_MAX, ofproto_unixctl_trace_actions, NULL);
d13ee228 690}