Enable flow actions in flow filter to modify packet. 46/10646/1
authorShigeru Yasuda <s-yasuda@da.jp.nec.com>
Tue, 2 Sep 2014 17:50:41 +0000 (02:50 +0900)
committerShigeru Yasuda <s-yasuda@da.jp.nec.com>
Tue, 2 Sep 2014 17:50:41 +0000 (02:50 +0900)
Other changes:

  * Apply flow filters for outgoing packets when an unicast packet is
    broadcasted in the vBridge. In that case REDIRECT flow filter is
    ignored.

Change-Id: Id17cf857806f289b737a088af3f8c7dae27dc0f9
Signed-off-by: Shigeru Yasuda <s-yasuda@da.jp.nec.com>
41 files changed:
manager/api/src/main/java/org/opendaylight/vtn/manager/flow/action/SetDscpAction.java
manager/api/src/main/java/org/opendaylight/vtn/manager/flow/filter/package-info.java
manager/api/src/test/java/org/opendaylight/vtn/manager/flow/action/FlowActionTest.java
manager/api/src/test/java/org/opendaylight/vtn/manager/flow/action/SetDscpActionTest.java
manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/ActionList.java
manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/PacketContext.java
manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/cluster/DropFlowFilterImpl.java
manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/cluster/EthernetMatchImpl.java
manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/cluster/FlowActionImpl.java
manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/cluster/FlowFilterImpl.java
manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/cluster/FlowFilterMap.java
manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/cluster/InetAddressActionImpl.java
manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/cluster/MacMapImpl.java
manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/cluster/MapReference.java
manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/cluster/MapType.java
manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/cluster/PassFlowFilterImpl.java
manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/cluster/PortBridge.java
manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/cluster/PortInterface.java
manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/cluster/RedirectFlowFilterImpl.java
manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/cluster/SetDlDstActionImpl.java
manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/cluster/SetDlSrcActionImpl.java
manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/cluster/SetDscpActionImpl.java
manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/cluster/SetIcmpCodeActionImpl.java
manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/cluster/SetIcmpTypeActionImpl.java
manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/cluster/SetVlanPcpActionImpl.java
manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/cluster/TpPortActionImpl.java
manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/cluster/VBridgeImpl.java
manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/cluster/VTenantImpl.java
manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/cluster/VTerminalImpl.java
manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/cluster/VirtualMapNode.java
manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/cluster/VlanMapImpl.java
manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/packet/CachedPacket.java
manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/packet/EtherPacket.java
manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/packet/IcmpPacket.java
manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/packet/Inet4Packet.java
manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/packet/PortProtoPacket.java
manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/PacketContextTest.java
manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/TestBase.java
manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/TestBridgeNode.java
manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/TestUseVTNManagerBase.java
manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/cluster/MapTypeTest.java

index f68093f32e626e97ee80c134f9b211282208bbd1..dc978cc0793844b763f4e81e2edcf2fecba867b6 100644 (file)
@@ -17,6 +17,7 @@ import javax.xml.bind.annotation.XmlRootElement;
 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
