aboutsummaryrefslogtreecommitdiffstats
path: root/framework/src/onos/apps/cordfabric
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/apps/cordfabric
parent6139282e1e93c2322076de4b91b1c85d0bc4a8b3 (diff)
ONOS checkin based on commit tag e796610b1f721d02f9b0e213cf6f7790c10ecd60
Change-Id: Ife8810491034fe7becdba75dda20de4267bd15cd
Diffstat (limited to 'framework/src/onos/apps/cordfabric')
-rw-r--r--framework/src/onos/apps/cordfabric/pom.xml135
-rw-r--r--framework/src/onos/apps/cordfabric/src/main/java/org/onosproject/cordfabric/CordFabricManager.java433
-rw-r--r--framework/src/onos/apps/cordfabric/src/main/java/org/onosproject/cordfabric/FabricService.java50
-rw-r--r--framework/src/onos/apps/cordfabric/src/main/java/org/onosproject/cordfabric/FabricVlan.java57
-rw-r--r--framework/src/onos/apps/cordfabric/src/main/java/org/onosproject/cordfabric/FabricVlanCodec.java68
-rw-r--r--framework/src/onos/apps/cordfabric/src/main/java/org/onosproject/cordfabric/FabricWebResource.java99
-rw-r--r--framework/src/onos/apps/cordfabric/src/main/java/org/onosproject/cordfabric/cli/FabricAddCommand.java64
-rw-r--r--framework/src/onos/apps/cordfabric/src/main/java/org/onosproject/cordfabric/cli/FabricRemoveCommand.java44
-rw-r--r--framework/src/onos/apps/cordfabric/src/main/java/org/onosproject/cordfabric/cli/FabricShowCommand.java47
-rw-r--r--framework/src/onos/apps/cordfabric/src/main/java/org/onosproject/cordfabric/cli/package-info.java20
-rw-r--r--framework/src/onos/apps/cordfabric/src/main/java/org/onosproject/cordfabric/package-info.java20
-rw-r--r--framework/src/onos/apps/cordfabric/src/main/resources/OSGI-INF/blueprint/shell-config.xml36
-rw-r--r--framework/src/onos/apps/cordfabric/src/main/webapp/WEB-INF/web.xml44
13 files changed, 1117 insertions, 0 deletions
diff --git a/framework/src/onos/apps/cordfabric/pom.xml b/framework/src/onos/apps/cordfabric/pom.xml
new file mode 100644
index 00000000..f5388553
--- /dev/null
+++ b/framework/src/onos/apps/cordfabric/pom.xml
@@ -0,0 +1,135 @@
+<?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/xsd/maven-4.0.0.xsd">
+ <parent>
+ <artifactId>onos-apps</artifactId>
+ <groupId>org.onosproject</groupId>
+ <version>1.3.0-SNAPSHOT</version>
+ <relativePath>../pom.xml</relativePath>
+ </parent>
+ <modelVersion>4.0.0</modelVersion>
+
+ <artifactId>onos-app-cordfabric</artifactId>
+
+ <packaging>bundle</packaging>
+ <description>Simple fabric application for CORD</description>
+
+ <properties>
+ <onos.app.name>org.onosproject.cordfabric</onos.app.name>
+ <web.context>/onos/cordfabric</web.context>
+ <api.version>1.0.0</api.version>
+ <api.title>ONOS CORD Fabric REST API</api.title>
+ <api.description>
+ APIs for interacting with the CORD Fabric application.
+ </api.description>
+ <api.package>org.onosproject.cordfabric</api.package>
+ </properties>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.onosproject</groupId>
+ <artifactId>onos-cli</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.karaf.shell</groupId>
+ <artifactId>org.apache.karaf.shell.console</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.onosproject</groupId>
+ <artifactId>onos-rest</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.onosproject</groupId>
+ <artifactId>onlab-rest</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>javax.ws.rs</groupId>
+ <artifactId>jsr311-api</artifactId>
+ <version>1.1.1</version>
+ </dependency>
+ <dependency>
+ <groupId>com.sun.jersey</groupId>
+ <artifactId>jersey-servlet</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>com.fasterxml.jackson.core</groupId>
+ <artifactId>jackson-databind</artifactId>
+ </dependency>
+
+ <dependency>
+ <groupId>com.fasterxml.jackson.core</groupId>
+ <artifactId>jackson-annotations</artifactId>
+ </dependency>
+
+ <dependency>
+ <groupId>org.osgi</groupId>
+ <artifactId>org.osgi.compendium</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.osgi</groupId>
+ <artifactId>org.osgi.core</artifactId>
+ </dependency>
+ </dependencies>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-bundle-plugin</artifactId>
+ <extensions>true</extensions>
+ <configuration>
+ <instructions>
+ <_wab>src/main/webapp/</_wab>
+ <Include-Resource>
+ WEB-INF/classes/apidoc/swagger.json=target/swagger.json,
+ {maven-resources}
+ </Include-Resource>
+ <Bundle-SymbolicName>
+ ${project.groupId}.${project.artifactId}
+ </Bundle-SymbolicName>
+ <Import-Package>
+ org.slf4j,
+ org.osgi.framework,
+ javax.ws.rs,
+ javax.ws.rs.core,
+ com.sun.jersey.api.core,
+ com.sun.jersey.spi.container.servlet,
+ com.sun.jersey.server.impl.container.servlet,
+ com.fasterxml.jackson.databind,
+ com.fasterxml.jackson.databind.node,
+ org.apache.karaf.shell.commands,
+ org.apache.commons.lang.math.*,
+ com.google.common.*,
+ org.onlab.packet.*,
+ org.onlab.rest.*,
+ org.onosproject.*,
+ org.onlab.util.*,
+ org.jboss.netty.util.*
+ </Import-Package>
+ <Web-ContextPath>${web.context}</Web-ContextPath>
+ </instructions>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+</project>
diff --git a/framework/src/onos/apps/cordfabric/src/main/java/org/onosproject/cordfabric/CordFabricManager.java b/framework/src/onos/apps/cordfabric/src/main/java/org/onosproject/cordfabric/CordFabricManager.java
new file mode 100644
index 00000000..1523e9c2
--- /dev/null
+++ b/framework/src/onos/apps/cordfabric/src/main/java/org/onosproject/cordfabric/CordFabricManager.java
@@ -0,0 +1,433 @@
+/*
+ * 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.cordfabric;
+
+import com.google.common.collect.HashMultimap;
+import com.google.common.collect.Multimap;
+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.apache.felix.scr.annotations.Service;
+import org.onlab.packet.Ethernet;
+import org.onlab.packet.IPv4;
+import org.onlab.packet.MacAddress;
+import org.onlab.packet.TpPort;
+import org.onlab.packet.VlanId;
+import org.onosproject.core.ApplicationId;
+import org.onosproject.core.CoreService;
+import org.onosproject.net.ConnectPoint;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.PortNumber;
+import org.onosproject.net.device.DeviceEvent;
+import org.onosproject.net.device.DeviceListener;
+import org.onosproject.net.device.DeviceService;
+import org.onosproject.net.flow.DefaultTrafficSelector;
+import org.onosproject.net.flow.DefaultTrafficTreatment;
+import org.onosproject.net.flow.TrafficSelector;
+import org.onosproject.net.flow.TrafficTreatment;
+import org.onosproject.net.flowobjective.DefaultForwardingObjective;
+import org.onosproject.net.flowobjective.FlowObjectiveService;
+import org.onosproject.net.flowobjective.ForwardingObjective;
+import org.onosproject.net.flowobjective.Objective;
+import org.onosproject.net.flowobjective.ObjectiveContext;
+import org.onosproject.net.flowobjective.ObjectiveError;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.ArrayList;
+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;
+
+/**
+ * CORD fabric application.
+ */
+@Service
+@Component(immediate = true)
+public class CordFabricManager implements FabricService {
+
+ private final Logger log = getLogger(getClass());
+
+ private ApplicationId appId;
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected CoreService coreService;
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected FlowObjectiveService flowObjectiveService;
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected DeviceService deviceService;
+
+ private InternalDeviceListener deviceListener = new InternalDeviceListener();
+
+ private static final int PRIORITY = 50000;
+ private static final int TESTPRIO = 49999;
+
+ private short radiusPort = 1812;
+
+ private short ofPort = 6633;
+
+ private DeviceId fabricDeviceId = DeviceId.deviceId("of:5e3e486e73000187");
+
+ private final Multimap<VlanId, ConnectPoint> vlans = HashMultimap.create();
+
+ //TODO make this configurable
+ private boolean testMode = true;
+
+
+ @Activate
+ public void activate() {
+ appId = coreService.registerApplication("org.onosproject.cordfabric");
+
+ deviceService.addListener(deviceListener);
+
+ if (deviceService.isAvailable(fabricDeviceId)) {
+ setupDefaultFlows();
+ }
+
+ log.info("Started");
+ }
+
+ @Deactivate
+ public void deactivate() {
+ deviceService.removeListener(deviceListener);
+
+ log.info("Stopped");
+ }
+
+ private void setupDefaultFlows() {
+ TrafficSelector ofInBandMatchUp = DefaultTrafficSelector.builder()
+ .matchEthType(Ethernet.TYPE_IPV4)
+ .matchIPProtocol(IPv4.PROTOCOL_TCP)
+ .matchTcpDst(TpPort.tpPort(ofPort))
+ .matchInPort(PortNumber.portNumber(6))
+ .build();
+
+ TrafficSelector ofInBandMatchDown = DefaultTrafficSelector.builder()
+ .matchEthType(Ethernet.TYPE_IPV4)
+ .matchIPProtocol(IPv4.PROTOCOL_TCP)
+ .matchTcpSrc(TpPort.tpPort(ofPort))
+ .matchInPort(PortNumber.portNumber(1))
+ .build();
+
+ TrafficSelector oltMgmtUp = DefaultTrafficSelector.builder()
+ .matchEthSrc(MacAddress.valueOf("00:0c:d5:00:01:01"))
+ .matchInPort(PortNumber.portNumber(2))
+ .build();
+
+ TrafficSelector oltMgmtDown = DefaultTrafficSelector.builder()
+ .matchEthDst(MacAddress.valueOf("00:0c:d5:00:01:01"))
+ .matchInPort(PortNumber.portNumber(9))
+ .build();
+
+ TrafficTreatment up = DefaultTrafficTreatment.builder()
+ .setOutput(PortNumber.portNumber(1))
+ .build();
+
+ TrafficTreatment down = DefaultTrafficTreatment.builder()
+ .setOutput(PortNumber.portNumber(6))
+ .build();
+
+ TrafficSelector toRadius = DefaultTrafficSelector.builder()
+ .matchInPort(PortNumber.portNumber(2))
+ .matchEthType(Ethernet.TYPE_IPV4)
+ .matchIPProtocol(IPv4.PROTOCOL_UDP)
+ .matchUdpDst(TpPort.tpPort(radiusPort))
+ .build();
+
+ TrafficSelector fromRadius = DefaultTrafficSelector.builder()
+ .matchInPort(PortNumber.portNumber(5))
+ .matchEthType(Ethernet.TYPE_IPV4)
+ .matchIPProtocol(IPv4.PROTOCOL_UDP)
+ .matchUdpDst(TpPort.tpPort(radiusPort))
+ .build();
+
+ TrafficTreatment toOlt = DefaultTrafficTreatment.builder()
+ .setOutput(PortNumber.portNumber(2))
+ .build();
+
+ TrafficTreatment toVolt = DefaultTrafficTreatment.builder()
+ .setOutput(PortNumber.portNumber(9))
+ .build();
+
+ TrafficTreatment sentToRadius = DefaultTrafficTreatment.builder()
+ .setOutput(PortNumber.portNumber(5))
+ .build();
+
+ TrafficTreatment testPort = DefaultTrafficTreatment.builder()
+ .setOutput(PortNumber.portNumber(8))
+ .build();
+
+ ForwardingObjective ofTestPath = DefaultForwardingObjective.builder()
+ .fromApp(appId)
+ .makePermanent()
+ .withFlag(ForwardingObjective.Flag.VERSATILE)
+ .withPriority(TESTPRIO)
+ .withSelector(
+ DefaultTrafficSelector.builder()
+ .matchInPort(PortNumber.portNumber(2))
+ .build())
+ .withTreatment(testPort)
+ .add();
+
+ ForwardingObjective radiusToServer = DefaultForwardingObjective.builder()
+ .fromApp(appId)
+ .makePermanent()
+ .withFlag(ForwardingObjective.Flag.VERSATILE)
+ .withPriority(PRIORITY)
+ .withSelector(toRadius)
+ .withTreatment(sentToRadius)
+ .add();
+
+ ForwardingObjective serverToRadius = DefaultForwardingObjective.builder()
+ .fromApp(appId)
+ .makePermanent()
+ .withFlag(ForwardingObjective.Flag.VERSATILE)
+ .withPriority(PRIORITY)
+ .withSelector(fromRadius)
+ .withTreatment(toOlt)
+ .add();
+
+
+
+ ForwardingObjective upCtrl = DefaultForwardingObjective.builder()
+ .fromApp(appId)
+ .makePermanent()
+ .withFlag(ForwardingObjective.Flag.VERSATILE)
+ .withPriority(PRIORITY)
+ .withSelector(ofInBandMatchUp)
+ .withTreatment(up)
+ .add();
+
+ ForwardingObjective downCtrl = DefaultForwardingObjective.builder()
+ .fromApp(appId)
+ .makePermanent()
+ .withFlag(ForwardingObjective.Flag.VERSATILE)
+ .withPriority(PRIORITY)
+ .withSelector(ofInBandMatchDown)
+ .withTreatment(down)
+ .add();
+
+ ForwardingObjective upOltMgmt = DefaultForwardingObjective.builder()
+ .fromApp(appId)
+ .makePermanent()
+ .withFlag(ForwardingObjective.Flag.VERSATILE)
+ .withPriority(PRIORITY)
+ .withSelector(oltMgmtUp)
+ .withTreatment(toVolt)
+ .add();
+
+ ForwardingObjective downOltMgmt = DefaultForwardingObjective.builder()
+ .fromApp(appId)
+ .makePermanent()
+ .withFlag(ForwardingObjective.Flag.VERSATILE)
+ .withPriority(PRIORITY)
+ .withSelector(oltMgmtDown)
+ .withTreatment(toOlt)
+ .add();
+
+ if (testMode) {
+ flowObjectiveService.forward(fabricDeviceId, ofTestPath);
+ }
+
+ flowObjectiveService.forward(fabricDeviceId, upCtrl);
+ flowObjectiveService.forward(fabricDeviceId, downCtrl);
+ flowObjectiveService.forward(fabricDeviceId, radiusToServer);
+ flowObjectiveService.forward(fabricDeviceId, serverToRadius);
+ flowObjectiveService.forward(fabricDeviceId, upOltMgmt);
+ flowObjectiveService.forward(fabricDeviceId, downOltMgmt);
+ }
+
+ @Override
+ public void addVlan(FabricVlan vlan) {
+ checkNotNull(vlan);
+ checkArgument(vlan.ports().size() > 1);
+ verifyPorts(vlan.ports());
+
+ removeVlan(vlan.vlan());
+
+ if (vlan.iptv()) {
+ provisionIPTV();
+ }
+
+ vlan.ports().forEach(cp -> {
+ if (vlans.put(vlan.vlan(), cp)) {
+ addForwarding(vlan.vlan(), cp.deviceId(), cp.port(),
+ vlan.ports().stream()
+ .filter(p -> p != cp)
+ .map(ConnectPoint::port)
+ .collect(Collectors.toList()));
+ }
+ });
+ }
+
+ //FIXME: pass iptv vlan in here.
+ private void provisionIPTV() {
+ TrafficSelector ipTvUp = DefaultTrafficSelector.builder()
+ .matchVlanId(VlanId.vlanId((short) 7))
+ .matchInPort(PortNumber.portNumber(2))
+ .build();
+
+ TrafficTreatment ipTvActUp = DefaultTrafficTreatment.builder()
+ .setOutput(PortNumber.portNumber(7)).build();
+
+ TrafficSelector ipTvDown = DefaultTrafficSelector.builder()
+ .matchVlanId(VlanId.vlanId((short) 7))
+ .matchInPort(PortNumber.portNumber(7))
+ .build();
+
+ TrafficTreatment ipTvActDown = DefaultTrafficTreatment.builder()
+ .setOutput(PortNumber.portNumber(2)).build();
+
+ ForwardingObjective ipTvUpstream = DefaultForwardingObjective.builder()
+ .fromApp(appId)
+ .makePermanent()
+ .withFlag(ForwardingObjective.Flag.VERSATILE)
+ .withPriority(PRIORITY)
+ .withSelector(ipTvUp)
+ .withTreatment(ipTvActUp)
+ .add();
+
+ ForwardingObjective ipTvDownstream = DefaultForwardingObjective.builder()
+ .fromApp(appId)
+ .makePermanent()
+ .withFlag(ForwardingObjective.Flag.VERSATILE)
+ .withPriority(PRIORITY)
+ .withSelector(ipTvDown)
+ .withTreatment(ipTvActDown)
+ .add();
+
+ flowObjectiveService.forward(fabricDeviceId, ipTvUpstream);
+ flowObjectiveService.forward(fabricDeviceId, ipTvDownstream);
+ }
+
+ @Override
+ public void removeVlan(VlanId vlanId) {
+ Collection<ConnectPoint> ports = vlans.removeAll(vlanId);
+
+ ports.forEach(cp -> removeForwarding(vlanId, cp.deviceId(), cp.port(),
+ ports.stream()
+ .filter(p -> p != cp)
+ .map(ConnectPoint::port)
+ .collect(Collectors.toList())));
+ }
+
+ @Override
+ public List<FabricVlan> getVlans() {
+ List<FabricVlan> fVlans = new ArrayList<>();
+ vlans.keySet().forEach(vlan -> fVlans.add(
+ //FIXME: Very aweful but will fo for now
+ new FabricVlan(vlan, vlans.get(vlan), vlan.toShort() == 201)));
+ return fVlans;
+ }
+
+ private static void verifyPorts(List<ConnectPoint> ports) {
+ DeviceId deviceId = ports.get(0).deviceId();
+ for (ConnectPoint connectPoint : ports) {
+ if (!connectPoint.deviceId().equals(deviceId)) {
+ throw new IllegalArgumentException("Ports must all be on the same device");
+ }
+ }
+ }
+
+ private void addForwarding(VlanId vlanId, DeviceId deviceId, PortNumber inPort,
+ List<PortNumber> outPorts) {
+
+ TrafficSelector selector = DefaultTrafficSelector.builder()
+ .matchVlanId(vlanId)
+ .matchInPort(inPort)
+ .build();
+
+ TrafficTreatment.Builder treatmentBuilder = DefaultTrafficTreatment.builder();
+
+ outPorts.forEach(p -> treatmentBuilder.setOutput(p));
+
+ ForwardingObjective objective = DefaultForwardingObjective.builder()
+ .fromApp(appId)
+ .makePermanent()
+ .withFlag(ForwardingObjective.Flag.VERSATILE)
+ .withPriority(PRIORITY)
+ .withSelector(selector)
+ .withTreatment(treatmentBuilder.build())
+ .add(new ObjectiveHandler());
+
+ flowObjectiveService.forward(deviceId, objective);
+ }
+
+ private void removeForwarding(VlanId vlanId, DeviceId deviceId, PortNumber inPort,
+ List<PortNumber> outPorts) {
+ TrafficSelector selector = DefaultTrafficSelector.builder()
+ .matchVlanId(vlanId)
+ .matchInPort(inPort)
+ .build();
+
+ TrafficTreatment.Builder treatmentBuilder = DefaultTrafficTreatment.builder();
+
+ outPorts.forEach(p -> treatmentBuilder.setOutput(p));
+
+ ForwardingObjective objective = DefaultForwardingObjective.builder()
+ .fromApp(appId)
+ .makePermanent()
+ .withFlag(ForwardingObjective.Flag.VERSATILE)
+ .withPriority(PRIORITY)
+ .withSelector(selector)
+ .withTreatment(treatmentBuilder.build())
+ .remove(new ObjectiveHandler());
+
+ flowObjectiveService.forward(deviceId, objective);
+ }
+
+ private static class ObjectiveHandler implements ObjectiveContext {
+ private static Logger log = LoggerFactory.getLogger(ObjectiveHandler.class);
+
+ @Override
+ public void onSuccess(Objective objective) {
+ log.info("Flow objective operation successful: {}", objective);
+ }
+
+ @Override
+ public void onError(Objective objective, ObjectiveError error) {
+ log.info("Flow objective operation failed: {}", objective);
+ }
+ }
+
+ /**
+ * Internal listener for device service events.
+ */
+ private class InternalDeviceListener implements DeviceListener {
+ @Override
+ public void event(DeviceEvent event) {
+ switch (event.type()) {
+ case DEVICE_ADDED:
+ case DEVICE_AVAILABILITY_CHANGED:
+ if (event.subject().id().equals(fabricDeviceId) &&
+ deviceService.isAvailable(event.subject().id())) {
+ setupDefaultFlows();
+ }
+ default:
+ break;
+ }
+ }
+ }
+}
diff --git a/framework/src/onos/apps/cordfabric/src/main/java/org/onosproject/cordfabric/FabricService.java b/framework/src/onos/apps/cordfabric/src/main/java/org/onosproject/cordfabric/FabricService.java
new file mode 100644
index 00000000..5c2ce25c
--- /dev/null
+++ b/framework/src/onos/apps/cordfabric/src/main/java/org/onosproject/cordfabric/FabricService.java
@@ -0,0 +1,50 @@
+/*
+ * 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.cordfabric;
+
+import org.onlab.packet.VlanId;
+
+import java.util.List;
+
+/**
+ * Service used to interact with fabric.
+ */
+public interface FabricService {
+
+ /**
+ * Remaps a vlan to the specified ports. The specified ports will be the
+ * only ports in this vlan once the operation completes.
+ *
+ * @param vlan vlan object to add
+ */
+ void addVlan(FabricVlan vlan);
+
+ /**
+ * Removes a vlan from all ports in the fabric.
+ *
+ * @param vlanId ID of vlan to remove
+ */
+ void removeVlan(VlanId vlanId);
+
+ /**
+ * Returns the vlan to port mapping for all vlans/ports configured in the
+ * fabric.
+ *
+ * @return mapping of vlan to port
+ */
+ List<FabricVlan> getVlans();
+}
diff --git a/framework/src/onos/apps/cordfabric/src/main/java/org/onosproject/cordfabric/FabricVlan.java b/framework/src/onos/apps/cordfabric/src/main/java/org/onosproject/cordfabric/FabricVlan.java
new file mode 100644
index 00000000..a5cfc07f
--- /dev/null
+++ b/framework/src/onos/apps/cordfabric/src/main/java/org/onosproject/cordfabric/FabricVlan.java
@@ -0,0 +1,57 @@
+/*
+ * 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.cordfabric;
+
+import com.google.common.collect.ImmutableList;
+import org.onlab.packet.VlanId;
+import org.onosproject.net.ConnectPoint;
+
+import java.util.Collection;
+import java.util.List;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+/**
+ * Vlan which spans multiple fabric ports.
+ */
+public class FabricVlan {
+
+ private final VlanId vlan;
+
+ private final List<ConnectPoint> ports;
+ private final boolean iptv;
+
+ public FabricVlan(VlanId vlan, Collection<ConnectPoint> ports, boolean iptv) {
+ checkNotNull(vlan);
+ checkNotNull(ports);
+ this.vlan = vlan;
+ this.ports = ImmutableList.copyOf(ports);
+ this.iptv = iptv;
+ }
+
+ public VlanId vlan() {
+ return vlan;
+ }
+
+ public List<ConnectPoint> ports() {
+ return ports;
+ }
+
+ public boolean iptv() {
+ return iptv;
+ }
+}
diff --git a/framework/src/onos/apps/cordfabric/src/main/java/org/onosproject/cordfabric/FabricVlanCodec.java b/framework/src/onos/apps/cordfabric/src/main/java/org/onosproject/cordfabric/FabricVlanCodec.java
new file mode 100644
index 00000000..00736bca
--- /dev/null
+++ b/framework/src/onos/apps/cordfabric/src/main/java/org/onosproject/cordfabric/FabricVlanCodec.java
@@ -0,0 +1,68 @@
+/*
+ * 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.cordfabric;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.node.ArrayNode;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import org.onlab.packet.VlanId;
+import org.onosproject.codec.CodecContext;
+import org.onosproject.codec.JsonCodec;
+import org.onosproject.net.ConnectPoint;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+/**
+ * Codec for encoding/decoding a FabricVlan object to/from JSON.
+ */
+public final class FabricVlanCodec extends JsonCodec<FabricVlan> {
+
+ // JSON field names
+ private static final String VLAN = "vlan";
+ private static final String PORTS = "ports";
+ private static final String IPTV = "iptv";
+
+ @Override
+ public ObjectNode encode(FabricVlan vlan, CodecContext context) {
+ checkNotNull(vlan, "Vlan cannot be null");
+ final ObjectNode result = context.mapper().createObjectNode()
+ .put(VLAN, vlan.vlan().toShort());
+
+ final ArrayNode jsonPorts = result.putArray(PORTS);
+
+ vlan.ports().forEach(cp -> jsonPorts.add(context.codec(ConnectPoint.class).encode(cp, context)));
+
+ return result;
+ }
+
+ @Override
+ public FabricVlan decode(ObjectNode json, CodecContext context) {
+ short vlan = json.path(VLAN).shortValue();
+ boolean iptv = json.path(IPTV).booleanValue();
+ List<ConnectPoint> ports = new ArrayList<>();
+
+ ArrayNode portArray = (ArrayNode) json.path(PORTS);
+ for (JsonNode o : portArray) {
+ ports.add(context.codec(ConnectPoint.class).decode((ObjectNode) o, context));
+ }
+
+ return new FabricVlan(VlanId.vlanId(vlan), ports, iptv);
+ }
+}
diff --git a/framework/src/onos/apps/cordfabric/src/main/java/org/onosproject/cordfabric/FabricWebResource.java b/framework/src/onos/apps/cordfabric/src/main/java/org/onosproject/cordfabric/FabricWebResource.java
new file mode 100644
index 00000000..c35d975b
--- /dev/null
+++ b/framework/src/onos/apps/cordfabric/src/main/java/org/onosproject/cordfabric/FabricWebResource.java
@@ -0,0 +1,99 @@
+/*
+ * 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.cordfabric;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import org.onlab.packet.VlanId;
+import org.onosproject.rest.AbstractWebResource;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.DELETE;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.List;
+
+/**
+ * Web resource for interacting with the fabric.
+ */
+@Path("vlans")
+public class FabricWebResource extends AbstractWebResource {
+
+ private static final FabricVlanCodec VLAN_CODEC = new FabricVlanCodec();
+
+ /**
+ * Get all CORD fabric VLANs.
+ *
+ * @return array of cord VLANs in the system.
+ */
+ @GET
+ @Produces(MediaType.APPLICATION_JSON)
+ public Response getVlans() {
+ FabricService fabricService = get(FabricService.class);
+ List<FabricVlan> vlans = fabricService.getVlans();
+ ObjectNode result = new ObjectMapper().createObjectNode();
+ result.set("vlans", new FabricVlanCodec().encode(vlans, this));
+
+ return ok(result.toString()).build();
+ }
+
+ /**
+ * Create a CORD fabric VLAN.
+ *
+ * @param input JSON stream describing new VLAN
+ * @return status of the request - CREATED if the JSON is correct,
+ * INTERNAL_SERVER_ERROR if the JSON is invalid
+ * @throws IOException if the JSON is invalid
+ */
+ @POST
+ @Path("add")
+ @Consumes(MediaType.APPLICATION_JSON)
+ public Response addVlan(InputStream input) throws IOException {
+ ObjectMapper mapper = new ObjectMapper();
+ ObjectNode vlanJson = (ObjectNode) mapper.readTree(input);
+ FabricService fabricService = get(FabricService.class);
+
+ fabricService.addVlan(VLAN_CODEC.decode(vlanJson, this));
+
+ return Response.ok().build();
+ }
+
+ /**
+ * Delete a CORD fabric VLAN.
+ *
+ * @param vlan identifier of the VLAN to remove
+ * @return status of the request - OK
+ */
+ @DELETE
+ @Path("{vlan}")
+ public Response deleteVlan(@PathParam("vlan") String vlan) {
+ VlanId vlanId = VlanId.vlanId(Short.parseShort(vlan));
+
+ FabricService fabricService = get(FabricService.class);
+
+ fabricService.removeVlan(vlanId);
+
+ return Response.ok().build();
+ }
+}
diff --git a/framework/src/onos/apps/cordfabric/src/main/java/org/onosproject/cordfabric/cli/FabricAddCommand.java b/framework/src/onos/apps/cordfabric/src/main/java/org/onosproject/cordfabric/cli/FabricAddCommand.java
new file mode 100644
index 00000000..e8cc6419
--- /dev/null
+++ b/framework/src/onos/apps/cordfabric/src/main/java/org/onosproject/cordfabric/cli/FabricAddCommand.java
@@ -0,0 +1,64 @@
+/*
+ * 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.cordfabric.cli;
+
+import org.apache.karaf.shell.commands.Argument;
+import org.apache.karaf.shell.commands.Command;
+import org.onlab.packet.VlanId;
+import org.onosproject.cli.AbstractShellCommand;
+import org.onosproject.cordfabric.FabricService;
+import org.onosproject.cordfabric.FabricVlan;
+import org.onosproject.net.ConnectPoint;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Adds a vlan to the fabric.
+ */
+@Command(scope = "onos", name = "add-fabric-vlan",
+ description = "Adds a VLAN to the fabric")
+public class FabricAddCommand extends AbstractShellCommand {
+
+ @Argument(index = 0, name = "vlanid", description = "VLAN ID",
+ required = true, multiValued = false)
+ private String vlanIdString = null;
+
+ @Argument(index = 1, name = "ports",
+ description = "List of ports in the VLAN",
+ required = true, multiValued = true)
+ private String[] portStrings = null;
+
+ @Override
+ protected void execute() {
+ FabricService service = AbstractShellCommand.get(FabricService.class);
+
+ VlanId vlan = VlanId.vlanId(Short.parseShort(vlanIdString));
+
+ if (portStrings.length < 2) {
+ throw new IllegalArgumentException("Must have at least 2 ports");
+ }
+
+ List<ConnectPoint> ports = new ArrayList<>(portStrings.length);
+
+ for (String portString : portStrings) {
+ ports.add(ConnectPoint.deviceConnectPoint(portString));
+ }
+
+ service.addVlan(new FabricVlan(vlan, ports, false));
+ }
+}
diff --git a/framework/src/onos/apps/cordfabric/src/main/java/org/onosproject/cordfabric/cli/FabricRemoveCommand.java b/framework/src/onos/apps/cordfabric/src/main/java/org/onosproject/cordfabric/cli/FabricRemoveCommand.java
new file mode 100644
index 00000000..9e470442
--- /dev/null
+++ b/framework/src/onos/apps/cordfabric/src/main/java/org/onosproject/cordfabric/cli/FabricRemoveCommand.java
@@ -0,0 +1,44 @@
+/*
+ * 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.cordfabric.cli;
+
+import org.apache.karaf.shell.commands.Argument;
+import org.apache.karaf.shell.commands.Command;
+import org.onlab.packet.VlanId;
+import org.onosproject.cli.AbstractShellCommand;
+import org.onosproject.cordfabric.FabricService;
+
+/**
+ * Removes a vlan from the fabric.
+ */
+@Command(scope = "onos", name = "remove-fabric-vlan",
+ description = "Removes a VLAN from the fabric")
+public class FabricRemoveCommand extends AbstractShellCommand {
+
+ @Argument(index = 0, name = "vlanid", description = "VLAN ID",
+ required = true, multiValued = false)
+ private String vlanIdString = null;
+
+ @Override
+ protected void execute() {
+ FabricService service = AbstractShellCommand.get(FabricService.class);
+
+ VlanId vlan = VlanId.vlanId(Short.parseShort(vlanIdString));
+
+ service.removeVlan(vlan);
+ }
+}
diff --git a/framework/src/onos/apps/cordfabric/src/main/java/org/onosproject/cordfabric/cli/FabricShowCommand.java b/framework/src/onos/apps/cordfabric/src/main/java/org/onosproject/cordfabric/cli/FabricShowCommand.java
new file mode 100644
index 00000000..f632a883
--- /dev/null
+++ b/framework/src/onos/apps/cordfabric/src/main/java/org/onosproject/cordfabric/cli/FabricShowCommand.java
@@ -0,0 +1,47 @@
+/*
+ * 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.cordfabric.cli;
+
+import org.apache.karaf.shell.commands.Command;
+import org.onosproject.cli.AbstractShellCommand;
+import org.onosproject.cordfabric.FabricService;
+import org.onosproject.cordfabric.FabricVlan;
+
+import java.util.List;
+
+/**
+ * Shows the vlans in the fabric.
+ */
+@Command(scope = "onos", name = "fabric",
+ description = "Shows the fabric vlans")
+public class FabricShowCommand extends AbstractShellCommand {
+
+ private static final String VLAN_HEADER_LINE_FORMAT = "VLAN %s";
+ private static final String PORT_LINE_FORMAT = "\t%s";
+
+ @Override
+ protected void execute() {
+ FabricService service = AbstractShellCommand.get(FabricService.class);
+
+ List<FabricVlan> vlans = service.getVlans();
+
+ vlans.forEach(fabricVlan -> {
+ print(VLAN_HEADER_LINE_FORMAT, fabricVlan.vlan());
+ fabricVlan.ports().forEach(cp -> print(PORT_LINE_FORMAT, cp));
+ });
+ }
+}
diff --git a/framework/src/onos/apps/cordfabric/src/main/java/org/onosproject/cordfabric/cli/package-info.java b/framework/src/onos/apps/cordfabric/src/main/java/org/onosproject/cordfabric/cli/package-info.java
new file mode 100644
index 00000000..e86ee9ef
--- /dev/null
+++ b/framework/src/onos/apps/cordfabric/src/main/java/org/onosproject/cordfabric/cli/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.
+ */
+
+/**
+ * Console commands for managing fabric of VLANs.
+ */
+package org.onosproject.cordfabric.cli; \ No newline at end of file
diff --git a/framework/src/onos/apps/cordfabric/src/main/java/org/onosproject/cordfabric/package-info.java b/framework/src/onos/apps/cordfabric/src/main/java/org/onosproject/cordfabric/package-info.java
new file mode 100644
index 00000000..d895f1f3
--- /dev/null
+++ b/framework/src/onos/apps/cordfabric/src/main/java/org/onosproject/cordfabric/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.
+ */
+
+/**
+ * Service for managing fabric of VLANs.
+ */
+package org.onosproject.cordfabric; \ No newline at end of file
diff --git a/framework/src/onos/apps/cordfabric/src/main/resources/OSGI-INF/blueprint/shell-config.xml b/framework/src/onos/apps/cordfabric/src/main/resources/OSGI-INF/blueprint/shell-config.xml
new file mode 100644
index 00000000..128f8612
--- /dev/null
+++ b/framework/src/onos/apps/cordfabric/src/main/resources/OSGI-INF/blueprint/shell-config.xml
@@ -0,0 +1,36 @@
+<!--
+ ~ 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.
+ -->
+<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0">
+
+ <command-bundle xmlns="http://karaf.apache.org/xmlns/shell/v1.1.0">
+ <command>
+ <action class="org.onosproject.cordfabric.cli.FabricShowCommand"/>
+ </command>
+ <command>
+ <action class="org.onosproject.cordfabric.cli.FabricAddCommand"/>
+ <completers>
+ <ref component-id="placeholderCompleter"/>
+ <ref component-id="connectPointCompleter"/>
+ </completers>
+ </command>
+ <command>
+ <action class="org.onosproject.cordfabric.cli.FabricRemoveCommand"/>
+ </command>
+ </command-bundle>
+
+ <bean id="connectPointCompleter" class="org.onosproject.cli.net.ConnectPointCompleter"/>
+ <bean id="placeholderCompleter" class="org.onosproject.cli.PlaceholderCompleter"/>
+</blueprint>
diff --git a/framework/src/onos/apps/cordfabric/src/main/webapp/WEB-INF/web.xml b/framework/src/onos/apps/cordfabric/src/main/webapp/WEB-INF/web.xml
new file mode 100644
index 00000000..06d3a355
--- /dev/null
+++ b/framework/src/onos/apps/cordfabric/src/main/webapp/WEB-INF/web.xml
@@ -0,0 +1,44 @@
+<?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.
+ -->
+<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee"
+ xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
+ xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
+ id="ONOS" version="2.5">
+ <display-name>CORD Fabric REST API v1.0</display-name>
+
+ <servlet>
+ <servlet-name>JAX-RS Service</servlet-name>
+ <servlet-class>com.sun.jersey.spi.container.servlet.ServletContainer</servlet-class>
+ <init-param>
+ <param-name>com.sun.jersey.config.property.resourceConfigClass</param-name>
+ <param-value>com.sun.jersey.api.core.ClassNamesResourceConfig</param-value>
+ </init-param>
+ <init-param>
+ <param-name>com.sun.jersey.config.property.classnames</param-name>
+ <param-value>
+ org.onosproject.cordfabric.FabricWebResource
+ </param-value>
+ </init-param>
+ <load-on-startup>1</load-on-startup>
+ </servlet>
+
+ <servlet-mapping>
+ <servlet-name>JAX-RS Service</servlet-name>
+ <url-pattern>/*</url-pattern>
+ </servlet-mapping>
+
+</web-app>