blob: be0c3c40fa60a5c3c415794dda6c3588e41afc91 [file] [log] [blame]
Jonathan Hart062a2e82014-02-03 09:41:57 -08001package net.onrc.onos.ofcontroller.networkgraph;
2
3import java.util.ArrayList;
4import java.util.List;
5
6import net.onrc.onos.datastore.RCObject;
Yuta HIGUCHIb4335ad2014-02-05 09:56:07 -08007import net.onrc.onos.datastore.RCObject.WriteOp;
Jonathan Hart369875b2014-02-13 10:00:31 -08008import net.onrc.onos.datastore.topology.RCLink;
Jonathan Hart69864df2014-02-13 10:44:12 -08009import net.onrc.onos.datastore.topology.RCPort;
Jonathan Hart062a2e82014-02-03 09:41:57 -080010import net.onrc.onos.datastore.topology.RCSwitch;
11
12import org.slf4j.Logger;
13import org.slf4j.LoggerFactory;
14
15import edu.stanford.ramcloud.JRamCloud.ObjectDoesntExistException;
16import edu.stanford.ramcloud.JRamCloud.ObjectExistsException;
17import edu.stanford.ramcloud.JRamCloud.WrongVersionException;
18
19/**
Yuta HIGUCHIb4335ad2014-02-05 09:56:07 -080020 * The southbound interface to the network graph which allows clients to
Jonathan Hart062a2e82014-02-03 09:41:57 -080021 * mutate the graph. This class will maintain the invariants of the network
22 * graph. The southbound discovery modules will use this interface to update
23 * the network graph as they learn about the state of the network.
24 *
Yuta HIGUCHI181d34d2014-02-05 15:05:46 -080025 * Modification to the Network Map by this module will:
26 * 1. Writes to Cluster-wide DataStore.
27 * 2. Update ONOS instance In-memory Network Map.
28 * 3. Send-out Notification. (TBD)
29 * (XXX: To update other instances In-memory Network Map,
30 * notification should be triggered here.
31 * But if we want to aggregate notification to minimize notification,
32 * It might be better for the caller to trigger notification.)
33 *
Jonathan Hart062a2e82014-02-03 09:41:57 -080034 */
Jonathan Hartfa01c242014-02-11 10:03:03 -080035public class NetworkGraphDatastore {
36 private static final Logger log = LoggerFactory.getLogger(NetworkGraphDatastore.class);
Yuta HIGUCHIb4335ad2014-02-05 09:56:07 -080037
Jonathan Hart062a2e82014-02-03 09:41:57 -080038 private static final int NUM_RETRIES = 10;
Yuta HIGUCHIcb951982014-02-11 13:31:44 -080039
Pavlin Radoslavovdb7dbb22014-02-18 14:45:10 -080040 private final TopologyManager graph;
Yuta HIGUCHIb4335ad2014-02-05 09:56:07 -080041
Pavlin Radoslavovdb7dbb22014-02-18 14:45:10 -080042 public NetworkGraphDatastore(TopologyManager graph) {
Jonathan Hart4b5bbb52014-02-06 10:09:31 -080043 this.graph = graph;
44 }
Yuta HIGUCHIb4335ad2014-02-05 09:56:07 -080045
Pavlin Radoslavovca529072014-02-19 14:07:52 -080046 /**
47 * Add a switch to the database.
48 *
49 * @param sw the switch to add.
50 * @return true on success, otherwise false.
51 */
52 public boolean addSwitch(SwitchEvent sw) {
Jonathan Hart4b5bbb52014-02-06 10:09:31 -080053 log.debug("Adding switch {}", sw);
Yuta HIGUCHIb4335ad2014-02-05 09:56:07 -080054 ArrayList<WriteOp> groupOp = new ArrayList<>();
55
Jonathan Hart062a2e82014-02-03 09:41:57 -080056 RCSwitch rcSwitch = new RCSwitch(sw.getDpid());
57 rcSwitch.setStatus(RCSwitch.STATUS.ACTIVE);
Yuta HIGUCHIb4335ad2014-02-05 09:56:07 -080058
59 // XXX Is ForceCreating Switch on DB OK here?
60 // If ForceCreating, who ever is calling this method needs
61 // to assure that DPID is unique cluster-wide, etc.
62 groupOp.add(WriteOp.ForceCreate(rcSwitch));
63
Jonathan Hart69864df2014-02-13 10:44:12 -080064 //for (Port port : sw.getPorts()) {
65 for (PortEvent portEvent : sw.getPorts()) {
66 RCPort rcPort = new RCPort(sw.getDpid(), portEvent.getNumber());
67 rcPort.setStatus(RCPort.STATUS.ACTIVE);
68 //rcSwitch.addPortId(rcPort.getId());
69
70 groupOp.add(WriteOp.ForceCreate(rcPort));
71 }
Yuta HIGUCHIb4335ad2014-02-05 09:56:07 -080072
Jonathan Hart369875b2014-02-13 10:00:31 -080073 boolean failed = RCObject.multiWrite(groupOp);
Yuta HIGUCHIb4335ad2014-02-05 09:56:07 -080074
Jonathan Hart369875b2014-02-13 10:00:31 -080075 if (failed) {
Jonathan Hart4b5bbb52014-02-06 10:09:31 -080076 log.error("Adding Switch {} and its ports failed.", sw.getDpid());
Jonathan Hart369875b2014-02-13 10:00:31 -080077 for (WriteOp op : groupOp) {
Yuta HIGUCHIb4335ad2014-02-05 09:56:07 -080078 log.debug("Operation:{} for {} - Result:{}", op.getOp(), op.getObject(), op.getStatus() );
79
80 // If we changed the operation from ForceCreate to
81 // Conditional operation (Create/Update) then we should retry here.
82 }
83 }
Pavlin Radoslavovca529072014-02-19 14:07:52 -080084 return (! failed);
Jonathan Hart062a2e82014-02-03 09:41:57 -080085 }
Yuta HIGUCHIb4335ad2014-02-05 09:56:07 -080086
Pavlin Radoslavovca529072014-02-19 14:07:52 -080087 /**
88 * Update a switch as inactive in the database.
89 *
90 * @param sw the switch to update.
91 * @return true on success, otherwise false.
92 */
93 public boolean deactivateSwitch(SwitchEvent sw) {
Jonathan Hart4b5bbb52014-02-06 10:09:31 -080094 log.debug("Deactivating switch {}", sw);
Jonathan Hart062a2e82014-02-03 09:41:57 -080095 RCSwitch rcSwitch = new RCSwitch(sw.getDpid());
Yuta HIGUCHIb4335ad2014-02-05 09:56:07 -080096
Jonathan Hart062a2e82014-02-03 09:41:57 -080097 List<RCObject> objectsToDeactive = new ArrayList<RCObject>();
Yuta HIGUCHIb4335ad2014-02-05 09:56:07 -080098
Jonathan Hart062a2e82014-02-03 09:41:57 -080099 for (int i = 0; i < NUM_RETRIES; i++) {
100 try {
101 rcSwitch.read();
102 rcSwitch.setStatus(RCSwitch.STATUS.INACTIVE);
103 objectsToDeactive.add(rcSwitch);
Yuta HIGUCHIb4335ad2014-02-05 09:56:07 -0800104
Yuta HIGUCHIcb951982014-02-11 13:31:44 -0800105// for (Port p : sw.getPorts()) {
106// RCPort rcPort = new RCPort(sw.getDpid(), (long)p.getNumber());
107// rcPort.read();
108// rcPort.setStatus(RCPort.STATUS.INACTIVE);
109// objectsToDeactive.add(rcPort);
110// }
Jonathan Hart062a2e82014-02-03 09:41:57 -0800111 } catch (ObjectDoesntExistException e) {
112 log.warn("Trying to deactivate an object that doesn't exist", e);
113 // We don't care to much if the object wasn't there, it's
114 // being deactivated anyway
Pavlin Radoslavovca529072014-02-19 14:07:52 -0800115 return true; // Success: no object in the DB
Jonathan Hart062a2e82014-02-03 09:41:57 -0800116 }
Yuta HIGUCHIb4335ad2014-02-05 09:56:07 -0800117
Jonathan Hart062a2e82014-02-03 09:41:57 -0800118 try {
Yuta HIGUCHIb4335ad2014-02-05 09:56:07 -0800119 for (RCObject rcObject : objectsToDeactive) {
Jonathan Hart062a2e82014-02-03 09:41:57 -0800120 rcObject.update();
121 }
Pavlin Radoslavovca529072014-02-19 14:07:52 -0800122 return true; // Success
Jonathan Hart062a2e82014-02-03 09:41:57 -0800123 } catch (ObjectDoesntExistException e) {
Yuta HIGUCHIb4335ad2014-02-05 09:56:07 -0800124 // Unlikely, and we don't care anyway.
Jonathan Hart062a2e82014-02-03 09:41:57 -0800125 // TODO But, this will cause everything else to fail
126 log.warn("Trying to deactivate object that doesn't exist", e);
Pavlin Radoslavovca529072014-02-19 14:07:52 -0800127 return true; // Success: no object in the DB
Jonathan Hart062a2e82014-02-03 09:41:57 -0800128 } catch (WrongVersionException e) {
129 // Need to re-read and retry
130 }
131 }
Pavlin Radoslavovca529072014-02-19 14:07:52 -0800132
133 return false; // Failure
Jonathan Hart062a2e82014-02-03 09:41:57 -0800134 }
Yuta HIGUCHIb4335ad2014-02-05 09:56:07 -0800135
Pavlin Radoslavovca529072014-02-19 14:07:52 -0800136 /**
137 * Add a port to the database.
138 *
139 * @param port the port to add.
140 * @return true on success, otherwise false.
141 */
142 public boolean addPort(PortEvent port) {
Jonathan Hart4b5bbb52014-02-06 10:09:31 -0800143 log.debug("Adding port {}", port);
Jonathan Hart4c263272014-02-13 17:41:05 -0800144 //RCSwitch rcSwitch = new RCSwitch(sw.getDpid());
145
146 //try {
147 //rcSwitch.read();
148 //} catch (ObjectDoesntExistException e) {
149 //log.warn("Add port failed because switch {} doesn't exist", sw.getDpid(), e);
Pavlin Radoslavovca529072014-02-19 14:07:52 -0800150 //return false;
Jonathan Hart4c263272014-02-13 17:41:05 -0800151 //}
152
153 RCPort rcPort = new RCPort(port.getDpid(), port.getNumber());
154 rcPort.setStatus(RCPort.STATUS.ACTIVE);
155 // TODO add description into RCPort
156 //rcPort.setDescription(port.getDescription());
157 //rcSwitch.addPortId(rcPort.getId());
158
Pavlin Radoslavovca529072014-02-19 14:07:52 -0800159 boolean success = writeObject(rcPort);
160 // success &= writeObject(rcSwitch);
161 return success;
Jonathan Hart062a2e82014-02-03 09:41:57 -0800162 }
Yuta HIGUCHIb4335ad2014-02-05 09:56:07 -0800163
Pavlin Radoslavovca529072014-02-19 14:07:52 -0800164 /**
165 * Update a port as inactive in the database.
166 *
167 * @param port the port to update.
168 * @return true on success, otherwise false.
169 */
170 public boolean deactivatePort(PortEvent port) {
Jonathan Hart4b5bbb52014-02-06 10:09:31 -0800171 log.debug("Deactivating port {}", port);
Jonathan Hart4c263272014-02-13 17:41:05 -0800172 RCPort rcPort = new RCPort(port.getDpid(), port.getNumber());
173
174 for (int i = 0; i < NUM_RETRIES; i++) {
175 try {
Pavlin Radoslavovca529072014-02-19 14:07:52 -0800176 rcPort.read();
Jonathan Hart4c263272014-02-13 17:41:05 -0800177 } catch (ObjectDoesntExistException e) {
178 // oh well, we were deactivating anyway
179 log.warn("Trying to deactivate a port that doesn't exist: {}", port);
Pavlin Radoslavovca529072014-02-19 14:07:52 -0800180 return true; // Success: no object in the DB
Jonathan Hart4c263272014-02-13 17:41:05 -0800181 }
182
183 rcPort.setStatus(RCPort.STATUS.INACTIVE);
184
185 try {
186 rcPort.update();
Pavlin Radoslavovca529072014-02-19 14:07:52 -0800187 return true; // Success
Jonathan Hart4c263272014-02-13 17:41:05 -0800188 } catch (ObjectDoesntExistException | WrongVersionException e) {
189 // retry
190 }
191 }
Pavlin Radoslavovca529072014-02-19 14:07:52 -0800192
193 return false; // Failure
Jonathan Hart062a2e82014-02-03 09:41:57 -0800194 }
Yuta HIGUCHIb4335ad2014-02-05 09:56:07 -0800195
Pavlin Radoslavovca529072014-02-19 14:07:52 -0800196 /**
197 * Add a link to the database.
198 *
199 * @param link the link to add.
200 * @return true on success, otherwise false.
201 */
202 public boolean addLink(LinkEvent link) {
203 log.debug("Adding link {}", link);
Yuta HIGUCHI0a4bd192014-02-17 13:52:34 -0800204
Pavlin Radoslavovca529072014-02-19 14:07:52 -0800205 RCLink rcLink = new RCLink(link.getSrc().getDpid(),
206 link.getSrc().getNumber(),
207 link.getDst().getDpid(),
208 link.getDst().getNumber());
Jonathan Hart369875b2014-02-13 10:00:31 -0800209
Yuta HIGUCHIef479672014-02-19 09:14:39 -0800210 // XXX This method is called only by discovery,
211 // which means what we are trying to write currently is the truth
212 // so we can force write here
Pavlin Radoslavovca529072014-02-19 14:07:52 -0800213 //
214 // TODO: We need to check for errors
Yuta HIGUCHIef479672014-02-19 09:14:39 -0800215 rcLink.setStatus(RCLink.STATUS.ACTIVE);
216 rcLink.forceCreate();
Pavlin Radoslavovca529072014-02-19 14:07:52 -0800217
218 return true; // Success
Jonathan Hart062a2e82014-02-03 09:41:57 -0800219 }
Yuta HIGUCHIb4335ad2014-02-05 09:56:07 -0800220
Pavlin Radoslavovca529072014-02-19 14:07:52 -0800221 /**
222 * Remove a link from the database.
223 *
224 * @param link the link to remove.
225 * @return true on success, otherwise false.
226 */
227 public boolean removeLink(LinkEvent link) {
228 log.debug("Removing link {}", link);
229 RCLink rcLink = new RCLink(link.getSrc().getDpid(),
230 link.getSrc().getNumber(),
231 link.getDst().getDpid(),
232 link.getDst().getNumber());
Jonathan Hart369875b2014-02-13 10:00:31 -0800233
234 //RCPort rcSrcPort = new RCPort(link.getSourceSwitchDpid(), (long)link.getSourcePortNumber());
235 //RCPort rcDstPort = new RCPort(link.getDestinationSwitchDpid(), (long)link.getDestinationPortNumber());
236
237 for (int i = 0; i < NUM_RETRIES; i++) {
238 try {
239 //rcSrcPort.read();
240 //rcDstPort.read();
241 rcLink.read();
242 } catch (ObjectDoesntExistException e) {
Yuta HIGUCHI0a4bd192014-02-17 13:52:34 -0800243 // XXX Note: This error might be harmless, if triggered by out-dated remove Link event
Pavlin Radoslavovca529072014-02-19 14:07:52 -0800244 log.error("Remove link failed {}", link, e);
245 return true; // Success: no object in the DB
Jonathan Hart369875b2014-02-13 10:00:31 -0800246 }
247
248 //rcSrcPort.removeLinkId(rcLink.getId());
249 //rcDstPort.removeLinkId(rcLink.getId());
250
251 try {
252 //rcSrcPort.update();
253 //rcDstPort.update();
254 rcLink.delete();
Pavlin Radoslavovca529072014-02-19 14:07:52 -0800255 return true; // Success
Jonathan Hart369875b2014-02-13 10:00:31 -0800256 } catch (ObjectDoesntExistException e) {
Pavlin Radoslavovca529072014-02-19 14:07:52 -0800257 log.error("Remove link failed {}", link, e);
258 return true; // Success: no object in the DB
Jonathan Hart369875b2014-02-13 10:00:31 -0800259 } catch (WrongVersionException e) {
260 // retry
261 }
262 }
Pavlin Radoslavovca529072014-02-19 14:07:52 -0800263
264 return false; // Failure
Jonathan Hart062a2e82014-02-03 09:41:57 -0800265 }
Yuta HIGUCHIb4335ad2014-02-05 09:56:07 -0800266
Pavlin Radoslavovca529072014-02-19 14:07:52 -0800267 /**
268 * Add a device to the database.
269 *
270 * @param device the device to add.
271 * @return true on success, otherwise false.
272 */
273 public boolean updateDevice(DeviceEvent device) {
Jonathan Hart062a2e82014-02-03 09:41:57 -0800274 // TODO implement
Pavlin Radoslavovca529072014-02-19 14:07:52 -0800275 return false; // Failure: not implemented yet
Jonathan Hart062a2e82014-02-03 09:41:57 -0800276 }
Yuta HIGUCHIb4335ad2014-02-05 09:56:07 -0800277
Pavlin Radoslavovca529072014-02-19 14:07:52 -0800278 /**
279 * Remove a device from the database.
280 *
281 * @param device the device to remove.
282 * @return true on success, otherwise false.
283 */
284 public boolean removeDevice(DeviceEvent device) {
Jonathan Hart062a2e82014-02-03 09:41:57 -0800285 // TODO implement
Pavlin Radoslavovca529072014-02-19 14:07:52 -0800286 return false; // Failure: not implemented yet
Jonathan Hart062a2e82014-02-03 09:41:57 -0800287 }
Yuta HIGUCHIb4335ad2014-02-05 09:56:07 -0800288
Pavlin Radoslavovca529072014-02-19 14:07:52 -0800289 /**
290 * Write an object to the database.
291 *
292 * @param object the object to write.
293 * @return true on success, otherwise false.
294 */
295 private boolean writeObject(RCObject object) {
Jonathan Hart062a2e82014-02-03 09:41:57 -0800296 for (int i = 0; i < NUM_RETRIES; i++) {
297 try {
298 object.create();
299 } catch (ObjectExistsException e) {
300 try {
301 object.read();
302 } catch (ObjectDoesntExistException e1) {
303 // TODO Auto-generated catch block
304 log.error(" ", e);
Pavlin Radoslavovca529072014-02-19 14:07:52 -0800305 return false; // Failure
Jonathan Hart062a2e82014-02-03 09:41:57 -0800306 }
307 }
Yuta HIGUCHIb4335ad2014-02-05 09:56:07 -0800308
Jonathan Hart062a2e82014-02-03 09:41:57 -0800309 try {
310 // TODO check API for writing without caring what's there
311 object.update();
Pavlin Radoslavovca529072014-02-19 14:07:52 -0800312 return true; // Success
Jonathan Hart062a2e82014-02-03 09:41:57 -0800313 } catch (ObjectDoesntExistException | WrongVersionException e) {
314 log.debug(" ", e);
315 // re-read and retry
316 }
317 }
Pavlin Radoslavovca529072014-02-19 14:07:52 -0800318
319 return false; // Failure
Jonathan Hart062a2e82014-02-03 09:41:57 -0800320 }
321}