blob: addb207c851f1e9cf726498aed9ad5a0f96bd837 [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;
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -07004import java.util.Collection;
5import java.util.Collections;
6import java.util.HashMap;
7import java.util.Iterator;
8import java.util.Map;
9import java.util.Set;
10import java.util.TreeSet;
11
Jonathan Hart6df90172014-04-03 10:13:11 -070012import net.onrc.onos.core.datastore.DataStoreClient;
13import net.onrc.onos.core.datastore.IKVTable.IKVEntry;
TeruU28adcc32014-04-15 17:57:35 -070014import net.onrc.onos.core.datastore.serializers.Device.DeviceProperty;
Jonathan Hart6df90172014-04-03 10:13:11 -070015import net.onrc.onos.core.datastore.topology.KVLink.STATUS;
16import net.onrc.onos.core.datastore.utils.ByteArrayComparator;
17import net.onrc.onos.core.datastore.utils.ByteArrayUtil;
18import net.onrc.onos.core.datastore.utils.KVObject;
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -070019import net.onrc.onos.core.topology.HostData;
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -070020
21import org.slf4j.Logger;
22import org.slf4j.LoggerFactory;
23
24import com.esotericsoftware.kryo.Kryo;
TeruU28adcc32014-04-15 17:57:35 -070025import com.google.protobuf.ByteString;
26import com.google.protobuf.InvalidProtocolBufferException;
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -070027
28/**
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -070029 * Host object.
Ray Milkey269ffb92014-04-03 14:43:30 -070030 * <p/>
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -070031 */
32public class KVDevice extends KVObject {
33 private static final Logger log = LoggerFactory.getLogger(KVDevice.class);
34
Ray Milkey5c9f2db2014-04-09 10:31:21 -070035 private static final ThreadLocal<Kryo> DEVICE_KRYO = new ThreadLocal<Kryo>() {
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -070036 @Override
37 protected Kryo initialValue() {
38 Kryo kryo = new Kryo();
39 kryo.setRegistrationRequired(true);
40 kryo.setReferences(false);
41 kryo.register(byte[].class);
42 kryo.register(byte[][].class);
43 kryo.register(HashMap.class);
44 // TODO check if we should explicitly specify EnumSerializer
45 kryo.register(STATUS.class);
46 return kryo;
47 }
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -070048 };
49
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -070050 static final String DEVICE_TABLE_SUFFIX = ":Host";
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -070051
52 private final byte[] mac;
53 private TreeSet<byte[]> portIds;
Ray Milkey269ffb92014-04-03 14:43:30 -070054
Yuta HIGUCHIcc561882014-05-22 10:31:32 -070055 /**
Pavlin Radoslavov53b208a2014-07-28 13:16:11 -070056 * Generate a HostID from MAC address.
Yuta HIGUCHIcc561882014-05-22 10:31:32 -070057 * <p/>
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -070058 * We're assuming MAC address can be an unique identifier for Host.
Yuta HIGUCHIcc561882014-05-22 10:31:32 -070059 *
60 * @param mac MAC address
Pavlin Radoslavov53b208a2014-07-28 13:16:11 -070061 * @return HostID
Yuta HIGUCHIcc561882014-05-22 10:31:32 -070062 */
Pavlin Radoslavov53b208a2014-07-28 13:16:11 -070063 public static byte[] getHostID(final byte[] mac) {
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -070064 return HostData.getHostID(mac).array();
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -070065 }
66
Yuta HIGUCHIcc561882014-05-22 10:31:32 -070067 /**
Pavlin Radoslavov53b208a2014-07-28 13:16:11 -070068 * Gets the MAC address from HostID.
Yuta HIGUCHIcc561882014-05-22 10:31:32 -070069 *
Pavlin Radoslavov53b208a2014-07-28 13:16:11 -070070 * @param key HostID
Yuta HIGUCHIcc561882014-05-22 10:31:32 -070071 * @return MAC address
72 */
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -070073 public static byte[] getMacFromKey(final byte[] key) {
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -070074 ByteBuffer keyBuf = ByteBuffer.wrap(key);
Pavlin Radoslavov53b208a2014-07-28 13:16:11 -070075 if (keyBuf.getChar() != 'H') {
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -070076 throw new IllegalArgumentException("Invalid Host key");
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -070077 }
78 byte[] mac = new byte[keyBuf.remaining()];
79 keyBuf.get(mac);
80 return mac;
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -070081 }
82
Yuta HIGUCHIcc561882014-05-22 10:31:32 -070083 /**
84 * KVDevice constructor for default namespace.
85 *
86 * @param mac MAC address
87 */
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -070088 public KVDevice(final byte[] mac) {
Yuta HIGUCHIcc561882014-05-22 10:31:32 -070089 this(mac, DEFAULT_NAMESPACE);
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -070090 }
91
92 /**
Yuta HIGUCHIcc561882014-05-22 10:31:32 -070093 * KVDevice constructor for specified namespace.
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -070094 *
Yuta HIGUCHIcc561882014-05-22 10:31:32 -070095 * @param mac MAC address
96 * @param namespace namespace to create this object
97 */
98 public KVDevice(final byte[] mac, final String namespace) {
99 super(DataStoreClient.getClient()
100 .getTable(namespace + DEVICE_TABLE_SUFFIX),
Pavlin Radoslavov53b208a2014-07-28 13:16:11 -0700101 getHostID(mac), namespace);
Yuta HIGUCHIcc561882014-05-22 10:31:32 -0700102
103 this.mac = mac.clone();
104 this.portIds = new TreeSet<>(ByteArrayComparator.BYTEARRAY_COMPARATOR);
105 }
106
107 /**
Pavlin Radoslavov53b208a2014-07-28 13:16:11 -0700108 * Gets an instance from HostID in default namespace.
Jonathan Hart99ff20a2014-06-15 16:53:00 -0700109 * <p/>
110 * Note: You need to call `read()` to get the DB content.
Yuta HIGUCHIcc561882014-05-22 10:31:32 -0700111 *
Pavlin Radoslavov53b208a2014-07-28 13:16:11 -0700112 * @param key HostID
Yuta HIGUCHIcc561882014-05-22 10:31:32 -0700113 * @return KVDevice instance
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700114 */
115 public static KVDevice createFromKey(final byte[] key) {
Yuta HIGUCHIcc561882014-05-22 10:31:32 -0700116 return createFromKey(key, DEFAULT_NAMESPACE);
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700117 }
118
Yuta HIGUCHIcc561882014-05-22 10:31:32 -0700119 /**
Pavlin Radoslavov53b208a2014-07-28 13:16:11 -0700120 * Gets an instance from HostID in specified namespace.
Jonathan Hart99ff20a2014-06-15 16:53:00 -0700121 * <p/>
122 * Note: You need to call `read()` to get the DB content.
Yuta HIGUCHIcc561882014-05-22 10:31:32 -0700123 *
Pavlin Radoslavov53b208a2014-07-28 13:16:11 -0700124 * @param key HostID
Yuta HIGUCHIcc561882014-05-22 10:31:32 -0700125 * @param namespace namespace to create this object in
126 * @return KVDevice instance
Yuta HIGUCHIcc561882014-05-22 10:31:32 -0700127 */
128 public static KVDevice createFromKey(final byte[] key, final String namespace) {
129 return new KVDevice(getMacFromKey(key), namespace);
130 }
131
132 /**
133 * Gets all the Devices in default namespace.
134 *
135 * @return Devices
136 */
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700137 public static Iterable<KVDevice> getAllDevices() {
Yuta HIGUCHIcc561882014-05-22 10:31:32 -0700138 return new DeviceEnumerator(DEFAULT_NAMESPACE);
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700139 }
140
Yuta HIGUCHIcc561882014-05-22 10:31:32 -0700141 /**
142 * Gets all the Devices in specified namespace.
143 *
144 * @param namespace namespace to iterate over
145 * @return Devices
146 */
147 public static Iterable<KVDevice> getAllDevices(final String namespace) {
148 return new DeviceEnumerator(namespace);
149 }
150
151 /**
152 * Utility class to provide Iterable interface.
153 */
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700154 public static class DeviceEnumerator implements Iterable<KVDevice> {
155
Yuta HIGUCHIcc561882014-05-22 10:31:32 -0700156 private final String namespace;
157
158 /**
159 * Constructor to iterate Links in specified namespace.
160 *
161 * @param namespace namespace to iterate through
162 */
163 public DeviceEnumerator(final String namespace) {
164 this.namespace = namespace;
165 }
166
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700167 @Override
168 public Iterator<KVDevice> iterator() {
Yuta HIGUCHIcc561882014-05-22 10:31:32 -0700169 return new DeviceIterator(namespace);
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700170 }
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700171 }
172
Yuta HIGUCHIcc561882014-05-22 10:31:32 -0700173 /**
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -0700174 * Utility class to provide Iterator over all the Host objects.
Yuta HIGUCHIcc561882014-05-22 10:31:32 -0700175 */
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700176 public static class DeviceIterator extends AbstractObjectIterator<KVDevice> {
177
Yuta HIGUCHIcc561882014-05-22 10:31:32 -0700178 /**
179 * Constructor to create an iterator to iterate all the Devices
180 * in specified namespace.
181 *
182 * @param namespace namespace to iterate through
183 */
184 public DeviceIterator(final String namespace) {
185 super(DataStoreClient.getClient()
186 .getTable(namespace + DEVICE_TABLE_SUFFIX), namespace);
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700187 }
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700188
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700189 @Override
190 public KVDevice next() {
191 IKVEntry o = enumerator.next();
Yuta HIGUCHIcc561882014-05-22 10:31:32 -0700192 KVDevice e = KVDevice.createFromKey(o.getKey(), namespace);
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700193 e.deserialize(o.getValue(), o.getVersion());
194 return e;
195 }
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700196 }
197
Yuta HIGUCHIcc561882014-05-22 10:31:32 -0700198 /**
199 * Gets the MAC address.
200 *
201 * @return MAC address
202 */
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700203 public byte[] getMac() {
Yuta HIGUCHIce7e7f82014-04-15 21:37:38 -0700204 return mac.clone();
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700205 }
206
Yuta HIGUCHIcc561882014-05-22 10:31:32 -0700207 /**
Pavlin Radoslavov53b208a2014-07-28 13:16:11 -0700208 * Gets the HostID.
Yuta HIGUCHIcc561882014-05-22 10:31:32 -0700209 *
Pavlin Radoslavov53b208a2014-07-28 13:16:11 -0700210 * @return HostID
Yuta HIGUCHIcc561882014-05-22 10:31:32 -0700211 */
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700212 public byte[] getId() {
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700213 return getKey();
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700214 }
215
Yuta HIGUCHIcc561882014-05-22 10:31:32 -0700216 /**
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -0700217 * Add a port to this Host's attachment points.
Yuta HIGUCHIcc561882014-05-22 10:31:32 -0700218 *
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -0700219 * @param portId PortID of the port which this Host is attached
Yuta HIGUCHIcc561882014-05-22 10:31:32 -0700220 */
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700221 public void addPortId(final byte[] portId) {
Yuta HIGUCHIcc561882014-05-22 10:31:32 -0700222 portIds.add(portId.clone());
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700223 }
224
225 /**
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -0700226 * Remove a port from this Host's attachment points.
Yuta HIGUCHIcc561882014-05-22 10:31:32 -0700227 *
228 * @param portId PortID to remove
229 */
230 public void removePortId(final byte[] portId) {
231 portIds.remove(portId);
232 }
233
234 /**
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -0700235 * Empty this Host's attachment points.
Yuta HIGUCHIcc561882014-05-22 10:31:32 -0700236 */
237 public void emptyPortIds() {
238 portIds.clear();
239 }
240
241 /**
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -0700242 * Add ports to this Host's attachment points.
Yuta HIGUCHIcc561882014-05-22 10:31:32 -0700243 *
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -0700244 * @param newPortIds PortIDs which this Host is attached
Yuta HIGUCHIcc561882014-05-22 10:31:32 -0700245 */
246 public void addAllToPortIds(final Collection<byte[]> newPortIds) {
247 // TODO: Should we copy each portId, or reference is OK.
248 portIds.addAll(newPortIds);
249 }
250
251 /**
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -0700252 * Gets all the PortIDs which this Host is attached.
Yuta HIGUCHIcc561882014-05-22 10:31:32 -0700253 *
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700254 * @return Unmodifiable Set view of all the PortIds;
255 */
256 public Set<byte[]> getAllPortIds() {
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700257 return Collections.unmodifiableSet(portIds);
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700258 }
259
260 @Override
261 public byte[] serialize() {
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700262 Map<Object, Object> map = getPropertyMap();
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700263
TeruU28adcc32014-04-15 17:57:35 -0700264 DeviceProperty.Builder dev = DeviceProperty.newBuilder();
265
266 dev.setMac(ByteString.copyFrom(mac));
267 for (byte[] port : portIds) {
268 dev.addPortIds(ByteString.copyFrom(port));
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700269 }
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700270
TeruU28adcc32014-04-15 17:57:35 -0700271 if (!map.isEmpty()) {
272 byte[] propMaps = serializePropertyMap(DEVICE_KRYO.get(), map);
273 dev.setValue(ByteString.copyFrom(propMaps));
274 }
275
276 return dev.build().toByteArray();
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700277 }
278
279 @Override
280 protected boolean deserialize(final byte[] bytes) {
TeruU28adcc32014-04-15 17:57:35 -0700281
282 try {
283 boolean success = true;
284
285 DeviceProperty dev = DeviceProperty.parseFrom(bytes);
286 for (ByteString portId : dev.getPortIdsList()) {
287 this.addPortId(portId.toByteArray());
288 }
289 byte[] props = dev.getValue().toByteArray();
290 success &= deserializePropertyMap(DEVICE_KRYO.get(), props);
291 return success;
292 } catch (InvalidProtocolBufferException e) {
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -0700293 log.error("Deserializing Host: " + this + " failed.", e);
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700294 return false;
295 }
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700296 }
297
298 @Override
299 public String toString() {
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700300 // TODO output all properties?
301 return "[" + this.getClass().getSimpleName()
Yuta HIGUCHI805bc8f2014-04-16 11:51:43 -0700302 + " " + ByteArrayUtil.toHexStringBuilder(mac, ":") + "]";
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700303 }
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700304}