@@ -37,7 +38,12 @@ public final class SetDscpAction extends FlowAction {
     /**
      * 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.
@@ -56,6 +62,26 @@ public final class SetDscpAction extends FlowAction {
     @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.
      */
@@ -80,7 +106,7 @@ public final class SetDscpAction extends FlowAction {
      *    {@code null} is passed to {@code act}.
      */
     public SetDscpAction(SetNwTos act) {
-        dscp = (byte)act.getNwTos();
+        dscp = tosToDscp((byte)act.getNwTos());
     }
 
     /**
index f2dbec0c0cb64e8a12fc02af2032795b9a300ac0..798e884debae8f0d456a8599e447dbe436f6055a 100644 (file)
  *         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>
  *
index fd0ed305bfe730e81db676a4d3c70484ac2591a9..6a108f5d5afdee50a29c54488ada72c13da7ae20 100644 (file)
@@ -52,7 +52,11 @@ public class FlowActionTest extends TestBase {
         };
         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(),
@@ -90,14 +94,15 @@ public class FlowActionTest extends TestBase {
                 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);
index 687bd6cbea7b65ea1ef19d9691d75d5906f7a962..75b2b6472bc16d3042f15af9a8e840e12b814403 100644 (file)
@@ -21,6 +21,20 @@ import org.opendaylight.controller.sal.action.SetNwTos;
  * 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.
      */
@@ -32,9 +46,10 @@ public class SetDscpActionTest extends TestBase {
             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());
         }
index bdc5568f9c35420622db00a0df2ae87abd3fa1f3..cd8bcbdcacc9c99e2af0db7c80eeafe84458a6e8 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * 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
@@ -60,6 +60,19 @@ public class ActionList {
         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.
      *
index 59859726af1c8eaba17cff1621e1c7476ff2f550..2b539d346ca8f2b99a6b0ffb6e371933fe8c34cf 100644 (file)
 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;
@@ -36,6 +38,7 @@ import org.opendaylight.vtn.manager.internal.packet.Inet4Packet;
 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;
@@ -59,7 +62,7 @@ import org.opendaylight.controller.sal.utils.NetUtils;
  *   This class is designed to be used by a single thread.
  * </p>
  */
-public class PacketContext {
+public class PacketContext implements Cloneable {
     /**
      * Logger instance.
      */
@@ -71,6 +74,14 @@ public class PacketContext {
      */
     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.
      */
@@ -79,7 +90,7 @@ public class PacketContext {
     /**
      * Decoded ethernet frame.
      */
-    private final EtherPacket  etherFrame;
+    private EtherPacket  etherFrame;
 
     /**
      * Source IP address.
@@ -89,7 +100,7 @@ public class PacketContext {
     /**
      * Obsolete layer 2 host entries.
      */
-    private final Set<ObjectPair<MacVlan, NodeConnector>>  obsoleteHosts =
+    private Set<ObjectPair<MacVlan, NodeConnector>>  obsoleteHosts =
         new HashSet<ObjectPair<MacVlan, NodeConnector>>();
 
     /**
@@ -100,19 +111,19 @@ public class PacketContext {
     /**
      * 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);
 
     /**
@@ -153,6 +164,28 @@ public class PacketContext {
      */
     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.
      *
@@ -167,12 +200,19 @@ public class PacketContext {
     /**
      * 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;
     }
 
     /**
@@ -285,7 +325,7 @@ public class PacketContext {
         }
 
         NodeConnector nc = rawPacket.getIncomingNodeConnector();
-        return new PortVlan(nc, getVlan());
+        return new PortVlan(nc, etherFrame.getOriginalVlan());
     }
 
     /**
@@ -308,6 +348,15 @@ public class PacketContext {
         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.
      *
@@ -328,13 +377,16 @@ public class PacketContext {
             // 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());
@@ -388,7 +440,6 @@ public class PacketContext {
         return obsoleteHosts;
     }
 
-
     /**
      * Purge VTN flows relevant to obsolete layer 2 host entries.
      *
@@ -550,20 +601,6 @@ public class PacketContext {
         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.
@@ -572,6 +609,10 @@ public class PacketContext {
      */
     public void setMapReference(MapReference ref) {
         mapReference = ref;
+        MatchType mtype = ref.getMapType().getMatchType();
+        if (mtype != null) {
+            matchFields.add(mtype);
+        }
     }
 
     /**
@@ -586,7 +627,7 @@ public class PacketContext {
             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();
 
@@ -609,12 +650,25 @@ public class PacketContext {
     }
 
     /**
-     * Add match field to be configured into a flow entry.
+     * Add 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);
+            }
+        }
     }
 
     /**
@@ -624,6 +678,7 @@ public class PacketContext {
      * @return  A match object that matches the packet.
      */
     public Match createMatch(NodeConnector inPort) {
+        assert !flooding;
         Match match = new Match();
 
         // Incoming port field is mandatory.
@@ -759,7 +814,14 @@ public class PacketContext {
      */
     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);
     }
 
     /**
@@ -769,7 +831,16 @@ public class PacketContext {
      * @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);
@@ -783,4 +854,156 @@ public class PacketContext {
         // 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);
+        }
+    }
 }
index d806ea5387618dfc9db3604143118dfff4cc98ac..83064a588224f79e38a4986c8ad01432855dbafb 100644 (file)
@@ -33,7 +33,7 @@ public final class DropFlowFilterImpl extends FlowFilterImpl {
     /**
      * Version number for serialization.
      */
-    private static final long serialVersionUID = 5797523592920393192L;
+    private static final long serialVersionUID = -4839160630229249797L;
 
     /**
      * Logger instance.
@@ -71,6 +71,21 @@ public final class DropFlowFilterImpl extends FlowFilterImpl {
         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.
      *
index 99092df35cdfa79809955d691ba90789d9270661..33da77d3134ff5054a3ccb6c77a006bcb1351bae 100644 (file)
@@ -373,19 +373,20 @@ public final class EthernetMatchImpl implements PacketMatch {
     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.
@@ -397,6 +398,8 @@ public final class EthernetMatchImpl implements PacketMatch {
         }
 
         // 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;
index aceb94d52b4931d49217fbd34f1d894cd03450d5..cc24b955fbb69232ffd01369d5f53e69716eecfa 100644 (file)
@@ -18,6 +18,8 @@ import java.util.Map;
 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;
@@ -45,7 +47,7 @@ public abstract class FlowActionImpl implements Serializable {
     /**
      * Version number for serialization.
      */
-    private static final long serialVersionUID = 6166295951874905466L;
+    private static final long serialVersionUID = 9015667825740105469L;
 
     /**
      * Suffix of action implementation class name.
@@ -71,8 +73,8 @@ public abstract class FlowActionImpl implements Serializable {
         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,
@@ -82,12 +84,12 @@ public abstract class FlowActionImpl implements Serializable {
             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);
             }
@@ -201,6 +203,16 @@ public abstract class FlowActionImpl implements Serializable {
      */
     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.
      *
index be924e23bbae586291921bb46e881c31a22436a0..63737179c566ff8ac2036e80d97d12d80f40814d 100644 (file)
@@ -43,7 +43,7 @@ public abstract class FlowFilterImpl implements Serializable {
     /**
      * Version number for serialization.
      */
-    private static final long serialVersionUID = -2734872622088458798L;
+    private static final long serialVersionUID = -2804474498924166254L;
 
     /**
      * The minimum value of filter index.
@@ -70,6 +70,21 @@ public abstract class FlowFilterImpl implements Serializable {
      */
     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.
      *
@@ -189,30 +204,30 @@ public abstract class FlowFilterImpl implements Serializable {
     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;
@@ -247,6 +262,38 @@ public abstract class FlowFilterImpl implements Serializable {
         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.
      *
@@ -276,6 +323,64 @@ public abstract class FlowFilterImpl implements Serializable {
      */
     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.
      *
index 1b76cee696547f0c7037fe6d3a9a6a04071d9b41..12326a713d33958811d2e6e29a62a3d03cbeb89f 100644 (file)
@@ -49,7 +49,7 @@ public final class FlowFilterMap implements Serializable, Cloneable {
     /**
      * Version number for serialization.
      */
-    private static final long serialVersionUID = -777381317561613808L;
+    private static final long serialVersionUID = 2909825600683228034L;
 
     /**
      * Logger instance.
@@ -333,20 +333,80 @@ public final class FlowFilterMap implements Serializable, Cloneable {
      */
     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",
@@ -365,12 +425,18 @@ public final class FlowFilterMap implements Serializable, Cloneable {
     }
 
     /**
-     * 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());
+        }
     }
 
     /**
index ca6fd3a901ce96ec434fa6571c28abd3e0154c87..288f9a03f7bfe7312c17763a77786b4c35a513f0 100644 (file)
@@ -15,6 +15,7 @@ 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;
 
@@ -31,7 +32,7 @@ public abstract class InetAddressActionImpl extends FlowActionImpl {
     /**
      * Version number for serialization.
      */
-    private static final long serialVersionUID = -6711928072439846526L;
+    private static final long serialVersionUID = -5303473358097612716L;
 
     /**
      * IP address to be set.
@@ -71,6 +72,15 @@ 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.
      *
index 8d9e0f9a30027b2d18e6c744d34b8c1c2b0c7e28..050f014b42bc1c18abeb4ea0411efde9e5a93a82 100644 (file)
@@ -73,7 +73,7 @@ public final class MacMapImpl implements VBridgeNode, Cloneable {
     /**
      * Version number for serialization.
      */
-    private static final long serialVersionUID = 8275152227769388186L;
+    private static final long serialVersionUID = 7872635405280024017L;
 
     /**
      * Logger instance.
@@ -1027,12 +1027,15 @@ public final class MacMapImpl implements VBridgeNode, Cloneable {
      * 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) {
@@ -1046,13 +1049,30 @@ public final class MacMapImpl implements VBridgeNode, Cloneable {
                 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);
         }
@@ -1498,27 +1518,34 @@ public final class MacMapImpl implements VBridgeNode, Cloneable {
     }
 
     /**
-     * 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
index 29211ac7491f322096dbc65b71dd36869ac4847e..4a32549545b5ac27388f476942cd352c284ce38e 100644 (file)
@@ -10,8 +10,6 @@
 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;
@@ -30,21 +28,6 @@ public class MapReference implements Serializable, Comparable<MapReference> {
      */
     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.
      */
@@ -151,7 +134,7 @@ public class MapReference implements Serializable, Comparable<MapReference> {
      * @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);
index 8bced5bd1962a258f08d47fdf477fdcbc23fc131..0b2fb9022e2053352818bfb4b94ec12fa050c187 100644 (file)
@@ -9,6 +9,10 @@
 
 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.
@@ -17,17 +21,17 @@ public enum MapType {
     /**
      * 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.
@@ -39,13 +43,51 @@ public enum MapType {
      */
     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;
     }
 
     /**
@@ -58,4 +100,26 @@ public enum MapType {
     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;
+    }
 }
index d8f487e3ce683848ccac1752fd1d8b889a866ca7..7aea478b0fb8d5784491851da9ff5a46c3563eb3 100644 (file)
@@ -66,8 +66,8 @@ public final class PassFlowFilterImpl extends FlowFilterImpl {
      */
     @Override
     protected void apply(VTNManagerImpl mgr, PacketContext pctx,
-                            FlowFilterMap ffmap) {
-        // REVISIT: Not yet implemented.
+                         FlowFilterMap ffmap) {
+        // Nothing to do.
     }
 
     /**
index 2a2dc45d11e965a624dd5dc0f86d15e561d2e8fd..844bdd43ca50799a1e84ed1a550754020ca1e22a 100644 (file)
@@ -50,7 +50,7 @@ public abstract class PortBridge<T extends PortInterface>
     /**
      * 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.
@@ -272,7 +272,7 @@ public abstract class PortBridge<T extends PortInterface>
                 // 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 {
@@ -575,10 +575,13 @@ public abstract class PortBridge<T extends PortInterface>
      *
      * @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;
 
     /**
index c8009eed647bd9dfbbae5670b3c7c1dea896e84e..fc9d58afddfb1b6d5d46ff0e3c4ff64a40795e53 100644 (file)
@@ -59,7 +59,7 @@ public abstract class PortInterface extends AbstractInterface
     /**
      * Version number for serialization.
      */
-    private static final long serialVersionUID = 7145233837389323463L;
+    private static final long serialVersionUID = 7528273171488986531L;
 
     /**
      * Port mapping configuration.
@@ -360,13 +360,30 @@ public abstract class PortInterface extends AbstractInterface
             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);
@@ -909,23 +926,38 @@ public abstract class PortInterface extends AbstractInterface
     }
 
     /**
-     * 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
index 61603bde79d421bd2a67c8532e76e947fdd468c6..ec030141b407652ec29171d2d803507378fdaed0 100644 (file)
@@ -39,7 +39,7 @@ public final class RedirectFlowFilterImpl extends FlowFilterImpl {
     /**
      * Version number for serialization.
      */
-    private static final long serialVersionUID = 4047222122155716062L;
+    private static final long serialVersionUID = -5004273201378790703L;
 
     /**
      * Logger instance.
@@ -153,7 +153,20 @@ public final class RedirectFlowFilterImpl extends FlowFilterImpl {
             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.
index b85b001191df7176074caaae371151e98c08637c..fb02052f590359627af0cf6b69187ff8f06b5535 100644 (file)
@@ -12,6 +12,9 @@ package org.opendaylight.vtn.manager.internal.cluster;
 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.
@@ -26,7 +29,7 @@ public final class SetDlDstActionImpl extends DlAddrActionImpl {
     /**
      * Version number for serialization.
      */
-    private static final long serialVersionUID = 7134765478589068419L;
+    private static final long serialVersionUID = -4389217399774516871L;
 
     /**
      * Construct a new instance.
@@ -48,4 +51,15 @@ public final class SetDlDstActionImpl extends DlAddrActionImpl {
     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;
+    }
 }
index fc0ccddfa9b9d925396cf8afa084cfa4b736c647..aff3e80143d40559faf321b2168ed0b2de5fdecc 100644 (file)
@@ -12,6 +12,9 @@ package org.opendaylight.vtn.manager.internal.cluster;
 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.
@@ -26,7 +29,7 @@ public final class SetDlSrcActionImpl extends DlAddrActionImpl {
     /**
      * Version number for serialization.
      */
-    private static final long serialVersionUID = -4310613948193975272L;
+    private static final long serialVersionUID = -1613024024719683362L;
 
     /**
      * Construct a new instance.
@@ -48,4 +51,15 @@ public final class SetDlSrcActionImpl extends DlAddrActionImpl {
     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;
+    }
 }
index e83050abcb5745e0e243e2e0c1ec2bed7ae1a8e2..18c1483573d95b091d8a5d9f814ec7880f20396b 100644 (file)
@@ -14,6 +14,8 @@ 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.vtn.manager.internal.packet.Inet4Packet;
 
 import org.opendaylight.controller.sal.utils.StatusCode;
 
@@ -30,7 +32,7 @@ public final class SetDscpActionImpl extends FlowActionImpl {
     /**
      * Version number for serialization.
      */
-    private static final long serialVersionUID = -3906046474805749284L;
+    private static final long serialVersionUID = -1924798722051088828L;
 
     /**
      * DSCP field value to be set.
@@ -107,4 +109,18 @@ public final class SetDscpActionImpl extends FlowActionImpl {
     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;
+    }
 }
index fe1b3817fe7e8261956f60541fd5f23a9985ccb1..c00c0411e7cc74bbc4b0234923c0557e74b5a538 100644 (file)
@@ -14,6 +14,9 @@ import org.opendaylight.vtn.manager.VTNException;
 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;
 
@@ -31,7 +34,7 @@ public final class SetIcmpCodeActionImpl extends FlowActionImpl {
     /**
      * Version number for serialization.
      */
-    private static final long serialVersionUID = 3037343901730872355L;
+    private static final long serialVersionUID = -875563808348172512L;
 
     /**
      * ICMP code value to be set.
@@ -106,4 +109,19 @@ public final class SetIcmpCodeActionImpl extends FlowActionImpl {
     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;
+    }
 }
index 00bfdfd3bd96d4b59c0c44c7092c2cbad9178ab9..fadec00dd43bc4afda8942053f844c625124fc14 100644 (file)
@@ -14,6 +14,9 @@ import org.opendaylight.vtn.manager.VTNException;
 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;
 
@@ -31,7 +34,7 @@ public final class SetIcmpTypeActionImpl extends FlowActionImpl {
     /**
      * Version number for serialization.
      */
-    private static final long serialVersionUID = 4011870176452756178L;
+    private static final long serialVersionUID = 7985609778860682790L;
 
     /**
      * ICMP type value to be set.
@@ -106,4 +109,19 @@ public final class SetIcmpTypeActionImpl extends FlowActionImpl {
     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;
+    }
 }
index 322dc7c07174e61963cf75075dc14ae4dcf47afd..7aef12b0992dd4352e371ddd12d7d501f1af32f5 100644 (file)
@@ -14,6 +14,8 @@ import org.opendaylight.vtn.manager.VTNException;
 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;
 
@@ -30,7 +32,7 @@ public final class SetVlanPcpActionImpl extends FlowActionImpl {
     /**
      * Version number for serialization.
      */
-    private static final long serialVersionUID = 2656305491316609840L;
+    private static final long serialVersionUID = -1355670340796521474L;
 
     /**
      * VLAN priority to be set.
@@ -108,4 +110,14 @@ public final class SetVlanPcpActionImpl extends FlowActionImpl {
     public SetVlanPcpAction getFlowAction() {
         return new SetVlanPcpAction(priority);
     }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public boolean apply(PacketContext pctx) {
+        EtherPacket ether = pctx.getEtherPacket();
+        ether.setVlanPriority(priority);
+        return true;
+    }
 }
index 023cc4fd64b24d7e458a9b31c24fc982629af72f..ef47d3dbcbbdc323d79a6834d634e69778fef3f7 100644 (file)
@@ -13,6 +13,7 @@ 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;
 
@@ -30,7 +31,7 @@ public abstract class TpPortActionImpl extends FlowActionImpl {
     /**
      * Version number for serialization.
      */
-    private static final long serialVersionUID = 2892201590657891707L;
+    private static final long serialVersionUID = -8000141230774734830L;
 
     /**
      * A port number to be set.
@@ -63,6 +64,15 @@ 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.
      *
index 434926120241e575fd468a38bcd4a1a5373e563c..ec0393bee386abba9e0fb4ae98a3c2d96d300acc 100644 (file)
@@ -81,7 +81,7 @@ public final class VBridgeImpl extends PortBridge<VBridgeIfImpl>
     /**
      * Version number for serialization.
      */
-    private static final long serialVersionUID = -1152732096599635100L;
+    private static final long serialVersionUID = 6513589025699567661L;
 
     /**
      * Logger instance.
@@ -860,10 +860,20 @@ public final class VBridgeImpl extends PortBridge<VBridgeIfImpl>
             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;
     }
@@ -891,8 +901,11 @@ public final class VBridgeImpl extends PortBridge<VBridgeIfImpl>
         // 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;
@@ -914,8 +927,12 @@ public final class VBridgeImpl extends PortBridge<VBridgeIfImpl>
         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.
@@ -936,6 +953,9 @@ public final class VBridgeImpl extends PortBridge<VBridgeIfImpl>
      * @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();
@@ -951,12 +971,12 @@ public final class VBridgeImpl extends PortBridge<VBridgeIfImpl>
         // 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)) {
@@ -1301,17 +1321,21 @@ public final class VBridgeImpl extends PortBridge<VBridgeIfImpl>
     // 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);
     }
 
     /**
@@ -1471,7 +1495,7 @@ public final class VBridgeImpl extends PortBridge<VBridgeIfImpl>
         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(),
@@ -1480,7 +1504,7 @@ public final class VBridgeImpl extends PortBridge<VBridgeIfImpl>
             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.
index d38b96edec93648d98f2e81ff635295b7ba67182..67b795d1b771c89a97f8e873ef9421951c3c2dc1 100644 (file)
@@ -12,6 +12,7 @@ package org.opendaylight.vtn.manager.internal.cluster;
 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;
@@ -1546,6 +1547,12 @@ public final class VTenantImpl implements FlowFilterNode {
         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);
@@ -2331,6 +2338,20 @@ public final class VTenantImpl implements FlowFilterNode {
         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
 
     /**
index bc2a05d770610eb39f7e16804823f6518a5a9da6..3da54558b453cc4aae31607ededdb8037ea8f4c0 100644 (file)
@@ -53,7 +53,7 @@ public final class VTerminalImpl extends PortBridge<VTerminalIfImpl> {
     /**
      * Version number for serialization.
      */
-    private static final long serialVersionUID = -6198751253263625812L;
+    private static final long serialVersionUID = 518889407387134507L;
 
     /**
      * Logger instance.
@@ -434,7 +434,8 @@ public final class VTerminalImpl extends PortBridge<VTerminalIfImpl> {
     // 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.
@@ -442,9 +443,13 @@ public final class VTerminalImpl extends PortBridge<VTerminalIfImpl> {
      *
      * @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;
     }
 
     /**
index b0f8343611827cb83d6af860530d14c8d836c26e..297e64f74274104a2210e6f1c9c9c30fbf77204a 100644 (file)
@@ -13,6 +13,7 @@ import java.io.Serializable;
 
 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;
 
@@ -58,18 +59,31 @@ public interface VirtualMapNode extends Serializable {
     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;
 }
index 506139f73c0c486b6bb989e6efe6d88817f25dd6..9439375600c694e45e5ec3349e3ae0dfc64956a1 100644 (file)
@@ -53,7 +53,7 @@ public final class VlanMapImpl implements VBridgeNode {
     /**
      * Version number for serialization.
      */
-    private static final long serialVersionUID = 8889310983300538855L;
+    private static final long serialVersionUID = -2162170566149009094L;
 
     /**
      * Logger instance.
@@ -272,12 +272,15 @@ public final class VlanMapImpl implements VBridgeNode {
      * 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();
@@ -293,7 +296,24 @@ public final class VlanMapImpl implements VBridgeNode {
             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)) {
@@ -303,7 +323,7 @@ public final class VlanMapImpl implements VBridgeNode {
             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);
         }
@@ -520,26 +540,33 @@ public final class VlanMapImpl implements VBridgeNode {
     }
 
     /**
-     * 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);
     }
 }
index 72ce1d4294bc3ed07086afdfc78b437abde02361..18d295b86d7a04e0903574a7d0fb909dc340829d 100644 (file)
@@ -11,6 +11,10 @@ package org.opendaylight.vtn.manager.internal.packet;
 
 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;
@@ -19,10 +23,15 @@ 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();
@@ -30,9 +39,31 @@ public interface CachedPacket {
     /**
      * 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();
 }
index 88e0a32ebcb06fc94300c64be8b6ab583c88d1e7..adbef2141eb3d3ec5bce797080f056411d28cc36 100644 (file)
@@ -11,6 +11,11 @@ package org.opendaylight.vtn.manager.internal.packet;
 
 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;
@@ -39,12 +44,6 @@ public final class EtherPacket implements CachedPacket {
      */
     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.
      */
@@ -56,49 +55,211 @@ public final class EtherPacket implements CachedPacket {
     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.
@@ -111,17 +272,21 @@ public final class EtherPacket implements CachedPacket {
         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();
@@ -133,11 +298,23 @@ public final class EtherPacket implements CachedPacket {
      * @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);
     }
 
     /**
@@ -146,11 +323,23 @@ public final class EtherPacket implements CachedPacket {
      * @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);
     }
 
     /**
@@ -159,12 +348,15 @@ public final class EtherPacket implements CachedPacket {
      * @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;
     }
 
     /**
@@ -173,12 +365,15 @@ public final class EtherPacket implements CachedPacket {
      * @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;
     }
 
     /**
@@ -190,6 +385,17 @@ public final class EtherPacket implements CachedPacket {
         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.
      *
@@ -198,11 +404,17 @@ public final class EtherPacket implements CachedPacket {
      *          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);
     }
 
     /**
@@ -210,20 +422,38 @@ public final class EtherPacket implements CachedPacket {
      *
      * @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.
@@ -241,6 +471,15 @@ public final class EtherPacket implements CachedPacket {
         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.
      *
@@ -251,11 +490,42 @@ public final class EtherPacket implements CachedPacket {
         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
@@ -266,33 +536,119 @@ public final class EtherPacket implements CachedPacket {
     /**
      * 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);
+        }
+    }
 }
index ea92a137efb87618bb176f75b50c623478163c1a..61a8b730cf087a61f5ededf6aef44bd6c50d558f 100644 (file)
@@ -11,6 +11,12 @@ package org.opendaylight.vtn.manager.internal.packet;
 
 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;
@@ -26,19 +32,136 @@ public final class IcmpPacket implements CachedPacket {
     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.
@@ -55,33 +178,113 @@ public final class IcmpPacket implements CachedPacket {
      * @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
@@ -92,22 +295,92 @@ public final class IcmpPacket implements CachedPacket {
     /**
      * 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);
         }
     }
 }
index e61562c490e0980df88306eef536f3d5fde8250f..b44f9ba5a3fe11a286379382129b07e4b2202147 100644 (file)
@@ -11,8 +11,13 @@ package org.opendaylight.vtn.manager.internal.packet;
 
 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;
@@ -36,7 +41,7 @@ public final class Inet4Packet implements CachedPacket {
     /**
      * An {@link IPv4} packet.
      */
-    private final IPv4  packet;
+    private IPv4  packet;
 
     /**
      * An integer value which indicates the source IP address.
@@ -66,9 +71,87 @@ public final class Inet4Packet implements CachedPacket {
     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.
@@ -126,18 +209,86 @@ public final class Inet4Packet implements CachedPacket {
      * @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
@@ -148,12 +299,20 @@ public final class Inet4Packet implements CachedPacket {
     /**
      * 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.
@@ -176,7 +335,53 @@ public final class Inet4Packet implements CachedPacket {
         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);
         }
     }
 }
index 62cdaed5c02d403589f53fb6b9d6aedc5d3a2392..ab0cf6111b91b87a9d37cf1358b8816d429baf3b 100644 (file)
@@ -11,6 +11,8 @@ package org.opendaylight.vtn.manager.internal.packet;
 
 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;
@@ -107,4 +109,26 @@ public abstract class PortProtoPacket implements CachedPacket {
             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);
+        }
+    }
 }
index 6ff48be39933d8033c1c2ff9da4d361ff0e8898b..ee7e0219d3539957bcedda77f06f2a17374c5b35 100644 (file)
@@ -539,9 +539,9 @@ public class PacketContextTest extends TestUseVTNManagerBase {
                 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) {
index 0a6679d40ba0c9c349adba9a8a2aeaf7cc1c3bdd..d2f2eba23072c5a660a6d0710304ecbb63c4bf5f 100644 (file)
@@ -833,6 +833,20 @@ public abstract class TestBase extends Assert {
         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.
      *
@@ -953,7 +967,7 @@ public abstract class TestBase extends Assert {
     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);
     }
 
@@ -970,7 +984,7 @@ public abstract class TestBase extends Assert {
      */
     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);
     }
 
index 7066a9d5f8c96b2efa709265d405a6a212735b13..eb7ec24644750726cc2a9b91c5c29b31e874556d 100644 (file)
@@ -125,18 +125,30 @@ public class TestBridgeNode implements VBridgeNode {
     }
 
     /**
-     * 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;
     }
 }
index 3303f12be2f010f3db97ca9c898a1b45c69c7394..ae38f6e8ce496deff6ae05de10aba823a7dfe0b1 100644 (file)
@@ -1289,6 +1289,7 @@ public class TestUseVTNManagerBase extends TestBase {
         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.
@@ -1328,6 +1329,7 @@ public class TestUseVTNManagerBase extends TestBase {
         assertNotNull(port);
         Packet decoded = stubObj.decodeDataPacket(pkt);
         PacketContext pctx = new PacketContext((Ethernet)decoded, port);
+        pctx.addUnicastMatchFields();
 
         try {
             byte[] pld = pctx.getPayload().serialize();
index 0e97910219d76f54d1fe23e2615900d3051558e0..79517ba5062e4fea2d2d6060b47bf195fab4e237 100644 (file)
@@ -11,12 +11,50 @@ package org.opendaylight.vtn.manager.internal.cluster;
 
 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)}.
      */