blob: 73b59866b807452a0e4f39e3a93940b498ee42ab [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.LinkProperty;
Jonathan Hart6df90172014-04-03 10:13:11 -070011import net.onrc.onos.core.datastore.utils.KVObject;
Jonathan Hart472062d2014-04-03 10:56:48 -070012import net.onrc.onos.core.topology.LinkEvent;
13import 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 * Link object in data store.
26 */
27public class KVLink extends KVObject {
28 private static final Logger log = LoggerFactory.getLogger(KVLink.class);
29
Ray Milkey5c9f2db2014-04-09 10:31:21 -070030 private static final ThreadLocal<Kryo> LINK_KRYO = new ThreadLocal<Kryo>() {
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -070031 @Override
32 protected Kryo initialValue() {
33 Kryo kryo = new Kryo();
34 kryo.setRegistrationRequired(true);
35 kryo.setReferences(false);
36 kryo.register(byte[].class);
37 kryo.register(byte[][].class);
38 kryo.register(HashMap.class);
39 // TODO check if we should explicitly specify EnumSerializer
40 kryo.register(STATUS.class);
41 return kryo;
42 }
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -070043 };
44
Yuta HIGUCHI8f3dfa32014-06-25 00:14:25 -070045 // TODO eliminate this class and util SwitchPort.
Yuta HIGUCHIcc561882014-05-22 10:31:32 -070046 /**
47 * Internal data structure to represent a port on a switch.
48 */
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -070049 public static class SwitchPort {
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -070050 public final Long dpid;
51 public final Long number;
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -070052
Yuta HIGUCHIcc561882014-05-22 10:31:32 -070053 /**
54 * Constructor.
55 *
56 * @param dpid datapath ID of this switch port
57 * @param number port number of this port on switch({@code dpid})
58 */
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -070059 public SwitchPort(final Long dpid, final Long number) {
60 this.dpid = dpid;
61 this.number = number;
62 }
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -070063
Yuta HIGUCHIcc561882014-05-22 10:31:32 -070064 /**
Yuta HIGUCHI8f3dfa32014-06-25 00:14:25 -070065 * Constructor.
66 *
Praseed Balakrishnanccb35832014-07-09 11:04:29 -070067 * @param srcDpid datapath ID of this switch port
68 * @param srcPortNo port number of this port on switch({@code dpid})
Yuta HIGUCHI8f3dfa32014-06-25 00:14:25 -070069 */
70 public SwitchPort(final Dpid srcDpid, final PortNumber srcPortNo) {
71 this.dpid = srcDpid.value();
72 this.number = (long) srcPortNo.value();
73 }
74
75 /**
Yuta HIGUCHIcc561882014-05-22 10:31:32 -070076 * Gets the PortID of a port this object represent.
77 *
78 * @return PortID
79 */
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -070080 public byte[] getPortID() {
81 return KVPort.getPortID(dpid, number);
82 }
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -070083
Yuta HIGUCHIcc561882014-05-22 10:31:32 -070084 /**
85 * Gets the SwitchID of a switch this object represent.
86 *
87 * @return SwitchID
88 */
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -070089 public byte[] getSwitchID() {
90 return KVSwitch.getSwitchID(dpid);
91 }
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -070092
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -070093 @Override
94 public String toString() {
95 return "(" + Long.toHexString(dpid) + "@" + number + ")";
96 }
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -070097
98 }
99
Yuta HIGUCHIcc561882014-05-22 10:31:32 -0700100 static final String LINK_TABLE_SUFFIX = ":Link";
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700101
102 // must not re-order enum members, ordinal will be sent over wire
Yuta HIGUCHIcc561882014-05-22 10:31:32 -0700103 /**
104 * Status.
105 */
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700106 public enum STATUS {
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700107 INACTIVE, ACTIVE;
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700108 }
109
110 private final SwitchPort src;
111 private final SwitchPort dst;
112 private STATUS status;
113
Yuta HIGUCHIcc561882014-05-22 10:31:32 -0700114 /**
115 * Generate a LinkID from Link 4-tuples.
116 *
117 * @param srcDpid source DPID
118 * @param srcPortNo source port number
119 * @param dstDpid destination DPID
120 * @param dstPortNo destination port number
121 * @return LinkID
122 */
Yuta HIGUCHI8f3dfa32014-06-25 00:14:25 -0700123 public static byte[] getLinkID(final Dpid srcDpid, final PortNumber srcPortNo,
124 final Dpid dstDpid, final PortNumber dstPortNo) {
125 return LinkEvent.getLinkID(srcDpid, srcPortNo,
126 dstDpid, dstPortNo).array();
127 }
128
129 /**
130 * Generate a LinkID from Link 4-tuples.
131 *
132 * @param srcDpid source DPID
133 * @param srcPortNo source port number
134 * @param dstDpid destination DPID
135 * @param dstPortNo destination port number
136 * @return LinkID
137 */
Ray Milkey9526d6f2014-04-10 14:54:15 -0700138 public static byte[] getLinkID(final Long srcDpid, final Long srcPortNo,
139 final Long dstDpid, final Long dstPortNo) {
140 return LinkEvent.getLinkID(srcDpid, srcPortNo, dstDpid,
141 dstPortNo).array();
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700142 }
143
Yuta HIGUCHIcc561882014-05-22 10:31:32 -0700144 /**
145 * Gets Link 4-tuples from LinkID.
146 *
147 * @param key LinkID
148 * @return Link 4-tuple: [src DPID, src PortNo, dst DPID, dst PortNo]
149 */
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700150 public static long[] getLinkTupleFromKey(final byte[] key) {
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700151 return getLinkTupleFromKey(ByteBuffer.wrap(key));
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700152 }
153
Yuta HIGUCHIcc561882014-05-22 10:31:32 -0700154 /**
155 * Gets Link 4-tuples from LinkID.
156 *
157 * @param keyBuf LinkID
158 * @return Link 4-tuple: [src DPID, src PortNo, dst DPID, dst PortNo]
159 */
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700160 public static long[] getLinkTupleFromKey(final ByteBuffer keyBuf) {
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700161 if (keyBuf.getChar() != 'L') {
162 throw new IllegalArgumentException("Invalid Link key");
163 }
Yuta HIGUCHIa14eb172014-03-24 15:03:23 -0700164 final long[] srcPortPair = KVPort.getPortPairFromKey(keyBuf.slice());
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700165 keyBuf.position(2 + PortEvent.PORTID_BYTES);
Yuta HIGUCHIa14eb172014-03-24 15:03:23 -0700166 final long[] dstPortPair = KVPort.getPortPairFromKey(keyBuf.slice());
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700167
Yuta HIGUCHIa14eb172014-03-24 15:03:23 -0700168 long[] tuple = new long[4];
169 tuple[0] = srcPortPair[0];
170 tuple[1] = srcPortPair[1];
171 tuple[2] = dstPortPair[0];
172 tuple[3] = dstPortPair[1];
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700173
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700174 return tuple;
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700175 }
176
Yuta HIGUCHIcc561882014-05-22 10:31:32 -0700177
178 /**
179 * KVLink constructor for default namespace.
180 *
181 * @param srcDpid source DPID
182 * @param srcPortNo source port number
183 * @param dstDpid destination DPID
184 * @param dstPortNo destination port number
185 */
Ray Milkey9526d6f2014-04-10 14:54:15 -0700186 public KVLink(final Long srcDpid, final Long srcPortNo,
187 final Long dstDpid, final Long dstPortNo) {
Yuta HIGUCHIcc561882014-05-22 10:31:32 -0700188 this(srcDpid, srcPortNo, dstDpid, dstPortNo, DEFAULT_NAMESPACE);
189 }
190
191 /**
192 * KVLink constructor for specified namespace.
193 *
194 * @param srcDpid source DPID
195 * @param srcPortNo source port number
196 * @param dstDpid destination DPID
197 * @param dstPortNo destination port number
198 * @param namespace namespace to create this object
199 */
200 public KVLink(final Long srcDpid, final Long srcPortNo,
201 final Long dstDpid, final Long dstPortNo,
202 final String namespace) {
203 super(DataStoreClient.getClient()
204 .getTable(namespace + LINK_TABLE_SUFFIX),
205 getLinkID(srcDpid, srcPortNo, dstDpid, dstPortNo),
206 namespace);
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700207
Ray Milkey9526d6f2014-04-10 14:54:15 -0700208 src = new SwitchPort(srcDpid, srcPortNo);
209 dst = new SwitchPort(dstDpid, dstPortNo);
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700210 status = STATUS.INACTIVE;
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700211 }
212
213 /**
Yuta HIGUCHI8f3dfa32014-06-25 00:14:25 -0700214 * KVLink constructor for default namespace.
215 *
216 * @param srcDpid source DPID
217 * @param srcPortNo source port number
218 * @param dstDpid destination DPID
219 * @param dstPortNo destination port number
220 */
221 public KVLink(final Dpid srcDpid, final PortNumber srcPortNo,
222 final Dpid dstDpid, final PortNumber dstPortNo) {
223 this(srcDpid, srcPortNo, dstDpid, dstPortNo, DEFAULT_NAMESPACE);
224 }
225
226 /**
227 * KVLink constructor for specified namespace.
228 *
229 * @param srcDpid source DPID
230 * @param srcPortNo source port number
231 * @param dstDpid destination DPID
232 * @param dstPortNo destination port number
233 * @param namespace namespace to create this object
234 */
235 public KVLink(final Dpid srcDpid, final PortNumber srcPortNo,
236 final Dpid dstDpid, final PortNumber dstPortNo,
237 final String namespace) {
238 super(DataStoreClient.getClient()
239 .getTable(namespace + LINK_TABLE_SUFFIX),
240 getLinkID(srcDpid, srcPortNo, dstDpid, dstPortNo),
241 namespace);
242
243 src = new SwitchPort(srcDpid, srcPortNo);
244 dst = new SwitchPort(dstDpid, dstPortNo);
245 status = STATUS.INACTIVE;
246 }
247
248 /**
Yuta HIGUCHIcc561882014-05-22 10:31:32 -0700249 * Gets an instance from LinkID in default namespace.
Jonathan Hart99ff20a2014-06-15 16:53:00 -0700250 * <p/>
251 * Note: You need to call `read()` to get the DB content.
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700252 *
Yuta HIGUCHIcc561882014-05-22 10:31:32 -0700253 * @param key LinkID
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700254 * @return KVLink instance
255 */
256 public static KVLink createFromKey(final byte[] key) {
Yuta HIGUCHIcc561882014-05-22 10:31:32 -0700257 return createFromKey(key, DEFAULT_NAMESPACE);
258 }
259
260 /**
261 * Gets an instance from LinkID in specified namespace.
Jonathan Hart99ff20a2014-06-15 16:53:00 -0700262 * <p/>
263 * Note: You need to call `read()` to get the DB content.
Yuta HIGUCHIcc561882014-05-22 10:31:32 -0700264 *
265 * @param key LinkID
266 * @param namespace namespace to create this object in
267 * @return KVLink instance
Yuta HIGUCHIcc561882014-05-22 10:31:32 -0700268 */
269 public static KVLink createFromKey(final byte[] key, final String namespace) {
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700270 long[] linkTuple = getLinkTupleFromKey(key);
Yuta HIGUCHIcc561882014-05-22 10:31:32 -0700271 return new KVLink(linkTuple[0], linkTuple[1],
272 linkTuple[2], linkTuple[3],
273 namespace);
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700274 }
275
Yuta HIGUCHIcc561882014-05-22 10:31:32 -0700276 /**
277 * Gets all the Links in default namespace.
278 *
279 * @return Links
280 */
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700281 public static Iterable<KVLink> getAllLinks() {
Yuta HIGUCHIcc561882014-05-22 10:31:32 -0700282 return getAllLinks(DEFAULT_NAMESPACE);
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700283 }
284
Yuta HIGUCHIcc561882014-05-22 10:31:32 -0700285 /**
286 * Gets all the Links in specified namespace.
287 *
288 * @param namespace namespace to iterate over
289 * @return Links
290 */
291 public static Iterable<KVLink> getAllLinks(final String namespace) {
292 return new LinkEnumerator(namespace);
293 }
294
295 /**
296 * Utility class to provide Iterable interface.
297 */
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700298 public static class LinkEnumerator implements Iterable<KVLink> {
299
Yuta HIGUCHIcc561882014-05-22 10:31:32 -0700300 private final String namespace;
301
302 /**
303 * Constructor to iterate Links in specified namespace.
304 *
305 * @param namespace namespace to iterate through
306 */
307 public LinkEnumerator(final String namespace) {
308 this.namespace = namespace;
309 }
310
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700311 @Override
312 public Iterator<KVLink> iterator() {
Yuta HIGUCHIcc561882014-05-22 10:31:32 -0700313 return new LinkIterator(namespace);
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700314 }
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700315 }
316
Yuta HIGUCHIcc561882014-05-22 10:31:32 -0700317 /**
318 * Utility class to provide Iterator over all the Link objects.
319 */
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700320 public static class LinkIterator extends AbstractObjectIterator<KVLink> {
321
Yuta HIGUCHIcc561882014-05-22 10:31:32 -0700322 /**
323 * Constructor to create an iterator to iterate all the Links
324 * in specified namespace.
325 *
326 * @param namespace namespace to iterate through
327 */
328 public LinkIterator(final String namespace) {
329 super(DataStoreClient.getClient()
330 .getTable(namespace + LINK_TABLE_SUFFIX),
331 namespace);
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700332 }
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700333
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700334 @Override
335 public KVLink next() {
336 IKVEntry o = enumerator.next();
Yuta HIGUCHIcc561882014-05-22 10:31:32 -0700337 KVLink e = KVLink.createFromKey(o.getKey(), namespace);
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700338 e.deserialize(o.getValue(), o.getVersion());
339 return e;
340 }
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700341 }
342
Yuta HIGUCHIcc561882014-05-22 10:31:32 -0700343 /**
344 * Gets the status.
345 *
346 * @return status
347 */
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700348 public STATUS getStatus() {
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700349 return status;
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700350 }
351
Yuta HIGUCHIcc561882014-05-22 10:31:32 -0700352 /**
353 * Sets the status.
354 *
355 * @param status new status
356 */
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700357 public void setStatus(final STATUS status) {
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700358 this.status = status;
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700359 }
360
Yuta HIGUCHIcc561882014-05-22 10:31:32 -0700361 /**
362 * Gets the source SwitchPort object.
363 *
364 * @return source SwitchPort object
365 */
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700366 public SwitchPort getSrc() {
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700367 return src;
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700368 }
369
Yuta HIGUCHIcc561882014-05-22 10:31:32 -0700370 /**
371 * Gets the destination SwitchPort object.
372 *
373 * @return destination SwitchPort object
374 */
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700375 public SwitchPort getDst() {
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700376 return dst;
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700377 }
378
Yuta HIGUCHIcc561882014-05-22 10:31:32 -0700379 /**
380 * Gets the LinkID of this object.
381 *
382 * @return LinkID
383 */
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700384 public byte[] getId() {
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700385 return getKey();
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700386 }
387
388 @Override
389 public byte[] serialize() {
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700390 Map<Object, Object> map = getPropertyMap();
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700391
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700392 LinkProperty.Builder link = LinkProperty.newBuilder();
393 link.setSrcSwId(ByteString.copyFrom(src.getSwitchID()));
394 link.setSrcPortId(ByteString.copyFrom(src.getPortID()));
395 link.setDstSwId(ByteString.copyFrom(dst.getSwitchID()));
396 link.setDstPortId(ByteString.copyFrom(dst.getPortID()));
397 link.setStatus(status.ordinal());
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700398
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700399 if (!map.isEmpty()) {
Ray Milkey5c9f2db2014-04-09 10:31:21 -0700400 byte[] propMaps = serializePropertyMap(LINK_KRYO.get(), map);
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700401 link.setValue(ByteString.copyFrom(propMaps));
402 }
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700403
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700404 return link.build().toByteArray();
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700405 }
406
407 @Override
408 protected boolean deserialize(final byte[] bytes) {
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700409 try {
410 boolean success = true;
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700411
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700412 LinkProperty link = LinkProperty.parseFrom(bytes);
413 byte[] props = link.getValue().toByteArray();
Ray Milkey5c9f2db2014-04-09 10:31:21 -0700414 success &= deserializePropertyMap(LINK_KRYO.get(), props);
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700415 this.status = STATUS.values()[link.getStatus()];
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700416
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700417 return success;
418 } catch (InvalidProtocolBufferException e) {
419 log.error("Deserializing Link: " + this + " failed.", e);
420 return false;
421 }
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700422 }
423
424 @Override
425 public String toString() {
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700426 // TODO output all properties?
427 return "[" + this.getClass().getSimpleName()
428 + " " + src + "->" + dst + " STATUS:" + status + "]";
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700429 }
430}