blob: aed08be20bac0dffc84984b058fb43e53d0185a4 [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 HIGUCHI66ca1bf2014-03-12 18:34:09 -070013
14import org.slf4j.Logger;
15import org.slf4j.LoggerFactory;
16
17import com.esotericsoftware.kryo.Kryo;
18import com.google.protobuf.ByteString;
19import com.google.protobuf.InvalidProtocolBufferException;
20
21/**
22 * Switch object in data store.
Ray Milkey269ffb92014-04-03 14:43:30 -070023 * <p/>
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -070024 * Note: This class will not maintain invariants.
Ray Milkey269ffb92014-04-03 14:43:30 -070025 * e.g., It will NOT automatically remove Ports on Switch,
26 * when deleting a Switch.
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -070027 */
28public class KVSwitch extends KVObject {
29 private static final Logger log = LoggerFactory.getLogger(KVSwitch.class);
30
Ray Milkey5c9f2db2014-04-09 10:31:21 -070031 private static final ThreadLocal<Kryo> SWITCH_KRYO = new ThreadLocal<Kryo>() {
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -070032 @Override
33 protected Kryo initialValue() {
34 Kryo kryo = new Kryo();
35 kryo.setRegistrationRequired(true);
36 kryo.setReferences(false);
37 kryo.register(byte[].class);
38 kryo.register(byte[][].class);
39 kryo.register(HashMap.class);
40 // TODO check if we should explicitly specify EnumSerializer
41 kryo.register(STATUS.class);
42 return kryo;
43 }
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -070044 };
45
Yuta HIGUCHIcc561882014-05-22 10:31:32 -070046 static final String SWITCH_TABLE_SUFFIX = ":Switch";
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -070047
48 // must not re-order enum members, ordinal will be sent over wire
Yuta HIGUCHIcc561882014-05-22 10:31:32 -070049 /**
50 * Status.
51 */
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -070052 public enum STATUS {
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -070053 INACTIVE, ACTIVE;
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -070054 }
55
56 private final Long dpid;
57 private STATUS status;
58
Yuta HIGUCHIcc561882014-05-22 10:31:32 -070059 /**
60 * Generate a SwitchID from dpid.
61 *
62 * @param dpid dpid of the switch
63 * @return SwitchID
64 */
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -070065 public static byte[] getSwitchID(final Long dpid) {
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -070066 return SwitchEvent.getSwitchID(dpid).array();
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -070067 }
68
Yuta HIGUCHIcc561882014-05-22 10:31:32 -070069 /**
70 * Gets the DPID from SwitchID.
71 *
72 * @param key SwitchID
73 * @return dpid
74 */
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -070075 public static long getDpidFromKey(final byte[] key) {
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -070076 return getDpidFromKey(ByteBuffer.wrap(key));
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -070077 }
78
Yuta HIGUCHIcc561882014-05-22 10:31:32 -070079 /**
80 * Gets the DPID from SwitchID.
81 *
82 * @param keyBuf SwitchID
83 * @return dpid
84 */
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -070085 public static long getDpidFromKey(final ByteBuffer keyBuf) {
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -070086 if (keyBuf.getChar() != 'S') {
87 throw new IllegalArgumentException("Invalid Switch key");
88 }
89 return keyBuf.getLong();
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -070090 }
91
Yuta HIGUCHIcc561882014-05-22 10:31:32 -070092 // FIXME Should the parameter be DPID here, or should caller specify the key?
93 // Should layer above have the control of the ID computation/generation?
94 /**
95 * KVSwitch constructor for default namespace.
96 *
97 * @param dpid dpid of this switch
98 */
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -070099 public KVSwitch(final Long dpid) {
Yuta HIGUCHIcc561882014-05-22 10:31:32 -0700100 this(dpid, KVObject.DEFAULT_NAMESPACE);
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700101 }
102
103 /**
Yuta HIGUCHIcc561882014-05-22 10:31:32 -0700104 * KVSwitch constructor for specified namespace.
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700105 *
Yuta HIGUCHIcc561882014-05-22 10:31:32 -0700106 * @param dpid dpid of this switch
107 * @param namespace namespace to create this object
108 */
109 public KVSwitch(final Long dpid, final String namespace) {
110 super(DataStoreClient.getClient()
111 .getTable(namespace + SWITCH_TABLE_SUFFIX),
112 getSwitchID(dpid), namespace);
113
114 this.dpid = dpid;
115 this.status = STATUS.INACTIVE;
116 // may need to store namespace here or at KVObject.
117 }
118
119 /**
120 * Gets an instance from SwitchID in default namespace.
121 *
122 * @param key SwitchID
123 * @return {@link KVSwitch} instance
Ray Milkey269ffb92014-04-03 14:43:30 -0700124 * @note You need to call `read()` to get the DB content.
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700125 */
126 public static KVSwitch createFromKey(final byte[] key) {
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700127 return new KVSwitch(getDpidFromKey(key));
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700128 }
129
Yuta HIGUCHIcc561882014-05-22 10:31:32 -0700130 /**
131 * Gets an instance from SwitchID in specified namespace.
132 *
133 * @param key SwitchID
134 * @param namespace namespace to create this object
135 * @return {@link KVSwitch} instance
136 * @note You need to call `read()` to get the DB content.
137 */
138 public static KVSwitch createFromKey(final byte[] key, final String namespace) {
139 return new KVSwitch(getDpidFromKey(key), namespace);
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700140 }
141
Yuta HIGUCHIcc561882014-05-22 10:31:32 -0700142 /**
143 * Gets all the switches in default namespace.
144 *
145 * @return All the {@link KVSwitch}
146 */
147 public static Iterable<KVSwitch> getAllSwitches() {
148 return getAllSwitches(DEFAULT_NAMESPACE);
149 }
150
151 /**
152 * Gets all the switches in specified namespace.
153 *
154 * @param namespace Namespace to get all switches.
155 * @return All the {@link KVSwitch}
156 */
157 public static Iterable<KVSwitch> getAllSwitches(final String namespace) {
158 return new SwitchEnumerator(namespace);
159 }
160
161 /**
162 * Utility class to provide Iterable interface.
163 */
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700164 public static class SwitchEnumerator implements Iterable<KVSwitch> {
165
Yuta HIGUCHIcc561882014-05-22 10:31:32 -0700166 private final String namespace;
167
168 /**
169 * Constructor to iterate Ports in specified namespace.
170 *
171 * @param namespace namespace to iterate through
172 */
173 public SwitchEnumerator(final String namespace) {
174 this.namespace = namespace;
175 }
176
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700177 @Override
178 public Iterator<KVSwitch> iterator() {
Yuta HIGUCHIcc561882014-05-22 10:31:32 -0700179 return new SwitchIterator(namespace);
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700180 }
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700181 }
182
Yuta HIGUCHIcc561882014-05-22 10:31:32 -0700183 /**
184 * Utility class to provide Iterator over all the Switch objects.
185 */
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700186 public static class SwitchIterator extends AbstractObjectIterator<KVSwitch> {
187
Yuta HIGUCHIcc561882014-05-22 10:31:32 -0700188 /**
189 * Constructor to create an iterator to iterate all the Switches
190 * in specified namespace.
191 *
192 * @param namespace namespace to iterate through
193 */
194 public SwitchIterator(final String namespace) {
195 super(DataStoreClient.getClient()
196 .getTable(namespace + SWITCH_TABLE_SUFFIX), namespace);
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700197 }
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700198
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700199 @Override
200 public KVSwitch next() {
201 IKVEntry o = enumerator.next();
Yuta HIGUCHIcc561882014-05-22 10:31:32 -0700202 KVSwitch e = KVSwitch.createFromKey(o.getKey(), namespace);
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700203 e.deserialize(o.getValue(), o.getVersion());
204 return e;
205 }
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700206 }
207
Yuta HIGUCHIcc561882014-05-22 10:31:32 -0700208 /**
209 * Gets the status.
210 *
211 * @return status
212 */
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700213 public STATUS getStatus() {
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700214 return status;
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700215 }
216
Yuta HIGUCHIcc561882014-05-22 10:31:32 -0700217 /**
218 * Sets the status.
219 *
220 * @param status new status
221 */
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700222 public void setStatus(final STATUS status) {
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700223 this.status = status;
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700224 }
225
Yuta HIGUCHIcc561882014-05-22 10:31:32 -0700226 /**
227 * Gets the DPID of the switch this port is on.
228 *
229 * @return DPID of the switch this port is on
230 */
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700231 public Long getDpid() {
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700232 return dpid;
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700233 }
234
Yuta HIGUCHIcc561882014-05-22 10:31:32 -0700235 /**
236 * Gets the SwitchID.
237 *
238 * @return SwitchID
239 */
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700240 public byte[] getId() {
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700241 return getKey();
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700242 }
243
244 @Override
245 public byte[] serialize() {
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700246 Map<Object, Object> map = getPropertyMap();
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700247
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700248 SwitchProperty.Builder sw = SwitchProperty.newBuilder();
249 sw.setDpid(dpid);
250 sw.setStatus(status.ordinal());
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700251
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700252 if (!map.isEmpty()) {
Ray Milkey5c9f2db2014-04-09 10:31:21 -0700253 byte[] propMaps = serializePropertyMap(SWITCH_KRYO.get(), map);
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700254 sw.setValue(ByteString.copyFrom(propMaps));
255 }
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700256
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700257 return sw.build().toByteArray();
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700258 }
259
260 @Override
261 protected boolean deserialize(final byte[] bytes) {
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700262 try {
263 boolean success = true;
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700264
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700265 SwitchProperty sw = SwitchProperty.parseFrom(bytes);
266 byte[] props = sw.getValue().toByteArray();
Ray Milkey5c9f2db2014-04-09 10:31:21 -0700267 success &= deserializePropertyMap(SWITCH_KRYO.get(), props);
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700268 this.status = STATUS.values()[sw.getStatus()];
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700269
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700270 return success;
271 } catch (InvalidProtocolBufferException e) {
272 log.error("Deserializing Switch: " + this + " failed.", e);
273 return false;
274 }
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700275 }
276
277 @Override
278 public String toString() {
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700279 // TODO output all properties?
280 return "[" + this.getClass().getSimpleName()
281 + " 0x" + Long.toHexString(dpid) + " STATUS:" + status + "]";
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700282 }
283
284}