Add group rule service, purge flood rules, use group to handle ARP

Change-Id: If0db889d6ab28a4d36f433f16bf84241d2726045
diff --git a/apps/openstacknetworking/api/src/main/java/org/onosproject/openstacknetworking/api/Constants.java b/apps/openstacknetworking/api/src/main/java/org/onosproject/openstacknetworking/api/Constants.java
index 6475a7a..891b1ee 100644
--- a/apps/openstacknetworking/api/src/main/java/org/onosproject/openstacknetworking/api/Constants.java
+++ b/apps/openstacknetworking/api/src/main/java/org/onosproject/openstacknetworking/api/Constants.java
@@ -68,7 +68,6 @@
     public static final String UNSUPPORTED_VENDOR = "unsupported_vendor";
 
     public static final int PRIORITY_TUNNEL_TAG_RULE = 30000;
-    public static final int PRIORITY_FLOATING_INTERNAL = 42000;
     public static final int PRIORITY_FLOATING_EXTERNAL = 41000;
     public static final int PRIORITY_STATEFUL_SNAT_RULE = 40500;
     public static final int PRIORITY_ICMP_RULE = 43000;
@@ -79,7 +78,6 @@
     public static final int PRIORITY_SNAT_RULE = 26000;
     public static final int PRIORITY_SWITCHING_RULE = 30000;
     public static final int PRIORITY_FLAT_JUMP_UPSTREAM_RULE = 41000;
-    public static final int PRIORITY_FLAT_JUMP_DOWNSTREAM_RULE = 41000;
     public static final int PRIORITY_FLAT_UPSTREAM_RULE = 41000;
     public static final int PRIORITY_FLAT_DOWNSTREAM_RULE = 42000;
     public static final int PRIORITY_DHCP_RULE = 42000;
@@ -90,11 +88,10 @@
     public static final int PRIORITY_CT_RULE = 32000;
     public static final int PRIORITY_CT_DROP_RULE = 32500;
     public static final int PRIORITY_ARP_GATEWAY_RULE = 41000;
-    public static final int PRIORITY_ARP_SUBNET_RULE = 40000;
     public static final int PRIORITY_ARP_CONTROL_RULE = 40000;
     public static final int PRIORITY_ARP_REPLY_RULE = 40000;
     public static final int PRIORITY_ARP_REQUEST_RULE = 40000;
-    public static final int PRIORITY_ARP_FLOOD_RULE = 39000;
+    public static final int PRIORITY_ARP_GROUP_RULE = 39000;
     public static final int PRIORITY_FORCED_ACL_RULE = 50000;
     public static final int PRIORITY_ICMP_PROBE_RULE = 50000;
 
