[ovs-dev] [PATCH 9/9] ofproto/trace: Support ct_mark and ct_label in --ct-next
Yi-Hung Wei
yihung.wei at gmail.com
Fri Aug 25 22:51:19 UTC 2017
Previously, --ct-next option in ofproto/trace only supports specifying
ct_state. This patch adds support of ct_mark and ct_label.
Signed-off-by: Yi-Hung Wei <yihung.wei at gmail.com>
---
lib/ct-dpif.c | 7 ++++
lib/ct-dpif.h | 3 ++
lib/netlink-conntrack.c | 5 +++
lib/odp-util.c | 3 +-
lib/odp-util.h | 1 +
ofproto/ofproto-dpif-trace.c | 98 ++++++++++++++++++++++++++++----------------
ofproto/ofproto-dpif-trace.h | 7 ++--
ofproto/ofproto-unixctl.man | 16 +++++---
tests/ofproto-dpif.at | 12 +++---
tests/system-traffic.at | 6 +--
10 files changed, 103 insertions(+), 55 deletions(-)
diff --git a/lib/ct-dpif.c b/lib/ct-dpif.c
index 91388dd6681b..07c549707303 100644
--- a/lib/ct-dpif.c
+++ b/lib/ct-dpif.c
@@ -144,6 +144,13 @@ ct_dpif_format_info(const struct ct_dpif_info *info, struct ds *output)
format_flags(&s, ct_state_to_string, info->ct_state, '|');
ds_put_format(output, "ct_state=%s", ds_cstr(&s));
ds_destroy(&s);
+
+ ds_put_format(output, ",ct_mark=%#"PRIx32, info->ct_mark);
+ if (info->have_label) {
+ ovs_be128 value = hton128(info->ct_label);
+ ds_put_cstr(output, ",ct_label=");
+ ds_put_hex(output, &value, sizeof value);
+ }
}
void
diff --git a/lib/ct-dpif.h b/lib/ct-dpif.h
index 9122e8cd752b..9d50db920e6e 100644
--- a/lib/ct-dpif.h
+++ b/lib/ct-dpif.h
@@ -175,6 +175,9 @@ struct ct_dpif_entry {
struct ct_dpif_info {
uint32_t ct_state;
+ uint32_t ct_mark;
+ bool have_label;
+ ovs_u128 ct_label;
};
struct ct_dpif_exp_entry {
diff --git a/lib/netlink-conntrack.c b/lib/netlink-conntrack.c
index de1e467dc61a..57da43f77135 100644
--- a/lib/netlink-conntrack.c
+++ b/lib/netlink-conntrack.c
@@ -523,6 +523,11 @@ nl_ct_get_info(struct ct_dpif_tuple *tuple, uint16_t zone,
nl_ct_get_ct_state(tuple, &entry, &info->ct_state);
info->ct_state |= CS_TRACKED;
+ info->ct_mark = entry.mark;
+ if (entry.have_labels == true) {
+ info->have_label = true;
+ memcpy(&info->ct_label, &entry.labels, sizeof(info->ct_label));
+ }
ofpbuf_delete(reply);
return 0;
diff --git a/lib/odp-util.c b/lib/odp-util.c
index 4f1499ed4a47..c9669ca4572a 100644
--- a/lib/odp-util.c
+++ b/lib/odp-util.c
@@ -88,7 +88,6 @@ static struct nlattr *generate_all_wildcard_mask(const struct attr_len_tbl tbl[]
const struct nlattr *key);
static void format_u128(struct ds *d, const ovs_32aligned_u128 *key,
const ovs_32aligned_u128 *mask, bool verbose);
-static int scan_u128(const char *s, ovs_u128 *value, ovs_u128 *mask);
static int parse_odp_action(const char *s, const struct simap *port_names,
struct ofpbuf *actions);
@@ -3527,7 +3526,7 @@ format_u128(struct ds *ds, const ovs_32aligned_u128 *key,
* If either the value or mask is larger than 64 bits, the string must
* be in hexadecimal.
*/
-static int
+int
scan_u128(const char *s_, ovs_u128 *value, ovs_u128 *mask)
{
char *s = CONST_CAST(char *, s_);
diff --git a/lib/odp-util.h b/lib/odp-util.h
index 27c2ab4f0111..c2633797284b 100644
--- a/lib/odp-util.h
+++ b/lib/odp-util.h
@@ -344,4 +344,5 @@ void odp_put_push_eth_action(struct ofpbuf *odp_actions,
const struct eth_addr *eth_src,
const struct eth_addr *eth_dst);
+int scan_u128(const char *s, ovs_u128 *value, ovs_u128 *mask);
#endif /* odp-util.h */
diff --git a/ofproto/ofproto-dpif-trace.c b/ofproto/ofproto-dpif-trace.c
index d00d41a89cab..a6844b205f56 100644
--- a/ofproto/ofproto-dpif-trace.c
+++ b/ofproto/ofproto-dpif-trace.c
@@ -29,7 +29,7 @@
static void ofproto_trace(struct ofproto_dpif *, const struct flow *,
const struct dp_packet *packet,
const struct ofpact[], size_t ofpacts_len,
- struct ovs_list *next_ct_states,
+ struct ovs_list *next_cts,
struct ds *);
static void oftrace_node_destroy(struct oftrace_node *);
@@ -124,20 +124,19 @@ oftrace_recirc_node_destroy(struct oftrace_recirc_node *node)
}
static void
-oftrace_push_ct_state(struct ovs_list *next_ct_states, uint32_t ct_state)
+oftrace_push_ct_info(struct ovs_list *next_cts, struct ct_dpif_info info)
{
- struct oftrace_next_ct_state *next_ct_state =
- xmalloc(sizeof *next_ct_state);
- next_ct_state->state = ct_state;
- ovs_list_push_back(next_ct_states, &next_ct_state->node);
+ struct oftrace_next_ct *next_ct = xmalloc(sizeof *next_ct);
+ next_ct->info = info;
+ ovs_list_push_back(next_cts, &next_ct->node);
}
static void
-oftrace_pop_ct_state(struct ovs_list *next_ct_states, uint32_t *ct_state)
+oftrace_pop_ct_info(struct ovs_list *next_cts, struct ct_dpif_info *info)
{
- struct oftrace_next_ct_state *s;
- LIST_FOR_EACH_POP (s, node, next_ct_states) {
- *ct_state = s->state;
+ struct oftrace_next_ct *s;
+ LIST_FOR_EACH_POP (s, node, next_cts) {
+ *info = s->info;
free(s);
return;
}
@@ -187,10 +186,12 @@ oftrace_node_print_details(struct ds *output,
static char * OVS_WARN_UNUSED_RESULT
parse_oftrace_options(int argc, const char *argv[],
- struct ovs_list *next_ct_states)
+ struct ovs_list *next_cts)
{
int k;
+ char *name, *value, *arg;
struct ds ds = DS_EMPTY_INITIALIZER;
+ struct ct_dpif_info info;
for (k = 0; k < argc; k++) {
if (!strncmp(argv[k], "--ct-next", 9)) {
@@ -198,14 +199,36 @@ parse_oftrace_options(int argc, const char *argv[],
return xasprintf("Missing argument for option %s", argv[k]);
}
- uint32_t ct_state;
- if (!parse_ct_state(argv[++k], 0, "|", &ct_state, &ds)) {
- return ds_steal_cstr(&ds);
- }
- if (!validate_ct_state(ct_state, &ds)) {
- return ds_steal_cstr(&ds);
+ memset(&info, 0, sizeof(info));
+ arg = CONST_CAST(char *, argv[++k]);
+
+ while (ofputil_parse_key_value(&arg, &name, &value)) {
+ if (!*value) {
+ return xasprintf("Field %s missing value", name);
+ }
+
+ if (!strcmp(name, "ct_state")) {
+ if (!parse_ct_state(value, 0, "|", &info.ct_state, &ds)) {
+ return ds_steal_cstr(&ds);
+ }
+ if (!validate_ct_state(info.ct_state, &ds)) {
+ return ds_steal_cstr(&ds);
+ }
+ } else if (!strcmp(name, "ct_mark")) {
+ char *err = str_to_u32(value, &info.ct_mark);
+ if (err) {
+ free(err);
+ return xasprintf("Failed to parse ct_mark");
+ }
+ } else if (!strcmp(name, "ct_label")) {
+ int err = scan_u128(value, &info.ct_label, NULL);
+ if (err < 0) {
+ return xasprintf("Failed to parse ct_label");
+ }
+ info.have_label = true;
+ }
}
- oftrace_push_ct_state(next_ct_states, ct_state);
+ oftrace_push_ct_info(next_cts, info);
} else {
return xasprintf("Invalid option %s", argv[k]);
}
@@ -227,7 +250,7 @@ static char * OVS_WARN_UNUSED_RESULT
parse_flow_and_packet(int argc, const char *argv[],
struct ofproto_dpif **ofprotop, struct flow *flow,
struct dp_packet **packetp,
- struct ovs_list *next_ct_states)
+ struct ovs_list *next_cts)
{
const struct dpif_backer *backer = NULL;
const char *error = NULL;
@@ -268,7 +291,7 @@ parse_flow_and_packet(int argc, const char *argv[],
}
m_err = parse_oftrace_options(argc - first_option, argv + first_option,
- next_ct_states);
+ next_cts);
if (m_err) {
goto exit;
}
@@ -407,11 +430,11 @@ exit:
}
static void
-free_ct_states(struct ovs_list *ct_states)
+free_cts(struct ovs_list *cts)
{
- while (!ovs_list_is_empty(ct_states)) {
- uint32_t state;
- oftrace_pop_ct_state(ct_states, &state);
+ while (!ovs_list_is_empty(cts)) {
+ struct ct_dpif_info info;
+ oftrace_pop_ct_info(cts, &info);
}
}
@@ -423,16 +446,15 @@ ofproto_unixctl_trace(struct unixctl_conn *conn, int argc, const char *argv[],
struct dp_packet *packet;
char *error;
struct flow flow;
- struct ovs_list next_ct_states = OVS_LIST_INITIALIZER(&next_ct_states);
+ struct ovs_list next_cts = OVS_LIST_INITIALIZER(&next_cts);
error = parse_flow_and_packet(argc, argv, &ofproto, &flow, &packet,
- &next_ct_states);
+ &next_cts);
if (!error) {
struct ds result;
ds_init(&result);
- ofproto_trace(ofproto, &flow, packet, NULL, 0, &next_ct_states,
- &result);
+ ofproto_trace(ofproto, &flow, packet, NULL, 0, &next_cts, &result);
unixctl_command_reply(conn, ds_cstr(&result));
ds_destroy(&result);
dp_packet_delete(packet);
@@ -440,7 +462,7 @@ ofproto_unixctl_trace(struct unixctl_conn *conn, int argc, const char *argv[],
unixctl_command_reply_error(conn, error);
free(error);
}
- free_ct_states(&next_ct_states);
+ free_cts(&next_cts);
}
static void
@@ -455,7 +477,7 @@ ofproto_unixctl_trace_actions(struct unixctl_conn *conn, int argc,
struct ds result;
struct match match;
uint16_t in_port;
- struct ovs_list next_ct_states = OVS_LIST_INITIALIZER(&next_ct_states);
+ struct ovs_list next_cts = OVS_LIST_INITIALIZER(&next_cts);
/* Three kinds of error return values! */
enum ofperr retval;
@@ -486,7 +508,7 @@ ofproto_unixctl_trace_actions(struct unixctl_conn *conn, int argc,
}
error = parse_flow_and_packet(argc, argv, &ofproto, &match.flow, &packet,
- &next_ct_states);
+ &next_cts);
if (error) {
unixctl_command_reply_error(conn, error);
free(error);
@@ -534,14 +556,14 @@ ofproto_unixctl_trace_actions(struct unixctl_conn *conn, int argc,
}
ofproto_trace(ofproto, &match.flow, packet,
- ofpacts.data, ofpacts.size, &next_ct_states, &result);
+ ofpacts.data, ofpacts.size, &next_cts, &result);
unixctl_command_reply(conn, ds_cstr(&result));
exit:
ds_destroy(&result);
dp_packet_delete(packet);
ofpbuf_uninit(&ofpacts);
- free_ct_states(&next_ct_states);
+ free_cts(&next_cts);
}
static void
@@ -633,7 +655,7 @@ static void
ofproto_trace(struct ofproto_dpif *ofproto, const struct flow *flow,
const struct dp_packet *packet,
const struct ofpact ofpacts[], size_t ofpacts_len,
- struct ovs_list *next_ct_states, struct ds *output)
+ struct ovs_list *next_cts, struct ds *output)
{
struct ovs_list recirc_queue = OVS_LIST_INITIALIZER(&recirc_queue);
ofproto_trace__(ofproto, flow, packet, &recirc_queue,
@@ -650,7 +672,7 @@ ofproto_trace(struct ofproto_dpif *ofproto, const struct flow *flow,
struct ct_dpif_info ct_info;
memset(&ct_info, 0, sizeof(ct_info));
- if (ovs_list_is_empty(next_ct_states)) {
+ if (ovs_list_is_empty(next_cts)) {
struct ds errs = DS_EMPTY_INITIALIZER;
struct ct_dpif_tuple tuple;
int err, indent_size;
@@ -681,10 +703,14 @@ ofproto_trace(struct ofproto_dpif *ofproto, const struct flow *flow,
ds_put_format(output, " (use --ct-next to customize)");
ds_destroy(&errs);
} else {
- oftrace_pop_ct_state(next_ct_states, &ct_info.ct_state);
+ oftrace_pop_ct_info(next_cts, &ct_info);
ct_dpif_format_info(&ct_info, output);
}
recirc_node->flow.ct_state = ct_info.ct_state;
+ recirc_node->flow.ct_mark = ct_info.ct_mark;
+ if (ct_info.have_label) {
+ recirc_node->flow.ct_label = ct_info.ct_label;
+ }
}
ds_put_char(output, '\n');
ds_put_char_multiple(output, '=', 79);
diff --git a/ofproto/ofproto-dpif-trace.h b/ofproto/ofproto-dpif-trace.h
index 5e51771b19b0..1c5ef645aa6d 100644
--- a/ofproto/ofproto-dpif-trace.h
+++ b/ofproto/ofproto-dpif-trace.h
@@ -28,6 +28,7 @@
* each action (OFT_ACTION) executed in the table.
*/
+#include "ct-dpif.h"
#include "openvswitch/compiler.h"
#include "openvswitch/list.h"
#include "flow.h"
@@ -72,10 +73,10 @@ struct oftrace_recirc_node {
struct dp_packet *packet;
};
-/* A node within a next_ct_states list. */
-struct oftrace_next_ct_state {
+/* A node within a next_cts list. */
+struct oftrace_next_ct {
struct ovs_list node; /* In next_ct_states. */
- uint32_t state;
+ struct ct_dpif_info info;
};
void ofproto_dpif_trace_init(void);
diff --git a/ofproto/ofproto-unixctl.man b/ofproto/ofproto-unixctl.man
index abc9481f0faf..c966beba1e57 100644
--- a/ofproto/ofproto-unixctl.man
+++ b/ofproto/ofproto-unixctl.man
@@ -51,12 +51,16 @@ wildcards.) \fIbridge\fR names of the bridge through which
.RS
\fBofproto/trace\fR supports the following options:
.
-.IP "--ct-next \fIflags\fR"
+.IP "--ct-next \fIfield\fR=\fIvalue\fR[,\fIfield\fR=\fIvalue\fR]"
When the traced flow triggers conntrack actions, \fBofproto/trace\fR
will automatically trace the forked packet processing pipeline with
-user specified ct_state. This option sets the ct_state flags that the
-conntrack module will report. The \fIflags\fR must be a vertical
-bar separated list of the following connection tracking flags:
+user specified conntrack fields. Currently, the supported conntrack
+fields include ct_state, ct_mark, and ct_label.
+.
+.IP
+\fBct_state\fR: Sets the ct_state flags that the conntrack module will
+report. The \fIvalue\fR of ct_state must be a vertical bar separated
+list of the following connection tracking flags:
.
.RS
.IP \(bu
@@ -89,7 +93,9 @@ changed.
.
.IP
When --ct-next is unspecified, or when there are fewer --ct-next options than
-ct actions, the \fIflags\fR default to trk|new.
+ct actions, ofproto/trace queries the conntrack fields from the datapath. If
+the conntrack fields can not be queried, then the \fIct_state\fR default to
+trk|new, and the \fIct_mark\fR and \fIct_label\fR default to zero.
.
.RE
.
diff --git a/tests/ofproto-dpif.at b/tests/ofproto-dpif.at
index 7353cbd6289a..32b837e5ea75 100644
--- a/tests/ofproto-dpif.at
+++ b/tests/ofproto-dpif.at
@@ -9834,14 +9834,14 @@ table=1,priority=1,action=drop
dnl
dnl Table 2
dnl
-table=2,priority=10,in_port=1,tcp,ct_zone=1,ct_state=+trk+new,tcp,action=ct(commit,zone=1),ct(table=3,zone=2)
-table=2,priority=10,in_port=1,tcp,ct_zone=1,ct_state=+trk+est,tcp,action=ct(table=3,zone=2)
+table=2,priority=10,in_port=1,tcp,ct_zone=1,ct_state=+trk+new,tcp,action=ct(commit,zone=1,exec(set_field:0x11->ct_mark)),ct(table=3,zone=2)
+table=2,priority=10,in_port=1,tcp,ct_zone=1,ct_state=+trk+est,ct_mark=0x11,tcp,action=ct(table=3,zone=2)
table=2,priority=1,action=drop
dnl
dnl Table 3
dnl
-table=3,priority=10,in_port=1,tcp,ct_zone=2,ct_state=+trk+new,tcp,action=ct(commit,zone=2),4
-table=3,priority=10,in_port=1,tcp,ct_zone=2,ct_state=+trk+est,tcp,action=3
+table=3,priority=10,in_port=1,tcp,ct_zone=2,ct_state=+trk+new,tcp,action=ct(commit,zone=2,exec(set_field:0x22->ct_mark),exec(set_field:0x112233445566778899->ct_label)),4
+table=3,priority=10,in_port=1,tcp,ct_zone=2,ct_state=+trk+est,ct_mark=0x22,ct_label=0x112233445566778899,tcp,action=3
table=2,priority=1,action=drop
])
@@ -9859,10 +9859,10 @@ AT_CHECK([tail -1 stdout], [0],
AT_CHECK([ovs-appctl ofproto/trace br0 'in_port=1,tcp'], [0], [stdout])
AT_CHECK([tail -1 stdout], [0],
- [Datapath actions: ct(commit,zone=2),4
+ [Datapath actions: ct(commit,zone=2,mark=0x22/0xffffffff,label=0x112233445566778899),4
])
-AT_CHECK([ovs-appctl ofproto/trace br0 'in_port=1,tcp' --ct-next 'trk|est' --ct-next 'trk|est' ], [0], [stdout])
+AT_CHECK([ovs-appctl ofproto/trace br0 'in_port=1,tcp' --ct-next 'ct_state=trk|est,ct_mark=0x11' --ct-next 'ct_state=trk|est,ct_mark=0x22,ct_label=0x112233445566778899'], [0], [stdout])
AT_CHECK([tail -1 stdout], [0],
[Datapath actions: 3
])
diff --git a/tests/system-traffic.at b/tests/system-traffic.at
index 727f97f7a7dd..e9ebcd3e2688 100644
--- a/tests/system-traffic.at
+++ b/tests/system-traffic.at
@@ -4013,8 +4013,8 @@ table=0,priority=100,arp,action=normal
table=0,priority=10,in_port=1,tcp,action=ct(table=1,zone=1)
table=0,priority=10,in_port=2,tcp,ct_state=-trk,action=ct(table=1,zone=1)
-table=1,priority=10,in_port=1,tcp,ct_state=+trk+new,action=ct(commit,zone=1),2
-table=1,priority=10,in_port=1,tcp,ct_state=+trk+est,action=2
+table=1,priority=10,in_port=1,tcp,ct_state=+trk+new,action=ct(commit,zone=1,exec(set_field:0x77->ct_mark),exec(set_field:0x11223344556677889900->ct_label)),2
+table=1,priority=10,in_port=1,tcp,ct_state=+trk+est,ct_mark=0x77,ct_label=0x11223344556677889900,action=2
table=1,priority=10,in_port=2,tcp,ct_state=+trk+new,action=drop
table=1,priority=10,in_port=2,tcp,ct_state=+trk+est+rpl,action=1
])
@@ -4029,7 +4029,7 @@ on_exit 'rm -f payload100.bin'
dnl Run ofproto/trace before connection is established.
AT_CHECK([ovs-appctl ofproto/trace br0 "in_port=1,dl_type=0x800,nw_src=10.1.1.1,nw_dst=10.1.1.2,nw_proto=6,tcp_src=33333,tcp_dst=22222"], [0], [stdout])
AT_CHECK([tail -1 stdout], [0],
- [Datapath actions: ct(commit,zone=1),3
+ [Datapath actions: ct(commit,zone=1,mark=0x77/0xffffffff,label=0x11223344556677889900),3
])
AT_CHECK([grep -c 'ct_state=new|trk' stdout], [0], [2
])
--
2.7.4
More information about the dev
mailing list