blob: 9a3014efc442ca92d8aa32ae81cf9412f69fd823 [file] [log] [blame]
Jonathan Hart6df90172014-04-03 10:13:11 -07001package net.onrc.onos.core.datastore.topology;
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -07002
3import java.nio.ByteBuffer;
4import java.util.HashMap;
5import java.util.Iterator;
6import java.util.Map;
7
Jonathan Hart6df90172014-04-03 10:13:11 -07008import net.onrc.onos.core.datastore.DataStoreClient;
9import net.onrc.onos.core.datastore.IKVTable.IKVEntry;
Yuta HIGUCHI1cd90292014-04-03 14:31:10 -070010import net.onrc.onos.core.datastore.serializers.Topology.PortProperty;
Jonathan Hart6df90172014-04-03 10:13:11 -070011import net.onrc.onos.core.datastore.utils.ByteArrayUtil;
12import net.onrc.onos.core.datastore.utils.KVObject;
Jonathan Hart472062d2014-04-03 10:56:48 -070013import net.onrc.onos.core.topology.PortEvent;
Yuta HIGUCHI8f3dfa32014-06-25 00:14:25 -070014import net.onrc.onos.core.util.Dpid;
15import net.onrc.onos.core.util.PortNumber;
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -070016
17import org.slf4j.Logger;
18import org.slf4j.LoggerFactory;
19
20import com.esotericsoftware.kryo.Kryo;
21import com.google.protobuf.ByteString;
22import com.google.protobuf.InvalidProtocolBufferException;
23
24/**
25 * Port object in data store.
Ray Milkey269ffb92014-04-03 14:43:30 -070026 * <p/>
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -070027 * Note: This class will not maintain invariants.
Ray Milkey269ffb92014-04-03 14:43:30 -070028 * e.g., It will NOT automatically remove Links or Devices on Port,
29 * when deleting a Port.
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -070030 */
31public class KVPort extends KVObject {
32 private static final Logger log = LoggerFactory.getLogger(KVPort.class);
33
Ray Milkey5c9f2db2014-04-09 10:31:21 -070034 private static final ThreadLocal<Kryo> PORT_KRYO = new ThreadLocal<Kryo>() {
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -070035 @Override
36 protected Kryo initialValue() {
37 Kryo kryo = new Kryo();
38 kryo.setRegistrationRequired(true);
39 kryo.setReferences(false);
40 kryo.register(byte[].class);
41 kryo.register(byte[][].class);
42 kryo.register(HashMap.class);
43 // TODO check if we should explicitly specify EnumSerializer
44 kryo.register(STATUS.class);
45 return kryo;
46 }
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -070047 };
48
Yuta HIGUCHIcc561882014-05-22 10:31:32 -070049 static final String PORT_TABLE_SUFFIX = ":Port";
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -070050
51 // must not re-order enum members, ordinal will be sent over wire
Yuta HIGUCHIcc561882014-05-22 10:31:32 -070052 /**
53 * Status.
54 */
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -070055 public enum STATUS {
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -070056 INACTIVE, ACTIVE;
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -070057 }
58
59 private final Long dpid;
60 private final Long number;
61
62 private STATUS status;
63
Yuta HIGUCHIcc561882014-05-22 10:31:32 -070064 /**
65 * Generate a PortID from port pair (dpid, number).
66 *
67 * @param dpid DPID of a switch it reside on.
68 * @param number port number of this
69 * @return PortID
70 */
Yuta HIGUCHI8f3dfa32014-06-25 00:14:25 -070071 public static byte[] getPortID(final Dpid dpid, final PortNumber number) {
72 return PortEvent.getPortID(dpid, number).array();
73 }
74
75 /**
76 * Generate a PortID from port pair (dpid, number).
77 *
78 * @param dpid DPID of a switch it reside on.
79 * @param number port number of this
80 * @return PortID
81 */
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -070082 public static byte[] getPortID(final Long dpid, final Long number) {
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -070083 return PortEvent.getPortID(dpid, number).array();
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -070084 }
85
Yuta HIGUCHIcc561882014-05-22 10:31:32 -070086 /**
87 * Gets the port pair from PortID.
88 *
89 * @param key PortID
90 * @return port pair (dpid, number)
91 */
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -070092 public static long[] getPortPairFromKey(final byte[] key) {
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -070093 return getPortPairFromKey(ByteBuffer.wrap(key));
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -070094 }
95
Yuta HIGUCHIcc561882014-05-22 10:31:32 -070096 /**
97 * Gets the port pair from PortID.
98 *
99 * @param keyBuf PortID
100 * @return port pair (dpid, number)
101 */
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700102 public static long[] getPortPairFromKey(final ByteBuffer keyBuf) {
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700103 if (keyBuf.getChar() != 'S') {
104 throw new IllegalArgumentException("Invalid Port key:" + keyBuf
105 + " "
Yuta HIGUCHI805bc8f2014-04-16 11:51:43 -0700106 + ByteArrayUtil.toHexStringBuilder(keyBuf.array(), ":"));
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700107 }
Yuta HIGUCHIa14eb172014-03-24 15:03:23 -0700108 long[] pair = new long[2];
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700109 pair[0] = keyBuf.getLong();
110 if (keyBuf.getChar() != 'P') {
111 throw new IllegalArgumentException("Invalid Port key:" + keyBuf
112 + " "
Yuta HIGUCHI805bc8f2014-04-16 11:51:43 -0700113 + ByteArrayUtil.toHexStringBuilder(keyBuf.array(), ":"));
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700114 }
115 pair[1] = keyBuf.getLong();
116 return pair;
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700117
118 }
119
Yuta HIGUCHIcc561882014-05-22 10:31:32 -0700120 /**
121 * Gets the port number from PortID.
122 *
123 * @param key PortID
124 * @return port number
125 */
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700126 public static long getDpidFromKey(final byte[] key) {
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700127 return getPortPairFromKey(key)[0];
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700128 }
129
Yuta HIGUCHIcc561882014-05-22 10:31:32 -0700130 /**
131 * Gets the dpid of an switch from PortID.
132 *
133 * @param key PortID
134 * @return dpid
135 */
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700136 public static long getNumberFromKey(final byte[] key) {
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700137 return getPortPairFromKey(key)[1];
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700138 }
139
Yuta HIGUCHIcc561882014-05-22 10:31:32 -0700140 /**
141 * KVPort constructor for default namespace.
142 *
143 * @param dpid DPID of the switch this port is on
144 * @param number port number of this port
145 */
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700146 public KVPort(final Long dpid, final Long number) {
Yuta HIGUCHIcc561882014-05-22 10:31:32 -0700147 this(dpid, number, DEFAULT_NAMESPACE);
148 }
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700149
Yuta HIGUCHIcc561882014-05-22 10:31:32 -0700150 /**
151 * KVPort constructor for specified namespace.
152 *
153 * @param dpid DPID of the switch this port is on
154 * @param number port number of this port
155 * @param namespace namespace to create this object
156 */
157 public KVPort(final Long dpid, final Long number, final String namespace) {
158 super(DataStoreClient.getClient()
159 .getTable(namespace + PORT_TABLE_SUFFIX),
160 getPortID(dpid, number), namespace);
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700161
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700162 this.dpid = dpid;
163 this.number = number;
164 this.status = STATUS.INACTIVE;
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700165 }
166
167 /**
Yuta HIGUCHI8f3dfa32014-06-25 00:14:25 -0700168 * KVPort constructor for default namespace.
169 *
170 * @param dpid DPID of the switch this port is on
171 * @param number port number of this port
172 */
173 public KVPort(final Dpid dpid, final PortNumber number) {
174 this(dpid, number, DEFAULT_NAMESPACE);
175 }
176
177 /**
178 * KVPort constructor for specified namespace.
179 *
180 * @param dpid DPID of the switch this port is on
181 * @param number port number of this port
182 * @param namespace namespace to create this object
183 */
184 public KVPort(final Dpid dpid, final PortNumber number, final String namespace) {
185 this(dpid.value(), (long) number.value(), namespace);
186 }
187
188 /**
Yuta HIGUCHIcc561882014-05-22 10:31:32 -0700189 * Gets an instance from PortID in default namespace.
Jonathan Hart99ff20a2014-06-15 16:53:00 -0700190 * <p/>
191 * Note: You need to call `read()` to get the DB content.
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700192 *
Yuta HIGUCHIcc561882014-05-22 10:31:32 -0700193 * @param key PortID
194 * @return {@link KVPort} instance
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700195 */
196 public static KVPort createFromKey(final byte[] key) {
Yuta HIGUCHIcc561882014-05-22 10:31:32 -0700197 return createFromKey(key, DEFAULT_NAMESPACE);
198 }
199
200 /**
201 * Gets an instance from PortID in specified namespace.
Jonathan Hart99ff20a2014-06-15 16:53:00 -0700202 * <p/>
203 * Note: You need to call `read()` to get the DB content.
Yuta HIGUCHIcc561882014-05-22 10:31:32 -0700204 *
205 * @param key PortID
206 * @param namespace namespace to create this object.
207 * @return {@link KVPort} instance
Yuta HIGUCHIcc561882014-05-22 10:31:32 -0700208 */
209 public static KVPort createFromKey(final byte[] key, final String namespace) {
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700210 long[] pair = getPortPairFromKey(key);
Yuta HIGUCHIcc561882014-05-22 10:31:32 -0700211 return new KVPort(pair[0], pair[1], namespace);
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700212 }
213
Yuta HIGUCHIcc561882014-05-22 10:31:32 -0700214 /**
215 * Gets all the Ports in default namespace.
216 *
217 * @return Ports
218 */
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700219 public static Iterable<KVPort> getAllPorts() {
Yuta HIGUCHIcc561882014-05-22 10:31:32 -0700220 return getAllPorts(DEFAULT_NAMESPACE);
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700221 }
222
Yuta HIGUCHIcc561882014-05-22 10:31:32 -0700223 /**
224 * Gets all the Ports in specified namespace.
225 *
226 * @param namespace namespace to iterate over
227 * @return Ports
228 */
229 public static Iterable<KVPort> getAllPorts(final String namespace) {
230 return new PortEnumerator(namespace);
231 }
232
233 /**
234 * Utility class to provide Iterable interface.
235 */
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700236 public static class PortEnumerator implements Iterable<KVPort> {
237
Yuta HIGUCHIcc561882014-05-22 10:31:32 -0700238 private final String namespace;
239
240 /**
241 * Constructor to iterate Ports in specified namespace.
242 *
243 * @param namespace namespace to iterate through
244 */
245 public PortEnumerator(final String namespace) {
246 this.namespace = namespace;
247 }
248
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700249 @Override
250 public Iterator<KVPort> iterator() {
Yuta HIGUCHIcc561882014-05-22 10:31:32 -0700251 return new PortIterator(namespace);
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700252 }
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700253 }
254
Yuta HIGUCHIcc561882014-05-22 10:31:32 -0700255 /**
256 * Utility class to provide Iterator over all the Port objects.
257 */
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700258 public static class PortIterator extends AbstractObjectIterator<KVPort> {
259
Yuta HIGUCHIcc561882014-05-22 10:31:32 -0700260 /**
261 * Constructor to create an iterator to iterate all the Ports
262 * in specified namespace.
263 *
264 * @param namespace namespace to iterate through
265 */
266 public PortIterator(final String namespace) {
267 super(DataStoreClient.getClient()
268 .getTable(namespace + PORT_TABLE_SUFFIX), namespace);
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700269 }
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700270
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700271 @Override
272 public KVPort next() {
273 IKVEntry o = enumerator.next();
Yuta HIGUCHIcc561882014-05-22 10:31:32 -0700274 KVPort e = KVPort.createFromKey(o.getKey(), namespace);
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700275 e.deserialize(o.getValue(), o.getVersion());
276 return e;
277 }
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700278 }
279
Yuta HIGUCHIcc561882014-05-22 10:31:32 -0700280 /**
281 * Gets the status.
282 *
283 * @return status
284 */
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700285 public STATUS getStatus() {
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700286 return status;
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700287 }
288
Yuta HIGUCHIcc561882014-05-22 10:31:32 -0700289 /**
290 * Sets the status.
291 *
292 * @param status new status
293 */
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700294 public void setStatus(final STATUS status) {
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700295 this.status = status;
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700296 }
297
Yuta HIGUCHIcc561882014-05-22 10:31:32 -0700298 /**
299 * Gets the DPID of the switch this port is on.
300 *
301 * @return DPID of the switch this port is on
302 */
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700303 public Long getDpid() {
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700304 return dpid;
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700305 }
306
Yuta HIGUCHIcc561882014-05-22 10:31:32 -0700307 /**
308 * Gets the port number of this port.
309 *
310 * @return port number of this port
311 */
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700312 public Long getNumber() {
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700313 return number;
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700314 }
315
Yuta HIGUCHIcc561882014-05-22 10:31:32 -0700316 /**
317 * Gets the PortID.
318 *
319 * @return PortID
320 */
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700321 public byte[] getId() {
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700322 return getKey();
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700323 }
324
325 @Override
326 public byte[] serialize() {
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700327 Map<Object, Object> map = getPropertyMap();
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700328
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700329 PortProperty.Builder port = PortProperty.newBuilder();
330 port.setDpid(dpid);
331 port.setNumber(number);
332 port.setStatus(status.ordinal());
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700333
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700334 if (!map.isEmpty()) {
Ray Milkey5c9f2db2014-04-09 10:31:21 -0700335 byte[] propMaps = serializePropertyMap(PORT_KRYO.get(), map);
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700336 port.setValue(ByteString.copyFrom(propMaps));
337 }
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700338
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700339 return port.build().toByteArray();
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700340 }
341
342 @Override
343 protected boolean deserialize(final byte[] bytes) {
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700344 try {
345 boolean success = true;
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700346
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700347 PortProperty port = PortProperty.parseFrom(bytes);
348 byte[] props = port.getValue().toByteArray();
Ray Milkey5c9f2db2014-04-09 10:31:21 -0700349 success &= deserializePropertyMap(PORT_KRYO.get(), props);
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700350 this.status = STATUS.values()[port.getStatus()];
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700351
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700352 return success;
353 } catch (InvalidProtocolBufferException e) {
354 log.error("Deserializing Port: " + this + " failed.", e);
355 return false;
356 }
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700357 }
358
359 @Override
360 public String toString() {
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700361 // TODO output all properties?
362 return "[" + this.getClass().getSimpleName()
363 + " 0x" + Long.toHexString(dpid) + "@" + number
364 + " STATUS:" + status + "]";
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700365 }
366}