blob: 5ef8045ef5db4c014f0a5411b20b48d0ed07e3a6 [file] [log] [blame]
Daniel Parka7d6e9f2016-01-18 17:54:14 +09001/*
Brian O'Connor5ab426f2016-04-09 01:19:45 -07002 * Copyright 2016-present Open Networking Laboratory
Daniel Parka7d6e9f2016-01-18 17:54:14 +09003 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16package org.onosproject.openstacknode;
17
Hyunsun Moon34bbe172016-06-28 19:18:40 -070018import com.google.common.collect.Sets;
Daniel Parka7d6e9f2016-01-18 17:54:14 +090019import org.apache.felix.scr.annotations.Activate;
20import org.apache.felix.scr.annotations.Component;
21import org.apache.felix.scr.annotations.Deactivate;
Hyunsun Moon34bbe172016-06-28 19:18:40 -070022import org.apache.felix.scr.annotations.Modified;
23import org.apache.felix.scr.annotations.Property;
Daniel Parka7d6e9f2016-01-18 17:54:14 +090024import org.apache.felix.scr.annotations.Reference;
25import org.apache.felix.scr.annotations.ReferenceCardinality;
26import org.apache.felix.scr.annotations.Service;
Hyunsun Moon34bbe172016-06-28 19:18:40 -070027import org.onlab.packet.IpAddress;
28import org.onlab.packet.TpPort;
Daniel Parka7d6e9f2016-01-18 17:54:14 +090029import org.onlab.util.KryoNamespace;
Hyunsun Moon34bbe172016-06-28 19:18:40 -070030import org.onlab.util.Tools;
31import org.onosproject.cfg.ComponentConfigService;
Daniel Parka7d6e9f2016-01-18 17:54:14 +090032import org.onosproject.cluster.ClusterService;
Hyunsun Moon052c71f2016-07-11 18:56:18 -070033import org.onosproject.cluster.ControllerNode;
Daniel Parkad21c572016-03-09 10:18:24 +090034import org.onosproject.cluster.LeadershipService;
35import org.onosproject.cluster.NodeId;
Daniel Parka7d6e9f2016-01-18 17:54:14 +090036import org.onosproject.core.ApplicationId;
37import org.onosproject.core.CoreService;
Hyunsun Moon05d9b262016-07-03 18:38:44 -070038import org.onosproject.event.ListenerRegistry;
Daniel Parka7d6e9f2016-01-18 17:54:14 +090039import org.onosproject.net.Device;
40import org.onosproject.net.DeviceId;
41import org.onosproject.net.Port;
Hyunsun Moon34bbe172016-06-28 19:18:40 -070042import org.onosproject.net.PortNumber;
Daniel Parka7d6e9f2016-01-18 17:54:14 +090043import org.onosproject.net.behaviour.BridgeConfig;
Hyunsun Moon1251e192016-06-07 16:57:05 -070044import org.onosproject.net.behaviour.BridgeDescription;
Hyunsun Moon052c71f2016-07-11 18:56:18 -070045import org.onosproject.net.behaviour.BridgeName;
Daniel Parka7d6e9f2016-01-18 17:54:14 +090046import org.onosproject.net.behaviour.ControllerInfo;
Hyunsun Moon1251e192016-06-07 16:57:05 -070047import org.onosproject.net.behaviour.DefaultBridgeDescription;
Hyunsun Moon34bbe172016-06-28 19:18:40 -070048import org.onosproject.net.behaviour.DefaultPatchDescription;
Daniel Parka7d6e9f2016-01-18 17:54:14 +090049import org.onosproject.net.behaviour.DefaultTunnelDescription;
Hyunsun Moondd14e8e2016-06-09 16:17:32 -070050import org.onosproject.net.behaviour.InterfaceConfig;
Hyunsun Moon34bbe172016-06-28 19:18:40 -070051import org.onosproject.net.behaviour.PatchDescription;
Daniel Parka7d6e9f2016-01-18 17:54:14 +090052import org.onosproject.net.behaviour.TunnelDescription;
Hyunsun Moondd14e8e2016-06-09 16:17:32 -070053import org.onosproject.net.behaviour.TunnelEndPoints;
54import org.onosproject.net.behaviour.TunnelKeys;
Daniel Parka7d6e9f2016-01-18 17:54:14 +090055import org.onosproject.net.config.ConfigFactory;
56import org.onosproject.net.config.NetworkConfigEvent;
57import org.onosproject.net.config.NetworkConfigListener;
58import org.onosproject.net.config.NetworkConfigRegistry;
Daniel Parka7d6e9f2016-01-18 17:54:14 +090059import org.onosproject.net.config.basics.SubjectFactories;
Daniel Parka7d6e9f2016-01-18 17:54:14 +090060import org.onosproject.net.device.DeviceEvent;
61import org.onosproject.net.device.DeviceListener;
62import org.onosproject.net.device.DeviceService;
Hyunsun Moon05d9b262016-07-03 18:38:44 -070063import org.onosproject.openstacknode.OpenstackNodeEvent.NodeState;
Daniel Parka7d6e9f2016-01-18 17:54:14 +090064import org.onosproject.ovsdb.controller.OvsdbClientService;
65import org.onosproject.ovsdb.controller.OvsdbController;
66import org.onosproject.ovsdb.controller.OvsdbNodeId;
67import org.onosproject.store.serializers.KryoNamespaces;
68import org.onosproject.store.service.ConsistentMap;
Hyunsun Moon34bbe172016-06-28 19:18:40 -070069import org.onosproject.store.service.MapEvent;
70import org.onosproject.store.service.MapEventListener;
Daniel Parka7d6e9f2016-01-18 17:54:14 +090071import org.onosproject.store.service.Serializer;
72import org.onosproject.store.service.StorageService;
Hyunsun Moon34bbe172016-06-28 19:18:40 -070073import org.onosproject.store.service.Versioned;
74import org.osgi.service.component.ComponentContext;
Daniel Parka7d6e9f2016-01-18 17:54:14 +090075import org.slf4j.Logger;
76
Hyunsun Moon052c71f2016-07-11 18:56:18 -070077import static com.google.common.base.Preconditions.checkArgument;
Daniel Parkad21c572016-03-09 10:18:24 +090078import static java.util.concurrent.Executors.newSingleThreadScheduledExecutor;
Daniel Parka7d6e9f2016-01-18 17:54:14 +090079import static org.onlab.util.Tools.groupedThreads;
Hyunsun Moon34bbe172016-06-28 19:18:40 -070080import static org.onosproject.net.AnnotationKeys.PORT_NAME;
Daniel Parka7d6e9f2016-01-18 17:54:14 +090081import static org.onosproject.net.Device.Type.SWITCH;
82import static org.onosproject.net.behaviour.TunnelDescription.Type.VXLAN;
Hyunsun Moon34bbe172016-06-28 19:18:40 -070083import static org.onosproject.openstacknode.Constants.*;
Hyunsun Moon05d9b262016-07-03 18:38:44 -070084import static org.onosproject.openstacknode.OpenstackNodeEvent.NodeState.*;
Daniel Parka7d6e9f2016-01-18 17:54:14 +090085import static org.slf4j.LoggerFactory.getLogger;
86
Hyunsun Moon34bbe172016-06-28 19:18:40 -070087import java.util.Dictionary;
Daniel Parka7d6e9f2016-01-18 17:54:14 +090088import java.util.List;
Hyunsun Moon34bbe172016-06-28 19:18:40 -070089import java.util.Objects;
90import java.util.Optional;
91import java.util.Set;
Daniel Parka7d6e9f2016-01-18 17:54:14 +090092import java.util.concurrent.ExecutorService;
Daniel Parka7d6e9f2016-01-18 17:54:14 +090093import java.util.stream.Collectors;
94
Daniel Parka7d6e9f2016-01-18 17:54:14 +090095/**
96 * Initializes devices in compute/gateway nodes according to there type.
97 */
98@Component(immediate = true)
99@Service
Hyunsun Moon05d9b262016-07-03 18:38:44 -0700100public final class OpenstackNodeManager extends ListenerRegistry<OpenstackNodeEvent, OpenstackNodeListener>
101 implements OpenstackNodeService {
102 private final Logger log = getLogger(getClass());
Hyunsun Moon34bbe172016-06-28 19:18:40 -0700103
Daniel Parka7d6e9f2016-01-18 17:54:14 +0900104 private static final KryoNamespace.Builder NODE_SERIALIZER = KryoNamespace.newBuilder()
105 .register(KryoNamespaces.API)
106 .register(OpenstackNode.class)
Hyunsun Moon34bbe172016-06-28 19:18:40 -0700107 .register(NodeType.class)
Daniel Parka7d6e9f2016-01-18 17:54:14 +0900108 .register(NodeState.class);
Daniel Parka7d6e9f2016-01-18 17:54:14 +0900109
Hyunsun Moon34bbe172016-06-28 19:18:40 -0700110 private static final String OVSDB_PORT = "ovsdbPort";
Daniel Parka7d6e9f2016-01-18 17:54:14 +0900111 private static final int DPID_BEGIN = 3;
Hyunsun Moon34bbe172016-06-28 19:18:40 -0700112
113 private static final String APP_ID = "org.onosproject.openstacknode";
114 private static final Class<OpenstackNodeConfig> CONFIG_CLASS = OpenstackNodeConfig.class;
Daniel Parka7d6e9f2016-01-18 17:54:14 +0900115
116 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
117 protected CoreService coreService;
118
119 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
120 protected DeviceService deviceService;
121
122 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Hyunsun Moon052c71f2016-07-11 18:56:18 -0700123 protected OvsdbController ovsdbController;
Daniel Parka7d6e9f2016-01-18 17:54:14 +0900124
125 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
126 protected ClusterService clusterService;
127
128 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Daniel Parka7d6e9f2016-01-18 17:54:14 +0900129 protected StorageService storageService;
130
131 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Hyunsun Moon34bbe172016-06-28 19:18:40 -0700132 protected ComponentConfigService componentConfigService;
Daniel Parka7d6e9f2016-01-18 17:54:14 +0900133
134 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
135 protected NetworkConfigRegistry configRegistry;
136
Daniel Parkad21c572016-03-09 10:18:24 +0900137 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
138 protected LeadershipService leadershipService;
139
Hyunsun Moon34bbe172016-06-28 19:18:40 -0700140 @Property(name = OVSDB_PORT, intValue = DEFAULT_OVSDB_PORT,
141 label = "OVSDB server listen port")
142 private int ovsdbPort = DEFAULT_OVSDB_PORT;
143
144 private final ExecutorService eventExecutor =
Hyunsun Moon052c71f2016-07-11 18:56:18 -0700145 newSingleThreadScheduledExecutor(groupedThreads("onos/openstack-node", "event-handler", log));
Hyunsun Moon34bbe172016-06-28 19:18:40 -0700146
Daniel Parka7d6e9f2016-01-18 17:54:14 +0900147 private final ConfigFactory configFactory =
Hyunsun Moon34bbe172016-06-28 19:18:40 -0700148 new ConfigFactory<ApplicationId, OpenstackNodeConfig>(
149 SubjectFactories.APP_SUBJECT_FACTORY, CONFIG_CLASS, "openstacknode") {
Daniel Parka7d6e9f2016-01-18 17:54:14 +0900150 @Override
151 public OpenstackNodeConfig createConfig() {
152 return new OpenstackNodeConfig();
153 }
154 };
155
Hyunsun Moon34bbe172016-06-28 19:18:40 -0700156 private final NetworkConfigListener configListener = new InternalConfigListener();
Daniel Parka7d6e9f2016-01-18 17:54:14 +0900157 private final DeviceListener deviceListener = new InternalDeviceListener();
Hyunsun Moon34bbe172016-06-28 19:18:40 -0700158 private final MapEventListener<String, OpenstackNode> nodeStoreListener = new InternalMapListener();
Daniel Parka7d6e9f2016-01-18 17:54:14 +0900159
Hyunsun Moon34bbe172016-06-28 19:18:40 -0700160 private final OvsdbHandler ovsdbHandler = new OvsdbHandler();
161 private final BridgeHandler bridgeHandler = new BridgeHandler();
162
163 private ConsistentMap<String, OpenstackNode> nodeStore;
Daniel Parka7d6e9f2016-01-18 17:54:14 +0900164 private ApplicationId appId;
Daniel Parkad21c572016-03-09 10:18:24 +0900165 private NodeId localNodeId;
Daniel Parka7d6e9f2016-01-18 17:54:14 +0900166
Daniel Parka7d6e9f2016-01-18 17:54:14 +0900167 @Activate
168 protected void activate() {
Hyunsun Moon34bbe172016-06-28 19:18:40 -0700169 appId = coreService.getAppId(APP_ID);
170
Daniel Parkad21c572016-03-09 10:18:24 +0900171 localNodeId = clusterService.getLocalNode().id();
172 leadershipService.runForLeadership(appId.name());
173
Hyunsun Moon34bbe172016-06-28 19:18:40 -0700174 nodeStore = storageService.<String, OpenstackNode>consistentMapBuilder()
Daniel Parka7d6e9f2016-01-18 17:54:14 +0900175 .withSerializer(Serializer.using(NODE_SERIALIZER.build()))
Hyunsun Moon34bbe172016-06-28 19:18:40 -0700176 .withName("openstack-nodestore")
Daniel Parka7d6e9f2016-01-18 17:54:14 +0900177 .withApplicationId(appId)
178 .build();
179
Hyunsun Moon34bbe172016-06-28 19:18:40 -0700180 nodeStore.addListener(nodeStoreListener);
Daniel Parka7d6e9f2016-01-18 17:54:14 +0900181 deviceService.addListener(deviceListener);
Hyunsun Moon34bbe172016-06-28 19:18:40 -0700182
Daniel Parka7d6e9f2016-01-18 17:54:14 +0900183 configRegistry.registerConfigFactory(configFactory);
Hyunsun Moon34bbe172016-06-28 19:18:40 -0700184 configRegistry.addListener(configListener);
185 componentConfigService.registerProperties(getClass());
Daniel Parka7d6e9f2016-01-18 17:54:14 +0900186
Hyunsun Moonef6bad22016-07-19 16:25:43 -0700187 readConfiguration();
Daniel Parka7d6e9f2016-01-18 17:54:14 +0900188 log.info("Started");
189 }
190
191 @Deactivate
192 protected void deactivate() {
Hyunsun Moon34bbe172016-06-28 19:18:40 -0700193 configRegistry.removeListener(configListener);
Daniel Parka7d6e9f2016-01-18 17:54:14 +0900194 deviceService.removeListener(deviceListener);
Hyunsun Moon34bbe172016-06-28 19:18:40 -0700195 nodeStore.removeListener(nodeStoreListener);
Daniel Parka7d6e9f2016-01-18 17:54:14 +0900196
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700197 componentConfigService.unregisterProperties(getClass(), false);
Daniel Parka7d6e9f2016-01-18 17:54:14 +0900198 configRegistry.unregisterConfigFactory(configFactory);
Hyunsun Moon34bbe172016-06-28 19:18:40 -0700199
Daniel Parkad21c572016-03-09 10:18:24 +0900200 leadershipService.withdraw(appId.name());
Hyunsun Moon34bbe172016-06-28 19:18:40 -0700201 eventExecutor.shutdown();
Daniel Parka7d6e9f2016-01-18 17:54:14 +0900202
203 log.info("Stopped");
204 }
205
Hyunsun Moon34bbe172016-06-28 19:18:40 -0700206 @Modified
207 protected void modified(ComponentContext context) {
208 Dictionary<?, ?> properties = context.getProperties();
209 int updatedOvsdbPort = Tools.getIntegerProperty(properties, OVSDB_PORT);
210 if (!Objects.equals(updatedOvsdbPort, ovsdbPort)) {
211 ovsdbPort = updatedOvsdbPort;
212 }
213
214 log.info("Modified");
215 }
Daniel Parka7d6e9f2016-01-18 17:54:14 +0900216
217 @Override
Hyunsun Moon34bbe172016-06-28 19:18:40 -0700218 public void addOrUpdateNode(OpenstackNode node) {
219 nodeStore.put(node.hostname(),
220 OpenstackNode.getUpdatedNode(node, nodeState(node)));
Daniel Parka7d6e9f2016-01-18 17:54:14 +0900221 }
222
223 @Override
224 public void deleteNode(OpenstackNode node) {
Hyunsun Moon34bbe172016-06-28 19:18:40 -0700225 nodeStore.remove(node.hostname());
Hyunsun Moon05d9b262016-07-03 18:38:44 -0700226 process(new OpenstackNodeEvent(INCOMPLETE, node));
227 }
228
229 @Override
230 public void processInitState(OpenstackNode node) {
231 // make sure there is OVSDB connection
232 if (!isOvsdbConnected(node)) {
233 connectOvsdb(node);
234 return;
235 }
Hyunsun Moon05d9b262016-07-03 18:38:44 -0700236 process(new OpenstackNodeEvent(INIT, node));
Hyunsun Moon05d9b262016-07-03 18:38:44 -0700237
Hyunsun Moon052c71f2016-07-11 18:56:18 -0700238 createBridge(node, INTEGRATION_BRIDGE, node.intBridge());
Hyunsun Moon05d9b262016-07-03 18:38:44 -0700239 if (node.type().equals(NodeType.GATEWAY)) {
Hyunsun Moon052c71f2016-07-11 18:56:18 -0700240 createBridge(node, ROUTER_BRIDGE, node.routerBridge().get());
241 // TODO remove this when OVSDB provides port event
242 setNodeState(node, nodeState(node));
Hyunsun Moon05d9b262016-07-03 18:38:44 -0700243 }
244 }
245
246 @Override
247 public void processDeviceCreatedState(OpenstackNode node) {
248 // make sure there is OVSDB connection
249 if (!isOvsdbConnected(node)) {
250 connectOvsdb(node);
251 return;
252 }
253 process(new OpenstackNodeEvent(DEVICE_CREATED, node));
Hyunsun Moon052c71f2016-07-11 18:56:18 -0700254
Hyunsun Moon05d9b262016-07-03 18:38:44 -0700255 createTunnelInterface(node);
Hyunsun Moon05d9b262016-07-03 18:38:44 -0700256 if (node.type().equals(NodeType.GATEWAY)) {
257 createPatchInterface(node);
Hyunsun Moon052c71f2016-07-11 18:56:18 -0700258 addUplink(node);
259 // TODO remove this when OVSDB provides port event
260 setNodeState(node, nodeState(node));
Hyunsun Moon05d9b262016-07-03 18:38:44 -0700261 }
262 }
263
264 @Override
265 public void processCompleteState(OpenstackNode node) {
Hyunsun Moon05d9b262016-07-03 18:38:44 -0700266 process(new OpenstackNodeEvent(COMPLETE, node));
267 log.info("Finished init {}", node.hostname());
268 }
269
270 @Override
271 public void processIncompleteState(OpenstackNode node) {
272 process(new OpenstackNodeEvent(INCOMPLETE, node));
Daniel Parka7d6e9f2016-01-18 17:54:14 +0900273 }
274
275 @Override
Hyunsun Moon34bbe172016-06-28 19:18:40 -0700276 public List<OpenstackNode> nodes() {
277 return nodeStore.values().stream().map(Versioned::value).collect(Collectors.toList());
Daniel Parka7d6e9f2016-01-18 17:54:14 +0900278 }
279
280 @Override
Hyunsun Moon34bbe172016-06-28 19:18:40 -0700281 public Set<OpenstackNode> completeNodes() {
282 return nodeStore.values().stream().map(Versioned::value)
Hyunsun Moon05d9b262016-07-03 18:38:44 -0700283 .filter(node -> node.state().equals(COMPLETE))
Hyunsun Moon34bbe172016-06-28 19:18:40 -0700284 .collect(Collectors.toSet());
285 }
Daniel Parka7d6e9f2016-01-18 17:54:14 +0900286
Hyunsun Moon34bbe172016-06-28 19:18:40 -0700287 @Override
Hyunsun Moon34bbe172016-06-28 19:18:40 -0700288 public Optional<IpAddress> dataIp(DeviceId deviceId) {
289 OpenstackNode node = nodeByDeviceId(deviceId);
290 if (node == null) {
291 log.warn("Failed to get node for {}", deviceId);
292 return Optional.empty();
293 }
294 return Optional.of(node.dataIp());
295 }
Daniel Parka7d6e9f2016-01-18 17:54:14 +0900296
Hyunsun Moon34bbe172016-06-28 19:18:40 -0700297 @Override
298 public Optional<PortNumber> tunnelPort(DeviceId deviceId) {
299 return deviceService.getPorts(deviceId).stream()
300 .filter(p -> p.annotations().value(PORT_NAME).equals(DEFAULT_TUNNEL) &&
301 p.isEnabled())
302 .map(Port::number).findFirst();
303 }
304
305 @Override
306 public Optional<DeviceId> routerBridge(DeviceId intBridgeId) {
307 OpenstackNode node = nodeByDeviceId(intBridgeId);
308 if (node == null || node.type().equals(NodeType.COMPUTE)) {
309 log.warn("Failed to find router bridge connected to {}", intBridgeId);
310 return Optional.empty();
311 }
312 return node.routerBridge();
313 }
314
315 @Override
316 public Optional<PortNumber> externalPort(DeviceId intBridgeId) {
317 return deviceService.getPorts(intBridgeId).stream()
318 .filter(p -> p.annotations().value(PORT_NAME).equals(PATCH_INTG_BRIDGE) &&
319 p.isEnabled())
320 .map(Port::number).findFirst();
321 }
322
323 private void initNode(OpenstackNode node) {
Hyunsun Moon05d9b262016-07-03 18:38:44 -0700324 NodeState state = node.state();
Hyunsun Moon34bbe172016-06-28 19:18:40 -0700325 state.process(this, node);
326 log.debug("Processing node: {} state: {}", node.hostname(), state);
327 }
328
Hyunsun Moon34bbe172016-06-28 19:18:40 -0700329 private void setNodeState(OpenstackNode node, NodeState newState) {
Hyunsun Moon052c71f2016-07-11 18:56:18 -0700330 if (node.state() != newState) {
331 log.debug("Changed {} state: {}", node.hostname(), newState);
332 nodeStore.put(node.hostname(), OpenstackNode.getUpdatedNode(node, newState));
333 }
Hyunsun Moon34bbe172016-06-28 19:18:40 -0700334 }
335
336 private NodeState nodeState(OpenstackNode node) {
Hyunsun Moon052c71f2016-07-11 18:56:18 -0700337 if (!isOvsdbConnected(node) || !deviceService.isAvailable(node.intBridge())) {
Hyunsun Moon05d9b262016-07-03 18:38:44 -0700338 return INIT;
Daniel Parka7d6e9f2016-01-18 17:54:14 +0900339 }
Hyunsun Moon052c71f2016-07-11 18:56:18 -0700340
341 // TODO use device service when we use single ONOS cluster for both openstackNode and vRouter
Hyunsun Moon34bbe172016-06-28 19:18:40 -0700342 if (node.type().equals(NodeType.GATEWAY) &&
Hyunsun Moon052c71f2016-07-11 18:56:18 -0700343 !isBridgeCreated(node.ovsdbId(), ROUTER_BRIDGE)) {
Hyunsun Moon05d9b262016-07-03 18:38:44 -0700344 return INIT;
Daniel Parka7d6e9f2016-01-18 17:54:14 +0900345 }
346
Hyunsun Moon052c71f2016-07-11 18:56:18 -0700347 if (!isIfaceCreated(node.ovsdbId(), DEFAULT_TUNNEL)) {
Hyunsun Moon05d9b262016-07-03 18:38:44 -0700348 return DEVICE_CREATED;
Hyunsun Moon34bbe172016-06-28 19:18:40 -0700349 }
350
Hyunsun Moon052c71f2016-07-11 18:56:18 -0700351 if (node.type().equals(NodeType.GATEWAY) && (
352 !isIfaceCreated(node.ovsdbId(), PATCH_ROUT_BRIDGE) ||
353 !isIfaceCreated(node.ovsdbId(), PATCH_INTG_BRIDGE) ||
354 !isIfaceCreated(node.ovsdbId(), node.uplink().get()))) {
355 return DEVICE_CREATED;
356 }
Hyunsun Moon05d9b262016-07-03 18:38:44 -0700357 return COMPLETE;
Daniel Parka7d6e9f2016-01-18 17:54:14 +0900358 }
359
Hyunsun Moon34bbe172016-06-28 19:18:40 -0700360 private boolean isIfaceCreated(DeviceId deviceId, String ifaceName) {
Hyunsun Moon052c71f2016-07-11 18:56:18 -0700361 Device device = deviceService.getDevice(deviceId);
362 if (device == null || !device.is(BridgeConfig.class)) {
363 return false;
364 }
365
366 BridgeConfig bridgeConfig = device.as(BridgeConfig.class);
367 return bridgeConfig.getPorts().stream()
368 .filter(port -> port.annotations().value(PORT_NAME).equals(ifaceName))
Hyunsun Moon34bbe172016-06-28 19:18:40 -0700369 .findAny()
370 .isPresent();
371 }
372
Hyunsun Moon052c71f2016-07-11 18:56:18 -0700373 private boolean isBridgeCreated(DeviceId deviceId, String bridgeName) {
374 Device device = deviceService.getDevice(deviceId);
375 if (device == null || !device.is(BridgeConfig.class)) {
376 return false;
377 }
378
379 BridgeConfig bridgeConfig = device.as(BridgeConfig.class);
380 return bridgeConfig.getBridges().stream()
381 .filter(bridge -> bridge.name().equals(bridgeName))
382 .findAny()
383 .isPresent();
384 }
385
386 private void createBridge(OpenstackNode node, String bridgeName, DeviceId deviceId) {
Hyunsun Moon34bbe172016-06-28 19:18:40 -0700387 Device device = deviceService.getDevice(node.ovsdbId());
388 if (device == null || !device.is(BridgeConfig.class)) {
389 log.error("Failed to create integration bridge on {}", node.ovsdbId());
Daniel Parka7d6e9f2016-01-18 17:54:14 +0900390 return;
391 }
392
Hyunsun Moon052c71f2016-07-11 18:56:18 -0700393 // TODO fix this when we use single ONOS cluster for both openstackNode and vRouter
394 Set<IpAddress> controllerIps;
395 if (bridgeName.equals(ROUTER_BRIDGE)) {
396 controllerIps = Sets.newHashSet(node.routerController().get());
397 } else {
398 controllerIps = clusterService.getNodes().stream()
399 .map(ControllerNode::ip)
400 .collect(Collectors.toSet());
401 }
Daniel Parka7d6e9f2016-01-18 17:54:14 +0900402
Hyunsun Moon052c71f2016-07-11 18:56:18 -0700403 List<ControllerInfo> controllers = controllerIps.stream()
404 .map(ip -> new ControllerInfo(ip, DEFAULT_OFPORT, DEFAULT_OF_PROTO))
405 .collect(Collectors.toList());
406
407 String dpid = deviceId.toString().substring(DPID_BEGIN);
Hyunsun Moondd14e8e2016-06-09 16:17:32 -0700408 BridgeDescription bridgeDesc = DefaultBridgeDescription.builder()
Hyunsun Moon34bbe172016-06-28 19:18:40 -0700409 .name(bridgeName)
Hyunsun Moondd14e8e2016-06-09 16:17:32 -0700410 .failMode(BridgeDescription.FailMode.SECURE)
411 .datapathId(dpid)
412 .disableInBand()
413 .controllers(controllers)
414 .build();
415
Hyunsun Moon052c71f2016-07-11 18:56:18 -0700416 BridgeConfig bridgeConfig = device.as(BridgeConfig.class);
Hyunsun Moon34bbe172016-06-28 19:18:40 -0700417 bridgeConfig.addBridge(bridgeDesc);
Daniel Parka7d6e9f2016-01-18 17:54:14 +0900418 }
419
Daniel Parka7d6e9f2016-01-18 17:54:14 +0900420 private void createTunnelInterface(OpenstackNode node) {
Hyunsun Moon052c71f2016-07-11 18:56:18 -0700421 if (isIfaceCreated(node.ovsdbId(), DEFAULT_TUNNEL)) {
422 return;
423 }
424
Hyunsun Moon34bbe172016-06-28 19:18:40 -0700425 Device device = deviceService.getDevice(node.ovsdbId());
426 if (device == null || !device.is(InterfaceConfig.class)) {
427 log.error("Failed to create tunnel interface on {}", node.ovsdbId());
Daniel Parka7d6e9f2016-01-18 17:54:14 +0900428 return;
429 }
430
Hyunsun Moon34bbe172016-06-28 19:18:40 -0700431 TunnelDescription tunnelDesc = DefaultTunnelDescription.builder()
432 .deviceId(INTEGRATION_BRIDGE)
Hyunsun Moondd14e8e2016-06-09 16:17:32 -0700433 .ifaceName(DEFAULT_TUNNEL)
434 .type(VXLAN)
435 .remote(TunnelEndPoints.flowTunnelEndpoint())
436 .key(TunnelKeys.flowTunnelKey())
437 .build();
Hyunsun Moon34bbe172016-06-28 19:18:40 -0700438
Hyunsun Moon052c71f2016-07-11 18:56:18 -0700439 InterfaceConfig ifaceConfig = device.as(InterfaceConfig.class);
Hyunsun Moon34bbe172016-06-28 19:18:40 -0700440 ifaceConfig.addTunnelMode(DEFAULT_TUNNEL, tunnelDesc);
Daniel Parka7d6e9f2016-01-18 17:54:14 +0900441 }
442
Hyunsun Moon34bbe172016-06-28 19:18:40 -0700443 private void createPatchInterface(OpenstackNode node) {
Hyunsun Moon052c71f2016-07-11 18:56:18 -0700444 checkArgument(node.type().equals(NodeType.GATEWAY));
445 if (isIfaceCreated(node.ovsdbId(), PATCH_INTG_BRIDGE) &&
446 isIfaceCreated(node.ovsdbId(), PATCH_ROUT_BRIDGE)) {
447 return;
448 }
449
Hyunsun Moon34bbe172016-06-28 19:18:40 -0700450 Device device = deviceService.getDevice(node.ovsdbId());
451 if (device == null || !device.is(InterfaceConfig.class)) {
452 log.error("Failed to create patch interfaces on {}", node.hostname());
Daniel Parka7d6e9f2016-01-18 17:54:14 +0900453 return;
454 }
455
Hyunsun Moon34bbe172016-06-28 19:18:40 -0700456 PatchDescription patchIntg = DefaultPatchDescription.builder()
457 .deviceId(INTEGRATION_BRIDGE)
458 .ifaceName(PATCH_INTG_BRIDGE)
459 .peer(PATCH_ROUT_BRIDGE)
460 .build();
461
462 PatchDescription patchRout = DefaultPatchDescription.builder()
463 .deviceId(ROUTER_BRIDGE)
464 .ifaceName(PATCH_ROUT_BRIDGE)
465 .peer(PATCH_INTG_BRIDGE)
466 .build();
467
Hyunsun Moon052c71f2016-07-11 18:56:18 -0700468 InterfaceConfig ifaceConfig = device.as(InterfaceConfig.class);
Hyunsun Moon34bbe172016-06-28 19:18:40 -0700469 ifaceConfig.addPatchMode(PATCH_INTG_BRIDGE, patchIntg);
470 ifaceConfig.addPatchMode(PATCH_ROUT_BRIDGE, patchRout);
471 }
472
Hyunsun Moon052c71f2016-07-11 18:56:18 -0700473 private void addUplink(OpenstackNode node) {
474 checkArgument(node.type().equals(NodeType.GATEWAY));
475 if (isIfaceCreated(node.ovsdbId(), node.uplink().get())) {
476 return;
477 }
478
479 Device device = deviceService.getDevice(node.ovsdbId());
480 if (device == null || !device.is(BridgeConfig.class)) {
481 log.error("Failed to add port {} on {}", node.uplink().get(), node.ovsdbId());
482 return;
483 }
484
485 BridgeConfig bridgeConfig = device.as(BridgeConfig.class);
486 bridgeConfig.addPort(BridgeName.bridgeName(ROUTER_BRIDGE),
487 node.uplink().get());
488 }
489
Hyunsun Moon34bbe172016-06-28 19:18:40 -0700490 private boolean isOvsdbConnected(OpenstackNode node) {
491 OvsdbNodeId ovsdb = new OvsdbNodeId(node.managementIp(), ovsdbPort);
Hyunsun Moon052c71f2016-07-11 18:56:18 -0700492 OvsdbClientService client = ovsdbController.getOvsdbClient(ovsdb);
Hyunsun Moon34bbe172016-06-28 19:18:40 -0700493 return deviceService.isAvailable(node.ovsdbId()) &&
494 client != null &&
495 client.isConnected();
496 }
497
498 private void connectOvsdb(OpenstackNode node) {
Hyunsun Moon052c71f2016-07-11 18:56:18 -0700499 ovsdbController.connect(node.managementIp(), TpPort.tpPort(ovsdbPort));
Hyunsun Moon34bbe172016-06-28 19:18:40 -0700500 }
501
502 private Set<String> systemIfaces(OpenstackNode node) {
503 Set<String> ifaces = Sets.newHashSet(DEFAULT_TUNNEL);
504 if (node.type().equals(NodeType.GATEWAY)) {
505 ifaces.add(PATCH_INTG_BRIDGE);
506 ifaces.add(PATCH_ROUT_BRIDGE);
Hyunsun Moon052c71f2016-07-11 18:56:18 -0700507 ifaces.add(node.uplink().get());
Hyunsun Moon34bbe172016-06-28 19:18:40 -0700508 }
509 return ifaces;
510 }
511
512 private OpenstackNode nodeByDeviceId(DeviceId deviceId) {
513 OpenstackNode node = nodes().stream()
514 .filter(n -> n.intBridge().equals(deviceId))
515 .findFirst().orElseGet(() -> nodes().stream()
516 .filter(n -> n.routerBridge().isPresent())
517 .filter(n -> n.routerBridge().get().equals(deviceId))
518 .findFirst().orElse(null));
519
520 return node;
521 }
522
523 private class OvsdbHandler implements ConnectionHandler<Device> {
524
525 @Override
526 public void connected(Device device) {
527 OpenstackNode node = nodes().stream()
528 .filter(n -> n.ovsdbId().equals(device.id()))
529 .findFirst()
530 .orElse(null);
531 if (node != null) {
532 setNodeState(node, nodeState(node));
533 } else {
534 log.debug("{} is detected on unregistered node, ignore it.", device.id());
535 }
536 }
537
538 @Override
539 public void disconnected(Device device) {
Hyunsun Moon052c71f2016-07-11 18:56:18 -0700540 OpenstackNode node = nodeByDeviceId(device.id());
541 if (node != null) {
542 log.warn("Device {} is disconnected", device.id());
543 setNodeState(node, NodeState.INCOMPLETE);
544 }
Hyunsun Moon34bbe172016-06-28 19:18:40 -0700545 }
546 }
547
548 private class BridgeHandler implements ConnectionHandler<Device> {
549
550 @Override
551 public void connected(Device device) {
552 OpenstackNode node = nodeByDeviceId(device.id());
553 if (node != null) {
554 setNodeState(node, nodeState(node));
555 } else {
556 log.debug("{} is detected on unregistered node, ignore it.", device.id());
557 }
558 }
559
560 @Override
561 public void disconnected(Device device) {
562 OpenstackNode node = nodeByDeviceId(device.id());
563 if (node != null) {
564 log.warn("Device {} is disconnected", device.id());
565 setNodeState(node, NodeState.INCOMPLETE);
566 }
567 }
568
569 /**
570 * Handles port added situation.
571 * If the added port is tunnel or data plane interface, proceed to the remaining
572 * node initialization. Otherwise, do nothing.
573 *
574 * @param port port
575 */
576 public void portAdded(Port port) {
577 OpenstackNode node = nodeByDeviceId((DeviceId) port.element().id());
578 String portName = port.annotations().value(PORT_NAME);
579 if (node == null) {
580 log.debug("{} is added to unregistered node, ignore it.", portName);
581 return;
582 }
583
584 log.info("Port {} is added to {}", portName, node.hostname());
585 if (systemIfaces(node).contains(portName)) {
586 setNodeState(node, nodeState(node));
587 }
588 }
589
590 /**
591 * Handles port removed situation.
592 * If the removed port is tunnel or data plane interface, proceed to the remaining
593 * node initialization.Others, do nothing.
594 *
595 * @param port port
596 */
597 public void portRemoved(Port port) {
598 OpenstackNode node = nodeByDeviceId((DeviceId) port.element().id());
599 String portName = port.annotations().value(PORT_NAME);
600
601 if (node == null) {
602 return;
603 }
604
605 log.info("Port {} is removed from {}", portName, node.hostname());
606 if (systemIfaces(node).contains(portName)) {
607 setNodeState(node, NodeState.INCOMPLETE);
608 }
Daniel Parka7d6e9f2016-01-18 17:54:14 +0900609 }
610 }
611
612 private class InternalDeviceListener implements DeviceListener {
613
614 @Override
615 public void event(DeviceEvent event) {
Daniel Parkad21c572016-03-09 10:18:24 +0900616
Hyunsun Moon34bbe172016-06-28 19:18:40 -0700617 NodeId leaderNodeId = leadershipService.getLeader(appId.name());
618 if (!Objects.equals(localNodeId, leaderNodeId)) {
619 // do not allow to proceed without leadership
Daniel Parkad21c572016-03-09 10:18:24 +0900620 return;
621 }
Daniel Parka7d6e9f2016-01-18 17:54:14 +0900622
623 Device device = event.subject();
624 ConnectionHandler<Device> handler =
625 (device.type().equals(SWITCH) ? bridgeHandler : ovsdbHandler);
626
627 switch (event.type()) {
Hyunsun Moon052c71f2016-07-11 18:56:18 -0700628 // TODO implement OVSDB port event so that we can handle updates on the OVSDB
Daniel Parka7d6e9f2016-01-18 17:54:14 +0900629 case PORT_ADDED:
Hyunsun Moon34bbe172016-06-28 19:18:40 -0700630 eventExecutor.execute(() -> bridgeHandler.portAdded(event.port()));
Daniel Parka7d6e9f2016-01-18 17:54:14 +0900631 break;
632 case PORT_UPDATED:
633 if (!event.port().isEnabled()) {
Hyunsun Moon34bbe172016-06-28 19:18:40 -0700634 eventExecutor.execute(() -> bridgeHandler.portRemoved(event.port()));
Daniel Parka7d6e9f2016-01-18 17:54:14 +0900635 }
636 break;
637 case DEVICE_ADDED:
638 case DEVICE_AVAILABILITY_CHANGED:
639 if (deviceService.isAvailable(device.id())) {
Hyunsun Moon34bbe172016-06-28 19:18:40 -0700640 eventExecutor.execute(() -> handler.connected(device));
Daniel Parka7d6e9f2016-01-18 17:54:14 +0900641 } else {
Hyunsun Moon34bbe172016-06-28 19:18:40 -0700642 eventExecutor.execute(() -> handler.disconnected(device));
Daniel Parka7d6e9f2016-01-18 17:54:14 +0900643 }
644 break;
645 default:
Daniel Parka7d6e9f2016-01-18 17:54:14 +0900646 break;
647 }
648 }
649 }
650
Daniel Parka7d6e9f2016-01-18 17:54:14 +0900651 private void readConfiguration() {
Hyunsun Moon34bbe172016-06-28 19:18:40 -0700652 OpenstackNodeConfig config = configRegistry.getConfig(appId, CONFIG_CLASS);
Daniel Parka7d6e9f2016-01-18 17:54:14 +0900653 if (config == null) {
Hyunsun Moon34bbe172016-06-28 19:18:40 -0700654 log.debug("No configuration found");
Daniel Parka7d6e9f2016-01-18 17:54:14 +0900655 return;
656 }
Hyunsun Moon34bbe172016-06-28 19:18:40 -0700657 config.openstackNodes().forEach(this::addOrUpdateNode);
Daniel Parka7d6e9f2016-01-18 17:54:14 +0900658 }
659
660 private class InternalConfigListener implements NetworkConfigListener {
661
662 @Override
663 public void event(NetworkConfigEvent event) {
Hyunsun Moon34bbe172016-06-28 19:18:40 -0700664 NodeId leaderNodeId = leadershipService.getLeader(appId.name());
665 if (!Objects.equals(localNodeId, leaderNodeId)) {
666 // do not allow to proceed without leadership
667 return;
668 }
669
670 if (!event.configClass().equals(CONFIG_CLASS)) {
Daniel Parka7d6e9f2016-01-18 17:54:14 +0900671 return;
672 }
673
674 switch (event.type()) {
675 case CONFIG_ADDED:
676 case CONFIG_UPDATED:
677 eventExecutor.execute(OpenstackNodeManager.this::readConfiguration);
678 break;
679 default:
680 break;
681 }
682 }
683 }
684
Hyunsun Moon34bbe172016-06-28 19:18:40 -0700685 private class InternalMapListener implements MapEventListener<String, OpenstackNode> {
Daniel Parka7d6e9f2016-01-18 17:54:14 +0900686
Hyunsun Moon34bbe172016-06-28 19:18:40 -0700687 @Override
688 public void event(MapEvent<String, OpenstackNode> event) {
689 NodeId leaderNodeId = leadershipService.getLeader(appId.name());
690 if (!Objects.equals(localNodeId, leaderNodeId)) {
691 // do not allow to proceed without leadership
692 return;
693 }
694
695 OpenstackNode oldNode;
696 OpenstackNode newNode;
697
698 switch (event.type()) {
699 case UPDATE:
700 oldNode = event.oldValue().value();
701 newNode = event.newValue().value();
702
Hyunsun Moon052c71f2016-07-11 18:56:18 -0700703 log.info("Reloaded {}", newNode.hostname());
Hyunsun Moon34bbe172016-06-28 19:18:40 -0700704 if (!newNode.equals(oldNode)) {
705 log.debug("New node: {}", newNode);
706 }
707 // performs init procedure even if the node is not changed
708 // for robustness since it's no harm to run init procedure
709 // multiple times
710 eventExecutor.execute(() -> initNode(newNode));
711 break;
712 case INSERT:
713 newNode = event.newValue().value();
714 log.info("Added {}", newNode.hostname());
715 eventExecutor.execute(() -> initNode(newNode));
716 break;
717 case REMOVE:
718 oldNode = event.oldValue().value();
719 log.info("Removed {}", oldNode.hostname());
720 break;
721 default:
722 break;
723 }
724 }
725 }
Daniel Parka7d6e9f2016-01-18 17:54:14 +0900726}