blob: 78cc22855dad270d6cc00398d6dc6f77887eef0d [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 Moon126171d2016-02-09 01:55:48 -080019import com.jcraft.jsch.Session;
Hyunsun Mooncb799442016-01-15 20:03:18 -080020import org.apache.felix.scr.annotations.Activate;
21import org.apache.felix.scr.annotations.Component;
22import org.apache.felix.scr.annotations.Deactivate;
23import org.apache.felix.scr.annotations.Reference;
24import org.apache.felix.scr.annotations.ReferenceCardinality;
25import org.apache.felix.scr.annotations.Service;
Hyunsun Moon126171d2016-02-09 01:55:48 -080026import org.onlab.packet.IpAddress;
Hyunsun Mooncb799442016-01-15 20:03:18 -080027import org.onlab.util.KryoNamespace;
28import org.onosproject.cluster.ClusterService;
Hyunsun Moon7004fcf2016-03-08 04:36:02 -080029import org.onosproject.cluster.LeadershipService;
30import org.onosproject.cluster.NodeId;
Hyunsun Moonc031d9b2016-08-04 13:57:22 -070031import org.onosproject.net.AnnotationKeys;
Hyunsun Moon81a13562016-08-04 13:48:08 -070032import org.onosproject.net.behaviour.BridgeDescription;
33import org.onosproject.net.behaviour.DefaultBridgeDescription;
34import org.onosproject.net.behaviour.InterfaceConfig;
35import org.onosproject.net.behaviour.TunnelEndPoints;
36import org.onosproject.net.behaviour.TunnelKeys;
Hyunsun Mooneaf75e62016-09-27 16:40:23 -070037import org.onosproject.net.config.ConfigFactory;
38import org.onosproject.net.config.basics.SubjectFactories;
Hyunsun Moonfd5a24e2016-10-19 19:15:48 -070039import org.opencord.cordvtn.api.node.ConnectionHandler;
40import org.opencord.cordvtn.api.config.CordVtnConfig;
41import org.opencord.cordvtn.api.node.CordVtnNode;
42import org.opencord.cordvtn.api.node.CordVtnNodeState;
43import org.opencord.cordvtn.api.instance.InstanceService;
44import org.opencord.cordvtn.api.node.NetworkAddress;
45import org.opencord.cordvtn.api.node.SshAccessInfo;
Hyunsun Mooncb799442016-01-15 20:03:18 -080046import org.onosproject.core.ApplicationId;
47import org.onosproject.core.CoreService;
Hyunsun Mooncb799442016-01-15 20:03:18 -080048import org.onosproject.net.ConnectPoint;
Hyunsun Mooncb799442016-01-15 20:03:18 -080049import org.onosproject.net.Device;
50import org.onosproject.net.DeviceId;
Hyunsun Mooncb799442016-01-15 20:03:18 -080051import org.onosproject.net.Port;
Hyunsun Moone7e4bb32016-05-16 04:32:45 -070052import org.onosproject.net.PortNumber;
Hyunsun Mooncb799442016-01-15 20:03:18 -080053import org.onosproject.net.behaviour.BridgeConfig;
54import org.onosproject.net.behaviour.BridgeName;
55import org.onosproject.net.behaviour.ControllerInfo;
56import org.onosproject.net.behaviour.DefaultTunnelDescription;
Hyunsun Mooncb799442016-01-15 20:03:18 -080057import org.onosproject.net.behaviour.TunnelDescription;
Hyunsun Mooncb799442016-01-15 20:03:18 -080058import org.onosproject.net.config.NetworkConfigEvent;
59import org.onosproject.net.config.NetworkConfigListener;
60import org.onosproject.net.config.NetworkConfigRegistry;
61import org.onosproject.net.config.NetworkConfigService;
Hyunsun Mooncb799442016-01-15 20:03:18 -080062import org.onosproject.net.device.DeviceAdminService;
63import org.onosproject.net.device.DeviceEvent;
64import org.onosproject.net.device.DeviceListener;
65import org.onosproject.net.device.DeviceService;
Hyunsun Mooncb799442016-01-15 20:03:18 -080066import org.onosproject.net.host.HostService;
67import org.onosproject.ovsdb.controller.OvsdbClientService;
68import org.onosproject.ovsdb.controller.OvsdbController;
69import org.onosproject.ovsdb.controller.OvsdbNodeId;
70import org.onosproject.store.serializers.KryoNamespaces;
71import org.onosproject.store.service.ConsistentMap;
Hyunsun Moonff55e812016-03-10 12:40:16 -080072import org.onosproject.store.service.MapEvent;
73import org.onosproject.store.service.MapEventListener;
Hyunsun Mooncb799442016-01-15 20:03:18 -080074import org.onosproject.store.service.Serializer;
75import org.onosproject.store.service.StorageService;
Hyunsun Moond05b32e2016-03-02 19:27:26 -080076import org.onosproject.store.service.Versioned;
Hyunsun Mooncb799442016-01-15 20:03:18 -080077import org.slf4j.Logger;
78
Hyunsun Mooncb799442016-01-15 20:03:18 -080079import java.util.List;
Hyunsun Moon7004fcf2016-03-08 04:36:02 -080080import java.util.Objects;
Hyunsun Moonc031d9b2016-08-04 13:57:22 -070081import java.util.Optional;
Hyunsun Moon126171d2016-02-09 01:55:48 -080082import java.util.Set;
Hyunsun Mooncb799442016-01-15 20:03:18 -080083import java.util.concurrent.ExecutorService;
Hyunsun Moon58ddbdc2016-03-07 16:37:17 -080084import java.util.stream.Collectors;
Hyunsun Mooncb799442016-01-15 20:03:18 -080085
86import static com.google.common.base.Preconditions.checkNotNull;
Hyunsun Moon537018f2016-07-27 18:51:00 -070087import static java.util.concurrent.Executors.newSingleThreadExecutor;
Hyunsun Mooncb799442016-01-15 20:03:18 -080088import static org.onlab.util.Tools.groupedThreads;
Hyunsun Moon81a13562016-08-04 13:48:08 -070089import static org.onosproject.net.AnnotationKeys.PORT_NAME;
Hyunsun Mooncb799442016-01-15 20:03:18 -080090import static org.onosproject.net.Device.Type.SWITCH;
91import static org.onosproject.net.behaviour.TunnelDescription.Type.VXLAN;
Hyunsun Moon5401aaa2016-06-12 17:40:34 -070092import static org.opencord.cordvtn.api.Constants.*;
alshabibb4d31712016-06-01 18:51:03 -070093import static org.opencord.cordvtn.impl.RemoteIpCommandUtil.*;
Hyunsun Mooncb799442016-01-15 20:03:18 -080094import static org.slf4j.LoggerFactory.getLogger;
95
96/**
97 * Reads node information from the network config file and handles the config
98 * update events.
99 * Only a leader controller performs the node addition or deletion.
100 */
101@Component(immediate = true)
102@Service(value = CordVtnNodeManager.class)
103public class CordVtnNodeManager {
104
105 protected final Logger log = getLogger(getClass());
106
107 private static final KryoNamespace.Builder NODE_SERIALIZER = KryoNamespace.newBuilder()
108 .register(KryoNamespaces.API)
109 .register(CordVtnNode.class)
Hyunsun Moon126171d2016-02-09 01:55:48 -0800110 .register(NodeState.class)
111 .register(SshAccessInfo.class)
112 .register(NetworkAddress.class);
Hyunsun Mooncb799442016-01-15 20:03:18 -0800113
Hyunsun Mooncb799442016-01-15 20:03:18 -0800114 private static final int DPID_BEGIN = 3;
Hyunsun Mooncb799442016-01-15 20:03:18 -0800115
116 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
117 protected CoreService coreService;
118
119 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
120 protected NetworkConfigRegistry configRegistry;
121
122 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
123 protected NetworkConfigService configService;
124
125 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
126 protected StorageService storageService;
127
128 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
129 protected DeviceAdminService adminService;
130
131 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Hyunsun Moon81a13562016-08-04 13:48:08 -0700132 protected OvsdbController ovsdbController;
Hyunsun Mooncb799442016-01-15 20:03:18 -0800133
134 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
135 protected ClusterService clusterService;
136
137 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Hyunsun Mooncb799442016-01-15 20:03:18 -0800138 protected DeviceService deviceService;
139
140 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
141 protected HostService hostService;
142
143 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Hyunsun Moon7004fcf2016-03-08 04:36:02 -0800144 protected LeadershipService leadershipService;
Hyunsun Mooncb799442016-01-15 20:03:18 -0800145
146 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Hyunsun Moon5401aaa2016-06-12 17:40:34 -0700147 protected InstanceService instanceService;
Hyunsun Mooncb799442016-01-15 20:03:18 -0800148
149 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700150 protected CordVtnPipeline pipeline;
Hyunsun Mooncb799442016-01-15 20:03:18 -0800151
Hyunsun Mooneaf75e62016-09-27 16:40:23 -0700152 private static final Class<CordVtnConfig> CONFIG_CLASS = CordVtnConfig.class;
153 private final ConfigFactory configFactory =
154 new ConfigFactory<ApplicationId, CordVtnConfig>(
155 SubjectFactories.APP_SUBJECT_FACTORY, CONFIG_CLASS, "cordvtn") {
156 @Override
157 public CordVtnConfig createConfig() {
158 return new CordVtnConfig();
159 }
160 };
161
Hyunsun Mooncb799442016-01-15 20:03:18 -0800162 private final ExecutorService eventExecutor =
Hyunsun Moon537018f2016-07-27 18:51:00 -0700163 newSingleThreadExecutor(groupedThreads("onos/cordvtn-node", "event-handler", log));
Hyunsun Mooncb799442016-01-15 20:03:18 -0800164
165 private final NetworkConfigListener configListener = new InternalConfigListener();
166 private final DeviceListener deviceListener = new InternalDeviceListener();
Hyunsun Moonff55e812016-03-10 12:40:16 -0800167 private final MapEventListener<String, CordVtnNode> nodeStoreListener = new InternalMapListener();
Hyunsun Mooncb799442016-01-15 20:03:18 -0800168
169 private final OvsdbHandler ovsdbHandler = new OvsdbHandler();
170 private final BridgeHandler bridgeHandler = new BridgeHandler();
171
Hyunsun Moon58ddbdc2016-03-07 16:37:17 -0800172 private ConsistentMap<String, CordVtnNode> nodeStore;
Hyunsun Mooncb799442016-01-15 20:03:18 -0800173 private ApplicationId appId;
Hyunsun Moon7004fcf2016-03-08 04:36:02 -0800174 private NodeId localNodeId;
Hyunsun Mooncb799442016-01-15 20:03:18 -0800175
Hyunsun Moon58ddbdc2016-03-07 16:37:17 -0800176 private enum NodeState implements CordVtnNodeState {
Hyunsun Mooncb799442016-01-15 20:03:18 -0800177
178 INIT {
179 @Override
180 public void process(CordVtnNodeManager nodeManager, CordVtnNode node) {
Hyunsun Moon81a13562016-08-04 13:48:08 -0700181 // make sure there is OVSDB connection
Hyunsun Moon126171d2016-02-09 01:55:48 -0800182 if (!nodeManager.isOvsdbConnected(node)) {
Hyunsun Mooncb799442016-01-15 20:03:18 -0800183 nodeManager.connectOvsdb(node);
Hyunsun Moon81a13562016-08-04 13:48:08 -0700184 return;
Hyunsun Mooncb799442016-01-15 20:03:18 -0800185 }
Hyunsun Moon81a13562016-08-04 13:48:08 -0700186 nodeManager.createIntegrationBridge(node);
Hyunsun Mooncb799442016-01-15 20:03:18 -0800187 }
188 },
189 BRIDGE_CREATED {
190 @Override
191 public void process(CordVtnNodeManager nodeManager, CordVtnNode node) {
Hyunsun Moon81a13562016-08-04 13:48:08 -0700192 // make sure there is OVSDB connection
Hyunsun Moon126171d2016-02-09 01:55:48 -0800193 if (!nodeManager.isOvsdbConnected(node)) {
Hyunsun Mooncb799442016-01-15 20:03:18 -0800194 nodeManager.connectOvsdb(node);
Hyunsun Moon81a13562016-08-04 13:48:08 -0700195 return;
196 }
197
198 nodeManager.createTunnelInterface(node);
199 nodeManager.addSystemInterface(node, node.dataIface());
200 if (node.hostMgmtIface().isPresent()) {
201 nodeManager.addSystemInterface(node, node.hostMgmtIface().get());
Hyunsun Mooncb799442016-01-15 20:03:18 -0800202 }
203 }
204 },
Hyunsun Moon126171d2016-02-09 01:55:48 -0800205 PORTS_ADDED {
Hyunsun Moonbd572c12016-01-21 00:54:52 -0800206 @Override
207 public void process(CordVtnNodeManager nodeManager, CordVtnNode node) {
Hyunsun Moon126171d2016-02-09 01:55:48 -0800208 nodeManager.setIpAddress(node);
Hyunsun Moonbd572c12016-01-21 00:54:52 -0800209 }
Hyunsun Moonbd572c12016-01-21 00:54:52 -0800210 },
Hyunsun Mooncb799442016-01-15 20:03:18 -0800211 COMPLETE {
212 @Override
213 public void process(CordVtnNodeManager nodeManager, CordVtnNode node) {
214 nodeManager.postInit(node);
215 }
216 },
217 INCOMPLETE {
218 @Override
219 public void process(CordVtnNodeManager nodeManager, CordVtnNode node) {
220 }
221 };
222
Hyunsun Mooncb799442016-01-15 20:03:18 -0800223 public abstract void process(CordVtnNodeManager nodeManager, CordVtnNode node);
224 }
225
226 @Activate
Hyunsun Moon479b7752016-05-06 20:13:28 -0700227 protected void activate() {
Hyunsun Mooneaf75e62016-09-27 16:40:23 -0700228 appId = coreService.registerApplication(CORDVTN_APP_ID);
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700229
Hyunsun Mooneaf75e62016-09-27 16:40:23 -0700230 configRegistry.registerConfigFactory(configFactory);
Hyunsun Moon7004fcf2016-03-08 04:36:02 -0800231 localNodeId = clusterService.getLocalNode().id();
232 leadershipService.runForLeadership(appId.name());
233
Hyunsun Moon58ddbdc2016-03-07 16:37:17 -0800234 nodeStore = storageService.<String, CordVtnNode>consistentMapBuilder()
Hyunsun Mooncb799442016-01-15 20:03:18 -0800235 .withSerializer(Serializer.using(NODE_SERIALIZER.build()))
236 .withName("cordvtn-nodestore")
237 .withApplicationId(appId)
238 .build();
239
Hyunsun Moonff55e812016-03-10 12:40:16 -0800240 nodeStore.addListener(nodeStoreListener);
Hyunsun Mooncb799442016-01-15 20:03:18 -0800241 deviceService.addListener(deviceListener);
242 configService.addListener(configListener);
Hyunsun Moon479b7752016-05-06 20:13:28 -0700243
244 log.info("Started");
Hyunsun Mooncb799442016-01-15 20:03:18 -0800245 }
246
247 @Deactivate
248 protected void deactivate() {
Hyunsun Mooncb799442016-01-15 20:03:18 -0800249 configService.removeListener(configListener);
250 deviceService.removeListener(deviceListener);
Hyunsun Moonff55e812016-03-10 12:40:16 -0800251 nodeStore.removeListener(nodeStoreListener);
Hyunsun Moonff55e812016-03-10 12:40:16 -0800252
Hyunsun Moon7004fcf2016-03-08 04:36:02 -0800253 leadershipService.withdraw(appId.name());
Hyunsun Mooneaf75e62016-09-27 16:40:23 -0700254 configRegistry.unregisterConfigFactory(configFactory);
Hyunsun Moonff55e812016-03-10 12:40:16 -0800255 eventExecutor.shutdown();
Hyunsun Moon479b7752016-05-06 20:13:28 -0700256
257 log.info("Stopped");
Hyunsun Mooncb799442016-01-15 20:03:18 -0800258 }
259
260 /**
Hyunsun Moonff55e812016-03-10 12:40:16 -0800261 * Adds or updates a new node to the service.
Hyunsun Mooncb799442016-01-15 20:03:18 -0800262 *
263 * @param node cordvtn node
264 */
Hyunsun Moonff55e812016-03-10 12:40:16 -0800265 public void addOrUpdateNode(CordVtnNode node) {
Hyunsun Mooncb799442016-01-15 20:03:18 -0800266 checkNotNull(node);
Hyunsun Moon58ddbdc2016-03-07 16:37:17 -0800267 nodeStore.put(node.hostname(), CordVtnNode.getUpdatedNode(node, getNodeState(node)));
Hyunsun Mooncb799442016-01-15 20:03:18 -0800268 }
269
270 /**
271 * Deletes a node from the service.
272 *
273 * @param node cordvtn node
274 */
275 public void deleteNode(CordVtnNode node) {
276 checkNotNull(node);
Hyunsun Moon81a13562016-08-04 13:48:08 -0700277 OvsdbClientService ovsdbClient = getOvsdbClient(node);
278 if (ovsdbClient != null && ovsdbClient.isConnected()) {
279 ovsdbClient.disconnect();
Hyunsun Mooncb799442016-01-15 20:03:18 -0800280 }
Hyunsun Moon58ddbdc2016-03-07 16:37:17 -0800281 nodeStore.remove(node.hostname());
Hyunsun Mooncb799442016-01-15 20:03:18 -0800282 }
283
284 /**
Hyunsun Mooncb799442016-01-15 20:03:18 -0800285 * Returns node initialization state.
286 *
287 * @param node cordvtn node
288 * @return true if initial node setup is completed, otherwise false
289 */
Hyunsun Moon126171d2016-02-09 01:55:48 -0800290 public boolean isNodeInitComplete(CordVtnNode node) {
Hyunsun Mooncb799442016-01-15 20:03:18 -0800291 checkNotNull(node);
Hyunsun Moon6066bd32016-10-24 15:35:34 -0700292 return isNodeStateComplete(node);
Hyunsun Mooncb799442016-01-15 20:03:18 -0800293 }
294
295 /**
296 * Returns the number of the nodes known to the service.
297 *
298 * @return number of nodes
299 */
300 public int getNodeCount() {
301 return nodeStore.size();
302 }
303
304 /**
305 * Returns all nodes known to the service.
306 *
307 * @return list of nodes
308 */
309 public List<CordVtnNode> getNodes() {
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700310 return nodeStore.values().stream().map(Versioned::value).collect(Collectors.toList());
Hyunsun Mooncb799442016-01-15 20:03:18 -0800311 }
312
313 /**
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700314 * Returns all nodes in complete state.
Hyunsun Mooncb799442016-01-15 20:03:18 -0800315 *
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700316 * @return set of nodes
Hyunsun Mooncb799442016-01-15 20:03:18 -0800317 */
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700318 public Set<CordVtnNode> completeNodes() {
Hyunsun Moon81a13562016-08-04 13:48:08 -0700319 return getNodes().stream().filter(this::isNodeStateComplete)
320 .collect(Collectors.toSet());
Hyunsun Mooncb799442016-01-15 20:03:18 -0800321 }
322
323 /**
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700324 * Returns physical data plane port number of a given device.
Hyunsun Mooncb799442016-01-15 20:03:18 -0800325 *
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700326 * @param deviceId integration bridge device id
327 * @return port number; null otherwise
Hyunsun Mooncb799442016-01-15 20:03:18 -0800328 */
Hyunsun Moon81a13562016-08-04 13:48:08 -0700329 public PortNumber dataPort(DeviceId deviceId) {
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700330 CordVtnNode node = nodeByBridgeId(deviceId);
331 if (node == null) {
332 log.warn("Failed to get node for {}", deviceId);
333 return null;
334 }
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700335
Hyunsun Moonc031d9b2016-08-04 13:57:22 -0700336 Optional<PortNumber> port = getPortNumber(deviceId, node.dataIface());
337 return port.isPresent() ? port.get() : null;
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700338 }
339
340 /**
341 * Returns physical data plane IP address of a given device.
342 *
343 * @param deviceId integration bridge device id
344 * @return ip address; null otherwise
345 */
Hyunsun Moon81a13562016-08-04 13:48:08 -0700346 public IpAddress dataIp(DeviceId deviceId) {
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700347 CordVtnNode node = nodeByBridgeId(deviceId);
348 if (node == null) {
349 log.warn("Failed to get node for {}", deviceId);
350 return null;
351 }
Hyunsun Moon81a13562016-08-04 13:48:08 -0700352 return node.dataIp().ip();
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700353 }
354
355 /**
356 * Returns tunnel port number of a given device.
357 *
358 * @param deviceId integration bridge device id
359 * @return port number
360 */
361 public PortNumber tunnelPort(DeviceId deviceId) {
Hyunsun Moonc031d9b2016-08-04 13:57:22 -0700362 Optional<PortNumber> port = getPortNumber(deviceId, DEFAULT_TUNNEL);
363 return port.isPresent() ? port.get() : null;
364 }
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700365
Hyunsun Moonc031d9b2016-08-04 13:57:22 -0700366 /**
367 * Returns host management interface port number if exists.
368 *
369 * @param deviceId integration bridge device id
370 * @return port number; null if it does not exist
371 */
372 public PortNumber hostManagementPort(DeviceId deviceId) {
373 CordVtnNode node = nodeByBridgeId(deviceId);
374 if (node == null) {
375 log.warn("Failed to get node for {}", deviceId);
376 return null;
377 }
378
379 if (node.hostMgmtIface().isPresent()) {
380 Optional<PortNumber> port = getPortNumber(deviceId, node.hostMgmtIface().get());
381 return port.isPresent() ? port.get() : null;
382 } else {
383 return null;
384 }
385 }
386
387 private Optional<PortNumber> getPortNumber(DeviceId deviceId, String portName) {
388 PortNumber port = deviceService.getPorts(deviceId).stream()
389 .filter(p -> p.annotations().value(AnnotationKeys.PORT_NAME).equals(portName) &&
390 p.isEnabled())
391 .map(Port::number)
392 .findAny()
393 .orElse(null);
394 return Optional.ofNullable(port);
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700395 }
396
397 /**
398 * Returns if current node state saved in nodeStore is COMPLETE or not.
399 *
400 * @param node cordvtn node
401 * @return true if it's complete state, otherwise false
402 */
403 private boolean isNodeStateComplete(CordVtnNode node) {
404 checkNotNull(node);
405
406 // the state saved in nodeStore can be wrong if IP address settings are changed
407 // after the node init has been completed since there's no way to detect it
408 // getNodeState and checkNodeInitState always return correct answer but can be slow
409 Versioned<CordVtnNode> versionedNode = nodeStore.get(node.hostname());
410 CordVtnNodeState state = versionedNode.value().state();
411 return state != null && state.equals(NodeState.COMPLETE);
412 }
413
414 /**
415 * Initiates node to serve virtual tenant network.
416 *
417 * @param node cordvtn node
418 */
419 private void initNode(CordVtnNode node) {
420 checkNotNull(node);
421
422 NodeState state = (NodeState) node.state();
423 log.debug("Processing node: {} state: {}", node.hostname(), state);
424
425 state.process(this, node);
426 }
427
428 /**
429 * Performs tasks after node initialization.
430 * It disconnects unnecessary OVSDB connection and installs initial flow
431 * rules on the device.
432 *
433 * @param node cordvtn node
434 */
435 private void postInit(CordVtnNode node) {
Hyunsun Moon81a13562016-08-04 13:48:08 -0700436 checkNotNull(node);
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700437
Hyunsun Moon81a13562016-08-04 13:48:08 -0700438 // disconnect OVSDB session once the node bootstrap is done
439 OvsdbClientService ovsdbClient = getOvsdbClient(node);
440 if (ovsdbClient != null && ovsdbClient.isConnected()) {
441 ovsdbClient.disconnect();
442 }
443
Hyunsun Moonc031d9b2016-08-04 13:57:22 -0700444 pipeline.initPipeline(node);
Hyunsun Moon81a13562016-08-04 13:48:08 -0700445
446 // adds existing instances to the host list
447 deviceService.getPorts(node.integrationBridgeId()).stream()
Hyunsun Moon1e88fef2016-08-04 14:00:35 -0700448 .filter(port -> !node.systemIfaces().contains(portName(port)) &&
449 !port.number().equals(PortNumber.LOCAL) &&
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700450 port.isEnabled())
Hyunsun Moon5401aaa2016-06-12 17:40:34 -0700451 .forEach(port -> instanceService.addInstance(connectPoint(port)));
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700452
Hyunsun Moon81a13562016-08-04 13:48:08 -0700453 // removes stale instances from the host list
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700454 hostService.getHosts().forEach(host -> {
Hyunsun Moon81a13562016-08-04 13:48:08 -0700455 if (deviceService.getPort(
456 host.location().deviceId(),
457 host.location().port()) == null) {
458 instanceService.removeInstance(host.location());
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700459 }
460 });
461
462 log.info("Finished init {}", node.hostname());
Hyunsun Mooncb799442016-01-15 20:03:18 -0800463 }
464
465 /**
Hyunsun Mooncb799442016-01-15 20:03:18 -0800466 * Sets a new state for a given cordvtn node.
467 *
468 * @param node cordvtn node
469 * @param newState new node state
470 */
471 private void setNodeState(CordVtnNode node, NodeState newState) {
472 checkNotNull(node);
Hyunsun Moonff55e812016-03-10 12:40:16 -0800473 log.debug("Changed {} state: {}", node.hostname(), newState);
Hyunsun Moon58ddbdc2016-03-07 16:37:17 -0800474 nodeStore.put(node.hostname(), CordVtnNode.getUpdatedNode(node, newState));
Hyunsun Mooncb799442016-01-15 20:03:18 -0800475 }
476
477 /**
478 * Checks current state of a given cordvtn node and returns it.
479 *
480 * @param node cordvtn node
481 * @return node state
482 */
Hyunsun Moon126171d2016-02-09 01:55:48 -0800483 private NodeState getNodeState(CordVtnNode node) {
Hyunsun Mooncb799442016-01-15 20:03:18 -0800484 checkNotNull(node);
Hyunsun Moon81a13562016-08-04 13:48:08 -0700485 if (!isIntegrationBridgeCreated(node)) {
Hyunsun Mooncb799442016-01-15 20:03:18 -0800486 return NodeState.INIT;
487 }
Hyunsun Moon81a13562016-08-04 13:48:08 -0700488 for (String iface : node.systemIfaces()) {
489 if (!isIfaceCreated(node, iface)) {
490 return NodeState.BRIDGE_CREATED;
491 }
492 }
493 if (!isIpAddressSet(node)) {
494 return NodeState.PORTS_ADDED;
495 }
496 return NodeState.COMPLETE;
Hyunsun Mooncb799442016-01-15 20:03:18 -0800497 }
498
499 /**
Hyunsun Mooncb799442016-01-15 20:03:18 -0800500 * Returns connection state of OVSDB server for a given node.
501 *
502 * @param node cordvtn node
503 * @return true if it is connected, false otherwise
504 */
Hyunsun Moon126171d2016-02-09 01:55:48 -0800505 private boolean isOvsdbConnected(CordVtnNode node) {
Hyunsun Mooncb799442016-01-15 20:03:18 -0800506 checkNotNull(node);
Hyunsun Mooncb799442016-01-15 20:03:18 -0800507 OvsdbClientService ovsdbClient = getOvsdbClient(node);
508 return deviceService.isAvailable(node.ovsdbId()) &&
Hyunsun Moon81a13562016-08-04 13:48:08 -0700509 ovsdbClient != null &&
510 ovsdbClient.isConnected();
Hyunsun Mooncb799442016-01-15 20:03:18 -0800511 }
512
513 /**
514 * Connects to OVSDB server for a given node.
515 *
516 * @param node cordvtn node
517 */
518 private void connectOvsdb(CordVtnNode node) {
519 checkNotNull(node);
Hyunsun Moon81a13562016-08-04 13:48:08 -0700520 ovsdbController.connect(node.hostMgmtIp().ip(), node.ovsdbPort());
Hyunsun Mooncb799442016-01-15 20:03:18 -0800521 }
522
523 /**
524 * Returns OVSDB client for a given node.
525 *
526 * @param node cordvtn node
Hyunsun Moon81a13562016-08-04 13:48:08 -0700527 * @return ovsdb client, or null if there's no ovsdb connection
Hyunsun Mooncb799442016-01-15 20:03:18 -0800528 */
529 private OvsdbClientService getOvsdbClient(CordVtnNode node) {
530 checkNotNull(node);
Hyunsun Moon81a13562016-08-04 13:48:08 -0700531 OvsdbNodeId ovsdb = new OvsdbNodeId(
532 node.hostMgmtIp().ip(), node.ovsdbPort().toInt());
533 return ovsdbController.getOvsdbClient(ovsdb);
Hyunsun Mooncb799442016-01-15 20:03:18 -0800534 }
535
Hyunsun Mooncb799442016-01-15 20:03:18 -0800536 private void createIntegrationBridge(CordVtnNode node) {
Hyunsun Moon81a13562016-08-04 13:48:08 -0700537 Device device = deviceService.getDevice(node.ovsdbId());
538 if (device == null || !device.is(BridgeConfig.class)) {
539 log.error("Failed to create integration bridge on {}", node.ovsdbId());
Hyunsun Mooncb799442016-01-15 20:03:18 -0800540 return;
541 }
542
Hyunsun Moon81a13562016-08-04 13:48:08 -0700543 List<ControllerInfo> controllers = clusterService.getNodes().stream()
544 .map(controller -> new ControllerInfo(controller.ip(), OF_PORT, "tcp"))
545 .collect(Collectors.toList());
Hyunsun Mooncb799442016-01-15 20:03:18 -0800546
Hyunsun Moon81a13562016-08-04 13:48:08 -0700547 String dpid = node.integrationBridgeId().toString().substring(DPID_BEGIN);
548 BridgeDescription bridgeDesc = DefaultBridgeDescription.builder()
549 .name(INTEGRATION_BRIDGE)
550 .failMode(BridgeDescription.FailMode.SECURE)
551 .datapathId(dpid)
552 .disableInBand()
553 .controllers(controllers)
554 .build();
Hyunsun Mooncb799442016-01-15 20:03:18 -0800555
Hyunsun Moon81a13562016-08-04 13:48:08 -0700556 BridgeConfig bridgeConfig = device.as(BridgeConfig.class);
557 bridgeConfig.addBridge(bridgeDesc);
Hyunsun Mooncb799442016-01-15 20:03:18 -0800558 }
559
Hyunsun Mooncb799442016-01-15 20:03:18 -0800560 private void createTunnelInterface(CordVtnNode node) {
Hyunsun Moon81a13562016-08-04 13:48:08 -0700561 Device device = deviceService.getDevice(node.ovsdbId());
562 if (device == null || !device.is(InterfaceConfig.class)) {
563 log.error("Failed to create tunnel interface on {}", node.ovsdbId());
Hyunsun Mooncb799442016-01-15 20:03:18 -0800564 return;
565 }
566
Hyunsun Moon81a13562016-08-04 13:48:08 -0700567 TunnelDescription tunnelDesc = DefaultTunnelDescription.builder()
568 .deviceId(INTEGRATION_BRIDGE)
569 .ifaceName(DEFAULT_TUNNEL)
570 .type(VXLAN)
571 .remote(TunnelEndPoints.flowTunnelEndpoint())
572 .key(TunnelKeys.flowTunnelKey())
573 .build();
Hyunsun Mooncb799442016-01-15 20:03:18 -0800574
Hyunsun Moon81a13562016-08-04 13:48:08 -0700575 InterfaceConfig ifaceConfig = device.as(InterfaceConfig.class);
576 ifaceConfig.addTunnelMode(DEFAULT_TUNNEL, tunnelDesc);
Hyunsun Moonbd572c12016-01-21 00:54:52 -0800577 }
578
Hyunsun Moon81a13562016-08-04 13:48:08 -0700579 private void addSystemInterface(CordVtnNode node, String ifaceName) {
Hyunsun Moon479b7752016-05-06 20:13:28 -0700580 Session session = connect(node.sshInfo());
Hyunsun Moon81a13562016-08-04 13:48:08 -0700581 if (session == null || !isInterfaceUp(session, ifaceName)) {
582 log.warn("Interface {} is not available on {}", ifaceName, node.hostname());
583 disconnect(session);
584 return;
585 } else {
586 disconnect(session);
587 }
588
589 Device device = deviceService.getDevice(node.ovsdbId());
590 if (!device.is(BridgeConfig.class)) {
591 log.error("BridgeConfig is not supported for {}", node.ovsdbId());
Hyunsun Moon479b7752016-05-06 20:13:28 -0700592 return;
593 }
594
Hyunsun Moon81a13562016-08-04 13:48:08 -0700595 BridgeConfig bridgeConfig = device.as(BridgeConfig.class);
596 bridgeConfig.addPort(BridgeName.bridgeName(INTEGRATION_BRIDGE), ifaceName);
Hyunsun Moon126171d2016-02-09 01:55:48 -0800597 }
598
599 /**
600 * Flushes IP address from data plane interface and adds data plane IP address
601 * to integration bridge.
602 *
603 * @param node cordvtn node
604 */
605 private void setIpAddress(CordVtnNode node) {
Hyunsun Moon479b7752016-05-06 20:13:28 -0700606 Session session = connect(node.sshInfo());
Hyunsun Moon126171d2016-02-09 01:55:48 -0800607 if (session == null) {
608 log.debug("Failed to SSH to {}", node.hostname());
609 return;
610 }
Hyunsun Moon81a13562016-08-04 13:48:08 -0700611 getCurrentIps(session, INTEGRATION_BRIDGE).stream()
Hyunsun Moon0592c3d2016-06-23 14:47:52 -0700612 .filter(ip -> !ip.equals(node.localMgmtIp().ip()))
Hyunsun Moon81a13562016-08-04 13:48:08 -0700613 .filter(ip -> !ip.equals(node.dataIp().ip()))
614 .forEach(ip -> deleteIp(session, ip, INTEGRATION_BRIDGE));
Hyunsun Moon0592c3d2016-06-23 14:47:52 -0700615
Hyunsun Moon81a13562016-08-04 13:48:08 -0700616 boolean result = flushIp(session, node.dataIface()) &&
617 setInterfaceUp(session, node.dataIface()) &&
618 addIp(session, node.dataIp(), INTEGRATION_BRIDGE) &&
619 addIp(session, node.localMgmtIp(), INTEGRATION_BRIDGE) &&
620 setInterfaceUp(session, INTEGRATION_BRIDGE);
Hyunsun Moon126171d2016-02-09 01:55:48 -0800621
Hyunsun Moon479b7752016-05-06 20:13:28 -0700622 disconnect(session);
Hyunsun Moon126171d2016-02-09 01:55:48 -0800623 if (result) {
624 setNodeState(node, NodeState.COMPLETE);
Hyunsun Mooncb799442016-01-15 20:03:18 -0800625 }
626 }
627
Hyunsun Moon81a13562016-08-04 13:48:08 -0700628 private boolean isIntegrationBridgeCreated(CordVtnNode node) {
629 return deviceService.getDevice(node.integrationBridgeId()) != null &&
630 deviceService.isAvailable(node.integrationBridgeId());
Hyunsun Mooncb799442016-01-15 20:03:18 -0800631 }
632
Hyunsun Moon81a13562016-08-04 13:48:08 -0700633 private boolean isIfaceCreated(CordVtnNode node, String ifaceName) {
634 if (Strings.isNullOrEmpty(ifaceName)) {
635 return false;
636 }
637 return deviceService.getPorts(node.integrationBridgeId()).stream()
638 .filter(p -> portName(p).contains(ifaceName) &&
639 p.isEnabled())
640 .findAny()
641 .isPresent();
Hyunsun Mooncb799442016-01-15 20:03:18 -0800642 }
643
644 /**
Hyunsun Moon126171d2016-02-09 01:55:48 -0800645 * Checks if the IP addresses are correctly set.
646 *
647 * @param node cordvtn node
648 * @return true if the IP is set, false otherwise
649 */
650 private boolean isIpAddressSet(CordVtnNode node) {
Hyunsun Moon479b7752016-05-06 20:13:28 -0700651 Session session = connect(node.sshInfo());
Hyunsun Moon126171d2016-02-09 01:55:48 -0800652 if (session == null) {
653 log.debug("Failed to SSH to {}", node.hostname());
654 return false;
655 }
656
Hyunsun Moon81a13562016-08-04 13:48:08 -0700657 Set<IpAddress> intBrIps = getCurrentIps(session, INTEGRATION_BRIDGE);
658 boolean result = getCurrentIps(session, node.dataIface()).isEmpty() &&
659 isInterfaceUp(session, node.dataIface()) &&
660 intBrIps.contains(node.dataIp().ip()) &&
Hyunsun Moon126171d2016-02-09 01:55:48 -0800661 intBrIps.contains(node.localMgmtIp().ip()) &&
Hyunsun Moon81a13562016-08-04 13:48:08 -0700662 isInterfaceUp(session, INTEGRATION_BRIDGE);
Hyunsun Moon126171d2016-02-09 01:55:48 -0800663
Hyunsun Moon479b7752016-05-06 20:13:28 -0700664 disconnect(session);
Hyunsun Moon126171d2016-02-09 01:55:48 -0800665 return result;
666 }
667
668 /**
Hyunsun Mooncb799442016-01-15 20:03:18 -0800669 * Returns connect point of a given port.
670 *
671 * @param port port
672 * @return connect point
673 */
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700674 private ConnectPoint connectPoint(Port port) {
Hyunsun Mooncb799442016-01-15 20:03:18 -0800675 return new ConnectPoint(port.element().id(), port.number());
676 }
677
678 /**
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700679 * Returns cordvtn node associated with a given OVSDB device.
680 *
681 * @param ovsdbId OVSDB device id
682 * @return cordvtn node, null if it fails to find the node
683 */
684 private CordVtnNode nodeByOvsdbId(DeviceId ovsdbId) {
685 return getNodes().stream()
686 .filter(node -> node.ovsdbId().equals(ovsdbId))
687 .findFirst().orElse(null);
688 }
689
690 /**
691 * Returns cordvtn node associated with a given integration bridge.
692 *
693 * @param bridgeId device id of integration bridge
694 * @return cordvtn node, null if it fails to find the node
695 */
696 private CordVtnNode nodeByBridgeId(DeviceId bridgeId) {
697 return getNodes().stream()
Hyunsun Moon81a13562016-08-04 13:48:08 -0700698 .filter(node -> node.integrationBridgeId().equals(bridgeId))
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700699 .findFirst().orElse(null);
700 }
701
702 /**
703 * Returns port name.
704 *
705 * @param port port
706 * @return port name
707 */
708 private String portName(Port port) {
Hyunsun Moon81a13562016-08-04 13:48:08 -0700709 return port.annotations().value(PORT_NAME);
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700710 }
711
Hyunsun Mooncb799442016-01-15 20:03:18 -0800712 private class OvsdbHandler implements ConnectionHandler<Device> {
713
714 @Override
715 public void connected(Device device) {
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700716 CordVtnNode node = nodeByOvsdbId(device.id());
Hyunsun Mooncb799442016-01-15 20:03:18 -0800717 if (node != null) {
Hyunsun Moon126171d2016-02-09 01:55:48 -0800718 setNodeState(node, getNodeState(node));
Hyunsun Mooncb799442016-01-15 20:03:18 -0800719 } else {
720 log.debug("{} is detected on unregistered node, ignore it.", device.id());
721 }
722 }
723
724 @Override
725 public void disconnected(Device device) {
Hyunsun Moon81a13562016-08-04 13:48:08 -0700726 log.debug("Device {} is disconnected", device.id());
727 adminService.removeDevice(device.id());
Hyunsun Mooncb799442016-01-15 20:03:18 -0800728 }
729 }
730
731 private class BridgeHandler implements ConnectionHandler<Device> {
732
733 @Override
734 public void connected(Device device) {
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700735 CordVtnNode node = nodeByBridgeId(device.id());
Hyunsun Mooncb799442016-01-15 20:03:18 -0800736 if (node != null) {
Hyunsun Moon126171d2016-02-09 01:55:48 -0800737 setNodeState(node, getNodeState(node));
Hyunsun Mooncb799442016-01-15 20:03:18 -0800738 } else {
739 log.debug("{} is detected on unregistered node, ignore it.", device.id());
740 }
741 }
742
743 @Override
744 public void disconnected(Device device) {
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700745 CordVtnNode node = nodeByBridgeId(device.id());
Hyunsun Mooncb799442016-01-15 20:03:18 -0800746 if (node != null) {
Hyunsun Moon81a13562016-08-04 13:48:08 -0700747 log.warn("Integration Bridge is disconnected from {}", node.hostname());
Hyunsun Mooncb799442016-01-15 20:03:18 -0800748 setNodeState(node, NodeState.INCOMPLETE);
749 }
750 }
751
752 /**
753 * Handles port added situation.
Hyunsun Moon126171d2016-02-09 01:55:48 -0800754 * If the added port is tunnel or data plane interface, proceed to the remaining
755 * node initialization. Otherwise, do nothing.
Hyunsun Mooncb799442016-01-15 20:03:18 -0800756 *
757 * @param port port
758 */
759 public void portAdded(Port port) {
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700760 CordVtnNode node = nodeByBridgeId((DeviceId) port.element().id());
761 String portName = portName(port);
Hyunsun Mooncb799442016-01-15 20:03:18 -0800762
763 if (node == null) {
764 log.debug("{} is added to unregistered node, ignore it.", portName);
765 return;
766 }
767
Hyunsun Moonff55e812016-03-10 12:40:16 -0800768 log.info("Port {} is added to {}", portName, node.hostname());
Hyunsun Mooncb799442016-01-15 20:03:18 -0800769
Hyunsun Moon1e88fef2016-08-04 14:00:35 -0700770 if (node.systemIfaces().contains(portName)) {
Hyunsun Moon126171d2016-02-09 01:55:48 -0800771 setNodeState(node, getNodeState(node));
Hyunsun Moon1e88fef2016-08-04 14:00:35 -0700772 } else if (isNodeStateComplete(node)) {
773 instanceService.addInstance(connectPoint(port));
774 } else {
775 log.warn("Instance is detected on incomplete node, ignore it.", portName);
Hyunsun Mooncb799442016-01-15 20:03:18 -0800776 }
777 }
778
779 /**
780 * Handles port removed situation.
Hyunsun Moon126171d2016-02-09 01:55:48 -0800781 * If the removed port is tunnel or data plane interface, proceed to the remaining
782 * node initialization.Others, do nothing.
Hyunsun Mooncb799442016-01-15 20:03:18 -0800783 *
784 * @param port port
785 */
786 public void portRemoved(Port port) {
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700787 CordVtnNode node = nodeByBridgeId((DeviceId) port.element().id());
788 String portName = portName(port);
Hyunsun Mooncb799442016-01-15 20:03:18 -0800789
790 if (node == null) {
791 return;
792 }
793
Hyunsun Moonff55e812016-03-10 12:40:16 -0800794 log.info("Port {} is removed from {}", portName, node.hostname());
Hyunsun Mooncb799442016-01-15 20:03:18 -0800795
Hyunsun Moon1e88fef2016-08-04 14:00:35 -0700796 if (node.systemIfaces().contains(portName)) {
Hyunsun Mooncb799442016-01-15 20:03:18 -0800797 setNodeState(node, NodeState.INCOMPLETE);
Hyunsun Moon1e88fef2016-08-04 14:00:35 -0700798 } else if (isNodeStateComplete(node)) {
799 instanceService.removeInstance(connectPoint(port));
800 } else {
801 log.warn("VM is vanished from incomplete node, ignore it.", portName);
Hyunsun Mooncb799442016-01-15 20:03:18 -0800802 }
803 }
804 }
805
806 private class InternalDeviceListener implements DeviceListener {
807
808 @Override
809 public void event(DeviceEvent event) {
810
Hyunsun Moon7004fcf2016-03-08 04:36:02 -0800811 NodeId leaderNodeId = leadershipService.getLeader(appId.name());
812 if (!Objects.equals(localNodeId, leaderNodeId)) {
Hyunsun Moonff55e812016-03-10 12:40:16 -0800813 // do not allow to proceed without leadership
Hyunsun Moon7004fcf2016-03-08 04:36:02 -0800814 return;
815 }
816
Hyunsun Mooncb799442016-01-15 20:03:18 -0800817 Device device = event.subject();
818 ConnectionHandler<Device> handler =
819 (device.type().equals(SWITCH) ? bridgeHandler : ovsdbHandler);
820
821 switch (event.type()) {
822 case PORT_ADDED:
Hyunsun Moonff55e812016-03-10 12:40:16 -0800823 eventExecutor.execute(() -> bridgeHandler.portAdded(event.port()));
Hyunsun Mooncb799442016-01-15 20:03:18 -0800824 break;
825 case PORT_UPDATED:
826 if (!event.port().isEnabled()) {
Hyunsun Moonff55e812016-03-10 12:40:16 -0800827 eventExecutor.execute(() -> bridgeHandler.portRemoved(event.port()));
Hyunsun Mooncb799442016-01-15 20:03:18 -0800828 }
829 break;
830 case DEVICE_ADDED:
831 case DEVICE_AVAILABILITY_CHANGED:
832 if (deviceService.isAvailable(device.id())) {
Hyunsun Moonff55e812016-03-10 12:40:16 -0800833 eventExecutor.execute(() -> handler.connected(device));
Hyunsun Mooncb799442016-01-15 20:03:18 -0800834 } else {
Hyunsun Moonff55e812016-03-10 12:40:16 -0800835 eventExecutor.execute(() -> handler.disconnected(device));
Hyunsun Mooncb799442016-01-15 20:03:18 -0800836 }
837 break;
838 default:
839 break;
840 }
841 }
842 }
843
844 /**
Hyunsun Moon3fc17f72016-01-24 21:47:06 -0800845 * Reads cordvtn nodes from config file.
Hyunsun Mooncb799442016-01-15 20:03:18 -0800846 */
847 private void readConfiguration() {
848 CordVtnConfig config = configRegistry.getConfig(appId, CordVtnConfig.class);
Hyunsun Mooncb799442016-01-15 20:03:18 -0800849 if (config == null) {
Hyunsun Moon3fc17f72016-01-24 21:47:06 -0800850 log.debug("No configuration found");
Hyunsun Mooncb799442016-01-15 20:03:18 -0800851 return;
852 }
Hyunsun Moonff55e812016-03-10 12:40:16 -0800853 config.cordVtnNodes().forEach(this::addOrUpdateNode);
Hyunsun Mooncb799442016-01-15 20:03:18 -0800854 }
855
856 private class InternalConfigListener implements NetworkConfigListener {
857
858 @Override
859 public void event(NetworkConfigEvent event) {
Hyunsun Moonff55e812016-03-10 12:40:16 -0800860 NodeId leaderNodeId = leadershipService.getLeader(appId.name());
861 if (!Objects.equals(localNodeId, leaderNodeId)) {
862 // do not allow to proceed without leadership
863 return;
864 }
865
Hyunsun Mooncb799442016-01-15 20:03:18 -0800866 if (!event.configClass().equals(CordVtnConfig.class)) {
867 return;
868 }
869
870 switch (event.type()) {
871 case CONFIG_ADDED:
Hyunsun Mooncb799442016-01-15 20:03:18 -0800872 case CONFIG_UPDATED:
Hyunsun Mooncb799442016-01-15 20:03:18 -0800873 eventExecutor.execute(CordVtnNodeManager.this::readConfiguration);
874 break;
875 default:
876 break;
877 }
878 }
879 }
Hyunsun Moonff55e812016-03-10 12:40:16 -0800880
881 private class InternalMapListener implements MapEventListener<String, CordVtnNode> {
882
883 @Override
884 public void event(MapEvent<String, CordVtnNode> event) {
885 NodeId leaderNodeId = leadershipService.getLeader(appId.name());
886 if (!Objects.equals(localNodeId, leaderNodeId)) {
887 // do not allow to proceed without leadership
888 return;
889 }
890
891 CordVtnNode oldNode;
892 CordVtnNode newNode;
893
894 switch (event.type()) {
895 case UPDATE:
896 oldNode = event.oldValue().value();
897 newNode = event.newValue().value();
898
Hyunsun Moon479b7752016-05-06 20:13:28 -0700899 log.info("Reloaded {}", newNode.hostname());
Hyunsun Moonff55e812016-03-10 12:40:16 -0800900 if (!newNode.equals(oldNode)) {
Hyunsun Moonff55e812016-03-10 12:40:16 -0800901 log.debug("New node: {}", newNode);
902 }
Hyunsun Moon479b7752016-05-06 20:13:28 -0700903 // performs init procedure even if the node is not changed
904 // for robustness since it's no harm to run init procedure
905 // multiple times
Hyunsun Moonff55e812016-03-10 12:40:16 -0800906 eventExecutor.execute(() -> initNode(newNode));
907 break;
908 case INSERT:
909 newNode = event.newValue().value();
910 log.info("Added {}", newNode.hostname());
911 eventExecutor.execute(() -> initNode(newNode));
912 break;
913 case REMOVE:
914 oldNode = event.oldValue().value();
Hyunsun Moon479b7752016-05-06 20:13:28 -0700915 log.info("Removed {}", oldNode.hostname());
Hyunsun Moonff55e812016-03-10 12:40:16 -0800916 break;
917 default:
918 break;
919 }
920 }
921 }
Hyunsun Mooncb799442016-01-15 20:03:18 -0800922}