[ovs-dev] [PATCH v3 2/3] ovn: Add ct_commit(ct_mark=INT, ct_label=INT); action.

Russell Bryant russell at ovn.org
Mon Mar 21 14:54:58 UTC 2016


Update the "ct_commit;" logical flow action to optionally take
one or two parameters, setting the value of "ct_mark" or "ct_label".
Supported ct_commit syntax now includes:

    ct_commit;
    ct_commit();
    ct_commit(ct_mark=1);
    ct_commit(ct_label=1);
    ct_commit(ct_mark=1, ct_label=1);

Setting ct_mark via this type of logical flow results in an OpenFlow
flow that looks like:

    actions=ct(commit,zone=NXM_NX_REG5[0..15],exec(set_field:0x1->ct_mark))

Similarly, setting ct_label results in:

    actions=ct(commit,zone=NXM_NX_REG5[0..15],exec(set_field:0x1->ct_label))

A future commit will make use of this feature.

Signed-off-by: Russell Bryant <russell at ovn.org>
---
 ovn/lib/actions.c | 128 ++++++++++++++++++++++++++++++++++++++++++++++++++++--
 ovn/ovn-sb.xml    |  13 +++++-
 2 files changed, 136 insertions(+), 5 deletions(-)

diff --git a/ovn/lib/actions.c b/ovn/lib/actions.c
index 6f67b93..a6b1988 100644
--- a/ovn/lib/actions.c
+++ b/ovn/lib/actions.c
@@ -412,7 +412,8 @@ parse_put_arp_action(struct action_context *ctx)
 }
 
 static void
-emit_ct(struct action_context *ctx, bool recirc_next, bool commit)
+emit_ct(struct action_context *ctx, bool recirc_next, bool commit,
+        int *ct_mark, ovs_be128 *ct_label)
 {
     struct ofpact_conntrack *ct = ofpact_put_CT(ctx->ofpacts);
     ct->flags |= commit ? NX_CT_F_COMMIT : 0;
@@ -438,6 +439,127 @@ emit_ct(struct action_context *ctx, bool recirc_next, bool commit)
 
     /* CT only works with IP, so set up a prerequisite. */
     add_prerequisite(ctx, "ip");
+
+    if (ct_mark) {
+        size_t set_field_offset = ctx->ofpacts->size;
+        ofpbuf_pull(ctx->ofpacts, set_field_offset);
+
+        struct ofpact_set_field *sf = ofpact_put_SET_FIELD(ctx->ofpacts);
+        sf->field = mf_from_id(MFF_CT_MARK);
+        sf->value.be32 = htonl(*ct_mark);
+        sf->mask.be32 = OVS_BE32_MAX;
+
+        ctx->ofpacts->header = ofpbuf_push_uninit(ctx->ofpacts, set_field_offset);
+        ct = ctx->ofpacts->header;
+        ofpact_finish(ctx->ofpacts, &ct->ofpact);
+    }
+
+    if (ct_label) {
+        size_t set_field_offset = ctx->ofpacts->size;
+        ofpbuf_pull(ctx->ofpacts, set_field_offset);
+
+        struct ofpact_set_field *sf = ofpact_put_SET_FIELD(ctx->ofpacts);
+        sf->field = mf_from_id(MFF_CT_LABEL);
+        sf->value.be128 = *ct_label;
+        sf->mask.be128 = OVS_BE128_MAX;
+
+        ctx->ofpacts->header = ofpbuf_push_uninit(ctx->ofpacts, set_field_offset);
+        ct = ctx->ofpacts->header;
+        ofpact_finish(ctx->ofpacts, &ct->ofpact);
+
+    }
+}
+
+/* Parse an argument to the ct_commit(); action.  Supported arguments include:
+ *
+ *      ct_mark=0
+ *      ct_label=0
+ *
+ * If a comma separates the current argument from the next argument, this
+ * function will consume it.
+ *
+ * Return true after successfully parsing an argument.  false on failure. */
+static bool
+parse_ct_commit_arg(struct action_context *ctx,
+                    bool *set_mark, int *mark_value,
+                    bool *set_label, ovs_be128 *label_value)
+{
+    if (lexer_match_id(ctx->lexer, "ct_mark")) {
+        if (!lexer_match(ctx->lexer, LEX_T_EQUALS)) {
+            action_error(ctx, "Expected '=' after argument to ct_commit");
+            return false;
+        }
+        if (!action_get_int(ctx, mark_value)) {
+            return false;
+        }
+        *set_mark = true;
+    } else if (lexer_match_id(ctx->lexer, "ct_label")) {
+        if (!lexer_match(ctx->lexer, LEX_T_EQUALS)) {
+            action_error(ctx, "Expected '=' after argument to ct_commit");
+            return false;
+        }
+        /* XXX We only support a ct_label value specified as decimal.
+         * ct_label is 128-bit, so we should eventually also support specifying
+         * full 128-bit values as hex.  Hex support isn't really needed until
+         * we need more than 32 bits. */
+        int val;
+        if (!action_get_int(ctx, &val)) {
+            return false;
+        }
+        label_value->be32[3] = htonl(val);
+        *set_label = true;
+    } else {
+        action_error(ctx, "Expected argument to ct_commit()");
+        return false;
+    }
+
+    if (lexer_match(ctx->lexer, LEX_T_COMMA)) {
+        /* A comma is valid after an argument, but only if another
+         * argument is present (not a closing paren) */
+        if (lexer_lookahead(ctx->lexer) != LEX_T_RPAREN) {
+            action_error(ctx, "Another argument to ct_commit() expected "
+                              "after comma.");
+            return false;
+        }
+    }
+
+    return true;
+}
+
+static void
+parse_ct_commit_action(struct action_context *ctx)
+{
+    if (!lexer_match(ctx->lexer, LEX_T_LPAREN)) {
+        /* ct_commit; */
+        emit_ct(ctx, false, true, NULL, NULL);
+        return;
+    }
+
+    if (lexer_match(ctx->lexer, LEX_T_RPAREN)) {
+        /* ct_commit(); */
+        emit_ct(ctx, false, true, NULL, NULL);
+        return;
+    }
+
+    /* ct_commit(ct_mark=0); */
+    /* ct_commit(ct_label=0); */
+    /* ct_commit(ct_mark=0, ct_label=0); */
+
+    bool set_mark = false;
+    bool set_label = false;
+    int mark_value = 0;
+    ovs_be128 label_value = { .be32 = { 0, }, };
+
+    while (!lexer_match(ctx->lexer, LEX_T_RPAREN)) {
+        if (!parse_ct_commit_arg(ctx, &set_mark, &mark_value,
+                                 &set_label, &label_value)) {
+            return;
+        }
+    }
+
+    emit_ct(ctx, false, true,
+            set_mark ? &mark_value : NULL,
+            set_label ? &label_value : NULL);
 }
 
 static bool
