blob: 8a59d36c8c8ccadec95da32f1c653acbee03f27e [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;
Hyunsun Moon44aac662017-02-18 02:07:01 +090030import org.onosproject.cluster.ClusterService;
31import org.onosproject.cluster.LeadershipService;
32import org.onosproject.cluster.NodeId;
33import org.onosproject.core.ApplicationId;
34import org.onosproject.core.CoreService;
Jian Li24ec59f2018-05-23 19:01:25 +090035import org.onosproject.net.DeviceId;
Hyunsun Moon44aac662017-02-18 02:07:01 +090036import org.onosproject.net.device.DeviceService;
37import org.onosproject.net.flow.DefaultTrafficSelector;
38import org.onosproject.net.flow.DefaultTrafficTreatment;
39import org.onosproject.net.flow.TrafficSelector;
40import org.onosproject.net.flow.TrafficTreatment;
Hyunsun Moon44aac662017-02-18 02:07:01 +090041import org.onosproject.openstacknetworking.api.Constants;
daniel park32b42202018-03-14 16:53:44 +090042import org.onosproject.openstacknetworking.api.ExternalPeerRouter;
Hyunsun Moon44aac662017-02-18 02:07:01 +090043import org.onosproject.openstacknetworking.api.InstancePort;
Jian Liec5c32b2018-07-13 14:28:58 +090044import org.onosproject.openstacknetworking.api.InstancePortAdminService;
Jian Li24ec59f2018-05-23 19:01:25 +090045import org.onosproject.openstacknetworking.api.InstancePortEvent;
46import org.onosproject.openstacknetworking.api.InstancePortListener;
sanghodc375372017-06-08 10:41:30 +090047import org.onosproject.openstacknetworking.api.OpenstackFlowRuleService;
Jian Lie1a39032018-06-19 21:49:36 +090048import org.onosproject.openstacknetworking.api.OpenstackNetworkEvent;
49import org.onosproject.openstacknetworking.api.OpenstackNetworkListener;
sanghodc375372017-06-08 10:41:30 +090050import org.onosproject.openstacknetworking.api.OpenstackNetworkService;
Jian Lif3a28b02018-06-11 21:29:13 +090051import org.onosproject.openstacknetworking.api.OpenstackRouterAdminService;
Hyunsun Moon44aac662017-02-18 02:07:01 +090052import org.onosproject.openstacknetworking.api.OpenstackRouterEvent;
53import org.onosproject.openstacknetworking.api.OpenstackRouterListener;
Jian Li8f64feb2018-07-24 13:20:16 +090054import org.onosproject.openstacknetworking.api.PreCommitPortService;
Hyunsun Moon0d457362017-06-27 17:19:41 +090055import org.onosproject.openstacknode.api.OpenstackNode;
56import org.onosproject.openstacknode.api.OpenstackNodeEvent;
57import org.onosproject.openstacknode.api.OpenstackNodeListener;
58import org.onosproject.openstacknode.api.OpenstackNodeService;
daniel parkeeb8e042018-02-21 14:06:58 +090059import org.openstack4j.model.network.ExternalGateway;
Hyunsun Moon44aac662017-02-18 02:07:01 +090060import org.openstack4j.model.network.NetFloatingIP;
61import org.openstack4j.model.network.Network;
daniel parkee8700b2017-05-11 15:50:03 +090062import org.openstack4j.model.network.NetworkType;
Hyunsun Moon44aac662017-02-18 02:07:01 +090063import org.openstack4j.model.network.Port;
daniel parkeeb8e042018-02-21 14:06:58 +090064import org.openstack4j.model.network.Router;
65import org.openstack4j.model.network.RouterInterface;
66import org.openstack4j.model.network.Subnet;
Jian Lif3a28b02018-06-11 21:29:13 +090067import org.openstack4j.openstack.networking.domain.NeutronFloatingIP;
Hyunsun Moon44aac662017-02-18 02:07:01 +090068import org.slf4j.Logger;
69import org.slf4j.LoggerFactory;
70
71import java.util.Objects;
Jian Li99892e92018-04-13 14:59:39 +090072import java.util.Set;
Hyunsun Moon44aac662017-02-18 02:07:01 +090073import java.util.concurrent.ExecutorService;
74
75import static java.util.concurrent.Executors.newSingleThreadExecutor;
76import static org.onlab.util.Tools.groupedThreads;
sanghodc375372017-06-08 10:41:30 +090077import static org.onosproject.openstacknetworking.api.Constants.GW_COMMON_TABLE;
78import static org.onosproject.openstacknetworking.api.Constants.OPENSTACK_NETWORKING_APP_ID;
daniel parkeeb8e042018-02-21 14:06:58 +090079import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_EXTERNAL_FLOATING_ROUTING_RULE;
sanghodc375372017-06-08 10:41:30 +090080import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_FLOATING_EXTERNAL;
daniel parkeeb8e042018-02-21 14:06:58 +090081import static org.onosproject.openstacknetworking.api.Constants.ROUTING_TABLE;
Jian Li8a5fb642018-09-14 15:50:04 +090082import static org.onosproject.openstacknetworking.api.InstancePort.State.REMOVE_PENDING;
Jian Lie1a39032018-06-19 21:49:36 +090083import static org.onosproject.openstacknetworking.api.InstancePortEvent.Type.OPENSTACK_INSTANCE_MIGRATION_ENDED;
84import static org.onosproject.openstacknetworking.api.InstancePortEvent.Type.OPENSTACK_INSTANCE_MIGRATION_STARTED;
Jian Li8f64feb2018-07-24 13:20:16 +090085import static org.onosproject.openstacknetworking.api.OpenstackNetworkEvent.Type.OPENSTACK_PORT_PRE_REMOVE;
Jian Li24ec59f2018-05-23 19:01:25 +090086import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.associatedFloatingIp;
Jian Li1064e4f2018-05-29 16:16:53 +090087import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.getGwByComputeDevId;
Jian Li24ec59f2018-05-23 19:01:25 +090088import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.isAssociatedWithVM;
Jian Liec5c32b2018-07-13 14:28:58 +090089import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.swapStaleLocation;
Jian Li26949762018-03-30 15:46:37 +090090import static org.onosproject.openstacknetworking.util.RulePopulatorUtil.buildExtension;
Hyunsun Moon0d457362017-06-27 17:19:41 +090091import static org.onosproject.openstacknode.api.OpenstackNode.NodeType.GATEWAY;
Hyunsun Moon44aac662017-02-18 02:07:01 +090092
93/**
94 * Handles OpenStack floating IP events.
95 */
96@Component(immediate = true)
97public class OpenstackRoutingFloatingIpHandler {
98
99 private final Logger log = LoggerFactory.getLogger(getClass());
100
101 private static final String ERR_FLOW = "Failed set flows for floating IP %s: ";
Ray Milkeyc6c9b172018-02-26 09:36:31 -0800102 private static final String ERR_UNSUPPORTED_NET_TYPE = "Unsupported network type %s";
Hyunsun Moon44aac662017-02-18 02:07:01 +0900103
104 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
105 protected CoreService coreService;
106
107 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
108 protected DeviceService deviceService;
109
110 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Hyunsun Moon44aac662017-02-18 02:07:01 +0900111 protected LeadershipService leadershipService;
112
113 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
114 protected ClusterService clusterService;
115
116 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
117 protected OpenstackNodeService osNodeService;
118
119 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Jian Liec5c32b2018-07-13 14:28:58 +0900120 protected InstancePortAdminService instancePortService;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900121
122 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Jian Lif3a28b02018-06-11 21:29:13 +0900123 protected OpenstackRouterAdminService osRouterAdminService;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900124
125 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
126 protected OpenstackNetworkService osNetworkService;
127
sanghodc375372017-06-08 10:41:30 +0900128 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
129 protected OpenstackFlowRuleService osFlowRuleService;
130
Jian Li8f64feb2018-07-24 13:20:16 +0900131 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
132 protected PreCommitPortService preCommitPortService;
133
Hyunsun Moon44aac662017-02-18 02:07:01 +0900134 private final ExecutorService eventExecutor = newSingleThreadExecutor(
135 groupedThreads(this.getClass().getSimpleName(), "event-handler", log));
Jian Li24ec59f2018-05-23 19:01:25 +0900136 private final OpenstackRouterListener floatingIpListener = new InternalFloatingIpListener();
137 private final InstancePortListener instancePortListener = new InternalInstancePortListener();
Hyunsun Moon44aac662017-02-18 02:07:01 +0900138 private final OpenstackNodeListener osNodeListener = new InternalNodeListener();
Jian Lie1a39032018-06-19 21:49:36 +0900139 private final OpenstackNetworkListener osNetworkListener = new InternalOpenstackNetworkListener();
140 private final InstancePortListener instPortListener = new InternalInstancePortListener();
141
Hyunsun Moon44aac662017-02-18 02:07:01 +0900142 private ApplicationId appId;
143 private NodeId localNodeId;
144
145 @Activate
146 protected void activate() {
147 appId = coreService.registerApplication(OPENSTACK_NETWORKING_APP_ID);
148 localNodeId = clusterService.getLocalNode().id();
149 leadershipService.runForLeadership(appId.name());
Jian Li24ec59f2018-05-23 19:01:25 +0900150 osRouterAdminService.addListener(floatingIpListener);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900151 osNodeService.addListener(osNodeListener);
Jian Li24ec59f2018-05-23 19:01:25 +0900152 instancePortService.addListener(instancePortListener);
Jian Lie1a39032018-06-19 21:49:36 +0900153 osNodeService.addListener(osNodeListener);
154 osNetworkService.addListener(osNetworkListener);
155 instancePortService.addListener(instPortListener);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900156
157 log.info("Started");
158 }
159
160 @Deactivate
161 protected void deactivate() {
Jian Li24ec59f2018-05-23 19:01:25 +0900162 instancePortService.removeListener(instancePortListener);
Jian Lie1a39032018-06-19 21:49:36 +0900163 instancePortService.removeListener(instPortListener);
164 osNetworkService.removeListener(osNetworkListener);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900165 osNodeService.removeListener(osNodeListener);
Jian Li24ec59f2018-05-23 19:01:25 +0900166 osRouterAdminService.removeListener(floatingIpListener);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900167 leadershipService.withdraw(appId.name());
168 eventExecutor.shutdown();
169
170 log.info("Stopped");
171 }
172
Jian Li628a7cb2018-08-11 23:04:24 +0900173 private void setFloatingIpRules(NetFloatingIP floatingIp, InstancePort instPort,
Jian Li1064e4f2018-05-29 16:16:53 +0900174 OpenstackNode gateway, boolean install) {
Jian Li628a7cb2018-08-11 23:04:24 +0900175
176 if (instPort == null) {
177 log.debug("No instance port found");
178 return;
179 }
180
181 Network osNet = osNetworkService.network(instPort.networkId());
Jian Li8f64feb2018-07-24 13:20:16 +0900182
Hyunsun Moon44aac662017-02-18 02:07:01 +0900183 if (osNet == null) {
Jian Li71670d12018-03-02 21:31:07 +0900184 final String errorFormat = ERR_FLOW + "no network(%s) exists";
185 final String error = String.format(errorFormat,
Hyunsun Moon44aac662017-02-18 02:07:01 +0900186 floatingIp.getFloatingIpAddress(),
Jian Li628a7cb2018-08-11 23:04:24 +0900187 instPort.networkId());
Hyunsun Moon44aac662017-02-18 02:07:01 +0900188 throw new IllegalStateException(error);
189 }
190
daniel park32b42202018-03-14 16:53:44 +0900191 ExternalPeerRouter externalPeerRouter = externalPeerRouter(osNet);
192 if (externalPeerRouter == null) {
daniel parkc2a2ed62018-04-10 15:17:42 +0900193 final String errorFormat = ERR_FLOW + "no external peer router found";
194 throw new IllegalStateException(errorFormat);
daniel park32b42202018-03-14 16:53:44 +0900195 }
196
Jian Li8f64feb2018-07-24 13:20:16 +0900197 if (install) {
Jian Li628a7cb2018-08-11 23:04:24 +0900198 preCommitPortService.subscribePreCommit(instPort.portId(),
Jian Li8f64feb2018-07-24 13:20:16 +0900199 OPENSTACK_PORT_PRE_REMOVE, this.getClass().getName());
Jian Li628a7cb2018-08-11 23:04:24 +0900200 log.info("Subscribed the port {} on listening pre-remove event", instPort.portId());
Jian Li8f64feb2018-07-24 13:20:16 +0900201 } else {
Jian Li628a7cb2018-08-11 23:04:24 +0900202 preCommitPortService.unsubscribePreCommit(instPort.portId(),
203 OPENSTACK_PORT_PRE_REMOVE, instancePortService, this.getClass().getName());
204 log.info("Unsubscribed the port {} on listening pre-remove event", instPort.portId());
Jian Li8f64feb2018-07-24 13:20:16 +0900205 }
206
Jian Lide679782018-06-05 01:41:29 +0900207 updateComputeNodeRules(instPort, osNet, gateway, install);
208 updateGatewayNodeRules(floatingIp, instPort, osNet, externalPeerRouter, gateway, install);
209
Jian Lide679782018-06-05 01:41:29 +0900210 // TODO: need to refactor setUpstreamRules if possible
daniel park32b42202018-03-14 16:53:44 +0900211 setUpstreamRules(floatingIp, osNet, instPort, externalPeerRouter, install);
Jian Li8f64feb2018-07-24 13:20:16 +0900212
daniel parkc2a2ed62018-04-10 15:17:42 +0900213 log.trace("Succeeded to set flow rules for floating ip {}:{} and install: {}",
214 floatingIp.getFloatingIpAddress(),
215 floatingIp.getFixedIpAddress(),
216 install);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900217 }
218
Jian Lide679782018-06-05 01:41:29 +0900219 private synchronized void updateGatewayNodeRules(NetFloatingIP fip,
220 InstancePort instPort,
221 Network osNet,
222 ExternalPeerRouter router,
223 OpenstackNode gateway,
224 boolean install) {
225
226 Set<OpenstackNode> completedGws = osNodeService.completeNodes(GATEWAY);
227 Set<OpenstackNode> finalGws = Sets.newConcurrentHashSet();
228 finalGws.addAll(ImmutableSet.copyOf(completedGws));
229
Jian Lia171a432018-06-11 11:52:11 +0900230
231 if (gateway == null) {
232 // these are floating IP related cases...
233 setDownstreamExternalRulesHelper(fip, osNet, instPort, router,
234 ImmutableSet.copyOf(finalGws), install);
235
Jian Lide679782018-06-05 01:41:29 +0900236 } else {
Jian Lia171a432018-06-11 11:52:11 +0900237 // these are openstack node related cases...
238 if (install) {
239 if (completedGws.contains(gateway)) {
240 if (completedGws.size() > 1) {
241 finalGws.remove(gateway);
242 if (fip.getPortId() != null) {
243 setDownstreamExternalRulesHelper(fip, osNet, instPort, router,
244 ImmutableSet.copyOf(finalGws), false);
245 finalGws.add(gateway);
246 }
247 }
Jian Lide679782018-06-05 01:41:29 +0900248 if (fip.getPortId() != null) {
249 setDownstreamExternalRulesHelper(fip, osNet, instPort, router,
250 ImmutableSet.copyOf(finalGws), true);
251 }
Jian Lia171a432018-06-11 11:52:11 +0900252 } else {
253 log.warn("Detected node should be included in completed gateway set");
Jian Lide679782018-06-05 01:41:29 +0900254 }
255 } else {
Jian Lia171a432018-06-11 11:52:11 +0900256 if (!completedGws.contains(gateway)) {
257 if (completedGws.size() >= 1) {
258 if (fip.getPortId() != null) {
259 setDownstreamExternalRulesHelper(fip, osNet, instPort, router,
260 ImmutableSet.copyOf(finalGws), true);
261 }
262 }
263 } else {
264 log.warn("Detected node should NOT be included in completed gateway set");
265 }
Jian Lide679782018-06-05 01:41:29 +0900266 }
267 }
268 }
269
270 private synchronized void updateComputeNodeRules(InstancePort instPort,
271 Network osNet,
272 OpenstackNode gateway,
273 boolean install) {
Jian Li1064e4f2018-05-29 16:16:53 +0900274
275 Set<OpenstackNode> completedGws = osNodeService.completeNodes(GATEWAY);
276 Set<OpenstackNode> finalGws = Sets.newConcurrentHashSet();
277 finalGws.addAll(ImmutableSet.copyOf(completedGws));
278
279 if (gateway == null) {
280 // these are floating IP related cases...
281 setComputeNodeToGatewayHelper(instPort, osNet,
282 ImmutableSet.copyOf(finalGws), install);
Jian Lide679782018-06-05 01:41:29 +0900283
Jian Li1064e4f2018-05-29 16:16:53 +0900284 } else {
285 // these are openstack node related cases...
286 if (install) {
287 if (completedGws.contains(gateway)) {
288 if (completedGws.size() > 1) {
289 finalGws.remove(gateway);
290 setComputeNodeToGatewayHelper(instPort, osNet,
291 ImmutableSet.copyOf(finalGws), false);
292 finalGws.add(gateway);
293 }
294
295 setComputeNodeToGatewayHelper(instPort, osNet,
296 ImmutableSet.copyOf(finalGws), true);
297 } else {
298 log.warn("Detected node should be included in completed gateway set");
299 }
300 } else {
301 if (!completedGws.contains(gateway)) {
302 finalGws.add(gateway);
303 setComputeNodeToGatewayHelper(instPort, osNet,
304 ImmutableSet.copyOf(finalGws), false);
305 finalGws.remove(gateway);
306 if (completedGws.size() >= 1) {
307 setComputeNodeToGatewayHelper(instPort, osNet,
308 ImmutableSet.copyOf(finalGws), true);
309 }
310 } else {
311 log.warn("Detected node should NOT be included in completed gateway set");
312 }
313 }
314 }
315 }
316
317 // a helper method
318 private void setComputeNodeToGatewayHelper(InstancePort instPort,
319 Network osNet,
320 Set<OpenstackNode> gateways,
321 boolean install) {
daniel parkeeb8e042018-02-21 14:06:58 +0900322 TrafficTreatment treatment;
323
324 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder()
325 .matchEthType(Ethernet.TYPE_IPV4)
326 .matchIPSrc(instPort.ipAddress().toIpPrefix())
327 .matchEthDst(Constants.DEFAULT_GATEWAY_MAC);
328
329 switch (osNet.getNetworkType()) {
330 case VXLAN:
331 sBuilder.matchTunnelId(Long.parseLong(osNet.getProviderSegID()));
332 break;
333 case VLAN:
334 sBuilder.matchVlanId(VlanId.vlanId(osNet.getProviderSegID()));
335 break;
336 default:
337 final String error = String.format(
Ray Milkeyc6c9b172018-02-26 09:36:31 -0800338 ERR_UNSUPPORTED_NET_TYPE,
daniel parkeeb8e042018-02-21 14:06:58 +0900339 osNet.getNetworkType().toString());
340 throw new IllegalStateException(error);
341 }
342
Jian Li1064e4f2018-05-29 16:16:53 +0900343 OpenstackNode selectedGatewayNode = getGwByComputeDevId(gateways, instPort.deviceId());
344
daniel parkeeb8e042018-02-21 14:06:58 +0900345 if (selectedGatewayNode == null) {
daniel parkc2a2ed62018-04-10 15:17:42 +0900346 final String errorFormat = ERR_FLOW + "no gateway node selected";
347 throw new IllegalStateException(errorFormat);
daniel parkeeb8e042018-02-21 14:06:58 +0900348 }
349 treatment = DefaultTrafficTreatment.builder()
350 .extension(buildExtension(
351 deviceService,
352 instPort.deviceId(),
353 selectedGatewayNode.dataIp().getIp4Address()),
354 instPort.deviceId())
355 .setOutput(osNodeService.node(instPort.deviceId()).tunnelPortNum())
356 .build();
357
358 osFlowRuleService.setRule(
359 appId,
360 instPort.deviceId(),
361 sBuilder.build(),
362 treatment,
363 PRIORITY_EXTERNAL_FLOATING_ROUTING_RULE,
364 ROUTING_TABLE,
365 install);
daniel parkc2a2ed62018-04-10 15:17:42 +0900366 log.trace("Succeeded to set flow rules from compute node to gateway on compute node");
daniel parkeeb8e042018-02-21 14:06:58 +0900367 }
368
Jian Lide679782018-06-05 01:41:29 +0900369 private void setDownstreamExternalRulesHelper(NetFloatingIP floatingIp,
370 Network osNet,
371 InstancePort instPort,
372 ExternalPeerRouter externalPeerRouter,
373 Set<OpenstackNode> gateways, boolean install) {
374 OpenstackNode cNode = osNodeService.node(instPort.deviceId());
375 if (cNode == null) {
376 final String error = String.format("Cannot find openstack node for device %s",
377 instPort.deviceId());
378 throw new IllegalStateException(error);
379 }
380 if (osNet.getNetworkType() == NetworkType.VXLAN && cNode.dataIp() == null) {
381 final String errorFormat = ERR_FLOW + "VXLAN mode is not ready for %s";
382 final String error = String.format(errorFormat, floatingIp, cNode.hostname());
383 throw new IllegalStateException(error);
384 }
385 if (osNet.getNetworkType() == NetworkType.VLAN && cNode.vlanIntf() == null) {
386 final String errorFormat = ERR_FLOW + "VLAN mode is not ready for %s";
387 final String error = String.format(errorFormat, floatingIp, cNode.hostname());
388 throw new IllegalStateException(error);
389 }
390
391 IpAddress floating = IpAddress.valueOf(floatingIp.getFloatingIpAddress());
392
393 OpenstackNode selectedGatewayNode = getGwByComputeDevId(gateways, instPort.deviceId());
394
395 if (selectedGatewayNode == null) {
396 final String errorFormat = ERR_FLOW + "no gateway node selected";
397 throw new IllegalStateException(errorFormat);
398 }
399
400 TrafficSelector.Builder externalSelectorBuilder = DefaultTrafficSelector.builder()
401 .matchEthType(Ethernet.TYPE_IPV4)
Daniel Park319b9ab2018-09-14 11:27:04 +0900402 .matchInPort(selectedGatewayNode.uplinkPortNum())
Jian Lide679782018-06-05 01:41:29 +0900403 .matchIPDst(floating.toIpPrefix());
404
405 TrafficTreatment.Builder externalTreatmentBuilder = DefaultTrafficTreatment.builder()
406 .setEthSrc(Constants.DEFAULT_GATEWAY_MAC)
407 .setEthDst(instPort.macAddress())
408 .setIpDst(instPort.ipAddress().getIp4Address());
409
Jian Li5e2ad4a2018-07-16 13:40:53 +0900410 if (!externalPeerRouter.vlanId().equals(VlanId.NONE)) {
411 externalSelectorBuilder.matchVlanId(externalPeerRouter.vlanId()).build();
Jian Lide679782018-06-05 01:41:29 +0900412 externalTreatmentBuilder.popVlan();
413 }
414
415 switch (osNet.getNetworkType()) {
416 case VXLAN:
417 externalTreatmentBuilder.setTunnelId(Long.valueOf(osNet.getProviderSegID()))
418 .extension(buildExtension(
419 deviceService,
420 selectedGatewayNode.intgBridge(),
421 cNode.dataIp().getIp4Address()),
422 selectedGatewayNode.intgBridge())
423 .setOutput(selectedGatewayNode.tunnelPortNum());
424 break;
425 case VLAN:
426 externalTreatmentBuilder.pushVlan()
427 .setVlanId(VlanId.vlanId(osNet.getProviderSegID()))
428 .setOutput(selectedGatewayNode.vlanPortNum());
429 break;
430 default:
431 final String error = String.format(ERR_UNSUPPORTED_NET_TYPE,
432 osNet.getNetworkType());
433 throw new IllegalStateException(error);
434 }
435
436 osFlowRuleService.setRule(
437 appId,
438 selectedGatewayNode.intgBridge(),
439 externalSelectorBuilder.build(),
440 externalTreatmentBuilder.build(),
441 PRIORITY_FLOATING_EXTERNAL,
442 GW_COMMON_TABLE,
443 install);
444 }
445
Hyunsun Moon44aac662017-02-18 02:07:01 +0900446 private void setUpstreamRules(NetFloatingIP floatingIp, Network osNet,
daniel park32b42202018-03-14 16:53:44 +0900447 InstancePort instPort, ExternalPeerRouter externalPeerRouter,
448 boolean install) {
Hyunsun Moon44aac662017-02-18 02:07:01 +0900449 IpAddress floating = IpAddress.valueOf(floatingIp.getFloatingIpAddress());
daniel parkee8700b2017-05-11 15:50:03 +0900450 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder()
Hyunsun Moon44aac662017-02-18 02:07:01 +0900451 .matchEthType(Ethernet.TYPE_IPV4)
daniel parkee8700b2017-05-11 15:50:03 +0900452 .matchIPSrc(instPort.ipAddress().toIpPrefix());
453
454 switch (osNet.getNetworkType()) {
455 case VXLAN:
456 sBuilder.matchTunnelId(Long.valueOf(osNet.getProviderSegID()));
457 break;
458 case VLAN:
459 sBuilder.matchVlanId(VlanId.vlanId(osNet.getProviderSegID()));
460 break;
461 default:
Ray Milkeyc6c9b172018-02-26 09:36:31 -0800462 final String error = String.format(ERR_UNSUPPORTED_NET_TYPE,
Hyunsun Moon0d457362017-06-27 17:19:41 +0900463 osNet.getNetworkType());
daniel parkee8700b2017-05-11 15:50:03 +0900464 throw new IllegalStateException(error);
465 }
Hyunsun Moon44aac662017-02-18 02:07:01 +0900466
Daniel Park75e3d7f2018-05-29 14:43:53 +0900467 TrafficSelector selector = sBuilder.build();
daniel parkeeb8e042018-02-21 14:06:58 +0900468
Hyunsun Moon0d457362017-06-27 17:19:41 +0900469 osNodeService.completeNodes(GATEWAY).forEach(gNode -> {
Daniel Park75e3d7f2018-05-29 14:43:53 +0900470 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder()
471 .setIpSrc(floating.getIp4Address())
472 .setEthSrc(instPort.macAddress())
Jian Li5e2ad4a2018-07-16 13:40:53 +0900473 .setEthDst(externalPeerRouter.macAddress());
Hyunsun Moon44aac662017-02-18 02:07:01 +0900474
Daniel Park75e3d7f2018-05-29 14:43:53 +0900475 if (osNet.getNetworkType().equals(NetworkType.VLAN)) {
476 tBuilder.popVlan();
477 }
478
Jian Li5e2ad4a2018-07-16 13:40:53 +0900479 if (!externalPeerRouter.vlanId().equals(VlanId.NONE)) {
480 tBuilder.pushVlan().setVlanId(externalPeerRouter.vlanId());
Daniel Park75e3d7f2018-05-29 14:43:53 +0900481 }
sanghodc375372017-06-08 10:41:30 +0900482 osFlowRuleService.setRule(
Hyunsun Moon44aac662017-02-18 02:07:01 +0900483 appId,
Hyunsun Moon0d457362017-06-27 17:19:41 +0900484 gNode.intgBridge(),
Daniel Park75e3d7f2018-05-29 14:43:53 +0900485 selector,
daniel parkeeb8e042018-02-21 14:06:58 +0900486 tBuilder.setOutput(gNode.uplinkPortNum()).build(),
Hyunsun Moon44aac662017-02-18 02:07:01 +0900487 PRIORITY_FLOATING_EXTERNAL,
sanghodc375372017-06-08 10:41:30 +0900488 GW_COMMON_TABLE,
Hyunsun Moon44aac662017-02-18 02:07:01 +0900489 install);
Daniel Park75e3d7f2018-05-29 14:43:53 +0900490 });
daniel parkc2a2ed62018-04-10 15:17:42 +0900491 log.trace("Succeeded to set flow rules for upstream on gateway nodes");
Hyunsun Moon44aac662017-02-18 02:07:01 +0900492 }
493
daniel park32b42202018-03-14 16:53:44 +0900494 private ExternalPeerRouter externalPeerRouter(Network network) {
daniel parkeeb8e042018-02-21 14:06:58 +0900495 if (network == null) {
496 return null;
497 }
498
499 Subnet subnet = osNetworkService.subnets(network.getId()).stream().findAny().orElse(null);
500
501 if (subnet == null) {
502 return null;
503 }
504
Jian Lif3a28b02018-06-11 21:29:13 +0900505 RouterInterface osRouterIface = osRouterAdminService.routerInterfaces().stream()
daniel parkeeb8e042018-02-21 14:06:58 +0900506 .filter(i -> Objects.equals(i.getSubnetId(), subnet.getId()))
507 .findAny().orElse(null);
508 if (osRouterIface == null) {
509 return null;
510 }
511
Jian Lif3a28b02018-06-11 21:29:13 +0900512 Router osRouter = osRouterAdminService.router(osRouterIface.getId());
daniel parkeeb8e042018-02-21 14:06:58 +0900513 if (osRouter == null) {
514 return null;
515 }
516 if (osRouter.getExternalGatewayInfo() == null) {
517 return null;
518 }
519
520 ExternalGateway exGatewayInfo = osRouter.getExternalGatewayInfo();
daniel park65e1c202018-04-03 13:15:28 +0900521 return osNetworkService.externalPeerRouter(exGatewayInfo);
daniel parkeeb8e042018-02-21 14:06:58 +0900522 }
daniel park65e1c202018-04-03 13:15:28 +0900523
Jian Li99892e92018-04-13 14:59:39 +0900524 private void associateFloatingIp(NetFloatingIP osFip) {
Jian Li628a7cb2018-08-11 23:04:24 +0900525 InstancePort instPort = instancePortService.instancePort(osFip.getPortId());
526
527 if (instPort == null) {
528 log.warn("Failed to insert floating IP rule for {} due to missing of port info.",
529 osFip.getFloatingIpAddress());
530 return;
Jian Li99892e92018-04-13 14:59:39 +0900531 }
Jian Li628a7cb2018-08-11 23:04:24 +0900532
Jian Li99892e92018-04-13 14:59:39 +0900533 // set floating IP rules only if the port is associated to a VM
Jian Li628a7cb2018-08-11 23:04:24 +0900534 if (!Strings.isNullOrEmpty(instPort.deviceId().toString())) {
535 setFloatingIpRules(osFip, instPort, null, true);
Jian Li99892e92018-04-13 14:59:39 +0900536 }
537 }
538
539 private void disassociateFloatingIp(NetFloatingIP osFip, String portId) {
Jian Li628a7cb2018-08-11 23:04:24 +0900540 InstancePort instPort = instancePortService.instancePort(portId);
Jian Lie1a39032018-06-19 21:49:36 +0900541
Jian Li628a7cb2018-08-11 23:04:24 +0900542 if (instPort == null) {
543 log.warn("Failed to remove floating IP rule for {} due to missing of port info.",
544 osFip.getFloatingIpAddress());
545 return;
Jian Lie1a39032018-06-19 21:49:36 +0900546 }
547
Jian Li99892e92018-04-13 14:59:39 +0900548 // set floating IP rules only if the port is associated to a VM
Jian Li628a7cb2018-08-11 23:04:24 +0900549 if (!Strings.isNullOrEmpty(instPort.deviceId().toString())) {
550 setFloatingIpRules(osFip, instPort, null, false);
Jian Li99892e92018-04-13 14:59:39 +0900551 }
552 }
553
Hyunsun Moon0d457362017-06-27 17:19:41 +0900554 private class InternalFloatingIpListener implements OpenstackRouterListener {
Hyunsun Moon44aac662017-02-18 02:07:01 +0900555
556 @Override
557 public boolean isRelevant(OpenstackRouterEvent event) {
558 // do not allow to proceed without leadership
559 NodeId leader = leadershipService.getLeader(appId.name());
560 if (!Objects.equals(localNodeId, leader)) {
561 return false;
562 }
563 return event.floatingIp() != null;
564 }
565
566 @Override
567 public void event(OpenstackRouterEvent event) {
568 switch (event.type()) {
569 case OPENSTACK_FLOATING_IP_ASSOCIATED:
Hyunsun Moon7a5f9042017-05-11 18:19:01 +0900570 eventExecutor.execute(() -> {
Hyunsun Moonb720e632017-05-16 15:41:36 +0900571 NetFloatingIP osFip = event.floatingIp();
Jian Li0488c732018-09-14 20:53:07 +0900572 if (instancePortService.instancePort(osFip.getPortId()) != null) {
573 associateFloatingIp(osFip);
574 log.info("Associated floating IP {}:{}",
575 osFip.getFloatingIpAddress(),
576 osFip.getFixedIpAddress());
577 }
Hyunsun Moon7a5f9042017-05-11 18:19:01 +0900578 });
579 break;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900580 case OPENSTACK_FLOATING_IP_DISASSOCIATED:
581 eventExecutor.execute(() -> {
Hyunsun Moonb720e632017-05-16 15:41:36 +0900582 NetFloatingIP osFip = event.floatingIp();
Jian Li0488c732018-09-14 20:53:07 +0900583 if (instancePortService.instancePort(event.portId()) != null) {
584 disassociateFloatingIp(osFip, event.portId());
585 log.info("Disassociated floating IP {}:{}",
586 osFip.getFloatingIpAddress(),
587 osFip.getFixedIpAddress());
588 }
Hyunsun Moon7a5f9042017-05-11 18:19:01 +0900589 });
590 break;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900591 case OPENSTACK_FLOATING_IP_CREATED:
Hyunsun Moonb720e632017-05-16 15:41:36 +0900592 eventExecutor.execute(() -> {
593 NetFloatingIP osFip = event.floatingIp();
Jian Li0488c732018-09-14 20:53:07 +0900594 String portId = osFip.getPortId();
595 if (!Strings.isNullOrEmpty(portId) &&
596 instancePortService.instancePort(portId) != null) {
Hyunsun Moonb720e632017-05-16 15:41:36 +0900597 associateFloatingIp(event.floatingIp());
598 }
599 log.info("Created floating IP {}", osFip.getFloatingIpAddress());
600 });
601 break;
Jian Lia171a432018-06-11 11:52:11 +0900602 case OPENSTACK_FLOATING_IP_REMOVED:
603 eventExecutor.execute(() -> {
604 NetFloatingIP osFip = event.floatingIp();
Jian Li0488c732018-09-14 20:53:07 +0900605 String portId = osFip.getPortId();
Jian Lia171a432018-06-11 11:52:11 +0900606 if (!Strings.isNullOrEmpty(osFip.getPortId())) {
Jian Lic2403592018-07-18 12:56:45 +0900607 // in case the floating IP is not associated with any port due to
608 // port removal, we simply do not execute floating IP disassociation
Jian Li0488c732018-09-14 20:53:07 +0900609 if (osNetworkService.port(portId) != null &&
610 instancePortService.instancePort(portId) != null) {
611 disassociateFloatingIp(osFip, portId);
Jian Lic2403592018-07-18 12:56:45 +0900612 }
Jian Lida03ce92018-07-24 21:41:53 +0900613
614 // since we skip floating IP disassociation, we need to
615 // manually unsubscribe the port pre-remove event
616 preCommitPortService.unsubscribePreCommit(osFip.getPortId(),
Jian Li628a7cb2018-08-11 23:04:24 +0900617 OPENSTACK_PORT_PRE_REMOVE, instancePortService,
618 this.getClass().getName());
Jian Lida03ce92018-07-24 21:41:53 +0900619 log.info("Unsubscribed the port {} on listening pre-remove event", osFip.getPortId());
Jian Lia171a432018-06-11 11:52:11 +0900620 }
621 log.info("Removed floating IP {}", osFip.getFloatingIpAddress());
622 });
623 break;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900624 case OPENSTACK_FLOATING_IP_UPDATED:
Hyunsun Moon44aac662017-02-18 02:07:01 +0900625 case OPENSTACK_ROUTER_CREATED:
626 case OPENSTACK_ROUTER_UPDATED:
627 case OPENSTACK_ROUTER_REMOVED:
628 case OPENSTACK_ROUTER_INTERFACE_ADDED:
629 case OPENSTACK_ROUTER_INTERFACE_UPDATED:
630 case OPENSTACK_ROUTER_INTERFACE_REMOVED:
631 default:
632 // do nothing for the other events
633 break;
634 }
635 }
636 }
637
638 private class InternalNodeListener implements OpenstackNodeListener {
639
640 @Override
641 public boolean isRelevant(OpenstackNodeEvent event) {
642 // do not allow to proceed without leadership
643 NodeId leader = leadershipService.getLeader(appId.name());
644 if (!Objects.equals(localNodeId, leader)) {
645 return false;
646 }
647 return event.subject().type() == GATEWAY;
648 }
649
650 @Override
651 public void event(OpenstackNodeEvent event) {
Hyunsun Moon44aac662017-02-18 02:07:01 +0900652
653 switch (event.type()) {
Hyunsun Moon0d457362017-06-27 17:19:41 +0900654 case OPENSTACK_NODE_COMPLETE:
Hyunsun Moon44aac662017-02-18 02:07:01 +0900655 eventExecutor.execute(() -> {
Jian Lif3a28b02018-06-11 21:29:13 +0900656 for (NetFloatingIP fip : osRouterAdminService.floatingIps()) {
Jian Lie1a39032018-06-19 21:49:36 +0900657
Hyunsun Moon7a5f9042017-05-11 18:19:01 +0900658 if (Strings.isNullOrEmpty(fip.getPortId())) {
659 continue;
660 }
Jian Lie1a39032018-06-19 21:49:36 +0900661
Hyunsun Moon7a5f9042017-05-11 18:19:01 +0900662 Port osPort = osNetworkService.port(fip.getPortId());
Jian Li628a7cb2018-08-11 23:04:24 +0900663 InstancePort instPort = instancePortService.instancePort(fip.getPortId());
664
665 // we check both Openstack Port and Instance Port
666 if (osPort == null || instPort == null) {
Hyunsun Moon7a5f9042017-05-11 18:19:01 +0900667 continue;
668 }
Jian Lie1a39032018-06-19 21:49:36 +0900669
Jian Li628a7cb2018-08-11 23:04:24 +0900670 setFloatingIpRules(fip, instPort, event.subject(), true);
Hyunsun Moon7a5f9042017-05-11 18:19:01 +0900671 }
Hyunsun Moon44aac662017-02-18 02:07:01 +0900672 });
673 break;
Hyunsun Moon0d457362017-06-27 17:19:41 +0900674 case OPENSTACK_NODE_INCOMPLETE:
Jian Li1064e4f2018-05-29 16:16:53 +0900675 eventExecutor.execute(() -> {
Jian Lif3a28b02018-06-11 21:29:13 +0900676 for (NetFloatingIP fip : osRouterAdminService.floatingIps()) {
Jian Li1064e4f2018-05-29 16:16:53 +0900677 if (Strings.isNullOrEmpty(fip.getPortId())) {
678 continue;
679 }
680 Port osPort = osNetworkService.port(fip.getPortId());
681 if (osPort == null) {
682 log.warn("Failed to set floating IP {}", fip.getId());
683 continue;
684 }
685 Network osNet = osNetworkService.network(osPort.getNetworkId());
686 if (osNet == null) {
687 final String errorFormat = ERR_FLOW + "no network(%s) exists";
688 final String error = String.format(errorFormat,
689 fip.getFloatingIpAddress(),
690 osPort.getNetworkId());
691 throw new IllegalStateException(error);
692 }
693 MacAddress srcMac = MacAddress.valueOf(osPort.getMacAddress());
694 log.trace("Mac address of openstack port: {}", srcMac);
695 InstancePort instPort = instancePortService.instancePort(srcMac);
696
697 if (instPort == null) {
698 final String errorFormat = ERR_FLOW + "no host(MAC:%s) found";
699 final String error = String.format(errorFormat,
700 fip.getFloatingIpAddress(), srcMac);
701 throw new IllegalStateException(error);
702 }
703
Jian Lide679782018-06-05 01:41:29 +0900704 ExternalPeerRouter externalPeerRouter = externalPeerRouter(osNet);
705 if (externalPeerRouter == null) {
706 final String errorFormat = ERR_FLOW + "no external peer router found";
707 throw new IllegalStateException(errorFormat);
708 }
709
710 updateComputeNodeRules(instPort, osNet, event.subject(), false);
711 updateGatewayNodeRules(fip, instPort, osNet,
712 externalPeerRouter, event.subject(), false);
Jian Li1064e4f2018-05-29 16:16:53 +0900713 }
714 });
715 break;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900716 default:
Hyunsun Moon0d457362017-06-27 17:19:41 +0900717 // do nothing
Hyunsun Moon44aac662017-02-18 02:07:01 +0900718 break;
719 }
720 }
721 }
Jian Li99892e92018-04-13 14:59:39 +0900722
Jian Li24ec59f2018-05-23 19:01:25 +0900723 private class InternalInstancePortListener implements InstancePortListener {
724
725 @Override
726 public boolean isRelevant(InstancePortEvent event) {
Jian Li24ec59f2018-05-23 19:01:25 +0900727
Jian Lie1a39032018-06-19 21:49:36 +0900728 if (event.type() == OPENSTACK_INSTANCE_MIGRATION_ENDED ||
729 event.type() == OPENSTACK_INSTANCE_MIGRATION_STARTED) {
730 Set<NetFloatingIP> ips = osRouterAdminService.floatingIps();
731 NetFloatingIP fip = associatedFloatingIp(event.subject(), ips);
732
733 // we check the possible NPE to avoid duplicated null check
734 // for OPENSTACK_INSTANCE_MIGRATION_ENDED and
735 // OPENSTACK_INSTANCE_MIGRATION_STARTED cases
736 if (fip == null || !isAssociatedWithVM(osNetworkService, fip)) {
737 return false;
738 }
739 }
740
741 // do not allow to proceed without leadership
742 NodeId leader = leadershipService.getLeader(appId.name());
743
744 return Objects.equals(localNodeId, leader);
Jian Li24ec59f2018-05-23 19:01:25 +0900745 }
746
747 @Override
748 public void event(InstancePortEvent event) {
Jian Lie1a39032018-06-19 21:49:36 +0900749 InstancePort instPort = event.subject();
Jian Li24ec59f2018-05-23 19:01:25 +0900750 Set<OpenstackNode> gateways = osNodeService.completeNodes(GATEWAY);
751
Jian Lie1a39032018-06-19 21:49:36 +0900752 Set<NetFloatingIP> ips = osRouterAdminService.floatingIps();
753 NetFloatingIP fip;
754 Port osPort;
755 Network osNet;
756 ExternalPeerRouter externalPeerRouter;
Jian Li24ec59f2018-05-23 19:01:25 +0900757
758 switch (event.type()) {
Jian Lie1a39032018-06-19 21:49:36 +0900759 case OPENSTACK_INSTANCE_PORT_DETECTED:
Jian Li77323c52018-06-24 01:26:18 +0900760 if (instPort != null && instPort.portId() != null) {
Jian Li46b74002018-07-15 18:39:08 +0900761 osRouterAdminService.floatingIps().stream()
762 .filter(f -> f.getPortId() != null)
763 .filter(f -> f.getPortId().equals(instPort.portId()))
Jian Li628a7cb2018-08-11 23:04:24 +0900764 .forEach(f -> setFloatingIpRules(f, instPort, null, true));
Jian Lie1a39032018-06-19 21:49:36 +0900765 }
766
767 break;
768
Jian Li24ec59f2018-05-23 19:01:25 +0900769 case OPENSTACK_INSTANCE_MIGRATION_STARTED:
Jian Lie1a39032018-06-19 21:49:36 +0900770
771 fip = associatedFloatingIp(event.subject(), ips);
772
773 if (fip == null) {
774 return;
775 }
776
777 osPort = osNetworkService.port(fip.getPortId());
778 osNet = osNetworkService.network(osPort.getNetworkId());
779 externalPeerRouter = externalPeerRouter(osNet);
780
781 if (externalPeerRouter == null) {
782 final String errorFormat = ERR_FLOW + "no external peer router found";
783 throw new IllegalStateException(errorFormat);
784 }
785
Jian Li24ec59f2018-05-23 19:01:25 +0900786 eventExecutor.execute(() -> {
787
Jian Li24ec59f2018-05-23 19:01:25 +0900788 // since DownstreamExternal rules should only be placed in
789 // corresponding gateway node, we need to install new rule to
790 // the corresponding gateway node
791 setDownstreamExternalRulesHelper(fip, osNet,
792 event.subject(), externalPeerRouter, gateways, true);
793
794 // since ComputeNodeToGateway rules should only be placed in
795 // corresponding compute node, we need to install new rule to
796 // the target compute node, and remove rules from original node
797 setComputeNodeToGatewayHelper(event.subject(), osNet, gateways, true);
Jian Li24ec59f2018-05-23 19:01:25 +0900798 });
799 break;
800 case OPENSTACK_INSTANCE_MIGRATION_ENDED:
801
Jian Liec5c32b2018-07-13 14:28:58 +0900802 InstancePort revisedInstPort = swapStaleLocation(event.subject());
803
804 fip = associatedFloatingIp(revisedInstPort, ips);
Jian Lie1a39032018-06-19 21:49:36 +0900805
806 if (fip == null) {
807 return;
808 }
809
810 osPort = osNetworkService.port(fip.getPortId());
811 osNet = osNetworkService.network(osPort.getNetworkId());
812 externalPeerRouter = externalPeerRouter(osNet);
813
814 if (externalPeerRouter == null) {
815 final String errorFormat = ERR_FLOW + "no external peer router found";
816 throw new IllegalStateException(errorFormat);
817 }
818
819 // If we only have one gateway, we simply do not remove any
Jian Li24ec59f2018-05-23 19:01:25 +0900820 // flow rules from either gateway or compute node
821 if (gateways.size() == 1) {
822 return;
823 }
824
Jian Lie1a39032018-06-19 21:49:36 +0900825 // Checks whether the destination compute node's device id
Jian Li24ec59f2018-05-23 19:01:25 +0900826 // has identical gateway hash or not
827 // if it is true, we simply do not remove the rules, as
828 // it has been overwritten at port detention event
829 // if it is false, we will remove the rules
Jian Liec5c32b2018-07-13 14:28:58 +0900830 DeviceId newDeviceId = event.subject().deviceId();
831 DeviceId oldDeviceId = revisedInstPort.deviceId();
Jian Li24ec59f2018-05-23 19:01:25 +0900832
833 OpenstackNode oldGateway = getGwByComputeDevId(gateways, oldDeviceId);
834 OpenstackNode newGateway = getGwByComputeDevId(gateways, newDeviceId);
835
836 if (oldGateway != null && oldGateway.equals(newGateway)) {
837 return;
838 }
839
840 eventExecutor.execute(() -> {
841
Jian Lie1a39032018-06-19 21:49:36 +0900842 // We need to remove the old ComputeNodeToGateway rules from
Jian Li24ec59f2018-05-23 19:01:25 +0900843 // original compute node
Jian Liec5c32b2018-07-13 14:28:58 +0900844 setComputeNodeToGatewayHelper(revisedInstPort, osNet, gateways, false);
Jian Li24ec59f2018-05-23 19:01:25 +0900845
Jian Lie1a39032018-06-19 21:49:36 +0900846 // Since DownstreamExternal rules should only be placed in
Jian Li24ec59f2018-05-23 19:01:25 +0900847 // corresponding gateway node, we need to remove old rule from
848 // the corresponding gateway node
Jian Liec5c32b2018-07-13 14:28:58 +0900849 setDownstreamExternalRulesHelper(fip, osNet, revisedInstPort,
850 externalPeerRouter, gateways, false);
Jian Li24ec59f2018-05-23 19:01:25 +0900851 });
852 break;
853 default:
854 break;
855 }
856 }
857 }
Jian Lie1a39032018-06-19 21:49:36 +0900858
859 private class InternalOpenstackNetworkListener implements OpenstackNetworkListener {
860
861 @Override
862 public boolean isRelevant(OpenstackNetworkEvent event) {
863 // do not allow to proceed without leadership
864 NodeId leader = leadershipService.getLeader(appId.name());
Jian Lida03ce92018-07-24 21:41:53 +0900865 return Objects.equals(localNodeId, leader);
Jian Lie1a39032018-06-19 21:49:36 +0900866 }
867
868 @Override
869 public void event(OpenstackNetworkEvent event) {
870 switch (event.type()) {
Jian Li8f64feb2018-07-24 13:20:16 +0900871 case OPENSTACK_PORT_PRE_REMOVE:
Jian Li427811e2018-08-28 17:35:16 +0900872 InstancePort instPort =
873 instancePortService.instancePort(event.port().getId());
Jian Libcc42282018-09-13 20:59:34 +0900874
875 if (instPort == null) {
876 break;
877 }
878
Jian Li427811e2018-08-28 17:35:16 +0900879 NetFloatingIP fip =
880 associatedFloatingIp(instPort, osRouterAdminService.floatingIps());
881
882 if (fip != null) {
Jian Li8a5fb642018-09-14 15:50:04 +0900883
884 instancePortService.updateInstancePort(instPort.updateState(REMOVE_PENDING));
885
Jian Li427811e2018-08-28 17:35:16 +0900886 eventExecutor.execute(() ->
887 updateFipStore(instancePortService.instancePort(event.port().getId())));
888 } else {
889 instancePortService.removeInstancePort(instPort.portId());
890 }
Jian Li8f64feb2018-07-24 13:20:16 +0900891 break;
Jian Lie1a39032018-06-19 21:49:36 +0900892 default:
893 break;
894 }
895 }
896
897 private void updateFipStore(InstancePort port) {
898
899 if (port == null) {
900 return;
901 }
902
903 Set<NetFloatingIP> ips = osRouterAdminService.floatingIps();
904 for (NetFloatingIP fip : ips) {
905 if (Strings.isNullOrEmpty(fip.getFixedIpAddress())) {
906 continue;
907 }
908 if (Strings.isNullOrEmpty(fip.getFloatingIpAddress())) {
909 continue;
910 }
911 if (fip.getFixedIpAddress().equals(port.ipAddress().toString())) {
912 NeutronFloatingIP neutronFip = (NeutronFloatingIP) fip;
913 // invalidate bound fixed IP and port
914 neutronFip.setFixedIpAddress(null);
915 neutronFip.setPortId(null);
Jian Lie1a39032018-06-19 21:49:36 +0900916
917 // Following update will in turn trigger
918 // OPENSTACK_FLOATING_IP_DISASSOCIATED event
919 osRouterAdminService.updateFloatingIp(neutronFip);
920 log.info("Updated floating IP {}, due to host removal",
921 neutronFip.getFloatingIpAddress());
922 }
923 }
924 }
925 }
Hyunsun Moon44aac662017-02-18 02:07:01 +0900926}