blob: f7f9c2d0657e8e84ef2262fba75e06ea8791ca78 [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 Mooncb799442016-01-15 20:03:18 -080032import org.onosproject.core.ApplicationId;
33import org.onosproject.core.CoreService;
Hyunsun Moon0984cbd2016-12-01 17:34:11 -080034import org.onosproject.net.AnnotationKeys;
Hyunsun Mooncb799442016-01-15 20:03:18 -080035import org.onosproject.net.ConnectPoint;
Hyunsun Mooncb799442016-01-15 20:03:18 -080036import org.onosproject.net.Device;
37import org.onosproject.net.DeviceId;
Hyunsun Mooncb799442016-01-15 20:03:18 -080038import org.onosproject.net.Port;
Hyunsun Moone7e4bb32016-05-16 04:32:45 -070039import org.onosproject.net.PortNumber;
Hyunsun Mooncb799442016-01-15 20:03:18 -080040import org.onosproject.net.behaviour.BridgeConfig;
Hyunsun Moon0984cbd2016-12-01 17:34:11 -080041import org.onosproject.net.behaviour.BridgeDescription;
Hyunsun Mooncb799442016-01-15 20:03:18 -080042import org.onosproject.net.behaviour.BridgeName;
43import org.onosproject.net.behaviour.ControllerInfo;
Hyunsun Moon0984cbd2016-12-01 17:34:11 -080044import org.onosproject.net.behaviour.DefaultBridgeDescription;
Hyunsun Mooncb799442016-01-15 20:03:18 -080045import org.onosproject.net.behaviour.DefaultTunnelDescription;
Hyunsun Moon0984cbd2016-12-01 17:34:11 -080046import org.onosproject.net.behaviour.InterfaceConfig;
Hyunsun Mooncb799442016-01-15 20:03:18 -080047import org.onosproject.net.behaviour.TunnelDescription;
Hyunsun Moon0984cbd2016-12-01 17:34:11 -080048import org.onosproject.net.behaviour.TunnelEndPoints;
49import org.onosproject.net.behaviour.TunnelKeys;
Hyunsun Mooncb799442016-01-15 20:03:18 -080050import org.onosproject.net.config.NetworkConfigEvent;
51import org.onosproject.net.config.NetworkConfigListener;
Hyunsun Mooncb799442016-01-15 20:03:18 -080052import org.onosproject.net.config.NetworkConfigService;
Hyunsun Mooncb799442016-01-15 20:03:18 -080053import org.onosproject.net.device.DeviceAdminService;
54import org.onosproject.net.device.DeviceEvent;
55import org.onosproject.net.device.DeviceListener;
56import org.onosproject.net.device.DeviceService;
Hyunsun Mooncb799442016-01-15 20:03:18 -080057import org.onosproject.net.host.HostService;
58import org.onosproject.ovsdb.controller.OvsdbClientService;
59import org.onosproject.ovsdb.controller.OvsdbController;
60import org.onosproject.ovsdb.controller.OvsdbNodeId;
61import org.onosproject.store.serializers.KryoNamespaces;
62import org.onosproject.store.service.ConsistentMap;
Hyunsun Moonff55e812016-03-10 12:40:16 -080063import org.onosproject.store.service.MapEvent;
64import org.onosproject.store.service.MapEventListener;
Hyunsun Mooncb799442016-01-15 20:03:18 -080065import org.onosproject.store.service.Serializer;
66import org.onosproject.store.service.StorageService;
Hyunsun Moond05b32e2016-03-02 19:27:26 -080067import org.onosproject.store.service.Versioned;
Hyunsun Moon0984cbd2016-12-01 17:34:11 -080068import org.opencord.cordvtn.api.config.CordVtnConfig;
69import org.opencord.cordvtn.api.instance.InstanceService;
70import org.opencord.cordvtn.api.node.ConnectionHandler;
71import org.opencord.cordvtn.api.node.CordVtnNode;
72import org.opencord.cordvtn.api.node.CordVtnNodeState;
73import org.opencord.cordvtn.api.node.NetworkAddress;
74import org.opencord.cordvtn.api.node.SshAccessInfo;
Hyunsun Mooncb799442016-01-15 20:03:18 -080075import org.slf4j.Logger;
76
Hyunsun Mooncb799442016-01-15 20:03:18 -080077import java.util.List;
Hyunsun Moon7004fcf2016-03-08 04:36:02 -080078import java.util.Objects;
Hyunsun Moonc031d9b2016-08-04 13:57:22 -070079import java.util.Optional;
Hyunsun Moon126171d2016-02-09 01:55:48 -080080import java.util.Set;
Hyunsun Mooncb799442016-01-15 20:03:18 -080081import java.util.concurrent.ExecutorService;
Hyunsun Moon58ddbdc2016-03-07 16:37:17 -080082import java.util.stream.Collectors;
Hyunsun Mooncb799442016-01-15 20:03:18 -080083
84import static com.google.common.base.Preconditions.checkNotNull;
Hyunsun Moon537018f2016-07-27 18:51:00 -070085import static java.util.concurrent.Executors.newSingleThreadExecutor;
Hyunsun Mooncb799442016-01-15 20:03:18 -080086import static org.onlab.util.Tools.groupedThreads;
Hyunsun Moon81a13562016-08-04 13:48:08 -070087import static org.onosproject.net.AnnotationKeys.PORT_NAME;
Hyunsun Mooncb799442016-01-15 20:03:18 -080088import static org.onosproject.net.Device.Type.SWITCH;
89import static org.onosproject.net.behaviour.TunnelDescription.Type.VXLAN;
Hyunsun Moon5401aaa2016-06-12 17:40:34 -070090import static org.opencord.cordvtn.api.Constants.*;
alshabibb4d31712016-06-01 18:51:03 -070091import static org.opencord.cordvtn.impl.RemoteIpCommandUtil.*;
Hyunsun Mooncb799442016-01-15 20:03:18 -080092import static org.slf4j.LoggerFactory.getLogger;
93
94/**
95 * Reads node information from the network config file and handles the config
96 * update events.
97 * Only a leader controller performs the node addition or deletion.
98 */
99@Component(immediate = true)
100@Service(value = CordVtnNodeManager.class)
101public class CordVtnNodeManager {
102
103 protected final Logger log = getLogger(getClass());
104
105 private static final KryoNamespace.Builder NODE_SERIALIZER = KryoNamespace.newBuilder()
106 .register(KryoNamespaces.API)
107 .register(CordVtnNode.class)
Hyunsun Moon126171d2016-02-09 01:55:48 -0800108 .register(NodeState.class)
109 .register(SshAccessInfo.class)
110 .register(NetworkAddress.class);
Hyunsun Mooncb799442016-01-15 20:03:18 -0800111
Hyunsun Mooncb799442016-01-15 20:03:18 -0800112 private static final int DPID_BEGIN = 3;
Hyunsun Mooncb799442016-01-15 20:03:18 -0800113
114 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
115 protected CoreService coreService;
116
117 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Hyunsun Mooncb799442016-01-15 20:03:18 -0800118 protected NetworkConfigService configService;
119
120 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
121 protected StorageService storageService;
122
123 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
124 protected DeviceAdminService adminService;
125
126 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Hyunsun Moon81a13562016-08-04 13:48:08 -0700127 protected OvsdbController ovsdbController;
Hyunsun Mooncb799442016-01-15 20:03:18 -0800128
129 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
130 protected ClusterService clusterService;
131
132 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Hyunsun Mooncb799442016-01-15 20:03:18 -0800133 protected DeviceService deviceService;
134
135 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
136 protected HostService hostService;
137
138 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Hyunsun Moon7004fcf2016-03-08 04:36:02 -0800139 protected LeadershipService leadershipService;
Hyunsun Mooncb799442016-01-15 20:03:18 -0800140
141 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Hyunsun Moon5401aaa2016-06-12 17:40:34 -0700142 protected InstanceService instanceService;
Hyunsun Mooncb799442016-01-15 20:03:18 -0800143
144 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700145 protected CordVtnPipeline pipeline;
Hyunsun Mooncb799442016-01-15 20:03:18 -0800146
Hyunsun Mooncb799442016-01-15 20:03:18 -0800147 private final ExecutorService eventExecutor =
Hyunsun Moon537018f2016-07-27 18:51:00 -0700148 newSingleThreadExecutor(groupedThreads("onos/cordvtn-node", "event-handler", log));
Hyunsun Mooncb799442016-01-15 20:03:18 -0800149
150 private final NetworkConfigListener configListener = new InternalConfigListener();
151 private final DeviceListener deviceListener = new InternalDeviceListener();
Hyunsun Moonff55e812016-03-10 12:40:16 -0800152 private final MapEventListener<String, CordVtnNode> nodeStoreListener = new InternalMapListener();
Hyunsun Mooncb799442016-01-15 20:03:18 -0800153
154 private final OvsdbHandler ovsdbHandler = new OvsdbHandler();
155 private final BridgeHandler bridgeHandler = new BridgeHandler();
156
Hyunsun Moon58ddbdc2016-03-07 16:37:17 -0800157 private ConsistentMap<String, CordVtnNode> nodeStore;
Hyunsun Moon3fc0cbc2016-11-22 18:29:12 -0800158 private List<ControllerInfo> controllers = Lists.newArrayList();
Hyunsun Mooncb799442016-01-15 20:03:18 -0800159 private ApplicationId appId;
Hyunsun Moon7004fcf2016-03-08 04:36:02 -0800160 private NodeId localNodeId;
Hyunsun Mooncb799442016-01-15 20:03:18 -0800161
Hyunsun Moon58ddbdc2016-03-07 16:37:17 -0800162 private enum NodeState implements CordVtnNodeState {
Hyunsun Mooncb799442016-01-15 20:03:18 -0800163
164 INIT {
165 @Override
166 public void process(CordVtnNodeManager nodeManager, CordVtnNode node) {
Hyunsun Moon81a13562016-08-04 13:48:08 -0700167 // make sure there is OVSDB connection
Hyunsun Moon126171d2016-02-09 01:55:48 -0800168 if (!nodeManager.isOvsdbConnected(node)) {
Hyunsun Mooncb799442016-01-15 20:03:18 -0800169 nodeManager.connectOvsdb(node);
Hyunsun Moon81a13562016-08-04 13:48:08 -0700170 return;
Hyunsun Mooncb799442016-01-15 20:03:18 -0800171 }
Hyunsun Moon81a13562016-08-04 13:48:08 -0700172 nodeManager.createIntegrationBridge(node);
Hyunsun Mooncb799442016-01-15 20:03:18 -0800173 }
174 },
175 BRIDGE_CREATED {
176 @Override
177 public void process(CordVtnNodeManager nodeManager, CordVtnNode node) {
Hyunsun Moon81a13562016-08-04 13:48:08 -0700178 // make sure there is OVSDB connection
Hyunsun Moon126171d2016-02-09 01:55:48 -0800179 if (!nodeManager.isOvsdbConnected(node)) {
Hyunsun Mooncb799442016-01-15 20:03:18 -0800180 nodeManager.connectOvsdb(node);
Hyunsun Moon81a13562016-08-04 13:48:08 -0700181 return;
182 }
183
184 nodeManager.createTunnelInterface(node);
185 nodeManager.addSystemInterface(node, node.dataIface());
186 if (node.hostMgmtIface().isPresent()) {
187 nodeManager.addSystemInterface(node, node.hostMgmtIface().get());
Hyunsun Mooncb799442016-01-15 20:03:18 -0800188 }
189 }
190 },
Hyunsun Moon126171d2016-02-09 01:55:48 -0800191 PORTS_ADDED {
Hyunsun Moonbd572c12016-01-21 00:54:52 -0800192 @Override
193 public void process(CordVtnNodeManager nodeManager, CordVtnNode node) {
Hyunsun Moon126171d2016-02-09 01:55:48 -0800194 nodeManager.setIpAddress(node);
Hyunsun Moonbd572c12016-01-21 00:54:52 -0800195 }
Hyunsun Moonbd572c12016-01-21 00:54:52 -0800196 },
Hyunsun Mooncb799442016-01-15 20:03:18 -0800197 COMPLETE {
198 @Override
199 public void process(CordVtnNodeManager nodeManager, CordVtnNode node) {
200 nodeManager.postInit(node);
201 }
202 },
203 INCOMPLETE {
204 @Override
205 public void process(CordVtnNodeManager nodeManager, CordVtnNode node) {
206 }
207 };
208
Hyunsun Mooncb799442016-01-15 20:03:18 -0800209 public abstract void process(CordVtnNodeManager nodeManager, CordVtnNode node);
210 }
211
212 @Activate
Hyunsun Moon479b7752016-05-06 20:13:28 -0700213 protected void activate() {
Hyunsun Mooneaf75e62016-09-27 16:40:23 -0700214 appId = coreService.registerApplication(CORDVTN_APP_ID);
Hyunsun Moon7004fcf2016-03-08 04:36:02 -0800215 leadershipService.runForLeadership(appId.name());
Hyunsun Moon3fc0cbc2016-11-22 18:29:12 -0800216 localNodeId = clusterService.getLocalNode().id();
Hyunsun Moon7004fcf2016-03-08 04:36:02 -0800217
Hyunsun Moon58ddbdc2016-03-07 16:37:17 -0800218 nodeStore = storageService.<String, CordVtnNode>consistentMapBuilder()
Hyunsun Mooncb799442016-01-15 20:03:18 -0800219 .withSerializer(Serializer.using(NODE_SERIALIZER.build()))
220 .withName("cordvtn-nodestore")
221 .withApplicationId(appId)
222 .build();
223
Hyunsun Moonff55e812016-03-10 12:40:16 -0800224 nodeStore.addListener(nodeStoreListener);
Hyunsun Mooncb799442016-01-15 20:03:18 -0800225 deviceService.addListener(deviceListener);
226 configService.addListener(configListener);
Hyunsun Moon479b7752016-05-06 20:13:28 -0700227
Hyunsun Moon3fc0cbc2016-11-22 18:29:12 -0800228 // TODO read nodes as well after more tests
229 readControllers();
Hyunsun Moon479b7752016-05-06 20:13:28 -0700230 log.info("Started");
Hyunsun Mooncb799442016-01-15 20:03:18 -0800231 }
232
233 @Deactivate
234 protected void deactivate() {
Hyunsun Mooncb799442016-01-15 20:03:18 -0800235 configService.removeListener(configListener);
236 deviceService.removeListener(deviceListener);
Hyunsun Moonff55e812016-03-10 12:40:16 -0800237 nodeStore.removeListener(nodeStoreListener);
Hyunsun Moonff55e812016-03-10 12:40:16 -0800238
Hyunsun Moon7004fcf2016-03-08 04:36:02 -0800239 leadershipService.withdraw(appId.name());
Hyunsun Moonff55e812016-03-10 12:40:16 -0800240 eventExecutor.shutdown();
Hyunsun Moon479b7752016-05-06 20:13:28 -0700241
242 log.info("Stopped");
Hyunsun Mooncb799442016-01-15 20:03:18 -0800243 }
244
245 /**
Hyunsun Moonff55e812016-03-10 12:40:16 -0800246 * Adds or updates a new node to the service.
Hyunsun Mooncb799442016-01-15 20:03:18 -0800247 *
248 * @param node cordvtn node
249 */
Hyunsun Moonff55e812016-03-10 12:40:16 -0800250 public void addOrUpdateNode(CordVtnNode node) {
Hyunsun Mooncb799442016-01-15 20:03:18 -0800251 checkNotNull(node);
Hyunsun Moon58ddbdc2016-03-07 16:37:17 -0800252 nodeStore.put(node.hostname(), CordVtnNode.getUpdatedNode(node, getNodeState(node)));
Hyunsun Mooncb799442016-01-15 20:03:18 -0800253 }
254
255 /**
256 * Deletes a node from the service.
257 *
258 * @param node cordvtn node
259 */
260 public void deleteNode(CordVtnNode node) {
261 checkNotNull(node);
Hyunsun Moon81a13562016-08-04 13:48:08 -0700262 OvsdbClientService ovsdbClient = getOvsdbClient(node);
263 if (ovsdbClient != null && ovsdbClient.isConnected()) {
264 ovsdbClient.disconnect();
Hyunsun Mooncb799442016-01-15 20:03:18 -0800265 }
Hyunsun Moon58ddbdc2016-03-07 16:37:17 -0800266 nodeStore.remove(node.hostname());
Hyunsun Mooncb799442016-01-15 20:03:18 -0800267 }
268
269 /**
Hyunsun Mooncb799442016-01-15 20:03:18 -0800270 * Returns node initialization state.
271 *
272 * @param node cordvtn node
273 * @return true if initial node setup is completed, otherwise false
274 */
Hyunsun Moon126171d2016-02-09 01:55:48 -0800275 public boolean isNodeInitComplete(CordVtnNode node) {
Hyunsun Mooncb799442016-01-15 20:03:18 -0800276 checkNotNull(node);
Hyunsun Moon6066bd32016-10-24 15:35:34 -0700277 return isNodeStateComplete(node);
Hyunsun Mooncb799442016-01-15 20:03:18 -0800278 }
279
280 /**
281 * Returns the number of the nodes known to the service.
282 *
283 * @return number of nodes
284 */
285 public int getNodeCount() {
286 return nodeStore.size();
287 }
288
289 /**
290 * Returns all nodes known to the service.
291 *
292 * @return list of nodes
293 */
294 public List<CordVtnNode> getNodes() {
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700295 return nodeStore.values().stream().map(Versioned::value).collect(Collectors.toList());
Hyunsun Mooncb799442016-01-15 20:03:18 -0800296 }
297
298 /**
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700299 * Returns all nodes in complete state.
Hyunsun Mooncb799442016-01-15 20:03:18 -0800300 *
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700301 * @return set of nodes
Hyunsun Mooncb799442016-01-15 20:03:18 -0800302 */
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700303 public Set<CordVtnNode> completeNodes() {
Hyunsun Moon81a13562016-08-04 13:48:08 -0700304 return getNodes().stream().filter(this::isNodeStateComplete)
305 .collect(Collectors.toSet());
Hyunsun Mooncb799442016-01-15 20:03:18 -0800306 }
307
308 /**
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700309 * Returns physical data plane port number of a given device.
Hyunsun Mooncb799442016-01-15 20:03:18 -0800310 *
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700311 * @param deviceId integration bridge device id
312 * @return port number; null otherwise
Hyunsun Mooncb799442016-01-15 20:03:18 -0800313 */
Hyunsun Moon81a13562016-08-04 13:48:08 -0700314 public PortNumber dataPort(DeviceId deviceId) {
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700315 CordVtnNode node = nodeByBridgeId(deviceId);
316 if (node == null) {
Hyunsun Moon3fc0cbc2016-11-22 18:29:12 -0800317 log.debug("Failed to get node for {}", deviceId);
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700318 return null;
319 }
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700320
Hyunsun Moonc031d9b2016-08-04 13:57:22 -0700321 Optional<PortNumber> port = getPortNumber(deviceId, node.dataIface());
322 return port.isPresent() ? port.get() : null;
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700323 }
324
325 /**
326 * Returns physical data plane IP address of a given device.
327 *
328 * @param deviceId integration bridge device id
329 * @return ip address; null otherwise
330 */
Hyunsun Moon81a13562016-08-04 13:48:08 -0700331 public IpAddress dataIp(DeviceId deviceId) {
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700332 CordVtnNode node = nodeByBridgeId(deviceId);
333 if (node == null) {
Hyunsun Moon3fc0cbc2016-11-22 18:29:12 -0800334 log.debug("Failed to get node for {}", deviceId);
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700335 return null;
336 }
Hyunsun Moon81a13562016-08-04 13:48:08 -0700337 return node.dataIp().ip();
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700338 }
339
340 /**
341 * Returns tunnel port number of a given device.
342 *
343 * @param deviceId integration bridge device id
344 * @return port number
345 */
346 public PortNumber tunnelPort(DeviceId deviceId) {
Hyunsun Moonc031d9b2016-08-04 13:57:22 -0700347 Optional<PortNumber> port = getPortNumber(deviceId, DEFAULT_TUNNEL);
348 return port.isPresent() ? port.get() : null;
349 }
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700350
Hyunsun Moonc031d9b2016-08-04 13:57:22 -0700351 /**
352 * Returns host management interface port number if exists.
353 *
354 * @param deviceId integration bridge device id
355 * @return port number; null if it does not exist
356 */
357 public PortNumber hostManagementPort(DeviceId deviceId) {
358 CordVtnNode node = nodeByBridgeId(deviceId);
359 if (node == null) {
Hyunsun Moon3fc0cbc2016-11-22 18:29:12 -0800360 log.debug("Failed to get node for {}", deviceId);
Hyunsun Moonc031d9b2016-08-04 13:57:22 -0700361 return null;
362 }
363
364 if (node.hostMgmtIface().isPresent()) {
365 Optional<PortNumber> port = getPortNumber(deviceId, node.hostMgmtIface().get());
366 return port.isPresent() ? port.get() : null;
367 } else {
368 return null;
369 }
370 }
371
372 private Optional<PortNumber> getPortNumber(DeviceId deviceId, String portName) {
373 PortNumber port = deviceService.getPorts(deviceId).stream()
374 .filter(p -> p.annotations().value(AnnotationKeys.PORT_NAME).equals(portName) &&
375 p.isEnabled())
376 .map(Port::number)
377 .findAny()
378 .orElse(null);
379 return Optional.ofNullable(port);
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700380 }
381
382 /**
383 * Returns if current node state saved in nodeStore is COMPLETE or not.
384 *
385 * @param node cordvtn node
386 * @return true if it's complete state, otherwise false
387 */
388 private boolean isNodeStateComplete(CordVtnNode node) {
389 checkNotNull(node);
390
391 // the state saved in nodeStore can be wrong if IP address settings are changed
392 // after the node init has been completed since there's no way to detect it
393 // getNodeState and checkNodeInitState always return correct answer but can be slow
394 Versioned<CordVtnNode> versionedNode = nodeStore.get(node.hostname());
395 CordVtnNodeState state = versionedNode.value().state();
396 return state != null && state.equals(NodeState.COMPLETE);
397 }
398
399 /**
400 * Initiates node to serve virtual tenant network.
401 *
402 * @param node cordvtn node
403 */
404 private void initNode(CordVtnNode node) {
405 checkNotNull(node);
406
407 NodeState state = (NodeState) node.state();
408 log.debug("Processing node: {} state: {}", node.hostname(), state);
409
410 state.process(this, node);
411 }
412
413 /**
414 * Performs tasks after node initialization.
415 * It disconnects unnecessary OVSDB connection and installs initial flow
416 * rules on the device.
417 *
418 * @param node cordvtn node
419 */
420 private void postInit(CordVtnNode node) {
Hyunsun Moon81a13562016-08-04 13:48:08 -0700421 checkNotNull(node);
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700422
Hyunsun Moon81a13562016-08-04 13:48:08 -0700423 // disconnect OVSDB session once the node bootstrap is done
424 OvsdbClientService ovsdbClient = getOvsdbClient(node);
425 if (ovsdbClient != null && ovsdbClient.isConnected()) {
426 ovsdbClient.disconnect();
427 }
428
Hyunsun Moonc031d9b2016-08-04 13:57:22 -0700429 pipeline.initPipeline(node);
Hyunsun Moon81a13562016-08-04 13:48:08 -0700430
431 // adds existing instances to the host list
432 deviceService.getPorts(node.integrationBridgeId()).stream()
Hyunsun Moon1e88fef2016-08-04 14:00:35 -0700433 .filter(port -> !node.systemIfaces().contains(portName(port)) &&
434 !port.number().equals(PortNumber.LOCAL) &&
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700435 port.isEnabled())
Hyunsun Moon5401aaa2016-06-12 17:40:34 -0700436 .forEach(port -> instanceService.addInstance(connectPoint(port)));
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700437
Hyunsun Moon81a13562016-08-04 13:48:08 -0700438 // removes stale instances from the host list
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700439 hostService.getHosts().forEach(host -> {
Hyunsun Moon81a13562016-08-04 13:48:08 -0700440 if (deviceService.getPort(
441 host.location().deviceId(),
442 host.location().port()) == null) {
443 instanceService.removeInstance(host.location());
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700444 }
445 });
446
447 log.info("Finished init {}", node.hostname());
Hyunsun Mooncb799442016-01-15 20:03:18 -0800448 }
449
450 /**
Hyunsun Mooncb799442016-01-15 20:03:18 -0800451 * Sets a new state for a given cordvtn node.
452 *
453 * @param node cordvtn node
454 * @param newState new node state
455 */
456 private void setNodeState(CordVtnNode node, NodeState newState) {
457 checkNotNull(node);
Hyunsun Moonff55e812016-03-10 12:40:16 -0800458 log.debug("Changed {} state: {}", node.hostname(), newState);
Hyunsun Moon58ddbdc2016-03-07 16:37:17 -0800459 nodeStore.put(node.hostname(), CordVtnNode.getUpdatedNode(node, newState));
Hyunsun Mooncb799442016-01-15 20:03:18 -0800460 }
461
462 /**
463 * Checks current state of a given cordvtn node and returns it.
464 *
465 * @param node cordvtn node
466 * @return node state
467 */
Hyunsun Moon126171d2016-02-09 01:55:48 -0800468 private NodeState getNodeState(CordVtnNode node) {
Hyunsun Mooncb799442016-01-15 20:03:18 -0800469 checkNotNull(node);
Hyunsun Moon81a13562016-08-04 13:48:08 -0700470 if (!isIntegrationBridgeCreated(node)) {
Hyunsun Mooncb799442016-01-15 20:03:18 -0800471 return NodeState.INIT;
472 }
Hyunsun Moon81a13562016-08-04 13:48:08 -0700473 for (String iface : node.systemIfaces()) {
474 if (!isIfaceCreated(node, iface)) {
475 return NodeState.BRIDGE_CREATED;
476 }
477 }
478 if (!isIpAddressSet(node)) {
479 return NodeState.PORTS_ADDED;
480 }
481 return NodeState.COMPLETE;
Hyunsun Mooncb799442016-01-15 20:03:18 -0800482 }
483
484 /**
Hyunsun Mooncb799442016-01-15 20:03:18 -0800485 * Returns connection state of OVSDB server for a given node.
486 *
487 * @param node cordvtn node
488 * @return true if it is connected, false otherwise
489 */
Hyunsun Moon126171d2016-02-09 01:55:48 -0800490 private boolean isOvsdbConnected(CordVtnNode node) {
Hyunsun Mooncb799442016-01-15 20:03:18 -0800491 checkNotNull(node);
Hyunsun Mooncb799442016-01-15 20:03:18 -0800492 OvsdbClientService ovsdbClient = getOvsdbClient(node);
493 return deviceService.isAvailable(node.ovsdbId()) &&
Hyunsun Moon81a13562016-08-04 13:48:08 -0700494 ovsdbClient != null &&
495 ovsdbClient.isConnected();
Hyunsun Mooncb799442016-01-15 20:03:18 -0800496 }
497
498 /**
499 * Connects to OVSDB server for a given node.
500 *
501 * @param node cordvtn node
502 */
503 private void connectOvsdb(CordVtnNode node) {
504 checkNotNull(node);
Hyunsun Moon81a13562016-08-04 13:48:08 -0700505 ovsdbController.connect(node.hostMgmtIp().ip(), node.ovsdbPort());
Hyunsun Mooncb799442016-01-15 20:03:18 -0800506 }
507
508 /**
509 * Returns OVSDB client for a given node.
510 *
511 * @param node cordvtn node
Hyunsun Moon81a13562016-08-04 13:48:08 -0700512 * @return ovsdb client, or null if there's no ovsdb connection
Hyunsun Mooncb799442016-01-15 20:03:18 -0800513 */
514 private OvsdbClientService getOvsdbClient(CordVtnNode node) {
515 checkNotNull(node);
Hyunsun Moon81a13562016-08-04 13:48:08 -0700516 OvsdbNodeId ovsdb = new OvsdbNodeId(
517 node.hostMgmtIp().ip(), node.ovsdbPort().toInt());
518 return ovsdbController.getOvsdbClient(ovsdb);
Hyunsun Mooncb799442016-01-15 20:03:18 -0800519 }
520
Hyunsun Mooncb799442016-01-15 20:03:18 -0800521 private void createIntegrationBridge(CordVtnNode node) {
Hyunsun Moon81a13562016-08-04 13:48:08 -0700522 Device device = deviceService.getDevice(node.ovsdbId());
523 if (device == null || !device.is(BridgeConfig.class)) {
524 log.error("Failed to create integration bridge on {}", node.ovsdbId());
Hyunsun Mooncb799442016-01-15 20:03:18 -0800525 return;
526 }
527
Hyunsun Moon81a13562016-08-04 13:48:08 -0700528 String dpid = node.integrationBridgeId().toString().substring(DPID_BEGIN);
529 BridgeDescription bridgeDesc = DefaultBridgeDescription.builder()
530 .name(INTEGRATION_BRIDGE)
531 .failMode(BridgeDescription.FailMode.SECURE)
532 .datapathId(dpid)
533 .disableInBand()
534 .controllers(controllers)
535 .build();
Hyunsun Mooncb799442016-01-15 20:03:18 -0800536
Hyunsun Moon81a13562016-08-04 13:48:08 -0700537 BridgeConfig bridgeConfig = device.as(BridgeConfig.class);
538 bridgeConfig.addBridge(bridgeDesc);
Hyunsun Mooncb799442016-01-15 20:03:18 -0800539 }
540
Hyunsun Mooncb799442016-01-15 20:03:18 -0800541 private void createTunnelInterface(CordVtnNode node) {
Hyunsun Moon81a13562016-08-04 13:48:08 -0700542 Device device = deviceService.getDevice(node.ovsdbId());
543 if (device == null || !device.is(InterfaceConfig.class)) {
544 log.error("Failed to create tunnel interface on {}", node.ovsdbId());
Hyunsun Mooncb799442016-01-15 20:03:18 -0800545 return;
546 }
547
Hyunsun Moon81a13562016-08-04 13:48:08 -0700548 TunnelDescription tunnelDesc = DefaultTunnelDescription.builder()
549 .deviceId(INTEGRATION_BRIDGE)
550 .ifaceName(DEFAULT_TUNNEL)
551 .type(VXLAN)
552 .remote(TunnelEndPoints.flowTunnelEndpoint())
553 .key(TunnelKeys.flowTunnelKey())
554 .build();
Hyunsun Mooncb799442016-01-15 20:03:18 -0800555
Hyunsun Moon81a13562016-08-04 13:48:08 -0700556 InterfaceConfig ifaceConfig = device.as(InterfaceConfig.class);
557 ifaceConfig.addTunnelMode(DEFAULT_TUNNEL, tunnelDesc);
Hyunsun Moonbd572c12016-01-21 00:54:52 -0800558 }
559
Hyunsun Moon81a13562016-08-04 13:48:08 -0700560 private void addSystemInterface(CordVtnNode node, String ifaceName) {
Hyunsun Moon479b7752016-05-06 20:13:28 -0700561 Session session = connect(node.sshInfo());
Hyunsun Moon81a13562016-08-04 13:48:08 -0700562 if (session == null || !isInterfaceUp(session, ifaceName)) {
563 log.warn("Interface {} is not available on {}", ifaceName, node.hostname());
564 disconnect(session);
565 return;
566 } else {
567 disconnect(session);
568 }
569
570 Device device = deviceService.getDevice(node.ovsdbId());
571 if (!device.is(BridgeConfig.class)) {
572 log.error("BridgeConfig is not supported for {}", node.ovsdbId());
Hyunsun Moon479b7752016-05-06 20:13:28 -0700573 return;
574 }
575
Hyunsun Moon81a13562016-08-04 13:48:08 -0700576 BridgeConfig bridgeConfig = device.as(BridgeConfig.class);
577 bridgeConfig.addPort(BridgeName.bridgeName(INTEGRATION_BRIDGE), ifaceName);
Hyunsun Moon126171d2016-02-09 01:55:48 -0800578 }
579
580 /**
581 * Flushes IP address from data plane interface and adds data plane IP address
582 * to integration bridge.
583 *
584 * @param node cordvtn node
585 */
586 private void setIpAddress(CordVtnNode node) {
Hyunsun Moon479b7752016-05-06 20:13:28 -0700587 Session session = connect(node.sshInfo());
Hyunsun Moon126171d2016-02-09 01:55:48 -0800588 if (session == null) {
589 log.debug("Failed to SSH to {}", node.hostname());
590 return;
591 }
Hyunsun Moon81a13562016-08-04 13:48:08 -0700592 getCurrentIps(session, INTEGRATION_BRIDGE).stream()
Hyunsun Moon0592c3d2016-06-23 14:47:52 -0700593 .filter(ip -> !ip.equals(node.localMgmtIp().ip()))
Hyunsun Moon81a13562016-08-04 13:48:08 -0700594 .filter(ip -> !ip.equals(node.dataIp().ip()))
595 .forEach(ip -> deleteIp(session, ip, INTEGRATION_BRIDGE));
Hyunsun Moon0592c3d2016-06-23 14:47:52 -0700596
Hyunsun Moon81a13562016-08-04 13:48:08 -0700597 boolean result = flushIp(session, node.dataIface()) &&
598 setInterfaceUp(session, node.dataIface()) &&
599 addIp(session, node.dataIp(), INTEGRATION_BRIDGE) &&
600 addIp(session, node.localMgmtIp(), INTEGRATION_BRIDGE) &&
601 setInterfaceUp(session, INTEGRATION_BRIDGE);
Hyunsun Moon126171d2016-02-09 01:55:48 -0800602
Hyunsun Moon479b7752016-05-06 20:13:28 -0700603 disconnect(session);
Hyunsun Moon126171d2016-02-09 01:55:48 -0800604 if (result) {
605 setNodeState(node, NodeState.COMPLETE);
Hyunsun Mooncb799442016-01-15 20:03:18 -0800606 }
607 }
608
Hyunsun Moon81a13562016-08-04 13:48:08 -0700609 private boolean isIntegrationBridgeCreated(CordVtnNode node) {
610 return deviceService.getDevice(node.integrationBridgeId()) != null &&
611 deviceService.isAvailable(node.integrationBridgeId());
Hyunsun Mooncb799442016-01-15 20:03:18 -0800612 }
613
Hyunsun Moon81a13562016-08-04 13:48:08 -0700614 private boolean isIfaceCreated(CordVtnNode node, String ifaceName) {
615 if (Strings.isNullOrEmpty(ifaceName)) {
616 return false;
617 }
618 return deviceService.getPorts(node.integrationBridgeId()).stream()
619 .filter(p -> portName(p).contains(ifaceName) &&
620 p.isEnabled())
621 .findAny()
622 .isPresent();
Hyunsun Mooncb799442016-01-15 20:03:18 -0800623 }
624
625 /**
Hyunsun Moon126171d2016-02-09 01:55:48 -0800626 * Checks if the IP addresses are correctly set.
627 *
628 * @param node cordvtn node
629 * @return true if the IP is set, false otherwise
630 */
631 private boolean isIpAddressSet(CordVtnNode node) {
Hyunsun Moon479b7752016-05-06 20:13:28 -0700632 Session session = connect(node.sshInfo());
Hyunsun Moon126171d2016-02-09 01:55:48 -0800633 if (session == null) {
634 log.debug("Failed to SSH to {}", node.hostname());
635 return false;
636 }
637
Hyunsun Moon81a13562016-08-04 13:48:08 -0700638 Set<IpAddress> intBrIps = getCurrentIps(session, INTEGRATION_BRIDGE);
639 boolean result = getCurrentIps(session, node.dataIface()).isEmpty() &&
640 isInterfaceUp(session, node.dataIface()) &&
641 intBrIps.contains(node.dataIp().ip()) &&
Hyunsun Moon126171d2016-02-09 01:55:48 -0800642 intBrIps.contains(node.localMgmtIp().ip()) &&
Hyunsun Moon81a13562016-08-04 13:48:08 -0700643 isInterfaceUp(session, INTEGRATION_BRIDGE);
Hyunsun Moon126171d2016-02-09 01:55:48 -0800644
Hyunsun Moon479b7752016-05-06 20:13:28 -0700645 disconnect(session);
Hyunsun Moon126171d2016-02-09 01:55:48 -0800646 return result;
647 }
648
649 /**
Hyunsun Mooncb799442016-01-15 20:03:18 -0800650 * Returns connect point of a given port.
651 *
652 * @param port port
653 * @return connect point
654 */
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700655 private ConnectPoint connectPoint(Port port) {
Hyunsun Mooncb799442016-01-15 20:03:18 -0800656 return new ConnectPoint(port.element().id(), port.number());
657 }
658
659 /**
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700660 * Returns cordvtn node associated with a given OVSDB device.
661 *
662 * @param ovsdbId OVSDB device id
663 * @return cordvtn node, null if it fails to find the node
664 */
665 private CordVtnNode nodeByOvsdbId(DeviceId ovsdbId) {
666 return getNodes().stream()
667 .filter(node -> node.ovsdbId().equals(ovsdbId))
668 .findFirst().orElse(null);
669 }
670
671 /**
672 * Returns cordvtn node associated with a given integration bridge.
673 *
674 * @param bridgeId device id of integration bridge
675 * @return cordvtn node, null if it fails to find the node
676 */
677 private CordVtnNode nodeByBridgeId(DeviceId bridgeId) {
678 return getNodes().stream()
Hyunsun Moon81a13562016-08-04 13:48:08 -0700679 .filter(node -> node.integrationBridgeId().equals(bridgeId))
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700680 .findFirst().orElse(null);
681 }
682
683 /**
684 * Returns port name.
685 *
686 * @param port port
687 * @return port name
688 */
689 private String portName(Port port) {
Hyunsun Moon81a13562016-08-04 13:48:08 -0700690 return port.annotations().value(PORT_NAME);
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700691 }
692
Hyunsun Mooncb799442016-01-15 20:03:18 -0800693 private class OvsdbHandler implements ConnectionHandler<Device> {
694
695 @Override
696 public void connected(Device device) {
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700697 CordVtnNode node = nodeByOvsdbId(device.id());
Hyunsun Mooncb799442016-01-15 20:03:18 -0800698 if (node != null) {
Hyunsun Moon126171d2016-02-09 01:55:48 -0800699 setNodeState(node, getNodeState(node));
Hyunsun Mooncb799442016-01-15 20:03:18 -0800700 } else {
701 log.debug("{} is detected on unregistered node, ignore it.", device.id());
702 }
703 }
704
705 @Override
706 public void disconnected(Device device) {
Hyunsun Moon81a13562016-08-04 13:48:08 -0700707 log.debug("Device {} is disconnected", device.id());
708 adminService.removeDevice(device.id());
Hyunsun Mooncb799442016-01-15 20:03:18 -0800709 }
710 }
711
712 private class BridgeHandler implements ConnectionHandler<Device> {
713
714 @Override
715 public void connected(Device device) {
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700716 CordVtnNode node = nodeByBridgeId(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 Moone7e4bb32016-05-16 04:32:45 -0700726 CordVtnNode node = nodeByBridgeId(device.id());
Hyunsun Mooncb799442016-01-15 20:03:18 -0800727 if (node != null) {
Hyunsun Moon81a13562016-08-04 13:48:08 -0700728 log.warn("Integration Bridge is disconnected from {}", node.hostname());
Hyunsun Mooncb799442016-01-15 20:03:18 -0800729 setNodeState(node, NodeState.INCOMPLETE);
730 }
731 }
732
733 /**
734 * Handles port added situation.
Hyunsun Moon126171d2016-02-09 01:55:48 -0800735 * If the added port is tunnel or data plane interface, proceed to the remaining
736 * node initialization. Otherwise, do nothing.
Hyunsun Mooncb799442016-01-15 20:03:18 -0800737 *
738 * @param port port
739 */
740 public void portAdded(Port port) {
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700741 CordVtnNode node = nodeByBridgeId((DeviceId) port.element().id());
742 String portName = portName(port);
Hyunsun Mooncb799442016-01-15 20:03:18 -0800743
744 if (node == null) {
745 log.debug("{} is added to unregistered node, ignore it.", portName);
746 return;
747 }
748
Hyunsun Moonff55e812016-03-10 12:40:16 -0800749 log.info("Port {} is added to {}", portName, node.hostname());
Hyunsun Mooncb799442016-01-15 20:03:18 -0800750
Hyunsun Moon1e88fef2016-08-04 14:00:35 -0700751 if (node.systemIfaces().contains(portName)) {
Hyunsun Moon126171d2016-02-09 01:55:48 -0800752 setNodeState(node, getNodeState(node));
Hyunsun Moon1e88fef2016-08-04 14:00:35 -0700753 } else if (isNodeStateComplete(node)) {
754 instanceService.addInstance(connectPoint(port));
755 } else {
756 log.warn("Instance is detected on incomplete node, ignore it.", portName);
Hyunsun Mooncb799442016-01-15 20:03:18 -0800757 }
758 }
759
760 /**
761 * Handles port removed situation.
Hyunsun Moon126171d2016-02-09 01:55:48 -0800762 * If the removed port is tunnel or data plane interface, proceed to the remaining
763 * node initialization.Others, do nothing.
Hyunsun Mooncb799442016-01-15 20:03:18 -0800764 *
765 * @param port port
766 */
767 public void portRemoved(Port port) {
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700768 CordVtnNode node = nodeByBridgeId((DeviceId) port.element().id());
769 String portName = portName(port);
Hyunsun Mooncb799442016-01-15 20:03:18 -0800770
771 if (node == null) {
772 return;
773 }
774
Hyunsun Moonff55e812016-03-10 12:40:16 -0800775 log.info("Port {} is removed from {}", portName, node.hostname());
Hyunsun Mooncb799442016-01-15 20:03:18 -0800776
Hyunsun Moon1e88fef2016-08-04 14:00:35 -0700777 if (node.systemIfaces().contains(portName)) {
Hyunsun Mooncb799442016-01-15 20:03:18 -0800778 setNodeState(node, NodeState.INCOMPLETE);
Hyunsun Moon1e88fef2016-08-04 14:00:35 -0700779 } else if (isNodeStateComplete(node)) {
780 instanceService.removeInstance(connectPoint(port));
781 } else {
782 log.warn("VM is vanished from incomplete node, ignore it.", portName);
Hyunsun Mooncb799442016-01-15 20:03:18 -0800783 }
784 }
785 }
786
787 private class InternalDeviceListener implements DeviceListener {
788
789 @Override
790 public void event(DeviceEvent event) {
791
Hyunsun Moon7004fcf2016-03-08 04:36:02 -0800792 NodeId leaderNodeId = leadershipService.getLeader(appId.name());
793 if (!Objects.equals(localNodeId, leaderNodeId)) {
Hyunsun Moonff55e812016-03-10 12:40:16 -0800794 // do not allow to proceed without leadership
Hyunsun Moon7004fcf2016-03-08 04:36:02 -0800795 return;
796 }
797
Hyunsun Mooncb799442016-01-15 20:03:18 -0800798 Device device = event.subject();
799 ConnectionHandler<Device> handler =
800 (device.type().equals(SWITCH) ? bridgeHandler : ovsdbHandler);
801
802 switch (event.type()) {
803 case PORT_ADDED:
Hyunsun Moonff55e812016-03-10 12:40:16 -0800804 eventExecutor.execute(() -> bridgeHandler.portAdded(event.port()));
Hyunsun Mooncb799442016-01-15 20:03:18 -0800805 break;
806 case PORT_UPDATED:
807 if (!event.port().isEnabled()) {
Hyunsun Moonff55e812016-03-10 12:40:16 -0800808 eventExecutor.execute(() -> bridgeHandler.portRemoved(event.port()));
Hyunsun Mooncb799442016-01-15 20:03:18 -0800809 }
810 break;
811 case DEVICE_ADDED:
812 case DEVICE_AVAILABILITY_CHANGED:
813 if (deviceService.isAvailable(device.id())) {
Hyunsun Moonff55e812016-03-10 12:40:16 -0800814 eventExecutor.execute(() -> handler.connected(device));
Hyunsun Mooncb799442016-01-15 20:03:18 -0800815 } else {
Hyunsun Moonff55e812016-03-10 12:40:16 -0800816 eventExecutor.execute(() -> handler.disconnected(device));
Hyunsun Mooncb799442016-01-15 20:03:18 -0800817 }
818 break;
819 default:
820 break;
821 }
822 }
823 }
824
825 /**
Hyunsun Moon3fc17f72016-01-24 21:47:06 -0800826 * Reads cordvtn nodes from config file.
Hyunsun Mooncb799442016-01-15 20:03:18 -0800827 */
Hyunsun Moon3fc0cbc2016-11-22 18:29:12 -0800828 private void readNodes() {
829 NodeId leaderNodeId = leadershipService.getLeader(appId.name());
830 if (!Objects.equals(localNodeId, leaderNodeId)) {
831 // do not allow to proceed without leadership
832 return;
833 }
834
Hyunsun Moon0984cbd2016-12-01 17:34:11 -0800835 CordVtnConfig config = configService.getConfig(appId, CordVtnConfig.class);
Hyunsun Mooncb799442016-01-15 20:03:18 -0800836 if (config == null) {
Hyunsun Moon3fc17f72016-01-24 21:47:06 -0800837 log.debug("No configuration found");
Hyunsun Mooncb799442016-01-15 20:03:18 -0800838 return;
839 }
Hyunsun Moonff55e812016-03-10 12:40:16 -0800840 config.cordVtnNodes().forEach(this::addOrUpdateNode);
Hyunsun Mooncb799442016-01-15 20:03:18 -0800841 }
842
Hyunsun Moon3fc0cbc2016-11-22 18:29:12 -0800843 private void readControllers() {
Hyunsun Moon0984cbd2016-12-01 17:34:11 -0800844 CordVtnConfig config = configService.getConfig(appId, CordVtnConfig.class);
Hyunsun Moon3fc0cbc2016-11-22 18:29:12 -0800845 if (config == null) {
846 log.debug("No configuration found");
847 return;
848 }
849 controllers = config.controllers();
850 controllers.stream().forEach(ctrl -> {
851 log.debug("Added controller {}:{}", ctrl.ip(), ctrl.port());
852 });
853 }
854
Hyunsun Mooncb799442016-01-15 20:03:18 -0800855 private class InternalConfigListener implements NetworkConfigListener {
856
857 @Override
858 public void event(NetworkConfigEvent event) {
859 if (!event.configClass().equals(CordVtnConfig.class)) {
860 return;
861 }
862
863 switch (event.type()) {
864 case CONFIG_ADDED:
Hyunsun Mooncb799442016-01-15 20:03:18 -0800865 case CONFIG_UPDATED:
Hyunsun Moon3fc0cbc2016-11-22 18:29:12 -0800866 eventExecutor.execute(() -> {
867 readControllers();
868 readNodes();
869 });
Hyunsun Mooncb799442016-01-15 20:03:18 -0800870 break;
871 default:
872 break;
873 }
874 }
875 }
Hyunsun Moonff55e812016-03-10 12:40:16 -0800876
877 private class InternalMapListener implements MapEventListener<String, CordVtnNode> {
878
879 @Override
880 public void event(MapEvent<String, CordVtnNode> event) {
881 NodeId leaderNodeId = leadershipService.getLeader(appId.name());
882 if (!Objects.equals(localNodeId, leaderNodeId)) {
883 // do not allow to proceed without leadership
884 return;
885 }
886
887 CordVtnNode oldNode;
888 CordVtnNode newNode;
889
890 switch (event.type()) {
891 case UPDATE:
892 oldNode = event.oldValue().value();
893 newNode = event.newValue().value();
894
Hyunsun Moon479b7752016-05-06 20:13:28 -0700895 log.info("Reloaded {}", newNode.hostname());
Hyunsun Moonff55e812016-03-10 12:40:16 -0800896 if (!newNode.equals(oldNode)) {
Hyunsun Moonff55e812016-03-10 12:40:16 -0800897 log.debug("New node: {}", newNode);
898 }
Hyunsun Moon479b7752016-05-06 20:13:28 -0700899 // performs init procedure even if the node is not changed
900 // for robustness since it's no harm to run init procedure
901 // multiple times
Hyunsun Moonff55e812016-03-10 12:40:16 -0800902 eventExecutor.execute(() -> initNode(newNode));
903 break;
904 case INSERT:
905 newNode = event.newValue().value();
906 log.info("Added {}", newNode.hostname());
907 eventExecutor.execute(() -> initNode(newNode));
908 break;
909 case REMOVE:
910 oldNode = event.oldValue().value();
Hyunsun Moon479b7752016-05-06 20:13:28 -0700911 log.info("Removed {}", oldNode.hostname());
Hyunsun Moonff55e812016-03-10 12:40:16 -0800912 break;
913 default:
914 break;
915 }
916 }
917 }
Hyunsun Mooncb799442016-01-15 20:03:18 -0800918}