blob: 9ef6fa9bbb5d46df634c1ffa6b2c7dae44c95995 [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;
Saurav Dasfb93c252014-08-18 20:40:13 -070010import java.util.Map.Entry;
Pavlin Radoslavov24409672014-08-20 16:45:11 -070011import java.util.concurrent.BlockingQueue;
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -070012import java.util.concurrent.ConcurrentHashMap;
13import java.util.concurrent.ConcurrentMap;
Pavlin Radoslavov24409672014-08-20 16:45:11 -070014import java.util.concurrent.LinkedBlockingQueue;
Jonathan Hart369875b2014-02-13 10:00:31 -080015import java.util.concurrent.TimeUnit;
Jonathan Hart4b5bbb52014-02-06 10:09:31 -080016
17import net.floodlightcontroller.core.IFloodlightProviderService;
Pavlin Radoslavov695f8952014-07-23 16:57:01 -070018import net.floodlightcontroller.core.IFloodlightProviderService.Role;
Jonathan Hart4b5bbb52014-02-06 10:09:31 -080019import net.floodlightcontroller.core.IOFSwitch;
Brian O'Connorc67f9fa2014-08-07 18:17:46 -070020import net.floodlightcontroller.core.IOFSwitch.PortChangeType;
21import net.floodlightcontroller.core.IOFSwitchListener;
Jonathan Hart4b5bbb52014-02-06 10:09:31 -080022import net.floodlightcontroller.core.module.FloodlightModuleContext;
23import net.floodlightcontroller.core.module.FloodlightModuleException;
24import net.floodlightcontroller.core.module.IFloodlightModule;
25import net.floodlightcontroller.core.module.IFloodlightService;
Jonathan Hart369875b2014-02-13 10:00:31 -080026import net.floodlightcontroller.core.util.SingletonTask;
27import net.floodlightcontroller.threadpool.IThreadPoolService;
Pavlin Radoslavov24409672014-08-20 16:45:11 -070028import net.onrc.onos.api.batchoperation.BatchOperationEntry;
Saurav Dasfb93c252014-08-18 20:40:13 -070029import net.onrc.onos.core.configmanager.INetworkConfigService;
30import net.onrc.onos.core.configmanager.INetworkConfigService.LinkConfigStatus;
31import net.onrc.onos.core.configmanager.INetworkConfigService.NetworkConfigState;
32import net.onrc.onos.core.configmanager.INetworkConfigService.SwitchConfigStatus;
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -070033import net.onrc.onos.core.datagrid.IDatagridService;
34import net.onrc.onos.core.datagrid.IEventChannel;
Jonathan Hart03102132014-07-01 23:22:04 -070035import net.onrc.onos.core.hostmanager.Host;
36import net.onrc.onos.core.hostmanager.IHostListener;
37import net.onrc.onos.core.hostmanager.IHostService;
Jonathan Hart23701d12014-04-03 10:45:48 -070038import net.onrc.onos.core.linkdiscovery.ILinkDiscoveryListener;
39import net.onrc.onos.core.linkdiscovery.ILinkDiscoveryService;
Jonathan Hart284e70f2014-07-05 12:32:51 -070040import net.onrc.onos.core.linkdiscovery.Link;
Jonathan Hartdeda0ba2014-04-03 11:14:12 -070041import net.onrc.onos.core.registry.IControllerRegistryService;
Jonathan Hartdeda0ba2014-04-03 11:14:12 -070042import net.onrc.onos.core.registry.IControllerRegistryService.ControlChangeCallback;
Jonathan Harta99ec672014-04-03 11:30:34 -070043import net.onrc.onos.core.registry.RegistryException;
Yuta HIGUCHI5bbbaca2014-06-09 16:39:08 -070044import net.onrc.onos.core.util.Dpid;
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -070045import net.onrc.onos.core.util.OnosInstanceId;
Yuta HIGUCHIa507baf2014-08-22 13:42:40 -070046import net.onrc.onos.core.util.PortNumberUtils;
Yuta HIGUCHI5c8cbeb2014-06-27 11:13:48 -070047import net.onrc.onos.core.util.SwitchPort;
Jonathan Hart4b5bbb52014-02-06 10:09:31 -080048
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -070049import org.apache.commons.lang3.concurrent.ConcurrentUtils;
Brian O'Connorc67f9fa2014-08-07 18:17:46 -070050import org.projectfloodlight.openflow.protocol.OFPortDesc;
51import org.projectfloodlight.openflow.util.HexString;
Toshio Koide2f570c12014-02-06 16:55:32 -080052import org.slf4j.Logger;
53import org.slf4j.LoggerFactory;
Jonathan Hart4b5bbb52014-02-06 10:09:31 -080054
Jonathan Hart88770672014-04-02 18:08:30 -070055/**
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -070056 * Class for publishing topology-related events.
57 *
58 * The events are received from the discovery modules, reformatted and
59 * published to the other ONOS instances.
60 *
61 * TODO: Add a synchronization mechanism when publishing the events to
62 * preserve the ordering and to avoid mismatch in the local "published" state,
63 * because each of the caller (the discovery modules) might be running
64 * on a different thread.
Jonathan Hart88770672014-04-02 18:08:30 -070065 */
Brian O'Connorc67f9fa2014-08-07 18:17:46 -070066public class TopologyPublisher implements IOFSwitchListener,
Ray Milkey269ffb92014-04-03 14:43:30 -070067 ILinkDiscoveryListener,
68 IFloodlightModule,
Pavlin Radoslavov24409672014-08-20 16:45:11 -070069 IHostListener,
70 ITopologyPublisherService {
Jonathan Hart88770672014-04-02 18:08:30 -070071 private static final Logger log =
Jonathan Harte37e4e22014-05-13 19:12:02 -070072 LoggerFactory.getLogger(TopologyPublisher.class);
Yuta HIGUCHIcb951982014-02-11 13:31:44 -080073
Jonathan Hart88770672014-04-02 18:08:30 -070074 private IFloodlightProviderService floodlightProvider;
75 private ILinkDiscoveryService linkDiscovery;
76 private IControllerRegistryService registryService;
Jonathan Harte37e4e22014-05-13 19:12:02 -070077 private ITopologyService topologyService;
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -070078 private IDatagridService datagridService;
Toshio Koide2f570c12014-02-06 16:55:32 -080079
Jonathan Hart03102132014-07-01 23:22:04 -070080 private IHostService hostService;
Yuta HIGUCHId92b10c2014-08-25 09:30:28 -070081 private MutableTopology mutableTopology;
Saurav Dasfb93c252014-08-18 20:40:13 -070082 private INetworkConfigService networkConfigService;
Jonathan Hartb3e1b052014-04-02 16:01:12 -070083
Jonathan Hart88770672014-04-02 18:08:30 -070084 private static final String ENABLE_CLEANUP_PROPERTY = "EnableCleanup";
85 private boolean cleanupEnabled = true;
86 private static final int CLEANUP_TASK_INTERVAL = 60; // in seconds
87 private SingletonTask cleanupTask;
Pavlin Radoslavov24409672014-08-20 16:45:11 -070088 private DelayedOperationsHandler delayedOperationsHandler =
89 new DelayedOperationsHandler();
Toshio Koide2f570c12014-02-06 16:55:32 -080090
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -070091 private IEventChannel<byte[], TopologyEvent> eventChannel;
92
93 //
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -070094 // Local state for keeping track of locally published events so we can
95 // cleanup properly when an entry is removed.
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -070096 //
97 // We keep all Port, (incoming) Link and Host events per Switch DPID:
98 // - If a switch goes down, we remove all corresponding Port, Link and
99 // Host events.
100 // - If a port on a switch goes down, we remove all corresponding Link
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700101 // and Host events attached to this port.
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700102 //
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700103 // TODO: What to do if the Mastership changes?
104 // - Cleanup state from publishedFoo maps, but do not send REMOVE events?
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700105 //
Yuta HIGUCHId8fd2f52014-09-01 23:19:45 -0700106 private ConcurrentMap<Dpid, MastershipData> publishedMastershipDataEntries =
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700107 new ConcurrentHashMap<>();
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700108 private ConcurrentMap<Dpid, SwitchData> publishedSwitchDataEntries =
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700109 new ConcurrentHashMap<>();
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700110 private ConcurrentMap<Dpid, ConcurrentMap<ByteBuffer, PortData>>
111 publishedPortDataEntries = new ConcurrentHashMap<>();
112 private ConcurrentMap<Dpid, ConcurrentMap<ByteBuffer, LinkData>>
113 publishedLinkDataEntries = new ConcurrentHashMap<>();
114 private ConcurrentMap<Dpid, ConcurrentMap<ByteBuffer, HostData>>
115 publishedHostDataEntries = new ConcurrentHashMap<>();
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700116
Pavlin Radoslavov24409672014-08-20 16:45:11 -0700117 private BlockingQueue<TopologyBatchOperation> delayedOperations =
118 new LinkedBlockingQueue<>();
119
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700120
Jonathan Hart369875b2014-02-13 10:00:31 -0800121 /**
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700122 * Gets the ONOS Instance ID.
123 *
124 * @return the ONOS Instance ID.
125 */
126 private OnosInstanceId getOnosInstanceId() {
127 return registryService.getOnosInstanceId();
128 }
129
130 /**
131 * Cleanup old switches from the topology. Old switches are those which
132 * have no controller in the registry.
133 *
134 * TODO: The overall switch cleanup mechanism needs refactoring/redesign.
Jonathan Hart369875b2014-02-13 10:00:31 -0800135 */
136 private class SwitchCleanup implements ControlChangeCallback, Runnable {
137 @Override
138 public void run() {
139 String old = Thread.currentThread().getName();
140 Thread.currentThread().setName("SwitchCleanup@" + old);
Jonathan Hartb3e1b052014-04-02 16:01:12 -0700141
Jonathan Hart369875b2014-02-13 10:00:31 -0800142 try {
Jonathan Hart88770672014-04-02 18:08:30 -0700143 if (log.isTraceEnabled()) {
144 log.trace("Running cleanup thread");
145 }
Jonathan Hart369875b2014-02-13 10:00:31 -0800146 switchCleanup();
Jonathan Hart369875b2014-02-13 10:00:31 -0800147 } finally {
148 cleanupTask.reschedule(CLEANUP_TASK_INTERVAL,
Jonathan Hart88770672014-04-02 18:08:30 -0700149 TimeUnit.SECONDS);
Jonathan Hart369875b2014-02-13 10:00:31 -0800150 Thread.currentThread().setName(old);
151 }
152 }
Jonathan Hartb3e1b052014-04-02 16:01:12 -0700153
Jonathan Hart88770672014-04-02 18:08:30 -0700154 /**
155 * First half of the switch cleanup operation. This method will attempt
156 * to get control of any switch it sees without a controller via the
157 * registry.
158 */
Jonathan Hart369875b2014-02-13 10:00:31 -0800159 private void switchCleanup() {
Yuta HIGUCHId92b10c2014-08-25 09:30:28 -0700160 Iterable<Switch> switches = mutableTopology.getSwitches();
Jonathan Hart369875b2014-02-13 10:00:31 -0800161
Jonathan Hart88770672014-04-02 18:08:30 -0700162 if (log.isTraceEnabled()) {
163 log.trace("Checking for inactive switches");
164 }
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700165 // For each switch check if a controller exists in controller
166 // registry
Ray Milkey269ffb92014-04-03 14:43:30 -0700167 for (Switch sw : switches) {
Praseed Balakrishnane82adc62014-08-04 10:59:24 -0700168 // FIXME How to handle case where Switch has never been
169 // registered to ZK
170 if (sw.getConfigState() == ConfigState.CONFIGURED) {
171 continue;
172 }
Jonathan Hart88770672014-04-02 18:08:30 -0700173 try {
174 String controller =
Yuta HIGUCHI8f3dfa32014-06-25 00:14:25 -0700175 registryService.getControllerForSwitch(sw.getDpid().value());
Jonathan Hart88770672014-04-02 18:08:30 -0700176 if (controller == null) {
177 log.debug("Requesting control to set switch {} INACTIVE",
Yuta HIGUCHI8f3dfa32014-06-25 00:14:25 -0700178 sw.getDpid());
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700179 registryService.requestControl(sw.getDpid().value(),
180 this);
Jonathan Hart88770672014-04-02 18:08:30 -0700181 }
182 } catch (RegistryException e) {
183 log.error("Caught RegistryException in cleanup thread", e);
184 }
185 }
Jonathan Hart369875b2014-02-13 10:00:31 -0800186 }
187
Jonathan Hart88770672014-04-02 18:08:30 -0700188 /**
189 * Second half of the switch cleanup operation. If the registry grants
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700190 * control of a switch, we can be sure no other instance is writing
191 * this switch to the topology, so we can remove it now.
192 *
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700193 * @param dpid the dpid of the switch we requested control for
Jonathan Hart88770672014-04-02 18:08:30 -0700194 * @param hasControl whether we got control or not
195 */
196 @Override
197 public void controlChanged(long dpid, boolean hasControl) {
198 if (hasControl) {
199 log.debug("Got control to set switch {} INACTIVE",
200 HexString.toHexString(dpid));
Jonathan Harte02cf542014-04-02 16:24:44 -0700201
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700202 SwitchData switchData = new SwitchData(new Dpid(dpid));
203 publishRemoveSwitchEvent(switchData);
Jonathan Hart88770672014-04-02 18:08:30 -0700204 registryService.releaseControl(dpid);
205 }
206 }
Jonathan Hart369875b2014-02-13 10:00:31 -0800207 }
Jonathan Hart4b5bbb52014-02-06 10:09:31 -0800208
Pavlin Radoslavov24409672014-08-20 16:45:11 -0700209 /**
210 * A class to deal with Topology Operations that couldn't be pushed
211 * to the Global Log writer, because they need to be delayed.
212 * For example, a link cannot be pushed before the switches on both
213 * ends are in the Global Log.
214 *
215 * TODO: This is an ugly hack that should go away: right now we have to
216 * keep trying periodically.
217 * TODO: Currently, we retry only ADD Link Events, everything else
218 * is thrown away.
219 */
220 private class DelayedOperationsHandler extends Thread {
221 private static final long RETRY_INTERVAL_MS = 10; // 10ms
222
223 @Override
224 public void run() {
225 List<TopologyBatchOperation> operations = new LinkedList<>();
226
227 this.setName("TopologyPublisher.DelayedOperationsHandler " +
228 this.getId());
229 //
230 // The main loop
231 //
232 while (true) {
233 try {
234 //
235 // Block-waiting for an operation to be added, sleep
236 // and try to publish it again.
237 //
238 TopologyBatchOperation firstTbo = delayedOperations.take();
239 Thread.sleep(RETRY_INTERVAL_MS);
240 operations.add(firstTbo);
241 delayedOperations.drainTo(operations);
242
243 // Retry only the appropriate operations
244 for (TopologyBatchOperation tbo : operations) {
245 for (BatchOperationEntry<
246 TopologyBatchOperation.Operator,
247 TopologyEvent> boe : tbo.getOperations()) {
248 TopologyBatchOperation.Operator oper =
249 boe.getOperator();
250 switch (oper) {
251 case ADD:
252 TopologyEvent topologyEvent = boe.getTarget();
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700253 LinkData linkData =
254 topologyEvent.getLinkData();
Pavlin Radoslavov24409672014-08-20 16:45:11 -0700255 //
256 // Test whether the Link Event still can be
257 // published.
258 // TODO: The implementation below has a bug:
259 // If it happens that the same Link Event was
260 // removed in the middle of checking, we might
261 // incorrectly publish it again from here.
262 //
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700263 if (linkData == null) {
Pavlin Radoslavov24409672014-08-20 16:45:11 -0700264 break;
265 }
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700266 ConcurrentMap<ByteBuffer, LinkData>
267 linkDataEntries = publishedLinkDataEntries.get(
268 linkData.getDst().getDpid());
269 if (linkDataEntries == null) {
Pavlin Radoslavov24409672014-08-20 16:45:11 -0700270 break;
271 }
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700272 if (linkDataEntries.get(linkData.getIDasByteBuffer()) == null) {
Pavlin Radoslavov24409672014-08-20 16:45:11 -0700273 break;
274 }
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700275 publishAddLinkEvent(linkData);
Pavlin Radoslavov24409672014-08-20 16:45:11 -0700276 break;
277 case REMOVE:
278 break;
279 default:
280 log.error("Unknown Topology Batch Operation {}", oper);
281 break;
282 }
283 }
284 }
285 } catch (InterruptedException exception) {
286 log.debug("Exception processing delayed operations: ",
287 exception);
288 }
289 }
290 }
291 }
292
Jonathan Hart88770672014-04-02 18:08:30 -0700293 @Override
Jonathan Hart284e70f2014-07-05 12:32:51 -0700294 public void linkAdded(Link link) {
Saurav Dasfb93c252014-08-18 20:40:13 -0700295 LinkConfigStatus ret = networkConfigService.checkLinkConfig(link);
296 if (ret.getConfigState() == NetworkConfigState.DENY) {
297 log.warn("Discovered {} denied by configuration. {} "
298 + "Not allowing it to proceed.", link, ret.getMsg());
299 return;
300 }
301
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700302 LinkData linkData = new LinkData(
Jonathan Hart284e70f2014-07-05 12:32:51 -0700303 new SwitchPort(link.getSrc(), link.getSrcPort()),
304 new SwitchPort(link.getDst(), link.getDstPort()));
305
Yuta HIGUCHIbf0a8712014-06-30 18:59:46 -0700306 // FIXME should be merging, with existing attrs, etc..
307 // TODO define attr name as constant somewhere.
308 // TODO populate appropriate attributes.
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700309 linkData.createStringAttribute(TopologyElement.TYPE,
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700310 TopologyElement.TYPE_PACKET_LAYER);
Saurav Dasfb93c252014-08-18 20:40:13 -0700311 if (ret.getConfigState() == NetworkConfigState.ACCEPT_ADD) {
312 Map<String, String> attr = ret.getLinkConfig().getPublishAttributes();
313 for (Entry<String, String> e : attr.entrySet()) {
314 linkData.createStringAttribute(e.getKey(), e.getValue());
315 }
316 linkData.createStringAttribute(TopologyElement.ELEMENT_CONFIG_STATE,
317 ConfigState.CONFIGURED.toString());
318 } else {
319 linkData.createStringAttribute(TopologyElement.ELEMENT_CONFIG_STATE,
320 ConfigState.NOT_CONFIGURED.toString());
321 }
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700322 linkData.createStringAttribute(TopologyElement.ELEMENT_ADMIN_STATUS,
Praseed Balakrishnan2aa6c0b2014-07-17 11:42:05 -0700323 AdminStatus.ACTIVE.toString());
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700324 linkData.freeze();
Jonathan Hartb3e1b052014-04-02 16:01:12 -0700325
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700326 publishAddLinkEvent(linkData);
Jonathan Hart284e70f2014-07-05 12:32:51 -0700327 }
328
329 @Override
330 public void linkRemoved(Link link) {
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700331 LinkData linkData = new LinkData(
Jonathan Hart284e70f2014-07-05 12:32:51 -0700332 new SwitchPort(link.getSrc(), link.getSrcPort()),
333 new SwitchPort(link.getDst(), link.getDstPort()));
334
335 // FIXME should be merging, with existing attrs, etc..
336 // TODO define attr name as constant somewhere.
337 // TODO populate appropriate attributes.
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700338 linkData.createStringAttribute(TopologyElement.TYPE,
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700339 TopologyElement.TYPE_PACKET_LAYER);
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700340 linkData.freeze();
Jonathan Hart284e70f2014-07-05 12:32:51 -0700341
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700342 publishRemoveLinkEvent(linkData);
Jonathan Hart88770672014-04-02 18:08:30 -0700343 }
Jonathan Hart4b5bbb52014-02-06 10:09:31 -0800344
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700345 /* *****************
346 * IOFSwitchListener
347 * *****************/
348
Jonathan Hart88770672014-04-02 18:08:30 -0700349 @Override
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700350 public void switchActivatedMaster(long swId) {
351 IOFSwitch sw = floodlightProvider.getSwitch(swId);
352 final Dpid dpid = new Dpid(swId);
353 if (sw == null) {
354 log.warn("Added switch not available {} ", dpid);
355 return;
356 }
357
Saurav Dasfb93c252014-08-18 20:40:13 -0700358 SwitchConfigStatus ret = networkConfigService.checkSwitchConfig(dpid);
359 if (ret.getConfigState() == NetworkConfigState.DENY) {
360 log.warn("Activated switch {} denied by network configuration. {} "
361 + "Not allowing it to proceed.", dpid, ret.getMsg());
362 return;
363 }
364
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700365 controllerRoleChanged(dpid, Role.MASTER);
366
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700367 SwitchData switchData = new SwitchData(dpid);
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700368 // FIXME should be merging, with existing attrs, etc..
369 // TODO define attr name as constant somewhere.
370 // TODO populate appropriate attributes.
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700371 switchData.createStringAttribute(TopologyElement.TYPE,
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700372 TopologyElement.TYPE_PACKET_LAYER);
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700373 switchData.createStringAttribute("ConnectedSince",
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700374 sw.getConnectedSince().toString());
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700375 switchData.createStringAttribute(TopologyElement.ELEMENT_ADMIN_STATUS,
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700376 AdminStatus.ACTIVE.toString());
Saurav Dasfb93c252014-08-18 20:40:13 -0700377 if (ret.getConfigState() == NetworkConfigState.ACCEPT_ADD) {
378 Map<String, String> attr = ret.getSwitchConfig().getPublishAttributes();
379 for (Entry<String, String> e : attr.entrySet()) {
380 switchData.createStringAttribute(e.getKey(), e.getValue());
381 }
382 switchData.createStringAttribute(TopologyElement.ELEMENT_CONFIG_STATE,
383 ConfigState.CONFIGURED.toString());
384 } else {
385 switchData.createStringAttribute(TopologyElement.ELEMENT_CONFIG_STATE,
386 ConfigState.NOT_CONFIGURED.toString());
387 }
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700388 switchData.freeze();
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700389 // The Port events
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700390 List<PortData> portDataEntries = new ArrayList<PortData>();
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700391 for (OFPortDesc port : sw.getPorts()) {
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700392 PortData portData = new PortData(dpid,
Yuta HIGUCHIa507baf2014-08-22 13:42:40 -0700393 PortNumberUtils.openFlow(port));
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700394 // FIXME should be merging, with existing attrs, etc..
395 // TODO define attr name as constant somewhere.
396 // TODO populate appropriate attributes.
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700397 portData.createStringAttribute("name", port.getName());
398 portData.createStringAttribute(TopologyElement.TYPE,
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700399 TopologyElement.TYPE_PACKET_LAYER);
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700400 portData.createStringAttribute(TopologyElement.ELEMENT_CONFIG_STATE,
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700401 ConfigState.NOT_CONFIGURED.toString());
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700402 portData.createStringAttribute(TopologyElement.ELEMENT_ADMIN_STATUS,
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700403 AdminStatus.ACTIVE.toString());
404
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700405 portData.freeze();
406 portDataEntries.add(portData);
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700407 }
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700408 publishAddSwitchEvent(switchData, portDataEntries);
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700409 }
410
411 @Override
412 public void switchActivatedEqual(long swId) {
413 final Dpid dpid = new Dpid(swId);
414 controllerRoleChanged(dpid, Role.EQUAL);
415 }
416
417 @Override
418 public void switchMasterToEqual(long swId) {
419 final Dpid dpid = new Dpid(swId);
420 controllerRoleChanged(dpid, Role.EQUAL);
421 }
422
423 @Override
424 public void switchEqualToMaster(long swId) {
425 // for now treat as switchActivatedMaster
426 switchActivatedMaster(swId);
427 }
428
429 @Override
430 public void switchDisconnected(long swId) {
431 final Dpid dpid = new Dpid(swId);
432
433 log.debug("Local switch disconnected: dpid = {} role = {}", dpid);
434
435 Role role = Role.SLAVE; // TODO: Should be Role.UNKNOWN
436
Yuta HIGUCHId8fd2f52014-09-01 23:19:45 -0700437 MastershipData mastershipData =
438 new MastershipData(dpid, getOnosInstanceId(), role);
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700439 // FIXME should be merging, with existing attrs, etc..
440 // TODO define attr name as constant somewhere.
441 // TODO populate appropriate attributes.
Yuta HIGUCHId8fd2f52014-09-01 23:19:45 -0700442 mastershipData.createStringAttribute(TopologyElement.TYPE,
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700443 TopologyElement.TYPE_ALL_LAYERS);
Yuta HIGUCHId8fd2f52014-09-01 23:19:45 -0700444 mastershipData.freeze();
445 publishRemoveSwitchMastershipEvent(mastershipData);
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700446 }
447
448 @Override
449 public void switchPortChanged(long swId, OFPortDesc port,
450 PortChangeType changeType) {
451 switch (changeType) {
452 case ADD:
453 switchPortAdded(swId, port);
454 break;
455 case DELETE:
456 switchPortRemoved(swId, port);
457 break;
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700458 case UP:
Pavlin Radoslavov7946c612014-08-13 15:06:00 -0700459 // NOTE: Currently, we treat Port UP/DOWN same as Port ADD/DELETE
460 switchPortAdded(swId, port);
461 break;
462 case DOWN:
463 // NOTE: Currently, we treat Port UP/DOWN same as Port ADD/DELETE
464 switchPortRemoved(swId, port);
465 break;
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700466 case OTHER_UPDATE:
467 default:
468 // XXX S what is the right set of port change handlers?
469 log.debug("Topology publisher does not handle these port updates: {}",
470 changeType);
471 }
472 }
473
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700474 /**
475 * Prepares an event for adding a port on a switch.
476 *
477 * @param switchId the switch ID (DPID)
478 * @param port the port to add
479 */
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700480 private void switchPortAdded(long switchId, OFPortDesc port) {
Yuta HIGUCHIbf0a8712014-06-30 18:59:46 -0700481 final Dpid dpid = new Dpid(switchId);
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700482 final PortData portData = new PortData(dpid,
Yuta HIGUCHIa507baf2014-08-22 13:42:40 -0700483 PortNumberUtils.openFlow(port));
Yuta HIGUCHIbf0a8712014-06-30 18:59:46 -0700484 // FIXME should be merging, with existing attrs, etc..
485 // TODO define attr name as constant somewhere.
486 // TODO populate appropriate attributes.
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700487 portData.createStringAttribute(TopologyElement.TYPE,
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700488 TopologyElement.TYPE_PACKET_LAYER);
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700489 portData.createStringAttribute("name", port.getName());
490 portData.freeze();
Yuta HIGUCHIbf0a8712014-06-30 18:59:46 -0700491
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700492 publishAddPortEvent(portData);
Jonathan Hart88770672014-04-02 18:08:30 -0700493 }
Jonathan Hart4b5bbb52014-02-06 10:09:31 -0800494
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700495 /**
496 * Prepares an event for removing a port on a switch.
497 *
498 * @param switchId the switch ID (DPID)
499 * @param port the port to remove
500 */
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700501 private void switchPortRemoved(long switchId, OFPortDesc port) {
Yuta HIGUCHIe2a4e172014-07-03 10:50:39 -0700502 final Dpid dpid = new Dpid(switchId);
Yuta HIGUCHI5bbbaca2014-06-09 16:39:08 -0700503
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700504 final PortData portData = new PortData(dpid,
Yuta HIGUCHIa507baf2014-08-22 13:42:40 -0700505 PortNumberUtils.openFlow(port));
Yuta HIGUCHI1222ac52014-07-09 16:50:28 -0700506 // FIXME should be merging, with existing attrs, etc..
507 // TODO define attr name as constant somewhere.
508 // TODO populate appropriate attributes.
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700509 portData.createStringAttribute(TopologyElement.TYPE,
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700510 TopologyElement.TYPE_PACKET_LAYER);
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700511 portData.createStringAttribute("name", port.getName());
512 portData.freeze();
Yuta HIGUCHI1222ac52014-07-09 16:50:28 -0700513
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700514 publishRemovePortEvent(portData);
Jonathan Hart88770672014-04-02 18:08:30 -0700515 }
Jonathan Hart4b5bbb52014-02-06 10:09:31 -0800516
Jonathan Hart88770672014-04-02 18:08:30 -0700517 @Override
Jonathan Hart88770672014-04-02 18:08:30 -0700518 public String getName() {
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700519 return "topologyPublisher";
Jonathan Hart88770672014-04-02 18:08:30 -0700520 }
Jonathan Hart4b5bbb52014-02-06 10:09:31 -0800521
Jonathan Hart88770672014-04-02 18:08:30 -0700522 /* *****************
523 * IFloodlightModule
524 * *****************/
Toshio Koide2f570c12014-02-06 16:55:32 -0800525
Jonathan Hart88770672014-04-02 18:08:30 -0700526 @Override
527 public Collection<Class<? extends IFloodlightService>> getModuleServices() {
Pavlin Radoslavov24409672014-08-20 16:45:11 -0700528 List<Class<? extends IFloodlightService>> services =
529 new ArrayList<Class<? extends IFloodlightService>>();
530 services.add(ITopologyPublisherService.class);
531 return services;
Jonathan Hart88770672014-04-02 18:08:30 -0700532 }
Jonathan Hart4b5bbb52014-02-06 10:09:31 -0800533
Jonathan Hart88770672014-04-02 18:08:30 -0700534 @Override
535 public Map<Class<? extends IFloodlightService>, IFloodlightService>
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700536 getServiceImpls() {
Pavlin Radoslavov24409672014-08-20 16:45:11 -0700537 Map<Class<? extends IFloodlightService>, IFloodlightService> impls =
538 new HashMap<Class<? extends IFloodlightService>, IFloodlightService>();
539 impls.put(ITopologyPublisherService.class, this);
540 return impls;
Jonathan Hart88770672014-04-02 18:08:30 -0700541 }
Jonathan Hart4b5bbb52014-02-06 10:09:31 -0800542
Jonathan Hart88770672014-04-02 18:08:30 -0700543 @Override
544 public Collection<Class<? extends IFloodlightService>>
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700545 getModuleDependencies() {
Jonathan Hart88770672014-04-02 18:08:30 -0700546 Collection<Class<? extends IFloodlightService>> l =
547 new ArrayList<Class<? extends IFloodlightService>>();
Jonathan Hart4b5bbb52014-02-06 10:09:31 -0800548 l.add(IFloodlightProviderService.class);
549 l.add(ILinkDiscoveryService.class);
Jonathan Hart369875b2014-02-13 10:00:31 -0800550 l.add(IThreadPoolService.class);
Jonathan Hart4b5bbb52014-02-06 10:09:31 -0800551 l.add(IControllerRegistryService.class);
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700552 l.add(IDatagridService.class);
Jonathan Harte37e4e22014-05-13 19:12:02 -0700553 l.add(ITopologyService.class);
Jonathan Hart03102132014-07-01 23:22:04 -0700554 l.add(IHostService.class);
Saurav Dasfb93c252014-08-18 20:40:13 -0700555 l.add(INetworkConfigService.class);
Jonathan Hart4b5bbb52014-02-06 10:09:31 -0800556 return l;
Jonathan Hart88770672014-04-02 18:08:30 -0700557 }
Jonathan Hart4b5bbb52014-02-06 10:09:31 -0800558
Jonathan Hart88770672014-04-02 18:08:30 -0700559 @Override
560 public void init(FloodlightModuleContext context)
561 throws FloodlightModuleException {
562 floodlightProvider = context.getServiceImpl(IFloodlightProviderService.class);
563 linkDiscovery = context.getServiceImpl(ILinkDiscoveryService.class);
564 registryService = context.getServiceImpl(IControllerRegistryService.class);
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700565 datagridService = context.getServiceImpl(IDatagridService.class);
Jonathan Hart03102132014-07-01 23:22:04 -0700566 hostService = context.getServiceImpl(IHostService.class);
Saurav Dasfb93c252014-08-18 20:40:13 -0700567 networkConfigService = context.getServiceImpl(INetworkConfigService.class);
Jonathan Harte37e4e22014-05-13 19:12:02 -0700568 topologyService = context.getServiceImpl(ITopologyService.class);
Jonathan Hart88770672014-04-02 18:08:30 -0700569 }
Jonathan Hart4b5bbb52014-02-06 10:09:31 -0800570
Jonathan Hart88770672014-04-02 18:08:30 -0700571 @Override
572 public void startUp(FloodlightModuleContext context) {
573 floodlightProvider.addOFSwitchListener(this);
574 linkDiscovery.addListener(this);
Jonathan Hart03102132014-07-01 23:22:04 -0700575 hostService.addHostListener(this);
Toshio Koide2f570c12014-02-06 16:55:32 -0800576
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700577 eventChannel = datagridService.createChannel(
578 TopologyManager.EVENT_CHANNEL_NAME,
579 byte[].class,
580 TopologyEvent.class);
581
Yuta HIGUCHId92b10c2014-08-25 09:30:28 -0700582 mutableTopology = topologyService.getTopology();
Jonathan Hartb3e1b052014-04-02 16:01:12 -0700583
Jonathan Hart88770672014-04-02 18:08:30 -0700584 // Run the cleanup thread
585 String enableCleanup =
586 context.getConfigParams(this).get(ENABLE_CLEANUP_PROPERTY);
587 if (enableCleanup != null
588 && enableCleanup.equalsIgnoreCase("false")) {
589 cleanupEnabled = false;
590 }
Jonathan Hartb3e1b052014-04-02 16:01:12 -0700591
Jonathan Hart88770672014-04-02 18:08:30 -0700592 log.debug("Cleanup thread is {}enabled", (cleanupEnabled) ? "" : "not ");
Jonathan Hartb3e1b052014-04-02 16:01:12 -0700593
Jonathan Hart88770672014-04-02 18:08:30 -0700594 if (cleanupEnabled) {
595 IThreadPoolService threadPool =
596 context.getServiceImpl(IThreadPoolService.class);
597 cleanupTask = new SingletonTask(threadPool.getScheduledExecutor(),
598 new SwitchCleanup());
599 // Run the cleanup task immediately on startup
600 cleanupTask.reschedule(0, TimeUnit.SECONDS);
601 }
Pavlin Radoslavov24409672014-08-20 16:45:11 -0700602
603 // Run the Delayed Operations Handler thread
604 delayedOperationsHandler.start();
Jonathan Hart88770672014-04-02 18:08:30 -0700605 }
Jonathan Hartb3e1b052014-04-02 16:01:12 -0700606
Jonathan Hart88770672014-04-02 18:08:30 -0700607 @Override
Jonathan Hart03102132014-07-01 23:22:04 -0700608 public void hostAdded(Host host) {
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700609 log.debug("Host added with MAC {}", host.getMacAddress());
TeruUd1c5b652014-03-24 13:58:46 -0700610
Jonathan Hart03102132014-07-01 23:22:04 -0700611 SwitchPort sp = new SwitchPort(host.getSwitchDPID(), host.getSwitchPort());
Jonathan Hart88770672014-04-02 18:08:30 -0700612 List<SwitchPort> spLists = new ArrayList<SwitchPort>();
613 spLists.add(sp);
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700614 HostData hostData = new HostData(host.getMacAddress());
615 hostData.setAttachmentPoints(spLists);
616 hostData.setLastSeenTime(host.getLastSeenTimestamp().getTime());
Jonathan Hart88770672014-04-02 18:08:30 -0700617 // Does not use vlan info now.
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700618 hostData.freeze();
Jonathan Hartb3e1b052014-04-02 16:01:12 -0700619
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700620 publishAddHostEvent(hostData);
Jonathan Hart88770672014-04-02 18:08:30 -0700621 }
TeruUd1c5b652014-03-24 13:58:46 -0700622
Jonathan Hart88770672014-04-02 18:08:30 -0700623 @Override
Jonathan Hart03102132014-07-01 23:22:04 -0700624 public void hostRemoved(Host host) {
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700625 log.debug("Host removed with MAC {}", host.getMacAddress());
626
627 //
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700628 // Remove all previously added HostData for this MAC address
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700629 //
630 // TODO: Currently, the caller of hostRemoved() might not include
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700631 // the correct set of Attachment Points in the HostData entry itself.
632 // Also, we might have multiple HostData entries for the same
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700633 // host (MAC address), each containing a single (different) Attachment
634 // Point.
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700635 // Hence, here we have to cleanup all HostData entries for this
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700636 // particular host, based on its MAC address.
637 //
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700638 List<HostData> removeHostDataEntries = new LinkedList<>();
639 for (ConcurrentMap<ByteBuffer, HostData> cm : publishedHostDataEntries.values()) {
640 for (HostData hostData : cm.values()) {
641 if (hostData.getMac().equals(host.getMacAddress())) {
642 removeHostDataEntries.add(hostData);
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700643 }
644 }
645 }
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700646 for (HostData hostData : removeHostDataEntries) {
647 publishRemoveHostEvent(hostData);
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700648 }
Jonathan Hart88770672014-04-02 18:08:30 -0700649 }
Pavlin Radoslavov695f8952014-07-23 16:57:01 -0700650
Pavlin Radoslavov24409672014-08-20 16:45:11 -0700651 @Override
652 public boolean publish(TopologyBatchOperation tbo) {
653 publishTopologyOperations(tbo);
654 return true;
655 }
656
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700657 /**
658 * Prepares the Controller role changed event for a switch.
659 *
660 * @param dpid the switch DPID
661 * @param role the new role of the controller
662 */
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700663 private void controllerRoleChanged(Dpid dpid, Role role) {
664 log.debug("Local switch controller mastership role changed: dpid = {} role = {}",
665 dpid, role);
Yuta HIGUCHId8fd2f52014-09-01 23:19:45 -0700666 MastershipData mastershipData =
667 new MastershipData(dpid, getOnosInstanceId(), role);
Pavlin Radoslavov695f8952014-07-23 16:57:01 -0700668 // FIXME should be merging, with existing attrs, etc..
669 // TODO define attr name as constant somewhere.
670 // TODO populate appropriate attributes.
Yuta HIGUCHId8fd2f52014-09-01 23:19:45 -0700671 mastershipData.createStringAttribute(TopologyElement.TYPE,
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700672 TopologyElement.TYPE_ALL_LAYERS);
Yuta HIGUCHId8fd2f52014-09-01 23:19:45 -0700673 mastershipData.freeze();
674 publishAddSwitchMastershipEvent(mastershipData);
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700675 }
676
677 /**
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700678 * Publishes ADD Mastership Event.
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700679 *
Yuta HIGUCHId8fd2f52014-09-01 23:19:45 -0700680 * @param mastershipData the mastership event to publish
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700681 */
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700682 private void publishAddSwitchMastershipEvent(
Yuta HIGUCHId8fd2f52014-09-01 23:19:45 -0700683 MastershipData mastershipData) {
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700684 // Publish the information
Pavlin Radoslavov24409672014-08-20 16:45:11 -0700685 TopologyBatchOperation tbo = new TopologyBatchOperation();
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700686 TopologyEvent topologyEvent =
Yuta HIGUCHId8fd2f52014-09-01 23:19:45 -0700687 new TopologyEvent(mastershipData, getOnosInstanceId());
Pavlin Radoslavov24409672014-08-20 16:45:11 -0700688 tbo.appendAddOperation(topologyEvent);
689 publishTopologyOperations(tbo);
Yuta HIGUCHId8fd2f52014-09-01 23:19:45 -0700690 publishedMastershipDataEntries.put(mastershipData.getDpid(),
691 mastershipData);
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700692 }
693
694 /**
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700695 * Publishes REMOVE Mastership Event.
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700696 *
Yuta HIGUCHId8fd2f52014-09-01 23:19:45 -0700697 * @param mastershipData the mastership event to publish
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700698 */
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700699 private void publishRemoveSwitchMastershipEvent(
Yuta HIGUCHId8fd2f52014-09-01 23:19:45 -0700700 MastershipData mastershipData) {
701 if (publishedMastershipDataEntries.get(mastershipData.getDpid()) == null) {
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700702 return; // Nothing to do
703 }
704
705 // Publish the information
Pavlin Radoslavov24409672014-08-20 16:45:11 -0700706 TopologyBatchOperation tbo = new TopologyBatchOperation();
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700707 TopologyEvent topologyEvent =
Yuta HIGUCHId8fd2f52014-09-01 23:19:45 -0700708 new TopologyEvent(mastershipData, getOnosInstanceId());
Pavlin Radoslavov24409672014-08-20 16:45:11 -0700709 tbo.appendRemoveOperation(topologyEvent);
710 publishTopologyOperations(tbo);
Yuta HIGUCHId8fd2f52014-09-01 23:19:45 -0700711 publishedMastershipDataEntries.remove(mastershipData.getDpid());
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700712 }
713
714 /**
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700715 * Publishes ADD Switch Event.
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700716 *
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700717 * @param switchData the switch event to publish
718 * @param portDataEntries the corresponding port events for the switch to
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700719 * publish
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700720 */
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700721 private void publishAddSwitchEvent(SwitchData switchData,
722 Collection<PortData> portDataEntries) {
723 if (!registryService.hasControl(switchData.getOriginDpid().value())) {
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700724 log.debug("Not the master for switch {}. Suppressed switch add event {}.",
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700725 switchData.getOriginDpid(), switchData);
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700726 return;
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700727 }
728
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700729 // Keep track of the old Port Events that should be removed
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700730 ConcurrentMap<ByteBuffer, PortData> oldPortDataEntries =
731 publishedPortDataEntries.get(switchData.getDpid());
732 if (oldPortDataEntries == null) {
733 oldPortDataEntries = new ConcurrentHashMap<>();
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700734 }
735
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700736 // Publish the information for the switch
Pavlin Radoslavov24409672014-08-20 16:45:11 -0700737 TopologyBatchOperation tbo = new TopologyBatchOperation();
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700738 TopologyEvent topologyEvent =
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700739 new TopologyEvent(switchData, getOnosInstanceId());
Pavlin Radoslavov24409672014-08-20 16:45:11 -0700740 tbo.appendAddOperation(topologyEvent);
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700741
742 // Publish the information for each port
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700743 ConcurrentMap<ByteBuffer, PortData> newPortDataEntries =
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700744 new ConcurrentHashMap<>();
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700745 for (PortData portData : portDataEntries) {
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700746 topologyEvent =
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700747 new TopologyEvent(portData, getOnosInstanceId());
Pavlin Radoslavov24409672014-08-20 16:45:11 -0700748 tbo.appendAddOperation(topologyEvent);
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700749
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700750 ByteBuffer id = portData.getIDasByteBuffer();
751 newPortDataEntries.put(id, portData);
752 oldPortDataEntries.remove(id);
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700753 }
Pavlin Radoslavov24409672014-08-20 16:45:11 -0700754 publishTopologyOperations(tbo);
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700755 publishedSwitchDataEntries.put(switchData.getDpid(), switchData);
756 publishedPortDataEntries.put(switchData.getDpid(), newPortDataEntries);
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700757
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700758 // Cleanup for each of the old removed port
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700759 for (PortData portData : oldPortDataEntries.values()) {
760 publishRemovePortEvent(portData);
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700761 }
762 }
763
764 /**
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700765 * Publishes REMOVE Switch Event.
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700766 *
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700767 * @param switchData the switch event to publish
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700768 */
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700769 private void publishRemoveSwitchEvent(SwitchData switchData) {
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700770 //
771 // TODO: Removed the check for now, because currently this method is
772 // also called by the SwitchCleanup thread, and in that case
773 // the Switch Event was published by some other ONOS instance.
774 //
775 /*
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700776 if (publishedSwitchDataEntries.get(switchData.getDpid()) == null) {
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700777 return; // Nothing to do
778 }
779 */
780
781 // Publish the information
Pavlin Radoslavov24409672014-08-20 16:45:11 -0700782 TopologyBatchOperation tbo = new TopologyBatchOperation();
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700783 TopologyEvent topologyEvent =
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700784 new TopologyEvent(switchData, getOnosInstanceId());
Pavlin Radoslavov24409672014-08-20 16:45:11 -0700785 tbo.appendRemoveOperation(topologyEvent);
786 publishTopologyOperations(tbo);
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700787 publishedSwitchDataEntries.remove(switchData.getDpid());
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700788
789 // Cleanup for each port
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700790 ConcurrentMap<ByteBuffer, PortData> portDataEntries =
791 publishedPortDataEntries.get(switchData.getDpid());
792 if (portDataEntries != null) {
793 for (PortData portData : portDataEntries.values()) {
794 publishRemovePortEvent(portData);
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700795 }
796 }
797
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700798 publishedPortDataEntries.remove(switchData.getDpid());
799 publishedLinkDataEntries.remove(switchData.getDpid());
800 publishedHostDataEntries.remove(switchData.getDpid());
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700801 }
802
803 /**
804 * Publishes ADD Port Event.
805 *
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700806 * @param portData the port event to publish
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700807 */
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700808 private void publishAddPortEvent(PortData portData) {
809 if (!registryService.hasControl(portData.getOriginDpid().value())) {
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700810 log.debug("Not the master for switch {}. Suppressed port add event {}.",
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700811 portData.getOriginDpid(), portData);
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700812 return;
813 }
814
815 // Publish the information
Pavlin Radoslavov24409672014-08-20 16:45:11 -0700816 TopologyBatchOperation tbo = new TopologyBatchOperation();
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700817 TopologyEvent topologyEvent =
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700818 new TopologyEvent(portData, getOnosInstanceId());
Pavlin Radoslavov24409672014-08-20 16:45:11 -0700819 tbo.appendAddOperation(topologyEvent);
820 publishTopologyOperations(tbo);
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700821
822 // Store the new Port Event in the local cache
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700823 ConcurrentMap<ByteBuffer, PortData> portDataEntries =
824 ConcurrentUtils.putIfAbsent(publishedPortDataEntries,
825 portData.getDpid(),
826 new ConcurrentHashMap<ByteBuffer, PortData>());
827 portDataEntries.put(portData.getIDasByteBuffer(), portData);
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700828 }
829
830 /**
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700831 * Publishes REMOVE Port Event.
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700832 *
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700833 * @param portData the port event to publish
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700834 */
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700835 private void publishRemovePortEvent(PortData portData) {
836 ConcurrentMap<ByteBuffer, PortData> portDataEntries =
837 publishedPortDataEntries.get(portData.getDpid());
838 if (portDataEntries == null) {
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700839 return; // Nothing to do
840 }
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700841 if (portDataEntries.get(portData.getIDasByteBuffer()) == null) {
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700842 return; // Nothing to do
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700843 }
844
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700845 // Publish the information
Pavlin Radoslavov24409672014-08-20 16:45:11 -0700846 TopologyBatchOperation tbo = new TopologyBatchOperation();
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700847 TopologyEvent topologyEvent =
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700848 new TopologyEvent(portData, getOnosInstanceId());
Pavlin Radoslavov24409672014-08-20 16:45:11 -0700849 tbo.appendRemoveOperation(topologyEvent);
850 publishTopologyOperations(tbo);
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700851
852 // Cleanup for the incoming link(s)
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700853 ConcurrentMap<ByteBuffer, LinkData> linkDataEntries =
854 publishedLinkDataEntries.get(portData.getDpid());
855 if (linkDataEntries != null) {
856 for (LinkData linkData : linkDataEntries.values()) {
857 if (linkData.getDst().equals(portData.getSwitchPort())) {
858 publishRemoveLinkEvent(linkData);
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700859 }
860 }
861 }
862
863 // Cleanup for the connected hosts
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700864 ConcurrentMap<ByteBuffer, HostData> hostDataEntries =
865 publishedHostDataEntries.get(portData.getDpid());
866 if (hostDataEntries != null) {
867 for (HostData hostData : hostDataEntries.values()) {
868 for (SwitchPort swp : hostData.getAttachmentPoints()) {
869 if (swp.equals(portData.getSwitchPort())) {
870 publishRemoveHostEvent(hostData);
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700871 }
872 }
873 }
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700874 }
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700875
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700876 portDataEntries.remove(portData.getIDasByteBuffer());
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700877 }
878
879 /**
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700880 * Publishes ADD Link Event.
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700881 *
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700882 * @param linkData the link event to publish
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700883 */
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700884 private void publishAddLinkEvent(LinkData linkData) {
885 if (!registryService.hasControl(linkData.getOriginDpid().value())) {
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700886 log.debug("Not the master for dst switch {}. Suppressed link add event {}.",
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700887 linkData.getOriginDpid(), linkData);
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700888 return;
889 }
890
891 // Publish the information
Pavlin Radoslavov24409672014-08-20 16:45:11 -0700892 TopologyBatchOperation tbo = new TopologyBatchOperation();
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700893 TopologyEvent topologyEvent =
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700894 new TopologyEvent(linkData, getOnosInstanceId());
Pavlin Radoslavov24409672014-08-20 16:45:11 -0700895 tbo.appendAddOperation(topologyEvent);
896 publishTopologyOperations(tbo);
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700897
898 // Store the new Link Event in the local cache
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700899 ConcurrentMap<ByteBuffer, LinkData> linkDataEntries =
900 ConcurrentUtils.putIfAbsent(publishedLinkDataEntries,
901 linkData.getDst().getDpid(),
902 new ConcurrentHashMap<ByteBuffer, LinkData>());
903 linkDataEntries.put(linkData.getIDasByteBuffer(), linkData);
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700904 }
905
906 /**
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700907 * Publishes REMOVE Link Event.
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700908 *
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700909 * @param linkData the link event to publish
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700910 */
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700911 private void publishRemoveLinkEvent(LinkData linkData) {
912 ConcurrentMap<ByteBuffer, LinkData> linkDataEntries =
913 publishedLinkDataEntries.get(linkData.getDst().getDpid());
914 if (linkDataEntries == null) {
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700915 return; // Nothing to do
916 }
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700917 if (linkDataEntries.get(linkData.getIDasByteBuffer()) == null) {
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700918 return; // Nothing to do
919 }
920
921 // Publish the information
Pavlin Radoslavov24409672014-08-20 16:45:11 -0700922 TopologyBatchOperation tbo = new TopologyBatchOperation();
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700923 TopologyEvent topologyEvent =
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700924 new TopologyEvent(linkData, getOnosInstanceId());
Pavlin Radoslavov24409672014-08-20 16:45:11 -0700925 tbo.appendRemoveOperation(topologyEvent);
926 publishTopologyOperations(tbo);
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700927
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700928 linkDataEntries.remove(linkData.getIDasByteBuffer());
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700929 }
930
931 /**
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700932 * Publishes ADD Host Event.
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700933 *
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700934 * @param hostData the host event to publish
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700935 */
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700936 private void publishAddHostEvent(HostData hostData) {
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700937 //
938 // NOTE: The implementation below assumes that there is just one
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700939 // attachment point stored in hostData. Currently, this assumption
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700940 // is true based on the existing implementation of the caller
941 // hostAdded().
942 //
943
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700944 if (!registryService.hasControl(hostData.getOriginDpid().value())) {
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700945 log.debug("Not the master for attachment switch {}. Suppressed host add event {}.",
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700946 hostData.getOriginDpid(), hostData);
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700947 return;
948 }
949
950 // Publish the information
Pavlin Radoslavov24409672014-08-20 16:45:11 -0700951 TopologyBatchOperation tbo = new TopologyBatchOperation();
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700952 TopologyEvent topologyEvent =
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700953 new TopologyEvent(hostData, getOnosInstanceId());
Pavlin Radoslavov24409672014-08-20 16:45:11 -0700954 tbo.appendAddOperation(topologyEvent);
955 publishTopologyOperations(tbo);
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700956
957 // Store the new Host Event in the local cache
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700958 ConcurrentMap<ByteBuffer, HostData> hostDataEntries =
959 ConcurrentUtils.putIfAbsent(publishedHostDataEntries,
960 hostData.getOriginDpid(),
961 new ConcurrentHashMap<ByteBuffer, HostData>());
962 hostDataEntries.put(hostData.getIDasByteBuffer(), hostData);
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700963 }
964
965 /**
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700966 * Publishes REMOVE Host Event.
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700967 *
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700968 * @param hostData the host event to publish
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700969 */
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700970 private void publishRemoveHostEvent(HostData hostData) {
971 ConcurrentMap<ByteBuffer, HostData> hostDataEntries =
972 publishedHostDataEntries.get(hostData.getOriginDpid());
973 if (hostDataEntries == null) {
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700974 return; // Nothing to do
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700975 }
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700976 if (hostDataEntries.get(hostData.getIDasByteBuffer()) == null) {
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700977 return; // Nothing to do
978 }
979
980 // Publish the information
Pavlin Radoslavov24409672014-08-20 16:45:11 -0700981 TopologyBatchOperation tbo = new TopologyBatchOperation();
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700982 TopologyEvent topologyEvent =
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700983 new TopologyEvent(hostData, getOnosInstanceId());
Pavlin Radoslavov24409672014-08-20 16:45:11 -0700984 tbo.appendRemoveOperation(topologyEvent);
985 publishTopologyOperations(tbo);
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700986
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700987 hostDataEntries.remove(hostData.getIDasByteBuffer());
Pavlin Radoslavov695f8952014-07-23 16:57:01 -0700988 }
Pavlin Radoslavov24409672014-08-20 16:45:11 -0700989
990 /**
991 * Publishes Topology Operations.
992 *
993 * @param tbo the Topology Operations to publish
994 */
995 private void publishTopologyOperations(TopologyBatchOperation tbo) {
996 // TODO: This flag should be configurable
997 boolean isGlobalLogWriter = false;
998
999 log.debug("Publishing: {}", tbo);
1000
1001 if (isGlobalLogWriter) {
1002 if (!topologyService.publish(tbo)) {
1003 log.debug("Cannot publish: {}", tbo);
1004 delayedOperations.add(tbo);
1005 }
1006 } else {
1007 // TODO: For now we publish each TopologyEvent independently
1008 for (BatchOperationEntry<TopologyBatchOperation.Operator,
1009 TopologyEvent> boe : tbo.getOperations()) {
1010 TopologyBatchOperation.Operator oper = boe.getOperator();
1011 TopologyEvent topologyEvent = boe.getTarget();
1012 switch (oper) {
1013 case ADD:
1014 eventChannel.addEntry(topologyEvent.getID(),
1015 topologyEvent);
1016 break;
1017 case REMOVE:
1018 eventChannel.removeEntry(topologyEvent.getID());
1019 break;
1020 default:
1021 log.error("Unknown Topology Batch Operation {}", oper);
1022 break;
1023 }
1024 }
1025 }
1026 }
Jonathan Hart4b5bbb52014-02-06 10:09:31 -08001027}