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:
26
lib/learn.c
26
lib/learn.c
@@ -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));
|
||||
}
|
||||
|
Reference in New Issue
Block a user