aboutsummaryrefslogtreecommitdiffstats
path: root/framework/src/onos/providers/openflow/group/src/main/java/org/onosproject/provider/of
diff options
context:
space:
mode:
Diffstat (limited to 'framework/src/onos/providers/openflow/group/src/main/java/org/onosproject/provider/of')
-rw-r--r--framework/src/onos/providers/openflow/group/src/main/java/org/onosproject/provider/of/group/impl/GroupBucketEntryBuilder.java343
-rw-r--r--framework/src/onos/providers/openflow/group/src/main/java/org/onosproject/provider/of/group/impl/GroupModBuilder.java376
-rw-r--r--framework/src/onos/providers/openflow/group/src/main/java/org/onosproject/provider/of/group/impl/GroupStatsCollector.java111
-rw-r--r--framework/src/onos/providers/openflow/group/src/main/java/org/onosproject/provider/of/group/impl/OpenFlowGroupProvider.java366
-rw-r--r--framework/src/onos/providers/openflow/group/src/main/java/org/onosproject/provider/of/group/impl/package-info.java20
5 files changed, 1216 insertions, 0 deletions
diff --git a/framework/src/onos/providers/openflow/group/src/main/java/org/onosproject/provider/of/group/impl/GroupBucketEntryBuilder.java b/framework/src/onos/providers/openflow/group/src/main/java/org/onosproject/provider/of/group/impl/GroupBucketEntryBuilder.java
new file mode 100644
index 00000000..b9de7c0f
--- /dev/null
+++ b/framework/src/onos/providers/openflow/group/src/main/java/org/onosproject/provider/of/group/impl/GroupBucketEntryBuilder.java
@@ -0,0 +1,343 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * 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.provider.of.group.impl;
+
+import com.google.common.collect.Lists;
+
+import org.onlab.packet.Ip4Address;
+import org.onlab.packet.MacAddress;
+import org.onlab.packet.MplsLabel;
+import org.onlab.packet.VlanId;
+import org.onosproject.core.DefaultGroupId;
+import org.onosproject.core.GroupId;
+import org.onosproject.net.Lambda;
+import org.onosproject.net.PortNumber;
+import org.onosproject.net.flow.DefaultTrafficTreatment;
+import org.onosproject.net.flow.TrafficTreatment;
+import org.onosproject.net.flow.instructions.Instructions;
+import org.onosproject.net.group.DefaultGroupBucket;
+import org.onosproject.net.group.GroupBucket;
+import org.onosproject.net.group.GroupBuckets;
+import org.projectfloodlight.openflow.protocol.OFBucket;
+import org.projectfloodlight.openflow.protocol.OFGroupType;
+import org.projectfloodlight.openflow.protocol.action.OFAction;
+import org.projectfloodlight.openflow.protocol.action.OFActionCircuit;
+import org.projectfloodlight.openflow.protocol.action.OFActionCopyTtlIn;
+import org.projectfloodlight.openflow.protocol.action.OFActionCopyTtlOut;
+import org.projectfloodlight.openflow.protocol.action.OFActionDecMplsTtl;
+import org.projectfloodlight.openflow.protocol.action.OFActionDecNwTtl;
+import org.projectfloodlight.openflow.protocol.action.OFActionExperimenter;
+import org.projectfloodlight.openflow.protocol.action.OFActionGroup;
+import org.projectfloodlight.openflow.protocol.action.OFActionOutput;
+import org.projectfloodlight.openflow.protocol.action.OFActionPopMpls;
+import org.projectfloodlight.openflow.protocol.action.OFActionPushMpls;
+import org.projectfloodlight.openflow.protocol.action.OFActionSetDlDst;
+import org.projectfloodlight.openflow.protocol.action.OFActionSetDlSrc;
+import org.projectfloodlight.openflow.protocol.action.OFActionSetField;
+import org.projectfloodlight.openflow.protocol.action.OFActionSetNwDst;
+import org.projectfloodlight.openflow.protocol.action.OFActionSetNwSrc;
+import org.projectfloodlight.openflow.protocol.action.OFActionSetVlanPcp;
+import org.projectfloodlight.openflow.protocol.action.OFActionSetVlanVid;
+import org.projectfloodlight.openflow.protocol.oxm.OFOxm;
+import org.projectfloodlight.openflow.protocol.oxm.OFOxmOchSigidBasic;
+import org.projectfloodlight.openflow.types.IPv4Address;
+import org.projectfloodlight.openflow.types.OFVlanVidMatch;
+import org.projectfloodlight.openflow.types.U32;
+import org.projectfloodlight.openflow.types.U8;
+import org.projectfloodlight.openflow.types.VlanPcp;
+import org.slf4j.Logger;
+
+import java.util.List;
+
+import static org.slf4j.LoggerFactory.getLogger;
+
+/*
+ * Builder for GroupBucketEntry.
+ */
+public class GroupBucketEntryBuilder {
+
+ private List<OFBucket> ofBuckets;
+ private OFGroupType type;
+
+ private final Logger log = getLogger(getClass());
+
+ /**
+ * Creates a builder.
+ *
+ * @param ofBuckets list of OFBucket
+ * @param type Group type
+ */
+ public GroupBucketEntryBuilder(List<OFBucket> ofBuckets, OFGroupType type) {
+ this.ofBuckets = ofBuckets;
+ this.type = type;
+ }
+
+ /**
+ * Builds a GroupBuckets.
+ *
+ * @return GroupBuckets object, a list of GroupBuckets
+ */
+ public GroupBuckets build() {
+ List<GroupBucket> bucketList = Lists.newArrayList();
+
+ for (OFBucket bucket: ofBuckets) {
+ TrafficTreatment treatment = buildTreatment(bucket.getActions());
+ // TODO: Use GroupBucketEntry
+ GroupBucket groupBucket = null;
+ switch (type) {
+ case INDIRECT:
+ groupBucket =
+ DefaultGroupBucket.createIndirectGroupBucket(treatment);
+ break;
+ case SELECT:
+ groupBucket =
+ DefaultGroupBucket.createSelectGroupBucket(treatment);
+ break;
+ case FF:
+ PortNumber port =
+ PortNumber.portNumber(bucket.getWatchPort().getPortNumber());
+ GroupId groupId =
+ new DefaultGroupId(bucket.getWatchGroup().getGroupNumber());
+ groupBucket =
+ DefaultGroupBucket.createFailoverGroupBucket(treatment,
+ port, groupId);
+ break;
+ default:
+ log.error("Unsupported Group type : {}", type);
+ }
+ if (groupBucket != null) {
+ bucketList.add(groupBucket);
+ }
+ }
+ return new GroupBuckets(bucketList);
+ }
+
+
+ private TrafficTreatment buildTreatment(List<OFAction> actions) {
+ TrafficTreatment.Builder builder = DefaultTrafficTreatment.builder();
+ // If this is a drop rule
+ if (actions.size() == 0) {
+ builder.drop();
+ return builder.build();
+ }
+ for (OFAction act : actions) {
+ switch (act.getType()) {
+ case OUTPUT:
+ OFActionOutput out = (OFActionOutput) act;
+ builder.setOutput(
+ PortNumber.portNumber(out.getPort().getPortNumber()));
+ break;
+ case SET_VLAN_VID:
+ OFActionSetVlanVid vlan = (OFActionSetVlanVid) act;
+ builder.setVlanId(VlanId.vlanId(vlan.getVlanVid().getVlan()));
+ break;
+ case SET_VLAN_PCP:
+ OFActionSetVlanPcp pcp = (OFActionSetVlanPcp) act;
+ builder.setVlanPcp(pcp.getVlanPcp().getValue());
+ break;
+ case POP_VLAN:
+ builder.popVlan();
+ break;
+ case PUSH_VLAN:
+ builder.pushVlan();
+ break;
+ case SET_DL_DST:
+ OFActionSetDlDst dldst = (OFActionSetDlDst) act;
+ builder.setEthDst(
+ MacAddress.valueOf(dldst.getDlAddr().getLong()));
+ break;
+ case SET_DL_SRC:
+ OFActionSetDlSrc dlsrc = (OFActionSetDlSrc) act;
+ builder.setEthSrc(
+ MacAddress.valueOf(dlsrc.getDlAddr().getLong()));
+
+ break;
+ case SET_NW_DST:
+ OFActionSetNwDst nwdst = (OFActionSetNwDst) act;
+ IPv4Address di = nwdst.getNwAddr();
+ builder.setIpDst(Ip4Address.valueOf(di.getInt()));
+ break;
+ case SET_NW_SRC:
+ OFActionSetNwSrc nwsrc = (OFActionSetNwSrc) act;
+ IPv4Address si = nwsrc.getNwAddr();
+ builder.setIpSrc(Ip4Address.valueOf(si.getInt()));
+ break;
+ case EXPERIMENTER:
+ OFActionExperimenter exp = (OFActionExperimenter) act;
+ if (exp.getExperimenter() == 0x80005A06 ||
+ exp.getExperimenter() == 0x748771) {
+ OFActionCircuit ct = (OFActionCircuit) exp;
+ short lambda = ((OFOxmOchSigidBasic) ct.getField()).getValue().getChannelNumber();
+ builder.add(Instructions.modL0Lambda(Lambda.indexedLambda(lambda)));
+ } else {
+ log.warn("Unsupported OFActionExperimenter {}", exp.getExperimenter());
+ }
+ break;
+ case SET_FIELD:
+ OFActionSetField setField = (OFActionSetField) act;
+ handleSetField(builder, setField.getField());
+ break;
+ case POP_MPLS:
+ OFActionPopMpls popMpls = (OFActionPopMpls) act;
+ builder.popMpls((short) popMpls.getEthertype().getValue());
+ break;
+ case PUSH_MPLS:
+ OFActionPushMpls pushMpls = (OFActionPushMpls) act;
+ builder.pushMpls();
+ break;
+ case COPY_TTL_IN:
+ OFActionCopyTtlIn copyTtlIn = (OFActionCopyTtlIn) act;
+ builder.copyTtlIn();
+ break;
+ case COPY_TTL_OUT:
+ OFActionCopyTtlOut copyTtlOut = (OFActionCopyTtlOut) act;
+ builder.copyTtlOut();
+ break;
+ case DEC_MPLS_TTL:
+ OFActionDecMplsTtl decMplsTtl = (OFActionDecMplsTtl) act;
+ builder.decMplsTtl();
+ break;
+ case DEC_NW_TTL:
+ OFActionDecNwTtl decNwTtl = (OFActionDecNwTtl) act;
+ builder.decNwTtl();
+ break;
+ case GROUP:
+ OFActionGroup grp = (OFActionGroup) act;
+ builder.group(new DefaultGroupId(grp.getGroup().getGroupNumber()));
+ break;
+ case SET_TP_DST:
+ case SET_TP_SRC:
+ case POP_PBB:
+ case PUSH_PBB:
+ case SET_MPLS_LABEL:
+ case SET_MPLS_TC:
+ case SET_MPLS_TTL:
+ case SET_NW_ECN:
+ case SET_NW_TOS:
+ case SET_NW_TTL:
+ case SET_QUEUE:
+ case STRIP_VLAN:
+ case ENQUEUE:
+ default:
+ log.warn("Action type {} not yet implemented.", act.getType());
+ }
+ }
+
+ return builder.build();
+ }
+
+ private void handleSetField(TrafficTreatment.Builder builder, OFOxm<?> oxm) {
+ switch (oxm.getMatchField().id) {
+ case VLAN_PCP:
+ @SuppressWarnings("unchecked")
+ OFOxm<VlanPcp> vlanpcp = (OFOxm<VlanPcp>) oxm;
+ builder.setVlanPcp(vlanpcp.getValue().getValue());
+ break;
+ case VLAN_VID:
+ @SuppressWarnings("unchecked")
+ OFOxm<OFVlanVidMatch> vlanvid = (OFOxm<OFVlanVidMatch>) oxm;
+ builder.setVlanId(VlanId.vlanId(vlanvid.getValue().getVlan()));
+ break;
+ case ETH_DST:
+ @SuppressWarnings("unchecked")
+ OFOxm<org.projectfloodlight.openflow.types.MacAddress> ethdst =
+ (OFOxm<org.projectfloodlight.openflow.types.MacAddress>) oxm;
+ builder.setEthDst(MacAddress.valueOf(ethdst.getValue().getLong()));
+ break;
+ case ETH_SRC:
+ @SuppressWarnings("unchecked")
+ OFOxm<org.projectfloodlight.openflow.types.MacAddress> ethsrc =
+ (OFOxm<org.projectfloodlight.openflow.types.MacAddress>) oxm;
+ builder.setEthSrc(MacAddress.valueOf(ethsrc.getValue().getLong()));
+ break;
+ case IPV4_DST:
+ @SuppressWarnings("unchecked")
+ OFOxm<IPv4Address> ip4dst = (OFOxm<IPv4Address>) oxm;
+ builder.setIpDst(Ip4Address.valueOf(ip4dst.getValue().getInt()));
+ break;
+ case IPV4_SRC:
+ @SuppressWarnings("unchecked")
+ OFOxm<IPv4Address> ip4src = (OFOxm<IPv4Address>) oxm;
+ builder.setIpSrc(Ip4Address.valueOf(ip4src.getValue().getInt()));
+ break;
+ case MPLS_LABEL:
+ @SuppressWarnings("unchecked")
+ OFOxm<U32> labelId = (OFOxm<U32>) oxm;
+ builder.setMpls(MplsLabel.mplsLabel((int) labelId.getValue().getValue()));
+ break;
+ case MPLS_BOS:
+ @SuppressWarnings("unchecked")
+ OFOxm<U8> mplsBos = (OFOxm<U8>) oxm;
+ builder.setMplsBos(mplsBos.getValue() == U8.ZERO ? false : true);
+ break;
+ case ARP_OP:
+ case ARP_SHA:
+ case ARP_SPA:
+ case ARP_THA:
+ case ARP_TPA:
+ case BSN_EGR_PORT_GROUP_ID:
+ case BSN_GLOBAL_VRF_ALLOWED:
+ case BSN_IN_PORTS_128:
+ case BSN_L3_DST_CLASS_ID:
+ case BSN_L3_INTERFACE_CLASS_ID:
+ case BSN_L3_SRC_CLASS_ID:
+ case BSN_LAG_ID:
+ case BSN_TCP_FLAGS:
+ case BSN_UDF0:
+ case BSN_UDF1:
+ case BSN_UDF2:
+ case BSN_UDF3:
+ case BSN_UDF4:
+ case BSN_UDF5:
+ case BSN_UDF6:
+ case BSN_UDF7:
+ case BSN_VLAN_XLATE_PORT_GROUP_ID:
+ case BSN_VRF:
+ case ETH_TYPE:
+ case ICMPV4_CODE:
+ case ICMPV4_TYPE:
+ case ICMPV6_CODE:
+ case ICMPV6_TYPE:
+ case IN_PHY_PORT:
+ case IN_PORT:
+ case IPV6_DST:
+ case IPV6_FLABEL:
+ case IPV6_ND_SLL:
+ case IPV6_ND_TARGET:
+ case IPV6_ND_TLL:
+ case IPV6_SRC:
+ case IP_DSCP:
+ case IP_ECN:
+ case IP_PROTO:
+ case METADATA:
+ case MPLS_TC:
+ case OCH_SIGID:
+ case OCH_SIGID_BASIC:
+ case OCH_SIGTYPE:
+ case OCH_SIGTYPE_BASIC:
+ case SCTP_DST:
+ case SCTP_SRC:
+ case TCP_DST:
+ case TCP_SRC:
+ case TUNNEL_ID:
+ case UDP_DST:
+ case UDP_SRC:
+ default:
+ log.warn("Set field type {} not yet implemented.", oxm.getMatchField().id);
+ break;
+ }
+ }
+}
diff --git a/framework/src/onos/providers/openflow/group/src/main/java/org/onosproject/provider/of/group/impl/GroupModBuilder.java b/framework/src/onos/providers/openflow/group/src/main/java/org/onosproject/provider/of/group/impl/GroupModBuilder.java
new file mode 100644
index 00000000..d5804f44
--- /dev/null
+++ b/framework/src/onos/providers/openflow/group/src/main/java/org/onosproject/provider/of/group/impl/GroupModBuilder.java
@@ -0,0 +1,376 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * 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.provider.of.group.impl;
+
+import org.onlab.packet.Ip4Address;
+import org.onlab.packet.Ip6Address;
+import org.onosproject.core.GroupId;
+import org.onosproject.net.PortNumber;
+import org.onosproject.net.flow.TrafficTreatment;
+import org.onosproject.net.flow.instructions.Instruction;
+import org.onosproject.net.flow.instructions.Instructions;
+import org.onosproject.net.flow.instructions.L0ModificationInstruction;
+import org.onosproject.net.flow.instructions.L2ModificationInstruction;
+import org.onosproject.net.flow.instructions.L3ModificationInstruction;
+import org.onosproject.net.group.GroupBucket;
+import org.onosproject.net.group.GroupBuckets;
+import org.onosproject.net.group.GroupDescription;
+import org.projectfloodlight.openflow.protocol.OFBucket;
+import org.projectfloodlight.openflow.protocol.OFFactory;
+import org.projectfloodlight.openflow.protocol.OFGroupAdd;
+import org.projectfloodlight.openflow.protocol.OFGroupDelete;
+import org.projectfloodlight.openflow.protocol.OFGroupMod;
+import org.projectfloodlight.openflow.protocol.OFGroupType;
+import org.projectfloodlight.openflow.protocol.action.OFAction;
+import org.projectfloodlight.openflow.protocol.action.OFActionGroup;
+import org.projectfloodlight.openflow.protocol.action.OFActionOutput;
+import org.projectfloodlight.openflow.protocol.oxm.OFOxm;
+import org.projectfloodlight.openflow.types.CircuitSignalID;
+import org.projectfloodlight.openflow.types.EthType;
+import org.projectfloodlight.openflow.types.IPv4Address;
+import org.projectfloodlight.openflow.types.IPv6Address;
+import org.projectfloodlight.openflow.types.IPv6FlowLabel;
+import org.projectfloodlight.openflow.types.MacAddress;
+import org.projectfloodlight.openflow.types.OFBooleanValue;
+import org.projectfloodlight.openflow.types.OFGroup;
+import org.projectfloodlight.openflow.types.OFPort;
+import org.projectfloodlight.openflow.types.OFVlanVidMatch;
+import org.projectfloodlight.openflow.types.U32;
+import org.projectfloodlight.openflow.types.VlanPcp;
+import org.slf4j.Logger;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Optional;
+
+import static org.slf4j.LoggerFactory.getLogger;
+
+/*
+ * Builder for GroupMod.
+ */
+public final class GroupModBuilder {
+
+ private GroupBuckets buckets;
+ private GroupId groupId;
+ private GroupDescription.Type type;
+ private OFFactory factory;
+ private Long xid;
+
+ private final Logger log = getLogger(getClass());
+
+ private static final int OFPCML_NO_BUFFER = 0xffff;
+
+ private GroupModBuilder(GroupBuckets buckets, GroupId groupId,
+ GroupDescription.Type type, OFFactory factory,
+ Optional<Long> xid) {
+ this.buckets = buckets;
+ this.groupId = groupId;
+ this.type = type;
+ this.factory = factory;
+ this.xid = xid.orElse((long) 0);
+ }
+
+ /**
+ * Creates a builder for GroupMod.
+ *
+ * @param buckets GroupBuckets object
+ * @param groupId Group Id to create
+ * @param type Group type
+ * @param factory OFFactory object
+ * @param xid transaction ID
+ * @return GroupModBuilder object
+ */
+ public static GroupModBuilder builder(GroupBuckets buckets, GroupId groupId,
+ GroupDescription.Type type, OFFactory factory,
+ Optional<Long> xid) {
+
+ return new GroupModBuilder(buckets, groupId, type, factory, xid);
+ }
+
+ /**
+ * Builds the GroupAdd OF message.
+ *
+ * @return GroupAdd OF message
+ */
+ public OFGroupAdd buildGroupAdd() {
+
+ List<OFBucket> ofBuckets = new ArrayList<OFBucket>();
+ for (GroupBucket bucket: buckets.buckets()) {
+ List<OFAction> actions = buildActions(bucket.treatment());
+
+ OFBucket.Builder bucketBuilder = factory.buildBucket();
+ bucketBuilder.setActions(actions);
+ if (type == GroupDescription.Type.SELECT) {
+ bucketBuilder.setWeight(1);
+ }
+ bucketBuilder.setWatchGroup(OFGroup.ANY);
+ bucketBuilder.setWatchPort(OFPort.ANY);
+ OFBucket ofBucket = bucketBuilder.build();
+ ofBuckets.add(ofBucket);
+ }
+
+ OFGroupAdd groupMsg = factory.buildGroupAdd()
+ .setGroup(OFGroup.of(groupId.id()))
+ .setBuckets(ofBuckets)
+ .setGroupType(getOFGroupType(type))
+ .setXid(xid)
+ .build();
+
+ return groupMsg;
+ }
+
+ /**
+ * Builds the GroupMod OF message.
+ *
+ * @return GroupMod OF message
+ */
+ public OFGroupMod buildGroupMod() {
+ List<OFBucket> ofBuckets = new ArrayList<OFBucket>();
+ for (GroupBucket bucket: buckets.buckets()) {
+ List<OFAction> actions = buildActions(bucket.treatment());
+
+ OFBucket.Builder bucketBuilder = factory.buildBucket();
+ bucketBuilder.setActions(actions);
+ if (type == GroupDescription.Type.SELECT) {
+ bucketBuilder.setWeight(1);
+ }
+ bucketBuilder.setWatchGroup(OFGroup.ANY);
+ bucketBuilder.setWatchPort(OFPort.ANY);
+ OFBucket ofBucket = bucketBuilder.build();
+ ofBuckets.add(ofBucket);
+ }
+
+ OFGroupMod groupMsg = factory.buildGroupModify()
+ .setGroup(OFGroup.of(groupId.id()))
+ .setBuckets(ofBuckets)
+ .setGroupType(getOFGroupType(type))
+ .setXid(xid)
+ .build();
+
+ return groupMsg;
+ }
+
+ /**
+ * Builds the GroupDel OF message.
+ *
+ * @return GroupDel OF message
+ */
+ public OFGroupDelete buildGroupDel() {
+
+ OFGroupDelete groupMsg = factory.buildGroupDelete()
+ .setGroup(OFGroup.of(groupId.id()))
+ .setGroupType(OFGroupType.SELECT)
+ .setXid(xid)
+ .build();
+
+ return groupMsg;
+ }
+
+ private List<OFAction> buildActions(TrafficTreatment treatment) {
+ if (treatment == null) {
+ return Collections.emptyList();
+ }
+
+ List<OFAction> actions = new LinkedList<>();
+ for (Instruction i : treatment.allInstructions()) {
+ switch (i.type()) {
+ case DROP:
+ log.warn("Saw drop action; assigning drop action");
+ return Collections.emptyList();
+ case L0MODIFICATION:
+ actions.add(buildL0Modification(i));
+ break;
+ case L2MODIFICATION:
+ actions.add(buildL2Modification(i));
+ break;
+ case L3MODIFICATION:
+ actions.add(buildL3Modification(i));
+ break;
+ case OUTPUT:
+ Instructions.OutputInstruction out =
+ (Instructions.OutputInstruction) i;
+ OFActionOutput.Builder action = factory.actions().buildOutput()
+ .setPort(OFPort.of((int) out.port().toLong()));
+ if (out.port().equals(PortNumber.CONTROLLER)) {
+ action.setMaxLen(OFPCML_NO_BUFFER);
+ }
+ actions.add(action.build());
+ break;
+ case GROUP:
+ Instructions.GroupInstruction grp =
+ (Instructions.GroupInstruction) i;
+ OFActionGroup.Builder actgrp = factory.actions().buildGroup()
+ .setGroup(OFGroup.of(grp.groupId().id()));
+ actions.add(actgrp.build());
+ break;
+ default:
+ log.warn("Instruction type {} not yet implemented.", i.type());
+ }
+ }
+
+ return actions;
+ }
+
+ private OFAction buildL0Modification(Instruction i) {
+ L0ModificationInstruction l0m = (L0ModificationInstruction) i;
+ switch (l0m.subtype()) {
+ case LAMBDA:
+ L0ModificationInstruction.ModLambdaInstruction ml =
+ (L0ModificationInstruction.ModLambdaInstruction) i;
+ return factory.actions().circuit(factory.oxms().ochSigidBasic(
+ new CircuitSignalID((byte) 1, (byte) 2, ml.lambda(), (short) 1)));
+ default:
+ log.warn("Unimplemented action type {}.", l0m.subtype());
+ break;
+ }
+ return null;
+ }
+
+ private OFAction buildL2Modification(Instruction i) {
+ L2ModificationInstruction l2m = (L2ModificationInstruction) i;
+ L2ModificationInstruction.ModEtherInstruction eth;
+ OFOxm<?> oxm = null;
+ switch (l2m.subtype()) {
+ case ETH_DST:
+ eth = (L2ModificationInstruction.ModEtherInstruction) l2m;
+ oxm = factory.oxms().ethDst(MacAddress.of(eth.mac().toLong()));
+ break;
+ case ETH_SRC:
+ eth = (L2ModificationInstruction.ModEtherInstruction) l2m;
+ oxm = factory.oxms().ethSrc(MacAddress.of(eth.mac().toLong()));
+ break;
+ case VLAN_ID:
+ L2ModificationInstruction.ModVlanIdInstruction vlanId =
+ (L2ModificationInstruction.ModVlanIdInstruction) l2m;
+ oxm = factory.oxms().vlanVid(OFVlanVidMatch.ofVlan(vlanId.vlanId().toShort()));
+ break;
+ case VLAN_PCP:
+ L2ModificationInstruction.ModVlanPcpInstruction vlanPcp =
+ (L2ModificationInstruction.ModVlanPcpInstruction) l2m;
+ oxm = factory.oxms().vlanPcp(VlanPcp.of(vlanPcp.vlanPcp()));
+ break;
+ case VLAN_POP:
+ return factory.actions().popVlan();
+ case VLAN_PUSH:
+ L2ModificationInstruction.PushHeaderInstructions pushVlanInstruction
+ = (L2ModificationInstruction.PushHeaderInstructions) l2m;
+ return factory.actions().pushVlan(
+ EthType.of(pushVlanInstruction.ethernetType().toShort()));
+ case MPLS_PUSH:
+ L2ModificationInstruction.PushHeaderInstructions pushHeaderInstructions =
+ (L2ModificationInstruction.PushHeaderInstructions) l2m;
+ return factory.actions().pushMpls(EthType.of(pushHeaderInstructions
+ .ethernetType().toShort()));
+ case MPLS_POP:
+ L2ModificationInstruction.PushHeaderInstructions popHeaderInstructions =
+ (L2ModificationInstruction.PushHeaderInstructions) l2m;
+ return factory.actions().popMpls(EthType.of(popHeaderInstructions
+ .ethernetType().toShort()));
+ case MPLS_LABEL:
+ L2ModificationInstruction.ModMplsLabelInstruction mplsLabel =
+ (L2ModificationInstruction.ModMplsLabelInstruction) l2m;
+ oxm = factory.oxms().mplsLabel(U32.of(mplsLabel.mplsLabel().toInt()));
+ break;
+ case MPLS_BOS:
+ L2ModificationInstruction.ModMplsBosInstruction mplsBos =
+ (L2ModificationInstruction.ModMplsBosInstruction) l2m;
+ oxm = factory.oxms()
+ .mplsBos(mplsBos.mplsBos() ? OFBooleanValue.TRUE
+ : OFBooleanValue.FALSE);
+ break;
+ case DEC_MPLS_TTL:
+ return factory.actions().decMplsTtl();
+ default:
+ log.warn("Unimplemented action type {}.", l2m.subtype());
+ break;
+ }
+
+ if (oxm != null) {
+ return factory.actions().buildSetField().setField(oxm).build();
+ }
+ return null;
+ }
+
+ private OFAction buildL3Modification(Instruction i) {
+ L3ModificationInstruction l3m = (L3ModificationInstruction) i;
+ L3ModificationInstruction.ModIPInstruction ip;
+ Ip4Address ip4;
+ Ip6Address ip6;
+ OFOxm<?> oxm = null;
+ switch (l3m.subtype()) {
+ case IPV4_SRC:
+ ip = (L3ModificationInstruction.ModIPInstruction) i;
+ ip4 = ip.ip().getIp4Address();
+ oxm = factory.oxms().ipv4Src(IPv4Address.of(ip4.toInt()));
+ break;
+ case IPV4_DST:
+ ip = (L3ModificationInstruction.ModIPInstruction) i;
+ ip4 = ip.ip().getIp4Address();
+ oxm = factory.oxms().ipv4Dst(IPv4Address.of(ip4.toInt()));
+ break;
+ case IPV6_SRC:
+ ip = (L3ModificationInstruction.ModIPInstruction) i;
+ ip6 = ip.ip().getIp6Address();
+ oxm = factory.oxms().ipv6Src(IPv6Address.of(ip6.toOctets()));
+ break;
+ case IPV6_DST:
+ ip = (L3ModificationInstruction.ModIPInstruction) i;
+ ip6 = ip.ip().getIp6Address();
+ oxm = factory.oxms().ipv6Dst(IPv6Address.of(ip6.toOctets()));
+ break;
+ case IPV6_FLABEL:
+ L3ModificationInstruction.ModIPv6FlowLabelInstruction flowLabelInstruction =
+ (L3ModificationInstruction.ModIPv6FlowLabelInstruction) i;
+ int flowLabel = flowLabelInstruction.flowLabel();
+ oxm = factory.oxms().ipv6Flabel(IPv6FlowLabel.of(flowLabel));
+ break;
+ case DEC_TTL:
+ return factory.actions().decNwTtl();
+ case TTL_IN:
+ return factory.actions().copyTtlIn();
+ case TTL_OUT:
+ return factory.actions().copyTtlOut();
+ default:
+ log.warn("Unimplemented action type {}.", l3m.subtype());
+ break;
+ }
+
+ if (oxm != null) {
+ return factory.actions().buildSetField().setField(oxm).build();
+ }
+ return null;
+ }
+
+ private OFGroupType getOFGroupType(GroupDescription.Type groupType) {
+ switch (groupType) {
+ case INDIRECT:
+ return OFGroupType.INDIRECT;
+ case SELECT:
+ return OFGroupType.SELECT;
+ case FAILOVER:
+ return OFGroupType.FF;
+ case ALL:
+ return OFGroupType.ALL;
+ default:
+ log.error("Unsupported group type : {}", groupType);
+ break;
+ }
+ return null;
+ }
+}
+
diff --git a/framework/src/onos/providers/openflow/group/src/main/java/org/onosproject/provider/of/group/impl/GroupStatsCollector.java b/framework/src/onos/providers/openflow/group/src/main/java/org/onosproject/provider/of/group/impl/GroupStatsCollector.java
new file mode 100644
index 00000000..9816426b
--- /dev/null
+++ b/framework/src/onos/providers/openflow/group/src/main/java/org/onosproject/provider/of/group/impl/GroupStatsCollector.java
@@ -0,0 +1,111 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * 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.provider.of.group.impl;
+
+import org.jboss.netty.util.HashedWheelTimer;
+import org.jboss.netty.util.Timeout;
+import org.jboss.netty.util.TimerTask;
+import org.onlab.util.Timer;
+import org.onosproject.openflow.controller.OpenFlowSwitch;
+import org.onosproject.openflow.controller.RoleState;
+import org.projectfloodlight.openflow.protocol.OFGroupDescStatsRequest;
+import org.projectfloodlight.openflow.protocol.OFGroupStatsRequest;
+import org.projectfloodlight.openflow.types.OFGroup;
+import org.slf4j.Logger;
+
+import java.util.concurrent.TimeUnit;
+
+import static org.slf4j.LoggerFactory.getLogger;
+
+/*
+ * Sends Group Stats Request and collect the group statistics with a time interval.
+ */
+public class GroupStatsCollector implements TimerTask {
+
+ private final HashedWheelTimer timer = Timer.getTimer();
+ private final OpenFlowSwitch sw;
+ private final Logger log = getLogger(getClass());
+ private final int refreshInterval;
+
+ private Timeout timeout;
+
+ private boolean stopTimer = false;
+
+ /**
+ * Creates a GroupStatsCollector object.
+ *
+ * @param sw Open Flow switch
+ * @param interval time interval for collecting group statistic
+ */
+ public GroupStatsCollector(OpenFlowSwitch sw, int interval) {
+ this.sw = sw;
+ this.refreshInterval = interval;
+ }
+
+ @Override
+ public void run(Timeout timeout) throws Exception {
+ log.trace("Collecting stats for {}", sw.getStringId());
+
+ sendGroupStatistic();
+
+ if (!this.stopTimer) {
+ log.trace("Scheduling stats collection in {} seconds for {}",
+ this.refreshInterval, this.sw.getStringId());
+ timeout.getTimer().newTimeout(this, refreshInterval,
+ TimeUnit.SECONDS);
+ }
+ }
+
+ private void sendGroupStatistic() {
+ if (log.isTraceEnabled()) {
+ log.trace("sendGroupStatistics {}:{}", sw.getStringId(), sw.getRole());
+ }
+ if (sw.getRole() != RoleState.MASTER) {
+ return;
+ }
+ Long statsXid = OpenFlowGroupProvider.getXidAndAdd(2);
+ OFGroupStatsRequest statsRequest = sw.factory().buildGroupStatsRequest()
+ .setGroup(OFGroup.ALL)
+ .setXid(statsXid)
+ .build();
+ sw.sendMsg(statsRequest);
+
+ Long descXid = statsXid + 1;
+ OFGroupDescStatsRequest descStatsRequest =
+ sw.factory().buildGroupDescStatsRequest()
+ .setXid(descXid)
+ .build();
+ sw.sendMsg(descStatsRequest);
+ }
+
+ /**
+ * Starts the collector.
+ */
+ public void start() {
+ log.info("Starting Group Stats collection thread for {}", sw.getStringId());
+ timeout = timer.newTimeout(this, 1, TimeUnit.SECONDS);
+ }
+
+ /**
+ * Stops the collector.
+ */
+ public void stop() {
+ log.info("Stopping Group Stats collection thread for {}", sw.getStringId());
+ this.stopTimer = true;
+ timeout.cancel();
+ }
+}
diff --git a/framework/src/onos/providers/openflow/group/src/main/java/org/onosproject/provider/of/group/impl/OpenFlowGroupProvider.java b/framework/src/onos/providers/openflow/group/src/main/java/org/onosproject/provider/of/group/impl/OpenFlowGroupProvider.java
new file mode 100644
index 00000000..78650fe6
--- /dev/null
+++ b/framework/src/onos/providers/openflow/group/src/main/java/org/onosproject/provider/of/group/impl/OpenFlowGroupProvider.java
@@ -0,0 +1,366 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * 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.provider.of.group.impl;
+
+import com.google.common.collect.Maps;
+
+import org.apache.felix.scr.annotations.Activate;
+import org.apache.felix.scr.annotations.Component;
+import org.apache.felix.scr.annotations.Deactivate;
+import org.apache.felix.scr.annotations.Reference;
+import org.apache.felix.scr.annotations.ReferenceCardinality;
+import org.onosproject.core.DefaultGroupId;
+import org.onosproject.core.GroupId;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.group.DefaultGroup;
+import org.onosproject.net.group.Group;
+import org.onosproject.net.group.GroupBuckets;
+import org.onosproject.net.group.GroupDescription;
+import org.onosproject.net.group.GroupOperation;
+import org.onosproject.net.group.GroupOperations;
+import org.onosproject.net.group.GroupProvider;
+import org.onosproject.net.group.GroupProviderRegistry;
+import org.onosproject.net.group.GroupProviderService;
+import org.onosproject.net.group.StoredGroupBucketEntry;
+import org.onosproject.net.provider.AbstractProvider;
+import org.onosproject.net.provider.ProviderId;
+import org.onosproject.openflow.controller.Dpid;
+import org.onosproject.openflow.controller.OpenFlowController;
+import org.onosproject.openflow.controller.OpenFlowEventListener;
+import org.onosproject.openflow.controller.OpenFlowSwitch;
+import org.onosproject.openflow.controller.OpenFlowSwitchListener;
+import org.onosproject.openflow.controller.RoleState;
+import org.projectfloodlight.openflow.protocol.OFBucketCounter;
+import org.projectfloodlight.openflow.protocol.OFErrorMsg;
+import org.projectfloodlight.openflow.protocol.OFErrorType;
+import org.projectfloodlight.openflow.protocol.OFGroupDescStatsEntry;
+import org.projectfloodlight.openflow.protocol.OFGroupDescStatsReply;
+import org.projectfloodlight.openflow.protocol.OFGroupMod;
+import org.projectfloodlight.openflow.protocol.OFGroupStatsEntry;
+import org.projectfloodlight.openflow.protocol.OFGroupStatsReply;
+import org.projectfloodlight.openflow.protocol.OFGroupType;
+import org.projectfloodlight.openflow.protocol.OFMessage;
+import org.projectfloodlight.openflow.protocol.OFPortStatus;
+import org.projectfloodlight.openflow.protocol.OFStatsReply;
+import org.projectfloodlight.openflow.protocol.OFStatsType;
+import org.projectfloodlight.openflow.protocol.OFVersion;
+import org.slf4j.Logger;
+
+import java.util.Collection;
+import java.util.Map;
+import java.util.Optional;
+import java.util.concurrent.atomic.AtomicLong;
+
+import static org.slf4j.LoggerFactory.getLogger;
+
+/**
+ * Provider which uses an OpenFlow controller to handle Group.
+ */
+@Component(immediate = true)
+public class OpenFlowGroupProvider extends AbstractProvider implements GroupProvider {
+
+ private final Logger log = getLogger(getClass());
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected OpenFlowController controller;
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected GroupProviderRegistry providerRegistry;
+
+ private GroupProviderService providerService;
+
+ static final int POLL_INTERVAL = 10;
+
+ private final InternalGroupProvider listener = new InternalGroupProvider();
+
+ private static final AtomicLong XID_COUNTER = new AtomicLong(1);
+ private final Map<Dpid, GroupStatsCollector> collectors = Maps.newHashMap();
+ private final Map<Long, OFStatsReply> groupStats = Maps.newConcurrentMap();
+ private final Map<GroupId, GroupOperation> pendingGroupOperations =
+ Maps.newConcurrentMap();
+
+ /* Map<Group ID, Transaction ID> */
+ private final Map<GroupId, Long> pendingXidMaps = Maps.newConcurrentMap();
+
+ /**
+ * Creates a OpenFlow group provider.
+ */
+ public OpenFlowGroupProvider() {
+ super(new ProviderId("of", "org.onosproject.provider.group"));
+ }
+
+ @Activate
+ public void activate() {
+ providerService = providerRegistry.register(this);
+ controller.addListener(listener);
+ controller.addEventListener(listener);
+
+ for (OpenFlowSwitch sw : controller.getSwitches()) {
+ if (isGroupSupported(sw)) {
+ GroupStatsCollector gsc = new GroupStatsCollector(sw, POLL_INTERVAL);
+ gsc.start();
+ collectors.put(new Dpid(sw.getId()), gsc);
+ }
+ }
+
+ log.info("Started");
+ }
+
+ @Deactivate
+ public void deactivate() {
+ providerRegistry.unregister(this);
+ providerService = null;
+
+ log.info("Stopped");
+ }
+
+ @Override
+ public void performGroupOperation(DeviceId deviceId, GroupOperations groupOps) {
+ Map<OFGroupMod, OpenFlowSwitch> mods = Maps.newIdentityHashMap();
+ final Dpid dpid = Dpid.dpid(deviceId.uri());
+ OpenFlowSwitch sw = controller.getSwitch(dpid);
+ for (GroupOperation groupOperation: groupOps.operations()) {
+ if (sw == null) {
+ log.error("SW {} is not found", dpid);
+ return;
+ }
+ final Long groupModXid = XID_COUNTER.getAndIncrement();
+ GroupModBuilder builder =
+ GroupModBuilder.builder(groupOperation.buckets(),
+ groupOperation.groupId(),
+ groupOperation.groupType(),
+ sw.factory(),
+ Optional.of(groupModXid));
+ OFGroupMod groupMod = null;
+ switch (groupOperation.opType()) {
+ case ADD:
+ groupMod = builder.buildGroupAdd();
+ break;
+ case MODIFY:
+ groupMod = builder.buildGroupMod();
+ break;
+ case DELETE:
+ groupMod = builder.buildGroupDel();
+ break;
+ default:
+ log.error("Unsupported Group operation");
+ }
+ sw.sendMsg(groupMod);
+ GroupId groudId = new DefaultGroupId(groupMod.getGroup().getGroupNumber());
+ pendingGroupOperations.put(groudId, groupOperation);
+ pendingXidMaps.put(groudId, groupModXid);
+ }
+ }
+
+ private void pushGroupMetrics(Dpid dpid, OFStatsReply statsReply) {
+ DeviceId deviceId = DeviceId.deviceId(Dpid.uri(dpid));
+
+ OFGroupStatsReply groupStatsReply = null;
+ OFGroupDescStatsReply groupDescStatsReply = null;
+
+ synchronized (groupStats) {
+ if (statsReply.getStatsType() == OFStatsType.GROUP) {
+ OFStatsReply reply = groupStats.get(statsReply.getXid() + 1);
+ if (reply != null) {
+ groupStatsReply = (OFGroupStatsReply) statsReply;
+ groupDescStatsReply = (OFGroupDescStatsReply) reply;
+ groupStats.remove(statsReply.getXid() + 1);
+ } else {
+ groupStats.put(statsReply.getXid(), statsReply);
+ }
+ } else if (statsReply.getStatsType() == OFStatsType.GROUP_DESC) {
+ OFStatsReply reply = groupStats.get(statsReply.getXid() - 1);
+ if (reply != null) {
+ groupStatsReply = (OFGroupStatsReply) reply;
+ groupDescStatsReply = (OFGroupDescStatsReply) statsReply;
+ groupStats.remove(statsReply.getXid() - 1);
+ } else {
+ groupStats.put(statsReply.getXid(), statsReply);
+ }
+ }
+ }
+
+ if (groupStatsReply != null && groupDescStatsReply != null) {
+ Collection<Group> groups = buildGroupMetrics(deviceId,
+ groupStatsReply, groupDescStatsReply);
+ providerService.pushGroupMetrics(deviceId, groups);
+ for (Group group: groups) {
+ pendingGroupOperations.remove(group.id());
+ pendingXidMaps.remove(group.id());
+ }
+ }
+ }
+
+ private Collection<Group> buildGroupMetrics(DeviceId deviceId,
+ OFGroupStatsReply groupStatsReply,
+ OFGroupDescStatsReply groupDescStatsReply) {
+
+ Map<Integer, Group> groups = Maps.newHashMap();
+
+
+ for (OFGroupDescStatsEntry entry: groupDescStatsReply.getEntries()) {
+ int id = entry.getGroup().getGroupNumber();
+ GroupId groupId = new DefaultGroupId(id);
+ GroupDescription.Type type = getGroupType(entry.getGroupType());
+ GroupBuckets buckets = new GroupBucketEntryBuilder(entry.getBuckets(),
+ entry.getGroupType()).build();
+ DefaultGroup group = new DefaultGroup(groupId, deviceId, type, buckets);
+ groups.put(id, group);
+ }
+
+ for (OFGroupStatsEntry entry: groupStatsReply.getEntries()) {
+ int groupId = entry.getGroup().getGroupNumber();
+ DefaultGroup group = (DefaultGroup) groups.get(groupId);
+ if (group != null) {
+ group.setBytes(entry.getByteCount().getValue());
+ group.setLife(entry.getDurationSec());
+ group.setPackets(entry.getPacketCount().getValue());
+ group.setReferenceCount(entry.getRefCount());
+ int bucketIndex = 0;
+ for (OFBucketCounter bucketStats:entry.getBucketStats()) {
+ ((StoredGroupBucketEntry) group.buckets().buckets()
+ .get(bucketIndex))
+ .setPackets(bucketStats
+ .getPacketCount().getValue());
+ ((StoredGroupBucketEntry) group.buckets().buckets()
+ .get(bucketIndex))
+ .setBytes(entry.getBucketStats()
+ .get(bucketIndex)
+ .getByteCount().getValue());
+ bucketIndex++;
+ }
+ }
+ }
+
+ return groups.values();
+ }
+
+ private GroupDescription.Type getGroupType(OFGroupType type) {
+ switch (type) {
+ case ALL:
+ return GroupDescription.Type.ALL;
+ case INDIRECT:
+ return GroupDescription.Type.INDIRECT;
+ case SELECT:
+ return GroupDescription.Type.SELECT;
+ case FF:
+ return GroupDescription.Type.FAILOVER;
+ default:
+ log.error("Unsupported OF group type : {}", type);
+ break;
+ }
+ return null;
+ }
+
+ /**
+ * Returns a transaction ID for entire group operations and increases
+ * the counter by the number given.
+ *
+ * @param increase the amount to increase the counter by
+ * @return a transaction ID
+ */
+ public static long getXidAndAdd(int increase) {
+ return XID_COUNTER.getAndAdd(increase);
+ }
+
+ private boolean isGroupSupported(OpenFlowSwitch sw) {
+ if (sw.factory().getVersion() == OFVersion.OF_10 ||
+ sw.factory().getVersion() == OFVersion.OF_11 ||
+ sw.factory().getVersion() == OFVersion.OF_12) {
+ return false;
+ }
+
+ return true;
+ }
+
+ private class InternalGroupProvider
+ implements OpenFlowSwitchListener, OpenFlowEventListener {
+
+ @Override
+ public void handleMessage(Dpid dpid, OFMessage msg) {
+ switch (msg.getType()) {
+ case STATS_REPLY:
+ pushGroupMetrics(dpid, (OFStatsReply) msg);
+ break;
+ case ERROR:
+ OFErrorMsg errorMsg = (OFErrorMsg) msg;
+ if (errorMsg.getErrType() == OFErrorType.GROUP_MOD_FAILED) {
+ GroupId pendingGroupId = null;
+ for (Map.Entry<GroupId, Long> entry: pendingXidMaps.entrySet()) {
+ if (entry.getValue() == errorMsg.getXid()) {
+ pendingGroupId = entry.getKey();
+ break;
+ }
+ }
+ if (pendingGroupId == null) {
+ log.warn("Error for unknown group operation: {}",
+ errorMsg.getXid());
+ } else {
+ GroupOperation operation =
+ pendingGroupOperations.get(pendingGroupId);
+ DeviceId deviceId = DeviceId.deviceId(Dpid.uri(dpid));
+ if (operation != null) {
+ providerService.groupOperationFailed(deviceId,
+ operation);
+ pendingGroupOperations.remove(pendingGroupId);
+ pendingXidMaps.remove(pendingGroupId);
+ log.warn("Received an group mod error {}", msg);
+ } else {
+ log.error("Cannot find pending group operation with group ID: {}",
+ pendingGroupId);
+ }
+ }
+ break;
+ }
+ default:
+ break;
+ }
+ }
+
+ @Override
+ public void switchAdded(Dpid dpid) {
+ OpenFlowSwitch sw = controller.getSwitch(dpid);
+ if (isGroupSupported(sw)) {
+ GroupStatsCollector gsc = new GroupStatsCollector(
+ controller.getSwitch(dpid), POLL_INTERVAL);
+ gsc.start();
+ collectors.put(dpid, gsc);
+ }
+ }
+
+ @Override
+ public void switchRemoved(Dpid dpid) {
+ GroupStatsCollector collector = collectors.remove(dpid);
+ if (collector != null) {
+ collector.stop();
+ }
+ }
+
+ @Override
+ public void switchChanged(Dpid dpid) {
+ }
+
+ @Override
+ public void portChanged(Dpid dpid, OFPortStatus status) {
+ }
+
+ @Override
+ public void receivedRoleReply(Dpid dpid, RoleState requested, RoleState response) {
+ }
+ }
+
+}
diff --git a/framework/src/onos/providers/openflow/group/src/main/java/org/onosproject/provider/of/group/impl/package-info.java b/framework/src/onos/providers/openflow/group/src/main/java/org/onosproject/provider/of/group/impl/package-info.java
new file mode 100644
index 00000000..9fda4a31
--- /dev/null
+++ b/framework/src/onos/providers/openflow/group/src/main/java/org/onosproject/provider/of/group/impl/package-info.java
@@ -0,0 +1,20 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * 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.
+ */
+
+/**
+ * Provider that uses OpenFlow controller as a means of device port group management.
+ */
+package org.onosproject.provider.of.group.impl; \ No newline at end of file