This element does not affect packets without IPv4 header.
- *
- * This element is not yet supported.
- *
*
*
*
inet4dst
@@ -249,9 +246,6 @@ public final class FlowFilter implements Serializable {
* The type of this element must be {@link SetInet4DstAction}.
*
*
This element does not affect packets without IPv4 header.
- *
- * This element is not yet supported.
- *
*
*
*
dscp
@@ -276,9 +270,6 @@ public final class FlowFilter implements Serializable {
*
* This element does not affect packets without TCP or UDP header.
*
- *
- * This element is not yet supported.
- *
*
*
*
tpdst
@@ -292,9 +283,6 @@ public final class FlowFilter implements Serializable {
*
* This element does not affect packets without TCP or UDP header.
*
- *
- * This element is not yet supported.
- *
*
*
*
icmptype
diff --git a/manager/api/src/test/java/org/opendaylight/vtn/manager/flow/action/SetInet4DstActionTest.java b/manager/api/src/test/java/org/opendaylight/vtn/manager/flow/action/SetInet4DstActionTest.java
index ff7b697e..10cb951d 100644
--- a/manager/api/src/test/java/org/opendaylight/vtn/manager/flow/action/SetInet4DstActionTest.java
+++ b/manager/api/src/test/java/org/opendaylight/vtn/manager/flow/action/SetInet4DstActionTest.java
@@ -123,6 +123,8 @@ public class SetInet4DstActionTest extends TestBase {
// Specifying invalid address.
String[] invalid = {
// Invalid address
+ "",
+ " ",
"invalid_address",
"100.200.300.400",
diff --git a/manager/api/src/test/java/org/opendaylight/vtn/manager/flow/action/SetInet4SrcActionTest.java b/manager/api/src/test/java/org/opendaylight/vtn/manager/flow/action/SetInet4SrcActionTest.java
index cba92f91..5c037670 100644
--- a/manager/api/src/test/java/org/opendaylight/vtn/manager/flow/action/SetInet4SrcActionTest.java
+++ b/manager/api/src/test/java/org/opendaylight/vtn/manager/flow/action/SetInet4SrcActionTest.java
@@ -123,6 +123,8 @@ public class SetInet4SrcActionTest extends TestBase {
// Specifying invalid address.
String[] invalid = {
// Invalid address
+ "",
+ " ",
"invalid_address",
"100.200.300.400",
diff --git a/manager/api/src/test/java/org/opendaylight/vtn/manager/flow/action/SetTpDstActionTest.java b/manager/api/src/test/java/org/opendaylight/vtn/manager/flow/action/SetTpDstActionTest.java
index aaa9dd8c..4af270bf 100644
--- a/manager/api/src/test/java/org/opendaylight/vtn/manager/flow/action/SetTpDstActionTest.java
+++ b/manager/api/src/test/java/org/opendaylight/vtn/manager/flow/action/SetTpDstActionTest.java
@@ -32,7 +32,7 @@ public class SetTpDstActionTest extends TestBase {
assertEquals(port, act.getPort());
}
- int[] valid = {1, 2, 100, 999, 10000, 29999, 49999, 65534, 65535};
+ int[] valid = {0, 1, 2, 100, 999, 10000, 29999, 49999, 65534, 65535};
for (int port: valid) {
SetTpDst sact = new SetTpDst(port);
SetTpDstAction act = new SetTpDstAction(sact);
diff --git a/manager/api/src/test/java/org/opendaylight/vtn/manager/flow/action/SetTpSrcActionTest.java b/manager/api/src/test/java/org/opendaylight/vtn/manager/flow/action/SetTpSrcActionTest.java
index 83c2a93f..bc6cf41d 100644
--- a/manager/api/src/test/java/org/opendaylight/vtn/manager/flow/action/SetTpSrcActionTest.java
+++ b/manager/api/src/test/java/org/opendaylight/vtn/manager/flow/action/SetTpSrcActionTest.java
@@ -32,7 +32,7 @@ public class SetTpSrcActionTest extends TestBase {
assertEquals(port, act.getPort());
}
- int[] valid = {1, 2, 100, 1000, 9999, 20000, 30000, 65534, 65535};
+ int[] valid = {0, 1, 2, 100, 1000, 9999, 20000, 30000, 65534, 65535};
for (int port: valid) {
SetTpSrc sact = new SetTpSrc(port);
SetTpSrcAction act = new SetTpSrcAction(sact);
diff --git a/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/ActionList.java b/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/ActionList.java
index 8e38f2b5..23ac52f1 100644
--- a/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/ActionList.java
+++ b/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/ActionList.java
@@ -10,6 +10,7 @@
package org.opendaylight.vtn.manager.internal;
import java.util.ArrayList;
+import java.util.Collection;
import java.util.List;
import org.opendaylight.controller.sal.action.Action;
@@ -84,14 +85,15 @@ public class ActionList {
}
/**
- * Append all SAL actions in the given list to the tail of the action list.
+ * Append all SAL actions in the given collection to the tail of the
+ * action list.
*
- * @param list A SAL actions.
+ * @param c A collection of SAL actions.
* @return This object is always returned.
*/
- public ActionList addAll(List extends Action> list) {
- if (list != null) {
- actionList.addAll(list);
+ public ActionList addAll(Collection extends Action> c) {
+ if (c != null) {
+ actionList.addAll(c);
}
return this;
}
diff --git a/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/MiscUtils.java b/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/MiscUtils.java
index 910b5d6f..e93b9ffa 100644
--- a/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/MiscUtils.java
+++ b/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/MiscUtils.java
@@ -10,12 +10,14 @@
package org.opendaylight.vtn.manager.internal;
import java.net.InetAddress;
+import java.net.Inet4Address;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.opendaylight.vtn.manager.VTNException;
import org.opendaylight.vtn.manager.internal.cluster.MacVlan;
+import org.opendaylight.controller.sal.packet.Packet;
import org.opendaylight.controller.sal.utils.HexEncode;
import org.opendaylight.controller.sal.utils.NetUtils;
import org.opendaylight.controller.sal.utils.Status;
@@ -26,6 +28,16 @@ import org.opendaylight.controller.sal.utils.StatusCode;
* methods.
*/
public final class MiscUtils {
+ /**
+ * A mask value which represents all bits in a byte value.
+ */
+ public static final int MASK_BYTE = (1 << Byte.SIZE) - 1;
+
+ /**
+ * A mask value which represents all bits in a short value.
+ */
+ public static final int MASK_SHORT = (1 << Short.SIZE) - 1;
+
/**
* Maximum length of the resource name.
*/
@@ -59,6 +71,21 @@ public final class MiscUtils {
*/
private static final int MASK_TP_PORT = 0xffff;
+ /**
+ * The number of bits to be shifted to get the first octet in an integer.
+ */
+ private static final int INT_SHIFT_OCTET1 = 24;
+
+ /**
+ * The number of bits to be shifted to get the second octet in an integer.
+ */
+ private static final int INT_SHIFT_OCTET2 = 16;
+
+ /**
+ * The number of bits to be shifted to get the third octet in an integer.
+ */
+ private static final int INT_SHIFT_OCTET3 = 8;
+
/**
* Private constructor that protects this class from instantiating.
*/
@@ -206,4 +233,75 @@ public final class MiscUtils {
throw new IllegalStateException(builder.toString(), e);
}
}
+
+ /**
+ * Convert an IPv4 address into an integer.
+ *
+ * @param addr A {@link InetAddress} instance which represents an IPv4
+ * address.
+ * @return An integer value.
+ * @throws IllegalStateException
+ * An error occurred.
+ */
+ public static int toInteger(InetAddress addr) {
+ if (addr instanceof Inet4Address) {
+ byte[] bytes = addr.getAddress();
+ return NetUtils.byteArray4ToInt(bytes);
+ }
+
+ StringBuilder builder =
+ new StringBuilder("Unexpected InetAddress: addr=");
+ builder.append(addr);
+ throw new IllegalStateException(builder.toString());
+ }
+
+ /**
+ * Copy the contents of the given packet.
+ *
+ * @param src The source {@link Packet} instance.
+ * @param dst The destination {@link Packet} instance.
+ * @param Type of packet.
+ * @return {@code dst}.
+ * @throws VTNException
+ * Failed to copy the packet.
+ */
+ public static T copy(T src, T dst) throws VTNException {
+ try {
+ byte[] raw = src.serialize();
+ int nbits = raw.length * NetUtils.NumBitsInAByte;
+ dst.deserialize(raw, 0, nbits);
+ return dst;
+ } catch (Exception e) {
+ // This should never happen.
+ throw new VTNException("Failed to copy the packet.", e);
+ }
+ }
+
+ /**
+ * Set an integer value into the given byte array in network byte order.
+ *
+ * @param array A byte array.
+ * @param off Index of {@code array} to store value.
+ * @param value An integer value.
+ */
+ public static void setInt(byte[] array, int off, int value) {
+ int index = off;
+ array[index++] = (byte)(value >>> INT_SHIFT_OCTET1);
+ array[index++] = (byte)(value >>> INT_SHIFT_OCTET2);
+ array[index++] = (byte)(value >>> INT_SHIFT_OCTET3);
+ array[index] = (byte)value;
+ }
+
+ /**
+ * Set a short integer value into the given byte array in network byte
+ * order.
+ *
+ * @param array A byte array.
+ * @param off Index of {@code array} to store value.
+ * @param value A short integer value.
+ */
+ public static void setShort(byte[] array, int off, short value) {
+ array[off] = (byte)(value >>> Byte.SIZE);
+ array[off + 1] = (byte)value;
+ }
}
diff --git a/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/PacketContext.java b/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/PacketContext.java
index 2346f9b2..c678f3dc 100644
--- a/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/PacketContext.java
+++ b/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/PacketContext.java
@@ -11,9 +11,12 @@ package org.opendaylight.vtn.manager.internal;
import java.net.InetAddress;
import java.util.ArrayList;
+import java.util.Collection;
import java.util.EnumSet;
import java.util.HashSet;
+import java.util.LinkedHashMap;
import java.util.List;
+import java.util.Map;
import java.util.Set;
import org.slf4j.Logger;
@@ -32,10 +35,10 @@ import org.opendaylight.vtn.manager.internal.cluster.ObjectPair;
import org.opendaylight.vtn.manager.internal.cluster.PortVlan;
import org.opendaylight.vtn.manager.internal.cluster.RedirectFlowException;
import org.opendaylight.vtn.manager.internal.cluster.VTNFlow;
-import org.opendaylight.vtn.manager.internal.packet.CachedPacket;
import org.opendaylight.vtn.manager.internal.packet.EtherPacket;
import org.opendaylight.vtn.manager.internal.packet.IcmpPacket;
import org.opendaylight.vtn.manager.internal.packet.Inet4Packet;
+import org.opendaylight.vtn.manager.internal.packet.L4Packet;
import org.opendaylight.vtn.manager.internal.packet.TcpPacket;
import org.opendaylight.vtn.manager.internal.packet.UdpPacket;
@@ -139,10 +142,10 @@ public class PacketContext implements Cloneable {
private Inet4Packet inet4Packet;
/**
- * A {@link CachedPacket} instance which represents the layer 4 protocol
+ * A {@link L4Packet} instance which represents the layer 4 protocol
* data.
*/
- private CachedPacket l4Packet;
+ private L4Packet l4Packet;
/**
* Route resolver for this packet.
@@ -166,9 +169,9 @@ public class PacketContext implements Cloneable {
private MapReference mapReference;
/**
- * A list of SAL actions created by flow filters.
+ * A map that keeps SAL actions created by flow filters.
*/
- private List filterActions;
+ private Map, Action> filterActions;
/**
* The number of virtual node hops caused by REDIRECT flow filter.
@@ -192,6 +195,11 @@ public class PacketContext implements Cloneable {
*/
private boolean filterDisabled;
+ /**
+ * Set {@code true} at least one flow filter is evaluated.
+ */
+ private boolean filtered;
+
/**
* Determine whether the destination MAC address of this packet is equal to
* the controller's MAC address or not.
@@ -574,13 +582,13 @@ public class PacketContext implements Cloneable {
}
/**
- * Return a {@link CachedPacket} instance which represents layer 4
- * protocol data.
+ * Return a {@link L4Packet} instance which represents layer 4 protocol
+ * data.
*
- * @return A {@link CachedPacket} instance if found.
+ * @return A {@link L4Packet} instance if found.
* {@code null} if not found.
*/
- public CachedPacket getL4Packet() {
+ public L4Packet getL4Packet() {
if (l4Packet == null) {
Inet4Packet ipv4 = getInet4Packet();
if (ipv4 != null) {
@@ -677,6 +685,18 @@ public class PacketContext implements Cloneable {
}
}
+ /**
+ * Determine whether the given match field will be configured in a flow
+ * entry or not.
+ *
+ * @param type A match type to be tested.
+ * @return {@code true} only if the given match type will be configured
+ * in a flow entry.
+ */
+ public boolean hasMatchField(MatchType type) {
+ return matchFields.contains(type);
+ }
+
/**
* Add match fields to be configured into an unicast flow entry.
*/
@@ -705,7 +725,7 @@ public class PacketContext implements Cloneable {
Inet4Packet ipv4 = getInet4Packet();
if (ipv4 != null) {
ipv4.setMatch(match, matchFields);
- CachedPacket l4 = getL4Packet();
+ L4Packet l4 = getL4Packet();
if (l4 != null) {
l4.setMatch(match, matchFields);
}
@@ -917,21 +937,33 @@ public class PacketContext implements Cloneable {
public void addFilterAction(Action act) {
if (!flooding) {
if (filterActions == null) {
- filterActions = new ArrayList();
+ filterActions =
+ new LinkedHashMap, Action>();
}
- filterActions.add(act);
+ filterActions.put(act.getClass(), act);
+ }
+ }
+
+ /**
+ * Remove the specified flow action from the flow filter action list.
+ *
+ * @param actClass A class of SAL action to be removed.
+ */
+ public void removeFilterAction(Class extends Action> actClass) {
+ if (!flooding && filterActions != null) {
+ filterActions.remove(actClass);
}
}
/**
* Return a list of SAL actions created by flow filters.
*
- * @return A list of SAL actions.
+ * @return A collection of SAL actions.
* {@code null} is returned if no SAL action was created by
* flow filter.
*/
- public List getFilterActions() {
- return filterActions;
+ public Collection getFilterActions() {
+ return (filterActions == null) ? null : filterActions.values();
}
/**
@@ -941,11 +973,28 @@ public class PacketContext implements Cloneable {
* Failed to copy the packet.
*/
public void commit() throws VTNException {
+ // Commit modification to the Ethernet header.
etherFrame.commit(this);
- CachedPacket l4 = l4Packet;
+
+ // Commit modification to layer 4 protocol header.
+ L4Packet l4 = l4Packet;
Inet4Packet inet4 = inet4Packet;
- boolean l4Changed = (l4 != null) ? l4.commit(this) : false;
+ boolean l4Changed;
+ if (l4 == null) {
+ l4Changed = false;
+ } else {
+ l4Changed = l4.commit(this);
+ if (l4Changed || inet4.isAddressModified()) {
+ // Update checksum.
+ if (l4.updateChecksum(inet4)) {
+ l4Changed = true;
+ }
+ }
+ }
+
+ // Commit modification to IPv4 header.
boolean inet4Changed = (inet4 != null) ? inet4.commit(this) : false;
+
if (l4Changed) {
Packet payload = l4.getPacket();
inet4.getPacket().setPayload(payload);
@@ -1003,6 +1052,27 @@ public class PacketContext implements Cloneable {
filterDisabled = b;
}
+ /**
+ * Determine whether at least one flow filter is evaluated with this packet
+ * or not.
+ *
+ * @return {@code true} only if at least one flow filter is evaluated.
+ */
+ public boolean isFiltered() {
+ return filtered;
+ }
+
+ /**
+ * Set a boolean value which determines whetehr at least one flow filter
+ * is evaluated with this packet or not.
+ *
+ * @param b {@code true} means that at least one flow filter is evaluated
+ * with this packet.
+ */
+ public void setFiltered(boolean b) {
+ filtered = b;
+ }
+
/**
* Determine whether the destination address of this packet is equal to
* the controller address or not.
@@ -1102,7 +1172,7 @@ public class PacketContext implements Cloneable {
pctx.inet4Packet = inet4.clone();
}
- CachedPacket l4 = pctx.l4Packet;
+ L4Packet l4 = pctx.l4Packet;
if (l4 != null) {
pctx.l4Packet = l4.clone();
}
diff --git a/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/StatsReader.java b/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/StatsReader.java
index f6027557..ff95f66a 100644
--- a/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/StatsReader.java
+++ b/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/StatsReader.java
@@ -14,6 +14,9 @@ import java.util.Map;
import java.util.HashMap;
import java.util.concurrent.TimeUnit;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
import org.opendaylight.vtn.manager.flow.FlowStats;
import org.opendaylight.controller.forwardingrulesmanager.FlowEntry;
@@ -29,6 +32,12 @@ import org.opendaylight.controller.statisticsmanager.IStatisticsManager;
*
*/
public class StatsReader {
+ /**
+ * Logger instance.
+ */
+ private static final Logger LOG =
+ LoggerFactory.getLogger(StatsReader.class);
+
/**
* Statistics manager service.
*/
@@ -47,7 +56,7 @@ public class StatsReader {
/**
* Construct a new instance.
*
- * @param stMgr VTN Manager service.
+ * @param stMgr Statistics manager service.
* @param update if {@code true}, flow statistics are derived from
* physical switch. Otherwise this instance will return
* statistics cached in statistics manager.
@@ -73,11 +82,15 @@ public class StatsReader {
* the specified flow entry was not found.
*/
public FlowStats get(FlowEntry fent) {
+ LOG.debug("Request for statistics: {}", fent);
FlowOnNode stats = getStats(fent);
if (stats == null) {
+ LOG.debug("Statistics not found: {}", fent);
return null;
}
+ LOG.debug("Statistics found: fent={}, stat={}", fent, stats);
+
// Convert duration into the number of milliseconds.
int sec = stats.getDurationSeconds();
int nsec = stats.getDurationNanoseconds();
@@ -105,6 +118,8 @@ public class StatsReader {
if (statsCache != null) {
nodeMap = statsCache.get(node);
if (nodeMap != null) {
+ LOG.trace("Use statistics cache: node={}, cache={}",
+ node, nodeMap);
return nodeMap.get(fent);
}
@@ -120,6 +135,8 @@ public class StatsReader {
List stats = (doUpdate)
? statsManager.getFlowsNoCache(node)
: statsManager.getFlows(node);
+
+ LOG.trace("Statistics for node {}: {}", node, stats);
for (FlowOnNode st: stats) {
// Ignore flow tables other than table 0.
if (st.getTableId() == 0) {
diff --git a/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/cluster/FlowActionImpl.java b/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/cluster/FlowActionImpl.java
index cc24b955..86da47ec 100644
--- a/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/cluster/FlowActionImpl.java
+++ b/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/cluster/FlowActionImpl.java
@@ -27,6 +27,10 @@ import org.opendaylight.vtn.manager.flow.action.SetDlSrcAction;
import org.opendaylight.vtn.manager.flow.action.SetDscpAction;
import org.opendaylight.vtn.manager.flow.action.SetIcmpCodeAction;
import org.opendaylight.vtn.manager.flow.action.SetIcmpTypeAction;
+import org.opendaylight.vtn.manager.flow.action.SetInet4DstAction;
+import org.opendaylight.vtn.manager.flow.action.SetInet4SrcAction;
+import org.opendaylight.vtn.manager.flow.action.SetTpDstAction;
+import org.opendaylight.vtn.manager.flow.action.SetTpSrcAction;
import org.opendaylight.vtn.manager.flow.action.SetVlanPcpAction;
import org.opendaylight.vtn.manager.internal.MiscUtils;
@@ -71,15 +75,15 @@ public abstract class FlowActionImpl implements Serializable {
*/
static {
CONSTRUCTORS = new HashMap, Constructor>>();
-
- // REVISIT:
- // Currenlty flow actions that require recalculation of TCP/UDP
- // checksum are not yet supported.
Class>[] classes = {
SetDlSrcAction.class,
SetDlDstAction.class,
SetVlanPcpAction.class,
+ SetInet4SrcAction.class,
+ SetInet4DstAction.class,
SetDscpAction.class,
+ SetTpSrcAction.class,
+ SetTpDstAction.class,
SetIcmpTypeAction.class,
SetIcmpCodeAction.class,
};
diff --git a/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/cluster/FlowFilterMap.java b/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/cluster/FlowFilterMap.java
index 88b426c2..dd97d941 100644
--- a/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/cluster/FlowFilterMap.java
+++ b/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/cluster/FlowFilterMap.java
@@ -360,17 +360,15 @@ public abstract class FlowFilterMap implements Serializable, Cloneable {
public final PacketContext evaluate(VTNManagerImpl mgr, PacketContext pctx,
short vid)
throws DropFlowException, RedirectFlowException {
- if (pctx.isFilterDisabled()) {
- logDisabled(mgr, pctx);
- return pctx;
- }
-
- PacketContext pc;
- if (flowFilters.isEmpty()) {
- pc = pctx;
- } else {
- pc = getPacketContext(pctx);
- evaluateImpl(mgr, pc, vid);
+ PacketContext pc = pctx;
+ if (!flowFilters.isEmpty()) {
+ pctx.setFiltered(true);
+ if (pctx.isFilterDisabled()) {
+ logDisabled(mgr, pctx);
+ } else {
+ pc = getPacketContext(pctx);
+ evaluateImpl(mgr, pc, vid);
+ }
}
return pc;
diff --git a/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/cluster/InetAddressActionImpl.java b/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/cluster/InetAddressActionImpl.java
index 288f9a03..ca6fd3a9 100644
--- a/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/cluster/InetAddressActionImpl.java
+++ b/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/cluster/InetAddressActionImpl.java
@@ -15,7 +15,6 @@ import org.opendaylight.vtn.manager.VTNException;
import org.opendaylight.vtn.manager.flow.action.InetAddressAction;
import org.opendaylight.vtn.manager.internal.MiscUtils;
-import org.opendaylight.vtn.manager.internal.PacketContext;
import org.opendaylight.controller.sal.utils.Status;
@@ -32,7 +31,7 @@ public abstract class InetAddressActionImpl extends FlowActionImpl {
/**
* Version number for serialization.
*/
- private static final long serialVersionUID = -5303473358097612716L;
+ private static final long serialVersionUID = -6711928072439846526L;
/**
* IP address to be set.
@@ -72,15 +71,6 @@ public abstract class InetAddressActionImpl extends FlowActionImpl {
return address;
}
- /**
- * {@inheritDoc}
- */
- @Override
- public final boolean apply(PacketContext pctx) {
- // REVISIT: Not yet supported.
- return false;
- }
-
/**
* Determine whether the given object is identical to this object.
*
diff --git a/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/cluster/SetDlDstActionImpl.java b/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/cluster/SetDlDstActionImpl.java
index fb02052f..bdac8042 100644
--- a/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/cluster/SetDlDstActionImpl.java
+++ b/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/cluster/SetDlDstActionImpl.java
@@ -15,6 +15,8 @@ import org.opendaylight.vtn.manager.flow.action.SetDlDstAction;
import org.opendaylight.vtn.manager.internal.PacketContext;
import org.opendaylight.vtn.manager.internal.packet.EtherPacket;
+import org.opendaylight.controller.sal.action.SetDlDst;
+
/**
* Implementation of flow action that modifies destination MAC address in
* Ethernet frame.
@@ -60,6 +62,7 @@ public final class SetDlDstActionImpl extends DlAddrActionImpl {
EtherPacket ether = pctx.getEtherPacket();
byte[] addr = getAddress();
ether.setDestinationAddress(addr);
+ pctx.addFilterAction(new SetDlDst(addr));
return true;
}
}
diff --git a/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/cluster/SetDlSrcActionImpl.java b/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/cluster/SetDlSrcActionImpl.java
index aff3e801..9926414a 100644
--- a/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/cluster/SetDlSrcActionImpl.java
+++ b/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/cluster/SetDlSrcActionImpl.java
@@ -15,6 +15,8 @@ import org.opendaylight.vtn.manager.flow.action.SetDlSrcAction;
import org.opendaylight.vtn.manager.internal.PacketContext;
import org.opendaylight.vtn.manager.internal.packet.EtherPacket;
+import org.opendaylight.controller.sal.action.SetDlSrc;
+
/**
* Implementation of flow action that modifies source MAC address in Ethernet
* frame.
@@ -60,6 +62,7 @@ public final class SetDlSrcActionImpl extends DlAddrActionImpl {
EtherPacket ether = pctx.getEtherPacket();
byte[] addr = getAddress();
ether.setSourceAddress(addr);
+ pctx.addFilterAction(new SetDlSrc(addr));
return true;
}
}
diff --git a/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/cluster/SetDscpActionImpl.java b/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/cluster/SetDscpActionImpl.java
index 18c14835..5c3f2799 100644
--- a/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/cluster/SetDscpActionImpl.java
+++ b/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/cluster/SetDscpActionImpl.java
@@ -17,6 +17,7 @@ import org.opendaylight.vtn.manager.internal.MiscUtils;
import org.opendaylight.vtn.manager.internal.PacketContext;
import org.opendaylight.vtn.manager.internal.packet.Inet4Packet;
+import org.opendaylight.controller.sal.action.SetNwTos;
import org.opendaylight.controller.sal.utils.StatusCode;
/**
@@ -118,6 +119,8 @@ public final class SetDscpActionImpl extends FlowActionImpl {
Inet4Packet ipv4 = pctx.getInet4Packet();
if (ipv4 != null) {
ipv4.setDscp(dscp);
+ int tos = (int)SetDscpAction.dscpToTos(dscp);
+ pctx.addFilterAction(new SetNwTos(tos));
return true;
}
diff --git a/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/cluster/SetIcmpCodeActionImpl.java b/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/cluster/SetIcmpCodeActionImpl.java
index c00c0411..54f9737f 100644
--- a/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/cluster/SetIcmpCodeActionImpl.java
+++ b/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/cluster/SetIcmpCodeActionImpl.java
@@ -15,9 +15,10 @@ import org.opendaylight.vtn.manager.flow.action.SetIcmpCodeAction;
import org.opendaylight.vtn.manager.internal.MiscUtils;
import org.opendaylight.vtn.manager.internal.PacketContext;
-import org.opendaylight.vtn.manager.internal.packet.CachedPacket;
import org.opendaylight.vtn.manager.internal.packet.IcmpPacket;
+import org.opendaylight.vtn.manager.internal.packet.L4Packet;
+import org.opendaylight.controller.sal.action.SetTpDst;
import org.opendaylight.controller.sal.utils.StatusCode;
/**
@@ -115,10 +116,11 @@ public final class SetIcmpCodeActionImpl extends FlowActionImpl {
*/
@Override
public boolean apply(PacketContext pctx) {
- CachedPacket packet = pctx.getL4Packet();
+ L4Packet packet = pctx.getL4Packet();
if (packet instanceof IcmpPacket) {
IcmpPacket icmp = (IcmpPacket)packet;
icmp.setCode(code);
+ pctx.addFilterAction(new SetTpDst((int)code));
return true;
}
diff --git a/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/cluster/SetIcmpTypeActionImpl.java b/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/cluster/SetIcmpTypeActionImpl.java
index fadec00d..ce6b2b55 100644
--- a/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/cluster/SetIcmpTypeActionImpl.java
+++ b/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/cluster/SetIcmpTypeActionImpl.java
@@ -15,9 +15,10 @@ import org.opendaylight.vtn.manager.flow.action.SetIcmpTypeAction;
import org.opendaylight.vtn.manager.internal.MiscUtils;
import org.opendaylight.vtn.manager.internal.PacketContext;
-import org.opendaylight.vtn.manager.internal.packet.CachedPacket;
import org.opendaylight.vtn.manager.internal.packet.IcmpPacket;
+import org.opendaylight.vtn.manager.internal.packet.L4Packet;
+import org.opendaylight.controller.sal.action.SetTpSrc;
import org.opendaylight.controller.sal.utils.StatusCode;
/**
@@ -115,10 +116,11 @@ public final class SetIcmpTypeActionImpl extends FlowActionImpl {
*/
@Override
public boolean apply(PacketContext pctx) {
- CachedPacket packet = pctx.getL4Packet();
+ L4Packet packet = pctx.getL4Packet();
if (packet instanceof IcmpPacket) {
IcmpPacket icmp = (IcmpPacket)packet;
icmp.setType(type);
+ pctx.addFilterAction(new SetTpSrc((int)type));
return true;
}
diff --git a/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/cluster/SetInet4DstActionImpl.java b/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/cluster/SetInet4DstActionImpl.java
index 505ef045..6ad5e544 100644
--- a/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/cluster/SetInet4DstActionImpl.java
+++ b/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/cluster/SetInet4DstActionImpl.java
@@ -9,9 +9,16 @@
package org.opendaylight.vtn.manager.internal.cluster;
+import java.net.InetAddress;
+
import org.opendaylight.vtn.manager.VTNException;
import org.opendaylight.vtn.manager.flow.action.SetInet4DstAction;
+import org.opendaylight.vtn.manager.internal.PacketContext;
+import org.opendaylight.vtn.manager.internal.packet.Inet4Packet;
+
+import org.opendaylight.controller.sal.action.SetNwDst;
+
/**
* Implementation of flow action that modifies destination IP address in IPv4
* header.
@@ -26,7 +33,7 @@ public final class SetInet4DstActionImpl extends InetAddressActionImpl {
/**
* Version number for serialization.
*/
- private static final long serialVersionUID = 3548684343825850653L;
+ private static final long serialVersionUID = -846214438904204416L;
/**
* Construct a new instance.
@@ -48,4 +55,20 @@ public final class SetInet4DstActionImpl extends InetAddressActionImpl {
public SetInet4DstAction getFlowAction() {
return new SetInet4DstAction(getAddress());
}
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public boolean apply(PacketContext pctx) {
+ Inet4Packet ipv4 = pctx.getInet4Packet();
+ if (ipv4 != null) {
+ InetAddress iaddr = getAddress();
+ ipv4.setDestinationAddress(iaddr);
+ pctx.addFilterAction(new SetNwDst(iaddr));
+ return true;
+ }
+
+ return false;
+ }
}
diff --git a/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/cluster/SetInet4SrcActionImpl.java b/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/cluster/SetInet4SrcActionImpl.java
index 56ce16be..6e609016 100644
--- a/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/cluster/SetInet4SrcActionImpl.java
+++ b/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/cluster/SetInet4SrcActionImpl.java
@@ -9,9 +9,16 @@
package org.opendaylight.vtn.manager.internal.cluster;
+import java.net.InetAddress;
+
import org.opendaylight.vtn.manager.VTNException;
import org.opendaylight.vtn.manager.flow.action.SetInet4SrcAction;
+import org.opendaylight.vtn.manager.internal.PacketContext;
+import org.opendaylight.vtn.manager.internal.packet.Inet4Packet;
+
+import org.opendaylight.controller.sal.action.SetNwSrc;
+
/**
* Implementation of flow action that modifies source IP address in IPv4
* header.
@@ -26,7 +33,7 @@ public final class SetInet4SrcActionImpl extends InetAddressActionImpl {
/**
* Version number for serialization.
*/
- private static final long serialVersionUID = 2930155952373937514L;
+ private static final long serialVersionUID = 2335727194215172858L;
/**
* Construct a new instance.
@@ -48,4 +55,20 @@ public final class SetInet4SrcActionImpl extends InetAddressActionImpl {
public SetInet4SrcAction getFlowAction() {
return new SetInet4SrcAction(getAddress());
}
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public boolean apply(PacketContext pctx) {
+ Inet4Packet ipv4 = pctx.getInet4Packet();
+ if (ipv4 != null) {
+ InetAddress iaddr = getAddress();
+ ipv4.setSourceAddress(iaddr);
+ pctx.addFilterAction(new SetNwSrc(iaddr));
+ return true;
+ }
+
+ return false;
+ }
}
diff --git a/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/cluster/SetTpDstActionImpl.java b/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/cluster/SetTpDstActionImpl.java
index 53154187..8f59d3f6 100644
--- a/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/cluster/SetTpDstActionImpl.java
+++ b/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/cluster/SetTpDstActionImpl.java
@@ -12,6 +12,12 @@ package org.opendaylight.vtn.manager.internal.cluster;
import org.opendaylight.vtn.manager.VTNException;
import org.opendaylight.vtn.manager.flow.action.SetTpDstAction;
+import org.opendaylight.vtn.manager.internal.PacketContext;
+import org.opendaylight.vtn.manager.internal.packet.L4Packet;
+import org.opendaylight.vtn.manager.internal.packet.PortProtoPacket;
+
+import org.opendaylight.controller.sal.action.SetTpDst;
+
/**
* Implementation of flow action that modifies destination port number in
* TCP or UDP header.
@@ -26,7 +32,7 @@ public final class SetTpDstActionImpl extends TpPortActionImpl {
/**
* Version number for serialization.
*/
- private static final long serialVersionUID = 6524364010316084813L;
+ private static final long serialVersionUID = -515773805142320193L;
/**
* Construct a new instance.
@@ -48,4 +54,21 @@ public final class SetTpDstActionImpl extends TpPortActionImpl {
public SetTpDstAction getFlowAction() {
return new SetTpDstAction(getPort());
}
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public boolean apply(PacketContext pctx) {
+ L4Packet packet = pctx.getL4Packet();
+ if (packet instanceof PortProtoPacket) {
+ PortProtoPacket pkt = (PortProtoPacket)packet;
+ int port = getPort();
+ pkt.setDestinationPort(port);
+ pctx.addFilterAction(new SetTpDst(port));
+ return true;
+ }
+
+ return false;
+ }
}
diff --git a/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/cluster/SetTpSrcActionImpl.java b/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/cluster/SetTpSrcActionImpl.java
index 026b65ed..2bf6357e 100644
--- a/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/cluster/SetTpSrcActionImpl.java
+++ b/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/cluster/SetTpSrcActionImpl.java
@@ -12,6 +12,12 @@ package org.opendaylight.vtn.manager.internal.cluster;
import org.opendaylight.vtn.manager.VTNException;
import org.opendaylight.vtn.manager.flow.action.SetTpSrcAction;
+import org.opendaylight.vtn.manager.internal.PacketContext;
+import org.opendaylight.vtn.manager.internal.packet.L4Packet;
+import org.opendaylight.vtn.manager.internal.packet.PortProtoPacket;
+
+import org.opendaylight.controller.sal.action.SetTpSrc;
+
/**
* Implementation of flow action that modifies source port number in
* TCP or UDP header.
@@ -26,7 +32,7 @@ public final class SetTpSrcActionImpl extends TpPortActionImpl {
/**
* Version number for serialization.
*/
- private static final long serialVersionUID = 644126347054787614L;
+ private static final long serialVersionUID = 531081632567093651L;
/**
* Construct a new instance.
@@ -48,4 +54,21 @@ public final class SetTpSrcActionImpl extends TpPortActionImpl {
public SetTpSrcAction getFlowAction() {
return new SetTpSrcAction(getPort());
}
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public boolean apply(PacketContext pctx) {
+ L4Packet packet = pctx.getL4Packet();
+ if (packet instanceof PortProtoPacket) {
+ PortProtoPacket pkt = (PortProtoPacket)packet;
+ int port = getPort();
+ pkt.setSourcePort(port);
+ pctx.addFilterAction(new SetTpSrc(port));
+ return true;
+ }
+
+ return false;
+ }
}
diff --git a/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/cluster/SetVlanPcpActionImpl.java b/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/cluster/SetVlanPcpActionImpl.java
index 7aef12b0..b6a95a13 100644
--- a/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/cluster/SetVlanPcpActionImpl.java
+++ b/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/cluster/SetVlanPcpActionImpl.java
@@ -17,6 +17,7 @@ import org.opendaylight.vtn.manager.internal.MiscUtils;
import org.opendaylight.vtn.manager.internal.PacketContext;
import org.opendaylight.vtn.manager.internal.packet.EtherPacket;
+import org.opendaylight.controller.sal.action.SetVlanPcp;
import org.opendaylight.controller.sal.utils.StatusCode;
/**
@@ -118,6 +119,7 @@ public final class SetVlanPcpActionImpl extends FlowActionImpl {
public boolean apply(PacketContext pctx) {
EtherPacket ether = pctx.getEtherPacket();
ether.setVlanPriority(priority);
+ pctx.addFilterAction(new SetVlanPcp((int)priority));
return true;
}
}
diff --git a/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/cluster/TpPortActionImpl.java b/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/cluster/TpPortActionImpl.java
index ef47d3db..023cc4fd 100644
--- a/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/cluster/TpPortActionImpl.java
+++ b/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/cluster/TpPortActionImpl.java
@@ -13,7 +13,6 @@ import org.opendaylight.vtn.manager.VTNException;
import org.opendaylight.vtn.manager.flow.action.TpPortAction;
import org.opendaylight.vtn.manager.internal.MiscUtils;
-import org.opendaylight.vtn.manager.internal.PacketContext;
import org.opendaylight.controller.sal.utils.StatusCode;
@@ -31,7 +30,7 @@ public abstract class TpPortActionImpl extends FlowActionImpl {
/**
* Version number for serialization.
*/
- private static final long serialVersionUID = -8000141230774734830L;
+ private static final long serialVersionUID = 2892201590657891707L;
/**
* A port number to be set.
@@ -64,15 +63,6 @@ public abstract class TpPortActionImpl extends FlowActionImpl {
return port;
}
- /**
- * {@inheritDoc}
- */
- @Override
- public final boolean apply(PacketContext pctx) {
- // REVISIT: Not yet supported.
- return false;
- }
-
/**
* Determine whether the given object is identical to this object.
*
diff --git a/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/cluster/VTerminalImpl.java b/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/cluster/VTerminalImpl.java
index 346ca29c..bcc2c7b3 100644
--- a/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/cluster/VTerminalImpl.java
+++ b/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/cluster/VTerminalImpl.java
@@ -32,6 +32,7 @@ import org.opendaylight.vtn.manager.VTerminalConfig;
import org.opendaylight.vtn.manager.VTerminalIfPath;
import org.opendaylight.vtn.manager.VTerminalPath;
+import org.opendaylight.vtn.manager.internal.LogProvider;
import org.opendaylight.vtn.manager.internal.PacketContext;
import org.opendaylight.vtn.manager.internal.VTNManagerImpl;
import org.opendaylight.vtn.manager.internal.VTNThreadData;
@@ -39,6 +40,7 @@ import org.opendaylight.vtn.manager.internal.VTNThreadData;
import org.opendaylight.controller.hosttracker.hostAware.HostNodeConnector;
import org.opendaylight.controller.sal.core.NodeConnector;
import org.opendaylight.controller.sal.core.UpdateType;
+import org.opendaylight.controller.sal.match.MatchType;
import org.opendaylight.controller.sal.packet.PacketResult;
import org.opendaylight.controller.sal.utils.HexEncode;
import org.opendaylight.controller.sal.utils.NetUtils;
@@ -57,7 +59,7 @@ public final class VTerminalImpl extends PortBridge {
/**
* Version number for serialization.
*/
- private static final long serialVersionUID = -1930350835055234980L;
+ private static final long serialVersionUID = -4401735057418279006L;
/**
* Logger instance.
@@ -479,18 +481,47 @@ public final class VTerminalImpl extends PortBridge {
*/
@Override
protected PacketResult handlePacket(VTNManagerImpl mgr, PacketContext pctx,
- VirtualMapNode vnode) {
+ final VirtualMapNode vnode) {
RedirectFlowException rex = pctx.getFirstRedirection();
if (rex == null) {
// Notify source host of the packet.
notifyHost(mgr, pctx);
- if (LOG.isDebugEnabled()) {
- LOG.debug("{}:{}: Disable input from vTerminal interface.",
- getContainerName(), vnode.getPath());
+ if (pctx.isFiltered()) {
+ LOG.debug("{}:{}: Discard packet from vTerminal interface: " +
+ "packet={}", getContainerName(), vnode.getPath(),
+ pctx.getDescription());
+
+ if (!pctx.isUnicast()) {
+ // In that case we should specify multicast address in a
+ // drop flow entry, or it may discard packets to be
+ // filtered by flow filter.
+ pctx.addMatchField(MatchType.DL_TYPE);
+ pctx.addMatchField(MatchType.DL_DST);
+ }
+
+ LogProvider lp = new LogProvider() {
+ @Override
+ public Logger getLogger() {
+ return LOG;
+ }
+
+ @Override
+ public String getLogPrefix() {
+ StringBuilder builder =
+ new StringBuilder(getContainerName());
+ builder.append(':').append(vnode.getPath());
+ return builder.toString();
+ }
+ };
+ pctx.installDropFlow(mgr, getNodePath(), lp);
+ } else {
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("{}:{}: Disable input from vTerminal interface.",
+ getContainerName(), vnode.getPath());
+ }
+ vnode.disableInput(mgr, pctx);
}
-
- vnode.disableInput(mgr, pctx);
} else {
Logger logger = rex.getLogger();
VNodePath path = getNodePath();
diff --git a/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/packet/EtherPacket.java b/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/packet/EtherPacket.java
index adbef214..295106e9 100644
--- a/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/packet/EtherPacket.java
+++ b/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/packet/EtherPacket.java
@@ -234,10 +234,10 @@ public final class EtherPacket implements CachedPacket {
* @param tag An {@link IEEE8021Q} instance.
*/
private void fill(Ethernet ether, IEEE8021Q tag) {
- if (sourceMac == MAC_NONE) {
+ if (sourceAddress == null) {
setSourceAddress(ether.getSourceMACAddress());
}
- if (destinationMac == MAC_NONE) {
+ if (destinationAddress == null) {
setDestinationAddress(ether.getDestinationMACAddress());
}
if (vlanPriority == VLANPRI_NONE && tag != null) {
@@ -283,7 +283,7 @@ public final class EtherPacket implements CachedPacket {
} else {
ethType = ether.getEtherType();
vlanTag = null;
- vid = 0;
+ vid = MatchType.DL_VLAN_NONE;
}
values = new Values(vid);
@@ -350,7 +350,7 @@ public final class EtherPacket implements CachedPacket {
public long getSourceMacAddress() {
Values v = getValues();
long mac = v.getSourceMacAddress();
- if (mac == MAC_NONE) {
+ if (v.getSourceAddress() == null) {
byte[] addr = packet.getSourceMACAddress();
v.setSourceAddress(addr);
mac = v.getSourceMacAddress();
@@ -367,7 +367,7 @@ public final class EtherPacket implements CachedPacket {
public long getDestinationMacAddress() {
Values v = getValues();
long mac = v.getDestinationMacAddress();
- if (mac == MAC_NONE) {
+ if (v.getDestinationAddress() == null) {
byte[] addr = packet.getDestinationMACAddress();
v.setDestinationAddress(addr);
mac = v.getDestinationMacAddress();
@@ -587,35 +587,47 @@ public final class EtherPacket implements CachedPacket {
*/
@Override
public boolean commit(PacketContext pctx) {
- // We don't need to create a copy of original packet and action to
- // configure VLAN ID.
- // - PacketContext creates Ethernet header and VLAN tag from scratch.
- // - Flow action to configure VLAN ID is controller by VBridgeImpl.
+ // We don't need to set modified values to Ethernet and IEEE8021Q
+ // instances because PacketContext always creates Ethernet header and
+ // VLAN tag from scratch.
boolean mod = false;
if (modifiedValues != null) {
if (values.getSourceMacAddress() !=
modifiedValues.getSourceMacAddress()) {
// Source MAC address was modified.
- byte[] addr = modifiedValues.getSourceAddress();
- pctx.addFilterAction(new SetDlSrc(addr));
mod = true;
+ } else if (pctx.hasMatchField(MatchType.DL_SRC)) {
+ // Source MAC address is not modified, and it will be specified
+ // in flow match. So we don't need to configure SET_DL_SRC
+ // action.
+ pctx.removeFilterAction(SetDlSrc.class);
}
if (values.getDestinationMacAddress() !=
modifiedValues.getDestinationMacAddress()) {
// Destination MAC address was modified.
- byte[] addr = modifiedValues.getDestinationAddress();
- pctx.addFilterAction(new SetDlDst(addr));
mod = true;
+ } else if (pctx.hasMatchField(MatchType.DL_DST)) {
+ // Destination MAC address is not modified, and it will be
+ // specified in flow match. So we don't need to configure
+ // SET_DL_DST action.
+ pctx.removeFilterAction(SetDlDst.class);
}
short vlan = modifiedValues.getVlan();
- if (vlan != 0) {
+ if (vlan == MatchType.DL_VLAN_NONE) {
+ // SET_VLAN_PCP should never be applied to untagged frame.
+ pctx.removeFilterAction(SetVlanPcp.class);
+ } else {
byte pri = modifiedValues.getVlanPriority();
if (values.getVlanPriority() != pri) {
// VLAN priority was modified.
- pctx.addFilterAction(new SetVlanPcp((int)pri));
mod = true;
+ } else if (pctx.hasMatchField(MatchType.DL_VLAN_PR)) {
+ // VLAN priority is not modified, and it will be specified
+ // in flow match. So we don't need to configure
+ // SET_VLAN_PCP action.
+ pctx.removeFilterAction(SetVlanPcp.class);
}
}
}
diff --git a/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/packet/IcmpPacket.java b/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/packet/IcmpPacket.java
index 61a8b730..53807855 100644
--- a/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/packet/IcmpPacket.java
+++ b/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/packet/IcmpPacket.java
@@ -13,6 +13,7 @@ import java.util.Set;
import org.opendaylight.vtn.manager.VTNException;
+import org.opendaylight.vtn.manager.internal.MiscUtils;
import org.opendaylight.vtn.manager.internal.PacketContext;
import org.opendaylight.controller.sal.action.SetTpDst;
@@ -25,7 +26,7 @@ import org.opendaylight.controller.sal.utils.NetUtils;
/**
* {@code IcmpPacket} class implements a cache for an {@link ICMP} instance.
*/
-public final class IcmpPacket implements CachedPacket {
+public final class IcmpPacket implements L4Packet {
/**
* A pseudo short value which indicates the byte value is not specified.
*/
@@ -95,9 +96,11 @@ public final class IcmpPacket implements CachedPacket {
* Set the ICMP type.
*
* @param value A byte integer value which indicates the ICMP type.
+ * @return A short value which represents the given ICMP type.
*/
- private void setType(byte value) {
+ private short setType(byte value) {
type = (short)NetUtils.getUnsignedByte(value);
+ return type;
}
/**
@@ -124,9 +127,11 @@ public final class IcmpPacket implements CachedPacket {
* Set the ICMP code.
*
* @param value A byte integer value which indicates the ICMP code.
+ * @return A short value which represents the given ICMP code.
*/
- private void setCode(byte value) {
+ private short setCode(byte value) {
code = (short)NetUtils.getUnsignedByte(value);
+ return code;
}
/**
@@ -139,10 +144,10 @@ public final class IcmpPacket implements CachedPacket {
* @param icmp An {@link ICMP} instance.
*/
private void fill(ICMP icmp) {
- if (type != VALUE_NONE) {
+ if (type == VALUE_NONE) {
setType(icmp.getType());
}
- if (code != VALUE_NONE) {
+ if (code == VALUE_NONE) {
setCode(icmp.getCode());
}
}
@@ -182,7 +187,7 @@ public final class IcmpPacket implements CachedPacket {
short type = v.getType();
if (type == VALUE_NONE) {
byte b = packet.getType();
- v.setType(b);
+ type = v.setType(b);
}
return type;
@@ -208,7 +213,7 @@ public final class IcmpPacket implements CachedPacket {
short code = v.getCode();
if (code == VALUE_NONE) {
byte b = packet.getCode();
- v.setCode(b);
+ code = v.setCode(b);
}
return code;
@@ -259,16 +264,7 @@ public final class IcmpPacket implements CachedPacket {
private ICMP getPacketForWrite() throws VTNException {
if (cloned) {
// Create a copy of the original packet.
- try {
- byte[] raw = packet.serialize();
- int nbits = raw.length * NetUtils.NumBitsInAByte;
- packet = new ICMP();
- packet.deserialize(raw, 0, nbits);
- } catch (Exception e) {
- // This should never happen.
- throw new VTNException("Failed to copy the packet.", e);
- }
-
+ packet = MiscUtils.copy(packet, new ICMP());
cloned = false;
}
@@ -330,31 +326,37 @@ public final class IcmpPacket implements CachedPacket {
boolean mod = false;
ICMP icmp = null;
if (modifiedValues != null) {
+ // At least one flow action that modifies ICMP header is
+ // configured.
+ pctx.addMatchField(MatchType.DL_TYPE);
+ pctx.addMatchField(MatchType.NW_PROTO);
+
short type = modifiedValues.getType();
if (values.getType() != type) {
// ICMP type was modified.
- pctx.addFilterAction(new SetTpSrc((int)type));
icmp = getPacketForWrite();
icmp.setType((byte)type);
mod = true;
+ } else if (pctx.hasMatchField(MatchType.TP_SRC)) {
+ // ICMP type in the original packet is unchanged and it will be
+ // specified in flow match. So we don't need to configure
+ // SET_TP_SRC action.
+ pctx.removeFilterAction(SetTpSrc.class);
}
short code = modifiedValues.getCode();
if (values.getCode() != code) {
// ICMP code was modifled.
- pctx.addFilterAction(new SetTpDst((int)code));
if (icmp == null) {
icmp = getPacketForWrite();
}
icmp.setCode((byte)code);
mod = true;
- }
-
- if (mod) {
- // Note that this action must be applied to only ICMPv4
- // packets.
- pctx.addMatchField(MatchType.DL_TYPE);
- pctx.addMatchField(MatchType.NW_PROTO);
+ } else if (pctx.hasMatchField(MatchType.TP_DST)) {
+ // ICMP code in the original packet is unchanged and it will be
+ // specified in flow match. So we don't need to configure
+ // SET_TP_DST action.
+ pctx.removeFilterAction(SetTpDst.class);
}
}
@@ -383,4 +385,22 @@ public final class IcmpPacket implements CachedPacket {
throw new IllegalStateException("clone() failed", e);
}
}
+
+ // L4Packet
+
+ /**
+ * Calculate the checksum of the packet.
+ *
+ *
+ * This method does nothing because the ICMP checksum is computed by
+ * {@link ICMP} class.
+ *
+ *
+ * @param ipv4 Never used.
+ * @return {@code false}.
+ */
+ @Override
+ public boolean updateChecksum(Inet4Packet ipv4) {
+ return false;
+ }
}
diff --git a/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/packet/Inet4Packet.java b/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/packet/Inet4Packet.java
index b44f9ba5..902d294e 100644
--- a/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/packet/Inet4Packet.java
+++ b/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/packet/Inet4Packet.java
@@ -9,14 +9,16 @@
package org.opendaylight.vtn.manager.internal.packet;
+import java.net.InetAddress;
import java.util.Set;
import org.opendaylight.vtn.manager.VTNException;
-import org.opendaylight.vtn.manager.flow.action.SetDscpAction;
import org.opendaylight.vtn.manager.internal.MiscUtils;
import org.opendaylight.vtn.manager.internal.PacketContext;
+import org.opendaylight.controller.sal.action.SetNwDst;
+import org.opendaylight.controller.sal.action.SetNwSrc;
import org.opendaylight.controller.sal.action.SetNwTos;
import org.opendaylight.controller.sal.match.Match;
import org.opendaylight.controller.sal.match.MatchType;
@@ -39,31 +41,44 @@ public final class Inet4Packet implements CachedPacket {
private static final byte DSCP_NONE = -1;
/**
- * An {@link IPv4} packet.
+ * The number of bytes in an IPv4 address.
*/
- private IPv4 packet;
+ private static final int ADDR_SIZE = 4;
+
+ /**
+ * Byte offset to the source address in a pseudo IPv4 header used for
+ * computing TCP/UDP checksum.
+ */
+ private static final int CKSUM_OFF_SRC = 0;
+
+ /**
+ * Byte offset to the destination address in a pseudo IPv4 header used for
+ * computing TCP/UDP checksum.
+ */
+ private static final int CKSUM_OFF_DST = 4;
/**
- * An integer value which indicates the source IP address.
+ * Byte offset to the IP protocol number in a pseudo IPv4 header used for
+ * computing TCP/UDP checksum.
*/
- private int sourceAddress;
+ private static final int CKSUM_OFF_PROTO = 9;
/**
- * An integer value which indicates the destination IP address.
+ * Byte offset to the payload length in a pseudo IPv4 header used for
+ * computing TCP/UDP checksum.
*/
- private int destinationAddress;
+ private static final int CKSUM_OFF_LEN = 10;
/**
- * A boolean value which determines whether {@link #sourceAddress} is
- * initialized or not.
+ * The number of bytes in a pseudo IPv4 header used for computing
+ * TCP/UDP checksum.
*/
- private boolean sourceSet;
+ private static final int CKSUM_HEADER_SIZE = 12;
/**
- * A boolean value which determines whether {@link #destinationAddress} is
- * initialized or not.
+ * An {@link IPv4} packet.
*/
- private boolean destinationSet;
+ private IPv4 packet;
/**
* The IP protocol number in the IPv4 packet.
@@ -89,19 +104,134 @@ public final class Inet4Packet implements CachedPacket {
* This class describes modifiable fields in IPv4 header.
*/
private static final class Values implements Cloneable {
+ /**
+ * An integer value which indicates the source IP address.
+ */
+ private int sourceAddress;
+
+ /**
+ * An integer value which indicates the destination IP address.
+ */
+ private int destinationAddress;
+
+ /**
+ * An {@link InetAddress} instance which indicates the source IP
+ * address.
+ */
+ private InetAddress sourceInetAddress;
+
+ /**
+ * An {@link InetAddress} instance which indicates the destination IP
+ * address.
+ */
+ private InetAddress destinationInetAddress;
+
/**
* The DSCP field value in the IPv4 packet.
*/
private byte dscp = DSCP_NONE;
- // REVISIT: Source and destination IP address are not yet supported.
-
/**
* Constructor.
*/
private Values() {
}
+ /**
+ * Return the source IP address.
+ *
+ * @return An integer value which represents the source IP address.
+ * Note that the returned value is unspecified if
+ * {@link #getSourceInetAddress()} returns {@code null}.
+ */
+ private int getSourceAddress() {
+ return sourceAddress;
+ }
+
+ /**
+ * Return the source IP address.
+ *
+ * @return An {@link InetAddress} instance which represents the
+ * source IP address.
+ * {@code null} is returned if not configured.
+ */
+ private InetAddress getSourceInetAddress() {
+ return sourceInetAddress;
+ }
+
+ /**
+ * Set the source IP address.
+ *
+ * @param addr An {@link InetAddress} instance which represents the
+ * source IPv4 address.
+ */
+ private void setSourceAddress(InetAddress addr) {
+ sourceAddress = MiscUtils.toInteger(addr);
+ sourceInetAddress = addr;
+ }
+
+ /**
+ * Set the source IP address.
+ *
+ * @param addr An integer value which represents the source IPv4
+ * address.
+ * @return An {@link InetAddress} instance which represents the
+ * given IP address.
+ */
+ private InetAddress setSourceAddress(int addr) {
+ sourceAddress = addr;
+ sourceInetAddress = MiscUtils.toInetAddress(addr);
+ return sourceInetAddress;
+ }
+
+ /**
+ * Return the destination IP address.
+ *
+ * @return An integer value which represents the destination IP
+ * address.
+ * Note that the returned value is unspecified if
+ * {@link #getDestinationInetAddress()} returns {@code null}.
+ */
+ private int getDestinationAddress() {
+ return destinationAddress;
+ }
+
+ /**
+ * Return the destination IP address.
+ *
+ * @return An {@link InetAddress} instance which represents the
+ * destination IP address.
+ * {@code null} is returned if not configured.
+ */
+ private InetAddress getDestinationInetAddress() {
+ return destinationInetAddress;
+ }
+
+ /**
+ * Set the destination IP address.
+ *
+ * @param addr An {@link InetAddress} instance which represents the
+ * destination IPv4 address.
+ */
+ private void setDestinationAddress(InetAddress addr) {
+ destinationAddress = MiscUtils.toInteger(addr);
+ destinationInetAddress = addr;
+ }
+
+ /**
+ * Set the destination IP address.
+ *
+ * @param addr An integer value which represents the destination IPv4
+ * address.
+ * @return An {@link InetAddress} instance which represents the
+ * given IP address.
+ */
+ private InetAddress setDestinationAddress(int addr) {
+ destinationAddress = addr;
+ destinationInetAddress = MiscUtils.toInetAddress(addr);
+ return destinationInetAddress;
+ }
+
/**
* Return the DSCP field value.
*
@@ -132,7 +262,13 @@ public final class Inet4Packet implements CachedPacket {
* @param ipv4 An {@link IPv4} instance.
*/
private void fill(IPv4 ipv4) {
- if (dscp != DSCP_NONE) {
+ if (sourceInetAddress == null) {
+ setSourceAddress(ipv4.getSourceAddress());
+ }
+ if (destinationInetAddress == null) {
+ setDestinationAddress(ipv4.getDestinationAddress());
+ }
+ if (dscp == DSCP_NONE) {
dscp = ipv4.getDiffServ();
}
}
@@ -168,12 +304,44 @@ public final class Inet4Packet implements CachedPacket {
* @return An integer value which represents the source IP address.
*/
public int getSourceAddress() {
- if (!sourceSet) {
- sourceAddress = packet.getSourceAddress();
- sourceSet = true;
+ Values v = getValues();
+ int addr;
+ if (v.getSourceInetAddress() == null) {
+ addr = packet.getSourceAddress();
+ v.setSourceAddress(addr);
+ } else {
+ addr = v.getSourceAddress();
+ }
+
+ return addr;
+ }
+
+ /**
+ * Return the source IP address.
+ *
+ * @return An {@link InetAddress} instance which represents the source
+ * IP address.
+ */
+ public InetAddress getSourceInetAddress() {
+ Values v = getValues();
+ InetAddress addr = v.getSourceInetAddress();
+ if (addr == null) {
+ int address = packet.getSourceAddress();
+ addr = v.setSourceAddress(address);
}
- return sourceAddress;
+ return addr;
+ }
+
+ /**
+ * Set the source IP address.
+ *
+ * @param addr An {@link InetAddress} instance which represents the
+ * source IPv4 address.
+ */
+ public void setSourceAddress(InetAddress addr) {
+ Values v = getModifiedValues();
+ v.setSourceAddress(addr);
}
/**
@@ -182,12 +350,44 @@ public final class Inet4Packet implements CachedPacket {
* @return An integer value which represents the destination IP address.
*/
public int getDestinationAddress() {
- if (!destinationSet) {
- destinationAddress = packet.getDestinationAddress();
- destinationSet = true;
+ Values v = getValues();
+ int addr;
+ if (v.getDestinationInetAddress() == null) {
+ addr = packet.getDestinationAddress();
+ v.setDestinationAddress(addr);
+ } else {
+ addr = v.getDestinationAddress();
}
- return destinationAddress;
+ return addr;
+ }
+
+ /**
+ * Return the destination IP address.
+ *
+ * @return An {@link InetAddress} instance which represents the
+ * destination IP address.
+ */
+ public InetAddress getDestinationInetAddress() {
+ Values v = getValues();
+ InetAddress addr = v.getDestinationInetAddress();
+ if (addr == null) {
+ int address = packet.getDestinationAddress();
+ addr = v.setDestinationAddress(address);
+ }
+
+ return addr;
+ }
+
+ /**
+ * Set the destination IP address.
+ *
+ * @param addr An {@link InetAddress} instance which represents the
+ * destination IPv4 address.
+ */
+ public void setDestinationAddress(InetAddress addr) {
+ Values v = getModifiedValues();
+ v.setDestinationAddress(addr);
}
/**
@@ -229,6 +429,43 @@ public final class Inet4Packet implements CachedPacket {
v.setDscp(dscp);
}
+ /**
+ * Determine whether the source or destination address is modified or not.
+ *
+ * @return {@code true} only if the source or destination address is
+ * modified.
+ */
+ public boolean isAddressModified() {
+ if (modifiedValues == null) {
+ return false;
+ }
+
+ return (values.getSourceAddress() !=
+ modifiedValues.getSourceAddress() ||
+ values.getDestinationAddress() !=
+ modifiedValues.getDestinationAddress());
+ }
+
+ /**
+ * Create a pseudo IPv4 header used for computing TCP/UDP checksum.
+ *
+ * @param proto An IP protocol number.
+ * @param len The number of octets in a payload.
+ * @return A byte array which represents the pseudo IPv4 header.
+ */
+ public byte[] getHeaderForChecksum(byte proto, short len) {
+ byte[] header = new byte[CKSUM_HEADER_SIZE];
+
+ int src = getSourceAddress();
+ int dst = getDestinationAddress();
+ MiscUtils.setInt(header, CKSUM_OFF_SRC, src);
+ MiscUtils.setInt(header, CKSUM_OFF_DST, dst);
+ header[CKSUM_OFF_PROTO] = proto;
+ MiscUtils.setShort(header, CKSUM_OFF_LEN, len);
+
+ return header;
+ }
+
/**
* Return a {@link Values} instance that keeps current values for
* IPv4 header fields.
@@ -263,16 +500,8 @@ public final class Inet4Packet implements CachedPacket {
*/
private IPv4 getPacketForWrite() throws VTNException {
if (cloned) {
- try {
- byte[] raw = packet.serialize();
- int nbits = raw.length * NetUtils.NumBitsInAByte;
- packet = new IPv4();
- packet.deserialize(raw, 0, nbits);
- } catch (Exception e) {
- // This should never happen.
- throw new VTNException("Failed to copy the packet.", e);
- }
-
+ // Create a copy of the original packet.
+ packet = MiscUtils.copy(packet, new IPv4());
cloned = false;
}
@@ -316,14 +545,13 @@ public final class Inet4Packet implements CachedPacket {
MatchType type = MatchType.NW_SRC;
if (fields.contains(type)) {
// Test source IP address.
- match.setField(type, MiscUtils.toInetAddress(getSourceAddress()));
+ match.setField(type, v.getSourceInetAddress());
}
type = MatchType.NW_DST;
if (fields.contains(type)) {
// Test destination IP address.
- match.setField(type,
- MiscUtils.toInetAddress(getDestinationAddress()));
+ match.setField(type, v.getDestinationInetAddress());
}
type = MatchType.NW_PROTO;
@@ -345,17 +573,55 @@ public final class Inet4Packet implements CachedPacket {
@Override
public boolean commit(PacketContext pctx) throws VTNException {
boolean mod = false;
+ IPv4 ipv4 = null;
if (modifiedValues != null) {
+ // At least one flow action that modifies IPv4 header is
+ // configured.
+ pctx.addMatchField(MatchType.DL_TYPE);
+
+ if (values.getSourceAddress() !=
+ modifiedValues.getSourceAddress()) {
+ // Source address was modified.
+ InetAddress iaddr = modifiedValues.getSourceInetAddress();
+ ipv4 = getPacketForWrite();
+ ipv4.setSourceAddress(iaddr);
+ mod = true;
+ } else if (pctx.hasMatchField(MatchType.NW_SRC)) {
+ // Source IP address in the original packet is unchanged and
+ // it will be specified in flow match. So we don't need to
+ // configure SET_NW_SRC action.
+ pctx.removeFilterAction(SetNwSrc.class);
+ }
+
+ if (values.getDestinationAddress() !=
+ modifiedValues.getDestinationAddress()) {
+ // Destination address was modified.
+ InetAddress iaddr = modifiedValues.getDestinationInetAddress();
+ if (ipv4 == null) {
+ ipv4 = getPacketForWrite();
+ }
+ ipv4.setDestinationAddress(iaddr);
+ mod = true;
+ } else if (pctx.hasMatchField(MatchType.NW_DST)) {
+ // Destination IP address in the original packet is unchanged
+ // and it will be specified in flow match. So we don't need to
+ // configure SET_NW_DST action.
+ pctx.removeFilterAction(SetNwDst.class);
+ }
+
byte dscp = modifiedValues.getDscp();
if (values.getDscp() != dscp) {
// DSCP field was modified.
- // Note that this action must be applied to only IPv4 packets.
- int tos = (int)SetDscpAction.dscpToTos(dscp);
- pctx.addFilterAction(new SetNwTos(tos));
- pctx.addMatchField(MatchType.DL_TYPE);
- IPv4 ipv4 = getPacketForWrite();
+ if (ipv4 == null) {
+ ipv4 = getPacketForWrite();
+ }
ipv4.setDiffServ(dscp);
mod = true;
+ } else if (pctx.hasMatchField(MatchType.NW_TOS)) {
+ // DSCP value in the original packet is unchanged and it will
+ // be specified in flow match. So we don't need to configure
+ // SET_NW_TOS action.
+ pctx.removeFilterAction(SetNwTos.class);
}
}
diff --git a/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/packet/L4Packet.java b/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/packet/L4Packet.java
new file mode 100644
index 00000000..57038167
--- /dev/null
+++ b/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/packet/L4Packet.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2014 NEC Corporation
+ * All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this
+ * distribution, and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.vtn.manager.internal.packet;
+
+import org.opendaylight.vtn.manager.VTNException;
+
+/**
+ * {@code L4Packet} defines interfaces that implements cache for layer 4
+ * protocol header.
+ */
+public interface L4Packet extends CachedPacket {
+ /**
+ * Calculate the checksum of the packet, and set the computed checksum
+ * into a {@link org.opendaylight.controller.sal.packet.Packet} instance
+ * configured in this instance.
+ *
+ * @param ipv4 An {@link Inet4Packet} instance that contains this
+ * packet.
+ * @return {@code true} is returned if the checksum field was updated.
+ * {@code false} is returned if the packet was not modified.
+ * @throws VTNException
+ * An error occurred.
+ */
+ boolean updateChecksum(Inet4Packet ipv4) throws VTNException;
+
+ /**
+ * Return a deep copy of this instance.
+ *
+ * @return A deep copy of this instance.
+ */
+ L4Packet clone();
+}
diff --git a/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/packet/PortProtoPacket.java b/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/packet/PortProtoPacket.java
index ab0cf611..16ea3115 100644
--- a/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/packet/PortProtoPacket.java
+++ b/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/packet/PortProtoPacket.java
@@ -11,31 +11,271 @@ package org.opendaylight.vtn.manager.internal.packet;
import java.util.Set;
+import org.opendaylight.vtn.manager.VTNException;
+
+import org.opendaylight.vtn.manager.internal.MiscUtils;
import org.opendaylight.vtn.manager.internal.PacketContext;
+import org.opendaylight.controller.sal.action.SetTpDst;
+import org.opendaylight.controller.sal.action.SetTpSrc;
import org.opendaylight.controller.sal.match.Match;
import org.opendaylight.controller.sal.match.MatchType;
+import org.opendaylight.controller.sal.packet.Packet;
import org.opendaylight.controller.sal.utils.NetUtils;
/**
- * {@code TcpPacket} class implements a cache for layer 4 protocol header,
- * which identifies the service using 16-bit port number.
+ * {@code PortProtoPacket} class implements a cache for layer 4 protocol
+ * header, which identifies the service using 16-bit port number.
+ *
+ * @param Type of packet.
*/
-public abstract class PortProtoPacket implements CachedPacket {
+public abstract class PortProtoPacket implements L4Packet {
/**
* A pseudo port number which indicates the port number is not specified.
*/
private static final int PORT_NONE = -1;
/**
- * The source port number.
+ * Computed checksum that indicates the packet verification succeeded.
+ */
+ private static final int CKSUM_OK = 0xffff;
+
+ /**
+ * The number of octets in TCP/UDP checksum.
+ */
+ private static final int CKSUM_BYTES =
+ Short.SIZE / NetUtils.NumBitsInAByte;
+
+ /**
+ * A mask value used to clear LSB.
+ */
+ private static final int MASK_CLEAR_LSB = ~1;
+
+ /**
+ * Cached values in a protocol header.
+ */
+ private Values values = new Values();
+
+ /**
+ * Protocol header values to be set.
+ */
+ private Values modifiedValues;
+
+ /**
+ * Set {@code true} if this instance is created by {@link #clone()}.
*/
- private int sourcePort = PORT_NONE;
+ private boolean cloned;
/**
- * The destination port number.
+ * This class describes modifiable fields in a protocol hedaer.
*/
- private int destinationPort = PORT_NONE;
+ private static final class Values implements Cloneable {
+ /**
+ * The source port number.
+ */
+ private int sourcePort = PORT_NONE;
+
+ /**
+ * The destination port number.
+ */
+ private int destinationPort = PORT_NONE;
+
+ /**
+ * Constructor.
+ */
+ private Values() {
+ }
+
+ /**
+ * Return the source port number.
+ *
+ * @return An integer value which indicates the source port.
+ * {@link PortProtoPacket#PORT_NONE} is returned if not
+ * configured.
+ */
+ private int getSourcePort() {
+ return sourcePort;
+ }
+
+ /**
+ * Set the source port number.
+ *
+ * @param port An integer value which indicates the source port.
+ */
+ private void setSourcePort(int port) {
+ sourcePort = port;
+ }
+
+ /**
+ * Set the source port number.
+ *
+ * @param port A short integer value which indicates the source port.
+ * @return An integer value which indicates the source port.
+ */
+ private int setSourcePort(short port) {
+ sourcePort = NetUtils.getUnsignedShort(port);
+ return sourcePort;
+ }
+
+ /**
+ * Return the destination port number.
+ *
+ * @return An integer value which indicates the destination port.
+ * {@link PortProtoPacket#PORT_NONE} is returned if not
+ * configured.
+ */
+ private int getDestinationPort() {
+ return destinationPort;
+ }
+
+ /**
+ * Set the destination port number.
+ *
+ * @param port An integer value which indicates the destination port.
+ */
+ private void setDestinationPort(int port) {
+ destinationPort = port;
+ }
+
+ /**
+ * Set the destination port number.
+ *
+ * @param port A short integer value which indicates the destination
+ * port.
+ * @return An integer value which indicates the destination port.
+ */
+ private int setDestinationPort(short port) {
+ destinationPort = NetUtils.getUnsignedShort(port);
+ return destinationPort;
+ }
+
+ /**
+ * Fetch all modifiable field values from the given packet.
+ *
+ *
+ * Field values already cached in this instance are preserved.
+ *
+ *
+ * @param packet A {@link PortProtoPacket} instance.
+ */
+ private void fill(PortProtoPacket packet) {
+ if (sourcePort == PORT_NONE) {
+ setSourcePort(packet.getRawSourcePort());
+ }
+ if (destinationPort == PORT_NONE) {
+ setDestinationPort(packet.getRawDestinationPort());
+ }
+ }
+
+ /**
+ * Return a shallow copy of this instance.
+ *
+ * @return A shallow copy of this instance.
+ */
+ @Override
+ public Values clone() {
+ try {
+ return (Values)super.clone();
+ } catch (CloneNotSupportedException e) {
+ // This should never happen.
+ throw new IllegalStateException("clone() failed", e);
+ }
+ }
+ }
+
+ /**
+ * Compute the one's complement sum of all 16-bit words in the given
+ * packet.
+ *
+ * @param ipv4 An {@link Inet4Packet} instance that contains the given
+ * packet.
+ * @param data A serialized packet data.
+ * @return A computed checksum.
+ */
+ private static int computeChecksum(Inet4Packet ipv4, byte[] data) {
+ // Create a pseudo IPv4 header.
+ byte proto = (byte)ipv4.getProtocol();
+ byte[] header = ipv4.getHeaderForChecksum(proto, (short)data.length);
+ int sum = 0;
+ for (int i = 0; i < header.length; i += CKSUM_BYTES) {
+ int v = ((header[i] & MiscUtils.MASK_BYTE) << Byte.SIZE) |
+ (header[i + 1] & MiscUtils.MASK_BYTE);
+ sum += v;
+ }
+
+ int rsize = (data.length & MASK_CLEAR_LSB);
+ for (int i = 0; i < rsize; i += CKSUM_BYTES) {
+ int v = ((data[i] & MiscUtils.MASK_BYTE) << Byte.SIZE) |
+ (data[i + 1] & MiscUtils.MASK_BYTE);
+ sum += v;
+ }
+ if (rsize < data.length) {
+ // Zero padding is needed.
+ int v = (data[rsize] & MiscUtils.MASK_BYTE) << Byte.SIZE;
+ sum += v;
+ }
+
+ int carry = (sum >>> Short.SIZE);
+ return (sum & MiscUtils.MASK_SHORT) + carry;
+ }
+
+ /**
+ * Compute the checksum of the given packet.
+ *
+ * @param ipv4 An {@link Inet4Packet} instance that contains the given
+ * packet.
+ * @param packet A {@link Packet} instance.
+ * @param sumOff Offset in bytes to the checksum field.
+ * @return A computed checksum.
+ * @throws VTNException
+ * An error occurred.
+ */
+ protected static final short computeChecksum(Inet4Packet ipv4,
+ Packet packet, int sumOff)
+ throws VTNException {
+ // Serialize the given packet.
+ byte[] data;
+ try {
+ data = packet.serialize();
+ } catch (Exception e) {
+ // This should never happen.
+ throw new VTNException("Failed to serialize the packet.", e);
+ }
+
+ // Clear checksum field.
+ MiscUtils.setShort(data, sumOff, (short)0);
+
+ // Compute checksum.
+ int sum = computeChecksum(ipv4, data);
+ return (short)~sum;
+ }
+
+ /**
+ * Verify the packet using the checksum.
+ *
+ * @param ipv4 An {@link Inet4Packet} instance that contains the given
+ * packet.
+ * @param packet A {@link Packet} to be verified.
+ * @return {@code true} is returned only if the verification succeeded.
+ * @throws VTNException
+ * An error occurred.
+ */
+ protected static final boolean verifyChecksum(Inet4Packet ipv4,
+ Packet packet)
+ throws VTNException {
+ // Serialize the given packet.
+ byte[] data;
+ try {
+ data = packet.serialize();
+ } catch (Exception e) {
+ // This should never happen.
+ throw new VTNException("Failed to serialize the packet.", e);
+ }
+
+ // Compute checksum.
+ int sum = computeChecksum(ipv4, data);
+ return (sum == CKSUM_OK);
+ }
/**
* Construct a new instance.
@@ -49,12 +289,24 @@ public abstract class PortProtoPacket implements CachedPacket {
* @return An integer value which represents the source port number.
*/
public final int getSourcePort() {
- if (sourcePort == PORT_NONE) {
- short port = getRawSourcePort();
- sourcePort = NetUtils.getUnsignedShort(port);
+ Values v = getValues();
+ int port = v.getSourcePort();
+ if (port == PORT_NONE) {
+ short p = getRawSourcePort();
+ port = v.setSourcePort(p);
}
- return sourcePort;
+ return port;
+ }
+
+ /**
+ * Set the source port number.
+ *
+ * @param port An integer value which indicates the source port.
+ */
+ public final void setSourcePort(int port) {
+ Values v = getModifiedValues();
+ v.setSourcePort(port);
}
/**
@@ -63,12 +315,37 @@ public abstract class PortProtoPacket implements CachedPacket {
* @return An integer value which represents the destination port number.
*/
public final int getDestinationPort() {
- if (destinationPort == PORT_NONE) {
- short port = getRawDestinationPort();
- destinationPort = NetUtils.getUnsignedShort(port);
+ Values v = getValues();
+ int port = v.getDestinationPort();
+ if (port == PORT_NONE) {
+ short p = getRawDestinationPort();
+ port = v.setDestinationPort(p);
}
- return destinationPort;
+ return port;
+ }
+
+ /**
+ * Set the destination port number.
+ *
+ * @param port An integer value which indicates the destination port.
+ */
+ public final void setDestinationPort(int port) {
+ Values v = getModifiedValues();
+ v.setDestinationPort(port);
+ }
+
+ /**
+ * Return a {@link Packet} instance to set modified values.
+ *
+ * @return A {@link Packet} instance.
+ * @throws VTNException
+ * Failed to copy the packet.
+ */
+ protected final T getPacketForWrite() throws VTNException {
+ T pkt = getPacketForWrite(cloned);
+ cloned = false;
+ return pkt;
}
/**
@@ -76,7 +353,7 @@ public abstract class PortProtoPacket implements CachedPacket {
*
* @return A short integer value which represents the source port number.
*/
- public abstract short getRawSourcePort();
+ protected abstract short getRawSourcePort();
/**
* Derive the destination port number from the packet.
@@ -84,29 +361,89 @@ public abstract class PortProtoPacket implements CachedPacket {
* @return A short integer value which represents the destination port
* number.
*/
- public abstract short getRawDestinationPort();
+ protected abstract short getRawDestinationPort();
+
+ /**
+ * Set the source port number to the given packet.
+ *
+ * @param pkt A {@link Packet} instance.
+ * @param port A short integer value which indicates the source port.
+ */
+ protected abstract void setRawSourcePort(T pkt, short port);
+
+ /**
+ * Set the destination port number to the given packet.
+ *
+ * @param pkt A {@link Packet} instance.
+ * @param port A short integer value which indicates the destination port.
+ */
+ protected abstract void setRawDestinationPort(T pkt, short port);
+
+ /**
+ * Return a {@link Packet} instance to set modified values.
+ *
+ * @param doCopy {@code true} is passed if the packet configured in this
+ * instance needs to be copied.
+ * @return A {@link Packet} instance.
+ * @throws VTNException
+ * Failed to copy the packet.
+ */
+ protected abstract T getPacketForWrite(boolean doCopy) throws VTNException;
+
+ /**
+ * Return a {@link Values} instance that keeps current values for
+ * protocol header fields.
+ *
+ * @return A {@link Values} instance.
+ */
+ private Values getValues() {
+ return (modifiedValues == null) ? values : modifiedValues;
+ }
+
+ /**
+ * Return a {@link Values} instance that keeps protocol header field values
+ * to be set.
+ *
+ * @return A {@link Values} instance.
+ */
+ private Values getModifiedValues() {
+ if (modifiedValues == null) {
+ values.fill(this);
+ modifiedValues = values.clone();
+ }
+
+ return modifiedValues;
+ }
// CachedPacket
/**
* Configure match fields to test TCP/UDP header in this packet.
*
+ *
+ * Note that this method creates match fields that matches the original
+ * packet. Any modification to the packet is ignored.
+ *
+ *
* @param match A {@link Match} instance.
* @param fields A set of {@link MatchType} instances corresponding to
* match fields to be tested.
*/
@Override
public final void setMatch(Match match, Set fields) {
+ Values v = values;
+ v.fill(this);
+
MatchType type = MatchType.TP_SRC;
if (fields.contains(type)) {
// Test source port number.
- match.setField(type, (short)getSourcePort());
+ match.setField(type, (short)v.getSourcePort());
}
type = MatchType.TP_DST;
if (fields.contains(type)) {
// Test destination port number.
- match.setField(type, (short)getDestinationPort());
+ match.setField(type, (short)v.getDestinationPort());
}
}
@@ -114,9 +451,45 @@ public abstract class PortProtoPacket implements CachedPacket {
* {@inheritDoc}
*/
@Override
- public final boolean commit(PacketContext pctx) {
- // REVISIT: Not yet supported.
- return false;
+ public final boolean commit(PacketContext pctx) throws VTNException {
+ boolean mod = false;
+ T pkt = null;
+ if (modifiedValues != null) {
+ // At least one flow action that modifies TCP or UDP header is
+ // configured.
+ pctx.addMatchField(MatchType.DL_TYPE);
+ pctx.addMatchField(MatchType.NW_PROTO);
+
+ int src = modifiedValues.getSourcePort();
+ if (values.getSourcePort() != src) {
+ // Source port was modified.
+ pkt = getPacketForWrite();
+ setRawSourcePort(pkt, (short)src);
+ mod = true;
+ } else if (pctx.hasMatchField(MatchType.TP_SRC)) {
+ // Source port in the original packet is unchanged and it will
+ // be specified in flow match. So we don't need to configure
+ // SET_TP_SRC action.
+ pctx.removeFilterAction(SetTpSrc.class);
+ }
+
+ int dst = modifiedValues.getDestinationPort();
+ if (values.getDestinationPort() != dst) {
+ // Destination port was modified.
+ if (pkt == null) {
+ pkt = getPacketForWrite();
+ }
+ setRawDestinationPort(pkt, (short)dst);
+ mod = true;
+ } else if (pctx.hasMatchField(MatchType.TP_DST)) {
+ // Destination port in the original packet is unchanged and
+ // it will be specified in flow match. So we don't need to
+ // configure SET_TP_DST action.
+ pctx.removeFilterAction(SetTpDst.class);
+ }
+ }
+
+ return mod;
}
/**
@@ -125,7 +498,17 @@ public abstract class PortProtoPacket implements CachedPacket {
@Override
public final PortProtoPacket clone() {
try {
- return (PortProtoPacket)super.clone();
+ PortProtoPacket p = (PortProtoPacket)super.clone();
+ Values v = p.values;
+ p.values = v.clone();
+
+ v = p.modifiedValues;
+ if (v != null) {
+ p.modifiedValues = v.clone();
+ }
+ p.cloned = true;
+
+ return p;
} catch (CloneNotSupportedException e) {
// This should never happen.
throw new IllegalStateException("clone() failed", e);
diff --git a/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/packet/TcpPacket.java b/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/packet/TcpPacket.java
index ad8ff341..5cb6ca86 100644
--- a/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/packet/TcpPacket.java
+++ b/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/packet/TcpPacket.java
@@ -9,16 +9,25 @@
package org.opendaylight.vtn.manager.internal.packet;
+import org.opendaylight.vtn.manager.VTNException;
+
+import org.opendaylight.vtn.manager.internal.MiscUtils;
+
import org.opendaylight.controller.sal.packet.TCP;
/**
* {@code TcpPacket} class implements a cache for a {@link TCP} instance.
*/
-public final class TcpPacket extends PortProtoPacket {
+public final class TcpPacket extends PortProtoPacket {
+ /**
+ * Byte offset to the checksum field in TCP header.
+ */
+ private static final int TCP_OFF_CHECKSUM = 16;
+
/**
* A {@link TCP} packet.
*/
- private final TCP packet;
+ private TCP packet;
/**
* Construct a new instance.
@@ -29,13 +38,15 @@ public final class TcpPacket extends PortProtoPacket {
packet = tcp;
}
+ // PortProtoPacket
+
/**
* Derive the source port number from the packet.
*
* @return A short integer value which represents the source port number.
*/
@Override
- public short getRawSourcePort() {
+ protected short getRawSourcePort() {
return packet.getSourcePort();
}
@@ -46,10 +57,75 @@ public final class TcpPacket extends PortProtoPacket {
* number.
*/
@Override
- public short getRawDestinationPort() {
+ protected short getRawDestinationPort() {
return packet.getDestinationPort();
}
+ /**
+ * Set the source port number to the given packet.
+ *
+ * @param pkt A {@link TCP} instance.
+ * @param port A short integer value which indicates the source port.
+ */
+ @Override
+ protected void setRawSourcePort(TCP pkt, short port) {
+ pkt.setSourcePort(port);
+ }
+
+ /**
+ * Set the destination port number to the given packet.
+ *
+ * @param pkt A {@link TCP} instance.
+ * @param port A short integer value which indicates the destination port.
+ */
+ @Override
+ protected void setRawDestinationPort(TCP pkt, short port) {
+ pkt.setDestinationPort(port);
+ }
+
+ /**
+ * Return a {@link TCP} instance to set modified values.
+ *
+ * @param doCopy {@code true} is passed if the packet configured in this
+ * instance needs to be copied.
+ * @return A {@link TCP} instance.
+ * @throws VTNException
+ * Failed to copy the packet.
+ */
+ @Override
+ protected TCP getPacketForWrite(boolean doCopy) throws VTNException {
+ TCP pkt;
+ if (doCopy) {
+ pkt = MiscUtils.copy(packet, new TCP());
+ packet = pkt;
+ } else {
+ pkt = packet;
+ }
+
+ return pkt;
+ }
+
+ // L4Packet
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public boolean updateChecksum(Inet4Packet ipv4) throws VTNException {
+ short sum = packet.getChecksum();
+ TCP pkt = getPacketForWrite();
+ short newSum = computeChecksum(ipv4, pkt, TCP_OFF_CHECKSUM);
+ boolean mod;
+ if (sum != newSum) {
+ pkt.setChecksum(newSum);
+ mod = true;
+ } else {
+ mod = false;
+ }
+
+ return mod;
+ }
+
// CachedPacket
/**
diff --git a/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/packet/UdpPacket.java b/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/packet/UdpPacket.java
index b35adcb3..624a7395 100644
--- a/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/packet/UdpPacket.java
+++ b/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/packet/UdpPacket.java
@@ -9,16 +9,30 @@
package org.opendaylight.vtn.manager.internal.packet;
+import org.opendaylight.vtn.manager.VTNException;
+
+import org.opendaylight.vtn.manager.internal.MiscUtils;
+
import org.opendaylight.controller.sal.packet.UDP;
/**
* {@code UdpPacket} class implements a cache for a {@link UDP} instance.
*/
-public final class UdpPacket extends PortProtoPacket {
+public final class UdpPacket extends PortProtoPacket {
+ /**
+ * Byte offset to the checksum field in UDP header.
+ */
+ private static final int UDP_OFF_CHECKSUM = 6;
+
+ /**
+ * Checksum value which indicates the checksum is disabled.
+ */
+ private static final short UDP_CKSUM_DISABLED = 0;
+
/**
* A {@link UDP} packet.
*/
- private final UDP packet;
+ private UDP packet;
/**
* Construct a new instance.
@@ -35,7 +49,7 @@ public final class UdpPacket extends PortProtoPacket {
* @return A short integer value which represents the source port number.
*/
@Override
- public short getRawSourcePort() {
+ protected short getRawSourcePort() {
return packet.getSourcePort();
}
@@ -46,10 +60,80 @@ public final class UdpPacket extends PortProtoPacket {
* number.
*/
@Override
- public short getRawDestinationPort() {
+ protected short getRawDestinationPort() {
return packet.getDestinationPort();
}
+ /**
+ * Set the source port number to the given packet.
+ *
+ * @param pkt A {@link UDP} instance.
+ * @param port A short integer value which indicates the source port.
+ */
+ @Override
+ protected void setRawSourcePort(UDP pkt, short port) {
+ pkt.setSourcePort(port);
+ }
+
+ /**
+ * Set the destination port number to the given packet.
+ *
+ * @param pkt A {@link UDP} instance.
+ * @param port A short integer value which indicates the destination port.
+ */
+ @Override
+ protected void setRawDestinationPort(UDP pkt, short port) {
+ pkt.setDestinationPort(port);
+ }
+
+ /**
+ * Return a {@link UDP} instance to set modified values.
+ *
+ * @param doCopy {@code true} is passed if the packet configured in this
+ * instance needs to be copied.
+ * @return A {@link UDP} instance.
+ * @throws VTNException
+ * Failed to copy the packet.
+ */
+ @Override
+ protected UDP getPacketForWrite(boolean doCopy) throws VTNException {
+ UDP pkt;
+ if (doCopy) {
+ pkt = MiscUtils.copy(packet, new UDP());
+ packet = pkt;
+ } else {
+ pkt = packet;
+ }
+
+ return pkt;
+ }
+
+ // L4Packet
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public boolean updateChecksum(Inet4Packet ipv4) throws VTNException {
+ // Update checksum only if the UDP packet contains a valid checksum.
+ boolean mod = false;
+ short sum = packet.getChecksum();
+ if (sum != 0) {
+ UDP pkt = getPacketForWrite();
+ short newSum = computeChecksum(ipv4, pkt, UDP_OFF_CHECKSUM);
+ if (newSum == UDP_CKSUM_DISABLED) {
+ // Set all bits in the checksum field instead of zero.
+ newSum = (short)~newSum;
+ }
+ if (sum != newSum) {
+ pkt.setChecksum(newSum);
+ mod = true;
+ }
+ }
+
+ return mod;
+ }
+
// CachedPacket
/**
diff --git a/manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/ArpHandlerTest.java b/manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/ArpHandlerTest.java
index ce27dba8..d9e3bdcb 100644
--- a/manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/ArpHandlerTest.java
+++ b/manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/ArpHandlerTest.java
@@ -219,9 +219,8 @@ public class ArpHandlerTest extends VTNManagerImplTestCommon {
swMgr.addSubnet(sconf);
// in case VLAN ID doesn't match.
- InetAddress ia
- = getInetAddressFromAddress(new byte[] {(byte)192, (byte)168,
- (byte)0, (byte)254});
+ InetAddress ia = createInetAddress(
+ new byte[] {(byte)192, (byte)168, (byte)0, (byte)254});
Subnet sub = swMgr.getSubnetByNetworkAddress(ia);
sub.setVlan((short)2);
@@ -233,7 +232,7 @@ public class ArpHandlerTest extends VTNManagerImplTestCommon {
assertEquals(PacketResult.IGNORED, result);
assertEquals(0, dataList.size());
- ia = getInetAddressFromAddress(HOST_IP);
+ ia = createInetAddress(HOST_IP);
sub = swMgr.getSubnetByNetworkAddress(ia);
sub.setVlan((short)0);
for (Node node : existNodes) {
@@ -484,7 +483,7 @@ public class ArpHandlerTest extends VTNManagerImplTestCommon {
unexpected(e);
}
- InetAddress ia = getInetAddressFromAddress(
+ InetAddress ia = createInetAddress(
new byte[] {(byte)10, (byte)0, (byte)0, (byte)1});
byte [] mac = new byte [] {0x00, 0x00, 0x00, 0x11, 0x22, 0x33};
diff --git a/manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/GlobalResourceManagerTest.java b/manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/GlobalResourceManagerTest.java
index 9542743d..0c948bdb 100644
--- a/manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/GlobalResourceManagerTest.java
+++ b/manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/GlobalResourceManagerTest.java
@@ -2341,7 +2341,7 @@ public class GlobalResourceManagerTest extends TestBase {
@Test
public void testGetRemoteClusterSize() {
InetAddress loopbackAddr = InetAddress.getLoopbackAddress();
- InetAddress otherAddr = getInetAddressFromAddress(
+ InetAddress otherAddr = createInetAddress(
new byte[] {(byte)10, (byte)0, (byte)1, (byte)99});
ComponentImpl c = new ComponentImpl(null, null, null);
@@ -2446,16 +2446,15 @@ public class GlobalResourceManagerTest extends TestBase {
List entries = getMacEntries(vtnMgr, bpath);
assertEquals(0, entries.size());
- InetAddress ipaddr
- = getInetAddressFromAddress(new byte[] {(byte)192, (byte)168,
- (byte)0, (byte)2});
+ InetAddress ipaddr = createInetAddress(
+ new byte[] {(byte)192, (byte)168, (byte)0, (byte)2});
mac = 2L;
MacTableEntryId eidRemote = new MacTableEntryId(ipaddr, 2L, bpath, mac);
MacTableEntry entRemote = new MacTableEntry(eidRemote, nc, (short)0,
ipaddr);
- ipaddr = getInetAddressFromAddress(new byte[] {(byte)192, (byte)168,
- (byte)0, (byte)3});
+ ipaddr = createInetAddress(
+ new byte[] {(byte)192, (byte)168, (byte)0, (byte)3});
mac = 3L;
MacTableEntryId eidRemote2 = new MacTableEntryId(ipaddr, 3L, bpath,
mac);
diff --git a/manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/MacAddressTableTest.java b/manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/MacAddressTableTest.java
index 7d1bcfd9..aaa9b337 100644
--- a/manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/MacAddressTableTest.java
+++ b/manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/MacAddressTableTest.java
@@ -171,8 +171,8 @@ public class MacAddressTableTest extends TestUseVTNManagerBase {
PacketContext ncpctx = createARPPacketContext(src, dst, sender, target,
(short)-1, connectors.get(1), ARP.REQUEST);
- InetAddress ia = getInetAddressFromAddress(sender);
- InetAddress ia2 = getInetAddressFromAddress(sender2);
+ InetAddress ia = createInetAddress(sender);
+ InetAddress ia2 = createInetAddress(sender2);
Set ipSet = new HashSet();
// get from empty table.
@@ -321,7 +321,7 @@ public class MacAddressTableTest extends TestUseVTNManagerBase {
ARP.REQUEST);
bnode.setPath(ipath1);
tbl.add(pctx, bnode);
- InetAddress ipaddr = getInetAddressFromAddress(sender);
+ InetAddress ipaddr = createInetAddress(sender);
long key = 1000L;
tent = new MacTableEntry(path1, key, connectors.get(0), (short)0,
@@ -439,7 +439,7 @@ public class MacAddressTableTest extends TestUseVTNManagerBase {
(byte)0x00, (byte)0x00, (byte)0x01};
byte [] target = new byte[] {(byte)192, (byte)168, (byte)0, (byte)250};
byte [] sender = new byte[] {(byte)192, (byte)168, (byte)0, (byte)1};
- InetAddress ia = getInetAddressFromAddress(sender);
+ InetAddress ia = createInetAddress(sender);
Set ipSet = new HashSet();
Node node = NodeCreator.createOFNode(Long.valueOf(0L));
@@ -476,7 +476,7 @@ public class MacAddressTableTest extends TestUseVTNManagerBase {
// change IP Address
sender = new byte[] {(byte)192, (byte)168, (byte)0, (byte)2};
- ia = getInetAddressFromAddress(sender);
+ ia = createInetAddress(sender);
pctx = createARPPacketContext(src, dst, sender, target,
vlan, nc, ARP.REQUEST);
tbl.add(pctx, bnode);
@@ -584,12 +584,10 @@ public class MacAddressTableTest extends TestUseVTNManagerBase {
tbl1, tbl2, tbl3, tbl4, tbl5, tbl6, tbl7,
};
- InetAddress contIpAddr1 =
- getInetAddressFromAddress(new byte[] {(byte)192, (byte)168,
- (byte)100, (byte)254});
- InetAddress contIpAddr2 =
- getInetAddressFromAddress(new byte[] {(byte)192, (byte)168,
- (byte)100, (byte)253});
+ InetAddress contIpAddr1 = createInetAddress(
+ new byte[] {(byte)192, (byte)168, (byte)100, (byte)254});
+ InetAddress contIpAddr2 = createInetAddress(
+ new byte[] {(byte)192, (byte)168, (byte)100, (byte)253});
List connectors = createNodeConnectors(3, false);
short vlan = 0;
@@ -617,7 +615,7 @@ public class MacAddressTableTest extends TestUseVTNManagerBase {
tblArray[i].add(pctx, bnode);
}
- InetAddress ipaddr = getInetAddressFromAddress(sender);
+ InetAddress ipaddr = createInetAddress(sender);
MacTableEntryId mentid = new MacTableEntryId(
((id % 2) == 0) ? contIpAddr1 : contIpAddr2,
(long)id, path7, NetUtils.byteArray6ToLong(src));
@@ -742,7 +740,7 @@ public class MacAddressTableTest extends TestUseVTNManagerBase {
VlanMapPath vpath = new VlanMapPath(path, ifName);
MacAddressTable tbl = new MacAddressTable(mgr, path, 600);
- InetAddress contIpAddr = getInetAddressFromAddress(
+ InetAddress contIpAddr = createInetAddress(
new byte[] {(byte)192, (byte)168, (byte)100, (byte)254});
List connectors = createNodeConnectors(3, false);
@@ -756,11 +754,11 @@ public class MacAddressTableTest extends TestUseVTNManagerBase {
(byte)100, (byte)iphost};
long key = NetUtils.byteArray6ToLong(src);
- InetAddress ipaddr = getInetAddressFromAddress(sender);
+ InetAddress ipaddr = createInetAddress(sender);
MacTableEntry tent = new MacTableEntry(
ipath, key, connectors.get(iphost % 3),
(short)(((vlan / 3) > 0) ? (vlan / 3) : -1), ipaddr);
- InetAddress ipaddr2 = getInetAddressFromAddress(sender);
+ InetAddress ipaddr2 = createInetAddress(sender);
MacTableEntry tent2 = new MacTableEntry(
ipath, key, connectors.get(iphost % 3),
(short)(((vlan / 3) > 0) ? (vlan / 3) : -1), ipaddr2);
@@ -877,11 +875,9 @@ public class MacAddressTableTest extends TestUseVTNManagerBase {
// create MacTableEntry added by remote node.
short vlanRemote = 0;
- InetAddress ipRemoteNode
- = getInetAddressFromAddress(new byte[] {0, 0, 0, 0});
- InetAddress ipRemoteEnt
- = getInetAddressFromAddress(new byte[] {(byte)192, (byte)168,
- (byte)100, (byte)1});
+ InetAddress ipRemoteNode = createInetAddress(new byte[] {0, 0, 0, 0});
+ InetAddress ipRemoteEnt = createInetAddress(
+ new byte[] {(byte)192, (byte)168, (byte)100, (byte)1});
long macKey = 99L;
MacTableEntryId evidRemote = new MacTableEntryId(ipRemoteNode, 0L,
path, macKey);
diff --git a/manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/MiscUtilsTest.java b/manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/MiscUtilsTest.java
new file mode 100644
index 00000000..433fce79
--- /dev/null
+++ b/manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/MiscUtilsTest.java
@@ -0,0 +1,846 @@
+/*
+ * Copyright (c) 2014 NEC Corporation
+ * All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this
+ * distribution, and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.vtn.manager.internal;
+
+import java.net.InetAddress;
+import java.net.Inet4Address;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Random;
+
+import org.junit.Test;
+
+import org.opendaylight.vtn.manager.VTNException;
+
+import org.opendaylight.controller.sal.match.MatchType;
+import org.opendaylight.controller.sal.packet.Ethernet;
+import org.opendaylight.controller.sal.packet.ICMP;
+import org.opendaylight.controller.sal.packet.IEEE8021Q;
+import org.opendaylight.controller.sal.packet.IPv4;
+import org.opendaylight.controller.sal.packet.Packet;
+import org.opendaylight.controller.sal.packet.TCP;
+import org.opendaylight.controller.sal.packet.UDP;
+import org.opendaylight.controller.sal.utils.EtherTypes;
+import org.opendaylight.controller.sal.utils.IPProtocols;
+import org.opendaylight.controller.sal.utils.Status;
+import org.opendaylight.controller.sal.utils.StatusCode;
+
+/**
+ * JUnit test for {@link MiscUtils}
+ */
+public class MiscUtilsTest extends TestBase {
+ /**
+ * Verify static constants.
+ */
+ @Test
+ public void testConstants() {
+ assertEquals(0xff, MiscUtils.MASK_BYTE);
+ assertEquals(0xffff, MiscUtils.MASK_SHORT);
+ }
+
+ /**
+ * Test case for {@link MiscUtils#hashCode(long)}.
+ */
+ @Test
+ public void testHashCode() {
+ Random rand = new Random();
+ for (int i = 0; i < 50; i++) {
+ int hi = rand.nextInt();
+ int lo = rand.nextInt();
+ long l = ((long)hi << Integer.SIZE) | (long)(lo & 0xffffffffL);
+ assertEquals(hi ^ lo, MiscUtils.hashCode(l));
+ }
+ }
+
+ /**
+ * Test case for {@link MiscUtils#formatMacAddress(long mac)}.
+ */
+ @Test
+ public void testFormatMacAddress() {
+ assertEquals("00:00:00:00:00:00", MiscUtils.formatMacAddress(0L));
+ assertEquals("00:00:00:00:00:01", MiscUtils.formatMacAddress(1L));
+ assertEquals("00:00:00:00:00:ff", MiscUtils.formatMacAddress(0xffL));
+ assertEquals("00:00:00:00:a0:ff", MiscUtils.formatMacAddress(0xa0ffL));
+ assertEquals("00:00:00:12:34:56",
+ MiscUtils.formatMacAddress(0x123456L));
+ assertEquals("aa:bb:cc:dd:ee:ff",
+ MiscUtils.formatMacAddress(0xaabbccddeeffL));
+ }
+
+ /**
+ * Test case for {@link MiscUtils#checkName(String, String)}.
+ */
+ @Test
+ public void testCheckName() {
+ String[] descriptions = {"desc-1", "desc-2", "desc-3"};
+
+ String[] good = {
+ "a",
+ "1",
+ "12",
+ "name",
+ "NaMe_",
+ "GooD_NamE1",
+ "1234567890123456789012345678901",
+ };
+
+ Map badRequests = new HashMap();
+ badRequests.put(null, "%s name cannot be null");
+ badRequests.put("", "%s name cannot be empty");
+ badRequests.put("12345678901234567890123456789012",
+ "%s name is too long");
+ badRequests.put("_name", "%s name contains invalid character");
+
+ List badCharacters = new ArrayList();
+ for (char c = 0; c < 0x80; c++) {
+ if (c == '_') {
+ continue;
+ }
+
+ int type = Character.getType(c);
+ if (type != Character.DECIMAL_DIGIT_NUMBER &&
+ type != Character.UPPERCASE_LETTER &&
+ type != Character.LOWERCASE_LETTER) {
+ badCharacters.add(c);
+ }
+ }
+
+ // Unicode fullwidth digit zero.
+ badCharacters.add((char)0xff10);
+
+ // Unicode hiragana letter A.
+ badCharacters.add((char)0x3042);
+
+ List badNames = new ArrayList();
+ for (char bad: badCharacters) {
+ StringBuilder builder = new StringBuilder();
+ badNames.add(builder.append(bad).append("name").toString());
+
+ builder = new StringBuilder("na");
+ badNames.add(builder.append(bad).append("me").toString());
+
+ builder = new StringBuilder("name");
+ badNames.add(builder.append(bad).toString());
+ }
+
+ for (String desc: descriptions) {
+ for (String name: good) {
+ try {
+ MiscUtils.checkName(desc, name);
+ } catch (Exception e) {
+ unexpected(e);
+ }
+ }
+
+ for (Map.Entry entry: badRequests.entrySet()) {
+ String name = entry.getKey();
+ String msg = String.format(entry.getValue(), desc);
+
+ try {
+ MiscUtils.checkName(desc, name);
+ unexpected();
+ } catch (VTNException e) {
+ checkException(e, msg);
+ }
+ }
+
+ String msg = desc + " name contains invalid character";
+ for (String name: badNames) {
+ try {
+ MiscUtils.checkName(desc, name);
+ unexpected();
+ } catch (VTNException e) {
+ checkException(e, msg);
+ }
+ }
+ }
+ }
+
+ /**
+ * Test case for {@link MiscUtils#checkVlan(short)}.
+ */
+ @Test
+ public void testCheckVlan() {
+ for (short vid = 0; vid <= 4095; vid++) {
+ try {
+ MiscUtils.checkVlan(vid);
+ } catch (Exception e) {
+ unexpected(e);
+ }
+ }
+
+ short[] badVids = {
+ Short.MIN_VALUE, -30000, -20000, -10000, -5000, -100, -23, -2, -1,
+ 4096, 4097, 6000, 8000, 10000, 15000, 20000, 30000, 32000,
+ Short.MAX_VALUE,
+ };
+ for (short vid: badVids) {
+ try {
+ MiscUtils.checkVlan(vid);
+ unexpected();
+ } catch (VTNException e) {
+ checkException(e, "Invalid VLAN ID: " + vid);
+ }
+ }
+ }
+
+ /**
+ * Test case for {@link MiscUtils#isVlanPriorityValid(byte)}.
+ */
+ @Test
+ public void testIsVlanPriorityValid() {
+ for (int i = 0; i <= 0xff; i++) {
+ byte pri = (byte)i;
+ assertEquals(pri >= 0 && pri <= 7,
+ MiscUtils.isVlanPriorityValid(pri));
+ }
+ }
+
+ /**
+ * Test case for {@link MiscUtils#isDscpValid(byte)}.
+ */
+ @Test
+ public void testIsDscpValid() {
+ for (int i = 0; i <= 0xff; i++) {
+ byte dscp = (byte)i;
+ assertEquals(dscp >= 0 && dscp <= 63, MiscUtils.isDscpValid(dscp));
+ }
+ }
+
+ /**
+ * Test case for {@link MiscUtils#isIcmpValueValid(short)}.
+ */
+ @Test
+ public void testIsIcmpValueValid() {
+ for (short v = 0; v <= 0xff; v++) {
+ assertTrue(MiscUtils.isIcmpValueValid(v));
+ }
+
+ short[] badValues = {
+ Short.MIN_VALUE, -30000, -20000, -10000, -5000, -100, -14, -2, -1,
+ 256, 257, 300, 2000, 8000, 12000, 28000, 30000, Short.MAX_VALUE,
+ };
+ for (short v: badValues) {
+ assertFalse(MiscUtils.isIcmpValueValid(v));
+ }
+ }
+
+ /**
+ * Test case for {@link MiscUtils#isPortNumberValid(int)}.
+ */
+ @Test
+ public void testIsPortNumberValid() {
+ int[] validPorts = {
+ 0, 1, 44, 555, 1000, 4000, 10000, 13000, 20000, 30000, 40000,
+ 50000, 65000, 65534, 65535,
+ };
+ for (int port: validPorts) {
+ assertTrue(MiscUtils.isPortNumberValid(port));
+ }
+
+ int[] badValues = {
+ Integer.MIN_VALUE, (int)0xfff00000, (int)0xf0000000, -10000,
+ -100, -3, -2, -1,
+ 0x10000, 0x10001, 0x11000, 0x100000, 0x333333,
+ 0x444444, 0x500000, 0x1000000, 0xa000000, 0x10000000,
+ 0x50000000, 0x7f000000, Integer.MAX_VALUE,
+ };
+ for (int port: badValues) {
+ assertFalse(MiscUtils.isPortNumberValid(port));
+ }
+ }
+
+ /**
+ * Test case for {@link MiscUtils#argumentIsNull(String)}.
+ */
+ @Test
+ public void testArgumentIsNull() {
+ String[] descriptions = {"desc-1", "desc-2", "desc-3"};
+ for (String desc: descriptions) {
+ Status st = MiscUtils.argumentIsNull(desc);
+ checkStatus(st, desc + " cannot be null");
+ }
+ }
+
+ /**
+ * Test case for {@link MiscUtils#toInetAddress(int)} and
+ * {@link MiscUtils#toInteger(InetAddress)}.
+ */
+ @Test
+ public void testToInetAddress() {
+ Random rand = new Random();
+ for (int i = 0; i < 100; i++) {
+ int v = rand.nextInt();
+ InetAddress iaddr = MiscUtils.toInetAddress(v);
+ assertTrue(iaddr instanceof Inet4Address);
+
+ byte[] raw = iaddr.getAddress();
+ assertEquals(4, raw.length);
+ for (int j = 0; j < raw.length; j++) {
+ byte b = (byte)(v >>> ((3 - j) * Byte.SIZE));
+ assertEquals(b, raw[j]);
+ }
+
+ assertEquals(v, MiscUtils.toInteger(iaddr));
+ }
+
+ List invalid = new ArrayList();
+ invalid.add(null);
+ try {
+ invalid.add(InetAddress.getByName("::1"));
+ } catch (Exception e) {
+ unexpected(e);
+ }
+
+ for (InetAddress iaddr: invalid) {
+ try {
+ MiscUtils.toInteger(iaddr);
+ unexpected();
+ } catch (IllegalStateException e) {
+ }
+ }
+ }
+
+ /**
+ * Test case for {@link MiscUtils#copy(Packet, Packet)}.
+ *
+ * @throws Exception An error occurred.
+ */
+ @Test
+ public void testCopyPacket() throws Exception {
+ // Specifying null.
+ try {
+ MiscUtils.copy((Packet)null, (Packet)null);
+ unexpected();
+ } catch (VTNException e) {
+ checkException(e, "Failed to copy the packet.",
+ StatusCode.INTERNALERROR);
+ assertTrue(e.getCause() instanceof NullPointerException);
+ }
+
+ byte[] raw = {
+ (byte)0x7c, (byte)0xe8, (byte)0x07, (byte)0xde,
+ (byte)0xc5, (byte)0x1b, (byte)0x40, (byte)0x86,
+ (byte)0xc0, (byte)0xa1, (byte)0xe3, (byte)0xe0,
+ (byte)0x90, (byte)0xdd, (byte)0x0c, (byte)0xe6,
+ };
+
+ // Ensure that Ethernet instance with raw payload can be copied.
+ byte[] srcMac = {
+ (byte)0x00, (byte)0x11, (byte)0x22,
+ (byte)0x33, (byte)0x44, (byte)0x55,
+ };
+ byte[] dstMac = {
+ (byte)0xf0, (byte)0xfa, (byte)0xfb,
+ (byte)0xfc, (byte)0xfd, (byte)0xfe,
+ };
+ short etype = 0xa00;
+ short vid = MatchType.DL_VLAN_NONE;
+ byte pcp = 1;
+ for (int loop = 0; loop < 5; loop++) {
+ Ethernet org = createEthernet(srcMac, dstMac, etype, vid, pcp, raw);
+ Ethernet copy = new Ethernet();
+ assertSame(copy, MiscUtils.copy(org, copy));
+ checkCopy(org, copy, srcMac, dstMac, etype, vid, pcp, raw);
+ etype++;
+ vid++;
+ srcMac[3]++;
+ dstMac[4]++;
+ }
+
+ // Ensure that IPv4 instance with raw payload can be copied.
+ int srcIp = (int)0x0a010203;
+ int dstIp = (int)0xc0a864c8;
+ short ipproto = 30;
+ byte dscp = 0;
+ for (int loop = 0; loop < 5; loop++) {
+ IPv4 org = createIPv4(srcIp, dstIp, ipproto, dscp);
+ org.setRawPayload(raw);
+
+ // Copy the original in order to fix up header fields, such as
+ // checksum.
+ org = MiscUtils.copy(org, new IPv4());
+
+ IPv4 copy = new IPv4();
+ assertSame(copy, MiscUtils.copy(org, copy));
+ checkCopy(org, copy, srcIp, dstIp, ipproto, dscp, raw);
+ srcIp++;
+ dstIp++;
+ ipproto++;
+ dscp++;
+ }
+
+ // Ensure that TCP instance with raw payload can be copied.
+ int seq = 0x3333;
+ int ack = 0x4567;
+ byte dataOff = 0;
+ byte resv = 0;
+ short win = (short)0xfc00;
+ short urp = (short)0x5678;
+ short cksum = (short)0x1234;
+ short flags = 0x18;
+ short srcPort = 17;
+ short dstPort = 30000;
+ for (int loop = 0; loop < 5; loop++) {
+ TCP org = new TCP();
+ org.setSourcePort(srcPort).setDestinationPort(dstPort).
+ setSequenceNumber(seq).setAckNumber(ack).
+ setDataOffset(dataOff).setHeaderLenFlags(flags).
+ setReserved(resv).setWindowSize(win).setChecksum(cksum).
+ setUrgentPointer(urp).setRawPayload(raw);
+ TCP copy = new TCP();
+ assertSame(copy, MiscUtils.copy(org, copy));
+ checkCopy(org, copy, srcPort, dstPort, cksum, raw);
+
+ seq++;
+ ack++;
+ dataOff = (byte)((dataOff + 1) & 0xf);
+ cksum += 7;
+ srcPort++;
+ dstPort++;
+ }
+
+ // Ensure that UDP instance with raw payload can be copied.
+ srcPort = (short)45678;
+ dstPort = 133;
+ cksum = (short)0xf1a0;
+ short udpLen = (short)(raw.length + 8);
+ for (int loop = 0; loop < 5; loop++) {
+ UDP org = new UDP();
+ org.setSourcePort(srcPort).setDestinationPort(dstPort).
+ setLength(udpLen).setChecksum(cksum).setRawPayload(raw);
+ UDP copy = new UDP();
+ assertSame(copy, MiscUtils.copy(org, copy));
+ checkCopy(org, copy, srcPort, dstPort, cksum, raw);
+
+ srcPort++;
+ dstPort++;
+ cksum++;
+ }
+
+ // Ensure that ICMP instance with raw payload can be copied.
+ short icmpSeq = 0x13a9;
+ short icmpId = 0x7c;
+ byte icmpType = 0;
+ byte icmpCode = 6;
+ for (int loop = 0; loop < 5; loop++) {
+ ICMP org = new ICMP();
+ org.setType(icmpType).setCode(icmpCode).setIdentifier(icmpId).
+ setSequenceNumber(icmpSeq).setRawPayload(raw);
+
+ // Copy the original in order to fix up header fields, such as
+ // checksum.
+ org = MiscUtils.copy(org, new ICMP());
+
+ ICMP copy = new ICMP();
+ assertSame(copy, MiscUtils.copy(org, copy));
+ checkCopy(org, copy, icmpType, icmpCode, icmpId, icmpSeq, raw);
+
+ icmpSeq++;
+ icmpId++;
+ icmpType++;
+ icmpCode++;
+ }
+
+ // Ensure that nested Etherner frame can be copied.
+ IPProtocols[] protos = {
+ IPProtocols.TCP,
+ IPProtocols.UDP,
+ IPProtocols.ICMP,
+ };
+ int protoIndex = 0;
+ vid = MatchType.DL_VLAN_NONE;
+ etype = EtherTypes.IPv4.shortValue();
+ pcp = 0;
+ dscp = 0;
+ srcPort = 128;
+ dstPort = 12345;
+ cksum = (short)0xed03;
+ for (int loop = 0; loop < protos.length * 5; loop++) {
+ IPProtocols proto = protos[protoIndex];
+ protoIndex++;
+ if (protoIndex >= protos.length) {
+ protoIndex = 0;
+ }
+
+ Packet l4 = null;
+ switch (proto) {
+ case TCP:
+ l4 = new TCP().setSourcePort(srcPort).
+ setDestinationPort(dstPort).setSequenceNumber(seq).
+ setAckNumber(ack).setDataOffset(dataOff).
+ setHeaderLenFlags(flags).setReserved(resv).
+ setWindowSize(win).setChecksum(cksum).
+ setUrgentPointer(urp);
+ break;
+
+ case UDP:
+ l4 = new UDP().setSourcePort(srcPort).
+ setDestinationPort(dstPort).setLength(udpLen).
+ setChecksum(cksum);
+ break;
+
+ case ICMP:
+ l4 = new ICMP().setType(icmpType).setCode(icmpCode).
+ setIdentifier(icmpId).setSequenceNumber(icmpSeq);
+ break;
+
+ default:
+ unexpected();
+ break;
+ }
+
+ l4.setRawPayload(raw);
+
+ ipproto = proto.byteValue();
+ IPv4 ipv4 = createIPv4(srcIp, dstIp, ipproto, dscp);
+ ipv4.setPayload(l4);
+ Ethernet ether = createEthernet(srcMac, dstMac, etype, vid, pcp,
+ ipv4);
+
+ // Copy the original in order to fix up header fields, such as
+ // IP checksum.
+ ether = MiscUtils.copy(ether, new Ethernet());
+
+ Ethernet copy = new Ethernet();
+ assertSame(copy, MiscUtils.copy(ether, copy));
+ checkCopy(ether, copy, srcMac, dstMac, etype, vid, pcp, null);
+
+ IPv4 ipCopy;
+ if (vid == MatchType.DL_VLAN_NONE) {
+ ipv4 = (IPv4)ether.getPayload();
+ ipCopy = (IPv4)copy.getPayload();
+ } else {
+ Packet pkt = ether.getPayload();
+ ipv4 = (IPv4)pkt.getPayload();
+ pkt = copy.getPayload();
+ ipCopy = (IPv4)pkt.getPayload();
+ }
+ vid = (short)((vid + 1) & 0xfff);
+ srcMac[5]++;
+ dstMac[2]++;
+
+ // Check IPv4 packet.
+ checkCopy(ipv4, ipCopy, srcIp, dstIp, ipproto, dscp, null);
+ srcIp++;
+ dstIp++;
+ dscp = (byte)((dscp + 1) & 0x3f);
+
+ switch (proto) {
+ case TCP:
+ // Check TCP packet.
+ TCP tcp = (TCP)ipv4.getPayload();
+ TCP tcpCopy = (TCP)ipCopy.getPayload();
+ checkCopy(tcp, tcpCopy, srcPort, dstPort, cksum, raw);
+ seq++;
+ ack++;
+ dataOff = (byte)((dataOff + 1) & 0xf);
+ cksum += 13;
+ srcPort++;
+ dstPort++;
+ break;
+
+ case UDP:
+ // Check UDP packet.
+ UDP udp = (UDP)ipv4.getPayload();
+ UDP udpCopy = (UDP)ipCopy.getPayload();
+ checkCopy(udp, udpCopy, srcPort, dstPort, cksum, raw);
+ srcPort++;
+ dstPort++;
+ cksum += 23;
+ break;
+
+ case ICMP:
+ // Check ICMP packet.
+ ICMP icmp = (ICMP)ipv4.getPayload();
+ ICMP icmpCopy = (ICMP)ipCopy.getPayload();
+ checkCopy(icmp, icmpCopy, icmpType, icmpCode, icmpId, icmpSeq,
+ raw);
+ icmpSeq++;
+ icmpId++;
+ icmpType++;
+ icmpCode++;
+ break;
+
+ default:
+ unexpected();
+ break;
+ }
+ }
+ }
+
+ /**
+ * Test case for {@link MiscUtils#setInt(byte[], int, int)}.
+ */
+ @Test
+ public void testSetInt() {
+ int size = 32;
+ int value = 0xa1b2c3d4;
+ byte[] bytes = {(byte)0xa1, (byte)0xb2, (byte)0xc3, (byte)0xd4};
+ for (int off = 0; off <= size - 4; off++) {
+ byte[] buffer = new byte[size];
+ MiscUtils.setInt(buffer, off, value);
+ for (int i = 0; i < buffer.length; i++) {
+ if (i >= off && i < off + 4) {
+ assertEquals(bytes[i - off], buffer[i]);
+ } else {
+ assertEquals((byte)0, buffer[i]);
+ }
+ }
+ }
+ }
+
+ /**
+ * Test case for {@link MiscUtils#setShort(byte[], int, short)}.
+ */
+ @Test
+ public void testSetShort() {
+ int size = 32;
+ short value = (short)0xa1b2;
+ byte[] bytes = {(byte)0xa1, (byte)0xb2};
+ for (int off = 0; off <= size - 2; off++) {
+ byte[] buffer = new byte[size];
+ MiscUtils.setShort(buffer, off, value);
+ for (int i = 0; i < buffer.length; i++) {
+ if (i >= off && i < off + 2) {
+ assertEquals(bytes[i - off], buffer[i]);
+ } else {
+ assertEquals((byte)0, buffer[i]);
+ }
+ }
+ }
+ }
+
+ /**
+ * Verify the contents of the given {@link VTNException}.
+ *
+ *
+ * This method expects that {@link StatusCode#BADREQUEST} is configured
+ * in the given exception.
+ *
+ *
+ * @param e A {@link VTNException} to be tested.
+ * @param desc An expected description.
+ */
+ private void checkException(VTNException e, String desc) {
+ checkException(e, desc, StatusCode.BADREQUEST);
+ }
+
+ /**
+ * Verify the contents of the given {@link VTNException}.
+ *
+ * @param e A {@link VTNException} to be tested.
+ * @param desc An expected description.
+ * @param code An expected status code.
+ */
+ private void checkException(VTNException e, String desc, StatusCode code) {
+ checkStatus(e.getStatus(), desc, code);
+ }
+
+ /**
+ * Verify the contents of the given {@link Status}.
+ *
+ *
+ * This method expects that {@link StatusCode#BADREQUEST} is configured
+ * in the given status.
+ *
+ *
+ * @param st A {@link Status} instance to be tested.
+ * @param desc An expected description.
+ */
+ private void checkStatus(Status st, String desc) {
+ checkStatus(st, desc, StatusCode.BADREQUEST);
+ }
+
+ /**
+ * Verify the contents of the given {@link Status}.
+ *
+ * @param st A {@link Status} instance to be tested.
+ * @param desc An expected description.
+ * @param code An expected status code.
+ */
+ private void checkStatus(Status st, String desc, StatusCode code) {
+ assertEquals(desc, st.getDescription());
+ assertEquals(code, st.getCode());
+ }
+
+ /**
+ * Ensure that the raw payload of the packet was copied successfully.
+ *
+ * @param org Original{@link Packet} instance.
+ * @param copy A copy of {@code org}.
+ * @param raw Expected raw payload.
+ */
+ private void checkRawPayloadCopy(Packet org, Packet copy, byte[] raw) {
+ byte[] rawPayload = copy.getRawPayload();
+ byte[] orgPayload = org.getRawPayload();
+ if (raw == null) {
+ assertEquals(null, rawPayload);
+ assertEquals(null, orgPayload);
+ } else {
+ assertEquals(null, org.getPayload());
+ assertEquals(null, copy.getPayload());
+ assertNotSame(raw, rawPayload);
+ assertNotSame(orgPayload, rawPayload);
+ assertArrayEquals(raw, rawPayload);
+ assertArrayEquals(raw, orgPayload);
+ }
+ }
+
+ /**
+ * Ensure that an {@link Ethernet} instance was copied successfully.
+ *
+ * @param org Original {@link Ethernet} instance.
+ * @param copy A copy of {@code org}.
+ * @param src Expected source MAC address.
+ * @param dst Expected destination MAC address.
+ * @param etype Expected ethernet type.
+ * @param vid Expected VLAN ID.
+ * @param pcp Expected VLAN priority.
+ * @param raw Expected raw payload.
+ */
+ private void checkCopy(Ethernet org, Ethernet copy, byte[] src, byte[] dst,
+ short etype, short vid, byte pcp, byte[] raw) {
+ assertNotSame(copy, org);
+ assertEquals(copy, org);
+ assertArrayEquals(src, org.getSourceMACAddress());
+ assertArrayEquals(dst, org.getDestinationMACAddress());
+ assertArrayEquals(src, copy.getSourceMACAddress());
+ assertArrayEquals(dst, copy.getDestinationMACAddress());
+ Packet parent;
+ Packet orgParent;
+ if (vid == MatchType.DL_VLAN_NONE) {
+ assertEquals(etype, org.getEtherType());
+ assertEquals(etype, copy.getEtherType());
+ parent = copy;
+ orgParent = org;
+ } else {
+ assertEquals(EtherTypes.VLANTAGGED.shortValue(),
+ org.getEtherType());
+ assertEquals(EtherTypes.VLANTAGGED.shortValue(),
+ copy.getEtherType());
+ IEEE8021Q orgTag = (IEEE8021Q)org.getPayload();
+ IEEE8021Q vlanTag = (IEEE8021Q)copy.getPayload();
+ assertNotNull(vlanTag);
+ assertNotSame(orgTag, vlanTag);
+ assertEquals(orgTag, vlanTag);
+ assertEquals(etype, orgTag.getEtherType());
+ assertEquals(vid, orgTag.getVid());
+ assertEquals(pcp, orgTag.getPcp());
+ assertEquals((byte)0, orgTag.getCfi());
+ assertEquals(etype, vlanTag.getEtherType());
+ assertEquals(vid, vlanTag.getVid());
+ assertEquals(pcp, vlanTag.getPcp());
+ assertEquals((byte)0, vlanTag.getCfi());
+ parent = vlanTag;
+ orgParent = orgTag;
+ }
+
+ checkRawPayloadCopy(parent, orgParent, raw);
+ }
+
+ /**
+ * Ensure that an {@link IPv4} instance was copied successfully.
+ *
+ * @param org Original {@link IPv4} instance.
+ * @param copy A copy of {@code org}.
+ * @param src Expected source IP address.
+ * @param dst Expected destination IP address.
+ * @param proto Expected IP protocol number.
+ * @param dscp Expected DSCP field value.
+ * @param raw Expected raw payload.
+ */
+ private void checkCopy(IPv4 org, IPv4 copy, int src, int dst, short proto,
+ byte dscp, byte[] raw) {
+ assertNotSame(copy, org);
+ assertEquals(copy, org);
+ for (IPv4 ipv4: new IPv4[]{org, copy}) {
+ assertEquals(src, ipv4.getSourceAddress());
+ assertEquals(dst, ipv4.getDestinationAddress());
+ assertEquals((byte)proto, ipv4.getProtocol());
+ assertEquals(dscp, ipv4.getDiffServ());
+ }
+
+ checkRawPayloadCopy(org, copy, raw);
+ }
+
+ /**
+ * Ensure that an {@link TCP} instance was copied successfully.
+ *
+ * @param org Original {@link TCP} instance.
+ * @param copy A copy of {@code org}.
+ * @param src Expected source port number.
+ * @param dst Expected destination port number.
+ * @param cksum Expected TCP checksum.
+ * @param raw Expected raw payload.
+ */
+ private void checkCopy(TCP org, TCP copy, short src, short dst,
+ short cksum, byte[] raw) {
+ assertNotSame(copy, org);
+ assertEquals(copy, org);
+ for (TCP tcp: new TCP[]{org, copy}) {
+ assertEquals(src, tcp.getSourcePort());
+ assertEquals(dst, tcp.getDestinationPort());
+ assertEquals(cksum, tcp.getChecksum());
+ }
+
+ checkRawPayloadCopy(org, copy, raw);
+ }
+
+ /**
+ * Ensure that an {@link UDP} instance was copied successfully.
+ *
+ * @param org Original {@link UDP} instance.
+ * @param copy A copy of {@code org}.
+ * @param src Expected source port number.
+ * @param dst Expected destination port number.
+ * @param cksum Expected UDP checksum.
+ * @param raw Expected raw payload.
+ */
+ private void checkCopy(UDP org, UDP copy, short src, short dst,
+ short cksum, byte[] raw) {
+ assertNotSame(copy, org);
+ assertEquals(copy, org);
+ for (UDP udp: new UDP[]{org, copy}) {
+ assertEquals(src, udp.getSourcePort());
+ assertEquals(dst, udp.getDestinationPort());
+ assertEquals(cksum, udp.getChecksum());
+ }
+
+ checkRawPayloadCopy(org, copy, raw);
+ }
+
+ /**
+ * Ensure that an {@link ICMP} instance was copied successfully.
+ *
+ * @param org Original {@link UDP} instance.
+ * @param copy A copy of {@code org}.
+ * @param type Expected ICMP type.
+ * @param code Expected ICMP code.
+ * @param id Expected identifier.
+ * @param seq Expected sequence number.
+ * @param raw Expected raw payload.
+ */
+ private void checkCopy(ICMP org, ICMP copy, byte type, byte code,
+ short id, short seq, byte[] raw) {
+ assertNotSame(copy, org);
+ assertEquals(copy, org);
+ for (ICMP icmp: new ICMP[]{org, copy}) {
+ assertEquals(type, icmp.getType());
+ assertEquals(code, icmp.getCode());
+ assertEquals(id, icmp.getIdentifier());
+ assertEquals(seq, icmp.getSequenceNumber());
+ }
+
+ checkRawPayloadCopy(org, copy, raw);
+ }
+}
diff --git a/manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/TestBase.java b/manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/TestBase.java
index d2f2eba2..64ed4f23 100644
--- a/manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/TestBase.java
+++ b/manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/TestBase.java
@@ -15,7 +15,6 @@ import java.io.File;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.InetAddress;
-import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
@@ -47,10 +46,12 @@ import org.opendaylight.vtn.manager.internal.cluster.VlanMapPath;
import org.opendaylight.controller.sal.core.Edge;
import org.opendaylight.controller.sal.core.Node;
import org.opendaylight.controller.sal.core.NodeConnector;
+import org.opendaylight.controller.sal.match.MatchType;
import org.opendaylight.controller.sal.packet.ARP;
import org.opendaylight.controller.sal.packet.Ethernet;
import org.opendaylight.controller.sal.packet.IEEE8021Q;
import org.opendaylight.controller.sal.packet.IPv4;
+import org.opendaylight.controller.sal.packet.Packet;
import org.opendaylight.controller.sal.packet.RawPacket;
import org.opendaylight.controller.sal.packet.address.EthernetAddress;
import org.opendaylight.controller.sal.utils.EtherTypes;
@@ -277,6 +278,28 @@ public abstract class TestBase extends Assert {
return ref;
}
+ /**
+ * Create a deep copy of the specified {@link Packet} instance.
+ *
+ * @param src The source {@link Packet} instance.
+ * @param dst The destination {@link Packet} instance.
+ * @param Type of the packet.
+ * @return {@code dst}.
+ */
+ protected static T copy(T src, T dst) {
+ if (src != null) {
+ try {
+ byte[] raw = src.serialize();
+ int nbits = raw.length * NetUtils.NumBitsInAByte;
+ dst.deserialize(raw, 0, nbits);
+ } catch (Exception e) {
+ unexpected(e);
+ }
+ }
+
+ return dst;
+ }
+
/**
* Create a list of boolean values and a {@code null}.
*
@@ -744,6 +767,45 @@ public abstract class TestBase extends Assert {
return list;
}
+ /**
+ * Create a list of IPv4 addresses and {@code null}.
+ *
+ * @return A list of {@link InetAddress} instances.
+ */
+ protected static List createInet4Addresses() {
+ return createInet4Addresses(true);
+ }
+
+ /**
+ * Create a list of IPv4 addresses.
+ *
+ * @param setNull Set {@code null} to returned list if {@code true}.
+ * @return A list of {@link InetAddress} instances.
+ */
+ protected static List createInet4Addresses(boolean setNull) {
+ List list = new ArrayList();
+ if (setNull) {
+ list.add(null);
+ }
+
+ String[] addrs = {
+ "0.0.0.0",
+ "255.255.255.255",
+ "127.0.0.1",
+ "10.20.30.40",
+ "192.168.100.200",
+ };
+ for (String addr: addrs) {
+ try {
+ list.add(InetAddress.getByName(addr));
+ } catch (Exception e) {
+ unexpected(e);
+ }
+ }
+
+ return list;
+ }
+
/**
* Create a {@link InetAddress} instance which represents the specified
* IP address.
@@ -847,6 +909,173 @@ public abstract class TestBase extends Assert {
return pctx;
}
+ /**
+ * Create an Ethernet frame.
+ *
+ * @param src Source MAC address.
+ * @param dst Destination MAC address.
+ * @param type Ethernet type.
+ * @param vid A VLAN ID.
+ * @param pcp VLAN priority.
+ * @param payload A {@link Packet} instance to be set as payload.
+ * @return An {@link Ethernet} instance.
+ */
+ protected static Ethernet createEthernet(byte[] src, byte[] dst, int type,
+ short vid, byte pcp,
+ Packet payload) {
+ Ethernet pkt = new Ethernet();
+ pkt.setSourceMACAddress(src).setDestinationMACAddress(dst);
+ if (vid == MatchType.DL_VLAN_NONE) {
+ pkt.setEtherType((short)type).setPayload(payload);
+ } else {
+ IEEE8021Q tag = new IEEE8021Q();
+ tag.setCfi((byte)0).setPcp(pcp).setVid(vid).
+ setEtherType((short)type).setPayload(payload);
+ pkt.setEtherType(EtherTypes.VLANTAGGED.shortValue()).
+ setPayload(tag);
+ }
+
+ return pkt;
+ }
+
+ /**
+ * Create an Ethernet frame.
+ *
+ * @param src Source MAC address.
+ * @param dst Destination MAC address.
+ * @param type Ethernet type.
+ * @param vid A VLAN ID.
+ * @param pcp VLAN priority
+ * @param raw A byte array to be set as payload.
+ * @return An {@link Ethernet} instance.
+ */
+ protected static Ethernet createEthernet(byte[] src, byte[] dst, int type,
+ short vid, byte pcp, byte[] raw) {
+ Ethernet pkt = new Ethernet();
+ pkt.setSourceMACAddress(src).setDestinationMACAddress(dst);
+ if (vid == MatchType.DL_VLAN_NONE) {
+ pkt.setEtherType((short)type).setRawPayload(raw);
+ } else {
+ IEEE8021Q tag = new IEEE8021Q();
+ tag.setCfi((byte)0).setPcp(pcp).setVid(vid).
+ setEtherType((short)type).setRawPayload(raw);
+ pkt.setEtherType(EtherTypes.VLANTAGGED.shortValue()).
+ setPayload(tag);
+ }
+
+ return pkt;
+ }
+
+ /**
+ * Create an untagged Ethernet frame that contains the given IPv4 packet.
+ *
+ *
+ * Fixed values are used for the source and destination MAC address.
+ *
+ *
+ * @param ipv4 An {@link IPv4} to be configured as payload.
+ * @return An {@link Ethernet} instance.
+ */
+ protected static Ethernet createEthernet(IPv4 ipv4) {
+ byte[] src = {
+ (byte)0x00, (byte)0x11, (byte)0x22,
+ (byte)0x33, (byte)0x44, (byte)0x55,
+ };
+ byte[] dst = {
+ (byte)0xa0, (byte)0xb0, (byte)0xc0,
+ (byte)0xdd, (byte)0xee, (byte)0xff,
+ };
+
+ return createEthernet(src, dst, EtherTypes.IPv4.intValue(),
+ MatchType.DL_VLAN_NONE, (byte)0, ipv4);
+ }
+
+ /**
+ * Create an {@link IPv4} instance.
+ *
+ * @param src Source IP address.
+ * @param dst Destination IP address.
+ * @param proto IP protocol number.
+ * @param dscp DSCP field value.
+ * @return An {@link IPv4} instance.
+ */
+ protected static IPv4 createIPv4(InetAddress src, InetAddress dst,
+ short proto, byte dscp) {
+ IPv4 pkt = new IPv4();
+ return pkt.setSourceAddress(src).setDestinationAddress(dst).
+ setProtocol((byte)proto).setDiffServ(dscp).
+ setTtl((byte)64);
+ }
+
+ /**
+ * Create an {@link IPv4} instance.
+ *
+ * @param src A byte array which represents the source IP address.
+ * @param dst A byte array which represents the destination IP address.
+ * @param proto IP protocol number.
+ * @param dscp DSCP field value.
+ * @return An {@link IPv4} instance.
+ */
+ protected static IPv4 createIPv4(byte[] src, byte[] dst, short proto,
+ byte dscp) {
+ InetAddress srcInet = createInetAddress(src);
+ InetAddress dstInet = createInetAddress(dst);
+ return createIPv4(srcInet, dstInet, proto, dscp);
+ }
+
+ /**
+ * Create an {@link IPv4} instance.
+ *
+ * @param src An integer value which represents the source IP address.
+ * @param dst An integer value which represents the destination IP
+ * address.
+ * @param proto IP protocol number.
+ * @param dscp DSCP field value.
+ * @return An {@link IPv4} instance.
+ */
+ protected static IPv4 createIPv4(int src, int dst, short proto,
+ byte dscp) {
+ byte[] srcAddr = NetUtils.intToByteArray4(src);
+ byte[] dstAddr = NetUtils.intToByteArray4(dst);
+ return createIPv4(srcAddr, dstAddr, proto, dscp);
+ }
+
+ /**
+ * Create an {@link IPv4} instance.
+ *
+ * @param src A byte array which represents the source IP address.
+ * @param dst A byte array which represents the destination IP address.
+ * @param proto IP protocol number.
+ * @param dscp DSCP field value.
+ * @param payload A {@link Packet} instance to be configured as payload.
+ * @return An {@link IPv4} instance.
+ */
+ protected static IPv4 createIPv4(byte[] src, byte[] dst, short proto,
+ byte dscp, Packet payload) {
+ IPv4 pkt = createIPv4(src, dst, proto, dscp);
+ pkt.setPayload(payload);
+
+ return pkt;
+ }
+
+ /**
+ * Create an {@link IPv4} instance.
+ *
+ *
+ * Fixed values are used for the source and destination IP address,
+ * and DSCP field.
+ *
+ *
+ * @param proto IP protocol number.
+ * @param payload A {@link Packet} instance to be configured as payload.
+ * @return An {@link IPv4} instance.
+ */
+ protected static IPv4 createIPv4(short proto, Packet payload) {
+ byte[] src = {(byte)10, (byte)1, (byte)2, (byte)30};
+ byte[] dst = {(byte)127, (byte)0, (byte)0, (byte)1};
+ return createIPv4(src, dst, proto, (byte)0, payload);
+ }
+
/**
* create a {@link RawPacket} object.
*
@@ -889,8 +1118,8 @@ public abstract class TestBase extends Assert {
setFragmentOffset((short)0).
setTtl((byte)64);
- ip.setDestinationAddress(getInetAddressFromAddress(target));
- ip.setSourceAddress(getInetAddressFromAddress(sender));
+ ip.setDestinationAddress(createInetAddress(target));
+ ip.setSourceAddress(createInetAddress(sender));
Ethernet eth = new Ethernet();
eth.setSourceMACAddress(src).setDestinationMACAddress(dst);
@@ -1085,22 +1314,6 @@ public abstract class TestBase extends Assert {
return list;
}
- /**
- * get {@link InetAddress} object from byte arrays.
- *
- * @param ipaddr byte arrays of IP Address.
- * @return A InetAddress object.
- */
- protected InetAddress getInetAddressFromAddress(byte[] ipaddr) {
- InetAddress inet = null;
- try {
- inet = InetAddress.getByAddress(ipaddr);
- } catch (UnknownHostException e) {
- unexpected(e);
- }
- return inet;
- }
-
/**
* Determine whether the specified two strings are identical or not.
*
diff --git a/manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/VTNManagerImplClusterTest.java b/manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/VTNManagerImplClusterTest.java
index 6a7e1ac0..1caebc33 100644
--- a/manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/VTNManagerImplClusterTest.java
+++ b/manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/VTNManagerImplClusterTest.java
@@ -293,9 +293,8 @@ public class VTNManagerImplClusterTest extends VTNManagerImplTestCommon {
getCache(VTNManagerImpl.CACHE_STATE);
VTenantPath tpathNull = new VTenantPath(null);
- InetAddress ia
- = getInetAddressFromAddress(new byte[] {(byte)192, (byte)168,
- (byte)0, (byte)2});
+ InetAddress ia = createInetAddress(
+ new byte[] {(byte)192, (byte)168, (byte)0, (byte)2});
ObjectPair obj
= new ObjectPair(ia, Boolean.FALSE);
stateDB.put(tpathNull, obj);
@@ -313,8 +312,8 @@ public class VTNManagerImplClusterTest extends VTNManagerImplTestCommon {
stateDB = (ConcurrentMap)stubObj.
getCache(VTNManagerImpl.CACHE_STATE);
- ia = getInetAddressFromAddress(new byte[] {(byte)192, (byte)168,
- (byte)0, (byte)99});
+ ia = createInetAddress(
+ new byte[] {(byte)192, (byte)168, (byte)0, (byte)99});
obj = new ObjectPair(ia, Boolean.FALSE);
assertNull(stateDB.put(tpathNull, obj));
@@ -479,7 +478,7 @@ public class VTNManagerImplClusterTest extends VTNManagerImplTestCommon {
assertEquals(1, vtnMgr.getFlowDB().size());
// in case MAC Address Table cache remain.
- InetAddress ipaddr = getInetAddressFromAddress(new byte[]{10, 0, 0, 1});
+ InetAddress ipaddr = createInetAddress(new byte[]{10, 0, 0, 1});
MacTableEntry tent = new MacTableEntry(bpath, 1L, innc,
(short)0, ipaddr);
vtnMgr.putMacTableEntry(tent);
@@ -498,7 +497,7 @@ public class VTNManagerImplClusterTest extends VTNManagerImplTestCommon {
assertEquals(0, map.size());
// in case remote entry is remained.
- InetAddress ipaddrRemote = getInetAddressFromAddress(new byte[] {0, 0, 0, 0});
+ InetAddress ipaddrRemote = createInetAddress(new byte[] {0, 0, 0, 0});
MacTableEntryId evidRemote = new MacTableEntryId(ipaddrRemote, 1L, bpath, 1L);
tent = new MacTableEntry(evidRemote, innc, (short)0, ipaddr);
@@ -1360,7 +1359,7 @@ public class VTNManagerImplClusterTest extends VTNManagerImplTestCommon {
File configFile = new File(dir, configFileName);
Set evIdSet = new HashSet();
- InetAddress ipaddr = getInetAddressFromAddress(new byte[] {0, 0, 0, 0});
+ InetAddress ipaddr = createInetAddress(new byte[] {0, 0, 0, 0});
ClusterEventId evidRemote = new ClusterEventId(ipaddr, 0);
ClusterEventId evidLocal = new ClusterEventId();
evIdSet.add(evidLocal);
@@ -1449,7 +1448,7 @@ public class VTNManagerImplClusterTest extends VTNManagerImplTestCommon {
File configFile = new File(dir, configFileName);
Set evIdSet = new HashSet();
- InetAddress ipaddr = getInetAddressFromAddress(new byte[] {0, 0, 0, 0});
+ InetAddress ipaddr = createInetAddress(new byte[] {0, 0, 0, 0});
ClusterEventId evIdRemote = new ClusterEventId(ipaddr, 0);
ClusterEventId evIdLocal = new ClusterEventId();
evIdSet.add(evIdLocal);
@@ -1502,7 +1501,7 @@ public class VTNManagerImplClusterTest extends VTNManagerImplTestCommon {
File configFile = new File(dir, configFileName);
Set evIdSet = new HashSet();
- InetAddress ipaddr = getInetAddressFromAddress(new byte[] {0, 0, 0, 0});
+ InetAddress ipaddr = createInetAddress(new byte[] {0, 0, 0, 0});
ClusterEventId evIdRemote = new ClusterEventId(ipaddr, 0);
ClusterEventId evIdLocal = new ClusterEventId();
evIdSet.add(evIdLocal);
@@ -1546,7 +1545,7 @@ public class VTNManagerImplClusterTest extends VTNManagerImplTestCommon {
nodeSet.add(node0);
nodeSet.add(node1);
- InetAddress ipaddr = getInetAddressFromAddress(new byte[] {0, 0, 0, 0});
+ InetAddress ipaddr = createInetAddress(new byte[] {0, 0, 0, 0});
ClusterEventId evidRemote = new ClusterEventId(ipaddr, 0);
ClusterEventId evidLocal = new ClusterEventId();
Set evIdSet = new HashSet();
diff --git a/manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/VTNManagerImplDisableNodesTest.java b/manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/VTNManagerImplDisableNodesTest.java
index bbf70af5..9602bef5 100644
--- a/manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/VTNManagerImplDisableNodesTest.java
+++ b/manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/VTNManagerImplDisableNodesTest.java
@@ -446,7 +446,7 @@ public class VTNManagerImplDisableNodesTest extends TestBase {
RawPacketEvent ev = new RawPacketEvent(pkt, outnc);
- InetAddress ipaddr = getInetAddressFromAddress(new byte[] {0, 0, 0, 0});
+ InetAddress ipaddr = createInetAddress(new byte[] {0, 0, 0, 0});
ClusterEventId evidRemote = new ClusterEventId(ipaddr, 0);
ClusterEventId evidLocal = new ClusterEventId();
diff --git a/manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/VTNManagerImplTest.java b/manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/VTNManagerImplTest.java
index 92b16f14..59d23c7b 100644
--- a/manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/VTNManagerImplTest.java
+++ b/manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/VTNManagerImplTest.java
@@ -332,7 +332,7 @@ public class VTNManagerImplTest extends VTNManagerImplTestCommon {
getCache(VTNManagerImpl.CACHE_EVENT);
FlowGroupId gid = new FlowGroupId("test_tenant");
- InetAddress ipaddr = getInetAddressFromAddress(new byte[] {0, 0, 0, 0});
+ InetAddress ipaddr = createInetAddress(new byte[] {0, 0, 0, 0});
FlowGroupId gidRemote = new FlowGroupId(ipaddr, 0L, "test_tenant2");
VTNFlow flow = new VTNFlow(gid);
@@ -391,7 +391,7 @@ public class VTNManagerImplTest extends VTNManagerImplTestCommon {
assertEquals(1, vtnMgr.getFlowDB().size());
// in case MAC Address Table cache remain.
- ipaddr = getInetAddressFromAddress(new byte[] {10, 0, 0, 1});
+ ipaddr = createInetAddress(new byte[] {10, 0, 0, 1});
MacTableEntry tent = new MacTableEntry(bpath, 1L, innc, (short)0,
ipaddr);
vtnMgr.putMacTableEntry(tent);
@@ -5881,7 +5881,7 @@ public class VTNManagerImplTest extends VTNManagerImplTestCommon {
RawPacketEvent ev = new RawPacketEvent(pkt, outnc);
- InetAddress ipaddr = getInetAddressFromAddress(new byte[] {0, 0, 0, 0});
+ InetAddress ipaddr = createInetAddress(new byte[] {0, 0, 0, 0});
ClusterEventId evidRemote = new ClusterEventId(ipaddr, 0);
ClusterEventId evidLocal = new ClusterEventId();
@@ -5972,7 +5972,7 @@ public class VTNManagerImplTest extends VTNManagerImplTestCommon {
FlowRemoveEvent removeEvent = new FlowRemoveEvent(flow.getFlowEntries());
Set evIdSet = new HashSet();
- InetAddress ipaddr = getInetAddressFromAddress(new byte[] {0, 0, 0, 0});
+ InetAddress ipaddr = createInetAddress(new byte[] {0, 0, 0, 0});
ClusterEventId evIdRemote = new ClusterEventId(ipaddr, 0);
evIdSet.add(evIdRemote);
@@ -6203,7 +6203,7 @@ public class VTNManagerImplTest extends VTNManagerImplTestCommon {
}
InetAddress ipaddr
- = getInetAddressFromAddress(new byte[] {0, 0, 0, 0});
+ = createInetAddress(new byte[] {0, 0, 0, 0});
ClusterEventId evidRemote = new ClusterEventId(ipaddr, 0);
ClusterEventId evidLocal = new ClusterEventId();
@@ -6292,7 +6292,7 @@ public class VTNManagerImplTest extends VTNManagerImplTestCommon {
VTNFlowDatabase fdb = vtnMgr.getTenantFlowDB(path.getTenantName());
// create FlowGroupId.
- InetAddress ipaddr = getInetAddressFromAddress(new byte[] {0, 0, 0, 0});
+ InetAddress ipaddr = createInetAddress(new byte[] {0, 0, 0, 0});
FlowGroupId evIdRemote = new FlowGroupId(ipaddr, 0L, "tenant");
FlowGroupId evIdLocal = new FlowGroupId(InetAddress.getLoopbackAddress(),
0L, "tenant");
@@ -6443,7 +6443,7 @@ public class VTNManagerImplTest extends VTNManagerImplTestCommon {
Node node = NodeCreator.createOFNode(Long.valueOf(0L));
NodeConnector nc = NodeConnectorCreator
.createOFNodeConnector(Short.valueOf("1"), node);
- InetAddress ipaddr = getInetAddressFromAddress(new byte[] {0, 0, 0, 0});
+ InetAddress ipaddr = createInetAddress(new byte[] {0, 0, 0, 0});
MacTableEntryId evidRemote = new MacTableEntryId(ipaddr, 0L, bpath, mac);
MacTableEntryId evidLocal = new MacTableEntryId(bpath, mac);
diff --git a/manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/VTNManagerImplWithNodesTest.java b/manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/VTNManagerImplWithNodesTest.java
index 78ff014a..1491cd28 100644
--- a/manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/VTNManagerImplWithNodesTest.java
+++ b/manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/VTNManagerImplWithNodesTest.java
@@ -3133,7 +3133,7 @@ public class VTNManagerImplWithNodesTest extends VTNManagerImplTestCommon {
}
}
- InetAddress ia = getInetAddressFromAddress(new byte[] {10, 0, 0, 1});
+ InetAddress ia = createInetAddress(new byte[] {10, 0, 0, 1});
InetAddress ia6 = null;
try {
diff --git a/manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/cluster/FlowActionImplTest.java b/manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/cluster/FlowActionImplTest.java
index 338a9074..23f86939 100644
--- a/manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/cluster/FlowActionImplTest.java
+++ b/manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/cluster/FlowActionImplTest.java
@@ -9,6 +9,7 @@
package org.opendaylight.vtn.manager.internal.cluster;
+import java.net.InetAddress;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
@@ -25,6 +26,10 @@ import org.opendaylight.vtn.manager.flow.action.SetDlSrcAction;
import org.opendaylight.vtn.manager.flow.action.SetDscpAction;
import org.opendaylight.vtn.manager.flow.action.SetIcmpCodeAction;
import org.opendaylight.vtn.manager.flow.action.SetIcmpTypeAction;
+import org.opendaylight.vtn.manager.flow.action.SetInet4DstAction;
+import org.opendaylight.vtn.manager.flow.action.SetInet4SrcAction;
+import org.opendaylight.vtn.manager.flow.action.SetTpDstAction;
+import org.opendaylight.vtn.manager.flow.action.SetTpSrcAction;
import org.opendaylight.vtn.manager.flow.action.SetVlanIdAction;
import org.opendaylight.vtn.manager.flow.action.SetVlanPcpAction;
@@ -46,14 +51,18 @@ public class FlowActionImplTest extends TestBase {
* Test case for {@link FlowActionImpl#create(FlowAction)}.
*/
@Test
- public void testCreate() {
+ public void testCreate() throws Exception {
// Expected action implementation classes.
HashMap, Class>> implClasses =
new HashMap, Class>>();
implClasses.put(SetDlSrcAction.class, SetDlSrcActionImpl.class);
implClasses.put(SetDlDstAction.class, SetDlDstActionImpl.class);
implClasses.put(SetVlanPcpAction.class, SetVlanPcpActionImpl.class);
+ implClasses.put(SetInet4SrcAction.class, SetInet4SrcActionImpl.class);
+ implClasses.put(SetInet4DstAction.class, SetInet4DstActionImpl.class);
implClasses.put(SetDscpAction.class, SetDscpActionImpl.class);
+ implClasses.put(SetTpSrcAction.class, SetTpSrcActionImpl.class);
+ implClasses.put(SetTpDstAction.class, SetTpDstActionImpl.class);
implClasses.put(SetIcmpTypeAction.class, SetIcmpTypeActionImpl.class);
implClasses.put(SetIcmpCodeAction.class, SetIcmpCodeActionImpl.class);
@@ -86,11 +95,39 @@ public class FlowActionImplTest extends TestBase {
actions.add(new SetVlanPcpAction(pri));
}
+ count = 0;
+ do {
+ int v = rand.nextInt();
+ byte[] addr = NetUtils.intToByteArray4(v);
+ InetAddress iaddr = InetAddress.getByAddress(addr);
+ actions.add(new SetInet4SrcAction(iaddr));
+ count++;
+ } while (count < naddrs);
+
+ count = 0;
+ do {
+ int v = rand.nextInt();
+ byte[] addr = NetUtils.intToByteArray4(v);
+ InetAddress iaddr = InetAddress.getByAddress(addr);
+ actions.add(new SetInet4DstAction(iaddr));
+ count++;
+ } while (count < naddrs);
+
byte[] dscps = {0, 18, 32, 63};
for (byte dscp: dscps) {
actions.add(new SetDscpAction(dscp));
}
+ int[] ports = {0, 53, 200, 456, 20000, 40000, 65535};
+ for (int port: ports) {
+ actions.add(new SetTpSrcAction(port));
+ }
+
+ ports = new int[]{0, 31, 113, 789, 12345, 34567, 65535};
+ for (int port: ports) {
+ actions.add(new SetTpDstAction(port));
+ }
+
short[] types = {0, 63, 112, 255};
for (short type: types) {
actions.add(new SetIcmpTypeAction(type));
@@ -140,7 +177,11 @@ public class FlowActionImplTest extends TestBase {
new SetDlSrcAction(new byte[0]),
new SetDlDstAction(new byte[]{0, 0, 0, 0, 0, 0}),
new SetVlanPcpAction((byte)-1),
+ new SetInet4SrcAction((InetAddress)null),
+ new SetInet4DstAction((InetAddress)null),
new SetDscpAction((byte)64),
+ new SetTpSrcAction(-1),
+ new SetTpDstAction(0x10000),
new SetIcmpTypeAction((short)256),
new SetIcmpCodeAction((short)-1),
};
diff --git a/manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/cluster/MacTableEntryTest.java b/manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/cluster/MacTableEntryTest.java
index 38d57531..d1aedf90 100644
--- a/manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/cluster/MacTableEntryTest.java
+++ b/manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/cluster/MacTableEntryTest.java
@@ -88,8 +88,8 @@ public class MacTableEntryTest extends TestBase {
checkMacTableEntry(me, ips, mac, nc, vlan);
- InetAddress ia
- = getInetAddressFromAddress(new byte[] {10, 1, 1, 100});
+ InetAddress ia =
+ createInetAddress(new byte[] {10, 1, 1, 100});
me = new MacTableEntry(path, mac, copy(nc),
vlan, ia);
me.setInetAddresses(ips);
diff --git a/manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/cluster/SetDlDstActionImplTest.java b/manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/cluster/SetDlDstActionImplTest.java
index 18a7787d..79969088 100644
--- a/manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/cluster/SetDlDstActionImplTest.java
+++ b/manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/cluster/SetDlDstActionImplTest.java
@@ -9,10 +9,13 @@
package org.opendaylight.vtn.manager.internal.cluster;
+import java.io.ByteArrayInputStream;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
+import javax.xml.bind.JAXB;
+
import org.junit.Test;
import org.opendaylight.vtn.manager.VTNException;
@@ -31,20 +34,21 @@ import org.opendaylight.controller.sal.utils.StatusCode;
public class SetDlDstActionImplTest extends TestBase {
/**
* Test case for getter methods.
+ *
+ * @throws Exception An unexpected exception occurred.
*/
@Test
- public void testGetter() {
+ public void testGetter() throws Exception {
for (EthernetAddress eaddr: createEthernetAddresses(false)) {
byte[] bytes = eaddr.getValue();
SetDlDstAction act = new SetDlDstAction(bytes);
try {
SetDlDstActionImpl impl = new SetDlDstActionImpl(act);
+ assertEquals(act, impl.getFlowAction());
// Ensure that MAC address bytes are copied.
- for (int i = 0; i < bytes.length; i++) {
- bytes[i] = 0;
- }
- assertEquals(act, impl.getFlowAction());
+ assertNotSame(bytes, impl.getAddress());
+ assertArrayEquals(bytes, impl.getAddress());
} catch (Exception e) {
unexpected(e);
}
@@ -95,6 +99,19 @@ public class SetDlDstActionImplTest extends TestBase {
assertEquals(StatusCode.BADREQUEST, e.getStatus().getCode());
}
}
+
+ // Specify invalid MAC address via JAXB.
+ String xml =
+ "" +
+ "";
+ ByteArrayInputStream in = new ByteArrayInputStream(xml.getBytes());
+ SetDlDstAction act = JAXB.unmarshal(in, SetDlDstAction.class);
+ try {
+ new SetDlDstActionImpl(act);
+ unexpected();
+ } catch (VTNException e) {
+ assertEquals(StatusCode.BADREQUEST, e.getStatus().getCode());
+ }
}
/**
diff --git a/manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/cluster/SetDlSrcActionImplTest.java b/manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/cluster/SetDlSrcActionImplTest.java
index 791c4873..3d1d247e 100644
--- a/manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/cluster/SetDlSrcActionImplTest.java
+++ b/manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/cluster/SetDlSrcActionImplTest.java
@@ -9,10 +9,13 @@
package org.opendaylight.vtn.manager.internal.cluster;
+import java.io.ByteArrayInputStream;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
+import javax.xml.bind.JAXB;
+
import org.junit.Test;
import org.opendaylight.vtn.manager.VTNException;
@@ -31,20 +34,21 @@ import org.opendaylight.controller.sal.utils.StatusCode;
public class SetDlSrcActionImplTest extends TestBase {
/**
* Test case for getter methods.
+ *
+ * @throws Exception An unexpected exception occurred.
*/
@Test
- public void testGetter() {
+ public void testGetter() throws Exception {
for (EthernetAddress eaddr: createEthernetAddresses(false)) {
byte[] bytes = eaddr.getValue();
SetDlSrcAction act = new SetDlSrcAction(bytes);
try {
SetDlSrcActionImpl impl = new SetDlSrcActionImpl(act);
+ assertEquals(act, impl.getFlowAction());
// Ensure that MAC address bytes are copied.
- for (int i = 0; i < bytes.length; i++) {
- bytes[i] = 0;
- }
- assertEquals(act, impl.getFlowAction());
+ assertNotSame(bytes, impl.getAddress());
+ assertArrayEquals(bytes, impl.getAddress());
} catch (Exception e) {
unexpected(e);
}
@@ -95,6 +99,19 @@ public class SetDlSrcActionImplTest extends TestBase {
assertEquals(StatusCode.BADREQUEST, e.getStatus().getCode());
}
}
+
+ // Specify invalid MAC address via JAXB.
+ String xml =
+ "" +
+ "";
+ ByteArrayInputStream in = new ByteArrayInputStream(xml.getBytes());
+ SetDlSrcAction act = JAXB.unmarshal(in, SetDlSrcAction.class);
+ try {
+ new SetDlSrcActionImpl(act);
+ unexpected();
+ } catch (VTNException e) {
+ assertEquals(StatusCode.BADREQUEST, e.getStatus().getCode());
+ }
}
/**
diff --git a/manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/cluster/SetInet4DstActionImplTest.java b/manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/cluster/SetInet4DstActionImplTest.java
new file mode 100644
index 00000000..860d3e23
--- /dev/null
+++ b/manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/cluster/SetInet4DstActionImplTest.java
@@ -0,0 +1,140 @@
+/*
+ * Copyright (c) 2014 NEC Corporation
+ * All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this
+ * distribution, and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.vtn.manager.internal.cluster;
+
+import java.io.ByteArrayInputStream;
+import java.net.InetAddress;
+import java.util.HashSet;
+import java.util.List;
+
+import javax.xml.bind.JAXB;
+
+import org.junit.Test;
+
+import org.opendaylight.vtn.manager.VTNException;
+import org.opendaylight.vtn.manager.flow.action.SetInet4DstAction;
+
+import org.opendaylight.vtn.manager.internal.TestBase;
+
+import org.opendaylight.controller.sal.utils.StatusCode;
+
+/**
+ * JUnit test for {@link SetInet4DstActionImpl}.
+ */
+public class SetInet4DstActionImplTest extends TestBase {
+ /**
+ * Test case for getter methods.
+ *
+ * @throws Exception An unexpected exception occurred.
+ */
+ @Test
+ public void testGetter() throws Exception {
+ for (InetAddress iaddr: createInet4Addresses(false)) {
+ SetInet4DstAction act = new SetInet4DstAction(iaddr);
+ SetInet4DstActionImpl impl = new SetInet4DstActionImpl(act);
+ assertEquals(act, impl.getFlowAction());
+ assertEquals(iaddr, impl.getAddress());
+ }
+
+ // null action.
+ try {
+ new SetInet4DstActionImpl(null);
+ unexpected();
+ } catch (VTNException e) {
+ assertEquals(StatusCode.BADREQUEST, e.getStatus().getCode());
+ }
+
+ // Specify invalid IP address via JAXB.
+ String[] badAddrs = {
+ null,
+ "",
+ " ",
+ "::1",
+ "Bad IP address",
+ };
+
+ String xmlDef =
+ "";
+ for (String addr: badAddrs) {
+ StringBuilder builder = new StringBuilder(xmlDef);
+ if (addr == null) {
+ builder.append("");
+ } else {
+ builder.append("");
+ }
+ ByteArrayInputStream in =
+ new ByteArrayInputStream(builder.toString().getBytes());
+ SetInet4DstAction act =
+ JAXB.unmarshal(in, SetInet4DstAction.class);
+ try {
+ new SetInet4DstActionImpl(act);
+ unexpected();
+ } catch (VTNException e) {
+ assertEquals(StatusCode.BADREQUEST, e.getStatus().getCode());
+ }
+ }
+ }
+
+ /**
+ * Test case for {@link SetInet4DstActionImpl#equals(Object)} and
+ * {@link SetInet4DstActionImpl#hashCode()}.
+ *
+ * @throws Exception An unexpected exception occurred.
+ */
+ @Test
+ public void testEquals() throws Exception {
+ HashSet