diff --git a/apps/openstacknetworking/api/src/main/java/org/onosproject/openstacknetworking/api/OpenstackGroupRuleService.java b/apps/openstacknetworking/api/src/main/java/org/onosproject/openstacknetworking/api/OpenstackGroupRuleService.java
new file mode 100644
index 0000000..4a0df58
--- /dev/null
+++ b/apps/openstacknetworking/api/src/main/java/org/onosproject/openstacknetworking/api/OpenstackGroupRuleService.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright 2019-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.openstacknetworking.api;
+
+import org.onosproject.core.ApplicationId;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.group.GroupBucket;
+import org.onosproject.net.group.GroupDescription;
+
+import java.util.List;
+
+/**
+ * Service for setting group rules.
+ */
+public interface OpenstackGroupRuleService {
+
+    /**
+     * Configures the group table rule.
+     *
+     * @param appId         application ID
+     * @param deviceId      device ID
+     * @param groupId       group ID
+     * @param type          group type
+     * @param buckets       a list of group buckets
+     * @param install       true for rule addition, false for rule removal
+     */
+    void setRule(ApplicationId appId, DeviceId deviceId, int groupId,
+                 GroupDescription.Type type, List<GroupBucket> buckets, boolean install);
+
+    /**
+     * Checks whether has the group in store with given device ID and group ID.
+     *
+     * @param deviceId      device ID
+     * @param groupId       group ID
+     * @return true if the group exists, false otherwise
+     */
+    boolean hasGroup(DeviceId deviceId, int groupId);
+
+    /**
+     * Configures buckets to the existing group.
+     * With install flag true, this method will add buckets to existing buckets,
+     * while with install flag false, this method will remove buckets from
+     * existing buckets.
+     *
+     * @param appId         application ID
+     * @param deviceId      device ID
+     * @param groupId       group ID
+     * @param buckets       a list of group buckets
+     * @param install       true for buckets addition, false for buckets removal
+     */
+    void setBuckets(ApplicationId appId, DeviceId deviceId, int groupId,
+                    List<GroupBucket> buckets, boolean install);
+
+    /**
+     * Configures buckets.
+     *
+     * @param appId         application ID
+     * @param deviceId      device ID
+     * @param groupId       group ID
+     * @param buckets       a lit of group buckets
+     */
+    void setBuckets(ApplicationId appId, DeviceId deviceId, int groupId,
+                    List<GroupBucket> buckets);
+}
diff --git a/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackGroupRuleManager.java b/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackGroupRuleManager.java
new file mode 100644
index 0000000..e3af2c1
--- /dev/null
+++ b/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackGroupRuleManager.java
@@ -0,0 +1,103 @@
+/*
+ * Copyright 2019-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.openstacknetworking.impl;
+
+import org.onosproject.core.ApplicationId;
+import org.onosproject.core.CoreService;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.group.DefaultGroupDescription;
+import org.onosproject.net.group.GroupBucket;
+import org.onosproject.net.group.GroupBuckets;
+import org.onosproject.net.group.GroupDescription;
+import org.onosproject.net.group.GroupService;
+import org.onosproject.openstacknetworking.api.OpenstackGroupRuleService;
+import org.osgi.service.component.annotations.Activate;
+import org.osgi.service.component.annotations.Component;
+import org.osgi.service.component.annotations.Deactivate;
+import org.osgi.service.component.annotations.Reference;
+import org.osgi.service.component.annotations.ReferenceCardinality;
+import org.slf4j.Logger;
+
+import java.util.List;
+
+import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.getGroupKey;
+import static org.slf4j.LoggerFactory.getLogger;
+
+/**
+ * Sets group table rules directly using GroupService.
+ */
+@Component(immediate = true, service = OpenstackGroupRuleService.class)
+public class OpenstackGroupRuleManager implements OpenstackGroupRuleService {
+
+    private final Logger log = getLogger(getClass());
+
+    @Reference(cardinality = ReferenceCardinality.MANDATORY)
+    protected GroupService groupService;
+
+    @Reference(cardinality = ReferenceCardinality.MANDATORY)
+    protected CoreService coreService;
+
+    @Activate
+    protected void activate() {
+        log.info("Started");
+    }
+
+    @Deactivate
+    protected void deactivate() {
+        log.info("Stopped");
+    }
+
+    @Override
+    public void setRule(ApplicationId appId, DeviceId deviceId, int groupId,
+                        GroupDescription.Type type, List<GroupBucket> buckets,
+                        boolean install) {
+        if (install) {
+            GroupDescription groupDesc = new DefaultGroupDescription(deviceId,
+                    type, new GroupBuckets(buckets), getGroupKey(groupId), groupId, appId);
+            groupService.addGroup(groupDesc);
+            log.info("Adding group rule {}", groupId);
+        } else {
+            groupService.removeGroup(deviceId, getGroupKey(groupId), appId);
+            log.info("Removing group rule {}", groupId);
+        }
+    }
+
+    @Override
+    public boolean hasGroup(DeviceId deviceId, int groupId) {
+        return groupService.getGroup(deviceId, getGroupKey(groupId)) != null;
+    }
+
+    @Override
+    public void setBuckets(ApplicationId appId, DeviceId deviceId,
+                           int groupId, List<GroupBucket> buckets, boolean install) {
+        if (install) {
+            groupService.addBucketsToGroup(deviceId, getGroupKey(groupId),
+                    new GroupBuckets(buckets), getGroupKey(groupId), appId);
+            log.info("Adding buckets for group rule {}", groupId);
+        } else {
+            groupService.removeBucketsFromGroup(deviceId, getGroupKey(groupId),
+                    new GroupBuckets(buckets), getGroupKey(groupId), appId);
+            log.info("Removing buckets for group rule {}", groupId);
+        }
+    }
+
+    @Override
+    public void setBuckets(ApplicationId appId, DeviceId deviceId,
+                           int groupId, List<GroupBucket> buckets) {
+        groupService.setBucketsForGroup(deviceId, getGroupKey(groupId),
+                new GroupBuckets(buckets), getGroupKey(groupId), appId);
+    }
+}
diff --git a/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackSwitchingArpHandler.java b/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackSwitchingArpHandler.java
index a4e817f..8c6d1d9 100644
--- a/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackSwitchingArpHandler.java
+++ b/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackSwitchingArpHandler.java
@@ -15,6 +15,7 @@
  */
 package org.onosproject.openstacknetworking.impl;
 
