A conjunctive flow consists of two or more multiple flows with conjunction actions. When input to the ofproto/trace command matches a conjunctive flow, it outputs flows of all dimensions.
Signed-off-by: Nobuhiro MIKI <[email protected]> --- lib/classifier.c | 35 +++++++++++++++++++++++++++++++++++ lib/classifier.h | 2 ++ lib/flow.h | 1 + ofproto/ofproto-dpif-xlate.c | 31 +++++++++++++++++++++++++++++++ tests/classifier.at | 11 +++++++++++ 5 files changed, 80 insertions(+) diff --git a/lib/classifier.c b/lib/classifier.c index 18dbfc83ad44..c580301318cc 100644 --- a/lib/classifier.c +++ b/lib/classifier.c @@ -169,6 +169,7 @@ cls_rule_init__(struct cls_rule *rule, unsigned int priority) rculist_init(&rule->node); *CONST_CAST(int *, &rule->priority) = priority; ovsrcu_init(&rule->cls_match, NULL); + ovs_list_init(CONST_CAST(struct ovs_list *, &rule->conj_flows)); } /* Initializes 'rule' to match packets specified by 'match' at the given @@ -218,6 +219,36 @@ cls_rule_move(struct cls_rule *dst, struct cls_rule *src) CONST_CAST(struct minimatch *, &src->match)); } +static void +cls_rule_free_conj_flows(const struct cls_rule *rule) +{ + struct miniflow *flow; + + LIST_FOR_EACH_POP (flow, list_node, + CONST_CAST(struct ovs_list *, &rule->conj_flows)) { + free(flow); + } +} + +static void +cls_rule_append_conj_flows(const struct cls_rule *rule, + struct cls_conjunction_set **soft, size_t n_soft) +{ + const struct miniflow *src; + struct miniflow *dst; + size_t data_size; + int i; + + for (i = 0; i < n_soft; i++) { + src = &soft[i]->match->flow; + data_size = miniflow_alloc(&dst, 1, src); + miniflow_clone(dst, src, data_size / sizeof(uint64_t)); + + ovs_list_push_back(CONST_CAST(struct ovs_list *, &rule->conj_flows), + &dst->list_node); + } +} + /* Frees memory referenced by 'rule'. Doesn't free 'rule' itself (it's * normally embedded into a larger structure). * @@ -226,6 +257,8 @@ void cls_rule_destroy(struct cls_rule *rule) OVS_NO_THREAD_SAFETY_ANALYSIS { + cls_rule_free_conj_flows(rule); + /* Must not be in a classifier. */ ovs_assert(!get_cls_match_protected(rule)); @@ -1101,6 +1134,8 @@ classifier_lookup__(const struct classifier *cls, ovs_version_t version, flow->conj_id = saved_conj_id; if (rule) { + cls_rule_free_conj_flows(rule); + cls_rule_append_conj_flows(rule, soft, n_soft); free_conjunctive_matches(&matches, cm_stubs, ARRAY_SIZE(cm_stubs)); if (soft != soft_stub) { diff --git a/lib/classifier.h b/lib/classifier.h index f646a8f7429b..0ef0a520e207 100644 --- a/lib/classifier.h +++ b/lib/classifier.h @@ -299,6 +299,7 @@ * parallel to the rule's removal. */ #include "cmap.h" +#include "openvswitch/list.h" #include "openvswitch/match.h" #include "openvswitch/meta-flow.h" #include "pvector.h" @@ -357,6 +358,7 @@ struct cls_rule { OVSRCU_TYPE(struct cls_match *) cls_match; /* NULL if not in a * classifier. */ const struct minimatch match; /* Matching rule. */ + const struct ovs_list conj_flows; }; /* Constructor/destructor. Must run single-threaded. */ diff --git a/lib/flow.h b/lib/flow.h index a9d026e1ce3b..d94ae95394fd 100644 --- a/lib/flow.h +++ b/lib/flow.h @@ -517,6 +517,7 @@ flowmap_next_index(struct flowmap_aux *aux, size_t *idx) * A miniflow is always dynamically allocated so that the maps are followed by * at least as many elements as there are 1-bits in maps. */ struct miniflow { + struct ovs_list list_node; struct flowmap map; /* Followed by: * uint64_t values[n]; diff --git a/ofproto/ofproto-dpif-xlate.c b/ofproto/ofproto-dpif-xlate.c index be4bd6657688..0fa5dac2be90 100644 --- a/ofproto/ofproto-dpif-xlate.c +++ b/ofproto/ofproto-dpif-xlate.c @@ -866,6 +866,35 @@ xlate_report_action_set(const struct xlate_ctx *ctx, const char *verb) } } +static void +xlate_report_conj_matches(const struct xlate_ctx *ctx, + const struct cls_rule *rule) +{ + struct miniflow *conj_flow; + struct match match; + struct flow f; + int count; + int i = 0; + + count = ovs_list_size(&rule->conj_flows); + + LIST_FOR_EACH (conj_flow, list_node, &rule->conj_flows) { + miniflow_expand(conj_flow, &f); + + match_init(&match, &f, ctx->xin->wc); + match.wc.masks.conj_id = 0; + match.wc.masks.recirc_id = 0; + match.wc.masks.in_port.ofp_port = 0; + + struct ds s = DS_EMPTY_INITIALIZER; + + match_format(&match, NULL, &s, OFP_DEFAULT_PRIORITY); + xlate_report_debug(ctx, OFT_DETAIL, "conj(%d/%d). %s", + ++i, count, ds_cstr(&s)); + + ds_destroy(&s); + } +} /* If tracing is enabled in 'ctx', appends a node representing 'rule' (in * OpenFlow table 'table_id') to the trace and makes this node the parent for @@ -918,6 +947,8 @@ xlate_report_table(const struct xlate_ctx *ctx, struct rule_dpif *rule, ctx->xin->trace = &oftrace_report(ctx->xin->trace, OFT_TABLE, ds_cstr(&s))->subs; ds_destroy(&s); + + xlate_report_conj_matches(ctx, &rule->up.cr); } /* If tracing is enabled in 'ctx', adds an OFT_DETAIL trace node to 'ctx' diff --git a/tests/classifier.at b/tests/classifier.at index de2705653e00..8ce00c2b835e 100644 --- a/tests/classifier.at +++ b/tests/classifier.at @@ -278,6 +278,17 @@ for src in 0 1 2 3 4 5 6 7; do ]) done done +dnl Check detailed output for conjunctive match. +AT_CHECK([ovs-appctl ofproto/trace br0 "in_port=1,dl_type=0x0800,nw_src=10.0.0.7,nw_dst=10.0.0.5" | grep conj], [0], [dnl + 0. conj_id=1, priority 32768 + -> conj(1/2). ip,nw_src=10.0.0.7,nw_dst=0.0.0.0,nw_frag=no + -> conj(2/2). ip,nw_src=0.0.0.0,nw_dst=10.0.0.5,nw_frag=no +]) +AT_CHECK([ovs-appctl ofproto/trace br0 "in_port=1,dl_type=0x0800,nw_src=10.0.0.1,nw_dst=10.0.0.5" | grep conj], [0], [dnl + 0. conj_id=1, priority 32768 + -> conj(1/2). ip,nw_src=10.0.0.1,nw_dst=0.0.0.0,nw_frag=no + -> conj(2/2). ip,nw_src=0.0.0.0,nw_dst=10.0.0.5,nw_frag=no +]) OVS_VSWITCHD_STOP AT_CLEANUP -- 2.31.1 _______________________________________________ dev mailing list [email protected] https://mail.openvswitch.org/mailman/listinfo/ovs-dev
