2
0
mirror of https://github.com/openvswitch/ovs synced 2025-08-31 14:25:26 +00:00

Implement learned flow deletion.

When a flow with a "learn" action is deleted, one often wants the flows
that it created (the "learned flows") to be deleted as well.  This commit
makes that possible.

I am aware of a race condition that could lead to a learned flow not being
properly deleted.  Suppose thread A deletes a flow with a "learn" action.
Meanwhile, thread B obtains the actions for this flow and translates and
executes them.  Thread B could obtain the actions for the flow before it is
deleted, but execute them after the "learn" flow and its learned flows are
deleted.  The result is that the flow created by thread B persists despite
its "learn" flow having been deleted.  This race can and should be fixed,
but I think that this commit is worth reviewing without it.

VMware-BZ: #1254021
Signed-off-by: Ben Pfaff <blp@nicira.com>
Acked-by: Thomas Graf <tgraf@suug.ch>
Acked-by: Ethan Jackson <ethan@nicira.com>
This commit is contained in:
Ben Pfaff
2014-06-05 21:53:34 -07:00
parent 9ca4a86fff
commit 35f48b8bd9
8 changed files with 375 additions and 18 deletions

View File

@@ -101,15 +101,9 @@ learn_from_openflow(const struct nx_action_learn *nal, struct ofpbuf *ofpacts)
learn->fin_idle_timeout = ntohs(nal->fin_idle_timeout);
learn->fin_hard_timeout = ntohs(nal->fin_hard_timeout);
/* We only support "send-flow-removed" for now. */
switch (ntohs(nal->flags)) {
case 0:
learn->flags = 0;
break;
case OFPFF_SEND_FLOW_REM:
learn->flags = OFPUTIL_FF_SEND_FLOW_REM;
break;
default:
learn->flags = ntohs(nal->flags);
if (learn->flags & ~(NX_LEARN_F_SEND_FLOW_REM |
NX_LEARN_F_DELETE_LEARNED)) {
return OFPERR_OFPBAC_BAD_ARGUMENT;
}
@@ -321,7 +315,10 @@ learn_execute(const struct ofpact_learn *learn, const struct flow *flow,
fm->hard_timeout = learn->hard_timeout;
fm->buffer_id = UINT32_MAX;
fm->out_port = OFPP_NONE;
fm->flags = learn->flags;
fm->flags = 0;
if (learn->flags & NX_LEARN_F_SEND_FLOW_REM) {
fm->flags |= OFPUTIL_FF_SEND_FLOW_REM;
}
fm->ofpacts = NULL;
fm->ofpacts_len = 0;
fm->delete_reason = OFPRR_DELETE;
@@ -582,7 +579,9 @@ learn_parse__(char *orig, char *arg, struct ofpbuf *ofpacts)
} else if (!strcmp(name, "cookie")) {
learn->cookie = htonll(strtoull(value, NULL, 0));
} else if (!strcmp(name, "send_flow_rem")) {
learn->flags |= OFPFF_SEND_FLOW_REM;
learn->flags |= NX_LEARN_F_SEND_FLOW_REM;
} else if (!strcmp(name, "delete_learned")) {
learn->flags |= NX_LEARN_F_DELETE_LEARNED;
} else {
struct ofpact_learn_spec *spec;
char *error;
@@ -656,9 +655,12 @@ learn_format(const struct ofpact_learn *learn, struct ds *s)
if (learn->priority != OFP_DEFAULT_PRIORITY) {
ds_put_format(s, ",priority=%"PRIu16, learn->priority);
}
if (learn->flags & OFPFF_SEND_FLOW_REM) {
if (learn->flags & NX_LEARN_F_SEND_FLOW_REM) {
ds_put_cstr(s, ",send_flow_rem");
}
if (learn->flags & NX_LEARN_F_DELETE_LEARNED) {
ds_put_cstr(s, ",delete_learned");
}
if (learn->cookie != 0) {
ds_put_format(s, ",cookie=%#"PRIx64, ntohll(learn->cookie));
}