+import com.google.common.collect.Lists;
 import org.onlab.packet.ARP;
 import org.onlab.packet.EthType;
 import org.onlab.packet.Ethernet;
@@ -30,6 +31,7 @@
 import org.onosproject.cluster.NodeId;
 import org.onosproject.core.ApplicationId;
 import org.onosproject.core.CoreService;
+import org.onosproject.core.GroupId;
 import org.onosproject.mastership.MastershipService;
 import org.onosproject.net.Device;
 import org.onosproject.net.PortNumber;
@@ -38,6 +40,7 @@
 import org.onosproject.net.flow.DefaultTrafficTreatment;
 import org.onosproject.net.flow.TrafficSelector;
 import org.onosproject.net.flow.TrafficTreatment;
+import org.onosproject.net.group.GroupBucket;
 import org.onosproject.net.packet.DefaultOutboundPacket;
 import org.onosproject.net.packet.PacketContext;
 import org.onosproject.net.packet.PacketProcessor;
@@ -47,6 +50,7 @@
 import org.onosproject.openstacknetworking.api.InstancePortListener;
 import org.onosproject.openstacknetworking.api.InstancePortService;
 import org.onosproject.openstacknetworking.api.OpenstackFlowRuleService;
+import org.onosproject.openstacknetworking.api.OpenstackGroupRuleService;
 import org.onosproject.openstacknetworking.api.OpenstackNetwork.Type;
 import org.onosproject.openstacknetworking.api.OpenstackNetworkEvent;
 import org.onosproject.openstacknetworking.api.OpenstackNetworkListener;
@@ -71,6 +75,7 @@
 
 import java.nio.ByteBuffer;
 import java.util.Dictionary;
+import java.util.List;
 import java.util.Objects;
 import java.util.Set;
 import java.util.concurrent.ExecutorService;
@@ -79,13 +84,14 @@
 import static com.google.common.base.Preconditions.checkNotNull;
 import static java.util.concurrent.Executors.newSingleThreadExecutor;
 import static org.onlab.util.Tools.groupedThreads;
+import static org.onosproject.net.group.GroupDescription.Type.ALL;
 import static org.onosproject.openstacknetworking.api.Constants.ARP_BROADCAST_MODE;
 import static org.onosproject.openstacknetworking.api.Constants.ARP_PROXY_MODE;
 import static org.onosproject.openstacknetworking.api.Constants.ARP_TABLE;
 import static org.onosproject.openstacknetworking.api.Constants.OPENSTACK_NETWORKING_APP_ID;
 import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_ARP_CONTROL_RULE;
-import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_ARP_FLOOD_RULE;
 import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_ARP_GATEWAY_RULE;
+import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_ARP_GROUP_RULE;
 import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_ARP_REPLY_RULE;
 import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_ARP_REQUEST_RULE;
 import static org.onosproject.openstacknetworking.api.InstancePort.State.ACTIVE;
@@ -102,6 +108,7 @@
 import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.swapStaleLocation;
 import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.tunnelPortNumByNetId;
 import static org.onosproject.openstacknetworking.util.RulePopulatorUtil.buildExtension;
+import static org.onosproject.openstacknetworking.util.RulePopulatorUtil.buildGroupBucket;
 import static org.onosproject.openstacknetworking.util.RulePopulatorUtil.buildMoveArpShaToThaExtension;
 import static org.onosproject.openstacknetworking.util.RulePopulatorUtil.buildMoveArpSpaToTpaExtension;
 import static org.onosproject.openstacknetworking.util.RulePopulatorUtil.buildMoveEthSrcToDstExtension;
@@ -131,6 +138,9 @@
     protected OpenstackFlowRuleService osFlowRuleService;
 
     @Reference(cardinality = ReferenceCardinality.MANDATORY)
+    protected OpenstackGroupRuleService osGroupRuleService;
+
+    @Reference(cardinality = ReferenceCardinality.MANDATORY)
     protected ComponentConfigService configService;
 
     @Reference(cardinality = ReferenceCardinality.MANDATORY)
@@ -417,9 +427,11 @@
             case GRE:
             case GENEVE:
                 setRemoteArpRequestRuleForTunnel(port, install);
+                setLocalArpRequestRuleForVnet(port, install);
                 break;
             case VLAN:
                 setArpRequestRuleForVlan(port, install);
+                setLocalArpRequestRuleForVnet(port, install);
                 break;
             default:
                 break;
