blob: 72fa34844eaf1380f584d96740b7665baa1c656a [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 HIGUCHI66ca1bf2014-03-12 18:34:09 -070014
15import org.slf4j.Logger;
16import org.slf4j.LoggerFactory;
17
18import com.esotericsoftware.kryo.Kryo;
19import com.google.protobuf.ByteString;
20import com.google.protobuf.InvalidProtocolBufferException;
21
22/**
23 * Port object in data store.
Ray Milkey269ffb92014-04-03 14:43:30 -070024 * <p/>
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -070025 * Note: This class will not maintain invariants.
Ray Milkey269ffb92014-04-03 14:43:30 -070026 * e.g., It will NOT automatically remove Links or Devices on Port,
27 * when deleting a Port.
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -070028 */
29public class KVPort extends KVObject {
30 private static final Logger log = LoggerFactory.getLogger(KVPort.class);
31
Ray Milkey5c9f2db2014-04-09 10:31:21 -070032 private static final ThreadLocal<Kryo> PORT_KRYO = new ThreadLocal<Kryo>() {
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -070033 @Override
34 protected Kryo initialValue() {
35 Kryo kryo = new Kryo();
36 kryo.setRegistrationRequired(true);
37 kryo.setReferences(false);
38 kryo.register(byte[].class);
39 kryo.register(byte[][].class);
40 kryo.register(HashMap.class);
41 // TODO check if we should explicitly specify EnumSerializer
42 kryo.register(STATUS.class);
43 return kryo;
44 }
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -070045 };
46
Yuta HIGUCHIcc561882014-05-22 10:31:32 -070047 static final String PORT_TABLE_SUFFIX = ":Port";
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -070048
49 // must not re-order enum members, ordinal will be sent over wire
Yuta HIGUCHIcc561882014-05-22 10:31:32 -070050 /**
51 * Status.
52 */
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -070053 public enum STATUS {
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -070054 INACTIVE, ACTIVE;
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -070055 }
56
57 private final Long dpid;
58 private final Long number;
59
60 private STATUS status;
61
Yuta HIGUCHIcc561882014-05-22 10:31:32 -070062 /**
63 * Generate a PortID from port pair (dpid, number).
64 *
65 * @param dpid DPID of a switch it reside on.
66 * @param number port number of this
67 * @return PortID
68 */
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -070069 public static byte[] getPortID(final Long dpid, final Long number) {
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -070070 return PortEvent.getPortID(dpid, number).array();
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -070071 }
72
Yuta HIGUCHIcc561882014-05-22 10:31:32 -070073 /**
74 * Gets the port pair from PortID.
75 *
76 * @param key PortID
77 * @return port pair (dpid, number)
78 */
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -070079 public static long[] getPortPairFromKey(final byte[] key) {
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -070080 return getPortPairFromKey(ByteBuffer.wrap(key));
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -070081 }
82
Yuta HIGUCHIcc561882014-05-22 10:31:32 -070083 /**
84 * Gets the port pair from PortID.
85 *
86 * @param keyBuf PortID
87 * @return port pair (dpid, number)
88 */
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -070089 public static long[] getPortPairFromKey(final ByteBuffer keyBuf) {
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -070090 if (keyBuf.getChar() != 'S') {
91 throw new IllegalArgumentException("Invalid Port key:" + keyBuf
92 + " "
Yuta HIGUCHI805bc8f2014-04-16 11:51:43 -070093 + ByteArrayUtil.toHexStringBuilder(keyBuf.array(), ":"));
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -070094 }
Yuta HIGUCHIa14eb172014-03-24 15:03:23 -070095 long[] pair = new long[2];
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -070096 pair[0] = keyBuf.getLong();
97 if (keyBuf.getChar() != 'P') {
98 throw new IllegalArgumentException("Invalid Port key:" + keyBuf
99 + " "
Yuta HIGUCHI805bc8f2014-04-16 11:51:43 -0700100 + ByteArrayUtil.toHexStringBuilder(keyBuf.array(), ":"));
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700101 }
102 pair[1] = keyBuf.getLong();
103 return pair;
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700104
105 }
106
Yuta HIGUCHIcc561882014-05-22 10:31:32 -0700107 /**
108 * Gets the port number from PortID.
109 *
110 * @param key PortID
111 * @return port number
112 */
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700113 public static long getDpidFromKey(final byte[] key) {
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700114 return getPortPairFromKey(key)[0];
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700115 }
116
Yuta HIGUCHIcc561882014-05-22 10:31:32 -0700117 /**
118 * Gets the dpid of an switch from PortID.
119 *
120 * @param key PortID
121 * @return dpid
122 */
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700123 public static long getNumberFromKey(final byte[] key) {
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700124 return getPortPairFromKey(key)[1];
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700125 }
126
Yuta HIGUCHIcc561882014-05-22 10:31:32 -0700127 /**
128 * KVPort constructor for default namespace.
129 *
130 * @param dpid DPID of the switch this port is on
131 * @param number port number of this port
132 */
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700133 public KVPort(final Long dpid, final Long number) {
Yuta HIGUCHIcc561882014-05-22 10:31:32 -0700134 this(dpid, number, DEFAULT_NAMESPACE);
135 }
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700136
Yuta HIGUCHIcc561882014-05-22 10:31:32 -0700137 /**
138 * KVPort constructor for specified namespace.
139 *
140 * @param dpid DPID of the switch this port is on
141 * @param number port number of this port
142 * @param namespace namespace to create this object
143 */
144 public KVPort(final Long dpid, final Long number, final String namespace) {
145 super(DataStoreClient.getClient()
146 .getTable(namespace + PORT_TABLE_SUFFIX),
147 getPortID(dpid, number), namespace);
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700148
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700149 this.dpid = dpid;
150 this.number = number;
151 this.status = STATUS.INACTIVE;
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700152 }
153
154 /**
Yuta HIGUCHIcc561882014-05-22 10:31:32 -0700155 * Gets an instance from PortID in default namespace.
Jonathan Hart99ff20a2014-06-15 16:53:00 -0700156 * <p/>
157 * Note: You need to call `read()` to get the DB content.
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700158 *
Yuta HIGUCHIcc561882014-05-22 10:31:32 -0700159 * @param key PortID
160 * @return {@link KVPort} instance
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700161 */
162 public static KVPort createFromKey(final byte[] key) {
Yuta HIGUCHIcc561882014-05-22 10:31:32 -0700163 return createFromKey(key, DEFAULT_NAMESPACE);
164 }
165
166 /**
167 * Gets an instance from PortID in specified namespace.
Jonathan Hart99ff20a2014-06-15 16:53:00 -0700168 * <p/>
169 * Note: You need to call `read()` to get the DB content.
Yuta HIGUCHIcc561882014-05-22 10:31:32 -0700170 *
171 * @param key PortID
172 * @param namespace namespace to create this object.
173 * @return {@link KVPort} instance
Yuta HIGUCHIcc561882014-05-22 10:31:32 -0700174 */
175 public static KVPort createFromKey(final byte[] key, final String namespace) {
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700176 long[] pair = getPortPairFromKey(key);
Yuta HIGUCHIcc561882014-05-22 10:31:32 -0700177 return new KVPort(pair[0], pair[1], namespace);
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700178 }
179
Yuta HIGUCHIcc561882014-05-22 10:31:32 -0700180 /**
181 * Gets all the Ports in default namespace.
182 *
183 * @return Ports
184 */
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700185 public static Iterable<KVPort> getAllPorts() {
Yuta HIGUCHIcc561882014-05-22 10:31:32 -0700186 return getAllPorts(DEFAULT_NAMESPACE);
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700187 }
188
Yuta HIGUCHIcc561882014-05-22 10:31:32 -0700189 /**
190 * Gets all the Ports in specified namespace.
191 *
192 * @param namespace namespace to iterate over
193 * @return Ports
194 */
195 public static Iterable<KVPort> getAllPorts(final String namespace) {
196 return new PortEnumerator(namespace);
197 }
198
199 /**
200 * Utility class to provide Iterable interface.
201 */
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700202 public static class PortEnumerator implements Iterable<KVPort> {
203
Yuta HIGUCHIcc561882014-05-22 10:31:32 -0700204 private final String namespace;
205
206 /**
207 * Constructor to iterate Ports in specified namespace.
208 *
209 * @param namespace namespace to iterate through
210 */
211 public PortEnumerator(final String namespace) {
212 this.namespace = namespace;
213 }
214
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700215 @Override
216 public Iterator<KVPort> iterator() {
Yuta HIGUCHIcc561882014-05-22 10:31:32 -0700217 return new PortIterator(namespace);
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700218 }
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700219 }
220
Yuta HIGUCHIcc561882014-05-22 10:31:32 -0700221 /**
222 * Utility class to provide Iterator over all the Port objects.
223 */
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700224 public static class PortIterator extends AbstractObjectIterator<KVPort> {
225
Yuta HIGUCHIcc561882014-05-22 10:31:32 -0700226 /**
227 * Constructor to create an iterator to iterate all the Ports
228 * in specified namespace.
229 *
230 * @param namespace namespace to iterate through
231 */
232 public PortIterator(final String namespace) {
233 super(DataStoreClient.getClient()
234 .getTable(namespace + PORT_TABLE_SUFFIX), namespace);
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700235 }
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700236
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700237 @Override
238 public KVPort next() {
239 IKVEntry o = enumerator.next();
Yuta HIGUCHIcc561882014-05-22 10:31:32 -0700240 KVPort e = KVPort.createFromKey(o.getKey(), namespace);
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700241 e.deserialize(o.getValue(), o.getVersion());
242 return e;
243 }
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700244 }
245
Yuta HIGUCHIcc561882014-05-22 10:31:32 -0700246 /**
247 * Gets the status.
248 *
249 * @return status
250 */
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700251 public STATUS getStatus() {
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700252 return status;
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700253 }
254
Yuta HIGUCHIcc561882014-05-22 10:31:32 -0700255 /**
256 * Sets the status.
257 *
258 * @param status new status
259 */
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700260 public void setStatus(final STATUS status) {
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700261 this.status = status;
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700262 }
263
Yuta HIGUCHIcc561882014-05-22 10:31:32 -0700264 /**
265 * Gets the DPID of the switch this port is on.
266 *
267 * @return DPID of the switch this port is on
268 */
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700269 public Long getDpid() {
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700270 return dpid;
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700271 }
272
Yuta HIGUCHIcc561882014-05-22 10:31:32 -0700273 /**
274 * Gets the port number of this port.
275 *
276 * @return port number of this port
277 */
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700278 public Long getNumber() {
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700279 return number;
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700280 }
281
Yuta HIGUCHIcc561882014-05-22 10:31:32 -0700282 /**
283 * Gets the PortID.
284 *
285 * @return PortID
286 */
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700287 public byte[] getId() {
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700288 return getKey();
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700289 }
290
291 @Override
292 public byte[] serialize() {
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700293 Map<Object, Object> map = getPropertyMap();
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700294
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700295 PortProperty.Builder port = PortProperty.newBuilder();
296 port.setDpid(dpid);
297 port.setNumber(number);
298 port.setStatus(status.ordinal());
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700299
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700300 if (!map.isEmpty()) {
Ray Milkey5c9f2db2014-04-09 10:31:21 -0700301 byte[] propMaps = serializePropertyMap(PORT_KRYO.get(), map);
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700302 port.setValue(ByteString.copyFrom(propMaps));
303 }
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700304
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700305 return port.build().toByteArray();
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700306 }
307
308 @Override
309 protected boolean deserialize(final byte[] bytes) {
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700310 try {
311 boolean success = true;
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700312
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700313 PortProperty port = PortProperty.parseFrom(bytes);
314 byte[] props = port.getValue().toByteArray();
Ray Milkey5c9f2db2014-04-09 10:31:21 -0700315 success &= deserializePropertyMap(PORT_KRYO.get(), props);
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700316 this.status = STATUS.values()[port.getStatus()];
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700317
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700318 return success;
319 } catch (InvalidProtocolBufferException e) {
320 log.error("Deserializing Port: " + this + " failed.", e);
321 return false;
322 }
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700323 }
324
325 @Override
326 public String toString() {
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700327 // TODO output all properties?
328 return "[" + this.getClass().getSimpleName()
329 + " 0x" + Long.toHexString(dpid) + "@" + number
330 + " STATUS:" + status + "]";
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700331 }
332}