import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import org.opendaylight.controller.sal.action.SetNwTos;
+import org.opendaylight.controller.sal.utils.NetUtils;
/**
* This class describes a flow action that sets the specified value into the
/**
* Version number for serialization.
*/
- private static final long serialVersionUID = 7711399852397187977L;
+ private static final long serialVersionUID = -8431285777472515088L;
+
+ /**
+ * The number of bits in IPv4 ECN field.
+ */
+ private static final int NBITS_ECN = 2;
/**
* DSCP field value to be set.
@XmlAttribute
private byte dscp;
+ /**
+ * Convert DSCP field value into type-of-service value.
+ *
+ * @param dscp DSCP field value.
+ * @return Type-of-service field value.
+ */
+ public static byte dscpToTos(byte dscp) {
+ return (byte)(dscp << NBITS_ECN);
+ }
+
+ /**
+ * Convert type-of-service field value into DSCP value.
+ *
+ * @param tos Type-of-service field value.
+ * @return DSCP field value.
+ */
+ public static byte tosToDscp(byte tos) {
+ return (byte)(NetUtils.getUnsignedByte(tos) >>> NBITS_ECN);
+ }
+
/**
* Private constructor only for JAXB.
*/
* {@code null} is passed to {@code act}.
*/
public SetDscpAction(SetNwTos act) {
- dscp = (byte)act.getNwTos();
+ dscp = tosToDscp((byte)act.getNwTos());
}
/**
* flow filter, then the packet is discarded.
* </li>
* </ul>
+ * <p>
+ * If an unicast packet is mapped to the vBridge, and its destination
+ * MAC address is not learned in the vBridge, the packet is broadcasted
+ * to all physical network elements mapped to the vBridge.
+ * In that case all <a href="#type.REDIRECT">REDIRECT</a> flow filters
+ * configured in the vBridge and vBridge interface for outgoing packets
+ * are ignored.
+ * </p>
+ * </div>
+ *
+ * <h4 id="multicast" style="border-bottom: 1px dashed #aaaaaa;">
+ * Self-originated packet
+ * </h4>
+ * <div style="margin-left: 1em;">
+ * <p>
+ * Flow filters never affect packets originated by the VTN Manager.
+ * The following APIs may transmit self-originated ARP packet.
+ * </p>
+ * <ul>
+ * <li>
+ * {@link org.opendaylight.vtn.manager.IVTNManager#findHost(java.net.InetAddress, java.util.Set)}
+ * </li>
+ * <li>
+ * {@link org.opendaylight.vtn.manager.IVTNManager#probeHost(org.opendaylight.controller.hosttracker.hostAware.HostNodeConnector)}
+ * </li>
+ * <li>
+ * {@link org.opendaylight.controller.hosttracker.hostAware.IHostFinder#find(java.net.InetAddress)}
+ * </li>
+ * <li>
+ * {@link org.opendaylight.controller.hosttracker.hostAware.IHostFinder#probe(org.opendaylight.controller.hosttracker.hostAware.HostNodeConnector)}
+ * </li>
+ * </ul>
+ * </div>
+ *
+ * <h4 id="multicast" style="border-bottom: 1px dashed #aaaaaa;">
+ * Packet sent to the controller
+ * </h4>
+ * <div style="margin-left: 1em;">
+ * <p>
+ * Flow filters never affect packets sent to the controller.
+ * If the destination MAC address of the packet is equal to the
+ * controller's MAC address, the VTN Manager ignores all flow filters.
+ * </p>
* </div>
* </div>
*
};
short[] vlans = {1, 2, 100, 1000, 4000, 4095};
List<InetAddress> inet4Addrs = createInet4Addresses(false);
- byte[] tos = {0, 1, 20, 30, 40, 50, 60, 63};
+ byte[] dscps = {
+ 0, 1, 3, 10, 15,
+ // REVISIT: SetNwTos
+ // 30, 31, 32, 40, 50, 60, 63
+ };
int[] protocols = {
-1, 0,
IPProtocols.TCP.intValue(),
act = FlowAction.create(new SetNwSrc(iaddr), proto);
assertEquals(new SetInet4SrcAction(iaddr), act);
}
- for (byte dscp: tos) {
- act = FlowAction.create(new SetNwTos(dscp), proto);
+ for (byte dscp: dscps) {
+ int tos = (dscp << 2) & 0xff;
+ act = FlowAction.create(new SetNwTos(tos), proto);
assertEquals(new SetDscpAction(dscp), act);
}
}
int icmp = IPProtocols.ICMP.intValue();
- short[] icmpValues = {1, 2, 64, 128, 200, 255};
+ short[] icmpValues = {0, 1, 2, 64, 128, 200, 255};
for (short v: icmpValues) {
Action sal = new SetTpSrc((int)v);
FlowAction act = FlowAction.create(sal, icmp);
* JUnit test for {@link SetDscpAction}.
*/
public class SetDscpActionTest extends TestBase {
+ /**
+ * Test case for {@link SetDscpAction#dscpToTos(byte)} and
+ * {@link SetDscpAction#tosToDscp(byte)}.
+ */
+ @Test
+ public void testTos() {
+ for (byte dscp = 0; dscp <= 63; dscp++) {
+ byte tos = SetDscpAction.dscpToTos(dscp);
+ byte expected = (byte)((dscp << 2) & 0xff);
+ assertEquals(expected, tos);
+ assertEquals(dscp, SetDscpAction.tosToDscp(tos));
+ }
+ }
+
/**
* Test case for getter methods.
*/
assertEquals(b, act.getDscp());
}
- byte[] valid = {0, 1, 20, 40, 60, 63};
- for (byte b: valid) {
- SetNwTos sact = new SetNwTos((int)b);
+ // REVISIT: SetNwTos
+ for (byte b = 0; b <= 15; b++) {
+ int tos = (b << 2) & 0xff;
+ SetNwTos sact = new SetNwTos(tos);
SetDscpAction act = new SetDscpAction(sact);
assertEquals(b, act.getDscp());
}
/*
- * Copyright (c) 2013 NEC Corporation
+ * Copyright (c) 2013-2014 NEC Corporation
* All rights reserved.
*
* This program and the accompanying materials are made available under the
return new ArrayList<Action>(actionList);
}
+ /**
+ * Append all SAL actions in the given list to the tail of the action list.
+ *
+ * @param list A SAL actions.
+ * @return This object is always returned.
+ */
+ public ActionList addAll(List<? extends Action> list) {
+ if (list != null) {
+ actionList.addAll(list);
+ }
+ return this;
+ }
+
/**
* Add an output action to the tail of the action list.
*
package org.opendaylight.vtn.manager.internal;
import java.net.InetAddress;
-import java.util.Arrays;
+import java.util.ArrayList;
import java.util.EnumSet;
-import java.util.Set;
import java.util.HashSet;
-import java.util.Map;
import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.opendaylight.vtn.manager.VNodePath;
import org.opendaylight.vtn.manager.VNodeRoute;
+import org.opendaylight.vtn.manager.VTNException;
import org.opendaylight.vtn.manager.VTenantPath;
import org.opendaylight.vtn.manager.internal.cluster.MacTableEntry;
import org.opendaylight.vtn.manager.internal.cluster.MacVlan;
import org.opendaylight.vtn.manager.internal.packet.TcpPacket;
import org.opendaylight.vtn.manager.internal.packet.UdpPacket;
+import org.opendaylight.controller.sal.action.Action;
import org.opendaylight.controller.sal.core.NodeConnector;
import org.opendaylight.controller.sal.match.Match;
import org.opendaylight.controller.sal.match.MatchType;
* This class is designed to be used by a single thread.
* </p>
*/
-public class PacketContext {
+public class PacketContext implements Cloneable {
/**
* Logger instance.
*/
*/
private static final int ETHER_TYPE_MASK = 0xffff;
+ /**
+ * Flow match fields to be configured in an unicast flow entry.
+ */
+ private static final MatchType[] UNICAST_MATCHES = {
+ MatchType.DL_SRC,
+ MatchType.DL_DST,
+ };
+
/**
* A received raw packet.
*/
/**
* Decoded ethernet frame.
*/
- private final EtherPacket etherFrame;
+ private EtherPacket etherFrame;
/**
* Source IP address.
/**
* Obsolete layer 2 host entries.
*/
- private final Set<ObjectPair<MacVlan, NodeConnector>> obsoleteHosts =
+ private Set<ObjectPair<MacVlan, NodeConnector>> obsoleteHosts =
new HashSet<ObjectPair<MacVlan, NodeConnector>>();
/**
/**
* Set of virtual node paths to be associated with the data flow.
*/
- private final Set<VTenantPath> virtualNodes = new HashSet<VTenantPath>();
+ private Set<VTenantPath> virtualNodes = new HashSet<VTenantPath>();
/**
* A sequence of virtual packet routing.
*/
- private final Map<VNodePath, VNodeRoute> virtualRoute =
+ private Map<VNodePath, VNodeRoute> virtualRoute =
new LinkedHashMap<VNodePath, VNodeRoute>();
/**
* A set of {@link MatchType} instances which represents match fields
* to be configured.
*/
- private final EnumSet<MatchType> matchFields =
+ private EnumSet<MatchType> matchFields =
EnumSet.noneOf(MatchType.class);
/**
*/
private MapReference mapReference;
+ /**
+ * A list of SAL actions created by flow filters.
+ */
+ private List<Action> filterActions;
+
+ /**
+ * Set {@code true} if this packet is goint to be broadcasted in the
+ * vBridge.
+ */
+ private boolean flooding;
+
+ /**
+ * Determine whether the flow filter should be disabled or not.
+ */
+ private boolean filterDisabled;
+
+ /**
+ * Determine whether the destination MAC address of this packet is equal to
+ * the controller's MAC address or not.
+ */
+ private boolean toController;
+
/**
* Construct a new packet context.
*
/**
* Construct a new packet context from the specified ethernet frame.
*
+ * <p>
+ * This constructor is used to transmit self-originated packet.
+ * </p>
+ *
* @param ether An ethernet frame.
* @param out Outgoing node connector.
*/
PacketContext(Ethernet ether, NodeConnector out) {
this(null, ether);
outgoing = out;
+
+ // Flow filter must not affect self-originated packet.
+ filterDisabled = true;
}
/**
}
NodeConnector nc = rawPacket.getIncomingNodeConnector();
- return new PortVlan(nc, getVlan());
+ return new PortVlan(nc, etherFrame.getOriginalVlan());
}
/**
return etherFrame.getVlan();
}
+ /**
+ * Set VLAN ID used for packet matching.
+ *
+ * @param vid A VLAN ID.
+ */
+ public void setVlan(short vid) {
+ etherFrame.setVlan(vid);
+ }
+
/**
* Create a new ethernet frame which forwards the received packet.
*
// We don't strip VLAN tag with zero VLAN ID because PCP field
// in the VLAN tag should affect even if the VLAN ID is zero.
IEEE8021Q tag = new IEEE8021Q();
- byte cfi, pcp;
+ byte pcp = etherFrame.getVlanPriority();
+ if (pcp < 0) {
+ pcp = (byte)0;
+ }
+
+ byte cfi;
if (vlanTag != null) {
cfi = vlanTag.getCfi();
- pcp = vlanTag.getPcp();
} else {
cfi = (byte)0;
- pcp = (byte)0;
}
tag.setCfi(cfi).setPcp(pcp).setVid(vlan).setEtherType(ethType);
ether.setEtherType(EtherTypes.VLANTAGGED.shortValue());
return obsoleteHosts;
}
-
/**
* Purge VTN flows relevant to obsolete layer 2 host entries.
*
return NetUtils.isUnicastMACAddr(dst);
}
- /**
- * Determine whether the destination address of this packet is equal to
- * the controller address or not.
- *
- * @param mgr VTN Manager service.
- * @return {@code true} is returned if this packet is sent to the
- * controller. Otherwise {@code false} is returned.
- */
- public boolean isResponseToController(VTNManagerImpl mgr) {
- byte[] ctlrMac = mgr.getSwitchManager().getControllerMAC();
- byte[] dst = etherFrame.getDestinationAddress();
- return Arrays.equals(ctlrMac, dst);
- }
-
/**
* Set a {@link MapReference} instance that determines the ingress virtual
* node.
*/
public void setMapReference(MapReference ref) {
mapReference = ref;
+ MatchType mtype = ref.getMapType().getMatchType();
+ if (mtype != null) {
+ matchFields.add(mtype);
+ }
}
/**
int srcIp = ipv4.getSourceAddress();
byte[] dst = etherFrame.getSourceAddress();
byte[] tpa = NetUtils.intToByteArray4(srcIp);
- short vlan = getVlan();
+ short vlan = etherFrame.getOriginalVlan();
Ethernet ether = mgr.createArpRequest(dst, tpa, vlan);
NodeConnector port = getIncomingNodeConnector();
}
/**
- * Add match field to be configured into a flow entry.
+ * Add a match field to be configured into a flow entry.
*
* @param type A match type to be added.
*/
public void addMatchField(MatchType type) {
- matchFields.add(type);
+ if (!flooding) {
+ matchFields.add(type);
+ }
+ }
+
+ /**
+ * Add match fields to be configured into an unicast flow entry.
+ */
+ public void addUnicastMatchFields() {
+ if (!flooding) {
+ for (MatchType type: UNICAST_MATCHES) {
+ matchFields.add(type);
+ }
+ }
}
/**
* @return A match object that matches the packet.
*/
public Match createMatch(NodeConnector inPort) {
+ assert !flooding;
Match match = new Match();
// Incoming port field is mandatory.
*/
public int getFlowPriority(VTNManagerImpl mgr) {
int pri = mgr.getVTNConfig().getL2FlowPriority();
- return (pri + matchFields.size());
+ int nmatches = matchFields.size();
+ for (MatchType type: UNICAST_MATCHES) {
+ if (matchFields.contains(type)) {
+ nmatches--;
+ }
+ }
+
+ return (pri + nmatches);
}
/**
* @param fdb VTN flow database.
*/
public void installDropFlow(VTNManagerImpl mgr, VTNFlowDatabase fdb) {
+ if (flooding) {
+ // Never install flow entry on packet flooding.
+ return;
+ }
+
// Create a flow entry that discards the given packet.
+ if (isUnicast()) {
+ addUnicastMatchFields();
+ }
+
NodeConnector incoming = getIncomingNodeConnector();
Match match = createMatch(incoming);
int pri = getFlowPriority(mgr);
// Install a flow entry.
fdb.install(mgr, vflow);
}
+
+ /**
+ * Append a SAL action to the flow filter action list.
+ *
+ * @param act A SAL action.
+ */
+ public void addFilterAction(Action act) {
+ if (!flooding) {
+ if (filterActions == null) {
+ filterActions = new ArrayList<Action>();
+ }
+ filterActions.add(act);
+ }
+ }
+
+ /**
+ * Return a list of SAL actions created by flow filters.
+ *
+ * @return A list of SAL actions.
+ * {@code null} is returned if no SAL action was created by
+ * flow filter.
+ */
+ public List<Action> getFilterActions() {
+ return filterActions;
+ }
+
+ /**
+ * Commit all modifications to the packet.
+ *
+ * @throws VTNException
+ * Failed to copy the packet.
+ */
+ public void commit() throws VTNException {
+ etherFrame.commit(this);
+ CachedPacket l4 = l4Packet;
+ Inet4Packet inet4 = inet4Packet;
+ boolean l4Changed = (l4 != null) ? l4.commit(this) : false;
+ boolean inet4Changed = (inet4 != null) ? inet4.commit(this) : false;
+ if (l4Changed) {
+ Packet payload = l4.getPacket();
+ inet4.getPacket().setPayload(payload);
+ inet4Changed = true;
+ }
+ if (inet4Changed) {
+ IPv4 payload = inet4.getPacket();
+ etherFrame.setPayload(payload);
+ }
+ }
+
+ /**
+ * Determine whether the packet is going to be broadcasted in the vBridge
+ * or not.
+ *
+ * @return {@code true} is returned only if the packet is going to be
+ * broadcasted in the vBridge.
+ */
+ public boolean isFlooding() {
+ return flooding;
+ }
+
+ /**
+ * Set a boolean value which indicates whether the packet is going to
+ * be broadcasted in the vBridge.
+ *
+ * @param b {@code true} means that the packet is going to be broadcasted
+ * in the vBridge.
+ */
+ public void setFlooding(boolean b) {
+ flooding = b;
+ }
+
+ /**
+ * Determine whether this packet should be handled without flow filters
+ * or not.
+ *
+ * @return {@code true} is returned only if flow filters should be
+ * disabled.
+ */
+ public boolean isFilterDisabled() {
+ return filterDisabled;
+ }
+
+ /**
+ * Set a boolean value which indicates whether this packet should be
+ * handled without flow filters or not.
+ *
+ * @param b {@code true} means that this packet should be handled without
+ * flow filter.
+ * {@code false} means that flow filters should be applied to
+ * this packet.
+ */
+ public void setFilterDisabled(boolean b) {
+ filterDisabled = b;
+ }
+
+ /**
+ * Determine whether the destination address of this packet is equal to
+ * the controller address or not.
+ *
+ * @return {@code true} is returned if this packet is sent to the
+ * controller. Otherwise {@code false} is returned.
+ */
+ public boolean isToController() {
+ return toController;
+ }
+
+ /**
+ * Set a boolean value which indicates whether the packet is sent to the
+ * controller or not.
+ *
+ * @param b {@code true} means that the packet is sent to the controller.
+ * Pass {@code false} otherwise.
+ */
+ public void setToController(boolean b) {
+ toController = b;
+ if (b) {
+ // Disable flow filter.
+ filterDisabled = true;
+ }
+ }
+
+ /**
+ * Return a copy of this instance.
+ *
+ * @return A copy of this instance.
+ */
+ @Override
+ public PacketContext clone() {
+ // Currently this method is expected to be called only if the packet
+ // is flooding in the vBridge.
+ assert flooding;
+
+ try {
+ PacketContext pctx = (PacketContext)super.clone();
+ pctx.etherFrame = pctx.etherFrame.clone();
+
+ Inet4Packet inet4 = pctx.inet4Packet;
+ if (inet4 != null) {
+ pctx.inet4Packet = inet4.clone();
+ }
+
+ CachedPacket l4 = pctx.l4Packet;
+ if (l4 != null) {
+ pctx.l4Packet = l4.clone();
+ }
+
+ return pctx;
+ } catch (CloneNotSupportedException e) {
+ // This should never happen.
+ throw new IllegalStateException("clone() failed", e);
+ }
+ }
}
/**
* Version number for serialization.
*/
- private static final long serialVersionUID = 5797523592920393192L;
+ private static final long serialVersionUID = -4839160630229249797L;
/**
* Logger instance.
return true;
}
+ /**
+ * Determine whether this flow filter needs to apply flow actions to the
+ * packet.
+ *
+ * <p>
+ * This method always returns {@code false} because applying flow actions
+ * to the packet to be discarded is meaningless.
+ * </p>
+ *
+ * @return {@code false}.
+ */
+ protected boolean needFlowAction() {
+ return false;
+ }
+
/**
* Apply this DROP flow filter to the given packet.
*
public boolean match(PacketContext pctx) {
EtherPacket ether = pctx.getEtherPacket();
- // We don't need to set DL_SRC, DL_DST, DL_VLAN fields to PacketContext
- // because they are mandatory.
-
// Test source MAC address.
- if (sourceAddress != MAC_ANY &&
- sourceAddress != ether.getSourceMacAddress()) {
- return false;
+ if (sourceAddress != MAC_ANY) {
+ pctx.addMatchField(MatchType.DL_SRC);
+ if (sourceAddress != ether.getSourceMacAddress()) {
+ return false;
+ }
}
// Test destination MAC address.
- if (destinationAddress != MAC_ANY &&
- destinationAddress != ether.getDestinationMacAddress()) {
- return false;
+ if (destinationAddress != MAC_ANY) {
+ pctx.addMatchField(MatchType.DL_DST);
+ if (destinationAddress != ether.getDestinationMacAddress()) {
+ return false;
+ }
}
// Test Ethernet type.
}
// Test VLAN ID.
+ // We don't need to set DL_VLAN field to PacketContext because it is
+ // mandatory.
if (vlan != VLAN_ANY) {
if (vlan != ether.getVlan()) {
return false;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import org.opendaylight.vtn.manager.internal.PacketContext;
+
import org.opendaylight.vtn.manager.VTNException;
import org.opendaylight.vtn.manager.flow.action.FlowAction;
import org.opendaylight.vtn.manager.flow.action.SetDlDstAction;
/**
* Version number for serialization.
*/
- private static final long serialVersionUID = 6166295951874905466L;
+ private static final long serialVersionUID = 9015667825740105469L;
/**
* Suffix of action implementation class name.
CONSTRUCTORS = new HashMap<Class<?>, Constructor<?>>();
// REVISIT:
- // Currenlty flow actions that require recalculation of checksum
- // are not yet supported.
+ // Currenlty flow actions that require recalculation of TCP/UDP
+ // checksum are not yet supported.
Class<?>[] classes = {
SetDlSrcAction.class,
SetDlDstAction.class,
SetIcmpCodeAction.class,
};
- Logger log = LoggerFactory.getLogger(FlowActionImpl.class);
Package pkg = FlowActionImpl.class.getPackage();
for (Class<?> cl: classes) {
try {
setConstructor(pkg, cl);
} catch (Exception e) {
+ Logger log = LoggerFactory.getLogger(FlowActionImpl.class);
log.error("Failed to initialize implementation of " +
cl.getSimpleName(), e);
}
*/
public abstract FlowAction getFlowAction();
+ /**
+ * Apply this flow action to the given packet.
+ *
+ * @param pctx The context of the received packet.
+ * @return {@code true} is returned if this flow action is actually
+ * applied.
+ * {@code false} is returned if this flow action is ignored.
+ */
+ public abstract boolean apply(PacketContext pctx);
+
/**
* Determine whether the given object is identical to this object.
*
/**
* Version number for serialization.
*/
- private static final long serialVersionUID = -2734872622088458798L;
+ private static final long serialVersionUID = -2804474498924166254L;
/**
* The minimum value of filter index.
*/
private final List<FlowActionImpl> actions;
+ /**
+ * An internal exception to notify that this flow filter does not support
+ * the given packet.
+ */
+ private final class UnsupportedPacketException extends Exception {
+ /**
+ * Construct a new exception.
+ *
+ * @param msg A message.
+ */
+ private UnsupportedPacketException(String msg) {
+ super(msg);
+ }
+ }
+
/**
* Create a new flow filter implementation.
*
public final boolean evaluate(VTNManagerImpl mgr, PacketContext pctx,
FlowFilterMap ffmap)
throws DropFlowException {
- Logger logger = getLogger();
- if (!pctx.isUnicast() && !isMulticastSupported()) {
- if (logger.isDebugEnabled()) {
- logger.debug("{}: Ignore flow filter: " +
- "multicast packet not supported: {}",
- ffmap.getLogPrefix(index), condition);
- }
- return false;
- }
-
boolean ret = false;
- FlowCondImpl fc = mgr.getFlowCondDB().get(condition);
- if (fc == null) {
+ try {
+ FlowCondImpl fc = getCondition(mgr, pctx);
+ if (fc.match(mgr, pctx)) {
+ // Apply this flow filter.
+ if (needFlowAction()) {
+ applyFlowActions(pctx, ffmap);
+ }
+ apply(mgr, pctx, ffmap);
+ ret = true;
+ } else {
+ Logger logger = getLogger();
+ if (logger.isTraceEnabled()) {
+ logger.trace("{}: Packet does not match the condition: {}",
+ ffmap.getLogPrefix(index), condition);
+ }
+ }
+ } catch (UnsupportedPacketException e) {
+ Logger logger = getLogger();
+ String msg = e.getMessage();
if (logger.isDebugEnabled()) {
- logger.debug("{}: Ignore flow filter: condition not found: {}",
- ffmap.getLogPrefix(index), condition);
+ logger.debug("{}: Ignore flow filter: {}: {}",
+ ffmap.getLogPrefix(index), msg, condition);
}
- } else if (fc.match(mgr, pctx)) {
- // Apply this flow filter.
- apply(mgr, pctx, ffmap);
- ret = true;
- } else if (logger.isTraceEnabled()) {
- logger.trace("{}: Packet does not match the condition: {}",
- ffmap.getLogPrefix(index), condition);
}
return ret;
return false;
}
+ /**
+ * Determine whether this flow filter needs to apply flow actions to the
+ * packet.
+ *
+ * <p>
+ * This method returns {@code true} which indicates that this flow filter
+ * needs to apply flow actions configured in this instance.
+ * Subclass may override this method to ignore flow actions.
+ * </p>
+ *
+ * @return {@code true}.
+ */
+ protected boolean needFlowAction() {
+ return true;
+ }
+
+ /**
+ * Determine whether this flow filter supports packet flooding or not.
+ *
+ * <p>
+ * This method returns {@code true} which indicates that this flow filter
+ * needs to be evaluated even when the packet is going to be broadcasted
+ * in the vBridge.
+ * Subclass may override this method to ignore flow actions.
+ * </p>
+ *
+ * @return {@code true}.
+ */
+ protected boolean isFloodingSuppoted() {
+ return true;
+ }
+
/**
* Apply this flow filter to the given packet.
*
*/
protected abstract Logger getLogger();
+ /**
+ * Apply flow actions to the given packet.
+ *
+ * @param pctx A packet context which contains the packet.
+ * @param ffmap A {@link FlowFilterMap} instance that contains this
+ * flow filter.
+ */
+ private void applyFlowActions(PacketContext pctx, FlowFilterMap ffmap) {
+ Logger logger = getLogger();
+ boolean doTrace = logger.isTraceEnabled();
+ for (FlowActionImpl ai: actions) {
+ if (ai.apply(pctx)) {
+ if (doTrace) {
+ logger.trace("{}: Flow action was applied: {}",
+ ffmap.getLogPrefix(index), ai);
+ }
+ } else if (doTrace) {
+ logger.trace("{}: Flow action was ignored: {}",
+ ffmap.getLogPrefix(index), ai);
+ }
+ }
+ }
+
+ /**
+ * Return a {@link FlowCondImpl} instance which determines whether this
+ * flow filter needs to be applied to the given packet.
+ *
+ * <p>
+ * Note that this method also checks whether this flow filter supports
+ * the given packet or not.
+ * </p>
+ *
+ * @param mgr VTN Manager service.
+ * @param pctx A packet context which contains the packet.
+ * @return A {@link FlowCondImpl} instance which selects the packet.
+ * @throws UnsupportedPacketException
+ * This flow filter does not support the given packet.
+ */
+ private FlowCondImpl getCondition(VTNManagerImpl mgr, PacketContext pctx)
+ throws UnsupportedPacketException {
+ if (!pctx.isUnicast() && !isMulticastSupported()) {
+ throw new UnsupportedPacketException(
+ "multicast packet is not supported");
+ }
+
+ if (pctx.isFlooding() && !isFloodingSuppoted()) {
+ throw new UnsupportedPacketException(
+ "flooding packet is not supported");
+ }
+
+ FlowCondImpl fc = mgr.getFlowCondDB().get(condition);
+ if (fc == null) {
+ throw new UnsupportedPacketException("flow condition not found");
+ }
+
+ return fc;
+ }
+
/**
* Determine whether the given object is identical to this object.
*
/**
* Version number for serialization.
*/
- private static final long serialVersionUID = -777381317561613808L;
+ private static final long serialVersionUID = 2909825600683228034L;
/**
* Logger instance.
*/
public void evaluate(VTNManagerImpl mgr, PacketContext pctx)
throws DropFlowException {
- if (pctx.isResponseToController(mgr)) {
- if (LOG.isTraceEnabled()) {
- LOG.trace("{}:{}:{}: Ignore response to the controller: {}",
- parent.getContainerName(), parent.getPath(),
- getFlowDirectionName(output), pctx.getDescription());
+ if (pctx.isFilterDisabled()) {
+ logDisabled(mgr, pctx);
+ } else {
+ evaluateImpl(mgr, pctx);
+ }
+ }
+
+ /**
+ * Evaluate flow filters for outgoing packet.
+ *
+ * <p>
+ * This method must be called with holding the lock for the parent node.
+ * </p>
+ *
+ * @param mgr VTN Manager service.
+ * @param pctx A packet context which contains the packet.
+ * @param vid A VLAN ID for the outgoing packet.
+ * @return A {@link PacketContext} to be used for transmitting packet.
+ * @throws DropFlowException
+ * The given packet was discarded by a flow filter configured in
+ * this instance.
+ */
+ public PacketContext evaluate(VTNManagerImpl mgr, PacketContext pctx,
+ short vid)
+ throws DropFlowException {
+ if (pctx.isFilterDisabled()) {
+ logDisabled(mgr, pctx);
+ return pctx;
+ }
+
+ PacketContext pc = pctx;
+ if (!flowFilters.isEmpty()) {
+ if (pctx.isFlooding()) {
+ // We have to preserve the original incoming packet for
+ // succeeding transmission.
+ pc = pctx.clone();
}
- return;
+
+ // Use new VLAN ID for packet matching.
+ pc.setVlan(vid);
+
+ // Evaluate flow filters.
+ evaluateImpl(mgr, pc);
}
+ return pc;
+ }
+
+ /**
+ * Set the virtual node that contains this flow filter.
+ *
+ * @param fnode Virtual node that contains this flow filter.
+ */
+ void setParent(FlowFilterNode fnode) {
+ parent = fnode;
+ }
+
+ /**
+ * Evaluate flow filters configured in this instance.
+ *
+ * @param mgr VTN Manager service.
+ * @param pctx A packet context which contains the packet.
+ * @throws DropFlowException
+ * The given packet was discarded by a flow filter configured in
+ * this instance.
+ */
+ private void evaluateImpl(VTNManagerImpl mgr, PacketContext pctx)
+ throws DropFlowException {
if (LOG.isDebugEnabled()) {
LOG.debug("{}:{}:{}: Evaluating flow filter map: {}",
parent.getContainerName(), parent.getPath(),
getFlowDirectionName(output), pctx.getDescription());
}
+
for (FlowFilterImpl fi: flowFilters.values()) {
if (LOG.isTraceEnabled()) {
LOG.trace("{}: Evaluating flow filter",
}
/**
- * Set the virtual node that contains this flow filter.
+ * Record a log message that indicates the given packet disables the
+ * flow filter.
*
- * @param fnode Virtual node that contains this flow filter.
+ * @param mgr VTN Manager service.
+ * @param pctx A packet context which contains the packet.
*/
- void setParent(FlowFilterNode fnode) {
- parent = fnode;
+ private void logDisabled(VTNManagerImpl mgr, PacketContext pctx) {
+ if (LOG.isTraceEnabled()) {
+ LOG.trace("{}:{}:{}: Flow filter is disabled: {}",
+ parent.getContainerName(), parent.getPath(),
+ getFlowDirectionName(output), pctx.getDescription());
+ }
}
/**
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;
/**
* Version number for serialization.
*/
- private static final long serialVersionUID = -6711928072439846526L;
+ private static final long serialVersionUID = -5303473358097612716L;
/**
* IP address to be set.
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.
*
/**
* Version number for serialization.
*/
- private static final long serialVersionUID = 8275152227769388186L;
+ private static final long serialVersionUID = 7872635405280024017L;
/**
* Logger instance.
* Transmit the specified packet to the network established by this
* MAC mapping.
*
- * @param mgr VTN manager service.
- * @param pctx The context of the packet.
- * @param sent A set of {@link PortVlan} which indicates the network
- * already processed.
+ * @param mgr VTN manager service.
+ * @param pctx The context of the packet.
+ * @param vbr A {@link VBridgeImpl} instance which contains this
+ * MAC mapping.
+ * @param sent A set of {@link PortVlan} which indicates the network
+ * already processed.
*/
- void transmit(VTNManagerImpl mgr, PacketContext pctx, Set<PortVlan> sent) {
+ void transmit(VTNManagerImpl mgr, PacketContext pctx, VBridgeImpl vbr,
+ Set<PortVlan> sent) {
IVTNResourceManager resMgr = mgr.getResourceManager();
Set<PortVlan> networks = resMgr.getMacMappedNetworks(mgr, mapPath);
if (networks == null) {
continue;
}
- NodeConnector port = pvlan.getNodeConnector();
+ // Apply outgoing flow filters.
short vlan = pvlan.getVlan();
- Ethernet frame = pctx.createFrame(vlan);
+ PacketContext pc;
+ try {
+ pc = vbr.filterOutgoingPacket(mgr, pctx, vlan);
+ } catch (DropFlowException e) {
+ // Filtered out by DROP filter.
+ continue;
+ }
+
+ // Commit changes to the packet.
+ try {
+ pc.commit();
+ } catch (Exception e) {
+ mgr.logException(LOG, mapPath, e);
+ continue;
+ }
+
+ NodeConnector port = pvlan.getNodeConnector();
+ Ethernet frame = pc.createFrame(vlan);
if (LOG.isTraceEnabled()) {
LOG.trace("{}:{}: Transmit packet to MAC mapping: {}",
mgr.getContainerName(), mapPath,
- pctx.getDescription(frame, port, vlan));
+ pc.getDescription(frame, port, vlan));
}
mgr.transmit(port, frame);
}
}
/**
- * Evaluate flow filters configured in this virtual mapping.
+ * Evaluate flow filters for incoming packet mapped by this MAC mapping.
*
* @param mgr VTN Manager service.
* @param pctx The context of the received packet.
- * @param out {@code true} means that the given packet is an outgoing
- * packet. {@code false} means that the given packet is
- * an incoming packet.
+ */
+ @Override
+ public void filterPacket(VTNManagerImpl mgr, PacketContext pctx) {
+ // Nothing to do.
+ }
+
+ /**
+ * Evaluate flow filters for outgoing packet to be transmitted by this
+ * MAC mapping.
+ *
+ * @param mgr VTN Manager service.
+ * @param pctx The context of the received packet.
+ * @param vid A VLAN ID for the outgoing packet.
* @param bridge A {@link PortBridge} instance associated with this
* virtual mapping.
+ * @return A {@link PacketContext} to be used for transmitting packet.
* @throws DropFlowException
* The given packet was discarded by a flow filter.
*/
@Override
- public void filterPacket(VTNManagerImpl mgr, PacketContext pctx,
- boolean out, PortBridge<?> bridge)
+ public PacketContext filterPacket(VTNManagerImpl mgr, PacketContext pctx,
+ short vid, PortBridge<?> bridge)
throws DropFlowException {
- // Evaluate outgoing flow filters configured in parent vBridge.
- // vBridge incoming flow filter will be evlauated by VBridgeImpl.
- if (out) {
- bridge.filterOutgoingPacket(mgr, pctx);
- }
+ return bridge.filterOutgoingPacket(mgr, pctx, vid);
}
// Cloneable
package org.opendaylight.vtn.manager.internal.cluster;
import java.io.Serializable;
-import java.util.EnumMap;
-import java.util.Map;
import org.opendaylight.vtn.manager.VNodePath;
import org.opendaylight.vtn.manager.VNodeRoute;
*/
private static final long serialVersionUID = 7660028679508618972L;
- /**
- * Pairs of {@link MapType} and {@link Reason}.
- */
- private static final Map<MapType, Reason> MAP_REASON;
-
- /**
- * Initialize {@link #MAP_REASON}.
- */
- static {
- MAP_REASON = new EnumMap<MapType, Reason>(MapType.class);
- MAP_REASON.put(MapType.PORT, Reason.PORTMAPPED);
- MAP_REASON.put(MapType.VLAN, Reason.VLANMAPPED);
- MAP_REASON.put(MapType.MAC, Reason.MACMAPPED);
- }
-
/**
* Mapping type.
*/
* @return A {@link VNodeRoute} instance.
*/
public VNodeRoute getIngressRoute() {
- Reason reason = MAP_REASON.get(mapType);
+ Reason reason = mapType.getReason();
assert reason != null;
return new VNodeRoute(vnodePath, reason);
package org.opendaylight.vtn.manager.internal.cluster;
+import org.opendaylight.vtn.manager.VNodeRoute.Reason;
+
+import org.opendaylight.controller.sal.match.MatchType;
+
/**
* {@code MapType} class represents types of mappings between virtual and
* physical network.
/**
* Port mapping.
*/
- PORT(1 << 0),
+ PORT(1 << 0, Reason.PORTMAPPED),
/**
* MAC mapping.
*/
- MAC(1 << 1),
+ MAC(1 << 1, Reason.MACMAPPED, MatchType.DL_SRC),
/**
* VLAN mapping.
*/
- VLAN(1 << 2),
+ VLAN(1 << 2, Reason.VLANMAPPED),
/**
* A pseudo mapping type which means a wildcard.
*/
private final int mask;
+ /**
+ * A {@link Reason} instance which represents the packet is mapped by
+ * this type of virtual mapping.
+ */
+ private final Reason reason;
+
+ /**
+ * A {@link MatchType} instance which represents flow match field
+ * to be specfied in the ingress flow entry.
+ */
+ private final MatchType matchType;
+
/**
* Construct a new mapping type.
*
- * @param mask A bitmask which identifies the mapping type.
+ * @param mask A bitmask which identifies the mapping type.
*/
private MapType(int mask) {
+ this(mask, null, null);
+ }
+
+ /**
+ * Construct a new mapping type.
+ *
+ * @param mask A bitmask which identifies the mapping type.
+ * @param reason A {@link Reason} instance associated with the mapping
+ * type.
+ */
+ private MapType(int mask, Reason reason) {
+ this(mask, reason, null);
+ }
+
+ /**
+ * Construct a new mapping type.
+ *
+ * @param mask A bitmask which identifies the mapping type.
+ * @param reason A {@link Reason} instance associated with the mapping
+ * type.
+ * @param mtype A {@link MatchType} instance which represents flow match
+ * fields to specify the packet.
+ */
+ private MapType(int mask, Reason reason, MatchType mtype) {
this.mask = mask;
+ this.reason = reason;
+ matchType = mtype;
}
/**
public boolean match(MapType type) {
return ((mask & type.mask) != 0);
}
+
+ /**
+ * Return a {@link Reason} instance associated with this type of
+ * virtual mapping.
+ *
+ * @return A {@link Reason} instance.
+ */
+ public Reason getReason() {
+ return reason;
+ }
+
+ /**
+ * Return a {@link MatchType} instance which represents the flow match
+ * field to be specified in the ingress flow entry.
+ *
+ * @return A {@link MatchType} instance.
+ * {@code null} is returned if no additional match field is
+ * required.
+ */
+ public MatchType getMatchType() {
+ return matchType;
+ }
}
*/
@Override
protected void apply(VTNManagerImpl mgr, PacketContext pctx,
- FlowFilterMap ffmap) {
- // REVISIT: Not yet implemented.
+ FlowFilterMap ffmap) {
+ // Nothing to do.
}
/**
/**
* Version number for serialization.
*/
- private static final long serialVersionUID = -4413669330044382305L;
+ private static final long serialVersionUID = -1842700126892000255L;
/**
* Construct an abstract bridge node that can have port mappings.
// Evaluate flow filters configured in the virtual mapping.
// Actually this evaluates virtual interface flow filters for
// incoming packets.
- vnode.filterPacket(mgr, pctx, false, this);
+ vnode.filterPacket(mgr, pctx);
handlePacket(mgr, pctx, vnode);
} else {
*
* @param mgr VTN Manager service.
* @param pctx The context of the received packet.
+ * @param vid A VLAN ID for the outgoing packet.
+ * @return A {@link PacketContext} to be used for transmitting packet.
* @throws DropFlowException
* The given packet was discarded by a flow filter.
*/
- abstract void filterOutgoingPacket(VTNManagerImpl mgr, PacketContext pctx)
+ abstract PacketContext filterOutgoingPacket(VTNManagerImpl mgr,
+ PacketContext pctx, short vid)
throws DropFlowException;
/**
/**
* Version number for serialization.
*/
- private static final long serialVersionUID = 7145233837389323463L;
+ private static final long serialVersionUID = 7528273171488986531L;
/**
* Port mapping configuration.
return;
}
- Ethernet frame = pctx.createFrame(vlan);
+ // Apply outgoing flow filters.
Logger logger = getLogger();
+ PacketContext pc;
+ try {
+ pc = outFlowFilters.evaluate(mgr, pctx, vlan);
+ } catch (DropFlowException e) {
+ // Filtered out by DROP filter.
+ return;
+ }
+
+ // Commit changes to the packet.
+ try {
+ pc.commit();
+ } catch (Exception e) {
+ mgr.logException(logger, getPath(), e);
+ return;
+ }
+
+ Ethernet frame = pc.createFrame(vlan);
if (logger.isTraceEnabled()) {
VInterfacePath path = getInterfacePath();
logger.trace("{}:{}: Transmit packet to {} interface: {}",
getContainerName(), path, path.getNodeType(),
- pctx.getDescription(frame, mapped, vlan));
+ pc.getDescription(frame, mapped, vlan));
}
mgr.transmit(mapped, frame);
}
/**
- * Evaluate flow filters configured in this virtual mapping.
+ * Evaluate flow filters for incoming packet configured in this virtual
+ * interface.
+ *
+ * @param mgr VTN Manager service.
+ * @param pctx The context of the received packet.
+ * @throws DropFlowException
+ * The given packet was discarded by a flow filter.
+ */
+ @Override
+ public final void filterPacket(VTNManagerImpl mgr, PacketContext pctx)
+ throws DropFlowException {
+ inFlowFilters.evaluate(mgr, pctx);
+ }
+
+ /**
+ * Evaluate flow filters for outgoing packet configured in this virtual
+ * interface.
*
* @param mgr VTN Manager service.
* @param pctx The context of the received packet.
- * @param out {@code true} means that the given packet is an outgoing
- * packet. {@code false} means that the given packet is
- * an incoming packet.
* @param bridge Never used.
+ * @param vid A VLAN ID for the outgoing packet.
+ * @return A {@link PacketContext} to be used for transmitting packet.
* @throws DropFlowException
* The given packet was discarded by a flow filter.
*/
@Override
- public final void filterPacket(VTNManagerImpl mgr, PacketContext pctx,
- boolean out, PortBridge<?> bridge)
+ public final PacketContext filterPacket(VTNManagerImpl mgr,
+ PacketContext pctx, short vid,
+ PortBridge<?> bridge)
throws DropFlowException {
- FlowFilterMap ffmap = (out) ? outFlowFilters : inFlowFilters;
- ffmap.evaluate(mgr, pctx);
+ return outFlowFilters.evaluate(mgr, pctx, vid);
}
// AbstractInterface
/**
* Version number for serialization.
*/
- private static final long serialVersionUID = 4047222122155716062L;
+ private static final long serialVersionUID = -5004273201378790703L;
/**
* Logger instance.
append(",direction=").append((output) ? "out" : "in");
}
- // FlowFilterImpl
+ /**
+ * Determine whether this flow filter supports packet flooding or not.
+ *
+ * <p>
+ * This method returns {@code false} because REDIRECT filter does not
+ * support broadcast packets.
+ * </p>
+ *
+ * @return {@code false}.
+ */
+ @Override
+ protected boolean isFloodingSuppoted() {
+ return false;
+ }
/**
* Apply this REDIRECT flow filter to the given packet.
import org.opendaylight.vtn.manager.VTNException;
import org.opendaylight.vtn.manager.flow.action.SetDlDstAction;
+import org.opendaylight.vtn.manager.internal.PacketContext;
+import org.opendaylight.vtn.manager.internal.packet.EtherPacket;
+
/**
* Implementation of flow action that modifies destination MAC address in
* Ethernet frame.
/**
* Version number for serialization.
*/
- private static final long serialVersionUID = 7134765478589068419L;
+ private static final long serialVersionUID = -4389217399774516871L;
/**
* Construct a new instance.
public SetDlDstAction getFlowAction() {
return new SetDlDstAction(getAddress());
}
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public boolean apply(PacketContext pctx) {
+ EtherPacket ether = pctx.getEtherPacket();
+ byte[] addr = getAddress();
+ ether.setDestinationAddress(addr);
+ return true;
+ }
}
import org.opendaylight.vtn.manager.VTNException;
import org.opendaylight.vtn.manager.flow.action.SetDlSrcAction;
+import org.opendaylight.vtn.manager.internal.PacketContext;
+import org.opendaylight.vtn.manager.internal.packet.EtherPacket;
+
/**
* Implementation of flow action that modifies source MAC address in Ethernet
* frame.
/**
* Version number for serialization.
*/
- private static final long serialVersionUID = -4310613948193975272L;
+ private static final long serialVersionUID = -1613024024719683362L;
/**
* Construct a new instance.
public SetDlSrcAction getFlowAction() {
return new SetDlSrcAction(getAddress());
}
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public boolean apply(PacketContext pctx) {
+ EtherPacket ether = pctx.getEtherPacket();
+ byte[] addr = getAddress();
+ ether.setSourceAddress(addr);
+ return true;
+ }
}
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.vtn.manager.internal.packet.Inet4Packet;
import org.opendaylight.controller.sal.utils.StatusCode;
/**
* Version number for serialization.
*/
- private static final long serialVersionUID = -3906046474805749284L;
+ private static final long serialVersionUID = -1924798722051088828L;
/**
* DSCP field value to be set.
public SetDscpAction getFlowAction() {
return new SetDscpAction(dscp);
}
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public boolean apply(PacketContext pctx) {
+ Inet4Packet ipv4 = pctx.getInet4Packet();
+ if (ipv4 != null) {
+ ipv4.setDscp(dscp);
+ return true;
+ }
+
+ return false;
+ }
}
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.controller.sal.utils.StatusCode;
/**
* Version number for serialization.
*/
- private static final long serialVersionUID = 3037343901730872355L;
+ private static final long serialVersionUID = -875563808348172512L;
/**
* ICMP code value to be set.
public SetIcmpCodeAction getFlowAction() {
return new SetIcmpCodeAction(code);
}
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public boolean apply(PacketContext pctx) {
+ CachedPacket packet = pctx.getL4Packet();
+ if (packet instanceof IcmpPacket) {
+ IcmpPacket icmp = (IcmpPacket)packet;
+ icmp.setCode(code);
+ return true;
+ }
+
+ return false;
+ }
}
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.controller.sal.utils.StatusCode;
/**
* Version number for serialization.
*/
- private static final long serialVersionUID = 4011870176452756178L;
+ private static final long serialVersionUID = 7985609778860682790L;
/**
* ICMP type value to be set.
public SetIcmpTypeAction getFlowAction() {
return new SetIcmpTypeAction(type);
}
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public boolean apply(PacketContext pctx) {
+ CachedPacket packet = pctx.getL4Packet();
+ if (packet instanceof IcmpPacket) {
+ IcmpPacket icmp = (IcmpPacket)packet;
+ icmp.setType(type);
+ return true;
+ }
+
+ return false;
+ }
}
import org.opendaylight.vtn.manager.flow.action.SetVlanPcpAction;
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.utils.StatusCode;
/**
* Version number for serialization.
*/
- private static final long serialVersionUID = 2656305491316609840L;
+ private static final long serialVersionUID = -1355670340796521474L;
/**
* VLAN priority to be set.
public SetVlanPcpAction getFlowAction() {
return new SetVlanPcpAction(priority);
}
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public boolean apply(PacketContext pctx) {
+ EtherPacket ether = pctx.getEtherPacket();
+ ether.setVlanPriority(priority);
+ return true;
+ }
}
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;
/**
* Version number for serialization.
*/
- private static final long serialVersionUID = 2892201590657891707L;
+ private static final long serialVersionUID = -8000141230774734830L;
/**
* A port number to be set.
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.
*
/**
* Version number for serialization.
*/
- private static final long serialVersionUID = -1152732096599635100L;
+ private static final long serialVersionUID = 6513589025699567661L;
/**
* Logger instance.
return null;
}
- pctx.setEgressVNodePath(bnode.getPath());
+ VBridgePath bpath = bnode.getPath();
+ pctx.setEgressVNodePath(bpath);
// Evaluate flow filters for outgoing packets.
- bnode.filterPacket(mgr, pctx, true, this);
+ // Note that this should never clone a PacketContext.
+ bnode.filterPacket(mgr, pctx, outVlan, this);
+
+ // Commit changes to the packet.
+ try {
+ pctx.commit();
+ } catch (Exception e) {
+ mgr.logException(LOG, bpath, e, bnode.getPath());
+ return null;
+ }
return tent;
}
// Purge obsolete flows before installing new flow.
pctx.purgeObsoleteFlow(mgr, fdb);
+ // Prepare to install an unicast flow entry.
+ pctx.addUnicastMatchFields();
+
NodeConnector incoming = pctx.getIncomingNodeConnector();
- short vlan = pctx.getVlan();
+ short vlan = pctx.getEtherPacket().getOriginalVlan();
int pri = pctx.getFlowPriority(mgr);
VTNFlow vflow = fdb.create(mgr);
Match match;
Node dnode = outgoing.getNode();
assert incoming.getNode().equals(outgoing.getNode());
match = pctx.createMatch(incoming);
+
+ // Note that flow action that modifies the VLAN tag has to be set
+ // before other actions.
ActionList actions = new ActionList(dnode);
- actions.addVlanId(outVlan).addOutput(outgoing);
+ actions.addVlanId(outVlan).addAll(pctx.getFilterActions()).
+ addOutput(outgoing);
vflow.addFlow(mgr, match, actions, pri);
// Fix up the VTN flow.
* @param pctx The context of the packet.
*/
private void flood(VTNManagerImpl mgr, PacketContext pctx) {
+ // From here, REDIRECT flow filters are ignored.
+ pctx.setFlooding(true);
+
// Don't send the packet to the incoming network.
HashSet<PortVlan> sent = new HashSet<PortVlan>();
PortVlan innw = pctx.getIncomingNetwork();
// Forward packet to the network established by the MAC mapping.
MacMapImpl mmap = macMap;
if (mmap != null) {
- mmap.transmit(mgr, pctx, sent);
+ mmap.transmit(mgr, pctx, this, sent);
}
// Forward packet to the network established by the VLAN mapping.
for (VlanMapImpl vmap: vlanMaps.values()) {
- vmap.transmit(mgr, pctx, sent);
+ vmap.transmit(mgr, pctx, this, sent);
}
if (LOG.isDebugEnabled() && sent.size() == 1 && sent.contains(innw)) {
// PortBridge
/**
- * Evaluate flow filters configured in this bridge.
+ * Evaluate flow filters configured in this vBridge against the given
+ * outgoing packet.
*
* @param mgr VTN Manager service.
* @param pctx The context of the received packet.
+ * @param vid A VLAN ID for the outgoing packet.
+ * @return A {@link PacketContext} to be used for transmitting packet.
* @throws DropFlowException
* The given packet was discarded by a flow filter.
*/
@Override
- void filterOutgoingPacket(VTNManagerImpl mgr, PacketContext pctx)
+ PacketContext filterOutgoingPacket(VTNManagerImpl mgr, PacketContext pctx,
+ short vid)
throws DropFlowException {
- outFlowFilters.evaluate(mgr, pctx);
+ return outFlowFilters.evaluate(mgr, pctx, vid);
}
/**
MacAddressTable table = mgr.getMacAddressTable(bpath);
table.add(pctx, (VBridgeNode)vnode);
- if (pctx.isResponseToController(mgr)) {
+ if (pctx.isToController()) {
if (LOG.isTraceEnabled()) {
LOG.trace("{}:{}: Ignore packet sent to controller: {}",
getContainerName(), getNodePath(),
return;
}
- // Evaluate flow filters for incoming packets.
+ // Evaluate vBridge flow filters for incoming packets.
inFlowFilters.evaluate(mgr, pctx);
// Determine whether the destination address is known or not.
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.IOException;
+import java.util.Arrays;
import java.util.Iterator;
import java.util.Map;
import java.util.TreeMap;
Lock rdlock = rwLock.readLock();
rdlock.lock();
try {
+ // Determine whether the packet is sent to the controller or not.
+ boolean toCtlr = isToController(mgr, pctx);
+ if (toCtlr) {
+ pctx.setToController(toCtlr);
+ }
+
// Evaluate path maps.
RouteResolver rr = evalPathMap(mgr, pctx);
pctx.setRouteResolver(rr);
return mgr.evalPathMap(pctx, tenantConfig);
}
+ /**
+ * Determine whether the given packet is sent to the controller or not.
+ *
+ * @param mgr VTN Manager service.
+ * @param pctx The context of the received packet.
+ * @return {@code true} is returned if this packet is sent to the
+ * controller. Otherwise {@code false} is returned.
+ */
+ private boolean isToController(VTNManagerImpl mgr, PacketContext pctx) {
+ byte[] ctlrMac = mgr.getSwitchManager().getControllerMAC();
+ byte[] dst = pctx.getDestinationAddress();
+ return Arrays.equals(ctlrMac, dst);
+ }
+
// FlowFilterNode
/**
/**
* Version number for serialization.
*/
- private static final long serialVersionUID = -6198751253263625812L;
+ private static final long serialVersionUID = 518889407387134507L;
/**
* Logger instance.
// PortBridge
/**
- * Evaluate flow filters configured in this bridge.
+ * Evaluate flow filters configured in this vTerminal against the given
+ * outgoing packet.
*
* <p>
* This method does nothing because vTerminal can not have flow filters.
*
* @param mgr VTN Manager service.
* @param pctx The context of the received packet.
+ * @param vid A VLAN ID for the outgoing packet.
+ * @return A value passed to {@code pctx} is always returned.
*/
@Override
- void filterOutgoingPacket(VTNManagerImpl mgr, PacketContext pctx) {
+ PacketContext filterOutgoingPacket(VTNManagerImpl mgr, PacketContext pctx,
+ short vid) {
+ return pctx;
}
/**
import org.opendaylight.vtn.manager.VNodePath;
import org.opendaylight.vtn.manager.VNodeRoute;
+
import org.opendaylight.vtn.manager.internal.PacketContext;
import org.opendaylight.vtn.manager.internal.VTNManagerImpl;
void disableInput(VTNManagerImpl mgr, PacketContext pctx);
/**
- * Evaluate flow filters configured in this virtual mapping.
+ * Evaluate flow filters for incoming packet mapped by this virtual
+ * mapping.
+ *
+ * @param mgr VTN Manager service.
+ * @param pctx The context of the received packet.
+ * @throws DropFlowException
+ * The given packet was discarded by a flow filter.
+ */
+ void filterPacket(VTNManagerImpl mgr, PacketContext pctx)
+ throws DropFlowException;
+
+ /**
+ * Evaluate flow filters for outgoing packet to be transmitted by this
+ * virtual mapping.
*
* @param mgr VTN Manager service.
* @param pctx The context of the received packet.
- * @param out {@code true} means that the given packet is an outgoing
- * packet. {@code false} means that the given packet is
- * an incoming packet.
+ * @param vid A VLAN ID for the outgoing packet.
* @param bridge A {@link PortBridge} instance associated with this
* virtual mapping.
+ * @return A {@link PacketContext} to be used for transmitting packet.
* @throws DropFlowException
* The given packet was discarded by a flow filter.
*/
- void filterPacket(VTNManagerImpl mgr, PacketContext pctx, boolean out,
- PortBridge<?> bridge) throws DropFlowException;
+ PacketContext filterPacket(VTNManagerImpl mgr, PacketContext pctx,
+ short vid, PortBridge<?> bridge)
+ throws DropFlowException;
}
/**
* Version number for serialization.
*/
- private static final long serialVersionUID = 8889310983300538855L;
+ private static final long serialVersionUID = -2162170566149009094L;
/**
* Logger instance.
* Transmit the specified packet to the network established by this
* VLAN mapping.
*
- * @param mgr VTN manager service.
- * @param pctx The context of the packet.
- * @param sent A set of {@link PortVlan} which indicates the network
- * already processed.
+ * @param mgr VTN manager service.
+ * @param pctx The context of the packet.
+ * @param vbr A {@link VBridgeImpl} instance which contains this
+ * VLAN mapping.
+ * @param sent A set of {@link PortVlan} which indicates the network
+ * already processed.
*/
- void transmit(VTNManagerImpl mgr, PacketContext pctx, Set<PortVlan> sent) {
+ void transmit(VTNManagerImpl mgr, PacketContext pctx, VBridgeImpl vbr,
+ Set<PortVlan> sent) {
// Determine edge ports of this VLAN mapping.
IVTNResourceManager resMgr = mgr.getResourceManager();
Node node = vlanMapConfig.getNode();
return;
}
- Ethernet frame = pctx.createFrame(vlan);
+ // Apply outgoing flow filters.
+ PacketContext pc;
+ try {
+ pc = vbr.filterOutgoingPacket(mgr, pctx, vlan);
+ } catch (DropFlowException e) {
+ // Filtered out by DROP filter.
+ return;
+ }
+
+ // Commit changes to the packet.
+ try {
+ pc.commit();
+ } catch (Exception e) {
+ mgr.logException(LOG, mapPath, e);
+ return;
+ }
+
+ Ethernet frame = pc.createFrame(vlan);
for (NodeConnector nc: ports) {
PortVlan pvlan = new PortVlan(nc, vlan);
if (!sent.add(pvlan)) {
if (LOG.isTraceEnabled()) {
LOG.trace("{}:{}: Transmit packet to VLAN mapping: {}",
mgr.getContainerName(), mapPath,
- pctx.getDescription(frame, nc, vlan));
+ pc.getDescription(frame, nc, vlan));
}
mgr.transmit(nc, frame);
}
}
/**
- * Evaluate flow filters configured in this virtual mapping.
+ * Evaluate flow filters for incoming packet mapped by this VLAN mapping.
*
* @param mgr VTN Manager service.
* @param pctx The context of the received packet.
- * @param out {@code true} means that the given packet is an outgoing
- * packet. {@code false} means that the given packet is
- * an incoming packet.
+ */
+ @Override
+ public void filterPacket(VTNManagerImpl mgr, PacketContext pctx) {
+ // Nothing to do.
+ }
+
+ /**
+ * Evaluate flow filters for outgoing packet to be transmitted by this
+ * VLAN mapping.
+ *
+ * @param mgr VTN Manager service.
+ * @param pctx The context of the received packet.
+ * @param vid A VLAN ID for the outgoing packet.
* @param bridge A {@link PortBridge} instance associated with this
* virtual mapping.
+ * @return A {@link PacketContext} to be used for transmitting packet.
* @throws DropFlowException
* The given packet was discarded by a flow filter.
*/
@Override
- public void filterPacket(VTNManagerImpl mgr, PacketContext pctx,
- boolean out, PortBridge<?> bridge)
+ public PacketContext filterPacket(VTNManagerImpl mgr, PacketContext pctx,
+ short vid, PortBridge<?> bridge)
throws DropFlowException {
- // Evaluate outgoing flow filters configured in parent vBridge.
- // vBridge incoming flow filter will be evlauated by VBridgeImpl.
- if (out) {
- bridge.filterOutgoingPacket(mgr, pctx);
- }
+ return bridge.filterOutgoingPacket(mgr, pctx, vid);
}
}
import java.util.Set;
+import org.opendaylight.vtn.manager.VTNException;
+
+import org.opendaylight.vtn.manager.internal.PacketContext;
+
import org.opendaylight.controller.sal.match.Match;
import org.opendaylight.controller.sal.match.MatchType;
import org.opendaylight.controller.sal.packet.Packet;
* {@code CachedPacket} defines interfaces that implements cache for a
* {@link Packet} instance.
*/
-public interface CachedPacket {
+public interface CachedPacket extends Cloneable {
/**
* Return a {@link Packet} instance.
*
+ * <p>
+ * Note that modification to this instance is not applied to the
+ * returned until {@link #commit(PacketContext)} is called.
+ * </p>
+ *
* @return A {@link Packet} instance.
*/
Packet getPacket();
/**
* Configure match fields to test protocol header in this packet.
*
+ * <p>
+ * Note that this method creates match fields that matches the original
+ * packet. Any modification to the packet is ignored.
+ * </p>
+ *
* @param match A {@link Match} instance.
* @param fields A set of {@link MatchType} instances corresponding to
* match fields to be tested.
*/
void setMatch(Match match, Set<MatchType> fields);
+
+ /**
+ * Finalize modification to the packet.
+ *
+ * @param pctx The context of the received packet.
+ * @return {@code true} only if this packet is modified.
+ * @throws VTNException
+ * Failed to copy the packet.
+ */
+ boolean commit(PacketContext pctx) throws VTNException;
+
+ /**
+ * Return a deep copy of this instance.
+ *
+ * @return A deep copy of this instance.
+ */
+ CachedPacket clone();
}
import java.util.Set;
+import org.opendaylight.vtn.manager.internal.PacketContext;
+
+import org.opendaylight.controller.sal.action.SetDlDst;
+import org.opendaylight.controller.sal.action.SetDlSrc;
+import org.opendaylight.controller.sal.action.SetVlanPcp;
import org.opendaylight.controller.sal.match.Match;
import org.opendaylight.controller.sal.match.MatchType;
import org.opendaylight.controller.sal.packet.Ethernet;
*/
private static final byte VLANPRI_NONE = -1;
- /**
- * A pseudo VLAN priority which represents the VLAN priority is not
- * configured in Ethernet frame.
- */
- private static final byte VLANPRI_UNDEF = -2;
-
/**
* An {@link Ethernet} instance.
*/
private final IEEE8021Q vlanTag;
/**
- * A byte array which represents the source MAC address.
+ * The ethernet type.
*/
- private byte[] sourceAddress;
+ private final int etherType;
/**
- * A byte array which represents the destination MAC address.
+ * Payload of the Ethernet frame.
*/
- private byte[] destinationAddress;
+ private Packet payload;
/**
- * A long value which represents the source MAC address.
+ * Unparsed payload of the Ethernet frame.
*/
- private long sourceMac = MAC_NONE;
+ private final byte[] rawPayload;
/**
- * A long value which represents the destination MAC address.
+ * Cached values in Ethernet header.
*/
- private long destinationMac = MAC_NONE;
+ private Values values;
/**
- * The ethernet type.
+ * Ethernet header values to be set.
*/
- private final int etherType;
+ private Values modifiedValues;
/**
- * The VLAN ID.
+ * This class describes modifiable fields in Ethernet header.
*/
- private short vlan = VLAN_NONE;
+ private static final class Values implements Cloneable {
+ /**
+ * A byte array which represents the source MAC address.
+ */
+ private byte[] sourceAddress;
+
+ /**
+ * A byte array which represents the destination MAC address.
+ */
+ private byte[] destinationAddress;
+
+ /**
+ * A long value which represents the source MAC address.
+ */
+ private long sourceMac = MAC_NONE;
+
+ /**
+ * A long value which represents the destination MAC address.
+ */
+ private long destinationMac = MAC_NONE;
+
+ /**
+ * The VLAN ID.
+ */
+ private short vlan;
+
+ /**
+ * The VLAN priority.
+ */
+ private byte vlanPriority = VLANPRI_NONE;
+
+ /**
+ * Constructor.
+ *
+ * @param vid VLAN ID in the original Ethernet frame.
+ */
+ private Values(short vid) {
+ vlan = vid;
+ }
- /**
- * The VLAN priority.
- */
- private byte vlanPriority = VLANPRI_NONE;
+ /**
+ * Return the source MAC address as a byte array.
+ *
+ * @return The source MAC address.
+ * {@code null} is returned if not configured.
+ */
+ private byte[] getSourceAddress() {
+ return sourceAddress;
+ }
- /**
- * Payload of the Ethernet frame.
- */
- private final Packet payload;
+ /**
+ * Set the source MAC address.
+ *
+ * @param addr A byte array that represents the source MAC address.
+ */
+ private void setSourceAddress(byte[] addr) {
+ sourceAddress = addr.clone();
+ sourceMac = NetUtils.byteArray6ToLong(sourceAddress);
+ }
- /**
- * Unparsed payload of the Ethernet frame.
- */
- private final byte[] rawPayload;
+ /**
+ * Return the destination MAC address as a byte array.
+ *
+ * @return The destination MAC address.
+ * {@code null} is returned if not configured.
+ */
+ private byte[] getDestinationAddress() {
+ return destinationAddress;
+ }
+
+ /**
+ * Set the destination MAC address.
+ *
+ * @param addr A byte array that represents the destination
+ * MAC address.
+ */
+ private void setDestinationAddress(byte[] addr) {
+ destinationAddress = addr.clone();
+ destinationMac = NetUtils.byteArray6ToLong(destinationAddress);
+ }
+
+ /**
+ * Return the source MAC address as a long integer.
+ *
+ * @return The source MAC address.
+ * {@link EtherPacket#MAC_NONE} is returned if not configured.
+ */
+ private long getSourceMacAddress() {
+ return sourceMac;
+ }
+
+ /**
+ * Return the destination MAC address as a long integer.
+ *
+ * @return The destination MAC address.
+ * {@link EtherPacket#MAC_NONE} is returned if not configured.
+ */
+ private long getDestinationMacAddress() {
+ return destinationMac;
+ }
+
+ /**
+ * Return the VLAN ID.
+ *
+ * @return A VLAN ID.
+ * {@link EtherPacket#VLAN_NONE} is returned if not
+ * configured.
+ */
+ private short getVlan() {
+ return vlan;
+ }
+
+ /**
+ * Set the VLAN ID.
+ *
+ * @param vid A VLAN ID.
+ */
+ private void setVlan(short vid) {
+ vlan = vid;
+ }
+
+ /**
+ * Return the VLAN priority.
+ *
+ * @return A byte value which represents the VLAN priority.
+ * {@link EtherPacket#VLANPRI_NONE} is returned if not
+ * configured.
+ */
+ private byte getVlanPriority() {
+ return vlanPriority;
+ }
+
+ /**
+ * Set the VLAN priority.
+ *
+ * @param pri A VLAN priority.
+ */
+ private void setVlanPriority(byte pri) {
+ vlanPriority = pri;
+ }
+
+ /**
+ * Fetch all modifiable field values from the given packet.
+ *
+ * <p>
+ * Field values already cached in this instance are preserved.
+ * </p>
+ *
+ * @param ether An {@link Ethernet} instance.
+ * @param tag An {@link IEEE8021Q} instance.
+ */
+ private void fill(Ethernet ether, IEEE8021Q tag) {
+ if (sourceMac == MAC_NONE) {
+ setSourceAddress(ether.getSourceMACAddress());
+ }
+ if (destinationMac == MAC_NONE) {
+ setDestinationAddress(ether.getDestinationMACAddress());
+ }
+ if (vlanPriority == VLANPRI_NONE && tag != null) {
+ vlanPriority = tag.getPcp();
+ }
+ }
+
+ /**
+ * 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);
+ }
+ }
+ }
/**
* Construct a new instance.
Packet parent = ether;
Packet pld = ether.getPayload();
short ethType;
+ short vid;
if (pld instanceof IEEE8021Q) {
// This packet has a VLAN tag.
vlanTag = (IEEE8021Q)pld;
pld = vlanTag.getPayload();
ethType = vlanTag.getEtherType();
parent = vlanTag;
+ vid = vlanTag.getVid();
} else {
ethType = ether.getEtherType();
vlanTag = null;
+ vid = 0;
}
+ values = new Values(vid);
etherType = NetUtils.getUnsignedShort(ethType);
payload = pld;
rawPayload = parent.getRawPayload();
* @return The source MAC address.
*/
public byte[] getSourceAddress() {
- if (sourceAddress == null) {
- sourceAddress = packet.getSourceMACAddress();
+ Values v = getValues();
+ byte[] addr = v.getSourceAddress();
+ if (addr == null) {
+ addr = packet.getSourceMACAddress();
+ v.setSourceAddress(addr);
}
- return sourceAddress;
+ return addr;
+ }
+
+ /**
+ * Set the source MAC address.
+ *
+ * @param addr A byte array that represents the source MAC address.
+ */
+ public void setSourceAddress(byte[] addr) {
+ getModifiedValues().setSourceAddress(addr);
}
/**
* @return The destination MAC address.
*/
public byte[] getDestinationAddress() {
- if (destinationAddress == null) {
- destinationAddress = packet.getDestinationMACAddress();
+ Values v = getValues();
+ byte[] addr = v.getDestinationAddress();
+ if (addr == null) {
+ addr = packet.getDestinationMACAddress();
+ v.setDestinationAddress(addr);
}
- return destinationAddress;
+ return addr;
+ }
+
+ /**
+ * Set the source MAC address.
+ *
+ * @param addr A byte array that represents the source MAC address.
+ */
+ public void setDestinationAddress(byte[] addr) {
+ getModifiedValues().setDestinationAddress(addr);
}
/**
* @return The source MAC address.
*/
public long getSourceMacAddress() {
- if (sourceMac == MAC_NONE) {
- byte[] addr = getSourceAddress();
- sourceMac = NetUtils.byteArray6ToLong(addr);
+ Values v = getValues();
+ long mac = v.getSourceMacAddress();
+ if (mac == MAC_NONE) {
+ byte[] addr = packet.getSourceMACAddress();
+ v.setSourceAddress(addr);
+ mac = v.getSourceMacAddress();
}
- return sourceMac;
+ return mac;
}
/**
* @return The destination MAC address.
*/
public long getDestinationMacAddress() {
- if (destinationMac == MAC_NONE) {
- byte[] addr = getDestinationAddress();
- destinationMac = NetUtils.byteArray6ToLong(addr);
+ Values v = getValues();
+ long mac = v.getDestinationMacAddress();
+ if (mac == MAC_NONE) {
+ byte[] addr = packet.getDestinationMACAddress();
+ v.setDestinationAddress(addr);
+ mac = v.getDestinationMacAddress();
}
- return destinationMac;
+ return mac;
}
/**
return etherType;
}
+ /**
+ * Return the VLAN ID in the original Ethernet frame.
+ *
+ * @return A short value which represents the VLAN ID.
+ * Zero is returned if no VLAN tag was found in the original
+ * Ethernet frame.
+ */
+ public short getOriginalVlan() {
+ return values.getVlan();
+ }
+
/**
* Return the VLAN ID.
*
* frame.
*/
public short getVlan() {
- if (vlan == VLAN_NONE) {
- vlan = (vlanTag == null) ? 0 : vlanTag.getVid();
- }
+ // VLAN ID is always cached.
+ return getValues().getVlan();
+ }
- return vlan;
+ /**
+ * Set the VLAN ID.
+ *
+ * @param vid A VLAN ID.
+ */
+ public void setVlan(short vid) {
+ getModifiedValues().setVlan(vid);
}
/**
*
* @return A byte value which represents the VLAN priority.
* A negative value is returned if no VLAN tag was found in
- * the Ethernet frame.
+ * the Ethernet frame and no VLAN priority is set by the call of
+ * {@link #setVlanPriority(byte)}.
*/
public byte getVlanPriority() {
- if (vlanPriority == VLANPRI_NONE) {
- vlanPriority = (vlanTag == null)
- ? VLANPRI_UNDEF : vlanTag.getPcp();
+ Values v = getValues();
+ byte pri = v.getVlanPriority();
+ if (pri == VLANPRI_NONE && vlanTag != null) {
+ pri = vlanTag.getPcp();
+ v.setVlanPriority(pri);
}
- return vlanPriority;
+ return pri;
+ }
+
+ /**
+ * Set the VLAN priority.
+ *
+ * @param pri A VLAN priority.
+ */
+ public void setVlanPriority(byte pri) {
+ getModifiedValues().setVlanPriority(pri);
}
/**
* Return the VLAN tag in the Ethernet frame.
*
+ * <p>
+ * Note that this method returns the VLAN tag in the original Ethernet
+ * frame. Any modification to VLAN tag is never applied to the returned
+ * value even if {@link #commit(PacketContext)} is called.
+ * </p>
+ *
* @return An {@link IEEE8021Q} instance which represents the VLAN tag.
* {@code null} is returned if no VLAN tag was found in the
* Ethernet frame.
return payload;
}
+ /**
+ * Set the payload of the Ethernet frame.
+ *
+ * @param packet The payload of the Ethernet frame.
+ */
+ public void setPayload(Packet packet) {
+ payload = packet;
+ }
+
/**
* Return the unparsed payload in the Ethernet frame.
*
return rawPayload;
}
+ /**
+ * Return a {@link Values} instance that keeps current values for
+ * Ethernet header fields.
+ *
+ * @return A {@link Values} instance.
+ */
+ private Values getValues() {
+ return (modifiedValues == null) ? values : modifiedValues;
+ }
+
+ /**
+ * Return a {@link Values} instance that keeps Ethernet header field values
+ * to be set.
+ *
+ * @return A {@link Values} instance.
+ */
+ private Values getModifiedValues() {
+ if (modifiedValues == null) {
+ values.fill(packet, vlanTag);
+ modifiedValues = values.clone();
+ }
+
+ return modifiedValues;
+ }
+
// CachedPacket
/**
* Return an {@link Ethernet} instance configured in this instance.
*
+ * <p>
+ * Note that this method returns the original ethernet frame.
+ * Any modification to Ethernet header field is never applied to the
+ * returned value even if {@link #commit(PacketContext)} is called.
+ * </p>
+ *
* @return An {@link Ethernet} instance.
*/
@Override
/**
* Configure match fields to test Ethernet header in this packet.
*
+ * <p>
+ * Note that this method creates match fields that matches the original
+ * packet. Any modification to the packet is ignored.
+ * </p>
+ *
* @param match A {@link Match} instance.
* @param fields A set of {@link MatchType} instances corresponding to
* match fields to be tested.
*/
@Override
public void setMatch(Match match, Set<MatchType> fields) {
- // Source and destination MAC address, and VLAN ID fields are
- // mandatory.
- match.setField(MatchType.DL_SRC, getSourceAddress());
- match.setField(MatchType.DL_DST, getDestinationAddress());
+ Values v = values;
+ v.fill(packet, vlanTag);
- // This code expects MatchType.DL_VLAN_NONE is zero.
- short vid = getVlan();
+ // VLAN ID field is mandatory.
+ // Note that this code expects MatchType.DL_VLAN_NONE is zero.
+ short vid = v.getVlan();
match.setField(MatchType.DL_VLAN, vid);
+ MatchType type = MatchType.DL_SRC;
+ if (fields.contains(type)) {
+ // Test source MAC address.
+ match.setField(type, v.getSourceAddress());
+ }
+
+ type = MatchType.DL_DST;
+ if (fields.contains(type)) {
+ // Test destination MAC address.
+ match.setField(type, v.getDestinationAddress());
+ }
+
// Test VLAN priority only if this packet has a VLAN tag.
if (vid != MatchType.DL_VLAN_NONE) {
- MatchType type = MatchType.DL_VLAN_PR;
+ type = MatchType.DL_VLAN_PR;
if (fields.contains(type)) {
- match.setField(type, getVlanPriority());
+ match.setField(type, v.getVlanPriority());
}
}
- MatchType type = MatchType.DL_TYPE;
+ type = MatchType.DL_TYPE;
if (fields.contains(type)) {
// Test Ethernet type.
match.setField(type, (short)etherType);
}
}
+
+ /**
+ * {@inheritDoc}
+ */
+ @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.
+ 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;
+ }
+
+ if (values.getDestinationMacAddress() !=
+ modifiedValues.getDestinationMacAddress()) {
+ // Destination MAC address was modified.
+ byte[] addr = modifiedValues.getDestinationAddress();
+ pctx.addFilterAction(new SetDlDst(addr));
+ mod = true;
+ }
+
+ short vlan = modifiedValues.getVlan();
+ if (vlan != 0) {
+ byte pri = modifiedValues.getVlanPriority();
+ if (values.getVlanPriority() != pri) {
+ // VLAN priority was modified.
+ pctx.addFilterAction(new SetVlanPcp((int)pri));
+ mod = true;
+ }
+ }
+ }
+
+ return mod;
+ }
+
+ /**
+ * Return a deep copy of this instance.
+ *
+ * <p>
+ * Note that this method does not copy the original Ethernet header and
+ * VLAN tag because this class never modifies them.
+ * </p>
+ *
+ * @return A deep copy of this instance.
+ */
+ @Override
+ public EtherPacket clone() {
+ try {
+ EtherPacket ether = (EtherPacket)super.clone();
+ Values v = ether.values;
+ ether.values = v.clone();
+
+ v = ether.modifiedValues;
+ if (v != null) {
+ ether.modifiedValues = v.clone();
+ }
+
+ return ether;
+ } catch (CloneNotSupportedException e) {
+ // This should never happen.
+ throw new IllegalStateException("clone() failed", e);
+ }
+ }
}
import java.util.Set;
+import org.opendaylight.vtn.manager.VTNException;
+
+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.ICMP;
private static final short VALUE_NONE = -1;
/**
- * The ICMP type.
+ * An {@link ICMP} packet.
*/
- private short type = VALUE_NONE;
+ private ICMP packet;
/**
- * The ICMP code.
+ * Cached values in ICMP header.
*/
- private short code = VALUE_NONE;
+ private Values values = new Values();
/**
- * An {@link ICMP} packet.
+ * ICMP header values to be set.
*/
- private final ICMP packet;
+ private Values modifiedValues;
+
+ /**
+ * Set {@code true} if this instance is created by {@link #clone()}.
+ */
+ private boolean cloned;
+
+ /**
+ * This class describes modifiable fields in ICMPv4 hedaer.
+ */
+ private static final class Values implements Cloneable {
+ /**
+ * The ICMP type.
+ */
+ private short type = VALUE_NONE;
+
+ /**
+ * The ICMP code.
+ */
+ private short code = VALUE_NONE;
+
+ /**
+ * Constructor.
+ */
+ private Values() {
+ }
+
+ /**
+ * Return the ICMP type.
+ *
+ * @return A short integer value which indicates the ICMP type.
+ * {@link IcmpPacket#VALUE_NONE} is returned if not
+ * configured.
+ */
+ private short getType() {
+ return type;
+ }
+
+ /**
+ * Set the ICMP type.
+ *
+ * @param value A short integer value which indicates the ICMP type.
+ */
+ private void setType(short value) {
+ type = value;
+ }
+
+ /**
+ * Set the ICMP type.
+ *
+ * @param value A byte integer value which indicates the ICMP type.
+ */
+ private void setType(byte value) {
+ type = (short)NetUtils.getUnsignedByte(value);
+ }
+
+ /**
+ * Return the ICMP code.
+ *
+ * @return A short integer value which indicates the ICMP code.
+ * {@link IcmpPacket#VALUE_NONE} is returned if not
+ * configured.
+ */
+ private short getCode() {
+ return code;
+ }
+
+ /**
+ * Set the ICMP code.
+ *
+ * @param value A short integer value which indicates the ICMP code.
+ */
+ private void setCode(short value) {
+ code = value;
+ }
+
+ /**
+ * Set the ICMP code.
+ *
+ * @param value A byte integer value which indicates the ICMP code.
+ */
+ private void setCode(byte value) {
+ code = (short)NetUtils.getUnsignedByte(value);
+ }
+
+ /**
+ * Fetch all modifiable field values from the given packet.
+ *
+ * <p>
+ * Field values already cached in this instance are preserved.
+ * </p>
+ *
+ * @param icmp An {@link ICMP} instance.
+ */
+ private void fill(ICMP icmp) {
+ if (type != VALUE_NONE) {
+ setType(icmp.getType());
+ }
+ if (code != VALUE_NONE) {
+ setCode(icmp.getCode());
+ }
+ }
+
+ /**
+ * 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);
+ }
+ }
+ }
/**
* Construct a new instance.
* @return A short integer value which indicates the ICMP type.
*/
public short getType() {
+ Values v = getValues();
+ short type = v.getType();
if (type == VALUE_NONE) {
byte b = packet.getType();
- type = (short)NetUtils.getUnsignedByte(b);
+ v.setType(b);
}
return type;
}
+ /**
+ * Set the ICMP type.
+ *
+ * @param type A short integer value which indicates the ICMP type.
+ */
+ public void setType(short type) {
+ Values v = getModifiedValues();
+ v.setType(type);
+ }
+
/**
* Return the ICMP code.
*
* @return A short integer value which indicates the ICMP code.
*/
public short getCode() {
+ Values v = getValues();
+ short code = v.getCode();
if (code == VALUE_NONE) {
byte b = packet.getCode();
- code = (short)NetUtils.getUnsignedByte(b);
+ v.setCode(b);
}
return code;
}
+ /**
+ * Set the ICMP code.
+ *
+ * @param code A short integer value which indicates the ICMP code.
+ */
+ public void setCode(short code) {
+ Values v = getModifiedValues();
+ v.setCode(code);
+ }
+
+ /**
+ * Return a {@link Values} instance that keeps current values for
+ * ICMP header fields.
+ *
+ * @return A {@link Values} instance.
+ */
+ private Values getValues() {
+ return (modifiedValues == null) ? values : modifiedValues;
+ }
+
+ /**
+ * Return a {@link Values} instance that keeps ICMP header field values
+ * to be set.
+ *
+ * @return A {@link Values} instance.
+ */
+ private Values getModifiedValues() {
+ if (modifiedValues == null) {
+ values.fill(packet);
+ modifiedValues = values.clone();
+ }
+
+ return modifiedValues;
+ }
+
+ /**
+ * Return an {@link ICMP} instance to set modified values.
+ *
+ * @return An {@link ICMP} instance.
+ * @throws VTNException
+ * Failed to copy the packet.
+ */
+ 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);
+ }
+
+ cloned = false;
+ }
+
+ return packet;
+ }
+
// CachedPacket
/**
* Return a {@link ICMP} instance configured in this instance.
*
+ * <p>
+ * Note that modification to the ICMP header is not applied to the
+ * returned until {@link #commit(PacketContext)} is called.
+ * </p>
+ *
* @return A {@link ICMP} instance.
*/
@Override
/**
* Configure match fields to test ICMP header in this packet.
*
+ * <p>
+ * Note that this method creates match fields that matches the original
+ * packet. Any modification to the packet is ignored.
+ * </p>
+ *
* @param match A {@link Match} instance.
* @param fields A set of {@link MatchType} instances corresponding to
* match fields to be tested.
*/
@Override
public void setMatch(Match match, Set<MatchType> fields) {
+ Values v = values;
+ v.fill(packet);
+
MatchType mt = MatchType.TP_SRC;
if (fields.contains(mt)) {
// Test ICMP type.
- match.setField(mt, getType());
+ match.setField(mt, v.getType());
}
mt = MatchType.TP_DST;
if (fields.contains(mt)) {
// Test ICMP code.
- match.setField(mt, getCode());
+ match.setField(mt, v.getCode());
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public boolean commit(PacketContext pctx) throws VTNException {
+ boolean mod = false;
+ ICMP icmp = null;
+ if (modifiedValues != null) {
+ 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;
+ }
+
+ 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);
+ }
+ }
+
+ return mod;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public IcmpPacket clone() {
+ try {
+ IcmpPacket icmp = (IcmpPacket)super.clone();
+ Values v = icmp.values;
+ icmp.values = v.clone();
+
+ v = icmp.modifiedValues;
+ if (v != null) {
+ icmp.modifiedValues = v.clone();
+ }
+ icmp.cloned = true;
+
+ return icmp;
+ } catch (CloneNotSupportedException e) {
+ // This should never happen.
+ throw new IllegalStateException("clone() failed", e);
}
}
}
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.SetNwTos;
import org.opendaylight.controller.sal.match.Match;
import org.opendaylight.controller.sal.match.MatchType;
import org.opendaylight.controller.sal.packet.IPv4;
/**
* An {@link IPv4} packet.
*/
- private final IPv4 packet;
+ private IPv4 packet;
/**
* An integer value which indicates the source IP address.
private short protocol = PROTO_NONE;
/**
- * The DSCP field value in the IPv4 packet.
+ * Cached values in IPv4 header.
*/
- private byte dscp = PROTO_NONE;
+ private Values values = new Values();
+
+ /**
+ * IPv4 header values to be set.
+ */
+ private Values modifiedValues;
+
+ /**
+ * Set {@code true} if this instance is created by {@link #clone()}.
+ */
+ private boolean cloned;
+
+ /**
+ * This class describes modifiable fields in IPv4 header.
+ */
+ private static final class Values implements Cloneable {
+ /**
+ * 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 DSCP field value.
+ *
+ * @return A byte value which indicates the DSCP field value.
+ * {@link Inet4Packet#DSCP_NONE} is returned if not
+ * configured.
+ */
+ private byte getDscp() {
+ return dscp;
+ }
+
+ /**
+ * Set the DSCP field value.
+ *
+ * @param value A byte value which indicates the DSCP field value.
+ */
+ private void setDscp(byte value) {
+ dscp = value;
+ }
+
+ /**
+ * Fetch all modifiable field values from the given packet.
+ *
+ * <p>
+ * Field values already cached in this instance are preserved.
+ * </p>
+ *
+ * @param ipv4 An {@link IPv4} instance.
+ */
+ private void fill(IPv4 ipv4) {
+ if (dscp != DSCP_NONE) {
+ dscp = ipv4.getDiffServ();
+ }
+ }
+
+ /**
+ * 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);
+ }
+ }
+ }
/**
* Construct a new instance.
* @return A byte value which indicates the DSCP field value.
*/
public byte getDscp() {
+ Values v = getValues();
+ byte dscp = v.getDscp();
if (dscp == DSCP_NONE) {
dscp = packet.getDiffServ();
+ v.setDscp(dscp);
}
return dscp;
}
+ /**
+ * Set the DSCP field value.
+ *
+ * @param dscp A byte value which indicates the DSCP field value.
+ */
+ public void setDscp(byte dscp) {
+ Values v = getModifiedValues();
+ v.setDscp(dscp);
+ }
+
+ /**
+ * Return a {@link Values} instance that keeps current values for
+ * IPv4 header fields.
+ *
+ * @return A {@link Values} instance.
+ */
+ private Values getValues() {
+ return (modifiedValues == null) ? values : modifiedValues;
+ }
+
+ /**
+ * Return a {@link Values} instance that keeps IPv4 header field values to
+ * be set.
+ *
+ * @return A {@link Values} instance.
+ */
+ private Values getModifiedValues() {
+ if (modifiedValues == null) {
+ values.fill(packet);
+ modifiedValues = values.clone();
+ }
+
+ return modifiedValues;
+ }
+
+ /**
+ * Return an {@link IPv4} instance to set modified values.
+ *
+ * @return An {@link IPv4} instance.
+ * @throws VTNException
+ * Failed to copy the packet.
+ */
+ 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);
+ }
+
+ cloned = false;
+ }
+
+ return packet;
+ }
+
// CachedPacket
/**
* Return an {@link IPv4} instance configured in this instance.
*
+ * <p>
+ * Note that modification to the IPv4 header is not applied to the
+ * returned until {@link #commit(PacketContext)} is called.
+ * </p>
+ *
* @return An {@link IPv4} instance.
*/
@Override
/**
* Configure match fields to test IP header in this packet.
*
+ * <p>
+ * Note that this method creates match fields that matches the original
+ * packet. Any modification to the packet is ignored.
+ * </p>
+ *
* @param match A {@link Match} instance.
* @param fields A set of {@link MatchType} instances corresponding to
* match fields to be tested.
*/
@Override
public void setMatch(Match match, Set<MatchType> fields) {
+ Values v = values;
+ v.fill(packet);
+
MatchType type = MatchType.NW_SRC;
if (fields.contains(type)) {
// Test source IP address.
type = MatchType.NW_TOS;
if (fields.contains(type)) {
// Test DSCP field.
- match.setField(type, getDscp());
+ match.setField(type, v.getDscp());
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public boolean commit(PacketContext pctx) throws VTNException {
+ boolean mod = false;
+ if (modifiedValues != null) {
+ 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();
+ ipv4.setDiffServ(dscp);
+ mod = true;
+ }
+ }
+
+ return mod;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public Inet4Packet clone() {
+ try {
+ Inet4Packet ip = (Inet4Packet)super.clone();
+ Values v = ip.values;
+ ip.values = v.clone();
+
+ v = ip.modifiedValues;
+ if (v != null) {
+ ip.modifiedValues = v.clone();
+ }
+ ip.cloned = true;
+
+ return ip;
+ } catch (CloneNotSupportedException e) {
+ // This should never happen.
+ throw new IllegalStateException("clone() failed", e);
}
}
}
import java.util.Set;
+import org.opendaylight.vtn.manager.internal.PacketContext;
+
import org.opendaylight.controller.sal.match.Match;
import org.opendaylight.controller.sal.match.MatchType;
import org.opendaylight.controller.sal.utils.NetUtils;
match.setField(type, (short)getDestinationPort());
}
}
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public final boolean commit(PacketContext pctx) {
+ // REVISIT: Not yet supported.
+ return false;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public final PortProtoPacket clone() {
+ try {
+ return (PortProtoPacket)super.clone();
+ } catch (CloneNotSupportedException e) {
+ // This should never happen.
+ throw new IllegalStateException("clone() failed", e);
+ }
+ }
}
for (MatchType type : match.getMatchesList()) {
MatchField field = match.getField(type);
if (type == MatchType.DL_SRC) {
- assertEquals(field.getValue(), src);
+ assertArrayEquals((byte[])field.getValue(), src);
} else if (type == MatchType.DL_DST) {
- assertEquals(field.getValue(), dst);
+ assertArrayEquals((byte[])field.getValue(), dst);
} else if (type == MatchType.DL_VLAN) {
assertEquals(field.getValue(), (vlan > 0) ? vlan : 0);
} else if (type == MatchType.IN_PORT) {
return pctx;
}
+ /**
+ * Create a {@link PacketContext} object for unicast packet transmission.
+ *
+ * @param eth A {@link Ethernet} object.
+ * @param nc A incoming node connector.
+ * @return A {@link PacketContext} object.
+ */
+ protected PacketContext createUnicastPacketContext(Ethernet eth,
+ NodeConnector nc) {
+ PacketContext pctx = createPacketContext(eth, nc);
+ pctx.addUnicastMatchFields();
+ return pctx;
+ }
+
/**
* create a {@link RawPacket} object.
*
protected PacketContext createARPPacketContext(byte[] src, byte[] dst,
byte[] sender, byte[] target, short vlan, NodeConnector nc,
short arptype) {
- return createPacketContext(
+ return createUnicastPacketContext(
createARPPacket(src, dst, sender, target, vlan, arptype), nc);
}
*/
protected PacketContext createIPv4PacketContext(byte[] src, byte[] dst,
byte[] sender, byte[] target, short vlan, NodeConnector nc) {
- return createPacketContext(
+ return createUnicastPacketContext(
createIPv4Packet(src, dst, sender, target, vlan), nc);
}
}
/**
- * Evaluate flow filters configured in this virtual mapping.
+ * Evaluate flow filters for incoming packet mapped by this virtual
+ * mapping.
*
* @param mgr VTN Manager service.
* @param pctx The context of the received packet.
- * @param out {@code true} means that the given packet is an outgoing
- * packet. {@code false} means that the given packet is
- * an incoming packet.
+ */
+ @Override
+ public void filterPacket(VTNManagerImpl mgr, PacketContext pctx) {
+ }
+
+ /**
+ * Evaluate flow filters for outgoing packet to be transmitted by this
+ * virtual mapping.
+ *
+ * @param mgr VTN Manager service.
+ * @param pctx The context of the received packet.
+ * @param vid A VLAN ID for the outgoing packet.
* @param bridge A {@link PortBridge} instance associated with this
* virtual mapping.
+ * @return A {@link PacketContext} to be used for transmitting packet.
*/
@Override
- public void filterPacket(VTNManagerImpl mgr, PacketContext pctx,
- boolean out, PortBridge<?> bridge) {
+ public PacketContext filterPacket(VTNManagerImpl mgr, PacketContext pctx,
+ short vid, PortBridge<?> bridge) {
+ return pctx;
}
}
IDataPacketService pktSrv = vtnMgr.getDataPacketService();
Packet decoded = pktSrv.decodeDataPacket(pkt);
PacketContext pctx = new PacketContext(pkt, (Ethernet)decoded);
+ pctx.addUnicastMatchFields();
// Packet.equals(Object) will not work if it contains byte array.
// So we need to compare serialized payload.
assertNotNull(port);
Packet decoded = stubObj.decodeDataPacket(pkt);
PacketContext pctx = new PacketContext((Ethernet)decoded, port);
+ pctx.addUnicastMatchFields();
try {
byte[] pld = pctx.getPayload().serialize();
import org.junit.Test;
+import org.opendaylight.vtn.manager.VNodeRoute.Reason;
+
import org.opendaylight.vtn.manager.internal.TestBase;
+import org.opendaylight.controller.sal.match.MatchType;
+
/**
* JUnit test for {@link MapType}.
*/
public class MapTypeTest extends TestBase {
+ /**
+ * Verify parameters configured in {@link MapType}.
+ */
+ @Test
+ public void testParameters() {
+ for (MapType type: MapType.values()) {
+ switch (type) {
+ case PORT:
+ assertEquals(Reason.PORTMAPPED, type.getReason());
+ assertEquals(null, type.getMatchType());
+ break;
+
+ case MAC:
+ assertEquals(Reason.MACMAPPED, type.getReason());
+ assertEquals(MatchType.DL_SRC, type.getMatchType());
+ break;
+
+ case VLAN:
+ assertEquals(Reason.VLANMAPPED, type.getReason());
+ assertEquals(null, type.getMatchType());
+ break;
+
+ case ALL:
+ assertEquals(null, type.getReason());
+ assertEquals(null, type.getMatchType());
+ break;
+
+ default:
+ unexpected();
+ break;
+ }
+ }
+ }
+
/**
* Test case for {@link MapType#match(MapType)}.
*/