X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?p=controller.git;a=blobdiff_plain;f=opendaylight%2Fprotocol_plugins%2Fopenflow%2Fsrc%2Fmain%2Fjava%2Forg%2Fopendaylight%2Fcontroller%2Fprotocol_plugin%2Fopenflow%2Finternal%2FFlowConverter.java;h=78a2ea5120da60ad09053efb894e039533c52d68;hp=47ce283331c0bbe6b29fe6a231761656fdcb7728;hb=dad78e1fc8a7c67fa4b88cf09d6a952443462feb;hpb=f6b70bf10eed6de95ec52bb6bf6f47d6bc7c9eaf diff --git a/opendaylight/protocol_plugins/openflow/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/internal/FlowConverter.java b/opendaylight/protocol_plugins/openflow/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/internal/FlowConverter.java index 47ce283331..78a2ea5120 100644 --- a/opendaylight/protocol_plugins/openflow/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/internal/FlowConverter.java +++ b/opendaylight/protocol_plugins/openflow/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/internal/FlowConverter.java @@ -12,37 +12,17 @@ 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; -import org.openflow.protocol.OFFlowMod; -import org.openflow.protocol.OFMatch; -import org.openflow.protocol.OFMessage; -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.OFActionDataLayerDestination; -import org.openflow.protocol.action.OFActionDataLayerSource; -import org.openflow.protocol.action.OFActionNetworkLayerAddress; -import org.openflow.protocol.action.OFActionNetworkLayerDestination; -import org.openflow.protocol.action.OFActionNetworkLayerSource; -import org.openflow.protocol.action.OFActionNetworkTypeOfService; -import org.openflow.protocol.action.OFActionOutput; -import org.openflow.protocol.action.OFActionStripVirtualLan; -import org.openflow.protocol.action.OFActionTransportLayer; -import org.openflow.protocol.action.OFActionTransportLayerDestination; -import org.openflow.protocol.action.OFActionTransportLayerSource; -import org.openflow.protocol.action.OFActionVirtualLanIdentifier; -import org.openflow.protocol.action.OFActionVirtualLanPriorityCodePoint; -import org.openflow.util.U16; -import org.openflow.util.U32; - 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; @@ -67,11 +47,46 @@ import org.opendaylight.controller.sal.match.MatchField; import org.opendaylight.controller.sal.match.MatchType; import org.opendaylight.controller.sal.utils.NetUtils; import org.opendaylight.controller.sal.utils.NodeConnectorCreator; +import org.openflow.protocol.OFFlowMod; +import org.openflow.protocol.OFMatch; +import org.openflow.protocol.OFMessage; +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; +import org.openflow.protocol.action.OFActionNetworkTypeOfService; +import org.openflow.protocol.action.OFActionOutput; +import org.openflow.protocol.action.OFActionStripVirtualLan; +import org.openflow.protocol.action.OFActionTransportLayer; +import org.openflow.protocol.action.OFActionTransportLayerDestination; +import org.openflow.protocol.action.OFActionTransportLayerSource; +import org.openflow.protocol.action.OFActionVirtualLanIdentifier; +import org.openflow.protocol.action.OFActionVirtualLanPriorityCodePoint; +import org.openflow.util.U16; +import org.openflow.util.U32; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; /** * Utility class for converting a SAL Flow into the OF flow and vice-versa */ 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 actionsList; // OF 1.0 actions @@ -97,7 +112,7 @@ public class FlowConverter { /** * Returns the match in OF 1.0 (OFMatch) form or OF 1.0 + IPv6 extensions * form (V6Match) - * + * * @return */ public OFMatch getOFMatch() { @@ -139,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; @@ -174,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; @@ -193,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); } @@ -252,13 +258,14 @@ public class FlowConverter { ofMatch.setWildcards(U32.t(Long.valueOf(wildcards))); } } - + logger.trace("SAL Match: {} Openflow Match: {}", flow.getMatch(), + ofMatch); return ofMatch; } /** * Returns the list of actions in OF 1.0 form - * + * * @return */ public List getOFActions() { @@ -274,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; } @@ -350,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) { @@ -358,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) { @@ -407,18 +423,20 @@ public class FlowConverter { continue; } if (action.getType() == ActionType.SET_NEXT_HOP) { - // TODO + logger.warn("Unsupported action: {}", action); continue; } } } + logger.trace("SAL Actions: {} Openflow Actions: {}", flow.getActions(), + actionsList); return actionsList; } /** * Utility to convert a SAL flow to an OF 1.0 (OFFlowMod) or to an OF 1.0 + * IPv6 extension (V6FlowMod) Flow modifier Message - * + * * @param sw * @param command * @param port @@ -446,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(); @@ -470,15 +485,15 @@ 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, + actionsList); + logger.trace("Openflow Mod Message: {}", fm); return fm; } @@ -493,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 @@ -516,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 @@ -545,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 @@ -584,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 @@ -614,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())); } } } @@ -654,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) @@ -680,7 +723,7 @@ public class FlowConverter { try { ip = InetAddress.getByAddress(addr); } catch (UnknownHostException e) { - e.printStackTrace(); + logger.error("", e); } salAction = new SetNwSrc(ip); } else if (ofAction instanceof OFActionNetworkLayerDestination) { @@ -691,7 +734,7 @@ public class FlowConverter { try { ip = InetAddress.getByAddress(addr); } catch (UnknownHostException e) { - e.printStackTrace(); + logger.error("", e); } salAction = new SetNwDst(ip); } else if (ofAction instanceof OFActionNetworkTypeOfService) { @@ -715,7 +758,56 @@ public class FlowConverter { // Create Flow flow = new Flow(salMatch, salActionList); } + logger.trace("Openflow Match: {} Openflow Actions: {}", ofMatch, + actionsList); + logger.trace("SAL Flow: {}", flow); return flow; } -} \ No newline at end of file + private static final Map> actionMap = new HashMap>() { + 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> getFlowActions(int ofActionBitmask) { + List> list = new ArrayList>(); + + 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; + } + +}