blob: 0945071a8ff200dc7d2ce808491e94d9b32bf2a2 [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.
Jonathan Hart99ff20a2014-06-15 16:53:00 -0700186 * <p/>
187 * Note: You need to call `read()` to get the DB content.
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700188 *
Yuta HIGUCHIcc561882014-05-22 10:31:32 -0700189 * @param key LinkID
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700190 * @return KVLink instance
191 */
192 public static KVLink createFromKey(final byte[] key) {
Yuta HIGUCHIcc561882014-05-22 10:31:32 -0700193 return createFromKey(key, DEFAULT_NAMESPACE);
194 }
195
196 /**
197 * Gets an instance from LinkID in specified namespace.
Jonathan Hart99ff20a2014-06-15 16:53:00 -0700198 * <p/>
199 * Note: You need to call `read()` to get the DB content.
Yuta HIGUCHIcc561882014-05-22 10:31:32 -0700200 *
201 * @param key LinkID
202 * @param namespace namespace to create this object in
203 * @return KVLink instance
Yuta HIGUCHIcc561882014-05-22 10:31:32 -0700204 */
205 public static KVLink createFromKey(final byte[] key, final String namespace) {
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700206 long[] linkTuple = getLinkTupleFromKey(key);
Yuta HIGUCHIcc561882014-05-22 10:31:32 -0700207 return new KVLink(linkTuple[0], linkTuple[1],
208 linkTuple[2], linkTuple[3],
209 namespace);
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700210 }
211
Yuta HIGUCHIcc561882014-05-22 10:31:32 -0700212 /**
213 * Gets all the Links in default namespace.
214 *
215 * @return Links
216 */
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700217 public static Iterable<KVLink> getAllLinks() {
Yuta HIGUCHIcc561882014-05-22 10:31:32 -0700218 return getAllLinks(DEFAULT_NAMESPACE);
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700219 }
220
Yuta HIGUCHIcc561882014-05-22 10:31:32 -0700221 /**
222 * Gets all the Links in specified namespace.
223 *
224 * @param namespace namespace to iterate over
225 * @return Links
226 */
227 public static Iterable<KVLink> getAllLinks(final String namespace) {
228 return new LinkEnumerator(namespace);
229 }
230
231 /**
232 * Utility class to provide Iterable interface.
233 */
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700234 public static class LinkEnumerator implements Iterable<KVLink> {
235
Yuta HIGUCHIcc561882014-05-22 10:31:32 -0700236 private final String namespace;
237
238 /**
239 * Constructor to iterate Links in specified namespace.
240 *
241 * @param namespace namespace to iterate through
242 */
243 public LinkEnumerator(final String namespace) {
244 this.namespace = namespace;
245 }
246
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700247 @Override
248 public Iterator<KVLink> iterator() {
Yuta HIGUCHIcc561882014-05-22 10:31:32 -0700249 return new LinkIterator(namespace);
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700250 }
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700251 }
252
Yuta HIGUCHIcc561882014-05-22 10:31:32 -0700253 /**
254 * Utility class to provide Iterator over all the Link objects.
255 */
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700256 public static class LinkIterator extends AbstractObjectIterator<KVLink> {
257
Yuta HIGUCHIcc561882014-05-22 10:31:32 -0700258 /**
259 * Constructor to create an iterator to iterate all the Links
260 * in specified namespace.
261 *
262 * @param namespace namespace to iterate through
263 */
264 public LinkIterator(final String namespace) {
265 super(DataStoreClient.getClient()
266 .getTable(namespace + LINK_TABLE_SUFFIX),
267 namespace);
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700268 }
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700269
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700270 @Override
271 public KVLink next() {
272 IKVEntry o = enumerator.next();
Yuta HIGUCHIcc561882014-05-22 10:31:32 -0700273 KVLink e = KVLink.createFromKey(o.getKey(), namespace);
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700274 e.deserialize(o.getValue(), o.getVersion());
275 return e;
276 }
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700277 }
278
Yuta HIGUCHIcc561882014-05-22 10:31:32 -0700279 /**
280 * Gets the status.
281 *
282 * @return status
283 */
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700284 public STATUS getStatus() {
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700285 return status;
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700286 }
287
Yuta HIGUCHIcc561882014-05-22 10:31:32 -0700288 /**
289 * Sets the status.
290 *
291 * @param status new status
292 */
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700293 public void setStatus(final STATUS status) {
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700294 this.status = status;
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700295 }
296
Yuta HIGUCHIcc561882014-05-22 10:31:32 -0700297 /**
298 * Gets the source SwitchPort object.
299 *
300 * @return source SwitchPort object
301 */
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700302 public SwitchPort getSrc() {
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700303 return src;
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700304 }
305
Yuta HIGUCHIcc561882014-05-22 10:31:32 -0700306 /**
307 * Gets the destination SwitchPort object.
308 *
309 * @return destination SwitchPort object
310 */
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700311 public SwitchPort getDst() {
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700312 return dst;
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700313 }
314
Yuta HIGUCHIcc561882014-05-22 10:31:32 -0700315 /**
316 * Gets the LinkID of this object.
317 *
318 * @return LinkID
319 */
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700320 public byte[] getId() {
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700321 return getKey();
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700322 }
323
324 @Override
325 public byte[] serialize() {
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700326 Map<Object, Object> map = getPropertyMap();
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700327
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700328 LinkProperty.Builder link = LinkProperty.newBuilder();
329 link.setSrcSwId(ByteString.copyFrom(src.getSwitchID()));
330 link.setSrcPortId(ByteString.copyFrom(src.getPortID()));
331 link.setDstSwId(ByteString.copyFrom(dst.getSwitchID()));
332 link.setDstPortId(ByteString.copyFrom(dst.getPortID()));
333 link.setStatus(status.ordinal());
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700334
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700335 if (!map.isEmpty()) {
Ray Milkey5c9f2db2014-04-09 10:31:21 -0700336 byte[] propMaps = serializePropertyMap(LINK_KRYO.get(), map);
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700337 link.setValue(ByteString.copyFrom(propMaps));
338 }
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700339
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700340 return link.build().toByteArray();
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700341 }
342
343 @Override
344 protected boolean deserialize(final byte[] bytes) {
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700345 try {
346 boolean success = true;
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700347
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700348 LinkProperty link = LinkProperty.parseFrom(bytes);
349 byte[] props = link.getValue().toByteArray();
Ray Milkey5c9f2db2014-04-09 10:31:21 -0700350 success &= deserializePropertyMap(LINK_KRYO.get(), props);
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700351 this.status = STATUS.values()[link.getStatus()];
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700352
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700353 return success;
354 } catch (InvalidProtocolBufferException e) {
355 log.error("Deserializing Link: " + this + " failed.", e);
356 return false;
357 }
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700358 }
359
360 @Override
361 public String toString() {
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700362 // TODO output all properties?
363 return "[" + this.getClass().getSimpleName()
364 + " " + src + "->" + dst + " STATUS:" + status + "]";
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700365 }
366}