Merge "Update docs header to Magnesium in the master"
[openflowplugin.git] / openflowplugin / src / main / java / org / opendaylight / openflowplugin / openflow / md / util / OpenflowPortsUtil.java
1 /*
2  * Copyright (c) 2013, 2015 Cisco Systems, Inc. and others.  All rights reserved.
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6  * and is available at http://www.eclipse.org/legal/epl-v10.html
7  */
8
9 package org.opendaylight.openflowplugin.openflow.md.util;
10
11 import com.google.common.collect.ImmutableBiMap;
12 import java.util.Objects;
13 import javax.annotation.Nullable;
14 import org.opendaylight.openflowjava.protocol.api.util.BinContent;
15 import org.opendaylight.openflowplugin.api.OFConstants;
16 import org.opendaylight.openflowplugin.api.openflow.md.util.OpenflowVersion;
17 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Uri;
18 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.port.rev130925.PortNumberUni;
19 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.OutputPortValues;
20 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.common.types.rev130731.PortNumberValues;
21 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.common.types.rev130731.PortNumberValuesV10;
22 import org.slf4j.Logger;
23 import org.slf4j.LoggerFactory;
24
25 /**
26  * Class which integrates the port constants defined and used by MDSAL and the ports defined in openflow java
27  * This class is responsible for converting MDSAL given logical names to port numbers and back.
28  * Any newer version of openflow can have a similar mapping or can/should be extended.
29  */
30 public final class OpenflowPortsUtil {
31     private OpenflowPortsUtil() {
32     }
33
34     private static final Logger LOG = LoggerFactory.getLogger(OpenflowPortsUtil.class);
35     private static final ImmutableBiMap<Short, ImmutableBiMap<String, Long>> VERSION_PORT_MAP;
36     private static final ImmutableBiMap<Short, ImmutableBiMap<Long, String>> VERSION_INVERSE_PORT_MAP;
37
38     private static boolean inportWarnignAlreadyFired = false;
39
40     static {
41         // v1.0 ports
42         final ImmutableBiMap<String, Long> ofv10ports = new ImmutableBiMap.Builder<String, Long>()
43                 .put(OutputPortValues.MAX.getName(), (long) PortNumberValuesV10.MAX.getIntValue()) //0xff00
44                 .put(OutputPortValues.INPORT.getName(), (long) PortNumberValuesV10.INPORT.getIntValue()) //0xfff8
45                 .put(OutputPortValues.TABLE.getName(), (long) PortNumberValuesV10.TABLE.getIntValue()) //0xfff9
46                 .put(OutputPortValues.NORMAL.getName(), (long) PortNumberValuesV10.NORMAL.getIntValue()) //0xfffa
47                 .put(OutputPortValues.FLOOD.getName(), (long) PortNumberValuesV10.FLOOD.getIntValue()) //0xfffb
48                 .put(OutputPortValues.ALL.getName(), (long) PortNumberValuesV10.ALL.getIntValue()) //0xfffc
49                 .put(OutputPortValues.CONTROLLER.getName(),
50                         (long) PortNumberValuesV10.CONTROLLER.getIntValue()) //0xfffd
51                 .put(OutputPortValues.LOCAL.getName(), (long) PortNumberValuesV10.LOCAL.getIntValue()) //0xfffe
52                 .put(OutputPortValues.NONE.getName(), (long) PortNumberValuesV10.NONE.getIntValue()) //0xffff
53                 .build();
54
55         // openflow 1.3 reserved ports.
56         // PortNumberValues are defined in OFJava yang. And yang maps an int to all enums. Hence we need to create
57         // longs from (-ve) ints
58         // TODO: do we need to define these ports in yang?
59         final ImmutableBiMap<String, Long> ofv13ports = new ImmutableBiMap.Builder<String, Long>()
60                 .put(OutputPortValues.MAX.getName(),
61                         BinContent.intToUnsignedLong(PortNumberValues.MAX.getIntValue())) // 0xffffff00
62                 .put(OutputPortValues.INPORT.getName(),
63                         BinContent.intToUnsignedLong(PortNumberValues.INPORT.getIntValue())) // 0xfffffff8
64                 .put(OutputPortValues.TABLE.getName(),
65                         BinContent.intToUnsignedLong(PortNumberValues.TABLE.getIntValue())) // 0xfffffff9
66                 .put(OutputPortValues.NORMAL.getName(),
67                         BinContent.intToUnsignedLong(PortNumberValues.NORMAL.getIntValue())) // 0xfffffffa
68                 .put(OutputPortValues.FLOOD.getName(),
69                         BinContent.intToUnsignedLong(PortNumberValues.FLOOD.getIntValue())) // 0xfffffffb
70                 .put(OutputPortValues.ALL.getName(),
71                         BinContent.intToUnsignedLong(PortNumberValues.ALL.getIntValue())) // 0xfffffffc
72                 .put(OutputPortValues.CONTROLLER.getName(),
73                         BinContent.intToUnsignedLong(PortNumberValues.CONTROLLER.getIntValue())) // 0xfffffffd
74                 .put(OutputPortValues.LOCAL.getName(),
75                         BinContent.intToUnsignedLong(PortNumberValues.LOCAL.getIntValue())) // 0xfffffffe
76                 .put(OutputPortValues.ANY.getName(),
77                         BinContent.intToUnsignedLong(PortNumberValues.ANY.getIntValue())) // 0xffffffff
78                 .build();
79
80         VERSION_PORT_MAP = new ImmutableBiMap.Builder<Short, ImmutableBiMap<String, Long>>()
81                 .put(OFConstants.OFP_VERSION_1_0, ofv10ports)
82                 .put(OFConstants.OFP_VERSION_1_3, ofv13ports)
83                 .build();
84
85         VERSION_INVERSE_PORT_MAP = new ImmutableBiMap.Builder<Short, ImmutableBiMap<Long, String>>()
86                 .put(OFConstants.OFP_VERSION_1_0, ofv10ports.inverse())
87                 .put(OFConstants.OFP_VERSION_1_3, ofv13ports.inverse())
88                 .build();
89     }
90
91     public static String getPortLogicalName(final short ofVersion, final Long portNumber) {
92         return VERSION_INVERSE_PORT_MAP.get(ofVersion).get(portNumber);
93     }
94
95     public static String getPortLogicalName(final OpenflowVersion ofVersion, final Long portNumber) {
96         return ofVersion.equals(OpenflowVersion.UNSUPPORTED)
97                 ? null
98                 : getPortLogicalName(ofVersion.getVersion(), portNumber);
99     }
100
101     @Nullable
102     static Long getPortFromLogicalName(final OpenflowVersion ofVersion, final String logicalNameOrPort) {
103
104         //The correct keyword defined in openflow specification in IN_PORT so we need to allow to use it
105         //for legacy reasons we can't just simply drop the misspelled INPORT
106         //TODO: Consider to remove 'INPORT' keyword
107         Long port;
108         if (Objects.equals(logicalNameOrPort, "INPORT")) {
109             if (!inportWarnignAlreadyFired) {
110                 LOG.warn("Using '{}' in port field is not recommended use 'IN_PORT' instead", logicalNameOrPort);
111                 inportWarnignAlreadyFired = true;
112             }
113             port = VERSION_PORT_MAP.get(ofVersion.getVersion()).get(OutputPortValues.INPORT.getName());
114         } else {
115             port = VERSION_PORT_MAP.get(ofVersion.getVersion()).get(logicalNameOrPort);
116         }
117         if (port == null) {
118             try {
119                 port = Long.decode(logicalNameOrPort);
120             } catch (final NumberFormatException ne) {
121                 //ignore, sent null back.
122                 if (logicalNameOrPort.contains(":")) {
123                     port = Long.parseLong(logicalNameOrPort.substring(logicalNameOrPort.lastIndexOf(":") + 1));
124                 }
125             }
126         }
127         return port;
128     }
129
130     public static PortNumberUni getProtocolAgnosticPort(final OpenflowVersion ofVersion, final Long portNumber) {
131         final String reservedPortLogicalName = getPortLogicalName(ofVersion, portNumber);
132
133         return reservedPortLogicalName == null
134                 ? new PortNumberUni(portNumber)
135                 : new PortNumberUni(reservedPortLogicalName);
136     }
137
138     public static Long getProtocolPortNumber(final OpenflowVersion ofVersion, final PortNumberUni port) {
139         final String portLogicalName = port.getString();
140
141         return portLogicalName != null
142                 ? VERSION_PORT_MAP.get(ofVersion.getVersion()).get(portLogicalName)
143                 : port.getUint32();
144     }
145
146     public static Long getMaxPortForVersion(final OpenflowVersion ofVersion) {
147         return getPortFromLogicalName(ofVersion, OutputPortValues.MAX.getName());
148     }
149
150     public static boolean isPortReserved(final OpenflowVersion ofVersion, final Long portNumber) {
151         return VERSION_INVERSE_PORT_MAP.get(ofVersion.getVersion()).containsKey(portNumber);
152     }
153
154     /**
155      * Checks port validity.
156      *
157      * @param ofVersion OpenFlow version of the switch
158      * @param portNumber port number
159      * @return true if port number is valid for given protocol version
160      */
161     public static boolean checkPortValidity(final OpenflowVersion ofVersion, final Long portNumber) {
162         boolean portIsValid = true;
163         if (portNumber == null) {
164             portIsValid = false;
165         } else if (portNumber < 0) {
166             portIsValid = false;
167         } else if (portNumber > getMaxPortForVersion(ofVersion)) {
168             if (!isPortReserved(ofVersion, portNumber)) {
169                 portIsValid = false;
170             }
171         }
172         return portIsValid;
173     }
174
175     /**
176      * Converts a port number to a string.
177      *
178      * @param portNumber port number
179      * @return string containing number or logical name
180      */
181     public static String portNumberToString(final PortNumberUni portNumber) {
182         String result = null;
183         if (portNumber.getUint32() != null) {
184             result = String.valueOf(portNumber.getUint32());
185         } else if (portNumber.getString() != null) {
186             result = portNumber.getString();
187         }
188         return result;
189     }
190
191     /**
192      * Converts port number to Uri.
193      *
194      * @param version openflow version
195      * @param portNumber port number
196      * @return port number uri
197      */
198     public static Uri getProtocolAgnosticPortUri(final short version, final long portNumber) {
199         return new Uri(portNumberToString(getProtocolAgnosticPort(OpenflowVersion.get(version), portNumber)));
200     }
201 }