/*
* Copyright (c) 2013, 2015 Cisco Systems, Inc. and others. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v1.0 which accompanies this distribution,
* and is available at http://www.eclipse.org/legal/epl-v10.html
*/
package org.opendaylight.openflowplugin.openflow.md.util;
import com.google.common.collect.ImmutableBiMap;
import org.opendaylight.openflowjava.protocol.api.util.BinContent;
import org.opendaylight.openflowplugin.api.OFConstants;
import org.opendaylight.openflowplugin.api.openflow.md.util.OpenflowVersion;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Uri;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.port.rev130925.PortNumberUni;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.OutputPortValues;
import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.common.types.rev130731.PortNumberValues;
import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.common.types.rev130731.PortNumberValuesV10;
/**
* Class which integrates the port constants defined and used by MDSAL and the ports defined in openflow java
* This class is responsible for converting MDSAL given logical names to port numbers and back.
* Any newer version of openflow can have a similar mapping or can/should be extended.
*
* @author Kamal Rameshan on 5/2/14.
*/
public class OpenflowPortsUtil {
private static final ImmutableBiMap<Short, ImmutableBiMap<String, Long>> versionPortMap;
private static final ImmutableBiMap<Short, ImmutableBiMap<Long, String>> versionInversePortMap;
static {
// v1.0 ports
final ImmutableBiMap<String, Long> ofv10ports = new ImmutableBiMap.Builder<String, Long>()
.put(OutputPortValues.MAX.toString(), (long) PortNumberValuesV10.MAX.getIntValue()) //0xff00
.put(OutputPortValues.INPORT.toString(), (long) PortNumberValuesV10.INPORT.getIntValue()) //0xfff8
.put(OutputPortValues.TABLE.toString(), (long) PortNumberValuesV10.TABLE.getIntValue()) //0xfff9
.put(OutputPortValues.NORMAL.toString(), (long) PortNumberValuesV10.NORMAL.getIntValue()) //0xfffa
.put(OutputPortValues.FLOOD.toString(), (long) PortNumberValuesV10.FLOOD.getIntValue()) //0xfffb
.put(OutputPortValues.ALL.toString(), (long) PortNumberValuesV10.ALL.getIntValue()) //0xfffc
.put(OutputPortValues.CONTROLLER.toString(), (long) PortNumberValuesV10.CONTROLLER.getIntValue()) //0xfffd
.put(OutputPortValues.LOCAL.toString(), (long) PortNumberValuesV10.LOCAL.getIntValue()) //0xfffe
.put(OutputPortValues.NONE.toString(), (long) PortNumberValuesV10.NONE.getIntValue()) //0xffff
.build();
// openflow 1.3 reserved ports.
// PortNumberValues are defined in OFJava yang. And yang maps an int to all enums. Hence we need to create longs from (-ve) ints
// TODO: do we need to define these ports in yang?
final ImmutableBiMap<String, Long> ofv13ports = new ImmutableBiMap.Builder<String, Long>()
.put(OutputPortValues.MAX.toString(), BinContent.intToUnsignedLong(PortNumberValues.MAX.getIntValue())) //0xffffff00
.put(OutputPortValues.INPORT.toString(), BinContent.intToUnsignedLong(PortNumberValues.INPORT.getIntValue())) //0xfffffff8
.put(OutputPortValues.TABLE.toString(), BinContent.intToUnsignedLong(PortNumberValues.TABLE.getIntValue())) //0xfffffff9
.put(OutputPortValues.NORMAL.toString(), BinContent.intToUnsignedLong(PortNumberValues.NORMAL.getIntValue())) //0xfffffffa
.put(OutputPortValues.FLOOD.toString(), BinContent.intToUnsignedLong(PortNumberValues.FLOOD.getIntValue())) //0xfffffffb
.put(OutputPortValues.ALL.toString(), BinContent.intToUnsignedLong(PortNumberValues.ALL.getIntValue())) //0xfffffffc
.put(OutputPortValues.CONTROLLER.toString(), BinContent.intToUnsignedLong(PortNumberValues.CONTROLLER.getIntValue())) //0xfffffffd
.put(OutputPortValues.LOCAL.toString(), BinContent.intToUnsignedLong(PortNumberValues.LOCAL.getIntValue())) //0xfffffffe
.put(OutputPortValues.ANY.toString(), BinContent.intToUnsignedLong(PortNumberValues.ANY.getIntValue())) //0xffffffff
.build();
versionPortMap = new ImmutableBiMap.Builder<Short, ImmutableBiMap<String, Long>>()
.put(OFConstants.OFP_VERSION_1_0, ofv10ports)
.put(OFConstants.OFP_VERSION_1_3, ofv13ports)
.build();
versionInversePortMap = new ImmutableBiMap.Builder<Short, ImmutableBiMap<Long, String>>()
.put(OFConstants.OFP_VERSION_1_0, ofv10ports.inverse())
.put(OFConstants.OFP_VERSION_1_3, ofv13ports.inverse())
.build();
}
public static String getPortLogicalName(final short ofVersion, final Long portNumber) {
return versionInversePortMap.get(ofVersion).get(portNumber);
}
public static String getPortLogicalName(final OpenflowVersion ofVersion, final Long portNumber) {
return ofVersion.equals(OpenflowVersion.UNSUPPORTED)
? null
: getPortLogicalName(ofVersion.getVersion(), portNumber);
}
public static Long getPortFromLogicalName(final OpenflowVersion ofVersion, final String logicalNameOrPort) {
Long port = versionPortMap.get(ofVersion.getVersion()).get(logicalNameOrPort);
if (port == null) {
try {
port = Long.decode(logicalNameOrPort);
} catch (final NumberFormatException ne) {
//ignore, sent null back.
if (logicalNameOrPort.contains(":")) {
port = Long.parseLong(logicalNameOrPort.substring(logicalNameOrPort.lastIndexOf(":") + 1));
}
}
}
return port;
}
public static PortNumberUni getProtocolAgnosticPort(final OpenflowVersion ofVersion, final Long portNumber) {
final String reservedPortLogicalName = getPortLogicalName(ofVersion, portNumber);
return reservedPortLogicalName == null
? new PortNumberUni(portNumber)
: new PortNumberUni(reservedPortLogicalName);
}
public static Long getProtocolPortNumber(final OpenflowVersion ofVersion, final PortNumberUni port) {
final String portLogicalName = port.getString();
return portLogicalName != null
? versionPortMap.get(ofVersion.getVersion()).get(portLogicalName)
: port.getUint32();
}
public static Long getMaxPortForVersion(final OpenflowVersion ofVersion) {
return getPortFromLogicalName(ofVersion, OutputPortValues.MAX.getName());
}
public static boolean isPortReserved(final OpenflowVersion ofVersion, final Long portNumber) {
return versionInversePortMap.get(ofVersion.getVersion()).containsKey(portNumber);
}
/**
* @param ofVersion OpenFlow version of the switch
* @param portNumber port number
* @return true if port number is valid for given protocol version
*/
public static boolean checkPortValidity(final OpenflowVersion ofVersion, final Long portNumber) {
boolean portIsValid = true;
if (portNumber == null) {
portIsValid = false;
} else if (portNumber < 0) {
portIsValid = false;
} else if (portNumber > getMaxPortForVersion(ofVersion)) {
if (!isPortReserved(ofVersion, portNumber)) {
portIsValid = false;
}
}
return portIsValid;
}
/**
* @param portNumber port number
* @return string containing number or logical name
*/
public static String portNumberToString(final PortNumberUni portNumber) {
String result = null;
if (portNumber.getUint32() != null) {
result = String.valueOf(portNumber.getUint32());
} else if (portNumber.getString() != null) {
result = portNumber.getString();
}
return result;
}
/**
* Converts port number to Uri
* @param version openflow version
* @param portNumber port number
* @return port number uri
*/
public static Uri getProtocolAgnosticPortUri(final short version, final long portNumber) {
return new Uri(portNumberToString(getProtocolAgnosticPort(OpenflowVersion.get(version), portNumber)));
}
}