bool
oftrace_add_recirc_node(struct ovs_list *recirc_queue,
enum oftrace_recirc_type type, const struct flow *flow,
+ const struct ofpact_nat *ofn,
const struct dp_packet *packet, uint32_t recirc_id,
const uint16_t zone)
{
node->flow = *flow;
node->flow.recirc_id = recirc_id;
node->flow.ct_zone = zone;
+ node->nat_act = ofn;
node->packet = packet ? dp_packet_clone(packet) : NULL;
return true;
}
}
+static void
+oftrace_print_ip_flow(const struct flow *flow, int af, struct ds *output)
+{
+ if (af == AF_INET) {
+ ds_put_format(output, "nw_src="IP_FMT",tp_src=%"PRIu16","
+ "nw_dst="IP_FMT",tp_dst=%"PRIu16,
+ IP_ARGS(flow->nw_src), ntohs(flow->tp_src),
+ IP_ARGS(flow->nw_dst), ntohs(flow->tp_dst));
+ } else if (af == AF_INET6) {
+ ds_put_cstr(output, "ipv6_src=");
+ ipv6_format_addr_bracket(&flow->ipv6_src, output, true);
+ ds_put_format(output, ",tp_src=%"PRIu16, ntohs(flow->tp_src));
+ ds_put_cstr(output, ",ipv6_dst=");
+ ipv6_format_addr_bracket(&flow->ipv6_dst, output, true);
+ ds_put_format(output, ",tp_dst=%"PRIu16, ntohs(flow->tp_dst));
+ }
+ ds_put_char(output, '\n');
+}
+
/* Parses the 'argc' elements of 'argv', ignoring argv[0]. The following
* forms are supported:
*
ofpbuf_uninit(&pruned_actions);
}
+static void
+ofproto_trace_recirc_node(struct oftrace_recirc_node *node,
+ struct ovs_list *next_ct_states,
+ struct ds *output)
+{
+ ds_put_cstr(output, "\n\n");
+ ds_put_char_multiple(output, '=', 79);
+ ds_put_format(output, "\nrecirc(%#"PRIx32")", node->recirc_id);
+
+ if (next_ct_states && node->type == OFT_RECIRC_CONNTRACK) {
+ uint32_t ct_state;
+ if (ovs_list_is_empty(next_ct_states)) {
+ ct_state = CS_TRACKED | CS_NEW;
+ ds_put_cstr(output, " - resume conntrack with default "
+ "ct_state=trk|new (use --ct-next to customize)");
+ } else {
+ ct_state = oftrace_pop_ct_state(next_ct_states);
+ struct ds s = DS_EMPTY_INITIALIZER;
+ format_flags(&s, ct_state_to_string, ct_state, '|');
+ ds_put_format(output, " - resume conntrack with ct_state=%s",
+ ds_cstr(&s));
+ ds_destroy(&s);
+ }
+ node->flow.ct_state = ct_state;
+ }
+ ds_put_char(output, '\n');
+
+ /* If there's any snat/dnat information assume we always translate to
+ * the first IP/port to make sure we don't match on incorrect flows later
+ * on.
+ */
+ if (node->nat_act) {
+ const struct ofpact_nat *ofn = node->nat_act;
+
+ ds_put_cstr(output, "Replacing src/dst IP/ports to simulate NAT:\n");
+ ds_put_cstr(output, " Initial flow: ");
+ oftrace_print_ip_flow(&node->flow, ofn->range_af, output);
+
+ if (ofn->flags & NX_NAT_F_SRC) {
+ if (ofn->range_af == AF_INET) {
+ node->flow.nw_src = ofn->range.addr.ipv4.min;
+ } else if (ofn->range_af == AF_INET6) {
+ node->flow.ipv6_src = ofn->range.addr.ipv6.min;
+ }
+
+ if (ofn->range_af != AF_UNSPEC && ofn->range.proto.min) {
+ node->flow.tp_src = htons(ofn->range.proto.min);
+ }
+ }
+ if (ofn->flags & NX_NAT_F_DST) {
+ if (ofn->range_af == AF_INET) {
+ node->flow.nw_dst = ofn->range.addr.ipv4.min;
+ } else if (ofn->range_af == AF_INET6) {
+ node->flow.ipv6_dst = ofn->range.addr.ipv6.min;
+ }
+
+ if (ofn->range_af != AF_UNSPEC && ofn->range.proto.min) {
+ node->flow.tp_dst = htons(ofn->range.proto.min);
+ }
+ }
+ ds_put_cstr(output, " Modified flow: ");
+ oftrace_print_ip_flow(&node->flow, ofn->range_af, output);
+ }
+ ds_put_char_multiple(output, '=', 79);
+ ds_put_cstr(output, "\n\n");
+}
+
static void
ofproto_trace__(struct ofproto_dpif *ofproto, const struct flow *flow,
const struct dp_packet *packet, struct ovs_list *recirc_queue,
struct oftrace_recirc_node *recirc_node;
LIST_FOR_EACH_POP (recirc_node, node, &recirc_queue) {
- ds_put_cstr(output, "\n\n");
- ds_put_char_multiple(output, '=', 79);
- ds_put_format(output, "\nrecirc(%#"PRIx32")",
- recirc_node->recirc_id);
-
- if (next_ct_states && recirc_node->type == OFT_RECIRC_CONNTRACK) {
- uint32_t ct_state;
- if (ovs_list_is_empty(next_ct_states)) {
- ct_state = CS_TRACKED | CS_NEW;
- ds_put_cstr(output, " - resume conntrack with default "
- "ct_state=trk|new (use --ct-next to customize)");
- } else {
- ct_state = oftrace_pop_ct_state(next_ct_states);
- struct ds s = DS_EMPTY_INITIALIZER;
- format_flags(&s, ct_state_to_string, ct_state, '|');
- ds_put_format(output, " - resume conntrack with ct_state=%s",
- ds_cstr(&s));
- ds_destroy(&s);
- }
- recirc_node->flow.ct_state = ct_state;
- }
- ds_put_char(output, '\n');
- ds_put_char_multiple(output, '=', 79);
- ds_put_cstr(output, "\n\n");
-
+ ofproto_trace_recirc_node(recirc_node, next_ct_states, output);
ofproto_trace__(ofproto, &recirc_node->flow, recirc_node->packet,
&recirc_queue, ofpacts, ofpacts_len, output);
oftrace_recirc_node_destroy(recirc_node);
OVS_VSWITCHD_STOP
AT_CLEANUP
+AT_SETUP([ofproto-dpif - nat - ofproto/trace])
+OVS_VSWITCHD_START
+
+add_of_ports br0 1 2 3
+
+flow="in_port=1,udp,nw_src=1.1.1.1,nw_dst=1.1.1.2,udp_src=100,udp_dst=200"
+AT_DATA([flows.txt], [dnl
+table=0,priority=100,ip,nw_src=1.1.1.1,ct_state=-trk,action=ct(commit,nat(src=10.0.0.1-10.0.0.42:1000-1042),table=0)
+table=0,priority=100,udp,ct_state=+trk,nw_src=10.0.0.1,nw_dst=1.1.1.2,tp_src=1000,tp_dst=200,action=ct(commit,nat(dst=20.0.0.1-20.0.0.42:2000-2042),table=0)
+table=0,priority=100,udp,ct_state=+trk,nw_src=10.0.0.1,nw_dst=20.0.0.1,tp_src=1000,tp_dst=2000,action=3
+table=0,priority=90,ip,ct_state=+trk,action=2
+])
+AT_CHECK([ovs-ofctl del-flows br0])
+AT_CHECK([ovs-ofctl add-flows br0 flows.txt])
+AT_CHECK([ovs-appctl ofproto/trace br0 "$flow"], [0], [stdout])
+AT_CHECK([tail -1 stdout], [0],
+ [Datapath actions: 3
+])
+
+flow="in_port=1,udp6,ipv6_src=1::1,ipv6_dst=1::2,udp_src=100,udp_dst=200"
+AT_DATA([flows.txt], [dnl
+table=0,priority=100,ip6,ipv6_src=1::1,ct_state=-trk,action=ct(commit,nat(src=[[10::1]]-[[10::42]]:1000-1042),table=0)
+table=0,priority=100,udp6,ct_state=+trk,ipv6_src=10::1,ipv6_dst=1::2,tp_src=1000,tp_dst=200,action=ct(commit,nat(dst=[[20::1]]-[[20::42]]:2000-2042),table=0)
+table=0,priority=100,udp6,ct_state=+trk,ipv6_src=10::1,ipv6_dst=20::1,tp_src=1000,tp_dst=2000,action=3
+table=0,priority=90,ip6,ct_state=+trk,action=2
+])
+AT_CHECK([ovs-ofctl del-flows br0])
+AT_CHECK([ovs-ofctl add-flows br0 flows.txt])
+AT_CHECK([ovs-appctl ofproto/trace br0 "$flow"], [0], [stdout])
+AT_CHECK([tail -1 stdout], [0],
+ [Datapath actions: 3
+])
+
+OVS_VSWITCHD_STOP
+AT_CLEANUP
+
AT_SETUP([ofproto - set mtu])
OVS_VSWITCHD_START