blob: c6e939549ab2e538603663c9429672fde65754a6 [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;
Jian Li2d68c192018-12-13 15:52:59 +090060import org.openstack4j.model.network.NetworkType;
Hyunsun Moon0d457362017-06-27 17:19:41 +090061import org.osgi.service.component.ComponentContext;
Ray Milkeyd84f89b2018-08-17 14:54:17 -070062import org.osgi.service.component.annotations.Activate;
63import org.osgi.service.component.annotations.Component;
64import org.osgi.service.component.annotations.Deactivate;
65import org.osgi.service.component.annotations.Modified;
66import org.osgi.service.component.annotations.Reference;
67import org.osgi.service.component.annotations.ReferenceCardinality;
Hyunsun Moon0d457362017-06-27 17:19:41 +090068import org.slf4j.Logger;
69
Daniel Parke2658ba2018-08-24 22:33:29 +090070import java.util.Collection;
Hyunsun Moon0d457362017-06-27 17:19:41 +090071import java.util.Dictionary;
72import java.util.List;
73import java.util.Objects;
Daniel Parke2658ba2018-08-24 22:33:29 +090074import java.util.Optional;
Hyunsun Moon0d457362017-06-27 17:19:41 +090075import java.util.Set;
76import java.util.concurrent.ExecutorService;
77import java.util.stream.Collectors;
78
Hyunsun Moon0d457362017-06-27 17:19:41 +090079import static java.util.concurrent.Executors.newSingleThreadExecutor;
80import static org.onlab.packet.TpPort.tpPort;
81import static org.onlab.util.Tools.groupedThreads;
82import static org.onosproject.net.AnnotationKeys.PORT_NAME;
Jian Li2d68c192018-12-13 15:52:59 +090083import static org.onosproject.openstacknode.api.Constants.GRE_TUNNEL;
84import static org.onosproject.openstacknode.api.Constants.VXLAN_TUNNEL;
Jian Li5afbea42018-02-28 10:37:03 +090085import static org.onosproject.openstacknode.api.Constants.INTEGRATION_BRIDGE;
Daniel Parke2658ba2018-08-24 22:33:29 +090086import static org.onosproject.openstacknode.api.Constants.TUNNEL_BRIDGE;
Daniel Parkd02d7bd2018-08-23 23:04:31 +090087import static org.onosproject.openstacknode.api.DpdkConfig.DatapathType.NETDEV;
Jian Li5afbea42018-02-28 10:37:03 +090088import static org.onosproject.openstacknode.api.NodeState.COMPLETE;
89import static org.onosproject.openstacknode.api.NodeState.DEVICE_CREATED;
90import static org.onosproject.openstacknode.api.NodeState.INCOMPLETE;
Jian Li51b844c2018-05-31 10:59:03 +090091import static org.onosproject.openstacknode.api.NodeState.INIT;
92import static org.onosproject.openstacknode.api.OpenstackNode.NodeType.CONTROLLER;
Hyunsun Moon0d457362017-06-27 17:19:41 +090093import static org.onosproject.openstacknode.api.OpenstackNode.NodeType.GATEWAY;
94import static org.onosproject.openstacknode.api.OpenstackNodeService.APP_ID;
Ray Milkey8e406512018-10-24 15:56:50 -070095import static org.onosproject.openstacknode.impl.OsgiPropertyConstants.AUTO_RECOVERY;
96import static org.onosproject.openstacknode.impl.OsgiPropertyConstants.AUTO_RECOVERY_DEFAULT;
97import static org.onosproject.openstacknode.impl.OsgiPropertyConstants.OVSDB_PORT;
98import static org.onosproject.openstacknode.impl.OsgiPropertyConstants.OVSDB_PORT_NUM_DEFAULT;
Daniel Park5a6a7102018-09-06 23:58:33 +090099import static org.onosproject.openstacknode.util.OpenstackNodeUtil.addOrRemoveDpdkInterface;
100import static org.onosproject.openstacknode.util.OpenstackNodeUtil.addOrRemoveSystemInterface;
Jian Li97482c12018-07-03 01:08:23 +0900101import static org.onosproject.openstacknode.util.OpenstackNodeUtil.getBooleanProperty;
Jian Li51b844c2018-05-31 10:59:03 +0900102import static org.onosproject.openstacknode.util.OpenstackNodeUtil.getConnectedClient;
Daniel Parke2658ba2018-08-24 22:33:29 +0900103import static org.onosproject.openstacknode.util.OpenstackNodeUtil.getOvsdbClient;
Daniel Parkc4d06402018-05-28 15:57:37 +0900104import static org.onosproject.openstacknode.util.OpenstackNodeUtil.isOvsdbConnected;
Hyunsun Moon0d457362017-06-27 17:19:41 +0900105import static org.slf4j.LoggerFactory.getLogger;
106
107/**
108 * Service bootstraps openstack node based on its type.
109 */
Ray Milkey8e406512018-10-24 15:56:50 -0700110@Component(immediate = true,
111 property = {
112 OVSDB_PORT + ":Integer=" + OVSDB_PORT_NUM_DEFAULT,
113 AUTO_RECOVERY + ":Boolean=" + AUTO_RECOVERY_DEFAULT
114 }
115)
Hyunsun Moon0d457362017-06-27 17:19:41 +0900116public class DefaultOpenstackNodeHandler implements OpenstackNodeHandler {
117
Jian Li5afbea42018-02-28 10:37:03 +0900118 private final Logger log = getLogger(getClass());
Hyunsun Moon0d457362017-06-27 17:19:41 +0900119
Hyunsun Moon0d457362017-06-27 17:19:41 +0900120 private static final String DEFAULT_OF_PROTO = "tcp";
121 private static final int DEFAULT_OFPORT = 6653;
122 private static final int DPID_BEGIN = 3;
123
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700124 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Hyunsun Moon0d457362017-06-27 17:19:41 +0900125 protected CoreService coreService;
126
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700127 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Hyunsun Moon0d457362017-06-27 17:19:41 +0900128 protected LeadershipService leadershipService;
129
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700130 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Hyunsun Moon0d457362017-06-27 17:19:41 +0900131 protected ClusterService clusterService;
132
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700133 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Hyunsun Moon0d457362017-06-27 17:19:41 +0900134 protected DeviceService deviceService;
135
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700136 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Hyunsun Moon0d457362017-06-27 17:19:41 +0900137 protected DeviceAdminService deviceAdminService;
138
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700139 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Hyunsun Moon0d457362017-06-27 17:19:41 +0900140 protected OvsdbController ovsdbController;
141
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700142 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Hyunsun Moon0d457362017-06-27 17:19:41 +0900143 protected OpenstackNodeService osNodeService;
144
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700145 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Hyunsun Moon0d457362017-06-27 17:19:41 +0900146 protected OpenstackNodeAdminService osNodeAdminService;
147
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700148 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Hyunsun Moon0d457362017-06-27 17:19:41 +0900149 protected ComponentConfigService componentConfigService;
150
Ray Milkey8e406512018-10-24 15:56:50 -0700151 /** OVSDB server listen port. */
152 private int ovsdbPortNum = OVSDB_PORT_NUM_DEFAULT;
Hyunsun Moon0d457362017-06-27 17:19:41 +0900153
Jian Li900b7232018-12-14 14:04:51 +0900154 /** Indicates whether auto-recover openstack node status on switch re-conn event. */
Ray Milkey8e406512018-10-24 15:56:50 -0700155 private boolean autoRecovery = AUTO_RECOVERY_DEFAULT;
Jian Li97482c12018-07-03 01:08:23 +0900156
Hyunsun Moon0d457362017-06-27 17:19:41 +0900157 private final ExecutorService eventExecutor = newSingleThreadExecutor(
158 groupedThreads(this.getClass().getSimpleName(), "event-handler", log));
159
160 private final DeviceListener ovsdbListener = new InternalOvsdbListener();
161 private final DeviceListener bridgeListener = new InternalBridgeListener();
Hyunsun Moon0d457362017-06-27 17:19:41 +0900162 private final OpenstackNodeListener osNodeListener = new InternalOpenstackNodeListener();
163
164 private ApplicationId appId;
165 private NodeId localNode;
166
167 @Activate
168 protected void activate() {
169 appId = coreService.getAppId(APP_ID);
170 localNode = clusterService.getLocalNode().id();
171
172 componentConfigService.registerProperties(getClass());
173 leadershipService.runForLeadership(appId.name());
Hyunsun Moon0d457362017-06-27 17:19:41 +0900174 deviceService.addListener(ovsdbListener);
175 deviceService.addListener(bridgeListener);
176 osNodeService.addListener(osNodeListener);
177
178 log.info("Started");
179 }
180
181 @Deactivate
182 protected void deactivate() {
183 osNodeService.removeListener(osNodeListener);
184 deviceService.removeListener(bridgeListener);
185 deviceService.removeListener(ovsdbListener);
Hyunsun Moon0d457362017-06-27 17:19:41 +0900186 componentConfigService.unregisterProperties(getClass(), false);
187 leadershipService.withdraw(appId.name());
188 eventExecutor.shutdown();
189
190 log.info("Stopped");
191 }
192
193 @Modified
194 protected void modified(ComponentContext context) {
Jian Li97482c12018-07-03 01:08:23 +0900195 readComponentConfiguration(context);
Hyunsun Moon0d457362017-06-27 17:19:41 +0900196
197 log.info("Modified");
198 }
199
200 @Override
201 public void processInitState(OpenstackNode osNode) {
Ray Milkey8e406512018-10-24 15:56:50 -0700202 if (!isOvsdbConnected(osNode, ovsdbPortNum, ovsdbController, deviceService)) {
203 ovsdbController.connect(osNode.managementIp(), tpPort(ovsdbPortNum));
Hyunsun Moon0d457362017-06-27 17:19:41 +0900204 return;
205 }
206 if (!deviceService.isAvailable(osNode.intgBridge())) {
207 createBridge(osNode, INTEGRATION_BRIDGE, osNode.intgBridge());
208 }
Daniel Parke2658ba2018-08-24 22:33:29 +0900209 if (hasDpdkTunnelBridge(osNode)) {
210 createDpdkTunnelBridge(osNode);
211 }
Hyunsun Moon0d457362017-06-27 17:19:41 +0900212 }
213
214 @Override
215 public void processDeviceCreatedState(OpenstackNode osNode) {
daniel parkb18424c2018-02-05 15:43:43 +0900216 try {
Ray Milkey8e406512018-10-24 15:56:50 -0700217 if (!isOvsdbConnected(osNode, ovsdbPortNum, ovsdbController, deviceService)) {
218 ovsdbController.connect(osNode.managementIp(), tpPort(ovsdbPortNum));
daniel parkb18424c2018-02-05 15:43:43 +0900219 return;
220 }
Hyunsun Moon0d457362017-06-27 17:19:41 +0900221
daniel parkb18424c2018-02-05 15:43:43 +0900222 if (osNode.type() == GATEWAY) {
Jian Li97482c12018-07-03 01:08:23 +0900223 addOrRemoveSystemInterface(osNode, INTEGRATION_BRIDGE,
Daniel Park5a6a7102018-09-06 23:58:33 +0900224 osNode.uplinkPort(), deviceService, true);
daniel parkb18424c2018-02-05 15:43:43 +0900225 }
226
227 if (osNode.dataIp() != null &&
Jian Li2d68c192018-12-13 15:52:59 +0900228 !isIntfEnabled(osNode, VXLAN_TUNNEL)) {
229 createVxlanTunnelInterface(osNode);
230 }
231
232 if (osNode.dataIp() != null &&
233 !isIntfEnabled(osNode, GRE_TUNNEL)) {
234 createGreTunnelInterface(osNode);
daniel parkb18424c2018-02-05 15:43:43 +0900235 }
236
Daniel Parke2658ba2018-08-24 22:33:29 +0900237 if (osNode.dpdkConfig() != null && osNode.dpdkConfig().dpdkIntfs() != null) {
Daniel Park5a6a7102018-09-06 23:58:33 +0900238 osNode.dpdkConfig().dpdkIntfs().stream()
Jian Li5ecfd1a2018-12-10 11:41:03 +0900239 .filter(dpdkintf -> dpdkintf.deviceName().equals(TUNNEL_BRIDGE))
240 .forEach(dpdkintf -> addOrRemoveDpdkInterface(
241 osNode, dpdkintf, ovsdbPortNum, ovsdbController, true));
Daniel Park5a6a7102018-09-06 23:58:33 +0900242
243 osNode.dpdkConfig().dpdkIntfs().stream()
Jian Li5ecfd1a2018-12-10 11:41:03 +0900244 .filter(dpdkintf -> dpdkintf.deviceName().equals(INTEGRATION_BRIDGE))
245 .forEach(dpdkintf -> addOrRemoveDpdkInterface(
246 osNode, dpdkintf, ovsdbPortNum, ovsdbController, true));
Daniel Parke2658ba2018-08-24 22:33:29 +0900247 }
248
Jian Lie6312162018-03-21 21:41:00 +0900249 osNode.phyIntfs().forEach(i -> {
250 if (!isIntfEnabled(osNode, i.intf())) {
Jian Li97482c12018-07-03 01:08:23 +0900251 addOrRemoveSystemInterface(osNode, INTEGRATION_BRIDGE,
Daniel Park5a6a7102018-09-06 23:58:33 +0900252 i.intf(), deviceService, true);
Jian Lie6312162018-03-21 21:41:00 +0900253 }
254 });
255
Daniel Park5a6a7102018-09-06 23:58:33 +0900256 if (osNode.vlanIntf() != null &&
257 !isIntfEnabled(osNode, osNode.vlanIntf())) {
258 addOrRemoveSystemInterface(osNode, INTEGRATION_BRIDGE,
Jian Li5ecfd1a2018-12-10 11:41:03 +0900259 osNode.vlanIntf(), deviceService, true);
Daniel Park5a6a7102018-09-06 23:58:33 +0900260 }
daniel parkb18424c2018-02-05 15:43:43 +0900261 } catch (Exception e) {
Jian Li340165f2018-02-27 10:38:17 +0900262 log.error("Exception occurred because of {}", e.toString());
Hyunsun Moon0d457362017-06-27 17:19:41 +0900263 }
264 }
265
266 @Override
267 public void processCompleteState(OpenstackNode osNode) {
Daniel Parkc4d06402018-05-28 15:57:37 +0900268 //Do something if needed
Hyunsun Moon0d457362017-06-27 17:19:41 +0900269 }
270
271 @Override
272 public void processIncompleteState(OpenstackNode osNode) {
daniel parkb18424c2018-02-05 15:43:43 +0900273 //TODO
Hyunsun Moon0d457362017-06-27 17:19:41 +0900274 }
275
Daniel Parke2658ba2018-08-24 22:33:29 +0900276 private boolean hasDpdkTunnelBridge(OpenstackNode osNode) {
277 if (osNode.dpdkConfig() != null && osNode.dpdkConfig().dpdkIntfs() != null) {
278 return osNode.dpdkConfig().dpdkIntfs().stream()
279 .anyMatch(intf -> intf.deviceName().equals(TUNNEL_BRIDGE));
280 }
281 return false;
282 }
283
284 private boolean dpdkTunnelBridgeCreated(OpenstackNode osNode) {
285
Ray Milkey8e406512018-10-24 15:56:50 -0700286 OvsdbClientService client = getOvsdbClient(osNode, ovsdbPortNum, ovsdbController);
Daniel Parke2658ba2018-08-24 22:33:29 +0900287 if (client == null) {
288 log.info("Failed to get ovsdb client");
289 return false;
290 }
291
292 return client.getBridges().stream()
293 .anyMatch(bridge -> bridge.name().equals(TUNNEL_BRIDGE));
294 }
295
Jian Li340165f2018-02-27 10:38:17 +0900296 /**
Jian Li340165f2018-02-27 10:38:17 +0900297 * Creates a bridge with a given name on a given openstack node.
298 *
299 * @param osNode openstack node
300 * @param bridgeName bridge name
301 * @param deviceId device identifier
302 */
Hyunsun Moon0d457362017-06-27 17:19:41 +0900303 private void createBridge(OpenstackNode osNode, String bridgeName, DeviceId deviceId) {
304 Device device = deviceService.getDevice(osNode.ovsdb());
Hyunsun Moon0d457362017-06-27 17:19:41 +0900305
Jian Li789fadb2018-07-10 13:59:47 +0900306 List<ControllerInfo> controllers;
307
308 if (osNode.controllers() != null && osNode.controllers().size() > 0) {
309 controllers = (List<ControllerInfo>) osNode.controllers();
310 } else {
311 Set<IpAddress> controllerIps = clusterService.getNodes().stream()
Hyunsun Moon0d457362017-06-27 17:19:41 +0900312 .map(ControllerNode::ip)
313 .collect(Collectors.toSet());
Hyunsun Moon0d457362017-06-27 17:19:41 +0900314
Jian Li789fadb2018-07-10 13:59:47 +0900315 controllers = controllerIps.stream()
316 .map(ip -> new ControllerInfo(ip, DEFAULT_OFPORT, DEFAULT_OF_PROTO))
317 .collect(Collectors.toList());
318 }
Hyunsun Moon0d457362017-06-27 17:19:41 +0900319
320 String dpid = deviceId.toString().substring(DPID_BEGIN);
daniel parkb18424c2018-02-05 15:43:43 +0900321
Daniel Park92abf312018-08-08 17:01:35 +0900322 BridgeDescription.Builder builder = DefaultBridgeDescription.builder()
Hyunsun Moon0d457362017-06-27 17:19:41 +0900323 .name(bridgeName)
324 .failMode(BridgeDescription.FailMode.SECURE)
325 .datapathId(dpid)
326 .disableInBand()
Daniel Park92abf312018-08-08 17:01:35 +0900327 .controllers(controllers);
328
329 if (osNode.datapathType().equals(NETDEV)) {
Daniel Parke2658ba2018-08-24 22:33:29 +0900330 builder.datapathType(NETDEV.name().toLowerCase());
Daniel Park92abf312018-08-08 17:01:35 +0900331 }
Hyunsun Moon0d457362017-06-27 17:19:41 +0900332
333 BridgeConfig bridgeConfig = device.as(BridgeConfig.class);
Daniel Park92abf312018-08-08 17:01:35 +0900334 bridgeConfig.addBridge(builder.build());
Hyunsun Moon0d457362017-06-27 17:19:41 +0900335 }
336
Daniel Parke2658ba2018-08-24 22:33:29 +0900337 private void createDpdkTunnelBridge(OpenstackNode osNode) {
338 Device device = deviceService.getDevice(osNode.ovsdb());
339
340 BridgeDescription.Builder builder = DefaultBridgeDescription.builder()
341 .name(TUNNEL_BRIDGE)
342 .datapathType(NETDEV.name().toLowerCase());
343
344 BridgeConfig bridgeConfig = device.as(BridgeConfig.class);
345 bridgeConfig.addBridge(builder.build());
346 }
347
Jian Li340165f2018-02-27 10:38:17 +0900348 /**
Jian Li2d68c192018-12-13 15:52:59 +0900349 * Creates a VXLAN tunnel interface in a given openstack node.
350 *
351 * @param osNode openstack node
352 */
353 private void createVxlanTunnelInterface(OpenstackNode osNode) {
354 createTunnelInterface(osNode, NetworkType.VXLAN, VXLAN_TUNNEL);
355 }
356
357 /**
358 * Creates a GRE tunnel interface in a given openstack node.
359 *
360 * @param osNode openstack node
361 */
362 private void createGreTunnelInterface(OpenstackNode osNode) {
363 createTunnelInterface(osNode, NetworkType.GRE, GRE_TUNNEL);
364 }
365
366 /**
Jian Li340165f2018-02-27 10:38:17 +0900367 * Creates a tunnel interface in a given openstack node.
368 *
369 * @param osNode openstack node
370 */
Jian Li2d68c192018-12-13 15:52:59 +0900371 private void createTunnelInterface(OpenstackNode osNode,
372 NetworkType type, String intfName) {
373 if (isIntfEnabled(osNode, intfName)) {
Hyunsun Moon0d457362017-06-27 17:19:41 +0900374 return;
375 }
376
377 Device device = deviceService.getDevice(osNode.ovsdb());
378 if (device == null || !device.is(InterfaceConfig.class)) {
379 log.error("Failed to create tunnel interface on {}", osNode.ovsdb());
380 return;
381 }
382
Jian Li2d68c192018-12-13 15:52:59 +0900383 TunnelDescription tunnelDesc = buildTunnelDesc(type, intfName);
Hyunsun Moon0d457362017-06-27 17:19:41 +0900384
385 InterfaceConfig ifaceConfig = device.as(InterfaceConfig.class);
Jian Li2d68c192018-12-13 15:52:59 +0900386 ifaceConfig.addTunnelMode(intfName, tunnelDesc);
387 }
388
389 /**
390 * Builds tunnel description according to the network type.
391 *
392 * @param type network type
393 * @return tunnel description
394 */
395 private TunnelDescription buildTunnelDesc(NetworkType type, String intfName) {
396 if (type == NetworkType.VXLAN || type == NetworkType.GRE) {
397 TunnelDescription.Builder tdBuilder =
398 DefaultTunnelDescription.builder()
399 .deviceId(INTEGRATION_BRIDGE)
400 .ifaceName(intfName)
401 .remote(TunnelEndPoints.flowTunnelEndpoint())
402 .key(TunnelKeys.flowTunnelKey());
403
404 switch (type) {
405 case VXLAN:
406 tdBuilder.type(TunnelDescription.Type.VXLAN);
407 break;
408 case GRE:
409 tdBuilder.type(TunnelDescription.Type.GRE);
410 break;
411 default:
412 return null;
413 }
414
415 return tdBuilder.build();
416 }
417 return null;
Hyunsun Moon0d457362017-06-27 17:19:41 +0900418 }
419
Jian Li340165f2018-02-27 10:38:17 +0900420 /**
Jian Li5ecfd1a2018-12-10 11:41:03 +0900421 * Checks whether a given network interface in a given openstack node
422 * is enabled or not.
Jian Li340165f2018-02-27 10:38:17 +0900423 *
424 * @param osNode openstack node
425 * @param intf network interface name
426 * @return true if the given interface is enabled, false otherwise
427 */
Hyunsun Moon0d457362017-06-27 17:19:41 +0900428 private boolean isIntfEnabled(OpenstackNode osNode, String intf) {
Jian Li5afbea42018-02-28 10:37:03 +0900429 return deviceService.isAvailable(osNode.intgBridge()) &&
430 deviceService.getPorts(osNode.intgBridge()).stream()
431 .anyMatch(port -> Objects.equals(
432 port.annotations().value(PORT_NAME), intf) &&
433 port.isEnabled());
Hyunsun Moon0d457362017-06-27 17:19:41 +0900434 }
435
Jian Li340165f2018-02-27 10:38:17 +0900436 /**
437 * Checks whether all requirements for this state are fulfilled or not.
438 *
439 * @param osNode openstack node
440 * @return true if all requirements are fulfilled, false otherwise
441 */
Hyunsun Moon0d457362017-06-27 17:19:41 +0900442 private boolean isCurrentStateDone(OpenstackNode osNode) {
443 switch (osNode.state()) {
444 case INIT:
Jian Li5ecfd1a2018-12-10 11:41:03 +0900445 if (!isOvsdbConnected(osNode, ovsdbPortNum,
446 ovsdbController, deviceService)) {
Daniel Parkc4d06402018-05-28 15:57:37 +0900447 return false;
448 }
449
Daniel Parke2658ba2018-08-24 22:33:29 +0900450 boolean initStateDone = deviceService.isAvailable(osNode.intgBridge());
451 if (hasDpdkTunnelBridge(osNode)) {
452 initStateDone = initStateDone && dpdkTunnelBridgeCreated(osNode);
453 }
454 return initStateDone;
Hyunsun Moon0d457362017-06-27 17:19:41 +0900455 case DEVICE_CREATED:
456 if (osNode.dataIp() != null &&
Jian Li2d68c192018-12-13 15:52:59 +0900457 !isIntfEnabled(osNode, VXLAN_TUNNEL)) {
458 return false;
459 }
460 if (osNode.dataIp() != null &&
461 !isIntfEnabled(osNode, GRE_TUNNEL)) {
Hyunsun Moon0d457362017-06-27 17:19:41 +0900462 return false;
463 }
464 if (osNode.vlanIntf() != null &&
465 !isIntfEnabled(osNode, osNode.vlanIntf())) {
466 return false;
467 }
daniel parkb18424c2018-02-05 15:43:43 +0900468 if (osNode.type() == GATEWAY &&
469 !isIntfEnabled(osNode, osNode.uplinkPort())) {
Hyunsun Moon0d457362017-06-27 17:19:41 +0900470 return false;
471 }
Daniel Park5a6a7102018-09-06 23:58:33 +0900472 if (osNode.dpdkConfig() != null &&
473 osNode.dpdkConfig().dpdkIntfs() != null &&
474 !isDpdkIntfsCreated(osNode, osNode.dpdkConfig().dpdkIntfs())) {
475 return false;
Daniel Parke2658ba2018-08-24 22:33:29 +0900476 }
Jian Lie6312162018-03-21 21:41:00 +0900477
478 for (OpenstackPhyInterface intf : osNode.phyIntfs()) {
479 if (intf != null && !isIntfEnabled(osNode, intf.intf())) {
480 return false;
481 }
482 }
483
Hyunsun Moon0d457362017-06-27 17:19:41 +0900484 return true;
Hyunsun Moon0d457362017-06-27 17:19:41 +0900485 case COMPLETE:
Hyunsun Moon0d457362017-06-27 17:19:41 +0900486 case INCOMPLETE:
487 // always return false
488 // run init CLI to re-trigger node bootstrap
489 return false;
490 default:
491 return true;
492 }
493 }
494
Jian Li40888bf2018-11-21 09:46:32 +0900495 private boolean isDpdkIntfsCreated(OpenstackNode osNode,
496 Collection<DpdkInterface> dpdkInterfaces) {
Ray Milkey8e406512018-10-24 15:56:50 -0700497 OvsdbClientService client = getOvsdbClient(osNode, ovsdbPortNum, ovsdbController);
Daniel Parke2658ba2018-08-24 22:33:29 +0900498 if (client == null) {
499 log.info("Failed to get ovsdb client");
500 return false;
501 }
502
503 Set<OvsdbPort> ports = client.getPorts();
504
Jian Li5ecfd1a2018-12-10 11:41:03 +0900505 for (DpdkInterface dpdkIntf : dpdkInterfaces) {
Daniel Parke2658ba2018-08-24 22:33:29 +0900506 Optional<OvsdbPort> port = ports.stream()
Jian Li5ecfd1a2018-12-10 11:41:03 +0900507 .filter(ovsdbPort -> ovsdbPort.portName().value().equals(dpdkIntf.intf()))
Daniel Parke2658ba2018-08-24 22:33:29 +0900508 .findAny();
509
510 if (!port.isPresent()) {
511 return false;
512 }
Jian Li5ecfd1a2018-12-10 11:41:03 +0900513 Interface intf = client.getInterface(dpdkIntf.intf());
Daniel Parke2658ba2018-08-24 22:33:29 +0900514 if (intf == null) {
515 return false;
516 }
517
518 OvsdbSet mtu = (OvsdbSet) intf.getMtuColumn().data();
519 if (mtu == null) {
520 return false;
521 }
522
523 OvsdbMap option = (OvsdbMap) intf.getOptionsColumn().data();
524 if (option == null) {
525 return false;
526 }
527
Jian Li5ecfd1a2018-12-10 11:41:03 +0900528 if (!mtu.set().contains(dpdkIntf.mtu().intValue()) ||
529 !option.toString().contains(dpdkIntf.pciAddress())) {
Jian Li40888bf2018-11-21 09:46:32 +0900530 log.trace("The dpdk interface {} was created but mtu or " +
531 "pci address is different from the config.");
Daniel Parke2658ba2018-08-24 22:33:29 +0900532 return false;
533 }
534 }
535 return true;
536 }
537
Jian Li340165f2018-02-27 10:38:17 +0900538 /**
539 * Configures the openstack node with new state.
540 *
541 * @param osNode openstack node
542 * @param newState a new state
543 */
Hyunsun Moon0d457362017-06-27 17:19:41 +0900544 private void setState(OpenstackNode osNode, NodeState newState) {
545 if (osNode.state() == newState) {
546 return;
547 }
548 OpenstackNode updated = osNode.updateState(newState);
549 osNodeAdminService.updateNode(updated);
550 log.info("Changed {} state: {}", osNode.hostname(), newState);
551 }
552
Jian Li340165f2018-02-27 10:38:17 +0900553 /**
554 * Bootstraps a new openstack node.
555 *
556 * @param osNode openstack node
557 */
Hyunsun Moon0d457362017-06-27 17:19:41 +0900558 private void bootstrapNode(OpenstackNode osNode) {
Jian Li51b844c2018-05-31 10:59:03 +0900559 if (osNode.type() == CONTROLLER) {
560 if (osNode.state() == INIT && checkEndpoint(osNode)) {
561 setState(osNode, COMPLETE);
562 }
Hyunsun Moon0d457362017-06-27 17:19:41 +0900563 } else {
Jian Li51b844c2018-05-31 10:59:03 +0900564 if (isCurrentStateDone(osNode)) {
565 setState(osNode, osNode.state().nextState());
566 } else {
Jian Li97482c12018-07-03 01:08:23 +0900567 log.trace("Processing {} state for {}", osNode.state(),
568 osNode.hostname());
Jian Li51b844c2018-05-31 10:59:03 +0900569 osNode.state().process(this, osNode);
570 }
571 }
572 }
573
Daniel Park5a6a7102018-09-06 23:58:33 +0900574 private void removeVlanInterface(OpenstackNode osNode) {
575 if (osNode.vlanIntf() != null) {
Jian Li5ecfd1a2018-12-10 11:41:03 +0900576 Optional<DpdkInterface> dpdkIntf =
577 dpdkInterfaceByIntfName(osNode, osNode.vlanIntf());
Daniel Park5a6a7102018-09-06 23:58:33 +0900578
Jian Li5ecfd1a2018-12-10 11:41:03 +0900579 removeInterfaceOnIntegrationBridge(osNode, osNode.vlanIntf(), dpdkIntf);
Daniel Park5a6a7102018-09-06 23:58:33 +0900580 }
581 }
582
583 private void removePhysicalInterface(OpenstackNode osNode) {
584 osNode.phyIntfs().forEach(phyIntf -> {
Jian Li5ecfd1a2018-12-10 11:41:03 +0900585 Optional<DpdkInterface> dpdkIntf = dpdkInterfaceByIntfName(osNode, phyIntf.intf());
Daniel Park5a6a7102018-09-06 23:58:33 +0900586
Jian Li5ecfd1a2018-12-10 11:41:03 +0900587 removeInterfaceOnIntegrationBridge(osNode, phyIntf.intf(), dpdkIntf);
Daniel Park5a6a7102018-09-06 23:58:33 +0900588 });
589 }
590
Jian Li5ecfd1a2018-12-10 11:41:03 +0900591 private Optional<DpdkInterface> dpdkInterfaceByIntfName(OpenstackNode osNode,
592 String intf) {
Daniel Park5a6a7102018-09-06 23:58:33 +0900593 return osNode.dpdkConfig() == null ? Optional.empty() :
594 osNode.dpdkConfig().dpdkIntfs().stream()
595 .filter(dpdkIntf -> dpdkIntf.intf().equals(intf))
596 .findAny();
597 }
598
599 private void removeInterfaceOnIntegrationBridge(OpenstackNode osNode,
600 String intfName,
601 Optional<DpdkInterface> dpdkInterface) {
602 if (dpdkInterface.isPresent()) {
Ray Milkey8e406512018-10-24 15:56:50 -0700603 addOrRemoveDpdkInterface(osNode, dpdkInterface.get(), ovsdbPortNum,
Daniel Park5a6a7102018-09-06 23:58:33 +0900604 ovsdbController, false);
605 } else {
606 addOrRemoveSystemInterface(osNode, INTEGRATION_BRIDGE, intfName, deviceService,
607 false);
608 }
609 }
610
611 private void processOpenstackNodeRemoved(OpenstackNode osNode) {
Ray Milkey8e406512018-10-24 15:56:50 -0700612 OvsdbClientService client = getOvsdbClient(osNode, ovsdbPortNum, ovsdbController);
Daniel Park489645c2018-10-24 11:34:22 +0900613 if (client == null) {
614 log.info("Failed to get ovsdb client");
615 return;
616 }
617
Daniel Park5a6a7102018-09-06 23:58:33 +0900618 //delete physical interfaces from the node
619 removePhysicalInterface(osNode);
620
621 //delete vlan interface from the node
622 removeVlanInterface(osNode);
623
624 //delete dpdk interfaces from the node
625 if (osNode.dpdkConfig() != null) {
626 osNode.dpdkConfig().dpdkIntfs().forEach(dpdkInterface -> {
627 if (isDpdkIntfsCreated(osNode, Lists.newArrayList(dpdkInterface))) {
Jian Li40888bf2018-11-21 09:46:32 +0900628 addOrRemoveDpdkInterface(osNode, dpdkInterface, ovsdbPortNum,
629 ovsdbController, false);
Daniel Park5a6a7102018-09-06 23:58:33 +0900630 }
631 });
632 }
Daniel Park489645c2018-10-24 11:34:22 +0900633
634 //delete tunnel bridge from the node
635 if (hasDpdkTunnelBridge(osNode)) {
636 client.dropBridge(TUNNEL_BRIDGE);
637 }
638
639 //delete integration bridge from the node
640 client.dropBridge(INTEGRATION_BRIDGE);
641
642 //disconnect ovsdb
643 client.disconnect();
Daniel Park5a6a7102018-09-06 23:58:33 +0900644 }
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
722 if (!isRelevantHelper()) {
723 return;
724 }
725
Jian Licab41762018-11-06 12:30:08 +0900726 OpenstackNode osNode = osNodeService.node(device.id());
727
728 if (osNode == null || osNode.type() == CONTROLLER) {
729 return;
730 }
731
Hyunsun Moon0d457362017-06-27 17:19:41 +0900732 if (deviceService.isAvailable(device.id())) {
733 log.debug("OVSDB {} detected", device.id());
734 bootstrapNode(osNode);
Hyunsun Moon0d457362017-06-27 17:19:41 +0900735 }
736 });
737 break;
738 case PORT_ADDED:
739 case PORT_REMOVED:
740 case DEVICE_REMOVED:
741 default:
742 // do nothing
743 break;
744 }
745 }
746 }
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
774 if (!isRelevantHelper()) {
775 return;
776 }
777
Jian Licab41762018-11-06 12:30:08 +0900778 OpenstackNode osNode = osNodeService.node(device.id());
779
780 if (osNode == null || osNode.type() == CONTROLLER) {
781 return;
782 }
783
Hyunsun Moon0d457362017-06-27 17:19:41 +0900784 if (deviceService.isAvailable(device.id())) {
785 log.debug("Integration bridge created on {}", osNode.hostname());
786 bootstrapNode(osNode);
787 } else if (osNode.state() == COMPLETE) {
Jian Li97482c12018-07-03 01:08:23 +0900788 log.info("Device {} disconnected", device.id());
Hyunsun Moon0d457362017-06-27 17:19:41 +0900789 setState(osNode, INCOMPLETE);
790 }
Jian Li97482c12018-07-03 01:08:23 +0900791
792 if (autoRecovery) {
793 if (osNode.state() == INCOMPLETE ||
794 osNode.state() == DEVICE_CREATED) {
795 log.info("Device {} is reconnected", device.id());
796 osNodeAdminService.updateNode(
797 osNode.updateState(NodeState.INIT));
798 }
799 }
Hyunsun Moon0d457362017-06-27 17:19:41 +0900800 });
801 break;
Daniel Park5a6a7102018-09-06 23:58:33 +0900802 case PORT_UPDATED:
Hyunsun Moon0d457362017-06-27 17:19:41 +0900803 case PORT_ADDED:
804 eventExecutor.execute(() -> {
Jian Li40888bf2018-11-21 09:46:32 +0900805
806 if (!isRelevantHelper()) {
807 return;
808 }
809
Jian Licab41762018-11-06 12:30:08 +0900810 OpenstackNode osNode = osNodeService.node(device.id());
811
812 if (osNode == null || osNode.type() == CONTROLLER) {
813 return;
814 }
815
Hyunsun Moon0d457362017-06-27 17:19:41 +0900816 Port port = event.port();
817 String portName = port.annotations().value(PORT_NAME);
818 if (osNode.state() == DEVICE_CREATED && (
Jian Li2d68c192018-12-13 15:52:59 +0900819 Objects.equals(portName, VXLAN_TUNNEL) ||
820 Objects.equals(portName, GRE_TUNNEL) ||
Hyunsun Moon0d457362017-06-27 17:19:41 +0900821 Objects.equals(portName, osNode.vlanIntf()) ||
Jian Lie6312162018-03-21 21:41:00 +0900822 Objects.equals(portName, osNode.uplinkPort()) ||
Daniel Park5a6a7102018-09-06 23:58:33 +0900823 containsPhyIntf(osNode, portName)) ||
824 containsDpdkIntfs(osNode, portName)) {
825 log.info("Interface {} added or updated to {}",
826 portName, device.id());
Hyunsun Moon0d457362017-06-27 17:19:41 +0900827 bootstrapNode(osNode);
828 }
829 });
830 break;
831 case PORT_REMOVED:
832 eventExecutor.execute(() -> {
Jian Li40888bf2018-11-21 09:46:32 +0900833
834 if (!isRelevantHelper()) {
835 return;
836 }
837
Jian Licab41762018-11-06 12:30:08 +0900838 OpenstackNode osNode = osNodeService.node(device.id());
839
840 if (osNode == null || osNode.type() == CONTROLLER) {
841 return;
842 }
843
Hyunsun Moon0d457362017-06-27 17:19:41 +0900844 Port port = event.port();
845 String portName = port.annotations().value(PORT_NAME);
846 if (osNode.state() == COMPLETE && (
Jian Li2d68c192018-12-13 15:52:59 +0900847 Objects.equals(portName, VXLAN_TUNNEL) ||
848 Objects.equals(portName, GRE_TUNNEL) ||
Hyunsun Moon0d457362017-06-27 17:19:41 +0900849 Objects.equals(portName, osNode.vlanIntf()) ||
Jian Li97482c12018-07-03 01:08:23 +0900850 Objects.equals(portName, osNode.uplinkPort()) ||
Daniel Park5a6a7102018-09-06 23:58:33 +0900851 containsPhyIntf(osNode, portName)) ||
852 containsDpdkIntfs(osNode, portName)) {
Jian Li97482c12018-07-03 01:08:23 +0900853 log.warn("Interface {} removed from {}",
854 portName, event.subject().id());
Hyunsun Moon0d457362017-06-27 17:19:41 +0900855 setState(osNode, INCOMPLETE);
856 }
857 });
858 break;
Hyunsun Moon0d457362017-06-27 17:19:41 +0900859 case DEVICE_REMOVED:
860 default:
861 // do nothing
862 break;
863 }
864 }
865 }
866
Jian Li340165f2018-02-27 10:38:17 +0900867 /**
Jian Lie6312162018-03-21 21:41:00 +0900868 * Checks whether the openstack node contains the given physical interface.
869 *
870 * @param osNode openstack node
871 * @param portName physical interface
872 * @return true if openstack node contains the given physical interface,
873 * false otherwise
874 */
875 private boolean containsPhyIntf(OpenstackNode osNode, String portName) {
Daniel Park5a6a7102018-09-06 23:58:33 +0900876 return osNode.phyIntfs().stream()
877 .anyMatch(phyInterface -> phyInterface.intf().equals(portName));
878 }
Jian Lie6312162018-03-21 21:41:00 +0900879
Daniel Park5a6a7102018-09-06 23:58:33 +0900880 /**
881 * Checks whether the openstack node contains the given dpdk interface.
882 *
883 * @param osNode openstack node
884 * @param portName dpdk interface
885 * @return true if openstack node contains the given dpdk interface,
886 * false otherwise
887 */
888 private boolean containsDpdkIntfs(OpenstackNode osNode, String portName) {
889 if (osNode.dpdkConfig() == null) {
890 return false;
891 }
892 return osNode.dpdkConfig().dpdkIntfs().stream()
893 .anyMatch(dpdkInterface -> dpdkInterface.intf().equals(portName));
Jian Lie6312162018-03-21 21:41:00 +0900894 }
895
896 /**
Jian Li340165f2018-02-27 10:38:17 +0900897 * An internal openstack node listener.
898 * The notification is triggered by OpenstackNodeStore.
899 */
Hyunsun Moon0d457362017-06-27 17:19:41 +0900900 private class InternalOpenstackNodeListener implements OpenstackNodeListener {
901
Jian Li40888bf2018-11-21 09:46:32 +0900902 private boolean isRelevantHelper() {
903 return Objects.equals(localNode, leadershipService.getLeader(appId.name()));
Hyunsun Moon0d457362017-06-27 17:19:41 +0900904 }
905
906 @Override
907 public void event(OpenstackNodeEvent event) {
908 switch (event.type()) {
909 case OPENSTACK_NODE_CREATED:
910 case OPENSTACK_NODE_UPDATED:
Jian Li40888bf2018-11-21 09:46:32 +0900911 eventExecutor.execute(() -> {
912
913 if (!isRelevantHelper()) {
914 return;
915 }
916
917 bootstrapNode(event.subject());
918 });
Hyunsun Moon0d457362017-06-27 17:19:41 +0900919 break;
920 case OPENSTACK_NODE_REMOVED:
Jian Li40888bf2018-11-21 09:46:32 +0900921 eventExecutor.execute(() -> {
922
923 if (!isRelevantHelper()) {
924 return;
925 }
926
927 processOpenstackNodeRemoved(event.subject());
928 });
Hyunsun Moon0d457362017-06-27 17:19:41 +0900929 break;
Jian Li40888bf2018-11-21 09:46:32 +0900930 case OPENSTACK_NODE_COMPLETE:
Hyunsun Moon0d457362017-06-27 17:19:41 +0900931 default:
932 break;
933 }
934 }
935 }
936}