@@ -454,7 +466,7 @@
     }
 
     /**
-     * Installs flow rules to match ARP request packets only for VxLAN.
+     * Installs flow rules at remote node to match ARP request packets for Tunnel.
      *
      * @param port      instance port
      * @param install   installation flag
@@ -476,6 +488,22 @@
     }
 
     /**
+     * Installs flow rules at local node to matchA RP request packets for Tunnel.
+     *
+     * @param port      instance port
+     * @param install   installation flag
+     */
+    private void setLocalArpRequestRuleForVnet(InstancePort port, boolean install) {
+        TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder()
+                .setOutput(port.portNumber());
+
+        List<GroupBucket> bkts = Lists.newArrayList();
+        bkts.add(buildGroupBucket(tBuilder.build(), ALL, (short) -1));
+        osGroupRuleService.setBuckets(appId, port.deviceId(),
+                port.networkId().hashCode(), bkts, install);
+    }
+
+    /**
      * Installs flow rules to match ARP request packets for VLAN.
      *
      * @param port      instance port
@@ -761,6 +789,43 @@
         }
     }
 
+    // a helper method
+    private void setBaseVnetArpRuleForBroadcastMode(OpenstackNode osNode,
+                                                    String segId, String netId,
+                                                    boolean isTunnel,
+                                                    boolean install) {
+
+        // add group rule
+        int groupId = netId.hashCode();
+        osGroupRuleService.setRule(appId, osNode.intgBridge(), groupId,
+                ALL, Lists.newArrayList(), install);
+
+        // add flow rule
+        TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder()
+                .matchEthType(EthType.EtherType.ARP.ethType().toShort())
+                .matchArpOp(ARP.OP_REQUEST);
+
+        if (isTunnel) {
+            sBuilder.matchTunnelId(Long.parseLong(segId));
+        } else {
+            sBuilder.matchVlanId(VlanId.vlanId(segId));
+        }
+
+        TrafficTreatment treatment = DefaultTrafficTreatment.builder()
+                .group(GroupId.valueOf(netId.hashCode()))
+                .build();
+
+        osFlowRuleService.setRule(
+                appId,
+                osNode.intgBridge(),
+                sBuilder.build(),
+                treatment,
+                PRIORITY_ARP_GROUP_RULE,
+                ARP_TABLE,
+                install
+        );
+    }
+
     /**
      * Extracts properties from the component configuration context.
      *
@@ -795,35 +860,6 @@
         }
     }
 
-    private void setBaseVnetArpRuleForBroadcastMode(OpenstackNode osNode,
-                                                    String segId,
-                                                    boolean isTunnel,
-                                                    boolean install) {
-        TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder()
-                .matchEthType(EthType.EtherType.ARP.ethType().toShort())
-                .matchArpOp(ARP.OP_REQUEST);
-
-        if (isTunnel) {
-            sBuilder.matchTunnelId(Long.valueOf(segId));
-        } else {
-            sBuilder.matchVlanId(VlanId.vlanId(segId));
-        }
-
-        TrafficTreatment treatment = DefaultTrafficTreatment.builder()
-                .setOutput(PortNumber.FLOOD)
-                .build();
-
-        osFlowRuleService.setRule(
-                appId,
-                osNode.intgBridge(),
-                sBuilder.build(),
-                treatment,
-                PRIORITY_ARP_FLOOD_RULE,
-                ARP_TABLE,
-                install
-        );
-    }
-
     /**
      * An internal network listener which listens to openstack network event,
      * manages the gateway collection and installs flow rule that handles
@@ -915,14 +951,18 @@
                     && netType != NetworkType.VLAN) {
                 String segId = osNetworkService.segmentId(netId);
                 osNodeService.completeNodes(COMPUTE)
-                        .forEach(node -> setBaseVnetArpRuleForBroadcastMode(
-                                node, segId, true, install));
+                        .forEach(node -> {
+                            setBaseVnetArpRuleForBroadcastMode(node, segId,
+                                    netId, true, install);
+                        });
             }
             if (netType == NetworkType.VLAN) {
                 String segId = osNetworkService.segmentId(netId);
                 osNodeService.completeNodes(COMPUTE)
-                        .forEach(node -> setBaseVnetArpRuleForBroadcastMode(
-                                node, segId, false, install));
+                        .forEach(node -> {
+                            setBaseVnetArpRuleForBroadcastMode(
+                                    node, segId, netId, false, install);
+                        });
             }
         }
     }
@@ -1042,19 +1082,17 @@
                                     osNetworkService.networkType(nid) == GENEVE)
                     .forEach(nid -> {
                         String segId = osNetworkService.segmentId(nid);
-                        setBaseVnetArpRuleForBroadcastMode(osNode, segId, true, install);
+                        setBaseVnetArpRuleForBroadcastMode(osNode, segId, nid, true, install);
                     });
 
             netIds.stream()
                     .filter(nid -> osNetworkService.networkType(nid) == VLAN)
                     .forEach(nid -> {
                         String segId = osNetworkService.segmentId(nid);
-                        setBaseVnetArpRuleForBroadcastMode(osNode, segId, false, install);
+                        setBaseVnetArpRuleForBroadcastMode(osNode, segId, nid, false, install);
                     });
         }
 
-
-
         private void setAllArpRules(OpenstackNode osNode, boolean install) {
             if (ARP_BROADCAST_MODE.equals(getArpMode())) {
                 instancePortService.instancePorts().stream()
@@ -1064,6 +1102,8 @@
                             setArpRequestRule(p, install);
                             setArpReplyRule(p, install);
                 });
+            } else {
+                // we do nothing for proxy mode
             }
         }
     }
diff --git a/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/util/OpenstackNetworkingUtil.java b/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/util/OpenstackNetworkingUtil.java
index 40d07f5..8837a65 100644
--- a/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/util/OpenstackNetworkingUtil.java
+++ b/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/util/OpenstackNetworkingUtil.java
@@ -56,6 +56,8 @@
 import org.onosproject.net.device.DeviceService;
 import org.onosproject.net.flow.DefaultTrafficTreatment;
 import org.onosproject.net.flow.TrafficTreatment;
+import org.onosproject.net.group.DefaultGroupKey;
+import org.onosproject.net.group.GroupKey;
 import org.onosproject.net.packet.DefaultOutboundPacket;
 import org.onosproject.net.packet.PacketService;
 import org.onosproject.openstacknetworking.api.Constants.VnicType;
@@ -1321,6 +1323,16 @@
     }
 
     /**
+     * Obtains flow group key from the given id.
+     *
+     * @param groupId flow group identifier
+     * @return flow group key
+     */
+    public static GroupKey getGroupKey(int groupId) {
+        return new DefaultGroupKey((Integer.toString(groupId)).getBytes());
+    }
+
+    /**
      * Builds up and a complete endpoint URL from gateway node.
      *
      * @param node gateway node
diff --git a/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/util/RulePopulatorUtil.java b/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/util/RulePopulatorUtil.java
index bc7ecba..de5295c 100644
--- a/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/util/RulePopulatorUtil.java
+++ b/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/util/RulePopulatorUtil.java
@@ -25,11 +25,15 @@
 import org.onosproject.net.device.DeviceService;
 import org.onosproject.net.driver.DriverHandler;
 import org.onosproject.net.driver.DriverService;
+import org.onosproject.net.flow.TrafficTreatment;
 import org.onosproject.net.flow.criteria.ExtensionSelector;
 import org.onosproject.net.flow.criteria.ExtensionSelectorType;
 import org.onosproject.net.flow.instructions.ExtensionPropertyException;
 import org.onosproject.net.flow.instructions.ExtensionTreatment;
 import org.onosproject.net.flow.instructions.ExtensionTreatmentType;
+import org.onosproject.net.group.DefaultGroupBucket;
+import org.onosproject.net.group.GroupBucket;
+import org.onosproject.net.group.GroupDescription;
 import org.slf4j.Logger;
 
 import java.util.ArrayList;
@@ -226,6 +230,32 @@
     }
 
     /**
+     * Returns the group bucket with given traffic treatment and group type.
+     *
+     * @param treatment     traffic treatment
+     * @param type          group type
+     * @param weight        weight (only for select type)
+     * @return group bucket
+     */
+    public static GroupBucket buildGroupBucket(TrafficTreatment treatment,
+                                               GroupDescription.Type type, short weight) {
+        switch (type) {
+            case ALL:
+                return DefaultGroupBucket.createAllGroupBucket(treatment);
+            case SELECT:
+                if (weight == -1) {
+                    return DefaultGroupBucket.createSelectGroupBucket(treatment);
+                } else {
+                    return DefaultGroupBucket.createSelectGroupBucket(treatment, weight);
+                }
+            case INDIRECT:
+                return DefaultGroupBucket.createIndirectGroupBucket(treatment);
+            default:
+                return null;
+        }
+    }
+
+    /**
      * Returns the nicira push extension treatment.
      *
      * @param device        device instance