alshabib

adding packet types

Showing 34 changed files with 4945 additions and 344 deletions
......@@ -21,6 +21,10 @@
<groupId>com.google.guava</groupId>
<artifactId>guava-testlib</artifactId>
</dependency>
<dependency>
<groupId>org.onlab.onos</groupId>
<artifactId>onlab-misc</artifactId>
</dependency>
</dependencies>
</project>
......
......@@ -56,7 +56,6 @@
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.felix</groupId>
<artifactId>maven-bundle-plugin</artifactId>
......
package org.onlab.onos.of.controller;
import org.onlab.packet.Ethernet;
import org.projectfloodlight.openflow.protocol.OFPacketIn;
import org.projectfloodlight.openflow.protocol.OFPacketOut;
import org.projectfloodlight.openflow.types.OFPort;
public class DefaultPacketContext implements PacketContext {
private boolean free = true;
private boolean isBuilt = false;
private final OpenFlowSwitch sw;
private final OFPacketIn pktin;
private final OFPacketOut pktout = null;
private DefaultPacketContext(OpenFlowSwitch s, OFPacketIn pkt) {
this.sw = s;
this.pktin = pkt;
}
@Override
public void block() {
free = false;
}
@Override
public void send() {
if (free && isBuilt) {
sw.sendMsg(pktout);
}
}
@Override
public void build(OFPort outPort) {
isBuilt = true;
}
@Override
public void build(Ethernet ethFrame, OFPort outPort) {
// TODO Auto-generated method stub
}
@Override
public Ethernet parsed() {
// TODO Auto-generated method stub
return null;
}
@Override
public Dpid dpid() {
// TODO Auto-generated method stub
return null;
}
public static PacketContext PacketContextFromPacketIn(OpenFlowSwitch s, OFPacketIn pkt) {
return new DefaultPacketContext(s, pkt);
}
}
......@@ -87,9 +87,10 @@ public interface OpenFlowController {
/**
* Process a message and notify the appropriate listeners.
*
* @param dpid the dpid the message arrived on
* @param msg the message to process.
*/
public void processPacket(OFMessage msg);
public void processPacket(Dpid dpid, OFMessage msg);
/**
* Sets the role for a given switch.
......
package org.onlab.onos.of.controller;
import org.onlab.packet.Ethernet;
import org.projectfloodlight.openflow.types.OFPort;
/**
......@@ -34,13 +35,13 @@ public interface PacketContext {
* @param ethFrame the actual packet to send out.
* @param outPort the out port to send to packet out of.
*/
public void build(Object ethFrame, OFPort outPort);
public void build(Ethernet ethFrame, OFPort outPort);
/**
* Provided a handle onto the parsed payload.
* @return the parsed form of the payload.
*/
public Object parsed();
public Ethernet parsed();
/**
* Provide the dpid of the switch where the packet in arrived.
......
......@@ -159,7 +159,7 @@ public abstract class AbstractOpenFlowSwitch implements OpenFlowSwitchDriver {
*/
@Override
public final void handleMessage(OFMessage m) {
this.agent.processMessage(m);
this.agent.processMessage(dpid, m);
}
@Override
......
......@@ -69,7 +69,9 @@ public interface OpenFlowAgent {
/**
* Process a message coming from a switch.
*
* @param dpid the dpid the message came on.
* @param m the message to process
*/
public void processMessage(OFMessage m);
public void processMessage(Dpid dpid, OFMessage m);
}
......
# 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>
......@@ -6,9 +6,7 @@ import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import org.apache.felix.scr.annotations.Activate;
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Deactivate;
import org.apache.felix.scr.annotations.Service;
import org.onlab.onos.of.controller.Dpid;
import org.onlab.onos.of.controller.OpenFlowController;
import org.onlab.onos.of.controller.OpenFlowSwitch;
......@@ -17,11 +15,10 @@ import org.onlab.onos.of.controller.PacketListener;
import org.onlab.onos.of.controller.RoleState;
import org.onlab.onos.of.controller.driver.OpenFlowAgent;
import org.projectfloodlight.openflow.protocol.OFMessage;
import org.projectfloodlight.openflow.protocol.OFPortStatus;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@Component(immediate = true)
@Service
public class OpenFlowControllerImpl implements OpenFlowController {
private static final Logger log =
......@@ -38,6 +35,9 @@ public class OpenFlowControllerImpl implements OpenFlowController {
protected ArrayList<OpenFlowSwitchListener> ofEventListener =
new ArrayList<OpenFlowSwitchListener>();
protected ArrayList<PacketListener> ofPacketListener =
new ArrayList<PacketListener>();
private final Controller ctrl = new Controller();
@Activate
......@@ -94,14 +94,12 @@ public class OpenFlowControllerImpl implements OpenFlowController {
@Override
public void addPacketListener(int priority, PacketListener listener) {
// TODO Auto-generated method stub
ofPacketListener.add(priority, listener);
}
@Override
public void removePacketListener(PacketListener listener) {
// TODO Auto-generated method stub
ofPacketListener.remove(listener);
}
@Override
......@@ -110,8 +108,22 @@ public class OpenFlowControllerImpl implements OpenFlowController {
}
@Override
public void processPacket(OFMessage msg) {
log.info("Got message {}", msg);
public void processPacket(Dpid dpid, OFMessage msg) {
switch (msg.getType()) {
case PORT_STATUS:
for (OpenFlowSwitchListener l : ofEventListener) {
l.portChanged(dpid, (OFPortStatus) msg);
}
break;
case PACKET_IN:
for (PacketListener p : ofPacketListener) {
//TODO fix me!
p.handlePacket(null);
}
break;
default:
log.warn("Handling message type {} not yet implemented", msg.getType());
}
}
@Override
......@@ -252,8 +264,8 @@ public class OpenFlowControllerImpl implements OpenFlowController {
}
@Override
public void processMessage(OFMessage m) {
processPacket(m);
public void processMessage(Dpid dpid, OFMessage m) {
processPacket(dpid, m);
}
}
......
......@@ -22,6 +22,13 @@
<module>drivers</module>
</modules>
<dependencies>
<dependency>
<groupId>org.onlab.onos</groupId>
<artifactId>onlab-misc</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
......
package org.onlab.onos.provider.of.link.impl;
import static org.slf4j.LoggerFactory.getLogger;
import org.apache.felix.scr.annotations.Activate;
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Deactivate;
......@@ -11,10 +13,10 @@ import org.onlab.onos.net.link.LinkProviderService;
import org.onlab.onos.net.provider.AbstractProvider;
import org.onlab.onos.net.provider.ProviderId;
import org.onlab.onos.of.controller.OpenFlowController;
import org.onlab.onos.of.controller.PacketContext;
import org.onlab.onos.of.controller.PacketListener;
import org.slf4j.Logger;
import static org.slf4j.LoggerFactory.getLogger;
/**
* Provider which uses an OpenFlow controller to detect network
* infrastructure links.
......@@ -32,6 +34,8 @@ public class OpenFlowLinkProvider extends AbstractProvider implements LinkProvid
private LinkProviderService providerService;
private final PacketListener listener = new InternalLinkProvider();
/**
* Creates an OpenFlow link provider.
*/
......@@ -42,14 +46,26 @@ public class OpenFlowLinkProvider extends AbstractProvider implements LinkProvid
@Activate
public void activate() {
providerService = providerRegistry.register(this);
controller.addPacketListener(0, listener);
log.info("Started");
}
@Deactivate
public void deactivate() {
providerRegistry.unregister(this);
controller.removePacketListener(listener);
providerService = null;
log.info("Stopped");
}
private class InternalLinkProvider implements PacketListener {
@Override
public void handlePacket(PacketContext pktCtx) {
}
}
}
......
......@@ -25,5 +25,7 @@
<suppress files=".*" checks="TodoCommentCheck"/>
<suppress files=".*" checks="AvoidInlineConditionalsCheck"/>
<suppress files=".*" checks="OperatorWrapCheck"/>
<suppress files=".*" checks="HiddenField"/>
</suppressions>
......
/*******************************************************************************
* Copyright 2014 Open Networking Laboratory
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
******************************************************************************/
/**
* 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 org.onlab.packet;
import java.nio.ByteBuffer;
import java.util.Arrays;
/**
*
* @author David Erickson (daviderickson@cs.stanford.edu)
*/
public class ARP extends BasePacket {
public static final short HW_TYPE_ETHERNET = 0x1;
public static final short PROTO_TYPE_IP = 0x800;
public static final short OP_REQUEST = 0x1;
public static final short OP_REPLY = 0x2;
public static final short OP_RARP_REQUEST = 0x3;
public static final short OP_RARP_REPLY = 0x4;
protected short hardwareType;
protected short protocolType;
protected byte hardwareAddressLength;
protected byte protocolAddressLength;
protected short opCode;
protected byte[] senderHardwareAddress;
protected byte[] senderProtocolAddress;
protected byte[] targetHardwareAddress;
protected byte[] targetProtocolAddress;
/**
* @return the hardwareType
*/
public short getHardwareType() {
return this.hardwareType;
}
/**
* @param hardwareType
* the hardwareType to set
*/
public ARP setHardwareType(final short hwType) {
this.hardwareType = hwType;
return this;
}
/**
* @return the protocolType
*/
public short getProtocolType() {
return this.protocolType;
}
/**
* @param protocolType
* the protocolType to set
*/
public ARP setProtocolType(final short protoType) {
this.protocolType = protoType;
return this;
}
/**
* @return the hardwareAddressLength
*/
public byte getHardwareAddressLength() {
return this.hardwareAddressLength;
}
/**
* @param hwAddressLength
* the hardwareAddressLength to set
*/
public ARP setHardwareAddressLength(final byte hwAddressLength) {
this.hardwareAddressLength = hwAddressLength;
return this;
}
/**
* @return the protocolAddressLength
*/
public byte getProtocolAddressLength() {
return this.protocolAddressLength;
}
/**
* @param protocolAddressLength
* the protocolAddressLength to set
*/
public ARP setProtocolAddressLength(final byte protoAddressLength) {
this.protocolAddressLength = protoAddressLength;
return this;
}
/**
* @return the opCode
*/
public short getOpCode() {
return this.opCode;
}
/**
* @param opCode
* the opCode to set
*/
public ARP setOpCode(final short op) {
this.opCode = op;
return this;
}
/**
* @return the senderHardwareAddress
*/
public byte[] getSenderHardwareAddress() {
return this.senderHardwareAddress;
}
/**
* @param senderHardwareAddress
* the senderHardwareAddress to set
*/
public ARP setSenderHardwareAddress(final byte[] senderHWAddress) {
this.senderHardwareAddress = senderHWAddress;
return this;
}
/**
* @return the senderProtocolAddress
*/
public byte[] getSenderProtocolAddress() {
return this.senderProtocolAddress;
}
/**
* @param senderProtocolAddress
* the senderProtocolAddress to set
*/
public ARP setSenderProtocolAddress(final byte[] senderProtoAddress) {
this.senderProtocolAddress = senderProtoAddress;
return this;
}
public ARP setSenderProtocolAddress(final int address) {
this.senderProtocolAddress = ByteBuffer.allocate(4).putInt(address)
.array();
return this;
}
/**
* @return the targetHardwareAddress
*/
public byte[] getTargetHardwareAddress() {
return this.targetHardwareAddress;
}
/**
* @param targetHardwareAddress
* the targetHardwareAddress to set
*/
public ARP setTargetHardwareAddress(final byte[] targetHWAddress) {
this.targetHardwareAddress = targetHWAddress;
return this;
}
/**
* @return the targetProtocolAddress
*/
public byte[] getTargetProtocolAddress() {
return this.targetProtocolAddress;
}
/**
* @return True if gratuitous ARP (SPA = TPA), false otherwise
*/
public boolean isGratuitous() {
assert this.senderProtocolAddress.length == this.targetProtocolAddress.length;
int indx = 0;
while (indx < this.senderProtocolAddress.length) {
if (this.senderProtocolAddress[indx] != this.targetProtocolAddress[indx]) {
return false;
}
indx++;
}
return true;
}
/**
* @param targetProtocolAddress
* the targetProtocolAddress to set
*/
public ARP setTargetProtocolAddress(final byte[] targetProtoAddress) {
this.targetProtocolAddress = targetProtoAddress;
return this;
}
public ARP setTargetProtocolAddress(final int address) {
this.targetProtocolAddress = ByteBuffer.allocate(4).putInt(address)
.array();
return this;
}
@Override
public byte[] serialize() {
final int length = 8 + 2 * (0xff & this.hardwareAddressLength) + 2
* (0xff & this.protocolAddressLength);
final byte[] data = new byte[length];
final ByteBuffer bb = ByteBuffer.wrap(data);
bb.putShort(this.hardwareType);
bb.putShort(this.protocolType);
bb.put(this.hardwareAddressLength);
bb.put(this.protocolAddressLength);
bb.putShort(this.opCode);
bb.put(this.senderHardwareAddress, 0, 0xff & this.hardwareAddressLength);
bb.put(this.senderProtocolAddress, 0, 0xff & this.protocolAddressLength);
bb.put(this.targetHardwareAddress, 0, 0xff & this.hardwareAddressLength);
bb.put(this.targetProtocolAddress, 0, 0xff & this.protocolAddressLength);
return data;
}
@Override
public IPacket deserialize(final byte[] data, final int offset,
final int length) {
final ByteBuffer bb = ByteBuffer.wrap(data, offset, length);
this.hardwareType = bb.getShort();
this.protocolType = bb.getShort();
this.hardwareAddressLength = bb.get();
this.protocolAddressLength = bb.get();
this.opCode = bb.getShort();
this.senderHardwareAddress = new byte[0xff & this.hardwareAddressLength];
bb.get(this.senderHardwareAddress, 0, this.senderHardwareAddress.length);
this.senderProtocolAddress = new byte[0xff & this.protocolAddressLength];
bb.get(this.senderProtocolAddress, 0, this.senderProtocolAddress.length);
this.targetHardwareAddress = new byte[0xff & this.hardwareAddressLength];
bb.get(this.targetHardwareAddress, 0, this.targetHardwareAddress.length);
this.targetProtocolAddress = new byte[0xff & this.protocolAddressLength];
bb.get(this.targetProtocolAddress, 0, this.targetProtocolAddress.length);
return this;
}
/*
* (non-Javadoc)
*
* @see java.lang.Object#hashCode()
*/
@Override
public int hashCode() {
final int prime = 13121;
int result = super.hashCode();
result = prime * result + this.hardwareAddressLength;
result = prime * result + this.hardwareType;
result = prime * result + this.opCode;
result = prime * result + this.protocolAddressLength;
result = prime * result + this.protocolType;
result = prime * result + Arrays.hashCode(this.senderHardwareAddress);
result = prime * result + Arrays.hashCode(this.senderProtocolAddress);
result = prime * result + Arrays.hashCode(this.targetHardwareAddress);
result = prime * result + Arrays.hashCode(this.targetProtocolAddress);
return result;
}
/*
* (non-Javadoc)
*
* @see java.lang.Object#equals(java.lang.Object)
*/
@Override
public boolean equals(final Object obj) {
if (this == obj) {
return true;
}
if (!super.equals(obj)) {
return false;
}
if (!(obj instanceof ARP)) {
return false;
}
final ARP other = (ARP) obj;
if (this.hardwareAddressLength != other.hardwareAddressLength) {
return false;
}
if (this.hardwareType != other.hardwareType) {
return false;
}
if (this.opCode != other.opCode) {
return false;
}
if (this.protocolAddressLength != other.protocolAddressLength) {
return false;
}
if (this.protocolType != other.protocolType) {
return false;
}
if (!Arrays.equals(this.senderHardwareAddress,
other.senderHardwareAddress)) {
return false;
}
if (!Arrays.equals(this.senderProtocolAddress,
other.senderProtocolAddress)) {
return false;
}
if (!Arrays.equals(this.targetHardwareAddress,
other.targetHardwareAddress)) {
return false;
}
if (!Arrays.equals(this.targetProtocolAddress,
other.targetProtocolAddress)) {
return false;
}
return true;
}
/*
* (non-Javadoc)
*
* @see java.lang.Object#toString()
*/
@Override
public String toString() {
return "ARP [hardwareType=" + this.hardwareType + ", protocolType="
+ this.protocolType + ", hardwareAddressLength="
+ this.hardwareAddressLength + ", protocolAddressLength="
+ this.protocolAddressLength + ", opCode=" + this.opCode
+ ", senderHardwareAddress="
+ Arrays.toString(this.senderHardwareAddress)
+ ", senderProtocolAddress="
+ Arrays.toString(this.senderProtocolAddress)
+ ", targetHardwareAddress="
+ Arrays.toString(this.targetHardwareAddress)
+ ", targetProtocolAddress="
+ Arrays.toString(this.targetProtocolAddress) + "]";
}
}
/*******************************************************************************
* Copyright 2014 Open Networking Laboratory
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
******************************************************************************/
/**
* 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 org.onlab.packet;
/**
*
* @author David Erickson (daviderickson@cs.stanford.edu)
*/
public abstract class BasePacket implements IPacket {
protected IPacket parent;
protected IPacket payload;
/**
* @return the parent
*/
@Override
public IPacket getParent() {
return this.parent;
}
/**
* @param parent
* the parent to set
*/
@Override
public IPacket setParent(final IPacket parent) {
this.parent = parent;
return this;
}
/**
* @return the payload
*/
@Override
public IPacket getPayload() {
return this.payload;
}
/**
* @param payload
* the payload to set
*/
@Override
public IPacket setPayload(final IPacket payload) {
this.payload = payload;
return this;
}
@Override
public void resetChecksum() {
if (this.parent != null) {
this.parent.resetChecksum();
}
}
/*
* (non-Javadoc)
*
* @see java.lang.Object#hashCode()
*/
@Override
public int hashCode() {
final int prime = 6733;
int result = 1;
result = prime * result
+ (this.payload == null ? 0 : this.payload.hashCode());
return result;
}
/*
* (non-Javadoc)
*
* @see java.lang.Object#equals(java.lang.Object)
*/
@Override
public boolean equals(final Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (!(obj instanceof BasePacket)) {
return false;
}
final BasePacket other = (BasePacket) obj;
if (this.payload == null) {
if (other.payload != null) {
return false;
}
} else if (!this.payload.equals(other.payload)) {
return false;
}
return true;
}
@Override
public Object clone() {
IPacket pkt;
try {
pkt = this.getClass().newInstance();
} catch (final Exception e) {
throw new RuntimeException("Could not clone packet");
}
// TODO: we are using serialize()/deserialize() to perform the
// cloning. Not the most efficient way but simple. We can revisit
// if we hit performance problems.
final byte[] data = this.serialize();
pkt.deserialize(this.serialize(), 0, data.length);
pkt.setParent(this.parent);
return pkt;
}
}
/*******************************************************************************
* Copyright 2014 Open Networking Laboratory
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
******************************************************************************/
/**
* 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 org.onlab.packet;
import java.io.UnsupportedEncodingException;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.List;
import java.util.ListIterator;
/**
*
* @author David Erickson (daviderickson@cs.stanford.edu)
*/
public class DHCP extends BasePacket {
/**
* Dynamic Host Configuration Protocol packet.
* ------------------------------------------ |op (1) | htype(1) | hlen(1) |
* hops(1) | ------------------------------------------ | xid (4) |
* ------------------------------------------ | secs (2) | flags (2) |
* ------------------------------------------ | ciaddr (4) |
* ------------------------------------------ | yiaddr (4) |
* ------------------------------------------ | siaddr (4) |
* ------------------------------------------ | giaddr (4) |
* ------------------------------------------ | chaddr (16) |
* ------------------------------------------ | sname (64) |
* ------------------------------------------ | file (128) |
* ------------------------------------------ | options (312) |
* ------------------------------------------
*
*/
// Header + magic without options
public static final int MIN_HEADER_LENGTH = 240;
public static final byte OPCODE_REQUEST = 0x1;
public static final byte OPCODE_REPLY = 0x2;
public static final byte HWTYPE_ETHERNET = 0x1;
public enum DHCPOptionCode {
OptionCode_SubnetMask((byte) 1), OptionCode_RequestedIP((byte) 50), OptionCode_LeaseTime(
(byte) 51), OptionCode_MessageType((byte) 53), OptionCode_DHCPServerIp(
(byte) 54), OptionCode_RequestedParameters((byte) 55), OptionCode_RenewalTime(
(byte) 58), OPtionCode_RebindingTime((byte) 59), OptionCode_ClientID(
(byte) 61), OptionCode_END((byte) 255);
protected byte value;
private DHCPOptionCode(final byte value) {
this.value = value;
}
public byte getValue() {
return this.value;
}
}
protected byte opCode;
protected byte hardwareType;
protected byte hardwareAddressLength;
protected byte hops;
protected int transactionId;
protected short seconds;
protected short flags;
protected int clientIPAddress;
protected int yourIPAddress;
protected int serverIPAddress;
protected int gatewayIPAddress;
protected byte[] clientHardwareAddress;
protected String serverName;
protected String bootFileName;
protected List<DHCPOption> options = new ArrayList<DHCPOption>();
/**
* @return the opCode
*/
public byte getOpCode() {
return this.opCode;
}
/**
* @param opCode
* the opCode to set
*/
public DHCP setOpCode(final byte opCode) {
this.opCode = opCode;
return this;
}
/**
* @return the hardwareType
*/
public byte getHardwareType() {
return this.hardwareType;
}
/**
* @param hardwareType
* the hardwareType to set
*/
public DHCP setHardwareType(final byte hardwareType) {
this.hardwareType = hardwareType;
return this;
}
/**
* @return the hardwareAddressLength
*/
public byte getHardwareAddressLength() {
return this.hardwareAddressLength;
}
/**
* @param hardwareAddressLength
* the hardwareAddressLength to set
*/
public DHCP setHardwareAddressLength(final byte hardwareAddressLength) {
this.hardwareAddressLength = hardwareAddressLength;
return this;
}
/**
* @return the hops
*/
public byte getHops() {
return this.hops;
}
/**
* @param hops
* the hops to set
*/
public DHCP setHops(final byte hops) {
this.hops = hops;
return this;
}
/**
* @return the transactionId
*/
public int getTransactionId() {
return this.transactionId;
}
/**
* @param transactionId
* the transactionId to set
*/
public DHCP setTransactionId(final int transactionId) {
this.transactionId = transactionId;
return this;
}
/**
* @return the seconds
*/
public short getSeconds() {
return this.seconds;
}
/**
* @param seconds
* the seconds to set
*/
public DHCP setSeconds(final short seconds) {
this.seconds = seconds;
return this;
}
/**
* @return the flags
*/
public short getFlags() {
return this.flags;
}
/**
* @param flags
* the flags to set
*/
public DHCP setFlags(final short flags) {
this.flags = flags;
return this;
}
/**
* @return the clientIPAddress
*/
public int getClientIPAddress() {
return this.clientIPAddress;
}
/**
* @param clientIPAddress
* the clientIPAddress to set
*/
public DHCP setClientIPAddress(final int clientIPAddress) {
this.clientIPAddress = clientIPAddress;
return this;
}
/**
* @return the yourIPAddress
*/
public int getYourIPAddress() {
return this.yourIPAddress;
}
/**
* @param yourIPAddress
* the yourIPAddress to set
*/
public DHCP setYourIPAddress(final int yourIPAddress) {
this.yourIPAddress = yourIPAddress;
return this;
}
/**
* @return the serverIPAddress
*/
public int getServerIPAddress() {
return this.serverIPAddress;
}
/**
* @param serverIPAddress
* the serverIPAddress to set
*/
public DHCP setServerIPAddress(final int serverIPAddress) {
this.serverIPAddress = serverIPAddress;
return this;
}
/**
* @return the gatewayIPAddress
*/
public int getGatewayIPAddress() {
return this.gatewayIPAddress;
}
/**
* @param gatewayIPAddress
* the gatewayIPAddress to set
*/
public DHCP setGatewayIPAddress(final int gatewayIPAddress) {
this.gatewayIPAddress = gatewayIPAddress;
return this;
}
/**
* @return the clientHardwareAddress
*/
public byte[] getClientHardwareAddress() {
return this.clientHardwareAddress;
}
/**
* @param clientHardwareAddress
* the clientHardwareAddress to set
*/
public DHCP setClientHardwareAddress(final byte[] clientHardwareAddress) {
this.clientHardwareAddress = clientHardwareAddress;
return this;
}
/**
* Gets a specific DHCP option parameter.
*
* @param opetionCode
* The option code to get
* @return The value of the option if it exists, null otherwise
*/
public DHCPOption getOption(final DHCPOptionCode optionCode) {
for (final DHCPOption opt : this.options) {
if (opt.code == optionCode.value) {
return opt;
}
}
return null;
}
/**
* @return the options
*/
public List<DHCPOption> getOptions() {
return this.options;
}
/**
* @param options
* the options to set
*/
public DHCP setOptions(final List<DHCPOption> options) {
this.options = options;
return this;
}
/**
* @return the packetType base on option 53
*/
public DHCPPacketType getPacketType() {
final ListIterator<DHCPOption> lit = this.options.listIterator();
while (lit.hasNext()) {
final DHCPOption option = lit.next();
// only care option 53
if (option.getCode() == 53) {
return DHCPPacketType.getType(option.getData()[0]);
}
}
return null;
}
/**
* @return the serverName
*/
public String getServerName() {
return this.serverName;
}
/**
* @param server
* the serverName to set
*/
public DHCP setServerName(final String server) {
this.serverName = server;
return this;
}
/**
* @return the bootFileName
*/
public String getBootFileName() {
return this.bootFileName;
}
/**
* @param bootFile
* the bootFileName to set
*/
public DHCP setBootFileName(final String bootFile) {
this.bootFileName = bootFile;
return this;
}
@Override
public byte[] serialize() {
// not guaranteed to retain length/exact format
this.resetChecksum();
// minimum size 240 including magic cookie, options generally padded to
// 300
int optionsLength = 0;
for (final DHCPOption option : this.options) {
if (option.getCode() == 0 || option.getCode() == 255) {
optionsLength += 1;
} else {
optionsLength += 2 + (0xff & option.getLength());
}
}
int optionsPadLength = 0;
if (optionsLength < 60) {
optionsPadLength = 60 - optionsLength;
}
final byte[] data = new byte[240 + optionsLength + optionsPadLength];
final ByteBuffer bb = ByteBuffer.wrap(data);
bb.put(this.opCode);
bb.put(this.hardwareType);
bb.put(this.hardwareAddressLength);
bb.put(this.hops);
bb.putInt(this.transactionId);
bb.putShort(this.seconds);
bb.putShort(this.flags);
bb.putInt(this.clientIPAddress);
bb.putInt(this.yourIPAddress);
bb.putInt(this.serverIPAddress);
bb.putInt(this.gatewayIPAddress);
bb.put(this.clientHardwareAddress);
if (this.clientHardwareAddress.length < 16) {
for (int i = 0; i < 16 - this.clientHardwareAddress.length; ++i) {
bb.put((byte) 0x0);
}
}
this.writeString(this.serverName, bb, 64);
this.writeString(this.bootFileName, bb, 128);
// magic cookie
bb.put((byte) 0x63);
bb.put((byte) 0x82);
bb.put((byte) 0x53);
bb.put((byte) 0x63);
for (final DHCPOption option : this.options) {
final int code = option.getCode() & 0xff;
bb.put((byte) code);
if (code != 0 && code != 255) {
bb.put(option.getLength());
bb.put(option.getData());
}
}
// assume the rest is padded out with zeroes
return data;
}
protected void writeString(final String string, final ByteBuffer bb,
final int maxLength) {
if (string == null) {
for (int i = 0; i < maxLength; ++i) {
bb.put((byte) 0x0);
}
} else {
byte[] bytes = null;
try {
bytes = string.getBytes("ascii");
} catch (final UnsupportedEncodingException e) {
throw new RuntimeException("Failure encoding server name", e);
}
int writeLength = bytes.length;
if (writeLength > maxLength) {
writeLength = maxLength;
}
bb.put(bytes, 0, writeLength);
for (int i = writeLength; i < maxLength; ++i) {
bb.put((byte) 0x0);
}
}
}
@Override
public IPacket deserialize(final byte[] data, final int offset,
final int length) {
final ByteBuffer bb = ByteBuffer.wrap(data, offset, length);
if (bb.remaining() < DHCP.MIN_HEADER_LENGTH) {
return this;
}
this.opCode = bb.get();
this.hardwareType = bb.get();
this.hardwareAddressLength = bb.get();
this.hops = bb.get();
this.transactionId = bb.getInt();
this.seconds = bb.getShort();
this.flags = bb.getShort();
this.clientIPAddress = bb.getInt();
this.yourIPAddress = bb.getInt();
this.serverIPAddress = bb.getInt();
this.gatewayIPAddress = bb.getInt();
final int hardwareAddressLength = 0xff & this.hardwareAddressLength;
this.clientHardwareAddress = new byte[hardwareAddressLength];
bb.get(this.clientHardwareAddress);
for (int i = hardwareAddressLength; i < 16; ++i) {
bb.get();
}
this.serverName = this.readString(bb, 64);
this.bootFileName = this.readString(bb, 128);
// read the magic cookie
// magic cookie
bb.get();
bb.get();
bb.get();
bb.get();
// read options
while (bb.hasRemaining()) {
final DHCPOption option = new DHCPOption();
int code = 0xff & bb.get(); // convert signed byte to int in range
// [0,255]
option.setCode((byte) code);
if (code == 0) {
// skip these
continue;
} else if (code != 255) {
if (bb.hasRemaining()) {
final int l = 0xff & bb.get(); // convert signed byte to
// int in range [0,255]
option.setLength((byte) l);
if (bb.remaining() >= l) {
final byte[] optionData = new byte[l];
bb.get(optionData);
option.setData(optionData);
} else {
// Skip the invalid option and set the END option
code = 0xff;
option.setCode((byte) code);
option.setLength((byte) 0);
}
} else {
// Skip the invalid option and set the END option
code = 0xff;
option.setCode((byte) code);
option.setLength((byte) 0);
}
}
this.options.add(option);
if (code == 255) {
// remaining bytes are supposed to be 0, but ignore them just in
// case
break;
}
}
return this;
}
protected String readString(final ByteBuffer bb, final int maxLength) {
final byte[] bytes = new byte[maxLength];
bb.get(bytes);
String result = null;
try {
result = new String(bytes, "ascii").trim();
} catch (final UnsupportedEncodingException e) {
throw new RuntimeException("Failure decoding string", e);
}
return result;
}
}
/*******************************************************************************
* Copyright 2014 Open Networking Laboratory
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
******************************************************************************/
/**
* 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 org.onlab.packet;
import java.util.Arrays;
/**
*
* @author David Erickson (daviderickson@cs.stanford.edu)
*/
public class DHCPOption {
protected byte code;
protected byte length;
protected byte[] data;
/**
* @return the code
*/
public byte getCode() {
return this.code;
}
/**
* @param code
* the code to set
*/
public DHCPOption setCode(final byte code) {
this.code = code;
return this;
}
/**
* @return the length
*/
public byte getLength() {
return this.length;
}
/**
* @param length
* the length to set
*/
public DHCPOption setLength(final byte length) {
this.length = length;
return this;
}
/**
* @return the data
*/
public byte[] getData() {
return this.data;
}
/**
* @param data
* the data to set
*/
public DHCPOption setData(final byte[] data) {
this.data = data;
return this;
}
/*
* (non-Javadoc)
*
* @see java.lang.Object#hashCode()
*/
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + this.code;
result = prime * result + Arrays.hashCode(this.data);
result = prime * result + this.length;
return result;
}
/*
* (non-Javadoc)
*
* @see java.lang.Object#equals(java.lang.Object)
*/
@Override
public boolean equals(final Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (!(obj instanceof DHCPOption)) {
return false;
}
final DHCPOption other = (DHCPOption) obj;
if (this.code != other.code) {
return false;
}
if (!Arrays.equals(this.data, other.data)) {
return false;
}
if (this.length != other.length) {
return false;
}
return true;
}
/*
* (non-Javadoc)
*
* @see java.lang.Object#toString()
*/
@Override
public String toString() {
return "DHCPOption [code=" + this.code + ", length=" + this.length
+ ", data=" + Arrays.toString(this.data) + "]";
}
}
/*******************************************************************************
* Copyright 2014 Open Networking Laboratory
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
******************************************************************************/
/**
* 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 org.onlab.packet;
public enum DHCPPacketType {
// From RFC 1533
DHCPDISCOVER(1), DHCPOFFER(2), DHCPREQUEST(3), DHCPDECLINE(4), DHCPACK(5), DHCPNAK(
6), DHCPRELEASE(7),
// From RFC2132
DHCPINFORM(8),
// From RFC3203
DHCPFORCERENEW(9),
// From RFC4388
DHCPLEASEQUERY(10), DHCPLEASEUNASSIGNED(11), DHCPLEASEUNKNOWN(12), DHCPLEASEACTIVE(
13);
protected int value;
private DHCPPacketType(final int value) {
this.value = value;
}
public int getValue() {
return this.value;
}
@Override
public String toString() {
switch (this.value) {
case 1:
return "DHCPDISCOVER";
case 2:
return "DHCPOFFER";
case 3:
return "DHCPREQUEST";
case 4:
return "DHCPDECLINE";
case 5:
return "DHCPACK";
case 6:
return "DHCPNAK";
case 7:
return "DHCPRELEASE";
case 8:
return "DHCPINFORM";
case 9:
return "DHCPFORCERENEW";
case 10:
return "DHCPLEASEQUERY";
case 11:
return "DHCPLEASEUNASSIGNED";
case 12:
return "DHCPLEASEUNKNOWN";
case 13:
return "DHCPLEASEACTIVE";
default:
break;
}
return null;
}
public static DHCPPacketType getType(final int value) {
switch (value) {
case 1:
return DHCPDISCOVER;
case 2:
return DHCPOFFER;
case 3:
return DHCPREQUEST;
case 4:
return DHCPDECLINE;
case 5:
return DHCPACK;
case 6:
return DHCPNAK;
case 7:
return DHCPRELEASE;
case 8:
return DHCPINFORM;
case 9:
return DHCPFORCERENEW;
case 10:
return DHCPLEASEQUERY;
case 11:
return DHCPLEASEUNASSIGNED;
case 12:
return DHCPLEASEUNKNOWN;
case 13:
return DHCPLEASEACTIVE;
default:
break;
}
return null;
}
}
/*******************************************************************************
* Copyright 2014 Open Networking Laboratory
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
******************************************************************************/
/**
* 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 org.onlab.packet;
import java.util.Arrays;
/**
*
* @author David Erickson (daviderickson@cs.stanford.edu)
*/
public class Data extends BasePacket {
protected byte[] data;
/**
*
*/
public Data() {
}
/**
* @param data
*/
public Data(final byte[] data) {
this.data = data;
}
/**
* @return the data
*/
public byte[] getData() {
return this.data;
}
/**
* @param data
* the data to set
*/
public Data setData(final byte[] data) {
this.data = data;
return this;
}
@Override
public byte[] serialize() {
return this.data;
}
@Override
public IPacket deserialize(final byte[] data, final int offset,
final int length) {
this.data = Arrays.copyOfRange(data, offset, data.length);
return this;
}
/*
* (non-Javadoc)
*
* @see java.lang.Object#hashCode()
*/
@Override
public int hashCode() {
final int prime = 1571;
int result = super.hashCode();
result = prime * result + Arrays.hashCode(this.data);
return result;
}
/*
* (non-Javadoc)
*
* @see java.lang.Object#equals(java.lang.Object)
*/
@Override
public boolean equals(final Object obj) {
if (this == obj) {
return true;
}
if (!super.equals(obj)) {
return false;
}
if (!(obj instanceof Data)) {
return false;
}
final Data other = (Data) obj;
if (!Arrays.equals(this.data, other.data)) {
return false;
}
return true;
}
}
/*******************************************************************************
* Copyright 2014 Open Networking Laboratory
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
******************************************************************************/
/**
* 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 org.onlab.packet;
import java.nio.ByteBuffer;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
/**
*
* @author David Erickson (daviderickson@cs.stanford.edu)
*/
public class Ethernet extends BasePacket {
private static final String HEXES = "0123456789ABCDEF";
public static final short TYPE_ARP = 0x0806;
public static final short TYPE_RARP = (short) 0x8035;
public static final short TYPE_IPV4 = 0x0800;
public static final short TYPE_LLDP = (short) 0x88cc;
public static final short TYPE_BSN = (short) 0x8942;
public static final short VLAN_UNTAGGED = (short) 0xffff;
public static final short DATALAYER_ADDRESS_LENGTH = 6; // bytes
public static Map<Short, Class<? extends IPacket>> etherTypeClassMap;
static {
Ethernet.etherTypeClassMap = new HashMap<Short, Class<? extends IPacket>>();
Ethernet.etherTypeClassMap.put(Ethernet.TYPE_ARP, ARP.class);
Ethernet.etherTypeClassMap.put(Ethernet.TYPE_RARP, ARP.class);
Ethernet.etherTypeClassMap.put(Ethernet.TYPE_IPV4, IPv4.class);
Ethernet.etherTypeClassMap.put(Ethernet.TYPE_LLDP, LLDP.class);
}
protected MACAddress destinationMACAddress;
protected MACAddress sourceMACAddress;
protected byte priorityCode;
protected short vlanID;
protected short etherType;
protected boolean pad = false;
/**
* By default, set Ethernet to untagged.
*/
public Ethernet() {
super();
this.vlanID = Ethernet.VLAN_UNTAGGED;
}
/**
* Gets the destination MAC address.
*
* @return the destination MAC as a byte array
*/
public byte[] getDestinationMACAddress() {
return this.destinationMACAddress.toBytes();
}
/**
* Gets the destination MAC address.
*
* @return the destination MAC
*/
public MACAddress getDestinationMAC() {
return this.destinationMACAddress;
}
/**
* Sets the destination MAC address.
*
* @param destinationMACAddress the destination MAC to set
* @return the Ethernet frame
*/
public Ethernet setDestinationMACAddress(final byte[] destMac) {
this.destinationMACAddress = MACAddress.valueOf(destMac);
return this;
}
/**
* Sets the destination MAC address.
*
* @param destinationMACAddress the destination MAC to set
* @return the Ethernet frame
*/
public Ethernet setDestinationMACAddress(final String destMac) {
this.destinationMACAddress = MACAddress.valueOf(destMac);
return this;
}
/**
* Gets the source MAC address.
*
* @return the source MACAddress as a byte array
*/
public byte[] getSourceMACAddress() {
return this.sourceMACAddress.toBytes();
}
/**
* Gets the source MAC address.
*
* @return the source MACAddress
*/
public MACAddress getSourceMAC() {
return this.sourceMACAddress;
}
/**
* Sets the source MAC address.
*
* @param sourceMACAddress the source MAC to set
* @return the Ethernet frame
*/
public Ethernet setSourceMACAddress(final byte[] sourceMac) {
this.sourceMACAddress = MACAddress.valueOf(sourceMac);
return this;
}
/**
* Sets the source MAC address.
*
* @param sourceMACAddress the source MAC to set
* @return the Ethernet frame
*/
public Ethernet setSourceMACAddress(final String sourceMac) {
this.sourceMACAddress = MACAddress.valueOf(sourceMac);
return this;
}
/**
* Gets the priority code.
*
* @return the priorityCode
*/
public byte getPriorityCode() {
return this.priorityCode;
}
/**
* Sets the priority code.
*
* @param priorityCode the priorityCode to set
* @return the Ethernet frame
*/
public Ethernet setPriorityCode(final byte priority) {
this.priorityCode = priority;
return this;
}
/**
* Gets the VLAN ID.
*
* @return the vlanID
*/
public short getVlanID() {
return this.vlanID;
}
/**
* Sets the VLAN ID.
*
* @param vlanID the vlanID to set
* @return the Ethernet frame
*/
public Ethernet setVlanID(final short vlan) {
this.vlanID = vlan;
return this;
}
/**
* Gets the Ethernet type.
*
* @return the etherType
*/
public short getEtherType() {
return this.etherType;
}
/**
* Sets the Ethernet type.
*
* @param etherType the etherType to set
* @return the Ethernet frame
*/
public Ethernet setEtherType(final short ethType) {
this.etherType = ethType;
return this;
}
/**
* @return True if the Ethernet frame is broadcast, false otherwise
*/
public boolean isBroadcast() {
assert this.destinationMACAddress.length() == 6;
return this.destinationMACAddress.isBroadcast();
}
/**
* @return True is the Ethernet frame is multicast, False otherwise
*/
public boolean isMulticast() {
return this.destinationMACAddress.isMulticast();
}
/**
* Pad this packet to 60 bytes minimum, filling with zeros?
*
* @return the pad
*/
public boolean isPad() {
return this.pad;
}
/**
* Pad this packet to 60 bytes minimum, filling with zeros?
*
* @param pad
* the pad to set
*/
public Ethernet setPad(final boolean pd) {
this.pad = pd;
return this;
}
@Override
public byte[] serialize() {
byte[] payloadData = null;
if (this.payload != null) {
this.payload.setParent(this);
payloadData = this.payload.serialize();
}
int length = 14 + (this.vlanID == Ethernet.VLAN_UNTAGGED ? 0 : 4)
+ (payloadData == null ? 0 : payloadData.length);
if (this.pad && length < 60) {
length = 60;
}
final byte[] data = new byte[length];
final ByteBuffer bb = ByteBuffer.wrap(data);
bb.put(this.destinationMACAddress.toBytes());
bb.put(this.sourceMACAddress.toBytes());
if (this.vlanID != Ethernet.VLAN_UNTAGGED) {
bb.putShort((short) 0x8100);
bb.putShort((short) (this.priorityCode << 13 | this.vlanID & 0x0fff));
}
bb.putShort(this.etherType);
if (payloadData != null) {
bb.put(payloadData);
}
if (this.pad) {
Arrays.fill(data, bb.position(), data.length, (byte) 0x0);
}
return data;
}
@Override
public IPacket deserialize(final byte[] data, final int offset,
final int length) {
if (length <= 0) {
return null;
}
final ByteBuffer bb = ByteBuffer.wrap(data, offset, length);
if (this.destinationMACAddress == null) {
this.destinationMACAddress = MACAddress.valueOf(new byte[6]);
}
final byte[] dstAddr = new byte[MACAddress.MAC_ADDRESS_LENGTH];
bb.get(dstAddr);
this.destinationMACAddress = MACAddress.valueOf(dstAddr);
if (this.sourceMACAddress == null) {
this.sourceMACAddress = MACAddress.valueOf(new byte[6]);
}
final byte[] srcAddr = new byte[MACAddress.MAC_ADDRESS_LENGTH];
bb.get(srcAddr);
this.sourceMACAddress = MACAddress.valueOf(srcAddr);
short ethType = bb.getShort();
if (ethType == (short) 0x8100) {
final short tci = bb.getShort();
this.priorityCode = (byte) (tci >> 13 & 0x07);
this.vlanID = (short) (tci & 0x0fff);
ethType = bb.getShort();
} else {
this.vlanID = Ethernet.VLAN_UNTAGGED;
}
this.etherType = ethType;
IPacket payload;
if (Ethernet.etherTypeClassMap.containsKey(this.etherType)) {
final Class<? extends IPacket> clazz = Ethernet.etherTypeClassMap
.get(this.etherType);
try {
payload = clazz.newInstance();
} catch (final Exception e) {
throw new RuntimeException(
"Error parsing payload for Ethernet packet", e);
}
} else {
payload = new Data();
}
this.payload = payload.deserialize(data, bb.position(),
bb.limit() - bb.position());
this.payload.setParent(this);
return this;
}
/**
* Checks to see if a string is a valid MAC address.
*
* @param macAddress
* @return True if macAddress is a valid MAC, False otherwise
*/
public static boolean isMACAddress(final String macAddress) {
final String[] macBytes = macAddress.split(":");
if (macBytes.length != 6) {
return false;
}
for (int i = 0; i < 6; ++i) {
if (Ethernet.HEXES.indexOf(macBytes[i].toUpperCase().charAt(0)) == -1
|| Ethernet.HEXES.indexOf(macBytes[i].toUpperCase().charAt(
1)) == -1) {
return false;
}
}
return true;
}
/**
* Accepts a MAC address of the form 00:aa:11:bb:22:cc, case does not
* matter, and returns a corresponding byte[].
*
* @param macAddress
* The MAC address to convert into a bye array
* @return The macAddress as a byte array
*/
public static byte[] toMACAddress(final String macAddress) {
return MACAddress.valueOf(macAddress).toBytes();
}
/**
* Accepts a MAC address and returns the corresponding long, where the MAC
* bytes are set on the lower order bytes of the long.
*
* @param macAddress
* @return a long containing the mac address bytes
*/
public static long toLong(final byte[] macAddress) {
return MACAddress.valueOf(macAddress).toLong();
}
/**
* Converts a long MAC address to a byte array.
*
* @param macAddress
* @return the bytes of the mac address
*/
public static byte[] toByteArray(final long macAddress) {
return MACAddress.valueOf(macAddress).toBytes();
}
/*
* (non-Javadoc)
*
* @see java.lang.Object#hashCode()
*/
@Override
public int hashCode() {
final int prime = 7867;
int result = super.hashCode();
result = prime * result + this.destinationMACAddress.hashCode();
result = prime * result + this.etherType;
result = prime * result + this.vlanID;
result = prime * result + this.priorityCode;
result = prime * result + (this.pad ? 1231 : 1237);
result = prime * result + this.sourceMACAddress.hashCode();
return result;
}
/*
* (non-Javadoc)
*
* @see java.lang.Object#equals(java.lang.Object)
*/
@Override
public boolean equals(final Object obj) {
if (this == obj) {
return true;
}
if (!super.equals(obj)) {
return false;
}
if (!(obj instanceof Ethernet)) {
return false;
}
final Ethernet other = (Ethernet) obj;
if (!this.destinationMACAddress.equals(other.destinationMACAddress)) {
return false;
}
if (this.priorityCode != other.priorityCode) {
return false;
}
if (this.vlanID != other.vlanID) {
return false;
}
if (this.etherType != other.etherType) {
return false;
}
if (this.pad != other.pad) {
return false;
}
if (!this.sourceMACAddress.equals(other.sourceMACAddress)) {
return false;
}
return true;
}
/*
* (non-Javadoc)
*
* @see java.lang.Object#toString(java.lang.Object)
*/
@Override
public String toString() {
final StringBuffer sb = new StringBuffer("\n");
final IPacket pkt = this.getPayload();
if (pkt instanceof ARP) {
sb.append("arp");
} else if (pkt instanceof LLDP) {
sb.append("lldp");
} else if (pkt instanceof ICMP) {
sb.append("icmp");
} else if (pkt instanceof IPv4) {
sb.append("ip");
} else if (pkt instanceof DHCP) {
sb.append("dhcp");
} else {
sb.append(this.getEtherType());
}
sb.append("\ndl_vlan: ");
if (this.getVlanID() == Ethernet.VLAN_UNTAGGED) {
sb.append("untagged");
} else {
sb.append(this.getVlanID());
}
sb.append("\ndl_vlan_pcp: ");
sb.append(this.getPriorityCode());
sb.append("\ndl_src: ");
sb.append(bytesToHex(this.getSourceMACAddress()));
sb.append("\ndl_dst: ");
sb.append(bytesToHex(this.getDestinationMACAddress()));
if (pkt instanceof ARP) {
final ARP p = (ARP) pkt;
sb.append("\nnw_src: ");
sb.append(IPv4.fromIPv4Address(IPv4.toIPv4Address(p
.getSenderProtocolAddress())));
sb.append("\nnw_dst: ");
sb.append(IPv4.fromIPv4Address(IPv4.toIPv4Address(p
.getTargetProtocolAddress())));
} else if (pkt instanceof LLDP) {
sb.append("lldp packet");
} else if (pkt instanceof ICMP) {
final ICMP icmp = (ICMP) pkt;
sb.append("\nicmp_type: ");
sb.append(icmp.getIcmpType());
sb.append("\nicmp_code: ");
sb.append(icmp.getIcmpCode());
} else if (pkt instanceof IPv4) {
final IPv4 p = (IPv4) pkt;
sb.append("\nnw_src: ");
sb.append(IPv4.fromIPv4Address(p.getSourceAddress()));
sb.append("\nnw_dst: ");
sb.append(IPv4.fromIPv4Address(p.getDestinationAddress()));
sb.append("\nnw_tos: ");
sb.append(p.getDiffServ());
sb.append("\nnw_proto: ");
sb.append(p.getProtocol());
if (pkt instanceof TCP) {
sb.append("\ntp_src: ");
sb.append(((TCP) pkt).getSourcePort());
sb.append("\ntp_dst: ");
sb.append(((TCP) pkt).getDestinationPort());
} else if (pkt instanceof UDP) {
sb.append("\ntp_src: ");
sb.append(((UDP) pkt).getSourcePort());
sb.append("\ntp_dst: ");
sb.append(((UDP) pkt).getDestinationPort());
}
if (pkt instanceof ICMP) {
final ICMP icmp = (ICMP) pkt;
sb.append("\nicmp_type: ");
sb.append(icmp.getIcmpType());
sb.append("\nicmp_code: ");
sb.append(icmp.getIcmpCode());
}
} else if (pkt instanceof DHCP) {
sb.append("\ndhcp packet");
} else if (pkt instanceof Data) {
sb.append("\ndata packet");
} else if (pkt instanceof LLC) {
sb.append("\nllc packet");
} else {
sb.append("\nunknwon packet");
}
return sb.toString();
}
public static String bytesToHex(byte[] in) {
final StringBuilder builder = new StringBuilder();
for (byte b : in) {
builder.append(String.format("%02x", b));
}
return builder.toString();
}
}
/*******************************************************************************
* Copyright 2014 Open Networking Laboratory
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
******************************************************************************/
/**
* 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 org.onlab.packet;
import java.nio.ByteBuffer;
/**
* Implements ICMP packet format.
*
* @author shudong.zhou@bigswitch.com
*/
public class ICMP extends BasePacket {
protected byte icmpType;
protected byte icmpCode;
protected short checksum;
/**
* @return the icmpType
*/
public byte getIcmpType() {
return this.icmpType;
}
/**
* @param icmpType
* to set
*/
public ICMP setIcmpType(final byte icmpType) {
this.icmpType = icmpType;
return this;
}
/**
* @return the icmp code
*/
public byte getIcmpCode() {
return this.icmpCode;
}
/**
* @param icmpCode
* code to set
*/
public ICMP setIcmpCode(final byte icmpCode) {
this.icmpCode = icmpCode;
return this;
}
/**
* @return the checksum
*/
public short getChecksum() {
return this.checksum;
}
/**
* @param checksum
* the checksum to set
*/
public ICMP setChecksum(final short checksum) {
this.checksum = checksum;
return this;
}
/**
* Serializes the packet. Will compute and set the following fields if they
* are set to specific values at the time serialize is called: -checksum : 0
* -length : 0
*/
@Override
public byte[] serialize() {
int length = 4;
byte[] payloadData = null;
if (this.payload != null) {
this.payload.setParent(this);
payloadData = this.payload.serialize();
length += payloadData.length;
}
final byte[] data = new byte[length];
final ByteBuffer bb = ByteBuffer.wrap(data);
bb.put(this.icmpType);
bb.put(this.icmpCode);
bb.putShort(this.checksum);
if (payloadData != null) {
bb.put(payloadData);
}
if (this.parent != null && this.parent instanceof IPv4) {
((IPv4) this.parent).setProtocol(IPv4.PROTOCOL_ICMP);
}
// compute checksum if needed
if (this.checksum == 0) {
bb.rewind();
int accumulation = 0;
for (int i = 0; i < length / 2; ++i) {
accumulation += 0xffff & bb.getShort();
}
// pad to an even number of shorts
if (length % 2 > 0) {
accumulation += (bb.get() & 0xff) << 8;
}
accumulation = (accumulation >> 16 & 0xffff)
+ (accumulation & 0xffff);
this.checksum = (short) (~accumulation & 0xffff);
bb.putShort(2, this.checksum);
}
return data;
}
/*
* (non-Javadoc)
*
* @see java.lang.Object#hashCode()
*/
@Override
public int hashCode() {
final int prime = 5807;
int result = super.hashCode();
result = prime * result + this.icmpType;
result = prime * result + this.icmpCode;
result = prime * result + this.checksum;
return result;
}
/*
* (non-Javadoc)
*
* @see java.lang.Object#equals(java.lang.Object)
*/
@Override
public boolean equals(final Object obj) {
if (this == obj) {
return true;
}
if (!super.equals(obj)) {
return false;
}
if (!(obj instanceof ICMP)) {
return false;
}
final ICMP other = (ICMP) obj;
if (this.icmpType != other.icmpType) {
return false;
}
if (this.icmpCode != other.icmpCode) {
return false;
}
if (this.checksum != other.checksum) {
return false;
}
return true;
}
@Override
public IPacket deserialize(final byte[] data, final int offset,
final int length) {
final ByteBuffer bb = ByteBuffer.wrap(data, offset, length);
this.icmpType = bb.get();
this.icmpCode = bb.get();
this.checksum = bb.getShort();
this.payload = new Data();
this.payload = this.payload.deserialize(data, bb.position(), bb.limit()
- bb.position());
this.payload.setParent(this);
return this;
}
}
/*******************************************************************************
* Copyright 2014 Open Networking Laboratory
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
******************************************************************************/
/**
* 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 org.onlab.packet;
/**
*
* @author David Erickson (daviderickson@cs.stanford.edu)
*/
public interface IPacket {
/**
*
* @return
*/
public IPacket getPayload();
/**
*
* @param packet
* @return
*/
public IPacket setPayload(IPacket packet);
/**
*
* @return
*/
public IPacket getParent();
/**
*
* @param packet
* @return
*/
public IPacket setParent(IPacket packet);
/**
* Reset any checksums as needed, and call resetChecksum on all parents.
*/
public void resetChecksum();
/**
* Sets all payloads parent packet if applicable, then serializes this
* packet and all payloads.
*
* @return a byte[] containing this packet and payloads
*/
public byte[] serialize();
/**
* Deserializes this packet layer and all possible payloads.
*
* @param data
* @param offset
* offset to start deserializing from
* @param length
* length of the data to deserialize
* @return the deserialized data
*/
public IPacket deserialize(byte[] data, int offset, int length);
/**
* Clone this packet and its payload packet but not its parent.
*
* @return
*/
public Object clone();
}
/*******************************************************************************
* Copyright 2014 Open Networking Laboratory
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
******************************************************************************/
/**
* 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 org.onlab.packet;
import java.nio.ByteBuffer;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
/**
* @author David Erickson (daviderickson@cs.stanford.edu)
*
*/
public class IPv4 extends BasePacket {
public static final byte PROTOCOL_ICMP = 0x1;
public static final byte PROTOCOL_TCP = 0x6;
public static final byte PROTOCOL_UDP = 0x11;
public static Map<Byte, Class<? extends IPacket>> protocolClassMap;
static {
IPv4.protocolClassMap = new HashMap<Byte, Class<? extends IPacket>>();
IPv4.protocolClassMap.put(IPv4.PROTOCOL_ICMP, ICMP.class);
IPv4.protocolClassMap.put(IPv4.PROTOCOL_TCP, TCP.class);
IPv4.protocolClassMap.put(IPv4.PROTOCOL_UDP, UDP.class);
}
protected byte version;
protected byte headerLength;
protected byte diffServ;
protected short totalLength;
protected short identification;
protected byte flags;
protected short fragmentOffset;
protected byte ttl;
protected byte protocol;
protected short checksum;
protected int sourceAddress;
protected int destinationAddress;
protected byte[] options;
protected boolean isTruncated;
/**
* Default constructor that sets the version to 4.
*/
public IPv4() {
super();
this.version = 4;
this.isTruncated = false;
}
/**
* @return the version
*/
public byte getVersion() {
return this.version;
}
/**
* @param version
* the version to set
*/
public IPv4 setVersion(final byte version) {
this.version = version;
return this;
}
/**
* @return the headerLength
*/
public byte getHeaderLength() {
return this.headerLength;
}
/**
* @return the diffServ
*/
public byte getDiffServ() {
return this.diffServ;
}
/**
* @param diffServ
* the diffServ to set
*/
public IPv4 setDiffServ(final byte diffServ) {
this.diffServ = diffServ;
return this;
}
/**
* @return the totalLength
*/
public short getTotalLength() {
return this.totalLength;
}
/**
* @return the identification
*/
public short getIdentification() {
return this.identification;
}
public boolean isTruncated() {
return this.isTruncated;
}
public void setTruncated(final boolean isTruncated) {
this.isTruncated = isTruncated;
}
/**
* @param identification
* the identification to set
*/
public IPv4 setIdentification(final short identification) {
this.identification = identification;
return this;
}
/**
* @return the flags
*/
public byte getFlags() {
return this.flags;
}
/**
* @param flags
* the flags to set
*/
public IPv4 setFlags(final byte flags) {
this.flags = flags;
return this;
}
/**
* @return the fragmentOffset
*/
public short getFragmentOffset() {
return this.fragmentOffset;
}
/**
* @param fragmentOffset
* the fragmentOffset to set
*/
public IPv4 setFragmentOffset(final short fragmentOffset) {
this.fragmentOffset = fragmentOffset;
return this;
}
/**
* @return the ttl
*/
public byte getTtl() {
return this.ttl;
}
/**
* @param ttl
* the ttl to set
*/
public IPv4 setTtl(final byte ttl) {
this.ttl = ttl;
return this;
}
/**
* @return the protocol
*/
public byte getProtocol() {
return this.protocol;
}
/**
* @param protocol
* the protocol to set
*/
public IPv4 setProtocol(final byte protocol) {
this.protocol = protocol;
return this;
}
/**
* @return the checksum
*/
public short getChecksum() {
return this.checksum;
}
/**
* @param checksum
* the checksum to set
*/
public IPv4 setChecksum(final short checksum) {
this.checksum = checksum;
return this;
}
@Override
public void resetChecksum() {
this.checksum = 0;
super.resetChecksum();
}
/**
* @return the sourceAddress
*/
public int getSourceAddress() {
return this.sourceAddress;
}
/**
* @param sourceAddress
* the sourceAddress to set
*/
public IPv4 setSourceAddress(final int sourceAddress) {
this.sourceAddress = sourceAddress;
return this;
}
/**
* @param sourceAddress
* the sourceAddress to set
*/
public IPv4 setSourceAddress(final String sourceAddress) {
this.sourceAddress = IPv4.toIPv4Address(sourceAddress);
return this;
}
/**
* @return the destinationAddress
*/
public int getDestinationAddress() {
return this.destinationAddress;
}
/**
* @param destinationAddress
* the destinationAddress to set
*/
public IPv4 setDestinationAddress(final int destinationAddress) {
this.destinationAddress = destinationAddress;
return this;
}
/**
* @param destinationAddress
* the destinationAddress to set
*/
public IPv4 setDestinationAddress(final String destinationAddress) {
this.destinationAddress = IPv4.toIPv4Address(destinationAddress);
return this;
}
/**
* @return the options
*/
public byte[] getOptions() {
return this.options;
}
/**
* @param options
* the options to set
*/
public IPv4 setOptions(final byte[] options) {
if (options != null && options.length % 4 > 0) {
throw new IllegalArgumentException(
"Options length must be a multiple of 4");
}
this.options = options;
return this;
}
/**
* Serializes the packet. Will compute and set the following fields if they
* are set to specific values at the time serialize is called: -checksum : 0
* -headerLength : 0 -totalLength : 0
*/
@Override
public byte[] serialize() {
byte[] payloadData = null;
if (this.payload != null) {
this.payload.setParent(this);
payloadData = this.payload.serialize();
}
int optionsLength = 0;
if (this.options != null) {
optionsLength = this.options.length / 4;
}
this.headerLength = (byte) (5 + optionsLength);
this.totalLength = (short) (this.headerLength * 4 + (payloadData == null ? 0
: payloadData.length));
final byte[] data = new byte[this.totalLength];
final ByteBuffer bb = ByteBuffer.wrap(data);
bb.put((byte) ((this.version & 0xf) << 4 | this.headerLength & 0xf));
bb.put(this.diffServ);
bb.putShort(this.totalLength);
bb.putShort(this.identification);
bb.putShort((short) ((this.flags & 0x7) << 13 | this.fragmentOffset & 0x1fff));
bb.put(this.ttl);
bb.put(this.protocol);
bb.putShort(this.checksum);
bb.putInt(this.sourceAddress);
bb.putInt(this.destinationAddress);
if (this.options != null) {
bb.put(this.options);
}
if (payloadData != null) {
bb.put(payloadData);
}
// compute checksum if needed
if (this.checksum == 0) {
bb.rewind();
int accumulation = 0;
for (int i = 0; i < this.headerLength * 2; ++i) {
accumulation += 0xffff & bb.getShort();
}
accumulation = (accumulation >> 16 & 0xffff)
+ (accumulation & 0xffff);
this.checksum = (short) (~accumulation & 0xffff);
bb.putShort(10, this.checksum);
}
return data;
}
@Override
public IPacket deserialize(final byte[] data, final int offset,
final int length) {
final ByteBuffer bb = ByteBuffer.wrap(data, offset, length);
short sscratch;
this.version = bb.get();
this.headerLength = (byte) (this.version & 0xf);
this.version = (byte) (this.version >> 4 & 0xf);
this.diffServ = bb.get();
this.totalLength = bb.getShort();
this.identification = bb.getShort();
sscratch = bb.getShort();
this.flags = (byte) (sscratch >> 13 & 0x7);
this.fragmentOffset = (short) (sscratch & 0x1fff);
this.ttl = bb.get();
this.protocol = bb.get();
this.checksum = bb.getShort();
this.sourceAddress = bb.getInt();
this.destinationAddress = bb.getInt();
if (this.headerLength > 5) {
final int optionsLength = (this.headerLength - 5) * 4;
this.options = new byte[optionsLength];
bb.get(this.options);
}
IPacket payload;
if (IPv4.protocolClassMap.containsKey(this.protocol)) {
final Class<? extends IPacket> clazz = IPv4.protocolClassMap
.get(this.protocol);
try {
payload = clazz.newInstance();
} catch (final Exception e) {
throw new RuntimeException(
"Error parsing payload for IPv4 packet", e);
}
} else {
payload = new Data();
}
this.payload = payload.deserialize(data, bb.position(),
bb.limit() - bb.position());
this.payload.setParent(this);
if (this.totalLength != length) {
this.isTruncated = true;
} else {
this.isTruncated = false;
}
return this;
}
/**
* Accepts an IPv4 address of the form xxx.xxx.xxx.xxx, ie 192.168.0.1 and
* returns the corresponding 32 bit integer.
*
* @param ipAddress
* @return
*/
public static int toIPv4Address(final String ipAddress) {
if (ipAddress == null) {
throw new IllegalArgumentException("Specified IPv4 address must"
+ "contain 4 sets of numerical digits separated by periods");
}
final String[] octets = ipAddress.split("\\.");
if (octets.length != 4) {
throw new IllegalArgumentException("Specified IPv4 address must"
+ "contain 4 sets of numerical digits separated by periods");
}
int result = 0;
for (int i = 0; i < 4; ++i) {
result |= Integer.valueOf(octets[i]) << (3 - i) * 8;
}
return result;
}
/**
* Accepts an IPv4 address in a byte array and returns the corresponding
* 32-bit integer value.
*
* @param ipAddress
* @return
*/
public static int toIPv4Address(final byte[] ipAddress) {
int ip = 0;
for (int i = 0; i < 4; i++) {
final int t = (ipAddress[i] & 0xff) << (3 - i) * 8;
ip |= t;
}
return ip;
}
/**
* Accepts an IPv4 address and returns of string of the form xxx.xxx.xxx.xxx,
* e.g., 192.168.0.1.
*
* @param ipAddress
* @return
*/
public static String fromIPv4Address(final int ipAddress) {
final StringBuffer sb = new StringBuffer();
int result = 0;
for (int i = 0; i < 4; ++i) {
result = ipAddress >> (3 - i) * 8 & 0xff;
sb.append(Integer.valueOf(result).toString());
if (i != 3) {
sb.append(".");
}
}
return sb.toString();
}
/**
* Accepts a collection of IPv4 addresses as integers and returns a single
* String useful in toString method's containing collections of IP
* addresses.
*
* @param ipAddresses
* collection
* @return
*/
public static String fromIPv4AddressCollection(
final Collection<Integer> ipAddresses) {
if (ipAddresses == null) {
return "null";
}
final StringBuffer sb = new StringBuffer();
sb.append("[");
for (final Integer ip : ipAddresses) {
sb.append(IPv4.fromIPv4Address(ip));
sb.append(",");
}
sb.replace(sb.length() - 1, sb.length(), "]");
return sb.toString();
}
/**
* Accepts an IPv4 address of the form xxx.xxx.xxx.xxx, ie 192.168.0.1 and
* returns the corresponding byte array.
*
* @param ipAddress
* The IP address in the form xx.xxx.xxx.xxx.
* @return The IP address separated into bytes
*/
public static byte[] toIPv4AddressBytes(final String ipAddress) {
final String[] octets = ipAddress.split("\\.");
if (octets.length != 4) {
throw new IllegalArgumentException("Specified IPv4 address must"
+ "contain 4 sets of numerical digits separated by periods");
}
final byte[] result = new byte[4];
for (int i = 0; i < 4; ++i) {
result[i] = Integer.valueOf(octets[i]).byteValue();
}
return result;
}
/**
* Accepts an IPv4 address in the form of an integer and returns the
* corresponding byte array.
*
* @param ipAddress
* The IP address as an integer.
* @return The IP address separated into bytes.
*/
public static byte[] toIPv4AddressBytes(final int ipAddress) {
return new byte[] {(byte) (ipAddress >>> 24),
(byte) (ipAddress >>> 16), (byte) (ipAddress >>> 8),
(byte) ipAddress};
}
/*
* (non-Javadoc)
*
* @see java.lang.Object#hashCode()
*/
@Override
public int hashCode() {
final int prime = 2521;
int result = super.hashCode();
result = prime * result + this.checksum;
result = prime * result + this.destinationAddress;
result = prime * result + this.diffServ;
result = prime * result + this.flags;
result = prime * result + this.fragmentOffset;
result = prime * result + this.headerLength;
result = prime * result + this.identification;
result = prime * result + Arrays.hashCode(this.options);
result = prime * result + this.protocol;
result = prime * result + this.sourceAddress;
result = prime * result + this.totalLength;
result = prime * result + this.ttl;
result = prime * result + this.version;
return result;
}
/*
* (non-Javadoc)
*
* @see java.lang.Object#equals(java.lang.Object)
*/
@Override
public boolean equals(final Object obj) {
if (this == obj) {
return true;
}
if (!super.equals(obj)) {
return false;
}
if (!(obj instanceof IPv4)) {
return false;
}
final IPv4 other = (IPv4) obj;
if (this.checksum != other.checksum) {
return false;
}
if (this.destinationAddress != other.destinationAddress) {
return false;
}
if (this.diffServ != other.diffServ) {
return false;
}
if (this.flags != other.flags) {
return false;
}
if (this.fragmentOffset != other.fragmentOffset) {
return false;
}
if (this.headerLength != other.headerLength) {
return false;
}
if (this.identification != other.identification) {
return false;
}
if (!Arrays.equals(this.options, other.options)) {
return false;
}
if (this.protocol != other.protocol) {
return false;
}
if (this.sourceAddress != other.sourceAddress) {
return false;
}
if (this.totalLength != other.totalLength) {
return false;
}
if (this.ttl != other.ttl) {
return false;
}
if (this.version != other.version) {
return false;
}
return true;
}
}
/*******************************************************************************
* Copyright 2014 Open Networking Laboratory
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
******************************************************************************/
/**
* 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 org.onlab.packet;
import java.nio.ByteBuffer;
/**
* This class represents an Link Local Control header that is used in Ethernet
* 802.3.
*
* @author alexreimers
*
*/
public class LLC extends BasePacket {
private byte dsap = 0;
private byte ssap = 0;
private byte ctrl = 0;
public byte getDsap() {
return this.dsap;
}
public void setDsap(final byte dsap) {
this.dsap = dsap;
}
public byte getSsap() {
return this.ssap;
}
public void setSsap(final byte ssap) {
this.ssap = ssap;
}
public byte getCtrl() {
return this.ctrl;
}
public void setCtrl(final byte ctrl) {
this.ctrl = ctrl;
}
@Override
public byte[] serialize() {
final byte[] data = new byte[3];
final ByteBuffer bb = ByteBuffer.wrap(data);
bb.put(this.dsap);
bb.put(this.ssap);
bb.put(this.ctrl);
return data;
}
@Override
public IPacket deserialize(final byte[] data, final int offset,
final int length) {
final ByteBuffer bb = ByteBuffer.wrap(data, offset, length);
this.dsap = bb.get();
this.ssap = bb.get();
this.ctrl = bb.get();
return this;
}
}
/*******************************************************************************
* Copyright 2014 Open Networking Laboratory
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
******************************************************************************/
/**
* 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 org.onlab.packet;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.List;
/**
* @author David Erickson (daviderickson@cs.stanford.edu)
*
*/
public class LLDP extends BasePacket {
protected LLDPTLV chassisId;
protected LLDPTLV portId;
protected LLDPTLV ttl;
protected List<LLDPTLV> optionalTLVList;
protected short ethType;
public LLDP() {
this.optionalTLVList = new ArrayList<LLDPTLV>();
this.ethType = Ethernet.TYPE_LLDP;
}
/**
* @return the chassisId
*/
public LLDPTLV getChassisId() {
return this.chassisId;
}
/**
* @param chassisId
* the chassisId to set
*/
public LLDP setChassisId(final LLDPTLV chassis) {
this.chassisId = chassis;
return this;
}
/**
* @return the portId
*/
public LLDPTLV getPortId() {
return this.portId;
}
/**
* @param portId
* the portId to set
*/
public LLDP setPortId(final LLDPTLV portId) {
this.portId = portId;
return this;
}
/**
* @return the ttl
*/
public LLDPTLV getTtl() {
return this.ttl;
}
/**
* @param ttl
* the ttl to set
*/
public LLDP setTtl(final LLDPTLV ttl) {
this.ttl = ttl;
return this;
}
/**
* @return the optionalTLVList
*/
public List<LLDPTLV> getOptionalTLVList() {
return this.optionalTLVList;
}
/**
* @param optionalTLVList
* the optionalTLVList to set
*/
public LLDP setOptionalTLVList(final List<LLDPTLV> optionalTLVList) {
this.optionalTLVList = optionalTLVList;
return this;
}
@Override
public byte[] serialize() {
int length = 2 + this.chassisId.getLength() + 2
+ this.portId.getLength() + 2 + this.ttl.getLength() + 2;
for (final LLDPTLV tlv : this.optionalTLVList) {
length += 2 + tlv.getLength();
}
final byte[] data = new byte[length];
final ByteBuffer bb = ByteBuffer.wrap(data);
bb.put(this.chassisId.serialize());
bb.put(this.portId.serialize());
bb.put(this.ttl.serialize());
for (final LLDPTLV tlv : this.optionalTLVList) {
bb.put(tlv.serialize());
}
bb.putShort((short) 0); // End of LLDPDU
/*
* if (this.parent != null && this.parent instanceof Ethernet) {
* ((Ethernet) this.parent).setEtherType(this.ethType); }
*/
return data;
}
@Override
public IPacket deserialize(final byte[] data, final int offset,
final int length) {
final ByteBuffer bb = ByteBuffer.wrap(data, offset, length);
LLDPTLV tlv;
do {
tlv = new LLDPTLV().deserialize(bb);
// if there was a failure to deserialize stop processing TLVs
if (tlv == null) {
break;
}
switch (tlv.getType()) {
case 0x0:
// can throw this one away, its just an end delimiter
break;
case 0x1:
this.chassisId = tlv;
break;
case 0x2:
this.portId = tlv;
break;
case 0x3:
this.ttl = tlv;
break;
default:
this.optionalTLVList.add(tlv);
break;
}
} while (tlv.getType() != 0 && bb.hasRemaining());
return this;
}
/*
* (non-Javadoc)
*
* @see java.lang.Object#hashCode()
*/
@Override
public int hashCode() {
final int prime = 883;
int result = super.hashCode();
result = prime * result
+ (this.chassisId == null ? 0 : this.chassisId.hashCode());
result = prime * result + this.optionalTLVList.hashCode();
result = prime * result
+ (this.portId == null ? 0 : this.portId.hashCode());
result = prime * result + (this.ttl == null ? 0 : this.ttl.hashCode());
return result;
}
/*
* (non-Javadoc)
*
* @see java.lang.Object#equals(java.lang.Object)
*/
@Override
public boolean equals(final Object obj) {
if (this == obj) {
return true;
}
if (!super.equals(obj)) {
return false;
}
if (!(obj instanceof LLDP)) {
return false;
}
final LLDP other = (LLDP) obj;
if (this.chassisId == null) {
if (other.chassisId != null) {
return false;
}
} else if (!this.chassisId.equals(other.chassisId)) {
return false;
}
if (!this.optionalTLVList.equals(other.optionalTLVList)) {
return false;
}
if (this.portId == null) {
if (other.portId != null) {
return false;
}
} else if (!this.portId.equals(other.portId)) {
return false;
}
if (this.ttl == null) {
if (other.ttl != null) {
return false;
}
} else if (!this.ttl.equals(other.ttl)) {
return false;
}
return true;
}
}
/*******************************************************************************
* Copyright 2014 Open Networking Laboratory
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
******************************************************************************/
/**
* 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.onlab.packet;
import java.nio.ByteBuffer;
import java.nio.charset.Charset;
import java.util.Arrays;
/**
* The class representing LLDP Organizationally Specific TLV.
*
* @author Sho Shimizu (sho.shimizu@gmail.com)
*/
public class LLDPOrganizationalTLV extends LLDPTLV {
public static final int OUI_LENGTH = 3;
public static final int SUBTYPE_LENGTH = 1;
public static final byte ORGANIZATIONAL_TLV_TYPE = 127;
public static final int MAX_INFOSTRING_LENGTH = 507;
protected byte[] oui;
protected byte subType;
private byte[] infoString;
public LLDPOrganizationalTLV() {
this.type = LLDPOrganizationalTLV.ORGANIZATIONAL_TLV_TYPE;
}
/**
* Set the value of OUI.
*
* @param oui
* The value of OUI to be set.
* @return This LLDP Organizationally Specific TLV.
*/
public LLDPOrganizationalTLV setOUI(final byte[] oui) {
if (oui.length != LLDPOrganizationalTLV.OUI_LENGTH) {
throw new IllegalArgumentException("The length of OUI must be "
+ LLDPOrganizationalTLV.OUI_LENGTH + ", but it is "
+ oui.length);
}
this.oui = Arrays.copyOf(oui, oui.length);
return this;
}
/**
* Returns the value of the OUI.
*
* @return The value of the OUI .
*/
public byte[] getOUI() {
return Arrays.copyOf(this.oui, this.oui.length);
}
/**
* Set the value of sub type.
*
* @param subType
* The value of sub type to be set.
* @return This LLDP Organizationally Specific TLV.
*/
public LLDPOrganizationalTLV setSubType(final byte subType) {
this.subType = subType;
return this;
}
/**
* Returns the value of the sub type.
*
* @return The value of the sub type.
*/
public byte getSubType() {
return this.subType;
}
/**
* Set the value of information string.
*
* @param infoString
* the byte array of the value of information string.
* @return This LLDP Organizationally Specific TLV.
*/
public LLDPOrganizationalTLV setInfoString(final byte[] infoString) {
if (infoString.length > LLDPOrganizationalTLV.MAX_INFOSTRING_LENGTH) {
throw new IllegalArgumentException(
"The length of infoString cannot exceed "
+ LLDPOrganizationalTLV.MAX_INFOSTRING_LENGTH);
}
this.infoString = Arrays.copyOf(infoString, infoString.length);
return this;
}
/**
* Set the value of information string. The String value is automatically
* converted into byte array with UTF-8 encoding.
*
* @param infoString
* the String value of information string.
* @return This LLDP Organizationally Specific TLV.
*/
public LLDPOrganizationalTLV setInfoString(final String infoString) {
final byte[] infoStringBytes = infoString.getBytes(Charset
.forName("UTF-8"));
return this.setInfoString(infoStringBytes);
}
/**
* Returns the value of information string.
*
* @return the value of information string.
*/
public byte[] getInfoString() {
return Arrays.copyOf(this.infoString, this.infoString.length);
}
@Override
public byte[] serialize() {
final int valueLength = LLDPOrganizationalTLV.OUI_LENGTH
+ LLDPOrganizationalTLV.SUBTYPE_LENGTH + this.infoString.length;
this.value = new byte[valueLength];
final ByteBuffer bb = ByteBuffer.wrap(this.value);
bb.put(this.oui);
bb.put(this.subType);
bb.put(this.infoString);
return super.serialize();
}
@Override
public LLDPTLV deserialize(final ByteBuffer bb) {
super.deserialize(bb);
final ByteBuffer optionalField = ByteBuffer.wrap(this.value);
final byte[] oui = new byte[LLDPOrganizationalTLV.OUI_LENGTH];
optionalField.get(oui);
this.setOUI(oui);
this.setSubType(optionalField.get());
final byte[] infoString = new byte[this.getLength()
- LLDPOrganizationalTLV.OUI_LENGTH
- LLDPOrganizationalTLV.SUBTYPE_LENGTH];
optionalField.get(infoString);
this.setInfoString(infoString);
return this;
}
@Override
public int hashCode() {
final int prime = 1423;
int result = 1;
result = prime * result + this.type;
result = prime * result + this.length;
result = prime * result + Arrays.hashCode(this.oui);
result = prime * result + this.subType;
result = prime * result + Arrays.hashCode(this.infoString);
return result;
}
@Override
public boolean equals(final Object o) {
if (o == this) {
return true;
}
if (!(o instanceof LLDPOrganizationalTLV)) {
return false;
}
final LLDPOrganizationalTLV other = (LLDPOrganizationalTLV) o;
if (this.type != other.type) {
return false;
}
if (this.length != other.length) {
return false;
}
if (!Arrays.equals(this.oui, other.oui)) {
return false;
}
if (this.subType != other.subType) {
return false;
}
if (!Arrays.equals(this.infoString, other.infoString)) {
return false;
}
return true;
}
}
/*******************************************************************************
* Copyright 2014 Open Networking Laboratory
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
******************************************************************************/
/**
* 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 org.onlab.packet;
import java.nio.ByteBuffer;
import java.util.Arrays;
/**
*
*
* @author David Erickson (daviderickson@cs.stanford.edu)
*/
public class LLDPTLV {
protected byte type;
protected short length;
protected byte[] value;
/**
* @return the type
*/
public byte getType() {
return this.type;
}
/**
* @param type
* the type to set
*/
public LLDPTLV setType(final byte type) {
this.type = type;
return this;
}
/**
* @return the length
*/
public short getLength() {
return this.length;
}
/**
* @param length
* the length to set
*/
public LLDPTLV setLength(final short length) {
this.length = length;
return this;
}
/**
* @return the value
*/
public byte[] getValue() {
return this.value;
}
/**
* @param value
* the value to set
*/
public LLDPTLV setValue(final byte[] value) {
this.value = value;
return this;
}
public byte[] serialize() {
// type = 7 bits
// info string length 9 bits, each value == byte
// info string
final short scratch = (short) ((0x7f & this.type) << 9 | 0x1ff & this.length);
final byte[] data = new byte[2 + this.length];
final ByteBuffer bb = ByteBuffer.wrap(data);
bb.putShort(scratch);
if (this.value != null) {
bb.put(this.value);
}
return data;
}
public LLDPTLV deserialize(final ByteBuffer bb) {
short sscratch;
sscratch = bb.getShort();
this.type = (byte) (sscratch >> 9 & 0x7f);
this.length = (short) (sscratch & 0x1ff);
if (this.length > 0) {
this.value = new byte[this.length];
// if there is an underrun just toss the TLV
if (bb.remaining() < this.length) {
return null;
}
bb.get(this.value);
}
return this;
}
/*
* (non-Javadoc)
*
* @see java.lang.Object#hashCode()
*/
@Override
public int hashCode() {
final int prime = 1423;
int result = 1;
result = prime * result + this.length;
result = prime * result + this.type;
result = prime * result + Arrays.hashCode(this.value);
return result;
}
/*
* (non-Javadoc)
*
* @see java.lang.Object#equals(java.lang.Object)
*/
@Override
public boolean equals(final Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (!(obj instanceof LLDPTLV)) {
return false;
}
final LLDPTLV other = (LLDPTLV) obj;
if (this.length != other.length) {
return false;
}
if (this.type != other.type) {
return false;
}
if (!Arrays.equals(this.value, other.value)) {
return false;
}
return true;
}
}
/*******************************************************************************
* Copyright 2014 Open Networking Laboratory
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
******************************************************************************/
package org.onlab.packet;
import java.util.Arrays;
/**
* The class representing MAC address.
*
* @author Sho Shimizu (sho.shimizu@gmail.com)
*/
public class MACAddress {
public static final int MAC_ADDRESS_LENGTH = 6;
private byte[] address = new byte[MACAddress.MAC_ADDRESS_LENGTH];
public MACAddress(final byte[] address) {
this.address = Arrays.copyOf(address, MACAddress.MAC_ADDRESS_LENGTH);
}
/**
* Returns a MAC address instance representing the value of the specified
* {@code String}.
*
* @param address
* the String representation of the MAC Address to be parsed.
* @return a MAC Address instance representing the value of the specified
* {@code String}.
* @throws IllegalArgumentException
* if the string cannot be parsed as a MAC address.
*/
public static MACAddress valueOf(final String address) {
final String[] elements = address.split(":");
if (elements.length != MACAddress.MAC_ADDRESS_LENGTH) {
throw new IllegalArgumentException(
"Specified MAC Address must contain 12 hex digits"
+ " separated pairwise by :'s.");
}
final byte[] addressInBytes = new byte[MACAddress.MAC_ADDRESS_LENGTH];
for (int i = 0; i < MACAddress.MAC_ADDRESS_LENGTH; i++) {
final String element = elements[i];
addressInBytes[i] = (byte) Integer.parseInt(element, 16);
}
return new MACAddress(addressInBytes);
}
/**
* Returns a MAC address instance representing the specified {@code byte}
* array.
*
* @param address
* the byte array to be parsed.
* @return a MAC address instance representing the specified {@code byte}
* array.
* @throws IllegalArgumentException
* if the byte array cannot be parsed as a MAC address.
*/
public static MACAddress valueOf(final byte[] address) {
if (address.length != MACAddress.MAC_ADDRESS_LENGTH) {
throw new IllegalArgumentException("the length is not "
+ MACAddress.MAC_ADDRESS_LENGTH);
}
return new MACAddress(address);
}
/**
* Returns a MAC address instance representing the specified {@code long}
* value. The lower 48 bits of the long value are used to parse as a MAC
* address.
*
* @param address
* the long value to be parsed. The lower 48 bits are used for a
* MAC address.
* @return a MAC address instance representing the specified {@code long}
* value.
* @throws IllegalArgumentException
* if the long value cannot be parsed as a MAC address.
*/
public static MACAddress valueOf(final long address) {
final byte[] addressInBytes = new byte[] {
(byte) (address >> 40 & 0xff), (byte) (address >> 32 & 0xff),
(byte) (address >> 24 & 0xff), (byte) (address >> 16 & 0xff),
(byte) (address >> 8 & 0xff), (byte) (address >> 0 & 0xff) };
return new MACAddress(addressInBytes);
}
/**
* Returns the length of the {@code MACAddress}.
*
* @return the length of the {@code MACAddress}.
*/
public int length() {
return this.address.length;
}
/**
* Returns the value of the {@code MACAddress} as a {@code byte} array.
*
* @return the numeric value represented by this object after conversion to
* type {@code byte} array.
*/
public byte[] toBytes() {
return Arrays.copyOf(this.address, this.address.length);
}
/**
* Returns the value of the {@code MACAddress} as a {@code long}.
*
* @return the numeric value represented by this object after conversion to
* type {@code long}.
*/
public long toLong() {
long mac = 0;
for (int i = 0; i < 6; i++) {
final long t = (this.address[i] & 0xffL) << (5 - i) * 8;
mac |= t;
}
return mac;
}
/**
* 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() {
for (final byte b : this.address) {
if (b != -1) {
return false;
}
}
return true;
}
/**
* Returns {@code true} if the MAC address is the multicast address.
*
* @return {@code true} if the MAC address is the multicast address.
*/
public boolean isMulticast() {
if (this.isBroadcast()) {
return false;
}
return (this.address[0] & 0x01) != 0;
}
@Override
public boolean equals(final Object o) {
if (o == this) {
return true;
}
if (!(o instanceof MACAddress)) {
return false;
}
final MACAddress other = (MACAddress) o;
return Arrays.equals(this.address, other.address);
}
@Override
public int hashCode() {
return Arrays.hashCode(this.address);
}
@Override
public String toString() {
final StringBuilder builder = new StringBuilder();
for (final byte b : this.address) {
if (builder.length() > 0) {
builder.append(":");
}
builder.append(String.format("%02X", b & 0xFF));
}
return builder.toString();
}
/**
* @return MAC address in string representation without colons (useful for
* radix tree storage)
*/
public String toStringNoColon() {
final StringBuilder builder = new StringBuilder();
for (final byte b : this.address) {
builder.append(String.format("%02X", b & 0xFF));
}
return builder.toString();
}
public byte[] getAddress() {
return this.address;
}
}
/*******************************************************************************
* Copyright 2014 Open Networking Laboratory
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
******************************************************************************/
package org.onlab.packet;
import java.nio.ByteBuffer;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;
import org.apache.commons.lang.ArrayUtils;
/**
* LLDP packets OpenVirteX uses for discovery of physical network topology.
* Refer to IEEE Std 802.1ABTM-2009 for more information.
*
*/
@SuppressWarnings("rawtypes")
public class OVXLLDP extends LLDP {
// ON.Lab OUI and OVX name for organizationally specific TLVs
public static final byte[] ONLAB_OUI = {(byte) 0xa4, 0x23, 0x05};
public static final String OVX_NAME = "OpenVirteX";
public static final byte[] LLDP_NICIRA = {0x01, 0x23, 0x20, 0x00, 0x00,
0x01};
public static final byte[] LLDP_MULTICAST = {0x01, (byte) 0x80,
(byte) 0xc2, 0x00, 0x00, 0x0e};
public static final byte[] BDDP_MULTICAST = {(byte) 0xff, (byte) 0xff,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff};
public static final short ETHERTYPE_VLAN = (short) 0x8100;
// TLV constants: type, size and subtype
// Organizationally specific TLV also have packet offset and contents of TLV
// header
private static final byte CHASSIS_TLV_TYPE = 1;
private static final byte CHASSIS_TLV_SIZE = 7;
private static final byte CHASSIS_TLV_SUBTYPE = 4;
private static final byte PORT_TLV_TYPE = 2;
private static final byte PORT_TLV_SIZE = 7;
private static final byte PORT_TLV_SUBTYPE = 2;
private static final byte TTL_TLV_TYPE = 3;
private static final byte TTL_TLV_SIZE = 2;
private static final byte NAME_TLV_TYPE = 127;
// 4 = OUI (3) + subtype (1)
private static final byte NAME_TLV_SIZE = (byte) (4 + OVXLLDP.OVX_NAME.length());
private static final byte NAME_TLV_SUBTYPE = 1;
private static final short NAME_TLV_OFFSET = 32;
private static final short NAME_TLV_HEADER = (short) ((NAME_TLV_TYPE << 9) | NAME_TLV_SIZE);
// Contents of full name TLV
private static final byte[] NAME_TLV = ByteBuffer.allocate(NAME_TLV_SIZE + 2)
.putShort(NAME_TLV_HEADER).put(ONLAB_OUI).put(NAME_TLV_SUBTYPE)
.put(OVX_NAME.getBytes()).array();
private static final byte DPID_TLV_TYPE = 127;
private static final byte DPID_TLV_SIZE = (byte) (12); // 12 = OUI (3) + subtype
// (1) + dpid (8)
private static final byte DPID_TLV_SUBTYPE = 2;
private static final short DPID_TLV_HEADER = (short) ((DPID_TLV_TYPE << 9) | DPID_TLV_SIZE);
// Contents of dpid TLV
// Note that this does *not* contain the actual dpid since we cannot match
// on it
private static final byte[] DPID_TLV = ByteBuffer.allocate(DPID_TLV_SIZE + 2 - 8)
.putShort(DPID_TLV_HEADER).put(ONLAB_OUI).put(DPID_TLV_SUBTYPE)
.array();
// Pre-built contents of both organizationally specific TLVs
private static final byte[] OUI_TLV = ArrayUtils.addAll(NAME_TLV, DPID_TLV);
// Default switch, port number and TTL
private static final byte[] DEFAULT_DPID = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00 };
private static final short DEFAULT_PORT = 0;
private static final short DEFAULT_TTL = 120; // in seconds
// Minimum and OVX-generated LLDP packet sizes
private static final short MINIMUM_LLDP_SIZE = 61;
// Add 12 for 2-byte header of each TLV and a single EndOfLLDPTLV
private static final short OVX_LLDP_SIZE = (short) (CHASSIS_TLV_SIZE
+ PORT_TLV_SIZE + TTL_TLV_SIZE + NAME_TLV_SIZE + DPID_TLV_SIZE + 12);
// Field offsets in OVX-generated LLDP
private static final short ETHERTYPE_OFFSET = 12;
private static final short PORT_OFFSET = 26;
private static final short DPID_OFFSET = 54;
// Private member fields
// Byte arrays for TLV information string
private ByteBuffer bb;
private final byte[] chassisId = new byte[CHASSIS_TLV_SIZE];
private final byte[] portId = new byte[PORT_TLV_SIZE];
private final byte[] ttl = new byte[TTL_TLV_SIZE];
private final byte[] ouiName = new byte[NAME_TLV_SIZE];
private final byte[] ouiDpid = new byte[DPID_TLV_SIZE];
// TLVs
private final LLDPTLV chassisTLV;
private final LLDPTLV portTLV;
private final LLDPTLV ttlTLV;
private final LLDPTLV ouiNameTLV;
private final LLDPTLV ouiDpidTLV;
private final List<LLDPTLV> optionalTLVList;
/**
* Instantiates a new OVX LDDP message.
*/
public OVXLLDP() {
// Create TLVs
this.chassisTLV = new LLDPTLV();
this.portTLV = new LLDPTLV();
this.ttlTLV = new LLDPTLV();
this.ouiNameTLV = new LLDPTLV();
this.ouiDpidTLV = new LLDPTLV();
this.optionalTLVList = new LinkedList<LLDPTLV>();
this.optionalTLVList.add(this.ouiNameTLV);
this.optionalTLVList.add(this.ouiDpidTLV);
// Add TLVs to LLDP packet
this.setChassisId(this.chassisTLV);
this.setPortId(this.portTLV);
this.setTtl(this.ttlTLV);
this.setOptionalTLVList(this.optionalTLVList);
// Set TLVs to default values
this.setChassisTLV(DEFAULT_DPID);
this.setPortTLV(DEFAULT_PORT);
this.setTTLTLV(DEFAULT_TTL);
this.setOUIName(OVXLLDP.OVX_NAME);
this.setOUIDpid(DEFAULT_DPID);
}
/**
* Sets chassis TLV. Note that we can only put 6 bytes in the chassis ID, so
* we use another organizationally specific TLV to put the full dpid (see
* setOUIDpid()).
*
* @param dpid the switch DPID
*/
private void setChassisTLV(final byte[] dpid) {
this.bb = ByteBuffer.wrap(this.chassisId);
this.bb.put(CHASSIS_TLV_SUBTYPE);
for (int i = 2; i < 8; i++) {
bb.put(dpid[i]);
}
this.chassisTLV.setLength(CHASSIS_TLV_SIZE);
this.chassisTLV.setType(CHASSIS_TLV_TYPE);
this.chassisTLV.setValue(this.chassisId);
}
/**
* Sets port TLV.
*
* @param portNumber the port number
*/
private void setPortTLV(final long portNumber) {
this.bb = ByteBuffer.wrap(this.portId);
this.bb.put(PORT_TLV_SUBTYPE);
this.bb.putLong(portNumber);
this.portTLV.setLength(PORT_TLV_SIZE);
this.portTLV.setType(PORT_TLV_TYPE);
this.portTLV.setValue(this.portId);
}
/**
* Sets Time To Live TLV.
*
* @param time the time to live
*/
private void setTTLTLV(final short time) {
this.bb = ByteBuffer.wrap(this.ttl);
this.bb.putShort(time);
this.ttlTLV.setLength(TTL_TLV_SIZE);
this.ttlTLV.setType(TTL_TLV_TYPE);
this.ttlTLV.setValue(this.ttl);
}
/**
* Set. organizationally specific TLV for OVX name (subtype 1).
*
* @param name the name
*/
private void setOUIName(final String name) {
this.bb = ByteBuffer.wrap(ouiName);
this.bb.put(OVXLLDP.ONLAB_OUI);
this.bb.put(NAME_TLV_SUBTYPE);
this.bb.put(name.getBytes());
this.ouiNameTLV.setLength(NAME_TLV_SIZE);
this.ouiNameTLV.setType(NAME_TLV_TYPE);
this.ouiNameTLV.setValue(ouiName);
}
/**
* Sets organizationally specific TLV for OVX full dpid (subtype 2).
*
* @param dpid the switch DPID
*/
private void setOUIDpid(final byte[] dpid) {
this.bb = ByteBuffer.wrap(ouiDpid);
this.bb.put(OVXLLDP.ONLAB_OUI);
this.bb.put(DPID_TLV_SUBTYPE);
this.bb.put(dpid);
this.ouiDpidTLV.setLength(DPID_TLV_SIZE);
this.ouiDpidTLV.setType(DPID_TLV_TYPE);
this.ouiDpidTLV.setValue(ouiDpid);
}
/**
* Sets switch DPID in LLDP packet.
*
* @param sw the switch instance
*/
public void setSwitch(long dp) {
final byte[] dpid = ByteBuffer.allocate(8).putLong(dp)
.array();
this.setChassisTLV(dpid);
this.setOUIDpid(dpid);
}
/**
* Sets port in LLDP packet.
*
* @param port the port instance
*/
public void setPort(long port) {
long portNumber = port;
this.setPortTLV(portNumber);
}
/**
* Serializes full LLDP packet to byte array. Need to set both switch and
* port before you can serialize.
*/
@Override
public byte[] serialize() {
return super.serialize();
}
/**
* Checks if LLDP packet has correct size, LLDP multicast address, and
* ethertype. Packet assumed to have Ethernet header.
*
* @param packet
* @return true if packet is LLDP, false otherwise
*/
public static boolean isLLDP(final byte[] packet) {
// Does packet exist and does it have the mininum size?
if (packet == null || packet.length < MINIMUM_LLDP_SIZE) {
return false;
}
// Packet has LLDP multicast destination address?
final ByteBuffer bb = ByteBuffer.wrap(packet);
final byte[] dst = new byte[6];
bb.get(dst);
if (!(Arrays.equals(dst, OVXLLDP.LLDP_NICIRA)
|| Arrays.equals(dst, OVXLLDP.LLDP_MULTICAST) || Arrays.equals(
dst, OVXLLDP.BDDP_MULTICAST))) {
return false;
}
// Fetch ethertype, skip VLAN tag if it's there
short etherType = bb.getShort(ETHERTYPE_OFFSET);
if (etherType == ETHERTYPE_VLAN) {
etherType = bb.getShort(ETHERTYPE_OFFSET + 4);
}
// Check ethertype
if (etherType == Ethernet.TYPE_LLDP) {
return true;
}
if (etherType == Ethernet.TYPE_BSN) {
return true;
}
return false;
}
/**
* Checks if packet has size of OVX-generated LLDP, and correctness of two
* organizationally specific TLVs that use ON.Lab's OUI. Assumes packet is
* valid LLDP packet
*
* @param packet
* @return
*/
public static boolean isOVXLLDP(byte[] packet) {
if (packet.length < OVX_LLDP_SIZE) {
return false;
}
// Extra offset due to VLAN tag
final ByteBuffer bb = ByteBuffer.wrap(packet);
int offset = 0;
if (bb.getShort(ETHERTYPE_OFFSET) != Ethernet.TYPE_LLDP
&& bb.getShort(ETHERTYPE_OFFSET) != Ethernet.TYPE_BSN) {
offset = 4;
}
// Compare packet's organizationally specific TLVs to the expected
// values
for (int i = 0; i < OUI_TLV.length; i++) {
if (packet[NAME_TLV_OFFSET + offset + i] != OUI_TLV[i]) {
return false;
}
}
return true;
}
/**
* Extracts dpid and port from OVX-generated LLDP packet.
*
* @param packet
* @return Dpid and port
*/
/* public static long parseLLDP(final byte[] packet) {
final ByteBuffer bb = ByteBuffer.wrap(packet);
// Extra offset due to VLAN tag
int offset = 0;
if (bb.getShort(ETHERTYPE_OFFSET) != Ethernet.TYPE_LLDP
&& bb.getShort(ETHERTYPE_OFFSET) != Ethernet.TYPE_BSN) {
offset = 4;
}
final short port = bb.getLong(PORT_OFFSET + offset);
final long dpid = bb.getLong(DPID_OFFSET + offset);
return dpid
}
*/
}
/*******************************************************************************
* Copyright 2014 Open Networking Laboratory
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
******************************************************************************/
/**
* 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 org.onlab.packet;
import java.nio.ByteBuffer;
/**
*
* @author shudong.zhou@bigswitch.com
*/
public class TCP extends BasePacket {
protected short sourcePort;
protected short destinationPort;
protected int sequence;
protected int acknowledge;
protected byte dataOffset;
protected short flags;
protected short windowSize;
protected short checksum;
protected short urgentPointer;
protected byte[] options;
/**
* @return the sourcePort
*/
public short getSourcePort() {
return this.sourcePort;
}
/**
* @param sourcePort
* the sourcePort to set
*/
public TCP setSourcePort(final short sourcePort) {
this.sourcePort = sourcePort;
return this;
}
/**
* @return the destinationPort
*/
public short getDestinationPort() {
return this.destinationPort;
}
/**
* @param destinationPort
* the destinationPort to set
*/
public TCP setDestinationPort(final short destinationPort) {
this.destinationPort = destinationPort;
return this;
}
/**
* @return the checksum
*/
public short getChecksum() {
return this.checksum;
}
public int getSequence() {
return this.sequence;
}
public TCP setSequence(final int seq) {
this.sequence = seq;
return this;
}
public int getAcknowledge() {
return this.acknowledge;
}
public TCP setAcknowledge(final int ack) {
this.acknowledge = ack;
return this;
}
public byte getDataOffset() {
return this.dataOffset;
}
public TCP setDataOffset(final byte offset) {
this.dataOffset = offset;
return this;
}
public short getFlags() {
return this.flags;
}
public TCP setFlags(final short flags) {
this.flags = flags;
return this;
}
public short getWindowSize() {
return this.windowSize;
}
public TCP setWindowSize(final short windowSize) {
this.windowSize = windowSize;
return this;
}
public short getTcpChecksum() {
return this.checksum;
}
public TCP setTcpChecksum(final short checksum) {
this.checksum = checksum;
return this;
}
@Override
public void resetChecksum() {
this.checksum = 0;
super.resetChecksum();
}
public short getUrgentPointer(final short urgentPointer) {
return this.urgentPointer;
}
public TCP setUrgentPointer(final short urgentPointer) {
this.urgentPointer = urgentPointer;
return this;
}
public byte[] getOptions() {
return this.options;
}
public TCP setOptions(final byte[] options) {
this.options = options;
this.dataOffset = (byte) (20 + options.length + 3 >> 2);
return this;
}
/**
* @param checksum
* the checksum to set
*/
public TCP setChecksum(final short checksum) {
this.checksum = checksum;
return this;
}
/**
* Serializes the packet. Will compute and set the following fields if they
* are set to specific values at the time serialize is called: -checksum : 0
* -length : 0
*/
@Override
public byte[] serialize() {
int length;
if (this.dataOffset == 0) {
this.dataOffset = 5; // default header length
}
length = this.dataOffset << 2;
byte[] payloadData = null;
if (this.payload != null) {
this.payload.setParent(this);
payloadData = this.payload.serialize();
length += payloadData.length;
}
final byte[] data = new byte[length];
final ByteBuffer bb = ByteBuffer.wrap(data);
bb.putShort(this.sourcePort);
bb.putShort(this.destinationPort);
bb.putInt(this.sequence);
bb.putInt(this.acknowledge);
bb.putShort((short) (this.flags | this.dataOffset << 12));
bb.putShort(this.windowSize);
bb.putShort(this.checksum);
bb.putShort(this.urgentPointer);
if (this.dataOffset > 5) {
int padding;
bb.put(this.options);
padding = (this.dataOffset << 2) - 20 - this.options.length;
for (int i = 0; i < padding; i++) {
bb.put((byte) 0);
}
}
if (payloadData != null) {
bb.put(payloadData);
}
if (this.parent != null && this.parent instanceof IPv4) {
((IPv4) this.parent).setProtocol(IPv4.PROTOCOL_TCP);
}
// compute checksum if needed
if (this.checksum == 0) {
bb.rewind();
int accumulation = 0;
// compute pseudo header mac
if (this.parent != null && this.parent instanceof IPv4) {
final IPv4 ipv4 = (IPv4) this.parent;
accumulation += (ipv4.getSourceAddress() >> 16 & 0xffff)
+ (ipv4.getSourceAddress() & 0xffff);
accumulation += (ipv4.getDestinationAddress() >> 16 & 0xffff)
+ (ipv4.getDestinationAddress() & 0xffff);
accumulation += ipv4.getProtocol() & 0xff;
accumulation += length & 0xffff;
}
for (int i = 0; i < length / 2; ++i) {
accumulation += 0xffff & bb.getShort();
}
// pad to an even number of shorts
if (length % 2 > 0) {
accumulation += (bb.get() & 0xff) << 8;
}
accumulation = (accumulation >> 16 & 0xffff)
+ (accumulation & 0xffff);
this.checksum = (short) (~accumulation & 0xffff);
bb.putShort(16, this.checksum);
}
return data;
}
/*
* (non-Javadoc)
*
* @see java.lang.Object#hashCode()
*/
@Override
public int hashCode() {
final int prime = 5807;
int result = super.hashCode();
result = prime * result + this.checksum;
result = prime * result + this.destinationPort;
result = prime * result + this.sourcePort;
return result;
}
/*
* (non-Javadoc)
*
* @see java.lang.Object#equals(java.lang.Object)
*/
@Override
public boolean equals(final Object obj) {
if (this == obj) {
return true;
}
if (!super.equals(obj)) {
return false;
}
if (!(obj instanceof TCP)) {
return false;
}
final TCP other = (TCP) obj;
// May want to compare fields based on the flags set
return this.checksum == other.checksum
&& this.destinationPort == other.destinationPort
&& this.sourcePort == other.sourcePort
&& this.sequence == other.sequence
&& this.acknowledge == other.acknowledge
&& this.dataOffset == other.dataOffset
&& this.flags == other.flags
&& this.windowSize == other.windowSize
&& this.urgentPointer == other.urgentPointer
&& (this.dataOffset == 5 || this.options.equals(other.options));
}
@Override
public IPacket deserialize(final byte[] data, final int offset,
final int length) {
final ByteBuffer bb = ByteBuffer.wrap(data, offset, length);
this.sourcePort = bb.getShort();
this.destinationPort = bb.getShort();
this.sequence = bb.getInt();
this.acknowledge = bb.getInt();
this.flags = bb.getShort();
this.dataOffset = (byte) (this.flags >> 12 & 0xf);
this.flags = (short) (this.flags & 0x1ff);
this.windowSize = bb.getShort();
this.checksum = bb.getShort();
this.urgentPointer = bb.getShort();
if (this.dataOffset > 5) {
int optLength = (this.dataOffset << 2) - 20;
if (bb.limit() < bb.position() + optLength) {
optLength = bb.limit() - bb.position();
}
try {
this.options = new byte[optLength];
bb.get(this.options, 0, optLength);
} catch (final IndexOutOfBoundsException e) {
this.options = null;
}
}
this.payload = new Data();
this.payload = this.payload.deserialize(data, bb.position(), bb.limit()
- bb.position());
this.payload.setParent(this);
return this;
}
}
/*******************************************************************************
* Copyright 2014 Open Networking Laboratory
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
******************************************************************************/
/**
* 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 org.onlab.packet;
import java.nio.ByteBuffer;
import java.util.HashMap;
import java.util.Map;
/**
*
* @author David Erickson (daviderickson@cs.stanford.edu)
*/
public class UDP extends BasePacket {
public static Map<Short, Class<? extends IPacket>> decodeMap;
public static final short DHCP_SERVER_PORT = (short) 67;
public static final short DHCP_CLIENT_PORT = (short) 68;
static {
UDP.decodeMap = new HashMap<Short, Class<? extends IPacket>>();
/*
* Disable DHCP until the deserialize code is hardened to deal with
* garbage input
*/
UDP.decodeMap.put(UDP.DHCP_SERVER_PORT, DHCP.class);
UDP.decodeMap.put(UDP.DHCP_CLIENT_PORT, DHCP.class);
}
protected short sourcePort;
protected short destinationPort;
protected short length;
protected short checksum;
/**
* @return the sourcePort
*/
public short getSourcePort() {
return this.sourcePort;
}
/**
* @param sourcePort
* the sourcePort to set
*/
public UDP setSourcePort(final short sourcePort) {
this.sourcePort = sourcePort;
return this;
}
/**
* @return the destinationPort
*/
public short getDestinationPort() {
return this.destinationPort;
}
/**
* @param destinationPort
* the destinationPort to set
*/
public UDP setDestinationPort(final short destinationPort) {
this.destinationPort = destinationPort;
return this;
}
/**
* @return the length
*/
public short getLength() {
return this.length;
}
/**
* @return the checksum
*/
public short getChecksum() {
return this.checksum;
}
/**
* @param checksum
* the checksum to set
*/
public UDP setChecksum(final short checksum) {
this.checksum = checksum;
return this;
}
@Override
public void resetChecksum() {
this.checksum = 0;
super.resetChecksum();
}
/**
* Serializes the packet. Will compute and set the following fields if they
* are set to specific values at the time serialize is called: -checksum : 0
* -length : 0
*/
@Override
public byte[] serialize() {
byte[] payloadData = null;
if (this.payload != null) {
this.payload.setParent(this);
payloadData = this.payload.serialize();
}
this.length = (short) (8 + (payloadData == null ? 0
: payloadData.length));
final byte[] data = new byte[this.length];
final ByteBuffer bb = ByteBuffer.wrap(data);
bb.putShort(this.sourcePort);
bb.putShort(this.destinationPort);
bb.putShort(this.length);
bb.putShort(this.checksum);
if (payloadData != null) {
bb.put(payloadData);
}
if (this.parent != null && this.parent instanceof IPv4) {
((IPv4) this.parent).setProtocol(IPv4.PROTOCOL_UDP);
}
// compute checksum if needed
if (this.checksum == 0) {
bb.rewind();
int accumulation = 0;
// compute pseudo header mac
if (this.parent != null && this.parent instanceof IPv4) {
final IPv4 ipv4 = (IPv4) this.parent;
accumulation += (ipv4.getSourceAddress() >> 16 & 0xffff)
+ (ipv4.getSourceAddress() & 0xffff);
accumulation += (ipv4.getDestinationAddress() >> 16 & 0xffff)
+ (ipv4.getDestinationAddress() & 0xffff);
accumulation += ipv4.getProtocol() & 0xff;
accumulation += this.length & 0xffff;
}
for (int i = 0; i < this.length / 2; ++i) {
accumulation += 0xffff & bb.getShort();
}
// pad to an even number of shorts
if (this.length % 2 > 0) {
accumulation += (bb.get() & 0xff) << 8;
}
accumulation = (accumulation >> 16 & 0xffff)
+ (accumulation & 0xffff);
this.checksum = (short) (~accumulation & 0xffff);
bb.putShort(6, this.checksum);
}
return data;
}
/*
* (non-Javadoc)
*
* @see java.lang.Object#hashCode()
*/
@Override
public int hashCode() {
final int prime = 5807;
int result = super.hashCode();
result = prime * result + this.checksum;
result = prime * result + this.destinationPort;
result = prime * result + this.length;
result = prime * result + this.sourcePort;
return result;
}
/*
* (non-Javadoc)
*
* @see java.lang.Object#equals(java.lang.Object)
*/
@Override
public boolean equals(final Object obj) {
if (this == obj) {
return true;
}
if (!super.equals(obj)) {
return false;
}
if (!(obj instanceof UDP)) {
return false;
}
final UDP other = (UDP) obj;
if (this.checksum != other.checksum) {
return false;
}
if (this.destinationPort != other.destinationPort) {
return false;
}
if (this.length != other.length) {
return false;
}
if (this.sourcePort != other.sourcePort) {
return false;
}
return true;
}
@Override
public IPacket deserialize(final byte[] data, final int offset,
final int length) {
final ByteBuffer bb = ByteBuffer.wrap(data, offset, length);
this.sourcePort = bb.getShort();
this.destinationPort = bb.getShort();
this.length = bb.getShort();
this.checksum = bb.getShort();
if (UDP.decodeMap.containsKey(this.destinationPort)) {
try {
this.payload = UDP.decodeMap.get(this.destinationPort)
.getConstructor().newInstance();
} catch (final Exception e) {
throw new RuntimeException("Failure instantiating class", e);
}
} else if (UDP.decodeMap.containsKey(this.sourcePort)) {
try {
this.payload = UDP.decodeMap.get(this.sourcePort)
.getConstructor().newInstance();
} catch (final Exception e) {
throw new RuntimeException("Failure instantiating class", e);
}
} else {
this.payload = new Data();
}
this.payload = this.payload.deserialize(data, bb.position(), bb.limit()
- bb.position());
this.payload.setParent(this);
return this;
}
}
......@@ -27,6 +27,11 @@
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
</dependency>
<dependency>
<groupId>commons-lang</groupId>
<artifactId>commons-lang</artifactId>
<version>2.3</version>
</dependency>
</dependencies>
<build>
......