@@ -329,22 +329,28 @@ Try this command::
The output should look something like this::
- Flow: metadata=0,in_port=1,vlan_tci=0x0000,dl_src=00:00:00:00:00:00,dl_dst=01:80:c2:00:00:05,dl_type=0x0000
- Rule: table=0 cookie=0 dl_dst=01:80:c2:00:00:00/ff:ff:ff:ff:ff:f0
- OpenFlow actions=drop
+ Flow: in_port=1,vlan_tci=0x0000,dl_src=00:00:00:00:00:00,dl_dst=01:80:c2:00:00:05,dl_type=0x0000
+
+ bridge("br0")
+ -------------
+ 0. dl_dst=01:80:c2:00:00:00/ff:ff:ff:ff:ff:f0, priority 32768
+ drop
Final flow: unchanged
+ Megaflow: recirc_id=0,in_port=1,dl_src=00:00:00:00:00:00/01:00:00:00:00:00,dl_dst=01:80:c2:00:00:00/ff:ff:ff:ff:ff:f0,dl_type=0x0000
Datapath actions: drop
-The first block of lines describes an OpenFlow table lookup. The first line
-shows the fields used for the table lookup (which is mostly zeros because
-that's the default if we don't specify everything). The second line gives the
-OpenFlow flow that the fields matched (called a "rule" because that is the name
-used inside Open vSwitch for an OpenFlow flow). In this case, we see that this
-packet that has a reserved multicast destination address matches the rule that
-drops those packets. The third line gives the rule's OpenFlow actions.
+The first line shows the flow being traced, in slightly greater detail
+than specified on the command line. It is mostly zeros because
+unspecified fields default to zeros.
+
+The second group of lines shows the packet's trip through bridge br0.
+We see, in table 0, the OpenFlow flow that the fields matched, along
+with its priority, followed by its actions, one per line. In this
+case, we see that this packet that has a reserved multicast
+destination address matches the flow that drops those packets.
-The second block of lines summarizes the results, which are not very
+The final block of lines summarizes the results, which are not very
interesting here.
Example 2
@@ -356,26 +362,27 @@ Try another command::
The output should be::
- Flow: metadata=0,in_port=1,vlan_tci=0x0000,dl_src=00:00:00:00:00:00,dl_dst=01:80:c2:00:00:10,dl_type=0x0000
- Rule: table=0 cookie=0 priority=0
- OpenFlow actions=resubmit(,1)
+ Flow: in_port=1,vlan_tci=0x0000,dl_src=00:00:00:00:00:00,dl_dst=01:80:c2:00:00:10,dl_type=0x0000
- Resubmitted flow: unchanged
- Resubmitted regs: reg0=0x0 reg1=0x0 reg2=0x0 reg3=0x0 reg4=0x0 reg5=0x0 reg6=0x0 reg7=0x0
- Resubmitted odp: drop
- No match
+ bridge("br0")
+ -------------
+ 0. priority 0
+ resubmit(,1)
+ 1. No match.
+ drop
Final flow: unchanged
+ Megaflow: recirc_id=0,in_port=1,dl_src=00:00:00:00:00:00/01:00:00:00:00:00,dl_dst=01:80:c2:00:00:10/ff:ff:ff:ff:ff:f0,dl_type=0x0000
Datapath actions: drop
-This time the flow we handed to ``ofproto/trace`` doesn't match any of our
-"drop" rules, so it falls through to the low-priority "resubmit" rule, which we
-see in the rule and the actions selected in the first block. The "resubmit"
-causes a second lookup in OpenFlow table 1, described by the additional block
-of indented text in the output. We haven't yet added any flows to OpenFlow
-table 1, so no flow actually matches in the second lookup. Therefore, the
-packet is still actually dropped, which means that the externally observable
-results would be identical to our first example.
+This time the flow we handed to ``ofproto/trace`` doesn't match any of
+our "drop" flows in table 0, so it falls through to the low-priority
+"resubmit" flow. The "resubmit" causes a second lookup in OpenFlow
+table 1, described by the block of text that starts with "1." We
+haven't yet added any flows to OpenFlow table 1, so no flow actually
+matches in the second lookup. Therefore, the packet is still actually
+dropped, which means that the externally observable results would be
+identical to our first example.
Implementing Table 1: VLAN Input Processing
-------------------------------------------
@@ -389,7 +396,7 @@ being part of the VLAN header, reducing special cases.
Let's start by adding a low-priority flow that drops all packets, before we add
flows that pass through acceptable packets. You can think of this as a
-"default drop" rule::
+"default drop" flow::
$ ovs-ofctl add-flow br0 "table=1, priority=0, actions=drop"
@@ -410,8 +417,8 @@ stage::
table=1, priority=99, in_port=4, vlan_tci=0, actions=mod_vlan_vid:30, resubmit(,2)
EOF
-We don't write any rules that match packets with 802.1Q that enter this stage
-on any of the access ports, so the "default drop" rule we added earlier causes
+We don't write any flows that match packets with 802.1Q that enter this stage
+on any of the access ports, so the "default drop" flow we added earlier causes
them to be dropped, which is ordinarily what we want for access ports.
.. note::
@@ -422,7 +429,7 @@ them to be dropped, which is ordinarily what we want for access ports.
Testing Table 1
---------------
-``ofproto/trace`` allows us to test the ingress VLAN rules that we added above.
+``ofproto/trace`` allows us to test the ingress VLAN flows that we added above.
Example 1: Packet on Trunk Port
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -435,22 +442,19 @@ The output shows the lookup in table 0, the resubmit to table 1, and the
resubmit to table 2 (which does nothing because we haven't put anything there
yet)::
- Flow: metadata=0,in_port=1,vlan_tci=0x0005,dl_src=00:00:00:00:00:00,dl_dst=00:00:00:00:00:00,dl_type=0x0000
- Rule: table=0 cookie=0 priority=0
- OpenFlow actions=resubmit(,1)
+ Flow: in_port=1,vlan_tci=0x0005,dl_src=00:00:00:00:00:00,dl_dst=00:00:00:00:00:00,dl_type=0x0000
- Resubmitted flow: unchanged
- Resubmitted regs: reg0=0x0 reg1=0x0 reg2=0x0 reg3=0x0 reg4=0x0 reg5=0x0 reg6=0x0 reg7=0x0
- Resubmitted odp: drop
- Rule: table=1 cookie=0 priority=99,in_port=1
- OpenFlow actions=resubmit(,2)
-
- Resubmitted flow: unchanged
- Resubmitted regs: reg0=0x0 reg1=0x0 reg2=0x0 reg3=0x0 reg4=0x0 reg5=0x0 reg6=0x0 reg7=0x0
- Resubmitted odp: drop
- No match
+ bridge("br0")
+ -------------
+ 0. priority 0
+ resubmit(,1)
+ 1. in_port=1, priority 99
+ resubmit(,2)
+ 2. No match.
+ drop
Final flow: unchanged
+ Megaflow: recirc_id=0,in_port=1,dl_src=00:00:00:00:00:00/01:00:00:00:00:00,dl_dst=00:00:00:00:00:00/ff:ff:ff:ff:ff:f0,dl_type=0x0000
Datapath actions: drop
Example 2: Valid Packet on Access Port
@@ -465,22 +469,20 @@ The output is similar to that for the previous case, except that it
additionally tags the packet with ``p2``'s VLAN 20 before it passes it along to
table 2::
- Flow: metadata=0,in_port=2,vlan_tci=0x0000,dl_src=00:00:00:00:00:00,dl_dst=00:00:00:00:00:00,dl_type=0x0000
- Rule: table=0 cookie=0 priority=0
- OpenFlow actions=resubmit(,1)
-
- Resubmitted flow: unchanged
- Resubmitted regs: reg0=0x0 reg1=0x0 reg2=0x0 reg3=0x0 reg4=0x0 reg5=0x0 reg6=0x0 reg7=0x0
- Resubmitted odp: drop
- Rule: table=1 cookie=0 priority=99,in_port=2,vlan_tci=0x0000
- OpenFlow actions=mod_vlan_vid:20,resubmit(,2)
+ Flow: in_port=2,vlan_tci=0x0000,dl_src=00:00:00:00:00:00,dl_dst=00:00:00:00:00:00,dl_type=0x0000
- Resubmitted flow: metadata=0,in_port=2,dl_vlan=20,dl_vlan_pcp=0,dl_src=00:00:00:00:00:00,dl_dst=00:00:00:00:00:00,dl_type=0x0000
- Resubmitted regs: reg0=0x0 reg1=0x0 reg2=0x0 reg3=0x0 reg4=0x0 reg5=0x0 reg6=0x0 reg7=0x0
- Resubmitted odp: drop
- No match
+ bridge("br0")
+ -------------
+ 0. priority 0
+ resubmit(,1)
+ 1. in_port=2,vlan_tci=0x0000, priority 99
+ mod_vlan_vid:20
+ resubmit(,2)
+ 2. No match.
+ drop
- Final flow: unchanged
+ Final flow: in_port=2,dl_vlan=20,dl_vlan_pcp=0,dl_src=00:00:00:00:00:00,dl_dst=00:00:00:00:00:00,dl_type=0x0000
+ Megaflow: recirc_id=0,in_port=2,vlan_tci=0x0000,dl_src=00:00:00:00:00:00/01:00:00:00:00:00,dl_dst=00:00:00:00:00:00/ff:ff:ff:ff:ff:f0,dl_type=0x0000
Datapath actions: drop
Example 3: Invalid Packet on Access Port
@@ -491,19 +493,19 @@ access port ``p2``::
$ ovs-appctl ofproto/trace br0 in_port=2,vlan_tci=5
-The output shows the packet matching the default drop rule::
+The output shows the packet matching the default drop flow::
- Flow: metadata=0,in_port=2,vlan_tci=0x0005,dl_src=00:00:00:00:00:00,dl_dst=00:00:00:00:00:00,dl_type=0x0000
- Rule: table=0 cookie=0 priority=0
- OpenFlow actions=resubmit(,1)
+ Flow: in_port=2,vlan_tci=0x0005,dl_src=00:00:00:00:00:00,dl_dst=00:00:00:00:00:00,dl_type=0x0000
- Resubmitted flow: unchanged
- Resubmitted regs: reg0=0x0 reg1=0x0 reg2=0x0 reg3=0x0 reg4=0x0 reg5=0x0 reg6=0x0 reg7=0x0
- Resubmitted odp: drop
- Rule: table=1 cookie=0 priority=0
- OpenFlow actions=drop
+ bridge("br0")
+ -------------
+ 0. priority 0
+ resubmit(,1)
+ 1. priority 0
+ drop
Final flow: unchanged
+ Megaflow: recirc_id=0,in_port=2,vlan_tci=0x0005,dl_src=00:00:00:00:00:00/01:00:00:00:00:00,dl_dst=00:00:00:00:00:00/ff:ff:ff:ff:ff:f0,dl_type=0x0000
Datapath actions: drop
Implementing Table 2: MAC+VLAN Learning for Ingress Port
@@ -571,8 +573,27 @@ Try the following test command::
$ ovs-appctl ofproto/trace br0 \
in_port=1,vlan_tci=20,dl_src=50:00:00:00:00:01 -generate
-The output shows that "learn" was executed, but it isn't otherwise informative,
-so we won't include it here.
+The output shows that "learn" was executed in table 2 and the
+particular flow that was added:
+
+ Flow: in_port=1,vlan_tci=0x0014,dl_src=50:00:00:00:00:01,dl_dst=00:00:00:00:00:00,dl_type=0x0000
+
+ bridge("br0")
+ -------------
+ 0. priority 0
+ resubmit(,1)
+ 1. in_port=1, priority 99
+ resubmit(,2)
+ 2. priority 32768
+ learn(table=10,NXM_OF_VLAN_TCI[0..11],NXM_OF_ETH_DST[]=NXM_OF_ETH_SRC[],load:NXM_OF_IN_PORT[]->NXM_NX_REG0[0..15])
+ -> table=10 vlan_tci=0x0014/0x0fff,dl_dst=50:00:00:00:00:01 priority=32768 actions=load:0x1->NXM_NX_REG0[0..15]
+ resubmit(,3)
+ 3. No match.
+ drop
+
+ Final flow: unchanged
+ Megaflow: recirc_id=0,in_port=1,vlan_tci=0x0014/0x1fff,dl_src=50:00:00:00:00:01,dl_dst=00:00:00:00:00:00/ff:ff:ff:ff:ff:f0,dl_type=0x0000
+ Datapath actions: drop
The ``-generate`` keyword is new. Ordinarily, ``ofproto/trace`` has no side
effects: "output" actions do not actually output packets, "learn" actions do
@@ -662,22 +683,35 @@ on ``p1`` in VLAN ``20``::
in_port=1,dl_vlan=20,dl_src=f0:00:00:00:00:01,dl_dst=90:00:00:00:00:01 \
-generate
-Here's an excerpt from the output that shows (from the "no match" looking up
-the resubmit to table 10) that the flow's destination was unknown::
+The output shows (from the "no match" looking up the resubmit to
+table 10) that the flow's destination was unknown::
+
+ Flow: in_port=1,dl_vlan=20,dl_vlan_pcp=0,dl_src=f0:00:00:00:00:01,dl_dst=90:00:00:00:00:01,dl_type=0x0000
+
+ bridge("br0")
+ -------------
+ 0. priority 0
+ resubmit(,1)
+ 1. in_port=1, priority 99
+ resubmit(,2)
+ 2. priority 32768
+ learn(table=10,NXM_OF_VLAN_TCI[0..11],NXM_OF_ETH_DST[]=NXM_OF_ETH_SRC[],load:NXM_OF_IN_PORT[]->NXM_NX_REG0[0..15])
+ -> table=10 vlan_tci=0x0014/0x0fff,dl_dst=f0:00:00:00:00:01 priority=32768 actions=load:0x1->NXM_NX_REG0[0..15]
+ resubmit(,3)
+ 3. priority 50
+ resubmit(,10)
+ 10. No match.
+ drop
+ resubmit(,4)
+ 4. No match.
+ drop
- Resubmitted flow: unchanged
- Resubmitted regs: reg0=0x0 reg1=0x0 reg2=0x0 reg3=0x0 reg4=0x0 reg5=0x0 reg6=0x0 reg7=0x0
- Resubmitted odp: drop
- Rule: table=3 cookie=0 priority=50
- OpenFlow actions=resubmit(,10),resubmit(,4)
-
- Resubmitted flow: unchanged
- Resubmitted regs: reg0=0x0 reg1=0x0 reg2=0x0 reg3=0x0 reg4=0x0 reg5=0x0 reg6=0x0 reg7=0x0
- Resubmitted odp: drop
- No match
+ Final flow: unchanged
+ Megaflow: recirc_id=0,in_port=1,dl_vlan=20,dl_src=f0:00:00:00:00:01,dl_dst=90:00:00:00:00:01,dl_type=0x0000
+ Datapath actions: drop
-You can verify that the packet's source was learned two ways. The most direct
-way is to dump the learning table with::
+There are two ways that you can verify that the packet's source was
+learned. The most direct way is to dump the learning table with::
$ ovs-ofctl dump-flows br0 table=10
@@ -698,16 +732,35 @@ that we just learned on p1:
$ ovs-appctl ofproto/trace br0 \
in_port=2,dl_src=90:00:00:00:00:01,dl_dst=f0:00:00:00:00:01 -generate
-Here's an interesting excerpt from that command's output. This group of lines
-traces the ``resubmit(,10)``, showing that the packet matched the learned flow
-for the first MAC we used, loading the OpenFlow port number for the learned
-port ``p1`` into register ``0``::
-
- Resubmitted flow: unchanged
- Resubmitted regs: reg0=0x0 reg1=0x0 reg2=0x0 reg3=0x0 reg4=0x0 reg5=0x0 reg6=0x0 reg7=0x0
- Resubmitted odp: drop
- Rule: table=10 cookie=0 vlan_tci=0x0014/0x0fff,dl_dst=f0:00:00:00:00:01
- OpenFlow actions=load:0x1->NXM_NX_REG0[0..15]
+Here is this command's output. Take a look at the lines that trace
+the ``resubmit(,10)``, showing that the packet matched the learned
+flow for the first MAC we used, loading the OpenFlow port number for
+the learned port ``p1`` into register ``0``::
+
+ Flow: in_port=2,vlan_tci=0x0000,dl_src=90:00:00:00:00:01,dl_dst=f0:00:00:00:00:01,dl_type=0x0000
+
+ bridge("br0")
+ -------------
+ 0. priority 0
+ resubmit(,1)
+ 1. in_port=2,vlan_tci=0x0000, priority 99
+ mod_vlan_vid:20
+ resubmit(,2)
+ 2. priority 32768
+ learn(table=10,NXM_OF_VLAN_TCI[0..11],NXM_OF_ETH_DST[]=NXM_OF_ETH_SRC[],load:NXM_OF_IN_PORT[]->NXM_NX_REG0[0..15])
+ -> table=10 vlan_tci=0x0014/0x0fff,dl_dst=90:00:00:00:00:01 priority=32768 actions=load:0x2->NXM_NX_REG0[0..15]
+ resubmit(,3)
+ 3. priority 50
+ resubmit(,10)
+ 10. vlan_tci=0x0014/0x0fff,dl_dst=f0:00:00:00:00:01, priority 32768
+ load:0x1->NXM_NX_REG0[0..15]
+ resubmit(,4)
+ 4. No match.
+ drop
+
+ Final flow: reg0=0x1,in_port=2,dl_vlan=20,dl_vlan_pcp=0,dl_src=90:00:00:00:00:01,dl_dst=f0:00:00:00:00:01,dl_type=0x0000
+ Megaflow: recirc_id=0,in_port=2,vlan_tci=0x0000,dl_src=90:00:00:00:00:01,dl_dst=f0:00:00:00:00:01,dl_type=0x0000
+ Datapath actions: drop
If you read the commands above carefully, then you might have noticed that they
simply have the Ethernet source and destination addresses exchanged. That
@@ -717,13 +770,28 @@ means that if we now rerun the first ``ovs-appctl`` command above, e.g.:
in_port=1,dl_vlan=20,dl_src=f0:00:00:00:00:01,dl_dst=90:00:00:00:00:01 \
-generate
-then we see in the output that the destination has now been learned::
-
- Resubmitted flow: unchanged
- Resubmitted regs: reg0=0x0 reg1=0x0 reg2=0x0 reg3=0x0 reg4=0x0 reg5=0x0 reg6=0x0 reg7=0x0
- Resubmitted odp: drop
- Rule: table=10 cookie=0 vlan_tci=0x0014/0x0fff,dl_dst=90:00:00:00:00:01
- OpenFlow actions=load:0x2->NXM_NX_REG0[0..15]
+then we see in the output, looking at the indented "load" action
+executed in table 10, that the destination has now been learned::
+
+ Flow: in_port=1,dl_vlan=20,dl_vlan_pcp=0,dl_src=f0:00:00:00:00:01,dl_dst=90:00:00:00:00:01,dl_type=0x0000
+
+ bridge("br0")
+ -------------
+ 0. priority 0
+ resubmit(,1)
+ 1. in_port=1, priority 99
+ resubmit(,2)
+ 2. priority 32768
+ learn(table=10,NXM_OF_VLAN_TCI[0..11],NXM_OF_ETH_DST[]=NXM_OF_ETH_SRC[],load:NXM_OF_IN_PORT[]->NXM_NX_REG0[0..15])
+ -> table=10 vlan_tci=0x0014/0x0fff,dl_dst=f0:00:00:00:00:01 priority=32768 actions=load:0x1->NXM_NX_REG0[0..15]
+ resubmit(,3)
+ 3. priority 50
+ resubmit(,10)
+ 10. vlan_tci=0x0014/0x0fff,dl_dst=90:00:00:00:00:01, priority 32768
+ load:0x2->NXM_NX_REG0[0..15]
+ resubmit(,4)
+ 4. No match.
+ drop
Implementing Table 4: Output Processing
@@ -761,7 +829,7 @@ in copies output to access ports::
EOF
.. note::
- Our rules rely on the standard OpenFlow behavior that an output action will
+ Our flows rely on the standard OpenFlow behavior that an output action will
not forward a packet back out the port it came in on. That is, if a packet
comes in on p1, and we've learned that the packet's destination MAC is also
on p1, so that we end up with ``actions=1`` as our actions, the switch will
@@ -1740,30 +1740,21 @@ nxm_execute_stack_push(const struct ofpact_stack *push,
nx_stack_push(stack, &dst_value);
}
-void
+bool
nxm_execute_stack_pop(const struct ofpact_stack *pop,
struct flow *flow, struct flow_wildcards *wc,
struct ofpbuf *stack)
{
- union mf_subvalue *src_value;
-
- src_value = nx_stack_pop(stack);
-
- /* Only pop if stack is not empty. Otherwise, give warning. */
- if (src_value) {
- union mf_subvalue mask_value;
-
- memset(&mask_value, 0xff, sizeof mask_value);
- mf_write_subfield_flow(&pop->subfield, &mask_value, &wc->masks);
- mf_write_subfield_flow(&pop->subfield, src_value, flow);
- } else {
- if (!VLOG_DROP_WARN(&rl)) {
- char *flow_str = flow_to_string(flow);
- VLOG_WARN_RL(&rl, "Failed to pop from an empty stack. On flow\n"
- " %s", flow_str);
- free(flow_str);
- }
+ union mf_subvalue *src_value = nx_stack_pop(stack);
+ if (!src_value) {
+ return false;
}
+
+ union mf_subvalue mask_value;
+ memset(&mask_value, 0xff, sizeof mask_value);
+ mf_write_subfield_flow(&pop->subfield, &mask_value, &wc->masks);
+ mf_write_subfield_flow(&pop->subfield, src_value, flow);
+ return true;
}
/* Formats 'sf' into 's' in a format normally acceptable to
@@ -129,9 +129,9 @@ enum ofperr nxm_stack_pop_check(const struct ofpact_stack *,
void nxm_execute_stack_push(const struct ofpact_stack *,
const struct flow *, struct flow_wildcards *,
struct ofpbuf *);
-void nxm_execute_stack_pop(const struct ofpact_stack *,
- struct flow *, struct flow_wildcards *,
- struct ofpbuf *);
+bool nxm_execute_stack_pop(const struct ofpact_stack *,
+ struct flow *, struct flow_wildcards *,
+ struct ofpbuf *);
ovs_be64 oxm_bitmap_from_mf_bitmap(const struct mf_bitmap *, enum ofp_version);
struct mf_bitmap oxm_bitmap_to_mf_bitmap(ovs_be64 oxm_bitmap,
@@ -23,165 +23,82 @@
#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)
-{
- 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');
-
- 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');
-}
-
-static void
-trace_format_flow(struct ds *result, int level, const char *title,
- struct trace_ctx *trace)
+struct oftrace_node *
+oftrace_report(struct ovs_list *super, enum oftrace_node_type type,
+ const char *text)
{
- 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;
- }
- ds_put_char(result, '\n');
+ struct oftrace_node *node = xmalloc(sizeof *node);
+ ovs_list_push_back(super, &node->node);
+ node->type = type;
+ node->name = xstrdup(text);
+ node->always_indent = false;
+ ovs_list_init(&node->subs);
+
+ return node;
}
-static void
-trace_format_regs(struct ds *result, int level, const char *title,
- struct trace_ctx *trace)
+static bool
+oftrace_node_type_is_terminal(enum oftrace_node_type type)
{
- 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]);
+ 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');
-}
-static void
-trace_format_odp(struct ds *result, int level, const char *title,
- struct trace_ctx *trace)
-{
- 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');
+ OVS_NOT_REACHED();
}
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) {
+ bool more = sub->node.next != nodes || sub->always_indent || oftrace_node_type_is_terminal(sub->type);
+ bool title = sub->type == OFT_BRIDGE;
-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\".");
+ if (title) {
+ ds_put_char(output, '\n');
+ }
+ ds_put_char_multiple(output, ' ', (level + more) * 4);
+ switch (sub->type) {
+ case OFT_DETAIL:
+ ds_put_format(output, " -> %s\n", sub->name);
+ break;
+ case OFT_WARN:
+ ds_put_format(output, " >> %s\n", sub->name);
+ break;
+ case OFT_ERROR:
+ ds_put_format(output, " >>>> %s <<<<\n", sub->name);
+ break;
+ case OFT_BRIDGE:
+ ds_put_format(output, "%s\n", sub->name);
+ ds_put_char_multiple(output, ' ', (level + more) * 4);
+ ds_put_char_multiple(output, '-', strlen(sub->name));
+ ds_put_char(output, '\n');
+ break;
+ case OFT_TABLE:
+ case OFT_THAW:
+ case OFT_ACTION:
+ ds_put_format(output, "%s\n", sub->name);
+ 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 +383,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 +395,74 @@ 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');
- 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);
+ 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');
+
+ 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);
}
void
@@ -15,6 +15,31 @@
#ifndef OFPROTO_DPIF_TRACE_H
#define OFPROTO_DPIF_TRACE_H 1
+#include "openvswitch/compiler.h"
+#include "openvswitch/list.h"
+
+enum oftrace_node_type {
+ OFT_BRIDGE, /* Packet travel through an OpenFlow switch. */
+ OFT_TABLE, /* Packet travel through a flow table. */
+ OFT_THAW, /* Thawing a frozen state. */
+ OFT_ACTION, /* An action. */
+ OFT_DETAIL, /* Some detail of an action. */
+ OFT_WARN, /* A worrisome situation. */
+ OFT_ERROR, /* An erroneous situation, worth logging. */
+};
+
+struct oftrace_node {
+ struct ovs_list node; /* In parent. */
+
+ enum oftrace_node_type type;
+ const char *name;
+ bool always_indent;
+ struct ovs_list subs; /* List of "struct oftrace_node" children. */
+};
+
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 */
@@ -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);
@@ -553,43 +549,166 @@ 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, ...)
+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);
}
+ return subtrace;
+}
+
+/* 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) && 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);
}
-static struct vlog_rate_limit error_report_rl = VLOG_RATE_LIMIT_INIT(1, 5);
+/* 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) && 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,
+static struct ovs_list *
+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)) {
+ struct ovs_list *subtrace = NULL;
+ 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));
+ subtrace = &oftrace_report(ctx->xin->trace, type, ds_cstr(&s))->subs;
+ ds_destroy(&s);
+ }
+ return subtrace;
+}
+
+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);
+ }
+}
+
+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);
+}
+
+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);
}
}
@@ -1466,10 +1585,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 +1672,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 +1692,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 +1730,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 +1820,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 +1856,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 +1873,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 +1890,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 +2063,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 +2077,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 +2089,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 +2102,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 +2145,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 +2156,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 +2208,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 +2218,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 +2227,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 +2238,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 +2266,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 +2292,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 +2320,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 +2350,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 +2377,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 +2437,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 +2447,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 +2484,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 +2512,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 +2537,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 +2553,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 +2561,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 +2581,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 +2600,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);
}
}
@@ -2744,8 +2879,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
@@ -2794,18 +2928,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;
}
@@ -2816,7 +2951,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) {
@@ -2836,7 +2972,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);
@@ -2908,38 +3044,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;
}
@@ -2955,6 +3095,7 @@ compose_output_action__(struct xlate_ctx *ctx, ofp_port_t ofp_port,
struct ofpbuf old_stack = ctx->stack;
union mf_subvalue new_stack[1024 / sizeof(union mf_subvalue)];
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);
@@ -2969,6 +3110,8 @@ compose_output_action__(struct xlate_ctx *ctx, ofp_port_t ofp_port,
flow->actset_output = OFPP_UNSET;
ctx->conntracked = false;
clear_conntrack(flow);
+ 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
@@ -3020,6 +3163,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;
}
@@ -3099,12 +3243,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) {
@@ -3118,10 +3262,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 */
}
@@ -3230,7 +3374,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;
@@ -3239,24 +3382,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;
@@ -3287,9 +3429,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
@@ -3303,7 +3442,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;
@@ -3339,11 +3482,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);
@@ -3558,6 +3699,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);
@@ -3771,7 +3914,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;
}
@@ -3826,10 +3969,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;
@@ -3851,10 +3994,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);
@@ -3883,6 +4026,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;
}
}
@@ -3934,6 +4079,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;
}
@@ -3976,7 +4122,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;
}
@@ -3997,12 +4143,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);
}
}
@@ -4022,7 +4172,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:
@@ -4035,9 +4186,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;
}
@@ -4050,7 +4200,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;
}
@@ -4139,6 +4289,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);
}
@@ -4168,6 +4319,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);
@@ -4177,10 +4351,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");
}
}
@@ -4233,11 +4409,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;
}
@@ -4248,9 +4422,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;
}
@@ -4281,9 +4454,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);
}
}
@@ -4369,16 +4542,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);
}
@@ -4521,13 +4700,14 @@ 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) {
if (ofc->alg == IPPORT_FTP) {
nl_msg_put_string(odp_actions, OVS_CT_ATTR_HELPER, "ftp");
} else {
- VLOG_WARN("Cannot serialize ct_helper %d\n", ofc->alg);
+ xlate_report_error(ctx, "cannot serialize ct_helper %d", ofc->alg);
}
}
}
@@ -4621,7 +4801,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);
@@ -4736,6 +4916,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)
{
@@ -4748,6 +4956,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;
@@ -4770,6 +4983,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,
@@ -4926,12 +5146,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:
@@ -4944,6 +5167,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;
@@ -4953,8 +5181,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:
@@ -4997,6 +5224,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:
@@ -5016,34 +5244,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;
@@ -5051,6 +5274,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:
@@ -5125,10 +5349,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;
@@ -5387,7 +5609,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,
@@ -5430,17 +5651,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;
}
@@ -5453,10 +5674,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;
@@ -5468,7 +5688,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(flow);
@@ -5489,7 +5710,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;
@@ -5502,14 +5723,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;
}
@@ -5524,7 +5746,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;
}
@@ -5552,9 +5774,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,
@@ -5586,12 +5806,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;
@@ -5860,10 +6077,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);
}
@@ -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);
+ /* If nonnull, this indicates that the translation is being traced. It
+ * points to the list of oftrace nodes to which the translation should add
+ * tracing information (with oftrace_node_append()). */
+ 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;
@@ -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
@@ -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 *);
@@ -3823,7 +3823,7 @@ do
AT_CHECK([ovs-appctl ofproto/trace ovs-dummy "$flow"], [0], [stdout])
: > expout
if test $mode = drop && test $type != no; then
- echo 'Packets dropped because they are IP fragments and the fragment handling mode is "drop".' >> expout
+ echo ' 0. Packets are IP fragments and the fragment handling mode is "drop".' >> expout
echo "Datapath actions: $exp_output" >> expout
elif test $type = later; then
echo "Datapath actions: $exp_output" >> expout
@@ -4873,9 +4873,10 @@ AT_CHECK([ovs-appctl ofproto/trace \
AT_CHECK([tail -1 stdout], [0], [dnl
Datapath actions: 2
])
-AT_CHECK([head -n 2 stdout], [0], [dnl
-Bridge: br0
+AT_CHECK([head -n 3 stdout], [0], [dnl
Flow: pkt_mark=0x2,skb_priority=0x1,arp,in_port=1,vlan_tci=0x0000,dl_src=50:54:00:00:00:01,dl_dst=50:54:00:00:00:02,arp_spa=0.0.0.0,arp_tpa=0.0.0.0,arp_op=0,arp_sha=00:00:00:00:00:00,arp_tha=00:00:00:00:00:00
+
+bridge("br0")
])
# Test command: ofproto/trace dp_name odp_flow packet
@@ -4884,9 +4885,10 @@ AT_CHECK([ovs-appctl ofproto/trace ovs-dummy \
AT_CHECK([tail -1 stdout], [0], [dnl
Datapath actions: 2
])
-AT_CHECK([head -n 2 stdout], [0], [dnl
-Bridge: br0
+AT_CHECK([head -n 3 stdout], [0], [dnl
Flow: pkt_mark=0x2,skb_priority=0x1,arp,in_port=1,vlan_tci=0x0000,dl_src=50:54:00:00:00:01,dl_dst=50:54:00:00:00:02,arp_spa=0.0.0.0,arp_tpa=0.0.0.0,arp_op=0,arp_sha=00:00:00:00:00:00,arp_tha=00:00:00:00:00:00
+
+bridge("br0")
])
# Test command: ofproto/trace br_name br_flow packet
@@ -4895,9 +4897,10 @@ AT_CHECK([ovs-appctl ofproto/trace br0 \
AT_CHECK([tail -1 stdout], [0], [dnl
Datapath actions: 1
])
-AT_CHECK([head -n 2 stdout], [0], [dnl
-Bridge: br0
+AT_CHECK([head -n 3 stdout], [0], [dnl
Flow: pkt_mark=0x1,skb_priority=0x2,arp,in_port=2,vlan_tci=0x0000,dl_src=50:54:00:00:00:02,dl_dst=50:54:00:00:00:01,arp_spa=0.0.0.0,arp_tpa=0.0.0.0,arp_op=0,arp_sha=00:00:00:00:00:00,arp_tha=00:00:00:00:00:00
+
+bridge("br0")
])
OVS_VSWITCHD_STOP
@@ -5032,12 +5035,12 @@ AT_CHECK([ovs-appctl dpif/dump-flows -m br0 | sed 's/, packets.*$//' > dp_flows1
odp_flow=`cat dp_flows1.txt`
AT_CHECK([ovs-appctl ofproto/trace "$odp_flow" | sed 's/\([[Ff]]low:\).*/\1 <cleared>/'], [0], [dnl
-Bridge: br0
Flow: <cleared>
-No match, packets dropped because OFPPC_NO_PACKET_IN is set on in_port.
-Rule: table=254 cookie=0 priority=0,reg0=0x2
-OpenFlow actions=drop
+bridge("br0")
+-------------
+ 0. No match.
+ drop
Final flow: <cleared>
Megaflow: <cleared>
@@ -5053,12 +5056,12 @@ AT_CHECK([ovs-appctl dpif/dump-flows -m br0 | sed 's/, packets.*$//' > dp_flows2
odp_flow=`cat dp_flows2.txt`
AT_CHECK([ovs-appctl ofproto/trace "$odp_flow" | sed 's/\([[Ff]]low:\).*/\1 <cleared>/'], [0], [dnl
-Bridge: br0
Flow: <cleared>
-No match, packets dropped because OFPPC_NO_PACKET_IN is set on in_port.
-Rule: table=254 cookie=0 priority=0,reg0=0x2
-OpenFlow actions=drop
+bridge("br0")
+-------------
+ 0. No match.
+ drop
Final flow: <cleared>
Megaflow: <cleared>
@@ -5728,7 +5731,7 @@ AT_CHECK([ovs-appctl ofproto/trace br0 in_port=LOCAL,dl_src=10:20:30:40:50:60],
AT_CHECK([tail -1 stdout], [0], [Datapath actions: 2
])
dnl the output(port=1,max_len=100) fails the translation, only output:2 in datapath
-AT_CHECK([grep "output_trunc does not support port: [[0-9]]*" stdout], [0], [stdout])
+AT_CHECK([grep "output_trunc does not support patch port [[0-9]]*" stdout], [0], [stdout])
OVS_VSWITCHD_STOP
AT_CLEANUP
@@ -7125,11 +7128,11 @@ AT_CHECK([strip_ufid < ovs-vswitchd.log | filter_flow_install | strip_used], [0]
recirc_id(0),in_port(100),eth_type(0x0800),ipv4(src=192.168.0.1,frag=no), actions:101,set(ipv4(src=255.255.255.254)),2
])
-AT_CHECK([grep -e '|nx_match|WARN|' ovs-vswitchd.log | sed "s/^.*|WARN|//"], [0], [dnl
-Failed to pop from an empty stack. On flow
+AT_CHECK([grep -e '|ofproto_dpif_xlate|WARN|' ovs-vswitchd.log | sed "s/^.*|WARN|//"], [0], [dnl
+stack underflow while processing icmp,in_port=LOCAL,vlan_tci=0x0000,dl_src=50:54:00:00:00:05,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,icmp_type=8,icmp_code=0 on bridge br1
])
-OVS_VSWITCHD_STOP(["/Failed to pop from an empty stack/d"])
+OVS_VSWITCHD_STOP(["/stack underflow/d"])
AT_CLEANUP
AT_SETUP([ofproto-dpif - port duration])
@@ -2303,7 +2303,7 @@ test_arp() {
local request=ffffffffffff${sha}08060001080006040001${sha}${spa}ffffffffffff${tpa}
hv=hv`vif_to_hv $inport`
as $hv ovs-appctl netdev-dummy/receive vif$inport $request
- #as $hv ovs-appctl ofproto/trace br-int in_port=$inport $request
+ as $hv ovs-appctl ofproto/trace br-int in_port=$inport $request
# Expect to receive the broadcast ARP on the other logical switch ports if
# IP address is not configured to the switch patch port.
@@ -6073,7 +6073,7 @@ src_ip=`ip_to_hex 192 168 1 2`
dst_ip=`ip_to_hex 172 16 1 3`
packet=${dst_mac}${src_mac}08004500001c0000000040110000${src_ip}${dst_ip}0035111100080000
as hv1 ovs-appctl netdev-dummy/receive hv1-vif1 $packet
-#as hv1 ovs-appctl ofproto/trace br-int in_port=1 $packet
+as hv1 ovs-appctl ofproto/trace br-int in_port=1 $packet
# Send ip packets between bar1 and bob1
src_mac="f00000010204"
@@ -213,10 +213,10 @@ port p2: RSTP state changed from Disabled to Discarding
])
AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'in_port(7),eth(src=50:54:00:00:00:09,dst=50:54:00:00:00:0a),eth_type(0x0800),ipv4(src=10.0.0.2,dst=10.0.0.1,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0)' | grep STP], [0], [dnl
-RSTP not in forwarding state, skipping output
+ >> RSTP not in forwarding state, skipping output
])
AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'in_port(8),eth(src=50:54:00:00:00:0b,dst=50:54:00:00:00:0c),eth_type(0x0800),ipv4(src=10.0.0.3,dst=10.0.0.4,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0)' | grep STP], [0], [dnl
-RSTP not in forwarding state, skipping output
+ >> RSTP not in forwarding state, skipping output
])
#
@@ -428,10 +428,10 @@ port p2: STP state changed from disabled to listening
])
AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'in_port(7),eth(src=50:54:00:00:00:09,dst=50:54:00:00:00:0a),eth_type(0x0800),ipv4(src=10.0.0.2,dst=10.0.0.1,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0)' | grep STP], [0], [dnl
-STP not in forwarding state, skipping output
+ >> STP not in forwarding state, skipping output
])
AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'in_port(8),eth(src=50:54:00:00:00:0b,dst=50:54:00:00:00:0c),eth_type(0x0800),ipv4(src=10.0.0.3,dst=10.0.0.4,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0)' | grep STP], [0], [dnl
-STP not in forwarding state, skipping output
+ >> STP not in forwarding state, skipping output
])
# give time for STP to synchronize