Fixed inappropriate uses of log level INFO
[controller.git] / opendaylight / protocol_plugins / openflow / src / main / java / org / opendaylight / controller / protocol_plugin / openflow / internal / FlowConverter.java
index 45c92aa91a6b806e310f1e62bfeb3e75bf6a92a8..78a2ea5120da60ad09053efb894e039533c52d68 100644 (file)
@@ -12,7 +12,9 @@ import java.math.BigInteger;
 import java.net.InetAddress;
 import java.net.UnknownHostException;
 import java.util.ArrayList;
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
 
 import org.opendaylight.controller.protocol_plugin.openflow.vendorextension.v6extension.V6FlowMod;
 import org.opendaylight.controller.protocol_plugin.openflow.vendorextension.v6extension.V6Match;
@@ -20,6 +22,7 @@ import org.opendaylight.controller.sal.action.Action;
 import org.opendaylight.controller.sal.action.ActionType;
 import org.opendaylight.controller.sal.action.Controller;
 import org.opendaylight.controller.sal.action.Drop;
+import org.opendaylight.controller.sal.action.Enqueue;
 import org.opendaylight.controller.sal.action.Flood;
 import org.opendaylight.controller.sal.action.FloodAll;
 import org.opendaylight.controller.sal.action.HwPath;
@@ -51,8 +54,10 @@ import org.openflow.protocol.OFPacketOut;
 import org.openflow.protocol.OFPort;
 import org.openflow.protocol.OFVendor;
 import org.openflow.protocol.action.OFAction;
+import org.openflow.protocol.action.OFActionDataLayer;
 import org.openflow.protocol.action.OFActionDataLayerDestination;
 import org.openflow.protocol.action.OFActionDataLayerSource;
+import org.openflow.protocol.action.OFActionEnqueue;
 import org.openflow.protocol.action.OFActionNetworkLayerAddress;
 import org.openflow.protocol.action.OFActionNetworkLayerDestination;
 import org.openflow.protocol.action.OFActionNetworkLayerSource;
