summaryrefslogtreecommitdiff
path: root/ofproto
diff options
context:
space:
mode:
authorBen Pfaff <blp@ovn.org>2017-01-12 08:15:02 -0800
committerBen Pfaff <blp@ovn.org>2017-01-12 08:58:20 -0800
commit2d9b49dd92bfbd040da5ad60b84d0629a355b099 (patch)
tree39dd0d57ec7745dd4236d9e1f8d1f3c7d51137bd /ofproto
parent9fff138ec3a6dbe75073d16cba7fbe86ac273c36 (diff)
downloadopenvswitch-2d9b49dd92bfbd040da5ad60b84d0629a355b099.tar.gz
ofproto-dpif: Make ofproto/trace output easier to read.
"ovs-appctl ofproto/trace" is invaluable for debugging, but as the users of Open vSwitch have evolved it has failed to keep up with the times. It's pretty easy to design OpenFlow tables and pipelines that resubmit dozens of times. Each resubmit causes an additional tab of indentation, so the output wraps around, sometimes again and again, and makes the output close to unreadable. ovn-trace pioneered better formatting for tracing in OVN logical datapaths, mostly by not increasing indentation for tail recursion, which in practice gets rid of almost all indentation. This commit experiments with redoing ofproto/trace the same way. Try looking at, for example, the testsuite output for test 2282 "ovn -- 3 HVs, 3 LRs connected via LS, source IP based routes". Without this commit, it indents 61 levels (488 spaces!). With this commit, it indents 1 level (4 spaces) and it's possible to actually understand what's going on almost at a glance. To see this for yourself, try the following command either with or without this commit (but be sure to keep the change to ovn.at that adds an ofproto/trace to the test): make check TESTSUITEFLAGS='-d 2282' && less tests/testsuite.dir/2282/testsuite.log Signed-off-by: Ben Pfaff <blp@ovn.org> Acked-by: Lance Richardson <lrichard@redhat.com> Acked-by: Justin Pettit <jpettit@ovn.org>
Diffstat (limited to 'ofproto')
-rw-r--r--ofproto/ofproto-dpif-trace.c291
-rw-r--r--ofproto/ofproto-dpif-trace.h44
-rw-r--r--ofproto/ofproto-dpif-xlate.c839
-rw-r--r--ofproto/ofproto-dpif-xlate.h28
-rw-r--r--ofproto/ofproto-dpif.c6
-rw-r--r--ofproto/ofproto-dpif.h2
6 files changed, 720 insertions, 490 deletions
diff --git a/ofproto/ofproto-dpif-trace.c b/ofproto/ofproto-dpif-trace.c
index 52c175875..b01a13182 100644
--- a/ofproto/ofproto-dpif-trace.c
+++ b/ofproto/ofproto-dpif-trace.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016 Nicira, Inc.
+ * Copyright (c) 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017 Nicira, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -23,165 +23,108 @@
#include "openvswitch/ofp-parse.h"
#include "unixctl.h"
-struct trace_ctx {
- struct xlate_out xout;
- struct xlate_in xin;
- const struct flow *key;
- struct flow flow;
- struct ds *result;
- struct flow_wildcards wc;
- struct ofpbuf odp_actions;
-};
-
static void ofproto_trace(struct ofproto_dpif *, struct flow *,
const struct dp_packet *packet,
const struct ofpact[], size_t ofpacts_len,
struct ds *);
-
-static void
-trace_format_rule(struct ofproto *ofproto, struct ds *result, int level,
- const struct rule_dpif *rule)
+static void oftrace_node_destroy(struct oftrace_node *);
+
+/* Creates a new oftrace_node, populates it with the given 'type' and a copy of
+ * 'text', and appends it to list 'super'. The caller retains ownership of
+ * 'text'. */
+struct oftrace_node *
+oftrace_report(struct ovs_list *super, enum oftrace_node_type type,
+ const char *text)
{
- const struct rule_actions *actions;
- ovs_be64 cookie;
-
- ds_put_char_multiple(result, '\t', level);
- if (!rule) {
- ds_put_cstr(result, "No match\n");
- return;
- }
-
- ovs_mutex_lock(&rule->up.mutex);
- cookie = rule->up.flow_cookie;
- ovs_mutex_unlock(&rule->up.mutex);
-
- ds_put_format(result, "Rule: table=%"PRIu8" cookie=%#"PRIx64" ",
- rule ? rule->up.table_id : 0, ntohll(cookie));
- cls_rule_format(&rule->up.cr, ofproto_get_tun_tab(ofproto), result);
- ds_put_char(result, '\n');
+ struct oftrace_node *node = xmalloc(sizeof *node);
+ ovs_list_push_back(super, &node->node);
+ node->type = type;
+ node->text = xstrdup(text);
+ ovs_list_init(&node->subs);
- actions = rule_get_actions(&rule->up);
-
- ds_put_char_multiple(result, '\t', level);
- ds_put_cstr(result, "OpenFlow actions=");
- ofpacts_format(actions->ofpacts, actions->ofpacts_len, result);
- ds_put_char(result, '\n');
+ return node;
}
-static void
-trace_format_flow(struct ds *result, int level, const char *title,
- struct trace_ctx *trace)
+static bool
+oftrace_node_type_is_terminal(enum oftrace_node_type type)
{
- ds_put_char_multiple(result, '\t', level);
- ds_put_format(result, "%s: ", title);
- /* Do not report unchanged flows for resubmits. */
- if ((level > 0 && flow_equal(&trace->xin.flow, &trace->flow))
- || (level == 0 && flow_equal(&trace->xin.flow, trace->key))) {
- ds_put_cstr(result, "unchanged");
- } else {
- flow_format(result, &trace->xin.flow);
- trace->flow = trace->xin.flow;
+ switch (type) {
+ case OFT_ACTION:
+ case OFT_DETAIL:
+ case OFT_WARN:
+ case OFT_ERROR:
+ return true;
+
+ case OFT_BRIDGE:
+ case OFT_TABLE:
+ case OFT_THAW:
+ return false;
}
- ds_put_char(result, '\n');
+
+ OVS_NOT_REACHED();
}
static void
-trace_format_regs(struct ds *result, int level, const char *title,
- struct trace_ctx *trace)
+oftrace_node_list_destroy(struct ovs_list *nodes)
{
- size_t i;
-
- ds_put_char_multiple(result, '\t', level);
- ds_put_format(result, "%s:", title);
- for (i = 0; i < FLOW_N_REGS; i++) {
- ds_put_format(result, " reg%"PRIuSIZE"=0x%"PRIx32, i, trace->flow.regs[i]);
+ if (nodes) {
+ struct oftrace_node *node, *next;
+ LIST_FOR_EACH_SAFE (node, next, node, nodes) {
+ ovs_list_remove(&node->node);
+ oftrace_node_destroy(node);
+ }
}
- ds_put_char(result, '\n');
}
static void
-trace_format_odp(struct ds *result, int level, const char *title,
- struct trace_ctx *trace)
+oftrace_node_destroy(struct oftrace_node *node)
{
- struct ofpbuf *odp_actions = &trace->odp_actions;
-
- ds_put_char_multiple(result, '\t', level);
- ds_put_format(result, "%s: ", title);
- format_odp_actions(result, odp_actions->data, odp_actions->size);
- ds_put_char(result, '\n');
+ if (node) {
+ oftrace_node_list_destroy(&node->subs);
+ free(node->text);
+ free(node);
+ }
}
static void
-trace_format_megaflow(struct ds *result, int level, const char *title,
- struct trace_ctx *trace)
+oftrace_node_print_details(struct ds *output,
+ const struct ovs_list *nodes, int level)
{
- struct match match;
-
- ds_put_char_multiple(result, '\t', level);
- ds_put_format(result, "%s: ", title);
- match_init(&match, trace->key, &trace->wc);
- match_format(&match, result, OFP_DEFAULT_PRIORITY);
- ds_put_char(result, '\n');
-}
-
-static void trace_report(struct xlate_in *, int indentation,
- const char *format, ...)
- OVS_PRINTF_FORMAT(3, 4);
-static void trace_report_valist(struct xlate_in *, int indentation,
- const char *format, va_list args)
- OVS_PRINTF_FORMAT(3, 0);
+ const struct oftrace_node *sub;
+ LIST_FOR_EACH (sub, node, nodes) {
+ if (sub->type == OFT_BRIDGE) {
+ ds_put_char(output, '\n');
+ }
-static void
-trace_resubmit(struct xlate_in *xin, struct rule_dpif *rule, int indentation)
-{
- struct trace_ctx *trace = CONTAINER_OF(xin, struct trace_ctx, xin);
- struct ds *result = trace->result;
-
- if (!indentation) {
- if (rule == xin->ofproto->miss_rule) {
- trace_report(xin, indentation,
- "No match, flow generates \"packet in\"s.");
- } else if (rule == xin->ofproto->no_packet_in_rule) {
- trace_report(xin, indentation, "No match, packets dropped because "
- "OFPPC_NO_PACKET_IN is set on in_port.");
- } else if (rule == xin->ofproto->drop_frags_rule) {
- trace_report(xin, indentation,
- "Packets dropped because they are IP fragments and "
- "the fragment handling mode is \"drop\".");
+ bool more = (sub->node.next != nodes
+ || oftrace_node_type_is_terminal(sub->type));
+
+ ds_put_char_multiple(output, ' ', (level + more) * 4);
+ switch (sub->type) {
+ case OFT_DETAIL:
+ ds_put_format(output, " -> %s\n", sub->text);
+ break;
+ case OFT_WARN:
+ ds_put_format(output, " >> %s\n", sub->text);
+ break;
+ case OFT_ERROR:
+ ds_put_format(output, " >>>> %s <<<<\n", sub->text);
+ break;
+ case OFT_BRIDGE:
+ ds_put_format(output, "%s\n", sub->text);
+ ds_put_char_multiple(output, ' ', (level + more) * 4);
+ ds_put_char_multiple(output, '-', strlen(sub->text));
+ ds_put_char(output, '\n');
+ break;
+ case OFT_TABLE:
+ case OFT_THAW:
+ case OFT_ACTION:
+ ds_put_format(output, "%s\n", sub->text);
+ break;
}
- }
- ds_put_char(result, '\n');
- if (indentation) {
- trace_format_flow(result, indentation, "Resubmitted flow", trace);
- trace_format_regs(result, indentation, "Resubmitted regs", trace);
- trace_format_odp(result, indentation, "Resubmitted odp", trace);
- trace_format_megaflow(result, indentation, "Resubmitted megaflow",
- trace);
+ oftrace_node_print_details(output, &sub->subs, level + more + more);
}
- trace_format_rule(&xin->ofproto->up, result, indentation, rule);
-}
-
-static void
-trace_report_valist(struct xlate_in *xin, int indentation,
- const char *format, va_list args)
-{
- struct trace_ctx *trace = CONTAINER_OF(xin, struct trace_ctx, xin);
- struct ds *result = trace->result;
-
- ds_put_char_multiple(result, '\t', indentation);
- ds_put_format_valist(result, format, args);
- ds_put_char(result, '\n');
-}
-
-static void
-trace_report(struct xlate_in *xin, int indentation, const char *format, ...)
-{
- va_list args;
-
- va_start(args, format);
- trace_report_valist(xin, indentation, format, args);
- va_end(args);
}
/* Parses the 'argc' elements of 'argv', ignoring argv[0]. The following
@@ -466,7 +409,7 @@ exit:
}
/* Implements a "trace" through 'ofproto''s flow table, appending a textual
- * description of the results to 'ds'.
+ * description of the results to 'output'.
*
* The trace follows a packet with the specified 'flow' through the flow
* table. 'packet' may be nonnull to trace an actual packet, with consequent
@@ -478,61 +421,75 @@ static void
ofproto_trace(struct ofproto_dpif *ofproto, struct flow *flow,
const struct dp_packet *packet,
const struct ofpact ofpacts[], size_t ofpacts_len,
- struct ds *ds)
+ struct ds *output)
{
- struct trace_ctx trace;
- enum xlate_error error;
-
- ds_put_format(ds, "Bridge: %s\n", ofproto->up.name);
- ds_put_cstr(ds, "Flow: ");
- flow_format(ds, flow);
- ds_put_char(ds, '\n');
-
- ofpbuf_init(&trace.odp_actions, 0);
+ struct ofpbuf odp_actions;
+ ofpbuf_init(&odp_actions, 0);
- trace.result = ds;
- trace.key = flow; /* Original flow key, used for megaflow. */
- trace.flow = *flow; /* May be modified by actions. */
- xlate_in_init(&trace.xin, ofproto,
+ struct xlate_in xin;
+ struct flow_wildcards wc;
+ struct ovs_list trace = OVS_LIST_INITIALIZER(&trace);
+ xlate_in_init(&xin, ofproto,
ofproto_dpif_get_tables_version(ofproto), flow,
flow->in_port.ofp_port, NULL, ntohs(flow->tcp_flags),
- packet, &trace.wc, &trace.odp_actions);
- trace.xin.ofpacts = ofpacts;
- trace.xin.ofpacts_len = ofpacts_len;
- trace.xin.resubmit_hook = trace_resubmit;
- trace.xin.report_hook = trace_report_valist;
+ packet, &wc, &odp_actions);
+ xin.ofpacts = ofpacts;
+ xin.ofpacts_len = ofpacts_len;
+ xin.trace = &trace;
+
+ /* Copy initial flow out of xin.flow. It differs from '*flow' because
+ * xlate_in_init() initializes actset_output to OFPP_UNSET. */
+ struct flow initial_flow = xin.flow;
+ ds_put_cstr(output, "Flow: ");
+ flow_format(output, &initial_flow);
+ ds_put_char(output, '\n');
+
+ struct xlate_out xout;
+ enum xlate_error error = xlate_actions(&xin, &xout);
+
+ oftrace_node_print_details(output, &trace, 0);
+
+ ds_put_cstr(output, "\nFinal flow: ");
+ if (flow_equal(&initial_flow, &xin.flow)) {
+ ds_put_cstr(output, "unchanged");
+ } else {
+ flow_format(output, &xin.flow);
+ }
+ ds_put_char(output, '\n');
- error = xlate_actions(&trace.xin, &trace.xout);
- ds_put_char(ds, '\n');
- trace.xin.flow.actset_output = 0;
- trace_format_flow(ds, 0, "Final flow", &trace);
- trace_format_megaflow(ds, 0, "Megaflow", &trace);
+ ds_put_cstr(output, "Megaflow: ");
+ struct match match;
+ match_init(&match, flow, &wc);
+ match_format(&match, output, OFP_DEFAULT_PRIORITY);
+ ds_put_char(output, '\n');
- ds_put_cstr(ds, "Datapath actions: ");
- format_odp_actions(ds, trace.odp_actions.data, trace.odp_actions.size);
+ ds_put_cstr(output, "Datapath actions: ");
+ format_odp_actions(output, odp_actions.data, odp_actions.size);
if (error != XLATE_OK) {
- ds_put_format(ds, "\nTranslation failed (%s), packet is dropped.\n",
+ ds_put_format(output,
+ "\nTranslation failed (%s), packet is dropped.\n",
xlate_strerror(error));
- } else if (trace.xout.slow) {
+ } else if (xout.slow) {
enum slow_path_reason slow;
- ds_put_cstr(ds, "\nThis flow is handled by the userspace "
+ ds_put_cstr(output, "\nThis flow is handled by the userspace "
"slow path because it:");
- slow = trace.xout.slow;
+ slow = xout.slow;
while (slow) {
enum slow_path_reason bit = rightmost_1bit(slow);
- ds_put_format(ds, "\n\t- %s.",
+ ds_put_format(output, "\n\t- %s.",
slow_path_reason_to_explanation(bit));
slow &= ~bit;
}
}
- xlate_out_uninit(&trace.xout);
- ofpbuf_uninit(&trace.odp_actions);
+ xlate_out_uninit(&xout);
+ ofpbuf_uninit(&odp_actions);
+ oftrace_node_list_destroy(&trace);
}
void
diff --git a/ofproto/ofproto-dpif-trace.h b/ofproto/ofproto-dpif-trace.h
index 06d63f894..e3d3b393c 100644
--- a/ofproto/ofproto-dpif-trace.h
+++ b/ofproto/ofproto-dpif-trace.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016 Nicira, Inc.
+/* Copyright (c) 2016, 2017 Nicira, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -15,6 +15,48 @@
#ifndef OFPROTO_DPIF_TRACE_H
#define OFPROTO_DPIF_TRACE_H 1
+/* Tracing
+ * =======
+ *
+ * The Open vSwitch software datapath based switch implementation supports
+ * "tracing". A trace describes what happens to a particular kind of packet as
+ * it passes through the switch, including information on each table, flow, and
+ * action that would apply to the packet. The trace is internally represented
+ * as a tree that reflects control flow; for example, an OpenFlow switch
+ * top-level node (of type OFT_BRIDGE) has a child node for each table visited
+ * by a packet (of type OFT_TABLE), and each table node has a child node for
+ * each action (OFT_ACTION) executed in the table.
+ */
+
+#include "openvswitch/compiler.h"
+#include "openvswitch/list.h"
+
+/* Type of a node within a trace. */
+enum oftrace_node_type {
+ /* Nodes that may have children (nonterminal nodes). */
+ OFT_BRIDGE, /* Packet travel through an OpenFlow switch. */
+ OFT_TABLE, /* Packet travel through a flow table. */
+ OFT_THAW, /* Thawing a frozen state. */
+
+ /* Nodes that never have children (terminal nodes). */
+ OFT_ACTION, /* An action. */
+ OFT_DETAIL, /* Some detail of an action. */
+ OFT_WARN, /* A worrisome situation. */
+ OFT_ERROR, /* An erroneous situation, worth logging. */
+};
+
+/* A node within a trace. */
+struct oftrace_node {
+ struct ovs_list node; /* In parent. */
+ struct ovs_list subs; /* List of "struct oftrace_node" children. */
+
+ enum oftrace_node_type type;
+ char *text;
+};
+
void ofproto_dpif_trace_init(void);
+struct oftrace_node *oftrace_report(struct ovs_list *, enum oftrace_node_type,
+ const char *text);
+
#endif /* ofproto-dpif-trace.h */
diff --git a/ofproto/ofproto-dpif-xlate.c b/ofproto/ofproto-dpif-xlate.c
index a35214b4f..e02771edb 100644
--- a/ofproto/ofproto-dpif-xlate.c
+++ b/ofproto/ofproto-dpif-xlate.c
@@ -47,6 +47,7 @@
#include "ofproto/ofproto-dpif-mirror.h"
#include "ofproto/ofproto-dpif-monitor.h"
#include "ofproto/ofproto-dpif-sflow.h"
+#include "ofproto/ofproto-dpif-trace.h"
#include "ofproto/ofproto-dpif-xlate-cache.h"
#include "ofproto/ofproto-dpif.h"
#include "ofproto/ofproto-provider.h"
@@ -204,10 +205,7 @@ struct xlate_ctx {
/* Statistics maintained by xlate_table_action().
*
- * 'indentation' is the nesting level for resubmits. It is used to indent
- * the output of resubmit_hook (e.g. for the "ofproto/trace" feature).
- *
- * The other statistics limit the amount of work that a single flow
+ * These statistics limit the amount of work that a single flow
* translation can perform. The goal of the first of these, 'depth', is
* primarily to prevent translation from performing an infinite amount of
* work. It counts the current depth of nested "resubmit"s (and a few
@@ -225,7 +223,6 @@ struct xlate_ctx {
* translation can perform. Translation aborts when 'resubmits' exceeds
* MAX_RESUBMITS (which is much larger than MAX_DEPTH).
*/
- int indentation; /* Indentation level for resubmit_hook. */
int depth; /* Current resubmit nesting depth. */
int resubmits; /* Total number of resubmits. */
bool in_group; /* Currently translating ofgroup, if true. */
@@ -484,12 +481,11 @@ static bool may_receive(const struct xport *, struct xlate_ctx *);
static void do_xlate_actions(const struct ofpact *, size_t ofpacts_len,
struct xlate_ctx *);
static void xlate_normal(struct xlate_ctx *);
-static inline void xlate_report(struct xlate_ctx *, const char *, ...)
- OVS_PRINTF_FORMAT(2, 3);
static void xlate_table_action(struct xlate_ctx *, ofp_port_t in_port,
uint8_t table_id, bool may_packet_in,
bool honor_table_miss);
-static bool input_vid_is_valid(uint16_t vid, struct xbundle *, bool warn);
+static bool input_vid_is_valid(const struct xlate_ctx *,
+ uint16_t vid, struct xbundle *);
static uint16_t input_vid_to_vlan(const struct xbundle *, uint16_t vid);
static void output_normal(struct xlate_ctx *, const struct xbundle *,
uint16_t vlan);
@@ -552,48 +548,205 @@ static void xlate_xbundle_copy(struct xbridge *, struct xbundle *);
static void xlate_xport_copy(struct xbridge *, struct xbundle *,
struct xport *);
static void xlate_xcfg_free(struct xlate_cfg *);
-
-static inline void
-xlate_report(struct xlate_ctx *ctx, const char *format, ...)
+
+/* Tracing helpers. */
+
+/* If tracing is enabled in 'ctx', creates a new trace node and appends it to
+ * the list of nodes maintained in ctx->xin. The new node has type 'type' and
+ * its text is created from 'format' by treating it as a printf format string.
+ * Returns the list of nodes embedded within the new trace node; ordinarily,
+ * the calleer can ignore this, but it is useful if the caller needs to nest
+ * more trace nodes within the new node.
+ *
+ * If tracing is not enabled, does nothing and returns NULL. */
+static struct ovs_list * OVS_PRINTF_FORMAT(3, 4)
+xlate_report(const struct xlate_ctx *ctx, enum oftrace_node_type type,
+ const char *format, ...)
{
- if (OVS_UNLIKELY(ctx->xin->report_hook)) {
+ struct ovs_list *subtrace = NULL;
+ if (OVS_UNLIKELY(ctx->xin->trace)) {
va_list args;
-
va_start(args, format);
- ctx->xin->report_hook(ctx->xin, ctx->indentation, format, args);
+ char *text = xvasprintf(format, args);
+ subtrace = &oftrace_report(ctx->xin->trace, type, text)->subs;
va_end(args);
+ free(text);
}
+ return subtrace;
}
-static struct vlog_rate_limit error_report_rl = VLOG_RATE_LIMIT_INIT(1, 5);
+/* This is like xlate_report() for errors that are serious enough that we
+ * should log them even if we are not tracing. */
+static void OVS_PRINTF_FORMAT(2, 3)
+xlate_report_error(const struct xlate_ctx *ctx, const char *format, ...)
+{
+ static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
+ if (!OVS_UNLIKELY(ctx->xin->trace)
+ && (!ctx->xin->packet || VLOG_DROP_WARN(&rl))) {
+ return;
+ }
+
+ struct ds s = DS_EMPTY_INITIALIZER;
+ va_list args;
+ va_start(args, format);
+ ds_put_format_valist(&s, format, args);
+ va_end(args);
+
+ if (ctx->xin->trace) {
+ oftrace_report(ctx->xin->trace, OFT_ERROR, ds_cstr(&s));
+ } else {
+ ds_put_cstr(&s, " while processing ");
+ flow_format(&s, &ctx->base_flow);
+ ds_put_format(&s, " on bridge %s", ctx->xbridge->name);
+ VLOG_WARN("%s", ds_cstr(&s));
+ }
+ ds_destroy(&s);
+}
+
+/* This is like xlate_report() for messages that should be logged at debug
+ * level (even if we are not tracing) because they can be valuable for
+ * debugging. */
+static void OVS_PRINTF_FORMAT(3, 4)
+xlate_report_debug(const struct xlate_ctx *ctx, enum oftrace_node_type type,
+ const char *format, ...)
+{
+ static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(30, 300);
+ if (!OVS_UNLIKELY(ctx->xin->trace)
+ && (!ctx->xin->packet || VLOG_DROP_DBG(&rl))) {
+ return;
+ }
+
+ struct ds s = DS_EMPTY_INITIALIZER;
+ va_list args;
+ va_start(args, format);
+ ds_put_format_valist(&s, format, args);
+ va_end(args);
-#define XLATE_REPORT_ERROR(CTX, ...) \
- do { \
- if (OVS_UNLIKELY((CTX)->xin->report_hook)) { \
- xlate_report(CTX, __VA_ARGS__); \
- } else { \
- struct ds ds = DS_EMPTY_INITIALIZER; \
- \
- ds_put_format(&ds, __VA_ARGS__); \
- ds_put_cstr(&ds, ": "); \
- flow_format(&ds, &(CTX)->base_flow); \
- VLOG_ERR_RL(&error_report_rl, "%s", ds_cstr(&ds)); \
- ds_destroy(&ds); \
- } \
- } while (0)
+ if (ctx->xin->trace) {
+ oftrace_report(ctx->xin->trace, type, ds_cstr(&s));
+ } else {
+ VLOG_DBG("bridge %s: %s", ctx->xbridge->name, ds_cstr(&s));
+ }
+ ds_destroy(&s);
+}
-static inline void
-xlate_report_actions(struct xlate_ctx *ctx, const char *title,
+/* If tracing is enabled in 'ctx', appends a node of the given 'type' to the
+ * trace, whose text is 'title' followed by a formatted version of the
+ * 'ofpacts_len' OpenFlow actions in 'ofpacts'.
+ *
+ * If tracing is not enabled, does nothing. */
+static void
+xlate_report_actions(const struct xlate_ctx *ctx, enum oftrace_node_type type,
+ const char *title,
const struct ofpact *ofpacts, size_t ofpacts_len)
{
- if (OVS_UNLIKELY(ctx->xin->report_hook)) {
+ if (OVS_UNLIKELY(ctx->xin->trace)) {
struct ds s = DS_EMPTY_INITIALIZER;
+ ds_put_format(&s, "%s: ", title);
ofpacts_format(ofpacts, ofpacts_len, &s);
- xlate_report(ctx, "%s: %s", title, ds_cstr(&s));
+ oftrace_report(ctx->xin->trace, type, ds_cstr(&s));
ds_destroy(&s);
}
}
+/* If tracing is enabled in 'ctx', appends a node of type OFT_DETAIL to the
+ * trace, whose the message is a formatted version of the OpenFlow action set.
+ * 'verb' should be "was" or "is", depending on whether the action set reported
+ * is the new action set or the old one.
+ *
+ * If tracing is not enabled, does nothing. */
+static void
+xlate_report_action_set(const struct xlate_ctx *ctx, const char *verb)
+{
+ if (OVS_UNLIKELY(ctx->xin->trace)) {
+ struct ofpbuf action_list;
+ ofpbuf_init(&action_list, 0);
+ ofpacts_execute_action_set(&action_list, &ctx->action_set);
+ if (action_list.size) {
+ struct ds s = DS_EMPTY_INITIALIZER;
+ ofpacts_format(action_list.data, action_list.size, &s);
+ xlate_report(ctx, OFT_DETAIL, "action set %s: %s",
+ verb, ds_cstr(&s));
+ ds_destroy(&s);
+ } else {
+ xlate_report(ctx, OFT_DETAIL, "action set %s empty", verb);
+ }
+ ofpbuf_uninit(&action_list);
+ }
+}
+
+
+/* If tracing is enabled in 'ctx', appends a node representing 'rule' (in
+ * OpenFlow table 'table_id') to the trace and makes this node the parent for
+ * future trace nodes. The caller should save ctx->xin->trace before calling
+ * this function, then after tracing all of the activities under the table,
+ * restore its previous value.
+ *
+ * If tracing is not enabled, does nothing. */
+static void
+xlate_report_table(const struct xlate_ctx *ctx, struct rule_dpif *rule,
+ uint8_t table_id)
+{
+ if (OVS_LIKELY(!ctx->xin->trace)) {
+ return;
+ }
+
+ struct ds s = DS_EMPTY_INITIALIZER;
+ ds_put_format(&s, "%2d. ", table_id);
+ if (rule == ctx->xin->ofproto->miss_rule) {
+ ds_put_cstr(&s, "No match, and a \"packet-in\" is called for.");
+ } else if (rule == ctx->xin->ofproto->no_packet_in_rule) {
+ ds_put_cstr(&s, "No match.");
+ } else if (rule == ctx->xin->ofproto->drop_frags_rule) {
+ ds_put_cstr(&s, "Packets are IP fragments and "
+ "the fragment handling mode is \"drop\".");
+ } else {
+ minimatch_format(&rule->up.cr.match,
+ ofproto_get_tun_tab(&ctx->xin->ofproto->up),
+ &s, OFP_DEFAULT_PRIORITY);
+ if (ds_last(&s) != ' ') {
+ ds_put_cstr(&s, ", ");
+ }
+ ds_put_format(&s, "priority %d", rule->up.cr.priority);
+ if (rule->up.flow_cookie) {
+ ds_put_format(&s, ", cookie %#"PRIx64,
+ ntohll(rule->up.flow_cookie));
+ }
+ }
+ ctx->xin->trace = &oftrace_report(ctx->xin->trace, OFT_TABLE,
+ ds_cstr(&s))->subs;
+ ds_destroy(&s);
+}
+
+/* If tracing is enabled in 'ctx', adds an OFT_DETAIL trace node to 'ctx'
+ * reporting the value of subfield 'sf'.
+ *
+ * If tracing is not enabled, does nothing. */
+static void
+xlate_report_subfield(const struct xlate_ctx *ctx,
+ const struct mf_subfield *sf)
+{
+ if (OVS_UNLIKELY(ctx->xin->trace)) {
+ struct ds s = DS_EMPTY_INITIALIZER;
+ mf_format_subfield(sf, &s);
+ ds_put_cstr(&s, " is now ");
+
+ if (sf->ofs == 0 && sf->n_bits >= sf->field->n_bits) {
+ union mf_value value;
+ mf_get_value(sf->field, &ctx->xin->flow, &value);
+ mf_format(sf->field, &value, NULL, &s);
+ } else {
+ union mf_subvalue cst;
+ mf_read_subfield(sf, &ctx->xin->flow, &cst);
+ ds_put_hex(&s, &cst, sizeof cst);
+ }
+
+ xlate_report(ctx, OFT_DETAIL, "%s", ds_cstr(&s));
+
+ ds_destroy(&s);
+ }
+}
+
static void
xlate_xbridge_init(struct xlate_cfg *xcfg, struct xbridge *xbridge)
{
@@ -1466,10 +1619,8 @@ bucket_is_alive(const struct xlate_ctx *ctx,
struct ofputil_bucket *bucket, int depth)
{
if (depth >= MAX_LIVENESS_RECURSION) {
- static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 1);
-
- VLOG_WARN_RL(&rl, "bucket chaining exceeded %d links",
- MAX_LIVENESS_RECURSION);
+ xlate_report_error(ctx, "bucket chaining exceeded %d links",
+ MAX_LIVENESS_RECURSION);
return false;
}
@@ -1555,8 +1706,8 @@ xbundle_mirror_dst(const struct xbridge *xbridge, struct xbundle *xbundle)
}
static struct xbundle *
-lookup_input_bundle(const struct xbridge *xbridge, ofp_port_t in_port,
- bool warn, struct xport **in_xportp)
+lookup_input_bundle__(const struct xbridge *xbridge,
+ ofp_port_t in_port, struct xport **in_xportp)
{
struct xport *xport;
@@ -1575,27 +1726,33 @@ lookup_input_bundle(const struct xbridge *xbridge, ofp_port_t in_port,
if (in_port == OFPP_CONTROLLER || in_port == OFPP_NONE) {
return &ofpp_none_bundle;
}
+ return NULL;
+}
- /* Odd. A few possible reasons here:
- *
- * - We deleted a port but there are still a few packets queued up
- * from it.
- *
- * - Someone externally added a port (e.g. "ovs-dpctl add-if") that
- * we don't know about.
- *
- * - The ofproto client didn't configure the port as part of a bundle.
- * This is particularly likely to happen if a packet was received on the
- * port after it was created, but before the client had a chance to
- * configure its bundle.
- */
- if (warn) {
- static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
-
- VLOG_WARN_RL(&rl, "bridge %s: received packet on unknown "
- "port %"PRIu16, xbridge->name, in_port);
+static struct xbundle *
+lookup_input_bundle(const struct xlate_ctx *ctx,
+ ofp_port_t in_port, struct xport **in_xportp)
+{
+ struct xbundle *xbundle = lookup_input_bundle__(ctx->xbridge,
+ in_port, in_xportp);
+ if (!xbundle) {
+ /* Odd. A few possible reasons here:
+ *
+ * - We deleted a port but there are still a few packets queued up
+ * from it.
+ *
+ * - Someone externally added a port (e.g. "ovs-dpctl add-if") that
+ * we don't know about.
+ *
+ * - The ofproto client didn't configure the port as part of a bundle.
+ * This is particularly likely to happen if a packet was received on
+ * the port after it was created, but before the client had a chance
+ * to configure its bundle.
+ */
+ xlate_report_error(ctx, "received packet on unknown port %"PRIu16,
+ in_port);
}
- return NULL;
+ return xbundle;
}
/* Mirrors the packet represented by 'ctx' to appropriate mirror destinations,
@@ -1607,9 +1764,8 @@ mirror_packet(struct xlate_ctx *ctx, struct xbundle *xbundle,
{
/* Figure out what VLAN the packet is in (because mirrors can select
* packets on basis of VLAN). */
- bool warn = ctx->xin->packet != NULL;
uint16_t vid = vlan_tci_to_vid(ctx->xin->flow.vlan_tci);
- if (!input_vid_is_valid(vid, xbundle, warn)) {
+ if (!input_vid_is_valid(ctx, vid, xbundle)) {
return;
}
uint16_t vlan = input_vid_to_vlan(xbundle, vid);
@@ -1698,9 +1854,8 @@ static void
mirror_ingress_packet(struct xlate_ctx *ctx)
{
if (mbridge_has_mirrors(ctx->xbridge->mbridge)) {
- bool warn = ctx->xin->packet != NULL;
struct xbundle *xbundle = lookup_input_bundle(
- ctx->xbridge, ctx->xin->flow.in_port.ofp_port, warn, NULL);
+ ctx, ctx->xin->flow.in_port.ofp_port, NULL);
if (xbundle) {
mirror_packet(ctx, xbundle,
xbundle_mirror_src(ctx->xbridge, xbundle));
@@ -1735,14 +1890,14 @@ input_vid_to_vlan(const struct xbundle *in_xbundle, uint16_t vid)
}
/* Checks whether a packet with the given 'vid' may ingress on 'in_xbundle'.
- * If so, returns true. Otherwise, returns false and, if 'warn' is true, logs
- * a warning.
+ * If so, returns true. Otherwise, returns false.
*
* 'vid' should be the VID obtained from the 802.1Q header that was received as
* part of a packet (specify 0 if there was no 802.1Q header), in the range
* 0...4095. */
static bool
-input_vid_is_valid(uint16_t vid, struct xbundle *in_xbundle, bool warn)
+input_vid_is_valid(const struct xlate_ctx *ctx,
+ uint16_t vid, struct xbundle *in_xbundle)
{
/* Allow any VID on the OFPP_NONE port. */
if (in_xbundle == &ofpp_none_bundle) {
@@ -1752,13 +1907,10 @@ input_vid_is_valid(uint16_t vid, struct xbundle *in_xbundle, bool warn)
switch (in_xbundle->vlan_mode) {
case PORT_VLAN_ACCESS:
if (vid) {
- if (warn) {
- static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
- VLOG_WARN_RL(&rl, "dropping VLAN %"PRIu16" tagged "
- "packet received on port %s configured as VLAN "
- "%"PRIu16" access port", vid, in_xbundle->name,
- in_xbundle->vlan);
- }
+ xlate_report_error(ctx, "dropping VLAN %"PRIu16" tagged "
+ "packet received on port %s configured as VLAN "
+ "%"PRIu16" access port", vid, in_xbundle->name,
+ in_xbundle->vlan);
return false;
}
return true;
@@ -1772,12 +1924,10 @@ input_vid_is_valid(uint16_t vid, struct xbundle *in_xbundle, bool warn)
/* Fall through. */
case PORT_VLAN_TRUNK:
if (!xbundle_includes_vlan(in_xbundle, vid)) {
- if (warn) {
- static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
- VLOG_WARN_RL(&rl, "dropping VLAN %"PRIu16" packet "
- "received on port %s not configured for trunking "
- "VLAN %"PRIu16, vid, in_xbundle->name, vid);
- }
+ xlate_report_error(ctx, "dropping VLAN %"PRIu16" packet "
+ "received on port %s not configured for "
+ "trunking VLAN %"PRIu16,
+ vid, in_xbundle->name, vid);
return false;
}
return true;
@@ -1947,7 +2097,8 @@ is_admissible(struct xlate_ctx *ctx, struct xport *in_port,
/* Drop frames for reserved multicast addresses
* only if forward_bpdu option is absent. */
if (!xbridge->forward_bpdu && eth_addr_is_reserved(flow->dl_dst)) {
- xlate_report(ctx, "packet has reserved destination MAC, dropping");
+ xlate_report(ctx, OFT_DETAIL,
+ "packet has reserved destination MAC, dropping");
return false;
}
@@ -1960,7 +2111,8 @@ is_admissible(struct xlate_ctx *ctx, struct xport *in_port,
break;
case BV_DROP:
- xlate_report(ctx, "bonding refused admissibility, dropping");
+ xlate_report(ctx, OFT_DETAIL,
+ "bonding refused admissibility, dropping");
return false;
case BV_DROP_IF_MOVED:
@@ -1971,7 +2123,8 @@ is_admissible(struct xlate_ctx *ctx, struct xport *in_port,
&& (!is_gratuitous_arp(flow, ctx->wc)
|| mac_entry_is_grat_arp_locked(mac))) {
ovs_rwlock_unlock(&xbridge->ml->rwlock);
- xlate_report(ctx, "SLB bond thinks this packet looped back, "
+ xlate_report(ctx, OFT_DETAIL,
+ "SLB bond thinks this packet looped back, "
"dropping");
return false;
}
@@ -1983,39 +2136,41 @@ is_admissible(struct xlate_ctx *ctx, struct xport *in_port,
return true;
}
+static bool
+update_learning_table__(const struct xbridge *xbridge,
+ struct xbundle *in_xbundle, struct eth_addr dl_src,
+ int vlan, bool is_grat_arp)
+{
+ return (in_xbundle == &ofpp_none_bundle
+ || !mac_learning_update(xbridge->ml, dl_src, vlan,
+ is_grat_arp,
+ in_xbundle->bond != NULL,
+ in_xbundle->ofbundle));
+}
+
static void
-update_learning_table(const struct xbridge *xbridge,
+update_learning_table(const struct xlate_ctx *ctx,
struct xbundle *in_xbundle, struct eth_addr dl_src,
int vlan, bool is_grat_arp)
{
- if (in_xbundle == &ofpp_none_bundle) {
- return;
- }
-
- if (mac_learning_update(xbridge->ml, dl_src, vlan, is_grat_arp,
- in_xbundle->bond != NULL, in_xbundle->ofbundle)) {
- /* The log messages here could actually be useful in debugging,
- * so keep the rate limit relatively high. */
- static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(30, 300);
-
- VLOG_DBG_RL(&rl, "bridge %s: learned that "ETH_ADDR_FMT" is "
- "on port %s in VLAN %d",
- xbridge->name, ETH_ADDR_ARGS(dl_src), in_xbundle->name,
- vlan);
+ if (!update_learning_table__(ctx->xbridge, in_xbundle, dl_src, vlan,
+ is_grat_arp)) {
+ xlate_report_debug(ctx, OFT_DETAIL, "learned that "ETH_ADDR_FMT" is "
+ "on port %s in VLAN %d",
+ ETH_ADDR_ARGS(dl_src), in_xbundle->name, vlan);
}
}
/* Updates multicast snooping table 'ms' given that a packet matching 'flow'
* was received on 'in_xbundle' in 'vlan' and is either Report or Query. */
static void
-update_mcast_snooping_table4__(const struct xbridge *xbridge,
+update_mcast_snooping_table4__(const struct xlate_ctx *ctx,
const struct flow *flow,
struct mcast_snooping *ms, int vlan,
struct xbundle *in_xbundle,
const struct dp_packet *packet)
OVS_REQ_WRLOCK(ms->rwlock)
{
- static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(60, 30);
const struct igmp_header *igmp;
int count;
size_t offset;
@@ -2024,9 +2179,10 @@ update_mcast_snooping_table4__(const struct xbridge *xbridge,
offset = (char *) dp_packet_l4(packet) - (char *) dp_packet_data(packet);
igmp = dp_packet_at(packet, offset, IGMP_HEADER_LEN);
if (!igmp || csum(igmp, dp_packet_l4_size(packet)) != 0) {
- VLOG_DBG_RL(&rl, "bridge %s: multicast snooping received bad IGMP "
- "checksum on port %s in VLAN %d",
- xbridge->name, in_xbundle->name, vlan);
+ xlate_report_debug(ctx, OFT_DETAIL,
+ "multicast snooping received bad IGMP "
+ "checksum on port %s in VLAN %d",
+ in_xbundle->name, vlan);
return;
}
@@ -2034,47 +2190,47 @@ update_mcast_snooping_table4__(const struct xbridge *xbridge,
case IGMP_HOST_MEMBERSHIP_REPORT:
case IGMPV2_HOST_MEMBERSHIP_REPORT:
if (mcast_snooping_add_group4(ms, ip4, vlan, in_xbundle->ofbundle)) {
- VLOG_DBG_RL(&rl, "bridge %s: multicast snooping learned that "
- IP_FMT" is on port %s in VLAN %d",
- xbridge->name, IP_ARGS(ip4), in_xbundle->name, vlan);
+ xlate_report_debug(ctx, OFT_DETAIL,
+ "multicast snooping learned that "
+ IP_FMT" is on port %s in VLAN %d",
+ IP_ARGS(ip4), in_xbundle->name, vlan);
}
break;
case IGMP_HOST_LEAVE_MESSAGE:
if (mcast_snooping_leave_group4(ms, ip4, vlan, in_xbundle->ofbundle)) {
- VLOG_DBG_RL(&rl, "bridge %s: multicast snooping leaving "
- IP_FMT" is on port %s in VLAN %d",
- xbridge->name, IP_ARGS(ip4), in_xbundle->name, vlan);
+ xlate_report_debug(ctx, OFT_DETAIL, "multicast snooping leaving "
+ IP_FMT" is on port %s in VLAN %d",
+ IP_ARGS(ip4), in_xbundle->name, vlan);
}
break;
case IGMP_HOST_MEMBERSHIP_QUERY:
if (flow->nw_src && mcast_snooping_add_mrouter(ms, vlan,
- in_xbundle->ofbundle)) {
- VLOG_DBG_RL(&rl, "bridge %s: multicast snooping query from "
- IP_FMT" is on port %s in VLAN %d",
- xbridge->name, IP_ARGS(flow->nw_src),
- in_xbundle->name, vlan);
+ in_xbundle->ofbundle)) {
+ xlate_report_debug(ctx, OFT_DETAIL, "multicast snooping query "
+ "from "IP_FMT" is on port %s in VLAN %d",
+ IP_ARGS(flow->nw_src), in_xbundle->name, vlan);
}
break;
case IGMPV3_HOST_MEMBERSHIP_REPORT:
- if ((count = mcast_snooping_add_report(ms, packet, vlan,
- in_xbundle->ofbundle))) {
- VLOG_DBG_RL(&rl, "bridge %s: multicast snooping processed %d "
- "addresses on port %s in VLAN %d",
- xbridge->name, count, in_xbundle->name, vlan);
+ count = mcast_snooping_add_report(ms, packet, vlan,
+ in_xbundle->ofbundle);
+ if (count) {
+ xlate_report_debug(ctx, OFT_DETAIL, "multicast snooping processed "
+ "%d addresses on port %s in VLAN %d",
+ count, in_xbundle->name, vlan);
}
break;
}
}
static void
-update_mcast_snooping_table6__(const struct xbridge *xbridge,
+update_mcast_snooping_table6__(const struct xlate_ctx *ctx,
const struct flow *flow,
struct mcast_snooping *ms, int vlan,
struct xbundle *in_xbundle,
const struct dp_packet *packet)
OVS_REQ_WRLOCK(ms->rwlock)
{
- static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(60, 30);
const struct mld_header *mld;
int count;
size_t offset;
@@ -2086,9 +2242,9 @@ update_mcast_snooping_table6__(const struct xbridge *xbridge,
packet_csum_upperlayer6(dp_packet_l3(packet),
mld, IPPROTO_ICMPV6,
dp_packet_l4_size(packet)) != 0) {
- VLOG_DBG_RL(&rl, "bridge %s: multicast snooping received bad MLD "
- "checksum on port %s in VLAN %d",
- xbridge->name, in_xbundle->name, vlan);
+ xlate_report_debug(ctx, OFT_DETAIL, "multicast snooping received "
+ "bad MLD checksum on port %s in VLAN %d",
+ in_xbundle->name, vlan);
return;
}
@@ -2096,9 +2252,8 @@ update_mcast_snooping_table6__(const struct xbridge *xbridge,
case MLD_QUERY:
if (!ipv6_addr_equals(&flow->ipv6_src, &in6addr_any)
&& mcast_snooping_add_mrouter(ms, vlan, in_xbundle->ofbundle)) {
- VLOG_DBG_RL(&rl, "bridge %s: multicast snooping query on port %s"
- "in VLAN %d",
- xbridge->name, in_xbundle->name, vlan);
+ xlate_report_debug(ctx, OFT_DETAIL, "multicast snooping query on "
+ "port %s in VLAN %d", in_xbundle->name, vlan);
}
break;
case MLD_REPORT:
@@ -2106,9 +2261,9 @@ update_mcast_snooping_table6__(const struct xbridge *xbridge,
case MLD2_REPORT:
count = mcast_snooping_add_mld(ms, packet, vlan, in_xbundle->ofbundle);
if (count) {
- VLOG_DBG_RL(&rl, "bridge %s: multicast snooping processed %d "
- "addresses on port %s in VLAN %d",
- xbridge->name, count, in_xbundle->name, vlan);
+ xlate_report_debug(ctx, OFT_DETAIL, "multicast snooping processed "
+ "%d addresses on port %s in VLAN %d",
+ count, in_xbundle->name, vlan);
}
break;
}
@@ -2117,12 +2272,12 @@ update_mcast_snooping_table6__(const struct xbridge *xbridge,
/* Updates multicast snooping table 'ms' given that a packet matching 'flow'
* was received on 'in_xbundle' in 'vlan'. */
static void
-update_mcast_snooping_table(const struct xbridge *xbridge,
+update_mcast_snooping_table(const struct xlate_ctx *ctx,
const struct flow *flow, int vlan,
struct xbundle *in_xbundle,
const struct dp_packet *packet)
{
- struct mcast_snooping *ms = xbridge->ms;
+ struct mcast_snooping *ms = ctx->xbridge->ms;
struct xlate_cfg *xcfg;
struct xbundle *mcast_xbundle;
struct mcast_port_bundle *fport;
@@ -2145,10 +2300,10 @@ update_mcast_snooping_table(const struct xbridge *xbridge,
if (!mcast_xbundle || mcast_xbundle != in_xbundle) {
if (flow->dl_type == htons(ETH_TYPE_IP)) {
- update_mcast_snooping_table4__(xbridge, flow, ms, vlan,
+ update_mcast_snooping_table4__(ctx, flow, ms, vlan,
in_xbundle, packet);
} else {
- update_mcast_snooping_table6__(xbridge, flow, ms, vlan,
+ update_mcast_snooping_table6__(ctx, flow, ms, vlan,
in_xbundle, packet);
}
}
@@ -2171,12 +2326,14 @@ xlate_normal_mcast_send_group(struct xlate_ctx *ctx,
LIST_FOR_EACH(b, bundle_node, &grp->bundle_lru) {
mcast_xbundle = xbundle_lookup(xcfg, b->port);
if (mcast_xbundle && mcast_xbundle != in_xbundle) {
- xlate_report(ctx, "forwarding to mcast group port");
+ xlate_report(ctx, OFT_DETAIL, "forwarding to mcast group port");
output_normal(ctx, mcast_xbundle, vlan);
} else if (!mcast_xbundle) {
- xlate_report(ctx, "mcast group port is unknown, dropping");
+ xlate_report(ctx, OFT_WARN,
+ "mcast group port is unknown, dropping");
} else {
- xlate_report(ctx, "mcast group port is input port, dropping");
+ xlate_report(ctx, OFT_DETAIL,
+ "mcast group port is input port, dropping");
}
}
}
@@ -2197,14 +2354,17 @@ xlate_normal_mcast_send_mrouters(struct xlate_ctx *ctx,
mcast_xbundle = xbundle_lookup(xcfg, mrouter->port);
if (mcast_xbundle && mcast_xbundle != in_xbundle
&& mrouter->vlan == vlan) {
- xlate_report(ctx, "forwarding to mcast router port");
+ xlate_report(ctx, OFT_DETAIL, "forwarding to mcast router port");
output_normal(ctx, mcast_xbundle, vlan);
} else if (!mcast_xbundle) {
- xlate_report(ctx, "mcast router port is unknown, dropping");
+ xlate_report(ctx, OFT_WARN,
+ "mcast router port is unknown, dropping");
} else if (mrouter->vlan != vlan) {
- xlate_report(ctx, "mcast router is on another vlan, dropping");
+ xlate_report(ctx, OFT_DETAIL,
+ "mcast router is on another vlan, dropping");
} else {
- xlate_report(ctx, "mcast router port is input port, dropping");
+ xlate_report(ctx, OFT_DETAIL,
+ "mcast router port is input port, dropping");
}
}
}
@@ -2224,12 +2384,14 @@ xlate_normal_mcast_send_fports(struct xlate_ctx *ctx,
LIST_FOR_EACH(fport, node, &ms->fport_list) {
mcast_xbundle = xbundle_lookup(xcfg, fport->port);
if (mcast_xbundle && mcast_xbundle != in_xbundle) {
- xlate_report(ctx, "forwarding to mcast flood port");
+ xlate_report(ctx, OFT_DETAIL, "forwarding to mcast flood port");
output_normal(ctx, mcast_xbundle, vlan);
} else if (!mcast_xbundle) {
- xlate_report(ctx, "mcast flood port is unknown, dropping");
+ xlate_report(ctx, OFT_WARN,
+ "mcast flood port is unknown, dropping");
} else {
- xlate_report(ctx, "mcast flood port is input port, dropping");
+ xlate_report(ctx, OFT_DETAIL,
+ "mcast flood port is input port, dropping");
}
}
}
@@ -2249,12 +2411,15 @@ xlate_normal_mcast_send_rports(struct xlate_ctx *ctx,
LIST_FOR_EACH(rport, node, &ms->rport_list) {
mcast_xbundle = xbundle_lookup(xcfg, rport->port);
if (mcast_xbundle && mcast_xbundle != in_xbundle) {
- xlate_report(ctx, "forwarding Report to mcast flagged port");
+ xlate_report(ctx, OFT_DETAIL,
+ "forwarding report to mcast flagged port");
output_normal(ctx, mcast_xbundle, vlan);
} else if (!mcast_xbundle) {
- xlate_report(ctx, "mcast port is unknown, dropping the Report");
+ xlate_report(ctx, OFT_WARN,
+ "mcast port is unknown, dropping the report");
} else {
- xlate_report(ctx, "mcast port is input port, dropping the Report");
+ xlate_report(ctx, OFT_DETAIL,
+ "mcast port is input port, dropping the Report");
}
}
}
@@ -2306,10 +2471,9 @@ xlate_normal(struct xlate_ctx *ctx)
memset(&wc->masks.dl_dst, 0xff, sizeof wc->masks.dl_dst);
wc->masks.vlan_tci |= htons(VLAN_VID_MASK | VLAN_CFI);
- in_xbundle = lookup_input_bundle(ctx->xbridge, flow->in_port.ofp_port,
- ctx->xin->packet != NULL, &in_port);
+ in_xbundle = lookup_input_bundle(ctx, flow->in_port.ofp_port, &in_port);
if (!in_xbundle) {
- xlate_report(ctx, "no input bundle, dropping");
+ xlate_report(ctx, OFT_WARN, "no input bundle, dropping");
return;
}
@@ -2317,31 +2481,31 @@ xlate_normal(struct xlate_ctx *ctx)
if (flow->dl_type == htons(ETH_TYPE_VLAN) &&
!(flow->vlan_tci & htons(VLAN_CFI))) {
if (ctx->xin->packet != NULL) {
- static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
- VLOG_WARN_RL(&rl, "bridge %s: dropping packet with partial "
- "VLAN tag received on port %s",
- ctx->xbridge->name, in_xbundle->name);
+ xlate_report_error(ctx, "dropping packet with partial "
+ "VLAN tag received on port %s",
+ in_xbundle->name);
}
- xlate_report(ctx, "partial VLAN tag, dropping");
+ xlate_report(ctx, OFT_WARN, "partial VLAN tag, dropping");
return;
}
/* Drop frames on bundles reserved for mirroring. */
if (xbundle_mirror_out(ctx->xbridge, in_xbundle)) {
if (ctx->xin->packet != NULL) {
- static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
- VLOG_WARN_RL(&rl, "bridge %s: dropping packet received on port "
- "%s, which is reserved exclusively for mirroring",
- ctx->xbridge->name, in_xbundle->name);
+ xlate_report_error(ctx, "dropping packet received on port %s, "
+ "which is reserved exclusively for mirroring",
+ in_xbundle->name);
}
- xlate_report(ctx, "input port is mirror output port, dropping");
+ xlate_report(ctx, OFT_WARN,
+ "input port is mirror output port, dropping");
return;
}
/* Check VLAN. */
vid = vlan_tci_to_vid(flow->vlan_tci);
- if (!input_vid_is_valid(vid, in_xbundle, ctx->xin->packet != NULL)) {
- xlate_report(ctx, "disallowed VLAN VID for this input port, dropping");
+ if (!input_vid_is_valid(ctx, vid, in_xbundle)) {
+ xlate_report(ctx, OFT_WARN,
+ "disallowed VLAN VID for this input port, dropping");
return;
}
vlan = input_vid_to_vlan(in_xbundle, vid);
@@ -2354,7 +2518,7 @@ xlate_normal(struct xlate_ctx *ctx)
/* Learn source MAC. */
bool is_grat_arp = is_gratuitous_arp(flow, wc);
if (ctx->xin->allow_side_effects) {
- update_learning_table(ctx->xbridge, in_xbundle, flow->dl_src, vlan,
+ update_learning_table(ctx, in_xbundle, flow->dl_src, vlan,
is_grat_arp);
}
if (ctx->xin->xcache && in_xbundle != &ofpp_none_bundle) {
@@ -2382,7 +2546,7 @@ xlate_normal(struct xlate_ctx *ctx)
if (mcast_snooping_is_membership(flow->tp_src) ||
mcast_snooping_is_query(flow->tp_src)) {
if (ctx->xin->allow_side_effects && ctx->xin->packet) {
- update_mcast_snooping_table(ctx->xbridge, flow, vlan,
+ update_mcast_snooping_table(ctx, flow, vlan,
in_xbundle, ctx->xin->packet);
}
/*
@@ -2407,14 +2571,14 @@ xlate_normal(struct xlate_ctx *ctx)
xlate_normal_mcast_send_rports(ctx, ms, in_xbundle, vlan);
ovs_rwlock_unlock(&ms->rwlock);
} else {
- xlate_report(ctx, "multicast traffic, flooding");
+ xlate_report(ctx, OFT_DETAIL, "multicast traffic, flooding");
xlate_normal_flood(ctx, in_xbundle, vlan);
}
return;
} else if (is_mld(flow, wc)) {
ctx->xout->slow |= SLOW_ACTION;
if (ctx->xin->allow_side_effects && ctx->xin->packet) {
- update_mcast_snooping_table(ctx->xbridge, flow, vlan,
+ update_mcast_snooping_table(ctx, flow, vlan,
in_xbundle, ctx->xin->packet);
}
if (is_mld_report(flow, wc)) {
@@ -2423,7 +2587,7 @@ xlate_normal(struct xlate_ctx *ctx)
xlate_normal_mcast_send_rports(ctx, ms, in_xbundle, vlan);
ovs_rwlock_unlock(&ms->rwlock);
} else {
- xlate_report(ctx, "MLD query, flooding");
+ xlate_report(ctx, OFT_DETAIL, "MLD query, flooding");
xlate_normal_flood(ctx, in_xbundle, vlan);
}
} else {
@@ -2431,7 +2595,8 @@ xlate_normal(struct xlate_ctx *ctx)
/* RFC4541: section 2.1.2, item 2: Packets with a dst IP
* address in the 224.0.0.x range which are not IGMP must
* be forwarded on all ports */
- xlate_report(ctx, "RFC4541: section 2.1.2, item 2, flooding");
+ xlate_report(ctx, OFT_DETAIL,
+ "RFC4541: section 2.1.2, item 2, flooding");
xlate_normal_flood(ctx, in_xbundle, vlan);
return;
}
@@ -2450,7 +2615,8 @@ xlate_normal(struct xlate_ctx *ctx)
xlate_normal_mcast_send_mrouters(ctx, ms, in_xbundle, vlan);
} else {
if (mcast_snooping_flood_unreg(ms)) {
- xlate_report(ctx, "unregistered multicast, flooding");
+ xlate_report(ctx, OFT_DETAIL,
+ "unregistered multicast, flooding");
xlate_normal_flood(ctx, in_xbundle, vlan);
} else {
xlate_normal_mcast_send_mrouters(ctx, ms, in_xbundle, vlan);
@@ -2468,15 +2634,18 @@ xlate_normal(struct xlate_ctx *ctx)
struct xlate_cfg *xcfg = ovsrcu_get(struct xlate_cfg *, &xcfgp);
struct xbundle *mac_xbundle = xbundle_lookup(xcfg, mac_port);
if (mac_xbundle && mac_xbundle != in_xbundle) {
- xlate_report(ctx, "forwarding to learned port");
+ xlate_report(ctx, OFT_DETAIL, "forwarding to learned port");
output_normal(ctx, mac_xbundle, vlan);
} else if (!mac_xbundle) {
- xlate_report(ctx, "learned port is unknown, dropping");
+ xlate_report(ctx, OFT_WARN,
+ "learned port is unknown, dropping");
} else {
- xlate_report(ctx, "learned port is input port, dropping");
+ xlate_report(ctx, OFT_DETAIL,
+ "learned port is input port, dropping");
}
} else {
- xlate_report(ctx, "no learned MAC for destination, flooding");
+ xlate_report(ctx, OFT_DETAIL,
+ "no learned MAC for destination, flooding");
xlate_normal_flood(ctx, in_xbundle, vlan);
}
}
@@ -2755,8 +2924,7 @@ compose_table_xlate(struct xlate_ctx *ctx, const struct xport *out_dev,
return ofproto_dpif_execute_actions__(xbridge->ofproto,
ctx->xin->tables_version, &flow,
NULL, &output.ofpact, sizeof output,
- ctx->indentation, ctx->depth,
- ctx->resubmits, packet);
+ ctx->depth, ctx->resubmits, packet);
}
static void
@@ -2805,18 +2973,19 @@ build_tunnel_send(struct xlate_ctx *ctx, const struct xport *xport,
err = tnl_route_lookup_flow(flow, &d_ip6, &s_ip6, &out_dev);
if (err) {
- xlate_report(ctx, "native tunnel routing failed");
+ xlate_report(ctx, OFT_WARN, "native tunnel routing failed");
return err;
}
- xlate_report(ctx, "tunneling to %s via %s",
+ xlate_report(ctx, OFT_DETAIL, "tunneling to %s via %s",
ipv6_string_mapped(buf_dip6, &d_ip6),
netdev_get_name(out_dev->netdev));
/* Use mac addr of bridge port of the peer. */
err = netdev_get_etheraddr(out_dev->netdev, &smac);
if (err) {
- xlate_report(ctx, "tunnel output device lacks Ethernet address");
+ xlate_report(ctx, OFT_WARN,
+ "tunnel output device lacks Ethernet address");
return err;
}
@@ -2827,7 +2996,8 @@ build_tunnel_send(struct xlate_ctx *ctx, const struct xport *xport,
err = tnl_neigh_lookup(out_dev->xbridge->name, &d_ip6, &dmac);
if (err) {
- xlate_report(ctx, "neighbor cache miss for %s on bridge %s, "
+ xlate_report(ctx, OFT_DETAIL,
+ "neighbor cache miss for %s on bridge %s, "
"sending %s request",
buf_dip6, out_dev->xbridge->name, d_ip ? "ARP" : "ND");
if (d_ip) {
@@ -2847,7 +3017,7 @@ build_tunnel_send(struct xlate_ctx *ctx, const struct xport *xport,
entry->tnl_neigh_cache.d_ipv6 = d_ip6;
}
- xlate_report(ctx, "tunneling from "ETH_ADDR_FMT" %s"
+ xlate_report(ctx, OFT_DETAIL, "tunneling from "ETH_ADDR_FMT" %s"
" to "ETH_ADDR_FMT" %s",
ETH_ADDR_ARGS(smac), ipv6_string_mapped(buf_sip6, &s_ip6),
ETH_ADDR_ARGS(dmac), buf_dip6);
@@ -2921,38 +3091,42 @@ compose_output_action__(struct xlate_ctx *ctx, ofp_port_t ofp_port,
memset(&flow_tnl, 0, sizeof flow_tnl);
if (!xport) {
- xlate_report(ctx, "Nonexistent output port");
+ xlate_report(ctx, OFT_WARN, "Nonexistent output port");
return;
} else if (xport->config & OFPUTIL_PC_NO_FWD) {
- xlate_report(ctx, "OFPPC_NO_FWD set, skipping output");
+ xlate_report(ctx, OFT_DETAIL, "OFPPC_NO_FWD set, skipping output");
return;
} else if (ctx->mirror_snaplen != 0 && xport->odp_port == ODPP_NONE) {
- xlate_report(ctx, "Mirror truncate to ODPP_NONE, skipping output");
+ xlate_report(ctx, OFT_WARN,
+ "Mirror truncate to ODPP_NONE, skipping output");
return;
} else if (xlate_flow_is_protected(ctx, flow, xport)) {
- xlate_report(ctx, "Flow is between protected ports, skipping output.");
+ xlate_report(ctx, OFT_WARN,
+ "Flow is between protected ports, skipping output.");
return;
} else if (check_stp) {
if (is_stp(&ctx->base_flow)) {
if (!xport_stp_should_forward_bpdu(xport) &&
!xport_rstp_should_manage_bpdu(xport)) {
if (ctx->xbridge->stp != NULL) {
- xlate_report(ctx, "STP not in listening state, "
- "skipping bpdu output");
+ xlate_report(ctx, OFT_WARN,
+ "STP not in listening state, "
+ "skipping bpdu output");
} else if (ctx->xbridge->rstp != NULL) {
- xlate_report(ctx, "RSTP not managing BPDU in this state, "
- "skipping bpdu output");
+ xlate_report(ctx, OFT_WARN,
+ "RSTP not managing BPDU in this state, "
+ "skipping bpdu output");
}
return;
}
} else if (!xport_stp_forward_state(xport) ||
!xport_rstp_forward_state(xport)) {
if (ctx->xbridge->stp != NULL) {
- xlate_report(ctx, "STP not in forwarding state, "
- "skipping output");
+ xlate_report(ctx, OFT_WARN,
+ "STP not in forwarding state, skipping output");
} else if (ctx->xbridge->rstp != NULL) {
- xlate_report(ctx, "RSTP not in forwarding state, "
- "skipping output");
+ xlate_report(ctx, OFT_WARN,
+ "RSTP not in forwarding state, skipping output");
}
return;
}
@@ -2968,6 +3142,7 @@ compose_output_action__(struct xlate_ctx *ctx, ofp_port_t ofp_port,
struct ofpbuf old_stack = ctx->stack;
uint8_t new_stack[1024];
struct ofpbuf old_action_set = ctx->action_set;
+ struct ovs_list *old_trace = ctx->xin->trace;
uint64_t actset_stub[1024 / 8];
ofpbuf_use_stub(&ctx->stack, new_stack, sizeof new_stack);
@@ -2981,6 +3156,8 @@ compose_output_action__(struct xlate_ctx *ctx, ofp_port_t ofp_port,
memset(flow->regs, 0, sizeof flow->regs);
flow->actset_output = OFPP_UNSET;
clear_conntrack(ctx);
+ ctx->xin->trace = xlate_report(ctx, OFT_BRIDGE,
+ "bridge(\"%s\")", peer->xbridge->name);
/* When the patch port points to a different bridge, then the mirrors
* for that bridge clearly apply independently to the packet, so we
@@ -3032,6 +3209,7 @@ compose_output_action__(struct xlate_ctx *ctx, ofp_port_t ofp_port,
}
}
+ ctx->xin->trace = old_trace;
if (independent_mirrors) {
ctx->mirrors = old_mirrors;
}
@@ -3111,12 +3289,12 @@ compose_output_action__(struct xlate_ctx *ctx, ofp_port_t ofp_port,
flow_tnl = flow->tunnel;
odp_port = tnl_port_send(xport->ofport, flow, ctx->wc);
if (odp_port == ODPP_NONE) {
- xlate_report(ctx, "Tunneling decided against output");
+ xlate_report(ctx, OFT_WARN, "Tunneling decided against output");
goto out; /* restore flow_nw_tos */
}
dst = flow_tnl_dst(&flow->tunnel);
if (ipv6_addr_equals(&dst, &ctx->orig_tunnel_ipv6_dst)) {
- xlate_report(ctx, "Not tunneling to our own address");
+ xlate_report(ctx, OFT_WARN, "Not tunneling to our own address");
goto out; /* restore flow_nw_tos */
}
if (ctx->xin->resubmit_stats) {
@@ -3130,10 +3308,10 @@ compose_output_action__(struct xlate_ctx *ctx, ofp_port_t ofp_port,
}
out_port = odp_port;
if (ovs_native_tunneling_is_on(ctx->xbridge->ofproto)) {
- xlate_report(ctx, "output to native tunnel");
+ xlate_report(ctx, OFT_DETAIL, "output to native tunnel");
tnl_push_pop_send = true;
} else {
- xlate_report(ctx, "output to kernel tunnel");
+ xlate_report(ctx, OFT_DETAIL, "output to kernel tunnel");
commit_odp_tunnel_action(flow, &ctx->base_flow, ctx->odp_actions);
flow->tunnel = flow_tnl; /* Restore tunnel metadata */
}
@@ -3242,7 +3420,6 @@ xlate_recursively(struct xlate_ctx *ctx, struct rule_dpif *rule, bool deepens)
ctx->resubmits++;
- ctx->indentation++;
ctx->depth += deepens;
ctx->rule = rule;
ctx->rule_cookie = rule->up.flow_cookie;
@@ -3251,24 +3428,23 @@ xlate_recursively(struct xlate_ctx *ctx, struct rule_dpif *rule, bool deepens)
ctx->rule_cookie = old_cookie;
ctx->rule = old_rule;
ctx->depth -= deepens;
- ctx->indentation--;
}
static bool
xlate_resubmit_resource_check(struct xlate_ctx *ctx)
{
if (ctx->depth >= MAX_DEPTH) {
- XLATE_REPORT_ERROR(ctx, "over max translation depth %d", MAX_DEPTH);
+ xlate_report_error(ctx, "over max translation depth %d", MAX_DEPTH);
ctx->error = XLATE_RECURSION_TOO_DEEP;
} else if (ctx->resubmits >= MAX_RESUBMITS) {
- XLATE_REPORT_ERROR(ctx, "over %d resubmit actions", MAX_RESUBMITS);
+ xlate_report_error(ctx, "over %d resubmit actions", MAX_RESUBMITS);
ctx->error = XLATE_TOO_MANY_RESUBMITS;
} else if (ctx->odp_actions->size > UINT16_MAX) {
- XLATE_REPORT_ERROR(ctx, "resubmits yielded over 64 kB of actions");
+ xlate_report_error(ctx, "resubmits yielded over 64 kB of actions");
/* NOT an error, as we'll be slow-pathing the flow in this case? */
ctx->exit = true; /* XXX: translation still terminated! */
} else if (ctx->stack.size >= 65536) {
- XLATE_REPORT_ERROR(ctx, "resubmits yielded over 64 kB of stack");
+ xlate_report_error(ctx, "resubmits yielded over 64 kB of stack");
ctx->error = XLATE_STACK_TOO_DEEP;
} else {
return true;
@@ -3299,9 +3475,6 @@ xlate_table_action(struct xlate_ctx *ctx, ofp_port_t in_port, uint8_t table_id,
&ctx->table_id, in_port,
may_packet_in, honor_table_miss,
ctx->xin->xcache);
- if (OVS_UNLIKELY(ctx->xin->resubmit_hook)) {
- ctx->xin->resubmit_hook(ctx->xin, rule, ctx->indentation + 1);
- }
if (rule) {
/* Fill in the cache entry here instead of xlate_recursively
@@ -3315,7 +3488,11 @@ xlate_table_action(struct xlate_ctx *ctx, ofp_port_t in_port, uint8_t table_id,
entry->rule = rule;
ofproto_rule_ref(&rule->up);
}
+
+ struct ovs_list *old_trace = ctx->xin->trace;
+ xlate_report_table(ctx, rule, table_id);
xlate_recursively(ctx, rule, table_id <= old_table_id);
+ ctx->xin->trace = old_trace;
}
ctx->table_id = old_table_id;
@@ -3351,11 +3528,9 @@ xlate_group_bucket(struct xlate_ctx *ctx, struct ofputil_bucket *bucket)
bool old_was_mpls = ctx->was_mpls;
ofpacts_execute_action_set(&action_list, &action_set);
- ctx->indentation++;
ctx->depth++;
do_xlate_actions(action_list.data, action_list.size, ctx);
ctx->depth--;
- ctx->indentation--;
ofpbuf_uninit(&action_list);
@@ -3570,6 +3745,8 @@ xlate_group_action(struct xlate_ctx *ctx, uint32_t group_id)
ctx->xin->tables_version, ctx->xin->xcache);
if (!group) {
/* XXX: Should set ctx->error ? */
+ xlate_report(ctx, OFT_WARN, "output to nonexistent group %"PRIu32,
+ group_id);
return true;
}
xlate_group_action__(ctx, group);
@@ -3782,7 +3959,7 @@ finish_freezing__(struct xlate_ctx *ctx, uint8_t table)
* with the udpif key ('ukey') created for each new datapath flow. */
uint32_t id = recirc_alloc_id_ctx(&state);
if (!id) {
- XLATE_REPORT_ERROR(ctx, "Failed to allocate recirculation id");
+ xlate_report_error(ctx, "Failed to allocate recirculation id");
ctx->error = XLATE_NO_RECIRCULATION_CONTEXT;
return;
}
@@ -3837,10 +4014,10 @@ compose_mpls_push_action(struct xlate_ctx *ctx, struct ofpact_push_mpls *mpls)
xlate_commit_actions(ctx);
} else if (n >= FLOW_MAX_MPLS_LABELS) {
if (ctx->xin->packet != NULL) {
- XLATE_REPORT_ERROR(ctx, "bridge %s: dropping packet on which an "
- "MPLS push action can't be performed as it would "
- "have more MPLS LSEs than the %d supported.",
- ctx->xbridge->name, FLOW_MAX_MPLS_LABELS);
+ xlate_report_error(ctx, "dropping packet on which an MPLS push "
+ "action can't be performed as it would have "
+ "more MPLS LSEs than the %d supported.",
+ FLOW_MAX_MPLS_LABELS);
}
ctx->error = XLATE_TOO_MANY_MPLS_LABELS;
return;
@@ -3862,10 +4039,10 @@ compose_mpls_pop_action(struct xlate_ctx *ctx, ovs_be16 eth_type)
}
} else if (n >= FLOW_MAX_MPLS_LABELS) {
if (ctx->xin->packet != NULL) {
- XLATE_REPORT_ERROR(ctx, "bridge %s: dropping packet on which an "
- "MPLS pop action can't be performed as it has "
- "more MPLS LSEs than the %d supported.",
- ctx->xbridge->name, FLOW_MAX_MPLS_LABELS);
+ xlate_report_error(ctx, "dropping packet on which an "
+ "MPLS pop action can't be performed as it has "
+ "more MPLS LSEs than the %d supported.",
+ FLOW_MAX_MPLS_LABELS);
}
ctx->error = XLATE_TOO_MANY_MPLS_LABELS;
ofpbuf_clear(ctx->odp_actions);
@@ -3894,6 +4071,8 @@ compose_dec_ttl(struct xlate_ctx *ctx, struct ofpact_cnt_ids *ids)
}
/* Stop processing for current table. */
+ xlate_report(ctx, OFT_WARN, "IPv%d decrement TTL exception",
+ flow->dl_type == htons(ETH_TYPE_IP) ? 4 : 6);
return true;
}
}
@@ -3945,6 +4124,7 @@ compose_dec_mpls_ttl_action(struct xlate_ctx *ctx)
}
/* Stop processing for current table. */
+ xlate_report(ctx, OFT_WARN, "MPLS decrement TTL exception");
return true;
}
@@ -3987,7 +4167,7 @@ xlate_output_action(struct xlate_ctx *ctx,
if (port != ctx->xin->flow.in_port.ofp_port) {
compose_output_action(ctx, port, NULL);
} else {
- xlate_report(ctx, "skipping output to input port");
+ xlate_report(ctx, OFT_WARN, "skipping output to input port");
}
break;
}
@@ -4008,12 +4188,16 @@ xlate_output_reg_action(struct xlate_ctx *ctx,
{
uint64_t port = mf_get_subfield(&or->src, &ctx->xin->flow);
if (port <= UINT16_MAX) {
+ xlate_report(ctx, OFT_DETAIL, "output port is %"PRIu64, port);
+
union mf_subvalue value;
memset(&value, 0xff, sizeof value);
mf_write_subfield_flow(&or->src, &value, &ctx->wc->masks);
- xlate_output_action(ctx, u16_to_ofp(port),
- or->max_len, false);
+ xlate_output_action(ctx, u16_to_ofp(port), or->max_len, false);
+ } else {
+ xlate_report(ctx, OFT_WARN, "output port %"PRIu64" is out of range",
+ port);
}
}
@@ -4033,7 +4217,8 @@ xlate_output_trunc_action(struct xlate_ctx *ctx,
case OFPP_CONTROLLER:
case OFPP_NONE:
ofputil_port_to_string(port, name, sizeof name);
- xlate_report(ctx, "output_trunc does not support port: %s", name);
+ xlate_report(ctx, OFT_WARN,
+ "output_trunc does not support port: %s", name);
break;
case OFPP_LOCAL:
case OFPP_IN_PORT:
@@ -4046,9 +4231,8 @@ xlate_output_trunc_action(struct xlate_ctx *ctx,
* the output port is a patch port, the behavior is somehow
* unpredicable. For simpilicity, disallow this case. */
ofputil_port_to_string(port, name, sizeof name);
- XLATE_REPORT_ERROR(ctx, "bridge %s: "
- "output_trunc does not support port: %s",
- ctx->xbridge->name, name);
+ xlate_report_error(ctx, "output_trunc does not support "
+ "patch port %s", name);
break;
}
@@ -4061,7 +4245,7 @@ xlate_output_trunc_action(struct xlate_ctx *ctx,
ctx->xout->slow |= SLOW_ACTION;
}
} else {
- xlate_report(ctx, "skipping output to input port");
+ xlate_report(ctx, OFT_WARN, "skipping output to input port");
}
break;
}
@@ -4150,6 +4334,7 @@ xlate_bundle_action(struct xlate_ctx *ctx,
CONST_CAST(struct xbridge *, ctx->xbridge));
if (bundle->dst.field) {
nxm_reg_load(&bundle->dst, ofp_to_u16(port), &ctx->xin->flow, ctx->wc);
+ xlate_report_subfield(ctx, &bundle->dst);
} else {
xlate_output_action(ctx, port, 0, false);
}
@@ -4179,6 +4364,29 @@ xlate_learn_action(struct xlate_ctx *ctx, const struct ofpact_learn *learn)
ofpbuf_use_stub(&ofpacts, ofpacts_stub, sizeof ofpacts_stub);
learn_execute(learn, &ctx->xin->flow, &fm, &ofpacts);
+ if (OVS_UNLIKELY(ctx->xin->trace)) {
+ struct ds s = DS_EMPTY_INITIALIZER;
+ ds_put_format(&s, "table=%"PRIu8" ", fm.table_id);
+ match_format(&fm.match, &s, OFP_DEFAULT_PRIORITY);
+ ds_chomp(&s, ' ');
+ ds_put_format(&s, " priority=%d", fm.priority);
+ if (fm.new_cookie) {
+ ds_put_format(&s, " cookie=%#"PRIx64, ntohll(fm.new_cookie));
+ }
+ if (fm.idle_timeout != OFP_FLOW_PERMANENT) {
+ ds_put_format(&s, " idle=%"PRIu16, fm.idle_timeout);
+ }
+ if (fm.hard_timeout != OFP_FLOW_PERMANENT) {
+ ds_put_format(&s, " hard=%"PRIu16, fm.hard_timeout);
+ }
+ if (fm.flags & NX_LEARN_F_SEND_FLOW_REM) {
+ ds_put_cstr(&s, " send_flow_rem");
+ }
+ ds_put_cstr(&s, " actions=");
+ ofpacts_format(fm.ofpacts, fm.ofpacts_len, &s);
+ xlate_report(ctx, OFT_DETAIL, "%s", ds_cstr(&s));
+ ds_destroy(&s);
+ }
error = ofproto_dpif_flow_mod_init_for_learn(ctx->xbridge->ofproto,
&fm, ofm);
ofpbuf_uninit(&ofpacts);
@@ -4188,10 +4396,12 @@ xlate_learn_action(struct xlate_ctx *ctx, const struct ofpact_learn *learn)
}
if (error) {
- static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
- VLOG_WARN_RL(&rl, "%s: LEARN action execution failed (%s).",
- ctx->xbridge->name, ofperr_to_string(error));
+ xlate_report_error(ctx, "LEARN action execution failed (%s).",
+ ofperr_to_string(error));
}
+ } else {
+ xlate_report(ctx, OFT_WARN,
+ "suppressing side effects, so learn action ignored");
}
}
@@ -4244,11 +4454,9 @@ xlate_sample_action(struct xlate_ctx *ctx,
uint32_t probability = (os->probability << 16) | os->probability;
if (!ctx->xbridge->support.variable_length_userdata) {
- static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 1);
-
- VLOG_ERR_RL(&rl, "ignoring NXAST_SAMPLE action because datapath "
- "lacks support (needs Linux 3.10+ or kernel module from "
- "OVS 1.11+)");
+ xlate_report_error(ctx, "ignoring NXAST_SAMPLE action because "
+ "datapath lacks support (needs Linux 3.10+ or "
+ "kernel module from OVS 1.11+)");
return;
}
@@ -4259,9 +4467,8 @@ xlate_sample_action(struct xlate_ctx *ctx,
output_odp_port = ofp_port_to_odp_port(ctx->xbridge,
os->sampling_port);
if (output_odp_port == ODPP_NONE) {
- static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 1);
- VLOG_WARN_RL(&rl, "can't use unknown port %d in flow sample "
- "action", os->sampling_port);
+ xlate_report_error(ctx, "can't use unknown port %d in flow sample "
+ "action", os->sampling_port);
return;
}
@@ -4292,9 +4499,9 @@ xlate_sample_action(struct xlate_ctx *ctx,
flow->tunnel = flow_tnl;
}
} else {
- static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 1);
- VLOG_WARN_RL(&rl, "sampling_port:%d should be a tunnel port.",
- os->sampling_port);
+ xlate_report_error(ctx,
+ "sampling_port:%d should be a tunnel port.",
+ os->sampling_port);
}
}
@@ -4408,16 +4615,22 @@ xlate_write_actions(struct xlate_ctx *ctx, const struct ofpact_nest *a)
static void
xlate_action_set(struct xlate_ctx *ctx)
{
- uint64_t action_list_stub[1024 / 64];
- struct ofpbuf action_list;
-
- ctx->in_action_set = true;
- ofpbuf_use_stub(&action_list, action_list_stub, sizeof action_list_stub);
+ uint64_t action_list_stub[1024 / 8];
+ struct ofpbuf action_list = OFPBUF_STUB_INITIALIZER(action_list_stub);
ofpacts_execute_action_set(&action_list, &ctx->action_set);
/* Clear the action set, as it is not needed any more. */
ofpbuf_clear(&ctx->action_set);
- do_xlate_actions(action_list.data, action_list.size, ctx);
- ctx->in_action_set = false;
+ if (action_list.size) {
+ ctx->in_action_set = true;
+
+ struct ovs_list *old_trace = ctx->xin->trace;
+ ctx->xin->trace = xlate_report(ctx, OFT_TABLE,
+ "--. Executing action set:");
+ do_xlate_actions(action_list.data, action_list.size, ctx);
+ ctx->xin->trace = old_trace;
+
+ ctx->in_action_set = false;
+ }
ofpbuf_uninit(&action_list);
}
@@ -4561,7 +4774,8 @@ put_ct_label(const struct flow *flow, struct ofpbuf *odp_actions,
}
static void
-put_ct_helper(struct ofpbuf *odp_actions, struct ofpact_conntrack *ofc)
+put_ct_helper(struct xlate_ctx *ctx,
+ struct ofpbuf *odp_actions, struct ofpact_conntrack *ofc)
{
if (ofc->alg) {
switch(ofc->alg) {
@@ -4572,7 +4786,7 @@ put_ct_helper(struct ofpbuf *odp_actions, struct ofpact_conntrack *ofc)
nl_msg_put_string(odp_actions, OVS_CT_ATTR_HELPER, "tftp");
break;
default:
- VLOG_WARN("Cannot serialize ct_helper %d\n", ofc->alg);
+ xlate_report_error(ctx, "cannot serialize ct_helper %d", ofc->alg);
break;
}
}
@@ -4667,7 +4881,7 @@ compose_conntrack_action(struct xlate_ctx *ctx, struct ofpact_conntrack *ofc)
nl_msg_put_u16(ctx->odp_actions, OVS_CT_ATTR_ZONE, zone);
put_ct_mark(&ctx->xin->flow, ctx->odp_actions, ctx->wc);
put_ct_label(&ctx->xin->flow, ctx->odp_actions, ctx->wc);
- put_ct_helper(ctx->odp_actions, ofc);
+ put_ct_helper(ctx, ctx->odp_actions, ofc);
put_ct_nat(ctx);
ctx->ct_nat_action = NULL;
nl_msg_end_nested(ctx->odp_actions, ct_offset);
@@ -4783,6 +4997,34 @@ recirc_for_mpls(const struct ofpact *a, struct xlate_ctx *ctx)
}
static void
+xlate_ofpact_reg_move(struct xlate_ctx *ctx, const struct ofpact_reg_move *a)
+{
+ mf_subfield_copy(&a->src, &a->dst, &ctx->xin->flow, ctx->wc);
+ xlate_report_subfield(ctx, &a->dst);
+}
+
+static void
+xlate_ofpact_stack_pop(struct xlate_ctx *ctx, const struct ofpact_stack *a)
+{
+ if (nxm_execute_stack_pop(a, &ctx->xin->flow, ctx->wc, &ctx->stack)) {
+ xlate_report_subfield(ctx, &a->subfield);
+ } else {
+ xlate_report_error(ctx, "stack underflow");
+ }
+}
+
+/* Restore translation context data that was stored earlier. */
+static void
+xlate_ofpact_unroll_xlate(struct xlate_ctx *ctx,
+ const struct ofpact_unroll_xlate *a)
+{
+ ctx->table_id = a->rule_table_id;
+ ctx->rule_cookie = a->rule_cookie;
+ xlate_report(ctx, OFT_THAW, "restored state: table=%"PRIu8", "
+ "cookie=%#"PRIx64, a->rule_table_id, a->rule_cookie);
+}
+
+static void
do_xlate_actions(const struct ofpact *ofpacts, size_t ofpacts_len,
struct xlate_ctx *ctx)
{
@@ -4795,6 +5037,11 @@ do_xlate_actions(const struct ofpact *ofpacts, size_t ofpacts_len,
}
/* dl_type already in the mask, not set below. */
+ if (!ofpacts_len) {
+ xlate_report(ctx, OFT_ACTION, "drop");
+ return;
+ }
+
OFPACT_FOR_EACH (a, ofpacts, ofpacts_len) {
struct ofpact_controller *controller;
const struct ofpact_metadata *metadata;
@@ -4817,6 +5064,13 @@ do_xlate_actions(const struct ofpact *ofpacts, size_t ofpacts_len,
break;
}
+ if (OVS_UNLIKELY(ctx->xin->trace)) {
+ struct ds s = DS_EMPTY_INITIALIZER;
+ ofpacts_format(a, OFPACT_ALIGN(a->len), &s);
+ xlate_report(ctx, OFT_ACTION, "%s", ds_cstr(&s));
+ ds_destroy(&s);
+ }
+
switch (a->type) {
case OFPACT_OUTPUT:
xlate_output_action(ctx, ofpact_get_OUTPUT(a)->port,
@@ -4973,12 +5227,15 @@ do_xlate_actions(const struct ofpact *ofpacts, size_t ofpacts_len,
case OFPACT_POP_QUEUE:
memset(&wc->masks.skb_priority, 0xff,
sizeof wc->masks.skb_priority);
- flow->skb_priority = ctx->orig_skb_priority;
+ if (flow->skb_priority != ctx->orig_skb_priority) {
+ flow->skb_priority = ctx->orig_skb_priority;
+ xlate_report(ctx, OFT_DETAIL, "queue = %#"PRIx32,
+ flow->skb_priority);
+ }
break;
case OFPACT_REG_MOVE:
- mf_subfield_copy(&ofpact_get_REG_MOVE(a)->src,
- &ofpact_get_REG_MOVE(a)->dst, flow, wc);
+ xlate_ofpact_reg_move(ctx, ofpact_get_REG_MOVE(a));
break;
case OFPACT_SET_FIELD:
@@ -4991,6 +5248,11 @@ do_xlate_actions(const struct ofpact *ofpacts, size_t ofpacts_len,
mf_set_flow_value_masked(mf, set_field->value,
ofpact_set_field_mask(set_field),
flow);
+ } else {
+ xlate_report(ctx, OFT_WARN,
+ "unmet prerequisites for %s, set_field ignored",
+ mf->name);
+
}
break;
@@ -5000,8 +5262,7 @@ do_xlate_actions(const struct ofpact *ofpacts, size_t ofpacts_len,
break;
case OFPACT_STACK_POP:
- nxm_execute_stack_pop(ofpact_get_STACK_POP(a), flow, wc,
- &ctx->stack);
+ xlate_ofpact_stack_pop(ctx, ofpact_get_STACK_POP(a));
break;
case OFPACT_PUSH_MPLS:
@@ -5044,6 +5305,7 @@ do_xlate_actions(const struct ofpact *ofpacts, size_t ofpacts_len,
case OFPACT_MULTIPATH:
multipath_execute(ofpact_get_MULTIPATH(a), flow, wc);
+ xlate_report_subfield(ctx, &ofpact_get_MULTIPATH(a)->dst);
break;
case OFPACT_BUNDLE:
@@ -5063,34 +5325,29 @@ do_xlate_actions(const struct ofpact *ofpacts, size_t ofpacts_len,
xlate_learn_action(ctx, ofpact_get_LEARN(a));
break;
- case OFPACT_CONJUNCTION: {
+ case OFPACT_CONJUNCTION:
/* A flow with a "conjunction" action represents part of a special
* kind of "set membership match". Such a flow should not actually
* get executed, but it could via, say, a "packet-out", even though
* that wouldn't be useful. Log it to help debugging. */
- static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 1);
- VLOG_INFO_RL(&rl, "executing no-op conjunction action");
+ xlate_report_error(ctx, "executing no-op conjunction action");
break;
- }
case OFPACT_EXIT:
ctx->exit = true;
break;
- case OFPACT_UNROLL_XLATE: {
- struct ofpact_unroll_xlate *unroll = ofpact_get_UNROLL_XLATE(a);
-
- /* Restore translation context data that was stored earlier. */
- ctx->table_id = unroll->rule_table_id;
- ctx->rule_cookie = unroll->rule_cookie;
+ case OFPACT_UNROLL_XLATE:
+ xlate_ofpact_unroll_xlate(ctx, ofpact_get_UNROLL_XLATE(a));
break;
- }
+
case OFPACT_FIN_TIMEOUT:
memset(&wc->masks.nw_proto, 0xff, sizeof wc->masks.nw_proto);
xlate_fin_timeout(ctx, ofpact_get_FIN_TIMEOUT(a));
break;
case OFPACT_CLEAR_ACTIONS:
+ xlate_report_action_set(ctx, "was");
ofpbuf_clear(&ctx->action_set);
ctx->xin->flow.actset_output = OFPP_UNSET;
ctx->action_set_has_group = false;
@@ -5098,6 +5355,7 @@ do_xlate_actions(const struct ofpact *ofpacts, size_t ofpacts_len,
case OFPACT_WRITE_ACTIONS:
xlate_write_actions(ctx, ofpact_get_WRITE_ACTIONS(a));
+ xlate_report_action_set(ctx, "is");
break;
case OFPACT_WRITE_METADATA:
@@ -5176,10 +5434,8 @@ xlate_in_init(struct xlate_in *xin, struct ofproto_dpif *ofproto,
xin->ofpacts = NULL;
xin->ofpacts_len = 0;
xin->tcp_flags = tcp_flags;
- xin->resubmit_hook = NULL;
- xin->report_hook = NULL;
+ xin->trace = NULL;
xin->resubmit_stats = NULL;
- xin->indentation = 0;
xin->depth = 0;
xin->resubmits = 0;
xin->wc = wc;
@@ -5438,7 +5694,6 @@ xlate_actions(struct xlate_in *xin, struct xlate_out *xout)
: &(struct flow_wildcards) { .masks = { .dl_type = 0 } }),
.odp_actions = xin->odp_actions ? xin->odp_actions : &scratch_actions,
- .indentation = xin->indentation,
.depth = xin->depth,
.resubmits = xin->resubmits,
.in_group = false,
@@ -5481,17 +5736,17 @@ xlate_actions(struct xlate_in *xin, struct xlate_out *xout)
COVERAGE_INC(xlate_actions);
+ xin->trace = xlate_report(&ctx, OFT_BRIDGE, "bridge(\"%s\")",
+ xbridge->name);
if (xin->frozen_state) {
const struct frozen_state *state = xin->frozen_state;
- xlate_report(&ctx, "Thawing frozen state:");
+ struct ovs_list *old_trace = xin->trace;
+ xin->trace = xlate_report(&ctx, OFT_THAW, "thaw");
if (xin->ofpacts_len > 0 || ctx.rule) {
- static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 1);
- const char *conflict = xin->ofpacts_len ? "actions" : "rule";
-
- VLOG_WARN_RL(&rl, "Recirculation conflict (%s)!", conflict);
- xlate_report(&ctx, "- Recirculation conflict (%s)!", conflict);
+ xlate_report_error(&ctx, "Recirculation conflict (%s)!",
+ xin->ofpacts_len ? "actions" : "rule");
ctx.error = XLATE_RECIRCULATION_CONFLICT;
goto exit;
}
@@ -5504,10 +5759,9 @@ xlate_actions(struct xlate_in *xin, struct xlate_out *xout)
if (OVS_UNLIKELY(!new_bridge)) {
/* Drop the packet if the bridge cannot be found. */
- static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 1);
- VLOG_WARN_RL(&rl, "Frozen bridge no longer exists.");
- xlate_report(&ctx, "- Frozen bridge no longer exists.");
+ xlate_report_error(&ctx, "Frozen bridge no longer exists.");
ctx.error = XLATE_BRIDGE_NOT_FOUND;
+ xin->trace = old_trace;
goto exit;
}
ctx.xbridge = new_bridge;
@@ -5519,7 +5773,8 @@ xlate_actions(struct xlate_in *xin, struct xlate_out *xout)
/* Set the thawed table id. Note: A table lookup is done only if there
* are no frozen actions. */
ctx.table_id = state->table_id;
- xlate_report(&ctx, "- Resuming from table %"PRIu8, ctx.table_id);
+ xlate_report(&ctx, OFT_THAW,
+ "Resuming from table %"PRIu8, ctx.table_id);
if (!state->conntracked) {
clear_conntrack(&ctx);
@@ -5539,7 +5794,7 @@ xlate_actions(struct xlate_in *xin, struct xlate_out *xout)
/* Restore action set, if any. */
if (state->action_set_len) {
- xlate_report_actions(&ctx, "- Restoring action set",
+ xlate_report_actions(&ctx, OFT_THAW, "Restoring action set",
state->action_set, state->action_set_len);
flow->actset_output = OFPP_UNSET;
@@ -5552,14 +5807,15 @@ xlate_actions(struct xlate_in *xin, struct xlate_out *xout)
xin->ofpacts = state->ofpacts;
xin->ofpacts_len = state->ofpacts_len;
if (state->ofpacts_len) {
- xlate_report_actions(&ctx, "- Restoring actions",
+ xlate_report_actions(&ctx, OFT_THAW, "Restoring actions",
xin->ofpacts, xin->ofpacts_len);
}
- } else if (OVS_UNLIKELY(flow->recirc_id)) {
- static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 1);
- VLOG_WARN_RL(&rl, "Recirculation context not found for ID %"PRIx32,
- flow->recirc_id);
+ xin->trace = old_trace;
+ } else if (OVS_UNLIKELY(flow->recirc_id)) {
+ xlate_report_error(&ctx,
+ "Recirculation context not found for ID %"PRIx32,
+ flow->recirc_id);
ctx.error = XLATE_NO_RECIRCULATION_CONTEXT;
goto exit;
}
@@ -5574,7 +5830,7 @@ xlate_actions(struct xlate_in *xin, struct xlate_out *xout)
&xin->upcall_flow->tunnel,
&flow->tunnel);
if (err) {
- XLATE_REPORT_ERROR(&ctx, "Invalid Geneve tunnel metadata");
+ xlate_report_error(&ctx, "Invalid Geneve tunnel metadata");
ctx.error = XLATE_INVALID_TUNNEL_METADATA;
goto exit;
}
@@ -5603,9 +5859,7 @@ xlate_actions(struct xlate_in *xin, struct xlate_out *xout)
ofproto_rule_ref(&ctx.rule->up);
}
- if (OVS_UNLIKELY(ctx.xin->resubmit_hook)) {
- ctx.xin->resubmit_hook(ctx.xin, ctx.rule, 0);
- }
+ xlate_report_table(&ctx, ctx.rule, ctx.table_id);
}
/* Get the proximate input port of the packet. (If xin->frozen_state,
@@ -5637,12 +5891,9 @@ xlate_actions(struct xlate_in *xin, struct xlate_out *xout)
* was done before they were frozen and should not be redone. */
} else if (in_port && in_port->xbundle
&& xbundle_mirror_out(xbridge, in_port->xbundle)) {
- if (ctx.xin->packet != NULL) {
- static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
- VLOG_WARN_RL(&rl, "bridge %s: dropping packet received on port "
- "%s, which is reserved exclusively for mirroring",
- ctx.xbridge->name, in_port->xbundle->name);
- }
+ xlate_report_error(&ctx, "dropping packet received on port "
+ "%s, which is reserved exclusively for mirroring",
+ in_port->xbundle->name);
} else {
/* Sampling is done on initial reception; don't redo after thawing. */
unsigned int user_cookie_offset = 0;
@@ -5911,10 +6162,10 @@ xlate_mac_learning_update(const struct ofproto_dpif *ofproto,
return;
}
- xbundle = lookup_input_bundle(xbridge, in_port, false, NULL);
+ xbundle = lookup_input_bundle__(xbridge, in_port, NULL);
if (!xbundle) {
return;
}
- update_learning_table(xbridge, xbundle, dl_src, vlan, is_grat_arp);
+ update_learning_table__(xbridge, xbundle, dl_src, vlan, is_grat_arp);
}
diff --git a/ofproto/ofproto-dpif-xlate.h b/ofproto/ofproto-dpif-xlate.h
index 51c05ace2..5d00d6dc9 100644
--- a/ofproto/ofproto-dpif-xlate.h
+++ b/ofproto/ofproto-dpif-xlate.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016 Nicira, Inc.
+/* Copyright (c) 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017 Nicira, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -83,27 +83,10 @@ struct xlate_in {
* timeouts.) */
uint16_t tcp_flags;
- /* If nonnull, flow translation calls this function just before executing a
- * resubmit or OFPP_TABLE action. In addition, disables logging of traces
- * when the recursion depth is exceeded.
- *
- * 'rule' is the rule being submitted into. It will be null if the
- * resubmit or OFPP_TABLE action didn't find a matching rule.
- *
- * 'indentation' is the resubmit recursion depth at time of invocation,
- * suitable for indenting the output.
- *
- * This is normally null so the client has to set it manually after
- * calling xlate_in_init(). */
- void (*resubmit_hook)(struct xlate_in *, struct rule_dpif *rule,
- int indentation);
-
- /* If nonnull, flow translation calls this function to report some
- * significant decision, e.g. to explain why OFPP_NORMAL translation
- * dropped a packet. 'indentation' is the resubmit recursion depth at time
- * of invocation, suitable for indenting the output. */
- void (*report_hook)(struct xlate_in *, int indentation,
- const char *format, va_list args);
+ /* Set to nonnull to trace the translation. See ofproto-dpif-trace.h for
+ * more information. This points to the list of oftrace nodes to which the
+ * translation should add tracing information (with oftrace_report()). */
+ struct ovs_list *trace;
/* If nonnull, flow translation credits the specified statistics to each
* rule reached through a resubmit or OFPP_TABLE action.
@@ -127,7 +110,6 @@ struct xlate_in {
* These fields are really implementation details; the client doesn't care
* about what they mean. See the corresponding fields in xlate_ctx for
* real documentation. */
- int indentation;
int depth;
int resubmits;
diff --git a/ofproto/ofproto-dpif.c b/ofproto/ofproto-dpif.c
index 3b036a116..3b274eebb 100644
--- a/ofproto/ofproto-dpif.c
+++ b/ofproto/ofproto-dpif.c
@@ -3600,7 +3600,7 @@ ofproto_dpif_execute_actions__(struct ofproto_dpif *ofproto,
ovs_version_t version, const struct flow *flow,
struct rule_dpif *rule,
const struct ofpact *ofpacts, size_t ofpacts_len,
- int indentation, int depth, int resubmits,
+ int depth, int resubmits,
struct dp_packet *packet)
{
struct dpif_flow_stats stats;
@@ -3624,7 +3624,6 @@ ofproto_dpif_execute_actions__(struct ofproto_dpif *ofproto,
xin.ofpacts = ofpacts;
xin.ofpacts_len = ofpacts_len;
xin.resubmit_stats = &stats;
- xin.indentation = indentation;
xin.depth = depth;
xin.resubmits = resubmits;
if (xlate_actions(&xin, &xout) != XLATE_OK) {
@@ -3663,8 +3662,7 @@ ofproto_dpif_execute_actions(struct ofproto_dpif *ofproto,
struct dp_packet *packet)
{
return ofproto_dpif_execute_actions__(ofproto, version, flow, rule,
- ofpacts, ofpacts_len, 0, 0, 0,
- packet);
+ ofpacts, ofpacts_len, 0, 0, packet);
}
static void
diff --git a/ofproto/ofproto-dpif.h b/ofproto/ofproto-dpif.h
index d62c730f4..c4f7baa53 100644
--- a/ofproto/ofproto-dpif.h
+++ b/ofproto/ofproto-dpif.h
@@ -288,7 +288,7 @@ int ofproto_dpif_execute_actions(struct ofproto_dpif *, ovs_version_t,
int ofproto_dpif_execute_actions__(struct ofproto_dpif *, ovs_version_t,
const struct flow *, struct rule_dpif *,
const struct ofpact *, size_t ofpacts_len,
- int indentation, int depth, int resubmits,
+ int depth, int resubmits,
struct dp_packet *);
void ofproto_dpif_send_async_msg(struct ofproto_dpif *,
struct ofproto_async_msg *);