blob: 01f8e4fee0854e0f0dd7e62174052eec10040854 [file] [log] [blame]
Hyunsun Moon0d457362017-06-27 17:19:41 +09001/*
Brian O'Connora09fe5b2017-08-03 21:12:30 -07002 * Copyright 2017-present Open Networking Foundation
Hyunsun Moon0d457362017-06-27 17:19:41 +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.impl;
17
Ray Milkey86ad7bb2018-09-27 12:32:28 -070018import com.google.common.collect.Lists;
Hyunsun Moon0d457362017-06-27 17:19:41 +090019import org.onlab.packet.IpAddress;
20import org.onlab.util.Tools;
21import org.onosproject.cfg.ComponentConfigService;
22import org.onosproject.cluster.ClusterService;
23import org.onosproject.cluster.ControllerNode;
24import org.onosproject.cluster.LeadershipService;
25import org.onosproject.cluster.NodeId;
26import org.onosproject.core.ApplicationId;
27import org.onosproject.core.CoreService;
Hyunsun Moon0d457362017-06-27 17:19:41 +090028import org.onosproject.net.Device;
29import org.onosproject.net.DeviceId;
30import org.onosproject.net.Port;
31import org.onosproject.net.behaviour.BridgeConfig;
32import org.onosproject.net.behaviour.BridgeDescription;
Hyunsun Moon0d457362017-06-27 17:19:41 +090033import org.onosproject.net.behaviour.ControllerInfo;
34import org.onosproject.net.behaviour.DefaultBridgeDescription;
Hyunsun Moon0d457362017-06-27 17:19:41 +090035import org.onosproject.net.behaviour.DefaultTunnelDescription;
Hyunsun Moon0d457362017-06-27 17:19:41 +090036import org.onosproject.net.behaviour.InterfaceConfig;
Hyunsun Moon0d457362017-06-27 17:19:41 +090037import org.onosproject.net.behaviour.TunnelDescription;
38import org.onosproject.net.behaviour.TunnelEndPoints;
39import org.onosproject.net.behaviour.TunnelKeys;
40import org.onosproject.net.device.DeviceAdminService;
41import org.onosproject.net.device.DeviceEvent;
42import org.onosproject.net.device.DeviceListener;
43import org.onosproject.net.device.DeviceService;
Daniel Parke2658ba2018-08-24 22:33:29 +090044import org.onosproject.openstacknode.api.DpdkInterface;
Hyunsun Moon0d457362017-06-27 17:19:41 +090045import org.onosproject.openstacknode.api.NodeState;
46import org.onosproject.openstacknode.api.OpenstackNode;
Hyunsun Moon0d457362017-06-27 17:19:41 +090047import org.onosproject.openstacknode.api.OpenstackNodeAdminService;
48import org.onosproject.openstacknode.api.OpenstackNodeEvent;
49import org.onosproject.openstacknode.api.OpenstackNodeHandler;
50import org.onosproject.openstacknode.api.OpenstackNodeListener;
51import org.onosproject.openstacknode.api.OpenstackNodeService;
Jian Lie6312162018-03-21 21:41:00 +090052import org.onosproject.openstacknode.api.OpenstackPhyInterface;
Daniel Parke2658ba2018-08-24 22:33:29 +090053import org.onosproject.ovsdb.controller.OvsdbClientService;
Hyunsun Moon0d457362017-06-27 17:19:41 +090054import org.onosproject.ovsdb.controller.OvsdbController;
Daniel Parke2658ba2018-08-24 22:33:29 +090055import org.onosproject.ovsdb.controller.OvsdbPort;
56import org.onosproject.ovsdb.rfc.notation.OvsdbMap;
57import org.onosproject.ovsdb.rfc.notation.OvsdbSet;
58import org.onosproject.ovsdb.rfc.table.Interface;
Jian Li51b844c2018-05-31 10:59:03 +090059import org.openstack4j.api.OSClient;
Hyunsun Moon0d457362017-06-27 17:19:41 +090060import org.osgi.service.component.ComponentContext;
Ray Milkeyd84f89b2018-08-17 14:54:17 -070061import org.osgi.service.component.annotations.Activate;
62import org.osgi.service.component.annotations.Component;
63import org.osgi.service.component.annotations.Deactivate;
64import org.osgi.service.component.annotations.Modified;
65import org.osgi.service.component.annotations.Reference;
66import org.osgi.service.component.annotations.ReferenceCardinality;
Hyunsun Moon0d457362017-06-27 17:19:41 +090067import org.slf4j.Logger;
68
Daniel Parke2658ba2018-08-24 22:33:29 +090069import java.util.Collection;
Hyunsun Moon0d457362017-06-27 17:19:41 +090070import java.util.Dictionary;
71import java.util.List;
72import java.util.Objects;
Daniel Parke2658ba2018-08-24 22:33:29 +090073import java.util.Optional;
Hyunsun Moon0d457362017-06-27 17:19:41 +090074import java.util.Set;
75import java.util.concurrent.ExecutorService;
76import java.util.stream.Collectors;
77
Hyunsun Moon0d457362017-06-27 17:19:41 +090078import static java.util.concurrent.Executors.newSingleThreadExecutor;
79import static org.onlab.packet.TpPort.tpPort;
80import static org.onlab.util.Tools.groupedThreads;
81import static org.onosproject.net.AnnotationKeys.PORT_NAME;
Jian Li621f73c2018-12-15 01:49:22 +090082import static org.onosproject.openstacknode.api.Constants.GENEVE;
83import static org.onosproject.openstacknode.api.Constants.GENEVE_TUNNEL;
SONA Project6bc5c4a2018-12-14 23:49:52 +090084import static org.onosproject.openstacknode.api.Constants.GRE;
Jian Li2d68c192018-12-13 15:52:59 +090085import static org.onosproject.openstacknode.api.Constants.GRE_TUNNEL;
Jian Li5afbea42018-02-28 10:37:03 +090086import static org.onosproject.openstacknode.api.Constants.INTEGRATION_BRIDGE;
Daniel Parke2658ba2018-08-24 22:33:29 +090087import static org.onosproject.openstacknode.api.Constants.TUNNEL_BRIDGE;
SONA Project6bc5c4a2018-12-14 23:49:52 +090088import static org.onosproject.openstacknode.api.Constants.VXLAN;
89import static org.onosproject.openstacknode.api.Constants.VXLAN_TUNNEL;
Daniel Parkd02d7bd2018-08-23 23:04:31 +090090import static org.onosproject.openstacknode.api.DpdkConfig.DatapathType.NETDEV;
Jian Li5afbea42018-02-28 10:37:03 +090091import static org.onosproject.openstacknode.api.NodeState.COMPLETE;
92import static org.onosproject.openstacknode.api.NodeState.DEVICE_CREATED;
93import static org.onosproject.openstacknode.api.NodeState.INCOMPLETE;
Jian Li51b844c2018-05-31 10:59:03 +090094import static org.onosproject.openstacknode.api.NodeState.INIT;
95import static org.onosproject.openstacknode.api.OpenstackNode.NodeType.CONTROLLER;
Hyunsun Moon0d457362017-06-27 17:19:41 +090096import static org.onosproject.openstacknode.api.OpenstackNode.NodeType.GATEWAY;
97import static org.onosproject.openstacknode.api.OpenstackNodeService.APP_ID;
Ray Milkey8e406512018-10-24 15:56:50 -070098import static org.onosproject.openstacknode.impl.OsgiPropertyConstants.AUTO_RECOVERY;
99import static org.onosproject.openstacknode.impl.OsgiPropertyConstants.AUTO_RECOVERY_DEFAULT;
100import static org.onosproject.openstacknode.impl.OsgiPropertyConstants.OVSDB_PORT;
101import static org.onosproject.openstacknode.impl.OsgiPropertyConstants.OVSDB_PORT_NUM_DEFAULT;
Daniel Park5a6a7102018-09-06 23:58:33 +0900102import static org.onosproject.openstacknode.util.OpenstackNodeUtil.addOrRemoveDpdkInterface;
103import static org.onosproject.openstacknode.util.OpenstackNodeUtil.addOrRemoveSystemInterface;
Jian Li97482c12018-07-03 01:08:23 +0900104import static org.onosproject.openstacknode.util.OpenstackNodeUtil.getBooleanProperty;
Jian Li51b844c2018-05-31 10:59:03 +0900105import static org.onosproject.openstacknode.util.OpenstackNodeUtil.getConnectedClient;
Daniel Parke2658ba2018-08-24 22:33:29 +0900106import static org.onosproject.openstacknode.util.OpenstackNodeUtil.getOvsdbClient;
Daniel Parkc4d06402018-05-28 15:57:37 +0900107import static org.onosproject.openstacknode.util.OpenstackNodeUtil.isOvsdbConnected;
Hyunsun Moon0d457362017-06-27 17:19:41 +0900108import static org.slf4j.LoggerFactory.getLogger;
109
110/**
111 * Service bootstraps openstack node based on its type.
112 */
Ray Milkey8e406512018-10-24 15:56:50 -0700113@Component(immediate = true,
114 property = {
115 OVSDB_PORT + ":Integer=" + OVSDB_PORT_NUM_DEFAULT,
116 AUTO_RECOVERY + ":Boolean=" + AUTO_RECOVERY_DEFAULT
117 }
118)
Hyunsun Moon0d457362017-06-27 17:19:41 +0900119public class DefaultOpenstackNodeHandler implements OpenstackNodeHandler {
120
Jian Li5afbea42018-02-28 10:37:03 +0900121 private final Logger log = getLogger(getClass());
Hyunsun Moon0d457362017-06-27 17:19:41 +0900122
Hyunsun Moon0d457362017-06-27 17:19:41 +0900123 private static final String DEFAULT_OF_PROTO = "tcp";
Daniel Park4b24cec2018-11-28 19:21:25 +0900124 private static final String NO_OVSDB_CLIENT_MSG = "Failed to get ovsdb client";
Hyunsun Moon0d457362017-06-27 17:19:41 +0900125 private static final int DEFAULT_OFPORT = 6653;
126 private static final int DPID_BEGIN = 3;
127
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700128 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Hyunsun Moon0d457362017-06-27 17:19:41 +0900129 protected CoreService coreService;
130
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700131 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Hyunsun Moon0d457362017-06-27 17:19:41 +0900132 protected LeadershipService leadershipService;
133
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700134 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Hyunsun Moon0d457362017-06-27 17:19:41 +0900135 protected ClusterService clusterService;
136
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700137 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Hyunsun Moon0d457362017-06-27 17:19:41 +0900138 protected DeviceService deviceService;
139
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700140 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Hyunsun Moon0d457362017-06-27 17:19:41 +0900141 protected DeviceAdminService deviceAdminService;
142
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700143 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Hyunsun Moon0d457362017-06-27 17:19:41 +0900144 protected OvsdbController ovsdbController;
145
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700146 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Hyunsun Moon0d457362017-06-27 17:19:41 +0900147 protected OpenstackNodeService osNodeService;
148
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700149 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Hyunsun Moon0d457362017-06-27 17:19:41 +0900150 protected OpenstackNodeAdminService osNodeAdminService;
151
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700152 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Hyunsun Moon0d457362017-06-27 17:19:41 +0900153 protected ComponentConfigService componentConfigService;
154
Ray Milkey8e406512018-10-24 15:56:50 -0700155 /** OVSDB server listen port. */
156 private int ovsdbPortNum = OVSDB_PORT_NUM_DEFAULT;
Hyunsun Moon0d457362017-06-27 17:19:41 +0900157
Jian Li900b7232018-12-14 14:04:51 +0900158 /** Indicates whether auto-recover openstack node status on switch re-conn event. */
Ray Milkey8e406512018-10-24 15:56:50 -0700159 private boolean autoRecovery = AUTO_RECOVERY_DEFAULT;
Jian Li97482c12018-07-03 01:08:23 +0900160
Hyunsun Moon0d457362017-06-27 17:19:41 +0900161 private final ExecutorService eventExecutor = newSingleThreadExecutor(
162 groupedThreads(this.getClass().getSimpleName(), "event-handler", log));
163
164 private final DeviceListener ovsdbListener = new InternalOvsdbListener();
165 private final DeviceListener bridgeListener = new InternalBridgeListener();
Hyunsun Moon0d457362017-06-27 17:19:41 +0900166 private final OpenstackNodeListener osNodeListener = new InternalOpenstackNodeListener();
167
168 private ApplicationId appId;
169 private NodeId localNode;
170
171 @Activate
172 protected void activate() {
173 appId = coreService.getAppId(APP_ID);
174 localNode = clusterService.getLocalNode().id();
175
176 componentConfigService.registerProperties(getClass());
177 leadershipService.runForLeadership(appId.name());
Hyunsun Moon0d457362017-06-27 17:19:41 +0900178 deviceService.addListener(ovsdbListener);
179 deviceService.addListener(bridgeListener);
180 osNodeService.addListener(osNodeListener);
181
182 log.info("Started");
183 }
184
185 @Deactivate
186 protected void deactivate() {
187 osNodeService.removeListener(osNodeListener);
188 deviceService.removeListener(bridgeListener);
189 deviceService.removeListener(ovsdbListener);
Hyunsun Moon0d457362017-06-27 17:19:41 +0900190 componentConfigService.unregisterProperties(getClass(), false);
191 leadershipService.withdraw(appId.name());
192 eventExecutor.shutdown();
193
194 log.info("Stopped");
195 }
196
197 @Modified
198 protected void modified(ComponentContext context) {
Jian Li97482c12018-07-03 01:08:23 +0900199 readComponentConfiguration(context);
Hyunsun Moon0d457362017-06-27 17:19:41 +0900200
201 log.info("Modified");
202 }
203
204 @Override
205 public void processInitState(OpenstackNode osNode) {
Ray Milkey8e406512018-10-24 15:56:50 -0700206 if (!isOvsdbConnected(osNode, ovsdbPortNum, ovsdbController, deviceService)) {
207 ovsdbController.connect(osNode.managementIp(), tpPort(ovsdbPortNum));
Hyunsun Moon0d457362017-06-27 17:19:41 +0900208 return;
209 }
210 if (!deviceService.isAvailable(osNode.intgBridge())) {
211 createBridge(osNode, INTEGRATION_BRIDGE, osNode.intgBridge());
212 }
Daniel Parke2658ba2018-08-24 22:33:29 +0900213 if (hasDpdkTunnelBridge(osNode)) {
214 createDpdkTunnelBridge(osNode);
215 }
Hyunsun Moon0d457362017-06-27 17:19:41 +0900216 }
217
218 @Override
219 public void processDeviceCreatedState(OpenstackNode osNode) {
daniel parkb18424c2018-02-05 15:43:43 +0900220 try {
Ray Milkey8e406512018-10-24 15:56:50 -0700221 if (!isOvsdbConnected(osNode, ovsdbPortNum, ovsdbController, deviceService)) {
222 ovsdbController.connect(osNode.managementIp(), tpPort(ovsdbPortNum));
daniel parkb18424c2018-02-05 15:43:43 +0900223 return;
224 }
Hyunsun Moon0d457362017-06-27 17:19:41 +0900225
daniel parkb18424c2018-02-05 15:43:43 +0900226 if (osNode.type() == GATEWAY) {
Jian Li97482c12018-07-03 01:08:23 +0900227 addOrRemoveSystemInterface(osNode, INTEGRATION_BRIDGE,
Daniel Park5a6a7102018-09-06 23:58:33 +0900228 osNode.uplinkPort(), deviceService, true);
daniel parkb18424c2018-02-05 15:43:43 +0900229 }
230
231 if (osNode.dataIp() != null &&
Jian Li2d68c192018-12-13 15:52:59 +0900232 !isIntfEnabled(osNode, VXLAN_TUNNEL)) {
233 createVxlanTunnelInterface(osNode);
234 }
235
236 if (osNode.dataIp() != null &&
237 !isIntfEnabled(osNode, GRE_TUNNEL)) {
238 createGreTunnelInterface(osNode);
daniel parkb18424c2018-02-05 15:43:43 +0900239 }
240
Jian Li621f73c2018-12-15 01:49:22 +0900241 if (osNode.dataIp() != null &&
242 !isIntfEnabled(osNode, GENEVE_TUNNEL)) {
243 createGeneveTunnelInterface(osNode);
244 }
245
Daniel Parke2658ba2018-08-24 22:33:29 +0900246 if (osNode.dpdkConfig() != null && osNode.dpdkConfig().dpdkIntfs() != null) {
Daniel Park5a6a7102018-09-06 23:58:33 +0900247 osNode.dpdkConfig().dpdkIntfs().stream()
Jian Li5ecfd1a2018-12-10 11:41:03 +0900248 .filter(dpdkintf -> dpdkintf.deviceName().equals(TUNNEL_BRIDGE))
249 .forEach(dpdkintf -> addOrRemoveDpdkInterface(
250 osNode, dpdkintf, ovsdbPortNum, ovsdbController, true));
Daniel Park5a6a7102018-09-06 23:58:33 +0900251
252 osNode.dpdkConfig().dpdkIntfs().stream()
Jian Li5ecfd1a2018-12-10 11:41:03 +0900253 .filter(dpdkintf -> dpdkintf.deviceName().equals(INTEGRATION_BRIDGE))
254 .forEach(dpdkintf -> addOrRemoveDpdkInterface(
255 osNode, dpdkintf, ovsdbPortNum, ovsdbController, true));
Daniel Parke2658ba2018-08-24 22:33:29 +0900256 }
257
Jian Lie6312162018-03-21 21:41:00 +0900258 osNode.phyIntfs().forEach(i -> {
259 if (!isIntfEnabled(osNode, i.intf())) {
Jian Li97482c12018-07-03 01:08:23 +0900260 addOrRemoveSystemInterface(osNode, INTEGRATION_BRIDGE,
Daniel Park5a6a7102018-09-06 23:58:33 +0900261 i.intf(), deviceService, true);
Jian Lie6312162018-03-21 21:41:00 +0900262 }
263 });
264
Daniel Park5a6a7102018-09-06 23:58:33 +0900265 if (osNode.vlanIntf() != null &&
266 !isIntfEnabled(osNode, osNode.vlanIntf())) {
267 addOrRemoveSystemInterface(osNode, INTEGRATION_BRIDGE,
Jian Li5ecfd1a2018-12-10 11:41:03 +0900268 osNode.vlanIntf(), deviceService, true);
Daniel Park5a6a7102018-09-06 23:58:33 +0900269 }
daniel parkb18424c2018-02-05 15:43:43 +0900270 } catch (Exception e) {
Jian Li621f73c2018-12-15 01:49:22 +0900271 log.error("Exception occurred because of {}", e);
Hyunsun Moon0d457362017-06-27 17:19:41 +0900272 }
273 }
274
275 @Override
276 public void processCompleteState(OpenstackNode osNode) {
Daniel Parkc4d06402018-05-28 15:57:37 +0900277 //Do something if needed
Hyunsun Moon0d457362017-06-27 17:19:41 +0900278 }
279
280 @Override
281 public void processIncompleteState(OpenstackNode osNode) {
Daniel Park4b24cec2018-11-28 19:21:25 +0900282 //Do nothing for now
Hyunsun Moon0d457362017-06-27 17:19:41 +0900283 }
284
Daniel Parke2658ba2018-08-24 22:33:29 +0900285 private boolean hasDpdkTunnelBridge(OpenstackNode osNode) {
286 if (osNode.dpdkConfig() != null && osNode.dpdkConfig().dpdkIntfs() != null) {
287 return osNode.dpdkConfig().dpdkIntfs().stream()
288 .anyMatch(intf -> intf.deviceName().equals(TUNNEL_BRIDGE));
289 }
290 return false;
291 }
292
293 private boolean dpdkTunnelBridgeCreated(OpenstackNode osNode) {
294
Ray Milkey8e406512018-10-24 15:56:50 -0700295 OvsdbClientService client = getOvsdbClient(osNode, ovsdbPortNum, ovsdbController);
Daniel Parke2658ba2018-08-24 22:33:29 +0900296 if (client == null) {
Daniel Park4b24cec2018-11-28 19:21:25 +0900297 log.info(NO_OVSDB_CLIENT_MSG);
Daniel Parke2658ba2018-08-24 22:33:29 +0900298 return false;
299 }
300
301 return client.getBridges().stream()
302 .anyMatch(bridge -> bridge.name().equals(TUNNEL_BRIDGE));
303 }
304
Jian Li340165f2018-02-27 10:38:17 +0900305 /**
Jian Li340165f2018-02-27 10:38:17 +0900306 * Creates a bridge with a given name on a given openstack node.
307 *
308 * @param osNode openstack node
309 * @param bridgeName bridge name
310 * @param deviceId device identifier
311 */
Hyunsun Moon0d457362017-06-27 17:19:41 +0900312 private void createBridge(OpenstackNode osNode, String bridgeName, DeviceId deviceId) {
313 Device device = deviceService.getDevice(osNode.ovsdb());
Hyunsun Moon0d457362017-06-27 17:19:41 +0900314
Jian Li789fadb2018-07-10 13:59:47 +0900315 List<ControllerInfo> controllers;
316
317 if (osNode.controllers() != null && osNode.controllers().size() > 0) {
318 controllers = (List<ControllerInfo>) osNode.controllers();
319 } else {
320 Set<IpAddress> controllerIps = clusterService.getNodes().stream()
Hyunsun Moon0d457362017-06-27 17:19:41 +0900321 .map(ControllerNode::ip)
322 .collect(Collectors.toSet());
Hyunsun Moon0d457362017-06-27 17:19:41 +0900323
Jian Li789fadb2018-07-10 13:59:47 +0900324 controllers = controllerIps.stream()
325 .map(ip -> new ControllerInfo(ip, DEFAULT_OFPORT, DEFAULT_OF_PROTO))
326 .collect(Collectors.toList());
327 }
Hyunsun Moon0d457362017-06-27 17:19:41 +0900328
329 String dpid = deviceId.toString().substring(DPID_BEGIN);
daniel parkb18424c2018-02-05 15:43:43 +0900330
Daniel Park92abf312018-08-08 17:01:35 +0900331 BridgeDescription.Builder builder = DefaultBridgeDescription.builder()
Hyunsun Moon0d457362017-06-27 17:19:41 +0900332 .name(bridgeName)
333 .failMode(BridgeDescription.FailMode.SECURE)
334 .datapathId(dpid)
335 .disableInBand()
Daniel Park92abf312018-08-08 17:01:35 +0900336 .controllers(controllers);
337
338 if (osNode.datapathType().equals(NETDEV)) {
Daniel Parke2658ba2018-08-24 22:33:29 +0900339 builder.datapathType(NETDEV.name().toLowerCase());
Daniel Park92abf312018-08-08 17:01:35 +0900340 }
Hyunsun Moon0d457362017-06-27 17:19:41 +0900341
342 BridgeConfig bridgeConfig = device.as(BridgeConfig.class);
Daniel Park92abf312018-08-08 17:01:35 +0900343 bridgeConfig.addBridge(builder.build());
Hyunsun Moon0d457362017-06-27 17:19:41 +0900344 }
345
Daniel Parke2658ba2018-08-24 22:33:29 +0900346 private void createDpdkTunnelBridge(OpenstackNode osNode) {
347 Device device = deviceService.getDevice(osNode.ovsdb());
348
349 BridgeDescription.Builder builder = DefaultBridgeDescription.builder()
350 .name(TUNNEL_BRIDGE)
351 .datapathType(NETDEV.name().toLowerCase());
352
353 BridgeConfig bridgeConfig = device.as(BridgeConfig.class);
354 bridgeConfig.addBridge(builder.build());
355 }
356
Jian Li340165f2018-02-27 10:38:17 +0900357 /**
Jian Li2d68c192018-12-13 15:52:59 +0900358 * Creates a VXLAN tunnel interface in a given openstack node.
359 *
360 * @param osNode openstack node
361 */
362 private void createVxlanTunnelInterface(OpenstackNode osNode) {
SONA Project6bc5c4a2018-12-14 23:49:52 +0900363 createTunnelInterface(osNode, VXLAN, VXLAN_TUNNEL);
Jian Li2d68c192018-12-13 15:52:59 +0900364 }
365
366 /**
367 * Creates a GRE tunnel interface in a given openstack node.
368 *
369 * @param osNode openstack node
370 */
371 private void createGreTunnelInterface(OpenstackNode osNode) {
SONA Project6bc5c4a2018-12-14 23:49:52 +0900372 createTunnelInterface(osNode, GRE, GRE_TUNNEL);
Jian Li2d68c192018-12-13 15:52:59 +0900373 }
374
375 /**
Jian Li621f73c2018-12-15 01:49:22 +0900376 * Creates a GENEVE tunnel interface in a given openstack node.
377 *
378 * @param osNode openstack node
379 */
380 private void createGeneveTunnelInterface(OpenstackNode osNode) {
381 createTunnelInterface(osNode, GENEVE, GENEVE_TUNNEL);
382 }
383
384 /**
Jian Li340165f2018-02-27 10:38:17 +0900385 * Creates a tunnel interface in a given openstack node.
386 *
387 * @param osNode openstack node
388 */
Jian Li2d68c192018-12-13 15:52:59 +0900389 private void createTunnelInterface(OpenstackNode osNode,
SONA Project6bc5c4a2018-12-14 23:49:52 +0900390 String type, String intfName) {
Jian Li2d68c192018-12-13 15:52:59 +0900391 if (isIntfEnabled(osNode, intfName)) {
Hyunsun Moon0d457362017-06-27 17:19:41 +0900392 return;
393 }
394
395 Device device = deviceService.getDevice(osNode.ovsdb());
396 if (device == null || !device.is(InterfaceConfig.class)) {
397 log.error("Failed to create tunnel interface on {}", osNode.ovsdb());
398 return;
399 }
400
Jian Li2d68c192018-12-13 15:52:59 +0900401 TunnelDescription tunnelDesc = buildTunnelDesc(type, intfName);
Hyunsun Moon0d457362017-06-27 17:19:41 +0900402
403 InterfaceConfig ifaceConfig = device.as(InterfaceConfig.class);
Jian Li2d68c192018-12-13 15:52:59 +0900404 ifaceConfig.addTunnelMode(intfName, tunnelDesc);
405 }
406
407 /**
408 * Builds tunnel description according to the network type.
409 *
410 * @param type network type
411 * @return tunnel description
412 */
SONA Project6bc5c4a2018-12-14 23:49:52 +0900413 private TunnelDescription buildTunnelDesc(String type, String intfName) {
Jian Li621f73c2018-12-15 01:49:22 +0900414 if (VXLAN.equals(type) || GRE.equals(type) || GENEVE.equals(type)) {
Jian Li2d68c192018-12-13 15:52:59 +0900415 TunnelDescription.Builder tdBuilder =
416 DefaultTunnelDescription.builder()
417 .deviceId(INTEGRATION_BRIDGE)
418 .ifaceName(intfName)
419 .remote(TunnelEndPoints.flowTunnelEndpoint())
420 .key(TunnelKeys.flowTunnelKey());
421
422 switch (type) {
423 case VXLAN:
424 tdBuilder.type(TunnelDescription.Type.VXLAN);
425 break;
426 case GRE:
427 tdBuilder.type(TunnelDescription.Type.GRE);
428 break;
Jian Li621f73c2018-12-15 01:49:22 +0900429 case GENEVE:
430 tdBuilder.type(TunnelDescription.Type.GENEVE);
431 break;
Jian Li2d68c192018-12-13 15:52:59 +0900432 default:
433 return null;
434 }
435
436 return tdBuilder.build();
437 }
438 return null;
Hyunsun Moon0d457362017-06-27 17:19:41 +0900439 }
440
Jian Li340165f2018-02-27 10:38:17 +0900441 /**
Jian Li5ecfd1a2018-12-10 11:41:03 +0900442 * Checks whether a given network interface in a given openstack node
443 * is enabled or not.
Jian Li340165f2018-02-27 10:38:17 +0900444 *
445 * @param osNode openstack node
446 * @param intf network interface name
447 * @return true if the given interface is enabled, false otherwise
448 */
Hyunsun Moon0d457362017-06-27 17:19:41 +0900449 private boolean isIntfEnabled(OpenstackNode osNode, String intf) {
Jian Li5afbea42018-02-28 10:37:03 +0900450 return deviceService.isAvailable(osNode.intgBridge()) &&
451 deviceService.getPorts(osNode.intgBridge()).stream()
452 .anyMatch(port -> Objects.equals(
453 port.annotations().value(PORT_NAME), intf) &&
454 port.isEnabled());
Hyunsun Moon0d457362017-06-27 17:19:41 +0900455 }
456
Daniel Park4b24cec2018-11-28 19:21:25 +0900457
458 private boolean initStateDone(OpenstackNode osNode) {
459 if (!isOvsdbConnected(osNode, ovsdbPortNum, ovsdbController, deviceService)) {
460 return false;
461 }
462
463 boolean initStateDone = deviceService.isAvailable(osNode.intgBridge());
464 if (hasDpdkTunnelBridge(osNode)) {
465 initStateDone = initStateDone && dpdkTunnelBridgeCreated(osNode);
466 }
467
468 return initStateDone;
469 }
470
471 private boolean deviceCreatedStateDone(OpenstackNode osNode) {
472 if (osNode.dataIp() != null &&
473 !isIntfEnabled(osNode, VXLAN_TUNNEL)) {
474 return false;
475 }
476 if (osNode.dataIp() != null &&
477 !isIntfEnabled(osNode, GRE_TUNNEL)) {
478 return false;
479 }
480 if (osNode.dataIp() != null &&
481 !isIntfEnabled(osNode, GENEVE_TUNNEL)) {
482 return false;
483 }
484 if (osNode.vlanIntf() != null &&
485 !isIntfEnabled(osNode, osNode.vlanIntf())) {
486 return false;
487 }
488 if (osNode.type() == GATEWAY &&
489 !isIntfEnabled(osNode, osNode.uplinkPort())) {
490 return false;
491 }
492 if (osNode.dpdkConfig() != null &&
493 osNode.dpdkConfig().dpdkIntfs() != null &&
494 !isDpdkIntfsCreated(osNode, osNode.dpdkConfig().dpdkIntfs())) {
495 return false;
496 }
497
498 for (OpenstackPhyInterface intf : osNode.phyIntfs()) {
499 if (intf != null && !isIntfEnabled(osNode, intf.intf())) {
500 return false;
501 }
502 }
503
504 return true;
505 }
506
507
Jian Li340165f2018-02-27 10:38:17 +0900508 /**
509 * Checks whether all requirements for this state are fulfilled or not.
510 *
511 * @param osNode openstack node
512 * @return true if all requirements are fulfilled, false otherwise
513 */
Hyunsun Moon0d457362017-06-27 17:19:41 +0900514 private boolean isCurrentStateDone(OpenstackNode osNode) {
515 switch (osNode.state()) {
516 case INIT:
Daniel Park4b24cec2018-11-28 19:21:25 +0900517 return initStateDone(osNode);
Hyunsun Moon0d457362017-06-27 17:19:41 +0900518 case DEVICE_CREATED:
Daniel Park4b24cec2018-11-28 19:21:25 +0900519 return deviceCreatedStateDone(osNode);
Hyunsun Moon0d457362017-06-27 17:19:41 +0900520 case COMPLETE:
Hyunsun Moon0d457362017-06-27 17:19:41 +0900521 case INCOMPLETE:
522 // always return false
523 // run init CLI to re-trigger node bootstrap
524 return false;
525 default:
526 return true;
527 }
528 }
529
Jian Li40888bf2018-11-21 09:46:32 +0900530 private boolean isDpdkIntfsCreated(OpenstackNode osNode,
531 Collection<DpdkInterface> dpdkInterfaces) {
Ray Milkey8e406512018-10-24 15:56:50 -0700532 OvsdbClientService client = getOvsdbClient(osNode, ovsdbPortNum, ovsdbController);
Daniel Parke2658ba2018-08-24 22:33:29 +0900533 if (client == null) {
534 log.info("Failed to get ovsdb client");
535 return false;
536 }
537
538 Set<OvsdbPort> ports = client.getPorts();
539
Jian Li5ecfd1a2018-12-10 11:41:03 +0900540 for (DpdkInterface dpdkIntf : dpdkInterfaces) {
Daniel Parke2658ba2018-08-24 22:33:29 +0900541 Optional<OvsdbPort> port = ports.stream()
Jian Li5ecfd1a2018-12-10 11:41:03 +0900542 .filter(ovsdbPort -> ovsdbPort.portName().value().equals(dpdkIntf.intf()))
Daniel Parke2658ba2018-08-24 22:33:29 +0900543 .findAny();
544
545 if (!port.isPresent()) {
546 return false;
547 }
Jian Li5ecfd1a2018-12-10 11:41:03 +0900548 Interface intf = client.getInterface(dpdkIntf.intf());
Daniel Parke2658ba2018-08-24 22:33:29 +0900549 if (intf == null) {
550 return false;
551 }
552
553 OvsdbSet mtu = (OvsdbSet) intf.getMtuColumn().data();
554 if (mtu == null) {
555 return false;
556 }
557
558 OvsdbMap option = (OvsdbMap) intf.getOptionsColumn().data();
559 if (option == null) {
560 return false;
561 }
562
Jian Li5ecfd1a2018-12-10 11:41:03 +0900563 if (!mtu.set().contains(dpdkIntf.mtu().intValue()) ||
564 !option.toString().contains(dpdkIntf.pciAddress())) {
Jian Li40888bf2018-11-21 09:46:32 +0900565 log.trace("The dpdk interface {} was created but mtu or " +
566 "pci address is different from the config.");
Daniel Parke2658ba2018-08-24 22:33:29 +0900567 return false;
568 }
569 }
570 return true;
571 }
572
Jian Li340165f2018-02-27 10:38:17 +0900573 /**
574 * Configures the openstack node with new state.
575 *
576 * @param osNode openstack node
577 * @param newState a new state
578 */
Hyunsun Moon0d457362017-06-27 17:19:41 +0900579 private void setState(OpenstackNode osNode, NodeState newState) {
580 if (osNode.state() == newState) {
581 return;
582 }
583 OpenstackNode updated = osNode.updateState(newState);
584 osNodeAdminService.updateNode(updated);
585 log.info("Changed {} state: {}", osNode.hostname(), newState);
586 }
587
Jian Li340165f2018-02-27 10:38:17 +0900588 /**
589 * Bootstraps a new openstack node.
590 *
591 * @param osNode openstack node
592 */
Hyunsun Moon0d457362017-06-27 17:19:41 +0900593 private void bootstrapNode(OpenstackNode osNode) {
Jian Li51b844c2018-05-31 10:59:03 +0900594 if (osNode.type() == CONTROLLER) {
595 if (osNode.state() == INIT && checkEndpoint(osNode)) {
596 setState(osNode, COMPLETE);
597 }
Hyunsun Moon0d457362017-06-27 17:19:41 +0900598 } else {
Jian Li51b844c2018-05-31 10:59:03 +0900599 if (isCurrentStateDone(osNode)) {
600 setState(osNode, osNode.state().nextState());
601 } else {
Jian Li97482c12018-07-03 01:08:23 +0900602 log.trace("Processing {} state for {}", osNode.state(),
603 osNode.hostname());
Jian Li51b844c2018-05-31 10:59:03 +0900604 osNode.state().process(this, osNode);
605 }
606 }
607 }
608
Daniel Park5a6a7102018-09-06 23:58:33 +0900609 private void removeVlanInterface(OpenstackNode osNode) {
610 if (osNode.vlanIntf() != null) {
Jian Li5ecfd1a2018-12-10 11:41:03 +0900611 Optional<DpdkInterface> dpdkIntf =
612 dpdkInterfaceByIntfName(osNode, osNode.vlanIntf());
Daniel Park5a6a7102018-09-06 23:58:33 +0900613
Jian Li5ecfd1a2018-12-10 11:41:03 +0900614 removeInterfaceOnIntegrationBridge(osNode, osNode.vlanIntf(), dpdkIntf);
Daniel Park5a6a7102018-09-06 23:58:33 +0900615 }
616 }
617
618 private void removePhysicalInterface(OpenstackNode osNode) {
619 osNode.phyIntfs().forEach(phyIntf -> {
Jian Li5ecfd1a2018-12-10 11:41:03 +0900620 Optional<DpdkInterface> dpdkIntf = dpdkInterfaceByIntfName(osNode, phyIntf.intf());
Daniel Park5a6a7102018-09-06 23:58:33 +0900621
Jian Li5ecfd1a2018-12-10 11:41:03 +0900622 removeInterfaceOnIntegrationBridge(osNode, phyIntf.intf(), dpdkIntf);
Daniel Park5a6a7102018-09-06 23:58:33 +0900623 });
624 }
625
Jian Li5ecfd1a2018-12-10 11:41:03 +0900626 private Optional<DpdkInterface> dpdkInterfaceByIntfName(OpenstackNode osNode,
627 String intf) {
Daniel Park5a6a7102018-09-06 23:58:33 +0900628 return osNode.dpdkConfig() == null ? Optional.empty() :
629 osNode.dpdkConfig().dpdkIntfs().stream()
630 .filter(dpdkIntf -> dpdkIntf.intf().equals(intf))
631 .findAny();
632 }
633
634 private void removeInterfaceOnIntegrationBridge(OpenstackNode osNode,
635 String intfName,
636 Optional<DpdkInterface> dpdkInterface) {
637 if (dpdkInterface.isPresent()) {
Ray Milkey8e406512018-10-24 15:56:50 -0700638 addOrRemoveDpdkInterface(osNode, dpdkInterface.get(), ovsdbPortNum,
Daniel Park5a6a7102018-09-06 23:58:33 +0900639 ovsdbController, false);
640 } else {
641 addOrRemoveSystemInterface(osNode, INTEGRATION_BRIDGE, intfName, deviceService,
642 false);
643 }
644 }
645
Jian Li51b844c2018-05-31 10:59:03 +0900646 /**
647 * Checks the validity of the given endpoint.
648 *
649 * @param osNode gateway node
650 * @return validity result
651 */
652 private boolean checkEndpoint(OpenstackNode osNode) {
653 if (osNode == null) {
654 log.warn("Keystone auth info has not been configured. " +
655 "Please specify auth info via network-cfg.json.");
656 return false;
657 }
658
659 OSClient client = getConnectedClient(osNode);
660
661 if (client == null) {
662 return false;
663 } else {
664 return client.getSupportedServices().size() != 0;
Hyunsun Moon0d457362017-06-27 17:19:41 +0900665 }
666 }
667
Jian Li340165f2018-02-27 10:38:17 +0900668 /**
Jian Li97482c12018-07-03 01:08:23 +0900669 * Extracts properties from the component configuration context.
670 *
671 * @param context the component context
672 */
673 private void readComponentConfiguration(ComponentContext context) {
674 Dictionary<?, ?> properties = context.getProperties();
675
676 Integer ovsdbPortConfigured = Tools.getIntegerProperty(properties, OVSDB_PORT);
677 if (ovsdbPortConfigured == null) {
Ray Milkey8e406512018-10-24 15:56:50 -0700678 ovsdbPortNum = OVSDB_PORT_NUM_DEFAULT;
679 log.info("OVSDB port is NOT configured, default value is {}", ovsdbPortNum);
Jian Li97482c12018-07-03 01:08:23 +0900680 } else {
Ray Milkey8e406512018-10-24 15:56:50 -0700681 ovsdbPortNum = ovsdbPortConfigured;
682 log.info("Configured. OVSDB port is {}", ovsdbPortNum);
Jian Li97482c12018-07-03 01:08:23 +0900683 }
684
685 Boolean autoRecoveryConfigured =
686 getBooleanProperty(properties, AUTO_RECOVERY);
687 if (autoRecoveryConfigured == null) {
Ray Milkey8e406512018-10-24 15:56:50 -0700688 autoRecovery = AUTO_RECOVERY_DEFAULT;
Jian Li97482c12018-07-03 01:08:23 +0900689 log.info("Auto recovery flag is NOT " +
690 "configured, default value is {}", autoRecovery);
691 } else {
692 autoRecovery = autoRecoveryConfigured;
693 log.info("Configured. Auto recovery flag is {}", autoRecovery);
694 }
695 }
696
697 /**
Jian Li340165f2018-02-27 10:38:17 +0900698 * An internal OVSDB listener. This listener is used for listening the
699 * network facing events from OVSDB device. If a new OVSDB device is detected,
700 * ONOS tries to bootstrap the openstack node.
701 */
Hyunsun Moon0d457362017-06-27 17:19:41 +0900702 private class InternalOvsdbListener implements DeviceListener {
703
704 @Override
705 public boolean isRelevant(DeviceEvent event) {
Jian Li40888bf2018-11-21 09:46:32 +0900706 return event.subject().type() == Device.Type.CONTROLLER;
707 }
708
709 private boolean isRelevantHelper() {
710 return Objects.equals(localNode, leadershipService.getLeader(appId.name()));
Hyunsun Moon0d457362017-06-27 17:19:41 +0900711 }
712
713 @Override
714 public void event(DeviceEvent event) {
715 Device device = event.subject();
Hyunsun Moon0d457362017-06-27 17:19:41 +0900716
717 switch (event.type()) {
718 case DEVICE_AVAILABILITY_CHANGED:
719 case DEVICE_ADDED:
720 eventExecutor.execute(() -> {
Jian Li40888bf2018-11-21 09:46:32 +0900721 if (!isRelevantHelper()) {
722 return;
723 }
Daniel Park4b24cec2018-11-28 19:21:25 +0900724 processDeviceAddedOfOvsdbDevice(osNodeService.node(device.id()), device);
Hyunsun Moon0d457362017-06-27 17:19:41 +0900725 });
726 break;
727 case PORT_ADDED:
728 case PORT_REMOVED:
729 case DEVICE_REMOVED:
730 default:
731 // do nothing
732 break;
733 }
734 }
Daniel Park4b24cec2018-11-28 19:21:25 +0900735
736 private void processDeviceAddedOfOvsdbDevice(OpenstackNode osNode, Device device) {
737 if (osNode == null || osNode.type() == CONTROLLER) {
738 return;
739 }
740
741 if (deviceService.isAvailable(device.id())) {
742 log.debug("OVSDB {} detected", device.id());
743 bootstrapNode(osNode);
744 }
745 }
Hyunsun Moon0d457362017-06-27 17:19:41 +0900746 }
747
Jian Li340165f2018-02-27 10:38:17 +0900748 /**
749 * An internal integration bridge listener. This listener is used for
750 * listening the events from integration bridge. To listen the events from
751 * other types of bridge such as provider bridge or tunnel bridge, we need
752 * to augment OpenstackNodeService.node() method.
753 */
Hyunsun Moon0d457362017-06-27 17:19:41 +0900754 private class InternalBridgeListener implements DeviceListener {
755
756 @Override
757 public boolean isRelevant(DeviceEvent event) {
Jian Li40888bf2018-11-21 09:46:32 +0900758 return event.subject().type() == Device.Type.SWITCH;
759 }
760
761 private boolean isRelevantHelper() {
762 return Objects.equals(localNode, leadershipService.getLeader(appId.name()));
Hyunsun Moon0d457362017-06-27 17:19:41 +0900763 }
764
765 @Override
766 public void event(DeviceEvent event) {
767 Device device = event.subject();
Hyunsun Moon0d457362017-06-27 17:19:41 +0900768
769 switch (event.type()) {
770 case DEVICE_AVAILABILITY_CHANGED:
771 case DEVICE_ADDED:
772 eventExecutor.execute(() -> {
Jian Li40888bf2018-11-21 09:46:32 +0900773 if (!isRelevantHelper()) {
774 return;
775 }
Daniel Park4b24cec2018-11-28 19:21:25 +0900776 processDeviceAddedOfBridge(osNodeService.node(device.id()), device);
Hyunsun Moon0d457362017-06-27 17:19:41 +0900777 });
778 break;
Daniel Park5a6a7102018-09-06 23:58:33 +0900779 case PORT_UPDATED:
Hyunsun Moon0d457362017-06-27 17:19:41 +0900780 case PORT_ADDED:
781 eventExecutor.execute(() -> {
Jian Li40888bf2018-11-21 09:46:32 +0900782 if (!isRelevantHelper()) {
783 return;
784 }
Daniel Park4b24cec2018-11-28 19:21:25 +0900785 processPortAddedOfBridge(osNodeService.node(device.id()), event.port());
Hyunsun Moon0d457362017-06-27 17:19:41 +0900786 });
787 break;
788 case PORT_REMOVED:
789 eventExecutor.execute(() -> {
Jian Li40888bf2018-11-21 09:46:32 +0900790 if (!isRelevantHelper()) {
791 return;
792 }
Daniel Park4b24cec2018-11-28 19:21:25 +0900793 processPortRemovedOfBridge(osNodeService.node(device.id()), event.port());
Hyunsun Moon0d457362017-06-27 17:19:41 +0900794 });
795 break;
Hyunsun Moon0d457362017-06-27 17:19:41 +0900796 case DEVICE_REMOVED:
797 default:
798 // do nothing
799 break;
800 }
801 }
Hyunsun Moon0d457362017-06-27 17:19:41 +0900802
Daniel Park4b24cec2018-11-28 19:21:25 +0900803 private void processDeviceAddedOfBridge(OpenstackNode osNode, Device device) {
Jian Lie6312162018-03-21 21:41:00 +0900804
Daniel Park4b24cec2018-11-28 19:21:25 +0900805 if (osNode == null || osNode.type() == CONTROLLER) {
806 return;
807 }
808
809 if (deviceService.isAvailable(device.id())) {
810 log.debug("Integration bridge created on {}", osNode.hostname());
811 bootstrapNode(osNode);
812 } else if (osNode.state() == COMPLETE) {
813 log.info("Device {} disconnected", device.id());
814 setState(osNode, INCOMPLETE);
815 }
816
817 if (autoRecovery) {
818 if (osNode.state() == INCOMPLETE ||
819 osNode.state() == DEVICE_CREATED) {
820 log.info("Device {} is reconnected", device.id());
821 osNodeAdminService.updateNode(
822 osNode.updateState(NodeState.INIT));
823 }
824 }
Daniel Park5a6a7102018-09-06 23:58:33 +0900825 }
Daniel Park4b24cec2018-11-28 19:21:25 +0900826
827 private void processPortAddedOfBridge(OpenstackNode osNode, Port port) {
828 if (osNode == null || osNode.type() == CONTROLLER) {
829 return;
830 }
831
832 String portName = port.annotations().value(PORT_NAME);
833 if (osNode.state() == DEVICE_CREATED && (
834 Objects.equals(portName, VXLAN_TUNNEL) ||
835 Objects.equals(portName, GRE_TUNNEL) ||
836 Objects.equals(portName, GENEVE_TUNNEL) ||
837 Objects.equals(portName, osNode.vlanIntf()) ||
838 Objects.equals(portName, osNode.uplinkPort()) ||
839 containsPhyIntf(osNode, portName)) ||
840 containsDpdkIntfs(osNode, portName)) {
841 log.info("Interface {} added or updated to {}",
842 portName, osNode.intgBridge());
843 bootstrapNode(osNode);
844 }
845 }
846
847 private void processPortRemovedOfBridge(OpenstackNode osNode, Port port) {
848 if (osNode == null || osNode.type() == CONTROLLER) {
849 return;
850 }
851
852 String portName = port.annotations().value(PORT_NAME);
853 if (osNode.state() == COMPLETE && (
854 Objects.equals(portName, VXLAN_TUNNEL) ||
855 Objects.equals(portName, GRE_TUNNEL) ||
856 Objects.equals(portName, GENEVE_TUNNEL) ||
857 Objects.equals(portName, osNode.vlanIntf()) ||
858 Objects.equals(portName, osNode.uplinkPort()) ||
859 containsPhyIntf(osNode, portName)) ||
860 containsDpdkIntfs(osNode, portName)) {
861 log.warn("Interface {} removed from {}",
862 portName, osNode.intgBridge());
863 setState(osNode, INCOMPLETE);
864 }
865 }
866
867
868 /**
869 * Checks whether the openstack node contains the given physical interface.
870 *
871 * @param osNode openstack node
872 * @param portName physical interface
873 * @return true if openstack node contains the given physical interface,
874 * false otherwise
875 */
876 private boolean containsPhyIntf(OpenstackNode osNode, String portName) {
877 return osNode.phyIntfs().stream()
878 .anyMatch(phyInterface -> phyInterface.intf().equals(portName));
879 }
880
881 /**
882 * Checks whether the openstack node contains the given dpdk interface.
883 *
884 * @param osNode openstack node
885 * @param portName dpdk interface
886 * @return true if openstack node contains the given dpdk interface,
887 * false otherwise
888 */
889 private boolean containsDpdkIntfs(OpenstackNode osNode, String portName) {
890 if (osNode.dpdkConfig() == null) {
891 return false;
892 }
893 return osNode.dpdkConfig().dpdkIntfs().stream()
894 .anyMatch(dpdkInterface -> dpdkInterface.intf().equals(portName));
895 }
Jian Lie6312162018-03-21 21:41:00 +0900896 }
897
Daniel Park4b24cec2018-11-28 19:21:25 +0900898
Jian Lie6312162018-03-21 21:41:00 +0900899 /**
Jian Li340165f2018-02-27 10:38:17 +0900900 * An internal openstack node listener.
901 * The notification is triggered by OpenstackNodeStore.
902 */
Hyunsun Moon0d457362017-06-27 17:19:41 +0900903 private class InternalOpenstackNodeListener implements OpenstackNodeListener {
904
Jian Li40888bf2018-11-21 09:46:32 +0900905 private boolean isRelevantHelper() {
906 return Objects.equals(localNode, leadershipService.getLeader(appId.name()));
Hyunsun Moon0d457362017-06-27 17:19:41 +0900907 }
908
909 @Override
910 public void event(OpenstackNodeEvent event) {
911 switch (event.type()) {
912 case OPENSTACK_NODE_CREATED:
913 case OPENSTACK_NODE_UPDATED:
Jian Li40888bf2018-11-21 09:46:32 +0900914 eventExecutor.execute(() -> {
915
916 if (!isRelevantHelper()) {
917 return;
918 }
919
920 bootstrapNode(event.subject());
921 });
Hyunsun Moon0d457362017-06-27 17:19:41 +0900922 break;
923 case OPENSTACK_NODE_REMOVED:
Jian Li40888bf2018-11-21 09:46:32 +0900924 eventExecutor.execute(() -> {
925
926 if (!isRelevantHelper()) {
927 return;
928 }
Jian Li40888bf2018-11-21 09:46:32 +0900929 processOpenstackNodeRemoved(event.subject());
930 });
Hyunsun Moon0d457362017-06-27 17:19:41 +0900931 break;
Jian Li40888bf2018-11-21 09:46:32 +0900932 case OPENSTACK_NODE_COMPLETE:
Hyunsun Moon0d457362017-06-27 17:19:41 +0900933 default:
934 break;
935 }
936 }
Daniel Park4b24cec2018-11-28 19:21:25 +0900937
938 private void processOpenstackNodeRemoved(OpenstackNode osNode) {
939 OvsdbClientService client = getOvsdbClient(osNode, ovsdbPortNum, ovsdbController);
940 if (client == null) {
941 log.info("Failed to get ovsdb client");
942 return;
943 }
944
945 //delete physical interfaces from the node
946 removePhysicalInterface(osNode);
947
948 //delete vlan interface from the node
949 removeVlanInterface(osNode);
950
951 //delete dpdk interfaces from the node
952 if (osNode.dpdkConfig() != null) {
953 osNode.dpdkConfig().dpdkIntfs().forEach(dpdkInterface -> {
954 if (isDpdkIntfsCreated(osNode, Lists.newArrayList(dpdkInterface))) {
955 addOrRemoveDpdkInterface(osNode, dpdkInterface, ovsdbPortNum,
956 ovsdbController, false);
957 }
958 });
959 }
960
961 //delete tunnel bridge from the node
962 if (hasDpdkTunnelBridge(osNode)) {
963 client.dropBridge(TUNNEL_BRIDGE);
964 }
965
966 //delete integration bridge from the node
967 client.dropBridge(INTEGRATION_BRIDGE);
968
969 //disconnect ovsdb
970 client.disconnect();
971 }
Hyunsun Moon0d457362017-06-27 17:19:41 +0900972 }
973}