Add connection tracking label support.
[cascardo/ovs.git] / ofproto / ofproto-dpif-xlate.c
index b815a30..26460c3 100644 (file)
@@ -2807,6 +2807,8 @@ clear_conntrack(struct flow *flow)
 {
     flow->ct_state = 0;
     flow->ct_zone = 0;
+    flow->ct_mark = 0;
+    memset(&flow->ct_label, 0, sizeof flow->ct_label);
 }
 
 static void
@@ -4145,9 +4147,48 @@ recirc_unroll_actions(const struct ofpact *ofpacts, size_t ofpacts_len,
         CHECK_MPLS_RECIRCULATION();       \
     }
 
+static void
+put_ct_mark(const struct flow *flow, struct flow *base_flow,
+            struct ofpbuf *odp_actions, struct flow_wildcards *wc)
+{
+    struct {
+        uint32_t key;
+        uint32_t mask;
+    } odp_attr;
+
+    odp_attr.key = flow->ct_mark;
+    odp_attr.mask = wc->masks.ct_mark;
+
+    if (odp_attr.mask && odp_attr.key != base_flow->ct_mark) {
+        nl_msg_put_unspec(odp_actions, OVS_CT_ATTR_MARK, &odp_attr,
+                          sizeof(odp_attr));
+    }
+}
+
+static void
+put_ct_label(const struct flow *flow, struct flow *base_flow,
+             struct ofpbuf *odp_actions, struct flow_wildcards *wc)
+{
+    if (!ovs_u128_is_zero(&wc->masks.ct_label)
+        && !ovs_u128_equals(&flow->ct_label, &base_flow->ct_label)) {
+        struct {
+            ovs_u128 key;
+            ovs_u128 mask;
+        } *odp_ct_label;
+
+        odp_ct_label = nl_msg_put_unspec_uninit(odp_actions,
+                                                OVS_CT_ATTR_LABELS,
+                                                sizeof(*odp_ct_label));
+        odp_ct_label->key = flow->ct_label;
+        odp_ct_label->mask = wc->masks.ct_label;
+    }
+}
+
 static void
 compose_conntrack_action(struct xlate_ctx *ctx, struct ofpact_conntrack *ofc)
 {
+    ovs_u128 old_ct_label = ctx->base_flow.ct_label;
+    uint32_t old_ct_mark = ctx->base_flow.ct_mark;
     size_t ct_offset;
     uint16_t zone;
 
@@ -4155,6 +4196,9 @@ compose_conntrack_action(struct xlate_ctx *ctx, struct ofpact_conntrack *ofc)
      * conntrack action. */
     xlate_commit_actions(ctx);
 
+    /* Process nested actions first, to populate the key. */
+    do_xlate_actions(ofc->actions, ofpact_ct_get_action_len(ofc), ctx);
+
     if (ofc->zone_src.field) {
         zone = mf_get_subfield(&ofc->zone_src, &ctx->xin->flow);
     } else {
@@ -4166,8 +4210,15 @@ compose_conntrack_action(struct xlate_ctx *ctx, struct ofpact_conntrack *ofc)
         nl_msg_put_flag(ctx->odp_actions, OVS_CT_ATTR_COMMIT);
     }
     nl_msg_put_u16(ctx->odp_actions, OVS_CT_ATTR_ZONE, zone);
+    put_ct_mark(&ctx->xin->flow, &ctx->base_flow, ctx->odp_actions, ctx->wc);
+    put_ct_label(&ctx->xin->flow, &ctx->base_flow, ctx->odp_actions, ctx->wc);
     nl_msg_end_nested(ctx->odp_actions, ct_offset);
 
+    /* Restore the original ct fields in the key. These should only be exposed
+     * after recirculation to another table. */
+    ctx->base_flow.ct_mark = old_ct_mark;
+    ctx->base_flow.ct_label = old_ct_label;
+
     if (ofc->recirc_table == NX_CT_RECIRC_NONE) {
         /* If we do not recirculate as part of this action, hide the results of
          * connection tracking from subsequent recirculations. */