blob: 4ad9b742a459685b59a9856326662de84f5ffdb7 [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 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 * Link object in data store.
24 */
25public class KVLink extends KVObject {
26 private static final Logger log = LoggerFactory.getLogger(KVLink.class);
27
Ray Milkey5c9f2db2014-04-09 10:31:21 -070028 private static final ThreadLocal<Kryo> LINK_KRYO = new ThreadLocal<Kryo>() {
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -070029 @Override
30 protected Kryo initialValue() {
31 Kryo kryo = new Kryo();
32 kryo.setRegistrationRequired(true);
33 kryo.setReferences(false);
34 kryo.register(byte[].class);
35 kryo.register(byte[][].class);
36 kryo.register(HashMap.class);
37 // TODO check if we should explicitly specify EnumSerializer
38 kryo.register(STATUS.class);
39 return kryo;
40 }
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -070041 };
42
Yuta HIGUCHIcc561882014-05-22 10:31:32 -070043 /**
44 * Internal data structure to represent a port on a switch.
45 */
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -070046 public static class SwitchPort {
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -070047 public final Long dpid;
48 public final Long number;
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -070049
Yuta HIGUCHIcc561882014-05-22 10:31:32 -070050 /**
51 * Constructor.
52 *
53 * @param dpid datapath ID of this switch port
54 * @param number port number of this port on switch({@code dpid})
55 */
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -070056 public SwitchPort(final Long dpid, final Long number) {
57 this.dpid = dpid;
58 this.number = number;
59 }
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -070060
Yuta HIGUCHIcc561882014-05-22 10:31:32 -070061 /**
62 * Gets the PortID of a port this object represent.
63 *
64 * @return PortID
65 */
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -070066 public byte[] getPortID() {
67 return KVPort.getPortID(dpid, number);
68 }
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -070069
Yuta HIGUCHIcc561882014-05-22 10:31:32 -070070 /**
71 * Gets the SwitchID of a switch this object represent.
72 *
73 * @return SwitchID
74 */
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -070075 public byte[] getSwitchID() {
76 return KVSwitch.getSwitchID(dpid);
77 }
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -070078
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -070079 @Override
80 public String toString() {
81 return "(" + Long.toHexString(dpid) + "@" + number + ")";
82 }
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -070083
84 }
85
Yuta HIGUCHIcc561882014-05-22 10:31:32 -070086 static final String LINK_TABLE_SUFFIX = ":Link";
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -070087
88 // must not re-order enum members, ordinal will be sent over wire
Yuta HIGUCHIcc561882014-05-22 10:31:32 -070089 /**
90 * Status.
91 */
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -070092 public enum STATUS {
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -070093 INACTIVE, ACTIVE;
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -070094 }
95
96 private final SwitchPort src;
97 private final SwitchPort dst;
98 private STATUS status;
99
Yuta HIGUCHIcc561882014-05-22 10:31:32 -0700100 /**
101 * Generate a LinkID from Link 4-tuples.
102 *
103 * @param srcDpid source DPID
104 * @param srcPortNo source port number
105 * @param dstDpid destination DPID
106 * @param dstPortNo destination port number
107 * @return LinkID
108 */
Ray Milkey9526d6f2014-04-10 14:54:15 -0700109 public static byte[] getLinkID(final Long srcDpid, final Long srcPortNo,
110 final Long dstDpid, final Long dstPortNo) {
111 return LinkEvent.getLinkID(srcDpid, srcPortNo, dstDpid,
112 dstPortNo).array();
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700113 }
114
Yuta HIGUCHIcc561882014-05-22 10:31:32 -0700115 /**
116 * Gets Link 4-tuples from LinkID.
117 *
118 * @param key LinkID
119 * @return Link 4-tuple: [src DPID, src PortNo, dst DPID, dst PortNo]
120 */
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700121 public static long[] getLinkTupleFromKey(final byte[] key) {
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700122 return getLinkTupleFromKey(ByteBuffer.wrap(key));
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700123 }
124
Yuta HIGUCHIcc561882014-05-22 10:31:32 -0700125 /**
126 * Gets Link 4-tuples from LinkID.
127 *
128 * @param keyBuf LinkID
129 * @return Link 4-tuple: [src DPID, src PortNo, dst DPID, dst PortNo]
130 */
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700131 public static long[] getLinkTupleFromKey(final ByteBuffer keyBuf) {
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700132 if (keyBuf.getChar() != 'L') {
133 throw new IllegalArgumentException("Invalid Link key");
134 }
Yuta HIGUCHIa14eb172014-03-24 15:03:23 -0700135 final long[] srcPortPair = KVPort.getPortPairFromKey(keyBuf.slice());
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700136 keyBuf.position(2 + PortEvent.PORTID_BYTES);
Yuta HIGUCHIa14eb172014-03-24 15:03:23 -0700137 final long[] dstPortPair = KVPort.getPortPairFromKey(keyBuf.slice());
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700138
Yuta HIGUCHIa14eb172014-03-24 15:03:23 -0700139 long[] tuple = new long[4];
140 tuple[0] = srcPortPair[0];
141 tuple[1] = srcPortPair[1];
142 tuple[2] = dstPortPair[0];
143 tuple[3] = dstPortPair[1];
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700144
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700145 return tuple;
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700146 }
147
Yuta HIGUCHIcc561882014-05-22 10:31:32 -0700148
149 /**
150 * KVLink constructor for default namespace.
151 *
152 * @param srcDpid source DPID
153 * @param srcPortNo source port number
154 * @param dstDpid destination DPID
155 * @param dstPortNo destination port number
156 */
Ray Milkey9526d6f2014-04-10 14:54:15 -0700157 public KVLink(final Long srcDpid, final Long srcPortNo,
158 final Long dstDpid, final Long dstPortNo) {
Yuta HIGUCHIcc561882014-05-22 10:31:32 -0700159 this(srcDpid, srcPortNo, dstDpid, dstPortNo, DEFAULT_NAMESPACE);
160 }
161
162 /**
163 * KVLink constructor for specified namespace.
164 *
165 * @param srcDpid source DPID
166 * @param srcPortNo source port number
167 * @param dstDpid destination DPID
168 * @param dstPortNo destination port number
169 * @param namespace namespace to create this object
170 */
171 public KVLink(final Long srcDpid, final Long srcPortNo,
172 final Long dstDpid, final Long dstPortNo,
173 final String namespace) {
174 super(DataStoreClient.getClient()
175 .getTable(namespace + LINK_TABLE_SUFFIX),
176 getLinkID(srcDpid, srcPortNo, dstDpid, dstPortNo),
177 namespace);
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700178
Ray Milkey9526d6f2014-04-10 14:54:15 -0700179 src = new SwitchPort(srcDpid, srcPortNo);
180 dst = new SwitchPort(dstDpid, dstPortNo);
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700181 status = STATUS.INACTIVE;
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700182 }
183
184 /**
Yuta HIGUCHIcc561882014-05-22 10:31:32 -0700185 * Gets an instance from LinkID in default namespace.
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700186 *
Yuta HIGUCHIcc561882014-05-22 10:31:32 -0700187 * @param key LinkID
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700188 * @return KVLink instance
Ray Milkey269ffb92014-04-03 14:43:30 -0700189 * @note You need to call `read()` to get the DB content.
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700190 */
191 public static KVLink createFromKey(final byte[] key) {
Yuta HIGUCHIcc561882014-05-22 10:31:32 -0700192 return createFromKey(key, DEFAULT_NAMESPACE);
193 }
194
195 /**
196 * Gets an instance from LinkID in specified namespace.
197 *
198 * @param key LinkID
199 * @param namespace namespace to create this object in
200 * @return KVLink instance
201 * @note You need to call `read()` to get the DB content.
202 */
203 public static KVLink createFromKey(final byte[] key, final String namespace) {
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700204 long[] linkTuple = getLinkTupleFromKey(key);
Yuta HIGUCHIcc561882014-05-22 10:31:32 -0700205 return new KVLink(linkTuple[0], linkTuple[1],
206 linkTuple[2], linkTuple[3],
207 namespace);
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700208 }
209
Yuta HIGUCHIcc561882014-05-22 10:31:32 -0700210 /**
211 * Gets all the Links in default namespace.
212 *
213 * @return Links
214 */
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700215 public static Iterable<KVLink> getAllLinks() {
Yuta HIGUCHIcc561882014-05-22 10:31:32 -0700216 return getAllLinks(DEFAULT_NAMESPACE);
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700217 }
218
Yuta HIGUCHIcc561882014-05-22 10:31:32 -0700219 /**
220 * Gets all the Links in specified namespace.
221 *
222 * @param namespace namespace to iterate over
223 * @return Links
224 */
225 public static Iterable<KVLink> getAllLinks(final String namespace) {
226 return new LinkEnumerator(namespace);
227 }
228
229 /**
230 * Utility class to provide Iterable interface.
231 */
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700232 public static class LinkEnumerator implements Iterable<KVLink> {
233
Yuta HIGUCHIcc561882014-05-22 10:31:32 -0700234 private final String namespace;
235
236 /**
237 * Constructor to iterate Links in specified namespace.
238 *
239 * @param namespace namespace to iterate through
240 */
241 public LinkEnumerator(final String namespace) {
242 this.namespace = namespace;
243 }
244
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700245 @Override
246 public Iterator<KVLink> iterator() {
Yuta HIGUCHIcc561882014-05-22 10:31:32 -0700247 return new LinkIterator(namespace);
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700248 }
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700249 }
250
Yuta HIGUCHIcc561882014-05-22 10:31:32 -0700251 /**
252 * Utility class to provide Iterator over all the Link objects.
253 */
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700254 public static class LinkIterator extends AbstractObjectIterator<KVLink> {
255
Yuta HIGUCHIcc561882014-05-22 10:31:32 -0700256 /**
257 * Constructor to create an iterator to iterate all the Links
258 * in specified namespace.
259 *
260 * @param namespace namespace to iterate through
261 */
262 public LinkIterator(final String namespace) {
263 super(DataStoreClient.getClient()
264 .getTable(namespace + LINK_TABLE_SUFFIX),
265 namespace);
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700266 }
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700267
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700268 @Override
269 public KVLink next() {
270 IKVEntry o = enumerator.next();
Yuta HIGUCHIcc561882014-05-22 10:31:32 -0700271 KVLink e = KVLink.createFromKey(o.getKey(), namespace);
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700272 e.deserialize(o.getValue(), o.getVersion());
273 return e;
274 }
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700275 }
276
Yuta HIGUCHIcc561882014-05-22 10:31:32 -0700277 /**
278 * Gets the status.
279 *
280 * @return status
281 */
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700282 public STATUS getStatus() {
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700283 return status;
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700284 }
285
Yuta HIGUCHIcc561882014-05-22 10:31:32 -0700286 /**
287 * Sets the status.
288 *
289 * @param status new status
290 */
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700291 public void setStatus(final STATUS status) {
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700292 this.status = status;
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700293 }
294
Yuta HIGUCHIcc561882014-05-22 10:31:32 -0700295 /**
296 * Gets the source SwitchPort object.
297 *
298 * @return source SwitchPort object
299 */
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700300 public SwitchPort getSrc() {
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700301 return src;
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700302 }
303
Yuta HIGUCHIcc561882014-05-22 10:31:32 -0700304 /**
305 * Gets the destination SwitchPort object.
306 *
307 * @return destination SwitchPort object
308 */
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700309 public SwitchPort getDst() {
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700310 return dst;
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700311 }
312
Yuta HIGUCHIcc561882014-05-22 10:31:32 -0700313 /**
314 * Gets the LinkID of this object.
315 *
316 * @return LinkID
317 */
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700318 public byte[] getId() {
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700319 return getKey();
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700320 }
321
322 @Override
323 public byte[] serialize() {
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700324 Map<Object, Object> map = getPropertyMap();
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700325
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700326 LinkProperty.Builder link = LinkProperty.newBuilder();
327 link.setSrcSwId(ByteString.copyFrom(src.getSwitchID()));
328 link.setSrcPortId(ByteString.copyFrom(src.getPortID()));
329 link.setDstSwId(ByteString.copyFrom(dst.getSwitchID()));
330 link.setDstPortId(ByteString.copyFrom(dst.getPortID()));
331 link.setStatus(status.ordinal());
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700332
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700333 if (!map.isEmpty()) {
Ray Milkey5c9f2db2014-04-09 10:31:21 -0700334 byte[] propMaps = serializePropertyMap(LINK_KRYO.get(), map);
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700335 link.setValue(ByteString.copyFrom(propMaps));
336 }
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700337
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700338 return link.build().toByteArray();
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700339 }
340
341 @Override
342 protected boolean deserialize(final byte[] bytes) {
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700343 try {
344 boolean success = true;
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700345
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700346 LinkProperty link = LinkProperty.parseFrom(bytes);
347 byte[] props = link.getValue().toByteArray();
Ray Milkey5c9f2db2014-04-09 10:31:21 -0700348 success &= deserializePropertyMap(LINK_KRYO.get(), props);
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700349 this.status = STATUS.values()[link.getStatus()];
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700350
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700351 return success;
352 } catch (InvalidProtocolBufferException e) {
353 log.error("Deserializing Link: " + this + " failed.", e);
354 return false;
355 }
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700356 }
357
358 @Override
359 public String toString() {
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700360 // TODO output all properties?
361 return "[" + this.getClass().getSimpleName()
362 + " " + src + "->" + dst + " STATUS:" + status + "]";
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700363 }
364}