The new action stores the 8 relevant bits of the OVS ct_state field into
a register.  This is implemented through an additional OpenFlow table,
OFTABLE_CT_STATE_SAVE, that contains two (static) rules:
- high-priority, set the target register to 0 if ct_state -trk is set
- low-priority, copy the 8 bits ct_state to the target register
  otherwise

>From a logical flow perspective, the action is supposed to be used in
the following way:
  R = ct_state_save();

Signed-off-by: Dumitru Ceara <dce...@redhat.com>
---
V2:
- Addressed Ales' comment:
  - properly set the saved ct state register if ct_state includes +trk
- Fixed up output of ovn-trace for ct_state_save() to include the actual
  value that gets copied to the destination register.
---
 controller/lflow.c           |  1 +
 controller/lflow.h           |  1 +
 controller/physical.c        | 23 +++++++++++++++++++++++
 include/ovn/actions.h        |  3 +++
 include/ovn/logical-fields.h |  2 ++
 lib/actions.c                | 27 +++++++++++++++++++++++++++
 lib/ovn-util.c               |  2 +-
 ovn-sb.xml                   |  8 ++++++++
 tests/ovn-macros.at          |  1 +
 tests/ovn.at                 | 28 ++++++++++++++++++++++++++--
 tests/test-ovn.c             |  1 +
 utilities/ovn-trace.c        | 21 +++++++++++++++++++++
 12 files changed, 115 insertions(+), 3 deletions(-)

diff --git a/controller/lflow.c b/controller/lflow.c
index 196f6a21ac..c24b2e2127 100644
--- a/controller/lflow.c
+++ b/controller/lflow.c
@@ -893,6 +893,7 @@ add_matches_to_flow_table(const struct sbrec_logical_flow 
*lflow,
         .ct_ip6_dst_load_table = OFTABLE_CT_ORIG_IP6_DST_LOAD,
         .ct_tp_dst_load_table = OFTABLE_CT_ORIG_TP_DST_LOAD,
         .flood_remote_table = OFTABLE_FLOOD_REMOTE_CHASSIS,
+        .ct_state_save_table = OFTABLE_CT_STATE_SAVE,
         .ctrl_meter_id = ctrl_meter_id,
         .common_nat_ct_zone = get_common_nat_zone(ldp),
     };
diff --git a/controller/lflow.h b/controller/lflow.h
index fa99173e67..3fd7ca99f5 100644
--- a/controller/lflow.h
+++ b/controller/lflow.h
@@ -99,6 +99,7 @@ struct uuid;
 #define OFTABLE_CT_ORIG_IP6_DST_LOAD     82
 #define OFTABLE_CT_ORIG_TP_DST_LOAD      83
 #define OFTABLE_FLOOD_REMOTE_CHASSIS     84
+#define OFTABLE_CT_STATE_SAVE            85
 
 /* Common defines shared between some controller components. */
 #define CHASSIS_FLOOD_INDEX_START 0x8000
