blob: 2a66263b4688441f9110bd0ddf849af58d41cf56 [file] [log] [blame]
Hyunsun Moonb77b60f2016-01-15 20:03:18 -08001/*
2 * Copyright 2014-2015 Open Networking Laboratory
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 */
16package org.onosproject.cordvtn;
17
18import com.google.common.collect.Sets;
19import org.apache.felix.scr.annotations.Activate;
20import org.apache.felix.scr.annotations.Component;
21import org.apache.felix.scr.annotations.Deactivate;
22import org.apache.felix.scr.annotations.Reference;
23import org.apache.felix.scr.annotations.ReferenceCardinality;
24import org.apache.felix.scr.annotations.Service;
25import org.onlab.util.ItemNotFoundException;
26import org.onlab.util.KryoNamespace;
27import org.onosproject.cluster.ClusterService;
28import org.onosproject.core.ApplicationId;
29import org.onosproject.core.CoreService;
30import org.onosproject.mastership.MastershipService;
31import org.onosproject.net.ConnectPoint;
32import org.onosproject.net.DefaultAnnotations;
33import org.onosproject.net.Device;
34import org.onosproject.net.DeviceId;
35import org.onosproject.net.Host;
36import org.onosproject.net.Port;
37import org.onosproject.net.behaviour.BridgeConfig;
38import org.onosproject.net.behaviour.BridgeName;
39import org.onosproject.net.behaviour.ControllerInfo;
40import org.onosproject.net.behaviour.DefaultTunnelDescription;
41import org.onosproject.net.behaviour.TunnelConfig;
42import org.onosproject.net.behaviour.TunnelDescription;
43import org.onosproject.net.behaviour.TunnelName;
Hyunsun Moonb77b60f2016-01-15 20:03:18 -080044import org.onosproject.net.config.NetworkConfigEvent;
45import org.onosproject.net.config.NetworkConfigListener;
46import org.onosproject.net.config.NetworkConfigRegistry;
47import org.onosproject.net.config.NetworkConfigService;
Hyunsun Moonb77b60f2016-01-15 20:03:18 -080048import org.onosproject.net.device.DeviceAdminService;
49import org.onosproject.net.device.DeviceEvent;
50import org.onosproject.net.device.DeviceListener;
51import org.onosproject.net.device.DeviceService;
52import org.onosproject.net.driver.DriverHandler;
53import org.onosproject.net.driver.DriverService;
54import org.onosproject.net.flow.FlowRuleService;
55import org.onosproject.net.group.GroupService;
56import org.onosproject.net.host.HostService;
57import org.onosproject.ovsdb.controller.OvsdbClientService;
58import org.onosproject.ovsdb.controller.OvsdbController;
59import org.onosproject.ovsdb.controller.OvsdbNodeId;
60import org.onosproject.store.serializers.KryoNamespaces;
61import org.onosproject.store.service.ConsistentMap;
62import org.onosproject.store.service.Serializer;
63import org.onosproject.store.service.StorageService;
64import org.slf4j.Logger;
65
66import java.util.ArrayList;
67import java.util.HashMap;
68import java.util.List;
69import java.util.Map;
70import java.util.concurrent.ExecutorService;
71
72import static com.google.common.base.Preconditions.checkNotNull;
73import static java.util.concurrent.Executors.newSingleThreadScheduledExecutor;
74import static org.onlab.util.Tools.groupedThreads;
75import static org.onosproject.net.Device.Type.SWITCH;
76import static org.onosproject.net.behaviour.TunnelDescription.Type.VXLAN;
77import static org.slf4j.LoggerFactory.getLogger;
78
79/**
80 * Reads node information from the network config file and handles the config
81 * update events.
82 * Only a leader controller performs the node addition or deletion.
83 */
84@Component(immediate = true)
85@Service(value = CordVtnNodeManager.class)
86public class CordVtnNodeManager {
87
88 protected final Logger log = getLogger(getClass());
89
90 private static final KryoNamespace.Builder NODE_SERIALIZER = KryoNamespace.newBuilder()
91 .register(KryoNamespaces.API)
92 .register(CordVtnNode.class)
93 .register(NodeState.class);
94
95 private static final String DEFAULT_BRIDGE = "br-int";
96 private static final String DEFAULT_TUNNEL = "vxlan";
97 private static final String VPORT_PREFIX = "tap";
98 private static final String OK = "OK";
99 private static final String NO = "NO";
100
101 private static final Map<String, String> DEFAULT_TUNNEL_OPTIONS = new HashMap<String, String>() {
102 {
103 put("key", "flow");
104 put("remote_ip", "flow");
105 }
106 };
107 private static final int DPID_BEGIN = 3;
108 private static final int OFPORT = 6653;
109
110 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
111 protected CoreService coreService;
112
113 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
114 protected NetworkConfigRegistry configRegistry;
115
116 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
117 protected NetworkConfigService configService;
118
119 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
120 protected StorageService storageService;
121
122 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
123 protected DeviceAdminService adminService;
124
125 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
126 protected OvsdbController controller;
127
128 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
129 protected ClusterService clusterService;
130
131 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
132 protected DriverService driverService;
133
134 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
135 protected DeviceService deviceService;
136
137 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
138 protected HostService hostService;
139
140 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
141 protected FlowRuleService flowRuleService;
142
143 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
144 protected MastershipService mastershipService;
145
146 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
147 protected GroupService groupService;
148
149 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
150 protected CordVtnService cordVtnService;
151
Hyunsun Moonb77b60f2016-01-15 20:03:18 -0800152 private final ExecutorService eventExecutor =
153 newSingleThreadScheduledExecutor(groupedThreads("onos/cordvtncfg", "event-handler"));
154
155 private final NetworkConfigListener configListener = new InternalConfigListener();
156 private final DeviceListener deviceListener = new InternalDeviceListener();
157
158 private final OvsdbHandler ovsdbHandler = new OvsdbHandler();
159 private final BridgeHandler bridgeHandler = new BridgeHandler();
160
161 private ConsistentMap<CordVtnNode, NodeState> nodeStore;
162 private CordVtnRuleInstaller ruleInstaller;
163 private ApplicationId appId;
164
165 private enum NodeState {
166
167 INIT {
168 @Override
169 public void process(CordVtnNodeManager nodeManager, CordVtnNode node) {
170 nodeManager.connectOvsdb(node);
171 }
172 },
173 OVSDB_CONNECTED {
174 @Override
175 public void process(CordVtnNodeManager nodeManager, CordVtnNode node) {
176 if (!nodeManager.getOvsdbConnectionState(node)) {
177 nodeManager.connectOvsdb(node);
178 } else {
179 nodeManager.createIntegrationBridge(node);
180 }
181 }
182 },
183 BRIDGE_CREATED {
184 @Override
185 public void process(CordVtnNodeManager nodeManager, CordVtnNode node) {
186 if (!nodeManager.getOvsdbConnectionState(node)) {
187 nodeManager.connectOvsdb(node);
188 } else {
189 nodeManager.createTunnelInterface(node);
190 }
191 }
192 },
Hyunsun Moon177506f2016-01-21 00:54:52 -0800193 TUNNEL_INTERFACE_CREATED {
194 @Override
195 public void process(CordVtnNodeManager nodeManager, CordVtnNode node) {
196 if (!nodeManager.getOvsdbConnectionState(node)) {
197 nodeManager.connectOvsdb(node);
198 } else {
199 nodeManager.createPhyInterface(node);
200 }
201 }
202
203 },
Hyunsun Moonb77b60f2016-01-15 20:03:18 -0800204 COMPLETE {
205 @Override
206 public void process(CordVtnNodeManager nodeManager, CordVtnNode node) {
207 nodeManager.postInit(node);
208 }
209 },
210 INCOMPLETE {
211 @Override
212 public void process(CordVtnNodeManager nodeManager, CordVtnNode node) {
213 }
214 };
215
216 // TODO Add physical port add state
217
218 public abstract void process(CordVtnNodeManager nodeManager, CordVtnNode node);
219 }
220
221 @Activate
222 protected void active() {
223 appId = coreService.getAppId(CordVtnService.CORDVTN_APP_ID);
Hyunsun Moonb77b60f2016-01-15 20:03:18 -0800224 nodeStore = storageService.<CordVtnNode, NodeState>consistentMapBuilder()
225 .withSerializer(Serializer.using(NODE_SERIALIZER.build()))
226 .withName("cordvtn-nodestore")
227 .withApplicationId(appId)
228 .build();
229
230 ruleInstaller = new CordVtnRuleInstaller(appId, flowRuleService,
231 deviceService,
232 driverService,
233 groupService,
234 mastershipService,
235 DEFAULT_TUNNEL);
236
237 deviceService.addListener(deviceListener);
238 configService.addListener(configListener);
Hyunsun Moon746956f2016-01-24 21:47:06 -0800239 readConfiguration();
Hyunsun Moonb77b60f2016-01-15 20:03:18 -0800240 }
241
242 @Deactivate
243 protected void deactivate() {
Hyunsun Moonb77b60f2016-01-15 20:03:18 -0800244 configService.removeListener(configListener);
245 deviceService.removeListener(deviceListener);
246
247 eventExecutor.shutdown();
248 nodeStore.clear();
249 }
250
251 /**
252 * Adds a new node to the service.
253 *
254 * @param node cordvtn node
255 */
256 public void addNode(CordVtnNode node) {
257 checkNotNull(node);
258
259 nodeStore.putIfAbsent(node, checkNodeState(node));
260 initNode(node);
261 }
262
263 /**
264 * Deletes a node from the service.
265 *
266 * @param node cordvtn node
267 */
268 public void deleteNode(CordVtnNode node) {
269 checkNotNull(node);
270
271 if (getOvsdbConnectionState(node)) {
272 disconnectOvsdb(node);
273 }
274
275 nodeStore.remove(node);
276 }
277
278 /**
279 * Initiates node to serve virtual tenant network.
280 *
281 * @param node cordvtn node
282 */
283 public void initNode(CordVtnNode node) {
284 checkNotNull(node);
285
286 if (!nodeStore.containsKey(node)) {
287 log.warn("Node {} does not exist, add node first", node.hostname());
288 return;
289 }
290
291 NodeState state = checkNodeState(node);
292 state.process(this, node);
293 }
294
295 /**
296 * Returns node initialization state.
297 *
298 * @param node cordvtn node
299 * @return true if initial node setup is completed, otherwise false
300 */
301 public boolean getNodeInitState(CordVtnNode node) {
302 checkNotNull(node);
303
304 NodeState state = getNodeState(node);
305 return state != null && state.equals(NodeState.COMPLETE);
306 }
307
308 /**
309 * Returns detailed node initialization state.
310 * Return string includes the following information.
311 *
312 * Integration bridge created/connected: OK or NO
313 * VXLAN interface created: OK or NO
314 * Physical interface added: OK or NO
315 *
316 * @param node cordvtn node
317 * @return string including detailed node init state
318 */
319 public String checkNodeInitState(CordVtnNode node) {
320 checkNotNull(node);
321
322 NodeState state = getNodeState(node);
323 if (state == null) {
324 log.warn("Failed to get init state of {}", node.hostname());
325 return null;
326 }
327
328 String result = String.format(
329 "Integration bridge created/connected : %s (%s)%n" +
330 "VXLAN interface created : %s%n" +
331 "Physical interface added : %s (%s)",
332 checkIntegrationBridge(node) ? OK : NO, DEFAULT_BRIDGE,
333 checkTunnelInterface(node) ? OK : NO,
334 checkPhyInterface(node) ? OK : NO, node.phyPortName());
335
336 return result;
337 }
338
339 /**
340 * Returns the number of the nodes known to the service.
341 *
342 * @return number of nodes
343 */
344 public int getNodeCount() {
345 return nodeStore.size();
346 }
347
348 /**
349 * Returns all nodes known to the service.
350 *
351 * @return list of nodes
352 */
353 public List<CordVtnNode> getNodes() {
354 List<CordVtnNode> nodes = new ArrayList<>();
355 nodes.addAll(nodeStore.keySet());
356 return nodes;
357 }
358
359 /**
360 * Returns cordvtn node associated with a given OVSDB device.
361 *
362 * @param ovsdbId OVSDB device id
363 * @return cordvtn node, null if it fails to find the node
364 */
365 private CordVtnNode getNodeByOvsdbId(DeviceId ovsdbId) {
366 return getNodes().stream()
367 .filter(node -> node.ovsdbId().equals(ovsdbId))
368 .findFirst().orElse(null);
369 }
370
371 /**
372 * Returns cordvtn node associated with a given integration bridge.
373 *
374 * @param bridgeId device id of integration bridge
375 * @return cordvtn node, null if it fails to find the node
376 */
377 private CordVtnNode getNodeByBridgeId(DeviceId bridgeId) {
378 return getNodes().stream()
379 .filter(node -> node.intBrId().equals(bridgeId))
380 .findFirst().orElse(null);
381 }
382
383 /**
384 * Returns state of a given cordvtn node.
385 *
386 * @param node cordvtn node
387 * @return node state, or null if no such node exists
388 */
389 private NodeState getNodeState(CordVtnNode node) {
390 checkNotNull(node);
391
392 try {
393 return nodeStore.get(node).value();
394 } catch (NullPointerException e) {
395 log.error("Failed to get state of {}", node.hostname());
396 return null;
397 }
398 }
399
400 /**
401 * Sets a new state for a given cordvtn node.
402 *
403 * @param node cordvtn node
404 * @param newState new node state
405 */
406 private void setNodeState(CordVtnNode node, NodeState newState) {
407 checkNotNull(node);
408
409 log.debug("Changed {} state: {}", node.hostname(), newState.toString());
410
411 nodeStore.put(node, newState);
412 newState.process(this, node);
413 }
414
415 /**
416 * Checks current state of a given cordvtn node and returns it.
417 *
418 * @param node cordvtn node
419 * @return node state
420 */
421 private NodeState checkNodeState(CordVtnNode node) {
422 checkNotNull(node);
423
Hyunsun Moon177506f2016-01-21 00:54:52 -0800424 if (checkIntegrationBridge(node) && checkTunnelInterface(node) &&
425 checkPhyInterface(node)) {
426 return NodeState.COMPLETE;
427 } else if (checkTunnelInterface(node)) {
428 return NodeState.TUNNEL_INTERFACE_CREATED;
Hyunsun Moonb77b60f2016-01-15 20:03:18 -0800429 } else if (checkIntegrationBridge(node)) {
430 return NodeState.BRIDGE_CREATED;
431 } else if (getOvsdbConnectionState(node)) {
432 return NodeState.OVSDB_CONNECTED;
433 } else {
434 return NodeState.INIT;
435 }
436 }
437
438 /**
439 * Performs tasks after node initialization.
440 * It disconnects unnecessary OVSDB connection and installs initial flow
441 * rules on the device.
442 *
443 * @param node cordvtn node
444 */
445 private void postInit(CordVtnNode node) {
446 disconnectOvsdb(node);
447
448 ruleInstaller.init(node.intBrId(), node.phyPortName(), node.localIp());
449
450 // add existing hosts to the service
451 deviceService.getPorts(node.intBrId()).stream()
452 .filter(port -> getPortName(port).startsWith(VPORT_PREFIX) &&
453 port.isEnabled())
454 .forEach(port -> cordVtnService.addServiceVm(node, getConnectPoint(port)));
455
456 // remove stale hosts from the service
457 hostService.getHosts().forEach(host -> {
458 Port port = deviceService.getPort(host.location().deviceId(), host.location().port());
459 if (port == null) {
460 cordVtnService.removeServiceVm(getConnectPoint(host));
461 }
462 });
463
464 log.info("Finished init {}", node.hostname());
465 }
466
467 /**
468 * Returns port name.
469 *
470 * @param port port
471 * @return port name
472 */
473 private String getPortName(Port port) {
474 return port.annotations().value("portName");
475 }
476
477 /**
478 * Returns connection state of OVSDB server for a given node.
479 *
480 * @param node cordvtn node
481 * @return true if it is connected, false otherwise
482 */
483 private boolean getOvsdbConnectionState(CordVtnNode node) {
484 checkNotNull(node);
485
486 OvsdbClientService ovsdbClient = getOvsdbClient(node);
487 return deviceService.isAvailable(node.ovsdbId()) &&
488 ovsdbClient != null && ovsdbClient.isConnected();
489 }
490
491 /**
492 * Connects to OVSDB server for a given node.
493 *
494 * @param node cordvtn node
495 */
496 private void connectOvsdb(CordVtnNode node) {
497 checkNotNull(node);
498
499 if (!nodeStore.containsKey(node)) {
500 log.warn("Node {} does not exist", node.hostname());
501 return;
502 }
503
504 if (!getOvsdbConnectionState(node)) {
505 controller.connect(node.ovsdbIp(), node.ovsdbPort());
506 }
507 }
508
509 /**
510 * Disconnects OVSDB server for a given node.
511 *
512 * @param node cordvtn node
513 */
514 private void disconnectOvsdb(CordVtnNode node) {
515 checkNotNull(node);
516
517 if (!nodeStore.containsKey(node)) {
518 log.warn("Node {} does not exist", node.hostname());
519 return;
520 }
521
522 if (getOvsdbConnectionState(node)) {
523 OvsdbClientService ovsdbClient = getOvsdbClient(node);
524 ovsdbClient.disconnect();
525 }
526 }
527
528 /**
529 * Returns OVSDB client for a given node.
530 *
531 * @param node cordvtn node
532 * @return OVSDB client, or null if it fails to get OVSDB client
533 */
534 private OvsdbClientService getOvsdbClient(CordVtnNode node) {
535 checkNotNull(node);
536
537 OvsdbClientService ovsdbClient = controller.getOvsdbClient(
538 new OvsdbNodeId(node.ovsdbIp(), node.ovsdbPort().toInt()));
539 if (ovsdbClient == null) {
540 log.trace("Couldn't find OVSDB client for {}", node.hostname());
541 }
542 return ovsdbClient;
543 }
544
545 /**
546 * Creates an integration bridge for a given node.
547 *
548 * @param node cordvtn node
549 */
550 private void createIntegrationBridge(CordVtnNode node) {
551 if (checkIntegrationBridge(node)) {
552 return;
553 }
554
555 List<ControllerInfo> controllers = new ArrayList<>();
556 Sets.newHashSet(clusterService.getNodes()).stream()
557 .forEach(controller -> {
558 ControllerInfo ctrlInfo = new ControllerInfo(controller.ip(), OFPORT, "tcp");
559 controllers.add(ctrlInfo);
560 });
561
562 String dpid = node.intBrId().toString().substring(DPID_BEGIN);
563
564 try {
565 DriverHandler handler = driverService.createHandler(node.ovsdbId());
566 BridgeConfig bridgeConfig = handler.behaviour(BridgeConfig.class);
567 bridgeConfig.addBridge(BridgeName.bridgeName(DEFAULT_BRIDGE), dpid, controllers);
568 } catch (ItemNotFoundException e) {
Hyunsun Moon177506f2016-01-21 00:54:52 -0800569 log.warn("Failed to create integration bridge on {}", node.hostname());
Hyunsun Moonb77b60f2016-01-15 20:03:18 -0800570 }
571 }
572
573 /**
574 * Creates tunnel interface to the integration bridge for a given node.
575 *
576 * @param node cordvtn node
577 */
578 private void createTunnelInterface(CordVtnNode node) {
579 if (checkTunnelInterface(node)) {
580 return;
581 }
582
583 DefaultAnnotations.Builder optionBuilder = DefaultAnnotations.builder();
584 for (String key : DEFAULT_TUNNEL_OPTIONS.keySet()) {
585 optionBuilder.set(key, DEFAULT_TUNNEL_OPTIONS.get(key));
586 }
587
588 TunnelDescription description = new DefaultTunnelDescription(
589 null, null, VXLAN, TunnelName.tunnelName(DEFAULT_TUNNEL),
590 optionBuilder.build());
591
592 try {
593 DriverHandler handler = driverService.createHandler(node.ovsdbId());
594 TunnelConfig tunnelConfig = handler.behaviour(TunnelConfig.class);
595 tunnelConfig.createTunnelInterface(BridgeName.bridgeName(DEFAULT_BRIDGE), description);
596 } catch (ItemNotFoundException e) {
Hyunsun Moon177506f2016-01-21 00:54:52 -0800597 log.warn("Failed to create tunnel interface on {}", node.hostname());
598 }
599 }
600
601 /**
602 * Creates physical interface to a given node.
603 *
604 * @param node cordvtn node
605 */
606 private void createPhyInterface(CordVtnNode node) {
607 if (checkPhyInterface(node)) {
608 return;
609 }
610
611 try {
612 DriverHandler handler = driverService.createHandler(node.ovsdbId());
613 BridgeConfig bridgeConfig = handler.behaviour(BridgeConfig.class);
614 bridgeConfig.addPort(BridgeName.bridgeName(DEFAULT_BRIDGE), node.phyPortName());
615 } catch (ItemNotFoundException e) {
616 log.warn("Failed to add {} on {}", node.phyPortName(), node.hostname());
Hyunsun Moonb77b60f2016-01-15 20:03:18 -0800617 }
618 }
619
620 /**
621 * Checks if integration bridge exists and available.
622 *
623 * @param node cordvtn node
624 * @return true if the bridge is available, false otherwise
625 */
626 private boolean checkIntegrationBridge(CordVtnNode node) {
627 return (deviceService.getDevice(node.intBrId()) != null
628 && deviceService.isAvailable(node.intBrId()));
629 }
630
631 /**
632 * Checks if tunnel interface exists.
633 *
634 * @param node cordvtn node
635 * @return true if the interface exists, false otherwise
636 */
637 private boolean checkTunnelInterface(CordVtnNode node) {
638 return deviceService.getPorts(node.intBrId())
639 .stream()
640 .filter(p -> getPortName(p).contains(DEFAULT_TUNNEL) &&
641 p.isEnabled())
642 .findAny().isPresent();
643 }
644
645 /**
646 * Checks if physical interface exists.
647 *
648 * @param node cordvtn node
649 * @return true if the interface exists, false otherwise
650 */
651 private boolean checkPhyInterface(CordVtnNode node) {
652 return deviceService.getPorts(node.intBrId())
653 .stream()
654 .filter(p -> getPortName(p).contains(node.phyPortName()) &&
655 p.isEnabled())
656 .findAny().isPresent();
657 }
658
659 /**
660 * Returns connect point of a given port.
661 *
662 * @param port port
663 * @return connect point
664 */
665 private ConnectPoint getConnectPoint(Port port) {
666 return new ConnectPoint(port.element().id(), port.number());
667 }
668
669 /**
670 * Returns connect point of a given host.
671 *
672 * @param host host
673 * @return connect point
674 */
675 private ConnectPoint getConnectPoint(Host host) {
676 return new ConnectPoint(host.location().deviceId(), host.location().port());
677 }
678
679 private class OvsdbHandler implements ConnectionHandler<Device> {
680
681 @Override
682 public void connected(Device device) {
683 CordVtnNode node = getNodeByOvsdbId(device.id());
684 if (node != null) {
685 setNodeState(node, checkNodeState(node));
686 } else {
687 log.debug("{} is detected on unregistered node, ignore it.", device.id());
688 }
689 }
690
691 @Override
692 public void disconnected(Device device) {
693 if (!deviceService.isAvailable(device.id())) {
694 adminService.removeDevice(device.id());
695 }
696 }
697 }
698
699 private class BridgeHandler implements ConnectionHandler<Device> {
700
701 @Override
702 public void connected(Device device) {
703 CordVtnNode node = getNodeByBridgeId(device.id());
704 if (node != null) {
705 setNodeState(node, checkNodeState(node));
706 } else {
707 log.debug("{} is detected on unregistered node, ignore it.", device.id());
708 }
709 }
710
711 @Override
712 public void disconnected(Device device) {
713 CordVtnNode node = getNodeByBridgeId(device.id());
714 if (node != null) {
715 log.debug("Integration Bridge is disconnected from {}", node.hostname());
716 setNodeState(node, NodeState.INCOMPLETE);
717 }
718 }
719
720 /**
721 * Handles port added situation.
722 * If the added port is tunnel or physical port, proceed remaining node
723 * initialization. Otherwise, do nothing.
724 *
725 * @param port port
726 */
727 public void portAdded(Port port) {
728 CordVtnNode node = getNodeByBridgeId((DeviceId) port.element().id());
729 String portName = getPortName(port);
730
731 if (node == null) {
732 log.debug("{} is added to unregistered node, ignore it.", portName);
733 return;
734 }
735
736 log.debug("Port {} is added to {}", portName, node.hostname());
737
738 if (portName.startsWith(VPORT_PREFIX)) {
739 if (getNodeInitState(node)) {
740 cordVtnService.addServiceVm(node, getConnectPoint(port));
741 } else {
742 log.debug("VM is detected on incomplete node, ignore it.", portName);
743 }
744 } else if (portName.contains(DEFAULT_TUNNEL) || portName.equals(node.phyPortName())) {
745 setNodeState(node, checkNodeState(node));
746 }
747 }
748
749 /**
750 * Handles port removed situation.
751 * If the removed port is tunnel or physical port, proceed remaining node
752 * initialization.Others, do nothing.
753 *
754 * @param port port
755 */
756 public void portRemoved(Port port) {
757 CordVtnNode node = getNodeByBridgeId((DeviceId) port.element().id());
758 String portName = getPortName(port);
759
760 if (node == null) {
761 return;
762 }
763
764 log.debug("Port {} is removed from {}", portName, node.hostname());
765
766 if (portName.startsWith(VPORT_PREFIX)) {
767 if (getNodeInitState(node)) {
768 cordVtnService.removeServiceVm(getConnectPoint(port));
769 } else {
770 log.debug("VM is vanished from incomplete node, ignore it.", portName);
771 }
772 } else if (portName.contains(DEFAULT_TUNNEL) || portName.equals(node.phyPortName())) {
773 setNodeState(node, NodeState.INCOMPLETE);
774 }
775 }
776 }
777
778 private class InternalDeviceListener implements DeviceListener {
779
780 @Override
781 public void event(DeviceEvent event) {
782
783 Device device = event.subject();
784 ConnectionHandler<Device> handler =
785 (device.type().equals(SWITCH) ? bridgeHandler : ovsdbHandler);
786
787 switch (event.type()) {
788 case PORT_ADDED:
789 eventExecutor.submit(() -> bridgeHandler.portAdded(event.port()));
790 break;
791 case PORT_UPDATED:
792 if (!event.port().isEnabled()) {
793 eventExecutor.submit(() -> bridgeHandler.portRemoved(event.port()));
794 }
795 break;
796 case DEVICE_ADDED:
797 case DEVICE_AVAILABILITY_CHANGED:
798 if (deviceService.isAvailable(device.id())) {
799 eventExecutor.submit(() -> handler.connected(device));
800 } else {
801 eventExecutor.submit(() -> handler.disconnected(device));
802 }
803 break;
804 default:
805 break;
806 }
807 }
808 }
809
810 /**
Hyunsun Moon746956f2016-01-24 21:47:06 -0800811 * Reads cordvtn nodes from config file.
Hyunsun Moonb77b60f2016-01-15 20:03:18 -0800812 */
813 private void readConfiguration() {
814 CordVtnConfig config = configRegistry.getConfig(appId, CordVtnConfig.class);
815
816 if (config == null) {
Hyunsun Moon746956f2016-01-24 21:47:06 -0800817 log.debug("No configuration found");
Hyunsun Moonb77b60f2016-01-15 20:03:18 -0800818 return;
819 }
820
821 config.cordVtnNodes().forEach(node -> {
822 CordVtnNode cordVtnNode = new CordVtnNode(
823 node.hostname(),
824 node.ovsdbIp(),
825 node.ovsdbPort(),
826 node.bridgeId(),
827 node.phyPortName(),
828 node.localIp());
829
830 addNode(cordVtnNode);
831 });
Hyunsun Moon746956f2016-01-24 21:47:06 -0800832
833 // TODO remove nodes if needed
Hyunsun Moonb77b60f2016-01-15 20:03:18 -0800834 }
835
836 private class InternalConfigListener implements NetworkConfigListener {
837
838 @Override
839 public void event(NetworkConfigEvent event) {
840 if (!event.configClass().equals(CordVtnConfig.class)) {
841 return;
842 }
843
844 switch (event.type()) {
845 case CONFIG_ADDED:
Hyunsun Moonb77b60f2016-01-15 20:03:18 -0800846 case CONFIG_UPDATED:
Hyunsun Moonb77b60f2016-01-15 20:03:18 -0800847 eventExecutor.execute(CordVtnNodeManager.this::readConfiguration);
848 break;
849 default:
850 break;
851 }
852 }
853 }
854}