summaryrefslogtreecommitdiffstats
path: root/framework/src/onos/providers/openflow
diff options
context:
space:
mode:
authorAshlee Young <ashlee@onosfw.com>2015-09-09 22:15:21 -0700
committerAshlee Young <ashlee@onosfw.com>2015-09-09 22:15:21 -0700
commit13d05bc8458758ee39cb829098241e89616717ee (patch)
tree22a4d1ce65f15952f07a3df5af4b462b4697cb3a /framework/src/onos/providers/openflow
parent6139282e1e93c2322076de4b91b1c85d0bc4a8b3 (diff)
ONOS checkin based on commit tag e796610b1f721d02f9b0e213cf6f7790c10ecd60
Change-Id: Ife8810491034fe7becdba75dda20de4267bd15cd
Diffstat (limited to 'framework/src/onos/providers/openflow')
-rw-r--r--framework/src/onos/providers/openflow/app/app.xml33
-rw-r--r--framework/src/onos/providers/openflow/app/features.xml34
-rw-r--r--framework/src/onos/providers/openflow/app/pom.xml81
-rw-r--r--framework/src/onos/providers/openflow/device/pom.xml39
-rw-r--r--framework/src/onos/providers/openflow/device/src/main/java/org/onosproject/provider/of/device/impl/OpenFlowDeviceProvider.java569
-rw-r--r--framework/src/onos/providers/openflow/device/src/main/java/org/onosproject/provider/of/device/impl/PortStatsCollector.java113
-rw-r--r--framework/src/onos/providers/openflow/device/src/main/java/org/onosproject/provider/of/device/impl/package-info.java20
-rw-r--r--framework/src/onos/providers/openflow/device/src/test/java/org/onosproject/provider/of/device/impl/OpenFlowDeviceProviderTest.java402
-rw-r--r--framework/src/onos/providers/openflow/flow/pom.xml40
-rw-r--r--framework/src/onos/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/FlowEntryBuilder.java707
-rw-r--r--framework/src/onos/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/FlowModBuilder.java444
-rw-r--r--framework/src/onos/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/FlowModBuilderVer10.java230
-rw-r--r--framework/src/onos/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/FlowModBuilderVer13.java458
-rw-r--r--framework/src/onos/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/FlowStatsCollector.java100
-rw-r--r--framework/src/onos/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/NoMappingFoundException.java31
-rw-r--r--framework/src/onos/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/OpenFlowRuleProvider.java453
-rw-r--r--framework/src/onos/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/OpenFlowValueMapper.java152
-rw-r--r--framework/src/onos/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/package-info.java20
-rw-r--r--framework/src/onos/providers/openflow/group/pom.xml34
-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
-rw-r--r--framework/src/onos/providers/openflow/group/src/test/java/org/onosproject/provider/of/group/impl/OpenFlowGroupProviderTest.java397
-rw-r--r--framework/src/onos/providers/openflow/meter/pom.xml34
-rw-r--r--framework/src/onos/providers/openflow/meter/src/main/java/org/onosproject/provider/of/meter/impl/MeterModBuilder.java159
-rw-r--r--framework/src/onos/providers/openflow/meter/src/main/java/org/onosproject/provider/of/meter/impl/MeterStatsCollector.java103
-rw-r--r--framework/src/onos/providers/openflow/meter/src/main/java/org/onosproject/provider/of/meter/impl/OpenFlowMeterProvider.java393
-rw-r--r--framework/src/onos/providers/openflow/meter/src/main/java/org/onosproject/provider/of/meter/impl/package-info.java20
-rw-r--r--framework/src/onos/providers/openflow/meter/src/test/java/org/onosproject/provider/of/meter/impl/OpenFlowMeterProviderTest.java22
-rw-r--r--framework/src/onos/providers/openflow/packet/pom.xml34
-rw-r--r--framework/src/onos/providers/openflow/packet/src/main/java/org/onosproject/provider/of/packet/impl/OpenFlowCorePacketContext.java99
-rw-r--r--framework/src/onos/providers/openflow/packet/src/main/java/org/onosproject/provider/of/packet/impl/OpenFlowPacketProvider.java176
-rw-r--r--framework/src/onos/providers/openflow/packet/src/main/java/org/onosproject/provider/of/packet/impl/package-info.java21
-rw-r--r--framework/src/onos/providers/openflow/packet/src/test/java/org/onosproject/provider/of/packet/impl/OpenFlowPacketProviderTest.java431
-rw-r--r--framework/src/onos/providers/openflow/pom.xml63
37 files changed, 7128 insertions, 0 deletions
diff --git a/framework/src/onos/providers/openflow/app/app.xml b/framework/src/onos/providers/openflow/app/app.xml
new file mode 100644
index 00000000..e54d1a8a
--- /dev/null
+++ b/framework/src/onos/providers/openflow/app/app.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ 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.
+ -->
+<app name="org.onosproject.openflow" origin="ON.Lab" version="${project.version}"
+ featuresRepo="mvn:${project.groupId}/${project.artifactId}/${project.version}/xml/features"
+ features="${project.artifactId}">
+ <description>${project.description}</description>
+
+ <artifact>mvn:${project.groupId}/onos-of-api/${project.version}</artifact>
+ <artifact>mvn:${project.groupId}/onos-of-ctl/${project.version}</artifact>
+ <artifact>mvn:${project.groupId}/onos-drivers/${project.version}</artifact>
+
+ <artifact>mvn:${project.groupId}/onos-lldp-provider/${project.version}</artifact>
+ <artifact>mvn:${project.groupId}/onos-host-provider/${project.version}</artifact>
+ <artifact>mvn:${project.groupId}/onos-of-provider-device/${project.version}</artifact>
+ <artifact>mvn:${project.groupId}/onos-of-provider-packet/${project.version}</artifact>
+ <artifact>mvn:${project.groupId}/onos-of-provider-flow/${project.version}</artifact>
+ <artifact>mvn:${project.groupId}/onos-of-provider-group/${project.version}</artifact>
+ <artifact>mvn:${project.groupId}/onos-of-provider-meter/${project.version}</artifact>
+</app>
diff --git a/framework/src/onos/providers/openflow/app/features.xml b/framework/src/onos/providers/openflow/app/features.xml
new file mode 100644
index 00000000..7c410172
--- /dev/null
+++ b/framework/src/onos/providers/openflow/app/features.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<!--
+ ~ 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.
+ -->
+<features xmlns="http://karaf.apache.org/xmlns/features/v1.2.0" name="${project.artifactId}-${project.version}">
+ <repository>mvn:${project.groupId}/${project.artifactId}/${project.version}/xml/features</repository>
+ <feature name="${project.artifactId}" version="${project.version}"
+ description="${project.description}">
+ <feature>onos-api</feature>
+ <bundle>mvn:io.netty/netty/3.9.2.Final</bundle>
+ <bundle>mvn:${project.groupId}/onos-of-api/${project.version}</bundle>
+ <bundle>mvn:${project.groupId}/onos-of-ctl/${project.version}</bundle>
+
+ <bundle>mvn:${project.groupId}/onos-lldp-provider/${project.version}</bundle>
+ <bundle>mvn:${project.groupId}/onos-host-provider/${project.version}</bundle>
+ <bundle>mvn:${project.groupId}/onos-of-provider-device/${project.version}</bundle>
+ <bundle>mvn:${project.groupId}/onos-of-provider-packet/${project.version}</bundle>
+ <bundle>mvn:${project.groupId}/onos-of-provider-flow/${project.version}</bundle>
+ <bundle>mvn:${project.groupId}/onos-of-provider-group/${project.version}</bundle>
+ <bundle>mvn:${project.groupId}/onos-of-provider-meter/${project.version}</bundle>
+ </feature>
+</features>
diff --git a/framework/src/onos/providers/openflow/app/pom.xml b/framework/src/onos/providers/openflow/app/pom.xml
new file mode 100644
index 00000000..62e5eb87
--- /dev/null
+++ b/framework/src/onos/providers/openflow/app/pom.xml
@@ -0,0 +1,81 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ 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.
+ -->
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+
+ <parent>
+ <groupId>org.onosproject</groupId>
+ <artifactId>onos-of-providers</artifactId>
+ <version>1.3.0-SNAPSHOT</version>
+ <relativePath>../pom.xml</relativePath>
+ </parent>
+
+ <artifactId>onos-openflow</artifactId>
+ <packaging>pom</packaging>
+
+ <description>OpenFlow protocol southbound providers</description>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.onosproject</groupId>
+ <artifactId>onos-of-api</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.onosproject</groupId>
+ <artifactId>onos-of-ctl</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.onosproject</groupId>
+ <artifactId>onos-drivers</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.onosproject</groupId>
+ <artifactId>onos-of-provider-device</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.onosproject</groupId>
+ <artifactId>onos-of-provider-packet</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.onosproject</groupId>
+ <artifactId>onos-of-provider-flow</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.onosproject</groupId>
+ <artifactId>onos-of-provider-group</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.onosproject</groupId>
+ <artifactId>onos-lldp-provider</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.onosproject</groupId>
+ <artifactId>onos-host-provider</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ </dependencies>
+
+</project>
diff --git a/framework/src/onos/providers/openflow/device/pom.xml b/framework/src/onos/providers/openflow/device/pom.xml
new file mode 100644
index 00000000..5f27d42b
--- /dev/null
+++ b/framework/src/onos/providers/openflow/device/pom.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright 2014 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.
+ -->
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+
+ <parent>
+ <groupId>org.onosproject</groupId>
+ <artifactId>onos-of-providers</artifactId>
+ <version>1.3.0-SNAPSHOT</version>
+ <relativePath>../pom.xml</relativePath>
+ </parent>
+
+ <artifactId>onos-of-provider-device</artifactId>
+ <packaging>bundle</packaging>
+
+ <description>ONOS OpenFlow protocol device provider</description>
+ <dependencies>
+ <dependency>
+ <groupId>org.osgi</groupId>
+ <artifactId>org.osgi.compendium</artifactId>
+ </dependency>
+ </dependencies>
+</project>
diff --git a/framework/src/onos/providers/openflow/device/src/main/java/org/onosproject/provider/of/device/impl/OpenFlowDeviceProvider.java b/framework/src/onos/providers/openflow/device/src/main/java/org/onosproject/provider/of/device/impl/OpenFlowDeviceProvider.java
new file mode 100644
index 00000000..cb19dc52
--- /dev/null
+++ b/framework/src/onos/providers/openflow/device/src/main/java/org/onosproject/provider/of/device/impl/OpenFlowDeviceProvider.java
@@ -0,0 +1,569 @@
+/*
+ * Copyright 2014-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.device.impl;
+
+import com.google.common.base.Strings;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+import com.google.common.collect.Sets;
+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.Modified;
+import org.apache.felix.scr.annotations.Property;
+import org.apache.felix.scr.annotations.Reference;
+import org.apache.felix.scr.annotations.ReferenceCardinality;
+import org.onlab.packet.ChassisId;
+import org.onlab.util.Frequency;
+import org.onosproject.cfg.ComponentConfigService;
+import org.onlab.util.Spectrum;
+import org.onosproject.net.AnnotationKeys;
+import org.onosproject.net.ChannelSpacing;
+import org.onosproject.net.DefaultAnnotations;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.GridType;
+import org.onosproject.net.MastershipRole;
+import org.onosproject.net.OchSignal;
+import org.onosproject.net.OduSignalType;
+import org.onosproject.net.Port;
+import org.onosproject.net.PortNumber;
+import org.onosproject.net.SparseAnnotations;
+import org.onosproject.net.device.DefaultDeviceDescription;
+import org.onosproject.net.device.DefaultPortDescription;
+import org.onosproject.net.device.DefaultPortStatistics;
+import org.onosproject.net.device.DeviceDescription;
+import org.onosproject.net.device.DeviceProvider;
+import org.onosproject.net.device.DeviceProviderRegistry;
+import org.onosproject.net.device.DeviceProviderService;
+import org.onosproject.net.device.OchPortDescription;
+import org.onosproject.net.device.OmsPortDescription;
+import org.onosproject.net.device.PortDescription;
+import org.onosproject.net.device.PortStatistics;
+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.OpenFlowOpticalSwitch;
+import org.onosproject.openflow.controller.OpenFlowSwitch;
+import org.onosproject.openflow.controller.OpenFlowSwitchListener;
+import org.onosproject.openflow.controller.PortDescPropertyType;
+import org.onosproject.openflow.controller.RoleState;
+import org.osgi.service.component.ComponentContext;
+import org.projectfloodlight.openflow.protocol.OFCalientPortDescStatsEntry;
+import org.projectfloodlight.openflow.protocol.OFFactory;
+import org.projectfloodlight.openflow.protocol.OFMessage;
+import org.projectfloodlight.openflow.protocol.OFPortConfig;
+import org.projectfloodlight.openflow.protocol.OFPortDesc;
+import org.projectfloodlight.openflow.protocol.OFPortDescPropOpticalTransport;
+import org.projectfloodlight.openflow.protocol.OFPortFeatures;
+import org.projectfloodlight.openflow.protocol.OFPortOptical;
+import org.projectfloodlight.openflow.protocol.OFPortReason;
+import org.projectfloodlight.openflow.protocol.OFPortState;
+import org.projectfloodlight.openflow.protocol.OFPortStatsEntry;
+import org.projectfloodlight.openflow.protocol.OFPortStatsReply;
+import org.projectfloodlight.openflow.protocol.OFPortStatus;
+import org.projectfloodlight.openflow.protocol.OFStatsReply;
+import org.projectfloodlight.openflow.protocol.OFStatsReplyFlags;
+import org.projectfloodlight.openflow.protocol.OFStatsType;
+import org.projectfloodlight.openflow.protocol.OFVersion;
+import org.projectfloodlight.openflow.types.PortSpeed;
+import org.slf4j.Logger;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Dictionary;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Strings.isNullOrEmpty;
+import static org.onlab.util.Tools.get;
+import static org.onosproject.net.DeviceId.deviceId;
+import static org.onosproject.net.Port.Type.COPPER;
+import static org.onosproject.net.Port.Type.FIBER;
+import static org.onosproject.openflow.controller.Dpid.dpid;
+import static org.onosproject.openflow.controller.Dpid.uri;
+import static org.slf4j.LoggerFactory.getLogger;
+
+/**
+ * Provider which uses an OpenFlow controller to detect network
+ * infrastructure devices.
+ */
+@Component(immediate = true)
+public class OpenFlowDeviceProvider extends AbstractProvider implements DeviceProvider {
+
+ private static final Logger LOG = getLogger(OpenFlowDeviceProvider.class);
+ private static final long MBPS = 1_000 * 1_000;
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected DeviceProviderRegistry providerRegistry;
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected OpenFlowController controller;
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected ComponentConfigService cfgService;
+
+ private DeviceProviderService providerService;
+
+ private final InternalDeviceProvider listener = new InternalDeviceProvider();
+
+ // TODO: We need to make the poll interval configurable.
+ static final int POLL_INTERVAL = 5;
+ @Property(name = "PortStatsPollFrequency", intValue = POLL_INTERVAL,
+ label = "Frequency (in seconds) for polling switch Port statistics")
+ private int portStatsPollFrequency = POLL_INTERVAL;
+
+ private HashMap<Dpid, PortStatsCollector> collectors = Maps.newHashMap();
+
+ /**
+ * Creates an OpenFlow device provider.
+ */
+ public OpenFlowDeviceProvider() {
+ super(new ProviderId("of", "org.onosproject.provider.openflow"));
+ }
+
+ @Activate
+ public void activate(ComponentContext context) {
+ cfgService.registerProperties(getClass());
+ providerService = providerRegistry.register(this);
+ controller.addListener(listener);
+ controller.addEventListener(listener);
+ for (OpenFlowSwitch sw : controller.getSwitches()) {
+ try {
+ listener.switchAdded(new Dpid(sw.getId()));
+ } catch (Exception e) {
+ LOG.warn("Failed initially adding {} : {}", sw.getStringId(), e.getMessage());
+ LOG.debug("Error details:", e);
+ // disconnect to trigger switch-add later
+ sw.disconnectSwitch();
+ }
+ PortStatsCollector psc = new PortStatsCollector(sw, portStatsPollFrequency);
+ psc.start();
+ collectors.put(new Dpid(sw.getId()), psc);
+ }
+ LOG.info("Started");
+ }
+
+ @Deactivate
+ public void deactivate(ComponentContext context) {
+ cfgService.unregisterProperties(getClass(), false);
+ providerRegistry.unregister(this);
+ controller.removeListener(listener);
+ collectors.values().forEach(PortStatsCollector::stop);
+ providerService = null;
+ LOG.info("Stopped");
+ }
+
+ @Modified
+ public void modified(ComponentContext context) {
+ Dictionary<?, ?> properties = context.getProperties();
+ int newPortStatsPollFrequency;
+ try {
+ String s = get(properties, "PortStatsPollFrequency");
+ newPortStatsPollFrequency = isNullOrEmpty(s) ? portStatsPollFrequency : Integer.parseInt(s.trim());
+
+ } catch (NumberFormatException | ClassCastException e) {
+ newPortStatsPollFrequency = portStatsPollFrequency;
+ }
+
+ if (newPortStatsPollFrequency != portStatsPollFrequency) {
+ portStatsPollFrequency = newPortStatsPollFrequency;
+ collectors.values().forEach(psc -> psc.adjustPollInterval(portStatsPollFrequency));
+ }
+
+ LOG.info("Settings: portStatsPollFrequency={}", portStatsPollFrequency);
+ }
+
+ @Override
+ public boolean isReachable(DeviceId deviceId) {
+ OpenFlowSwitch sw = controller.getSwitch(dpid(deviceId.uri()));
+ if (sw == null || !sw.isConnected()) {
+ return false;
+ }
+ return true;
+ }
+
+ @Override
+ public void triggerProbe(DeviceId deviceId) {
+ LOG.debug("Triggering probe on device {}", deviceId);
+
+ final Dpid dpid = dpid(deviceId.uri());
+ OpenFlowSwitch sw = controller.getSwitch(dpid);
+ if (sw == null || !sw.isConnected()) {
+ LOG.error("Failed to probe device {} on sw={}", deviceId, sw);
+ providerService.deviceDisconnected(deviceId);
+ return;
+ } else {
+ LOG.trace("Confirmed device {} connection", deviceId);
+ }
+
+ // Prompt an update of port information. We can use any XID for this.
+ OFFactory fact = sw.factory();
+ switch (fact.getVersion()) {
+ case OF_10:
+ sw.sendMsg(fact.buildFeaturesRequest().setXid(0).build());
+ break;
+ case OF_13:
+ sw.sendMsg(fact.buildPortDescStatsRequest().setXid(0).build());
+ break;
+ default:
+ LOG.warn("Unhandled protocol version");
+ }
+ }
+
+ @Override
+ public void roleChanged(DeviceId deviceId, MastershipRole newRole) {
+ switch (newRole) {
+ case MASTER:
+ controller.setRole(dpid(deviceId.uri()), RoleState.MASTER);
+ break;
+ case STANDBY:
+ controller.setRole(dpid(deviceId.uri()), RoleState.EQUAL);
+ break;
+ case NONE:
+ controller.setRole(dpid(deviceId.uri()), RoleState.SLAVE);
+ break;
+ default:
+ LOG.error("Unknown Mastership state : {}", newRole);
+
+ }
+ LOG.debug("Accepting mastership role change for device {}", deviceId);
+ }
+
+ private void pushPortMetrics(Dpid dpid, List<OFPortStatsEntry> portStatsEntries) {
+ DeviceId deviceId = DeviceId.deviceId(dpid.uri(dpid));
+ Collection<PortStatistics> stats = buildPortStatistics(deviceId, portStatsEntries);
+ providerService.updatePortStatistics(deviceId, stats);
+ }
+
+ private Collection<PortStatistics> buildPortStatistics(DeviceId deviceId,
+ List<OFPortStatsEntry> entries) {
+ HashSet<PortStatistics> stats = Sets.newHashSet();
+
+ for (OFPortStatsEntry entry : entries) {
+ try {
+ if (entry == null || entry.getPortNo() == null || entry.getPortNo().getPortNumber() < 0) {
+ continue;
+ }
+ DefaultPortStatistics.Builder builder = DefaultPortStatistics.builder();
+ DefaultPortStatistics stat = builder.setDeviceId(deviceId)
+ .setPort(entry.getPortNo().getPortNumber())
+ .setPacketsReceived(entry.getRxPackets().getValue())
+ .setPacketsSent(entry.getTxPackets().getValue())
+ .setBytesReceived(entry.getRxBytes().getValue())
+ .setBytesSent(entry.getTxBytes().getValue())
+ .setPacketsRxDropped(entry.getRxDropped().getValue())
+ .setPacketsTxDropped(entry.getTxDropped().getValue())
+ .setPacketsRxErrors(entry.getRxErrors().getValue())
+ .setPacketsTxErrors(entry.getTxErrors().getValue())
+ .setDurationSec(entry.getVersion() == OFVersion.OF_10 ? 0 : entry.getDurationSec())
+ .setDurationNano(entry.getVersion() == OFVersion.OF_10 ? 0 : entry.getDurationNsec())
+ .build();
+
+ stats.add(stat);
+ } catch (Exception e) {
+ LOG.warn("Unable to process port stats", e);
+ }
+ }
+
+ return Collections.unmodifiableSet(stats);
+
+ }
+
+ private class InternalDeviceProvider implements OpenFlowSwitchListener, OpenFlowEventListener {
+
+ private HashMap<Dpid, List<OFPortStatsEntry>> portStatsReplies = new HashMap<>();
+
+ @Override
+ public void switchAdded(Dpid dpid) {
+ if (providerService == null) {
+ return;
+ }
+ DeviceId did = deviceId(uri(dpid));
+ OpenFlowSwitch sw = controller.getSwitch(dpid);
+
+ ChassisId cId = new ChassisId(dpid.value());
+
+ SparseAnnotations annotations = DefaultAnnotations.builder()
+ .set("protocol", sw.factory().getVersion().toString())
+ .set("channelId", sw.channelId())
+ .build();
+
+ DeviceDescription description =
+ new DefaultDeviceDescription(did.uri(), sw.deviceType(),
+ sw.manufacturerDescription(),
+ sw.hardwareDescription(),
+ sw.softwareDescription(),
+ sw.serialNumber(),
+ cId, annotations);
+ providerService.deviceConnected(did, description);
+ providerService.updatePorts(did, buildPortDescriptions(sw));
+
+ PortStatsCollector psc =
+ new PortStatsCollector(controller.getSwitch(dpid), portStatsPollFrequency);
+ psc.start();
+ collectors.put(dpid, psc);
+ }
+
+ @Override
+ public void switchRemoved(Dpid dpid) {
+ if (providerService == null) {
+ return;
+ }
+ providerService.deviceDisconnected(deviceId(uri(dpid)));
+
+ PortStatsCollector collector = collectors.remove(dpid);
+ if (collector != null) {
+ collector.stop();
+ }
+ }
+
+ @Override
+ public void switchChanged(Dpid dpid) {
+ if (providerService == null) {
+ return;
+ }
+ DeviceId did = deviceId(uri(dpid));
+ OpenFlowSwitch sw = controller.getSwitch(dpid);
+ providerService.updatePorts(did, buildPortDescriptions(sw));
+ }
+
+ @Override
+ public void portChanged(Dpid dpid, OFPortStatus status) {
+ PortDescription portDescription = buildPortDescription(status);
+ providerService.portStatusChanged(deviceId(uri(dpid)), portDescription);
+ }
+
+ @Override
+ public void receivedRoleReply(Dpid dpid, RoleState requested, RoleState response) {
+ MastershipRole request = roleOf(requested);
+ MastershipRole reply = roleOf(response);
+
+ providerService.receivedRoleReply(deviceId(uri(dpid)), request, reply);
+ }
+
+ /**
+ * Translates a RoleState to the corresponding MastershipRole.
+ *
+ * @param response role state
+ * @return a MastershipRole
+ */
+ private MastershipRole roleOf(RoleState response) {
+ switch (response) {
+ case MASTER:
+ return MastershipRole.MASTER;
+ case EQUAL:
+ return MastershipRole.STANDBY;
+ case SLAVE:
+ return MastershipRole.NONE;
+ default:
+ LOG.warn("unknown role {}", response);
+ return null;
+ }
+ }
+
+ /**
+ * Builds a list of port descriptions for a given list of ports.
+ *
+ * @return list of portdescriptions
+ */
+ private List<PortDescription> buildPortDescriptions(OpenFlowSwitch sw) {
+ final List<PortDescription> portDescs = new ArrayList<>(sw.getPorts().size());
+ sw.getPorts().forEach(port -> portDescs.add(buildPortDescription(port)));
+
+ OpenFlowOpticalSwitch opsw;
+ switch (sw.deviceType()) {
+ case ROADM:
+ opsw = (OpenFlowOpticalSwitch) sw;
+ opsw.getPortTypes().forEach(type -> {
+ opsw.getPortsOf(type).forEach(
+ op -> {
+ portDescs.add(buildPortDescription(type, (OFPortOptical) op));
+ }
+ );
+ });
+ break;
+ case FIBER_SWITCH:
+ opsw = (OpenFlowOpticalSwitch) sw;
+ opsw.getPortTypes().forEach(type -> {
+ opsw.getPortsOf(type).forEach(
+ op -> {
+ portDescs.add(buildPortDescription((OFCalientPortDescStatsEntry) op));
+ }
+ );
+ });
+ break;
+ default:
+ break;
+ }
+
+ return portDescs;
+ }
+
+ /**
+ * Creates an annotation for the port name if one is available.
+ *
+ * @param port description of the port
+ * @return annotation containing the port name if one is found,
+ * null otherwise
+ */
+ private SparseAnnotations makePortNameAnnotation(String port) {
+ SparseAnnotations annotations = null;
+ String portName = Strings.emptyToNull(port);
+ if (portName != null) {
+ annotations = DefaultAnnotations.builder()
+ .set(AnnotationKeys.PORT_NAME, portName).build();
+ }
+ return annotations;
+ }
+
+ /**
+ * Build a portDescription from a given Ethernet port description.
+ *
+ * @param port the port to build from.
+ * @return portDescription for the port.
+ */
+ private PortDescription buildPortDescription(OFPortDesc port) {
+ PortNumber portNo = PortNumber.portNumber(port.getPortNo().getPortNumber());
+ boolean enabled =
+ !port.getState().contains(OFPortState.LINK_DOWN) &&
+ !port.getConfig().contains(OFPortConfig.PORT_DOWN);
+ Port.Type type = port.getCurr().contains(OFPortFeatures.PF_FIBER) ? FIBER : COPPER;
+ SparseAnnotations annotations = makePortNameAnnotation(port.getName());
+ return new DefaultPortDescription(portNo, enabled, type,
+ portSpeed(port), annotations);
+ }
+
+ /**
+ * Build a portDescription from a given a port description describing some
+ * Optical port.
+ *
+ * @param port description property type.
+ * @param port the port to build from.
+ * @return portDescription for the port.
+ */
+ private PortDescription buildPortDescription(PortDescPropertyType ptype, OFPortOptical port) {
+ checkArgument(port.getDesc().size() >= 1);
+
+ // Minimally functional fixture. This needs to be fixed as we add better support.
+ PortNumber portNo = PortNumber.portNumber(port.getPortNo().getPortNumber());
+
+ boolean enabled = !port.getState().contains(OFPortState.LINK_DOWN)
+ && !port.getConfig().contains(OFPortConfig.PORT_DOWN);
+ SparseAnnotations annotations = makePortNameAnnotation(port.getName());
+
+ if (port.getVersion() == OFVersion.OF_13
+ && ptype == PortDescPropertyType.OPTICAL_TRANSPORT) {
+ // At this point, not much is carried in the optical port message.
+ LOG.debug("Optical transport port message {}", port.toString());
+ } else {
+ // removable once 1.4+ support complete.
+ LOG.debug("Unsupported optical port properties");
+ }
+
+ OFPortDescPropOpticalTransport desc = port.getDesc().get(0);
+ switch (desc.getPortSignalType()) {
+ // FIXME: use constants once loxi has full optical extensions
+ case 2: // OMS port
+ // Assume complete optical spectrum and 50 GHz grid
+ // LINC-OE is only supported optical OF device for now
+ return new OmsPortDescription(portNo, enabled,
+ Spectrum.U_BAND_MIN, Spectrum.O_BAND_MAX, Frequency.ofGHz(50), annotations);
+ case 5: // OCH port
+ OchSignal signal = new OchSignal(GridType.DWDM, ChannelSpacing.CHL_50GHZ, 0, 4);
+ return new OchPortDescription(portNo, enabled, OduSignalType.ODU4,
+ true, signal, annotations);
+ default:
+ break;
+ }
+
+ return new DefaultPortDescription(portNo, enabled, FIBER, 0, annotations);
+ }
+
+ /**
+ * Build a portDescription from a given port description describing a fiber switch optical port.
+ *
+ * @param port description property type.
+ * @param port the port to build from.
+ * @return portDescription for the port.
+ */
+ private PortDescription buildPortDescription(OFCalientPortDescStatsEntry port) {
+ PortNumber portNo = PortNumber.portNumber(port.getPortNo().getPortNumber());
+
+ // FIXME when Calient OF agent reports port status
+ boolean enabled = true;
+ SparseAnnotations annotations = makePortNameAnnotation(port.getName());
+
+ // S160 data sheet
+ // Wavelength range: 1260 - 1630 nm, grid is irrelevant for this type of switch
+ return new OmsPortDescription(portNo, enabled,
+ Spectrum.U_BAND_MIN, Spectrum.O_BAND_MAX, Frequency.ofGHz(100), annotations);
+ }
+
+ private PortDescription buildPortDescription(OFPortStatus status) {
+ OFPortDesc port = status.getDesc();
+ if (status.getReason() != OFPortReason.DELETE) {
+ return buildPortDescription(port);
+ } else {
+ PortNumber portNo = PortNumber.portNumber(port.getPortNo().getPortNumber());
+ Port.Type type = port.getCurr().contains(OFPortFeatures.PF_FIBER) ? FIBER : COPPER;
+ SparseAnnotations annotations = makePortNameAnnotation(port.getName());
+ return new DefaultPortDescription(portNo, false, type,
+ portSpeed(port), annotations);
+ }
+ }
+
+ private long portSpeed(OFPortDesc port) {
+ if (port.getVersion() == OFVersion.OF_13) {
+ return port.getCurrSpeed() / MBPS;
+ }
+
+ PortSpeed portSpeed = PortSpeed.SPEED_NONE;
+ for (OFPortFeatures feat : port.getCurr()) {
+ portSpeed = PortSpeed.max(portSpeed, feat.getPortSpeed());
+ }
+ return portSpeed.getSpeedBps() / MBPS;
+ }
+
+ @Override
+ public void handleMessage(Dpid dpid, OFMessage msg) {
+ switch (msg.getType()) {
+ case STATS_REPLY:
+ if (((OFStatsReply) msg).getStatsType() == OFStatsType.PORT) {
+ OFPortStatsReply portStatsReply = (OFPortStatsReply) msg;
+ List<OFPortStatsEntry> portStatsReplyList = portStatsReplies.get(dpid);
+ if (portStatsReplyList == null) {
+ portStatsReplyList = Lists.newArrayList();
+ }
+ portStatsReplyList.addAll(portStatsReply.getEntries());
+ portStatsReplies.put(dpid, portStatsReplyList);
+ if (!portStatsReply.getFlags().contains(OFStatsReplyFlags.REPLY_MORE)) {
+ pushPortMetrics(dpid, portStatsReplies.get(dpid));
+ portStatsReplies.get(dpid).clear();
+ }
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ }
+
+}
diff --git a/framework/src/onos/providers/openflow/device/src/main/java/org/onosproject/provider/of/device/impl/PortStatsCollector.java b/framework/src/onos/providers/openflow/device/src/main/java/org/onosproject/provider/of/device/impl/PortStatsCollector.java
new file mode 100644
index 00000000..8383fa3f
--- /dev/null
+++ b/framework/src/onos/providers/openflow/device/src/main/java/org/onosproject/provider/of/device/impl/PortStatsCollector.java
@@ -0,0 +1,113 @@
+/*
+ * 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.device.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.OFPortStatsRequest;
+import org.projectfloodlight.openflow.types.OFPort;
+import org.slf4j.Logger;
+
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicLong;
+
+import static org.slf4j.LoggerFactory.getLogger;
+
+/*
+ * Sends Group Stats Request and collect the group statistics with a time interval.
+ */
+public class PortStatsCollector implements TimerTask {
+
+ // TODO: Refactoring is required using ScheduledExecutorService
+
+ private final HashedWheelTimer timer = Timer.getTimer();
+ private final OpenFlowSwitch sw;
+ private final Logger log = getLogger(getClass());
+ private int refreshInterval;
+ private final AtomicLong xidAtomic = new AtomicLong(1);
+
+ private Timeout timeout;
+ private volatile boolean stopped;
+
+ /**
+ * Creates a GroupStatsCollector object.
+ *
+ * @param sw Open Flow switch
+ * @param interval time interval for collecting group statistic
+ */
+ public PortStatsCollector(OpenFlowSwitch sw, int interval) {
+ this.sw = sw;
+ this.refreshInterval = interval;
+ }
+
+ @Override
+ public void run(Timeout to) throws Exception {
+ if (stopped || timeout.isCancelled()) {
+ return;
+ }
+ log.trace("Collecting stats for {}", sw.getStringId());
+
+ sendPortStatistic();
+
+ if (!stopped && !timeout.isCancelled()) {
+ log.trace("Scheduling stats collection in {} seconds for {}",
+ this.refreshInterval, this.sw.getStringId());
+ timeout.getTimer().newTimeout(this, refreshInterval, TimeUnit.SECONDS);
+ }
+ }
+
+ synchronized void adjustPollInterval(int pollInterval) {
+ this.refreshInterval = pollInterval;
+ // task.cancel();
+ // task = new InternalTimerTask();
+ // timer.scheduleAtFixedRate(task, pollInterval * SECONDS, pollInterval * 1000);
+ }
+
+ private void sendPortStatistic() {
+ if (sw.getRole() != RoleState.MASTER) {
+ return;
+ }
+ Long statsXid = xidAtomic.getAndIncrement();
+ OFPortStatsRequest statsRequest = sw.factory().buildPortStatsRequest()
+ .setPortNo(OFPort.ANY)
+ .setXid(statsXid)
+ .build();
+ sw.sendMsg(statsRequest);
+ }
+
+ /**
+ * Starts the collector.
+ */
+ public synchronized void start() {
+ log.info("Starting Port Stats collection thread for {}", sw.getStringId());
+ stopped = false;
+ timeout = timer.newTimeout(this, 1, TimeUnit.SECONDS);
+ }
+
+ /**
+ * Stops the collector.
+ */
+ public synchronized void stop() {
+ log.info("Stopping Port Stats collection thread for {}", sw.getStringId());
+ stopped = true;
+ timeout.cancel();
+ }
+}
diff --git a/framework/src/onos/providers/openflow/device/src/main/java/org/onosproject/provider/of/device/impl/package-info.java b/framework/src/onos/providers/openflow/device/src/main/java/org/onosproject/provider/of/device/impl/package-info.java
new file mode 100644
index 00000000..9376b47d
--- /dev/null
+++ b/framework/src/onos/providers/openflow/device/src/main/java/org/onosproject/provider/of/device/impl/package-info.java
@@ -0,0 +1,20 @@
+/*
+ * Copyright 2014 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 infrastructure device discovery.
+ */
+package org.onosproject.provider.of.device.impl;
diff --git a/framework/src/onos/providers/openflow/device/src/test/java/org/onosproject/provider/of/device/impl/OpenFlowDeviceProviderTest.java b/framework/src/onos/providers/openflow/device/src/test/java/org/onosproject/provider/of/device/impl/OpenFlowDeviceProviderTest.java
new file mode 100644
index 00000000..7b4d7922
--- /dev/null
+++ b/framework/src/onos/providers/openflow/device/src/test/java/org/onosproject/provider/of/device/impl/OpenFlowDeviceProviderTest.java
@@ -0,0 +1,402 @@
+/*
+ * Copyright 2014-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.device.impl;
+
+import com.google.common.collect.HashMultimap;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Multimap;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.onosproject.cfg.ComponentConfigAdapter;
+import org.onosproject.net.DefaultDevice;
+import org.onosproject.net.Device;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.MastershipRole;
+import org.onosproject.net.device.DeviceDescription;
+import org.onosproject.net.device.DeviceProvider;
+import org.onosproject.net.device.DeviceProviderRegistry;
+import org.onosproject.net.device.DeviceProviderService;
+import org.onosproject.net.device.PortDescription;
+import org.onosproject.net.device.PortStatistics;
+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.PacketListener;
+import org.onosproject.openflow.controller.RoleState;
+import org.projectfloodlight.openflow.protocol.OFFactory;
+import org.projectfloodlight.openflow.protocol.OFMessage;
+import org.projectfloodlight.openflow.protocol.OFPortDesc;
+import org.projectfloodlight.openflow.protocol.OFPortReason;
+import org.projectfloodlight.openflow.protocol.OFPortStatus;
+import org.projectfloodlight.openflow.protocol.ver10.OFFactoryVer10;
+import org.projectfloodlight.openflow.types.OFPort;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import static org.junit.Assert.*;
+import static org.onosproject.net.Device.Type.SWITCH;
+import static org.onosproject.net.MastershipRole.*;
+
+public class OpenFlowDeviceProviderTest {
+
+ private static final ProviderId PID = new ProviderId("of", "test");
+ private static final DeviceId DID1 = DeviceId.deviceId("of:0000000000000001");
+ private static final Dpid DPID1 = Dpid.dpid(DID1.uri());
+
+ private static final OFPortDesc PD1 = portDesc(1);
+ private static final OFPortDesc PD2 = portDesc(2);
+ private static final OFPortDesc PD3 = portDesc(3);
+
+ private static final List<OFPortDesc> PLIST = Lists.newArrayList(PD1, PD2);
+
+ private static final Device DEV1 =
+ new DefaultDevice(PID, DID1, SWITCH, "", "", "", "", null);
+
+ private static final TestOpenFlowSwitch SW1 = new TestOpenFlowSwitch();
+
+ private final OpenFlowDeviceProvider provider = new OpenFlowDeviceProvider();
+ private final TestDeviceRegistry registry = new TestDeviceRegistry();
+ private final TestController controller = new TestController();
+
+ @Before
+ public void startUp() {
+ provider.providerRegistry = registry;
+ provider.controller = controller;
+ provider.cfgService = new ComponentConfigAdapter();
+ controller.switchMap.put(DPID1, SW1);
+ provider.activate(null);
+ assertNotNull("provider should be registered", registry.provider);
+ assertNotNull("listener should be registered", controller.listener);
+ assertEquals("devices not added", 1, registry.connected.size());
+ assertEquals("ports not added", 2, registry.ports.get(DID1).size());
+ }
+
+ @After
+ public void tearDown() {
+ provider.deactivate(null);
+ assertNull("listener should be removed", controller.listener);
+ provider.controller = null;
+ provider.providerRegistry = null;
+ }
+
+ @Test
+ public void roleChanged() {
+ provider.roleChanged(DID1, MASTER);
+ assertEquals("Should be MASTER", RoleState.MASTER, controller.roleMap.get(DPID1));
+ provider.roleChanged(DID1, STANDBY);
+ assertEquals("Should be EQUAL", RoleState.EQUAL, controller.roleMap.get(DPID1));
+ provider.roleChanged(DID1, NONE);
+ assertEquals("Should be SLAVE", RoleState.SLAVE, controller.roleMap.get(DPID1));
+ }
+
+ @Test
+ public void triggerProbe() {
+
+ }
+
+ @Test
+ public void switchRemoved() {
+ controller.listener.switchRemoved(DPID1);
+ assertTrue("device not removed", registry.connected.isEmpty());
+ }
+
+ @Test
+ public void portChanged() {
+ OFPortStatus stat = SW1.factory().buildPortStatus()
+ .setReason(OFPortReason.ADD)
+ .setDesc(PD3)
+ .build();
+ controller.listener.portChanged(DPID1, stat);
+ assertNotNull("never went throught the provider service", registry.descr);
+ assertEquals("port status unhandled", 3, registry.ports.get(DID1).size());
+ }
+
+ @Test
+ public void receivedRoleReply() {
+ // check translation capabilities
+ controller.listener.receivedRoleReply(DPID1, RoleState.MASTER, RoleState.MASTER);
+ assertEquals("wrong role reported", DPID1, registry.roles.get(MASTER));
+ controller.listener.receivedRoleReply(DPID1, RoleState.EQUAL, RoleState.MASTER);
+ assertEquals("wrong role reported", DPID1, registry.roles.get(STANDBY));
+ controller.listener.receivedRoleReply(DPID1, RoleState.SLAVE, RoleState.MASTER);
+ assertEquals("wrong role reported", DPID1, registry.roles.get(NONE));
+ }
+
+ private static OFPortDesc portDesc(int port) {
+ OFPortDesc.Builder builder = OFFactoryVer10.INSTANCE.buildPortDesc();
+ builder.setPortNo(OFPort.of(port));
+
+ return builder.build();
+ }
+
+ private class TestDeviceRegistry implements DeviceProviderRegistry {
+ DeviceProvider provider;
+
+ Set<DeviceId> connected = new HashSet<>();
+ Multimap<DeviceId, PortDescription> ports = HashMultimap.create();
+ PortDescription descr = null;
+ Map<MastershipRole, Dpid> roles = new HashMap<>();
+
+ @Override
+ public DeviceProviderService register(DeviceProvider provider) {
+ this.provider = provider;
+ return new TestProviderService();
+ }
+
+ @Override
+ public void unregister(DeviceProvider provider) {
+ }
+
+ @Override
+ public Set<ProviderId> getProviders() {
+ return null;
+ }
+
+ private class TestProviderService implements DeviceProviderService {
+
+ @Override
+ public DeviceProvider provider() {
+ return null;
+ }
+
+ @Override
+ public void deviceConnected(DeviceId deviceId,
+ DeviceDescription deviceDescription) {
+ connected.add(deviceId);
+ }
+
+ @Override
+ public void deviceDisconnected(DeviceId deviceId) {
+ connected.remove(deviceId);
+ ports.removeAll(deviceId);
+ }
+
+ @Override
+ public void updatePorts(DeviceId deviceId,
+ List<PortDescription> portDescriptions) {
+ for (PortDescription p : portDescriptions) {
+ ports.put(deviceId, p);
+ }
+ }
+
+ @Override
+ public void portStatusChanged(DeviceId deviceId,
+ PortDescription portDescription) {
+ ports.put(deviceId, portDescription);
+ descr = portDescription;
+ }
+
+ @Override
+ public void receivedRoleReply(DeviceId deviceId,
+ MastershipRole requested, MastershipRole response) {
+ roles.put(requested, Dpid.dpid(deviceId.uri()));
+ }
+
+ @Override
+ public void updatePortStatistics(DeviceId deviceId, Collection<PortStatistics> portStatistics) {
+
+ }
+
+ }
+ }
+
+ private class TestController implements OpenFlowController {
+ OpenFlowSwitchListener listener = null;
+ Map<Dpid, RoleState> roleMap = new HashMap<Dpid, RoleState>();
+ Map<Dpid, OpenFlowSwitch> switchMap = new HashMap<Dpid, OpenFlowSwitch>();
+
+ @Override
+ public Iterable<OpenFlowSwitch> getSwitches() {
+ return switchMap.values();
+ }
+
+ @Override
+ public Iterable<OpenFlowSwitch> getMasterSwitches() {
+ return null;
+ }
+
+ @Override
+ public Iterable<OpenFlowSwitch> getEqualSwitches() {
+ return null;
+ }
+
+ @Override
+ public OpenFlowSwitch getSwitch(Dpid dpid) {
+ return switchMap.get(dpid);
+ }
+
+ @Override
+ public OpenFlowSwitch getMasterSwitch(Dpid dpid) {
+ return null;
+ }
+
+ @Override
+ public OpenFlowSwitch getEqualSwitch(Dpid dpid) {
+
+ return null;
+ }
+
+ @Override
+ public void addListener(OpenFlowSwitchListener listener) {
+ this.listener = listener;
+ }
+
+ @Override
+ public void removeListener(OpenFlowSwitchListener listener) {
+ this.listener = null;
+ }
+
+ @Override
+ public void addPacketListener(int priority, PacketListener listener) {
+ }
+
+ @Override
+ public void removePacketListener(PacketListener listener) {
+ }
+
+ @Override
+ public void addEventListener(OpenFlowEventListener listener) {
+ }
+
+ @Override
+ public void removeEventListener(OpenFlowEventListener listener) {
+ }
+
+ @Override
+ public void write(Dpid dpid, OFMessage msg) {
+ }
+
+ @Override
+ public void processPacket(Dpid dpid, OFMessage msg) {
+ }
+
+ @Override
+ public void setRole(Dpid dpid, RoleState role) {
+ roleMap.put(dpid, role);
+ }
+ }
+
+ private static class TestOpenFlowSwitch implements OpenFlowSwitch {
+
+ RoleState state;
+ List<OFMessage> sent = new ArrayList<OFMessage>();
+ OFFactory factory = OFFactoryVer10.INSTANCE;
+
+ @Override
+ public void sendMsg(OFMessage msg) {
+ sent.add(msg);
+ }
+
+ @Override
+ public void sendMsg(List<OFMessage> msgs) {
+ }
+
+ @Override
+ public void handleMessage(OFMessage fromSwitch) {
+ }
+
+ @Override
+ public void setRole(RoleState role) {
+ state = role;
+ }
+
+ @Override
+ public RoleState getRole() {
+ return state;
+ }
+
+ @Override
+ public List<OFPortDesc> getPorts() {
+ return PLIST;
+ }
+
+ @Override
+ public OFFactory factory() {
+ return factory;
+ }
+
+ @Override
+ public String getStringId() {
+ return null;
+ }
+
+ @Override
+ public long getId() {
+ return DPID1.value();
+ }
+
+ @Override
+ public String manufacturerDescription() {
+ return null;
+ }
+
+ @Override
+ public String datapathDescription() {
+ return null;
+ }
+
+ @Override
+ public String hardwareDescription() {
+ return null;
+ }
+
+ @Override
+ public String softwareDescription() {
+ return null;
+ }
+
+ @Override
+ public String serialNumber() {
+ return null;
+ }
+
+ @Override
+ public boolean isConnected() {
+ return true;
+ }
+
+ @Override
+ public void disconnectSwitch() {
+ }
+
+ @Override
+ public Device.Type deviceType() {
+ return Device.Type.SWITCH;
+ }
+
+ @Override
+ public void returnRoleReply(RoleState requested, RoleState response) {
+ }
+
+ @Override
+ public String channelId() {
+ return "1.2.3.4:1";
+ }
+
+ }
+
+}
diff --git a/framework/src/onos/providers/openflow/flow/pom.xml b/framework/src/onos/providers/openflow/flow/pom.xml
new file mode 100644
index 00000000..24c430e3
--- /dev/null
+++ b/framework/src/onos/providers/openflow/flow/pom.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright 2014 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.
+ -->
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+
+ <parent>
+ <groupId>org.onosproject</groupId>
+ <artifactId>onos-of-providers</artifactId>
+ <version>1.3.0-SNAPSHOT</version>
+ <relativePath>../pom.xml</relativePath>
+ </parent>
+
+ <artifactId>onos-of-provider-flow</artifactId>
+ <packaging>bundle</packaging>
+
+ <description>ONOS OpenFlow protocol flow provider</description>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.osgi</groupId>
+ <artifactId>org.osgi.compendium</artifactId>
+ </dependency>
+ </dependencies>
+</project>
diff --git a/framework/src/onos/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/FlowEntryBuilder.java b/framework/src/onos/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/FlowEntryBuilder.java
new file mode 100644
index 00000000..f238bdb1
--- /dev/null
+++ b/framework/src/onos/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/FlowEntryBuilder.java
@@ -0,0 +1,707 @@
+/*
+ * Copyright 2014-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.flow.impl;
+
+import static org.onosproject.net.flow.criteria.Criteria.matchLambda;
+import static org.onosproject.net.flow.criteria.Criteria.matchOchSignalType;
+import static org.onosproject.provider.of.flow.impl.OpenFlowValueMapper.lookupChannelSpacing;
+import static org.onosproject.provider.of.flow.impl.OpenFlowValueMapper.lookupGridType;
+import static org.onosproject.provider.of.flow.impl.OpenFlowValueMapper.lookupOchSignalType;
+import static org.slf4j.LoggerFactory.getLogger;
+
+import java.util.List;
+
+import org.onlab.packet.Ip4Address;
+import org.onlab.packet.Ip4Prefix;
+import org.onlab.packet.Ip6Address;
+import org.onlab.packet.Ip6Prefix;
+import org.onlab.packet.MacAddress;
+import org.onlab.packet.MplsLabel;
+import org.onlab.packet.TpPort;
+import org.onlab.packet.VlanId;
+import org.onosproject.core.DefaultGroupId;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.Lambda;
+import org.onosproject.net.PortNumber;
+import org.onosproject.net.flow.DefaultFlowEntry;
+import org.onosproject.net.flow.DefaultFlowRule;
+import org.onosproject.net.flow.DefaultTrafficSelector;
+import org.onosproject.net.flow.DefaultTrafficTreatment;
+import org.onosproject.net.flow.FlowEntry;
+import org.onosproject.net.flow.FlowEntry.FlowEntryState;
+import org.onosproject.net.flow.FlowRule;
+import org.onosproject.net.flow.TrafficSelector;
+import org.onosproject.net.flow.TrafficTreatment;
+import org.onosproject.net.flow.instructions.Instructions;
+import org.onosproject.openflow.controller.Dpid;
+import org.projectfloodlight.openflow.protocol.OFFlowMod;
+import org.projectfloodlight.openflow.protocol.OFFlowRemoved;
+import org.projectfloodlight.openflow.protocol.OFFlowStatsEntry;
+import org.projectfloodlight.openflow.protocol.action.OFAction;
+import org.projectfloodlight.openflow.protocol.action.OFActionCircuit;
+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.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.instruction.OFInstruction;
+import org.projectfloodlight.openflow.protocol.instruction.OFInstructionApplyActions;
+import org.projectfloodlight.openflow.protocol.instruction.OFInstructionGotoTable;
+import org.projectfloodlight.openflow.protocol.instruction.OFInstructionWriteActions;
+import org.projectfloodlight.openflow.protocol.instruction.OFInstructionWriteMetadata;
+import org.projectfloodlight.openflow.protocol.match.Match;
+import org.projectfloodlight.openflow.protocol.match.MatchField;
+import org.projectfloodlight.openflow.protocol.oxm.OFOxm;
+import org.projectfloodlight.openflow.protocol.oxm.OFOxmOchSigidBasic;
+import org.projectfloodlight.openflow.protocol.ver13.OFFactoryVer13;
+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.Masked;
+import org.projectfloodlight.openflow.types.OFVlanVidMatch;
+import org.projectfloodlight.openflow.types.TransportPort;
+import org.projectfloodlight.openflow.types.U32;
+import org.projectfloodlight.openflow.types.U64;
+import org.projectfloodlight.openflow.types.U8;
+import org.projectfloodlight.openflow.types.VlanPcp;
+import org.slf4j.Logger;
+
+import com.google.common.collect.Lists;
+
+public class FlowEntryBuilder {
+ private final Logger log = getLogger(getClass());
+
+ private final OFFlowStatsEntry stat;
+ private final OFFlowRemoved removed;
+ private final OFFlowMod flowMod;
+
+ private final Match match;
+
+ // All actions are contained in an OFInstruction. For OF1.0
+ // the instruction type is apply instruction (immediate set in ONOS speak)
+ private final List<OFInstruction> instructions;
+
+ private final Dpid dpid;
+
+ public enum FlowType { STAT, REMOVED, MOD }
+
+ private final FlowType type;
+
+ public FlowEntryBuilder(Dpid dpid, OFFlowStatsEntry entry) {
+ this.stat = entry;
+ this.match = entry.getMatch();
+ this.instructions = getInstructions(entry);
+ this.dpid = dpid;
+ this.removed = null;
+ this.flowMod = null;
+ this.type = FlowType.STAT;
+ }
+
+ public FlowEntryBuilder(Dpid dpid, OFFlowRemoved removed) {
+ this.match = removed.getMatch();
+ this.removed = removed;
+
+ this.dpid = dpid;
+ this.instructions = null;
+ this.stat = null;
+ this.flowMod = null;
+ this.type = FlowType.REMOVED;
+
+ }
+
+ public FlowEntryBuilder(Dpid dpid, OFFlowMod fm) {
+ this.match = fm.getMatch();
+ this.dpid = dpid;
+ this.instructions = getInstructions(fm);
+ this.type = FlowType.MOD;
+ this.flowMod = fm;
+ this.stat = null;
+ this.removed = null;
+ }
+
+ public FlowEntry build(FlowEntryState... state) {
+ FlowRule rule;
+ switch (this.type) {
+ case STAT:
+ rule = DefaultFlowRule.builder()
+ .forDevice(DeviceId.deviceId(Dpid.uri(dpid)))
+ .withSelector(buildSelector())
+ .withTreatment(buildTreatment())
+ .withPriority(stat.getPriority())
+ .makeTemporary(stat.getIdleTimeout())
+ .withCookie(stat.getCookie().getValue())
+ .forTable(stat.getTableId().getValue())
+ .build();
+
+ return new DefaultFlowEntry(rule, FlowEntryState.ADDED,
+ stat.getDurationSec(), stat.getPacketCount().getValue(),
+ stat.getByteCount().getValue());
+ case REMOVED:
+ rule = DefaultFlowRule.builder()
+ .forDevice(DeviceId.deviceId(Dpid.uri(dpid)))
+ .withSelector(buildSelector())
+ .withPriority(removed.getPriority())
+ .makeTemporary(removed.getIdleTimeout())
+ .withCookie(removed.getCookie().getValue())
+ .forTable(removed.getTableId().getValue())
+ .build();
+
+ return new DefaultFlowEntry(rule, FlowEntryState.REMOVED, removed.getDurationSec(),
+ removed.getPacketCount().getValue(), removed.getByteCount().getValue());
+ case MOD:
+ FlowEntryState flowState = state.length > 0 ? state[0] : FlowEntryState.FAILED;
+ rule = DefaultFlowRule.builder()
+ .forDevice(DeviceId.deviceId(Dpid.uri(dpid)))
+ .withSelector(buildSelector())
+ .withTreatment(buildTreatment())
+ .withPriority(flowMod.getPriority())
+ .makeTemporary(flowMod.getIdleTimeout())
+ .withCookie(flowMod.getCookie().getValue())
+ .forTable(flowMod.getTableId().getValue())
+ .build();
+
+ return new DefaultFlowEntry(rule, flowState, 0, 0, 0);
+ default:
+ log.error("Unknown flow type : {}", this.type);
+ return null;
+ }
+
+ }
+
+ private List<OFInstruction> getInstructions(OFFlowMod entry) {
+ switch (entry.getVersion()) {
+ case OF_10:
+ return Lists.newArrayList(OFFactoryVer13.INSTANCE.instructions()
+ .applyActions(
+ entry.getActions()));
+ case OF_11:
+ case OF_12:
+ case OF_13:
+ return entry.getInstructions();
+ default:
+ log.warn("Unknown OF version {}", entry.getVersion());
+ }
+ return Lists.newLinkedList();
+ }
+
+ private List<OFInstruction> getInstructions(OFFlowStatsEntry entry) {
+ switch (entry.getVersion()) {
+ case OF_10:
+ return Lists.newArrayList(
+ OFFactoryVer13.INSTANCE.instructions().applyActions(entry.getActions()));
+ case OF_11:
+ case OF_12:
+ case OF_13:
+ return entry.getInstructions();
+ default:
+ log.warn("Unknown OF version {}", entry.getVersion());
+ }
+ return Lists.newLinkedList();
+ }
+
+ private TrafficTreatment buildTreatment() {
+ TrafficTreatment.Builder builder = DefaultTrafficTreatment.builder();
+ // If this is a drop rule
+ if (instructions.size() == 0) {
+ builder.drop();
+ return builder.build();
+ }
+ for (OFInstruction in : instructions) {
+ switch (in.getType()) {
+ case GOTO_TABLE:
+ builder.transition(((int) ((OFInstructionGotoTable) in)
+ .getTableId().getValue()));
+ break;
+ case WRITE_METADATA:
+ OFInstructionWriteMetadata m = (OFInstructionWriteMetadata) in;
+ builder.writeMetadata(m.getMetadata().getValue(),
+ m.getMetadataMask().getValue());
+ break;
+ case WRITE_ACTIONS:
+ builder.deferred();
+ buildActions(((OFInstructionWriteActions) in).getActions(),
+ builder);
+ break;
+ case APPLY_ACTIONS:
+ builder.immediate();
+ buildActions(((OFInstructionApplyActions) in).getActions(),
+ builder);
+ break;
+ case CLEAR_ACTIONS:
+ builder.wipeDeferred();
+ break;
+ case EXPERIMENTER:
+ break;
+ case METER:
+ break;
+ default:
+ log.warn("Unknown instructions type {}", in.getType());
+ }
+ }
+
+ return builder.build();
+ }
+
+ private TrafficTreatment.Builder buildActions(List<OFAction> actions,
+ TrafficTreatment.Builder builder) {
+ 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 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:
+ builder.pushMpls();
+ break;
+ case COPY_TTL_IN:
+ builder.copyTtlIn();
+ break;
+ case COPY_TTL_OUT:
+ builder.copyTtlOut();
+ break;
+ case DEC_MPLS_TTL:
+ builder.decMplsTtl();
+ break;
+ case DEC_NW_TTL:
+ builder.decNwTtl();
+ break;
+ case GROUP:
+ OFActionGroup group = (OFActionGroup) act;
+ builder.group(new DefaultGroupId(group.getGroup().getGroupNumber()));
+ break;
+ case STRIP_VLAN:
+ case POP_VLAN:
+ builder.popVlan();
+ break;
+ case PUSH_VLAN:
+ builder.pushVlan();
+ 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 ENQUEUE:
+ default:
+ log.warn("Action type {} not yet implemented.", act.getType());
+ }
+ }
+ return builder;
+ }
+
+
+ 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 TUNNEL_ID:
+ @SuppressWarnings("unchecked")
+ OFOxm<U64> tunnelId = (OFOxm<U64>) oxm;
+ builder.setTunnelId(tunnelId.getValue().getValue());
+ break;
+ case TCP_DST:
+ @SuppressWarnings("unchecked")
+ OFOxm<TransportPort> tcpdst = (OFOxm<TransportPort>) oxm;
+ builder.setTcpDst(TpPort.tpPort(tcpdst.getValue().getPort()));
+ break;
+ case TCP_SRC:
+ @SuppressWarnings("unchecked")
+ OFOxm<TransportPort> tcpsrc = (OFOxm<TransportPort>) oxm;
+ builder.setTcpSrc(TpPort.tpPort(tcpsrc.getValue().getPort()));
+ break;
+ case UDP_DST:
+ @SuppressWarnings("unchecked")
+ OFOxm<TransportPort> udpdst = (OFOxm<TransportPort>) oxm;
+ builder.setUdpDst(TpPort.tpPort(udpdst.getValue().getPort()));
+ break;
+ case UDP_SRC:
+ @SuppressWarnings("unchecked")
+ OFOxm<TransportPort> udpsrc = (OFOxm<TransportPort>) oxm;
+ builder.setUdpSrc(TpPort.tpPort(udpsrc.getValue().getPort()));
+ 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:
+ default:
+ log.warn("Set field type {} not yet implemented.", oxm.getMatchField().id);
+ break;
+ }
+ }
+
+ // CHECKSTYLE IGNORE MethodLength FOR NEXT 1 LINES
+ private TrafficSelector buildSelector() {
+ MacAddress mac;
+ Ip4Prefix ip4Prefix;
+ Ip6Address ip6Address;
+ Ip6Prefix ip6Prefix;
+
+ TrafficSelector.Builder builder = DefaultTrafficSelector.builder();
+ for (MatchField<?> field : match.getMatchFields()) {
+ switch (field.id) {
+ case IN_PORT:
+ builder.matchInPort(PortNumber
+ .portNumber(match.get(MatchField.IN_PORT).getPortNumber()));
+ break;
+ case IN_PHY_PORT:
+ builder.matchInPhyPort(PortNumber
+ .portNumber(match.get(MatchField.IN_PHY_PORT).getPortNumber()));
+ break;
+ case METADATA:
+ long metadata =
+ match.get(MatchField.METADATA).getValue().getValue();
+ builder.matchMetadata(metadata);
+ break;
+ case ETH_DST:
+ mac = MacAddress.valueOf(match.get(MatchField.ETH_DST).getLong());
+ builder.matchEthDst(mac);
+ break;
+ case ETH_SRC:
+ mac = MacAddress.valueOf(match.get(MatchField.ETH_SRC).getLong());
+ builder.matchEthSrc(mac);
+ break;
+ case ETH_TYPE:
+ int ethType = match.get(MatchField.ETH_TYPE).getValue();
+ if (ethType == EthType.VLAN_FRAME.getValue()) {
+ builder.matchVlanId(VlanId.ANY);
+ } else {
+ builder.matchEthType((short) ethType);
+ }
+ break;
+ case VLAN_VID:
+ VlanId vlanId = null;
+ if (match.isPartiallyMasked(MatchField.VLAN_VID)) {
+ Masked<OFVlanVidMatch> masked = match.getMasked(MatchField.VLAN_VID);
+ if (masked.getValue().equals(OFVlanVidMatch.PRESENT)
+ && masked.getMask().equals(OFVlanVidMatch.PRESENT)) {
+ vlanId = VlanId.ANY;
+ }
+ } else {
+ if (!match.get(MatchField.VLAN_VID).isPresentBitSet()) {
+ vlanId = VlanId.NONE;
+ } else {
+ vlanId = VlanId.vlanId(match.get(MatchField.VLAN_VID).getVlan());
+ }
+ }
+ if (vlanId != null) {
+ builder.matchVlanId(vlanId);
+ }
+ break;
+ case VLAN_PCP:
+ byte vlanPcp = match.get(MatchField.VLAN_PCP).getValue();
+ builder.matchVlanPcp(vlanPcp);
+ break;
+ case IP_DSCP:
+ byte ipDscp = match.get(MatchField.IP_DSCP).getDscpValue();
+ builder.matchIPDscp(ipDscp);
+ break;
+ case IP_ECN:
+ byte ipEcn = match.get(MatchField.IP_ECN).getEcnValue();
+ builder.matchIPEcn(ipEcn);
+ break;
+ case IP_PROTO:
+ short proto = match.get(MatchField.IP_PROTO).getIpProtocolNumber();
+ builder.matchIPProtocol((byte) proto);
+ break;
+ case IPV4_SRC:
+ if (match.isPartiallyMasked(MatchField.IPV4_SRC)) {
+ Masked<IPv4Address> maskedIp = match.getMasked(MatchField.IPV4_SRC);
+ ip4Prefix = Ip4Prefix.valueOf(
+ maskedIp.getValue().getInt(),
+ maskedIp.getMask().asCidrMaskLength());
+ } else {
+ ip4Prefix = Ip4Prefix.valueOf(
+ match.get(MatchField.IPV4_SRC).getInt(),
+ Ip4Prefix.MAX_MASK_LENGTH);
+ }
+ builder.matchIPSrc(ip4Prefix);
+ break;
+ case IPV4_DST:
+ if (match.isPartiallyMasked(MatchField.IPV4_DST)) {
+ Masked<IPv4Address> maskedIp = match.getMasked(MatchField.IPV4_DST);
+ ip4Prefix = Ip4Prefix.valueOf(
+ maskedIp.getValue().getInt(),
+ maskedIp.getMask().asCidrMaskLength());
+ } else {
+ ip4Prefix = Ip4Prefix.valueOf(
+ match.get(MatchField.IPV4_DST).getInt(),
+ Ip4Prefix.MAX_MASK_LENGTH);
+ }
+ builder.matchIPDst(ip4Prefix);
+ break;
+ case TCP_SRC:
+ builder.matchTcpSrc(TpPort.tpPort(match.get(MatchField.TCP_SRC).getPort()));
+ break;
+ case TCP_DST:
+ builder.matchTcpDst(TpPort.tpPort(match.get(MatchField.TCP_DST).getPort()));
+ break;
+ case UDP_SRC:
+ builder.matchUdpSrc(TpPort.tpPort(match.get(MatchField.UDP_SRC).getPort()));
+ break;
+ case UDP_DST:
+ builder.matchUdpDst(TpPort.tpPort(match.get(MatchField.UDP_DST).getPort()));
+ break;
+ case MPLS_LABEL:
+ builder.matchMplsLabel(MplsLabel.mplsLabel((int) match.get(MatchField.MPLS_LABEL)
+ .getValue()));
+ break;
+ case MPLS_BOS:
+ builder.matchMplsBos(match.get(MatchField.MPLS_BOS).getValue());
+ break;
+ case SCTP_SRC:
+ builder.matchSctpSrc(TpPort.tpPort(match.get(MatchField.SCTP_SRC).getPort()));
+ break;
+ case SCTP_DST:
+ builder.matchSctpDst(TpPort.tpPort(match.get(MatchField.SCTP_DST).getPort()));
+ break;
+ case ICMPV4_TYPE:
+ byte icmpType = (byte) match.get(MatchField.ICMPV4_TYPE).getType();
+ builder.matchIcmpType(icmpType);
+ break;
+ case ICMPV4_CODE:
+ byte icmpCode = (byte) match.get(MatchField.ICMPV4_CODE).getCode();
+ builder.matchIcmpCode(icmpCode);
+ break;
+ case IPV6_SRC:
+ if (match.isPartiallyMasked(MatchField.IPV6_SRC)) {
+ Masked<IPv6Address> maskedIp = match.getMasked(MatchField.IPV6_SRC);
+ ip6Prefix = Ip6Prefix.valueOf(
+ maskedIp.getValue().getBytes(),
+ maskedIp.getMask().asCidrMaskLength());
+ } else {
+ ip6Prefix = Ip6Prefix.valueOf(
+ match.get(MatchField.IPV6_SRC).getBytes(),
+ Ip6Prefix.MAX_MASK_LENGTH);
+ }
+ builder.matchIPv6Src(ip6Prefix);
+ break;
+ case IPV6_DST:
+ if (match.isPartiallyMasked(MatchField.IPV6_DST)) {
+ Masked<IPv6Address> maskedIp = match.getMasked(MatchField.IPV6_DST);
+ ip6Prefix = Ip6Prefix.valueOf(
+ maskedIp.getValue().getBytes(),
+ maskedIp.getMask().asCidrMaskLength());
+ } else {
+ ip6Prefix = Ip6Prefix.valueOf(
+ match.get(MatchField.IPV6_DST).getBytes(),
+ Ip6Prefix.MAX_MASK_LENGTH);
+ }
+ builder.matchIPv6Dst(ip6Prefix);
+ break;
+ case IPV6_FLABEL:
+ int flowLabel =
+ match.get(MatchField.IPV6_FLABEL).getIPv6FlowLabelValue();
+ builder.matchIPv6FlowLabel(flowLabel);
+ break;
+ case ICMPV6_TYPE:
+ byte icmpv6type = (byte) match.get(MatchField.ICMPV6_TYPE).getValue();
+ builder.matchIcmpv6Type(icmpv6type);
+ break;
+ case ICMPV6_CODE:
+ byte icmpv6code = (byte) match.get(MatchField.ICMPV6_CODE).getValue();
+ builder.matchIcmpv6Code(icmpv6code);
+ break;
+ case IPV6_ND_TARGET:
+ ip6Address =
+ Ip6Address.valueOf(match.get(MatchField.IPV6_ND_TARGET).getBytes());
+ builder.matchIPv6NDTargetAddress(ip6Address);
+ break;
+ case IPV6_ND_SLL:
+ mac = MacAddress.valueOf(match.get(MatchField.IPV6_ND_SLL).getLong());
+ builder.matchIPv6NDSourceLinkLayerAddress(mac);
+ break;
+ case IPV6_ND_TLL:
+ mac = MacAddress.valueOf(match.get(MatchField.IPV6_ND_TLL).getLong());
+ builder.matchIPv6NDTargetLinkLayerAddress(mac);
+ break;
+ case IPV6_EXTHDR:
+ builder.matchIPv6ExthdrFlags((short) match.get(MatchField.IPV6_EXTHDR)
+ .getValue());
+ break;
+ case OCH_SIGID:
+ CircuitSignalID sigId = match.get(MatchField.OCH_SIGID);
+ builder.add(matchLambda(Lambda.ochSignal(
+ lookupGridType(sigId.getGridType()), lookupChannelSpacing(sigId.getChannelSpacing()),
+ sigId.getChannelNumber(), sigId.getSpectralWidth())
+ ));
+ break;
+ case OCH_SIGTYPE:
+ U8 sigType = match.get(MatchField.OCH_SIGTYPE);
+ builder.add(matchOchSignalType(lookupOchSignalType((byte) sigType.getValue())));
+ break;
+ case TUNNEL_ID:
+ long tunnelId = match.get(MatchField.TUNNEL_ID).getValue();
+ builder.matchTunnelId(tunnelId);
+ break;
+ case ARP_OP:
+ case ARP_SHA:
+ case ARP_SPA:
+ case ARP_THA:
+ case ARP_TPA:
+ case MPLS_TC:
+ default:
+ log.warn("Match type {} not yet implemented.", field.id);
+ }
+ }
+ return builder.build();
+ }
+}
diff --git a/framework/src/onos/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/FlowModBuilder.java b/framework/src/onos/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/FlowModBuilder.java
new file mode 100644
index 00000000..e050524a
--- /dev/null
+++ b/framework/src/onos/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/FlowModBuilder.java
@@ -0,0 +1,444 @@
+/*
+ * Copyright 2014-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.flow.impl;
+
+import static org.slf4j.LoggerFactory.getLogger;
+
+import java.util.Optional;
+
+import org.onlab.packet.Ip4Address;
+import org.onlab.packet.Ip4Prefix;
+import org.onlab.packet.Ip6Address;
+import org.onlab.packet.Ip6Prefix;
+import org.onlab.packet.VlanId;
+import org.onosproject.net.OchSignal;
+import org.onosproject.net.flow.FlowRule;
+import org.onosproject.net.flow.TrafficSelector;
+import org.onosproject.net.flow.criteria.Criterion;
+import org.onosproject.net.flow.criteria.EthCriterion;
+import org.onosproject.net.flow.criteria.EthTypeCriterion;
+import org.onosproject.net.flow.criteria.IPCriterion;
+import org.onosproject.net.flow.criteria.IPDscpCriterion;
+import org.onosproject.net.flow.criteria.IPEcnCriterion;
+import org.onosproject.net.flow.criteria.IPProtocolCriterion;
+import org.onosproject.net.flow.criteria.IPv6ExthdrFlagsCriterion;
+import org.onosproject.net.flow.criteria.IPv6FlowLabelCriterion;
+import org.onosproject.net.flow.criteria.IPv6NDLinkLayerAddressCriterion;
+import org.onosproject.net.flow.criteria.IPv6NDTargetAddressCriterion;
+import org.onosproject.net.flow.criteria.IcmpCodeCriterion;
+import org.onosproject.net.flow.criteria.IcmpTypeCriterion;
+import org.onosproject.net.flow.criteria.Icmpv6CodeCriterion;
+import org.onosproject.net.flow.criteria.Icmpv6TypeCriterion;
+import org.onosproject.net.flow.criteria.MetadataCriterion;
+import org.onosproject.net.flow.criteria.MplsBosCriterion;
+import org.onosproject.net.flow.criteria.MplsCriterion;
+import org.onosproject.net.flow.criteria.OchSignalCriterion;
+import org.onosproject.net.flow.criteria.OchSignalTypeCriterion;
+import org.onosproject.net.flow.criteria.PortCriterion;
+import org.onosproject.net.flow.criteria.SctpPortCriterion;
+import org.onosproject.net.flow.criteria.TcpPortCriterion;
+import org.onosproject.net.flow.criteria.TunnelIdCriterion;
+import org.onosproject.net.flow.criteria.UdpPortCriterion;
+import org.onosproject.net.flow.criteria.VlanIdCriterion;
+import org.onosproject.net.flow.criteria.VlanPcpCriterion;
+import org.projectfloodlight.openflow.protocol.OFFactory;
+import org.projectfloodlight.openflow.protocol.OFFlowAdd;
+import org.projectfloodlight.openflow.protocol.OFFlowDelete;
+import org.projectfloodlight.openflow.protocol.OFFlowMod;
+import org.projectfloodlight.openflow.protocol.match.Match;
+import org.projectfloodlight.openflow.protocol.match.MatchField;
+import org.projectfloodlight.openflow.types.CircuitSignalID;
+import org.projectfloodlight.openflow.types.EthType;
+import org.projectfloodlight.openflow.types.ICMPv4Code;
+import org.projectfloodlight.openflow.types.ICMPv4Type;
+import org.projectfloodlight.openflow.types.IPv4Address;
+import org.projectfloodlight.openflow.types.IPv6Address;
+import org.projectfloodlight.openflow.types.IPv6FlowLabel;
+import org.projectfloodlight.openflow.types.IpDscp;
+import org.projectfloodlight.openflow.types.IpEcn;
+import org.projectfloodlight.openflow.types.IpProtocol;
+import org.projectfloodlight.openflow.types.MacAddress;
+import org.projectfloodlight.openflow.types.Masked;
+import org.projectfloodlight.openflow.types.OFBooleanValue;
+import org.projectfloodlight.openflow.types.OFMetadata;
+import org.projectfloodlight.openflow.types.OFPort;
+import org.projectfloodlight.openflow.types.OFVlanVidMatch;
+import org.projectfloodlight.openflow.types.TransportPort;
+import org.projectfloodlight.openflow.types.U16;
+import org.projectfloodlight.openflow.types.U32;
+import org.projectfloodlight.openflow.types.U64;
+import org.projectfloodlight.openflow.types.U8;
+import org.projectfloodlight.openflow.types.VlanPcp;
+import org.projectfloodlight.openflow.types.VlanVid;
+import org.slf4j.Logger;
+
+/**
+ * Builder for OpenFlow flow mods based on FlowRules.
+ */
+public abstract class FlowModBuilder {
+
+ private final Logger log = getLogger(getClass());
+
+ private final OFFactory factory;
+ private final FlowRule flowRule;
+ private final TrafficSelector selector;
+ protected final Long xid;
+
+ /**
+ * Creates a new flow mod builder.
+ *
+ * @param flowRule the flow rule to transform into a flow mod
+ * @param factory the OpenFlow factory to use to build the flow mod
+ * @param xid the transaction ID
+ * @return the new flow mod builder
+ */
+ public static FlowModBuilder builder(FlowRule flowRule,
+ OFFactory factory,
+ Optional<Long> xid) {
+ switch (factory.getVersion()) {
+ case OF_10:
+ return new FlowModBuilderVer10(flowRule, factory, xid);
+ case OF_13:
+ return new FlowModBuilderVer13(flowRule, factory, xid);
+ default:
+ throw new UnsupportedOperationException(
+ "No flow mod builder for protocol version " + factory.getVersion());
+ }
+ }
+
+ /**
+ * Constructs a flow mod builder.
+ *
+ * @param flowRule the flow rule to transform into a flow mod
+ * @param factory the OpenFlow factory to use to build the flow mod
+ * @param xid the transaction ID
+ */
+ protected FlowModBuilder(FlowRule flowRule, OFFactory factory, Optional<Long> xid) {
+ this.factory = factory;
+ this.flowRule = flowRule;
+ this.selector = flowRule.selector();
+ this.xid = xid.orElse(0L);
+
+ }
+
+ /**
+ * Builds an ADD flow mod.
+ *
+ * @return the flow mod
+ */
+ public abstract OFFlowAdd buildFlowAdd();
+
+ /**
+ * Builds a MODIFY flow mod.
+ *
+ * @return the flow mod
+ */
+ public abstract OFFlowMod buildFlowMod();
+
+ /**
+ * Builds a DELETE flow mod.
+ *
+ * @return the flow mod
+ */
+ public abstract OFFlowDelete buildFlowDel();
+
+ /**
+ * Builds the match for the flow mod.
+ *
+ * @return the match
+ */
+ // CHECKSTYLE IGNORE MethodLength FOR NEXT 300 LINES
+ protected Match buildMatch() {
+ Match.Builder mBuilder = factory.buildMatch();
+ Ip6Address ip6Address;
+ Ip4Prefix ip4Prefix;
+ Ip6Prefix ip6Prefix;
+ EthCriterion ethCriterion;
+ IPCriterion ipCriterion;
+ TcpPortCriterion tcpPortCriterion;
+ UdpPortCriterion udpPortCriterion;
+ SctpPortCriterion sctpPortCriterion;
+ IPv6NDLinkLayerAddressCriterion llAddressCriterion;
+
+ for (Criterion c : selector.criteria()) {
+ switch (c.type()) {
+ case IN_PORT:
+ PortCriterion inPort = (PortCriterion) c;
+ mBuilder.setExact(MatchField.IN_PORT,
+ OFPort.of((int) inPort.port().toLong()));
+ break;
+ case IN_PHY_PORT:
+ PortCriterion inPhyPort = (PortCriterion) c;
+ mBuilder.setExact(MatchField.IN_PORT,
+ OFPort.of((int) inPhyPort.port().toLong()));
+ break;
+ case METADATA:
+ MetadataCriterion metadata = (MetadataCriterion) c;
+ mBuilder.setExact(MatchField.METADATA,
+ OFMetadata.ofRaw(metadata.metadata()));
+ break;
+ case ETH_DST:
+ ethCriterion = (EthCriterion) c;
+ mBuilder.setExact(MatchField.ETH_DST,
+ MacAddress.of(ethCriterion.mac().toLong()));
+ break;
+ case ETH_SRC:
+ ethCriterion = (EthCriterion) c;
+ mBuilder.setExact(MatchField.ETH_SRC,
+ MacAddress.of(ethCriterion.mac().toLong()));
+ break;
+ case ETH_TYPE:
+ EthTypeCriterion ethType = (EthTypeCriterion) c;
+ mBuilder.setExact(MatchField.ETH_TYPE, EthType.of(ethType.ethType().toShort()));
+ break;
+ case VLAN_VID:
+ VlanIdCriterion vid = (VlanIdCriterion) c;
+
+ if (vid.vlanId().equals(VlanId.ANY)) {
+ mBuilder.setMasked(MatchField.VLAN_VID, OFVlanVidMatch.PRESENT,
+ OFVlanVidMatch.PRESENT);
+ } else if (vid.vlanId().equals(VlanId.NONE)) {
+ mBuilder.setExact(MatchField.VLAN_VID, OFVlanVidMatch.NONE);
+ } else {
+ mBuilder.setExact(MatchField.VLAN_VID,
+ OFVlanVidMatch.ofVlanVid(VlanVid.ofVlan(vid.vlanId().toShort())));
+ }
+ break;
+ case VLAN_PCP:
+ VlanPcpCriterion vpcp = (VlanPcpCriterion) c;
+ mBuilder.setExact(MatchField.VLAN_PCP, VlanPcp.of(vpcp.priority()));
+ break;
+ case IP_DSCP:
+ IPDscpCriterion ipDscpCriterion = (IPDscpCriterion) c;
+ mBuilder.setExact(MatchField.IP_DSCP,
+ IpDscp.of(ipDscpCriterion.ipDscp()));
+ break;
+ case IP_ECN:
+ IPEcnCriterion ipEcnCriterion = (IPEcnCriterion) c;
+ mBuilder.setExact(MatchField.IP_ECN,
+ IpEcn.of(ipEcnCriterion.ipEcn()));
+ break;
+ case IP_PROTO:
+ IPProtocolCriterion p = (IPProtocolCriterion) c;
+ mBuilder.setExact(MatchField.IP_PROTO, IpProtocol.of(p.protocol()));
+ break;
+ case IPV4_SRC:
+ ipCriterion = (IPCriterion) c;
+ ip4Prefix = ipCriterion.ip().getIp4Prefix();
+ if (ip4Prefix.prefixLength() != Ip4Prefix.MAX_MASK_LENGTH) {
+ Ip4Address maskAddr =
+ Ip4Address.makeMaskPrefix(ip4Prefix.prefixLength());
+ Masked<IPv4Address> maskedIp =
+ Masked.of(IPv4Address.of(ip4Prefix.address().toInt()),
+ IPv4Address.of(maskAddr.toInt()));
+ mBuilder.setMasked(MatchField.IPV4_SRC, maskedIp);
+ } else {
+ mBuilder.setExact(MatchField.IPV4_SRC,
+ IPv4Address.of(ip4Prefix.address().toInt()));
+ }
+ break;
+ case IPV4_DST:
+ ipCriterion = (IPCriterion) c;
+ ip4Prefix = ipCriterion.ip().getIp4Prefix();
+ if (ip4Prefix.prefixLength() != Ip4Prefix.MAX_MASK_LENGTH) {
+ Ip4Address maskAddr =
+ Ip4Address.makeMaskPrefix(ip4Prefix.prefixLength());
+ Masked<IPv4Address> maskedIp =
+ Masked.of(IPv4Address.of(ip4Prefix.address().toInt()),
+ IPv4Address.of(maskAddr.toInt()));
+ mBuilder.setMasked(MatchField.IPV4_DST, maskedIp);
+ } else {
+ mBuilder.setExact(MatchField.IPV4_DST,
+ IPv4Address.of(ip4Prefix.address().toInt()));
+ }
+ break;
+ case TCP_SRC:
+ tcpPortCriterion = (TcpPortCriterion) c;
+ mBuilder.setExact(MatchField.TCP_SRC,
+ TransportPort.of(tcpPortCriterion.tcpPort().toInt()));
+ break;
+ case TCP_DST:
+ tcpPortCriterion = (TcpPortCriterion) c;
+ mBuilder.setExact(MatchField.TCP_DST,
+ TransportPort.of(tcpPortCriterion.tcpPort().toInt()));
+ break;
+ case UDP_SRC:
+ udpPortCriterion = (UdpPortCriterion) c;
+ mBuilder.setExact(MatchField.UDP_SRC,
+ TransportPort.of(udpPortCriterion.udpPort().toInt()));
+ break;
+ case UDP_DST:
+ udpPortCriterion = (UdpPortCriterion) c;
+ mBuilder.setExact(MatchField.UDP_DST,
+ TransportPort.of(udpPortCriterion.udpPort().toInt()));
+ break;
+ case SCTP_SRC:
+ sctpPortCriterion = (SctpPortCriterion) c;
+ mBuilder.setExact(MatchField.SCTP_SRC,
+ TransportPort.of(sctpPortCriterion.sctpPort().toInt()));
+ break;
+ case SCTP_DST:
+ sctpPortCriterion = (SctpPortCriterion) c;
+ mBuilder.setExact(MatchField.SCTP_DST,
+ TransportPort.of(sctpPortCriterion.sctpPort().toInt()));
+ break;
+ case ICMPV4_TYPE:
+ IcmpTypeCriterion icmpType = (IcmpTypeCriterion) c;
+ mBuilder.setExact(MatchField.ICMPV4_TYPE,
+ ICMPv4Type.of(icmpType.icmpType()));
+ break;
+ case ICMPV4_CODE:
+ IcmpCodeCriterion icmpCode = (IcmpCodeCriterion) c;
+ mBuilder.setExact(MatchField.ICMPV4_CODE,
+ ICMPv4Code.of(icmpCode.icmpCode()));
+ break;
+ case IPV6_SRC:
+ ipCriterion = (IPCriterion) c;
+ ip6Prefix = ipCriterion.ip().getIp6Prefix();
+ if (ip6Prefix.prefixLength() != Ip6Prefix.MAX_MASK_LENGTH) {
+ Ip6Address maskAddr =
+ Ip6Address.makeMaskPrefix(ip6Prefix.prefixLength());
+ Masked<IPv6Address> maskedIp =
+ Masked.of(IPv6Address.of(ip6Prefix.address().toString()),
+ IPv6Address.of(maskAddr.toString()));
+ mBuilder.setMasked(MatchField.IPV6_SRC, maskedIp);
+ } else {
+ mBuilder.setExact(MatchField.IPV6_SRC,
+ IPv6Address.of(ip6Prefix.address().toString()));
+ }
+ break;
+ case IPV6_DST:
+ ipCriterion = (IPCriterion) c;
+ ip6Prefix = ipCriterion.ip().getIp6Prefix();
+ if (ip6Prefix.prefixLength() != Ip6Prefix.MAX_MASK_LENGTH) {
+ Ip6Address maskAddr =
+ Ip6Address.makeMaskPrefix(ip6Prefix.prefixLength());
+ Masked<IPv6Address> maskedIp =
+ Masked.of(IPv6Address.of(ip6Prefix.address().toString()),
+ IPv6Address.of(maskAddr.toString()));
+ mBuilder.setMasked(MatchField.IPV6_DST, maskedIp);
+ } else {
+ mBuilder.setExact(MatchField.IPV6_DST,
+ IPv6Address.of(ip6Prefix.address().toString()));
+ }
+ break;
+ case IPV6_FLABEL:
+ IPv6FlowLabelCriterion flowLabelCriterion =
+ (IPv6FlowLabelCriterion) c;
+ mBuilder.setExact(MatchField.IPV6_FLABEL,
+ IPv6FlowLabel.of(flowLabelCriterion.flowLabel()));
+ break;
+ case ICMPV6_TYPE:
+ Icmpv6TypeCriterion icmpv6Type = (Icmpv6TypeCriterion) c;
+ mBuilder.setExact(MatchField.ICMPV6_TYPE,
+ U8.of(icmpv6Type.icmpv6Type()));
+ break;
+ case ICMPV6_CODE:
+ Icmpv6CodeCriterion icmpv6Code = (Icmpv6CodeCriterion) c;
+ mBuilder.setExact(MatchField.ICMPV6_CODE,
+ U8.of(icmpv6Code.icmpv6Code()));
+ break;
+ case IPV6_ND_TARGET:
+ IPv6NDTargetAddressCriterion targetAddressCriterion =
+ (IPv6NDTargetAddressCriterion) c;
+ ip6Address = targetAddressCriterion.targetAddress();
+ mBuilder.setExact(MatchField.IPV6_ND_TARGET,
+ IPv6Address.of(ip6Address.toOctets()));
+ break;
+ case IPV6_ND_SLL:
+ llAddressCriterion =
+ (IPv6NDLinkLayerAddressCriterion) c;
+ mBuilder.setExact(MatchField.IPV6_ND_SLL,
+ MacAddress.of(llAddressCriterion.mac().toLong()));
+ break;
+ case IPV6_ND_TLL:
+ llAddressCriterion =
+ (IPv6NDLinkLayerAddressCriterion) c;
+ mBuilder.setExact(MatchField.IPV6_ND_TLL,
+ MacAddress.of(llAddressCriterion.mac().toLong()));
+ break;
+ case MPLS_LABEL:
+ MplsCriterion mp = (MplsCriterion) c;
+ mBuilder.setExact(MatchField.MPLS_LABEL, U32.of(mp.label().toInt()));
+ break;
+ case IPV6_EXTHDR:
+ IPv6ExthdrFlagsCriterion exthdrFlagsCriterion =
+ (IPv6ExthdrFlagsCriterion) c;
+ mBuilder.setExact(MatchField.IPV6_EXTHDR,
+ U16.of(exthdrFlagsCriterion.exthdrFlags()));
+ break;
+ case OCH_SIGID:
+ try {
+ OchSignalCriterion ochSignalCriterion = (OchSignalCriterion) c;
+ OchSignal signal = ochSignalCriterion.lambda();
+ byte gridType = OpenFlowValueMapper.lookupGridType(signal.gridType());
+ byte channelSpacing = OpenFlowValueMapper.lookupChannelSpacing(signal.channelSpacing());
+ mBuilder.setExact(MatchField.OCH_SIGID,
+ new CircuitSignalID(gridType, channelSpacing,
+ (short) signal.spacingMultiplier(), (short) signal.slotGranularity()));
+ } catch (NoMappingFoundException e) {
+ log.warn(e.getMessage());
+ }
+ break;
+ case OCH_SIGTYPE:
+ OchSignalTypeCriterion sc = (OchSignalTypeCriterion) c;
+ byte signalType = OpenFlowValueMapper.lookupOchSignalType(sc.signalType());
+ mBuilder.setExact(MatchField.OCH_SIGTYPE, U8.of(signalType));
+ break;
+ case TUNNEL_ID:
+ TunnelIdCriterion tunnelId = (TunnelIdCriterion) c;
+ mBuilder.setExact(MatchField.TUNNEL_ID,
+ U64.of(tunnelId.tunnelId()));
+ break;
+ case MPLS_BOS:
+ MplsBosCriterion mplsBos = (MplsBosCriterion) c;
+ mBuilder.setExact(MatchField.MPLS_BOS,
+ mplsBos.mplsBos() ? OFBooleanValue.TRUE
+ : OFBooleanValue.FALSE);
+ break;
+ case ARP_OP:
+ case ARP_SHA:
+ case ARP_SPA:
+ case ARP_THA:
+ case ARP_TPA:
+ case MPLS_TC:
+ case PBB_ISID:
+ default:
+ log.warn("Match type {} not yet implemented.", c.type());
+ }
+ }
+ return mBuilder.build();
+ }
+
+ /**
+ * Returns the flow rule for this builder.
+ *
+ * @return the flow rule
+ */
+ protected FlowRule flowRule() {
+ return flowRule;
+ }
+
+ /**
+ * Returns the factory used for building OpenFlow constructs.
+ *
+ * @return the factory
+ */
+ protected OFFactory factory() {
+ return factory;
+ }
+
+}
diff --git a/framework/src/onos/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/FlowModBuilderVer10.java b/framework/src/onos/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/FlowModBuilderVer10.java
new file mode 100644
index 00000000..c9de4500
--- /dev/null
+++ b/framework/src/onos/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/FlowModBuilderVer10.java
@@ -0,0 +1,230 @@
+/*
+ * Copyright 2014-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.flow.impl;
+
+import org.onlab.packet.Ip4Address;
+import org.onosproject.net.PortNumber;
+import org.onosproject.net.flow.FlowRule;
+import org.onosproject.net.flow.TrafficTreatment;
+import org.onosproject.net.flow.instructions.Instruction;
+import org.onosproject.net.flow.instructions.Instructions.OutputInstruction;
+import org.onosproject.net.flow.instructions.L2ModificationInstruction;
+import org.onosproject.net.flow.instructions.L2ModificationInstruction.ModEtherInstruction;
+import org.onosproject.net.flow.instructions.L2ModificationInstruction.ModVlanIdInstruction;
+import org.onosproject.net.flow.instructions.L2ModificationInstruction.ModVlanPcpInstruction;
+import org.onosproject.net.flow.instructions.L3ModificationInstruction;
+import org.onosproject.net.flow.instructions.L3ModificationInstruction.ModIPInstruction;
+import org.projectfloodlight.openflow.protocol.OFFactory;
+import org.projectfloodlight.openflow.protocol.OFFlowAdd;
+import org.projectfloodlight.openflow.protocol.OFFlowDelete;
+import org.projectfloodlight.openflow.protocol.OFFlowMod;
+import org.projectfloodlight.openflow.protocol.OFFlowModFlags;
+import org.projectfloodlight.openflow.protocol.action.OFAction;
+import org.projectfloodlight.openflow.protocol.action.OFActionOutput;
+import org.projectfloodlight.openflow.protocol.match.Match;
+import org.projectfloodlight.openflow.types.IPv4Address;
+import org.projectfloodlight.openflow.types.MacAddress;
+import org.projectfloodlight.openflow.types.OFBufferId;
+import org.projectfloodlight.openflow.types.OFPort;
+import org.projectfloodlight.openflow.types.U64;
+import org.projectfloodlight.openflow.types.VlanPcp;
+import org.projectfloodlight.openflow.types.VlanVid;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.Collections;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Optional;
+
+/**
+ * Flow mod builder for OpenFlow 1.0.
+ */
+public class FlowModBuilderVer10 extends FlowModBuilder {
+
+ private final Logger log = LoggerFactory.getLogger(getClass());
+ private static final int OFPCML_NO_BUFFER = 0xffff;
+
+ private final TrafficTreatment treatment;
+
+ /**
+ * Constructor for a flow mod builder for OpenFlow 1.0.
+ *
+ * @param flowRule the flow rule to transform into a flow mod
+ * @param factory the OpenFlow factory to use to build the flow mod
+ * @param xid the transaction ID
+ */
+ protected FlowModBuilderVer10(FlowRule flowRule,
+ OFFactory factory, Optional<Long> xid) {
+ super(flowRule, factory, xid);
+
+ this.treatment = flowRule.treatment();
+ }
+
+ @Override
+ public OFFlowAdd buildFlowAdd() {
+ Match match = buildMatch();
+ List<OFAction> actions = buildActions();
+
+ long cookie = flowRule().id().value();
+
+
+ OFFlowAdd fm = factory().buildFlowAdd()
+ .setXid(xid)
+ .setCookie(U64.of(cookie))
+ .setBufferId(OFBufferId.NO_BUFFER)
+ .setActions(actions)
+ .setMatch(match)
+ .setFlags(Collections.singleton(OFFlowModFlags.SEND_FLOW_REM))
+ .setPriority(flowRule().priority())
+ .build();
+
+ return fm;
+ }
+
+ @Override
+ public OFFlowMod buildFlowMod() {
+ Match match = buildMatch();
+ List<OFAction> actions = buildActions();
+
+ long cookie = flowRule().id().value();
+
+ OFFlowMod fm = factory().buildFlowModify()
+ .setXid(xid)
+ .setCookie(U64.of(cookie))
+ .setBufferId(OFBufferId.NO_BUFFER)
+ .setActions(actions)
+ .setMatch(match)
+ .setFlags(Collections.singleton(OFFlowModFlags.SEND_FLOW_REM))
+ .setPriority(flowRule().priority())
+ .build();
+
+ return fm;
+ }
+
+ @Override
+ public OFFlowDelete buildFlowDel() {
+ Match match = buildMatch();
+
+ long cookie = flowRule().id().value();
+
+ OFFlowDelete fm = factory().buildFlowDelete()
+ .setXid(xid)
+ .setCookie(U64.of(cookie))
+ .setBufferId(OFBufferId.NO_BUFFER)
+ .setMatch(match)
+ .setFlags(Collections.singleton(OFFlowModFlags.SEND_FLOW_REM))
+ .setPriority(flowRule().priority())
+ .build();
+
+ return fm;
+ }
+
+ private List<OFAction> buildActions() {
+ List<OFAction> acts = new LinkedList<>();
+ OFAction act;
+ if (treatment == null) {
+ return acts;
+ }
+ for (Instruction i : treatment.immediate()) {
+ switch (i.type()) {
+ case DROP:
+ log.warn("Saw drop action; assigning drop action");
+ return Collections.emptyList();
+ case L2MODIFICATION:
+ act = buildL2Modification(i);
+ if (act != null) {
+ acts.add(buildL2Modification(i));
+ }
+ break;
+ case L3MODIFICATION:
+ act = buildL3Modification(i);
+ if (act != null) {
+ acts.add(buildL3Modification(i));
+ }
+ break;
+ case OUTPUT:
+ OutputInstruction out = (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);
+ }
+ acts.add(action.build());
+ break;
+ case L0MODIFICATION:
+ case GROUP:
+ case TABLE:
+ case METADATA:
+ log.warn("Instruction type {} not supported with protocol version {}",
+ i.type(), factory().getVersion());
+ break;
+ default:
+ log.warn("Instruction type {} not yet implemented.", i.type());
+ }
+ }
+
+ return acts;
+ }
+
+ private OFAction buildL3Modification(Instruction i) {
+ L3ModificationInstruction l3m = (L3ModificationInstruction) i;
+ ModIPInstruction ip;
+ Ip4Address ip4;
+ switch (l3m.subtype()) {
+ case IPV4_SRC:
+ ip = (ModIPInstruction) i;
+ ip4 = ip.ip().getIp4Address();
+ return factory().actions().setNwSrc(IPv4Address.of(ip4.toInt()));
+ case IPV4_DST:
+ ip = (ModIPInstruction) i;
+ ip4 = ip.ip().getIp4Address();
+ return factory().actions().setNwDst(IPv4Address.of(ip4.toInt()));
+ default:
+ log.warn("Unimplemented action type {}.", l3m.subtype());
+ break;
+ }
+ return null;
+ }
+
+ private OFAction buildL2Modification(Instruction i) {
+ L2ModificationInstruction l2m = (L2ModificationInstruction) i;
+ ModEtherInstruction eth;
+ switch (l2m.subtype()) {
+ case ETH_DST:
+ eth = (ModEtherInstruction) l2m;
+ return factory().actions().setDlDst(MacAddress.of(eth.mac().toLong()));
+ case ETH_SRC:
+ eth = (ModEtherInstruction) l2m;
+ return factory().actions().setDlSrc(MacAddress.of(eth.mac().toLong()));
+ case VLAN_ID:
+ ModVlanIdInstruction vlanId = (ModVlanIdInstruction) l2m;
+ return factory().actions().setVlanVid(VlanVid.ofVlan(vlanId.vlanId().toShort()));
+ case VLAN_PCP:
+ ModVlanPcpInstruction vlanPcp = (ModVlanPcpInstruction) l2m;
+ return factory().actions().setVlanPcp(VlanPcp.of(vlanPcp.vlanPcp()));
+ case VLAN_POP:
+ return factory().actions().stripVlan();
+ case VLAN_PUSH:
+ return null;
+ default:
+ log.warn("Unimplemented action type {}.", l2m.subtype());
+ break;
+ }
+ return null;
+ }
+
+}
diff --git a/framework/src/onos/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/FlowModBuilderVer13.java b/framework/src/onos/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/FlowModBuilderVer13.java
new file mode 100644
index 00000000..8918d337
--- /dev/null
+++ b/framework/src/onos/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/FlowModBuilderVer13.java
@@ -0,0 +1,458 @@
+/*
+ * Copyright 2014-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.flow.impl;
+
+import com.google.common.collect.Lists;
+import org.onlab.packet.Ip4Address;
+import org.onlab.packet.Ip6Address;
+import org.onosproject.net.OchSignal;
+import org.onosproject.net.PortNumber;
+import org.onosproject.net.flow.FlowRule;
+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.Instructions.GroupInstruction;
+import org.onosproject.net.flow.instructions.Instructions.OutputInstruction;
+import org.onosproject.net.flow.instructions.L0ModificationInstruction;
+import org.onosproject.net.flow.instructions.L0ModificationInstruction.ModLambdaInstruction;
+import org.onosproject.net.flow.instructions.L0ModificationInstruction.ModOchSignalInstruction;
+import org.onosproject.net.flow.instructions.L2ModificationInstruction;
+import org.onosproject.net.flow.instructions.L2ModificationInstruction.ModEtherInstruction;
+import org.onosproject.net.flow.instructions.L2ModificationInstruction.ModMplsBosInstruction;
+import org.onosproject.net.flow.instructions.L2ModificationInstruction.ModMplsLabelInstruction;
+import org.onosproject.net.flow.instructions.L2ModificationInstruction.ModVlanIdInstruction;
+import org.onosproject.net.flow.instructions.L2ModificationInstruction.ModVlanPcpInstruction;
+import org.onosproject.net.flow.instructions.L2ModificationInstruction.PushHeaderInstructions;
+import org.onosproject.net.flow.instructions.L2ModificationInstruction.ModTunnelIdInstruction;
+import org.onosproject.net.flow.instructions.L3ModificationInstruction;
+import org.onosproject.net.flow.instructions.L3ModificationInstruction.ModIPInstruction;
+import org.onosproject.net.flow.instructions.L3ModificationInstruction.ModIPv6FlowLabelInstruction;
+import org.onosproject.net.flow.instructions.L4ModificationInstruction;
+import org.onosproject.net.flow.instructions.L4ModificationInstruction.ModTransportPortInstruction;
+import org.projectfloodlight.openflow.protocol.OFFactory;
+import org.projectfloodlight.openflow.protocol.OFFlowAdd;
+import org.projectfloodlight.openflow.protocol.OFFlowDelete;
+import org.projectfloodlight.openflow.protocol.OFFlowMod;
+import org.projectfloodlight.openflow.protocol.OFFlowModFlags;
+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.instruction.OFInstruction;
+import org.projectfloodlight.openflow.protocol.match.Match;
+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.OFBufferId;
+import org.projectfloodlight.openflow.types.OFGroup;
+import org.projectfloodlight.openflow.types.OFPort;
+import org.projectfloodlight.openflow.types.OFVlanVidMatch;
+import org.projectfloodlight.openflow.types.TableId;
+import org.projectfloodlight.openflow.types.TransportPort;
+import org.projectfloodlight.openflow.types.U32;
+import org.projectfloodlight.openflow.types.U64;
+import org.projectfloodlight.openflow.types.VlanPcp;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.Collections;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Optional;
+
+/**
+ * Flow mod builder for OpenFlow 1.3+.
+ */
+public class FlowModBuilderVer13 extends FlowModBuilder {
+
+ private final Logger log = LoggerFactory.getLogger(getClass());
+ private static final int OFPCML_NO_BUFFER = 0xffff;
+
+ private final TrafficTreatment treatment;
+
+ /**
+ * Constructor for a flow mod builder for OpenFlow 1.3.
+ *
+ * @param flowRule the flow rule to transform into a flow mod
+ * @param factory the OpenFlow factory to use to build the flow mod
+ * @param xid the transaction ID
+ */
+ protected FlowModBuilderVer13(FlowRule flowRule, OFFactory factory, Optional<Long> xid) {
+ super(flowRule, factory, xid);
+
+ this.treatment = flowRule.treatment();
+ }
+
+ @Override
+ public OFFlowAdd buildFlowAdd() {
+ Match match = buildMatch();
+ List<OFAction> deferredActions = buildActions(treatment.deferred());
+ List<OFAction> immediateActions = buildActions(treatment.immediate());
+ List<OFInstruction> instructions = Lists.newLinkedList();
+
+
+ if (treatment.clearedDeferred()) {
+ instructions.add(factory().instructions().clearActions());
+ }
+ if (immediateActions.size() > 0) {
+ instructions.add(factory().instructions().applyActions(immediateActions));
+ }
+ if (deferredActions.size() > 0) {
+ instructions.add(factory().instructions().writeActions(deferredActions));
+ }
+ if (treatment.tableTransition() != null) {
+ instructions.add(buildTableGoto(treatment.tableTransition()));
+ }
+ if (treatment.writeMetadata() != null) {
+ instructions.add(buildMetadata(treatment.writeMetadata()));
+ }
+
+ long cookie = flowRule().id().value();
+
+ OFFlowAdd fm = factory().buildFlowAdd()
+ .setXid(xid)
+ .setCookie(U64.of(cookie))
+ .setBufferId(OFBufferId.NO_BUFFER)
+ .setInstructions(instructions)
+ .setMatch(match)
+ .setFlags(Collections.singleton(OFFlowModFlags.SEND_FLOW_REM))
+ .setPriority(flowRule().priority())
+ .setTableId(TableId.of(flowRule().tableId()))
+ .build();
+
+ return fm;
+ }
+
+ @Override
+ public OFFlowMod buildFlowMod() {
+ Match match = buildMatch();
+ List<OFAction> deferredActions = buildActions(treatment.deferred());
+ List<OFAction> immediateActions = buildActions(treatment.immediate());
+ List<OFInstruction> instructions = Lists.newLinkedList();
+
+
+ if (immediateActions.size() > 0) {
+ instructions.add(factory().instructions().applyActions(immediateActions));
+ }
+ if (treatment.clearedDeferred()) {
+ instructions.add(factory().instructions().clearActions());
+ }
+ if (deferredActions.size() > 0) {
+ instructions.add(factory().instructions().writeActions(deferredActions));
+ }
+ if (treatment.tableTransition() != null) {
+ instructions.add(buildTableGoto(treatment.tableTransition()));
+ }
+ if (treatment.writeMetadata() != null) {
+ instructions.add(buildMetadata(treatment.writeMetadata()));
+ }
+ if (treatment.metered() != null) {
+ instructions.add(buildMeter(treatment.metered()));
+ }
+
+ long cookie = flowRule().id().value();
+
+ OFFlowMod fm = factory().buildFlowModify()
+ .setXid(xid)
+ .setCookie(U64.of(cookie))
+ .setBufferId(OFBufferId.NO_BUFFER)
+ .setInstructions(instructions)
+ .setMatch(match)
+ .setFlags(Collections.singleton(OFFlowModFlags.SEND_FLOW_REM))
+ .setPriority(flowRule().priority())
+ .setTableId(TableId.of(flowRule().tableId()))
+ .build();
+
+ return fm;
+ }
+
+ @Override
+ public OFFlowDelete buildFlowDel() {
+ Match match = buildMatch();
+
+ long cookie = flowRule().id().value();
+
+ OFFlowDelete fm = factory().buildFlowDelete()
+ .setXid(xid)
+ .setCookie(U64.of(cookie))
+ .setBufferId(OFBufferId.NO_BUFFER)
+ .setMatch(match)
+ .setFlags(Collections.singleton(OFFlowModFlags.SEND_FLOW_REM))
+ .setPriority(flowRule().priority())
+ .setTableId(TableId.of(flowRule().tableId()))
+ .build();
+
+ return fm;
+ }
+
+ private List<OFAction> buildActions(List<Instruction> treatments) {
+ if (treatment == null) {
+ return Collections.emptyList();
+ }
+
+ boolean tableFound = false;
+ List<OFAction> actions = new LinkedList<>();
+ for (Instruction i : treatments) {
+ switch (i.type()) {
+ case DROP:
+ 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 L4MODIFICATION:
+ actions.add(buildL4Modification(i));
+ break;
+ case OUTPUT:
+ OutputInstruction out = (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:
+ GroupInstruction group = (GroupInstruction) i;
+ OFActionGroup.Builder groupBuilder = factory().actions().buildGroup()
+ .setGroup(OFGroup.of(group.groupId().id()));
+ actions.add(groupBuilder.build());
+ break;
+ case TABLE:
+ //FIXME: should not occur here.
+ tableFound = true;
+ break;
+ default:
+ log.warn("Instruction type {} not yet implemented.", i.type());
+ }
+ }
+ if (tableFound && actions.isEmpty()) {
+ // handles the case where there are no actions, but there is
+ // a goto instruction for the next table
+ return Collections.emptyList();
+ }
+ return actions;
+ }
+
+ private OFInstruction buildTableGoto(Instructions.TableTypeTransition i) {
+ OFInstruction instruction = factory().instructions().gotoTable(
+ TableId.of(i.tableId()));
+ return instruction;
+ }
+
+ private OFInstruction buildMetadata(Instructions.MetadataInstruction m) {
+ OFInstruction instruction = factory().instructions().writeMetadata(
+ U64.of(m.metadata()), U64.of(m.metadataMask()));
+ return instruction;
+ }
+
+ private OFInstruction buildMeter(Instructions.MeterInstruction metered) {
+ return factory().instructions().meter(metered.meterId().id());
+ }
+
+
+ private OFAction buildL0Modification(Instruction i) {
+ L0ModificationInstruction l0m = (L0ModificationInstruction) i;
+ switch (l0m.subtype()) {
+ case LAMBDA:
+ return buildModLambdaInstruction((ModLambdaInstruction) i);
+ case OCH:
+ try {
+ return buildModOchSignalInstruction((ModOchSignalInstruction) i);
+ } catch (NoMappingFoundException e) {
+ log.warn(e.getMessage());
+ break;
+ }
+ default:
+ log.warn("Unimplemented action type {}.", l0m.subtype());
+ break;
+ }
+ return null;
+ }
+
+ private OFAction buildModLambdaInstruction(ModLambdaInstruction instruction) {
+ return factory().actions().circuit(factory().oxms().ochSigidBasic(
+ new CircuitSignalID((byte) 1, (byte) 2, instruction.lambda(), (short) 1)));
+ }
+
+ private OFAction buildModOchSignalInstruction(ModOchSignalInstruction instruction) {
+ OchSignal signal = instruction.lambda();
+ byte gridType = OpenFlowValueMapper.lookupGridType(signal.gridType());
+ byte channelSpacing = OpenFlowValueMapper.lookupChannelSpacing(signal.channelSpacing());
+
+ return factory().actions().circuit(factory().oxms().ochSigidBasic(
+ new CircuitSignalID(gridType, channelSpacing,
+ (short) signal.spacingMultiplier(), (short) signal.slotGranularity())
+ ));
+ }
+
+ private OFAction buildL2Modification(Instruction i) {
+ L2ModificationInstruction l2m = (L2ModificationInstruction) i;
+ ModEtherInstruction eth;
+ OFOxm<?> oxm = null;
+ switch (l2m.subtype()) {
+ case ETH_DST:
+ eth = (ModEtherInstruction) l2m;
+ oxm = factory().oxms().ethDst(MacAddress.of(eth.mac().toLong()));
+ break;
+ case ETH_SRC:
+ eth = (ModEtherInstruction) l2m;
+ oxm = factory().oxms().ethSrc(MacAddress.of(eth.mac().toLong()));
+ break;
+ case VLAN_ID:
+ ModVlanIdInstruction vlanId = (ModVlanIdInstruction) l2m;
+ oxm = factory().oxms().vlanVid(OFVlanVidMatch.ofVlan(vlanId.vlanId().toShort()));
+ break;
+ case VLAN_PCP:
+ ModVlanPcpInstruction vlanPcp = (ModVlanPcpInstruction) l2m;
+ oxm = factory().oxms().vlanPcp(VlanPcp.of(vlanPcp.vlanPcp()));
+ break;
+ case MPLS_PUSH:
+ PushHeaderInstructions pushHeaderInstructions =
+ (PushHeaderInstructions) l2m;
+ return factory().actions().pushMpls(EthType.of(pushHeaderInstructions
+ .ethernetType().toShort()));
+ case MPLS_POP:
+ PushHeaderInstructions popHeaderInstructions =
+ (PushHeaderInstructions) l2m;
+ return factory().actions().popMpls(EthType.of(popHeaderInstructions
+ .ethernetType().toShort()));
+ case MPLS_LABEL:
+ ModMplsLabelInstruction mplsLabel =
+ (ModMplsLabelInstruction) l2m;
+ oxm = factory().oxms().mplsLabel(U32.of(mplsLabel.mplsLabel().toInt()));
+ break;
+ case MPLS_BOS:
+ ModMplsBosInstruction mplsBos = (ModMplsBosInstruction) l2m;
+ oxm = factory().oxms()
+ .mplsBos(mplsBos.mplsBos() ? OFBooleanValue.TRUE
+ : OFBooleanValue.FALSE);
+ break;
+ case DEC_MPLS_TTL:
+ return factory().actions().decMplsTtl();
+ case VLAN_POP:
+ return factory().actions().popVlan();
+ case VLAN_PUSH:
+ PushHeaderInstructions pushVlanInstruction = (PushHeaderInstructions) l2m;
+ return factory().actions().pushVlan(
+ EthType.of(pushVlanInstruction.ethernetType().toShort()));
+ case TUNNEL_ID:
+ ModTunnelIdInstruction tunnelId = (ModTunnelIdInstruction) l2m;
+ oxm = factory().oxms().tunnelId(U64.of(tunnelId.tunnelId()));
+ break;
+ 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;
+ ModIPInstruction ip;
+ Ip4Address ip4;
+ Ip6Address ip6;
+ OFOxm<?> oxm = null;
+ switch (l3m.subtype()) {
+ case IPV4_SRC:
+ ip = (ModIPInstruction) i;
+ ip4 = ip.ip().getIp4Address();
+ oxm = factory().oxms().ipv4Src(IPv4Address.of(ip4.toInt()));
+ break;
+ case IPV4_DST:
+ ip = (ModIPInstruction) i;
+ ip4 = ip.ip().getIp4Address();
+ oxm = factory().oxms().ipv4Dst(IPv4Address.of(ip4.toInt()));
+ break;
+ case IPV6_SRC:
+ ip = (ModIPInstruction) i;
+ ip6 = ip.ip().getIp6Address();
+ oxm = factory().oxms().ipv6Src(IPv6Address.of(ip6.toOctets()));
+ break;
+ case IPV6_DST:
+ ip = (ModIPInstruction) i;
+ ip6 = ip.ip().getIp6Address();
+ oxm = factory().oxms().ipv6Dst(IPv6Address.of(ip6.toOctets()));
+ break;
+ case IPV6_FLABEL:
+ ModIPv6FlowLabelInstruction flowLabelInstruction =
+ (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 OFAction buildL4Modification(Instruction i) {
+ L4ModificationInstruction l4m = (L4ModificationInstruction) i;
+ ModTransportPortInstruction tp;
+ OFOxm<?> oxm = null;
+ switch (l4m.subtype()) {
+ case TCP_SRC:
+ tp = (ModTransportPortInstruction) l4m;
+ oxm = factory().oxms().tcpSrc(TransportPort.of(tp.port().toInt()));
+ break;
+ case TCP_DST:
+ tp = (ModTransportPortInstruction) l4m;
+ oxm = factory().oxms().tcpDst(TransportPort.of(tp.port().toInt()));
+ break;
+ case UDP_SRC:
+ tp = (ModTransportPortInstruction) l4m;
+ oxm = factory().oxms().udpSrc(TransportPort.of(tp.port().toInt()));
+ break;
+ case UDP_DST:
+ tp = (ModTransportPortInstruction) l4m;
+ oxm = factory().oxms().udpDst(TransportPort.of(tp.port().toInt()));
+ break;
+ default:
+ log.warn("Unimplemented action type {}.", l4m.subtype());
+ break;
+ }
+
+ if (oxm != null) {
+ return factory().actions().buildSetField().setField(oxm).build();
+ }
+ return null;
+ }
+
+}
diff --git a/framework/src/onos/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/FlowStatsCollector.java b/framework/src/onos/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/FlowStatsCollector.java
new file mode 100644
index 00000000..c4c81afa
--- /dev/null
+++ b/framework/src/onos/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/FlowStatsCollector.java
@@ -0,0 +1,100 @@
+/*
+ * Copyright 2014 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.flow.impl;
+
+import org.onlab.util.SharedExecutors;
+import org.onosproject.openflow.controller.OpenFlowSwitch;
+import org.onosproject.openflow.controller.RoleState;
+import org.projectfloodlight.openflow.protocol.OFFlowStatsRequest;
+import org.projectfloodlight.openflow.types.OFPort;
+import org.projectfloodlight.openflow.types.TableId;
+import org.slf4j.Logger;
+
+import java.util.Timer;
+import java.util.TimerTask;
+
+import static org.slf4j.LoggerFactory.getLogger;
+
+/**
+ * Collects flow statistics for the specified switch.
+ */
+class FlowStatsCollector {
+
+ private final Logger log = getLogger(getClass());
+
+ public static final int SECONDS = 1000;
+
+ private final OpenFlowSwitch sw;
+ private Timer timer;
+ private TimerTask task;
+
+ private int pollInterval;
+
+ /**
+ * Creates a new collector for the given switch and poll frequency.
+ *
+ * @param timer timer to use for scheduling
+ * @param sw switch to pull
+ * @param pollInterval poll frequency in seconds
+ */
+ FlowStatsCollector(Timer timer, OpenFlowSwitch sw, int pollInterval) {
+ this.timer = timer;
+ this.sw = sw;
+ this.pollInterval = pollInterval;
+ }
+
+ /**
+ * Adjusts poll frequency.
+ *
+ * @param pollInterval poll frequency in seconds
+ */
+ synchronized void adjustPollInterval(int pollInterval) {
+ this.pollInterval = pollInterval;
+ task.cancel();
+ task = new InternalTimerTask();
+ timer.scheduleAtFixedRate(task, pollInterval * SECONDS, pollInterval * 1000);
+ }
+
+ private class InternalTimerTask extends TimerTask {
+ @Override
+ public void run() {
+ if (sw.getRole() == RoleState.MASTER) {
+ log.trace("Collecting stats for {}", sw.getStringId());
+ OFFlowStatsRequest request = sw.factory().buildFlowStatsRequest()
+ .setMatch(sw.factory().matchWildcardAll())
+ .setTableId(TableId.ALL)
+ .setOutPort(OFPort.NO_MASK)
+ .build();
+ sw.sendMsg(request);
+ }
+ }
+ }
+
+ public synchronized void start() {
+ // Initially start polling quickly. Then drop down to configured value
+ log.debug("Starting Stats collection thread for {}", sw.getStringId());
+ task = new InternalTimerTask();
+ SharedExecutors.getTimer().scheduleAtFixedRate(task, 1 * SECONDS,
+ pollInterval * SECONDS);
+ }
+
+ public synchronized void stop() {
+ log.debug("Stopping Stats collection thread for {}", sw.getStringId());
+ task.cancel();
+ task = null;
+ }
+
+}
diff --git a/framework/src/onos/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/NoMappingFoundException.java b/framework/src/onos/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/NoMappingFoundException.java
new file mode 100644
index 00000000..898b286d
--- /dev/null
+++ b/framework/src/onos/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/NoMappingFoundException.java
@@ -0,0 +1,31 @@
+/*
+ * 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.flow.impl;
+
+/**
+ * Thrown to indicate that no mapping for the input value is found.
+ */
+public class NoMappingFoundException extends RuntimeException {
+ /**
+ * Creates an instance with the specified values.
+ *
+ * @param input input value of mapping causing this exception
+ * @param output the desired class which the input value is mapped to
+ */
+ public NoMappingFoundException(Object input, Class<?> output) {
+ super(String.format("No mapping found for %s when converting to %s", input, output.getName()));
+ }
+}
diff --git a/framework/src/onos/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/OpenFlowRuleProvider.java b/framework/src/onos/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/OpenFlowRuleProvider.java
new file mode 100644
index 00000000..de079e03
--- /dev/null
+++ b/framework/src/onos/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/OpenFlowRuleProvider.java
@@ -0,0 +1,453 @@
+/*
+ * Copyright 2014 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.flow.impl;
+
+import com.google.common.cache.Cache;
+import com.google.common.cache.CacheBuilder;
+import com.google.common.cache.RemovalCause;
+import com.google.common.cache.RemovalNotification;
+import com.google.common.collect.Maps;
+import com.google.common.collect.Sets;
+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.Modified;
+import org.apache.felix.scr.annotations.Property;
+import org.apache.felix.scr.annotations.Reference;
+import org.apache.felix.scr.annotations.ReferenceCardinality;
+import org.onosproject.cfg.ComponentConfigService;
+import org.onosproject.core.ApplicationId;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.flow.CompletedBatchOperation;
+import org.onosproject.net.flow.FlowEntry;
+import org.onosproject.net.flow.FlowRule;
+import org.onosproject.net.flow.FlowRuleBatchEntry;
+import org.onosproject.net.flow.FlowRuleBatchOperation;
+import org.onosproject.net.flow.FlowRuleExtPayLoad;
+import org.onosproject.net.flow.FlowRuleProvider;
+import org.onosproject.net.flow.FlowRuleProviderRegistry;
+import org.onosproject.net.flow.FlowRuleProviderService;
+import org.onosproject.net.provider.AbstractProvider;
+import org.onosproject.net.provider.ProviderId;
+import org.onosproject.net.statistic.DefaultLoad;
+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.onosproject.openflow.controller.ThirdPartyMessage;
+import org.osgi.service.component.ComponentContext;
+import org.projectfloodlight.openflow.protocol.OFBadRequestCode;
+import org.projectfloodlight.openflow.protocol.OFBarrierRequest;
+import org.projectfloodlight.openflow.protocol.OFErrorMsg;
+import org.projectfloodlight.openflow.protocol.OFErrorType;
+import org.projectfloodlight.openflow.protocol.OFFlowMod;
+import org.projectfloodlight.openflow.protocol.OFFlowRemoved;
+import org.projectfloodlight.openflow.protocol.OFFlowStatsReply;
+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.errormsg.OFBadRequestErrorMsg;
+import org.projectfloodlight.openflow.protocol.errormsg.OFFlowModFailedErrorMsg;
+import org.slf4j.Logger;
+
+import java.util.Collections;
+import java.util.Dictionary;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import java.util.Set;
+import java.util.Timer;
+import java.util.concurrent.TimeUnit;
+import java.util.stream.Collectors;
+
+import static com.google.common.base.Strings.isNullOrEmpty;
+import static org.onlab.util.Tools.get;
+import static org.slf4j.LoggerFactory.getLogger;
+
+/**
+ * Provider which uses an OpenFlow controller to detect network end-station
+ * hosts.
+ */
+@Component(immediate = true)
+public class OpenFlowRuleProvider extends AbstractProvider
+ implements FlowRuleProvider {
+
+ private final Logger log = getLogger(getClass());
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected FlowRuleProviderRegistry providerRegistry;
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected OpenFlowController controller;
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected ComponentConfigService cfgService;
+
+ private static final int DEFAULT_POLL_FREQUENCY = 10;
+ @Property(name = "flowPollFrequency", intValue = DEFAULT_POLL_FREQUENCY,
+ label = "Frequency (in seconds) for polling flow statistics")
+ private int flowPollFrequency = DEFAULT_POLL_FREQUENCY;
+
+ private FlowRuleProviderService providerService;
+
+ private final InternalFlowProvider listener = new InternalFlowProvider();
+
+ private Cache<Long, InternalCacheEntry> pendingBatches;
+
+ private final Timer timer = new Timer("onos-openflow-collector");
+ private final Map<Dpid, FlowStatsCollector> collectors = Maps.newHashMap();
+
+ /**
+ * Creates an OpenFlow host provider.
+ */
+ public OpenFlowRuleProvider() {
+ super(new ProviderId("of", "org.onosproject.provider.openflow"));
+ }
+
+ @Activate
+ public void activate(ComponentContext context) {
+ cfgService.registerProperties(getClass());
+ providerService = providerRegistry.register(this);
+ controller.addListener(listener);
+ controller.addEventListener(listener);
+
+ pendingBatches = createBatchCache();
+ createCollectors();
+
+ log.info("Started");
+ }
+
+ @Deactivate
+ public void deactivate(ComponentContext context) {
+ cfgService.unregisterProperties(getClass(), false);
+ stopCollectors();
+ providerRegistry.unregister(this);
+ providerService = null;
+
+ log.info("Stopped");
+ }
+
+ @Modified
+ public void modified(ComponentContext context) {
+ Dictionary<?, ?> properties = context.getProperties();
+ int newFlowPollFrequency;
+ try {
+ String s = get(properties, "flowPollFrequency");
+ newFlowPollFrequency = isNullOrEmpty(s) ? flowPollFrequency : Integer.parseInt(s.trim());
+
+ } catch (NumberFormatException | ClassCastException e) {
+ newFlowPollFrequency = flowPollFrequency;
+ }
+
+ if (newFlowPollFrequency != flowPollFrequency) {
+ flowPollFrequency = newFlowPollFrequency;
+ adjustRate();
+ }
+
+ log.info("Settings: flowPollFrequency={}", flowPollFrequency);
+ }
+
+ private Cache<Long, InternalCacheEntry> createBatchCache() {
+ return CacheBuilder.newBuilder()
+ .expireAfterWrite(10, TimeUnit.SECONDS)
+ .removalListener((RemovalNotification<Long, InternalCacheEntry> notification) -> {
+ if (notification.getCause() == RemovalCause.EXPIRED) {
+ providerService.batchOperationCompleted(notification.getKey(),
+ notification.getValue().failedCompletion());
+ }
+ }).build();
+ }
+
+ private void createCollectors() {
+ controller.getSwitches().forEach(this::createCollector);
+ }
+
+ private void createCollector(OpenFlowSwitch sw) {
+ FlowStatsCollector fsc = new FlowStatsCollector(timer, sw, flowPollFrequency);
+ fsc.start();
+ collectors.put(new Dpid(sw.getId()), fsc);
+ }
+
+ private void stopCollectors() {
+ collectors.values().forEach(FlowStatsCollector::stop);
+ collectors.clear();
+ }
+
+ private void adjustRate() {
+ DefaultLoad.setPollInterval(flowPollFrequency);
+ collectors.values().forEach(fsc -> fsc.adjustPollInterval(flowPollFrequency));
+ }
+
+ @Override
+ public void applyFlowRule(FlowRule... flowRules) {
+ for (FlowRule flowRule : flowRules) {
+ applyRule(flowRule);
+ }
+ }
+
+ private void applyRule(FlowRule flowRule) {
+ OpenFlowSwitch sw = controller.getSwitch(Dpid.dpid(flowRule.deviceId()
+ .uri()));
+ FlowRuleExtPayLoad flowRuleExtPayLoad = flowRule.payLoad();
+ if (hasPayload(flowRuleExtPayLoad)) {
+ OFMessage msg = new ThirdPartyMessage(flowRuleExtPayLoad.payLoad());
+ sw.sendMsg(msg);
+ return;
+ }
+ sw.sendMsg(FlowModBuilder.builder(flowRule, sw.factory(),
+ Optional.empty()).buildFlowAdd());
+ }
+
+ @Override
+ public void removeFlowRule(FlowRule... flowRules) {
+ for (FlowRule flowRule : flowRules) {
+ removeRule(flowRule);
+ }
+ }
+
+ private void removeRule(FlowRule flowRule) {
+ OpenFlowSwitch sw = controller.getSwitch(Dpid.dpid(flowRule.deviceId()
+ .uri()));
+ FlowRuleExtPayLoad flowRuleExtPayLoad = flowRule.payLoad();
+ if (hasPayload(flowRuleExtPayLoad)) {
+ OFMessage msg = new ThirdPartyMessage(flowRuleExtPayLoad.payLoad());
+ sw.sendMsg(msg);
+ return;
+ }
+ sw.sendMsg(FlowModBuilder.builder(flowRule, sw.factory(),
+ Optional.empty()).buildFlowDel());
+ }
+
+ @Override
+ public void removeRulesById(ApplicationId id, FlowRule... flowRules) {
+ // TODO: optimize using the ApplicationId
+ removeFlowRule(flowRules);
+ }
+
+ @Override
+ public void executeBatch(FlowRuleBatchOperation batch) {
+
+ pendingBatches.put(batch.id(), new InternalCacheEntry(batch));
+
+ OpenFlowSwitch sw = controller.getSwitch(Dpid.dpid(batch.deviceId()
+ .uri()));
+ OFFlowMod mod;
+ for (FlowRuleBatchEntry fbe : batch.getOperations()) {
+ // flow is the third party privacy flow
+
+ FlowRuleExtPayLoad flowRuleExtPayLoad = fbe.target().payLoad();
+ if (hasPayload(flowRuleExtPayLoad)) {
+ OFMessage msg = new ThirdPartyMessage(flowRuleExtPayLoad.payLoad());
+ sw.sendMsg(msg);
+ continue;
+ }
+ FlowModBuilder builder = FlowModBuilder.builder(fbe.target(), sw
+ .factory(), Optional.of(batch.id()));
+ switch (fbe.operator()) {
+ case ADD:
+ mod = builder.buildFlowAdd();
+ break;
+ case REMOVE:
+ mod = builder.buildFlowDel();
+ break;
+ case MODIFY:
+ mod = builder.buildFlowMod();
+ break;
+ default:
+ log.error("Unsupported batch operation {}; skipping flowmod {}",
+ fbe.operator(), fbe);
+ continue;
+ }
+ sw.sendMsg(mod);
+ }
+ OFBarrierRequest.Builder builder = sw.factory().buildBarrierRequest()
+ .setXid(batch.id());
+ sw.sendMsg(builder.build());
+ }
+
+ private boolean hasPayload(FlowRuleExtPayLoad flowRuleExtPayLoad) {
+ return flowRuleExtPayLoad != null &&
+ flowRuleExtPayLoad.payLoad() != null &&
+ flowRuleExtPayLoad.payLoad().length > 0;
+ }
+
+ private class InternalFlowProvider
+ implements OpenFlowSwitchListener, OpenFlowEventListener {
+
+ @Override
+ public void switchAdded(Dpid dpid) {
+ createCollector(controller.getSwitch(dpid));
+ }
+
+ @Override
+ public void switchRemoved(Dpid dpid) {
+ FlowStatsCollector collector = collectors.remove(dpid);
+ if (collector != null) {
+ collector.stop();
+ }
+ }
+
+ @Override
+ public void switchChanged(Dpid dpid) {
+ }
+
+ @Override
+ public void portChanged(Dpid dpid, OFPortStatus status) {
+ // TODO: Decide whether to evict flows internal store.
+ }
+
+ @Override
+ public void handleMessage(Dpid dpid, OFMessage msg) {
+ OpenFlowSwitch sw = controller.getSwitch(dpid);
+ switch (msg.getType()) {
+ case FLOW_REMOVED:
+ OFFlowRemoved removed = (OFFlowRemoved) msg;
+
+ FlowEntry fr = new FlowEntryBuilder(dpid, removed).build();
+ providerService.flowRemoved(fr);
+ break;
+ case STATS_REPLY:
+ if (((OFStatsReply) msg).getStatsType() == OFStatsType.FLOW) {
+ pushFlowMetrics(dpid, (OFFlowStatsReply) msg);
+ }
+ break;
+ case BARRIER_REPLY:
+ try {
+ InternalCacheEntry entry = pendingBatches.getIfPresent(msg.getXid());
+ if (entry != null) {
+ providerService
+ .batchOperationCompleted(msg.getXid(),
+ entry.completed());
+ } else {
+ log.warn("Received unknown Barrier Reply: {}",
+ msg.getXid());
+ }
+ } finally {
+ pendingBatches.invalidate(msg.getXid());
+ }
+ break;
+ case ERROR:
+ // TODO: This needs to get suppressed in a better way.
+ if (msg instanceof OFBadRequestErrorMsg &&
+ ((OFBadRequestErrorMsg) msg).getCode() == OFBadRequestCode.BAD_TYPE) {
+ log.debug("Received error message {} from {}", msg, dpid);
+ } else {
+ log.warn("Received error message {} from {}", msg, dpid);
+ }
+
+ OFErrorMsg error = (OFErrorMsg) msg;
+ if (error.getErrType() == OFErrorType.FLOW_MOD_FAILED) {
+ OFFlowModFailedErrorMsg fmFailed = (OFFlowModFailedErrorMsg) error;
+ if (fmFailed.getData().getParsedMessage().isPresent()) {
+ OFMessage m = fmFailed.getData().getParsedMessage().get();
+ OFFlowMod fm = (OFFlowMod) m;
+ InternalCacheEntry entry =
+ pendingBatches.getIfPresent(msg.getXid());
+ if (entry != null) {
+ entry.appendFailure(new FlowEntryBuilder(dpid, fm).build());
+ } else {
+ log.error("No matching batch for this error: {}", error);
+ }
+ } else {
+ // FIXME: Potentially add flowtracking to avoid this message.
+ log.error("Flow installation failed but switch didn't"
+ + " tell us which one.");
+ }
+ }
+ break;
+ default:
+ log.debug("Unhandled message type: {}", msg.getType());
+ }
+
+ }
+
+ @Override
+ public void receivedRoleReply(Dpid dpid, RoleState requested,
+ RoleState response) {
+ // Do nothing here for now.
+ }
+
+ private void pushFlowMetrics(Dpid dpid, OFFlowStatsReply replies) {
+
+ DeviceId did = DeviceId.deviceId(Dpid.uri(dpid));
+ OpenFlowSwitch sw = controller.getSwitch(dpid);
+
+ List<FlowEntry> flowEntries = replies.getEntries().stream()
+ .map(entry -> new FlowEntryBuilder(dpid, entry).build())
+ .collect(Collectors.toList());
+
+ providerService.pushFlowMetrics(did, flowEntries);
+ }
+ }
+
+ /**
+ * The internal cache entry holding the original request as well as
+ * accumulating the any failures along the way.
+ * <p/>
+ * If this entry is evicted from the cache then the entire operation is
+ * considered failed. Otherwise, only the failures reported by the device
+ * will be propagated up.
+ */
+ private class InternalCacheEntry {
+
+ private final FlowRuleBatchOperation operation;
+ private final Set<FlowRule> failures = Sets.newConcurrentHashSet();
+
+ public InternalCacheEntry(FlowRuleBatchOperation operation) {
+ this.operation = operation;
+ }
+
+ /**
+ * Appends a failed rule to the set of failed items.
+ *
+ * @param rule the failed rule
+ */
+ public void appendFailure(FlowRule rule) {
+ failures.add(rule);
+ }
+
+ /**
+ * Fails the entire batch and returns the failed operation.
+ *
+ * @return the failed operation
+ */
+ public CompletedBatchOperation failedCompletion() {
+ Set<FlowRule> fails = operation.getOperations().stream()
+ .map(op -> op.target()).collect(Collectors.toSet());
+ return new CompletedBatchOperation(false,
+ Collections
+ .unmodifiableSet(fails),
+ operation.deviceId());
+ }
+
+ /**
+ * Returns the completed operation and whether the batch suceeded.
+ *
+ * @return the completed operation
+ */
+ public CompletedBatchOperation completed() {
+ return new CompletedBatchOperation(
+ failures.isEmpty(),
+ Collections
+ .unmodifiableSet(failures),
+ operation.deviceId());
+ }
+ }
+
+}
diff --git a/framework/src/onos/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/OpenFlowValueMapper.java b/framework/src/onos/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/OpenFlowValueMapper.java
new file mode 100644
index 00000000..2f0831c6
--- /dev/null
+++ b/framework/src/onos/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/OpenFlowValueMapper.java
@@ -0,0 +1,152 @@
+/*
+ * 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.flow.impl;
+
+import com.google.common.collect.BiMap;
+import com.google.common.collect.EnumHashBiMap;
+import org.onosproject.net.ChannelSpacing;
+import org.onosproject.net.GridType;
+import org.onosproject.net.OchSignalType;
+
+/**
+ * Collection of helper methods to convert protocol agnostic models to values used in OpenFlow spec.
+ */
+final class OpenFlowValueMapper {
+
+ // prohibit instantiation
+ private OpenFlowValueMapper() {}
+
+ private static final BiMap<GridType, Byte> GRID_TYPES = EnumHashBiMap.create(GridType.class);
+ static {
+ // See ONF "Optical Transport Protocol Extensions Version 1.0" for the following values
+ GRID_TYPES.put(GridType.DWDM, (byte) 1); // OFPGRIDT_DWDM of enum ofp_grid_type
+ GRID_TYPES.put(GridType.CWDM, (byte) 2); // OFPGRIDT_CWDM of enum ofp_grid_type
+ GRID_TYPES.put(GridType.FLEX, (byte) 3); // OFPGRIDT_FLEX of enum ofp_grid_type
+ }
+
+ private static final BiMap<ChannelSpacing, Byte> CHANNEL_SPACING = EnumHashBiMap.create(ChannelSpacing.class);
+ static {
+ // See ONF "Optical Transport Protocol Extensions Version 1.0" for the following values
+ CHANNEL_SPACING.put(ChannelSpacing.CHL_100GHZ, (byte) 1); // OFPCS_100GHZ of enum ofp_chl_spacing
+ CHANNEL_SPACING.put(ChannelSpacing.CHL_50GHZ, (byte) 2); // OFPCS_50GHZ of enum ofp_chl_spacing
+ CHANNEL_SPACING.put(ChannelSpacing.CHL_25GHZ, (byte) 3); // OFPCS_25GHZ of enum ofp_chl_spacing
+ CHANNEL_SPACING.put(ChannelSpacing.CHL_12P5GHZ, (byte) 4); // OFPCS_12P5GHZ of enum ofp_chl_spacing
+ CHANNEL_SPACING.put(ChannelSpacing.CHL_6P25GHZ, (byte) 5); // OFPCS_6P25GHZ of enum ofp_chl_spacing
+ }
+
+ private static final BiMap<OchSignalType, Byte> OCH_SIGNAL_TYPES = EnumHashBiMap.create(OchSignalType.class);
+ static {
+ // See ONF "Optical Transport Protocol Extensions Version 1.0" for the following values
+ OCH_SIGNAL_TYPES.put(OchSignalType.FIXED_GRID, (byte) 1); // OFPOCHT_FIX_GRID of enum ofp_och_signal_type
+ OCH_SIGNAL_TYPES.put(OchSignalType.FLEX_GRID, (byte) 2); // OFPOCHT_FLEX_GRID of enum ofp_och_signal_type
+ }
+
+ /**
+ * Looks up the specified input value to the corresponding value with the specified map.
+ *
+ * @param map bidirectional mapping
+ * @param input input value
+ * @param cls class of output value
+ * @param <I> type of input value
+ * @param <O> type of output value
+ * @return the corresponding value stored in the specified map
+ * @throws NoMappingFoundException if no corresponding value is found
+ */
+ private static <I, O> O lookup(BiMap<I, O> map, I input, Class<O> cls) {
+ if (!map.containsKey(input)) {
+ throw new NoMappingFoundException(input, cls);
+ }
+
+ return map.get(input);
+ }
+
+ /**
+ * Looks up the corresponding byte value defined in
+ * ONF "Optical Transport Protocol Extensions Version 1.0"
+ * from the specified {@link GridType} instance.
+ *
+ * @param type grid type
+ * @return the byte value corresponding to the specified grid type
+ * @throws NoMappingFoundException if the specified grid type is not found
+ */
+ static byte lookupGridType(GridType type) {
+ return lookup(GRID_TYPES, type, Byte.class);
+ }
+
+ /**
+ * Looks up the corresponding {@link GridType} instance
+ * from the specified byte value for grid type
+ * defined in ONF "Optical Transport Protocol Extensions Version 1.0".
+ *
+ * @param type byte value as grid type defined the spec
+ * @return the corresponding GridType instance
+ */
+ static GridType lookupGridType(byte type) {
+ return lookup(GRID_TYPES.inverse(), type, GridType.class);
+ }
+
+ /**
+ * Looks up the corresponding byte value for channel spacing defined in
+ * ONF "Optical Transport Protocol Extensions Version 1.0"
+ * from the specified {@link ChannelSpacing} instance.
+ *
+ * @param spacing channel spacing
+ * @return byte value corresponding to the specified channel spacing
+ * @throws NoMappingFoundException if the specified channel spacing is not found
+ */
+ static byte lookupChannelSpacing(ChannelSpacing spacing) {
+ return lookup(CHANNEL_SPACING, spacing, Byte.class);
+ }
+
+ /**
+ * Looks up the corresponding {@link ChannelSpacing} instance
+ * from the specified byte value for channel spacing
+ * defined in ONF "Optical Transport Protocol Extensions Version 1.0".
+ *
+ * @param spacing byte value as channel spacing defined the spec
+ * @return the corresponding ChannelSpacing instance
+ * @throws NoMappingFoundException if the specified channel spacing is not found
+ */
+ static ChannelSpacing lookupChannelSpacing(byte spacing) {
+ return lookup(CHANNEL_SPACING.inverse(), spacing, ChannelSpacing.class);
+ }
+
+ /**
+ * Looks up the corresponding byte value for Och signal type defined in
+ * ONF "Optical Transport Protocol Extensions Version 1.0"
+ * from the specified {@link OchSignalType} instance.
+ *
+ * @param signalType optical signal type
+ * @return byte value corresponding to the specified OCh signal type
+ * @throws NoMappingFoundException if the specified Och signal type is not found
+ */
+ static byte lookupOchSignalType(OchSignalType signalType) {
+ return lookup(OCH_SIGNAL_TYPES, signalType, Byte.class);
+ }
+
+ /**
+ * Looks up the the corresponding {@link OchSignalType} instance
+ * from the specified byte value for Och signal type defined in
+ * ONF "Optical Transport Protocol Extensions Version 1.0".
+ *
+ * @param signalType byte value as Och singal type defined the spec
+ * @return the corresponding OchSignalType instance
+ * @throws NoMappingFoundException if the specified Och signal type is not found
+ */
+ static OchSignalType lookupOchSignalType(byte signalType) {
+ return lookup(OCH_SIGNAL_TYPES.inverse(), signalType, OchSignalType.class);
+ }
+}
diff --git a/framework/src/onos/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/package-info.java b/framework/src/onos/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/package-info.java
new file mode 100644
index 00000000..2acc1510
--- /dev/null
+++ b/framework/src/onos/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/package-info.java
@@ -0,0 +1,20 @@
+/*
+ * Copyright 2014 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 ending and receiving flow information.
+ */
+package org.onosproject.provider.of.flow.impl;
diff --git a/framework/src/onos/providers/openflow/group/pom.xml b/framework/src/onos/providers/openflow/group/pom.xml
new file mode 100644
index 00000000..97ac5ffe
--- /dev/null
+++ b/framework/src/onos/providers/openflow/group/pom.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ 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.
+ -->
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+
+ <parent>
+ <groupId>org.onosproject</groupId>
+ <artifactId>onos-of-providers</artifactId>
+ <version>1.3.0-SNAPSHOT</version>
+ <relativePath>../pom.xml</relativePath>
+ </parent>
+
+ <artifactId>onos-of-provider-group</artifactId>
+ <packaging>bundle</packaging>
+
+ <description>ONOS OpenFlow protocol group provider</description>
+
+</project> \ No newline at end of file
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
diff --git a/framework/src/onos/providers/openflow/group/src/test/java/org/onosproject/provider/of/group/impl/OpenFlowGroupProviderTest.java b/framework/src/onos/providers/openflow/group/src/test/java/org/onosproject/provider/of/group/impl/OpenFlowGroupProviderTest.java
new file mode 100644
index 00000000..d66ba090
--- /dev/null
+++ b/framework/src/onos/providers/openflow/group/src/test/java/org/onosproject/provider/of/group/impl/OpenFlowGroupProviderTest.java
@@ -0,0 +1,397 @@
+package org.onosproject.provider.of.group.impl;
+
+import com.google.common.collect.Lists;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.onosproject.core.DefaultGroupId;
+import org.onosproject.core.GroupId;
+import org.onosproject.net.Device;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.PortNumber;
+import org.onosproject.net.flow.DefaultTrafficTreatment;
+import org.onosproject.net.flow.TrafficTreatment;
+import org.onosproject.net.group.DefaultGroupBucket;
+import org.onosproject.net.group.Group;
+import org.onosproject.net.group.GroupBucket;
+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.provider.AbstractProviderService;
+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.PacketListener;
+import org.onosproject.openflow.controller.RoleState;
+import org.projectfloodlight.openflow.protocol.OFFactories;
+import org.projectfloodlight.openflow.protocol.OFFactory;
+import org.projectfloodlight.openflow.protocol.OFGroupDescStatsReply;
+import org.projectfloodlight.openflow.protocol.OFGroupMod;
+import org.projectfloodlight.openflow.protocol.OFGroupModFailedCode;
+import org.projectfloodlight.openflow.protocol.OFGroupStatsReply;
+import org.projectfloodlight.openflow.protocol.OFGroupType;
+import org.projectfloodlight.openflow.protocol.OFMessage;
+import org.projectfloodlight.openflow.protocol.OFPortDesc;
+import org.projectfloodlight.openflow.protocol.OFVersion;
+import org.projectfloodlight.openflow.protocol.errormsg.OFGroupModFailedErrorMsg;
+import org.projectfloodlight.openflow.types.OFGroup;
+
+import java.util.Collection;
+import java.util.List;
+import java.util.Set;
+
+import static org.junit.Assert.*;
+
+public class OpenFlowGroupProviderTest {
+
+ OpenFlowGroupProvider provider = new OpenFlowGroupProvider();
+ private final OpenFlowController controller = new TestController();
+ GroupProviderRegistry providerRegistry = new TestGroupProviderRegistry();
+ GroupProviderService providerService;
+
+ private DeviceId deviceId = DeviceId.deviceId("of:0000000000000001");
+ private Dpid dpid1 = Dpid.dpid(deviceId.uri());
+
+ @Before
+ public void setUp() {
+ provider.controller = controller;
+ provider.providerRegistry = providerRegistry;
+ provider.activate();
+ }
+
+ @Test
+ public void basics() {
+ assertNotNull("registration expected", providerService);
+ assertEquals("incorrect provider", provider, providerService.provider());
+ }
+
+ @Test
+ public void addGroup() {
+
+ GroupId groupId = new DefaultGroupId(1);
+
+ List<GroupBucket> bucketList = Lists.newArrayList();
+ TrafficTreatment.Builder builder = DefaultTrafficTreatment.builder();
+ builder.setOutput(PortNumber.portNumber(1));
+ GroupBucket bucket =
+ DefaultGroupBucket.createSelectGroupBucket(builder.build());
+ bucketList.add(bucket);
+ GroupBuckets buckets = new GroupBuckets(bucketList);
+
+ List<GroupOperation> operationList = Lists.newArrayList();
+ GroupOperation operation = GroupOperation.createAddGroupOperation(groupId,
+ GroupDescription.Type.SELECT, buckets);
+ operationList.add(operation);
+ GroupOperations operations = new GroupOperations(operationList);
+
+ provider.performGroupOperation(deviceId, operations);
+
+ final Dpid dpid = Dpid.dpid(deviceId.uri());
+ TestOpenFlowSwitch sw = (TestOpenFlowSwitch) controller.getSwitch(dpid);
+ assertNotNull("Switch should not be nul", sw);
+ assertNotNull("OFGroupMsg should not be null", sw.msg);
+
+ }
+
+
+ @Test
+ public void groupModFailure() {
+ TestOpenFlowGroupProviderService testProviderService =
+ (TestOpenFlowGroupProviderService) providerService;
+
+ GroupId groupId = new DefaultGroupId(1);
+ List<GroupBucket> bucketList = Lists.newArrayList();
+ TrafficTreatment.Builder builder = DefaultTrafficTreatment.builder();
+ builder.setOutput(PortNumber.portNumber(1));
+ GroupBucket bucket =
+ DefaultGroupBucket.createSelectGroupBucket(builder.build());
+ bucketList.add(bucket);
+ GroupBuckets buckets = new GroupBuckets(bucketList);
+ List<GroupOperation> operationList = Lists.newArrayList();
+ GroupOperation operation = GroupOperation.createAddGroupOperation(groupId,
+ GroupDescription.Type.SELECT, buckets);
+ operationList.add(operation);
+ GroupOperations operations = new GroupOperations(operationList);
+
+ provider.performGroupOperation(deviceId, operations);
+
+ OFGroupModFailedErrorMsg.Builder errorBuilder =
+ OFFactories.getFactory(OFVersion.OF_13).errorMsgs().buildGroupModFailedErrorMsg();
+ OFGroupMod.Builder groupBuilder = OFFactories.getFactory(OFVersion.OF_13).buildGroupModify();
+ groupBuilder.setGroupType(OFGroupType.ALL);
+ groupBuilder.setGroup(OFGroup.of(1));
+ errorBuilder.setCode(OFGroupModFailedCode.GROUP_EXISTS);
+ errorBuilder.setXid(provider.getXidAndAdd(0) - 1);
+
+ controller.processPacket(dpid1, errorBuilder.build());
+
+ assertNotNull("Operation failed should not be null",
+ testProviderService.failedOperation);
+ }
+
+
+ @Test
+ public void groupStatsEvent() {
+ TestOpenFlowGroupProviderService testProviderService =
+ (TestOpenFlowGroupProviderService) providerService;
+
+ OFGroupStatsReply.Builder rep1 =
+ OFFactories.getFactory(OFVersion.OF_13).buildGroupStatsReply();
+ rep1.setXid(1);
+ controller.processPacket(dpid1, rep1.build());
+ OFGroupDescStatsReply.Builder rep2 =
+ OFFactories.getFactory(OFVersion.OF_13).buildGroupDescStatsReply();
+ assertNull("group entries is not set yet", testProviderService.getGroupEntries());
+
+ rep2.setXid(2);
+ controller.processPacket(dpid1, rep2.build());
+ assertNotNull("group entries should be set", testProviderService.getGroupEntries());
+ }
+
+
+
+ @After
+ public void tearDown() {
+ provider.deactivate();
+ provider.providerRegistry = null;
+ provider.controller = null;
+ }
+
+ private class TestOpenFlowGroupProviderService
+ extends AbstractProviderService<GroupProvider>
+ implements GroupProviderService {
+
+ Collection<Group> groups = null;
+ GroupOperation failedOperation = null;
+
+ protected TestOpenFlowGroupProviderService(GroupProvider provider) {
+ super(provider);
+ }
+
+ @Override
+ public void groupOperationFailed(DeviceId deviceId, GroupOperation operation) {
+ this.failedOperation = operation;
+ }
+
+ @Override
+ public void pushGroupMetrics(DeviceId deviceId, Collection<Group> groupEntries) {
+ this.groups = groupEntries;
+ }
+
+ public Collection<Group> getGroupEntries() {
+ return groups;
+ }
+ }
+
+ private class TestController implements OpenFlowController {
+
+ OpenFlowEventListener eventListener = null;
+ List<OpenFlowSwitch> switches = Lists.newArrayList();
+
+ public TestController() {
+ OpenFlowSwitch testSwitch = new TestOpenFlowSwitch();
+ switches.add(testSwitch);
+ }
+
+ @Override
+ public void addListener(OpenFlowSwitchListener listener) {
+ }
+
+ @Override
+ public void removeListener(OpenFlowSwitchListener listener) {
+
+ }
+
+ @Override
+ public void addPacketListener(int priority, PacketListener listener) {
+
+ }
+
+ @Override
+ public void removePacketListener(PacketListener listener) {
+
+ }
+
+ @Override
+ public void addEventListener(OpenFlowEventListener listener) {
+ this.eventListener = listener;
+ }
+
+ @Override
+ public void removeEventListener(OpenFlowEventListener listener) {
+
+ }
+
+ @Override
+ public void write(Dpid dpid, OFMessage msg) {
+
+ }
+
+ @Override
+ public void processPacket(Dpid dpid, OFMessage msg) {
+ eventListener.handleMessage(dpid, msg);
+ }
+
+ @Override
+ public void setRole(Dpid dpid, RoleState role) {
+
+ }
+
+ @Override
+ public Iterable<OpenFlowSwitch> getSwitches() {
+ return switches;
+ }
+
+ @Override
+ public Iterable<OpenFlowSwitch> getMasterSwitches() {
+ return null;
+ }
+
+ @Override
+ public Iterable<OpenFlowSwitch> getEqualSwitches() {
+ return null;
+ }
+
+ @Override
+ public OpenFlowSwitch getSwitch(Dpid dpid) {
+ return switches.get(0);
+ }
+
+ @Override
+ public OpenFlowSwitch getMasterSwitch(Dpid dpid) {
+ return null;
+ }
+
+ @Override
+ public OpenFlowSwitch getEqualSwitch(Dpid dpid) {
+ return null;
+ }
+
+ }
+
+ private class TestGroupProviderRegistry implements GroupProviderRegistry {
+
+ @Override
+ public GroupProviderService register(GroupProvider provider) {
+ providerService = new TestOpenFlowGroupProviderService(provider);
+ return providerService;
+ }
+
+ @Override
+ public void unregister(GroupProvider provider) {
+ }
+
+ @Override
+ public Set<ProviderId> getProviders() {
+ return null;
+ }
+ }
+
+ private class TestOpenFlowSwitch implements OpenFlowSwitch {
+
+ OFMessage msg = null;
+
+ @Override
+ public void sendMsg(OFMessage msg) {
+ this.msg = msg;
+ }
+
+ @Override
+ public void sendMsg(List<OFMessage> msgs) {
+
+ }
+
+ @Override
+ public void handleMessage(OFMessage fromSwitch) {
+
+ }
+
+ @Override
+ public void setRole(RoleState role) {
+
+ }
+
+ @Override
+ public RoleState getRole() {
+ return null;
+ }
+
+ @Override
+ public List<OFPortDesc> getPorts() {
+ return null;
+ }
+
+ @Override
+ public OFFactory factory() {
+ return OFFactories.getFactory(OFVersion.OF_13);
+ }
+
+ @Override
+ public String getStringId() {
+ return null;
+ }
+
+ @Override
+ public long getId() {
+ return 0;
+ }
+
+ @Override
+ public String manufacturerDescription() {
+ return null;
+ }
+
+ @Override
+ public String datapathDescription() {
+ return null;
+ }
+
+ @Override
+ public String hardwareDescription() {
+ return null;
+ }
+
+ @Override
+ public String softwareDescription() {
+ return null;
+ }
+
+ @Override
+ public String serialNumber() {
+ return null;
+ }
+
+ @Override
+ public boolean isConnected() {
+ return false;
+ }
+
+ @Override
+ public void disconnectSwitch() {
+
+ }
+
+ @Override
+ public void returnRoleReply(RoleState requested, RoleState response) {
+
+ }
+
+ @Override
+ public Device.Type deviceType() {
+ return Device.Type.SWITCH;
+ }
+
+ @Override
+ public String channelId() {
+ return null;
+ }
+
+ }
+} \ No newline at end of file
diff --git a/framework/src/onos/providers/openflow/meter/pom.xml b/framework/src/onos/providers/openflow/meter/pom.xml
new file mode 100644
index 00000000..9de5c1b0
--- /dev/null
+++ b/framework/src/onos/providers/openflow/meter/pom.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ 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.
+ -->
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+
+ <parent>
+ <groupId>org.onosproject</groupId>
+ <artifactId>onos-of-providers</artifactId>
+ <version>1.3.0-SNAPSHOT</version>
+ <relativePath>../pom.xml</relativePath>
+ </parent>
+
+ <artifactId>onos-of-provider-meter</artifactId>
+ <packaging>bundle</packaging>
+
+ <description>ONOS OpenFlow protocol meter provider</description>
+
+</project> \ No newline at end of file
diff --git a/framework/src/onos/providers/openflow/meter/src/main/java/org/onosproject/provider/of/meter/impl/MeterModBuilder.java b/framework/src/onos/providers/openflow/meter/src/main/java/org/onosproject/provider/of/meter/impl/MeterModBuilder.java
new file mode 100644
index 00000000..c07354b6
--- /dev/null
+++ b/framework/src/onos/providers/openflow/meter/src/main/java/org/onosproject/provider/of/meter/impl/MeterModBuilder.java
@@ -0,0 +1,159 @@
+/*
+ * 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.meter.impl;
+
+import org.onosproject.net.meter.Band;
+import org.onosproject.net.meter.Meter;
+import org.onosproject.net.meter.MeterId;
+import org.projectfloodlight.openflow.protocol.OFFactory;
+import org.projectfloodlight.openflow.protocol.OFMeterFlags;
+import org.projectfloodlight.openflow.protocol.OFMeterMod;
+import org.projectfloodlight.openflow.protocol.OFMeterModCommand;
+import org.projectfloodlight.openflow.protocol.meterband.OFMeterBand;
+import org.projectfloodlight.openflow.protocol.meterband.OFMeterBandDrop;
+import org.projectfloodlight.openflow.protocol.meterband.OFMeterBandDscpRemark;
+import org.slf4j.Logger;
+
+import java.util.Collection;
+import java.util.List;
+import java.util.stream.Collectors;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
+import static org.slf4j.LoggerFactory.getLogger;
+
+/**
+ * Builder for a meter modification.
+ */
+public final class MeterModBuilder {
+
+ private final Logger log = getLogger(getClass());
+
+ private final long xid;
+ private final OFFactory factory;
+ private Meter.Unit unit = Meter.Unit.KB_PER_SEC;
+ private boolean burst = false;
+ private Long id;
+ private Collection<Band> bands;
+
+ public MeterModBuilder(long xid, OFFactory factory) {
+ this.xid = xid;
+ this.factory = factory;
+ }
+
+ public static MeterModBuilder builder(long xid, OFFactory factory) {
+ return new MeterModBuilder(xid, factory);
+ }
+
+ public MeterModBuilder withRateUnit(Meter.Unit unit) {
+ this.unit = unit;
+ return this;
+ }
+
+ public MeterModBuilder burst() {
+ this.burst = true;
+ return this;
+ }
+
+ public MeterModBuilder withId(MeterId meterId) {
+ this.id = meterId.id();
+ return this;
+ }
+
+ public MeterModBuilder withBands(Collection<Band> bands) {
+ this.bands = bands;
+ return this;
+ }
+
+ public OFMeterMod add() {
+ validate();
+ OFMeterMod.Builder builder = builderMeterMod();
+ builder.setCommand(OFMeterModCommand.ADD.ordinal());
+ return builder.build();
+ }
+
+ public OFMeterMod remove() {
+ validate();
+ OFMeterMod.Builder builder = builderMeterMod();
+ builder.setCommand(OFMeterModCommand.DELETE.ordinal());
+ return builder.build();
+ }
+
+ public OFMeterMod modify() {
+ validate();
+ OFMeterMod.Builder builder = builderMeterMod();
+ builder.setCommand(OFMeterModCommand.MODIFY.ordinal());
+ return builder.build();
+ }
+
+ private OFMeterMod.Builder builderMeterMod() {
+ OFMeterMod.Builder builder = factory.buildMeterMod();
+ int flags = 0;
+ if (burst) {
+ // covering loxi short comings.
+ flags |= 1 << OFMeterFlags.BURST.ordinal();
+ }
+ switch (unit) {
+ case PKTS_PER_SEC:
+ flags |= 1 << OFMeterFlags.PKTPS.ordinal();
+ break;
+ case KB_PER_SEC:
+ flags |= 1 << OFMeterFlags.KBPS.ordinal();
+ break;
+ default:
+ log.warn("Unknown unit type {}", unit);
+ }
+ //FIXME: THIS WILL CHANGE IN OF1.4 to setBands.
+ builder.setMeters(buildBands());
+ builder.setFlags(flags)
+ .setMeterId(id)
+ .setXid(xid);
+ return builder;
+ }
+
+ private List<OFMeterBand> buildBands() {
+ return bands.stream().map(b -> {
+ switch (b.type()) {
+ case DROP:
+ OFMeterBandDrop.Builder dropBuilder =
+ factory.meterBands().buildDrop();
+ if (burst) {
+ dropBuilder.setBurstSize(b.burst());
+ }
+ dropBuilder.setRate(b.rate());
+ return dropBuilder.build();
+ case REMARK:
+ OFMeterBandDscpRemark.Builder remarkBand =
+ factory.meterBands().buildDscpRemark();
+ if (burst) {
+ remarkBand.setBurstSize(b.burst());
+ }
+ remarkBand.setRate(b.rate());
+ remarkBand.setPrecLevel(b.dropPrecedence());
+ return remarkBand.build();
+ default:
+ log.warn("Unknown band type {}", b.type());
+ return null;
+ }
+ }).filter(value -> value != null).collect(Collectors.toList());
+ }
+
+ private void validate() {
+ checkNotNull(id, "id cannot be null");
+ checkNotNull(bands, "Must have bands");
+ checkArgument(bands.size() > 0, "Must have at lease one band");
+ }
+}
diff --git a/framework/src/onos/providers/openflow/meter/src/main/java/org/onosproject/provider/of/meter/impl/MeterStatsCollector.java b/framework/src/onos/providers/openflow/meter/src/main/java/org/onosproject/provider/of/meter/impl/MeterStatsCollector.java
new file mode 100644
index 00000000..83dc6458
--- /dev/null
+++ b/framework/src/onos/providers/openflow/meter/src/main/java/org/onosproject/provider/of/meter/impl/MeterStatsCollector.java
@@ -0,0 +1,103 @@
+/*
+ * 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.meter.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.OFMeterStatsRequest;
+import org.slf4j.Logger;
+
+import java.util.concurrent.TimeUnit;
+
+import static org.slf4j.LoggerFactory.getLogger;
+
+/*
+ * Sends Meter Stats Request and collect the Meter statistics with a time interval.
+ */
+public class MeterStatsCollector 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 MeterStatsCollector(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());
+
+ sendMeterStatistic();
+
+ 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 sendMeterStatistic() {
+ if (log.isTraceEnabled()) {
+ log.trace("sendMeterStatistics {}:{}", sw.getStringId(), sw.getRole());
+ }
+ if (sw.getRole() != RoleState.MASTER) {
+ return;
+ }
+
+ OFMeterStatsRequest.Builder builder =
+ sw.factory().buildMeterStatsRequest();
+ builder.setXid(0).setMeterId(0xFFFFFFFF);
+
+ sw.sendMsg(builder.build());
+
+ }
+
+ /**
+ * Starts the collector.
+ */
+ public void start() {
+ log.info("Starting Meter Stats collection thread for {}", sw.getStringId());
+ timeout = timer.newTimeout(this, 1, TimeUnit.SECONDS);
+ }
+
+ /**
+ * Stops the collector.
+ */
+ public void stop() {
+ log.info("Stopping Meter Stats collection thread for {}", sw.getStringId());
+ this.stopTimer = true;
+ timeout.cancel();
+ }
+}
diff --git a/framework/src/onos/providers/openflow/meter/src/main/java/org/onosproject/provider/of/meter/impl/OpenFlowMeterProvider.java b/framework/src/onos/providers/openflow/meter/src/main/java/org/onosproject/provider/of/meter/impl/OpenFlowMeterProvider.java
new file mode 100644
index 00000000..f5a777be
--- /dev/null
+++ b/framework/src/onos/providers/openflow/meter/src/main/java/org/onosproject/provider/of/meter/impl/OpenFlowMeterProvider.java
@@ -0,0 +1,393 @@
+/*
+ * 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.meter.impl;
+
+
+import com.google.common.cache.Cache;
+import com.google.common.cache.CacheBuilder;
+import com.google.common.cache.RemovalCause;
+import com.google.common.cache.RemovalNotification;
+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.CoreService;
+import org.onosproject.net.meter.Band;
+import org.onosproject.net.meter.DefaultBand;
+import org.onosproject.net.meter.DefaultMeter;
+import org.onosproject.net.meter.Meter;
+import org.onosproject.net.meter.MeterFailReason;
+import org.onosproject.net.meter.MeterId;
+import org.onosproject.net.meter.MeterOperation;
+import org.onosproject.net.meter.MeterOperations;
+import org.onosproject.net.meter.MeterProvider;
+import org.onosproject.net.meter.MeterProviderRegistry;
+import org.onosproject.net.meter.MeterProviderService;
+import org.onosproject.net.meter.MeterState;
+import org.onosproject.net.DeviceId;
+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.OFErrorMsg;
+import org.projectfloodlight.openflow.protocol.OFErrorType;
+import org.projectfloodlight.openflow.protocol.OFMessage;
+import org.projectfloodlight.openflow.protocol.OFMeterBandStats;
+import org.projectfloodlight.openflow.protocol.OFMeterConfigStatsReply;
+import org.projectfloodlight.openflow.protocol.OFMeterStats;
+import org.projectfloodlight.openflow.protocol.OFMeterStatsReply;
+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.projectfloodlight.openflow.protocol.errormsg.OFMeterModFailedErrorMsg;
+import org.slf4j.Logger;
+
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicLong;
+import java.util.stream.Collectors;
+
+import static org.slf4j.LoggerFactory.getLogger;
+
+/**
+ * Provider which uses an OpenFlow controller to handle meters.
+ */
+@Component(immediate = true, enabled = true)
+public class OpenFlowMeterProvider extends AbstractProvider implements MeterProvider {
+
+
+ private final Logger log = getLogger(getClass());
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected OpenFlowController controller;
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected MeterProviderRegistry providerRegistry;
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected CoreService coreService;
+
+ private MeterProviderService providerService;
+
+ private static final AtomicLong XID_COUNTER = new AtomicLong(1);
+
+ static final int POLL_INTERVAL = 10;
+ static final long TIMEOUT = 30;
+
+ private Cache<Long, MeterOperation> pendingOperations;
+
+
+ private InternalMeterListener listener = new InternalMeterListener();
+ private Map<Dpid, MeterStatsCollector> collectors = Maps.newHashMap();
+
+ /**
+ * Creates a OpenFlow meter provider.
+ */
+ public OpenFlowMeterProvider() {
+ super(new ProviderId("of", "org.onosproject.provider.meter"));
+ }
+
+ @Activate
+ public void activate() {
+ providerService = providerRegistry.register(this);
+
+ pendingOperations = CacheBuilder.newBuilder()
+ .expireAfterWrite(TIMEOUT, TimeUnit.SECONDS)
+ .removalListener((RemovalNotification<Long, MeterOperation> notification) -> {
+ if (notification.getCause() == RemovalCause.EXPIRED) {
+ providerService.meterOperationFailed(notification.getValue(),
+ MeterFailReason.TIMEOUT);
+ }
+ }).build();
+
+ controller.addEventListener(listener);
+ controller.addListener(listener);
+
+ controller.getSwitches().forEach((sw -> createStatsCollection(sw)));
+ }
+
+ @Deactivate
+ public void deactivate() {
+ providerRegistry.unregister(this);
+ controller.removeEventListener(listener);
+ controller.removeListener(listener);
+ providerService = null;
+ }
+
+ @Override
+ public void performMeterOperation(DeviceId deviceId, MeterOperations meterOps) {
+ Dpid dpid = Dpid.dpid(deviceId.uri());
+ OpenFlowSwitch sw = controller.getSwitch(dpid);
+ if (sw == null) {
+ log.error("Unknown device {}", deviceId);
+ meterOps.operations().forEach(op ->
+ providerService.meterOperationFailed(op,
+ MeterFailReason.UNKNOWN_DEVICE)
+ );
+ return;
+ }
+
+ meterOps.operations().forEach(op -> performOperation(sw, op));
+ }
+
+ @Override
+ public void performMeterOperation(DeviceId deviceId, MeterOperation meterOp) {
+ Dpid dpid = Dpid.dpid(deviceId.uri());
+ OpenFlowSwitch sw = controller.getSwitch(dpid);
+ if (sw == null) {
+ log.error("Unknown device {}", deviceId);
+ providerService.meterOperationFailed(meterOp,
+ MeterFailReason.UNKNOWN_DEVICE);
+ return;
+ }
+
+ performOperation(sw, meterOp);
+
+ }
+
+ private void performOperation(OpenFlowSwitch sw, MeterOperation op) {
+
+ pendingOperations.put(op.meter().id().id(), op);
+
+
+ Meter meter = op.meter();
+ MeterModBuilder builder = MeterModBuilder.builder(meter.id().id(), sw.factory());
+ if (meter.isBurst()) {
+ builder.burst();
+ }
+ builder.withBands(meter.bands())
+ .withId(meter.id())
+ .withRateUnit(meter.unit());
+
+ switch (op.type()) {
+ case ADD:
+ sw.sendMsg(builder.add());
+ break;
+ case REMOVE:
+ sw.sendMsg(builder.remove());
+ break;
+ case MODIFY:
+ sw.sendMsg(builder.modify());
+ break;
+ default:
+ log.warn("Unknown Meter command {}; not sending anything",
+ op.type());
+ providerService.meterOperationFailed(op,
+ MeterFailReason.UNKNOWN_COMMAND);
+ }
+
+ }
+
+ private void createStatsCollection(OpenFlowSwitch sw) {
+ if (isMeterSupported(sw)) {
+ MeterStatsCollector msc = new MeterStatsCollector(sw, POLL_INTERVAL);
+ msc.start();
+ collectors.put(new Dpid(sw.getId()), msc);
+ }
+ }
+
+ private boolean isMeterSupported(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 void pushMeterStats(Dpid dpid, OFStatsReply msg) {
+ DeviceId deviceId = DeviceId.deviceId(Dpid.uri(dpid));
+
+ if (msg.getStatsType() == OFStatsType.METER) {
+ OFMeterStatsReply reply = (OFMeterStatsReply) msg;
+ Collection<Meter> meters = buildMeters(deviceId, reply.getEntries());
+ //TODO do meter accounting here.
+ providerService.pushMeterMetrics(deviceId, meters);
+ } else if (msg.getStatsType() == OFStatsType.METER_CONFIG) {
+ OFMeterConfigStatsReply reply = (OFMeterConfigStatsReply) msg;
+ // FIXME: Map<Long, Meter> meters = collectMeters(deviceId, reply);
+ }
+
+ }
+
+ private Map<Long, Meter> collectMeters(DeviceId deviceId,
+ OFMeterConfigStatsReply reply) {
+ return Maps.newHashMap();
+ //TODO: Needs a fix to be applied to loxi MeterConfig stat is incorrect
+ }
+
+ private Collection<Meter> buildMeters(DeviceId deviceId,
+ List<OFMeterStats> entries) {
+ return entries.stream().map(stat -> {
+ DefaultMeter.Builder builder = DefaultMeter.builder();
+ Collection<Band> bands = buildBands(stat.getBandStats());
+ builder.forDevice(deviceId)
+ .withId(MeterId.meterId(stat.getMeterId()))
+ //FIXME: need to encode appId in meter id, but that makes
+ // things a little annoying for debugging
+ .fromApp(coreService.getAppId("org.onosproject.core"))
+ .withBands(bands);
+ DefaultMeter meter = builder.build();
+ meter.setState(MeterState.ADDED);
+ meter.setLife(stat.getDurationSec());
+ meter.setProcessedBytes(stat.getByteInCount().getValue());
+ meter.setProcessedPackets(stat.getPacketInCount().getValue());
+ meter.setReferenceCount(stat.getFlowCount());
+
+ // marks the meter as seen on the dataplane
+ pendingOperations.invalidate(stat.getMeterId());
+ return meter;
+ }).collect(Collectors.toSet());
+ }
+
+ private Collection<Band> buildBands(List<OFMeterBandStats> bandStats) {
+ return bandStats.stream().map(stat -> {
+ DefaultBand band = DefaultBand.builder().build();
+ band.setBytes(stat.getByteBandCount().getValue());
+ band.setPackets(stat.getPacketBandCount().getValue());
+ return band;
+ }).collect(Collectors.toSet());
+ }
+
+ private void signalMeterError(OFMeterModFailedErrorMsg meterError,
+ MeterOperation op) {
+ switch (meterError.getCode()) {
+ case UNKNOWN:
+ providerService.meterOperationFailed(op,
+ MeterFailReason.UNKNOWN_DEVICE);
+ break;
+ case METER_EXISTS:
+ providerService.meterOperationFailed(op,
+ MeterFailReason.EXISTING_METER);
+ break;
+ case INVALID_METER:
+ providerService.meterOperationFailed(op,
+ MeterFailReason.INVALID_METER);
+ break;
+ case UNKNOWN_METER:
+ providerService.meterOperationFailed(op,
+ MeterFailReason.UNKNOWN);
+ break;
+ case BAD_COMMAND:
+ providerService.meterOperationFailed(op,
+ MeterFailReason.UNKNOWN_COMMAND);
+ break;
+ case BAD_FLAGS:
+ providerService.meterOperationFailed(op,
+ MeterFailReason.UNKNOWN_FLAGS);
+ break;
+ case BAD_RATE:
+ providerService.meterOperationFailed(op,
+ MeterFailReason.BAD_RATE);
+ break;
+ case BAD_BURST:
+ providerService.meterOperationFailed(op,
+ MeterFailReason.BAD_BURST);
+ break;
+ case BAD_BAND:
+ providerService.meterOperationFailed(op,
+ MeterFailReason.BAD_BAND);
+ break;
+ case BAD_BAND_VALUE:
+ providerService.meterOperationFailed(op,
+ MeterFailReason.BAD_BAND_VALUE);
+ break;
+ case OUT_OF_METERS:
+ providerService.meterOperationFailed(op,
+ MeterFailReason.OUT_OF_METERS);
+ break;
+ case OUT_OF_BANDS:
+ providerService.meterOperationFailed(op,
+ MeterFailReason.OUT_OF_BANDS);
+ break;
+ default:
+ providerService.meterOperationFailed(op,
+ MeterFailReason.UNKNOWN);
+ }
+ }
+
+ private class InternalMeterListener
+ implements OpenFlowSwitchListener, OpenFlowEventListener {
+ @Override
+ public void handleMessage(Dpid dpid, OFMessage msg) {
+ switch (msg.getType()) {
+ case STATS_REPLY:
+ pushMeterStats(dpid, (OFStatsReply) msg);
+ break;
+ case ERROR:
+ OFErrorMsg error = (OFErrorMsg) msg;
+ if (error.getErrType() == OFErrorType.METER_MOD_FAILED) {
+ MeterOperation op =
+ pendingOperations.getIfPresent(error.getXid());
+ pendingOperations.invalidate(error.getXid());
+ if (op == null) {
+ log.warn("Unknown Meter operation failed {}", error);
+ } else {
+ OFMeterModFailedErrorMsg meterError =
+ (OFMeterModFailedErrorMsg) error;
+ signalMeterError(meterError, op);
+ }
+ }
+ break;
+ default:
+ break;
+ }
+
+ }
+
+ @Override
+ public void switchAdded(Dpid dpid) {
+ createStatsCollection(controller.getSwitch(dpid));
+ }
+
+ @Override
+ public void switchRemoved(Dpid dpid) {
+ MeterStatsCollector msc = collectors.remove(dpid);
+ if (msc != null) {
+ msc.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/meter/src/main/java/org/onosproject/provider/of/meter/impl/package-info.java b/framework/src/onos/providers/openflow/meter/src/main/java/org/onosproject/provider/of/meter/impl/package-info.java
new file mode 100644
index 00000000..9515712c
--- /dev/null
+++ b/framework/src/onos/providers/openflow/meter/src/main/java/org/onosproject/provider/of/meter/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 metering management.
+ */
+package org.onosproject.provider.of.meter.impl; \ No newline at end of file
diff --git a/framework/src/onos/providers/openflow/meter/src/test/java/org/onosproject/provider/of/meter/impl/OpenFlowMeterProviderTest.java b/framework/src/onos/providers/openflow/meter/src/test/java/org/onosproject/provider/of/meter/impl/OpenFlowMeterProviderTest.java
new file mode 100644
index 00000000..0c5d5389
--- /dev/null
+++ b/framework/src/onos/providers/openflow/meter/src/test/java/org/onosproject/provider/of/meter/impl/OpenFlowMeterProviderTest.java
@@ -0,0 +1,22 @@
+/*
+ * 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.meter.impl;
+
+
+public class OpenFlowMeterProviderTest {
+
+
+} \ No newline at end of file
diff --git a/framework/src/onos/providers/openflow/packet/pom.xml b/framework/src/onos/providers/openflow/packet/pom.xml
new file mode 100644
index 00000000..f7f62d8e
--- /dev/null
+++ b/framework/src/onos/providers/openflow/packet/pom.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright 2014 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.
+ -->
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+
+ <parent>
+ <groupId>org.onosproject</groupId>
+ <artifactId>onos-of-providers</artifactId>
+ <version>1.3.0-SNAPSHOT</version>
+ <relativePath>../pom.xml</relativePath>
+ </parent>
+
+ <artifactId>onos-of-provider-packet</artifactId>
+ <packaging>bundle</packaging>
+
+ <description>ONOS OpenFlow protocol packet provider</description>
+
+</project>
diff --git a/framework/src/onos/providers/openflow/packet/src/main/java/org/onosproject/provider/of/packet/impl/OpenFlowCorePacketContext.java b/framework/src/onos/providers/openflow/packet/src/main/java/org/onosproject/provider/of/packet/impl/OpenFlowCorePacketContext.java
new file mode 100644
index 00000000..6d153103
--- /dev/null
+++ b/framework/src/onos/providers/openflow/packet/src/main/java/org/onosproject/provider/of/packet/impl/OpenFlowCorePacketContext.java
@@ -0,0 +1,99 @@
+/*
+ * Copyright 2014-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.packet.impl;
+
+import org.onlab.packet.DeserializationException;
+import org.onlab.packet.Ethernet;
+import org.onosproject.net.PortNumber;
+import org.onosproject.net.flow.instructions.Instruction;
+import org.onosproject.net.flow.instructions.Instruction.Type;
+import org.onosproject.net.flow.instructions.Instructions.OutputInstruction;
+import org.onosproject.net.packet.DefaultPacketContext;
+import org.onosproject.net.packet.InboundPacket;
+import org.onosproject.net.packet.OutboundPacket;
+import org.onosproject.openflow.controller.OpenFlowPacketContext;
+import org.projectfloodlight.openflow.types.OFPort;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.List;
+
+/**
+ * Packet context used with the OpenFlow providers.
+ */
+public class OpenFlowCorePacketContext extends DefaultPacketContext {
+
+ private static final Logger log = LoggerFactory.getLogger(OpenFlowCorePacketContext.class);
+
+ private final OpenFlowPacketContext ofPktCtx;
+
+ /**
+ * Creates a new OpenFlow core packet context.
+ *
+ * @param time creation time
+ * @param inPkt inbound packet
+ * @param outPkt outbound packet
+ * @param block whether the context is blocked or not
+ * @param ofPktCtx OpenFlow packet context
+ */
+ protected OpenFlowCorePacketContext(long time, InboundPacket inPkt,
+ OutboundPacket outPkt, boolean block,
+ OpenFlowPacketContext ofPktCtx) {
+ super(time, inPkt, outPkt, block);
+ this.ofPktCtx = ofPktCtx;
+ }
+
+ @Override
+ public void send() {
+ if (!this.block()) {
+ if (outPacket() == null) {
+ sendPacket(null);
+ } else {
+ try {
+ Ethernet eth = Ethernet.deserializer()
+ .deserialize(outPacket().data().array(), 0,
+ outPacket().data().array().length);
+ sendPacket(eth);
+ } catch (DeserializationException e) {
+ log.warn("Unable to deserialize packet");
+ }
+ }
+ }
+ }
+
+ private void sendPacket(Ethernet eth) {
+ List<Instruction> ins = treatmentBuilder().build().allInstructions();
+ OFPort p = null;
+ //TODO: support arbitrary list of treatments must be supported in ofPacketContext
+ for (Instruction i : ins) {
+ if (i.type() == Type.OUTPUT) {
+ p = buildPort(((OutputInstruction) i).port());
+ break; //for now...
+ }
+ }
+ if (eth == null) {
+ ofPktCtx.build(p);
+ } else {
+ ofPktCtx.build(eth, p);
+ }
+ ofPktCtx.send();
+ }
+
+ private OFPort buildPort(PortNumber port) {
+ return OFPort.of((int) port.toLong());
+ }
+
+}
diff --git a/framework/src/onos/providers/openflow/packet/src/main/java/org/onosproject/provider/of/packet/impl/OpenFlowPacketProvider.java b/framework/src/onos/providers/openflow/packet/src/main/java/org/onosproject/provider/of/packet/impl/OpenFlowPacketProvider.java
new file mode 100644
index 00000000..dc79feff
--- /dev/null
+++ b/framework/src/onos/providers/openflow/packet/src/main/java/org/onosproject/provider/of/packet/impl/OpenFlowPacketProvider.java
@@ -0,0 +1,176 @@
+/*
+ * Copyright 2014-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.packet.impl;
+
+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.net.ConnectPoint;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.PortNumber;
+import org.onosproject.net.flow.instructions.Instruction;
+import org.onosproject.net.flow.instructions.Instructions.OutputInstruction;
+import org.onosproject.net.packet.DefaultInboundPacket;
+import org.onosproject.net.packet.DefaultOutboundPacket;
+import org.onosproject.net.packet.OutboundPacket;
+import org.onosproject.net.packet.PacketProvider;
+import org.onosproject.net.packet.PacketProviderRegistry;
+import org.onosproject.net.packet.PacketProviderService;
+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.OpenFlowPacketContext;
+import org.onosproject.openflow.controller.OpenFlowSwitch;
+import org.onosproject.openflow.controller.PacketListener;
+import org.projectfloodlight.openflow.protocol.OFPacketOut;
+import org.projectfloodlight.openflow.protocol.OFPortDesc;
+import org.projectfloodlight.openflow.protocol.action.OFAction;
+import org.projectfloodlight.openflow.protocol.ver10.OFFactoryVer10;
+import org.projectfloodlight.openflow.types.OFBufferId;
+import org.projectfloodlight.openflow.types.OFPort;
+import org.slf4j.Logger;
+
+import java.nio.ByteBuffer;
+import java.util.Collections;
+
+import static org.slf4j.LoggerFactory.getLogger;
+
+
+/**
+ * Provider which uses an OpenFlow controller to detect network
+ * infrastructure links.
+ */
+@Component(immediate = true)
+public class OpenFlowPacketProvider extends AbstractProvider implements PacketProvider {
+
+ private final Logger log = getLogger(getClass());
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected PacketProviderRegistry providerRegistry;
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected OpenFlowController controller;
+
+ private PacketProviderService providerService;
+
+ private final InternalPacketProvider listener = new InternalPacketProvider();
+
+ /**
+ * Creates an OpenFlow link provider.
+ */
+ public OpenFlowPacketProvider() {
+ super(new ProviderId("of", "org.onosproject.provider.openflow"));
+ }
+
+ @Activate
+ public void activate() {
+ providerService = providerRegistry.register(this);
+ controller.addPacketListener(20, listener);
+ log.info("Started");
+ }
+
+ @Deactivate
+ public void deactivate() {
+ providerRegistry.unregister(this);
+ controller.removePacketListener(listener);
+ providerService = null;
+ log.info("Stopped");
+ }
+
+ @Override
+ public void emit(OutboundPacket packet) {
+ DeviceId devId = packet.sendThrough();
+ String scheme = devId.toString().split(":")[0];
+
+ if (!scheme.equals(this.id().scheme())) {
+ throw new IllegalArgumentException(
+ "Don't know how to handle Device with scheme " + scheme);
+ }
+
+ Dpid dpid = Dpid.dpid(devId.uri());
+ OpenFlowSwitch sw = controller.getSwitch(dpid);
+ if (sw == null) {
+ log.warn("Device {} isn't available?", devId);
+ return;
+ }
+
+ //Ethernet eth = new Ethernet();
+ //eth.deserialize(packet.data().array(), 0, packet.data().array().length);
+ OFPortDesc p = null;
+ for (Instruction inst : packet.treatment().allInstructions()) {
+ if (inst.type().equals(Instruction.Type.OUTPUT)) {
+ p = portDesc(((OutputInstruction) inst).port());
+ OFPacketOut po = packetOut(sw, packet.data().array(), p.getPortNo());
+ sw.sendMsg(po);
+ }
+ }
+
+ }
+
+ private OFPortDesc portDesc(PortNumber port) {
+ OFPortDesc.Builder builder = OFFactoryVer10.INSTANCE.buildPortDesc();
+ builder.setPortNo(OFPort.of((int) port.toLong()));
+
+ return builder.build();
+ }
+
+ private OFPacketOut packetOut(OpenFlowSwitch sw, byte[] eth, OFPort out) {
+ OFPacketOut.Builder builder = sw.factory().buildPacketOut();
+ OFAction act = sw.factory().actions()
+ .buildOutput()
+ .setPort(out)
+ .build();
+ return builder
+ .setBufferId(OFBufferId.NO_BUFFER)
+ .setInPort(OFPort.CONTROLLER)
+ .setActions(Collections.singletonList(act))
+ .setData(eth)
+ .build();
+ }
+
+ /**
+ * Internal Packet Provider implementation.
+ *
+ */
+ private class InternalPacketProvider implements PacketListener {
+
+ @Override
+ public void handlePacket(OpenFlowPacketContext pktCtx) {
+ DeviceId id = DeviceId.deviceId(Dpid.uri(pktCtx.dpid().value()));
+
+ DefaultInboundPacket inPkt = new DefaultInboundPacket(
+ new ConnectPoint(id, PortNumber.portNumber(pktCtx.inPort())),
+ pktCtx.parsed(), ByteBuffer.wrap(pktCtx.unparsed()));
+
+ DefaultOutboundPacket outPkt = null;
+ if (!pktCtx.isBuffered()) {
+ outPkt = new DefaultOutboundPacket(id, null,
+ ByteBuffer.wrap(pktCtx.unparsed()));
+ }
+
+ OpenFlowCorePacketContext corePktCtx =
+ new OpenFlowCorePacketContext(System.currentTimeMillis(),
+ inPkt, outPkt, pktCtx.isHandled(), pktCtx);
+ providerService.processPacket(corePktCtx);
+ }
+
+ }
+
+
+}
diff --git a/framework/src/onos/providers/openflow/packet/src/main/java/org/onosproject/provider/of/packet/impl/package-info.java b/framework/src/onos/providers/openflow/packet/src/main/java/org/onosproject/provider/of/packet/impl/package-info.java
new file mode 100644
index 00000000..dd1130c0
--- /dev/null
+++ b/framework/src/onos/providers/openflow/packet/src/main/java/org/onosproject/provider/of/packet/impl/package-info.java
@@ -0,0 +1,21 @@
+/*
+ * Copyright 2014 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 intercepting and
+ * emitting packets.
+ */
+package org.onosproject.provider.of.packet.impl;
diff --git a/framework/src/onos/providers/openflow/packet/src/test/java/org/onosproject/provider/of/packet/impl/OpenFlowPacketProviderTest.java b/framework/src/onos/providers/openflow/packet/src/test/java/org/onosproject/provider/of/packet/impl/OpenFlowPacketProviderTest.java
new file mode 100644
index 00000000..5fded926
--- /dev/null
+++ b/framework/src/onos/providers/openflow/packet/src/test/java/org/onosproject/provider/of/packet/impl/OpenFlowPacketProviderTest.java
@@ -0,0 +1,431 @@
+/*
+ * Copyright 2014-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.packet.impl;
+
+import com.google.common.collect.Lists;
+import com.google.common.collect.Sets;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.onlab.packet.ARP;
+import org.onlab.packet.Ethernet;
+import org.onosproject.net.Device;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.PortNumber;
+import org.onosproject.net.flow.DefaultTrafficTreatment;
+import org.onosproject.net.flow.TrafficTreatment;
+import org.onosproject.net.flow.instructions.Instruction;
+import org.onosproject.net.flow.instructions.Instructions;
+import org.onosproject.net.packet.DefaultOutboundPacket;
+import org.onosproject.net.packet.OutboundPacket;
+import org.onosproject.net.packet.PacketContext;
+import org.onosproject.net.packet.PacketProvider;
+import org.onosproject.net.packet.PacketProviderRegistry;
+import org.onosproject.net.packet.PacketProviderService;
+import org.onosproject.net.provider.ProviderId;
+import org.onosproject.openflow.controller.DefaultOpenFlowPacketContext;
+import org.onosproject.openflow.controller.Dpid;
+import org.onosproject.openflow.controller.OpenFlowController;
+import org.onosproject.openflow.controller.OpenFlowEventListener;
+import org.onosproject.openflow.controller.OpenFlowPacketContext;
+import org.onosproject.openflow.controller.OpenFlowSwitch;
+import org.onosproject.openflow.controller.OpenFlowSwitchListener;
+import org.onosproject.openflow.controller.PacketListener;
+import org.onosproject.openflow.controller.RoleState;
+import org.projectfloodlight.openflow.protocol.OFFactory;
+import org.projectfloodlight.openflow.protocol.OFMessage;
+import org.projectfloodlight.openflow.protocol.OFPacketIn;
+import org.projectfloodlight.openflow.protocol.OFPacketInReason;
+import org.projectfloodlight.openflow.protocol.OFPortDesc;
+import org.projectfloodlight.openflow.protocol.ver10.OFFactoryVer10;
+import org.projectfloodlight.openflow.types.MacAddress;
+import org.projectfloodlight.openflow.types.OFBufferId;
+import org.projectfloodlight.openflow.types.OFPort;
+
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Set;
+
+import static org.junit.Assert.*;
+
+
+public class OpenFlowPacketProviderTest {
+
+ private static final int PN1 = 100;
+ private static final int PN2 = 200;
+ private static final int PN3 = 300;
+ private static final short VLANID = (short) 100;
+
+ private static final DeviceId DID = DeviceId.deviceId("of:1");
+ private static final DeviceId DID_MISSING = DeviceId.deviceId("of:2");
+ private static final DeviceId DID_WRONG = DeviceId.deviceId("test:1");
+ private static final PortNumber P1 = PortNumber.portNumber(PN1);
+ private static final PortNumber P2 = PortNumber.portNumber(PN2);
+ private static final PortNumber P3 = PortNumber.portNumber(PN3);
+
+ private static final Instruction INST1 = Instructions.createOutput(P1);
+ private static final Instruction INST2 = Instructions.createOutput(P2);
+ private static final Instruction INST3 = Instructions.createOutput(P3);
+
+ private static final OFPortDesc PD1 = portDesc(PN1);
+ private static final OFPortDesc PD2 = portDesc(PN2);
+
+ private static final List<OFPortDesc> PLIST = Lists.newArrayList(PD1, PD2);
+ private static final TrafficTreatment TR = treatment(INST1, INST2);
+ private static final TrafficTreatment TR_MISSING = treatment(INST1, INST3);
+
+ private static final byte[] ANY = new byte [] {0, 0, 0, 0};
+
+ private final OpenFlowPacketProvider provider = new OpenFlowPacketProvider();
+ private final TestPacketRegistry registry = new TestPacketRegistry();
+ private final TestController controller = new TestController();
+
+ private final TestOpenFlowSwitch sw = new TestOpenFlowSwitch();
+
+ @Before
+ public void startUp() {
+ provider.providerRegistry = registry;
+ provider.controller = controller;
+ provider.activate();
+ assertNotNull("listener should be registered", registry.listener);
+ }
+
+ @After
+ public void teardown() {
+ provider.deactivate();
+ assertNull("listeners shouldn't be registered", registry.listener);
+ provider.controller = null;
+ provider.providerRegistry = null;
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void wrongScheme() {
+ sw.setRole(RoleState.MASTER);
+ OutboundPacket schemeFailPkt = outPacket(DID_WRONG, TR, null);
+ provider.emit(schemeFailPkt);
+ assertEquals("message sent incorrectly", 0, sw.sent.size());
+ }
+
+ @Test
+ public void emit() {
+
+ MacAddress mac1 = MacAddress.of("00:00:00:11:00:01");
+ MacAddress mac2 = MacAddress.of("00:00:00:22:00:02");
+
+ ARP arp = new ARP();
+ arp.setSenderProtocolAddress(ANY)
+ .setSenderHardwareAddress(mac1.getBytes())
+ .setTargetHardwareAddress(mac2.getBytes())
+ .setTargetProtocolAddress(ANY)
+ .setHardwareType((short) 0)
+ .setProtocolType((short) 0)
+ .setHardwareAddressLength((byte) 6)
+ .setProtocolAddressLength((byte) 4)
+ .setOpCode((byte) 0);
+
+ Ethernet eth = new Ethernet();
+ eth.setVlanID(VLANID)
+ .setEtherType(Ethernet.TYPE_ARP)
+ .setSourceMACAddress("00:00:00:11:00:01")
+ .setDestinationMACAddress("00:00:00:22:00:02")
+ .setPayload(arp);
+
+ //the should-be working setup.
+ OutboundPacket passPkt = outPacket(DID, TR, eth);
+ sw.setRole(RoleState.MASTER);
+ provider.emit(passPkt);
+ assertEquals("invalid switch", sw, controller.current);
+ assertEquals("message not sent", PLIST.size(), sw.sent.size());
+ sw.sent.clear();
+
+ //wrong Role
+ //sw.setRole(RoleState.SLAVE);
+ //provider.emit(passPkt);
+ //assertEquals("invalid switch", sw, controller.current);
+ //assertEquals("message sent incorrectly", 0, sw.sent.size());
+
+ //sw.setRole(RoleState.MASTER);
+
+ //missing switch
+ OutboundPacket swFailPkt = outPacket(DID_MISSING, TR, eth);
+ provider.emit(swFailPkt);
+ assertNull("invalid switch", controller.current);
+ assertEquals("message sent incorrectly", 0, sw.sent.size());
+
+ //to missing port
+ //OutboundPacket portFailPkt = outPacket(DID, TR_MISSING, eth);
+ //provider.emit(portFailPkt);
+ //assertEquals("extra message sent", 1, sw.sent.size());
+
+ }
+
+ @Test
+ public void handlePacket() {
+ OFPacketIn pkt = sw.factory().buildPacketIn()
+ .setBufferId(OFBufferId.NO_BUFFER)
+ .setInPort(OFPort.NO_MASK)
+ .setReason(OFPacketInReason.INVALID_TTL)
+ .build();
+
+ controller.processPacket(null, pkt);
+ assertNotNull("message unprocessed", registry.ctx);
+
+ }
+
+ private static OFPortDesc portDesc(int port) {
+ OFPortDesc.Builder builder = OFFactoryVer10.INSTANCE.buildPortDesc();
+ builder.setPortNo(OFPort.of(port));
+
+ return builder.build();
+ }
+
+ private static TrafficTreatment treatment(Instruction ... insts) {
+ TrafficTreatment.Builder builder = DefaultTrafficTreatment.builder();
+ for (Instruction i : insts) {
+ builder.add(i);
+ }
+ return builder.build();
+ }
+
+ private static OutboundPacket outPacket(
+ DeviceId d, TrafficTreatment t, Ethernet e) {
+ ByteBuffer buf = null;
+ if (e != null) {
+ buf = ByteBuffer.wrap(e.serialize());
+ }
+ return new DefaultOutboundPacket(d, t, buf);
+ }
+
+ private class TestPacketRegistry implements PacketProviderRegistry {
+
+ PacketProvider listener = null;
+ PacketContext ctx = null;
+
+ @Override
+ public PacketProviderService register(PacketProvider provider) {
+ listener = provider;
+ return new TestPacketProviderService();
+ }
+
+ @Override
+ public void unregister(PacketProvider provider) {
+ listener = null;
+ }
+
+ @Override
+ public Set<ProviderId> getProviders() {
+ return Sets.newHashSet(listener.id());
+ }
+
+ private class TestPacketProviderService implements PacketProviderService {
+
+ @Override
+ public PacketProvider provider() {
+ return null;
+ }
+
+ @Override
+ public void processPacket(PacketContext context) {
+ ctx = context;
+ }
+
+ }
+ }
+
+ private class TestController implements OpenFlowController {
+
+ PacketListener pktListener;
+ OpenFlowSwitch current;
+
+ @Override
+ public Iterable<OpenFlowSwitch> getSwitches() {
+ return null;
+ }
+
+ @Override
+ public Iterable<OpenFlowSwitch> getMasterSwitches() {
+ return null;
+ }
+
+ @Override
+ public Iterable<OpenFlowSwitch> getEqualSwitches() {
+ return null;
+ }
+
+ @Override
+ public OpenFlowSwitch getSwitch(Dpid dpid) {
+ if (dpid.equals(Dpid.dpid(DID.uri()))) {
+ current = sw;
+ } else {
+ current = null;
+ }
+ return current;
+ }
+
+ @Override
+ public OpenFlowSwitch getMasterSwitch(Dpid dpid) {
+ return null;
+ }
+
+ @Override
+ public OpenFlowSwitch getEqualSwitch(Dpid dpid) {
+ return null;
+ }
+
+ @Override
+ public void addListener(OpenFlowSwitchListener listener) {
+ }
+
+ @Override
+ public void removeListener(OpenFlowSwitchListener listener) {
+ }
+
+ @Override
+ public void addPacketListener(int priority, PacketListener listener) {
+ pktListener = listener;
+ }
+
+ @Override
+ public void removePacketListener(PacketListener listener) {
+ }
+
+ @Override
+ public void addEventListener(OpenFlowEventListener listener) {
+ }
+
+ @Override
+ public void removeEventListener(OpenFlowEventListener listener) {
+ }
+
+ @Override
+ public void write(Dpid dpid, OFMessage msg) {
+ }
+
+ @Override
+ public void processPacket(Dpid dpid, OFMessage msg) {
+ OpenFlowPacketContext pktCtx =
+ DefaultOpenFlowPacketContext.
+ packetContextFromPacketIn(sw, (OFPacketIn) msg);
+ pktListener.handlePacket(pktCtx);
+ }
+
+ @Override
+ public void setRole(Dpid dpid, RoleState role) {
+ }
+
+ }
+
+ private class TestOpenFlowSwitch implements OpenFlowSwitch {
+
+ RoleState state;
+ List<OFMessage> sent = new ArrayList<OFMessage>();
+ OFFactory factory = OFFactoryVer10.INSTANCE;
+
+ @Override
+ public void sendMsg(OFMessage msg) {
+ sent.add(msg);
+ }
+
+ @Override
+ public void sendMsg(List<OFMessage> msgs) {
+ }
+
+ @Override
+ public void handleMessage(OFMessage fromSwitch) {
+ }
+
+ @Override
+ public void setRole(RoleState role) {
+ state = role;
+ }
+
+ @Override
+ public RoleState getRole() {
+ return state;
+ }
+
+ @Override
+ public List<OFPortDesc> getPorts() {
+ return PLIST;
+ }
+
+ @Override
+ public OFFactory factory() {
+ return factory;
+ }
+
+ @Override
+ public String getStringId() {
+ return null;
+ }
+
+ @Override
+ public long getId() {
+ return 0;
+ }
+
+ @Override
+ public String manufacturerDescription() {
+ return null;
+ }
+
+ @Override
+ public String datapathDescription() {
+ return null;
+ }
+
+ @Override
+ public String hardwareDescription() {
+ return null;
+ }
+
+ @Override
+ public String softwareDescription() {
+ return null;
+ }
+
+ @Override
+ public String serialNumber() {
+ return null;
+ }
+
+ @Override
+ public boolean isConnected() {
+ return true;
+ }
+
+ @Override
+ public void disconnectSwitch() {
+ }
+
+ @Override
+ public void returnRoleReply(RoleState requested, RoleState reponse) {
+ }
+ @Override
+ public Device.Type deviceType() {
+ return Device.Type.SWITCH;
+ }
+
+ @Override
+ public String channelId() {
+ return "1.2.3.4:1";
+ }
+
+
+ }
+
+}
diff --git a/framework/src/onos/providers/openflow/pom.xml b/framework/src/onos/providers/openflow/pom.xml
new file mode 100644
index 00000000..99ff6649
--- /dev/null
+++ b/framework/src/onos/providers/openflow/pom.xml
@@ -0,0 +1,63 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright 2014 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.
+ -->
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+
+ <parent>
+ <groupId>org.onosproject</groupId>
+ <artifactId>onos-providers</artifactId>
+ <version>1.3.0-SNAPSHOT</version>
+ <relativePath>../pom.xml</relativePath>
+ </parent>
+
+ <artifactId>onos-of-providers</artifactId>
+ <packaging>pom</packaging>
+
+ <description>ONOS OpenFlow protocol adapters</description>
+
+ <modules>
+ <module>device</module>
+ <module>packet</module>
+ <module>flow</module>
+ <module>group</module>
+ <module>meter</module>
+ <module>app</module>
+ </modules>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.onosproject</groupId>
+ <artifactId>onos-of-api</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.onosproject</groupId>
+ <artifactId>onos-of-api</artifactId>
+ <classifier>tests</classifier>
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>org.onosproject</groupId>
+ <artifactId>onos-api</artifactId>
+ <classifier>tests</classifier>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+
+</project>