-
/*
* Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
*
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;
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<OFAction> actionsList; // OF 1.0 actions
}
/**
- * Returns the match in OF 1.0 (OFMatch) form or OF 1.0 + IPv6 extensions form (V6Match)
+ * Returns the match in OF 1.0 (OFMatch) form or OF 1.0 + IPv6 extensions
+ * form (V6Match)
*
* @return
*/
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;
}
if (match.isPresent(MatchType.NW_TOS)) {
/*
- * OF 1.0 switch expects the TOS as the 6 msb in the byte.
- * it is actually the DSCP field followed by a zero ECN
+ * OF 1.0 switch expects the TOS as the 6 msb in the byte. it is
+ * 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;
}
}
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);
}
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<OFAction> getOFActions() {
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;
}
if (action.getType() == ActionType.CONTROLLER) {
OFActionOutput ofAction = new OFActionOutput();
ofAction.setPort(OFPort.OFPP_CONTROLLER.getValue());
- // We want the whole frame hitting the match be sent to the controller
+ // We want the whole frame hitting the match be sent to the
+ // controller
ofAction.setMaxLength((short) 0xffff);
actionsList.add(ofAction);
actionsLength += OFActionOutput.MINIMUM_LENGTH;
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) {
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) {
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
+ * 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
if (port != null) {
((OFFlowMod) fm).setOutPort(port);
}
+ if (command == OFFlowMod.OFPFC_ADD || command == OFFlowMod.OFPFC_MODIFY
+ || command == OFFlowMod.OFPFC_MODIFY_STRICT) {
+ // Instruct switch to let controller know when flow is removed
+ ((OFFlowMod) fm).setFlags((short) 1);
+ }
} else {
((V6FlowMod) fm).setVendor();
((V6FlowMod) fm).setMatch((V6Match) ofMatch);
if (port != null) {
((V6FlowMod) fm).setOutPort(port);
}
+ if (command == OFFlowMod.OFPFC_ADD || command == OFFlowMod.OFPFC_MODIFY
+ || command == OFFlowMod.OFPFC_MODIFY_STRICT) {
+ // 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;
}
Match salMatch = new Match();
/*
- * Installed flow may not have a Match defined
- * like in case of a drop all flow
+ * Installed flow may not have a Match defined like in case of a
+ * drop all flow
*/
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
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) {
+ if ((ofMatch.getWildcards() & OFMatch.OFPFW_DL_VLAN_PCP) == 0) {
salMatch.setField(MatchType.DL_VLAN_PR, ofMatch
.getDataLayerVirtualLanPriorityCodePoint());
}
if (ofMatch.getNetworkSource() != 0) {
salMatch.setField(MatchType.NW_SRC, NetUtils
.getInetAddress(ofMatch.getNetworkSource()),
- NetUtils.getInetNetworkMask(ofMatch
- .getNetworkSourceMaskLen(), false));
+ NetUtils.getInetNetworkMask(
+ ofMatch.getNetworkSourceMaskLen(),
+ false));
}
if (ofMatch.getNetworkDestination() != 0) {
- salMatch
- .setField(
- MatchType.NW_DST,
- NetUtils.getInetAddress(ofMatch
- .getNetworkDestination()),
- NetUtils
- .getInetNetworkMask(
- ofMatch
- .getNetworkDestinationMaskLen(),
- false));
+ salMatch.setField(MatchType.NW_DST,
+ NetUtils.getInetAddress(ofMatch
+ .getNetworkDestination()),
+ NetUtils.getInetNetworkMask(
+ ofMatch.getNetworkDestinationMaskLen(),
+ false));
}
if (ofMatch.getNetworkTypeOfService() != 0) {
- int dscp = NetUtils.getUnsignedByte(
- ofMatch.getNetworkTypeOfService());
- byte tos = (byte)(dscp >> 2);
+ int dscp = NetUtils.getUnsignedByte(ofMatch
+ .getNetworkTypeOfService());
+ 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());
+ salMatch.setField(MatchType.NW_PROTO,
+ ofMatch.getNetworkProtocol());
}
if (ofMatch.getTransportSource() != 0) {
- salMatch.setField(MatchType.TP_SRC, ((Short) ofMatch
- .getTransportSource()));
+ salMatch.setField(MatchType.TP_SRC,
+ ofMatch.getTransportSource());
}
if (ofMatch.getTransportDestination() != 0) {
- salMatch.setField(MatchType.TP_DST, ((Short) ofMatch
- .getTransportDestination()));
+ salMatch.setField(MatchType.TP_DST,
+ 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
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) {
+ if ((v6Match.getWildcards() & OFMatch.OFPFW_DL_VLAN_PCP) == 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());
+ 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());
+ 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.getNetworkTypeOfService());
- byte tos = (byte) (dscp >> 2);
+ int dscp = NetUtils.getUnsignedByte(v6Match
+ .getNetworkTypeOfService());
+ byte tos = (byte) (dscp >> 2);
salMatch.setField(MatchType.NW_TOS, tos);
}
if (v6Match.getNetworkProtocol() != 0) {
- salMatch.setField(MatchType.NW_PROTO, v6Match
- .getNetworkProtocol());
+ salMatch.setField(MatchType.NW_PROTO,
+ v6Match.getNetworkProtocol());
}
if (v6Match.getTransportSource() != 0) {
- salMatch.setField(MatchType.TP_SRC, ((Short) v6Match
- .getTransportSource()));
+ salMatch.setField(MatchType.TP_SRC,
+ (v6Match.getTransportSource()));
}
if (v6Match.getTransportDestination() != 0) {
- salMatch.setField(MatchType.TP_DST, ((Short) v6Match
- .getTransportDestination()));
+ salMatch.setField(MatchType.TP_DST,
+ (v6Match.getTransportDestination()));
}
}
}
} else if (ofPort == OFPort.OFPP_NORMAL.getValue()) {
salAction = new HwPath();
} else if (ofPort == OFPort.OFPP_TABLE.getValue()) {
- salAction = new HwPath(); //TODO: we do not handle table in sal for now
+ salAction = new HwPath(); // TODO: we do not handle
+ // table in sal for now
} else {
- salAction = new Output(NodeConnectorCreator
- .createOFNodeConnector(ofPort, node));
+ salAction = new Output(
+ 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)
try {
ip = InetAddress.getByAddress(addr);
} catch (UnknownHostException e) {
- e.printStackTrace();
+ logger.error("", e);
}
salAction = new SetNwSrc(ip);
} else if (ofAction instanceof OFActionNetworkLayerDestination) {
try {
ip = InetAddress.getByAddress(addr);
} catch (UnknownHostException e) {
- e.printStackTrace();
+ logger.error("", e);
}
salAction = new SetNwDst(ip);
} else if (ofAction instanceof OFActionNetworkTypeOfService) {
// 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<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;
+ }
+
+}