alshabib

initial import

Change-Id: Ief25aef0066ea96bd2c329ccef974c072b3a5a73
Showing 170 changed files with 19316 additions and 0 deletions
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<!--
~ Copyright (c) 2014 Hewlett-Packard Development Company, L.P.
~
~ This program and the accompanying materials are made available under the
~ terms of the Eclipse Public License v1.0 which accompanies this distribution,
~ and is available at http://www.eclipse.org/legal/epl-v10.html
-->
<features xmlns="http://karaf.apache.org/xmlns/features/v1.2.0"
name="net.onrc.onos-1.0.0">
<repository>mvn:net.onrc.onos/onos-features/1.0.0-SNAPSHOT/xml/features</repository>
<feature name="thirdparty" version="1.0.0"
description="ONOS 3rd party dependencies">
<bundle>mvn:com.google.code.findbugs/annotations/2.0.2</bundle>
<bundle>mvn:io.netty/netty/3.9.2.Final</bundle>
<bundle>mvn:com.google.guava/guava/17.0</bundle>
<bundle>mvn:com.google.guava/guava/15.0</bundle>
</feature>
<feature name="base" version="1.0.0"
description="ONOS Base">
<feature>scr</feature>
<feature>thirdparty</feature>
<bundle>mvn:net.onrc.onos.sb/onos-sb/0.0.1</bundle>
<bundle>mvn:org.projectfloodlight/openflowj/0.3.6-SNAPSHOT</bundle>
</feature>
</features>
package net.onrc.onos.api;
/**
* Base abstraction of a piece of information about network elements.
*/
public interface Description {
}
package net.onrc.onos.api;
import java.net.URI;
/**
* Immutable representaion of a device identity.
*/
public class DeviceId {
private final URI uri;
public DeviceId(URI uri) {
this.uri = uri;
}
/**
* Returns the backing URI.
*
* @return backing device URI
*/
public URI uri() {
return uri;
}
}
package net.onrc.onos.api;
/**
* Representation of a port number.
*/
public interface PortNumber {
}
package net.onrc.onos.api;
/**
* Abstraction of a provider of information about network environment.
*/
public interface Provider {
ProviderId id();
}
package net.onrc.onos.api;
/**
* Broker used for registering/unregistering information providers with the core.
*
* @param <T> type of the information provider
* @param <S> type of the provider service
*/
public interface ProviderBroker<T extends Provider, S extends ProviderService> {
/**
* Registers the supplied provider with the core.
*
* @param provider provider to be registered
* @return provider service for injecting information into core
*/
S register(T provider);
/**
* Unregisters the supplied provider. As a result the previously issued
* provider service will be invalidated.
*
* @param provider provider to be unregistered
*/
void unregister(T provider);
}
package net.onrc.onos.api;
/**
* Notion of provider identity.
*/
public class ProviderId {
private final String id;
public ProviderId(String id) {
this.id = id;
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
ProviderId that = (ProviderId) o;
if (!id.equals(that.id)) {
return false;
}
return true;
}
@Override
public int hashCode() {
return id.hashCode();
}
@Override
public String toString() {
return "ProviderId{" +
"id='" + id + '\'' +
'}';
}
}
package net.onrc.onos.api;
/**
* Abstraction of a service through which providers can inject information
* about the network environment into the core.
*/
public interface ProviderService {
}
package net.onrc.onos.api.device;
import net.onrc.onos.api.Description;
import java.net.URI;
/**
* Carrier of immutable information about a device.
*/
public interface DeviceDescription extends Description {
/**
* Protocol/provider specific URI that can be used to encode the identity
* information required to communicate with the device externally, e.g.
* datapath ID.
*
* @return provider specific URI for the device
*/
URI deviceURI();
}
\ No newline at end of file
package net.onrc.onos.api.device;
import net.onrc.onos.api.Provider;
/**
* Abstraction of a device information provider.
*/
public interface DeviceProvider extends Provider {
}
package net.onrc.onos.api.device;
import net.onrc.onos.api.ProviderBroker;
/**
* Abstraction of a device provider brokerage.
*/
public interface DeviceProviderBroker
extends ProviderBroker<DeviceProvider, DeviceProviderService> {
}
package net.onrc.onos.api.device;
import net.onrc.onos.api.ProviderService;
import java.util.List;
/**
* Service through which device providers can inject device information into
* the core.
*/
public interface DeviceProviderService extends ProviderService {
// TODO: define suspend and remove actions on the mezzanine administrative API
/**
* Signals the core that a device has connected or has been detected somehow.
*
* @param deviceDescription information about network device
*/
void deviceConnected(DeviceDescription deviceDescription);
/**
* Signals the core that a device has disconnected or is no longer reachable.
*
* @param deviceDescription device to be removed
*/
void deviceDisconnected(DeviceDescription deviceDescription);
/**
* Sends information about all ports of a device. It is up to the core to
* determine what has changed.
*
* @param ports list of device ports
*/
void updatePorts(List<PortDescription> ports);
/**
* Used to notify the core about port status change of a single port.
*
* @param port description of the port that changed
*/
void portStatusChanged(PortDescription port);
}
package net.onrc.onos.api.device;
/**
* Information about a port.
*/
public interface PortDescription {
// TODO: possibly relocate this to a common ground so that this can also used by host tracking if required
}
package net.onrc.onos.api.host;
/**
* Information describing host and its location.
*/
public interface HostDescription {
// IP, MAC, VLAN-ID, HostLocation -> (ConnectionPoint + timestamp)
}
package net.onrc.onos.api.host;
import net.onrc.onos.api.Provider;
/**
* Provider of information about hosts and their location on the network.
*/
public interface HostProvider extends Provider {
}
package net.onrc.onos.api.host;
import net.onrc.onos.api.ProviderBroker;
/**
* Abstraction of a host provider brokerage.
*/
public interface HostProviderBroker
extends ProviderBroker<HostProvider, HostProviderService> {
}
package net.onrc.onos.api.host;
import net.onrc.onos.api.ProviderService;
/**
* Means of conveying host information to the core.
*/
public interface HostProviderService extends ProviderService {
void hostDetected(HostDescription hostDescription);
}
package net.onrc.onos.api.link;
/**
* Describes an infrastructure link.
*/
public interface LinkDescription {
// TODO: src, dst connection points, which are pairs of (DeviceId, PortNumber)
// On the north:
// Link = (ConnectPoint src, ConnectPoint dst);
// ConnectPoint = (DeviceId, PortNumber);
// On the south
// LinkDescription ~ Link
}
package net.onrc.onos.api.link;
import net.onrc.onos.api.Provider;
/**
* Abstraction of an entity providing information about infrastructure links
* to the core.
*/
public interface LinkProvider extends Provider {
}
package net.onrc.onos.api.link;
import net.onrc.onos.api.ProviderBroker;
/**
* Abstraction of an infrastructure link provider brokerage.
*/
public interface LinkProviderBroker
extends ProviderBroker<LinkProvider, LinkProviderService> {
}
package net.onrc.onos.api.link;
import net.onrc.onos.api.ProviderService;
/**
* Means for injecting link information into the core.
*/
public interface LinkProviderService extends ProviderService {
/**
* Signals that an infrastructure link has been connected.
*
* @param linkDescription link information
*/
void linkConnected(LinkDescription linkDescription);
/**
* Signals that an infrastructure link has been disconnected.
*
* @param linkDescription link information
*/
void linkDisconnected(LinkDescription linkDescription);
}
# See: http://rolf-engelhard.de/2011/04/using-the-same-suppression-filter-for-checkstyle-in-eclipse-and-maven/
config_loc=conf/checkstyle
<?xml version="1.0"?>
<!DOCTYPE module PUBLIC
"-//Puppy Crawl//DTD Check Configuration 1.3//EN"
"http://www.puppycrawl.com/dtds/configuration_1_3.dtd">
<!--
Checkstyle configuration that checks the sun coding conventions from:
- the Java Language Specification at
http://java.sun.com/docs/books/jls/second_edition/html/index.html
- the Sun Code Conventions at http://java.sun.com/docs/codeconv/
- the Javadoc guidelines at
http://java.sun.com/j2se/javadoc/writingdoccomments/index.html
- the JDK Api documentation http://java.sun.com/j2se/docs/api/index.html
- some best practices
Checkstyle is very configurable. Be sure to read the documentation at
http://checkstyle.sf.net (or in your downloaded distribution).
Most Checks are configurable, be sure to consult the documentation.
To completely disable a check, just comment it out or delete it from the file.
Finally, it is worth reading the documentation.
-->
<!--
The default severity setting in checkstyle is 'error', so some
of the rules below are configured to change the severity to
'warning'. Over time, these 'warning' settings should be
removed as more of the ONOS source code is modified to
follow the recommended rules.
-->
<module name="Checker">
<module name="SuppressionFilter">
<property name="file" value="${config_loc}/suppressions.xml"/>
</module>
<!--
If you set the basedir property below, then all reported file
names will be relative to the specified directory. See
http://checkstyle.sourceforge.net/5.x/config.html#Checker
<property name="basedir" value="${basedir}"/>
-->
<!-- 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"/> -->
<!-- Checks whether files end with a new line. -->
<!-- See http://checkstyle.sf.net/config_misc.html#NewlineAtEndOfFile -->
<module name="NewlineAtEndOfFile"/>
<!-- Checks that property files contain the same keys. -->
<!-- See http://checkstyle.sf.net/config_misc.html#Translation -->
<module name="Translation"/>
<!-- Checks for Size Violations. -->
<!-- See http://checkstyle.sf.net/config_sizes.html -->
<module name="FileLength">
<property name="max" value="2500"/>
</module>
<!-- Checks for whitespace -->
<!-- See http://checkstyle.sf.net/config_whitespace.html -->
<module name="FileTabCharacter"/>
<!-- Miscellaneous other checks. -->
<!-- See http://checkstyle.sf.net/config_misc.html -->
<module name="RegexpSingleline">
<property name="format" value="\s+$"/>
<property name="minimum" value="0"/>
<property name="maximum" value="0"/>
<property name="message" value="Line has trailing spaces."/>
</module>
<!-- Checks for Headers -->
<!-- See http://checkstyle.sf.net/config_header.html -->
<!-- <module name="Header"> -->
<!-- <property name="headerFile" value="${checkstyle.header.file}"/> -->
<!-- <property name="fileExtensions" value="java"/> -->
<!-- </module> -->
<module name="SuppressionCommentFilter">
<property name="offCommentFormat" value="(CHECKSTYLE\:OFF|Generated by the protocol buffer compiler.)"/>
<property name="onCommentFormat" value="CHECKSTYLE:ON"/>
</module>
<module name="SuppressWithNearbyCommentFilter">
<property name="commentFormat" value="CHECKSTYLE IGNORE THIS LINE" />
<property name="checkFormat" value=".*" />
<property name="influenceFormat" value="0" />
</module>
<!-- Example: // CHECKSTYLE IGNORE FinalClass FOR NEXT 1 LINES -->
<module name="SuppressWithNearbyCommentFilter">
<property name="commentFormat" value="CHECKSTYLE IGNORE (\w+) FOR NEXT (\d+) LINES"/>
<property name="checkFormat" value="$1"/>
<property name="influenceFormat" value="$2"/>
</module>
<module name="TreeWalker">
<module name="FileContentsHolder"/>
<!-- Checks for Javadoc comments. -->
<!-- See http://checkstyle.sf.net/config_javadoc.html -->
<module name="JavadocMethod">
<property name="severity" value="warning"/>
<property name="allowUndeclaredRTE" value="true"/>
</module>
<module name="JavadocType">
<property name="severity" value="warning"/>
</module>
<module name="JavadocVariable">
<!-- Suppress check for private member Javadocs.
Possibly revist fixing these. -->
<property name="scope" value="public"/>
<property name="severity" value="warning"/>
</module>
<module name="JavadocStyle"/>
<!-- @author tag should not be used -->
<module name="WriteTag">
<property name="tag" value="@author"/>
<property name="tagFormat" value="\S"/>
<property name="severity" value="ignore"/>
<property name="tagSeverity" value="error"/>
</module>
<!-- Checks for Naming Conventions. -->
<!-- See http://checkstyle.sf.net/config_naming.html -->
<module name="ConstantName">
<!-- ONOS allows the name "log" for static final Loggers -->
<property name="format"
value="^log$|^[A-Z][A-Z0-9]*(_[A-Z0-9]+)*$"/>
</module>
<module name="LocalFinalVariableName"/>
<module name="LocalVariableName"/>
<module name="MemberName"/>
<module name="MethodName"/>
<module name="PackageName"/>
<module name="ParameterName"/>
<module name="StaticVariableName"/>
<module name="TypeName"/>
<!-- Checks for imports -->
<!-- See http://checkstyle.sf.net/config_import.html -->
<module name="AvoidStarImport">
<property name="allowStaticMemberImports" value="true"/>
</module>
<module name="IllegalImport"/>
<!-- defaults to sun.* packages -->
<module name="RedundantImport"/>
<module name="UnusedImports"/>
<!-- Checks for Size Violations. -->
<!-- See http://checkstyle.sf.net/config_sizes.html -->
<module name="LineLength">
<!-- ONOS standard usage is 80 columns, but we allow up
to 120 to not break the build. -->
<property name="max" value="120"/>
<property name="ignorePattern" value="^import"/>
</module>
<module name="MethodLength">
<property name="max" value="400"/>
</module>
<module name="ParameterNumber"/>
<!-- Checks for whitespace -->
<!-- See http://checkstyle.sf.net/config_whitespace.html -->
<module name="EmptyForIteratorPad"/>
<module name="GenericWhitespace"/>
<module name="MethodParamPad"/>
<module name="NoWhitespaceAfter"/>
<module name="NoWhitespaceBefore"/>
<!-- Disabled for ONOS. Default rules specify undesired behavior for the '?' operator -->
<!-- <module name="OperatorWrap"/> -->
<module name="ParenPad"/>
<module name="TypecastParenPad"/>
<module name="WhitespaceAfter"/>
<module name="WhitespaceAround">
<property name="allowEmptyConstructors" value="true"/>
<property name="allowEmptyMethods" value="true"/>
</module>
<!-- Modifier Checks -->
<!-- See http://checkstyle.sf.net/config_modifiers.html -->
<module name="ModifierOrder"/>
<!-- Disabled for ONOS to allow use of public -->
<!-- modifiers in interfaces. -->
<!-- <module name="RedundantModifier"/> -->
<!-- Checks for blocks. You know, those {}'s -->
<!-- See http://checkstyle.sf.net/config_blocks.html -->
<module name="AvoidNestedBlocks">
<!-- ONOS alows declarations inside of switch case blocks -->
<property name="allowInSwitchCase" value="true"/>
</module>
<module name="EmptyBlock"/>
<module name="LeftCurly"/>
<module name="NeedBraces"/>
<module name="RightCurly"/>
<!-- Checks for common coding problems -->
<!-- See http://checkstyle.sf.net/config_coding.html -->
<!-- ONOS allows conditional operators -->
<!-- <module name="AvoidInlineConditionals"/> -->
<module name="EmptyStatement"/>
<module name="EqualsHashCode"/>
<module name="HiddenField">
<property name="ignoreSetter" value="true"/>
<property name="ignoreConstructorParameter" value="true"/>
</module>
<module name="IllegalInstantiation"/>
<module name="InnerAssignment"/>
<!-- Many violations of this rule present, revist in a
subsequent round of cleanups -->
<!-- <module name="MagicNumber"/> -->
<module name="MissingSwitchDefault"/>
<module name="RedundantThrows">
<property name="allowSubclasses" value="true"/>
<property name="allowUnchecked" value="true"/>
<property name="suppressLoadErrors" value="true"/>
</module>
<module name="SimplifyBooleanExpression"/>
<module name="SimplifyBooleanReturn"/>
<!-- Checks for class design -->
<!-- See http://checkstyle.sf.net/config_design.html -->
<!-- ONOS produces many warnings of this type.
Fixing all of these is outside the scope of the current cleanup. -->
<!-- <module name="DesignForExtension"/> -->
<module name="FinalClass"/>
<module name="HideUtilityClassConstructor"/>
<module name="InterfaceIsType"/>
<module name="VisibilityModifier">
<property name="severity" value="warning"/>
</module>
<!-- Miscellaneous other checks. -->
<!-- See http://checkstyle.sf.net/config_misc.html -->
<module name="ArrayTypeStyle"/>
<!-- Many violations of this rule currently, too many to fix
in the current cleanup. -->
<!-- <module name="FinalParameters"/> -->
<!-- ONOS allows TODO markers in checked in source code -->
<!-- <module name="TodoComment"/> -->
<module name="UpperEll"/>
</module>
</module>
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE suppressions PUBLIC "-//Puppy Crawl//DTD Suppressions 1.1//EN" "http://www.puppycrawl.com/dtds/suppressions_1_1.dtd">
<suppressions>
<!--
Note: Exclusion definition exists in multiple places.
- In file ${findbugs.excludeFilterFile} defined at top of pom.xml
- In file conf/checkstyle/onos_suppressions.xml (this file)
- maven-pmd-plugin configuration in pom.xml
(under build and reporting)
-->
<suppress files=".*" checks="FinalParametersCheck"/>
<suppress files=".*" checks="MagicNumbersCheck"/>
<suppress files=".*" checks="DesignForExtensionCheck"/>
<suppress files=".*" checks="TodoCommentCheck"/>
<suppress files=".*" checks="AvoidInlineConditionalsCheck"/>
<suppress files=".*" checks="OperatorWrapCheck"/>
</suppressions>
<FindBugsFilter>
<!--
Note: Exclusion definition exists in multiple places.
- In file ${findbugs.excludeFilterFile} defined at top of pom.xml (this file)
- In file conf/checkstyle/onos_suppressions.xml
- maven-pmd-plugin configuration in pom.xml
(under build and reporting)
-->
<Match>
<Class name="~net\.onrc\.onos\.core\.datastore\.serializers\..*" />
</Match>
<Match>
<Class name="~.*edu\.stanford\..*"/>
</Match>
<Match>
<Class name="~.org\.projectfloodlight\..*"/>
</Match>
</FindBugsFilter>
<?xml version="1.0"?>
<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>
<prerequisites>
<maven>3.0.4</maven>
</prerequisites>
<groupId>net.onrc.onos.sb</groupId>
<artifactId>onos-sb</artifactId>
<version>0.0.1</version>
<packaging>bundle</packaging>
<name>ONOS-SB</name>
<url>http://onlab.us/</url>
<licenses>
<license>
<name>Apache License, Version 2.0</name>
<url>http://www.apache.org/licenses/LICENSE-2.0.txt</url>
</license>
</licenses>
<repositories>
<repository>
<id>central</id>
<name>Maven Central repository</name>
<url>https://repo1.maven.org/maven2</url>
</repository>
<repository>
<id>maven-restlet</id>
<name>Public online Restlet repository</name>
<url>http://maven.restlet.org</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
<repository>
<id>sonatype-oss-snapshot</id>
<name>Sonatype OSS snapshot repository</name>
<url>https://oss.sonatype.org/content/repositories/snapshots</url>
<releases>
<enabled>false</enabled>
</releases>
</repository>
</repositories>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<powermock.version>1.5.5</powermock.version>
<restlet.version>2.1.4</restlet.version>
<cobertura-maven-plugin.version>2.6</cobertura-maven-plugin.version>
<!-- Following 2 findbugs version needs to be updated in sync to match the
findbugs version used in findbugs-plugin -->
<findbugs.version>3.0.0</findbugs.version>
<findbugs-plugin.version>3.0.0</findbugs-plugin.version>
<findbugs.effort>Max</findbugs.effort>
<findbugs.excludeFilterFile>conf/findbugs/exclude.xml</findbugs.excludeFilterFile>
<checkstyle-plugin.version>2.12</checkstyle-plugin.version>
<!-- To publish javadoc to github,
uncomment com.github.github site-maven-plugin and
see https://github.com/OPENNETWORKINGLAB/ONOS/pull/425
<github.global.server>github</github.global.server>
-->
<metrics.version>3.0.2</metrics.version>
<maven.surefire.plugin.version>2.16</maven.surefire.plugin.version>
</properties>
<build>
<plugins>
<plugin>
<groupId>org.apache.felix</groupId>
<artifactId>maven-scr-plugin</artifactId>
<version>1.15.0</version>
<executions>
<execution>
<id>generate-scr-srcdescriptor</id>
<goals>
<goal>scr</goal>
</goals>
</execution>
</executions>
<configuration>
<supportedProjectTypes>
<supportedProjectType>bundle</supportedProjectType>
<supportedProjectType>war</supportedProjectType>
</supportedProjectTypes>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.felix</groupId>
<artifactId>maven-bundle-plugin</artifactId>
<version>2.3.6</version>
<extensions>true</extensions>
<configuration>
<instructions>
<Bundle-SymbolicName>${project.groupId}.${project.artifactId}</Bundle-SymbolicName>
</instructions>
</configuration>
</plugin>
<!-- Note: the checkstyle configuration is also in the reporting section -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-checkstyle-plugin</artifactId>
<version>${checkstyle-plugin.version}</version>
<configuration>
<configLocation>conf/checkstyle/sun_checks.xml</configLocation>
<propertiesLocation>${basedir}/conf/checkstyle/checkstyle_maven.properties</propertiesLocation>
<failsOnError>false</failsOnError>
<logViolationsToConsole>true</logViolationsToConsole>
<includeTestSourceDirectory>true</includeTestSourceDirectory>
</configuration>
<executions>
<execution>
<id>validate-checkstyle</id>
<phase>verify</phase>
<goals>
<goal>check</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-install-plugin</artifactId>
<version>2.5.1</version>
<executions>
</executions>
</plugin>
<!-- guice maven plugin for dependency injection inside maven -->
<plugin>
<groupId>org.apache.camel</groupId>
<artifactId>guice-maven-plugin</artifactId>
<version>2.11.0</version>
</plugin>
<plugin>
<artifactId>maven-clean-plugin</artifactId>
<version>2.5</version>
</plugin>
<plugin>
<artifactId>maven-deploy-plugin</artifactId>
<version>2.8</version>
</plugin>
<plugin>
<artifactId>maven-jar-plugin</artifactId>
<version>2.4</version>
</plugin>
<plugin>
<artifactId>maven-resources-plugin</artifactId>
<version>2.6</version>
</plugin>
<plugin>
<artifactId>maven-site-plugin</artifactId>
<version>3.3</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.1</version>
<configuration>
<source>1.7</source>
<target>1.7</target>
<encoding>UTF-8</encoding>
<showDeprecation>true</showDeprecation>
<showWarnings>true</showWarnings>
<compilerArgs>
<arg>-Xlint:all</arg>
<arg>-Xlint:-serial</arg>
<arg>-Werror</arg>
</compilerArgs>
</configuration>
<executions>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>${maven.surefire.plugin.version}</version>
<configuration>
<!-- FIXME -XX:-UseSplitVerifier added as workaround for JDK 1.7.0u65 + PowerMock issue
https://issues.jboss.org/browse/JASSIST-228 -->
<argLine>-XX:MaxPermSize=256m -XX:-UseSplitVerifier</argLine>
<redirectTestOutputToFile>false</redirectTestOutputToFile>
<excludedGroups>net.onrc.onos.core.util.IntegrationTest</excludedGroups>
</configuration>
</plugin>
<!-- TODO exec:java no longer used remove at some point? -->
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>1.2.1</version>
<configuration>
<mainClass>net.onrc.onos.core.main.Main</mainClass>
</configuration>
<executions>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>2.9.1</version>
<configuration>
<charset>UTF-8</charset>
<locale>en</locale>
<author>false</author>
<excludePackageNames>net.floodlightcontroller.*:net.onrc.onos.core.datastore.serializers</excludePackageNames>
</configuration>
</plugin>
<!-- Remove me when we're sure that system test no longer need JaCoCo
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<version>0.6.3.201306030806</version>
<executions>
<execution>
<id>jacoco-initialize</id>
<goals>
<goal>prepare-agent</goal>
</goals>
</execution>
<execution>
<id>jacoco-site</id>
<phase>package</phase>
<goals>
<goal>report</goal>
</goals>
</execution>
</executions>
</plugin>
-->
<!-- Uncomment when publishing javadoc to github in the future.
<plugin>
<groupId>com.github.github</groupId>
<artifactId>site-maven-plugin</artifactId>
<version>0.8</version>
<configuration>
<message>Creating site for ${project.version}</message>
<dryRun>true</dryRun>
<repositoryName>ONOS</repositoryName>
<repositoryOwner>OPENNETWORKINGLAB</repositoryOwner>
<path>javadoc/${project.version}/</path>
</configuration>
<executions>
<execution>
<goals>
<goal>site</goal>
</goals>
<phase>site</phase>
</execution>
</executions>
</plugin>
-->
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<version>2.4</version>
<configuration>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
</configuration>
</plugin>
<plugin>
<!-- Using groovy script to set maven property ${hostname}.
This is a workaround to get hostname as a property inside pom file,
which current Maven does not provide. -->
<groupId>org.codehaus.gmaven</groupId>
<artifactId>groovy-maven-plugin</artifactId>
<version>2.0</version>
<executions>
<execution>
<phase>initialize</phase>
<goals>
<goal>execute</goal>
</goals>
<configuration>
<source>
project.properties["hostname"] = InetAddress.getLocalHost().getHostName()
</source>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<version>2.8</version>
<executions>
<execution>
<id>build-classpath</id>
<phase>compile</phase>
<goals>
<goal>build-classpath</goal>
</goals>
<configuration>
<outputFile>${project.basedir}/.javacp.${hostname}</outputFile>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>cobertura-maven-plugin</artifactId>
<version>${cobertura-maven-plugin.version}</version>
<configuration>
<instrumentation>
<ignores>
<ignore>org.slf4j.*</ignore>
</ignores>
<excludes>
<exclude>edu/stanford/ramcloud/**/*.class</exclude>
<exclude>net/floodlightcontroller/**/web/**/*.class</exclude>
</excludes>
</instrumentation>
<quiet>true</quiet>
</configuration>
<executions>
<execution>
<goals>
<goal>clean</goal>
</goals>
</execution>
</executions>
</plugin>
<!-- Note: the findbugs configuration is also in the reporting section -->
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>findbugs-maven-plugin</artifactId>
<version>${findbugs-plugin.version}</version>
<configuration>
<effort>${findbugs.effort}</effort>
<excludeFilterFile>${findbugs.excludeFilterFile}</excludeFilterFile>
</configuration>
<executions>
<execution>
<id>validate-findbugs</id>
<phase>verify</phase>
<goals>
<goal>check</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-pmd-plugin</artifactId>
<version>3.1</version>
<configuration>
<!--
Note: Exclusion definition exists in multiple places.
- In file ${findbugs.excludeFilterFile} defined at top of pom.xml
- In file conf/checkstyle/onos_suppressions.xml
- maven-pmd-plugin configuration in pom.xml
(under build and reporting)
-->
<excludes>
<exclude>**/datastore/serializers/**</exclude>
<exclude>**/edu/stanford/**</exclude>
<exclude>**/net/floodlightcontroller/**</exclude>
</excludes>
<rulesets>
<ruleset>${basedir}/conf/pmd/onos_ruleset.xml</ruleset>
</rulesets>
</configuration>
<executions>
<execution>
<id>validate-pmd</id>
<phase>verify</phase>
<goals>
<!-- Uncomment this goal to make the build fail on pmd errors -->
<!--<goal>check</goal>-->
</goals>
</execution>
</executions>
</plugin>
</plugins>
<pluginManagement>
<plugins>
<!--This plugin's configuration is used to store Eclipse m2e settings
only. It has no influence on the Maven build itself. -->
<plugin>
<groupId>org.eclipse.m2e</groupId>
<artifactId>lifecycle-mapping</artifactId>
<version>1.0.0</version>
<configuration>
<lifecycleMappingMetadata>
<pluginExecutions>
<pluginExecution>
<pluginExecutionFilter>
<groupId>
org.apache.maven.plugins
</groupId>
<artifactId>
maven-dependency-plugin
</artifactId>
<versionRange>[2.8,)</versionRange>
<goals>
<goal>build-classpath</goal>
</goals>
</pluginExecutionFilter>
<action>
<ignore></ignore>
</action>
</pluginExecution>
<pluginExecution>
<pluginExecutionFilter>
<groupId>org.codehaus.gmaven</groupId>
<artifactId>groovy-maven-plugin</artifactId>
<versionRange>[2.0,)</versionRange>
<goals>
<goal>execute</goal>
</goals>
</pluginExecutionFilter>
<action>
<ignore></ignore>
</action>
</pluginExecution>
</pluginExecutions>
</lifecycleMappingMetadata>
</configuration>
</plugin>
</plugins>
</pluginManagement>
</build>
<!-- for getting visualization reporting -->
<reporting>
<excludeDefaults>true</excludeDefaults>
<outputDirectory>${project.build.directory}/site</outputDirectory>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-project-info-reports-plugin</artifactId>
<version>2.7</version>
<configuration>
<dependencyDetailsEnabled>false</dependencyDetailsEnabled>
<dependencyLocationsEnabled>false</dependencyLocationsEnabled>
</configuration>
<reportSets>
<reportSet>
<reports>
<report>dependencies</report>
<report>scm</report>
</reports>
</reportSet>
</reportSets>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>2.9.1</version>
<configuration>
<charset>UTF-8</charset>
<locale>en</locale>
<author>false</author>
<excludePackageNames>net.floodlightcontroller.*:net.onrc.onos.core.datastore.serializers</excludePackageNames>
</configuration>
</plugin>
<plugin>
<!-- Note: the checkstyle configuration is also in the build section -->
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-checkstyle-plugin</artifactId>
<version>${checkstyle-plugin.version}</version>
<configuration>
<configLocation>conf/checkstyle/sun_checks.xml</configLocation>
<!--
Note: Exclusion definition exists in multiple places.
- In file ${findbugs.excludeFilterFile} defined at top of pom.xml
- maven-checkstyle-plugin configuration in pom.xml
- maven-pmd-plugin configuration in pom.xml
(under build and reporting)
-->
<propertiesLocation>${basedir}/conf/checkstyle/checkstyle_maven.properties</propertiesLocation>
<includeTestSourceDirectory>true</includeTestSourceDirectory>
</configuration>
<reportSets>
<reportSet>
<reports>
<report>checkstyle</report>
</reports>
</reportSet>
</reportSets>
</plugin>
<!-- Note: the findbugs configuration is also in the build section -->
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>findbugs-maven-plugin</artifactId>
<version>${findbugs-plugin.version}</version>
<configuration>
<effort>${findbugs.effort}</effort>
<excludeFilterFile>${findbugs.excludeFilterFile}</excludeFilterFile>
<reportPlugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>findbugs-maven-plugin</artifactId>
</plugin>
</reportPlugins>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-pmd-plugin</artifactId>
<version>3.1</version>
<configuration>
<!--
Note: Exclusion definition exists in multiple places.
- In file ${findbugs.excludeFilterFile} defined at top of pom.xml
- In file conf/checkstyle/onos_suppressions.xml
- maven-pmd-plugin configuration in pom.xml
(under build and reporting)
-->
<excludes>
<exclude>**/datastore/serializers/**</exclude>
<exclude>**/edu/stanford/**</exclude>
<exclude>**/net/floodlightcontroller/**</exclude>
</excludes>
<rulesets>
<ruleset>${basedir}/conf/pmd/onos_ruleset.xml</ruleset>
</rulesets>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jxr-plugin</artifactId>
<version>2.4</version>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>cobertura-maven-plugin</artifactId>
<version>${cobertura-maven-plugin.version}</version>
</plugin>
</plugins>
</reporting>
<dependencies>
<!-- ONOS's direct dependencies -->
<dependency>
<groupId>org.apache.felix</groupId>
<artifactId>org.apache.felix.scr.annotations</artifactId>
<version>1.9.6</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.1.2</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-core</artifactId>
<version>1.1.2</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.5</version>
</dependency>
<dependency>
<!-- findbugs suppression annotation and @GuardedBy, etc. -->
<groupId>com.google.code.findbugs</groupId>
<artifactId>annotations</artifactId>
<version>${findbugs.version}</version>
</dependency>
<dependency>
<groupId>org.projectfloodlight</groupId>
<artifactId>openflowj</artifactId>
<version>0.3.6-SNAPSHOT</version>
</dependency>
<!-- Floodlight's dependencies -->
<dependency>
<!-- dependency to old version of netty? -->
<groupId>io.netty</groupId>
<artifactId>netty</artifactId>
<version>3.9.2.Final</version>
</dependency>
<!-- Dependency for libraries used for testing -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.easymock</groupId>
<artifactId>easymock</artifactId>
<version>3.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-module-junit4</artifactId>
<version>${powermock.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-api-easymock</artifactId>
<version>${powermock.version}</version>
<scope>test</scope>
</dependency>
</dependencies>
<profiles>
<!-- Jenkins by default defines a property BUILD_NUMBER which is used to
enable the profile. -->
<profile>
<id>jenkins</id>
<activation>
<property>
<name>env.BUILD_NUMBER</name>
</property>
</activation>
<build>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>cobertura-maven-plugin</artifactId>
<version>${cobertura-maven-plugin.version}</version>
<configuration>
<formats>
<format>xml</format>
</formats>
<quiet>true</quiet>
</configuration>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>cobertura</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
<profile>
<id>all-tests</id>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>${maven.surefire.plugin.version}</version>
<configuration combine.self="merge">
<excludedGroups></excludedGroups>
</configuration>
</plugin>
</plugins>
</build>
</profile>
<profile>
<id>error-prone</id>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.1</version>
<configuration>
<compilerArgs combine.children="append">
<!-- FIXME -Xlint:-path required when using findbugs + error-prone -->
<arg>-Xlint:-path</arg>
</compilerArgs>
<!-- Turn on error-prone -->
<compilerId>javac-with-errorprone</compilerId>
<forceJavacCompilerUse>true</forceJavacCompilerUse>
</configuration>
<dependencies combine.children="append">
<dependency>
<groupId>com.google.errorprone</groupId>
<artifactId>error_prone_core</artifactId>
<version>1.1.2</version>
</dependency>
<dependency>
<groupId>org.codehaus.plexus</groupId>
<artifactId>plexus-compiler-javac</artifactId>
<version>2.3</version>
</dependency>
<dependency>
<groupId>org.codehaus.plexus</groupId>
<artifactId>plexus-compiler-javac-errorprone</artifactId>
<version>2.3</version>
</dependency>
</dependencies>
</plugin>
</plugins>
</build>
</profile>
</profiles>
</project>
/**
* Copyright 2011, Big Switch Networks, Inc.
* Originally created by David Erickson, Stanford University
*
* 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 net.onrc.onos.of.ctl;
import java.io.IOException;
import java.util.Collection;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.Future;
import net.onrc.onos.of.ctl.debugcounter.IDebugCounterService;
import net.onrc.onos.of.ctl.debugcounter.IDebugCounterService.CounterException;
import net.onrc.onos.of.ctl.util.OrderedCollection;
import org.jboss.netty.channel.Channel;
import org.projectfloodlight.openflow.protocol.OFActionType;
import org.projectfloodlight.openflow.protocol.OFCapabilities;
import org.projectfloodlight.openflow.protocol.OFDescStatsReply;
import org.projectfloodlight.openflow.protocol.OFFeaturesReply;
import org.projectfloodlight.openflow.protocol.OFMessage;
import org.projectfloodlight.openflow.protocol.OFPortDesc;
import org.projectfloodlight.openflow.protocol.OFPortDescStatsReply;
import org.projectfloodlight.openflow.protocol.OFPortStatus;
import org.projectfloodlight.openflow.protocol.OFStatsReply;
import org.projectfloodlight.openflow.protocol.OFStatsRequest;
import org.projectfloodlight.openflow.protocol.OFVersion;
import org.projectfloodlight.openflow.types.U64;
public interface IOFSwitch {
/**
* OF1.3 switches should support role-request messages as in the 1.3 spec.
* OF1.0 switches may or may not support the Nicira role request extensions.
* To indicate the support, this property should be set by the associated
* OF1.0 switch driver in the net.onrc.onos.core.drivermanager package.
* The property will be ignored for OF1.3 switches.
*/
public static final String SWITCH_SUPPORTS_NX_ROLE = "supportsNxRole";
//************************
// Channel related
//************************
/**
* Disconnects the switch by closing the TCP connection. Results in a call
* to the channel handler's channelDisconnected method for cleanup
* @throws IOException
*/
public void disconnectSwitch();
/**
* Writes to the OFMessage to the output stream.
* The message will be handed to the floodlightProvider for possible filtering
* and processing by message listeners
*
* @param m
* @param bc
* @throws IOException
*/
public void write(OFMessage m) throws IOException;
/**
* Writes the list of messages to the output stream.
* The message will be handed to the floodlightProvider for possible filtering
* and processing by message listeners.
*
* @param msglist
* @param bc
* @throws IOException
*/
public void write(List<OFMessage> msglist) throws IOException;
/**
* Gets the date the switch connected to this controller.
*
* @return the date
*/
public Date getConnectedSince();
/**
* Gets the next available transaction id.
*
* @return the next transaction ID
*/
public int getNextTransactionId();
/**
* Checks if the switch is still connected.
* Only call while holding processMessageLock
*
* @return whether the switch is still disconnected
*/
public boolean isConnected();
/**
* Sets whether the switch is connected.
* Only call while holding modifySwitchLock
*
* @param connected whether the switch is connected
*/
public void setConnected(boolean connected);
/**
* Flushes all flows queued for this switch in the current thread.
* NOTE: The contract is limited to the current thread
*/
public void flush();
/**
* Sets the Netty Channel this switch instance is associated with.
* <p>
* Called immediately after instantiation
*
* @param channel the channel
*/
public void setChannel(Channel channel);
//************************
// Switch features related
//************************
/**
* Gets the datapathId of the switch.
*
* @return the switch buffers
*/
public long getId();
/**
* Gets a string version of the ID for this switch.
*
* @return string version of the ID
*/
public String getStringId();
/**
* Gets the number of buffers.
*
* @return the number of buffers
*/
public int getNumBuffers();
public Set<OFCapabilities> getCapabilities();
public byte getNumTables();
/**
* Returns an OFDescStatsReply message object. Use the methods contained
* to retrieve switch descriptions for Manufacturer, Hw/Sw version etc.
*/
public OFDescStatsReply getSwitchDescription();
/**
* Cancel features reply with a specific transaction ID.
* @param transactionId the transaction ID
*/
public void cancelFeaturesReply(int transactionId);
/**
* Gets the OFActionType set.
* <p>
* getActions has relevance only for an OpenFlow 1.0 switch.
* For OF1.3, each table can support different actions
*
* @return the action set
*/
public Set<OFActionType> getActions();
public void setOFVersion(OFVersion ofv);
public OFVersion getOFVersion();
//************************
// Switch port related
//************************
/**
* the type of change that happened to an open flow port.
*/
public enum PortChangeType {
/** Either a new port has been added by the switch, or we are
* adding a port we just deleted (via a prior notification) due to
* a change in the portNumber-portName mapping.
*/
ADD,
/** some other feature of the port has changed (eg. speed)*/
OTHER_UPDATE,
/** Either a port has been deleted by the switch, or we are deleting
* a port whose portNumber-portName mapping has changed. Note that in
* the latter case, a subsequent notification will be sent out to add a
* port with the new portNumber-portName mapping.
*/
DELETE,
/** Port is up (i.e. enabled). Presumably an earlier notification had
* indicated that it was down. To be UP implies that the port is
* administratively considered UP (see ofp_port_config) AND the port
* link is up AND the port is no longer blocked (see ofp_port_state).
*/
UP,
/** Port is down (i.e. disabled). Presumably an earlier notification had
* indicated that it was up, or the port was always up.
* To be DOWN implies that the port has been either
* administratively brought down (see ofp_port_config) OR the port
* link is down OR the port is blocked (see ofp_port_state).
*/
DOWN,
}
/**
* Describes a change of an open flow port.
*/
public static class PortChangeEvent {
public final OFPortDesc port;
public final PortChangeType type;
/**
* @param port
* @param type
*/
public PortChangeEvent(OFPortDesc port,
PortChangeType type) {
this.port = port;
this.type = type;
}
/* (non-Javadoc)
* @see java.lang.Object#hashCode()
*/
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((port == null) ? 0 : port.hashCode());
result = prime * result + ((type == null) ? 0 : type.hashCode());
return result;
}
/* (non-Javadoc)
* @see java.lang.Object#equals(java.lang.Object)
*/
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
PortChangeEvent other = (PortChangeEvent) obj;
if (port == null) {
if (other.port != null) {
return false;
}
} else if (!port.equals(other.port)) {
return false;
}
if (type != other.type) {
return false;
}
return true;
}
/* (non-Javadoc)
* @see java.lang.Object#toString()
*/
@Override
public String toString() {
return "[" + type + " " + port.toString() + "]";
}
}
/**
* Get list of all enabled ports. This will typically be different from
* the list of ports in the OFFeaturesReply, since that one is a static
* snapshot of the ports at the time the switch connected to the controller
* whereas this port list also reflects the port status messages that have
* been received.
*
* @return Unmodifiable list of ports not backed by the underlying collection
*/
public Collection<OFPortDesc> getEnabledPorts();
/**
* Get list of the port numbers of all enabled ports. This will typically
* be different from the list of ports in the OFFeaturesReply, since that
* one is a static snapshot of the ports at the time the switch connected
* to the controller whereas this port list also reflects the port status
* messages that have been received.
*
* @return Unmodifiable list of ports not backed by the underlying collection
*/
public Collection<Integer> getEnabledPortNumbers();
/**
* Retrieve the port object by the port number. The port object
* is the one that reflects the port status updates that have been
* received, not the one from the features reply.
*
* @param portNumber
* @return port object
*/
public OFPortDesc getPort(int portNumber);
/**
* Retrieve the port object by the port name. The port object
* is the one that reflects the port status updates that have been
* received, not the one from the features reply.
*
* @param portName
* @return port object
*/
public OFPortDesc getPort(String portName);
/**
* Add or modify a switch port. This is called by the core controller
* code in response to a OFPortStatus message. It should not typically be
* called by other floodlight applications.
*
* OFPPR_MODIFY and OFPPR_ADD will be treated as equivalent. The OpenFlow
* spec is not clear on whether portNames are portNumbers are considered
* authoritative identifiers. We treat portNames <-> portNumber mappings
* as fixed. If they change, we delete all previous conflicting ports and
* add all new ports.
*
* @param ps the port status message
* @return the ordered Collection of changes "applied" to the old ports
* of the switch according to the PortStatus message. A single PortStatus
* message can result in multiple changes.
* If portName <-> portNumber mappings have
* changed, the iteration order ensures that delete events for old
* conflicting appear before before events adding new ports
*/
public OrderedCollection<PortChangeEvent> processOFPortStatus(OFPortStatus ps);
/**
* Get list of all ports. This will typically be different from
* the list of ports in the OFFeaturesReply, since that one is a static
* snapshot of the ports at the time the switch connected to the controller
* whereas this port list also reflects the port status messages that have
* been received.
*
* @return Unmodifiable list of ports
*/
public Collection<OFPortDesc> getPorts();
/**
* @param portName
* @return Whether a port is enabled per latest port status message
* (not configured down nor link down nor in spanning tree blocking state)
*/
public boolean portEnabled(int portName);
/**
* @param portNumber
* @return Whether a port is enabled per latest port status message
* (not configured down nor link down nor in spanning tree blocking state)
*/
public boolean portEnabled(String portName);
/**
* Compute the changes that would be required to replace the old ports
* of this switch with the new ports.
* @param ports new ports to set
* @return the ordered collection of changes "applied" to the old ports
* of the switch in order to set them to the new set.
* If portName <-> portNumber mappings have
* changed, the iteration order ensures that delete events for old
* conflicting appear before before events adding new ports
*/
public OrderedCollection<PortChangeEvent>
comparePorts(Collection<OFPortDesc> ports);
/**
* Replace the ports of this switch with the given ports.
* @param ports new ports to set
* @return the ordered collection of changes "applied" to the old ports
* of the switch in order to set them to the new set.
* If portName <-> portNumber mappings have
* changed, the iteration order ensures that delete events for old
* conflicting appear before before events adding new ports
*/
public OrderedCollection<PortChangeEvent>
setPorts(Collection<OFPortDesc> ports);
// XXX S The odd use of providing an API call to 'set ports' (above) would
// logically suggest that there should be a way to delete or unset the ports.
// Right now we forbid this. We should probably not use setPorts too.
//
// /**
// * Delete a port for the switch. This is called by the core controller
// * code in response to a OFPortStatus message. It should not typically be
// * called by other floodlight applications.
// *
// * @param portNumber
// */
// public void deletePort(short portNumber);
//
// /**
// * Delete a port for the switch. This is called by the core controller
// * code in response to a OFPortStatus message. It should not typically be
// * called by other floodlight applications.
// *
// * @param portName
// */
// public void deletePort(String portName);
//*******************************************
// IOFSwitch object attributes
//************************
/**
* Gets attributes of this switch.
*
* @return attributes of the switch
*/
public Map<Object, Object> getAttributes();
/**
* Checks if a specific switch property exists for this switch.
*
* @param name name of property
* @return value for name
*/
boolean hasAttribute(String name);
/**
* Gets properties for switch specific behavior.
*
* @param name name of property
* @return 'value' for 'name', or null if no entry for 'name' exists
*/
Object getAttribute(String name);
/**
* Sets properties for switch specific behavior.
*
* @param name name of property
* @param value value for name
*/
void setAttribute(String name, Object value);
/**
* Removes properties for switch specific behavior.
*
* @param name name of property
* @return current value for name or null (if not present)
*/
Object removeAttribute(String name);
//************************
// Switch statistics
//************************
/**
* Delivers the statistics future reply.
*
* @param reply the reply to deliver
*/
public void deliverStatisticsReply(OFMessage reply);
/**
* Cancels the statistics reply with the given transaction ID.
*
* @param transactionId the transaction ID
*/
public void cancelStatisticsReply(int transactionId);
/**
* Cancels all statistics replies.
*/
public void cancelAllStatisticsReplies();
/**
* Gets a Future object that can be used to retrieve the asynchronous.
* OFStatisticsReply when it is available.
*
* @param request statistics request
* @return Future object wrapping OFStatisticsReply
* @throws IOException
*/
public Future<List<OFStatsReply>> getStatistics(OFStatsRequest<?> request)
throws IOException;
//************************
// Switch other utilities
//************************
/**
* Clears all flowmods on this switch.
*/
public void clearAllFlowMods();
/**
* Gets the current role of this controller for this IOFSwitch.
*/
public Role getRole();
/**
* Sets this controller's Role for this IOFSwitch to role.
*
* @param role
*/
public void setRole(Role role);
/**
* Gets the next generation ID.
* <p>
* Note: relevant for role request messages in OF1.3
*
* @return next generation ID
*/
public U64 getNextGenerationId();
/**
* Set debug counter service for per-switch counters.
* Called immediately after instantiation.
* @param debugCounters
* @throws CounterException
*/
public void setDebugCounterService(IDebugCounterService debugCounter)
throws CounterException;
/**
* Start this switch driver's sub handshake. This might be a no-op but
* this method must be called at least once for the switch to be become
* ready.
* This method must only be called from the I/O thread
* @throws IOException
* @throws SwitchDriverSubHandshakeAlreadyStarted if the sub-handshake has
* already been started
*/
public void startDriverHandshake() throws IOException;
/**
* Check if the sub-handshake for this switch driver has been completed.
* This method can only be called after startDriverHandshake()
*
* This methods must only be called from the I/O thread
* @return true if the sub-handshake has been completed. False otherwise
* @throws SwitchDriverSubHandshakeNotStarted if startDriverHandshake() has
* not been called yet.
*/
public boolean isDriverHandshakeComplete();
/**
* Pass the given OFMessage to the driver as part of this driver's
* sub-handshake. Must not be called after the handshake has been completed
* This methods must only be called from the I/O thread
* @param m The message that the driver should process
* @throws SwitchDriverSubHandshakeCompleted if isDriverHandshake() returns
* false before this method call
* @throws SwitchDriverSubHandshakeNotStarted if startDriverHandshake() has
* not been called yet.
*/
public void processDriverHandshakeMessage(OFMessage m);
/**
* Set the flow table full flag in the switch.
* XXX S Rethink this for multiple tables
*/
public void setTableFull(boolean isFull);
/**
* Save the features reply for this switch.
*
* @param featuresReply
*/
public void setFeaturesReply(OFFeaturesReply featuresReply);
/**
* Save the portset for this switch.
*
* @param portDescReply
*/
public void setPortDescReply(OFPortDescStatsReply portDescReply);
//************************
// Message handling
//************************
/**
* Handle the message coming from the dataplane.
*
* @param m the actual message
*/
public void handleMessage(OFMessage m);
}
package net.onrc.onos.of.ctl;
import org.projectfloodlight.openflow.protocol.OFVersion;
import net.onrc.onos.of.ctl.registry.IControllerRegistry;
/**
* Interface to passed to controller class in order to allow
* it to spawn the appropriate type of switch and furthermore
* specify a registry object (ie. ZooKeeper).
*
*/
public interface IOFSwitchManager {
/**
* Given a description string for a switch spawn the
* concrete representation of that switch.
*
* @param mfr manufacturer description
* @param hwDesc hardware description
* @param swDesc software description
* @param ofv openflow version
* @return A switch of type IOFSwitch.
*/
public IOFSwitch getSwitchImpl(String mfr, String hwDesc, String swDesc, OFVersion ofv);
/**
* Returns the mastership registry used during controller-switch role election.
* @return the registry
*/
public IControllerRegistry getRegistry();
}
package net.onrc.onos.of.ctl;
import org.projectfloodlight.openflow.protocol.OFControllerRole;
/**
* The role of the controller as it pertains to a particular switch.
* Note that this definition of the role enum is different from the
* OF1.3 definition. It is maintained here to be backward compatible to
* earlier versions of the controller code. This enum is translated
* to the OF1.3 enum, before role messages are sent to the switch.
* See sendRoleRequestMessage method in OFSwitchImpl
*/
public enum Role {
EQUAL(OFControllerRole.ROLE_EQUAL),
MASTER(OFControllerRole.ROLE_MASTER),
SLAVE(OFControllerRole.ROLE_SLAVE);
private Role(OFControllerRole nxRole) {
nxRole.ordinal();
}
/*
private static Map<Integer,Role> nxRoleToEnum
= new HashMap<Integer,Role>();
static {
for(Role r: Role.values())
nxRoleToEnum.put(r.toNxRole(), r);
}
public int toNxRole() {
return nxRole;
}
// Return the enum representing the given nxRole or null if no
// such role exists
public static Role fromNxRole(int nxRole) {
return nxRoleToEnum.get(nxRole);
}*/
}
/**
* Copyright 2012, Big Switch Networks, Inc.
* Originally created by David Erickson, Stanford University
*
* 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 net.onrc.onos.of.ctl.annotations;
import java.lang.annotation.ElementType;
import java.lang.annotation.Target;
/**
* Annotation used to set the category for log messages for a class.
*
*/
@Target({ ElementType.TYPE, ElementType.METHOD })
public @interface LogMessageCategory {
/**
* The category for the log messages for this class.
*
* @return
*/
String value() default "Core";
}
/**
* Copyright 2012, Big Switch Networks, Inc.
* Originally created by David Erickson, Stanford University
*
* 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 net.onrc.onos.of.ctl.annotations;
import java.lang.annotation.ElementType;
import java.lang.annotation.Target;
/**
* Annotation used to document log messages. This can be used to generate
* documentation on syslog output.
*
*/
@Target({ ElementType.TYPE, ElementType.METHOD })
public @interface LogMessageDoc {
public static final String NO_ACTION = "No action is required.";
public static final String UNKNOWN_ERROR = "An unknown error occured";
public static final String GENERIC_ACTION =
"Examine the returned error or exception and take " +
"appropriate action.";
public static final String CHECK_SWITCH =
"Check the health of the indicated switch. " +
"Test and troubleshoot IP connectivity.";
public static final String CHECK_CONTROLLER =
"Verify controller system health, CPU usage, and memory. " +
"Rebooting the controller node may help if the controller " +
"node is in a distressed state.";
public static final String REPORT_CONTROLLER_BUG =
"This is likely a defect in the controller. Please report this " +
"issue. Restarting the controller or switch may help to " +
"alleviate.";
public static final String REPORT_SWITCH_BUG =
"This is likely a defect in the switch. Please report this " +
"issue. Restarting the controller or switch may help to " +
"alleviate.";
/**
* The log level for the log message.
*
* @return the log level as a tring
*/
String level() default "INFO";
/**
* The message that will be printed.
*
* @return the message
*/
String message() default UNKNOWN_ERROR;
/**
* An explanation of the meaning of the log message.
*
* @return the explanation
*/
String explanation() default UNKNOWN_ERROR;
/**
* The recommendated action associated with the log message.
*
* @return the recommendation
*/
String recommendation() default NO_ACTION;
}
/**
* Copyright 2012, Big Switch Networks, Inc.
* Originally created by David Erickson, Stanford University
*
* 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 net.onrc.onos.of.ctl.annotations;
import java.lang.annotation.ElementType;
import java.lang.annotation.Target;
/**
* Annotation used to document log messages. This can be used to generate
* documentation on syslog output. This version allows multiple log messages
* to be documentated on an interface.
*
*/
@Target({ ElementType.TYPE, ElementType.METHOD })
public @interface LogMessageDocs {
/**
* A list of {@link LogMessageDoc} elements.
*
* @return the list of log message doc
*/
LogMessageDoc[] value();
}
package net.onrc.onos.of.ctl.debugcounter;
import java.util.ArrayList;
import java.util.Arrays;
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.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.common.collect.Sets;
/**
* This class implements a central store for all counters used for debugging the
* system. For counters based on traffic-type, see ICounterStoreService.
*
*/
public class DebugCounter implements IDebugCounterService {
protected static final Logger log = LoggerFactory.getLogger(DebugCounter.class);
/**
* registered counters need a counter id.
*/
protected AtomicInteger counterIdCounter = new AtomicInteger();
/**
* The counter value.
*/
protected static class MutableLong {
long value = 0;
public void increment() { value += 1; }
public void increment(long incr) { value += incr; }
public long get() { return value; }
public void set(long val) { value = val; }
}
/**
* protected class to store counter information.
*/
public static class CounterInfo {
String moduleCounterHierarchy;
String counterDesc;
CounterType ctype;
String moduleName;
String counterHierarchy;
int counterId;
boolean enabled;
String[] metaData;
public CounterInfo(int counterId, boolean enabled,
String moduleName, String counterHierarchy,
String desc, CounterType ctype, String... metaData) {
this.moduleCounterHierarchy = moduleName + "/" + counterHierarchy;
this.moduleName = moduleName;
this.counterHierarchy = counterHierarchy;
this.counterDesc = desc;
this.ctype = ctype;
this.counterId = counterId;
this.enabled = enabled;
this.metaData = metaData;
}
public String getModuleCounterHierarchy() { return moduleCounterHierarchy; }
public String getCounterDesc() { return counterDesc; }
public CounterType getCtype() { return ctype; }
public String getModuleName() { return moduleName; }
public String getCounterHierarchy() { return counterHierarchy; }
public int getCounterId() { return counterId; }
public boolean isEnabled() { return enabled; }
public String[] getMetaData() { return this.metaData.clone(); }
}
//******************
// Global stores
//******************
/**
* Counter info for a debug counter.
*/
public static class DebugCounterInfo {
CounterInfo cinfo;
AtomicLong cvalue;
public DebugCounterInfo(CounterInfo cinfo) {
this.cinfo = cinfo;
this.cvalue = new AtomicLong();
}
public CounterInfo getCounterInfo() {
return cinfo;
}
public Long getCounterValue() {
return cvalue.get();
}
}
/**
* Global debug-counter storage across all threads. These are
* updated from the local per thread counters by the flush counters method.
*/
private static final DebugCounterInfo[] ALLCOUNTERS =
new DebugCounterInfo[MAX_COUNTERS];
/**
* per module counters, indexed by the module name and storing three levels
* of Counter information in the form of CounterIndexStore.
*/
protected ConcurrentHashMap<String, ConcurrentHashMap<String, CounterIndexStore>>
moduleCounters = new ConcurrentHashMap<String,
ConcurrentHashMap<String,
CounterIndexStore>>();
protected static class CounterIndexStore {
int index;
Map<String, CounterIndexStore> nextLevel;
public CounterIndexStore(int index, Map<String, CounterIndexStore> cis) {
this.index = index;
this.nextLevel = cis;
}
}
/**
* fast global cache for counter ids that are currently active.
*/
protected Set<Integer> currentCounters = Collections.newSetFromMap(
new ConcurrentHashMap<Integer, Boolean>());
//******************
// Thread local stores
//******************
/**
* Thread local storage of counter info.
*/
protected static class LocalCounterInfo {
boolean enabled;
MutableLong cvalue;
public LocalCounterInfo(boolean enabled) {
this.enabled = enabled;
this.cvalue = new MutableLong();
}
}
/**
* Thread local debug counters used for maintaining counters local to a thread.
*/
protected final ThreadLocal<LocalCounterInfo[]> threadlocalCounters =
new ThreadLocal<LocalCounterInfo[]>() {
@Override
protected LocalCounterInfo[] initialValue() {
return new LocalCounterInfo[MAX_COUNTERS];
}
};
/**
* Thread local cache for counter ids that are currently active.
*/
protected final ThreadLocal<Set<Integer>> threadlocalCurrentCounters =
new ThreadLocal<Set<Integer>>() {
@Override
protected Set<Integer> initialValue() {
return new HashSet<Integer>();
}
};
//*******************************
// IDebugCounter
//*******************************
protected class CounterImpl implements IDebugCounter {
private final int counterId;
public CounterImpl(int counterId) {
this.counterId = counterId;
}
@Override
public void updateCounterWithFlush() {
if (!validCounterId()) {
return;
}
updateCounter(counterId, 1, true);
}
@Override
public void updateCounterNoFlush() {
if (!validCounterId()) {
return;
}
updateCounter(counterId, 1, false);
}
@Override
public void updateCounterWithFlush(int incr) {
if (!validCounterId()) {
return;
}
updateCounter(counterId, incr, true);
}
@Override
public void updateCounterNoFlush(int incr) {
if (!validCounterId()) {
return;
}
updateCounter(counterId, incr, false);
}
@Override
public long getCounterValue() {
if (!validCounterId()) {
return -1;
}
return ALLCOUNTERS[counterId].cvalue.get();
}
/**
* Checks if this is a valid counter.
* @return true if the counter id is valid
*/
private boolean validCounterId() {
if (counterId < 0 || counterId >= MAX_COUNTERS) {
log.error("Invalid counterId invoked");
return false;
}
return true;
}
}
//*******************************
// IDebugCounterService
//*******************************
@Override
public IDebugCounter registerCounter(String moduleName, String counterHierarchy,
String counterDescription, CounterType counterType,
String... metaData)
throws CounterException {
// check if counter already exists
if (!moduleCounters.containsKey(moduleName)) {
moduleCounters.putIfAbsent(moduleName,
new ConcurrentHashMap<String, CounterIndexStore>());
}
RetCtrInfo rci = getCounterId(moduleName, counterHierarchy);
if (rci.allLevelsFound) {
// counter exists
log.info("Counter exists for {}/{} -- resetting counters", moduleName,
counterHierarchy);
resetCounterHierarchy(moduleName, counterHierarchy);
return new CounterImpl(rci.ctrIds[rci.foundUptoLevel - 1]);
}
// check for validity of counter
if (rci.levels.length > MAX_HIERARCHY) {
String err = "Registry of counterHierarchy " + counterHierarchy +
" exceeds max hierachy " + MAX_HIERARCHY + ".. aborting";
throw new MaxHierarchyRegistered(err);
}
if (rci.foundUptoLevel < rci.levels.length - 1) {
StringBuilder sb = new StringBuilder();
for (int i = 0; i <= rci.foundUptoLevel; i++) {
sb.append(rci.levels[i]);
}
String needToRegister = sb.toString();
String err = "Attempting to register hierarchical counterHierarchy " +
counterHierarchy + " but parts of hierarchy missing. " +
"Please register " + needToRegister + " first";
throw new MissingHierarchicalLevel(err);
}
// get a new counter id
int counterId = counterIdCounter.getAndIncrement();
if (counterId >= MAX_COUNTERS) {
throw new MaxCountersRegistered("max counters reached");
}
// create storage for counter
boolean enabled = (counterType == CounterType.ALWAYS_COUNT) ? true : false;
CounterInfo ci = new CounterInfo(counterId, enabled, moduleName,
counterHierarchy, counterDescription,
counterType, metaData);
ALLCOUNTERS[counterId] = new DebugCounterInfo(ci);
// account for the new counter in the module counter hierarchy
addToModuleCounterHierarchy(moduleName, counterId, rci);
// finally add to active counters
if (enabled) {
currentCounters.add(counterId);
}
return new CounterImpl(counterId);
}
private void updateCounter(int counterId, int incr, boolean flushNow) {
if (counterId < 0 || counterId >= MAX_COUNTERS) {
return;
}
LocalCounterInfo[] thiscounters = this.threadlocalCounters.get();
if (thiscounters[counterId] == null) {
// seeing this counter for the first time in this thread - create local
// store by consulting global store
DebugCounterInfo dc = ALLCOUNTERS[counterId];
if (dc != null) {
thiscounters[counterId] = new LocalCounterInfo(dc.cinfo.enabled);
if (dc.cinfo.enabled) {
Set<Integer> thisset = this.threadlocalCurrentCounters.get();
thisset.add(counterId);
}
} else {
log.error("updateCounter seen locally for counter {} but no global"
+ "storage exists for it yet .. not updating", counterId);
return;
}
}
// update local store if enabled locally for updating
LocalCounterInfo lc = thiscounters[counterId];
if (lc.enabled) {
lc.cvalue.increment(incr);
if (flushNow) {
DebugCounterInfo dc = ALLCOUNTERS[counterId];
if (dc.cinfo.enabled) {
// globally enabled - flush now
dc.cvalue.addAndGet(lc.cvalue.get());
lc.cvalue.set(0);
} else {
// global counter is disabled - don't flush, disable locally
lc.enabled = false;
Set<Integer> thisset = this.threadlocalCurrentCounters.get();
thisset.remove(counterId);
}
}
}
}
@Override
public void flushCounters() {
LocalCounterInfo[] thiscounters = this.threadlocalCounters.get();
Set<Integer> thisset = this.threadlocalCurrentCounters.get();
ArrayList<Integer> temp = new ArrayList<Integer>();
for (int counterId : thisset) {
LocalCounterInfo lc = thiscounters[counterId];
if (lc.cvalue.get() > 0) {
DebugCounterInfo dc = ALLCOUNTERS[counterId];
if (dc.cinfo.enabled) {
// globally enabled - flush now
dc.cvalue.addAndGet(lc.cvalue.get());
lc.cvalue.set(0);
} else {
// global counter is disabled - don't flush, disable locally
lc.enabled = false;
temp.add(counterId);
}
}
}
for (int cId : temp) {
thisset.remove(cId);
}
// At this point it is possible that the thread-local set does not
// include a counter that has been enabled and is present in the global set.
// We need to sync thread-local currently enabled set of counterIds with
// the global set.
Sets.SetView<Integer> sv = Sets.difference(currentCounters, thisset);
for (int counterId : sv) {
if (thiscounters[counterId] != null) {
thiscounters[counterId].enabled = true;
thisset.add(counterId);
}
}
}
@Override
public void resetCounterHierarchy(String moduleName, String counterHierarchy) {
RetCtrInfo rci = getCounterId(moduleName, counterHierarchy);
if (!rci.allLevelsFound) {
String missing = rci.levels[rci.foundUptoLevel];
log.error("Cannot reset counter hierarchy - missing counter {}", missing);
return;
}
// reset at this level
ALLCOUNTERS[rci.ctrIds[rci.foundUptoLevel - 1]].cvalue.set(0);
// reset all levels below
ArrayList<Integer> resetIds = getHierarchyBelow(moduleName, rci);
for (int index : resetIds) {
ALLCOUNTERS[index].cvalue.set(0);
}
}
@Override
public void resetAllCounters() {
RetCtrInfo rci = new RetCtrInfo();
rci.levels = "".split("/");
for (String moduleName : moduleCounters.keySet()) {
ArrayList<Integer> resetIds = getHierarchyBelow(moduleName, rci);
for (int index : resetIds) {
ALLCOUNTERS[index].cvalue.set(0);
}
}
}
@Override
public void resetAllModuleCounters(String moduleName) {
Map<String, CounterIndexStore> target = moduleCounters.get(moduleName);
RetCtrInfo rci = new RetCtrInfo();
rci.levels = "".split("/");
if (target != null) {
ArrayList<Integer> resetIds = getHierarchyBelow(moduleName, rci);
for (int index : resetIds) {
ALLCOUNTERS[index].cvalue.set(0);
}
} else {
if (log.isDebugEnabled()) {
log.debug("No module found with name {}", moduleName);
}
}
}
@Override
public void enableCtrOnDemand(String moduleName, String counterHierarchy) {
RetCtrInfo rci = getCounterId(moduleName, counterHierarchy);
if (!rci.allLevelsFound) {
String missing = rci.levels[rci.foundUptoLevel];
log.error("Cannot enable counter - counter not found {}", missing);
return;
}
// enable specific counter
DebugCounterInfo dc = ALLCOUNTERS[rci.ctrIds[rci.foundUptoLevel - 1]];
dc.cinfo.enabled = true;
currentCounters.add(dc.cinfo.counterId);
}
@Override
public void disableCtrOnDemand(String moduleName, String counterHierarchy) {
RetCtrInfo rci = getCounterId(moduleName, counterHierarchy);
if (!rci.allLevelsFound) {
String missing = rci.levels[rci.foundUptoLevel];
log.error("Cannot disable counter - counter not found {}", missing);
return;
}
// disable specific counter
DebugCounterInfo dc = ALLCOUNTERS[rci.ctrIds[rci.foundUptoLevel - 1]];
if (dc.cinfo.ctype == CounterType.COUNT_ON_DEMAND) {
dc.cinfo.enabled = false;
dc.cvalue.set(0);
currentCounters.remove(dc.cinfo.counterId);
}
}
@Override
public List<DebugCounterInfo> getCounterHierarchy(String moduleName,
String counterHierarchy) {
RetCtrInfo rci = getCounterId(moduleName, counterHierarchy);
if (!rci.allLevelsFound) {
String missing = rci.levels[rci.foundUptoLevel];
log.error("Cannot fetch counter - counter not found {}", missing);
return Collections.emptyList();
}
ArrayList<DebugCounterInfo> dcilist = new ArrayList<DebugCounterInfo>();
// get counter and all below it
DebugCounterInfo dc = ALLCOUNTERS[rci.ctrIds[rci.foundUptoLevel - 1]];
dcilist.add(dc);
ArrayList<Integer> belowIds = getHierarchyBelow(moduleName, rci);
for (int index : belowIds) {
dcilist.add(ALLCOUNTERS[index]);
}
return dcilist;
}
@Override
public List<DebugCounterInfo> getAllCounterValues() {
List<DebugCounterInfo> dcilist = new ArrayList<DebugCounterInfo>();
RetCtrInfo rci = new RetCtrInfo();
rci.levels = "".split("/");
for (String moduleName : moduleCounters.keySet()) {
ArrayList<Integer> resetIds = getHierarchyBelow(moduleName, rci);
for (int index : resetIds) {
dcilist.add(ALLCOUNTERS[index]);
}
}
return dcilist;
}
@Override
public List<DebugCounterInfo> getModuleCounterValues(String moduleName) {
List<DebugCounterInfo> dcilist = new ArrayList<DebugCounterInfo>();
RetCtrInfo rci = new RetCtrInfo();
rci.levels = "".split("/");
if (moduleCounters.containsKey(moduleName)) {
ArrayList<Integer> resetIds = getHierarchyBelow(moduleName, rci);
for (int index : resetIds) {
dcilist.add(ALLCOUNTERS[index]);
}
}
return dcilist;
}
@Override
public boolean containsModuleCounterHierarchy(String moduleName,
String counterHierarchy) {
if (!moduleCounters.containsKey(moduleName)) {
return false;
}
RetCtrInfo rci = getCounterId(moduleName, counterHierarchy);
return rci.allLevelsFound;
}
@Override
public boolean containsModuleName(String moduleName) {
return (moduleCounters.containsKey(moduleName)) ? true : false;
}
@Override
public List<String> getModuleList() {
List<String> retval = new ArrayList<String>();
retval.addAll(moduleCounters.keySet());
return retval;
}
@Override
public List<String> getModuleCounterList(String moduleName) {
if (!moduleCounters.containsKey(moduleName)) {
return Collections.emptyList();
}
List<String> retval = new ArrayList<String>();
RetCtrInfo rci = new RetCtrInfo();
rci.levels = "".split("/");
ArrayList<Integer> cids = getHierarchyBelow(moduleName, rci);
for (int index : cids) {
retval.add(ALLCOUNTERS[index].cinfo.counterHierarchy);
}
return retval;
}
//*******************************
// Internal Methods
//*******************************
protected class RetCtrInfo {
boolean allLevelsFound; // counter indices found all the way down the hierarchy
boolean hierarchical; // true if counterHierarchy is hierarchical
int foundUptoLevel;
int[] ctrIds;
String[] levels;
public RetCtrInfo() {
ctrIds = new int[MAX_HIERARCHY];
for (int i = 0; i < MAX_HIERARCHY; i++) {
ctrIds[i] = -1;
}
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + getOuterType().hashCode();
result = prime * result + (allLevelsFound ? 1231 : 1237);
result = prime * result + Arrays.hashCode(ctrIds);
result = prime * result + foundUptoLevel;
result = prime * result + (hierarchical ? 1231 : 1237);
result = prime * result + Arrays.hashCode(levels);
return result;
}
@Override
public boolean equals(Object oth) {
if (!(oth instanceof RetCtrInfo)) {
return false;
}
RetCtrInfo other = (RetCtrInfo) oth;
if (other.allLevelsFound != this.allLevelsFound) {
return false;
}
if (other.hierarchical != this.hierarchical) {
return false;
}
if (other.foundUptoLevel != this.foundUptoLevel) {
return false;
}
if (!Arrays.equals(other.ctrIds, this.ctrIds)) {
return false;
}
if (!Arrays.equals(other.levels, this.levels)) {
return false;
}
return true;
}
private DebugCounter getOuterType() {
return DebugCounter.this;
}
}
protected RetCtrInfo getCounterId(String moduleName, String counterHierarchy) {
RetCtrInfo rci = new RetCtrInfo();
Map<String, CounterIndexStore> templevel = moduleCounters.get(moduleName);
rci.levels = counterHierarchy.split("/");
if (rci.levels.length > 1) {
rci.hierarchical = true;
}
if (templevel == null) {
log.error("moduleName {} does not exist in debugCounters", moduleName);
return rci;
}
/*
if (rci.levels.length > MAX_HIERARCHY) {
// chop off all array elems greater that MAX_HIERARCHY
String[] temp = new String[MAX_HIERARCHY];
System.arraycopy(rci.levels, 0, temp, 0, MAX_HIERARCHY);
rci.levels = temp;
}
*/
for (int i = 0; i < rci.levels.length; i++) {
if (templevel != null) {
CounterIndexStore cis = templevel.get(rci.levels[i]);
if (cis == null) {
// could not find counterHierarchy part at this level
break;
} else {
rci.ctrIds[i] = cis.index;
templevel = cis.nextLevel;
rci.foundUptoLevel++;
if (i == rci.levels.length - 1) {
rci.allLevelsFound = true;
}
}
} else {
// there are no more levels, which means that some part of the
// counterHierarchy has no corresponding map
break;
}
}
return rci;
}
protected void addToModuleCounterHierarchy(String moduleName, int counterId,
RetCtrInfo rci) {
Map<String, CounterIndexStore> target = moduleCounters.get(moduleName);
if (target == null) {
return;
}
CounterIndexStore cis = null;
for (int i = 0; i < rci.foundUptoLevel; i++) {
cis = target.get(rci.levels[i]);
target = cis.nextLevel;
}
if (cis != null) {
if (cis.nextLevel == null) {
cis.nextLevel = new ConcurrentHashMap<String, CounterIndexStore>();
}
cis.nextLevel.put(rci.levels[rci.foundUptoLevel],
new CounterIndexStore(counterId, null));
} else {
target.put(rci.levels[rci.foundUptoLevel],
new CounterIndexStore(counterId, null));
}
}
// given a partial hierarchical counter, return the rest of the hierarchy
protected ArrayList<Integer> getHierarchyBelow(String moduleName, RetCtrInfo rci) {
Map<String, CounterIndexStore> target = moduleCounters.get(moduleName);
CounterIndexStore cis = null;
ArrayList<Integer> retval = new ArrayList<Integer>();
if (target == null) {
return retval;
}
// get to the level given
for (int i = 0; i < rci.foundUptoLevel; i++) {
cis = target.get(rci.levels[i]);
target = cis.nextLevel;
}
if (target == null || rci.foundUptoLevel == MAX_HIERARCHY) {
// no more levels
return retval;
} else {
// recursively get all ids
getIdsAtLevel(target, retval, rci.foundUptoLevel + 1);
}
return retval;
}
protected void getIdsAtLevel(Map<String, CounterIndexStore> hcy,
ArrayList<Integer> retval, int level) {
if (level > MAX_HIERARCHY) {
return;
}
if (hcy == null || retval == null) {
return;
}
// Can return the counter names as well but for now ids are enough.
for (CounterIndexStore cistemp : hcy.values()) {
retval.add(cistemp.index); // value at this level
if (cistemp.nextLevel != null) {
getIdsAtLevel(cistemp.nextLevel, retval, level + 1);
}
}
}
}
package net.onrc.onos.of.ctl.debugcounter;
public interface IDebugCounter {
/**
* Increments the counter by 1 thread-locally, and immediately flushes to
* the global counter storage. This method should be used for counters that
* are updated outside the OF message processing pipeline.
*/
void updateCounterWithFlush();
/**
* Increments the counter by 1 thread-locally. Flushing to the global
* counter storage is delayed (happens with flushCounters() in IDebugCounterService),
* resulting in higher performance. This method should be used for counters
* updated in the OF message processing pipeline.
*/
void updateCounterNoFlush();
/**
* Increments the counter thread-locally by the 'incr' specified, and immediately
* flushes to the global counter storage. This method should be used for counters
* that are updated outside the OF message processing pipeline.
*/
void updateCounterWithFlush(int incr);
/**
* Increments the counter thread-locally by the 'incr' specified. Flushing to the global
* counter storage is delayed (happens with flushCounters() in IDebugCounterService),
* resulting in higher performance. This method should be used for counters
* updated in the OF message processing pipeline.
*/
void updateCounterNoFlush(int incr);
/**
* Retrieve the value of the counter from the global counter store.
*/
long getCounterValue();
}
package net.onrc.onos.of.ctl.debugcounter;
import java.util.List;
import net.onrc.onos.of.ctl.debugcounter.DebugCounter.DebugCounterInfo;
public interface IDebugCounterService {
/**
* Different counter types. Counters that are meant to be counted-on-demand
* need to be separately enabled/disabled.
*/
public enum CounterType {
ALWAYS_COUNT,
COUNT_ON_DEMAND
}
/**
* Debug Counter Qualifiers.
*/
public static final String CTR_MDATA_WARN = "warn";
public static final String CTR_MDATA_ERROR = "error";
public static final String CTR_MDATA_DROP = "drop";
/**
* A limit on the maximum number of counters that can be created.
*/
public static final int MAX_COUNTERS = 5000;
/**
* Exception thrown when MAX_COUNTERS have been registered.
*/
public class MaxCountersRegistered extends CounterException {
private static final long serialVersionUID = 3173747663719376745L;
String errormsg;
public MaxCountersRegistered(String errormsg) {
this.errormsg = errormsg;
}
@Override
public String getMessage() {
return this.errormsg;
}
}
/**
* Exception thrown when MAX_HIERARCHY has been reached.
*/
public class MaxHierarchyRegistered extends CounterException {
private static final long serialVersionUID = 967431358683523871L;
private String errormsg;
public MaxHierarchyRegistered(String errormsg) {
this.errormsg = errormsg;
}
@Override
public String getMessage() {
return this.errormsg;
}
}
/**
* Exception thrown when attempting to register a hierarchical counter
* where higher levels of the hierarchy have not been pre-registered.
*/
public class MissingHierarchicalLevel extends CounterException {
private static final long serialVersionUID = 517315311533995739L;
private String errormsg;
public MissingHierarchicalLevel(String errormsg) {
this.errormsg = errormsg;
}
@Override
public String getMessage() {
return this.errormsg;
}
}
public class CounterException extends Exception {
private static final long serialVersionUID = 2219781500857866035L;
}
/**
* maximum levels of hierarchy.
* Example of moduleName/counterHierarchy:
* switch/00:00:00:00:01:02:03:04/pktin/drops where
* moduleName ==> "switch" and
* counterHierarchy of 3 ==> "00:00:00:00:01:02:03:04/pktin/drops"
*/
public static final int MAX_HIERARCHY = 3;
/**
* All modules that wish to have the DebugCounterService count for them, must
* register their counters by making this call (typically from that module's
* 'startUp' method). The counter can then be updated, displayed, reset etc.
* using the registered moduleName and counterHierarchy.
*
* @param moduleName the name of the module which is registering the
* counter eg. linkdiscovery or controller or switch
* @param counterHierarchy the hierarchical counter name specifying all
* the hierarchical levels that come above it.
* For example: to register a drop counter for
* packet-ins from a switch, the counterHierarchy
* can be "00:00:00:00:01:02:03:04/pktin/drops"
* It is necessary that counters in hierarchical levels
* above have already been pre-registered - in this
* example: "00:00:00:00:01:02:03:04/pktin" and
* "00:00:00:00:01:02:03:04"
* @param counterDescription a descriptive string that gives more information
* of what the counter is measuring. For example,
* "Measures the number of incoming packets seen by
* this module".
* @param counterType One of CounterType. On-demand counter types
* need to be explicitly enabled/disabled using other
* methods in this API -- i.e. registering them is
* not enough to start counting.
* @param metaData variable arguments that qualify a counter
* eg. warn, error etc.
* @return IDebugCounter with update methods that can be
* used to update a counter.
* @throws MaxCountersRegistered
* @throws MaxHierarchyRegistered
* @throws MissingHierarchicalLevel
*/
public IDebugCounter registerCounter(String moduleName, String counterHierarchy,
String counterDescription, CounterType counterType,
String... metaData)
throws CounterException;
/**
* Flush all thread-local counter values (from the current thread)
* to the global counter store. This method is not intended for use by any
* module. It's typical usage is from floodlight core and it is meant
* to flush those counters that are updated in the packet-processing pipeline,
* typically with the 'updateCounterNoFlush" methods in IDebugCounter.
*/
public void flushCounters();
/**
* Resets the value of counters in the hierarchy to zero. Note that the reset
* applies to the level of counter hierarchy specified AND ALL LEVELS BELOW it
* in the hierarchy.
* For example: If a hierarchy exists like "00:00:00:00:01:02:03:04/pktin/drops"
* specifying a reset hierarchy: "00:00:00:00:01:02:03:04"
* will reset all counters for the switch dpid specified;
* while specifying a reset hierarchy: ""00:00:00:00:01:02:03:04/pktin"
* will reset the pktin counter and all levels below it (like drops)
* for the switch dpid specified.
*/
void resetCounterHierarchy(String moduleName, String counterHierarchy);
/**
* Resets the values of all counters in the system.
*/
public void resetAllCounters();
/**
* Resets the values of all counters belonging
* to a module with the given 'moduleName'.
*/
public void resetAllModuleCounters(String moduleName);
/**
* This method applies only to CounterType.COUNT_ON_DEMAND. It is used to
* enable counting on the counter. Note that this step is necessary to start
* counting for these counter types - merely registering the counter is not
* enough (as is the case for CounterType.ALWAYS_COUNT). Newly
* enabled counters start from an initial value of zero.
*
* Enabling a counter in a counterHierarchy enables only THAT counter. It
* does not enable any other part of the counterHierarchy. For example, if
* a hierarchy exists like "00:00:00:00:01:02:03:04/pktin/drops", where the
* 'pktin' and 'drops' counters are CounterType.COUNT_ON_DEMAND, then enabling
* the 'pktin' counter by specifying the counterHierarchy as
* "00:00:00:00:01:02:03:04/pktin" does NOT enable the 'drops' counter.
*/
public void enableCtrOnDemand(String moduleName, String counterHierarchy);
/**
* This method applies only to CounterType.COUNT_ON_DEMAND. It is used to
* enable counting on the counter. Note that disabling a counter results in a loss
* of the counter value. When re-enabled the counter will restart from zero.
*
* Disabling a counter in a counterHierarchy disables only THAT counter. It
* does not disable any other part of the counterHierarchy. For example, if
* a hierarchy exists like "00:00:00:00:01:02:03:04/pktin/drops", where the
* 'pktin' and 'drops' counters are CounterType.COUNT_ON_DEMAND, then disabling
* the 'pktin' counter by specifying the counterHierarchy as
* "00:00:00:00:01:02:03:04/pktin" does NOT disable the 'drops' counter.
*/
public void disableCtrOnDemand(String moduleName, String counterHierarchy);
/**
* Get counter value and associated information for the specified counterHierarchy.
* Note that information on the level of counter hierarchy specified
* AND ALL LEVELS BELOW it in the hierarchy will be returned.
*
* For example,
* if a hierarchy exists like "00:00:00:00:01:02:03:04/pktin/drops", then
* specifying a counterHierarchy of "00:00:00:00:01:02:03:04/pktin" in the
* get call will return information on the 'pktin' as well as the 'drops'
* counters for the switch dpid specified.
*
* @return A list of DebugCounterInfo or an empty list if the counter
* could not be found
*/
public List<DebugCounterInfo> getCounterHierarchy(String moduleName,
String counterHierarchy);
/**
* Get counter values and associated information for all counters in the
* system.
*
* @return the list of values/info or an empty list
*/
public List<DebugCounterInfo> getAllCounterValues();
/**
* Get counter values and associated information for all counters associated
* with a module.
*
* @param moduleName
* @return the list of values/info or an empty list
*/
public List<DebugCounterInfo> getModuleCounterValues(String moduleName);
/**
* Convenience method to figure out if the the given 'counterHierarchy' corresponds
* to a registered counterHierarchy for 'moduleName'. Note that the counter may or
* may not be enabled for counting, but if it is registered the method will
* return true.
*
* @param param
* @return false if moduleCounterHierarchy is not a registered counter
*/
public boolean containsModuleCounterHierarchy(String moduleName,
String counterHierarchy);
/**
* Convenience method to figure out if the the given 'moduleName' corresponds
* to a registered moduleName or not. Note that the module may or may not have
* a counter enabled for counting, but if it is registered the method will
* return true.
*
* @param param
* @return false if moduleName is not a registered counter
*/
public boolean containsModuleName(String moduleName);
/**
* Returns a list of moduleNames registered for debug counters or an empty
* list if no counters have been registered in the system.
*/
public List<String> getModuleList();
/**
* Returns a list of all counters registered for a specific moduleName
* or a empty list.
*/
public List<String> getModuleCounterList(String moduleName);
}
package net.onrc.onos.of.ctl.debugcounter;
import java.util.Collections;
import java.util.List;
import net.onrc.onos.of.ctl.debugcounter.DebugCounter.DebugCounterInfo;
public class NullDebugCounter implements IDebugCounterService {
@Override
public void flushCounters() {
}
@Override
public void resetAllCounters() {
}
@Override
public void resetAllModuleCounters(String moduleName) {
}
@Override
public void resetCounterHierarchy(String moduleName, String counterHierarchy) {
}
@Override
public void enableCtrOnDemand(String moduleName, String counterHierarchy) {
}
@Override
public void disableCtrOnDemand(String moduleName, String counterHierarchy) {
}
@Override
public List<DebugCounterInfo> getCounterHierarchy(String moduleName,
String counterHierarchy) {
return Collections.emptyList();
}
@Override
public List<DebugCounterInfo> getAllCounterValues() {
return Collections.emptyList();
}
@Override
public List<DebugCounterInfo> getModuleCounterValues(String moduleName) {
return Collections.emptyList();
}
@Override
public boolean containsModuleCounterHierarchy(String moduleName,
String counterHierarchy) {
return false;
}
@Override
public boolean containsModuleName(String moduleName) {
return false;
}
@Override
public
IDebugCounter
registerCounter(String moduleName, String counterHierarchy,
String counterDescription,
CounterType counterType, String... metaData)
throws MaxCountersRegistered {
return new NullCounterImpl();
}
@Override
public List<String> getModuleList() {
return Collections.emptyList();
}
@Override
public List<String> getModuleCounterList(String moduleName) {
return Collections.emptyList();
}
public static class NullCounterImpl implements IDebugCounter {
@Override
public void updateCounterWithFlush() {
}
@Override
public void updateCounterNoFlush() {
}
@Override
public void updateCounterWithFlush(int incr) {
}
@Override
public void updateCounterNoFlush(int incr) {
}
@Override
public long getCounterValue() {
return -1;
}
}
}
/**
* Copyright 2011, Big Switch Networks, Inc.
* Originally created by David Erickson, Stanford University
*
* 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 net.onrc.onos.of.ctl.internal;
import java.lang.management.ManagementFactory;
import java.lang.management.RuntimeMXBean;
import java.net.InetSocketAddress;
import java.net.UnknownHostException;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executors;
import net.onrc.onos.of.ctl.IOFSwitchManager;
import net.onrc.onos.of.ctl.Role;
import net.onrc.onos.of.ctl.annotations.LogMessageDoc;
import net.onrc.onos.of.ctl.annotations.LogMessageDocs;
import net.onrc.onos.of.ctl.debugcounter.DebugCounter;
import net.onrc.onos.of.ctl.debugcounter.IDebugCounter;
import net.onrc.onos.of.ctl.debugcounter.IDebugCounterService;
import net.onrc.onos.of.ctl.debugcounter.IDebugCounterService.CounterException;
import net.onrc.onos.of.ctl.debugcounter.IDebugCounterService.CounterType;
import net.onrc.onos.of.ctl.internal.OFChannelHandler.RoleRecvStatus;
import net.onrc.onos.of.ctl.registry.IControllerRegistry;
import net.onrc.onos.of.ctl.registry.RegistryException;
import net.onrc.onos.of.ctl.registry.IControllerRegistry.ControlChangeCallback;
import net.onrc.onos.of.ctl.util.Dpid;
import net.onrc.onos.of.ctl.util.DummySwitchForTesting;
import net.onrc.onos.of.ctl.util.InstanceId;
import net.onrc.onos.of.ctl.IOFSwitch;
import net.onrc.onos.of.ctl.IOFSwitch.PortChangeType;
import org.apache.felix.scr.annotations.Activate;
import org.apache.felix.scr.annotations.Component;
import org.jboss.netty.bootstrap.ServerBootstrap;
import org.jboss.netty.channel.ChannelPipelineFactory;
import org.jboss.netty.channel.group.ChannelGroup;
import org.jboss.netty.channel.group.DefaultChannelGroup;
import org.jboss.netty.channel.socket.nio.NioServerSocketChannelFactory;
import org.projectfloodlight.openflow.protocol.OFDescStatsReply;
import org.projectfloodlight.openflow.protocol.OFFactories;
import org.projectfloodlight.openflow.protocol.OFFactory;
import org.projectfloodlight.openflow.protocol.OFPortDesc;
import org.projectfloodlight.openflow.protocol.OFVersion;
import org.projectfloodlight.openflow.util.HexString;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* The main controller class. Handles all setup and network listeners
* - Distributed ownership control of switch through IControllerRegistryService
*/
@Component(immediate = true)
public class Controller {
protected static final Logger log = LoggerFactory.getLogger(Controller.class);
static final String ERROR_DATABASE =
"The controller could not communicate with the system database.";
protected static final OFFactory FACTORY13 = OFFactories.getFactory(OFVersion.OF_13);
protected static final OFFactory FACTORY10 = OFFactories.getFactory(OFVersion.OF_10);
// connectedSwitches cache contains all connected switch's channelHandlers
// including ones where this controller is a master/equal/slave controller
// as well as ones that have not been activated yet
protected ConcurrentHashMap<Long, OFChannelHandler> connectedSwitches;
// These caches contains only those switches that are active
protected ConcurrentHashMap<Long, IOFSwitch> activeMasterSwitches;
protected ConcurrentHashMap<Long, IOFSwitch> activeEqualSwitches;
// lock to synchronize on, when manipulating multiple caches above
private Object multiCacheLock;
// The controllerNodeIPsCache maps Controller IDs to their IP address.
// It's only used by handleControllerNodeIPsChanged
protected HashMap<String, String> controllerNodeIPsCache;
// Module dependencies
protected IControllerRegistry registryService;
protected IDebugCounterService debugCounters;
private IOFSwitchManager switchManager;
// Configuration options
protected int openFlowPort = 6633;
protected int workerThreads = 0;
// defined counters
private Counters counters;
// Start time of the controller
protected long systemStartTime;
// Flag to always flush flow table on switch reconnect (HA or otherwise)
protected boolean alwaysClearFlowsOnSwAdd = false;
private InstanceId instanceId;
// Perf. related configuration
protected static final int SEND_BUFFER_SIZE = 4 * 1024 * 1024;
protected static final int BATCH_MAX_SIZE = 100;
protected static final boolean ALWAYS_DECODE_ETH = true;
protected boolean addConnectedSwitch(long dpid, OFChannelHandler h) {
if (connectedSwitches.get(dpid) != null) {
log.error("Trying to add connectedSwitch but found a previous "
+ "value for dpid: {}", dpid);
return false;
} else {
log.error("Added switch {}", dpid);
connectedSwitches.put(dpid, h);
return true;
}
}
private boolean validActivation(long dpid) {
if (connectedSwitches.get(dpid) == null) {
log.error("Trying to activate switch but is not in "
+ "connected switches: dpid {}. Aborting ..",
HexString.toHexString(dpid));
return false;
}
if (activeMasterSwitches.get(dpid) != null ||
activeEqualSwitches.get(dpid) != null) {
log.error("Trying to activate switch but it is already "
+ "activated: dpid {}. Found in activeMaster: {} "
+ "Found in activeEqual: {}. Aborting ..", new Object[] {
HexString.toHexString(dpid),
(activeMasterSwitches.get(dpid) == null) ? 'Y' : 'N',
(activeEqualSwitches.get(dpid) == null) ? 'Y' : 'N'});
counters.switchWithSameDpidActivated.updateCounterWithFlush();
return false;
}
return true;
}
/**
* Called when a switch is activated, with this controller's role as MASTER.
*/
protected boolean addActivatedMasterSwitch(long dpid, IOFSwitch sw) {
synchronized (multiCacheLock) {
if (!validActivation(dpid)) {
return false;
}
activeMasterSwitches.put(dpid, sw);
}
//update counters and events
counters.switchActivated.updateCounterWithFlush();
return true;
}
/**
* Called when a switch is activated, with this controller's role as EQUAL.
*/
protected boolean addActivatedEqualSwitch(long dpid, IOFSwitch sw) {
synchronized (multiCacheLock) {
if (!validActivation(dpid)) {
return false;
}
activeEqualSwitches.put(dpid, sw);
}
//update counters and events
counters.switchActivated.updateCounterWithFlush();
return true;
}
/**
* Called when this controller's role for a switch transitions from equal
* to master. For 1.0 switches, we internally refer to the role 'slave' as
* 'equal' - so this transition is equivalent to 'addActivatedMasterSwitch'.
*/
protected void transitionToMasterSwitch(long dpid) {
synchronized (multiCacheLock) {
IOFSwitch sw = activeEqualSwitches.remove(dpid);
if (sw == null) {
log.error("Transition to master called on sw {}, but switch "
+ "was not found in controller-cache", dpid);
return;
}
activeMasterSwitches.put(dpid, sw);
}
}
/**
* Called when this controller's role for a switch transitions to equal.
* For 1.0 switches, we internally refer to the role 'slave' as
* 'equal'.
*/
protected void transitionToEqualSwitch(long dpid) {
synchronized (multiCacheLock) {
IOFSwitch sw = activeMasterSwitches.remove(dpid);
if (sw == null) {
log.error("Transition to equal called on sw {}, but switch "
+ "was not found in controller-cache", dpid);
return;
}
activeEqualSwitches.put(dpid, sw);
}
}
/**
* Clear all state in controller switch maps for a switch that has
* disconnected from the local controller. Also release control for
* that switch from the global repository. Notify switch listeners.
*/
protected void removeConnectedSwitch(long dpid) {
releaseRegistryControl(dpid);
connectedSwitches.remove(dpid);
IOFSwitch sw = activeMasterSwitches.remove(dpid);
if (sw == null) {
sw = activeEqualSwitches.remove(dpid);
}
if (sw != null) {
sw.cancelAllStatisticsReplies();
sw.setConnected(false); // do we need this?
}
counters.switchDisconnected.updateCounterWithFlush();
}
/**
* Indicates that ports on the given switch have changed. Enqueue a
* switch update.
* @param sw
*/
protected void notifyPortChanged(long dpid, OFPortDesc port,
PortChangeType changeType) {
if (port == null || changeType == null) {
String msg = String.format("Switch port or changetType must not "
+ "be null in port change notification");
throw new NullPointerException(msg);
}
if (connectedSwitches.get(dpid) == null || getSwitch(dpid) == null) {
log.warn("Port change update on switch {} not connected or activated "
+ "... Aborting.", HexString.toHexString(dpid));
return;
}
}
// ***************
// Getters/Setters
// ***************
public synchronized void setIOFSwitchManager(IOFSwitchManager swManager) {
this.switchManager = swManager;
this.registryService = swManager.getRegistry();
}
public void setDebugCounter(IDebugCounterService dcs) {
this.debugCounters = dcs;
}
IDebugCounterService getDebugCounter() {
return this.debugCounters;
}
// **********************
// Role Handling
// **********************
/**
* created by ONOS - works with registry service.
*/
protected class RoleChangeCallback implements ControlChangeCallback {
@Override
public void controlChanged(long dpidLong, boolean hasControl) {
Dpid dpid = new Dpid(dpidLong);
log.info("Role change callback for switch {}, hasControl {}",
dpid, hasControl);
Role role = null;
/*
* issue #229
* Cannot rely on sw.getRole() as it can be behind due to pending
* role changes in the queue. Just submit it and late the
* RoleChanger handle duplicates.
*/
if (hasControl) {
role = Role.MASTER;
} else {
role = Role.EQUAL; // treat the same as Role.SLAVE
}
OFChannelHandler swCh = connectedSwitches.get(dpid.value());
if (swCh == null) {
log.warn("Switch {} not found in connected switches", dpid);
return;
}
log.debug("Sending role request {} msg to {}", role, dpid);
swCh.sendRoleRequest(role, RoleRecvStatus.MATCHED_SET_ROLE);
}
}
/**
* Submit request to the registry service for mastership of the
* switch.
* @param dpid this datapath to get role for
*/
public synchronized void submitRegistryRequest(long dpid) {
if (registryService == null) {
/*
* If we have no registry then simply assign
* mastership to this controller.
*/
new RoleChangeCallback().controlChanged(dpid, true);
return;
}
OFChannelHandler h = connectedSwitches.get(dpid);
if (h == null) {
log.error("Trying to request registry control for switch {} "
+ "not in connected switches. Aborting.. ",
HexString.toHexString(dpid));
connectedSwitches.get(dpid).disconnectSwitch();
return;
}
//Request control of the switch from the global registry
try {
h.controlRequested = Boolean.TRUE;
registryService.requestControl(dpid, new RoleChangeCallback());
} catch (RegistryException e) {
log.debug("Registry error: {}", e.getMessage());
h.controlRequested = Boolean.FALSE;
}
if (!h.controlRequested) { // XXX what is being attempted here?
// yield to allow other thread(s) to release control
// TODO AAS: this is awful and needs to be fixed
Thread.yield();
// safer to bounce the switch to reconnect here than proceeding further
// XXX S why? can't we just try again a little later?
log.debug("Closing sw:{} because we weren't able to request control " +
"successfully" + dpid);
connectedSwitches.get(dpid).disconnectSwitch();
}
}
/**
* Relinquish role for the switch.
* @param dpidLong the controlled datapath
*/
public synchronized void releaseRegistryControl(long dpidLong) {
OFChannelHandler h = connectedSwitches.get(dpidLong);
if (h == null) {
log.error("Trying to release registry control for switch {} "
+ "not in connected switches. Aborting.. ",
HexString.toHexString(dpidLong));
return;
}
if (h.controlRequested) {
registryService.releaseControl(dpidLong);
}
}
// ***************
// IFloodlightProviderService
// ***************
// FIXME: remove this method
public Map<Long, IOFSwitch> getSwitches() {
return getMasterSwitches();
}
// FIXME: remove this method
public Map<Long, IOFSwitch> getMasterSwitches() {
return Collections.unmodifiableMap(activeMasterSwitches);
}
public Set<Long> getAllSwitchDpids() {
Set<Long> dpids = new HashSet<Long>();
dpids.addAll(activeMasterSwitches.keySet());
dpids.addAll(activeEqualSwitches.keySet());
return dpids;
}
public Set<Long> getAllMasterSwitchDpids() {
Set<Long> dpids = new HashSet<Long>();
dpids.addAll(activeMasterSwitches.keySet());
return dpids;
}
public Set<Long> getAllEqualSwitchDpids() {
Set<Long> dpids = new HashSet<Long>();
dpids.addAll(activeEqualSwitches.keySet());
return dpids;
}
public IOFSwitch getSwitch(long dpid) {
IOFSwitch sw = null;
sw = activeMasterSwitches.get(dpid);
if (sw != null) {
return sw;
}
sw = activeEqualSwitches.get(dpid);
if (sw != null) {
return sw;
}
return sw;
}
public IOFSwitch getMasterSwitch(long dpid) {
return activeMasterSwitches.get(dpid);
}
public IOFSwitch getEqualSwitch(long dpid) {
return activeEqualSwitches.get(dpid);
}
public OFFactory getOFMessageFactory10() {
return FACTORY10;
}
public OFFactory getOFMessageFactory13() {
return FACTORY13;
}
public Map<String, String> getControllerNodeIPs() {
// We return a copy of the mapping so we can guarantee that
// the mapping return is the same as one that will be (or was)
// dispatched to IHAListeners
HashMap<String, String> retval = new HashMap<String, String>();
synchronized (controllerNodeIPsCache) {
retval.putAll(controllerNodeIPsCache);
}
return retval;
}
public long getSystemStartTime() {
return (this.systemStartTime);
}
public void setAlwaysClearFlowsOnSwAdd(boolean value) {
this.alwaysClearFlowsOnSwAdd = value;
}
public InstanceId getInstanceId() {
return instanceId;
}
// **************
// Initialization
// **************
/**
* Tell controller that we're ready to accept switches loop.
*
* @throws IOException
*/
@LogMessageDocs({
@LogMessageDoc(message = "Listening for switch connections on {address}",
explanation = "The controller is ready and listening for new" +
" switch connections"),
@LogMessageDoc(message = "Storage exception in controller " +
"updates loop; terminating process",
explanation = ERROR_DATABASE,
recommendation = LogMessageDoc.CHECK_CONTROLLER),
@LogMessageDoc(level = "ERROR",
message = "Exception in controller updates loop",
explanation = "Failed to dispatch controller event",
recommendation = LogMessageDoc.GENERIC_ACTION)
})
public void run() {
try {
final ServerBootstrap bootstrap = createServerBootStrap();
bootstrap.setOption("reuseAddr", true);
bootstrap.setOption("child.keepAlive", true);
bootstrap.setOption("child.tcpNoDelay", true);
bootstrap.setOption("child.sendBufferSize", Controller.SEND_BUFFER_SIZE);
ChannelPipelineFactory pfact =
new OpenflowPipelineFactory(this, null);
bootstrap.setPipelineFactory(pfact);
InetSocketAddress sa = new InetSocketAddress(openFlowPort);
final ChannelGroup cg = new DefaultChannelGroup();
cg.add(bootstrap.bind(sa));
log.info("Listening for switch connections on {}", sa);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
private ServerBootstrap createServerBootStrap() {
if (workerThreads == 0) {
return new ServerBootstrap(
new NioServerSocketChannelFactory(
Executors.newCachedThreadPool(),
Executors.newCachedThreadPool()));
} else {
return new ServerBootstrap(
new NioServerSocketChannelFactory(
Executors.newCachedThreadPool(),
Executors.newCachedThreadPool(), workerThreads));
}
}
public void setConfigParams(Map<String, String> configParams) {
String ofPort = configParams.get("openflowport");
if (ofPort != null) {
this.openFlowPort = Integer.parseInt(ofPort);
}
log.debug("OpenFlow port set to {}", this.openFlowPort);
String threads = configParams.get("workerthreads");
if (threads != null) {
this.workerThreads = Integer.parseInt(threads);
}
log.debug("Number of worker threads set to {}", this.workerThreads);
String controllerId = configParams.get("controllerid");
if (controllerId != null) {
this.instanceId = new InstanceId(controllerId);
} else {
//Try to get the hostname of the machine and use that for controller ID
try {
String hostname = java.net.InetAddress.getLocalHost().getHostName();
this.instanceId = new InstanceId(hostname);
} catch (UnknownHostException e) {
log.warn("Can't get hostname, using the default");
}
}
log.debug("ControllerId set to {}", this.instanceId);
}
/**
* Initialize internal data structures.
*/
public void init(Map<String, String> configParams) {
// These data structures are initialized here because other
// module's startUp() might be called before ours
this.activeMasterSwitches = new ConcurrentHashMap<Long, IOFSwitch>();
this.activeEqualSwitches = new ConcurrentHashMap<Long, IOFSwitch>();
this.connectedSwitches = new ConcurrentHashMap<Long, OFChannelHandler>();
this.controllerNodeIPsCache = new HashMap<String, String>();
setConfigParams(configParams);
this.systemStartTime = System.currentTimeMillis();
this.setDebugCounter(new DebugCounter());
this.counters = new Counters();
this.multiCacheLock = new Object();
String option = configParams.get("flushSwitchesOnReconnect");
if (option != null && option.equalsIgnoreCase("true")) {
this.setAlwaysClearFlowsOnSwActivate(true);
log.info("Flush switches on reconnect -- Enabled.");
} else {
this.setAlwaysClearFlowsOnSwActivate(false);
log.info("Flush switches on reconnect -- Disabled");
}
}
/**
* Startup all of the controller's components.
*/
@LogMessageDoc(message = "Waiting for storage source",
explanation = "The system database is not yet ready",
recommendation = "If this message persists, this indicates " +
"that the system database has failed to start. " +
LogMessageDoc.CHECK_CONTROLLER)
public synchronized void startupComponents() {
try {
if (registryService != null) {
registryService.registerController(instanceId.toString());
}
} catch (RegistryException e) {
log.warn("Registry service error: {}", e.getMessage());
}
// register counters and events
try {
this.counters.createCounters(debugCounters);
} catch (CounterException e) {
log.warn("Counters unavailable: {}", e.getMessage());
}
}
// **************
// debugCounter registrations
// **************
public static class Counters {
public static final String PREFIX = "controller";
public IDebugCounter switchActivated;
public IDebugCounter switchWithSameDpidActivated; // warn
public IDebugCounter switchDisconnected;
public IDebugCounter messageReceived;
public IDebugCounter switchDisconnectReadTimeout;
public IDebugCounter switchDisconnectHandshakeTimeout;
public IDebugCounter switchDisconnectIOError;
public IDebugCounter switchDisconnectParseError;
public IDebugCounter switchDisconnectSwitchStateException;
public IDebugCounter rejectedExecutionException;
public IDebugCounter switchDisconnectOtherException;
public IDebugCounter switchConnected;
public IDebugCounter unhandledMessage;
public IDebugCounter packetInWhileSwitchIsSlave;
public IDebugCounter epermErrorWhileSwitchIsMaster;
public IDebugCounter roleReplyTimeout;
public IDebugCounter roleReplyReceived; // expected RoleReply received
public IDebugCounter roleReplyErrorUnsupported;
public IDebugCounter switchCounterRegistrationFailed;
void createCounters(IDebugCounterService debugCounters) throws CounterException {
switchActivated =
debugCounters.registerCounter(
PREFIX, "switch-activated",
"A switch connected to this controller is now " +
"in MASTER role",
CounterType.ALWAYS_COUNT);
switchWithSameDpidActivated = // warn
debugCounters.registerCounter(
PREFIX, "switch-with-same-dpid-activated",
"A switch with the same DPID as another switch " +
"connected to the controller. This can be " +
"caused by multiple switches configured with " +
"the same DPID or by a switch reconnecting very " +
"quickly.",
CounterType.COUNT_ON_DEMAND,
IDebugCounterService.CTR_MDATA_WARN);
switchDisconnected =
debugCounters.registerCounter(
PREFIX, "switch-disconnected",
"FIXME: switch has disconnected",
CounterType.ALWAYS_COUNT);
//------------------------
// channel handler counters. Factor them out ??
messageReceived =
debugCounters.registerCounter(
PREFIX, "message-received",
"Number of OpenFlow messages received. Some of " +
"these might be throttled",
CounterType.ALWAYS_COUNT);
switchDisconnectReadTimeout =
debugCounters.registerCounter(
PREFIX, "switch-disconnect-read-timeout",
"Number of times a switch was disconnected due " +
"due the switch failing to send OpenFlow " +
"messages or responding to OpenFlow ECHOs",
CounterType.ALWAYS_COUNT,
IDebugCounterService.CTR_MDATA_ERROR);
switchDisconnectHandshakeTimeout =
debugCounters.registerCounter(
PREFIX, "switch-disconnect-handshake-timeout",
"Number of times a switch was disconnected " +
"because it failed to complete the handshake " +
"in time.",
CounterType.ALWAYS_COUNT,
IDebugCounterService.CTR_MDATA_ERROR);
switchDisconnectIOError =
debugCounters.registerCounter(
PREFIX, "switch-disconnect-io-error",
"Number of times a switch was disconnected " +
"due to IO errors on the switch connection.",
CounterType.ALWAYS_COUNT,
IDebugCounterService.CTR_MDATA_ERROR);
switchDisconnectParseError =
debugCounters.registerCounter(
PREFIX, "switch-disconnect-parse-error",
"Number of times a switch was disconnected " +
"because it sent an invalid packet that could " +
"not be parsed",
CounterType.ALWAYS_COUNT,
IDebugCounterService.CTR_MDATA_ERROR);
switchDisconnectSwitchStateException =
debugCounters.registerCounter(
PREFIX, "switch-disconnect-switch-state-exception",
"Number of times a switch was disconnected " +
"because it sent messages that were invalid " +
"given the switch connection's state.",
CounterType.ALWAYS_COUNT,
IDebugCounterService.CTR_MDATA_ERROR);
rejectedExecutionException =
debugCounters.registerCounter(
PREFIX, "rejected-execution-exception",
"TODO",
CounterType.ALWAYS_COUNT,
IDebugCounterService.CTR_MDATA_ERROR);
switchDisconnectOtherException =
debugCounters.registerCounter(
PREFIX, "switch-disconnect-other-exception",
"Number of times a switch was disconnected " +
"due to an exceptional situation not covered " +
"by other counters",
CounterType.ALWAYS_COUNT,
IDebugCounterService.CTR_MDATA_ERROR);
switchConnected =
debugCounters.registerCounter(
PREFIX, "switch-connected",
"Number of times a new switch connection was " +
"established",
CounterType.ALWAYS_COUNT);
unhandledMessage =
debugCounters.registerCounter(
PREFIX, "unhandled-message",
"Number of times an OpenFlow message was " +
"received that the controller ignored because " +
"it was inapproriate given the switch " +
"connection's state.",
CounterType.ALWAYS_COUNT,
IDebugCounterService.CTR_MDATA_WARN);
// might be less than warning
packetInWhileSwitchIsSlave =
debugCounters.registerCounter(
PREFIX, "packet-in-while-switch-is-slave",
"Number of times a packet in was received " +
"from a switch that was in SLAVE role. " +
"Possibly inidicates inconsistent roles.",
CounterType.ALWAYS_COUNT);
epermErrorWhileSwitchIsMaster =
debugCounters.registerCounter(
PREFIX, "eperm-error-while-switch-is-master",
"Number of times a permission error was " +
"received while the switch was in MASTER role. " +
"Possibly inidicates inconsistent roles.",
CounterType.ALWAYS_COUNT,
IDebugCounterService.CTR_MDATA_WARN);
roleReplyTimeout =
debugCounters.registerCounter(
PREFIX, "role-reply-timeout",
"Number of times a role request message did not " +
"receive the expected reply from a switch",
CounterType.ALWAYS_COUNT,
IDebugCounterService.CTR_MDATA_WARN);
roleReplyReceived = // expected RoleReply received
debugCounters.registerCounter(
PREFIX, "role-reply-received",
"Number of times the controller received the " +
"expected role reply message from a switch",
CounterType.ALWAYS_COUNT);
roleReplyErrorUnsupported =
debugCounters.registerCounter(
PREFIX, "role-reply-error-unsupported",
"Number of times the controller received an " +
"error from a switch in response to a role " +
"request indicating that the switch does not " +
"support roles.",
CounterType.ALWAYS_COUNT);
switchCounterRegistrationFailed =
debugCounters.registerCounter(PREFIX,
"switch-counter-registration-failed",
"Number of times the controller failed to " +
"register per-switch debug counters",
CounterType.ALWAYS_COUNT,
IDebugCounterService.CTR_MDATA_WARN);
}
}
public Counters getCounters() {
return this.counters;
}
// **************
// Utility methods
// **************
public void setAlwaysClearFlowsOnSwActivate(boolean value) {
//this.alwaysClearFlowsOnSwActivate = value;
// XXX S need to be a little more careful about this
}
public Map<String, Long> getMemory() {
Map<String, Long> m = new HashMap<String, Long>();
Runtime runtime = Runtime.getRuntime();
m.put("total", runtime.totalMemory());
m.put("free", runtime.freeMemory());
return m;
}
public Long getUptime() {
RuntimeMXBean rb = ManagementFactory.getRuntimeMXBean();
return rb.getUptime();
}
/**
* Forward to the driver-manager to get an IOFSwitch instance.
* @param desc
* @return
*/
protected IOFSwitch getOFSwitchInstance(OFDescStatsReply desc, OFVersion ofv) {
if (switchManager == null) {
return new DummySwitchForTesting();
}
return switchManager.getSwitchImpl(desc.getMfrDesc(), desc.getHwDesc(),
desc.getSwDesc(), ofv);
}
@Activate
public void activate() {
log.info("Initialising OpenFlow Lib and IO");
this.init(new HashMap<String, String>());
this.startupComponents();
this.run();
}
}
/**
* Copyright 2011, Big Switch Networks, Inc.
* Originally created by David Erickson, Stanford University
*
* 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 net.onrc.onos.of.ctl.internal;
/**
* Exception is thrown when the handshake fails to complete.
* before a specified time
*
*/
public class HandshakeTimeoutException extends Exception {
private static final long serialVersionUID = 6859880268940337312L;
}
/**
* Copyright 2011, Big Switch Networks, Inc.
* Originally created by David Erickson, Stanford University
*
* 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 net.onrc.onos.of.ctl.internal;
import java.util.concurrent.TimeUnit;
import org.jboss.netty.channel.ChannelHandlerContext;
import org.jboss.netty.channel.ChannelStateEvent;
import org.jboss.netty.channel.Channels;
import org.jboss.netty.channel.SimpleChannelUpstreamHandler;
import org.jboss.netty.util.Timeout;
import org.jboss.netty.util.Timer;
import org.jboss.netty.util.TimerTask;
/**
* Trigger a timeout if a switch fails to complete handshake soon enough.
*/
public class HandshakeTimeoutHandler
extends SimpleChannelUpstreamHandler {
static final HandshakeTimeoutException EXCEPTION =
new HandshakeTimeoutException();
final OFChannelHandler channelHandler;
final Timer timer;
final long timeoutNanos;
volatile Timeout timeout;
public HandshakeTimeoutHandler(OFChannelHandler channelHandler,
Timer timer,
long timeoutSeconds) {
super();
this.channelHandler = channelHandler;
this.timer = timer;
this.timeoutNanos = TimeUnit.SECONDS.toNanos(timeoutSeconds);
}
@Override
public void channelOpen(ChannelHandlerContext ctx, ChannelStateEvent e)
throws Exception {
if (timeoutNanos > 0) {
timeout = timer.newTimeout(new HandshakeTimeoutTask(ctx),
timeoutNanos, TimeUnit.NANOSECONDS);
}
ctx.sendUpstream(e);
}
@Override
public void channelClosed(ChannelHandlerContext ctx, ChannelStateEvent e)
throws Exception {
if (timeout != null) {
timeout.cancel();
timeout = null;
}
}
private final class HandshakeTimeoutTask implements TimerTask {
private final ChannelHandlerContext ctx;
HandshakeTimeoutTask(ChannelHandlerContext ctx) {
this.ctx = ctx;
}
@Override
public void run(Timeout t) throws Exception {
if (t.isCancelled()) {
return;
}
if (!ctx.getChannel().isOpen()) {
return;
}
if (!channelHandler.isHandshakeComplete()) {
Channels.fireExceptionCaught(ctx, EXCEPTION);
}
}
}
}
package net.onrc.onos.of.ctl.internal;
import java.io.IOException;
import java.nio.channels.ClosedChannelException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.RejectedExecutionException;
import net.onrc.onos.of.ctl.IOFSwitch;
import net.onrc.onos.of.ctl.IOFSwitch.PortChangeEvent;
import net.onrc.onos.of.ctl.Role;
import net.onrc.onos.of.ctl.annotations.LogMessageDoc;
import net.onrc.onos.of.ctl.annotations.LogMessageDocs;
import net.onrc.onos.of.ctl.debugcounter.IDebugCounterService.CounterException;
import net.onrc.onos.of.ctl.internal.Controller.Counters;
import net.onrc.onos.of.ctl.internal.OFChannelHandler.ChannelState.RoleReplyInfo;
import org.jboss.netty.channel.Channel;
import org.jboss.netty.channel.ChannelHandlerContext;
import org.jboss.netty.channel.ChannelStateEvent;
import org.jboss.netty.channel.ExceptionEvent;
import org.jboss.netty.channel.MessageEvent;
import org.jboss.netty.handler.timeout.IdleStateAwareChannelHandler;
import org.jboss.netty.handler.timeout.IdleStateEvent;
import org.jboss.netty.handler.timeout.ReadTimeoutException;
import org.projectfloodlight.openflow.exceptions.OFParseError;
import org.projectfloodlight.openflow.protocol.OFAsyncGetReply;
import org.projectfloodlight.openflow.protocol.OFBadRequestCode;
import org.projectfloodlight.openflow.protocol.OFBarrierReply;
import org.projectfloodlight.openflow.protocol.OFBarrierRequest;
import org.projectfloodlight.openflow.protocol.OFControllerRole;
import org.projectfloodlight.openflow.protocol.OFDescStatsReply;
import org.projectfloodlight.openflow.protocol.OFDescStatsRequest;
import org.projectfloodlight.openflow.protocol.OFEchoReply;
import org.projectfloodlight.openflow.protocol.OFEchoRequest;
import org.projectfloodlight.openflow.protocol.OFErrorMsg;
import org.projectfloodlight.openflow.protocol.OFErrorType;
import org.projectfloodlight.openflow.protocol.OFExperimenter;
import org.projectfloodlight.openflow.protocol.OFFactory;
import org.projectfloodlight.openflow.protocol.OFFeaturesReply;
import org.projectfloodlight.openflow.protocol.OFFlowModFailedCode;
import org.projectfloodlight.openflow.protocol.OFFlowRemoved;
import org.projectfloodlight.openflow.protocol.OFGetConfigReply;
import org.projectfloodlight.openflow.protocol.OFGetConfigRequest;
import org.projectfloodlight.openflow.protocol.OFHello;
import org.projectfloodlight.openflow.protocol.OFHelloElem;
import org.projectfloodlight.openflow.protocol.OFMessage;
import org.projectfloodlight.openflow.protocol.OFNiciraControllerRole;
import org.projectfloodlight.openflow.protocol.OFNiciraControllerRoleReply;
import org.projectfloodlight.openflow.protocol.OFPacketIn;
import org.projectfloodlight.openflow.protocol.OFPortDescStatsReply;
import org.projectfloodlight.openflow.protocol.OFPortDescStatsRequest;
import org.projectfloodlight.openflow.protocol.OFPortStatus;
import org.projectfloodlight.openflow.protocol.OFQueueGetConfigReply;
import org.projectfloodlight.openflow.protocol.OFRoleReply;
import org.projectfloodlight.openflow.protocol.OFRoleRequest;
import org.projectfloodlight.openflow.protocol.OFSetConfig;
import org.projectfloodlight.openflow.protocol.OFStatsReply;
import org.projectfloodlight.openflow.protocol.OFStatsReplyFlags;
import org.projectfloodlight.openflow.protocol.OFStatsType;
import org.projectfloodlight.openflow.protocol.OFType;
import org.projectfloodlight.openflow.protocol.OFVersion;
import org.projectfloodlight.openflow.protocol.errormsg.OFBadRequestErrorMsg;
import org.projectfloodlight.openflow.protocol.errormsg.OFFlowModFailedErrorMsg;
import org.projectfloodlight.openflow.protocol.errormsg.OFRoleRequestFailedErrorMsg;
import org.projectfloodlight.openflow.types.U32;
import org.projectfloodlight.openflow.types.U64;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Channel handler deals with the switch connection and dispatches
* switch messages to the appropriate locations.
*/
class OFChannelHandler extends IdleStateAwareChannelHandler {
private static final Logger log = LoggerFactory.getLogger(OFChannelHandler.class);
private static final long DEFAULT_ROLE_TIMEOUT_MS = 2 * 1000; // 10 sec
private final Controller controller;
private final Counters counters;
private IOFSwitch sw;
private long thisdpid; // channelHandler cached value of connected switch id
private Channel channel;
// State needs to be volatile because the HandshakeTimeoutHandler
// needs to check if the handshake is complete
private volatile ChannelState state;
// All role messaging is handled by the roleChanger. The channel state machine
// coordinates between the roleChanger and the controller-global-registry-service
// to determine controller roles per switch.
private RoleChanger roleChanger;
// Used to coordinate between the controller and the cleanup thread(?)
// for access to the global registry on a per switch basis.
volatile Boolean controlRequested;
// When a switch with a duplicate dpid is found (i.e we already have a
// connected switch with the same dpid), the new switch is immediately
// disconnected. At that point netty callsback channelDisconnected() which
// proceeds to cleaup switch state - we need to ensure that it does not cleanup
// switch state for the older (still connected) switch
private volatile Boolean duplicateDpidFound;
// Temporary storage for switch-features and port-description
private OFFeaturesReply featuresReply;
private OFPortDescStatsReply portDescReply;
// a concurrent ArrayList to temporarily store port status messages
// before we are ready to deal with them
private final CopyOnWriteArrayList<OFPortStatus> pendingPortStatusMsg;
//Indicates the openflow version used by this switch
protected OFVersion ofVersion;
protected OFFactory factory13;
protected OFFactory factory10;
/** transaction Ids to use during handshake. Since only one thread
* calls into an OFChannelHandler instance, we don't need atomic.
* We will count down
*/
private int handshakeTransactionIds = -1;
/**
* Create a new unconnected OFChannelHandler.
* @param controller
*/
OFChannelHandler(Controller controller) {
this.controller = controller;
this.counters = controller.getCounters();
this.roleChanger = new RoleChanger(DEFAULT_ROLE_TIMEOUT_MS);
this.state = ChannelState.INIT;
this.pendingPortStatusMsg = new CopyOnWriteArrayList<OFPortStatus>();
factory13 = controller.getOFMessageFactory13();
factory10 = controller.getOFMessageFactory10();
controlRequested = Boolean.FALSE;
duplicateDpidFound = Boolean.FALSE;
}
//*******************
// Role Handling
//*******************
/**
* When we remove a pending role request we use this enum to indicate how we
* arrived at the decision. When we send a role request to the switch, we
* also use this enum to indicate what we expect back from the switch, so the
* role changer can match the reply to our expectation.
*/
public enum RoleRecvStatus {
/** The switch returned an error indicating that roles are not.
* supported*/
UNSUPPORTED,
/** The request timed out. */
NO_REPLY,
/** The reply was old, there is a newer request pending. */
OLD_REPLY,
/**
* The reply's role matched the role that this controller set in the
* request message - invoked either initially at startup or to reassert
* current role.
*/
MATCHED_CURRENT_ROLE,
/**
* The reply's role matched the role that this controller set in the
* request message - this is the result of a callback from the
* global registry, followed by a role request sent to the switch.
*/
MATCHED_SET_ROLE,
/**
* The reply's role was a response to the query made by this controller.
*/
REPLY_QUERY,
/** We received a role reply message from the switch
* but the expectation was unclear, or there was no expectation.
*/
OTHER_EXPECTATION,
}
/**
* Forwards to RoleChanger. See there.
* @param role
*/
public void sendRoleRequest(Role role, RoleRecvStatus expectation) {
try {
roleChanger.sendRoleRequest(role, expectation);
} catch (IOException e) {
log.error("Disconnecting switch {} due to IO Error: {}",
getSwitchInfoString(), e.getMessage());
channel.close();
}
}
// XXX S consider if necessary
public void disconnectSwitch() {
sw.disconnectSwitch();
}
/**
* A utility class to handle role requests and replies for this channel.
* After a role request is submitted the role changer keeps track of the
* pending request, collects the reply (if any) and times out the request
* if necessary.
*
* To simplify role handling we only keep track of the /last/ pending
* role reply send to the switch. If multiple requests are pending and
* we receive replies for earlier requests we ignore them. However, this
* way of handling pending requests implies that we could wait forever if
* a new request is submitted before the timeout triggers. If necessary
* we could work around that though.
*/
private class RoleChanger {
// indicates that a request is currently pending
// needs to be volatile to allow correct double-check idiom
private volatile boolean requestPending;
// the transaction Id of the pending request
private int pendingXid;
// the role that's pending
private Role pendingRole;
// system time in MS when we send the request
private long roleSubmitTime;
// the timeout to use
private final long roleTimeoutMs;
// the expectation set by the caller for the returned role
private RoleRecvStatus expectation;
public RoleChanger(long roleTimeoutMs) {
this.requestPending = false;
this.roleSubmitTime = 0;
this.pendingXid = -1;
this.pendingRole = null;
this.roleTimeoutMs = roleTimeoutMs;
this.expectation = RoleRecvStatus.MATCHED_CURRENT_ROLE;
}
/**
* Send NX role request message to the switch requesting the specified
* role.
*
* @param sw switch to send the role request message to
* @param role role to request
*/
private int sendNxRoleRequest(Role role) throws IOException {
// Convert the role enum to the appropriate role to send
OFNiciraControllerRole roleToSend = OFNiciraControllerRole.ROLE_OTHER;
switch (role) {
case MASTER:
roleToSend = OFNiciraControllerRole.ROLE_MASTER;
break;
case SLAVE:
case EQUAL:
default:
// ensuring that the only two roles sent to 1.0 switches with
// Nicira role support, are MASTER and SLAVE
roleToSend = OFNiciraControllerRole.ROLE_SLAVE;
log.warn("Sending Nx Role.SLAVE to switch {}.", sw);
}
int xid = sw.getNextTransactionId();
OFExperimenter roleRequest = factory10
.buildNiciraControllerRoleRequest()
.setXid(xid)
.setRole(roleToSend)
.build();
sw.write(Collections.<OFMessage>singletonList(roleRequest));
return xid;
}
private int sendOF13RoleRequest(Role role) throws IOException {
// Convert the role enum to the appropriate role to send
OFControllerRole roleToSend = OFControllerRole.ROLE_NOCHANGE;
switch (role) {
case EQUAL:
roleToSend = OFControllerRole.ROLE_EQUAL;
break;
case MASTER:
roleToSend = OFControllerRole.ROLE_MASTER;
break;
case SLAVE:
roleToSend = OFControllerRole.ROLE_SLAVE;
break;
default:
log.warn("Sending default role.noChange to switch {}."
+ " Should only be used for queries.", sw);
}
int xid = sw.getNextTransactionId();
OFRoleRequest rrm = factory13
.buildRoleRequest()
.setRole(roleToSend)
.setXid(xid)
.setGenerationId(sw.getNextGenerationId())
.build();
sw.write(rrm);
return xid;
}
/**
* Send a role request with the given role to the switch and update
* the pending request and timestamp.
* Sends an OFPT_ROLE_REQUEST to an OF1.3 switch, OR
* Sends an NX_ROLE_REQUEST to an OF1.0 switch if configured to support it
* in the IOFSwitch driver. If not supported, this method sends nothing
* and returns 'false'. The caller should take appropriate action.
*
* One other optimization we do here is that for OF1.0 switches with
* Nicira role message support, we force the Role.EQUAL to become
* Role.SLAVE, as there is no defined behavior for the Nicira role OTHER.
* We cannot expect it to behave like SLAVE. We don't have this problem with
* OF1.3 switches, because Role.EQUAL is well defined and we can simulate
* SLAVE behavior by using ASYNC messages.
*
* @param role
* @throws IOException
* @returns false if and only if the switch does not support role-request
* messages, according to the switch driver; true otherwise.
*/
synchronized boolean sendRoleRequest(Role role, RoleRecvStatus exp)
throws IOException {
this.expectation = exp;
if (ofVersion == OFVersion.OF_10) {
Boolean supportsNxRole = (Boolean)
sw.getAttribute(IOFSwitch.SWITCH_SUPPORTS_NX_ROLE);
if (!supportsNxRole) {
log.debug("Switch driver indicates no support for Nicira "
+ "role request messages. Not sending ...");
state.handleUnsentRoleMessage(OFChannelHandler.this, role,
expectation);
return false;
}
// OF1.0 switch with support for NX_ROLE_REQUEST vendor extn.
// make Role.EQUAL become Role.SLAVE
role = (role == Role.EQUAL) ? Role.SLAVE : role;
pendingXid = sendNxRoleRequest(role);
pendingRole = role;
roleSubmitTime = System.currentTimeMillis();
requestPending = true;
} else {
// OF1.3 switch, use OFPT_ROLE_REQUEST message
pendingXid = sendOF13RoleRequest(role);
pendingRole = role;
roleSubmitTime = System.currentTimeMillis();
requestPending = true;
}
return true;
}
/**
* Deliver a received role reply.
*
* Check if a request is pending and if the received reply matches the
* the expected pending reply (we check both role and xid) we set
* the role for the switch/channel.
*
* If a request is pending but doesn't match the reply we ignore it, and
* return
*
* If no request is pending we disconnect with a SwitchStateException
*
* @param RoleReplyInfo information about role-reply in format that
* controller can understand.
* @throws SwitchStateException if no request is pending
*/
synchronized RoleRecvStatus deliverRoleReply(RoleReplyInfo rri)
throws SwitchStateException {
if (!requestPending) {
Role currentRole = (sw != null) ? sw.getRole() : null;
if (currentRole != null) {
if (currentRole == rri.getRole()) {
// Don't disconnect if the role reply we received is
// for the same role we are already in.
log.debug("Received unexpected RoleReply from "
+ "Switch: {} in State: {}. "
+ "Role in reply is same as current role of this "
+ "controller for this sw. Ignoring ...",
getSwitchInfoString(), state.toString());
return RoleRecvStatus.OTHER_EXPECTATION;
} else {
String msg = String.format("Switch: [%s], State: [%s], "
+ "received unexpected RoleReply[%s]. "
+ "No roles are pending, and this controller's "
+ "current role:[%s] does not match reply. "
+ "Disconnecting switch ... ",
OFChannelHandler.this.getSwitchInfoString(),
OFChannelHandler.this.state.toString(),
rri, currentRole);
throw new SwitchStateException(msg);
}
}
log.debug("Received unexpected RoleReply {} from "
+ "Switch: {} in State: {}. "
+ "This controller has no current role for this sw. "
+ "Ignoring ...", new Object[] {rri,
getSwitchInfoString(), state});
return RoleRecvStatus.OTHER_EXPECTATION;
}
int xid = (int) rri.getXid();
Role role = rri.getRole();
// XXX S should check generation id meaningfully and other cases of expectations
// U64 genId = rri.getGenId();
if (pendingXid != xid) {
log.debug("Received older role reply from " +
"switch {} ({}). Ignoring. " +
"Waiting for {}, xid={}",
new Object[] {getSwitchInfoString(), rri,
pendingRole, pendingXid });
return RoleRecvStatus.OLD_REPLY;
}
if (pendingRole == role) {
log.debug("Received role reply message from {} that matched "
+ "expected role-reply {} with expectations {}",
new Object[] {getSwitchInfoString(), role, expectation});
counters.roleReplyReceived.updateCounterWithFlush();
//setSwitchRole(role, RoleRecvStatus.RECEIVED_REPLY); dont want to set state here
if (expectation == RoleRecvStatus.MATCHED_CURRENT_ROLE ||
expectation == RoleRecvStatus.MATCHED_SET_ROLE) {
return expectation;
} else {
return RoleRecvStatus.OTHER_EXPECTATION;
}
}
// if xids match but role's don't, perhaps its a query (OF1.3)
if (expectation == RoleRecvStatus.REPLY_QUERY) {
return expectation;
}
return RoleRecvStatus.OTHER_EXPECTATION;
}
/**
* Called if we receive an error message. If the xid matches the
* pending request we handle it otherwise we ignore it.
*
* Note: since we only keep the last pending request we might get
* error messages for earlier role requests that we won't be able
* to handle
*/
synchronized RoleRecvStatus deliverError(OFErrorMsg error)
throws SwitchStateException {
if (!requestPending) {
log.debug("Received an error msg from sw {}, but no pending "
+ "requests in role-changer; not handling ...",
getSwitchInfoString());
return RoleRecvStatus.OTHER_EXPECTATION;
}
if (pendingXid != error.getXid()) {
if (error.getErrType() == OFErrorType.ROLE_REQUEST_FAILED) {
log.debug("Received an error msg from sw {} for a role request,"
+ " but not for pending request in role-changer; "
+ " ignoring error {} ...",
getSwitchInfoString(), error);
}
return RoleRecvStatus.OTHER_EXPECTATION;
}
// it is an error related to a currently pending role request message
if (error.getErrType() == OFErrorType.BAD_REQUEST) {
counters.roleReplyErrorUnsupported.updateCounterWithFlush();
log.error("Received a error msg {} from sw {} in state {} for "
+ "pending role request {}. Switch driver indicates "
+ "role-messaging is supported. Possible issues in "
+ "switch driver configuration?", new Object[] {
((OFBadRequestErrorMsg) error).toString(),
getSwitchInfoString(), state, pendingRole
});
return RoleRecvStatus.UNSUPPORTED;
}
if (error.getErrType() == OFErrorType.ROLE_REQUEST_FAILED) {
OFRoleRequestFailedErrorMsg rrerr =
(OFRoleRequestFailedErrorMsg) error;
switch (rrerr.getCode()) {
case BAD_ROLE:
// switch says that current-role-req has bad role?
// for now we disconnect
// fall-thru
case STALE:
// switch says that current-role-req has stale gen-id?
// for now we disconnect
// fall-thru
case UNSUP:
// switch says that current-role-req has role that
// cannot be supported? for now we disconnect
String msgx = String.format("Switch: [%s], State: [%s], "
+ "received Error to for pending role request [%s]. "
+ "Error:[%s]. Disconnecting switch ... ",
OFChannelHandler.this.getSwitchInfoString(),
OFChannelHandler.this.state.toString(),
pendingRole, rrerr);
throw new SwitchStateException(msgx);
default:
break;
}
}
// This error message was for a role request message but we dont know
// how to handle errors for nicira role request messages
return RoleRecvStatus.OTHER_EXPECTATION;
}
/**
* Check if a pending role request has timed out.
*/
void checkTimeout() {
if (!requestPending) {
return;
}
synchronized (this) {
if (!requestPending) {
return;
}
long now = System.currentTimeMillis();
if (now - roleSubmitTime > roleTimeoutMs) {
// timeout triggered.
counters.roleReplyTimeout.updateCounterWithFlush();
//setSwitchRole(pendingRole, RoleRecvStatus.NO_REPLY);
// XXX S come back to this
}
}
}
}
//*************************
// Channel State Machine
//*************************
/**
* The state machine for handling the switch/channel state. All state
* transitions should happen from within the state machine (and not from other
* parts of the code)
*/
enum ChannelState {
/**
* Initial state before channel is connected.
*/
INIT(false) {
@Override
void processOFMessage(OFChannelHandler h, OFMessage m)
throws IOException, SwitchStateException {
illegalMessageReceived(h, m);
}
@Override
void processOFError(OFChannelHandler h, OFErrorMsg m)
throws IOException {
// need to implement since its abstract but it will never
// be called
}
@Override
void processOFPortStatus(OFChannelHandler h, OFPortStatus m)
throws IOException {
unhandledMessageReceived(h, m);
}
},
/**
* We send a OF 1.3 HELLO to the switch and wait for a Hello from the switch.
* Once we receive the reply, we decide on OF 1.3 or 1.0 switch - no other
* protocol version is accepted.
* We send an OFFeaturesRequest depending on the protocol version selected
* Next state is WAIT_FEATURES_REPLY
*/
WAIT_HELLO(false) {
@Override
void processOFHello(OFChannelHandler h, OFHello m)
throws IOException {
// TODO We could check for the optional bitmap, but for now
// we are just checking the version number.
if (m.getVersion() == OFVersion.OF_13) {
log.info("Received {} Hello from {}", m.getVersion(),
h.channel.getRemoteAddress());
h.ofVersion = OFVersion.OF_13;
} else if (m.getVersion() == OFVersion.OF_10) {
log.info("Received {} Hello from {} - switching to OF "
+ "version 1.0", m.getVersion(),
h.channel.getRemoteAddress());
h.ofVersion = OFVersion.OF_10;
} else {
log.error("Received Hello of version {} from switch at {}. "
+ "This controller works with OF1.0 and OF1.3 "
+ "switches. Disconnecting switch ...",
m.getVersion(), h.channel.getRemoteAddress());
h.channel.disconnect();
return;
}
h.sendHandshakeFeaturesRequestMessage();
h.setState(WAIT_FEATURES_REPLY);
}
@Override
void processOFFeaturesReply(OFChannelHandler h, OFFeaturesReply m)
throws IOException, SwitchStateException {
illegalMessageReceived(h, m);
}
@Override
void processOFStatisticsReply(OFChannelHandler h,
OFStatsReply m)
throws IOException, SwitchStateException {
illegalMessageReceived(h, m);
}
@Override
void processOFError(OFChannelHandler h, OFErrorMsg m) {
logErrorDisconnect(h, m);
}
@Override
void processOFPortStatus(OFChannelHandler h, OFPortStatus m)
throws IOException {
unhandledMessageReceived(h, m);
}
},
/**
* We are waiting for a features reply message. Once we receive it, the
* behavior depends on whether this is a 1.0 or 1.3 switch. For 1.0,
* we send a SetConfig request, barrier, and GetConfig request and the
* next state is WAIT_CONFIG_REPLY. For 1.3, we send a Port description
* request and the next state is WAIT_PORT_DESC_REPLY.
*/
WAIT_FEATURES_REPLY(false) {
@Override
void processOFFeaturesReply(OFChannelHandler h, OFFeaturesReply m)
throws IOException {
h.thisdpid = m.getDatapathId().getLong();
log.info("Received features reply for switch at {} with dpid {}",
h.getSwitchInfoString(), h.thisdpid);
//update the controller about this connected switch
boolean success = h.controller.addConnectedSwitch(
h.thisdpid, h);
if (!success) {
disconnectDuplicate(h);
return;
}
h.featuresReply = m; //temp store
if (h.ofVersion == OFVersion.OF_10) {
h.sendHandshakeSetConfig();
h.setState(WAIT_CONFIG_REPLY);
} else {
//version is 1.3, must get switchport information
h.sendHandshakeOFPortDescRequest();
h.setState(WAIT_PORT_DESC_REPLY);
}
}
@Override
void processOFStatisticsReply(OFChannelHandler h,
OFStatsReply m)
throws IOException, SwitchStateException {
illegalMessageReceived(h, m);
}
@Override
void processOFError(OFChannelHandler h, OFErrorMsg m) {
logErrorDisconnect(h, m);
}
@Override
void processOFPortStatus(OFChannelHandler h, OFPortStatus m)
throws IOException {
unhandledMessageReceived(h, m);
}
},
/**
* We are waiting for a description of the 1.3 switch ports.
* Once received, we send a SetConfig request
* Next State is WAIT_CONFIG_REPLY
*/
WAIT_PORT_DESC_REPLY(false) {
@Override
void processOFStatisticsReply(OFChannelHandler h, OFStatsReply m)
throws SwitchStateException {
// Read port description
if (m.getStatsType() != OFStatsType.PORT_DESC) {
log.warn("Expecting port description stats but received stats "
+ "type {} from {}. Ignoring ...", m.getStatsType(),
h.channel.getRemoteAddress());
return;
}
if (m.getFlags().contains(OFStatsReplyFlags.REPLY_MORE)) {
log.warn("Stats reply indicates more stats from sw {} for "
+ "port description - not currently handled",
h.getSwitchInfoString());
}
h.portDescReply = (OFPortDescStatsReply) m; // temp store
log.info("Received port desc reply for switch at {}",
h.getSwitchInfoString());
try {
h.sendHandshakeSetConfig();
} catch (IOException e) {
log.error("Unable to send setConfig after PortDescReply. "
+ "Error: {}", e.getMessage());
}
h.setState(WAIT_CONFIG_REPLY);
}
@Override
void processOFError(OFChannelHandler h, OFErrorMsg m)
throws IOException, SwitchStateException {
logErrorDisconnect(h, m);
}
@Override
void processOFPortStatus(OFChannelHandler h, OFPortStatus m)
throws IOException, SwitchStateException {
unhandledMessageReceived(h, m);
}
},
/**
* We are waiting for a config reply message. Once we receive it
* we send a DescriptionStatsRequest to the switch.
* Next state: WAIT_DESCRIPTION_STAT_REPLY
*/
WAIT_CONFIG_REPLY(false) {
@Override
@LogMessageDocs({
@LogMessageDoc(level = "WARN",
message = "Config Reply from {switch} has "
+ "miss length set to {length}",
explanation = "The controller requires that the switch "
+ "use a miss length of 0xffff for correct "
+ "function",
recommendation = "Use a different switch to ensure "
+ "correct function")
})
void processOFGetConfigReply(OFChannelHandler h, OFGetConfigReply m)
throws IOException {
if (m.getMissSendLen() == 0xffff) {
log.trace("Config Reply from switch {} confirms "
+ "miss length set to 0xffff",
h.getSwitchInfoString());
} else {
// FIXME: we can't really deal with switches that don't send
// full packets. Shouldn't we drop the connection here?
log.warn("Config Reply from switch {} has"
+ "miss length set to {}",
h.getSwitchInfoString(),
m.getMissSendLen());
}
h.sendHandshakeDescriptionStatsRequest();
h.setState(WAIT_DESCRIPTION_STAT_REPLY);
}
@Override
void processOFBarrierReply(OFChannelHandler h, OFBarrierReply m) {
// do nothing;
}
@Override
void processOFFeaturesReply(OFChannelHandler h, OFFeaturesReply m)
throws IOException, SwitchStateException {
illegalMessageReceived(h, m);
}
@Override
void processOFStatisticsReply(OFChannelHandler h,
OFStatsReply m)
throws IOException, SwitchStateException {
log.error("Received multipart(stats) message sub-type {}",
m.getStatsType());
illegalMessageReceived(h, m);
}
@Override
void processOFError(OFChannelHandler h, OFErrorMsg m) {
logErrorDisconnect(h, m);
}
@Override
void processOFPortStatus(OFChannelHandler h, OFPortStatus m)
throws IOException {
h.pendingPortStatusMsg.add(m);
}
},
/**
* We are waiting for a OFDescriptionStat message from the switch.
* Once we receive any stat message we try to parse it. If it's not
* a description stats message we disconnect. If its the expected
* description stats message, we:
* - use the switch driver to bind the switch and get an IOFSwitch instance
* - setup the IOFSwitch instance
* - add switch to FloodlightProvider(Controller) and send the initial role
* request to the switch.
* Next state: WAIT_INITIAL_ROLE
* In the typical case, where switches support role request messages
* the next state is where we expect the role reply message.
* In the special case that where the switch does not support any kind
* of role request messages, we don't send a role message, but we do
* request mastership from the registry service. This controller
* should become master once we hear back from the registry service.
* All following states will have a h.sw instance!
*/
WAIT_DESCRIPTION_STAT_REPLY(false) {
@LogMessageDoc(message = "Switch {switch info} bound to class "
+ "{switch driver}, description {switch description}",
explanation = "The specified switch has been bound to "
+ "a switch driver based on the switch description"
+ "received from the switch")
@Override
void processOFStatisticsReply(OFChannelHandler h, OFStatsReply m)
throws SwitchStateException {
// Read description, if it has been updated
if (m.getStatsType() != OFStatsType.DESC) {
log.warn("Expecting Description stats but received stats "
+ "type {} from {}. Ignoring ...", m.getStatsType(),
h.channel.getRemoteAddress());
return;
}
log.info("Received switch description reply from switch at {}",
h.channel.getRemoteAddress());
OFDescStatsReply drep = (OFDescStatsReply) m;
// Here is where we differentiate between different kinds of switches
h.sw = h.controller.getOFSwitchInstance(drep, h.ofVersion);
// set switch information
h.sw.setOFVersion(h.ofVersion);
h.sw.setFeaturesReply(h.featuresReply);
h.sw.setPortDescReply(h.portDescReply);
h.sw.setConnected(true);
h.sw.setChannel(h.channel);
try {
h.sw.setDebugCounterService(h.controller.getDebugCounter());
} catch (CounterException e) {
h.counters.switchCounterRegistrationFailed
.updateCounterNoFlush();
log.warn("Could not register counters for switch {} ",
h.getSwitchInfoString(), e);
}
log.info("Switch {} bound to class {}, description {}",
new Object[] {h.sw, h.sw.getClass(), drep });
//Put switch in EQUAL mode until we hear back from the global registry
log.debug("Setting new switch {} to EQUAL and sending Role request",
h.sw.getStringId());
h.setSwitchRole(Role.EQUAL);
try {
boolean supportsRRMsg = h.roleChanger.sendRoleRequest(Role.EQUAL,
RoleRecvStatus.MATCHED_CURRENT_ROLE);
if (!supportsRRMsg) {
log.warn("Switch {} does not support role request messages "
+ "of any kind. No role messages were sent. "
+ "This controller instance SHOULD become MASTER "
+ "from the registry process. ",
h.getSwitchInfoString());
}
h.setState(WAIT_INITIAL_ROLE);
// request control of switch from global registry -
// necessary even if this is the only controller the
// switch is connected to.
h.controller.submitRegistryRequest(h.sw.getId());
} catch (IOException e) {
log.error("Exception when sending role request: {} ",
e.getMessage());
// FIXME shouldn't we disconnect?
}
}
@Override
void processOFError(OFChannelHandler h, OFErrorMsg m) {
logErrorDisconnect(h, m);
}
@Override
void processOFFeaturesReply(OFChannelHandler h, OFFeaturesReply m)
throws IOException, SwitchStateException {
illegalMessageReceived(h, m);
}
@Override
void processOFPortStatus(OFChannelHandler h, OFPortStatus m)
throws IOException {
h.pendingPortStatusMsg.add(m);
}
},
/**
* We are waiting for a role reply message in response to a role request
* sent after hearing back from the registry service -- OR -- we are
* just waiting to hear back from the registry service in the case that
* the switch does not support role messages. If completed successfully,
* the controller's role for this switch will be set here.
* Before we move to the state corresponding to the role, we allow the
* switch specific driver to complete its configuration. This configuration
* typically depends on the role the controller is playing for this switch.
* And so we set the switch role (for 'this' controller) before we start
* the driver-sub-handshake.
* Next State: WAIT_SWITCH_DRIVER_SUB_HANDSHAKE
*/
WAIT_INITIAL_ROLE(false) {
@Override
void processOFError(OFChannelHandler h, OFErrorMsg m)
throws SwitchStateException {
// role changer will ignore the error if it isn't for it
RoleRecvStatus rrstatus = h.roleChanger.deliverError(m);
if (rrstatus == RoleRecvStatus.OTHER_EXPECTATION) {
logError(h, m);
}
}
@Override
void processOFExperimenter(OFChannelHandler h, OFExperimenter m)
throws IOException, SwitchStateException {
Role role = extractNiciraRoleReply(h, m);
// If role == null it means the vendor (experimenter) message
// wasn't really a Nicira role reply. We ignore this case.
if (role != null) {
RoleReplyInfo rri = new RoleReplyInfo(role, null, m.getXid());
RoleRecvStatus rrs = h.roleChanger.deliverRoleReply(rri);
if (rrs == RoleRecvStatus.MATCHED_SET_ROLE) {
setRoleAndStartDriverHandshake(h, rri.getRole());
} // else do nothing - wait for the correct expected reply
} else {
unhandledMessageReceived(h, m);
}
}
@Override
void processOFRoleReply(OFChannelHandler h, OFRoleReply m)
throws SwitchStateException, IOException {
RoleReplyInfo rri = extractOFRoleReply(h, m);
RoleRecvStatus rrs = h.roleChanger.deliverRoleReply(rri);
if (rrs == RoleRecvStatus.MATCHED_SET_ROLE) {
setRoleAndStartDriverHandshake(h, rri.getRole());
} // else do nothing - wait for the correct expected reply
}
@Override
void handleUnsentRoleMessage(OFChannelHandler h, Role role,
RoleRecvStatus expectation) throws IOException {
// typically this is triggered for a switch where role messages
// are not supported - we confirm that the role being set is
// master and move to the next state
if (expectation == RoleRecvStatus.MATCHED_SET_ROLE) {
if (role == Role.MASTER) {
setRoleAndStartDriverHandshake(h, role);
} else {
log.error("Expected MASTER role from registry for switch "
+ "which has no support for role-messages."
+ "Received {}. It is possible that this switch "
+ "is connected to other controllers, in which "
+ "case it should support role messages - not "
+ "moving forward.", role);
}
} // else do nothing - wait to hear back from registry
}
private void setRoleAndStartDriverHandshake(OFChannelHandler h,
Role role) throws IOException {
h.setSwitchRole(role);
h.sw.startDriverHandshake();
if (h.sw.isDriverHandshakeComplete()) {
Role mySwitchRole = h.sw.getRole();
if (mySwitchRole == Role.MASTER) {
log.info("Switch-driver sub-handshake complete. "
+ "Activating switch {} with Role: MASTER",
h.getSwitchInfoString());
handlePendingPortStatusMessages(h); //before activation
boolean success = h.controller.addActivatedMasterSwitch(
h.sw.getId(), h.sw);
if (!success) {
disconnectDuplicate(h);
return;
}
h.setState(MASTER);
} else {
log.info("Switch-driver sub-handshake complete. "
+ "Activating switch {} with Role: EQUAL",
h.getSwitchInfoString());
handlePendingPortStatusMessages(h); //before activation
boolean success = h.controller.addActivatedEqualSwitch(
h.sw.getId(), h.sw);
if (!success) {
disconnectDuplicate(h);
return;
}
h.setState(EQUAL);
}
} else {
h.setState(WAIT_SWITCH_DRIVER_SUB_HANDSHAKE);
}
}
@Override
void processOFFeaturesReply(OFChannelHandler h, OFFeaturesReply m)
throws IOException, SwitchStateException {
illegalMessageReceived(h, m);
}
@Override
void processOFStatisticsReply(OFChannelHandler h, OFStatsReply m)
throws SwitchStateException {
illegalMessageReceived(h, m);
}
@Override
void processOFPortStatus(OFChannelHandler h, OFPortStatus m)
throws IOException, SwitchStateException {
h.pendingPortStatusMsg.add(m);
}
},
/**
* We are waiting for the respective switch driver to complete its
* configuration. Notice that we do not consider this to be part of the main
* switch-controller handshake. But we do consider it as a step that comes
* before we declare the switch as available to the controller.
* Next State: depends on the role of this controller for this switch - either
* MASTER or EQUAL.
*/
WAIT_SWITCH_DRIVER_SUB_HANDSHAKE(true) {
@Override
void processOFError(OFChannelHandler h, OFErrorMsg m)
throws IOException {
// will never be called. We override processOFMessage
}
@Override
void processOFMessage(OFChannelHandler h, OFMessage m)
throws IOException {
if (m.getType() == OFType.ECHO_REQUEST) {
processOFEchoRequest(h, (OFEchoRequest) m);
} else {
// FIXME: other message to handle here?
h.sw.processDriverHandshakeMessage(m);
if (h.sw.isDriverHandshakeComplete()) {
// consult the h.sw role and goto that state
Role mySwitchRole = h.sw.getRole();
if (mySwitchRole == Role.MASTER) {
log.info("Switch-driver sub-handshake complete. "
+ "Activating switch {} with Role: MASTER",
h.getSwitchInfoString());
handlePendingPortStatusMessages(h); //before activation
boolean success = h.controller.addActivatedMasterSwitch(
h.sw.getId(), h.sw);
if (!success) {
disconnectDuplicate(h);
return;
}
h.setState(MASTER);
} else {
log.info("Switch-driver sub-handshake complete. "
+ "Activating switch {} with Role: EQUAL",
h.getSwitchInfoString());
handlePendingPortStatusMessages(h); //before activation
boolean success = h.controller.addActivatedEqualSwitch(
h.sw.getId(), h.sw);
if (!success) {
disconnectDuplicate(h);
return;
}
h.setState(EQUAL);
}
}
}
}
@Override
void processOFPortStatus(OFChannelHandler h, OFPortStatus m)
throws IOException, SwitchStateException {
h.pendingPortStatusMsg.add(m);
}
},
/**
* This controller is in MASTER role for this switch. We enter this state
* after requesting and winning control from the global registry.
* The main handshake as well as the switch-driver sub-handshake
* is complete at this point.
* // XXX S reconsider below
* In the (near) future we may deterministically assign controllers to
* switches at startup.
* We only leave this state if the switch disconnects or
* if we send a role request for SLAVE /and/ receive the role reply for
* SLAVE.
*/
MASTER(true) {
@LogMessageDoc(level = "WARN",
message = "Received permission error from switch {} while"
+ "being master. Reasserting master role.",
explanation = "The switch has denied an operation likely "
+ "indicating inconsistent controller roles",
recommendation = "This situation can occurs transiently during role"
+ " changes. If, however, the condition persists or happens"
+ " frequently this indicates a role inconsistency. "
+ LogMessageDoc.CHECK_CONTROLLER)
@Override
void processOFError(OFChannelHandler h, OFErrorMsg m)
throws IOException, SwitchStateException {
// first check if the error msg is in response to a role-request message
RoleRecvStatus rrstatus = h.roleChanger.deliverError(m);
if (rrstatus != RoleRecvStatus.OTHER_EXPECTATION) {
// rolechanger has handled the error message - we are done
return;
}
// if we get here, then the error message is for something else
if (m.getErrType() == OFErrorType.BAD_REQUEST &&
((OFBadRequestErrorMsg) m).getCode() ==
OFBadRequestCode.EPERM) {
// We are the master controller and the switch returned
// a permission error. This is a likely indicator that
// the switch thinks we are slave. Reassert our
// role
// FIXME: this could be really bad during role transitions
// if two controllers are master (even if its only for
// a brief period). We might need to see if these errors
// persist before we reassert
h.counters.epermErrorWhileSwitchIsMaster.updateCounterWithFlush();
log.warn("Received permission error from switch {} while" +
"being master. Reasserting master role.",
h.getSwitchInfoString());
//h.controller.reassertRole(h, Role.MASTER);
// XXX S reassert in role changer or reconsider if all this
// stuff is really needed
} else if (m.getErrType() == OFErrorType.FLOW_MOD_FAILED &&
((OFFlowModFailedErrorMsg) m).getCode() ==
OFFlowModFailedCode.ALL_TABLES_FULL) {
h.sw.setTableFull(true);
} else {
logError(h, m);
}
h.dispatchMessage(m);
}
@Override
void processOFStatisticsReply(OFChannelHandler h,
OFStatsReply m) {
h.sw.deliverStatisticsReply(m);
}
@Override
void processOFExperimenter(OFChannelHandler h, OFExperimenter m)
throws IOException, SwitchStateException {
Role role = extractNiciraRoleReply(h, m);
if (role == null) {
// The message wasn't really a Nicira role reply. We just
// dispatch it to the OFMessage listeners in this case.
h.dispatchMessage(m);
return;
}
RoleRecvStatus rrs = h.roleChanger.deliverRoleReply(
new RoleReplyInfo(role, null, m.getXid()));
if (rrs == RoleRecvStatus.MATCHED_SET_ROLE) {
checkAndSetRoleTransition(h, role);
}
}
@Override
void processOFRoleReply(OFChannelHandler h, OFRoleReply m)
throws SwitchStateException, IOException {
RoleReplyInfo rri = extractOFRoleReply(h, m);
RoleRecvStatus rrs = h.roleChanger.deliverRoleReply(rri);
if (rrs == RoleRecvStatus.MATCHED_SET_ROLE) {
checkAndSetRoleTransition(h, rri.getRole());
}
}
@Override
void processOFPortStatus(OFChannelHandler h, OFPortStatus m)
throws IOException, SwitchStateException {
handlePortStatusMessage(h, m, true);
h.dispatchMessage(m);
}
@Override
void processOFPacketIn(OFChannelHandler h, OFPacketIn m)
throws IOException {
h.dispatchMessage(m);
}
@Override
void processOFFlowRemoved(OFChannelHandler h,
OFFlowRemoved m) throws IOException {
h.dispatchMessage(m);
}
@Override
void processOFBarrierReply(OFChannelHandler h, OFBarrierReply m)
throws IOException {
h.dispatchMessage(m);
}
},
/**
* This controller is in EQUAL role for this switch. We enter this state
* after some /other/ controller instance wins mastership-role over this
* switch. The EQUAL role can be considered the same as the SLAVE role
* if this controller does NOT send commands or packets to the switch.
* This should always be true for OF1.0 switches. XXX S need to enforce.
*
* For OF1.3 switches, choosing this state as EQUAL instead of SLAVE,
* gives us the flexibility that if an app wants to send commands/packets
* to switches, it can, even thought it is running on a controller instance
* that is not in a MASTER role for this switch. Of course, it is the job
* of the app to ensure that commands/packets sent by this (EQUAL) controller
* instance does not clash/conflict with commands/packets sent by the MASTER
* controller for this switch. Neither the controller instances, nor the
* switch provides any kind of resolution mechanism should conflicts occur.
*/
EQUAL(true) {
@Override
void processOFError(OFChannelHandler h, OFErrorMsg m)
throws IOException, SwitchStateException {
// role changer will ignore the error if it isn't for it
RoleRecvStatus rrstatus = h.roleChanger.deliverError(m);
if (rrstatus == RoleRecvStatus.OTHER_EXPECTATION) {
logError(h, m);
h.dispatchMessage(m);
}
}
@Override
void processOFStatisticsReply(OFChannelHandler h,
OFStatsReply m) {
h.sw.deliverStatisticsReply(m);
}
@Override
void processOFExperimenter(OFChannelHandler h, OFExperimenter m)
throws IOException, SwitchStateException {
Role role = extractNiciraRoleReply(h, m);
// If role == null it means the message wasn't really a
// Nicira role reply. We ignore it in this state.
if (role != null) {
RoleRecvStatus rrs = h.roleChanger.deliverRoleReply(
new RoleReplyInfo(role, null, m.getXid()));
if (rrs == RoleRecvStatus.MATCHED_SET_ROLE) {
checkAndSetRoleTransition(h, role);
}
} else {
unhandledMessageReceived(h, m);
}
}
@Override
void processOFRoleReply(OFChannelHandler h, OFRoleReply m)
throws SwitchStateException, IOException {
RoleReplyInfo rri = extractOFRoleReply(h, m);
RoleRecvStatus rrs = h.roleChanger.deliverRoleReply(rri);
if (rrs == RoleRecvStatus.MATCHED_SET_ROLE) {
checkAndSetRoleTransition(h, rri.getRole());
}
}
// XXX S needs more handlers for 1.3 switches in equal role
@Override
void processOFPortStatus(OFChannelHandler h, OFPortStatus m)
throws IOException, SwitchStateException {
handlePortStatusMessage(h, m, true);
}
@Override
@LogMessageDoc(level = "WARN",
message = "Received PacketIn from switch {} while "
+ "being slave. Reasserting slave role.",
explanation = "The switch has receive a PacketIn despite being "
+ "in slave role indicating inconsistent controller roles",
recommendation = "This situation can occurs transiently during role"
+ " changes. If, however, the condition persists or happens"
+ " frequently this indicates a role inconsistency. "
+ LogMessageDoc.CHECK_CONTROLLER)
void processOFPacketIn(OFChannelHandler h, OFPacketIn m) throws IOException {
// we don't expect packetIn while slave, reassert we are slave
h.counters.packetInWhileSwitchIsSlave.updateCounterNoFlush();
log.warn("Received PacketIn from switch {} while" +
"being slave. Reasserting slave role.", h.sw);
//h.controller.reassertRole(h, Role.SLAVE);
// XXX reassert in role changer
}
};
private final boolean handshakeComplete;
ChannelState(boolean handshakeComplete) {
this.handshakeComplete = handshakeComplete;
}
/**
* Is this a state in which the handshake has completed?
* @return true if the handshake is complete
*/
public boolean isHandshakeComplete() {
return handshakeComplete;
}
/**
* Get a string specifying the switch connection, state, and
* message received. To be used as message for SwitchStateException
* or log messages
* @param h The channel handler (to get switch information_
* @param m The OFMessage that has just been received
* @param details A string giving more details about the exact nature
* of the problem.
* @return
*/
// needs to be protected because enum members are actually subclasses
protected String getSwitchStateMessage(OFChannelHandler h,
OFMessage m,
String details) {
return String.format("Switch: [%s], State: [%s], received: [%s]"
+ ", details: %s",
h.getSwitchInfoString(),
this.toString(),
m.getType().toString(),
details);
}
/**
* We have an OFMessage we didn't expect given the current state and
* we want to treat this as an error.
* We currently throw an exception that will terminate the connection
* However, we could be more forgiving
* @param h the channel handler that received the message
* @param m the message
* @throws SwitchStateException
* @throws SwitchStateExeption we always through the execption
*/
// needs to be protected because enum members are acutally subclasses
protected void illegalMessageReceived(OFChannelHandler h, OFMessage m)
throws SwitchStateException {
String msg = getSwitchStateMessage(h, m,
"Switch should never send this message in the current state");
throw new SwitchStateException(msg);
}
/**
* We have an OFMessage we didn't expect given the current state and
* we want to ignore the message.
* @param h the channel handler the received the message
* @param m the message
*/
protected void unhandledMessageReceived(OFChannelHandler h,
OFMessage m) {
h.counters.unhandledMessage.updateCounterNoFlush();
if (log.isDebugEnabled()) {
String msg = getSwitchStateMessage(h, m,
"Ignoring unexpected message");
log.debug(msg);
}
}
/**
* Log an OpenFlow error message from a switch.
* @param sw The switch that sent the error
* @param error The error message
*/
@LogMessageDoc(level = "ERROR",
message = "Error {error type} {error code} from {switch} "
+ "in state {state}",
explanation = "The switch responded with an unexpected error"
+ "to an OpenFlow message from the controller",
recommendation = "This could indicate improper network operation. "
+ "If the problem persists restarting the switch and "
+ "controller may help."
)
protected void logError(OFChannelHandler h, OFErrorMsg error) {
log.error("{} from switch {} in state {}",
new Object[] {
error,
h.getSwitchInfoString(),
this.toString()});
}
/**
* Log an OpenFlow error message from a switch and disconnect the
* channel.
*
* @param h the IO channel for this switch.
* @param error The error message
*/
protected void logErrorDisconnect(OFChannelHandler h, OFErrorMsg error) {
logError(h, error);
h.channel.disconnect();
}
/**
* log an error message for a duplicate dpid and disconnect this channel.
* @param h the IO channel for this switch.
*/
protected void disconnectDuplicate(OFChannelHandler h) {
log.error("Duplicated dpid or incompleted cleanup - "
+ "disconnecting channel {}", h.getSwitchInfoString());
h.duplicateDpidFound = Boolean.TRUE;
h.channel.disconnect();
}
/**
* Extract the role from an OFVendor message.
*
* Extract the role from an OFVendor message if the message is a
* Nicira role reply. Otherwise return null.
*
* @param h The channel handler receiving the message
* @param vendorMessage The vendor message to parse.
* @return The role in the message if the message is a Nicira role
* reply, null otherwise.
* @throws SwitchStateException If the message is a Nicira role reply
* but the numeric role value is unknown.
*/
protected Role extractNiciraRoleReply(OFChannelHandler h,
OFExperimenter experimenterMsg) throws SwitchStateException {
int vendor = (int) experimenterMsg.getExperimenter();
if (vendor != 0x2320) {
return null;
}
OFNiciraControllerRoleReply nrr =
(OFNiciraControllerRoleReply) experimenterMsg;
Role role = null;
OFNiciraControllerRole ncr = nrr.getRole();
switch(ncr) {
case ROLE_MASTER:
role = Role.MASTER;
break;
case ROLE_OTHER:
role = Role.EQUAL;
break;
case ROLE_SLAVE:
role = Role.SLAVE;
break;
default: //handled below
}
if (role == null) {
String msg = String.format("Switch: [%s], State: [%s], "
+ "received NX_ROLE_REPLY with invalid role "
+ "value %s",
h.getSwitchInfoString(),
this.toString(),
nrr.getRole());
throw new SwitchStateException(msg);
}
return role;
}
/**
* Helper class returns role reply information in the format understood
* by the controller.
*/
protected static class RoleReplyInfo {
private Role role;
private U64 genId;
private long xid;
RoleReplyInfo(Role role, U64 genId, long xid) {
this.role = role;
this.genId = genId;
this.xid = xid;
}
public Role getRole() { return role; }
public U64 getGenId() { return genId; }
public long getXid() { return xid; }
@Override
public String toString() {
return "[Role:" + role + " GenId:" + genId + " Xid:" + xid + "]";
}
}
/**
* Extract the role information from an OF1.3 Role Reply Message.
* @param h
* @param rrmsg
* @return RoleReplyInfo object
* @throws SwitchStateException
*/
protected RoleReplyInfo extractOFRoleReply(OFChannelHandler h,
OFRoleReply rrmsg) throws SwitchStateException {
OFControllerRole cr = rrmsg.getRole();
Role role = null;
switch(cr) {
case ROLE_EQUAL:
role = Role.EQUAL;
break;
case ROLE_MASTER:
role = Role.MASTER;
break;
case ROLE_SLAVE:
role = Role.SLAVE;
break;
case ROLE_NOCHANGE: // switch should send current role
default:
String msg = String.format("Unknown controller role %s "
+ "received from switch %s", cr, h.sw);
throw new SwitchStateException(msg);
}
return new RoleReplyInfo(role, rrmsg.getGenerationId(), rrmsg.getXid());
}
/**
* Handles all pending port status messages before a switch is declared
* activated in MASTER or EQUAL role. Note that since this handling
* precedes the activation (and therefore notification to IOFSwitchListerners)
* the changes to ports will already be visible once the switch is
* activated. As a result, no notifications are sent out for these
* pending portStatus messages.
* @param h
* @throws SwitchStateException
*/
protected void handlePendingPortStatusMessages(OFChannelHandler h) {
try {
handlePendingPortStatusMessages(h, 0);
} catch (SwitchStateException e) {
log.error(e.getMessage());
}
}
private void handlePendingPortStatusMessages(OFChannelHandler h, int index)
throws SwitchStateException {
if (h.sw == null) {
String msg = "State machine error: switch is null. Should never " +
"happen";
throw new SwitchStateException(msg);
}
ArrayList<OFPortStatus> temp = new ArrayList<OFPortStatus>();
for (OFPortStatus ps: h.pendingPortStatusMsg) {
temp.add(ps);
handlePortStatusMessage(h, ps, false);
}
temp.clear();
// expensive but ok - we don't expect too many port-status messages
// note that we cannot use clear(), because of the reasons below
h.pendingPortStatusMsg.removeAll(temp);
// the iterator above takes a snapshot of the list - so while we were
// dealing with the pending port-status messages, we could have received
// newer ones. Handle them recursively, but break the recursion after
// five steps to avoid an attack.
if (!h.pendingPortStatusMsg.isEmpty() && ++index < 5) {
handlePendingPortStatusMessages(h, index);
}
}
/**
* Handle a port status message.
*
* Handle a port status message by updating the port maps in the
* IOFSwitch instance and notifying Controller about the change so
* it can dispatch a switch update.
*
* @param h The OFChannelHhandler that received the message
* @param m The PortStatus message we received
* @param doNotify if true switch port changed events will be
* dispatched
* @throws SwitchStateException
*
*/
protected void handlePortStatusMessage(OFChannelHandler h, OFPortStatus m,
boolean doNotify) throws SwitchStateException {
if (h.sw == null) {
String msg = getSwitchStateMessage(h, m,
"State machine error: switch is null. Should never " +
"happen");
throw new SwitchStateException(msg);
}
Collection<PortChangeEvent> changes = h.sw.processOFPortStatus(m);
if (doNotify) {
for (PortChangeEvent ev: changes) {
h.controller.notifyPortChanged(h.sw.getId(), ev.port, ev.type);
}
}
}
/**
* Checks if the role received (from the role-reply msg) is different
* from the existing role in the IOFSwitch object for this controller.
* If so, it transitions the controller to the new role. Note that
* the caller should have already verified that the role-reply msg
* received was in response to a role-request msg sent out by this
* controller after hearing from the registry service.
*
* @param h the ChannelHandler that received the message
* @param role the role in the recieved role reply message
*/
protected void checkAndSetRoleTransition(OFChannelHandler h, Role role) {
// we received a role-reply in response to a role message
// sent after hearing from the registry service. It is
// possible that the role of this controller instance for
// this switch has changed:
// for 1.0 switch: from MASTER to SLAVE
// for 1.3 switch: from MASTER to EQUAL
if ((h.sw.getRole() == Role.MASTER && role == Role.SLAVE) ||
(h.sw.getRole() == Role.MASTER && role == Role.EQUAL)) {
// the mastership has changed
h.sw.setRole(role);
h.setState(EQUAL);
h.controller.transitionToEqualSwitch(h.sw.getId());
return;
}
// or for both 1.0 and 1.3 switches from EQUAL to MASTER.
// note that for 1.0, even though we mean SLAVE,
// internally we call the role EQUAL.
if (h.sw.getRole() == Role.EQUAL && role == Role.MASTER) {
// the mastership has changed
h.sw.setRole(role);
h.setState(MASTER);
h.controller.transitionToMasterSwitch(h.sw.getId());
return;
}
}
/**
* Process an OF message received on the channel and
* update state accordingly.
*
* The main "event" of the state machine. Process the received message,
* send follow up message if required and update state if required.
*
* Switches on the message type and calls more specific event handlers
* for each individual OF message type. If we receive a message that
* is supposed to be sent from a controller to a switch we throw
* a SwitchStateExeption.
*
* The more specific handlers can also throw SwitchStateExceptions
*
* @param h The OFChannelHandler that received the message
* @param m The message we received.
* @throws SwitchStateException
* @throws IOException
*/
void processOFMessage(OFChannelHandler h, OFMessage m)
throws IOException, SwitchStateException {
h.roleChanger.checkTimeout();
switch(m.getType()) {
case HELLO:
processOFHello(h, (OFHello) m);
break;
case BARRIER_REPLY:
processOFBarrierReply(h, (OFBarrierReply) m);
break;
case ECHO_REPLY:
processOFEchoReply(h, (OFEchoReply) m);
break;
case ECHO_REQUEST:
processOFEchoRequest(h, (OFEchoRequest) m);
break;
case ERROR:
processOFError(h, (OFErrorMsg) m);
break;
case FEATURES_REPLY:
processOFFeaturesReply(h, (OFFeaturesReply) m);
break;
case FLOW_REMOVED:
processOFFlowRemoved(h, (OFFlowRemoved) m);
break;
case GET_CONFIG_REPLY:
processOFGetConfigReply(h, (OFGetConfigReply) m);
break;
case PACKET_IN:
processOFPacketIn(h, (OFPacketIn) m);
break;
case PORT_STATUS:
processOFPortStatus(h, (OFPortStatus) m);
break;
case QUEUE_GET_CONFIG_REPLY:
processOFQueueGetConfigReply(h, (OFQueueGetConfigReply) m);
break;
case STATS_REPLY: // multipart_reply in 1.3
processOFStatisticsReply(h, (OFStatsReply) m);
break;
case EXPERIMENTER:
processOFExperimenter(h, (OFExperimenter) m);
break;
case ROLE_REPLY:
processOFRoleReply(h, (OFRoleReply) m);
break;
case GET_ASYNC_REPLY:
processOFGetAsyncReply(h, (OFAsyncGetReply) m);
break;
// The following messages are sent to switches. The controller
// should never receive them
case SET_CONFIG:
case GET_CONFIG_REQUEST:
case PACKET_OUT:
case PORT_MOD:
case QUEUE_GET_CONFIG_REQUEST:
case BARRIER_REQUEST:
case STATS_REQUEST: // multipart request in 1.3
case FEATURES_REQUEST:
case FLOW_MOD:
case GROUP_MOD:
case TABLE_MOD:
case GET_ASYNC_REQUEST:
case SET_ASYNC:
case METER_MOD:
default:
illegalMessageReceived(h, m);
break;
}
}
/*-----------------------------------------------------------------
* Default implementation for message handlers in any state.
*
* Individual states must override these if they want a behavior
* that differs from the default.
*
* In general, these handlers simply ignore the message and do
* nothing.
*
* There are some exceptions though, since some messages really
* are handled the same way in every state (e.g., ECHO_REQUST) or
* that are only valid in a single state (e.g., HELLO, GET_CONFIG_REPLY
-----------------------------------------------------------------*/
void processOFHello(OFChannelHandler h, OFHello m)
throws IOException, SwitchStateException {
// we only expect hello in the WAIT_HELLO state
illegalMessageReceived(h, m);
}
void processOFBarrierReply(OFChannelHandler h, OFBarrierReply m)
throws IOException {
// Silently ignore.
}
void processOFEchoRequest(OFChannelHandler h, OFEchoRequest m)
throws IOException {
if (h.ofVersion == null) {
log.error("No OF version set for {}. Not sending Echo REPLY",
h.channel.getRemoteAddress());
return;
}
OFFactory factory = (h.ofVersion == OFVersion.OF_13) ?
h.controller.getOFMessageFactory13() : h.controller.getOFMessageFactory10();
OFEchoReply reply = factory
.buildEchoReply()
.setXid(m.getXid())
.setData(m.getData())
.build();
h.channel.write(Collections.singletonList(reply));
}
void processOFEchoReply(OFChannelHandler h, OFEchoReply m)
throws IOException {
// Do nothing with EchoReplies !!
}
// no default implementation for OFError
// every state must override it
abstract void processOFError(OFChannelHandler h, OFErrorMsg m)
throws IOException, SwitchStateException;
void processOFFeaturesReply(OFChannelHandler h, OFFeaturesReply m)
throws IOException, SwitchStateException {
unhandledMessageReceived(h, m);
}
void processOFFlowRemoved(OFChannelHandler h, OFFlowRemoved m)
throws IOException {
unhandledMessageReceived(h, m);
}
void processOFGetConfigReply(OFChannelHandler h, OFGetConfigReply m)
throws IOException, SwitchStateException {
// we only expect config replies in the WAIT_CONFIG_REPLY state
illegalMessageReceived(h, m);
}
void processOFPacketIn(OFChannelHandler h, OFPacketIn m)
throws IOException {
unhandledMessageReceived(h, m);
}
// no default implementation. Every state needs to handle it.
abstract void processOFPortStatus(OFChannelHandler h, OFPortStatus m)
throws IOException, SwitchStateException;
void processOFQueueGetConfigReply(OFChannelHandler h,
OFQueueGetConfigReply m)
throws IOException {
unhandledMessageReceived(h, m);
}
void processOFStatisticsReply(OFChannelHandler h, OFStatsReply m)
throws IOException, SwitchStateException {
unhandledMessageReceived(h, m);
}
void processOFExperimenter(OFChannelHandler h, OFExperimenter m)
throws IOException, SwitchStateException {
// TODO: it might make sense to parse the vendor message here
// into the known vendor messages we support and then call more
// specific event handlers
unhandledMessageReceived(h, m);
}
void processOFRoleReply(OFChannelHandler h, OFRoleReply m)
throws SwitchStateException, IOException {
unhandledMessageReceived(h, m);
}
void processOFGetAsyncReply(OFChannelHandler h,
OFAsyncGetReply m) {
unhandledMessageReceived(h, m);
}
void handleUnsentRoleMessage(OFChannelHandler h, Role role,
RoleRecvStatus expectation) throws IOException {
// do nothing in most states
}
}
//*************************
// Channel handler methods
//*************************
@Override
@LogMessageDoc(message = "New switch connection from {ip address}",
explanation = "A new switch has connected from the "
+ "specified IP address")
public void channelConnected(ChannelHandlerContext ctx,
ChannelStateEvent e) throws Exception {
counters.switchConnected.updateCounterWithFlush();
channel = e.getChannel();
log.info("New switch connection from {}",
channel.getRemoteAddress());
sendHandshakeHelloMessage();
setState(ChannelState.WAIT_HELLO);
}
@Override
@LogMessageDoc(message = "Disconnected switch {switch information}",
explanation = "The specified switch has disconnected.")
public void channelDisconnected(ChannelHandlerContext ctx,
ChannelStateEvent e) throws Exception {
log.info("Switch disconnected callback for sw:{}. Cleaning up ...",
getSwitchInfoString());
if (thisdpid != 0) {
if (!duplicateDpidFound) {
// if the disconnected switch (on this ChannelHandler)
// was not one with a duplicate-dpid, it is safe to remove all
// state for it at the controller. Notice that if the disconnected
// switch was a duplicate-dpid, calling the method below would clear
// all state for the original switch (with the same dpid),
// which we obviously don't want.
controller.removeConnectedSwitch(thisdpid);
} else {
// A duplicate was disconnected on this ChannelHandler,
// this is the same switch reconnecting, but the original state was
// not cleaned up - XXX check liveness of original ChannelHandler
duplicateDpidFound = Boolean.FALSE;
}
} else {
log.warn("no dpid in channelHandler registered for "
+ "disconnected switch {}", getSwitchInfoString());
}
}
@Override
@LogMessageDocs({
@LogMessageDoc(level = "ERROR",
message = "Disconnecting switch {switch} due to read timeout",
explanation = "The connected switch has failed to send any "
+ "messages or respond to echo requests",
recommendation = LogMessageDoc.CHECK_SWITCH),
@LogMessageDoc(level = "ERROR",
message = "Disconnecting switch {switch}: failed to "
+ "complete handshake",
explanation = "The switch did not respond correctly "
+ "to handshake messages",
recommendation = LogMessageDoc.CHECK_SWITCH),
@LogMessageDoc(level = "ERROR",
message = "Disconnecting switch {switch} due to IO Error: {}",
explanation = "There was an error communicating with the switch",
recommendation = LogMessageDoc.CHECK_SWITCH),
@LogMessageDoc(level = "ERROR",
message = "Disconnecting switch {switch} due to switch "
+ "state error: {error}",
explanation = "The switch sent an unexpected message",
recommendation = LogMessageDoc.CHECK_SWITCH),
@LogMessageDoc(level = "ERROR",
message = "Disconnecting switch {switch} due to "
+ "message parse failure",
explanation = "Could not parse a message from the switch",
recommendation = LogMessageDoc.CHECK_SWITCH),
@LogMessageDoc(level = "ERROR",
message = "Terminating controller due to storage exception",
explanation = Controller.ERROR_DATABASE,
recommendation = LogMessageDoc.CHECK_CONTROLLER),
@LogMessageDoc(level = "ERROR",
message = "Could not process message: queue full",
explanation = "OpenFlow messages are arriving faster than "
+ "the controller can process them.",
recommendation = LogMessageDoc.CHECK_CONTROLLER),
@LogMessageDoc(level = "ERROR",
message = "Error while processing message "
+ "from switch {switch} {cause}",
explanation = "An error occurred processing the switch message",
recommendation = LogMessageDoc.GENERIC_ACTION)
})
public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e)
throws Exception {
if (e.getCause() instanceof ReadTimeoutException) {
// switch timeout
log.error("Disconnecting switch {} due to read timeout",
getSwitchInfoString());
counters.switchDisconnectReadTimeout.updateCounterWithFlush();
ctx.getChannel().close();
} else if (e.getCause() instanceof HandshakeTimeoutException) {
log.error("Disconnecting switch {}: failed to complete handshake",
getSwitchInfoString());
counters.switchDisconnectHandshakeTimeout.updateCounterWithFlush();
ctx.getChannel().close();
} else if (e.getCause() instanceof ClosedChannelException) {
log.debug("Channel for sw {} already closed", getSwitchInfoString());
} else if (e.getCause() instanceof IOException) {
log.error("Disconnecting switch {} due to IO Error: {}",
getSwitchInfoString(), e.getCause().getMessage());
if (log.isDebugEnabled()) {
// still print stack trace if debug is enabled
log.debug("StackTrace for previous Exception: ", e.getCause());
}
counters.switchDisconnectIOError.updateCounterWithFlush();
ctx.getChannel().close();
} else if (e.getCause() instanceof SwitchStateException) {
log.error("Disconnecting switch {} due to switch state error: {}",
getSwitchInfoString(), e.getCause().getMessage());
if (log.isDebugEnabled()) {
// still print stack trace if debug is enabled
log.debug("StackTrace for previous Exception: ", e.getCause());
}
counters.switchDisconnectSwitchStateException.updateCounterWithFlush();
ctx.getChannel().close();
} else if (e.getCause() instanceof OFParseError) {
log.error("Disconnecting switch "
+ getSwitchInfoString() +
" due to message parse failure",
e.getCause());
counters.switchDisconnectParseError.updateCounterWithFlush();
ctx.getChannel().close();
} else if (e.getCause() instanceof RejectedExecutionException) {
log.warn("Could not process message: queue full");
counters.rejectedExecutionException.updateCounterWithFlush();
} else {
log.error("Error while processing message from switch "
+ getSwitchInfoString()
+ "state " + this.state, e.getCause());
counters.switchDisconnectOtherException.updateCounterWithFlush();
ctx.getChannel().close();
}
}
@Override
public String toString() {
return getSwitchInfoString();
}
@Override
public void channelIdle(ChannelHandlerContext ctx, IdleStateEvent e)
throws Exception {
OFFactory factory = (ofVersion == OFVersion.OF_13) ? factory13 : factory10;
OFMessage m = factory.buildEchoRequest().build();
log.info("Sending Echo Request on idle channel: {}",
e.getChannel().getPipeline().getLast().toString());
e.getChannel().write(Collections.singletonList(m));
// XXX S some problems here -- echo request has no transaction id, and
// echo reply is not correlated to the echo request.
}
@Override
public void messageReceived(ChannelHandlerContext ctx, MessageEvent e)
throws Exception {
if (e.getMessage() instanceof List) {
@SuppressWarnings("unchecked")
List<OFMessage> msglist = (List<OFMessage>) e.getMessage();
for (OFMessage ofm : msglist) {
counters.messageReceived.updateCounterNoFlush();
// Do the actual packet processing
state.processOFMessage(this, ofm);
}
} else {
counters.messageReceived.updateCounterNoFlush();
state.processOFMessage(this, (OFMessage) e.getMessage());
}
}
//*************************
// Channel utility methods
//*************************
/**
* Is this a state in which the handshake has completed?
* @return true if the handshake is complete
*/
public boolean isHandshakeComplete() {
return this.state.isHandshakeComplete();
}
private void dispatchMessage(OFMessage m) throws IOException {
sw.handleMessage(m);
}
/**
* Return a string describing this switch based on the already available
* information (DPID and/or remote socket).
* @return
*/
private String getSwitchInfoString() {
if (sw != null) {
return sw.toString();
}
String channelString;
if (channel == null || channel.getRemoteAddress() == null) {
channelString = "?";
} else {
channelString = channel.getRemoteAddress().toString();
}
String dpidString;
if (featuresReply == null) {
dpidString = "?";
} else {
dpidString = featuresReply.getDatapathId().toString();
}
return String.format("[%s DPID[%s]]", channelString, dpidString);
}
/**
* Update the channels state. Only called from the state machine.
* TODO: enforce restricted state transitions
* @param state
*/
private void setState(ChannelState state) {
this.state = state;
}
/**
* Send hello message to the switch using the handshake transactions ids.
* @throws IOException
*/
private void sendHandshakeHelloMessage() throws IOException {
// The OF protocol requires us to start things off by sending the highest
// version of the protocol supported.
// bitmap represents OF1.0 (ofp_version=0x01) and OF1.3 (ofp_version=0x04)
// see Sec. 7.5.1 of the OF1.3.4 spec
U32 bitmap = U32.ofRaw(0x00000012);
OFHelloElem hem = factory13.buildHelloElemVersionbitmap()
.setBitmaps(Collections.singletonList(bitmap))
.build();
OFMessage.Builder mb = factory13.buildHello()
.setXid(this.handshakeTransactionIds--)
.setElements(Collections.singletonList(hem));
log.info("Sending OF_13 Hello to {}", channel.getRemoteAddress());
channel.write(Collections.singletonList(mb.build()));
}
/**
* Send featuresRequest msg to the switch using the handshake transactions ids.
* @throws IOException
*/
private void sendHandshakeFeaturesRequestMessage() throws IOException {
OFFactory factory = (ofVersion == OFVersion.OF_13) ? factory13 : factory10;
OFMessage m = factory.buildFeaturesRequest()
.setXid(this.handshakeTransactionIds--)
.build();
channel.write(Collections.singletonList(m));
}
private void setSwitchRole(Role role) {
sw.setRole(role);
}
/**
* Send the configuration requests to tell the switch we want full
* packets.
* @throws IOException
*/
private void sendHandshakeSetConfig() throws IOException {
OFFactory factory = (ofVersion == OFVersion.OF_13) ? factory13 : factory10;
//log.debug("Sending CONFIG_REQUEST to {}", channel.getRemoteAddress());
List<OFMessage> msglist = new ArrayList<OFMessage>(3);
// Ensure we receive the full packet via PacketIn
// FIXME: We don't set the reassembly flags.
OFSetConfig sc = factory
.buildSetConfig()
.setMissSendLen((short) 0xffff)
.setXid(this.handshakeTransactionIds--)
.build();
msglist.add(sc);
// Barrier
OFBarrierRequest br = factory
.buildBarrierRequest()
.setXid(this.handshakeTransactionIds--)
.build();
msglist.add(br);
// Verify (need barrier?)
OFGetConfigRequest gcr = factory
.buildGetConfigRequest()
.setXid(this.handshakeTransactionIds--)
.build();
msglist.add(gcr);
channel.write(msglist);
}
/**
* send a description state request.
* @throws IOException
*/
private void sendHandshakeDescriptionStatsRequest() throws IOException {
// Get Description to set switch-specific flags
OFFactory factory = (ofVersion == OFVersion.OF_13) ? factory13 : factory10;
OFDescStatsRequest dreq = factory
.buildDescStatsRequest()
.setXid(handshakeTransactionIds--)
.build();
channel.write(Collections.singletonList(dreq));
}
private void sendHandshakeOFPortDescRequest() throws IOException {
// Get port description for 1.3 switch
OFPortDescStatsRequest preq = factory13
.buildPortDescStatsRequest()
.setXid(handshakeTransactionIds--)
.build();
channel.write(Collections.singletonList(preq));
}
ChannelState getStateForTesting() {
return state;
}
void useRoleChangerWithOtherTimeoutForTesting(long roleTimeoutMs) {
roleChanger = new RoleChanger(roleTimeoutMs);
}
}
/**
* Copyright 2011, Big Switch Networks, Inc.
* Originally created by David Erickson, Stanford University
*
* 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 net.onrc.onos.of.ctl.internal;
import org.jboss.netty.buffer.ChannelBuffer;
import org.jboss.netty.channel.Channel;
import org.jboss.netty.channel.ChannelHandlerContext;
import org.jboss.netty.handler.codec.frame.FrameDecoder;
import org.projectfloodlight.openflow.protocol.OFFactories;
import org.projectfloodlight.openflow.protocol.OFMessage;
import org.projectfloodlight.openflow.protocol.OFMessageReader;
/**
* Decode an openflow message from a Channel, for use in a netty pipeline.
*/
public class OFMessageDecoder extends FrameDecoder {
@Override
protected Object decode(ChannelHandlerContext ctx, Channel channel,
ChannelBuffer buffer) throws Exception {
if (!channel.isConnected()) {
// In testing, I see decode being called AFTER decode last.
// This check avoids that from reading corrupted frames
return null;
}
// Note that a single call to decode results in reading a single
// OFMessage from the channel buffer, which is passed on to, and processed
// by, the controller (in OFChannelHandler).
// This is different from earlier behavior (with the original openflowj),
// where we parsed all the messages in the buffer, before passing on
// a list of the parsed messages to the controller.
// The performance *may or may not* not be as good as before.
OFMessageReader<OFMessage> reader = OFFactories.getGenericReader();
OFMessage message = reader.readFrom(buffer);
return message;
}
}
/**
* Copyright 2011, Big Switch Networks, Inc.
* Originally created by David Erickson, Stanford University
*
* 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 net.onrc.onos.of.ctl.internal;
import java.util.List;
import org.jboss.netty.buffer.ChannelBuffer;
import org.jboss.netty.buffer.ChannelBuffers;
import org.jboss.netty.channel.Channel;
import org.jboss.netty.channel.ChannelHandlerContext;
import org.jboss.netty.handler.codec.oneone.OneToOneEncoder;
import org.projectfloodlight.openflow.protocol.OFMessage;
/**
* Encode an openflow message for output into a ChannelBuffer, for use in a
* netty pipeline.
*/
public class OFMessageEncoder extends OneToOneEncoder {
@Override
protected Object encode(ChannelHandlerContext ctx, Channel channel,
Object msg) throws Exception {
if (!(msg instanceof List)) {
return msg;
}
@SuppressWarnings("unchecked")
List<OFMessage> msglist = (List<OFMessage>) msg;
/* XXX S can't get length of OFMessage in loxigen's openflowj??
int size = 0;
for (OFMessage ofm : msglist) {
size += ofm.getLengthU();
}*/
ChannelBuffer buf = ChannelBuffers.dynamicBuffer();
for (OFMessage ofm : msglist) {
ofm.writeTo(buf);
}
return buf;
}
}
/**
* Copyright 2011, Big Switch Networks, Inc.
* Originally created by David Erickson, Stanford University
*
* 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 net.onrc.onos.of.ctl.internal;
import java.util.concurrent.ThreadPoolExecutor;
import org.jboss.netty.channel.ChannelPipeline;
import org.jboss.netty.channel.ChannelPipelineFactory;
import org.jboss.netty.channel.Channels;
import org.jboss.netty.handler.execution.ExecutionHandler;
import org.jboss.netty.handler.timeout.IdleStateHandler;
import org.jboss.netty.handler.timeout.ReadTimeoutHandler;
import org.jboss.netty.util.ExternalResourceReleasable;
import org.jboss.netty.util.HashedWheelTimer;
import org.jboss.netty.util.Timer;
/**
* Creates a ChannelPipeline for a server-side openflow channel.
*/
public class OpenflowPipelineFactory
implements ChannelPipelineFactory, ExternalResourceReleasable {
protected Controller controller;
protected ThreadPoolExecutor pipelineExecutor;
protected Timer timer;
protected IdleStateHandler idleHandler;
protected ReadTimeoutHandler readTimeoutHandler;
public OpenflowPipelineFactory(Controller controller,
ThreadPoolExecutor pipelineExecutor) {
super();
this.controller = controller;
this.pipelineExecutor = pipelineExecutor;
this.timer = new HashedWheelTimer();
this.idleHandler = new IdleStateHandler(timer, 20, 25, 0);
this.readTimeoutHandler = new ReadTimeoutHandler(timer, 30);
}
@Override
public ChannelPipeline getPipeline() throws Exception {
OFChannelHandler handler = new OFChannelHandler(controller);
ChannelPipeline pipeline = Channels.pipeline();
pipeline.addLast("ofmessagedecoder", new OFMessageDecoder());
pipeline.addLast("ofmessageencoder", new OFMessageEncoder());
pipeline.addLast("idle", idleHandler);
pipeline.addLast("timeout", readTimeoutHandler);
// XXX S ONOS: was 15 increased it to fix Issue #296
pipeline.addLast("handshaketimeout",
new HandshakeTimeoutHandler(handler, timer, 60));
if (pipelineExecutor != null) {
pipeline.addLast("pipelineExecutor",
new ExecutionHandler(pipelineExecutor));
}
pipeline.addLast("handler", handler);
return pipeline;
}
@Override
public void releaseExternalResources() {
timer.stop();
}
}
package net.onrc.onos.of.ctl.internal;
/**
* Thrown when IOFSwitch.startDriverHandshake() is called more than once.
*
*/
public class SwitchDriverSubHandshakeAlreadyStarted extends
SwitchDriverSubHandshakeException {
private static final long serialVersionUID = -5491845708752443501L;
public SwitchDriverSubHandshakeAlreadyStarted() {
super();
}
}
package net.onrc.onos.of.ctl.internal;
import org.projectfloodlight.openflow.protocol.OFMessage;
/**
* Indicates that a message was passed to a switch driver's subhandshake
* handling code but the driver has already completed the sub-handshake.
*
*/
public class SwitchDriverSubHandshakeCompleted
extends SwitchDriverSubHandshakeException {
private static final long serialVersionUID = -8817822245846375995L;
public SwitchDriverSubHandshakeCompleted(OFMessage m) {
super("Sub-Handshake is already complete but received message "
+ m.getType());
}
}
package net.onrc.onos.of.ctl.internal;
/**
* Base class for exception thrown by switch driver sub-handshake processing.
*
*/
public class SwitchDriverSubHandshakeException extends RuntimeException {
private static final long serialVersionUID = -6257836781419604438L;
protected SwitchDriverSubHandshakeException() {
super();
}
protected SwitchDriverSubHandshakeException(String arg0, Throwable arg1) {
super(arg0, arg1);
}
protected SwitchDriverSubHandshakeException(String arg0) {
super(arg0);
}
protected SwitchDriverSubHandshakeException(Throwable arg0) {
super(arg0);
}
}
package net.onrc.onos.of.ctl.internal;
/**
* Thrown when a switch driver's sub-handshake has not been started but an
* operation requiring the sub-handshake has been attempted.
*
*/
public class SwitchDriverSubHandshakeNotStarted extends
SwitchDriverSubHandshakeException {
private static final long serialVersionUID = -5491845708752443501L;
public SwitchDriverSubHandshakeNotStarted() {
super();
}
}
package net.onrc.onos.of.ctl.internal;
/**
* Thrown when a switch driver's sub-handshake state-machine receives an
* unexpected OFMessage and/or is in an invald state.
*
*/
public class SwitchDriverSubHandshakeStateException extends
SwitchDriverSubHandshakeException {
private static final long serialVersionUID = -8249926069195147051L;
public SwitchDriverSubHandshakeStateException(String msg) {
super(msg);
}
}
/**
* Copyright 2011, Big Switch Networks, Inc.
* Originally created by David Erickson, Stanford University
*
* 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 net.onrc.onos.of.ctl.internal;
/**
* This exception indicates an error or unexpected message during
* message handling. E.g., if an OFMessage is received that is illegal or
* unexpected given the current handshake state.
*
* We don't allow wrapping other exception in a switch state exception. We
* only log the SwitchStateExceptions message so the causing exceptions
* stack trace is generally not available.
*
*/
public class SwitchStateException extends Exception {
private static final long serialVersionUID = 9153954512470002631L;
public SwitchStateException() {
super();
}
public SwitchStateException(String arg0, Throwable arg1) {
super(arg0, arg1);
}
public SwitchStateException(String arg0) {
super(arg0);
}
public SwitchStateException(Throwable arg0) {
super(arg0);
}
}
package net.onrc.onos.of.ctl.registry;
public class ControllerRegistryEntry implements Comparable<ControllerRegistryEntry> {
//
// TODO: Refactor the implementation and decide whether controllerId
// is needed. If "yes", we might need to consider it inside the
// compareTo(), equals() and hashCode() implementations.
//
private final String controllerId;
private final int sequenceNumber;
public ControllerRegistryEntry(String controllerId, int sequenceNumber) {
this.controllerId = controllerId;
this.sequenceNumber = sequenceNumber;
}
public String getControllerId() {
return controllerId;
}
/**
* Compares this object with the specified object for order.
* NOTE: the test is based on ControllerRegistryEntry sequence numbers,
* and doesn't include the controllerId.
*
* @param o the object to be compared.
* @return a negative integer, zero, or a positive integer as this object
* is less than, equal to, or greater than the specified object.
*/
@Override
public int compareTo(ControllerRegistryEntry o) {
return this.sequenceNumber - o.sequenceNumber;
}
/**
* Test whether some other object is "equal to" this one.
* NOTE: the test is based on ControllerRegistryEntry sequence numbers,
* and doesn't include the controllerId.
*
* @param obj the reference object with which to compare.
* @return true if this object is the same as the obj argument; false
* otherwise.
*/
@Override
public boolean equals(Object obj) {
if (obj instanceof ControllerRegistryEntry) {
ControllerRegistryEntry other = (ControllerRegistryEntry) obj;
return this.sequenceNumber == other.sequenceNumber;
}
return false;
}
/**
* Get the hash code for the object.
* NOTE: the computation is based on ControllerRegistryEntry sequence
* numbers, and doesn't include the controller ID.
*
* @return a hash code value for this object.
*/
@Override
public int hashCode() {
return Integer.valueOf(this.sequenceNumber).hashCode();
}
}
package net.onrc.onos.of.ctl.registry;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import net.onrc.onos.of.ctl.util.InstanceId;
/**
* A registry service that allows ONOS to register controllers and switches in a
* way that is global to the entire ONOS cluster. The registry is the arbiter
* for allowing controllers to control switches.
* <p/>
* The OVS/OF1.{2,3} fault tolerance model is a switch connects to multiple
* controllers, and the controllers send role requests to tell the switch their
* role in controlling the switch.
* <p/>
* The ONOS fault tolerance model allows only a single controller to have
* control of a switch (MASTER role) at once. Controllers therefore need a
* mechanism that enables them to decide who should control a each switch. The
* registry service provides this mechanism.
*/
public interface IControllerRegistry {
/**
* Callback interface for control change events.
*/
public interface ControlChangeCallback {
/**
* Called whenever the control changes from the point of view of the
* registry. The callee can check whether they have control or not using
* the hasControl parameter.
*
* @param dpid The switch that control has changed for
* @param hasControl Whether the listener now has control or not
*/
void controlChanged(long dpid, boolean hasControl);
}
/**
* Request for control of a switch. This method does not block. When control
* for a switch changes, the controlChanged method on the callback object
* will be called. This happens any time the control changes while the
* request is still active (until releaseControl is called)
*
* @param dpid Switch to request control for
* @param cb Callback that will be used to notify caller of control changes
* @throws RegistryException Errors contacting the registry service
*/
public void requestControl(long dpid, ControlChangeCallback cb)
throws RegistryException;
/**
* Stop trying to take control of a switch. This removes the entry for this
* controller requesting this switch in the registry. If the controller had
* control when this is called, another controller will now gain control of
* the switch. This call doesn't block.
*
* @param dpid Switch to release control of
*/
public void releaseControl(long dpid);
/**
* Check whether the controller has control of the switch This call doesn't
* block.
*
* @param dpid Switch to check control of
* @return true if controller has control of the switch.
*/
public boolean hasControl(long dpid);
/**
* Check whether this instance is the leader for the cluster. This call
* doesn't block.
*
* @return true if the instance is the leader for the cluster, otherwise
* false.
*/
public boolean isClusterLeader();
/**
* Gets the unique ID used to identify this ONOS instance in the cluster.
*
* @return Instance ID.
*/
public InstanceId getOnosInstanceId();
/**
* Register a controller to the ONOS cluster. Must be called before the
* registry can be used to take control of any switches.
*
* @param controllerId A unique string ID identifying this controller in the
* cluster
* @throws RegistryException for errors connecting to registry service,
* controllerId already registered
*/
public void registerController(String controllerId)
throws RegistryException;
/**
* Get all controllers in the cluster.
*
* @return Collection of controller IDs
* @throws RegistryException on error
*/
public Collection<String> getAllControllers() throws RegistryException;
/**
* Get all switches in the cluster, along with which controller is in
* control of them (if any) and any other controllers that have requested
* control.
*
* @return Map of all switches.
*/
public Map<String, List<ControllerRegistryEntry>> getAllSwitches();
/**
* Get the controller that has control of a given switch.
*
* @param dpid Switch to find controller for
* @return controller ID
* @throws RegistryException Errors contacting registry service
*/
public String getControllerForSwitch(long dpid) throws RegistryException;
/**
* Get all switches controlled by a given controller.
*
* @param controllerId ID of the controller
* @return Collection of dpids
*/
public Collection<Long> getSwitchesControlledByController(String controllerId);
/**
* Get a unique Id Block.
*
* @return Id Block.
*/
public IdBlock allocateUniqueIdBlock();
/**
* Get next unique id and retrieve a new range of ids if needed.
*
* @param range range to use for the identifier
* @return Id Block.
*/
public IdBlock allocateUniqueIdBlock(long range);
/**
* Get a globally unique ID.
*
* @return a globally unique ID.
*/
public long getNextUniqueId();
}
package net.onrc.onos.of.ctl.registry;
public class IdBlock {
private final long start;
private final long end;
private final long size;
public IdBlock(long start, long end, long size) {
this.start = start;
this.end = end;
this.size = size;
}
public long getStart() {
return start;
}
public long getEnd() {
return end;
}
public long getSize() {
return size;
}
@Override
public String toString() {
return "IdBlock [start=" + start + ", end=" + end + ", size=" + size
+ "]";
}
}
package net.onrc.onos.of.ctl.registry;
public class RegistryException extends Exception {
private static final long serialVersionUID = -8276300722010217913L;
public RegistryException(String message) {
super(message);
}
public RegistryException(String message, Throwable cause) {
super(message, cause);
}
}
package net.onrc.onos.of.ctl.util;
import org.projectfloodlight.openflow.util.HexString;
/**
* The class representing a network switch DPID.
* This class is immutable.
*/
public final class Dpid {
private static final long UNKNOWN = 0;
private final long value;
/**
* Default constructor.
*/
public Dpid() {
this.value = Dpid.UNKNOWN;
}
/**
* Constructor from a long value.
*
* @param value the value to use.
*/
public Dpid(long value) {
this.value = value;
}
/**
* Constructor from a string.
*
* @param value the value to use.
*/
public Dpid(String value) {
this.value = HexString.toLong(value);
}
/**
* Get the value of the DPID.
*
* @return the value of the DPID.
*/
public long value() {
return value;
}
/**
* Convert the DPID value to a ':' separated hexadecimal string.
*
* @return the DPID value as a ':' separated hexadecimal string.
*/
@Override
public String toString() {
return HexString.toHexString(this.value);
}
@Override
public boolean equals(Object other) {
if (!(other instanceof Dpid)) {
return false;
}
Dpid otherDpid = (Dpid) other;
return value == otherDpid.value;
}
@Override
public int hashCode() {
int hash = 17;
hash += 31 * hash + (int) (value ^ value >>> 32);
return hash;
}
}
package net.onrc.onos.of.ctl.util;
import java.io.IOException;
import java.util.Collection;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.Future;
import org.jboss.netty.channel.Channel;
import org.projectfloodlight.openflow.protocol.OFActionType;
import org.projectfloodlight.openflow.protocol.OFCapabilities;
import org.projectfloodlight.openflow.protocol.OFDescStatsReply;
import org.projectfloodlight.openflow.protocol.OFFeaturesReply;
import org.projectfloodlight.openflow.protocol.OFMessage;
import org.projectfloodlight.openflow.protocol.OFPortDesc;
import org.projectfloodlight.openflow.protocol.OFPortDescStatsReply;
import org.projectfloodlight.openflow.protocol.OFPortStatus;
import org.projectfloodlight.openflow.protocol.OFStatsReply;
import org.projectfloodlight.openflow.protocol.OFStatsRequest;
import org.projectfloodlight.openflow.protocol.OFVersion;
import org.projectfloodlight.openflow.types.DatapathId;
import org.projectfloodlight.openflow.types.U64;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import net.onrc.onos.of.ctl.IOFSwitch;
import net.onrc.onos.of.ctl.Role;
import net.onrc.onos.of.ctl.debugcounter.IDebugCounterService;
import net.onrc.onos.of.ctl.debugcounter.IDebugCounterService.CounterException;
public class DummySwitchForTesting implements IOFSwitch {
protected static final Logger log = LoggerFactory.getLogger(DummySwitchForTesting.class);
private Channel channel;
private boolean connected = false;
private OFVersion ofv = OFVersion.OF_10;
private Collection<OFPortDesc> ports;
private DatapathId datapathId;
private Set<OFCapabilities> capabilities;
private int buffers;
private byte tables;
private String stringId;
private Role role;
@Override
public void disconnectSwitch() {
this.channel.close();
}
@Override
public void write(OFMessage m) throws IOException {
this.channel.write(m);
}
@Override
public void write(List<OFMessage> msglist) throws IOException {
for (OFMessage m : msglist) {
this.channel.write(m);
}
}
@Override
public Date getConnectedSince() {
// TODO Auto-generated method stub
return null;
}
@Override
public int getNextTransactionId() {
return 0;
}
@Override
public boolean isConnected() {
return this.connected;
}
@Override
public void setConnected(boolean connected) {
this.connected = connected;
}
@Override
public void flush() {
// TODO Auto-generated method stub
}
@Override
public void setChannel(Channel channel) {
this.channel = channel;
}
@Override
public long getId() {
if (this.stringId == null) {
throw new RuntimeException("Features reply has not yet been set");
}
return this.datapathId.getLong();
}
@Override
public String getStringId() {
// TODO Auto-generated method stub
return "DummySwitch";
}
@Override
public int getNumBuffers() {
// TODO Auto-generated method stub
return 0;
}
@Override
public Set<OFCapabilities> getCapabilities() {
// TODO Auto-generated method stub
return null;
}
@Override
public byte getNumTables() {
// TODO Auto-generated method stub
return 0;
}
@Override
public OFDescStatsReply getSwitchDescription() {
// TODO Auto-generated method stub
return null;
}
@Override
public void cancelFeaturesReply(int transactionId) {
// TODO Auto-generated method stub
}
@Override
public Set<OFActionType> getActions() {
// TODO Auto-generated method stub
return null;
}
@Override
public void setOFVersion(OFVersion version) {
// TODO Auto-generated method stub
}
@Override
public OFVersion getOFVersion() {
return this.ofv;
}
@Override
public Collection<OFPortDesc> getEnabledPorts() {
// TODO Auto-generated method stub
return null;
}
@Override
public Collection<Integer> getEnabledPortNumbers() {
// TODO Auto-generated method stub
return null;
}
@Override
public OFPortDesc getPort(int portNumber) {
// TODO Auto-generated method stub
return null;
}
@Override
public OFPortDesc getPort(String portName) {
// TODO Auto-generated method stub
return null;
}
@Override
public OrderedCollection<PortChangeEvent> processOFPortStatus(
OFPortStatus ps) {
// TODO Auto-generated method stub
return null;
}
@Override
public Collection<OFPortDesc> getPorts() {
return ports;
}
@Override
public boolean portEnabled(int portName) {
// TODO Auto-generated method stub
return false;
}
@Override
public OrderedCollection<PortChangeEvent> setPorts(
Collection<OFPortDesc> p) {
this.ports = p;
return null;
}
@Override
public Map<Object, Object> getAttributes() {
return null;
}
@Override
public boolean hasAttribute(String name) {
// TODO Auto-generated method stub
return false;
}
@Override
public Object getAttribute(String name) {
return Boolean.FALSE;
}
@Override
public void setAttribute(String name, Object value) {
// TODO Auto-generated method stub
}
@Override
public Object removeAttribute(String name) {
// TODO Auto-generated method stub
return null;
}
@Override
public void deliverStatisticsReply(OFMessage reply) {
// TODO Auto-generated method stub
}
@Override
public void cancelStatisticsReply(int transactionId) {
// TODO Auto-generated method stub
}
@Override
public void cancelAllStatisticsReplies() {
// TODO Auto-generated method stub
}
@Override
public Future<List<OFStatsReply>> getStatistics(OFStatsRequest<?> request)
throws IOException {
// TODO Auto-generated method stub
return null;
}
@Override
public void clearAllFlowMods() {
// TODO Auto-generated method stub
}
@Override
public Role getRole() {
return this.role;
}
@Override
public void setRole(Role role) {
this.role = role;
}
@Override
public U64 getNextGenerationId() {
// TODO Auto-generated method stub
return null;
}
@Override
public void setDebugCounterService(IDebugCounterService debugCounter)
throws CounterException {
// TODO Auto-generated method stub
}
@Override
public void startDriverHandshake() throws IOException {
// TODO Auto-generated method stub
}
@Override
public boolean isDriverHandshakeComplete() {
return true;
}
@Override
public void processDriverHandshakeMessage(OFMessage m) {
}
@Override
public void setTableFull(boolean isFull) {
// TODO Auto-generated method stub
}
@Override
public void setFeaturesReply(OFFeaturesReply featuresReply) {
if (featuresReply == null) {
log.error("Error setting featuresReply for switch: {}", getStringId());
return;
}
this.datapathId = featuresReply.getDatapathId();
this.capabilities = featuresReply.getCapabilities();
this.buffers = (int) featuresReply.getNBuffers();
this.tables = (byte) featuresReply.getNTables();
this.stringId = this.datapathId.toString();
}
@Override
public void setPortDescReply(OFPortDescStatsReply portDescReply) {
// TODO Auto-generated method stub
}
@Override
public void handleMessage(OFMessage m) {
log.info("Got packet {} but I am dumb so I don't know what to do.", m);
}
@Override
public boolean portEnabled(String portName) {
// TODO Auto-generated method stub
return false;
}
@Override
public OrderedCollection<PortChangeEvent> comparePorts(
Collection<OFPortDesc> p) {
// TODO Auto-generated method stub
return null;
}
}
package net.onrc.onos.of.ctl.util;
import java.util.EnumSet;
import java.util.Set;
/**
* A utility class to convert between integer based bitmaps for (OpenFlow)
* flags and Enum and EnumSet based representations.
*
* The enum used to represent individual flags needs to implement the
* BitmapableEnum interface.
*
* Example:
* {@code
* int bitmap = 0x11; // OFPPC_PORT_DOWN | OFPPC_NO_STP
* EnumSet<OFPortConfig> s = toEnumSet(OFPortConfig.class, bitmap);
* // s will contain OFPPC_PORT_DOWN and OFPPC_NO_STP
* }
*
* {@code
* EnumSet<OFPortConfig> s = EnumSet.of(OFPPC_NO_STP, OFPPC_PORT_DOWN);
* int bitmap = toBitmap(s); // returns 0x11
* }
*
*/
public final class EnumBitmaps {
private EnumBitmaps() { }
/**
* Enums used to represent individual flags needs to implement this
* interface.
*/
public interface BitmapableEnum {
/** Return the value in the bitmap that the enum constant represents.
* The returned value must have only a single bit set. E.g.,1 << 3
*/
int getValue();
}
/**
* Convert an integer bitmap to an EnumSet.
*
* See class description for example
* @param type The Enum class to use. Must implement BitmapableEnum
* @param bitmap The integer bitmap
* @return A newly allocated EnumSet representing the bits set in the
* bitmap
* @throws NullPointerException if type is null
* @throws IllegalArgumentException if any enum constant from type has
* more than one bit set.
* @throws IllegalArgumentException if the bitmap has any bits set not
* represented by an enum constant.
*/
public static <E extends Enum<E> & BitmapableEnum>
EnumSet<E> toEnumSet(Class<E> type, int bitmap) {
if (type == null) {
throw new NullPointerException("Given enum type must not be null");
}
EnumSet<E> s = EnumSet.noneOf(type);
// allSetBitmap will eventually have all valid bits for the given
// type set.
int allSetBitmap = 0;
for (E element: type.getEnumConstants()) {
if (Integer.bitCount(element.getValue()) != 1) {
String msg = String.format("The %s (%x) constant of the " +
"enum %s is supposed to represent a bitmap entry but " +
"has more than one bit set.",
element.toString(), element.getValue(), type.getName());
throw new IllegalArgumentException(msg);
}
allSetBitmap |= element.getValue();
if ((bitmap & element.getValue()) != 0) {
s.add(element);
}
}
if (((~allSetBitmap) & bitmap) != 0) {
// check if only valid flags are set in the given bitmap
String msg = String.format("The bitmap %x for enum %s has " +
"bits set that are presented by any enum constant",
bitmap, type.getName());
throw new IllegalArgumentException(msg);
}
return s;
}
/**
* Return the bitmap mask with all possible bits set. E.g., If a bitmap
* has the individual flags 0x1, 0x2, and 0x8 (note the missing 0x4) then
* the mask will be 0xb (1011 binary)
*
* @param type The Enum class to use. Must implement BitmapableEnum
* @throws NullPointerException if type is null
* @throws IllegalArgumentException if any enum constant from type has
* more than one bit set
* @return an integer with all possible bits for the given bitmap enum
* type set.
*/
public static <E extends Enum<E> & BitmapableEnum>
int getMask(Class<E> type) {
if (type == null) {
throw new NullPointerException("Given enum type must not be null");
}
// allSetBitmap will eventually have all valid bits for the given
// type set.
int allSetBitmap = 0;
for (E element: type.getEnumConstants()) {
if (Integer.bitCount(element.getValue()) != 1) {
String msg = String.format("The %s (%x) constant of the " +
"enum %s is supposed to represent a bitmap entry but " +
"has more than one bit set.",
element.toString(), element.getValue(), type.getName());
throw new IllegalArgumentException(msg);
}
allSetBitmap |= element.getValue();
}
return allSetBitmap;
}
/**
* Convert the given EnumSet to the integer bitmap representation.
* @param set The EnumSet to convert. The enum must implement
* BitmapableEnum
* @return the integer bitmap
* @throws IllegalArgumentException if an enum constant from the set (!) has
* more than one bit set
* @throws NullPointerException if the set is null
*/
public static <E extends Enum<E> & BitmapableEnum>
int toBitmap(Set<E> set) {
if (set == null) {
throw new NullPointerException("Given set must not be null");
}
int bitmap = 0;
for (E element: set) {
if (Integer.bitCount(element.getValue()) != 1) {
String msg = String.format("The %s (%x) constant in the set " +
"is supposed to represent a bitmap entry but " +
"has more than one bit set.",
element.toString(), element.getValue());
throw new IllegalArgumentException(msg);
}
bitmap |= element.getValue();
}
return bitmap;
}
}
/**
* Copyright 2012, Big Switch Networks, Inc.
* Originally created by David Erickson, Stanford University
*
* 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 net.onrc.onos.of.ctl.util;
import java.util.Iterator;
import java.util.NoSuchElementException;
/**
* An iterator that will filter values from an iterator and return only
* those values that match the predicate.
*/
public abstract class FilterIterator<T> implements Iterator<T> {
protected Iterator<T> subIterator;
protected T next;
/**
* Construct a filter iterator from the given sub iterator.
*
* @param subIterator the sub iterator over which we'll filter
*/
public FilterIterator(Iterator<T> subIterator) {
super();
this.subIterator = subIterator;
}
/**
* Check whether the given value should be returned by the
* filter.
*
* @param value the value to check
* @return true if the value should be included
*/
protected abstract boolean matches(T value);
// ***********
// Iterator<T>
// ***********
@Override
public boolean hasNext() {
if (next != null) {
return true;
}
while (subIterator.hasNext()) {
next = subIterator.next();
if (matches(next)) {
return true;
}
}
next = null;
return false;
}
@Override
public T next() {
if (hasNext()) {
T cur = next;
next = null;
return cur;
}
throw new NoSuchElementException();
}
@Override
public void remove() {
throw new UnsupportedOperationException();
}
}
package net.onrc.onos.of.ctl.util;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Preconditions.checkArgument;
/**
* The class representing an ONOS Instance ID.
*
* This class is immutable.
*/
public final class InstanceId {
private final String id;
/**
* Constructor from a string value.
*
* @param id the value to use.
*/
public InstanceId(String id) {
this.id = checkNotNull(id);
checkArgument(!id.isEmpty(), "Empty ONOS Instance ID");
}
@Override
public int hashCode() {
return id.hashCode();
}
@Override
public boolean equals(Object obj) {
if (obj == this) {
return true;
}
if (!(obj instanceof InstanceId)) {
return false;
}
InstanceId that = (InstanceId) obj;
return this.id.equals(that.id);
}
@Override
public String toString() {
return id;
}
}
/**
* Copyright 2012 Big Switch Networks, Inc.
* Originally created by David Erickson, Stanford University
*
* 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 net.onrc.onos.of.ctl.util;
import java.util.Iterator;
import java.util.NoSuchElementException;
/**
* Iterator over all values in an iterator of iterators.
*
* @param <T> the type of elements returned by this iterator
*/
public class IterableIterator<T> implements Iterator<T> {
Iterator<? extends Iterable<T>> subIterator;
Iterator<T> current = null;
public IterableIterator(Iterator<? extends Iterable<T>> subIterator) {
super();
this.subIterator = subIterator;
}
@Override
public boolean hasNext() {
if (current == null) {
if (subIterator.hasNext()) {
current = subIterator.next().iterator();
} else {
return false;
}
}
while (!current.hasNext() && subIterator.hasNext()) {
current = subIterator.next().iterator();
}
return current.hasNext();
}
@Override
public T next() {
if (hasNext()) {
return current.next();
}
throw new NoSuchElementException();
}
@Override
public void remove() {
if (hasNext()) {
current.remove();
}
throw new NoSuchElementException();
}
}
/**
* Copyright 2011, Big Switch Networks, Inc.
* Originally created by David Erickson, Stanford University
*
* 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 net.onrc.onos.of.ctl.util;
import java.util.LinkedHashMap;
import java.util.Map;
public class LRUHashMap<K, V> extends LinkedHashMap<K, V> {
private static final long serialVersionUID = 1L;
private final int capacity;
public LRUHashMap(int capacity) {
super(capacity + 1, 0.75f, true);
this.capacity = capacity;
}
protected boolean removeEldestEntry(Map.Entry<K, V> eldest) {
return size() > capacity;
}
}
package net.onrc.onos.of.ctl.util;
import java.util.Collection;
import java.util.LinkedHashSet;
import com.google.common.collect.ForwardingCollection;
/**
* A simple wrapper / forwarder that forwards all calls to a LinkedHashSet.
* This wrappers sole reason for existence is to implement the
* OrderedCollection marker interface.
*
*/
public class LinkedHashSetWrapper<E>
extends ForwardingCollection<E> implements OrderedCollection<E> {
private final Collection<E> delegate;
public LinkedHashSetWrapper() {
super();
this.delegate = new LinkedHashSet<E>();
}
public LinkedHashSetWrapper(Collection<? extends E> c) {
super();
this.delegate = new LinkedHashSet<E>(c);
}
@Override
protected Collection<E> delegate() {
return this.delegate;
}
}
/**
* Copyright 2012 Big Switch Networks, Inc.
* Originally created by David Erickson, Stanford University
*
* 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 net.onrc.onos.of.ctl.util;
import java.util.Iterator;
import java.util.NoSuchElementException;
/**
* Iterator over all values in an iterator of iterators.
*
* @param <T> the type of elements returned by this iterator
*/
public class MultiIterator<T> implements Iterator<T> {
Iterator<Iterator<T>> subIterator;
Iterator<T> current = null;
public MultiIterator(Iterator<Iterator<T>> subIterator) {
super();
this.subIterator = subIterator;
}
@Override
public boolean hasNext() {
if (current == null) {
if (subIterator.hasNext()) {
current = subIterator.next();
} else {
return false;
}
}
while (!current.hasNext() && subIterator.hasNext()) {
current = subIterator.next();
}
return current.hasNext();
}
@Override
public T next() {
if (hasNext()) {
return current.next();
}
throw new NoSuchElementException();
}
@Override
public void remove() {
if (hasNext()) {
current.remove();
}
throw new NoSuchElementException();
}
}
package net.onrc.onos.of.ctl.util;
import java.util.Collection;
/**
* A marker interface indicating that this Collection defines a particular
* iteration order. The details about the iteration order are specified by
* the concrete implementation.
*
* @param <E>
*/
public interface OrderedCollection<E> extends Collection<E> {
}
<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>
<groupId>org.sonatype.oss</groupId>
<artifactId>oss-parent</artifactId>
<version>7</version>
</parent>
<groupId>org.projectfloodlight</groupId>
<artifactId>openflowj</artifactId>
<version>0.3.6-SNAPSHOT</version>
<packaging>bundle</packaging>
<name>OpenFlowJ-Loxi</name>
<description>OpenFlowJ API supporting OpenFlow versions 1.0 through 1.3.1, generated by LoxiGen</description>
<url>http://www.projectfloodlight.org/projects/</url>
<licenses>
<license>
<name>The Apache Software License, Version 2.0</name>
<url>http://www.apache.org/licenses/LICENSE-2.0.txt</url>
<distribution>repo</distribution>
</license>
</licenses>
<scm>
<connection>scm:git:git@github.com:floodlight/loxigen.git</connection>
<developerConnection>scm:git:git@github.com:floodlight/loxigen.git</developerConnection>
<url>git@github.com:floodlight/loxigen.git</url>
</scm>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>com.google.code.findbugs</groupId>
<artifactId>annotations</artifactId>
<version>2.0.2</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.hamcrest</groupId>
<artifactId>hamcrest-integration</artifactId>
<version>1.3</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty</artifactId>
<version>3.9.0.Final</version>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>15.0</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.5</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-core</artifactId>
<version>1.0.13</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.0.13</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.felix</groupId>
<artifactId>maven-bundle-plugin</artifactId>
<version>2.3.6</version>
<extensions>true</extensions>
<configuration>
<instructions>
<Bundle-SymbolicName>${project.groupId}.${project.artifactId}</Bundle-SymbolicName>
</instructions>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.1</version>
<configuration>
<source>1.7</source>
<target>1.7</target>
</configuration>
</plugin>
<plugin>
<!-- pick up sources from gen-src -->
<groupId>org.codehaus.mojo</groupId>
<artifactId>build-helper-maven-plugin</artifactId>
<version>1.8</version>
<executions>
<execution>
<id>gen-src-add-source</id>
<phase>generate-sources</phase>
<goals><goal>add-source</goal></goals>
<configuration>
<sources>
<source>gen-src/main/java</source>
</sources>
</configuration>
</execution>
<execution>
<id>add-gen-src-test-source</id>
<!-- note: purposefully not using phase generate-test-sources, because that is not picked up by eclipse:eclipse -->
<phase>validate</phase>
<goals><goal>add-test-source</goal></goals>
<configuration>
<sources>
<source>gen-src/test/java</source>
</sources>
</configuration>
</execution>
</executions>
</plugin>
<!-- attach sources -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<version>2.2.1</version>
<executions>
<execution>
<id>attach-sources</id>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>
<!-- attach javadoc -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>2.9.1</version>
<executions>
<execution>
<id>attach-javadocs</id>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-eclipse-plugin</artifactId>
<version>2.9</version>
<configuration>
<downloadSources>true</downloadSources>
<downloadJavadocs>true</downloadJavadocs>
</configuration>
</plugin>
<!-- use maven git-commit-id plugin to provide vcs metadata -->
<plugin>
<groupId>pl.project13.maven</groupId>
<artifactId>git-commit-id-plugin</artifactId>
<version>2.1.5</version>
<executions>
<execution>
<goals>
<goal>revision</goal>
</goals>
</execution>
</executions>
<configuration>
<!-- our BuildInfoManager expects dates to be in ISO-8601 format -->
<dateFormat>yyyy-MM-dd'T'HH:mm:ssZ</dateFormat>
<verbose>true</verbose>
<skipPoms>true</skipPoms>
<generateGitPropertiesFile>false</generateGitPropertiesFile>
<dotGitDirectory>${project.basedir}/../../.git</dotGitDirectory>
<failOnNoGitDirectory>false</failOnNoGitDirectory>
<gitDescribe>
<skip>true</skip>
<always>true</always>
<abbrev>7</abbrev>
<dirty>-dirty</dirty>
<forceLongFormat>false</forceLongFormat>
</gitDescribe>
</configuration>
</plugin>
<!-- include git info in generated jars -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>2.4</version>
<executions>
<execution>
<goals>
<goal>test-jar</goal>
</goals>
</execution>
</executions>
<configuration>
<archive>
<manifest>
<mainClass>org.projectfloodlight.core.Main</mainClass>
</manifest>
<manifestSections>
<manifestSection>
<name>Floodlight-buildinfo</name>
<manifestEntries>
<projectName>${project.name}</projectName>
<version>${project.version}</version>
<vcsRevision>${git.commit.id.abbrev}</vcsRevision>
<!-- note: git.branch does not work in jenkins, because jenkins
builds the system in 'detached head' state. Because we mostly
about jenkins builds, we instead use the environment variable
GIT_BRANCH set by jenkins here -->
<vcsBranch>${env.GIT_BRANCH}</vcsBranch>
<buildUser>${user.name}</buildUser>
<buildDate>${git.build.time}</buildDate>
<!-- continuous integration information from jenkins env variables:
https://wiki.jenkins-ci.org/display/JENKINS/Building+a+software+project#Buildingasoftwareproject-below -->
<ciBuildNumber>${env.BUILD_NUMBER}</ciBuildNumber>
<ciBuildId>${env.BUILD_ID}</ciBuildId>
<ciBuildTag>${env.BUILD_TAG}</ciBuildTag>
<ciJobName>${env.JOB_NAME}</ciJobName>
i <ciNodeName>${env.NODE_NAME}</ciNodeName>
</manifestEntries>
</manifestSection>
</manifestSections>
</archive>
</configuration>
</plugin>
<!--
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-gpg-plugin</artifactId>
<version>1.4</version>
<executions>
<execution>
<id>sign-artifacts</id>
<phase>verify</phase>
<goals>
<goal>sign</goal>
</goals>
</execution>
</executions>
</plugin>
-->
</plugins>
<resources>
<resource>
<directory>${basedir}</directory>
<filtering>false</filtering>
<includes>
<include>LICENSE.txt</include>
</includes>
</resource>
</resources>
</build>
</project>
package org.projectfloodlight.openflow.annotations;
/**
* This annotation marks a class that is considered externally immutable. I.e.,
* the externally visible state of the class will not change after its
* construction. Such a class can be freely shared between threads and does not
* require defensive copying (don't call clone).
*
* @author Andreas Wundsam <andreas.wundsam@bigswitch.com>
*/
public @interface Immutable {
}
package org.projectfloodlight.openflow.exceptions;
/**
* Error: someone asked to create an OFMessage with wireformat type and version,
* but that doesn't exist
*
* @author capveg
*/
public class NonExistantMessage extends Exception {
private static final long serialVersionUID = 1L;
byte type;
byte version;
/**
* Error: someone asked to create an OFMessage with wireformat type and
* version, but that doesn't exist
*
* @param type
* the wire format
* @param version
* the OpenFlow wireformat version number, e.g. 1 == v1.1, 2 =
* v1.2, etc.
*/
public NonExistantMessage(final byte type, final byte version) {
this.type = type;
this.version = version;
}
}
package org.projectfloodlight.openflow.exceptions;
public class OFParseError extends Exception {
private static final long serialVersionUID = 1L;
public OFParseError() {
super();
}
public OFParseError(final String message, final Throwable cause) {
super(message, cause);
}
public OFParseError(final String message) {
super(message);
}
public OFParseError(final Throwable cause) {
super(cause);
}
}
package org.projectfloodlight.openflow.exceptions;
public class OFShortRead extends Exception {
private static final long serialVersionUID = 1L;
}
package org.projectfloodlight.openflow.exceptions;
public class OFShortWrite extends Exception {
private static final long serialVersionUID = 1L;
}
package org.projectfloodlight.openflow.exceptions;
public class OFUnsupported extends Exception {
private static final long serialVersionUID = 1L;
}
package org.projectfloodlight.openflow.protocol;
public class OFBsnVportQInQT {
}
package org.projectfloodlight.openflow.protocol;
import org.projectfloodlight.openflow.types.PrimitiveSinkable;
import com.google.common.hash.PrimitiveSink;
public class OFMatchBmap implements PrimitiveSinkable{
@Override
public void putTo(PrimitiveSink sink) {
}
}
package org.projectfloodlight.openflow.protocol;
import org.jboss.netty.buffer.ChannelBuffer;
import org.projectfloodlight.openflow.exceptions.OFParseError;
public interface OFMessageReader<T> {
T readFrom(ChannelBuffer bb) throws OFParseError;
}
package org.projectfloodlight.openflow.protocol;
import org.jboss.netty.buffer.ChannelBuffer;
import org.projectfloodlight.openflow.exceptions.OFParseError;
public interface OFMessageWriter<T> {
public void write(ChannelBuffer bb, T message) throws OFParseError;
}
package org.projectfloodlight.openflow.protocol;
import org.projectfloodlight.openflow.types.PrimitiveSinkable;
/**
* Base interface of all OpenFlow objects (e.g., messages, actions, stats, etc.)
*/
public interface OFObject extends Writeable, PrimitiveSinkable {
OFVersion getVersion();
}
package org.projectfloodlight.openflow.protocol;
import org.jboss.netty.buffer.ChannelBuffer;
public interface OFObjectFactory<T extends OFObject> {
T read(ChannelBuffer buffer);
}
package org.projectfloodlight.openflow.protocol;
import java.util.EnumMap;
import java.util.Iterator;
import java.util.Map;
import org.jboss.netty.buffer.ChannelBuffer;
import org.projectfloodlight.openflow.exceptions.OFParseError;
import org.projectfloodlight.openflow.protocol.match.MatchField;
import org.projectfloodlight.openflow.protocol.match.MatchFields;
import org.projectfloodlight.openflow.protocol.oxm.OFOxm;
import org.projectfloodlight.openflow.types.OFValueType;
import org.projectfloodlight.openflow.types.PrimitiveSinkable;
import org.projectfloodlight.openflow.util.ChannelUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.common.base.Objects;
import com.google.common.collect.ImmutableMap;
import com.google.common.hash.PrimitiveSink;
public class OFOxmList implements Iterable<OFOxm<?>>, Writeable, PrimitiveSinkable {
private static final Logger logger = LoggerFactory.getLogger(OFOxmList.class);
private final Map<MatchFields, OFOxm<?>> oxmMap;
public final static OFOxmList EMPTY = new OFOxmList(ImmutableMap.<MatchFields, OFOxm<?>>of());
private OFOxmList(Map<MatchFields, OFOxm<?>> oxmMap) {
this.oxmMap = oxmMap;
}
@SuppressWarnings("unchecked")
public <T extends OFValueType<T>> OFOxm<T> get(MatchField<T> matchField) {
return (OFOxm<T>) oxmMap.get(matchField.id);
}
public static class Builder {
private final Map<MatchFields, OFOxm<?>> oxmMap;
public Builder() {
oxmMap = new EnumMap<MatchFields, OFOxm<?>>(MatchFields.class);
}
public Builder(EnumMap<MatchFields, OFOxm<?>> oxmMap) {
this.oxmMap = oxmMap;
}
public <T extends OFValueType<T>> void set(OFOxm<T> oxm) {
oxmMap.put(oxm.getMatchField().id, oxm);
}
public <T extends OFValueType<T>> void unset(MatchField<T> matchField) {
oxmMap.remove(matchField.id);
}
public OFOxmList build() {
return OFOxmList.ofList(oxmMap.values());
}
}
@Override
public Iterator<OFOxm<?>> iterator() {
return oxmMap.values().iterator();
}
public static OFOxmList ofList(Iterable<OFOxm<?>> oxmList) {
Map<MatchFields, OFOxm<?>> map = new EnumMap<MatchFields, OFOxm<?>>(
MatchFields.class);
for (OFOxm<?> o : oxmList) {
OFOxm<?> canonical = o.getCanonical();
if(logger.isDebugEnabled() && !Objects.equal(o, canonical)) {
logger.debug("OFOxmList: normalized non-canonical OXM {} to {}", o, canonical);
}
if(canonical != null)
map.put(canonical.getMatchField().id, canonical);
}
return new OFOxmList(map);
}
public static OFOxmList of(OFOxm<?>... oxms) {
Map<MatchFields, OFOxm<?>> map = new EnumMap<MatchFields, OFOxm<?>>(
MatchFields.class);
for (OFOxm<?> o : oxms) {
OFOxm<?> canonical = o.getCanonical();
if(logger.isDebugEnabled() && !Objects.equal(o, canonical)) {
logger.debug("OFOxmList: normalized non-canonical OXM {} to {}", o, canonical);
}
if(canonical != null)
map.put(canonical.getMatchField().id, canonical);
}
return new OFOxmList(map);
}
public static OFOxmList readFrom(ChannelBuffer bb, int length,
OFMessageReader<OFOxm<?>> reader) throws OFParseError {
return ofList(ChannelUtils.readList(bb, length, reader));
}
@Override
public void writeTo(ChannelBuffer bb) {
for (OFOxm<?> o : this) {
o.writeTo(bb);
}
}
public OFOxmList.Builder createBuilder() {
return new OFOxmList.Builder(new EnumMap<MatchFields, OFOxm<?>>(oxmMap));
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((oxmMap == null) ? 0 : oxmMap.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
OFOxmList other = (OFOxmList) obj;
if (oxmMap == null) {
if (other.oxmMap != null)
return false;
} else if (!oxmMap.equals(other.oxmMap))
return false;
return true;
}
@Override
public String toString() {
return "OFOxmList" + oxmMap;
}
@Override
public void putTo(PrimitiveSink sink) {
for (OFOxm<?> o : this) {
o.putTo(sink);
}
}
}
package org.projectfloodlight.openflow.protocol;
/** Type safety interface. Enables type safe combinations of requests and replies */
public interface OFRequest<REPLY extends OFMessage> extends OFMessage {
}
package org.projectfloodlight.openflow.protocol;
public class OFTableFeature {
// FIXME implement
}
package org.projectfloodlight.openflow.protocol;
public enum OFVersion {
OF_10(1), OF_11(2), OF_12(3), OF_13(4);
public final int wireVersion;
OFVersion(final int wireVersion) {
this.wireVersion = wireVersion;
}
public int getWireVersion() {
return wireVersion;
}
}
package org.projectfloodlight.openflow.protocol;
import org.jboss.netty.buffer.ChannelBuffer;
public interface Writeable {
void writeTo(ChannelBuffer bb);
}
package org.projectfloodlight.openflow.protocol;
public interface XidGenerator {
long nextXid();
}
package org.projectfloodlight.openflow.protocol;
import java.util.concurrent.atomic.AtomicLong;
public class XidGenerators {
private static final XidGenerator GLOBAL_XID_GENERATOR = new StandardXidGenerator();
public static XidGenerator create() {
return new StandardXidGenerator();
}
public static XidGenerator global() {
return GLOBAL_XID_GENERATOR;
}
}
class StandardXidGenerator implements XidGenerator {
private final AtomicLong xidGen = new AtomicLong();
long MAX_XID = 0xFFffFFffL;
@Override
public long nextXid() {
long xid;
do {
xid = xidGen.incrementAndGet();
if(xid > MAX_XID) {
synchronized(this) {
if(xidGen.get() > MAX_XID) {
xidGen.set(0);
}
}
}
} while(xid > MAX_XID);
return xid;
}
}
\ No newline at end of file
package org.projectfloodlight.openflow.protocol.match;
import org.projectfloodlight.openflow.protocol.OFObject;
import org.projectfloodlight.openflow.types.Masked;
import org.projectfloodlight.openflow.types.OFValueType;
/**
* Generic interface for version-agnostic immutable Match structure.
* The Match structure is defined in the OpenFlow protocol, and it contains information on
* the fields to be matched in a specific flow record.
* This interface does not assume anything on the fields in the Match structure. If in
* some version, the match structure cannot handle a certain field, it may return <code>false</code>
* for <code>supports(...)</code> calls, and throw <code>UnsupportedOperationException</code> from all
* other methods in such cases.
* <br><br>
* On wildcards and masks:<br>
* This interface defines the following masking notations for fields:
* <ul>
* <li><b>Exact</b>: field is matched exactly against a single, fixed value (no mask, or mask is all ones).
* <li><b>Wildcarded</b>: field is not being matched. It is fully masked (mask=0) and any value of it
* will match the flow record having this match.
* <li><b>Partially masked</b>: field is matched using a specified mask which is neither 0 nor all ones. Mask can
* be either arbitrary or require some specific structure.
* </ul>
* Implementing classes may or may not support all types of these masking types. They may also support
* them in part. For example, OF1.0 supports exact match and (full) wildcarding for all fields, but it
* does only supports partial masking for IP source/destination fields, and this partial masking must be
* in the CIDR prefix format. Thus, OF1.0 implementation may throw <code>UnsupportedOperationException</code> if given
* in <code>setMasked</code> an IP mask of, for example, 255.0.255.0, or if <code>setMasked</code> is called for any field
* which is not IP source/destination address.
* <br><br>
* On prerequisites:<br>
* From the OF1.1 spec, page 28, the OF1.0 spec failed to explicitly specify this, but it
* is the behavior of OF1.0 switches:
* "Protocol-specific fields within ofp_match will be ignored within a single table when
* the corresponding protocol is not specified in the match. The MPLS match fields will
* be ignored unless the Ethertype is specified as MPLS. Likewise, the IP header and
* transport header fields will be ignored unless the Ethertype is specified as either
* IPv4 or ARP. The tp_src and tp_dst fields will be ignored unless the network protocol
* specified is as TCP, UDP or SCTP. Fields that are ignored don't need to be wildcarded
* and should be set to 0."
* <br><br>
* This interface uses generics to assure type safety in users code. However, implementing classes may have to suppress
* 'unchecked cast' warnings while making sure they correctly cast base on their implementation details.
*
* @author Yotam Harchol (yotam.harchol@bigswitch.com)
*/
public interface Match extends OFObject {
/**
* Returns a value for the given field if:
* <ul>
* <li>Field is supported
* <li>Field is not fully wildcarded
* <li>Prerequisites are ok
* </ul>
* If one of the above conditions does not hold, returns null. Value is returned masked if partially wildcarded.
*
* @param field Match field to retrieve
* @return Value of match field (may be masked), or <code>null</code> if field is one of the conditions above does not hold.
* @throws UnsupportedOperationException If field is not supported.
*/
public <F extends OFValueType<F>> F get(MatchField<F> field) throws UnsupportedOperationException;
/**
* Returns the masked value for the given field from this match, along with the mask itself.
* Prerequisite: field is partially masked.
* If prerequisite is not met, a <code>null</code> is returned.
*
* @param field Match field to retrieve.
* @return Masked value of match field or null if no mask is set.
* @throws UnsupportedOperationException If field is not supported.
*/
public <F extends OFValueType<F>> Masked<F> getMasked(MatchField<F> field) throws UnsupportedOperationException;
/**
* Returns true if and only if this match object supports the given match field.
*
* @param field Match field
* @return true if field is supported, false otherwise.
*/
public boolean supports(MatchField<?> field);
/**
* Returns true if and only if this match object supports partially bitmasking of the given field.
* (note: not all possible values of this bitmask have to be acceptable)
*
* @param field Match field.
* @return true if field can be partially masked, false otherwise.
* @throws UnsupportedOperationException If field is not supported.
*/
public boolean supportsMasked(MatchField<?> field) throws UnsupportedOperationException;
/**
* Returns true if and only if this field is currently specified in the match with an exact value and
* no mask. I.e., the specified match will only select packets that match the exact value of getValue(field).
*
* @param field Match field.
* @return true if field has a specific exact value, false if not.
* @throws UnsupportedOperationException If field is not supported.
*/
public boolean isExact(MatchField<?> field) throws UnsupportedOperationException;
/**
* True if and only if this field is currently logically unspecified in the match, i.e, the
* value returned by getValue(f) has no impact on whether a packet will be selected
* by the match or not.
*
* @param field Match field.
* @return true if field is fully wildcarded, false if not.
* @throws UnsupportedOperationException If field is not supported.
*/
public boolean isFullyWildcarded(MatchField<?> field) throws UnsupportedOperationException;
/**
* True if and only if this field is currently partially specified in the match, i.e, the
* match will only select packets that match (p.value & getMask(field)) == getValue(field),
* and getMask(field) != 0.
*
* @param field Match field.
* @return true if field is partially masked, false if not.
* @throws UnsupportedOperationException If field is not supported.
*/
public boolean isPartiallyMasked(MatchField<?> field) throws UnsupportedOperationException;
/**
* Get an Iterable over the match fields that have been specified for the
* match. This includes the match fields that are exact or masked match
* (but not fully wildcarded).
*
* @return
*/
public Iterable<MatchField<?>> getMatchFields();
/**
* Returns a builder to build new instances of this type of match object.
* @return Match builder
*/
public Builder createBuilder();
/**
* Builder interface for Match objects.
* Builder is used to create new Match objects and it creates the match according to the version it
* corresponds to. The builder uses the same notation of wildcards and masks, and can also throw
* <code>UnsupportedOperationException</code> if it is asked to create some matching that is not supported in
* the version it represents.
*
* While used, MatchBuilder may not be consistent in terms of field prerequisites. However, user must
* solve these before using the generated Match object as these prerequisites should be enforced in the
* getters.
*
* @author Yotam Harchol (yotam.harchol@bigswitch.com)
*/
interface Builder {
public <F extends OFValueType<F>> F get(MatchField<F> field) throws UnsupportedOperationException;
public <F extends OFValueType<F>> Masked<F> getMasked(MatchField<F> field) throws UnsupportedOperationException;
public boolean supports(MatchField<?> field);
public boolean supportsMasked(MatchField<?> field) throws UnsupportedOperationException;
public boolean isExact(MatchField<?> field) throws UnsupportedOperationException;
public boolean isFullyWildcarded(MatchField<?> field) throws UnsupportedOperationException;
public boolean isPartiallyMasked(MatchField<?> field) throws UnsupportedOperationException;
/**
* Sets a specific exact value for a field.
*
* @param field Match field to set.
* @param value Value of match field.
* @return the Builder instance used.
* @throws UnsupportedOperationException If field is not supported.
*/
public <F extends OFValueType<F>> Builder setExact(MatchField<F> field, F value) throws UnsupportedOperationException;
/**
* Sets a masked value for a field.
*
* @param field Match field to set.
* @param value Value of field.
* @param mask Mask value.
* @return the Builder instance used.
* @throws UnsupportedOperationException If field is not supported, if field is supported but does not support masking, or if mask structure is not supported.
*/
public <F extends OFValueType<F>> Builder setMasked(MatchField<F> field, F value, F mask) throws UnsupportedOperationException;
/**
* Sets a masked value for a field.
*
* @param field Match field to set.
* @param valueWithMask Compound Masked object contains the value and the mask.
* @return the Builder instance used.
* @throws UnsupportedOperationException If field is not supported, if field is supported but does not support masking, or if mask structure is not supported.
*/
public <F extends OFValueType<F>> Builder setMasked(MatchField<F> field, Masked<F> valueWithMask) throws UnsupportedOperationException;
/**
* Unsets any value given for the field and wildcards it so that it matches any value.
*
* @param field Match field to unset.
* @return the Builder instance used.
* @throws UnsupportedOperationException If field is not supported.
*/
public <F extends OFValueType<F>> Builder wildcard(MatchField<F> field) throws UnsupportedOperationException;
/**
* Returns the match created by this builder.
*
* @return a Match object.
*/
public Match build();
}
}
\ No newline at end of file
package org.projectfloodlight.openflow.protocol.match;
import org.projectfloodlight.openflow.types.ArpOpcode;
import org.projectfloodlight.openflow.types.ClassId;
import org.projectfloodlight.openflow.types.EthType;
import org.projectfloodlight.openflow.types.ICMPv4Code;
import org.projectfloodlight.openflow.types.ICMPv4Type;
import org.projectfloodlight.openflow.types.IPv4Address;
import org.projectfloodlight.openflow.types.IPv6Address;
import org.projectfloodlight.openflow.types.IPv6FlowLabel;
import org.projectfloodlight.openflow.types.IpDscp;
import org.projectfloodlight.openflow.types.IpEcn;
import org.projectfloodlight.openflow.types.IpProtocol;
import org.projectfloodlight.openflow.types.LagId;
import org.projectfloodlight.openflow.types.MacAddress;
import org.projectfloodlight.openflow.types.OFBitMask128;
import org.projectfloodlight.openflow.types.OFBooleanValue;
import org.projectfloodlight.openflow.types.OFMetadata;
import org.projectfloodlight.openflow.types.OFPort;
import org.projectfloodlight.openflow.types.OFValueType;
import org.projectfloodlight.openflow.types.OFVlanVidMatch;
import org.projectfloodlight.openflow.types.TransportPort;
import org.projectfloodlight.openflow.types.U16;
import org.projectfloodlight.openflow.types.U64;
import org.projectfloodlight.openflow.types.U32;
import org.projectfloodlight.openflow.types.U8;
import org.projectfloodlight.openflow.types.UDF;
import org.projectfloodlight.openflow.types.VRF;
import org.projectfloodlight.openflow.types.VlanPcp;
@SuppressWarnings("unchecked")
public class MatchField<F extends OFValueType<F>> {
private final String name;
public final MatchFields id;
private final Prerequisite<?>[] prerequisites;
private MatchField(final String name, final MatchFields id, Prerequisite<?>... prerequisites) {
this.name = name;
this.id = id;
this.prerequisites = prerequisites;
}
public final static MatchField<OFPort> IN_PORT =
new MatchField<OFPort>("in_port", MatchFields.IN_PORT);
public final static MatchField<OFPort> IN_PHY_PORT =
new MatchField<OFPort>("in_phy_port", MatchFields.IN_PHY_PORT,
new Prerequisite<OFPort>(MatchField.IN_PORT));
public final static MatchField<OFMetadata> METADATA =
new MatchField<OFMetadata>("metadata", MatchFields.METADATA);
public final static MatchField<MacAddress> ETH_DST =
new MatchField<MacAddress>("eth_dst", MatchFields.ETH_DST);
public final static MatchField<MacAddress> ETH_SRC =
new MatchField<MacAddress>("eth_src", MatchFields.ETH_SRC);
public final static MatchField<EthType> ETH_TYPE =
new MatchField<EthType>("eth_type", MatchFields.ETH_TYPE);
public final static MatchField<OFVlanVidMatch> VLAN_VID =
new MatchField<OFVlanVidMatch>("vlan_vid", MatchFields.VLAN_VID);
public final static MatchField<VlanPcp> VLAN_PCP =
new MatchField<VlanPcp>("vlan_pcp", MatchFields.VLAN_PCP,
new Prerequisite<OFVlanVidMatch>(MatchField.VLAN_VID));
public final static MatchField<IpDscp> IP_DSCP =
new MatchField<IpDscp>("ip_dscp", MatchFields.IP_DSCP,
new Prerequisite<EthType>(MatchField.ETH_TYPE, EthType.IPv4, EthType.IPv6));
public final static MatchField<IpEcn> IP_ECN =
new MatchField<IpEcn>("ip_ecn", MatchFields.IP_ECN,
new Prerequisite<EthType>(MatchField.ETH_TYPE, EthType.IPv4, EthType.IPv6));
public final static MatchField<IpProtocol> IP_PROTO =
new MatchField<IpProtocol>("ip_proto", MatchFields.IP_PROTO,
new Prerequisite<EthType>(MatchField.ETH_TYPE, EthType.IPv4, EthType.IPv6));
public final static MatchField<IPv4Address> IPV4_SRC =
new MatchField<IPv4Address>("ipv4_src", MatchFields.IPV4_SRC,
new Prerequisite<EthType>(MatchField.ETH_TYPE, EthType.IPv4));
public final static MatchField<IPv4Address> IPV4_DST =
new MatchField<IPv4Address>("ipv4_dst", MatchFields.IPV4_DST,
new Prerequisite<EthType>(MatchField.ETH_TYPE, EthType.IPv4));
public final static MatchField<TransportPort> TCP_SRC = new MatchField<TransportPort>(
"tcp_src", MatchFields.TCP_SRC,
new Prerequisite<IpProtocol>(MatchField.IP_PROTO, IpProtocol.TCP));
public final static MatchField<TransportPort> TCP_DST = new MatchField<TransportPort>(
"tcp_dst", MatchFields.TCP_DST,
new Prerequisite<IpProtocol>(MatchField.IP_PROTO, IpProtocol.TCP));
public final static MatchField<TransportPort> UDP_SRC = new MatchField<TransportPort>(
"udp_src", MatchFields.UDP_SRC,
new Prerequisite<IpProtocol>(MatchField.IP_PROTO, IpProtocol.UDP));
public final static MatchField<TransportPort> UDP_DST = new MatchField<TransportPort>(
"udp_dst", MatchFields.UDP_DST,
new Prerequisite<IpProtocol>(MatchField.IP_PROTO, IpProtocol.UDP));
public final static MatchField<TransportPort> SCTP_SRC = new MatchField<TransportPort>(
"sctp_src", MatchFields.SCTP_SRC,
new Prerequisite<IpProtocol>(MatchField.IP_PROTO, IpProtocol.SCTP));
public final static MatchField<TransportPort> SCTP_DST = new MatchField<TransportPort>(
"sctp_dst", MatchFields.SCTP_DST,
new Prerequisite<IpProtocol>(MatchField.IP_PROTO, IpProtocol.SCTP));
public final static MatchField<ICMPv4Type> ICMPV4_TYPE = new MatchField<ICMPv4Type>(
"icmpv4_type", MatchFields.ICMPV4_TYPE,
new Prerequisite<IpProtocol>(MatchField.IP_PROTO, IpProtocol.ICMP));
public final static MatchField<ICMPv4Code> ICMPV4_CODE = new MatchField<ICMPv4Code>(
"icmpv4_code", MatchFields.ICMPV4_CODE,
new Prerequisite<IpProtocol>(MatchField.IP_PROTO, IpProtocol.ICMP));
public final static MatchField<ArpOpcode> ARP_OP = new MatchField<ArpOpcode>(
"arp_op", MatchFields.ARP_OP,
new Prerequisite<EthType>(MatchField.ETH_TYPE, EthType.ARP));
public final static MatchField<IPv4Address> ARP_SPA =
new MatchField<IPv4Address>("arp_spa", MatchFields.ARP_SPA,
new Prerequisite<EthType>(MatchField.ETH_TYPE, EthType.ARP));
public final static MatchField<IPv4Address> ARP_TPA =
new MatchField<IPv4Address>("arp_tpa", MatchFields.ARP_TPA,
new Prerequisite<EthType>(MatchField.ETH_TYPE, EthType.ARP));
public final static MatchField<MacAddress> ARP_SHA =
new MatchField<MacAddress>("arp_sha", MatchFields.ARP_SHA,
new Prerequisite<EthType>(MatchField.ETH_TYPE, EthType.ARP));
public final static MatchField<MacAddress> ARP_THA =
new MatchField<MacAddress>("arp_tha", MatchFields.ARP_THA,
new Prerequisite<EthType>(MatchField.ETH_TYPE, EthType.ARP));
public final static MatchField<IPv6Address> IPV6_SRC =
new MatchField<IPv6Address>("ipv6_src", MatchFields.IPV6_SRC,
new Prerequisite<EthType>(MatchField.ETH_TYPE, EthType.IPv6));
public final static MatchField<IPv6Address> IPV6_DST =
new MatchField<IPv6Address>("ipv6_dst", MatchFields.IPV6_DST,
new Prerequisite<EthType>(MatchField.ETH_TYPE, EthType.IPv6));
public final static MatchField<IPv6FlowLabel> IPV6_FLABEL =
new MatchField<IPv6FlowLabel>("ipv6_flabel", MatchFields.IPV6_FLABEL,
new Prerequisite<EthType>(MatchField.ETH_TYPE, EthType.IPv6));
public final static MatchField<U8> ICMPV6_TYPE =
new MatchField<U8>("icmpv6_type", MatchFields.ICMPV6_TYPE,
new Prerequisite<IpProtocol>(MatchField.IP_PROTO, IpProtocol.IPv6_ICMP));
public final static MatchField<U8> ICMPV6_CODE =
new MatchField<U8>("icmpv6_code", MatchFields.ICMPV6_CODE,
new Prerequisite<IpProtocol>(MatchField.IP_PROTO, IpProtocol.IPv6_ICMP));
public final static MatchField<IPv6Address> IPV6_ND_TARGET =
new MatchField<IPv6Address>("ipv6_nd_target", MatchFields.IPV6_ND_TARGET,
new Prerequisite<U8>(MatchField.ICMPV6_TYPE, U8.of((short)135), U8.of((short)136)));
public final static MatchField<MacAddress> IPV6_ND_SLL =
new MatchField<MacAddress>("ipv6_nd_sll", MatchFields.IPV6_ND_SLL,
new Prerequisite<U8>(MatchField.ICMPV6_TYPE, U8.of((short)135)));
public final static MatchField<MacAddress> IPV6_ND_TLL =
new MatchField<MacAddress>("ipv6_nd_tll", MatchFields.IPV6_ND_TLL,
new Prerequisite<U8>(MatchField.ICMPV6_TYPE, U8.of((short)136)));
public final static MatchField<U32> MPLS_LABEL =
new MatchField<U32>("mpls_label", MatchFields.MPLS_LABEL,
new Prerequisite<EthType>(MatchField.ETH_TYPE, EthType.MPLS_UNICAST, EthType.MPLS_MULTICAST));
public final static MatchField<U8> MPLS_TC =
new MatchField<U8>("mpls_tc", MatchFields.MPLS_TC,
new Prerequisite<EthType>(MatchField.ETH_TYPE, EthType.MPLS_UNICAST, EthType.MPLS_MULTICAST));
public final static MatchField<U64> TUNNEL_ID =
new MatchField<U64>("tunnel_id", MatchFields.TUNNEL_ID);
public final static MatchField<OFBitMask128> BSN_IN_PORTS_128 =
new MatchField<OFBitMask128>("bsn_in_ports_128", MatchFields.BSN_IN_PORTS_128);
public final static MatchField<LagId> BSN_LAG_ID =
new MatchField<LagId>("bsn_lag_id", MatchFields.BSN_LAG_ID);
public final static MatchField<VRF> BSN_VRF =
new MatchField<VRF>("bsn_vrf", MatchFields.BSN_VRF);
public final static MatchField<OFBooleanValue> BSN_GLOBAL_VRF_ALLOWED =
new MatchField<OFBooleanValue>("bsn_global_vrf_allowed", MatchFields.BSN_GLOBAL_VRF_ALLOWED);
public final static MatchField<ClassId> BSN_L3_INTERFACE_CLASS_ID =
new MatchField<ClassId>("bsn_l3_interface_class_id", MatchFields.BSN_L3_INTERFACE_CLASS_ID);
public final static MatchField<ClassId> BSN_L3_SRC_CLASS_ID =
new MatchField<ClassId>("bsn_l3_src_class_id", MatchFields.BSN_L3_SRC_CLASS_ID);
public final static MatchField<ClassId> BSN_L3_DST_CLASS_ID =
new MatchField<ClassId>("bsn_l3_dst_class_id", MatchFields.BSN_L3_DST_CLASS_ID);
public final static MatchField<ClassId> BSN_EGR_PORT_GROUP_ID =
new MatchField<ClassId>("bsn_egr_port_group_id", MatchFields.BSN_EGR_PORT_GROUP_ID);
public final static MatchField<UDF> BSN_UDF0 =
new MatchField<UDF>("bsn_udf", MatchFields.BSN_UDF0);
public final static MatchField<UDF> BSN_UDF1 =
new MatchField<UDF>("bsn_udf", MatchFields.BSN_UDF1);
public final static MatchField<UDF> BSN_UDF2 =
new MatchField<UDF>("bsn_udf", MatchFields.BSN_UDF2);
public final static MatchField<UDF> BSN_UDF3 =
new MatchField<UDF>("bsn_udf", MatchFields.BSN_UDF3);
public final static MatchField<UDF> BSN_UDF4 =
new MatchField<UDF>("bsn_udf", MatchFields.BSN_UDF4);
public final static MatchField<UDF> BSN_UDF5 =
new MatchField<UDF>("bsn_udf", MatchFields.BSN_UDF5);
public final static MatchField<UDF> BSN_UDF6 =
new MatchField<UDF>("bsn_udf", MatchFields.BSN_UDF6);
public final static MatchField<UDF> BSN_UDF7 =
new MatchField<UDF>("bsn_udf", MatchFields.BSN_UDF7);
public final static MatchField<U16> BSN_TCP_FLAGS =
new MatchField<U16>("bsn_tcp_flags", MatchFields.BSN_TCP_FLAGS);
public String getName() {
return name;
}
public boolean arePrerequisitesOK(Match match) {
for (Prerequisite<?> p : this.prerequisites) {
if (!p.isSatisfied(match)) {
return false;
}
}
return true;
}
}
package org.projectfloodlight.openflow.protocol.match;
// MUST BE ORDERED BY THE ORDER OF OF SPEC!!!
public enum MatchFields {
IN_PORT,
IN_PHY_PORT,
METADATA,
ETH_DST,
ETH_SRC,
ETH_TYPE,
VLAN_VID,
VLAN_PCP,
IP_DSCP,
IP_ECN,
IP_PROTO,
IPV4_SRC,
IPV4_DST,
TCP_SRC,
TCP_DST,
UDP_SRC,
UDP_DST,
SCTP_SRC,
SCTP_DST,
ICMPV4_TYPE,
ICMPV4_CODE,
ARP_OP,
ARP_SPA,
ARP_TPA,
ARP_SHA,
ARP_THA,
IPV6_SRC,
IPV6_DST,
IPV6_FLABEL,
ICMPV6_TYPE,
ICMPV6_CODE,
IPV6_ND_TARGET,
IPV6_ND_SLL,
IPV6_ND_TLL,
MPLS_LABEL,
MPLS_TC,
TUNNEL_ID,
BSN_IN_PORTS_128,
BSN_LAG_ID,
BSN_VRF,
BSN_GLOBAL_VRF_ALLOWED,
BSN_L3_INTERFACE_CLASS_ID,
BSN_L3_SRC_CLASS_ID,
BSN_L3_DST_CLASS_ID,
BSN_EGR_PORT_GROUP_ID,
BSN_UDF0,
BSN_UDF1,
BSN_UDF2,
BSN_UDF3,
BSN_UDF4,
BSN_UDF5,
BSN_UDF6,
BSN_UDF7,
BSN_TCP_FLAGS,
}
package org.projectfloodlight.openflow.protocol.match;
import java.util.HashSet;
import java.util.Set;
import org.projectfloodlight.openflow.types.OFValueType;
public class Prerequisite<T extends OFValueType<T>> {
private final MatchField<T> field;
private final Set<OFValueType<T>> values;
private boolean any;
@SafeVarargs
public Prerequisite(MatchField<T> field, OFValueType<T>... values) {
this.values = new HashSet<OFValueType<T>>();
this.field = field;
if (values == null || values.length == 0) {
this.any = true;
} else {
this.any = false;
for (OFValueType<T> value : values) {
this.values.add(value);
}
}
}
/**
* Returns true if this prerequisite is satisfied by the given match object.
*
* @param match Match object
* @return true iff prerequisite is satisfied.
*/
public boolean isSatisfied(Match match) {
OFValueType<T> res = match.get(this.field);
if (res == null)
return false;
if (this.any)
return true;
if (this.values.contains(res)) {
return true;
}
return false;
}
}
package org.projectfloodlight.openflow.protocol.ver10;
import java.util.EnumSet;
import java.util.Set;
import org.jboss.netty.buffer.ChannelBuffer;
import org.projectfloodlight.openflow.exceptions.OFParseError;
import org.projectfloodlight.openflow.protocol.OFActionType;
import org.projectfloodlight.openflow.protocol.match.Match;
import com.google.common.hash.PrimitiveSink;
/**
* Collection of helper functions for reading and writing into ChannelBuffers
*
* @author capveg
*/
public class ChannelUtilsVer10 {
public static Match readOFMatch(final ChannelBuffer bb) throws OFParseError {
return OFMatchV1Ver10.READER.readFrom(bb);
}
public static Set<OFActionType> readSupportedActions(ChannelBuffer bb) {
int actions = bb.readInt();
EnumSet<OFActionType> supportedActions = EnumSet.noneOf(OFActionType.class);
if ((actions & (1 << OFActionTypeSerializerVer10.OUTPUT_VAL)) != 0)
supportedActions.add(OFActionType.OUTPUT);
if ((actions & (1 << OFActionTypeSerializerVer10.SET_VLAN_VID_VAL)) != 0)
supportedActions.add(OFActionType.SET_VLAN_VID);
if ((actions & (1 << OFActionTypeSerializerVer10.SET_VLAN_PCP_VAL)) != 0)
supportedActions.add(OFActionType.SET_VLAN_PCP);
if ((actions & (1 << OFActionTypeSerializerVer10.STRIP_VLAN_VAL)) != 0)
supportedActions.add(OFActionType.STRIP_VLAN);
if ((actions & (1 << OFActionTypeSerializerVer10.SET_DL_SRC_VAL)) != 0)
supportedActions.add(OFActionType.SET_DL_SRC);
if ((actions & (1 << OFActionTypeSerializerVer10.SET_DL_DST_VAL)) != 0)
supportedActions.add(OFActionType.SET_DL_DST);
if ((actions & (1 << OFActionTypeSerializerVer10.SET_NW_SRC_VAL)) != 0)
supportedActions.add(OFActionType.SET_NW_SRC);
if ((actions & (1 << OFActionTypeSerializerVer10.SET_NW_DST_VAL)) != 0)
supportedActions.add(OFActionType.SET_NW_DST);
if ((actions & (1 << OFActionTypeSerializerVer10.SET_NW_TOS_VAL)) != 0)
supportedActions.add(OFActionType.SET_NW_TOS);
if ((actions & (1 << OFActionTypeSerializerVer10.SET_TP_SRC_VAL)) != 0)
supportedActions.add(OFActionType.SET_TP_SRC);
if ((actions & (1 << OFActionTypeSerializerVer10.SET_TP_DST_VAL)) != 0)
supportedActions.add(OFActionType.SET_TP_DST);
if ((actions & (1 << OFActionTypeSerializerVer10.ENQUEUE_VAL)) != 0)
supportedActions.add(OFActionType.ENQUEUE);
return supportedActions;
}
public static int supportedActionsToWire(Set<OFActionType> supportedActions) {
int supportedActionsVal = 0;
if (supportedActions.contains(OFActionType.OUTPUT))
supportedActionsVal |= (1 << OFActionTypeSerializerVer10.OUTPUT_VAL);
if (supportedActions.contains(OFActionType.SET_VLAN_VID))
supportedActionsVal |= (1 << OFActionTypeSerializerVer10.SET_VLAN_VID_VAL);
if (supportedActions.contains(OFActionType.SET_VLAN_PCP))
supportedActionsVal |= (1 << OFActionTypeSerializerVer10.SET_VLAN_PCP_VAL);
if (supportedActions.contains(OFActionType.STRIP_VLAN))
supportedActionsVal |= (1 << OFActionTypeSerializerVer10.STRIP_VLAN_VAL);
if (supportedActions.contains(OFActionType.SET_DL_SRC))
supportedActionsVal |= (1 << OFActionTypeSerializerVer10.SET_DL_SRC_VAL);
if (supportedActions.contains(OFActionType.SET_DL_DST))
supportedActionsVal |= (1 << OFActionTypeSerializerVer10.SET_DL_DST_VAL);
if (supportedActions.contains(OFActionType.SET_NW_SRC))
supportedActionsVal |= (1 << OFActionTypeSerializerVer10.SET_NW_SRC_VAL);
if (supportedActions.contains(OFActionType.SET_NW_DST))
supportedActionsVal |= (1 << OFActionTypeSerializerVer10.SET_NW_DST_VAL);
if (supportedActions.contains(OFActionType.SET_NW_TOS))
supportedActionsVal |= (1 << OFActionTypeSerializerVer10.SET_NW_TOS_VAL);
if (supportedActions.contains(OFActionType.SET_TP_SRC))
supportedActionsVal |= (1 << OFActionTypeSerializerVer10.SET_TP_SRC_VAL);
if (supportedActions.contains(OFActionType.SET_TP_DST))
supportedActionsVal |= (1 << OFActionTypeSerializerVer10.SET_TP_DST_VAL);
if (supportedActions.contains(OFActionType.ENQUEUE))
supportedActionsVal |= (1 << OFActionTypeSerializerVer10.ENQUEUE_VAL);
return supportedActionsVal;
}
public static void putSupportedActionsTo(Set<OFActionType> supportedActions, PrimitiveSink sink) {
sink.putInt(supportedActionsToWire(supportedActions));
}
public static void writeSupportedActions(ChannelBuffer bb, Set<OFActionType> supportedActions) {
bb.writeInt(supportedActionsToWire(supportedActions));
}
}
package org.projectfloodlight.openflow.protocol.ver11;
import org.jboss.netty.buffer.ChannelBuffer;
import org.projectfloodlight.openflow.exceptions.OFParseError;
import org.projectfloodlight.openflow.protocol.OFMatchBmap;
import org.projectfloodlight.openflow.protocol.match.Match;
/**
* Collection of helper functions for reading and writing into ChannelBuffers
*
* @author capveg
*/
public class ChannelUtilsVer11 {
public static Match readOFMatch(final ChannelBuffer bb) throws OFParseError {
return OFMatchV2Ver11.READER.readFrom(bb);
}
public static OFMatchBmap readOFMatchBmap(ChannelBuffer bb) {
throw new UnsupportedOperationException("not implemented");
}
public static void writeOFMatchBmap(ChannelBuffer bb, OFMatchBmap match) {
throw new UnsupportedOperationException("not implemented");
}
}
package org.projectfloodlight.openflow.protocol.ver12;
import org.jboss.netty.buffer.ChannelBuffer;
import org.projectfloodlight.openflow.exceptions.OFParseError;
import org.projectfloodlight.openflow.protocol.OFMatchBmap;
import org.projectfloodlight.openflow.protocol.match.Match;
import org.projectfloodlight.openflow.protocol.ver12.OFMatchV3Ver12;
import org.projectfloodlight.openflow.protocol.OFBsnVportQInQ;
/**
* Collection of helper functions for reading and writing into ChannelBuffers
*
* @author capveg
*/
public class ChannelUtilsVer12 {
public static Match readOFMatch(final ChannelBuffer bb) throws OFParseError {
return OFMatchV3Ver12.READER.readFrom(bb);
}
// TODO these need to be figured out / removed
public static OFBsnVportQInQ readOFBsnVportQInQ(ChannelBuffer bb) {
throw new UnsupportedOperationException("not implemented");
}
public static void writeOFBsnVportQInQ(ChannelBuffer bb,
OFBsnVportQInQ vport) {
throw new UnsupportedOperationException("not implemented");
}
public static OFMatchBmap readOFMatchBmap(ChannelBuffer bb) {
throw new UnsupportedOperationException("not implemented");
}
public static void writeOFMatchBmap(ChannelBuffer bb, OFMatchBmap match) {
throw new UnsupportedOperationException("not implemented");
}
}
package org.projectfloodlight.openflow.protocol.ver13;
import org.jboss.netty.buffer.ChannelBuffer;
import org.projectfloodlight.openflow.exceptions.OFParseError;
import org.projectfloodlight.openflow.protocol.OFMatchBmap;
import org.projectfloodlight.openflow.protocol.match.Match;
/**
* Collection of helper functions for reading and writing into ChannelBuffers
*
* @author capveg
*/
public class ChannelUtilsVer13 {
public static Match readOFMatch(final ChannelBuffer bb) throws OFParseError {
return OFMatchV3Ver13.READER.readFrom(bb);
}
public static OFMatchBmap readOFMatchBmap(ChannelBuffer bb) {
throw new UnsupportedOperationException("not implemented");
}
public static void writeOFMatchBmap(ChannelBuffer bb, OFMatchBmap match) {
throw new UnsupportedOperationException("not implemented");
}
}
package org.projectfloodlight.openflow.types;
import org.jboss.netty.buffer.ChannelBuffer;
import com.google.common.hash.PrimitiveSink;
import com.google.common.primitives.UnsignedInts;
public class ArpOpcode implements OFValueType<ArpOpcode> {
final static int LENGTH = 2;
private static final int VAL_REQUEST = 1;
private static final int VAL_REPLY = 2;
private static final int VAL_REQUEST_REVERSE = 3;
private static final int VAL_REPLY_REVERSE = 4;
private static final int VAL_DRARP_REQUEST = 5;
private static final int VAL_DRARP_REPLY = 6;
private static final int VAL_DRARP_ERROR = 7;
private static final int VAL_INARP_REQUEST = 8;
private static final int VAL_INARP_REPLY = 9;
private static final int VAL_ARP_NAK = 10;
private static final int VAL_MARS_REQUEST = 11;
private static final int VAL_MARS_MULTI = 12;
private static final int VAL_MARS_MSERV = 13;
private static final int VAL_MARS_JOIN = 14;
private static final int VAL_MARS_LEAVE = 15;
private static final int VAL_MARS_NAK = 16;
private static final int VAL_MARS_UNSERV = 17;
private static final int VAL_MARS_SJOIN = 18;
private static final int VAL_MARS_SLEAVE = 19;
private static final int VAL_MARS_GROUPLIST_REQUEST = 20;
private static final int VAL_MARS_GROUPLIST_REPLY = 21;
private static final int VAL_MARS_REDIRECT_MAP = 22;
private static final int VAL_MAPOS_UNARP = 23;
private static final int VAL_OP_EXP1 = 24;
private static final int VAL_OP_EXP2 = 25;
public static final ArpOpcode REQUEST = new ArpOpcode(VAL_REQUEST);
public static final ArpOpcode REPLY = new ArpOpcode(VAL_REPLY);
public static final ArpOpcode REQUEST_REVERSE = new ArpOpcode(VAL_REQUEST_REVERSE);
public static final ArpOpcode REPLY_REVERSE = new ArpOpcode(VAL_REPLY_REVERSE);
public static final ArpOpcode DRARP_REQUEST = new ArpOpcode(VAL_DRARP_REQUEST);
public static final ArpOpcode DRARP_REPLY = new ArpOpcode(VAL_DRARP_REPLY);
public static final ArpOpcode DRARP_ERROR = new ArpOpcode(VAL_DRARP_ERROR);
public static final ArpOpcode INARP_REQUEST = new ArpOpcode(VAL_INARP_REQUEST);
public static final ArpOpcode INARP_REPLY = new ArpOpcode(VAL_INARP_REPLY);
public static final ArpOpcode ARP_NAK = new ArpOpcode(VAL_ARP_NAK);
public static final ArpOpcode MARS_REQUEST = new ArpOpcode(VAL_MARS_REQUEST);
public static final ArpOpcode MARS_MULTI = new ArpOpcode(VAL_MARS_MULTI);
public static final ArpOpcode MARS_MSERV = new ArpOpcode(VAL_MARS_MSERV);
public static final ArpOpcode MARS_JOIN = new ArpOpcode(VAL_MARS_JOIN);
public static final ArpOpcode MARS_LEAVE = new ArpOpcode(VAL_MARS_LEAVE);
public static final ArpOpcode MARS_NAK = new ArpOpcode(VAL_MARS_NAK);
public static final ArpOpcode MARS_UNSERV = new ArpOpcode(VAL_MARS_UNSERV);
public static final ArpOpcode MARS_SJOIN = new ArpOpcode(VAL_MARS_SJOIN);
public static final ArpOpcode MARS_SLEAVE = new ArpOpcode(VAL_MARS_SLEAVE);
public static final ArpOpcode MARS_GROUPLIST_REQUEST = new ArpOpcode(VAL_MARS_GROUPLIST_REQUEST);
public static final ArpOpcode MARS_GROUPLIST_REPLY = new ArpOpcode(VAL_MARS_GROUPLIST_REPLY);
public static final ArpOpcode MARS_REDIRECT_MAP = new ArpOpcode(VAL_MARS_REDIRECT_MAP);
public static final ArpOpcode MAPOS_UNARP = new ArpOpcode(VAL_MAPOS_UNARP);
public static final ArpOpcode OP_EXP1 = new ArpOpcode(VAL_OP_EXP1);
public static final ArpOpcode OP_EXP2 = new ArpOpcode(VAL_OP_EXP2);
private static final int MIN_OPCODE = 0;
private static final int MAX_OPCODE = 0xFFFF;
private static final int NONE_VAL = 0;
public static final ArpOpcode NONE = new ArpOpcode(NONE_VAL);
public static final ArpOpcode NO_MASK = new ArpOpcode(0xFFFFFFFF);
public static final ArpOpcode FULL_MASK = new ArpOpcode(0x00000000);
private final int opcode;
private ArpOpcode(int opcode) {
this.opcode = opcode;
}
@Override
public int getLength() {
return LENGTH;
}
public int getOpcode() {
return this.opcode;
}
public static ArpOpcode of(int opcode) {
if (opcode < MIN_OPCODE || opcode > MAX_OPCODE)
throw new IllegalArgumentException("Invalid ARP opcode: " + opcode);
switch (opcode) {
case NONE_VAL:
return NONE;
case VAL_REQUEST:
return REQUEST;
case VAL_REPLY:
return REPLY;
case VAL_REQUEST_REVERSE:
return REQUEST_REVERSE;
case VAL_REPLY_REVERSE:
return REPLY_REVERSE;
case VAL_DRARP_REQUEST:
return DRARP_REQUEST;
case VAL_DRARP_REPLY:
return DRARP_REPLY;
case VAL_DRARP_ERROR:
return DRARP_ERROR;
case VAL_INARP_REQUEST:
return INARP_REQUEST;
case VAL_INARP_REPLY:
return INARP_REPLY;
case VAL_ARP_NAK:
return ARP_NAK;
case VAL_MARS_REQUEST:
return MARS_REQUEST;
case VAL_MARS_MULTI:
return MARS_MULTI;
case VAL_MARS_MSERV:
return MARS_MSERV;
case VAL_MARS_JOIN:
return MARS_JOIN;
case VAL_MARS_LEAVE:
return MARS_LEAVE;
case VAL_MARS_NAK:
return MARS_NAK;
case VAL_MARS_UNSERV:
return MARS_UNSERV;
case VAL_MARS_SJOIN:
return MARS_SJOIN;
case VAL_MARS_SLEAVE:
return MARS_SLEAVE;
case VAL_MARS_GROUPLIST_REQUEST:
return MARS_GROUPLIST_REQUEST;
case VAL_MARS_GROUPLIST_REPLY:
return MARS_GROUPLIST_REPLY;
case VAL_MARS_REDIRECT_MAP:
return MARS_REDIRECT_MAP;
case VAL_MAPOS_UNARP:
return MAPOS_UNARP;
case VAL_OP_EXP1:
return OP_EXP1;
case VAL_OP_EXP2:
return OP_EXP2;
default:
return new ArpOpcode(opcode);
}
}
public void write2Bytes(ChannelBuffer c) {
c.writeShort(this.opcode);
}
public static ArpOpcode read2Bytes(ChannelBuffer c) {
return ArpOpcode.of(c.readUnsignedShort());
}
@Override
public ArpOpcode applyMask(ArpOpcode mask) {
return ArpOpcode.of(this.opcode & mask.opcode);
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + opcode;
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
ArpOpcode other = (ArpOpcode) obj;
if (opcode != other.opcode)
return false;
return true;
}
@Override
public int compareTo(ArpOpcode o) {
return UnsignedInts.compare(opcode, o.opcode);
}
@Override
public void putTo(PrimitiveSink sink) {
sink.putShort((short) this.opcode);
}
@Override
public String toString() {
return String.valueOf(this.opcode);
}
}
package org.projectfloodlight.openflow.types;
import javax.annotation.concurrent.Immutable;
import org.jboss.netty.buffer.ChannelBuffer;
import com.google.common.hash.PrimitiveSink;
import com.google.common.primitives.UnsignedInts;
@Immutable
public class ClassId implements OFValueType<ClassId> {
static final int LENGTH = 4;
private final static int NONE_VAL = 0;
public final static ClassId NONE = new ClassId(NONE_VAL);
private final static int NO_MASK_VAL = 0xFFFFFFFF;
public final static ClassId NO_MASK = new ClassId(NO_MASK_VAL);
public final static ClassId FULL_MASK = NONE;
private final int rawValue;
private ClassId(final int rawValue) {
this.rawValue = rawValue;
}
public static ClassId of(final int raw) {
if(raw == NONE_VAL)
return NONE;
else if(raw == NO_MASK_VAL)
return NO_MASK;
return new ClassId(raw);
}
public int getInt() {
return rawValue;
}
@Override
public int getLength() {
return LENGTH;
}
@Override
public String toString() {
return Integer.toString(rawValue);
}
@Override
public ClassId applyMask(ClassId mask) {
return ClassId.of(rawValue & mask.rawValue); }
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + rawValue;
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
ClassId other = (ClassId) obj;
if (rawValue != other.rawValue)
return false;
return true;
}
public void write4Bytes(ChannelBuffer c) {
c.writeInt(rawValue);
}
public static ClassId read4Bytes(ChannelBuffer c) {
return ClassId.of(c.readInt());
}
@Override
public int compareTo(ClassId o) {
return UnsignedInts.compare(rawValue, rawValue);
}
@Override
public void putTo(PrimitiveSink sink) {
sink.putInt(rawValue);
}
}
package org.projectfloodlight.openflow.types;
import org.projectfloodlight.openflow.annotations.Immutable;
import org.projectfloodlight.openflow.util.HexString;
import com.google.common.hash.PrimitiveSink;
import com.google.common.primitives.Longs;
import com.google.common.primitives.UnsignedLongs;
/**
* Abstraction of a datapath ID that can be set and/or accessed as either a
* long value or a colon-separated string. Immutable
*
* @author Rob Vaterlaus <rob.vaterlaus@bigswitch.com>
*/
@Immutable
public class DatapathId implements PrimitiveSinkable, Comparable<DatapathId> {
public static final DatapathId NONE = new DatapathId(0);
private final long rawValue;
private DatapathId(long rawValue) {
this.rawValue = rawValue;
}
public static DatapathId of(long rawValue) {
return new DatapathId(rawValue);
}
public static DatapathId of(String s) {
return new DatapathId(HexString.toLong(s));
}
public static DatapathId of(byte[] bytes) {
return new DatapathId(Longs.fromByteArray(bytes));
}
public long getLong() {
return rawValue;
}
public U64 getUnsignedLong() {
return U64.of(rawValue);
}
public byte[] getBytes() {
return Longs.toByteArray(rawValue);
}
@Override
public String toString() {
return HexString.toHexString(rawValue);
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + (int) (rawValue ^ (rawValue >>> 32));
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
DatapathId other = (DatapathId) obj;
if (rawValue != other.rawValue)
return false;
return true;
}
@Override
public void putTo(PrimitiveSink sink) {
sink.putLong(rawValue);
}
@Override
public int compareTo(DatapathId o) {
return UnsignedLongs.compare(rawValue, o.rawValue);
}
}
package org.projectfloodlight.openflow.types;
import org.jboss.netty.buffer.ChannelBuffer;
import com.google.common.hash.PrimitiveSink;
import com.google.common.primitives.UnsignedInts;
/**
* EtherType field representation.
*
* @author Yotam Harchol (yotam.harchol@bigswitch.com)
*/
public class EthType implements OFValueType<EthType> {
static final int LENGTH = 2;
private final int rawValue;
static final int VAL_IPv4 = 0x0800; // Internet Protocol version 4 (IPv4)
static final int VAL_ARP = 0x0806; // Address Resolution Protocol (ARP)
static final int VAL_WAKE_ON_LAN = 0x0842; // Wake-on-LAN[3]
static final int VAL_TRILL = 0x22F3; // IETF TRILL Protocol
static final int VAL_DECNET_IV = 0x6003; // DECnet Phase IV
static final int VAL_REV_ARP = 0x8035; // Reverse Address Resolution Protocol
static final int VAL_APPLE_TALK = 0x809B; // AppleTalk (Ethertalk)
static final int VAL_APPLE_TALK_ARP = 0x80F3; // AppleTalk Address Resolution Protocol (AARP)
static final int VAL_VLAN_FRAME = 0x8100; // VLAN-tagged frame (IEEE 802.1Q) & Shortest Path Bridging IEEE 802.1aq[4]
static final int VAL_IPX_8137 = 0x8137; // IPX
static final int VAL_IPX_8138 = 0x8138; // IPX
static final int VAL_QNX = 0x8204; // QNX Qnet
static final int VAL_IPv6 = 0x86DD; // Internet Protocol Version 6 (IPv6)
static final int VAL_ETH_FLOW = 0x8808; // Ethernet flow control
static final int VAL_SLOW_PROTOCOLS = 0x8809; // Slow Protocols (IEEE 802.3)
static final int VAL_COBRANET = 0x8819; // CobraNet
static final int VAL_MPLS_UNICAST = 0x8847; // MPLS unicast
static final int VAL_MPLS_MULTICAST = 0x8848; // MPLS multicast
static final int VAL_PPPoE_DISCOVERY = 0x8863; // PPPoE Discovery Stage
static final int VAL_PPPoE_SESSION = 0x8864; // PPPoE Session Stage
static final int VAL_JUMBO_FRAMES = 0x8870; // Jumbo Frames
static final int VAL_HOMEPLUG_10 = 0x887B; // HomePlug 1.0 MME
static final int VAL_EAP_OVER_LAN = 0x888E; // EAP over LAN (IEEE 802.1X)
static final int VAL_PROFINET = 0x8892; // PROFINET Protocol
static final int VAL_HYPERSCSI = 0x889A; // HyperSCSI (SCSI over Ethernet)
static final int VAL_ATA_OVER_ETH = 0x88A2; // ATA over Ethernet
static final int VAL_ETHERCAT = 0x88A4; // EtherCAT Protocol
static final int VAL_BRIDGING = 0x88A8; // Provider Bridging (IEEE 802.1ad) & Shortest Path Bridging IEEE 802.1aq[5]
static final int VAL_POWERLINK = 0x88AB; // Ethernet Powerlink[citation needed]
static final int VAL_LLDP = 0x88CC; // Link Layer Discovery Protocol (LLDP)
static final int VAL_SERCOS = 0x88CD; // SERCOS III
static final int VAL_HOMEPLUG_AV = 0x88E1; // HomePlug AV MME[citation needed]
static final int VAL_MRP = 0x88E3; // Media Redundancy Protocol (IEC62439-2)
static final int VAL_MAC_SEC = 0x88E5; // MAC security (IEEE 802.1AE)
static final int VAL_PTP = 0x88F7; // Precision Time Protocol (IEEE 1588)
static final int VAL_CFM = 0x8902; // IEEE 802.1ag Connectivity Fault Management (CFM) Protocol / ITU-T Recommendation Y.1731 (OAM)
static final int VAL_FCoE = 0x8906; // Fibre Channel over Ethernet (FCoE)
static final int VAL_FCoE_INIT = 0x8914; // FCoE Initialization Protocol
static final int VAL_RoCE = 0x8915; // RDMA over Converged Ethernet (RoCE)
static final int VAL_HSR = 0x892F; // High-availability Seamless Redundancy (HSR)
static final int VAL_CONF_TEST = 0x9000; // Ethernet Configuration Testing Protocol[6]
static final int VAL_Q_IN_Q = 0x9100; // Q-in-Q
static final int VAL_LLT = 0xCAFE; // Veritas Low Latency Transport (LLT)[7] for Veritas Cluster Server
public static final EthType IPv4 = new EthType(VAL_IPv4);
public static final EthType ARP = new EthType(VAL_ARP);
public static final EthType WAKE_ON_LAN = new EthType(VAL_WAKE_ON_LAN);
public static final EthType TRILL = new EthType(VAL_TRILL);
public static final EthType DECNET_IV = new EthType(VAL_DECNET_IV);
public static final EthType REV_ARP = new EthType(VAL_REV_ARP );
public static final EthType APPLE_TALK = new EthType(VAL_APPLE_TALK);
public static final EthType APPLE_TALK_ARP = new EthType(VAL_APPLE_TALK_ARP);
public static final EthType VLAN_FRAME = new EthType(VAL_VLAN_FRAME );
public static final EthType IPX_8137 = new EthType(VAL_IPX_8137 );
public static final EthType IPX_8138 = new EthType(VAL_IPX_8138 );
public static final EthType QNX = new EthType(VAL_QNX );
public static final EthType IPv6 = new EthType(VAL_IPv6 );
public static final EthType ETH_FLOW = new EthType(VAL_ETH_FLOW);
public static final EthType SLOW_PROTOCOLS = new EthType(VAL_SLOW_PROTOCOLS );
public static final EthType COBRANET = new EthType(VAL_COBRANET );
public static final EthType MPLS_UNICAST = new EthType(VAL_MPLS_UNICAST );
public static final EthType MPLS_MULTICAST = new EthType(VAL_MPLS_MULTICAST );
public static final EthType PPPoE_DISCOVERY = new EthType(VAL_PPPoE_DISCOVERY);
public static final EthType PPPoE_SESSION = new EthType(VAL_PPPoE_SESSION );
public static final EthType JUMBO_FRAMES = new EthType(VAL_JUMBO_FRAMES );
public static final EthType HOMEPLUG_10 = new EthType(VAL_HOMEPLUG_10 );
public static final EthType EAP_OVER_LAN = new EthType(VAL_EAP_OVER_LAN );
public static final EthType PROFINET = new EthType(VAL_PROFINET );
public static final EthType HYPERSCSI = new EthType(VAL_HYPERSCSI );
public static final EthType ATA_OVER_ETH = new EthType(VAL_ATA_OVER_ETH);
public static final EthType ETHERCAT = new EthType(VAL_ETHERCAT );
public static final EthType BRIDGING = new EthType(VAL_BRIDGING );
public static final EthType POWERLINK = new EthType(VAL_POWERLINK );
public static final EthType LLDP = new EthType(VAL_LLDP );
public static final EthType SERCOS = new EthType(VAL_SERCOS );
public static final EthType HOMEPLUG_AV = new EthType(VAL_HOMEPLUG_AV );
public static final EthType MRP = new EthType(VAL_MRP );
public static final EthType MAC_SEC = new EthType(VAL_MAC_SEC);
public static final EthType PTP = new EthType(VAL_PTP );
public static final EthType CFM = new EthType(VAL_CFM );
public static final EthType FCoE = new EthType(VAL_FCoE );
public static final EthType FCoE_INIT = new EthType(VAL_FCoE_INIT );
public static final EthType RoCE = new EthType(VAL_RoCE );
public static final EthType HSR = new EthType(VAL_HSR );
public static final EthType CONF_TEST = new EthType(VAL_CONF_TEST );
public static final EthType Q_IN_Q = new EthType(VAL_Q_IN_Q );
public static final EthType LLT = new EthType(VAL_LLT );
private static final int NONE_VAL = 0x0;
public static final EthType NONE = new EthType(NONE_VAL);
public static final EthType NO_MASK = new EthType(0xFFFFFFFF);
public static final EthType FULL_MASK = new EthType(0x00000000);
private EthType(int type) {
this.rawValue = type;
}
@Override
public int getLength() {
return LENGTH;
}
public static EthType of(int type) {
switch (type) {
case NONE_VAL:
return NONE;
case VAL_IPv4:
return IPv4;
case VAL_ARP:
return ARP;
case VAL_WAKE_ON_LAN:
return WAKE_ON_LAN;
case VAL_TRILL:
return TRILL;
case VAL_DECNET_IV:
return DECNET_IV;
case VAL_REV_ARP:
return REV_ARP;
case VAL_APPLE_TALK:
return APPLE_TALK;
case VAL_APPLE_TALK_ARP:
return APPLE_TALK_ARP;
case VAL_VLAN_FRAME:
return VLAN_FRAME;
case VAL_IPX_8137:
return IPX_8137;
case VAL_IPX_8138:
return IPX_8138;
case VAL_QNX:
return QNX;
case VAL_IPv6:
return IPv6;
case VAL_ETH_FLOW:
return ETH_FLOW;
case VAL_SLOW_PROTOCOLS:
return SLOW_PROTOCOLS;
case VAL_COBRANET:
return COBRANET;
case VAL_MPLS_UNICAST:
return MPLS_UNICAST;
case VAL_MPLS_MULTICAST:
return MPLS_MULTICAST;
case VAL_PPPoE_DISCOVERY:
return PPPoE_DISCOVERY;
case VAL_PPPoE_SESSION:
return PPPoE_SESSION;
case VAL_JUMBO_FRAMES:
return JUMBO_FRAMES;
case VAL_HOMEPLUG_10:
return HOMEPLUG_10;
case VAL_EAP_OVER_LAN:
return EAP_OVER_LAN;
case VAL_PROFINET:
return PROFINET;
case VAL_HYPERSCSI:
return HYPERSCSI;
case VAL_ATA_OVER_ETH:
return ATA_OVER_ETH;
case VAL_ETHERCAT:
return ETHERCAT;
case VAL_BRIDGING:
return BRIDGING;
case VAL_POWERLINK:
return POWERLINK;
case VAL_LLDP:
return LLDP;
case VAL_SERCOS:
return SERCOS;
case VAL_HOMEPLUG_AV:
return HOMEPLUG_AV;
case VAL_MRP:
return MRP;
case VAL_MAC_SEC:
return MAC_SEC;
case VAL_PTP:
return PTP;
case VAL_CFM:
return CFM;
case VAL_FCoE:
return FCoE;
case VAL_FCoE_INIT:
return FCoE_INIT;
case VAL_RoCE:
return RoCE;
case VAL_HSR:
return HSR;
case VAL_CONF_TEST:
return CONF_TEST;
case VAL_Q_IN_Q:
return Q_IN_Q;
case VAL_LLT:
return LLT;
default:
// TODO: What's here?
return new EthType(type);
}
}
@Override
public String toString() {
return Integer.toHexString(rawValue);
}
public void write2Bytes(ChannelBuffer c) {
c.writeShort(this.rawValue);
}
public static EthType read2Bytes(ChannelBuffer c) {
return EthType.of(c.readUnsignedShort());
}
@Override
public EthType applyMask(EthType mask) {
return EthType.of(this.rawValue & mask.rawValue);
}
public int getValue() {
return rawValue;
}
@Override
public boolean equals(Object obj) {
if (!(obj instanceof EthType))
return false;
EthType o = (EthType)obj;
if (o.rawValue != this.rawValue)
return false;
return true;
}
@Override
public int hashCode() {
final int prime = 37;
int result = 1;
result = prime * result + rawValue;
return result;
}
@Override
public int compareTo(EthType o) {
return UnsignedInts.compare(rawValue, o.rawValue);
}
@Override
public void putTo(PrimitiveSink sink) {
sink.putInt(rawValue);
}
}
package org.projectfloodlight.openflow.types;
import org.jboss.netty.buffer.ChannelBuffer;
import org.projectfloodlight.openflow.exceptions.OFParseError;
import com.google.common.hash.PrimitiveSink;
import com.google.common.primitives.UnsignedInts;
public class GenTableId implements OFValueType<GenTableId>, Comparable<GenTableId> {
final static int LENGTH = 2;
private static final int VALIDATION_MASK = 0xFFFF;
private static final int ALL_VAL = 0xFFFF;
private static final int NONE_VAL = 0x0000;
public static final GenTableId NONE = new GenTableId(NONE_VAL);
public static final GenTableId ALL = new GenTableId(ALL_VAL);
public static final GenTableId ZERO = NONE;
private final int id;
private GenTableId(int id) {
this.id = id;
}
public static GenTableId of(int id) {
switch(id) {
case NONE_VAL:
return NONE;
case ALL_VAL:
return ALL;
default:
if ((id & VALIDATION_MASK) != id)
throw new IllegalArgumentException("Illegal Table id value: " + id);
return new GenTableId(id);
}
}
@Override
public String toString() {
return "0x" + Integer.toHexString(id);
}
public int getValue() {
return id;
}
@Override
public int getLength() {
return LENGTH;
}
public void write2Bytes(ChannelBuffer c) {
c.writeShort(this.id);
}
public static GenTableId read2Bytes(ChannelBuffer c) throws OFParseError {
return GenTableId.of(c.readUnsignedShort());
}
@Override
public GenTableId applyMask(GenTableId mask) {
return GenTableId.of(this.id & mask.id);
}
@Override
public boolean equals(Object obj) {
if (!(obj instanceof GenTableId))
return false;
GenTableId other = (GenTableId)obj;
if (other.id != this.id)
return false;
return true;
}
@Override
public int hashCode() {
int prime = 13873;
return this.id * prime;
}
@Override
public int compareTo(GenTableId other) {
return UnsignedInts.compare(this.id, other.id);
}
@Override
public void putTo(PrimitiveSink sink) {
sink.putShort((byte) id);
}
}
package org.projectfloodlight.openflow.types;
import javax.annotation.concurrent.Immutable;
/** a hash value that supports bit-wise combinations, mainly to calculate hash values for
* reconciliation operations.
*
* @author Andreas Wundsam <andreas.wundsam@bigswitch.com>
*
* @param <H> - this type, for return type safety.
*/
@Immutable
public interface HashValue<H extends HashValue<H>> {
/** return the "numBits" highest-order bits of the hash.
* @param numBits number of higest-order bits to return [0-32].
* @return a numberic value of the 0-32 highest-order bits.
*/
int prefixBits(int numBits);
/** @return the bitwise inverse of this value */
H inverse();
/** or this value with another value value of the same type */
H or(H other);
/** and this value with another value value of the same type */
H and(H other);
/** xor this value with another value value of the same type */
H xor(H other);
/** calculate a combined hash value of this hash value (the <b>Key</b>) and the hash value
* specified as a parameter (the <b>Value</b>).
* <p>
* The value is constructed as follows:
* <ul>
* <li>the first keyBits bits are taken only from the Key
* <li>the other bits are taken from key xor value.
* </ul>
* The overall result looks like this:
* <pre>
* MSB LSB
* +---------+--------------+
* | key | key ^ value |
* +---------+--------------+
* |-keyBits-|
* </pre>
*
* @param value - hash value to be compared with this value (the key)
* @param keyBits number of prefix bits that are just taken from key
* @return the combined value.
*/
H combineWithValue(H value, int keyBits);
}
\ No newline at end of file
package org.projectfloodlight.openflow.types;
import com.google.common.base.Preconditions;
public class HashValueUtils {
private HashValueUtils() { }
public static long combineWithValue(long key, long value, int keyBits) {
Preconditions.checkArgument(keyBits >= 0 && keyBits <= 64, "keyBits must be [0,64]");
int valueBits = 64 - keyBits;
long valueMask = valueBits == 64 ? 0xFFFFFFFFFFFFFFFFL : (1L << valueBits) - 1;
return key ^ (value & valueMask);
}
public static int prefixBits(long raw1, int numBits) {
Preconditions.checkArgument(numBits >= 0 && numBits <= 32,
"numBits must be in range [0, 32]");
if(numBits == 0)
return 0;
final int shiftDown = 64 - numBits;
return (int) (raw1 >>> shiftDown);
}
}
package org.projectfloodlight.openflow.types;
import org.jboss.netty.buffer.ChannelBuffer;
import com.google.common.hash.PrimitiveSink;
import com.google.common.primitives.Shorts;
/**
*
* @author Yotam Harchol (yotam.harchol@bigswitch.com)
*
*/
public class ICMPv4Code implements OFValueType<ICMPv4Code> {
final static int LENGTH = 1;
final static short MAX_CODE = 0xFF;
private final short code;
private static final short NONE_VAL = 0;
public static final ICMPv4Code NONE = new ICMPv4Code(NONE_VAL);
public static final ICMPv4Code NO_MASK = new ICMPv4Code((short)0xFFFF);
public static final ICMPv4Code FULL_MASK = new ICMPv4Code((short)0x0000);
private ICMPv4Code(short code) {
this.code = code;
}
public static ICMPv4Code of(short code) {
if(code == NONE_VAL)
return NONE;
if (code > MAX_CODE || code < 0)
throw new IllegalArgumentException("Illegal ICMPv4 code: " + code);
return new ICMPv4Code(code);
}
@Override
public int getLength() {
return LENGTH;
}
public short getCode() {
return code;
}
public void writeByte(ChannelBuffer c) {
c.writeByte(this.code);
}
public static ICMPv4Code readByte(ChannelBuffer c) {
return ICMPv4Code.of(c.readUnsignedByte());
}
@Override
public ICMPv4Code applyMask(ICMPv4Code mask) {
return ICMPv4Code.of((short)(this.code & mask.code));
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + code;
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
ICMPv4Code other = (ICMPv4Code) obj;
if (code != other.code)
return false;
return true;
}
@Override
public int compareTo(ICMPv4Code o) {
return Shorts.compare(code, o.code);
}
@Override
public void putTo(PrimitiveSink sink) {
sink.putShort(code);
}
@Override
public String toString() {
return String.valueOf(this.code);
}
}
package org.projectfloodlight.openflow.types;
import org.jboss.netty.buffer.ChannelBuffer;
import com.google.common.hash.PrimitiveSink;
import com.google.common.primitives.Shorts;
public class ICMPv4Type implements OFValueType<ICMPv4Type> {
final static int LENGTH = 1;
private static final short VAL_ECHO_REPLY = 0;
private static final short VAL_DESTINATION_UNREACHABLE = 3;
private static final short VAL_SOURCE_QUENCH = 4;
private static final short VAL_REDIRECT = 5;
private static final short VAL_ALTERNATE_HOST_ADDRESS = 6;
private static final short VAL_ECHO = 8;
private static final short VAL_ROUTER_ADVERTISEMENT = 9;
private static final short VAL_ROUTER_SOLICITATION = 10;
private static final short VAL_TIME_EXCEEDED = 11;
private static final short VAL_PARAMETER_PROBLEM = 12;
private static final short VAL_TIMESTAMP = 13;
private static final short VAL_TIMESTAMP_REPLY = 14;
private static final short VAL_INFORMATION_REQUEST = 15;
private static final short VAL_INFORMATION_REPLY = 16;
private static final short VAL_ADDRESS_MASK_REQUEST = 17;
private static final short VAL_ADDRESS_MASK_REPLY = 18;
private static final short VAL_TRACEROUTE = 30;
private static final short VAL_DATAGRAM_CONVERSION_ERROR = 31;
private static final short VAL_MOBILE_HOST_REDIRECT = 32;
private static final short VAL_IPV6_WHERE_ARE_YOU = 33;
private static final short VAL_IPV6_I_AM_HERE = 34;
private static final short VAL_MOBILE_REGISTRATION_REQUEST = 35;
private static final short VAL_MOBILE_REGISTRATION_REPLY = 36;
private static final short VAL_DOMAIN_NAME_REQUEST = 37;
private static final short VAL_DOMAIN_NAME_REPLY = 38;
private static final short VAL_SKIP = 39;
private static final short VAL_PHOTURIS = 40;
private static final short VAL_EXPERIMENTAL_MOBILITY = 41;
public static final ICMPv4Type ECHO_REPLY = new ICMPv4Type(VAL_ECHO_REPLY);
public static final ICMPv4Type DESTINATION_UNREACHABLE = new ICMPv4Type(VAL_DESTINATION_UNREACHABLE);
public static final ICMPv4Type SOURCE_QUENCH = new ICMPv4Type(VAL_SOURCE_QUENCH);
public static final ICMPv4Type REDIRECT = new ICMPv4Type(VAL_REDIRECT);
public static final ICMPv4Type ALTERNATE_HOST_ADDRESS = new ICMPv4Type(VAL_ALTERNATE_HOST_ADDRESS);
public static final ICMPv4Type ECHO = new ICMPv4Type(VAL_ECHO);
public static final ICMPv4Type ROUTER_ADVERTISEMENT = new ICMPv4Type(VAL_ROUTER_ADVERTISEMENT);
public static final ICMPv4Type ROUTER_SOLICITATION = new ICMPv4Type(VAL_ROUTER_SOLICITATION);
public static final ICMPv4Type TIME_EXCEEDED = new ICMPv4Type(VAL_TIME_EXCEEDED);
public static final ICMPv4Type PARAMETER_PROBLEM = new ICMPv4Type(VAL_PARAMETER_PROBLEM);
public static final ICMPv4Type TIMESTAMP = new ICMPv4Type(VAL_TIMESTAMP);
public static final ICMPv4Type TIMESTAMP_REPLY = new ICMPv4Type(VAL_TIMESTAMP_REPLY);
public static final ICMPv4Type INFORMATION_REQUEST = new ICMPv4Type(VAL_INFORMATION_REQUEST);
public static final ICMPv4Type INFORMATION_REPLY = new ICMPv4Type(VAL_INFORMATION_REPLY);
public static final ICMPv4Type ADDRESS_MASK_REQUEST = new ICMPv4Type(VAL_ADDRESS_MASK_REQUEST);
public static final ICMPv4Type ADDRESS_MASK_REPLY = new ICMPv4Type(VAL_ADDRESS_MASK_REPLY);
public static final ICMPv4Type TRACEROUTE = new ICMPv4Type(VAL_TRACEROUTE);
public static final ICMPv4Type DATAGRAM_CONVERSION_ERROR = new ICMPv4Type(VAL_DATAGRAM_CONVERSION_ERROR);
public static final ICMPv4Type MOBILE_HOST_REDIRECT = new ICMPv4Type(VAL_MOBILE_HOST_REDIRECT);
public static final ICMPv4Type IPV6_WHERE_ARE_YOU = new ICMPv4Type(VAL_IPV6_WHERE_ARE_YOU);
public static final ICMPv4Type IPV6_I_AM_HERE = new ICMPv4Type(VAL_IPV6_I_AM_HERE);
public static final ICMPv4Type MOBILE_REGISTRATION_REQUEST = new ICMPv4Type(VAL_MOBILE_REGISTRATION_REQUEST);
public static final ICMPv4Type MOBILE_REGISTRATION_REPLY = new ICMPv4Type(VAL_MOBILE_REGISTRATION_REPLY);
public static final ICMPv4Type DOMAIN_NAME_REQUEST = new ICMPv4Type(VAL_DOMAIN_NAME_REQUEST);
public static final ICMPv4Type DOMAIN_NAME_REPLY = new ICMPv4Type(VAL_DOMAIN_NAME_REPLY);
public static final ICMPv4Type SKIP = new ICMPv4Type(VAL_SKIP);
public static final ICMPv4Type PHOTURIS = new ICMPv4Type(VAL_PHOTURIS);
public static final ICMPv4Type EXPERIMENTAL_MOBILITY = new ICMPv4Type(VAL_EXPERIMENTAL_MOBILITY);
// HACK alert - we're disapproriating ECHO_REPLY (value 0) as 'none' as well
public static final ICMPv4Type NONE = ECHO_REPLY;
public static final ICMPv4Type NO_MASK = new ICMPv4Type((short)0xFFFF);
public static final ICMPv4Type FULL_MASK = new ICMPv4Type((short)0x0000);
private final short type;
private static final int MIN_TYPE = 0;
private static final int MAX_TYPE = 0xFF;
private ICMPv4Type(short type) {
this.type = type;
}
public static ICMPv4Type of(short type) {
if (type < MIN_TYPE || type > MAX_TYPE)
throw new IllegalArgumentException("Invalid ICMPv4 type: " + type);
switch (type) {
case VAL_ECHO_REPLY:
return ECHO_REPLY;
case VAL_DESTINATION_UNREACHABLE:
return DESTINATION_UNREACHABLE;
case VAL_SOURCE_QUENCH:
return SOURCE_QUENCH;
case VAL_REDIRECT:
return REDIRECT;
case VAL_ALTERNATE_HOST_ADDRESS:
return ALTERNATE_HOST_ADDRESS;
case VAL_ECHO:
return ECHO;
case VAL_ROUTER_ADVERTISEMENT:
return ROUTER_ADVERTISEMENT;
case VAL_ROUTER_SOLICITATION:
return ROUTER_SOLICITATION;
case VAL_TIME_EXCEEDED:
return TIME_EXCEEDED;
case VAL_PARAMETER_PROBLEM:
return PARAMETER_PROBLEM;
case VAL_TIMESTAMP:
return TIMESTAMP;
case VAL_TIMESTAMP_REPLY:
return TIMESTAMP_REPLY;
case VAL_INFORMATION_REQUEST:
return INFORMATION_REQUEST;
case VAL_INFORMATION_REPLY:
return INFORMATION_REPLY;
case VAL_ADDRESS_MASK_REQUEST:
return ADDRESS_MASK_REQUEST;
case VAL_ADDRESS_MASK_REPLY:
return ADDRESS_MASK_REPLY;
case VAL_TRACEROUTE:
return TRACEROUTE;
case VAL_DATAGRAM_CONVERSION_ERROR:
return DATAGRAM_CONVERSION_ERROR;
case VAL_MOBILE_HOST_REDIRECT:
return MOBILE_HOST_REDIRECT;
case VAL_IPV6_WHERE_ARE_YOU:
return IPV6_WHERE_ARE_YOU;
case VAL_IPV6_I_AM_HERE:
return IPV6_I_AM_HERE;
case VAL_MOBILE_REGISTRATION_REQUEST:
return MOBILE_REGISTRATION_REQUEST;
case VAL_MOBILE_REGISTRATION_REPLY:
return MOBILE_REGISTRATION_REPLY;
case VAL_DOMAIN_NAME_REQUEST:
return DOMAIN_NAME_REQUEST;
case VAL_DOMAIN_NAME_REPLY:
return DOMAIN_NAME_REPLY;
case VAL_SKIP:
return SKIP;
case VAL_PHOTURIS:
return PHOTURIS;
case VAL_EXPERIMENTAL_MOBILITY:
return EXPERIMENTAL_MOBILITY;
default:
return new ICMPv4Type(type);
}
}
@Override
public int getLength() {
return LENGTH;
}
public short getType() {
return type;
}
public void writeByte(ChannelBuffer c) {
c.writeByte(this.type);
}
public static ICMPv4Type readByte(ChannelBuffer c) {
return ICMPv4Type.of(c.readUnsignedByte());
}
@Override
public ICMPv4Type applyMask(ICMPv4Type mask) {
return ICMPv4Type.of((short)(this.type & mask.type));
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + type;
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
ICMPv4Type other = (ICMPv4Type) obj;
if (type != other.type)
return false;
return true;
}
@Override
public int compareTo(ICMPv4Type o) {
return Shorts.compare(type, o.type);
}
@Override
public void putTo(PrimitiveSink sink) {
sink.putShort(type);
}
@Override
public String toString() {
return String.valueOf(this.type);
}
}
package org.projectfloodlight.openflow.types;
import java.net.Inet4Address;
import java.net.Inet6Address;
import java.net.InetAddress;
import javax.annotation.Nonnull;
import com.google.common.base.Preconditions;
public abstract class IPAddress<F extends IPAddress<F>> implements OFValueType<F> {
public abstract IPVersion getIpVersion();
/**
* Checks if this IPAddress represents a valid CIDR style netmask, i.e.,
* it has a set of leading "1" bits followed by only "0" bits
* @return true if this represents a valid CIDR style netmask, false
* otherwise
*/
public abstract boolean isCidrMask();
/**
* If this IPAddress represents a valid CIDR style netmask (see
* isCidrMask()) returns the length of the prefix (the number of "1" bits).
* @return length of CIDR mask if this represents a valid CIDR mask
* @throws IllegalStateException if isCidrMask() == false
*/
public abstract int asCidrMaskLength();
/**
* Checks if the IPAddress is the global broadcast address
* 255.255.255.255 in case of IPv4
* @return boolean true or false
*/
public abstract boolean isBroadcast();
/**
* Perform a low level AND operation on the bits of two IPAddress<?> objects
* @param other IPAddress<?>
* @return new IPAddress<?> object after the AND oper
*/
public abstract F and(F other);
/**
* Perform a low level OR operation on the bits of two IPAddress<?> objects
* @param other IPAddress<?>
* @return new IPAddress<?> object after the AND oper
*/
public abstract F or(F other);
/**
* Returns a new IPAddress object with the bits inverted
* @return IPAddress<?>
*/
public abstract F not();
@Override
public abstract boolean equals(Object other);
@Override
public abstract int hashCode();
/** parse an IPv4Address or IPv6Address from their conventional string representation.
* For details on supported representations, refer to {@link IPv4Address#of(String)}
* and {@link IPv6Address#of(String)}
*
* @param ip a string representation of an IP address
* @return the parsed IP address
* @throws NullPointerException if ip is null
* @throws IllegalArgumentException if string is not a valid IP address
*/
@Nonnull
public static IPAddress<?> of(@Nonnull String ip) {
Preconditions.checkNotNull(ip, "ip must not be null");
if (ip.indexOf('.') != -1)
return IPv4Address.of(ip);
else if (ip.indexOf(':') != -1)
return IPv6Address.of(ip);
else
throw new IllegalArgumentException("IP Address not well formed: " + ip);
}
/**
* Factory function for InetAddress values.
* @param address the InetAddress you wish to parse into an IPAddress object.
* @return the IPAddress object.
* @throws NullPointerException if address is null
*/
@Nonnull
public static IPAddress<?> fromInetAddress(@Nonnull InetAddress address) {
Preconditions.checkNotNull(address, "address must not be null");
byte [] bytes = address.getAddress();
if(address instanceof Inet4Address)
return IPv4Address.of(bytes);
else if (address instanceof Inet6Address)
return IPv6Address.of(bytes);
else
return IPAddress.of(address.getHostAddress());
}
}
package org.projectfloodlight.openflow.types;
public abstract class IPAddressWithMask<F extends IPAddress<F>> extends Masked<F> {
protected IPAddressWithMask(F value, F mask) {
super(value, mask);
}
public abstract IPVersion getIpVersion();
public F getSubnetBroadcastAddress() {
if (!mask.isCidrMask()) {
throw new IllegalArgumentException("Mask Invalid " + mask +
" cannot get subnet for non CIDR mask");
}
return value.or(mask.not());
}
public boolean isSubnetBroadcastAddress(F candidate) {
return getSubnetBroadcastAddress().equals(candidate);
}
public static IPAddressWithMask<?> of(String ip) {
if (ip == null) {
throw new NullPointerException("String ip must not be null");
}
if (ip.indexOf('.') != -1)
return IPv4AddressWithMask.of(ip);
else if (ip.indexOf(':') != -1)
return IPv6AddressWithMask.of(ip);
else
throw new IllegalArgumentException("IP Address not well formed: " + ip);
}
@Override
public String toString() {
StringBuilder res = new StringBuilder();
res.append(value.toString());
res.append('/');
if (mask.isCidrMask()) {
// CIDR notation
res.append(mask.asCidrMaskLength());
} else {
// Full address mask
res.append(mask.toString());
}
return res.toString();
}
}
package org.projectfloodlight.openflow.types;
public enum IPVersion {
IPv4,
IPv6
}
package org.projectfloodlight.openflow.types;
import java.util.Arrays;
import javax.annotation.Nonnull;
import org.jboss.netty.buffer.ChannelBuffer;
import com.google.common.hash.PrimitiveSink;
import com.google.common.primitives.UnsignedInts;
/**
* Wrapper around an IPv4Address address
*
* @author Andreas Wundsam <andreas.wundsam@bigswitch.com>
*/
public class IPv4Address extends IPAddress<IPv4Address> {
static final int LENGTH = 4;
private final int rawValue;
private static final int NOT_A_CIDR_MASK = -1;
private static final int CIDR_MASK_CACHE_UNSET = -2;
// Must appear before the static IPv4Address constant assignments
private volatile int cidrMaskLengthCache = CIDR_MASK_CACHE_UNSET;
private final static int NONE_VAL = 0x0;
public final static IPv4Address NONE = new IPv4Address(NONE_VAL);
public static final IPv4Address NO_MASK = IPv4Address.of(0xFFFFFFFF);
public static final IPv4Address FULL_MASK = IPv4Address.of(0x00000000);
private IPv4Address(final int rawValue) {
this.rawValue = rawValue;
}
@Override
public IPVersion getIpVersion() {
return IPVersion.IPv4;
}
private int asCidrMaskLengthInternal() {
if (cidrMaskLengthCache == CIDR_MASK_CACHE_UNSET) {
// No lock required. We only write cidrMaskLengthCache once
int maskint = getInt();
if (maskint == 0) {
cidrMaskLengthCache = 0;
} else if (Integer.bitCount((~maskint) + 1) == 1) {
// IP represents a true CIDR prefix length
cidrMaskLengthCache = Integer.bitCount(maskint);
} else {
cidrMaskLengthCache = NOT_A_CIDR_MASK;
}
}
return cidrMaskLengthCache;
}
@Override
public boolean isCidrMask() {
return asCidrMaskLengthInternal() != NOT_A_CIDR_MASK;
}
@Override
public int asCidrMaskLength() {
if (!isCidrMask()) {
throw new IllegalStateException("IP is not a valid CIDR prefix " +
"mask " + toString());
} else {
return asCidrMaskLengthInternal();
}
}
@Override
public boolean isBroadcast() {
return this.equals(NO_MASK);
}
@Override
public IPv4Address and(IPv4Address other) {
if (other == null) {
throw new NullPointerException("Other IP Address must not be null");
}
IPv4Address otherIp = (IPv4Address) other;
return IPv4Address.of(rawValue & otherIp.rawValue);
}
@Override
public IPv4Address or(IPv4Address other) {
if (other == null) {
throw new NullPointerException("Other IP Address must not be null");
}
IPv4Address otherIp = (IPv4Address) other;
return IPv4Address.of(rawValue | otherIp.rawValue);
}
@Override
public IPv4Address not() {
return IPv4Address.of(~rawValue);
}
public static IPv4Address of(final byte[] address) {
if (address == null) {
throw new NullPointerException("Address must not be null");
}
if (address.length != LENGTH) {
throw new IllegalArgumentException(
"Invalid byte array length for IPv4Address address: " + address.length);
}
int raw =
(address[0] & 0xFF) << 24 | (address[1] & 0xFF) << 16
| (address[2] & 0xFF) << 8 | (address[3] & 0xFF) << 0;
return IPv4Address.of(raw);
}
/** construct an IPv4Address from a 32-bit integer value.
*
* @param raw the IPAdress represented as a 32-bit integer
* @return the constructed IPv4Address
*/
public static IPv4Address of(final int raw) {
if(raw == NONE_VAL)
return NONE;
return new IPv4Address(raw);
}
/** parse an IPv4Address from the canonical dotted-quad representation
* (1.2.3.4).
*
* @param string an IPv4 address in dotted-quad representation
* @return the parsed IPv4 address
* @throws NullPointerException if string is null
* @throws IllegalArgumentException if string is not a valid IPv4Address
*/
@Nonnull
public static IPv4Address of(@Nonnull final String string) throws IllegalArgumentException {
if (string == null) {
throw new NullPointerException("String must not be null");
}
int start = 0;
int shift = 24;
int raw = 0;
while (shift >= 0) {
int end = string.indexOf('.', start);
if (end == start || !((shift > 0) ^ (end < 0)))
throw new IllegalArgumentException("IP Address not well formed: " + string);
String substr =
end > 0 ? string.substring(start, end) : string.substring(start);
int val = Integer.parseInt(substr);
if (val < 0 || val > 255)
throw new IllegalArgumentException("IP Address not well formed: " + string);
raw |= val << shift;
shift -= 8;
start = end + 1;
}
return IPv4Address.of(raw);
}
public int getInt() {
return rawValue;
}
private volatile byte[] bytesCache = null;
public byte[] getBytes() {
if (bytesCache == null) {
synchronized (this) {
if (bytesCache == null) {
bytesCache =
new byte[] { (byte) ((rawValue >>> 24) & 0xFF),
(byte) ((rawValue >>> 16) & 0xFF),
(byte) ((rawValue >>> 8) & 0xFF),
(byte) ((rawValue >>> 0) & 0xFF) };
}
}
}
return Arrays.copyOf(bytesCache, bytesCache.length);
}
@Override
public int getLength() {
return LENGTH;
}
@Override
public String toString() {
StringBuilder res = new StringBuilder();
res.append((rawValue >> 24) & 0xFF).append('.');
res.append((rawValue >> 16) & 0xFF).append('.');
res.append((rawValue >> 8) & 0xFF).append('.');
res.append((rawValue >> 0) & 0xFF);
return res.toString();
}
public void write4Bytes(ChannelBuffer c) {
c.writeInt(rawValue);
}
public static IPv4Address read4Bytes(ChannelBuffer c) {
return IPv4Address.of(c.readInt());
}
@Override
public IPv4Address applyMask(IPv4Address mask) {
return and(mask);
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + rawValue;
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
IPv4Address other = (IPv4Address) obj;
if (rawValue != other.rawValue)
return false;
return true;
}
@Override
public int compareTo(IPv4Address o) {
return UnsignedInts.compare(rawValue, o.rawValue);
}
@Override
public void putTo(PrimitiveSink sink) {
sink.putInt(rawValue);
}
}
package org.projectfloodlight.openflow.types;
public class IPv4AddressWithMask extends IPAddressWithMask<IPv4Address> {
public final static IPv4AddressWithMask NONE = of(IPv4Address.NONE, IPv4Address.NONE);
private IPv4AddressWithMask(int rawValue, int rawMask) {
super(IPv4Address.of(rawValue), IPv4Address.of(rawMask));
}
private IPv4AddressWithMask(IPv4Address value, IPv4Address mask) {
super(value, mask);
}
@Override
public IPVersion getIpVersion() {
return IPVersion.IPv4;
}
public static IPv4AddressWithMask of(int rawValue, int rawMask) {
return new IPv4AddressWithMask(rawValue, rawMask);
}
public static IPv4AddressWithMask of(IPv4Address value, IPv4Address mask) {
if (value == null) {
throw new NullPointerException("Value must not be null");
}
if (mask == null) {
throw new NullPointerException("Mask must not be null");
}
return new IPv4AddressWithMask(value, mask);
}
public static IPv4AddressWithMask of(final String string) {
if (string == null) {
throw new NullPointerException("String must not be null");
}
int slashPos;
String ip = string;
int maskBits = 32;
IPv4Address maskAddress = null;
// Read mask suffix
if ((slashPos = string.indexOf('/')) != -1) {
ip = string.substring(0, slashPos);
try {
String suffix = string.substring(slashPos + 1);
if (suffix.length() == 0)
throw new IllegalArgumentException("IP Address not well formed: " + string);
if (suffix.indexOf('.') != -1) {
// Full mask
maskAddress = IPv4Address.of(suffix);
} else {
// CIDR Suffix
maskBits = Integer.parseInt(suffix);
}
} catch (NumberFormatException e) {
throw new IllegalArgumentException("IP Address not well formed: " + string);
}
if (maskBits < 0 || maskBits > 32) {
throw new IllegalArgumentException("IP Address not well formed: " + string);
}
}
// Read IP
IPv4Address ipv4 = IPv4Address.of(ip);
if (maskAddress != null) {
// Full address mask
return IPv4AddressWithMask.of(ipv4, maskAddress);
} else if (maskBits == 32) {
// No mask
return IPv4AddressWithMask.of(ipv4, IPv4Address.NO_MASK);
} else if (maskBits == 0) {
// No mask
return IPv4AddressWithMask.of(ipv4, IPv4Address.FULL_MASK);
} else {
// With mask
int mask = (-1) << (32 - maskBits);
return IPv4AddressWithMask.of(ipv4, IPv4Address.of(mask));
}
}
}
package org.projectfloodlight.openflow.types;
import java.util.Arrays;
import java.util.regex.Pattern;
import javax.annotation.Nonnull;
import org.jboss.netty.buffer.ChannelBuffer;
import org.projectfloodlight.openflow.exceptions.OFParseError;
import com.google.common.hash.PrimitiveSink;
import com.google.common.primitives.Longs;
/**
* IPv6 address object. Instance controlled, immutable. Internal representation:
* two 64 bit longs (not that you'd have to know).
*
* @author Andreas Wundsam <andreas.wundsam@teleteach.de>
*/
public class IPv6Address extends IPAddress<IPv6Address> {
static final int LENGTH = 16;
private final long raw1;
private final long raw2;
private static final int NOT_A_CIDR_MASK = -1;
private static final int CIDR_MASK_CACHE_UNSET = -2;
// Must appear before the static IPv4Address constant assignments
private volatile int cidrMaskLengthCache = CIDR_MASK_CACHE_UNSET;
private final static long NONE_VAL1 = 0x0L;
private final static long NONE_VAL2 = 0x0L;
public static final IPv6Address NONE = new IPv6Address(NONE_VAL1, NONE_VAL2);
public static final IPv6Address NO_MASK = IPv6Address.of(0xFFFFFFFFFFFFFFFFl, 0xFFFFFFFFFFFFFFFFl);
public static final IPv6Address FULL_MASK = IPv6Address.of(0x0, 0x0);
private IPv6Address(final long raw1, final long raw2) {
this.raw1 = raw1;
this.raw2 = raw2;
}
@Override
public IPVersion getIpVersion() {
return IPVersion.IPv6;
}
private int computeCidrMask64(long raw) {
long mask = raw;
if (raw == 0)
return 0;
else if (Long.bitCount((~mask) + 1) == 1) {
// represent a true CIDR prefix length
return Long.bitCount(mask);
}
else {
// Not a true prefix
return NOT_A_CIDR_MASK;
}
}
private int asCidrMaskLengthInternal() {
if (cidrMaskLengthCache == CIDR_MASK_CACHE_UNSET) {
// No synchronization needed. Writing cidrMaskLengthCache only once
if (raw1 == 0 && raw2 == 0) {
cidrMaskLengthCache = 0;
} else if (raw1 == -1L) {
// top half is all 1 bits
int tmpLength = computeCidrMask64(raw2);
if (tmpLength != NOT_A_CIDR_MASK)
tmpLength += 64;
cidrMaskLengthCache = tmpLength;
} else if (raw2 == 0) {
cidrMaskLengthCache = computeCidrMask64(raw1);
} else {
cidrMaskLengthCache = NOT_A_CIDR_MASK;
}
}
return cidrMaskLengthCache;
}
@Override
public boolean isCidrMask() {
return asCidrMaskLengthInternal() != NOT_A_CIDR_MASK;
}
@Override
public int asCidrMaskLength() {
if (!isCidrMask()) {
throw new IllegalStateException("IP is not a valid CIDR prefix " +
"mask " + toString());
} else {
return asCidrMaskLengthInternal();
}
}
@Override
public boolean isBroadcast() {
return this.equals(NO_MASK);
}
@Override
public IPv6Address and(IPv6Address other) {
if (other == null) {
throw new NullPointerException("Other IP Address must not be null");
}
IPv6Address otherIp = (IPv6Address) other;
return IPv6Address.of((raw1 & otherIp.raw1), (raw2 & otherIp.raw2));
}
@Override
public IPv6Address or(IPv6Address other) {
if (other == null) {
throw new NullPointerException("Other IP Address must not be null");
}
IPv6Address otherIp = (IPv6Address) other;
return IPv6Address.of((raw1 | otherIp.raw1), (raw2 | otherIp.raw2));
}
@Override
public IPv6Address not() {
return IPv6Address.of(~raw1, ~raw2);
}
public static IPv6Address of(final byte[] address) {
if (address == null) {
throw new NullPointerException("Address must not be null");
}
if (address.length != LENGTH) {
throw new IllegalArgumentException(
"Invalid byte array length for IPv6 address: " + address.length);
}
long raw1 =
(address[0] & 0xFFL) << 56 | (address[1] & 0xFFL) << 48
| (address[2] & 0xFFL) << 40 | (address[3] & 0xFFL) << 32
| (address[4] & 0xFFL) << 24 | (address[5] & 0xFFL) << 16
| (address[6] & 0xFFL) << 8 | (address[7]);
long raw2 =
(address[8] & 0xFFL) << 56 | (address[9] & 0xFFL) << 48
| (address[10] & 0xFFL) << 40 | (address[11] & 0xFFL) << 32
| (address[12] & 0xFFL) << 24 | (address[13] & 0xFFL) << 16
| (address[14] & 0xFFL) << 8 | (address[15]);
return IPv6Address.of(raw1, raw2);
}
private static class IPv6Builder {
private long raw1, raw2;
public void setUnsignedShortWord(final int i, final int value) {
int shift = 48 - (i % 4) * 16;
if (value < 0 || value > 0xFFFF)
throw new IllegalArgumentException("16 bit word must be in [0, 0xFFFF]");
if (i >= 0 && i < 4)
raw1 = raw1 & ~(0xFFFFL << shift) | (value & 0xFFFFL) << shift;
else if (i >= 4 && i < 8)
raw2 = raw2 & ~(0xFFFFL << shift) | (value & 0xFFFFL) << shift;
else
throw new IllegalArgumentException("16 bit word index must be in [0,7]");
}
public IPv6Address getIPv6() {
return IPv6Address.of(raw1, raw2);
}
}
private final static Pattern colonPattern = Pattern.compile(":");
/** parse an IPv6Address from its conventional string representation.
* <p>
* Expects up to 8 groups of 16-bit hex words seperated by colons
* (e.g., 2001:db8:85a3:8d3:1319:8a2e:370:7348).
* <p>
* Supports zero compression (e.g., 2001:db8::7348).
* Does <b>not</b> currently support embedding a dotted-quad IPv4 address
* into the IPv6 address (e.g., 2001:db8::192.168.0.1).
*
* @param string a string representation of an IPv6 address
* @return the parsed IPv6 address
* @throws NullPointerException if string is null
* @throws IllegalArgumentException if string is not a valid IPv6Address
*/
@Nonnull
public static IPv6Address of(@Nonnull final String string) throws IllegalArgumentException {
if (string == null) {
throw new NullPointerException("String must not be null");
}
IPv6Builder builder = new IPv6Builder();
String[] parts = colonPattern.split(string, -1);
int leftWord = 0;
int leftIndex = 0;
boolean hitZeroCompression = false;
for (leftIndex = 0; leftIndex < parts.length; leftIndex++) {
String part = parts[leftIndex];
if (part.length() == 0) {
// hit empty group of zero compression
hitZeroCompression = true;
break;
}
builder.setUnsignedShortWord(leftWord++, Integer.parseInt(part, 16));
}
if (hitZeroCompression) {
if (leftIndex == 0) {
// if colon is at the start, two columns must be at the start,
// move to the second empty group
leftIndex = 1;
if (parts.length < 2 || parts[1].length() > 0)
throw new IllegalArgumentException("Malformed IPv6 address: " + string);
}
int rightWord = 7;
int rightIndex;
for (rightIndex = parts.length - 1; rightIndex > leftIndex; rightIndex--) {
String part = parts[rightIndex];
if (part.length() == 0)
break;
builder.setUnsignedShortWord(rightWord--, Integer.parseInt(part, 16));
}
if (rightIndex == parts.length - 1) {
// if colon is at the end, two columns must be at the end, move
// to the second empty group
if (rightIndex < 1 || parts[rightIndex - 1].length() > 0)
throw new IllegalArgumentException("Malformed IPv6 address: " + string);
rightIndex--;
}
if (leftIndex != rightIndex)
throw new IllegalArgumentException("Malformed IPv6 address: " + string);
} else {
if (leftIndex != 8) {
throw new IllegalArgumentException("Malformed IPv6 address: " + string);
}
}
return builder.getIPv6();
}
/** construct an IPv6 adress from two 64 bit integers representing the first and
* second 8-byte blocks of the address.
*
* @param raw1 - the first 8 byte block of the address
* @param raw2 - the second 8 byte block of the address
* @return the constructed IPv6Address
*/
public static IPv6Address of(final long raw1, final long raw2) {
if(raw1==NONE_VAL1 && raw2 == NONE_VAL2)
return NONE;
return new IPv6Address(raw1, raw2);
}
private volatile byte[] bytesCache = null;
public byte[] getBytes() {
if (bytesCache == null) {
synchronized (this) {
if (bytesCache == null) {
bytesCache =
new byte[] { (byte) ((raw1 >> 56) & 0xFF),
(byte) ((raw1 >> 48) & 0xFF),
(byte) ((raw1 >> 40) & 0xFF),
(byte) ((raw1 >> 32) & 0xFF),
(byte) ((raw1 >> 24) & 0xFF),
(byte) ((raw1 >> 16) & 0xFF),
(byte) ((raw1 >> 8) & 0xFF),
(byte) ((raw1 >> 0) & 0xFF),
(byte) ((raw2 >> 56) & 0xFF),
(byte) ((raw2 >> 48) & 0xFF),
(byte) ((raw2 >> 40) & 0xFF),
(byte) ((raw2 >> 32) & 0xFF),
(byte) ((raw2 >> 24) & 0xFF),
(byte) ((raw2 >> 16) & 0xFF),
(byte) ((raw2 >> 8) & 0xFF),
(byte) ((raw2 >> 0) & 0xFF) };
}
}
}
return Arrays.copyOf(bytesCache, bytesCache.length);
}
@Override
public int getLength() {
return LENGTH;
}
@Override
public String toString() {
return toString(true, false);
}
public int getUnsignedShortWord(final int i) {
if (i >= 0 && i < 4)
return (int) ((raw1 >>> (48 - i * 16)) & 0xFFFF);
else if (i >= 4 && i < 8)
return (int) ((raw2 >>> (48 - (i - 4) * 16)) & 0xFFFF);
else
throw new IllegalArgumentException("16 bit word index must be in [0,7]");
}
/** get the index of the first word where to apply IPv6 zero compression */
public int getZeroCompressStart() {
int start = Integer.MAX_VALUE;
int maxLength = -1;
int candidateStart = -1;
for (int i = 0; i < 8; i++) {
if (candidateStart >= 0) {
// in a zero octect
if (getUnsignedShortWord(i) != 0) {
// end of this candidate word
int candidateLength = i - candidateStart;
if (candidateLength >= maxLength) {
start = candidateStart;
maxLength = candidateLength;
}
candidateStart = -1;
}
} else {
// not in a zero octect
if (getUnsignedShortWord(i) == 0) {
candidateStart = i;
}
}
}
if (candidateStart >= 0) {
int candidateLength = 8 - candidateStart;
if (candidateLength >= maxLength) {
start = candidateStart;
maxLength = candidateLength;
}
}
return start;
}
public String toString(final boolean zeroCompression, final boolean leadingZeros) {
StringBuilder res = new StringBuilder();
int compressionStart = zeroCompression ? getZeroCompressStart() : Integer.MAX_VALUE;
boolean inCompression = false;
boolean colonNeeded = false;
for (int i = 0; i < 8; i++) {
int word = getUnsignedShortWord(i);
if (word == 0) {
if (inCompression)
continue;
else if (i == compressionStart) {
res.append(':').append(':');
inCompression = true;
colonNeeded = false;
continue;
}
} else {
inCompression = false;
}
if (colonNeeded) {
res.append(':');
colonNeeded = false;
}
res.append(leadingZeros ? String.format("%04x", word) : Integer.toString(word,
16));
colonNeeded = true;
}
return res.toString();
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + (int) (raw1 ^ (raw1 >>> 32));
result = prime * result + (int) (raw2 ^ (raw2 >>> 32));
return result;
}
@Override
public boolean equals(final Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
IPv6Address other = (IPv6Address) obj;
if (raw1 != other.raw1)
return false;
if (raw2 != other.raw2)
return false;
return true;
}
public void write16Bytes(ChannelBuffer c) {
c.writeLong(this.raw1);
c.writeLong(this.raw2);
}
public static IPv6Address read16Bytes(ChannelBuffer c) throws OFParseError {
return IPv6Address.of(c.readLong(), c.readLong());
}
@Override
public IPv6Address applyMask(IPv6Address mask) {
return and(mask);
}
@Override
public int compareTo(IPv6Address o) {
int res = Longs.compare(raw1, o.raw1);
if(res != 0)
return res;
else
return Longs.compare(raw2, o.raw2);
}
@Override
public void putTo(PrimitiveSink sink) {
sink.putLong(raw1);
sink.putLong(raw2);
}
}
package org.projectfloodlight.openflow.types;
import java.math.BigInteger;
import java.util.Arrays;
public class IPv6AddressWithMask extends IPAddressWithMask<IPv6Address> {
public final static IPv6AddressWithMask NONE = of(IPv6Address.NONE, IPv6Address.NONE);
private IPv6AddressWithMask(IPv6Address value, IPv6Address mask) {
super(value, mask);
}
@Override
public IPVersion getIpVersion() {
return IPVersion.IPv6;
}
public static IPv6AddressWithMask of(IPv6Address value, IPv6Address mask) {
if (value == null) {
throw new NullPointerException("Value must not be null");
}
if (mask == null) {
throw new NullPointerException("Mask must not be null");
}
return new IPv6AddressWithMask(value, mask);
}
public static IPv6AddressWithMask of(final String string) {
if (string == null) {
throw new NullPointerException("String must not be null");
}
int slashPos;
String ip = string;
int maskBits = 128;
IPv6Address maskAddress = null;
// Read mask suffix
if ((slashPos = string.indexOf('/')) != -1) {
ip = string.substring(0, slashPos);
try {
String suffix = string.substring(slashPos + 1);
if (suffix.length() == 0)
throw new IllegalArgumentException("IPv6 Address not well formed: " + string);
if (suffix.indexOf(':') != -1) {
// Full mask
maskAddress = IPv6Address.of(suffix);
} else {
// CIDR Suffix
maskBits = Integer.parseInt(suffix);
}
} catch (NumberFormatException e) {
throw new IllegalArgumentException("IPv6 Address not well formed: " + string);
}
if (maskBits < 0 || maskBits > 128) {
throw new IllegalArgumentException("IPv6 Address not well formed: " + string);
}
}
// Read IP
IPv6Address ipv6 = IPv6Address.of(ip);
if (maskAddress != null) {
// Full address mask
return IPv6AddressWithMask.of(ipv6, maskAddress);
} else if (maskBits == 128) {
// No mask
return IPv6AddressWithMask.of(ipv6, IPv6Address.NO_MASK);
} else if (maskBits == 0) {
// Entirely masked out
return IPv6AddressWithMask.of(ipv6, IPv6Address.FULL_MASK);
}else {
// With mask
BigInteger mask = BigInteger.ONE.negate().shiftLeft(128 - maskBits);
byte[] maskBytesTemp = mask.toByteArray();
byte[] maskBytes;
if (maskBytesTemp.length < 16) {
maskBytes = new byte[16];
System.arraycopy(maskBytesTemp, 0, maskBytes, 16 - maskBytesTemp.length, maskBytesTemp.length);
Arrays.fill(maskBytes, 0, 16 - maskBytesTemp.length, (byte)(0xFF));
} else if (maskBytesTemp.length > 16) {
maskBytes = new byte[16];
System.arraycopy(maskBytesTemp, 0, maskBytes, 0, maskBytes.length);
} else {
maskBytes = maskBytesTemp;
}
return IPv6AddressWithMask.of(ipv6, IPv6Address.of(maskBytes));
}
}
}
package org.projectfloodlight.openflow.types;
import org.jboss.netty.buffer.ChannelBuffer;
import org.projectfloodlight.openflow.exceptions.OFParseError;
import com.google.common.hash.PrimitiveSink;
import com.google.common.primitives.UnsignedInts;
public class IPv6FlowLabel implements OFValueType<IPv6FlowLabel> {
static final int LENGTH = 4;
private final int label;
private final static int NONE_VAL = 0x0;
public static final IPv6FlowLabel NONE = new IPv6FlowLabel(NONE_VAL);
public static final IPv6FlowLabel NO_MASK = IPv6FlowLabel.of(0xFFFFFFFF);
public static final IPv6FlowLabel FULL_MASK = IPv6FlowLabel.of(0x0);
private IPv6FlowLabel(int label) {
this.label = label;
}
public static IPv6FlowLabel of(int label) {
if(label == NONE_VAL)
return NONE;
return new IPv6FlowLabel(label);
}
@Override
public int getLength() {
return LENGTH;
}
@Override
public boolean equals(Object obj) {
if (!(obj instanceof IPv6FlowLabel))
return false;
IPv6FlowLabel other = (IPv6FlowLabel)obj;
if (other.label != this.label)
return false;
return true;
}
@Override
public int hashCode() {
final int prime = 59;
int result = 1;
result = prime * result + label;
return result;
}
@Override
public String toString() {
return Integer.toHexString(label);
}
public void write4Bytes(ChannelBuffer c) {
c.writeInt(this.label);
}
public static IPv6FlowLabel read4Bytes(ChannelBuffer c) throws OFParseError {
return IPv6FlowLabel.of((int)(c.readUnsignedInt() & 0xFFFFFFFF));
}
@Override
public IPv6FlowLabel applyMask(IPv6FlowLabel mask) {
return IPv6FlowLabel.of(this.label & mask.label);
}
public int getIPv6FlowLabelValue() {
return label;
}
@Override
public int compareTo(IPv6FlowLabel o) {
return UnsignedInts.compare(label, o.label);
}
@Override
public void putTo(PrimitiveSink sink) {
sink.putInt(this.label);
}
}
package org.projectfloodlight.openflow.types;
import org.jboss.netty.buffer.ChannelBuffer;
import org.projectfloodlight.openflow.exceptions.OFParseError;
import com.google.common.hash.PrimitiveSink;
public enum IpDscp implements OFValueType<IpDscp> {
DSCP_0((byte)0),
DSCP_1((byte)1),
DSCP_2((byte)2),
DSCP_3((byte)3),
DSCP_4((byte)4),
DSCP_5((byte)5),
DSCP_6((byte)6),
DSCP_7((byte)7),
DSCP_8((byte)8),
DSCP_9((byte)9),
DSCP_10((byte)10),
DSCP_11((byte)11),
DSCP_12((byte)12),
DSCP_13((byte)13),
DSCP_14((byte)14),
DSCP_15((byte)15),
DSCP_16((byte)16),
DSCP_17((byte)17),
DSCP_18((byte)18),
DSCP_19((byte)19),
DSCP_20((byte)20),
DSCP_21((byte)21),
DSCP_22((byte)22),
DSCP_23((byte)23),
DSCP_24((byte)24),
DSCP_25((byte)25),
DSCP_26((byte)26),
DSCP_27((byte)27),
DSCP_28((byte)28),
DSCP_29((byte)29),
DSCP_30((byte)30),
DSCP_31((byte)31),
DSCP_32((byte)32),
DSCP_33((byte)33),
DSCP_34((byte)34),
DSCP_35((byte)35),
DSCP_36((byte)36),
DSCP_37((byte)37),
DSCP_38((byte)38),
DSCP_39((byte)39),
DSCP_40((byte)40),
DSCP_41((byte)41),
DSCP_42((byte)42),
DSCP_43((byte)43),
DSCP_44((byte)44),
DSCP_45((byte)45),
DSCP_46((byte)46),
DSCP_47((byte)47),
DSCP_48((byte)48),
DSCP_49((byte)49),
DSCP_50((byte)50),
DSCP_51((byte)51),
DSCP_52((byte)52),
DSCP_53((byte)53),
DSCP_54((byte)54),
DSCP_55((byte)55),
DSCP_56((byte)56),
DSCP_57((byte)57),
DSCP_58((byte)58),
DSCP_59((byte)59),
DSCP_60((byte)60),
DSCP_61((byte)61),
DSCP_62((byte)62),
DSCP_63((byte)63),
DSCP_NO_MASK((byte)0xFF);
static final int LENGTH = 1;
public static final IpDscp NONE = DSCP_0;
public static final IpDscp NO_MASK = DSCP_NO_MASK;
public static final IpDscp FULL_MASK = DSCP_0;
private final byte dscp;
private IpDscp(byte dscp) {
this.dscp = dscp;
}
public static IpDscp of(byte dscp) {
switch (dscp) {
case 0:
return DSCP_0;
case 1:
return DSCP_1;
case 2:
return DSCP_2;
case 3:
return DSCP_3;
case 4:
return DSCP_4;
case 5:
return DSCP_5;
case 6:
return DSCP_6;
case 7:
return DSCP_7;
case 8:
return DSCP_8;
case 9:
return DSCP_9;
case 10:
return DSCP_10;
case 11:
return DSCP_11;
case 12:
return DSCP_12;
case 13:
return DSCP_13;
case 14:
return DSCP_14;
case 15:
return DSCP_15;
case 16:
return DSCP_16;
case 17:
return DSCP_17;
case 18:
return DSCP_18;
case 19:
return DSCP_19;
case 20:
return DSCP_20;
case 21:
return DSCP_21;
case 22:
return DSCP_22;
case 23:
return DSCP_23;
case 24:
return DSCP_24;
case 25:
return DSCP_25;
case 26:
return DSCP_26;
case 27:
return DSCP_27;
case 28:
return DSCP_28;
case 29:
return DSCP_29;
case 30:
return DSCP_30;
case 31:
return DSCP_31;
case 32:
return DSCP_32;
case 33:
return DSCP_33;
case 34:
return DSCP_34;
case 35:
return DSCP_35;
case 36:
return DSCP_36;
case 37:
return DSCP_37;
case 38:
return DSCP_38;
case 39:
return DSCP_39;
case 40:
return DSCP_40;
case 41:
return DSCP_41;
case 42:
return DSCP_42;
case 43:
return DSCP_43;
case 44:
return DSCP_44;
case 45:
return DSCP_45;
case 46:
return DSCP_46;
case 47:
return DSCP_47;
case 48:
return DSCP_48;
case 49:
return DSCP_49;
case 50:
return DSCP_50;
case 51:
return DSCP_51;
case 52:
return DSCP_52;
case 53:
return DSCP_53;
case 54:
return DSCP_54;
case 55:
return DSCP_55;
case 56:
return DSCP_56;
case 57:
return DSCP_57;
case 58:
return DSCP_58;
case 59:
return DSCP_59;
case 60:
return DSCP_60;
case 61:
return DSCP_61;
case 62:
return DSCP_62;
case 63:
return DSCP_63;
default:
throw new IllegalArgumentException("Illegal IPv4 DSCP value: " + dscp);
}
}
@Override
public int getLength() {
return LENGTH;
}
@Override
public String toString() {
return Integer.toHexString(dscp);
}
public void writeByte(ChannelBuffer c) {
c.writeByte(this.dscp);
}
public static IpDscp readByte(ChannelBuffer c) throws OFParseError {
return IpDscp.of((byte)(c.readUnsignedByte()));
}
@Override
public IpDscp applyMask(IpDscp mask) {
return IpDscp.of((byte)(this.dscp & mask.dscp));
}
public byte getDscpValue() {
return dscp;
}
@Override
public void putTo(PrimitiveSink sink) {
sink.putByte(dscp);
}
}
package org.projectfloodlight.openflow.types;
import org.jboss.netty.buffer.ChannelBuffer;
import org.projectfloodlight.openflow.exceptions.OFParseError;
import com.google.common.hash.PrimitiveSink;
public enum IpEcn implements OFValueType<IpEcn> {
ECN_00((byte)0),
ECN_01((byte)1),
ECN_10((byte)2),
ECN_11((byte)3),
ECN_NO_MASK((byte)0xFF);
public static final IpEcn NONE = ECN_00;
public static final IpEcn NO_MASK = ECN_NO_MASK;
public static final IpEcn FULL_MASK = ECN_00;
static final int LENGTH = 1;
private final byte ecn;
private IpEcn(byte ecn) {
this.ecn = ecn;
}
public static IpEcn of(byte ecn) {
switch (ecn) {
case 0:
return ECN_00;
case 1:
return ECN_01;
case 2:
return ECN_10;
case 3:
return ECN_11;
default:
throw new IllegalArgumentException("Illegal IP ECN value: " + ecn);
}
}
@Override
public int getLength() {
return LENGTH;
}
@Override
public String toString() {
return (ecn < 3 ? "0" : "") + Integer.toBinaryString(ecn);
}
public void writeByte(ChannelBuffer c) {
c.writeByte(this.ecn);
}
public static IpEcn readByte(ChannelBuffer c) throws OFParseError {
return IpEcn.of((byte)(c.readUnsignedByte()));
}
@Override
public IpEcn applyMask(IpEcn mask) {
return IpEcn.of((byte)(this.ecn & mask.ecn));
}
public byte getEcnValue() {
return ecn;
}
@Override
public void putTo(PrimitiveSink sink) {
sink.putByte(ecn);
}
}
package org.projectfloodlight.openflow.types;
import org.jboss.netty.buffer.ChannelBuffer;
import com.google.common.hash.PrimitiveSink;
import com.google.common.primitives.Shorts;
/**
* IP-Protocol field representation
*
* @author Yotam Harchol (yotam.harchol@bigswitch.com)
*/
public class IpProtocol implements OFValueType<IpProtocol> {
static final short MAX_PROTO = 0xFF;
static final int LENGTH = 1;
private final short proto;
static final short NUM_HOPOPT = 0x00;
static final short NUM_ICMP = 0x01;
static final short NUM_IGMP = 0x02;
static final short NUM_GGP = 0x03;
static final short NUM_IPv4 = 0x04;
static final short NUM_ST = 0x05;
static final short NUM_TCP = 0x06;
static final short NUM_CBT = 0x07;
static final short NUM_EGP = 0x08;
static final short NUM_IGP = 0x09;
static final short NUM_BBN_RCC_MON = 0x0A;
static final short NUM_NVP_II = 0x0B;
static final short NUM_PUP = 0x0C;
static final short NUM_ARGUS = 0x0D;
static final short NUM_EMCON = 0x0E;
static final short NUM_XNET = 0x0F;
static final short NUM_CHAOS = 0x10;
static final short NUM_UDP = 0x11;
static final short NUM_MUX = 0x12;
static final short NUM_DCN_MEAS = 0x13;
static final short NUM_HMP = 0x14;
static final short NUM_PRM = 0x15;
static final short NUM_XNS_IDP = 0x16;
static final short NUM_TRUNK_1 = 0x17;
static final short NUM_TRUNK_2 = 0x18;
static final short NUM_LEAF_1 = 0x19;
static final short NUM_LEAF_2 = 0x1A;
static final short NUM_RDP = 0x1B;
static final short NUM_IRTP = 0x1C;
static final short NUM_ISO_TP4 = 0x1D;
static final short NUM_NETBLT = 0x1E;
static final short NUM_MFE_NSP = 0x1F;
static final short NUM_MERIT_INP = 0x20;
static final short NUM_DCCP = 0x21;
static final short NUM_3PC = 0x22;
static final short NUM_IDPR = 0x23;
static final short NUM_XTP = 0x24;
static final short NUM_DDP = 0x25;
static final short NUM_IDPR_CMTP = 0x26;
static final short NUM_TP_PP = 0x27;
static final short NUM_IL = 0x28;
static final short NUM_IPv6 = 0x29;
static final short NUM_SDRP = 0x2A;
static final short NUM_IPv6_ROUTE = 0x2B;
static final short NUM_IPv6_FRAG = 0x2C;
static final short NUM_IDRP = 0x2D;
static final short NUM_RSVP = 0x2E;
static final short NUM_GRE = 0x2F;
static final short NUM_MHRP = 0x30;
static final short NUM_BNA = 0x31;
static final short NUM_ESP = 0x32;
static final short NUM_AH = 0x33;
static final short NUM_I_NLSP = 0x34;
static final short NUM_SWIPE = 0x35;
static final short NUM_NARP = 0x36;
static final short NUM_MOBILE = 0x37;
static final short NUM_TLSP = 0x38;
static final short NUM_SKIP = 0x39;
static final short NUM_IPv6_ICMP = 0x3A;
static final short NUM_IPv6_NO_NXT = 0x3B;
static final short NUM_IPv6_OPTS = 0x3C;
static final short NUM_HOST_INTERNAL = 0x3D;
static final short NUM_CFTP = 0x3E;
static final short NUM_LOCAL_NET = 0x3F;
static final short NUM_SAT_EXPAK = 0x40;
static final short NUM_KRYPTOLAN = 0x41;
static final short NUM_RVD = 0x42;
static final short NUM_IPPC = 0x43;
static final short NUM_DIST_FS = 0x44;
static final short NUM_SAT_MON = 0x45;
static final short NUM_VISA = 0x46;
static final short NUM_IPCV = 0x47;
static final short NUM_CPNX = 0x48;
static final short NUM_CPHB = 0x49;
static final short NUM_WSN = 0x4A;
static final short NUM_PVP = 0x4B;
static final short NUM_BR_SAT_MON = 0x4C;
static final short NUM_SUN_ND = 0x4D;
static final short NUM_WB_MON = 0x4E;
static final short NUM_WB_EXPAK = 0x4F;
static final short NUM_ISO_IP = 0x50;
static final short NUM_VMTP = 0x51;
static final short NUM_SECURE_VMTP = 0x52;
static final short NUM_VINES = 0x53;
static final short NUM_TTP_IPTM = 0x54;
static final short NUM_NSFNET_IGP = 0x55;
static final short NUM_DGP = 0x56;
static final short NUM_TCF = 0x57;
static final short NUM_EIGRP = 0x58;
static final short NUM_OSPF = 0x59;
static final short NUM_Sprite_RPC = 0x5A;
static final short NUM_LARP = 0x5B;
static final short NUM_MTP = 0x5C;
static final short NUM_AX_25 = 0x5D;
static final short NUM_IPIP = 0x5E;
static final short NUM_MICP = 0x5F;
static final short NUM_SCC_SP = 0x60;
static final short NUM_ETHERIP = 0x61;
static final short NUM_ENCAP = 0x62;
static final short NUM_PRIVATE_ENCRYPT = 0x63;
static final short NUM_GMTP = 0x64;
static final short NUM_IFMP = 0x65;
static final short NUM_PNNI = 0x66;
static final short NUM_PIM = 0x67;
static final short NUM_ARIS = 0x68;
static final short NUM_SCPS = 0x69;
static final short NUM_QNX = 0x6A;
static final short NUM_A_N = 0x6B;
static final short NUM_IP_COMP = 0x6C;
static final short NUM_SNP = 0x6D;
static final short NUM_COMPAQ_PEER = 0x6E;
static final short NUM_IPX_IN_IP = 0x6F;
static final short NUM_VRRP = 0x70;
static final short NUM_PGM = 0x71;
static final short NUM_ZERO_HOP = 0x72;
static final short NUM_L2TP = 0x73;
static final short NUM_DDX = 0x74;
static final short NUM_IATP = 0x75;
static final short NUM_STP = 0x76;
static final short NUM_SRP = 0x77;
static final short NUM_UTI = 0x78;
static final short NUM_SMP = 0x79;
static final short NUM_SM = 0x7A;
static final short NUM_PTP = 0x7B;
static final short NUM_IS_IS_OVER_IPv4 = 0x7C;
static final short NUM_FIRE = 0x7D;
static final short NUM_CRTP = 0x7E;
static final short NUM_CRUDP = 0x7F;
static final short NUM_SSCOPMCE = 0x80;
static final short NUM_IPLT = 0x81;
static final short NUM_SPS = 0x82;
static final short NUM_PIPE = 0x83;
static final short NUM_SCTP = 0x84;
static final short NUM_FC = 0x85;
static final short NUM_RSVP_E2E_IGNORE = 0x86;
static final short NUM_MOBILITY_HEADER = 0x87;
static final short NUM_UDP_LITE = 0x88;
static final short NUM_MPLS_IN_IP = 0x89;
static final short NUM_MANET = 0x8A;
static final short NUM_HIP = 0x8B;
static final short NUM_SHIM6 = 0x8C;
public static final IpProtocol HOPOPT = new IpProtocol(NUM_HOPOPT);
public static final IpProtocol ICMP = new IpProtocol(NUM_ICMP);
public static final IpProtocol IGMP = new IpProtocol(NUM_IGMP);
public static final IpProtocol GGP = new IpProtocol(NUM_GGP);
public static final IpProtocol IPv4 = new IpProtocol(NUM_IPv4);
public static final IpProtocol ST = new IpProtocol(NUM_ST);
public static final IpProtocol TCP = new IpProtocol(NUM_TCP);
public static final IpProtocol CBT = new IpProtocol(NUM_CBT);
public static final IpProtocol EGP = new IpProtocol(NUM_EGP);
public static final IpProtocol IGP = new IpProtocol(NUM_IGP);
public static final IpProtocol BBN_RCC_MON = new IpProtocol(NUM_BBN_RCC_MON);
public static final IpProtocol NVP_II = new IpProtocol(NUM_NVP_II);
public static final IpProtocol PUP = new IpProtocol(NUM_PUP);
public static final IpProtocol ARGUS = new IpProtocol(NUM_ARGUS);
public static final IpProtocol EMCON = new IpProtocol(NUM_EMCON);
public static final IpProtocol XNET = new IpProtocol(NUM_XNET);
public static final IpProtocol CHAOS = new IpProtocol(NUM_CHAOS);
public static final IpProtocol UDP = new IpProtocol(NUM_UDP);
public static final IpProtocol MUX = new IpProtocol(NUM_MUX);
public static final IpProtocol DCN_MEAS = new IpProtocol(NUM_DCN_MEAS);
public static final IpProtocol HMP = new IpProtocol(NUM_HMP);
public static final IpProtocol PRM = new IpProtocol(NUM_PRM);
public static final IpProtocol XNS_IDP = new IpProtocol(NUM_XNS_IDP);
public static final IpProtocol TRUNK_1 = new IpProtocol(NUM_TRUNK_1);
public static final IpProtocol TRUNK_2 = new IpProtocol(NUM_TRUNK_2);
public static final IpProtocol LEAF_1 = new IpProtocol(NUM_LEAF_1);
public static final IpProtocol LEAF_2 = new IpProtocol(NUM_LEAF_2);
public static final IpProtocol RDP = new IpProtocol(NUM_RDP);
public static final IpProtocol IRTP = new IpProtocol(NUM_IRTP);
public static final IpProtocol ISO_TP4 = new IpProtocol(NUM_ISO_TP4);
public static final IpProtocol NETBLT = new IpProtocol(NUM_NETBLT);
public static final IpProtocol MFE_NSP = new IpProtocol(NUM_MFE_NSP);
public static final IpProtocol MERIT_INP = new IpProtocol(NUM_MERIT_INP);
public static final IpProtocol DCCP = new IpProtocol(NUM_DCCP);
public static final IpProtocol _3PC = new IpProtocol(NUM_3PC);
public static final IpProtocol IDPR = new IpProtocol(NUM_IDPR);
public static final IpProtocol XTP = new IpProtocol(NUM_XTP);
public static final IpProtocol DDP = new IpProtocol(NUM_DDP);
public static final IpProtocol IDPR_CMTP = new IpProtocol(NUM_IDPR_CMTP);
public static final IpProtocol TP_PP = new IpProtocol(NUM_TP_PP);
public static final IpProtocol IL = new IpProtocol(NUM_IL);
public static final IpProtocol IPv6 = new IpProtocol(NUM_IPv6);
public static final IpProtocol SDRP = new IpProtocol(NUM_SDRP);
public static final IpProtocol IPv6_ROUTE = new IpProtocol(NUM_IPv6_ROUTE);
public static final IpProtocol IPv6_FRAG = new IpProtocol(NUM_IPv6_FRAG);
public static final IpProtocol IDRP = new IpProtocol(NUM_IDRP);
public static final IpProtocol RSVP = new IpProtocol(NUM_RSVP);
public static final IpProtocol GRE = new IpProtocol(NUM_GRE);
public static final IpProtocol MHRP = new IpProtocol(NUM_MHRP);
public static final IpProtocol BNA = new IpProtocol(NUM_BNA);
public static final IpProtocol ESP = new IpProtocol(NUM_ESP);
public static final IpProtocol AH = new IpProtocol(NUM_AH);
public static final IpProtocol I_NLSP = new IpProtocol(NUM_I_NLSP);
public static final IpProtocol SWIPE = new IpProtocol(NUM_SWIPE);
public static final IpProtocol NARP = new IpProtocol(NUM_NARP);
public static final IpProtocol MOBILE = new IpProtocol(NUM_MOBILE);
public static final IpProtocol TLSP = new IpProtocol(NUM_TLSP);
public static final IpProtocol SKIP = new IpProtocol(NUM_SKIP);
public static final IpProtocol IPv6_ICMP = new IpProtocol(NUM_IPv6_ICMP);
public static final IpProtocol IPv6_NO_NXT = new IpProtocol(NUM_IPv6_NO_NXT);
public static final IpProtocol IPv6_OPTS = new IpProtocol(NUM_IPv6_OPTS);
public static final IpProtocol HOST_INTERNAL = new IpProtocol(NUM_HOST_INTERNAL);
public static final IpProtocol CFTP = new IpProtocol(NUM_CFTP);
public static final IpProtocol LOCAL_NET = new IpProtocol(NUM_LOCAL_NET);
public static final IpProtocol SAT_EXPAK = new IpProtocol(NUM_SAT_EXPAK);
public static final IpProtocol KRYPTOLAN = new IpProtocol(NUM_KRYPTOLAN);
public static final IpProtocol RVD = new IpProtocol(NUM_RVD);
public static final IpProtocol IPPC = new IpProtocol(NUM_IPPC);
public static final IpProtocol DIST_FS = new IpProtocol(NUM_DIST_FS);
public static final IpProtocol SAT_MON = new IpProtocol(NUM_SAT_MON);
public static final IpProtocol VISA = new IpProtocol(NUM_VISA);
public static final IpProtocol IPCV = new IpProtocol(NUM_IPCV);
public static final IpProtocol CPNX = new IpProtocol(NUM_CPNX);
public static final IpProtocol CPHB = new IpProtocol(NUM_CPHB);
public static final IpProtocol WSN = new IpProtocol(NUM_WSN);
public static final IpProtocol PVP = new IpProtocol(NUM_PVP);
public static final IpProtocol BR_SAT_MON = new IpProtocol(NUM_BR_SAT_MON);
public static final IpProtocol SUN_ND = new IpProtocol(NUM_SUN_ND);
public static final IpProtocol WB_MON = new IpProtocol(NUM_WB_MON);
public static final IpProtocol WB_EXPAK = new IpProtocol(NUM_WB_EXPAK);
public static final IpProtocol ISO_IP = new IpProtocol(NUM_ISO_IP);
public static final IpProtocol VMTP = new IpProtocol(NUM_VMTP);
public static final IpProtocol SECURE_VMTP = new IpProtocol(NUM_SECURE_VMTP);
public static final IpProtocol VINES = new IpProtocol(NUM_VINES);
public static final IpProtocol TTP_IPTM = new IpProtocol(NUM_TTP_IPTM);
public static final IpProtocol NSFNET_IGP = new IpProtocol(NUM_NSFNET_IGP);
public static final IpProtocol DGP = new IpProtocol(NUM_DGP);
public static final IpProtocol TCF = new IpProtocol(NUM_TCF);
public static final IpProtocol EIGRP = new IpProtocol(NUM_EIGRP);
public static final IpProtocol OSPF = new IpProtocol(NUM_OSPF);
public static final IpProtocol Sprite_RPC = new IpProtocol(NUM_Sprite_RPC);
public static final IpProtocol LARP = new IpProtocol(NUM_LARP);
public static final IpProtocol MTP = new IpProtocol(NUM_MTP);
public static final IpProtocol AX_25 = new IpProtocol(NUM_AX_25);
public static final IpProtocol IPIP = new IpProtocol(NUM_IPIP);
public static final IpProtocol MICP = new IpProtocol(NUM_MICP);
public static final IpProtocol SCC_SP = new IpProtocol(NUM_SCC_SP);
public static final IpProtocol ETHERIP = new IpProtocol(NUM_ETHERIP);
public static final IpProtocol ENCAP = new IpProtocol(NUM_ENCAP);
public static final IpProtocol PRIVATE_ENCRYPT = new IpProtocol(NUM_PRIVATE_ENCRYPT);
public static final IpProtocol GMTP = new IpProtocol(NUM_GMTP);
public static final IpProtocol IFMP = new IpProtocol(NUM_IFMP);
public static final IpProtocol PNNI = new IpProtocol(NUM_PNNI);
public static final IpProtocol PIM = new IpProtocol(NUM_PIM);
public static final IpProtocol ARIS = new IpProtocol(NUM_ARIS);
public static final IpProtocol SCPS = new IpProtocol(NUM_SCPS);
public static final IpProtocol QNX = new IpProtocol(NUM_QNX);
public static final IpProtocol A_N = new IpProtocol(NUM_A_N);
public static final IpProtocol IP_COMP = new IpProtocol(NUM_IP_COMP);
public static final IpProtocol SNP = new IpProtocol(NUM_SNP);
public static final IpProtocol COMPAQ_PEER = new IpProtocol(NUM_COMPAQ_PEER);
public static final IpProtocol IPX_IN_IP = new IpProtocol(NUM_IPX_IN_IP);
public static final IpProtocol VRRP = new IpProtocol(NUM_VRRP);
public static final IpProtocol PGM = new IpProtocol(NUM_PGM);
public static final IpProtocol ZERO_HOP = new IpProtocol(NUM_ZERO_HOP);
public static final IpProtocol L2TP = new IpProtocol(NUM_L2TP);
public static final IpProtocol DDX = new IpProtocol(NUM_DDX);
public static final IpProtocol IATP = new IpProtocol(NUM_IATP);
public static final IpProtocol STP = new IpProtocol(NUM_STP);
public static final IpProtocol SRP = new IpProtocol(NUM_SRP);
public static final IpProtocol UTI = new IpProtocol(NUM_UTI);
public static final IpProtocol SMP = new IpProtocol(NUM_SMP);
public static final IpProtocol SM = new IpProtocol(NUM_SM);
public static final IpProtocol PTP = new IpProtocol(NUM_PTP);
public static final IpProtocol IS_IS_OVER_IPv4 = new IpProtocol(NUM_IS_IS_OVER_IPv4);
public static final IpProtocol FIRE = new IpProtocol(NUM_FIRE);
public static final IpProtocol CRTP = new IpProtocol(NUM_CRTP);
public static final IpProtocol CRUDP = new IpProtocol(NUM_CRUDP);
public static final IpProtocol SSCOPMCE = new IpProtocol(NUM_SSCOPMCE);
public static final IpProtocol IPLT = new IpProtocol(NUM_IPLT);
public static final IpProtocol SPS = new IpProtocol(NUM_SPS);
public static final IpProtocol PIPE = new IpProtocol(NUM_PIPE);
public static final IpProtocol SCTP = new IpProtocol(NUM_SCTP);
public static final IpProtocol FC = new IpProtocol(NUM_FC);
public static final IpProtocol RSVP_E2E_IGNORE = new IpProtocol(NUM_RSVP_E2E_IGNORE);
public static final IpProtocol MOBILITY_HEADER = new IpProtocol(NUM_MOBILITY_HEADER);
public static final IpProtocol UDP_LITE = new IpProtocol(NUM_UDP_LITE);
public static final IpProtocol MPLS_IN_IP = new IpProtocol(NUM_MPLS_IN_IP);
public static final IpProtocol MANET = new IpProtocol(NUM_MANET);
public static final IpProtocol HIP = new IpProtocol(NUM_HIP);
public static final IpProtocol SHIM6 = new IpProtocol(NUM_SHIM6);
public static final IpProtocol NONE = HOPOPT;
public static final IpProtocol NO_MASK = HOPOPT;
public static final IpProtocol FULL_MASK = new IpProtocol((short)0x0000);
private IpProtocol(short version) {
this.proto = version;
}
@Override
public int getLength() {
return LENGTH;
}
public static IpProtocol of(short proto) {
switch (proto) {
case NUM_HOPOPT:
return HOPOPT;
case NUM_ICMP:
return ICMP;
case NUM_IGMP:
return IGMP;
case NUM_GGP:
return GGP;
case NUM_IPv4:
return IPv4;
case NUM_ST:
return ST;
case NUM_TCP:
return TCP;
case NUM_CBT:
return CBT;
case NUM_EGP:
return EGP;
case NUM_IGP:
return IGP;
case NUM_BBN_RCC_MON:
return BBN_RCC_MON;
case NUM_NVP_II:
return NVP_II;
case NUM_PUP:
return PUP;
case NUM_ARGUS:
return ARGUS;
case NUM_EMCON:
return EMCON;
case NUM_XNET:
return XNET;
case NUM_CHAOS:
return CHAOS;
case NUM_UDP:
return UDP;
case NUM_MUX:
return MUX;
case NUM_DCN_MEAS:
return DCN_MEAS;
case NUM_HMP:
return HMP;
case NUM_PRM:
return PRM;
case NUM_XNS_IDP:
return XNS_IDP;
case NUM_TRUNK_1:
return TRUNK_1;
case NUM_TRUNK_2:
return TRUNK_2;
case NUM_LEAF_1:
return LEAF_1;
case NUM_LEAF_2:
return LEAF_2;
case NUM_RDP:
return RDP;
case NUM_IRTP:
return IRTP;
case NUM_ISO_TP4:
return ISO_TP4;
case NUM_NETBLT:
return NETBLT;
case NUM_MFE_NSP:
return MFE_NSP;
case NUM_MERIT_INP:
return MERIT_INP;
case NUM_DCCP:
return DCCP;
case NUM_3PC:
return _3PC;
case NUM_IDPR:
return IDPR;
case NUM_XTP:
return XTP;
case NUM_DDP:
return DDP;
case NUM_IDPR_CMTP:
return IDPR_CMTP;
case NUM_TP_PP:
return TP_PP;
case NUM_IL:
return IL;
case NUM_IPv6:
return IPv6;
case NUM_SDRP:
return SDRP;
case NUM_IPv6_ROUTE:
return IPv6_ROUTE;
case NUM_IPv6_FRAG:
return IPv6_FRAG;
case NUM_IDRP:
return IDRP;
case NUM_RSVP:
return RSVP;
case NUM_GRE:
return GRE;
case NUM_MHRP:
return MHRP;
case NUM_BNA:
return BNA;
case NUM_ESP:
return ESP;
case NUM_AH:
return AH;
case NUM_I_NLSP:
return I_NLSP;
case NUM_SWIPE:
return SWIPE;
case NUM_NARP:
return NARP;
case NUM_MOBILE:
return MOBILE;
case NUM_TLSP:
return TLSP;
case NUM_SKIP:
return SKIP;
case NUM_IPv6_ICMP:
return IPv6_ICMP;
case NUM_IPv6_NO_NXT:
return IPv6_NO_NXT;
case NUM_IPv6_OPTS:
return IPv6_OPTS;
case NUM_HOST_INTERNAL:
return HOST_INTERNAL;
case NUM_CFTP:
return CFTP;
case NUM_LOCAL_NET:
return LOCAL_NET;
case NUM_SAT_EXPAK:
return SAT_EXPAK;
case NUM_KRYPTOLAN:
return KRYPTOLAN;
case NUM_RVD:
return RVD;
case NUM_IPPC:
return IPPC;
case NUM_DIST_FS:
return DIST_FS;
case NUM_SAT_MON:
return SAT_MON;
case NUM_VISA:
return VISA;
case NUM_IPCV:
return IPCV;
case NUM_CPNX:
return CPNX;
case NUM_CPHB:
return CPHB;
case NUM_WSN:
return WSN;
case NUM_PVP:
return PVP;
case NUM_BR_SAT_MON:
return BR_SAT_MON;
case NUM_SUN_ND:
return SUN_ND;
case NUM_WB_MON:
return WB_MON;
case NUM_WB_EXPAK:
return WB_EXPAK;
case NUM_ISO_IP:
return ISO_IP;
case NUM_VMTP:
return VMTP;
case NUM_SECURE_VMTP:
return SECURE_VMTP;
case NUM_VINES:
return VINES;
case NUM_TTP_IPTM:
return TTP_IPTM;
case NUM_NSFNET_IGP:
return NSFNET_IGP;
case NUM_DGP:
return DGP;
case NUM_TCF:
return TCF;
case NUM_EIGRP:
return EIGRP;
case NUM_OSPF:
return OSPF;
case NUM_Sprite_RPC:
return Sprite_RPC;
case NUM_LARP:
return LARP;
case NUM_MTP:
return MTP;
case NUM_AX_25:
return AX_25;
case NUM_IPIP:
return IPIP;
case NUM_MICP:
return MICP;
case NUM_SCC_SP:
return SCC_SP;
case NUM_ETHERIP:
return ETHERIP;
case NUM_ENCAP:
return ENCAP;
case NUM_PRIVATE_ENCRYPT:
return PRIVATE_ENCRYPT;
case NUM_GMTP:
return GMTP;
case NUM_IFMP:
return IFMP;
case NUM_PNNI:
return PNNI;
case NUM_PIM:
return PIM;
case NUM_ARIS:
return ARIS;
case NUM_SCPS:
return SCPS;
case NUM_QNX:
return QNX;
case NUM_A_N:
return A_N;
case NUM_IP_COMP:
return IP_COMP;
case NUM_SNP:
return SNP;
case NUM_COMPAQ_PEER:
return COMPAQ_PEER;
case NUM_IPX_IN_IP:
return IPX_IN_IP;
case NUM_VRRP:
return VRRP;
case NUM_PGM:
return PGM;
case NUM_ZERO_HOP:
return ZERO_HOP;
case NUM_L2TP:
return L2TP;
case NUM_DDX:
return DDX;
case NUM_IATP:
return IATP;
case NUM_STP:
return STP;
case NUM_SRP:
return SRP;
case NUM_UTI:
return UTI;
case NUM_SMP:
return SMP;
case NUM_SM:
return SM;
case NUM_PTP:
return PTP;
case NUM_IS_IS_OVER_IPv4:
return IS_IS_OVER_IPv4;
case NUM_FIRE:
return FIRE;
case NUM_CRTP:
return CRTP;
case NUM_CRUDP:
return CRUDP;
case NUM_SSCOPMCE:
return SSCOPMCE;
case NUM_IPLT:
return IPLT;
case NUM_SPS:
return SPS;
case NUM_PIPE:
return PIPE;
case NUM_SCTP:
return SCTP;
case NUM_FC:
return FC;
case NUM_RSVP_E2E_IGNORE:
return RSVP_E2E_IGNORE;
case NUM_MOBILITY_HEADER:
return MOBILITY_HEADER;
case NUM_UDP_LITE:
return UDP_LITE;
case NUM_MPLS_IN_IP:
return MPLS_IN_IP;
case NUM_MANET:
return MANET;
case NUM_HIP:
return HIP;
case NUM_SHIM6:
return SHIM6;
default:
if (proto >= MAX_PROTO) {
throw new IllegalArgumentException("Illegal IP protocol number: "
+ proto);
} else {
return new IpProtocol(proto);
}
}
}
@Override
public String toString() {
return Integer.toHexString(proto);
}
public void writeByte(ChannelBuffer c) {
c.writeByte(this.proto);
}
public static IpProtocol readByte(ChannelBuffer c) {
return IpProtocol.of(c.readUnsignedByte());
}
@Override
public IpProtocol applyMask(IpProtocol mask) {
return IpProtocol.of((short)(this.proto & mask.proto));
}
public short getIpProtocolNumber() {
return proto;
}
@Override
public boolean equals(Object obj) {
if (!(obj instanceof IpProtocol))
return false;
IpProtocol o = (IpProtocol)obj;
if (o.proto != this.proto)
return false;
return true;
}
@Override
public int hashCode() {
final int prime = 37;
int result = 1;
result = prime * result + proto;
return result;
}
@Override
public int compareTo(IpProtocol o) {
return Shorts.compare(proto, o.proto);
}
@Override
public void putTo(PrimitiveSink sink) {
sink.putShort(proto);
}
}
\ No newline at end of file
package org.projectfloodlight.openflow.types;
import javax.annotation.concurrent.Immutable;
import org.jboss.netty.buffer.ChannelBuffer;
import com.google.common.hash.PrimitiveSink;
import com.google.common.primitives.UnsignedInts;
@Immutable
public class LagId implements OFValueType<LagId> {
static final int LENGTH = 4;
private final int rawValue;
private final static int NONE_VAL = 0;
public final static LagId NONE = new LagId(NONE_VAL);
private final static int NO_MASK_VAL = 0xFFFFFFFF;
public final static LagId NO_MASK = new LagId(NO_MASK_VAL);
public final static LagId FULL_MASK = NONE;
private LagId(final int rawValue) {
this.rawValue = rawValue;
}
public static LagId of(final int raw) {
if(raw == NONE_VAL)
return NONE;
else if (raw == NO_MASK_VAL)
return NO_MASK;
return new LagId(raw);
}
public int getInt() {
return rawValue;
}
@Override
public int getLength() {
return LENGTH;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + rawValue;
return result;
}
@Override
public String toString() {
return Integer.toString(rawValue);
}
@Override
public boolean equals(final Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
LagId other = (LagId) obj;
if (rawValue != other.rawValue)
return false;
return true;
}
public void write4Bytes(ChannelBuffer c) {
c.writeInt(rawValue);
}
public static LagId read4Bytes(ChannelBuffer c) {
return LagId.of(c.readInt());
}
@Override
public int compareTo(LagId o) {
return UnsignedInts.compare(rawValue, o.rawValue);
}
@Override
public LagId applyMask(LagId mask) {
return LagId.of(rawValue & mask.rawValue);
}
@Override
public void putTo(PrimitiveSink sink) {
sink.putInt(rawValue);
}
}
package org.projectfloodlight.openflow.types;
import java.util.Arrays;
import javax.annotation.Nonnull;
import org.jboss.netty.buffer.ChannelBuffer;
import org.projectfloodlight.openflow.exceptions.OFParseError;
import org.projectfloodlight.openflow.util.HexString;
import com.google.common.hash.PrimitiveSink;
import com.google.common.primitives.Longs;
/**
* Wrapper around a 6 byte mac address.
*
* @author Andreas Wundsam <andreas.wundsam@bigswitch.com>
*/
public class MacAddress implements OFValueType<MacAddress> {
static final int MacAddrLen = 6;
private final long rawValue;
private final static long NONE_VAL = 0x0L;
public static final MacAddress NONE = new MacAddress(NONE_VAL);
private final static long BROADCAST_VAL = 0x0000FFFFFFFFFFFFL;
public static final MacAddress BROADCAST = new MacAddress(BROADCAST_VAL);
public static final MacAddress NO_MASK = MacAddress.of(0xFFFFFFFFFFFFFFFFl);
public static final MacAddress FULL_MASK = MacAddress.of(0x0);
private static final long LLDP_MAC_ADDRESS_MASK = 0xfffffffffff0L;
private static final long LLDP_MAC_ADDRESS_VALUE = 0x0180c2000000L;
private MacAddress(final long rawValue) {
this.rawValue = rawValue;
}
public static MacAddress of(final byte[] address) {
if (address.length != MacAddrLen)
throw new IllegalArgumentException(
"Mac address byte array must be exactly 6 bytes long; length = " + address.length);
long raw =
(address[0] & 0xFFL) << 40 | (address[1] & 0xFFL) << 32
| (address[2] & 0xFFL) << 24 | (address[3] & 0xFFL) << 16
| (address[4] & 0xFFL) << 8 | (address[5] & 0xFFL);
return MacAddress.of(raw);
}
public static MacAddress of(long raw) {
raw &= BROADCAST_VAL;
if(raw == NONE_VAL)
return NONE;
if (raw == BROADCAST_VAL)
return BROADCAST;
return new MacAddress(raw);
}
/** Parse a mac adress from the canonical string representation as
* 6 hex bytes separated by colons (01:02:03:04:05:06).
*
* @param macString - a mac address in canonical string representation
* @return the parsed MacAddress
* @throws IllegalArgumentException if macString is not a valid mac adddress
*/
@Nonnull
public static MacAddress of(@Nonnull final String macString) throws IllegalArgumentException {
if (macString == null) {
throw new NullPointerException("macString must not be null");
}
int index = 0;
int shift = 40;
final String FORMAT_ERROR = "Mac address is not well-formed. " +
"It must consist of 6 hex digit pairs separated by colons: ";
long raw = 0;
if (macString.length() != 6 * 2 + 5)
throw new IllegalArgumentException(FORMAT_ERROR + macString);
while (shift >= 0) {
int digit1 = Character.digit(macString.charAt(index++), 16);
int digit2 = Character.digit(macString.charAt(index++), 16);
if ((digit1 < 0) || (digit2 < 0))
throw new IllegalArgumentException(FORMAT_ERROR + macString);
raw |= ((long) (digit1 << 4 | digit2)) << shift;
if (shift == 0)
break;
if (macString.charAt(index++) != ':')
throw new IllegalArgumentException(FORMAT_ERROR + macString);
shift -= 8;
}
return MacAddress.of(raw);
}
private volatile byte[] bytesCache = null;
public byte[] getBytes() {
if (bytesCache == null) {
synchronized (this) {
if (bytesCache == null) {
bytesCache =
new byte[] { (byte) ((rawValue >> 40) & 0xFF),
(byte) ((rawValue >> 32) & 0xFF),
(byte) ((rawValue >> 24) & 0xFF),
(byte) ((rawValue >> 16) & 0xFF),
(byte) ((rawValue >> 8) & 0xFF),
(byte) ((rawValue >> 0) & 0xFF) };
}
}
}
return Arrays.copyOf(bytesCache, bytesCache.length);
}
/**
* Returns {@code true} if the MAC address is the broadcast address.
* @return {@code true} if the MAC address is the broadcast address.
*/
public boolean isBroadcast() {
return this == BROADCAST;
}
/**
* Returns {@code true} if the MAC address is a multicast address.
* @return {@code true} if the MAC address is a multicast address.
*/
public boolean isMulticast() {
if (isBroadcast()) {
return false;
}
return (rawValue & (0x01L << 40)) != 0;
}
/**
* Returns {@code true} if the MAC address is an LLDP mac address.
* @return {@code true} if the MAC address is an LLDP mac address.
*/
public boolean isLLDPAddress() {
return (rawValue & LLDP_MAC_ADDRESS_MASK) == LLDP_MAC_ADDRESS_VALUE;
}
@Override
public int getLength() {
return MacAddrLen;
}
@Override
public String toString() {
return HexString.toHexString(rawValue, 6);
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + (int) (rawValue ^ (rawValue >>> 32));
return result;
}
@Override
public boolean equals(final Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
MacAddress other = (MacAddress) obj;
if (rawValue != other.rawValue)
return false;
return true;
}
public long getLong() {
return rawValue;
}
public void write6Bytes(ChannelBuffer c) {
c.writeInt((int) (this.rawValue >> 16));
c.writeShort((int) this.rawValue & 0xFFFF);
}
public static MacAddress read6Bytes(ChannelBuffer c) throws OFParseError {
long raw = c.readUnsignedInt() << 16 | c.readUnsignedShort();
return MacAddress.of(raw);
}
@Override
public MacAddress applyMask(MacAddress mask) {
return MacAddress.of(this.rawValue & mask.rawValue);
}
@Override
public int compareTo(MacAddress o) {
return Longs.compare(rawValue, o.rawValue);
}
@Override
public void putTo(PrimitiveSink sink) {
sink.putInt((int) (this.rawValue >> 16));
sink.putShort((short) (this.rawValue & 0xFFFF));
}
}
package org.projectfloodlight.openflow.types;
import com.google.common.hash.PrimitiveSink;
public class Masked<T extends OFValueType<T>> implements OFValueType<Masked<T>> {
protected final T value;
/** bitmask of the value. Note: a set (1) bit in this mask means 'match on this value'.
* This the natural mask represenation as in IPv[46] netmasks. It is the inverse of the
* OpenFlow 1.0 'wildcard' meaning.
*/
protected final T mask;
protected Masked(T value, T mask) {
this.value = value.applyMask(mask);
this.mask = mask;
}
public T getValue() {
return value;
}
public T getMask() {
return mask;
}
public static <T extends OFValueType<T>> Masked<T> of(T value, T mask) {
return new Masked<T>(value, mask);
}
@Override
public int getLength() {
return this.value.getLength() + this.mask.getLength();
}
@Override
public String toString() {
// General representation: value/mask
StringBuilder sb = new StringBuilder();
sb.append(value.toString()).append('/').append(mask.toString());
return sb.toString();
}
/** Determine whether candidate value is matched by this masked value
* (i.e., does candiate lie in the 'network/range' specified by this masked
* value).
*
* @param candidate the candidate value to test
* @return true iff the candidate lies in the area specified by this masked
* value.
*/
public boolean matches(T candidate) {
// candidate lies in the area of this masked value if its
// value with the masked bit zero'ed out equals this's value
// (e.g., our 'network address' for networks)
return candidate.applyMask(this.mask).equals(this.value);
}
@Override
public Masked<T> applyMask(Masked<T> mask) {
return this;
}
@Override
public boolean equals(Object obj) {
if (!(obj instanceof Masked<?>))
return false;
Masked<?> mobj = (Masked<?>)obj;
return this.value.equals(mobj.value) && this.mask.equals(mobj.mask);
}
@Override
public int hashCode() {
final int prime = 59;
int result = 1;
result = prime * result + this.value.hashCode();
result = prime * result + this.mask.hashCode();
return result;
}
@Override
public int compareTo(Masked<T> o) {
int res = value.compareTo(o.value);
if(res != 0)
return res;
else
return mask.compareTo(o.mask);
}
@Override
public void putTo(PrimitiveSink sink) {
value.putTo(sink);
mask.putTo(sink);
}
}
package org.projectfloodlight.openflow.types;
import org.jboss.netty.buffer.ChannelBuffer;
import org.projectfloodlight.openflow.exceptions.OFParseError;
import com.google.common.hash.PrimitiveSink;
import com.google.common.primitives.Shorts;
public class OFAuxId implements Comparable<OFAuxId>, PrimitiveSinkable {
private static final short VALIDATION_MASK = 0xFF;
private static final short MAIN_VAL = 0x0000;
public static final OFAuxId MAIN = new OFAuxId(MAIN_VAL);
private final short id;
private OFAuxId(short id) {
this.id = id;
}
public static OFAuxId of(short id) {
switch(id) {
case MAIN_VAL:
return MAIN;
default:
if ((id & VALIDATION_MASK) != id)
throw new IllegalArgumentException("Illegal Aux id value: " + id);
return new OFAuxId(id);
}
}
public static OFAuxId of(int id) {
if((id & VALIDATION_MASK) != id)
throw new IllegalArgumentException("Illegal Aux id value: "+id);
return of((short) id);
}
@Override
public String toString() {
return "0x" + Integer.toHexString(id);
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + id;
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj) return true;
if (obj == null) return false;
if (getClass() != obj.getClass()) return false;
OFAuxId other = (OFAuxId) obj;
if (id != other.id) return false;
return true;
}
public short getValue() {
return id;
}
public void writeByte(ChannelBuffer c) {
c.writeByte(this.id);
}
public static OFAuxId readByte(ChannelBuffer c) throws OFParseError {
return OFAuxId.of(c.readUnsignedByte());
}
@Override
public int compareTo(OFAuxId other) {
return Shorts.compare(this.id, other.id);
}
@Override
public void putTo(PrimitiveSink sink) {
sink.putByte((byte) id);
}
}
package org.projectfloodlight.openflow.types;
import org.jboss.netty.buffer.ChannelBuffer;
import com.google.common.hash.PrimitiveSink;
public class OFBitMask128 implements OFValueType<OFBitMask128> {
static final int LENGTH = 16;
private final long raw1; // MSBs (ports 64-127)
private final long raw2; // LSBs (ports 0-63)
public static final OFBitMask128 ALL = new OFBitMask128(-1, -1);
public static final OFBitMask128 NONE = new OFBitMask128(0, 0);
public static final OFBitMask128 NO_MASK = ALL;
public static final OFBitMask128 FULL_MASK = NONE;
private OFBitMask128(long raw1, long raw2) {
this.raw1 = raw1;
this.raw2 = raw2;
}
public static OFBitMask128 of(long raw1, long raw2) {
if (raw1 == -1 && raw2 == -1)
return ALL;
if (raw1 == 0 && raw2 == 0)
return NONE;
return new OFBitMask128(raw1, raw2);
}
@Override
public int getLength() {
return LENGTH;
}
@Override
public OFBitMask128 applyMask(OFBitMask128 mask) {
return of(this.raw1 & mask.raw1, this.raw2 & mask.raw2);
}
@Override
public boolean equals(Object obj) {
if (!(obj instanceof OFBitMask128))
return false;
OFBitMask128 other = (OFBitMask128)obj;
return (other.raw1 == this.raw1 && other.raw2 == this.raw2);
}
@Override
public int hashCode() {
return (int)(31 * raw1 + raw2);
}
protected static boolean isBitOn(long raw1, long raw2, int bit) {
if (bit < 0 || bit >= 128)
throw new IndexOutOfBoundsException();
long word;
if (bit < 64) {
word = raw2; // ports 0-63
} else {
word = raw1; // ports 64-127
bit -= 64;
}
return (word & ((long)1 << bit)) != 0;
}
public void write16Bytes(ChannelBuffer cb) {
cb.writeLong(raw1);
cb.writeLong(raw2);
}
public static OFBitMask128 read16Bytes(ChannelBuffer cb) {
long raw1 = cb.readLong();
long raw2 = cb.readLong();
return of(raw1, raw2);
}
public boolean isOn(int bit) {
return isBitOn(raw1, raw2, bit);
}
@Override
public String toString() {
return (String.format("%64s", Long.toBinaryString(raw2)) + String.format("%64s", Long.toBinaryString(raw1))).replaceAll(" ", "0");
}
@Override
public int compareTo(OFBitMask128 o) {
long c = this.raw1 - o.raw1;
if (c != 0)
return Long.signum(c);
return Long.signum(this.raw2 - o.raw2);
}
@Override
public void putTo(PrimitiveSink sink) {
sink.putLong(raw1);
sink.putLong(raw2);
}
}
/**
* Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior
* University
*
* 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.projectfloodlight.openflow.types;
import org.jboss.netty.buffer.ChannelBuffer;
import org.projectfloodlight.openflow.exceptions.OFParseError;
import org.projectfloodlight.openflow.protocol.OFMessageReader;
import org.projectfloodlight.openflow.protocol.Writeable;
import com.google.common.hash.PrimitiveSink;
public class OFBooleanValue implements Writeable, OFValueType<OFBooleanValue> {
public final static OFBooleanValue TRUE = new OFBooleanValue(true);
public final static OFBooleanValue FALSE = new OFBooleanValue(false);
public final static OFBooleanValue NO_MASK = TRUE;
public final static OFBooleanValue FULL_MASK = FALSE;
private final boolean value;
private OFBooleanValue(boolean value) {
this.value = value;
}
public static OFBooleanValue of(boolean value) {
return value ? TRUE : FALSE;
}
public boolean getValue() {
return value;
}
public int getInt() {
return value ? 1 : 0;
}
@Override
public String toString() {
return "" + value;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + getInt();
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
OFBooleanValue other = (OFBooleanValue) obj;
if (value != other.value)
return false;
return true;
}
@Override
public void writeTo(ChannelBuffer bb) {
bb.writeByte(getInt());
}
private static class Reader implements OFMessageReader<OFBooleanValue> {
@Override
public OFBooleanValue readFrom(ChannelBuffer bb) throws OFParseError {
return of(bb.readByte() != 0);
}
}
@Override
public int getLength() {
return 1;
}
@Override
public OFBooleanValue applyMask(OFBooleanValue mask) {
return of(value && mask.value);
}
@Override
public int compareTo(OFBooleanValue o) {
return getInt() - o.getInt();
}
@Override
public void putTo(PrimitiveSink sink) {
sink.putByte((byte)getInt());
}
}
package org.projectfloodlight.openflow.types;
import org.projectfloodlight.openflow.annotations.Immutable;
import com.google.common.hash.PrimitiveSink;
import com.google.common.primitives.UnsignedInts;
/**
* Abstraction of a buffer id in OpenFlow. Immutable.
*
* @author Rob Vaterlaus <rob.vaterlaus@bigswitch.com>
*/
@Immutable
public class OFBufferId implements Comparable<OFBufferId>, PrimitiveSinkable {
public static final OFBufferId NO_BUFFER = new OFBufferId(0xFFFFFFFF);
private final int rawValue;
private OFBufferId(int rawValue) {
this.rawValue = rawValue;
}
public static OFBufferId of(final int rawValue) {
if (rawValue == NO_BUFFER.getInt())
return NO_BUFFER;
return new OFBufferId(rawValue);
}
public int getInt() {
return rawValue;
}
@Override
public String toString() {
return Long.toString(U32.f(rawValue));
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + rawValue;
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
OFBufferId other = (OFBufferId) obj;
if (rawValue != other.rawValue)
return false;
return true;
}
@Override
public int compareTo(OFBufferId o) {
return UnsignedInts.compare(rawValue, o.rawValue);
}
@Override
public void putTo(PrimitiveSink sink) {
sink.putInt(rawValue);
}
}
package org.projectfloodlight.openflow.types;
import java.util.Arrays;
import org.jboss.netty.buffer.ChannelBuffer;
import org.jboss.netty.buffer.ChannelBuffers;
import org.projectfloodlight.openflow.exceptions.OFParseError;
import org.projectfloodlight.openflow.protocol.OFErrorMsg;
import org.projectfloodlight.openflow.protocol.OFFactories;
import org.projectfloodlight.openflow.protocol.OFFactory;
import org.projectfloodlight.openflow.protocol.OFMessage;
import org.projectfloodlight.openflow.protocol.OFVersion;
import org.projectfloodlight.openflow.protocol.Writeable;
import org.projectfloodlight.openflow.util.ChannelUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.common.base.Optional;
import com.google.common.hash.PrimitiveSink;
/** A special-purpose wrapper for the 'data' field in an {@link OFErrorMsg} message
* that contains a byte serialization of the offending message.
*
* This attempts to parse the offending message on demand, and if successful
* will present the parsed message.
*
* @author Andreas Wundsam <andreas.wundsam@bigswitch.com>
*/
public class OFErrorCauseData implements Writeable, PrimitiveSinkable {
private static final Logger logger =
LoggerFactory.getLogger(OFErrorCauseData.class);
/** A default 'empty' cause. Note: the OFVersion OF_13 passed in here is irrelevant,
* because parsing of the 0-byte array will always return null, irrespective of the
* version.
*/
public static final OFErrorCauseData NONE = new OFErrorCauseData(new byte[0], OFVersion.OF_13);
private final byte[] data;
private final OFVersion version;
private OFErrorCauseData(byte[] data, OFVersion version) {
this.data = data;
this.version = version;
}
public static OFErrorCauseData of(byte[] data, OFVersion version) {
return new OFErrorCauseData(Arrays.copyOf(data, data.length), version);
}
public byte[] getData() {
return Arrays.copyOf(data, data.length);
}
public Optional<OFMessage> getParsedMessage() {
OFFactory factory = OFFactories.getFactory(version);
try {
OFMessage msg = factory.getReader().readFrom(ChannelBuffers.wrappedBuffer(data));
if(msg != null)
return Optional.of(msg);
else
return Optional.absent();
} catch (OFParseError e) {
logger.debug("Error parsing error cause data as OFMessage: {}", e.getMessage(), e);
return Optional.absent();
}
}
public static OFErrorCauseData read(ChannelBuffer bb, int length, OFVersion version) {
byte[] bytes = ChannelUtils.readBytes(bb, length);
return of(bytes, version);
}
@Override
public void putTo(PrimitiveSink sink) {
sink.putBytes(data);
}
@Override
public void writeTo(ChannelBuffer bb) {
bb.writeBytes(data);
}
@Override
public String toString() {
Optional<OFMessage> parsedMessage = getParsedMessage();
if(parsedMessage.isPresent()) {
return String.valueOf(parsedMessage.get());
} else {
StringBuilder b = new StringBuilder();
b.append("[unparsed: ");
for(int i=0; i<data.length; i++) {
if(i>0)
b.append(" ");
b.append(String.format("%02x", data[i]));
}
b.append("]");
return b.toString();
}
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + Arrays.hashCode(data);
result = prime * result + ((version == null) ? 0 : version.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
OFErrorCauseData other = (OFErrorCauseData) obj;
if (!Arrays.equals(data, other.data))
return false;
if (version != other.version)
return false;
return true;
}
}
\ No newline at end of file
package org.projectfloodlight.openflow.types;
import org.jboss.netty.buffer.ChannelBuffer;
import org.projectfloodlight.openflow.annotations.Immutable;
import org.projectfloodlight.openflow.exceptions.OFParseError;
import com.google.common.hash.PrimitiveSink;
import com.google.common.primitives.UnsignedInts;
/**
* Abstraction of an logical / OpenFlow group (ofp_group) in OpenFlow.
* Immutable.
*
* @author Andreas Wundsam <andreas.wundsam@bigswitch.com>
*/
@Immutable
public class OFGroup implements OFValueType<OFGroup> {
static final int LENGTH = 4;
// private int constants (OF1.1+) to avoid duplication in the code
// should not have to use these outside this class
private static final int ZERO_VAL = 0x00;
private static final int MAX_VAL = 0xffffff00;
private static final int ALL_VAL = 0xfffffffc;
private static final int ANY_VAL = 0xffffffff;
// ////////////// public constants - use to access well known OpenFlow group constants
/** Maximum number of physical and logical switch groups. */
public final static OFGroup MAX = new NamedGroup(MAX_VAL, "max");
/** All groups */
public final static OFGroup ALL = new NamedGroup(ALL_VAL, "all");
/**
* Wildcard group used only for flow mod (delete) and flow stats requests. */
public final static OFGroup ANY = new NamedGroup(ANY_VAL, "any");
/** group 0 in case we need it */
public static final OFGroup ZERO = OFGroup.of(ZERO_VAL);
public static final OFGroup NO_MASK = ANY;
public static final OFGroup FULL_MASK = ZERO;
/** raw openflow group number as a signed 32 bit integer */
private final int groupNumber;
/** private constructor. use of*-Factory methods instead */
private OFGroup(final int portNumber) {
this.groupNumber = portNumber;
}
/**
* get an OFGroup object corresponding to a raw 32-bit integer group number.
* NOTE: The group object may either be newly allocated or cached. Do not
* rely on either behavior.
*
* @param groupNumber the raw 32-bit group number
* @return a corresponding OFPort
*/
public static OFGroup of(final int groupNumber) {
switch(groupNumber) {
case ZERO_VAL:
return MAX;
case MAX_VAL:
return MAX;
case ALL_VAL:
return ALL;
case ANY_VAL:
return ANY;
default:
if(UnsignedInts.compare(groupNumber, MAX_VAL) > 0) {
// greater than max_val, but not one of the reserved values
throw new IllegalArgumentException("Unknown special group number: "
+ groupNumber);
}
return new OFGroup(groupNumber);
}
}
/** return the group number as a int32 */
public int getGroupNumber() {
return groupNumber;
}
@Override
public String toString() {
return UnsignedInts.toString(groupNumber);
}
/** Extension of OFGroup for named groups */
static class NamedGroup extends OFGroup {
private final String name;
NamedGroup(final int portNo, final String name) {
super(portNo);
this.name = name;
}
public String getName() {
return name;
}
@Override
public String toString() {
return name;
}
}
@Override
public int getLength() {
return LENGTH;
}
@Override
public boolean equals(Object obj) {
if (!(obj instanceof OFGroup))
return false;
OFGroup other = (OFGroup)obj;
if (other.groupNumber != this.groupNumber)
return false;
return true;
}
@Override
public int hashCode() {
final int prime = 53;
int result = 1;
result = prime * result + groupNumber;
return result;
}
public void write4Bytes(ChannelBuffer c) {
c.writeInt(this.groupNumber);
}
public static OFGroup read4Bytes(ChannelBuffer c) throws OFParseError {
return OFGroup.of(c.readInt());
}
@Override
public OFGroup applyMask(OFGroup mask) {
return OFGroup.of(this.groupNumber & mask.groupNumber);
}
@Override
public int compareTo(OFGroup o) {
return UnsignedInts.compare(this.groupNumber, o.groupNumber);
}
@Override
public void putTo(PrimitiveSink sink) {
sink.putInt(groupNumber);
}
}
package org.projectfloodlight.openflow.types;
public interface OFHelloElement {
}
package org.projectfloodlight.openflow.types;
import org.jboss.netty.buffer.ChannelBuffer;
import com.google.common.hash.PrimitiveSink;
public class OFMetadata implements OFValueType<OFMetadata> {
static int LENGTH = 8;
private final U64 u64;
public static final OFMetadata NONE = OFMetadata.of(U64.ZERO);
public static final OFMetadata NO_MASK = OFMetadata.of(U64.ofRaw(0xFFFFFFFFFFFFFFFFl));
public static final OFMetadata FULL_MASK = OFMetadata.of(U64.ofRaw(0x0));
public OFMetadata(U64 ofRaw) {
u64 = ofRaw;
}
public static OFMetadata of(U64 u64) {
return new OFMetadata(u64);
}
public static OFMetadata ofRaw(long raw) {
return new OFMetadata(U64.ofRaw(raw));
}
public U64 getValue() {
return u64;
}
public static OFMetadata read8Bytes(ChannelBuffer cb) {
return OFMetadata.ofRaw(cb.readLong());
}
public void write8Bytes(ChannelBuffer cb) {
u64.writeTo(cb);
}
@Override
public int getLength() {
return u64.getLength();
}
@Override
public OFMetadata applyMask(OFMetadata mask) {
return OFMetadata.of(this.u64.applyMask(mask.u64));
}
@Override
public boolean equals(Object arg0) {
if (!(arg0 instanceof OFMetadata))
return false;
OFMetadata other = (OFMetadata)arg0;
return this.u64.equals(other.u64);
}
@Override
public int hashCode() {
int prime = 53;
return this.u64.hashCode() * prime;
}
@Override
public String toString() {
return "Metadata: " + u64.toString();
}
@Override
public int compareTo(OFMetadata o) {
return u64.compareTo(o.u64);
}
@Override
public void putTo(PrimitiveSink sink) {
u64.putTo(sink);
}
}
package org.projectfloodlight.openflow.types;
import org.jboss.netty.buffer.ChannelBuffer;
import org.projectfloodlight.openflow.annotations.Immutable;
import org.projectfloodlight.openflow.exceptions.OFParseError;
import com.google.common.hash.PrimitiveSink;
import com.google.common.primitives.UnsignedInts;
/**
* Abstraction of an logical / OpenFlow switch port (ofp_port_no) in OpenFlow.
* Immutable. Note: Switch port numbers were changed in OpenFlow 1.1 from uint16
* to uint32. This class uses a 32 bit representation internally. Port numbers
* are converted from/to uint16 when constructed / getPortNumberasShort is
* called. If this port is not representable in OpenFlow 1.0, an
* IllegalStateException is raised.
*
* @author Andreas Wundsam <andreas.wundsam@bigswitch.com>
*/
@Immutable
public class OFPort implements OFValueType<OFPort> {
static final int LENGTH = 4;
// private int constants (OF1.1+) to avoid duplication in the code
// should not have to use these outside this class
private static final int OFPP_ANY_INT = 0xFFffFFff;
private static final int OFPP_LOCAL_INT = 0xFFffFFfe;
private static final int OFPP_CONTROLLER_INT = 0xFFffFFfd;
private static final int OFPP_ALL_INT = 0xFFffFFfc;
private static final int OFPP_FLOOD_INT = 0xFFffFFfb;
private static final int OFPP_NORMAL_INT = 0xFFffFFfa;
private static final int OFPP_TABLE_INT = 0xFFffFFf9;
private static final int OFPP_MAX_INT = 0xFFffFF00;
private static final int OFPP_IN_PORT_INT = 0xFFffFFf8;
// private short constants (OF1.0) to avoid duplication in the code
// should not have to use these outside this class
private static final short OFPP_ANY_SHORT = (short) 0xFFff;
private static final short OFPP_LOCAL_SHORT = (short) 0xFFfe;
private static final short OFPP_CONTROLLER_SHORT = (short) 0xFFfd;
private static final short OFPP_ALL_SHORT = (short) 0xFFfc;
private static final short OFPP_FLOOD_SHORT = (short) 0xFFfb;
private static final short OFPP_NORMAL_SHORT = (short) 0xFFfa;
private static final short OFPP_TABLE_SHORT = (short) 0xFFf9;
private static final short OFPP_IN_PORT_SHORT = (short) 0xFFf8;
private static final short OFPP_MAX_SHORT = (short) 0xFF00;
private static final int OFPP_MAX_SHORT_UNSIGNED = 0xFF00;
// ////////////// public constants - use to access well known OpenFlow ports
/** Maximum number of physical and logical switch ports. */
public final static OFPort MAX = new NamedPort(OFPP_MAX_INT, "max");
/**
* Send the packet out the input port. This reserved port must be explicitly
* used in order to send back out of the input port.
*/
public final static OFPort IN_PORT = new NamedPort(OFPP_IN_PORT_INT, "in_port");
/**
* Submit the packet to the first flow table NB: This destination port can
* only be used in packet-out messages.
*/
public final static OFPort TABLE = new NamedPort(OFPP_TABLE_INT, "table");
/** Process with normal L2/L3 switching. */
public final static OFPort NORMAL = new NamedPort(OFPP_NORMAL_INT, "normal");
/**
* All physical ports in VLAN, except input port and those blocked or link
* down
*/
public final static OFPort FLOOD = new NamedPort(OFPP_FLOOD_INT, "flood");
/** All physical ports except input port */
public final static OFPort ALL = new NamedPort(OFPP_ALL_INT, "all");
/** Send to controller */
public final static OFPort CONTROLLER =
new NamedPort(OFPP_CONTROLLER_INT, "controller");
/** local openflow "port" */
public final static OFPort LOCAL = new NamedPort(OFPP_LOCAL_INT, "local");
/**
* Wildcard port used only for flow mod (delete) and flow stats requests.
* Selects all flows regardless of output port (including flows with no
* output port). NOTE: OpenFlow 1.0 calls this 'NONE'
*/
public final static OFPort ANY = new NamedPort(OFPP_ANY_INT, "any");
/** the wildcarded default for OpenFlow 1.0 (value: 0). Elsewhere in OpenFlow
* we need "ANY" as the default
*/
public static final OFPort ZERO = OFPort.of(0);
public static final OFPort NO_MASK = OFPort.of(0xFFFFFFFF);
public static final OFPort FULL_MASK = ZERO;
/** cache of frequently used ports */
private static class PrecachedPort {
private final static OFPort p0 = new OFPort(0);
private final static OFPort p1 = new OFPort(1);
private final static OFPort p2 = new OFPort(2);
private final static OFPort p3 = new OFPort(3);
private final static OFPort p4 = new OFPort(4);
private final static OFPort p5 = new OFPort(5);
private final static OFPort p6 = new OFPort(6);
private final static OFPort p7 = new OFPort(7);
private final static OFPort p8 = new OFPort(8);
private final static OFPort p9 = new OFPort(9);
private final static OFPort p10 = new OFPort(10);
private final static OFPort p11 = new OFPort(11);
private final static OFPort p12 = new OFPort(12);
private final static OFPort p13 = new OFPort(13);
private final static OFPort p14 = new OFPort(14);
private final static OFPort p15 = new OFPort(15);
private final static OFPort p16 = new OFPort(16);
private final static OFPort p17 = new OFPort(17);
private final static OFPort p18 = new OFPort(18);
private final static OFPort p19 = new OFPort(19);
private final static OFPort p20 = new OFPort(20);
private final static OFPort p21 = new OFPort(21);
private final static OFPort p22 = new OFPort(22);
private final static OFPort p23 = new OFPort(23);
private final static OFPort p24 = new OFPort(24);
private final static OFPort p25 = new OFPort(25);
private final static OFPort p26 = new OFPort(26);
private final static OFPort p27 = new OFPort(27);
private final static OFPort p28 = new OFPort(28);
private final static OFPort p29 = new OFPort(29);
private final static OFPort p31 = new OFPort(31);
private final static OFPort p32 = new OFPort(32);
private final static OFPort p33 = new OFPort(33);
private final static OFPort p34 = new OFPort(34);
private final static OFPort p35 = new OFPort(35);
private final static OFPort p36 = new OFPort(36);
private final static OFPort p37 = new OFPort(37);
private final static OFPort p38 = new OFPort(38);
private final static OFPort p39 = new OFPort(39);
private final static OFPort p40 = new OFPort(40);
private final static OFPort p41 = new OFPort(41);
private final static OFPort p42 = new OFPort(42);
private final static OFPort p43 = new OFPort(43);
private final static OFPort p44 = new OFPort(44);
private final static OFPort p45 = new OFPort(45);
private final static OFPort p46 = new OFPort(46);
private final static OFPort p47 = new OFPort(47);
private final static OFPort p48 = new OFPort(48);
}
/** raw openflow port number as a signed 32 bit integer */
private final int portNumber;
/** private constructor. use of*-Factory methods instead */
private OFPort(final int portNumber) {
this.portNumber = portNumber;
}
/**
* get an OFPort object corresponding to a raw 32-bit integer port number.
* NOTE: The port object may either be newly allocated or cached. Do not
* rely on either behavior.
*
* @param portNumber
* @return a corresponding OFPort
*/
public static OFPort ofInt(final int portNumber) {
switch (portNumber) {
case 0:
return PrecachedPort.p0;
case 1:
return PrecachedPort.p1;
case 2:
return PrecachedPort.p2;
case 3:
return PrecachedPort.p3;
case 4:
return PrecachedPort.p4;
case 5:
return PrecachedPort.p5;
case 6:
return PrecachedPort.p6;
case 7:
return PrecachedPort.p7;
case 8:
return PrecachedPort.p8;
case 9:
return PrecachedPort.p9;
case 10:
return PrecachedPort.p10;
case 11:
return PrecachedPort.p11;
case 12:
return PrecachedPort.p12;
case 13:
return PrecachedPort.p13;
case 14:
return PrecachedPort.p14;
case 15:
return PrecachedPort.p15;
case 16:
return PrecachedPort.p16;
case 17:
return PrecachedPort.p17;
case 18:
return PrecachedPort.p18;
case 19:
return PrecachedPort.p19;
case 20:
return PrecachedPort.p20;
case 21:
return PrecachedPort.p21;
case 22:
return PrecachedPort.p22;
case 23:
return PrecachedPort.p23;
case 24:
return PrecachedPort.p24;
case 25:
return PrecachedPort.p25;
case 26:
return PrecachedPort.p26;
case 27:
return PrecachedPort.p27;
case 28:
return PrecachedPort.p28;
case 29:
return PrecachedPort.p29;
case 31:
return PrecachedPort.p31;
case 32:
return PrecachedPort.p32;
case 33:
return PrecachedPort.p33;
case 34:
return PrecachedPort.p34;
case 35:
return PrecachedPort.p35;
case 36:
return PrecachedPort.p36;
case 37:
return PrecachedPort.p37;
case 38:
return PrecachedPort.p38;
case 39:
return PrecachedPort.p39;
case 40:
return PrecachedPort.p40;
case 41:
return PrecachedPort.p41;
case 42:
return PrecachedPort.p42;
case 43:
return PrecachedPort.p43;
case 44:
return PrecachedPort.p44;
case 45:
return PrecachedPort.p45;
case 46:
return PrecachedPort.p46;
case 47:
return PrecachedPort.p47;
case 48:
return PrecachedPort.p48;
case OFPP_MAX_INT:
return MAX;
case OFPP_IN_PORT_INT:
return IN_PORT;
case OFPP_TABLE_INT:
return TABLE;
case OFPP_NORMAL_INT:
return NORMAL;
case OFPP_FLOOD_INT:
return FLOOD;
case OFPP_ALL_INT:
return ALL;
case OFPP_CONTROLLER_INT:
return CONTROLLER;
case OFPP_LOCAL_INT:
return LOCAL;
case OFPP_ANY_INT:
return ANY;
default:
// note: This means effectively : portNumber > OFPP_MAX_SHORT
// accounting for
// signedness of both portNumber and OFPP_MAX_INT(which is
// -256).
// Any unsigned integer value > OFPP_MAX_INT will be ]-256:0[
// when read signed
if (portNumber < 0 && portNumber > OFPP_MAX_INT)
throw new IllegalArgumentException("Unknown special port number: "
+ portNumber);
return new OFPort(portNumber);
}
}
/** convenience function: delegates to ofInt */
public static OFPort of(final int portNumber) {
return ofInt(portNumber);
}
/**
* get an OFPort object corresponding to a raw signed 16-bit integer port
* number (OF1.0). Note that the port returned will have the corresponding
* 32-bit integer value allocated as its port number. NOTE: The port object
* may either be newly allocated or cached. Do not rely on either behavior.
*
* @param portNumber
* @return a corresponding OFPort
*/
public static OFPort ofShort(final short portNumber) {
switch (portNumber) {
case 0:
return PrecachedPort.p0;
case 1:
return PrecachedPort.p1;
case 2:
return PrecachedPort.p2;
case 3:
return PrecachedPort.p3;
case 4:
return PrecachedPort.p4;
case 5:
return PrecachedPort.p5;
case 6:
return PrecachedPort.p6;
case 7:
return PrecachedPort.p7;
case 8:
return PrecachedPort.p8;
case 9:
return PrecachedPort.p9;
case 10:
return PrecachedPort.p10;
case 11:
return PrecachedPort.p11;
case 12:
return PrecachedPort.p12;
case 13:
return PrecachedPort.p13;
case 14:
return PrecachedPort.p14;
case 15:
return PrecachedPort.p15;
case 16:
return PrecachedPort.p16;
case 17:
return PrecachedPort.p17;
case 18:
return PrecachedPort.p18;
case 19:
return PrecachedPort.p19;
case 20:
return PrecachedPort.p20;
case 21:
return PrecachedPort.p21;
case 22:
return PrecachedPort.p22;
case 23:
return PrecachedPort.p23;
case 24:
return PrecachedPort.p24;
case 25:
return PrecachedPort.p25;
case 26:
return PrecachedPort.p26;
case 27:
return PrecachedPort.p27;
case 28:
return PrecachedPort.p28;
case 29:
return PrecachedPort.p29;
case 31:
return PrecachedPort.p31;
case 32:
return PrecachedPort.p32;
case 33:
return PrecachedPort.p33;
case 34:
return PrecachedPort.p34;
case 35:
return PrecachedPort.p35;
case 36:
return PrecachedPort.p36;
case 37:
return PrecachedPort.p37;
case 38:
return PrecachedPort.p38;
case 39:
return PrecachedPort.p39;
case 40:
return PrecachedPort.p40;
case 41:
return PrecachedPort.p41;
case 42:
return PrecachedPort.p42;
case 43:
return PrecachedPort.p43;
case 44:
return PrecachedPort.p44;
case 45:
return PrecachedPort.p45;
case 46:
return PrecachedPort.p46;
case 47:
return PrecachedPort.p47;
case 48:
return PrecachedPort.p48;
case OFPP_MAX_SHORT:
return MAX;
case OFPP_IN_PORT_SHORT:
return IN_PORT;
case OFPP_TABLE_SHORT:
return TABLE;
case OFPP_NORMAL_SHORT:
return NORMAL;
case OFPP_FLOOD_SHORT:
return FLOOD;
case OFPP_ALL_SHORT:
return ALL;
case OFPP_CONTROLLER_SHORT:
return CONTROLLER;
case OFPP_LOCAL_SHORT:
return LOCAL;
case OFPP_ANY_SHORT:
return ANY;
default:
// note: This means effectively : portNumber > OFPP_MAX_SHORT
// accounting for
// signedness of both portNumber and OFPP_MAX_SHORT (which is
// -256).
// Any unsigned integer value > OFPP_MAX_SHORT will be ]-256:0[
// when read signed
if (portNumber < 0 && portNumber > OFPP_MAX_SHORT)
throw new IllegalArgumentException("Unknown special port number: "
+ portNumber);
return new OFPort(portNumber);
}
}
/** return the port number as a int32 */
public int getPortNumber() {
return portNumber;
}
/**
* return the port number as int16. Special ports as defined by the OpenFlow
* spec will be converted to their OpenFlow 1.0 equivalent. port numbers >=
* FF00 will cause a IllegalArgumentException to be thrown
*
* @throws IllegalArgumentException
* if a regular port number exceeds the maximum value in OF1.0
**/
public short getShortPortNumber() {
switch (portNumber) {
case OFPP_MAX_INT:
return OFPP_MAX_SHORT;
case OFPP_IN_PORT_INT:
return OFPP_IN_PORT_SHORT;
case OFPP_TABLE_INT:
return OFPP_TABLE_SHORT;
case OFPP_NORMAL_INT:
return OFPP_NORMAL_SHORT;
case OFPP_FLOOD_INT:
return OFPP_FLOOD_SHORT;
case OFPP_ALL_INT:
return OFPP_ALL_SHORT;
case OFPP_CONTROLLER_INT:
return OFPP_CONTROLLER_SHORT;
case OFPP_LOCAL_INT:
return OFPP_LOCAL_SHORT;
case OFPP_ANY_INT:
return OFPP_ANY_SHORT;
default:
if (portNumber >= OFPP_MAX_SHORT_UNSIGNED || portNumber < 0)
throw new IllegalArgumentException("32bit Port number "
+ U32.f(portNumber)
+ " cannot be represented as uint16 (OF1.0)");
return (short) portNumber;
}
}
@Override
public String toString() {
return Long.toString(U32.f(portNumber));
}
/** Extension of OFPort for named ports */
static class NamedPort extends OFPort {
private final String name;
NamedPort(final int portNo, final String name) {
super(portNo);
this.name = name;
}
public String getName() {
return name;
}
@Override
public String toString() {
return name;
}
}
@Override
public int getLength() {
return LENGTH;
}
@Override
public boolean equals(Object obj) {
if (!(obj instanceof OFPort))
return false;
OFPort other = (OFPort)obj;
if (other.portNumber != this.portNumber)
return false;
return true;
}
@Override
public int hashCode() {
final int prime = 53;
int result = 1;
result = prime * result + portNumber;
return result;
}
public void write2Bytes(ChannelBuffer c) {
c.writeShort(this.portNumber);
}
public static OFPort read2Bytes(ChannelBuffer c) throws OFParseError {
return OFPort.ofShort(c.readShort());
}
public void write4Bytes(ChannelBuffer c) {
c.writeInt(this.portNumber);
}
public static OFPort read4Bytes(ChannelBuffer c) throws OFParseError {
return OFPort.of((int)(c.readUnsignedInt() & 0xFFFFFFFF));
}
@Override
public OFPort applyMask(OFPort mask) {
return OFPort.of(this.portNumber & mask.portNumber);
}
@Override
public int compareTo(OFPort o) {
return UnsignedInts.compare(this.portNumber, o.portNumber);
}
@Override
public void putTo(PrimitiveSink sink) {
sink.putInt(portNumber);
}
}
package org.projectfloodlight.openflow.types;
import java.util.ArrayList;
import javax.annotation.concurrent.Immutable;
/** User-facing object representing a bitmap of ports that can be matched on.
* This is implemented by the custom BSN OXM type of_oxm_bsn_in_ports_182.
*
* You can call set() on the builder for all the Ports you want to match on
* and unset to exclude the port.
*
* <b>Implementation note:</b> to comply with the matching semantics of OXM (which is a logical "AND" not "OR")
* the underlying match uses a data format which is very unintuitive. The value is always
* 0, and the mask has the bits set for the ports that should <b>NOT</b> be included in the
* range.
*
* For the curious: We transformed the bitmap (a logical OR) problem into a logical
* AND NOT problem.
*
* We logically mean: Inport is 1 OR 3
* We technically say: Inport IS NOT 2 AND IS NOT 4 AND IS NOT 5 AND IS NOT ....
* The second term cannot be represented in OXM, the second can.
*
* That said, all that craziness is hidden from the user of this object.
*
* <h2>Usage</h2>
* OFPortBitmap is meant to be used with MatchField <tt>BSN_IN_PORTS_128</tt> in place
* of the raw type Masked&lt;OFBitMask128&gt;.
*
* <h3>Example:</h3>:
* <pre>
* OFPortBitMap portBitMap;
* Match.Builder matchBuilder;
* // initialize
* matchBuilder.setMasked(MatchField.BSN_IN_PORTS_128, portBitmap);
* </pre>
*
* @author Andreas Wundsam <andreas.wundsam@bigswitch.com>
*/
@Immutable
public class OFPortBitMap extends Masked<OFBitMask128> {
private OFPortBitMap(OFBitMask128 mask) {
super(OFBitMask128.NONE, mask);
}
/** @return whether or not the given port is logically included in the
* match, i.e., whether a packet from in-port <emph>port</emph> be matched by
* this OXM.
*/
public boolean isOn(OFPort port) {
// see the implementation note above about the logical inversion of the mask
return !(this.mask.isOn(port.getPortNumber()));
}
public static OFPortBitMap ofPorts(OFPort... ports) {
Builder builder = new Builder();
for (OFPort port: ports) {
builder.set(port);
}
return builder.build();
}
/** @return an OFPortBitmap based on the 'mask' part of an OFBitMask128, as, e.g., returned
* by the switch.
**/
public static OFPortBitMap of(OFBitMask128 mask) {
return new OFPortBitMap(mask);
}
/** @return iterating over all ports that are logically included in the
* match, i.e., whether a packet from in-port <emph>port</emph> be matched by
* this OXM.
*/
public Iterable<OFPort> getOnPorts() {
ArrayList<OFPort> ports = new ArrayList<>();
for(int i=0; i < 127; i++) {
if(!(this.mask.isOn(i))) {
ports.add(OFPort.of(i));
}
}
return ports;
}
@Override
public boolean equals(Object obj) {
if (!(obj instanceof OFPortBitMap))
return false;
OFPortBitMap other = (OFPortBitMap)obj;
return (other.value.equals(this.value) && other.mask.equals(this.mask));
}
@Override
public int hashCode() {
return 619 * mask.hashCode() + 257 * value.hashCode();
}
public static class Builder {
private long raw1 = -1, raw2 = -1;
public Builder() {
}
/** @return whether or not the given port is logically included in the
* match, i.e., whether a packet from in-port <emph>port</emph> be matched by
* this OXM.
*/
public boolean isOn(OFPort port) {
// see the implementation note above about the logical inversion of the mask
return !(OFBitMask128.isBitOn(raw1, raw2, port.getPortNumber()));
}
/** remove this port from the match, i.e., packets from this in-port
* will NOT be matched.
*/
public Builder unset(OFPort port) {
// see the implementation note above about the logical inversion of the mask
int bit = port.getPortNumber();
if (bit < 0 || bit > 127)
throw new IndexOutOfBoundsException("Port number is out of bounds");
else if (bit == 127)
// the highest order bit in the bitmask is reserved. The switch will
// set that bit for all ports >= 127. The reason is that we don't want
// the OFPortMap to match all ports out of its range (i.e., a packet
// coming in on port 181 would match *any* OFPortMap).
throw new IndexOutOfBoundsException("The highest order bit in the bitmask is reserved.");
else if (bit < 64) {
raw2 |= ((long)1 << bit);
} else {
raw1 |= ((long)1 << (bit - 64));
}
return this;
}
/** add this port from the match, i.e., packets from this in-port
* will NOT be matched.
*/
public Builder set(OFPort port) {
// see the implementation note above about the logical inversion of the mask
int bit = port.getPortNumber();
if (bit < 0 || bit > 127)
throw new IndexOutOfBoundsException("Port number is out of bounds");
else if (bit == 127)
// the highest order bit in the bitmask is reserved. The switch will
// set that bit for all ports >= 127. The reason is that we don't want
// the OFPortMap to match all ports out of its range (i.e., a packet
// coming in on port 181 would match *any* OFPortMap).
throw new IndexOutOfBoundsException("The highest order bit in the bitmask is reserved.");
else if (bit < 64) {
raw2 &= ~((long)1 << bit);
} else {
raw1 &= ~((long)1 << (bit - 64));
}
return this;
}
public OFPortBitMap build() {
return new OFPortBitMap(OFBitMask128.of(raw1, raw2));
}
}
}
package org.projectfloodlight.openflow.types;
public interface OFValueType<T extends OFValueType<T>> extends Comparable<T>, PrimitiveSinkable {
public int getLength();
public T applyMask(T mask);
}
package org.projectfloodlight.openflow.types;
import java.util.Arrays;
import javax.annotation.Nullable;
import org.jboss.netty.buffer.ChannelBuffer;
import org.projectfloodlight.openflow.exceptions.OFParseError;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.common.hash.PrimitiveSink;
import com.google.common.primitives.Shorts;
/** Represents an OpenFlow Vlan VID for use in Matches, as specified by the OpenFlow 1.3 spec.
*
* <b> Note: this is not just the 12-bit vlan tag. OpenFlow defines
* the additional mask bits 0x1000 to represent the presence of a vlan
* tag. This additional bit will be stripped when writing a OF1.0 value
* tag.
* </b>
*
*
* @author Andreas Wundsam <andreas.wundsam@bigswitch.com>
*
*/
public class OFVlanVidMatch implements OFValueType<OFVlanVidMatch> {
private static final Logger logger = LoggerFactory.getLogger(OFVlanVidMatch.class);
private static final short VALIDATION_MASK = 0x1FFF;
private static final short PRESENT_VAL = 0x1000;
private static final short VLAN_MASK = 0x0FFF;
private static final short NONE_VAL = 0x0000;
private static final short UNTAGGED_VAL_OF13 = (short) 0x0000;
private static final short UNTAGGED_VAL_OF10 = (short) 0xFFFF;
final static int LENGTH = 2;
/** presence of a VLAN tag is indicated by the presence of bit 0x1000 */
public static final OFVlanVidMatch PRESENT = new OFVlanVidMatch(PRESENT_VAL);
/** this value means 'not set' in OF1.0 (e.g., in a match). not used elsewhere */
public static final OFVlanVidMatch NONE = new OFVlanVidMatch(NONE_VAL);
/** for use with masking operations */
public static final OFVlanVidMatch NO_MASK = new OFVlanVidMatch((short)0xFFFF);
public static final OFVlanVidMatch FULL_MASK = NONE;
/** an untagged packet is specified as 0000 in OF 1.0, but 0xFFFF in OF1.0. Special case that. */
public static final OFVlanVidMatch UNTAGGED = new OFVlanVidMatch(NONE_VAL) {
@Override
public void write2BytesOF10(ChannelBuffer c) {
c.writeShort(UNTAGGED_VAL_OF10);
}
};
private final short vid;
private OFVlanVidMatch(short vid) {
this.vid = vid;
}
public static OFVlanVidMatch ofRawVid(short vid) {
if(vid == UNTAGGED_VAL_OF13)
return UNTAGGED;
else if(vid == PRESENT_VAL)
return PRESENT;
else if(vid == UNTAGGED_VAL_OF10) {
// workaround for IVS sometimes sending 0F1.0 untagged (0xFFFF) values
logger.warn("Warning: received OF1.0 untagged vlan value (0xFFFF) in OF1.3 VlanVid. Treating as UNTAGGED");
return UNTAGGED;
} else if ((vid & VALIDATION_MASK) != vid)
throw new IllegalArgumentException(String.format("Illegal VLAN value: %x", vid));
return new OFVlanVidMatch(vid);
}
public static OFVlanVidMatch ofVlanVid(VlanVid vid) {
if(vid == null)
return UNTAGGED;
else if(VlanVid.NO_MASK.equals(vid))
// NO_MASK is a special value in that it doesn't fit in the
// allowed value space (0x1FFF) of this type. Do a manual conversion
return NO_MASK;
else
return ofVlan(vid.getVlan());
}
public static OFVlanVidMatch ofVlan(int vlan) {
if( (vlan & VLAN_MASK) != vlan)
throw new IllegalArgumentException(String.format("Illegal VLAN value: %x", vlan));
return ofRawVid( (short) (vlan | PRESENT_VAL));
}
public static OFVlanVidMatch ofVlanOF10(short of10vlan) {
if(of10vlan == NONE_VAL) {
return NONE;
} else if(of10vlan == UNTAGGED_VAL_OF10) {
return UNTAGGED;
} else {
return ofVlan(of10vlan);
}
}
/** @return whether or not this VlanId has the present (0x1000) bit set */
public boolean isPresentBitSet() {
return (vid & PRESENT_VAL) != 0;
}
/** @return the actual VLAN tag this vid identifies */
public short getVlan() {
return (short) (vid & VLAN_MASK);
}
/** @return the actual vlan tag this vid identifies as a VlanVid object, if this
* VlanVidMatch has the present bit set (i.e., identifies a tagged VLAN).
* Else, returns null.
*/
@Nullable
public VlanVid getVlanVid() {
if(this.equals(NO_MASK))
return VlanVid.NO_MASK;
else if(isPresentBitSet())
return VlanVid.ofVlan((short) (vid & VLAN_MASK));
else
return null;
}
@Override
public boolean equals(Object obj) {
if (!(obj instanceof OFVlanVidMatch))
return false;
OFVlanVidMatch other = (OFVlanVidMatch)obj;
if (other.vid != this.vid)
return false;
return true;
}
@Override
public int hashCode() {
int prime = 13873;
return this.vid * prime;
}
@Override
public String toString() {
return "0x" + Integer.toHexString(vid);
}
public short getRawVid() {
return vid;
}
@Override
public int getLength() {
return LENGTH;
}
private volatile byte[] bytesCache = null;
public byte[] getBytes() {
if (bytesCache == null) {
synchronized (this) {
if (bytesCache == null) {
bytesCache =
new byte[] { (byte) ((vid >>> 8) & 0xFF),
(byte) ((vid >>> 0) & 0xFF) };
}
}
}
return Arrays.copyOf(bytesCache, bytesCache.length);
}
public void write2Bytes(ChannelBuffer c) {
c.writeShort(this.vid);
}
public void write2BytesOF10(ChannelBuffer c) {
c.writeShort(this.getVlan());
}
public static OFVlanVidMatch read2Bytes(ChannelBuffer c) throws OFParseError {
return OFVlanVidMatch.ofRawVid(c.readShort());
}
public static OFVlanVidMatch read2BytesOF10(ChannelBuffer c) throws OFParseError {
return OFVlanVidMatch.ofVlanOF10(c.readShort());
}
@Override
public OFVlanVidMatch applyMask(OFVlanVidMatch mask) {
return OFVlanVidMatch.ofRawVid((short)(this.vid & mask.vid));
}
@Override
public int compareTo(OFVlanVidMatch o) {
return Shorts.compare(vid, o.vid);
}
@Override
public void putTo(PrimitiveSink sink) {
sink.putShort(vid);
}
}
package org.projectfloodlight.openflow.types;
public class OFVlanVidMatchWithMask extends Masked<OFVlanVidMatch> {
private OFVlanVidMatchWithMask(OFVlanVidMatch value, OFVlanVidMatch mask) {
super(value, mask);
}
/* a combination of Vlan Vid and mask that matches any tagged packet */
public final static OFVlanVidMatchWithMask ANY_TAGGED = new OFVlanVidMatchWithMask(OFVlanVidMatch.PRESENT, OFVlanVidMatch.PRESENT);
}
package org.projectfloodlight.openflow.types;
/**
* Represents the speed of a port
*/
public enum PortSpeed {
/** no speed set */
SPEED_NONE(0),
SPEED_10MB(10),
SPEED_100MB(100),
SPEED_1GB(1_000),
SPEED_10GB(10_000),
SPEED_40GB(40_000),
SPEED_100GB(100_000),
SPEED_1TB(1_000_000);
private long speedInBps;
private PortSpeed(int speedInMbps) {
this.speedInBps = speedInMbps * 1000L*1000L;
}
public long getSpeedBps() {
return this.speedInBps;
}
public static PortSpeed max(PortSpeed s1, PortSpeed s2) {
return (s1.getSpeedBps() > s2.getSpeedBps()) ? s1 : s2;
}
public static PortSpeed min(PortSpeed s1, PortSpeed s2) {
return (s1.getSpeedBps() < s2.getSpeedBps()) ? s1 : s2;
}
}
package org.projectfloodlight.openflow.types;
import com.google.common.hash.PrimitiveSink;
public interface PrimitiveSinkable {
public void putTo(PrimitiveSink sink);
}
package org.projectfloodlight.openflow.types;
import org.jboss.netty.buffer.ChannelBuffer;
import org.projectfloodlight.openflow.exceptions.OFParseError;
import com.google.common.hash.PrimitiveSink;
import com.google.common.primitives.Shorts;
public class TableId implements OFValueType<TableId>, Comparable<TableId> {
final static int LENGTH = 1;
private static final short VALIDATION_MASK = 0x00FF;
private static final short ALL_VAL = 0x00FF;
private static final short NONE_VAL = 0x0000;
public static final TableId NONE = new TableId(NONE_VAL);
public static final TableId ALL = new TableId(ALL_VAL);
public static final TableId ZERO = NONE;
private final short id;
private TableId(short id) {
this.id = id;
}
public static TableId of(short id) {
switch(id) {
case NONE_VAL:
return NONE;
case ALL_VAL:
return ALL;
default:
if ((id & VALIDATION_MASK) != id)
throw new IllegalArgumentException("Illegal Table id value: " + id);
return new TableId(id);
}
}
public static TableId of(int id) {
if((id & VALIDATION_MASK) != id)
throw new IllegalArgumentException("Illegal Table id value: "+id);
return of((short) id);
}
@Override
public String toString() {
return "0x" + Integer.toHexString(id);
}
public short getValue() {
return id;
}
@Override
public int getLength() {
return LENGTH;
}
public void writeByte(ChannelBuffer c) {
c.writeByte(this.id);
}
public static TableId readByte(ChannelBuffer c) throws OFParseError {
return TableId.of(c.readUnsignedByte());
}
@Override
public TableId applyMask(TableId mask) {
return TableId.of((short)(this.id & mask.id));
}
@Override
public boolean equals(Object obj) {
if (!(obj instanceof TableId))
return false;
TableId other = (TableId)obj;
if (other.id != this.id)
return false;
return true;
}
@Override
public int hashCode() {
int prime = 13873;
return this.id * prime;
}
@Override
public int compareTo(TableId other) {
return Shorts.compare(this.id, other.id);
}
@Override
public void putTo(PrimitiveSink sink) {
sink.putByte((byte) id);
}
}
package org.projectfloodlight.openflow.types;
import org.jboss.netty.buffer.ChannelBuffer;
import org.projectfloodlight.openflow.exceptions.OFParseError;
import com.google.common.hash.PrimitiveSink;
import com.google.common.primitives.Ints;
/**
* Represents L4 (Transport Layer) port (TCP, UDP, etc.)
*
* @author Yotam Harchol (yotam.harchol@bigswitch.com)
*/
public class TransportPort implements OFValueType<TransportPort> {
static final int LENGTH = 2;
static final int MAX_PORT = 0xFFFF;
static final int MIN_PORT = 0;
private final static int NONE_VAL = 0;
public final static TransportPort NONE = new TransportPort(NONE_VAL);
public static final TransportPort NO_MASK = new TransportPort(0xFFFFFFFF);
public static final TransportPort FULL_MASK = TransportPort.of(0x0);
private final int port;
private TransportPort(int port) {
this.port = port;
}
public static TransportPort of(int port) {
if(port == NONE_VAL)
return NONE;
else if (port == NO_MASK.port)
return NO_MASK;
else if (port < MIN_PORT || port > MAX_PORT) {
throw new IllegalArgumentException("Illegal transport layer port number: " + port);
}
return new TransportPort(port);
}
@Override
public int getLength() {
return LENGTH;
}
public int getPort() {
return port;
}
@Override
public boolean equals(Object obj) {
if (!(obj instanceof TransportPort))
return false;
TransportPort other = (TransportPort)obj;
if (other.port != this.port)
return false;
return true;
}
@Override
public int hashCode() {
final int prime = 59;
int result = 1;
result = prime * result + port;
return result;
}
@Override
public String toString() {
return Integer.toString(port);
}
public void write2Bytes(ChannelBuffer c) {
c.writeShort(this.port);
}
public static TransportPort read2Bytes(ChannelBuffer c) throws OFParseError {
return TransportPort.of((c.readUnsignedShort() & 0x0FFFF));
}
@Override
public TransportPort applyMask(TransportPort mask) {
return TransportPort.of(this.port & mask.port);
}
@Override
public int compareTo(TransportPort o) {
return Ints.compare(port, o.port);
}
@Override
public void putTo(PrimitiveSink sink) {
sink.putShort((short) port);
}
}
package org.projectfloodlight.openflow.types;
import javax.annotation.Nonnull;
import org.jboss.netty.buffer.ChannelBuffer;
import com.google.common.hash.PrimitiveSink;
import com.google.common.primitives.UnsignedLongs;
public class U128 implements OFValueType<U128>, HashValue<U128> {
static final int LENGTH = 16;
private final long raw1; // MSBs
private final long raw2; // LSBs
public static final U128 ZERO = new U128(0, 0);
private U128(long raw1, long raw2) {
this.raw1 = raw1;
this.raw2 = raw2;
}
public static U128 of(long raw1, long raw2) {
if (raw1 == 0 && raw2 == 0)
return ZERO;
return new U128(raw1, raw2);
}
@Override
public int getLength() {
return LENGTH;
}
public long getMsb() {
return raw1;
}
public long getLsb() {
return raw2;
}
@Override
public U128 applyMask(U128 mask) {
return and(mask);
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + (int) (raw1 ^ (raw1 >>> 32));
result = prime * result + (int) (raw2 ^ (raw2 >>> 32));
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
U128 other = (U128) obj;
if (raw1 != other.raw1)
return false;
if (raw2 != other.raw2)
return false;
return true;
}
public void write16Bytes(ChannelBuffer cb) {
cb.writeLong(raw1);
cb.writeLong(raw2);
}
public static U128 read16Bytes(ChannelBuffer cb) {
long raw1 = cb.readLong();
long raw2 = cb.readLong();
return of(raw1, raw2);
}
@Override
public String toString() {
return String.format("0x%016x%016x", raw1, raw2);
}
@Override
public int compareTo(@Nonnull U128 o) {
int msb = UnsignedLongs.compare(this.raw1, o.raw1);
if(msb != 0)
return msb;
else
return UnsignedLongs.compare(this.raw2, o.raw2);
}
@Override
public void putTo(PrimitiveSink sink) {
sink.putLong(raw1);
sink.putLong(raw2);
}
@Override
public U128 inverse() {
return U128.of(~raw1, ~raw2);
}
@Override
public U128 or(U128 other) {
return U128.of(raw1 | other.raw1, raw2 | other.raw2);
}
@Override
public U128 and(U128 other) {
return U128.of(raw1 & other.raw1, raw2 & other.raw2);
}
@Override
public U128 xor(U128 other) {
return U128.of(raw1 ^ other.raw1, raw2 ^ other.raw2);
}
@Override
public int prefixBits(int numBits) {
return HashValueUtils.prefixBits(this.raw1, numBits);
}
@Override
public U128 combineWithValue(U128 value, int keyBits) {
return U128.of(
HashValueUtils.combineWithValue(this.raw1, value.raw1, Math.min(64, keyBits)),
HashValueUtils.combineWithValue(this.raw2, value.raw2, Math.max(0,keyBits-64))
);
}
}
/**
* Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior
* University
*
* 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.projectfloodlight.openflow.types;
import org.jboss.netty.buffer.ChannelBuffer;
import org.projectfloodlight.openflow.exceptions.OFParseError;
import org.projectfloodlight.openflow.protocol.OFMessageReader;
import org.projectfloodlight.openflow.protocol.Writeable;
import com.google.common.hash.PrimitiveSink;
import com.google.common.primitives.Ints;
public class U16 implements Writeable, OFValueType<U16> {
private final static short ZERO_VAL = 0;
public final static U16 ZERO = new U16(ZERO_VAL);
private static final short NO_MASK_VAL = (short)0xFFff;
public final static U16 NO_MASK = new U16(NO_MASK_VAL);
public static final U16 FULL_MASK = ZERO;
public static int f(final short i) {
return i & 0xffff;
}
public static short t(final int l) {
return (short) l;
}
private final short raw;
private U16(short raw) {
this.raw = raw;
}
public static final U16 of(int value) {
return ofRaw(t(value));
}
public static final U16 ofRaw(short raw) {
if(raw == ZERO_VAL)
return ZERO;
return new U16(raw);
}
public int getValue() {
return f(raw);
}
public short getRaw() {
return raw;
}
@Override
public String toString() {
return String.format("0x%04x", raw);
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + raw;
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
U16 other = (U16) obj;
if (raw != other.raw)
return false;
return true;
}
@Override
public void writeTo(ChannelBuffer bb) {
bb.writeShort(raw);
}
public final static Reader READER = new Reader();
private static class Reader implements OFMessageReader<U16> {
@Override
public U16 readFrom(ChannelBuffer bb) throws OFParseError {
return ofRaw(bb.readShort());
}
}
@Override
public int getLength() {
return 2;
}
@Override
public U16 applyMask(U16 mask) {
return ofRaw( (short) (raw & mask.raw));
}
@Override
public int compareTo(U16 o) {
return Ints.compare(f(raw), f(o.raw));
}
@Override
public void putTo(PrimitiveSink sink) {
sink.putShort(raw);
}
}
/**
* Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior
* University
*
* 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.projectfloodlight.openflow.types;
import org.jboss.netty.buffer.ChannelBuffer;
import org.projectfloodlight.openflow.exceptions.OFParseError;
import org.projectfloodlight.openflow.protocol.OFMessageReader;
import org.projectfloodlight.openflow.protocol.Writeable;
import com.google.common.hash.PrimitiveSink;
import com.google.common.primitives.UnsignedInts;
public class U32 implements Writeable, OFValueType<U32> {
private final static int ZERO_VAL = 0;
public final static U32 ZERO = new U32(ZERO_VAL);
private static final int NO_MASK_VAL = 0xFFffFFff;
public final static U32 NO_MASK = new U32(NO_MASK_VAL);
public static final U32 FULL_MASK = ZERO;
private final int raw;
private U32(int raw) {
this.raw = raw;
}
public static U32 of(long value) {
return ofRaw(U32.t(value));
}
public static U32 ofRaw(int raw) {
if(raw == ZERO_VAL)
return ZERO;
if(raw == NO_MASK_VAL)
return NO_MASK;
return new U32(raw);
}
public long getValue() {
return f(raw);
}
public int getRaw() {
return raw;
}
@Override
public String toString() {
return String.format("0x%08x", raw);
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + raw;
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
U32 other = (U32) obj;
if (raw != other.raw)
return false;
return true;
}
public static long f(final int i) {
return i & 0xffffffffL;
}
public static int t(final long l) {
return (int) l;
}
@Override
public void writeTo(ChannelBuffer bb) {
bb.writeInt(raw);
}
public final static Reader READER = new Reader();
private static class Reader implements OFMessageReader<U32> {
@Override
public U32 readFrom(ChannelBuffer bb) throws OFParseError {
return new U32(bb.readInt());
}
}
@Override
public int getLength() {
return 4;
}
@Override
public U32 applyMask(U32 mask) {
return ofRaw(raw & mask.raw);
}
@Override
public int compareTo(U32 o) {
return UnsignedInts.compare(raw, o.raw);
}
@Override
public void putTo(PrimitiveSink sink) {
sink.putInt(raw);
}}
/**
* Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior
* University
*
* 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.projectfloodlight.openflow.types;
import java.math.BigInteger;
import org.jboss.netty.buffer.ChannelBuffer;
import org.projectfloodlight.openflow.exceptions.OFParseError;
import org.projectfloodlight.openflow.protocol.OFMessageReader;
import org.projectfloodlight.openflow.protocol.Writeable;
import com.google.common.hash.PrimitiveSink;
import com.google.common.primitives.UnsignedLongs;
public class U64 implements Writeable, OFValueType<U64>, HashValue<U64> {
private static final long UNSIGNED_MASK = 0x7fffffffffffffffL;
private final static long ZERO_VAL = 0;
public final static U64 ZERO = new U64(ZERO_VAL);
private static final long NO_MASK_VAL = 0xFFffFFffFFffFFffL;
public final static U64 NO_MASK = new U64(NO_MASK_VAL);
public static final U64 FULL_MASK = ZERO;
private final long raw;
protected U64(final long raw) {
this.raw = raw;
}
public static U64 of(long raw) {
return ofRaw(raw);
}
public static U64 ofRaw(final long raw) {
if(raw == ZERO_VAL)
return ZERO;
return new U64(raw);
}
public static U64 parseHex(String hex) {
return new U64(new BigInteger(hex, 16).longValue());
}
public long getValue() {
return raw;
}
public BigInteger getBigInteger() {
BigInteger bigInt = BigInteger.valueOf(raw & UNSIGNED_MASK);
if (raw < 0) {
bigInt = bigInt.setBit(Long.SIZE - 1);
}
return bigInt;
}
@Override
public String toString() {
return String.format("0x%016x", raw);
}
public static BigInteger f(final long value) {
BigInteger bigInt = BigInteger.valueOf(value & UNSIGNED_MASK);
if (value < 0) {
bigInt = bigInt.setBit(Long.SIZE - 1);
}
return bigInt;
}
public static long t(final BigInteger l) {
return l.longValue();
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + (int) (raw ^ (raw >>> 32));
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
U64 other = (U64) obj;
if (raw != other.raw)
return false;
return true;
}
@Override
public int getLength() {
return 8;
}
@Override
public U64 applyMask(U64 mask) {
return and(mask);
}
@Override
public void writeTo(ChannelBuffer bb) {
bb.writeLong(raw);
}
@Override
public int compareTo(U64 o) {
return UnsignedLongs.compare(raw, o.raw);
}
@Override
public void putTo(PrimitiveSink sink) {
sink.putLong(raw);
}
@Override
public U64 inverse() {
return U64.of(~raw);
}
@Override
public U64 or(U64 other) {
return U64.of(raw | other.raw);
}
@Override
public U64 and(U64 other) {
return ofRaw(raw & other.raw);
}
@Override
public U64 xor(U64 other) {
return U64.of(raw ^ other.raw);
}
/** return the "numBits" highest-order bits of the hash.
* @param numBits number of higest-order bits to return [0-32].
* @return a numberic value of the 0-32 highest-order bits.
*/
@Override
public int prefixBits(int numBits) {
return HashValueUtils.prefixBits(raw, numBits);
}
@Override
public U64 combineWithValue(U64 value, int keyBits) {
return U64.of(HashValueUtils.combineWithValue(this.raw, value.raw, keyBits));
}
public final static Reader READER = new Reader();
private static class Reader implements OFMessageReader<U64> {
@Override
public U64 readFrom(ChannelBuffer bb) throws OFParseError {
return U64.ofRaw(bb.readLong());
}
}
}
/**
* Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior
* University
*
* 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.projectfloodlight.openflow.types;
import org.jboss.netty.buffer.ChannelBuffer;
import org.projectfloodlight.openflow.exceptions.OFParseError;
import org.projectfloodlight.openflow.protocol.OFMessageReader;
import org.projectfloodlight.openflow.protocol.Writeable;
import com.google.common.hash.PrimitiveSink;
import com.google.common.primitives.UnsignedBytes;
public class U8 implements Writeable, OFValueType<U8> {
private final static byte ZERO_VAL = 0;
public final static U8 ZERO = new U8(ZERO_VAL);
private static final byte NO_MASK_VAL = (byte) 0xFF;
public static final U8 NO_MASK = new U8(NO_MASK_VAL);
public static final U8 FULL_MASK = ZERO;
private final byte raw;
private U8(byte raw) {
this.raw = raw;
}
public static final U8 of(short value) {
if(value == ZERO_VAL)
return ZERO;
if(value == NO_MASK_VAL)
return NO_MASK;
return new U8(t(value));
}
public static final U8 ofRaw(byte value) {
return new U8(value);
}
public short getValue() {
return f(raw);
}
public byte getRaw() {
return raw;
}
@Override
public String toString() {
return String.format("0x%02x", raw);
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + raw;
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
U8 other = (U8) obj;
if (raw != other.raw)
return false;
return true;
}
@Override
public void writeTo(ChannelBuffer bb) {
bb.writeByte(raw);
}
public static short f(final byte i) {
return (short) (i & 0xff);
}
public static byte t(final short l) {
return (byte) l;
}
public final static Reader READER = new Reader();
private static class Reader implements OFMessageReader<U8> {
@Override
public U8 readFrom(ChannelBuffer bb) throws OFParseError {
return new U8(bb.readByte());
}
}
@Override
public int getLength() {
return 1;
}
@Override
public U8 applyMask(U8 mask) {
return ofRaw( (byte) (raw & mask.raw));
}
@Override
public int compareTo(U8 o) {
return UnsignedBytes.compare(raw, o.raw);
}
@Override
public void putTo(PrimitiveSink sink) {
sink.putByte(raw);
}
}
package org.projectfloodlight.openflow.types;
import javax.annotation.concurrent.Immutable;
import org.jboss.netty.buffer.ChannelBuffer;
import com.google.common.hash.PrimitiveSink;
import com.google.common.primitives.UnsignedInts;
@Immutable
public class UDF implements OFValueType<UDF> {
static final int LENGTH = 4;
private final int rawValue;
public static final UDF ZERO = UDF.of(0x0);
public static final UDF NO_MASK = UDF.of(0xFFFFFFFF);
public static final UDF FULL_MASK = UDF.of(0x00000000);
private UDF(final int rawValue) {
this.rawValue = rawValue;
}
public static UDF of(final int raw) {
return new UDF(raw);
}
public int getInt() {
return rawValue;
}
@Override
public int getLength() {
return LENGTH;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + rawValue;
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
UDF other = (UDF) obj;
if (rawValue != other.rawValue)
return false;
return true;
}
@Override
public String toString() {
return Integer.toString(rawValue);
}
public void write4Bytes(ChannelBuffer c) {
c.writeInt(rawValue);
}
public static UDF read4Bytes(ChannelBuffer c) {
return UDF.of(c.readInt());
}
@Override
public UDF applyMask(UDF mask) {
return UDF.of(this.rawValue & mask.rawValue);
}
@Override
public int compareTo(UDF o) {
return UnsignedInts.compare(rawValue, o.rawValue);
}
@Override
public void putTo(PrimitiveSink sink) {
sink.putInt(rawValue);
}
}
package org.projectfloodlight.openflow.types;
import javax.annotation.concurrent.Immutable;
import org.jboss.netty.buffer.ChannelBuffer;
import com.google.common.hash.PrimitiveSink;
import com.google.common.primitives.UnsignedInts;
@Immutable
public class VRF implements OFValueType<VRF> {
static final int LENGTH = 4;
private final int rawValue;
public static final VRF ZERO = VRF.of(0x0);
public static final VRF NO_MASK = VRF.of(0xFFFFFFFF);
public static final VRF FULL_MASK = VRF.of(0x00000000);
private VRF(final int rawValue) {
this.rawValue = rawValue;
}
public static VRF of(final int raw) {
return new VRF(raw);
}
public int getInt() {
return rawValue;
}
@Override
public int getLength() {
return LENGTH;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + rawValue;
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
VRF other = (VRF) obj;
if (rawValue != other.rawValue)
return false;
return true;
}
@Override
public String toString() {
return Integer.toString(rawValue);
}
public void write4Bytes(ChannelBuffer c) {
c.writeInt(rawValue);
}
public static VRF read4Bytes(ChannelBuffer c) {
return VRF.of(c.readInt());
}
@Override
public VRF applyMask(VRF mask) {
return VRF.of(this.rawValue & mask.rawValue);
}
@Override
public int compareTo(VRF o) {
return UnsignedInts.compare(rawValue, o.rawValue);
}
@Override
public void putTo(PrimitiveSink sink) {
sink.putInt(rawValue);
}
}
package org.projectfloodlight.openflow.types;
import org.jboss.netty.buffer.ChannelBuffer;
import org.projectfloodlight.openflow.exceptions.OFParseError;
import com.google.common.hash.PrimitiveSink;
import com.google.common.primitives.UnsignedBytes;
public class VlanPcp implements OFValueType<VlanPcp> {
private static final byte VALIDATION_MASK = 0x07;
private static final byte NONE_VAL = 0x00;
static final int LENGTH = 1;
private final byte pcp;
public static final VlanPcp NONE = new VlanPcp(NONE_VAL);
public static final VlanPcp NO_MASK = new VlanPcp((byte)0xFF);
public static final VlanPcp FULL_MASK = VlanPcp.of((byte)0x0);
private VlanPcp(byte pcp) {
this.pcp = pcp;
}
public static VlanPcp of(byte pcp) {
if ((pcp & VALIDATION_MASK) != pcp)
throw new IllegalArgumentException("Illegal VLAN PCP value: " + pcp);
return new VlanPcp(pcp);
}
@Override
public boolean equals(Object obj) {
if (!(obj instanceof VlanPcp))
return false;
VlanPcp other = (VlanPcp)obj;
if (other.pcp != this.pcp)
return false;
return true;
}
@Override
public int hashCode() {
int prime = 20173;
return this.pcp * prime;
}
@Override
public String toString() {
return "0x" + Integer.toHexString(pcp);
}
public byte getValue() {
return pcp;
}
@Override
public int getLength() {
return LENGTH;
}
public void writeByte(ChannelBuffer c) {
c.writeByte(this.pcp);
}
public static VlanPcp readByte(ChannelBuffer c) throws OFParseError {
return VlanPcp.of((byte)(c.readUnsignedByte() & 0xFF));
}
@Override
public VlanPcp applyMask(VlanPcp mask) {
return VlanPcp.of((byte)(this.pcp & mask.pcp));
}
@Override
public int compareTo(VlanPcp o) {
return UnsignedBytes.compare(pcp, o.pcp);
}
@Override
public void putTo(PrimitiveSink sink) {
sink.putByte(pcp);
}
}
package org.projectfloodlight.openflow.types;
import java.util.Arrays;
import org.jboss.netty.buffer.ChannelBuffer;
import org.projectfloodlight.openflow.exceptions.OFParseError;
import com.google.common.hash.PrimitiveSink;
import com.google.common.primitives.Shorts;
/** Represents an 802.1Q Vlan VID (12 bits).
*
* @author Andreas Wundsam <andreas.wundsam@bigswitch.com>
*
*/
public class VlanVid implements OFValueType<VlanVid> {
private static final short VALIDATION_MASK = 0x0FFF;
private static final short ZERO_VAL = 0x0000;
final static int LENGTH = 2;
/** this value means 'not set' in OF1.0 (e.g., in a match). not used elsewhere */
public static final VlanVid ZERO = new VlanVid(ZERO_VAL);
/** for use with masking operations */
public static final VlanVid NO_MASK = new VlanVid((short)0xFFFF);
public static final VlanVid FULL_MASK = ZERO;
private final short vid;
private VlanVid(short vid) {
this.vid = vid;
}
public static VlanVid ofVlan(int vid) {
if (vid == NO_MASK.vid)
return NO_MASK;
if ((vid & VALIDATION_MASK) != vid)
throw new IllegalArgumentException(String.format("Illegal VLAN value: %x", vid));
return new VlanVid((short) vid);
}
/** @return the actual VLAN tag this vid identifies */
public short getVlan() {
return vid;
}
@Override
public boolean equals(Object obj) {
if (!(obj instanceof VlanVid))
return false;
VlanVid other = (VlanVid)obj;
if (other.vid != this.vid)
return false;
return true;
}
@Override
public int hashCode() {
int prime = 13873;
return this.vid * prime;
}
@Override
public String toString() {
return "0x" + Integer.toHexString(vid);
}
@Override
public int getLength() {
return LENGTH;
}
private volatile byte[] bytesCache = null;
public byte[] getBytes() {
if (bytesCache == null) {
synchronized (this) {
if (bytesCache == null) {
bytesCache =
new byte[] { (byte) ((vid >>> 8) & 0xFF),
(byte) ((vid >>> 0) & 0xFF) };
}
}
}
return Arrays.copyOf(bytesCache, bytesCache.length);
}
public void write2Bytes(ChannelBuffer c) {
c.writeShort(this.vid);
}
public void write2BytesOF10(ChannelBuffer c) {
c.writeShort(this.getVlan());
}
public static VlanVid read2Bytes(ChannelBuffer c) throws OFParseError {
return VlanVid.ofVlan(c.readShort());
}
@Override
public VlanVid applyMask(VlanVid mask) {
return VlanVid.ofVlan((short)(this.vid & mask.vid));
}
@Override
public int compareTo(VlanVid o) {
return Shorts.compare(vid, o.vid);
}
@Override
public void putTo(PrimitiveSink sink) {
sink.putShort(vid);
}
}
package org.projectfloodlight.openflow.util;
import java.util.List;
import org.projectfloodlight.openflow.protocol.OFFlowMod;
import org.projectfloodlight.openflow.protocol.OFFlowStatsEntry;
import org.projectfloodlight.openflow.protocol.OFInstructionType;
import org.projectfloodlight.openflow.protocol.OFVersion;
import org.projectfloodlight.openflow.protocol.action.OFAction;
import org.projectfloodlight.openflow.protocol.instruction.OFInstruction;
import org.projectfloodlight.openflow.protocol.instruction.OFInstructionApplyActions;
import com.google.common.collect.ImmutableList;
public class ActionUtils {
private ActionUtils() {}
public static List<OFAction> getActions(OFFlowStatsEntry e) {
if(e.getVersion() == OFVersion.OF_10) {
return e.getActions();
} else {
for(OFInstruction i: e.getInstructions()) {
if(i.getType() == OFInstructionType.APPLY_ACTIONS) {
return ((OFInstructionApplyActions) i).getActions();
}
}
return ImmutableList.of();
}
}
public static List<OFAction> getActions(OFFlowMod e) {
if(e.getVersion() == OFVersion.OF_10) {
return e.getActions();
} else {
for(OFInstruction i: e.getInstructions()) {
if(i.getType() == OFInstructionType.APPLY_ACTIONS) {
return ((OFInstructionApplyActions) i).getActions();
}
}
return ImmutableList.of();
}
}
}
package org.projectfloodlight.openflow.util;
import java.util.List;
import org.jboss.netty.buffer.ChannelBuffer;
import org.projectfloodlight.openflow.exceptions.OFParseError;
import org.projectfloodlight.openflow.protocol.OFMessageReader;
import org.projectfloodlight.openflow.protocol.Writeable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.common.base.Charsets;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableList.Builder;
/**
* Collection of helper functions for reading and writing into ChannelBuffers
*
* @author capveg
*/
public class ChannelUtils {
private static final Logger logger = LoggerFactory.getLogger(ChannelUtils.class);
public static String readFixedLengthString(ChannelBuffer bb, int length) {
byte[] dst = new byte[length];
bb.readBytes(dst, 0, length);
int validLength = 0;
for (validLength = 0; validLength < length; validLength++) {
if (dst[validLength] == 0)
break;
}
return new String(dst, 0, validLength, Charsets.US_ASCII);
}
public static void writeFixedLengthString(ChannelBuffer bb, String string,
int length) {
int l = string.length();
if (l > length) {
throw new IllegalArgumentException("Error writing string: length="
+ l + " > max Length=" + length);
}
bb.writeBytes(string.getBytes(Charsets.US_ASCII));
if (l < length) {
bb.writeZero(length - l);
}
}
static public byte[] readBytes(final ChannelBuffer bb, final int length) {
byte byteArray[] = new byte[length];
bb.readBytes(byteArray);
return byteArray;
}
static public void writeBytes(final ChannelBuffer bb,
final byte byteArray[]) {
bb.writeBytes(byteArray);
}
public static <T> List<T> readList(ChannelBuffer bb, int length, OFMessageReader<T> reader) throws OFParseError {
int end = bb.readerIndex() + length;
Builder<T> builder = ImmutableList.<T>builder();
if(logger.isTraceEnabled())
logger.trace("readList(length={}, reader={})", length, reader.getClass());
while(bb.readerIndex() < end) {
T read = reader.readFrom(bb);
if(logger.isTraceEnabled())
logger.trace("readList: read={}, left={}", read, end - bb.readerIndex());
builder.add(read);
}
if(bb.readerIndex() != end) {
throw new IllegalStateException("Overread length: length="+length + " overread by "+ (bb.readerIndex() - end) + " reader: "+reader);
}
return builder.build();
}
public static void writeList(ChannelBuffer bb, List<? extends Writeable> writeables) {
for(Writeable w: writeables)
w.writeTo(bb);
}
}
package org.projectfloodlight.openflow.util;
import java.util.List;
import org.projectfloodlight.openflow.types.PrimitiveSinkable;
import com.google.common.hash.PrimitiveSink;
public class FunnelUtils {
public static void putList(List<? extends PrimitiveSinkable> sinkables, PrimitiveSink sink) {
for(PrimitiveSinkable p: sinkables)
p.putTo(sink);
}
}
/**
* Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior
* University
*
* 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.projectfloodlight.openflow.util;
import org.projectfloodlight.openflow.types.U8;
public class HexString {
/**
* Convert a string of bytes to a ':' separated hex string
*
* @param bytes
* @return "0f:ca:fe:de:ad:be:ef"
*/
public static String toHexString(final byte[] bytes) {
int i;
String ret = "";
String tmp;
for (i = 0; i < bytes.length; i++) {
if (i > 0)
ret += ":";
tmp = Integer.toHexString(U8.f(bytes[i]));
if (tmp.length() == 1)
ret += "0";
ret += tmp;
}
return ret;
}
public static String toHexString(final long val, final int padTo) {
char arr[] = Long.toHexString(val).toCharArray();
String ret = "";
// prepend the right number of leading zeros
int i = 0;
for (; i < (padTo * 2 - arr.length); i++) {
ret += "0";
if ((i % 2) != 0)
ret += ":";
}
for (int j = 0; j < arr.length; j++) {
ret += arr[j];
if ((((i + j) % 2) != 0) && (j < (arr.length - 1)))
ret += ":";
}
return ret;
}
public static String toHexString(final long val) {
return toHexString(val, 8);
}
/**
* Convert a string of hex values into a string of bytes
*
* @param values
* "0f:ca:fe:de:ad:be:ef"
* @return [15, 5 ,2, 5, 17]
* @throws NumberFormatException
* If the string can not be parsed
*/
public static byte[] fromHexString(final String values) throws NumberFormatException {
String[] octets = values.split(":");
byte[] ret = new byte[octets.length];
for (int i = 0; i < octets.length; i++) {
if (octets[i].length() > 2)
throw new NumberFormatException("Invalid octet length");
ret[i] = Integer.valueOf(octets[i], 16).byteValue();
}
return ret;
}
public static long toLong(String value) throws NumberFormatException {
String[] octets = value.split(":");
if (octets.length > 8)
throw new NumberFormatException("Input string is too big to fit in long: " + value);
long l = 0;
for (String octet: octets) {
if (octet.length() > 2)
throw new NumberFormatException("Each colon-separated byte component must consist of 1 or 2 hex digits: " + value);
short s = Short.parseShort(octet, 16);
l = (l << 8) + s;
}
return l;
}
}
/**
* Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior
* University
*
* 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.projectfloodlight.openflow.util;
import java.util.LinkedHashMap;
public class LRULinkedHashMap<K, V> extends LinkedHashMap<K, V> {
private static final long serialVersionUID = -2964986094089626647L;
protected int maximumCapacity;
public LRULinkedHashMap(final int initialCapacity, final int maximumCapacity) {
super(initialCapacity, 0.75f, true);
this.maximumCapacity = maximumCapacity;
}
public LRULinkedHashMap(final int maximumCapacity) {
super(16, 0.75f, true);
this.maximumCapacity = maximumCapacity;
}
@Override
protected boolean removeEldestEntry(final java.util.Map.Entry<K, V> eldest) {
if (this.size() > maximumCapacity)
return true;
return false;
}
}
package org.projectfloodlight.openflow.util;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.channels.GatheringByteChannel;
import java.nio.channels.ScatteringByteChannel;
import java.nio.charset.Charset;
import org.jboss.netty.buffer.ChannelBuffer;
import org.jboss.netty.buffer.ChannelBufferFactory;
import org.jboss.netty.buffer.ChannelBufferIndexFinder;
public class LengthCountingPseudoChannelBuffer implements ChannelBuffer {
int writerIndex = 0;
private int markedWriterIndex;
@Override
public ChannelBufferFactory factory() {
return null;
}
@Override
public int capacity() {
return Integer.MAX_VALUE;
}
@Override
public ByteOrder order() {
return ByteOrder.BIG_ENDIAN;
}
@Override
public boolean isDirect() {
return true;
}
@Override
public int readerIndex() {
return 0;
}
@Override
public void readerIndex(int readerIndex) {
throw new UnsupportedOperationException();
}
@Override
public int writerIndex() {
return writerIndex;
}
@Override
public void writerIndex(int writerIndex) {
this.writerIndex = writerIndex;
}
@Override
public void setIndex(int readerIndex, int writerIndex) {
if(readerIndex != 0)
throw new UnsupportedOperationException();
this.writerIndex = writerIndex;
}
@Override
public int readableBytes() {
return writerIndex;
}
@Override
public int writableBytes() {
return Integer.MAX_VALUE - writerIndex;
}
@Override
public boolean readable() {
return writerIndex > 0;
}
@Override
public boolean writable() {
return writerIndex < Integer.MAX_VALUE;
}
@Override
public void clear() {
writerIndex = 0;
}
@Override
public void markReaderIndex() {
}
@Override
public void resetReaderIndex() {
}
@Override
public void markWriterIndex() {
markedWriterIndex = writerIndex;
}
@Override
public void resetWriterIndex() {
writerIndex = markedWriterIndex;
}
@Override
public void discardReadBytes() {
throw new UnsupportedOperationException();
}
@Override
public void ensureWritableBytes(int writableBytes) {
if(!((Integer.MAX_VALUE - writableBytes) > writerIndex))
throw new IllegalStateException();
}
@Override
public byte getByte(int index) {
throw new UnsupportedOperationException();
}
@Override
public short getUnsignedByte(int index) {
throw new UnsupportedOperationException();
}
@Override
public short getShort(int index) {
throw new UnsupportedOperationException();
}
@Override
public int getUnsignedShort(int index) {
throw new UnsupportedOperationException();
}
@Override
public int getMedium(int index) {
throw new UnsupportedOperationException();
}
@Override
public int getUnsignedMedium(int index) {
throw new UnsupportedOperationException();
}
@Override
public int getInt(int index) {
throw new UnsupportedOperationException();
}
@Override
public long getUnsignedInt(int index) {
throw new UnsupportedOperationException();
}
@Override
public long getLong(int index) {
throw new UnsupportedOperationException();
}
@Override
public char getChar(int index) {
throw new UnsupportedOperationException();
}
@Override
public float getFloat(int index) {
throw new UnsupportedOperationException();
}
@Override
public double getDouble(int index) {
throw new UnsupportedOperationException();
}
@Override
public void getBytes(int index, ChannelBuffer dst) {
throw new UnsupportedOperationException();
}
@Override
public void getBytes(int index, ChannelBuffer dst, int length) {
throw new UnsupportedOperationException();
}
@Override
public void getBytes(int index, ChannelBuffer dst, int dstIndex, int length) {
throw new UnsupportedOperationException();
}
@Override
public void getBytes(int index, byte[] dst) {
throw new UnsupportedOperationException();
}
@Override
public void getBytes(int index, byte[] dst, int dstIndex, int length) {
throw new UnsupportedOperationException();
}
@Override
public void getBytes(int index, ByteBuffer dst) {
throw new UnsupportedOperationException();
}
@Override
public void getBytes(int index, OutputStream out, int length)
throws IOException {
throw new UnsupportedOperationException();
}
@Override
public int getBytes(int index, GatheringByteChannel out, int length)
throws IOException {
throw new UnsupportedOperationException();
}
@Override
public void setByte(int index, int value) {
}
@Override
public void setShort(int index, int value) {
}
@Override
public void setMedium(int index, int value) {
}
@Override
public void setInt(int index, int value) {
}
@Override
public void setLong(int index, long value) {
}
@Override
public void setChar(int index, int value) {
}
@Override
public void setFloat(int index, float value) {
}
@Override
public void setDouble(int index, double value) {
}
@Override
public void setBytes(int index, ChannelBuffer src) {
}
@Override
public void setBytes(int index, ChannelBuffer src, int length) {
}
@Override
public void setBytes(int index, ChannelBuffer src, int srcIndex, int length) {
}
@Override
public void setBytes(int index, byte[] src) {
}
@Override
public void setBytes(int index, byte[] src, int srcIndex, int length) {
}
@Override
public void setBytes(int index, ByteBuffer src) {
}
@Override
public int setBytes(int index, InputStream in, int length)
throws IOException {
throw new UnsupportedOperationException();
}
@Override
public int setBytes(int index, ScatteringByteChannel in, int length)
throws IOException {
throw new UnsupportedOperationException();
}
@Override
public void setZero(int index, int length) {
}
@Override
public byte readByte() {
throw new UnsupportedOperationException();
}
@Override
public short readUnsignedByte() {
throw new UnsupportedOperationException();
}
@Override
public short readShort() {
throw new UnsupportedOperationException();
}
@Override
public int readUnsignedShort() {
throw new UnsupportedOperationException();
}
@Override
public int readMedium() {
throw new UnsupportedOperationException();
}
@Override
public int readUnsignedMedium() {
throw new UnsupportedOperationException();
}
@Override
public int readInt() {
throw new UnsupportedOperationException();
}
@Override
public long readUnsignedInt() {
throw new UnsupportedOperationException();
}
@Override
public long readLong() {
throw new UnsupportedOperationException();
}
@Override
public char readChar() {
throw new UnsupportedOperationException();
}
@Override
public float readFloat() {
throw new UnsupportedOperationException();
}
@Override
public double readDouble() {
throw new UnsupportedOperationException();
}
@Override
public ChannelBuffer readBytes(int length) {
throw new UnsupportedOperationException();
}
@Override
@Deprecated
public ChannelBuffer readBytes(ChannelBufferIndexFinder indexFinder) {
throw new UnsupportedOperationException();
}
@Override
public ChannelBuffer readSlice(int length) {
throw new UnsupportedOperationException();
}
@Override
@Deprecated
public
ChannelBuffer readSlice(ChannelBufferIndexFinder indexFinder) {
throw new UnsupportedOperationException();
}
@Override
public void readBytes(ChannelBuffer dst) {
throw new UnsupportedOperationException();
}
@Override
public void readBytes(ChannelBuffer dst, int length) {
throw new UnsupportedOperationException();
}
@Override
public void readBytes(ChannelBuffer dst, int dstIndex, int length) {
throw new UnsupportedOperationException();
}
@Override
public void readBytes(byte[] dst) {
throw new UnsupportedOperationException();
}
@Override
public void readBytes(byte[] dst, int dstIndex, int length) {
throw new UnsupportedOperationException();
}
@Override
public void readBytes(ByteBuffer dst) {
throw new UnsupportedOperationException();
}
@Override
public void readBytes(OutputStream out, int length) throws IOException {
throw new UnsupportedOperationException();
}
@Override
public int readBytes(GatheringByteChannel out, int length)
throws IOException {
throw new UnsupportedOperationException();
}
@Override
public void skipBytes(int length) {
throw new UnsupportedOperationException();
}
@Override
@Deprecated
public int skipBytes(ChannelBufferIndexFinder indexFinder) {
throw new UnsupportedOperationException();
}
@Override
public void writeByte(int value) {
writerIndex++;
}
@Override
public void writeShort(int value) {
writerIndex += 2;
}
@Override
public void writeMedium(int value) {
writerIndex += 3;
}
@Override
public void writeInt(int value) {
writerIndex += 4;
}
@Override
public void writeLong(long value) {
writerIndex += 8;
}
@Override
public void writeChar(int value) {
writeShort(value);
}
@Override
public void writeFloat(float value) {
writeInt(Float.floatToIntBits(value));
}
@Override
public void writeDouble(double value) {
writeLong(Double.doubleToLongBits(value));
}
@Override
public void writeBytes(ChannelBuffer src) {
writerIndex += src.readableBytes();
}
@Override
public void writeBytes(ChannelBuffer src, int length) {
writerIndex += src.readableBytes();
}
@Override
public void writeBytes(ChannelBuffer src, int srcIndex, int length) {
writerIndex += length;
}
@Override
public void writeBytes(byte[] src) {
writerIndex += src.length;
}
@Override
public void writeBytes(byte[] src, int srcIndex, int length) {
writerIndex += length;
}
@Override
public void writeBytes(ByteBuffer src) {
writerIndex += src.remaining();
}
@Override
public int writeBytes(InputStream in, int length) throws IOException {
writerIndex += length;
return length;
}
@Override
public int writeBytes(ScatteringByteChannel in, int length)
throws IOException {
writerIndex += length;
return length;
}
@Override
public void writeZero(int length) {
writerIndex += length;
}
@Override
public int indexOf(int fromIndex, int toIndex, byte value) {
throw new UnsupportedOperationException();
}
@Override
public int indexOf(int fromIndex, int toIndex,
ChannelBufferIndexFinder indexFinder) {
throw new UnsupportedOperationException();
}
@Override
public int bytesBefore(byte value) {
throw new UnsupportedOperationException();
}
@Override
public int bytesBefore(ChannelBufferIndexFinder indexFinder) {
throw new UnsupportedOperationException();
}
@Override
public int bytesBefore(int length, byte value) {
throw new UnsupportedOperationException();
}
@Override
public int bytesBefore(int length, ChannelBufferIndexFinder indexFinder) {
throw new UnsupportedOperationException();
}
@Override
public int bytesBefore(int index, int length, byte value) {
throw new UnsupportedOperationException();
}
@Override
public int bytesBefore(int index, int length,
ChannelBufferIndexFinder indexFinder) {
throw new UnsupportedOperationException();
}
@Override
public ChannelBuffer copy() {
throw new UnsupportedOperationException();
}
@Override
public ChannelBuffer copy(int index, int length) {
throw new UnsupportedOperationException();
}
@Override
public ChannelBuffer slice() {
throw new UnsupportedOperationException();
}
@Override
public ChannelBuffer slice(int index, int length) {
throw new UnsupportedOperationException();
}
@Override
public ChannelBuffer duplicate() {
throw new UnsupportedOperationException();
}
@Override
public ByteBuffer toByteBuffer() {
throw new UnsupportedOperationException();
}
@Override
public ByteBuffer toByteBuffer(int index, int length) {
throw new UnsupportedOperationException();
}
@Override
public ByteBuffer[] toByteBuffers() {
throw new UnsupportedOperationException();
}
@Override
public ByteBuffer[] toByteBuffers(int index, int length) {
throw new UnsupportedOperationException();
}
@Override
public boolean hasArray() {
throw new UnsupportedOperationException();
}
@Override
public byte[] array() {
throw new UnsupportedOperationException();
}
@Override
public int arrayOffset() {
throw new UnsupportedOperationException();
}
@Override
public String toString(Charset charset) {
return "LengthCountingPseudoChannelBuffer(length="+writerIndex+")";
}
@Override
public String toString(int index, int length, Charset charset) {
return toString();
}
@Override
@Deprecated
public String toString(String charsetName) {
return toString();
}
@Override
@Deprecated
public String toString(String charsetName,
ChannelBufferIndexFinder terminatorFinder) {
return toString();
}
@Override
@Deprecated
public String toString(int index, int length, String charsetName) {
return toString();
}
@Override
@Deprecated
public
String toString(int index, int length, String charsetName,
ChannelBufferIndexFinder terminatorFinder) {
return toString();
}
@Override
public int compareTo(ChannelBuffer buffer) {
throw new UnsupportedOperationException();
}
}
package org.projectfloodlight.openflow.util;
import java.util.Set;
import com.google.common.collect.ImmutableSet;
import org.projectfloodlight.openflow.types.U64;
import org.projectfloodlight.openflow.protocol.OFBsnPktinFlag;
import org.projectfloodlight.openflow.protocol.OFPacketIn;
import org.projectfloodlight.openflow.protocol.OFVersion;
import org.projectfloodlight.openflow.protocol.match.MatchField;
import org.projectfloodlight.openflow.protocol.match.Match;
import org.projectfloodlight.openflow.protocol.ver13.OFBsnPktinFlagSerializerVer13;
import org.projectfloodlight.openflow.types.OFMetadata;
public class MultiplePktInReasonUtil {
private MultiplePktInReasonUtil() {}
/**
* This function is used in BVS T5/6 to decode the multiple packet in
* reasons in Match.MetaData field.
* */
public static Set<OFBsnPktinFlag> getOFBsnPktinFlags(OFPacketIn pktIn) {
if(pktIn.getVersion() != OFVersion.OF_13) {
throw new IllegalArgumentException("multiple pkt in reasons are "
+ "only supported by BVS using "
+ "openflow 1.3");
}
Match match = pktIn.getMatch();
if(match == null) {
return ImmutableSet.<OFBsnPktinFlag>of();
}
OFMetadata metaData = match.get(MatchField.METADATA);
if(metaData == null) {
return ImmutableSet.<OFBsnPktinFlag>of();
}
U64 metaDataValue = metaData.getValue();
if(metaDataValue == null) {
return ImmutableSet.<OFBsnPktinFlag>of();
}
return OFBsnPktinFlagSerializerVer13.ofWireValue(metaDataValue
.getValue());
}
}
package org.projectfloodlight.openflow.util;
import java.util.List;
import java.util.SortedSet;
import javax.annotation.Nullable;
import org.projectfloodlight.openflow.types.PrimitiveSinkable;
import com.google.common.hash.PrimitiveSink;
/** Utility methods for dumping collections into primitive sinks.
*
* @author Andreas Wundsam <andreas.wundsam@bigswitch.com>
*/
public class PrimitiveSinkUtils {
private PrimitiveSinkUtils() {}
/** puts a nullable String into a primitive sink. The entry is prepended by a 'presence'
* boolean bit and the string length;
*
*
* @param sink the sink to put the object
* @param nullableObj the potentially null string to put in the sink
*/
public static void putNullableStringTo(PrimitiveSink sink,
@Nullable CharSequence nullableChars) {
sink.putBoolean(nullableChars != null);
if(nullableChars != null) {
sink.putInt(nullableChars.length());
sink.putUnencodedChars(nullableChars);
}
}
/** puts a nullable element into a primitive sink. The entry is prepended by a 'present' bit.
*
* @param sink the sink to put the object
* @param nullableObj the nullable object
*/
public static void putNullableTo(PrimitiveSink sink,
@Nullable PrimitiveSinkable nullableObj) {
sink.putBoolean(nullableObj != null);
if(nullableObj != null)
nullableObj.putTo(sink);
}
/** puts the elements of a sorted set into the {@link PrimitiveSink}. Does not support null
* elements. The elements are assumed to be self-delimitating.
*
* @param sink
* @param set
*/
public static void putSortedSetTo(PrimitiveSink sink,
SortedSet<? extends PrimitiveSinkable> set) {
sink.putInt(set.size());
for(PrimitiveSinkable e: set) {
e.putTo(sink);
}
}
/** puts the elements of a list into the {@link PrimitiveSink}. Does not support null
* elements. The elements are assumed to be self-delimitating.
*
* @param sink
* @param set
*/
public static void putListTo(PrimitiveSink sink,
List<? extends PrimitiveSinkable> set) {
sink.putInt(set.size());
for(PrimitiveSinkable e: set) {
e.putTo(sink);
}
}
}
/**
* Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior
* University
*
* 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.projectfloodlight.openflow.util;
import java.io.UnsupportedEncodingException;
import java.nio.charset.Charset;
import java.util.Arrays;
import org.jboss.netty.buffer.ChannelBuffer;
public class StringByteSerializer {
public static String readFrom(final ChannelBuffer data, final int length) {
byte[] stringBytes = new byte[length];
data.readBytes(stringBytes);
// find the first index of 0
int index = 0;
for (byte b : stringBytes) {
if (0 == b)
break;
++index;
}
return new String(Arrays.copyOf(stringBytes, index), Charset.forName("ascii"));
}
public static void writeTo(final ChannelBuffer data, final int length,
final String value) {
try {
byte[] name = value.getBytes("ASCII");
if (name.length < length) {
data.writeBytes(name);
for (int i = name.length; i < length; ++i) {
data.writeByte((byte) 0);
}
} else {
data.writeBytes(name, 0, length - 1);
data.writeByte((byte) 0);
}
} catch (UnsupportedEncodingException e) {
throw new RuntimeException(e);
}
}
}
package org.projectfloodlight.openflow.types;
import static org.hamcrest.CoreMatchers.equalTo;
import static org.junit.Assert.assertThat;
import org.junit.Test;
public class HashValueUtilsTest {
@Test
public void testBasic() {
long key = 0x1234_5678_1234_5678L;
long value = 0x8765_4321_8765_4321L;
long firstword = 0xFFFF_FFFF_0000_0000L;
long secondword = 0x0000_0000_FFFF_FFFFL;
long xor = key ^ value;
assertThat(HashValueUtils.combineWithValue(key, value, 0), equalTo(xor));
assertThat(HashValueUtils.combineWithValue(key, value, 64), equalTo(key));
assertThat(HashValueUtils.combineWithValue(key, value, 32), equalTo(key & firstword | xor & secondword ));
assertThat(HashValueUtils.combineWithValue(key, value, 8), equalTo(0x1251_1559_9551_1559L));
}
}
package org.projectfloodlight.openflow.types;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.fail;
import java.net.UnknownHostException;
import org.junit.Test;
/**
* Most tests are in IPv4AddressTest and IPv6AddressTest
* Just exception testing here
* @author gregor
*
*/
public class IPAddressTest {
@Test
public void testOfException() {
try {
IPAddress.of("Foobar");
fail("Should have thrown IllegalArgumentException");
} catch (IllegalArgumentException e) {
// expected
}
try {
IPAddressWithMask.of("Foobar");
fail("Should have thrown IllegalArgumentException");
} catch (IllegalArgumentException e) {
// expected
}
try {
IPAddress.of(null);
fail("Should have thrown NullPointerException");
} catch (NullPointerException e) {
assertNotNull(e.getMessage());
}
try {
IPAddressWithMask.of(null);
fail("Should have thrown NullPointerException");
} catch (NullPointerException e) {
assertNotNull(e.getMessage());
}
try {
IPAddress.of(null);
fail("Should have thrown NullPointerException");
} catch (NullPointerException e) {
assertNotNull(e.getMessage());
}
try {
IPAddressWithMask.of(null);
fail("Should have thrown NullPointerException");
} catch (NullPointerException e) {
assertNotNull(e.getMessage());
}
}
@Test
public void testFromInetAddressException() throws UnknownHostException {
try {
IPAddress.fromInetAddress(null);
fail("Should have thrown NullPointerException");
} catch (NullPointerException e) {
assertNotNull(e.getMessage());
}
}
}
package org.projectfloodlight.openflow.types;
import static org.hamcrest.CoreMatchers.equalTo;
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;
import static org.junit.Assert.fail;
import org.hamcrest.CoreMatchers;
import org.jboss.netty.buffer.ChannelBuffers;
import org.junit.Test;
import org.projectfloodlight.openflow.exceptions.OFParseError;
public class IPv4AddressTest {
byte[][] testAddresses = new byte[][] {
{0x01, 0x02, 0x03, 0x04 },
{127, 0, 0, 1},
{(byte) 192, (byte) 168, 0, 100 },
{(byte) 255, (byte) 255, (byte) 255, (byte) 255 }
};
String[] testStrings = {
"1.2.3.4",
"127.0.0.1",
"192.168.0.100",
"255.255.255.255"
};
int[] testInts = {
0x01020304,
0x7f000001,
(192 << 24) | (168 << 16) | 100,
0xffffffff
};
String[] invalidIPs = {
"",
".",
"1.2..3.4",
"1.2.3.4.",
"257.11.225.1",
"256.11.225.1",
"-1.2.3.4",
"1.2.3.4.5",
"1.x.3.4",
"1.2x.3.4"
};
String[] ipsWithMask = {
"1.2.3.4/24",
"192.168.130.140/255.255.192.0",
"127.0.0.1/8",
"8.8.8.8",
"8.8.8.8/32",
"0.0.0.0/0",
"192.168.130.140/255.0.255.0",
"1.2.3.4/0.127.0.255"
};
boolean[] hasMask = {
true,
true,
true,
false,
false,
true,
true,
true
};
byte[][][] ipsWithMaskValues = {
new byte[][] { new byte[] { (byte)0x01, (byte)0x02, (byte)0x03, (byte)0x04 }, new byte[] { (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0x00 } },
new byte[][] { new byte[] { (byte)0xC0, (byte)0xA8, (byte)0x82, (byte)0x8C }, new byte[] { (byte)0xFF, (byte)0xFF, (byte)0xC0, (byte)0x00 } },
new byte[][] { new byte[] { (byte)0x7F, (byte)0x00, (byte)0x00, (byte)0x01 }, new byte[] { (byte)0xFF, (byte)0x00, (byte)0x00, (byte)0x00 } },
new byte[][] { new byte[] { (byte)0x08, (byte)0x08, (byte)0x08, (byte)0x08 }, new byte[] { (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF } },
new byte[][] { new byte[] { (byte)0x08, (byte)0x08, (byte)0x08, (byte)0x08 }, new byte[] { (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF } },
new byte[][] { new byte[] { (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00 }, new byte[] { (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00 } },
new byte[][] { new byte[] { (byte)0xC0, (byte)0xA8, (byte)0x82, (byte)0x8C }, new byte[] { (byte)0xFF, (byte)0x00, (byte)0xFF, (byte)0x00 } },
new byte[][] { new byte[] { (byte)0x01, (byte)0x02, (byte)0x03, (byte)0x04 }, new byte[] { (byte)0x00, (byte)0x7F, (byte)0x00, (byte)0xFF } }
};
int[] ipsWithMaskLengths = {
24,
18,
8,
32,
32,
0,
-1,
-1
};
String[] invalidIpsWithMask = {
"asdf",
"1.2.3.4/33",
"1.2.3.4/34",
"1.2.3.4/-1",
"1.2.3.4/256.0.0.0",
"1.256.3.4/255.255.0.0",
"1.2.3.4/255.255.0.0.0",
};
@Test
public void testLogicalOperatorsBroadcast() {
assertTrue(IPv4Address.NO_MASK.not().equals(IPv4Address.FULL_MASK));
assertTrue(IPv4Address.NO_MASK.or(IPv4Address.FULL_MASK).
equals(IPv4Address.NO_MASK));
assertTrue(IPv4Address.NO_MASK.and(IPv4Address.FULL_MASK).
equals(IPv4Address.FULL_MASK));
assertTrue(IPv4Address.NO_MASK.isBroadcast());
assertTrue(!IPv4Address.FULL_MASK.isBroadcast());
}
@Test
public void testMaskedSubnetBroadcast() {
assertTrue(IPv4AddressWithMask.of("10.10.10.1/24")
.getSubnetBroadcastAddress()
.equals(IPv4Address.of("10.10.10.255")));
assertTrue(IPv4AddressWithMask.of("10.10.10.1/24")
.isSubnetBroadcastAddress(IPv4Address.of("10.10.10.255")));
assertTrue(!IPv4AddressWithMask.of("10.10.10.1/24")
.isSubnetBroadcastAddress(IPv4Address.of("10.10.10.254")));
}
@Test
public void testMaskedMatchesCidr() {
IPv4AddressWithMask slash28 = IPv4AddressWithMask.of("10.0.42.16/28");
String[] notContained = {"0.0.0.0", "11.0.42.16", "10.0.41.1", "10.0.42.0", "10.0.42.15",
"10.0.42.32", "255.255.255.255" };
for(String n: notContained) {
assertThat(String.format("slash 28 %s should not contain address %s",
slash28, n),
slash28.matches(IPv4Address.of(n)), equalTo(false));
}
for(int i=16; i < 32; i++) {
IPv4Address c = IPv4Address.of(String.format("10.0.42.%d", i));
assertThat(String.format("slash 28 %s should contain address %s",
slash28, c),
slash28.matches(c), equalTo(true));
}
}
@Test
public void testMaskedMatchesArbitrary() {
// irregular octect on the 3rd bitmask requires '1'bit to be set
// 4 bit unset, all others arbitrary
IPv4AddressWithMask slash28 = IPv4AddressWithMask.of("1.2.1.4/255.255.5.255");
String[] notContained = {"0.0.0.0", "1.2.3.5", "1.2.3.3",
"1.2.0.4", "1.2.2.4", "1.2.4.4", "1.2.5.4", "1.2.6.4", "1.2.7.4",
"1.2.8.4", "1.2.12.4", "1.2.13.4"
};
String[] contained = {"1.2.1.4", "1.2.3.4", "1.2.9.4", "1.2.11.4", "1.2.251.4",
};
for(String n: notContained) {
assertThat(String.format("slash 28 %s should not contain address %s",
slash28, n),
slash28.matches(IPv4Address.of(n)), equalTo(false));
}
for(String c: contained) {
IPv4Address addr = IPv4Address.of(c);
assertThat(String.format("slash 28 %s should contain address %s",
slash28, addr),
slash28.matches(addr), equalTo(true));
}
}
@Test
public void testConstants() {
byte[] zeros = { (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00 };
byte[] ones = { (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF };
// Make sure class initializtation and static assignment don't get
// messed up. Test everything twice for cached values
assertTrue(IPv4Address.NONE.isCidrMask());
assertEquals(0, IPv4Address.NONE.asCidrMaskLength());
assertArrayEquals(zeros, IPv4Address.NONE.getBytes());
assertTrue(IPv4Address.NONE.isCidrMask());
assertEquals(0, IPv4Address.NONE.asCidrMaskLength());
assertArrayEquals(zeros, IPv4Address.NONE.getBytes());
assertTrue(IPv4Address.NO_MASK.isCidrMask());
assertEquals(32, IPv4Address.NO_MASK.asCidrMaskLength());
assertArrayEquals(ones, IPv4Address.NO_MASK.getBytes());
assertTrue(IPv4Address.NO_MASK.isCidrMask());
assertEquals(32, IPv4Address.NO_MASK.asCidrMaskLength());
assertArrayEquals(ones, IPv4Address.NO_MASK.getBytes());
assertTrue(IPv4Address.FULL_MASK.isCidrMask());
assertEquals(0, IPv4Address.FULL_MASK.asCidrMaskLength());
assertArrayEquals(zeros, IPv4Address.FULL_MASK.getBytes());
assertTrue(IPv4Address.FULL_MASK.isCidrMask());
assertEquals(0, IPv4Address.FULL_MASK.asCidrMaskLength());
assertArrayEquals(zeros, IPv4Address.FULL_MASK.getBytes());
}
@Test
public void testOfString() {
for(int i=0; i < testAddresses.length; i++ ) {
IPv4Address ip = IPv4Address.of(testStrings[i]);
assertEquals(testInts[i], ip.getInt());
assertArrayEquals(testAddresses[i], ip.getBytes());
assertEquals(testStrings[i], ip.toString());
}
}
@Test
public void testOfByteArray() {
for(int i=0; i < testAddresses.length; i++ ) {
IPv4Address ip = IPv4Address.of(testAddresses[i]);
assertEquals(testInts[i], ip.getInt());
assertArrayEquals(testAddresses[i], ip.getBytes());
assertEquals(testStrings[i], ip.toString());
}
}
@Test
public void testReadFrom() throws OFParseError {
for(int i=0; i < testAddresses.length; i++ ) {
IPv4Address ip = IPv4Address.read4Bytes(ChannelBuffers.copiedBuffer(testAddresses[i]));
assertEquals(testInts[i], ip.getInt());
assertArrayEquals(testAddresses[i], ip.getBytes());
assertEquals(testStrings[i], ip.toString());
}
}
@Test
public void testInvalidIPs() throws OFParseError {
for(String invalid : invalidIPs) {
try {
IPv4Address.of(invalid);
fail("Invalid IP "+invalid+ " should have raised IllegalArgumentException");
} catch(IllegalArgumentException e) {
// ok
}
}
}
@Test
public void testOfMasked() throws OFParseError {
for (int i = 0; i < ipsWithMask.length; i++) {
IPv4AddressWithMask value = IPv4AddressWithMask.of(ipsWithMask[i]);
if (!hasMask[i]) {
IPv4Address ip = value.getValue();
assertArrayEquals(ipsWithMaskValues[i][0], ip.getBytes());
}
IPv4Address mask = value.getMask();
if (ipsWithMaskLengths[i] == -1) {
assertFalse(mask.isCidrMask());
try {
mask.asCidrMaskLength();
fail("Expected IllegalStateException not thrown");
} catch(IllegalStateException e) {
//expected
}
} else {
assertTrue(mask.isCidrMask());
assertEquals(ipsWithMaskLengths[i], mask.asCidrMaskLength());
}
assertArrayEquals(ipsWithMaskValues[i][1], mask.getBytes());
byte[] ipBytes = new byte[4];
System.arraycopy(ipsWithMaskValues[i][0], 0, ipBytes, 0, 4);
assertEquals(ipBytes.length, value.getValue().getBytes().length);
for (int j = 0; j < ipBytes.length; j++) {
ipBytes[j] &= ipsWithMaskValues[i][1][j];
}
assertArrayEquals(ipBytes, value.getValue().getBytes());
assertThat(String.format("Byte comparison for mask of %s (%s)", ipsWithMask[i], value),
value.getMask().getBytes(), CoreMatchers.equalTo(ipsWithMaskValues[i][1]));
}
}
@Test
public void testOfMaskedInvalid() throws Exception {
for(String invalid : invalidIpsWithMask) {
try {
IPv4Address.of(invalid);
fail("Invalid IP "+invalid+ " should have raised IllegalArgumentException");
} catch(IllegalArgumentException e) {
// ok
}
}
}
@Test
public void testSuperclass() throws Exception {
for(String ipString: testStrings) {
IPAddress<?> superIp = IPAddress.of(ipString);
assertEquals(IPVersion.IPv4, superIp.getIpVersion());
assertEquals(IPv4Address.of(ipString), superIp);
}
for(String ipMaskedString: ipsWithMask) {
IPAddressWithMask<?> superIp = IPAddressWithMask.of(ipMaskedString);
assertEquals(IPVersion.IPv4, superIp.getIpVersion());
assertEquals(IPv4AddressWithMask.of(ipMaskedString), superIp);
}
}
@Test
public void testOfExceptions() {
// We check if the message of a caught NPE is set to a useful message
// as a hacky way of verifying that we got an NPE thrown by use rather
// than one the JVM created for a null access.
try {
String s = null;
IPv4Address.of(s);
fail("Should have thrown NullPointerException");
} catch (NullPointerException e) {
assertNotNull(e.getMessage());
}
try {
byte[] b = null;
IPv4Address.of(b);
fail("Should have thrown NullPointerException");
} catch (NullPointerException e) {
assertNotNull(e.getMessage());
}
try {
byte[] b = new byte[3];
IPv4Address.of(b);
fail("Should have thrown IllegalArgumentException");
} catch (IllegalArgumentException e) {
// expected
}
try {
byte[] b = new byte[5];
IPv4Address.of(b);
fail("Should have thrown IllegalArgumentException");
} catch (IllegalArgumentException e) {
// expected
}
try {
IPv4AddressWithMask.of(null);
fail("Should have thrown NullPointerException");
} catch (NullPointerException e) {
assertNotNull(e.getMessage());
}
try {
IPv4AddressWithMask.of(IPv4Address.of("1.2.3.4"), null);
fail("Should have thrown NullPointerException");
} catch (NullPointerException e) {
assertNotNull(e.getMessage());
}
try {
IPv4AddressWithMask.of(null, IPv4Address.of("255.0.0.0"));
fail("Should have thrown NullPointerException");
} catch (NullPointerException e) {
assertNotNull(e.getMessage());
}
try {
IPv4AddressWithMask.of(IPv4Address.of("10.10.10.0"),
IPv4Address.of("255.0.255.0"))
.getSubnetBroadcastAddress();
fail("Should have thrown IllegalArgumentException");
} catch (IllegalArgumentException e) {
assertNotNull(e.getMessage());
}
}
}
package org.projectfloodlight.openflow.types;
import static org.junit.Assert.*;
import java.net.Inet6Address;
import java.net.InetAddress;
import java.net.UnknownHostException;
import org.hamcrest.CoreMatchers;
import org.jboss.netty.buffer.ChannelBuffers;
import org.junit.Test;
import org.projectfloodlight.openflow.exceptions.OFParseError;
import com.google.common.io.BaseEncoding;
public class IPv6AddressTest {
String[] testStrings = {
"::",
"::1",
"ffe0::",
"1:2:3:4:5:6:7:8"
};
private final BaseEncoding hex = BaseEncoding.base16().omitPadding().lowerCase();
private class WithMaskTaskCase {
final String input;
boolean hasMask;
int expectedMaskLength = 128;
byte[] expectedMask = hex.decode("ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff".replaceAll(" ", ""));
public WithMaskTaskCase(String input) {
super();
this.input = input;
}
public WithMaskTaskCase maskHex(String string) {
string = string.replaceAll(" ", "");
this.hasMask = true;
expectedMask = hex.decode(string);
return this;
}
public WithMaskTaskCase expectedMaskLength(int expectedLength) {
this.expectedMaskLength = expectedLength;
return this;
}
}
WithMaskTaskCase[] withMasks = new WithMaskTaskCase[] {
new WithMaskTaskCase("1::1/80")
.maskHex("ff ff ff ff ff ff ff ff ff ff 00 00 00 00 00 00")
.expectedMaskLength(80),
new WithMaskTaskCase("ffff:ffee:1::/ff00:ff00:ff00:ff00::")
.maskHex("ff 00 ff 00 ff 00 ff 00 00 00 00 00 00 00 00 00")
.expectedMaskLength(-1),
new WithMaskTaskCase("1:2:3:4:5:6:7:8/1::ff00:ff00")
.maskHex("00 01 00 00 00 00 00 00 00 00 00 00 ff 00 ff 00")
.expectedMaskLength(-1),
new WithMaskTaskCase("1:2:3:4:5:6:7:8/::ff00:ff00")
.maskHex("00 00 00 00 00 00 00 00 00 00 00 00 ff 00 ff 00")
.expectedMaskLength(-1),
new WithMaskTaskCase("1:2:3:4:5:6:7:8/ffff:ffff:ffff:ffff:ffff::ff00:ff00")
.maskHex("ff ff ff ff ff ff ff ff ff ff 00 00 ff 00 ff 00")
.expectedMaskLength(-1),
new WithMaskTaskCase("8:8:8:8:8:8:8:8"),
new WithMaskTaskCase("8:8:8:8:8:8:8:8"),
new WithMaskTaskCase("1:2:3:4:5:6:7:8/128"),
new WithMaskTaskCase("::/0")
.maskHex("00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00")
.expectedMaskLength(0),
};
@Test
public void testLogicalOperatorsBroadcast() {
assertTrue(IPv6Address.NO_MASK.not().equals(IPv6Address.FULL_MASK));
assertTrue(IPv6Address.NO_MASK.or(IPv6Address.FULL_MASK).
equals(IPv6Address.NO_MASK));
assertTrue(IPv6Address.NO_MASK.and(IPv6Address.FULL_MASK).
equals(IPv6Address.FULL_MASK));
assertTrue(IPv6Address.NO_MASK.isBroadcast());
assertTrue(!IPv6Address.FULL_MASK.isBroadcast());
}
@Test
public void testMaskedSubnetBroadcast() {
assertTrue(IPv6AddressWithMask.of("10:10::1/112")
.getSubnetBroadcastAddress()
.equals(IPv6Address.of("10:10::ffff")));
assertTrue(IPv6AddressWithMask.of("10:10::1/112")
.isSubnetBroadcastAddress(IPv6Address.of("10:10::ffff")));
assertTrue(!IPv6AddressWithMask.of("10:10::1/112")
.isSubnetBroadcastAddress(IPv6Address.of("10:10::fffd")));
}
@Test
public void testConstants() {
byte[] zeros = { (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00,
(byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00,
(byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00,
(byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00 };
byte[] ones = { (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 };
// Make sure class initializtation and static assignment don't get
// messed up. Test everything twice for cached values
assertTrue(IPv6Address.NONE.isCidrMask());
assertEquals(0, IPv6Address.NONE.asCidrMaskLength());
assertArrayEquals(zeros, IPv6Address.NONE.getBytes());
assertTrue(IPv6Address.NONE.isCidrMask());
assertEquals(0, IPv6Address.NONE.asCidrMaskLength());
assertArrayEquals(zeros, IPv6Address.NONE.getBytes());
assertTrue(IPv6Address.NO_MASK.isCidrMask());
assertEquals(128, IPv6Address.NO_MASK.asCidrMaskLength());
assertArrayEquals(ones, IPv6Address.NO_MASK.getBytes());
assertTrue(IPv6Address.NO_MASK.isCidrMask());
assertEquals(128, IPv6Address.NO_MASK.asCidrMaskLength());
assertArrayEquals(ones, IPv6Address.NO_MASK.getBytes());
assertTrue(IPv6Address.FULL_MASK.isCidrMask());
assertEquals(0, IPv6Address.FULL_MASK.asCidrMaskLength());
assertArrayEquals(zeros, IPv6Address.FULL_MASK.getBytes());
assertTrue(IPv6Address.FULL_MASK.isCidrMask());
assertEquals(0, IPv6Address.FULL_MASK.asCidrMaskLength());
assertArrayEquals(zeros, IPv6Address.FULL_MASK.getBytes());
}
@Test
public void testMasked() throws UnknownHostException {
for(WithMaskTaskCase w: withMasks) {
IPv6AddressWithMask value = IPv6AddressWithMask.of(w.input);
if (!w.hasMask) {
IPv6Address ip = value.getValue();
InetAddress inetAddress = InetAddress.getByName(w.input.split("/")[0]);
assertArrayEquals(ip.getBytes(), inetAddress.getAddress());
assertEquals(w.input.split("/")[0], ip.toString());
}
InetAddress inetAddress = InetAddress.getByName(w.input.split("/")[0]);
if (w.expectedMaskLength == -1) {
assertFalse(value.getMask().isCidrMask());
try {
value.getMask().asCidrMaskLength();
fail("Expected IllegalStateException not thrown");
} catch(IllegalStateException e) {
//expected
}
} else {
assertTrue(value.getMask().isCidrMask());
assertEquals("Input " + w.input, w.expectedMaskLength,
value.getMask().asCidrMaskLength());
}
byte[] address = inetAddress.getAddress();
assertEquals(address.length, value.getValue().getBytes().length);
for (int j = 0; j < address.length; j++) {
address[j] &= w.expectedMask[j];
}
assertThat("Address bytes for input " + w.input + ", value=" + value, value.getValue().getBytes(), CoreMatchers.equalTo(address));
assertThat("mask check for input " + w.input + ", value=" + value, value.getMask().getBytes(), CoreMatchers.equalTo(w.expectedMask));
}
for (int i = 0; i <= 128; i++) {
String ipString = String.format("8001:2::1/%d", i);
IPv6AddressWithMask value = IPv6AddressWithMask.of(ipString);
assertEquals("Input " + ipString, i, value.getMask().asCidrMaskLength());
}
}
@Test
public void testOfString() throws UnknownHostException {
for(int i=0; i < testStrings.length; i++ ) {
IPv6Address ip = IPv6Address.of(testStrings[i]);
InetAddress inetAddress = InetAddress.getByName(testStrings[i]);
assertArrayEquals(ip.getBytes(), inetAddress.getAddress());
assertEquals(testStrings[i], ip.toString());
}
}
@Test
public void testOfByteArray() throws UnknownHostException {
for(int i=0; i < testStrings.length; i++ ) {
byte[] bytes = Inet6Address.getByName(testStrings[i]).getAddress();
IPv6Address ip = IPv6Address.of(bytes);
assertEquals(testStrings[i], ip.toString());
assertArrayEquals(bytes, ip.getBytes());
}
}
@Test
public void testReadFrom() throws OFParseError, UnknownHostException {
for(int i=0; i < testStrings.length; i++ ) {
byte[] bytes = Inet6Address.getByName(testStrings[i]).getAddress();
IPv6Address ip = IPv6Address.read16Bytes(ChannelBuffers.copiedBuffer(bytes));
assertEquals(testStrings[i], ip.toString());
assertArrayEquals(bytes, ip.getBytes());
}
}
String[] invalidIPs = {
"",
":",
"1:2:3:4:5:6:7:8:9",
"1:2:3:4:5:6:7:8:",
"1:2:3:4:5:6:7:8g",
"1:2:3:",
"12345::",
"1::3::8",
"::3::"
};
@Test
public void testInvalidIPs() throws OFParseError {
for(String invalid : invalidIPs) {
try {
IPv6Address.of(invalid);
fail("Invalid IP "+invalid+ " should have raised IllegalArgumentException");
} catch(IllegalArgumentException e) {
// ok
}
}
}
@Test
public void testZeroCompression() throws OFParseError {
assertEquals("::", IPv6Address.of("::").toString(true, false));
assertEquals("0:0:0:0:0:0:0:0", IPv6Address.of("::").toString(false, false));
assertEquals("0000:0000:0000:0000:0000:0000:0000:0000", IPv6Address.of("::").toString(false, true));
assertEquals("1::4:5:6:0:8", IPv6Address.of("1:0:0:4:5:6:0:8").toString(true, false));
assertEquals("1:0:0:4::8", IPv6Address.of("1:0:0:4:0:0:0:8").toString(true, false));
}
@Test
public void testSuperclass() throws Exception {
for(String ipString: testStrings) {
IPAddress<?> superIp = IPAddress.of(ipString);
assertEquals(IPVersion.IPv6, superIp.getIpVersion());
assertEquals(IPv6Address.of(ipString), superIp);
}
for(WithMaskTaskCase w: withMasks) {
String ipMaskedString = w.input;
IPAddressWithMask<?> superIp = IPAddressWithMask.of(ipMaskedString);
assertEquals(IPVersion.IPv6, superIp.getIpVersion());
assertEquals(IPv6AddressWithMask.of(ipMaskedString), superIp);
}
}
@Test
public void testOfExceptions() throws Exception {
try {
IPv6AddressWithMask.of(null);
fail("Should have thrown NullPointerException");
} catch (NullPointerException e) {
assertNotNull(e.getMessage());
}
try {
String s = null;
IPv6Address.of(s);
fail("Should have thrown NullPointerException");
} catch (NullPointerException e) {
assertNotNull(e.getMessage());
}
try {
byte[] b = null;
IPv6Address.of(b);
fail("Should have thrown NullPointerException");
} catch (NullPointerException e) {
assertNotNull(e.getMessage());
}
try {
byte[] b = new byte[7];
IPv6Address.of(b);
fail("Should have thrown IllegalArgumentException");
} catch (IllegalArgumentException e) {
// expected
}
try {
byte[] b = new byte[9];
IPv6Address.of(b);
fail("Should have thrown IllegalArgumentException");
} catch (IllegalArgumentException e) {
// expected
}
try {
IPv6AddressWithMask.of(IPv6Address.of("1::"), null);
fail("Should have thrown NullPointerException");
} catch (NullPointerException e) {
assertNotNull(e.getMessage());
}
try {
IPv6AddressWithMask.of(null, IPv6Address.of("255::"));
fail("Should have thrown NullPointerException");
} catch (NullPointerException e) {
assertNotNull(e.getMessage());
}
try {
IPv6AddressWithMask.of(IPv6Address.of("10:10::0"),
IPv6Address.of("ffff:0:ffff::"))
.getSubnetBroadcastAddress();
fail("Should have thrown IllegalArgumentException");
} catch (IllegalArgumentException e) {
assertNotNull(e.getMessage());
}
}
}
package org.projectfloodlight.openflow.types;
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import java.util.Arrays;
import org.jboss.netty.buffer.ChannelBuffers;
import org.junit.Test;
import org.projectfloodlight.openflow.exceptions.OFParseError;
public class MacAddressTest {
byte[][] testAddresses = new byte[][] {
{0x01, 0x02, 0x03, 0x04, 0x05, 0x06 },
{(byte) 0x80, 0x0, 0x0, 0x0, 0x0, 0x01},
{(byte) 255, (byte) 255, (byte) 255, (byte) 255, (byte) 255, (byte) 255 }
};
String[] testStrings = {
"01:02:03:04:05:06",
"80:00:00:00:00:01",
"ff:ff:ff:ff:ff:ff"
};
long[] testInts = {
0x00010203040506L,
0x00800000000001L,
0x00ffffffffffffL
};
String[] invalidMacStrings = {
"",
"1.2.3.4",
"0T:00:01:02:03:04",
"00:01:02:03:04:05:06",
"00:ff:ef:12:12:ff:",
"00:fff:ef:12:12:ff",
"01:02:03:04:05;06",
"0:1:2:3:4:5:6",
"01:02:03:04"
};
byte[][] invalidMacBytes = {
new byte[]{0x01, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06},
new byte[]{0x01, 0x01, 0x02, 0x03, 0x04}
};
@Test
public void testOfString() {
for(int i=0; i < testAddresses.length; i++ ) {
MacAddress ip = MacAddress.of(testStrings[i]);
assertEquals(testInts[i], ip.getLong());
assertArrayEquals(testAddresses[i], ip.getBytes());
assertEquals(testStrings[i], ip.toString());
}
}
@Test
public void testOfByteArray() {
for(int i=0; i < testAddresses.length; i++ ) {
MacAddress ip = MacAddress.of(testAddresses[i]);
assertEquals("error checking long representation of "+Arrays.toString(testAddresses[i]) + "(should be "+Long.toHexString(testInts[i]) +")", testInts[i], ip.getLong());
assertArrayEquals(testAddresses[i], ip.getBytes());
assertEquals(testStrings[i], ip.toString());
}
}
@Test
public void testReadFrom() throws OFParseError {
for(int i=0; i < testAddresses.length; i++ ) {
MacAddress ip = MacAddress.read6Bytes(ChannelBuffers.copiedBuffer(testAddresses[i]));
assertEquals(testInts[i], ip.getLong());
assertArrayEquals(testAddresses[i], ip.getBytes());
assertEquals(testStrings[i], ip.toString());
}
}
@Test
public void testInvalidMacStrings() throws OFParseError {
for(String invalid : invalidMacStrings) {
try {
MacAddress.of(invalid);
fail("Invalid MAC address "+invalid+ " should have raised IllegalArgumentException");
} catch(IllegalArgumentException e) {
// ok
}
}
}
@Test
public void testInvalidMacBytes() throws OFParseError {
for(byte[] invalid : invalidMacBytes) {
try {
MacAddress.of(invalid);
fail("Invalid MAC address bytes "+ Arrays.toString(invalid) + " should have raised IllegalArgumentException");
} catch(IllegalArgumentException e) {
// ok
}
}
}
// Test data is imported from org.projectfloodlight.packet.EthernetTest
@Test
public void testToLong() {
assertEquals(
281474976710655L,
MacAddress.of(new byte[]{(byte) 0xff, (byte) 0xff,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff}).getLong());
assertEquals(
1103823438081L,
MacAddress.of(new byte[] { (byte) 0x01, (byte) 0x01,
(byte) 0x01, (byte) 0x01, (byte) 0x01, (byte) 0x01 }).getLong());
assertEquals(
141289400074368L,
MacAddress.of(new byte[] { (byte) 0x80, (byte) 0x80,
(byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0x80 }).getLong());
}
@Test
public void testIsBroadcast() {
assertTrue(MacAddress.of("FF:FF:FF:FF:FF:FF").isBroadcast());
assertTrue(MacAddress.of(-1).isBroadcast());
assertTrue(MacAddress.of(0x05FFFFFFFFFFFFL).isBroadcast());
assertFalse(MacAddress.of("11:22:33:44:55:66").isBroadcast());
}
@Test
public void testIsMulticast() {
assertTrue(MacAddress.of("01:80:C2:00:00:00").isMulticast());
assertFalse(MacAddress.of("00:80:C2:00:00:00").isMulticast());
assertFalse(MacAddress.of("FE:80:C2:00:00:00").isMulticast());
assertFalse(MacAddress.of(-1).isMulticast());
assertFalse(MacAddress.of(0x05FFFFFFFFFFFFL).isMulticast());
assertFalse(MacAddress.of("FF:FF:FF:FF:FF:FF").isMulticast());
}
@Test
public void testIsLLDPAddress() {
assertTrue(MacAddress.of("01:80:C2:00:00:00").isLLDPAddress());
assertTrue(MacAddress.of("01:80:C2:00:00:0f").isLLDPAddress());
assertFalse(MacAddress.of("01:80:C2:00:00:50").isLLDPAddress());
assertFalse(MacAddress.of("01:80:C2:00:10:00").isLLDPAddress());
assertFalse(MacAddress.of("01:80:C2:40:00:01").isLLDPAddress());
assertFalse(MacAddress.of("00:80:C2:f0:00:00").isLLDPAddress());
assertFalse(MacAddress.of("FE:80:C2:00:00:00").isLLDPAddress());
}
}
package org.projectfloodlight.openflow.types;
import static org.hamcrest.CoreMatchers.equalTo;
import static org.junit.Assert.assertThat;
import org.hamcrest.Matchers;
import org.jboss.netty.buffer.ChannelBuffer;
import org.jboss.netty.buffer.ChannelBuffers;
import org.junit.Test;
import org.projectfloodlight.openflow.protocol.OFFactories;
import org.projectfloodlight.openflow.protocol.OFFlowAdd;
import org.projectfloodlight.openflow.protocol.OFVersion;
public class OFErrorCauseDataTest {
@Test
public void testEmpty() {
OFErrorCauseData emptyCause = OFErrorCauseData.of(new byte[] {}, OFVersion.OF_13);
assertThat(emptyCause.getData(), equalTo(new byte[] {}));
assertThat(emptyCause.getParsedMessage().isPresent(), equalTo(false));
assertThat(emptyCause.toString(), Matchers.containsString("unparsed"));
}
@Test
public void testTooShort() {
OFErrorCauseData emptyCause = OFErrorCauseData.of(new byte[] {0x1, 0x2}, OFVersion.OF_13);
assertThat(emptyCause.getData(), equalTo(new byte[] {0x1, 0x2}));
assertThat(emptyCause.getParsedMessage().isPresent(), equalTo(false));
assertThat(emptyCause.toString(), Matchers.containsString("unparsed"));
assertThat(emptyCause.toString(), Matchers.containsString("01 02"));
}
byte[] truncatedFlowAddd = new byte[] {
0x04, 0x0e, // version, type
0x00, (byte) 0x80, // length
0x12, 0x34, 0x56, 0x78, // xid
(byte) 0xfe, (byte) 0xdc , (byte) 0xba, (byte) 0x98, 0x76, 0x54, 0x32, 0x10, // cookie
(byte) 0xff, 0x00, (byte) 0xff, 0x00, (byte) 0xff, 0x00, (byte) 0xff, 0x00, // cookie_mask
0x03 // table_id
// rest truncated
};
@Test
public void testTruncated() {
OFErrorCauseData emptyCause = OFErrorCauseData.of(truncatedFlowAddd, OFVersion.OF_13);
assertThat(emptyCause.getData(), equalTo(truncatedFlowAddd));
assertThat(emptyCause.getParsedMessage().isPresent(), equalTo(false));
assertThat(emptyCause.toString(), Matchers.containsString("unparsed"));
assertThat(emptyCause.toString(), Matchers.containsString("04 0e 00 80"));
}
@Test
public void testFlowAdd() {
OFFlowAdd flowAdd = OFFactories.getFactory(OFVersion.OF_13).buildFlowAdd()
.setXid(0x12345678)
.setCookie(U64.parseHex("FEDCBA9876543210"))
.setCookieMask(U64.parseHex("FF00FF00FF00FF00"))
.setTableId(TableId.of(3))
.setIdleTimeout(5)
.setHardTimeout(10)
.setPriority(6000)
.build();
ChannelBuffer bb = ChannelBuffers.dynamicBuffer();
flowAdd.writeTo(bb);
byte[] flowAddBytes = new byte[bb.readableBytes()];
bb.readBytes(flowAddBytes);
OFErrorCauseData emptyCause = OFErrorCauseData.of(flowAddBytes, OFVersion.OF_13);
assertThat(emptyCause.getData(), equalTo(flowAddBytes));
assertThat(emptyCause.getParsedMessage().isPresent(), equalTo(true));
assertThat(emptyCause.toString(), Matchers.containsString("OFFlowAdd"));
assertThat(emptyCause.toString(), Matchers.containsString("idleTimeout=5"));
}
}
package org.projectfloodlight.openflow.types;
import static org.hamcrest.Matchers.contains;
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertThat;
import junit.framework.TestCase;
import org.junit.Test;
public class OFPortBitMapTest extends TestCase {
@Test
public void testCreateAndIterate() {
OFPortBitMap map = OFPortBitMap.ofPorts(OFPort.of(1), OFPort.of(2), OFPort.of(5));
assertThat(map.getOnPorts(), contains(OFPort.of(1), OFPort.of(2), OFPort.of(5)));
}
@Test
public void testOFBitMap() {
OFBitMask128 bitmap = OFBitMask128.of(0xFFFF_FFFF_FFFF_FFFFL, 0xFFFF_FFFF_FFFF_FFD9L);
OFPortBitMap map = OFPortBitMap.of(bitmap);
assertThat(map.getOnPorts(), contains(OFPort.of(1), OFPort.of(2), OFPort.of(5)));
}
@Test
public void testOFPortBitMap() {
Boolean[] on = new Boolean[127];
for (int i = 0; i < 127; i++) {
on[i] = false;
}
OFPortBitMap.Builder builder = new OFPortBitMap.Builder();
for (int i = 0; i < 127; i += 3) {
OFPort p = OFPort.of(i);
builder.set(p);
on[p.getPortNumber()] = true;
}
// Test that all ports that were added are actually on, and all other ports are off
OFPortBitMap portmap = builder.build();
//System.out.println(portmap);
Boolean[] actual = new Boolean[127];
for (int i = 0; i < 127; i++) {
actual[i] = false;
}
for (int i = 0; i < 127; i++) {
actual[i] = portmap.isOn(OFPort.of(i));
}
assertArrayEquals(on, actual);
// Turn some ports off
for (int i = 0; i < 127; i += 7) {
on[i] = false;
builder.unset(OFPort.of(i));
}
// Test again
portmap = builder.build();
actual = new Boolean[127];
for (int i = 0; i < 127; i++) {
actual[i] = false;
}
for (int i = 0; i < 127; i++) {
actual[i] = portmap.isOn(OFPort.of(i));
}
assertArrayEquals(on, actual);
}
}
package org.projectfloodlight.openflow.types;
import static org.hamcrest.CoreMatchers.equalTo;
import static org.junit.Assert.assertThat;
import org.hamcrest.CoreMatchers;
import org.junit.Test;
public class OFVlanVidMatchTest {
@Test
public void testofVlanVid() {
assertThat(
(int) OFVlanVidMatch.ofVlanVid(VlanVid.ofVlan(1)).getRawVid(),
equalTo(0x1001));
assertThat(
(int) OFVlanVidMatch.ofVlanVid(VlanVid.ofVlan(0xFFF)).getRawVid(),
equalTo(0x1FFF));
assertThat(OFVlanVidMatch.ofVlanVid(null), equalTo(OFVlanVidMatch.UNTAGGED));
assertThat(OFVlanVidMatch.ofVlanVid(VlanVid.NO_MASK),
equalTo(OFVlanVidMatch.NO_MASK));
// a fully masked VlanVid means "PRESENT" in OFVlanVid
// (because a VlanVid always specifies a Vlan)
assertThat(OFVlanVidMatch.ofVlanVid(VlanVid.FULL_MASK),
equalTo(OFVlanVidMatch.PRESENT));
}
@Test
public void testtoVlanVid() {
assertThat(
OFVlanVidMatch.ofRawVid((short)0x1001).getVlanVid(),
equalTo(VlanVid.ofVlan(1)));
assertThat(
OFVlanVidMatch.ofRawVid((short)0x1FFF).getVlanVid(),
equalTo(VlanVid.ofVlan(0xFFF)));
assertThat(OFVlanVidMatch.UNTAGGED.getVlanVid(), CoreMatchers.nullValue());
assertThat(
OFVlanVidMatch.NO_MASK.getVlanVid(),
equalTo(VlanVid.NO_MASK));
assertThat(
OFVlanVidMatch.PRESENT.getVlanVid(),
equalTo(VlanVid.FULL_MASK));
}
}
package org.projectfloodlight.openflow.types;
import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.CoreMatchers.not;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import org.hamcrest.Matchers;
import org.junit.Test;
import com.google.common.hash.HashCode;
import com.google.common.hash.Hasher;
import com.google.common.hash.Hashing;
public class U128Test {
@Test
public void testPositiveRaws() {
assertThat(U128.of(0, 0).getMsb(), equalTo(0L));
assertThat(U128.of(0, 0).getLsb(), equalTo(0L));
assertThat(U128.of(1, 2).getMsb(), equalTo(1L));
assertThat(U128.of(1, 2).getLsb(), equalTo(2L));
}
@Test
public void testPutTo() {
U128 h = U128.of(0x1234_5678_90ab_cdefL,0xdeafbeefdeadbeefL);
U128 hSame = U128.of(0x1234_5678_90ab_cdefL,0xdeafbeefdeadbeefL);
U128 hBothDiff = U128.of(0x1234_5678_90ab_cdefL,0x1234_5678_90ab_cdefL);
U128 hMsbDiff = U128.of(0x0234_5678_90ab_cdefL,0xdeafbeefdeadbeefL);
U128 hLsbDiff = U128.of(0x1234_5678_90ab_cdefL,0xdeafbeefdeadbeeeL);
assertThat(hash(h), equalTo(hash(hSame)));
assertThat(hash(h), not(hash(hBothDiff)));
assertThat(hash(h), not(hash(hMsbDiff)));
assertThat(hash(h), not(hash(hLsbDiff)));
}
private HashCode hash(U128 f) {
Hasher hash = Hashing.murmur3_128().newHasher();
f.putTo(hash);
return hash.hash();
}
@Test
public void testEqualHashCode() {
U128 h1 = U128.of(0xdeafbeefdeadbeefL, 0xdeafbeefdeadbeefL);
U128 h2 = U128.of(0xdeafbeefdeadbeefL, 0xdeafbeefdeadbeefL);
U128 h3 = U128.of(0xeeafbeefdeadbeefL, 0xdeafbeefdeadbeefL);
U128 h3_2 = U128.of(0xdeafbeefdeadbeefL, 0xeeafbeefdeadbeefL);
assertTrue(h1.equals(h1));
assertTrue(h1.equals(h2));
assertFalse(h1.equals(h3));
assertFalse(h1.equals(h3_2));
assertTrue(h2.equals(h1));
assertEquals(h1.hashCode(), h2.hashCode());
assertNotEquals(h1.hashCode(), h3.hashCode()); // not technically a requirement, but we'll hopefully be lucky.
assertNotEquals(h1.hashCode(), h3_2.hashCode()); // not technically a requirement, but we'll hopefully be lucky.
}
@Test
public void testXor() {
U128 hNull = U128.of(0, 0);
U128 hDeadBeef = U128.of(0xdeafbeefdeadbeefL, 0xdeafbeefdeadbeefL);
assertThat(hNull.xor(hNull), equalTo(hNull));
assertThat(hNull.xor(hDeadBeef), equalTo(hDeadBeef));
assertThat(hDeadBeef.xor(hNull), equalTo(hDeadBeef));
assertThat(hDeadBeef.xor(hDeadBeef), equalTo(hNull));
U128 h1_0 = U128.of(1L, 0);
U128 h8_0 = U128.of(0x8000000000000000L, 0);
U128 h81_0 = U128.of(0x8000000000000001L, 0);
assertThat(h1_0.xor(h8_0), equalTo(h81_0));
U128 h0_1 = U128.of(0, 1L);
U128 h0_8 = U128.of(0, 0x8000000000000000L);
U128 h0_81 = U128.of(0, 0x8000000000000001L);
assertThat(h0_1.xor(h0_8), equalTo(h0_81));
}
@Test
public void testKeyBits() {
U128 zeroU = U128.of(0,0);
assertThat(zeroU.prefixBits(0), equalTo(0));
assertThat(zeroU.prefixBits(16), equalTo(0));
assertThat(zeroU.prefixBits(32), equalTo(0));
checkInvalidKeyBitSize(zeroU, 33);
checkInvalidKeyBitSize(zeroU, 64);
assertThat(zeroU.prefixBits(3), equalTo(0));
U128 positiveU = U128.of(0x1234_5678_1234_5678L, 0x1234_5678_1234_5678L);
assertThat(positiveU.prefixBits(0), equalTo(0));
assertThat(positiveU.prefixBits(16), equalTo(0x1234));
assertThat(positiveU.prefixBits(32), equalTo(0x12345678));
checkInvalidKeyBitSize(positiveU, 33);
checkInvalidKeyBitSize(positiveU, 64);
U128 signedBitU = U128.of(0x8765_4321_8765_4321L, 0x1234_5678_1234_5678L);
assertThat(signedBitU.prefixBits(0), equalTo(0));
assertThat(signedBitU.prefixBits(16), equalTo(0x8765));
assertThat(signedBitU.prefixBits(32), equalTo(0x8765_4321));
checkInvalidKeyBitSize(signedBitU, 33);
checkInvalidKeyBitSize(signedBitU, 64);
}
private void
checkInvalidKeyBitSize(U128 u, int prefixBit) {
try {
u.prefixBits(prefixBit);
fail("Expected exception not thrown for "+prefixBit + " bits");
} catch(IllegalArgumentException e) {
// expected
}
}
@Test
public void testCompare() {
U128 u0_0 = U128.of(0, 0);
U128 u0_1 = U128.of(0, 1);
U128 u0_8 = U128.of(0, 0x8765_4321_8765_4321L);
U128 u1_0 = U128.of(0x1234_5678_1234_5678L, 0);
U128 u8_0 = U128.of(0x8765_4321_8765_4321L, 0);
U128 uf_0 = U128.of(0xFFFF_FFFF_FFFF_FFFFL, 0);
U128[] us = new U128[] { u0_0, u0_1, u0_8, u1_0, u8_0, uf_0 };
for(int i = 0; i< us.length; i++) {
U128 u_base = us[i];
assertThat(
String.format("%s should be equal to itself (compareTo)", u_base),
u_base.compareTo(u_base), equalTo(0));
assertThat(
String.format("%s should be equal to itself (equals)", u_base),
u_base.equals(u_base), equalTo(true));
assertThat(
String.format("%s should be equal to itself (equals, by value)", u_base),
u_base.equals(U128.of(u_base.getMsb(), u_base.getLsb())), equalTo(true));
for(int j = i+1; j< us.length; j++) {
U128 u_greater = us[j];
assertThat(
String.format("%s should not be equal to %s", u_base, u_greater),
u_base.equals(u_base), equalTo(true));
assertThat(
String.format("%s should be smaller than %s", u_base, u_greater),
u_base.compareTo(u_greater), Matchers.lessThan(0));
assertThat(
String.format("%s should be greater than %s", u_greater, u_base),
u_greater.compareTo(u_base), Matchers.greaterThan(0));
}
}
}
@Test
public void testCombine() {
long key = 0x1234567890abcdefL;
long val = 0xdeafbeefdeadbeefL;
U128 hkey = U128.of(key, key*2);
U128 hVal = U128.of(val, val/2);
assertThat(hkey.combineWithValue(hVal, 0), equalTo(hkey.xor(hVal)));
assertThat(hkey.combineWithValue(hVal, 64), equalTo(U128.of(hkey.getMsb(), hkey.getLsb() ^ hVal.getLsb())));
assertThat(hkey.combineWithValue(hVal, 128), equalTo(hkey));
long mask8 = 0xFF00_0000_0000_0000L;
assertThat(hkey.combineWithValue(hVal, 8), equalTo(U128.of(hkey.getMsb() & mask8 | hkey.getMsb() ^ hVal.getMsb() & ~mask8,
hkey.getLsb() ^ hVal.getLsb() )));
}
}
package org.projectfloodlight.openflow.types;
import static org.hamcrest.CoreMatchers.equalTo;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import java.math.BigInteger;
import org.junit.Test;
public class U64Test {
@Test
public void testPositiveRaws() {
for(long positive: new long[] { 0, 1, 100, Long.MAX_VALUE }) {
assertEquals(positive, U64.ofRaw(positive).getValue());
assertEquals(BigInteger.valueOf(positive), U64.ofRaw(positive).getBigInteger());
}
}
@Test
public void testNegativeRaws() {
long minus_1 = 0xFFFF_FFFF_FFFF_FFFFL;
assertEquals(minus_1, U64.ofRaw(minus_1).getValue());
assertEquals(new BigInteger("FFFF_FFFF_FFFF_FFFF".replace("_", ""), 16), U64.ofRaw(minus_1).getBigInteger());
assertEquals(new BigInteger("18446744073709551615"), U64.ofRaw(minus_1).getBigInteger());
}
@Test
public void testEqualHashCode() {
U64 h1 = U64.of(0xdeafbeefdeadbeefL);
U64 h2 = U64.of(0xdeafbeefdeadbeefL);
U64 h3 = U64.of(0xeeafbeefdeadbeefL);
assertTrue(h1.equals(h1));
assertTrue(h1.equals(h2));
assertFalse(h1.equals(h3));
assertTrue(h2.equals(h1));
assertEquals(h1.hashCode(), h2.hashCode());
assertNotEquals(h1.hashCode(), h3.hashCode()); // not technically a requirement, but we'll hopefully be lucky.
}
@Test
public void testXor() {
U64 hNull = U64.of(0);
U64 hDeadBeef = U64.of(0xdeafbeefdeadbeefL);
assertThat(hNull.xor(hNull), equalTo(hNull));
assertThat(hNull.xor(hDeadBeef), equalTo(hDeadBeef));
assertThat(hDeadBeef.xor(hNull), equalTo(hDeadBeef));
assertThat(hDeadBeef.xor(hDeadBeef), equalTo(hNull));
U64 h1 = U64.of(1L);
U64 h8 = U64.of(0x8000000000000000L);
U64 h81 = U64.of(0x8000000000000001L);
assertThat(h1.xor(h8), equalTo(h81));
}
@Test
public void testCombine() {
long key = 0x1234567890abcdefL;
long val = 0xdeafbeefdeadbeefL;
U64 hkey = U64.of(key);
U64 hVal = U64.of(val);
assertThat(hkey.combineWithValue(hVal, 0), equalTo(hkey.xor(hVal)));
assertThat(hkey.combineWithValue(hVal, 64), equalTo(hkey));
long mask32 = 0x00000000FFFFFFFFL;
assertThat(hkey.combineWithValue(hVal, 32),
equalTo(U64.of(key & ~mask32| (key ^ val) & mask32)));
long tenMask = 0x003FFFFFFFFFFFFFL;
assertThat(hkey.combineWithValue(hVal, 10),
equalTo(U64.of(key & ~tenMask | (key ^ val) & tenMask)));
}
@Test
public void testKeyBits() {
U64 zeroU = U64.of(0);
assertThat(zeroU.prefixBits(0), equalTo(0));
assertThat(zeroU.prefixBits(16), equalTo(0));
assertThat(zeroU.prefixBits(32), equalTo(0));
checkInvalidKeyBitSize(zeroU, 33);
checkInvalidKeyBitSize(zeroU, 64);
assertThat(zeroU.prefixBits(3), equalTo(0));
U64 positiveU = U64.of(0x1234_5678_1234_5678L);
assertThat(positiveU.prefixBits(0), equalTo(0));
assertThat(positiveU.prefixBits(16), equalTo(0x1234));
assertThat(positiveU.prefixBits(32), equalTo(0x12345678));
checkInvalidKeyBitSize(positiveU, 33);
checkInvalidKeyBitSize(positiveU, 64);
U64 signedBitU = U64.of(0x8765_4321_8765_4321L);
assertThat(signedBitU.prefixBits(0), equalTo(0));
assertThat(signedBitU.prefixBits(16), equalTo(0x8765));
assertThat(signedBitU.prefixBits(32), equalTo(0x8765_4321));
checkInvalidKeyBitSize(signedBitU, 33);
checkInvalidKeyBitSize(signedBitU, 64);
}
private void
checkInvalidKeyBitSize(U64 u, int prefixBit) {
try {
u.prefixBits(prefixBit);
fail("Expected exception not thrown for "+prefixBit + " bits");
} catch(IllegalArgumentException e) {
// expected
}
}
}
/**
* Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior
* University
*
* 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.projectfloodlight.openflow.util;
import static org.junit.Assert.assertEquals;
import org.junit.Test;
/**
* Does hexstring conversion work?
*
* @author Rob Sherwood (rob.sherwood@stanford.edu)
*/
public class HexStringTest {
@Test
public void testMarshalling() throws Exception {
String dpidStr = "00:00:00:23:20:2d:16:71";
long dpid = HexString.toLong(dpidStr);
String testStr = HexString.toHexString(dpid);
assertEquals(dpidStr, testStr);
}
@Test
public void testToLong() {
String dpidStr = "3e:1f:01:fc:72:8c:63:31";
long valid = 0x3e1f01fc728c6331L;
long testLong = HexString.toLong(dpidStr);
assertEquals(valid, testLong);
}
@Test
public void testToLong2() {
String dpidStr = "1f:1:fc:72:3:f:31";
long valid = 0x1f01fc72030f31L;
long testLong = HexString.toLong(dpidStr);
assertEquals(valid, testLong);
}
@Test
public void testToLongMSB() {
String dpidStr = "ca:7c:5e:d1:64:7a:95:9b";
long valid = -3856102927509056101L;
long testLong = HexString.toLong(dpidStr);
assertEquals(valid, testLong);
}
@Test(expected=NumberFormatException.class)
public void testToLongErrorTooManyBytes() {
HexString.toLong("09:08:07:06:05:04:03:02:01");
}
@Test(expected=NumberFormatException.class)
public void testToLongErrorByteValueTooLong() {
HexString.toLong("234:01");
}
@Test(expected=NumberFormatException.class)
public void testToLongErrorEmptyByte() {
HexString.toLong("03::01");
}
@Test(expected=NumberFormatException.class)
public void testToLongErrorInvalidHexDigit() {
HexString.toLong("ss:01");
}
@Test(expected=NumberFormatException.class)
public void testToLongErrorEmptyString() {
HexString.toLong("");
}
@Test
public void testToStringBytes() {
byte[] dpid = { 0, 0, 0, 0, 0, 0, 0, -1 };
String valid = "00:00:00:00:00:00:00:ff";
String testString = HexString.toHexString(dpid);
assertEquals(valid, testString);
}
@Test(expected=NumberFormatException.class)
public void testFromHexStringError() {
String invalidStr = "00:00:00:00:00:00:ffff";
HexString.fromHexString(invalidStr);
}
}
package org.projectfloodlight.openflow.util;
import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.CoreMatchers.not;
import static org.junit.Assert.assertThat;
import java.util.Arrays;
import org.junit.Before;
import org.junit.Test;
import org.projectfloodlight.openflow.types.OFPort;
import org.projectfloodlight.openflow.types.PrimitiveSinkable;
import com.google.common.collect.ImmutableSortedSet;
import com.google.common.hash.HashCode;
import com.google.common.hash.HashFunction;
import com.google.common.hash.Hasher;
import com.google.common.hash.Hashing;
public class PrimitiveSinkUtilsTest {
private HashFunction hash;
@Before
public void setup() {
hash = Hashing.murmur3_128();
}
@Test
public void testPutNullableString() {
// test that these different invocations of putNullable
// differ pairwise
HashCode[] hs = new HashCode[] {
calcPutNullableString((String) null),
calcPutNullableString(""),
calcPutNullableString(null, null),
calcPutNullableString(null, ""),
calcPutNullableString("", null),
calcPutNullableString("a\0a", null),
calcPutNullableString(null, "a\0a"),
};
checkPairwiseDifferent(hs);
}
@Test
public void testPutNullable() {
// test that these different invocations of putNullable
// differ pairwise
HashCode[] hs = new HashCode[] {
calcPutNullables(),
calcPutNullables(OFPort.of(1)),
calcPutNullables(OFPort.of(1), null),
calcPutNullables(OFPort.of(1), null, null),
calcPutNullables(null, OFPort.of(1), null),
calcPutNullables(null, null, OFPort.of(1))
};
checkPairwiseDifferent(hs);
}
private void checkPairwiseDifferent(HashCode[] hs) {
for(int i=0;i<hs.length;i++) {
for(int j=i+1; j<hs.length;j++) {
assertThat(hs[i], not(hs[j]));
}
}
}
@Test
public void testPutList() {
HashCode[] hs = new HashCode[] {
calcPutList(),
calcPutList(OFPort.of(1)),
calcPutList(OFPort.of(2)),
calcPutList(OFPort.of(1), OFPort.of(2)),
calcPutList(OFPort.of(2), OFPort.of(1)),
calcPutList(OFPort.of(1), OFPort.of(3)),
calcPutList(OFPort.of(1), OFPort.of(2), OFPort.of(3)),
};
checkPairwiseDifferent(hs);
}
@Test
public void testPutSortedSet() {
HashCode[] hs = new HashCode[] {
calcPutSortedSet(),
calcPutSortedSet(OFPort.of(1)),
calcPutSortedSet(OFPort.of(2)),
calcPutSortedSet(OFPort.of(1), OFPort.of(2)),
calcPutSortedSet(OFPort.of(1), OFPort.of(3)),
calcPutSortedSet(OFPort.of(1), OFPort.of(2), OFPort.of(3)),
};
checkPairwiseDifferent(hs);
assertThat(calcPutSortedSet(OFPort.of(1), OFPort.of(2)),
equalTo(calcPutSortedSet(OFPort.of(2), OFPort.of(1))));
}
private HashCode calcPutNullableString(String... strings) {
Hasher h = hash.newHasher();
for(String s: strings) {
PrimitiveSinkUtils.putNullableStringTo(h, s);
}
return h.hash();
}
private HashCode calcPutSortedSet(OFPort... ports) {
Hasher h = hash.newHasher();
PrimitiveSinkUtils.putSortedSetTo(h, ImmutableSortedSet.copyOf(ports));
return h.hash();
}
private HashCode calcPutList(OFPort... ports) {
Hasher h = hash.newHasher();
PrimitiveSinkUtils.putListTo(h, Arrays.asList(ports));
return h.hash();
}
private HashCode calcPutNullables(PrimitiveSinkable... ps) {
Hasher h = hash.newHasher();
for(PrimitiveSinkable p : ps) {
PrimitiveSinkUtils.putNullableTo(h, p);
}
return h.hash();
}
}
package org.projectfloodlight.protocol;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertThat;
import org.hamcrest.CoreMatchers;
import org.junit.Before;
import org.junit.Test;
import org.projectfloodlight.openflow.protocol.OFFactories;
import org.projectfloodlight.openflow.protocol.OFOxmList;
import org.projectfloodlight.openflow.protocol.OFVersion;
import org.projectfloodlight.openflow.protocol.match.MatchField;
import org.projectfloodlight.openflow.protocol.oxm.OFOxmIpv6DstMasked;
import org.projectfloodlight.openflow.protocol.oxm.OFOxmIpv6SrcMasked;
import org.projectfloodlight.openflow.protocol.oxm.OFOxms;
import org.projectfloodlight.openflow.types.IPv6AddressWithMask;
public class OFOxmListTest {
private OFOxms oxms;
@Before
public void setup() {
oxms = OFFactories.getFactory(OFVersion.OF_13).oxms();
}
@Test
public void testCanonicalize() {
OFOxmList.Builder builder = new OFOxmList.Builder();
IPv6AddressWithMask fullMasked = IPv6AddressWithMask.of("::/0");
OFOxmIpv6DstMasked fullMaskedOxm = oxms.ipv6DstMasked(fullMasked.getValue(), fullMasked.getMask());
builder.set(fullMaskedOxm);
IPv6AddressWithMask address= IPv6AddressWithMask.of("1:2:3:4:5:6::8");
OFOxmIpv6SrcMasked addressSrcOxm = oxms.ipv6SrcMasked(address.getValue(), address.getMask());
builder.set(addressSrcOxm);
OFOxmList list = builder.build();
assertThat(list.get(MatchField.IPV6_DST), CoreMatchers.nullValue());
assertFalse(list.get(MatchField.IPV6_SRC).isMasked());
}
}
package org.projectfloodlight.protocol;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
import org.hamcrest.CoreMatchers;
import org.junit.Before;
import org.junit.Test;
import org.projectfloodlight.openflow.protocol.OFFactories;
import org.projectfloodlight.openflow.protocol.OFVersion;
import org.projectfloodlight.openflow.protocol.oxm.OFOxm;
import org.projectfloodlight.openflow.protocol.oxm.OFOxmIpv4Src;
import org.projectfloodlight.openflow.protocol.oxm.OFOxmIpv4SrcMasked;
import org.projectfloodlight.openflow.protocol.oxm.OFOxms;
import org.projectfloodlight.openflow.types.IPv4Address;
import org.projectfloodlight.openflow.types.IPv4AddressWithMask;
public class OFOxmTest {
private OFOxms oxms;
@Before
public void setup() {
oxms = OFFactories.getFactory(OFVersion.OF_13).oxms();
}
@Test
public void testGetCanonicalFullMask() {
IPv4AddressWithMask empty = IPv4AddressWithMask.of("0.0.0.0/0");
assertEquals(IPv4Address.FULL_MASK, empty.getMask());
OFOxmIpv4SrcMasked ipv4SrcMasked = oxms.ipv4SrcMasked(empty.getValue(), empty.getMask());
// canonicalize should remove /0
assertNull(ipv4SrcMasked.getCanonical());
}
@Test
public void testGetCanonicalNoMask() {
IPv4AddressWithMask fullIp = IPv4AddressWithMask.of("1.2.3.4/32");
assertEquals(IPv4Address.NO_MASK, fullIp.getMask());
OFOxmIpv4SrcMasked ipv4SrcMasked = oxms.ipv4SrcMasked(fullIp.getValue(), fullIp.getMask());
assertTrue(ipv4SrcMasked.isMasked());
assertEquals(IPv4Address.NO_MASK, ipv4SrcMasked.getMask());
// canonicalize should convert the masked oxm to the non-masked one
OFOxm<IPv4Address> canonical = ipv4SrcMasked.getCanonical();
assertThat(canonical, CoreMatchers.instanceOf(OFOxmIpv4Src.class));
assertFalse(canonical.isMasked());
}
@Test
public void testGetCanonicalNormalMask() {
IPv4AddressWithMask ip = IPv4AddressWithMask.of("1.2.3.0/24");
OFOxmIpv4SrcMasked ipv4SrcMasked = oxms.ipv4SrcMasked(ip.getValue(), ip.getMask());
assertTrue(ipv4SrcMasked.isMasked());
// canonicalize should convert the masked oxm to the non-masked one
OFOxm<IPv4Address> canonical = ipv4SrcMasked.getCanonical();
assertEquals(ipv4SrcMasked, canonical);
}
}
package org.projectfloodlight.protocol.match;
import org.projectfloodlight.openflow.protocol.OFFactories;
import org.projectfloodlight.openflow.protocol.OFVersion;
public class MatchFieldIteration10Test extends MatchFieldIterationBase {
public MatchFieldIteration10Test() {
super(OFFactories.getFactory(OFVersion.OF_10));
}
}
package org.projectfloodlight.protocol.match;
import org.projectfloodlight.openflow.protocol.OFFactories;
import org.projectfloodlight.openflow.protocol.OFVersion;
public class MatchFieldIteration13Test extends MatchFieldIterationBase {
public MatchFieldIteration13Test() {
super(OFFactories.getFactory(OFVersion.OF_13));
}
}
package org.projectfloodlight.protocol.match;
import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.fail;
import java.util.Iterator;
import org.junit.Test;
import org.projectfloodlight.openflow.protocol.OFFactory;
import org.projectfloodlight.openflow.protocol.OFVersion;
import org.projectfloodlight.openflow.protocol.match.Match;
import org.projectfloodlight.openflow.protocol.match.MatchField;
import org.projectfloodlight.openflow.protocol.match.MatchFields;
import org.projectfloodlight.openflow.types.ArpOpcode;
import org.projectfloodlight.openflow.types.EthType;
import org.projectfloodlight.openflow.types.IPv4Address;
import org.projectfloodlight.openflow.types.IpProtocol;
import org.projectfloodlight.openflow.types.MacAddress;
import org.projectfloodlight.openflow.types.Masked;
import org.projectfloodlight.openflow.types.OFPort;
import org.projectfloodlight.openflow.types.TransportPort;
import com.google.common.collect.Iterables;
public class MatchFieldIterationBase {
private OFFactory factory;
protected MatchFieldIterationBase(OFFactory factory) {
this.factory = factory;
}
@Test
public void iterateEmptyMatch() {
Match match = factory.buildMatch().build();
Iterator<MatchField<?>> iter = match.getMatchFields().iterator();
assertThat(iter.hasNext(), is(false));
}
@Test
public void iterateSingleExactMatchField() {
OFPort port5 = OFPort.of(5);
Match match = factory.buildMatch()
.setExact(MatchField.IN_PORT, port5)
.build();
Iterator<MatchField<?>> iter = match.getMatchFields().iterator();
assertThat(iter.hasNext(), is(true));
MatchField<?> matchField = iter.next();
assertThat(matchField.id, is(MatchFields.IN_PORT));
assertThat(match.isExact(matchField), is(true));
@SuppressWarnings("unchecked")
MatchField<OFPort> portMatchField = (MatchField<OFPort>) matchField;
OFPort port = match.get(portMatchField);
assertThat(port, is(port5));
assertThat(iter.hasNext(), is(false));
}
@SuppressWarnings("unchecked")
@Test
public void iterateExactMatchFields() {
OFPort port5 = OFPort.of(5);
MacAddress macSrc = MacAddress.of("00:01:02:03:04:05");
MacAddress macDst = MacAddress.of("01:01:02:02:03:03");
IPv4Address ipSrc = IPv4Address.of("10.192.20.1");
IPv4Address ipDst = IPv4Address.of("10.192.20.2");
TransportPort tcpSrc = TransportPort.of(100);
TransportPort tcpDst = TransportPort.of(200);
Match match = factory.buildMatch()
.setExact(MatchField.IN_PORT, port5)
.setExact(MatchField.ETH_TYPE, EthType.IPv4)
.setExact(MatchField.ETH_SRC, macSrc)
.setExact(MatchField.ETH_DST, macDst)
.setExact(MatchField.IP_PROTO, IpProtocol.TCP)
.setExact(MatchField.IPV4_SRC, ipSrc)
.setExact(MatchField.IPV4_DST, ipDst)
.setExact(MatchField.TCP_SRC, tcpSrc)
.setExact(MatchField.TCP_DST, tcpDst)
.build();
assertThat(Iterables.size(match.getMatchFields()), is(9));
for (MatchField<?> matchField: match.getMatchFields()) {
switch (matchField.id) {
case IN_PORT:
OFPort port = match.get((MatchField<OFPort>) matchField);
assertThat(port, is(port5));
break;
case ETH_TYPE:
EthType ethType = match.get((MatchField<EthType>) matchField);
assertThat(ethType, is(EthType.IPv4));
break;
case ETH_SRC:
MacAddress mac = match.get((MatchField<MacAddress>) matchField);
assertThat(mac, is(macSrc));
break;
case ETH_DST:
mac = match.get((MatchField<MacAddress>) matchField);
assertThat(mac, is(macDst));
break;
case IP_PROTO:
IpProtocol ipProtocol = match.get((MatchField<IpProtocol>) matchField);
assertThat(ipProtocol, is(IpProtocol.TCP));
break;
case IPV4_SRC:
IPv4Address ip = match.get((MatchField<IPv4Address>) matchField);
assertThat(ip, is(ipSrc));
break;
case IPV4_DST:
ip = match.get((MatchField<IPv4Address>) matchField);
assertThat(ip, is(ipDst));
break;
case TCP_SRC:
TransportPort tcp = match.get((MatchField<TransportPort>) matchField);
assertThat(tcp, is(tcpSrc));
break;
case TCP_DST:
tcp = match.get((MatchField<TransportPort>) matchField);
assertThat(tcp, is(tcpDst));
break;
default:
fail("Unexpected match field returned from iterator");
}
}
}
@SuppressWarnings("unchecked")
@Test
public void iterateArpFields() {
MacAddress macSrc = MacAddress.of("00:01:02:03:04:05");
MacAddress macDst = MacAddress.of("01:01:02:02:03:03");
IPv4Address ipSrc = IPv4Address.of("10.192.20.1");
IPv4Address ipDst = IPv4Address.of("10.192.20.2");
OFVersion version = factory.getVersion();
boolean supportsArpHardwareAddress = (version != OFVersion.OF_10) &&
(version != OFVersion.OF_11) && (version != OFVersion.OF_12);
int matchFieldCount = 4;
Match.Builder builder = factory.buildMatch();
builder.setExact(MatchField.ETH_TYPE, EthType.ARP)
.setExact(MatchField.ARP_OP, ArpOpcode.REPLY)
.setExact(MatchField.ARP_SPA, ipSrc)
.setExact(MatchField.ARP_TPA, ipDst);
if (supportsArpHardwareAddress) {
builder.setExact(MatchField.ARP_SHA, macSrc);
builder.setExact(MatchField.ARP_THA, macDst);
matchFieldCount += 2;
}
Match match = builder.build();
assertThat(Iterables.size(match.getMatchFields()), is(matchFieldCount));
for (MatchField<?> matchField: match.getMatchFields()) {
switch (matchField.id) {
case ETH_TYPE:
EthType ethType = match.get((MatchField<EthType>) matchField);
assertThat(ethType, is(EthType.ARP));
break;
case ARP_OP:
ArpOpcode opcode = match.get((MatchField<ArpOpcode>) matchField);
assertThat(opcode, is(ArpOpcode.REPLY));
break;
case ARP_SHA:
MacAddress mac = match.get((MatchField<MacAddress>) matchField);
assertThat(mac, is(macSrc));
break;
case ARP_THA:
mac = match.get((MatchField<MacAddress>) matchField);
assertThat(mac, is(macDst));
break;
case ARP_SPA:
IPv4Address ip = match.get((MatchField<IPv4Address>) matchField);
assertThat(ip, is(ipSrc));
break;
case ARP_TPA:
ip = match.get((MatchField<IPv4Address>) matchField);
assertThat(ip, is(ipDst));
break;
default:
fail("Unexpected match field returned from iterator");
}
}
}
@SuppressWarnings("unchecked")
@Test
public void iterateMaskedFields() {
MacAddress macSrc = MacAddress.of("01:02:03:04:00:00");
MacAddress macSrcMask = MacAddress.of("FF:FF:FF:FF:00:00");
MacAddress macDst = MacAddress.of("11:22:33:00:00:00");
MacAddress macDstMask = MacAddress.of("FF:FF:FF:00:00:00");
IPv4Address ipSrc = IPv4Address.of("10.192.20.0");
IPv4Address ipSrcMask = IPv4Address.of("255.255.255.0");
IPv4Address ipDst = IPv4Address.of("10.192.20.0");
IPv4Address ipDstMask = IPv4Address.of("255.255.255.128");
TransportPort tcpSrcMask = TransportPort.of(0x01F0);
OFVersion version = factory.getVersion();
boolean supportsAllMasks = (version != OFVersion.OF_10) &&
(version != OFVersion.OF_11) && (version != OFVersion.OF_12);
int matchFieldCount = 4;
Match.Builder builder = factory.buildMatch()
.setExact(MatchField.ETH_TYPE, EthType.IPv4)
.setMasked(MatchField.IPV4_SRC, ipSrc, ipSrcMask)
.setMasked(MatchField.IPV4_DST, ipDst, ipDstMask)
.setExact(MatchField.IP_PROTO, IpProtocol.TCP);
if (supportsAllMasks) {
builder.setMasked(MatchField.ETH_SRC, macSrc, macSrcMask);
builder.setMasked(MatchField.ETH_DST, macDst, macDstMask);
builder.setMasked(MatchField.TCP_SRC, tcpSrcMask, tcpSrcMask);
matchFieldCount += 3;
}
Match match = builder.build();
assertThat(Iterables.size(match.getMatchFields()), is(matchFieldCount));
for (MatchField<?> matchField: match.getMatchFields()) {
switch (matchField.id) {
case ETH_TYPE:
EthType ethType = match.get((MatchField<EthType>) matchField);
assertThat(ethType, is(EthType.IPv4));
break;
case ETH_SRC:
Masked<MacAddress> mac = match.getMasked((MatchField<MacAddress>) matchField);
assertThat(mac.getValue(), is(macSrc));
assertThat(mac.getMask(), is(macSrcMask));
break;
case ETH_DST:
mac = match.getMasked((MatchField<MacAddress>) matchField);
assertThat(mac.getValue(), is(macDst));
assertThat(mac.getMask(), is(macDstMask));
break;
case IP_PROTO:
IpProtocol ipProtocol = match.get((MatchField<IpProtocol>) matchField);
assertThat(ipProtocol, is(IpProtocol.TCP));
break;
case IPV4_SRC:
Masked<IPv4Address> ip = match.getMasked((MatchField<IPv4Address>) matchField);
assertThat(ip.getValue(), is(ipSrc));
assertThat(ip.getMask(), is(ipSrcMask));
break;
case IPV4_DST:
ip = match.getMasked((MatchField<IPv4Address>) matchField);
assertThat(ip.getValue(), is(ipDst));
assertThat(ip.getMask(), is(ipDstMask));
break;
case TCP_SRC:
Masked<TransportPort> tcp = match.getMasked((MatchField<TransportPort>) matchField);
assertThat(tcp.getValue(), is(tcpSrcMask));
assertThat(tcp.getMask(), is(tcpSrcMask));
break;
default:
fail("Unexpected match field returned from iterator");
}
}
}
}
package org.projectfloodlight.test;
import java.util.ArrayList;
import java.util.List;
import org.junit.Assert;
import com.google.common.base.Function;
import com.google.common.base.Joiner;
import com.google.common.collect.Lists;
import com.google.common.primitives.Bytes;
public class TestUtils {
private TestUtils() {}
private static final int PER_LINE = 8;
public static void betterAssertArrayEquals(byte[] expected, byte[] got) {
int maxlen = Math.max(expected.length, got.length);
List<String> expectedList = formatHex(Bytes.asList(expected));
List<String> gotList = formatHex(Bytes.asList(got));
boolean fail = false;
for (int i = 0; i < maxlen;i+= PER_LINE) {
int maxThisLine = Math.min(maxlen, PER_LINE);
boolean print = false;
ArrayList<String> changeMarkers = new ArrayList<String>();
for (int j = i; j < maxThisLine; j++) {
if (j >= expected.length || j >= got.length || expected[j] != got[j]) {
print = true;
fail = true;
changeMarkers.add("==");
break;
} else {
changeMarkers.add(" ");
}
}
if(print) {
System.out.println(String.format("%4x: %s", i, Joiner.on(" ").join(expectedList.subList(i, Math.min(expectedList.size(), i+PER_LINE)))));
System.out.println(String.format("%4x: %s", i, Joiner.on(" ").join(gotList.subList(i, Math.min(gotList.size(), i+PER_LINE)))));
System.out.println(String.format("%4s %s", "", Joiner.on(" ").join(changeMarkers)));
System.out.println("\n");
}
}
if(fail) {
Assert.fail("Array comparison failed");
}
}
private static List<String> formatHex(List<Byte> b) {
return Lists.transform(b, new Function<Byte, String>() {
@Override
public String apply(Byte input) {
return String.format("%02x", input);
}
});
}
}
\ No newline at end of file
<configuration scan="true">
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{HH:mm:ss.SSS} %level [%logger{20}:%thread] %msg%n</pattern>
</encoder>
</appender>
<root level="INFO">
<appender-ref ref="STDOUT" />
</root>
<logger name="org" level="WARN"/>
<logger name="LogService" level="WARN"/> <!-- Restlet access logging -->
<logger name="org.projectfloodlight.openflow" level="DEBUG"/>
</configuration>
File mode changed
<!--
~ Copyright (c) 2014 Hewlett-Packard Development Company, L.P.
~
~ This program and the accompanying materials are made available under the
~ terms of the Eclipse Public License v1.0 which accompanies this distribution,
~ and is available at http://www.eclipse.org/legal/epl-v10.html
-->
<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>
<groupId>net.onrc.onos</groupId>
<artifactId>onos-features</artifactId>
<packaging>jar</packaging>
<version>1.0.0-SNAPSHOT</version>
<name>onos-features</name>
<description>Apache Karaf features repository</description>
<dependencies>
<!--<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
<version>1.7</version>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.4</version>
</dependency>
<dependency>
<groupId>commons-lang</groupId>
<artifactId>commons-lang</artifactId>
<version>2.6</version>
</dependency>
<dependency>
<groupId>commons-configuration</groupId>
<artifactId>commons-configuration</artifactId>
<version>1.10</version>
</dependency>-->
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>build-helper-maven-plugin</artifactId>
<version>1.3</version>
<executions>
<execution>
<id>attach-artifacts</id>
<phase>package</phase>
<goals>
<goal>attach-artifact</goal>
</goals>
<configuration>
<artifacts>
<artifact>
<file>features.xml</file>
<type>xml</type>
<classifier>features</classifier>
</artifact>
</artifacts>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>