@@ -464,9 +586,9 @@ parse_action(struct action_context *ctx)
             action_syntax_error(ctx, "expecting `--'");
         }
     } else if (lexer_match_id(ctx->lexer, "ct_next")) {
-        emit_ct(ctx, true, false);
+        emit_ct(ctx, true, false, NULL, NULL);
     } else if (lexer_match_id(ctx->lexer, "ct_commit")) {
-        emit_ct(ctx, false, true);
+        parse_ct_commit_action(ctx);
     } else if (lexer_match_id(ctx->lexer, "arp")) {
         parse_arp_action(ctx);
     } else if (lexer_match_id(ctx->lexer, "get_arp")) {
diff --git a/ovn/ovn-sb.xml b/ovn/ovn-sb.xml
index 31af8dc..467f889 100644
--- a/ovn/ovn-sb.xml
+++ b/ovn/ovn-sb.xml
@@ -915,15 +915,24 @@
         </dd>
 
         <dt><code>ct_commit;</code></dt>
+        <dt><code>ct_commit(ct_mark=VALUE);</code></dt>
         <dd>
           <p>
             Commit the flow to the connection tracking entry associated
-            with it by a previous call to <code>ct_next</code>.
+            with it by a previous call to <code>ct_next</code>.  When
+            the ct_mark=VALUE parameter is supplied, ct_mark will be set
+            to the 32-bit integer indicated by VALUE on the connection
+            tracking entry.
           </p>
+
           <p>
             Note that if you want processing to continue in the next table,
             you must execute the <code>next</code> action after
-            <code>ct_commit</code>.
+            <code>ct_commit</code>.  You may also leave out <code>next</code>
+            which will commit connection tracking state, and then drop the
+            packet.  This could be useful for seting <code>ct_mark</code>
+            on a connection tracking entry before dropping a packet,
+            for example.
           </p>
         </dd>
 
-- 
2.5.0




More information about the dev mailing list