blob: 66e1b887067e5e3bb8c0d8f7873bd93992d91257 [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;
Saurav Das2d41a432014-10-21 20:40:10 -070019import net.floodlightcontroller.core.IOF13Switch;
Jonathan Hart4b5bbb52014-02-06 10:09:31 -080020import net.floodlightcontroller.core.IOFSwitch;
Brian O'Connorc67f9fa2014-08-07 18:17:46 -070021import net.floodlightcontroller.core.IOFSwitch.PortChangeType;
22import net.floodlightcontroller.core.IOFSwitchListener;
Jonathan Hart4b5bbb52014-02-06 10:09:31 -080023import net.floodlightcontroller.core.module.FloodlightModuleContext;
24import net.floodlightcontroller.core.module.FloodlightModuleException;
25import net.floodlightcontroller.core.module.IFloodlightModule;
26import net.floodlightcontroller.core.module.IFloodlightService;
Jonathan Hart369875b2014-02-13 10:00:31 -080027import net.floodlightcontroller.core.util.SingletonTask;
28import net.floodlightcontroller.threadpool.IThreadPoolService;
Pavlin Radoslavov24409672014-08-20 16:45:11 -070029import net.onrc.onos.api.batchoperation.BatchOperationEntry;
Saurav Dasfb93c252014-08-18 20:40:13 -070030import net.onrc.onos.core.configmanager.INetworkConfigService;
31import net.onrc.onos.core.configmanager.INetworkConfigService.LinkConfigStatus;
32import net.onrc.onos.core.configmanager.INetworkConfigService.NetworkConfigState;
33import net.onrc.onos.core.configmanager.INetworkConfigService.SwitchConfigStatus;
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -070034import net.onrc.onos.core.datagrid.IDatagridService;
35import net.onrc.onos.core.datagrid.IEventChannel;
Jonathan Hart03102132014-07-01 23:22:04 -070036import net.onrc.onos.core.hostmanager.Host;
37import net.onrc.onos.core.hostmanager.IHostListener;
38import net.onrc.onos.core.hostmanager.IHostService;
Jonathan Hart23701d12014-04-03 10:45:48 -070039import net.onrc.onos.core.linkdiscovery.ILinkDiscoveryListener;
40import net.onrc.onos.core.linkdiscovery.ILinkDiscoveryService;
Jonathan Hart284e70f2014-07-05 12:32:51 -070041import net.onrc.onos.core.linkdiscovery.Link;
Jonathan Hartdeda0ba2014-04-03 11:14:12 -070042import net.onrc.onos.core.registry.IControllerRegistryService;
Jonathan Hartdeda0ba2014-04-03 11:14:12 -070043import net.onrc.onos.core.registry.IControllerRegistryService.ControlChangeCallback;
Jonathan Harta99ec672014-04-03 11:30:34 -070044import net.onrc.onos.core.registry.RegistryException;
Yuta HIGUCHI5bbbaca2014-06-09 16:39:08 -070045import net.onrc.onos.core.util.Dpid;
Jonathan Hart8c802b42014-09-08 15:40:48 -070046import net.onrc.onos.core.util.LinkTuple;
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -070047import net.onrc.onos.core.util.OnosInstanceId;
Yuta HIGUCHIa507baf2014-08-22 13:42:40 -070048import net.onrc.onos.core.util.PortNumberUtils;
Yuta HIGUCHI5c8cbeb2014-06-27 11:13:48 -070049import net.onrc.onos.core.util.SwitchPort;
Jonathan Hart4b5bbb52014-02-06 10:09:31 -080050
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -070051import org.apache.commons.lang3.concurrent.ConcurrentUtils;
Brian O'Connorc67f9fa2014-08-07 18:17:46 -070052import org.projectfloodlight.openflow.protocol.OFPortDesc;
53import org.projectfloodlight.openflow.util.HexString;
Toshio Koide2f570c12014-02-06 16:55:32 -080054import org.slf4j.Logger;
55import org.slf4j.LoggerFactory;
Jonathan Hart4b5bbb52014-02-06 10:09:31 -080056
Jonathan Hart88770672014-04-02 18:08:30 -070057/**
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -070058 * Class for publishing topology-related events.
59 *
60 * The events are received from the discovery modules, reformatted and
61 * published to the other ONOS instances.
62 *
63 * TODO: Add a synchronization mechanism when publishing the events to
64 * preserve the ordering and to avoid mismatch in the local "published" state,
65 * because each of the caller (the discovery modules) might be running
66 * on a different thread.
Jonathan Hart88770672014-04-02 18:08:30 -070067 */
Brian O'Connorc67f9fa2014-08-07 18:17:46 -070068public class TopologyPublisher implements IOFSwitchListener,
Ray Milkey269ffb92014-04-03 14:43:30 -070069 ILinkDiscoveryListener,
70 IFloodlightModule,
Pavlin Radoslavov24409672014-08-20 16:45:11 -070071 IHostListener,
72 ITopologyPublisherService {
Jonathan Hart88770672014-04-02 18:08:30 -070073 private static final Logger log =
Jonathan Harte37e4e22014-05-13 19:12:02 -070074 LoggerFactory.getLogger(TopologyPublisher.class);
Yuta HIGUCHIcb951982014-02-11 13:31:44 -080075
Jonathan Hart88770672014-04-02 18:08:30 -070076 private IFloodlightProviderService floodlightProvider;
77 private ILinkDiscoveryService linkDiscovery;
78 private IControllerRegistryService registryService;
Jonathan Harte37e4e22014-05-13 19:12:02 -070079 private ITopologyService topologyService;
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -070080 private IDatagridService datagridService;
Toshio Koide2f570c12014-02-06 16:55:32 -080081
Jonathan Hart03102132014-07-01 23:22:04 -070082 private IHostService hostService;
Yuta HIGUCHId92b10c2014-08-25 09:30:28 -070083 private MutableTopology mutableTopology;
Saurav Dasfb93c252014-08-18 20:40:13 -070084 private INetworkConfigService networkConfigService;
Jonathan Hartb3e1b052014-04-02 16:01:12 -070085
Jonathan Hart88770672014-04-02 18:08:30 -070086 private static final String ENABLE_CLEANUP_PROPERTY = "EnableCleanup";
87 private boolean cleanupEnabled = true;
88 private static final int CLEANUP_TASK_INTERVAL = 60; // in seconds
89 private SingletonTask cleanupTask;
Pavlin Radoslavov24409672014-08-20 16:45:11 -070090 private DelayedOperationsHandler delayedOperationsHandler =
91 new DelayedOperationsHandler();
Toshio Koide2f570c12014-02-06 16:55:32 -080092
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -070093 private IEventChannel<byte[], TopologyEvent> eventChannel;
94
95 //
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -070096 // Local state for keeping track of locally published events so we can
97 // cleanup properly when an entry is removed.
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -070098 //
99 // We keep all Port, (incoming) Link and Host events per Switch DPID:
100 // - If a switch goes down, we remove all corresponding Port, Link and
101 // Host events.
102 // - If a port on a switch goes down, we remove all corresponding Link
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700103 // and Host events attached to this port.
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700104 //
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700105 // TODO: What to do if the Mastership changes?
106 // - Cleanup state from publishedFoo maps, but do not send REMOVE events?
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700107 //
Yuta HIGUCHId8fd2f52014-09-01 23:19:45 -0700108 private ConcurrentMap<Dpid, MastershipData> publishedMastershipDataEntries =
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700109 new ConcurrentHashMap<>();
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700110 private ConcurrentMap<Dpid, SwitchData> publishedSwitchDataEntries =
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700111 new ConcurrentHashMap<>();
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700112 private ConcurrentMap<Dpid, ConcurrentMap<ByteBuffer, PortData>>
113 publishedPortDataEntries = new ConcurrentHashMap<>();
114 private ConcurrentMap<Dpid, ConcurrentMap<ByteBuffer, LinkData>>
115 publishedLinkDataEntries = new ConcurrentHashMap<>();
116 private ConcurrentMap<Dpid, ConcurrentMap<ByteBuffer, HostData>>
117 publishedHostDataEntries = new ConcurrentHashMap<>();
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700118
Pavlin Radoslavov24409672014-08-20 16:45:11 -0700119 private BlockingQueue<TopologyBatchOperation> delayedOperations =
120 new LinkedBlockingQueue<>();
121
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700122
Jonathan Hart369875b2014-02-13 10:00:31 -0800123 /**
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700124 * Gets the ONOS Instance ID.
125 *
126 * @return the ONOS Instance ID.
127 */
128 private OnosInstanceId getOnosInstanceId() {
129 return registryService.getOnosInstanceId();
130 }
131
132 /**
133 * Cleanup old switches from the topology. Old switches are those which
134 * have no controller in the registry.
135 *
136 * TODO: The overall switch cleanup mechanism needs refactoring/redesign.
Jonathan Hart369875b2014-02-13 10:00:31 -0800137 */
138 private class SwitchCleanup implements ControlChangeCallback, Runnable {
139 @Override
140 public void run() {
141 String old = Thread.currentThread().getName();
142 Thread.currentThread().setName("SwitchCleanup@" + old);
Jonathan Hartb3e1b052014-04-02 16:01:12 -0700143
Jonathan Hart369875b2014-02-13 10:00:31 -0800144 try {
Jonathan Hart88770672014-04-02 18:08:30 -0700145 if (log.isTraceEnabled()) {
146 log.trace("Running cleanup thread");
147 }
Jonathan Hart369875b2014-02-13 10:00:31 -0800148 switchCleanup();
Jonathan Hart369875b2014-02-13 10:00:31 -0800149 } finally {
150 cleanupTask.reschedule(CLEANUP_TASK_INTERVAL,
Jonathan Hart88770672014-04-02 18:08:30 -0700151 TimeUnit.SECONDS);
Jonathan Hart369875b2014-02-13 10:00:31 -0800152 Thread.currentThread().setName(old);
153 }
154 }
Jonathan Hartb3e1b052014-04-02 16:01:12 -0700155
Jonathan Hart88770672014-04-02 18:08:30 -0700156 /**
157 * First half of the switch cleanup operation. This method will attempt
158 * to get control of any switch it sees without a controller via the
159 * registry.
160 */
Jonathan Hart369875b2014-02-13 10:00:31 -0800161 private void switchCleanup() {
Yuta HIGUCHId92b10c2014-08-25 09:30:28 -0700162 Iterable<Switch> switches = mutableTopology.getSwitches();
Jonathan Hart369875b2014-02-13 10:00:31 -0800163
Jonathan Hart88770672014-04-02 18:08:30 -0700164 if (log.isTraceEnabled()) {
165 log.trace("Checking for inactive switches");
166 }
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700167 // For each switch check if a controller exists in controller
168 // registry
Ray Milkey269ffb92014-04-03 14:43:30 -0700169 for (Switch sw : switches) {
Praseed Balakrishnane82adc62014-08-04 10:59:24 -0700170 // FIXME How to handle case where Switch has never been
171 // registered to ZK
172 if (sw.getConfigState() == ConfigState.CONFIGURED) {
173 continue;
174 }
Jonathan Hart88770672014-04-02 18:08:30 -0700175 try {
176 String controller =
Yuta HIGUCHI8f3dfa32014-06-25 00:14:25 -0700177 registryService.getControllerForSwitch(sw.getDpid().value());
Jonathan Hart88770672014-04-02 18:08:30 -0700178 if (controller == null) {
179 log.debug("Requesting control to set switch {} INACTIVE",
Yuta HIGUCHI8f3dfa32014-06-25 00:14:25 -0700180 sw.getDpid());
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700181 registryService.requestControl(sw.getDpid().value(),
182 this);
Jonathan Hart88770672014-04-02 18:08:30 -0700183 }
184 } catch (RegistryException e) {
185 log.error("Caught RegistryException in cleanup thread", e);
186 }
187 }
Jonathan Hart369875b2014-02-13 10:00:31 -0800188 }
189
Jonathan Hart88770672014-04-02 18:08:30 -0700190 /**
191 * Second half of the switch cleanup operation. If the registry grants
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700192 * control of a switch, we can be sure no other instance is writing
193 * this switch to the topology, so we can remove it now.
194 *
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700195 * @param dpid the dpid of the switch we requested control for
Jonathan Hart88770672014-04-02 18:08:30 -0700196 * @param hasControl whether we got control or not
197 */
198 @Override
199 public void controlChanged(long dpid, boolean hasControl) {
200 if (hasControl) {
201 log.debug("Got control to set switch {} INACTIVE",
202 HexString.toHexString(dpid));
Jonathan Harte02cf542014-04-02 16:24:44 -0700203
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700204 SwitchData switchData = new SwitchData(new Dpid(dpid));
205 publishRemoveSwitchEvent(switchData);
Jonathan Hart88770672014-04-02 18:08:30 -0700206 registryService.releaseControl(dpid);
207 }
208 }
Jonathan Hart369875b2014-02-13 10:00:31 -0800209 }
Jonathan Hart4b5bbb52014-02-06 10:09:31 -0800210
Pavlin Radoslavov24409672014-08-20 16:45:11 -0700211 /**
212 * A class to deal with Topology Operations that couldn't be pushed
213 * to the Global Log writer, because they need to be delayed.
214 * For example, a link cannot be pushed before the switches on both
215 * ends are in the Global Log.
216 *
217 * TODO: This is an ugly hack that should go away: right now we have to
218 * keep trying periodically.
219 * TODO: Currently, we retry only ADD Link Events, everything else
220 * is thrown away.
221 */
222 private class DelayedOperationsHandler extends Thread {
223 private static final long RETRY_INTERVAL_MS = 10; // 10ms
224
225 @Override
226 public void run() {
227 List<TopologyBatchOperation> operations = new LinkedList<>();
228
229 this.setName("TopologyPublisher.DelayedOperationsHandler " +
230 this.getId());
231 //
232 // The main loop
233 //
234 while (true) {
235 try {
236 //
237 // Block-waiting for an operation to be added, sleep
238 // and try to publish it again.
239 //
240 TopologyBatchOperation firstTbo = delayedOperations.take();
241 Thread.sleep(RETRY_INTERVAL_MS);
242 operations.add(firstTbo);
243 delayedOperations.drainTo(operations);
244
245 // Retry only the appropriate operations
246 for (TopologyBatchOperation tbo : operations) {
247 for (BatchOperationEntry<
248 TopologyBatchOperation.Operator,
249 TopologyEvent> boe : tbo.getOperations()) {
250 TopologyBatchOperation.Operator oper =
251 boe.getOperator();
252 switch (oper) {
253 case ADD:
254 TopologyEvent topologyEvent = boe.getTarget();
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700255 LinkData linkData =
256 topologyEvent.getLinkData();
Pavlin Radoslavov24409672014-08-20 16:45:11 -0700257 //
258 // Test whether the Link Event still can be
259 // published.
260 // TODO: The implementation below has a bug:
261 // If it happens that the same Link Event was
262 // removed in the middle of checking, we might
263 // incorrectly publish it again from here.
264 //
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700265 if (linkData == null) {
Pavlin Radoslavov24409672014-08-20 16:45:11 -0700266 break;
267 }
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700268 ConcurrentMap<ByteBuffer, LinkData>
269 linkDataEntries = publishedLinkDataEntries.get(
270 linkData.getDst().getDpid());
271 if (linkDataEntries == null) {
Pavlin Radoslavov24409672014-08-20 16:45:11 -0700272 break;
273 }
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700274 if (linkDataEntries.get(linkData.getIDasByteBuffer()) == null) {
Pavlin Radoslavov24409672014-08-20 16:45:11 -0700275 break;
276 }
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700277 publishAddLinkEvent(linkData);
Pavlin Radoslavov24409672014-08-20 16:45:11 -0700278 break;
279 case REMOVE:
280 break;
281 default:
282 log.error("Unknown Topology Batch Operation {}", oper);
283 break;
284 }
285 }
286 }
287 } catch (InterruptedException exception) {
288 log.debug("Exception processing delayed operations: ",
289 exception);
290 }
291 }
292 }
293 }
294
Jonathan Hart88770672014-04-02 18:08:30 -0700295 @Override
Jonathan Hart284e70f2014-07-05 12:32:51 -0700296 public void linkAdded(Link link) {
Jonathan Hart8c802b42014-09-08 15:40:48 -0700297 LinkTuple linkTuple = new LinkTuple(
298 new SwitchPort(link.getSrc(), link.getSrcPort()),
299 new SwitchPort(link.getDst(), link.getDstPort()));
300
301 LinkConfigStatus ret = networkConfigService.checkLinkConfig(linkTuple);
Saurav Dasfb93c252014-08-18 20:40:13 -0700302 if (ret.getConfigState() == NetworkConfigState.DENY) {
303 log.warn("Discovered {} denied by configuration. {} "
304 + "Not allowing it to proceed.", link, ret.getMsg());
305 return;
306 }
307
Jonathan Hart8c802b42014-09-08 15:40:48 -0700308 LinkData linkData = new LinkData(linkTuple);
Jonathan Hart284e70f2014-07-05 12:32:51 -0700309
Yuta HIGUCHIbf0a8712014-06-30 18:59:46 -0700310 // FIXME should be merging, with existing attrs, etc..
311 // TODO define attr name as constant somewhere.
312 // TODO populate appropriate attributes.
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700313 linkData.createStringAttribute(TopologyElement.TYPE,
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700314 TopologyElement.TYPE_PACKET_LAYER);
Saurav Dasfb93c252014-08-18 20:40:13 -0700315 if (ret.getConfigState() == NetworkConfigState.ACCEPT_ADD) {
316 Map<String, String> attr = ret.getLinkConfig().getPublishAttributes();
317 for (Entry<String, String> e : attr.entrySet()) {
318 linkData.createStringAttribute(e.getKey(), e.getValue());
319 }
320 linkData.createStringAttribute(TopologyElement.ELEMENT_CONFIG_STATE,
321 ConfigState.CONFIGURED.toString());
322 } else {
323 linkData.createStringAttribute(TopologyElement.ELEMENT_CONFIG_STATE,
324 ConfigState.NOT_CONFIGURED.toString());
325 }
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700326 linkData.createStringAttribute(TopologyElement.ELEMENT_ADMIN_STATUS,
Praseed Balakrishnan2aa6c0b2014-07-17 11:42:05 -0700327 AdminStatus.ACTIVE.toString());
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700328 linkData.freeze();
Jonathan Hartb3e1b052014-04-02 16:01:12 -0700329
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700330 publishAddLinkEvent(linkData);
Jonathan Hart284e70f2014-07-05 12:32:51 -0700331 }
332
333 @Override
334 public void linkRemoved(Link link) {
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700335 LinkData linkData = new LinkData(
Jonathan Hart284e70f2014-07-05 12:32:51 -0700336 new SwitchPort(link.getSrc(), link.getSrcPort()),
337 new SwitchPort(link.getDst(), link.getDstPort()));
338
339 // FIXME should be merging, with existing attrs, etc..
340 // TODO define attr name as constant somewhere.
341 // TODO populate appropriate attributes.
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700342 linkData.createStringAttribute(TopologyElement.TYPE,
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700343 TopologyElement.TYPE_PACKET_LAYER);
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700344 linkData.freeze();
Jonathan Hart284e70f2014-07-05 12:32:51 -0700345
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700346 publishRemoveLinkEvent(linkData);
Jonathan Hart88770672014-04-02 18:08:30 -0700347 }
Jonathan Hart4b5bbb52014-02-06 10:09:31 -0800348
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700349 /* *****************
350 * IOFSwitchListener
351 * *****************/
352
Jonathan Hart88770672014-04-02 18:08:30 -0700353 @Override
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700354 public void switchActivatedMaster(long swId) {
355 IOFSwitch sw = floodlightProvider.getSwitch(swId);
356 final Dpid dpid = new Dpid(swId);
357 if (sw == null) {
358 log.warn("Added switch not available {} ", dpid);
359 return;
360 }
361
Saurav Dasfb93c252014-08-18 20:40:13 -0700362 SwitchConfigStatus ret = networkConfigService.checkSwitchConfig(dpid);
363 if (ret.getConfigState() == NetworkConfigState.DENY) {
364 log.warn("Activated switch {} denied by network configuration. {} "
365 + "Not allowing it to proceed.", dpid, ret.getMsg());
366 return;
367 }
368
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700369 controllerRoleChanged(dpid, Role.MASTER);
370
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700371 SwitchData switchData = new SwitchData(dpid);
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700372 // FIXME should be merging, with existing attrs, etc..
373 // TODO define attr name as constant somewhere.
374 // TODO populate appropriate attributes.
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700375 switchData.createStringAttribute(TopologyElement.TYPE,
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700376 TopologyElement.TYPE_PACKET_LAYER);
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700377 switchData.createStringAttribute("ConnectedSince",
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700378 sw.getConnectedSince().toString());
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700379 switchData.createStringAttribute(TopologyElement.ELEMENT_ADMIN_STATUS,
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700380 AdminStatus.ACTIVE.toString());
Saurav Dasd0977442014-09-29 10:36:14 -0700381 // setting name from configuration (if it exists).
382 if (ret.getSwitchConfig() != null) {
383 switchData.createStringAttribute("name",
384 ret.getSwitchConfig().getName());
385 }
Fahad Naeem Khan1f8fb2e2014-09-25 16:39:18 -0700386 //set the switch socketAddress and port
387 switchData.createStringAttribute("remoteAddress",
388 sw.getChannelSocketAddress().toString().substring(1));
Saurav Dasfb93c252014-08-18 20:40:13 -0700389 if (ret.getConfigState() == NetworkConfigState.ACCEPT_ADD) {
390 Map<String, String> attr = ret.getSwitchConfig().getPublishAttributes();
391 for (Entry<String, String> e : attr.entrySet()) {
392 switchData.createStringAttribute(e.getKey(), e.getValue());
393 }
Saurav Das2d41a432014-10-21 20:40:10 -0700394 if (sw instanceof IOF13Switch) {
395 Map<String, String> pa = ((IOF13Switch) sw).getPublishAttributes();
396 for (Entry<String, String> e : pa.entrySet()) {
397 switchData.createStringAttribute(e.getKey(), e.getValue());
398 }
399 }
Saurav Dasfb93c252014-08-18 20:40:13 -0700400 switchData.createStringAttribute(TopologyElement.ELEMENT_CONFIG_STATE,
401 ConfigState.CONFIGURED.toString());
402 } else {
403 switchData.createStringAttribute(TopologyElement.ELEMENT_CONFIG_STATE,
404 ConfigState.NOT_CONFIGURED.toString());
405 }
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700406 switchData.freeze();
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700407 // The Port events
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700408 List<PortData> portDataEntries = new ArrayList<PortData>();
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700409 for (OFPortDesc port : sw.getPorts()) {
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700410 PortData portData = new PortData(dpid,
Yuta HIGUCHIa507baf2014-08-22 13:42:40 -0700411 PortNumberUtils.openFlow(port));
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700412 // FIXME should be merging, with existing attrs, etc..
413 // TODO define attr name as constant somewhere.
414 // TODO populate appropriate attributes.
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700415 portData.createStringAttribute("name", port.getName());
416 portData.createStringAttribute(TopologyElement.TYPE,
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700417 TopologyElement.TYPE_PACKET_LAYER);
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700418 portData.createStringAttribute(TopologyElement.ELEMENT_CONFIG_STATE,
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700419 ConfigState.NOT_CONFIGURED.toString());
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700420 portData.createStringAttribute(TopologyElement.ELEMENT_ADMIN_STATUS,
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700421 AdminStatus.ACTIVE.toString());
422
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700423 portData.freeze();
424 portDataEntries.add(portData);
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700425 }
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700426 publishAddSwitchEvent(switchData, portDataEntries);
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700427 }
428
429 @Override
430 public void switchActivatedEqual(long swId) {
431 final Dpid dpid = new Dpid(swId);
432 controllerRoleChanged(dpid, Role.EQUAL);
433 }
434
435 @Override
436 public void switchMasterToEqual(long swId) {
437 final Dpid dpid = new Dpid(swId);
438 controllerRoleChanged(dpid, Role.EQUAL);
439 }
440
441 @Override
442 public void switchEqualToMaster(long swId) {
443 // for now treat as switchActivatedMaster
444 switchActivatedMaster(swId);
445 }
446
447 @Override
448 public void switchDisconnected(long swId) {
449 final Dpid dpid = new Dpid(swId);
450
451 log.debug("Local switch disconnected: dpid = {} role = {}", dpid);
452
453 Role role = Role.SLAVE; // TODO: Should be Role.UNKNOWN
454
Yuta HIGUCHId8fd2f52014-09-01 23:19:45 -0700455 MastershipData mastershipData =
456 new MastershipData(dpid, getOnosInstanceId(), role);
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700457 // FIXME should be merging, with existing attrs, etc..
458 // TODO define attr name as constant somewhere.
459 // TODO populate appropriate attributes.
Yuta HIGUCHId8fd2f52014-09-01 23:19:45 -0700460 mastershipData.createStringAttribute(TopologyElement.TYPE,
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700461 TopologyElement.TYPE_ALL_LAYERS);
Yuta HIGUCHId8fd2f52014-09-01 23:19:45 -0700462 mastershipData.freeze();
463 publishRemoveSwitchMastershipEvent(mastershipData);
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700464 }
465
466 @Override
467 public void switchPortChanged(long swId, OFPortDesc port,
468 PortChangeType changeType) {
469 switch (changeType) {
470 case ADD:
471 switchPortAdded(swId, port);
472 break;
473 case DELETE:
474 switchPortRemoved(swId, port);
475 break;
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700476 case UP:
Pavlin Radoslavov7946c612014-08-13 15:06:00 -0700477 // NOTE: Currently, we treat Port UP/DOWN same as Port ADD/DELETE
478 switchPortAdded(swId, port);
479 break;
480 case DOWN:
481 // NOTE: Currently, we treat Port UP/DOWN same as Port ADD/DELETE
482 switchPortRemoved(swId, port);
483 break;
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700484 case OTHER_UPDATE:
485 default:
486 // XXX S what is the right set of port change handlers?
487 log.debug("Topology publisher does not handle these port updates: {}",
488 changeType);
489 }
490 }
491
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700492 /**
493 * Prepares an event for adding a port on a switch.
494 *
495 * @param switchId the switch ID (DPID)
496 * @param port the port to add
497 */
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700498 private void switchPortAdded(long switchId, OFPortDesc port) {
Yuta HIGUCHIbf0a8712014-06-30 18:59:46 -0700499 final Dpid dpid = new Dpid(switchId);
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700500 final PortData portData = new PortData(dpid,
Yuta HIGUCHIa507baf2014-08-22 13:42:40 -0700501 PortNumberUtils.openFlow(port));
Yuta HIGUCHIbf0a8712014-06-30 18:59:46 -0700502 // FIXME should be merging, with existing attrs, etc..
503 // TODO define attr name as constant somewhere.
504 // TODO populate appropriate attributes.
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700505 portData.createStringAttribute(TopologyElement.TYPE,
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700506 TopologyElement.TYPE_PACKET_LAYER);
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700507 portData.createStringAttribute("name", port.getName());
508 portData.freeze();
Yuta HIGUCHIbf0a8712014-06-30 18:59:46 -0700509
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700510 publishAddPortEvent(portData);
Jonathan Hart88770672014-04-02 18:08:30 -0700511 }
Jonathan Hart4b5bbb52014-02-06 10:09:31 -0800512
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700513 /**
514 * Prepares an event for removing a port on a switch.
515 *
516 * @param switchId the switch ID (DPID)
517 * @param port the port to remove
518 */
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700519 private void switchPortRemoved(long switchId, OFPortDesc port) {
Yuta HIGUCHIe2a4e172014-07-03 10:50:39 -0700520 final Dpid dpid = new Dpid(switchId);
Yuta HIGUCHI5bbbaca2014-06-09 16:39:08 -0700521
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700522 final PortData portData = new PortData(dpid,
Yuta HIGUCHIa507baf2014-08-22 13:42:40 -0700523 PortNumberUtils.openFlow(port));
Yuta HIGUCHI1222ac52014-07-09 16:50:28 -0700524 // FIXME should be merging, with existing attrs, etc..
525 // TODO define attr name as constant somewhere.
526 // TODO populate appropriate attributes.
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700527 portData.createStringAttribute(TopologyElement.TYPE,
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700528 TopologyElement.TYPE_PACKET_LAYER);
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700529 portData.createStringAttribute("name", port.getName());
530 portData.freeze();
Yuta HIGUCHI1222ac52014-07-09 16:50:28 -0700531
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700532 publishRemovePortEvent(portData);
Jonathan Hart88770672014-04-02 18:08:30 -0700533 }
Jonathan Hart4b5bbb52014-02-06 10:09:31 -0800534
Jonathan Hart88770672014-04-02 18:08:30 -0700535 @Override
Jonathan Hart88770672014-04-02 18:08:30 -0700536 public String getName() {
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700537 return "topologyPublisher";
Jonathan Hart88770672014-04-02 18:08:30 -0700538 }
Jonathan Hart4b5bbb52014-02-06 10:09:31 -0800539
Jonathan Hart88770672014-04-02 18:08:30 -0700540 /* *****************
541 * IFloodlightModule
542 * *****************/
Toshio Koide2f570c12014-02-06 16:55:32 -0800543
Jonathan Hart88770672014-04-02 18:08:30 -0700544 @Override
545 public Collection<Class<? extends IFloodlightService>> getModuleServices() {
Pavlin Radoslavov24409672014-08-20 16:45:11 -0700546 List<Class<? extends IFloodlightService>> services =
547 new ArrayList<Class<? extends IFloodlightService>>();
548 services.add(ITopologyPublisherService.class);
549 return services;
Jonathan Hart88770672014-04-02 18:08:30 -0700550 }
Jonathan Hart4b5bbb52014-02-06 10:09:31 -0800551
Jonathan Hart88770672014-04-02 18:08:30 -0700552 @Override
553 public Map<Class<? extends IFloodlightService>, IFloodlightService>
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700554 getServiceImpls() {
Pavlin Radoslavov24409672014-08-20 16:45:11 -0700555 Map<Class<? extends IFloodlightService>, IFloodlightService> impls =
556 new HashMap<Class<? extends IFloodlightService>, IFloodlightService>();
557 impls.put(ITopologyPublisherService.class, this);
558 return impls;
Jonathan Hart88770672014-04-02 18:08:30 -0700559 }
Jonathan Hart4b5bbb52014-02-06 10:09:31 -0800560
Jonathan Hart88770672014-04-02 18:08:30 -0700561 @Override
562 public Collection<Class<? extends IFloodlightService>>
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700563 getModuleDependencies() {
Jonathan Hart88770672014-04-02 18:08:30 -0700564 Collection<Class<? extends IFloodlightService>> l =
565 new ArrayList<Class<? extends IFloodlightService>>();
Jonathan Hart4b5bbb52014-02-06 10:09:31 -0800566 l.add(IFloodlightProviderService.class);
567 l.add(ILinkDiscoveryService.class);
Jonathan Hart369875b2014-02-13 10:00:31 -0800568 l.add(IThreadPoolService.class);
Jonathan Hart4b5bbb52014-02-06 10:09:31 -0800569 l.add(IControllerRegistryService.class);
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700570 l.add(IDatagridService.class);
Jonathan Harte37e4e22014-05-13 19:12:02 -0700571 l.add(ITopologyService.class);
Jonathan Hart03102132014-07-01 23:22:04 -0700572 l.add(IHostService.class);
Saurav Dasfb93c252014-08-18 20:40:13 -0700573 l.add(INetworkConfigService.class);
Jonathan Hart4b5bbb52014-02-06 10:09:31 -0800574 return l;
Jonathan Hart88770672014-04-02 18:08:30 -0700575 }
Jonathan Hart4b5bbb52014-02-06 10:09:31 -0800576
Jonathan Hart88770672014-04-02 18:08:30 -0700577 @Override
578 public void init(FloodlightModuleContext context)
579 throws FloodlightModuleException {
580 floodlightProvider = context.getServiceImpl(IFloodlightProviderService.class);
581 linkDiscovery = context.getServiceImpl(ILinkDiscoveryService.class);
582 registryService = context.getServiceImpl(IControllerRegistryService.class);
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700583 datagridService = context.getServiceImpl(IDatagridService.class);
Jonathan Hart03102132014-07-01 23:22:04 -0700584 hostService = context.getServiceImpl(IHostService.class);
Saurav Dasfb93c252014-08-18 20:40:13 -0700585 networkConfigService = context.getServiceImpl(INetworkConfigService.class);
Jonathan Harte37e4e22014-05-13 19:12:02 -0700586 topologyService = context.getServiceImpl(ITopologyService.class);
Jonathan Hart88770672014-04-02 18:08:30 -0700587 }
Jonathan Hart4b5bbb52014-02-06 10:09:31 -0800588
Jonathan Hart88770672014-04-02 18:08:30 -0700589 @Override
590 public void startUp(FloodlightModuleContext context) {
591 floodlightProvider.addOFSwitchListener(this);
592 linkDiscovery.addListener(this);
Jonathan Hart03102132014-07-01 23:22:04 -0700593 hostService.addHostListener(this);
Toshio Koide2f570c12014-02-06 16:55:32 -0800594
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700595 eventChannel = datagridService.createChannel(
596 TopologyManager.EVENT_CHANNEL_NAME,
597 byte[].class,
598 TopologyEvent.class);
599
Yuta HIGUCHId92b10c2014-08-25 09:30:28 -0700600 mutableTopology = topologyService.getTopology();
Jonathan Hartb3e1b052014-04-02 16:01:12 -0700601
Jonathan Hart88770672014-04-02 18:08:30 -0700602 // Run the cleanup thread
603 String enableCleanup =
604 context.getConfigParams(this).get(ENABLE_CLEANUP_PROPERTY);
605 if (enableCleanup != null
606 && enableCleanup.equalsIgnoreCase("false")) {
607 cleanupEnabled = false;
608 }
Jonathan Hartb3e1b052014-04-02 16:01:12 -0700609
Jonathan Hart88770672014-04-02 18:08:30 -0700610 log.debug("Cleanup thread is {}enabled", (cleanupEnabled) ? "" : "not ");
Jonathan Hartb3e1b052014-04-02 16:01:12 -0700611
Jonathan Hart88770672014-04-02 18:08:30 -0700612 if (cleanupEnabled) {
613 IThreadPoolService threadPool =
614 context.getServiceImpl(IThreadPoolService.class);
615 cleanupTask = new SingletonTask(threadPool.getScheduledExecutor(),
616 new SwitchCleanup());
617 // Run the cleanup task immediately on startup
618 cleanupTask.reschedule(0, TimeUnit.SECONDS);
619 }
Pavlin Radoslavov24409672014-08-20 16:45:11 -0700620
621 // Run the Delayed Operations Handler thread
622 delayedOperationsHandler.start();
Jonathan Hart88770672014-04-02 18:08:30 -0700623 }
Jonathan Hartb3e1b052014-04-02 16:01:12 -0700624
Jonathan Hart88770672014-04-02 18:08:30 -0700625 @Override
Jonathan Hart03102132014-07-01 23:22:04 -0700626 public void hostAdded(Host host) {
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700627 log.debug("Host added with MAC {}", host.getMacAddress());
TeruUd1c5b652014-03-24 13:58:46 -0700628
Jonathan Hart03102132014-07-01 23:22:04 -0700629 SwitchPort sp = new SwitchPort(host.getSwitchDPID(), host.getSwitchPort());
Jonathan Hart88770672014-04-02 18:08:30 -0700630 List<SwitchPort> spLists = new ArrayList<SwitchPort>();
631 spLists.add(sp);
Sangho Shin2f263692014-09-15 14:09:41 -0700632 HostData hostData = new HostData(host.getMacAddress(), host.getIpAddress());
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700633 hostData.setAttachmentPoints(spLists);
634 hostData.setLastSeenTime(host.getLastSeenTimestamp().getTime());
Jonathan Hart88770672014-04-02 18:08:30 -0700635 // Does not use vlan info now.
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700636 hostData.freeze();
Jonathan Hartb3e1b052014-04-02 16:01:12 -0700637
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700638 publishAddHostEvent(hostData);
Jonathan Hart88770672014-04-02 18:08:30 -0700639 }
TeruUd1c5b652014-03-24 13:58:46 -0700640
Jonathan Hart88770672014-04-02 18:08:30 -0700641 @Override
Jonathan Hart03102132014-07-01 23:22:04 -0700642 public void hostRemoved(Host host) {
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700643 log.debug("Host removed with MAC {}", host.getMacAddress());
644
645 //
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700646 // Remove all previously added HostData for this MAC address
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700647 //
648 // TODO: Currently, the caller of hostRemoved() might not include
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700649 // the correct set of Attachment Points in the HostData entry itself.
650 // Also, we might have multiple HostData entries for the same
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700651 // host (MAC address), each containing a single (different) Attachment
652 // Point.
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700653 // Hence, here we have to cleanup all HostData entries for this
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700654 // particular host, based on its MAC address.
655 //
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700656 List<HostData> removeHostDataEntries = new LinkedList<>();
657 for (ConcurrentMap<ByteBuffer, HostData> cm : publishedHostDataEntries.values()) {
658 for (HostData hostData : cm.values()) {
659 if (hostData.getMac().equals(host.getMacAddress())) {
660 removeHostDataEntries.add(hostData);
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700661 }
662 }
663 }
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700664 for (HostData hostData : removeHostDataEntries) {
665 publishRemoveHostEvent(hostData);
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700666 }
Jonathan Hart88770672014-04-02 18:08:30 -0700667 }
Pavlin Radoslavov695f8952014-07-23 16:57:01 -0700668
Pavlin Radoslavov24409672014-08-20 16:45:11 -0700669 @Override
670 public boolean publish(TopologyBatchOperation tbo) {
671 publishTopologyOperations(tbo);
672 return true;
673 }
674
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700675 /**
676 * Prepares the Controller role changed event for a switch.
677 *
678 * @param dpid the switch DPID
679 * @param role the new role of the controller
680 */
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700681 private void controllerRoleChanged(Dpid dpid, Role role) {
682 log.debug("Local switch controller mastership role changed: dpid = {} role = {}",
683 dpid, role);
Yuta HIGUCHId8fd2f52014-09-01 23:19:45 -0700684 MastershipData mastershipData =
685 new MastershipData(dpid, getOnosInstanceId(), role);
Pavlin Radoslavov695f8952014-07-23 16:57:01 -0700686 // FIXME should be merging, with existing attrs, etc..
687 // TODO define attr name as constant somewhere.
688 // TODO populate appropriate attributes.
Yuta HIGUCHId8fd2f52014-09-01 23:19:45 -0700689 mastershipData.createStringAttribute(TopologyElement.TYPE,
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700690 TopologyElement.TYPE_ALL_LAYERS);
Yuta HIGUCHId8fd2f52014-09-01 23:19:45 -0700691 mastershipData.freeze();
692 publishAddSwitchMastershipEvent(mastershipData);
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700693 }
694
695 /**
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700696 * Publishes ADD Mastership Event.
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700697 *
Yuta HIGUCHId8fd2f52014-09-01 23:19:45 -0700698 * @param mastershipData the mastership event to publish
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700699 */
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700700 private void publishAddSwitchMastershipEvent(
Yuta HIGUCHId8fd2f52014-09-01 23:19:45 -0700701 MastershipData mastershipData) {
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700702 // Publish the information
Pavlin Radoslavov24409672014-08-20 16:45:11 -0700703 TopologyBatchOperation tbo = new TopologyBatchOperation();
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700704 TopologyEvent topologyEvent =
Yuta HIGUCHId8fd2f52014-09-01 23:19:45 -0700705 new TopologyEvent(mastershipData, getOnosInstanceId());
Pavlin Radoslavov24409672014-08-20 16:45:11 -0700706 tbo.appendAddOperation(topologyEvent);
707 publishTopologyOperations(tbo);
Yuta HIGUCHId8fd2f52014-09-01 23:19:45 -0700708 publishedMastershipDataEntries.put(mastershipData.getDpid(),
709 mastershipData);
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700710 }
711
712 /**
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700713 * Publishes REMOVE Mastership Event.
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700714 *
Yuta HIGUCHId8fd2f52014-09-01 23:19:45 -0700715 * @param mastershipData the mastership event to publish
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700716 */
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700717 private void publishRemoveSwitchMastershipEvent(
Yuta HIGUCHId8fd2f52014-09-01 23:19:45 -0700718 MastershipData mastershipData) {
719 if (publishedMastershipDataEntries.get(mastershipData.getDpid()) == null) {
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700720 return; // Nothing to do
721 }
722
723 // Publish the information
Pavlin Radoslavov24409672014-08-20 16:45:11 -0700724 TopologyBatchOperation tbo = new TopologyBatchOperation();
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700725 TopologyEvent topologyEvent =
Yuta HIGUCHId8fd2f52014-09-01 23:19:45 -0700726 new TopologyEvent(mastershipData, getOnosInstanceId());
Pavlin Radoslavov24409672014-08-20 16:45:11 -0700727 tbo.appendRemoveOperation(topologyEvent);
728 publishTopologyOperations(tbo);
Yuta HIGUCHId8fd2f52014-09-01 23:19:45 -0700729 publishedMastershipDataEntries.remove(mastershipData.getDpid());
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700730 }
731
732 /**
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700733 * Publishes ADD Switch Event.
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700734 *
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700735 * @param switchData the switch event to publish
736 * @param portDataEntries the corresponding port events for the switch to
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700737 * publish
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700738 */
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700739 private void publishAddSwitchEvent(SwitchData switchData,
740 Collection<PortData> portDataEntries) {
741 if (!registryService.hasControl(switchData.getOriginDpid().value())) {
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700742 log.debug("Not the master for switch {}. Suppressed switch add event {}.",
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700743 switchData.getOriginDpid(), switchData);
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700744 return;
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700745 }
746
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700747 // Keep track of the old Port Events that should be removed
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700748 ConcurrentMap<ByteBuffer, PortData> oldPortDataEntries =
749 publishedPortDataEntries.get(switchData.getDpid());
750 if (oldPortDataEntries == null) {
751 oldPortDataEntries = new ConcurrentHashMap<>();
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700752 }
753
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700754 // Publish the information for the switch
Pavlin Radoslavov24409672014-08-20 16:45:11 -0700755 TopologyBatchOperation tbo = new TopologyBatchOperation();
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700756 TopologyEvent topologyEvent =
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700757 new TopologyEvent(switchData, getOnosInstanceId());
Pavlin Radoslavov24409672014-08-20 16:45:11 -0700758 tbo.appendAddOperation(topologyEvent);
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700759
760 // Publish the information for each port
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700761 ConcurrentMap<ByteBuffer, PortData> newPortDataEntries =
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700762 new ConcurrentHashMap<>();
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700763 for (PortData portData : portDataEntries) {
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700764 topologyEvent =
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700765 new TopologyEvent(portData, getOnosInstanceId());
Pavlin Radoslavov24409672014-08-20 16:45:11 -0700766 tbo.appendAddOperation(topologyEvent);
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700767
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700768 ByteBuffer id = portData.getIDasByteBuffer();
769 newPortDataEntries.put(id, portData);
770 oldPortDataEntries.remove(id);
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700771 }
Pavlin Radoslavov24409672014-08-20 16:45:11 -0700772 publishTopologyOperations(tbo);
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700773 publishedSwitchDataEntries.put(switchData.getDpid(), switchData);
774 publishedPortDataEntries.put(switchData.getDpid(), newPortDataEntries);
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700775
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700776 // Cleanup for each of the old removed port
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700777 for (PortData portData : oldPortDataEntries.values()) {
778 publishRemovePortEvent(portData);
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700779 }
780 }
781
782 /**
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700783 * Publishes REMOVE Switch Event.
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700784 *
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700785 * @param switchData the switch event to publish
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700786 */
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700787 private void publishRemoveSwitchEvent(SwitchData switchData) {
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700788 //
789 // TODO: Removed the check for now, because currently this method is
790 // also called by the SwitchCleanup thread, and in that case
791 // the Switch Event was published by some other ONOS instance.
792 //
793 /*
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700794 if (publishedSwitchDataEntries.get(switchData.getDpid()) == null) {
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700795 return; // Nothing to do
796 }
797 */
798
799 // Publish the information
Pavlin Radoslavov24409672014-08-20 16:45:11 -0700800 TopologyBatchOperation tbo = new TopologyBatchOperation();
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700801 TopologyEvent topologyEvent =
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700802 new TopologyEvent(switchData, getOnosInstanceId());
Pavlin Radoslavov24409672014-08-20 16:45:11 -0700803 tbo.appendRemoveOperation(topologyEvent);
804 publishTopologyOperations(tbo);
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700805 publishedSwitchDataEntries.remove(switchData.getDpid());
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700806
807 // Cleanup for each port
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700808 ConcurrentMap<ByteBuffer, PortData> portDataEntries =
809 publishedPortDataEntries.get(switchData.getDpid());
810 if (portDataEntries != null) {
811 for (PortData portData : portDataEntries.values()) {
812 publishRemovePortEvent(portData);
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700813 }
814 }
815
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700816 publishedPortDataEntries.remove(switchData.getDpid());
817 publishedLinkDataEntries.remove(switchData.getDpid());
818 publishedHostDataEntries.remove(switchData.getDpid());
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700819 }
820
821 /**
822 * Publishes ADD Port Event.
823 *
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700824 * @param portData the port event to publish
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700825 */
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700826 private void publishAddPortEvent(PortData portData) {
827 if (!registryService.hasControl(portData.getOriginDpid().value())) {
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700828 log.debug("Not the master for switch {}. Suppressed port add event {}.",
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700829 portData.getOriginDpid(), portData);
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700830 return;
831 }
832
833 // Publish the information
Pavlin Radoslavov24409672014-08-20 16:45:11 -0700834 TopologyBatchOperation tbo = new TopologyBatchOperation();
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700835 TopologyEvent topologyEvent =
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700836 new TopologyEvent(portData, getOnosInstanceId());
Pavlin Radoslavov24409672014-08-20 16:45:11 -0700837 tbo.appendAddOperation(topologyEvent);
838 publishTopologyOperations(tbo);
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700839
840 // Store the new Port Event in the local cache
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700841 ConcurrentMap<ByteBuffer, PortData> portDataEntries =
842 ConcurrentUtils.putIfAbsent(publishedPortDataEntries,
843 portData.getDpid(),
844 new ConcurrentHashMap<ByteBuffer, PortData>());
845 portDataEntries.put(portData.getIDasByteBuffer(), portData);
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700846 }
847
848 /**
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700849 * Publishes REMOVE Port Event.
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700850 *
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700851 * @param portData the port event to publish
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700852 */
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700853 private void publishRemovePortEvent(PortData portData) {
854 ConcurrentMap<ByteBuffer, PortData> portDataEntries =
855 publishedPortDataEntries.get(portData.getDpid());
856 if (portDataEntries == null) {
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700857 return; // Nothing to do
858 }
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700859 if (portDataEntries.get(portData.getIDasByteBuffer()) == null) {
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700860 return; // Nothing to do
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700861 }
862
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700863 // Publish the information
Pavlin Radoslavov24409672014-08-20 16:45:11 -0700864 TopologyBatchOperation tbo = new TopologyBatchOperation();
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700865 TopologyEvent topologyEvent =
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700866 new TopologyEvent(portData, getOnosInstanceId());
Pavlin Radoslavov24409672014-08-20 16:45:11 -0700867 tbo.appendRemoveOperation(topologyEvent);
868 publishTopologyOperations(tbo);
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700869
870 // Cleanup for the incoming link(s)
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700871 ConcurrentMap<ByteBuffer, LinkData> linkDataEntries =
872 publishedLinkDataEntries.get(portData.getDpid());
873 if (linkDataEntries != null) {
874 for (LinkData linkData : linkDataEntries.values()) {
875 if (linkData.getDst().equals(portData.getSwitchPort())) {
876 publishRemoveLinkEvent(linkData);
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700877 }
878 }
879 }
880
881 // Cleanup for the connected hosts
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700882 ConcurrentMap<ByteBuffer, HostData> hostDataEntries =
883 publishedHostDataEntries.get(portData.getDpid());
884 if (hostDataEntries != null) {
885 for (HostData hostData : hostDataEntries.values()) {
886 for (SwitchPort swp : hostData.getAttachmentPoints()) {
887 if (swp.equals(portData.getSwitchPort())) {
888 publishRemoveHostEvent(hostData);
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700889 }
890 }
891 }
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700892 }
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700893
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700894 portDataEntries.remove(portData.getIDasByteBuffer());
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700895 }
896
897 /**
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700898 * Publishes ADD Link Event.
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700899 *
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700900 * @param linkData the link event to publish
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700901 */
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700902 private void publishAddLinkEvent(LinkData linkData) {
903 if (!registryService.hasControl(linkData.getOriginDpid().value())) {
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700904 log.debug("Not the master for dst switch {}. Suppressed link add event {}.",
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700905 linkData.getOriginDpid(), linkData);
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700906 return;
907 }
908
909 // Publish the information
Pavlin Radoslavov24409672014-08-20 16:45:11 -0700910 TopologyBatchOperation tbo = new TopologyBatchOperation();
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700911 TopologyEvent topologyEvent =
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700912 new TopologyEvent(linkData, getOnosInstanceId());
Pavlin Radoslavov24409672014-08-20 16:45:11 -0700913 tbo.appendAddOperation(topologyEvent);
914 publishTopologyOperations(tbo);
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700915
916 // Store the new Link Event in the local cache
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700917 ConcurrentMap<ByteBuffer, LinkData> linkDataEntries =
918 ConcurrentUtils.putIfAbsent(publishedLinkDataEntries,
919 linkData.getDst().getDpid(),
920 new ConcurrentHashMap<ByteBuffer, LinkData>());
921 linkDataEntries.put(linkData.getIDasByteBuffer(), linkData);
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700922 }
923
924 /**
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700925 * Publishes REMOVE Link Event.
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700926 *
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700927 * @param linkData the link event to publish
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700928 */
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700929 private void publishRemoveLinkEvent(LinkData linkData) {
930 ConcurrentMap<ByteBuffer, LinkData> linkDataEntries =
931 publishedLinkDataEntries.get(linkData.getDst().getDpid());
932 if (linkDataEntries == null) {
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700933 return; // Nothing to do
934 }
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700935 if (linkDataEntries.get(linkData.getIDasByteBuffer()) == null) {
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700936 return; // Nothing to do
937 }
938
939 // Publish the information
Pavlin Radoslavov24409672014-08-20 16:45:11 -0700940 TopologyBatchOperation tbo = new TopologyBatchOperation();
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700941 TopologyEvent topologyEvent =
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700942 new TopologyEvent(linkData, getOnosInstanceId());
Pavlin Radoslavov24409672014-08-20 16:45:11 -0700943 tbo.appendRemoveOperation(topologyEvent);
944 publishTopologyOperations(tbo);
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700945
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700946 linkDataEntries.remove(linkData.getIDasByteBuffer());
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700947 }
948
949 /**
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700950 * Publishes ADD Host Event.
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700951 *
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700952 * @param hostData the host event to publish
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700953 */
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700954 private void publishAddHostEvent(HostData hostData) {
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700955 //
956 // NOTE: The implementation below assumes that there is just one
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700957 // attachment point stored in hostData. Currently, this assumption
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700958 // is true based on the existing implementation of the caller
959 // hostAdded().
960 //
961
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700962 if (!registryService.hasControl(hostData.getOriginDpid().value())) {
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700963 log.debug("Not the master for attachment switch {}. Suppressed host add event {}.",
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700964 hostData.getOriginDpid(), hostData);
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700965 return;
966 }
967
968 // Publish the information
Pavlin Radoslavov24409672014-08-20 16:45:11 -0700969 TopologyBatchOperation tbo = new TopologyBatchOperation();
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700970 TopologyEvent topologyEvent =
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700971 new TopologyEvent(hostData, getOnosInstanceId());
Pavlin Radoslavov24409672014-08-20 16:45:11 -0700972 tbo.appendAddOperation(topologyEvent);
973 publishTopologyOperations(tbo);
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700974
975 // Store the new Host Event in the local cache
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700976 ConcurrentMap<ByteBuffer, HostData> hostDataEntries =
977 ConcurrentUtils.putIfAbsent(publishedHostDataEntries,
978 hostData.getOriginDpid(),
979 new ConcurrentHashMap<ByteBuffer, HostData>());
980 hostDataEntries.put(hostData.getIDasByteBuffer(), hostData);
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700981 }
982
983 /**
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700984 * Publishes REMOVE Host Event.
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700985 *
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700986 * @param hostData the host event to publish
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700987 */
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700988 private void publishRemoveHostEvent(HostData hostData) {
989 ConcurrentMap<ByteBuffer, HostData> hostDataEntries =
990 publishedHostDataEntries.get(hostData.getOriginDpid());
991 if (hostDataEntries == null) {
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700992 return; // Nothing to do
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700993 }
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700994 if (hostDataEntries.get(hostData.getIDasByteBuffer()) == null) {
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700995 return; // Nothing to do
996 }
997
998 // Publish the information
Pavlin Radoslavov24409672014-08-20 16:45:11 -0700999 TopologyBatchOperation tbo = new TopologyBatchOperation();
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -07001000 TopologyEvent topologyEvent =
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -07001001 new TopologyEvent(hostData, getOnosInstanceId());
Pavlin Radoslavov24409672014-08-20 16:45:11 -07001002 tbo.appendRemoveOperation(topologyEvent);
1003 publishTopologyOperations(tbo);
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -07001004
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -07001005 hostDataEntries.remove(hostData.getIDasByteBuffer());
Pavlin Radoslavov695f8952014-07-23 16:57:01 -07001006 }
Pavlin Radoslavov24409672014-08-20 16:45:11 -07001007
1008 /**
1009 * Publishes Topology Operations.
1010 *
1011 * @param tbo the Topology Operations to publish
1012 */
1013 private void publishTopologyOperations(TopologyBatchOperation tbo) {
1014 // TODO: This flag should be configurable
1015 boolean isGlobalLogWriter = false;
1016
1017 log.debug("Publishing: {}", tbo);
1018
1019 if (isGlobalLogWriter) {
1020 if (!topologyService.publish(tbo)) {
1021 log.debug("Cannot publish: {}", tbo);
1022 delayedOperations.add(tbo);
1023 }
1024 } else {
1025 // TODO: For now we publish each TopologyEvent independently
1026 for (BatchOperationEntry<TopologyBatchOperation.Operator,
1027 TopologyEvent> boe : tbo.getOperations()) {
1028 TopologyBatchOperation.Operator oper = boe.getOperator();
1029 TopologyEvent topologyEvent = boe.getTarget();
1030 switch (oper) {
1031 case ADD:
1032 eventChannel.addEntry(topologyEvent.getID(),
1033 topologyEvent);
1034 break;
1035 case REMOVE:
1036 eventChannel.removeEntry(topologyEvent.getID());
1037 break;
1038 default:
1039 log.error("Unknown Topology Batch Operation {}", oper);
1040 break;
1041 }
1042 }
1043 }
1044 }
Jonathan Hart4b5bbb52014-02-06 10:09:31 -08001045}