Use ByteBuf.readRetainedSlice()
[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 package org.opendaylight.openflowplugin.openflow.md.util;
9
10 import com.google.common.collect.ImmutableBiMap;
11 import com.google.common.collect.Maps;
12 import java.util.Objects;
13 import org.eclipse.jdt.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.opendaylight.yangtools.yang.common.Uint32;
23 import org.opendaylight.yangtools.yang.common.Uint8;
24 import org.slf4j.Logger;
25 import org.slf4j.LoggerFactory;
26
27 /**
28  * Class which integrates the port constants defined and used by MDSAL and the ports defined in openflow java
29  * This class is responsible for converting MDSAL given logical names to port numbers and back.
30  * Any newer version of openflow can have a similar mapping or can/should be extended.
31  */
32 public final class OpenflowPortsUtil {
33     private OpenflowPortsUtil() {
34     }
35
36     private static final Logger LOG = LoggerFactory.getLogger(OpenflowPortsUtil.class);
37
38     // TODO: deprecate this
39     private static final ImmutableBiMap<Uint8, ImmutableBiMap<Long, String>> VERSION_INVERSE_PORT_MAP;
40
41     private static final ImmutableBiMap<Uint8, ImmutableBiMap<String, Uint32>> VERSION_PORT_MAP_UINT;
42     private static final ImmutableBiMap<Uint8, ImmutableBiMap<Uint32, String>> VERSION_INVERSE_PORT_MAP_UINT;
43
44     private static boolean inportWarnignAlreadyFired = false;
45
46     static {
47         // v1.0 ports
48         final ImmutableBiMap<String, Long> ofv10ports = new ImmutableBiMap.Builder<String, Long>()
49                 .put(OutputPortValues.MAX.getName(), (long) PortNumberValuesV10.MAX.getIntValue()) //0xff00
50                 .put(OutputPortValues.INPORT.getName(), (long) PortNumberValuesV10.INPORT.getIntValue()) //0xfff8
51                 .put(OutputPortValues.TABLE.getName(), (long) PortNumberValuesV10.TABLE.getIntValue()) //0xfff9
52                 .put(OutputPortValues.NORMAL.getName(), (long) PortNumberValuesV10.NORMAL.getIntValue()) //0xfffa
53                 .put(OutputPortValues.FLOOD.getName(), (long) PortNumberValuesV10.FLOOD.getIntValue()) //0xfffb
54                 .put(OutputPortValues.ALL.getName(), (long) PortNumberValuesV10.ALL.getIntValue()) //0xfffc
55                 .put(OutputPortValues.CONTROLLER.getName(),
56                         (long) PortNumberValuesV10.CONTROLLER.getIntValue()) //0xfffd
57                 .put(OutputPortValues.LOCAL.getName(), (long) PortNumberValuesV10.LOCAL.getIntValue()) //0xfffe
58                 .put(OutputPortValues.NONE.getName(), (long) PortNumberValuesV10.NONE.getIntValue()) //0xffff
59                 .build();
60
61         // openflow 1.3 reserved ports.
62         // PortNumberValues are defined in OFJava yang. And yang maps an int to all enums. Hence we need to create
63         // longs from (-ve) ints
64         // TODO: do we need to define these ports in yang?
65         final ImmutableBiMap<String, Long> ofv13ports = new ImmutableBiMap.Builder<String, Long>()
66                 .put(OutputPortValues.MAX.getName(),
67                         BinContent.intToUnsignedLong(PortNumberValues.MAX.getIntValue())) // 0xffffff00
68                 .put(OutputPortValues.INPORT.getName(),
69                         BinContent.intToUnsignedLong(PortNumberValues.INPORT.getIntValue())) // 0xfffffff8
70                 .put(OutputPortValues.TABLE.getName(),
71                         BinContent.intToUnsignedLong(PortNumberValues.TABLE.getIntValue())) // 0xfffffff9
72                 .put(OutputPortValues.NORMAL.getName(),
73                         BinContent.intToUnsignedLong(PortNumberValues.NORMAL.getIntValue())) // 0xfffffffa
74                 .put(OutputPortValues.FLOOD.getName(),
75                         BinContent.intToUnsignedLong(PortNumberValues.FLOOD.getIntValue())) // 0xfffffffb
76                 .put(OutputPortValues.ALL.getName(),
77                         BinContent.intToUnsignedLong(PortNumberValues.ALL.getIntValue())) // 0xfffffffc
78                 .put(OutputPortValues.CONTROLLER.getName(),
79                         BinContent.intToUnsignedLong(PortNumberValues.CONTROLLER.getIntValue())) // 0xfffffffd
80                 .put(OutputPortValues.LOCAL.getName(),
81                         BinContent.intToUnsignedLong(PortNumberValues.LOCAL.getIntValue())) // 0xfffffffe
82                 .put(OutputPortValues.ANY.getName(),
83                         BinContent.intToUnsignedLong(PortNumberValues.ANY.getIntValue())) // 0xffffffff
84                 .build();
85
86         VERSION_INVERSE_PORT_MAP = new ImmutableBiMap.Builder<Uint8, ImmutableBiMap<Long, String>>()
87                 .put(OFConstants.OFP_VERSION_1_0, ofv10ports.inverse())
88                 .put(OFConstants.OFP_VERSION_1_3, ofv13ports.inverse())
89                 .build();
90
91         final ImmutableBiMap<String, Uint32> ofv10portsUint = ImmutableBiMap.copyOf(Maps.transformValues(ofv10ports,
92             l -> Uint32.valueOf(l).intern()));
93         final ImmutableBiMap<String, Uint32> ofv13portsUint = ImmutableBiMap.copyOf(Maps.transformValues(ofv13ports,
94             l -> Uint32.valueOf(l).intern()));
95
96         VERSION_PORT_MAP_UINT = new ImmutableBiMap.Builder<Uint8, ImmutableBiMap<String, Uint32>>()
97                 .put(OFConstants.OFP_VERSION_1_0, ofv10portsUint)
98                 .put(OFConstants.OFP_VERSION_1_3, ofv13portsUint)
99                 .build();
100
101         VERSION_INVERSE_PORT_MAP_UINT = new ImmutableBiMap.Builder<Uint8, ImmutableBiMap<Uint32, String>>()
102                 .put(OFConstants.OFP_VERSION_1_0, ofv10portsUint.inverse())
103                 .put(OFConstants.OFP_VERSION_1_3, ofv13portsUint.inverse())
104                 .build();
105     }
106
107     // TODO: deprecate and migrate
108     public static String getPortLogicalName(final Uint8 ofVersion, final Long portNumber) {
109         return VERSION_INVERSE_PORT_MAP.get(ofVersion).get(portNumber);
110     }
111
112     public static String getPortLogicalName(final Uint8 ofVersion, final Uint32 portNumber) {
113         return VERSION_INVERSE_PORT_MAP_UINT.get(ofVersion).get(portNumber);
114     }
115
116     // TODO: deprecate and migrate
117     public static String getPortLogicalName(final OpenflowVersion ofVersion, final Long portNumber) {
118         return ofVersion.equals(OpenflowVersion.UNSUPPORTED)
119                 ? null
120                 : getPortLogicalName(ofVersion.getVersion(), portNumber);
121     }
122
123     public static String getPortLogicalName(final OpenflowVersion ofVersion, final Uint32 portNumber) {
124         return ofVersion.equals(OpenflowVersion.UNSUPPORTED)
125                 ? null
126                 : getPortLogicalName(ofVersion.getVersion(), portNumber);
127     }
128
129     @Nullable
130     static Uint32 getPortFromLogicalName(final OpenflowVersion ofVersion, final String logicalNameOrPort) {
131
132         //The correct keyword defined in openflow specification in IN_PORT so we need to allow to use it
133         //for legacy reasons we can't just simply drop the misspelled INPORT
134         //TODO: Consider to remove 'INPORT' keyword
135         Uint32 port;
136         if (Objects.equals(logicalNameOrPort, "INPORT")) {
137             if (!inportWarnignAlreadyFired) {
138                 LOG.warn("Using '{}' in port field is not recommended use 'IN_PORT' instead", logicalNameOrPort);
139                 inportWarnignAlreadyFired = true;
140             }
141             port = VERSION_PORT_MAP_UINT.get(ofVersion.getVersion()).get(OutputPortValues.INPORT.getName());
142         } else {
143             port = VERSION_PORT_MAP_UINT.get(ofVersion.getVersion()).get(logicalNameOrPort);
144         }
145         if (port == null) {
146             try {
147                 port = Uint32.valueOf(Long.decode(logicalNameOrPort));
148             } catch (final IllegalArgumentException ne) {
149                 //ignore, sent null back.
150                 final int lastColon = logicalNameOrPort.lastIndexOf(':');
151                 if (lastColon != -1) {
152                     port = Uint32.valueOf(logicalNameOrPort.substring(lastColon + 1));
153                 }
154             }
155         }
156         return port;
157     }
158
159     public static PortNumberUni getProtocolAgnosticPort(final OpenflowVersion ofVersion, final Long portNumber) {
160         final String reservedPortLogicalName = getPortLogicalName(ofVersion, portNumber);
161
162         return reservedPortLogicalName == null
163                 ? new PortNumberUni(portNumber == null ? (Uint32) null : Uint32.valueOf(portNumber))
164                 : new PortNumberUni(reservedPortLogicalName);
165     }
166
167     // TODO: deprecate and migrate
168     public static PortNumberUni getProtocolAgnosticPort(final OpenflowVersion ofVersion, final Uint32 portNumber) {
169         final String reservedPortLogicalName = getPortLogicalName(ofVersion, portNumber);
170
171         return reservedPortLogicalName == null
172                 ? new PortNumberUni(portNumber)
173                 : new PortNumberUni(reservedPortLogicalName);
174     }
175
176
177     public static Uint32 getProtocolPortNumber(final OpenflowVersion ofVersion, final PortNumberUni port) {
178         final String portLogicalName = port.getString();
179
180         return portLogicalName != null
181                 ? VERSION_PORT_MAP_UINT.get(ofVersion.getVersion()).get(portLogicalName)
182                 : port.getUint32();
183     }
184
185     public static Uint32 getMaxPortForVersion(final OpenflowVersion ofVersion) {
186         return getPortFromLogicalName(ofVersion, OutputPortValues.MAX.getName());
187     }
188
189     public static boolean isPortReserved(final OpenflowVersion ofVersion, final Uint32 portNumber) {
190         return VERSION_INVERSE_PORT_MAP_UINT.get(ofVersion.getVersion()).containsKey(portNumber);
191     }
192
193     /**
194      * Checks port validity.
195      *
196      * @param ofVersion OpenFlow version of the switch
197      * @param portNumber port number
198      * @return true if port number is valid for given protocol version
199      */
200     public static boolean checkPortValidity(final OpenflowVersion ofVersion, final Uint32 portNumber) {
201         boolean portIsValid = true;
202         if (portNumber == null) {
203             portIsValid = false;
204         } else if (portNumber.compareTo(getMaxPortForVersion(ofVersion)) > 0) {
205             if (!isPortReserved(ofVersion, portNumber)) {
206                 portIsValid = false;
207             }
208         }
209         return portIsValid;
210     }
211
212     /**
213      * Converts a port number to a string.
214      *
215      * @param portNumber port number
216      * @return string containing number or logical name
217      */
218     public static String portNumberToString(final PortNumberUni portNumber) {
219         String result = null;
220         if (portNumber.getUint32() != null) {
221             result = String.valueOf(portNumber.getUint32());
222         } else if (portNumber.getString() != null) {
223             result = portNumber.getString();
224         }
225         return result;
226     }
227
228     /**
229      * Converts port number to Uri.
230      *
231      * @param version openflow version
232      * @param portNumber port number
233      * @return port number uri
234      */
235     // TODO: deprecate and migrate
236     public static Uri getProtocolAgnosticPortUri(final Uint8 version, final long portNumber) {
237         return new Uri(portNumberToString(getProtocolAgnosticPort(OpenflowVersion.get(version), portNumber)));
238     }
239
240     /**
241      * Converts port number to Uri.
242      *
243      * @param version openflow version
244      * @param portNumber port number
245      * @return port number uri
246      */
247     public static Uri getProtocolAgnosticPortUri(final Uint8 version, final Uint32 portNumber) {
248         return new Uri(portNumberToString(getProtocolAgnosticPort(OpenflowVersion.get(version), portNumber)));
249     }
250 }