ofproto: Infra for table versioning.
[cascardo/ovs.git] / ofproto / ofproto-dpif-xlate.c
index 55ae683..337d6f8 100644 (file)
@@ -96,21 +96,8 @@ struct xbridge {
     bool has_in_band;             /* Bridge has in band control? */
     bool forward_bpdu;            /* Bridge forwards STP BPDUs? */
 
-    /* True if the datapath supports recirculation. */
-    bool enable_recirc;
-
-    /* True if the datapath supports variable-length
-     * OVS_USERSPACE_ATTR_USERDATA in OVS_ACTION_ATTR_USERSPACE actions.
-     * False if the datapath supports only 8-byte (or shorter) userdata. */
-    bool variable_length_userdata;
-
-    /* Number of MPLS label stack entries that the datapath supports
-     * in matches. */
-    size_t max_mpls_depth;
-
-    /* True if the datapath supports masked data in OVS_ACTION_ATTR_SET
-     * actions. */
-    bool masked_set_action;
+    /* Datapath feature support. */
+    struct dpif_backer_support support;
 };
 
 struct xbundle {
@@ -172,6 +159,9 @@ struct xlate_ctx {
 
     const struct xbridge *xbridge;
 
+    /* Flow tables version at the beginning of the translation. */
+    long long tables_version;
+
     /* Flow at the last commit. */
     struct flow base_flow;
 
@@ -492,10 +482,7 @@ static void xlate_xbridge_set(struct xbridge *, struct dpif *,
                               const struct dpif_ipfix *,
                               const struct netflow *,
                               bool forward_bpdu, bool has_in_band,
-                              bool enable_recirc,
-                              bool variable_length_userdata,
-                              size_t max_mpls_depth,
-                              bool masked_set_action);
+                              const struct dpif_backer_support *);
 static void xlate_xbundle_set(struct xbundle *xbundle,
                               enum port_vlan_mode vlan_mode, int vlan,
                               unsigned long *trunks, bool use_priority_tags,
@@ -563,10 +550,7 @@ xlate_xbridge_set(struct xbridge *xbridge,
                   const struct dpif_ipfix *ipfix,
                   const struct netflow *netflow,
                   bool forward_bpdu, bool has_in_band,
-                  bool enable_recirc,
-                  bool variable_length_userdata,
-                  size_t max_mpls_depth,
-                  bool masked_set_action)
+                  const struct dpif_backer_support *support)
 {
     if (xbridge->ml != ml) {
         mac_learning_unref(xbridge->ml);
@@ -611,10 +595,7 @@ xlate_xbridge_set(struct xbridge *xbridge,
     xbridge->dpif = dpif;
     xbridge->forward_bpdu = forward_bpdu;
     xbridge->has_in_band = has_in_band;
-    xbridge->enable_recirc = enable_recirc;
-    xbridge->variable_length_userdata = variable_length_userdata;
-    xbridge->max_mpls_depth = max_mpls_depth;
-    xbridge->masked_set_action = masked_set_action;
+    xbridge->support = *support;
 }
 
 static void
@@ -698,10 +679,8 @@ xlate_xbridge_copy(struct xbridge *xbridge)
                       xbridge->dpif, xbridge->ml, xbridge->stp,
                       xbridge->rstp, xbridge->ms, xbridge->mbridge,
                       xbridge->sflow, xbridge->ipfix, xbridge->netflow,
-                      xbridge->forward_bpdu,
-                      xbridge->has_in_band, xbridge->enable_recirc,
-                      xbridge->variable_length_userdata,
-                      xbridge->max_mpls_depth, xbridge->masked_set_action);
+                      xbridge->forward_bpdu, xbridge->has_in_band,
+                      &xbridge->support);
     LIST_FOR_EACH (xbundle, list_node, &xbridge->xbundles) {
         xlate_xbundle_copy(new_xbridge, xbundle);
     }
@@ -852,9 +831,8 @@ xlate_ofproto_set(struct ofproto_dpif *ofproto, const char *name,
                   const struct dpif_sflow *sflow,
                   const struct dpif_ipfix *ipfix,
                   const struct netflow *netflow,
-                  bool forward_bpdu, bool has_in_band, bool enable_recirc,
-                  bool variable_length_userdata, size_t max_mpls_depth,
-                  bool masked_set_action)
+                  bool forward_bpdu, bool has_in_band,
+                  const struct dpif_backer_support *support)
 {
     struct xbridge *xbridge;
 
@@ -872,9 +850,7 @@ xlate_ofproto_set(struct ofproto_dpif *ofproto, const char *name,
     xbridge->name = xstrdup(name);
 
     xlate_xbridge_set(xbridge, dpif, ml, stp, rstp, ms, mbridge, sflow, ipfix,
-                      netflow, forward_bpdu, has_in_band, enable_recirc,
-                      variable_length_userdata, max_mpls_depth,
-                      masked_set_action);
+                      netflow, forward_bpdu, has_in_band, support);
 }
 
 static void
