blob: e2bdb775119528115d88aef81893b478a20967a7 [file] [log] [blame]
Jonathan Hart472062d2014-04-03 10:56:48 -07001package net.onrc.onos.core.topology;
Jonathan Hart4b5bbb52014-02-06 10:09:31 -08002
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -07003import java.nio.ByteBuffer;
Jonathan Hart4b5bbb52014-02-06 10:09:31 -08004import java.util.ArrayList;
5import java.util.Collection;
Pavlin Radoslavov24409672014-08-20 16:45:11 -07006import java.util.HashMap;
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -07007import java.util.LinkedList;
Jonathan Hart369875b2014-02-13 10:00:31 -08008import java.util.List;
Jonathan Hart4b5bbb52014-02-06 10:09:31 -08009import java.util.Map;
Pavlin Radoslavov24409672014-08-20 16:45:11 -070010import java.util.concurrent.BlockingQueue;
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -070011import java.util.concurrent.ConcurrentHashMap;
12import java.util.concurrent.ConcurrentMap;
Pavlin Radoslavov24409672014-08-20 16:45:11 -070013import java.util.concurrent.LinkedBlockingQueue;
Jonathan Hart369875b2014-02-13 10:00:31 -080014import java.util.concurrent.TimeUnit;
Jonathan Hart4b5bbb52014-02-06 10:09:31 -080015
16import net.floodlightcontroller.core.IFloodlightProviderService;
Pavlin Radoslavov695f8952014-07-23 16:57:01 -070017import net.floodlightcontroller.core.IFloodlightProviderService.Role;
Jonathan Hart4b5bbb52014-02-06 10:09:31 -080018import net.floodlightcontroller.core.IOFSwitch;
Brian O'Connorc67f9fa2014-08-07 18:17:46 -070019import net.floodlightcontroller.core.IOFSwitch.PortChangeType;
20import net.floodlightcontroller.core.IOFSwitchListener;
Jonathan Hart4b5bbb52014-02-06 10:09:31 -080021import net.floodlightcontroller.core.module.FloodlightModuleContext;
22import net.floodlightcontroller.core.module.FloodlightModuleException;
23import net.floodlightcontroller.core.module.IFloodlightModule;
24import net.floodlightcontroller.core.module.IFloodlightService;
Jonathan Hart369875b2014-02-13 10:00:31 -080025import net.floodlightcontroller.core.util.SingletonTask;
26import net.floodlightcontroller.threadpool.IThreadPoolService;
Pavlin Radoslavov24409672014-08-20 16:45:11 -070027
28import net.onrc.onos.api.batchoperation.BatchOperationEntry;
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -070029import net.onrc.onos.core.datagrid.IDatagridService;
30import net.onrc.onos.core.datagrid.IEventChannel;
Jonathan Hart03102132014-07-01 23:22:04 -070031import net.onrc.onos.core.hostmanager.Host;
32import net.onrc.onos.core.hostmanager.IHostListener;
33import net.onrc.onos.core.hostmanager.IHostService;
Jonathan Hart23701d12014-04-03 10:45:48 -070034import net.onrc.onos.core.linkdiscovery.ILinkDiscoveryListener;
35import net.onrc.onos.core.linkdiscovery.ILinkDiscoveryService;
Jonathan Hart284e70f2014-07-05 12:32:51 -070036import net.onrc.onos.core.linkdiscovery.Link;
Jonathan Hartdeda0ba2014-04-03 11:14:12 -070037import net.onrc.onos.core.registry.IControllerRegistryService;
Jonathan Hartdeda0ba2014-04-03 11:14:12 -070038import net.onrc.onos.core.registry.IControllerRegistryService.ControlChangeCallback;
Jonathan Harta99ec672014-04-03 11:30:34 -070039import net.onrc.onos.core.registry.RegistryException;
Yuta HIGUCHI5bbbaca2014-06-09 16:39:08 -070040import net.onrc.onos.core.util.Dpid;
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -070041import net.onrc.onos.core.util.OnosInstanceId;
Yuta HIGUCHIa507baf2014-08-22 13:42:40 -070042import net.onrc.onos.core.util.PortNumberUtils;
Yuta HIGUCHI5c8cbeb2014-06-27 11:13:48 -070043import net.onrc.onos.core.util.SwitchPort;
Jonathan Hart4b5bbb52014-02-06 10:09:31 -080044
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -070045import org.apache.commons.lang3.concurrent.ConcurrentUtils;
Brian O'Connorc67f9fa2014-08-07 18:17:46 -070046import org.projectfloodlight.openflow.protocol.OFPortDesc;
47import org.projectfloodlight.openflow.util.HexString;
Toshio Koide2f570c12014-02-06 16:55:32 -080048import org.slf4j.Logger;
49import org.slf4j.LoggerFactory;
Jonathan Hart4b5bbb52014-02-06 10:09:31 -080050
Jonathan Hart88770672014-04-02 18:08:30 -070051/**
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -070052 * Class for publishing topology-related events.
53 *
54 * The events are received from the discovery modules, reformatted and
55 * published to the other ONOS instances.
56 *
57 * TODO: Add a synchronization mechanism when publishing the events to
58 * preserve the ordering and to avoid mismatch in the local "published" state,
59 * because each of the caller (the discovery modules) might be running
60 * on a different thread.
Jonathan Hart88770672014-04-02 18:08:30 -070061 */
Brian O'Connorc67f9fa2014-08-07 18:17:46 -070062public class TopologyPublisher implements IOFSwitchListener,
Ray Milkey269ffb92014-04-03 14:43:30 -070063 ILinkDiscoveryListener,
64 IFloodlightModule,
Pavlin Radoslavov24409672014-08-20 16:45:11 -070065 IHostListener,
66 ITopologyPublisherService {
Jonathan Hart88770672014-04-02 18:08:30 -070067 private static final Logger log =
Jonathan Harte37e4e22014-05-13 19:12:02 -070068 LoggerFactory.getLogger(TopologyPublisher.class);
Yuta HIGUCHIcb951982014-02-11 13:31:44 -080069
Jonathan Hart88770672014-04-02 18:08:30 -070070 private IFloodlightProviderService floodlightProvider;
71 private ILinkDiscoveryService linkDiscovery;
72 private IControllerRegistryService registryService;
Jonathan Harte37e4e22014-05-13 19:12:02 -070073 private ITopologyService topologyService;
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -070074 private IDatagridService datagridService;
Toshio Koide2f570c12014-02-06 16:55:32 -080075
Jonathan Hart03102132014-07-01 23:22:04 -070076 private IHostService hostService;
Jonathan Hartb3e1b052014-04-02 16:01:12 -070077
Yuta HIGUCHId92b10c2014-08-25 09:30:28 -070078 private MutableTopology mutableTopology;
Jonathan Hartb3e1b052014-04-02 16:01:12 -070079
Jonathan Hart88770672014-04-02 18:08:30 -070080 private static final String ENABLE_CLEANUP_PROPERTY = "EnableCleanup";
81 private boolean cleanupEnabled = true;
82 private static final int CLEANUP_TASK_INTERVAL = 60; // in seconds
83 private SingletonTask cleanupTask;
Pavlin Radoslavov24409672014-08-20 16:45:11 -070084 private DelayedOperationsHandler delayedOperationsHandler =
85 new DelayedOperationsHandler();
Toshio Koide2f570c12014-02-06 16:55:32 -080086
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -070087 private IEventChannel<byte[], TopologyEvent> eventChannel;
88
89 //
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -070090 // Local state for keeping track of locally published events so we can
91 // cleanup properly when an entry is removed.
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -070092 //
93 // We keep all Port, (incoming) Link and Host events per Switch DPID:
94 // - If a switch goes down, we remove all corresponding Port, Link and
95 // Host events.
96 // - If a port on a switch goes down, we remove all corresponding Link
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -070097 // and Host events attached to this port.
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -070098 //
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -070099 // TODO: What to do if the Mastership changes?
100 // - Cleanup state from publishedFoo maps, but do not send REMOVE events?
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700101 //
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700102 private ConcurrentMap<Dpid, MastershipEvent> publishedMastershipEvents =
103 new ConcurrentHashMap<>();
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700104 private ConcurrentMap<Dpid, SwitchData> publishedSwitchDataEntries =
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700105 new ConcurrentHashMap<>();
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700106 private ConcurrentMap<Dpid, ConcurrentMap<ByteBuffer, PortData>>
107 publishedPortDataEntries = new ConcurrentHashMap<>();
108 private ConcurrentMap<Dpid, ConcurrentMap<ByteBuffer, LinkData>>
109 publishedLinkDataEntries = new ConcurrentHashMap<>();
110 private ConcurrentMap<Dpid, ConcurrentMap<ByteBuffer, HostData>>
111 publishedHostDataEntries = new ConcurrentHashMap<>();
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700112
Pavlin Radoslavov24409672014-08-20 16:45:11 -0700113 private BlockingQueue<TopologyBatchOperation> delayedOperations =
114 new LinkedBlockingQueue<>();
115
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700116
Jonathan Hart369875b2014-02-13 10:00:31 -0800117 /**
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700118 * Gets the ONOS Instance ID.
119 *
120 * @return the ONOS Instance ID.
121 */
122 private OnosInstanceId getOnosInstanceId() {
123 return registryService.getOnosInstanceId();
124 }
125
126 /**
127 * Cleanup old switches from the topology. Old switches are those which
128 * have no controller in the registry.
129 *
130 * TODO: The overall switch cleanup mechanism needs refactoring/redesign.
Jonathan Hart369875b2014-02-13 10:00:31 -0800131 */
132 private class SwitchCleanup implements ControlChangeCallback, Runnable {
133 @Override
134 public void run() {
135 String old = Thread.currentThread().getName();
136 Thread.currentThread().setName("SwitchCleanup@" + old);
Jonathan Hartb3e1b052014-04-02 16:01:12 -0700137
Jonathan Hart369875b2014-02-13 10:00:31 -0800138 try {
Jonathan Hart88770672014-04-02 18:08:30 -0700139 if (log.isTraceEnabled()) {
140 log.trace("Running cleanup thread");
141 }
Jonathan Hart369875b2014-02-13 10:00:31 -0800142 switchCleanup();
Jonathan Hart369875b2014-02-13 10:00:31 -0800143 } finally {
144 cleanupTask.reschedule(CLEANUP_TASK_INTERVAL,
Jonathan Hart88770672014-04-02 18:08:30 -0700145 TimeUnit.SECONDS);
Jonathan Hart369875b2014-02-13 10:00:31 -0800146 Thread.currentThread().setName(old);
147 }
148 }
Jonathan Hartb3e1b052014-04-02 16:01:12 -0700149
Jonathan Hart88770672014-04-02 18:08:30 -0700150 /**
151 * First half of the switch cleanup operation. This method will attempt
152 * to get control of any switch it sees without a controller via the
153 * registry.
154 */
Jonathan Hart369875b2014-02-13 10:00:31 -0800155 private void switchCleanup() {
Yuta HIGUCHId92b10c2014-08-25 09:30:28 -0700156 Iterable<Switch> switches = mutableTopology.getSwitches();
Jonathan Hart369875b2014-02-13 10:00:31 -0800157
Jonathan Hart88770672014-04-02 18:08:30 -0700158 if (log.isTraceEnabled()) {
159 log.trace("Checking for inactive switches");
160 }
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700161 // For each switch check if a controller exists in controller
162 // registry
Ray Milkey269ffb92014-04-03 14:43:30 -0700163 for (Switch sw : switches) {
Praseed Balakrishnane82adc62014-08-04 10:59:24 -0700164 // FIXME How to handle case where Switch has never been
165 // registered to ZK
166 if (sw.getConfigState() == ConfigState.CONFIGURED) {
167 continue;
168 }
Jonathan Hart88770672014-04-02 18:08:30 -0700169 try {
170 String controller =
Yuta HIGUCHI8f3dfa32014-06-25 00:14:25 -0700171 registryService.getControllerForSwitch(sw.getDpid().value());
Jonathan Hart88770672014-04-02 18:08:30 -0700172 if (controller == null) {
173 log.debug("Requesting control to set switch {} INACTIVE",
Yuta HIGUCHI8f3dfa32014-06-25 00:14:25 -0700174 sw.getDpid());
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700175 registryService.requestControl(sw.getDpid().value(),
176 this);
Jonathan Hart88770672014-04-02 18:08:30 -0700177 }
178 } catch (RegistryException e) {
179 log.error("Caught RegistryException in cleanup thread", e);
180 }
181 }
Jonathan Hart369875b2014-02-13 10:00:31 -0800182 }
183
Jonathan Hart88770672014-04-02 18:08:30 -0700184 /**
185 * Second half of the switch cleanup operation. If the registry grants
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700186 * control of a switch, we can be sure no other instance is writing
187 * this switch to the topology, so we can remove it now.
188 *
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700189 * @param dpid the dpid of the switch we requested control for
Jonathan Hart88770672014-04-02 18:08:30 -0700190 * @param hasControl whether we got control or not
191 */
192 @Override
193 public void controlChanged(long dpid, boolean hasControl) {
194 if (hasControl) {
195 log.debug("Got control to set switch {} INACTIVE",
196 HexString.toHexString(dpid));
Jonathan Harte02cf542014-04-02 16:24:44 -0700197
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700198 SwitchData switchData = new SwitchData(new Dpid(dpid));
199 publishRemoveSwitchEvent(switchData);
Jonathan Hart88770672014-04-02 18:08:30 -0700200 registryService.releaseControl(dpid);
201 }
202 }
Jonathan Hart369875b2014-02-13 10:00:31 -0800203 }
Jonathan Hart4b5bbb52014-02-06 10:09:31 -0800204
Pavlin Radoslavov24409672014-08-20 16:45:11 -0700205 /**
206 * A class to deal with Topology Operations that couldn't be pushed
207 * to the Global Log writer, because they need to be delayed.
208 * For example, a link cannot be pushed before the switches on both
209 * ends are in the Global Log.
210 *
211 * TODO: This is an ugly hack that should go away: right now we have to
212 * keep trying periodically.
213 * TODO: Currently, we retry only ADD Link Events, everything else
214 * is thrown away.
215 */
216 private class DelayedOperationsHandler extends Thread {
217 private static final long RETRY_INTERVAL_MS = 10; // 10ms
218
219 @Override
220 public void run() {
221 List<TopologyBatchOperation> operations = new LinkedList<>();
222
223 this.setName("TopologyPublisher.DelayedOperationsHandler " +
224 this.getId());
225 //
226 // The main loop
227 //
228 while (true) {
229 try {
230 //
231 // Block-waiting for an operation to be added, sleep
232 // and try to publish it again.
233 //
234 TopologyBatchOperation firstTbo = delayedOperations.take();
235 Thread.sleep(RETRY_INTERVAL_MS);
236 operations.add(firstTbo);
237 delayedOperations.drainTo(operations);
238
239 // Retry only the appropriate operations
240 for (TopologyBatchOperation tbo : operations) {
241 for (BatchOperationEntry<
242 TopologyBatchOperation.Operator,
243 TopologyEvent> boe : tbo.getOperations()) {
244 TopologyBatchOperation.Operator oper =
245 boe.getOperator();
246 switch (oper) {
247 case ADD:
248 TopologyEvent topologyEvent = boe.getTarget();
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700249 LinkData linkData =
250 topologyEvent.getLinkData();
Pavlin Radoslavov24409672014-08-20 16:45:11 -0700251 //
252 // Test whether the Link Event still can be
253 // published.
254 // TODO: The implementation below has a bug:
255 // If it happens that the same Link Event was
256 // removed in the middle of checking, we might
257 // incorrectly publish it again from here.
258 //
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700259 if (linkData == null) {
Pavlin Radoslavov24409672014-08-20 16:45:11 -0700260 break;
261 }
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700262 ConcurrentMap<ByteBuffer, LinkData>
263 linkDataEntries = publishedLinkDataEntries.get(
264 linkData.getDst().getDpid());
265 if (linkDataEntries == null) {
Pavlin Radoslavov24409672014-08-20 16:45:11 -0700266 break;
267 }
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700268 if (linkDataEntries.get(linkData.getIDasByteBuffer()) == null) {
Pavlin Radoslavov24409672014-08-20 16:45:11 -0700269 break;
270 }
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700271 publishAddLinkEvent(linkData);
Pavlin Radoslavov24409672014-08-20 16:45:11 -0700272 break;
273 case REMOVE:
274 break;
275 default:
276 log.error("Unknown Topology Batch Operation {}", oper);
277 break;
278 }
279 }
280 }
281 } catch (InterruptedException exception) {
282 log.debug("Exception processing delayed operations: ",
283 exception);
284 }
285 }
286 }
287 }
288
Jonathan Hart88770672014-04-02 18:08:30 -0700289 @Override
Jonathan Hart284e70f2014-07-05 12:32:51 -0700290 public void linkAdded(Link link) {
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700291 LinkData linkData = new LinkData(
Jonathan Hart284e70f2014-07-05 12:32:51 -0700292 new SwitchPort(link.getSrc(), link.getSrcPort()),
293 new SwitchPort(link.getDst(), link.getDstPort()));
294
Yuta HIGUCHIbf0a8712014-06-30 18:59:46 -0700295 // FIXME should be merging, with existing attrs, etc..
296 // TODO define attr name as constant somewhere.
297 // TODO populate appropriate attributes.
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700298 linkData.createStringAttribute(TopologyElement.TYPE,
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700299 TopologyElement.TYPE_PACKET_LAYER);
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700300 linkData.createStringAttribute(TopologyElement.ELEMENT_CONFIG_STATE,
Praseed Balakrishnan2aa6c0b2014-07-17 11:42:05 -0700301 ConfigState.NOT_CONFIGURED.toString());
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700302 linkData.createStringAttribute(TopologyElement.ELEMENT_ADMIN_STATUS,
Praseed Balakrishnan2aa6c0b2014-07-17 11:42:05 -0700303 AdminStatus.ACTIVE.toString());
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700304 linkData.freeze();
Jonathan Hartb3e1b052014-04-02 16:01:12 -0700305
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700306 publishAddLinkEvent(linkData);
Jonathan Hart284e70f2014-07-05 12:32:51 -0700307 }
308
309 @Override
310 public void linkRemoved(Link link) {
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700311 LinkData linkData = new LinkData(
Jonathan Hart284e70f2014-07-05 12:32:51 -0700312 new SwitchPort(link.getSrc(), link.getSrcPort()),
313 new SwitchPort(link.getDst(), link.getDstPort()));
314
315 // FIXME should be merging, with existing attrs, etc..
316 // TODO define attr name as constant somewhere.
317 // TODO populate appropriate attributes.
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700318 linkData.createStringAttribute(TopologyElement.TYPE,
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700319 TopologyElement.TYPE_PACKET_LAYER);
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700320 linkData.freeze();
Jonathan Hart284e70f2014-07-05 12:32:51 -0700321
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700322 publishRemoveLinkEvent(linkData);
Jonathan Hart88770672014-04-02 18:08:30 -0700323 }
Jonathan Hart4b5bbb52014-02-06 10:09:31 -0800324
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700325 /* *****************
326 * IOFSwitchListener
327 * *****************/
328
Jonathan Hart88770672014-04-02 18:08:30 -0700329 @Override
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700330 public void switchActivatedMaster(long swId) {
331 IOFSwitch sw = floodlightProvider.getSwitch(swId);
332 final Dpid dpid = new Dpid(swId);
333 if (sw == null) {
334 log.warn("Added switch not available {} ", dpid);
335 return;
336 }
337
338 controllerRoleChanged(dpid, Role.MASTER);
339
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700340 SwitchData switchData = new SwitchData(dpid);
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700341 // FIXME should be merging, with existing attrs, etc..
342 // TODO define attr name as constant somewhere.
343 // TODO populate appropriate attributes.
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700344 switchData.createStringAttribute(TopologyElement.TYPE,
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700345 TopologyElement.TYPE_PACKET_LAYER);
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700346 switchData.createStringAttribute("ConnectedSince",
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700347 sw.getConnectedSince().toString());
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700348 switchData.createStringAttribute(TopologyElement.ELEMENT_CONFIG_STATE,
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700349 ConfigState.NOT_CONFIGURED.toString());
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700350 switchData.createStringAttribute(TopologyElement.ELEMENT_ADMIN_STATUS,
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700351 AdminStatus.ACTIVE.toString());
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700352 switchData.freeze();
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700353 // The Port events
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700354 List<PortData> portDataEntries = new ArrayList<PortData>();
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700355 for (OFPortDesc port : sw.getPorts()) {
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700356 PortData portData = new PortData(dpid,
Yuta HIGUCHIa507baf2014-08-22 13:42:40 -0700357 PortNumberUtils.openFlow(port));
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700358 // FIXME should be merging, with existing attrs, etc..
359 // TODO define attr name as constant somewhere.
360 // TODO populate appropriate attributes.
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700361 portData.createStringAttribute("name", port.getName());
362 portData.createStringAttribute(TopologyElement.TYPE,
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700363 TopologyElement.TYPE_PACKET_LAYER);
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700364 portData.createStringAttribute(TopologyElement.ELEMENT_CONFIG_STATE,
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700365 ConfigState.NOT_CONFIGURED.toString());
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700366 portData.createStringAttribute(TopologyElement.ELEMENT_ADMIN_STATUS,
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700367 AdminStatus.ACTIVE.toString());
368
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700369 portData.freeze();
370 portDataEntries.add(portData);
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700371 }
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700372 publishAddSwitchEvent(switchData, portDataEntries);
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700373 }
374
375 @Override
376 public void switchActivatedEqual(long swId) {
377 final Dpid dpid = new Dpid(swId);
378 controllerRoleChanged(dpid, Role.EQUAL);
379 }
380
381 @Override
382 public void switchMasterToEqual(long swId) {
383 final Dpid dpid = new Dpid(swId);
384 controllerRoleChanged(dpid, Role.EQUAL);
385 }
386
387 @Override
388 public void switchEqualToMaster(long swId) {
389 // for now treat as switchActivatedMaster
390 switchActivatedMaster(swId);
391 }
392
393 @Override
394 public void switchDisconnected(long swId) {
395 final Dpid dpid = new Dpid(swId);
396
397 log.debug("Local switch disconnected: dpid = {} role = {}", dpid);
398
399 Role role = Role.SLAVE; // TODO: Should be Role.UNKNOWN
400
401 MastershipEvent mastershipEvent =
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700402 new MastershipEvent(dpid, getOnosInstanceId(), role);
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700403 // FIXME should be merging, with existing attrs, etc..
404 // TODO define attr name as constant somewhere.
405 // TODO populate appropriate attributes.
406 mastershipEvent.createStringAttribute(TopologyElement.TYPE,
407 TopologyElement.TYPE_ALL_LAYERS);
408 mastershipEvent.freeze();
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700409 publishRemoveSwitchMastershipEvent(mastershipEvent);
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700410 }
411
412 @Override
413 public void switchPortChanged(long swId, OFPortDesc port,
414 PortChangeType changeType) {
415 switch (changeType) {
416 case ADD:
417 switchPortAdded(swId, port);
418 break;
419 case DELETE:
420 switchPortRemoved(swId, port);
421 break;
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700422 case UP:
Pavlin Radoslavov7946c612014-08-13 15:06:00 -0700423 // NOTE: Currently, we treat Port UP/DOWN same as Port ADD/DELETE
424 switchPortAdded(swId, port);
425 break;
426 case DOWN:
427 // NOTE: Currently, we treat Port UP/DOWN same as Port ADD/DELETE
428 switchPortRemoved(swId, port);
429 break;
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700430 case OTHER_UPDATE:
431 default:
432 // XXX S what is the right set of port change handlers?
433 log.debug("Topology publisher does not handle these port updates: {}",
434 changeType);
435 }
436 }
437
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700438 /**
439 * Prepares an event for adding a port on a switch.
440 *
441 * @param switchId the switch ID (DPID)
442 * @param port the port to add
443 */
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700444 private void switchPortAdded(long switchId, OFPortDesc port) {
Yuta HIGUCHIbf0a8712014-06-30 18:59:46 -0700445 final Dpid dpid = new Dpid(switchId);
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700446 final PortData portData = new PortData(dpid,
Yuta HIGUCHIa507baf2014-08-22 13:42:40 -0700447 PortNumberUtils.openFlow(port));
Yuta HIGUCHIbf0a8712014-06-30 18:59:46 -0700448 // FIXME should be merging, with existing attrs, etc..
449 // TODO define attr name as constant somewhere.
450 // TODO populate appropriate attributes.
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700451 portData.createStringAttribute(TopologyElement.TYPE,
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700452 TopologyElement.TYPE_PACKET_LAYER);
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700453 portData.createStringAttribute("name", port.getName());
454 portData.freeze();
Yuta HIGUCHIbf0a8712014-06-30 18:59:46 -0700455
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700456 publishAddPortEvent(portData);
Jonathan Hart88770672014-04-02 18:08:30 -0700457 }
Jonathan Hart4b5bbb52014-02-06 10:09:31 -0800458
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700459 /**
460 * Prepares an event for removing a port on a switch.
461 *
462 * @param switchId the switch ID (DPID)
463 * @param port the port to remove
464 */
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700465 private void switchPortRemoved(long switchId, OFPortDesc port) {
Yuta HIGUCHIe2a4e172014-07-03 10:50:39 -0700466 final Dpid dpid = new Dpid(switchId);
Yuta HIGUCHI5bbbaca2014-06-09 16:39:08 -0700467
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700468 final PortData portData = new PortData(dpid,
Yuta HIGUCHIa507baf2014-08-22 13:42:40 -0700469 PortNumberUtils.openFlow(port));
Yuta HIGUCHI1222ac52014-07-09 16:50:28 -0700470 // FIXME should be merging, with existing attrs, etc..
471 // TODO define attr name as constant somewhere.
472 // TODO populate appropriate attributes.
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700473 portData.createStringAttribute(TopologyElement.TYPE,
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700474 TopologyElement.TYPE_PACKET_LAYER);
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700475 portData.createStringAttribute("name", port.getName());
476 portData.freeze();
Yuta HIGUCHI1222ac52014-07-09 16:50:28 -0700477
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700478 publishRemovePortEvent(portData);
Jonathan Hart88770672014-04-02 18:08:30 -0700479 }
Jonathan Hart4b5bbb52014-02-06 10:09:31 -0800480
Jonathan Hart88770672014-04-02 18:08:30 -0700481 @Override
Jonathan Hart88770672014-04-02 18:08:30 -0700482 public String getName() {
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700483 return "topologyPublisher";
Jonathan Hart88770672014-04-02 18:08:30 -0700484 }
Jonathan Hart4b5bbb52014-02-06 10:09:31 -0800485
Jonathan Hart88770672014-04-02 18:08:30 -0700486 /* *****************
487 * IFloodlightModule
488 * *****************/
Toshio Koide2f570c12014-02-06 16:55:32 -0800489
Jonathan Hart88770672014-04-02 18:08:30 -0700490 @Override
491 public Collection<Class<? extends IFloodlightService>> getModuleServices() {
Pavlin Radoslavov24409672014-08-20 16:45:11 -0700492 List<Class<? extends IFloodlightService>> services =
493 new ArrayList<Class<? extends IFloodlightService>>();
494 services.add(ITopologyPublisherService.class);
495 return services;
Jonathan Hart88770672014-04-02 18:08:30 -0700496 }
Jonathan Hart4b5bbb52014-02-06 10:09:31 -0800497
Jonathan Hart88770672014-04-02 18:08:30 -0700498 @Override
499 public Map<Class<? extends IFloodlightService>, IFloodlightService>
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700500 getServiceImpls() {
Pavlin Radoslavov24409672014-08-20 16:45:11 -0700501 Map<Class<? extends IFloodlightService>, IFloodlightService> impls =
502 new HashMap<Class<? extends IFloodlightService>, IFloodlightService>();
503 impls.put(ITopologyPublisherService.class, this);
504 return impls;
Jonathan Hart88770672014-04-02 18:08:30 -0700505 }
Jonathan Hart4b5bbb52014-02-06 10:09:31 -0800506
Jonathan Hart88770672014-04-02 18:08:30 -0700507 @Override
508 public Collection<Class<? extends IFloodlightService>>
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700509 getModuleDependencies() {
Jonathan Hart88770672014-04-02 18:08:30 -0700510 Collection<Class<? extends IFloodlightService>> l =
511 new ArrayList<Class<? extends IFloodlightService>>();
Jonathan Hart4b5bbb52014-02-06 10:09:31 -0800512 l.add(IFloodlightProviderService.class);
513 l.add(ILinkDiscoveryService.class);
Jonathan Hart369875b2014-02-13 10:00:31 -0800514 l.add(IThreadPoolService.class);
Jonathan Hart4b5bbb52014-02-06 10:09:31 -0800515 l.add(IControllerRegistryService.class);
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700516 l.add(IDatagridService.class);
Jonathan Harte37e4e22014-05-13 19:12:02 -0700517 l.add(ITopologyService.class);
Jonathan Hart03102132014-07-01 23:22:04 -0700518 l.add(IHostService.class);
Jonathan Hart4b5bbb52014-02-06 10:09:31 -0800519 return l;
Jonathan Hart88770672014-04-02 18:08:30 -0700520 }
Jonathan Hart4b5bbb52014-02-06 10:09:31 -0800521
Jonathan Hart88770672014-04-02 18:08:30 -0700522 @Override
523 public void init(FloodlightModuleContext context)
524 throws FloodlightModuleException {
525 floodlightProvider = context.getServiceImpl(IFloodlightProviderService.class);
526 linkDiscovery = context.getServiceImpl(ILinkDiscoveryService.class);
527 registryService = context.getServiceImpl(IControllerRegistryService.class);
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700528 datagridService = context.getServiceImpl(IDatagridService.class);
Jonathan Hart03102132014-07-01 23:22:04 -0700529 hostService = context.getServiceImpl(IHostService.class);
Jonathan Harte37e4e22014-05-13 19:12:02 -0700530 topologyService = context.getServiceImpl(ITopologyService.class);
Jonathan Hart88770672014-04-02 18:08:30 -0700531 }
Jonathan Hart4b5bbb52014-02-06 10:09:31 -0800532
Jonathan Hart88770672014-04-02 18:08:30 -0700533 @Override
534 public void startUp(FloodlightModuleContext context) {
535 floodlightProvider.addOFSwitchListener(this);
536 linkDiscovery.addListener(this);
Jonathan Hart03102132014-07-01 23:22:04 -0700537 hostService.addHostListener(this);
Toshio Koide2f570c12014-02-06 16:55:32 -0800538
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700539 eventChannel = datagridService.createChannel(
540 TopologyManager.EVENT_CHANNEL_NAME,
541 byte[].class,
542 TopologyEvent.class);
543
Yuta HIGUCHId92b10c2014-08-25 09:30:28 -0700544 mutableTopology = topologyService.getTopology();
Jonathan Hartb3e1b052014-04-02 16:01:12 -0700545
Jonathan Hart88770672014-04-02 18:08:30 -0700546 // Run the cleanup thread
547 String enableCleanup =
548 context.getConfigParams(this).get(ENABLE_CLEANUP_PROPERTY);
549 if (enableCleanup != null
550 && enableCleanup.equalsIgnoreCase("false")) {
551 cleanupEnabled = false;
552 }
Jonathan Hartb3e1b052014-04-02 16:01:12 -0700553
Jonathan Hart88770672014-04-02 18:08:30 -0700554 log.debug("Cleanup thread is {}enabled", (cleanupEnabled) ? "" : "not ");
Jonathan Hartb3e1b052014-04-02 16:01:12 -0700555
Jonathan Hart88770672014-04-02 18:08:30 -0700556 if (cleanupEnabled) {
557 IThreadPoolService threadPool =
558 context.getServiceImpl(IThreadPoolService.class);
559 cleanupTask = new SingletonTask(threadPool.getScheduledExecutor(),
560 new SwitchCleanup());
561 // Run the cleanup task immediately on startup
562 cleanupTask.reschedule(0, TimeUnit.SECONDS);
563 }
Pavlin Radoslavov24409672014-08-20 16:45:11 -0700564
565 // Run the Delayed Operations Handler thread
566 delayedOperationsHandler.start();
Jonathan Hart88770672014-04-02 18:08:30 -0700567 }
Jonathan Hartb3e1b052014-04-02 16:01:12 -0700568
Jonathan Hart88770672014-04-02 18:08:30 -0700569 @Override
Jonathan Hart03102132014-07-01 23:22:04 -0700570 public void hostAdded(Host host) {
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700571 log.debug("Host added with MAC {}", host.getMacAddress());
TeruUd1c5b652014-03-24 13:58:46 -0700572
Jonathan Hart03102132014-07-01 23:22:04 -0700573 SwitchPort sp = new SwitchPort(host.getSwitchDPID(), host.getSwitchPort());
Jonathan Hart88770672014-04-02 18:08:30 -0700574 List<SwitchPort> spLists = new ArrayList<SwitchPort>();
575 spLists.add(sp);
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700576 HostData hostData = new HostData(host.getMacAddress());
577 hostData.setAttachmentPoints(spLists);
578 hostData.setLastSeenTime(host.getLastSeenTimestamp().getTime());
Jonathan Hart88770672014-04-02 18:08:30 -0700579 // Does not use vlan info now.
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700580 hostData.freeze();
Jonathan Hartb3e1b052014-04-02 16:01:12 -0700581
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700582 publishAddHostEvent(hostData);
Jonathan Hart88770672014-04-02 18:08:30 -0700583 }
TeruUd1c5b652014-03-24 13:58:46 -0700584
Jonathan Hart88770672014-04-02 18:08:30 -0700585 @Override
Jonathan Hart03102132014-07-01 23:22:04 -0700586 public void hostRemoved(Host host) {
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700587 log.debug("Host removed with MAC {}", host.getMacAddress());
588
589 //
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700590 // Remove all previously added HostData for this MAC address
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700591 //
592 // TODO: Currently, the caller of hostRemoved() might not include
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700593 // the correct set of Attachment Points in the HostData entry itself.
594 // Also, we might have multiple HostData entries for the same
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700595 // host (MAC address), each containing a single (different) Attachment
596 // Point.
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700597 // Hence, here we have to cleanup all HostData entries for this
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700598 // particular host, based on its MAC address.
599 //
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700600 List<HostData> removeHostDataEntries = new LinkedList<>();
601 for (ConcurrentMap<ByteBuffer, HostData> cm : publishedHostDataEntries.values()) {
602 for (HostData hostData : cm.values()) {
603 if (hostData.getMac().equals(host.getMacAddress())) {
604 removeHostDataEntries.add(hostData);
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700605 }
606 }
607 }
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700608 for (HostData hostData : removeHostDataEntries) {
609 publishRemoveHostEvent(hostData);
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700610 }
Jonathan Hart88770672014-04-02 18:08:30 -0700611 }
Pavlin Radoslavov695f8952014-07-23 16:57:01 -0700612
Pavlin Radoslavov24409672014-08-20 16:45:11 -0700613 @Override
614 public boolean publish(TopologyBatchOperation tbo) {
615 publishTopologyOperations(tbo);
616 return true;
617 }
618
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700619 /**
620 * Prepares the Controller role changed event for a switch.
621 *
622 * @param dpid the switch DPID
623 * @param role the new role of the controller
624 */
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700625 private void controllerRoleChanged(Dpid dpid, Role role) {
626 log.debug("Local switch controller mastership role changed: dpid = {} role = {}",
627 dpid, role);
Pavlin Radoslavov695f8952014-07-23 16:57:01 -0700628 MastershipEvent mastershipEvent =
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700629 new MastershipEvent(dpid, getOnosInstanceId(), role);
Pavlin Radoslavov695f8952014-07-23 16:57:01 -0700630 // FIXME should be merging, with existing attrs, etc..
631 // TODO define attr name as constant somewhere.
632 // TODO populate appropriate attributes.
633 mastershipEvent.createStringAttribute(TopologyElement.TYPE,
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700634 TopologyElement.TYPE_ALL_LAYERS);
Pavlin Radoslavov695f8952014-07-23 16:57:01 -0700635 mastershipEvent.freeze();
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700636 publishAddSwitchMastershipEvent(mastershipEvent);
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700637 }
638
639 /**
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700640 * Publishes ADD Mastership Event.
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700641 *
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700642 * @param mastershipEvent the mastership event to publish
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700643 */
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700644 private void publishAddSwitchMastershipEvent(
645 MastershipEvent mastershipEvent) {
646 // Publish the information
Pavlin Radoslavov24409672014-08-20 16:45:11 -0700647 TopologyBatchOperation tbo = new TopologyBatchOperation();
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700648 TopologyEvent topologyEvent =
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700649 new TopologyEvent(mastershipEvent, getOnosInstanceId());
Pavlin Radoslavov24409672014-08-20 16:45:11 -0700650 tbo.appendAddOperation(topologyEvent);
651 publishTopologyOperations(tbo);
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700652 publishedMastershipEvents.put(mastershipEvent.getDpid(),
653 mastershipEvent);
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700654 }
655
656 /**
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700657 * Publishes REMOVE Mastership Event.
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700658 *
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700659 * @param mastershipEvent the mastership event to publish
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700660 */
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700661 private void publishRemoveSwitchMastershipEvent(
662 MastershipEvent mastershipEvent) {
663 if (publishedMastershipEvents.get(mastershipEvent.getDpid()) == null) {
664 return; // Nothing to do
665 }
666
667 // Publish the information
Pavlin Radoslavov24409672014-08-20 16:45:11 -0700668 TopologyBatchOperation tbo = new TopologyBatchOperation();
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700669 TopologyEvent topologyEvent =
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700670 new TopologyEvent(mastershipEvent, getOnosInstanceId());
Pavlin Radoslavov24409672014-08-20 16:45:11 -0700671 tbo.appendRemoveOperation(topologyEvent);
672 publishTopologyOperations(tbo);
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700673 publishedMastershipEvents.remove(mastershipEvent.getDpid());
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700674 }
675
676 /**
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700677 * Publishes ADD Switch Event.
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700678 *
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700679 * @param switchData the switch event to publish
680 * @param portDataEntries the corresponding port events for the switch to
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700681 * publish
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700682 */
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700683 private void publishAddSwitchEvent(SwitchData switchData,
684 Collection<PortData> portDataEntries) {
685 if (!registryService.hasControl(switchData.getOriginDpid().value())) {
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700686 log.debug("Not the master for switch {}. Suppressed switch add event {}.",
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700687 switchData.getOriginDpid(), switchData);
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700688 return;
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700689 }
690
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700691 // Keep track of the old Port Events that should be removed
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700692 ConcurrentMap<ByteBuffer, PortData> oldPortDataEntries =
693 publishedPortDataEntries.get(switchData.getDpid());
694 if (oldPortDataEntries == null) {
695 oldPortDataEntries = new ConcurrentHashMap<>();
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700696 }
697
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700698 // Publish the information for the switch
Pavlin Radoslavov24409672014-08-20 16:45:11 -0700699 TopologyBatchOperation tbo = new TopologyBatchOperation();
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700700 TopologyEvent topologyEvent =
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700701 new TopologyEvent(switchData, getOnosInstanceId());
Pavlin Radoslavov24409672014-08-20 16:45:11 -0700702 tbo.appendAddOperation(topologyEvent);
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700703
704 // Publish the information for each port
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700705 ConcurrentMap<ByteBuffer, PortData> newPortDataEntries =
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700706 new ConcurrentHashMap<>();
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700707 for (PortData portData : portDataEntries) {
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700708 topologyEvent =
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700709 new TopologyEvent(portData, getOnosInstanceId());
Pavlin Radoslavov24409672014-08-20 16:45:11 -0700710 tbo.appendAddOperation(topologyEvent);
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700711
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700712 ByteBuffer id = portData.getIDasByteBuffer();
713 newPortDataEntries.put(id, portData);
714 oldPortDataEntries.remove(id);
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700715 }
Pavlin Radoslavov24409672014-08-20 16:45:11 -0700716 publishTopologyOperations(tbo);
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700717 publishedSwitchDataEntries.put(switchData.getDpid(), switchData);
718 publishedPortDataEntries.put(switchData.getDpid(), newPortDataEntries);
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700719
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700720 // Cleanup for each of the old removed port
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700721 for (PortData portData : oldPortDataEntries.values()) {
722 publishRemovePortEvent(portData);
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700723 }
724 }
725
726 /**
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700727 * Publishes REMOVE Switch Event.
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700728 *
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700729 * @param switchData the switch event to publish
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700730 */
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700731 private void publishRemoveSwitchEvent(SwitchData switchData) {
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700732 //
733 // TODO: Removed the check for now, because currently this method is
734 // also called by the SwitchCleanup thread, and in that case
735 // the Switch Event was published by some other ONOS instance.
736 //
737 /*
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700738 if (publishedSwitchDataEntries.get(switchData.getDpid()) == null) {
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700739 return; // Nothing to do
740 }
741 */
742
743 // Publish the information
Pavlin Radoslavov24409672014-08-20 16:45:11 -0700744 TopologyBatchOperation tbo = new TopologyBatchOperation();
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700745 TopologyEvent topologyEvent =
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700746 new TopologyEvent(switchData, getOnosInstanceId());
Pavlin Radoslavov24409672014-08-20 16:45:11 -0700747 tbo.appendRemoveOperation(topologyEvent);
748 publishTopologyOperations(tbo);
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700749 publishedSwitchDataEntries.remove(switchData.getDpid());
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700750
751 // Cleanup for each port
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700752 ConcurrentMap<ByteBuffer, PortData> portDataEntries =
753 publishedPortDataEntries.get(switchData.getDpid());
754 if (portDataEntries != null) {
755 for (PortData portData : portDataEntries.values()) {
756 publishRemovePortEvent(portData);
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700757 }
758 }
759
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700760 publishedPortDataEntries.remove(switchData.getDpid());
761 publishedLinkDataEntries.remove(switchData.getDpid());
762 publishedHostDataEntries.remove(switchData.getDpid());
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700763 }
764
765 /**
766 * Publishes ADD Port Event.
767 *
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700768 * @param portData the port event to publish
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700769 */
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700770 private void publishAddPortEvent(PortData portData) {
771 if (!registryService.hasControl(portData.getOriginDpid().value())) {
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700772 log.debug("Not the master for switch {}. Suppressed port add event {}.",
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700773 portData.getOriginDpid(), portData);
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700774 return;
775 }
776
777 // Publish the information
Pavlin Radoslavov24409672014-08-20 16:45:11 -0700778 TopologyBatchOperation tbo = new TopologyBatchOperation();
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700779 TopologyEvent topologyEvent =
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700780 new TopologyEvent(portData, getOnosInstanceId());
Pavlin Radoslavov24409672014-08-20 16:45:11 -0700781 tbo.appendAddOperation(topologyEvent);
782 publishTopologyOperations(tbo);
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700783
784 // Store the new Port Event in the local cache
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700785 ConcurrentMap<ByteBuffer, PortData> portDataEntries =
786 ConcurrentUtils.putIfAbsent(publishedPortDataEntries,
787 portData.getDpid(),
788 new ConcurrentHashMap<ByteBuffer, PortData>());
789 portDataEntries.put(portData.getIDasByteBuffer(), portData);
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700790 }
791
792 /**
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700793 * Publishes REMOVE Port Event.
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700794 *
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700795 * @param portData the port event to publish
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700796 */
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700797 private void publishRemovePortEvent(PortData portData) {
798 ConcurrentMap<ByteBuffer, PortData> portDataEntries =
799 publishedPortDataEntries.get(portData.getDpid());
800 if (portDataEntries == null) {
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700801 return; // Nothing to do
802 }
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700803 if (portDataEntries.get(portData.getIDasByteBuffer()) == null) {
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700804 return; // Nothing to do
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700805 }
806
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700807 // Publish the information
Pavlin Radoslavov24409672014-08-20 16:45:11 -0700808 TopologyBatchOperation tbo = new TopologyBatchOperation();
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700809 TopologyEvent topologyEvent =
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700810 new TopologyEvent(portData, getOnosInstanceId());
Pavlin Radoslavov24409672014-08-20 16:45:11 -0700811 tbo.appendRemoveOperation(topologyEvent);
812 publishTopologyOperations(tbo);
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700813
814 // Cleanup for the incoming link(s)
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700815 ConcurrentMap<ByteBuffer, LinkData> linkDataEntries =
816 publishedLinkDataEntries.get(portData.getDpid());
817 if (linkDataEntries != null) {
818 for (LinkData linkData : linkDataEntries.values()) {
819 if (linkData.getDst().equals(portData.getSwitchPort())) {
820 publishRemoveLinkEvent(linkData);
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700821 }
822 }
823 }
824
825 // Cleanup for the connected hosts
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700826 ConcurrentMap<ByteBuffer, HostData> hostDataEntries =
827 publishedHostDataEntries.get(portData.getDpid());
828 if (hostDataEntries != null) {
829 for (HostData hostData : hostDataEntries.values()) {
830 for (SwitchPort swp : hostData.getAttachmentPoints()) {
831 if (swp.equals(portData.getSwitchPort())) {
832 publishRemoveHostEvent(hostData);
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700833 }
834 }
835 }
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700836 }
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700837
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700838 portDataEntries.remove(portData.getIDasByteBuffer());
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700839 }
840
841 /**
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700842 * Publishes ADD Link Event.
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700843 *
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700844 * @param linkData the link event to publish
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700845 */
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700846 private void publishAddLinkEvent(LinkData linkData) {
847 if (!registryService.hasControl(linkData.getOriginDpid().value())) {
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700848 log.debug("Not the master for dst switch {}. Suppressed link add event {}.",
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700849 linkData.getOriginDpid(), linkData);
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700850 return;
851 }
852
853 // Publish the information
Pavlin Radoslavov24409672014-08-20 16:45:11 -0700854 TopologyBatchOperation tbo = new TopologyBatchOperation();
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700855 TopologyEvent topologyEvent =
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700856 new TopologyEvent(linkData, getOnosInstanceId());
Pavlin Radoslavov24409672014-08-20 16:45:11 -0700857 tbo.appendAddOperation(topologyEvent);
858 publishTopologyOperations(tbo);
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700859
860 // Store the new Link Event in the local cache
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700861 ConcurrentMap<ByteBuffer, LinkData> linkDataEntries =
862 ConcurrentUtils.putIfAbsent(publishedLinkDataEntries,
863 linkData.getDst().getDpid(),
864 new ConcurrentHashMap<ByteBuffer, LinkData>());
865 linkDataEntries.put(linkData.getIDasByteBuffer(), linkData);
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700866 }
867
868 /**
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700869 * Publishes REMOVE Link Event.
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700870 *
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700871 * @param linkData the link event to publish
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700872 */
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700873 private void publishRemoveLinkEvent(LinkData linkData) {
874 ConcurrentMap<ByteBuffer, LinkData> linkDataEntries =
875 publishedLinkDataEntries.get(linkData.getDst().getDpid());
876 if (linkDataEntries == null) {
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700877 return; // Nothing to do
878 }
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700879 if (linkDataEntries.get(linkData.getIDasByteBuffer()) == null) {
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700880 return; // Nothing to do
881 }
882
883 // Publish the information
Pavlin Radoslavov24409672014-08-20 16:45:11 -0700884 TopologyBatchOperation tbo = new TopologyBatchOperation();
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700885 TopologyEvent topologyEvent =
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700886 new TopologyEvent(linkData, getOnosInstanceId());
Pavlin Radoslavov24409672014-08-20 16:45:11 -0700887 tbo.appendRemoveOperation(topologyEvent);
888 publishTopologyOperations(tbo);
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700889
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700890 linkDataEntries.remove(linkData.getIDasByteBuffer());
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700891 }
892
893 /**
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700894 * Publishes ADD Host Event.
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700895 *
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700896 * @param hostData the host event to publish
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700897 */
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700898 private void publishAddHostEvent(HostData hostData) {
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700899 //
900 // NOTE: The implementation below assumes that there is just one
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700901 // attachment point stored in hostData. Currently, this assumption
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700902 // is true based on the existing implementation of the caller
903 // hostAdded().
904 //
905
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700906 if (!registryService.hasControl(hostData.getOriginDpid().value())) {
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700907 log.debug("Not the master for attachment switch {}. Suppressed host add event {}.",
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700908 hostData.getOriginDpid(), hostData);
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700909 return;
910 }
911
912 // Publish the information
Pavlin Radoslavov24409672014-08-20 16:45:11 -0700913 TopologyBatchOperation tbo = new TopologyBatchOperation();
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700914 TopologyEvent topologyEvent =
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700915 new TopologyEvent(hostData, getOnosInstanceId());
Pavlin Radoslavov24409672014-08-20 16:45:11 -0700916 tbo.appendAddOperation(topologyEvent);
917 publishTopologyOperations(tbo);
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700918
919 // Store the new Host Event in the local cache
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700920 ConcurrentMap<ByteBuffer, HostData> hostDataEntries =
921 ConcurrentUtils.putIfAbsent(publishedHostDataEntries,
922 hostData.getOriginDpid(),
923 new ConcurrentHashMap<ByteBuffer, HostData>());
924 hostDataEntries.put(hostData.getIDasByteBuffer(), hostData);
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700925 }
926
927 /**
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700928 * Publishes REMOVE Host Event.
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700929 *
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700930 * @param hostData the host event to publish
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700931 */
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700932 private void publishRemoveHostEvent(HostData hostData) {
933 ConcurrentMap<ByteBuffer, HostData> hostDataEntries =
934 publishedHostDataEntries.get(hostData.getOriginDpid());
935 if (hostDataEntries == null) {
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700936 return; // Nothing to do
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700937 }
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700938 if (hostDataEntries.get(hostData.getIDasByteBuffer()) == null) {
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700939 return; // Nothing to do
940 }
941
942 // Publish the information
Pavlin Radoslavov24409672014-08-20 16:45:11 -0700943 TopologyBatchOperation tbo = new TopologyBatchOperation();
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700944 TopologyEvent topologyEvent =
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700945 new TopologyEvent(hostData, getOnosInstanceId());
Pavlin Radoslavov24409672014-08-20 16:45:11 -0700946 tbo.appendRemoveOperation(topologyEvent);
947 publishTopologyOperations(tbo);
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700948
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700949 hostDataEntries.remove(hostData.getIDasByteBuffer());
Pavlin Radoslavov695f8952014-07-23 16:57:01 -0700950 }
Pavlin Radoslavov24409672014-08-20 16:45:11 -0700951
952 /**
953 * Publishes Topology Operations.
954 *
955 * @param tbo the Topology Operations to publish
956 */
957 private void publishTopologyOperations(TopologyBatchOperation tbo) {
958 // TODO: This flag should be configurable
959 boolean isGlobalLogWriter = false;
960
961 log.debug("Publishing: {}", tbo);
962
963 if (isGlobalLogWriter) {
964 if (!topologyService.publish(tbo)) {
965 log.debug("Cannot publish: {}", tbo);
966 delayedOperations.add(tbo);
967 }
968 } else {
969 // TODO: For now we publish each TopologyEvent independently
970 for (BatchOperationEntry<TopologyBatchOperation.Operator,
971 TopologyEvent> boe : tbo.getOperations()) {
972 TopologyBatchOperation.Operator oper = boe.getOperator();
973 TopologyEvent topologyEvent = boe.getTarget();
974 switch (oper) {
975 case ADD:
976 eventChannel.addEntry(topologyEvent.getID(),
977 topologyEvent);
978 break;
979 case REMOVE:
980 eventChannel.removeEntry(topologyEvent.getID());
981 break;
982 default:
983 log.error("Unknown Topology Batch Operation {}", oper);
984 break;
985 }
986 }
987 }
988 }
Jonathan Hart4b5bbb52014-02-06 10:09:31 -0800989}