diff --git a/controller/physical.c b/controller/physical.c
index 9e797b3b3c..b4f91b134d 100644
--- a/controller/physical.c
+++ b/controller/physical.c
@@ -3085,6 +3085,29 @@ physical_run(struct physical_ctx *p_ctx,
     ofctrl_add_flow(flow_table, OFTABLE_CT_ORIG_IP6_DST_LOAD, 100, 0, &match,
                     &ofpacts, hc_uuid);
 
+    /* Implement the ct_state_save() logical action. */
+
+    /* Add the flow:
+     * match = (1), action = (reg4[0..7] = ct_state[0..7])
+     * table = 85, priority = UINT16_MAX - 1
+     */
+    match_init_catchall(&match);
+    ofpbuf_clear(&ofpacts);
+    put_move(MFF_CT_STATE, 0,  MFF_LOG_CT_SAVED_STATE, 0, 8, &ofpacts);
+    ofctrl_add_flow(flow_table, OFTABLE_CT_STATE_SAVE, UINT16_MAX - 1, 0,
+                    &match, &ofpacts, hc_uuid);
+
+    /* Add the flow:
+     * match = (!ct.trk), action = (reg4[0..7] = 0)
+     * table = 85, priority = UINT16_MAX
+     */
+    match_init_catchall(&match);
+    ofpbuf_clear(&ofpacts);
+    match_set_ct_state_masked(&match, 0, OVS_CS_F_TRACKED);
+    put_load(0, MFF_LOG_CT_SAVED_STATE, 0, 8, &ofpacts);
+    ofctrl_add_flow(flow_table, OFTABLE_CT_STATE_SAVE, UINT16_MAX, 0,
+                    &match, &ofpacts, hc_uuid);
+
     physical_eval_remote_chassis_flows(p_ctx, &ofpacts, flow_table);
 
     ofpbuf_uninit(&ofpacts);
diff --git a/include/ovn/actions.h b/include/ovn/actions.h
index 0993ad0e5d..7fd7b26bfe 100644
--- a/include/ovn/actions.h
+++ b/include/ovn/actions.h
@@ -135,6 +135,7 @@ struct collector_set_ids;
     OVNACT(CT_ORIG_IP6_DST,   ovnact_result)          \
     OVNACT(CT_ORIG_TP_DST,    ovnact_result)          \
     OVNACT(FLOOD_REMOTE,      ovnact_null)            \
+    OVNACT(CT_STATE_SAVE,     ovnact_result)
 
 /* enum ovnact_type, with a member OVNACT_<ENUM> for each action. */
 enum OVS_PACKED_ENUM ovnact_type {
@@ -964,6 +965,8 @@ struct ovnact_encode_params {
                                     *  to resubmit. */
     uint32_t flood_remote_table; /* OpenFlow table for 'chassis_flood'
                                   * to resubmit. */
+    uint32_t ct_state_save_table; /* OpenFlow table for saving ct_state to
+                                   * register. */
 };
 
 void ovnacts_encode(const struct ovnact[], size_t ovnacts_len,
diff --git a/include/ovn/logical-fields.h b/include/ovn/logical-fields.h
index 7c6be6ea42..17154d38bd 100644
--- a/include/ovn/logical-fields.h
+++ b/include/ovn/logical-fields.h
@@ -63,6 +63,8 @@ enum ovn_controller_event {
 #define MFF_LOG_CT_ORIG_IP6_DST_ADDR        MFF_XXREG1 /* REG_ORIG_DIP_IPV6 */
 #define MFF_LOG_CT_ORIG_TP_DST_PORT         MFF_REG2   /* REG_ORIG_TP_DPORT
                                                         * (bits 0..15). */
+#define MFF_LOG_CT_SAVED_STATE              MFF_REG4   /* REG_CT_STATE
+                                                        * (bits 0..8). */
 
 /* Logical registers that are needed for backwards
  * compatibility with older northd versions.
diff --git a/lib/actions.c b/lib/actions.c
index b81061f5c1..f6f413be27 100644
--- a/lib/actions.c
+++ b/lib/actions.c
@@ -5552,6 +5552,29 @@ encode_FLOOD_REMOTE(const struct ovnact_null *null 
OVS_UNUSED,
     emit_resubmit(ofpacts, ep->flood_remote_table);
 }
 
+static void
+encode_CT_STATE_SAVE(const struct ovnact_result *res,
+                     const struct ovnact_encode_params *ep OVS_UNUSED,
+                     struct ofpbuf *ofpacts)
+{
+    encode_result_action___(res, ep->ct_state_save_table,
+                            MFF_LOG_CT_SAVED_STATE, 0, 8, ofpacts);
+}
+
+static void
+parse_CT_STATE_SAVE(struct action_context *ctx, const struct expr_field *dst,
+                    struct ovnact_result *res)
+{
+    parse_ovnact_result__(ctx, "ct_state_save", NULL, dst, res, 8);
+}
+
+static void
+format_CT_STATE_SAVE(const struct ovnact_result *res, struct ds *s)
+{
+    expr_field_format(&res->dst, s);
+    ds_put_cstr(s, " = ct_state_save();");
+}
+
 /* Parses an assignment or exchange or put_dhcp_opts action. */
 static void
 parse_set_action(struct action_context *ctx)
@@ -5658,6 +5681,10 @@ parse_set_action(struct action_context *ctx)
                    lexer_lookahead(ctx->lexer) == LEX_T_LPAREN) {
             parse_CT_ORIG_TP_DST(ctx, &lhs,
                                  ovnact_put_CT_ORIG_TP_DST(ctx->ovnacts));
+        } else if (!strcmp(ctx->lexer->token.s, "ct_state_save") &&
+                  lexer_lookahead(ctx->lexer) == LEX_T_LPAREN) {
+            parse_CT_STATE_SAVE(ctx, &lhs,
+                                ovnact_put_CT_STATE_SAVE(ctx->ovnacts));
         } else {
             parse_assignment_action(ctx, false, &lhs);
         }
diff --git a/lib/ovn-util.c b/lib/ovn-util.c
index f406114db2..c825e0936f 100644
--- a/lib/ovn-util.c
+++ b/lib/ovn-util.c
@@ -898,7 +898,7 @@ ip_address_and_port_from_lb_key(const char *key, char 
**ip_address,
  *
  * This value is also used to handle some backward compatibility during
  * upgrading. It should never decrease or rewind. */
-#define OVN_INTERNAL_MINOR_VER 7
+#define OVN_INTERNAL_MINOR_VER 8
 
 /* Returns the OVN version. The caller must free the returned value. */
 char *
diff --git a/ovn-sb.xml b/ovn-sb.xml
index 4bcf44d041..9777cc64ad 100644
--- a/ovn-sb.xml
+++ b/ovn-sb.xml
@@ -2792,6 +2792,14 @@ tcp.flags = RST;
           </p>
         </dd>
 
+        <dt><code><var>R</var> = ct_state_save();</code></dt>
+        <dd>
+          <p>
+            This action checks if the packet is tracked and stores the
+            conntrack original state in the 8-bit register <var>R</var>.
+          </p>
+        </dd>
+
         <dt><code>sample(probability=<var>packets</var>, ...)</code></dt>
         <dd>
           <p>
diff --git a/tests/ovn-macros.at b/tests/ovn-macros.at
index fd1a6b197a..0c1c1cd992 100644
--- a/tests/ovn-macros.at
+++ b/tests/ovn-macros.at
@@ -1494,5 +1494,6 @@ m4_define([OFTABLE_CT_ORIG_NW_DST_LOAD], [81])
 m4_define([OFTABLE_CT_ORIG_IP6_DST_LOAD], [82])
 m4_define([OFTABLE_CT_ORIG_TP_DST_LOAD], [83])
 m4_define([OFTABLE_FLOOD_REMOTE_CHASSIS], [84])
+m4_define([OFTABLE_CT_STATE_SAVE], [85])
 
 m4_define([OFTABLE_SAVE_INPORT_HEX], [m4_eval(OFTABLE_SAVE_INPORT, 16)])
diff --git a/tests/ovn.at b/tests/ovn.at
index bbaa653a82..938a0d0f0d 100644
--- a/tests/ovn.at
+++ b/tests/ovn.at
@@ -2287,6 +2287,28 @@ flood_remote;
 flood_remote();
     Syntax error at `(' expecting `;'.
 
+# ct_state_save()
+reg1[[0..7]] = ct_state_save();
+    encodes as 
set_field:0/0xff->reg4,resubmit(,OFTABLE_CT_STATE_SAVE),move:NXM_NX_REG4[[0..7]]->NXM_NX_XXREG0[[64..71]]
+
+reg1[[2..9]] = ct_state_save();
+    encodes as 
set_field:0/0xff->reg4,resubmit(,OFTABLE_CT_STATE_SAVE),move:NXM_NX_REG4[[0..7]]->NXM_NX_XXREG0[[66..73]]
+
+reg1[[24..31]] = ct_state_save();
+    encodes as 
set_field:0/0xff->reg4,resubmit(,OFTABLE_CT_STATE_SAVE),move:NXM_NX_REG4[[0..7]]->NXM_NX_XXREG0[[88..95]]
+
+xreg1 = ct_state_save();
+    Cannot use 64-bit field xreg1[[0..63]] where 8-bit field is required.
+
+reg1[[0..30]] = ct_state_save();
+    Cannot use 31-bit field reg1[[0..30]] where 8-bit field is required.
+
+ct_state_save;
+    Syntax error at `ct_state_save' expecting action.
+
+ct_state_save();
+    Syntax error at `ct_state_save' expecting action.
+
 # Miscellaneous negative tests.
 ;
     Syntax error at `;'.
@@ -37003,8 +37025,10 @@ check_default_flows() {
         # Tables 81, 82 and 83 are part of ct_nw_dst(), ct_ip6_dst() and 
ct_tp_dst()
         # actions respectively and its OK for them to not have default flows.
         # Table 84 is part of flood_remote; action and its OK for
-        #  it to not have default flows.
-        if test ${table} -eq 68 -o ${table} -eq 70 -o ${table} -eq 81 -o 
${table} -eq 82 -o ${table} -eq 83 -o ${table} -eq 84; then
+        # it to not have default flows.
+        # Table 85 is the implementation of the ct_state_save action and
+        # doesn't require a default flow.
+        if test ${table} -eq 68 -o ${table} -eq 70 -o ${table} -eq 81 -o 
${table} -eq 82 -o ${table} -eq 83 -o ${table} -eq 84 -o ${table} -eq 85; then
             continue;
         fi
         AT_CHECK([grep -qe "table=$table.* priority=0\(,metadata=0x\w*\)\? 
actions" oflows], [0], [ignore], [ignore], [echo "Table $table does not contain 
a default action"])
diff --git a/tests/test-ovn.c b/tests/test-ovn.c
index de0cb0b444..c4eb2a7dfb 100644
--- a/tests/test-ovn.c
+++ b/tests/test-ovn.c
@@ -1388,6 +1388,7 @@ test_parse_actions(struct ovs_cmdl_context *ctx 
OVS_UNUSED)
                 .ct_ip6_dst_load_table = OFTABLE_CT_ORIG_IP6_DST_LOAD,
                 .ct_tp_dst_load_table = OFTABLE_CT_ORIG_TP_DST_LOAD,
                 .flood_remote_table = OFTABLE_FLOOD_REMOTE_CHASSIS,
+                .ct_state_save_table = OFTABLE_CT_STATE_SAVE,
                 .lflow_uuid.parts =
                     { 0xaaaaaaaa, 0xbbbbbbbb, 0xcccccccc, 0xdddddddd},
                 .dp_key = 0xabcdef,
diff --git a/utilities/ovn-trace.c b/utilities/ovn-trace.c
index b8a9e0f0a6..ce55008a60 100644
--- a/utilities/ovn-trace.c
+++ b/utilities/ovn-trace.c
@@ -3121,6 +3121,23 @@ execute_check_out_port_sec(const struct ovnact_result 
*dl,
     mf_write_subfield_flow(&sf, &sv, uflow);
 }
 
+static void
+execute_ct_save_state(const struct ovnact_result *dl, struct flow *uflow,
+                      struct ovs_list *super)
+{
+    struct mf_subfield sf = expr_resolve_field(&dl->dst);
+    union mf_subvalue sv = {
+        .u8_val = uflow->ct_state & CS_TRACKED ? uflow->ct_state : 0,
+    };
+    mf_write_subfield_flow(&sf, &sv, uflow);
+
+    struct ds s = DS_EMPTY_INITIALIZER;
+    expr_field_format(&dl->dst, &s);
+    ovntrace_node_append(super, OVNTRACE_NODE_ACTION, "/* %s = %"PRIu8"; */",
+                         ds_cstr(&s), sv.u8_val);
+    ds_destroy(&s);
+}
+
 static void
 trace_actions(const struct ovnact *ovnacts, size_t ovnacts_len,
               const struct ovntrace_datapath *dp, struct flow *uflow,
@@ -3464,6 +3481,10 @@ trace_actions(const struct ovnact *ovnacts, size_t 
ovnacts_len,
         case OVNACT_FLOOD_REMOTE:
             ovntrace_node_append(super, OVNTRACE_NODE_OUTPUT,
                                  "/* Flood to all remote chassis */");
+            break;
+        case OVNACT_CT_STATE_SAVE:
+            execute_ct_save_state(ovnact_get_CT_STATE_SAVE(a), uflow, super);
+            break;
         }
     }
     ofpbuf_uninit(&stack);
-- 
2.49.0

_______________________________________________
dev mailing list
d...@openvswitch.org
https://mail.openvswitch.org/mailman/listinfo/ovs-dev

Reply via email to