@@ -1754,7 +1730,7 @@ output_normal(struct xlate_ctx *ctx, const struct xbundle *out_xbundle,
         struct flow_wildcards *wc = &ctx->xout->wc;
         struct ofport_dpif *ofport;
 
-        if (ctx->xbridge->enable_recirc) {
+        if (ctx->xbridge->support.recirc) {
             use_recirc = bond_may_recirc(
                 out_xbundle->bond, &xr.recirc_id, &xr.hash_basis);
 
@@ -2610,7 +2586,7 @@ process_special(struct xlate_ctx *ctx, const struct flow *flow,
                 : rstp_process_packet(xport, packet);
         }
         return SLOW_STP;
-    } else if (xport->lldp && lldp_should_process_flow(flow)) {
+    } else if (xport->lldp && lldp_should_process_flow(xport->lldp, flow)) {
         if (packet) {
             lldp_process_packet(xport->lldp, packet);
         }
@@ -2801,6 +2777,7 @@ compose_output_action__(struct xlate_ctx *ctx, ofp_port_t ofp_port,
         const struct xport *peer = xport->peer;
         struct flow old_flow = ctx->xin->flow;
         bool old_was_mpls = ctx->was_mpls;
+        long long old_version = ctx->tables_version;
         enum slow_path_reason special;
         struct ofpbuf old_stack = ctx->stack;
         union mf_subvalue new_stack[1024 / sizeof(union mf_subvalue)];
@@ -2816,6 +2793,10 @@ compose_output_action__(struct xlate_ctx *ctx, ofp_port_t ofp_port,
         memset(flow->regs, 0, sizeof flow->regs);
         flow->actset_output = OFPP_UNSET;
 
+        /* The bridge is now known so obtain its table version. */
+        ctx->tables_version
+            = ofproto_dpif_get_tables_version(ctx->xbridge->ofproto);
+
         special = process_special(ctx, &ctx->xin->flow, peer,
                                   ctx->xin->packet);
         if (special) {
@@ -2862,6 +2843,9 @@ compose_output_action__(struct xlate_ctx *ctx, ofp_port_t ofp_port,
         ofpbuf_uninit(&ctx->stack);
         ctx->stack = old_stack;
 
+        /* Restore calling bridge's lookup version. */
+        ctx->tables_version = old_version;
+
         /* The peer bridge popping MPLS should have no effect on the original
          * bridge. */
         ctx->was_mpls = old_was_mpls;
@@ -2953,10 +2937,11 @@ compose_output_action__(struct xlate_ctx *ctx, ofp_port_t ofp_port,
     }
 
     if (out_port != ODPP_NONE) {
+        bool use_masked = ctx->xbridge->support.masked_set_action;
+
         ctx->xout->slow |= commit_odp_actions(flow, &ctx->base_flow,
                                               ctx->xout->odp_actions,
-                                              wc,
-                                              ctx->xbridge->masked_set_action);
+                                              wc, use_masked);
 
         if (xr) {
             struct ovs_action_hash *act_hash;
@@ -3082,6 +3067,7 @@ xlate_table_action(struct xlate_ctx *ctx, ofp_port_t in_port, uint8_t table_id,
         wc = (ctx->xin->skip_wildcards) ? NULL : &ctx->xout->wc;
 
         rule = rule_dpif_lookup_from_table(ctx->xbridge->ofproto,
+                                           ctx->tables_version,
                                            &ctx->xin->flow, wc,
                                            ctx->xin->xcache != NULL,
                                            ctx->xin->resubmit_stats,
@@ -3426,6 +3412,7 @@ execute_controller_action(struct xlate_ctx *ctx, int len,
 {
     struct ofproto_packet_in *pin;
     struct dp_packet *packet;
+    bool use_masked;
 
     ctx->xout->slow |= SLOW_CONTROLLER;
     if (!ctx->xin->packet) {
@@ -3434,10 +3421,10 @@ execute_controller_action(struct xlate_ctx *ctx, int len,
 
     packet = dp_packet_clone(ctx->xin->packet);
 
+    use_masked = ctx->xbridge->support.masked_set_action;
     ctx->xout->slow |= commit_odp_actions(&ctx->xin->flow, &ctx->base_flow,
                                           ctx->xout->odp_actions,
-                                          &ctx->xout->wc,
-                                          ctx->xbridge->masked_set_action);
+                                          &ctx->xout->wc, use_masked);
 
     odp_execute_actions(NULL, &packet, 1, false,
                         ctx->xout->odp_actions->data,
@@ -3450,7 +3437,7 @@ execute_controller_action(struct xlate_ctx *ctx, int len,
     pin->up.table_id = ctx->table_id;
     pin->up.cookie = ctx->rule_cookie;
 
-    flow_get_metadata(&ctx->xin->flow, &pin->up.fmd);
+    flow_get_metadata(&ctx->xin->flow, &pin->up.flow_metadata);
 
     pin->controller_id = controller_id;
     pin->send_len = len;
@@ -3479,12 +3466,13 @@ static void
 compose_recirculate_action(struct xlate_ctx *ctx)
 {
     struct recirc_metadata md;
+    bool use_masked;
     uint32_t id;
 
+    use_masked = ctx->xbridge->support.masked_set_action;
     ctx->xout->slow |= commit_odp_actions(&ctx->xin->flow, &ctx->base_flow,
                                           ctx->xout->odp_actions,
-                                          &ctx->xout->wc,
-                                          ctx->xbridge->masked_set_action);
+                                          &ctx->xout->wc, use_masked);
 
     recirc_metadata_from_flow(&md, &ctx->xin->flow);
 
@@ -3534,10 +3522,11 @@ compose_mpls_push_action(struct xlate_ctx *ctx, struct ofpact_push_mpls *mpls)
 
     n = flow_count_mpls_labels(flow, wc);
     if (!n) {
+        bool use_masked = ctx->xbridge->support.masked_set_action;
+
         ctx->xout->slow |= commit_odp_actions(flow, &ctx->base_flow,
                                               ctx->xout->odp_actions,
-                                              &ctx->xout->wc,
-                                              ctx->xbridge->masked_set_action);
+                                              &ctx->xout->wc, use_masked);
     } else if (n >= FLOW_MAX_MPLS_LABELS) {
         if (ctx->xin->packet != NULL) {
             static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
@@ -3561,7 +3550,7 @@ compose_mpls_pop_action(struct xlate_ctx *ctx, ovs_be16 eth_type)
     int n = flow_count_mpls_labels(flow, wc);
 
     if (flow_pop_mpls(flow, n, eth_type, wc)) {
-        if (ctx->xbridge->enable_recirc) {
+        if (ctx->xbridge->support.recirc) {
             ctx->was_mpls = true;
         }
     } else if (n >= FLOW_MAX_MPLS_LABELS) {
@@ -3885,8 +3874,9 @@ xlate_sample_action(struct xlate_ctx *ctx,
     /* Scale the probability from 16-bit to 32-bit while representing
      * the same percentage. */
     uint32_t probability = (os->probability << 16) | os->probability;
+    bool use_masked;
 
-    if (!ctx->xbridge->variable_length_userdata) {
+    if (!ctx->xbridge->support.variable_length_userdata) {
         static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 1);
 
         VLOG_ERR_RL(&rl, "ignoring NXAST_SAMPLE action because datapath "
@@ -3895,10 +3885,10 @@ xlate_sample_action(struct xlate_ctx *ctx,
         return;
     }
 
+    use_masked = ctx->xbridge->support.masked_set_action;
     ctx->xout->slow |= commit_odp_actions(&ctx->xin->flow, &ctx->base_flow,
                                           ctx->xout->odp_actions,
-                                          &ctx->xout->wc,
-                                          ctx->xbridge->masked_set_action);
+                                          &ctx->xout->wc, use_masked);
 
     compose_flow_sample_cookie(os->probability, os->collector_set_id,
                                os->obs_domain_id, os->obs_point_id, &cookie);
@@ -4743,7 +4733,7 @@ xlate_actions(struct xlate_in *xin, struct xlate_out *xout)
         if (is_ip_any(flow)) {
             wc->masks.nw_frag |= FLOW_NW_FRAG_MASK;
         }
-        if (xbridge->enable_recirc) {
+        if (xbridge->support.recirc) {
             /* Always exactly match recirc_id when datapath supports
              * recirculation.  */
             wc->masks.recirc_id = UINT32_MAX;
@@ -4848,9 +4838,12 @@ xlate_actions(struct xlate_in *xin, struct xlate_out *xout)
                      flow->recirc_id);
         return;
     }
+    /* The bridge is now known so obtain its table version. */
+    ctx.tables_version = ofproto_dpif_get_tables_version(ctx.xbridge->ofproto);
 
     if (!xin->ofpacts && !ctx.rule) {
-        rule = rule_dpif_lookup_from_table(ctx.xbridge->ofproto, flow, wc,
+        rule = rule_dpif_lookup_from_table(ctx.xbridge->ofproto,
+                                           ctx.tables_version, flow, wc,
                                            ctx.xin->xcache != NULL,
                                            ctx.xin->resubmit_stats,
                                            &ctx.table_id,
@@ -5055,6 +5048,10 @@ xlate_actions(struct xlate_in *xin, struct xlate_out *xout)
             wc->masks.tp_src &= htons(UINT8_MAX);
             wc->masks.tp_dst &= htons(UINT8_MAX);
         }
+        /* VLAN_TCI CFI bit must be matched if any of the TCI is matched. */
+        if (wc->masks.vlan_tci) {
+            wc->masks.vlan_tci |= htons(VLAN_CFI);
+        }
     }
 }