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));
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);
+ 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)
{
}
}
+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)
{
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);