blob: 1d9b58e9b6a3cf2e307113759175214cf39646b5 [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.SwitchProperty;
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.SwitchEvent;
Yuta HIGUCHI8f3dfa32014-06-25 00:14:25 -070013import net.onrc.onos.core.util.Dpid;
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 * Switch 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 Ports on Switch,
27 * when deleting a Switch.
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -070028 */
29public class KVSwitch extends KVObject {
30 private static final Logger log = LoggerFactory.getLogger(KVSwitch.class);
31
Ray Milkey5c9f2db2014-04-09 10:31:21 -070032 private static final ThreadLocal<Kryo> SWITCH_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 SWITCH_TABLE_SUFFIX = ":Switch";
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 STATUS status;
59
Yuta HIGUCHIcc561882014-05-22 10:31:32 -070060 /**
61 * Generate a SwitchID from dpid.
62 *
63 * @param dpid dpid of the switch
64 * @return SwitchID
65 */
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -070066 public static byte[] getSwitchID(final Long dpid) {
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -070067 return SwitchEvent.getSwitchID(dpid).array();
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -070068 }
69
Yuta HIGUCHIcc561882014-05-22 10:31:32 -070070 /**
71 * Gets the DPID from SwitchID.
72 *
73 * @param key SwitchID
74 * @return dpid
75 */
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -070076 public static long getDpidFromKey(final byte[] key) {
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -070077 return getDpidFromKey(ByteBuffer.wrap(key));
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -070078 }
79
Yuta HIGUCHIcc561882014-05-22 10:31:32 -070080 /**
81 * Gets the DPID from SwitchID.
82 *
83 * @param keyBuf SwitchID
84 * @return dpid
85 */
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -070086 public static long getDpidFromKey(final ByteBuffer keyBuf) {
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -070087 if (keyBuf.getChar() != 'S') {
88 throw new IllegalArgumentException("Invalid Switch key");
89 }
90 return keyBuf.getLong();
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -070091 }
92
Yuta HIGUCHIcc561882014-05-22 10:31:32 -070093 // FIXME Should the parameter be DPID here, or should caller specify the key?
94 // Should layer above have the control of the ID computation/generation?
95 /**
96 * KVSwitch constructor for default namespace.
97 *
98 * @param dpid dpid of this switch
99 */
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700100 public KVSwitch(final Long dpid) {
Yuta HIGUCHIcc561882014-05-22 10:31:32 -0700101 this(dpid, KVObject.DEFAULT_NAMESPACE);
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700102 }
103
104 /**
Yuta HIGUCHIcc561882014-05-22 10:31:32 -0700105 * KVSwitch constructor for specified namespace.
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700106 *
Yuta HIGUCHIcc561882014-05-22 10:31:32 -0700107 * @param dpid dpid of this switch
108 * @param namespace namespace to create this object
109 */
110 public KVSwitch(final Long dpid, final String namespace) {
111 super(DataStoreClient.getClient()
112 .getTable(namespace + SWITCH_TABLE_SUFFIX),
113 getSwitchID(dpid), namespace);
114
115 this.dpid = dpid;
116 this.status = STATUS.INACTIVE;
117 // may need to store namespace here or at KVObject.
118 }
119
120 /**
Yuta HIGUCHI8f3dfa32014-06-25 00:14:25 -0700121 * KVSwitch constructor for default namespace.
122 *
123 * @param dpid dpid of this switch
124 */
125 public KVSwitch(final Dpid dpid) {
126 this(dpid, KVObject.DEFAULT_NAMESPACE);
127 }
128
129 /**
130 * KVSwitch constructor for specified namespace.
131 *
132 * @param dpid dpid of this switch
133 * @param namespace namespace to create this object
134 */
135 public KVSwitch(final Dpid dpid, final String namespace) {
136 this(dpid.value(), namespace);
137 }
138
139 /**
Yuta HIGUCHIcc561882014-05-22 10:31:32 -0700140 * Gets an instance from SwitchID in default namespace.
Jonathan Hart99ff20a2014-06-15 16:53:00 -0700141 * <p/>
142 * Note: You need to call `read()` to get the DB content.
Yuta HIGUCHIcc561882014-05-22 10:31:32 -0700143 *
144 * @param key SwitchID
145 * @return {@link KVSwitch} instance
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700146 */
147 public static KVSwitch createFromKey(final byte[] key) {
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700148 return new KVSwitch(getDpidFromKey(key));
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700149 }
150
Yuta HIGUCHIcc561882014-05-22 10:31:32 -0700151 /**
152 * Gets an instance from SwitchID in specified namespace.
Jonathan Hart99ff20a2014-06-15 16:53:00 -0700153 * <p/>
154 * Note: You need to call `read()` to get the DB content.
Yuta HIGUCHIcc561882014-05-22 10:31:32 -0700155 *
156 * @param key SwitchID
157 * @param namespace namespace to create this object
158 * @return {@link KVSwitch} instance
Yuta HIGUCHIcc561882014-05-22 10:31:32 -0700159 */
160 public static KVSwitch createFromKey(final byte[] key, final String namespace) {
161 return new KVSwitch(getDpidFromKey(key), namespace);
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700162 }
163
Yuta HIGUCHIcc561882014-05-22 10:31:32 -0700164 /**
165 * Gets all the switches in default namespace.
166 *
167 * @return All the {@link KVSwitch}
168 */
169 public static Iterable<KVSwitch> getAllSwitches() {
170 return getAllSwitches(DEFAULT_NAMESPACE);
171 }
172
173 /**
174 * Gets all the switches in specified namespace.
175 *
176 * @param namespace Namespace to get all switches.
177 * @return All the {@link KVSwitch}
178 */
179 public static Iterable<KVSwitch> getAllSwitches(final String namespace) {
180 return new SwitchEnumerator(namespace);
181 }
182
183 /**
184 * Utility class to provide Iterable interface.
185 */
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700186 public static class SwitchEnumerator implements Iterable<KVSwitch> {
187
Yuta HIGUCHIcc561882014-05-22 10:31:32 -0700188 private final String namespace;
189
190 /**
191 * Constructor to iterate Ports in specified namespace.
192 *
193 * @param namespace namespace to iterate through
194 */
195 public SwitchEnumerator(final String namespace) {
196 this.namespace = namespace;
197 }
198
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700199 @Override
200 public Iterator<KVSwitch> iterator() {
Yuta HIGUCHIcc561882014-05-22 10:31:32 -0700201 return new SwitchIterator(namespace);
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700202 }
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700203 }
204
Yuta HIGUCHIcc561882014-05-22 10:31:32 -0700205 /**
206 * Utility class to provide Iterator over all the Switch objects.
207 */
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700208 public static class SwitchIterator extends AbstractObjectIterator<KVSwitch> {
209
Yuta HIGUCHIcc561882014-05-22 10:31:32 -0700210 /**
211 * Constructor to create an iterator to iterate all the Switches
212 * in specified namespace.
213 *
214 * @param namespace namespace to iterate through
215 */
216 public SwitchIterator(final String namespace) {
217 super(DataStoreClient.getClient()
218 .getTable(namespace + SWITCH_TABLE_SUFFIX), namespace);
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700219 }
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700220
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700221 @Override
222 public KVSwitch next() {
223 IKVEntry o = enumerator.next();
Yuta HIGUCHIcc561882014-05-22 10:31:32 -0700224 KVSwitch e = KVSwitch.createFromKey(o.getKey(), namespace);
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700225 e.deserialize(o.getValue(), o.getVersion());
226 return e;
227 }
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700228 }
229
Yuta HIGUCHIcc561882014-05-22 10:31:32 -0700230 /**
231 * Gets the status.
232 *
233 * @return status
234 */
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700235 public STATUS getStatus() {
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700236 return status;
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700237 }
238
Yuta HIGUCHIcc561882014-05-22 10:31:32 -0700239 /**
240 * Sets the status.
241 *
242 * @param status new status
243 */
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700244 public void setStatus(final STATUS status) {
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700245 this.status = status;
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700246 }
247
Yuta HIGUCHIcc561882014-05-22 10:31:32 -0700248 /**
249 * Gets the DPID of the switch this port is on.
250 *
251 * @return DPID of the switch this port is on
252 */
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700253 public Long getDpid() {
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700254 return dpid;
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700255 }
256
Yuta HIGUCHIcc561882014-05-22 10:31:32 -0700257 /**
258 * Gets the SwitchID.
259 *
260 * @return SwitchID
261 */
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700262 public byte[] getId() {
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700263 return getKey();
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700264 }
265
266 @Override
267 public byte[] serialize() {
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700268 Map<Object, Object> map = getPropertyMap();
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700269
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700270 SwitchProperty.Builder sw = SwitchProperty.newBuilder();
271 sw.setDpid(dpid);
272 sw.setStatus(status.ordinal());
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700273
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700274 if (!map.isEmpty()) {
Ray Milkey5c9f2db2014-04-09 10:31:21 -0700275 byte[] propMaps = serializePropertyMap(SWITCH_KRYO.get(), map);
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700276 sw.setValue(ByteString.copyFrom(propMaps));
277 }
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700278
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700279 return sw.build().toByteArray();
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700280 }
281
282 @Override
283 protected boolean deserialize(final byte[] bytes) {
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700284 try {
285 boolean success = true;
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700286
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700287 SwitchProperty sw = SwitchProperty.parseFrom(bytes);
288 byte[] props = sw.getValue().toByteArray();
Ray Milkey5c9f2db2014-04-09 10:31:21 -0700289 success &= deserializePropertyMap(SWITCH_KRYO.get(), props);
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700290 this.status = STATUS.values()[sw.getStatus()];
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700291
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700292 return success;
293 } catch (InvalidProtocolBufferException e) {
294 log.error("Deserializing Switch: " + this + " failed.", e);
295 return false;
296 }
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700297 }
298
299 @Override
300 public String toString() {
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700301 // TODO output all properties?
302 return "[" + this.getClass().getSimpleName()
303 + " 0x" + Long.toHexString(dpid) + " STATUS:" + status + "]";
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700304 }
305
306}