blob: cbe22e0710530a210be816f0d6749a61af06188a [file] [log] [blame]
Hyunsun Moon44aac662017-02-18 02:07:01 +09001/*
Brian O'Connora09fe5b2017-08-03 21:12:30 -07002 * Copyright 2016-present Open Networking Foundation
Hyunsun Moon44aac662017-02-18 02:07:01 +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.openstacknetworking.impl;
17
18import com.google.common.base.Strings;
Jian Li1064e4f2018-05-29 16:16:53 +090019import com.google.common.collect.ImmutableSet;
Jian Li1064e4f2018-05-29 16:16:53 +090020import com.google.common.collect.Sets;
Hyunsun Moon44aac662017-02-18 02:07:01 +090021import org.apache.felix.scr.annotations.Activate;
22import org.apache.felix.scr.annotations.Component;
23import org.apache.felix.scr.annotations.Deactivate;
24import org.apache.felix.scr.annotations.Reference;
25import org.apache.felix.scr.annotations.ReferenceCardinality;
26import org.onlab.packet.Ethernet;
27import org.onlab.packet.IpAddress;
28import org.onlab.packet.MacAddress;
daniel parkee8700b2017-05-11 15:50:03 +090029import org.onlab.packet.VlanId;
Jian Li9d35bd62018-10-13 01:43:24 +090030import org.onosproject.cfg.ComponentConfigService;
Hyunsun Moon44aac662017-02-18 02:07:01 +090031import org.onosproject.cluster.ClusterService;
32import org.onosproject.cluster.LeadershipService;
33import org.onosproject.cluster.NodeId;
34import org.onosproject.core.ApplicationId;
35import org.onosproject.core.CoreService;
Jian Li24ec59f2018-05-23 19:01:25 +090036import org.onosproject.net.DeviceId;
Hyunsun Moon44aac662017-02-18 02:07:01 +090037import org.onosproject.net.device.DeviceService;
38import org.onosproject.net.flow.DefaultTrafficSelector;
39import org.onosproject.net.flow.DefaultTrafficTreatment;
40import org.onosproject.net.flow.TrafficSelector;
41import org.onosproject.net.flow.TrafficTreatment;
Hyunsun Moon44aac662017-02-18 02:07:01 +090042import org.onosproject.openstacknetworking.api.Constants;
daniel park32b42202018-03-14 16:53:44 +090043import org.onosproject.openstacknetworking.api.ExternalPeerRouter;
Hyunsun Moon44aac662017-02-18 02:07:01 +090044import org.onosproject.openstacknetworking.api.InstancePort;
Jian Liec5c32b2018-07-13 14:28:58 +090045import org.onosproject.openstacknetworking.api.InstancePortAdminService;
Jian Li24ec59f2018-05-23 19:01:25 +090046import org.onosproject.openstacknetworking.api.InstancePortEvent;
47import org.onosproject.openstacknetworking.api.InstancePortListener;
sanghodc375372017-06-08 10:41:30 +090048import org.onosproject.openstacknetworking.api.OpenstackFlowRuleService;
Jian Lie1a39032018-06-19 21:49:36 +090049import org.onosproject.openstacknetworking.api.OpenstackNetworkEvent;
50import org.onosproject.openstacknetworking.api.OpenstackNetworkListener;
sanghodc375372017-06-08 10:41:30 +090051import org.onosproject.openstacknetworking.api.OpenstackNetworkService;
Jian Lif3a28b02018-06-11 21:29:13 +090052import org.onosproject.openstacknetworking.api.OpenstackRouterAdminService;
Hyunsun Moon44aac662017-02-18 02:07:01 +090053import org.onosproject.openstacknetworking.api.OpenstackRouterEvent;
54import org.onosproject.openstacknetworking.api.OpenstackRouterListener;
Jian Li8f64feb2018-07-24 13:20:16 +090055import org.onosproject.openstacknetworking.api.PreCommitPortService;
Hyunsun Moon0d457362017-06-27 17:19:41 +090056import org.onosproject.openstacknode.api.OpenstackNode;
57import org.onosproject.openstacknode.api.OpenstackNodeEvent;
58import org.onosproject.openstacknode.api.OpenstackNodeListener;
59import org.onosproject.openstacknode.api.OpenstackNodeService;
daniel parkeeb8e042018-02-21 14:06:58 +090060import org.openstack4j.model.network.ExternalGateway;
Hyunsun Moon44aac662017-02-18 02:07:01 +090061import org.openstack4j.model.network.NetFloatingIP;
62import org.openstack4j.model.network.Network;
daniel parkee8700b2017-05-11 15:50:03 +090063import org.openstack4j.model.network.NetworkType;
Hyunsun Moon44aac662017-02-18 02:07:01 +090064import org.openstack4j.model.network.Port;
daniel parkeeb8e042018-02-21 14:06:58 +090065import org.openstack4j.model.network.Router;
66import org.openstack4j.model.network.RouterInterface;
67import org.openstack4j.model.network.Subnet;
Jian Lif3a28b02018-06-11 21:29:13 +090068import org.openstack4j.openstack.networking.domain.NeutronFloatingIP;
Hyunsun Moon44aac662017-02-18 02:07:01 +090069import org.slf4j.Logger;
70import org.slf4j.LoggerFactory;
71
72import java.util.Objects;
Jian Li99892e92018-04-13 14:59:39 +090073import java.util.Set;
Hyunsun Moon44aac662017-02-18 02:07:01 +090074import java.util.concurrent.ExecutorService;
75
76import static java.util.concurrent.Executors.newSingleThreadExecutor;
77import static org.onlab.util.Tools.groupedThreads;
sanghodc375372017-06-08 10:41:30 +090078import static org.onosproject.openstacknetworking.api.Constants.GW_COMMON_TABLE;
79import static org.onosproject.openstacknetworking.api.Constants.OPENSTACK_NETWORKING_APP_ID;
daniel parkeeb8e042018-02-21 14:06:58 +090080import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_EXTERNAL_FLOATING_ROUTING_RULE;
sanghodc375372017-06-08 10:41:30 +090081import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_FLOATING_EXTERNAL;
daniel parkeeb8e042018-02-21 14:06:58 +090082import static org.onosproject.openstacknetworking.api.Constants.ROUTING_TABLE;
Jian Li8a5fb642018-09-14 15:50:04 +090083import static org.onosproject.openstacknetworking.api.InstancePort.State.REMOVE_PENDING;
Jian Lie1a39032018-06-19 21:49:36 +090084import static org.onosproject.openstacknetworking.api.InstancePortEvent.Type.OPENSTACK_INSTANCE_MIGRATION_ENDED;
85import static org.onosproject.openstacknetworking.api.InstancePortEvent.Type.OPENSTACK_INSTANCE_MIGRATION_STARTED;
Jian Li8f64feb2018-07-24 13:20:16 +090086import static org.onosproject.openstacknetworking.api.OpenstackNetworkEvent.Type.OPENSTACK_PORT_PRE_REMOVE;
Jian Li24ec59f2018-05-23 19:01:25 +090087import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.associatedFloatingIp;
Jian Li1064e4f2018-05-29 16:16:53 +090088import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.getGwByComputeDevId;
Jian Li9d35bd62018-10-13 01:43:24 +090089import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.getPropertyValueAsBoolean;
Jian Li24ec59f2018-05-23 19:01:25 +090090import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.isAssociatedWithVM;
Jian Liec5c32b2018-07-13 14:28:58 +090091import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.swapStaleLocation;
Jian Li26949762018-03-30 15:46:37 +090092import static org.onosproject.openstacknetworking.util.RulePopulatorUtil.buildExtension;
Hyunsun Moon0d457362017-06-27 17:19:41 +090093import static org.onosproject.openstacknode.api.OpenstackNode.NodeType.GATEWAY;
Hyunsun Moon44aac662017-02-18 02:07:01 +090094
95/**
96 * Handles OpenStack floating IP events.
97 */
98@Component(immediate = true)
99public class OpenstackRoutingFloatingIpHandler {
100
101 private final Logger log = LoggerFactory.getLogger(getClass());
102
103 private static final String ERR_FLOW = "Failed set flows for floating IP %s: ";
Ray Milkeyc6c9b172018-02-26 09:36:31 -0800104 private static final String ERR_UNSUPPORTED_NET_TYPE = "Unsupported network type %s";
Hyunsun Moon44aac662017-02-18 02:07:01 +0900105
Jian Li9d35bd62018-10-13 01:43:24 +0900106 private static final String USE_SECURITY_GROUP = "useSecurityGroup";
107
Hyunsun Moon44aac662017-02-18 02:07:01 +0900108 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
109 protected CoreService coreService;
110
111 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
112 protected DeviceService deviceService;
113
114 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Hyunsun Moon44aac662017-02-18 02:07:01 +0900115 protected LeadershipService leadershipService;
116
117 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
118 protected ClusterService clusterService;
119
120 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Jian Li9d35bd62018-10-13 01:43:24 +0900121 protected ComponentConfigService componentConfigService;
122
123 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Hyunsun Moon44aac662017-02-18 02:07:01 +0900124 protected OpenstackNodeService osNodeService;
125
126 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Jian Liec5c32b2018-07-13 14:28:58 +0900127 protected InstancePortAdminService instancePortService;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900128
129 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Jian Lif3a28b02018-06-11 21:29:13 +0900130 protected OpenstackRouterAdminService osRouterAdminService;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900131
132 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
133 protected OpenstackNetworkService osNetworkService;
134
sanghodc375372017-06-08 10:41:30 +0900135 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
136 protected OpenstackFlowRuleService osFlowRuleService;
137
Jian Li8f64feb2018-07-24 13:20:16 +0900138 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
139 protected PreCommitPortService preCommitPortService;
140
Hyunsun Moon44aac662017-02-18 02:07:01 +0900141 private final ExecutorService eventExecutor = newSingleThreadExecutor(
142 groupedThreads(this.getClass().getSimpleName(), "event-handler", log));
Jian Li24ec59f2018-05-23 19:01:25 +0900143 private final OpenstackRouterListener floatingIpListener = new InternalFloatingIpListener();
144 private final InstancePortListener instancePortListener = new InternalInstancePortListener();
Hyunsun Moon44aac662017-02-18 02:07:01 +0900145 private final OpenstackNodeListener osNodeListener = new InternalNodeListener();
Jian Lie1a39032018-06-19 21:49:36 +0900146 private final OpenstackNetworkListener osNetworkListener = new InternalOpenstackNetworkListener();
147 private final InstancePortListener instPortListener = new InternalInstancePortListener();
148
Hyunsun Moon44aac662017-02-18 02:07:01 +0900149 private ApplicationId appId;
150 private NodeId localNodeId;
151
152 @Activate
153 protected void activate() {
154 appId = coreService.registerApplication(OPENSTACK_NETWORKING_APP_ID);
155 localNodeId = clusterService.getLocalNode().id();
156 leadershipService.runForLeadership(appId.name());
Jian Li24ec59f2018-05-23 19:01:25 +0900157 osRouterAdminService.addListener(floatingIpListener);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900158 osNodeService.addListener(osNodeListener);
Jian Li24ec59f2018-05-23 19:01:25 +0900159 instancePortService.addListener(instancePortListener);
Jian Lie1a39032018-06-19 21:49:36 +0900160 osNodeService.addListener(osNodeListener);
161 osNetworkService.addListener(osNetworkListener);
162 instancePortService.addListener(instPortListener);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900163
164 log.info("Started");
165 }
166
167 @Deactivate
168 protected void deactivate() {
Jian Li24ec59f2018-05-23 19:01:25 +0900169 instancePortService.removeListener(instancePortListener);
Jian Lie1a39032018-06-19 21:49:36 +0900170 instancePortService.removeListener(instPortListener);
171 osNetworkService.removeListener(osNetworkListener);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900172 osNodeService.removeListener(osNodeListener);
Jian Li24ec59f2018-05-23 19:01:25 +0900173 osRouterAdminService.removeListener(floatingIpListener);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900174 leadershipService.withdraw(appId.name());
175 eventExecutor.shutdown();
176
177 log.info("Stopped");
178 }
179
Jian Li628a7cb2018-08-11 23:04:24 +0900180 private void setFloatingIpRules(NetFloatingIP floatingIp, InstancePort instPort,
Jian Li1064e4f2018-05-29 16:16:53 +0900181 OpenstackNode gateway, boolean install) {
Jian Li628a7cb2018-08-11 23:04:24 +0900182
183 if (instPort == null) {
184 log.debug("No instance port found");
185 return;
186 }
187
188 Network osNet = osNetworkService.network(instPort.networkId());
Jian Li8f64feb2018-07-24 13:20:16 +0900189
Hyunsun Moon44aac662017-02-18 02:07:01 +0900190 if (osNet == null) {
Jian Li71670d12018-03-02 21:31:07 +0900191 final String errorFormat = ERR_FLOW + "no network(%s) exists";
192 final String error = String.format(errorFormat,
Hyunsun Moon44aac662017-02-18 02:07:01 +0900193 floatingIp.getFloatingIpAddress(),
Jian Li628a7cb2018-08-11 23:04:24 +0900194 instPort.networkId());
Hyunsun Moon44aac662017-02-18 02:07:01 +0900195 throw new IllegalStateException(error);
196 }
197
daniel park32b42202018-03-14 16:53:44 +0900198 ExternalPeerRouter externalPeerRouter = externalPeerRouter(osNet);
199 if (externalPeerRouter == null) {
daniel parkc2a2ed62018-04-10 15:17:42 +0900200 final String errorFormat = ERR_FLOW + "no external peer router found";
201 throw new IllegalStateException(errorFormat);
daniel park32b42202018-03-14 16:53:44 +0900202 }
203
Jian Li8f64feb2018-07-24 13:20:16 +0900204 if (install) {
Jian Li628a7cb2018-08-11 23:04:24 +0900205 preCommitPortService.subscribePreCommit(instPort.portId(),
Jian Li8f64feb2018-07-24 13:20:16 +0900206 OPENSTACK_PORT_PRE_REMOVE, this.getClass().getName());
Jian Li628a7cb2018-08-11 23:04:24 +0900207 log.info("Subscribed the port {} on listening pre-remove event", instPort.portId());
Jian Li8f64feb2018-07-24 13:20:16 +0900208 } else {
Jian Li628a7cb2018-08-11 23:04:24 +0900209 preCommitPortService.unsubscribePreCommit(instPort.portId(),
210 OPENSTACK_PORT_PRE_REMOVE, instancePortService, this.getClass().getName());
211 log.info("Unsubscribed the port {} on listening pre-remove event", instPort.portId());
Jian Li8f64feb2018-07-24 13:20:16 +0900212 }
213
Jian Lide679782018-06-05 01:41:29 +0900214 updateComputeNodeRules(instPort, osNet, gateway, install);
215 updateGatewayNodeRules(floatingIp, instPort, osNet, externalPeerRouter, gateway, install);
216
Jian Lide679782018-06-05 01:41:29 +0900217 // TODO: need to refactor setUpstreamRules if possible
daniel park32b42202018-03-14 16:53:44 +0900218 setUpstreamRules(floatingIp, osNet, instPort, externalPeerRouter, install);
Jian Li8f64feb2018-07-24 13:20:16 +0900219
daniel parkc2a2ed62018-04-10 15:17:42 +0900220 log.trace("Succeeded to set flow rules for floating ip {}:{} and install: {}",
221 floatingIp.getFloatingIpAddress(),
222 floatingIp.getFixedIpAddress(),
223 install);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900224 }
225
Jian Lide679782018-06-05 01:41:29 +0900226 private synchronized void updateGatewayNodeRules(NetFloatingIP fip,
227 InstancePort instPort,
228 Network osNet,
229 ExternalPeerRouter router,
230 OpenstackNode gateway,
231 boolean install) {
232
233 Set<OpenstackNode> completedGws = osNodeService.completeNodes(GATEWAY);
234 Set<OpenstackNode> finalGws = Sets.newConcurrentHashSet();
235 finalGws.addAll(ImmutableSet.copyOf(completedGws));
236
Jian Lia171a432018-06-11 11:52:11 +0900237
238 if (gateway == null) {
239 // these are floating IP related cases...
240 setDownstreamExternalRulesHelper(fip, osNet, instPort, router,
241 ImmutableSet.copyOf(finalGws), install);
242
Jian Lide679782018-06-05 01:41:29 +0900243 } else {
Jian Lia171a432018-06-11 11:52:11 +0900244 // these are openstack node related cases...
245 if (install) {
246 if (completedGws.contains(gateway)) {
247 if (completedGws.size() > 1) {
248 finalGws.remove(gateway);
249 if (fip.getPortId() != null) {
250 setDownstreamExternalRulesHelper(fip, osNet, instPort, router,
251 ImmutableSet.copyOf(finalGws), false);
252 finalGws.add(gateway);
253 }
254 }
Jian Lide679782018-06-05 01:41:29 +0900255 if (fip.getPortId() != null) {
256 setDownstreamExternalRulesHelper(fip, osNet, instPort, router,
257 ImmutableSet.copyOf(finalGws), true);
258 }
Jian Lia171a432018-06-11 11:52:11 +0900259 } else {
260 log.warn("Detected node should be included in completed gateway set");
Jian Lide679782018-06-05 01:41:29 +0900261 }
262 } else {
Jian Lia171a432018-06-11 11:52:11 +0900263 if (!completedGws.contains(gateway)) {
264 if (completedGws.size() >= 1) {
265 if (fip.getPortId() != null) {
266 setDownstreamExternalRulesHelper(fip, osNet, instPort, router,
267 ImmutableSet.copyOf(finalGws), true);
268 }
269 }
270 } else {
271 log.warn("Detected node should NOT be included in completed gateway set");
272 }
Jian Lide679782018-06-05 01:41:29 +0900273 }
274 }
275 }
276
277 private synchronized void updateComputeNodeRules(InstancePort instPort,
278 Network osNet,
279 OpenstackNode gateway,
280 boolean install) {
Jian Li1064e4f2018-05-29 16:16:53 +0900281
282 Set<OpenstackNode> completedGws = osNodeService.completeNodes(GATEWAY);
283 Set<OpenstackNode> finalGws = Sets.newConcurrentHashSet();
284 finalGws.addAll(ImmutableSet.copyOf(completedGws));
285
286 if (gateway == null) {
287 // these are floating IP related cases...
288 setComputeNodeToGatewayHelper(instPort, osNet,
289 ImmutableSet.copyOf(finalGws), install);
Jian Lide679782018-06-05 01:41:29 +0900290
Jian Li1064e4f2018-05-29 16:16:53 +0900291 } else {
292 // these are openstack node related cases...
293 if (install) {
294 if (completedGws.contains(gateway)) {
295 if (completedGws.size() > 1) {
296 finalGws.remove(gateway);
297 setComputeNodeToGatewayHelper(instPort, osNet,
298 ImmutableSet.copyOf(finalGws), false);
299 finalGws.add(gateway);
300 }
301
302 setComputeNodeToGatewayHelper(instPort, osNet,
303 ImmutableSet.copyOf(finalGws), true);
304 } else {
305 log.warn("Detected node should be included in completed gateway set");
306 }
307 } else {
308 if (!completedGws.contains(gateway)) {
309 finalGws.add(gateway);
310 setComputeNodeToGatewayHelper(instPort, osNet,
311 ImmutableSet.copyOf(finalGws), false);
312 finalGws.remove(gateway);
313 if (completedGws.size() >= 1) {
314 setComputeNodeToGatewayHelper(instPort, osNet,
315 ImmutableSet.copyOf(finalGws), true);
316 }
317 } else {
318 log.warn("Detected node should NOT be included in completed gateway set");
319 }
320 }
321 }
322 }
323
324 // a helper method
325 private void setComputeNodeToGatewayHelper(InstancePort instPort,
326 Network osNet,
327 Set<OpenstackNode> gateways,
328 boolean install) {
daniel parkeeb8e042018-02-21 14:06:58 +0900329 TrafficTreatment treatment;
330
331 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder()
332 .matchEthType(Ethernet.TYPE_IPV4)
333 .matchIPSrc(instPort.ipAddress().toIpPrefix())
334 .matchEthDst(Constants.DEFAULT_GATEWAY_MAC);
335
336 switch (osNet.getNetworkType()) {
337 case VXLAN:
338 sBuilder.matchTunnelId(Long.parseLong(osNet.getProviderSegID()));
339 break;
340 case VLAN:
341 sBuilder.matchVlanId(VlanId.vlanId(osNet.getProviderSegID()));
342 break;
343 default:
344 final String error = String.format(
Ray Milkeyc6c9b172018-02-26 09:36:31 -0800345 ERR_UNSUPPORTED_NET_TYPE,
daniel parkeeb8e042018-02-21 14:06:58 +0900346 osNet.getNetworkType().toString());
347 throw new IllegalStateException(error);
348 }
349
Jian Li1064e4f2018-05-29 16:16:53 +0900350 OpenstackNode selectedGatewayNode = getGwByComputeDevId(gateways, instPort.deviceId());
351
daniel parkeeb8e042018-02-21 14:06:58 +0900352 if (selectedGatewayNode == null) {
daniel parkc2a2ed62018-04-10 15:17:42 +0900353 final String errorFormat = ERR_FLOW + "no gateway node selected";
354 throw new IllegalStateException(errorFormat);
daniel parkeeb8e042018-02-21 14:06:58 +0900355 }
356 treatment = DefaultTrafficTreatment.builder()
357 .extension(buildExtension(
358 deviceService,
359 instPort.deviceId(),
360 selectedGatewayNode.dataIp().getIp4Address()),
361 instPort.deviceId())
362 .setOutput(osNodeService.node(instPort.deviceId()).tunnelPortNum())
363 .build();
364
365 osFlowRuleService.setRule(
366 appId,
367 instPort.deviceId(),
368 sBuilder.build(),
369 treatment,
370 PRIORITY_EXTERNAL_FLOATING_ROUTING_RULE,
371 ROUTING_TABLE,
372 install);
daniel parkc2a2ed62018-04-10 15:17:42 +0900373 log.trace("Succeeded to set flow rules from compute node to gateway on compute node");
daniel parkeeb8e042018-02-21 14:06:58 +0900374 }
375
Jian Lide679782018-06-05 01:41:29 +0900376 private void setDownstreamExternalRulesHelper(NetFloatingIP floatingIp,
377 Network osNet,
378 InstancePort instPort,
379 ExternalPeerRouter externalPeerRouter,
380 Set<OpenstackNode> gateways, boolean install) {
381 OpenstackNode cNode = osNodeService.node(instPort.deviceId());
382 if (cNode == null) {
383 final String error = String.format("Cannot find openstack node for device %s",
384 instPort.deviceId());
385 throw new IllegalStateException(error);
386 }
387 if (osNet.getNetworkType() == NetworkType.VXLAN && cNode.dataIp() == null) {
388 final String errorFormat = ERR_FLOW + "VXLAN mode is not ready for %s";
389 final String error = String.format(errorFormat, floatingIp, cNode.hostname());
390 throw new IllegalStateException(error);
391 }
392 if (osNet.getNetworkType() == NetworkType.VLAN && cNode.vlanIntf() == null) {
393 final String errorFormat = ERR_FLOW + "VLAN mode is not ready for %s";
394 final String error = String.format(errorFormat, floatingIp, cNode.hostname());
395 throw new IllegalStateException(error);
396 }
397
398 IpAddress floating = IpAddress.valueOf(floatingIp.getFloatingIpAddress());
399
400 OpenstackNode selectedGatewayNode = getGwByComputeDevId(gateways, instPort.deviceId());
401
402 if (selectedGatewayNode == null) {
403 final String errorFormat = ERR_FLOW + "no gateway node selected";
404 throw new IllegalStateException(errorFormat);
405 }
406
407 TrafficSelector.Builder externalSelectorBuilder = DefaultTrafficSelector.builder()
408 .matchEthType(Ethernet.TYPE_IPV4)
Daniel Park319b9ab2018-09-14 11:27:04 +0900409 .matchInPort(selectedGatewayNode.uplinkPortNum())
Jian Lide679782018-06-05 01:41:29 +0900410 .matchIPDst(floating.toIpPrefix());
411
412 TrafficTreatment.Builder externalTreatmentBuilder = DefaultTrafficTreatment.builder()
413 .setEthSrc(Constants.DEFAULT_GATEWAY_MAC)
414 .setEthDst(instPort.macAddress())
415 .setIpDst(instPort.ipAddress().getIp4Address());
416
Jian Li5e2ad4a2018-07-16 13:40:53 +0900417 if (!externalPeerRouter.vlanId().equals(VlanId.NONE)) {
418 externalSelectorBuilder.matchVlanId(externalPeerRouter.vlanId()).build();
Jian Lide679782018-06-05 01:41:29 +0900419 externalTreatmentBuilder.popVlan();
420 }
421
422 switch (osNet.getNetworkType()) {
423 case VXLAN:
424 externalTreatmentBuilder.setTunnelId(Long.valueOf(osNet.getProviderSegID()))
425 .extension(buildExtension(
426 deviceService,
427 selectedGatewayNode.intgBridge(),
428 cNode.dataIp().getIp4Address()),
429 selectedGatewayNode.intgBridge())
430 .setOutput(selectedGatewayNode.tunnelPortNum());
431 break;
432 case VLAN:
433 externalTreatmentBuilder.pushVlan()
434 .setVlanId(VlanId.vlanId(osNet.getProviderSegID()))
435 .setOutput(selectedGatewayNode.vlanPortNum());
436 break;
437 default:
438 final String error = String.format(ERR_UNSUPPORTED_NET_TYPE,
439 osNet.getNetworkType());
440 throw new IllegalStateException(error);
441 }
442
443 osFlowRuleService.setRule(
444 appId,
445 selectedGatewayNode.intgBridge(),
446 externalSelectorBuilder.build(),
447 externalTreatmentBuilder.build(),
448 PRIORITY_FLOATING_EXTERNAL,
449 GW_COMMON_TABLE,
450 install);
451 }
452
Hyunsun Moon44aac662017-02-18 02:07:01 +0900453 private void setUpstreamRules(NetFloatingIP floatingIp, Network osNet,
daniel park32b42202018-03-14 16:53:44 +0900454 InstancePort instPort, ExternalPeerRouter externalPeerRouter,
455 boolean install) {
Hyunsun Moon44aac662017-02-18 02:07:01 +0900456 IpAddress floating = IpAddress.valueOf(floatingIp.getFloatingIpAddress());
daniel parkee8700b2017-05-11 15:50:03 +0900457 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder()
Hyunsun Moon44aac662017-02-18 02:07:01 +0900458 .matchEthType(Ethernet.TYPE_IPV4)
daniel parkee8700b2017-05-11 15:50:03 +0900459 .matchIPSrc(instPort.ipAddress().toIpPrefix());
460
461 switch (osNet.getNetworkType()) {
462 case VXLAN:
463 sBuilder.matchTunnelId(Long.valueOf(osNet.getProviderSegID()));
464 break;
465 case VLAN:
466 sBuilder.matchVlanId(VlanId.vlanId(osNet.getProviderSegID()));
467 break;
468 default:
Ray Milkeyc6c9b172018-02-26 09:36:31 -0800469 final String error = String.format(ERR_UNSUPPORTED_NET_TYPE,
Hyunsun Moon0d457362017-06-27 17:19:41 +0900470 osNet.getNetworkType());
daniel parkee8700b2017-05-11 15:50:03 +0900471 throw new IllegalStateException(error);
472 }
Hyunsun Moon44aac662017-02-18 02:07:01 +0900473
Daniel Park75e3d7f2018-05-29 14:43:53 +0900474 TrafficSelector selector = sBuilder.build();
daniel parkeeb8e042018-02-21 14:06:58 +0900475
Hyunsun Moon0d457362017-06-27 17:19:41 +0900476 osNodeService.completeNodes(GATEWAY).forEach(gNode -> {
Daniel Park75e3d7f2018-05-29 14:43:53 +0900477 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder()
478 .setIpSrc(floating.getIp4Address())
479 .setEthSrc(instPort.macAddress())
Jian Li5e2ad4a2018-07-16 13:40:53 +0900480 .setEthDst(externalPeerRouter.macAddress());
Hyunsun Moon44aac662017-02-18 02:07:01 +0900481
Daniel Park75e3d7f2018-05-29 14:43:53 +0900482 if (osNet.getNetworkType().equals(NetworkType.VLAN)) {
483 tBuilder.popVlan();
484 }
485
Jian Li5e2ad4a2018-07-16 13:40:53 +0900486 if (!externalPeerRouter.vlanId().equals(VlanId.NONE)) {
487 tBuilder.pushVlan().setVlanId(externalPeerRouter.vlanId());
Daniel Park75e3d7f2018-05-29 14:43:53 +0900488 }
sanghodc375372017-06-08 10:41:30 +0900489 osFlowRuleService.setRule(
Hyunsun Moon44aac662017-02-18 02:07:01 +0900490 appId,
Hyunsun Moon0d457362017-06-27 17:19:41 +0900491 gNode.intgBridge(),
Daniel Park75e3d7f2018-05-29 14:43:53 +0900492 selector,
daniel parkeeb8e042018-02-21 14:06:58 +0900493 tBuilder.setOutput(gNode.uplinkPortNum()).build(),
Hyunsun Moon44aac662017-02-18 02:07:01 +0900494 PRIORITY_FLOATING_EXTERNAL,
sanghodc375372017-06-08 10:41:30 +0900495 GW_COMMON_TABLE,
Hyunsun Moon44aac662017-02-18 02:07:01 +0900496 install);
Daniel Park75e3d7f2018-05-29 14:43:53 +0900497 });
daniel parkc2a2ed62018-04-10 15:17:42 +0900498 log.trace("Succeeded to set flow rules for upstream on gateway nodes");
Hyunsun Moon44aac662017-02-18 02:07:01 +0900499 }
500
daniel park32b42202018-03-14 16:53:44 +0900501 private ExternalPeerRouter externalPeerRouter(Network network) {
daniel parkeeb8e042018-02-21 14:06:58 +0900502 if (network == null) {
503 return null;
504 }
505
506 Subnet subnet = osNetworkService.subnets(network.getId()).stream().findAny().orElse(null);
507
508 if (subnet == null) {
509 return null;
510 }
511
Jian Lif3a28b02018-06-11 21:29:13 +0900512 RouterInterface osRouterIface = osRouterAdminService.routerInterfaces().stream()
daniel parkeeb8e042018-02-21 14:06:58 +0900513 .filter(i -> Objects.equals(i.getSubnetId(), subnet.getId()))
514 .findAny().orElse(null);
515 if (osRouterIface == null) {
516 return null;
517 }
518
Jian Lif3a28b02018-06-11 21:29:13 +0900519 Router osRouter = osRouterAdminService.router(osRouterIface.getId());
daniel parkeeb8e042018-02-21 14:06:58 +0900520 if (osRouter == null) {
521 return null;
522 }
523 if (osRouter.getExternalGatewayInfo() == null) {
524 return null;
525 }
526
527 ExternalGateway exGatewayInfo = osRouter.getExternalGatewayInfo();
daniel park65e1c202018-04-03 13:15:28 +0900528 return osNetworkService.externalPeerRouter(exGatewayInfo);
daniel parkeeb8e042018-02-21 14:06:58 +0900529 }
daniel park65e1c202018-04-03 13:15:28 +0900530
Jian Li99892e92018-04-13 14:59:39 +0900531 private void associateFloatingIp(NetFloatingIP osFip) {
Jian Li628a7cb2018-08-11 23:04:24 +0900532 InstancePort instPort = instancePortService.instancePort(osFip.getPortId());
533
534 if (instPort == null) {
535 log.warn("Failed to insert floating IP rule for {} due to missing of port info.",
536 osFip.getFloatingIpAddress());
537 return;
Jian Li99892e92018-04-13 14:59:39 +0900538 }
Jian Li628a7cb2018-08-11 23:04:24 +0900539
Jian Li99892e92018-04-13 14:59:39 +0900540 // set floating IP rules only if the port is associated to a VM
Jian Li628a7cb2018-08-11 23:04:24 +0900541 if (!Strings.isNullOrEmpty(instPort.deviceId().toString())) {
542 setFloatingIpRules(osFip, instPort, null, true);
Jian Li99892e92018-04-13 14:59:39 +0900543 }
544 }
545
546 private void disassociateFloatingIp(NetFloatingIP osFip, String portId) {
Jian Li628a7cb2018-08-11 23:04:24 +0900547 InstancePort instPort = instancePortService.instancePort(portId);
Jian Lie1a39032018-06-19 21:49:36 +0900548
Jian Li628a7cb2018-08-11 23:04:24 +0900549 if (instPort == null) {
550 log.warn("Failed to remove floating IP rule for {} due to missing of port info.",
551 osFip.getFloatingIpAddress());
552 return;
Jian Lie1a39032018-06-19 21:49:36 +0900553 }
554
Jian Li99892e92018-04-13 14:59:39 +0900555 // set floating IP rules only if the port is associated to a VM
Jian Li628a7cb2018-08-11 23:04:24 +0900556 if (!Strings.isNullOrEmpty(instPort.deviceId().toString())) {
557 setFloatingIpRules(osFip, instPort, null, false);
Jian Li99892e92018-04-13 14:59:39 +0900558 }
559 }
560
Hyunsun Moon0d457362017-06-27 17:19:41 +0900561 private class InternalFloatingIpListener implements OpenstackRouterListener {
Hyunsun Moon44aac662017-02-18 02:07:01 +0900562
563 @Override
564 public boolean isRelevant(OpenstackRouterEvent event) {
565 // do not allow to proceed without leadership
566 NodeId leader = leadershipService.getLeader(appId.name());
567 if (!Objects.equals(localNodeId, leader)) {
568 return false;
569 }
570 return event.floatingIp() != null;
571 }
572
573 @Override
574 public void event(OpenstackRouterEvent event) {
575 switch (event.type()) {
576 case OPENSTACK_FLOATING_IP_ASSOCIATED:
Hyunsun Moon7a5f9042017-05-11 18:19:01 +0900577 eventExecutor.execute(() -> {
Hyunsun Moonb720e632017-05-16 15:41:36 +0900578 NetFloatingIP osFip = event.floatingIp();
Jian Li0488c732018-09-14 20:53:07 +0900579 if (instancePortService.instancePort(osFip.getPortId()) != null) {
580 associateFloatingIp(osFip);
581 log.info("Associated floating IP {}:{}",
582 osFip.getFloatingIpAddress(),
583 osFip.getFixedIpAddress());
584 }
Hyunsun Moon7a5f9042017-05-11 18:19:01 +0900585 });
586 break;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900587 case OPENSTACK_FLOATING_IP_DISASSOCIATED:
588 eventExecutor.execute(() -> {
Hyunsun Moonb720e632017-05-16 15:41:36 +0900589 NetFloatingIP osFip = event.floatingIp();
Jian Li0488c732018-09-14 20:53:07 +0900590 if (instancePortService.instancePort(event.portId()) != null) {
591 disassociateFloatingIp(osFip, event.portId());
592 log.info("Disassociated floating IP {}:{}",
593 osFip.getFloatingIpAddress(),
594 osFip.getFixedIpAddress());
595 }
Hyunsun Moon7a5f9042017-05-11 18:19:01 +0900596 });
597 break;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900598 case OPENSTACK_FLOATING_IP_CREATED:
Hyunsun Moonb720e632017-05-16 15:41:36 +0900599 eventExecutor.execute(() -> {
600 NetFloatingIP osFip = event.floatingIp();
Jian Li0488c732018-09-14 20:53:07 +0900601 String portId = osFip.getPortId();
602 if (!Strings.isNullOrEmpty(portId) &&
603 instancePortService.instancePort(portId) != null) {
Hyunsun Moonb720e632017-05-16 15:41:36 +0900604 associateFloatingIp(event.floatingIp());
605 }
606 log.info("Created floating IP {}", osFip.getFloatingIpAddress());
607 });
608 break;
Jian Lia171a432018-06-11 11:52:11 +0900609 case OPENSTACK_FLOATING_IP_REMOVED:
610 eventExecutor.execute(() -> {
611 NetFloatingIP osFip = event.floatingIp();
Jian Li0488c732018-09-14 20:53:07 +0900612 String portId = osFip.getPortId();
Jian Lia171a432018-06-11 11:52:11 +0900613 if (!Strings.isNullOrEmpty(osFip.getPortId())) {
Jian Lic2403592018-07-18 12:56:45 +0900614 // in case the floating IP is not associated with any port due to
615 // port removal, we simply do not execute floating IP disassociation
Jian Li0488c732018-09-14 20:53:07 +0900616 if (osNetworkService.port(portId) != null &&
617 instancePortService.instancePort(portId) != null) {
618 disassociateFloatingIp(osFip, portId);
Jian Lic2403592018-07-18 12:56:45 +0900619 }
Jian Lida03ce92018-07-24 21:41:53 +0900620
621 // since we skip floating IP disassociation, we need to
622 // manually unsubscribe the port pre-remove event
623 preCommitPortService.unsubscribePreCommit(osFip.getPortId(),
Jian Li628a7cb2018-08-11 23:04:24 +0900624 OPENSTACK_PORT_PRE_REMOVE, instancePortService,
625 this.getClass().getName());
Jian Lida03ce92018-07-24 21:41:53 +0900626 log.info("Unsubscribed the port {} on listening pre-remove event", osFip.getPortId());
Jian Lia171a432018-06-11 11:52:11 +0900627 }
628 log.info("Removed floating IP {}", osFip.getFloatingIpAddress());
629 });
630 break;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900631 case OPENSTACK_FLOATING_IP_UPDATED:
Hyunsun Moon44aac662017-02-18 02:07:01 +0900632 case OPENSTACK_ROUTER_CREATED:
633 case OPENSTACK_ROUTER_UPDATED:
634 case OPENSTACK_ROUTER_REMOVED:
635 case OPENSTACK_ROUTER_INTERFACE_ADDED:
636 case OPENSTACK_ROUTER_INTERFACE_UPDATED:
637 case OPENSTACK_ROUTER_INTERFACE_REMOVED:
638 default:
639 // do nothing for the other events
640 break;
641 }
642 }
643 }
644
645 private class InternalNodeListener implements OpenstackNodeListener {
646
647 @Override
648 public boolean isRelevant(OpenstackNodeEvent event) {
649 // do not allow to proceed without leadership
650 NodeId leader = leadershipService.getLeader(appId.name());
651 if (!Objects.equals(localNodeId, leader)) {
652 return false;
653 }
654 return event.subject().type() == GATEWAY;
655 }
656
657 @Override
658 public void event(OpenstackNodeEvent event) {
Hyunsun Moon44aac662017-02-18 02:07:01 +0900659
660 switch (event.type()) {
Hyunsun Moon0d457362017-06-27 17:19:41 +0900661 case OPENSTACK_NODE_COMPLETE:
Hyunsun Moon44aac662017-02-18 02:07:01 +0900662 eventExecutor.execute(() -> {
Jian Lif3a28b02018-06-11 21:29:13 +0900663 for (NetFloatingIP fip : osRouterAdminService.floatingIps()) {
Jian Lie1a39032018-06-19 21:49:36 +0900664
Hyunsun Moon7a5f9042017-05-11 18:19:01 +0900665 if (Strings.isNullOrEmpty(fip.getPortId())) {
666 continue;
667 }
Jian Lie1a39032018-06-19 21:49:36 +0900668
Hyunsun Moon7a5f9042017-05-11 18:19:01 +0900669 Port osPort = osNetworkService.port(fip.getPortId());
Jian Li628a7cb2018-08-11 23:04:24 +0900670 InstancePort instPort = instancePortService.instancePort(fip.getPortId());
671
672 // we check both Openstack Port and Instance Port
673 if (osPort == null || instPort == null) {
Hyunsun Moon7a5f9042017-05-11 18:19:01 +0900674 continue;
675 }
Jian Lie1a39032018-06-19 21:49:36 +0900676
Jian Li628a7cb2018-08-11 23:04:24 +0900677 setFloatingIpRules(fip, instPort, event.subject(), true);
Hyunsun Moon7a5f9042017-05-11 18:19:01 +0900678 }
Hyunsun Moon44aac662017-02-18 02:07:01 +0900679 });
680 break;
Hyunsun Moon0d457362017-06-27 17:19:41 +0900681 case OPENSTACK_NODE_INCOMPLETE:
Jian Li1064e4f2018-05-29 16:16:53 +0900682 eventExecutor.execute(() -> {
Jian Lif3a28b02018-06-11 21:29:13 +0900683 for (NetFloatingIP fip : osRouterAdminService.floatingIps()) {
Jian Li1064e4f2018-05-29 16:16:53 +0900684 if (Strings.isNullOrEmpty(fip.getPortId())) {
685 continue;
686 }
687 Port osPort = osNetworkService.port(fip.getPortId());
688 if (osPort == null) {
689 log.warn("Failed to set floating IP {}", fip.getId());
690 continue;
691 }
692 Network osNet = osNetworkService.network(osPort.getNetworkId());
693 if (osNet == null) {
694 final String errorFormat = ERR_FLOW + "no network(%s) exists";
695 final String error = String.format(errorFormat,
696 fip.getFloatingIpAddress(),
697 osPort.getNetworkId());
698 throw new IllegalStateException(error);
699 }
700 MacAddress srcMac = MacAddress.valueOf(osPort.getMacAddress());
701 log.trace("Mac address of openstack port: {}", srcMac);
702 InstancePort instPort = instancePortService.instancePort(srcMac);
703
704 if (instPort == null) {
705 final String errorFormat = ERR_FLOW + "no host(MAC:%s) found";
706 final String error = String.format(errorFormat,
707 fip.getFloatingIpAddress(), srcMac);
708 throw new IllegalStateException(error);
709 }
710
Jian Lide679782018-06-05 01:41:29 +0900711 ExternalPeerRouter externalPeerRouter = externalPeerRouter(osNet);
712 if (externalPeerRouter == null) {
713 final String errorFormat = ERR_FLOW + "no external peer router found";
714 throw new IllegalStateException(errorFormat);
715 }
716
717 updateComputeNodeRules(instPort, osNet, event.subject(), false);
718 updateGatewayNodeRules(fip, instPort, osNet,
719 externalPeerRouter, event.subject(), false);
Jian Li1064e4f2018-05-29 16:16:53 +0900720 }
721 });
722 break;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900723 default:
Hyunsun Moon0d457362017-06-27 17:19:41 +0900724 // do nothing
Hyunsun Moon44aac662017-02-18 02:07:01 +0900725 break;
726 }
727 }
728 }
Jian Li99892e92018-04-13 14:59:39 +0900729
Jian Li24ec59f2018-05-23 19:01:25 +0900730 private class InternalInstancePortListener implements InstancePortListener {
731
732 @Override
733 public boolean isRelevant(InstancePortEvent event) {
Jian Li24ec59f2018-05-23 19:01:25 +0900734
Jian Lie1a39032018-06-19 21:49:36 +0900735 if (event.type() == OPENSTACK_INSTANCE_MIGRATION_ENDED ||
736 event.type() == OPENSTACK_INSTANCE_MIGRATION_STARTED) {
737 Set<NetFloatingIP> ips = osRouterAdminService.floatingIps();
738 NetFloatingIP fip = associatedFloatingIp(event.subject(), ips);
739
740 // we check the possible NPE to avoid duplicated null check
741 // for OPENSTACK_INSTANCE_MIGRATION_ENDED and
742 // OPENSTACK_INSTANCE_MIGRATION_STARTED cases
743 if (fip == null || !isAssociatedWithVM(osNetworkService, fip)) {
744 return false;
745 }
746 }
747
748 // do not allow to proceed without leadership
749 NodeId leader = leadershipService.getLeader(appId.name());
750
751 return Objects.equals(localNodeId, leader);
Jian Li24ec59f2018-05-23 19:01:25 +0900752 }
753
754 @Override
755 public void event(InstancePortEvent event) {
Jian Lie1a39032018-06-19 21:49:36 +0900756 InstancePort instPort = event.subject();
Jian Li24ec59f2018-05-23 19:01:25 +0900757 Set<OpenstackNode> gateways = osNodeService.completeNodes(GATEWAY);
758
Jian Lie1a39032018-06-19 21:49:36 +0900759 Set<NetFloatingIP> ips = osRouterAdminService.floatingIps();
760 NetFloatingIP fip;
761 Port osPort;
762 Network osNet;
763 ExternalPeerRouter externalPeerRouter;
Jian Li24ec59f2018-05-23 19:01:25 +0900764
765 switch (event.type()) {
Jian Lie1a39032018-06-19 21:49:36 +0900766 case OPENSTACK_INSTANCE_PORT_DETECTED:
Jian Li77323c52018-06-24 01:26:18 +0900767 if (instPort != null && instPort.portId() != null) {
Jian Li46b74002018-07-15 18:39:08 +0900768 osRouterAdminService.floatingIps().stream()
769 .filter(f -> f.getPortId() != null)
770 .filter(f -> f.getPortId().equals(instPort.portId()))
Jian Li628a7cb2018-08-11 23:04:24 +0900771 .forEach(f -> setFloatingIpRules(f, instPort, null, true));
Jian Lie1a39032018-06-19 21:49:36 +0900772 }
773
774 break;
775
Jian Li24ec59f2018-05-23 19:01:25 +0900776 case OPENSTACK_INSTANCE_MIGRATION_STARTED:
Jian Lie1a39032018-06-19 21:49:36 +0900777
778 fip = associatedFloatingIp(event.subject(), ips);
779
780 if (fip == null) {
781 return;
782 }
783
784 osPort = osNetworkService.port(fip.getPortId());
785 osNet = osNetworkService.network(osPort.getNetworkId());
786 externalPeerRouter = externalPeerRouter(osNet);
787
788 if (externalPeerRouter == null) {
789 final String errorFormat = ERR_FLOW + "no external peer router found";
790 throw new IllegalStateException(errorFormat);
791 }
792
Jian Li24ec59f2018-05-23 19:01:25 +0900793 eventExecutor.execute(() -> {
794
Jian Li24ec59f2018-05-23 19:01:25 +0900795 // since DownstreamExternal rules should only be placed in
796 // corresponding gateway node, we need to install new rule to
797 // the corresponding gateway node
798 setDownstreamExternalRulesHelper(fip, osNet,
799 event.subject(), externalPeerRouter, gateways, true);
800
801 // since ComputeNodeToGateway rules should only be placed in
802 // corresponding compute node, we need to install new rule to
803 // the target compute node, and remove rules from original node
804 setComputeNodeToGatewayHelper(event.subject(), osNet, gateways, true);
Jian Li24ec59f2018-05-23 19:01:25 +0900805 });
806 break;
807 case OPENSTACK_INSTANCE_MIGRATION_ENDED:
808
Jian Liec5c32b2018-07-13 14:28:58 +0900809 InstancePort revisedInstPort = swapStaleLocation(event.subject());
810
811 fip = associatedFloatingIp(revisedInstPort, ips);
Jian Lie1a39032018-06-19 21:49:36 +0900812
813 if (fip == null) {
814 return;
815 }
816
817 osPort = osNetworkService.port(fip.getPortId());
818 osNet = osNetworkService.network(osPort.getNetworkId());
819 externalPeerRouter = externalPeerRouter(osNet);
820
821 if (externalPeerRouter == null) {
822 final String errorFormat = ERR_FLOW + "no external peer router found";
823 throw new IllegalStateException(errorFormat);
824 }
825
826 // If we only have one gateway, we simply do not remove any
Jian Li24ec59f2018-05-23 19:01:25 +0900827 // flow rules from either gateway or compute node
828 if (gateways.size() == 1) {
829 return;
830 }
831
Jian Lie1a39032018-06-19 21:49:36 +0900832 // Checks whether the destination compute node's device id
Jian Li24ec59f2018-05-23 19:01:25 +0900833 // has identical gateway hash or not
834 // if it is true, we simply do not remove the rules, as
835 // it has been overwritten at port detention event
836 // if it is false, we will remove the rules
Jian Liec5c32b2018-07-13 14:28:58 +0900837 DeviceId newDeviceId = event.subject().deviceId();
838 DeviceId oldDeviceId = revisedInstPort.deviceId();
Jian Li24ec59f2018-05-23 19:01:25 +0900839
840 OpenstackNode oldGateway = getGwByComputeDevId(gateways, oldDeviceId);
841 OpenstackNode newGateway = getGwByComputeDevId(gateways, newDeviceId);
842
843 if (oldGateway != null && oldGateway.equals(newGateway)) {
844 return;
845 }
846
847 eventExecutor.execute(() -> {
848
Jian Lie1a39032018-06-19 21:49:36 +0900849 // We need to remove the old ComputeNodeToGateway rules from
Jian Li24ec59f2018-05-23 19:01:25 +0900850 // original compute node
Jian Liec5c32b2018-07-13 14:28:58 +0900851 setComputeNodeToGatewayHelper(revisedInstPort, osNet, gateways, false);
Jian Li24ec59f2018-05-23 19:01:25 +0900852
Jian Lie1a39032018-06-19 21:49:36 +0900853 // Since DownstreamExternal rules should only be placed in
Jian Li24ec59f2018-05-23 19:01:25 +0900854 // corresponding gateway node, we need to remove old rule from
855 // the corresponding gateway node
Jian Liec5c32b2018-07-13 14:28:58 +0900856 setDownstreamExternalRulesHelper(fip, osNet, revisedInstPort,
857 externalPeerRouter, gateways, false);
Jian Li24ec59f2018-05-23 19:01:25 +0900858 });
859 break;
860 default:
861 break;
862 }
863 }
864 }
Jian Lie1a39032018-06-19 21:49:36 +0900865
866 private class InternalOpenstackNetworkListener implements OpenstackNetworkListener {
867
868 @Override
869 public boolean isRelevant(OpenstackNetworkEvent event) {
870 // do not allow to proceed without leadership
871 NodeId leader = leadershipService.getLeader(appId.name());
Jian Lida03ce92018-07-24 21:41:53 +0900872 return Objects.equals(localNodeId, leader);
Jian Lie1a39032018-06-19 21:49:36 +0900873 }
874
875 @Override
876 public void event(OpenstackNetworkEvent event) {
877 switch (event.type()) {
Jian Li8f64feb2018-07-24 13:20:16 +0900878 case OPENSTACK_PORT_PRE_REMOVE:
Jian Li427811e2018-08-28 17:35:16 +0900879 InstancePort instPort =
880 instancePortService.instancePort(event.port().getId());
Jian Libcc42282018-09-13 20:59:34 +0900881
882 if (instPort == null) {
883 break;
884 }
885
Jian Li427811e2018-08-28 17:35:16 +0900886 NetFloatingIP fip =
887 associatedFloatingIp(instPort, osRouterAdminService.floatingIps());
888
Jian Li9d35bd62018-10-13 01:43:24 +0900889 boolean sgFlag = getPropertyValueAsBoolean(
890 componentConfigService.getProperties(
891 OpenstackSecurityGroupHandler.class.getName()),
892 USE_SECURITY_GROUP);
893
Jian Li427811e2018-08-28 17:35:16 +0900894 if (fip != null) {
Jian Li9d35bd62018-10-13 01:43:24 +0900895 instancePortService.updateInstancePort(
896 instPort.updateState(REMOVE_PENDING));
Jian Li2360acb2018-10-17 00:46:31 +0900897 eventExecutor.execute(() -> updateFipStore(event.port().getId()));
Jian Li427811e2018-08-28 17:35:16 +0900898 } else {
Jian Li9d35bd62018-10-13 01:43:24 +0900899 // FIXME: we have dependency with security group, need to
900 // find a better way to remove this dependency
901 if (!sgFlag) {
902 instancePortService.removeInstancePort(instPort.portId());
903 }
Jian Li427811e2018-08-28 17:35:16 +0900904 }
Jian Li8f64feb2018-07-24 13:20:16 +0900905 break;
Jian Lie1a39032018-06-19 21:49:36 +0900906 default:
907 break;
908 }
909 }
910
Jian Li2360acb2018-10-17 00:46:31 +0900911 private void updateFipStore(String portId) {
Jian Lie1a39032018-06-19 21:49:36 +0900912
Jian Li2360acb2018-10-17 00:46:31 +0900913 if (portId == null) {
Jian Lie1a39032018-06-19 21:49:36 +0900914 return;
915 }
916
917 Set<NetFloatingIP> ips = osRouterAdminService.floatingIps();
918 for (NetFloatingIP fip : ips) {
919 if (Strings.isNullOrEmpty(fip.getFixedIpAddress())) {
920 continue;
921 }
922 if (Strings.isNullOrEmpty(fip.getFloatingIpAddress())) {
923 continue;
924 }
Jian Li2360acb2018-10-17 00:46:31 +0900925 if (fip.getPortId().equals(portId)) {
Jian Lie1a39032018-06-19 21:49:36 +0900926 NeutronFloatingIP neutronFip = (NeutronFloatingIP) fip;
927 // invalidate bound fixed IP and port
928 neutronFip.setFixedIpAddress(null);
929 neutronFip.setPortId(null);
Jian Lie1a39032018-06-19 21:49:36 +0900930
931 // Following update will in turn trigger
932 // OPENSTACK_FLOATING_IP_DISASSOCIATED event
933 osRouterAdminService.updateFloatingIp(neutronFip);
934 log.info("Updated floating IP {}, due to host removal",
935 neutronFip.getFloatingIpAddress());
936 }
937 }
938 }
939 }
Hyunsun Moon44aac662017-02-18 02:07:01 +0900940}