blob: c2a89b93eff0ba7f5bf660ce3c866e0c27fdb3fb [file] [log] [blame]
Hyunsun Mooncb799442016-01-15 20:03:18 -08001/*
Brian O'Connor8e57fd52016-04-09 01:19:45 -07002 * Copyright 2016-present Open Networking Laboratory
Hyunsun Mooncb799442016-01-15 20:03:18 -08003 *
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 */
alshabibb4d31712016-06-01 18:51:03 -070016package org.opencord.cordvtn.impl;
Hyunsun Mooncb799442016-01-15 20:03:18 -080017
Hyunsun Moon81a13562016-08-04 13:48:08 -070018import com.google.common.base.Strings;
Hyunsun Moon3fc0cbc2016-11-22 18:29:12 -080019import com.google.common.collect.Lists;
Hyunsun Moon126171d2016-02-09 01:55:48 -080020import com.jcraft.jsch.Session;
Hyunsun Mooncb799442016-01-15 20:03:18 -080021import org.apache.felix.scr.annotations.Activate;
22import org.apache.felix.scr.annotations.Component;
23import org.apache.felix.scr.annotations.Deactivate;
24import org.apache.felix.scr.annotations.Reference;
25import org.apache.felix.scr.annotations.ReferenceCardinality;
26import org.apache.felix.scr.annotations.Service;
Hyunsun Moon126171d2016-02-09 01:55:48 -080027import org.onlab.packet.IpAddress;
Hyunsun Mooncb799442016-01-15 20:03:18 -080028import org.onlab.util.KryoNamespace;
29import org.onosproject.cluster.ClusterService;
Hyunsun Moon7004fcf2016-03-08 04:36:02 -080030import org.onosproject.cluster.LeadershipService;
31import org.onosproject.cluster.NodeId;
Hyunsun Moonc031d9b2016-08-04 13:57:22 -070032import org.onosproject.net.AnnotationKeys;
Hyunsun Moon81a13562016-08-04 13:48:08 -070033import org.onosproject.net.behaviour.BridgeDescription;
34import org.onosproject.net.behaviour.DefaultBridgeDescription;
35import org.onosproject.net.behaviour.InterfaceConfig;
36import org.onosproject.net.behaviour.TunnelEndPoints;
37import org.onosproject.net.behaviour.TunnelKeys;
Hyunsun Mooneaf75e62016-09-27 16:40:23 -070038import org.onosproject.net.config.ConfigFactory;
39import org.onosproject.net.config.basics.SubjectFactories;
Hyunsun Moonfd5a24e2016-10-19 19:15:48 -070040import org.opencord.cordvtn.api.node.ConnectionHandler;
41import org.opencord.cordvtn.api.config.CordVtnConfig;
42import org.opencord.cordvtn.api.node.CordVtnNode;
43import org.opencord.cordvtn.api.node.CordVtnNodeState;
44import org.opencord.cordvtn.api.instance.InstanceService;
45import org.opencord.cordvtn.api.node.NetworkAddress;
46import org.opencord.cordvtn.api.node.SshAccessInfo;
Hyunsun Mooncb799442016-01-15 20:03:18 -080047import org.onosproject.core.ApplicationId;
48import org.onosproject.core.CoreService;
Hyunsun Mooncb799442016-01-15 20:03:18 -080049import org.onosproject.net.ConnectPoint;
Hyunsun Mooncb799442016-01-15 20:03:18 -080050import org.onosproject.net.Device;
51import org.onosproject.net.DeviceId;
Hyunsun Mooncb799442016-01-15 20:03:18 -080052import org.onosproject.net.Port;
Hyunsun Moone7e4bb32016-05-16 04:32:45 -070053import org.onosproject.net.PortNumber;
Hyunsun Mooncb799442016-01-15 20:03:18 -080054import org.onosproject.net.behaviour.BridgeConfig;
55import org.onosproject.net.behaviour.BridgeName;
56import org.onosproject.net.behaviour.ControllerInfo;
57import org.onosproject.net.behaviour.DefaultTunnelDescription;
Hyunsun Mooncb799442016-01-15 20:03:18 -080058import org.onosproject.net.behaviour.TunnelDescription;
Hyunsun Mooncb799442016-01-15 20:03:18 -080059import org.onosproject.net.config.NetworkConfigEvent;
60import org.onosproject.net.config.NetworkConfigListener;
61import org.onosproject.net.config.NetworkConfigRegistry;
62import org.onosproject.net.config.NetworkConfigService;
Hyunsun Mooncb799442016-01-15 20:03:18 -080063import org.onosproject.net.device.DeviceAdminService;
64import org.onosproject.net.device.DeviceEvent;
65import org.onosproject.net.device.DeviceListener;
66import org.onosproject.net.device.DeviceService;
Hyunsun Mooncb799442016-01-15 20:03:18 -080067import org.onosproject.net.host.HostService;
68import org.onosproject.ovsdb.controller.OvsdbClientService;
69import org.onosproject.ovsdb.controller.OvsdbController;
70import org.onosproject.ovsdb.controller.OvsdbNodeId;
71import org.onosproject.store.serializers.KryoNamespaces;
72import org.onosproject.store.service.ConsistentMap;
Hyunsun Moonff55e812016-03-10 12:40:16 -080073import org.onosproject.store.service.MapEvent;
74import org.onosproject.store.service.MapEventListener;
Hyunsun Mooncb799442016-01-15 20:03:18 -080075import org.onosproject.store.service.Serializer;
76import org.onosproject.store.service.StorageService;
Hyunsun Moond05b32e2016-03-02 19:27:26 -080077import org.onosproject.store.service.Versioned;
Hyunsun Mooncb799442016-01-15 20:03:18 -080078import org.slf4j.Logger;
79
Hyunsun Mooncb799442016-01-15 20:03:18 -080080import java.util.List;
Hyunsun Moon7004fcf2016-03-08 04:36:02 -080081import java.util.Objects;
Hyunsun Moonc031d9b2016-08-04 13:57:22 -070082import java.util.Optional;
Hyunsun Moon126171d2016-02-09 01:55:48 -080083import java.util.Set;
Hyunsun Mooncb799442016-01-15 20:03:18 -080084import java.util.concurrent.ExecutorService;
Hyunsun Moon58ddbdc2016-03-07 16:37:17 -080085import java.util.stream.Collectors;
Hyunsun Mooncb799442016-01-15 20:03:18 -080086
87import static com.google.common.base.Preconditions.checkNotNull;
Hyunsun Moon537018f2016-07-27 18:51:00 -070088import static java.util.concurrent.Executors.newSingleThreadExecutor;
Hyunsun Mooncb799442016-01-15 20:03:18 -080089import static org.onlab.util.Tools.groupedThreads;
Hyunsun Moon81a13562016-08-04 13:48:08 -070090import static org.onosproject.net.AnnotationKeys.PORT_NAME;
Hyunsun Mooncb799442016-01-15 20:03:18 -080091import static org.onosproject.net.Device.Type.SWITCH;
92import static org.onosproject.net.behaviour.TunnelDescription.Type.VXLAN;
Hyunsun Moon5401aaa2016-06-12 17:40:34 -070093import static org.opencord.cordvtn.api.Constants.*;
alshabibb4d31712016-06-01 18:51:03 -070094import static org.opencord.cordvtn.impl.RemoteIpCommandUtil.*;
Hyunsun Mooncb799442016-01-15 20:03:18 -080095import static org.slf4j.LoggerFactory.getLogger;
96
97/**
98 * Reads node information from the network config file and handles the config
99 * update events.
100 * Only a leader controller performs the node addition or deletion.
101 */
102@Component(immediate = true)
103@Service(value = CordVtnNodeManager.class)
104public class CordVtnNodeManager {
105
106 protected final Logger log = getLogger(getClass());
107
108 private static final KryoNamespace.Builder NODE_SERIALIZER = KryoNamespace.newBuilder()
109 .register(KryoNamespaces.API)
110 .register(CordVtnNode.class)
Hyunsun Moon126171d2016-02-09 01:55:48 -0800111 .register(NodeState.class)
112 .register(SshAccessInfo.class)
113 .register(NetworkAddress.class);
Hyunsun Mooncb799442016-01-15 20:03:18 -0800114
Hyunsun Mooncb799442016-01-15 20:03:18 -0800115 private static final int DPID_BEGIN = 3;
Hyunsun Mooncb799442016-01-15 20:03:18 -0800116
117 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
118 protected CoreService coreService;
119
120 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
121 protected NetworkConfigRegistry configRegistry;
122
123 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
124 protected NetworkConfigService configService;
125
126 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
127 protected StorageService storageService;
128
129 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
130 protected DeviceAdminService adminService;
131
132 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Hyunsun Moon81a13562016-08-04 13:48:08 -0700133 protected OvsdbController ovsdbController;
Hyunsun Mooncb799442016-01-15 20:03:18 -0800134
135 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
136 protected ClusterService clusterService;
137
138 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Hyunsun Mooncb799442016-01-15 20:03:18 -0800139 protected DeviceService deviceService;
140
141 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
142 protected HostService hostService;
143
144 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Hyunsun Moon7004fcf2016-03-08 04:36:02 -0800145 protected LeadershipService leadershipService;
Hyunsun Mooncb799442016-01-15 20:03:18 -0800146
147 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Hyunsun Moon5401aaa2016-06-12 17:40:34 -0700148 protected InstanceService instanceService;
Hyunsun Mooncb799442016-01-15 20:03:18 -0800149
150 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700151 protected CordVtnPipeline pipeline;
Hyunsun Mooncb799442016-01-15 20:03:18 -0800152
Hyunsun Mooneaf75e62016-09-27 16:40:23 -0700153 private static final Class<CordVtnConfig> CONFIG_CLASS = CordVtnConfig.class;
154 private final ConfigFactory configFactory =
155 new ConfigFactory<ApplicationId, CordVtnConfig>(
156 SubjectFactories.APP_SUBJECT_FACTORY, CONFIG_CLASS, "cordvtn") {
157 @Override
158 public CordVtnConfig createConfig() {
159 return new CordVtnConfig();
160 }
161 };
162
Hyunsun Mooncb799442016-01-15 20:03:18 -0800163 private final ExecutorService eventExecutor =
Hyunsun Moon537018f2016-07-27 18:51:00 -0700164 newSingleThreadExecutor(groupedThreads("onos/cordvtn-node", "event-handler", log));
Hyunsun Mooncb799442016-01-15 20:03:18 -0800165
166 private final NetworkConfigListener configListener = new InternalConfigListener();
167 private final DeviceListener deviceListener = new InternalDeviceListener();
Hyunsun Moonff55e812016-03-10 12:40:16 -0800168 private final MapEventListener<String, CordVtnNode> nodeStoreListener = new InternalMapListener();
Hyunsun Mooncb799442016-01-15 20:03:18 -0800169
170 private final OvsdbHandler ovsdbHandler = new OvsdbHandler();
171 private final BridgeHandler bridgeHandler = new BridgeHandler();
172
Hyunsun Moon58ddbdc2016-03-07 16:37:17 -0800173 private ConsistentMap<String, CordVtnNode> nodeStore;
Hyunsun Moon3fc0cbc2016-11-22 18:29:12 -0800174 private List<ControllerInfo> controllers = Lists.newArrayList();
Hyunsun Mooncb799442016-01-15 20:03:18 -0800175 private ApplicationId appId;
Hyunsun Moon7004fcf2016-03-08 04:36:02 -0800176 private NodeId localNodeId;
Hyunsun Mooncb799442016-01-15 20:03:18 -0800177
Hyunsun Moon58ddbdc2016-03-07 16:37:17 -0800178 private enum NodeState implements CordVtnNodeState {
Hyunsun Mooncb799442016-01-15 20:03:18 -0800179
180 INIT {
181 @Override
182 public void process(CordVtnNodeManager nodeManager, CordVtnNode node) {
Hyunsun Moon81a13562016-08-04 13:48:08 -0700183 // make sure there is OVSDB connection
Hyunsun Moon126171d2016-02-09 01:55:48 -0800184 if (!nodeManager.isOvsdbConnected(node)) {
Hyunsun Mooncb799442016-01-15 20:03:18 -0800185 nodeManager.connectOvsdb(node);
Hyunsun Moon81a13562016-08-04 13:48:08 -0700186 return;
Hyunsun Mooncb799442016-01-15 20:03:18 -0800187 }
Hyunsun Moon81a13562016-08-04 13:48:08 -0700188 nodeManager.createIntegrationBridge(node);
Hyunsun Mooncb799442016-01-15 20:03:18 -0800189 }
190 },
191 BRIDGE_CREATED {
192 @Override
193 public void process(CordVtnNodeManager nodeManager, CordVtnNode node) {
Hyunsun Moon81a13562016-08-04 13:48:08 -0700194 // make sure there is OVSDB connection
Hyunsun Moon126171d2016-02-09 01:55:48 -0800195 if (!nodeManager.isOvsdbConnected(node)) {
Hyunsun Mooncb799442016-01-15 20:03:18 -0800196 nodeManager.connectOvsdb(node);
Hyunsun Moon81a13562016-08-04 13:48:08 -0700197 return;
198 }
199
200 nodeManager.createTunnelInterface(node);
201 nodeManager.addSystemInterface(node, node.dataIface());
202 if (node.hostMgmtIface().isPresent()) {
203 nodeManager.addSystemInterface(node, node.hostMgmtIface().get());
Hyunsun Mooncb799442016-01-15 20:03:18 -0800204 }
205 }
206 },
Hyunsun Moon126171d2016-02-09 01:55:48 -0800207 PORTS_ADDED {
Hyunsun Moonbd572c12016-01-21 00:54:52 -0800208 @Override
209 public void process(CordVtnNodeManager nodeManager, CordVtnNode node) {
Hyunsun Moon126171d2016-02-09 01:55:48 -0800210 nodeManager.setIpAddress(node);
Hyunsun Moonbd572c12016-01-21 00:54:52 -0800211 }
Hyunsun Moonbd572c12016-01-21 00:54:52 -0800212 },
Hyunsun Mooncb799442016-01-15 20:03:18 -0800213 COMPLETE {
214 @Override
215 public void process(CordVtnNodeManager nodeManager, CordVtnNode node) {
216 nodeManager.postInit(node);
217 }
218 },
219 INCOMPLETE {
220 @Override
221 public void process(CordVtnNodeManager nodeManager, CordVtnNode node) {
222 }
223 };
224
Hyunsun Mooncb799442016-01-15 20:03:18 -0800225 public abstract void process(CordVtnNodeManager nodeManager, CordVtnNode node);
226 }
227
228 @Activate
Hyunsun Moon479b7752016-05-06 20:13:28 -0700229 protected void activate() {
Hyunsun Mooneaf75e62016-09-27 16:40:23 -0700230 appId = coreService.registerApplication(CORDVTN_APP_ID);
Hyunsun Moon7004fcf2016-03-08 04:36:02 -0800231 leadershipService.runForLeadership(appId.name());
Hyunsun Moon3fc0cbc2016-11-22 18:29:12 -0800232 localNodeId = clusterService.getLocalNode().id();
233 configRegistry.registerConfigFactory(configFactory);
Hyunsun Moon7004fcf2016-03-08 04:36:02 -0800234
Hyunsun Moon58ddbdc2016-03-07 16:37:17 -0800235 nodeStore = storageService.<String, CordVtnNode>consistentMapBuilder()
Hyunsun Mooncb799442016-01-15 20:03:18 -0800236 .withSerializer(Serializer.using(NODE_SERIALIZER.build()))
237 .withName("cordvtn-nodestore")
238 .withApplicationId(appId)
239 .build();
240
Hyunsun Moonff55e812016-03-10 12:40:16 -0800241 nodeStore.addListener(nodeStoreListener);
Hyunsun Mooncb799442016-01-15 20:03:18 -0800242 deviceService.addListener(deviceListener);
243 configService.addListener(configListener);
Hyunsun Moon479b7752016-05-06 20:13:28 -0700244
Hyunsun Moon3fc0cbc2016-11-22 18:29:12 -0800245 // TODO read nodes as well after more tests
246 readControllers();
Hyunsun Moon479b7752016-05-06 20:13:28 -0700247 log.info("Started");
Hyunsun Mooncb799442016-01-15 20:03:18 -0800248 }
249
250 @Deactivate
251 protected void deactivate() {
Hyunsun Mooncb799442016-01-15 20:03:18 -0800252 configService.removeListener(configListener);
253 deviceService.removeListener(deviceListener);
Hyunsun Moonff55e812016-03-10 12:40:16 -0800254 nodeStore.removeListener(nodeStoreListener);
Hyunsun Moonff55e812016-03-10 12:40:16 -0800255
Hyunsun Moon7004fcf2016-03-08 04:36:02 -0800256 leadershipService.withdraw(appId.name());
Hyunsun Mooneaf75e62016-09-27 16:40:23 -0700257 configRegistry.unregisterConfigFactory(configFactory);
Hyunsun Moonff55e812016-03-10 12:40:16 -0800258 eventExecutor.shutdown();
Hyunsun Moon479b7752016-05-06 20:13:28 -0700259
260 log.info("Stopped");
Hyunsun Mooncb799442016-01-15 20:03:18 -0800261 }
262
263 /**
Hyunsun Moonff55e812016-03-10 12:40:16 -0800264 * Adds or updates a new node to the service.
Hyunsun Mooncb799442016-01-15 20:03:18 -0800265 *
266 * @param node cordvtn node
267 */
Hyunsun Moonff55e812016-03-10 12:40:16 -0800268 public void addOrUpdateNode(CordVtnNode node) {
Hyunsun Mooncb799442016-01-15 20:03:18 -0800269 checkNotNull(node);
Hyunsun Moon58ddbdc2016-03-07 16:37:17 -0800270 nodeStore.put(node.hostname(), CordVtnNode.getUpdatedNode(node, getNodeState(node)));
Hyunsun Mooncb799442016-01-15 20:03:18 -0800271 }
272
273 /**
274 * Deletes a node from the service.
275 *
276 * @param node cordvtn node
277 */
278 public void deleteNode(CordVtnNode node) {
279 checkNotNull(node);
Hyunsun Moon81a13562016-08-04 13:48:08 -0700280 OvsdbClientService ovsdbClient = getOvsdbClient(node);
281 if (ovsdbClient != null && ovsdbClient.isConnected()) {
282 ovsdbClient.disconnect();
Hyunsun Mooncb799442016-01-15 20:03:18 -0800283 }
Hyunsun Moon58ddbdc2016-03-07 16:37:17 -0800284 nodeStore.remove(node.hostname());
Hyunsun Mooncb799442016-01-15 20:03:18 -0800285 }
286
287 /**
Hyunsun Mooncb799442016-01-15 20:03:18 -0800288 * Returns node initialization state.
289 *
290 * @param node cordvtn node
291 * @return true if initial node setup is completed, otherwise false
292 */
Hyunsun Moon126171d2016-02-09 01:55:48 -0800293 public boolean isNodeInitComplete(CordVtnNode node) {
Hyunsun Mooncb799442016-01-15 20:03:18 -0800294 checkNotNull(node);
Hyunsun Moon6066bd32016-10-24 15:35:34 -0700295 return isNodeStateComplete(node);
Hyunsun Mooncb799442016-01-15 20:03:18 -0800296 }
297
298 /**
299 * Returns the number of the nodes known to the service.
300 *
301 * @return number of nodes
302 */
303 public int getNodeCount() {
304 return nodeStore.size();
305 }
306
307 /**
308 * Returns all nodes known to the service.
309 *
310 * @return list of nodes
311 */
312 public List<CordVtnNode> getNodes() {
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700313 return nodeStore.values().stream().map(Versioned::value).collect(Collectors.toList());
Hyunsun Mooncb799442016-01-15 20:03:18 -0800314 }
315
316 /**
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700317 * Returns all nodes in complete state.
Hyunsun Mooncb799442016-01-15 20:03:18 -0800318 *
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700319 * @return set of nodes
Hyunsun Mooncb799442016-01-15 20:03:18 -0800320 */
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700321 public Set<CordVtnNode> completeNodes() {
Hyunsun Moon81a13562016-08-04 13:48:08 -0700322 return getNodes().stream().filter(this::isNodeStateComplete)
323 .collect(Collectors.toSet());
Hyunsun Mooncb799442016-01-15 20:03:18 -0800324 }
325
326 /**
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700327 * Returns physical data plane port number of a given device.
Hyunsun Mooncb799442016-01-15 20:03:18 -0800328 *
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700329 * @param deviceId integration bridge device id
330 * @return port number; null otherwise
Hyunsun Mooncb799442016-01-15 20:03:18 -0800331 */
Hyunsun Moon81a13562016-08-04 13:48:08 -0700332 public PortNumber dataPort(DeviceId deviceId) {
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700333 CordVtnNode node = nodeByBridgeId(deviceId);
334 if (node == null) {
Hyunsun Moon3fc0cbc2016-11-22 18:29:12 -0800335 log.debug("Failed to get node for {}", deviceId);
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700336 return null;
337 }
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700338
Hyunsun Moonc031d9b2016-08-04 13:57:22 -0700339 Optional<PortNumber> port = getPortNumber(deviceId, node.dataIface());
340 return port.isPresent() ? port.get() : null;
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700341 }
342
343 /**
344 * Returns physical data plane IP address of a given device.
345 *
346 * @param deviceId integration bridge device id
347 * @return ip address; null otherwise
348 */
Hyunsun Moon81a13562016-08-04 13:48:08 -0700349 public IpAddress dataIp(DeviceId deviceId) {
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700350 CordVtnNode node = nodeByBridgeId(deviceId);
351 if (node == null) {
Hyunsun Moon3fc0cbc2016-11-22 18:29:12 -0800352 log.debug("Failed to get node for {}", deviceId);
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700353 return null;
354 }
Hyunsun Moon81a13562016-08-04 13:48:08 -0700355 return node.dataIp().ip();
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700356 }
357
358 /**
359 * Returns tunnel port number of a given device.
360 *
361 * @param deviceId integration bridge device id
362 * @return port number
363 */
364 public PortNumber tunnelPort(DeviceId deviceId) {
Hyunsun Moonc031d9b2016-08-04 13:57:22 -0700365 Optional<PortNumber> port = getPortNumber(deviceId, DEFAULT_TUNNEL);
366 return port.isPresent() ? port.get() : null;
367 }
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700368
Hyunsun Moonc031d9b2016-08-04 13:57:22 -0700369 /**
370 * Returns host management interface port number if exists.
371 *
372 * @param deviceId integration bridge device id
373 * @return port number; null if it does not exist
374 */
375 public PortNumber hostManagementPort(DeviceId deviceId) {
376 CordVtnNode node = nodeByBridgeId(deviceId);
377 if (node == null) {
Hyunsun Moon3fc0cbc2016-11-22 18:29:12 -0800378 log.debug("Failed to get node for {}", deviceId);
Hyunsun Moonc031d9b2016-08-04 13:57:22 -0700379 return null;
380 }
381
382 if (node.hostMgmtIface().isPresent()) {
383 Optional<PortNumber> port = getPortNumber(deviceId, node.hostMgmtIface().get());
384 return port.isPresent() ? port.get() : null;
385 } else {
386 return null;
387 }
388 }
389
390 private Optional<PortNumber> getPortNumber(DeviceId deviceId, String portName) {
391 PortNumber port = deviceService.getPorts(deviceId).stream()
392 .filter(p -> p.annotations().value(AnnotationKeys.PORT_NAME).equals(portName) &&
393 p.isEnabled())
394 .map(Port::number)
395 .findAny()
396 .orElse(null);
397 return Optional.ofNullable(port);
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700398 }
399
400 /**
401 * Returns if current node state saved in nodeStore is COMPLETE or not.
402 *
403 * @param node cordvtn node
404 * @return true if it's complete state, otherwise false
405 */
406 private boolean isNodeStateComplete(CordVtnNode node) {
407 checkNotNull(node);
408
409 // the state saved in nodeStore can be wrong if IP address settings are changed
410 // after the node init has been completed since there's no way to detect it
411 // getNodeState and checkNodeInitState always return correct answer but can be slow
412 Versioned<CordVtnNode> versionedNode = nodeStore.get(node.hostname());
413 CordVtnNodeState state = versionedNode.value().state();
414 return state != null && state.equals(NodeState.COMPLETE);
415 }
416
417 /**
418 * Initiates node to serve virtual tenant network.
419 *
420 * @param node cordvtn node
421 */
422 private void initNode(CordVtnNode node) {
423 checkNotNull(node);
424
425 NodeState state = (NodeState) node.state();
426 log.debug("Processing node: {} state: {}", node.hostname(), state);
427
428 state.process(this, node);
429 }
430
431 /**
432 * Performs tasks after node initialization.
433 * It disconnects unnecessary OVSDB connection and installs initial flow
434 * rules on the device.
435 *
436 * @param node cordvtn node
437 */
438 private void postInit(CordVtnNode node) {
Hyunsun Moon81a13562016-08-04 13:48:08 -0700439 checkNotNull(node);
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700440
Hyunsun Moon81a13562016-08-04 13:48:08 -0700441 // disconnect OVSDB session once the node bootstrap is done
442 OvsdbClientService ovsdbClient = getOvsdbClient(node);
443 if (ovsdbClient != null && ovsdbClient.isConnected()) {
444 ovsdbClient.disconnect();
445 }
446
Hyunsun Moonc031d9b2016-08-04 13:57:22 -0700447 pipeline.initPipeline(node);
Hyunsun Moon81a13562016-08-04 13:48:08 -0700448
449 // adds existing instances to the host list
450 deviceService.getPorts(node.integrationBridgeId()).stream()
Hyunsun Moon1e88fef2016-08-04 14:00:35 -0700451 .filter(port -> !node.systemIfaces().contains(portName(port)) &&
452 !port.number().equals(PortNumber.LOCAL) &&
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700453 port.isEnabled())
Hyunsun Moon5401aaa2016-06-12 17:40:34 -0700454 .forEach(port -> instanceService.addInstance(connectPoint(port)));
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700455
Hyunsun Moon81a13562016-08-04 13:48:08 -0700456 // removes stale instances from the host list
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700457 hostService.getHosts().forEach(host -> {
Hyunsun Moon81a13562016-08-04 13:48:08 -0700458 if (deviceService.getPort(
459 host.location().deviceId(),
460 host.location().port()) == null) {
461 instanceService.removeInstance(host.location());
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700462 }
463 });
464
465 log.info("Finished init {}", node.hostname());
Hyunsun Mooncb799442016-01-15 20:03:18 -0800466 }
467
468 /**
Hyunsun Mooncb799442016-01-15 20:03:18 -0800469 * Sets a new state for a given cordvtn node.
470 *
471 * @param node cordvtn node
472 * @param newState new node state
473 */
474 private void setNodeState(CordVtnNode node, NodeState newState) {
475 checkNotNull(node);
Hyunsun Moonff55e812016-03-10 12:40:16 -0800476 log.debug("Changed {} state: {}", node.hostname(), newState);
Hyunsun Moon58ddbdc2016-03-07 16:37:17 -0800477 nodeStore.put(node.hostname(), CordVtnNode.getUpdatedNode(node, newState));
Hyunsun Mooncb799442016-01-15 20:03:18 -0800478 }
479
480 /**
481 * Checks current state of a given cordvtn node and returns it.
482 *
483 * @param node cordvtn node
484 * @return node state
485 */
Hyunsun Moon126171d2016-02-09 01:55:48 -0800486 private NodeState getNodeState(CordVtnNode node) {
Hyunsun Mooncb799442016-01-15 20:03:18 -0800487 checkNotNull(node);
Hyunsun Moon81a13562016-08-04 13:48:08 -0700488 if (!isIntegrationBridgeCreated(node)) {
Hyunsun Mooncb799442016-01-15 20:03:18 -0800489 return NodeState.INIT;
490 }
Hyunsun Moon81a13562016-08-04 13:48:08 -0700491 for (String iface : node.systemIfaces()) {
492 if (!isIfaceCreated(node, iface)) {
493 return NodeState.BRIDGE_CREATED;
494 }
495 }
496 if (!isIpAddressSet(node)) {
497 return NodeState.PORTS_ADDED;
498 }
499 return NodeState.COMPLETE;
Hyunsun Mooncb799442016-01-15 20:03:18 -0800500 }
501
502 /**
Hyunsun Mooncb799442016-01-15 20:03:18 -0800503 * Returns connection state of OVSDB server for a given node.
504 *
505 * @param node cordvtn node
506 * @return true if it is connected, false otherwise
507 */
Hyunsun Moon126171d2016-02-09 01:55:48 -0800508 private boolean isOvsdbConnected(CordVtnNode node) {
Hyunsun Mooncb799442016-01-15 20:03:18 -0800509 checkNotNull(node);
Hyunsun Mooncb799442016-01-15 20:03:18 -0800510 OvsdbClientService ovsdbClient = getOvsdbClient(node);
511 return deviceService.isAvailable(node.ovsdbId()) &&
Hyunsun Moon81a13562016-08-04 13:48:08 -0700512 ovsdbClient != null &&
513 ovsdbClient.isConnected();
Hyunsun Mooncb799442016-01-15 20:03:18 -0800514 }
515
516 /**
517 * Connects to OVSDB server for a given node.
518 *
519 * @param node cordvtn node
520 */
521 private void connectOvsdb(CordVtnNode node) {
522 checkNotNull(node);
Hyunsun Moon81a13562016-08-04 13:48:08 -0700523 ovsdbController.connect(node.hostMgmtIp().ip(), node.ovsdbPort());
Hyunsun Mooncb799442016-01-15 20:03:18 -0800524 }
525
526 /**
527 * Returns OVSDB client for a given node.
528 *
529 * @param node cordvtn node
Hyunsun Moon81a13562016-08-04 13:48:08 -0700530 * @return ovsdb client, or null if there's no ovsdb connection
Hyunsun Mooncb799442016-01-15 20:03:18 -0800531 */
532 private OvsdbClientService getOvsdbClient(CordVtnNode node) {
533 checkNotNull(node);
Hyunsun Moon81a13562016-08-04 13:48:08 -0700534 OvsdbNodeId ovsdb = new OvsdbNodeId(
535 node.hostMgmtIp().ip(), node.ovsdbPort().toInt());
536 return ovsdbController.getOvsdbClient(ovsdb);
Hyunsun Mooncb799442016-01-15 20:03:18 -0800537 }
538
Hyunsun Mooncb799442016-01-15 20:03:18 -0800539 private void createIntegrationBridge(CordVtnNode node) {
Hyunsun Moon81a13562016-08-04 13:48:08 -0700540 Device device = deviceService.getDevice(node.ovsdbId());
541 if (device == null || !device.is(BridgeConfig.class)) {
542 log.error("Failed to create integration bridge on {}", node.ovsdbId());
Hyunsun Mooncb799442016-01-15 20:03:18 -0800543 return;
544 }
545
Hyunsun Moon81a13562016-08-04 13:48:08 -0700546 String dpid = node.integrationBridgeId().toString().substring(DPID_BEGIN);
547 BridgeDescription bridgeDesc = DefaultBridgeDescription.builder()
548 .name(INTEGRATION_BRIDGE)
549 .failMode(BridgeDescription.FailMode.SECURE)
550 .datapathId(dpid)
551 .disableInBand()
552 .controllers(controllers)
553 .build();
Hyunsun Mooncb799442016-01-15 20:03:18 -0800554
Hyunsun Moon81a13562016-08-04 13:48:08 -0700555 BridgeConfig bridgeConfig = device.as(BridgeConfig.class);
556 bridgeConfig.addBridge(bridgeDesc);
Hyunsun Mooncb799442016-01-15 20:03:18 -0800557 }
558
Hyunsun Mooncb799442016-01-15 20:03:18 -0800559 private void createTunnelInterface(CordVtnNode node) {
Hyunsun Moon81a13562016-08-04 13:48:08 -0700560 Device device = deviceService.getDevice(node.ovsdbId());
561 if (device == null || !device.is(InterfaceConfig.class)) {
562 log.error("Failed to create tunnel interface on {}", node.ovsdbId());
Hyunsun Mooncb799442016-01-15 20:03:18 -0800563 return;
564 }
565
Hyunsun Moon81a13562016-08-04 13:48:08 -0700566 TunnelDescription tunnelDesc = DefaultTunnelDescription.builder()
567 .deviceId(INTEGRATION_BRIDGE)
568 .ifaceName(DEFAULT_TUNNEL)
569 .type(VXLAN)
570 .remote(TunnelEndPoints.flowTunnelEndpoint())
571 .key(TunnelKeys.flowTunnelKey())
572 .build();
Hyunsun Mooncb799442016-01-15 20:03:18 -0800573
Hyunsun Moon81a13562016-08-04 13:48:08 -0700574 InterfaceConfig ifaceConfig = device.as(InterfaceConfig.class);
575 ifaceConfig.addTunnelMode(DEFAULT_TUNNEL, tunnelDesc);
Hyunsun Moonbd572c12016-01-21 00:54:52 -0800576 }
577
Hyunsun Moon81a13562016-08-04 13:48:08 -0700578 private void addSystemInterface(CordVtnNode node, String ifaceName) {
Hyunsun Moon479b7752016-05-06 20:13:28 -0700579 Session session = connect(node.sshInfo());
Hyunsun Moon81a13562016-08-04 13:48:08 -0700580 if (session == null || !isInterfaceUp(session, ifaceName)) {
581 log.warn("Interface {} is not available on {}", ifaceName, node.hostname());
582 disconnect(session);
583 return;
584 } else {
585 disconnect(session);
586 }
587
588 Device device = deviceService.getDevice(node.ovsdbId());
589 if (!device.is(BridgeConfig.class)) {
590 log.error("BridgeConfig is not supported for {}", node.ovsdbId());
Hyunsun Moon479b7752016-05-06 20:13:28 -0700591 return;
592 }
593
Hyunsun Moon81a13562016-08-04 13:48:08 -0700594 BridgeConfig bridgeConfig = device.as(BridgeConfig.class);
595 bridgeConfig.addPort(BridgeName.bridgeName(INTEGRATION_BRIDGE), ifaceName);
Hyunsun Moon126171d2016-02-09 01:55:48 -0800596 }
597
598 /**
599 * Flushes IP address from data plane interface and adds data plane IP address
600 * to integration bridge.
601 *
602 * @param node cordvtn node
603 */
604 private void setIpAddress(CordVtnNode node) {
Hyunsun Moon479b7752016-05-06 20:13:28 -0700605 Session session = connect(node.sshInfo());
Hyunsun Moon126171d2016-02-09 01:55:48 -0800606 if (session == null) {
607 log.debug("Failed to SSH to {}", node.hostname());
608 return;
609 }
Hyunsun Moon81a13562016-08-04 13:48:08 -0700610 getCurrentIps(session, INTEGRATION_BRIDGE).stream()
Hyunsun Moon0592c3d2016-06-23 14:47:52 -0700611 .filter(ip -> !ip.equals(node.localMgmtIp().ip()))
Hyunsun Moon81a13562016-08-04 13:48:08 -0700612 .filter(ip -> !ip.equals(node.dataIp().ip()))
613 .forEach(ip -> deleteIp(session, ip, INTEGRATION_BRIDGE));
Hyunsun Moon0592c3d2016-06-23 14:47:52 -0700614
Hyunsun Moon81a13562016-08-04 13:48:08 -0700615 boolean result = flushIp(session, node.dataIface()) &&
616 setInterfaceUp(session, node.dataIface()) &&
617 addIp(session, node.dataIp(), INTEGRATION_BRIDGE) &&
618 addIp(session, node.localMgmtIp(), INTEGRATION_BRIDGE) &&
619 setInterfaceUp(session, INTEGRATION_BRIDGE);
Hyunsun Moon126171d2016-02-09 01:55:48 -0800620
Hyunsun Moon479b7752016-05-06 20:13:28 -0700621 disconnect(session);
Hyunsun Moon126171d2016-02-09 01:55:48 -0800622 if (result) {
623 setNodeState(node, NodeState.COMPLETE);
Hyunsun Mooncb799442016-01-15 20:03:18 -0800624 }
625 }
626
Hyunsun Moon81a13562016-08-04 13:48:08 -0700627 private boolean isIntegrationBridgeCreated(CordVtnNode node) {
628 return deviceService.getDevice(node.integrationBridgeId()) != null &&
629 deviceService.isAvailable(node.integrationBridgeId());
Hyunsun Mooncb799442016-01-15 20:03:18 -0800630 }
631
Hyunsun Moon81a13562016-08-04 13:48:08 -0700632 private boolean isIfaceCreated(CordVtnNode node, String ifaceName) {
633 if (Strings.isNullOrEmpty(ifaceName)) {
634 return false;
635 }
636 return deviceService.getPorts(node.integrationBridgeId()).stream()
637 .filter(p -> portName(p).contains(ifaceName) &&
638 p.isEnabled())
639 .findAny()
640 .isPresent();
Hyunsun Mooncb799442016-01-15 20:03:18 -0800641 }
642
643 /**
Hyunsun Moon126171d2016-02-09 01:55:48 -0800644 * Checks if the IP addresses are correctly set.
645 *
646 * @param node cordvtn node
647 * @return true if the IP is set, false otherwise
648 */
649 private boolean isIpAddressSet(CordVtnNode node) {
Hyunsun Moon479b7752016-05-06 20:13:28 -0700650 Session session = connect(node.sshInfo());
Hyunsun Moon126171d2016-02-09 01:55:48 -0800651 if (session == null) {
652 log.debug("Failed to SSH to {}", node.hostname());
653 return false;
654 }
655
Hyunsun Moon81a13562016-08-04 13:48:08 -0700656 Set<IpAddress> intBrIps = getCurrentIps(session, INTEGRATION_BRIDGE);
657 boolean result = getCurrentIps(session, node.dataIface()).isEmpty() &&
658 isInterfaceUp(session, node.dataIface()) &&
659 intBrIps.contains(node.dataIp().ip()) &&
Hyunsun Moon126171d2016-02-09 01:55:48 -0800660 intBrIps.contains(node.localMgmtIp().ip()) &&
Hyunsun Moon81a13562016-08-04 13:48:08 -0700661 isInterfaceUp(session, INTEGRATION_BRIDGE);
Hyunsun Moon126171d2016-02-09 01:55:48 -0800662
Hyunsun Moon479b7752016-05-06 20:13:28 -0700663 disconnect(session);
Hyunsun Moon126171d2016-02-09 01:55:48 -0800664 return result;
665 }
666
667 /**
Hyunsun Mooncb799442016-01-15 20:03:18 -0800668 * Returns connect point of a given port.
669 *
670 * @param port port
671 * @return connect point
672 */
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700673 private ConnectPoint connectPoint(Port port) {
Hyunsun Mooncb799442016-01-15 20:03:18 -0800674 return new ConnectPoint(port.element().id(), port.number());
675 }
676
677 /**
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700678 * Returns cordvtn node associated with a given OVSDB device.
679 *
680 * @param ovsdbId OVSDB device id
681 * @return cordvtn node, null if it fails to find the node
682 */
683 private CordVtnNode nodeByOvsdbId(DeviceId ovsdbId) {
684 return getNodes().stream()
685 .filter(node -> node.ovsdbId().equals(ovsdbId))
686 .findFirst().orElse(null);
687 }
688
689 /**
690 * Returns cordvtn node associated with a given integration bridge.
691 *
692 * @param bridgeId device id of integration bridge
693 * @return cordvtn node, null if it fails to find the node
694 */
695 private CordVtnNode nodeByBridgeId(DeviceId bridgeId) {
696 return getNodes().stream()
Hyunsun Moon81a13562016-08-04 13:48:08 -0700697 .filter(node -> node.integrationBridgeId().equals(bridgeId))
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700698 .findFirst().orElse(null);
699 }
700
701 /**
702 * Returns port name.
703 *
704 * @param port port
705 * @return port name
706 */
707 private String portName(Port port) {
Hyunsun Moon81a13562016-08-04 13:48:08 -0700708 return port.annotations().value(PORT_NAME);
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700709 }
710
Hyunsun Mooncb799442016-01-15 20:03:18 -0800711 private class OvsdbHandler implements ConnectionHandler<Device> {
712
713 @Override
714 public void connected(Device device) {
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700715 CordVtnNode node = nodeByOvsdbId(device.id());
Hyunsun Mooncb799442016-01-15 20:03:18 -0800716 if (node != null) {
Hyunsun Moon126171d2016-02-09 01:55:48 -0800717 setNodeState(node, getNodeState(node));
Hyunsun Mooncb799442016-01-15 20:03:18 -0800718 } else {
719 log.debug("{} is detected on unregistered node, ignore it.", device.id());
720 }
721 }
722
723 @Override
724 public void disconnected(Device device) {
Hyunsun Moon81a13562016-08-04 13:48:08 -0700725 log.debug("Device {} is disconnected", device.id());
726 adminService.removeDevice(device.id());
Hyunsun Mooncb799442016-01-15 20:03:18 -0800727 }
728 }
729
730 private class BridgeHandler implements ConnectionHandler<Device> {
731
732 @Override
733 public void connected(Device device) {
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700734 CordVtnNode node = nodeByBridgeId(device.id());
Hyunsun Mooncb799442016-01-15 20:03:18 -0800735 if (node != null) {
Hyunsun Moon126171d2016-02-09 01:55:48 -0800736 setNodeState(node, getNodeState(node));
Hyunsun Mooncb799442016-01-15 20:03:18 -0800737 } else {
738 log.debug("{} is detected on unregistered node, ignore it.", device.id());
739 }
740 }
741
742 @Override
743 public void disconnected(Device device) {
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700744 CordVtnNode node = nodeByBridgeId(device.id());
Hyunsun Mooncb799442016-01-15 20:03:18 -0800745 if (node != null) {
Hyunsun Moon81a13562016-08-04 13:48:08 -0700746 log.warn("Integration Bridge is disconnected from {}", node.hostname());
Hyunsun Mooncb799442016-01-15 20:03:18 -0800747 setNodeState(node, NodeState.INCOMPLETE);
748 }
749 }
750
751 /**
752 * Handles port added situation.
Hyunsun Moon126171d2016-02-09 01:55:48 -0800753 * If the added port is tunnel or data plane interface, proceed to the remaining
754 * node initialization. Otherwise, do nothing.
Hyunsun Mooncb799442016-01-15 20:03:18 -0800755 *
756 * @param port port
757 */
758 public void portAdded(Port port) {
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700759 CordVtnNode node = nodeByBridgeId((DeviceId) port.element().id());
760 String portName = portName(port);
Hyunsun Mooncb799442016-01-15 20:03:18 -0800761
762 if (node == null) {
763 log.debug("{} is added to unregistered node, ignore it.", portName);
764 return;
765 }
766
Hyunsun Moonff55e812016-03-10 12:40:16 -0800767 log.info("Port {} is added to {}", portName, node.hostname());
Hyunsun Mooncb799442016-01-15 20:03:18 -0800768
Hyunsun Moon1e88fef2016-08-04 14:00:35 -0700769 if (node.systemIfaces().contains(portName)) {
Hyunsun Moon126171d2016-02-09 01:55:48 -0800770 setNodeState(node, getNodeState(node));
Hyunsun Moon1e88fef2016-08-04 14:00:35 -0700771 } else if (isNodeStateComplete(node)) {
772 instanceService.addInstance(connectPoint(port));
773 } else {
774 log.warn("Instance is detected on incomplete node, ignore it.", portName);
Hyunsun Mooncb799442016-01-15 20:03:18 -0800775 }
776 }
777
778 /**
779 * Handles port removed situation.
Hyunsun Moon126171d2016-02-09 01:55:48 -0800780 * If the removed port is tunnel or data plane interface, proceed to the remaining
781 * node initialization.Others, do nothing.
Hyunsun Mooncb799442016-01-15 20:03:18 -0800782 *
783 * @param port port
784 */
785 public void portRemoved(Port port) {
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700786 CordVtnNode node = nodeByBridgeId((DeviceId) port.element().id());
787 String portName = portName(port);
Hyunsun Mooncb799442016-01-15 20:03:18 -0800788
789 if (node == null) {
790 return;
791 }
792
Hyunsun Moonff55e812016-03-10 12:40:16 -0800793 log.info("Port {} is removed from {}", portName, node.hostname());
Hyunsun Mooncb799442016-01-15 20:03:18 -0800794
Hyunsun Moon1e88fef2016-08-04 14:00:35 -0700795 if (node.systemIfaces().contains(portName)) {
Hyunsun Mooncb799442016-01-15 20:03:18 -0800796 setNodeState(node, NodeState.INCOMPLETE);
Hyunsun Moon1e88fef2016-08-04 14:00:35 -0700797 } else if (isNodeStateComplete(node)) {
798 instanceService.removeInstance(connectPoint(port));
799 } else {
800 log.warn("VM is vanished from incomplete node, ignore it.", portName);
Hyunsun Mooncb799442016-01-15 20:03:18 -0800801 }
802 }
803 }
804
805 private class InternalDeviceListener implements DeviceListener {
806
807 @Override
808 public void event(DeviceEvent event) {
809
Hyunsun Moon7004fcf2016-03-08 04:36:02 -0800810 NodeId leaderNodeId = leadershipService.getLeader(appId.name());
811 if (!Objects.equals(localNodeId, leaderNodeId)) {
Hyunsun Moonff55e812016-03-10 12:40:16 -0800812 // do not allow to proceed without leadership
Hyunsun Moon7004fcf2016-03-08 04:36:02 -0800813 return;
814 }
815
Hyunsun Mooncb799442016-01-15 20:03:18 -0800816 Device device = event.subject();
817 ConnectionHandler<Device> handler =
818 (device.type().equals(SWITCH) ? bridgeHandler : ovsdbHandler);
819
820 switch (event.type()) {
821 case PORT_ADDED:
Hyunsun Moonff55e812016-03-10 12:40:16 -0800822 eventExecutor.execute(() -> bridgeHandler.portAdded(event.port()));
Hyunsun Mooncb799442016-01-15 20:03:18 -0800823 break;
824 case PORT_UPDATED:
825 if (!event.port().isEnabled()) {
Hyunsun Moonff55e812016-03-10 12:40:16 -0800826 eventExecutor.execute(() -> bridgeHandler.portRemoved(event.port()));
Hyunsun Mooncb799442016-01-15 20:03:18 -0800827 }
828 break;
829 case DEVICE_ADDED:
830 case DEVICE_AVAILABILITY_CHANGED:
831 if (deviceService.isAvailable(device.id())) {
Hyunsun Moonff55e812016-03-10 12:40:16 -0800832 eventExecutor.execute(() -> handler.connected(device));
Hyunsun Mooncb799442016-01-15 20:03:18 -0800833 } else {
Hyunsun Moonff55e812016-03-10 12:40:16 -0800834 eventExecutor.execute(() -> handler.disconnected(device));
Hyunsun Mooncb799442016-01-15 20:03:18 -0800835 }
836 break;
837 default:
838 break;
839 }
840 }
841 }
842
843 /**
Hyunsun Moon3fc17f72016-01-24 21:47:06 -0800844 * Reads cordvtn nodes from config file.
Hyunsun Mooncb799442016-01-15 20:03:18 -0800845 */
Hyunsun Moon3fc0cbc2016-11-22 18:29:12 -0800846 private void readNodes() {
847 NodeId leaderNodeId = leadershipService.getLeader(appId.name());
848 if (!Objects.equals(localNodeId, leaderNodeId)) {
849 // do not allow to proceed without leadership
850 return;
851 }
852
Hyunsun Mooncb799442016-01-15 20:03:18 -0800853 CordVtnConfig config = configRegistry.getConfig(appId, CordVtnConfig.class);
Hyunsun Mooncb799442016-01-15 20:03:18 -0800854 if (config == null) {
Hyunsun Moon3fc17f72016-01-24 21:47:06 -0800855 log.debug("No configuration found");
Hyunsun Mooncb799442016-01-15 20:03:18 -0800856 return;
857 }
Hyunsun Moonff55e812016-03-10 12:40:16 -0800858 config.cordVtnNodes().forEach(this::addOrUpdateNode);
Hyunsun Mooncb799442016-01-15 20:03:18 -0800859 }
860
Hyunsun Moon3fc0cbc2016-11-22 18:29:12 -0800861 private void readControllers() {
862 CordVtnConfig config = configRegistry.getConfig(appId, CordVtnConfig.class);
863 if (config == null) {
864 log.debug("No configuration found");
865 return;
866 }
867 controllers = config.controllers();
868 controllers.stream().forEach(ctrl -> {
869 log.debug("Added controller {}:{}", ctrl.ip(), ctrl.port());
870 });
871 }
872
Hyunsun Mooncb799442016-01-15 20:03:18 -0800873 private class InternalConfigListener implements NetworkConfigListener {
874
875 @Override
876 public void event(NetworkConfigEvent event) {
877 if (!event.configClass().equals(CordVtnConfig.class)) {
878 return;
879 }
880
881 switch (event.type()) {
882 case CONFIG_ADDED:
Hyunsun Mooncb799442016-01-15 20:03:18 -0800883 case CONFIG_UPDATED:
Hyunsun Moon3fc0cbc2016-11-22 18:29:12 -0800884 eventExecutor.execute(() -> {
885 readControllers();
886 readNodes();
887 });
Hyunsun Mooncb799442016-01-15 20:03:18 -0800888 break;
889 default:
890 break;
891 }
892 }
893 }
Hyunsun Moonff55e812016-03-10 12:40:16 -0800894
895 private class InternalMapListener implements MapEventListener<String, CordVtnNode> {
896
897 @Override
898 public void event(MapEvent<String, CordVtnNode> event) {
899 NodeId leaderNodeId = leadershipService.getLeader(appId.name());
900 if (!Objects.equals(localNodeId, leaderNodeId)) {
901 // do not allow to proceed without leadership
902 return;
903 }
904
905 CordVtnNode oldNode;
906 CordVtnNode newNode;
907
908 switch (event.type()) {
909 case UPDATE:
910 oldNode = event.oldValue().value();
911 newNode = event.newValue().value();
912
Hyunsun Moon479b7752016-05-06 20:13:28 -0700913 log.info("Reloaded {}", newNode.hostname());
Hyunsun Moonff55e812016-03-10 12:40:16 -0800914 if (!newNode.equals(oldNode)) {
Hyunsun Moonff55e812016-03-10 12:40:16 -0800915 log.debug("New node: {}", newNode);
916 }
Hyunsun Moon479b7752016-05-06 20:13:28 -0700917 // performs init procedure even if the node is not changed
918 // for robustness since it's no harm to run init procedure
919 // multiple times
Hyunsun Moonff55e812016-03-10 12:40:16 -0800920 eventExecutor.execute(() -> initNode(newNode));
921 break;
922 case INSERT:
923 newNode = event.newValue().value();
924 log.info("Added {}", newNode.hostname());
925 eventExecutor.execute(() -> initNode(newNode));
926 break;
927 case REMOVE:
928 oldNode = event.oldValue().value();
Hyunsun Moon479b7752016-05-06 20:13:28 -0700929 log.info("Removed {}", oldNode.hostname());
Hyunsun Moonff55e812016-03-10 12:40:16 -0800930 break;
931 default:
932 break;
933 }
934 }
935 }
Hyunsun Mooncb799442016-01-15 20:03:18 -0800936}