Classifier: Staged subtable matching.
[sliver-openvswitch.git] / ofproto / ofproto-dpif-xlate.c
index c54f485..a331c0b 100644 (file)
@@ -772,7 +772,8 @@ bucket_is_alive(const struct xlate_ctx *ctx,
         return false;
     }
 
-    return (bucket->watch_port != OFPP_ANY &&
+    return !ofputil_bucket_has_liveness(bucket) ||
+           (bucket->watch_port != OFPP_ANY &&
             odp_port_is_alive(ctx, bucket->watch_port)) ||
            (bucket->watch_group != OFPG_ANY &&
             group_is_alive(ctx, bucket->watch_group, depth + 1));
@@ -795,6 +796,33 @@ group_first_live_bucket(const struct xlate_ctx *ctx,
     return NULL;
 }
 
+static const struct ofputil_bucket *
+group_best_live_bucket(const struct xlate_ctx *ctx,
+                       const struct group_dpif *group,
+                       uint32_t basis)
+{
+    const struct ofputil_bucket *best_bucket = NULL;
+    uint32_t best_score = 0;
+    int i = 0;
+
+    const struct ofputil_bucket *bucket;
+    const struct list *buckets;
+
+    group_dpif_get_buckets(group, &buckets);
+    LIST_FOR_EACH (bucket, list_node, buckets) {
+        if (bucket_is_alive(ctx, bucket, 0)) {
+            uint32_t score = (hash_int(i, basis) & 0xffff) * bucket->weight;
+            if (score >= best_score) {
+                best_bucket = bucket;
+                best_score = score;
+            }
+        }
+        i++;
+    }
+
+    return best_bucket;
+}
+
 static bool
 xbundle_trunks_vlan(const struct xbundle *bundle, uint16_t vlan)
 {
@@ -1635,7 +1663,7 @@ compose_output_action__(struct xlate_ctx *ctx, ofp_port_t ofp_port,
 
     /* If 'struct flow' gets additional metadata, we'll need to zero it out
      * before traversing a patch port. */
-    BUILD_ASSERT_DECL(FLOW_WC_SEQ == 22);
+    BUILD_ASSERT_DECL(FLOW_WC_SEQ == 23);
 
     if (!xport) {
         xlate_report(ctx, "Nonexistent output port");
@@ -1911,6 +1939,21 @@ xlate_ff_group(struct xlate_ctx *ctx, struct group_dpif *group)
     }
 }
 
+static void
+xlate_select_group(struct xlate_ctx *ctx, struct group_dpif *group)
+{
+    struct flow_wildcards *wc = &ctx->xout->wc;
+    const struct ofputil_bucket *bucket;
+    uint32_t basis;
+
+    basis = hash_bytes(ctx->xin->flow.dl_dst, sizeof ctx->xin->flow.dl_dst, 0);
+    bucket = group_best_live_bucket(ctx, group, basis);
+    if (bucket) {
+        memset(&wc->masks.dl_dst, 0xff, sizeof wc->masks.dl_dst);
+        xlate_group_bucket(ctx, bucket);
+    }
+}
+
 static void
 xlate_group_action__(struct xlate_ctx *ctx, struct group_dpif *group)
 {
@@ -1920,7 +1963,7 @@ xlate_group_action__(struct xlate_ctx *ctx, struct group_dpif *group)
         xlate_all_group(ctx, group);
         break;
     case OFPGT11_SELECT:
-        /* XXX not yet implemented */
+        xlate_select_group(ctx, group);
         break;
     case OFPGT11_FF:
         xlate_ff_group(ctx, group);