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 <[email protected]> --- 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 _______________________________________________ dev mailing list [email protected] https://mail.openvswitch.org/mailman/listinfo/ovs-dev
