diff options
372 files changed, 17306 insertions, 2349 deletions
diff --git a/framework/src/onos/apps/aaa/src/main/java/org/onosproject/aaa/AAA.java b/framework/src/onos/apps/aaa/src/main/java/org/onosproject/aaa/AAA.java index 72a5b122..567944a6 100644 --- a/framework/src/onos/apps/aaa/src/main/java/org/onosproject/aaa/AAA.java +++ b/framework/src/onos/apps/aaa/src/main/java/org/onosproject/aaa/AAA.java @@ -419,6 +419,7 @@ public class AAA { * Handles RADIUS packets. * * @param radiusPacket RADIUS packet coming from the RADIUS server. + * @throws StateMachineException if an illegal state transition is triggered */ protected void handleRadiusPacket(RADIUS radiusPacket) throws StateMachineException { StateMachine stateMachine = StateMachine.lookupStateMachineById(radiusPacket.getIdentifier()); diff --git a/framework/src/onos/apps/cordvtn/src/main/java/org/onosproject/cordvtn/CordVtn.java b/framework/src/onos/apps/cordvtn/src/main/java/org/onosproject/cordvtn/CordVtn.java index 4b28a14b..e15bc763 100644 --- a/framework/src/onos/apps/cordvtn/src/main/java/org/onosproject/cordvtn/CordVtn.java +++ b/framework/src/onos/apps/cordvtn/src/main/java/org/onosproject/cordvtn/CordVtn.java @@ -23,17 +23,27 @@ 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.util.ItemNotFoundException; import org.onlab.util.KryoNamespace; import org.onosproject.cluster.ClusterService; import org.onosproject.core.ApplicationId; import org.onosproject.core.CoreService; +import org.onosproject.net.DefaultAnnotations; import org.onosproject.net.Device; import org.onosproject.net.DeviceId; import org.onosproject.net.Host; +import org.onosproject.net.behaviour.BridgeConfig; +import org.onosproject.net.behaviour.BridgeName; import org.onosproject.net.behaviour.ControllerInfo; +import org.onosproject.net.behaviour.DefaultTunnelDescription; +import org.onosproject.net.behaviour.TunnelConfig; +import org.onosproject.net.behaviour.TunnelDescription; +import org.onosproject.net.behaviour.TunnelName; import org.onosproject.net.device.DeviceEvent; import org.onosproject.net.device.DeviceListener; import org.onosproject.net.device.DeviceService; +import org.onosproject.net.driver.DriverHandler; +import org.onosproject.net.driver.DriverService; import org.onosproject.net.host.HostEvent; import org.onosproject.net.host.HostListener; import org.onosproject.net.host.HostService; @@ -58,6 +68,7 @@ import java.util.concurrent.Executors; import static com.google.common.base.Preconditions.checkNotNull; import static org.onlab.util.Tools.groupedThreads; import static org.onosproject.net.Device.Type.SWITCH; +import static org.onosproject.net.behaviour.TunnelDescription.Type.VXLAN; import static org.slf4j.LoggerFactory.getLogger; /** @@ -79,7 +90,6 @@ public class CordVtn implements CordVtnService { private static final Map<String, String> DEFAULT_TUNNEL_OPTIONS = new HashMap<String, String>() { { put("key", "flow"); - put("local_ip", "flow"); put("remote_ip", "flow"); } }; @@ -99,6 +109,9 @@ public class CordVtn implements CordVtnService { protected HostService hostService; @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + protected DriverService driverService; + + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) protected OvsdbController controller; @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) @@ -213,8 +226,8 @@ public class CordVtn implements CordVtnService { if (deviceService.getDevice(ovsdb.intBrId()) == null || !deviceService.isAvailable(ovsdb.intBrId())) { createIntegrationBridge(ovsdb); - } else if (!checkVxlanPort(ovsdb)) { - createVxlanPort(ovsdb); + } else if (!checkVxlanInterface(ovsdb)) { + createVxlanInterface(ovsdb); } } @@ -272,26 +285,41 @@ public class CordVtn implements CordVtnService { }); String dpid = ovsdb.intBrId().toString().substring(DPID_BEGIN); - // TODO change to use bridge config - OvsdbClientService ovsdbClient = getOvsdbClient(ovsdb); - ovsdbClient.createBridge(DEFAULT_BRIDGE_NAME, dpid, controllers); + try { + DriverHandler handler = driverService.createHandler(ovsdb.deviceId()); + BridgeConfig bridgeConfig = handler.behaviour(BridgeConfig.class); + bridgeConfig.addBridge(BridgeName.bridgeName(DEFAULT_BRIDGE_NAME), dpid, controllers); + } catch (ItemNotFoundException e) { + log.warn("Failed to create integration bridge on {}", ovsdb.deviceId()); + } } - private void createVxlanPort(OvsdbNode ovsdb) { - // TODO change to use tunnel config and tunnel description - OvsdbClientService ovsdbClient = getOvsdbClient(ovsdb); - ovsdbClient.createTunnel(DEFAULT_BRIDGE_NAME, DEFAULT_TUNNEL, - DEFAULT_TUNNEL, DEFAULT_TUNNEL_OPTIONS); + private void createVxlanInterface(OvsdbNode ovsdb) { + DefaultAnnotations.Builder optionBuilder = DefaultAnnotations.builder(); + for (String key : DEFAULT_TUNNEL_OPTIONS.keySet()) { + optionBuilder.set(key, DEFAULT_TUNNEL_OPTIONS.get(key)); + } + TunnelDescription description = + new DefaultTunnelDescription(null, null, VXLAN, + TunnelName.tunnelName(DEFAULT_TUNNEL), + optionBuilder.build()); + try { + DriverHandler handler = driverService.createHandler(ovsdb.deviceId()); + TunnelConfig tunnelConfig = handler.behaviour(TunnelConfig.class); + tunnelConfig.createTunnelInterface(BridgeName.bridgeName(DEFAULT_BRIDGE_NAME), description); + } catch (ItemNotFoundException e) { + log.warn("Failed to create VXLAN interface on {}", ovsdb.deviceId()); + } } - private boolean checkVxlanPort(OvsdbNode ovsdb) { - // TODO change to use tunnel config - OvsdbClientService ovsdbClient = getOvsdbClient(ovsdb); + private boolean checkVxlanInterface(OvsdbNode ovsdb) { try { - ovsdbClient.getPorts().stream() - .filter(p -> p.portName().value().equals(DEFAULT_TUNNEL)) - .findFirst().get(); - } catch (NoSuchElementException e) { + DriverHandler handler = driverService.createHandler(ovsdb.deviceId()); + BridgeConfig bridgeConfig = handler.behaviour(BridgeConfig.class); + bridgeConfig.getPorts().stream() + .filter(p -> p.annotations().value("portName").equals(DEFAULT_TUNNEL)) + .findAny().get(); + } catch (ItemNotFoundException | NoSuchElementException e) { return false; } return true; @@ -374,8 +402,8 @@ public class CordVtn implements CordVtnService { return; } - if (!checkVxlanPort(ovsdb)) { - createVxlanPort(ovsdb); + if (!checkVxlanInterface(ovsdb)) { + createVxlanInterface(ovsdb); } } diff --git a/framework/src/onos/apps/cordvtn/src/main/java/org/onosproject/cordvtn/CordVtnConfigManager.java b/framework/src/onos/apps/cordvtn/src/main/java/org/onosproject/cordvtn/CordVtnConfigManager.java index 287f2a34..274ca9b4 100644 --- a/framework/src/onos/apps/cordvtn/src/main/java/org/onosproject/cordvtn/CordVtnConfigManager.java +++ b/framework/src/onos/apps/cordvtn/src/main/java/org/onosproject/cordvtn/CordVtnConfigManager.java @@ -72,8 +72,6 @@ public class CordVtnConfigManager { configService.addListener(configListener); configRegistry.registerConfigFactory(configFactory); - - readConfiguration(); } @Deactivate @@ -101,7 +99,22 @@ public class CordVtnConfigManager { @Override public void event(NetworkConfigEvent event) { - // TODO handle update event + if (!event.configClass().equals(CordVtnConfig.class)) { + return; + } + + switch (event.type()) { + case CONFIG_ADDED: + log.info("Network configuration added"); + readConfiguration(); + break; + case CONFIG_UPDATED: + log.info("Network configuration updated"); + readConfiguration(); + break; + default: + break; + } } } } diff --git a/framework/src/onos/apps/cordvtn/src/main/java/org/onosproject/cordvtn/DefaultOvsdbNode.java b/framework/src/onos/apps/cordvtn/src/main/java/org/onosproject/cordvtn/DefaultOvsdbNode.java index eba52108..46f6e29c 100644 --- a/framework/src/onos/apps/cordvtn/src/main/java/org/onosproject/cordvtn/DefaultOvsdbNode.java +++ b/framework/src/onos/apps/cordvtn/src/main/java/org/onosproject/cordvtn/DefaultOvsdbNode.java @@ -61,7 +61,7 @@ public class DefaultOvsdbNode implements OvsdbNode { @Override public DeviceId deviceId() { - return DeviceId.deviceId("ovsdb:" + this.ip.toString() + ":" + this.port.toString()); + return DeviceId.deviceId("ovsdb:" + this.ip.toString()); } @Override diff --git a/framework/src/onos/apps/dhcp/api/pom.xml b/framework/src/onos/apps/dhcp/api/pom.xml new file mode 100644 index 00000000..fb5246f7 --- /dev/null +++ b/framework/src/onos/apps/dhcp/api/pom.xml @@ -0,0 +1,64 @@ +<?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/xsd/maven-4.0.0.xsd"> + <modelVersion>4.0.0</modelVersion> + + <parent> + <artifactId>onos-dhcp</artifactId> + <groupId>org.onosproject</groupId> + <version>1.4.0-SNAPSHOT</version> + <relativePath>../pom.xml</relativePath> + </parent> + + <artifactId>onos-app-dhcp-api</artifactId> + <packaging>bundle</packaging> + + <url>http://onosproject.org</url> + + <description>DHCP Server application API</description> + + <dependencies> + <dependency> + <groupId>org.onosproject</groupId> + <artifactId>onlab-junit</artifactId> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.onosproject</groupId> + <artifactId>onos-core-serializers</artifactId> + <version>${project.version}</version> + </dependency> + + <dependency> + <groupId>org.onosproject</groupId> + <artifactId>onos-incubator-api</artifactId> + <version>${project.version}</version> + </dependency> + <dependency> + <groupId>org.onosproject</groupId> + <artifactId>onos-api</artifactId> + <version>${project.version}</version> + <classifier>tests</classifier> + <scope>test</scope> + </dependency> + + </dependencies> + + +</project> diff --git a/framework/src/onos/apps/dhcp/src/main/java/org/onosproject/dhcp/DhcpService.java b/framework/src/onos/apps/dhcp/api/src/main/java/org/onosproject/dhcp/DhcpService.java index 7c2127f9..7c2127f9 100644 --- a/framework/src/onos/apps/dhcp/src/main/java/org/onosproject/dhcp/DhcpService.java +++ b/framework/src/onos/apps/dhcp/api/src/main/java/org/onosproject/dhcp/DhcpService.java diff --git a/framework/src/onos/apps/dhcp/src/main/java/org/onosproject/dhcp/DhcpStore.java b/framework/src/onos/apps/dhcp/api/src/main/java/org/onosproject/dhcp/DhcpStore.java index e263b3a2..e263b3a2 100644 --- a/framework/src/onos/apps/dhcp/src/main/java/org/onosproject/dhcp/DhcpStore.java +++ b/framework/src/onos/apps/dhcp/api/src/main/java/org/onosproject/dhcp/DhcpStore.java diff --git a/framework/src/onos/apps/dhcp/src/main/java/org/onosproject/dhcp/IpAssignment.java b/framework/src/onos/apps/dhcp/api/src/main/java/org/onosproject/dhcp/IpAssignment.java index 9b3aa686..9b3aa686 100644 --- a/framework/src/onos/apps/dhcp/src/main/java/org/onosproject/dhcp/IpAssignment.java +++ b/framework/src/onos/apps/dhcp/api/src/main/java/org/onosproject/dhcp/IpAssignment.java diff --git a/framework/src/onos/apps/dhcp/src/main/java/org/onosproject/dhcp/package-info.java b/framework/src/onos/apps/dhcp/api/src/main/java/org/onosproject/dhcp/package-info.java index 56778a35..56778a35 100644 --- a/framework/src/onos/apps/dhcp/src/main/java/org/onosproject/dhcp/package-info.java +++ b/framework/src/onos/apps/dhcp/api/src/main/java/org/onosproject/dhcp/package-info.java diff --git a/framework/src/onos/apps/dhcp/src/test/java/org/onosproject/dhcp/IpAssignmentTest.java b/framework/src/onos/apps/dhcp/api/src/test/java/org/onosproject/dhcp/IpAssignmentTest.java index 3ecc5cfa..3ecc5cfa 100644 --- a/framework/src/onos/apps/dhcp/src/test/java/org/onosproject/dhcp/IpAssignmentTest.java +++ b/framework/src/onos/apps/dhcp/api/src/test/java/org/onosproject/dhcp/IpAssignmentTest.java diff --git a/framework/src/onos/apps/dhcp/app/app.xml b/framework/src/onos/apps/dhcp/app/app.xml new file mode 100644 index 00000000..bf324b19 --- /dev/null +++ b/framework/src/onos/apps/dhcp/app/app.xml @@ -0,0 +1,23 @@ +<?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.dhcp" 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}/${project.artifactId}/${project.version}</artifact> + <artifact>mvn:${project.groupId}/onos-app-dhcp-api/${project.version}</artifact> +</app> diff --git a/framework/src/onos/apps/dhcp/app/features.xml b/framework/src/onos/apps/dhcp/app/features.xml new file mode 100644 index 00000000..0b277dea --- /dev/null +++ b/framework/src/onos/apps/dhcp/app/features.xml @@ -0,0 +1,25 @@ +<?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:${project.groupId}/onos-app-dhcp-api/${project.version}</bundle> + <bundle>mvn:${project.groupId}/onos-app-dhcp/${project.version}</bundle> + </feature> +</features> diff --git a/framework/src/onos/apps/dhcp/app/pom.xml b/framework/src/onos/apps/dhcp/app/pom.xml new file mode 100644 index 00000000..6589402a --- /dev/null +++ b/framework/src/onos/apps/dhcp/app/pom.xml @@ -0,0 +1,166 @@ +<?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/xsd/maven-4.0.0.xsd"> + <modelVersion>4.0.0</modelVersion> + + <parent> + <artifactId>onos-dhcp</artifactId> + <groupId>org.onosproject</groupId> + <version>1.4.0-SNAPSHOT</version> + <relativePath>../pom.xml</relativePath> + </parent> + + <artifactId>onos-app-dhcp</artifactId> + <packaging>bundle</packaging> + + <url>http://onosproject.org</url> + + <description>DHCP Server application</description> + + <properties> + <onos.app.name>org.onosproject.dhcp</onos.app.name> + <web.context>/onos/dhcp</web.context> + <api.version>1.0.0</api.version> + <api.title>DHCP Server REST API</api.title> + <api.description> + APIs for interacting with the DHCP Server application. + </api.description> + <api.package>org.onosproject.dhcp.rest</api.package> + </properties> + + <dependencies> + <dependency> + <groupId>org.onosproject</groupId> + <artifactId>onos-app-dhcp-api</artifactId> + <version>${project.version}</version> + </dependency> + <dependency> + <groupId>org.osgi</groupId> + <artifactId>org.osgi.compendium</artifactId> + </dependency> + + <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> + <scope>compile</scope> + </dependency> + + <dependency> + <groupId>org.onosproject</groupId> + <artifactId>onlab-junit</artifactId> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.onosproject</groupId> + <artifactId>onos-core-serializers</artifactId> + <version>${project.version}</version> + </dependency> + + <dependency> + <groupId>org.onosproject</groupId> + <artifactId>onos-incubator-api</artifactId> + <version>${project.version}</version> + </dependency> + <dependency> + <groupId>org.onosproject</groupId> + <artifactId>onos-api</artifactId> + <version>${project.version}</version> + <classifier>tests</classifier> + <scope>test</scope> + </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> + </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, + com.fasterxml.jackson.core, + org.apache.karaf.shell.commands, + org.apache.karaf.shell.console, + 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/dhcp/src/main/java/org/onosproject/dhcp/cli/DhcpLeaseDetails.java b/framework/src/onos/apps/dhcp/app/src/main/java/org/onosproject/dhcp/cli/DhcpLeaseDetails.java index 95f49e69..95f49e69 100644 --- a/framework/src/onos/apps/dhcp/src/main/java/org/onosproject/dhcp/cli/DhcpLeaseDetails.java +++ b/framework/src/onos/apps/dhcp/app/src/main/java/org/onosproject/dhcp/cli/DhcpLeaseDetails.java diff --git a/framework/src/onos/apps/dhcp/src/main/java/org/onosproject/dhcp/cli/DhcpListAllMappings.java b/framework/src/onos/apps/dhcp/app/src/main/java/org/onosproject/dhcp/cli/DhcpListAllMappings.java index 209ba683..209ba683 100644 --- a/framework/src/onos/apps/dhcp/src/main/java/org/onosproject/dhcp/cli/DhcpListAllMappings.java +++ b/framework/src/onos/apps/dhcp/app/src/main/java/org/onosproject/dhcp/cli/DhcpListAllMappings.java diff --git a/framework/src/onos/apps/dhcp/src/main/java/org/onosproject/dhcp/cli/DhcpRemoveStaticMapping.java b/framework/src/onos/apps/dhcp/app/src/main/java/org/onosproject/dhcp/cli/DhcpRemoveStaticMapping.java index a92cd250..a92cd250 100644 --- a/framework/src/onos/apps/dhcp/src/main/java/org/onosproject/dhcp/cli/DhcpRemoveStaticMapping.java +++ b/framework/src/onos/apps/dhcp/app/src/main/java/org/onosproject/dhcp/cli/DhcpRemoveStaticMapping.java diff --git a/framework/src/onos/apps/dhcp/src/main/java/org/onosproject/dhcp/cli/DhcpSetStaticMapping.java b/framework/src/onos/apps/dhcp/app/src/main/java/org/onosproject/dhcp/cli/DhcpSetStaticMapping.java index 9f4f6580..9f4f6580 100644 --- a/framework/src/onos/apps/dhcp/src/main/java/org/onosproject/dhcp/cli/DhcpSetStaticMapping.java +++ b/framework/src/onos/apps/dhcp/app/src/main/java/org/onosproject/dhcp/cli/DhcpSetStaticMapping.java diff --git a/framework/src/onos/apps/dhcp/src/main/java/org/onosproject/dhcp/cli/FreeIpCompleter.java b/framework/src/onos/apps/dhcp/app/src/main/java/org/onosproject/dhcp/cli/FreeIpCompleter.java index 228d70fd..228d70fd 100644 --- a/framework/src/onos/apps/dhcp/src/main/java/org/onosproject/dhcp/cli/FreeIpCompleter.java +++ b/framework/src/onos/apps/dhcp/app/src/main/java/org/onosproject/dhcp/cli/FreeIpCompleter.java diff --git a/framework/src/onos/apps/dhcp/src/main/java/org/onosproject/dhcp/cli/MacIdCompleter.java b/framework/src/onos/apps/dhcp/app/src/main/java/org/onosproject/dhcp/cli/MacIdCompleter.java index d6cd73a7..d6cd73a7 100644 --- a/framework/src/onos/apps/dhcp/src/main/java/org/onosproject/dhcp/cli/MacIdCompleter.java +++ b/framework/src/onos/apps/dhcp/app/src/main/java/org/onosproject/dhcp/cli/MacIdCompleter.java diff --git a/framework/src/onos/apps/dhcp/src/main/java/org/onosproject/dhcp/cli/package-info.java b/framework/src/onos/apps/dhcp/app/src/main/java/org/onosproject/dhcp/cli/package-info.java index f8780195..f8780195 100644 --- a/framework/src/onos/apps/dhcp/src/main/java/org/onosproject/dhcp/cli/package-info.java +++ b/framework/src/onos/apps/dhcp/app/src/main/java/org/onosproject/dhcp/cli/package-info.java diff --git a/framework/src/onos/apps/dhcp/src/main/java/org/onosproject/dhcp/impl/DhcpConfig.java b/framework/src/onos/apps/dhcp/app/src/main/java/org/onosproject/dhcp/impl/DhcpConfig.java index 4353d623..4353d623 100644 --- a/framework/src/onos/apps/dhcp/src/main/java/org/onosproject/dhcp/impl/DhcpConfig.java +++ b/framework/src/onos/apps/dhcp/app/src/main/java/org/onosproject/dhcp/impl/DhcpConfig.java diff --git a/framework/src/onos/apps/dhcp/src/main/java/org/onosproject/dhcp/impl/DhcpManager.java b/framework/src/onos/apps/dhcp/app/src/main/java/org/onosproject/dhcp/impl/DhcpManager.java index 96d94a2b..96d94a2b 100644 --- a/framework/src/onos/apps/dhcp/src/main/java/org/onosproject/dhcp/impl/DhcpManager.java +++ b/framework/src/onos/apps/dhcp/app/src/main/java/org/onosproject/dhcp/impl/DhcpManager.java diff --git a/framework/src/onos/apps/dhcp/src/main/java/org/onosproject/dhcp/impl/DhcpUi.java b/framework/src/onos/apps/dhcp/app/src/main/java/org/onosproject/dhcp/impl/DhcpUi.java index bb2bd2c2..bb2bd2c2 100644 --- a/framework/src/onos/apps/dhcp/src/main/java/org/onosproject/dhcp/impl/DhcpUi.java +++ b/framework/src/onos/apps/dhcp/app/src/main/java/org/onosproject/dhcp/impl/DhcpUi.java diff --git a/framework/src/onos/apps/dhcp/src/main/java/org/onosproject/dhcp/impl/DhcpViewMessageHandler.java b/framework/src/onos/apps/dhcp/app/src/main/java/org/onosproject/dhcp/impl/DhcpViewMessageHandler.java index 9ce65d5e..9ce65d5e 100644 --- a/framework/src/onos/apps/dhcp/src/main/java/org/onosproject/dhcp/impl/DhcpViewMessageHandler.java +++ b/framework/src/onos/apps/dhcp/app/src/main/java/org/onosproject/dhcp/impl/DhcpViewMessageHandler.java diff --git a/framework/src/onos/apps/dhcp/src/main/java/org/onosproject/dhcp/impl/DistributedDhcpStore.java b/framework/src/onos/apps/dhcp/app/src/main/java/org/onosproject/dhcp/impl/DistributedDhcpStore.java index 63f69d40..63f69d40 100644 --- a/framework/src/onos/apps/dhcp/src/main/java/org/onosproject/dhcp/impl/DistributedDhcpStore.java +++ b/framework/src/onos/apps/dhcp/app/src/main/java/org/onosproject/dhcp/impl/DistributedDhcpStore.java diff --git a/framework/src/onos/apps/dhcp/src/main/java/org/onosproject/dhcp/impl/package-info.java b/framework/src/onos/apps/dhcp/app/src/main/java/org/onosproject/dhcp/impl/package-info.java index 12e14e48..12e14e48 100644 --- a/framework/src/onos/apps/dhcp/src/main/java/org/onosproject/dhcp/impl/package-info.java +++ b/framework/src/onos/apps/dhcp/app/src/main/java/org/onosproject/dhcp/impl/package-info.java diff --git a/framework/src/onos/apps/dhcp/src/main/java/org/onosproject/dhcp/rest/DHCPWebResource.java b/framework/src/onos/apps/dhcp/app/src/main/java/org/onosproject/dhcp/rest/DHCPWebResource.java index 646ab7ea..646ab7ea 100644 --- a/framework/src/onos/apps/dhcp/src/main/java/org/onosproject/dhcp/rest/DHCPWebResource.java +++ b/framework/src/onos/apps/dhcp/app/src/main/java/org/onosproject/dhcp/rest/DHCPWebResource.java diff --git a/framework/src/onos/apps/dhcp/src/main/java/org/onosproject/dhcp/rest/package-info.java b/framework/src/onos/apps/dhcp/app/src/main/java/org/onosproject/dhcp/rest/package-info.java index 73173c55..73173c55 100644 --- a/framework/src/onos/apps/dhcp/src/main/java/org/onosproject/dhcp/rest/package-info.java +++ b/framework/src/onos/apps/dhcp/app/src/main/java/org/onosproject/dhcp/rest/package-info.java diff --git a/framework/src/onos/apps/dhcp/src/main/resources/OSGI-INF/blueprint/shell-config.xml b/framework/src/onos/apps/dhcp/app/src/main/resources/OSGI-INF/blueprint/shell-config.xml index ce716315..ce716315 100644 --- a/framework/src/onos/apps/dhcp/src/main/resources/OSGI-INF/blueprint/shell-config.xml +++ b/framework/src/onos/apps/dhcp/app/src/main/resources/OSGI-INF/blueprint/shell-config.xml diff --git a/framework/src/onos/apps/dhcp/src/main/resources/app/view/dhcp/dhcp.css b/framework/src/onos/apps/dhcp/app/src/main/resources/app/view/dhcp/dhcp.css index e0a29314..e0a29314 100644 --- a/framework/src/onos/apps/dhcp/src/main/resources/app/view/dhcp/dhcp.css +++ b/framework/src/onos/apps/dhcp/app/src/main/resources/app/view/dhcp/dhcp.css diff --git a/framework/src/onos/apps/dhcp/src/main/resources/app/view/dhcp/dhcp.html b/framework/src/onos/apps/dhcp/app/src/main/resources/app/view/dhcp/dhcp.html index 5782badf..5782badf 100644 --- a/framework/src/onos/apps/dhcp/src/main/resources/app/view/dhcp/dhcp.html +++ b/framework/src/onos/apps/dhcp/app/src/main/resources/app/view/dhcp/dhcp.html diff --git a/framework/src/onos/apps/dhcp/src/main/resources/app/view/dhcp/dhcp.js b/framework/src/onos/apps/dhcp/app/src/main/resources/app/view/dhcp/dhcp.js index 061d0de6..061d0de6 100644 --- a/framework/src/onos/apps/dhcp/src/main/resources/app/view/dhcp/dhcp.js +++ b/framework/src/onos/apps/dhcp/app/src/main/resources/app/view/dhcp/dhcp.js diff --git a/framework/src/onos/apps/dhcp/src/main/resources/gui/css.html b/framework/src/onos/apps/dhcp/app/src/main/resources/gui/css.html index d02ad44a..d02ad44a 100644 --- a/framework/src/onos/apps/dhcp/src/main/resources/gui/css.html +++ b/framework/src/onos/apps/dhcp/app/src/main/resources/gui/css.html diff --git a/framework/src/onos/apps/dhcp/src/main/resources/gui/js.html b/framework/src/onos/apps/dhcp/app/src/main/resources/gui/js.html index d37b5768..d37b5768 100644 --- a/framework/src/onos/apps/dhcp/src/main/resources/gui/js.html +++ b/framework/src/onos/apps/dhcp/app/src/main/resources/gui/js.html diff --git a/framework/src/onos/apps/dhcp/src/main/webapp/WEB-INF/web.xml b/framework/src/onos/apps/dhcp/app/src/main/webapp/WEB-INF/web.xml index 27504548..27504548 100644 --- a/framework/src/onos/apps/dhcp/src/main/webapp/WEB-INF/web.xml +++ b/framework/src/onos/apps/dhcp/app/src/main/webapp/WEB-INF/web.xml diff --git a/framework/src/onos/apps/dhcp/src/test/java/org/onosproject/dhcp/impl/DhcpManagerTest.java b/framework/src/onos/apps/dhcp/app/src/test/java/org/onosproject/dhcp/impl/DhcpManagerTest.java index fd4701c6..fd4701c6 100644 --- a/framework/src/onos/apps/dhcp/src/test/java/org/onosproject/dhcp/impl/DhcpManagerTest.java +++ b/framework/src/onos/apps/dhcp/app/src/test/java/org/onosproject/dhcp/impl/DhcpManagerTest.java diff --git a/framework/src/onos/apps/dhcp/src/test/resources/dhcp-cfg.json b/framework/src/onos/apps/dhcp/app/src/test/resources/dhcp-cfg.json index abc48a83..abc48a83 100644 --- a/framework/src/onos/apps/dhcp/src/test/resources/dhcp-cfg.json +++ b/framework/src/onos/apps/dhcp/app/src/test/resources/dhcp-cfg.json diff --git a/framework/src/onos/apps/dhcp/pom.xml b/framework/src/onos/apps/dhcp/pom.xml index 0daa4f7b..7a10776e 100644 --- a/framework/src/onos/apps/dhcp/pom.xml +++ b/framework/src/onos/apps/dhcp/pom.xml @@ -13,149 +13,30 @@ ~ 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"> + --> +<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> - <artifactId>onos-apps</artifactId> <groupId>org.onosproject</groupId> + <artifactId>onos-apps</artifactId> <version>1.4.0-SNAPSHOT</version> <relativePath>../pom.xml</relativePath> </parent> - <artifactId>onos-app-dhcp</artifactId> - <packaging>bundle</packaging> - - <url>http://onosproject.org</url> + <artifactId>onos-dhcp</artifactId> + <packaging>pom</packaging> - <description>DHCP Server application</description> + <description>ONOS sample applications</description> - <properties> - <onos.app.name>org.onosproject.dhcp</onos.app.name> - <web.context>/onos/dhcp</web.context> - <api.version>1.0.0</api.version> - <api.title>DHCP Server REST API</api.title> - <api.description> - APIs for interacting with the DHCP Server application. - </api.description> - <api.package>org.onosproject.dhcp.rest</api.package> - </properties> + <modules> + <module>api</module> + <module>app</module> + </modules> <dependencies> - <dependency> - <groupId>org.osgi</groupId> - <artifactId>org.osgi.compendium</artifactId> - </dependency> - - <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> - <scope>compile</scope> - </dependency> - - <dependency> - <groupId>org.onosproject</groupId> - <artifactId>onlab-junit</artifactId> - <scope>test</scope> - </dependency> - <dependency> - <groupId>org.onosproject</groupId> - <artifactId>onos-core-serializers</artifactId> - <version>${project.version}</version> - </dependency> - - <dependency> - <groupId>org.onosproject</groupId> - <artifactId>onos-incubator-api</artifactId> - <version>${project.version}</version> - </dependency> - <dependency> - <groupId>org.onosproject</groupId> - <artifactId>onos-api</artifactId> - <version>${project.version}</version> - <classifier>tests</classifier> - <scope>test</scope> - </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> </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, - com.fasterxml.jackson.core, - org.apache.karaf.shell.commands, - org.apache.karaf.shell.console, - 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/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/tunnel/package-info.java b/framework/src/onos/apps/igmp/src/main/java/org/onosproject/igmp/impl/package-info.java index 3a84e6e3..7d420198 100644 --- a/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/tunnel/package-info.java +++ b/framework/src/onos/apps/igmp/src/main/java/org/onosproject/igmp/impl/package-info.java @@ -15,6 +15,6 @@ */ /** - * Service for interacting with the inventory of subnets. + * IGMP implementation. */ -package org.onosproject.vtnrsc.tunnel; +package org.onosproject.igmp.impl; diff --git a/framework/src/onos/apps/mfwd/src/main/java/org/onosproject/mfwd/rest/package-info.java b/framework/src/onos/apps/mfwd/src/main/java/org/onosproject/mfwd/rest/package-info.java new file mode 100644 index 00000000..b42586fe --- /dev/null +++ b/framework/src/onos/apps/mfwd/src/main/java/org/onosproject/mfwd/rest/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. + */ + +/** + * REST API for multicase forwarding. + */ +package org.onosproject.mfwd.rest; diff --git a/framework/src/onos/apps/mlb/src/main/java/org/onosproject/mlb/package-info.java b/framework/src/onos/apps/mlb/src/main/java/org/onosproject/mlb/package-info.java new file mode 100644 index 00000000..a7d83757 --- /dev/null +++ b/framework/src/onos/apps/mlb/src/main/java/org/onosproject/mlb/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. + */ + +/** + * Mastership load balancer. + */ +package org.onosproject.mlb; diff --git a/framework/src/onos/apps/openstackswitching/pom.xml b/framework/src/onos/apps/openstackswitching/pom.xml new file mode 100644 index 00000000..245b9e80 --- /dev/null +++ b/framework/src/onos/apps/openstackswitching/pom.xml @@ -0,0 +1,121 @@ +<?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-apps</artifactId> + <version>1.4.0-SNAPSHOT</version> + <relativePath>../pom.xml</relativePath> + </parent> + + <artifactId>onos-app-openstackswitching</artifactId> + <packaging>bundle</packaging> + + <description>SONA Openstack Switching applications</description> + <properties> + <onos.version>1.4.0-SNAPSHOT</onos.version> + <onos.app.name>org.onosproject.openstackswitching</onos.app.name> + <web.context>/onos/openstackswitching</web.context> + <api.version>1.0.0</api.version> + <api.title>ONOS OpenStack Switching REST API</api.title> + <api.description> + APIs for receiving Neutron information. + </api.description> + <api.package>org.onosproject.openstackswitching.web</api.package> + <onos.app.origin>SKT, Inc.</onos.app.origin> + </properties> + + + <dependencies> + <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> + <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, + com.fasterxml.jackson.core, + org.apache.karaf.shell.commands, + com.google.common.*, + org.onlab.packet.*, + org.onosproject.* + </Import-Package> + <Web-ContextPath>${web.context}</Web-ContextPath> + </instructions> + </configuration> + </plugin> + </plugins> + </build> + + +</project> diff --git a/framework/src/onos/apps/openstackswitching/src/main/java/org/onosproject/openstackswitching/OpenstackArpHandler.java b/framework/src/onos/apps/openstackswitching/src/main/java/org/onosproject/openstackswitching/OpenstackArpHandler.java new file mode 100644 index 00000000..afaf7a22 --- /dev/null +++ b/framework/src/onos/apps/openstackswitching/src/main/java/org/onosproject/openstackswitching/OpenstackArpHandler.java @@ -0,0 +1,51 @@ +/* +* 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.openstackswitching; + +import org.onosproject.net.packet.InboundPacket; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.HashMap; + +/** + * It handles ARP packet from VMs. + */ +public class OpenstackArpHandler { + + private static Logger log = LoggerFactory + .getLogger(OpenstackArpHandler.class); + + HashMap<String, OpenstackPort> openstackPortHashMap; + + /** + * Constructs an OpenstackArpHandler. + * + * @param openstackPortMap port map + */ + public OpenstackArpHandler(HashMap<String, OpenstackPort> openstackPortMap) { + this.openstackPortHashMap = openstackPortMap; + } + + /** + * Processes ARP packets. + * + * @param pkt ARP request packet + */ + public void processPacketIn(InboundPacket pkt) { + log.warn("Received an ARP packet"); + } +} diff --git a/framework/src/onos/apps/openstackswitching/src/main/java/org/onosproject/openstackswitching/OpenstackDhcpHandler.java b/framework/src/onos/apps/openstackswitching/src/main/java/org/onosproject/openstackswitching/OpenstackDhcpHandler.java new file mode 100644 index 00000000..9c3641c1 --- /dev/null +++ b/framework/src/onos/apps/openstackswitching/src/main/java/org/onosproject/openstackswitching/OpenstackDhcpHandler.java @@ -0,0 +1,45 @@ +/* +* 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.openstackswitching; + +import org.onosproject.net.packet.InboundPacket; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * It handles DHCP request packets. + */ +public class OpenstackDhcpHandler { + + private static Logger log = LoggerFactory + .getLogger(OpenstackDhcpHandler.class); + + /** + * Returns OpenstackDhcpHandler reference. + */ + public OpenstackDhcpHandler() { + + } + + /** + * Processes DHCP request packets. + * + * @param pkt DHCP request packet + */ + public void processPacketIn(InboundPacket pkt) { + log.warn("Received a DHCP packet"); + } +} diff --git a/framework/src/onos/apps/openstackswitching/src/main/java/org/onosproject/openstackswitching/OpenstackNetwork.java b/framework/src/onos/apps/openstackswitching/src/main/java/org/onosproject/openstackswitching/OpenstackNetwork.java new file mode 100644 index 00000000..dc7c0263 --- /dev/null +++ b/framework/src/onos/apps/openstackswitching/src/main/java/org/onosproject/openstackswitching/OpenstackNetwork.java @@ -0,0 +1,112 @@ +/* + * 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.openstackswitching; + +import static com.google.common.base.Preconditions.checkNotNull; + + +/** + * Represents the network information given by Neutron. + */ +public final class OpenstackNetwork { + + private String name; + private String tenantId; + private String segmentId; + private String networkType; + private String id; + + /** + * Returns the builder object of the OpenstackNetwork class. + * + * @return OpenstackNetwork builder object + */ + public static OpenstackNetwork.Builder builder() { + return new Builder(); + } + + private OpenstackNetwork(String name, String tenantId, String id, String sid, + String type) { + this.name = checkNotNull(name); + this.tenantId = checkNotNull(tenantId); + this.segmentId = checkNotNull(sid); + this.id = checkNotNull(id); + this.networkType = checkNotNull(type); + } + + public String name() { + return this.name; + } + + public String tenantId() { + return this.tenantId; + } + + public String id() { + return this.id; + } + + public String segmentId() { + return this.segmentId; + } + + public String networkType() { + return this.networkType; + } + + public static final class Builder { + private String name; + private String tenantId; + private String id; + private String sid; + private String networkType; + + public Builder name(String name) { + this.name = name; + + return this; + } + + public Builder tenantId(String tenantId) { + this.tenantId = tenantId; + + return this; + } + + public Builder id(String id) { + this.id = id; + + return this; + } + + public Builder segmentId(String sid) { + this.sid = sid; + + return this; + } + + public Builder networkType(String type) { + this.networkType = type; + + return this; + } + + public OpenstackNetwork build() { + return new OpenstackNetwork(name, tenantId, id, sid, networkType); + } + + } +} diff --git a/framework/src/onos/apps/openstackswitching/src/main/java/org/onosproject/openstackswitching/OpenstackPort.java b/framework/src/onos/apps/openstackswitching/src/main/java/org/onosproject/openstackswitching/OpenstackPort.java new file mode 100644 index 00000000..4326b4fc --- /dev/null +++ b/framework/src/onos/apps/openstackswitching/src/main/java/org/onosproject/openstackswitching/OpenstackPort.java @@ -0,0 +1,350 @@ +/* + * 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.openstackswitching; + +import com.google.common.collect.Lists; +import org.onlab.packet.Ip4Address; +import org.onlab.packet.MacAddress; + +import java.util.HashMap; +import java.util.List; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * It represents the Openstack Port information. + */ +public final class OpenstackPort { + + public enum PortStatus { + UP, + DOWN + } + + private PortStatus status; + private String name; + // FIX_ME + private String allowedAddressPairs; + private boolean adminStateUp; + private String networkId; + private String tenantId; + private String deviceOwner; + private MacAddress macAddress; + // <subnet id, ip address> + private HashMap<String, Ip4Address> fixedIps; + private String id; + private List<String> securityGroups; + private String deviceId; + + private OpenstackPort(PortStatus status, String name, boolean adminStateUp, + String networkId, String tenantId, String deviceOwner, + MacAddress macAddress, HashMap fixedIps, String id, + List<String> securityGroups, String deviceId) { + + this.status = status; + this.name = name; + this.adminStateUp = adminStateUp; + this.networkId = checkNotNull(networkId); + this.tenantId = checkNotNull(tenantId); + this.deviceOwner = deviceOwner; + this.macAddress = checkNotNull(macAddress); + this.fixedIps = checkNotNull(fixedIps); + this.id = checkNotNull(id); + this.securityGroups = securityGroups; + this.deviceId = deviceId; + } + + + + /** + * Returns OpenstackPort builder object. + * + * @return OpenstackPort builder + */ + public static OpenstackPort.Builder builder() { + return new Builder(); + } + + /** + * Returns port status. + * + * @return port status + */ + public PortStatus status() { + return status; + } + + /** + * Returns port name. + * + * @return port name + */ + public String name() { + return name; + } + + /** + * Returns whether admin state up or not. + * + * @return true if admin state up, false otherwise + */ + public boolean isAdminStateUp() { + return adminStateUp; + } + + /** + * Returns network ID. + * + * @return network ID + */ + public String networkId() { + return networkId; + } + + /** + * Returns device owner. + * + * @return device owner + */ + public String deviceOwner() { + return deviceOwner; + } + + /** + * Returns mac address. + * + * @return mac address + */ + public MacAddress macAddress() { + return macAddress; + } + + /** + * Returns the fixed IP information. + * + * @return fixed IP info + */ + public HashMap fixedIps() { + return fixedIps; + } + + /** + * Returns port ID. + * + * @return port ID + */ + public String id() { + return id; + } + + /** + * Returns security group information. + * + * @return security group info + */ + public List<String> securityGroups() { + return securityGroups; + } + + /** + * Returns device ID. + * + * @return device ID + */ + public String deviceId() { + return deviceId; + } + + // TODO : Implement the following functions when necessary + //@Override + //public void equals(Object that) { + // + //} + // + //@Override + //public int hashCode() { + // + //} + + /** + * OpenstackPort Builder class. + */ + public static final class Builder { + + private PortStatus status; + private String name; + // FIX_ME + private String allowedAddressPairs; + private boolean adminStateUp; + private String networkId; + private String tenantId; + private String deviceOwner; + private MacAddress macAddress; + // list of hash map <subnet id, ip address> + private HashMap<String, Ip4Address> fixedIps; + private String id; + private List<String> securityGroups; + private String deviceId; + + Builder() { + fixedIps = new HashMap<>(); + securityGroups = Lists.newArrayList(); + } + + /** + * Sets port status. + * + * @param status port status + * @return Builder object + */ + public Builder portStatus(PortStatus status) { + this.status = status; + + return this; + } + + /** + * Sets port name. + * + * @param name port name + * @return Builder object + */ + public Builder name(String name) { + this.name = name; + + return this; + } + + /** + * Sets whether admin state up or not. + * + * @param isAdminStateUp true if admin state is up, false otherwise + * @return Builder object + */ + public Builder adminState(boolean isAdminStateUp) { + this.adminStateUp = isAdminStateUp; + + return this; + } + + /** + * Sets network ID. + * + * @param networkId network ID + * @return Builder object + */ + public Builder netwrokId(String networkId) { + this.networkId = networkId; + + return this; + } + + /** + * Sets tenant ID. + * + * @param tenantId tenant ID + * @return Builder object + */ + public Builder tenantId(String tenantId) { + this.tenantId = tenantId; + + return this; + } + + /** + * Sets device owner. + * + * @param owner device owner + * @return Builder object + */ + public Builder deviceOwner(String owner) { + this.deviceOwner = owner; + + return this; + } + + /** + * Sets MAC address of the port. + * + * @param mac MAC address + * @return Builder object + */ + public Builder macAddress(MacAddress mac) { + this.macAddress = mac; + + return this; + } + + /** + * Sets Fixed IP address information. + * + * @param fixedIpList Fixed IP info + * @return Builder object + */ + public Builder fixedIps(HashMap<String, Ip4Address> fixedIpList) { + fixedIps.putAll(fixedIpList); + + return this; + } + + /** + * Sets ID of the port. + * + * @param id ID of the port + * @return Builder object + */ + public Builder id(String id) { + this.id = id; + + return this; + } + + /** + * Sets security group of the port. + * + * @param securityGroup security group of the port + * @return Builder object + */ + public Builder securityGroup(String securityGroup) { + securityGroups.add(securityGroup); + + return this; + } + + /** + * Sets device ID of the port. + * + * @param deviceId device ID + * @return Builder object + */ + public Builder deviceId(String deviceId) { + this.deviceId = deviceId; + + return this; + } + + /** + * Builds an OpenstackPort object. + * + * @return OpenstackPort objecet + */ + public OpenstackPort build() { + return new OpenstackPort(status, name, adminStateUp, networkId, networkId, + deviceOwner, macAddress, fixedIps, id, securityGroups, deviceId); + } + } +} + diff --git a/framework/src/onos/apps/openstackswitching/src/main/java/org/onosproject/openstackswitching/OpenstackSwitchingManager.java b/framework/src/onos/apps/openstackswitching/src/main/java/org/onosproject/openstackswitching/OpenstackSwitchingManager.java new file mode 100644 index 00000000..baae7f80 --- /dev/null +++ b/framework/src/onos/apps/openstackswitching/src/main/java/org/onosproject/openstackswitching/OpenstackSwitchingManager.java @@ -0,0 +1,437 @@ +/* + * 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.openstackswitching; + +import com.google.common.collect.Lists; +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.apache.felix.scr.annotations.Service; +import org.onlab.packet.Ethernet; +import org.onlab.packet.IPv4; +import org.onlab.packet.Ip4Address; +import org.onlab.packet.Ip4Prefix; +import org.onlab.packet.MacAddress; +import org.onlab.packet.UDP; +import org.onosproject.core.ApplicationId; +import org.onosproject.core.CoreService; +import org.onosproject.net.Device; +import org.onosproject.net.DeviceId; +import org.onosproject.net.Port; +import org.onosproject.net.device.DeviceEvent; +import org.onosproject.net.device.DeviceListener; +import org.onosproject.net.device.DeviceService; +import org.onosproject.net.flowobjective.FlowObjectiveService; +import org.onosproject.net.packet.InboundPacket; +import org.onosproject.net.packet.PacketContext; +import org.onosproject.net.packet.PacketProcessor; +import org.onosproject.net.packet.PacketService; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.HashMap; +import java.util.List; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; + +@SuppressWarnings("ALL") +@Service +@Component(immediate = true) +/** + * It populates forwarding rules for VMs created by Openstack. + */ +public class OpenstackSwitchingManager implements OpenstackSwitchingService { + + private static Logger log = LoggerFactory + .getLogger(OpenstackSwitchingManager.class); + + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + protected CoreService coreService; + + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + protected PacketService packetService; + + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + protected DeviceService deviceService; + + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + protected FlowObjectiveService flowObjectiveService; + + + public static final int DHCP_PORT = 67; + + private ApplicationId appId; + private OpenstackArpHandler arpHandler; + private OpenstackDhcpHandler dhcpHandler = new OpenstackDhcpHandler(); + private OpenstackSwitchingRulePopulator rulePopulator; + private ExecutorService deviceEventExcutorService = Executors.newFixedThreadPool(10); + + private InternalPacketProcessor internalPacketProcessor = new InternalPacketProcessor(); + private InternalDeviceListener internalDeviceListener = new InternalDeviceListener(); + + // Map <port_id, OpenstackPort> + private HashMap<String, OpenstackPort> openstackPortMap; + // Map <network_id, OpenstackNetwork> + private HashMap<String, OpenstackNetwork> openstackNetworkMap; + // Map <vni, List <Entry <portName, host ip>> + private HashMap<String, List<PortInfo>> vniPortMap; + private HashMap<Ip4Address, Port> tunnelPortMap; + + + @Activate + protected void activate() { + appId = coreService + .registerApplication("org.onosproject.openstackswitching"); + rulePopulator = new OpenstackSwitchingRulePopulator(appId, flowObjectiveService); + packetService.addProcessor(internalPacketProcessor, PacketProcessor.director(1)); + deviceService.addListener(internalDeviceListener); + + openstackPortMap = Maps.newHashMap(); + openstackNetworkMap = Maps.newHashMap(); + vniPortMap = Maps.newHashMap(); + tunnelPortMap = Maps.newHashMap(); + + arpHandler = new OpenstackArpHandler(openstackPortMap); + + log.info("Started"); + } + + @Deactivate + protected void deactivate() { + packetService.removeProcessor(internalPacketProcessor); + deviceService.removeListener(internalDeviceListener); + + deviceEventExcutorService.shutdown(); + + log.info("Stopped"); + } + + @Override + public void createPorts(OpenstackPort openstackPort) { + openstackPortMap.put(openstackPort.id(), openstackPort); + } + + @Override + public void deletePorts() { + + } + + @Override + public void updatePorts() { + + } + + @Override + public void createNetwork(OpenstackNetwork openstackNetwork) { + openstackNetworkMap.put(openstackNetwork.id(), openstackNetwork); + } + + private void processDeviceAdded(Device device) { + log.warn("device {} is added", device.id()); + rulePopulator.populateDefaultRules(device.id()); + } + + private void processPortAdded(Device device, Port port) { + // TODO: Simplify the data structure to store the network info + // TODO: Make it stateless + // TODO: All the logics need to be processed inside of the rulePopulator class + synchronized (vniPortMap) { + log.warn("port {} is updated", port.toString()); + + updatePortMaps(device, port); + if (!port.annotations().value("portName").equals("vxlan")) { + populateFlowRulesForTrafficToSameCnode(device, port); + populateFlowRulesForTrafficToDifferentCnode(device, port); + } + } + } + + private void processPortRemoved(Device device, Port port) { + log.warn("port {} is removed", port.toString()); + // TODO: need to update the vniPortMap + } + + /** + * Populates the flow rules for traffic to VMs in different Cnode using + * Nicira extention. + * + * @param device device to put rules + * @param port port information of the VM + */ + private void populateFlowRulesForTrafficToDifferentCnode(Device device, Port port) { + String portName = port.annotations().value("portName"); + String channelId = device.annotations().value("channelId"); + Ip4Address hostIpAddress = Ip4Address.valueOf(channelId.split(":")[0]); + Ip4Address fixedIp = getFixedIpAddressForPort(portName); + // TODO: Avoid duplicate flow rule set up for VMs in other Cnode + // (possibly avoided by flowrule subsystem?) + if (tunnelPortMap.get(hostIpAddress) == null) { + log.warn("There is no tunnel port information"); + return; + } + String vni = getVniForPort(portName); + MacAddress vmMac = getVmMacAddressForPort(portName); + if (!vniPortMap.isEmpty() && vniPortMap.get(vni) != null) { + for (PortInfo portInfo : vniPortMap.get(vni)) { + if (!portInfo.portName.equals(portName) && + !portInfo.hostIp.equals(hostIpAddress)) { + MacAddress vmMacx = getVmMacAddressForPort(portInfo.portName); + rulePopulator.populateForwardingRuleForOtherCnode(vni, + device.id(), portInfo.hostIp, portInfo.fixedIp, vmMacx, + tunnelPortMap.get(hostIpAddress).number(), + portInfo.deviceId, hostIpAddress, fixedIp, vmMac, + tunnelPortMap.get(portInfo.hostIp).number()); + } + } + } + } + + /** + * Populates the flow rules for traffic to VMs in the same Cnode as the sender. + * + * @param device device to put the rules + * @param port port info of the VM + */ + private void populateFlowRulesForTrafficToSameCnode(Device device, Port port) { + Ip4Prefix cidr = getCidrForPort(port.annotations().value("portName")); + Ip4Address vmIp = getFixedIpAddressForPort(port.annotations().value("portName")); + if (vmIp != null) { + rulePopulator.populateForwardingRule(vmIp, device.id(), port, cidr); + } + } + + /** + * Updates the port maps using the port information. + * + * @param device device info + * @param port port of the VM + */ + private void updatePortMaps(Device device, Port port) { + String portName = port.annotations().value("portName"); + String channelId = device.annotations().value("channelId"); + Ip4Address hostIpAddress = Ip4Address.valueOf(channelId.split(":")[0]); + if (portName.startsWith("vxlan")) { + tunnelPortMap.put(hostIpAddress, port); + } else { + String vni = getVniForPort(portName); + Ip4Address fixedIp = getFixedIpAddressForPort(portName); + if (vniPortMap.get(vni) == null) { + vniPortMap.put(vni, Lists.newArrayList()); + } + vniPortMap.get(vni).add(new PortInfo(device.id(), portName, fixedIp, hostIpAddress)); + } + } + + /** + * Returns CIDR information from the subnet map for the port. + * + * @param portName port name of the port of the VM + * @return CIDR of the VNI of the VM + */ + private Ip4Prefix getCidrForPort(String portName) { + String networkId = null; + String uuid = portName.substring(3); + OpenstackPort port = openstackPortMap.values().stream() + .filter(p -> p.id().startsWith(uuid)) + .findFirst().get(); + if (port == null) { + log.warn("No port information for port {}", portName); + return null; + } + + //OpenstackSubnet subnet = openstackSubnetMap.values().stream() + // .filter(s -> s.networkId().equals(port.networkId())) + // .findFirst().get(); + //if (subnet == null) { + // log.warn("No subnet information for network {}", subnet.id()); + // return null; + //} + + //return Ip4Prefix.valueOf(subnet.cidr()); + return null; + } + + /** + * Returns the VNI of the VM of the port. + * + * @param portName VM port + * @return VNI + */ + private String getVniForPort(String portName) { + String networkId = null; + String uuid = portName.substring(3); + OpenstackPort port = openstackPortMap.values().stream() + .filter(p -> p.id().startsWith(uuid)) + .findFirst().get(); + if (port == null) { + log.warn("No port information for port {}", portName); + return null; + } + OpenstackNetwork network = openstackNetworkMap.values().stream() + .filter(n -> n.id().equals(port.networkId())) + .findFirst().get(); + if (network == null) { + log.warn("No VNI information for network {}", network.id()); + return null; + } + + return network.segmentId(); + } + + /** + * Returns the Fixed IP address of the VM. + * + * @param portName VM port info + * @return IP address of the VM + */ + private Ip4Address getFixedIpAddressForPort(String portName) { + + // FIXME - For now we use the information stored from neutron Rest API call. + // TODO - Later, the information needs to be extracted from Neutron on-demand. + String uuid = portName.substring(3); + OpenstackPort port = openstackPortMap.values().stream() + .filter(p -> p.id().startsWith(uuid)) + .findFirst().get(); + + if (port == null) { + log.error("There is no port information for port name {}", portName); + return null; + } + + if (port.fixedIps().isEmpty()) { + log.error("There is no fixed IP info in the port information"); + return null; + } + + return (Ip4Address) port.fixedIps().values().toArray()[0]; + } + + /** + * Returns the MAC address of the VM of the port. + * + * @param portName VM port + * @return MAC address of the VM + */ + private MacAddress getVmMacAddressForPort(String portName) { + + String uuid = portName.substring(3); + OpenstackPort port = openstackPortMap.values().stream() + .filter(p -> p.id().startsWith(uuid)) + .findFirst().get(); + + if (port == null) { + log.error("There is no mac information for port name {}", portName); + return null; + } + + return port.macAddress(); + } + + private class InternalPacketProcessor implements PacketProcessor { + + @Override + public void process(PacketContext context) { + + if (context.isHandled()) { + return; + } + + InboundPacket pkt = context.inPacket(); + Ethernet ethernet = pkt.parsed(); + + if (ethernet.getEtherType() == Ethernet.TYPE_ARP) { + arpHandler.processPacketIn(pkt); + } else if (ethernet.getEtherType() == Ethernet.TYPE_IPV4) { + IPv4 ipPacket = (IPv4) ethernet.getPayload(); + + if (ipPacket.getProtocol() == IPv4.PROTOCOL_UDP) { + UDP udpPacket = (UDP) ipPacket.getPayload(); + if (udpPacket.getDestinationPort() == DHCP_PORT) { + dhcpHandler.processPacketIn(pkt); + } + } + } + } + } + + private class InternalDeviceListener implements DeviceListener { + + @Override + public void event(DeviceEvent event) { + deviceEventExcutorService.execute(new InternalEventHandler(event)); + } + } + + private class InternalEventHandler implements Runnable { + + volatile DeviceEvent deviceEvent; + + InternalEventHandler(DeviceEvent deviceEvent) { + this.deviceEvent = deviceEvent; + } + + @Override + public void run() { + switch (deviceEvent.type()) { + case DEVICE_ADDED: + processDeviceAdded((Device) deviceEvent.subject()); + break; + case DEVICE_UPDATED: + Port port = (Port) deviceEvent.subject(); + if (port.isEnabled()) { + processPortAdded((Device) deviceEvent.subject(), deviceEvent.port()); + } + break; + case DEVICE_AVAILABILITY_CHANGED: + Device device = (Device) deviceEvent.subject(); + if (deviceService.isAvailable(device.id())) { + processDeviceAdded(device); + } + break; + case PORT_ADDED: + processPortAdded((Device) deviceEvent.subject(), deviceEvent.port()); + break; + case PORT_UPDATED: + processPortAdded((Device) deviceEvent.subject(), deviceEvent.port()); + break; + case PORT_REMOVED: + processPortRemoved((Device) deviceEvent.subject(), deviceEvent.port()); + break; + default: + break; + } + } + } + + private final class PortInfo { + DeviceId deviceId; + String portName; + Ip4Address fixedIp; + Ip4Address hostIp; + + private PortInfo(DeviceId deviceId, String portName, Ip4Address fixedIp, + Ip4Address hostIp) { + this.deviceId = deviceId; + this.portName = portName; + this.fixedIp = fixedIp; + this.hostIp = hostIp; + } + } + +}
\ No newline at end of file diff --git a/framework/src/onos/apps/openstackswitching/src/main/java/org/onosproject/openstackswitching/OpenstackSwitchingRulePopulator.java b/framework/src/onos/apps/openstackswitching/src/main/java/org/onosproject/openstackswitching/OpenstackSwitchingRulePopulator.java new file mode 100644 index 00000000..9ead05f0 --- /dev/null +++ b/framework/src/onos/apps/openstackswitching/src/main/java/org/onosproject/openstackswitching/OpenstackSwitchingRulePopulator.java @@ -0,0 +1,228 @@ +/* +* 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.openstackswitching; + +import org.onlab.packet.Ethernet; +import org.onlab.packet.IPv4; +import org.onlab.packet.Ip4Address; +import org.onlab.packet.Ip4Prefix; +import org.onlab.packet.MacAddress; +import org.onlab.packet.TpPort; +import org.onosproject.core.ApplicationId; +import org.onosproject.net.DeviceId; +import org.onosproject.net.Port; +import org.onosproject.net.PortNumber; +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.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * It populates switching flow rules. + * + */ +public class OpenstackSwitchingRulePopulator { + + private static Logger log = LoggerFactory + .getLogger(OpenstackSwitchingRulePopulator.class); + + private FlowObjectiveService flowObjectiveService; + private ApplicationId appId; + + /** + * Creates OpenstackSwitchingRulPopulator. + * + * @param appId application id + * @param flowObjectiveService FlowObjectiveService reference + */ + public OpenstackSwitchingRulePopulator(ApplicationId appId, + FlowObjectiveService flowObjectiveService) { + this.flowObjectiveService = flowObjectiveService; + this.appId = appId; + } + + /** + * Populates flows rules for forwarding packets to and from VMs. + * + * @param ip v4 IP Address + * @param id device ID + * @param port port + * @param cidr v4 IP prefix + * @return true if it succeeds to populate rules, false otherwise. + */ + public boolean populateForwardingRule(Ip4Address ip, DeviceId id, Port port, Ip4Prefix cidr) { + + + setFlowRuleForVMsInSameCnode(ip, id, port, cidr); + + return true; + } + + /** + * Populates the common flows rules for all VMs. + * + * - Send ARP packets to the controller + * - Send DHCP packets to the controller + * + * @param id Device ID to populates rules to + */ + public void populateDefaultRules(DeviceId id) { + + //setFlowRuleForDHCP(id); + setFlowRuleForArp(id); + + log.warn("Default rule has been set"); + } + + /** + * Populates the forwarding rules for VMs with the same VNI but in other Code. + * + * @param vni VNI for the networks + * @param id device ID to populates the flow rules + * @param hostIp host IP address of the VM + * @param vmIp fixed IP address for the VM + * @param vmMac MAC address for the VM + * @param tunnelPort tunnel port number for the VM + * @param idx device ID for OVS of the other VM + * @param hostIpx host IP address of the other VM + * @param vmIpx fixed IP address of the other VM + * @param vmMacx MAC address for the other VM + * @param tunnelPortx x tunnel port number for other VM + */ + public void populateForwardingRuleForOtherCnode(String vni, DeviceId id, Ip4Address hostIp, + Ip4Address vmIp, MacAddress vmMac, PortNumber tunnelPort, + DeviceId idx, Ip4Address hostIpx, + Ip4Address vmIpx, MacAddress vmMacx, PortNumber tunnelPortx) { + setVxLanFlowRule(vni, id, hostIp, vmIp, vmMac, tunnelPort); + setVxLanFlowRule(vni, idx, hostIpx, vmIpx, vmMacx, tunnelPortx); + } + + /** + * Populates the flow rules for DHCP packets from VMs. + * + * @param id device ID to set the rules + */ + private void setFlowRuleForDHCP(DeviceId id) { + TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder(); + TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder(); + + sBuilder.matchEthType(Ethernet.TYPE_IPV4) + .matchIPProtocol(IPv4.PROTOCOL_UDP) + .matchUdpDst(TpPort.tpPort(OpenstackSwitchingManager.DHCP_PORT)); + tBuilder.setOutput(PortNumber.CONTROLLER); + + ForwardingObjective fo = DefaultForwardingObjective.builder() + .withSelector(sBuilder.build()) + .withTreatment(tBuilder.build()) + .withPriority(5000) + .withFlag(ForwardingObjective.Flag.VERSATILE) + .fromApp(appId) + .add(); + + flowObjectiveService.forward(id, fo); + } + + /** + * Populates the flow rules for ARP packets from VMs. + * + * @param id device ID to put rules. + */ + private void setFlowRuleForArp(DeviceId id) { + TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder(); + TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder(); + + sBuilder.matchEthType(Ethernet.TYPE_ARP); + tBuilder.setOutput(PortNumber.CONTROLLER); + + ForwardingObjective fo = DefaultForwardingObjective.builder() + .withSelector(sBuilder.build()) + .withTreatment(tBuilder.build()) + .withPriority(5000) + .withFlag(ForwardingObjective.Flag.VERSATILE) + .fromApp(appId) + .add(); + + flowObjectiveService.forward(id, fo); + } + + /** + * Sets the flow rules for traffic between VMs in the same Cnode. + * + * @param ip4Address VM IP address + * @param id device ID to put rules + * @param port VM port + * @param cidr subnet info of the VMs + */ + private void setFlowRuleForVMsInSameCnode(Ip4Address ip4Address, DeviceId id, + Port port, Ip4Prefix cidr) { + TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder(); + TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder(); + + sBuilder.matchEthType(Ethernet.TYPE_IPV4) + .matchIPDst(ip4Address.toIpPrefix()) + .matchIPSrc(cidr); + tBuilder.setOutput(port.number()); + + ForwardingObjective fo = DefaultForwardingObjective.builder() + .withSelector(sBuilder.build()) + .withTreatment(tBuilder.build()) + .withPriority(5000) + .withFlag(ForwardingObjective.Flag.VERSATILE) + .fromApp(appId) + .add(); + + flowObjectiveService.forward(id, fo); + } + + /** + * Sets the flow rules between traffic from VMs in different Cnode. + * + * @param vni VNI + * @param id device ID + * @param hostIp host IP of the VM + * @param vmIp fixed IP of the VM + * @param vmMac MAC address of the VM + * @param tunnelPort tunnel port to forward traffic to + */ + private void setVxLanFlowRule(String vni, DeviceId id, Ip4Address hostIp, + Ip4Address vmIp, MacAddress vmMac, PortNumber tunnelPort) { + TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder(); + TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder(); + + sBuilder.matchEthType(Ethernet.TYPE_IPV4) + .matchIPDst(vmIp.toIpPrefix()); + tBuilder.setTunnelId(Long.parseLong(vni)) + //.setTunnelDst() <- for Nicira ext + //.setEthDst(vmMac) + .setOutput(tunnelPort); + + ForwardingObjective fo = DefaultForwardingObjective.builder() + .withSelector(sBuilder.build()) + .withTreatment(tBuilder.build()) + .withPriority(5000) + .withFlag(ForwardingObjective.Flag.VERSATILE) + .fromApp(appId) + .add(); + + flowObjectiveService.forward(id, fo); + } +} diff --git a/framework/src/onos/apps/openstackswitching/src/main/java/org/onosproject/openstackswitching/OpenstackSwitchingService.java b/framework/src/onos/apps/openstackswitching/src/main/java/org/onosproject/openstackswitching/OpenstackSwitchingService.java new file mode 100644 index 00000000..d97b39c8 --- /dev/null +++ b/framework/src/onos/apps/openstackswitching/src/main/java/org/onosproject/openstackswitching/OpenstackSwitchingService.java @@ -0,0 +1,49 @@ +/* + * 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.openstackswitching; + +/** + * It handles port management REST API from Openstack for VMs. + */ +public interface OpenstackSwitchingService { + + /** + * Store the port information created by Openstack. + * + * @param openstackPort port information + */ + void createPorts(OpenstackPort openstackPort); + + /** + * Removes flow rules corresponding to the port removed by Openstack. + * + */ + void deletePorts(); + + /** + * Updates flow rules corresponding to the port information updated by Openstack. + * + */ + void updatePorts(); + + /** + * Store the network information created by openstack. + * + * @param openstackNetwork network information + */ + void createNetwork(OpenstackNetwork openstackNetwork); + +} diff --git a/framework/src/onos/apps/openstackswitching/src/main/java/org/onosproject/openstackswitching/package-info.java b/framework/src/onos/apps/openstackswitching/src/main/java/org/onosproject/openstackswitching/package-info.java new file mode 100644 index 00000000..cd50f912 --- /dev/null +++ b/framework/src/onos/apps/openstackswitching/src/main/java/org/onosproject/openstackswitching/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. + */ + +/** + * OpenStack switch interface. + */ +package org.onosproject.openstackswitching; diff --git a/framework/src/onos/apps/openstackswitching/src/main/java/org/onosproject/openstackswitching/web/OpenstackNetworkCodec.java b/framework/src/onos/apps/openstackswitching/src/main/java/org/onosproject/openstackswitching/web/OpenstackNetworkCodec.java new file mode 100644 index 00000000..43bd1583 --- /dev/null +++ b/framework/src/onos/apps/openstackswitching/src/main/java/org/onosproject/openstackswitching/web/OpenstackNetworkCodec.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.openstackswitching.web; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.node.ObjectNode; +import org.onosproject.codec.CodecContext; +import org.onosproject.codec.JsonCodec; +import org.onosproject.openstackswitching.OpenstackNetwork; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Implementation of the OpenstackNetwork Codec. + * + */ +public class OpenstackNetworkCodec extends JsonCodec<OpenstackNetwork> { + + protected static final Logger log = LoggerFactory + .getLogger(OpenstackNetworkCodec.class); + + private static final String NETWORK = "network"; + private static final String NAME = "name"; + private static final String TENANT_ID = "tenant_id"; + private static final String SEGMENTATION_ID = "provider:segmentation_id"; + private static final String NETWORK_TYPE = "provider:network_type"; + private static final String ID = "id"; + + @Override + public OpenstackNetwork decode(ObjectNode json, CodecContext context) { + + JsonNode networkInfo = json.get(NETWORK); + + String name = networkInfo.path(NAME).asText(); + String tenantId = networkInfo.path(TENANT_ID).asText(); + String id = networkInfo.path(ID).asText(); + + OpenstackNetwork.Builder onb = OpenstackNetwork.builder(); + onb.name(name) + .tenantId(tenantId) + .id(id); + + if (!networkInfo.path(NETWORK_TYPE).isMissingNode()) { + onb.name(networkInfo.path(NETWORK_TYPE).asText()); + onb.segmentId(networkInfo.path(SEGMENTATION_ID).asText()); + } + + return onb.build(); + } + +} diff --git a/framework/src/onos/apps/openstackswitching/src/main/java/org/onosproject/openstackswitching/web/OpenstackNetworkWebResource.java b/framework/src/onos/apps/openstackswitching/src/main/java/org/onosproject/openstackswitching/web/OpenstackNetworkWebResource.java new file mode 100644 index 00000000..f4c401fb --- /dev/null +++ b/framework/src/onos/apps/openstackswitching/src/main/java/org/onosproject/openstackswitching/web/OpenstackNetworkWebResource.java @@ -0,0 +1,62 @@ +/* + * 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.openstackswitching.web; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.node.ObjectNode; +import org.onosproject.openstackswitching.OpenstackNetwork; +import org.onosproject.openstackswitching.OpenstackSwitchingService; +import org.onosproject.rest.AbstractWebResource; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.ws.rs.Consumes; +import javax.ws.rs.POST; +import javax.ws.rs.Path; +import javax.ws.rs.Produces; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; +import java.io.InputStream; + +@Path("networks") +public class OpenstackNetworkWebResource extends AbstractWebResource { + + protected static final Logger log = LoggerFactory + .getLogger(OpenstackNetworkWebResource.class); + + private static final OpenstackNetworkCodec NETWORK_CODEC = new OpenstackNetworkCodec(); + + @POST + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + public Response createNetwork(InputStream input) { + try { + ObjectMapper mapper = new ObjectMapper(); + ObjectNode networkNode = (ObjectNode) mapper.readTree(input); + + OpenstackNetwork openstackNetwork = NETWORK_CODEC.decode(networkNode, this); + + OpenstackSwitchingService switchingService = get(OpenstackSwitchingService.class); + switchingService.createNetwork(openstackNetwork); + return Response.status(Response.Status.OK).build(); + } catch (Exception e) { + log.error("Creates VirtualPort failed because of exception {}", + e.toString()); + return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(e.toString()) + .build(); + } + } +} diff --git a/framework/src/onos/apps/openstackswitching/src/main/java/org/onosproject/openstackswitching/web/OpenstackPortCodec.java b/framework/src/onos/apps/openstackswitching/src/main/java/org/onosproject/openstackswitching/web/OpenstackPortCodec.java new file mode 100644 index 00000000..765b6901 --- /dev/null +++ b/framework/src/onos/apps/openstackswitching/src/main/java/org/onosproject/openstackswitching/web/OpenstackPortCodec.java @@ -0,0 +1,104 @@ +/* + * 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.openstackswitching.web; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.node.ArrayNode; +import com.fasterxml.jackson.databind.node.ObjectNode; +import org.onlab.packet.Ip4Address; +import org.onlab.packet.MacAddress; +import org.onosproject.codec.CodecContext; +import org.onosproject.codec.JsonCodec; +import org.onosproject.openstackswitching.OpenstackPort; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.HashMap; + +/** + * It encodes and decodes the OpenstackPort. + */ +public class OpenstackPortCodec extends JsonCodec<OpenstackPort> { + + private static Logger log = LoggerFactory + .getLogger(OpenstackPortCodec.class); + + // JSON field names + private static final String PORT = "port"; + private static final String STATUS = "status"; + private static final String NAME = "name"; + private static final String ADDRESS_PAIR = "allowed_address_pairs"; + private static final String ADMIN_STATUS = "admin_status"; + private static final String NETWORK_ID = "network_id"; + private static final String TENANT_ID = "tenant_id"; + private static final String DEVICE_OWNER = "device_owner"; + private static final String MAC_ADDRESS = "mac_address"; + private static final String FIXED_IPS = "fixed_ips"; + private static final String SUBNET_ID = "subnet_id"; + private static final String IP_ADDRESS = "ip_address"; + private static final String ID = "id"; + private static final String SECURITY_GROUPS = "security_groups"; + private static final String DEVICE_ID = "device_id"; + + @Override + public OpenstackPort decode(ObjectNode json, CodecContext context) { + + HashMap<String, Ip4Address> fixedIpMap = new HashMap<>(); + JsonNode portInfo = json.get(PORT); + + String status = portInfo.path(STATUS).asText(); + String name = portInfo.path(NAME).asText(); + boolean adminStateUp = portInfo.path(ADMIN_STATUS).asBoolean(); + String networkId = portInfo.path(NETWORK_ID).asText(); + String tenantId = portInfo.path(TENANT_ID).asText(); + String deviceOwner = portInfo.path(DEVICE_OWNER).asText(); + String macStr = portInfo.path(MAC_ADDRESS).asText(); + ArrayNode fixedIpList = (ArrayNode) portInfo.path(FIXED_IPS); + for (JsonNode fixedIpInfo: fixedIpList) { + String subnetId = fixedIpInfo.path(SUBNET_ID).asText(); + String ipAddressStr = fixedIpInfo.path(IP_ADDRESS).asText(); + if (ipAddressStr != null) { + Ip4Address ipAddress = Ip4Address.valueOf(ipAddressStr); + fixedIpMap.put(subnetId, ipAddress); + } + } + String id = portInfo.path(ID).asText(); + String securityGroups = portInfo.path(SECURITY_GROUPS).asText(); + String deviceId = portInfo.path(DEVICE_ID).asText(); + + OpenstackPort.Builder openstackPortBuilder = OpenstackPort.builder(); + openstackPortBuilder.portStatus(OpenstackPort.PortStatus.valueOf(status)) + .name(name) + .adminState(adminStateUp) + .netwrokId(networkId) + .tenantId(tenantId) + .deviceOwner(deviceOwner) + .macAddress(MacAddress.valueOf(macStr)) + .fixedIps(fixedIpMap) + .id(id) + .deviceId(deviceId); + + // FIX ME + if (!securityGroups.isEmpty()) { + openstackPortBuilder.securityGroup(securityGroups); + } + + OpenstackPort openstackPort = openstackPortBuilder.build(); + + return openstackPort; + } + +} diff --git a/framework/src/onos/apps/openstackswitching/src/main/java/org/onosproject/openstackswitching/web/OpenstackPortWebResource.java b/framework/src/onos/apps/openstackswitching/src/main/java/org/onosproject/openstackswitching/web/OpenstackPortWebResource.java new file mode 100644 index 00000000..67a9cebb --- /dev/null +++ b/framework/src/onos/apps/openstackswitching/src/main/java/org/onosproject/openstackswitching/web/OpenstackPortWebResource.java @@ -0,0 +1,106 @@ +/* + * 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.openstackswitching.web; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.node.ObjectNode; +import org.onosproject.openstackswitching.OpenstackPort; +import org.onosproject.openstackswitching.OpenstackSwitchingService; +import org.onosproject.rest.AbstractWebResource; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.ws.rs.Consumes; +import javax.ws.rs.DELETE; +import javax.ws.rs.POST; +import javax.ws.rs.PUT; +import javax.ws.rs.Path; +import javax.ws.rs.Produces; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; +import java.io.InputStream; + +@Path("ports") +public class OpenstackPortWebResource extends AbstractWebResource { + + protected static final Logger log = LoggerFactory + .getLogger(OpenstackPortWebResource.class); + + private static final OpenstackPortCodec PORT_CODEC = new OpenstackPortCodec(); + + @POST + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + public Response createPorts(InputStream input) { + try { + ObjectMapper mapper = new ObjectMapper(); + ObjectNode portNode = (ObjectNode) mapper.readTree(input); + + OpenstackPort openstackPort = PORT_CODEC.decode(portNode, this); + + OpenstackSwitchingService switchingService = get(OpenstackSwitchingService.class); + switchingService.createPorts(openstackPort); + log.info("REST API ports is called with {}", portNode.toString()); + return Response.status(Response.Status.OK).build(); + } catch (Exception e) { + log.error("Creates VirtualPort failed because of exception {}", + e.toString()); + return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(e.toString()) + .build(); + } + } + + @DELETE + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + public Response deletesPorts(InputStream input) { + try { + ObjectMapper mapper = new ObjectMapper(); + ObjectNode portNode = (ObjectNode) mapper.readTree(input); + + OpenstackSwitchingService switchingService = get(OpenstackSwitchingService.class); + switchingService.deletePorts(); + log.info("REST API ports is called with {}", portNode.toString()); + return Response.status(Response.Status.OK).build(); + } catch (Exception e) { + log.error("Delete VirtualPort failed because of exception {}", + e.toString()); + return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(e.toString()) + .build(); + } + } + + @PUT + @Path("{id}") + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + public Response updatePorts(InputStream input) { + try { + ObjectMapper mapper = new ObjectMapper(); + ObjectNode portNode = (ObjectNode) mapper.readTree(input); + + OpenstackSwitchingService switchingService = get(OpenstackSwitchingService.class); + switchingService.updatePorts(); + log.info("REST API ports is called with {}", portNode.toString()); + return Response.status(Response.Status.OK).build(); + } catch (Exception e) { + log.error("Update VirtualPort failed because of exception {}", + e.toString()); + return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(e.toString()) + .build(); + } + } +} diff --git a/framework/src/onos/apps/openstackswitching/src/main/java/org/onosproject/openstackswitching/web/package-info.java b/framework/src/onos/apps/openstackswitching/src/main/java/org/onosproject/openstackswitching/web/package-info.java new file mode 100644 index 00000000..91e19c62 --- /dev/null +++ b/framework/src/onos/apps/openstackswitching/src/main/java/org/onosproject/openstackswitching/web/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. + */ + +/** + * OpenStack switching REST API. + */ +package org.onosproject.openstackswitching.web; diff --git a/framework/src/onos/apps/openstackswitching/src/main/webapp/WEB-INF/web.xml b/framework/src/onos/apps/openstackswitching/src/main/webapp/WEB-INF/web.xml new file mode 100644 index 00000000..53b0e2e9 --- /dev/null +++ b/framework/src/onos/apps/openstackswitching/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>Openstack Switching 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.openstackswitching.web.OpenstackPortWebResource, + org.onosproject.openstackswitching.web.OpenstackNetworkWebResource + </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> diff --git a/framework/src/onos/apps/optical/src/main/java/org/onosproject/optical/OpticalPathProvisioner.java b/framework/src/onos/apps/optical/src/main/java/org/onosproject/optical/OpticalPathProvisioner.java index 8466b95e..e0545023 100644 --- a/framework/src/onos/apps/optical/src/main/java/org/onosproject/optical/OpticalPathProvisioner.java +++ b/framework/src/onos/apps/optical/src/main/java/org/onosproject/optical/OpticalPathProvisioner.java @@ -15,6 +15,7 @@ */ package org.onosproject.optical; +import com.google.common.collect.ImmutableList; import org.apache.felix.scr.annotations.Activate; import org.apache.felix.scr.annotations.Component; import org.apache.felix.scr.annotations.Deactivate; @@ -45,16 +46,16 @@ import org.onosproject.net.intent.IntentState; import org.onosproject.net.intent.OpticalCircuitIntent; import org.onosproject.net.intent.OpticalConnectivityIntent; import org.onosproject.net.intent.PointToPointIntent; +import org.onosproject.net.newresource.ResourceAllocation; import org.onosproject.net.newresource.ResourceService; import org.onosproject.net.resource.device.IntentSetMultimap; -import org.onosproject.net.resource.link.LinkResourceAllocations; -import org.onosproject.net.resource.link.LinkResourceService; import org.onosproject.net.topology.LinkWeight; import org.onosproject.net.topology.PathService; import org.onosproject.net.topology.TopologyEdge; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.util.Collection; import java.util.Collections; import java.util.Iterator; import java.util.LinkedList; @@ -101,9 +102,6 @@ public class OpticalPathProvisioner { protected IntentSetMultimap intentSetMultimap; @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) - protected LinkResourceService linkResourceService; - - @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) protected ResourceService resourceService; private ApplicationId appId; @@ -377,17 +375,17 @@ public class OpticalPathProvisioner { * @param intent the intent */ private void releaseResources(Intent intent) { - LinkResourceAllocations lra = linkResourceService.getAllocations(intent.id()); + Collection<ResourceAllocation> allocations = resourceService.getResourceAllocations(intent.id()); if (intent instanceof OpticalConnectivityIntent) { resourceService.release(intent.id()); - if (lra != null) { - linkResourceService.releaseResources(lra); + if (!allocations.isEmpty()) { + resourceService.release(ImmutableList.copyOf(allocations)); } } else if (intent instanceof OpticalCircuitIntent) { resourceService.release(intent.id()); intentSetMultimap.releaseMapping(intent.id()); - if (lra != null) { - linkResourceService.releaseResources(lra); + if (!allocations.isEmpty()) { + resourceService.release(ImmutableList.copyOf(allocations)); } } } diff --git a/framework/src/onos/apps/pom.xml b/framework/src/onos/apps/pom.xml index 98210736..005052fb 100644 --- a/framework/src/onos/apps/pom.xml +++ b/framework/src/onos/apps/pom.xml @@ -13,10 +13,7 @@ ~ 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"> + --><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> @@ -60,6 +57,7 @@ <module>igmp</module> <module>pim</module> <module>mlb</module> + <module>openstackswitching</module> </modules> <properties> diff --git a/framework/src/onos/apps/sdnip/src/main/java/org/onosproject/sdnip/PeerConnectivityManager.java b/framework/src/onos/apps/sdnip/src/main/java/org/onosproject/sdnip/PeerConnectivityManager.java index b2ce0f8a..a27baaf9 100644 --- a/framework/src/onos/apps/sdnip/src/main/java/org/onosproject/sdnip/PeerConnectivityManager.java +++ b/framework/src/onos/apps/sdnip/src/main/java/org/onosproject/sdnip/PeerConnectivityManager.java @@ -15,8 +15,6 @@ */ package org.onosproject.sdnip; -import com.google.common.collect.HashMultimap; -import com.google.common.collect.Multimap; import org.onlab.packet.Ethernet; import org.onlab.packet.IPv4; import org.onlab.packet.IPv6; @@ -27,6 +25,8 @@ import org.onosproject.core.ApplicationId; import org.onosproject.incubator.net.intf.Interface; import org.onosproject.incubator.net.intf.InterfaceService; import org.onosproject.net.ConnectPoint; +import org.onosproject.net.config.NetworkConfigEvent; +import org.onosproject.net.config.NetworkConfigListener; import org.onosproject.net.config.NetworkConfigService; import org.onosproject.net.flow.DefaultTrafficSelector; import org.onosproject.net.flow.DefaultTrafficTreatment; @@ -43,7 +43,9 @@ import org.slf4j.LoggerFactory; import java.util.ArrayList; import java.util.Collection; +import java.util.HashMap; import java.util.List; +import java.util.Map; import static com.google.common.base.Preconditions.checkNotNull; @@ -69,9 +71,10 @@ public class PeerConnectivityManager { private final ApplicationId appId; private final ApplicationId routerAppId; - // Just putting something random here for now. Figure out exactly what - // indexes we need when we start making use of them. - private final Multimap<BgpConfig.BgpSpeakerConfig, PointToPointIntent> peerIntents; + private final Map<Key, PointToPointIntent> peerIntents; + + private final InternalNetworkConfigListener configListener + = new InternalNetworkConfigListener(); /** * Creates a new PeerConnectivityManager. @@ -93,13 +96,14 @@ public class PeerConnectivityManager { this.routerAppId = routerAppId; this.interfaceService = interfaceService; - peerIntents = HashMultimap.create(); + peerIntents = new HashMap<>(); } /** * Starts the peer connectivity manager. */ public void start() { + configService.addListener(configListener); setUpConnectivity(); } @@ -107,6 +111,7 @@ public class PeerConnectivityManager { * Stops the peer connectivity manager. */ public void stop() { + configService.removeListener(configListener); } /** @@ -121,16 +126,27 @@ public class PeerConnectivityManager { return; } + Map<Key, PointToPointIntent> existingIntents = new HashMap<>(peerIntents); + for (BgpConfig.BgpSpeakerConfig bgpSpeaker : config.bgpSpeakers()) { log.debug("Start to set up BGP paths for BGP speaker: {}", bgpSpeaker); buildSpeakerIntents(bgpSpeaker).forEach(i -> { - peerIntents.put(bgpSpeaker, i); - intentSynchronizer.submit(i); + PointToPointIntent intent = existingIntents.remove(i.key()); + if (intent == null || !IntentUtils.equals(i, intent)) { + peerIntents.put(i.key(), i); + intentSynchronizer.submit(i); + } }); - } + + // Remove any remaining intents that we used to have that we don't need + // anymore + existingIntents.values().forEach(i -> { + peerIntents.remove(i.key()); + intentSynchronizer.withdraw(i); + }); } private Collection<PointToPointIntent> buildSpeakerIntents(BgpConfig.BgpSpeakerConfig speaker) { @@ -356,7 +372,7 @@ public class PeerConnectivityManager { * @param srcIp source IP address * @param dstIp destination IP address * @param suffix suffix string - * @return + * @return intent key */ private Key buildKey(IpAddress srcIp, IpAddress dstIp, String suffix) { String keyString = new StringBuilder() @@ -370,4 +386,26 @@ public class PeerConnectivityManager { return Key.of(keyString, appId); } + private class InternalNetworkConfigListener implements NetworkConfigListener { + + @Override + public void event(NetworkConfigEvent event) { + switch (event.type()) { + case CONFIG_REGISTERED: + break; + case CONFIG_UNREGISTERED: + break; + case CONFIG_ADDED: + case CONFIG_UPDATED: + case CONFIG_REMOVED: + if (event.configClass() == RoutingService.CONFIG_CLASS) { + setUpConnectivity(); + } + break; + default: + break; + } + } + } + } diff --git a/framework/src/onos/apps/sdnip/src/test/java/org/onosproject/sdnip/PeerConnectivityManagerTest.java b/framework/src/onos/apps/sdnip/src/test/java/org/onosproject/sdnip/PeerConnectivityManagerTest.java index c4b2daad..0dcc969d 100644 --- a/framework/src/onos/apps/sdnip/src/test/java/org/onosproject/sdnip/PeerConnectivityManagerTest.java +++ b/framework/src/onos/apps/sdnip/src/test/java/org/onosproject/sdnip/PeerConnectivityManagerTest.java @@ -34,6 +34,7 @@ import org.onosproject.incubator.net.intf.InterfaceService; import org.onosproject.net.ConnectPoint; import org.onosproject.net.DeviceId; import org.onosproject.net.PortNumber; +import org.onosproject.net.config.NetworkConfigListener; import org.onosproject.net.config.NetworkConfigService; import org.onosproject.net.flow.DefaultTrafficSelector; import org.onosproject.net.flow.DefaultTrafficTreatment; @@ -60,8 +61,10 @@ import java.util.Map; import java.util.Optional; import java.util.Set; +import static org.easymock.EasyMock.anyObject; import static org.easymock.EasyMock.createMock; import static org.easymock.EasyMock.expect; +import static org.easymock.EasyMock.expectLastCall; import static org.easymock.EasyMock.replay; import static org.easymock.EasyMock.reset; import static org.easymock.EasyMock.verify; @@ -119,6 +122,8 @@ public class PeerConnectivityManagerTest extends AbstractIntentTest { routingConfig = createMock(RoutingConfigurationService.class); interfaceService = createMock(InterfaceService.class); networkConfigService = createMock(NetworkConfigService.class); + networkConfigService.addListener(anyObject(NetworkConfigListener.class)); + expectLastCall().anyTimes(); bgpConfig = createMock(BgpConfig.class); // These will set expectations on routingConfig and interfaceService diff --git a/framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/ArpHandler.java b/framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/ArpHandler.java index f42f84b1..36563f01 100644 --- a/framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/ArpHandler.java +++ b/framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/ArpHandler.java @@ -35,7 +35,8 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.nio.ByteBuffer; -import java.util.List; +import java.util.Set; + import static com.google.common.base.Preconditions.checkNotNull; public class ArpHandler { @@ -112,7 +113,7 @@ public class ArpHandler { private boolean isArpReqForRouter(DeviceId deviceId, ARP arpRequest) { - List<Ip4Address> gatewayIpAddresses = config.getSubnetGatewayIps(deviceId); + Set<Ip4Address> gatewayIpAddresses = config.getPortIPs(deviceId); if (gatewayIpAddresses != null) { Ip4Address targetProtocolAddress = Ip4Address.valueOf(arpRequest .getTargetProtocolAddress()); diff --git a/framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/DefaultRoutingHandler.java b/framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/DefaultRoutingHandler.java index 40ee55fc..c4a91c75 100644 --- a/framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/DefaultRoutingHandler.java +++ b/framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/DefaultRoutingHandler.java @@ -23,14 +23,12 @@ import org.onlab.packet.IpPrefix; import org.onosproject.net.Device; import org.onosproject.net.DeviceId; import org.onosproject.net.Link; -import org.onosproject.net.MastershipRole; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; -import java.util.List; import java.util.Set; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; @@ -97,7 +95,7 @@ public class DefaultRoutingHandler { log.debug("populateAllRoutingRules: populationStatus is STARTED"); for (Device sw : srManager.deviceService.getDevices()) { - if (srManager.mastershipService.getLocalRole(sw.id()) != MastershipRole.MASTER) { + if (!srManager.mastershipService.isLocalMaster(sw.id())) { log.debug("populateAllRoutingRules: skipping device {}...we are not master", sw.id()); continue; @@ -146,8 +144,7 @@ public class DefaultRoutingHandler { // Take the snapshots of the links updatedEcmpSpgMap = new HashMap<>(); for (Device sw : srManager.deviceService.getDevices()) { - if (srManager.mastershipService. - getLocalRole(sw.id()) != MastershipRole.MASTER) { + if (!srManager.mastershipService.isLocalMaster(sw.id())) { continue; } ECMPShortestPathGraph ecmpSpgUpdated = @@ -273,8 +270,7 @@ public class DefaultRoutingHandler { for (Device sw : srManager.deviceService.getDevices()) { log.debug("Computing the impacted routes for device {} due to link fail", sw.id()); - if (srManager.mastershipService. - getLocalRole(sw.id()) != MastershipRole.MASTER) { + if (!srManager.mastershipService.isLocalMaster(sw.id())) { continue; } ECMPShortestPathGraph ecmpSpg = currentEcmpSpgMap.get(sw.id()); @@ -320,8 +316,7 @@ public class DefaultRoutingHandler { for (Device sw : srManager.deviceService.getDevices()) { log.debug("Computing the impacted routes for device {}", sw.id()); - if (srManager.mastershipService. - getLocalRole(sw.id()) != MastershipRole.MASTER) { + if (!srManager.mastershipService.isLocalMaster(sw.id())) { log.debug("No mastership for {} and skip route optimization", sw.id()); continue; @@ -455,7 +450,7 @@ public class DefaultRoutingHandler { // If both target switch and dest switch are edge routers, then set IP // rule for both subnet and router IP. if (config.isEdgeDevice(targetSw) && config.isEdgeDevice(destSw)) { - List<Ip4Prefix> subnets = config.getSubnets(destSw); + Set<Ip4Prefix> subnets = config.getSubnets(destSw); log.debug("* populateEcmpRoutingRulePartial in device {} towards {} for subnets {}", targetSw, destSw, subnets); result = rulePopulator.populateIpRuleForSubnet(targetSw, @@ -499,14 +494,13 @@ public class DefaultRoutingHandler { } /** - * Populates table miss entries for all tables, and pipeline rules for VLAN - * and TCAM tables. XXX rename/rethink + * Populates filtering rules for permitting Router DstMac and VLAN. * * @param deviceId Switch ID to set the rules */ - public void populateTtpRules(DeviceId deviceId) { - rulePopulator.populateTableVlan(deviceId); - rulePopulator.populateTableTMac(deviceId); + public void populatePortAddressingRules(DeviceId deviceId) { + rulePopulator.populateRouterMacVlanFilters(deviceId); + rulePopulator.populateRouterIpPunts(deviceId); } /** diff --git a/framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/DeviceConfiguration.java b/framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/DeviceConfiguration.java index 0bc155b8..828c51ce 100644 --- a/framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/DeviceConfiguration.java +++ b/framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/DeviceConfiguration.java @@ -15,6 +15,7 @@ */ package org.onosproject.segmentrouting; +import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import org.onlab.packet.Ip4Address; import org.onlab.packet.Ip4Prefix; @@ -38,20 +39,20 @@ import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; /** * Segment Routing configuration component that reads the * segment routing related configuration from Network Configuration Manager * component and organizes in more accessible formats. - * - * TODO: Merge multiple Segment Routing configuration wrapper classes into one. */ public class DeviceConfiguration implements DeviceProperties { private static final Logger log = LoggerFactory .getLogger(DeviceConfiguration.class); private final List<Integer> allSegmentIds = new ArrayList<>(); - private final HashMap<DeviceId, SegmentRouterInfo> deviceConfigMap = new HashMap<>(); + private final ConcurrentHashMap<DeviceId, SegmentRouterInfo> deviceConfigMap + = new ConcurrentHashMap<>(); private class SegmentRouterInfo { int nodeSid; @@ -126,18 +127,17 @@ public class DeviceConfiguration implements DeviceProperties { } /** - * Returns the segment id of a segment router. + * Returns the Node segment id of a segment router. * * @param deviceId device identifier * @return segment id */ @Override public int getSegmentId(DeviceId deviceId) { - if (deviceConfigMap.get(deviceId) != null) { - log.trace("getSegmentId for device{} is {}", - deviceId, - deviceConfigMap.get(deviceId).nodeSid); - return deviceConfigMap.get(deviceId).nodeSid; + SegmentRouterInfo srinfo = deviceConfigMap.get(deviceId); + if (srinfo != null) { + log.trace("getSegmentId for device{} is {}", deviceId, srinfo.nodeSid); + return srinfo.nodeSid; } else { log.warn("getSegmentId for device {} " + "throwing IllegalStateException " @@ -147,10 +147,10 @@ public class DeviceConfiguration implements DeviceProperties { } /** - * Returns the segment id of a segment router given its mac address. + * Returns the Node segment id of a segment router given its Router mac address. * * @param routerMac router mac address - * @return segment id + * @return node segment id, or -1 if not found in config */ public int getSegmentId(MacAddress routerMac) { for (Map.Entry<DeviceId, SegmentRouterInfo> entry: @@ -164,10 +164,10 @@ public class DeviceConfiguration implements DeviceProperties { } /** - * Returns the segment id of a segment router given its router ip address. + * Returns the Node segment id of a segment router given its Router ip address. * * @param routerAddress router ip address - * @return segment id + * @return node segment id, or -1 if not found in config */ public int getSegmentId(Ip4Address routerAddress) { for (Map.Entry<DeviceId, SegmentRouterInfo> entry: @@ -188,11 +188,10 @@ public class DeviceConfiguration implements DeviceProperties { */ @Override public MacAddress getDeviceMac(DeviceId deviceId) { - if (deviceConfigMap.get(deviceId) != null) { - log.trace("getDeviceMac for device{} is {}", - deviceId, - deviceConfigMap.get(deviceId).mac); - return deviceConfigMap.get(deviceId).mac; + SegmentRouterInfo srinfo = deviceConfigMap.get(deviceId); + if (srinfo != null) { + log.trace("getDeviceMac for device{} is {}", deviceId, srinfo.mac); + return srinfo.mac; } else { log.warn("getDeviceMac for device {} " + "throwing IllegalStateException " @@ -208,11 +207,10 @@ public class DeviceConfiguration implements DeviceProperties { * @return router ip address */ public Ip4Address getRouterIp(DeviceId deviceId) { - if (deviceConfigMap.get(deviceId) != null) { - log.trace("getDeviceIp for device{} is {}", - deviceId, - deviceConfigMap.get(deviceId).ip); - return deviceConfigMap.get(deviceId).ip; + SegmentRouterInfo srinfo = deviceConfigMap.get(deviceId); + if (srinfo != null) { + log.trace("getDeviceIp for device{} is {}", deviceId, srinfo.ip); + return srinfo.ip; } else { log.warn("getRouterIp for device {} " + "throwing IllegalStateException " @@ -223,18 +221,17 @@ public class DeviceConfiguration implements DeviceProperties { /** * Indicates if the segment router is a edge router or - * a transit/back bone router. + * a core/backbone router. * * @param deviceId device identifier * @return boolean */ @Override public boolean isEdgeDevice(DeviceId deviceId) { - if (deviceConfigMap.get(deviceId) != null) { - log.trace("isEdgeDevice for device{} is {}", - deviceId, - deviceConfigMap.get(deviceId).isEdge); - return deviceConfigMap.get(deviceId).isEdge; + SegmentRouterInfo srinfo = deviceConfigMap.get(deviceId); + if (srinfo != null) { + log.trace("isEdgeDevice for device{} is {}", deviceId, srinfo.isEdge); + return srinfo.isEdge; } else { log.warn("isEdgeDevice for device {} " + "throwing IllegalStateException " @@ -244,15 +241,35 @@ public class DeviceConfiguration implements DeviceProperties { } /** - * Returns the segment ids of all configured segment routers. + * Returns the node segment ids of all configured segment routers. * - * @return list of segment ids + * @return list of node segment ids */ @Override public List<Integer> getAllDeviceSegmentIds() { return allSegmentIds; } + @Override + public Map<Ip4Prefix, List<PortNumber>> getSubnetPortsMap(DeviceId deviceId) { + Map<Ip4Prefix, List<PortNumber>> subnetPortMap = new HashMap<>(); + + // Construct subnet-port mapping from port-subnet mapping + Map<PortNumber, Ip4Prefix> portSubnetMap = + this.deviceConfigMap.get(deviceId).subnets; + portSubnetMap.forEach((port, subnet) -> { + if (subnetPortMap.containsKey(subnet)) { + subnetPortMap.get(subnet).add(port); + } else { + ArrayList<PortNumber> ports = new ArrayList<>(); + ports.add(port); + subnetPortMap.put(subnet, ports); + } + }); + + return subnetPortMap; + } + /** * Returns the device identifier or data plane identifier (dpid) * of a segment router given its segment id. @@ -290,37 +307,68 @@ public class DeviceConfiguration implements DeviceProperties { } /** - * Returns the configured subnet gateway ip addresses for a segment router. + * Returns the configured port ip addresses for a segment router. + * These addresses serve as gateway IP addresses for the subnets configured + * on those ports. * * @param deviceId device identifier - * @return list of ip addresses + * @return immutable set of ip addresses configured on the ports or null if not found */ - public List<Ip4Address> getSubnetGatewayIps(DeviceId deviceId) { - if (deviceConfigMap.get(deviceId) != null) { - log.trace("getSubnetGatewayIps for device{} is {}", - deviceId, - deviceConfigMap.get(deviceId).gatewayIps.values()); - return new ArrayList<>(deviceConfigMap.get(deviceId).gatewayIps.values()); - } else { - return null; + public Set<Ip4Address> getPortIPs(DeviceId deviceId) { + SegmentRouterInfo srinfo = deviceConfigMap.get(deviceId); + if (srinfo != null) { + log.trace("getSubnetGatewayIps for device{} is {}", deviceId, + srinfo.gatewayIps.values()); + return ImmutableSet.copyOf(srinfo.gatewayIps.values()); + } + return null; + } + + /** + * Returns the configured IP addresses per port + * for a segment router. + * + * @param deviceId device identifier + * @return map of port to gateway IP addresses or null if not found + */ + public Map<PortNumber, Ip4Address> getPortIPMap(DeviceId deviceId) { + SegmentRouterInfo srinfo = deviceConfigMap.get(deviceId); + if (srinfo != null) { + return srinfo.gatewayIps; } + return null; } /** * Returns the configured subnet prefixes for a segment router. * * @param deviceId device identifier - * @return list of ip prefixes + * @return list of ip prefixes or null if not found */ - public List<Ip4Prefix> getSubnets(DeviceId deviceId) { - if (deviceConfigMap.get(deviceId) != null) { - log.trace("getSubnets for device{} is {}", - deviceId, - deviceConfigMap.get(deviceId).subnets.values()); - return new ArrayList<>(deviceConfigMap.get(deviceId).subnets.values()); - } else { - return null; + public Set<Ip4Prefix> getSubnets(DeviceId deviceId) { + SegmentRouterInfo srinfo = deviceConfigMap.get(deviceId); + if (srinfo != null) { + log.trace("getSubnets for device{} is {}", deviceId, + srinfo.subnets.values()); + return ImmutableSet.copyOf(srinfo.subnets.values()); } + return null; + } + + /** + * Returns the configured subnet on the given port, or null if no + * subnet has been configured on the port. + * + * @param deviceId device identifier + * @param pnum port identifier + * @return configured subnet on port, or null + */ + public Ip4Prefix getPortSubnet(DeviceId deviceId, PortNumber pnum) { + SegmentRouterInfo srinfo = deviceConfigMap.get(deviceId); + if (srinfo != null) { + return srinfo.subnets.get(pnum); + } + return null; } /** @@ -349,7 +397,7 @@ public class DeviceConfiguration implements DeviceProperties { * specified ip address as one of its subnet gateway ip address. * * @param gatewayIpAddress router gateway ip address - * @return router mac address + * @return router mac address or null if not found */ public MacAddress getRouterMacForAGatewayIp(Ip4Address gatewayIpAddress) { for (Map.Entry<DeviceId, SegmentRouterInfo> entry: @@ -377,7 +425,7 @@ public class DeviceConfiguration implements DeviceProperties { */ public boolean inSameSubnet(DeviceId deviceId, Ip4Address hostIp) { - List<Ip4Prefix> subnets = getSubnets(deviceId); + Set<Ip4Prefix> subnets = getSubnets(deviceId); if (subnets == null) { return false; } @@ -399,8 +447,9 @@ public class DeviceConfiguration implements DeviceProperties { * @return list of port numbers */ public List<Integer> getPortsForAdjacencySid(DeviceId deviceId, int sid) { - if (deviceConfigMap.get(deviceId) != null) { - for (AdjacencySid asid : deviceConfigMap.get(deviceId).adjacencySids) { + SegmentRouterInfo srinfo = deviceConfigMap.get(deviceId); + if (srinfo != null) { + for (AdjacencySid asid : srinfo.adjacencySids) { if (asid.getAsid() == sid) { return asid.getPorts(); } @@ -419,12 +468,13 @@ public class DeviceConfiguration implements DeviceProperties { * otherwise false */ public boolean isAdjacencySid(DeviceId deviceId, int sid) { - if (deviceConfigMap.get(deviceId) != null) { - if (deviceConfigMap.get(deviceId).adjacencySids.isEmpty()) { + SegmentRouterInfo srinfo = deviceConfigMap.get(deviceId); + if (srinfo != null) { + if (srinfo.adjacencySids.isEmpty()) { return false; } else { for (AdjacencySid asid: - deviceConfigMap.get(deviceId).adjacencySids) { + srinfo.adjacencySids) { if (asid.getAsid() == sid) { return true; } diff --git a/framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/IcmpHandler.java b/framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/IcmpHandler.java index f65f03e0..b3916b06 100644 --- a/framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/IcmpHandler.java +++ b/framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/IcmpHandler.java @@ -32,7 +32,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.nio.ByteBuffer; -import java.util.List; +import java.util.Set; import static com.google.common.base.Preconditions.checkNotNull; @@ -70,7 +70,7 @@ public class IcmpHandler { DeviceId deviceId = connectPoint.deviceId(); Ip4Address destinationAddress = Ip4Address.valueOf(ipv4.getDestinationAddress()); - List<Ip4Address> gatewayIpAddresses = config.getSubnetGatewayIps(deviceId); + Set<Ip4Address> gatewayIpAddresses = config.getPortIPs(deviceId); Ip4Address routerIp = config.getRouterIp(deviceId); IpPrefix routerIpPrefix = IpPrefix.valueOf(routerIp, IpPrefix.MAX_INET_MASK_LENGTH); Ip4Address routerIpAddress = routerIpPrefix.getIp4Prefix().address(); diff --git a/framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/RoutingRulePopulator.java b/framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/RoutingRulePopulator.java index 7641571d..d46028e7 100644 --- a/framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/RoutingRulePopulator.java +++ b/framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/RoutingRulePopulator.java @@ -25,6 +25,7 @@ import org.onlab.packet.VlanId; import org.onosproject.segmentrouting.grouphandler.NeighborSet; import org.onosproject.net.DeviceId; import org.onosproject.net.Link; +import org.onosproject.net.Port; import org.onosproject.net.PortNumber; import org.onosproject.net.flow.DefaultTrafficSelector; import org.onosproject.net.flow.DefaultTrafficTreatment; @@ -38,11 +39,13 @@ import org.onosproject.net.flowobjective.ForwardingObjective; import org.onosproject.net.flowobjective.Objective; import org.onosproject.net.flowobjective.ObjectiveError; import org.onosproject.net.flowobjective.ForwardingObjective.Builder; +import org.onosproject.net.flowobjective.ForwardingObjective.Flag; import org.onosproject.net.flowobjective.ObjectiveContext; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.ArrayList; +import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.concurrent.atomic.AtomicLong; @@ -57,6 +60,11 @@ public class RoutingRulePopulator { private AtomicLong rulePopulationCounter; private SegmentRoutingManager srManager; private DeviceConfiguration config; + + private static final int HIGHEST_PRIORITY = 0xffff; + private static final long OFPP_MAX = 0xffffff00L; + + /** * Creates a RoutingRulePopulator object. * @@ -98,7 +106,7 @@ public class RoutingRulePopulator { TrafficSelector.Builder sbuilder = DefaultTrafficSelector.builder(); TrafficTreatment.Builder tbuilder = DefaultTrafficTreatment.builder(); - sbuilder.matchIPDst(IpPrefix.valueOf(hostIp, 32)); + sbuilder.matchIPDst(IpPrefix.valueOf(hostIp, IpPrefix.MAX_INET_MASK_LENGTH)); sbuilder.matchEthType(Ethernet.TYPE_IPV4); tbuilder.deferred() @@ -134,7 +142,7 @@ public class RoutingRulePopulator { * @return true if all rules are set successfully, false otherwise */ public boolean populateIpRuleForSubnet(DeviceId deviceId, - List<Ip4Prefix> subnets, + Set<Ip4Prefix> subnets, DeviceId destSw, Set<DeviceId> nextHops) { @@ -350,40 +358,80 @@ public class RoutingRulePopulator { } /** - * Populates VLAN flows rules. All packets are forwarded to TMAC table. + * Creates a filtering objective to permit all untagged packets with a + * dstMac corresponding to the router's MAC address. For those pipelines + * that need to internally assign vlans to untagged packets, this method + * provides per-subnet vlan-ids as metadata. + * <p> + * Note that the vlan assignment is only done by the master-instance for a switch. + * However we send the filtering objective from slave-instances as well, so + * that drivers can obtain other information (like Router MAC and IP). * - * @param deviceId switch ID to set the rules + * @param deviceId the switch dpid for the router */ - public void populateTableVlan(DeviceId deviceId) { - FilteringObjective.Builder fob = DefaultFilteringObjective.builder(); - fob.withKey(Criteria.matchInPort(PortNumber.ALL)) + public void populateRouterMacVlanFilters(DeviceId deviceId) { + log.debug("Installing per-port filtering objective for untagged " + + "packets in device {}", deviceId); + for (Port port : srManager.deviceService.getPorts(deviceId)) { + if (port.number().toLong() > 0 && port.number().toLong() < OFPP_MAX) { + Ip4Prefix portSubnet = config.getPortSubnet(deviceId, port.number()); + VlanId assignedVlan = (portSubnet == null) + ? VlanId.vlanId(SegmentRoutingManager.ASSIGNED_VLAN_NO_SUBNET) + : srManager.getSubnetAssignedVlanId(deviceId, portSubnet); + FilteringObjective.Builder fob = DefaultFilteringObjective.builder(); + fob.withKey(Criteria.matchInPort(port.number())) + .addCondition(Criteria.matchEthDst(config.getDeviceMac(deviceId))) .addCondition(Criteria.matchVlanId(VlanId.NONE)); - fob.permit().fromApp(srManager.appId); - log.debug("populateTableVlan: Installing filtering objective for untagged packets"); - srManager.flowObjectiveService. - filter(deviceId, - fob.add(new SRObjectiveContext(deviceId, - SRObjectiveContext.ObjectiveType.FILTER))); + // vlan assignment is valid only if this instance is master + if (srManager.mastershipService.isLocalMaster(deviceId)) { + TrafficTreatment tt = DefaultTrafficTreatment.builder() + .pushVlan().setVlanId(assignedVlan).build(); + fob.setMeta(tt); + } + fob.permit().fromApp(srManager.appId); + srManager.flowObjectiveService. + filter(deviceId, fob.add(new SRObjectiveContext(deviceId, + SRObjectiveContext.ObjectiveType.FILTER))); + } + } } /** - * Populates TMAC table rules. IP packets are forwarded to IP table. MPLS - * packets are forwarded to MPLS table. + * Creates a forwarding objective to punt all IP packets, destined to the + * router's port IP addresses, to the controller. Note that the input + * port should not be matched on, as these packets can come from any input. + * Furthermore, these are applied only by the master instance. * - * @param deviceId switch ID to set the rules + * @param deviceId the switch dpid for the router */ - public void populateTableTMac(DeviceId deviceId) { - - FilteringObjective.Builder fob = DefaultFilteringObjective.builder(); - fob.withKey(Criteria.matchInPort(PortNumber.ALL)) - .addCondition(Criteria.matchEthDst(config - .getDeviceMac(deviceId))); - fob.permit().fromApp(srManager.appId); - log.debug("populateTableTMac: Installing filtering objective for router mac"); - srManager.flowObjectiveService. - filter(deviceId, - fob.add(new SRObjectiveContext(deviceId, - SRObjectiveContext.ObjectiveType.FILTER))); + public void populateRouterIpPunts(DeviceId deviceId) { + if (!srManager.mastershipService.isLocalMaster(deviceId)) { + log.debug("Not installing port-IP punts - not the master for dev:{} ", + deviceId); + return; + } + ForwardingObjective.Builder puntIp = DefaultForwardingObjective.builder(); + Set<Ip4Address> allIps = new HashSet<Ip4Address>(config.getPortIPs(deviceId)); + allIps.add(config.getRouterIp(deviceId)); + for (Ip4Address ipaddr : allIps) { + TrafficSelector.Builder selector = DefaultTrafficSelector.builder(); + TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder(); + selector.matchEthType(Ethernet.TYPE_IPV4); + selector.matchIPDst(IpPrefix.valueOf(ipaddr, + IpPrefix.MAX_INET_MASK_LENGTH)); + treatment.setOutput(PortNumber.CONTROLLER); + puntIp.withSelector(selector.build()); + puntIp.withTreatment(treatment.build()); + puntIp.withFlag(Flag.VERSATILE) + .withPriority(HIGHEST_PRIORITY) + .makePermanent() + .fromApp(srManager.appId); + log.debug("Installing forwarding objective to punt port IP addresses"); + srManager.flowObjectiveService. + forward(deviceId, + puntIp.add(new SRObjectiveContext(deviceId, + SRObjectiveContext.ObjectiveType.FORWARDING))); + } } private PortNumber selectOnePort(DeviceId srcId, Set<DeviceId> destIds) { diff --git a/framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/SegmentRoutingManager.java b/framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/SegmentRoutingManager.java index eb2cf569..9d60b279 100644 --- a/framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/SegmentRoutingManager.java +++ b/framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/SegmentRoutingManager.java @@ -22,11 +22,17 @@ 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.VlanId; import org.onlab.packet.IPv4; +import org.onlab.packet.Ip4Address; +import org.onlab.packet.Ip4Prefix; +import org.onlab.packet.IpAddress; +import org.onlab.packet.IpPrefix; import org.onlab.util.KryoNamespace; import org.onosproject.core.ApplicationId; import org.onosproject.core.CoreService; import org.onosproject.event.Event; +import org.onosproject.net.ConnectPoint; import org.onosproject.net.config.ConfigFactory; import org.onosproject.net.config.NetworkConfigEvent; import org.onosproject.net.config.NetworkConfigRegistry; @@ -45,7 +51,6 @@ import org.onosproject.net.device.DeviceEvent; import org.onosproject.net.device.DeviceListener; import org.onosproject.net.device.DeviceService; import org.onosproject.net.flowobjective.FlowObjectiveService; -import org.onosproject.net.group.GroupKey; import org.onosproject.net.host.HostService; import org.onosproject.net.intent.IntentService; import org.onosproject.net.link.LinkEvent; @@ -56,6 +61,7 @@ import org.onosproject.net.packet.PacketContext; import org.onosproject.net.packet.PacketProcessor; import org.onosproject.net.packet.PacketService; import org.onosproject.net.topology.TopologyService; +import org.onosproject.segmentrouting.grouphandler.SubnetNextObjectiveStoreKey; import org.onosproject.store.service.EventuallyConsistentMap; import org.onosproject.store.service.EventuallyConsistentMapBuilder; import org.onosproject.store.service.StorageService; @@ -64,9 +70,11 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.net.URI; +import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Map; +import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.Executors; @@ -133,8 +141,13 @@ public class SegmentRoutingManager implements SegmentRoutingService { // Per device next objective ID store with (device id + neighbor set) as key private EventuallyConsistentMap<NeighborSetNextObjectiveStoreKey, Integer> nsNextObjStore = null; + private EventuallyConsistentMap<SubnetNextObjectiveStoreKey, Integer> subnetNextObjStore = null; private EventuallyConsistentMap<String, Tunnel> tunnelStore = null; private EventuallyConsistentMap<String, Policy> policyStore = null; + // Per device, per-subnet assigned-vlans store, with (device id + subnet + // IPv4 prefix) as key + private EventuallyConsistentMap<SubnetAssignedVidStoreKey, VlanId> + subnetVidStore = null; @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) protected StorageService storageService; @@ -163,6 +176,9 @@ public class SegmentRoutingManager implements SegmentRoutingService { private KryoNamespace.Builder kryoBuilder = null; + private static final short ASSIGNED_VLAN_START = 4093; + public static final short ASSIGNED_VLAN_NO_SUBNET = 4094; + @Activate protected void activate() { appId = coreService @@ -170,6 +186,8 @@ public class SegmentRoutingManager implements SegmentRoutingService { kryoBuilder = new KryoNamespace.Builder() .register(NeighborSetNextObjectiveStoreKey.class, + SubnetNextObjectiveStoreKey.class, + SubnetAssignedVidStoreKey.class, NeighborSet.class, DeviceId.class, URI.class, @@ -180,7 +198,12 @@ public class SegmentRoutingManager implements SegmentRoutingService { DefaultTunnel.class, Policy.class, TunnelPolicy.class, - Policy.Type.class + Policy.Type.class, + VlanId.class, + Ip4Address.class, + Ip4Prefix.class, + IpAddress.Version.class, + ConnectPoint.class ); log.debug("Creating EC map nsnextobjectivestore"); @@ -194,6 +217,16 @@ public class SegmentRoutingManager implements SegmentRoutingService { .build(); log.trace("Current size {}", nsNextObjStore.size()); + log.debug("Creating EC map subnetnextobjectivestore"); + EventuallyConsistentMapBuilder<SubnetNextObjectiveStoreKey, Integer> + subnetNextObjMapBuilder = storageService.eventuallyConsistentMapBuilder(); + + subnetNextObjStore = subnetNextObjMapBuilder + .withName("subnetnextobjectivestore") + .withSerializer(kryoBuilder) + .withTimestampProvider((k, v) -> new WallClockTimestamp()) + .build(); + EventuallyConsistentMapBuilder<String, Tunnel> tunnelMapBuilder = storageService.eventuallyConsistentMapBuilder(); @@ -212,6 +245,15 @@ public class SegmentRoutingManager implements SegmentRoutingService { .withTimestampProvider((k, v) -> new WallClockTimestamp()) .build(); + EventuallyConsistentMapBuilder<SubnetAssignedVidStoreKey, VlanId> + subnetVidStoreMapBuilder = storageService.eventuallyConsistentMapBuilder(); + + subnetVidStore = subnetVidStoreMapBuilder + .withName("subnetvidstore") + .withSerializer(kryoBuilder) + .withTimestampProvider((k, v) -> new WallClockTimestamp()) + .build(); + cfgService.addListener(cfgListener); cfgService.registerConfigFactory(cfgFactory); @@ -296,23 +338,72 @@ public class SegmentRoutingManager implements SegmentRoutingService { } /** - * Returns the GroupKey object for the device and the NeighborSet given. - * XXX is this called + * Returns the vlan-id assigned to the subnet configured for a device. + * If no vlan-id has been assigned, a new one is assigned out of a pool of ids, + * if and only if this controller instance is the master for the device. + * <p> + * USAGE: The assigned vlans are meant to be applied to untagged packets on those + * switches/pipelines that need this functionality. These vids are meant + * to be used internally within a switch, and thus need to be unique only + * on a switch level. Note that packets never go out on the wire with these + * vlans. Currently, vlan ids are assigned from value 4093 down. + * Vlan id 4094 expected to be used for all ports that are not assigned subnets. + * Vlan id 4095 is reserved and unused. Only a single vlan id is assigned + * per subnet. + * XXX This method should avoid any vlans configured on the ports, but + * currently the app works only on untagged packets and as a result + * ignores any vlan configuration. * - * @param ns NeightborSet object for the GroupKey - * @return GroupKey object for the NeighborSet + * @param deviceId switch dpid + * @param subnet IPv4 prefix for which assigned vlan is desired + * @return VlanId assigned for the subnet on the device, or + * null if no vlan assignment was found and this instance is not + * the master for the device. */ - public GroupKey getGroupKey(NeighborSet ns) { - for (DefaultGroupHandler groupHandler : groupHandlerMap.values()) { - return groupHandler.getGroupKey(ns); + public VlanId getSubnetAssignedVlanId(DeviceId deviceId, Ip4Prefix subnet) { + VlanId assignedVid = subnetVidStore.get(new SubnetAssignedVidStoreKey( + deviceId, subnet)); + if (assignedVid != null) { + log.debug("Query for subnet:{} on device:{} returned assigned-vlan " + + "{}", subnet, deviceId, assignedVid); + return assignedVid; + } + //check mastership for the right to assign a vlan + if (!mastershipService.isLocalMaster(deviceId)) { + log.warn("This controller instance is not the master for device {}. " + + "Cannot assign vlan-id for subnet {}", deviceId, subnet); + return null; + } + // vlan assignment is expensive but done only once + Set<Ip4Prefix> configuredSubnets = deviceConfiguration.getSubnets(deviceId); + Set<Short> assignedVlans = new HashSet<>(); + Set<Ip4Prefix> unassignedSubnets = new HashSet<>(); + for (Ip4Prefix sub : configuredSubnets) { + VlanId v = subnetVidStore.get(new SubnetAssignedVidStoreKey(deviceId, + sub)); + if (v != null) { + assignedVlans.add(v.toShort()); + } else { + unassignedSubnets.add(sub); + } + } + short nextAssignedVlan = ASSIGNED_VLAN_START; + if (!assignedVlans.isEmpty()) { + nextAssignedVlan = (short) (Collections.min(assignedVlans) - 1); + } + for (Ip4Prefix unsub : unassignedSubnets) { + subnetVidStore.put(new SubnetAssignedVidStoreKey(deviceId, unsub), + VlanId.vlanId(nextAssignedVlan--)); + log.info("Assigned vlan: {} to subnet: {} on device: {}", + nextAssignedVlan + 1, unsub, deviceId); } - return null; + return subnetVidStore.get(new SubnetAssignedVidStoreKey(deviceId, subnet)); } /** - * Returns the next objective ID for the NeighborSet given. If the nextObjectiveID does not exist, - * a new one is created and returned. + * Returns the next objective ID for the given NeighborSet. + * If the nextObjectiveID does not exist, a new one is created and returned. * * @param deviceId Device ID * @param ns NegighborSet @@ -329,6 +420,25 @@ public class SegmentRoutingManager implements SegmentRoutingService { } } + /** + * Returns the next objective ID for the Subnet given. If the nextObjectiveID does not exist, + * a new one is created and returned. + * + * @param deviceId Device ID + * @param prefix Subnet + * @return next objective ID + */ + public int getSubnetNextObjectiveId(DeviceId deviceId, IpPrefix prefix) { + if (groupHandlerMap.get(deviceId) != null) { + log.trace("getSubnetNextObjectiveId query in device {}", deviceId); + return groupHandlerMap + .get(deviceId).getSubnetNextObjectiveId(prefix); + } else { + log.warn("getSubnetNextObjectiveId query in device {} not found", deviceId); + return -1; + } + } + private class InternalPacketProcessor implements PacketProcessor { @Override public void process(PacketContext context) { @@ -423,6 +533,8 @@ public class SegmentRoutingManager implements SegmentRoutingService { event.type() == DeviceEvent.Type.DEVICE_AVAILABILITY_CHANGED || event.type() == DeviceEvent.Type.DEVICE_UPDATED) { if (deviceService.isAvailable(((Device) event.subject()).id())) { + log.info("Processing device event {} for available device {}", + event.type(), ((Device) event.subject()).id()); processDeviceAdded((Device) event.subject()); } } else if (event.type() == DeviceEvent.Type.PORT_REMOVED) { @@ -484,20 +596,31 @@ public class SegmentRoutingManager implements SegmentRoutingService { private void processDeviceAdded(Device device) { log.debug("A new device with ID {} was added", device.id()); - //Irrespective whether the local is a MASTER or not for this device, - //create group handler instance and push default TTP flow rules. - //Because in a multi-instance setup, instances can initiate - //groups for any devices. Also the default TTP rules are needed - //to be pushed before inserting any IP table entries for any device - DefaultGroupHandler dgh = DefaultGroupHandler. + // Irrespective of whether the local is a MASTER or not for this device, + // we need to create a SR-group-handler instance. This is because in a + // multi-instance setup, any instance can initiate forwarding/next-objectives + // for any switch (even if this instance is a SLAVE or not even connected + // to the switch). To handle this, a default-group-handler instance is necessary + // per switch. + DefaultGroupHandler groupHandler = DefaultGroupHandler. createGroupHandler(device.id(), appId, deviceConfiguration, linkService, flowObjectiveService, - nsNextObjStore); - groupHandlerMap.put(device.id(), dgh); - defaultRoutingHandler.populateTtpRules(device.id()); + nsNextObjStore, + subnetNextObjStore); + groupHandlerMap.put(device.id(), groupHandler); + + // Also, in some cases, drivers may need extra + // information to process rules (eg. Router IP/MAC); and so, we send + // port addressing rules to the driver as well irrespective of whether + // this instance is the master or not. + defaultRoutingHandler.populatePortAddressingRules(device.id()); + + if (mastershipService.isLocalMaster(device.id())) { + groupHandler.createGroupsFromSubnetConfig(); + } } private void processPortRemoved(Device device, Port port) { @@ -531,18 +654,29 @@ public class SegmentRoutingManager implements SegmentRoutingService { tunnelHandler, policyStore); for (Device device : deviceService.getDevices()) { - //Irrespective whether the local is a MASTER or not for this device, - //create group handler instance and push default TTP flow rules. - //Because in a multi-instance setup, instances can initiate - //groups for any devices. Also the default TTP rules are needed - //to be pushed before inserting any IP table entries for any device + // Irrespective of whether the local is a MASTER or not for this device, + // we need to create a SR-group-handler instance. This is because in a + // multi-instance setup, any instance can initiate forwarding/next-objectives + // for any switch (even if this instance is a SLAVE or not even connected + // to the switch). To handle this, a default-group-handler instance is necessary + // per switch. DefaultGroupHandler groupHandler = DefaultGroupHandler .createGroupHandler(device.id(), appId, deviceConfiguration, linkService, flowObjectiveService, - nsNextObjStore); + nsNextObjStore, + subnetNextObjStore); groupHandlerMap.put(device.id(), groupHandler); - defaultRoutingHandler.populateTtpRules(device.id()); + + // Also, in some cases, drivers may need extra + // information to process rules (eg. Router IP/MAC); and so, we send + // port addressing rules to the driver as well, irrespective of whether + // this instance is the master or not. + defaultRoutingHandler.populatePortAddressingRules(device.id()); + + if (mastershipService.isLocalMaster(device.id())) { + groupHandler.createGroupsFromSubnetConfig(); + } } defaultRoutingHandler.startPopulationProcess(); diff --git a/framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/SubnetAssignedVidStoreKey.java b/framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/SubnetAssignedVidStoreKey.java new file mode 100644 index 00000000..84b44c97 --- /dev/null +++ b/framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/SubnetAssignedVidStoreKey.java @@ -0,0 +1,66 @@ +package org.onosproject.segmentrouting; + +import java.util.Objects; + +import org.onlab.packet.Ip4Prefix; +import org.onosproject.net.DeviceId; + +/** + * Class definition for key used to map per device subnets to assigned Vlan ids. + * + */ +public class SubnetAssignedVidStoreKey { + private final DeviceId deviceId; + private final Ip4Prefix subnet; + + public SubnetAssignedVidStoreKey(DeviceId deviceId, Ip4Prefix subnet) { + this.deviceId = deviceId; + this.subnet = subnet; + } + + /** + * Returns the device identification used to create this key. + * + * @return the device identifier + */ + public DeviceId deviceId() { + return deviceId; + } + + /** + * Returns the subnet information used to create this key. + * + * @return the subnet + */ + public Ip4Prefix subnet() { + return subnet; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (!(o instanceof SubnetAssignedVidStoreKey)) { + return false; + } + SubnetAssignedVidStoreKey that = + (SubnetAssignedVidStoreKey) o; + return (Objects.equals(this.deviceId, that.deviceId) && + Objects.equals(this.subnet, that.subnet)); + } + + @Override + public int hashCode() { + int result = 17; + result = 31 * result + Objects.hashCode(deviceId) + + Objects.hashCode(subnet); + return result; + } + + @Override + public String toString() { + return "Device: " + deviceId + " Subnet: " + subnet; + } + +} diff --git a/framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/grouphandler/DefaultEdgeGroupHandler.java b/framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/grouphandler/DefaultEdgeGroupHandler.java index c960adca..a5c1090f 100644 --- a/framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/grouphandler/DefaultEdgeGroupHandler.java +++ b/framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/grouphandler/DefaultEdgeGroupHandler.java @@ -52,9 +52,12 @@ public class DefaultEdgeGroupHandler extends DefaultGroupHandler { LinkService linkService, FlowObjectiveService flowObjService, EventuallyConsistentMap< - NeighborSetNextObjectiveStoreKey, - Integer> nsNextObjStore) { - super(deviceId, appId, config, linkService, flowObjService, nsNextObjStore); + NeighborSetNextObjectiveStoreKey, + Integer> nsNextObjStore, + EventuallyConsistentMap<SubnetNextObjectiveStoreKey, + Integer> subnetNextObjStore) { + super(deviceId, appId, config, linkService, flowObjService, + nsNextObjStore, subnetNextObjStore); } @Override diff --git a/framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/grouphandler/DefaultGroupHandler.java b/framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/grouphandler/DefaultGroupHandler.java index 9bbde2f3..69a0d86f 100644 --- a/framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/grouphandler/DefaultGroupHandler.java +++ b/framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/grouphandler/DefaultGroupHandler.java @@ -25,10 +25,11 @@ import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; -import java.util.Random; import java.util.Set; import java.util.stream.Collectors; +import org.onlab.packet.Ip4Prefix; +import org.onlab.packet.IpPrefix; import org.onlab.packet.MacAddress; import org.onlab.packet.MplsLabel; import org.onlab.util.KryoNamespace; @@ -74,7 +75,8 @@ public class DefaultGroupHandler { // new HashMap<NeighborSet, Integer>(); protected EventuallyConsistentMap< NeighborSetNextObjectiveStoreKey, Integer> nsNextObjStore = null; - protected Random rand = new Random(); + protected EventuallyConsistentMap< + SubnetNextObjectiveStoreKey, Integer> subnetNextObjStore = null; protected KryoNamespace.Builder kryo = new KryoNamespace.Builder() .register(URI.class).register(HashSet.class) @@ -89,8 +91,10 @@ public class DefaultGroupHandler { LinkService linkService, FlowObjectiveService flowObjService, EventuallyConsistentMap< - NeighborSetNextObjectiveStoreKey, - Integer> nsNextObjStore) { + NeighborSetNextObjectiveStoreKey, + Integer> nsNextObjStore, + EventuallyConsistentMap<SubnetNextObjectiveStoreKey, + Integer> subnetNextObjStore) { this.deviceId = checkNotNull(deviceId); this.appId = checkNotNull(appId); this.deviceConfig = checkNotNull(config); @@ -101,6 +105,7 @@ public class DefaultGroupHandler { nodeMacAddr = checkNotNull(config.getDeviceMac(deviceId)); this.flowObjectiveService = flowObjService; this.nsNextObjStore = nsNextObjStore; + this.subnetNextObjStore = subnetNextObjStore; populateNeighborMaps(); } @@ -115,7 +120,8 @@ public class DefaultGroupHandler { * @param config interface to retrieve the device properties * @param linkService link service object * @param flowObjService flow objective service object - * @param nsNextObjStore next objective store map + * @param nsNextObjStore NeighborSet next objective store map + * @param subnetNextObjStore subnet next objective store map * @return default group handler type */ public static DefaultGroupHandler createGroupHandler(DeviceId deviceId, @@ -123,18 +129,23 @@ public class DefaultGroupHandler { DeviceProperties config, LinkService linkService, FlowObjectiveService flowObjService, - EventuallyConsistentMap<NeighborSetNextObjectiveStoreKey, - Integer> nsNextObjStore) { + EventuallyConsistentMap< + NeighborSetNextObjectiveStoreKey, + Integer> nsNextObjStore, + EventuallyConsistentMap<SubnetNextObjectiveStoreKey, + Integer> subnetNextObjStore) { if (config.isEdgeDevice(deviceId)) { return new DefaultEdgeGroupHandler(deviceId, appId, config, linkService, flowObjService, - nsNextObjStore); + nsNextObjStore, + subnetNextObjStore); } else { return new DefaultTransitGroupHandler(deviceId, appId, config, linkService, flowObjService, - nsNextObjStore); + nsNextObjStore, + subnetNextObjStore); } } @@ -323,6 +334,21 @@ public class DefaultGroupHandler { } /** + * Returns the next objective associated with the subnet. + * If there is no next objective for this subnet, this API + * would create a next objective and return. + * + * @param prefix subnet information + * @return int if found or -1 + */ + public int getSubnetNextObjectiveId(IpPrefix prefix) { + Integer nextId = subnetNextObjStore. + get(new SubnetNextObjectiveStoreKey(deviceId, prefix)); + + return (nextId != null) ? nextId : -1; + } + + /** * Checks if the next objective ID (group) for the neighbor set exists or not. * * @param ns neighbor set to check @@ -486,6 +512,43 @@ public class DefaultGroupHandler { } } + public void createGroupsFromSubnetConfig() { + Map<Ip4Prefix, List<PortNumber>> subnetPortMap = + this.deviceConfig.getSubnetPortsMap(this.deviceId); + + // Construct a broadcast group for each subnet + subnetPortMap.forEach((subnet, ports) -> { + SubnetNextObjectiveStoreKey key = + new SubnetNextObjectiveStoreKey(deviceId, subnet); + + if (subnetNextObjStore.containsKey(key)) { + log.debug("Broadcast group for device {} and subnet {} exists", + deviceId, subnet); + return; + } + + int nextId = flowObjectiveService.allocateNextId(); + + NextObjective.Builder nextObjBuilder = DefaultNextObjective + .builder().withId(nextId) + .withType(NextObjective.Type.BROADCAST).fromApp(appId); + + ports.forEach(port -> { + TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder(); + tBuilder.setOutput(port); + nextObjBuilder.addTreatment(tBuilder.build()); + }); + + NextObjective nextObj = nextObjBuilder.add(); + flowObjectiveService.next(deviceId, nextObj); + log.debug("createGroupFromSubnetConfig: Submited " + + "next objective {} in device {}", + nextId, deviceId); + + subnetNextObjStore.put(key, nextId); + }); + } + public GroupKey getGroupKey(Object obj) { return new DefaultGroupKey(kryo.build().serialize(obj)); } diff --git a/framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/grouphandler/DefaultTransitGroupHandler.java b/framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/grouphandler/DefaultTransitGroupHandler.java index 3cb73aba..b009e869 100644 --- a/framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/grouphandler/DefaultTransitGroupHandler.java +++ b/framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/grouphandler/DefaultTransitGroupHandler.java @@ -45,9 +45,12 @@ public class DefaultTransitGroupHandler extends DefaultGroupHandler { LinkService linkService, FlowObjectiveService flowObjService, EventuallyConsistentMap< - NeighborSetNextObjectiveStoreKey, - Integer> nsNextObjStore) { - super(deviceId, appId, config, linkService, flowObjService, nsNextObjStore); + NeighborSetNextObjectiveStoreKey, + Integer> nsNextObjStore, + EventuallyConsistentMap<SubnetNextObjectiveStoreKey, + Integer> subnetNextObjStore) { + super(deviceId, appId, config, linkService, flowObjService, + nsNextObjStore, subnetNextObjStore); } @Override diff --git a/framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/grouphandler/DeviceProperties.java b/framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/grouphandler/DeviceProperties.java index 497f5256..d28d38d5 100644 --- a/framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/grouphandler/DeviceProperties.java +++ b/framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/grouphandler/DeviceProperties.java @@ -16,9 +16,12 @@ package org.onosproject.segmentrouting.grouphandler; import java.util.List; +import java.util.Map; +import org.onlab.packet.Ip4Prefix; import org.onlab.packet.MacAddress; import org.onosproject.net.DeviceId; +import org.onosproject.net.PortNumber; /** * Mechanism through which group handler module retrieves @@ -33,6 +36,7 @@ public interface DeviceProperties { * @return segment id of a device */ int getSegmentId(DeviceId deviceId); + /** * Returns the Mac address of a device to be used in group creation. * @@ -40,6 +44,7 @@ public interface DeviceProperties { * @return mac address of a device */ MacAddress getDeviceMac(DeviceId deviceId); + /** * Indicates whether a device is edge device or transit/core device. * @@ -47,6 +52,7 @@ public interface DeviceProperties { * @return boolean */ boolean isEdgeDevice(DeviceId deviceId); + /** * Returns all segment IDs to be considered in building auto * @@ -54,4 +60,16 @@ public interface DeviceProperties { * @return list of segment IDs */ List<Integer> getAllDeviceSegmentIds(); + + /** + * Returns subnet-to-ports mapping of given device. + * + * For each entry of the map + * Key: a subnet + * Value: a list of ports, which are bound to the subnet + * + * @param deviceId device identifier + * @return a map that contains all subnet-to-ports mapping of given device + */ + Map<Ip4Prefix, List<PortNumber>> getSubnetPortsMap(DeviceId deviceId); } diff --git a/framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/grouphandler/PolicyGroupHandler.java b/framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/grouphandler/PolicyGroupHandler.java index e7e87839..e47a6625 100644 --- a/framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/grouphandler/PolicyGroupHandler.java +++ b/framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/grouphandler/PolicyGroupHandler.java @@ -54,7 +54,8 @@ public class PolicyGroupHandler extends DefaultGroupHandler { * @param config interface to retrieve the device properties * @param linkService link service object * @param flowObjService flow objective service object - * @param nsNextObjStore next objective store map + * @param nsNextObjStore NeighborSet next objective store map + * @param subnetNextObjStore subnet next objective store map */ public PolicyGroupHandler(DeviceId deviceId, ApplicationId appId, @@ -62,8 +63,11 @@ public class PolicyGroupHandler extends DefaultGroupHandler { LinkService linkService, FlowObjectiveService flowObjService, EventuallyConsistentMap<NeighborSetNextObjectiveStoreKey, - Integer> nsNextObjStore) { - super(deviceId, appId, config, linkService, flowObjService, nsNextObjStore); + Integer> nsNextObjStore, + EventuallyConsistentMap<SubnetNextObjectiveStoreKey, + Integer> subnetNextObjStore) { + super(deviceId, appId, config, linkService, flowObjService, + nsNextObjStore, subnetNextObjStore); } public PolicyGroupIdentifier createPolicyGroupChain(String id, diff --git a/framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/grouphandler/SubnetNextObjectiveStoreKey.java b/framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/grouphandler/SubnetNextObjectiveStoreKey.java new file mode 100644 index 00000000..d6b16c7a --- /dev/null +++ b/framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/grouphandler/SubnetNextObjectiveStoreKey.java @@ -0,0 +1,78 @@ +/* + * 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.segmentrouting.grouphandler; + +import org.onlab.packet.IpPrefix; +import org.onosproject.net.DeviceId; + +import java.util.Objects; + +/** + * Class definition of Key for Subnet to NextObjective store. + */ +public class SubnetNextObjectiveStoreKey { + private final DeviceId deviceId; + private final IpPrefix prefix; + + public SubnetNextObjectiveStoreKey(DeviceId deviceId, + IpPrefix prefix) { + this.deviceId = deviceId; + this.prefix = prefix; + } + + /** + * Gets device id in this SubnetNextObjectiveStoreKey. + * + * @return device id + */ + public DeviceId deviceId() { + return this.deviceId; + } + + /** + * Gets subnet information in this SubnetNextObjectiveStoreKey. + * + * @return subnet information + */ + public IpPrefix prefix() { + return this.prefix; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (!(o instanceof SubnetNextObjectiveStoreKey)) { + return false; + } + SubnetNextObjectiveStoreKey that = + (SubnetNextObjectiveStoreKey) o; + return (Objects.equals(this.deviceId, that.deviceId) && + Objects.equals(this.prefix, that.prefix)); + } + + @Override + public int hashCode() { + return Objects.hash(deviceId, prefix); + } + + @Override + public String toString() { + return "Device: " + deviceId + " Subnet: " + prefix; + } +} diff --git a/framework/src/onos/apps/test/distributed-primitives/src/main/java/org/onosproject/distributedprimitives/cli/SetTestAddCommand.java b/framework/src/onos/apps/test/distributed-primitives/src/main/java/org/onosproject/distributedprimitives/cli/SetTestAddCommand.java index 204471c2..2d1aa0b8 100644 --- a/framework/src/onos/apps/test/distributed-primitives/src/main/java/org/onosproject/distributedprimitives/cli/SetTestAddCommand.java +++ b/framework/src/onos/apps/test/distributed-primitives/src/main/java/org/onosproject/distributedprimitives/cli/SetTestAddCommand.java @@ -23,7 +23,7 @@ import org.onosproject.store.serializers.KryoNamespaces; import org.onosproject.store.service.Serializer; import org.onosproject.store.service.StorageService; -import java.util.HashSet; +import java.util.Arrays; import java.util.Set; /** @@ -44,7 +44,6 @@ public class SetTestAddCommand extends AbstractShellCommand { String[] values = null; Set<String> set; - Set<String> toAdd = new HashSet<>(); Serializer serializer = Serializer.using( @@ -68,13 +67,10 @@ public class SetTestAddCommand extends AbstractShellCommand { } } else if (values.length >= 1) { // Add multiple elements to a set - for (String value : values) { - toAdd.add(value); - } - if (set.addAll(toAdd)) { - print("%s was added to the set %s", toAdd, setName); + if (set.addAll(Arrays.asList(values))) { + print("%s was added to the set %s", Arrays.asList(values), setName); } else { - print("%s was already in set %s", toAdd, setName); + print("%s was already in set %s", Arrays.asList(values), setName); } } } diff --git a/framework/src/onos/apps/test/distributed-primitives/src/main/java/org/onosproject/distributedprimitives/cli/SetTestGetCommand.java b/framework/src/onos/apps/test/distributed-primitives/src/main/java/org/onosproject/distributedprimitives/cli/SetTestGetCommand.java index fb36a06a..74c52c16 100644 --- a/framework/src/onos/apps/test/distributed-primitives/src/main/java/org/onosproject/distributedprimitives/cli/SetTestGetCommand.java +++ b/framework/src/onos/apps/test/distributed-primitives/src/main/java/org/onosproject/distributedprimitives/cli/SetTestGetCommand.java @@ -24,7 +24,7 @@ import org.onosproject.store.serializers.KryoNamespaces; import org.onosproject.store.service.Serializer; import org.onosproject.store.service.StorageService; -import java.util.HashSet; +import java.util.Arrays; import java.util.Set; /** @@ -49,7 +49,6 @@ public class SetTestGetCommand extends AbstractShellCommand { String[] values = null; Set<String> set; - Set<String> toCheck = new HashSet<>(); String output = ""; Serializer serializer = Serializer.using( @@ -95,13 +94,10 @@ public class SetTestGetCommand extends AbstractShellCommand { } } else if (values.length > 1) { //containsAll - for (String value : values) { - toCheck.add(value); - } - if (set.containsAll(toCheck)) { - print("Set %s contains the the subset %s", setName, toCheck); + if (set.containsAll(Arrays.asList(values))) { + print("Set %s contains the the subset %s", setName, Arrays.asList(values)); } else { - print("Set %s did not contain the the subset %s", setName, toCheck); + print("Set %s did not contain the the subset %s", setName, Arrays.asList(values)); } } } diff --git a/framework/src/onos/apps/test/distributed-primitives/src/main/java/org/onosproject/distributedprimitives/cli/SetTestRemoveCommand.java b/framework/src/onos/apps/test/distributed-primitives/src/main/java/org/onosproject/distributedprimitives/cli/SetTestRemoveCommand.java index d1f81e42..1fa073f3 100644 --- a/framework/src/onos/apps/test/distributed-primitives/src/main/java/org/onosproject/distributedprimitives/cli/SetTestRemoveCommand.java +++ b/framework/src/onos/apps/test/distributed-primitives/src/main/java/org/onosproject/distributedprimitives/cli/SetTestRemoveCommand.java @@ -24,7 +24,7 @@ import org.onosproject.store.serializers.KryoNamespaces; import org.onosproject.store.service.Serializer; import org.onosproject.store.service.StorageService; -import java.util.HashSet; +import java.util.Arrays; import java.util.Set; /** @@ -54,7 +54,6 @@ public class SetTestRemoveCommand extends AbstractShellCommand { String[] values = null; Set<String> set; - Set<String> givenValues = new HashSet<>(); Serializer serializer = Serializer.using( new KryoNamespace.Builder().register(KryoNamespaces.BASIC).build()); @@ -79,13 +78,10 @@ public class SetTestRemoveCommand extends AbstractShellCommand { } if (retain) { // Keep only the given values - for (String value : values) { - givenValues.add(value); - } - if (set.retainAll(givenValues)) { - print("%s was pruned to contain only elements of set %s", setName, givenValues); + if (set.retainAll(Arrays.asList(values))) { + print("%s was pruned to contain only elements of set %s", setName, Arrays.asList(values)); } else { - print("%s was not changed by retaining only elements of the set %s", setName, givenValues); + print("%s was not changed by retaining only elements of the set %s", setName, Arrays.asList(values)); } } else if (values.length == 1) { // Remove a single element from the set @@ -94,15 +90,12 @@ public class SetTestRemoveCommand extends AbstractShellCommand { } else { print("[%s] was not in set %s", values[0], setName); } - } else if (values.length >= 1) { + } else if (values.length > 1) { // Remove multiple elements from a set - for (String value : values) { - givenValues.add(value); - } - if (set.removeAll(givenValues)) { - print("%s was removed from the set %s", givenValues, setName); + if (set.removeAll(Arrays.asList(values))) { + print("%s was removed from the set %s", Arrays.asList(values), setName); } else { - print("No element of %s was in set %s", givenValues, setName); + print("No element of %s was in set %s", Arrays.asList(values), setName); } } } diff --git a/framework/src/onos/apps/virtualbng/src/main/java/org/onosproject/virtualbng/ConnectPointConfiguration.java b/framework/src/onos/apps/virtualbng/src/main/java/org/onosproject/virtualbng/ConnectPointConfiguration.java new file mode 100644 index 00000000..ff516d71 --- /dev/null +++ b/framework/src/onos/apps/virtualbng/src/main/java/org/onosproject/virtualbng/ConnectPointConfiguration.java @@ -0,0 +1,55 @@ +/* + * 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.virtualbng; + +import org.onosproject.net.ConnectPoint; + +/** + * Configuration for a connect point. + */ +public class ConnectPointConfiguration { + + private ConnectPoint connectPoint; + + /** + * Creats a new connect point from a string representation. + * + * @param string connect point string + */ + public ConnectPointConfiguration(String string) { + connectPoint = ConnectPoint.deviceConnectPoint(string); + } + + /** + * Creates a new connect point from a string representation. + * + * @param string connect point string + * @return new connect point configuration + */ + public static ConnectPointConfiguration of(String string) { + return new ConnectPointConfiguration(string); + } + + /** + * Gets the connect point. + * + * @return connect point + */ + public ConnectPoint connectPoint() { + return connectPoint; + } +} diff --git a/framework/src/onos/apps/virtualbng/src/main/java/org/onosproject/virtualbng/VbngConfiguration.java b/framework/src/onos/apps/virtualbng/src/main/java/org/onosproject/virtualbng/VbngConfiguration.java index ee2cbeaa..1841675f 100644 --- a/framework/src/onos/apps/virtualbng/src/main/java/org/onosproject/virtualbng/VbngConfiguration.java +++ b/framework/src/onos/apps/virtualbng/src/main/java/org/onosproject/virtualbng/VbngConfiguration.java @@ -17,13 +17,15 @@ package org.onosproject.virtualbng; import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonProperty; - -import java.util.Collections; -import java.util.List; - import org.onlab.packet.IpAddress; import org.onlab.packet.IpPrefix; import org.onlab.packet.MacAddress; +import org.onosproject.net.ConnectPoint; + +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; /** * Contains the configuration data for virtual BNG that has been read from a @@ -36,6 +38,7 @@ public final class VbngConfiguration { private final MacAddress publicFacingMac; private final IpAddress xosIpAddress; private final int xosRestPort; + private final Map<String, ConnectPointConfiguration> hosts; /** * Default constructor. @@ -46,6 +49,7 @@ public final class VbngConfiguration { publicFacingMac = null; xosIpAddress = null; xosRestPort = 0; + hosts = null; } /** @@ -57,6 +61,7 @@ public final class VbngConfiguration { * public IP addresses * @param xosIpAddress the XOS server IP address * @param xosRestPort the port of the XOS server for REST + * @param hosts map of hosts */ @JsonCreator public VbngConfiguration(@JsonProperty("localPublicIpPrefixes") @@ -68,12 +73,15 @@ public final class VbngConfiguration { @JsonProperty("xosIpAddress") IpAddress xosIpAddress, @JsonProperty("xosRestPort") - int xosRestPort) { + int xosRestPort, + @JsonProperty("hosts") + Map<String, ConnectPointConfiguration> hosts) { localPublicIpPrefixes = prefixes; this.nextHopIpAddress = nextHopIpAddress; this.publicFacingMac = publicFacingMac; this.xosIpAddress = xosIpAddress; this.xosRestPort = xosRestPort; + this.hosts = hosts; } /** @@ -120,4 +128,13 @@ public final class VbngConfiguration { public int getXosRestPort() { return xosRestPort; } + + public Map<String, ConnectPoint> getHosts() { + return hosts.entrySet() + .stream() + .collect(Collectors.toMap( + e -> e.getKey(), + e -> e.getValue().connectPoint() + )); + } } diff --git a/framework/src/onos/apps/virtualbng/src/main/java/org/onosproject/virtualbng/VbngConfigurationManager.java b/framework/src/onos/apps/virtualbng/src/main/java/org/onosproject/virtualbng/VbngConfigurationManager.java index d27d6904..eb83e06c 100644 --- a/framework/src/onos/apps/virtualbng/src/main/java/org/onosproject/virtualbng/VbngConfigurationManager.java +++ b/framework/src/onos/apps/virtualbng/src/main/java/org/onosproject/virtualbng/VbngConfigurationManager.java @@ -16,16 +16,6 @@ package org.onosproject.virtualbng; import com.fasterxml.jackson.databind.ObjectMapper; - -import java.io.File; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.util.Collections; -import java.util.Iterator; -import java.util.Map; -import java.util.Map.Entry; -import java.util.concurrent.ConcurrentHashMap; - import org.apache.felix.scr.annotations.Activate; import org.apache.felix.scr.annotations.Component; import org.apache.felix.scr.annotations.Deactivate; @@ -33,9 +23,19 @@ import org.apache.felix.scr.annotations.Service; import org.onlab.packet.IpAddress; import org.onlab.packet.IpPrefix; import org.onlab.packet.MacAddress; +import org.onosproject.net.ConnectPoint; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.io.File; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.util.Collections; +import java.util.Iterator; +import java.util.Map; +import java.util.Map.Entry; +import java.util.concurrent.ConcurrentHashMap; + /** * Implementation of ConfigurationService which reads virtual BNG * configuration from a file. @@ -63,6 +63,7 @@ public class VbngConfigurationManager implements VbngConfigurationService { private MacAddress macOfPublicIpAddresses; private IpAddress xosIpAddress; private int xosRestPort; + private Map<String, ConnectPoint> nodeToPort; @Activate public void activate() { @@ -104,6 +105,8 @@ public class VbngConfigurationManager implements VbngConfigurationService { macOfPublicIpAddresses = config.getPublicFacingMac(); xosIpAddress = config.getXosIpAddress(); xosRestPort = config.getXosRestPort(); + nodeToPort = config.getHosts(); + } catch (FileNotFoundException e) { log.warn("Configuration file not found: {}", configFileName); @@ -132,6 +135,11 @@ public class VbngConfigurationManager implements VbngConfigurationService { return xosRestPort; } + @Override + public Map<String, ConnectPoint> getNodeToPort() { + return nodeToPort; + } + // TODO handle the case: the number of public IP addresses is not enough // for 1:1 mapping from public IP to private IP. @Override diff --git a/framework/src/onos/apps/virtualbng/src/main/java/org/onosproject/virtualbng/VbngConfigurationService.java b/framework/src/onos/apps/virtualbng/src/main/java/org/onosproject/virtualbng/VbngConfigurationService.java index ef8698a0..68c048f4 100644 --- a/framework/src/onos/apps/virtualbng/src/main/java/org/onosproject/virtualbng/VbngConfigurationService.java +++ b/framework/src/onos/apps/virtualbng/src/main/java/org/onosproject/virtualbng/VbngConfigurationService.java @@ -15,10 +15,11 @@ */ package org.onosproject.virtualbng; -import java.util.Map; - import org.onlab.packet.IpAddress; import org.onlab.packet.MacAddress; +import org.onosproject.net.ConnectPoint; + +import java.util.Map; /** * Provides information about the virtual BNG configuration. @@ -54,6 +55,13 @@ public interface VbngConfigurationService { int getXosRestPort(); /** + * Gets the host to port map. + * + * @return host to port map + */ + Map<String, ConnectPoint> getNodeToPort(); + + /** * Evaluates whether an IP address is an assigned public IP address. * * @param ipAddress the IP address to evaluate diff --git a/framework/src/onos/apps/virtualbng/src/main/java/org/onosproject/virtualbng/VbngManager.java b/framework/src/onos/apps/virtualbng/src/main/java/org/onosproject/virtualbng/VbngManager.java index 5e82b7e8..e03b25e8 100644 --- a/framework/src/onos/apps/virtualbng/src/main/java/org/onosproject/virtualbng/VbngManager.java +++ b/framework/src/onos/apps/virtualbng/src/main/java/org/onosproject/virtualbng/VbngManager.java @@ -15,18 +15,9 @@ */ package org.onosproject.virtualbng; -import static com.google.common.base.Preconditions.checkNotNull; - import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.node.ArrayNode; import com.fasterxml.jackson.databind.node.ObjectNode; -import com.google.common.collect.Maps; - -import java.util.Iterator; -import java.util.Map; -import java.util.Map.Entry; -import java.util.concurrent.ConcurrentHashMap; - import org.apache.felix.scr.annotations.Activate; import org.apache.felix.scr.annotations.Component; import org.apache.felix.scr.annotations.Deactivate; @@ -42,7 +33,6 @@ import org.onosproject.core.CoreService; import org.onosproject.net.ConnectPoint; import org.onosproject.net.DeviceId; import org.onosproject.net.Host; -import org.onosproject.net.PortNumber; import org.onosproject.net.flow.DefaultTrafficSelector; import org.onosproject.net.flow.DefaultTrafficTreatment; import org.onosproject.net.flow.TrafficSelector; @@ -56,6 +46,13 @@ import org.onosproject.net.intent.PointToPointIntent; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.util.Iterator; +import java.util.Map; +import java.util.Map.Entry; +import java.util.concurrent.ConcurrentHashMap; + +import static com.google.common.base.Preconditions.checkNotNull; + /** * This is a virtual Broadband Network Gateway (BNG) application. It mainly * has 3 functions: @@ -111,9 +108,8 @@ public class VbngManager implements VbngService { p2pIntentsToHost = new ConcurrentHashMap<>(); privateIpAddressMap = new ConcurrentHashMap<>(); - setupMap(); - nextHopIpAddress = vbngConfigurationService.getNextHopIpAddress(); + nodeToPort = vbngConfigurationService.getNodeToPort(); hostListener = new InternalHostListener(); hostService.addListener(hostListener); @@ -136,10 +132,16 @@ public class VbngManager implements VbngService { */ private void statusRecovery() { log.info("vBNG starts to recover from XOS record......"); - RestClient restClient = - new RestClient(vbngConfigurationService.getXosIpAddress(), - vbngConfigurationService.getXosRestPort()); - ObjectNode map = restClient.getRest(); + ObjectNode map; + try { + RestClient restClient = + new RestClient(vbngConfigurationService.getXosIpAddress(), + vbngConfigurationService.getXosRestPort()); + map = restClient.getRest(); + } catch (Exception e) { + log.error("Could not contact XOS", e); + return; + } if (map == null) { log.info("Stop to recover vBNG status due to the vBNG map " + "is null!"); @@ -168,21 +170,6 @@ public class VbngManager implements VbngService { } /** - * Sets up mapping from hostname to connect point. - */ - private void setupMap() { - nodeToPort = Maps.newHashMap(); - - nodeToPort.put("cordcompute01.onlab.us", - new ConnectPoint(FABRIC_DEVICE_ID, - PortNumber.portNumber(48))); - - nodeToPort.put("cordcompute02.onlab.us", - new ConnectPoint(FABRIC_DEVICE_ID, - PortNumber.portNumber(47))); - } - - /** * Creates a new vBNG. * * @param privateIpAddress a private IP address diff --git a/framework/src/onos/apps/vtn/pom.xml b/framework/src/onos/apps/vtn/pom.xml index c2cfe2be..e91b0c9b 100644 --- a/framework/src/onos/apps/vtn/pom.xml +++ b/framework/src/onos/apps/vtn/pom.xml @@ -37,4 +37,21 @@ <module>vtnweb</module> <module>app</module> </modules> + <dependencies> + <dependency> + <groupId>org.onosproject</groupId> + <artifactId>onlab-junit</artifactId> + <scope>test</scope> + </dependency> + <dependency> + <groupId>com.google.guava</groupId> + <artifactId>guava-testlib</artifactId> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.easymock</groupId> + <artifactId>easymock</artifactId> + <scope>test</scope> + </dependency> + </dependencies> </project> diff --git a/framework/src/onos/apps/vtn/sfcmgr/src/main/java/org/onosproject/sfc/SfcService.java b/framework/src/onos/apps/vtn/sfcmgr/src/main/java/org/onosproject/sfc/SfcService.java new file mode 100644 index 00000000..a2748f5e --- /dev/null +++ b/framework/src/onos/apps/vtn/sfcmgr/src/main/java/org/onosproject/sfc/SfcService.java @@ -0,0 +1,52 @@ +/* + * 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.sfc; + +import org.onosproject.vtnrsc.PortChain; + +/** + * SFC application that applies flows to the device. + */ +public interface SfcService { + /** + * Applies flow classification to OVS. + * + * @param portChain Port-Chain. + */ + void InstallFlowClassification(PortChain portChain); + + + /** + * Remove flow classification from OVS. + * + * @param portChain Port-Chain. + */ + void UnInstallFlowClassification(PortChain portChain); + + /** + * Applies Service Function chain to OVS. + * + * @param portChain Port-Chain. + */ + void InstallServiceFunctionChain(PortChain portChain); + + /** + * Remove Service Function chain from OVS. + * + * @param portChain Port-Chain. + */ + void UnInstallServiceFunctionChain(PortChain portChain); +} diff --git a/framework/src/onos/apps/vtn/sfcmgr/src/main/java/org/onosproject/sfc/impl/SfcManager.java b/framework/src/onos/apps/vtn/sfcmgr/src/main/java/org/onosproject/sfc/impl/SfcManager.java new file mode 100644 index 00000000..1872295f --- /dev/null +++ b/framework/src/onos/apps/vtn/sfcmgr/src/main/java/org/onosproject/sfc/impl/SfcManager.java @@ -0,0 +1,69 @@ +/* + * 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.sfc.impl; + +import static org.slf4j.LoggerFactory.getLogger; + +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.Service; +import org.onosproject.vtnrsc.sfc.PortChain; +import org.slf4j.Logger; + +/** + * Provides implementation of SFC Service. + */ +@Component(immediate = true) +@Service +public class SfcManager implements SfcService { + + private final Logger log = getLogger(SfcManager.class); + + @Activate + public void activate() { + log.info("Started"); + } + + @Deactivate + public void deactivate() { + log.info("Stopped"); + } + + @Override + public void InstallFlowClassification(PortChain portChain) { + log.debug("InstallFlowClassification"); + //TODO: Installation of flow classification into OVS. + } + + @Override + public void UnInstallFlowClassification(PortChain portChain) { + log.debug("UnInstallFlowClassification"); + //TODO: Un-installation flow classification from OVS + } + + @Override + public void InstallServiceFunctionChain(PortChain portChain) { + log.debug("InstallServiceFunctionChain"); + //TODO: Installation of Service Function chain into OVS. + } + + @Override + public void UnInstallServiceFunctionChain(PortChain portChain) { + log.debug("UnInstallServiceFunctionChain"); + //TODO: Un-installation of Service Function chain from OVS. + } +} diff --git a/framework/src/onos/apps/vtn/sfcmgr/src/main/java/org/onosproject/sfc/impl/package-info.java b/framework/src/onos/apps/vtn/sfcmgr/src/main/java/org/onosproject/sfc/impl/package-info.java new file mode 100644 index 00000000..0dba868c --- /dev/null +++ b/framework/src/onos/apps/vtn/sfcmgr/src/main/java/org/onosproject/sfc/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. + */ + +/** + * SFC Service manager for interacting with SFC. + */ +package org.onosproject.sfc.impl; diff --git a/framework/src/onos/apps/vtn/sfcmgr/src/main/java/org/onosproject/sfc/package-info.java b/framework/src/onos/apps/vtn/sfcmgr/src/main/java/org/onosproject/sfc/package-info.java new file mode 100644 index 00000000..1dcb9929 --- /dev/null +++ b/framework/src/onos/apps/vtn/sfcmgr/src/main/java/org/onosproject/sfc/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 interacting with SFC. + */ +package org.onosproject.sfc; diff --git a/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/DefaultFlowClassifier.java b/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/DefaultFlowClassifier.java new file mode 100644 index 00000000..39df2cff --- /dev/null +++ b/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/DefaultFlowClassifier.java @@ -0,0 +1,413 @@ +/* + * 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.vtnrsc; + +import java.util.Objects; +import org.onlab.packet.IpPrefix; + +import com.google.common.base.MoreObjects; +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Provides Default flow classifier. + */ +public final class DefaultFlowClassifier implements FlowClassifier { + + private final FlowClassifierId flowClassifierId; + private final TenantId tenantId; + private final String name; + private final String description; + private final String etherType; + private final String protocol; + private final int minSrcPortRange; + private final int maxSrcPortRange; + private final int minDstPortRange; + private final int maxDstPortRange; + private final IpPrefix srcIpPrefix; + private final IpPrefix dstIpPrefix; + private final VirtualPortId srcPort; + private final VirtualPortId dstPort; + private static final int NULL_PORT = 0; + private static final String FLOW_CLASSIFIER_ID_NOT_NULL = "FlowClassifier id can not be null."; + private static final String TENANT_ID_NOT_NULL = "Tenant id can not be null."; + + /** + * Constructor to create default flow classifier. + * + * @param flowClassifierId flow classifier Id + * @param tenantId Tenant ID + * @param name flow classifier name + * @param description flow classifier description + * @param etherType etherType + * @param protocol IP protocol + * @param minSrcPortRange Minimum Source port range + * @param maxSrcPortRange Maximum Source port range + * @param minDstPortRange Minimum destination port range + * @param maxDstPortRange Maximum destination port range + * @param srcIpPrefix Source IP prefix + * @param dstIpPrefix destination IP prefix + * @param srcPort Source VirtualPort + * @param dstPort destination VirtualPort + */ + private DefaultFlowClassifier(FlowClassifierId flowClassifierId, TenantId tenantId, String name, + String description, String etherType, String protocol, int minSrcPortRange, int maxSrcPortRange, + int minDstPortRange, int maxDstPortRange, IpPrefix srcIpPrefix, IpPrefix dstIpPrefix, + VirtualPortId srcPort, VirtualPortId dstPort) { + this.flowClassifierId = flowClassifierId; + this.tenantId = tenantId; + this.name = name; + this.description = description; + this.etherType = etherType; + this.protocol = protocol; + this.minSrcPortRange = minSrcPortRange; + this.maxSrcPortRange = maxSrcPortRange; + this.minDstPortRange = minDstPortRange; + this.maxDstPortRange = maxDstPortRange; + this.srcIpPrefix = srcIpPrefix; + this.dstIpPrefix = dstIpPrefix; + this.srcPort = srcPort; + this.dstPort = dstPort; + } + + @Override + public FlowClassifierId flowClassifierId() { + return flowClassifierId; + } + + @Override + public TenantId tenantId() { + return tenantId; + } + + @Override + public String name() { + return name; + } + + @Override + public String description() { + return description; + } + + @Override + public String etherType() { + return etherType; + } + + @Override + public String protocol() { + return protocol; + } + + @Override + public int minSrcPortRange() { + return minSrcPortRange; + } + + @Override + public int maxSrcPortRange() { + return maxSrcPortRange; + } + + @Override + public int minDstPortRange() { + return minDstPortRange; + } + + @Override + public int maxDstPortRange() { + return maxDstPortRange; + } + + @Override + public IpPrefix srcIpPrefix() { + return srcIpPrefix; + } + + @Override + public IpPrefix dstIpPrefix() { + return dstIpPrefix; + } + + @Override + public VirtualPortId srcPort() { + return srcPort; + } + + @Override + public VirtualPortId dstPort() { + return dstPort; + } + + /** + * Builder class for constructing Flow classifier. + */ + public static class Builder implements FlowClassifier.Builder { + + private FlowClassifierId flowClassifierId; + private TenantId tenantId; + private String name; + private boolean isFlowClassifierNameSet = false; + private String description; + private boolean isFlowClassifierDescriptionSet = false; + private String etherType; + private boolean isEtherTypeSet = false; + private String protocol; + private boolean isProtocolSet = false; + private int minSrcPortRange; + private boolean isMinSrcPortRangeSet = false; + private int maxSrcPortRange; + private boolean isMaxSrcPortRangeSet = false; + private int minDstPortRange; + private boolean isMinDstPortRangeSet = false; + private int maxDstPortRange; + private boolean isMaxDstPortRangeSet = false; + private IpPrefix srcIpPrefix; + private boolean isSrcIpPrefixSet = false; + private IpPrefix dstIpPrefix; + private boolean isDstIpPrefixSet = false; + private VirtualPortId srcPort; + private boolean isSrcPortSet = false; + private VirtualPortId dstPort; + private boolean isDstPortSet = false; + + @Override + public FlowClassifier build() { + + checkNotNull(flowClassifierId, FLOW_CLASSIFIER_ID_NOT_NULL); + checkNotNull(tenantId, TENANT_ID_NOT_NULL); + String name = null; + String description = null; + String etherType = null; + String protocol = null; + int minSrcPortRange = NULL_PORT; + int maxSrcPortRange = NULL_PORT; + int minDstPortRange = NULL_PORT; + int maxDstPortRange = NULL_PORT; + IpPrefix srcIpPrefix = null; + IpPrefix dstIpPrefix = null; + VirtualPortId srcPort = null; + VirtualPortId dstPort = null; + + if (isFlowClassifierNameSet) { + name = this.name; + } + if (isFlowClassifierDescriptionSet) { + description = this.description; + } + if (isEtherTypeSet) { + etherType = this.etherType; + } + if (isProtocolSet) { + protocol = this.protocol; + } + if (isMinSrcPortRangeSet) { + minSrcPortRange = this.minSrcPortRange; + } + if (isMaxSrcPortRangeSet) { + maxSrcPortRange = this.maxSrcPortRange; + } + if (isMinDstPortRangeSet) { + minDstPortRange = this.minDstPortRange; + } + if (isMaxDstPortRangeSet) { + maxDstPortRange = this.maxDstPortRange; + } + if (isSrcIpPrefixSet) { + srcIpPrefix = this.srcIpPrefix; + } + if (isDstIpPrefixSet) { + dstIpPrefix = this.dstIpPrefix; + } + if (isSrcPortSet) { + srcPort = this.srcPort; + } + if (isDstPortSet) { + dstPort = this.dstPort; + } + + return new DefaultFlowClassifier(flowClassifierId, tenantId, name, description, etherType, protocol, + minSrcPortRange, maxSrcPortRange, minDstPortRange, maxDstPortRange, srcIpPrefix, dstIpPrefix, + srcPort, dstPort); + } + + @Override + public Builder setFlowClassifierId(FlowClassifierId flowClassifierId) { + this.flowClassifierId = flowClassifierId; + return this; + } + + @Override + public Builder setTenantId(TenantId tenantId) { + this.tenantId = tenantId; + return this; + } + + @Override + public Builder setName(String name) { + this.name = name; + this.isFlowClassifierNameSet = true; + return this; + } + + @Override + public Builder setDescription(String description) { + this.description = description; + this.isFlowClassifierDescriptionSet = true; + return this; + } + + @Override + public Builder setEtherType(String etherType) { + this.etherType = etherType; + this.isEtherTypeSet = true; + return this; + } + + @Override + public Builder setProtocol(String protocol) { + this.protocol = protocol; + this.isProtocolSet = true; + return this; + } + + @Override + public Builder setMinSrcPortRange(int minSrcPortRange) { + this.minSrcPortRange = minSrcPortRange; + this.isMinSrcPortRangeSet = true; + return this; + } + + @Override + public Builder setMaxSrcPortRange(int maxSrcPortRange) { + this.maxSrcPortRange = maxSrcPortRange; + this.isMaxSrcPortRangeSet = true; + return this; + } + + @Override + public Builder setMinDstPortRange(int minDstPortRange) { + this.minDstPortRange = minDstPortRange; + this.isMinDstPortRangeSet = true; + return this; + } + + @Override + public Builder setMaxDstPortRange(int maxDstPortRange) { + this.maxDstPortRange = maxDstPortRange; + this.isMaxDstPortRangeSet = true; + return this; + } + + @Override + public Builder setSrcIpPrefix(IpPrefix srcIpPrefix) { + this.srcIpPrefix = srcIpPrefix; + this.isSrcIpPrefixSet = true; + return this; + } + + @Override + public Builder setDstIpPrefix(IpPrefix dstIpPrefix) { + this.dstIpPrefix = dstIpPrefix; + this.isDstIpPrefixSet = true; + return this; + } + + @Override + public Builder setSrcPort(VirtualPortId srcPort) { + this.srcPort = srcPort; + this.isSrcPortSet = true; + return this; + } + + @Override + public Builder setDstPort(VirtualPortId dstPort) { + this.dstPort = dstPort; + this.isDstPortSet = true; + return this; + } + } + + @Override + public int hashCode() { + return Objects.hash(flowClassifierId, tenantId, name, description, etherType, protocol, minSrcPortRange, + maxSrcPortRange, minDstPortRange, maxDstPortRange, srcIpPrefix, dstIpPrefix, srcPort, dstPort); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof DefaultFlowClassifier) { + DefaultFlowClassifier other = (DefaultFlowClassifier) obj; + return Objects.equals(this.flowClassifierId, other.flowClassifierId) + && Objects.equals(this.tenantId, other.tenantId) + && Objects.equals(this.name, other.name) + && Objects.equals(this.description, other.description) + && Objects.equals(this.etherType, other.etherType) + && Objects.equals(this.protocol, other.protocol) + && Objects.equals(this.minSrcPortRange, other.minSrcPortRange) + && Objects.equals(this.maxSrcPortRange, other.maxSrcPortRange) + && Objects.equals(this.minDstPortRange, other.minDstPortRange) + && Objects.equals(this.maxDstPortRange, other.maxDstPortRange) + && Objects.equals(this.srcIpPrefix, other.srcIpPrefix) + && Objects.equals(this.dstIpPrefix, other.dstIpPrefix) + && Objects.equals(this.srcPort, other.srcPort) + && Objects.equals(this.dstPort, other.dstPort); + } + return false; + } + + @Override + public boolean exactMatch(FlowClassifier flowClassifier) { + return this.equals(flowClassifier) + && Objects.equals(this.flowClassifierId, flowClassifier.flowClassifierId()) + && Objects.equals(this.tenantId, flowClassifier.tenantId()) + && Objects.equals(this.name, flowClassifier.name()) + && Objects.equals(this.description, flowClassifier.description()) + && Objects.equals(this.etherType, flowClassifier.etherType()) + && Objects.equals(this.protocol, flowClassifier.protocol()) + && Objects.equals(this.minSrcPortRange, flowClassifier.minSrcPortRange()) + && Objects.equals(this.maxSrcPortRange, flowClassifier.maxSrcPortRange()) + && Objects.equals(this.minDstPortRange, flowClassifier.minDstPortRange()) + && Objects.equals(this.maxDstPortRange, flowClassifier.maxDstPortRange()) + && Objects.equals(this.srcIpPrefix, flowClassifier.srcIpPrefix()) + && Objects.equals(this.dstIpPrefix, flowClassifier.dstIpPrefix()) + && Objects.equals(this.srcPort, flowClassifier.srcPort()) + && Objects.equals(this.dstPort, flowClassifier.dstPort()); + } + + @Override + public String toString() { + return MoreObjects.toStringHelper(getClass()) + .add("FlowClassifierId", flowClassifierId) + .add("TenantId", tenantId) + .add("Name", name) + .add("Description", description) + .add("String", etherType) + .add("Protocol", protocol) + .add("MinSrcPortRange", minSrcPortRange) + .add("MaxSrcPortRange", maxSrcPortRange) + .add("MinDstPortRange", minDstPortRange) + .add("MaxDstPortRange", maxDstPortRange) + .add("SrcIpPrefix", srcIpPrefix) + .add("DstIpPrefix", dstIpPrefix) + .add("SrcPort", srcPort) + .add("DstPort", dstPort) + .toString(); + } +} diff --git a/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/DefaultPortChain.java b/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/DefaultPortChain.java new file mode 100644 index 00000000..89b94b3e --- /dev/null +++ b/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/DefaultPortChain.java @@ -0,0 +1,201 @@ +/* + * 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.vtnrsc; + +import static com.google.common.base.MoreObjects.toStringHelper; +import static com.google.common.base.Preconditions.checkNotNull; + +import java.util.List; +import java.util.Objects; + +import com.google.common.collect.ImmutableList; + +/** + * Implementation of port chain. + */ +public final class DefaultPortChain implements PortChain { + + private final PortChainId portChainId; + private final TenantId tenantId; + private final String name; + private final String description; + private final List<PortPairGroupId> portPairGroupList; + private final List<FlowClassifierId> flowClassifierList; + + /** + * Default constructor to create port chain. + * + * @param portChainId port chain id + * @param tenantId tenant id + * @param name name of port chain + * @param description description of port chain + * @param portPairGroupList port pair group list + * @param flowClassifierList flow classifier list + */ + private DefaultPortChain(PortChainId portChainId, TenantId tenantId, + String name, String description, + List<PortPairGroupId> portPairGroupList, + List<FlowClassifierId> flowClassifierList) { + + this.portChainId = portChainId; + this.tenantId = tenantId; + this.name = name; + this.description = description; + this.portPairGroupList = portPairGroupList; + this.flowClassifierList = flowClassifierList; + } + + @Override + public PortChainId portChainId() { + return portChainId; + } + + @Override + public TenantId tenantId() { + return tenantId; + } + + @Override + public String name() { + return name; + } + + @Override + public String description() { + return description; + } + + @Override + public List<PortPairGroupId> portPairGroups() { + return ImmutableList.copyOf(portPairGroupList); + } + + @Override + public List<FlowClassifierId> flowClassifiers() { + return ImmutableList.copyOf(flowClassifierList); + } + + @Override + public int hashCode() { + return Objects.hash(portChainId, tenantId, name, description, + portPairGroupList, flowClassifierList); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof DefaultPortChain) { + DefaultPortChain that = (DefaultPortChain) obj; + return Objects.equals(portChainId, that.portChainId) && + Objects.equals(tenantId, that.tenantId) && + Objects.equals(name, that.name) && + Objects.equals(description, that.description) && + Objects.equals(portPairGroupList, that.portPairGroupList) && + Objects.equals(flowClassifierList, that.flowClassifierList); + } + return false; + } + + @Override + public boolean exactMatch(PortChain portChain) { + return this.equals(portChain) && + Objects.equals(this.portChainId, portChain.portChainId()) && + Objects.equals(this.tenantId, portChain.tenantId()); + } + + @Override + public String toString() { + return toStringHelper(this) + .add("id", portChainId.toString()) + .add("tenantId", tenantId.toString()) + .add("name", name) + .add("description", description) + .add("portPairGroupList", portPairGroupList) + .add("flowClassifier", flowClassifierList) + .toString(); + } + + /** + * To create an instance of the builder. + * + * @return instance of builder + */ + public static Builder builder() { + return new Builder(); + } + + /** + * Builder class for Port chain. + */ + public static final class Builder implements PortChain.Builder { + + private PortChainId portChainId; + private TenantId tenantId; + private String name; + private String description; + private List<PortPairGroupId> portPairGroupList; + private List<FlowClassifierId> flowClassifierList; + + @Override + public Builder setId(PortChainId portChainId) { + this.portChainId = portChainId; + return this; + } + + @Override + public Builder setTenantId(TenantId tenantId) { + this.tenantId = tenantId; + return this; + } + + @Override + public Builder setName(String name) { + this.name = name; + return this; + } + + @Override + public Builder setDescription(String description) { + this.description = description; + return this; + } + + @Override + public Builder setPortPairGroups(List<PortPairGroupId> portPairGroups) { + this.portPairGroupList = portPairGroups; + return this; + } + + @Override + public Builder setFlowClassifiers(List<FlowClassifierId> flowClassifiers) { + this.flowClassifierList = flowClassifiers; + return this; + } + + @Override + public PortChain build() { + + checkNotNull(portChainId, "Port chain id cannot be null"); + checkNotNull(tenantId, "Tenant id cannot be null"); + checkNotNull(portPairGroupList, "Port pair groups cannot be null"); + + return new DefaultPortChain(portChainId, tenantId, name, description, + portPairGroupList, flowClassifierList); + } + } +} diff --git a/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/DefaultPortPair.java b/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/DefaultPortPair.java new file mode 100644 index 00000000..4b3b7cf3 --- /dev/null +++ b/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/DefaultPortPair.java @@ -0,0 +1,198 @@ +/* + * 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.vtnrsc; + +import static com.google.common.base.MoreObjects.toStringHelper; +import static com.google.common.base.Preconditions.checkNotNull; + +import java.util.Objects; + +/** + * Implementation of port pair. + */ +public final class DefaultPortPair implements PortPair { + + private final PortPairId portPairId; + private final TenantId tenantId; + private final String name; + private final String description; + private final String ingress; + private final String egress; + + /** + * Default constructor to create Port Pair. + * + * @param portPairId port pair id + * @param tenantId tenant id + * @param name name of port pair + * @param description description of port pair + * @param ingress ingress port + * @param egress egress port + */ + private DefaultPortPair(PortPairId portPairId, TenantId tenantId, + String name, String description, + String ingress, String egress) { + + this.portPairId = portPairId; + this.tenantId = tenantId; + this.name = name; + this.description = description; + this.ingress = ingress; + this.egress = egress; + } + + @Override + public PortPairId portPairId() { + return portPairId; + } + + @Override + public TenantId tenantId() { + return tenantId; + } + + @Override + public String name() { + return name; + } + + @Override + public String description() { + return description; + } + + @Override + public String ingress() { + return ingress; + } + + @Override + public String egress() { + return egress; + } + + @Override + public int hashCode() { + return Objects.hash(portPairId, tenantId, name, description, + ingress, egress); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof DefaultPortPair) { + DefaultPortPair that = (DefaultPortPair) obj; + return Objects.equals(portPairId, that.portPairId) && + Objects.equals(tenantId, that.tenantId) && + Objects.equals(name, that.name) && + Objects.equals(description, that.description) && + Objects.equals(ingress, that.ingress) && + Objects.equals(egress, that.egress); + } + return false; + } + + @Override + public boolean exactMatch(PortPair portPair) { + return this.equals(portPair) && + Objects.equals(this.portPairId, portPair.portPairId()) && + Objects.equals(this.tenantId, portPair.tenantId()); + } + + @Override + public String toString() { + return toStringHelper(this) + .add("id", portPairId.toString()) + .add("tenantId", tenantId.tenantId()) + .add("name", name) + .add("description", description) + .add("ingress", ingress) + .add("egress", egress) + .toString(); + } + + /** + * To create an instance of the builder. + * + * @return instance of builder + */ + public static Builder builder() { + return new Builder(); + } + + /** + * Builder class for Port pair. + */ + public static final class Builder implements PortPair.Builder { + + private PortPairId portPairId; + private TenantId tenantId; + private String name; + private String description; + private String ingress; + private String egress; + + @Override + public Builder setId(PortPairId portPairId) { + this.portPairId = portPairId; + return this; + } + + @Override + public Builder setTenantId(TenantId tenantId) { + this.tenantId = tenantId; + return this; + } + + @Override + public Builder setName(String name) { + this.name = name; + return this; + } + + @Override + public Builder setDescription(String description) { + this.description = description; + return this; + } + + @Override + public Builder setIngress(String ingress) { + this.ingress = ingress; + return this; + } + + @Override + public Builder setEgress(String egress) { + this.egress = egress; + return this; + } + + @Override + public PortPair build() { + + checkNotNull(portPairId, "Port pair id cannot be null"); + checkNotNull(tenantId, "Tenant id cannot be null"); + checkNotNull(ingress, "Ingress of a port pair cannot be null"); + checkNotNull(egress, "Egress of a port pair cannot be null"); + + return new DefaultPortPair(portPairId, tenantId, name, description, + ingress, egress); + } + } +} diff --git a/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/DefaultPortPairGroup.java b/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/DefaultPortPairGroup.java new file mode 100644 index 00000000..877cc6c9 --- /dev/null +++ b/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/DefaultPortPairGroup.java @@ -0,0 +1,183 @@ +/* + * 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.vtnrsc; + +import static com.google.common.base.MoreObjects.toStringHelper; +import static com.google.common.base.Preconditions.checkNotNull; + +import java.util.List; +import java.util.Objects; + +import com.google.common.collect.ImmutableList; + +/** + * Implementation of port pair group. + */ +public final class DefaultPortPairGroup implements PortPairGroup { + + private final PortPairGroupId portPairGroupId; + private final TenantId tenantId; + private final String name; + private final String description; + private final List<PortPairId> portPairList; + + /** + * Default constructor to create Port Pair Group. + * + * @param portPairGroupId port pair group id + * @param tenantId tenant id + * @param name name of port pair group + * @param description description of port pair group + * @param portPairList list of port pairs + */ + private DefaultPortPairGroup(PortPairGroupId portPairGroupId, TenantId tenantId, + String name, String description, + List<PortPairId> portPairList) { + + this.portPairGroupId = portPairGroupId; + this.tenantId = tenantId; + this.name = name; + this.description = description; + this.portPairList = portPairList; + } + + @Override + public PortPairGroupId portPairGroupId() { + return portPairGroupId; + } + + @Override + public TenantId tenantId() { + return tenantId; + } + + @Override + public String name() { + return name; + } + + @Override + public String description() { + return description; + } + + @Override + public List<PortPairId> portPairs() { + return ImmutableList.copyOf(portPairList); + } + + @Override + public int hashCode() { + return Objects.hash(portPairGroupId, tenantId, name, description, + portPairList); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof DefaultPortPairGroup) { + DefaultPortPairGroup that = (DefaultPortPairGroup) obj; + return Objects.equals(portPairGroupId, that.portPairGroupId) && + Objects.equals(tenantId, that.tenantId) && + Objects.equals(name, that.name) && + Objects.equals(description, that.description) && + Objects.equals(portPairList, that.portPairList); + } + return false; + } + + @Override + public boolean exactMatch(PortPairGroup portPairGroup) { + return this.equals(portPairGroup) && + Objects.equals(this.portPairGroupId, portPairGroup.portPairGroupId()) && + Objects.equals(this.tenantId, portPairGroup.tenantId()); + } + + @Override + public String toString() { + return toStringHelper(this) + .add("id", portPairGroupId.toString()) + .add("tenantId", tenantId.toString()) + .add("name", name) + .add("description", description) + .add("portPairGroupList", portPairList) + .toString(); + } + + /** + * To create an instance of the builder. + * + * @return instance of builder + */ + public static Builder builder() { + return new Builder(); + } + + /** + * Builder class for Port pair group. + */ + public static final class Builder implements PortPairGroup.Builder { + + private PortPairGroupId portPairGroupId; + private TenantId tenantId; + private String name; + private String description; + private List<PortPairId> portPairList; + + @Override + public Builder setId(PortPairGroupId portPairGroupId) { + this.portPairGroupId = portPairGroupId; + return this; + } + + @Override + public Builder setTenantId(TenantId tenantId) { + this.tenantId = tenantId; + return this; + } + + @Override + public Builder setName(String name) { + this.name = name; + return this; + } + + @Override + public Builder setDescription(String description) { + this.description = description; + return this; + } + + @Override + public Builder setPortPairs(List<PortPairId> portPairs) { + this.portPairList = portPairs; + return this; + } + + @Override + public PortPairGroup build() { + + checkNotNull(portPairGroupId, "Port pair group id cannot be null"); + checkNotNull(tenantId, "Tenant id cannot be null"); + checkNotNull(portPairList, "Port pairs cannot be null"); + + return new DefaultPortPairGroup(portPairGroupId, tenantId, name, description, + portPairList); + } + } +} diff --git a/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/FlowClassifier.java b/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/FlowClassifier.java new file mode 100644 index 00000000..7b4108dc --- /dev/null +++ b/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/FlowClassifier.java @@ -0,0 +1,259 @@ +/* + * 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.vtnrsc; + +import org.onlab.packet.IpPrefix; + +/** + * Abstraction of an entity which provides flow classifier for service function chain. + * FlowClassifier classify the traffic based on the criteria defined in the request. + * The classification can be based on port range or source and destination IP address or + * other flow classifier elements. + */ +public interface FlowClassifier { + + /** + * Returns flow classifier ID. + * + * @return flow classifier id + */ + FlowClassifierId flowClassifierId(); + + /** + * Returns Tenant ID. + * + * @return tenant Id + */ + TenantId tenantId(); + + /** + * Returns flow classifier name. + * + * @return flow classifier name + */ + String name(); + + /** + * Returns flow classifier description. + * + * @return flow classifier description + */ + String description(); + + /** + * Returns EtherType. + * + * @return EtherType + */ + String etherType(); + + /** + * Returns IP Protocol. + * + * @return IP protocol + */ + String protocol(); + + /** + * Returns minimum source port range. + * + * @return minimum source port range + */ + int minSrcPortRange(); + + /** + * Returns maximum source port range. + * + * @return maximum source port range + */ + int maxSrcPortRange(); + + /** + * Returns minimum destination port range. + * + * @return minimum destination port range + */ + int minDstPortRange(); + + /** + * Returns maximum destination port range. + * + * @return maximum destination port range. + */ + int maxDstPortRange(); + + /** + * Returns Source IP prefix. + * + * @return Source IP prefix + */ + IpPrefix srcIpPrefix(); + + /** + * Returns Destination IP prefix. + * + * @return Destination IP prefix + */ + IpPrefix dstIpPrefix(); + + /** + * Returns Source virtual port. + * + * @return Source virtual port + */ + VirtualPortId srcPort(); + + /** + * Returns Destination virtual port. + * + * @return Destination virtual port + */ + VirtualPortId dstPort(); + + /** + * Returns whether this Flow classifier is an exact match to the + * Flow classifier given in the argument. + * + * @param flowClassifier other flowClassifier to match against + * @return true if the flowClassifiers are an exact match, otherwise false + */ + boolean exactMatch(FlowClassifier flowClassifier); + + /** + * Builder for flow Classifier. + */ + interface Builder { + + /** + * Returns Flow Classifier. + * + * @return flow classifier. + */ + FlowClassifier build(); + + /** + * Sets Flow Classifier ID. + * + * @param flowClassifierId flow classifier id. + * @return Builder object by setting flow classifier Id. + */ + Builder setFlowClassifierId(FlowClassifierId flowClassifierId); + + /** + * Sets Tenant ID. + * + * @param tenantId tenant id. + * @return Builder object by setting Tenant ID. + */ + Builder setTenantId(TenantId tenantId); + + /** + * Sets Flow classifier name. + * + * @param name flow classifier name + * @return builder object by setting flow classifier name + */ + Builder setName(String name); + + /** + * Sets flow classifier description. + * + * @param description flow classifier description + * @return flow classifier description + */ + Builder setDescription(String description); + + /** + * Sets EtherType. + * + * @param etherType EtherType + * @return EtherType + */ + Builder setEtherType(String etherType); + + /** + * Sets IP protocol. + * + * @param protocol IP protocol + * @return builder object by setting IP protocol + */ + Builder setProtocol(String protocol); + + /** + * Set minimum source port range. + * + * @param minRange minimum source port range + * @return builder object by setting minimum source port range + */ + Builder setMinSrcPortRange(int minRange); + + /** + * Sets maximum source port range. + * + * @param maxRange maximum source port range + * @return builder object by setting maximum source port range + */ + Builder setMaxSrcPortRange(int maxRange); + + /** + * Sets minimum destination port range. + * + * @param minRange minimum destination port range + * @return builder object by setting minimum destination port range + */ + Builder setMinDstPortRange(int minRange); + + /** + * Sets maximum destination port range. + * + * @param maxRange maximum destination port range. + * @return builder object by setting maximum destination port range. + */ + Builder setMaxDstPortRange(int maxRange); + + /** + * Sets Source IP prefix. + * + * @param srcIpPrefix Source IP prefix + * @return builder object by setting Source IP prefix + */ + Builder setSrcIpPrefix(IpPrefix srcIpPrefix); + + /** + * Sets Destination IP prefix. + * + * @param dstIpPrefix Destination IP prefix + * @return builder object by setting Destination IP prefix + */ + Builder setDstIpPrefix(IpPrefix dstIpPrefix); + + /** + * Sets Source virtual port. + * + * @param srcPort Source virtual port + * @return builder object by setting Source virtual port + */ + Builder setSrcPort(VirtualPortId srcPort); + + /** + * Sets Destination virtual port. + * + * @param dstPort Destination virtual port + * @return builder object by setting Destination virtual port + */ + Builder setDstPort(VirtualPortId dstPort); + } +} diff --git a/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/FlowClassifierId.java b/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/FlowClassifierId.java new file mode 100644 index 00000000..b789abe3 --- /dev/null +++ b/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/FlowClassifierId.java @@ -0,0 +1,91 @@ +/* + * 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.vtnrsc; + +import com.google.common.base.MoreObjects; + +import java.util.UUID; +import java.util.Objects; + +/** + * Flow classification identifier. + */ +public final class FlowClassifierId { + + private final UUID flowClassifierId; + + /** + * Constructor to create flow classifier id. + * + * @param flowClassifierId flow classifier id. + */ + private FlowClassifierId(final UUID flowClassifierId) { + this.flowClassifierId = flowClassifierId; + } + + /** + * Returns new flow classifier id. + * + * @param flowClassifierId flow classifier id + * @return new flow classifier id + */ + public static FlowClassifierId flowClassifierId(final UUID flowClassifierId) { + return new FlowClassifierId(flowClassifierId); + } + + /** + * Returns new flow classifier id. + * + * @param flowClassifierId flow classifier id + * @return new flow classifier id + */ + public static FlowClassifierId flowClassifierId(final String flowClassifierId) { + return new FlowClassifierId(UUID.fromString(flowClassifierId)); + } + + /** + * Returns the value of flow classifier id. + * + * @return flow classifier id. + */ + public UUID value() { + return flowClassifierId; + } + + @Override + public int hashCode() { + return Objects.hashCode(this.flowClassifierId); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof FlowClassifierId) { + final FlowClassifierId other = (FlowClassifierId) obj; + return Objects.equals(this.flowClassifierId, other.flowClassifierId); + } + return false; + } + + @Override + public String toString() { + return MoreObjects.toStringHelper(getClass()) + .add("FlowClassifierId", flowClassifierId) + .toString(); + } +} diff --git a/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/PortChain.java b/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/PortChain.java new file mode 100644 index 00000000..d147eaaa --- /dev/null +++ b/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/PortChain.java @@ -0,0 +1,148 @@ +/* + * 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.vtnrsc; + +import java.util.List; + +/** + * Abstraction of an entity providing Port Chain information. + * A Port Chain (Service Function Path) consists of + * a set of Neutron ports, to define the sequence of service functions + * a set of flow classifiers, to specify the classified traffic flows to enter the chain + */ +public interface PortChain { + + /** + * Returns the ID of this port chain. + * + * @return the port chain id + */ + PortChainId portChainId(); + + /** + * Returns the tenant id of this port chain. + * + * @return the tenant id + */ + TenantId tenantId(); + + /** + * Returns the name of this port chain. + * + * @return name of port chain + */ + String name(); + + /** + * Returns the description of this port chain. + * + * @return description of port chain + */ + String description(); + + /** + * Returns the list of port pair groups associated with + * this port chain. + * + * @return list of port pair groups + */ + List<PortPairGroupId> portPairGroups(); + + /** + * Returns the list of flow classifiers associated with + * this port chain. + * + * @return list of flow classifiers + */ + List<FlowClassifierId> flowClassifiers(); + + /** + * Returns whether this port chain is an exact match to the port chain given + * in the argument. + * <p> + * Exact match means the port pair groups and flow classifiers match + * with the given port chain. It does not consider the port chain id, name + * and description. + * </p> + * + * @param portChain other port chain to match against + * @return true if the port chains are an exact match, otherwise false + */ + boolean exactMatch(PortChain portChain); + + /** + * A port chain builder.. + */ + interface Builder { + + /** + * Assigns the port chain id to this object. + * + * @param portChainId the port chain id + * @return this the builder object + */ + Builder setId(PortChainId portChainId); + + /** + * Assigns tenant id to this object. + * + * @param tenantId tenant id of the port chain + * @return this the builder object + */ + Builder setTenantId(TenantId tenantId); + + /** + * Assigns the name to this object. + * + * @param name name of the port chain + * @return this the builder object + */ + Builder setName(String name); + + /** + * Assigns the description to this object. + * + * @param description description of the port chain + * @return this the builder object + */ + Builder setDescription(String description); + + /** + * Assigns the port pair groups associated with the port chain + * to this object. + * + * @param portPairGroups list of port pair groups + * @return this the builder object + */ + Builder setPortPairGroups(List<PortPairGroupId> portPairGroups); + + /** + * Assigns the flow classifiers associated with the port chain + * to this object. + * + * @param flowClassifiers list of flow classifiers + * @return this the builder object + */ + Builder setFlowClassifiers(List<FlowClassifierId> flowClassifiers); + + /** + * Builds a port chain object. + * + * @return a port chain. + */ + PortChain build(); + } +} diff --git a/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/PortChainId.java b/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/PortChainId.java new file mode 100644 index 00000000..66edbdcc --- /dev/null +++ b/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/PortChainId.java @@ -0,0 +1,95 @@ +/* + * 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.vtnrsc; + +import static com.google.common.base.MoreObjects.toStringHelper; +import static com.google.common.base.Preconditions.checkNotNull; + +import java.util.UUID; + +import com.google.common.base.Objects; + +/** + * Representation of a Port Chain ID. + */ +public final class PortChainId { + + private final UUID portChainId; + + /** + * Private constructor for port chain id. + * + * @param id UUID id of port chain + */ + private PortChainId(UUID id) { + checkNotNull(id, "Port chain id can not be null"); + this.portChainId = id; + } + + /** + * Constructor to create port chain id from UUID. + * + * @param id UUID of port chain + * @return object of port chain id + */ + public static PortChainId portChainId(UUID id) { + return new PortChainId(id); + } + + /** + * Constructor to create port chain id from string. + * + * @param id port chain id in string + * @return object of port chain id + */ + public static PortChainId portChainId(String id) { + return new PortChainId(UUID.fromString(id)); + } + + /** + * Returns the value of port chain id. + * + * @return port chain id + */ + public UUID value() { + return portChainId; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + + if (obj.getClass() == this.getClass()) { + PortChainId that = (PortChainId) obj; + return Objects.equal(this.portChainId, that.portChainId); + } + return false; + } + + @Override + public int hashCode() { + return Objects.hashCode(this.portChainId); + } + + @Override + public String toString() { + return toStringHelper(this) + .add("portChainId", portChainId.toString()) + .toString(); + } +} diff --git a/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/PortPair.java b/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/PortPair.java new file mode 100644 index 00000000..f6285e61 --- /dev/null +++ b/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/PortPair.java @@ -0,0 +1,139 @@ +/* + * 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.vtnrsc; + + +/** + * Abstraction of an entity providing Port Pair information. + * A port pair represents a service function instance. + */ +public interface PortPair { + + /** + * Returns the ID of this port Pair. + * + * @return the port pair id + */ + PortPairId portPairId(); + + /** + * Returns the tenant id of this port pair. + * + * @return an tenant id + */ + TenantId tenantId(); + + /** + * Returns the description of this port pair. + * + * @return description of port pair + */ + String name(); + + /** + * Returns the description of this port pair. + * + * @return description of port pair + */ + String description(); + + /** + * Returns the ingress port of this port pair. + * + * @return ingress of port pair + */ + String ingress(); + + /** + * Returns the egress port of this port pair. + * + * @return egress of port pair + */ + String egress(); + + /** + * Returns whether this port pair is an exact match to the port pair given + * in the argument. + * <p> + * Exact match means the Port port pairs match with the given port pair. + * It does not consider the port pair id, name and description. + * </p> + * @param portPair other port pair to match against + * @return true if the port pairs are an exact match, otherwise false + */ + boolean exactMatch(PortPair portPair); + + /** + * A port pair builder.. + */ + interface Builder { + + /** + * Assigns the port pair id to this object. + * + * @param portPairId the port pair id + * @return this the builder object + */ + Builder setId(PortPairId portPairId); + + /** + * Assigns tenant id to this object. + * + * @param tenantId tenant id of the port pair + * @return this the builder object + */ + Builder setTenantId(TenantId tenantId); + + /** + * Assigns the name to this object. + * + * @param name name of the port pair + * @return this the builder object + */ + Builder setName(String name); + + /** + * Assigns the description to this object. + * + * @param description description of the port pair + * @return this the builder object + */ + Builder setDescription(String description); + + /** + * Assigns the ingress port to this object. + * + * @param port ingress port of the port pair + * @return this the builder object + */ + Builder setIngress(String port); + + /** + * Assigns the egress port to this object. + * + * @param port egress port of the port pair + * @return this the builder object + */ + Builder setEgress(String port); + + /** + * Builds a port pair object. + * + * @return a port pair. + */ + PortPair build(); + } +} diff --git a/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/PortPairGroup.java b/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/PortPairGroup.java new file mode 100644 index 00000000..f647b57f --- /dev/null +++ b/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/PortPairGroup.java @@ -0,0 +1,126 @@ +/* + * 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.vtnrsc; + +import java.util.List; + +/** + * Abstraction of an entity providing Port Pair Group information. + * A port pair group consists of one or more port pairs. + */ +public interface PortPairGroup { + + /** + * Returns the ID of this port pair group. + * + * @return the port pair group id + */ + PortPairGroupId portPairGroupId(); + + /** + * Returns the tenant id of this port pair group. + * + * @return the tenant id + */ + TenantId tenantId(); + + /** + * Returns the name of this port pair group. + * + * @return name of port pair group + */ + String name(); + + /** + * Returns the description of this port pair group. + * + * @return description of port pair group + */ + String description(); + + /** + * Returns the list of port pairs associated with this port pair group. + * + * @return list of port pairs + */ + List<PortPairId> portPairs(); + + /** + * Returns whether this port pair group is an exact match to the + * port pair group given in the argument. + * <p> + * Exact match means the Port pairs match with the given port pair group. + * It does not consider the port pair group id, name and description. + * </p> + * @param portPairGroup other port pair group to match against + * @return true if the port pairs are an exact match, otherwise false + */ + boolean exactMatch(PortPairGroup portPairGroup); + + /** + * A port pair group builder.. + */ + interface Builder { + + /** + * Assigns the port pair group id to this object. + * + * @param portPairGroupId the port pair group id + * @return this the builder object + */ + Builder setId(PortPairGroupId portPairGroupId); + + /** + * Assigns tenant id to this object. + * + * @param tenantId tenant id of port pair group + * @return this the builder object + */ + Builder setTenantId(TenantId tenantId); + + /** + * Assigns the name to this object. + * + * @param name name of the port pair group + * @return this the builder object + */ + Builder setName(String name); + + /** + * Assigns the description to this object. + * + * @param description description of the port pair group + * @return this the builder object + */ + Builder setDescription(String description); + + /** + * Assigns the port pairs associated with the port pair group + * to this object. + * + * @param portPairs list of port pairs + * @return this the builder object + */ + Builder setPortPairs(List<PortPairId> portPairs); + + /** + * Builds a port pair group object. + * + * @return a port pair group object. + */ + PortPairGroup build(); + } +} diff --git a/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/PortPairGroupId.java b/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/PortPairGroupId.java new file mode 100644 index 00000000..0474901c --- /dev/null +++ b/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/PortPairGroupId.java @@ -0,0 +1,95 @@ +/* + * 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.vtnrsc; + +import static com.google.common.base.MoreObjects.toStringHelper; +import static com.google.common.base.Preconditions.checkNotNull; + +import java.util.UUID; + +import com.google.common.base.Objects; + +/** + * Representation of a Port Pair Group ID. + */ +public final class PortPairGroupId { + + private final UUID portPairGroupId; + + /** + * Private constructor for port pair group id. + * + * @param id UUID id of port pair group + */ + private PortPairGroupId(UUID id) { + checkNotNull(id, "Port pair group id can not be null"); + this.portPairGroupId = id; + } + + /** + * Constructor to create port pair group id from UUID. + * + * @param id UUID of port pair group id + * @return object of port pair group id + */ + public static PortPairGroupId portPairGroupId(UUID id) { + return new PortPairGroupId(id); + } + + /** + * Constructor to create port pair group id from string. + * + * @param id port pair group id in string + * @return object of port pair group id + */ + public static PortPairGroupId portPairGroupId(String id) { + return new PortPairGroupId(UUID.fromString(id)); + } + + /** + * Returns the value of port pair group id. + * + * @return port pair group id + */ + public UUID value() { + return portPairGroupId; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + + if (obj.getClass() == this.getClass()) { + PortPairGroupId that = (PortPairGroupId) obj; + return Objects.equal(this.portPairGroupId, that.portPairGroupId); + } + return false; + } + + @Override + public int hashCode() { + return Objects.hashCode(this.portPairGroupId); + } + + @Override + public String toString() { + return toStringHelper(this) + .add("portPairGroupId", portPairGroupId.toString()) + .toString(); + } +} diff --git a/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/PortPairId.java b/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/PortPairId.java new file mode 100644 index 00000000..05c31aac --- /dev/null +++ b/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/PortPairId.java @@ -0,0 +1,95 @@ +/* + * 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.vtnrsc; + +import static com.google.common.base.MoreObjects.toStringHelper; +import static com.google.common.base.Preconditions.checkNotNull; + +import java.util.UUID; + +import com.google.common.base.Objects; + +/** + * Representation of a Port Pair ID. + */ +public final class PortPairId { + + private final UUID portPairId; + + /** + * Private constructor for port pair id. + * + * @param id UUID id of port pair + */ + private PortPairId(UUID id) { + checkNotNull(id, "Port chain id can not be null"); + this.portPairId = id; + } + + /** + * Constructor to create port pair id from UUID. + * + * @param id UUID of port pair id + * @return object of port pair id + */ + public static PortPairId portPairId(UUID id) { + return new PortPairId(id); + } + + /** + * Constructor to create port pair id from string. + * + * @param id port pair id in string + * @return object of port pair id + */ + public static PortPairId portPairId(String id) { + return new PortPairId(UUID.fromString(id)); + } + + /** + * Returns teh value of port pair id. + * + * @return port pair id + */ + public UUID value() { + return portPairId; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + + if (obj.getClass() == this.getClass()) { + PortPairId that = (PortPairId) obj; + return Objects.equal(this.portPairId, that.portPairId); + } + return false; + } + + @Override + public int hashCode() { + return Objects.hashCode(this.portPairId); + } + + @Override + public String toString() { + return toStringHelper(this) + .add("portPairId", portPairId.toString()) + .toString(); + } +} diff --git a/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/flowClassifier/FlowClassifierService.java b/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/flowClassifier/FlowClassifierService.java new file mode 100644 index 00000000..e379be81 --- /dev/null +++ b/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/flowClassifier/FlowClassifierService.java @@ -0,0 +1,72 @@ +/* + * 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.vtnrsc.flowClassifier; + +import org.onosproject.vtnrsc.FlowClassifier; +import org.onosproject.vtnrsc.FlowClassifierId; + +/** + * Provides Services for Flow Classifier. + */ +public interface FlowClassifierService { + + /** + * Store Flow Classifier. + * + * @param flowClassifier Flow Classifier + * @return true if adding Flow Classifier into store is success otherwise return false. + */ + boolean createFlowClassifier(FlowClassifier flowClassifier); + + /** + * Return the existing collection of Flow Classifier. + * + * @return Flow Classifier collections. + */ + Iterable<FlowClassifier> getFlowClassifiers(); + + /** + * Check whether Flow Classifier is present based on given Flow Classifier Id. + * + * @param id Flow Classifier. + * @return true if Flow Classifier is present otherwise return false. + */ + boolean hasFlowClassifier(FlowClassifierId id); + + /** + * Retrieve the Flow Classifier based on given Flow Classifier id. + * + * @param id Flow Classifier Id. + * @return Flow Classifier if present otherwise returns null. + */ + FlowClassifier getFlowClassifier(FlowClassifierId id); + + /** + * Update Flow Classifier based on given Flow Classifier Id. + * + * @param flowClassifier Flow Classifier. + * @return true if update is success otherwise return false. + */ + boolean updateFlowClassifier(FlowClassifier flowClassifier); + + /** + * Remove Flow Classifier from store based on given Flow Classifier Id. + * + * @param id Flow Classifier Id. + * @return true if Flow Classifier removal is success otherwise return false. + */ + boolean removeFlowClassifier(FlowClassifierId id); +}
\ No newline at end of file diff --git a/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/flowClassifier/impl/FlowClassifierManager.java b/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/flowClassifier/impl/FlowClassifierManager.java new file mode 100644 index 00000000..7238558a --- /dev/null +++ b/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/flowClassifier/impl/FlowClassifierManager.java @@ -0,0 +1,108 @@ +/* + * 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.vtnrsc.flowClassifier.impl; + +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; + +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.Service; +import org.onosproject.vtnrsc.FlowClassifierId; +import org.onosproject.vtnrsc.FlowClassifier; +import org.onosproject.vtnrsc.flowClassifier.FlowClassifierService; + +import org.slf4j.Logger; +import static org.slf4j.LoggerFactory.getLogger; + +import static com.google.common.base.Preconditions.checkNotNull; +import com.google.common.collect.ImmutableList; + +/** + * Provides implementation of the Flow Classifier Service. + */ +@Component(immediate = true) +@Service +public class FlowClassifierManager implements FlowClassifierService { + + private final Logger log = getLogger(FlowClassifierManager.class); + + private static final String FLOW_CLASSIFIER_NOT_NULL = "Flow Classifier cannot be null"; + private static final String FLOW_CLASSIFIER_ID_NOT_NULL = "Flow Classifier Id cannot be null"; + + private ConcurrentMap<FlowClassifierId, FlowClassifier> flowClassifierStore + = new ConcurrentHashMap<FlowClassifierId, FlowClassifier>(); + + @Activate + private void activate() { + log.info("Flow Classifier service activated"); + } + + @Deactivate + private void deactivate() { + log.info("Flow Classifier service deactivated"); + } + + @Override + public boolean createFlowClassifier(FlowClassifier flowClassifier) { + log.debug("createFlowClassifier"); + checkNotNull(flowClassifier, FLOW_CLASSIFIER_NOT_NULL); + FlowClassifierId id = flowClassifier.flowClassifierId(); + + flowClassifierStore.put(id, flowClassifier); + if (!flowClassifierStore.containsKey(id)) { + log.debug("Flow Classifier creation is failed whose identifier is {}.", id.toString()); + return false; + } + return true; + } + + @Override + public Iterable<FlowClassifier> getFlowClassifiers() { + return ImmutableList.copyOf(flowClassifierStore.values()); + } + + @Override + public boolean hasFlowClassifier(FlowClassifierId id) { + checkNotNull(id, FLOW_CLASSIFIER_ID_NOT_NULL); + return flowClassifierStore.containsKey(id); + } + + @Override + public FlowClassifier getFlowClassifier(FlowClassifierId id) { + checkNotNull(id, FLOW_CLASSIFIER_ID_NOT_NULL); + return flowClassifierStore.get(id); + } + + @Override + public boolean updateFlowClassifier(FlowClassifier flowClassifier) { + checkNotNull(flowClassifier, FLOW_CLASSIFIER_NOT_NULL); + FlowClassifierId id = flowClassifier.flowClassifierId(); + return flowClassifierStore.replace(id, flowClassifierStore.get(id), flowClassifier); + } + + @Override + public boolean removeFlowClassifier(FlowClassifierId id) { + checkNotNull(id, FLOW_CLASSIFIER_ID_NOT_NULL); + flowClassifierStore.remove(id); + if (flowClassifierStore.containsKey(id)) { + log.debug("The Flow Classifier removal is failed whose identifier is {}", id.toString()); + return false; + } + return true; + } +}
\ No newline at end of file diff --git a/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/flowClassifier/impl/package-info.java b/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/flowClassifier/impl/package-info.java new file mode 100644 index 00000000..4ea050b3 --- /dev/null +++ b/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/flowClassifier/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. + */ + +/** + * Provides implementation of the flow Classifier service. + */ +package org.onosproject.vtnrsc.flowClassifier.impl; diff --git a/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/flowClassifier/package-info.java b/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/flowClassifier/package-info.java new file mode 100644 index 00000000..07584170 --- /dev/null +++ b/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/flowClassifier/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 interacting with flow Classifier of SFC. + */ +package org.onosproject.vtnrsc.flowClassifier; diff --git a/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/portchain/PortChainService.java b/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/portchain/PortChainService.java new file mode 100644 index 00000000..b4ff917e --- /dev/null +++ b/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/portchain/PortChainService.java @@ -0,0 +1,80 @@ +/* + * 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.vtnrsc.portchain; + +import org.onosproject.vtnrsc.PortChain; +import org.onosproject.vtnrsc.PortChainId; + +/** + * Service for interacting with the inventory of port chains. + */ +public interface PortChainService { + + /** + * Returns if the port chain is existed. + * + * @param portChainId port chain identifier + * @return true or false if one with the given identifier exists. + */ + boolean exists(PortChainId portChainId); + + /** + * Returns the number of port chains known to the system. + * + * @return number of port chains. + */ + int getPortChainCount(); + + /** + * Returns an iterable collection of the currently known port chains. + * + * @return collection of port chains. + */ + Iterable<PortChain> getPortChains(); + + /** + * Returns the portChain with the given identifier. + * + * @param portChainId port chain identifier + * @return PortChain or null if port chain with the given identifier is not + * known. + */ + PortChain getPortChain(PortChainId portChainId); + + /** + * Creates a PortChain in the store. + * + * @param portChain the port chain to create + * @return true if given port chain is created successfully. + */ + boolean createPortChain(PortChain portChain); + + /** + * Updates the portChain in the store. + * + * @param portChain the port chain to update + * @return true if given port chain is updated successfully. + */ + boolean updatePortChain(PortChain portChain); + + /** + * Deletes portChain by given portChainId. + * + * @param portChainId id of port chain to remove + * @return true if the give port chain is deleted successfully. + */ + boolean removePortChain(PortChainId portChainId); +} diff --git a/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/portchain/package-info.java b/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/portchain/package-info.java new file mode 100644 index 00000000..74642bc3 --- /dev/null +++ b/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/portchain/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 interacting with the inventory of port chains. + */ +package org.onosproject.vtnrsc.portchain; diff --git a/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/portpairgroup/PortPairGroupService.java b/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/portpairgroup/PortPairGroupService.java new file mode 100644 index 00000000..77f483fc --- /dev/null +++ b/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/portpairgroup/PortPairGroupService.java @@ -0,0 +1,80 @@ +/* + * 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.vtnrsc.portpairgroup; + +import org.onosproject.vtnrsc.PortPairGroup; +import org.onosproject.vtnrsc.PortPairGroupId; + +/** + * Service for interacting with the inventory of port pair groups. + */ +public interface PortPairGroupService { + + /** + * Returns if the port pair group is existed. + * + * @param portPairGroupId port pair group identifier + * @return true or false if one with the given identifier exists. + */ + boolean exists(PortPairGroupId portPairGroupId); + + /** + * Returns the number of port pair groups known to the system. + * + * @return number of port pair groups. + */ + int getPortPairGroupCount(); + + /** + * Returns an iterable collection of the currently known port pair groups. + * + * @return collection of port pair groups. + */ + Iterable<PortPairGroup> getPortPairGroups(); + + /** + * Returns the portPairGroup with the given identifier. + * + * @param portPairGroupId port pair group identifier + * @return PortPairGroup or null if port pair group with the given identifier is not + * known. + */ + PortPairGroup getPortPairGroup(PortPairGroupId portPairGroupId); + + /** + * Creates a PortPairGroup in the store. + * + * @param portPairGroup the port pair group to create + * @return true if given port pair group is created successfully. + */ + boolean createPortPairGroup(PortPairGroup portPairGroup); + + /** + * Updates the portPairGroup in the store. + * + * @param portPairGroup the port pair group to update + * @return true if given port pair group is updated successfully. + */ + boolean updatePortPairGroup(PortPairGroup portPairGroup); + + /** + * Deletes portPairGroup by given portPairGroupId. + * + * @param portPairGroupId id of port pair group to remove + * @return true if the give port pair group is deleted successfully. + */ + boolean removePortPairGroup(PortPairGroupId portPairGroupId); +} diff --git a/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/portpairgroup/package-info.java b/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/portpairgroup/package-info.java new file mode 100644 index 00000000..8a79fe97 --- /dev/null +++ b/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/portpairgroup/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 interacting with the inventory of port pair groups. + */ +package org.onosproject.vtnrsc.portpairgroup; diff --git a/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/tunnel/TunnelConfigService.java b/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/tunnel/TunnelConfigService.java deleted file mode 100644 index 6f3cf653..00000000 --- a/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/tunnel/TunnelConfigService.java +++ /dev/null @@ -1,72 +0,0 @@ -/* - * 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.vtnrsc.tunnel; - -import org.onosproject.vtnrsc.Subnet; -import org.onosproject.vtnrsc.SubnetId; - - -/** - * Service for interacting with the inventory of subnets. - */ -public interface TunnelConfigService { - /** - * Returns the subnet with the specified identifier. - * - * @param subnetId subnet identifier - * @return true or false - */ - boolean exists(SubnetId subnetId); - /** - * Returns a collection of the currently known subnets. - * - * @return iterable collection of subnets - */ - Iterable<Subnet> getSubnets(); - - /** - * Returns the subnet with the specified identifier. - * - * @param subnetId subnet identifier - * @return subnet or null if one with the given identifier is not known - */ - Subnet getSubnet(SubnetId subnetId); - /** - * Creates new subnets. - * - * @param subnets the iterable collection of subnets - * @return true if the identifier subnet has been created right - */ - boolean createSubnets(Iterable<Subnet> subnets); - - /** - * Updates existing subnets. - * - * @param subnets the iterable collection of subnets - * @return true if all subnets were updated successfully - */ - boolean updateSubnets(Iterable<Subnet> subnets); - - /** - * Administratively removes the specified subnets from the store. - * - * @param subnetIds the iterable collection of subnets identifier - * @return true if remove identifier subnets successfully - */ - boolean removeSubnets(Iterable<SubnetId> subnetIds); - - -} diff --git a/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/virtualport/impl/VirtualPortManager.java b/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/virtualport/impl/VirtualPortManager.java index c45373b9..daec7839 100644 --- a/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/virtualport/impl/VirtualPortManager.java +++ b/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/virtualport/impl/VirtualPortManager.java @@ -191,22 +191,20 @@ public class VirtualPortManager implements VirtualPortService { @Override public boolean updatePorts(Iterable<VirtualPort> vPorts) { checkNotNull(vPorts, VIRTUALPORT_NOT_NULL); - if (vPorts != null) { - for (VirtualPort vPort : vPorts) { - vPortStore.put(vPort.portId(), vPort); - if (!vPortStore.containsKey(vPort.portId())) { - log.debug("The virtualPort is not exist whose identifier is {}", - vPort.portId().toString()); - return false; - } + for (VirtualPort vPort : vPorts) { + vPortStore.put(vPort.portId(), vPort); + if (!vPortStore.containsKey(vPort.portId())) { + log.debug("The virtualPort is not exist whose identifier is {}", + vPort.portId().toString()); + return false; + } - vPortStore.put(vPort.portId(), vPort); + vPortStore.put(vPort.portId(), vPort); - if (!vPort.equals(vPortStore.get(vPort.portId()))) { - log.debug("The virtualPort is updated failed whose identifier is {}", - vPort.portId().toString()); - return false; - } + if (!vPort.equals(vPortStore.get(vPort.portId()))) { + log.debug("The virtualPort is updated failed whose identifier is {}", + vPort.portId().toString()); + return false; } } return true; @@ -215,14 +213,12 @@ public class VirtualPortManager implements VirtualPortService { @Override public boolean removePorts(Iterable<VirtualPortId> vPortIds) { checkNotNull(vPortIds, VIRTUALPORT_ID_NULL); - if (vPortIds != null) { - for (VirtualPortId vPortId : vPortIds) { - vPortStore.remove(vPortId); - if (vPortStore.containsKey(vPortId)) { - log.debug("The virtualPort is removed failed whose identifier is {}", - vPortId.toString()); - return false; - } + for (VirtualPortId vPortId : vPortIds) { + vPortStore.remove(vPortId); + if (vPortStore.containsKey(vPortId)) { + log.debug("The virtualPort is removed failed whose identifier is {}", + vPortId.toString()); + return false; } } return true; diff --git a/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/web/FlowClassifierCodec.java b/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/web/FlowClassifierCodec.java new file mode 100644 index 00000000..fd5b1ee4 --- /dev/null +++ b/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/web/FlowClassifierCodec.java @@ -0,0 +1,134 @@ +/* + * 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.vtnrsc.web; + +import static com.google.common.base.Preconditions.checkNotNull; +import static org.onlab.util.Tools.nullIsIllegal; + +import java.util.UUID; + +import org.onlab.packet.IpPrefix; +import org.onosproject.codec.CodecContext; +import org.onosproject.codec.JsonCodec; +import org.onosproject.vtnrsc.DefaultFlowClassifier; +import org.onosproject.vtnrsc.FlowClassifier; +import org.onosproject.vtnrsc.FlowClassifierId; +import org.onosproject.vtnrsc.VirtualPortId; +import org.onosproject.vtnrsc.TenantId; + +import com.fasterxml.jackson.databind.node.ObjectNode; + +/** + * Flow Classifier JSON codec. + */ +public final class FlowClassifierCodec extends JsonCodec<FlowClassifier> { + + private static final String FLOW_CLASSIFIER_ID = "id"; + private static final String TENANT_ID = "tenant_id"; + private static final String NAME = "name"; + private static final String DESCRIPTION = "description"; + private static final String ETHER_TYPE = "etherType"; + private static final String PROTOCOL = "protocol"; + private static final String MIN_SRC_PORT_RANGE = "source_port_range_min"; + private static final String MAX_SRC_PORT_RANGE = "source_port_range_max"; + private static final String MIN_DST_PORT_RANGE = "destination_port_range_min"; + private static final String MAX_DST_PORT_RANGE = "destination_port_range_max"; + private static final String SRC_IP_PREFIX = "source_ip_prefix"; + private static final String DST_IP_PREFIX = "destination_ip_prefix"; + private static final String SRC_PORT = "logical_source_port"; + private static final String DST_PORT = "logical_destination_port"; + private static final String MISSING_MEMBER_MESSAGE = " member is required in Flow Classifier."; + + @Override + public FlowClassifier decode(ObjectNode json, CodecContext context) { + if (json == null || !json.isObject()) { + return null; + } + + FlowClassifier.Builder resultBuilder = new DefaultFlowClassifier.Builder(); + + String flowClassifierId = nullIsIllegal(json.get(FLOW_CLASSIFIER_ID), + FLOW_CLASSIFIER_ID + MISSING_MEMBER_MESSAGE).asText(); + resultBuilder.setFlowClassifierId(FlowClassifierId.flowClassifierId(UUID.fromString(flowClassifierId))); + + String tenantId = nullIsIllegal(json.get(TENANT_ID), TENANT_ID + MISSING_MEMBER_MESSAGE).asText(); + resultBuilder.setTenantId(TenantId.tenantId(tenantId)); + + String flowClassiferName = nullIsIllegal(json.get(NAME), NAME + MISSING_MEMBER_MESSAGE).asText(); + resultBuilder.setName(flowClassiferName); + + String flowClassiferDescription = nullIsIllegal(json.get(DESCRIPTION), DESCRIPTION + MISSING_MEMBER_MESSAGE) + .asText(); + resultBuilder.setDescription(flowClassiferDescription); + + String etherType = nullIsIllegal(json.get(ETHER_TYPE), ETHER_TYPE + MISSING_MEMBER_MESSAGE).asText(); + resultBuilder.setEtherType(etherType); + + String protocol = nullIsIllegal(json.get(PROTOCOL), PROTOCOL + MISSING_MEMBER_MESSAGE).asText(); + resultBuilder.setProtocol(protocol); + + int minSrcPortRange = nullIsIllegal(json.get(MIN_SRC_PORT_RANGE), MIN_SRC_PORT_RANGE + MISSING_MEMBER_MESSAGE) + .asInt(); + resultBuilder.setMinSrcPortRange(minSrcPortRange); + + int maxSrcPortRange = nullIsIllegal(json.get(MAX_SRC_PORT_RANGE), MAX_SRC_PORT_RANGE + MISSING_MEMBER_MESSAGE) + .asInt(); + resultBuilder.setMaxSrcPortRange(maxSrcPortRange); + + int minDstPortRange = nullIsIllegal(json.get(MIN_DST_PORT_RANGE), MIN_DST_PORT_RANGE + MISSING_MEMBER_MESSAGE) + .asInt(); + resultBuilder.setMinDstPortRange(minDstPortRange); + + int maxDstPortRange = nullIsIllegal(json.get(MAX_DST_PORT_RANGE), MAX_DST_PORT_RANGE + MISSING_MEMBER_MESSAGE) + .asInt(); + resultBuilder.setMaxDstPortRange(maxDstPortRange); + + String srcIpPrefix = nullIsIllegal(json.get(SRC_IP_PREFIX), SRC_IP_PREFIX + MISSING_MEMBER_MESSAGE).asText(); + resultBuilder.setSrcIpPrefix(IpPrefix.valueOf(srcIpPrefix)); + + String dstIpPrefix = nullIsIllegal(json.get(DST_IP_PREFIX), DST_IP_PREFIX + MISSING_MEMBER_MESSAGE).asText(); + resultBuilder.setDstIpPrefix(IpPrefix.valueOf(dstIpPrefix)); + + String srcPort = nullIsIllegal(json.get(SRC_PORT), SRC_PORT + MISSING_MEMBER_MESSAGE).asText(); + resultBuilder.setSrcPort(VirtualPortId.portId(srcPort)); + + String dstPort = nullIsIllegal(json.get(DST_PORT), DST_PORT + MISSING_MEMBER_MESSAGE).asText(); + resultBuilder.setDstPort(VirtualPortId.portId(dstPort)); + + return resultBuilder.build(); + } + + @Override + public ObjectNode encode(FlowClassifier flowClassifier, CodecContext context) { + checkNotNull(flowClassifier, "flowClassifier cannot be null"); + ObjectNode result = context.mapper().createObjectNode() + .put("FLOW_CLASSIFIER_ID", flowClassifier.flowClassifierId().toString()) + .put("TENANT_ID", flowClassifier.tenantId().toString()) + .put("NAME", flowClassifier.name()) + .put("DESCRIPTION", flowClassifier.description()) + .put("ETHER_TYPE", flowClassifier.etherType()) + .put("PROTOCOL", flowClassifier.protocol()) + .put("MIN_SRC_PORT_RANGE", flowClassifier.minSrcPortRange()) + .put("MAX_SRC_PORT_RANGE", flowClassifier.maxSrcPortRange()) + .put("MIN_DST_PORT_RANGE", flowClassifier.minDstPortRange()) + .put("MAX_DST_PORT_RANGE", flowClassifier.maxDstPortRange()) + .put("SRC_IP_PREFIX", flowClassifier.srcIpPrefix().toString()) + .put("DST_IP_PREFIX", flowClassifier.dstIpPrefix().toString()) + .put("SRC_PORT", flowClassifier.srcPort().toString()) + .put("DST_PORT", flowClassifier.dstPort().toString()); + return result; + } +}
\ No newline at end of file diff --git a/framework/src/onos/apps/vtn/vtnrsc/src/test/java/org/onosproject/vtnrsc/flowclassifier/FlowClassifierIdTest.java b/framework/src/onos/apps/vtn/vtnrsc/src/test/java/org/onosproject/vtnrsc/flowclassifier/FlowClassifierIdTest.java new file mode 100644 index 00000000..b2fed347 --- /dev/null +++ b/framework/src/onos/apps/vtn/vtnrsc/src/test/java/org/onosproject/vtnrsc/flowclassifier/FlowClassifierIdTest.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.vtnrsc.flowclassifier; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.notNullValue; +import static org.onlab.junit.ImmutableClassChecker.assertThatClassIsImmutable; + +import org.junit.Test; +import org.onosproject.vtnrsc.FlowClassifierId; + +import com.google.common.testing.EqualsTester; +import java.util.UUID; + +/** + * Unit tests for FlowClassifierId class. + */ +public class FlowClassifierIdTest { + + final FlowClassifierId flowClassifierId1 = FlowClassifierId + .flowClassifierId("78dcd363-fc23-aeb6-f44b-56dc5e2fb3ae"); + final FlowClassifierId sameAsFlowClassifierId1 = FlowClassifierId + .flowClassifierId("78dcd363-fc23-aeb6-f44b-56dc5e2fb3ae"); + final FlowClassifierId flowClassifierId2 = FlowClassifierId + .flowClassifierId("dace4513-24fc-4fae-af4b-321c5e2eb3d1"); + + /** + * Checks that the FlowClassifierId class is immutable. + */ + @Test + public void testImmutability() { + assertThatClassIsImmutable(FlowClassifierId.class); + } + + /** + * Checks the operation of equals() methods. + */ + @Test + public void testEquals() { + new EqualsTester().addEqualityGroup(flowClassifierId1, sameAsFlowClassifierId1) + .addEqualityGroup(flowClassifierId2).testEquals(); + } + + /** + * Checks the construction of a FlowClassifierId object. + */ + @Test + public void testConstruction() { + final String flowClassifierIdValue = "dace4513-24fc-4fae-af4b-321c5e2eb3d1"; + final FlowClassifierId flowClassifierId = FlowClassifierId.flowClassifierId(flowClassifierIdValue); + assertThat(flowClassifierId, is(notNullValue())); + assertThat(flowClassifierId.value(), is(UUID.fromString(flowClassifierIdValue))); + } +} diff --git a/framework/src/onos/apps/vtn/vtnrsc/src/test/java/org/onosproject/vtnrsc/subnet/DefaultAllocationPoolTest.java b/framework/src/onos/apps/vtn/vtnrsc/src/test/java/org/onosproject/vtnrsc/subnet/DefaultAllocationPoolTest.java new file mode 100644 index 00000000..4ce4def2 --- /dev/null +++ b/framework/src/onos/apps/vtn/vtnrsc/src/test/java/org/onosproject/vtnrsc/subnet/DefaultAllocationPoolTest.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.vtnrsc.subnet; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.is; +import static org.onlab.junit.ImmutableClassChecker.assertThatClassIsImmutable; + +import org.junit.Test; +import org.onlab.packet.IpAddress; +import org.onosproject.vtnrsc.AllocationPool; +import org.onosproject.vtnrsc.DefaultAllocationPool; + +import com.google.common.testing.EqualsTester; + +/** + * Unit tests for DefaultAllocationPool class. + */ +public class DefaultAllocationPoolTest { + + final IpAddress startIP1 = IpAddress.valueOf("192.168.1.1"); + final IpAddress startIP2 = IpAddress.valueOf("192.168.1.2"); + final IpAddress endIP1 = IpAddress.valueOf("192.168.1.1"); + final IpAddress endIP2 = IpAddress.valueOf("192.168.1.2"); + + /** + * Checks that the DefaultAllocationPool class is immutable. + */ + @Test + public void testImmutability() { + assertThatClassIsImmutable(DefaultAllocationPool.class); + } + + /** + * Checks the operation of equals() methods. + */ + @Test + public void testEquals() { + AllocationPool pool1 = new DefaultAllocationPool(startIP1, endIP1); + AllocationPool pool2 = new DefaultAllocationPool(startIP1, endIP1); + AllocationPool pool3 = new DefaultAllocationPool(startIP2, endIP2); + new EqualsTester().addEqualityGroup(pool1, pool2) + .addEqualityGroup(pool3).testEquals(); + } + + /** + * Checks the construction of a DefaultAllocationPool object. + */ + @Test + public void testConstruction() { + final AllocationPool apool = new DefaultAllocationPool(startIP1, endIP1); + assertThat(startIP1, is(apool.startIp())); + assertThat(endIP1, is(apool.endIp())); + } +} diff --git a/framework/src/onos/apps/vtn/vtnrsc/src/test/java/org/onosproject/vtnrsc/subnet/DefaultHostRouteTest.java b/framework/src/onos/apps/vtn/vtnrsc/src/test/java/org/onosproject/vtnrsc/subnet/DefaultHostRouteTest.java new file mode 100644 index 00000000..2f751742 --- /dev/null +++ b/framework/src/onos/apps/vtn/vtnrsc/src/test/java/org/onosproject/vtnrsc/subnet/DefaultHostRouteTest.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.vtnrsc.subnet; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.is; +import static org.onlab.junit.ImmutableClassChecker.assertThatClassIsImmutable; + +import org.junit.Test; +import org.onlab.packet.IpAddress; +import org.onlab.packet.IpPrefix; +import org.onosproject.vtnrsc.DefaultHostRoute; +import org.onosproject.vtnrsc.HostRoute; + +import com.google.common.testing.EqualsTester; + +/** + * Unit tests for DefaultHostRoute class. + */ +public class DefaultHostRouteTest { + final IpAddress nexthop1 = IpAddress.valueOf("192.168.1.1"); + final IpAddress nexthop2 = IpAddress.valueOf("192.168.1.2"); + final IpPrefix destination1 = IpPrefix.valueOf("1.1.1.1/1"); + final IpPrefix destination2 = IpPrefix.valueOf("1.1.1.1/2"); + + /** + * Checks that the DefaultHostRoute class is immutable. + */ + @Test + public void testImmutability() { + assertThatClassIsImmutable(DefaultHostRoute.class); + } + + /** + * Checks the operation of equals() methods. + */ + @Test + public void testEquals() { + HostRoute route1 = new DefaultHostRoute(nexthop1, destination1); + HostRoute route2 = new DefaultHostRoute(nexthop1, destination1); + HostRoute route3 = new DefaultHostRoute(nexthop2, destination2); + new EqualsTester().addEqualityGroup(route1, route2) + .addEqualityGroup(route3).testEquals(); + } + + /** + * Checks the construction of a DefaultHostRoute object. + */ + @Test + public void testConstruction() { + final HostRoute host = new DefaultHostRoute(nexthop1, destination1); + assertThat(nexthop1, is(host.nexthop())); + assertThat(destination1, is(host.destination())); + } +} diff --git a/framework/src/onos/apps/vtn/vtnrsc/src/test/java/org/onosproject/vtnrsc/subnet/SubnetIdTest.java b/framework/src/onos/apps/vtn/vtnrsc/src/test/java/org/onosproject/vtnrsc/subnet/SubnetIdTest.java new file mode 100644 index 00000000..d18dd41a --- /dev/null +++ b/framework/src/onos/apps/vtn/vtnrsc/src/test/java/org/onosproject/vtnrsc/subnet/SubnetIdTest.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.vtnrsc.subnet; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.notNullValue; +import static org.onlab.junit.ImmutableClassChecker.assertThatClassIsImmutable; + +import org.junit.Test; +import org.onosproject.vtnrsc.SubnetId; + +import com.google.common.testing.EqualsTester; + +/** + * Unit tests for SubnetId class. + */ +public class SubnetIdTest { + + final SubnetId subnetId1 = SubnetId.subnetId("1"); + final SubnetId sameAsSubnetId1 = SubnetId.subnetId("1"); + final SubnetId subnetId2 = SubnetId.subnetId("2"); + + /** + * Checks that the SubnetId class is immutable. + */ + @Test + public void testImmutability() { + assertThatClassIsImmutable(SubnetId.class); + } + + /** + * Checks the operation of equals() methods. + */ + @Test + public void testEquals() { + new EqualsTester().addEqualityGroup(subnetId1, sameAsSubnetId1).addEqualityGroup(subnetId2) + .testEquals(); + } + + /** + * Checks the construction of a SubnetId object. + */ + @Test + public void testConstruction() { + final String subnetIdValue = "s"; + final SubnetId subnetId = SubnetId.subnetId(subnetIdValue); + assertThat(subnetId, is(notNullValue())); + assertThat(subnetId.subnetId(), is(subnetIdValue)); + } +} diff --git a/framework/src/onos/apps/vtn/vtnrsc/src/test/java/org/onosproject/vtnrsc/tenantnetwork/DefaultNeutronNetworkTest.java b/framework/src/onos/apps/vtn/vtnrsc/src/test/java/org/onosproject/vtnrsc/tenantnetwork/DefaultNeutronNetworkTest.java new file mode 100644 index 00000000..742d5933 --- /dev/null +++ b/framework/src/onos/apps/vtn/vtnrsc/src/test/java/org/onosproject/vtnrsc/tenantnetwork/DefaultNeutronNetworkTest.java @@ -0,0 +1,83 @@ +/* + * 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.vtnrsc.tenantnetwork; + +import static org.onlab.junit.ImmutableClassChecker.assertThatClassIsImmutable; + +import org.junit.Test; +import org.onosproject.vtnrsc.DefaultTenantNetwork; +import org.onosproject.vtnrsc.PhysicalNetwork; +import org.onosproject.vtnrsc.SegmentationId; +import org.onosproject.vtnrsc.TenantId; +import org.onosproject.vtnrsc.TenantNetwork; +import org.onosproject.vtnrsc.TenantNetworkId; + +import com.google.common.testing.EqualsTester; + +/** + * Unit tests for DefaultNeutronNetwork class. + */ +public class DefaultNeutronNetworkTest { + + private String networkIdStr1 = "123"; + private String networkIdStr2 = "234"; + private String physicalNetworkStr = "1234"; + private String tenantIdStr = "345"; + private String segmentationIdStr = "1"; + private String name = "456"; + + /** + * Checks that the DefaultNeutronNetwork class is immutable. + */ + @Test + public void testImmutability() { + assertThatClassIsImmutable(DefaultTenantNetwork.class); + } + + /** + * Checks the operation of equals() methods. + */ + @Test + public void testEquality() { + TenantNetworkId networkid1 = TenantNetworkId.networkId(networkIdStr1); + TenantNetworkId networkid2 = TenantNetworkId.networkId(networkIdStr2); + PhysicalNetwork physicalNetwork = PhysicalNetwork + .physicalNetwork(physicalNetworkStr); + TenantId tenantId = TenantId.tenantId(tenantIdStr); + SegmentationId segmentationID = SegmentationId + .segmentationId(segmentationIdStr); + TenantNetwork p1 = new DefaultTenantNetwork(networkid1, name, false, + TenantNetwork.State.ACTIVE, + false, tenantId, false, + TenantNetwork.Type.LOCAL, + physicalNetwork, + segmentationID); + TenantNetwork p2 = new DefaultTenantNetwork(networkid1, name, false, + TenantNetwork.State.ACTIVE, + false, tenantId, false, + TenantNetwork.Type.LOCAL, + physicalNetwork, + segmentationID); + TenantNetwork p3 = new DefaultTenantNetwork(networkid2, name, false, + TenantNetwork.State.ACTIVE, + false, tenantId, false, + TenantNetwork.Type.LOCAL, + physicalNetwork, + segmentationID); + new EqualsTester().addEqualityGroup(p1, p2).addEqualityGroup(p3) + .testEquals(); + } +} diff --git a/framework/src/onos/apps/vtn/vtnrsc/src/test/java/org/onosproject/vtnrsc/tenantnetwork/PhysicalNetworkTest.java b/framework/src/onos/apps/vtn/vtnrsc/src/test/java/org/onosproject/vtnrsc/tenantnetwork/PhysicalNetworkTest.java new file mode 100644 index 00000000..e101795e --- /dev/null +++ b/framework/src/onos/apps/vtn/vtnrsc/src/test/java/org/onosproject/vtnrsc/tenantnetwork/PhysicalNetworkTest.java @@ -0,0 +1,65 @@ +/* + * 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.vtnrsc.tenantnetwork; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.notNullValue; +import static org.onlab.junit.ImmutableClassChecker.assertThatClassIsImmutable; + +import org.junit.Test; +import org.onosproject.vtnrsc.PhysicalNetwork; + +import com.google.common.testing.EqualsTester; + +/** + * Unit tests for PhysicalNetwork class. + */ +public class PhysicalNetworkTest { + + final PhysicalNetwork physicalNetwork1 = PhysicalNetwork.physicalNetwork("1"); + final PhysicalNetwork sameAsPhysicalNetwork1 = PhysicalNetwork.physicalNetwork("1"); + final PhysicalNetwork physicalNetwork2 = PhysicalNetwork.physicalNetwork("2"); + + /** + * Checks that the PhysicalNetwork class is immutable. + */ + @Test + public void testImmutability() { + assertThatClassIsImmutable(PhysicalNetwork.class); + } + + /** + * Checks the operation of equals() methods. + */ + @Test + public void testEquals() { + new EqualsTester().addEqualityGroup(physicalNetwork1, sameAsPhysicalNetwork1) + .addEqualityGroup(physicalNetwork2).testEquals(); + } + + /** + * Checks the construction of a PhysicalNetwork object. + */ + @Test + public void testConstruction() { + final String physicalNetworkValue = "s"; + final PhysicalNetwork physicalNetwork = PhysicalNetwork + .physicalNetwork(physicalNetworkValue); + assertThat(physicalNetwork, is(notNullValue())); + assertThat(physicalNetwork.physicalNetwork(), is(physicalNetworkValue)); + } +} diff --git a/framework/src/onos/apps/vtn/vtnrsc/src/test/java/org/onosproject/vtnrsc/tenantnetwork/SegmentationIdTest.java b/framework/src/onos/apps/vtn/vtnrsc/src/test/java/org/onosproject/vtnrsc/tenantnetwork/SegmentationIdTest.java new file mode 100644 index 00000000..dea7baf6 --- /dev/null +++ b/framework/src/onos/apps/vtn/vtnrsc/src/test/java/org/onosproject/vtnrsc/tenantnetwork/SegmentationIdTest.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.vtnrsc.tenantnetwork; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.notNullValue; +import static org.onlab.junit.ImmutableClassChecker.assertThatClassIsImmutable; + +import org.junit.Test; +import org.onosproject.vtnrsc.SegmentationId; + +import com.google.common.testing.EqualsTester; + +/** + * Unit tests for SegmentationId class. + */ +public class SegmentationIdTest { + + final SegmentationId segmentationID1 = SegmentationId.segmentationId("1"); + final SegmentationId sameAsSegmentationID1 = SegmentationId.segmentationId("1"); + final SegmentationId segmentationID2 = SegmentationId.segmentationId("2"); + + /** + * Checks that the SegmentationId class is immutable. + */ + @Test + public void testImmutability() { + assertThatClassIsImmutable(SegmentationId.class); + } + + /** + * Checks the operation of equals() methods. + */ + @Test + public void testEquals() { + new EqualsTester().addEqualityGroup(segmentationID1, sameAsSegmentationID1) + .addEqualityGroup(segmentationID2).testEquals(); + } + + /** + * Checks the construction of a segmentationId object. + */ + @Test + public void testConstruction() { + final String segmentationIdValue = "s"; + final SegmentationId segmentationId = SegmentationId.segmentationId(segmentationIdValue); + assertThat(segmentationId, is(notNullValue())); + assertThat(segmentationId.segmentationId(), is(segmentationIdValue)); + } +} diff --git a/framework/src/onos/apps/vtn/vtnrsc/src/test/java/org/onosproject/vtnrsc/tenantnetwork/TenantIdTest.java b/framework/src/onos/apps/vtn/vtnrsc/src/test/java/org/onosproject/vtnrsc/tenantnetwork/TenantIdTest.java new file mode 100644 index 00000000..e9216383 --- /dev/null +++ b/framework/src/onos/apps/vtn/vtnrsc/src/test/java/org/onosproject/vtnrsc/tenantnetwork/TenantIdTest.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.vtnrsc.tenantnetwork; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.notNullValue; +import static org.onlab.junit.ImmutableClassChecker.assertThatClassIsImmutable; + +import org.junit.Test; +import org.onosproject.vtnrsc.TenantId; + +import com.google.common.testing.EqualsTester; + +/** + * Unit tests for TenantId class. + */ +public class TenantIdTest { + + final TenantId tenantId1 = TenantId.tenantId("1"); + final TenantId sameAsTenantId1 = TenantId.tenantId("1"); + final TenantId tenantId2 = TenantId.tenantId("2"); + + /** + * Checks that the TenantId class is immutable. + */ + @Test + public void testImmutability() { + assertThatClassIsImmutable(TenantId.class); + } + + /** + * Checks the operation of equals() methods. + */ + @Test + public void testEquals() { + new EqualsTester().addEqualityGroup(tenantId1, sameAsTenantId1).addEqualityGroup(tenantId2) + .testEquals(); + } + + /** + * Checks the construction of a TenantId object. + */ + @Test + public void testConstruction() { + final String tenantIdValue = "s"; + final TenantId tenantId = TenantId.tenantId(tenantIdValue); + assertThat(tenantId, is(notNullValue())); + assertThat(tenantId.tenantId(), is(tenantIdValue)); + } +} diff --git a/framework/src/onos/apps/vtn/vtnrsc/src/test/java/org/onosproject/vtnrsc/tenantnetwork/TenantNetworkIdTest.java b/framework/src/onos/apps/vtn/vtnrsc/src/test/java/org/onosproject/vtnrsc/tenantnetwork/TenantNetworkIdTest.java new file mode 100644 index 00000000..8271b51c --- /dev/null +++ b/framework/src/onos/apps/vtn/vtnrsc/src/test/java/org/onosproject/vtnrsc/tenantnetwork/TenantNetworkIdTest.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.vtnrsc.tenantnetwork; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.notNullValue; +import static org.onlab.junit.ImmutableClassChecker.assertThatClassIsImmutable; + +import org.junit.Test; +import org.onosproject.vtnrsc.TenantNetworkId; + +import com.google.common.testing.EqualsTester; + +/** + * Unit tests for TenantNetworkId class. + */ +public class TenantNetworkIdTest { + + final TenantNetworkId networkId1 = TenantNetworkId.networkId("1"); + final TenantNetworkId sameAsnetworkId1 = TenantNetworkId.networkId("1"); + final TenantNetworkId networkId2 = TenantNetworkId.networkId("2"); + + /** + * Checks that the TenantNetworkId class is immutable. + */ + @Test + public void testImmutability() { + assertThatClassIsImmutable(TenantNetworkId.class); + } + + /** + * Checks the operation of equals() methods. + */ + @Test + public void testEquals() { + new EqualsTester().addEqualityGroup(networkId1, sameAsnetworkId1) + .addEqualityGroup(networkId2).testEquals(); + } + + /** + * Checks the construction of a TenantNetworkId object. + */ + @Test + public void testConstruction() { + final String networkIdValue = "s"; + final TenantNetworkId networkId = TenantNetworkId.networkId(networkIdValue); + assertThat(networkId, is(notNullValue())); + assertThat(networkId.networkId(), is(networkIdValue)); + } +} diff --git a/framework/src/onos/apps/vtn/vtnrsc/src/test/java/org/onosproject/vtnrsc/virtualport/AllowedAddressPairTest.java b/framework/src/onos/apps/vtn/vtnrsc/src/test/java/org/onosproject/vtnrsc/virtualport/AllowedAddressPairTest.java new file mode 100644 index 00000000..dabe5896 --- /dev/null +++ b/framework/src/onos/apps/vtn/vtnrsc/src/test/java/org/onosproject/vtnrsc/virtualport/AllowedAddressPairTest.java @@ -0,0 +1,76 @@ +/* + * 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.vtnrsc.virtualport; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.notNullValue; +import static org.onlab.junit.ImmutableClassChecker.assertThatClassIsImmutable; + +import org.junit.Test; +import org.onlab.packet.IpAddress; +import org.onlab.packet.MacAddress; +import org.onosproject.vtnrsc.AllowedAddressPair; + +import com.google.common.testing.EqualsTester; + +/** + * Unit tests for AllowedAddressPair class. + */ +public class AllowedAddressPairTest { + + final IpAddress ip1 = IpAddress.valueOf("192.168.0.1"); + final IpAddress ip2 = IpAddress.valueOf("192.168.0.2"); + final MacAddress mac1 = MacAddress.valueOf("fa:16:3e:76:83:88"); + final MacAddress mac2 = MacAddress.valueOf("aa:16:3e:76:83:88"); + + /** + * Checks that the AllowedAddressPair class is immutable. + */ + @Test + public void testImmutability() { + assertThatClassIsImmutable(AllowedAddressPair.class); + } + + /** + * Checks the operation of equals(). + */ + @Test + public void testEquals() { + AllowedAddressPair p1 = AllowedAddressPair + .allowedAddressPair(ip1, mac1); + AllowedAddressPair p2 = AllowedAddressPair + .allowedAddressPair(ip1, mac1); + AllowedAddressPair p3 = AllowedAddressPair + .allowedAddressPair(ip2, mac2); + new EqualsTester().addEqualityGroup(p1, p2).addEqualityGroup(p3) + .testEquals(); + } + + /** + * Checks the construction of a AllowedAddressPair object. + */ + @Test + public void testConstruction() { + AllowedAddressPair allowedAddressPair = AllowedAddressPair + .allowedAddressPair(ip1, mac1); + assertThat(ip1, is(notNullValue())); + assertThat(ip1, is(allowedAddressPair.ip())); + assertThat(mac1, is(notNullValue())); + assertThat(mac1, is(allowedAddressPair.mac())); + } +} diff --git a/framework/src/onos/apps/vtn/vtnrsc/src/test/java/org/onosproject/vtnrsc/virtualport/DefaultVirtualPortTest.java b/framework/src/onos/apps/vtn/vtnrsc/src/test/java/org/onosproject/vtnrsc/virtualport/DefaultVirtualPortTest.java new file mode 100644 index 00000000..8a0c8004 --- /dev/null +++ b/framework/src/onos/apps/vtn/vtnrsc/src/test/java/org/onosproject/vtnrsc/virtualport/DefaultVirtualPortTest.java @@ -0,0 +1,142 @@ +/* + * 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.vtnrsc.virtualport; + +import static org.onlab.junit.ImmutableClassChecker.assertThatClassIsImmutable; + +import java.util.Map; +import java.util.Set; + +import org.junit.Test; +import org.onlab.packet.IpAddress; +import org.onlab.packet.MacAddress; +import org.onosproject.net.DeviceId; +import org.onosproject.vtnrsc.AllowedAddressPair; +import org.onosproject.vtnrsc.BindingHostId; +import org.onosproject.vtnrsc.DefaultVirtualPort; +import org.onosproject.vtnrsc.FixedIp; +import org.onosproject.vtnrsc.SecurityGroup; +import org.onosproject.vtnrsc.SubnetId; +import org.onosproject.vtnrsc.TenantId; +import org.onosproject.vtnrsc.TenantNetworkId; +import org.onosproject.vtnrsc.VirtualPort; +import org.onosproject.vtnrsc.VirtualPortId; + +import com.google.common.collect.Maps; +import com.google.common.collect.Sets; +import com.google.common.testing.EqualsTester; + +/** + * Unit tests for DefaultVirtualPort class. + */ +public class DefaultVirtualPortTest { + + private Set<FixedIp> fixedIps; + private Map<String, String> propertyMap; + private Set<AllowedAddressPair> allowedAddressPairs; + private Set<SecurityGroup> securityGroups; + private VirtualPortId id1; + private VirtualPortId id2; + private String macAddressStr = "fa:12:3e:56:ee:a2"; + private String ipAddress = "10.1.1.1"; + private String deviceStr = "of:000000000000001"; + private String tenantIdStr = "123"; + private String portId1 = "1241"; + private String portId2 = "1242"; + private String tenantNetworkId = "1234567"; + private String subnet = "1212"; + private String hostIdStr = "fa:e2:3e:56:ee:a2"; + + private void initVirtualPortId() { + id1 = VirtualPortId.portId(portId1); + id2 = VirtualPortId.portId(portId2); + } + + private void initFixedIpSet() { + FixedIp fixedIp = FixedIp.fixedIp(SubnetId.subnetId(subnet), + IpAddress.valueOf(ipAddress)); + fixedIps = Sets.newHashSet(); + fixedIps.add(fixedIp); + } + + private void initPropertyMap() { + String deviceOwner = "james"; + propertyMap = Maps.newHashMap(); + propertyMap.putIfAbsent("deviceOwner", deviceOwner); + } + + private void initAddressPairSet() { + allowedAddressPairs = Sets.newHashSet(); + AllowedAddressPair allowedAddressPair = AllowedAddressPair + .allowedAddressPair(IpAddress.valueOf(ipAddress), + MacAddress.valueOf(macAddressStr)); + allowedAddressPairs.add(allowedAddressPair); + } + + private void initSecurityGroupSet() { + securityGroups = Sets.newHashSet(); + } + + /** + * Checks that the DefaultVirtualPort class is immutable. + */ + @Test + public void testImmutability() { + assertThatClassIsImmutable(SecurityGroup.class); + } + + /** + * Checks the operation of equals(). + */ + @Test + public void testEquals() { + initVirtualPortId(); + initFixedIpSet(); + initPropertyMap(); + initAddressPairSet(); + initSecurityGroupSet(); + TenantNetworkId networkId = TenantNetworkId.networkId(tenantNetworkId); + MacAddress macAddress = MacAddress.valueOf(macAddressStr); + TenantId tenantId = TenantId.tenantId(tenantIdStr); + DeviceId deviceId = DeviceId.deviceId(deviceStr); + BindingHostId bindingHostId = BindingHostId.bindingHostId(hostIdStr); + + VirtualPort d1 = new DefaultVirtualPort(id1, networkId, true, + propertyMap, + VirtualPort.State.ACTIVE, + macAddress, tenantId, deviceId, + fixedIps, bindingHostId, + allowedAddressPairs, + securityGroups); + VirtualPort d2 = new DefaultVirtualPort(id1, networkId, true, + propertyMap, + VirtualPort.State.ACTIVE, + macAddress, tenantId, deviceId, + fixedIps, bindingHostId, + allowedAddressPairs, + securityGroups); + VirtualPort d3 = new DefaultVirtualPort(id2, networkId, true, + propertyMap, + VirtualPort.State.ACTIVE, + macAddress, tenantId, deviceId, + fixedIps, bindingHostId, + allowedAddressPairs, + securityGroups); + new EqualsTester().addEqualityGroup(d1, d2).addEqualityGroup(d3) + .testEquals(); + } +} diff --git a/framework/src/onos/apps/vtn/vtnrsc/src/test/java/org/onosproject/vtnrsc/virtualport/FixedIpTest.java b/framework/src/onos/apps/vtn/vtnrsc/src/test/java/org/onosproject/vtnrsc/virtualport/FixedIpTest.java new file mode 100644 index 00000000..1e33da09 --- /dev/null +++ b/framework/src/onos/apps/vtn/vtnrsc/src/test/java/org/onosproject/vtnrsc/virtualport/FixedIpTest.java @@ -0,0 +1,72 @@ +/* + * 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.vtnrsc.virtualport; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.notNullValue; +import static org.onlab.junit.ImmutableClassChecker.assertThatClassIsImmutable; + +import org.junit.Test; +import org.onlab.packet.IpAddress; +import org.onosproject.vtnrsc.FixedIp; +import org.onosproject.vtnrsc.SubnetId; + +import com.google.common.testing.EqualsTester; + +/** + * Unit tests for FixedIp class. + */ +public class FixedIpTest { + + final SubnetId subnetId1 = SubnetId.subnetId("lef11-95w-4er-9c9c"); + final SubnetId subnetId2 = SubnetId.subnetId("lefaa-95w-4er-9c9c"); + final IpAddress ip1 = IpAddress.valueOf("192.168.0.1"); + final IpAddress ip2 = IpAddress.valueOf("192.168.1.1"); + + /** + * Checks that the FixedIp class is immutable. + */ + @Test + public void testImmutability() { + assertThatClassIsImmutable(FixedIp.class); + } + + /** + * Checks the operation of equals(). + */ + @Test + public void testEquals() { + FixedIp fixedIp1 = FixedIp.fixedIp(subnetId1, ip1); + FixedIp fixedIp2 = FixedIp.fixedIp(subnetId1, ip1); + FixedIp fixedIp3 = FixedIp.fixedIp(subnetId2, ip2); + new EqualsTester().addEqualityGroup(fixedIp1, fixedIp2) + .addEqualityGroup(fixedIp3).testEquals(); + } + + /** + * Checks the construction of a FixedIp object. + */ + @Test + public void testConstruction() { + FixedIp fixedIp = FixedIp.fixedIp(subnetId1, ip1); + assertThat(ip1, is(notNullValue())); + assertThat(ip1, is(fixedIp.ip())); + assertThat(subnetId1, is(notNullValue())); + assertThat(subnetId1, is(fixedIp.subnetId())); + } +} diff --git a/framework/src/onos/apps/vtn/vtnrsc/src/test/java/org/onosproject/vtnrsc/virtualport/SecurityGroupTest.java b/framework/src/onos/apps/vtn/vtnrsc/src/test/java/org/onosproject/vtnrsc/virtualport/SecurityGroupTest.java new file mode 100644 index 00000000..8c04e499 --- /dev/null +++ b/framework/src/onos/apps/vtn/vtnrsc/src/test/java/org/onosproject/vtnrsc/virtualport/SecurityGroupTest.java @@ -0,0 +1,66 @@ +/* + * 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.vtnrsc.virtualport; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.notNullValue; +import static org.onlab.junit.ImmutableClassChecker.assertThatClassIsImmutable; + +import org.junit.Test; +import org.onosproject.vtnrsc.SecurityGroup; + +import com.google.common.testing.EqualsTester; + +/** + * Unit tests for SecurityGroup class. + */ +public class SecurityGroupTest { + + final SecurityGroup securityGroup1 = SecurityGroup.securityGroup("1"); + final SecurityGroup sameAssecurityGroup = SecurityGroup.securityGroup("1"); + final SecurityGroup securityGroup2 = SecurityGroup.securityGroup("2"); + + /** + * Checks that the SecurityGroup class is immutable. + */ + @Test + public void testImmutability() { + assertThatClassIsImmutable(SecurityGroup.class); + } + + /** + * Checks the operation of equals(). + */ + @Test + public void testEquals() { + new EqualsTester().addEqualityGroup(securityGroup1, sameAssecurityGroup) + .addEqualityGroup(securityGroup2).testEquals(); + } + + /** + * Checks the construction of a SecurityGroup object. + */ + @Test + public void testConstruction() { + final String securityGroupValue = "1"; + final SecurityGroup securityGroup = SecurityGroup.securityGroup(securityGroupValue); + assertThat(securityGroup, is(notNullValue())); + assertThat(securityGroup.securityGroup(), is(securityGroupValue)); + + } +} diff --git a/framework/src/onos/apps/vtn/vtnrsc/src/test/java/org/onosproject/vtnrsc/virtualport/VirtualPortIdTest.java b/framework/src/onos/apps/vtn/vtnrsc/src/test/java/org/onosproject/vtnrsc/virtualport/VirtualPortIdTest.java new file mode 100644 index 00000000..2d63e91c --- /dev/null +++ b/framework/src/onos/apps/vtn/vtnrsc/src/test/java/org/onosproject/vtnrsc/virtualport/VirtualPortIdTest.java @@ -0,0 +1,66 @@ +/* + * 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.vtnrsc.virtualport; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.notNullValue; +import static org.onlab.junit.ImmutableClassChecker.assertThatClassIsImmutable; + +import org.junit.Test; +import org.onosproject.vtnrsc.VirtualPortId; + +import com.google.common.testing.EqualsTester; + +/** + * Unit tests for VirtualPortId class. + */ +public class VirtualPortIdTest { + + final VirtualPortId virtualPortId1 = VirtualPortId.portId("1"); + final VirtualPortId sameAsVirtualPortId1 = VirtualPortId.portId("1"); + final VirtualPortId virtualPortId2 = VirtualPortId.portId("2"); + + /** + * Checks that the VirtualPortId class is immutable. + */ + @Test + public void testImmutability() { + assertThatClassIsImmutable(VirtualPortId.class); + } + + /** + * Checks the operation of equals(). + */ + @Test + public void testEquals() { + new EqualsTester().addEqualityGroup(virtualPortId1, sameAsVirtualPortId1) + .addEqualityGroup(virtualPortId2).testEquals(); + } + + /** + * Checks the construction of a VirtualPortId object. + */ + @Test + public void testConstruction() { + final String vPortIdValue = "aaa"; + final VirtualPortId virtualPortId = VirtualPortId.portId(vPortIdValue); + assertThat(virtualPortId, is(notNullValue())); + assertThat(virtualPortId.portId(), is(vPortIdValue)); + + } +} diff --git a/framework/src/onos/apps/vtn/vtnweb/src/main/java/org/onosproject/vtnweb/resources/FlowClassifierWebResource.java b/framework/src/onos/apps/vtn/vtnweb/src/main/java/org/onosproject/vtnweb/resources/FlowClassifierWebResource.java new file mode 100644 index 00000000..1450e4ef --- /dev/null +++ b/framework/src/onos/apps/vtn/vtnweb/src/main/java/org/onosproject/vtnweb/resources/FlowClassifierWebResource.java @@ -0,0 +1,192 @@ +/* + * 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.vtnweb.resources; + +import static javax.ws.rs.core.Response.Status.INTERNAL_SERVER_ERROR; +import static org.onlab.util.Tools.nullIsNotFound; +import static javax.ws.rs.core.Response.Status.NOT_FOUND; + +import java.io.IOException; +import java.io.InputStream; +import java.net.URI; +import java.net.URISyntaxException; +import java.util.UUID; + +import javax.ws.rs.Consumes; +import javax.ws.rs.DELETE; +import javax.ws.rs.GET; +import javax.ws.rs.POST; +import javax.ws.rs.PUT; +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 org.onosproject.vtnrsc.FlowClassifier; +import org.onosproject.vtnrsc.FlowClassifierId; +import org.onosproject.rest.AbstractWebResource; +import org.onosproject.vtnrsc.flowClassifier.FlowClassifierService; +import org.onosproject.vtnrsc.web.FlowClassifierCodec; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.node.ObjectNode; + +/** + * Query and program flow classifier. + */ +@Path("flow_classifiers") +public class FlowClassifierWebResource extends AbstractWebResource { + + final FlowClassifierService service = get(FlowClassifierService.class); + final ObjectNode root = mapper().createObjectNode(); + public static final String FLOW_CLASSIFIER_NOT_FOUND = "Flow classifier not found"; + + /** + * Get all flow classifiers created. Returns list of all flow classifiers + * created. + * + * @return 200 OK + */ + @GET + @Produces(MediaType.APPLICATION_JSON) + public Response getFlowClassifiers() { + Iterable<FlowClassifier> flowClassifiers = service.getFlowClassifiers(); + ObjectNode result = new ObjectMapper().createObjectNode(); + result.set("flow_classifiers", new FlowClassifierCodec().encode(flowClassifiers, this)); + return ok(result.toString()).build(); + } + + /** + * Get details of a flow classifier. Returns details of a specified flow + * classifier id. + * + * @param id flow classifier id + * @return 200 OK + */ + @GET + @Path("{flow_id}") + @Produces(MediaType.APPLICATION_JSON) + public Response getFlowClassifier(@PathParam("flow_id") String id) { + + if (!service.hasFlowClassifier(FlowClassifierId.flowClassifierId(UUID.fromString(id)))) { + return Response.status(NOT_FOUND).entity(FLOW_CLASSIFIER_NOT_FOUND).build(); + } + FlowClassifier flowClassifier = nullIsNotFound( + service.getFlowClassifier(FlowClassifierId.flowClassifierId(UUID.fromString(id))), + FLOW_CLASSIFIER_NOT_FOUND); + + ObjectNode result = new ObjectMapper().createObjectNode(); + result.set("flow_classifier", new FlowClassifierCodec().encode(flowClassifier, this)); + return ok(result.toString()).build(); + } + + /** + * Creates and stores a new flow classifier. + * + * @param flowClassifierId flow classifier identifier + * @param stream flow classifier from JSON + * @return status of the request - CREATED if the JSON is correct, + * BAD_REQUEST if the JSON is invalid + */ + @POST + @Path("{flow_id}") + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + public Response createFlowClassifier(@PathParam("flow_id") String flowClassifierId, InputStream stream) { + URI location; + try { + ObjectNode jsonTree = (ObjectNode) mapper().readTree(stream); + + FlowClassifier flowClassifier = codec(FlowClassifier.class).decode(jsonTree, this); + service.createFlowClassifier(flowClassifier); + location = new URI(flowClassifierId); + } catch (IOException | URISyntaxException ex) { + throw new IllegalArgumentException(ex); + } + return Response.created(location).build(); + } + + /** + * Creates and stores a new flow classifier. + * + * @param stream flow classifier from JSON + * @return status of the request - CREATED if the JSON is correct, + * BAD_REQUEST if the JSON is invalid + */ + @POST + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + public Response createFlowClassifier(InputStream stream) { + URI location; + try { + ObjectNode jsonTree = (ObjectNode) mapper().readTree(stream); + + FlowClassifier flowClassifier = codec(FlowClassifier.class).decode(jsonTree, this); + service.createFlowClassifier(flowClassifier); + location = new URI(flowClassifier.flowClassifierId().toString()); + } catch (IOException | URISyntaxException ex) { + throw new IllegalArgumentException(ex); + } + return Response.created(location).build(); + } + + /** + * Update details of a flow classifier. Update details of a specified flow + * classifier id. + * + * @param id flow classifier id + * @param stream InputStream + * @return 200 OK + */ + @PUT + @Path("{flow_id}") + @Produces(MediaType.APPLICATION_JSON) + @Consumes(MediaType.APPLICATION_JSON) + public Response updateFlowClassifier(@PathParam("flow_id") String id, final InputStream stream) { + try { + ObjectNode jsonTree = (ObjectNode) mapper().readTree(stream); + FlowClassifier flowClassifier = codec(FlowClassifier.class).decode(jsonTree, this); + Boolean result = nullIsNotFound(service.updateFlowClassifier(flowClassifier), FLOW_CLASSIFIER_NOT_FOUND); + if (!result) { + return Response.status(204).entity(FLOW_CLASSIFIER_NOT_FOUND).build(); + } + return Response.status(203).entity(result.toString()).build(); + } catch (Exception e) { + return Response.status(INTERNAL_SERVER_ERROR).entity(e.toString()).build(); + } + } + + /** + * Delete details of a flow classifier. Delete details of a specified flow + * classifier id. + * + * @param id flow classifier id + * @return 200 OK + * @throws IOException when input doesn't match. + */ + @Path("{flow_id}") + @DELETE + public Response deleteFlowClassifier(@PathParam("flow_id") String id) throws IOException { + try { + FlowClassifierId flowClassifierId = FlowClassifierId.flowClassifierId(UUID.fromString(id)); + service.removeFlowClassifier(flowClassifierId); + return Response.status(201).entity("SUCCESS").build(); + } catch (Exception e) { + return Response.status(INTERNAL_SERVER_ERROR).entity(e.toString()).build(); + } + } +} diff --git a/framework/src/onos/apps/vtn/vtnweb/src/main/java/org/onosproject/vtnweb/resources/SubnetWebResource.java b/framework/src/onos/apps/vtn/vtnweb/src/main/java/org/onosproject/vtnweb/resources/SubnetWebResource.java index 251dcffc..0cc59a4e 100644 --- a/framework/src/onos/apps/vtn/vtnweb/src/main/java/org/onosproject/vtnweb/resources/SubnetWebResource.java +++ b/framework/src/onos/apps/vtn/vtnweb/src/main/java/org/onosproject/vtnweb/resources/SubnetWebResource.java @@ -56,7 +56,7 @@ import org.onosproject.vtnrsc.TenantId; import org.onosproject.vtnrsc.TenantNetworkId; import org.onosproject.vtnrsc.Subnet.Mode; import org.onosproject.vtnrsc.subnet.SubnetService; -import org.onosproject.vtnrsc.web.SubnetCodec; +import org.onosproject.vtnweb.web.SubnetCodec; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/framework/src/onos/apps/vtn/vtnweb/src/main/java/org/onosproject/vtnweb/resources/TenantNetworkWebResource.java b/framework/src/onos/apps/vtn/vtnweb/src/main/java/org/onosproject/vtnweb/resources/TenantNetworkWebResource.java index 0b877822..2dd931ea 100644 --- a/framework/src/onos/apps/vtn/vtnweb/src/main/java/org/onosproject/vtnweb/resources/TenantNetworkWebResource.java +++ b/framework/src/onos/apps/vtn/vtnweb/src/main/java/org/onosproject/vtnweb/resources/TenantNetworkWebResource.java @@ -51,7 +51,7 @@ import org.onosproject.vtnrsc.TenantNetworkId; import org.onosproject.vtnrsc.TenantNetwork.State; import org.onosproject.vtnrsc.TenantNetwork.Type; import org.onosproject.vtnrsc.tenantnetwork.TenantNetworkService; -import org.onosproject.vtnrsc.web.TenantNetworkCodec; +import org.onosproject.vtnweb.web.TenantNetworkCodec; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/framework/src/onos/apps/vtn/vtnweb/src/main/java/org/onosproject/vtnweb/resources/VirtualPortWebResource.java b/framework/src/onos/apps/vtn/vtnweb/src/main/java/org/onosproject/vtnweb/resources/VirtualPortWebResource.java index 03d3a653..e47a57df 100644 --- a/framework/src/onos/apps/vtn/vtnweb/src/main/java/org/onosproject/vtnweb/resources/VirtualPortWebResource.java +++ b/framework/src/onos/apps/vtn/vtnweb/src/main/java/org/onosproject/vtnweb/resources/VirtualPortWebResource.java @@ -58,7 +58,7 @@ import org.onosproject.vtnrsc.VirtualPort; import org.onosproject.vtnrsc.VirtualPort.State; import org.onosproject.vtnrsc.VirtualPortId; import org.onosproject.vtnrsc.virtualport.VirtualPortService; -import org.onosproject.vtnrsc.web.VirtualPortCodec; +import org.onosproject.vtnweb.web.VirtualPortCodec; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/web/AllocationPoolsCodec.java b/framework/src/onos/apps/vtn/vtnweb/src/main/java/org/onosproject/vtnweb/web/AllocationPoolsCodec.java index 57c97c1c..4b6b662f 100644 --- a/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/web/AllocationPoolsCodec.java +++ b/framework/src/onos/apps/vtn/vtnweb/src/main/java/org/onosproject/vtnweb/web/AllocationPoolsCodec.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.onosproject.vtnrsc.web; +package org.onosproject.vtnweb.web; import static com.google.common.base.Preconditions.checkNotNull; diff --git a/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/web/AllowedAddressPairCodec.java b/framework/src/onos/apps/vtn/vtnweb/src/main/java/org/onosproject/vtnweb/web/AllowedAddressPairCodec.java index 7960808f..8ffc4e91 100644 --- a/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/web/AllowedAddressPairCodec.java +++ b/framework/src/onos/apps/vtn/vtnweb/src/main/java/org/onosproject/vtnweb/web/AllowedAddressPairCodec.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.onosproject.vtnrsc.web; +package org.onosproject.vtnweb.web; import static com.google.common.base.Preconditions.checkNotNull; diff --git a/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/web/FixedIpCodec.java b/framework/src/onos/apps/vtn/vtnweb/src/main/java/org/onosproject/vtnweb/web/FixedIpCodec.java index 96c9bb4e..559de685 100644 --- a/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/web/FixedIpCodec.java +++ b/framework/src/onos/apps/vtn/vtnweb/src/main/java/org/onosproject/vtnweb/web/FixedIpCodec.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.onosproject.vtnrsc.web; +package org.onosproject.vtnweb.web; import static com.google.common.base.Preconditions.checkNotNull; diff --git a/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/web/HostRoutesCodec.java b/framework/src/onos/apps/vtn/vtnweb/src/main/java/org/onosproject/vtnweb/web/HostRoutesCodec.java index 69ca6b3f..815a0d02 100644 --- a/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/web/HostRoutesCodec.java +++ b/framework/src/onos/apps/vtn/vtnweb/src/main/java/org/onosproject/vtnweb/web/HostRoutesCodec.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.onosproject.vtnrsc.web; +package org.onosproject.vtnweb.web; import static com.google.common.base.Preconditions.checkNotNull; diff --git a/framework/src/onos/apps/vtn/vtnweb/src/main/java/org/onosproject/vtnweb/web/PortChainCodec.java b/framework/src/onos/apps/vtn/vtnweb/src/main/java/org/onosproject/vtnweb/web/PortChainCodec.java new file mode 100644 index 00000000..28da5cd1 --- /dev/null +++ b/framework/src/onos/apps/vtn/vtnweb/src/main/java/org/onosproject/vtnweb/web/PortChainCodec.java @@ -0,0 +1,105 @@ +/* + * 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.vtnweb.web; + + +import static com.google.common.base.Preconditions.checkNotNull; +import static org.onlab.util.Tools.nullIsIllegal; + +import java.util.List; +import java.util.UUID; + +import org.onosproject.codec.CodecContext; +import org.onosproject.codec.JsonCodec; +import org.onosproject.vtnrsc.TenantId; +import org.onosproject.vtnrsc.DefaultPortChain; +import org.onosproject.vtnrsc.FlowClassifierId; +import org.onosproject.vtnrsc.PortChain; +import org.onosproject.vtnrsc.PortChainId; +import org.onosproject.vtnrsc.PortPairGroupId; + +import com.fasterxml.jackson.databind.node.ArrayNode; +import com.fasterxml.jackson.databind.node.ObjectNode; +import com.google.common.collect.Lists; + +/** + * Port chain JSON codec. + */ +public final class PortChainCodec extends JsonCodec<PortChain> { + + private static final String ID = "id"; + private static final String TENANT_ID = "tenant_id"; + private static final String NAME = "name"; + private static final String DESCRIPTION = "description"; + private static final String PORT_PAIR_GROUPS = "port_pair_groups"; + private static final String FLOW_CLASSIFIERS = "flow_classifiers"; + private static final String MISSING_MEMBER_MESSAGE = + " member is required in PortChain"; + + @Override + public PortChain decode(ObjectNode json, CodecContext context) { + if (json == null || !json.isObject()) { + return null; + } + + PortChain.Builder resultBuilder = new DefaultPortChain.Builder(); + + String id = nullIsIllegal(json.get(ID), + ID + MISSING_MEMBER_MESSAGE).asText(); + resultBuilder.setId(PortChainId.portChainId(id)); + + String tenantId = nullIsIllegal(json.get(TENANT_ID), + TENANT_ID + MISSING_MEMBER_MESSAGE).asText(); + resultBuilder.setTenantId(TenantId.tenantId(tenantId)); + + String name = nullIsIllegal(json.get(NAME), + NAME + MISSING_MEMBER_MESSAGE).asText(); + resultBuilder.setName(name); + + String description = nullIsIllegal(json.get(DESCRIPTION), + DESCRIPTION + MISSING_MEMBER_MESSAGE).asText(); + resultBuilder.setDescription(description); + + ArrayNode arrayNode = (ArrayNode) json.path(PORT_PAIR_GROUPS); + if (arrayNode != null) { + List<PortPairGroupId> list = Lists.newArrayList(); + arrayNode.forEach(i -> list.add(PortPairGroupId.portPairGroupId(i.asText()))); + resultBuilder.setPortPairGroups(list); + } + + arrayNode = (ArrayNode) json.path(FLOW_CLASSIFIERS); + if (arrayNode != null) { + List<FlowClassifierId> list = Lists.newArrayList(); + arrayNode.forEach(i -> list.add(FlowClassifierId.flowClassifierId(UUID.fromString(i.asText())))); + resultBuilder.setFlowClassifiers(list); + } + + return resultBuilder.build(); + } + + @Override + public ObjectNode encode(PortChain portChain, CodecContext context) { + checkNotNull(portChain, "port pair cannot be null"); + ObjectNode result = context.mapper().createObjectNode() + .put(ID, portChain.portChainId().toString()) + .put(TENANT_ID, portChain.tenantId().toString()) + .put(NAME, portChain.name()) + .put(DESCRIPTION, portChain.description()) + .put(PORT_PAIR_GROUPS, portChain.portPairGroups().toString()) + .put(FLOW_CLASSIFIERS, portChain.flowClassifiers().toString()); + return result; + } +} diff --git a/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/web/SecurityGroupCodec.java b/framework/src/onos/apps/vtn/vtnweb/src/main/java/org/onosproject/vtnweb/web/SecurityGroupCodec.java index c2ded196..18ed61ba 100644 --- a/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/web/SecurityGroupCodec.java +++ b/framework/src/onos/apps/vtn/vtnweb/src/main/java/org/onosproject/vtnweb/web/SecurityGroupCodec.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.onosproject.vtnrsc.web; +package org.onosproject.vtnweb.web; import static com.google.common.base.Preconditions.checkNotNull; diff --git a/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/web/SubnetCodec.java b/framework/src/onos/apps/vtn/vtnweb/src/main/java/org/onosproject/vtnweb/web/SubnetCodec.java index 122b75a9..e3d92fea 100644 --- a/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/web/SubnetCodec.java +++ b/framework/src/onos/apps/vtn/vtnweb/src/main/java/org/onosproject/vtnweb/web/SubnetCodec.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.onosproject.vtnrsc.web; +package org.onosproject.vtnweb.web; import static com.google.common.base.Preconditions.checkNotNull; diff --git a/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/web/TenantNetworkCodec.java b/framework/src/onos/apps/vtn/vtnweb/src/main/java/org/onosproject/vtnweb/web/TenantNetworkCodec.java index 48ba3b97..8adba034 100644 --- a/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/web/TenantNetworkCodec.java +++ b/framework/src/onos/apps/vtn/vtnweb/src/main/java/org/onosproject/vtnweb/web/TenantNetworkCodec.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.onosproject.vtnrsc.web; +package org.onosproject.vtnweb.web; import static com.google.common.base.Preconditions.checkNotNull; diff --git a/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/web/VirtualPortCodec.java b/framework/src/onos/apps/vtn/vtnweb/src/main/java/org/onosproject/vtnweb/web/VirtualPortCodec.java index e57d56bc..5cea5327 100644 --- a/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/web/VirtualPortCodec.java +++ b/framework/src/onos/apps/vtn/vtnweb/src/main/java/org/onosproject/vtnweb/web/VirtualPortCodec.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.onosproject.vtnrsc.web; +package org.onosproject.vtnweb.web; import static com.google.common.base.Preconditions.checkNotNull; diff --git a/framework/src/onos/apps/vtn/vtnweb/src/main/java/org/onosproject/vtnweb/web/package-info.java b/framework/src/onos/apps/vtn/vtnweb/src/main/java/org/onosproject/vtnweb/web/package-info.java new file mode 100644 index 00000000..3a609435 --- /dev/null +++ b/framework/src/onos/apps/vtn/vtnweb/src/main/java/org/onosproject/vtnweb/web/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. + */ + +/** + * Codecs for virtual tenant objects. + */ +package org.onosproject.vtnweb.web; diff --git a/framework/src/onos/bgp/api/src/main/java/org/onosproject/bgp/controller/BgpPeerManager.java b/framework/src/onos/bgp/api/src/main/java/org/onosproject/bgp/controller/BgpPeerManager.java new file mode 100755 index 00000000..d2230967 --- /dev/null +++ b/framework/src/onos/bgp/api/src/main/java/org/onosproject/bgp/controller/BgpPeerManager.java @@ -0,0 +1,54 @@ +/* + * 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.bgp.controller; + +/** + * Responsible for keeping track of the current set BGPLS peers connected to the system. + * + */ +public interface BgpPeerManager { + + /** + * Add connected peer. + * + * @param bgpId BGP ID to add + * @param bgpPeer BGp peer instance + * + * @return false if peer already exist, otherwise true + */ + public boolean addConnectedPeer(BGPId bgpId, BGPPeer bgpPeer); + + /** + * Validate wheather peer is connected. + * + * @param bgpId BGP ID to validate + * + * @return true if peer exist, otherwise false + */ + public boolean isPeerConnected(BGPId bgpId); + + /** + * Remove connected peer. + * + * @param bgpId BGP ID + */ + public void removeConnectedPeer(BGPId bgpId); + + /** + * Gets connected peer. + * + * @param bgpId BGP ID + * @return BGPPeer the connected peer, otherwise null + */ + public BGPPeer getPeer(BGPId bgpId); +} diff --git a/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/protocol/BGPFactories.java b/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/protocol/BGPFactories.java new file mode 100755 index 00000000..71b9cbff --- /dev/null +++ b/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/protocol/BGPFactories.java @@ -0,0 +1,82 @@ +/*
+ * 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.bgpio.protocol;
+
+import org.jboss.netty.buffer.ChannelBuffer;
+import org.onosproject.bgpio.exceptions.BGPParseException;
+import org.onosproject.bgpio.protocol.ver4.BGPFactoryVer4;
+import org.onosproject.bgpio.types.BGPHeader;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Abstraction to provide the version for BGP.
+ */
+public final class BGPFactories {
+
+ protected static final Logger log = LoggerFactory.getLogger(BGPFactories.class);
+
+ private static final GenericReader GENERIC_READER = new GenericReader();
+
+ private BGPFactories() {
+ }
+
+ /**
+ * Returns the instance of BGP Version.
+ *
+ * @param version BGP version
+ * @return BGP version
+ */
+ public static BGPFactory getFactory(BGPVersion version) {
+ switch (version) {
+ case BGP_4:
+ return BGPFactoryVer4.INSTANCE;
+ default:
+ throw new IllegalArgumentException("[BGPFactory:]Unknown version: " + version);
+ }
+ }
+
+ /**
+ * Reader class for reading BGP messages from channel buffer.
+ *
+ */
+ private static class GenericReader implements BGPMessageReader<BGPMessage> {
+
+ @Override
+ public BGPMessage readFrom(ChannelBuffer bb, BGPHeader bgpHeader)
+ throws BGPParseException {
+ BGPFactory factory;
+
+ if (!bb.readable()) {
+ log.error("Empty message received");
+ throw new BGPParseException("Empty message received");
+ }
+ // TODO: Currently only BGP version 4 is supported
+ factory = org.onosproject.bgpio.protocol.ver4.BGPFactoryVer4.INSTANCE;
+ return factory.getReader().readFrom(bb, bgpHeader);
+ }
+ }
+
+ /**
+ * Returns BGP messsage generic reader.
+ *
+ * @return bgp message generic reader
+ */
+ public static BGPMessageReader<BGPMessage> getGenericReader() {
+ return GENERIC_READER;
+ }
+}
diff --git a/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/protocol/BGPFactory.java b/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/protocol/BGPFactory.java new file mode 100755 index 00000000..cf6bf008 --- /dev/null +++ b/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/protocol/BGPFactory.java @@ -0,0 +1,60 @@ +/* + * 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.bgpio.protocol; + +/** + * Abstraction of an message factory providing builder functions to BGP messages + * and objects. + * + */ +public interface BGPFactory { + + /** + * Gets the builder object for a open message. + * + * @return builder object for open message + */ + BGPOpenMsg.Builder openMessageBuilder(); + + /** + * Gets the builder object for a keepalive message. + * + * @return builder object for keepalive message + */ + BGPKeepaliveMsg.Builder keepaliveMessageBuilder(); + + /** + * Gets the builder object for a notification message. + * + * @return builder object for notification message. + */ + BGPNotificationMsg.Builder notificationMessageBuilder(); + + /** + * Gets the BGP message reader. + * + * @return BGP message reader + */ + BGPMessageReader<BGPMessage> getReader(); + + /** + * Returns BGP version. + * + * @return BGP version + */ + BGPVersion getVersion(); +} diff --git a/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/protocol/BGPNotificationMsg.java b/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/protocol/BGPNotificationMsg.java index 56540dd3..a1d9d578 100644 --- a/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/protocol/BGPNotificationMsg.java +++ b/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/protocol/BGPNotificationMsg.java @@ -16,36 +16,34 @@ package org.onosproject.bgpio.protocol; import org.onosproject.bgpio.exceptions.BGPParseException; -import org.onosproject.bgpio.types.BGPHeader; /** - * Abstraction of an entity providing BGP Notification Message. + * Abstraction of an entity providing BGP notification message. */ public interface BGPNotificationMsg extends BGPMessage { /** - * Returns errorCode in Notification message. + * Returns errorCode in notification message. * - * @return errorCode in Notification message + * @return errorCode in notification message */ byte getErrorCode(); /** - * Returns error SubCode in Notification message. + * Returns error subCode in notification message. * - * @return error SubCode in Notification message + * @return error subCode in notification message */ byte getErrorSubCode(); /** - * Returns error data in Notification message. + * Returns error data in notification message. * - * @return error data in Notification message + * @return error data in notification message */ byte[] getData(); /** - * Builder interface with get and set functions to build Notification - * message. + * Builder interface with get and set functions to build notification message. */ public interface Builder extends BGPMessage.Builder { @@ -53,26 +51,18 @@ public interface BGPNotificationMsg extends BGPMessage { BGPNotificationMsg build() throws BGPParseException; /** - * Sets notification message header and returns its builder. - * - * @param header of notification message - * @return Builder by setting notification message header - */ - Builder setNotificationMsgHeader(BGPHeader header); - - /** * Sets errorCode in notification message and return its builder. * * @param errorCode in notification message - * @return builder by setting ErrorCode in notification message + * @return builder by setting errorCode in notification message */ Builder setErrorCode(byte errorCode); /** - * Sets error SubCode in notification message and return its builder. + * Sets error subCode in notification message and return its builder. * - * @param errorSubCode in notification Message - * @return builder by setting ErrorSubCode in notification Message + * @param errorSubCode in notification message + * @return builder by setting error subCode in notification message */ Builder setErrorSubCode(byte errorSubCode); diff --git a/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/protocol/ver4/BGPFactoryVer4.java b/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/protocol/ver4/BGPFactoryVer4.java new file mode 100755 index 00000000..32af3854 --- /dev/null +++ b/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/protocol/ver4/BGPFactoryVer4.java @@ -0,0 +1,58 @@ +/* + * 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.bgpio.protocol.ver4; + +import org.onosproject.bgpio.protocol.BGPFactory; +import org.onosproject.bgpio.protocol.BGPKeepaliveMsg; +import org.onosproject.bgpio.protocol.BGPMessage; +import org.onosproject.bgpio.protocol.BGPMessageReader; +import org.onosproject.bgpio.protocol.BGPNotificationMsg; +import org.onosproject.bgpio.protocol.BGPOpenMsg; +import org.onosproject.bgpio.protocol.BGPVersion; + +/** + * Provides BGP Factory and returns builder classes for all objects and messages. + */ +public class BGPFactoryVer4 implements BGPFactory { + + public static final BGPFactoryVer4 INSTANCE = new BGPFactoryVer4(); + + @Override + public BGPOpenMsg.Builder openMessageBuilder() { + return new BGPOpenMsgVer4.Builder(); + } + + @Override + public BGPKeepaliveMsg.Builder keepaliveMessageBuilder() { + return new BGPKeepaliveMsgVer4.Builder(); + } + + @Override + public BGPNotificationMsg.Builder notificationMessageBuilder() { + return new BGPNotificationMsgVer4.Builder(); + } + + @Override + public BGPMessageReader<BGPMessage> getReader() { + return BGPMessageVer4.READER; + } + + @Override + public BGPVersion getVersion() { + return BGPVersion.BGP_4; + } +}
\ No newline at end of file diff --git a/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/protocol/ver4/BGPMessageVer4.java b/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/protocol/ver4/BGPMessageVer4.java new file mode 100755 index 00000000..d45e3de1 --- /dev/null +++ b/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/protocol/ver4/BGPMessageVer4.java @@ -0,0 +1,109 @@ +/* + * 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.bgpio.protocol.ver4; + +import org.jboss.netty.buffer.ChannelBuffer; +import org.onosproject.bgpio.exceptions.BGPParseException; +import org.onosproject.bgpio.protocol.BGPFactories; +import org.onosproject.bgpio.protocol.BGPMessage; +import org.onosproject.bgpio.protocol.BGPMessageReader; +import org.onosproject.bgpio.types.BGPErrorType; +import org.onosproject.bgpio.types.BGPHeader; +import org.onosproject.bgpio.util.Validation; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Provides BGP messages. + */ +public abstract class BGPMessageVer4 { + + protected static final Logger log = LoggerFactory.getLogger(BGPFactories.class); + + static final byte OPEN_MSG_TYPE = 0x1; + static final byte KEEPALIVE_MSG_TYPE = 0x4; + static final byte UPDATE_MSG_TYPE = 0x2; + static final byte NOTIFICATION_MSG_TYPE = 0x3; + static final int MINIMUM_COMMON_HEADER_LENGTH = 19; + static final int HEADER_AND_MSG_LEN = 18; + static final int MAXIMUM_PACKET_LENGTH = 4096; + + public static final BGPMessageVer4.Reader READER = new Reader(); + + /** + * Reader class for reading BGP messages from channel buffer. + * + */ + static class Reader implements BGPMessageReader<BGPMessage> { + @Override + public BGPMessage readFrom(ChannelBuffer cb, BGPHeader bgpHeader) + throws BGPParseException { + + if (cb.readableBytes() < MINIMUM_COMMON_HEADER_LENGTH) { + log.error("Packet should have minimum length."); + Validation.validateLen(BGPErrorType.MESSAGE_HEADER_ERROR, BGPErrorType.BAD_MESSAGE_LENGTH, + cb.readableBytes()); + } + if (cb.readableBytes() > MAXIMUM_PACKET_LENGTH) { + log.error("Packet length should not exceed {}.", MAXIMUM_PACKET_LENGTH); + Validation.validateLen(BGPErrorType.MESSAGE_HEADER_ERROR, BGPErrorType.BAD_MESSAGE_LENGTH, + cb.readableBytes()); + } + try { + // fixed value property version == 4 + byte[] marker = new byte[BGPHeader.MARKER_LENGTH]; + cb.readBytes(marker, 0, BGPHeader.MARKER_LENGTH); + bgpHeader.setMarker(marker); + for (int i = 0; i < BGPHeader.MARKER_LENGTH; i++) { + if (marker[i] != (byte) 0xff) { + throw new BGPParseException(BGPErrorType.MESSAGE_HEADER_ERROR, + BGPErrorType.CONNECTION_NOT_SYNCHRONIZED, null); + } + } + short length = cb.readShort(); + if (length != (cb.readableBytes() + HEADER_AND_MSG_LEN)) { + Validation.validateLen(BGPErrorType.MESSAGE_HEADER_ERROR, BGPErrorType.BAD_MESSAGE_LENGTH, length); + } + bgpHeader.setLength(length); + byte type = cb.readByte(); + bgpHeader.setType(type); + log.debug("Reading update message of type " + type); + + int len = length - MINIMUM_COMMON_HEADER_LENGTH; + switch (type) { + case OPEN_MSG_TYPE: + log.debug("OPEN MESSAGE is received"); + return BGPOpenMsgVer4.READER.readFrom(cb.readBytes(len), bgpHeader); + case KEEPALIVE_MSG_TYPE: + log.debug("KEEPALIVE MESSAGE is received"); + return BGPKeepaliveMsgVer4.READER.readFrom(cb.readBytes(len), bgpHeader); + case UPDATE_MSG_TYPE: + log.debug("UPDATE MESSAGE is received"); + // TODO: Update message version 4 + case NOTIFICATION_MSG_TYPE: + log.debug("NOTIFICATION MESSAGE is received"); + return BGPNotificationMsgVer4.READER.readFrom(cb.readBytes(len), bgpHeader); + default: + Validation.validateType(BGPErrorType.MESSAGE_HEADER_ERROR, BGPErrorType.BAD_MESSAGE_TYPE, type); + return null; + } + } catch (IndexOutOfBoundsException e) { + throw new BGPParseException(BGPErrorType.MESSAGE_HEADER_ERROR, BGPErrorType.BAD_MESSAGE_LENGTH, null); + } + } + } +}
\ No newline at end of file diff --git a/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/protocol/ver4/BGPNotificationMsgVer4.java b/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/protocol/ver4/BGPNotificationMsgVer4.java index 064deada..3bddd375 100644 --- a/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/protocol/ver4/BGPNotificationMsgVer4.java +++ b/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/protocol/ver4/BGPNotificationMsgVer4.java @@ -44,7 +44,7 @@ class BGPNotificationMsgVer4 implements BGPNotificationMsg { REFERENCE : RFC 4271 */ - protected static final Logger log = LoggerFactory.getLogger(BGPNotificationMsgVer4.class); + private static final Logger log = LoggerFactory.getLogger(BGPNotificationMsgVer4.class); static final byte PACKET_VERSION = 4; //BGPHeader(19) + Error code(1) + Error subcode(1) @@ -52,8 +52,10 @@ class BGPNotificationMsgVer4 implements BGPNotificationMsg { static final int PACKET_MINIMUM_LENGTH = 2; static final BGPType MSG_TYPE = BGPType.NOTIFICATION; static final byte DEFAULT_ERRORSUBCODE = 0; - static final byte[] MARKER = {0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01}; + static final byte[] MARKER = {(byte) 0xff, (byte) 0xff, (byte) 0xff, + (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, + (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, + (byte) 0xff, (byte) 0xff, (byte) 0xff }; static final byte MESSAGE_TYPE = 3; static final BGPHeader DEFAULT_MESSAGE_HEADER = new BGPHeader(MARKER, BGPHeader.DEFAULT_HEADER_LENGTH, MESSAGE_TYPE); @@ -65,7 +67,7 @@ class BGPNotificationMsgVer4 implements BGPNotificationMsg { public static final BGPNotificationMsgVer4.Reader READER = new Reader(); /** - * Resets fields. + * Initialize fields. */ public BGPNotificationMsgVer4() { this.bgpHeader = null; @@ -154,13 +156,6 @@ class BGPNotificationMsgVer4 implements BGPNotificationMsg { } @Override - public Builder setNotificationMsgHeader(BGPHeader header) { - this.bgpHeader = header; - this.isBGPHeaderSet = true; - return this; - } - - @Override public Builder setHeader(BGPHeader bgpMsgHeader) { this.bgpHeader = bgpMsgHeader; return this; diff --git a/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/protocol/ver4/BgpPathAttributes.java b/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/protocol/ver4/BgpPathAttributes.java new file mode 100644 index 00000000..08fea4c6 --- /dev/null +++ b/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/protocol/ver4/BgpPathAttributes.java @@ -0,0 +1,190 @@ +/* + * 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.bgpio.protocol.ver4; + +import java.util.LinkedList; +import java.util.List; + +import org.jboss.netty.buffer.ChannelBuffer; +import org.onosproject.bgpio.exceptions.BGPParseException; +import org.onosproject.bgpio.types.As4Path; +import org.onosproject.bgpio.types.AsPath; +import org.onosproject.bgpio.types.BGPErrorType; +import org.onosproject.bgpio.types.BGPValueType; +import org.onosproject.bgpio.types.LocalPref; +import org.onosproject.bgpio.types.Med; +import org.onosproject.bgpio.types.NextHop; +import org.onosproject.bgpio.types.Origin; +import org.onosproject.bgpio.util.UnSupportedAttribute; +import org.onosproject.bgpio.util.Validation; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.common.base.MoreObjects; + +/** + * Provides Implementation of BGP Path Attribute. + */ +public class BgpPathAttributes { + + /* Path attribute: + <attribute type, attribute length, attribute value> + + 0 1 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Attr. Flags |Attr. Type Code| + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + REFERENCE : RFC 4271 + */ + protected static final Logger log = LoggerFactory.getLogger(BgpPathAttributes.class); + + public static final int LINK_STATE_ATTRIBUTE_TYPE = 50; + public static final int MPREACHNLRI_TYPE = 14; + public static final int MPUNREACHNLRI_TYPE = 15; + + private final List<BGPValueType> pathAttribute; + + /** + * Initialize parameter. + */ + public BgpPathAttributes() { + this.pathAttribute = null; + } + + /** + * Constructor to initialize parameters for BGP path attributes. + * + * @param pathAttribute list of path attributes + */ + public BgpPathAttributes(List<BGPValueType> pathAttribute) { + this.pathAttribute = pathAttribute; + } + + /** + * Returns list of path attributes. + * + * @return list of path attributes + */ + public List<BGPValueType> pathAttributes() { + return this.pathAttribute; + } + + /** + * Reads from channelBuffer and parses BGP path attributes. + * + * @param cb channelBuffer + * @return object of BgpPathAttributes + * @throws BGPParseException while parsing BGP path attributes + */ + public static BgpPathAttributes read(ChannelBuffer cb) + throws BGPParseException { + + BGPValueType pathAttribute = null; + List<BGPValueType> pathAttributeList = new LinkedList<>(); + boolean isOrigin = false; + boolean isAsPath = false; + boolean isNextHop = false; + boolean isMpReach = false; + boolean isMpUnReach = false; + while (cb.readableBytes() > 0) { + cb.markReaderIndex(); + byte flags = cb.readByte(); + byte typeCode = cb.readByte(); + cb.resetReaderIndex(); + switch (typeCode) { + case Origin.ORIGIN_TYPE: + pathAttribute = Origin.read(cb); + isOrigin = ((Origin) pathAttribute).isOriginSet(); + break; + case AsPath.ASPATH_TYPE: + pathAttribute = AsPath.read(cb); + isAsPath = ((AsPath) pathAttribute).isaspathSet(); + break; + case As4Path.AS4PATH_TYPE: + pathAttribute = As4Path.read(cb); + break; + case NextHop.NEXTHOP_TYPE: + pathAttribute = NextHop.read(cb); + isNextHop = ((NextHop) pathAttribute).isNextHopSet(); + break; + case Med.MED_TYPE: + pathAttribute = Med.read(cb); + break; + case LocalPref.LOCAL_PREF_TYPE: + pathAttribute = LocalPref.read(cb); + break; + case MPREACHNLRI_TYPE: + //TODO: To be merged later + break; + case MPUNREACHNLRI_TYPE: + //TODO: To be merged later + break; + case LINK_STATE_ATTRIBUTE_TYPE: + //TODO: To be merged later + break; + default: + //skip bytes for unsupported attribute types + UnSupportedAttribute.read(cb); + } + pathAttributeList.add(pathAttribute); + } + + checkMandatoryAttr(isOrigin, isAsPath, isNextHop, isMpReach, isMpUnReach); + //TODO:if mp_reach or mp_unreach not present ignore the packet + return new BgpPathAttributes(pathAttributeList); + } + + /** + * Checks mandatory attributes are presents, if not present throws exception. + * + * @param isOrigin say whether origin attribute is present + * @param isAsPath say whether aspath attribute is present + * @param isNextHop say whether nexthop attribute is present + * @param isMpReach say whether mpreach attribute is present + * @param isMpUnReach say whether mpunreach attribute is present + * @throws BGPParseException if mandatory path attribute is not present + */ + public static void checkMandatoryAttr(boolean isOrigin, boolean isAsPath, + boolean isNextHop, boolean isMpReach, boolean isMpUnReach) + throws BGPParseException { + if (!isOrigin) { + log.debug("Mandatory Attributes not Present"); + Validation.validateType(BGPErrorType.UPDATE_MESSAGE_ERROR, + BGPErrorType.MISSING_WELLKNOWN_ATTRIBUTE, + Origin.ORIGIN_TYPE); + } + if (!isAsPath) { + log.debug("Mandatory Attributes not Present"); + Validation.validateType(BGPErrorType.UPDATE_MESSAGE_ERROR, + BGPErrorType.MISSING_WELLKNOWN_ATTRIBUTE, + AsPath.ASPATH_TYPE); + } + if (!isMpUnReach && !isMpReach && !isNextHop) { + log.debug("Mandatory Attributes not Present"); + Validation.validateType(BGPErrorType.UPDATE_MESSAGE_ERROR, + BGPErrorType.MISSING_WELLKNOWN_ATTRIBUTE, + NextHop.NEXTHOP_TYPE); + } + } + + @Override + public String toString() { + return MoreObjects.toStringHelper(getClass()) + .add("pathAttribute", pathAttribute) + .toString(); + } +} diff --git a/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/types/As4Path.java b/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/types/As4Path.java new file mode 100644 index 00000000..90e94e88 --- /dev/null +++ b/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/types/As4Path.java @@ -0,0 +1,170 @@ +/* + * 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.bgpio.types; + +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; + +import org.jboss.netty.buffer.ChannelBuffer; +import org.onosproject.bgpio.exceptions.BGPParseException; +import org.onosproject.bgpio.util.Validation; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.common.base.MoreObjects; + +/** + * Provides Implementation of As4Path BGP Path Attribute. + */ +public class As4Path implements BGPValueType { + private static final Logger log = LoggerFactory.getLogger(AsPath.class); + public static final byte AS4PATH_TYPE = 17; + public static final byte ASNUM_SIZE = 4; + public static final int TYPE_AND_LEN_AS_SHORT = 4; + public static final int TYPE_AND_LEN_AS_BYTE = 3; + + private List<Integer> as4pathSet; + private List<Integer> as4pathSeq; + + /** + * Initialize fields. + */ + public As4Path() { + this.as4pathSeq = null; + this.as4pathSet = null; + } + + /** + * Constructor to initialize parameters. + * + * @param as4pathSet AS4path Set + * @param as4pathSeq AS4path Sequence + */ + public As4Path(List<Integer> as4pathSet, List<Integer> as4pathSeq) { + this.as4pathSeq = as4pathSeq; + this.as4pathSet = as4pathSet; + } + + /** + * Reads from the channel buffer and parses As4Path. + * + * @param cb ChannelBuffer + * @return object of As4Path + * @throws BGPParseException while parsing As4Path + */ + public static As4Path read(ChannelBuffer cb) throws BGPParseException { + List<Integer> as4pathSet = new ArrayList<>(); + List<Integer> as4pathSeq = new ArrayList<>(); + ChannelBuffer tempCb = cb.copy(); + Validation validation = Validation.parseAttributeHeader(cb); + + if (cb.readableBytes() < validation.getLength()) { + Validation.validateLen(BGPErrorType.UPDATE_MESSAGE_ERROR, BGPErrorType.ATTRIBUTE_LENGTH_ERROR, + validation.getLength()); + } + //if fourth bit is set length is read as short otherwise as byte , len includes type, length and value + int len = validation.isShort() ? validation.getLength() + TYPE_AND_LEN_AS_SHORT : validation + .getLength() + TYPE_AND_LEN_AS_BYTE; + ChannelBuffer data = tempCb.readBytes(len); + if (validation.getFirstBit() && !validation.getSecondBit() && validation.getThirdBit()) { + throw new BGPParseException(BGPErrorType.UPDATE_MESSAGE_ERROR, BGPErrorType.ATTRIBUTE_FLAGS_ERROR, data); + } + + ChannelBuffer tempBuf = cb.readBytes(validation.getLength()); + while (tempBuf.readableBytes() > 0) { + byte pathSegType = tempBuf.readByte(); + //no of ASes + byte pathSegLen = tempBuf.readByte(); + //length = no of Ases * ASnum size (4 bytes) + int length = pathSegLen * ASNUM_SIZE; + if (tempBuf.readableBytes() < length) { + Validation.validateLen(BGPErrorType.UPDATE_MESSAGE_ERROR, + BGPErrorType.ATTRIBUTE_LENGTH_ERROR, length); + } + ChannelBuffer aspathBuf = tempBuf.readBytes(length); + while (aspathBuf.readableBytes() > 0) { + int asNum; + asNum = aspathBuf.readInt(); + switch (pathSegType) { + case AsPath.ASPATH_SET_TYPE: + as4pathSet.add(asNum); + break; + case AsPath.ASPATH_SEQ_TYPE: + as4pathSeq.add(asNum); + break; + default: log.debug("Other type Not Supported:" + pathSegType); + } + } + } + return new As4Path(as4pathSet, as4pathSeq); + } + + @Override + public short getType() { + return AS4PATH_TYPE; + } + + /** + * Returns list of ASNum in AS4path Sequence. + * + * @return list of ASNum in AS4path Sequence + */ + public List<Integer> as4PathSEQ() { + return this.as4pathSeq; + } + + /** + * Returns list of ASNum in AS4path Set. + * + * @return list of ASNum in AS4path Set + */ + public List<Integer> as4PathSET() { + return this.as4pathSet; + } + + @Override + public int hashCode() { + return Objects.hash(as4pathSet, as4pathSeq); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof As4Path) { + As4Path other = (As4Path) obj; + return Objects.equals(as4pathSet, other.as4pathSet) && Objects.equals(as4pathSeq, other.as4pathSeq); + } + return false; + } + + @Override + public String toString() { + return MoreObjects.toStringHelper(getClass()) + .omitNullValues() + .add("as4pathSet", as4pathSet) + .add("as4pathSeq", as4pathSeq) + .toString(); + } + + @Override + public int write(ChannelBuffer cb) { + //Not required to Implement as of now + return 0; + } +}
\ No newline at end of file diff --git a/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/types/AsPath.java b/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/types/AsPath.java new file mode 100644 index 00000000..100e14d7 --- /dev/null +++ b/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/types/AsPath.java @@ -0,0 +1,209 @@ +/* + * 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.bgpio.types; + +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; + +import org.jboss.netty.buffer.ChannelBuffer; +import org.onosproject.bgpio.exceptions.BGPParseException; +import org.onosproject.bgpio.util.Validation; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.common.base.MoreObjects; + +/** + * Provides Implementation of AsPath mandatory BGP Path Attribute. + */ +public class AsPath implements BGPValueType { + /** + * Enum to provide AS types. + */ + public enum ASTYPE { + AS_SET(1), AS_SEQUENCE(2), AS_CONFED_SEQUENCE(3), AS_CONFED_SET(4); + int value; + + /** + * Assign val with the value as the AS type. + * + * @param val AS type + */ + ASTYPE(int val) { + value = val; + } + + /** + * Returns value of AS type. + * + * @return AS type + */ + public byte getType() { + return (byte) value; + } + } + + private static final Logger log = LoggerFactory.getLogger(AsPath.class); + public static final byte ASPATH_TYPE = 2; + public static final byte ASPATH_SET_TYPE = 1; + public static final byte ASPATH_SEQ_TYPE = 2; + public static final byte ASNUM_SIZE = 2; + public static final int TYPE_AND_LEN_AS_SHORT = 4; + public static final int TYPE_AND_LEN_AS_BYTE = 3; + + private boolean isAsPath = false; + private List<Short> aspathSet; + private List<Short> aspathSeq; + + /** + * Initialize Fields. + */ + public AsPath() { + this.aspathSeq = null; + this.aspathSet = null; + } + + /** + * Constructor to initialize parameters. + * + * @param aspathSet ASpath Set type + * @param aspathSeq ASpath Sequence type + */ + public AsPath(List<Short> aspathSet, List<Short> aspathSeq) { + this.aspathSeq = aspathSeq; + this.aspathSet = aspathSet; + this.isAsPath = true; + } + + /** + * Reads from the channel buffer and parses AsPath. + * + * @param cb ChannelBuffer + * @return object of AsPath + * @throws BGPParseException while parsing AsPath + */ + public static AsPath read(ChannelBuffer cb) throws BGPParseException { + List<Short> aspathSet = new ArrayList<>(); + List<Short> aspathSeq = new ArrayList<>(); + ChannelBuffer tempCb = cb.copy(); + Validation validation = Validation.parseAttributeHeader(cb); + + if (cb.readableBytes() < validation.getLength()) { + Validation.validateLen(BGPErrorType.UPDATE_MESSAGE_ERROR, BGPErrorType.ATTRIBUTE_LENGTH_ERROR, + validation.getLength()); + } + //if fourth bit is set, length is read as short otherwise as byte , len includes type, length and value + int len = validation.isShort() ? validation.getLength() + TYPE_AND_LEN_AS_SHORT : validation + .getLength() + TYPE_AND_LEN_AS_BYTE; + ChannelBuffer data = tempCb.readBytes(len); + if (validation.getFirstBit() && !validation.getSecondBit() && validation.getThirdBit()) { + throw new BGPParseException(BGPErrorType.UPDATE_MESSAGE_ERROR, BGPErrorType.ATTRIBUTE_FLAGS_ERROR, data); + } + + ChannelBuffer tempBuf = cb.readBytes(validation.getLength()); + while (tempBuf.readableBytes() > 0) { + byte pathSegType = tempBuf.readByte(); + //no of ASes + byte pathSegLen = tempBuf.readByte(); + int length = pathSegLen * ASNUM_SIZE; + if (tempBuf.readableBytes() < length) { + Validation.validateLen(BGPErrorType.UPDATE_MESSAGE_ERROR, + BGPErrorType.ATTRIBUTE_LENGTH_ERROR, length); + } + ChannelBuffer aspathBuf = tempBuf.readBytes(length); + while (aspathBuf.readableBytes() > 0) { + short asNum; + asNum = aspathBuf.readShort(); + switch (pathSegType) { + case ASPATH_SET_TYPE: + aspathSet.add(asNum); + break; + case ASPATH_SEQ_TYPE: + aspathSeq.add(asNum); + break; + default: log.debug("Other type Not Supported:" + pathSegType); + } + } + } + return new AsPath(aspathSet, aspathSeq); + } + + @Override + public short getType() { + return ASPATH_TYPE; + } + + /** + * Returns whether ASpath path attribute is present. + * + * @return whether ASpath path attribute is present + */ + public boolean isaspathSet() { + return this.isAsPath; + } + + /** + * Returns list of ASNum in ASpath Sequence. + * + * @return list of ASNum in ASpath Sequence + */ + public List<Short> asPathSeq() { + return this.aspathSeq; + } + + /** + * Returns list of ASNum in ASpath SET. + * + * @return list of ASNum in ASpath SET + */ + public List<Short> asPathSet() { + return this.aspathSet; + } + + @Override + public int hashCode() { + return Objects.hash(aspathSet, aspathSeq); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof AsPath) { + AsPath other = (AsPath) obj; + return Objects.equals(aspathSet, other.aspathSet) && Objects.equals(aspathSeq, other.aspathSeq); + } + return false; + } + + @Override + public String toString() { + return MoreObjects.toStringHelper(getClass()) + .omitNullValues() + .add("aspathSet", aspathSet) + .add("aspathSeq", aspathSeq) + .toString(); + } + + @Override + public int write(ChannelBuffer cb) { + //Not required to Implement as of now + return 0; + } +}
\ No newline at end of file diff --git a/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/types/LocalPref.java b/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/types/LocalPref.java new file mode 100644 index 00000000..048d81ee --- /dev/null +++ b/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/types/LocalPref.java @@ -0,0 +1,120 @@ +/* + * 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.bgpio.types; + +import java.util.Objects; + +import org.jboss.netty.buffer.ChannelBuffer; +import org.onosproject.bgpio.exceptions.BGPParseException; +import org.onosproject.bgpio.util.Validation; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.common.base.MoreObjects; + +/** + * Provides implementation of LocalPref BGP Path Attribute. + */ +public class LocalPref implements BGPValueType { + + private static final Logger log = LoggerFactory.getLogger(LocalPref.class); + public static final byte LOCAL_PREF_TYPE = 5; + public static final int TYPE_AND_LEN_AS_SHORT = 4; + public static final int TYPE_AND_LEN_AS_BYTE = 3; + public static final byte LOCAL_PREF_MAX_LEN = 4; + + private int localPref; + + /** + * Constructor to initialize LocalPref. + * + * @param localPref local preference + */ + public LocalPref(int localPref) { + this.localPref = localPref; + } + + /** + * Returns local preference value. + * + * @return local preference value + */ + public int localPref() { + return this.localPref; + } + + /** + * Reads the channel buffer and returns object of LocalPref. + * + * @param cb channelBuffer + * @return object of LocalPref + * @throws BGPParseException while parsing localPref attribute + */ + public static LocalPref read(ChannelBuffer cb) throws BGPParseException { + int localPref; + ChannelBuffer tempCb = cb.copy(); + Validation parseFlags = Validation.parseAttributeHeader(cb); + if ((parseFlags.getLength() > LOCAL_PREF_MAX_LEN) || cb.readableBytes() < parseFlags.getLength()) { + Validation.validateLen(BGPErrorType.UPDATE_MESSAGE_ERROR, BGPErrorType.ATTRIBUTE_LENGTH_ERROR, + parseFlags.getLength()); + } + + int len = parseFlags.isShort() ? parseFlags.getLength() + TYPE_AND_LEN_AS_SHORT : parseFlags.getLength() + + TYPE_AND_LEN_AS_BYTE; + ChannelBuffer data = tempCb.readBytes(len); + if (parseFlags.getFirstBit()) { + throw new BGPParseException(BGPErrorType.UPDATE_MESSAGE_ERROR, BGPErrorType.ATTRIBUTE_FLAGS_ERROR, data); + } + + localPref = cb.readInt(); + return new LocalPref(localPref); + } + + @Override + public short getType() { + return LOCAL_PREF_TYPE; + } + + @Override + public int hashCode() { + return Objects.hash(localPref); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof LocalPref) { + LocalPref other = (LocalPref) obj; + return Objects.equals(localPref, other.localPref); + } + return false; + } + + @Override + public String toString() { + return MoreObjects.toStringHelper(getClass()) + .add("localPref", localPref) + .toString(); + } + + @Override + public int write(ChannelBuffer cb) { + //Not to implement as of now + return 0; + } +}
\ No newline at end of file diff --git a/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/types/Med.java b/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/types/Med.java new file mode 100644 index 00000000..49e1fc5a --- /dev/null +++ b/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/types/Med.java @@ -0,0 +1,119 @@ +/* + * 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.bgpio.types; + +import java.util.Objects; + +import org.jboss.netty.buffer.ChannelBuffer; +import org.onosproject.bgpio.exceptions.BGPParseException; +import org.onosproject.bgpio.util.Validation; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.common.base.MoreObjects; + +/** + * Provides Implementation of Med BGP Path Attribute. + */ +public class Med implements BGPValueType { + private static final Logger log = LoggerFactory.getLogger(Med.class); + public static final byte MED_TYPE = 4; + public static final int TYPE_AND_LEN_AS_SHORT = 4; + public static final int TYPE_AND_LEN_AS_BYTE = 3; + public static final byte MED_MAX_LEN = 4; + + private int med; + + /** + * Constructor to initialize med. + * + * @param med MULTI_EXIT_DISC value + */ + public Med(int med) { + this.med = med; + } + + /** + * Returns Med value. + * + * @return Med value + */ + public int med() { + return this.med; + } + + /** + * Reads the channel buffer and returns object of Med. + * + * @param cb ChannelBuffer + * @return object of Med + * @throws BGPParseException while parsing Med path attribute + */ + public static Med read(ChannelBuffer cb) throws BGPParseException { + int med; + ChannelBuffer tempCb = cb.copy(); + Validation parseFlags = Validation.parseAttributeHeader(cb); + + if ((parseFlags.getLength() > MED_MAX_LEN) || cb.readableBytes() < parseFlags.getLength()) { + Validation.validateLen(BGPErrorType.UPDATE_MESSAGE_ERROR, BGPErrorType.ATTRIBUTE_LENGTH_ERROR, + parseFlags.getLength()); + } + int len = parseFlags.isShort() ? parseFlags.getLength() + TYPE_AND_LEN_AS_SHORT : parseFlags + .getLength() + TYPE_AND_LEN_AS_BYTE; + ChannelBuffer data = tempCb.readBytes(len); + if (!parseFlags.getFirstBit() && parseFlags.getSecondBit() && parseFlags.getThirdBit()) { + throw new BGPParseException(BGPErrorType.UPDATE_MESSAGE_ERROR, BGPErrorType.ATTRIBUTE_FLAGS_ERROR, data); + } + + med = cb.readInt(); + return new Med(med); + } + + @Override + public short getType() { + return MED_TYPE; + } + + @Override + public int hashCode() { + return Objects.hash(med); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof Med) { + Med other = (Med) obj; + return Objects.equals(med, other.med); + } + return false; + } + + @Override + public String toString() { + return MoreObjects.toStringHelper(getClass()) + .add("med", med) + .toString(); + } + + @Override + public int write(ChannelBuffer cb) { + //Not to implement as of now + return 0; + } +}
\ No newline at end of file diff --git a/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/types/NextHop.java b/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/types/NextHop.java new file mode 100644 index 00000000..353ec3d5 --- /dev/null +++ b/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/types/NextHop.java @@ -0,0 +1,138 @@ +/* + * 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.bgpio.types; + +import java.net.InetAddress; +import java.util.Objects; + +import org.jboss.netty.buffer.ChannelBuffer; +import org.onlab.packet.Ip4Address; +import org.onosproject.bgpio.exceptions.BGPParseException; +import org.onosproject.bgpio.util.Validation; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.common.base.MoreObjects; +import com.google.common.base.Preconditions; + +/** + * Implementation of NextHop BGP Path Attribute. + */ +public class NextHop implements BGPValueType { + private static final Logger log = LoggerFactory.getLogger(NextHop.class); + public static final byte NEXTHOP_TYPE = 3; + public static final int TYPE_AND_LEN_AS_SHORT = 4; + public static final int TYPE_AND_LEN_AS_BYTE = 3; + + private boolean isNextHop = false; + private Ip4Address nextHop; + + /** + * Constructor to initialize parameters. + * + * @param nextHop nextHop address + */ + public NextHop(Ip4Address nextHop) { + this.nextHop = Preconditions.checkNotNull(nextHop); + this.isNextHop = true; + } + + /** + * Returns whether next hop is present. + * + * @return whether next hop is present + */ + public boolean isNextHopSet() { + return this.isNextHop; + } + + /** + * Reads from ChannelBuffer and parses NextHop. + * + * @param cb ChannelBuffer + * @return object of NextHop + * @throws BGPParseException while parsing nexthop attribute + */ + public static NextHop read(ChannelBuffer cb) throws BGPParseException { + Ip4Address nextHop; + ChannelBuffer tempCb = cb.copy(); + Validation parseFlags = Validation.parseAttributeHeader(cb); + + if (cb.readableBytes() < parseFlags.getLength()) { + Validation.validateLen(BGPErrorType.UPDATE_MESSAGE_ERROR, BGPErrorType.ATTRIBUTE_LENGTH_ERROR, + parseFlags.getLength()); + } + int len = parseFlags.isShort() ? parseFlags.getLength() + TYPE_AND_LEN_AS_SHORT : parseFlags + .getLength() + TYPE_AND_LEN_AS_BYTE; + ChannelBuffer data = tempCb.readBytes(len); + if (parseFlags.getFirstBit() && !parseFlags.getSecondBit() && parseFlags.getThirdBit()) { + throw new BGPParseException(BGPErrorType.UPDATE_MESSAGE_ERROR, BGPErrorType.ATTRIBUTE_FLAGS_ERROR, data); + } + + //TODO: use Validation.toInetAddress once Validation is merged + InetAddress ipAddress = (InetAddress) cb.readBytes(parseFlags.getLength()); + if (ipAddress.isMulticastAddress()) { + throw new BGPParseException("Multicast address is not supported"); + } + + nextHop = Ip4Address.valueOf(ipAddress); + return new NextHop(nextHop); + } + + /** + * Return nexthop address. + * + * @return nexthop address + */ + public Ip4Address nextHop() { + return nextHop; + } + + @Override + public short getType() { + return NEXTHOP_TYPE; + } + + @Override + public int write(ChannelBuffer cb) { + //Not required to be implemented now + return 0; + } + + @Override + public int hashCode() { + return Objects.hash(nextHop); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof NextHop) { + NextHop other = (NextHop) obj; + return Objects.equals(nextHop, other.nextHop); + } + return false; + } + + @Override + public String toString() { + return MoreObjects.toStringHelper(getClass()) + .add("nextHop", nextHop) + .toString(); + } +}
\ No newline at end of file diff --git a/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/types/Origin.java b/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/types/Origin.java new file mode 100644 index 00000000..3b2070de --- /dev/null +++ b/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/types/Origin.java @@ -0,0 +1,166 @@ +/* + * 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.bgpio.types; + +import java.util.Objects; + +import org.jboss.netty.buffer.ChannelBuffer; +import org.onosproject.bgpio.exceptions.BGPParseException; +import org.onosproject.bgpio.util.Validation; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.common.base.MoreObjects; + +/** + * Provides Implementation of mandatory BGP Origin path attribute. + */ +public class Origin implements BGPValueType { + private static final Logger log = LoggerFactory.getLogger(Origin.class); + + /** + * Enum to provide ORIGIN types. + */ + public enum ORIGINTYPE { + IGP(0), EGP(1), INCOMPLETE(2); + int value; + /** + * Assign val with the value as the ORIGIN type. + * + * @param val ORIGIN type + */ + ORIGINTYPE(int val) { + value = val; + } + + /** + * Returns value of ORIGIN type. + * + * @return ORIGIN type + */ + public byte getType() { + return (byte) value; + } + } + + public static final byte ORIGIN_TYPE = 1; + public static final byte ORIGIN_VALUE_LEN = 1; + public static final int TYPE_AND_LEN_AS_SHORT = 4; + public static final int TYPE_AND_LEN_AS_BYTE = 3; + + private boolean isOrigin = false; + private byte origin; + + /** + * Constructor to initialize parameters. + * + * @param origin origin value + */ + public Origin(byte origin) { + this.origin = origin; + this.isOrigin = true; + } + + /** + * Returns true if origin attribute is present otherwise false. + * + * @return whether origin is present or not + */ + public boolean isOriginSet() { + return this.isOrigin; + } + + /** + * Returns type of Origin in Enum values. + * + * @return type of Origin in Enum values + */ + public ORIGINTYPE origin() { + if (this.origin == 0) { + return ORIGINTYPE.IGP; + } else if (this.origin == 1) { + return ORIGINTYPE.EGP; + } else { + return ORIGINTYPE.INCOMPLETE; + } + } + + /** + * Reads from ChannelBuffer and parses Origin. + * + * @param cb ChannelBuffer + * @return object of Origin + * @throws BGPParseException while parsing Origin path attribute + */ + public static Origin read(ChannelBuffer cb) throws BGPParseException { + ChannelBuffer tempCb = cb.copy(); + Validation parseFlags = Validation.parseAttributeHeader(cb); + + int len = parseFlags.isShort() ? parseFlags.getLength() + TYPE_AND_LEN_AS_SHORT : parseFlags + .getLength() + TYPE_AND_LEN_AS_BYTE; + ChannelBuffer data = tempCb.readBytes(len); + if ((parseFlags.getLength() > ORIGIN_VALUE_LEN) || (cb.readableBytes() < parseFlags.getLength())) { + Validation.validateLen(BGPErrorType.UPDATE_MESSAGE_ERROR, BGPErrorType.ATTRIBUTE_LENGTH_ERROR, + parseFlags.getLength()); + } + if (parseFlags.getFirstBit() && !parseFlags.getSecondBit() && parseFlags.getThirdBit()) { + throw new BGPParseException(BGPErrorType.UPDATE_MESSAGE_ERROR, BGPErrorType.ATTRIBUTE_FLAGS_ERROR, data); + } + + byte originValue; + originValue = cb.readByte(); + if ((originValue != ORIGINTYPE.INCOMPLETE.value) || (originValue != ORIGINTYPE.IGP.value) || + (originValue != ORIGINTYPE.EGP.value)) { + throw new BGPParseException(BGPErrorType.UPDATE_MESSAGE_ERROR, BGPErrorType.INVALID_ORIGIN_ATTRIBUTE, data); + } + return new Origin(originValue); + } + + @Override + public short getType() { + return ORIGIN_TYPE; + } + + @Override + public int write(ChannelBuffer cb) { + //Not required to Implement as of now + return 0; + } + + @Override + public int hashCode() { + return Objects.hash(origin); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof Origin) { + Origin other = (Origin) obj; + return Objects.equals(origin, other.origin); + } + return false; + } + + @Override + public String toString() { + return MoreObjects.toStringHelper(getClass()) + .add("origin", origin) + .toString(); + } +}
\ No newline at end of file diff --git a/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/types/attr/BgpAttrNodeFlagBitTlv.java b/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/types/attr/BgpAttrNodeFlagBitTlv.java index ba02f6d1..e7f4a4c0 100755 --- a/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/types/attr/BgpAttrNodeFlagBitTlv.java +++ b/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/types/attr/BgpAttrNodeFlagBitTlv.java @@ -30,7 +30,7 @@ import com.google.common.base.MoreObjects; /** * Implements BGP attribute node flag. */ -public class BgpAttrNodeFlagBitTlv implements BGPValueType { +public final class BgpAttrNodeFlagBitTlv implements BGPValueType { protected static final Logger log = LoggerFactory .getLogger(BgpAttrNodeFlagBitTlv.class); @@ -38,16 +38,15 @@ public class BgpAttrNodeFlagBitTlv implements BGPValueType { public static final int ATTRNODE_FLAGBIT = 1024; /* Node flag bit TLV */ - private boolean bOverloadBit; - private boolean bAttachedBit; - private boolean bExternalBit; - private boolean bABRBit; + private final boolean bOverloadBit; + private final boolean bAttachedBit; + private final boolean bExternalBit; + private final boolean bAbrBit; - public static final int BIT_SET = 1; - public static final int FIRST_BIT = 0x80; - public static final int SECOND_BIT = 0x40; - public static final int THIRD_BIT = 0x20; - public static final int FOURTH_BIT = 0x01; + public static final byte FIRST_BIT = (byte) 0x80; + public static final byte SECOND_BIT = 0x40; + public static final byte THIRD_BIT = 0x20; + public static final byte FOURTH_BIT = 0x01; /** * Constructor to initialize parameters. @@ -55,14 +54,31 @@ public class BgpAttrNodeFlagBitTlv implements BGPValueType { * @param bOverloadBit Overload bit * @param bAttachedBit Attached bit * @param bExternalBit External bit - * @param bABRBit ABR Bit + * @param bAbrBit ABR Bit */ - BgpAttrNodeFlagBitTlv(boolean bOverloadBit, boolean bAttachedBit, - boolean bExternalBit, boolean bABRBit) { + private BgpAttrNodeFlagBitTlv(boolean bOverloadBit, boolean bAttachedBit, + boolean bExternalBit, boolean bAbrBit) { this.bOverloadBit = bOverloadBit; this.bAttachedBit = bAttachedBit; this.bExternalBit = bExternalBit; - this.bABRBit = bABRBit; + this.bAbrBit = bAbrBit; + } + + /** + * Returns object of this class with specified values. + * + * @param bOverloadBit Overload bit + * @param bAttachedBit Attached bit + * @param bExternalBit External bit + * @param bAbrBit ABR Bit + * @return object of BgpAttrNodeFlagBitTlv + */ + public static BgpAttrNodeFlagBitTlv of(final boolean bOverloadBit, + final boolean bAttachedBit, + final boolean bExternalBit, + final boolean bAbrBit) { + return new BgpAttrNodeFlagBitTlv(bOverloadBit, bAttachedBit, + bExternalBit, bAbrBit); } /** @@ -77,11 +93,11 @@ public class BgpAttrNodeFlagBitTlv implements BGPValueType { boolean bOverloadBit = false; boolean bAttachedBit = false; boolean bExternalBit = false; - boolean bABRBit = false; + boolean bAbrBit = false; short lsAttrLength = cb.readShort(); - if (lsAttrLength != 1) { + if ((lsAttrLength != 1) || (cb.readableBytes() < lsAttrLength)) { Validation.validateLen(BGPErrorType.UPDATE_MESSAGE_ERROR, BGPErrorType.ATTRIBUTE_LENGTH_ERROR, lsAttrLength); @@ -89,13 +105,13 @@ public class BgpAttrNodeFlagBitTlv implements BGPValueType { byte nodeFlagBits = cb.readByte(); - bOverloadBit = ((nodeFlagBits & (byte) FIRST_BIT) == FIRST_BIT); - bAttachedBit = ((nodeFlagBits & (byte) SECOND_BIT) == SECOND_BIT); - bExternalBit = ((nodeFlagBits & (byte) THIRD_BIT) == THIRD_BIT); - bABRBit = ((nodeFlagBits & (byte) FOURTH_BIT) == FOURTH_BIT); + bOverloadBit = ((nodeFlagBits & FIRST_BIT) == FIRST_BIT); + bAttachedBit = ((nodeFlagBits & SECOND_BIT) == SECOND_BIT); + bExternalBit = ((nodeFlagBits & THIRD_BIT) == THIRD_BIT); + bAbrBit = ((nodeFlagBits & FOURTH_BIT) == FOURTH_BIT); - return new BgpAttrNodeFlagBitTlv(bOverloadBit, bAttachedBit, - bExternalBit, bABRBit); + return BgpAttrNodeFlagBitTlv.of(bOverloadBit, bAttachedBit, + bExternalBit, bAbrBit); } /** @@ -103,7 +119,7 @@ public class BgpAttrNodeFlagBitTlv implements BGPValueType { * * @return Overload Bit */ - boolean getOverLoadBit() { + public boolean overLoadBit() { return bOverloadBit; } @@ -112,7 +128,7 @@ public class BgpAttrNodeFlagBitTlv implements BGPValueType { * * @return Attached Bit */ - boolean getAttachedBit() { + public boolean attachedBit() { return bAttachedBit; } @@ -121,7 +137,7 @@ public class BgpAttrNodeFlagBitTlv implements BGPValueType { * * @return External Bit */ - boolean getExternalBit() { + public boolean externalBit() { return bExternalBit; } @@ -130,8 +146,8 @@ public class BgpAttrNodeFlagBitTlv implements BGPValueType { * * @return ABR Bit */ - boolean getABRBit() { - return bABRBit; + public boolean abrBit() { + return bAbrBit; } @Override @@ -141,13 +157,13 @@ public class BgpAttrNodeFlagBitTlv implements BGPValueType { @Override public int write(ChannelBuffer cb) { - // TODO will be implementing it later + // TODO This will be implemented in the next version return 0; } @Override public int hashCode() { - return Objects.hash(bOverloadBit, bAttachedBit, bExternalBit, bABRBit); + return Objects.hash(bOverloadBit, bAttachedBit, bExternalBit, bAbrBit); } @Override @@ -161,7 +177,7 @@ public class BgpAttrNodeFlagBitTlv implements BGPValueType { return Objects.equals(bOverloadBit, other.bOverloadBit) && Objects.equals(bAttachedBit, other.bAttachedBit) && Objects.equals(bExternalBit, other.bExternalBit) - && Objects.equals(bABRBit, other.bABRBit); + && Objects.equals(bAbrBit, other.bAbrBit); } return false; } @@ -171,7 +187,7 @@ public class BgpAttrNodeFlagBitTlv implements BGPValueType { return MoreObjects.toStringHelper(getClass()) .add("bOverloadBit", bOverloadBit) .add("bAttachedBit", bAttachedBit) - .add("bExternalBit", bExternalBit).add("bABRBit", bABRBit) + .add("bExternalBit", bExternalBit).add("bAbrBit", bAbrBit) .toString(); } } diff --git a/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/types/attr/BgpAttrRouterIdV4.java b/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/types/attr/BgpAttrRouterIdV4.java index 00dffb58..a10d167a 100755 --- a/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/types/attr/BgpAttrRouterIdV4.java +++ b/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/types/attr/BgpAttrRouterIdV4.java @@ -31,15 +31,15 @@ import com.google.common.base.MoreObjects; /** * Implements BGP attribute node router ID. */ -public class BgpAttrRouterIdV4 implements BGPValueType { +public final class BgpAttrRouterIdV4 implements BGPValueType { protected static final Logger log = LoggerFactory .getLogger(BgpAttrRouterIdV4.class); - public short sType; + private final short sType; /* IPv4 Router-ID of Node */ - private Ip4Address ip4RouterId; + private final Ip4Address ip4RouterId; /** * Constructor to initialize the value. @@ -47,35 +47,45 @@ public class BgpAttrRouterIdV4 implements BGPValueType { * @param ip4RouterId IPV4 address of router * @param sType TLV type */ - BgpAttrRouterIdV4(Ip4Address ip4RouterId, short sType) { + private BgpAttrRouterIdV4(Ip4Address ip4RouterId, short sType) { this.ip4RouterId = ip4RouterId; this.sType = sType; } /** + * Returns object of this class with specified values. + * + * @param ip4RouterId IPv4 address + * @param sType Type of this TLV + * @return object of BgpAttrRouterIdV4 + */ + public static BgpAttrRouterIdV4 of(final Ip4Address ip4RouterId, + final short sType) { + return new BgpAttrRouterIdV4(ip4RouterId, sType); + } + + /** * Reads the IPv4 Router-ID. * * @param cb ChannelBuffer + * @param sType tag type * @return object of BgpAttrRouterIdV4 - * @throws BGPParseException while parsing BgpAttrNodeRouterId + * @throws BGPParseException while parsing BgpAttrRouterIdV4 */ public static BgpAttrRouterIdV4 read(ChannelBuffer cb, short sType) throws BGPParseException { - byte[] ipBytes; - Ip4Address ip4RouterId; - short lsAttrLength = cb.readShort(); - if (4 != lsAttrLength) { + if ((lsAttrLength != 4) || (cb.readableBytes() < lsAttrLength)) { Validation.validateLen(BGPErrorType.UPDATE_MESSAGE_ERROR, BGPErrorType.ATTRIBUTE_LENGTH_ERROR, lsAttrLength); } - ipBytes = new byte[lsAttrLength]; - cb.readBytes(ipBytes); - ip4RouterId = Ip4Address.valueOf(ipBytes); - return new BgpAttrRouterIdV4(ip4RouterId, sType); + byte[] ipBytes = new byte[lsAttrLength]; + cb.readBytes(ipBytes, 0, lsAttrLength); + Ip4Address ip4RouterId = Ip4Address.valueOf(ipBytes); + return BgpAttrRouterIdV4.of(ip4RouterId, sType); } /** @@ -83,7 +93,7 @@ public class BgpAttrRouterIdV4 implements BGPValueType { * * @return Router ID */ - Ip4Address getAttrRouterId() { + public Ip4Address attrRouterId() { return ip4RouterId; } @@ -112,7 +122,7 @@ public class BgpAttrRouterIdV4 implements BGPValueType { @Override public int write(ChannelBuffer cb) { - // TODO Auto-generated method stub + // TODO This will be implemented in the next version return 0; } diff --git a/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/types/attr/BgpAttrRouterIdV6.java b/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/types/attr/BgpAttrRouterIdV6.java index 561c3d4c..ea63c379 100755 --- a/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/types/attr/BgpAttrRouterIdV6.java +++ b/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/types/attr/BgpAttrRouterIdV6.java @@ -31,15 +31,15 @@ import com.google.common.base.MoreObjects; /** * Implements BGP attribute IPv6 router ID. */ -public class BgpAttrRouterIdV6 implements BGPValueType { +public final class BgpAttrRouterIdV6 implements BGPValueType { protected static final Logger log = LoggerFactory .getLogger(BgpAttrRouterIdV6.class); - public short sType; + private final short sType; /* IPv4 Router-ID of Node */ - private Ip6Address ip6RouterId; + private final Ip6Address ip6RouterId; /** * Constructor to initialize the value. @@ -47,15 +47,28 @@ public class BgpAttrRouterIdV6 implements BGPValueType { * @param ip6RouterId IPV6 address of the router ID * @param sType TLV type */ - BgpAttrRouterIdV6(Ip6Address ip6RouterId, short sType) { + private BgpAttrRouterIdV6(Ip6Address ip6RouterId, short sType) { this.ip6RouterId = ip6RouterId; this.sType = sType; } /** + * Returns object of this class with specified values. + * + * @param ip6RouterId IPV6 address of the router ID + * @param sType TLV type + * @return object of BgpAttrRouterIdV6 + */ + public static BgpAttrRouterIdV6 of(final Ip6Address ip6RouterId, + final short sType) { + return new BgpAttrRouterIdV6(ip6RouterId, sType); + } + + /** * Reads the IPv6 Router-ID. * * @param cb ChannelBuffer + * @param sType TLV type * @return object of BgpAttrRouterIdV6 * @throws BGPParseException while parsing BgpAttrRouterIdV6 */ @@ -66,7 +79,7 @@ public class BgpAttrRouterIdV6 implements BGPValueType { short lsAttrLength = cb.readShort(); - if (16 != lsAttrLength) { + if ((lsAttrLength != 16) || (cb.readableBytes() < lsAttrLength)) { Validation.validateLen(BGPErrorType.UPDATE_MESSAGE_ERROR, BGPErrorType.ATTRIBUTE_LENGTH_ERROR, lsAttrLength); @@ -75,7 +88,7 @@ public class BgpAttrRouterIdV6 implements BGPValueType { ipBytes = new byte[lsAttrLength]; cb.readBytes(ipBytes); ip6RouterId = Ip6Address.valueOf(ipBytes); - return new BgpAttrRouterIdV6(ip6RouterId, sType); + return BgpAttrRouterIdV6.of(ip6RouterId, sType); } /** @@ -83,7 +96,7 @@ public class BgpAttrRouterIdV6 implements BGPValueType { * * @return Router ID */ - Ip6Address getAttrRouterId() { + public Ip6Address attrRouterId() { return ip6RouterId; } @@ -112,7 +125,7 @@ public class BgpAttrRouterIdV6 implements BGPValueType { @Override public int write(ChannelBuffer cb) { - // TODO Auto-generated method stub + // TODO This will be implemented in the next version return 0; } diff --git a/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/types/attr/BgpLinkAttrIgpMetric.java b/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/types/attr/BgpLinkAttrIgpMetric.java new file mode 100755 index 00000000..c1cb299c --- /dev/null +++ b/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/types/attr/BgpLinkAttrIgpMetric.java @@ -0,0 +1,172 @@ +/* + * 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.bgpio.types.attr; + +import java.util.Objects; + +import org.jboss.netty.buffer.ChannelBuffer; +import org.onosproject.bgpio.exceptions.BGPParseException; +import org.onosproject.bgpio.types.BGPErrorType; +import org.onosproject.bgpio.types.BGPValueType; +import org.onosproject.bgpio.util.Validation; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.common.base.MoreObjects; + +/** + * Implements BGP link IGP metric attribute. + */ +public class BgpLinkAttrIgpMetric implements BGPValueType { + + protected static final Logger log = LoggerFactory + .getLogger(BgpLinkAttrIgpMetric.class); + + public static final int ATTRLINK_IGPMETRIC = 1095; + public static final int ATTRLINK_MAX_LEN = 3; + + /* Variable metric length based on protocol */ + public static final int ISIS_SMALL_METRIC = 1; + public static final int OSPF_LINK_METRIC = 2; + public static final int ISIS_WIDE_METRIC = 3; + + /* IGP Metric */ + private final int igpMetric; + private final int igpMetricLen; + + /** + * Constructor to initialize the value. + * + * @param igpMetric 3 byte IGP metric data. + * @param igpMetricLen length of IGP metric data. + */ + public BgpLinkAttrIgpMetric(final int igpMetric, final int igpMetricLen) { + this.igpMetric = igpMetric; + this.igpMetricLen = igpMetricLen; + } + + /** + * Returns object of this class with specified values. + * + * @param igpMetric 3 byte IGP metric data. + * @param igpMetricLen length of IGP metric data. + * @return object of BgpLinkAttrIgpMetric + */ + public static BgpLinkAttrIgpMetric of(final int igpMetric, + final int igpMetricLen) { + return new BgpLinkAttrIgpMetric(igpMetric, igpMetricLen); + } + + /** + * Reads the BGP link attributes IGP Metric. + * + * @param cb Channel buffer + * @return object of type BgpLinkAttrIgpMetric + * @throws BGPParseException while parsing BgpLinkAttrIgpMetric + */ + public static BgpLinkAttrIgpMetric read(ChannelBuffer cb) + throws BGPParseException { + + short linkigp; + int igpMetric = 0; + int igpMetricLen = 0; + + short lsAttrLength = cb.readShort(); + + if (cb.readableBytes() < lsAttrLength + || lsAttrLength > ATTRLINK_MAX_LEN) { + Validation.validateLen(BGPErrorType.UPDATE_MESSAGE_ERROR, + BGPErrorType.ATTRIBUTE_LENGTH_ERROR, + lsAttrLength); + } + + switch (lsAttrLength) { + case ISIS_SMALL_METRIC: + igpMetric = cb.readByte(); + igpMetricLen = ISIS_SMALL_METRIC; + break; + case OSPF_LINK_METRIC: + igpMetric = cb.readShort(); + igpMetricLen = OSPF_LINK_METRIC; + break; + case ISIS_WIDE_METRIC: + linkigp = cb.readShort(); + igpMetric = cb.readByte(); + igpMetric = (igpMetric << 16) | linkigp; + igpMetricLen = ISIS_WIDE_METRIC; + break; + default: // validation is already in place + break; + } + + return BgpLinkAttrIgpMetric.of(igpMetric, igpMetricLen); + } + + /** + * Returns the variable length IGP metric data. + * + * @return IGP metric data + */ + public int attrLinkIgpMetric() { + return igpMetric; + } + + /** + * Returns IGP metric data length. + * + * @return IGP metric length + */ + public int attrLinkIgpMetricLength() { + return igpMetricLen; + } + + @Override + public short getType() { + return ATTRLINK_IGPMETRIC; + } + + @Override + public int hashCode() { + return Objects.hash(igpMetric, igpMetricLen); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + + if (obj instanceof BgpLinkAttrIgpMetric) { + BgpLinkAttrIgpMetric other = (BgpLinkAttrIgpMetric) obj; + return Objects.equals(igpMetric, other.igpMetric) + && Objects.equals(igpMetricLen, other.igpMetricLen); + } + return false; + } + + @Override + public int write(ChannelBuffer cb) { + // TODO This will be implemented in the next version + return 0; + } + + @Override + public String toString() { + return MoreObjects.toStringHelper(getClass()) + .add("igpMetric", igpMetric).add("igpMetricLen", igpMetricLen) + .toString(); + } +} diff --git a/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/types/attr/BgpLinkAttrMplsProtocolMask.java b/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/types/attr/BgpLinkAttrMplsProtocolMask.java new file mode 100755 index 00000000..61143fae --- /dev/null +++ b/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/types/attr/BgpLinkAttrMplsProtocolMask.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.bgpio.types.attr; + +import java.util.Objects; + +import org.jboss.netty.buffer.ChannelBuffer; +import org.onosproject.bgpio.exceptions.BGPParseException; +import org.onosproject.bgpio.types.BGPErrorType; +import org.onosproject.bgpio.types.BGPValueType; +import org.onosproject.bgpio.util.Validation; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.common.base.MoreObjects; + +/** + * Implements BGP MPLS protocol mask attribute. + */ +public class BgpLinkAttrMplsProtocolMask implements BGPValueType { + + protected static final Logger log = LoggerFactory + .getLogger(BgpLinkAttrMplsProtocolMask.class); + + public static final int ATTRLINK_MPLSPROTOMASK = 1094; + public static final int MASK_BYTE_LEN = 1; + + private final boolean bLdp; + private final boolean bRsvpTe; + + public static final byte FIRST_BIT = (byte) 0x80; + public static final byte SECOND_BIT = 0x40; + + /** + * Constructor to initialize the values. + * + * @param bLdp boolean value true if LDP flag is available + * @param bRsvpTe boolean value true if RSVP TE information is available + */ + public BgpLinkAttrMplsProtocolMask(boolean bLdp, boolean bRsvpTe) { + this.bLdp = bLdp; + this.bRsvpTe = bRsvpTe; + } + + /** + * Returns object of this class with specified values. + * + * @param bLdp boolean value true if LDP flag is available + * @param bRsvpTe boolean value true if RSVP TE information is available + * @return object of BgpLinkAttrMplsProtocolMask + */ + public static BgpLinkAttrMplsProtocolMask of(final boolean bLdp, + final boolean bRsvpTe) { + return new BgpLinkAttrMplsProtocolMask(bLdp, bRsvpTe); + } + + /** + * Reads the BGP link attributes MPLS protocol mask. + * + * @param cb Channel buffer + * @return object of type BgpLinkAttrMPLSProtocolMask + * @throws BGPParseException while parsing BgpLinkAttrMplsProtocolMask + */ + public static BgpLinkAttrMplsProtocolMask read(ChannelBuffer cb) + throws BGPParseException { + boolean bLdp = false; + boolean bRsvpTe = false; + + short lsAttrLength = cb.readShort(); + + if ((lsAttrLength != MASK_BYTE_LEN) + || (cb.readableBytes() < lsAttrLength)) { + Validation.validateLen(BGPErrorType.UPDATE_MESSAGE_ERROR, + BGPErrorType.ATTRIBUTE_LENGTH_ERROR, + lsAttrLength); + } + + byte flags = cb.readByte(); + + bLdp = ((flags & (byte) FIRST_BIT) == FIRST_BIT); + bRsvpTe = ((flags & (byte) SECOND_BIT) == SECOND_BIT); + + return BgpLinkAttrMplsProtocolMask.of(bLdp, bRsvpTe); + } + + /** + * Returns true if LDP bit is set. + * + * @return True if LDP information is set else false. + */ + public boolean ldpBit() { + return bLdp; + } + + /** + * Returns RSVP TE information. + * + * @return True if RSVP TE information is set else false. + */ + public boolean rsvpBit() { + return bRsvpTe; + } + + @Override + public short getType() { + return ATTRLINK_MPLSPROTOMASK; + } + + @Override + public int hashCode() { + return Objects.hash(bLdp, bRsvpTe); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + + if (obj instanceof BgpLinkAttrMplsProtocolMask) { + BgpLinkAttrMplsProtocolMask other = (BgpLinkAttrMplsProtocolMask) obj; + return Objects.equals(bLdp, other.bLdp) + && Objects.equals(bRsvpTe, other.bRsvpTe); + } + return false; + } + + @Override + public int write(ChannelBuffer cb) { + // TODO This will be implemented in the next version + return 0; + } + + @Override + public String toString() { + return MoreObjects.toStringHelper(getClass()) + .add("bLdp", bLdp).add("bRsvpTe", bRsvpTe).toString(); + } +} diff --git a/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/types/attr/BgpLinkAttrProtectionType.java b/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/types/attr/BgpLinkAttrProtectionType.java new file mode 100755 index 00000000..b45d95b8 --- /dev/null +++ b/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/types/attr/BgpLinkAttrProtectionType.java @@ -0,0 +1,240 @@ +/* + * 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.bgpio.types.attr; + +import java.util.Objects; + +import org.jboss.netty.buffer.ChannelBuffer; +import org.onosproject.bgpio.exceptions.BGPParseException; +import org.onosproject.bgpio.types.BGPErrorType; +import org.onosproject.bgpio.types.BGPValueType; +import org.onosproject.bgpio.util.Validation; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.common.base.MoreObjects; + +/** + * Implements BGP link protection type attribute. + */ +public final class BgpLinkAttrProtectionType implements BGPValueType { + + protected static final Logger log = LoggerFactory + .getLogger(BgpLinkAttrProtectionType.class); + + public static final int ATTRLINK_PROTECTIONTYPE = 1093; + public static final int LINK_PROTECTION_LEN = 2; + + public static final int EXTRA_TRAFFIC = 0x01; + public static final int UNPROTECTED = 0x02; + public static final int SHARED = 0x04; + public static final int DEDICATED_ONE_ISTO_ONE = 0x08; + public static final int DEDICATED_ONE_PLUS_ONE = 0x10; + public static final int ENHANCED = 0x20; + + /* Link Protection type flags */ + private final boolean bExtraTraffic; + private final boolean bUnprotected; + private final boolean bShared; + private final boolean bDedOneIstoOne; + private final boolean bDedOnePlusOne; + private final boolean bEnhanced; + + /** + * Constructor to initialize the value. + * + * @param bExtraTraffic Extra Traffic + * @param bUnprotected Unprotected + * @param bShared Shared + * @param bDedOneIstoOne Dedicated 1:1 + * @param bDedOnePlusOne Dedicated 1+1 + * @param bEnhanced Enhanced + */ + private BgpLinkAttrProtectionType(boolean bExtraTraffic, + boolean bUnprotected, + boolean bShared, boolean bDedOneIstoOne, + boolean bDedOnePlusOne, boolean bEnhanced) { + this.bExtraTraffic = bExtraTraffic; + this.bUnprotected = bUnprotected; + this.bShared = bShared; + this.bDedOneIstoOne = bDedOneIstoOne; + this.bDedOnePlusOne = bDedOnePlusOne; + this.bEnhanced = bEnhanced; + } + + /** + * Returns object of this class with specified values. + * + * @param bExtraTraffic Extra Traffic + * @param bUnprotected Unprotected + * @param bShared Shared + * @param bDedOneIstoOne Dedicated 1:1 + * @param bDedOnePlusOne Dedicated 1+1 + * @param bEnhanced Enhanced + * @return object of BgpLinkAttrProtectionType + */ + public static BgpLinkAttrProtectionType of(boolean bExtraTraffic, + boolean bUnprotected, + boolean bShared, + boolean bDedOneIstoOne, + boolean bDedOnePlusOne, + boolean bEnhanced) { + return new BgpLinkAttrProtectionType(bExtraTraffic, bUnprotected, + bShared, bDedOneIstoOne, + bDedOnePlusOne, bEnhanced); + } + + /** + * Reads the BGP link attributes protection type. + * + * @param cb Channel buffer + * @return object of type BgpLinkAttrProtectionType + * @throws BGPParseException while parsing BgpLinkAttrProtectionType + */ + public static BgpLinkAttrProtectionType read(ChannelBuffer cb) + throws BGPParseException { + short linkProtectionType; + byte higherByte; + short lsAttrLength = cb.readShort(); + + boolean bExtraTraffic; + boolean bUnprotected; + boolean bShared; + boolean bDedOneIstoOne; + boolean bDedOnePlusOne; + boolean bEnhanced; + + if ((lsAttrLength != LINK_PROTECTION_LEN) + || (cb.readableBytes() < lsAttrLength)) { + Validation.validateLen(BGPErrorType.UPDATE_MESSAGE_ERROR, + BGPErrorType.ATTRIBUTE_LENGTH_ERROR, + lsAttrLength); + } + + linkProtectionType = cb.readShort(); + higherByte = (byte) (linkProtectionType >> 8); + + bExtraTraffic = ((higherByte & (byte) EXTRA_TRAFFIC) == EXTRA_TRAFFIC); + bUnprotected = ((higherByte & (byte) UNPROTECTED) == UNPROTECTED); + bShared = ((higherByte & (byte) SHARED) == SHARED); + bDedOneIstoOne = ((higherByte & (byte) DEDICATED_ONE_ISTO_ONE) == DEDICATED_ONE_ISTO_ONE); + bDedOnePlusOne = ((higherByte & (byte) DEDICATED_ONE_PLUS_ONE) == DEDICATED_ONE_PLUS_ONE); + bEnhanced = ((higherByte & (byte) ENHANCED) == ENHANCED); + + return BgpLinkAttrProtectionType.of(bExtraTraffic, bUnprotected, + bShared, bDedOneIstoOne, + bDedOnePlusOne, bEnhanced); + } + + /** + * Returns ExtraTraffic Bit. + * + * @return ExtraTraffic Bit + */ + public boolean extraTraffic() { + return bExtraTraffic; + } + + /** + * Returns Unprotected Bit. + * + * @return Unprotected Bit + */ + public boolean unprotected() { + return bUnprotected; + } + + /** + * Returns Shared Bit. + * + * @return Shared Bit + */ + public boolean shared() { + return bShared; + } + + /** + * Returns DedOneIstoOne Bit. + * + * @return DedOneIstoOne Bit + */ + public boolean dedOneIstoOne() { + return bDedOneIstoOne; + } + + /** + * Returns DedOnePlusOne Bit. + * + * @return DedOnePlusOne Bit + */ + public boolean dedOnePlusOne() { + return bDedOnePlusOne; + } + + /** + * Returns Enhanced Bit. + * + * @return Enhanced Bit + */ + public boolean enhanced() { + return bEnhanced; + } + + @Override + public short getType() { + return ATTRLINK_PROTECTIONTYPE; + } + + @Override + public int hashCode() { + return Objects.hash(bExtraTraffic, bUnprotected, bShared, + bDedOneIstoOne, bDedOnePlusOne, bEnhanced); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + + if (obj instanceof BgpLinkAttrProtectionType) { + BgpLinkAttrProtectionType other = (BgpLinkAttrProtectionType) obj; + return Objects.equals(bExtraTraffic, other.bExtraTraffic) + && Objects.equals(bUnprotected, other.bUnprotected) + && Objects.equals(bShared, other.bShared) + && Objects.equals(bDedOneIstoOne, other.bDedOneIstoOne) + && Objects.equals(bDedOnePlusOne, other.bDedOnePlusOne) + && Objects.equals(bEnhanced, other.bEnhanced); + } + return false; + } + + @Override + public int write(ChannelBuffer cb) { + // TODO This will be implemented in the next version + return 0; + } + + @Override + public String toString() { + return MoreObjects.toStringHelper(getClass()) + .add("bExtraTraffic", bExtraTraffic) + .add("bUnprotected", bUnprotected).add("bShared", bShared) + .add("bDedOneIstoOne", bDedOneIstoOne) + .add("bDedOnePlusOne", bDedOnePlusOne) + .add("bEnhanced", bEnhanced).toString(); + } +} diff --git a/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/types/attr/BgpPrefixAttrMetric.java b/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/types/attr/BgpPrefixAttrMetric.java new file mode 100755 index 00000000..0678b81f --- /dev/null +++ b/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/types/attr/BgpPrefixAttrMetric.java @@ -0,0 +1,131 @@ +/* + * 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.bgpio.types.attr; + +import java.util.Objects; + +import org.jboss.netty.buffer.ChannelBuffer; +import org.onosproject.bgpio.exceptions.BGPParseException; +import org.onosproject.bgpio.types.BGPErrorType; +import org.onosproject.bgpio.types.BGPValueType; +import org.onosproject.bgpio.util.Validation; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.common.base.MoreObjects; + +/** + * Implements BGP prefix metric attribute. + */ +public class BgpPrefixAttrMetric implements BGPValueType { + + protected static final Logger log = LoggerFactory + .getLogger(BgpPrefixAttrMetric.class); + + public static final int ATTR_PREFIX_METRIC = 1155; + public static final int ATTR_PREFIX_LEN = 4; + + /* TE Default Metric */ + private final int linkPfxMetric; + + /** + * Constructor to initialize value. + * + * @param linkPfxMetric Prefix Metric + */ + public BgpPrefixAttrMetric(int linkPfxMetric) { + this.linkPfxMetric = linkPfxMetric; + } + + /** + * Returns object of this class with specified values. + * + * @param linkPfxMetric Prefix Metric + * @return object of BgpPrefixAttrMetric + */ + public static BgpPrefixAttrMetric of(final int linkPfxMetric) { + return new BgpPrefixAttrMetric(linkPfxMetric); + } + + /** + * Reads the Prefix Metric. + * + * @param cb ChannelBuffer + * @return object of BgpPrefixAttrMetric + * @throws BGPParseException while parsing BgpPrefixAttrMetric + */ + public static BgpPrefixAttrMetric read(ChannelBuffer cb) + throws BGPParseException { + int linkPfxMetric; + + short lsAttrLength = cb.readShort(); // 4 Bytes + + if ((lsAttrLength != ATTR_PREFIX_LEN) + || (cb.readableBytes() < lsAttrLength)) { + Validation.validateLen(BGPErrorType.UPDATE_MESSAGE_ERROR, + BGPErrorType.ATTRIBUTE_LENGTH_ERROR, + lsAttrLength); + } + + linkPfxMetric = cb.readInt(); + + return BgpPrefixAttrMetric.of(linkPfxMetric); + } + + /** + * Returns the Prefix Metric. + * + * @return Prefix Metric + */ + public int attrPfxMetric() { + return linkPfxMetric; + } + + @Override + public short getType() { + return ATTR_PREFIX_METRIC; + } + + @Override + public int hashCode() { + return Objects.hash(linkPfxMetric); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + + if (obj instanceof BgpPrefixAttrMetric) { + BgpPrefixAttrMetric other = (BgpPrefixAttrMetric) obj; + return Objects.equals(linkPfxMetric, other.linkPfxMetric); + } + return false; + } + + @Override + public int write(ChannelBuffer cb) { + // TODO This will be implemented in the next version + return 0; + } + + @Override + public String toString() { + return MoreObjects.toStringHelper(getClass()) + .add("linkPfxMetric", linkPfxMetric).toString(); + } +} diff --git a/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/types/attr/BgpPrefixAttrOspfFwdAddr.java b/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/types/attr/BgpPrefixAttrOspfFwdAddr.java new file mode 100755 index 00000000..cf043046 --- /dev/null +++ b/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/types/attr/BgpPrefixAttrOspfFwdAddr.java @@ -0,0 +1,187 @@ +/* + * 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.bgpio.types.attr; + +import java.util.Objects; + +import org.jboss.netty.buffer.ChannelBuffer; +import org.onlab.packet.Ip4Address; +import org.onlab.packet.Ip6Address; +import org.onosproject.bgpio.exceptions.BGPParseException; +import org.onosproject.bgpio.types.BGPErrorType; +import org.onosproject.bgpio.types.BGPValueType; +import org.onosproject.bgpio.util.Validation; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.common.base.MoreObjects; + +/** + * Implements BGP prefix OSPF Forwarding address attribute. + */ +public class BgpPrefixAttrOspfFwdAddr implements BGPValueType { + + protected static final Logger log = LoggerFactory + .getLogger(BgpPrefixAttrOspfFwdAddr.class); + + public static final int ATTR_PREFIX_OSPFFWDADDR = 1156; + public static final int IPV4_LEN = 4; + public static final int IPV6_LEN = 16; + + /* OSPF Forwarding Address */ + private final short lsAttrLength; + private final Ip4Address ip4RouterId; + private final Ip6Address ip6RouterId; + + /** + * Constructor to initialize the value. + * + * @param lsAttrLength length of the IP address + * @param ip4RouterId Valid IPV4 address if length is 4 else null + * @param ip6RouterId Valid IPV6 address if length is 16 else null + */ + public BgpPrefixAttrOspfFwdAddr(short lsAttrLength, Ip4Address ip4RouterId, + Ip6Address ip6RouterId) { + this.lsAttrLength = lsAttrLength; + this.ip4RouterId = ip4RouterId; + this.ip6RouterId = ip6RouterId; + } + + /** + * Returns object of this class with specified values. + * + * @param lsAttrLength length of the IP address + * @param ip4RouterId Valid IPV4 address if length is 4 else null + * @param ip6RouterId Valid IPV6 address if length is 16 else null + * @return object of BgpPrefixAttrOspfFwdAddr + */ + public static BgpPrefixAttrOspfFwdAddr of(final short lsAttrLength, + final Ip4Address ip4RouterId, + final Ip6Address ip6RouterId) { + return new BgpPrefixAttrOspfFwdAddr(lsAttrLength, ip4RouterId, + ip6RouterId); + } + + /** + * Reads the OSPF Forwarding Address. + * + * @param cb ChannelBuffer + * @return object of BgpPrefixAttrOSPFFwdAddr + * @throws BGPParseException while parsing BgpPrefixAttrOspfFwdAddr + */ + public static BgpPrefixAttrOspfFwdAddr read(ChannelBuffer cb) + throws BGPParseException { + short lsAttrLength; + byte[] ipBytes; + Ip4Address ip4RouterId = null; + Ip6Address ip6RouterId = null; + + lsAttrLength = cb.readShort(); + ipBytes = new byte[lsAttrLength]; + + if ((cb.readableBytes() < lsAttrLength)) { + Validation.validateLen(BGPErrorType.UPDATE_MESSAGE_ERROR, + BGPErrorType.ATTRIBUTE_LENGTH_ERROR, + lsAttrLength); + } + + cb.readBytes(ipBytes); + + if (IPV4_LEN == lsAttrLength) { + ip4RouterId = Ip4Address.valueOf(ipBytes); + } else if (IPV6_LEN == lsAttrLength) { + ip6RouterId = Ip6Address.valueOf(ipBytes); + } + + return BgpPrefixAttrOspfFwdAddr.of(lsAttrLength, ip4RouterId, + ip6RouterId); + } + + /** + * Returns IPV4 Address of OSPF forwarding address. + * + * @return IPV4 address + */ + public Ip4Address ospfv4FwdAddr() { + return ip4RouterId; + } + + /** + * Returns IPV6 Address of OSPF forwarding address. + * + * @return IPV6 address + */ + public Ip6Address ospfv6FwdAddr() { + return ip6RouterId; + } + + /** + * Returns OSPF forwarding address length. + * + * @return length of the ip address + */ + public short ospfFwdAddrLen() { + return lsAttrLength; + } + + @Override + public short getType() { + return ATTR_PREFIX_OSPFFWDADDR; + } + + @Override + public int hashCode() { + if (IPV4_LEN == lsAttrLength) { + return Objects.hash(ip4RouterId); + } else { + return Objects.hash(ip6RouterId); + } + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + + if (obj instanceof BgpPrefixAttrOspfFwdAddr) { + BgpPrefixAttrOspfFwdAddr other = (BgpPrefixAttrOspfFwdAddr) obj; + if (IPV4_LEN == lsAttrLength) { + return Objects.equals(ip4RouterId, other.ip4RouterId); + } else { + return Objects.equals(ip6RouterId, other.ip6RouterId); + } + } + return false; + } + + @Override + public int write(ChannelBuffer cb) { + // TODO This will be implemented in the next version + return 0; + } + + @Override + public String toString() { + if (IPV4_LEN == lsAttrLength) { + return MoreObjects.toStringHelper(getClass()).omitNullValues() + .add("ip4RouterId", ip4RouterId).toString(); + } else { + return MoreObjects.toStringHelper(getClass()).omitNullValues() + .add("ip6RouterId", ip6RouterId).toString(); + } + } +} diff --git a/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/util/Validation.java b/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/util/Validation.java index 915aa580..bc131893 100644 --- a/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/util/Validation.java +++ b/framework/src/onos/bgp/bgpio/src/main/java/org/onosproject/bgpio/util/Validation.java @@ -16,6 +16,8 @@ package org.onosproject.bgpio.util; +import java.net.InetAddress; +import java.net.UnknownHostException; import java.util.Arrays; import org.jboss.netty.buffer.ChannelBuffer; @@ -23,6 +25,8 @@ import org.jboss.netty.buffer.ChannelBuffers; import org.onlab.packet.IpAddress; import org.onlab.packet.IpPrefix; import org.onosproject.bgpio.exceptions.BGPParseException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import com.google.common.primitives.Ints; @@ -30,10 +34,11 @@ import com.google.common.primitives.Ints; * Provides methods to parse attribute header, validate length and type. */ public class Validation { + private static final Logger log = LoggerFactory.getLogger(Validation.class); public static final byte FIRST_BIT = (byte) 0x80; public static final byte SECOND_BIT = 0x40; public static final byte THIRD_BIT = 0x20; - public static final byte FOURTH_BIT = 0x01; + public static final byte FOURTH_BIT = (byte) 0x10; public static final byte IPV4_SIZE = 4; private boolean firstBit; private boolean secondBit; @@ -42,6 +47,16 @@ public class Validation { private int len; private boolean isShort; + /** + * Constructor to initialize parameter. + * + * @param firstBit in AttributeFlags + * @param secondBit in AttributeFlags + * @param thirdBit in AttributeFlags + * @param fourthBit in AttributeFlags + * @param len length + * @param isShort true if length is read as short otherwise false + */ Validation(boolean firstBit, boolean secondBit, boolean thirdBit, boolean fourthBit, int len, boolean isShort) { this.firstBit = firstBit; this.secondBit = secondBit; @@ -119,6 +134,25 @@ public class Validation { } /** + * Convert byte array to InetAddress. + * + * @param length of IpAddress + * @param cb channelBuffer + * @return InetAddress + */ + public static InetAddress toInetAddress(int length, ChannelBuffer cb) { + byte[] address = new byte[length]; + cb.readBytes(address, 0, length); + InetAddress ipAddress = null; + try { + ipAddress = InetAddress.getByAddress(address); + } catch (UnknownHostException e) { + log.info("InetAddress convertion failed"); + } + return ipAddress; + } + + /** * Returns first bit in type flags. * * @return first bit in type flags diff --git a/framework/src/onos/bgp/bgpio/src/test/java/org/onosproject/bgp/BgpAttrNodeFlagBitTlvTest.java b/framework/src/onos/bgp/bgpio/src/test/java/org/onosproject/bgp/BgpAttrNodeFlagBitTlvTest.java new file mode 100644 index 00000000..5f1411ff --- /dev/null +++ b/framework/src/onos/bgp/bgpio/src/test/java/org/onosproject/bgp/BgpAttrNodeFlagBitTlvTest.java @@ -0,0 +1,51 @@ +/* + * 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.bgp; + +import org.junit.Test; +import org.onosproject.bgpio.types.attr.BgpAttrNodeFlagBitTlv; + +import com.google.common.testing.EqualsTester; + +/** + * Test for BGP attribute node flag. + */ +public class BgpAttrNodeFlagBitTlvTest { + + private final boolean bOverloadBit = true; + private final boolean bAttachedBit = true; + private final boolean bExternalBit = true; + private final boolean bABRBit = true; + + private final boolean bOverloadBit1 = false; + private final boolean bAttachedBit1 = false; + private final boolean bExternalBit1 = false; + private final boolean bABRBit1 = false; + + private final BgpAttrNodeFlagBitTlv data = BgpAttrNodeFlagBitTlv + .of(bOverloadBit, bAttachedBit, bExternalBit, bABRBit); + private final BgpAttrNodeFlagBitTlv sameAsData = BgpAttrNodeFlagBitTlv + .of(bOverloadBit, bAttachedBit, bExternalBit, bABRBit); + private final BgpAttrNodeFlagBitTlv diffData = BgpAttrNodeFlagBitTlv + .of(bOverloadBit1, bAttachedBit1, bExternalBit1, bABRBit1); + + @Test + public void basics() { + + new EqualsTester().addEqualityGroup(data, sameAsData) + .addEqualityGroup(diffData).testEquals(); + } +}
\ No newline at end of file diff --git a/framework/src/onos/bgp/bgpio/src/test/java/org/onosproject/bgp/BgpAttrRouterIdV6Test.java b/framework/src/onos/bgp/bgpio/src/test/java/org/onosproject/bgp/BgpAttrRouterIdV6Test.java new file mode 100644 index 00000000..72ca5dbf --- /dev/null +++ b/framework/src/onos/bgp/bgpio/src/test/java/org/onosproject/bgp/BgpAttrRouterIdV6Test.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.bgp; + +import org.junit.Test; +import org.onlab.packet.Ip6Address; +import org.onosproject.bgpio.types.attr.BgpAttrRouterIdV6; + +import com.google.common.testing.EqualsTester; + +/** + * Test for BGP attribute node router ID. + */ +public class BgpAttrRouterIdV6Test { + + private final short sType = 1; + private final Ip6Address ip6RouterId = Ip6Address + .valueOf("2001:0db8:0a0b:12f0:0000:0000:0000:0001"); + + private final short sType1 = 2; + private final Ip6Address ip6RouterId1 = Ip6Address + .valueOf("2004:0db8:0a0b:12f0:0000:0000:0000:0004"); + + private final BgpAttrRouterIdV6 data = BgpAttrRouterIdV6.of(ip6RouterId, + sType); + private final BgpAttrRouterIdV6 sameAsData = BgpAttrRouterIdV6 + .of(ip6RouterId, sType); + private final BgpAttrRouterIdV6 diffData = BgpAttrRouterIdV6 + .of(ip6RouterId1, sType1); + + @Test + public void basics() { + + new EqualsTester().addEqualityGroup(data, sameAsData) + .addEqualityGroup(diffData).testEquals(); + } +}
\ No newline at end of file diff --git a/framework/src/onos/bgp/bgpio/src/test/java/org/onosproject/bgp/BgpLinkAttrIgpMetricTest.java b/framework/src/onos/bgp/bgpio/src/test/java/org/onosproject/bgp/BgpLinkAttrIgpMetricTest.java new file mode 100644 index 00000000..32280a79 --- /dev/null +++ b/framework/src/onos/bgp/bgpio/src/test/java/org/onosproject/bgp/BgpLinkAttrIgpMetricTest.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.bgp; + +import org.junit.Test; +import org.onosproject.bgpio.types.attr.BgpLinkAttrIgpMetric; + +import com.google.common.testing.EqualsTester; + +/** + * Test for BGP link IGP metric attribute. + */ +public class BgpLinkAttrIgpMetricTest { + private final int val = 0x010203; + private final int valLen = 3; + private final int val1 = 0x01020304; + private final int val1Len = 4; + + private final BgpLinkAttrIgpMetric data = BgpLinkAttrIgpMetric.of(val, + valLen); + private final BgpLinkAttrIgpMetric sameAsData = BgpLinkAttrIgpMetric + .of(val, valLen); + private final BgpLinkAttrIgpMetric diffData = BgpLinkAttrIgpMetric + .of(val1, val1Len); + + @Test + public void basics() { + new EqualsTester().addEqualityGroup(data, sameAsData) + .addEqualityGroup(diffData).testEquals(); + } +}
\ No newline at end of file diff --git a/framework/src/onos/bgp/bgpio/src/test/java/org/onosproject/bgp/BgpLinkAttrProtectionTypeTest.java b/framework/src/onos/bgp/bgpio/src/test/java/org/onosproject/bgp/BgpLinkAttrProtectionTypeTest.java new file mode 100644 index 00000000..89f97a83 --- /dev/null +++ b/framework/src/onos/bgp/bgpio/src/test/java/org/onosproject/bgp/BgpLinkAttrProtectionTypeTest.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.bgp; + +import org.junit.Test; +import org.onosproject.bgpio.types.attr.BgpLinkAttrProtectionType; + +import com.google.common.testing.EqualsTester; + +/** + * Test for MPLS protocol mask attribute. + */ +public class BgpLinkAttrProtectionTypeTest { + boolean bExtraTraffic = true; + boolean bUnprotected = true; + boolean bShared = true; + boolean bDedOneIstoOne = true; + boolean bDedOnePlusOne = true; + boolean bEnhanced = true; + + boolean bExtraTraffic1 = false; + boolean bUnprotected1 = false; + boolean bShared1 = false; + boolean bDedOneIstoOne1 = false; + boolean bDedOnePlusOne1 = false; + boolean bEnhanced1 = false; + + private final BgpLinkAttrProtectionType data = BgpLinkAttrProtectionType + .of(bExtraTraffic, bUnprotected, bShared, bDedOneIstoOne, + bDedOnePlusOne, bEnhanced); + private final BgpLinkAttrProtectionType sameAsData = BgpLinkAttrProtectionType + .of(bExtraTraffic, bUnprotected, bShared, bDedOneIstoOne, + bDedOnePlusOne, bEnhanced); + private final BgpLinkAttrProtectionType diffData = BgpLinkAttrProtectionType + .of(bExtraTraffic1, bUnprotected1, bShared1, bDedOneIstoOne1, + bDedOnePlusOne1, bEnhanced1); + + @Test + public void basics() { + + new EqualsTester().addEqualityGroup(data, sameAsData) + .addEqualityGroup(diffData).testEquals(); + } +}
\ No newline at end of file diff --git a/framework/src/onos/bgp/bgpio/src/test/java/org/onosproject/bgp/BgpPrefixAttrOspfFwdAddrTest.java b/framework/src/onos/bgp/bgpio/src/test/java/org/onosproject/bgp/BgpPrefixAttrOspfFwdAddrTest.java new file mode 100644 index 00000000..f736bead --- /dev/null +++ b/framework/src/onos/bgp/bgpio/src/test/java/org/onosproject/bgp/BgpPrefixAttrOspfFwdAddrTest.java @@ -0,0 +1,52 @@ +/* + * 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.bgp; + +import org.junit.Test; +import org.onlab.packet.Ip4Address; +import org.onlab.packet.Ip6Address; +import org.onosproject.bgpio.types.attr.BgpPrefixAttrOspfFwdAddr; + +import com.google.common.testing.EqualsTester; + +/** + * Test for BGP prefix metric attribute. + */ +public class BgpPrefixAttrOspfFwdAddrTest { + + private final short lsAttrLength = 4; + private final Ip4Address ip4RouterId = Ip4Address.valueOf("192.168.1.1"); + private final Ip6Address ip6RouterId = Ip6Address + .valueOf("2001:0db8:0a0b:12f0:0000:0000:0000:0001"); + + private final short lsAttrLength1 = 16; + private final Ip4Address ip4RouterId1 = Ip4Address.valueOf("192.168.1.2"); + private final Ip6Address ip6RouterId1 = Ip6Address + .valueOf("1002:0db8:0a0b:12f0:0000:0000:0000:0002"); + + private final BgpPrefixAttrOspfFwdAddr data = BgpPrefixAttrOspfFwdAddr + .of(lsAttrLength, ip4RouterId, ip6RouterId); + private final BgpPrefixAttrOspfFwdAddr sameAsData = BgpPrefixAttrOspfFwdAddr + .of(lsAttrLength, ip4RouterId, ip6RouterId); + private final BgpPrefixAttrOspfFwdAddr diffData = BgpPrefixAttrOspfFwdAddr + .of(lsAttrLength1, ip4RouterId1, ip6RouterId1); + + @Test + public void basics() { + new EqualsTester().addEqualityGroup(data, sameAsData) + .addEqualityGroup(diffData).testEquals(); + } +}
\ No newline at end of file diff --git a/framework/src/onos/bgp/bgpio/src/test/java/org/onosproject/bgp/NextHopTest.java b/framework/src/onos/bgp/bgpio/src/test/java/org/onosproject/bgp/NextHopTest.java new file mode 100755 index 00000000..109197bb --- /dev/null +++ b/framework/src/onos/bgp/bgpio/src/test/java/org/onosproject/bgp/NextHopTest.java @@ -0,0 +1,41 @@ +/* + * 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.bgp; + +import org.junit.Test; +import org.onlab.packet.Ip4Address; +import org.onosproject.bgpio.types.NextHop; + +import com.google.common.testing.EqualsTester; + +/** + * Test for NextHop BGP Path Attribute. + */ +public class NextHopTest { + private final Ip4Address value1 = Ip4Address.valueOf("12.12.12.12"); + private final Ip4Address value2 = Ip4Address.valueOf("12.12.12.13"); + private final NextHop attr1 = new NextHop(value1); + private final NextHop sameAsAttr1 = new NextHop(value1); + private final NextHop attr2 = new NextHop(value2); + + @Test + public void basics() { + new EqualsTester() + .addEqualityGroup(attr1, sameAsAttr1) + .addEqualityGroup(attr2) + .testEquals(); + } +}
\ No newline at end of file diff --git a/framework/src/onos/cli/src/main/java/org/onosproject/cli/Comparators.java b/framework/src/onos/cli/src/main/java/org/onosproject/cli/Comparators.java index 1df2f049..03d25cee 100644 --- a/framework/src/onos/cli/src/main/java/org/onosproject/cli/Comparators.java +++ b/framework/src/onos/cli/src/main/java/org/onosproject/cli/Comparators.java @@ -71,7 +71,10 @@ public final class Comparators { public static final Comparator<FlowRule> FLOW_RULE_COMPARATOR = new Comparator<FlowRule>() { @Override public int compare(FlowRule f1, FlowRule f2) { - return Long.valueOf(f1.id().value()).compareTo(f2.id().value()); + int tableCompare = Integer.valueOf(f1.tableId()).compareTo(f2.tableId()); + return (tableCompare == 0) + ? Long.valueOf(f1.id().value()).compareTo(f2.id().value()) + : tableCompare; } }; diff --git a/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/AddOpticalIntentCommand.java b/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/AddOpticalIntentCommand.java index 57c41009..1049d90d 100644 --- a/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/AddOpticalIntentCommand.java +++ b/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/AddOpticalIntentCommand.java @@ -44,12 +44,12 @@ public class AddOpticalIntentCommand extends ConnectivityIntentCommand { @Argument(index = 0, name = "ingressDevice", description = "Ingress Device/Port Description", required = true, multiValued = false) - String ingressDeviceString = null; + String ingressDeviceString = ""; @Argument(index = 1, name = "egressDevice", description = "Egress Device/Port Description", required = true, multiValued = false) - String egressDeviceString = null; + String egressDeviceString = ""; @Option(name = "-b", aliases = "--bidirectional", description = "If this argument is passed the optical link created will be bidirectional, " + @@ -65,7 +65,6 @@ public class AddOpticalIntentCommand extends ConnectivityIntentCommand { "Connect point must be in \"deviceUri/portNumber\" format"); DeviceId deviceId = DeviceId.deviceId(splitted[0]); - DeviceService deviceService = get(DeviceService.class); List<Port> ports = deviceService.getPorts(deviceId); @@ -87,7 +86,8 @@ public class AddOpticalIntentCommand extends ConnectivityIntentCommand { ConnectPoint egress = createConnectPoint(egressDeviceString); if (ingress == null || egress == null) { - print("Could not create optical intent"); + print("Invalid endpoint(s); could not create optical intent"); + return; } DeviceService deviceService = get(DeviceService.class); diff --git a/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/FlowsListCommand.java b/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/FlowsListCommand.java index de84f519..331cca17 100644 --- a/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/FlowsListCommand.java +++ b/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/FlowsListCommand.java @@ -123,8 +123,14 @@ public class FlowsListCommand extends AbstractShellCommand { if (state != null && !state.equals("any")) { s = FlowEntryState.valueOf(state.toUpperCase()); } - Iterable<Device> devices = uri == null ? deviceService.getDevices() : - Collections.singletonList(deviceService.getDevice(DeviceId.deviceId(uri))); + Iterable<Device> devices = null; + if (uri == null) { + devices = deviceService.getDevices(); + } else { + Device dev = deviceService.getDevice(DeviceId.deviceId(uri)); + devices = (dev == null) ? deviceService.getDevices() + : Collections.singletonList(dev); + } for (Device d : devices) { if (s == null) { rules = newArrayList(service.getFlowEntries(d.id())); diff --git a/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/GroupsListCommand.java b/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/GroupsListCommand.java index afbcab80..b10621de 100644 --- a/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/GroupsListCommand.java +++ b/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/GroupsListCommand.java @@ -46,7 +46,7 @@ import static com.google.common.collect.Lists.newArrayList; public class GroupsListCommand extends AbstractShellCommand { private static final String FORMAT = - " id=%s, state=%s, bytes=%s, packets=%s, appId=%s"; + " id=%s, state=%s, type=%s, bytes=%s, packets=%s, appId=%s"; private static final String BUCKET_FORMAT = " id=%s, bucket=%s, bytes=%s, packets=%s, actions=%s"; @@ -121,7 +121,7 @@ public class GroupsListCommand extends AbstractShellCommand { private void printGroups(DeviceId deviceId, List<Group> groups) { print("deviceId=%s", deviceId); for (Group group : groups) { - print(FORMAT, group.id().id(), group.state(), + print(FORMAT, group.id().id(), group.state(), group.type(), group.bytes(), group.packets(), group.appId().name()); int i = 0; for (GroupBucket bucket:group.buckets().buckets()) { diff --git a/framework/src/onos/cli/src/main/resources/OSGI-INF/blueprint/shell-config.xml b/framework/src/onos/cli/src/main/resources/OSGI-INF/blueprint/shell-config.xml index cf76febe..9bd5dd9f 100644 --- a/framework/src/onos/cli/src/main/resources/OSGI-INF/blueprint/shell-config.xml +++ b/framework/src/onos/cli/src/main/resources/OSGI-INF/blueprint/shell-config.xml @@ -19,7 +19,6 @@ <command> <action class="org.onosproject.cli.SummaryCommand"/> </command> - <command> <action class="org.onosproject.cli.security.ReviewCommand"/> <completers> diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/cluster/ClusterAdminService.java b/framework/src/onos/core/api/src/main/java/org/onosproject/cluster/ClusterAdminService.java index 5f2b5fff..47944874 100644 --- a/framework/src/onos/core/api/src/main/java/org/onosproject/cluster/ClusterAdminService.java +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/cluster/ClusterAdminService.java @@ -30,9 +30,8 @@ public interface ClusterAdminService { * instance. * * @param nodes set of nodes that form the cluster - * @param ipPrefix IP address prefix, e.g. 10.0.1.* */ - void formCluster(Set<ControllerNode> nodes, String ipPrefix); + void formCluster(Set<ControllerNode> nodes); /** * Adds a new controller node to the cluster. diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/cluster/ClusterDefinitionService.java b/framework/src/onos/core/api/src/main/java/org/onosproject/cluster/ClusterDefinitionService.java deleted file mode 100644 index 1ee78b15..00000000 --- a/framework/src/onos/core/api/src/main/java/org/onosproject/cluster/ClusterDefinitionService.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * 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.cluster; - -import java.util.Set; - -/** - * Service for obtaining the static definition of a controller cluster. - */ -public interface ClusterDefinitionService { - - /** - * Returns the local controller node. - * @return local controller node - */ - ControllerNode localNode(); - - /** - * Returns the set of seed nodes that should be used for discovering other members - * of the cluster. - * @return set of seed controller nodes - */ - Set<ControllerNode> seedNodes(); - - /** - * Forms cluster configuration based on the specified set of node - * information. Assumes subsequent restart for the new configuration to - * take hold. - * - * @param nodes set of nodes that form the cluster - * @param ipPrefix IP address prefix, e.g. 10.0.1.* - */ - void formCluster(Set<ControllerNode> nodes, String ipPrefix); -}
\ No newline at end of file diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/cluster/ClusterMetadata.java b/framework/src/onos/core/api/src/main/java/org/onosproject/cluster/ClusterMetadata.java new file mode 100644 index 00000000..e1eacfee --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/cluster/ClusterMetadata.java @@ -0,0 +1,185 @@ +/* + * 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.cluster; + +import java.util.Arrays; +import java.util.Collection; +import java.util.Set; +import java.util.stream.Collectors; + +import static com.google.common.base.Preconditions.checkNotNull; +import static com.google.common.base.Verify.verifyNotNull; +import static com.google.common.base.Verify.verify; + +import com.google.common.base.MoreObjects; +import com.google.common.collect.Collections2; +import com.google.common.collect.ImmutableSet; +import com.google.common.collect.Sets; + +/** + * Cluster metadata. + * <p> + * Metadata specifies the attributes that define a ONOS cluster and comprises the collection + * of {@link org.onosproject.cluster.ControllerNode nodes} and the collection of data + * {@link org.onosproject.cluster.Partition partitions}. + */ +public final class ClusterMetadata { + + private String name; + private Set<ControllerNode> nodes; + private Set<Partition> partitions; + + /** + * Returns a new cluster metadata builder. + * @return The cluster metadata builder. + */ + public static Builder builder() { + return new Builder(); + } + + /** + * Returns the name of the cluster. + * + * @return cluster name + */ + public String getName() { + return this.name; + } + + /** + * Returns the collection of {@link org.onosproject.cluster.ControllerNode nodes} that make up the cluster. + * @return cluster nodes + */ + public Collection<ControllerNode> getNodes() { + return this.nodes; + } + + /** + * Returns the collection of data {@link org.onosproject.cluster.Partition partitions} that make up the cluster. + * @return collection of partitions. + */ + public Collection<Partition> getPartitions() { + return this.partitions; + } + + @Override + public String toString() { + return MoreObjects.toStringHelper(ClusterMetadata.class) + .add("name", name) + .add("nodes", nodes) + .add("partitions", partitions) + .toString(); + } + + @Override + public int hashCode() { + return Arrays.deepHashCode(new Object[] {name, nodes, partitions}); + } + + /* + * Provide a deep quality check of the meta data (non-Javadoc) + * + * @see java.lang.Object#equals(java.lang.Object) + */ + @Override + public boolean equals(Object object) { + + if (!ClusterMetadata.class.isInstance(object)) { + return false; + } + ClusterMetadata that = (ClusterMetadata) object; + + if (!this.name.equals(that.name) || this.nodes.size() != that.nodes.size() + || this.partitions.size() != that.partitions.size()) { + return false; + } + + return Sets.symmetricDifference(this.nodes, that.nodes).isEmpty() + && Sets.symmetricDifference(this.partitions, that.partitions).isEmpty(); + } + + /** + * Builder for a {@link ClusterMetadata} instance. + */ + public static class Builder { + + private final ClusterMetadata metadata; + + public Builder() { + metadata = new ClusterMetadata(); + } + + /** + * Sets the cluster name, returning the cluster metadata builder for method chaining. + * @param name cluster name + * @return this cluster metadata builder + */ + public Builder withName(String name) { + metadata.name = checkNotNull(name); + return this; + } + + /** + * Sets the collection of cluster nodes, returning the cluster metadata builder for method chaining. + * @param controllerNodes collection of cluster nodes + * @return this cluster metadata builder + */ + public Builder withControllerNodes(Collection<ControllerNode> controllerNodes) { + metadata.nodes = ImmutableSet.copyOf(checkNotNull(controllerNodes)); + return this; + } + + /** + * Sets the collection of data partitions, returning the cluster metadata builder for method chaining. + * @param partitions collection of partitions + * @return this cluster metadata builder + */ + public Builder withPartitions(Collection<Partition> partitions) { + metadata.partitions = ImmutableSet.copyOf(checkNotNull(partitions)); + return this; + } + + /** + * Builds the cluster metadata. + * @return cluster metadata + * @throws com.google.common.base.VerifyException VerifyException if the metadata is misconfigured + */ + public ClusterMetadata build() { + verifyMetadata(); + return metadata; + } + + /** + * Validates the constructed metadata for semantic correctness. + * @throws VerifyException if the metadata is misconfigured. + */ + private void verifyMetadata() { + verifyNotNull(metadata.getName(), "Cluster name must be specified"); + verifyNotNull(metadata.getNodes(), "Cluster nodes must be specified"); + verifyNotNull(metadata.getPartitions(), "Cluster partitions must be specified"); + verify(!metadata.getNodes().isEmpty(), "Cluster nodes must not be empty"); + verify(!metadata.getPartitions().isEmpty(), "Cluster nodes must not be empty"); + + // verify that partitions are constituted from valid cluster nodes. + boolean validPartitions = Collections2.transform(metadata.getNodes(), ControllerNode::id) + .containsAll(metadata.getPartitions() + .stream() + .flatMap(r -> r.getMembers().stream()) + .collect(Collectors.toSet())); + verify(validPartitions, "Partition locations must be valid cluster nodes"); + } + } +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/cluster/ClusterMetadataEvent.java b/framework/src/onos/core/api/src/main/java/org/onosproject/cluster/ClusterMetadataEvent.java new file mode 100644 index 00000000..a0f461c4 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/cluster/ClusterMetadataEvent.java @@ -0,0 +1,56 @@ +/* + * 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.cluster; + +import org.onosproject.event.AbstractEvent; + +/** + * Describes a cluster metadata event. + */ +public class ClusterMetadataEvent extends AbstractEvent<ClusterMetadataEvent.Type, ClusterMetadata> { + + /** + * Type of cluster metadata events. + */ + public enum Type { + /** + * Signifies that the cluster metadata has changed. + */ + METADATA_CHANGED, + } + + /** + * Creates an event of a given type and for the specified metadata and the + * current time. + * + * @param type cluster metadata event type + * @param metadata cluster metadata subject + */ + public ClusterMetadataEvent(Type type, ClusterMetadata metadata) { + super(type, metadata); + } + + /** + * Creates an event of a given type and for the specified metadata and time. + * + * @param type cluster metadata event type + * @param metadata cluster metadata subject + * @param time occurrence time + */ + public ClusterMetadataEvent(Type type, ClusterMetadata metadata, long time) { + super(type, metadata, time); + } +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/cluster/ClusterMetadataEventListener.java b/framework/src/onos/core/api/src/main/java/org/onosproject/cluster/ClusterMetadataEventListener.java new file mode 100644 index 00000000..fdfaeed0 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/cluster/ClusterMetadataEventListener.java @@ -0,0 +1,24 @@ +/* + * 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.cluster; + +import org.onosproject.event.EventListener; + +/** + * Entity capable of receiving cluster metadata related events. + */ +public interface ClusterMetadataEventListener extends EventListener<ClusterMetadataEvent> { +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/cluster/ClusterMetadataService.java b/framework/src/onos/core/api/src/main/java/org/onosproject/cluster/ClusterMetadataService.java new file mode 100644 index 00000000..25a6df63 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/cluster/ClusterMetadataService.java @@ -0,0 +1,40 @@ +/* + * 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.cluster; + +/** + * Service for obtaining metadata information about the cluster. + */ +public interface ClusterMetadataService { + + /** + * Returns the current cluster metadata. + * @return cluster metadata + */ + ClusterMetadata getClusterMetadata(); + + /** + * Updates the cluster metadata. + * @param metadata new metadata + */ + void setClusterMetadata(ClusterMetadata metadata); + + /** + * Returns the local controller node representing this instance. + * @return local controller node + */ + ControllerNode getLocalNode(); +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/cluster/ClusterMetadataStore.java b/framework/src/onos/core/api/src/main/java/org/onosproject/cluster/ClusterMetadataStore.java new file mode 100644 index 00000000..7e83b5b5 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/cluster/ClusterMetadataStore.java @@ -0,0 +1,77 @@ +/* + * 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.cluster; + +import java.util.Collection; + +import org.onosproject.store.Store; +import org.onosproject.store.service.Versioned; + +/** + * Manages persistence of cluster metadata; not intended for direct use. + */ +public interface ClusterMetadataStore extends Store<ClusterMetadataEvent, ClusterMetadataStoreDelegate> { + + /** + * Returns the cluster metadata. + * <p> + * The returned metadata is versioned to aid determining if a metadata instance is more recent than another. + * @return cluster metadata + */ + Versioned<ClusterMetadata> getClusterMetadata(); + + /** + * Updates the cluster metadata. + * @param metadata new metadata value + */ + void setClusterMetadata(ClusterMetadata metadata); + + // TODO: The below methods should move to a separate store interface that is responsible for + // tracking cluster partition operational state. + + /** + * Sets a controller node as an active member of a partition. + * <p> + * Active members are those replicas that are up to speed with the rest of the system and are + * usually capable of participating in the replica state management activities in accordance with + * the data consistency and replication protocol in use. + * @param partitionId partition identifier + * @param nodeId id of controller node + */ + void setActiveReplica(String partitionId, NodeId nodeId); + + /** + * Removes a controller node as an active member for a partition. + * <p> + * Active members are those replicas that are up to speed with the rest of the system and are + * usually capable of participating in the replica state management activities in accordance with + * the data consistency and replication protocol in use. + * @param partitionId partition identifier + * @param nodeId id of controller node + */ + void unsetActiveReplica(String partitionId, NodeId nodeId); + + /** + * Returns the collection of controller nodes that are the active replicas for a partition. + * <p> + * Active members are those replicas that are up to speed with the rest of the system and are + * usually capable of participating in the replica state management activities in accordance with + * the data consistency and replication protocol in use. + * @param partitionId partition identifier + * @return identifiers of controller nodes that are the active replicas + */ + Collection<NodeId> getActiveReplicas(String partitionId); +}
\ No newline at end of file diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/cluster/ClusterMetadataStoreDelegate.java b/framework/src/onos/core/api/src/main/java/org/onosproject/cluster/ClusterMetadataStoreDelegate.java new file mode 100644 index 00000000..b56b7a24 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/cluster/ClusterMetadataStoreDelegate.java @@ -0,0 +1,24 @@ +/* + * 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.cluster; + +import org.onosproject.store.StoreDelegate; + +/** + * Cluster metadata store delegate abstraction. + */ +public interface ClusterMetadataStoreDelegate extends StoreDelegate<ClusterMetadataEvent> { +}
\ No newline at end of file diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/cluster/NodeId.java b/framework/src/onos/core/api/src/main/java/org/onosproject/cluster/NodeId.java index 68b490f2..6cfb42c7 100644 --- a/framework/src/onos/core/api/src/main/java/org/onosproject/cluster/NodeId.java +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/cluster/NodeId.java @@ -20,7 +20,7 @@ import java.util.Objects; /** * Controller cluster identity. */ -public class NodeId { +public class NodeId implements Comparable<NodeId> { private final String id; @@ -55,4 +55,9 @@ public class NodeId { return id; } + @Override + public int compareTo(NodeId that) { + return this.id.compareTo(that.id); + } + } diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/cluster/Partition.java b/framework/src/onos/core/api/src/main/java/org/onosproject/cluster/Partition.java new file mode 100644 index 00000000..1eca4aeb --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/cluster/Partition.java @@ -0,0 +1,91 @@ +/* + * 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.cluster; + +import java.util.Arrays; +import java.util.Collection; +import java.util.Set; + +import com.google.common.collect.ImmutableSet; +import com.google.common.collect.Sets; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * A data partition. + * <p> + * Partition represents a slice of the data space and is made up of a collection + * of {@link org.onosproject.cluster.ControllerNode nodes} + * that all maintain copies of this data. + */ +public class Partition { + + private final String name; + private final Set<NodeId> members; + + private Partition() { + name = null; + members = null; + } + + public Partition(String name, Collection<NodeId> members) { + this.name = checkNotNull(name); + this.members = ImmutableSet.copyOf(checkNotNull(members)); + } + + /** + * Returns the partition name. + * <p> + * Each partition is identified by a unique name. + * @return partition name + */ + public String getName() { + return this.name; + } + + /** + * Returns the collection of controller node identifiers that make up this partition. + * @return collection of controller node identifiers + */ + public Collection<NodeId> getMembers() { + return this.members; + } + + @Override + public int hashCode() { + return Arrays.deepHashCode(new Object[] {name, members}); + } + + @Override + public boolean equals(Object other) { + if (this == other) { + return true; + } + + if (other == null || !Partition.class.isInstance(other)) { + return false; + } + + Partition that = (Partition) other; + + if (!this.name.equals(that.name) || (this.members == null && that.members != null) + || (this.members != null && that.members == null) || this.members.size() != that.members.size()) { + return false; + } + + return Sets.symmetricDifference(this.members, that.members).isEmpty(); + } +}
\ No newline at end of file diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/behaviour/BridgeConfig.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/behaviour/BridgeConfig.java index 7f157e95..e3d6993c 100644 --- a/framework/src/onos/core/api/src/main/java/org/onosproject/net/behaviour/BridgeConfig.java +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/behaviour/BridgeConfig.java @@ -36,6 +36,17 @@ public interface BridgeConfig extends HandlerBehaviour { void addBridge(BridgeName bridgeName); /** + * Adds a bridge with given bridge name and dpid, and sets the controller + * of the bridge with given controllers. + * + * @param bridgeName bridge name + * @param dpid dpid + * @param controllers list of controller + * @return true if succeeds, fail otherwise + */ + boolean addBridge(BridgeName bridgeName, String dpid, List<ControllerInfo> controllers); + + /** * Remove a bridge. * * @param bridgeName bridge name diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/behaviour/ExtensionResolver.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/behaviour/ExtensionResolver.java new file mode 100644 index 00000000..54cbc7ac --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/behaviour/ExtensionResolver.java @@ -0,0 +1,40 @@ +/* + * 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.net.behaviour; + +import com.google.common.annotations.Beta; +import org.onosproject.net.driver.HandlerBehaviour; +import org.onosproject.net.flow.instructions.ExtensionInstruction; +import org.onosproject.net.flow.instructions.ExtensionType; + +/** + * Provides access to the extension implemented by this driver. + */ +@Beta +public interface ExtensionResolver extends HandlerBehaviour { + + /** + * Gets an extension instruction instance of the specified type, if supported + * by the driver. + * + * @param type type of extension to get + * @return extension instruction + * @throws UnsupportedOperationException if the extension type is not + * supported by this driver + */ + ExtensionInstruction getExtensionInstruction(ExtensionType type); +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/behaviour/TunnelConfig.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/behaviour/TunnelConfig.java index 7e79a57e..e3b4c198 100644 --- a/framework/src/onos/core/api/src/main/java/org/onosproject/net/behaviour/TunnelConfig.java +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/behaviour/TunnelConfig.java @@ -32,6 +32,15 @@ public interface TunnelConfig extends HandlerBehaviour { void createTunnel(TunnelDescription tunnel); /** + * Creates a tunnel interface on a given bridge of this device. + * + * @param bridgeName bridge name + * @param tunnel tunnel description + * @return true if succeeds, false otherwise + */ + boolean createTunnelInterface(BridgeName bridgeName, TunnelDescription tunnel); + + /** * Removes a tunnel on this device. * * @param tunnel tunnel descriptor diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/DefaultTrafficSelector.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/DefaultTrafficSelector.java index 4416456c..453a7648 100644 --- a/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/DefaultTrafficSelector.java +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/DefaultTrafficSelector.java @@ -15,8 +15,14 @@ */ package org.onosproject.net.flow; -import com.google.common.base.MoreObjects; -import com.google.common.collect.ImmutableSet; +import java.util.Collections; +import java.util.Comparator; +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; +import java.util.Set; +import java.util.TreeSet; + import org.onlab.packet.Ip6Address; import org.onlab.packet.IpPrefix; import org.onlab.packet.MacAddress; @@ -27,13 +33,8 @@ import org.onosproject.net.PortNumber; import org.onosproject.net.flow.criteria.Criteria; import org.onosproject.net.flow.criteria.Criterion; -import java.util.Collections; -import java.util.Comparator; -import java.util.HashMap; -import java.util.Map; -import java.util.Objects; -import java.util.Set; -import java.util.TreeSet; +import com.google.common.base.MoreObjects; +import com.google.common.collect.ImmutableSet; /** * Default traffic selector implementation. diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/DefaultTrafficTreatment.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/DefaultTrafficTreatment.java index 6174cef6..6beeecc9 100644 --- a/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/DefaultTrafficTreatment.java +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/DefaultTrafficTreatment.java @@ -15,9 +15,11 @@ */ package org.onosproject.net.flow; -import com.google.common.base.MoreObjects; -import com.google.common.collect.ImmutableList; -import com.google.common.collect.Lists; +import static com.google.common.base.Preconditions.checkNotNull; + +import java.util.List; +import java.util.Objects; + import org.onlab.packet.EthType; import org.onlab.packet.IpAddress; import org.onlab.packet.MacAddress; @@ -25,16 +27,17 @@ import org.onlab.packet.MplsLabel; import org.onlab.packet.TpPort; import org.onlab.packet.VlanId; import org.onosproject.core.GroupId; +import org.onosproject.net.DeviceId; import org.onosproject.net.IndexedLambda; import org.onosproject.net.PortNumber; +import org.onosproject.net.flow.instructions.ExtensionInstruction; import org.onosproject.net.flow.instructions.Instruction; import org.onosproject.net.flow.instructions.Instructions; import org.onosproject.net.meter.MeterId; -import java.util.List; -import java.util.Objects; - -import static com.google.common.base.Preconditions.checkNotNull; +import com.google.common.base.MoreObjects; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.Lists; /** * Default traffic treatment implementation. @@ -239,9 +242,11 @@ public final class DefaultTrafficTreatment implements TrafficTreatment { case GROUP: case QUEUE: case L0MODIFICATION: + case L1MODIFICATION: case L2MODIFICATION: case L3MODIFICATION: case L4MODIFICATION: + case EXTENSION: current.add(instruction); break; case TABLE: @@ -479,6 +484,12 @@ public final class DefaultTrafficTreatment implements TrafficTreatment { } @Override + public TrafficTreatment.Builder extension(ExtensionInstruction extension, + DeviceId deviceId) { + return add(Instructions.extension(extension, deviceId)); + } + + @Override public TrafficTreatment build() { if (deferred.size() == 0 && immediate.size() == 0 && table == null && !clear) { diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/TrafficTreatment.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/TrafficTreatment.java index c7fe8b85..b14ab99c 100644 --- a/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/TrafficTreatment.java +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/TrafficTreatment.java @@ -15,6 +15,8 @@ */ package org.onosproject.net.flow; +import java.util.List; + import org.onlab.packet.EthType; import org.onlab.packet.IpAddress; import org.onlab.packet.MacAddress; @@ -22,13 +24,13 @@ import org.onlab.packet.MplsLabel; import org.onlab.packet.TpPort; import org.onlab.packet.VlanId; import org.onosproject.core.GroupId; +import org.onosproject.net.DeviceId; import org.onosproject.net.PortNumber; +import org.onosproject.net.flow.instructions.ExtensionInstruction; import org.onosproject.net.flow.instructions.Instruction; import org.onosproject.net.flow.instructions.Instructions; import org.onosproject.net.meter.MeterId; -import java.util.List; - /** * Abstraction of network traffic treatment. */ @@ -413,6 +415,15 @@ public interface TrafficTreatment { Builder setUdpDst(TpPort port); /** + * Uses an extension treatment. + * + * @param extension extension treatment + * @param deviceId device ID + * @return a treatment builder + */ + Builder extension(ExtensionInstruction extension, DeviceId deviceId); + + /** * Builds an immutable traffic treatment descriptor. * <p> * If the treatment is empty when build() is called, it will add a default diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/instructions/AbstractExtensionInstruction.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/instructions/AbstractExtensionInstruction.java new file mode 100644 index 00000000..9f22f888 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/instructions/AbstractExtensionInstruction.java @@ -0,0 +1,71 @@ +/* + * 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.net.flow.instructions; + +import java.lang.reflect.Field; +import java.util.ArrayList; +import java.util.List; + +/** + * Abstract implementation of the set/get property methods of ExtensionInstruction. + */ +public abstract class AbstractExtensionInstruction implements ExtensionInstruction { + + private static final String INVALID_KEY = "Invalid property key: "; + private static final String INVALID_TYPE = "Given type does not match field type: "; + + @Override + public <T> void setPropertyValue(String key, T value) throws ExtensionPropertyException { + Class<?> clazz = this.getClass(); + try { + Field field = clazz.getDeclaredField(key); + field.setAccessible(true); + field.set(this, value); + } catch (NoSuchFieldException | IllegalAccessException e) { + throw new ExtensionPropertyException(INVALID_KEY + key); + } + } + + @Override + public <T> T getPropertyValue(String key) throws ExtensionPropertyException { + Class<?> clazz = this.getClass(); + try { + Field field = clazz.getDeclaredField(key); + field.setAccessible(true); + @SuppressWarnings("unchecked") + T result = (T) field.get(this); + return result; + } catch (NoSuchFieldException | IllegalAccessException e) { + throw new ExtensionPropertyException(INVALID_KEY + key); + } catch (ClassCastException e) { + throw new ExtensionPropertyException(INVALID_TYPE + key); + } + } + + @Override + public List<String> getProperties() { + Class<?> clazz = this.getClass(); + + List<String> fields = new ArrayList<>(); + + for (Field field : clazz.getDeclaredFields()) { + fields.add(field.getName()); + } + + return fields; + } +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/instructions/ExtensionInstruction.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/instructions/ExtensionInstruction.java new file mode 100644 index 00000000..89e0cc5e --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/instructions/ExtensionInstruction.java @@ -0,0 +1,78 @@ +/* + * 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.net.flow.instructions; + +import java.util.List; + +/** + * An extensible instruction type. + */ +public interface ExtensionInstruction { + + /** + * Gets the type of the extension instruction. + * + * @return type + */ + ExtensionType type(); + + /** + * Sets a property on the extension instruction. + * + * @param key property key + * @param value value to set for the given key + * @param <T> class of the value + * @throws ExtensionPropertyException if the given key is not a valid + * property on this extension instruction + */ + <T> void setPropertyValue(String key, T value) throws ExtensionPropertyException; + + /** + * Gets a property value of an extension instruction. + * + * @param key property key + * @param <T> class of the value + * @return value of the property + * @throws ExtensionPropertyException if the given key is not a valid + * property on this extension instruction + */ + <T> T getPropertyValue(String key) throws ExtensionPropertyException; + + /** + * Gets a list of all properties on the extension instruction. + * + * @return list of properties + */ + List<String> getProperties(); + + /** + * Serialize the extension instruction to a byte array. + * + * @return byte array + */ + byte[] serialize(); + + /** + * Deserialize the extension instruction from a byte array. The properties + * of this object will be overwritten with the data in the byte array. + * + * @param data input byte array + */ + void deserialize(byte[] data); + + +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/Treatment.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/instructions/ExtensionPropertyException.java index a77079ce..5750d09e 100644 --- a/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/Treatment.java +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/instructions/ExtensionPropertyException.java @@ -1,5 +1,5 @@ /* - * Copyright 2014 Open Networking Laboratory + * 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. @@ -13,24 +13,20 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.onosproject.net.flow; -import org.onosproject.net.PortNumber; +package org.onosproject.net.flow.instructions; /** - * Abstraction of different kinds of treatment that can be applied to an - * outbound packet. + * Exception indicating there was an error while setting/getting an extension + * instruction property. */ -public interface Treatment { +public class ExtensionPropertyException extends Exception { - // TODO: implement these later: modifications, group - // TODO: elsewhere provide factory methods for some default treatments - - /** - * Returns the port number where the packet should be emitted. - * - * @return output port number - */ - PortNumber output(); + public ExtensionPropertyException(String message) { + super(message); + } + public ExtensionPropertyException(String message, Throwable cause) { + super(message, cause); + } } diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/instructions/ExtensionType.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/instructions/ExtensionType.java new file mode 100644 index 00000000..747a85b5 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/instructions/ExtensionType.java @@ -0,0 +1,92 @@ +/* + * 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.net.flow.instructions; + +import com.google.common.annotations.Beta; +import com.google.common.base.MoreObjects; + +import java.util.Objects; + +/** + * Type of extension instructions. + */ +@Beta +public final class ExtensionType { + + /** + * A list of well-known named extension instruction type codes. + */ + public enum ExtensionTypes { + // TODO fix type numbers to include experimenter id + NICIRA_SET_TUNNEL_DST(31); + + private ExtensionType type; + + /** + * Creates a new named extension instruction type. + * + * @param type type code + */ + ExtensionTypes(int type) { + this.type = new ExtensionType(type); + } + + /** + * Gets the extension type object for this named type code. + * + * @return extension type object + */ + public ExtensionType type() { + return type; + } + } + + private final int type; + + /** + * Creates an extension type with the given int type code. + * + * @param type type code + */ + public ExtensionType(int type) { + this.type = type; + } + + @Override + public int hashCode() { + return Objects.hash(type); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof ExtensionType) { + final ExtensionType that = (ExtensionType) obj; + return this.type == that.type; + } + return false; + } + + @Override + public String toString() { + return MoreObjects.toStringHelper(ExtensionType.class) + .add("type", type) + .toString(); + } +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/instructions/Instruction.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/instructions/Instruction.java index 2f6a1cc1..31ad80c5 100644 --- a/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/instructions/Instruction.java +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/instructions/Instruction.java @@ -92,7 +92,12 @@ public interface Instruction { /** * Signifies that the traffic should be modified in L4 way. */ - L4MODIFICATION + L4MODIFICATION, + + /** + * Signifies that an extension instruction will be used. + */ + EXTENSION } /** diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/instructions/Instructions.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/instructions/Instructions.java index 8868bf7c..aad407c8 100644 --- a/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/instructions/Instructions.java +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/instructions/Instructions.java @@ -22,6 +22,7 @@ import org.onlab.packet.MplsLabel; import org.onlab.packet.TpPort; import org.onlab.packet.VlanId; import org.onosproject.core.GroupId; +import org.onosproject.net.DeviceId; import org.onosproject.net.IndexedLambda; import org.onosproject.net.Lambda; import org.onosproject.net.OchSignal; @@ -480,6 +481,20 @@ public final class Instructions { } /** + * Creates an extension instruction. + * + * @param extension extension instruction + * @param deviceId device ID + * @return extension instruction + */ + public static ExtensionInstructionWrapper extension(ExtensionInstruction extension, + DeviceId deviceId) { + checkNotNull(extension, "Extension instruction cannot be null"); + checkNotNull(deviceId, "Device ID cannot be null"); + return new ExtensionInstructionWrapper(extension, deviceId); + } + + /** * Drop instruction. */ @Deprecated @@ -820,6 +835,59 @@ public final class Instructions { } } + /** + * Extension instruction. + */ + public static class ExtensionInstructionWrapper implements Instruction { + private final ExtensionInstruction extensionInstruction; + private final DeviceId deviceId; + + ExtensionInstructionWrapper(ExtensionInstruction extension, DeviceId deviceId) { + extensionInstruction = extension; + this.deviceId = deviceId; + } + + public ExtensionInstruction extensionInstruction() { + return extensionInstruction; + } + + public DeviceId deviceId() { + return deviceId; + } + + @Override + public Type type() { + return Type.EXTENSION; + } + + @Override + public String toString() { + return toStringHelper(type().toString()) + .add("extension", extensionInstruction) + .add("deviceId", deviceId) + .toString(); + } + + @Override + public int hashCode() { + return Objects.hash(type().ordinal(), extensionInstruction, deviceId); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof ExtensionInstructionWrapper) { + ExtensionInstructionWrapper that = (ExtensionInstructionWrapper) obj; + return Objects.equals(extensionInstruction, that.extensionInstruction) + && Objects.equals(deviceId, that.deviceId); + + } + return false; + } + } + } diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/flowobjective/DefaultFilteringObjective.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flowobjective/DefaultFilteringObjective.java index 7b5924fb..06305bf7 100644 --- a/framework/src/onos/core/api/src/main/java/org/onosproject/net/flowobjective/DefaultFilteringObjective.java +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flowobjective/DefaultFilteringObjective.java @@ -18,6 +18,7 @@ package org.onosproject.net.flowobjective; import com.google.common.annotations.Beta; import com.google.common.collect.ImmutableList; import org.onosproject.core.ApplicationId; +import org.onosproject.net.flow.TrafficTreatment; import org.onosproject.net.flow.criteria.Criteria; import org.onosproject.net.flow.criteria.Criterion; @@ -46,6 +47,7 @@ public final class DefaultFilteringObjective implements FilteringObjective { private final int id; private final Operation op; private final Optional<ObjectiveContext> context; + private final TrafficTreatment meta; private DefaultFilteringObjective(Builder builder) { this.key = builder.key; @@ -57,6 +59,7 @@ public final class DefaultFilteringObjective implements FilteringObjective { this.conditions = builder.conditions; this.op = builder.op; this.context = Optional.ofNullable(builder.context); + this.meta = builder.meta; this.id = Objects.hash(type, key, conditions, permanent, timeout, appId, priority); @@ -83,6 +86,12 @@ public final class DefaultFilteringObjective implements FilteringObjective { } @Override + public TrafficTreatment meta() { + return meta; + } + + + @Override public int priority() { return priority; } @@ -135,6 +144,7 @@ public final class DefaultFilteringObjective implements FilteringObjective { private List<Criterion> conditions; private Operation op; private ObjectiveContext context; + private TrafficTreatment meta; @Override public Builder withKey(Criterion key) { @@ -186,6 +196,12 @@ public final class DefaultFilteringObjective implements FilteringObjective { } @Override + public Builder setMeta(TrafficTreatment treatment) { + this.meta = treatment; + return this; + } + + @Override public FilteringObjective add() { conditions = listBuilder.build(); op = Operation.ADD; diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/flowobjective/FilteringObjective.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flowobjective/FilteringObjective.java index 58304571..29257c61 100644 --- a/framework/src/onos/core/api/src/main/java/org/onosproject/net/flowobjective/FilteringObjective.java +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flowobjective/FilteringObjective.java @@ -17,49 +17,54 @@ package org.onosproject.net.flowobjective; import com.google.common.annotations.Beta; import org.onosproject.core.ApplicationId; +import org.onosproject.net.flow.TrafficTreatment; import org.onosproject.net.flow.criteria.Criterion; import java.util.Collection; /** * Represents a filtering flow objective. Each filtering flow objective - * is made up of a key (criterion) to a set of criteria. Using this information - * a pipeline aware driver will decide how this objective should be mapped - * to the specific device pipeline. For example, consider the following - * filtering objective: - * - * portX -> {MAC1, IP1, MAC2} - * - * The driver could decide to pass L3 packet to the L3 table and L2 packets to - * the L2 table for packets arriving on portX. - * - * Filtering objectives do not only represent what should be permitted into the - * pipeline but can also be used to deny or drop unwanted packets by specifying - * the appropriate type of filtering objective. It is also important to note - * that submitting a filtering objective does not necessarily result in rules - * programmed at the switch, the driver is free to decide when these rules are - * programmed. For example, a filtering rule may only be programmed once a - * corresponding forwarding objective has been received. + * is made up of a key (typically a PortCriterion) mapped to a set of criteria. + * Using this information, a pipeline aware driver will decide how this objective + * should be mapped to the device specific pipeline-tables in order to satisfy the + * filtering condition. For example, consider the following PERMIT filtering + * objective: + * <p> + * portX -> {MAC1, VLAN1} + * <p> + * The driver could decide to pass packets to the MAC table or VLAN or PORT + * tables to ensure that only those packets arriving with the correct dst MAC + * and VLAN ids from Port X are allowed into the pipeline. + * <p> + * Filtering objectives of type PERMIT allow packets that match the key:criteria + * to enter the pipeline. As a result, the implication is that packets that don't + * match are automatically denied (dropped). + * <p> + * Filtering objectives of type DENY, are used to deny packets that would + * otherwise be permitted and forwarded through the pipeline (ie. those packets + * that make it through the PERMIT filters). */ @Beta public interface FilteringObjective extends Objective { enum Type { /** - * Enables the filtering condition. + * Permits packets that match the filtering condition to be processed + * by the rest of the pipeline. Automatically denies packets that don't + * match the criteria. */ PERMIT, /** - * Disables the filtering condition. + * Denies packets that make it through the permit filters. */ DENY } /** - * Obtain the key for this filter. + * Obtain the key for this filter. The filter may or may not require a key. * - * @return a criterion + * @return a criterion, which could be null if no key was provided. */ Criterion key(); @@ -78,6 +83,16 @@ public interface FilteringObjective extends Objective { Collection<Criterion> conditions(); /** + * Auxiliary optional information provided to the device-driver.Typically + * conveys information about changes (treatments) to packets that are + * permitted into the pipeline by the PERMIT filtering condition. + * + * @return a treatment on the packets that make it through the PERMIT filters. + * Value may be null if no meta information is provided. + */ + TrafficTreatment meta(); + + /** * Builder of Filtering objective entities. */ interface Builder extends Objective.Builder { @@ -113,11 +128,20 @@ public interface FilteringObjective extends Objective { Builder deny(); /** + * Set meta information about this filtering condition set. + * + * @param treatment traffic treatment to use + * @return a filtering builder + */ + Builder setMeta(TrafficTreatment treatment); + + /** * Assigns an application id. * * @param appId an application id * @return a filtering builder */ + @Override Builder fromApp(ApplicationId appId); /** diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/group/DefaultGroupBucket.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/group/DefaultGroupBucket.java index 6efd3e79..9d942ee4 100644 --- a/framework/src/onos/core/api/src/main/java/org/onosproject/net/group/DefaultGroupBucket.java +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/group/DefaultGroupBucket.java @@ -139,6 +139,20 @@ public final class DefaultGroupBucket implements GroupBucket, StoredGroupBucketE watchGroup); } + /** + * Creates all group bucket. + * + * @param treatment traffic treatment associated with group bucket + * @return all group bucket object + */ + public static GroupBucket createAllGroupBucket(TrafficTreatment treatment) { + return new DefaultGroupBucket(GroupDescription.Type.ALL, + treatment, + (short) -1, + null, + null); + } + @Override public GroupDescription.Type type() { return this.type; diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/intent/HostToHostIntent.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/intent/HostToHostIntent.java index bd4219ad..c1467241 100644 --- a/framework/src/onos/core/api/src/main/java/org/onosproject/net/intent/HostToHostIntent.java +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/intent/HostToHostIntent.java @@ -17,11 +17,15 @@ package org.onosproject.net.intent; import com.google.common.annotations.Beta; import com.google.common.base.MoreObjects; +import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableSet; + import org.onosproject.core.ApplicationId; import org.onosproject.net.HostId; +import org.onosproject.net.Link; import org.onosproject.net.flow.TrafficSelector; import org.onosproject.net.flow.TrafficTreatment; +import org.onosproject.net.intent.constraint.LinkTypeConstraint; import java.util.List; @@ -33,6 +37,8 @@ import static com.google.common.base.Preconditions.checkNotNull; @Beta public final class HostToHostIntent extends ConnectivityIntent { + static final LinkTypeConstraint NOT_OPTICAL = new LinkTypeConstraint(false, Link.Type.OPTICAL); + private final HostId one; private final HostId two; @@ -115,6 +121,15 @@ public final class HostToHostIntent extends ConnectivityIntent { */ public HostToHostIntent build() { + List<Constraint> theConstraints = constraints; + // If not-OPTICAL constraint hasn't been specified, add them + if (!constraints.contains(NOT_OPTICAL)) { + theConstraints = ImmutableList.<Constraint>builder() + .add(NOT_OPTICAL) + .addAll(constraints) + .build(); + } + return new HostToHostIntent( appId, key, @@ -122,7 +137,7 @@ public final class HostToHostIntent extends ConnectivityIntent { two, selector, treatment, - constraints, + theConstraints, priority ); } diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/intent/Key.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/intent/Key.java index 18baafc8..0344acbf 100644 --- a/framework/src/onos/core/api/src/main/java/org/onosproject/net/intent/Key.java +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/intent/Key.java @@ -28,7 +28,7 @@ import java.util.Objects; */ // TODO maybe pull this up to utils @Beta -public abstract class Key { +public abstract class Key implements Comparable<Key> { //TODO consider making this a HashCode object (worry about performance) private final long hash; @@ -117,6 +117,12 @@ public abstract class Key { Objects.equals(this.appId, other.appId) && Objects.equals(this.key, other.key); } + + @Override + public int compareTo(Key o) { + StringKey sk = (StringKey) o; + return this.key.compareTo(sk.key); + } } private static final class LongKey extends Key { @@ -157,6 +163,13 @@ public abstract class Key { this.key == other.key && Objects.equals(this.appId, other.appId); } + + @Override + public int compareTo(Key o) { + Long myKey = key; + Long otherKey = ((LongKey) o).key; + return myKey.compareTo(otherKey); + } } } diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/intent/constraint/BandwidthConstraint.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/intent/constraint/BandwidthConstraint.java index 43b8e4b1..20ccb55d 100644 --- a/framework/src/onos/core/api/src/main/java/org/onosproject/net/intent/constraint/BandwidthConstraint.java +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/intent/constraint/BandwidthConstraint.java @@ -16,6 +16,8 @@ package org.onosproject.net.intent.constraint; import com.google.common.annotations.Beta; + +import org.onlab.util.DataRateUnit; import org.onosproject.net.Link; import org.onosproject.net.resource.link.BandwidthResource; import org.onosproject.net.resource.link.BandwidthResourceRequest; @@ -32,7 +34,7 @@ import static com.google.common.base.Preconditions.checkNotNull; * Constraint that evaluates links based on available bandwidths. */ @Beta -public class BandwidthConstraint extends BooleanConstraint { +public final class BandwidthConstraint extends BooleanConstraint { private final BandwidthResource bandwidth; @@ -45,6 +47,17 @@ public class BandwidthConstraint extends BooleanConstraint { this.bandwidth = checkNotNull(bandwidth, "Bandwidth cannot be null"); } + /** + * Creates a new bandwidth constraint. + * + * @param v required amount of bandwidth + * @param unit {@link DataRateUnit} of {@code v} + * @return {@link BandwidthConstraint} instance with given bandwidth requirement + */ + public static BandwidthConstraint of(double v, DataRateUnit unit) { + return new BandwidthConstraint(BandwidthResource.of(v, unit)); + } + // Constructor for serialization private BandwidthConstraint() { this.bandwidth = null; diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/newresource/ResourceService.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/newresource/ResourceService.java index 82d84743..ad684c8c 100644 --- a/framework/src/onos/core/api/src/main/java/org/onosproject/net/newresource/ResourceService.java +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/newresource/ResourceService.java @@ -153,6 +153,14 @@ public interface ResourceService { Collection<ResourceAllocation> getResourceAllocations(ResourceConsumer consumer); /** + * Returns resource paths that point available child resources under the specified resource path. + * + * @param parent parent resource path + * @return available resource paths under the specified resource path + */ + Collection<ResourcePath> getAvailableResources(ResourcePath parent); + + /** * Returns the availability of the specified resource. * * @param resource resource to check the availability diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/newresource/ResourceStore.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/newresource/ResourceStore.java index 5a034b4d..2cab9d4b 100644 --- a/framework/src/onos/core/api/src/main/java/org/onosproject/net/newresource/ResourceStore.java +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/newresource/ResourceStore.java @@ -92,6 +92,14 @@ public interface ResourceStore { Collection<ResourcePath> getResources(ResourceConsumer consumer); /** + * Returns a collection of the child resources of the specified parent. + * + * @param parent parent of the resource to be returned + * @return a collection of the child resources of the specified resource + */ + Collection<ResourcePath> getChildResources(ResourcePath parent); + + /** * Returns a collection of the resources which are children of the specified parent and * whose type is the specified class. * diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/resource/link/BandwidthResource.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/resource/link/BandwidthResource.java index fe21e042..0bfb3795 100644 --- a/framework/src/onos/core/api/src/main/java/org/onosproject/net/resource/link/BandwidthResource.java +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/resource/link/BandwidthResource.java @@ -16,7 +16,7 @@ package org.onosproject.net.resource.link; import org.onlab.util.Bandwidth; - +import org.onlab.util.DataRateUnit; import java.util.Objects; import static com.google.common.base.Preconditions.checkNotNull; @@ -43,6 +43,17 @@ public final class BandwidthResource implements LinkResource { } /** + * Creates a new bandwidth resource. + * + * @param v amount of bandwidth to request + * @param unit {@link DataRateUnit} of {@code v} + * @return {@link BandwidthResource} instance with given bandwidth + */ + public static BandwidthResource of(double v, DataRateUnit unit) { + return new BandwidthResource(Bandwidth.of(v, unit)); + } + + /** * Returns bandwidth as a double value. * * @return bandwidth as a double value diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/resource/link/DefaultLinkResourceRequest.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/resource/link/DefaultLinkResourceRequest.java index 5153aebf..f8e143a4 100644 --- a/framework/src/onos/core/api/src/main/java/org/onosproject/net/resource/link/DefaultLinkResourceRequest.java +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/resource/link/DefaultLinkResourceRequest.java @@ -16,48 +16,47 @@ package org.onosproject.net.resource.link; import java.util.Collection; +import java.util.HashMap; import java.util.HashSet; +import java.util.Map; import java.util.Set; import java.util.Objects; +import java.util.stream.Collectors; +import com.google.common.annotations.Beta; +import com.google.common.collect.ImmutableMap; import org.onlab.util.Bandwidth; import org.onosproject.net.Link; import org.onosproject.net.intent.Constraint; import org.onosproject.net.intent.IntentId; -import com.google.common.collect.ImmutableSet; - import org.onosproject.net.intent.constraint.BandwidthConstraint; import org.onosproject.net.intent.constraint.LambdaConstraint; import org.onosproject.net.resource.ResourceRequest; import org.onosproject.net.resource.ResourceType; +import static com.google.common.base.Preconditions.checkNotNull; + /** * Implementation of {@link LinkResourceRequest}. */ public final class DefaultLinkResourceRequest implements LinkResourceRequest { private final IntentId intentId; - private final Collection<Link> links; - private final Set<ResourceRequest> resources; + protected final Map<Link, Set<ResourceRequest>> requests; /** - * Creates a new link resource request with the given ID, links, and - * resource requests. + * Creates a new link resource request with the specified Intent ID, + * and resource requests over links. * - * @param intentId intent ID related to this request - * @param links a set of links for the request - * @param resources a set of resources to be requested + * @param intentId intent ID associated with this request + * @param requests resource requests over links */ - private DefaultLinkResourceRequest(IntentId intentId, - Collection<Link> links, - Set<ResourceRequest> resources) { - this.intentId = intentId; - this.links = ImmutableSet.copyOf(links); - this.resources = ImmutableSet.copyOf(resources); + private DefaultLinkResourceRequest(IntentId intentId, Map<Link, Set<ResourceRequest>> requests) { + this.intentId = checkNotNull(intentId); + this.requests = checkNotNull(ImmutableMap.copyOf(requests)); } - @Override public ResourceType type() { return null; @@ -70,12 +69,19 @@ public final class DefaultLinkResourceRequest implements LinkResourceRequest { @Override public Collection<Link> links() { - return links; + return requests.keySet(); } @Override public Set<ResourceRequest> resources() { - return resources; + return requests.values().stream() + .flatMap(Collection::stream) + .collect(Collectors.toSet()); + } + + @Override + public Set<ResourceRequest> resources(Link link) { + return requests.get(link); } /** @@ -95,8 +101,7 @@ public final class DefaultLinkResourceRequest implements LinkResourceRequest { */ public static final class Builder implements LinkResourceRequest.Builder { private IntentId intentId; - private Collection<Link> links; - private Set<ResourceRequest> resources; + private Map<Link, Set<ResourceRequest>> requests; /** * Creates a new link resource request. @@ -106,18 +111,33 @@ public final class DefaultLinkResourceRequest implements LinkResourceRequest { */ private Builder(IntentId intentId, Collection<Link> links) { this.intentId = intentId; - this.links = links; - this.resources = new HashSet<>(); + this.requests = new HashMap<>(); + for (Link link : links) { + requests.put(link, new HashSet<>()); + } } /** * Adds lambda request. * * @return self + * @deprecated in Emu Release */ + @Deprecated @Override public Builder addLambdaRequest() { - resources.add(new LambdaResourceRequest()); + for (Link link : requests.keySet()) { + requests.get(link).add(new LambdaResourceRequest()); + } + return this; + } + + @Beta + @Override + public LinkResourceRequest.Builder addLambdaRequest(LambdaResource lambda) { + for (Link link : requests.keySet()) { + requests.get(link).add(new LambdaResourceRequest(lambda)); + } return this; } @@ -125,10 +145,36 @@ public final class DefaultLinkResourceRequest implements LinkResourceRequest { * Adds Mpls request. * * @return self + * @deprecated in Emu Release */ + @Deprecated @Override public Builder addMplsRequest() { - resources.add(new MplsLabelResourceRequest()); + for (Link link : requests.keySet()) { + requests.get(link).add(new MplsLabelResourceRequest()); + } + return this; + } + + @Beta + @Override + public Builder addMplsRequest(MplsLabel label) { + for (Link link : requests.keySet()) { + requests.get(link).add(new MplsLabelResourceRequest(label)); + } + return this; + } + + @Beta + @Override + public LinkResourceRequest.Builder addMplsRequest(Map<Link, MplsLabel> labels) { + for (Link link : labels.keySet()) { + if (!requests.containsKey(link)) { + requests.put(link, new HashSet<>()); + } + requests.get(link).add(new MplsLabelResourceRequest(labels.get(link))); + } + return this; } @@ -140,7 +186,9 @@ public final class DefaultLinkResourceRequest implements LinkResourceRequest { */ @Override public Builder addBandwidthRequest(double bandwidth) { - resources.add(new BandwidthResourceRequest(new BandwidthResource(Bandwidth.bps(bandwidth)))); + for (Link link : requests.keySet()) { + requests.get(link).add(new BandwidthResourceRequest(new BandwidthResource(Bandwidth.bps(bandwidth)))); + } return this; } @@ -162,13 +210,13 @@ public final class DefaultLinkResourceRequest implements LinkResourceRequest { */ @Override public LinkResourceRequest build() { - return new DefaultLinkResourceRequest(intentId, links, resources); + return new DefaultLinkResourceRequest(intentId, requests); } } @Override public int hashCode() { - return Objects.hash(intentId, links); + return Objects.hash(intentId, links()); } @Override @@ -181,6 +229,6 @@ public final class DefaultLinkResourceRequest implements LinkResourceRequest { } final DefaultLinkResourceRequest other = (DefaultLinkResourceRequest) obj; return Objects.equals(this.intentId, other.intentId) - && Objects.equals(this.links, other.links); + && Objects.equals(this.links(), other.links()); } } diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/resource/link/LambdaResourceRequest.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/resource/link/LambdaResourceRequest.java index b0391f5a..d264d5e5 100644 --- a/framework/src/onos/core/api/src/main/java/org/onosproject/net/resource/link/LambdaResourceRequest.java +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/resource/link/LambdaResourceRequest.java @@ -15,15 +15,50 @@ */ package org.onosproject.net.resource.link; +import com.google.common.annotations.Beta; import com.google.common.base.MoreObjects; import org.onosproject.net.resource.ResourceRequest; import org.onosproject.net.resource.ResourceType; +import static com.google.common.base.Preconditions.checkNotNull; + /** * Representation of a request for lambda resource. */ public class LambdaResourceRequest implements ResourceRequest { + private final LambdaResource lambda; + + /** + * Constructs a request specifying the given lambda. + * + * @param lambda lambda to be requested + */ + @Beta + public LambdaResourceRequest(LambdaResource lambda) { + this.lambda = checkNotNull(lambda); + } + + /** + * Constructs a request asking an arbitrary available lambda. + * + * @deprecated in Emu Release + */ + @Deprecated + public LambdaResourceRequest() { + this.lambda = null; + } + + /** + * Returns the lambda this request expects. + * + * @return the lambda this request expects + */ + @Beta + public LambdaResource lambda() { + return lambda; + } + @Override public ResourceType type() { return ResourceType.LAMBDA; @@ -32,6 +67,7 @@ public class LambdaResourceRequest implements ResourceRequest { @Override public String toString() { return MoreObjects.toStringHelper(this) + .add("lambda", lambda) .toString(); } } diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/resource/link/LinkResourceRequest.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/resource/link/LinkResourceRequest.java index 8023a92e..37622e79 100644 --- a/framework/src/onos/core/api/src/main/java/org/onosproject/net/resource/link/LinkResourceRequest.java +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/resource/link/LinkResourceRequest.java @@ -16,8 +16,10 @@ package org.onosproject.net.resource.link; import java.util.Collection; +import java.util.Map; import java.util.Set; +import com.google.common.annotations.Beta; import org.onosproject.net.Link; import org.onosproject.net.intent.Constraint; import org.onosproject.net.intent.IntentId; @@ -50,22 +52,62 @@ public interface LinkResourceRequest extends ResourceRequest { Set<ResourceRequest> resources(); /** + * Returns the set of resource request against the specified link. + * + * @param link link whose associated resource request is to be returned + * @return set of resource request against the specified link + */ + @Beta + Set<ResourceRequest> resources(Link link); + + /** * Builder of link resource request. */ interface Builder { - /** + /** * Adds lambda request. * * @return self + * @deprecated in Emu Release */ + @Deprecated Builder addLambdaRequest(); /** - * Adds MPLS request. - * - * @return self - */ - Builder addMplsRequest(); + * Adds lambda request. + * + * @param lambda lambda to be requested + * @return self + */ + @Beta + Builder addLambdaRequest(LambdaResource lambda); + + /** + * Adds MPLS request. + * + * @return self + * @deprecated in Emu Release + */ + @Deprecated + Builder addMplsRequest(); + + /** + * Adds MPLS request. + * + * @param label MPLS label to be requested + * @return self + */ + @Beta + Builder addMplsRequest(MplsLabel label); + + /** + * Adds MPLS request against the specified links. + * + * @param labels MPLS labels to be requested against links + * @return self + */ + @Beta + Builder addMplsRequest(Map<Link, MplsLabel> labels); /** * Adds bandwidth request with bandwidth value. diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/resource/link/LinkResourceService.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/resource/link/LinkResourceService.java index 6dc04dfc..71ea7e1a 100644 --- a/framework/src/onos/core/api/src/main/java/org/onosproject/net/resource/link/LinkResourceService.java +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/resource/link/LinkResourceService.java @@ -22,7 +22,10 @@ import org.onosproject.net.resource.ResourceRequest; /** * Service for providing link resource allocation. + * + * @deprecated in Emu Release */ +@Deprecated public interface LinkResourceService extends ListenerService<LinkResourceEvent, LinkResourceListener> { @@ -31,14 +34,18 @@ public interface LinkResourceService * * @param req resources to be allocated * @return allocated resources + * @deprecated in Emu Release */ + @Deprecated LinkResourceAllocations requestResources(LinkResourceRequest req); /** * Releases resources. * * @param allocations resources to be released + * @deprecated in Emu Release */ + @Deprecated void releaseResources(LinkResourceAllocations allocations); /** @@ -47,7 +54,9 @@ public interface LinkResourceService * @param req updated resource request * @param oldAllocations old resource allocations * @return new resource allocations + * @deprecated in Emu Release */ + @Deprecated LinkResourceAllocations updateResources(LinkResourceRequest req, LinkResourceAllocations oldAllocations); @@ -55,7 +64,9 @@ public interface LinkResourceService * Returns all allocated resources. * * @return allocated resources + * @deprecated in Emu Release */ + @Deprecated Iterable<LinkResourceAllocations> getAllocations(); /** @@ -63,7 +74,9 @@ public interface LinkResourceService * * @param link a target link * @return allocated resources + * @deprecated in Emu Release */ + @Deprecated Iterable<LinkResourceAllocations> getAllocations(Link link); /** @@ -71,7 +84,9 @@ public interface LinkResourceService * * @param intentId the target Intent's id * @return allocated resources for Intent + * @deprecated in Emu Release */ + @Deprecated LinkResourceAllocations getAllocations(IntentId intentId); /** @@ -79,7 +94,9 @@ public interface LinkResourceService * * @param link a target link * @return available resources for the target link + * @deprecated in Emu Release */ + @Deprecated Iterable<ResourceRequest> getAvailableResources(Link link); /** @@ -88,7 +105,9 @@ public interface LinkResourceService * @param link a target link * @param allocations allocations to be included as available * @return available resources for the target link + * @deprecated in Emu Release */ + @Deprecated Iterable<ResourceRequest> getAvailableResources(Link link, LinkResourceAllocations allocations); diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/resource/link/MplsLabelResourceRequest.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/resource/link/MplsLabelResourceRequest.java index 0a03f450..01a048b7 100644 --- a/framework/src/onos/core/api/src/main/java/org/onosproject/net/resource/link/MplsLabelResourceRequest.java +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/resource/link/MplsLabelResourceRequest.java @@ -15,15 +15,50 @@ */ package org.onosproject.net.resource.link; +import com.google.common.annotations.Beta; import com.google.common.base.MoreObjects; import org.onosproject.net.resource.ResourceRequest; import org.onosproject.net.resource.ResourceType; +import static com.google.common.base.Preconditions.checkNotNull; + /** * Representation of a request for lambda resource. */ public class MplsLabelResourceRequest implements ResourceRequest { + private final MplsLabel mplsLabel; + + /** + * Constructs a request specifying the given MPLS label. + * + * @param mplsLabel MPLS label to be requested + */ + @Beta + public MplsLabelResourceRequest(MplsLabel mplsLabel) { + this.mplsLabel = checkNotNull(mplsLabel); + } + + /** + * Constructs a request asking an arbitrary available MPLS label. + * + * @deprecated in Emu Release + */ + @Deprecated + public MplsLabelResourceRequest() { + this.mplsLabel = null; + } + + /** + * Returns the MPLS label this request expects. + * + * @return the MPLS label this request expects + */ + @Beta + public MplsLabel mplsLabel() { + return mplsLabel; + } + @Override public ResourceType type() { return ResourceType.MPLS_LABEL; @@ -32,6 +67,7 @@ public class MplsLabelResourceRequest implements ResourceRequest { @Override public String toString() { return MoreObjects.toStringHelper(this) + .add("mplsLabel", mplsLabel) .toString(); } } diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/persistence/PersistenceService.java b/framework/src/onos/core/api/src/main/java/org/onosproject/persistence/PersistenceService.java new file mode 100644 index 00000000..09065dec --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/persistence/PersistenceService.java @@ -0,0 +1,40 @@ +/* + * 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.persistence; + +/** + * Service that allows for the creation of local disk backed map for instance specific values that persist across + * restarts. Empty maps and sets are deleted on shutdown. + */ +public interface PersistenceService { + /** + * A builder for the creation of local persistent maps backed by disk. + * + * @param <K> the type of keys in this map + * @param <V> the type of values in this map + * @return a persistent map builder + */ + <K, V> PersistentMapBuilder<K, V> persistentMapBuilder(); + + /** + * A builder for the creation of local persistent sets backed by disk. + * + * @param <E> the type of the elements + * @return a persistent set builder + */ + <E> PersistentSetBuilder<E> persistentSetBuilder(); +}
\ No newline at end of file diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/persistence/PersistentMapBuilder.java b/framework/src/onos/core/api/src/main/java/org/onosproject/persistence/PersistentMapBuilder.java new file mode 100644 index 00000000..c3c855e1 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/persistence/PersistentMapBuilder.java @@ -0,0 +1,49 @@ +/* + * 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.persistence; + + +import org.onosproject.store.service.Serializer; + +import java.util.Map; + +/** + * The interface for a persistent map builder for use with mapDB. + */ +public interface PersistentMapBuilder<K, V> { + + /** + * Sets the name of this map. + * @param name the string name of this map + * @return a persistent map builder with the name option now set + */ + PersistentMapBuilder<K, V> withName(String name); + + /** + * Sets the key serializer to be used to serialize this map, this is a required parameter. + * @param serializer the serializer to be used for keys + * @return a persistent map builder with the key serializer set + */ + PersistentMapBuilder<K, V> withSerializer(Serializer serializer); + + /** + * Validates the map settings and then builds this map in the database. Throws an exception if invalid settings + * are found. + * @return The map that was created + */ + Map<K, V> build(); +}
\ No newline at end of file diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/persistence/PersistentSetBuilder.java b/framework/src/onos/core/api/src/main/java/org/onosproject/persistence/PersistentSetBuilder.java new file mode 100644 index 00000000..851872cf --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/persistence/PersistentSetBuilder.java @@ -0,0 +1,48 @@ +/* + * 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.persistence; + +import org.onosproject.store.service.Serializer; + +import java.util.Set; + +/** + * The default interface for the persistent set builder for use with mapDB. + */ +public interface PersistentSetBuilder<E> { + + /** + * Sets the name of this set. + * @param name the string name of this set + * @return a persistent set builder with the name option now set + */ + PersistentSetBuilder<E> withName(String name); + + /** + * Sets the serializer to be used to serialize this set, this is a required parameter. + * @param serializer the serializer to be used + * @return a persistent set builder with the serializer set + */ + PersistentSetBuilder<E> withSerializer(Serializer serializer); + + /** + * Validates the set settings and then builds this map in the database. Throws an exception if invalid settings + * are found. + * @return The set that was created + */ + Set<E> build(); +}
\ No newline at end of file diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/persistence/package-info.java b/framework/src/onos/core/api/src/main/java/org/onosproject/persistence/package-info.java new file mode 100644 index 00000000..6e11a5e1 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/persistence/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. + */ + +/** + * Persistence service and builders. + */ +package org.onosproject.persistence; diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/store/service/TransactionContext.java b/framework/src/onos/core/api/src/main/java/org/onosproject/store/service/TransactionContext.java index 94942e20..ef972536 100644 --- a/framework/src/onos/core/api/src/main/java/org/onosproject/store/service/TransactionContext.java +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/store/service/TransactionContext.java @@ -56,9 +56,9 @@ public interface TransactionContext { * Commits a transaction that was previously started thereby making its changes permanent * and externally visible. * - * @throws TransactionException if transaction fails to commit + * @return true if this transaction succeeded, otherwise false. */ - void commit(); + boolean commit(); /** * Aborts any changes made in this transaction context and discarding all locally cached updates. diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/ui/UiTopoOverlay.java b/framework/src/onos/core/api/src/main/java/org/onosproject/ui/UiTopoOverlay.java index e0d7d239..88796de7 100644 --- a/framework/src/onos/core/api/src/main/java/org/onosproject/ui/UiTopoOverlay.java +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/ui/UiTopoOverlay.java @@ -16,6 +16,8 @@ package org.onosproject.ui; +import org.onosproject.net.DeviceId; +import org.onosproject.net.HostId; import org.onosproject.ui.topo.PropertyPanel; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -105,8 +107,9 @@ public class UiTopoOverlay { * This default implementation does nothing. * * @param pp property panel model of summary data + * @param deviceId device id */ - public void modifyDeviceDetails(PropertyPanel pp) { + public void modifyDeviceDetails(PropertyPanel pp, DeviceId deviceId) { } /** @@ -115,7 +118,8 @@ public class UiTopoOverlay { * This default implementation does nothing. * * @param pp property panel model of summary data + * @param hostId host id */ - public void modifyHostDetails(PropertyPanel pp) { + public void modifyHostDetails(PropertyPanel pp, HostId hostId) { } } diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/ui/table/cell/AppIdFormatter.java b/framework/src/onos/core/api/src/main/java/org/onosproject/ui/table/cell/AppIdFormatter.java index 0e1c248b..f7947a75 100644 --- a/framework/src/onos/core/api/src/main/java/org/onosproject/ui/table/cell/AppIdFormatter.java +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/ui/table/cell/AppIdFormatter.java @@ -27,6 +27,7 @@ public final class AppIdFormatter extends AbstractCellFormatter { // non-instantiable private AppIdFormatter() { } + // NOTE: do not change this format; we parse it on the client side. @Override protected String nonNullFormat(Object value) { ApplicationId appId = (ApplicationId) value; diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/ui/topo/NodeBadge.java b/framework/src/onos/core/api/src/main/java/org/onosproject/ui/topo/NodeBadge.java index 7b517111..4edb6712 100644 --- a/framework/src/onos/core/api/src/main/java/org/onosproject/ui/topo/NodeBadge.java +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/ui/topo/NodeBadge.java @@ -40,7 +40,7 @@ public final class NodeBadge { return "{" + code + "}"; } - /** Returns the status code in string form. */ + /* Returns the status code in string form. */ public String code() { return code; } diff --git a/framework/src/onos/core/api/src/test/java/org/onosproject/net/intent/HostToHostIntentTest.java b/framework/src/onos/core/api/src/test/java/org/onosproject/net/intent/HostToHostIntentTest.java index 3f7650e4..c3a95473 100644 --- a/framework/src/onos/core/api/src/test/java/org/onosproject/net/intent/HostToHostIntentTest.java +++ b/framework/src/onos/core/api/src/test/java/org/onosproject/net/intent/HostToHostIntentTest.java @@ -16,15 +16,18 @@ package org.onosproject.net.intent; import org.junit.Test; +import org.onlab.util.DataRateUnit; import org.onosproject.TestApplicationId; import org.onosproject.core.ApplicationId; import org.onosproject.net.HostId; import org.onosproject.net.flow.TrafficSelector; - +import org.onosproject.net.intent.constraint.BandwidthConstraint; +import com.google.common.collect.ImmutableList; import com.google.common.testing.EqualsTester; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.hasItem; import static org.hamcrest.Matchers.is; import static org.onlab.junit.ImmutableClassChecker.assertThatClassIsImmutable; import static org.onosproject.net.NetTestTools.hid; @@ -102,6 +105,55 @@ public class HostToHostIntentTest extends IntentTest { .testEquals(); } + @Test + public void testImplicitConstraintsAreAdded() { + final Constraint other = BandwidthConstraint.of(1, DataRateUnit.GBPS); + final HostToHostIntent intent = HostToHostIntent.builder() + .appId(APPID) + .one(id1) + .two(id2) + .selector(selector) + .treatment(treatment) + .constraints(ImmutableList.of(other)) + .build(); + + assertThat(intent.constraints(), hasItem(HostToHostIntent.NOT_OPTICAL)); + } + + @Test + public void testImplicitConstraints() { + final HostToHostIntent implicit = HostToHostIntent.builder() + .appId(APPID) + .one(id1) + .two(id2) + .selector(selector) + .treatment(treatment) + .build(); + final HostToHostIntent empty = HostToHostIntent.builder() + .appId(APPID) + .one(id1) + .two(id2) + .selector(selector) + .treatment(treatment) + .constraints(ImmutableList.of()) + .build(); + final HostToHostIntent exact = HostToHostIntent.builder() + .appId(APPID) + .one(id1) + .two(id2) + .selector(selector) + .treatment(treatment) + .constraints(ImmutableList.of(HostToHostIntent.NOT_OPTICAL)) + .build(); + + new EqualsTester() + .addEqualityGroup(implicit.constraints(), + empty.constraints(), + exact.constraints()) + .testEquals(); + + } + @Override protected Intent createOne() { return HostToHostIntent.builder() diff --git a/framework/src/onos/core/api/src/test/java/org/onosproject/net/packet/DefaultPacketRequestTest.java b/framework/src/onos/core/api/src/test/java/org/onosproject/net/packet/DefaultPacketRequestTest.java new file mode 100644 index 00000000..592cd983 --- /dev/null +++ b/framework/src/onos/core/api/src/test/java/org/onosproject/net/packet/DefaultPacketRequestTest.java @@ -0,0 +1,93 @@ +/* + * 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.net.packet; + +import org.junit.Test; +import org.onosproject.core.DefaultApplicationId; +import org.onosproject.net.NetTestTools; +import org.onosproject.net.flow.DefaultTrafficSelector; +import org.onosproject.net.flow.TrafficSelector; + +import com.google.common.testing.EqualsTester; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.is; +import static org.onlab.junit.ImmutableClassChecker.assertThatClassIsImmutable; + +/** + * Unit tests for the DefaultPacketRequest class. + */ +public class DefaultPacketRequestTest { + + private final TrafficSelector selector = DefaultTrafficSelector + .builder() + .matchIcmpCode((byte) 1) + .build(); + + private final DefaultPacketRequest packetRequest1 = + new DefaultPacketRequest(DefaultTrafficSelector.emptySelector(), + PacketPriority.CONTROL, + NetTestTools.APP_ID); + private final DefaultPacketRequest sameAsacketRequest1 = + new DefaultPacketRequest(DefaultTrafficSelector.emptySelector(), + PacketPriority.CONTROL, + NetTestTools.APP_ID); + private final DefaultPacketRequest packetRequest2 = + new DefaultPacketRequest(selector, + PacketPriority.CONTROL, + NetTestTools.APP_ID); + private final DefaultPacketRequest packetRequest3 = + new DefaultPacketRequest(DefaultTrafficSelector.emptySelector(), + PacketPriority.REACTIVE, + NetTestTools.APP_ID); + private final DefaultPacketRequest packetRequest4 = + new DefaultPacketRequest(DefaultTrafficSelector.emptySelector(), + PacketPriority.CONTROL, + new DefaultApplicationId(1, "foo")); + + /** + * Tests the operation of the equals(), toAstring() and hashCode() methods. + */ + @Test + public void testEquals() { + new EqualsTester() + .addEqualityGroup(packetRequest1, sameAsacketRequest1) + .addEqualityGroup(packetRequest2) + .addEqualityGroup(packetRequest3) + .addEqualityGroup(packetRequest4) + .testEquals(); + } + + /** + * Tests that building and fetching from a DefaultPacketRequest is correct. + */ + @Test + public void testConstruction() { + assertThat(packetRequest1.priority(), is(PacketPriority.CONTROL)); + assertThat(packetRequest1.priority().priorityValue(), + is(PacketPriority.CONTROL.priorityValue())); + assertThat(packetRequest1.selector(), is(DefaultTrafficSelector.emptySelector())); + assertThat(packetRequest1.appId(), is(NetTestTools.APP_ID)); + } + + /** + * Checks that the DefaultPacketRequest class is immutable. + */ + @Test + public void testImmutability() { + assertThatClassIsImmutable(DefaultPacketRequest.class); + } +} diff --git a/framework/src/onos/core/api/src/test/java/org/onosproject/net/packet/PacketEventTest.java b/framework/src/onos/core/api/src/test/java/org/onosproject/net/packet/PacketEventTest.java new file mode 100644 index 00000000..f0d45f0c --- /dev/null +++ b/framework/src/onos/core/api/src/test/java/org/onosproject/net/packet/PacketEventTest.java @@ -0,0 +1,51 @@ +/* + * 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.net.packet; + +import org.junit.Test; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.greaterThanOrEqualTo; +import static org.hamcrest.Matchers.is; + +/** + * Unit tests for PacketEvent class. + */ +public class PacketEventTest { + + OutboundPacket packet; + + @Test + public void testConstruction1() { + long time = System.currentTimeMillis(); + PacketEvent event = new PacketEvent(PacketEvent.Type.EMIT, packet); + + assertThat(event.type(), is(PacketEvent.Type.EMIT)); + assertThat(event.subject(), is(packet)); + assertThat(event.time(), greaterThanOrEqualTo(time)); + } + + @Test + public void testConstruction2() { + long time = 12345678; + PacketEvent event = new PacketEvent(PacketEvent.Type.EMIT, packet, time); + + assertThat(event.type(), is(PacketEvent.Type.EMIT)); + assertThat(event.subject(), is(packet)); + assertThat(event.time(), is(time)); + } + +} diff --git a/framework/src/onos/core/api/src/test/java/org/onosproject/net/packet/PacketProcessorTest.java b/framework/src/onos/core/api/src/test/java/org/onosproject/net/packet/PacketProcessorTest.java new file mode 100644 index 00000000..7b2ef541 --- /dev/null +++ b/framework/src/onos/core/api/src/test/java/org/onosproject/net/packet/PacketProcessorTest.java @@ -0,0 +1,59 @@ +/* + * 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.net.packet; + +import org.junit.Test; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.greaterThanOrEqualTo; +import static org.hamcrest.Matchers.lessThan; + +/** + * Unit tests for static APIs in the packet processor class. + */ +public class PacketProcessorTest { + + /** + * Tests a priority in the advisor range. + */ + @Test + public void testAdvisorPriorities() { + int advisorPriority = PacketProcessor.advisor(3); + assertThat(advisorPriority, lessThan(PacketProcessor.ADVISOR_MAX)); + assertThat(advisorPriority, greaterThanOrEqualTo(0)); + } + + /** + * Tests a priority in the director range. + */ + @Test + public void testDirectorPriorities() { + int directorPriority = PacketProcessor.director(3); + assertThat(directorPriority, lessThan(PacketProcessor.DIRECTOR_MAX)); + assertThat(directorPriority, greaterThanOrEqualTo(PacketProcessor.ADVISOR_MAX)); + } + + /** + * Tests a priority in the observer range. + */ + @Test + public void testObserverPriorities() { + int observerPriority = PacketProcessor.observer(3); + assertThat(observerPriority, lessThan(PacketProcessor.OBSERVER_MAX)); + assertThat(observerPriority, greaterThanOrEqualTo(PacketProcessor.DIRECTOR_MAX)); + } + +} diff --git a/framework/src/onos/core/common/src/main/java/org/onosproject/codec/impl/DecodeCriterionCodecHelper.java b/framework/src/onos/core/common/src/main/java/org/onosproject/codec/impl/DecodeCriterionCodecHelper.java index 4e0f2bd9..69c5e791 100644 --- a/framework/src/onos/core/common/src/main/java/org/onosproject/codec/impl/DecodeCriterionCodecHelper.java +++ b/framework/src/onos/core/common/src/main/java/org/onosproject/codec/impl/DecodeCriterionCodecHelper.java @@ -15,6 +15,8 @@ */ package org.onosproject.codec.impl; +import static org.onlab.util.Tools.nullIsIllegal; + import java.util.HashMap; import java.util.Map; @@ -24,9 +26,13 @@ import org.onlab.packet.MacAddress; import org.onlab.packet.MplsLabel; import org.onlab.packet.TpPort; import org.onlab.packet.VlanId; +import org.onlab.util.HexString; import org.onosproject.net.ChannelSpacing; import org.onosproject.net.GridType; import org.onosproject.net.Lambda; +import org.onosproject.net.OchSignalType; +import org.onosproject.net.OduSignalId; +import org.onosproject.net.OduSignalType; import org.onosproject.net.PortNumber; import org.onosproject.net.flow.criteria.Criteria; import org.onosproject.net.flow.criteria.Criterion; @@ -34,8 +40,6 @@ import org.onosproject.net.flow.criteria.Criterion; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.node.ObjectNode; -import static org.onlab.util.Tools.nullIsIllegal; - /** * Decode portion of the criterion codec. */ @@ -95,6 +99,8 @@ public final class DecodeCriterionCodecHelper { decoderMap.put(Criterion.Type.OCH_SIGID.name(), new OchSigIdDecoder()); decoderMap.put(Criterion.Type.OCH_SIGTYPE.name(), new OchSigTypeDecoder()); decoderMap.put(Criterion.Type.TUNNEL_ID.name(), new TunnelIdDecoder()); + decoderMap.put(Criterion.Type.ODU_SIGID.name(), new OduSigIdDecoder()); + decoderMap.put(Criterion.Type.ODU_SIGTYPE.name(), new OduSigTypeDecoder()); } private class EthTypeDecoder implements CriterionDecoder { @@ -415,7 +421,9 @@ public final class DecodeCriterionCodecHelper { private class OchSigTypeDecoder implements CriterionDecoder { @Override public Criterion decodeCriterion(ObjectNode json) { - return null; + OchSignalType ochSignalType = OchSignalType.valueOf(nullIsIllegal(json.get(CriterionCodec.OCH_SIGNAL_TYPE), + CriterionCodec.OCH_SIGNAL_TYPE + MISSING_MEMBER_MESSAGE).asText()); + return Criteria.matchOchSignalType(ochSignalType); } } @@ -428,6 +436,34 @@ public final class DecodeCriterionCodecHelper { } } + private class OduSigIdDecoder implements CriterionDecoder { + @Override + public Criterion decodeCriterion(ObjectNode json) { + JsonNode oduSignalId = nullIsIllegal(json.get(CriterionCodec.ODU_SIGNAL_ID), + CriterionCodec.TRIBUTARY_PORT_NUMBER + MISSING_MEMBER_MESSAGE); + + int tributaryPortNumber = nullIsIllegal(oduSignalId.get(CriterionCodec.TRIBUTARY_PORT_NUMBER), + CriterionCodec.TRIBUTARY_PORT_NUMBER + MISSING_MEMBER_MESSAGE).asInt(); + int tributarySlotLen = nullIsIllegal(oduSignalId.get(CriterionCodec.TRIBUTARY_SLOT_LEN), + CriterionCodec.TRIBUTARY_SLOT_LEN + MISSING_MEMBER_MESSAGE).asInt(); + byte[] tributarySlotBitmap = HexString.fromHexString( + nullIsIllegal(oduSignalId.get(CriterionCodec.TRIBUTARY_SLOT_BITMAP), + CriterionCodec.TRIBUTARY_SLOT_BITMAP + MISSING_MEMBER_MESSAGE).asText()); + + return Criteria.matchOduSignalId( + OduSignalId.oduSignalId(tributaryPortNumber, tributarySlotLen, tributarySlotBitmap)); + } + } + + private class OduSigTypeDecoder implements CriterionDecoder { + @Override + public Criterion decodeCriterion(ObjectNode json) { + OduSignalType oduSignalType = OduSignalType.valueOf(nullIsIllegal(json.get(CriterionCodec.ODU_SIGNAL_TYPE), + CriterionCodec.ODU_SIGNAL_TYPE + MISSING_MEMBER_MESSAGE).asText()); + return Criteria.matchOduSignalType(oduSignalType); + } + } + /** * Decodes the JSON into a criterion object. * diff --git a/framework/src/onos/core/common/src/main/java/org/onosproject/codec/impl/DecodeInstructionCodecHelper.java b/framework/src/onos/core/common/src/main/java/org/onosproject/codec/impl/DecodeInstructionCodecHelper.java index 6a97a076..14555b3d 100644 --- a/framework/src/onos/core/common/src/main/java/org/onosproject/codec/impl/DecodeInstructionCodecHelper.java +++ b/framework/src/onos/core/common/src/main/java/org/onosproject/codec/impl/DecodeInstructionCodecHelper.java @@ -15,26 +15,29 @@ */ package org.onosproject.codec.impl; +import static org.onlab.util.Tools.nullIsIllegal; + import org.onlab.packet.IpAddress; import org.onlab.packet.MacAddress; import org.onlab.packet.MplsLabel; import org.onlab.packet.TpPort; import org.onlab.packet.VlanId; +import org.onlab.util.HexString; import org.onosproject.net.ChannelSpacing; import org.onosproject.net.GridType; import org.onosproject.net.Lambda; import org.onosproject.net.OchSignal; +import org.onosproject.net.OduSignalId; import org.onosproject.net.PortNumber; - -import com.fasterxml.jackson.databind.node.ObjectNode; 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.L1ModificationInstruction; import org.onosproject.net.flow.instructions.L2ModificationInstruction; import org.onosproject.net.flow.instructions.L3ModificationInstruction; import org.onosproject.net.flow.instructions.L4ModificationInstruction; -import static org.onlab.util.Tools.nullIsIllegal; +import com.fasterxml.jackson.databind.node.ObjectNode; /** * Decoding portion of the instruction codec. @@ -174,6 +177,30 @@ public final class DecodeInstructionCodecHelper { } /** + * Decodes a Layer 1 instruction. + * + * @return instruction object decoded from the JSON + * @throws IllegalArgumentException if the JSON is invalid + */ + private Instruction decodeL1() { + String subType = json.get(InstructionCodec.SUBTYPE).asText(); + if (subType.equals(L1ModificationInstruction.L1SubType.ODU_SIGID.name())) { + int tributaryPortNumber = nullIsIllegal(json.get(InstructionCodec.TRIBUTARY_PORT_NUMBER), + InstructionCodec.TRIBUTARY_PORT_NUMBER + InstructionCodec.MISSING_MEMBER_MESSAGE).asInt(); + int tributarySlotLen = nullIsIllegal(json.get(InstructionCodec.TRIBUTARY_SLOT_LEN), + InstructionCodec.TRIBUTARY_SLOT_LEN + InstructionCodec.MISSING_MEMBER_MESSAGE).asInt(); + byte[] tributarySlotBitmap = null; + tributarySlotBitmap = HexString.fromHexString( + nullIsIllegal(json.get(InstructionCodec.TRIBUTARY_SLOT_BITMAP), + InstructionCodec.TRIBUTARY_SLOT_BITMAP + InstructionCodec.MISSING_MEMBER_MESSAGE).asText()); + return Instructions.modL1OduSignalId(OduSignalId.oduSignalId(tributaryPortNumber, tributarySlotLen, + tributarySlotBitmap)); + } + throw new IllegalArgumentException("L1 Instruction subtype " + + subType + " is not supported"); + } + + /** * Decodes a Layer 4 instruction. * * @return instruction object decoded from the JSON @@ -221,6 +248,8 @@ public final class DecodeInstructionCodecHelper { return Instructions.createDrop(); } else if (type.equals(Instruction.Type.L0MODIFICATION.name())) { return decodeL0(); + } else if (type.equals(Instruction.Type.L1MODIFICATION.name())) { + return decodeL1(); } else if (type.equals(Instruction.Type.L2MODIFICATION.name())) { return decodeL2(); } else if (type.equals(Instruction.Type.L3MODIFICATION.name())) { diff --git a/framework/src/onos/core/common/src/main/java/org/onosproject/codec/impl/EncodeCriterionCodecHelper.java b/framework/src/onos/core/common/src/main/java/org/onosproject/codec/impl/EncodeCriterionCodecHelper.java index f7af736e..8fc6bbcf 100644 --- a/framework/src/onos/core/common/src/main/java/org/onosproject/codec/impl/EncodeCriterionCodecHelper.java +++ b/framework/src/onos/core/common/src/main/java/org/onosproject/codec/impl/EncodeCriterionCodecHelper.java @@ -17,8 +17,10 @@ package org.onosproject.codec.impl; import java.util.EnumMap; +import org.onlab.util.HexString; import org.onosproject.codec.CodecContext; import org.onosproject.net.OchSignal; +import org.onosproject.net.OduSignalId; import org.onosproject.net.flow.criteria.Criterion; import org.onosproject.net.flow.criteria.EthCriterion; import org.onosproject.net.flow.criteria.EthTypeCriterion; @@ -370,12 +372,18 @@ public final class EncodeCriterionCodecHelper { private static class FormatOduSignalId implements CriterionTypeFormatter { @Override public ObjectNode encodeCriterion(ObjectNode root, Criterion criterion) { - final OduSignalIdCriterion oduSignalIdCriterion = - (OduSignalIdCriterion) criterion; - return root.put(CriterionCodec.ODU_SIGNAL_ID, oduSignalIdCriterion.oduSignalId().toString()); + OduSignalId oduSignalId = ((OduSignalIdCriterion) criterion).oduSignalId(); + ObjectNode child = root.putObject(CriterionCodec.ODU_SIGNAL_ID); + + child.put(CriterionCodec.TRIBUTARY_PORT_NUMBER, oduSignalId.tributaryPortNumber()); + child.put(CriterionCodec.TRIBUTARY_SLOT_LEN, oduSignalId.tributarySlotLength()); + child.put(CriterionCodec.TRIBUTARY_SLOT_BITMAP, HexString.toHexString(oduSignalId.tributarySlotBitmap())); + + return root; } } + private static class FormatOduSignalType implements CriterionTypeFormatter { @Override public ObjectNode encodeCriterion(ObjectNode root, Criterion criterion) { diff --git a/framework/src/onos/core/common/src/main/java/org/onosproject/codec/impl/EncodeInstructionCodecHelper.java b/framework/src/onos/core/common/src/main/java/org/onosproject/codec/impl/EncodeInstructionCodecHelper.java index d12e4ad8..2ec301db 100644 --- a/framework/src/onos/core/common/src/main/java/org/onosproject/codec/impl/EncodeInstructionCodecHelper.java +++ b/framework/src/onos/core/common/src/main/java/org/onosproject/codec/impl/EncodeInstructionCodecHelper.java @@ -15,11 +15,14 @@ */ package org.onosproject.codec.impl; +import org.onlab.util.HexString; import org.onosproject.codec.CodecContext; import org.onosproject.net.OchSignal; +import org.onosproject.net.OduSignalId; 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.L1ModificationInstruction; import org.onosproject.net.flow.instructions.L2ModificationInstruction; import org.onosproject.net.flow.instructions.L3ModificationInstruction; import org.onosproject.net.flow.instructions.L4ModificationInstruction; @@ -81,6 +84,36 @@ public final class EncodeInstructionCodecHelper { } /** + * Encode an L1 modification instruction. + * + * @param result json node that the instruction attributes are added to + * @param instruction The L1 instruction + * @param context context of the request + */ + private void encodeL1(ObjectNode result) { + L1ModificationInstruction instruction = + (L1ModificationInstruction) this.instruction; + result.put(InstructionCodec.SUBTYPE, instruction.subtype().name()); + + switch (instruction.subtype()) { + case ODU_SIGID: + final L1ModificationInstruction.ModOduSignalIdInstruction oduSignalIdInstruction = + (L1ModificationInstruction.ModOduSignalIdInstruction) instruction; + OduSignalId oduSignalId = oduSignalIdInstruction.oduSignalId(); + + ObjectNode child = result.putObject("oduSignalId"); + + child.put(InstructionCodec.TRIBUTARY_PORT_NUMBER, oduSignalId.tributaryPortNumber()); + child.put(InstructionCodec.TRIBUTARY_SLOT_LEN, oduSignalId.tributarySlotLength()); + child.put(InstructionCodec.TRIBUTARY_SLOT_BITMAP, HexString.toHexString(oduSignalId.tributarySlotBitmap())); + break; + default: + log.info("Cannot convert L1 subtype of {}", instruction.subtype()); + break; + } + } + + /** * Encode an L2 modification instruction. * * @param result json node that the instruction attributes are added to @@ -222,6 +255,10 @@ public final class EncodeInstructionCodecHelper { encodeL0(result); break; + case L1MODIFICATION: + encodeL1(result); + break; + case L2MODIFICATION: encodeL2(result); break; diff --git a/framework/src/onos/core/common/src/main/java/org/onosproject/codec/impl/InstructionCodec.java b/framework/src/onos/core/common/src/main/java/org/onosproject/codec/impl/InstructionCodec.java index f4d5008a..d7307ad3 100644 --- a/framework/src/onos/core/common/src/main/java/org/onosproject/codec/impl/InstructionCodec.java +++ b/framework/src/onos/core/common/src/main/java/org/onosproject/codec/impl/InstructionCodec.java @@ -50,6 +50,9 @@ public final class InstructionCodec extends JsonCodec<Instruction> { protected static final String TUNNEL_ID = "tunnelId"; protected static final String TCP_PORT = "tcpPort"; protected static final String UDP_PORT = "udpPort"; + protected static final String TRIBUTARY_PORT_NUMBER = "tributaryPortNumber"; + protected static final String TRIBUTARY_SLOT_LEN = "tributarySlotLength"; + protected static final String TRIBUTARY_SLOT_BITMAP = "tributarySlotBitmap"; protected static final String MISSING_MEMBER_MESSAGE = " member is required in Instruction"; diff --git a/framework/src/onos/core/common/src/test/java/org/onosproject/codec/impl/CriterionCodecTest.java b/framework/src/onos/core/common/src/test/java/org/onosproject/codec/impl/CriterionCodecTest.java index 54e1146b..86374f81 100644 --- a/framework/src/onos/core/common/src/test/java/org/onosproject/codec/impl/CriterionCodecTest.java +++ b/framework/src/onos/core/common/src/test/java/org/onosproject/codec/impl/CriterionCodecTest.java @@ -31,6 +31,8 @@ import org.onosproject.net.ChannelSpacing; import org.onosproject.net.GridType; import org.onosproject.net.Lambda; import org.onosproject.net.OchSignalType; +import org.onosproject.net.OduSignalId; +import org.onosproject.net.OduSignalType; import org.onosproject.net.PortNumber; import org.onosproject.net.flow.criteria.Criteria; import org.onosproject.net.flow.criteria.Criterion; @@ -54,6 +56,10 @@ public class CriterionCodecTest { final IpPrefix ipPrefix6 = IpPrefix.valueOf("fe80::/64"); final MacAddress mac1 = MacAddress.valueOf("00:00:11:00:00:01"); final TpPort tpPort = TpPort.tpPort(40000); + final int tributaryPortNumber = 11; + final int tributarySlotLen = 80; + final byte[] tributarySlotBitmap = new byte[] {1, 2, 3, 4, 2, 3, 4, 2, 3, 4}; + /** * Sets up for each test. Creates a context and fetches the criterion @@ -427,4 +433,31 @@ public class CriterionCodecTest { ObjectNode result = criterionCodec.encode(criterion, context); assertThat(result, matchesCriterion(criterion)); } + + /** + * Tests Odu Signal ID criterion. + */ + @Test + public void matchOduSignalIdTest() { + + OduSignalId oduSignalId = OduSignalId.oduSignalId(tributaryPortNumber, tributarySlotLen, tributarySlotBitmap); + + Criterion criterion = Criteria.matchOduSignalId(oduSignalId); + ObjectNode result = criterionCodec.encode(criterion, context); + assertThat(result, matchesCriterion(criterion)); + } + + /** + * Tests Odu Signal Type criterion. + */ + @Test + public void matchOduSignalTypeTest() { + + OduSignalType signalType = OduSignalType.ODU2; + + Criterion criterion = Criteria.matchOduSignalType(signalType); + ObjectNode result = criterionCodec.encode(criterion, context); + assertThat(result, matchesCriterion(criterion)); + } + } diff --git a/framework/src/onos/core/common/src/test/java/org/onosproject/codec/impl/CriterionJsonMatcher.java b/framework/src/onos/core/common/src/test/java/org/onosproject/codec/impl/CriterionJsonMatcher.java index bb3acad5..b00632c3 100644 --- a/framework/src/onos/core/common/src/test/java/org/onosproject/codec/impl/CriterionJsonMatcher.java +++ b/framework/src/onos/core/common/src/test/java/org/onosproject/codec/impl/CriterionJsonMatcher.java @@ -15,13 +15,14 @@ */ package org.onosproject.codec.impl; -import com.google.common.base.Joiner; +import java.util.Objects; + import org.hamcrest.Description; import org.hamcrest.TypeSafeDiagnosingMatcher; +import org.onlab.util.HexString; import org.onosproject.net.OchSignal; +import org.onosproject.net.OduSignalId; import org.onosproject.net.flow.criteria.Criterion; - -import com.fasterxml.jackson.databind.JsonNode; import org.onosproject.net.flow.criteria.EthCriterion; import org.onosproject.net.flow.criteria.EthTypeCriterion; import org.onosproject.net.flow.criteria.IPCriterion; @@ -40,6 +41,8 @@ import org.onosproject.net.flow.criteria.MetadataCriterion; 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.OduSignalIdCriterion; +import org.onosproject.net.flow.criteria.OduSignalTypeCriterion; import org.onosproject.net.flow.criteria.PortCriterion; import org.onosproject.net.flow.criteria.SctpPortCriterion; import org.onosproject.net.flow.criteria.TcpPortCriterion; @@ -47,7 +50,8 @@ import org.onosproject.net.flow.criteria.UdpPortCriterion; import org.onosproject.net.flow.criteria.VlanIdCriterion; import org.onosproject.net.flow.criteria.VlanPcpCriterion; -import java.util.Objects; +import com.fasterxml.jackson.databind.JsonNode; +import com.google.common.base.Joiner; /** * Hamcrest matcher for criterion objects. @@ -496,6 +500,44 @@ public final class CriterionJsonMatcher extends return true; } + /** + * Matches an ODU signal ID criterion object. + * + * @param criterion criterion to match + * @return true if the JSON matches the criterion, false otherwise. + */ + private boolean matchCriterion(OduSignalIdCriterion criterion) { + final OduSignalId oduSignal = criterion.oduSignalId(); + final JsonNode jsonOduSignal = jsonCriterion.get(CriterionCodec.ODU_SIGNAL_ID); + int jsonTpn = jsonOduSignal.get(CriterionCodec.TRIBUTARY_PORT_NUMBER).intValue(); + int jsonTsLen = jsonOduSignal.get(CriterionCodec.TRIBUTARY_SLOT_LEN).intValue(); + byte[] jsonTributaryBitMap = HexString.fromHexString( + jsonOduSignal.get(CriterionCodec.TRIBUTARY_SLOT_BITMAP).asText()); + OduSignalId jsonOduSignalId = OduSignalId.oduSignalId(jsonTpn, jsonTsLen, jsonTributaryBitMap); + if (!oduSignal.equals(jsonOduSignalId)) { + description.appendText("oduSignalId was " + criterion); + return false; + } + return true; + } + + /** + * Matches an ODU signal Type criterion object. + * + * @param criterion criterion to match + * @return true if the JSON matches the criterion, false otherwise. + */ + private boolean matchCriterion(OduSignalTypeCriterion criterion) { + final String signalType = criterion.signalType().name(); + final String jsonOduSignalType = jsonCriterion.get("oduSignalType").textValue(); + if (!signalType.equals(jsonOduSignalType)) { + description.appendText("signalType was " + signalType); + return false; + } + return true; + } + + @Override public boolean matchesSafely(JsonNode jsonCriterion, Description description) { @@ -594,6 +636,12 @@ public final class CriterionJsonMatcher extends case OCH_SIGTYPE: return matchCriterion((OchSignalTypeCriterion) criterion); + case ODU_SIGID: + return matchCriterion((OduSignalIdCriterion) criterion); + + case ODU_SIGTYPE: + return matchCriterion((OduSignalTypeCriterion) criterion); + default: // Don't know how to format this type description.appendText("unknown criterion type " + diff --git a/framework/src/onos/core/common/src/test/java/org/onosproject/codec/impl/FlowRuleCodecTest.java b/framework/src/onos/core/common/src/test/java/org/onosproject/codec/impl/FlowRuleCodecTest.java index 6c88ac1e..f6a92131 100644 --- a/framework/src/onos/core/common/src/test/java/org/onosproject/codec/impl/FlowRuleCodecTest.java +++ b/framework/src/onos/core/common/src/test/java/org/onosproject/codec/impl/FlowRuleCodecTest.java @@ -15,6 +15,15 @@ */ package org.onosproject.codec.impl; +import static org.easymock.EasyMock.createMock; +import static org.easymock.EasyMock.expect; +import static org.easymock.EasyMock.replay; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.instanceOf; +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.notNullValue; +import static org.onosproject.net.NetTestTools.APP_ID; + import java.io.IOException; import java.io.InputStream; import java.util.SortedMap; @@ -35,6 +44,8 @@ import org.onosproject.net.ChannelSpacing; import org.onosproject.net.GridType; import org.onosproject.net.Lambda; import org.onosproject.net.OchSignal; +import org.onosproject.net.OchSignalType; +import org.onosproject.net.OduSignalType; import org.onosproject.net.PortNumber; import org.onosproject.net.flow.FlowRule; import org.onosproject.net.flow.criteria.Criterion; @@ -55,6 +66,9 @@ import org.onosproject.net.flow.criteria.Icmpv6TypeCriterion; import org.onosproject.net.flow.criteria.IndexedLambdaCriterion; 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.OduSignalIdCriterion; +import org.onosproject.net.flow.criteria.OduSignalTypeCriterion; import org.onosproject.net.flow.criteria.PortCriterion; import org.onosproject.net.flow.criteria.SctpPortCriterion; import org.onosproject.net.flow.criteria.TcpPortCriterion; @@ -62,9 +76,6 @@ 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 com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.node.ObjectNode; import org.onosproject.net.flow.instructions.Instruction; import org.onosproject.net.flow.instructions.Instructions; import org.onosproject.net.flow.instructions.L0ModificationInstruction; @@ -72,14 +83,8 @@ import org.onosproject.net.flow.instructions.L2ModificationInstruction; import org.onosproject.net.flow.instructions.L3ModificationInstruction; import org.onosproject.net.flow.instructions.L4ModificationInstruction; -import static org.easymock.EasyMock.createMock; -import static org.easymock.EasyMock.expect; -import static org.easymock.EasyMock.replay; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.instanceOf; -import static org.hamcrest.Matchers.is; -import static org.hamcrest.Matchers.notNullValue; -import static org.onosproject.net.NetTestTools.APP_ID; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.node.ObjectNode; /** * Flow rule codec unit tests. @@ -382,7 +387,7 @@ public class FlowRuleCodecTest { checkCommonData(rule); - assertThat(rule.selector().criteria().size(), is(33)); + assertThat(rule.selector().criteria().size(), is(36)); rule.selector().criteria() .stream() @@ -518,6 +523,25 @@ public class FlowRuleCodecTest { criterion = getCriterion(Criterion.Type.TUNNEL_ID); assertThat(((TunnelIdCriterion) criterion).tunnelId(), is(100L)); + + criterion = getCriterion(Criterion.Type.OCH_SIGTYPE); + assertThat(((OchSignalTypeCriterion) criterion).signalType(), + is(OchSignalType.FIXED_GRID)); + + criterion = getCriterion(Criterion.Type.ODU_SIGTYPE); + assertThat(((OduSignalTypeCriterion) criterion).signalType(), + is(OduSignalType.ODU4)); + + + criterion = getCriterion(Criterion.Type.ODU_SIGID); + assertThat(((OduSignalIdCriterion) criterion).oduSignalId().tributaryPortNumber(), + is(1)); + + assertThat(((OduSignalIdCriterion) criterion).oduSignalId().tributarySlotLength(), + is(80)); + + assertThat(((OduSignalIdCriterion) criterion).oduSignalId().tributarySlotBitmap(), + is(new byte [] {1, 1, 1, 1, 1, 1, 1, 1, 1, 1})); } /** diff --git a/framework/src/onos/core/common/src/test/java/org/onosproject/codec/impl/InstructionCodecTest.java b/framework/src/onos/core/common/src/test/java/org/onosproject/codec/impl/InstructionCodecTest.java index bafbc0f1..f7b0261e 100644 --- a/framework/src/onos/core/common/src/test/java/org/onosproject/codec/impl/InstructionCodecTest.java +++ b/framework/src/onos/core/common/src/test/java/org/onosproject/codec/impl/InstructionCodecTest.java @@ -15,6 +15,10 @@ */ package org.onosproject.codec.impl; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.notNullValue; +import static org.onosproject.codec.impl.InstructionJsonMatcher.matchesInstruction; + import org.junit.Before; import org.junit.Test; import org.onlab.packet.Ip4Address; @@ -28,26 +32,23 @@ import org.onosproject.net.ChannelSpacing; import org.onosproject.net.GridType; import org.onosproject.net.IndexedLambda; import org.onosproject.net.Lambda; +import org.onosproject.net.OduSignalId; import org.onosproject.net.PortNumber; 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.L1ModificationInstruction; import org.onosproject.net.flow.instructions.L2ModificationInstruction; import org.onosproject.net.flow.instructions.L3ModificationInstruction; import com.fasterxml.jackson.databind.node.ObjectNode; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.notNullValue; -import static org.onosproject.codec.impl.InstructionJsonMatcher.matchesInstruction; - /** * Unit tests for Instruction codec. */ public class InstructionCodecTest { CodecContext context; JsonCodec<Instruction> instructionCodec; - /** * Sets up for each test. Creates a context and fetches the instruction * codec. @@ -122,6 +123,20 @@ public class InstructionCodecTest { } /** + * Tests the encoding of mod ODU signal ID instructions. + */ + @Test + public void modOduSignalIdInstructionTest() { + OduSignalId oduSignalId = OduSignalId.oduSignalId(1, 8, new byte [] {8, 0, 0, 0, 0, 0, 0, 0, 0, 0}); + L1ModificationInstruction.ModOduSignalIdInstruction instruction = + (L1ModificationInstruction.ModOduSignalIdInstruction) + Instructions.modL1OduSignalId(oduSignalId); + ObjectNode instructionJson = + instructionCodec.encode(instruction, context); + assertThat(instructionJson, matchesInstruction(instruction)); + } + + /** * Tests the encoding of mod ether instructions. */ @Test diff --git a/framework/src/onos/core/common/src/test/java/org/onosproject/codec/impl/InstructionJsonMatcher.java b/framework/src/onos/core/common/src/test/java/org/onosproject/codec/impl/InstructionJsonMatcher.java index c3cdca0f..9ffb3c3a 100644 --- a/framework/src/onos/core/common/src/test/java/org/onosproject/codec/impl/InstructionJsonMatcher.java +++ b/framework/src/onos/core/common/src/test/java/org/onosproject/codec/impl/InstructionJsonMatcher.java @@ -17,15 +17,25 @@ package org.onosproject.codec.impl; import org.hamcrest.Description; import org.hamcrest.TypeSafeDiagnosingMatcher; +import org.onlab.util.HexString; +import org.onosproject.net.OduSignalId; import org.onosproject.net.flow.instructions.Instruction; +import org.onosproject.net.flow.instructions.Instructions.DropInstruction; +import org.onosproject.net.flow.instructions.Instructions.NoActionInstruction; +import org.onosproject.net.flow.instructions.Instructions.OutputInstruction; +import org.onosproject.net.flow.instructions.L0ModificationInstruction.ModLambdaInstruction; +import org.onosproject.net.flow.instructions.L0ModificationInstruction.ModOchSignalInstruction; +import org.onosproject.net.flow.instructions.L1ModificationInstruction.ModOduSignalIdInstruction; +import org.onosproject.net.flow.instructions.L2ModificationInstruction.ModEtherInstruction; +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.L3ModificationInstruction.ModIPInstruction; +import org.onosproject.net.flow.instructions.L3ModificationInstruction.ModIPv6FlowLabelInstruction; import com.fasterxml.jackson.databind.JsonNode; -import static org.onosproject.net.flow.instructions.Instructions.*; -import static org.onosproject.net.flow.instructions.L0ModificationInstruction.*; -import static org.onosproject.net.flow.instructions.L2ModificationInstruction.*; -import static org.onosproject.net.flow.instructions.L3ModificationInstruction.*; - /** * Hamcrest matcher for instructions. */ @@ -133,7 +143,7 @@ public final class InstructionJsonMatcher extends TypeSafeDiagnosingMatcher<Json } /** - * Matches teh contents of a mod OCh singal instruction. + * Matches the contents of a mod OCh singal instruction. * * @param instructionJson JSON instruction to match * @param description Description object used for recording errors @@ -184,6 +194,40 @@ public final class InstructionJsonMatcher extends TypeSafeDiagnosingMatcher<Json } /** + * Matches the contents of a mod ODU singal Id instruction. + * + * @param instructionJson JSON instruction to match + * @param description Description object used for recording errors + * @return true if contents matches, false otherwise + */ + private boolean matchModOduSingalIdInstruction(JsonNode instructionJson, + Description description) { + ModOduSignalIdInstruction instructionToMatch = + (ModOduSignalIdInstruction) instruction; + String jsonSubType = instructionJson.get("subtype").textValue(); + if (!instructionToMatch.subtype().name().equals(jsonSubType)) { + description.appendText("subtype was " + jsonSubType); + return false; + } + String jsonType = instructionJson.get("type").textValue(); + if (!instructionToMatch.type().name().equals(jsonType)) { + description.appendText("type was " + jsonType); + return false; + } + final JsonNode jsonOduSignal = instructionJson.get("oduSignalId"); + int jsonTpn = jsonOduSignal.get("tributaryPortNumber").intValue(); + int jsonTsLen = jsonOduSignal.get("tributarySlotLength").intValue(); + byte [] tributaryBitMap = HexString.fromHexString(jsonOduSignal.get("tributarySlotBitmap").asText()); + OduSignalId jsonOduSignalId = OduSignalId.oduSignalId(jsonTpn, jsonTsLen, tributaryBitMap); + if (!instructionToMatch.oduSignalId().equals(jsonOduSignalId)) { + description.appendText("oduSignalId was " + instructionToMatch); + return false; + } + return true; + } + + + /** * Matches the contents of a mod Ethernet instruction. * * @param instructionJson JSON instruction to match @@ -416,6 +460,8 @@ public final class InstructionJsonMatcher extends TypeSafeDiagnosingMatcher<Json description); } else if (instruction instanceof ModMplsLabelInstruction) { return matchModMplsLabelInstruction(jsonInstruction, description); + } else if (instruction instanceof ModOduSignalIdInstruction) { + return matchModOduSingalIdInstruction(jsonInstruction, description); } else if (instruction instanceof NoActionInstruction) { return true; } diff --git a/framework/src/onos/core/common/src/test/resources/org/onosproject/codec/impl/criteria-flow.json b/framework/src/onos/core/common/src/test/resources/org/onosproject/codec/impl/criteria-flow.json index 1a96e92f..ccb2e161 100644 --- a/framework/src/onos/core/common/src/test/resources/org/onosproject/codec/impl/criteria-flow.json +++ b/framework/src/onos/core/common/src/test/resources/org/onosproject/codec/impl/criteria-flow.json @@ -38,7 +38,10 @@ {"type":"MPLS_LABEL", "label":123}, {"type":"IPV6_EXTHDR", "exthdrFlags":99}, {"type":"OCH_SIGID", "lambda":122}, - {"type":"TUNNEL_ID", "tunnelId":100} + {"type":"TUNNEL_ID", "tunnelId":100}, + {"type":"OCH_SIGTYPE", "ochSignalType":"FIXED_GRID"}, + {"type":"ODU_SIGTYPE", "oduSignalType":"ODU4"}, + {"type":"ODU_SIGID", "oduSignalId" : {"tributaryPortNumber":1, "tributarySlotLen":80, "tributarySlotBitmap":"01:01:01:01:01:01:01:01:01:01"}} ] } } diff --git a/framework/src/onos/core/net/src/main/java/org/onosproject/cluster/impl/ClusterManager.java b/framework/src/onos/core/net/src/main/java/org/onosproject/cluster/impl/ClusterManager.java index 04d1dfdf..7ddac0ce 100644 --- a/framework/src/onos/core/net/src/main/java/org/onosproject/cluster/impl/ClusterManager.java +++ b/framework/src/onos/core/net/src/main/java/org/onosproject/cluster/impl/ClusterManager.java @@ -25,17 +25,26 @@ import org.apache.karaf.system.SystemService; import org.joda.time.DateTime; import org.onlab.packet.IpAddress; import org.onosproject.cluster.ClusterAdminService; -import org.onosproject.cluster.ClusterDefinitionService; import org.onosproject.cluster.ClusterEvent; import org.onosproject.cluster.ClusterEventListener; +import org.onosproject.cluster.ClusterMetadata; +import org.onosproject.cluster.ClusterMetadataService; import org.onosproject.cluster.ClusterService; import org.onosproject.cluster.ClusterStore; import org.onosproject.cluster.ClusterStoreDelegate; import org.onosproject.cluster.ControllerNode; import org.onosproject.cluster.NodeId; +import org.onosproject.cluster.Partition; import org.onosproject.event.AbstractListenerManager; import org.slf4j.Logger; +import com.google.common.collect.Lists; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.HashSet; +import java.util.List; import java.util.Set; import static com.google.common.base.Preconditions.checkArgument; @@ -44,8 +53,6 @@ import static org.onosproject.security.AppGuard.checkPermission; import static org.slf4j.LoggerFactory.getLogger; import static org.onosproject.security.AppPermission.Type.*; - - /** * Implementation of the cluster service. */ @@ -61,7 +68,7 @@ public class ClusterManager private ClusterStoreDelegate delegate = new InternalStoreDelegate(); @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) - protected ClusterDefinitionService clusterDefinitionService; + protected ClusterMetadataService clusterMetadataService; @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) protected ClusterStore store; @@ -73,8 +80,9 @@ public class ClusterManager public void activate() { store.setDelegate(delegate); eventDispatcher.addSink(ClusterEvent.class, listenerRegistry); - clusterDefinitionService.seedNodes() - .forEach(node -> store.addNode(node.id(), node.ip(), node.tcpPort())); + clusterMetadataService.getClusterMetadata() + .getNodes() + .forEach(node -> store.addNode(node.id(), node.ip(), node.tcpPort())); log.info("Started"); } @@ -119,11 +127,16 @@ public class ClusterManager } @Override - public void formCluster(Set<ControllerNode> nodes, String ipPrefix) { + public void formCluster(Set<ControllerNode> nodes) { checkNotNull(nodes, "Nodes cannot be null"); checkArgument(!nodes.isEmpty(), "Nodes cannot be empty"); - checkNotNull(ipPrefix, "IP prefix cannot be null"); - clusterDefinitionService.formCluster(nodes, ipPrefix); + + ClusterMetadata metadata = ClusterMetadata.builder() + .withName("default") + .withControllerNodes(nodes) + .withPartitions(buildDefaultPartitions(nodes)) + .build(); + clusterMetadataService.setClusterMetadata(metadata); try { log.warn("Shutting down container for cluster reconfiguration!"); systemService.reboot("now", SystemService.Swipe.NONE); @@ -153,4 +166,21 @@ public class ClusterManager post(event); } } + + private static Collection<Partition> buildDefaultPartitions(Collection<ControllerNode> nodes) { + List<ControllerNode> sorted = new ArrayList<>(nodes); + Collections.sort(sorted, (o1, o2) -> o1.id().toString().compareTo(o2.id().toString())); + Collection<Partition> partitions = Lists.newArrayList(); + + int length = nodes.size(); + int count = 3; + for (int i = 0; i < length; i++) { + Set<NodeId> set = new HashSet<>(count); + for (int j = 0; j < count; j++) { + set.add(sorted.get((i + j) % length).id()); + } + partitions.add(new Partition("p" + (i + 1), set)); + } + return partitions; + } } diff --git a/framework/src/onos/core/net/src/main/java/org/onosproject/cluster/impl/ClusterMetadataManager.java b/framework/src/onos/core/net/src/main/java/org/onosproject/cluster/impl/ClusterMetadataManager.java new file mode 100644 index 00000000..a0f7a833 --- /dev/null +++ b/framework/src/onos/core/net/src/main/java/org/onosproject/cluster/impl/ClusterMetadataManager.java @@ -0,0 +1,116 @@ +package org.onosproject.cluster.impl; + +import static com.google.common.base.Preconditions.checkNotNull; +import static org.slf4j.LoggerFactory.getLogger; + +import java.net.InetAddress; +import java.net.NetworkInterface; +import java.net.SocketException; +import java.util.Collection; +import java.util.Enumeration; + +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.IpAddress; +import org.onosproject.cluster.ClusterMetadata; +import org.onosproject.cluster.ClusterMetadataEvent; +import org.onosproject.cluster.ClusterMetadataEventListener; +import org.onosproject.cluster.ClusterMetadataService; +import org.onosproject.cluster.ClusterMetadataStore; +import org.onosproject.cluster.ClusterMetadataStoreDelegate; +import org.onosproject.cluster.ControllerNode; +import org.onosproject.event.AbstractListenerManager; +import org.onosproject.store.service.Versioned; +import org.slf4j.Logger; + +/** + * Implementation of ClusterMetadataService. + */ +@Component(immediate = true) +@Service +public class ClusterMetadataManager + extends AbstractListenerManager<ClusterMetadataEvent, ClusterMetadataEventListener> + implements ClusterMetadataService { + + private ControllerNode localNode; + private final Logger log = getLogger(getClass()); + + private ClusterMetadataStoreDelegate delegate = new InternalStoreDelegate(); + + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + protected ClusterMetadataStore store; + + @Activate + public void activate() { + store.setDelegate(delegate); + eventDispatcher.addSink(ClusterMetadataEvent.class, listenerRegistry); + establishSelfIdentity(); + log.info("Started"); + } + + @Deactivate + public void deactivate() { + store.unsetDelegate(delegate); + eventDispatcher.removeSink(ClusterMetadataEvent.class); + log.info("Stopped"); + } + + @Override + public ClusterMetadata getClusterMetadata() { + return Versioned.valueOrElse(store.getClusterMetadata(), null); + } + + @Override + public ControllerNode getLocalNode() { + return localNode; + } + + @Override + public void setClusterMetadata(ClusterMetadata metadata) { + checkNotNull(metadata, "Cluster metadata cannot be null"); + store.setClusterMetadata(metadata); + } + + // Store delegate to re-post events emitted from the store. + private class InternalStoreDelegate implements ClusterMetadataStoreDelegate { + @Override + public void notify(ClusterMetadataEvent event) { + post(event); + } + } + + private IpAddress findLocalIp(Collection<ControllerNode> controllerNodes) throws SocketException { + Enumeration<NetworkInterface> interfaces = + NetworkInterface.getNetworkInterfaces(); + while (interfaces.hasMoreElements()) { + NetworkInterface iface = interfaces.nextElement(); + Enumeration<InetAddress> inetAddresses = iface.getInetAddresses(); + while (inetAddresses.hasMoreElements()) { + IpAddress ip = IpAddress.valueOf(inetAddresses.nextElement()); + if (controllerNodes.stream() + .map(ControllerNode::ip) + .anyMatch(nodeIp -> ip.equals(nodeIp))) { + return ip; + } + } + } + throw new IllegalStateException("Unable to determine local ip"); + } + + private void establishSelfIdentity() { + try { + IpAddress ip = findLocalIp(getClusterMetadata().getNodes()); + localNode = getClusterMetadata().getNodes() + .stream() + .filter(node -> node.ip().equals(ip)) + .findFirst() + .get(); + } catch (SocketException e) { + throw new IllegalStateException("Cannot determine local IP", e); + } + } +}
\ No newline at end of file diff --git a/framework/src/onos/core/net/src/main/java/org/onosproject/net/device/impl/OpticalPortOperator.java b/framework/src/onos/core/net/src/main/java/org/onosproject/net/device/impl/OpticalPortOperator.java index 19377cf6..8f601497 100644 --- a/framework/src/onos/core/net/src/main/java/org/onosproject/net/device/impl/OpticalPortOperator.java +++ b/framework/src/onos/core/net/src/main/java/org/onosproject/net/device/impl/OpticalPortOperator.java @@ -112,10 +112,10 @@ public final class OpticalPortOperator implements ConfigOperator { return new OduCltPortDescription(port, odu.isEnabled(), odu.signalType(), sa); case PACKET: case FIBER: + case COPPER: return new DefaultPortDescription(port, descr.isEnabled(), descr.type(), descr.portSpeed(), sa); default: - // this includes copper ports. log.warn("Unsupported optical port type {} - can't update", descr.type()); return descr; } diff --git a/framework/src/onos/core/net/src/main/java/org/onosproject/net/flowobjective/impl/composition/FlowObjectiveCompositionUtil.java b/framework/src/onos/core/net/src/main/java/org/onosproject/net/flowobjective/impl/composition/FlowObjectiveCompositionUtil.java index 137aca1e..0a1af6f5 100644 --- a/framework/src/onos/core/net/src/main/java/org/onosproject/net/flowobjective/impl/composition/FlowObjectiveCompositionUtil.java +++ b/framework/src/onos/core/net/src/main/java/org/onosproject/net/flowobjective/impl/composition/FlowObjectiveCompositionUtil.java @@ -29,9 +29,11 @@ import org.onosproject.net.flow.criteria.VlanPcpCriterion; import org.onosproject.net.flow.criteria.MplsCriterion; import org.onosproject.net.flow.criteria.IPCriterion; import org.onosproject.net.flow.criteria.IPv6FlowLabelCriterion; +import org.onosproject.net.flow.criteria.OduSignalIdCriterion; import org.onosproject.net.flow.criteria.Criteria; import org.onosproject.net.flow.instructions.Instruction; import org.onosproject.net.flow.instructions.L0ModificationInstruction; +import org.onosproject.net.flow.instructions.L1ModificationInstruction; import org.onosproject.net.flow.instructions.L2ModificationInstruction; import org.onosproject.net.flow.instructions.L3ModificationInstruction; import org.onosproject.net.flowobjective.DefaultForwardingObjective; @@ -155,6 +157,7 @@ public final class FlowObjectiveCompositionUtil { return treatmentBuilder.build(); } + //CHECKSTYLE:OFF public static TrafficSelector revertTreatmentSelector(TrafficTreatment trafficTreatment, TrafficSelector trafficSelector) { @@ -195,14 +198,30 @@ public final class FlowObjectiveCompositionUtil { } else { return null; } - } else { - break; } default: break; } break; } + case L1MODIFICATION: { + L1ModificationInstruction l1 = (L1ModificationInstruction) instruction; + switch (l1.subtype()) { + case ODU_SIGID: + if (criterionMap.containsKey(Criterion.Type.ODU_SIGID)) { + if (((OduSignalIdCriterion) criterionMap.get((Criterion.Type.ODU_SIGID))).oduSignalId() + .equals(((L1ModificationInstruction.ModOduSignalIdInstruction) l1) + .oduSignalId())) { + criterionMap.remove(Criterion.Type.ODU_SIGID); + } else { + return null; + } + } + default: + break; + } + break; + } case L2MODIFICATION: { L2ModificationInstruction l2 = (L2ModificationInstruction) instruction; switch (l2.subtype()) { @@ -344,6 +363,7 @@ public final class FlowObjectiveCompositionUtil { return selectorBuilder.build(); } + //CHECKSTYLE:ON public static Set<Criterion.Type> getTypeSet(TrafficSelector trafficSelector) { Set<Criterion.Type> typeSet = new HashSet<>(); diff --git a/framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/MplsPathIntentCompiler.java b/framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/MplsPathIntentCompiler.java index 5fd1c85d..acc5a5d5 100644 --- a/framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/MplsPathIntentCompiler.java +++ b/framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/MplsPathIntentCompiler.java @@ -24,12 +24,14 @@ import org.apache.felix.scr.annotations.Reference; import org.apache.felix.scr.annotations.ReferenceCardinality; import org.onlab.packet.EthType; import org.onlab.packet.Ethernet; +import org.onlab.packet.MplsLabel; 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.Link; +import org.onosproject.net.LinkKey; import org.onosproject.net.PortNumber; import org.onosproject.net.flow.DefaultFlowRule; import org.onosproject.net.flow.DefaultTrafficSelector; @@ -46,24 +48,23 @@ import org.onosproject.net.intent.Intent; import org.onosproject.net.intent.IntentCompiler; import org.onosproject.net.intent.IntentExtensionService; import org.onosproject.net.intent.MplsPathIntent; -import org.onosproject.net.link.LinkStore; -import org.onosproject.net.resource.link.DefaultLinkResourceRequest; +import org.onosproject.net.newresource.ResourcePath; +import org.onosproject.net.newresource.ResourceService; import org.onosproject.net.resource.link.LinkResourceAllocations; -import org.onosproject.net.resource.link.LinkResourceRequest; -import org.onosproject.net.resource.link.LinkResourceService; -import org.onosproject.net.resource.link.MplsLabel; -import org.onosproject.net.resource.link.MplsLabelResourceAllocation; -import org.onosproject.net.resource.ResourceAllocation; -import org.onosproject.net.resource.ResourceType; import org.slf4j.Logger; import java.util.Collections; +import java.util.HashMap; import java.util.Iterator; import java.util.LinkedList; import java.util.List; +import java.util.Map; +import java.util.Optional; import java.util.Set; +import java.util.stream.Collectors; import static com.google.common.base.Preconditions.checkNotNull; +import static org.onosproject.net.LinkKey.linkKey; import static org.slf4j.LoggerFactory.getLogger; @Component(immediate = true) @@ -78,18 +79,15 @@ public class MplsPathIntentCompiler implements IntentCompiler<MplsPathIntent> { protected CoreService coreService; @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) - protected LinkResourceService resourceService; - - @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) - protected LinkStore linkStore; + protected ResourceService resourceService; protected ApplicationId appId; @Override public List<Intent> compile(MplsPathIntent intent, List<Intent> installable, Set<LinkResourceAllocations> resources) { - LinkResourceAllocations allocations = assignMplsLabel(intent); - List<FlowRule> rules = generateRules(intent, allocations); + Map<LinkKey, MplsLabel> labels = assignMplsLabel(intent); + List<FlowRule> rules = generateRules(intent, labels); return Collections.singletonList(new FlowRuleIntent(appId, rules, intent.resources())); } @@ -105,39 +103,60 @@ public class MplsPathIntentCompiler implements IntentCompiler<MplsPathIntent> { intentExtensionService.unregisterCompiler(MplsPathIntent.class); } - private LinkResourceAllocations assignMplsLabel(MplsPathIntent intent) { + private Map<LinkKey, MplsLabel> assignMplsLabel(MplsPathIntent intent) { // TODO: do it better... Suggestions? - Set<Link> linkRequest = Sets.newHashSetWithExpectedSize(intent.path() + Set<LinkKey> linkRequest = Sets.newHashSetWithExpectedSize(intent.path() .links().size() - 2); for (int i = 1; i <= intent.path().links().size() - 2; i++) { - Link link = intent.path().links().get(i); + LinkKey link = linkKey(intent.path().links().get(i)); linkRequest.add(link); // add the inverse link. I want that the label is reserved both for // the direct and inverse link - linkRequest.add(linkStore.getLink(link.dst(), link.src())); + linkRequest.add(linkKey(link.dst(), link.src())); } - LinkResourceRequest.Builder request = DefaultLinkResourceRequest - .builder(intent.id(), linkRequest).addMplsRequest(); - LinkResourceAllocations reqMpls = resourceService - .requestResources(request.build()); - return reqMpls; - } + Map<LinkKey, MplsLabel> labels = findMplsLabels(linkRequest); + if (labels.isEmpty()) { + return Collections.emptyMap(); + } + + List<ResourcePath> resources = labels.entrySet().stream() + .map(x -> new ResourcePath(linkKey(x.getKey().src(), x.getKey().src()), x.getValue())) + .collect(Collectors.toList()); + List<org.onosproject.net.newresource.ResourceAllocation> allocations = + resourceService.allocate(intent.id(), resources); + if (allocations.isEmpty()) { + Collections.emptyMap(); + } - private MplsLabel getMplsLabel(LinkResourceAllocations allocations, Link link) { - for (ResourceAllocation allocation : allocations - .getResourceAllocation(link)) { - if (allocation.type() == ResourceType.MPLS_LABEL) { - return ((MplsLabelResourceAllocation) allocation).mplsLabel(); + return labels; + } + private Map<LinkKey, MplsLabel> findMplsLabels(Set<LinkKey> links) { + Map<LinkKey, MplsLabel> labels = new HashMap<>(); + for (LinkKey link : links) { + Optional<MplsLabel> label = findMplsLabel(link); + if (label.isPresent()) { + labels.put(link, label.get()); } } - log.warn("MPLS label was not assigned successfully"); - return null; + + return labels; + } + + private Optional<MplsLabel> findMplsLabel(LinkKey link) { + return resourceService.getAvailableResources(new ResourcePath(link)).stream() + .filter(x -> x.lastComponent() instanceof MplsLabel) + .map(x -> (MplsLabel) x.lastComponent()) + .findFirst(); + } + + private MplsLabel getMplsLabel(Map<LinkKey, MplsLabel> labels, LinkKey link) { + return labels.get(link); } private List<FlowRule> generateRules(MplsPathIntent intent, - LinkResourceAllocations allocations) { + Map<LinkKey, MplsLabel> labels) { Iterator<Link> links = intent.path().links().iterator(); Link srcLink = links.next(); @@ -149,7 +168,7 @@ public class MplsPathIntentCompiler implements IntentCompiler<MplsPathIntent> { // Ingress traffic // Get the new MPLS label - MplsLabel mpls = getMplsLabel(allocations, link); + MplsLabel mpls = getMplsLabel(labels, linkKey(link)); checkNotNull(mpls); MplsLabel prevLabel = mpls; rules.add(ingressFlow(prev.port(), link, intent, mpls)); @@ -163,7 +182,7 @@ public class MplsPathIntentCompiler implements IntentCompiler<MplsPathIntent> { if (links.hasNext()) { // Transit traffic // Get the new MPLS label - mpls = getMplsLabel(allocations, link); + mpls = getMplsLabel(labels, linkKey(link)); checkNotNull(mpls); rules.add(transitFlow(prev.port(), link, intent, prevLabel, mpls)); @@ -181,7 +200,8 @@ public class MplsPathIntentCompiler implements IntentCompiler<MplsPathIntent> { } private FlowRule ingressFlow(PortNumber inPort, Link link, - MplsPathIntent intent, MplsLabel label) { + MplsPathIntent intent, + MplsLabel label) { TrafficSelector.Builder ingressSelector = DefaultTrafficSelector .builder(intent.selector()); @@ -193,10 +213,10 @@ public class MplsPathIntentCompiler implements IntentCompiler<MplsPathIntent> { .matchMplsLabel(intent.ingressLabel().get()); // Swap the MPLS label - treat.setMpls(label.label()); + treat.setMpls(label); } else { // Push and set the MPLS label - treat.pushMpls().setMpls(label.label()); + treat.pushMpls().setMpls(label); } // Add the output action treat.setOutput(link.src().port()); @@ -205,21 +225,21 @@ public class MplsPathIntentCompiler implements IntentCompiler<MplsPathIntent> { } private FlowRule transitFlow(PortNumber inPort, Link link, - MplsPathIntent intent, - MplsLabel prevLabel, - MplsLabel outLabel) { + MplsPathIntent intent, + MplsLabel prevLabel, + MplsLabel outLabel) { // Ignore the ingress Traffic Selector and use only the MPLS label // assigned in the previous link TrafficSelector.Builder selector = DefaultTrafficSelector.builder(); selector.matchInPort(inPort).matchEthType(Ethernet.MPLS_UNICAST) - .matchMplsLabel(prevLabel.label()); + .matchMplsLabel(prevLabel); TrafficTreatment.Builder treat = DefaultTrafficTreatment.builder(); // Set the new label only if the label on the packet is // different if (!prevLabel.equals(outLabel)) { - treat.setMpls(outLabel.label()); + treat.setMpls(outLabel); } treat.setOutput(link.src().port()); @@ -227,14 +247,14 @@ public class MplsPathIntentCompiler implements IntentCompiler<MplsPathIntent> { } private FlowRule egressFlow(PortNumber inPort, Link link, - MplsPathIntent intent, - MplsLabel prevLabel) { + MplsPathIntent intent, + MplsLabel prevLabel) { // egress point: either set the egress MPLS label or pop the // MPLS label based on the intent annotations TrafficSelector.Builder selector = DefaultTrafficSelector.builder(); selector.matchInPort(inPort).matchEthType(Ethernet.MPLS_UNICAST) - .matchMplsLabel(prevLabel.label()); + .matchMplsLabel(prevLabel); // apply the intent's treatments TrafficTreatment.Builder treat = DefaultTrafficTreatment.builder(intent diff --git a/framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/OpticalCircuitIntentCompiler.java b/framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/OpticalCircuitIntentCompiler.java index c6eb7c5a..fce8498c 100644 --- a/framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/OpticalCircuitIntentCompiler.java +++ b/framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/OpticalCircuitIntentCompiler.java @@ -17,6 +17,7 @@ package org.onosproject.net.intent.impl.compiler; import org.apache.commons.lang3.tuple.Pair; 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; @@ -70,7 +71,7 @@ import static com.google.common.base.Preconditions.checkArgument; * An intent compiler for {@link org.onosproject.net.intent.OpticalCircuitIntent}. */ // For now, remove component designation until dependency on the new resource manager is available. -// @Component(immediate = true) +@Component(immediate = true) public class OpticalCircuitIntentCompiler implements IntentCompiler<OpticalCircuitIntent> { private static final Logger log = LoggerFactory.getLogger(OpticalCircuitIntentCompiler.class); diff --git a/framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/OpticalConnectivityIntentCompiler.java b/framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/OpticalConnectivityIntentCompiler.java index eb5b4af8..d6725b7c 100644 --- a/framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/OpticalConnectivityIntentCompiler.java +++ b/framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/OpticalConnectivityIntentCompiler.java @@ -16,7 +16,11 @@ package org.onosproject.net.intent.impl.compiler; import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableSet; +import com.google.common.collect.Iterables; +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.Reference; import org.apache.felix.scr.annotations.ReferenceCardinality; @@ -24,6 +28,7 @@ import org.onlab.util.Frequency; import org.onosproject.net.AnnotationKeys; import org.onosproject.net.ConnectPoint; import org.onosproject.net.DeviceId; +import org.onosproject.net.IndexedLambda; import org.onosproject.net.Link; import org.onosproject.net.OchPort; import org.onosproject.net.OchSignal; @@ -38,32 +43,29 @@ import org.onosproject.net.intent.IntentExtensionService; import org.onosproject.net.intent.OpticalConnectivityIntent; import org.onosproject.net.intent.OpticalPathIntent; import org.onosproject.net.intent.impl.IntentCompilationException; +import org.onosproject.net.newresource.ResourceAllocation; import org.onosproject.net.newresource.ResourcePath; import org.onosproject.net.newresource.ResourceService; -import org.onosproject.net.resource.ResourceType; -import org.onosproject.net.resource.link.DefaultLinkResourceRequest; -import org.onosproject.net.resource.link.LambdaResource; -import org.onosproject.net.resource.link.LambdaResourceAllocation; import org.onosproject.net.resource.link.LinkResourceAllocations; -import org.onosproject.net.resource.link.LinkResourceRequest; -import org.onosproject.net.resource.link.LinkResourceService; import org.onosproject.net.topology.LinkWeight; import org.onosproject.net.topology.Topology; import org.onosproject.net.topology.TopologyService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.util.Collections; import java.util.List; import java.util.Set; import java.util.stream.Collectors; import static com.google.common.base.Preconditions.checkArgument; +import static org.onosproject.net.LinkKey.linkKey; /** * An intent compiler for {@link org.onosproject.net.intent.OpticalConnectivityIntent}. */ // For now, remove component designation until dependency on the new resource manager is available. -// @Component(immediate = true) +@Component(immediate = true) public class OpticalConnectivityIntentCompiler implements IntentCompiler<OpticalConnectivityIntent> { protected static final Logger log = LoggerFactory.getLogger(OpticalConnectivityIntentCompiler.class); @@ -80,9 +82,6 @@ public class OpticalConnectivityIntentCompiler implements IntentCompiler<Optical @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) protected ResourceService resourceService; - @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) - protected LinkResourceService linkResourceService; - @Activate public void activate() { intentManager.registerCompiler(OpticalConnectivityIntent.class, this); @@ -138,13 +137,12 @@ public class OpticalConnectivityIntentCompiler implements IntentCompiler<Optical ochSignal = srcOchPort.lambda(); } else { // Request and reserve lambda on path - LinkResourceAllocations linkAllocs = assignWavelength(intent, path); - if (linkAllocs == null) { + IndexedLambda lambda = assignWavelength(intent, path); + if (lambda == null) { continue; } - LambdaResourceAllocation lambdaAlloc = getWavelength(path, linkAllocs); OmsPort omsPort = (OmsPort) deviceService.getPort(path.src().deviceId(), path.src().port()); - ochSignal = new OchSignal(lambdaAlloc.lambda().toInt(), omsPort.maxFrequency(), omsPort.grid()); + ochSignal = new OchSignal((int) lambda.index(), omsPort.maxFrequency(), omsPort.grid()); } // Create installable optical path intent @@ -171,72 +169,46 @@ public class OpticalConnectivityIntentCompiler implements IntentCompiler<Optical } /** - * Find the lambda allocated to the path. - * - * @param path the path - * @param linkAllocs the link allocations - * @return lambda allocated to the given path - */ - private LambdaResourceAllocation getWavelength(Path path, LinkResourceAllocations linkAllocs) { - return path.links().stream() - .flatMap(x -> linkAllocs.getResourceAllocation(x).stream()) - .filter(x -> x.type() == ResourceType.LAMBDA) - .findFirst() - .map(x -> (LambdaResourceAllocation) x) - .orElse(null); - } - - /** * Request and reserve first available wavelength across path. * * @param path path in WDM topology - * @return first available lambda resource allocation + * @return first available lambda allocated */ - private LinkResourceAllocations assignWavelength(Intent intent, Path path) { - LinkResourceRequest.Builder request = - DefaultLinkResourceRequest.builder(intent.id(), path.links()) - .addLambdaRequest(); - - LinkResourceAllocations allocations = linkResourceService.requestResources(request.build()); - - if (!checkWavelengthContinuity(allocations, path)) { - linkResourceService.releaseResources(allocations); + private IndexedLambda assignWavelength(Intent intent, Path path) { + Set<IndexedLambda> lambdas = findCommonLambdasOverLinks(path.links()); + if (lambdas.isEmpty()) { return null; } - return allocations; - } + IndexedLambda minLambda = findFirstLambda(lambdas); + List<ResourcePath> lambdaResources = path.links().stream() + .map(x -> new ResourcePath(linkKey(x.src(), x.dst()))) + .map(x -> ResourcePath.child(x, minLambda)) + .collect(Collectors.toList()); - /** - * Checks wavelength continuity constraint across path, i.e., an identical lambda is used on all links. - * @return true if wavelength continuity is met, false otherwise - */ - private boolean checkWavelengthContinuity(LinkResourceAllocations allocations, Path path) { - if (allocations == null) { - return false; + List<ResourceAllocation> allocations = resourceService.allocate(intent.id(), lambdaResources); + if (allocations.isEmpty()) { + log.info("Resource allocation for {} failed (resource request: {})", intent, lambdaResources); } - List<LambdaResource> lambdas = path.links().stream() - .flatMap(x -> allocations.getResourceAllocation(x).stream()) - .filter(x -> x.type() == ResourceType.LAMBDA) - .map(x -> ((LambdaResourceAllocation) x).lambda()) - .collect(Collectors.toList()); + return minLambda; + } - LambdaResource lambda = null; - for (LambdaResource nextLambda: lambdas) { - if (nextLambda == null) { - return false; - } - if (lambda == null) { - lambda = nextLambda; - continue; - } - if (!lambda.equals(nextLambda)) { - return false; - } - } + private Set<IndexedLambda> findCommonLambdasOverLinks(List<Link> links) { + return links.stream() + .map(x -> new ResourcePath(linkKey(x.src(), x.dst()))) + .map(resourceService::getAvailableResources) + .map(x -> Iterables.filter(x, r -> r.lastComponent() instanceof IndexedLambda)) + .map(x -> Iterables.transform(x, r -> (IndexedLambda) r.lastComponent())) + .map(x -> (Set<IndexedLambda>) ImmutableSet.copyOf(x)) + .reduce(Sets::intersection) + .orElse(Collections.emptySet()); + } - return true; + private IndexedLambda findFirstLambda(Set<IndexedLambda> lambdas) { + return lambdas.stream() + .findFirst() + .get(); } private ConnectPoint staticPort(ConnectPoint connectPoint) { diff --git a/framework/src/onos/core/net/src/main/java/org/onosproject/net/newresource/impl/ResourceManager.java b/framework/src/onos/core/net/src/main/java/org/onosproject/net/newresource/impl/ResourceManager.java index 5226967f..10fe75ea 100644 --- a/framework/src/onos/core/net/src/main/java/org/onosproject/net/newresource/impl/ResourceManager.java +++ b/framework/src/onos/core/net/src/main/java/org/onosproject/net/newresource/impl/ResourceManager.java @@ -41,7 +41,7 @@ import static com.google.common.base.Preconditions.checkNotNull; /** * An implementation of ResourceService. */ -@Component(immediate = true, enabled = false) +@Component(immediate = true) @Service @Beta public final class ResourceManager implements ResourceService, ResourceAdminService { @@ -127,6 +127,17 @@ public final class ResourceManager implements ResourceService, ResourceAdminServ } @Override + public Collection<ResourcePath> getAvailableResources(ResourcePath parent) { + checkNotNull(parent); + + Collection<ResourcePath> children = store.getChildResources(parent); + return children.stream() + // We access store twice in this method, then the store may be updated by others + .filter(x -> !store.getConsumer(x).isPresent()) + .collect(Collectors.toList()); + } + + @Override public boolean isAvailable(ResourcePath resource) { checkNotNull(resource); diff --git a/framework/src/onos/core/net/src/main/java/org/onosproject/net/resource/impl/LinkResourceManager.java b/framework/src/onos/core/net/src/main/java/org/onosproject/net/resource/impl/LinkResourceManager.java index 8b9952ed..7eb189e5 100644 --- a/framework/src/onos/core/net/src/main/java/org/onosproject/net/resource/impl/LinkResourceManager.java +++ b/framework/src/onos/core/net/src/main/java/org/onosproject/net/resource/impl/LinkResourceManager.java @@ -31,7 +31,6 @@ import org.onosproject.net.resource.ResourceType; import org.onosproject.net.resource.link.BandwidthResourceAllocation; import org.onosproject.net.resource.link.BandwidthResourceRequest; import org.onosproject.net.resource.link.DefaultLinkResourceAllocations; -import org.onosproject.net.resource.link.LambdaResource; import org.onosproject.net.resource.link.LambdaResourceAllocation; import org.onosproject.net.resource.link.LambdaResourceRequest; import org.onosproject.net.resource.link.LinkResourceAllocations; @@ -46,15 +45,12 @@ import org.onosproject.net.resource.link.MplsLabelResourceAllocation; import org.onosproject.net.resource.link.MplsLabelResourceRequest; import org.slf4j.Logger; -import java.util.Collections; import java.util.HashMap; import java.util.HashSet; -import java.util.Iterator; import java.util.Map; +import java.util.Optional; import java.util.Set; -import static com.google.common.base.Preconditions.checkArgument; -import static com.google.common.base.Preconditions.checkNotNull; import static org.onosproject.security.AppGuard.checkPermission; import static org.slf4j.LoggerFactory.getLogger; import static org.onosproject.security.AppPermission.Type.*; @@ -86,67 +82,6 @@ public class LinkResourceManager log.info("Stopped"); } - /** - * Returns available lambdas on specified link. - * - * @param link the link - * @return available lambdas on specified link - */ - private Set<LambdaResource> getAvailableLambdas(Link link) { - checkNotNull(link); - Set<ResourceAllocation> resAllocs = store.getFreeResources(link); - if (resAllocs == null) { - return Collections.emptySet(); - } - Set<LambdaResource> lambdas = new HashSet<>(); - for (ResourceAllocation res : resAllocs) { - if (res.type() == ResourceType.LAMBDA) { - lambdas.add(((LambdaResourceAllocation) res).lambda()); - } - } - return lambdas; - } - - - /** - * Returns available lambdas on specified links. - * - * @param links the links - * @return available lambdas on specified links - */ - private Iterable<LambdaResource> getAvailableLambdas(Iterable<Link> links) { - checkNotNull(links); - Iterator<Link> i = links.iterator(); - checkArgument(i.hasNext()); - Set<LambdaResource> lambdas = new HashSet<>(getAvailableLambdas(i.next())); - while (i.hasNext()) { - lambdas.retainAll(getAvailableLambdas(i.next())); - } - return lambdas; - } - - - /** - * Returns available MPLS label on specified link. - * - * @param link the link - * @return available MPLS labels on specified link - */ - private Iterable<MplsLabel> getAvailableMplsLabels(Link link) { - Set<ResourceAllocation> resAllocs = store.getFreeResources(link); - if (resAllocs == null) { - return Collections.emptySet(); - } - Set<MplsLabel> mplsLabels = new HashSet<>(); - for (ResourceAllocation res : resAllocs) { - if (res.type() == ResourceType.MPLS_LABEL) { - - mplsLabels.add(((MplsLabelResourceAllocation) res).mplsLabel()); - } - } - - return mplsLabels; - } @Override public LinkResourceAllocations requestResources(LinkResourceRequest req) { @@ -164,26 +99,23 @@ public class LinkResourceManager allocs.add(new BandwidthResourceAllocation(br.bandwidth())); break; case LAMBDA: - Iterator<LambdaResource> lambdaIterator = - getAvailableLambdas(req.links()).iterator(); - if (lambdaIterator.hasNext()) { - allocs.add(new LambdaResourceAllocation(lambdaIterator.next())); - } else { - log.info("Failed to allocate lambda resource."); - return null; - } + LambdaResourceRequest lr = (LambdaResourceRequest) r; + allocs.add(new LambdaResourceAllocation(lr.lambda())); break; case MPLS_LABEL: for (Link link : req.links()) { if (allocsPerLink.get(link) == null) { allocsPerLink.put(link, new HashSet<>()); } - Iterator<MplsLabel> mplsIter = getAvailableMplsLabels(link) - .iterator(); - if (mplsIter.hasNext()) { - allocsPerLink.get(link) - .add(new MplsLabelResourceAllocation(mplsIter - .next())); + + Optional<MplsLabel> label = req.resources(link).stream() + .filter(x -> x.type() == ResourceType.MPLS_LABEL) + .map(x -> (MplsLabelResourceRequest) x) + .map(MplsLabelResourceRequest::mplsLabel) + .findFirst(); + + if (label.isPresent()) { + allocsPerLink.get(link).add(new MplsLabelResourceAllocation(label.get())); } else { log.info("Failed to allocate MPLS resource."); break; @@ -258,10 +190,12 @@ public class LinkResourceManager ((BandwidthResourceAllocation) alloc).bandwidth())); break; case LAMBDA: - result.add(new LambdaResourceRequest()); + result.add(new LambdaResourceRequest( + ((LambdaResourceAllocation) alloc).lambda())); break; case MPLS_LABEL: - result.add(new MplsLabelResourceRequest()); + result.add(new MplsLabelResourceRequest( + ((MplsLabelResourceAllocation) alloc).mplsLabel())); break; default: break; diff --git a/framework/src/onos/core/net/src/test/java/org/onosproject/net/intent/impl/compiler/MockResourceService.java b/framework/src/onos/core/net/src/test/java/org/onosproject/net/intent/impl/compiler/MockResourceService.java new file mode 100644 index 00000000..06b2c81e --- /dev/null +++ b/framework/src/onos/core/net/src/test/java/org/onosproject/net/intent/impl/compiler/MockResourceService.java @@ -0,0 +1,100 @@ +/* + * 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.net.intent.impl.compiler; + +import com.google.common.collect.ImmutableList; +import org.onlab.packet.MplsLabel; +import org.onosproject.net.newresource.ResourceAllocation; +import org.onosproject.net.newresource.ResourceConsumer; +import org.onosproject.net.newresource.ResourcePath; +import org.onosproject.net.newresource.ResourceService; + +import java.util.Collection; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.stream.Collectors; + +class MockResourceService implements ResourceService { + + private final Map<ResourcePath, ResourceConsumer> assignment = new HashMap<>(); + + @Override + public List<ResourceAllocation> allocate(ResourceConsumer consumer, List<ResourcePath> resources) { + assignment.putAll( + resources.stream().collect(Collectors.toMap(x -> x, x -> consumer)) + ); + + return resources.stream() + .map(x -> new ResourceAllocation(x, consumer)) + .collect(Collectors.toList()); + } + + @Override + public boolean release(List<ResourceAllocation> allocations) { + allocations.forEach(x -> assignment.remove(x.resource())); + + return true; + } + + @Override + public boolean release(ResourceConsumer consumer) { + List<ResourcePath> resources = assignment.entrySet().stream() + .filter(x -> x.getValue().equals(consumer)) + .map(Map.Entry::getKey) + .collect(Collectors.toList()); + List<ResourceAllocation> allocations = resources.stream() + .map(x -> new ResourceAllocation(x, consumer)) + .collect(Collectors.toList()); + + return release(allocations); + } + + @Override + public Optional<ResourceAllocation> getResourceAllocation(ResourcePath resource) { + return Optional.ofNullable(assignment.get(resource)) + .map(x -> new ResourceAllocation(resource, x)); + } + + @Override + public <T> Collection<ResourceAllocation> getResourceAllocations(ResourcePath parent, Class<T> cls) { + return assignment.entrySet().stream() + .filter(x -> x.getKey().parent().isPresent()) + .filter(x -> x.getKey().parent().get().equals(parent)) + .map(x -> new ResourceAllocation(x.getKey(), x.getValue())) + .collect(Collectors.toList()); + } + + @Override + public Collection<ResourceAllocation> getResourceAllocations(ResourceConsumer consumer) { + return assignment.entrySet().stream() + .filter(x -> x.getValue().equals(consumer)) + .map(x -> new ResourceAllocation(x.getKey(), x.getValue())) + .collect(Collectors.toList()); + } + + @Override + public Collection<ResourcePath> getAvailableResources(ResourcePath parent) { + ResourcePath resource = ResourcePath.child(parent, MplsLabel.mplsLabel(10)); + return ImmutableList.of(resource); + } + + @Override + public boolean isAvailable(ResourcePath resource) { + return true; + } +} diff --git a/framework/src/onos/core/net/src/test/java/org/onosproject/net/intent/impl/compiler/MplsPathIntentCompilerTest.java b/framework/src/onos/core/net/src/test/java/org/onosproject/net/intent/impl/compiler/MplsPathIntentCompilerTest.java index 771a9883..6cceee12 100644 --- a/framework/src/onos/core/net/src/test/java/org/onosproject/net/intent/impl/compiler/MplsPathIntentCompilerTest.java +++ b/framework/src/onos/core/net/src/test/java/org/onosproject/net/intent/impl/compiler/MplsPathIntentCompilerTest.java @@ -41,10 +41,8 @@ import org.onosproject.net.flow.TrafficTreatment; import org.onosproject.net.intent.FlowRuleIntent; import org.onosproject.net.intent.Intent; import org.onosproject.net.intent.IntentExtensionService; -import org.onosproject.net.intent.IntentTestsMocks; import org.onosproject.net.intent.MockIdGenerator; import org.onosproject.net.intent.MplsPathIntent; -import org.onosproject.store.trivial.SimpleLinkStore; import static org.easymock.EasyMock.createMock; import static org.easymock.EasyMock.expect; @@ -52,6 +50,7 @@ import static org.easymock.EasyMock.replay; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.hasSize; import static org.hamcrest.Matchers.is; +import static org.onosproject.net.DefaultEdgeLink.createEdgeLink; import static org.onosproject.net.Link.Type.DIRECT; import static org.onosproject.net.NetTestTools.APP_ID; import static org.onosproject.net.NetTestTools.PID; @@ -61,10 +60,12 @@ public class MplsPathIntentCompilerTest { private final ApplicationId appId = new TestApplicationId("test"); + private final ConnectPoint d1pi = connectPoint("s1", 100); private final ConnectPoint d1p1 = connectPoint("s1", 0); private final ConnectPoint d2p0 = connectPoint("s2", 0); private final ConnectPoint d2p1 = connectPoint("s2", 1); private final ConnectPoint d3p1 = connectPoint("s3", 1); + private final ConnectPoint d3pe = connectPoint("s3", 100); private final TrafficSelector selector = DefaultTrafficSelector.builder().build(); private final TrafficTreatment treatment = DefaultTrafficTreatment.builder().build(); @@ -75,8 +76,10 @@ public class MplsPathIntentCompilerTest { Optional.of(MplsLabel.mplsLabel(20)); private final List<Link> links = Arrays.asList( + createEdgeLink(d1pi, true), new DefaultLink(PID, d1p1, d2p0, DIRECT), - new DefaultLink(PID, d2p1, d3p1, DIRECT) + new DefaultLink(PID, d2p1, d3p1, DIRECT), + createEdgeLink(d3pe, false) ); private IdGenerator idGenerator = new MockIdGenerator(); @@ -92,8 +95,7 @@ public class MplsPathIntentCompilerTest { expect(coreService.registerApplication("org.onosproject.net.intent")) .andReturn(appId); sut.coreService = coreService; - sut.linkStore = new SimpleLinkStore(); - sut.resourceService = new IntentTestsMocks.MockResourceService(); + sut.resourceService = new MockResourceService(); Intent.bindIdGenerator(idGenerator); @@ -128,7 +130,7 @@ public class MplsPathIntentCompilerTest { assertThat(compiled, hasSize(1)); Collection<FlowRule> rules = ((FlowRuleIntent) compiled.get(0)).flowRules(); - assertThat(rules, hasSize(1)); + assertThat(rules, hasSize(3)); FlowRule rule = rules.stream() .filter(x -> x.deviceId().equals(d2p0.deviceId())) @@ -139,4 +141,5 @@ public class MplsPathIntentCompilerTest { sut.deactivate(); } + } diff --git a/framework/src/onos/core/net/src/test/java/org/onosproject/net/proxyarp/impl/ProxyArpManagerTest.java b/framework/src/onos/core/net/src/test/java/org/onosproject/net/proxyarp/impl/ProxyArpManagerTest.java index 1a160d98..3e806a73 100644 --- a/framework/src/onos/core/net/src/test/java/org/onosproject/net/proxyarp/impl/ProxyArpManagerTest.java +++ b/framework/src/onos/core/net/src/test/java/org/onosproject/net/proxyarp/impl/ProxyArpManagerTest.java @@ -21,11 +21,19 @@ import org.junit.Before; import org.junit.Test; import org.onlab.packet.ARP; import org.onlab.packet.Ethernet; +import org.onlab.packet.ICMP6; +import org.onlab.packet.IPacket; +import org.onlab.packet.IPv6; import org.onlab.packet.Ip4Address; import org.onlab.packet.Ip4Prefix; +import org.onlab.packet.Ip6Address; +import org.onlab.packet.Ip6Prefix; import org.onlab.packet.IpPrefix; import org.onlab.packet.MacAddress; import org.onlab.packet.VlanId; +import org.onlab.packet.ndp.NeighborAdvertisement; +import org.onlab.packet.ndp.NeighborDiscoveryOptions; +import org.onlab.packet.ndp.NeighborSolicitation; import org.onosproject.incubator.net.intf.Interface; import org.onosproject.incubator.net.intf.InterfaceService; import org.onosproject.net.ConnectPoint; @@ -66,9 +74,13 @@ import static org.easymock.EasyMock.anyObject; import static org.easymock.EasyMock.createMock; import static org.easymock.EasyMock.expect; import static org.easymock.EasyMock.replay; +import static org.hamcrest.Matchers.anyOf; +import static org.hamcrest.Matchers.is; import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertThat; import static org.junit.Assert.assertTrue; /** @@ -83,6 +95,8 @@ public class ProxyArpManagerTest { private static final Ip4Address IP1 = Ip4Address.valueOf("192.168.1.1"); private static final Ip4Address IP2 = Ip4Address.valueOf("192.168.1.2"); + private static final Ip6Address IP3 = Ip6Address.valueOf("1000::1"); + private static final Ip6Address IP4 = Ip6Address.valueOf("1000::2"); private static final ProviderId PID = new ProviderId("of", "foo"); @@ -90,8 +104,14 @@ public class ProxyArpManagerTest { private static final VlanId VLAN2 = VlanId.vlanId((short) 2); private static final MacAddress MAC1 = MacAddress.valueOf("00:00:11:00:00:01"); private static final MacAddress MAC2 = MacAddress.valueOf("00:00:22:00:00:02"); + private static final MacAddress MAC3 = MacAddress.valueOf("00:00:33:00:00:03"); + private static final MacAddress MAC4 = MacAddress.valueOf("00:00:44:00:00:04"); + private static final MacAddress SOLICITED_MAC3 = MacAddress.valueOf("33:33:FF:00:00:01"); private static final HostId HID1 = HostId.hostId(MAC1, VLAN1); private static final HostId HID2 = HostId.hostId(MAC2, VLAN1); + private static final HostId HID3 = HostId.hostId(MAC3, VLAN1); + private static final HostId HID4 = HostId.hostId(MAC4, VLAN1); + private static final HostId SOLICITED_HID3 = HostId.hostId(SOLICITED_MAC3, VLAN1); private static final DeviceId DID1 = getDeviceId(1); private static final DeviceId DID2 = getDeviceId(2); @@ -222,21 +242,29 @@ public class ProxyArpManagerTest { for (int i = 1; i <= NUM_ADDRESS_PORTS; i++) { ConnectPoint cp = new ConnectPoint(getDeviceId(i), P1); - Ip4Prefix prefix1 = - Ip4Prefix.valueOf("10.0." + (2 * i - 1) + ".0/24"); - Ip4Address addr1 = - Ip4Address.valueOf("10.0." + (2 * i - 1) + ".1"); + + // Interface address for IPv4 + Ip4Prefix prefix1 = Ip4Prefix.valueOf("10.0." + (2 * i - 1) + ".0/24"); + Ip4Address addr1 = Ip4Address.valueOf("10.0." + (2 * i - 1) + ".1"); Ip4Prefix prefix2 = Ip4Prefix.valueOf("10.0." + (2 * i) + ".0/24"); Ip4Address addr2 = Ip4Address.valueOf("10.0." + (2 * i) + ".1"); InterfaceIpAddress ia1 = new InterfaceIpAddress(addr1, prefix1); InterfaceIpAddress ia2 = new InterfaceIpAddress(addr2, prefix2); - Interface intf1 = new Interface(cp, Sets.newHashSet(ia1), + + // Interface address for IPv6 + Ip6Prefix prefix3 = Ip6Prefix.valueOf((2 * i - 1) + "000::0/64"); + Ip6Address addr3 = Ip6Address.valueOf((2 * i - 1) + "000::1"); + Ip6Prefix prefix4 = Ip6Prefix.valueOf((2 * i) + "000::0/64"); + Ip6Address addr4 = Ip6Address.valueOf((2 * i) + "000::1"); + InterfaceIpAddress ia3 = new InterfaceIpAddress(addr3, prefix3); + InterfaceIpAddress ia4 = new InterfaceIpAddress(addr4, prefix4); + + Interface intf1 = new Interface(cp, Sets.newHashSet(ia1, ia3), MacAddress.valueOf(2 * i - 1), VlanId.vlanId((short) 1)); - Interface intf2 = new Interface(cp, Sets.newHashSet(ia2), + Interface intf2 = new Interface(cp, Sets.newHashSet(ia2, ia4), MacAddress.valueOf(2 * i), VlanId.NONE); - interfaces.add(intf1); interfaces.add(intf2); @@ -321,6 +349,41 @@ public class ProxyArpManagerTest { /** * Tests {@link ProxyArpManager#reply(Ethernet, ConnectPoint)} in the case where the + * destination host is known. + * Verifies the correct NDP reply is sent out the correct port. + */ + @Test + public void testReplyKnownIpv6() { + //Set the return value of isEdgePoint from the edgemanager. + isEdgePointReturn = true; + + Host replyer = new DefaultHost(PID, HID3, MAC3, VLAN1, getLocation(4), + Collections.singleton(IP3)); + + Host requestor = new DefaultHost(PID, HID4, MAC4, VLAN1, getLocation(5), + Collections.singleton(IP4)); + + expect(hostService.getHostsByIp(IP3)) + .andReturn(Collections.singleton(replyer)); + expect(hostService.getHost(HID4)).andReturn(requestor); + + replay(hostService); + replay(interfaceService); + + Ethernet ndpRequest = buildNDP(ICMP6.NEIGHBOR_SOLICITATION, + MAC4, SOLICITED_MAC3, + IP4, IP3); + + proxyArp.reply(ndpRequest, getLocation(5)); + + assertEquals(1, packetService.packets.size()); + Ethernet ndpReply = buildNDP(ICMP6.NEIGHBOR_ADVERTISEMENT, + MAC3, MAC4, IP3, IP4); + verifyPacketOut(ndpReply, getLocation(5), packetService.packets.get(0)); + } + + /** + * Tests {@link ProxyArpManager#reply(Ethernet, ConnectPoint)} in the case where the * destination host is not known. * Verifies the ARP request is flooded out the correct edge ports. */ @@ -337,7 +400,6 @@ public class ProxyArpManagerTest { .andReturn(Collections.emptySet()); expect(hostService.getHost(HID2)).andReturn(requestor); - replay(hostService); replay(interfaceService); @@ -355,6 +417,41 @@ public class ProxyArpManagerTest { /** * Tests {@link ProxyArpManager#reply(Ethernet, ConnectPoint)} in the case where the + * destination host is not known. + * Verifies the NDP request is flooded out the correct edge ports. + */ + @Test + public void testReplyUnknownIpv6() { + isEdgePointReturn = true; + + Host requestor = new DefaultHost(PID, HID4, MAC4, VLAN1, getLocation(5), + Collections.singleton(IP4)); + + expect(hostService.getHostsByIp(IP3)) + .andReturn(Collections.emptySet()); + expect(interfaceService.getInterfacesByIp(IP4)) + .andReturn(Collections.emptySet()); + expect(hostService.getHost(HID4)).andReturn(requestor); + + replay(hostService); + replay(interfaceService); + + Ethernet ndpRequest = buildNDP(ICMP6.NEIGHBOR_SOLICITATION, + MAC4, SOLICITED_MAC3, + IP4, IP3); + + //Setup the set of edge ports to be used in the reply method + getEdgePointsNoArg = Lists.newLinkedList(); + getEdgePointsNoArg.add(new ConnectPoint(DeviceId.deviceId("5"), PortNumber.portNumber(1))); + getEdgePointsNoArg.add(new ConnectPoint(DeviceId.deviceId("4"), PortNumber.portNumber(1))); + + proxyArp.reply(ndpRequest, getLocation(6)); + + verifyFlood(ndpRequest); + } + + /** + * Tests {@link ProxyArpManager#reply(Ethernet, ConnectPoint)} in the case where the * destination host is known for that IP address, but is not on the same * VLAN as the source host. * Verifies the ARP request is flooded out the correct edge ports. @@ -388,6 +485,46 @@ public class ProxyArpManagerTest { verifyFlood(arpRequest); } + /** + * Tests {@link ProxyArpManager#reply(Ethernet, ConnectPoint)} in the case where the + * destination host is known for that IP address, but is not on the same + * VLAN as the source host. + * Verifies the NDP request is flooded out the correct edge ports. + */ + @Test + public void testReplyDifferentVlanIpv6() { + + Host replyer = new DefaultHost(PID, HID3, MAC3, VLAN2, getLocation(4), + Collections.singleton(IP3)); + + Host requestor = new DefaultHost(PID, HID4, MAC4, VLAN1, getLocation(5), + Collections.singleton(IP4)); + + expect(hostService.getHostsByIp(IP3)) + .andReturn(Collections.singleton(replyer)); + expect(interfaceService.getInterfacesByIp(IP4)) + .andReturn(Collections.emptySet()); + expect(hostService.getHost(HID4)).andReturn(requestor); + + replay(hostService); + replay(interfaceService); + + Ethernet ndpRequest = buildNDP(ICMP6.NEIGHBOR_SOLICITATION, + MAC4, SOLICITED_MAC3, + IP4, IP3); + + //Setup for flood test + getEdgePointsNoArg = Lists.newLinkedList(); + getEdgePointsNoArg.add(new ConnectPoint(DeviceId.deviceId("5"), PortNumber.portNumber(1))); + getEdgePointsNoArg.add(new ConnectPoint(DeviceId.deviceId("4"), PortNumber.portNumber(1))); + proxyArp.reply(ndpRequest, getLocation(6)); + + verifyFlood(ndpRequest); + } + + /** + * Test ARP request from external network to an internal host. + */ @Test public void testReplyToRequestForUs() { Ip4Address theirIp = Ip4Address.valueOf("10.0.1.254"); @@ -422,6 +559,63 @@ public class ProxyArpManagerTest { verifyPacketOut(arpReply, LOC1, packetService.packets.get(0)); } + /** + * Test NDP request from external network to an internal host. + */ + @Test + public void testReplyToRequestForUsIpv6() { + Ip6Address theirIp = Ip6Address.valueOf("1000::ffff"); + Ip6Address ourFirstIp = Ip6Address.valueOf("1000::1"); + Ip6Address ourSecondIp = Ip6Address.valueOf("2000::1"); + MacAddress firstMac = MacAddress.valueOf(1L); + MacAddress secondMac = MacAddress.valueOf(2L); + + Host requestor = new DefaultHost(PID, HID2, MAC2, VLAN1, LOC1, + Collections.singleton(theirIp)); + + expect(hostService.getHost(HID2)).andReturn(requestor); + expect(hostService.getHostsByIp(ourFirstIp)) + .andReturn(Collections.singleton(requestor)); + replay(hostService); + replay(interfaceService); + + Ethernet ndpRequest = buildNDP(ICMP6.NEIGHBOR_SOLICITATION, + MAC2, + MacAddress.valueOf("33:33:ff:00:00:01"), + theirIp, + ourFirstIp); + isEdgePointReturn = true; + proxyArp.reply(ndpRequest, LOC1); + assertEquals(1, packetService.packets.size()); + + Ethernet ndpReply = buildNDP(ICMP6.NEIGHBOR_ADVERTISEMENT, + firstMac, + MAC2, + ourFirstIp, + theirIp); + verifyPacketOut(ndpReply, LOC1, packetService.packets.get(0)); + + // Test a request for the second address on that port + packetService.packets.clear(); + ndpRequest = buildNDP(ICMP6.NEIGHBOR_SOLICITATION, + MAC2, + MacAddress.valueOf("33:33:ff:00:00:01"), + theirIp, + ourSecondIp); + proxyArp.reply(ndpRequest, LOC1); + assertEquals(1, packetService.packets.size()); + + ndpReply = buildNDP(ICMP6.NEIGHBOR_ADVERTISEMENT, + secondMac, + MAC2, + ourSecondIp, + theirIp); + verifyPacketOut(ndpReply, LOC1, packetService.packets.get(0)); + } + + /** + * Request for a valid external IPv4 address but coming in the wrong port. + */ @Test public void testReplyExternalPortBadRequest() { replay(hostService); // no further host service expectations @@ -442,6 +636,38 @@ public class ProxyArpManagerTest { assertEquals(0, packetService.packets.size()); } + /** + * Request for a valid external IPv6 address but coming in the wrong port. + */ + @Test + public void testReplyExternalPortBadRequestIpv6() { + replay(hostService); // no further host service expectations + replay(interfaceService); + + Ip6Address theirIp = Ip6Address.valueOf("1000::ffff"); + + Ethernet ndpRequest = buildNDP(ICMP6.NEIGHBOR_SOLICITATION, + MAC1, + MacAddress.valueOf("33:33:ff:00:00:01"), + theirIp, + Ip6Address.valueOf("3000::1")); + proxyArp.reply(ndpRequest, LOC1); + assertEquals(0, packetService.packets.size()); + + // Request for a valid internal IP address but coming in an external port + packetService.packets.clear(); + ndpRequest = buildNDP(ICMP6.NEIGHBOR_SOLICITATION, + MAC1, + MacAddress.valueOf("33:33:ff:00:00:01"), + theirIp, + IP3); + proxyArp.reply(ndpRequest, LOC1); + assertEquals(0, packetService.packets.size()); + } + + /** + * Test ARP request from internal network to an external host. + */ @Test public void testReplyToRequestFromUs() { Ip4Address ourIp = Ip4Address.valueOf("10.0.1.1"); @@ -474,6 +700,48 @@ public class ProxyArpManagerTest { } /** + * Test NDP request from internal network to an external host. + */ + @Test + public void testReplyToRequestFromUsIpv6() { + Ip6Address ourIp = Ip6Address.valueOf("1000::1"); + MacAddress ourMac = MacAddress.valueOf(1L); + Ip6Address theirIp = Ip6Address.valueOf("1000::100"); + + expect(hostService.getHostsByIp(theirIp)).andReturn(Collections.emptySet()); + expect(interfaceService.getInterfacesByIp(ourIp)) + .andReturn(Collections.singleton(new Interface(getLocation(1), + Collections.singleton(new InterfaceIpAddress( + ourIp, + IpPrefix.valueOf("1000::1/64"))), + ourMac, + VLAN1))); + expect(hostService.getHost(HostId.hostId(ourMac, VLAN1))).andReturn(null); + replay(hostService); + replay(interfaceService); + + // This is a request from something inside our network (like a BGP + // daemon) to an external host. + Ethernet ndpRequest = buildNDP(ICMP6.NEIGHBOR_SOLICITATION, + ourMac, + MacAddress.valueOf("33:33:ff:00:00:01"), + ourIp, + theirIp); + + //Ensure the packet is allowed through (it is not to an internal port) + isEdgePointReturn = true; + + proxyArp.reply(ndpRequest, getLocation(5)); + assertEquals(1, packetService.packets.size()); + verifyPacketOut(ndpRequest, getLocation(1), packetService.packets.get(0)); + + // The same request from a random external port should fail + packetService.packets.clear(); + proxyArp.reply(ndpRequest, getLocation(2)); + assertEquals(0, packetService.packets.size()); + } + + /** * Tests {@link ProxyArpManager#forward(Ethernet, ConnectPoint)} in the case where the * destination host is known. * Verifies the correct ARP request is sent out the correct port. @@ -502,6 +770,35 @@ public class ProxyArpManagerTest { /** * Tests {@link ProxyArpManager#forward(Ethernet, ConnectPoint)} in the case where the + * destination host is known. + * Verifies the correct ARP request is sent out the correct port. + */ + @Test + public void testForwardToHostIpv6() { + Host host1 = new DefaultHost(PID, HID3, MAC3, VLAN1, LOC1, + Collections.singleton(IP3)); + Host host2 = new DefaultHost(PID, HID4, MAC4, VLAN1, LOC2, + Collections.singleton(IP4)); + + expect(hostService.getHost(SOLICITED_HID3)).andReturn(host1); + expect(hostService.getHost(HID4)).andReturn(host2); + replay(hostService); + replay(interfaceService); + + Ethernet ndpRequest = buildNDP(ICMP6.NEIGHBOR_SOLICITATION, + MAC4, SOLICITED_MAC3, + IP4, IP3); + + proxyArp.forward(ndpRequest, LOC2); + + assertEquals(1, packetService.packets.size()); + OutboundPacket packet = packetService.packets.get(0); + + verifyPacketOut(ndpRequest, LOC1, packet); + } + + /** + * Tests {@link ProxyArpManager#forward(Ethernet, ConnectPoint)} in the case where the * destination host is not known. * Verifies the correct ARP request is flooded out the correct edge ports. */ @@ -526,6 +823,33 @@ public class ProxyArpManagerTest { } /** + * Tests {@link ProxyArpManager#forward(Ethernet, ConnectPoint)} in the case where the + * destination host is not known. + * Verifies the correct NDP request is flooded out the correct edge ports. + */ + @Test + public void testForwardFloodIpv6() { + expect(hostService.getHost(SOLICITED_HID3)).andReturn(null); + replay(hostService); + replay(interfaceService); + + Ethernet ndpRequest = buildNDP(ICMP6.NEIGHBOR_SOLICITATION, + MAC4, SOLICITED_MAC3, + IP4, IP3); + + //populate the list of edges when so that when forward hits flood in the manager it contains the values + //that should continue on + getEdgePointsNoArg = Lists.newLinkedList(); + getEdgePointsNoArg.add(new ConnectPoint(DeviceId.deviceId("3"), PortNumber.portNumber(1))); + getEdgePointsNoArg.add(new ConnectPoint(DeviceId.deviceId("5"), PortNumber.portNumber(1))); + getEdgePointsNoArg.add(new ConnectPoint(DeviceId.deviceId("4"), PortNumber.portNumber(1))); + + proxyArp.forward(ndpRequest, getLocation(6)); + + verifyFlood(ndpRequest); + } + + /** * Verifies that the given packet was flooded out all available edge ports, * except for the input port. * @@ -626,6 +950,61 @@ public class ProxyArpManagerTest { } /** + * Builds an NDP packet with the given parameters. + * + * @param type NeighborSolicitation or NeighborAdvertisement + * @param srcMac source MAC address + * @param dstMac destination MAC address, or null if this is a request + * @param srcIp source IP address + * @param dstIp destination IP address + * @return the NDP packet + */ + private Ethernet buildNDP(byte type, MacAddress srcMac, MacAddress dstMac, + Ip6Address srcIp, Ip6Address dstIp) { + assertThat(type, anyOf( + is(ICMP6.NEIGHBOR_SOLICITATION), + is(ICMP6.NEIGHBOR_ADVERTISEMENT) + )); + assertNotNull(srcMac); + assertNotNull(dstMac); + assertNotNull(srcIp); + assertNotNull(dstIp); + + IPacket ndp; + if (type == ICMP6.NEIGHBOR_SOLICITATION) { + ndp = new NeighborSolicitation().setTargetAddress(dstIp.toOctets()); + } else { + ndp = new NeighborAdvertisement() + .setSolicitedFlag((byte) 1) + .setOverrideFlag((byte) 1) + .setTargetAddress(srcIp.toOctets()) + .addOption(NeighborDiscoveryOptions.TYPE_TARGET_LL_ADDRESS, + srcMac.toBytes()); + } + + ICMP6 icmp6 = new ICMP6(); + icmp6.setIcmpType(type); + icmp6.setIcmpCode((byte) 0); + icmp6.setPayload(ndp); + + IPv6 ipv6 = new IPv6(); + ipv6.setDestinationAddress(dstIp.toOctets()); + ipv6.setSourceAddress(srcIp.toOctets()); + ipv6.setNextHeader(IPv6.PROTOCOL_ICMP6); + ipv6.setHopLimit((byte) 255); + ipv6.setPayload(icmp6); + + Ethernet eth = new Ethernet(); + eth.setDestinationMACAddress(dstMac); + eth.setSourceMACAddress(srcMac); + eth.setEtherType(Ethernet.TYPE_IPV6); + eth.setVlanID(VLAN1.toShort()); + eth.setPayload(ipv6); + + return eth; + } + + /** * Test PacketService implementation that simply stores OutboundPackets * passed to {@link #emit(OutboundPacket)} for later verification. */ diff --git a/framework/src/onos/core/store/dist/pom.xml b/framework/src/onos/core/store/dist/pom.xml index cc293da4..f2ec2a71 100644 --- a/framework/src/onos/core/store/dist/pom.xml +++ b/framework/src/onos/core/store/dist/pom.xml @@ -71,7 +71,7 @@ <dependency> <groupId>org.mapdb</groupId> <artifactId>mapdb</artifactId> - <version>1.0.7</version> + <version>1.0.8</version> </dependency> <dependency> diff --git a/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/cluster/impl/ClusterDefinition.java b/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/cluster/impl/ClusterDefinition.java deleted file mode 100644 index 75f05a31..00000000 --- a/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/cluster/impl/ClusterDefinition.java +++ /dev/null @@ -1,58 +0,0 @@ -/* - * 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.store.cluster.impl; - -import java.util.Set; - -import com.google.common.collect.ImmutableSet; - -/** - * Cluster definition. - */ -public class ClusterDefinition { - - private Set<NodeInfo> nodes; - private String ipPrefix; - - /** - * Creates a new cluster definition. - * @param nodes cluster nodes information - * @param ipPrefix ip prefix common to all cluster nodes - * @return cluster definition - */ - public static ClusterDefinition from(Set<NodeInfo> nodes, String ipPrefix) { - ClusterDefinition definition = new ClusterDefinition(); - definition.ipPrefix = ipPrefix; - definition.nodes = ImmutableSet.copyOf(nodes); - return definition; - } - - /** - * Returns set of cluster nodes info. - * @return cluster nodes info - */ - public Set<NodeInfo> getNodes() { - return ImmutableSet.copyOf(nodes); - } - - /** - * Returns ipPrefix in dotted decimal notion. - * @return ip prefix - */ - public String getIpPrefix() { - return ipPrefix; - } -}
\ No newline at end of file diff --git a/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/cluster/impl/ClusterDefinitionManager.java b/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/cluster/impl/ClusterDefinitionManager.java deleted file mode 100644 index 8b0001d8..00000000 --- a/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/cluster/impl/ClusterDefinitionManager.java +++ /dev/null @@ -1,194 +0,0 @@ -/* - * 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.store.cluster.impl; - -import com.google.common.collect.ImmutableSet; -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.Service; -import org.onlab.packet.IpAddress; -import org.onosproject.cluster.ClusterDefinitionService; -import org.onosproject.cluster.ControllerNode; -import org.onosproject.cluster.DefaultControllerNode; -import org.onosproject.cluster.NodeId; -import org.onosproject.store.consistent.impl.DatabaseDefinition; -import org.onosproject.store.consistent.impl.DatabaseDefinitionStore; -import org.slf4j.Logger; - -import java.io.File; -import java.io.IOException; -import java.net.InetAddress; -import java.net.NetworkInterface; -import java.net.SocketException; -import java.util.Enumeration; -import java.util.Set; -import java.util.stream.Collectors; - -import static java.net.NetworkInterface.getNetworkInterfaces; -import static java.util.Collections.list; -import static org.onosproject.cluster.DefaultControllerNode.DEFAULT_PORT; -import static org.onosproject.store.consistent.impl.DatabaseManager.PARTITION_DEFINITION_FILE; -import static org.slf4j.LoggerFactory.getLogger; - -/** - * Implementation of ClusterDefinitionService. - */ -@Component(immediate = true) -@Service -public class ClusterDefinitionManager implements ClusterDefinitionService { - - public static final String CLUSTER_DEFINITION_FILE = "../config/cluster.json"; - private static final String ONOS_NIC = "ONOS_NIC"; - private static final Logger log = getLogger(ClusterDefinitionManager.class); - private ControllerNode localNode; - private Set<ControllerNode> seedNodes; - - @Activate - public void activate() { - File clusterDefinitionFile = new File(CLUSTER_DEFINITION_FILE); - ClusterDefinitionStore clusterDefinitionStore = - new ClusterDefinitionStore(clusterDefinitionFile.getPath()); - - if (!clusterDefinitionFile.exists()) { - createDefaultClusterDefinition(clusterDefinitionStore); - } - - try { - ClusterDefinition clusterDefinition = clusterDefinitionStore.read(); - establishSelfIdentity(clusterDefinition); - seedNodes = ImmutableSet - .copyOf(clusterDefinition.getNodes()) - .stream() - .filter(n -> !localNode.id().equals(new NodeId(n.getId()))) - .map(n -> new DefaultControllerNode(new NodeId(n.getId()), - IpAddress.valueOf(n.getIp()), - n.getTcpPort())) - .collect(Collectors.toSet()); - } catch (IOException e) { - throw new IllegalStateException("Failed to read cluster definition.", e); - } - - log.info("Started"); - } - - @Deactivate - public void deactivate() { - log.info("Stopped"); - } - - @Override - public ControllerNode localNode() { - return localNode; - } - - @Override - public Set<ControllerNode> seedNodes() { - return seedNodes; - } - - @Override - public void formCluster(Set<ControllerNode> nodes, String ipPrefix) { - try { - Set<NodeInfo> infos = Sets.newHashSet(); - nodes.forEach(n -> infos.add(NodeInfo.from(n.id().toString(), - n.ip().toString(), - n.tcpPort()))); - - ClusterDefinition cdef = ClusterDefinition.from(infos, ipPrefix); - new ClusterDefinitionStore(CLUSTER_DEFINITION_FILE).write(cdef); - - DatabaseDefinition ddef = DatabaseDefinition.from(infos); - new DatabaseDefinitionStore(PARTITION_DEFINITION_FILE).write(ddef); - } catch (IOException e) { - log.error("Unable to form cluster", e); - } - } - - private IpAddress findLocalIp(ClusterDefinition clusterDefinition) throws SocketException { - Enumeration<NetworkInterface> interfaces = - NetworkInterface.getNetworkInterfaces(); - while (interfaces.hasMoreElements()) { - NetworkInterface iface = interfaces.nextElement(); - Enumeration<InetAddress> inetAddresses = iface.getInetAddresses(); - while (inetAddresses.hasMoreElements()) { - IpAddress ip = IpAddress.valueOf(inetAddresses.nextElement()); - if (clusterDefinition.getNodes().stream() - .map(NodeInfo::getIp) - .map(IpAddress::valueOf) - .anyMatch(nodeIp -> ip.equals(nodeIp))) { - return ip; - } - } - } - throw new IllegalStateException("Unable to determine local ip"); - } - - private void establishSelfIdentity(ClusterDefinition clusterDefinition) { - try { - IpAddress ip = findLocalIp(clusterDefinition); - localNode = new DefaultControllerNode(new NodeId(ip.toString()), ip); - } catch (SocketException e) { - throw new IllegalStateException("Cannot determine local IP", e); - } - } - - private void createDefaultClusterDefinition(ClusterDefinitionStore store) { - // Assumes IPv4 is returned. - String ip = getSiteLocalAddress(); - String ipPrefix = ip.replaceFirst("\\.[0-9]*$", ".*"); - NodeInfo node = NodeInfo.from(ip, ip, DEFAULT_PORT); - try { - store.write(ClusterDefinition.from(ImmutableSet.of(node), ipPrefix)); - } catch (IOException e) { - log.warn("Unable to write default cluster definition", e); - } - } - - /** - * Returns the address that matches the IP prefix given in ONOS_NIC - * environment variable if one was specified, or the first site local - * address if one can be found or the loopback address otherwise. - * - * @return site-local address in string form - */ - public static String getSiteLocalAddress() { - try { - String ipPrefix = System.getenv(ONOS_NIC); - for (NetworkInterface nif : list(getNetworkInterfaces())) { - for (InetAddress address : list(nif.getInetAddresses())) { - IpAddress ip = IpAddress.valueOf(address); - if (ipPrefix == null && address.isSiteLocalAddress() || - ipPrefix != null && matchInterface(ip.toString(), ipPrefix)) { - return ip.toString(); - } - } - } - } catch (SocketException e) { - log.error("Unable to get network interfaces", e); - } - - return IpAddress.valueOf(InetAddress.getLoopbackAddress()).toString(); - } - - // Indicates whether the specified interface address matches the given prefix. - // FIXME: Add a facility to IpPrefix to make this more robust - private static boolean matchInterface(String ip, String ipPrefix) { - String s = ipPrefix.replaceAll("\\.\\*", ""); - return ip.startsWith(s); - } -} diff --git a/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/cluster/impl/ClusterDefinitionStore.java b/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/cluster/impl/ClusterDefinitionStore.java deleted file mode 100644 index 2a2f4dc4..00000000 --- a/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/cluster/impl/ClusterDefinitionStore.java +++ /dev/null @@ -1,63 +0,0 @@ -/* - * 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.store.cluster.impl; - -import static com.google.common.base.Preconditions.checkNotNull; - -import com.fasterxml.jackson.databind.ObjectMapper; -import com.google.common.io.Files; - -import java.io.File; -import java.io.IOException; - -/** - * Allows for reading and writing cluster definition as a JSON file. - */ -public class ClusterDefinitionStore { - - private final File file; - - /** - * Creates a reader/writer of the cluster definition file. - * @param filePath location of the definition file - */ - public ClusterDefinitionStore(String filePath) { - file = new File(filePath); - } - - /** - * Returns the cluster definition. - * @return cluster definition - * @throws IOException when I/O exception of some sort has occurred - */ - public ClusterDefinition read() throws IOException { - ObjectMapper mapper = new ObjectMapper(); - return mapper.readValue(file, ClusterDefinition.class); - } - - /** - * Writes the specified cluster definition to file. - * @param definition cluster definition - * @throws IOException when I/O exception of some sort has occurred - */ - public void write(ClusterDefinition definition) throws IOException { - checkNotNull(definition); - // write back to file - Files.createParentDirs(file); - ObjectMapper mapper = new ObjectMapper(); - mapper.writeValue(file, definition); - } -} diff --git a/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/cluster/impl/DistributedClusterStore.java b/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/cluster/impl/DistributedClusterStore.java index 859efebf..3bb6a708 100644 --- a/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/cluster/impl/DistributedClusterStore.java +++ b/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/cluster/impl/DistributedClusterStore.java @@ -27,8 +27,8 @@ import org.apache.felix.scr.annotations.Service; import org.joda.time.DateTime; import org.onlab.packet.IpAddress; import org.onlab.util.KryoNamespace; -import org.onosproject.cluster.ClusterDefinitionService; import org.onosproject.cluster.ClusterEvent; +import org.onosproject.cluster.ClusterMetadataService; import org.onosproject.cluster.ClusterStore; import org.onosproject.cluster.ClusterStoreDelegate; import org.onosproject.cluster.ControllerNode; @@ -99,14 +99,14 @@ public class DistributedClusterStore private ControllerNode localNode; @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) - protected ClusterDefinitionService clusterDefinitionService; + protected ClusterMetadataService clusterMetadataService; @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) protected MessagingService messagingService; @Activate public void activate() { - localNode = clusterDefinitionService.localNode(); + localNode = clusterMetadataService.getLocalNode(); messagingService.registerHandler(HEARTBEAT_MESSAGE, new HeartbeatMessageHandler(), heartBeatMessageHandler); @@ -116,9 +116,6 @@ public class DistributedClusterStore heartBeatSender.scheduleWithFixedDelay(this::heartbeat, 0, HEARTBEAT_INTERVAL_MS, TimeUnit.MILLISECONDS); - addNode(localNode); - updateState(localNode.id(), State.ACTIVE); - log.info("Started"); } @@ -188,7 +185,7 @@ public class DistributedClusterStore private void addNode(ControllerNode node) { allNodes.put(node.id(), node); - updateState(node.id(), State.INACTIVE); + updateState(node.id(), node.equals(localNode) ? State.ACTIVE : State.INACTIVE); notifyDelegate(new ClusterEvent(ClusterEvent.Type.INSTANCE_ADDED, node)); } diff --git a/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/cluster/impl/StaticClusterMetadataStore.java b/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/cluster/impl/StaticClusterMetadataStore.java new file mode 100644 index 00000000..9f6c4130 --- /dev/null +++ b/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/cluster/impl/StaticClusterMetadataStore.java @@ -0,0 +1,221 @@ +package org.onosproject.store.cluster.impl; + +import static com.google.common.base.Preconditions.checkNotNull; +import static java.net.NetworkInterface.getNetworkInterfaces; +import static org.slf4j.LoggerFactory.getLogger; + +import java.io.File; +import java.io.IOException; +import java.net.InetAddress; +import java.net.NetworkInterface; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.concurrent.atomic.AtomicReference; +import java.util.function.Function; + +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.Service; +import org.onlab.packet.IpAddress; +import org.onosproject.cluster.ClusterMetadata; +import org.onosproject.cluster.ClusterMetadataEvent; +import org.onosproject.cluster.ClusterMetadataStore; +import org.onosproject.cluster.ClusterMetadataStoreDelegate; +import org.onosproject.cluster.ControllerNode; +import org.onosproject.cluster.DefaultControllerNode; +import org.onosproject.cluster.NodeId; +import org.onosproject.cluster.Partition; +import org.onosproject.store.AbstractStore; +import org.onosproject.store.service.Versioned; +import org.slf4j.Logger; + +import com.fasterxml.jackson.core.JsonGenerator; +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.DeserializationContext; +import com.fasterxml.jackson.databind.JsonDeserializer; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.JsonSerializer; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.SerializerProvider; +import com.fasterxml.jackson.databind.module.SimpleModule; +import com.google.common.base.Throwables; +import com.google.common.collect.Lists; +import com.google.common.io.Files; + +/** + * ClusterMetadataStore backed by a local file. + */ +@Component(immediate = true, enabled = true) +@Service +public class StaticClusterMetadataStore + extends AbstractStore<ClusterMetadataEvent, ClusterMetadataStoreDelegate> + implements ClusterMetadataStore { + + private final Logger log = getLogger(getClass()); + private static final String CLUSTER_METADATA_FILE = "../config/cluster.json"; + private static final int DEFAULT_ONOS_PORT = 9876; + private final File metadataFile = new File(CLUSTER_METADATA_FILE); + private AtomicReference<ClusterMetadata> metadata = new AtomicReference<>(); + private ObjectMapper mapper; + private long version; + + @Activate + public void activate() { + mapper = new ObjectMapper(); + SimpleModule module = new SimpleModule(); + module.addSerializer(NodeId.class, new NodeIdSerializer()); + module.addDeserializer(NodeId.class, new NodeIdDeserializer()); + module.addSerializer(ControllerNode.class, new ControllerNodeSerializer()); + module.addDeserializer(ControllerNode.class, new ControllerNodeDeserializer()); + mapper.registerModule(module); + File metadataFile = new File(CLUSTER_METADATA_FILE); + if (metadataFile.exists()) { + try { + metadata.set(mapper.readValue(metadataFile, ClusterMetadata.class)); + version = metadataFile.lastModified(); + } catch (IOException e) { + Throwables.propagate(e); + } + } else { + String localIp = getSiteLocalAddress(); + ControllerNode localNode = + new DefaultControllerNode(new NodeId(localIp), IpAddress.valueOf(localIp), DEFAULT_ONOS_PORT); + metadata.set(ClusterMetadata.builder() + .withName("default") + .withControllerNodes(Arrays.asList(localNode)) + .withPartitions(Lists.newArrayList(new Partition("p1", Lists.newArrayList(localNode.id())))) + .build()); + version = System.currentTimeMillis(); + } + log.info("Started"); + } + + @Deactivate + public void deactivate() { + log.info("Stopped"); + } + + @Override + public void setDelegate(ClusterMetadataStoreDelegate delegate) { + checkNotNull(delegate, "Delegate cannot be null"); + this.delegate = delegate; + } + + @Override + public void unsetDelegate(ClusterMetadataStoreDelegate delegate) { + this.delegate = null; + } + + @Override + public boolean hasDelegate() { + return this.delegate != null; + } + + @Override + public Versioned<ClusterMetadata> getClusterMetadata() { + return new Versioned<>(metadata.get(), version); + } + + @Override + public void setClusterMetadata(ClusterMetadata metadata) { + checkNotNull(metadata); + try { + Files.createParentDirs(metadataFile); + mapper.writeValue(metadataFile, metadata); + this.metadata.set(metadata); + } catch (IOException e) { + Throwables.propagate(e); + } + } + + @Override + public void setActiveReplica(String partitionId, NodeId nodeId) { + throw new UnsupportedOperationException(); + } + + @Override + public void unsetActiveReplica(String partitionId, NodeId nodeId) { + throw new UnsupportedOperationException(); + } + + @Override + public Collection<NodeId> getActiveReplicas(String partitionId) { + return metadata.get().getPartitions() + .stream() + .filter(r -> r.getName().equals(partitionId)) + .findFirst() + .map(r -> r.getMembers()) + .orElse(null); + } + + private static class ControllerNodeSerializer extends JsonSerializer<ControllerNode> { + @Override + public void serialize(ControllerNode node, JsonGenerator jgen, SerializerProvider provider) + throws IOException, JsonProcessingException { + jgen.writeStartObject(); + jgen.writeStringField("id", node.id().toString()); + jgen.writeStringField("ip", node.ip().toString()); + jgen.writeNumberField("port", node.tcpPort()); + jgen.writeEndObject(); + } + } + + private static class ControllerNodeDeserializer extends JsonDeserializer<ControllerNode> { + @Override + public ControllerNode deserialize(JsonParser jp, DeserializationContext ctxt) + throws IOException, JsonProcessingException { + JsonNode node = jp.getCodec().readTree(jp); + NodeId nodeId = new NodeId(node.get("id").textValue()); + IpAddress ip = IpAddress.valueOf(node.get("ip").textValue()); + int port = node.get("port").asInt(); + return new DefaultControllerNode(nodeId, ip, port); + } + } + + private static class NodeIdSerializer extends JsonSerializer<NodeId> { + @Override + public void serialize(NodeId nodeId, JsonGenerator jgen, SerializerProvider provider) + throws IOException, JsonProcessingException { + jgen.writeString(nodeId.toString()); + } + } + + private class NodeIdDeserializer extends JsonDeserializer<NodeId> { + @Override + public NodeId deserialize(JsonParser jp, DeserializationContext ctxt) + throws IOException, JsonProcessingException { + JsonNode node = jp.getCodec().readTree(jp); + return new NodeId(node.asText()); + } + } + + + private static String getSiteLocalAddress() { + Function<NetworkInterface, IpAddress> ipLookup = nif -> { + for (InetAddress address : Collections.list(nif.getInetAddresses())) { + if (address.isSiteLocalAddress()) { + return IpAddress.valueOf(address); + } + } + return null; + }; + try { + IpAddress ip = ipLookup.apply(NetworkInterface.getByName("eth0")); + if (ip != null) { + return ip.toString(); + } + for (NetworkInterface nif : Collections.list(getNetworkInterfaces())) { + ip = ipLookup.apply(nif); + if (ip != null) { + return ip.toString(); + } + } + } catch (Exception e) { + throw new IllegalStateException("Unable to get network interfaces", e); + } + return IpAddress.valueOf(InetAddress.getLoopbackAddress()).toString(); + } +}
\ No newline at end of file diff --git a/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/cluster/messaging/impl/IOLoopMessagingManager.java b/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/cluster/messaging/impl/IOLoopMessagingManager.java index ffdd25f2..ddb45f71 100644 --- a/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/cluster/messaging/impl/IOLoopMessagingManager.java +++ b/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/cluster/messaging/impl/IOLoopMessagingManager.java @@ -22,7 +22,7 @@ import org.apache.felix.scr.annotations.Reference; import org.apache.felix.scr.annotations.ReferenceCardinality; import org.apache.felix.scr.annotations.Service; import org.onlab.nio.service.IOLoopMessaging; -import org.onosproject.cluster.ClusterDefinitionService; +import org.onosproject.cluster.ClusterMetadataService; import org.onosproject.cluster.ControllerNode; import org.onosproject.store.cluster.messaging.Endpoint; import org.slf4j.Logger; @@ -38,11 +38,11 @@ public class IOLoopMessagingManager extends IOLoopMessaging { private final Logger log = LoggerFactory.getLogger(getClass()); @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) - protected ClusterDefinitionService clusterDefinitionService; + protected ClusterMetadataService clusterMetadataService; @Activate public void activate() throws Exception { - ControllerNode localNode = clusterDefinitionService.localNode(); + ControllerNode localNode = clusterMetadataService.getLocalNode(); super.start(new Endpoint(localNode.ip(), localNode.tcpPort())); log.info("Started"); } diff --git a/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/cluster/messaging/impl/NettyMessagingManager.java b/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/cluster/messaging/impl/NettyMessagingManager.java index 9328817b..23c81869 100644 --- a/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/cluster/messaging/impl/NettyMessagingManager.java +++ b/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/cluster/messaging/impl/NettyMessagingManager.java @@ -16,6 +16,7 @@ package org.onosproject.store.cluster.messaging.impl; import com.google.common.base.Strings; + import org.apache.felix.scr.annotations.Activate; import org.apache.felix.scr.annotations.Component; import org.apache.felix.scr.annotations.Deactivate; @@ -23,7 +24,7 @@ import org.apache.felix.scr.annotations.Reference; import org.apache.felix.scr.annotations.ReferenceCardinality; import org.apache.felix.scr.annotations.Service; import org.onlab.netty.NettyMessaging; -import org.onosproject.cluster.ClusterDefinitionService; +import org.onosproject.cluster.ClusterMetadataService; import org.onosproject.cluster.ControllerNode; import org.onosproject.store.cluster.messaging.Endpoint; import org.slf4j.Logger; @@ -41,11 +42,11 @@ public class NettyMessagingManager extends NettyMessaging { private static final short MIN_KS_LENGTH = 6; @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) - protected ClusterDefinitionService clusterDefinitionService; + protected ClusterMetadataService clusterMetadataService; @Activate public void activate() throws Exception { - ControllerNode localNode = clusterDefinitionService.localNode(); + ControllerNode localNode = clusterMetadataService.getLocalNode(); getTLSParameters(); super.start(new Endpoint(localNode.ip(), localNode.tcpPort())); log.info("Started"); diff --git a/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/DatabaseDefinition.java b/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/DatabaseDefinition.java deleted file mode 100644 index 11b56c14..00000000 --- a/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/DatabaseDefinition.java +++ /dev/null @@ -1,108 +0,0 @@ -/* - * 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.store.consistent.impl; - -import com.google.common.collect.ImmutableMap; -import com.google.common.collect.ImmutableSet; -import com.google.common.collect.Maps; -import org.onosproject.store.cluster.impl.NodeInfo; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; - -import static com.google.common.base.Preconditions.checkNotNull; - -/** - * Partitioned database configuration. - */ -public class DatabaseDefinition { - private Map<String, Set<NodeInfo>> partitions; - private Set<NodeInfo> nodes; - - /** - * Creates a new DatabaseDefinition. - * - * @param partitions partition map - * @param nodes set of nodes - * @return database definition - */ - public static DatabaseDefinition from(Map<String, Set<NodeInfo>> partitions, - Set<NodeInfo> nodes) { - checkNotNull(partitions); - checkNotNull(nodes); - DatabaseDefinition definition = new DatabaseDefinition(); - definition.partitions = ImmutableMap.copyOf(partitions); - definition.nodes = ImmutableSet.copyOf(nodes); - return definition; - } - - /** - * Creates a new DatabaseDefinition using default partitions. - * - * @param nodes set of nodes - * @return database definition - */ - public static DatabaseDefinition from(Set<NodeInfo> nodes) { - return from(generateDefaultPartitions(nodes), nodes); - } - - /** - * Returns the map of database partitions. - * - * @return db partition map - */ - public Map<String, Set<NodeInfo>> getPartitions() { - return partitions; - } - - /** - * Returns the set of nodes. - * - * @return nodes - */ - public Set<NodeInfo> getNodes() { - return nodes; - } - - - /** - * Generates set of default partitions using permutations of the nodes. - * - * @param nodes information about cluster nodes - * @return default partition map - */ - private static Map<String, Set<NodeInfo>> generateDefaultPartitions(Set<NodeInfo> nodes) { - List<NodeInfo> sorted = new ArrayList<>(nodes); - Collections.sort(sorted, (o1, o2) -> o1.getId().compareTo(o2.getId())); - Map<String, Set<NodeInfo>> partitions = Maps.newHashMap(); - - int length = nodes.size(); - int count = 3; - for (int i = 0; i < length; i++) { - Set<NodeInfo> set = new HashSet<>(count); - for (int j = 0; j < count; j++) { - set.add(sorted.get((i + j) % length)); - } - partitions.put("p" + (i + 1), set); - } - return partitions; - } - -}
\ No newline at end of file diff --git a/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/DatabaseDefinitionStore.java b/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/DatabaseDefinitionStore.java deleted file mode 100644 index b77667b2..00000000 --- a/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/DatabaseDefinitionStore.java +++ /dev/null @@ -1,74 +0,0 @@ -/* - * 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.store.consistent.impl; - -import static com.google.common.base.Preconditions.checkNotNull; -import java.io.File; -import java.io.IOException; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.google.common.io.Files; - -/** - * Allows for reading and writing partitioned database definition as a JSON file. - */ -public class DatabaseDefinitionStore { - - private final File file; - - /** - * Creates a reader/writer of the database definition file. - * - * @param filePath location of the definition file - */ - public DatabaseDefinitionStore(String filePath) { - file = new File(checkNotNull(filePath)); - } - - /** - * Creates a reader/writer of the database definition file. - * - * @param filePath location of the definition file - */ - public DatabaseDefinitionStore(File filePath) { - file = checkNotNull(filePath); - } - - /** - * Returns the database definition. - * - * @return database definition - * @throws IOException when I/O exception of some sort has occurred. - */ - public DatabaseDefinition read() throws IOException { - ObjectMapper mapper = new ObjectMapper(); - return mapper.readValue(file, DatabaseDefinition.class); - } - - /** - * Writes the specified database definition to file. - * - * @param definition database definition - * @throws IOException when I/O exception of some sort has occurred. - */ - public void write(DatabaseDefinition definition) throws IOException { - checkNotNull(definition); - // write back to file - Files.createParentDirs(file); - ObjectMapper mapper = new ObjectMapper(); - mapper.writeValue(file, definition); - } -} diff --git a/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/DatabaseManager.java b/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/DatabaseManager.java index 6ea7c220..3e89635a 100644 --- a/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/DatabaseManager.java +++ b/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/DatabaseManager.java @@ -18,7 +18,6 @@ package org.onosproject.store.consistent.impl; import com.google.common.collect.ArrayListMultimap; import com.google.common.collect.ImmutableList; -import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multimap; @@ -50,12 +49,12 @@ import org.apache.felix.scr.annotations.Service; import org.onosproject.app.ApplicationEvent; import org.onosproject.app.ApplicationListener; import org.onosproject.app.ApplicationService; +import org.onosproject.cluster.ClusterMetadataService; import org.onosproject.cluster.ClusterService; +import org.onosproject.cluster.ControllerNode; import org.onosproject.cluster.NodeId; import org.onosproject.core.ApplicationId; import org.onosproject.core.IdGenerator; -import org.onosproject.store.cluster.impl.ClusterDefinitionManager; -import org.onosproject.store.cluster.impl.NodeInfo; import org.onosproject.store.cluster.messaging.ClusterCommunicationService; import org.onosproject.store.ecmap.EventuallyConsistentMapBuilderImpl; import org.onosproject.store.service.AtomicCounterBuilder; @@ -73,8 +72,6 @@ import org.onosproject.store.service.Transaction; import org.onosproject.store.service.TransactionContextBuilder; import org.slf4j.Logger; -import java.io.File; -import java.io.IOException; import java.util.Collection; import java.util.List; import java.util.Map; @@ -99,8 +96,6 @@ public class DatabaseManager implements StorageService, StorageAdminService { private final Logger log = getLogger(getClass()); - public static final int COPYCAT_TCP_PORT = 9876; - public static final String PARTITION_DEFINITION_FILE = "../config/tablets.json"; public static final String BASE_PARTITION_NAME = "p0"; private static final int RAFT_ELECTION_TIMEOUT_MILLIS = 3000; @@ -122,6 +117,9 @@ public class DatabaseManager implements StorageService, StorageAdminService { Multimaps.synchronizedMultimap(ArrayListMultimap.create()); @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + protected ClusterMetadataService clusterMetadataService; + + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) protected ClusterService clusterService; @Reference(cardinality = ReferenceCardinality.OPTIONAL_UNARY, policy = ReferencePolicy.DYNAMIC) @@ -130,8 +128,9 @@ public class DatabaseManager implements StorageService, StorageAdminService { @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) protected ClusterCommunicationService clusterCommunicator; - protected String nodeToUri(NodeInfo node) { - return String.format("onos://%s:%d", node.getIp(), node.getTcpPort()); + protected String nodeIdToUri(NodeId nodeId) { + ControllerNode node = clusterService.getNode(nodeId); + return String.format("onos://%s:%d", node.ip(), node.tcpPort()); } protected void bindApplicationService(ApplicationService service) { @@ -147,30 +146,22 @@ public class DatabaseManager implements StorageService, StorageAdminService { @Activate public void activate() { localNodeId = clusterService.getLocalNode().id(); - // load database configuration - File databaseDefFile = new File(PARTITION_DEFINITION_FILE); - log.info("Loading database definition: {}", databaseDefFile.getAbsolutePath()); - Map<String, Set<NodeInfo>> partitionMap; - try { - DatabaseDefinitionStore databaseDefStore = new DatabaseDefinitionStore(databaseDefFile); - if (!databaseDefFile.exists()) { - createDefaultDatabaseDefinition(databaseDefStore); - } - partitionMap = databaseDefStore.read().getPartitions(); - } catch (IOException e) { - throw new IllegalStateException("Failed to load database config", e); - } + Map<String, Set<NodeId>> partitionMap = Maps.newHashMap(); + clusterMetadataService.getClusterMetadata().getPartitions().forEach(p -> { + partitionMap.put(p.getName(), Sets.newHashSet(p.getMembers())); + }); + String[] activeNodeUris = partitionMap.values() .stream() .reduce((s1, s2) -> Sets.union(s1, s2)) .get() .stream() - .map(this::nodeToUri) + .map(this::nodeIdToUri) .toArray(String[]::new); - String localNodeUri = nodeToUri(NodeInfo.of(clusterService.getLocalNode())); + String localNodeUri = nodeIdToUri(clusterMetadataService.getLocalNode().id()); Protocol protocol = new CopycatCommunicationProtocol(clusterService, clusterCommunicator); ClusterConfig clusterConfig = new ClusterConfig() @@ -198,7 +189,7 @@ public class DatabaseManager implements StorageService, StorageAdminService { List<Database> partitions = partitionMap.entrySet() .stream() .map(entry -> { - String[] replicas = entry.getValue().stream().map(this::nodeToUri).toArray(String[]::new); + String[] replicas = entry.getValue().stream().map(this::nodeIdToUri).toArray(String[]::new); return newDatabaseConfig(entry.getKey(), newPersistentLog(), replicas); }) .map(config -> { @@ -229,17 +220,6 @@ public class DatabaseManager implements StorageService, StorageAdminService { log.info("Started"); } - private void createDefaultDatabaseDefinition(DatabaseDefinitionStore store) { - // Assumes IPv4 is returned. - String ip = ClusterDefinitionManager.getSiteLocalAddress(); - NodeInfo node = NodeInfo.from(ip, ip, COPYCAT_TCP_PORT); - try { - store.write(DatabaseDefinition.from(ImmutableSet.of(node))); - } catch (IOException e) { - log.warn("Unable to write default cluster definition", e); - } - } - @Deactivate public void deactivate() { CompletableFuture.allOf(inMemoryDatabase.close(), partitionedDatabase.close()) diff --git a/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/DefaultTransactionContext.java b/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/DefaultTransactionContext.java index b66f424b..73888221 100644 --- a/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/DefaultTransactionContext.java +++ b/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/DefaultTransactionContext.java @@ -86,7 +86,7 @@ public class DefaultTransactionContext implements TransactionContext { @SuppressWarnings("unchecked") @Override - public void commit() { + public boolean commit() { // TODO: rework commit implementation to be more intuitive checkState(isOpen, TX_NOT_OPEN_ERROR); CommitResponse response = null; @@ -95,10 +95,11 @@ public class DefaultTransactionContext implements TransactionContext { txMaps.values().forEach(m -> updates.addAll(m.prepareDatabaseUpdates())); Transaction transaction = new DefaultTransaction(transactionId, updates); response = Futures.getUnchecked(database.prepareAndCommit(transaction)); + return response.success(); + } catch (Exception e) { + abort(); + return false; } finally { - if (response != null && !response.success()) { - abort(); - } isOpen = false; } } diff --git a/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/device/impl/GossipDeviceStore.java b/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/device/impl/GossipDeviceStore.java index 973db494..687762e0 100644 --- a/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/device/impl/GossipDeviceStore.java +++ b/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/device/impl/GossipDeviceStore.java @@ -427,6 +427,7 @@ public class GossipDeviceStore // Primary providers can respond to all changes, but ancillary ones // should respond only to annotation changes. + DeviceEvent event = null; if ((providerId.isAncillary() && annotationsChanged) || (!providerId.isAncillary() && (propertiesChanged || annotationsChanged))) { boolean replaced = devices.replace(newDevice.id(), oldDevice, newDevice); @@ -436,17 +437,18 @@ public class GossipDeviceStore providerId, oldDevice, devices.get(newDevice.id()) , newDevice); } - if (!providerId.isAncillary()) { - boolean wasOnline = availableDevices.contains(newDevice.id()); - markOnline(newDevice.id(), newTimestamp); - if (!wasOnline) { - notifyDelegateIfNotNull(new DeviceEvent(DEVICE_AVAILABILITY_CHANGED, newDevice, null)); - } - } - return new DeviceEvent(DeviceEvent.Type.DEVICE_UPDATED, newDevice, null); + event = new DeviceEvent(DeviceEvent.Type.DEVICE_UPDATED, newDevice, null); } - return null; + + if (!providerId.isAncillary()) { + boolean wasOnline = availableDevices.contains(newDevice.id()); + markOnline(newDevice.id(), newTimestamp); + if (!wasOnline) { + notifyDelegateIfNotNull(new DeviceEvent(DEVICE_AVAILABILITY_CHANGED, newDevice, null)); + } + } + return event; } @Override diff --git a/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/ecmap/MapDbPersistentStore.java b/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/ecmap/MapDbPersistentStore.java index e62a2d5c..f5ce47fc 100644 --- a/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/ecmap/MapDbPersistentStore.java +++ b/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/ecmap/MapDbPersistentStore.java @@ -100,4 +100,4 @@ class MapDbPersistentStore<K, V> implements PersistentStore<K, V> { items.remove(keyBytes); database.commit(); } -} +}
\ No newline at end of file diff --git a/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/newresource/impl/ConsistentResourceStore.java b/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/newresource/impl/ConsistentResourceStore.java index 10f79eb0..687576c3 100644 --- a/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/newresource/impl/ConsistentResourceStore.java +++ b/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/newresource/impl/ConsistentResourceStore.java @@ -52,7 +52,7 @@ import static com.google.common.base.Preconditions.checkNotNull; /** * Implementation of ResourceStore using TransactionalMap. */ -@Component(immediate = true, enabled = false) +@Component(immediate = true) @Service @Beta public class ConsistentResourceStore implements ResourceStore { @@ -239,6 +239,18 @@ public class ConsistentResourceStore implements ResourceStore { } @Override + public Collection<ResourcePath> getChildResources(ResourcePath parent) { + checkNotNull(parent); + + Versioned<List<ResourcePath>> children = childMap.get(parent); + if (children == null) { + return Collections.emptyList(); + } + + return children.value(); + } + + @Override public <T> Collection<ResourcePath> getAllocatedResources(ResourcePath parent, Class<T> cls) { checkNotNull(parent); checkNotNull(cls); diff --git a/framework/src/onos/core/store/dist/src/test/java/org/onosproject/store/intent/impl/PartitionManagerTest.java b/framework/src/onos/core/store/dist/src/test/java/org/onosproject/store/intent/impl/PartitionManagerTest.java index 25e23d3a..61d1937e 100644 --- a/framework/src/onos/core/store/dist/src/test/java/org/onosproject/store/intent/impl/PartitionManagerTest.java +++ b/framework/src/onos/core/store/dist/src/test/java/org/onosproject/store/intent/impl/PartitionManagerTest.java @@ -325,5 +325,11 @@ public class PartitionManagerTest { return Objects.equals(this.hash(), that.hash()); } + + @Override + public int compareTo(Key o) { + Long thisHash = hash(); + return thisHash.compareTo(o.hash()); + } } } diff --git a/framework/src/onos/core/store/persistence/pom.xml b/framework/src/onos/core/store/persistence/pom.xml new file mode 100644 index 00000000..555de11a --- /dev/null +++ b/framework/src/onos/core/store/persistence/pom.xml @@ -0,0 +1,66 @@ +<?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> + <repositories> + <repository> + <id>repository.springsource.com.release</id> + <name>SpringSource OBR - Release</name> + <url>http://repository.springsource.com/maven/bundles/release</url> + </repository> + <repository> + <id>repository.springsource.com.external</id> + <name>SpringSource OBR - External</name> + <url>http://repository.springsource.com/maven/bundles/external</url> + </repository> + </repositories> + + <parent> + <groupId>org.onosproject</groupId> + <artifactId>onos-core-store</artifactId> + <version>1.4.0-SNAPSHOT</version> + <relativePath>../pom.xml</relativePath> + </parent> + + <artifactId>onos-core-persistence</artifactId> + <packaging>bundle</packaging> + + <description>ONOS Core persistent local store subsystem</description> + + + + <dependencies> + <!--<dependency> + <groupId>org.onosproject</groupId> + <artifactId>onos-api</artifactId> + </dependency>--> + <dependency> + <groupId>org.onosproject</groupId> + <artifactId>onos-api</artifactId> + <classifier>tests</classifier> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.mapdb</groupId> + <artifactId>mapdb</artifactId> + <version>1.0.8</version> + </dependency> + </dependencies> + +</project> diff --git a/framework/src/onos/core/store/persistence/src/main/java/org/onosproject/persistence/impl/DefaultPersistentMapBuilder.java b/framework/src/onos/core/store/persistence/src/main/java/org/onosproject/persistence/impl/DefaultPersistentMapBuilder.java new file mode 100644 index 00000000..88c7d148 --- /dev/null +++ b/framework/src/onos/core/store/persistence/src/main/java/org/onosproject/persistence/impl/DefaultPersistentMapBuilder.java @@ -0,0 +1,63 @@ +/* + * 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.persistence.impl; + +import org.mapdb.DB; +import org.onosproject.persistence.PersistentMapBuilder; +import org.onosproject.store.service.Serializer; + +import java.util.Map; + +import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Default builder for persistent maps stored in the mapDB local database via the persistence service. + */ +public class DefaultPersistentMapBuilder<K, V> implements PersistentMapBuilder<K, V> { + + private final DB localDB; + + private String name = null; + + private Serializer serializer = null; + + + public DefaultPersistentMapBuilder(DB localDB) { + checkNotNull(localDB, "The local database cannot be null."); + this.localDB = localDB; + } + + public PersistentMapBuilder<K, V> withName(String name) { + this.name = PersistenceManager.MAP_PREFIX + checkNotNull(name); + return this; + } + + public PersistentMapBuilder<K, V> withSerializer(Serializer serializer) { + checkArgument(this.serializer == null); + checkNotNull(serializer); + this.serializer = serializer; + return this; + } + + public Map<K, V> build() { + checkNotNull(name, "The name must be assigned."); + checkNotNull(serializer, "The key serializer must be assigned."); + + return new PersistentMap<K, V>(serializer, localDB, name); + } +}
\ No newline at end of file diff --git a/framework/src/onos/core/store/persistence/src/main/java/org/onosproject/persistence/impl/DefaultPersistentSetBuilder.java b/framework/src/onos/core/store/persistence/src/main/java/org/onosproject/persistence/impl/DefaultPersistentSetBuilder.java new file mode 100644 index 00000000..e1544fb4 --- /dev/null +++ b/framework/src/onos/core/store/persistence/src/main/java/org/onosproject/persistence/impl/DefaultPersistentSetBuilder.java @@ -0,0 +1,59 @@ +/* + * 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.persistence.impl; + +import org.mapdb.DB; +import org.onosproject.persistence.PersistentSetBuilder; +import org.onosproject.store.service.Serializer; + +import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Default builder for persistent sets stored in the mapDB local database via the persistence service.. + */ +public class DefaultPersistentSetBuilder<E> implements PersistentSetBuilder<E> { + + private final DB localDB; + + private String name = null; + + private Serializer serializer = null; + + public DefaultPersistentSetBuilder(DB localDB) { + this.localDB = checkNotNull(localDB, "The local database cannot be null."); + } + + public PersistentSetBuilder<E> withName(String name) { + this.name = PersistenceManager.SET_PREFIX + checkNotNull(name); + return this; + } + + public PersistentSetBuilder<E> withSerializer(Serializer serializer) { + checkArgument(this.serializer == null); + checkNotNull(serializer); + this.serializer = serializer; + return this; + } + + public PersistentSet<E> build() { + checkNotNull(name, "The name must be assigned."); + checkNotNull(serializer, "The serializer must be assigned."); + + return new PersistentSet<E>(serializer, localDB, name); + } +}
\ No newline at end of file diff --git a/framework/src/onos/core/store/persistence/src/main/java/org/onosproject/persistence/impl/PersistenceException.java b/framework/src/onos/core/store/persistence/src/main/java/org/onosproject/persistence/impl/PersistenceException.java new file mode 100644 index 00000000..f2ba20c2 --- /dev/null +++ b/framework/src/onos/core/store/persistence/src/main/java/org/onosproject/persistence/impl/PersistenceException.java @@ -0,0 +1,30 @@ +/* + * 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.persistence.impl; + +/** + * An exception defined for failures of the local persistent store system. + */ + +/** + * Throws an exception with the specified message. + */ +public class PersistenceException extends RuntimeException { + public PersistenceException(String s) { + super(s); + } +} diff --git a/framework/src/onos/core/store/persistence/src/main/java/org/onosproject/persistence/impl/PersistenceManager.java b/framework/src/onos/core/store/persistence/src/main/java/org/onosproject/persistence/impl/PersistenceManager.java new file mode 100644 index 00000000..64a8683a --- /dev/null +++ b/framework/src/onos/core/store/persistence/src/main/java/org/onosproject/persistence/impl/PersistenceManager.java @@ -0,0 +1,138 @@ +/* + * 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.persistence.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.Service; +import org.mapdb.DB; +import org.mapdb.DBMaker; +import org.onosproject.persistence.PersistenceService; +import org.onosproject.persistence.PersistentMapBuilder; +import org.onosproject.persistence.PersistentSetBuilder; +import org.slf4j.Logger; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.Map; +import java.util.Set; +import java.util.Timer; +import java.util.TimerTask; + +import static org.slf4j.LoggerFactory.getLogger; + +/** + * Service that maintains local disk backed maps and sets. This implementation automatically deletes empty structures + * on shutdown. + */ +@Component(immediate = true) +@Service +public class PersistenceManager implements PersistenceService { + + private static final String DATABASE_PATH = "../data/localDB"; + + private static final String ENCLOSING_FOLDER = "../data"; + + static final String MAP_PREFIX = "map:"; + + static final String SET_PREFIX = "set:"; + + private final Logger log = getLogger(getClass()); + + private DB localDB = null; + + private static final int FLUSH_FREQUENCY_MILLIS = 3000; + + private final Timer timer = new Timer(); + + private final CommitTask commitTask = new CommitTask(); + + @Activate + public void activate() { + Path dbPath = Paths.get(DATABASE_PATH); + Path dbFolderPath = Paths.get(ENCLOSING_FOLDER); + //Make sure the directory exists, if it does not, make it. + if (!dbFolderPath.toFile().isDirectory()) { + log.info("The specified folder location for the database did not exist and will be created."); + try { + Files.createDirectories(dbFolderPath); + } catch (IOException e) { + log.error("Could not create the required folder for the database."); + throw new PersistenceException("Database folder could not be created."); + } + } + //Notify if the database file does not exist. + boolean dbFound = Files.exists(dbPath); + if (!dbFound) { + log.info("The database file could not be located, a new database will be constructed."); + + } else { + log.info("A previous database file has been found."); + } + localDB = DBMaker.newFileDB(dbPath.toFile()) + .asyncWriteEnable() + .closeOnJvmShutdown() + .make(); + timer.schedule(commitTask, FLUSH_FREQUENCY_MILLIS, FLUSH_FREQUENCY_MILLIS); + log.info("Started"); + } + + @Deactivate + public void deactivate() { + for (Map.Entry<String, Object> entry : localDB.getAll().entrySet()) { + String key = entry.getKey(); + Object value = entry.getValue(); + //This is a map implementation to be handled as such + if (value instanceof Map) { + Map asMap = (Map) value; + if (asMap.isEmpty()) { + //the map is empty and may be deleted + localDB.delete(key); + } + //This is a set implementation and can be handled as such + } else if (value instanceof Set) { + Set asSet = (Set) value; + if (asSet.isEmpty()) { + //the set is empty and may be deleted + localDB.delete(key); + } + } + } + localDB.commit(); + localDB.close(); + log.info("Stopped"); + } + + public <K, V> PersistentMapBuilder<K, V> persistentMapBuilder() { + return new DefaultPersistentMapBuilder<>(localDB); + } + + public <E> PersistentSetBuilder<E> persistentSetBuilder() { + return new DefaultPersistentSetBuilder<>(localDB); + } + + private class CommitTask extends TimerTask { + + @Override + public void run() { + localDB.commit(); + } + } +}
\ No newline at end of file diff --git a/framework/src/onos/core/store/persistence/src/main/java/org/onosproject/persistence/impl/PersistentMap.java b/framework/src/onos/core/store/persistence/src/main/java/org/onosproject/persistence/impl/PersistentMap.java new file mode 100644 index 00000000..4506bbda --- /dev/null +++ b/framework/src/onos/core/store/persistence/src/main/java/org/onosproject/persistence/impl/PersistentMap.java @@ -0,0 +1,192 @@ +/* + * 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.persistence.impl; + +import com.google.common.collect.Maps; +import com.google.common.collect.Sets; +import org.mapdb.DB; +import org.mapdb.Hasher; +import org.onosproject.store.service.Serializer; + +import java.util.Collection; +import java.util.Map; +import java.util.Set; + +import static com.google.common.base.Preconditions.checkNotNull; + + +/** + * A map implementation that stores and receives all data from a serialized internal map. + */ +public class PersistentMap<K, V> implements Map<K, V> { + + private final Serializer serializer; + + private final org.mapdb.DB database; + + private final Map<byte[], byte[]> items; + + private final String name; + + public PersistentMap(Serializer serializer, DB database, String name) { + this.serializer = checkNotNull(serializer); + this.database = checkNotNull(database); + this.name = checkNotNull(name); + + items = database + .createHashMap(name) + .keySerializer(org.mapdb.Serializer.BYTE_ARRAY) + .valueSerializer(org.mapdb.Serializer.BYTE_ARRAY) + .hasher(Hasher.BYTE_ARRAY) + .makeOrGet(); + } + + /** + * Reads this set in deserialized form into the provided map. + * + * @param items the map to be populated + */ + public void readInto(Map<K, V> items) { + this.items.forEach((keyBytes, valueBytes) -> + items.put(serializer.decode(keyBytes), + serializer.decode(valueBytes))); + } + + @Override + public V remove(Object key) { + checkNotNull(key, "Key can not be null."); + V removed = get(key); + items.remove(serializer.encode(key)); + return removed; + } + + @Override + public int size() { + return items.size(); + } + + @Override + public boolean isEmpty() { + return items.isEmpty(); + } + + @Override + public boolean containsKey(Object key) { + checkNotNull(key, "Key cannot be null."); + return items.containsKey(serializer.encode(key)); + } + + @Override + public boolean containsValue(Object value) { + checkNotNull(value, "Value cannot be null."); + byte[] serialized = serializer.encode(value); + for (byte[] compareValue : items.values()) { + boolean same = true; + if (compareValue == null) { + same = false; + } else if (compareValue.length != serialized.length) { + same = false; + } else { + for (int i = 0; i < serialized.length; i++) { + if (serialized[i] != compareValue[i]) { + same = false; + break; + } + } + } + if (same) { + return true; + } + } + return false; + } + + @Override + public V get(Object key) { + checkNotNull(key, "Key cannot be null."); + return serializer.decode(items.get(serializer.encode(key))); + } + + @Override + public V put(K key, V value) { + checkNotNull(key, "Key cannot be null."); + checkNotNull(value, "Value cannot be null."); + byte[] prevVal = items.put(serializer.encode(key), serializer.encode(value)); + if (prevVal == null) { + return null; + } + return serializer.decode(prevVal); + } + + @Override + public void putAll(Map<? extends K, ? extends V> m) { + checkNotNull(m, "The passed in map cannot be null."); + m.forEach((k, v) -> items.put(serializer.encode(k), serializer.encode(v))); + } + + @Override + public void clear() { + items.clear(); + } + + @Override + public Set<K> keySet() { + Set<K> keys = Sets.newHashSet(); + items.keySet().forEach(k -> keys.add(serializer.decode(k))); + return keys; + } + + @Override + public Collection<V> values() { + Collection<V> values = Sets.newHashSet(); + items.values().forEach(v -> values.add(serializer.decode(v))); + return values; + } + + @Override + public Set<Entry<K, V>> entrySet() { + Set<Entry<K, V>> entries = Sets.newHashSet(); + items.entrySet(). + forEach(e -> entries.add(Maps.immutableEntry(serializer.decode(e.getKey()), + serializer.decode(e.getValue())))); + return entries; + } + + @Override + public boolean equals(Object map) { + //This is not threadsafe and on larger maps incurs a significant processing cost + if (!(map instanceof Map)) { + return false; + } + Map asMap = (Map) map; + if (this.size() != asMap.size()) { + return false; + } + for (Entry entry : this.entrySet()) { + Object key = entry.getKey(); + if (!asMap.containsKey(key) || !asMap.get(key).equals(entry.getValue())) { + return false; + } + } + return true; + } + + @Override + public int hashCode() { + return super.hashCode(); + } +}
\ No newline at end of file diff --git a/framework/src/onos/core/store/persistence/src/main/java/org/onosproject/persistence/impl/PersistentSet.java b/framework/src/onos/core/store/persistence/src/main/java/org/onosproject/persistence/impl/PersistentSet.java new file mode 100644 index 00000000..26118cf6 --- /dev/null +++ b/framework/src/onos/core/store/persistence/src/main/java/org/onosproject/persistence/impl/PersistentSet.java @@ -0,0 +1,194 @@ +/* + * 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.persistence.impl; + +import com.google.common.collect.Iterators; +import org.mapdb.DB; +import org.mapdb.Hasher; +import org.mapdb.Serializer; + +import java.util.Collection; +import java.util.Iterator; +import java.util.Set; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * A set implementation that gets and receives all data from a serialized internal set. + */ +//TODO add locking for reads and writes +public class PersistentSet<E> implements Set<E> { + + private final org.onosproject.store.service.Serializer serializer; + + private final org.mapdb.DB database; + + private final Set<byte[]> items; + + private final String name; + + public PersistentSet(org.onosproject.store.service.Serializer serializer, DB database, String name) { + this.serializer = checkNotNull(serializer); + this.database = checkNotNull(database); + this.name = checkNotNull(name); + + items = database + .createHashSet(name) + .serializer(Serializer.BYTE_ARRAY) + .hasher(Hasher.BYTE_ARRAY) + .makeOrGet(); + } + + public void readInto(Set<E> items) { + this.items.forEach(item -> items.add(serializer.decode(item))); + } + + @Override + public int size() { + return items.size(); + } + + @Override + public boolean isEmpty() { + return items.isEmpty(); + } + + @Override + public boolean contains(Object o) { + checkNotNull(o, "The argument cannot be null"); + return items.contains(serializer.encode(o)); + } + + @Override + public Iterator<E> iterator() { + return Iterators.transform(items.iterator(), serializer::decode); + } + + @Override + public Object[] toArray() { + Object[] retArray = new Object[items.size()]; + int index = 0; + Iterator<byte[]> iterator = items.iterator(); + while (iterator.hasNext()) { + retArray[index] = serializer.decode(iterator.next()); + index++; + } + return retArray; + } + + @Override + public <T> T[] toArray(T[] a) { + checkNotNull(a, "The passed in array cannot be null."); + int index = 0; + Iterator<byte[]> iterator = items.iterator(); + T[] retArray; + if (a.length >= items.size()) { + retArray = a; + } else { + retArray = (T[]) new Object[items.size()]; + } + while (iterator.hasNext()) { + retArray[index++] = serializer.decode(iterator.next()); + } + if (retArray.length > items.size()) { + retArray[index] = null; + } + return retArray; + } + + @Override + public boolean add(E item) { + checkNotNull("Item to be added cannot be null."); + return items.add(serializer.encode(item)); + } + + @Override + public boolean remove(Object o) { + checkNotNull(o, "Item to be removed cannot be null."); + return items.remove(serializer.encode(o)); + } + + @Override + public boolean containsAll(Collection<?> c) { + checkNotNull(c, "Collection cannot be internal."); + for (Object item : c) { + if (!items.contains(serializer.encode(item))) { + return false; + } + } + return true; + } + + @Override + public boolean addAll(Collection<? extends E> c) { + checkNotNull(c, "The collection to be added cannot be null."); + boolean changed = false; + for (Object item : c) { + changed = items.add(serializer.encode(item)) || changed; + } + return changed; + } + + @Override + public boolean retainAll(Collection<?> c) { + boolean changed = false; + for (byte[] item : items) { + E deserialized = serializer.decode(item); + if (!c.contains(deserialized)) { + changed = items.remove(item) || changed; + } + } + return changed; + } + + @Override + public boolean removeAll(Collection<?> c) { + boolean changed = false; + for (Object item : c) { + changed = items.remove(serializer.encode(item)) || changed; + } + return changed; + } + + @Override + public void clear() { + items.clear(); + } + + @Override + public boolean equals(Object set) { + //This is not threadsafe and on larger sets incurs a significant processing cost + if (!(set instanceof Set)) { + return false; + } + Set asSet = (Set) set; + if (asSet.size() != this.size()) { + return false; + } + for (Object item : this) { + if (!asSet.contains(item)) { + return false; + } + } + return true; + } + + @Override + public int hashCode() { + return super.hashCode(); + } +}
\ No newline at end of file diff --git a/framework/src/onos/core/store/persistence/src/main/java/org/onosproject/persistence/impl/package-info.java b/framework/src/onos/core/store/persistence/src/main/java/org/onosproject/persistence/impl/package-info.java new file mode 100644 index 00000000..968a5046 --- /dev/null +++ b/framework/src/onos/core/store/persistence/src/main/java/org/onosproject/persistence/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. + */ + +/** + * Implementations of core persistence classes. + */ +package org.onosproject.persistence.impl; diff --git a/framework/src/onos/core/store/persistence/src/main/test/test/PersistentMapTest.java b/framework/src/onos/core/store/persistence/src/main/test/test/PersistentMapTest.java new file mode 100644 index 00000000..b059f18e --- /dev/null +++ b/framework/src/onos/core/store/persistence/src/main/test/test/PersistentMapTest.java @@ -0,0 +1,245 @@ +/* + * 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 test; + +import com.google.common.collect.Maps; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.mapdb.DB; +import org.mapdb.DBMaker; +import org.onosproject.persistence.impl.PersistentMap; +import org.onosproject.store.service.Serializer; + +import java.nio.file.Paths; +import java.util.Map; +import java.util.Set; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; + +/** + * Test suite for Persistent Map. + */ +public class PersistentMapTest { + + private Map<Integer, Integer> map = null; + private DB fakeDB = null; + + + /** + * Set up the database, create a map and a direct executor to handle it. + * + * @throws Exception if instantiation fails + */ + @Before + public void setUp() throws Exception { + //Creates a db, a map within it and a basic integer serializer (async writing is off) + fakeDB = DBMaker + .newFileDB(Paths.get("../testDb").toFile()) + .asyncWriteEnable() + .closeOnJvmShutdown() + .make(); + map = new PersistentMap<Integer, Integer>(new Serializer() { + @Override + public <T> byte[] encode(T object) { + if (object == null) { + return null; + } + int num = (Integer) object; + byte[] result = new byte[4]; + + result[0] = (byte) (num >> 24); + result[1] = (byte) (num >> 16); + result[2] = (byte) (num >> 8); + result[3] = (byte) num; + return result; + } + + @Override + public <T> T decode(byte[] bytes) { + if (bytes == null) { + return null; + } + int num = 0x00000000; + + num = num | bytes[0] << 24; + num = num | bytes[1] << 16; + num = num | bytes[2] << 8; + num = num | bytes[3]; + + return (T) new java.lang.Integer(num); + } + }, fakeDB, "map"); + } + + /** + * Clears and deletes the map, closes the datbase and deletes the file. + * + * @throws Exception if shutdown fails + */ + @After + public void tearDown() throws Exception { + map.clear(); + fakeDB.delete("map:map"); + fakeDB.commit(); + fakeDB.close(); + //This is key to prevent artifacts persisting between tests. + Paths.get("../testDB").toFile().delete(); + + + } + + @Test + public void testRemove() throws Exception { + //Checks removal and return values + fillMap(10); + assertEquals(10, map.size()); + for (int i = 0; i < 10; i++) { + assertEquals("The previous value was wrong.", new Integer(i), map.remove(i)); + assertNull("The previous value was wrong.", map.remove(i)); + //(i+1) compensates for base zero. + assertEquals("The size was wrong.", 10 - (i + 1), map.size()); + } + } + + @Test + public void testSize() throws Exception { + //Checks size values throughout addition and removal + for (int i = 0; i < 10; i++) { + map.put(i, i); + assertEquals("The map size is wrong.", i + 1, map.size()); + } + for (int i = 0; i < 10; i++) { + map.remove(i); + assertEquals("The map size is wrong.", 9 - i, map.size()); + } + } + + @Test + public void testIsEmpty() throws Exception { + //Checks empty condition + //asserts that the map starts out empty + assertTrue("Map should be empty", map.isEmpty()); + map.put(1, 1); + assertFalse("Map shouldn't be empty.", map.isEmpty()); + map.remove(1); + assertTrue("Map should be empty", map.isEmpty()); + } + + @Test + public void testContains() throws Exception { + //Checks both containsKey and containsValue be aware the implementations vary widely (value does not use mapDB + //due to object '=='being an insufficient check) + for (int i = 0; i < 10; i++) { + assertFalse("Map should not contain the key", map.containsKey(i)); + assertFalse("Map should not contain the value", map.containsValue(i)); + map.put(i, i); + assertTrue("Map should contain the key", map.containsKey(i)); + assertTrue("Map should contain the value", map.containsValue(i)); + } + } + + @Test + public void testGet() throws Exception { + //Tests value retrieval and nonexistent key return values + for (int i = 0; i < 10; i++) { + map.put(i, i); + for (int j = 0; j <= i; j++) { + assertEquals("The value was wrong.", new Integer(j), map.get(j)); + } + } + assertNull("Null return value for nonexistent keys.", map.get(10)); + } + + @Test + public void testPutAll() throws Exception { + //Tests adding of an outside map + Map<Integer, Integer> testMap = Maps.newHashMap(); + fillMap(10); + map.putAll(testMap); + for (int i = 0; i < 10; i++) { + assertTrue("The map should contain the current 'i' value.", map.containsKey(i)); + assertTrue("The map should contain the current 'i' value.", map.containsValue(i)); + } + } + + @Test + public void testClear() throws Exception { + //Tests clearing the map + assertTrue("Map was initialized incorrectly, should be empty.", map.isEmpty()); + fillMap(10); + assertFalse("Map should contain entries now.", map.isEmpty()); + map.clear(); + assertTrue("Map should have been cleared of entries.", map.isEmpty()); + + } + + @Test + public void testKeySet() throws Exception { + //Tests key set generation + fillMap(10); + Set<Integer> keys = map.keySet(); + for (int i = 0; i < 10; i++) { + assertTrue("The key set doesn't contain all keys 0-9", keys.contains(i)); + } + assertEquals("The key set has an incorrect number of entries", 10, keys.size()); + } + + @Test + public void testValues() throws Exception { + //Tests value set generation + fillMap(10); + Set<Integer> values = (Set<Integer>) map.values(); + for (int i = 0; i < 10; i++) { + assertTrue("The key set doesn't contain all keys 0-9", values.contains(i)); + } + assertEquals("The key set has an incorrect number of entries", 10, values.size()); + } + + @Test + public void testEntrySet() throws Exception { + //Test entry set generation (violates abstraction by knowing the type of the returned entries) + fillMap(10); + Set<Map.Entry<Integer, Integer>> entries = map.entrySet(); + for (int i = 0; i < 10; i++) { + assertTrue("The key set doesn't contain all keys 0-9", entries.contains(Maps.immutableEntry(i, i))); + } + assertEquals("The key set has an incorrect number of entries", 10, entries.size()); + } + + @Test public void testPut() throws Exception { + //Tests insertion behavior (particularly the returning of previous value) + fillMap(10); + for (int i = 0; i < 10; i++) { + assertEquals("Put should return the previous value", new Integer(i), map.put(i, i + 1)); + } + assertNull(map.put(11, 11)); + } + + /** + * Populated the map with pairs of integers from (0, 0) up to (numEntries - 1, numEntries -1). + * @param numEntries number of entries to add + */ + private void fillMap(int numEntries) { + for (int i = 0; i < numEntries; i++) { + map.put(i, i); + } + } +} diff --git a/framework/src/onos/core/store/persistence/src/main/test/test/PersistentSetTest.java b/framework/src/onos/core/store/persistence/src/main/test/test/PersistentSetTest.java new file mode 100644 index 00000000..3107ab30 --- /dev/null +++ b/framework/src/onos/core/store/persistence/src/main/test/test/PersistentSetTest.java @@ -0,0 +1,274 @@ +/* + * 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 test; + +import com.google.common.collect.Sets; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.mapdb.DB; +import org.mapdb.DBMaker; +import org.onosproject.persistence.impl.PersistentSet; +import org.onosproject.store.service.Serializer; + +import java.nio.file.Paths; +import java.util.HashSet; +import java.util.Set; + +import static com.google.common.base.Preconditions.checkNotNull; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotEquals; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; + +/** + * Test suite for Persistent Set. + */ +public class PersistentSetTest { + + private Set<Integer> set = null; + private DB fakeDB = null; + + @Before + public void setUp() throws Exception { + //Creates a db, a set within it and a basic integer serializer (async writing is off) + fakeDB = DBMaker + .newFileDB(Paths.get("../testDb").toFile()) + .asyncWriteEnable() + .closeOnJvmShutdown() + .make(); + set = new PersistentSet<Integer>(new Serializer() { + @Override + public <T> byte[] encode(T object) { + if (object == null) { + return null; + } + int num = (Integer) object; + byte[] result = new byte[4]; + + result[0] = (byte) (num >> 24); + result[1] = (byte) (num >> 16); + result[2] = (byte) (num >> 8); + result[3] = (byte) num; + return result; + } + + @Override + public <T> T decode(byte[] bytes) { + if (bytes == null) { + return null; + } + int num = 0x00000000; + + num = num | bytes[0] << 24; + num = num | bytes[1] << 16; + num = num | bytes[2] << 8; + num = num | bytes[3]; + + return (T) new java.lang.Integer(num); + } + }, fakeDB, "set"); + + } + + @After + public void tearDown() throws Exception { + set.clear(); + fakeDB.delete("map:map"); + fakeDB.commit(); + fakeDB.close(); + //This is key to prevent artifacts persisting between tests. + Paths.get("../testDB").toFile().delete(); + } + + @Test + public void testSize() throws Exception { + //Check correct sizing throughout population + for (int i = 0; i < 10; i++) { + set.add(i); + assertEquals("The set should have i + 1 entries.", i + 1, set.size()); + } + } + + @Test + public void testIsEmpty() throws Exception { + //test empty condition + assertTrue("The set should be initialized empty.", set.isEmpty()); + fillSet(5, this.set); + assertFalse("The set should no longer be empty.", set.isEmpty()); + set.clear(); + assertTrue("The set should have been cleared.", set.isEmpty()); + } + + @Test + public void testContains() throws Exception { + //Test contains + assertFalse("The set should not contain anything", set.contains(1)); + fillSet(10, this.set); + for (int i = 0; i < 10; i++) { + assertTrue("The set should contain all values 0-9.", set.contains(i)); + } + } + + @Test + public void testIterator() throws Exception { + //Test iterator behavior (no order guarantees are made) + Set<Integer> validationSet = Sets.newHashSet(); + fillSet(10, this.set); + fillSet(10, validationSet); + set.iterator().forEachRemaining(item -> assertTrue("Items were mismatched.", validationSet.remove(item))); + //All values should have been seen and removed + assertTrue("All entries in the validation set should have been removed.", validationSet.isEmpty()); + } + + @Test + public void testToArray() throws Exception { + //Test creation of a new array of the values + fillSet(10, set); + Object[] arr = set.toArray(); + assertEquals("The array should be of length 10.", 10, arr.length); + for (int i = 0; i < 10; i++) { + assertTrue("All elements of the array should be in the set.", set.contains((Integer) arr[i])); + } + } + + @Test + public void testToArray1() throws Exception { + //Test creation of a new array with the possibility of populating passed array if space allows + Integer[] originalArray = new Integer[9]; + fillSet(9, set); + //Test the case where the array and set match in size + Object[] retArray = set.toArray(originalArray); + assertEquals("If the set can fit the array should be the one passed in.", originalArray, retArray); + //Test the case where the passe array is too small to fit the set + set.add(9); + assertNotEquals("A new set should be generated if the contents will not fit in the passed set", + set.toArray(originalArray), originalArray); + //Now test the case where there should be a null terminator + set.clear(); + fillSet(5, set); + assertNull("The character one after last should be null if the array is larger than the set.", + set.toArray(originalArray)[5]); + } + + @Test + public void testAdd() throws Exception { + //Test of add + for (int i = 0; i < 10; i++) { + assertEquals("The size of the set is wrong.", i, set.size()); + assertTrue("The first add of an element should be true.", set.add(i)); + assertFalse("The second add of an element should be false.", set.add(i)); + } + } + + @Test + public void testRemove() throws Exception { + //Test removal + fillSet(10, set); + for (int i = 0; i < 10; i++) { + assertEquals("The size of the set is wrong.", 10 - i, set.size()); + assertTrue("The first removal should be true.", set.remove(i)); + assertFalse("The second removal should be false (item no longer contained).", set.remove(i)); + } + assertTrue("All elements should have been removed.", set.isEmpty()); + } + + @Test + public void testContainsAll() throws Exception { + //Test contains with short circuiting + Set<Integer> integersToCheck = Sets.newHashSet(); + fillSet(10, integersToCheck); + fillSet(10, set); + assertTrue("The sets should be identical so mutual subsets.", set.containsAll(integersToCheck)); + set.remove(9); + assertFalse("The set should contain one fewer value.", set.containsAll(integersToCheck)); + } + + @Test + public void testAddAll() throws Exception { + //Test multi-adds with change checking + Set<Integer> integersToCheck = Sets.newHashSet(); + fillSet(10, integersToCheck); + assertFalse("Set should be empty and so integers to check should not be a subset.", + set.containsAll(integersToCheck)); + assertTrue("The set should have changed as a result of add all.", set.addAll(integersToCheck)); + assertFalse("The set should not have changed as a result of add all a second time.", + set.addAll(integersToCheck)); + assertTrue("The sets should now be equivalent.", set.containsAll(integersToCheck)); + assertTrue("The sets should now be equivalent.", integersToCheck.containsAll(set)); + } + + @Test + public void testRetainAll() throws Exception { + //Test ability to generate the intersection set + Set<Integer> retainSet = Sets.newHashSet(); + fillSet(10, set); + assertTrue("The set should have changed.", set.retainAll(retainSet)); + assertTrue("The set should have been emptied.", set.isEmpty()); + fillSet(10, set); + fillSet(10, retainSet); + Set<Integer> duplicateSet = new HashSet<>(set); + assertFalse("The set should not have changed.", set.retainAll(retainSet)); + assertEquals("The set should be the same as the duplicate.", duplicateSet, set); + retainSet.remove(9); + assertTrue("The set should have changed.", set.retainAll(retainSet)); + duplicateSet.remove(9); + assertEquals("The set should have had the nine element removed.", duplicateSet, set); + } + + @Test + public void testRemoveAll() throws Exception { + //Test for mass removal and change checking + Set<Integer> removeSet = Sets.newHashSet(); + fillSet(10, set); + Set<Integer> duplicateSet = Sets.newHashSet(set); + assertFalse("No elements should change.", set.removeAll(removeSet)); + assertEquals("Set should not have diverged from the duplicate.", duplicateSet, set); + fillSet(5, removeSet); + assertTrue("Elements should have been removed.", set.removeAll(removeSet)); + assertNotEquals("Duplicate set should no longer be equivalent.", duplicateSet, set); + assertEquals("Five elements should have been removed from set.", 5, set.size()); + for (Integer item : removeSet) { + assertFalse("No element of remove set should remain.", set.contains(item)); + } + } + + @Test + public void testClear() throws Exception { + //Test set emptying + assertTrue("The set should be initialized empty.", set.isEmpty()); + set.clear(); + assertTrue("Clear should have no effect on an empty set.", set.isEmpty()); + fillSet(10, set); + assertFalse("The set should no longer be empty.", set.isEmpty()); + set.clear(); + assertTrue("The set should be empty after clear.", set.isEmpty()); + } + + /** + * Populated the map with integers from (0) up to (numEntries - 1). + * + * @param numEntries number of entries to add + */ + private void fillSet(int numEntries, Set<Integer> set) { + checkNotNull(set); + for (int i = 0; i < numEntries; i++) { + set.add(i); + } + } +} diff --git a/framework/src/onos/core/store/pom.xml b/framework/src/onos/core/store/pom.xml index 2b246b83..219ae5d0 100644 --- a/framework/src/onos/core/store/pom.xml +++ b/framework/src/onos/core/store/pom.xml @@ -33,7 +33,8 @@ <modules> <module>dist</module> - <module>serializers</module> + <module>persistence</module> + <module>serializers</module> </modules> <dependencies> diff --git a/framework/src/onos/core/store/serializers/src/main/java/org/onosproject/store/serializers/ExtensionInstructionSerializer.java b/framework/src/onos/core/store/serializers/src/main/java/org/onosproject/store/serializers/ExtensionInstructionSerializer.java new file mode 100644 index 00000000..6b12df96 --- /dev/null +++ b/framework/src/onos/core/store/serializers/src/main/java/org/onosproject/store/serializers/ExtensionInstructionSerializer.java @@ -0,0 +1,73 @@ +/* + * 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.store.serializers; + +import com.esotericsoftware.kryo.Kryo; +import com.esotericsoftware.kryo.Serializer; +import com.esotericsoftware.kryo.io.Input; +import com.esotericsoftware.kryo.io.Output; +import org.onlab.osgi.DefaultServiceDirectory; +import org.onosproject.net.DeviceId; +import org.onosproject.net.behaviour.ExtensionResolver; +import org.onosproject.net.driver.DefaultDriverData; +import org.onosproject.net.driver.DefaultDriverHandler; +import org.onosproject.net.driver.DriverHandler; +import org.onosproject.net.driver.DriverService; +import org.onosproject.net.flow.instructions.ExtensionInstruction; +import org.onosproject.net.flow.instructions.ExtensionType; +import org.onosproject.net.flow.instructions.Instructions; + +/** + * Created by jono on 10/29/15. + */ +public class ExtensionInstructionSerializer extends + Serializer<Instructions.ExtensionInstructionWrapper> { + + public ExtensionInstructionSerializer() { + super(false, true); + } + + @Override + public void write(Kryo kryo, Output output, Instructions.ExtensionInstructionWrapper object) { + kryo.writeClassAndObject(output, object.extensionInstruction().type()); + kryo.writeClassAndObject(output, object.deviceId()); + + kryo.writeClassAndObject(output, object.extensionInstruction().serialize()); + + } + + @Override + public Instructions.ExtensionInstructionWrapper read(Kryo kryo, Input input, + Class<Instructions.ExtensionInstructionWrapper> type) { + ExtensionType exType = (ExtensionType) kryo.readClassAndObject(input); + DeviceId deviceId = (DeviceId) kryo.readClassAndObject(input); + + DriverService driverService = DefaultServiceDirectory.getService(DriverService.class); + DriverHandler handler = new DefaultDriverHandler( + new DefaultDriverData(driverService.getDriver(deviceId), deviceId)); + + ExtensionResolver resolver = handler.behaviour(ExtensionResolver.class); + + ExtensionInstruction instruction = resolver.getExtensionInstruction(exType); + + byte[] bytes = (byte[]) kryo.readClassAndObject(input); + + instruction.deserialize(bytes); + + return Instructions.extension(instruction, deviceId); + } +} diff --git a/framework/src/onos/core/store/serializers/src/main/java/org/onosproject/store/serializers/KryoNamespaces.java b/framework/src/onos/core/store/serializers/src/main/java/org/onosproject/store/serializers/KryoNamespaces.java index 5b5056cb..0312bafd 100644 --- a/framework/src/onos/core/store/serializers/src/main/java/org/onosproject/store/serializers/KryoNamespaces.java +++ b/framework/src/onos/core/store/serializers/src/main/java/org/onosproject/store/serializers/KryoNamespaces.java @@ -70,6 +70,7 @@ import org.onosproject.net.OchPort; import org.onosproject.net.OchSignal; import org.onosproject.net.OchSignalType; import org.onosproject.net.OduCltPort; +import org.onosproject.net.OduSignalId; import org.onosproject.net.OduSignalType; import org.onosproject.net.OmsPort; import org.onosproject.net.Port; @@ -118,6 +119,8 @@ import org.onosproject.net.flow.criteria.MetadataCriterion; 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.OduSignalIdCriterion; +import org.onosproject.net.flow.criteria.OduSignalTypeCriterion; import org.onosproject.net.flow.criteria.PortCriterion; import org.onosproject.net.flow.criteria.SctpPortCriterion; import org.onosproject.net.flow.criteria.TcpPortCriterion; @@ -125,8 +128,10 @@ 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.onosproject.net.flow.instructions.ExtensionType; import org.onosproject.net.flow.instructions.Instructions; import org.onosproject.net.flow.instructions.L0ModificationInstruction; +import org.onosproject.net.flow.instructions.L1ModificationInstruction; import org.onosproject.net.flow.instructions.L2ModificationInstruction; import org.onosproject.net.flow.instructions.L3ModificationInstruction; import org.onosproject.net.flow.instructions.L4ModificationInstruction; @@ -337,6 +342,8 @@ public final class KryoNamespaces { IndexedLambdaCriterion.class, OchSignalCriterion.class, OchSignalTypeCriterion.class, + OduSignalIdCriterion.class, + OduSignalTypeCriterion.class, Criterion.class, Criterion.Type.class, DefaultTrafficTreatment.class, @@ -349,6 +356,9 @@ public final class KryoNamespaces { L0ModificationInstruction.L0SubType.class, L0ModificationInstruction.ModLambdaInstruction.class, L0ModificationInstruction.ModOchSignalInstruction.class, + L1ModificationInstruction.class, + L1ModificationInstruction.L1SubType.class, + L1ModificationInstruction.ModOduSignalIdInstruction.class, L2ModificationInstruction.class, L2ModificationInstruction.L2SubType.class, L2ModificationInstruction.ModEtherInstruction.class, @@ -441,6 +451,8 @@ public final class KryoNamespaces { .register(new HostLocationSerializer(), HostLocation.class) .register(new DefaultOutboundPacketSerializer(), DefaultOutboundPacket.class) .register(new AnnotationsSerializer(), DefaultAnnotations.class) + .register(new ExtensionInstructionSerializer(), Instructions.ExtensionInstructionWrapper.class) + .register(ExtensionType.class) .register(Versioned.class) .register(MapEvent.class) .register(MapEvent.Type.class) @@ -458,6 +470,7 @@ public final class KryoNamespaces { .register(OduCltPort.SignalType.class) .register(IndexedLambda.class) .register(OchSignal.class) + .register(OduSignalId.class) .register(OduCltPortDescription.class) .register(OchPortDescription.class) .register(OmsPortDescription.class) diff --git a/framework/src/onos/docs/internal-bgpls b/framework/src/onos/docs/internal-bgpls new file mode 100644 index 00000000..f264c7db --- /dev/null +++ b/framework/src/onos/docs/internal-bgpls @@ -0,0 +1,2 @@ +org.onosproject.bgp.controller* +org.onosproject.bgpio* diff --git a/framework/src/onos/docs/internal-stores b/framework/src/onos/docs/internal-stores index 13c00431..1f1f05ab 100644 --- a/framework/src/onos/docs/internal-stores +++ b/framework/src/onos/docs/internal-stores @@ -1 +1,2 @@ org.onosproject.store.* +org.onosproject.persistence.impl diff --git a/framework/src/onos/docs/internal.xml b/framework/src/onos/docs/internal.xml index de9c1c64..602479eb 100644 --- a/framework/src/onos/docs/internal.xml +++ b/framework/src/onos/docs/internal.xml @@ -90,6 +90,10 @@ <packages>@internal-pcep</packages> </group> <group> + <title>BGP-LS Providers</title> + <packages>@internal-bgpls</packages> + </group> + <group> <title>Other Providers</title> <packages>@internal-providers</packages> </group> diff --git a/framework/src/onos/drivers/src/main/java/org/onosproject/driver/extensions/NiciraExtensionInterpreter.java b/framework/src/onos/drivers/src/main/java/org/onosproject/driver/extensions/NiciraExtensionInterpreter.java new file mode 100644 index 00000000..082c5a6d --- /dev/null +++ b/framework/src/onos/drivers/src/main/java/org/onosproject/driver/extensions/NiciraExtensionInterpreter.java @@ -0,0 +1,84 @@ +/* + * 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.driver.extensions; + +import org.onlab.packet.Ip4Address; +import org.onosproject.net.behaviour.ExtensionResolver; +import org.onosproject.net.driver.AbstractHandlerBehaviour; +import org.onosproject.net.flow.instructions.ExtensionInstruction; +import org.onosproject.net.flow.instructions.ExtensionType; +import org.onosproject.openflow.controller.ExtensionInterpreter; +import org.projectfloodlight.openflow.protocol.OFActionType; +import org.projectfloodlight.openflow.protocol.OFFactory; +import org.projectfloodlight.openflow.protocol.action.OFAction; +import org.projectfloodlight.openflow.protocol.action.OFActionSetField; +import org.projectfloodlight.openflow.protocol.oxm.OFOxm; +import org.projectfloodlight.openflow.protocol.oxm.OFOxmTunnelIpv4Dst; +import org.projectfloodlight.openflow.types.IPv4Address; + +/** + * Interpreter for Nicira OpenFlow extensions. + */ +public class NiciraExtensionInterpreter extends AbstractHandlerBehaviour + implements ExtensionInterpreter, ExtensionResolver { + + @Override + public boolean supported(ExtensionType extensionType) { + if (extensionType.equals(ExtensionType.ExtensionTypes.NICIRA_SET_TUNNEL_DST)) { + return true; + } + + return false; + } + + @Override + public OFAction mapInstruction(OFFactory factory, ExtensionInstruction extensionInstruction) { + ExtensionType type = extensionInstruction.type(); + if (type.equals(ExtensionType.ExtensionTypes.NICIRA_SET_TUNNEL_DST.type())) { + NiciraSetTunnelDst tunnelDst = (NiciraSetTunnelDst) extensionInstruction; + return factory.actions().setField(factory.oxms().tunnelIpv4Dst( + IPv4Address.of(tunnelDst.tunnelDst().toInt()))); + } + return null; + } + + @Override + public ExtensionInstruction mapAction(OFAction action) { + if (action.getType().equals(OFActionType.SET_FIELD)) { + OFActionSetField setFieldAction = (OFActionSetField) action; + OFOxm<?> oxm = setFieldAction.getField(); + switch (oxm.getMatchField().id) { + case TUNNEL_IPV4_DST: + OFOxmTunnelIpv4Dst tunnelIpv4Dst = (OFOxmTunnelIpv4Dst) oxm; + return new NiciraSetTunnelDst(Ip4Address.valueOf(tunnelIpv4Dst.getValue().getInt())); + default: + throw new UnsupportedOperationException( + "Driver does not support extension type " + oxm.getMatchField().id); + } + } + return null; + } + + @Override + public ExtensionInstruction getExtensionInstruction(ExtensionType type) { + if (type.equals(ExtensionType.ExtensionTypes.NICIRA_SET_TUNNEL_DST.type())) { + return new NiciraSetTunnelDst(); + } + throw new UnsupportedOperationException( + "Driver does not support extension type " + type.toString()); + } +} diff --git a/framework/src/onos/drivers/src/main/java/org/onosproject/driver/extensions/NiciraSetTunnelDst.java b/framework/src/onos/drivers/src/main/java/org/onosproject/driver/extensions/NiciraSetTunnelDst.java new file mode 100644 index 00000000..16aa1b07 --- /dev/null +++ b/framework/src/onos/drivers/src/main/java/org/onosproject/driver/extensions/NiciraSetTunnelDst.java @@ -0,0 +1,106 @@ +/* + * 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.driver.extensions; + +import com.google.common.base.MoreObjects; +import org.onlab.packet.Ip4Address; +import org.onlab.util.KryoNamespace; +import org.onosproject.net.flow.instructions.AbstractExtensionInstruction; +import org.onosproject.net.flow.instructions.ExtensionType; +import org.onosproject.store.serializers.Ip4AddressSerializer; + +import java.util.Objects; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Nicira set tunnel destination extension instruction. + */ +public class NiciraSetTunnelDst extends AbstractExtensionInstruction { + + private Ip4Address tunnelDst; + + private final KryoNamespace appKryo = new KryoNamespace.Builder() + .register(new Ip4AddressSerializer(), Ip4Address.class) + .register(byte[].class) + .build(); + + /** + * Creates a new set tunnel destination instruction. + */ + NiciraSetTunnelDst() { + tunnelDst = null; + } + + /** + * Creates a new set tunnel destination instruction with a particular IPv4 + * address. + */ + NiciraSetTunnelDst(Ip4Address tunnelDst) { + checkNotNull(tunnelDst); + this.tunnelDst = tunnelDst; + } + + /** + * Gets the tunnel destination IPv4 address. + * + * @return tunnel destination IPv4 address + */ + public Ip4Address tunnelDst() { + return tunnelDst; + } + + @Override + public ExtensionType type() { + return ExtensionType.ExtensionTypes.NICIRA_SET_TUNNEL_DST.type(); + } + + @Override + public void deserialize(byte[] data) { + tunnelDst = appKryo.deserialize(data); + } + + @Override + public byte[] serialize() { + return appKryo.serialize(tunnelDst); + } + + @Override + public int hashCode() { + return Objects.hash(tunnelDst); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof NiciraSetTunnelDst) { + NiciraSetTunnelDst that = (NiciraSetTunnelDst) obj; + return Objects.equals(tunnelDst, that.tunnelDst); + + } + return false; + } + + @Override + public String toString() { + return MoreObjects.toStringHelper(getClass()) + .add("tunnelDst", tunnelDst) + .toString(); + } +} diff --git a/framework/src/onos/drivers/src/main/java/org/onosproject/driver/extensions/package-info.java b/framework/src/onos/drivers/src/main/java/org/onosproject/driver/extensions/package-info.java new file mode 100644 index 00000000..d9d2460d --- /dev/null +++ b/framework/src/onos/drivers/src/main/java/org/onosproject/driver/extensions/package-info.java @@ -0,0 +1,19 @@ +/* + * 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. + */ +/** + * Processing of Nicira extensions. + */ +package org.onosproject.driver.extensions; diff --git a/framework/src/onos/drivers/src/main/java/org/onosproject/driver/ovsdb/OvsdbBridgeConfig.java b/framework/src/onos/drivers/src/main/java/org/onosproject/driver/ovsdb/OvsdbBridgeConfig.java index 524163a1..77b48298 100644 --- a/framework/src/onos/drivers/src/main/java/org/onosproject/driver/ovsdb/OvsdbBridgeConfig.java +++ b/framework/src/onos/drivers/src/main/java/org/onosproject/driver/ovsdb/OvsdbBridgeConfig.java @@ -22,11 +22,13 @@ import java.util.Set; import java.util.stream.Collectors; import org.onlab.packet.IpAddress; +import org.onosproject.net.DefaultAnnotations; import org.onosproject.net.DeviceId; import org.onosproject.net.PortNumber; import org.onosproject.net.behaviour.BridgeConfig; import org.onosproject.net.behaviour.BridgeDescription; import org.onosproject.net.behaviour.BridgeName; +import org.onosproject.net.behaviour.ControllerInfo; import org.onosproject.net.behaviour.DefaultBridgeDescription; import org.onosproject.net.device.DefaultPortDescription; import org.onosproject.net.device.PortDescription; @@ -52,6 +54,13 @@ public class OvsdbBridgeConfig extends AbstractHandlerBehaviour } @Override + public boolean addBridge(BridgeName bridgeName, String dpid, List<ControllerInfo> controllers) { + DriverHandler handler = handler(); + OvsdbClientService clientService = getOvsdbClientService(handler); + return clientService.createBridge(bridgeName.name(), dpid, controllers); + } + + @Override public void deleteBridge(BridgeName bridgeName) { DriverHandler handler = handler(); OvsdbClientService clientService = getOvsdbClientService(handler); @@ -108,22 +117,22 @@ public class OvsdbBridgeConfig extends AbstractHandlerBehaviour return ports.stream() .map(x -> new DefaultPortDescription( PortNumber.portNumber(x.portNumber().value()), - true - ) - ) + true, + DefaultAnnotations.builder() + .set("portName", x.portName().value()) + .build())) .collect(Collectors.toSet()); } - // OvsdbNodeId(IP:port) is used in the adaptor while DeviceId(ovsdb:IP:port) + // OvsdbNodeId(IP) is used in the adaptor while DeviceId(ovsdb:IP) // is used in the core. So DeviceId need be changed to OvsdbNodeId. private OvsdbNodeId changeDeviceIdToNodeId(DeviceId deviceId) { - int lastColon = deviceId.toString().lastIndexOf(":"); - int fistColon = deviceId.toString().indexOf(":"); - String ip = deviceId.toString().substring(fistColon + 1, lastColon); - String port = deviceId.toString().substring(lastColon + 1); - IpAddress ipAddress = IpAddress.valueOf(ip); - long portL = Long.parseLong(port); - return new OvsdbNodeId(ipAddress, portL); + String[] splits = deviceId.toString().split(":"); + if (splits == null || splits.length < 1) { + return null; + } + IpAddress ipAddress = IpAddress.valueOf(splits[1]); + return new OvsdbNodeId(ipAddress, 0); } // Used for getting OvsdbClientService. diff --git a/framework/src/onos/drivers/src/main/java/org/onosproject/driver/ovsdb/OvsdbTunnelConfig.java b/framework/src/onos/drivers/src/main/java/org/onosproject/driver/ovsdb/OvsdbTunnelConfig.java index d32fb6be..a32553ad 100644 --- a/framework/src/onos/drivers/src/main/java/org/onosproject/driver/ovsdb/OvsdbTunnelConfig.java +++ b/framework/src/onos/drivers/src/main/java/org/onosproject/driver/ovsdb/OvsdbTunnelConfig.java @@ -16,12 +16,14 @@ package org.onosproject.driver.ovsdb; import java.util.Collection; - +import java.util.Map; import java.util.Set; import java.util.stream.Collectors; import org.onlab.packet.IpAddress; +import org.onosproject.net.DefaultAnnotations; import org.onosproject.net.DeviceId; +import org.onosproject.net.behaviour.BridgeName; import org.onosproject.net.behaviour.DefaultTunnelDescription; import org.onosproject.net.behaviour.IpTunnelEndPoint; import org.onosproject.net.behaviour.TunnelConfig; @@ -41,6 +43,8 @@ public class OvsdbTunnelConfig extends AbstractHandlerBehaviour implements TunnelConfig { private static final String DEFAULT_ADDRESS = "0.0.0.0"; + private static final String OPTION_LOCAL_IP = "local_ip"; + private static final String OPTION_REMOTE_IP = "remote_ip"; @Override public void createTunnel(TunnelDescription tunnel) { @@ -61,6 +65,22 @@ public class OvsdbTunnelConfig extends AbstractHandlerBehaviour } @Override + public boolean createTunnelInterface(BridgeName bridgeName, TunnelDescription tunnel) { + Map<String, String> options = ((DefaultAnnotations) tunnel.annotations()).asMap(); + if (tunnel.src() != null) { + options.put(OPTION_LOCAL_IP, tunnel.src().toString()); + } + if (tunnel.dst() != null) { + options.put(OPTION_REMOTE_IP, tunnel.dst().toString()); + } + + DriverHandler handler = handler(); + OvsdbClientService ovsdbClient = getOvsdbNode(handler); + return ovsdbClient.createTunnel(bridgeName.name(), tunnel.tunnelName().toString(), + tunnel.type().toString().toLowerCase(), options); + } + + @Override public void removeTunnel(TunnelDescription tunnel) { DriverHandler handler = handler(); OvsdbClientService ovsdbNode = getOvsdbNode(handler); @@ -102,16 +122,15 @@ public class OvsdbTunnelConfig extends AbstractHandlerBehaviour .collect(Collectors.toSet()); } - // OvsdbNodeId(IP:port) is used in the adaptor while DeviceId(ovsdb:IP:port) + // OvsdbNodeId(IP) is used in the adaptor while DeviceId(ovsdb:IP) // is used in the core. So DeviceId need be changed to OvsdbNodeId. private OvsdbNodeId changeDeviceIdToNodeId(DeviceId deviceId) { - int lastColon = deviceId.toString().lastIndexOf(":"); - int fistColon = deviceId.toString().indexOf(":"); - String ip = deviceId.toString().substring(fistColon + 1, lastColon); - String port = deviceId.toString().substring(lastColon + 1); - IpAddress ipAddress = IpAddress.valueOf(ip); - long portL = Long.parseLong(port); - return new OvsdbNodeId(ipAddress, portL); + String[] splits = deviceId.toString().split(":"); + if (splits == null || splits.length < 1) { + return null; + } + IpAddress ipAddress = IpAddress.valueOf(splits[1]); + return new OvsdbNodeId(ipAddress, 0); } private OvsdbClientService getOvsdbNode(DriverHandler handler) { diff --git a/framework/src/onos/drivers/src/main/java/org/onosproject/driver/pipeline/CpqdOFDPA1Pipeline.java b/framework/src/onos/drivers/src/main/java/org/onosproject/driver/pipeline/CpqdOFDPA2Pipeline.java index c9ef451e..a830ed49 100644 --- a/framework/src/onos/drivers/src/main/java/org/onosproject/driver/pipeline/CpqdOFDPA1Pipeline.java +++ b/framework/src/onos/drivers/src/main/java/org/onosproject/driver/pipeline/CpqdOFDPA2Pipeline.java @@ -29,22 +29,23 @@ import org.slf4j.Logger; /** - * Driver for software switch emulation of the OFDPA 1.0 pipeline. + * Driver for software switch emulation of the OFDPA 2.0 pipeline. * The software switch is the CPqD OF 1.3 switch. */ -public class CpqdOFDPA1Pipeline extends OFDPA1Pipeline { +public class CpqdOFDPA2Pipeline extends OFDPA2Pipeline { private final Logger log = getLogger(getClass()); @Override protected void initializePipeline() { processPortTable(); - //processVlanTable(); processTmacTable(); processIpTable(); - //processMcastTable(); processBridgingTable(); processAclTable(); + // XXX implement table miss entries and default groups + //processVlanTable(); + //processMPLSTable(); //processGroupTable(); } @@ -169,6 +170,7 @@ public class CpqdOFDPA1Pipeline extends OFDPA1Pipeline { })); } + @Override protected void processAclTable() { //table miss entry - catch all to executed action-set FlowRuleOperations.Builder ops = FlowRuleOperations.builder(); diff --git a/framework/src/onos/drivers/src/main/java/org/onosproject/driver/pipeline/OFDPA1Pipeline.java b/framework/src/onos/drivers/src/main/java/org/onosproject/driver/pipeline/OFDPA2Pipeline.java index f17309e1..b1a1256a 100644 --- a/framework/src/onos/drivers/src/main/java/org/onosproject/driver/pipeline/OFDPA1Pipeline.java +++ b/framework/src/onos/drivers/src/main/java/org/onosproject/driver/pipeline/OFDPA2Pipeline.java @@ -18,6 +18,7 @@ package org.onosproject.driver.pipeline; import static org.onlab.util.Tools.groupedThreads; import static org.slf4j.LoggerFactory.getLogger; +import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; @@ -30,18 +31,26 @@ import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; import org.onlab.osgi.ServiceDirectory; +import org.onlab.packet.Data; import org.onlab.packet.Ethernet; +import org.onlab.packet.IPv4; +import org.onlab.packet.IpPrefix; +import org.onlab.packet.MPLS; +import org.onlab.packet.MacAddress; import org.onlab.packet.MplsLabel; +import org.onlab.packet.UDP; import org.onlab.packet.VlanId; import org.onlab.util.KryoNamespace; import org.onosproject.core.ApplicationId; import org.onosproject.core.CoreService; import org.onosproject.core.DefaultGroupId; import org.onosproject.net.DeviceId; +import org.onosproject.net.Port; import org.onosproject.net.PortNumber; import org.onosproject.net.behaviour.NextGroup; import org.onosproject.net.behaviour.Pipeliner; import org.onosproject.net.behaviour.PipelinerContext; +import org.onosproject.net.device.DeviceService; import org.onosproject.net.driver.AbstractHandlerBehaviour; import org.onosproject.net.flow.DefaultFlowRule; import org.onosproject.net.flow.DefaultTrafficSelector; @@ -81,6 +90,11 @@ import org.onosproject.net.group.GroupEvent; import org.onosproject.net.group.GroupKey; import org.onosproject.net.group.GroupListener; import org.onosproject.net.group.GroupService; +import org.onosproject.net.packet.DefaultOutboundPacket; +import org.onosproject.net.packet.OutboundPacket; +import org.onosproject.net.packet.PacketContext; +import org.onosproject.net.packet.PacketProcessor; +import org.onosproject.net.packet.PacketService; import org.onosproject.store.serializers.KryoNamespaces; import org.slf4j.Logger; @@ -90,19 +104,22 @@ import com.google.common.cache.RemovalCause; import com.google.common.cache.RemovalNotification; /** - * Driver for Broadcom's OF-DPA v1.0 TTP. + * Driver for Broadcom's OF-DPA v2.0 TTP. * */ -public class OFDPA1Pipeline extends AbstractHandlerBehaviour implements Pipeliner { +public class OFDPA2Pipeline extends AbstractHandlerBehaviour implements Pipeliner { protected static final int PORT_TABLE = 0; protected static final int VLAN_TABLE = 10; protected static final int TMAC_TABLE = 20; protected static final int UNICAST_ROUTING_TABLE = 30; protected static final int MULTICAST_ROUTING_TABLE = 40; + protected static final int MPLS_TABLE_0 = 23; + protected static final int MPLS_TABLE_1 = 24; protected static final int BRIDGING_TABLE = 50; protected static final int ACL_TABLE = 60; protected static final int MAC_LEARNING_TABLE = 254; + protected static final long OFPP_MAX = 0xffffff00L; private static final int HIGHEST_PRIORITY = 0xffff; private static final int DEFAULT_PRIORITY = 0x8000; @@ -128,6 +145,8 @@ public class OFDPA1Pipeline extends AbstractHandlerBehaviour implements Pipeline */ private static final int L2INTERFACEMASK = 0x0; private static final int L3UNICASTMASK = 0x20000000; + //private static final int MPLSINTERFACEMASK = 0x90000000; + private static final int L3ECMPMASK = 0x70000000; private final Logger log = getLogger(getClass()); private ServiceDirectory serviceDirectory; @@ -137,7 +156,9 @@ public class OFDPA1Pipeline extends AbstractHandlerBehaviour implements Pipeline private FlowObjectiveStore flowObjectiveStore; protected DeviceId deviceId; protected ApplicationId driverId; - + protected PacketService packetService; + protected DeviceService deviceService; + private InternalPacketProcessor processor = new InternalPacketProcessor(); private KryoNamespace appKryo = new KryoNamespace.Builder() .register(KryoNamespaces.API) .register(GroupKey.class) @@ -151,7 +172,9 @@ public class OFDPA1Pipeline extends AbstractHandlerBehaviour implements Pipeline private ScheduledExecutorService groupChecker = Executors.newScheduledThreadPool(2, groupedThreads("onos/pipeliner", - "ofdpa1-%d")); + "ofdpa2-%d")); + private Set<IPCriterion> sentIpFilters = Collections.newSetFromMap( + new ConcurrentHashMap<IPCriterion, Boolean>()); @Override public void init(DeviceId deviceId, PipelinerContext context) { @@ -174,16 +197,29 @@ public class OFDPA1Pipeline extends AbstractHandlerBehaviour implements Pipeline flowRuleService = serviceDirectory.get(FlowRuleService.class); groupService = serviceDirectory.get(GroupService.class); flowObjectiveStore = context.store(); - + packetService = serviceDirectory.get(PacketService.class); + deviceService = serviceDirectory.get(DeviceService.class); + packetService.addProcessor(processor, PacketProcessor.director(2)); groupService.addListener(new InnerGroupListener()); driverId = coreService.registerApplication( - "org.onosproject.driver.OFDPA1Pipeline"); + "org.onosproject.driver.OFDPA2Pipeline"); + // OF-DPA does not require initializing the pipeline as it puts default + // rules automatically in the hardware. However emulation of OFDPA in + // software switches does require table-miss-entries. initializePipeline(); } + protected void initializePipeline() { + + } + + ////////////////////////////////////// + // Flow Objectives + ////////////////////////////////////// + @Override public void filter(FilteringObjective filteringObjective) { if (filteringObjective.type() == FilteringObjective.Type.PERMIT) { @@ -191,6 +227,11 @@ public class OFDPA1Pipeline extends AbstractHandlerBehaviour implements Pipeline filteringObjective.op() == Objective.Operation.ADD, filteringObjective.appId()); } else { + // Note that packets that don't match the PERMIT filter are + // automatically denied. The DENY filter is used to deny packets + // that are otherwise permitted by the PERMIT filter. + // Use ACL table flow rules here for DENY filtering objectives + log.debug("filter objective other than PERMIT currently not supported"); fail(filteringObjective, ObjectiveError.UNSUPPORTED); } } @@ -257,25 +298,31 @@ public class OFDPA1Pipeline extends AbstractHandlerBehaviour implements Pipeline } } + ////////////////////////////////////// + // Flow handling + ////////////////////////////////////// + /** - * As per OFDPA 1.0 TTP, filtering of VLAN ids, MAC addresses (for routing) + * As per OFDPA 2.0 TTP, filtering of VLAN ids, MAC addresses (for routing) * and IP addresses configured on switch ports happen in different tables. * Note that IP filtering rules need to be added to the ACL table, as there * is no mechanism to send to controller via IP table. * - * @param filt - * @param install - * @param applicationId + * @param filt the filtering objective + * @param install indicates whether to add or remove the objective + * @param applicationId the application that sent this objective */ private void processFilter(FilteringObjective filt, boolean install, ApplicationId applicationId) { // This driver only processes filtering criteria defined with switch // ports as the key - PortCriterion p = null; EthCriterion e = null; VlanIdCriterion v = null; + PortCriterion portCriterion = null; + EthCriterion ethCriterion = null; + VlanIdCriterion vidCriterion = null; Collection<IPCriterion> ips = new ArrayList<IPCriterion>(); if (!filt.key().equals(Criteria.dummy()) && filt.key().type() == Criterion.Type.IN_PORT) { - p = (PortCriterion) filt.key(); + portCriterion = (PortCriterion) filt.key(); } else { log.warn("No key defined in filtering objective from app: {}. Not" + "processing filtering objective", applicationId); @@ -284,199 +331,238 @@ public class OFDPA1Pipeline extends AbstractHandlerBehaviour implements Pipeline } // convert filtering conditions for switch-intfs into flowrules FlowRuleOperations.Builder ops = FlowRuleOperations.builder(); - for (Criterion c : filt.conditions()) { - if (c.type() == Criterion.Type.ETH_DST) { - e = (EthCriterion) c; - } else if (c.type() == Criterion.Type.VLAN_VID) { - v = (VlanIdCriterion) c; - } else if (c.type() == Criterion.Type.IPV4_DST) { - ips.add((IPCriterion) c); + for (Criterion criterion : filt.conditions()) { + if (criterion.type() == Criterion.Type.ETH_DST) { + ethCriterion = (EthCriterion) criterion; + } else if (criterion.type() == Criterion.Type.VLAN_VID) { + vidCriterion = (VlanIdCriterion) criterion; + } else if (criterion.type() == Criterion.Type.IPV4_DST) { + ips.add((IPCriterion) criterion); } else { - log.error("Unsupported filter {}", c); + log.error("Unsupported filter {}", criterion); fail(filt, ObjectiveError.UNSUPPORTED); return; } } - log.debug("adding VLAN filtering rule in VLAN table: {}", e.mac()); - TrafficSelector.Builder selector = DefaultTrafficSelector.builder(); - TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder(); - selector.matchInPort(p.port()); - selector.matchVlanId(v.vlanId()); - treatment.transition(TMAC_TABLE); - FlowRule rule = DefaultFlowRule.builder() - .forDevice(deviceId) - .withSelector(selector.build()) - .withTreatment(treatment.build()) - .withPriority(DEFAULT_PRIORITY) - .fromApp(applicationId) - .makePermanent() - .forTable(VLAN_TABLE).build(); - ops = ops.add(rule); + VlanId assignedVlan = null; + if (vidCriterion != null && vidCriterion.vlanId() == VlanId.NONE) { + // untagged packets are assigned vlans in OF-DPA + if (filt.meta() == null) { + log.error("Missing metadata in filtering objective required " + + "for vlan assignment in dev {}", deviceId); + fail(filt, ObjectiveError.BADPARAMS); + return; + } + for (Instruction i : filt.meta().allInstructions()) { + if (i instanceof ModVlanIdInstruction) { + assignedVlan = ((ModVlanIdInstruction) i).vlanId(); + } + } + if (assignedVlan == null) { + log.error("Driver requires an assigned vlan-id to tag incoming " + + "untagged packets. Not processing vlan filters on " + + "device {}", deviceId); + fail(filt, ObjectiveError.BADPARAMS); + return; + } + } - log.debug("adding MAC filtering rules in TMAC table: {}", e.mac()); - selector = DefaultTrafficSelector.builder(); - treatment = DefaultTrafficTreatment.builder(); - selector.matchInPort(p.port()); - selector.matchVlanId(v.vlanId()); - selector.matchEthType(Ethernet.TYPE_IPV4); - selector.matchEthDst(e.mac()); - treatment.transition(UNICAST_ROUTING_TABLE); - rule = DefaultFlowRule.builder() - .forDevice(deviceId) - .withSelector(selector.build()) - .withTreatment(treatment.build()) - .withPriority(DEFAULT_PRIORITY) - .fromApp(applicationId) - .makePermanent() - .forTable(TMAC_TABLE).build(); - ops = ops.add(rule); + if (ethCriterion == null) { + log.debug("filtering objective missing dstMac, cannot program TMAC table"); + } else { + for (FlowRule tmacRule : processEthDstFilter(portCriterion, ethCriterion, + vidCriterion, assignedVlan, + applicationId)) { + log.debug("adding MAC filtering rules in TMAC table: {} for dev: {}", + tmacRule, deviceId); + ops = install ? ops.add(tmacRule) : ops.remove(tmacRule); + } + } + + if (ethCriterion == null || vidCriterion == null) { + log.debug("filtering objective missing dstMac or vlan, cannot program" + + "Vlan Table"); + } else { + for (FlowRule vlanRule : processVlanIdFilter(portCriterion, vidCriterion, + assignedVlan, + applicationId)) { + log.debug("adding VLAN filtering rule in VLAN table: {} for dev: {}", + vlanRule, deviceId); + ops = install ? ops.add(vlanRule) : ops.remove(vlanRule); + } + } - log.debug("adding IP filtering rules in ACL table"); for (IPCriterion ipaddr : ips) { - selector = DefaultTrafficSelector.builder(); - treatment = DefaultTrafficTreatment.builder(); - selector.matchEthType(Ethernet.TYPE_IPV4); - selector.matchIPDst(ipaddr.ip()); - treatment.setOutput(PortNumber.CONTROLLER); - rule = DefaultFlowRule.builder() - .forDevice(deviceId) - .withSelector(selector.build()) - .withTreatment(treatment.build()) - .withPriority(HIGHEST_PRIORITY) - .fromApp(applicationId) - .makePermanent() - .forTable(ACL_TABLE).build(); - ops = ops.add(rule); + // since we ignore port information for IP rules, and the same (gateway) IP + // can be configured on multiple ports, we make sure that we send + // only a single rule to the switch. + if (!sentIpFilters.contains(ipaddr)) { + sentIpFilters.add(ipaddr); + log.debug("adding IP filtering rules in ACL table {} for dev: {}", + ipaddr, deviceId); + TrafficSelector.Builder selector = DefaultTrafficSelector.builder(); + TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder(); + selector.matchEthType(Ethernet.TYPE_IPV4); + selector.matchIPDst(ipaddr.ip()); + treatment.setOutput(PortNumber.CONTROLLER); + FlowRule rule = DefaultFlowRule.builder() + .forDevice(deviceId) + .withSelector(selector.build()) + .withTreatment(treatment.build()) + .withPriority(HIGHEST_PRIORITY) + .fromApp(applicationId) + .makePermanent() + .forTable(ACL_TABLE).build(); + ops = install ? ops.add(rule) : ops.remove(rule); + } } - ops = install ? ops.add(rule) : ops.remove(rule); // apply filtering flow rules flowRuleService.apply(ops.build(new FlowRuleOperationsContext() { @Override public void onSuccess(FlowRuleOperations ops) { - log.info("Applied filtering rules"); + log.info("Applied {} filtering rules in device {}", + ops.stages().get(0).size(), deviceId); pass(filt); } @Override public void onError(FlowRuleOperations ops) { - log.info("Failed to apply filtering rules"); + log.info("Failed to apply all filtering rules in dev {}", deviceId); fail(filt, ObjectiveError.FLOWINSTALLATIONFAILED); } })); } - /** - * As per the OFDPA 1.0 TTP, packets are sent out of ports by using - * a chain of groups, namely an L3 Unicast Group that points to an L2 Interface - * Group which in turns points to an output port. The Next Objective passed - * in by the application has to be broken up into a group chain - * to satisfy this TTP. + * Allows untagged packets into pipeline by assigning a vlan id. + * Vlan assignment is done by the application. + * Allows tagged packets into pipeline as per configured port-vlan info. * - * @param nextObj the nextObjective of type SIMPLE + * @param portCriterion port on device for which this filter is programmed + * @param vidCriterion vlan assigned to port, or NONE for untagged + * @param assignedVlan assigned vlan-id for untagged packets + * @param applicationId for application programming this filter + * @return list of FlowRule for port-vlan filters */ - private void processSimpleNextObjective(NextObjective nextObj) { - // break up simple next objective to GroupChain objects - TrafficTreatment treatment = nextObj.next().iterator().next(); - // for the l2interface group, get vlan and port info - // for the l3unicast group, get the src/dst mac and vlan info - TrafficTreatment.Builder l3utt = DefaultTrafficTreatment.builder(); - TrafficTreatment.Builder l2itt = DefaultTrafficTreatment.builder(); - VlanId vlanid = null; - long portNum = 0; - for (Instruction ins : treatment.allInstructions()) { - if (ins.type() == Instruction.Type.L2MODIFICATION) { - L2ModificationInstruction l2ins = (L2ModificationInstruction) ins; - switch (l2ins.subtype()) { - case ETH_DST: - l3utt.setEthDst(((ModEtherInstruction) l2ins).mac()); - break; - case ETH_SRC: - l3utt.setEthSrc(((ModEtherInstruction) l2ins).mac()); - break; - case VLAN_ID: - vlanid = ((ModVlanIdInstruction) l2ins).vlanId(); - l3utt.setVlanId(vlanid); - break; - case DEC_MPLS_TTL: - case MPLS_LABEL: - case MPLS_POP: - case MPLS_PUSH: - case VLAN_PCP: - case VLAN_POP: - case VLAN_PUSH: - default: - break; + protected List<FlowRule> processVlanIdFilter(PortCriterion portCriterion, + VlanIdCriterion vidCriterion, + VlanId assignedVlan, + ApplicationId applicationId) { + List<FlowRule> rules = new ArrayList<FlowRule>(); + TrafficSelector.Builder selector = DefaultTrafficSelector.builder(); + TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder(); + selector.matchVlanId(vidCriterion.vlanId()); + if (vidCriterion.vlanId() == VlanId.NONE) { + // untagged packets are assigned vlans + treatment.pushVlan().setVlanId(assignedVlan); + // XXX ofdpa may require an additional vlan match on the assigned vlan + // and it may not require the push. + } + treatment.transition(TMAC_TABLE); + + // ofdpa cannot match on ALL portnumber, so we need to use separate + // rules for each port. + List<PortNumber> portnums = new ArrayList<PortNumber>(); + if (portCriterion.port() == PortNumber.ALL) { + for (Port port : deviceService.getPorts(deviceId)) { + if (port.number().toLong() > 0 && port.number().toLong() < OFPP_MAX) { + portnums.add(port.number()); } - } else if (ins.type() == Instruction.Type.OUTPUT) { - portNum = ((OutputInstruction) ins).port().toLong(); - l2itt.add(ins); - } else { - log.warn("Driver does not handle this type of TrafficTreatment" - + " instruction in nextObjectives: {}", ins.type()); } + } else { + portnums.add(portCriterion.port()); } - - // assemble information for ofdpa l2interface group - int l2gk = nextObj.id() | GROUP1MASK; - final GroupKey l2groupkey = new DefaultGroupKey(appKryo.serialize(l2gk)); - Integer l2groupId = L2INTERFACEMASK | (vlanid.toShort() << 16) | (int) portNum; - - // assemble information for ofdpa l3unicast group - int l3gk = nextObj.id() | GROUP0MASK; - final GroupKey l3groupkey = new DefaultGroupKey(appKryo.serialize(l3gk)); - Integer l3groupId = L3UNICASTMASK | (int) portNum; - l3utt.group(new DefaultGroupId(l2groupId)); - GroupChainElem gce = new GroupChainElem(l3groupkey, l3groupId, - l3utt.build(), nextObj.appId()); - - // create object for local and distributed storage - List<GroupKey> gkeys = new ArrayList<GroupKey>(); - gkeys.add(l3groupkey); // group0 in chain - gkeys.add(l2groupkey); // group1 in chain - OfdpaGroupChain ofdpaGrp = new OfdpaGroupChain(gkeys, nextObj); - - // store l2groupkey with the groupChainElem for the l3group that depends on it - pendingGroups.put(l2groupkey, gce); - - // store l3groupkey with the ofdpaGroupChain for the nextObjective that depends on it - pendingNextObjectives.put(l3groupkey, ofdpaGrp); - - // create group description for the ofdpa l2interfacegroup and send to groupservice - GroupBucket bucket = - DefaultGroupBucket.createIndirectGroupBucket(l2itt.build()); - GroupDescription groupDescription = new DefaultGroupDescription(deviceId, - GroupDescription.Type.INDIRECT, - new GroupBuckets(Collections.singletonList(bucket)), - l2groupkey, - l2groupId, - nextObj.appId()); - groupService.addGroup(groupDescription); + for (PortNumber pnum : portnums) { + selector.matchInPort(pnum); + FlowRule rule = DefaultFlowRule.builder() + .forDevice(deviceId) + .withSelector(selector.build()) + .withTreatment(treatment.build()) + .withPriority(DEFAULT_PRIORITY) + .fromApp(applicationId) + .makePermanent() + .forTable(VLAN_TABLE).build(); + rules.add(rule); + } + return rules; } /** - * Processes next element of a group chain. Assumption is that if this - * group points to another group, the latter has already been created - * and this driver has received notification for it. A second assumption is - * that if there is another group waiting for this group then the appropriate - * stores already have the information to act upon the notification for the - * creating of this group. + * Allows routed packets with correct destination MAC to be directed + * to unicast-IP routing table or MPLS forwarding table. + * XXX need to add rule for multicast routing. * - * @param gce the group chain element to be processed next + * @param portCriterion port on device for which this filter is programmed + * @param ethCriterion dstMac of device for which is filter is programmed + * @param vidCriterion vlan assigned to port, or NONE for untagged + * @param assignedVlan assigned vlan-id for untagged packets + * @param applicationId for application programming this filter + * @return list of FlowRule for port-vlan filters + */ - private void processGroupChain(GroupChainElem gce) { - GroupBucket bucket = DefaultGroupBucket - .createIndirectGroupBucket(gce.getBucketActions()); - GroupDescription groupDesc = new DefaultGroupDescription(deviceId, - GroupDescription.Type.INDIRECT, - new GroupBuckets(Collections.singletonList(bucket)), - gce.getGkey(), - gce.getGivenGroupId(), - gce.getAppId()); - groupService.addGroup(groupDesc); + protected List<FlowRule> processEthDstFilter(PortCriterion portCriterion, + EthCriterion ethCriterion, + VlanIdCriterion vidCriterion, + VlanId assignedVlan, + ApplicationId applicationId) { + //handling untagged packets via assigned VLAN + if (vidCriterion.vlanId() == VlanId.NONE) { + vidCriterion = (VlanIdCriterion) Criteria.matchVlanId(assignedVlan); + } + // ofdpa cannot match on ALL portnumber, so we need to use separate + // rules for each port. + List<PortNumber> portnums = new ArrayList<PortNumber>(); + if (portCriterion.port() == PortNumber.ALL) { + for (Port port : deviceService.getPorts(deviceId)) { + if (port.number().toLong() > 0 && port.number().toLong() < OFPP_MAX) { + portnums.add(port.number()); + } + } + } else { + portnums.add(portCriterion.port()); + } + + List<FlowRule> rules = new ArrayList<FlowRule>(); + for (PortNumber pnum : portnums) { + // for unicast IP packets + TrafficSelector.Builder selector = DefaultTrafficSelector.builder(); + TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder(); + selector.matchInPort(pnum); + selector.matchVlanId(vidCriterion.vlanId()); + selector.matchEthType(Ethernet.TYPE_IPV4); + selector.matchEthDst(ethCriterion.mac()); + treatment.transition(UNICAST_ROUTING_TABLE); + FlowRule rule = DefaultFlowRule.builder() + .forDevice(deviceId) + .withSelector(selector.build()) + .withTreatment(treatment.build()) + .withPriority(DEFAULT_PRIORITY) + .fromApp(applicationId) + .makePermanent() + .forTable(TMAC_TABLE).build(); + rules.add(rule); + //for MPLS packets + selector = DefaultTrafficSelector.builder(); + treatment = DefaultTrafficTreatment.builder(); + selector.matchInPort(pnum); + selector.matchVlanId(vidCriterion.vlanId()); + selector.matchEthType(Ethernet.MPLS_UNICAST); + selector.matchEthDst(ethCriterion.mac()); + treatment.transition(MPLS_TABLE_0); + rule = DefaultFlowRule.builder() + .forDevice(deviceId) + .withSelector(selector.build()) + .withTreatment(treatment.build()) + .withPriority(DEFAULT_PRIORITY) + .fromApp(applicationId) + .makePermanent() + .forTable(TMAC_TABLE).build(); + rules.add(rule); + } + return rules; } private Collection<FlowRule> processForward(ForwardingObjective fwd) { @@ -493,7 +579,7 @@ public class OFDPA1Pipeline extends AbstractHandlerBehaviour implements Pipeline } /** - * In the OF-DPA 1.0 pipeline, versatile forwarding objectives go to the + * In the OF-DPA 2.0 pipeline, versatile forwarding objectives go to the * ACL table. * @param fwd the forwarding objective of type 'versatile' * @return a collection of flow rules to be sent to the switch. An empty @@ -508,37 +594,46 @@ public class OFDPA1Pipeline extends AbstractHandlerBehaviour implements Pipeline (EthTypeCriterion) selector.getCriterion(Criterion.Type.ETH_TYPE); if (ethType == null) { log.error("Versatile forwarding objective must include ethType"); - fail(fwd, ObjectiveError.UNKNOWN); + fail(fwd, ObjectiveError.BADPARAMS); return Collections.emptySet(); } - if (ethType.ethType().toShort() == Ethernet.TYPE_ARP) { - log.warn("Installing ARP rule to table 60"); - - // currently need to punt from ACL table should use: - // OF apply-actions-instruction - // To use OF write-actions-instruction - /*TrafficTreatment.Builder tb = DefaultTrafficTreatment.builder(); - fwd.treatment().allInstructions().stream() - .forEach(ti -> tb.deferred().add(ti));*/ - - FlowRule.Builder ruleBuilder = DefaultFlowRule.builder() - .fromApp(fwd.appId()) - .withPriority(fwd.priority()) - .forDevice(deviceId) - .withSelector(fwd.selector()) - .withTreatment(fwd.treatment()) - .makePermanent() - .forTable(ACL_TABLE); - - return Collections.singletonList(ruleBuilder.build()); + if (fwd.nextId() == null && fwd.treatment() == null) { + log.error("Forwarding objective {} from {} must contain " + + "nextId or Treatment", fwd.selector(), fwd.appId()); + return Collections.emptySet(); + } + // XXX driver does not currently do type checking as per Tables 65-67 in + // OFDPA 2.0 spec. The only allowed treatment is a punt to the controller. + if (fwd.treatment() != null && + fwd.treatment().allInstructions().size() == 1 && + fwd.treatment().allInstructions().get(0).type() == Instruction.Type.OUTPUT) { + OutputInstruction o = (OutputInstruction) fwd.treatment().allInstructions().get(0); + if (o.port() == PortNumber.CONTROLLER) { + FlowRule.Builder ruleBuilder = DefaultFlowRule.builder() + .fromApp(fwd.appId()) + .withPriority(fwd.priority()) + .forDevice(deviceId) + .withSelector(fwd.selector()) + .withTreatment(fwd.treatment()) + .makePermanent() + .forTable(ACL_TABLE); + return Collections.singletonList(ruleBuilder.build()); + } else { + log.warn("Only allowed treatments in versatile forwarding " + + "objectives are punts to the controller"); + return Collections.emptySet(); + } } - // XXX not handling other versatile flows yet + if (fwd.nextId() != null) { + // XXX overide case + log.warn("versatile objective --> next Id not yet implemeted"); + } return Collections.emptySet(); } /** - * In the OF-DPA 1.0 pipeline, specific forwarding refers to the IP table + * In the OF-DPA 2.0 pipeline, specific forwarding refers to the IP table * (unicast or multicast) or the L2 table (mac + vlan). * * @param fwd the forwarding objective of type 'specific' @@ -602,151 +697,126 @@ public class OFDPA1Pipeline extends AbstractHandlerBehaviour implements Pipeline } } - private void fail(Objective obj, ObjectiveError error) { if (obj.context().isPresent()) { obj.context().get().onError(obj, error); } } + ////////////////////////////////////// + // Group handling + ////////////////////////////////////// - protected void initializePipeline() { - processPortTable(); - processVlanTable(); - processTmacTable(); - processIpTable(); - //processMcastTable(); - //processBridgingTable(); - //processAclTable(); - //processGroupTable(); - //processMplsTable(); - } - - protected void processMplsTable() { - FlowRuleOperations.Builder ops = FlowRuleOperations.builder(); - TrafficSelector.Builder selector = DefaultTrafficSelector.builder(); - selector.matchEthType(Ethernet.MPLS_UNICAST); - selector.matchMplsLabel(MplsLabel.mplsLabel(0xff)); - selector.matchMplsBos(true); - TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder(); - treatment.popMpls(Ethernet.TYPE_IPV4); - treatment.transition(ACL_TABLE); - FlowRule test = DefaultFlowRule.builder().forDevice(deviceId) - .withSelector(selector.build()).withTreatment(treatment.build()) - .withPriority(LOWEST_PRIORITY).fromApp(driverId).makePermanent() - .forTable(25).build(); - ops = ops.add(test); - - flowRuleService.apply(ops.build(new FlowRuleOperationsContext() { - @Override - public void onSuccess(FlowRuleOperations ops) { - log.info("Initialized mpls table"); - } - - @Override - public void onError(FlowRuleOperations ops) { - log.info("Failed to initialize mpls table"); + /** + * As per the OFDPA 2.0 TTP, packets are sent out of ports by using + * a chain of groups, namely an L3 Unicast Group that points to an L2 Interface + * Group which in turns points to an output port. The Next Objective passed + * in by the application has to be broken up into a group chain + * to satisfy this TTP. + * + * @param nextObj the nextObjective of type SIMPLE + */ + private void processSimpleNextObjective(NextObjective nextObj) { + // break up simple next objective to GroupChain objects + TrafficTreatment treatment = nextObj.next().iterator().next(); + // for the l2interface group, get vlan and port info + // for the l3unicast group, get the src/dst mac and vlan info + TrafficTreatment.Builder l3utt = DefaultTrafficTreatment.builder(); + TrafficTreatment.Builder l2itt = DefaultTrafficTreatment.builder(); + VlanId vlanid = null; + long portNum = 0; + for (Instruction ins : treatment.allInstructions()) { + if (ins.type() == Instruction.Type.L2MODIFICATION) { + L2ModificationInstruction l2ins = (L2ModificationInstruction) ins; + switch (l2ins.subtype()) { + case ETH_DST: + l3utt.setEthDst(((ModEtherInstruction) l2ins).mac()); + break; + case ETH_SRC: + l3utt.setEthSrc(((ModEtherInstruction) l2ins).mac()); + break; + case VLAN_ID: + vlanid = ((ModVlanIdInstruction) l2ins).vlanId(); + l3utt.setVlanId(vlanid); + break; + case DEC_MPLS_TTL: + case MPLS_LABEL: + case MPLS_POP: + case MPLS_PUSH: + case VLAN_PCP: + case VLAN_POP: + case VLAN_PUSH: + default: + break; + } + } else if (ins.type() == Instruction.Type.OUTPUT) { + portNum = ((OutputInstruction) ins).port().toLong(); + l2itt.add(ins); + } else { + log.warn("Driver does not handle this type of TrafficTreatment" + + " instruction in nextObjectives: {}", ins.type()); } - })); + } - } + // assemble information for ofdpa l2interface group + int l2gk = nextObj.id() | GROUP1MASK; + final GroupKey l2groupkey = new DefaultGroupKey(appKryo.serialize(l2gk)); + Integer l2groupId = L2INTERFACEMASK | (vlanid.toShort() << 16) | (int) portNum; - protected void processPortTable() { - //XXX is table miss entry enough or do we need to do the maskable in-port 0? - FlowRuleOperations.Builder ops = FlowRuleOperations.builder(); - TrafficSelector.Builder selector = DefaultTrafficSelector.builder(); - selector.matchInPort(PortNumber.portNumber(0)); // should be maskable? - TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder(); - treatment.transition(VLAN_TABLE); - FlowRule tmisse = DefaultFlowRule.builder() - .forDevice(deviceId) - .withSelector(selector.build()) - .withTreatment(treatment.build()) - .withPriority(LOWEST_PRIORITY) - .fromApp(driverId) - .makePermanent() - .forTable(PORT_TABLE).build(); - /*ops = ops.add(tmisse); + // assemble information for ofdpa l3unicast group + int l3gk = nextObj.id() | GROUP0MASK; + final GroupKey l3groupkey = new DefaultGroupKey(appKryo.serialize(l3gk)); + Integer l3groupId = L3UNICASTMASK | (int) portNum; + l3utt.group(new DefaultGroupId(l2groupId)); + GroupChainElem gce = new GroupChainElem(l3groupkey, l3groupId, + l3utt.build(), nextObj.appId()); - flowRuleService.apply(ops.build(new FlowRuleOperationsContext() { - @Override - public void onSuccess(FlowRuleOperations ops) { - log.info("Initialized port table"); - } + // create object for local and distributed storage + List<GroupKey> gkeys = new ArrayList<GroupKey>(); + gkeys.add(l3groupkey); // group0 in chain + gkeys.add(l2groupkey); // group1 in chain + OfdpaGroupChain ofdpaGrp = new OfdpaGroupChain(gkeys, nextObj); - @Override - public void onError(FlowRuleOperations ops) { - log.info("Failed to initialize port table"); - } - }));*/ + // store l2groupkey with the groupChainElem for the l3group that depends on it + pendingGroups.put(l2groupkey, gce); - } + // store l3groupkey with the ofdpaGroupChain for the nextObjective that depends on it + pendingNextObjectives.put(l3groupkey, ofdpaGrp); - private void processVlanTable() { - // Table miss entry is not required as ofdpa default is to drop - // In OF terms, the absence of a t.m.e. also implies drop + // create group description for the ofdpa l2interfacegroup and send to groupservice + GroupBucket bucket = + DefaultGroupBucket.createIndirectGroupBucket(l2itt.build()); + GroupDescription groupDescription = new DefaultGroupDescription(deviceId, + GroupDescription.Type.INDIRECT, + new GroupBuckets(Collections.singletonList(bucket)), + l2groupkey, + l2groupId, + nextObj.appId()); + groupService.addGroup(groupDescription); } - - protected void processTmacTable() { - //table miss entry - FlowRuleOperations.Builder ops = FlowRuleOperations.builder(); - TrafficSelector.Builder selector = DefaultTrafficSelector.builder(); - TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder(); - selector = DefaultTrafficSelector.builder(); - treatment = DefaultTrafficTreatment.builder(); - treatment.transition(BRIDGING_TABLE); - FlowRule rule = DefaultFlowRule.builder() - .forDevice(deviceId) - .withSelector(selector.build()) - .withTreatment(treatment.build()) - .withPriority(LOWEST_PRIORITY) - .fromApp(driverId) - .makePermanent() - .forTable(TMAC_TABLE).build(); - /*ops = ops.add(rule); // XXX bug in ofdpa - flowRuleService.apply(ops.build(new FlowRuleOperationsContext() { - @Override - public void onSuccess(FlowRuleOperations ops) { - log.info("Initialized tmac table"); - } - - @Override - public void onError(FlowRuleOperations ops) { - log.info("Failed to initialize tmac table"); - } - }));*/ + /** + * Processes next element of a group chain. Assumption is that if this + * group points to another group, the latter has already been created + * and this driver has received notification for it. A second assumption is + * that if there is another group waiting for this group then the appropriate + * stores already have the information to act upon the notification for the + * creating of this group. + * + * @param gce the group chain element to be processed next + */ + private void processGroupChain(GroupChainElem gce) { + GroupBucket bucket = DefaultGroupBucket + .createIndirectGroupBucket(gce.getBucketActions()); + GroupDescription groupDesc = new DefaultGroupDescription(deviceId, + GroupDescription.Type.INDIRECT, + new GroupBuckets(Collections.singletonList(bucket)), + gce.getGkey(), + gce.getGivenGroupId(), + gce.getAppId()); + groupService.addGroup(groupDesc); } - protected void processIpTable() { - //table miss entry - FlowRuleOperations.Builder ops = FlowRuleOperations.builder(); - TrafficSelector.Builder selector = DefaultTrafficSelector.builder(); - TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder(); - selector = DefaultTrafficSelector.builder(); - treatment = DefaultTrafficTreatment.builder(); - treatment.transition(ACL_TABLE); - FlowRule rule = DefaultFlowRule.builder() - .forDevice(deviceId) - .withSelector(selector.build()) - .withTreatment(treatment.build()) - .withPriority(LOWEST_PRIORITY) - .fromApp(driverId) - .makePermanent() - .forTable(UNICAST_ROUTING_TABLE).build(); - /*ops = ops.add(rule); - flowRuleService.apply(ops.build(new FlowRuleOperationsContext() { - @Override - public void onSuccess(FlowRuleOperations ops) { - log.info("Initialized IP table"); - } - - @Override - public void onError(FlowRuleOperations ops) { - log.info("Failed to initialize unicast IP table"); - } - }));*/ - } private class GroupChecker implements Runnable { @Override @@ -884,4 +954,416 @@ public class OFDPA1Pipeline extends AbstractHandlerBehaviour implements Pipeline } } + + ////////////////////////////////////// + // Test code to be used for future + // static-flow-pusher app + ////////////////////////////////////// + + public void processStaticFlows() { + //processPortTable(); + processGroupTable(); + processVlanTable(); + processTmacTable(); + processIpTable(); + //processMcastTable(); + //processBridgingTable(); + processAclTable(); + sendPackets(); + processMplsTable(); + } + + protected void processGroupTable() { + TrafficTreatment.Builder act = DefaultTrafficTreatment.builder(); + + act.popVlan(); // to send out untagged packets + act.setOutput(PortNumber.portNumber(24)); + GroupBucket bucket = + DefaultGroupBucket.createIndirectGroupBucket(act.build()); + final GroupKey groupkey = new DefaultGroupKey(appKryo.serialize(500)); + Integer groupId = 0x00c80018; //l2 interface, vlan 200, port 24 + GroupDescription groupDescription = new DefaultGroupDescription(deviceId, + GroupDescription.Type.INDIRECT, + new GroupBuckets(Collections.singletonList(bucket)), + groupkey, + groupId, + driverId); + groupService.addGroup(groupDescription); + + TrafficTreatment.Builder act2 = DefaultTrafficTreatment.builder(); + act2.setOutput(PortNumber.portNumber(40)); + GroupBucket bucket2 = DefaultGroupBucket.createIndirectGroupBucket(act2.build()); + final GroupKey groupkey2 = new DefaultGroupKey(appKryo.serialize(502)); + Integer groupId2 = 0x00c50028; //l2 interface, vlan 197, port 40 + GroupDescription groupDescription2 = new DefaultGroupDescription(deviceId, + GroupDescription.Type.INDIRECT, + new GroupBuckets(Collections.singletonList(bucket2)), + groupkey2, + groupId2, + driverId); + groupService.addGroup(groupDescription2); + + while (groupService.getGroup(deviceId, groupkey2) == null) { + try { + Thread.sleep(500); + } catch (InterruptedException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + + //Now for L3 Unicast group + TrafficTreatment.Builder act3 = DefaultTrafficTreatment.builder(); + act3.setEthDst(MacAddress.valueOf(0x2020)); + act3.setEthSrc(MacAddress.valueOf(0x1010)); + act3.setVlanId(VlanId.vlanId((short) 200)); + act3.group(new DefaultGroupId(0x00c80018)); // point to L2 interface + // MPLS interface group - does not work for popping single label + //Integer secGroupId = MPLSINTERFACEMASK | 38; // 0x90000026 + Integer groupId3 = L3UNICASTMASK | 1; // 0x20000001 + GroupBucket bucket3 = + DefaultGroupBucket.createIndirectGroupBucket(act3.build()); + final GroupKey groupkey3 = new DefaultGroupKey(appKryo.serialize(503)); + GroupDescription groupDescription3 = new DefaultGroupDescription(deviceId, + GroupDescription.Type.INDIRECT, + new GroupBuckets(Collections.singletonList(bucket3)), + groupkey3, + groupId3, + driverId); + groupService.addGroup(groupDescription3); + + //Another L3 Unicast group + TrafficTreatment.Builder act4 = DefaultTrafficTreatment.builder(); + act4.setEthDst(MacAddress.valueOf(0x3030)); + act4.setEthSrc(MacAddress.valueOf(0x1010)); + act4.setVlanId(VlanId.vlanId((short) 197)); + act4.group(new DefaultGroupId(0x00c50028)); // point to L2 interface + Integer groupId4 = L3UNICASTMASK | 2; // 0x20000002 + GroupBucket bucket4 = + DefaultGroupBucket.createIndirectGroupBucket(act4.build()); + final GroupKey groupkey4 = new DefaultGroupKey(appKryo.serialize(504)); + GroupDescription groupDescription4 = new DefaultGroupDescription(deviceId, + GroupDescription.Type.INDIRECT, + new GroupBuckets(Collections.singletonList(bucket4)), + groupkey4, + groupId4, + driverId); + groupService.addGroup(groupDescription4); + + while (groupService.getGroup(deviceId, groupkey4) == null) { + try { + Thread.sleep(500); + } catch (InterruptedException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + + // L3 ecmp group + TrafficTreatment.Builder act5 = DefaultTrafficTreatment.builder(); + act5.group(new DefaultGroupId(0x20000001)); + TrafficTreatment.Builder act6 = DefaultTrafficTreatment.builder(); + act6.group(new DefaultGroupId(0x20000002)); + GroupBucket buckete1 = + DefaultGroupBucket.createSelectGroupBucket(act5.build()); + GroupBucket buckete2 = + DefaultGroupBucket.createSelectGroupBucket(act6.build()); + List<GroupBucket> bktlist = new ArrayList<GroupBucket>(); + bktlist.add(buckete1); + bktlist.add(buckete2); + final GroupKey groupkey5 = new DefaultGroupKey(appKryo.serialize(505)); + Integer groupId5 = L3ECMPMASK | 5; // 0x70000005 + GroupDescription groupDescription5 = new DefaultGroupDescription(deviceId, + GroupDescription.Type.SELECT, + new GroupBuckets(bktlist), + groupkey5, + groupId5, + driverId); + groupService.addGroup(groupDescription5); + + + } + + @SuppressWarnings("deprecation") + protected void processMplsTable() { + FlowRuleOperations.Builder ops = FlowRuleOperations.builder(); + TrafficSelector.Builder selector = DefaultTrafficSelector.builder(); + selector.matchEthType(Ethernet.MPLS_UNICAST); + selector.matchMplsLabel(MplsLabel.mplsLabel(0xff)); //255 + selector.matchMplsBos(true); + TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder(); + treatment.decMplsTtl(); // nw_ttl does not work + treatment.copyTtlIn(); + treatment.popMpls(Ethernet.TYPE_IPV4); + treatment.deferred().group(new DefaultGroupId(0x20000001)); // point to L3 Unicast + //treatment.deferred().group(new DefaultGroupId(0x70000005)); // point to L3 ECMP + treatment.transition(ACL_TABLE); + FlowRule test = DefaultFlowRule.builder().forDevice(deviceId) + .withSelector(selector.build()).withTreatment(treatment.build()) + .withPriority(DEFAULT_PRIORITY).fromApp(driverId).makePermanent() + .forTable(24).build(); + ops = ops.add(test); + + flowRuleService.apply(ops.build(new FlowRuleOperationsContext() { + @Override + public void onSuccess(FlowRuleOperations ops) { + log.info("Initialized mpls table"); + } + + @Override + public void onError(FlowRuleOperations ops) { + log.info("Failed to initialize mpls table"); + } + })); + + } + + protected void processPortTable() { + FlowRuleOperations.Builder ops = FlowRuleOperations.builder(); + TrafficSelector.Builder selector = DefaultTrafficSelector.builder(); + selector.matchInPort(PortNumber.portNumber(0)); // should be maskable? + TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder(); + treatment.transition(VLAN_TABLE); + FlowRule tmisse = DefaultFlowRule.builder() + .forDevice(deviceId) + .withSelector(selector.build()) + .withTreatment(treatment.build()) + .withPriority(LOWEST_PRIORITY) + .fromApp(driverId) + .makePermanent() + .forTable(PORT_TABLE).build(); + ops = ops.add(tmisse); + + flowRuleService.apply(ops.build(new FlowRuleOperationsContext() { + @Override + public void onSuccess(FlowRuleOperations ops) { + log.info("Initialized port table"); + } + + @Override + public void onError(FlowRuleOperations ops) { + log.info("Failed to initialize port table"); + } + })); + + } + + private void processVlanTable() { + // Table miss entry is not required as ofdpa default is to drop + // In OF terms, the absence of a t.m.e. also implies drop + FlowRuleOperations.Builder ops = FlowRuleOperations.builder(); + TrafficSelector.Builder selector = DefaultTrafficSelector.builder(); + TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder(); + selector.matchInPort(PortNumber.portNumber(12)); + selector.matchVlanId(VlanId.vlanId((short) 100)); + treatment.transition(TMAC_TABLE); + FlowRule rule = DefaultFlowRule.builder() + .forDevice(deviceId) + .withSelector(selector.build()) + .withTreatment(treatment.build()) + .withPriority(DEFAULT_PRIORITY) + .fromApp(driverId) + .makePermanent() + .forTable(VLAN_TABLE).build(); + ops = ops.add(rule); + flowRuleService.apply(ops.build(new FlowRuleOperationsContext() { + @Override + public void onSuccess(FlowRuleOperations ops) { + log.info("Initialized vlan table"); + } + + @Override + public void onError(FlowRuleOperations ops) { + log.info("Failed to initialize vlan table"); + } + })); + } + + protected void processTmacTable() { + //table miss entry + FlowRuleOperations.Builder ops = FlowRuleOperations.builder(); + TrafficSelector.Builder selector = DefaultTrafficSelector.builder(); + TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder(); + selector.matchInPort(PortNumber.portNumber(12)); + selector.matchVlanId(VlanId.vlanId((short) 100)); + selector.matchEthType(Ethernet.TYPE_IPV4); + selector.matchEthDst(MacAddress.valueOf("00:00:00:00:00:02")); + treatment.transition(UNICAST_ROUTING_TABLE); + FlowRule rule = DefaultFlowRule.builder() + .forDevice(deviceId) + .withSelector(selector.build()) + .withTreatment(treatment.build()) + .withPriority(DEFAULT_PRIORITY) + .fromApp(driverId) + .makePermanent() + .forTable(TMAC_TABLE).build(); + ops = ops.add(rule); + + selector.matchEthType(Ethernet.MPLS_UNICAST); + treatment.transition(MPLS_TABLE_0); + FlowRule rulempls = DefaultFlowRule.builder() + .forDevice(deviceId) + .withSelector(selector.build()) + .withTreatment(treatment.build()) + .withPriority(DEFAULT_PRIORITY) + .fromApp(driverId) + .makePermanent() + .forTable(TMAC_TABLE).build(); + ops = ops.add(rulempls); + + flowRuleService.apply(ops.build(new FlowRuleOperationsContext() { + @Override + public void onSuccess(FlowRuleOperations ops) { + log.info("Initialized tmac table"); + } + + @Override + public void onError(FlowRuleOperations ops) { + log.info("Failed to initialize tmac table"); + } + })); + } + + protected void processIpTable() { + //table miss entry + FlowRuleOperations.Builder ops = FlowRuleOperations.builder(); + TrafficSelector.Builder selector = DefaultTrafficSelector.builder(); + TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder(); + selector.matchEthType(Ethernet.TYPE_IPV4); + selector.matchIPDst(IpPrefix.valueOf("2.0.0.0/16")); + treatment.deferred().group(new DefaultGroupId(0x20000001)); + treatment.transition(ACL_TABLE); + FlowRule rule = DefaultFlowRule.builder() + .forDevice(deviceId) + .withSelector(selector.build()) + .withTreatment(treatment.build()) + .withPriority(30000) + .fromApp(driverId) + .makePermanent() + .forTable(UNICAST_ROUTING_TABLE).build(); + ops = ops.add(rule); + flowRuleService.apply(ops.build(new FlowRuleOperationsContext() { + @Override + public void onSuccess(FlowRuleOperations ops) { + log.info("Initialized IP table"); + } + + @Override + public void onError(FlowRuleOperations ops) { + log.info("Failed to initialize unicast IP table"); + } + })); + } + + protected void processAclTable() { + //table miss entry + FlowRuleOperations.Builder ops = FlowRuleOperations.builder(); + TrafficSelector.Builder selector = DefaultTrafficSelector.builder(); + TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder(); + selector.matchEthDst(MacAddress.valueOf("00:00:00:00:00:02")); + treatment.deferred().group(new DefaultGroupId(0x20000001)); + FlowRule rule = DefaultFlowRule.builder() + .forDevice(deviceId) + .withSelector(selector.build()) + .withTreatment(treatment.build()) + .withPriority(60000) + .fromApp(driverId) + .makePermanent() + .forTable(ACL_TABLE).build(); + ops = ops.add(rule); + flowRuleService.apply(ops.build(new FlowRuleOperationsContext() { + @Override + public void onSuccess(FlowRuleOperations ops) { + log.info("Initialized Acl table"); + } + + @Override + public void onError(FlowRuleOperations ops) { + log.info("Failed to initialize Acl table"); + } + })); + } + + private void sendPackets() { + Ethernet eth = new Ethernet(); + eth.setDestinationMACAddress("00:00:00:00:00:02"); + eth.setSourceMACAddress("00:00:00:11:22:33"); + eth.setVlanID((short) 100); + eth.setEtherType(Ethernet.MPLS_UNICAST); + MPLS mplsPkt = new MPLS(); + mplsPkt.setLabel(255); + mplsPkt.setTtl((byte) 5); + + IPv4 ipv4 = new IPv4(); + + ipv4.setDestinationAddress("4.0.5.6"); + ipv4.setSourceAddress("1.0.2.3"); + ipv4.setTtl((byte) 64); + ipv4.setChecksum((short) 0); + + UDP udp = new UDP(); + udp.setDestinationPort(666); + udp.setSourcePort(333); + udp.setPayload(new Data(new byte[]{(byte) 1, (byte) 2})); + udp.setChecksum((short) 0); + + ipv4.setPayload(udp); + mplsPkt.setPayload(ipv4); + eth.setPayload(mplsPkt); + + TrafficTreatment treatment = DefaultTrafficTreatment.builder() + .setOutput(PortNumber.portNumber(24)) + .build(); + OutboundPacket packet = new DefaultOutboundPacket(deviceId, + treatment, + ByteBuffer.wrap(eth.serialize())); + + + Ethernet eth2 = new Ethernet(); + eth2.setDestinationMACAddress("00:00:00:00:00:02"); + eth2.setSourceMACAddress("00:00:00:11:22:33"); + eth2.setVlanID((short) 100); + eth2.setEtherType(Ethernet.TYPE_IPV4); + + IPv4 ipv42 = new IPv4(); + ipv42.setDestinationAddress("2.0.0.2"); + ipv42.setSourceAddress("1.0.9.9"); + ipv42.setTtl((byte) 64); + ipv42.setChecksum((short) 0); + + UDP udp2 = new UDP(); + udp2.setDestinationPort(999); + udp2.setSourcePort(333); + udp2.setPayload(new Data(new byte[]{(byte) 1, (byte) 2})); + udp2.setChecksum((short) 0); + + ipv42.setPayload(udp2); + eth2.setPayload(ipv42); + + TrafficTreatment treatment2 = DefaultTrafficTreatment.builder() + .setOutput(PortNumber.portNumber(26)) + .build(); + OutboundPacket packet2 = new DefaultOutboundPacket(deviceId, + treatment2, + ByteBuffer.wrap(eth2.serialize())); + + + log.info("Emitting packets now"); + packetService.emit(packet); + packetService.emit(packet); + packetService.emit(packet2); + packetService.emit(packet); + packetService.emit(packet); + log.info("Done emitting packets"); + } + + private class InternalPacketProcessor implements PacketProcessor { + + @Override + public void process(PacketContext context) { + + + } + } + } diff --git a/framework/src/onos/drivers/src/main/java/org/onosproject/driver/pipeline/SpringOpenTTP.java b/framework/src/onos/drivers/src/main/java/org/onosproject/driver/pipeline/SpringOpenTTP.java index c02ba3ca..31297ff4 100644 --- a/framework/src/onos/drivers/src/main/java/org/onosproject/driver/pipeline/SpringOpenTTP.java +++ b/framework/src/onos/drivers/src/main/java/org/onosproject/driver/pipeline/SpringOpenTTP.java @@ -53,6 +53,7 @@ import org.onosproject.net.flow.criteria.MplsCriterion; import org.onosproject.net.flow.criteria.PortCriterion; import org.onosproject.net.flow.criteria.VlanIdCriterion; import org.onosproject.net.flow.instructions.Instruction; +import org.onosproject.net.flow.instructions.Instructions.OutputInstruction; import org.onosproject.net.flowobjective.FilteringObjective; import org.onosproject.net.flowobjective.FlowObjectiveStore; import org.onosproject.net.flowobjective.ForwardingObjective; @@ -246,6 +247,7 @@ public class SpringOpenTTP extends AbstractHandlerBehaviour private void addGroup(NextObjective nextObjective) { log.debug("addGroup with type{} for nextObjective id {}", nextObjective.type(), nextObjective.id()); + List<GroupBucket> buckets; switch (nextObjective.type()) { case SIMPLE: log.debug("processing SIMPLE next objective"); @@ -273,7 +275,7 @@ public class SpringOpenTTP extends AbstractHandlerBehaviour break; case HASHED: log.debug("processing HASHED next objective"); - List<GroupBucket> buckets = nextObjective + buckets = nextObjective .next() .stream() .map((treatment) -> DefaultGroupBucket @@ -297,8 +299,32 @@ public class SpringOpenTTP extends AbstractHandlerBehaviour } break; case BROADCAST: + log.debug("processing BROADCAST next objective"); + buckets = nextObjective + .next() + .stream() + .map((treatment) -> DefaultGroupBucket + .createAllGroupBucket(treatment)) + .collect(Collectors.toList()); + if (!buckets.isEmpty()) { + final GroupKey key = new DefaultGroupKey( + appKryo.serialize(nextObjective + .id())); + GroupDescription groupDescription = new DefaultGroupDescription( + deviceId, + GroupDescription.Type.ALL, + new GroupBuckets(buckets), + key, + null, + nextObjective.appId()); + log.debug("Creating BROADCAST group for next objective id {}", + nextObjective.id()); + groupService.addGroup(groupDescription); + pendingGroups.put(key, nextObjective); + } + break; case FAILOVER: - log.debug("BROADCAST and FAILOVER next objectives not supported"); + log.debug("FAILOVER next objectives not supported"); fail(nextObjective, ObjectiveError.UNSUPPORTED); log.warn("Unsupported next objective type {}", nextObjective.type()); break; @@ -326,6 +352,8 @@ public class SpringOpenTTP extends AbstractHandlerBehaviour bucket = DefaultGroupBucket.createIndirectGroupBucket(treatment); } else if (group.type() == GroupDescription.Type.SELECT) { bucket = DefaultGroupBucket.createSelectGroupBucket(treatment); + } else if (group.type() == GroupDescription.Type.ALL) { + bucket = DefaultGroupBucket.createAllGroupBucket(treatment); } else { log.warn("Unsupported Group type {}", group.type()); return; @@ -356,6 +384,8 @@ public class SpringOpenTTP extends AbstractHandlerBehaviour bucket = DefaultGroupBucket.createIndirectGroupBucket(treatment); } else if (group.type() == GroupDescription.Type.SELECT) { bucket = DefaultGroupBucket.createSelectGroupBucket(treatment); + } else if (group.type() == GroupDescription.Type.ALL) { + bucket = DefaultGroupBucket.createAllGroupBucket(treatment); } else { log.warn("Unsupported Group type {}", group.type()); return; @@ -383,7 +413,7 @@ public class SpringOpenTTP extends AbstractHandlerBehaviour private Collection<FlowRule> processVersatile(ForwardingObjective fwd) { log.debug("Processing versatile forwarding objective"); TrafficSelector selector = fwd.selector(); - + TrafficTreatment treatment = null; EthTypeCriterion ethType = (EthTypeCriterion) selector.getCriterion(Criterion.Type.ETH_TYPE); if (ethType == null) { @@ -410,15 +440,26 @@ public class SpringOpenTTP extends AbstractHandlerBehaviour return Collections.emptySet(); } treatmentBuilder.deferred().group(group.id()); + treatment = treatmentBuilder.build(); log.debug("Adding OUTGROUP action"); } + } else if (fwd.treatment() != null) { + if (fwd.treatment().allInstructions().size() == 1 && + fwd.treatment().allInstructions().get(0).type() == Instruction.Type.OUTPUT) { + OutputInstruction o = (OutputInstruction) fwd.treatment().allInstructions().get(0); + if (o.port() == PortNumber.CONTROLLER) { + log.warn("Punts to the controller are handled by misses in" + + " the TMAC, IP and MPLS tables."); + return Collections.emptySet(); + } + } + treatment = fwd.treatment(); } else { - log.warn("VERSATILE forwarding objective need next objective ID."); + log.warn("VERSATILE forwarding objective needs next objective ID " + + "or treatment."); return Collections.emptySet(); } - TrafficTreatment treatment = treatmentBuilder.build(); - FlowRule.Builder ruleBuilder = DefaultFlowRule.builder() .fromApp(fwd.appId()).withPriority(fwd.priority()) .forDevice(deviceId).withSelector(fwd.selector()) @@ -527,7 +568,7 @@ public class SpringOpenTTP extends AbstractHandlerBehaviour protected List<FlowRule> processEthDstFilter(Criterion c, FilteringObjective filt, ApplicationId applicationId) { - List<FlowRule> rules = new ArrayList<FlowRule>(); + List<FlowRule> rules = new ArrayList<>(); EthCriterion e = (EthCriterion) c; TrafficSelector.Builder selectorIp = DefaultTrafficSelector .builder(); @@ -565,7 +606,7 @@ public class SpringOpenTTP extends AbstractHandlerBehaviour protected List<FlowRule> processVlanIdFilter(Criterion c, FilteringObjective filt, ApplicationId applicationId) { - List<FlowRule> rules = new ArrayList<FlowRule>(); + List<FlowRule> rules = new ArrayList<>(); VlanIdCriterion v = (VlanIdCriterion) c; log.debug("adding rule for VLAN: {}", v.vlanId()); TrafficSelector.Builder selector = DefaultTrafficSelector @@ -616,21 +657,8 @@ public class SpringOpenTTP extends AbstractHandlerBehaviour ops = install ? ops.add(rule) : ops.remove(rule); } } else if (c.type() == Criterion.Type.IPV4_DST) { - IPCriterion ip = (IPCriterion) c; - log.debug("adding rule for IP: {}", ip.ip()); - TrafficSelector.Builder selector = DefaultTrafficSelector - .builder(); - TrafficTreatment.Builder treatment = DefaultTrafficTreatment - .builder(); - selector.matchEthType(Ethernet.TYPE_IPV4); - selector.matchIPDst(ip.ip()); - treatment.transition(aclTableId); - FlowRule rule = DefaultFlowRule.builder().forDevice(deviceId) - .withSelector(selector.build()) - .withTreatment(treatment.build()) - .withPriority(filt.priority()).fromApp(applicationId) - .makePermanent().forTable(ipv4UnicastTableId).build(); - ops = install ? ops.add(rule) : ops.remove(rule); + log.debug("driver does not process IP filtering rules as it " + + "sends all misses in the IP table to the controller"); } else { log.warn("Driver does not currently process filtering condition" + " of type: {}", c.type()); @@ -762,6 +790,7 @@ public class SpringOpenTTP extends AbstractHandlerBehaviour this.key = key; } + @SuppressWarnings("unused") public GroupKey key() { return key; } diff --git a/framework/src/onos/drivers/src/main/resources/onos-drivers.xml b/framework/src/onos/drivers/src/main/resources/onos-drivers.xml index 5059d4bf..af498832 100644 --- a/framework/src/onos/drivers/src/main/resources/onos-drivers.xml +++ b/framework/src/onos/drivers/src/main/resources/onos-drivers.xml @@ -32,12 +32,19 @@ impl="org.onosproject.driver.handshaker.NiciraSwitchHandshaker"/> <behaviour api="org.onosproject.net.behaviour.ControllerConfig" impl="org.onosproject.driver.ovsdb.OvsdbControllerConfig"/> + <behaviour api="org.onosproject.openflow.controller.ExtensionInterpreter" + impl="org.onosproject.driver.extensions.NiciraExtensionInterpreter" /> + <behaviour api="org.onosproject.net.behaviour.ExtensionResolver" + impl="org.onosproject.driver.extensions.NiciraExtensionInterpreter" /> </driver> <driver name="ovs-corsa" extends="ovs" manufacturer="Corsa" hwVersion="emulation" swVersion="0.0.0"> <behaviour api="org.onosproject.net.behaviour.Pipeliner" impl="org.onosproject.driver.pipeline.OVSCorsaPipeline"/> </driver> + <!-- Emulation of the spring-open pipeline using a CPqD OF 1.3 software switch. + ~ This driver is the default driver assigned to the CPqD switch. + --> <driver name="spring-open-cpqd" extends="default" manufacturer="Stanford University, Ericsson Research and CPqD Research" hwVersion="OpenFlow 1.3 Reference Userspace Switch" swVersion=".*"> @@ -66,7 +73,7 @@ <driver name="ofdpa" extends="default" manufacturer="Broadcom Corp." hwVersion="OF-DPA.*" swVersion="OF-DPA.*"> <behaviour api="org.onosproject.net.behaviour.Pipeliner" - impl="org.onosproject.driver.pipeline.OFDPA1Pipeline"/> + impl="org.onosproject.driver.pipeline.OFDPA2Pipeline"/> </driver> <driver name="pmc-olt" extends="default" manufacturer="Big Switch Networks" hwVersion="ivs 0.5" swVersion="ivs 0.5"> @@ -109,7 +116,7 @@ manufacturer="ONF" hwVersion="OF1.3 Software Switch from CPqD" swVersion="for Group Chaining"> <behaviour api="org.onosproject.net.behaviour.Pipeliner" - impl="org.onosproject.driver.pipeline.CpqdOFDPA1Pipeline"/> + impl="org.onosproject.driver.pipeline.CpqdOFDPA2Pipeline"/> </driver> <driver name="calient" extends="default" manufacturer="calient inc" hwVersion="calient hardware" diff --git a/framework/src/onos/features/features.xml b/framework/src/onos/features/features.xml index dec02998..1aae0f33 100644 --- a/framework/src/onos/features/features.xml +++ b/framework/src/onos/features/features.xml @@ -96,6 +96,7 @@ <bundle>mvn:org.onosproject/onos-core-net/@ONOS-VERSION</bundle> <bundle>mvn:org.onosproject/onos-core-common/@ONOS-VERSION</bundle> <bundle>mvn:org.onosproject/onos-core-dist/@ONOS-VERSION</bundle> + <bundle>mvn:org.onosproject/onos-core-persistence/@ONOS-VERSION</bundle> <bundle>mvn:org.onosproject/onos-core-serializers/@ONOS-VERSION</bundle> <bundle>mvn:org.onosproject/onlab-netty/@ONOS-VERSION</bundle> </feature> diff --git a/framework/src/onos/incubator/api/src/main/java/org/onosproject/incubator/net/intf/package-info.java b/framework/src/onos/incubator/api/src/main/java/org/onosproject/incubator/net/intf/package-info.java new file mode 100644 index 00000000..6cea24d1 --- /dev/null +++ b/framework/src/onos/incubator/api/src/main/java/org/onosproject/incubator/net/intf/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. + */ + +/** + * Interface Service. + */ +package org.onosproject.incubator.net.intf; diff --git a/framework/src/onos/netconf/api/src/main/java/org/onosproject/netconf/package-info.java b/framework/src/onos/netconf/api/src/main/java/org/onosproject/netconf/package-info.java new file mode 100644 index 00000000..5562bd33 --- /dev/null +++ b/framework/src/onos/netconf/api/src/main/java/org/onosproject/netconf/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. + */ + +/** + * Created by ray on 10/30/15. + */ +package org.onosproject.netconf; diff --git a/framework/src/onos/netconf/ctl/src/main/java/org/onosproject/netconf/ctl/package-info.java b/framework/src/onos/netconf/ctl/src/main/java/org/onosproject/netconf/ctl/package-info.java new file mode 100644 index 00000000..84992bf2 --- /dev/null +++ b/framework/src/onos/netconf/ctl/src/main/java/org/onosproject/netconf/ctl/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. + */ + +/** + * Created by ray on 10/30/15. + */ +package org.onosproject.netconf.ctl; diff --git a/framework/src/onos/netconf/rfc/src/main/java/org/onosproject/netconf/rfc/package-info.java b/framework/src/onos/netconf/rfc/src/main/java/org/onosproject/netconf/rfc/package-info.java new file mode 100644 index 00000000..616a7ce5 --- /dev/null +++ b/framework/src/onos/netconf/rfc/src/main/java/org/onosproject/netconf/rfc/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. + */ + +/** + * Created by ray on 10/30/15. + */ +package org.onosproject.netconf.rfc; diff --git a/framework/src/onos/openflow/api/src/main/java/org/onosproject/openflow/controller/ExtensionInterpreter.java b/framework/src/onos/openflow/api/src/main/java/org/onosproject/openflow/controller/ExtensionInterpreter.java new file mode 100644 index 00000000..44b121ac --- /dev/null +++ b/framework/src/onos/openflow/api/src/main/java/org/onosproject/openflow/controller/ExtensionInterpreter.java @@ -0,0 +1,58 @@ +/* + * 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.openflow.controller; + +import com.google.common.annotations.Beta; +import org.onosproject.net.driver.HandlerBehaviour; +import org.onosproject.net.flow.instructions.ExtensionInstruction; +import org.onosproject.net.flow.instructions.ExtensionType; +import org.projectfloodlight.openflow.protocol.OFFactory; +import org.projectfloodlight.openflow.protocol.action.OFAction; + +/** + * Interprets extension instructions and converts them to/from OpenFlow objects. + */ +@Beta +public interface ExtensionInterpreter extends HandlerBehaviour { + + /** + * Returns true if the given extension instruction is supported by this + * driver. + * + * @param extensionType extension instruction type + * @return true if the instruction is supported, otherwise false + */ + boolean supported(ExtensionType extensionType); + + /** + * Maps an extension instruction to an OpenFlow action. + * + * @param factory OpenFlow factory + * @param extensionInstruction extension instruction + * @return OpenFlow action + */ + OFAction mapInstruction(OFFactory factory, ExtensionInstruction extensionInstruction); + + /** + * Maps an OpenFlow action to an extension instruction. + * + * @param action OpenFlow action + * @return extension instruction + */ + ExtensionInstruction mapAction(OFAction action); + +} diff --git a/framework/src/onos/ovsdb/api/src/main/java/org/onosproject/ovsdb/controller/EventSubject.java b/framework/src/onos/ovsdb/api/src/main/java/org/onosproject/ovsdb/controller/EventSubject.java index 6a067244..d8aaef65 100644 --- a/framework/src/onos/ovsdb/api/src/main/java/org/onosproject/ovsdb/controller/EventSubject.java +++ b/framework/src/onos/ovsdb/api/src/main/java/org/onosproject/ovsdb/controller/EventSubject.java @@ -16,8 +16,7 @@ package org.onosproject.ovsdb.controller; /** - * Represents for a entity that carry important information for listener. + * Representation for an entity that carries important information for a listener. */ public interface EventSubject { - } diff --git a/framework/src/onos/ovsdb/api/src/main/java/org/onosproject/ovsdb/controller/OvsdbBridge.java b/framework/src/onos/ovsdb/api/src/main/java/org/onosproject/ovsdb/controller/OvsdbBridge.java index 1ee0a367..18c59e14 100644 --- a/framework/src/onos/ovsdb/api/src/main/java/org/onosproject/ovsdb/controller/OvsdbBridge.java +++ b/framework/src/onos/ovsdb/api/src/main/java/org/onosproject/ovsdb/controller/OvsdbBridge.java @@ -21,7 +21,8 @@ import static com.google.common.base.Preconditions.checkNotNull; import java.util.Objects; /** - * The class representing a ovsdb bridge. This class is immutable. + * The class representing an ovsdb bridge. + * This class is immutable. */ public final class OvsdbBridge { @@ -29,7 +30,7 @@ public final class OvsdbBridge { private final OvsdbDatapathId datapathId; /** - * Constructor from a OvsdbBridgeName bridgeName and a OvsdbDatapathId + * Constructor from an OvsdbBridgeName bridgeName and an OvsdbDatapathId * datapathId. * * @param bridgeName the bridgeName to use @@ -43,16 +44,16 @@ public final class OvsdbBridge { } /** - * Gets the bridge name of the bridge. + * Gets the bridge name of bridge. * - * @return the bridge name of the bridge + * @return the bridge name of bridge */ public OvsdbBridgeName bridgeName() { return bridgeName; } /** - * Gets the datapathId of the bridge. + * Gets the datapathId of bridge. * * @return datapathId the datapathId to use */ diff --git a/framework/src/onos/ovsdb/api/src/main/java/org/onosproject/ovsdb/controller/OvsdbBridgeName.java b/framework/src/onos/ovsdb/api/src/main/java/org/onosproject/ovsdb/controller/OvsdbBridgeName.java index daedff5f..899799fa 100644 --- a/framework/src/onos/ovsdb/api/src/main/java/org/onosproject/ovsdb/controller/OvsdbBridgeName.java +++ b/framework/src/onos/ovsdb/api/src/main/java/org/onosproject/ovsdb/controller/OvsdbBridgeName.java @@ -21,14 +21,15 @@ import static com.google.common.base.Preconditions.checkNotNull; import java.util.Objects; /** - * The class representing a bridge name. This class is immutable. + * The class representing a bridge name. + * This class is immutable. */ public final class OvsdbBridgeName { private final String value; /** - * Constructor from a String bridge name. + * Constructor from a String. * * @param value the bridge name to use */ @@ -38,7 +39,7 @@ public final class OvsdbBridgeName { } /** - * Gets the value of the bridge name. + * Gets the value of bridge name. * * @return the value of the bridge name */ diff --git a/framework/src/onos/ovsdb/api/src/main/java/org/onosproject/ovsdb/controller/OvsdbClientService.java b/framework/src/onos/ovsdb/api/src/main/java/org/onosproject/ovsdb/controller/OvsdbClientService.java index e619f8e0..edd25ac6 100644 --- a/framework/src/onos/ovsdb/api/src/main/java/org/onosproject/ovsdb/controller/OvsdbClientService.java +++ b/framework/src/onos/ovsdb/api/src/main/java/org/onosproject/ovsdb/controller/OvsdbClientService.java @@ -43,7 +43,7 @@ public interface OvsdbClientService extends OvsdbRPC { OvsdbNodeId nodeId(); /** - * Creates the configuration for the tunnel. + * Creates the configuration for tunnel. * * @param srcIp source IP address * @param dstIp destination IP address @@ -62,7 +62,7 @@ public interface OvsdbClientService extends OvsdbRPC { boolean createTunnel(String bridgeName, String portName, String tunnelType, Map<String, String> options); /** - * Drops the configuration for the tunnel. + * Drops the configuration for tunnel. * * @param srcIp source IP address * @param dstIp destination IP address @@ -70,7 +70,7 @@ public interface OvsdbClientService extends OvsdbRPC { void dropTunnel(IpAddress srcIp, IpAddress dstIp); /** - * Gets tunnels of the node. + * Gets tunnels of node. * * @return set of tunnels; empty if no tunnel is find */ @@ -102,14 +102,14 @@ public interface OvsdbClientService extends OvsdbRPC { void dropBridge(String bridgeName); /** - * Gets bridges of the node. + * Gets bridges of node. * * @return set of bridges; empty if no bridge is find */ Set<OvsdbBridge> getBridges(); /** - * Gets controllers of the node. + * Gets controllers of node. * * @param openflowDeviceId target device id * @return set of controllers; empty if no controller is find @@ -155,7 +155,7 @@ public interface OvsdbClientService extends OvsdbRPC { void dropPort(String bridgeName, String portName); /** - * Gets ports of the bridge. + * Gets ports of bridge. * * @return set of ports; empty if no ports is find */ @@ -247,7 +247,7 @@ public interface OvsdbClientService extends OvsdbRPC { DatabaseSchema getDatabaseSchema(String dbName); /** - * Gets the ovsdb row from the local ovsdb store. + * Gets the ovsdb row from local ovsdb store. * * @param dbName database name * @param tableName table name @@ -257,7 +257,7 @@ public interface OvsdbClientService extends OvsdbRPC { Row getRow(String dbName, String tableName, String uuid); /** - * Removes the ovsdb row from the local ovsdb store. + * Removes the ovsdb row from local ovsdb store. * * @param dbName database name * @param tableName table name diff --git a/framework/src/onos/ovsdb/api/src/main/java/org/onosproject/ovsdb/controller/OvsdbController.java b/framework/src/onos/ovsdb/api/src/main/java/org/onosproject/ovsdb/controller/OvsdbController.java index 24bfeae9..f22a5787 100644 --- a/framework/src/onos/ovsdb/api/src/main/java/org/onosproject/ovsdb/controller/OvsdbController.java +++ b/framework/src/onos/ovsdb/api/src/main/java/org/onosproject/ovsdb/controller/OvsdbController.java @@ -21,7 +21,7 @@ import org.onlab.packet.TpPort; import java.util.List; /** - * Abstraction of an ovsdb controller. Serves as a one stop shop for obtaining + * Abstraction of an ovsdb controller. Serves as an one stop shop for obtaining * OvsdbNode and (un)register listeners on ovsdb events and ovsdb node events. */ public interface OvsdbController { @@ -62,7 +62,7 @@ public interface OvsdbController { List<OvsdbNodeId> getNodeIds(); /** - * Gets a ovsdb client by node identifier. + * Gets an ovsdb client by node identifier. * * @param nodeId node identifier * @return OvsdbClient ovsdb node information diff --git a/framework/src/onos/ovsdb/api/src/main/java/org/onosproject/ovsdb/controller/OvsdbDatapathId.java b/framework/src/onos/ovsdb/api/src/main/java/org/onosproject/ovsdb/controller/OvsdbDatapathId.java index 1a2d8366..8ccf45f2 100644 --- a/framework/src/onos/ovsdb/api/src/main/java/org/onosproject/ovsdb/controller/OvsdbDatapathId.java +++ b/framework/src/onos/ovsdb/api/src/main/java/org/onosproject/ovsdb/controller/OvsdbDatapathId.java @@ -20,13 +20,14 @@ import static com.google.common.base.Preconditions.checkNotNull; import java.util.Objects; /** - * The class representing a datapathid. This class is immutable. + * The class representing a datapathid. + * This class is immutable. */ public final class OvsdbDatapathId { private final String value; /** - * Constructor from a String datapathid. + * Constructor from a String. * * @param value the datapathid to use */ @@ -36,9 +37,9 @@ public final class OvsdbDatapathId { } /** - * Gets the value of the datapathid. + * Gets the value of datapathid. * - * @return the value of the datapathid + * @return the value of datapathid */ public String value() { return value; diff --git a/framework/src/onos/ovsdb/api/src/main/java/org/onosproject/ovsdb/controller/OvsdbEventSubject.java b/framework/src/onos/ovsdb/api/src/main/java/org/onosproject/ovsdb/controller/OvsdbEventSubject.java index 263027f2..226a26e6 100644 --- a/framework/src/onos/ovsdb/api/src/main/java/org/onosproject/ovsdb/controller/OvsdbEventSubject.java +++ b/framework/src/onos/ovsdb/api/src/main/java/org/onosproject/ovsdb/controller/OvsdbEventSubject.java @@ -21,7 +21,7 @@ import org.onlab.packet.IpAddress; import org.onlab.packet.MacAddress; /** - * Represents for a entity that carry important information for listener. + * Represents for an entity that carry important information for listener. */ public interface OvsdbEventSubject extends EventSubject { /** diff --git a/framework/src/onos/ovsdb/api/src/main/java/org/onosproject/ovsdb/controller/OvsdbIfaceId.java b/framework/src/onos/ovsdb/api/src/main/java/org/onosproject/ovsdb/controller/OvsdbIfaceId.java index b0535d21..10ba80bc 100644 --- a/framework/src/onos/ovsdb/api/src/main/java/org/onosproject/ovsdb/controller/OvsdbIfaceId.java +++ b/framework/src/onos/ovsdb/api/src/main/java/org/onosproject/ovsdb/controller/OvsdbIfaceId.java @@ -20,13 +20,14 @@ import static com.google.common.base.Preconditions.checkNotNull; import java.util.Objects; /** - * The class representing a ifaceid. This class is immutable. + * The class representing an ifaceid. + * This class is immutable. */ public class OvsdbIfaceId { private final String value; /** - * Constructor from a String ifaceid. + * Constructor from a String. * * @param value the ifaceid to use */ @@ -36,9 +37,9 @@ public class OvsdbIfaceId { } /** - * Gets the value of the ifaceid. + * Gets the value of ifaceid. * - * @return the value of the ifaceid + * @return the value of ifaceid */ public String value() { return value; diff --git a/framework/src/onos/ovsdb/api/src/main/java/org/onosproject/ovsdb/controller/OvsdbNodeId.java b/framework/src/onos/ovsdb/api/src/main/java/org/onosproject/ovsdb/controller/OvsdbNodeId.java index 2c1a440b..f3bba4b8 100644 --- a/framework/src/onos/ovsdb/api/src/main/java/org/onosproject/ovsdb/controller/OvsdbNodeId.java +++ b/framework/src/onos/ovsdb/api/src/main/java/org/onosproject/ovsdb/controller/OvsdbNodeId.java @@ -39,7 +39,7 @@ public final class OvsdbNodeId { public OvsdbNodeId(IpAddress ipAddress, long port) { checkNotNull(ipAddress, "ipAddress is not null"); this.ipAddress = ipAddress.toString(); - this.nodeId = ipAddress + ":" + port; + this.nodeId = ipAddress.toString(); } @Override diff --git a/framework/src/onos/ovsdb/api/src/main/java/org/onosproject/ovsdb/controller/OvsdbPort.java b/framework/src/onos/ovsdb/api/src/main/java/org/onosproject/ovsdb/controller/OvsdbPort.java index 3c04f6a5..deea42d7 100644 --- a/framework/src/onos/ovsdb/api/src/main/java/org/onosproject/ovsdb/controller/OvsdbPort.java +++ b/framework/src/onos/ovsdb/api/src/main/java/org/onosproject/ovsdb/controller/OvsdbPort.java @@ -29,7 +29,7 @@ public final class OvsdbPort { private final OvsdbPortName portName; /** - * Constructor from a OvsdbPortNumber portNumber, OvsdbPortName portName. + * Constructor from OvsdbPortNumber portNumber, OvsdbPortName portName. * * @param portNumber the portNumber to use * @param portName the portName to use @@ -42,18 +42,18 @@ public final class OvsdbPort { } /** - * Gets the port number of the port. + * Gets the port number of port. * - * @return the port number of the port + * @return the port number of port */ public OvsdbPortNumber portNumber() { return portNumber; } /** - * Gets the port name of the port. + * Gets the port name of port. * - * @return the port name of the port + * @return the port name of port */ public OvsdbPortName portName() { return portName; diff --git a/framework/src/onos/ovsdb/api/src/main/java/org/onosproject/ovsdb/controller/OvsdbPortName.java b/framework/src/onos/ovsdb/api/src/main/java/org/onosproject/ovsdb/controller/OvsdbPortName.java index aa0f55b0..d9c7c2da 100644 --- a/framework/src/onos/ovsdb/api/src/main/java/org/onosproject/ovsdb/controller/OvsdbPortName.java +++ b/framework/src/onos/ovsdb/api/src/main/java/org/onosproject/ovsdb/controller/OvsdbPortName.java @@ -21,14 +21,15 @@ import static com.google.common.base.Preconditions.checkNotNull; import java.util.Objects; /** - * The class representing a port number. This class is immutable. + * The class representing a port number. + * This class is immutable. */ public final class OvsdbPortName { private final String value; /** - * Constructor from a String port name. + * Constructor from a String. * * @param value the port name to use */ @@ -38,9 +39,9 @@ public final class OvsdbPortName { } /** - * Gets the value of the port name. + * Gets the value of port name. * - * @return the value of the port name + * @return the value of port name */ public String value() { return value; diff --git a/framework/src/onos/ovsdb/api/src/main/java/org/onosproject/ovsdb/controller/OvsdbPortNumber.java b/framework/src/onos/ovsdb/api/src/main/java/org/onosproject/ovsdb/controller/OvsdbPortNumber.java index 9c57b5df..bd094d04 100644 --- a/framework/src/onos/ovsdb/api/src/main/java/org/onosproject/ovsdb/controller/OvsdbPortNumber.java +++ b/framework/src/onos/ovsdb/api/src/main/java/org/onosproject/ovsdb/controller/OvsdbPortNumber.java @@ -20,14 +20,15 @@ import static com.google.common.base.MoreObjects.toStringHelper; import java.util.Objects; /** - * The class representing a port number. This class is immutable. + * The class representing a port number. + * This class is immutable. */ public final class OvsdbPortNumber { private final long value; /** - * Constructor from a long port number. + * Constructor from a long value. * * @param value the port number to use */ @@ -36,9 +37,9 @@ public final class OvsdbPortNumber { } /** - * Gets the value of the port number. + * Gets the value of port number. * - * @return the value of the port number + * @return the value of port number */ public long value() { return value; diff --git a/framework/src/onos/ovsdb/api/src/main/java/org/onosproject/ovsdb/controller/OvsdbTableStore.java b/framework/src/onos/ovsdb/api/src/main/java/org/onosproject/ovsdb/controller/OvsdbTableStore.java index 1d9146eb..72b64f32 100644 --- a/framework/src/onos/ovsdb/api/src/main/java/org/onosproject/ovsdb/controller/OvsdbTableStore.java +++ b/framework/src/onos/ovsdb/api/src/main/java/org/onosproject/ovsdb/controller/OvsdbTableStore.java @@ -29,18 +29,18 @@ public class OvsdbTableStore { /** * Gets the ovsdbRowStore. * - * @param tableName a ovsdb table name - * @return OvsdbRowStore the data of the table + * @param tableName an ovsdb table name + * @return OvsdbRowStore the data of table */ public OvsdbRowStore getRows(String tableName) { return tableStore.get(tableName); } /** - * Create or update a value to tableStore. + * Creates or updates a value to tableStore. * - * @param tableName key of the tableName - * @param rowStore a row of the table + * @param tableName key of tableName + * @param rowStore a row of table */ public void createOrUpdateTable(String tableName, OvsdbRowStore rowStore) { tableStore.put(tableName, rowStore); @@ -49,14 +49,14 @@ public class OvsdbTableStore { /** * Drops a value to table data. * - * @param tableName key of the tableName + * @param tableName key of tableName */ public void dropTable(String tableName) { tableStore.remove(tableName); } /** - * Gets the tableStore. + * Gets tableStore. * * @return tableStore */ diff --git a/framework/src/onos/ovsdb/api/src/main/java/org/onosproject/ovsdb/controller/OvsdbTunnel.java b/framework/src/onos/ovsdb/api/src/main/java/org/onosproject/ovsdb/controller/OvsdbTunnel.java index e1c5c7fd..8c857da4 100644 --- a/framework/src/onos/ovsdb/api/src/main/java/org/onosproject/ovsdb/controller/OvsdbTunnel.java +++ b/framework/src/onos/ovsdb/api/src/main/java/org/onosproject/ovsdb/controller/OvsdbTunnel.java @@ -23,7 +23,8 @@ import java.util.Objects; import org.onlab.packet.IpAddress; /** - * The class representing a ovsdb tunnel. This class is immutable. + * The class representing an ovsdb tunnel. + * This class is immutable. */ public final class OvsdbTunnel { @@ -38,7 +39,7 @@ public final class OvsdbTunnel { private final OvsdbTunnelName tunnelName; /** - * Constructor from a IpAddress localIp, IpAddress remoteIp Type tunnelType, + * Constructor from an IpAddress localIp, IpAddress remoteIp Type tunnelType, * OvsdbTunnelName tunnelName. * * @param localIp the localIp to use @@ -58,36 +59,36 @@ public final class OvsdbTunnel { } /** - * Gets the local IP of the tunnel. + * Gets the local IP of tunnel. * - * @return the local IP of the tunnel + * @return the local IP of tunnel */ public IpAddress localIp() { return localIp; } /** - * Gets the remote IP of the tunnel. + * Gets the remote IP of tunnel. * - * @return the remote IP of the tunnel + * @return the remote IP of tunnel */ public IpAddress remoteIp() { return remoteIp; } /** - * Gets the tunnel type of the tunnel. + * Gets the tunnel type of tunnel. * - * @return the tunnel type of the tunnel + * @return the tunnel type of tunnel */ public Type tunnelType() { return tunnelType; } /** - * Gets the tunnel name of the tunnel. + * Gets the tunnel name of tunnel. * - * @return the tunnel name of the tunnel + * @return the tunnel name of tunnel */ public OvsdbTunnelName tunnelName() { return tunnelName; diff --git a/framework/src/onos/ovsdb/api/src/main/java/org/onosproject/ovsdb/controller/OvsdbTunnelName.java b/framework/src/onos/ovsdb/api/src/main/java/org/onosproject/ovsdb/controller/OvsdbTunnelName.java index 116f6217..80befab3 100644 --- a/framework/src/onos/ovsdb/api/src/main/java/org/onosproject/ovsdb/controller/OvsdbTunnelName.java +++ b/framework/src/onos/ovsdb/api/src/main/java/org/onosproject/ovsdb/controller/OvsdbTunnelName.java @@ -21,13 +21,14 @@ import static com.google.common.base.Preconditions.checkNotNull; import java.util.Objects; /** - * The class representing a tunnel name. This class is immutable. + * The class representing a tunnel name. + * This class is immutable. */ public final class OvsdbTunnelName { private final String value; /** - * Constructor from a String tunnel name. + * Constructor from a String. * * @param value the tunnel name to use */ @@ -37,9 +38,9 @@ public final class OvsdbTunnelName { } /** - * Gets the value of the tunnel name. + * Gets the value of tunnel name. * - * @return the value of the tunnel name + * @return the value of tunnel name */ public String value() { return value; diff --git a/framework/src/onos/pom.xml b/framework/src/onos/pom.xml index b9fdfe22..4686e3f3 100644 --- a/framework/src/onos/pom.xml +++ b/framework/src/onos/pom.xml @@ -58,6 +58,7 @@ <module>tools/package/archetypes</module> <module>tools/package/branding</module> + <module>tools/build/conf</module> <module>bgp</module> </modules> @@ -79,7 +80,7 @@ <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> - <onos-build-conf.version>1.0</onos-build-conf.version> + <onos-build-conf.version>1.1-SNAPSHOT</onos-build-conf.version> <netty4.version>4.0.23.Final</netty4.version> <copycat.version>0.5.0.onos</copycat.version> <openflowj.version>0.9.0.onos</openflowj.version> diff --git a/framework/src/onos/providers/lldp/src/main/java/org/onosproject/provider/lldp/impl/LLDPLinkProvider.java b/framework/src/onos/providers/lldp/src/main/java/org/onosproject/provider/lldp/impl/LLDPLinkProvider.java index a840f856..98442033 100644 --- a/framework/src/onos/providers/lldp/src/main/java/org/onosproject/provider/lldp/impl/LLDPLinkProvider.java +++ b/framework/src/onos/providers/lldp/src/main/java/org/onosproject/provider/lldp/impl/LLDPLinkProvider.java @@ -27,6 +27,7 @@ import org.apache.felix.scr.annotations.Reference; import org.apache.felix.scr.annotations.ReferenceCardinality; import org.onlab.packet.Ethernet; import org.onosproject.cfg.ComponentConfigService; +import org.onosproject.cluster.ClusterService; import org.onosproject.core.ApplicationId; import org.onosproject.core.CoreService; import org.onosproject.mastership.MastershipEvent; @@ -37,6 +38,7 @@ import org.onosproject.net.Device; import org.onosproject.net.DeviceId; import org.onosproject.net.LinkKey; import org.onosproject.net.Port; +import org.onosproject.net.config.NetworkConfigRegistry; import org.onosproject.net.device.DeviceEvent; import org.onosproject.net.device.DeviceListener; import org.onosproject.net.device.DeviceService; @@ -60,6 +62,7 @@ import java.io.IOException; import java.util.Dictionary; import java.util.EnumSet; import java.util.Map; +import java.util.Optional; import java.util.Properties; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ScheduledExecutorService; @@ -86,6 +89,10 @@ public class LLDPLinkProvider extends AbstractProvider implements LinkProvider { "Settings: enabled={}, useBDDP={}, probeRate={}, " + "staleLinkAge={}, lldpSuppression={}"; + // When a Device/Port has this annotation, do not send out LLDP/BDDP + public static final String NO_LLDP = "no-lldp"; + + private final Logger log = getLogger(getClass()); @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) @@ -109,6 +116,12 @@ public class LLDPLinkProvider extends AbstractProvider implements LinkProvider { @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) protected ComponentConfigService cfgService; + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + protected ClusterService clusterService; + + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + protected NetworkConfigRegistry cfgRegistry; + private LinkProviderService providerService; private ScheduledExecutorService executor; @@ -207,7 +220,7 @@ public class LLDPLinkProvider extends AbstractProvider implements LinkProvider { newLldpSuppression = isNullOrEmpty(s) ? DEFAULT_LLDP_SUPPRESSION_CONFIG : s; } catch (NumberFormatException e) { - log.warn(e.getMessage()); + log.warn("Component configuration had invalid values", e); newEnabled = enabled; newUseBddp = useBDDP; newProbeRate = probeRate; @@ -227,6 +240,14 @@ public class LLDPLinkProvider extends AbstractProvider implements LinkProvider { enable(); } else if (wasEnabled && !enabled) { disable(); + } else { + // reflect changes in suppression rules to discovery helpers + // FIXME: After migrating to Network Configuration Subsystem, + // it should be possible to update only changed subset + if (enabled) { + // update all discovery helper state + loadDevices(); + } } log.info(FORMAT, enabled, useBDDP, probeRate, staleLinkAge, lldpSuppression); @@ -277,31 +298,96 @@ public class LLDPLinkProvider extends AbstractProvider implements LinkProvider { * Loads available devices and registers their ports to be probed. */ private void loadDevices() { - for (Device device : deviceService.getAvailableDevices()) { - if (rules.isSuppressed(device)) { - log.debug("LinkDiscovery from {} disabled by configuration", device.id()); - continue; - } - LinkDiscovery ld = new LinkDiscovery(device, context); - discoverers.put(device.id(), ld); - addPorts(ld, device.id()); + deviceService.getAvailableDevices() + .forEach(d -> updateDevice(d) + .ifPresent(ld -> updatePorts(ld, d.id()))); + } + + /** + * Updates discovery helper for specified device. + * + * Adds and starts a discovery helper for specified device if enabled, + * calls {@link #removeDevice(DeviceId)} otherwise. + * + * @param device device to add + * @return discovery helper if discovery is enabled for the device + */ + private Optional<LinkDiscovery> updateDevice(Device device) { + if (rules.isSuppressed(device)) { + log.trace("LinkDiscovery from {} disabled by configuration", device.id()); + removeDevice(device.id()); + return Optional.empty(); + } + LinkDiscovery ld = discoverers.computeIfAbsent(device.id(), + did -> new LinkDiscovery(device, context)); + if (ld.isStopped()) { + ld.start(); } + return Optional.of(ld); } /** - * Adds ports of the specified device to the specified discovery helper. + * Removes after stopping discovery helper for specified device. + * @param deviceId device to remove */ - private void addPorts(LinkDiscovery discoverer, DeviceId deviceId) { - for (Port p : deviceService.getPorts(deviceId)) { - if (rules.isSuppressed(p)) { - continue; - } - if (!p.number().isLogical()) { - discoverer.addPort(p); - } + private void removeDevice(final DeviceId deviceId) { + discoverers.computeIfPresent(deviceId, (did, ld) -> { + ld.stop(); + providerService.linksVanished(deviceId); + return null; + }); + + } + + /** + * Updates ports of the specified device to the specified discovery helper. + */ + private void updatePorts(LinkDiscovery discoverer, DeviceId deviceId) { + deviceService.getPorts(deviceId).forEach(p -> updatePort(discoverer, p)); + } + + /** + * Updates discovery helper state of the specified port. + * + * Adds a port to the discovery helper if up and discovery is enabled, + * or calls {@link #removePort(Port)} otherwise. + */ + private void updatePort(LinkDiscovery discoverer, Port port) { + if (rules.isSuppressed(port)) { + log.trace("LinkDiscovery from {} disabled by configuration", port); + removePort(port); + return; + } + + // check if enabled and turn off discovery? + if (!port.isEnabled()) { + removePort(port); + return; + } + + if (!port.number().isLogical()) { + discoverer.addPort(port); } } + /** + * Removes a port from the specified discovery helper. + * @param port the port + */ + private void removePort(Port port) { + if (port.element() instanceof Device) { + Device d = (Device) port.element(); + LinkDiscovery ld = discoverers.get(d.id()); + if (ld != null) { + ld.removePort(port.number()); + } + + ConnectPoint point = new ConnectPoint(d.id(), port.number()); + providerService.linksVanished(point); + } else { + log.warn("Attempted to remove non-Device port", port); + } + } /** * Loads LLDP suppression rules. @@ -317,7 +403,7 @@ public class LLDPLinkProvider extends AbstractProvider implements LinkProvider { // default rule to suppress ROADM to maintain compatibility rules = new SuppressionRules(ImmutableSet.of(), EnumSet.of(Device.Type.ROADM), - ImmutableMap.of()); + ImmutableMap.of(NO_LLDP, SuppressionRules.ANY_VALUE)); } // should refresh discoverers when we need dynamic reconfiguration @@ -367,10 +453,9 @@ public class LLDPLinkProvider extends AbstractProvider implements LinkProvider { log.debug("Device {} doesn't exist, or isn't there yet", deviceId); return; } - if (rules.isSuppressed(device)) { - return; + if (clusterService.getLocalNode().id().equals(event.roleInfo().master())) { + updateDevice(device).ifPresent(ld -> updatePorts(ld, device.id())); } - discoverers.computeIfAbsent(deviceId, k -> new LinkDiscovery(device, context)); } } @@ -381,7 +466,6 @@ public class LLDPLinkProvider extends AbstractProvider implements LinkProvider { private class InternalDeviceListener implements DeviceListener { @Override public void event(DeviceEvent event) { - LinkDiscovery ld; Device device = event.subject(); Port port = event.port(); if (device == null) { @@ -393,73 +477,33 @@ public class LLDPLinkProvider extends AbstractProvider implements LinkProvider { switch (event.type()) { case DEVICE_ADDED: case DEVICE_UPDATED: - synchronized (discoverers) { - ld = discoverers.get(deviceId); - if (ld == null) { - if (rules != null && rules.isSuppressed(device)) { - log.debug("LinkDiscovery from {} disabled by configuration", device.id()); - return; - } - log.debug("Device added ({}) {}", event.type(), deviceId); - discoverers.put(deviceId, new LinkDiscovery(device, context)); - } else { - if (ld.isStopped()) { - log.debug("Device restarted ({}) {}", event.type(), deviceId); - ld.start(); - } - } - } + updateDevice(device).ifPresent(ld -> updatePorts(ld, deviceId)); break; case PORT_ADDED: case PORT_UPDATED: if (port.isEnabled()) { - ld = discoverers.get(deviceId); - if (ld == null) { - return; - } - if (rules.isSuppressed(port)) { - log.debug("LinkDiscovery from {}@{} disabled by configuration", - port.number(), device.id()); - return; - } - if (!port.number().isLogical()) { - log.debug("Port added {}", port); - ld.addPort(port); - } + updateDevice(device).ifPresent(ld -> updatePort(ld, port)); } else { log.debug("Port down {}", port); - ConnectPoint point = new ConnectPoint(deviceId, port.number()); - providerService.linksVanished(point); + removePort(port); } break; case PORT_REMOVED: log.debug("Port removed {}", port); - ConnectPoint point = new ConnectPoint(deviceId, port.number()); - providerService.linksVanished(point); - + removePort(port); break; case DEVICE_REMOVED: case DEVICE_SUSPENDED: log.debug("Device removed {}", deviceId); - ld = discoverers.get(deviceId); - if (ld == null) { - return; - } - ld.stop(); - providerService.linksVanished(deviceId); + removeDevice(deviceId); break; case DEVICE_AVAILABILITY_CHANGED: - ld = discoverers.get(deviceId); - if (ld == null) { - return; - } if (deviceService.isAvailable(deviceId)) { log.debug("Device up {}", deviceId); - ld.start(); + updateDevice(device); } else { - providerService.linksVanished(deviceId); log.debug("Device down {}", deviceId); - ld.stop(); + removeDevice(deviceId); } break; case PORT_STATS_UPDATED: @@ -508,17 +552,7 @@ public class LLDPLinkProvider extends AbstractProvider implements LinkProvider { } // check what deviceService sees, to see if we are missing anything try { - for (Device dev : deviceService.getDevices()) { - if (rules.isSuppressed(dev)) { - continue; - } - DeviceId did = dev.id(); - synchronized (discoverers) { - LinkDiscovery ld = discoverers - .computeIfAbsent(did, k -> new LinkDiscovery(dev, context)); - addPorts(ld, did); - } - } + loadDevices(); } catch (Exception e) { // Catch all exceptions to avoid task being suppressed log.error("Exception thrown during synchronization process", e); diff --git a/framework/src/onos/providers/lldp/src/main/java/org/onosproject/provider/lldp/impl/LinkDiscovery.java b/framework/src/onos/providers/lldp/src/main/java/org/onosproject/provider/lldp/impl/LinkDiscovery.java index 8cdfd50f..7dc9aed0 100644 --- a/framework/src/onos/providers/lldp/src/main/java/org/onosproject/provider/lldp/impl/LinkDiscovery.java +++ b/framework/src/onos/providers/lldp/src/main/java/org/onosproject/provider/lldp/impl/LinkDiscovery.java @@ -61,7 +61,7 @@ class LinkDiscovery implements TimerTask { private final ONOSLLDP lldpPacket; private final Ethernet ethPacket; - private Ethernet bddpEth; + private final Ethernet bddpEth; private Timeout timeout; private volatile boolean isStopped; @@ -126,7 +126,7 @@ class LinkDiscovery implements TimerTask { } /** - * Add physical port port to discovery process. + * Add physical port to discovery process. * Send out initial LLDP and label it as slow port. * * @param port the port @@ -141,6 +141,14 @@ class LinkDiscovery implements TimerTask { } /** + * removed physical port from discovery process. + * @param port the port number + */ + void removePort(PortNumber port) { + ports.remove(port.toLong()); + } + + /** * Handles an incoming LLDP packet. Creates link in topology and adds the * link for staleness tracking. * diff --git a/framework/src/onos/providers/lldp/src/test/java/org/onosproject/provider/lldp/impl/LLDPLinkProviderTest.java b/framework/src/onos/providers/lldp/src/test/java/org/onosproject/provider/lldp/impl/LLDPLinkProviderTest.java index b4b7b7b6..6070b857 100644 --- a/framework/src/onos/providers/lldp/src/test/java/org/onosproject/provider/lldp/impl/LLDPLinkProviderTest.java +++ b/framework/src/onos/providers/lldp/src/test/java/org/onosproject/provider/lldp/impl/LLDPLinkProviderTest.java @@ -16,6 +16,7 @@ package org.onosproject.provider.lldp.impl; import com.google.common.collect.ArrayListMultimap; +import com.google.common.collect.ImmutableList; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import org.junit.After; @@ -32,7 +33,9 @@ import org.onosproject.core.CoreService; import org.onosproject.core.DefaultApplicationId; import org.onosproject.mastership.MastershipListener; import org.onosproject.mastership.MastershipService; +import org.onosproject.net.Annotations; import org.onosproject.net.ConnectPoint; +import org.onosproject.net.DefaultAnnotations; import org.onosproject.net.DefaultDevice; import org.onosproject.net.DefaultPort; import org.onosproject.net.Device; @@ -73,6 +76,7 @@ public class LLDPLinkProviderTest { private static final DeviceId DID1 = DeviceId.deviceId("of:0000000000000001"); private static final DeviceId DID2 = DeviceId.deviceId("of:0000000000000002"); + private static final DeviceId DID3 = DeviceId.deviceId("of:0000000000000003"); private static Port pd1; private static Port pd2; @@ -133,10 +137,35 @@ public class LLDPLinkProviderTest { deviceListener.event(deviceEvent(DeviceEvent.Type.DEVICE_ADDED, DID1)); deviceListener.event(deviceEvent(DeviceEvent.Type.DEVICE_REMOVED, DID1)); - assertTrue("Discoverer is not gone", provider.discoverers.get(DID1).isStopped()); + final LinkDiscovery linkDiscovery = provider.discoverers.get(DID1); + if (linkDiscovery != null) { + // If LinkDiscovery helper is there after DEVICE_REMOVED, + // it should be stopped + assertTrue("Discoverer is not stopped", linkDiscovery.isStopped()); + } assertTrue("Device is not gone.", vanishedDpid(DID1)); } + /** + * Checks that links on a reconfigured switch are properly removed. + */ + @Test + public void switchSuppressed() { + // add device to stub DeviceService + deviceService.putDevice(device(DID3)); + deviceListener.event(deviceEvent(DeviceEvent.Type.DEVICE_ADDED, DID3)); + + assertFalse("Device not added", provider.discoverers.isEmpty()); + + // update device in stub DeviceService with suppression config + deviceService.putDevice(device(DID3, DefaultAnnotations.builder() + .set(LLDPLinkProvider.NO_LLDP, "true") + .build())); + deviceListener.event(deviceEvent(DeviceEvent.Type.DEVICE_UPDATED, DID3)); + + assertTrue("Links on suppressed Device was expected to vanish.", vanishedDpid(DID3)); + } + @Test public void portUp() { deviceListener.event(deviceEvent(DeviceEvent.Type.DEVICE_ADDED, DID1)); @@ -152,27 +181,101 @@ public class LLDPLinkProviderTest { deviceListener.event(deviceEvent(DeviceEvent.Type.DEVICE_ADDED, DID1)); deviceListener.event(portEvent(DeviceEvent.Type.PORT_ADDED, DID1, port(DID1, 1, false))); - - assertFalse("Port added to discoverer", provider.discoverers.get(DID1).containsPort(1L)); assertTrue("Port is not gone.", vanishedPort(1L)); } @Test + public void portRemoved() { + deviceListener.event(deviceEvent(DeviceEvent.Type.DEVICE_ADDED, DID1)); + deviceListener.event(portEvent(DeviceEvent.Type.PORT_ADDED, DID1, port(DID1, 3, true))); + deviceListener.event(portEvent(DeviceEvent.Type.PORT_REMOVED, DID1, port(DID1, 3, true))); + + assertTrue("Port is not gone.", vanishedPort(3L)); + assertFalse("Port was not removed from discoverer", + provider.discoverers.get(DID1).containsPort(3L)); + } + + /** + * Checks that discovery on reconfigured switch are properly restarted. + */ + @Test + public void portSuppressedByDeviceConfig() { + + /// When Device is configured with suppression:ON, Port also is same + + // add device in stub DeviceService with suppression configured + deviceService.putDevice(device(DID3, DefaultAnnotations.builder() + .set(LLDPLinkProvider.NO_LLDP, "true") + .build())); + deviceListener.event(deviceEvent(DeviceEvent.Type.DEVICE_ADDED, DID3)); + + // non-suppressed port added to suppressed device + final long portno3 = 3L; + deviceService.putPorts(DID3, port(DID3, portno3, true)); + deviceListener.event(portEvent(DeviceEvent.Type.PORT_ADDED, DID3, port(DID3, portno3, true))); + + // discovery on device is expected to be stopped + LinkDiscovery linkDiscovery = provider.discoverers.get(DID3); + if (linkDiscovery != null) { + assertTrue("Discovery expected to be stopped", linkDiscovery.isStopped()); + } + + /// When Device is reconfigured without suppression:OFF, + /// Port should be included for discovery + + // update device in stub DeviceService without suppression configured + deviceService.putDevice(device(DID3)); + // update the Port in stub DeviceService. (Port has reference to Device) + deviceService.putPorts(DID3, port(DID3, portno3, true)); + deviceListener.event(deviceEvent(DeviceEvent.Type.DEVICE_UPDATED, DID3)); + + // discovery should come back on + assertFalse("Discoverer is expected to start", provider.discoverers.get(DID3).isStopped()); + assertTrue("Discoverer should contain the port there", provider.discoverers.get(DID3).containsPort(portno3)); + } + + /** + * Checks that discovery on reconfigured port are properly restarted. + */ + @Test + public void portSuppressedByPortConfig() { + // add device in stub DeviceService without suppression configured + deviceService.putDevice(device(DID3)); + deviceListener.event(deviceEvent(DeviceEvent.Type.DEVICE_ADDED, DID3)); + + // suppressed port added to non-suppressed device + final long portno3 = 3L; + final Port port3 = port(DID3, portno3, true, + DefaultAnnotations.builder() + .set(LLDPLinkProvider.NO_LLDP, "true") + .build()); + deviceService.putPorts(DID3, port3); + deviceListener.event(portEvent(DeviceEvent.Type.PORT_ADDED, DID3, port3)); + + // discovery helper should be there turned on + assertFalse("Discoverer is expected to start", provider.discoverers.get(DID3).isStopped()); + assertFalse("Discoverer should not contain the port there", + provider.discoverers.get(DID3).containsPort(portno3)); + } + + @Test public void portUnknown() { deviceListener.event(deviceEvent(DeviceEvent.Type.DEVICE_ADDED, DID1)); - deviceListener.event(portEvent(DeviceEvent.Type.PORT_ADDED, DID2, port(DID2, 1, false))); + // Note: DID3 hasn't been added to TestDeviceService, but only port is added + deviceListener.event(portEvent(DeviceEvent.Type.PORT_ADDED, DID3, port(DID3, 1, false))); assertNull("DeviceId exists", - provider.discoverers.get(DID2)); + provider.discoverers.get(DID3)); } @Test public void unknownPktCtx() { - PacketContext pktCtx = new TestPacketContext(deviceService.getDevice(DID2)); + // Note: DID3 hasn't been added to TestDeviceService + PacketContext pktCtx = new TestPacketContext(device(DID3)); testProcessor.process(pktCtx); assertFalse("Context should still be free", pktCtx.isHandled()); @@ -206,6 +309,16 @@ public class LLDPLinkProviderTest { } + private DefaultDevice device(DeviceId did) { + return new DefaultDevice(ProviderId.NONE, did, Device.Type.SWITCH, + "TESTMF", "TESTHW", "TESTSW", "TESTSN", new ChassisId()); + } + + private DefaultDevice device(DeviceId did, Annotations annotations) { + return new DefaultDevice(ProviderId.NONE, did, Device.Type.SWITCH, + "TESTMF", "TESTHW", "TESTSW", "TESTSN", new ChassisId(), annotations); + } + @SuppressWarnings(value = { "unused" }) private DeviceEvent portEvent(DeviceEvent.Type type, DeviceId did, PortNumber port) { return new DeviceEvent(type, deviceService.getDevice(did), @@ -221,6 +334,10 @@ public class LLDPLinkProviderTest { PortNumber.portNumber(port), enabled); } + private Port port(DeviceId did, long port, boolean enabled, Annotations annotations) { + return new DefaultPort(deviceService.getDevice(did), + PortNumber.portNumber(port), enabled, annotations); + } private boolean vanishedDpid(DeviceId... dids) { for (int i = 0; i < dids.length; i++) { @@ -384,10 +501,9 @@ public class LLDPLinkProviderTest { private class TestDeviceService extends DeviceServiceAdapter { - private Map<DeviceId, Device> devices = new HashMap<>(); + private final Map<DeviceId, Device> devices = new HashMap<>(); private final ArrayListMultimap<DeviceId, Port> ports = ArrayListMultimap.create(); - public TestDeviceService() { Device d1 = new DefaultDevice(ProviderId.NONE, DID1, Device.Type.SWITCH, "TESTMF", "TESTHW", "TESTSW", "TESTSN", new ChassisId()); @@ -395,7 +511,6 @@ public class LLDPLinkProviderTest { "TESTMF", "TESTHW", "TESTSW", "TESTSN", new ChassisId()); devices.put(DID1, d1); devices.put(DID2, d2); - pd1 = new DefaultPort(d1, PortNumber.portNumber(1), true); pd2 = new DefaultPort(d1, PortNumber.portNumber(2), true); pd3 = new DefaultPort(d2, PortNumber.portNumber(1), true); @@ -405,6 +520,15 @@ public class LLDPLinkProviderTest { ports.putAll(DID2, Lists.newArrayList(pd3, pd4)); } + private void putDevice(Device device) { + DeviceId deviceId = device.id(); + devices.put(deviceId, device); + } + + private void putPorts(DeviceId did, Port...ports) { + this.ports.putAll(did, Lists.newArrayList(ports)); + } + @Override public int getDeviceCount() { return devices.values().size(); @@ -412,7 +536,7 @@ public class LLDPLinkProviderTest { @Override public Iterable<Device> getDevices() { - return Collections.emptyList(); + return ImmutableList.copyOf(devices.values()); } @Override 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 index 1039d049..4d5b6b28 100644 --- 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 @@ -15,15 +15,7 @@ */ 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 com.google.common.collect.Lists; import org.onlab.packet.Ip4Address; import org.onlab.packet.Ip4Prefix; import org.onlab.packet.Ip6Address; @@ -36,6 +28,11 @@ import org.onosproject.core.DefaultGroupId; import org.onosproject.net.DeviceId; import org.onosproject.net.Lambda; import org.onosproject.net.PortNumber; +import org.onosproject.net.driver.DefaultDriverData; +import org.onosproject.net.driver.DefaultDriverHandler; +import org.onosproject.net.driver.Driver; +import org.onosproject.net.driver.DriverHandler; +import org.onosproject.net.driver.DriverService; import org.onosproject.net.flow.DefaultFlowEntry; import org.onosproject.net.flow.DefaultFlowRule; import org.onosproject.net.flow.DefaultTrafficSelector; @@ -47,6 +44,7 @@ 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.onosproject.openflow.controller.ExtensionInterpreter; import org.projectfloodlight.openflow.protocol.OFFlowMod; import org.projectfloodlight.openflow.protocol.OFFlowRemoved; import org.projectfloodlight.openflow.protocol.OFFlowStatsEntry; @@ -55,13 +53,13 @@ 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.OFActionSetQueue; 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.OFActionSetQueue; import org.projectfloodlight.openflow.protocol.action.OFActionSetVlanPcp; import org.projectfloodlight.openflow.protocol.action.OFActionSetVlanVid; import org.projectfloodlight.openflow.protocol.instruction.OFInstruction; @@ -75,7 +73,6 @@ 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; @@ -87,7 +84,14 @@ import org.projectfloodlight.openflow.types.U8; import org.projectfloodlight.openflow.types.VlanPcp; import org.slf4j.Logger; -import com.google.common.collect.Lists; +import java.util.List; + +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; public class FlowEntryBuilder { private final Logger log = getLogger(getClass()); @@ -108,7 +112,9 @@ public class FlowEntryBuilder { private final FlowType type; - public FlowEntryBuilder(Dpid dpid, OFFlowStatsEntry entry) { + private final DriverService driverService; + + public FlowEntryBuilder(Dpid dpid, OFFlowStatsEntry entry, DriverService driverService) { this.stat = entry; this.match = entry.getMatch(); this.instructions = getInstructions(entry); @@ -116,9 +122,10 @@ public class FlowEntryBuilder { this.removed = null; this.flowMod = null; this.type = FlowType.STAT; + this.driverService = driverService; } - public FlowEntryBuilder(Dpid dpid, OFFlowRemoved removed) { + public FlowEntryBuilder(Dpid dpid, OFFlowRemoved removed, DriverService driverService) { this.match = removed.getMatch(); this.removed = removed; @@ -127,10 +134,10 @@ public class FlowEntryBuilder { this.stat = null; this.flowMod = null; this.type = FlowType.REMOVED; - + this.driverService = driverService; } - public FlowEntryBuilder(Dpid dpid, OFFlowMod fm) { + public FlowEntryBuilder(Dpid dpid, OFFlowMod fm, DriverService driverService) { this.match = fm.getMatch(); this.dpid = dpid; this.instructions = getInstructions(fm); @@ -138,6 +145,7 @@ public class FlowEntryBuilder { this.flowMod = fm; this.stat = null; this.removed = null; + this.driverService = driverService; } public FlowEntry build(FlowEntryState... state) { @@ -309,7 +317,7 @@ public class FlowEntryBuilder { break; case SET_FIELD: OFActionSetField setField = (OFActionSetField) act; - handleSetField(builder, setField.getField()); + handleSetField(builder, setField); break; case POP_MPLS: OFActionPopMpls popMpls = (OFActionPopMpls) act; @@ -365,7 +373,8 @@ public class FlowEntryBuilder { } - private void handleSetField(TrafficTreatment.Builder builder, OFOxm<?> oxm) { + private void handleSetField(TrafficTreatment.Builder builder, OFActionSetField action) { + OFOxm<?> oxm = action.getField(); switch (oxm.getMatchField().id) { case VLAN_PCP: @SuppressWarnings("unchecked") @@ -434,6 +443,13 @@ public class FlowEntryBuilder { OFOxm<TransportPort> udpsrc = (OFOxm<TransportPort>) oxm; builder.setUdpSrc(TpPort.tpPort(udpsrc.getValue().getPort())); break; + case TUNNEL_IPV4_DST: + DriverHandler driver = getDriver(dpid); + ExtensionInterpreter interpreter = driver.behaviour(ExtensionInterpreter.class); + if (interpreter != null) { + builder.extension(interpreter.mapAction(action), DeviceId.deviceId(Dpid.uri(dpid))); + } + break; case ARP_OP: case ARP_SHA: case ARP_SPA: @@ -520,11 +536,7 @@ public class FlowEntryBuilder { 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); - } + builder.matchEthType((short) ethType); break; case VLAN_VID: VlanId vlanId = null; @@ -703,4 +715,11 @@ public class FlowEntryBuilder { } return builder.build(); } + + private DriverHandler getDriver(Dpid dpid) { + DeviceId deviceId = DeviceId.deviceId(Dpid.uri(dpid)); + Driver driver = driverService.getDriver(deviceId); + DriverHandler handler = new DefaultDriverHandler(new DefaultDriverData(driver, deviceId)); + return handler; + } } 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 index e050524a..7eca4920 100644 --- 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 @@ -15,16 +15,13 @@ */ 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.driver.DriverService; import org.onosproject.net.flow.FlowRule; import org.onosproject.net.flow.TrafficSelector; import org.onosproject.net.flow.criteria.Criterion; @@ -85,6 +82,10 @@ import org.projectfloodlight.openflow.types.VlanPcp; import org.projectfloodlight.openflow.types.VlanVid; import org.slf4j.Logger; +import java.util.Optional; + +import static org.slf4j.LoggerFactory.getLogger; + /** * Builder for OpenFlow flow mods based on FlowRules. */ @@ -96,6 +97,7 @@ public abstract class FlowModBuilder { private final FlowRule flowRule; private final TrafficSelector selector; protected final Long xid; + protected final Optional<DriverService> driverService; /** * Creates a new flow mod builder. @@ -107,12 +109,13 @@ public abstract class FlowModBuilder { */ public static FlowModBuilder builder(FlowRule flowRule, OFFactory factory, - Optional<Long> xid) { + Optional<Long> xid, + Optional<DriverService> driverService) { switch (factory.getVersion()) { case OF_10: - return new FlowModBuilderVer10(flowRule, factory, xid); + return new FlowModBuilderVer10(flowRule, factory, xid, driverService); case OF_13: - return new FlowModBuilderVer13(flowRule, factory, xid); + return new FlowModBuilderVer13(flowRule, factory, xid, driverService); default: throw new UnsupportedOperationException( "No flow mod builder for protocol version " + factory.getVersion()); @@ -126,12 +129,13 @@ public abstract class FlowModBuilder { * @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) { + protected FlowModBuilder(FlowRule flowRule, OFFactory factory, Optional<Long> xid, + Optional<DriverService> driverService) { this.factory = factory; this.flowRule = flowRule; this.selector = flowRule.selector(); this.xid = xid.orElse(0L); - + this.driverService = driverService; } /** 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 index f77819d5..c7898414 100644 --- 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 @@ -17,6 +17,7 @@ package org.onosproject.provider.of.flow.impl; import org.onlab.packet.Ip4Address; import org.onosproject.net.PortNumber; +import org.onosproject.net.driver.DriverService; import org.onosproject.net.flow.FlowRule; import org.onosproject.net.flow.TrafficTreatment; import org.onosproject.net.flow.instructions.Instruction; @@ -68,8 +69,9 @@ public class FlowModBuilderVer10 extends FlowModBuilder { * @param xid the transaction ID */ protected FlowModBuilderVer10(FlowRule flowRule, - OFFactory factory, Optional<Long> xid) { - super(flowRule, factory, xid); + OFFactory factory, Optional<Long> xid, + Optional<DriverService> driverService) { + super(flowRule, factory, xid, driverService); this.treatment = flowRule.treatment(); } 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 index 64b4360a..a99aa817 100644 --- 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 @@ -18,10 +18,16 @@ 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.DeviceId; import org.onosproject.net.OchSignal; import org.onosproject.net.PortNumber; +import org.onosproject.net.driver.DefaultDriverData; +import org.onosproject.net.driver.DefaultDriverHandler; +import org.onosproject.net.driver.Driver; +import org.onosproject.net.driver.DriverService; import org.onosproject.net.flow.FlowRule; import org.onosproject.net.flow.TrafficTreatment; +import org.onosproject.net.flow.instructions.ExtensionInstruction; import org.onosproject.net.flow.instructions.Instruction; import org.onosproject.net.flow.instructions.Instructions; import org.onosproject.net.flow.instructions.Instructions.GroupInstruction; @@ -34,15 +40,16 @@ 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.ModTunnelIdInstruction; 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.onosproject.openflow.controller.ExtensionInterpreter; import org.projectfloodlight.openflow.protocol.OFFactory; import org.projectfloodlight.openflow.protocol.OFFlowAdd; import org.projectfloodlight.openflow.protocol.OFFlowDelete; @@ -88,6 +95,7 @@ public class FlowModBuilderVer13 extends FlowModBuilder { private static final int OFPCML_NO_BUFFER = 0xffff; private final TrafficTreatment treatment; + private final DeviceId deviceId; /** * Constructor for a flow mod builder for OpenFlow 1.3. @@ -96,10 +104,12 @@ public class FlowModBuilderVer13 extends FlowModBuilder { * @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); + protected FlowModBuilderVer13(FlowRule flowRule, OFFactory factory, Optional<Long> xid, + Optional<DriverService> driverService) { + super(flowRule, factory, xid, driverService); this.treatment = flowRule.treatment(); + this.deviceId = flowRule.deviceId(); } @Override @@ -256,6 +266,10 @@ public class FlowModBuilderVer13 extends FlowModBuilder { //FIXME: should not occur here. tableFound = true; break; + case EXTENSION: + actions.add(buildExtensionAction(((Instructions.ExtensionInstructionWrapper) i) + .extensionInstruction())); + break; default: log.warn("Instruction type {} not yet implemented.", i.type()); } @@ -467,4 +481,20 @@ public class FlowModBuilderVer13 extends FlowModBuilder { return null; } + private OFAction buildExtensionAction(ExtensionInstruction i) { + if (!driverService.isPresent()) { + log.error("No driver service present"); + return null; + } + Driver driver = driverService.get().getDriver(deviceId); + if (driver.hasBehaviour(ExtensionInterpreter.class)) { + DefaultDriverHandler handler = + new DefaultDriverHandler(new DefaultDriverData(driver, deviceId)); + ExtensionInterpreter interpreter = handler.behaviour(ExtensionInterpreter.class); + return interpreter.mapInstruction(factory(), i); + } + + return null; + } + } diff --git a/framework/src/onos/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/NewAdaptiveFlowStatsCollector.java b/framework/src/onos/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/NewAdaptiveFlowStatsCollector.java index 487cae96..d5186fa9 100644 --- a/framework/src/onos/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/NewAdaptiveFlowStatsCollector.java +++ b/framework/src/onos/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/NewAdaptiveFlowStatsCollector.java @@ -16,21 +16,10 @@ package org.onosproject.provider.of.flow.impl;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Optional;
-import java.util.Set;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.ScheduledFuture;
-import java.util.concurrent.Executors;
-import java.util.concurrent.ScheduledExecutorService;
-
import com.google.common.base.Objects;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
-
import org.onosproject.net.flow.DefaultTypedFlowEntry;
import org.onosproject.net.flow.FlowEntry;
import org.onosproject.net.flow.FlowId;
@@ -47,9 +36,19 @@ import org.projectfloodlight.openflow.types.OFPort; import org.projectfloodlight.openflow.types.TableId;
import org.slf4j.Logger;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import java.util.Set;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.ScheduledFuture;
+import java.util.concurrent.TimeUnit;
+
import static com.google.common.base.Preconditions.checkNotNull;
import static org.onlab.util.Tools.groupedThreads;
-import static org.onosproject.net.flow.TypedStoredFlowEntry.*;
+import static org.onosproject.net.flow.TypedStoredFlowEntry.FlowLiveType;
import static org.slf4j.LoggerFactory.getLogger;
/**
@@ -232,7 +231,8 @@ public class NewAdaptiveFlowStatsCollector { // send openflow flow stats request message with getting the specific flow entry(fe) to a given switch sw
private void ofFlowStatsRequestFlowSend(FlowEntry fe) {
// set find match
- Match match = FlowModBuilder.builder(fe, sw.factory(), Optional.empty()).buildMatch();
+ Match match = FlowModBuilder.builder(fe, sw.factory(), Optional.empty(),
+ Optional.empty()).buildMatch();
// set find tableId
TableId tableId = TableId.of(fe.tableId());
// set output port
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 index 6374ca55..b37cb42c 100644 --- 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 @@ -21,7 +21,6 @@ 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; @@ -32,6 +31,7 @@ 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.driver.DriverService; import org.onosproject.net.flow.CompletedBatchOperation; import org.onosproject.net.flow.DefaultTableStatisticsEntry; import org.onosproject.net.flow.FlowEntry; @@ -61,12 +61,12 @@ 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.OFTableStatsReply; -import org.projectfloodlight.openflow.protocol.OFTableStatsEntry; 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.OFTableStatsEntry; +import org.projectfloodlight.openflow.protocol.OFTableStatsReply; import org.projectfloodlight.openflow.protocol.errormsg.OFBadRequestErrorMsg; import org.projectfloodlight.openflow.protocol.errormsg.OFFlowModFailedErrorMsg; import org.slf4j.Logger; @@ -106,6 +106,9 @@ public class OpenFlowRuleProvider extends AbstractProvider @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) protected ComponentConfigService cfgService; + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + protected DriverService driverService; + private static final int DEFAULT_POLL_FREQUENCY = 5; @Property(name = "flowPollFrequency", intValue = DEFAULT_POLL_FREQUENCY, label = "Frequency (in seconds) for polling flow statistics") @@ -269,7 +272,7 @@ public class OpenFlowRuleProvider extends AbstractProvider return; } sw.sendMsg(FlowModBuilder.builder(flowRule, sw.factory(), - Optional.empty()).buildFlowAdd()); + Optional.empty(), Optional.of(driverService)).buildFlowAdd()); if (adaptiveFlowSampling) { // Add TypedFlowEntry to deviceFlowEntries in NewAdaptiveFlowStatsCollector @@ -298,7 +301,7 @@ public class OpenFlowRuleProvider extends AbstractProvider return; } sw.sendMsg(FlowModBuilder.builder(flowRule, sw.factory(), - Optional.empty()).buildFlowDel()); + Optional.empty(), Optional.of(driverService)).buildFlowDel()); if (adaptiveFlowSampling) { // Remove TypedFlowEntry to deviceFlowEntries in NewAdaptiveFlowStatsCollector @@ -334,7 +337,8 @@ public class OpenFlowRuleProvider extends AbstractProvider continue; } FlowModBuilder builder = - FlowModBuilder.builder(fbe.target(), sw.factory(), Optional.of(batch.id())); + FlowModBuilder.builder(fbe.target(), sw.factory(), + Optional.of(batch.id()), Optional.of(driverService)); NewAdaptiveFlowStatsCollector collector = afsCollectors.get(dpid); switch (fbe.operator()) { case ADD: @@ -423,7 +427,7 @@ public class OpenFlowRuleProvider extends AbstractProvider case FLOW_REMOVED: OFFlowRemoved removed = (OFFlowRemoved) msg; - FlowEntry fr = new FlowEntryBuilder(dpid, removed).build(); + FlowEntry fr = new FlowEntryBuilder(dpid, removed, driverService).build(); providerService.flowRemoved(fr); if (adaptiveFlowSampling) { @@ -474,7 +478,7 @@ public class OpenFlowRuleProvider extends AbstractProvider InternalCacheEntry entry = pendingBatches.getIfPresent(msg.getXid()); if (entry != null) { - entry.appendFailure(new FlowEntryBuilder(dpid, fm).build()); + entry.appendFailure(new FlowEntryBuilder(dpid, fm, driverService).build()); } else { log.error("No matching batch for this error: {}", error); } @@ -501,7 +505,7 @@ public class OpenFlowRuleProvider extends AbstractProvider DeviceId did = DeviceId.deviceId(Dpid.uri(dpid)); List<FlowEntry> flowEntries = replies.getEntries().stream() - .map(entry -> new FlowEntryBuilder(dpid, entry).build()) + .map(entry -> new FlowEntryBuilder(dpid, entry, driverService).build()) .collect(Collectors.toList()); if (adaptiveFlowSampling) { 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 index b9de7c0f..d3a23782 100644 --- 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 @@ -115,6 +115,10 @@ public class GroupBucketEntryBuilder { DefaultGroupBucket.createFailoverGroupBucket(treatment, port, groupId); break; + case ALL: + groupBucket = + DefaultGroupBucket.createAllGroupBucket(treatment); + break; default: log.error("Unsupported Group type : {}", type); } 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 index 8acf08ee..5783c842 100644 --- 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 @@ -252,7 +252,7 @@ public class OpenFlowGroupProvider extends AbstractProvider implements GroupProv private GroupDescription.Type getGroupType(OFGroupType type) { switch (type) { case ALL: - return GroupDescription.Type.ALL; + return GroupDescription.Type.ALL; case INDIRECT: return GroupDescription.Type.INDIRECT; case SELECT: diff --git a/framework/src/onos/providers/ovsdb/host/src/main/java/org/onosproject/ovsdb/provider/host/OvsdbHostProvider.java b/framework/src/onos/providers/ovsdb/host/src/main/java/org/onosproject/ovsdb/provider/host/OvsdbHostProvider.java index 0e3e1564..031fda78 100644 --- a/framework/src/onos/providers/ovsdb/host/src/main/java/org/onosproject/ovsdb/provider/host/OvsdbHostProvider.java +++ b/framework/src/onos/providers/ovsdb/host/src/main/java/org/onosproject/ovsdb/provider/host/OvsdbHostProvider.java @@ -111,7 +111,7 @@ public class OvsdbHostProvider extends AbstractProvider implements HostProvider } switch (event.type()) { case PORT_ADDED: - HostId hostId = HostId.hostId(subject.hwAddress(), null); + HostId hostId = HostId.hostId(subject.hwAddress(), VlanId.vlanId()); DeviceId deviceId = DeviceId.deviceId(uri(subject.dpid().value())); PortNumber portNumber = PortNumber.portNumber(subject .portNumber().value(), subject.portName().value()); @@ -127,7 +127,7 @@ public class OvsdbHostProvider extends AbstractProvider implements HostProvider providerService.hostDetected(hostId, hostDescription); break; case PORT_REMOVED: - HostId host = HostId.hostId(subject.hwAddress(), null); + HostId host = HostId.hostId(subject.hwAddress(), VlanId.vlanId()); providerService.hostVanished(host); break; default: diff --git a/framework/src/onos/tools/build/conf/pom.xml b/framework/src/onos/tools/build/conf/pom.xml index 29e4dea0..d56168f2 100644 --- a/framework/src/onos/tools/build/conf/pom.xml +++ b/framework/src/onos/tools/build/conf/pom.xml @@ -27,7 +27,7 @@ <groupId>org.onosproject</groupId> <artifactId>onos-build-conf</artifactId> - <version>1.1</version> + <version>1.1-SNAPSHOT</version> <description>Various ONOS build settings</description> <properties> diff --git a/framework/src/onos/tools/build/conf/src/main/resources/onos/checkstyle.xml b/framework/src/onos/tools/build/conf/src/main/resources/onos/checkstyle.xml index 1bb3b0bf..e04479c5 100644 --- a/framework/src/onos/tools/build/conf/src/main/resources/onos/checkstyle.xml +++ b/framework/src/onos/tools/build/conf/src/main/resources/onos/checkstyle.xml @@ -67,9 +67,7 @@ --> <!-- Checks that a package-info.java file exists for each package. --> <!-- See http://checkstyle.sf.net/config_javadoc.html#JavadocPackage --> - <!-- ONOS does not currently supply package level Javadoc information - in package-info files --> - <!-- <module name="JavadocPackage"/> --> + <module name="JavadocPackage"/> <!-- Checks whether files end with a new line. --> <!-- See http://checkstyle.sf.net/config_misc.html#NewlineAtEndOfFile --> diff --git a/framework/src/onos/tools/build/conf/src/main/resources/onos/suppressions.xml b/framework/src/onos/tools/build/conf/src/main/resources/onos/suppressions.xml index a71d941f..6d8f1982 100644 --- a/framework/src/onos/tools/build/conf/src/main/resources/onos/suppressions.xml +++ b/framework/src/onos/tools/build/conf/src/main/resources/onos/suppressions.xml @@ -29,4 +29,12 @@ <suppress files=".*" checks="HiddenField"/> <suppress files=".java" checks="NewlineAtEndOfFile"/> + <!-- Suppressions for unit testing code --> + <suppress checks="JavadocPackage" + files=".*/src/test/.*.java" + /> + + <suppress checks="JavadocPackage" + files=".*/thirdparty/.*.java"/> + </suppressions> diff --git a/framework/src/onos/tools/dev/bin/onos-build-selective b/framework/src/onos/tools/dev/bin/onos-build-selective index ac2dec8e..351c53ac 100755 --- a/framework/src/onos/tools/dev/bin/onos-build-selective +++ b/framework/src/onos/tools/dev/bin/onos-build-selective @@ -15,9 +15,11 @@ if [ -n "$projects" ]; then # Ascertain artifact IDs of the projects to be rebuilt modulesERE="" for pd in ${projects//,/ }; do - artifactId=$(grep -E "^ <artifactId>.*</artifactId>$" ${pd}/pom.xml | \ - sed 's/.[^>]*>//;s/<.*//') - modulesERE="$modulesERE|$artifactId" + if [ -f ${pd}/pom.xml ]; then + artifactId=$(grep -E "^ <artifactId>.*</artifactId>$" ${pd}/pom.xml | \ + sed 's/.[^>]*>//;s/<.*//') + modulesERE="$modulesERE|$artifactId" + fi done modulesERE=${modulesERE#|*} diff --git a/framework/src/onos/tools/dev/bin/onos-build-selective.exclude b/framework/src/onos/tools/dev/bin/onos-build-selective.exclude index 1265494e..487f848c 100644 --- a/framework/src/onos/tools/dev/bin/onos-build-selective.exclude +++ b/framework/src/onos/tools/dev/bin/onos-build-selective.exclude @@ -6,4 +6,5 @@ .*/cord-gui/.* .*/jdvue/.* .*/ovsdb/api/.* -.*/netconf/flow/.*
\ No newline at end of file +.*/netconf/flow/.* +.*/vtn/sfcmgr/.*
\ No newline at end of file diff --git a/framework/src/onos/tools/dev/bin/onos-setup-karaf b/framework/src/onos/tools/dev/bin/onos-setup-karaf index 3323d9d1..cbe62253 100755 --- a/framework/src/onos/tools/dev/bin/onos-setup-karaf +++ b/framework/src/onos/tools/dev/bin/onos-setup-karaf @@ -97,13 +97,11 @@ fi echo "Creating local cluster configs for IP $IP..." [ -d $STAGE/config ] || mkdir -p $STAGE/config cat > $STAGE/config/cluster.json <<EOF - { "ipPrefix": "$SUBNET.*", - "nodes":[ { "id": "$IP", "ip": "$IP", "tcpPort": 9876 }]} -EOF - -cat > $STAGE/config/tablets.json <<EOF - { "nodes": [ { "ip": "$IP", "id": "$IP", "tcpPort": 9876 }], - "partitions": { "p1": [ { "ip": "$IP", "id": "$IP", "tcpPort": 9876 }]}} +{ + "name": "default", + "nodes": [ {"id": "$IP", "ip": "$IP", "port": 9876 } ], + "partitions": [ { "name": "p1", "members": [ "$IP" ] } ] +} EOF if [ "$CLEAN" = "true" ]; then diff --git a/framework/src/onos/tools/package/archetypes/uitopo/src/main/resources/archetype-resources/src/main/java/AppUiTopovMessageHandler.java b/framework/src/onos/tools/package/archetypes/uitopo/src/main/resources/archetype-resources/src/main/java/AppUiTopovMessageHandler.java index 7c35cc53..65e3489f 100644 --- a/framework/src/onos/tools/package/archetypes/uitopo/src/main/resources/archetype-resources/src/main/java/AppUiTopovMessageHandler.java +++ b/framework/src/onos/tools/package/archetypes/uitopo/src/main/resources/archetype-resources/src/main/java/AppUiTopovMessageHandler.java @@ -33,7 +33,10 @@ import org.onosproject.net.link.LinkService; import org.onosproject.ui.RequestHandler; import org.onosproject.ui.UiConnection; import org.onosproject.ui.UiMessageHandler; +import org.onosproject.ui.topo.DeviceHighlight; import org.onosproject.ui.topo.Highlights; +import org.onosproject.ui.topo.NodeBadge; +import org.onosproject.ui.topo.NodeBadge.Status; import org.onosproject.ui.topo.TopoJson; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -224,11 +227,26 @@ public class AppUiTopovMessageHandler extends UiMessageHandler { if (elementOfNote != null && elementOfNote instanceof Device) { DeviceId devId = (DeviceId) elementOfNote.id(); Set<Link> links = linkService.getDeviceEgressLinks(devId); - sendHighlights(fromLinks(links, devId)); + Highlights highlights = fromLinks(links, devId); + addDeviceBadge(highlights, devId, links.size()); + sendHighlights(highlights); } // Note: could also process Host, if available } + private void addDeviceBadge(Highlights h, DeviceId devId, int n) { + DeviceHighlight dh = new DeviceHighlight(devId.toString()); + dh.setBadge(createBadge(n)); + h.add(dh); + } + + private NodeBadge createBadge(int n) { + Status status = n > 3 ? Status.ERROR : Status.WARN; + String noun = n > 3 ? "(critical)" : "(problematic)"; + String msg = "Egress links: " + n + " " + noun; + return NodeBadge.number(status, n, msg); + } + private Highlights fromLinks(Set<Link> links, DeviceId devId) { DemoLinkMap linkMap = new DemoLinkMap(); if (links != null) { diff --git a/framework/src/onos/tools/package/archetypes/uitopo/src/main/resources/archetype-resources/src/main/java/AppUiTopovOverlay.java b/framework/src/onos/tools/package/archetypes/uitopo/src/main/resources/archetype-resources/src/main/java/AppUiTopovOverlay.java index 98999825..48e75a5a 100644 --- a/framework/src/onos/tools/package/archetypes/uitopo/src/main/resources/archetype-resources/src/main/java/AppUiTopovOverlay.java +++ b/framework/src/onos/tools/package/archetypes/uitopo/src/main/resources/archetype-resources/src/main/java/AppUiTopovOverlay.java @@ -18,13 +18,20 @@ */ package ${package}; +import org.onosproject.net.DeviceId; import org.onosproject.ui.UiTopoOverlay; import org.onosproject.ui.topo.ButtonId; import org.onosproject.ui.topo.PropertyPanel; import org.onosproject.ui.topo.TopoConstants.CoreButtons; import org.onosproject.ui.topo.TopoConstants.Glyphs; -import static org.onosproject.ui.topo.TopoConstants.Properties.*; +import static org.onosproject.ui.topo.TopoConstants.Properties.FLOWS; +import static org.onosproject.ui.topo.TopoConstants.Properties.INTENTS; +import static org.onosproject.ui.topo.TopoConstants.Properties.LATITUDE; +import static org.onosproject.ui.topo.TopoConstants.Properties.LONGITUDE; +import static org.onosproject.ui.topo.TopoConstants.Properties.TOPOLOGY_SSCS; +import static org.onosproject.ui.topo.TopoConstants.Properties.TUNNELS; +import static org.onosproject.ui.topo.TopoConstants.Properties.VERSION; /** * Our topology overlay. @@ -61,7 +68,7 @@ public class AppUiTopovOverlay extends UiTopoOverlay { } @Override - public void modifyDeviceDetails(PropertyPanel pp) { + public void modifyDeviceDetails(PropertyPanel pp, DeviceId deviceId) { pp.title(MY_DEVICE_TITLE); pp.removeProps(LATITUDE, LONGITUDE); diff --git a/framework/src/onos/tools/test/bin/onos-config b/framework/src/onos/tools/test/bin/onos-config index 348cb839..e37dc3b2 100755 --- a/framework/src/onos/tools/test/bin/onos-config +++ b/framework/src/onos/tools/test/bin/onos-config @@ -37,17 +37,6 @@ export ONOS_BOOT_FEATURES="${ONOS_BOOT_FEATURES:-webconsole,onos-api,onos-core,o # ONOS builtin apps and providers ignited by default export ONOS_APPS="${ONOS_APPS:-drivers,openflow}" -# Generate a cluster.json from the ON* environment variables -CDEF_FILE=/tmp/${remote}.cluster.json -echo "{ \"ipPrefix\": \"$ONOS_NIC\"," > $CDEF_FILE -echo " \"nodes\":[" >> $CDEF_FILE -for node in $(env | sort | egrep "OC[2-9]+" | cut -d= -f2); do - echo " { \"id\": \"$node\", \"ip\": \"$node\", \"tcpPort\": 9876 }," >> $CDEF_FILE -done -echo " { \"id\": \"$OC1\", \"ip\": \"$OC1\", \"tcpPort\": 9876 }" >> $CDEF_FILE -echo "]}" >> $CDEF_FILE -scp -q $CDEF_FILE $remote:$ONOS_INSTALL_DIR/config/cluster.json - ssh $remote " echo \"onos.ip = \$(sudo ifconfig | grep $ONOS_NIC | cut -d: -f2 | cut -d\\ -f1)\" \ >> $ONOS_INSTALL_DIR/$KARAF_DIST/etc/system.properties @@ -66,10 +55,10 @@ ssh $remote " done " -# Generate a default tablets.json from the ON* environment variables -TDEF_FILE=/tmp/${remote}.tablets.json -onos-gen-partitions $TDEF_FILE -scp -q $TDEF_FILE $remote:$ONOS_INSTALL_DIR/config/tablets.json +# Generate a default cluster.json from the ON* environment variables +CDEF_FILE=/tmp/${remote}.cluster.json +onos-gen-partitions $CDEF_FILE +scp -q $CDEF_FILE $remote:$ONOS_INSTALL_DIR/config/cluster.json # Copy tools/package/config/ to remote scp -qr ${ONOS_ROOT}/tools/package/config/ $remote:$ONOS_INSTALL_DIR/ diff --git a/framework/src/onos/tools/test/bin/onos-execute-expect b/framework/src/onos/tools/test/bin/onos-execute-expect new file mode 100755 index 00000000..6ad95699 --- /dev/null +++ b/framework/src/onos/tools/test/bin/onos-execute-expect @@ -0,0 +1,27 @@ +#!/bin/bash +# ----------------------------------------------------------------------------- +# Executes a command on the given ONOS instance and matches the output +# to the passed one. +# First argument is the IP address of the machine to run the command on, +# then you pass the command and it's arguments if needed, then --expect and +# after it the string of what the output should be. +# Example: +# onos-execute-expect 1.1.1.1 fooCommand fooParamenter --expect fooOutputString +# ----------------------------------------------------------------------------- + +[ ! -d "$ONOS_ROOT" ] && echo "ONOS_ROOT is not defined" >&2 && exit 1 +. $ONOS_ROOT/tools/build/envDefaults + + +aux=/tmp/stc-$$.log +trap "rm -f $aux 2>/dev/null" EXIT +ip=$1 +cmd="" +for a in ${*:2}; do shift; if [ "$a" = "--expect" ]; then break; fi; cmd="$cmd $a"; done +expect="${@: -1}" +onos $ip $cmd > $aux +cat $aux +grep -q $expect $aux && echo "expected value found" && exit 0 +exit 1 + + diff --git a/framework/src/onos/tools/test/bin/onos-gen-partitions b/framework/src/onos/tools/test/bin/onos-gen-partitions index a2558392..35195b04 100755 --- a/framework/src/onos/tools/test/bin/onos-gen-partitions +++ b/framework/src/onos/tools/test/bin/onos-gen-partitions @@ -23,22 +23,27 @@ def get_OC_vars(): return sorted(vars, key=alphanum_key) def get_nodes(vars, port=9876): - node = lambda k: { 'id': k, 'ip': k, 'tcpPort': port } + node = lambda k: { 'id': k, 'ip': k, 'port': port } return [ node(environ[v]) for v in vars ] def generate_permutations(nodes, k): l = deque(nodes) - perms = {} + perms = [] for i in range(1, len(nodes)+1): - perms['p%d' % i] = list(l)[:k] + part = { + 'name': 'p%d' % i, + 'members': list(l)[:k] + } + perms.append(part) l.rotate(-1) - return OrderedDict(sorted(perms.iteritems(), key=lambda (k, v): alphanum_key(k))) + return perms if __name__ == '__main__': vars = get_OC_vars() nodes = get_nodes(vars) - partitions = generate_permutations(nodes, 3) - data = { + partitions = generate_permutations([v.get('id') for v in nodes], 3) + data = { + 'name': 'default', 'nodes': nodes, 'partitions': partitions } diff --git a/framework/src/onos/tools/test/bin/onos-secure-ssh b/framework/src/onos/tools/test/bin/onos-secure-ssh index a3980e17..6d898ee8 100755 --- a/framework/src/onos/tools/test/bin/onos-secure-ssh +++ b/framework/src/onos/tools/test/bin/onos-secure-ssh @@ -10,7 +10,8 @@ nodes=$(env | sort | egrep "OC[0-9]+" | cut -d= -f2) for node in $nodes; do # Prune the node entry from the known hosts file since server key changes - ssh-keygen -f "$HOME/.ssh/known_hosts" -R [$node]:8101 + ssh-keygen -f "$HOME/.ssh/known_hosts" -R [$node]:8101 || + ( echo "Failed to remove key from known_hosts" >&2 && exit 1 ) # Setup passwordless login for the local user on the remote node ssh $ONOS_USER@$node " diff --git a/framework/src/onos/tools/test/bin/stc b/framework/src/onos/tools/test/bin/stc index 8737cf3f..60a1720e 100755 --- a/framework/src/onos/tools/test/bin/stc +++ b/framework/src/onos/tools/test/bin/stc @@ -20,6 +20,7 @@ scenario=${1:-smoke} # If stcColor is not set, we will enable color if this is an interactive session [ -t 1 ] && interactive=true || interactive=false +[ -t 1 ] && notInteractive=false || notInteractive=true # stc requires that ONOS_USE_SSH=true, but we will store the old value and reset it after sshSet=$([ -z ${ONOS_USE_SSH+x} ]) && oldSSH=$ONOS_USE_SSH @@ -27,7 +28,8 @@ export ONOS_USE_SSH=true # Run stc [ -z "$stcDebug" ] && DEBUG_OPTS="" -stcColor=${stcColor:-$interactive} java $DEBUG_OPTS -jar $JAR $scenario "$@" +stcColor=${stcColor:-$interactive} stcDumpLogs=${stcDumpLogs:-$notInteractive} \ + java $DEBUG_OPTS -jar $JAR $scenario "$@" # Reset the old value of ONOS_USE_SSH [ $sshSet ] && export ONOS_USE_SSH=oldSSH || unset ONOS_USE_SSH diff --git a/framework/src/onos/tools/test/scenarios/dist-test-seq.xml b/framework/src/onos/tools/test/scenarios/dist-test-seq.xml new file mode 100644 index 00000000..2e99fa27 --- /dev/null +++ b/framework/src/onos/tools/test/scenarios/dist-test-seq.xml @@ -0,0 +1,67 @@ +<!-- + ~ Copyright 20${OCI}5 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. + --> + +<scenario name="dist-test" + description="ONOS distributed primitives setup"> + <group name="Distributed-Primitives"> + <!--<import file="${ONOS_SCENARIOS}/prerequisites.xml"/>--> + + <!--<import file="${ONOS_SCENARIOS}/setup.xml"/> + <dependency name="Setup" requires="Prerequisites"/>--> + + <sequential var="${OC#}" starts="Distributed-App-${#}" ends="Check-Distributed-Exceptions-${#-1}"> + <step name="Distributed-App-${#}" + requires="Setup" + exec="onos ${OC#} app activate org.onosproject.distributedprimitives"/> + + <step name="Test-Counter-Increment-${#}" + requires="Distributed-App-${#}" + exec="onos-execute-expect ${OC#} counter-test-increment fooCounter 5 --expect updated"/> + + <step name="Test-Add-${#}" + requires="Distributed-App-${#}" + exec="onos-execute-expect ${OC#} set-test-add fooSet foo --expect added"/> + + <step name="Test-Get-${#}" + requires="Test-Add-${#}" + exec="onos-execute-expect ${OC#} set-test-get fooSet foo --expect contains"/> + + <step name="Test-Remove-${#}" + requires="Test-Get-${#}" + exec="onos-execute-expect ${OC#} set-test-remove fooSet foo --expect removed"/> + + <step name="Test-Add-Multiple-${#}" + requires="Test-Remove-${#}" + exec="onos-execute-expect ${OC#} set-test-add fooSet foo foo2 foo3 --expect added"/> + + <step name="Test-Get-Multiple-${#}" + requires="Test-Add-Multiple-${#}" + exec="onos-execute-expect ${OC#} set-test-get fooSet foo foo2 foo3 --expect contains"/> + + <step name="Test-Remove-Multiple-${#}" + requires="Test-Get-Multiple-${#}" + exec="onos-execute-expect ${OC#} set-test-remove fooSet foo foo2 foo3 --expect removed"/> + + <step name="Sleep-${#}" + exec="sleep 2" + requires="Test-Remove-Multiple-${#}"/> + <!--Check with check logs--> + <step name="Check-Distributed-Exceptions-${#}" + exec="onos-check-logs ${OC#}" + requires="Sleep-${#}"/> + </sequential> + </group> +</scenario>
\ No newline at end of file diff --git a/framework/src/onos/tools/test/scenarios/dist-test.xml b/framework/src/onos/tools/test/scenarios/dist-test.xml new file mode 100644 index 00000000..5e7dab0b --- /dev/null +++ b/framework/src/onos/tools/test/scenarios/dist-test.xml @@ -0,0 +1,70 @@ +<!-- + ~ 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. +--> + +<scenario name="dist-test" + description="ONOS distributed primitives setup"> + <group name="Distributed-Primitives"> + + <!--<import file="${ONOS_SCENARIOS}/setup.xml"/> + <dependency name="Setup" requires="Prerequisites"/>--> + + <step name="Distributed-App" + requires="Setup" + exec="onos ${OCI} app activate org.onosproject.distributedprimitives"/> + + <step name="Test-Counter-Increment" + requires="Distributed-App" + exec="onos-execute-expect ${OCI} counter-test-increment fooCounter 5 --expect updated"/> + + <step name="Test-Add" + requires="Distributed-App" + exec="onos-execute-expect ${OCI} set-test-add fooSet foo --expect added"/> + + <step name="Test-Get" + requires="Test-Add" + exec="onos-execute-expect ${OCI} set-test-get fooSet foo --expect contains"/> + + <step name="Test-Remove" + requires="Test-Get" + exec="onos-execute-expect ${OCI} set-test-remove fooSet foo --expect removed"/> + + <step name="Test-Add-Multiple" + requires="Test-Remove" + exec="onos-execute-expect ${OCI} set-test-add fooSet foo foo2 foo3 --expect added"/> + + <step name="Test-Get-Multiple" + requires="Test-Add-Multiple" + exec="onos-execute-expect ${OCI} set-test-get fooSet foo foo2 foo3 --expect contains"/> + + <step name="Test-Remove-Multiple" + requires="Test-Get-Multiple" + exec="onos-execute-expect ${OCI} set-test-remove fooSet foo foo2 foo3 --expect removed"/> + + <step name="Test-Map-Put" + requires="Distributed-App" + exec="onos-execute-expect ${OCI} transactional-map-test-put 1 foo --expect Created"/> + + <step name="Test-Map-Get" + requires="Test-Map-Put" + exec="onos-execute-expect ${OCI} transactional-map-test-get Key1 --expect Key-value"/> + + <!--Check with check logs--> + <step name="Check-Distributed-Exceptions" + exec="onos-check-logs ${OCI}" + requires="Test-Map-Get"/> + </group> +</scenario> + diff --git a/framework/src/onos/tools/test/topos/opticalUtils.py b/framework/src/onos/tools/test/topos/opticalUtils.py index a1ae834b..5d955e51 100644 --- a/framework/src/onos/tools/test/topos/opticalUtils.py +++ b/framework/src/onos/tools/test/topos/opticalUtils.py @@ -344,7 +344,10 @@ class LINCSwitch(OpticalSwitch): continue portDict = {} portDict[ 'port' ] = port - portDict[ 'type' ] = 'FIBER' if isinstance(intf.link, LINCLink) else 'COPPER' + portType = 'COPPER' + if isinstance(intf.link, LINCLink): + portType = 'OCH' if intf.link.isCrossConnect else 'OMS' + portDict[ 'type' ] = portType intfList = [ intf.link.intf1, intf.link.intf2 ] intfList.remove(intf) portDict[ 'speed' ] = intfList[ 0 ].speed if isinstance(intf.link, LINCLink) else 0 @@ -787,7 +790,10 @@ class LINCIntf(OpticalIntf): configDict = {} configDict[ 'port' ] = self.port configDict[ 'speed' ] = self.speed - configDict[ 'type' ] = 'FIBER' + portType = 'COPPER' + if isinstance(self.link, LINCLink): + portType = 'OCH' if self.link.isCrossConnect else 'OMS' + configDict[ 'type' ] = portType return configDict def config(self, *args, **kwargs): diff --git a/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/Ethernet.java b/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/Ethernet.java index 003c1772..9ab5cab1 100644 --- a/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/Ethernet.java +++ b/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/Ethernet.java @@ -18,6 +18,12 @@ package org.onlab.packet; +import org.onlab.packet.ndp.NeighborAdvertisement; +import org.onlab.packet.ndp.NeighborSolicitation; +import org.onlab.packet.ndp.Redirect; +import org.onlab.packet.ndp.RouterAdvertisement; +import org.onlab.packet.ndp.RouterSolicitation; + import java.nio.ByteBuffer; import java.util.Arrays; import java.util.HashMap; @@ -531,27 +537,114 @@ public class Ethernet extends BasePacket { sb.append("\nnw_proto: "); sb.append(p.getProtocol()); - if (pkt instanceof TCP) { - sb.append("\ntp_src: "); - sb.append(((TCP) pkt).getSourcePort()); - sb.append("\ntp_dst: "); - sb.append(((TCP) pkt).getDestinationPort()); - - } else if (pkt instanceof UDP) { - sb.append("\ntp_src: "); - sb.append(((UDP) pkt).getSourcePort()); - sb.append("\ntp_dst: "); - sb.append(((UDP) pkt).getDestinationPort()); + IPacket payload = pkt.getPayload(); + if (payload != null) { + if (payload instanceof TCP) { + sb.append("\ntp_src: "); + sb.append(((TCP) payload).getSourcePort()); + sb.append("\ntp_dst: "); + sb.append(((TCP) payload).getDestinationPort()); + + } else if (payload instanceof UDP) { + sb.append("\ntp_src: "); + sb.append(((UDP) payload).getSourcePort()); + sb.append("\ntp_dst: "); + sb.append(((UDP) payload).getDestinationPort()); + } else if (payload instanceof ICMP) { + final ICMP icmp = (ICMP) payload; + sb.append("\nicmp_type: "); + sb.append(icmp.getIcmpType()); + sb.append("\nicmp_code: "); + sb.append(icmp.getIcmpCode()); + } } - - if (pkt instanceof ICMP) { - final ICMP icmp = (ICMP) pkt; - sb.append("\nicmp_type: "); - sb.append(icmp.getIcmpType()); - sb.append("\nicmp_code: "); - sb.append(icmp.getIcmpCode()); + } else if (pkt instanceof IPv6) { + final IPv6 ipv6 = (IPv6) pkt; + sb.append("\nipv6_src: "); + sb.append(Ip6Address.valueOf(ipv6.getSourceAddress()).toString()); + sb.append("\nipv6_dst: "); + sb.append(Ip6Address.valueOf(ipv6.getDestinationAddress()).toString()); + sb.append("\nipv6_proto: "); + sb.append(ipv6.getNextHeader()); + + IPacket payload = pkt.getPayload(); + if (payload != null && payload instanceof ICMP6) { + final ICMP6 icmp6 = (ICMP6) payload; + sb.append("\nicmp6_type: "); + sb.append(icmp6.getIcmpType()); + sb.append("\nicmp6_code: "); + sb.append(icmp6.getIcmpCode()); + + payload = payload.getPayload(); + if (payload != null) { + if (payload instanceof NeighborSolicitation) { + final NeighborSolicitation ns = (NeighborSolicitation) payload; + sb.append("\nns_target_addr: "); + sb.append(Ip6Address.valueOf(ns.getTargetAddress()).toString()); + ns.getOptions().forEach(option -> { + sb.append("\noption_type: "); + sb.append(option.type()); + sb.append("\noption_data: "); + sb.append(bytesToHex(option.data())); + }); + } else if (payload instanceof NeighborAdvertisement) { + final NeighborAdvertisement na = (NeighborAdvertisement) payload; + sb.append("\nna_target_addr: "); + sb.append(Ip6Address.valueOf(na.getTargetAddress()).toString()); + sb.append("\nna_solicited_flag: "); + sb.append(na.getSolicitedFlag()); + sb.append("\nna_router_flag: "); + sb.append(na.getRouterFlag()); + sb.append("\nna_override_flag: "); + sb.append(na.getOverrideFlag()); + na.getOptions().forEach(option -> { + sb.append("\noption_type: "); + sb.append(option.type()); + sb.append("\noption_data: "); + sb.append(bytesToHex(option.data())); + }); + } else if (payload instanceof RouterSolicitation) { + final RouterSolicitation rs = (RouterSolicitation) payload; + sb.append("\nrs"); + rs.getOptions().forEach(option -> { + sb.append("\noption_type: "); + sb.append(option.type()); + sb.append("\noption_data: "); + sb.append(bytesToHex(option.data())); + }); + } else if (payload instanceof RouterAdvertisement) { + final RouterAdvertisement ra = (RouterAdvertisement) payload; + sb.append("\nra_hop_limit: "); + sb.append(ra.getCurrentHopLimit()); + sb.append("\nra_mflag: "); + sb.append(ra.getMFlag()); + sb.append("\nra_oflag: "); + sb.append(ra.getOFlag()); + sb.append("\nra_reachable_time: "); + sb.append(ra.getReachableTime()); + sb.append("\nra_retransmit_time: "); + sb.append(ra.getRetransmitTimer()); + sb.append("\nra_router_lifetime: "); + sb.append(ra.getRouterLifetime()); + ra.getOptions().forEach(option -> { + sb.append("\noption_type: "); + sb.append(option.type()); + sb.append("\noption_data: "); + sb.append(bytesToHex(option.data())); + }); + } else if (payload instanceof Redirect) { + final Redirect rd = (Redirect) payload; + sb.append("\nrd_target_addr: "); + sb.append(Ip6Address.valueOf(rd.getTargetAddress()).toString()); + rd.getOptions().forEach(option -> { + sb.append("\noption_type: "); + sb.append(option.type()); + sb.append("\noption_data: "); + sb.append(bytesToHex(option.data())); + }); + } + } } - } else if (pkt instanceof DHCP) { sb.append("\ndhcp packet"); } else if (pkt instanceof Data) { diff --git a/framework/src/onos/utils/misc/src/main/java/org/onlab/util/Bandwidth.java b/framework/src/onos/utils/misc/src/main/java/org/onlab/util/Bandwidth.java index 349e660f..60806568 100644 --- a/framework/src/onos/utils/misc/src/main/java/org/onlab/util/Bandwidth.java +++ b/framework/src/onos/utils/misc/src/main/java/org/onlab/util/Bandwidth.java @@ -42,6 +42,17 @@ public final class Bandwidth implements RichComparable<Bandwidth> { } /** + * Creates a new instance with given bandwidth. + * + * @param v bandwidth value + * @param unit {@link DataRateUnit} of {@code v} + * @return {@link Bandwidth} instance with given bandwidth + */ + public static Bandwidth of(double v, DataRateUnit unit) { + return new Bandwidth(unit.toBitsPerSecond(v)); + } + + /** * Creates a new instance with given bandwidth in bps. * * @param bps bandwidth value to be assigned diff --git a/framework/src/onos/utils/misc/src/main/java/org/onlab/util/DataRateUnit.java b/framework/src/onos/utils/misc/src/main/java/org/onlab/util/DataRateUnit.java new file mode 100644 index 00000000..d49ed7b5 --- /dev/null +++ b/framework/src/onos/utils/misc/src/main/java/org/onlab/util/DataRateUnit.java @@ -0,0 +1,64 @@ +package org.onlab.util; + +import com.google.common.annotations.Beta; + +/** + * Data rate unit. + */ +@Beta +public enum DataRateUnit { + /** + * Bit per second. + */ + BPS(1L), + /** + * Kilobit per second. + * (Decimal/SI) + */ + KBPS(1_000L), + /** + * Megabit per second. + * (Decimal/SI) + */ + MBPS(1_000_000L), + /** + * Gigabit per second. + * (Decimal/SI) + */ + GBPS(1_000_000_000L); + + private final long multiplier; + + DataRateUnit(long multiplier) { + this.multiplier = multiplier; + } + + /** + * Returns the multiplier to use, when converting value of this unit to bps. + * + * @return multiplier + */ + public long multiplier() { + return multiplier; + } + + /** + * Converts given value in this unit to bits per seconds. + * + * @param v data rate value + * @return {@code v} in bits per seconds + */ + public long toBitsPerSecond(long v) { + return v * multiplier; + } + + /** + * Converts given value in this unit to bits per seconds. + * + * @param v data rate value + * @return {@code v} in bits per seconds + */ + public double toBitsPerSecond(double v) { + return v * multiplier; + } +} diff --git a/framework/src/onos/utils/misc/src/test/java/org/onlab/util/AbstractAccumulatorTest.java b/framework/src/onos/utils/misc/src/test/java/org/onlab/util/AbstractAccumulatorTest.java index db7224ad..8a409c3d 100644 --- a/framework/src/onos/utils/misc/src/test/java/org/onlab/util/AbstractAccumulatorTest.java +++ b/framework/src/onos/utils/misc/src/test/java/org/onlab/util/AbstractAccumulatorTest.java @@ -31,7 +31,10 @@ import static org.onlab.junit.TestTools.assertAfter; public class AbstractAccumulatorTest { - private final ManuallyAdvancingTimer timer = new ManuallyAdvancingTimer(); + private final ManuallyAdvancingTimer timer = new ManuallyAdvancingTimer(true); + + private static final int LONG_REAL_TIME_DELAY = 30; + private static final int SHORT_REAL_TIME_DELAY = 5; @Test @@ -52,7 +55,7 @@ public class AbstractAccumulatorTest { accumulator.add(new TestItem("d")); assertTrue("should not have fired yet", accumulator.batch.isEmpty()); accumulator.add(new TestItem("e")); - timer.advanceTimeMillis(20, 10); + timer.advanceTimeMillis(20, LONG_REAL_TIME_DELAY); assertFalse("should have fired", accumulator.batch.isEmpty()); assertEquals("incorrect batch", "abcde", accumulator.batch); } @@ -61,16 +64,16 @@ public class AbstractAccumulatorTest { public void timeTrigger() { TestAccumulator accumulator = new TestAccumulator(); accumulator.add(new TestItem("a")); - timer.advanceTimeMillis(30, 1); + timer.advanceTimeMillis(30, SHORT_REAL_TIME_DELAY); assertTrue("should not have fired yet", accumulator.batch.isEmpty()); accumulator.add(new TestItem("b")); - timer.advanceTimeMillis(30, 1); + timer.advanceTimeMillis(30, SHORT_REAL_TIME_DELAY); assertTrue("should not have fired yet", accumulator.batch.isEmpty()); accumulator.add(new TestItem("c")); - timer.advanceTimeMillis(30, 1); + timer.advanceTimeMillis(30, SHORT_REAL_TIME_DELAY); assertTrue("should not have fired yet", accumulator.batch.isEmpty()); accumulator.add(new TestItem("d")); - timer.advanceTimeMillis(10, 10); + timer.advanceTimeMillis(10, LONG_REAL_TIME_DELAY); assertFalse("should have fired", accumulator.batch.isEmpty()); assertEquals("incorrect batch", "abcd", accumulator.batch); } @@ -81,7 +84,7 @@ public class AbstractAccumulatorTest { accumulator.add(new TestItem("a")); assertTrue("should not have fired yet", accumulator.batch.isEmpty()); accumulator.add(new TestItem("b")); - timer.advanceTimeMillis(70, 10); + timer.advanceTimeMillis(70, LONG_REAL_TIME_DELAY); assertFalse("should have fired", accumulator.batch.isEmpty()); assertEquals("incorrect batch", "ab", accumulator.batch); } @@ -93,10 +96,10 @@ public class AbstractAccumulatorTest { accumulator.add(new TestItem("a")); assertTrue("should not have fired yet", accumulator.batch.isEmpty()); accumulator.add(new TestItem("b")); - timer.advanceTimeMillis(80, 1); + timer.advanceTimeMillis(80, SHORT_REAL_TIME_DELAY); assertTrue("should not have fired yet", accumulator.batch.isEmpty()); accumulator.ready = true; - timer.advanceTimeMillis(80, 10); + timer.advanceTimeMillis(80, LONG_REAL_TIME_DELAY); assertFalse("should have fired", accumulator.batch.isEmpty()); assertEquals("incorrect batch", "ab", accumulator.batch); } @@ -105,12 +108,12 @@ public class AbstractAccumulatorTest { public void readyLongTrigger() { TestAccumulator accumulator = new TestAccumulator(); accumulator.ready = false; - timer.advanceTimeMillis(120, 1); + timer.advanceTimeMillis(120, SHORT_REAL_TIME_DELAY); assertTrue("should not have fired yet", accumulator.batch.isEmpty()); accumulator.add(new TestItem("a")); assertTrue("should not have fired yet", accumulator.batch.isEmpty()); accumulator.ready = true; - timer.advanceTimeMillis(120, 10); + timer.advanceTimeMillis(120, LONG_REAL_TIME_DELAY); assertFalse("should have fired", accumulator.batch.isEmpty()); assertEquals("incorrect batch", "a", accumulator.batch); } @@ -128,7 +131,7 @@ public class AbstractAccumulatorTest { assertTrue("should not have fired yet", accumulator.batch.isEmpty()); accumulator.ready = true; accumulator.add(new TestItem("g")); - timer.advanceTimeMillis(10, 10); + timer.advanceTimeMillis(10, LONG_REAL_TIME_DELAY); assertFalse("should have fired", accumulator.batch.isEmpty()); assertEquals("incorrect batch", "abcdefg", accumulator.batch); } diff --git a/framework/src/onos/utils/misc/src/test/java/org/onlab/util/ManuallyAdvancingTimer.java b/framework/src/onos/utils/misc/src/test/java/org/onlab/util/ManuallyAdvancingTimer.java index 4116cbef..8fb008e8 100644 --- a/framework/src/onos/utils/misc/src/test/java/org/onlab/util/ManuallyAdvancingTimer.java +++ b/framework/src/onos/utils/misc/src/test/java/org/onlab/util/ManuallyAdvancingTimer.java @@ -65,6 +65,14 @@ public class ManuallyAdvancingTimer extends java.util.Timer { /* Data structure for tracking tasks */ private final TaskQueue queue = new TaskQueue(); + /* Whether execution should execute on the executor thread or the calling thread. */ + private final boolean runLocally; + + public ManuallyAdvancingTimer(boolean runLocally) { + this.runLocally = runLocally; + } + + @Override public void schedule(TimerTask task, long delay) { if (!staticsPopulated) { @@ -165,14 +173,16 @@ public class ManuallyAdvancingTimer extends java.util.Timer { /** * Advances the virtual time a certain number of millis triggers execution delays a certain amount to - * allow time for execution. + * allow time for execution. If runLocally is true then all real time delays are ignored. * * @param virtualTimeAdvance the time to be advances in millis of simulated time. * @param realTimeDelay the time to delay in real time to allow for processing. */ public void advanceTimeMillis(long virtualTimeAdvance, int realTimeDelay) { timerKeeper.advanceTimeMillis(virtualTimeAdvance); - delay(realTimeDelay); + if (!runLocally) { + delay(realTimeDelay); + } } /** @@ -238,7 +248,11 @@ public class ManuallyAdvancingTimer extends java.util.Timer { e.printStackTrace(); return false; } - executorService.execute(task); + if (runLocally) { + task.run(); + } else { + executorService.execute(task); + } return true; } else { //Calculate next execution time, using absolute value of period @@ -253,7 +267,11 @@ public class ManuallyAdvancingTimer extends java.util.Timer { } //Schedule next execution queue.insertOrdered(task); - executorService.execute(task); + if (runLocally) { + task.run(); + } else { + executorService.execute(task); + } return true; } } diff --git a/framework/src/onos/utils/misc/src/test/java/org/onlab/util/ManuallyAdvancingTimerTest.java b/framework/src/onos/utils/misc/src/test/java/org/onlab/util/ManuallyAdvancingTimerTest.java index b8e1e85e..36b50e67 100644 --- a/framework/src/onos/utils/misc/src/test/java/org/onlab/util/ManuallyAdvancingTimerTest.java +++ b/framework/src/onos/utils/misc/src/test/java/org/onlab/util/ManuallyAdvancingTimerTest.java @@ -47,14 +47,14 @@ public class ManuallyAdvancingTimerTest { private AtomicInteger tasksRunCount; // FIXME if this class fails first try increasing the real time delay to account for heavy system load. - private static final int REAL_TIME_DELAY = 1; + private static final int REAL_TIME_DELAY = 10; /** * Sets up the testing environment. */ @Before public void setup() { - timer = new ManuallyAdvancingTimer(); + timer = new ManuallyAdvancingTimer(true); idGenerator = new AtomicInteger(1); tasksRunCount = new AtomicInteger(0); taskList = Lists.newArrayList(); diff --git a/framework/src/onos/utils/stc/src/main/java/org/onlab/stc/Main.java b/framework/src/onos/utils/stc/src/main/java/org/onlab/stc/Main.java index bc10ec7a..ca04a7c2 100644 --- a/framework/src/onos/utils/stc/src/main/java/org/onlab/stc/Main.java +++ b/framework/src/onos/utils/stc/src/main/java/org/onlab/stc/Main.java @@ -16,13 +16,16 @@ package org.onlab.stc; import com.google.common.collect.ImmutableList; +import com.google.common.io.Files; import org.eclipse.jetty.server.Server; import org.eclipse.jetty.servlet.ServletHandler; import org.eclipse.jetty.util.log.Logger; import org.onlab.stc.Coordinator.Status; +import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; +import java.io.IOException; import java.text.SimpleDateFormat; import java.util.Date; import java.util.List; @@ -64,10 +67,12 @@ public final class Main { private String runToPatterns = ""; private Coordinator coordinator; + private Compiler compiler; private Monitor monitor; private Listener delegate = new Listener(); private static boolean useColor = Objects.equals("true", System.getenv("stcColor")); + private static boolean dumpLogs = Objects.equals("true", System.getenv("stcDumpLogs")); // usage: stc [<scenario-file>] [run] // usage: stc [<scenario-file>] run [from <from-patterns>] [to <to-patterns>]] @@ -113,7 +118,7 @@ public final class Main { Scenario scenario = Scenario.loadScenario(new FileInputStream(scenarioFile)); // Elaborate scenario - Compiler compiler = new Compiler(scenario); + compiler = new Compiler(scenario); compiler.compile(); // Setup the process flow coordinator @@ -221,7 +226,7 @@ public final class Main { /** * Internal delegate to monitor the process execution. */ - private static class Listener implements StepProcessListener { + private class Listener implements StepProcessListener { @Override public void onStart(Step step, String command) { logStatus(currentTimeMillis(), step.name(), IN_PROGRESS, command); @@ -230,6 +235,9 @@ public final class Main { @Override public void onCompletion(Step step, Status status) { logStatus(currentTimeMillis(), step.name(), status, null); + if (dumpLogs && !(step instanceof Group) && status == FAILED) { + dumpLogs(step); + } } @Override @@ -246,6 +254,18 @@ public final class Main { } } + // Dumps the step logs to standard output. + private void dumpLogs(Step step) { + File logFile = new File(compiler.logDir(), step.name() + ".log"); + try { + print(">>>>>"); + Files.copy(logFile, System.out); + print("<<<<<"); + } catch (IOException e) { + print("Unable to dump log file %s", logFile.getName()); + } + } + // Produces a description of event using the specified step status. private static String action(Status status) { return status == IN_PROGRESS ? "started" : diff --git a/framework/src/onos/web/api/src/main/java/org/onosproject/rest/resources/ClusterWebResource.java b/framework/src/onos/web/api/src/main/java/org/onosproject/rest/resources/ClusterWebResource.java index dd9b9fc3..312f6e35 100644 --- a/framework/src/onos/web/api/src/main/java/org/onosproject/rest/resources/ClusterWebResource.java +++ b/framework/src/onos/web/api/src/main/java/org/onosproject/rest/resources/ClusterWebResource.java @@ -84,10 +84,9 @@ public class ClusterWebResource extends AbstractWebResource { public Response formCluster(InputStream config) throws IOException { JsonCodec<ControllerNode> codec = codec(ControllerNode.class); ObjectNode root = (ObjectNode) mapper().readTree(config); - String ipPrefix = root.path("ipPrefix").asText(); List<ControllerNode> nodes = codec.decode((ArrayNode) root.path("nodes"), this); - get(ClusterAdminService.class).formCluster(new HashSet<>(nodes), ipPrefix); + get(ClusterAdminService.class).formCluster(new HashSet<>(nodes)); return Response.ok().build(); } diff --git a/framework/src/onos/web/gui/src/main/java/org/onosproject/ui/impl/TopologyViewMessageHandler.java b/framework/src/onos/web/gui/src/main/java/org/onosproject/ui/impl/TopologyViewMessageHandler.java index 8acdc2cf..82b7a782 100644 --- a/framework/src/onos/web/gui/src/main/java/org/onosproject/ui/impl/TopologyViewMessageHandler.java +++ b/framework/src/onos/web/gui/src/main/java/org/onosproject/ui/impl/TopologyViewMessageHandler.java @@ -27,12 +27,14 @@ import org.onosproject.cluster.ClusterEventListener; import org.onosproject.cluster.ControllerNode; import org.onosproject.core.ApplicationId; import org.onosproject.core.CoreService; +import org.onosproject.core.DefaultApplicationId; import org.onosproject.event.Event; import org.onosproject.mastership.MastershipAdminService; import org.onosproject.mastership.MastershipEvent; import org.onosproject.mastership.MastershipListener; import org.onosproject.net.ConnectPoint; import org.onosproject.net.Device; +import org.onosproject.net.DeviceId; import org.onosproject.net.Host; import org.onosproject.net.HostId; import org.onosproject.net.HostLocation; @@ -48,11 +50,14 @@ import org.onosproject.net.flow.TrafficTreatment; import org.onosproject.net.host.HostEvent; import org.onosproject.net.host.HostListener; import org.onosproject.net.intent.HostToHostIntent; +import org.onosproject.net.intent.Intent; import org.onosproject.net.intent.IntentEvent; import org.onosproject.net.intent.IntentListener; +import org.onosproject.net.intent.Key; import org.onosproject.net.intent.MultiPointToSinglePointIntent; import org.onosproject.net.link.LinkEvent; import org.onosproject.net.link.LinkListener; +import org.onosproject.ui.JsonUtils; import org.onosproject.ui.RequestHandler; import org.onosproject.ui.UiConnection; import org.onosproject.ui.impl.TrafficMonitor.Mode; @@ -76,7 +81,9 @@ import static org.onlab.util.Tools.groupedThreads; import static org.onosproject.cluster.ClusterEvent.Type.INSTANCE_ADDED; import static org.onosproject.net.DeviceId.deviceId; import static org.onosproject.net.HostId.hostId; -import static org.onosproject.net.device.DeviceEvent.Type.*; +import static org.onosproject.net.device.DeviceEvent.Type.DEVICE_ADDED; +import static org.onosproject.net.device.DeviceEvent.Type.DEVICE_UPDATED; +import static org.onosproject.net.device.DeviceEvent.Type.PORT_STATS_UPDATED; import static org.onosproject.net.host.HostEvent.Type.HOST_ADDED; import static org.onosproject.net.link.LinkEvent.Type.LINK_ADDED; import static org.onosproject.ui.JsonUtils.envelope; @@ -97,6 +104,7 @@ public class TopologyViewMessageHandler extends TopologyViewMessageHandlerBase { private static final String REQ_NEXT_INTENT = "requestNextRelatedIntent"; private static final String REQ_PREV_INTENT = "requestPrevRelatedIntent"; private static final String REQ_SEL_INTENT_TRAFFIC = "requestSelectedIntentTraffic"; + private static final String SEL_INTENT = "selectIntent"; private static final String REQ_ALL_FLOW_TRAFFIC = "requestAllFlowTraffic"; private static final String REQ_ALL_PORT_TRAFFIC = "requestAllPortTraffic"; private static final String REQ_DEV_LINK_FLOWS = "requestDeviceLinkFlows"; @@ -117,9 +125,13 @@ public class TopologyViewMessageHandler extends TopologyViewMessageHandlerBase { private static final String SPRITE_LIST_RESPONSE = "spriteListResponse"; private static final String SPRITE_DATA_RESPONSE = "spriteDataResponse"; private static final String UPDATE_INSTANCE = "updateInstance"; + private static final String TOPO_START_DONE = "topoStartDone"; // fields private static final String ID = "id"; + private static final String KEY = "key"; + private static final String APP_ID = "appId"; + private static final String APP_NAME = "appName"; private static final String DEVICE = "device"; private static final String HOST = "host"; private static final String CLASS = "class"; @@ -135,7 +147,7 @@ public class TopologyViewMessageHandler extends TopologyViewMessageHandlerBase { private static final String DEACTIVATE = "deactivate"; - private static final String APP_ID = "org.onosproject.gui"; + private static final String MY_APP_ID = "org.onosproject.gui"; private static final long TRAFFIC_PERIOD = 5000; private static final long SUMMARY_PERIOD = 30000; @@ -176,7 +188,7 @@ public class TopologyViewMessageHandler extends TopologyViewMessageHandlerBase { @Override public void init(UiConnection connection, ServiceDirectory directory) { super.init(connection, directory); - appId = directory.get(CoreService.class).registerApplication(APP_ID); + appId = directory.get(CoreService.class).registerApplication(MY_APP_ID); traffic = new TrafficMonitor(TRAFFIC_PERIOD, servicesBundle, this); } @@ -213,6 +225,7 @@ public class TopologyViewMessageHandler extends TopologyViewMessageHandlerBase { new ReqNextIntent(), new ReqPrevIntent(), new ReqSelectedIntentTraffic(), + new SelIntent(), new CancelTraffic() ); @@ -241,6 +254,7 @@ public class TopologyViewMessageHandler extends TopologyViewMessageHandlerBase { sendAllDevices(); sendAllLinks(); sendAllHosts(); + sendTopoStartDone(); } } @@ -344,11 +358,13 @@ public class TopologyViewMessageHandler extends TopologyViewMessageHandlerBase { PropertyPanel pp = null; if (type.equals(DEVICE)) { - pp = deviceDetails(deviceId(id), sid); - overlayCache.currentOverlay().modifyDeviceDetails(pp); + DeviceId did = deviceId(id); + pp = deviceDetails(did, sid); + overlayCache.currentOverlay().modifyDeviceDetails(pp, did); } else if (type.equals(HOST)) { - pp = hostDetails(hostId(id), sid); - overlayCache.currentOverlay().modifyHostDetails(pp); + HostId hid = hostId(id); + pp = hostDetails(hid, sid); + overlayCache.currentOverlay().modifyHostDetails(pp, hid); } sendMessage(envelope(SHOW_DETAILS, sid, json(pp))); @@ -524,6 +540,31 @@ public class TopologyViewMessageHandler extends TopologyViewMessageHandlerBase { } } + private final class SelIntent extends RequestHandler { + private SelIntent() { + super(SEL_INTENT); + } + + @Override + public void process(long sid, ObjectNode payload) { + int appId = Integer.parseInt(string(payload, APP_ID)); + String appName = string(payload, APP_NAME); + ApplicationId applicId = new DefaultApplicationId(appId, appName); + long intentKey = Long.decode(string(payload, KEY)); + + Key key = Key.of(intentKey, applicId); + log.debug("Attempting to select intent key={}", key); + + Intent intent = intentService.getIntent(key); + if (intent == null) { + log.debug("no such intent found!"); + } else { + log.debug("starting to monitor intent {}", key); + traffic.monitor(intent); + } + } + } + private final class CancelTraffic extends RequestHandler { private CancelTraffic() { super(CANCEL_TRAFFIC); @@ -623,6 +664,9 @@ public class TopologyViewMessageHandler extends TopologyViewMessageHandlerBase { return hostIds; } + private void sendTopoStartDone() { + sendMessage(JsonUtils.envelope(TOPO_START_DONE, objectNode())); + } private synchronized void startSummaryMonitoring() { stopSummaryMonitoring(); diff --git a/framework/src/onos/web/gui/src/main/java/org/onosproject/ui/impl/TrafficOverlay.java b/framework/src/onos/web/gui/src/main/java/org/onosproject/ui/impl/TrafficOverlay.java index ea8ca3ea..f4b5598d 100644 --- a/framework/src/onos/web/gui/src/main/java/org/onosproject/ui/impl/TrafficOverlay.java +++ b/framework/src/onos/web/gui/src/main/java/org/onosproject/ui/impl/TrafficOverlay.java @@ -17,6 +17,7 @@ package org.onosproject.ui.impl; +import org.onosproject.net.DeviceId; import org.onosproject.ui.UiTopoOverlay; import org.onosproject.ui.topo.ButtonId; import org.onosproject.ui.topo.PropertyPanel; @@ -55,7 +56,7 @@ public class TrafficOverlay extends UiTopoOverlay { } @Override - public void modifyDeviceDetails(PropertyPanel pp) { + public void modifyDeviceDetails(PropertyPanel pp, DeviceId deviceId) { pp.addButton(SHOW_DEVICE_FLOWS) .addButton(SHOW_RELATED_TRAFFIC); } diff --git a/framework/src/onos/web/gui/src/main/webapp/app/fw/layer/panel.css b/framework/src/onos/web/gui/src/main/webapp/app/fw/layer/panel.css index 46dbdb52..ded05cf1 100644 --- a/framework/src/onos/web/gui/src/main/webapp/app/fw/layer/panel.css +++ b/framework/src/onos/web/gui/src/main/webapp/app/fw/layer/panel.css @@ -34,6 +34,10 @@ border-radius: 6px; } +.floatpanel.dialog { + top: 180px; +} + html[data-platform='iPad'] .floatpanel { top: 80px; } diff --git a/framework/src/onos/web/gui/src/main/webapp/app/fw/layer/panel.js b/framework/src/onos/web/gui/src/main/webapp/app/fw/layer/panel.js index aef71eee..10f04813 100644 --- a/framework/src/onos/web/gui/src/main/webapp/app/fw/layer/panel.js +++ b/framework/src/onos/web/gui/src/main/webapp/app/fw/layer/panel.js @@ -171,7 +171,10 @@ } angular.module('onosLayer') - .factory('PanelService', ['$log', 'FnService', function (_$log_, _fs_) { + .factory('PanelService', + ['$log', '$window', 'FnService', + + function (_$log_, _$window_, _fs_) { $log = _$log_; fs = _fs_; @@ -210,5 +213,4 @@ destroyPanel: destroyPanel }; }]); - }()); diff --git a/framework/src/onos/web/gui/src/main/webapp/app/fw/svg/icon.js b/framework/src/onos/web/gui/src/main/webapp/app/fw/svg/icon.js index 15b44bc9..12536361 100644 --- a/framework/src/onos/web/gui/src/main/webapp/app/fw/svg/icon.js +++ b/framework/src/onos/web/gui/src/main/webapp/app/fw/svg/icon.js @@ -37,6 +37,8 @@ play: 'play', stop: 'stop', + topo: 'topo', + refresh: 'refresh', garbage: 'garbage', diff --git a/framework/src/onos/web/gui/src/main/webapp/app/fw/widget/table.css b/framework/src/onos/web/gui/src/main/webapp/app/fw/widget/table.css index 18b81ba6..356ac0f7 100644 --- a/framework/src/onos/web/gui/src/main/webapp/app/fw/widget/table.css +++ b/framework/src/onos/web/gui/src/main/webapp/app/fw/widget/table.css @@ -81,7 +81,7 @@ div.summary-list tr.no-data td { } .light div.summary-list tr.selected { - background-color: deepskyblue; + background-color: deepskyblue !important; } .dark div.summary-list tr.selected { diff --git a/framework/src/onos/web/gui/src/main/webapp/app/fw/widget/tableBuilder.js b/framework/src/onos/web/gui/src/main/webapp/app/fw/widget/tableBuilder.js index 24161bbb..6a5ffb1f 100644 --- a/framework/src/onos/web/gui/src/main/webapp/app/fw/widget/tableBuilder.js +++ b/framework/src/onos/web/gui/src/main/webapp/app/fw/widget/tableBuilder.js @@ -47,6 +47,7 @@ resp = o.tag + 'DataResponse', onSel = fs.isF(o.selCb), onResp = fs.isF(o.respCb), + idKey = o.idKey || 'id', oldTableData = [], loaded = false, refreshPromise, loadingPromise; @@ -104,7 +105,8 @@ // === selecting a row functions ---------------- function selCb($event, selRow) { - o.scope.selId = (o.scope.selId === selRow.id) ? null : selRow.id; + var selId = selRow[idKey]; + o.scope.selId = (o.scope.selId === selId) ? null : selId; onSel && onSel($event, selRow); } o.scope.selectCallback = selCb; diff --git a/framework/src/onos/web/gui/src/main/webapp/app/view/intent/intent.css b/framework/src/onos/web/gui/src/main/webapp/app/view/intent/intent.css index ed9cd48d..dfa50c37 100644 --- a/framework/src/onos/web/gui/src/main/webapp/app/view/intent/intent.css +++ b/framework/src/onos/web/gui/src/main/webapp/app/view/intent/intent.css @@ -23,7 +23,6 @@ } #ov-intent div.ctrl-btns { - width: 45px; } .light #ov-intent tr:nth-child(6n + 1), diff --git a/framework/src/onos/web/gui/src/main/webapp/app/view/intent/intent.html b/framework/src/onos/web/gui/src/main/webapp/app/view/intent/intent.html index 4883beed..98aa5659 100644 --- a/framework/src/onos/web/gui/src/main/webapp/app/view/intent/intent.html +++ b/framework/src/onos/web/gui/src/main/webapp/app/view/intent/intent.html @@ -1,24 +1,13 @@ -<!-- - ~ 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. - --> - <!-- Intent partial HTML --> <div id="ov-intent"> <div class="tabular-header"> <h2>Intents ({{tableData.length}} total)</h2> <div class="ctrl-btns"> + <div ng-class="{active: !!selId}" + icon icon-id="topo" icon-size="36" + tooltip tt-msg="topoTip" + ng-click="showIntent()"></div> + <div class="separator"></div> <div class="refresh" ng-class="{active: autoRefresh}" icon icon-size="36" icon-id="refresh" tooltip tt-msg="autoRefreshTip" @@ -51,6 +40,8 @@ </tr> <tr ng-repeat-start="intent in tableData track by $index" + ng-click="selectCallback($event, intent)" + ng-class="{selected: intent.key === selId}" ng-repeat-complete row-id="{{intent.key}}"> <td>{{intent.appId}}</td> <td>{{intent.key}}</td> @@ -58,10 +49,14 @@ <td>{{intent.priority}}</td> <td>{{intent.state}}</td> </tr> - <tr row-id="{{intent.key}}"> + <tr ng-click="selectCallback($event, intent)" + ng-class="{selected: intent.key === selId}" + row-id="{{intent.key}}"> <td class="resources" colspan="5">{{intent.resources}}</td> </tr> - <tr row-id="{{intent.key}}" ng-repeat-end> + <tr ng-click="selectCallback($event, intent)" + ng-class="{selected: intent.key === selId}" + row-id="{{intent.key}}" ng-repeat-end> <td class="details" colspan="5">{{intent.details}}</td> </tr> </table> diff --git a/framework/src/onos/web/gui/src/main/webapp/app/view/intent/intent.js b/framework/src/onos/web/gui/src/main/webapp/app/view/intent/intent.js index 5810f347..19f2c076 100644 --- a/framework/src/onos/web/gui/src/main/webapp/app/view/intent/intent.js +++ b/framework/src/onos/web/gui/src/main/webapp/app/view/intent/intent.js @@ -23,14 +23,37 @@ angular.module('ovIntent', []) .controller('OvIntentCtrl', - ['$log', '$scope', 'TableBuilderService', + ['$log', '$scope', 'TableBuilderService', 'NavService', - function ($log, $scope, tbs) { - tbs.buildTable({ - scope: $scope, - tag: 'intent' - }); + function ($log, $scope, tbs, ns) { - $log.log('OvIntentCtrl has been created'); - }]); + function selCb($event, row) { + $log.debug('Got a click on:', row); + var m = /(\d+)\s:\s(.*)/.exec(row.appId), + id = m ? m[1] : null, + name = m ? m[2] : null; + + $scope.intentData = ($scope.selId && m) ? { + intentAppId: id, + intentAppName: name, + intentKey: row.key + } : null; + } + + tbs.buildTable({ + scope: $scope, + tag: 'intent', + selCb: selCb, + idKey: 'key' + }); + + $scope.topoTip = 'Show selected intent on topology view'; + + $scope.showIntent = function () { + var d = $scope.intentData; + d && ns.navTo('topo', d); + }; + + $log.log('OvIntentCtrl has been created'); + }]); }()); diff --git a/framework/src/onos/web/gui/src/main/webapp/app/view/topo/topo.css b/framework/src/onos/web/gui/src/main/webapp/app/view/topo/topo.css index f4b089a0..dda6d5c6 100644 --- a/framework/src/onos/web/gui/src/main/webapp/app/view/topo/topo.css +++ b/framework/src/onos/web/gui/src/main/webapp/app/view/topo/topo.css @@ -96,6 +96,24 @@ html[data-platform='iPad'] #topo-p-detail { height: 30px; } +/* --- Topo Dialog Panel --- */ + +#topo-p-dialog .dialog-button { + display: inline-block; + cursor: pointer; + height: 20px; + padding: 2px 6px; + margin: 4px; + float: right; +} + +.light #topo-p-dialog .dialog-button { + background-color: #fec; +} +.dark #topo-p-dialog .dialog-button { + background-color: #369; +} + /* --- general topo-panel styling --- */ .topo-p div.header div.icon { @@ -427,6 +445,39 @@ html[data-platform='iPad'] #topo-p-detail { fill: #f90; } +/* Badges */ +/* (... works for both light and dark themes...) */ +#ov-topo svg .node .badge circle { + stroke: #aaa; +} + +#ov-topo svg .node .badge.badgeInfo circle { + fill: #ccf; +} + +#ov-topo svg .node .badge.badgeWarn circle { + fill: #da2; +} + +#ov-topo svg .node .badge.badgeError circle { + fill: #e44; +} + +#ov-topo svg .node .badge use { + fill: white; +} + +#ov-topo svg .node .badge.badgeInfo use { + fill: #448; +} + +#ov-topo svg .node .badge text { + fill: white; +} + +#ov-topo svg .node .badge.badgeInfo text { + fill: #448; +} /* Host Nodes */ diff --git a/framework/src/onos/web/gui/src/main/webapp/app/view/topo/topo.js b/framework/src/onos/web/gui/src/main/webapp/app/view/topo/topo.js index 0dfd6281..7ddfd136 100644 --- a/framework/src/onos/web/gui/src/main/webapp/app/view/topo/topo.js +++ b/framework/src/onos/web/gui/src/main/webapp/app/view/topo/topo.js @@ -412,6 +412,12 @@ flash.enable(true); } + function topoStartDone() { + var d = $scope.intentData; + if (d) { + tts.selectIntent(d); + } + } // --- Controller Definition ----------------------------------------- @@ -430,7 +436,8 @@ _zs_, _gs_, _ms_, _sus_, _flash_, _wss_, _ps_, _tes_, _tfs_, _tps_, _tis_, _tss_, _tls_, _tts_, _tos_, _fltr_, _ttbs_, tspr, _ttip_, _tov_) { - var projection, + var params = $loc.search(), + projection, dim, uplink = { // provides function calls back into this space @@ -438,7 +445,8 @@ projection: function () { return projection; }, zoomLayer: function () { return zoomLayer; }, zoomer: function () { return zoomer; }, - opacifyMap: opacifyMap + opacifyMap: opacifyMap, + topoStartDone: topoStartDone }; $scope = _$scope_; @@ -469,6 +477,14 @@ ttip = _ttip_; tov = _tov_; + if (params.intentKey && params.intentAppId && params.intentAppName) { + $scope.intentData = { + key: params.intentKey, + appId: params.intentAppId, + appName: params.intentAppName + }; + } + $scope.notifyResize = function () { svgResized(fs.windowSize(mast.mastHeight())); }; diff --git a/framework/src/onos/web/gui/src/main/webapp/app/view/topo/topoD3.js b/framework/src/onos/web/gui/src/main/webapp/app/view/topo/topoD3.js index 1f061dd6..1d2c5b10 100644 --- a/framework/src/onos/web/gui/src/main/webapp/app/view/topo/topoD3.js +++ b/framework/src/onos/web/gui/src/main/webapp/app/view/topo/topoD3.js @@ -55,8 +55,23 @@ height: 14 } }, + badgeConfig = { + radius: 12, + yoff: 5, + gdelta: 10 + }, icfg; + var status = { + i: 'badgeInfo', + w: 'badgeWarn', + e: 'badgeError' + }; + + function badgeStatus(badge) { + return status[badge.status] || status.i; + } + // internal state var deviceLabelIndex = 0, hostLabelIndex = 0; @@ -186,12 +201,15 @@ } - function updateDeviceLabel(d) { + function updateDeviceRendering(d) { var label = trimLabel(deviceLabel(d)), noLabel = !label, node = d.el, dim = icfg.device.dim, - box, dx, dy; + box, dx, dy, bsel, + bdg = d.badge, + bcr = badgeConfig.radius, + bcgd = badgeConfig.gdelta; node.select('text') .text(label) @@ -216,23 +234,34 @@ node.select('g.deviceIcon') .transition() .attr('transform', sus.translate(dx, dy)); - } - function updateDeviceBadge(d) { - // TODO: Fix this WIP - var node = d.el, - bsel; + // handle badge, if defined + if (bdg) { + node.select('g.badge').remove(); - if (d.badge) { bsel = node.append('g') .classed('badge', true) - .attr('transform', sus.translate(-14, -14)); + .classed(badgeStatus(bdg), true) + .attr('transform', sus.translate(dx + dim, dy)); bsel.append('circle') - .attr('r', 14); - bsel.append('text') - .attr('transform', sus.translate(-5, 3)) - .text('42'); + .attr('r', bcr); + + if (bdg.txt) { + bsel.append('text') + .attr('dy', badgeConfig.yoff) + .attr('text-anchor', 'middle') + .text(bdg.txt); + } else if (bdg.gid) { + bsel.append('use') + .attr({ + width: bcgd * 2, + height: bcgd * 2, + transform: sus.translate(-bcgd, -bcgd), + 'xlink:href': '#' + bdg.gid + }); + + } } } @@ -258,8 +287,7 @@ function deviceExisting(d) { var node = d.el; node.classed('online', d.online); - updateDeviceLabel(d); - updateDeviceBadge(d); + updateDeviceRendering(d); api.posNode(d, true); } @@ -574,7 +602,7 @@ deviceLabel: deviceLabel, trimLabel: trimLabel, - updateDeviceLabel: updateDeviceLabel, + updateDeviceLabel: updateDeviceRendering, updateHostLabel: updateHostLabel, updateDeviceColors: updateDeviceColors, diff --git a/framework/src/onos/web/gui/src/main/webapp/app/view/topo/topoDialog.js b/framework/src/onos/web/gui/src/main/webapp/app/view/topo/topoDialog.js new file mode 100644 index 00000000..93079183 --- /dev/null +++ b/framework/src/onos/web/gui/src/main/webapp/app/view/topo/topoDialog.js @@ -0,0 +1,183 @@ +/* + * 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. + */ + +/* + ONOS GUI -- Topology Dialog Module. + Defines functions for manipulating a dialog box. + */ + +(function () { + 'use strict'; + + // injected refs + var $log, $window, $rootScope, fs, ps, bns; + + // constants + var pCls = 'topo-p dialog', + idDialog = 'topo-p-dialog', + panelOpts = { + width: 300, + edge: 'left' + }; + + // internal state + var pApi, panel, dApi; + + // TODO: ESC key invokes Cancel callback + // TODO: Enter invokes OK callback + + // create the dialog; return its API + function createDialog() { + var header, body, footer, + p = ps.createPanel(idDialog, panelOpts); + p.classed(pCls, true); + panel = p; + + function reset() { + p.empty(); + p.append('div').classed('header', true); + p.append('div').classed('body', true); + p.append('div').classed('footer', true); + + header = p.el().select('.header'); + body = p.el().select('.body'); + footer = p.el().select('.footer'); + } + + function hAppend(x) { + if (typeof x === 'string') { + return header.append(x); + } + header.node().appendChild(x.node()); + return header; + } + + function bAppend(x) { + if (typeof x === 'string') { + return body.append(x); + } + body.node().appendChild(x.node()); + return body; + } + + function fAppend(x) { + if (typeof x === 'string') { + return footer.append(x); + } + footer.node().appendChild(x.node()); + return footer; + } + + function destroy() { + ps.destroyPanel(idDialog); + } + + return { + reset: reset, + appendHeader: hAppend, + appendBody: bAppend, + appendFooter: fAppend, + destroy: destroy + }; + } + + function makeButton(text, callback) { + var cb = fs.isF(callback); + + function invoke() { + cb && cb(); + panel.hide(); + } + return createDiv('dialog-button') + .text(text) + .on('click', invoke); + } + + function addContent(content) { + if (pApi) { + pApi.appendBody(content); + } + return dApi; + } + + function addButton(text, cb) { + if (pApi) { + pApi.appendFooter(makeButton(text, cb)); + } + return dApi; + } + + // opens the dialog (creates if necessary) + function openDialog() { + $log.debug('Open DIALOG'); + if (!pApi) { + pApi = createDialog(); + } + pApi.reset(); + pApi.appendHeader('h2').text('=dialog='); + panel.show(); + + // return the dialog object API + dApi = { + addContent: addContent, + addButton: addButton + }; + return dApi; + } + + // closes the dialog (destroying panel) + function closeDialog() { + $log.debug('Close DIALOG'); + if (pApi) { + panel.hide(); + pApi.destroy(); + pApi = null; + dApi = null; + } + } + + // creates a detached div, returning D3 selection + // optional CSS class may be provided + function createDiv(cls) { + var div = d3.select(document.createElement('div')); + if (cls) { + div.classed(cls, true); + } + return div; + } + + // ========================== + + angular.module('ovTopo') + .factory('TopoDialogService', + ['$log', '$window', '$rootScope', 'FnService', 'PanelService', 'ButtonService', + + function (_$log_, _$window_, _$rootScope_, + _fs_, _ps_, _bns_) { + $log = _$log_; + $window = _$window_; + $rootScope = _$rootScope_; + fs = _fs_; + ps = _ps_; + bns = _bns_; + + return { + openDialog: openDialog, + closeDialog: closeDialog, + createDiv: createDiv + }; + }]); +}()); diff --git a/framework/src/onos/web/gui/src/main/webapp/app/view/topo/topoEvent.js b/framework/src/onos/web/gui/src/main/webapp/app/view/topo/topoEvent.js index 5fd38bf6..2957629a 100644 --- a/framework/src/onos/web/gui/src/main/webapp/app/view/topo/topoEvent.js +++ b/framework/src/onos/web/gui/src/main/webapp/app/view/topo/topoEvent.js @@ -60,6 +60,8 @@ updateLink: tfs, removeLink: tfs, + topoStartDone: tfs, + spriteListResponse: tspr, spriteDataResponse: tspr }; diff --git a/framework/src/onos/web/gui/src/main/webapp/app/view/topo/topoForce.js b/framework/src/onos/web/gui/src/main/webapp/app/view/topo/topoForce.js index f00b87fa..844d7dc9 100644 --- a/framework/src/onos/web/gui/src/main/webapp/app/view/topo/topoForce.js +++ b/framework/src/onos/web/gui/src/main/webapp/app/view/topo/topoForce.js @@ -240,6 +240,11 @@ } } + function topoStartDone(data) { + // called when the initial barrage of data has been sent from server + uplink.topoStartDone(); + } + // ======================== function nodeById(id) { @@ -1140,7 +1145,8 @@ removeHost: removeHost, addLink: addLink, updateLink: updateLink, - removeLink: removeLink + removeLink: removeLink, + topoStartDone: topoStartDone }; }]); }()); diff --git a/framework/src/onos/web/gui/src/main/webapp/app/view/topo/topoOverlay.js b/framework/src/onos/web/gui/src/main/webapp/app/view/topo/topoOverlay.js index 9a3b4358..2dee4c40 100644 --- a/framework/src/onos/web/gui/src/main/webapp/app/view/topo/topoOverlay.js +++ b/framework/src/onos/web/gui/src/main/webapp/app/view/topo/topoOverlay.js @@ -34,7 +34,8 @@ // internal state var overlays = {}, - current = null; + current = null, + reset = true; function error(fn, msg) { $log.error(tos + fn + '(): ' + msg); @@ -144,7 +145,8 @@ payload[op] = oid; } - if (!same) { + if (reset || !same) { + reset = false; current && doop('deactivate'); current = overlays[id]; current && doop('activate'); @@ -390,6 +392,7 @@ tbSelection: tbSelection, installButtons: installButtons, addDetailButton: addDetailButton, + resetOnToolbarDestroy: function () { reset = true; }, hooks: { escape: escapeHook, emptySelect: emptySelectHook, diff --git a/framework/src/onos/web/gui/src/main/webapp/app/view/topo/topoSelect.js b/framework/src/onos/web/gui/src/main/webapp/app/view/topo/topoSelect.js index 483c4baa..4ad76903 100644 --- a/framework/src/onos/web/gui/src/main/webapp/app/view/topo/topoSelect.js +++ b/framework/src/onos/web/gui/src/main/webapp/app/view/topo/topoSelect.js @@ -240,6 +240,33 @@ return cc; } + // returns a selection context, providing info about what is selected + function selectionContext() { + var devices = [], + hosts = [], + types = {}; + + angular.forEach(selections, function (d) { + var o = d.obj, + c = o.class; + + if (c === 'device') { + devices.push(o.id); + types[o.id] = o.type; + } + if (c === 'host') { + hosts.push(o.id); + types[o.id] = o.type; + } + }); + + return { + devices: devices, + hosts: hosts, + types: types + }; + } + // === ----------------------------------------------------- // === MODULE DEFINITION === @@ -280,7 +307,8 @@ selectOrder: function () { return selectOrder; }, somethingSelected: somethingSelected, - clickConsumed: clickConsumed + clickConsumed: clickConsumed, + selectionContext: selectionContext }; }]); }()); diff --git a/framework/src/onos/web/gui/src/main/webapp/app/view/topo/topoToolbar.js b/framework/src/onos/web/gui/src/main/webapp/app/view/topo/topoToolbar.js index 3928cd21..06285442 100644 --- a/framework/src/onos/web/gui/src/main/webapp/app/view/topo/topoToolbar.js +++ b/framework/src/onos/web/gui/src/main/webapp/app/view/topo/topoToolbar.js @@ -243,6 +243,7 @@ function destroyToolbar() { tbs.destroyToolbar(name); + tov.resetOnToolbarDestroy(); } // allows us to ensure the button states track key strokes diff --git a/framework/src/onos/web/gui/src/main/webapp/app/view/topo/topoTraffic.js b/framework/src/onos/web/gui/src/main/webapp/app/view/topo/topoTraffic.js index ca379360..ff690c49 100644 --- a/framework/src/onos/web/gui/src/main/webapp/app/view/topo/topoTraffic.js +++ b/framework/src/onos/web/gui/src/main/webapp/app/view/topo/topoTraffic.js @@ -152,6 +152,14 @@ } } + // force the system to create a single intent selection + function selectIntent(data) { + trafficMode = 'intents'; + hoverMode = null; + wss.sendEvent('selectIntent', data); + flash.flash('Selecting Intent ' + data.key); + } + // === ------------------------------------------------------ // action buttons on detail panel (multiple selection) @@ -207,6 +215,7 @@ showPrevIntent: showPrevIntent, showNextIntent: showNextIntent, showSelectedIntentTraffic: showSelectedIntentTraffic, + selectIntent: selectIntent, // invoked from mouseover/mouseout and selection change requestTrafficForMode: requestTrafficForMode, diff --git a/framework/src/onos/web/gui/src/main/webapp/index.html b/framework/src/onos/web/gui/src/main/webapp/index.html index 5df3c664..7e0d9b7d 100644 --- a/framework/src/onos/web/gui/src/main/webapp/index.html +++ b/framework/src/onos/web/gui/src/main/webapp/index.html @@ -98,6 +98,7 @@ <script src="app/view/topo/topo.js"></script> <script src="app/view/topo/topoD3.js"></script> <script src="app/view/topo/topoEvent.js"></script> + <script src="app/view/topo/topoDialog.js"></script> <script src="app/view/topo/topoFilter.js"></script> <script src="app/view/topo/topoForce.js"></script> <script src="app/view/topo/topoInst.js"></script> diff --git a/framework/src/onos/web/gui/src/test/_karma/ev/badges/ev_10_showHighlights_stuff.json b/framework/src/onos/web/gui/src/test/_karma/ev/badges/ev_10_showHighlights_stuff.json new file mode 100644 index 00000000..4f35403f --- /dev/null +++ b/framework/src/onos/web/gui/src/test/_karma/ev/badges/ev_10_showHighlights_stuff.json @@ -0,0 +1,63 @@ +{ + "event": "showHighlights", + "payload": { + "devices": [ + { + "id": "of:0000000000000001", + "badge": { + "status": "i", + "gid": "xMark", + "msg": "x marks the spot" + } + }, + { + "id": "of:0000000000000002", + "badge": { + "status": "w", + "gid": "crown", + "msg": "it's good to be the King" + } + }, + { + "id": "of:0000000000000003", + "badge": { + "status": "e", + "gid": "chain", + "msg": "the weakest link" + } + }, + { + "id": "of:0000000000000004", + "badge": { + "status": "i", + "txt": "1", + "msg": "singular sensation" + } + }, + { + "id": "of:0000000000000005", + "badge": { + "status": "w", + "txt": "42", + "msg": "life, the universe, and everything!" + } + }, + { + "id": "of:0000000000000006", + "badge": { + "status": "e", + "txt": "99", + "msg": "cadbury's flake" + } + } + ], + "hosts": [], + "links": [ + { + "css": "primary", + "id": "of:0000000000000001/5-of:0000000000000002/7", + "label": "Foo!" + } + ] + } +} diff --git a/framework/src/onos/web/gui/src/test/_karma/ev/badges/ev_5_showHighlights_clear.json b/framework/src/onos/web/gui/src/test/_karma/ev/badges/ev_11_showHighlights_clear.json index 615efd25..615efd25 100644 --- a/framework/src/onos/web/gui/src/test/_karma/ev/badges/ev_5_showHighlights_clear.json +++ b/framework/src/onos/web/gui/src/test/_karma/ev/badges/ev_11_showHighlights_clear.json diff --git a/framework/src/onos/web/gui/src/test/_karma/ev/badges/ev_4_addDevice_s3.json b/framework/src/onos/web/gui/src/test/_karma/ev/badges/ev_4_addDevice_s3.json new file mode 100644 index 00000000..57f3251b --- /dev/null +++ b/framework/src/onos/web/gui/src/test/_karma/ev/badges/ev_4_addDevice_s3.json @@ -0,0 +1,18 @@ +{ + "event": "addDevice", + "payload": { + "id": "of:0000000000000003", + "type": "switch", + "online": true, + "master": "ONOS", + "labels": [ + "", + "switch-3", + "of:0000000000000003" + ], + "metaUi": { + "x": 600, + "y": 200 + } + } +} diff --git a/framework/src/onos/web/gui/src/test/_karma/ev/badges/ev_5_addDevice_s4.json b/framework/src/onos/web/gui/src/test/_karma/ev/badges/ev_5_addDevice_s4.json new file mode 100644 index 00000000..bab00488 --- /dev/null +++ b/framework/src/onos/web/gui/src/test/_karma/ev/badges/ev_5_addDevice_s4.json @@ -0,0 +1,18 @@ +{ + "event": "addDevice", + "payload": { + "id": "of:0000000000000004", + "type": "switch", + "online": true, + "master": "ONOS", + "labels": [ + "", + "switch-4", + "of:0000000000000004" + ], + "metaUi": { + "x": 200, + "y": 400 + } + } +} diff --git a/framework/src/onos/web/gui/src/test/_karma/ev/badges/ev_6_addDevice_s5.json b/framework/src/onos/web/gui/src/test/_karma/ev/badges/ev_6_addDevice_s5.json new file mode 100644 index 00000000..6ee18080 --- /dev/null +++ b/framework/src/onos/web/gui/src/test/_karma/ev/badges/ev_6_addDevice_s5.json @@ -0,0 +1,18 @@ +{ + "event": "addDevice", + "payload": { + "id": "of:0000000000000005", + "type": "switch", + "online": true, + "master": "ONOS", + "labels": [ + "", + "switch-5", + "of:0000000000000005" + ], + "metaUi": { + "x": 400, + "y": 420 + } + } +} diff --git a/framework/src/onos/web/gui/src/test/_karma/ev/badges/ev_6_showHighlights_stuff.json b/framework/src/onos/web/gui/src/test/_karma/ev/badges/ev_6_showHighlights_stuff.json deleted file mode 100644 index 74c42c5c..00000000 --- a/framework/src/onos/web/gui/src/test/_karma/ev/badges/ev_6_showHighlights_stuff.json +++ /dev/null @@ -1,30 +0,0 @@ -{ - "event": "showHighlights", - "payload": { - "devices": [ - { - "id": "of:0000000000000001", - "badge": { - "status": "e", - "gid": "xMark", - "msg": "x marks the spot" - } - }, - { - "id": "of:0000000000000002", - "badge": { - "status": "w", - "txt": "7" - } - } - ], - "hosts": [], - "links": [ - { - "css": "primary", - "id": "of:0000000000000001/5-of:0000000000000002/7", - "label": "Antz!" - } - ] - } -} diff --git a/framework/src/onos/web/gui/src/test/_karma/ev/badges/ev_7_addDevice_s6.json b/framework/src/onos/web/gui/src/test/_karma/ev/badges/ev_7_addDevice_s6.json new file mode 100644 index 00000000..4554996e --- /dev/null +++ b/framework/src/onos/web/gui/src/test/_karma/ev/badges/ev_7_addDevice_s6.json @@ -0,0 +1,18 @@ +{ + "event": "addDevice", + "payload": { + "id": "of:0000000000000006", + "type": "switch", + "online": true, + "master": "ONOS", + "labels": [ + "", + "switch-6", + "of:0000000000000006" + ], + "metaUi": { + "x": 600, + "y": 400 + } + } +} diff --git a/framework/src/onos/web/gui/src/test/_karma/ev/badges/ev_4_addLink_1_2.json b/framework/src/onos/web/gui/src/test/_karma/ev/badges/ev_8_addLink_1_2.json index fb952837..fb952837 100644 --- a/framework/src/onos/web/gui/src/test/_karma/ev/badges/ev_4_addLink_1_2.json +++ b/framework/src/onos/web/gui/src/test/_karma/ev/badges/ev_8_addLink_1_2.json diff --git a/framework/src/onos/web/gui/src/test/_karma/ev/badges/ev_7_showHighlights_clear.json b/framework/src/onos/web/gui/src/test/_karma/ev/badges/ev_9_showHighlights_clear.json index 615efd25..615efd25 100644 --- a/framework/src/onos/web/gui/src/test/_karma/ev/badges/ev_7_showHighlights_clear.json +++ b/framework/src/onos/web/gui/src/test/_karma/ev/badges/ev_9_showHighlights_clear.json diff --git a/framework/src/onos/web/gui/src/test/_karma/ev/badges/scenario.json b/framework/src/onos/web/gui/src/test/_karma/ev/badges/scenario.json index 0ca4f4f4..ae093d69 100644 --- a/framework/src/onos/web/gui/src/test/_karma/ev/badges/scenario.json +++ b/framework/src/onos/web/gui/src/test/_karma/ev/badges/scenario.json @@ -4,7 +4,7 @@ ], "title": "Demo adding badges", "params": { - "lastAuto": 5 + "lastAuto": 9 }, "description": [ "Demonstrate the device badging feature." |