blob: 2bb53c937ac9e0fdf2e873c717237191e0818aea [file] [log] [blame]
Lee Yongjae7c27bb42017-11-17 12:00:45 +09001/*
2 * Copyright 2017-present Open Networking Foundation
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package org.onosproject.simplefabric;
18
19import com.google.common.collect.ImmutableSet;
20import com.google.common.collect.Maps;
21import com.googlecode.concurrenttrees.radix.node.concrete.DefaultByteArrayNodeFactory;
22import com.googlecode.concurrenttrees.radixinverted.ConcurrentInvertedRadixTree;
23import com.googlecode.concurrenttrees.radixinverted.InvertedRadixTree;
24import org.apache.felix.scr.annotations.Activate;
25import org.apache.felix.scr.annotations.Component;
26import org.apache.felix.scr.annotations.Deactivate;
27import org.apache.felix.scr.annotations.Reference;
28import org.apache.felix.scr.annotations.ReferenceCardinality;
29import org.apache.felix.scr.annotations.Service;
30import org.onlab.packet.ARP;
31import org.onlab.packet.Ethernet;
32import org.onlab.packet.Ip4Address;
33import org.onlab.packet.Ip6Address;
34import org.onlab.packet.IpAddress;
35import org.onlab.packet.IpPrefix;
36import org.onlab.packet.IPv6;
37import org.onlab.packet.MacAddress;
38import org.onlab.packet.VlanId;
39import org.onlab.packet.ndp.NeighborSolicitation;
40import org.onosproject.app.ApplicationService;
41import org.onosproject.core.ApplicationId;
42import org.onosproject.core.CoreService;
43import org.onosproject.component.ComponentService;
44import org.onosproject.event.ListenerRegistry;
45import org.onosproject.net.intf.Interface;
46import org.onosproject.net.intf.InterfaceService;
47import org.onosproject.net.intf.InterfaceListener;
48import org.onosproject.net.intf.InterfaceEvent;
49import org.onosproject.net.config.ConfigFactory;
50import org.onosproject.net.config.NetworkConfigEvent;
51import org.onosproject.net.config.NetworkConfigListener;
52import org.onosproject.net.config.NetworkConfigRegistry;
53import org.onosproject.net.config.NetworkConfigService;
54import org.onosproject.net.config.basics.SubjectFactories;
55import org.onosproject.net.ConnectPoint;
56import org.onosproject.net.device.DeviceEvent;
57import org.onosproject.net.device.DeviceListener;
58import org.onosproject.net.device.DeviceService;
59import org.onosproject.net.flow.DefaultTrafficTreatment;
60import org.onosproject.net.flow.TrafficTreatment;
61import org.onosproject.net.Host;
62import org.onosproject.net.host.HostService;
63import org.onosproject.net.host.HostListener;
64import org.onosproject.net.host.HostEvent;
65import org.onosproject.net.packet.PacketService;
66import org.onosproject.net.packet.DefaultOutboundPacket;
67import org.onosproject.net.packet.OutboundPacket;
68import org.slf4j.Logger;
69import org.slf4j.LoggerFactory;
70
71import java.io.OutputStream;
72import java.io.PrintStream;
73import java.nio.ByteBuffer;
74import java.util.Iterator;
75import java.util.HashSet;
76import java.util.Collection;
77import java.util.Set;
78import java.util.Map;
79
80import static org.onosproject.simplefabric.RouteTools.createBinaryString;
81
82
83/**
84 * Reactive routing configuration manager.
85 */
86@Component(immediate = true)
87@Service
88public class SimpleFabricManager extends ListenerRegistry<SimpleFabricEvent, SimpleFabricListener>
89 implements SimpleFabricService {
90
91 private final Logger log = LoggerFactory.getLogger(getClass());
92
93 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
94 protected CoreService coreService;
95
96 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
97 protected ApplicationService applicationService;
98
99 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
100 protected NetworkConfigService configService;
101
102 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
103 protected NetworkConfigRegistry registry;
104
105 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
106 protected DeviceService deviceService;
107
108 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
109 protected InterfaceService interfaceService;
110
111 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
112 protected HostService hostService;
113
114 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
115 protected PacketService packetService;
116
117 // compoents to be activated within SimpleFabric
118 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
119 protected ComponentService componentService;
120
121 // SimpleFabric variables
122 private ApplicationId appId = null;
123
124 // l2 broadcast networks
125 private Set<L2Network> l2Networks = new HashSet<>();
126 private Set<Interface> l2NetworkInterfaces = new HashSet<>();
127
128 // Subnet table
129 private Set<IpSubnet> ipSubnets = new HashSet<>();
130 private InvertedRadixTree<IpSubnet> ip4SubnetTable =
131 new ConcurrentInvertedRadixTree<>(new DefaultByteArrayNodeFactory());
132 private InvertedRadixTree<IpSubnet> ip6SubnetTable =
133 new ConcurrentInvertedRadixTree<>(new DefaultByteArrayNodeFactory());
134
135 // Border Route table
136 private Set<Route> borderRoutes = new HashSet<>();
137 private InvertedRadixTree<Route> ip4BorderRouteTable =
138 new ConcurrentInvertedRadixTree<>(new DefaultByteArrayNodeFactory());
139 private InvertedRadixTree<Route> ip6BorderRouteTable =
140 new ConcurrentInvertedRadixTree<>(new DefaultByteArrayNodeFactory());
141
142 // VirtialGateway
143 private Map<IpAddress, MacAddress> virtualGatewayIpMacMap = Maps.newConcurrentMap();
144
145 // Refresh monitor thread
146 private Object refreshMonitor = new Object();
147 private boolean doRefresh = false;
148 private boolean doFlush = false;
149 private InternalRefreshThread refreshThread;
150
151 // Listener for Service Events
152 private final InternalNetworkConfigListener configListener = new InternalNetworkConfigListener();
153 private final InternalDeviceListener deviceListener = new InternalDeviceListener();
154 private final InternalHostListener hostListener = new InternalHostListener();
155 private final InternalInterfaceListener interfaceListener = new InternalInterfaceListener();
156
157 private ConfigFactory<ApplicationId, SimpleFabricConfig> simpleFabricConfigFactory =
158 new ConfigFactory<ApplicationId, SimpleFabricConfig>(
159 SubjectFactories.APP_SUBJECT_FACTORY,
160 SimpleFabricConfig.class, SimpleFabricConfig.KEY) {
161 @Override
162 public SimpleFabricConfig createConfig() {
163 return new SimpleFabricConfig();
164 }
165 };
166
167 @Activate
168 public void activate() {
169 log.info("simple fabric starting");
170
171 if (appId == null) {
172 appId = coreService.registerApplication(APP_ID);
173 }
174
175 // initial refresh
176 refresh();
177
178 configService.addListener(configListener);
179 registry.registerConfigFactory(simpleFabricConfigFactory);
180 deviceService.addListener(deviceListener);
181 hostService.addListener(hostListener);
182
183 componentService.activate(appId, SimpleFabricNeighbour.class.getName());
184 componentService.activate(appId, SimpleFabricReactiveRouting.class.getName());
185 if (SimpleFabricService.ALLOW_ETH_ADDRESS_SELECTOR) {
186 componentService.activate(appId, SimpleFabricL2Forward.class.getName());
187 }
188
189 refreshThread = new InternalRefreshThread();
190 refreshThread.start();
191
192 log.info("simple fabric started");
193 }
194
195 @Deactivate
196 public void deactivate() {
197 log.info("simple fabric stopping");
198
199 componentService.deactivate(appId, SimpleFabricNeighbour.class.getName());
200 componentService.deactivate(appId, SimpleFabricReactiveRouting.class.getName());
201 if (SimpleFabricService.ALLOW_ETH_ADDRESS_SELECTOR) {
202 componentService.deactivate(appId, SimpleFabricL2Forward.class.getName());
203 }
204
205 deviceService.removeListener(deviceListener);
206 hostService.removeListener(hostListener);
207 registry.unregisterConfigFactory(simpleFabricConfigFactory);
208 configService.removeListener(configListener);
209
210 refreshThread.stop();
211 refreshThread = null;
212
213 log.info("simple fabric stopped");
214 }
215
216 // Set up from configuration
217 // returns found dirty and refresh listners are called (true) or not (false)
218 private boolean refresh() {
219 log.debug("simple fabric refresh");
220 boolean dirty = false;
221
222 SimpleFabricConfig config = configService.getConfig(coreService.registerApplication(APP_ID),
223 SimpleFabricConfig.class);
224 if (config == null) {
225 log.debug("No reactive routing config available!");
226 return false;
227 }
228
229 // l2Networks
230 Set<L2Network> newL2Networks = new HashSet<>();
231 Set<Interface> newL2NetworkInterfaces = new HashSet<>();
232 for (L2Network newL2NetworkConfig : config.getL2Networks()) {
233 L2Network newL2Network = L2Network.of(newL2NetworkConfig);
234
235 // fill up interfaces and Hosts with active port only
236 for (String ifaceName : newL2NetworkConfig.interfaceNames()) {
237 Interface iface = getInterfaceByName(ifaceName);
238 if (iface != null && deviceService.isAvailable(iface.connectPoint().deviceId())) {
239 newL2Network.addInterface(iface);
240 newL2NetworkInterfaces.add(iface);
241 }
242 }
243 for (Host host : hostService.getHosts()) {
244 // consider host with ip only
245 if (!host.ipAddresses().isEmpty()) {
246 Interface iface = getAvailableDeviceHostInterface(host);
247 if (iface != null && newL2Network.contains(iface)) {
248 newL2Network.addHost(host);
249 }
250 }
251 }
252 newL2Network.setDirty(true);
253
254 // update newL2Network's dirty flags if same entry already exists
255 for (L2Network prevL2Network : l2Networks) {
256 if (prevL2Network.equals(newL2Network)) {
257 newL2Network.setDirty(prevL2Network.dirty());
258 break;
259 }
260 }
261 newL2Networks.add(newL2Network);
262 }
263 if (!l2Networks.equals(newL2Networks)) {
264 l2Networks = newL2Networks;
265 dirty = true;
266 }
267 if (!l2NetworkInterfaces.equals(newL2NetworkInterfaces)) {
268 l2NetworkInterfaces = newL2NetworkInterfaces;
269 dirty = true;
270 }
271
272 // ipSubnets
273 Set<IpSubnet> newIpSubnets = config.ipSubnets();
274 InvertedRadixTree<IpSubnet> newIp4SubnetTable =
275 new ConcurrentInvertedRadixTree<>(new DefaultByteArrayNodeFactory());
276 InvertedRadixTree<IpSubnet> newIp6SubnetTable =
277 new ConcurrentInvertedRadixTree<>(new DefaultByteArrayNodeFactory());
278 Map<IpAddress, MacAddress> newVirtualGatewayIpMacMap = Maps.newConcurrentMap();
279 for (IpSubnet subnet : newIpSubnets) {
280 if (subnet.ipPrefix().isIp4()) {
281 newIp4SubnetTable.put(createBinaryString(subnet.ipPrefix()), subnet);
282 } else {
283 newIp6SubnetTable.put(createBinaryString(subnet.ipPrefix()), subnet);
284 }
285 newVirtualGatewayIpMacMap.put(subnet.gatewayIp(), subnet.gatewayMac());
286 }
287 if (!ipSubnets.equals(newIpSubnets)) {
288 ipSubnets = newIpSubnets;
289 ip4SubnetTable = newIp4SubnetTable;
290 ip6SubnetTable = newIp6SubnetTable;
291 dirty = true;
292 }
293 if (!virtualGatewayIpMacMap.equals(newVirtualGatewayIpMacMap)) {
294 virtualGatewayIpMacMap = newVirtualGatewayIpMacMap;
295 dirty = true;
296 }
297
298 // borderRoutes config handling
299 Set<Route> newBorderRoutes = config.borderRoutes();
300 if (!borderRoutes.equals(newBorderRoutes)) {
301 InvertedRadixTree<Route> newIp4BorderRouteTable =
302 new ConcurrentInvertedRadixTree<>(new DefaultByteArrayNodeFactory());
303 InvertedRadixTree<Route> newIp6BorderRouteTable =
304 new ConcurrentInvertedRadixTree<>(new DefaultByteArrayNodeFactory());
305 for (Route route : newBorderRoutes) {
306 if (route.prefix().isIp4()) {
307 newIp4BorderRouteTable.put(createBinaryString(route.prefix()), route);
308 } else {
309 newIp6BorderRouteTable.put(createBinaryString(route.prefix()), route);
310 }
311 }
312 borderRoutes = newBorderRoutes;
313 ip4BorderRouteTable = newIp4BorderRouteTable;
314 ip6BorderRouteTable = newIp6BorderRouteTable;
315 dirty = true;
316 }
317
318 // notify to SimpleFabric listeners
319 if (dirty) {
320 log.info("simple fabric refresh; notify events");
321 process(new SimpleFabricEvent(SimpleFabricEvent.Type.SIMPLE_FABRIC_UPDATED, "updated"));
322 }
323 return dirty;
324 }
325
326 private Interface getInterfaceByName(String interfaceName) {
327 Interface intf = interfaceService.getInterfaces().stream()
328 .filter(iface -> iface.name().equals(interfaceName))
329 .findFirst()
330 .orElse(null);
331 if (intf == null) {
332 log.warn("simple fabric unknown interface name: {}", interfaceName);
333 }
334 return intf;
335 }
336
337 @Override
338 public ApplicationId getAppId() {
339 if (appId == null) {
340 appId = coreService.registerApplication(APP_ID);
341 }
342 return appId;
343 }
344
345 @Override
346 public Collection<L2Network> getL2Networks() {
347 return ImmutableSet.copyOf(l2Networks);
348 }
349
350 @Override
351 public Set<IpSubnet> getIpSubnets() {
352 return ImmutableSet.copyOf(ipSubnets);
353 }
354
355 @Override
356 public Set<Route> getBorderRoutes() {
357 return ImmutableSet.copyOf(borderRoutes);
358 }
359
360 @Override
361 public MacAddress getVMacForIp(IpAddress ip) {
362 return virtualGatewayIpMacMap.get(ip);
363 }
364
365 @Override
366 public boolean isVMac(MacAddress mac) {
367 return virtualGatewayIpMacMap.containsValue(mac);
368 }
369
370 @Override
371 public boolean isL2NetworkInterface(Interface intf) {
372 return l2NetworkInterfaces.contains(intf);
373 }
374
375 @Override
376 public L2Network findL2Network(ConnectPoint port, VlanId vlanId) {
377 for (L2Network l2Network : l2Networks) {
378 if (l2Network.contains(port, vlanId)) {
379 return l2Network;
380 }
381 }
382 return null;
383 }
384
385 @Override
386 public L2Network findL2Network(String name) {
387 for (L2Network l2Network : l2Networks) {
388 if (l2Network.name().equals(name)) {
389 return l2Network;
390 }
391 }
392 return null;
393 }
394
395 @Override
396 public IpSubnet findIpSubnet(IpAddress ip) {
397 Iterator<IpSubnet> it;
398 if (ip.isIp4()) {
399 it = ip4SubnetTable.getValuesForKeysPrefixing(
400 createBinaryString(IpPrefix.valueOf(ip, Ip4Address.BIT_LENGTH))).iterator();
401 } else {
402 it = ip6SubnetTable.getValuesForKeysPrefixing(
403 createBinaryString(IpPrefix.valueOf(ip, Ip6Address.BIT_LENGTH))) .iterator();
404 }
405 return (it.hasNext()) ? it.next() : null;
406 }
407
408 @Override
409 public Route findBorderRoute(IpAddress ip) {
410 // ASSUME: ipAddress is out of ipSubnet
411 Iterator<Route> it;
412 if (ip.isIp4()) {
413 it = ip4BorderRouteTable.getValuesForKeysPrefixing(
414 createBinaryString(IpPrefix.valueOf(ip, Ip4Address.BIT_LENGTH))) .iterator();
415 } else {
416 it = ip6BorderRouteTable.getValuesForKeysPrefixing(
417 createBinaryString(IpPrefix.valueOf(ip, Ip6Address.BIT_LENGTH))) .iterator();
418 }
419 return (it.hasNext()) ? it.next() : null;
420 }
421
422
423 @Override
424 public Interface getHostInterface(Host host) {
425 return interfaceService.getInterfaces().stream()
426 .filter(iface -> iface.connectPoint().equals(host.location()) &&
427 iface.vlan().equals(host.vlan()))
428 .findFirst()
429 .orElse(null);
430 }
431
432 private Interface getAvailableDeviceHostInterface(Host host) {
433 return interfaceService.getInterfaces().stream()
434 .filter(iface -> iface.connectPoint().equals(host.location()) &&
435 iface.vlan().equals(host.vlan()))
436 .filter(iface -> deviceService.isAvailable(iface.connectPoint().deviceId()))
437 .findFirst()
438 .orElse(null);
439 }
440
441 @Override
442 public boolean isIpAddressLocal(IpAddress ip) {
443 boolean result;
444 if (ip.isIp4()) {
445 return ip4SubnetTable.getValuesForKeysPrefixing(
446 createBinaryString(IpPrefix.valueOf(ip, Ip4Address.BIT_LENGTH)))
447 .iterator().hasNext();
448 } else {
449 return ip6SubnetTable.getValuesForKeysPrefixing(
450 createBinaryString(IpPrefix.valueOf(ip, Ip6Address.BIT_LENGTH)))
451 .iterator().hasNext();
452 }
453 }
454
455 @Override
456 public boolean isIpPrefixLocal(IpPrefix ipPrefix) {
457 if (ipPrefix.isIp4()) {
458 return (ip4SubnetTable.getValueForExactKey(createBinaryString(ipPrefix)) != null);
459 } else {
460 return (ip6SubnetTable.getValueForExactKey(createBinaryString(ipPrefix)) != null);
461 }
462 }
463
464 @Override
465 public boolean requestMac(IpAddress ip) {
466 IpSubnet ipSubnet = findIpSubnet(ip);
467 if (ipSubnet == null) {
468 log.warn("simple fabric request mac failed for unknown IpSubnet: {}", ip);
469 return false;
470 }
471 L2Network l2Network = findL2Network(ipSubnet.l2NetworkName());
472 if (l2Network == null) {
473 log.warn("simple fabric request mac failed for unknown l2Network name {}: {}",
474 ipSubnet.l2NetworkName(), ip);
475 return false;
476 }
477 log.debug("simple fabric send request mac L2Network {}: {}", l2Network.name(), ip);
478 for (Interface iface : l2Network.interfaces()) {
479 Ethernet neighbourReq;
480 if (ip.isIp4()) {
481 neighbourReq = ARP.buildArpRequest(ipSubnet.gatewayMac().toBytes(),
482 ipSubnet.gatewayIp().toOctets(),
483 ip.toOctets(),
484 iface.vlan().toShort());
485 } else {
486 byte[] soliciteIp = IPv6.getSolicitNodeAddress(ip.toOctets());
487 neighbourReq = NeighborSolicitation.buildNdpSolicit(
488 ip.toOctets(),
489 ipSubnet.gatewayIp().toOctets(),
490 soliciteIp,
491 ipSubnet.gatewayMac().toBytes(),
492 IPv6.getMCastMacAddress(soliciteIp),
493 iface.vlan());
494 }
495 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
496 .setOutput(iface.connectPoint().port()).build();
497 OutboundPacket packet = new DefaultOutboundPacket(iface.connectPoint().deviceId(),
498 treatment, ByteBuffer.wrap(neighbourReq.serialize()));
499 packetService.emit(packet);
500 }
501 return true;
502 }
503
504 @Override
505 public void dumpToStream(String subject, OutputStream out) {
506 SimpleFabricEvent event = new SimpleFabricEvent(SimpleFabricEvent.Type.SIMPLE_FABRIC_DUMP, subject, out);
507 dump(event.subject(), event.out()); // dump in itself
508 process(event); // dump in sub modules
509 }
510
511 // Dump handler
512 protected void dump(String subject, PrintStream out) {
513 if (subject == "show") {
514 out.println("Static Configuration Flag:");
515 out.println(" ALLOW_ETH_ADDRESS_SELECTOR="
516 + SimpleFabricService.ALLOW_ETH_ADDRESS_SELECTOR);
517 out.println(" REACTIVE_SINGLE_TO_SINGLE="
518 + SimpleFabricService.REACTIVE_SINGLE_TO_SINGLE);
519 out.println(" REACTIVE_ALLOW_LINK_CP="
520 + SimpleFabricService.REACTIVE_ALLOW_LINK_CP);
521 out.println(" REACTIVE_HASHED_PATH_SELECTION="
522 + SimpleFabricService.REACTIVE_HASHED_PATH_SELECTION);
523 out.println(" REACTIVE_MATCH_IP_PROTO="
524 + SimpleFabricService.REACTIVE_MATCH_IP_PROTO);
525 out.println("");
526 out.println("SimpleFabricAppId:");
527 out.println(" " + getAppId());
528 out.println("");
529 out.println("l2Networks:");
530 for (L2Network l2Network : getL2Networks()) {
531 out.println(" " + l2Network);
532 }
533 out.println("");
534 out.println("ipSubnets:");
535 for (IpSubnet ipSubnet : getIpSubnets()) {
536 out.println(" " + ipSubnet);
537 }
538 out.println("");
539 out.println("borderRoutes:");
540 for (Route route : getBorderRoutes()) {
541 out.println(" " + route);
542 }
543 }
544 }
545
546 // Refresh action thread and notifier
547
548 private class InternalRefreshThread extends Thread {
549 public void run() {
550 while (true) {
551 boolean doRefreshMarked = false;
552 boolean doFlushMarked = false;
553 synchronized (refreshMonitor) {
554 if (!doRefresh && !doFlush) {
555 try {
556 refreshMonitor.wait(IDLE_INTERVAL_MSEC);
557 } catch (InterruptedException e) {
558 }
559 }
560 doRefreshMarked = doRefresh;
561 doRefresh = false;
562 doFlushMarked = doFlush;
563 doFlush = false;
564 }
565 if (doRefreshMarked) {
566 try {
567 refresh();
568 } catch (Exception e) {
569 log.warn("simple fabric refresh failed: exception={}", e);
570 }
571 }
572 if (doFlushMarked) {
573 try {
574 log.info("simple fabric flush execute");
575 process(new SimpleFabricEvent(SimpleFabricEvent.Type.SIMPLE_FABRIC_FLUSH, "flush"));
576 } catch (Exception e) {
577 log.warn("simple fabric flush failed: exception={}", e);
578 }
579 }
580 if (!doRefreshMarked && !doFlushMarked) {
581 try {
582 if (!refresh()) {
583 process(new SimpleFabricEvent(SimpleFabricEvent.Type.SIMPLE_FABRIC_IDLE, "idle"));
584 }
585 } catch (Exception e) {
586 log.warn("simple fabric idle failed: exception={}", e);
587 }
588 }
589 }
590 }
591 }
592
593 @Override
594 public void triggerRefresh() {
595 synchronized (refreshMonitor) {
596 doRefresh = true;
597 refreshMonitor.notifyAll();
598 }
599 }
600
601 @Override
602 public void triggerFlush() {
603 synchronized (refreshMonitor) {
604 doFlush = true;
605 refreshMonitor.notifyAll();
606 }
607 }
608
609 // Service Listeners
610
611 private class InternalNetworkConfigListener implements NetworkConfigListener {
612 @Override
613 public void event(NetworkConfigEvent event) {
614 switch (event.type()) {
615 case CONFIG_REGISTERED:
616 case CONFIG_UNREGISTERED:
617 case CONFIG_ADDED:
618 case CONFIG_UPDATED:
619 case CONFIG_REMOVED:
620 if (event.configClass().equals(SimpleFabricConfig.class)) {
621 triggerRefresh();
622 }
623 break;
624 default:
625 break;
626 }
627 }
628 }
629
630 private class InternalDeviceListener implements DeviceListener {
631 @Override
632 public void event(DeviceEvent event) {
633 switch (event.type()) {
634 case DEVICE_ADDED:
635 case DEVICE_AVAILABILITY_CHANGED:
636 case DEVICE_REMOVED:
637 case DEVICE_SUSPENDED:
638 case DEVICE_UPDATED:
639 case PORT_ADDED:
640 case PORT_REMOVED:
641 case PORT_UPDATED:
642 // case PORT_STATS_UPDATED: IGNORED
643 triggerRefresh();
644 break;
645 default:
646 break;
647 }
648 }
649 }
650
651 private class InternalHostListener implements HostListener {
652 @Override
653 public void event(HostEvent event) {
654 Host host = event.subject();
655 Host prevHost = event.prevSubject();
656 switch (event.type()) {
657 case HOST_MOVED:
658 case HOST_REMOVED:
659 case HOST_ADDED:
660 case HOST_UPDATED:
661 triggerRefresh();
662 break;
663 default:
664 break;
665 }
666 }
667 }
668
669 private class InternalInterfaceListener implements InterfaceListener {
670 @Override
671 public void event(InterfaceEvent event) {
672 Interface iface = event.subject();
673 Interface prevIface = event.prevSubject();
674 switch (event.type()) {
675 case INTERFACE_ADDED:
676 case INTERFACE_REMOVED:
677 case INTERFACE_UPDATED:
678 triggerRefresh();
679 break;
680 default:
681 break;
682 }
683 }
684 }
685
686}
687