@@ -75,6 +80,13 @@ import org.slf4j.LoggerFactory;
 public class FlowConverter {
     protected static final Logger logger = LoggerFactory
             .getLogger(FlowConverter.class);
+
+    /*
+     * The value 0xffff (OFP_VLAN_NONE) is used to indicate
+     * that no VLAN ID is set for OF Flow.
+     */
+    private static final short OFP_VLAN_NONE = (short) 0xffff;
+
     private Flow flow; // SAL Flow
     private OFMatch ofMatch; // OF 1.0 match or OF 1.0 + IPv6 extension match
     private List<OFAction> actionsList; // OF 1.0 actions
@@ -142,6 +154,9 @@ public class FlowConverter {
             if (match.isPresent(MatchType.DL_VLAN)) {
                 short vlan = (Short) match.getField(MatchType.DL_VLAN)
                         .getValue();
+                if (vlan == MatchType.DL_VLAN_NONE) {
+                    vlan = OFP_VLAN_NONE;
+                }
                 if (!isIPv6) {
                     ofMatch.setDataLayerVirtualLan(vlan);
                     wildcards &= ~OFMatch.OFPFW_DL_VLAN;
@@ -177,7 +192,7 @@ public class FlowConverter {
                  * actually the DSCP field followed by a zero ECN
                  */
                 byte tos = (Byte) match.getField(MatchType.NW_TOS).getValue();
-                byte dscp = (byte) ((int) tos << 2);
+                byte dscp = (byte) (tos << 2);
                 if (!isIPv6) {
                     ofMatch.setNetworkTypeOfService(dscp);
                     wildcards &= ~OFMatch.OFPFW_NW_TOS;
@@ -196,35 +211,23 @@ public class FlowConverter {
                 }
             }
             if (match.isPresent(MatchType.NW_SRC)) {
-                InetAddress address = (InetAddress) match.getField(
-                        MatchType.NW_SRC).getValue();
-                InetAddress mask = (InetAddress) match.getField(
-                        MatchType.NW_SRC).getMask();
+                InetAddress address = (InetAddress) match.getField(MatchType.NW_SRC).getValue();
+                InetAddress mask = (InetAddress) match.getField(MatchType.NW_SRC).getMask();
                 if (!isIPv6) {
-                    ofMatch.setNetworkSource(NetUtils.byteArray4ToInt(address
-                            .getAddress()));
-                    int maskLength = NetUtils
-                            .getSubnetMaskLength((mask == null) ? null : mask
-                                    .getAddress());
-                    wildcards = (wildcards & ~OFMatch.OFPFW_NW_SRC_MASK)
-                            | (maskLength << OFMatch.OFPFW_NW_SRC_SHIFT);
+                    ofMatch.setNetworkSource(NetUtils.byteArray4ToInt(address.getAddress()));
+                    int maskLength = (mask == null) ? 32 : NetUtils.getSubnetMaskLength(mask);
+                    wildcards = (wildcards & ~OFMatch.OFPFW_NW_SRC_MASK) | ((32 - maskLength) << OFMatch.OFPFW_NW_SRC_SHIFT);
                 } else {
                     ((V6Match) ofMatch).setNetworkSource(address, mask);
                 }
             }
             if (match.isPresent(MatchType.NW_DST)) {
-                InetAddress address = (InetAddress) match.getField(
-                        MatchType.NW_DST).getValue();
-                InetAddress mask = (InetAddress) match.getField(
-                        MatchType.NW_DST).getMask();
+                InetAddress address = (InetAddress) match.getField(MatchType.NW_DST).getValue();
+                InetAddress mask = (InetAddress) match.getField(MatchType.NW_DST).getMask();
                 if (!isIPv6) {
-                    ofMatch.setNetworkDestination(NetUtils
-                            .byteArray4ToInt(address.getAddress()));
-                    int maskLength = NetUtils
-                            .getSubnetMaskLength((mask == null) ? null : mask
-                                    .getAddress());
-                    wildcards = (wildcards & ~OFMatch.OFPFW_NW_DST_MASK)
-                            | (maskLength << OFMatch.OFPFW_NW_DST_SHIFT);
+                    ofMatch.setNetworkDestination(NetUtils.byteArray4ToInt(address.getAddress()));
+                    int maskLength = (mask == null) ? 32 : NetUtils.getSubnetMaskLength(mask);
+                    wildcards = (wildcards & ~OFMatch.OFPFW_NW_DST_MASK) | ((32 - maskLength) << OFMatch.OFPFW_NW_DST_SHIFT);
                 } else {
                     ((V6Match) ofMatch).setNetworkDestination(address, mask);
                 }
@@ -278,6 +281,15 @@ public class FlowConverter {
                     actionsLength += OFActionOutput.MINIMUM_LENGTH;
                     continue;
                 }
+                if (action.getType() == ActionType.ENQUEUE) {
+                    Enqueue a = (Enqueue) action;
+                    OFActionEnqueue ofAction = new OFActionEnqueue();
+                    ofAction.setPort(PortConverter.toOFPort(a.getPort()));
+                    ofAction.setQueueId(a.getQueue());
+                    actionsList.add(ofAction);
+                    actionsLength += OFActionEnqueue.MINIMUM_LENGTH;
+                    continue;
+                }
                 if (action.getType() == ActionType.DROP) {
                     continue;
                 }
@@ -354,7 +366,7 @@ public class FlowConverter {
                     OFActionDataLayerSource ofAction = new OFActionDataLayerSource();
                     ofAction.setDataLayerAddress(a.getDlAddress());
                     actionsList.add(ofAction);
-                    actionsLength += OFActionDataLayerSource.MINIMUM_LENGTH;
+                    actionsLength += OFActionDataLayer.MINIMUM_LENGTH;
                     continue;
                 }
                 if (action.getType() == ActionType.SET_DL_DST) {
@@ -362,7 +374,7 @@ public class FlowConverter {
                     OFActionDataLayerDestination ofAction = new OFActionDataLayerDestination();
                     ofAction.setDataLayerAddress(a.getDlAddress());
                     actionsList.add(ofAction);
-                    actionsLength += OFActionDataLayerDestination.MINIMUM_LENGTH;
+                    actionsLength += OFActionDataLayer.MINIMUM_LENGTH;
                     continue;
                 }
                 if (action.getType() == ActionType.SET_NW_SRC) {
@@ -411,7 +423,7 @@ public class FlowConverter {
                     continue;
                 }
                 if (action.getType() == ActionType.SET_NEXT_HOP) {
-                    // TODO
+                    logger.warn("Unsupported action: {}", action);
                     continue;
                 }
             }
@@ -452,13 +464,10 @@ public class FlowConverter {
             if (port != null) {
                 ((OFFlowMod) fm).setOutPort(port);
             }
-            if (command == OFFlowMod.OFPFC_ADD
-                    || command == OFFlowMod.OFPFC_MODIFY
+            if (command == OFFlowMod.OFPFC_ADD || command == OFFlowMod.OFPFC_MODIFY
                     || command == OFFlowMod.OFPFC_MODIFY_STRICT) {
-                if (flow.getIdleTimeout() != 0 || flow.getHardTimeout() != 0) {
-                    // Instruct switch to let controller know when flow expires
-                    ((OFFlowMod) fm).setFlags((short) 1);
-                }
+                // Instruct switch to let controller know when flow is removed
+                ((OFFlowMod) fm).setFlags((short) 1);
             }
         } else {
             ((V6FlowMod) fm).setVendor();
@@ -476,13 +485,10 @@ public class FlowConverter {
             if (port != null) {
                 ((V6FlowMod) fm).setOutPort(port);
             }
-            if (command == OFFlowMod.OFPFC_ADD
-                    || command == OFFlowMod.OFPFC_MODIFY
+            if (command == OFFlowMod.OFPFC_ADD || command == OFFlowMod.OFPFC_MODIFY
                     || command == OFFlowMod.OFPFC_MODIFY_STRICT) {
-                if (flow.getIdleTimeout() != 0 || flow.getHardTimeout() != 0) {
-                    // Instruct switch to let controller know when flow expires
-                    ((V6FlowMod) fm).setFlags((short) 1);
-                }
+                // Instruct switch to let controller know when flow is removed
+                ((V6FlowMod) fm).setFlags((short) 1);
             }
         }
         logger.trace("Openflow Match: {} Openflow Actions: {}", ofMatch,
@@ -502,10 +508,10 @@ public class FlowConverter {
             if (ofMatch != null) {
                 if (!isIPv6) {
                     // Compute OF1.0 Match
-                    if (ofMatch.getInputPort() != 0) {
+                    if (ofMatch.getInputPort() != 0 && ofMatch.getInputPort() != OFPort.OFPP_LOCAL.getValue()) {
                         salMatch.setField(new MatchField(MatchType.IN_PORT,
                                 NodeConnectorCreator.createNodeConnector(
-                                        (Short) ofMatch.getInputPort(), node)));
+                                        ofMatch.getInputPort(), node)));
                     }
                     if (ofMatch.getDataLayerSource() != null
                             && !NetUtils
@@ -525,9 +531,13 @@ public class FlowConverter {
                         salMatch.setField(new MatchField(MatchType.DL_TYPE,
                                 ofMatch.getDataLayerType()));
                     }
-                    if (ofMatch.getDataLayerVirtualLan() != 0) {
+                    short vlan = ofMatch.getDataLayerVirtualLan();
+                    if (vlan != 0) {
+                        if (vlan == OFP_VLAN_NONE) {
+                            vlan = MatchType.DL_VLAN_NONE;
+                        }
                         salMatch.setField(new MatchField(MatchType.DL_VLAN,
-                                ofMatch.getDataLayerVirtualLan()));
+                                vlan));
                     }
                     if (ofMatch.getDataLayerVirtualLanPriorityCodePoint() != 0) {
                         salMatch.setField(MatchType.DL_VLAN_PR, ofMatch
@@ -554,26 +564,27 @@ public class FlowConverter {
                         byte tos = (byte) (dscp >> 2);
                         salMatch.setField(MatchType.NW_TOS, tos);
                     }
+                    //TODO: NW protocol 0 is a valid protocol
                     if (ofMatch.getNetworkProtocol() != 0) {
                         salMatch.setField(MatchType.NW_PROTO,
                                 ofMatch.getNetworkProtocol());
                     }
                     if (ofMatch.getTransportSource() != 0) {
                         salMatch.setField(MatchType.TP_SRC,
-                                ((Short) ofMatch.getTransportSource()));
+                                ofMatch.getTransportSource());
                     }
                     if (ofMatch.getTransportDestination() != 0) {
                         salMatch.setField(MatchType.TP_DST,
-                                ((Short) ofMatch.getTransportDestination()));
+                                ofMatch.getTransportDestination());
                     }
                 } else {
                     // Compute OF1.0 + IPv6 extensions Match
                     V6Match v6Match = (V6Match) ofMatch;
-                    if (v6Match.getInputPort() != 0) {
+                    if (v6Match.getInputPort() != 0 && v6Match.getInputPort() != OFPort.OFPP_LOCAL.getValue()) {
                         // Mask on input port is not defined
                         salMatch.setField(new MatchField(MatchType.IN_PORT,
                                 NodeConnectorCreator.createOFNodeConnector(
-                                        (Short) v6Match.getInputPort(), node)));
+                                        v6Match.getInputPort(), node)));
                     }
                     if (v6Match.getDataLayerSource() != null
                             && !NetUtils
@@ -593,23 +604,42 @@ public class FlowConverter {
                         salMatch.setField(new MatchField(MatchType.DL_TYPE,
                                 v6Match.getDataLayerType()));
                     }
-                    if (v6Match.getDataLayerVirtualLan() != 0) {
+                    short vlan = v6Match.getDataLayerVirtualLan();
+                    if (vlan != 0) {
+                        if (vlan == OFP_VLAN_NONE) {
+                            vlan = MatchType.DL_VLAN_NONE;
+                        }
                         salMatch.setField(new MatchField(MatchType.DL_VLAN,
-                                v6Match.getDataLayerVirtualLan()));
+                                vlan));
                     }
                     if (v6Match.getDataLayerVirtualLanPriorityCodePoint() != 0) {
                         salMatch.setField(MatchType.DL_VLAN_PR, v6Match
                                 .getDataLayerVirtualLanPriorityCodePoint());
                     }
+                    // V6Match may carry IPv4 address
                     if (v6Match.getNetworkSrc() != null) {
                         salMatch.setField(MatchType.NW_SRC,
                                 v6Match.getNetworkSrc(),
                                 v6Match.getNetworkSourceMask());
+                    } else if (v6Match.getNetworkSource() != 0) {
+                        salMatch.setField(MatchType.NW_SRC, NetUtils
+                                .getInetAddress(v6Match.getNetworkSource()),
+                                NetUtils.getInetNetworkMask(
+                                        v6Match.getNetworkSourceMaskLen(),
+                                        false));
                     }
+                    // V6Match may carry IPv4 address
                     if (v6Match.getNetworkDest() != null) {
                         salMatch.setField(MatchType.NW_DST,
                                 v6Match.getNetworkDest(),
                                 v6Match.getNetworkDestinationMask());
+                    } else if (v6Match.getNetworkDestination() != 0) {
+                        salMatch.setField(MatchType.NW_DST,
+                                NetUtils.getInetAddress(v6Match
+                                        .getNetworkDestination()),
+                                NetUtils.getInetNetworkMask(
+                                        v6Match.getNetworkDestinationMaskLen(),
+                                        false));
                     }
                     if (v6Match.getNetworkTypeOfService() != 0) {
                         int dscp = NetUtils.getUnsignedByte(v6Match
@@ -623,11 +653,11 @@ public class FlowConverter {
                     }
                     if (v6Match.getTransportSource() != 0) {
                         salMatch.setField(MatchType.TP_SRC,
-                                ((Short) v6Match.getTransportSource()));
+                                (v6Match.getTransportSource()));
                     }
                     if (v6Match.getTransportDestination() != 0) {
                         salMatch.setField(MatchType.TP_DST,
-                                ((Short) v6Match.getTransportDestination()));
+                                (v6Match.getTransportDestination()));
                     }
                 }
             }
@@ -663,6 +693,10 @@ public class FlowConverter {
                                     NodeConnectorCreator.createOFNodeConnector(
                                             ofPort, node));
                         }
+                    } else if (ofAction instanceof OFActionEnqueue) {
+                        salAction = new Enqueue(NodeConnectorCreator.createOFNodeConnector(
+                                ((OFActionEnqueue) ofAction).getPort(), node),
+                                ((OFActionEnqueue) ofAction).getQueueId());
                     } else if (ofAction instanceof OFActionVirtualLanIdentifier) {
                         salAction = new SetVlanId(
                                 ((OFActionVirtualLanIdentifier) ofAction)
@@ -730,4 +764,50 @@ public class FlowConverter {
         return flow;
     }
 
+    private static final Map<Integer, Class<? extends Action>> actionMap = new HashMap<Integer, Class<? extends Action>>() {
+        private static final long serialVersionUID = 1L;
+        {
+            put(1 << 0, Output.class);
+            put(1 << 1, SetVlanId.class);
+            put(1 << 2, SetVlanPcp.class);
+            put(1 << 3, PopVlan.class);
+            put(1 << 4, SetDlSrc.class);
+            put(1 << 5, SetDlDst.class);
+            put(1 << 6, SetNwSrc.class);
+            put(1 << 7, SetNwDst.class);
+            put(1 << 8, SetNwTos.class);
+            put(1 << 9, SetTpSrc.class);
+            put(1 << 10, SetTpDst.class);
+            put(1 << 11, Enqueue.class);
+        }
+    };
+
+    /**
+     * Returns the supported flow actions for the netwrok node given the bitmask
+     * representing the actions the Openflow 1.0 switch supports
+     *
+     * @param ofActionBitmask
+     *            OF 1.0 action bitmask
+     * @return The correspondent list of SAL Action classes
+     */
+    public static List<Class<? extends Action>> getFlowActions(int ofActionBitmask) {
+        List<Class<? extends Action>> list = new ArrayList<Class<? extends Action>>();
+
+        for (int i = 0; i < Integer.SIZE; i++) {
+            int index = 1 << i;
+            if ((index & ofActionBitmask) > 0) {
+                if (actionMap.containsKey(index)) {
+                    list.add(actionMap.get(index));
+                }
+            }
+        }
+        // Add implicit SAL actions
+        list.add(Controller.class);
+        list.add(SwPath.class);
+        list.add(HwPath.class);
+        list.add(Drop.class);
+
+        return list;
+    }
+
 }