blob: d1665661c6166defd62876203c8cafcf2736933d [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.
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700156 *
Yuta HIGUCHIcc561882014-05-22 10:31:32 -0700157 * @param key PortID
158 * @return {@link KVPort} instance
Ray Milkey269ffb92014-04-03 14:43:30 -0700159 * @note You need to call `read()` to get the DB content.
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700160 */
161 public static KVPort createFromKey(final byte[] key) {
Yuta HIGUCHIcc561882014-05-22 10:31:32 -0700162 return createFromKey(key, DEFAULT_NAMESPACE);
163 }
164
165 /**
166 * Gets an instance from PortID in specified namespace.
167 *
168 * @param key PortID
169 * @param namespace namespace to create this object.
170 * @return {@link KVPort} instance
171 * @note You need to call `read()` to get the DB content.
172 */
173 public static KVPort createFromKey(final byte[] key, final String namespace) {
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700174 long[] pair = getPortPairFromKey(key);
Yuta HIGUCHIcc561882014-05-22 10:31:32 -0700175 return new KVPort(pair[0], pair[1], namespace);
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700176 }
177
Yuta HIGUCHIcc561882014-05-22 10:31:32 -0700178 /**
179 * Gets all the Ports in default namespace.
180 *
181 * @return Ports
182 */
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700183 public static Iterable<KVPort> getAllPorts() {
Yuta HIGUCHIcc561882014-05-22 10:31:32 -0700184 return getAllPorts(DEFAULT_NAMESPACE);
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700185 }
186
Yuta HIGUCHIcc561882014-05-22 10:31:32 -0700187 /**
188 * Gets all the Ports in specified namespace.
189 *
190 * @param namespace namespace to iterate over
191 * @return Ports
192 */
193 public static Iterable<KVPort> getAllPorts(final String namespace) {
194 return new PortEnumerator(namespace);
195 }
196
197 /**
198 * Utility class to provide Iterable interface.
199 */
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700200 public static class PortEnumerator implements Iterable<KVPort> {
201
Yuta HIGUCHIcc561882014-05-22 10:31:32 -0700202 private final String namespace;
203
204 /**
205 * Constructor to iterate Ports in specified namespace.
206 *
207 * @param namespace namespace to iterate through
208 */
209 public PortEnumerator(final String namespace) {
210 this.namespace = namespace;
211 }
212
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700213 @Override
214 public Iterator<KVPort> iterator() {
Yuta HIGUCHIcc561882014-05-22 10:31:32 -0700215 return new PortIterator(namespace);
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700216 }
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700217 }
218
Yuta HIGUCHIcc561882014-05-22 10:31:32 -0700219 /**
220 * Utility class to provide Iterator over all the Port objects.
221 */
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700222 public static class PortIterator extends AbstractObjectIterator<KVPort> {
223
Yuta HIGUCHIcc561882014-05-22 10:31:32 -0700224 /**
225 * Constructor to create an iterator to iterate all the Ports
226 * in specified namespace.
227 *
228 * @param namespace namespace to iterate through
229 */
230 public PortIterator(final String namespace) {
231 super(DataStoreClient.getClient()
232 .getTable(namespace + PORT_TABLE_SUFFIX), namespace);
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700233 }
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700234
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700235 @Override
236 public KVPort next() {
237 IKVEntry o = enumerator.next();
Yuta HIGUCHIcc561882014-05-22 10:31:32 -0700238 KVPort e = KVPort.createFromKey(o.getKey(), namespace);
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700239 e.deserialize(o.getValue(), o.getVersion());
240 return e;
241 }
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700242 }
243
Yuta HIGUCHIcc561882014-05-22 10:31:32 -0700244 /**
245 * Gets the status.
246 *
247 * @return status
248 */
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700249 public STATUS getStatus() {
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700250 return status;
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700251 }
252
Yuta HIGUCHIcc561882014-05-22 10:31:32 -0700253 /**
254 * Sets the status.
255 *
256 * @param status new status
257 */
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700258 public void setStatus(final STATUS status) {
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700259 this.status = status;
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700260 }
261
Yuta HIGUCHIcc561882014-05-22 10:31:32 -0700262 /**
263 * Gets the DPID of the switch this port is on.
264 *
265 * @return DPID of the switch this port is on
266 */
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700267 public Long getDpid() {
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700268 return dpid;
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700269 }
270
Yuta HIGUCHIcc561882014-05-22 10:31:32 -0700271 /**
272 * Gets the port number of this port.
273 *
274 * @return port number of this port
275 */
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700276 public Long getNumber() {
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700277 return number;
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700278 }
279
Yuta HIGUCHIcc561882014-05-22 10:31:32 -0700280 /**
281 * Gets the PortID.
282 *
283 * @return PortID
284 */
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700285 public byte[] getId() {
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700286 return getKey();
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700287 }
288
289 @Override
290 public byte[] serialize() {
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700291 Map<Object, Object> map = getPropertyMap();
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700292
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700293 PortProperty.Builder port = PortProperty.newBuilder();
294 port.setDpid(dpid);
295 port.setNumber(number);
296 port.setStatus(status.ordinal());
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700297
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700298 if (!map.isEmpty()) {
Ray Milkey5c9f2db2014-04-09 10:31:21 -0700299 byte[] propMaps = serializePropertyMap(PORT_KRYO.get(), map);
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700300 port.setValue(ByteString.copyFrom(propMaps));
301 }
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700302
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700303 return port.build().toByteArray();
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700304 }
305
306 @Override
307 protected boolean deserialize(final byte[] bytes) {
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700308 try {
309 boolean success = true;
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700310
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700311 PortProperty port = PortProperty.parseFrom(bytes);
312 byte[] props = port.getValue().toByteArray();
Ray Milkey5c9f2db2014-04-09 10:31:21 -0700313 success &= deserializePropertyMap(PORT_KRYO.get(), props);
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700314 this.status = STATUS.values()[port.getStatus()];
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700315
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700316 return success;
317 } catch (InvalidProtocolBufferException e) {
318 log.error("Deserializing Port: " + this + " failed.", e);
319 return false;
320 }
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700321 }
322
323 @Override
324 public String toString() {
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700325 // TODO output all properties?
326 return "[" + this.getClass().getSimpleName()
327 + " 0x" + Long.toHexString(dpid) + "@" + number
328 + " STATUS:" + status + "]";
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700329 }
330}