blob: f0c0550f8e926e1d76676795a31c6748da8f9699 [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 Lie1a39032018-06-19 21:49:36 +090082import static org.onosproject.openstacknetworking.api.InstancePortEvent.Type.OPENSTACK_INSTANCE_MIGRATION_ENDED;
83import static org.onosproject.openstacknetworking.api.InstancePortEvent.Type.OPENSTACK_INSTANCE_MIGRATION_STARTED;
Jian Li8f64feb2018-07-24 13:20:16 +090084import static org.onosproject.openstacknetworking.api.OpenstackNetworkEvent.Type.OPENSTACK_PORT_PRE_REMOVE;
Jian Li24ec59f2018-05-23 19:01:25 +090085import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.associatedFloatingIp;
Jian Li1064e4f2018-05-29 16:16:53 +090086import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.getGwByComputeDevId;
Jian Li24ec59f2018-05-23 19:01:25 +090087import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.isAssociatedWithVM;
Jian Liec5c32b2018-07-13 14:28:58 +090088import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.swapStaleLocation;
Jian Li26949762018-03-30 15:46:37 +090089import static org.onosproject.openstacknetworking.util.RulePopulatorUtil.buildExtension;
Hyunsun Moon0d457362017-06-27 17:19:41 +090090import static org.onosproject.openstacknode.api.OpenstackNode.NodeType.GATEWAY;
Hyunsun Moon44aac662017-02-18 02:07:01 +090091
92/**
93 * Handles OpenStack floating IP events.
94 */
95@Component(immediate = true)
96public class OpenstackRoutingFloatingIpHandler {
97
98 private final Logger log = LoggerFactory.getLogger(getClass());
99
100 private static final String ERR_FLOW = "Failed set flows for floating IP %s: ";
Ray Milkeyc6c9b172018-02-26 09:36:31 -0800101 private static final String ERR_UNSUPPORTED_NET_TYPE = "Unsupported network type %s";
Hyunsun Moon44aac662017-02-18 02:07:01 +0900102
103 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
104 protected CoreService coreService;
105
106 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
107 protected DeviceService deviceService;
108
109 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Hyunsun Moon44aac662017-02-18 02:07:01 +0900110 protected LeadershipService leadershipService;
111
112 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
113 protected ClusterService clusterService;
114
115 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
116 protected OpenstackNodeService osNodeService;
117
118 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Jian Liec5c32b2018-07-13 14:28:58 +0900119 protected InstancePortAdminService instancePortService;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900120
121 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Jian Lif3a28b02018-06-11 21:29:13 +0900122 protected OpenstackRouterAdminService osRouterAdminService;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900123
124 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
125 protected OpenstackNetworkService osNetworkService;
126
sanghodc375372017-06-08 10:41:30 +0900127 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
128 protected OpenstackFlowRuleService osFlowRuleService;
129
Jian Li8f64feb2018-07-24 13:20:16 +0900130 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
131 protected PreCommitPortService preCommitPortService;
132
Hyunsun Moon44aac662017-02-18 02:07:01 +0900133 private final ExecutorService eventExecutor = newSingleThreadExecutor(
134 groupedThreads(this.getClass().getSimpleName(), "event-handler", log));
Jian Li24ec59f2018-05-23 19:01:25 +0900135 private final OpenstackRouterListener floatingIpListener = new InternalFloatingIpListener();
136 private final InstancePortListener instancePortListener = new InternalInstancePortListener();
Hyunsun Moon44aac662017-02-18 02:07:01 +0900137 private final OpenstackNodeListener osNodeListener = new InternalNodeListener();
Jian Lie1a39032018-06-19 21:49:36 +0900138 private final OpenstackNetworkListener osNetworkListener = new InternalOpenstackNetworkListener();
139 private final InstancePortListener instPortListener = new InternalInstancePortListener();
140
Hyunsun Moon44aac662017-02-18 02:07:01 +0900141 private ApplicationId appId;
142 private NodeId localNodeId;
143
144 @Activate
145 protected void activate() {
146 appId = coreService.registerApplication(OPENSTACK_NETWORKING_APP_ID);
147 localNodeId = clusterService.getLocalNode().id();
148 leadershipService.runForLeadership(appId.name());
Jian Li24ec59f2018-05-23 19:01:25 +0900149 osRouterAdminService.addListener(floatingIpListener);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900150 osNodeService.addListener(osNodeListener);
Jian Li24ec59f2018-05-23 19:01:25 +0900151 instancePortService.addListener(instancePortListener);
Jian Lie1a39032018-06-19 21:49:36 +0900152 osNodeService.addListener(osNodeListener);
153 osNetworkService.addListener(osNetworkListener);
154 instancePortService.addListener(instPortListener);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900155
156 log.info("Started");
157 }
158
159 @Deactivate
160 protected void deactivate() {
Jian Li24ec59f2018-05-23 19:01:25 +0900161 instancePortService.removeListener(instancePortListener);
Jian Lie1a39032018-06-19 21:49:36 +0900162 instancePortService.removeListener(instPortListener);
163 osNetworkService.removeListener(osNetworkListener);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900164 osNodeService.removeListener(osNodeListener);
Jian Li24ec59f2018-05-23 19:01:25 +0900165 osRouterAdminService.removeListener(floatingIpListener);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900166 leadershipService.withdraw(appId.name());
167 eventExecutor.shutdown();
168
169 log.info("Stopped");
170 }
171
Jian Li628a7cb2018-08-11 23:04:24 +0900172 private void setFloatingIpRules(NetFloatingIP floatingIp, InstancePort instPort,
Jian Li1064e4f2018-05-29 16:16:53 +0900173 OpenstackNode gateway, boolean install) {
Jian Li628a7cb2018-08-11 23:04:24 +0900174
175 if (instPort == null) {
176 log.debug("No instance port found");
177 return;
178 }
179
180 Network osNet = osNetworkService.network(instPort.networkId());
Jian Li8f64feb2018-07-24 13:20:16 +0900181
Hyunsun Moon44aac662017-02-18 02:07:01 +0900182 if (osNet == null) {
Jian Li71670d12018-03-02 21:31:07 +0900183 final String errorFormat = ERR_FLOW + "no network(%s) exists";
184 final String error = String.format(errorFormat,
Hyunsun Moon44aac662017-02-18 02:07:01 +0900185 floatingIp.getFloatingIpAddress(),
Jian Li628a7cb2018-08-11 23:04:24 +0900186 instPort.networkId());
Hyunsun Moon44aac662017-02-18 02:07:01 +0900187 throw new IllegalStateException(error);
188 }
189
daniel park32b42202018-03-14 16:53:44 +0900190 ExternalPeerRouter externalPeerRouter = externalPeerRouter(osNet);
191 if (externalPeerRouter == null) {
daniel parkc2a2ed62018-04-10 15:17:42 +0900192 final String errorFormat = ERR_FLOW + "no external peer router found";
193 throw new IllegalStateException(errorFormat);
daniel park32b42202018-03-14 16:53:44 +0900194 }
195
Jian Li8f64feb2018-07-24 13:20:16 +0900196 if (install) {
Jian Li628a7cb2018-08-11 23:04:24 +0900197 preCommitPortService.subscribePreCommit(instPort.portId(),
Jian Li8f64feb2018-07-24 13:20:16 +0900198 OPENSTACK_PORT_PRE_REMOVE, this.getClass().getName());
Jian Li628a7cb2018-08-11 23:04:24 +0900199 log.info("Subscribed the port {} on listening pre-remove event", instPort.portId());
Jian Li8f64feb2018-07-24 13:20:16 +0900200 } else {
Jian Li628a7cb2018-08-11 23:04:24 +0900201 preCommitPortService.unsubscribePreCommit(instPort.portId(),
202 OPENSTACK_PORT_PRE_REMOVE, instancePortService, this.getClass().getName());
203 log.info("Unsubscribed the port {} on listening pre-remove event", instPort.portId());
Jian Li8f64feb2018-07-24 13:20:16 +0900204 }
205
Jian Lide679782018-06-05 01:41:29 +0900206 updateComputeNodeRules(instPort, osNet, gateway, install);
207 updateGatewayNodeRules(floatingIp, instPort, osNet, externalPeerRouter, gateway, install);
208
Jian Lide679782018-06-05 01:41:29 +0900209 // TODO: need to refactor setUpstreamRules if possible
daniel park32b42202018-03-14 16:53:44 +0900210 setUpstreamRules(floatingIp, osNet, instPort, externalPeerRouter, install);
Jian Li8f64feb2018-07-24 13:20:16 +0900211
daniel parkc2a2ed62018-04-10 15:17:42 +0900212 log.trace("Succeeded to set flow rules for floating ip {}:{} and install: {}",
213 floatingIp.getFloatingIpAddress(),
214 floatingIp.getFixedIpAddress(),
215 install);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900216 }
217
Jian Lide679782018-06-05 01:41:29 +0900218 private synchronized void updateGatewayNodeRules(NetFloatingIP fip,
219 InstancePort instPort,
220 Network osNet,
221 ExternalPeerRouter router,
222 OpenstackNode gateway,
223 boolean install) {
224
225 Set<OpenstackNode> completedGws = osNodeService.completeNodes(GATEWAY);
226 Set<OpenstackNode> finalGws = Sets.newConcurrentHashSet();
227 finalGws.addAll(ImmutableSet.copyOf(completedGws));
228
Jian Lia171a432018-06-11 11:52:11 +0900229
230 if (gateway == null) {
231 // these are floating IP related cases...
232 setDownstreamExternalRulesHelper(fip, osNet, instPort, router,
233 ImmutableSet.copyOf(finalGws), install);
234
Jian Lide679782018-06-05 01:41:29 +0900235 } else {
Jian Lia171a432018-06-11 11:52:11 +0900236 // these are openstack node related cases...
237 if (install) {
238 if (completedGws.contains(gateway)) {
239 if (completedGws.size() > 1) {
240 finalGws.remove(gateway);
241 if (fip.getPortId() != null) {
242 setDownstreamExternalRulesHelper(fip, osNet, instPort, router,
243 ImmutableSet.copyOf(finalGws), false);
244 finalGws.add(gateway);
245 }
246 }
Jian Lide679782018-06-05 01:41:29 +0900247 if (fip.getPortId() != null) {
248 setDownstreamExternalRulesHelper(fip, osNet, instPort, router,
249 ImmutableSet.copyOf(finalGws), true);
250 }
Jian Lia171a432018-06-11 11:52:11 +0900251 } else {
252 log.warn("Detected node should be included in completed gateway set");
Jian Lide679782018-06-05 01:41:29 +0900253 }
254 } else {
Jian Lia171a432018-06-11 11:52:11 +0900255 if (!completedGws.contains(gateway)) {
256 if (completedGws.size() >= 1) {
257 if (fip.getPortId() != null) {
258 setDownstreamExternalRulesHelper(fip, osNet, instPort, router,
259 ImmutableSet.copyOf(finalGws), true);
260 }
261 }
262 } else {
263 log.warn("Detected node should NOT be included in completed gateway set");
264 }
Jian Lide679782018-06-05 01:41:29 +0900265 }
266 }
267 }
268
269 private synchronized void updateComputeNodeRules(InstancePort instPort,
270 Network osNet,
271 OpenstackNode gateway,
272 boolean install) {
Jian Li1064e4f2018-05-29 16:16:53 +0900273
274 Set<OpenstackNode> completedGws = osNodeService.completeNodes(GATEWAY);
275 Set<OpenstackNode> finalGws = Sets.newConcurrentHashSet();
276 finalGws.addAll(ImmutableSet.copyOf(completedGws));
277
278 if (gateway == null) {
279 // these are floating IP related cases...
280 setComputeNodeToGatewayHelper(instPort, osNet,
281 ImmutableSet.copyOf(finalGws), install);
Jian Lide679782018-06-05 01:41:29 +0900282
Jian Li1064e4f2018-05-29 16:16:53 +0900283 } else {
284 // these are openstack node related cases...
285 if (install) {
286 if (completedGws.contains(gateway)) {
287 if (completedGws.size() > 1) {
288 finalGws.remove(gateway);
289 setComputeNodeToGatewayHelper(instPort, osNet,
290 ImmutableSet.copyOf(finalGws), false);
291 finalGws.add(gateway);
292 }
293
294 setComputeNodeToGatewayHelper(instPort, osNet,
295 ImmutableSet.copyOf(finalGws), true);
296 } else {
297 log.warn("Detected node should be included in completed gateway set");
298 }
299 } else {
300 if (!completedGws.contains(gateway)) {
301 finalGws.add(gateway);
302 setComputeNodeToGatewayHelper(instPort, osNet,
303 ImmutableSet.copyOf(finalGws), false);
304 finalGws.remove(gateway);
305 if (completedGws.size() >= 1) {
306 setComputeNodeToGatewayHelper(instPort, osNet,
307 ImmutableSet.copyOf(finalGws), true);
308 }
309 } else {
310 log.warn("Detected node should NOT be included in completed gateway set");
311 }
312 }
313 }
314 }
315
316 // a helper method
317 private void setComputeNodeToGatewayHelper(InstancePort instPort,
318 Network osNet,
319 Set<OpenstackNode> gateways,
320 boolean install) {
daniel parkeeb8e042018-02-21 14:06:58 +0900321 TrafficTreatment treatment;
322
323 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder()
324 .matchEthType(Ethernet.TYPE_IPV4)
325 .matchIPSrc(instPort.ipAddress().toIpPrefix())
326 .matchEthDst(Constants.DEFAULT_GATEWAY_MAC);
327
328 switch (osNet.getNetworkType()) {
329 case VXLAN:
330 sBuilder.matchTunnelId(Long.parseLong(osNet.getProviderSegID()));
331 break;
332 case VLAN:
333 sBuilder.matchVlanId(VlanId.vlanId(osNet.getProviderSegID()));
334 break;
335 default:
336 final String error = String.format(
Ray Milkeyc6c9b172018-02-26 09:36:31 -0800337 ERR_UNSUPPORTED_NET_TYPE,
daniel parkeeb8e042018-02-21 14:06:58 +0900338 osNet.getNetworkType().toString());
339 throw new IllegalStateException(error);
340 }
341
Jian Li1064e4f2018-05-29 16:16:53 +0900342 OpenstackNode selectedGatewayNode = getGwByComputeDevId(gateways, instPort.deviceId());
343
daniel parkeeb8e042018-02-21 14:06:58 +0900344 if (selectedGatewayNode == null) {
daniel parkc2a2ed62018-04-10 15:17:42 +0900345 final String errorFormat = ERR_FLOW + "no gateway node selected";
346 throw new IllegalStateException(errorFormat);
daniel parkeeb8e042018-02-21 14:06:58 +0900347 }
348 treatment = DefaultTrafficTreatment.builder()
349 .extension(buildExtension(
350 deviceService,
351 instPort.deviceId(),
352 selectedGatewayNode.dataIp().getIp4Address()),
353 instPort.deviceId())
354 .setOutput(osNodeService.node(instPort.deviceId()).tunnelPortNum())
355 .build();
356
357 osFlowRuleService.setRule(
358 appId,
359 instPort.deviceId(),
360 sBuilder.build(),
361 treatment,
362 PRIORITY_EXTERNAL_FLOATING_ROUTING_RULE,
363 ROUTING_TABLE,
364 install);
daniel parkc2a2ed62018-04-10 15:17:42 +0900365 log.trace("Succeeded to set flow rules from compute node to gateway on compute node");
daniel parkeeb8e042018-02-21 14:06:58 +0900366 }
367
Jian Lide679782018-06-05 01:41:29 +0900368 private void setDownstreamExternalRulesHelper(NetFloatingIP floatingIp,
369 Network osNet,
370 InstancePort instPort,
371 ExternalPeerRouter externalPeerRouter,
372 Set<OpenstackNode> gateways, boolean install) {
373 OpenstackNode cNode = osNodeService.node(instPort.deviceId());
374 if (cNode == null) {
375 final String error = String.format("Cannot find openstack node for device %s",
376 instPort.deviceId());
377 throw new IllegalStateException(error);
378 }
379 if (osNet.getNetworkType() == NetworkType.VXLAN && cNode.dataIp() == null) {
380 final String errorFormat = ERR_FLOW + "VXLAN mode is not ready for %s";
381 final String error = String.format(errorFormat, floatingIp, cNode.hostname());
382 throw new IllegalStateException(error);
383 }
384 if (osNet.getNetworkType() == NetworkType.VLAN && cNode.vlanIntf() == null) {
385 final String errorFormat = ERR_FLOW + "VLAN mode is not ready for %s";
386 final String error = String.format(errorFormat, floatingIp, cNode.hostname());
387 throw new IllegalStateException(error);
388 }
389
390 IpAddress floating = IpAddress.valueOf(floatingIp.getFloatingIpAddress());
391
392 OpenstackNode selectedGatewayNode = getGwByComputeDevId(gateways, instPort.deviceId());
393
394 if (selectedGatewayNode == null) {
395 final String errorFormat = ERR_FLOW + "no gateway node selected";
396 throw new IllegalStateException(errorFormat);
397 }
398
399 TrafficSelector.Builder externalSelectorBuilder = DefaultTrafficSelector.builder()
400 .matchEthType(Ethernet.TYPE_IPV4)
Daniel Park319b9ab2018-09-14 11:27:04 +0900401 .matchInPort(selectedGatewayNode.uplinkPortNum())
Jian Lide679782018-06-05 01:41:29 +0900402 .matchIPDst(floating.toIpPrefix());
403
404 TrafficTreatment.Builder externalTreatmentBuilder = DefaultTrafficTreatment.builder()
405 .setEthSrc(Constants.DEFAULT_GATEWAY_MAC)
406 .setEthDst(instPort.macAddress())
407 .setIpDst(instPort.ipAddress().getIp4Address());
408
Jian Li5e2ad4a2018-07-16 13:40:53 +0900409 if (!externalPeerRouter.vlanId().equals(VlanId.NONE)) {
410 externalSelectorBuilder.matchVlanId(externalPeerRouter.vlanId()).build();
Jian Lide679782018-06-05 01:41:29 +0900411 externalTreatmentBuilder.popVlan();
412 }
413
414 switch (osNet.getNetworkType()) {
415 case VXLAN:
416 externalTreatmentBuilder.setTunnelId(Long.valueOf(osNet.getProviderSegID()))
417 .extension(buildExtension(
418 deviceService,
419 selectedGatewayNode.intgBridge(),
420 cNode.dataIp().getIp4Address()),
421 selectedGatewayNode.intgBridge())
422 .setOutput(selectedGatewayNode.tunnelPortNum());
423 break;
424 case VLAN:
425 externalTreatmentBuilder.pushVlan()
426 .setVlanId(VlanId.vlanId(osNet.getProviderSegID()))
427 .setOutput(selectedGatewayNode.vlanPortNum());
428 break;
429 default:
430 final String error = String.format(ERR_UNSUPPORTED_NET_TYPE,
431 osNet.getNetworkType());
432 throw new IllegalStateException(error);
433 }
434
435 osFlowRuleService.setRule(
436 appId,
437 selectedGatewayNode.intgBridge(),
438 externalSelectorBuilder.build(),
439 externalTreatmentBuilder.build(),
440 PRIORITY_FLOATING_EXTERNAL,
441 GW_COMMON_TABLE,
442 install);
443 }
444
Hyunsun Moon44aac662017-02-18 02:07:01 +0900445 private void setUpstreamRules(NetFloatingIP floatingIp, Network osNet,
daniel park32b42202018-03-14 16:53:44 +0900446 InstancePort instPort, ExternalPeerRouter externalPeerRouter,
447 boolean install) {
Hyunsun Moon44aac662017-02-18 02:07:01 +0900448 IpAddress floating = IpAddress.valueOf(floatingIp.getFloatingIpAddress());
daniel parkee8700b2017-05-11 15:50:03 +0900449 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder()
Hyunsun Moon44aac662017-02-18 02:07:01 +0900450 .matchEthType(Ethernet.TYPE_IPV4)
daniel parkee8700b2017-05-11 15:50:03 +0900451 .matchIPSrc(instPort.ipAddress().toIpPrefix());
452
453 switch (osNet.getNetworkType()) {
454 case VXLAN:
455 sBuilder.matchTunnelId(Long.valueOf(osNet.getProviderSegID()));
456 break;
457 case VLAN:
458 sBuilder.matchVlanId(VlanId.vlanId(osNet.getProviderSegID()));
459 break;
460 default:
Ray Milkeyc6c9b172018-02-26 09:36:31 -0800461 final String error = String.format(ERR_UNSUPPORTED_NET_TYPE,
Hyunsun Moon0d457362017-06-27 17:19:41 +0900462 osNet.getNetworkType());
daniel parkee8700b2017-05-11 15:50:03 +0900463 throw new IllegalStateException(error);
464 }
Hyunsun Moon44aac662017-02-18 02:07:01 +0900465
Daniel Park75e3d7f2018-05-29 14:43:53 +0900466 TrafficSelector selector = sBuilder.build();
daniel parkeeb8e042018-02-21 14:06:58 +0900467
Hyunsun Moon0d457362017-06-27 17:19:41 +0900468 osNodeService.completeNodes(GATEWAY).forEach(gNode -> {
Daniel Park75e3d7f2018-05-29 14:43:53 +0900469 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder()
470 .setIpSrc(floating.getIp4Address())
471 .setEthSrc(instPort.macAddress())
Jian Li5e2ad4a2018-07-16 13:40:53 +0900472 .setEthDst(externalPeerRouter.macAddress());
Hyunsun Moon44aac662017-02-18 02:07:01 +0900473
Daniel Park75e3d7f2018-05-29 14:43:53 +0900474 if (osNet.getNetworkType().equals(NetworkType.VLAN)) {
475 tBuilder.popVlan();
476 }
477
Jian Li5e2ad4a2018-07-16 13:40:53 +0900478 if (!externalPeerRouter.vlanId().equals(VlanId.NONE)) {
479 tBuilder.pushVlan().setVlanId(externalPeerRouter.vlanId());
Daniel Park75e3d7f2018-05-29 14:43:53 +0900480 }
sanghodc375372017-06-08 10:41:30 +0900481 osFlowRuleService.setRule(
Hyunsun Moon44aac662017-02-18 02:07:01 +0900482 appId,
Hyunsun Moon0d457362017-06-27 17:19:41 +0900483 gNode.intgBridge(),
Daniel Park75e3d7f2018-05-29 14:43:53 +0900484 selector,
daniel parkeeb8e042018-02-21 14:06:58 +0900485 tBuilder.setOutput(gNode.uplinkPortNum()).build(),
Hyunsun Moon44aac662017-02-18 02:07:01 +0900486 PRIORITY_FLOATING_EXTERNAL,
sanghodc375372017-06-08 10:41:30 +0900487 GW_COMMON_TABLE,
Hyunsun Moon44aac662017-02-18 02:07:01 +0900488 install);
Daniel Park75e3d7f2018-05-29 14:43:53 +0900489 });
daniel parkc2a2ed62018-04-10 15:17:42 +0900490 log.trace("Succeeded to set flow rules for upstream on gateway nodes");
Hyunsun Moon44aac662017-02-18 02:07:01 +0900491 }
492
daniel park32b42202018-03-14 16:53:44 +0900493 private ExternalPeerRouter externalPeerRouter(Network network) {
daniel parkeeb8e042018-02-21 14:06:58 +0900494 if (network == null) {
495 return null;
496 }
497
498 Subnet subnet = osNetworkService.subnets(network.getId()).stream().findAny().orElse(null);
499
500 if (subnet == null) {
501 return null;
502 }
503
Jian Lif3a28b02018-06-11 21:29:13 +0900504 RouterInterface osRouterIface = osRouterAdminService.routerInterfaces().stream()
daniel parkeeb8e042018-02-21 14:06:58 +0900505 .filter(i -> Objects.equals(i.getSubnetId(), subnet.getId()))
506 .findAny().orElse(null);
507 if (osRouterIface == null) {
508 return null;
509 }
510
Jian Lif3a28b02018-06-11 21:29:13 +0900511 Router osRouter = osRouterAdminService.router(osRouterIface.getId());
daniel parkeeb8e042018-02-21 14:06:58 +0900512 if (osRouter == null) {
513 return null;
514 }
515 if (osRouter.getExternalGatewayInfo() == null) {
516 return null;
517 }
518
519 ExternalGateway exGatewayInfo = osRouter.getExternalGatewayInfo();
daniel park65e1c202018-04-03 13:15:28 +0900520 return osNetworkService.externalPeerRouter(exGatewayInfo);
daniel parkeeb8e042018-02-21 14:06:58 +0900521 }
daniel park65e1c202018-04-03 13:15:28 +0900522
Jian Li99892e92018-04-13 14:59:39 +0900523 private void associateFloatingIp(NetFloatingIP osFip) {
Jian Li628a7cb2018-08-11 23:04:24 +0900524 InstancePort instPort = instancePortService.instancePort(osFip.getPortId());
525
526 if (instPort == null) {
527 log.warn("Failed to insert floating IP rule for {} due to missing of port info.",
528 osFip.getFloatingIpAddress());
529 return;
Jian Li99892e92018-04-13 14:59:39 +0900530 }
Jian Li628a7cb2018-08-11 23:04:24 +0900531
Jian Li99892e92018-04-13 14:59:39 +0900532 // set floating IP rules only if the port is associated to a VM
Jian Li628a7cb2018-08-11 23:04:24 +0900533 if (!Strings.isNullOrEmpty(instPort.deviceId().toString())) {
534 setFloatingIpRules(osFip, instPort, null, true);
Jian Li99892e92018-04-13 14:59:39 +0900535 }
536 }
537
538 private void disassociateFloatingIp(NetFloatingIP osFip, String portId) {
Jian Li628a7cb2018-08-11 23:04:24 +0900539 InstancePort instPort = instancePortService.instancePort(portId);
Jian Lie1a39032018-06-19 21:49:36 +0900540
Jian Li628a7cb2018-08-11 23:04:24 +0900541 if (instPort == null) {
542 log.warn("Failed to remove floating IP rule for {} due to missing of port info.",
543 osFip.getFloatingIpAddress());
544 return;
Jian Lie1a39032018-06-19 21:49:36 +0900545 }
546
Jian Li99892e92018-04-13 14:59:39 +0900547 // set floating IP rules only if the port is associated to a VM
Jian Li628a7cb2018-08-11 23:04:24 +0900548 if (!Strings.isNullOrEmpty(instPort.deviceId().toString())) {
549 setFloatingIpRules(osFip, instPort, null, false);
Jian Li99892e92018-04-13 14:59:39 +0900550 }
551 }
552
Hyunsun Moon0d457362017-06-27 17:19:41 +0900553 private class InternalFloatingIpListener implements OpenstackRouterListener {
Hyunsun Moon44aac662017-02-18 02:07:01 +0900554
555 @Override
556 public boolean isRelevant(OpenstackRouterEvent event) {
557 // do not allow to proceed without leadership
558 NodeId leader = leadershipService.getLeader(appId.name());
559 if (!Objects.equals(localNodeId, leader)) {
560 return false;
561 }
562 return event.floatingIp() != null;
563 }
564
565 @Override
566 public void event(OpenstackRouterEvent event) {
567 switch (event.type()) {
568 case OPENSTACK_FLOATING_IP_ASSOCIATED:
Hyunsun Moon7a5f9042017-05-11 18:19:01 +0900569 eventExecutor.execute(() -> {
Hyunsun Moonb720e632017-05-16 15:41:36 +0900570 NetFloatingIP osFip = event.floatingIp();
571 associateFloatingIp(osFip);
572 log.info("Associated floating IP {}:{}",
573 osFip.getFloatingIpAddress(), osFip.getFixedIpAddress());
Hyunsun Moon7a5f9042017-05-11 18:19:01 +0900574 });
575 break;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900576 case OPENSTACK_FLOATING_IP_DISASSOCIATED:
577 eventExecutor.execute(() -> {
Hyunsun Moonb720e632017-05-16 15:41:36 +0900578 NetFloatingIP osFip = event.floatingIp();
579 disassociateFloatingIp(osFip, event.portId());
580 log.info("Disassociated floating IP {}:{}",
581 osFip.getFloatingIpAddress(), osFip.getFixedIpAddress());
Hyunsun Moon7a5f9042017-05-11 18:19:01 +0900582 });
583 break;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900584 case OPENSTACK_FLOATING_IP_CREATED:
Hyunsun Moonb720e632017-05-16 15:41:36 +0900585 eventExecutor.execute(() -> {
586 NetFloatingIP osFip = event.floatingIp();
587 if (!Strings.isNullOrEmpty(osFip.getPortId())) {
588 associateFloatingIp(event.floatingIp());
589 }
590 log.info("Created floating IP {}", osFip.getFloatingIpAddress());
591 });
592 break;
Jian Lia171a432018-06-11 11:52:11 +0900593 case OPENSTACK_FLOATING_IP_REMOVED:
594 eventExecutor.execute(() -> {
595 NetFloatingIP osFip = event.floatingIp();
596 if (!Strings.isNullOrEmpty(osFip.getPortId())) {
Jian Lic2403592018-07-18 12:56:45 +0900597 // in case the floating IP is not associated with any port due to
598 // port removal, we simply do not execute floating IP disassociation
599 if (osNetworkService.port(osFip.getPortId()) != null) {
600 disassociateFloatingIp(osFip, osFip.getPortId());
601 }
Jian Lida03ce92018-07-24 21:41:53 +0900602
603 // since we skip floating IP disassociation, we need to
604 // manually unsubscribe the port pre-remove event
605 preCommitPortService.unsubscribePreCommit(osFip.getPortId(),
Jian Li628a7cb2018-08-11 23:04:24 +0900606 OPENSTACK_PORT_PRE_REMOVE, instancePortService,
607 this.getClass().getName());
Jian Lida03ce92018-07-24 21:41:53 +0900608 log.info("Unsubscribed the port {} on listening pre-remove event", osFip.getPortId());
Jian Lia171a432018-06-11 11:52:11 +0900609 }
610 log.info("Removed floating IP {}", osFip.getFloatingIpAddress());
611 });
612 break;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900613 case OPENSTACK_FLOATING_IP_UPDATED:
Hyunsun Moon44aac662017-02-18 02:07:01 +0900614 case OPENSTACK_ROUTER_CREATED:
615 case OPENSTACK_ROUTER_UPDATED:
616 case OPENSTACK_ROUTER_REMOVED:
617 case OPENSTACK_ROUTER_INTERFACE_ADDED:
618 case OPENSTACK_ROUTER_INTERFACE_UPDATED:
619 case OPENSTACK_ROUTER_INTERFACE_REMOVED:
620 default:
621 // do nothing for the other events
622 break;
623 }
624 }
625 }
626
627 private class InternalNodeListener implements OpenstackNodeListener {
628
629 @Override
630 public boolean isRelevant(OpenstackNodeEvent event) {
631 // do not allow to proceed without leadership
632 NodeId leader = leadershipService.getLeader(appId.name());
633 if (!Objects.equals(localNodeId, leader)) {
634 return false;
635 }
636 return event.subject().type() == GATEWAY;
637 }
638
639 @Override
640 public void event(OpenstackNodeEvent event) {
Hyunsun Moon44aac662017-02-18 02:07:01 +0900641
642 switch (event.type()) {
Hyunsun Moon0d457362017-06-27 17:19:41 +0900643 case OPENSTACK_NODE_COMPLETE:
Hyunsun Moon44aac662017-02-18 02:07:01 +0900644 eventExecutor.execute(() -> {
Jian Lif3a28b02018-06-11 21:29:13 +0900645 for (NetFloatingIP fip : osRouterAdminService.floatingIps()) {
Jian Lie1a39032018-06-19 21:49:36 +0900646
Hyunsun Moon7a5f9042017-05-11 18:19:01 +0900647 if (Strings.isNullOrEmpty(fip.getPortId())) {
648 continue;
649 }
Jian Lie1a39032018-06-19 21:49:36 +0900650
Hyunsun Moon7a5f9042017-05-11 18:19:01 +0900651 Port osPort = osNetworkService.port(fip.getPortId());
Jian Li628a7cb2018-08-11 23:04:24 +0900652 InstancePort instPort = instancePortService.instancePort(fip.getPortId());
653
654 // we check both Openstack Port and Instance Port
655 if (osPort == null || instPort == null) {
Hyunsun Moon7a5f9042017-05-11 18:19:01 +0900656 continue;
657 }
Jian Lie1a39032018-06-19 21:49:36 +0900658
Jian Li628a7cb2018-08-11 23:04:24 +0900659 setFloatingIpRules(fip, instPort, event.subject(), true);
Hyunsun Moon7a5f9042017-05-11 18:19:01 +0900660 }
Hyunsun Moon44aac662017-02-18 02:07:01 +0900661 });
662 break;
Hyunsun Moon0d457362017-06-27 17:19:41 +0900663 case OPENSTACK_NODE_INCOMPLETE:
Jian Li1064e4f2018-05-29 16:16:53 +0900664 eventExecutor.execute(() -> {
Jian Lif3a28b02018-06-11 21:29:13 +0900665 for (NetFloatingIP fip : osRouterAdminService.floatingIps()) {
Jian Li1064e4f2018-05-29 16:16:53 +0900666 if (Strings.isNullOrEmpty(fip.getPortId())) {
667 continue;
668 }
669 Port osPort = osNetworkService.port(fip.getPortId());
670 if (osPort == null) {
671 log.warn("Failed to set floating IP {}", fip.getId());
672 continue;
673 }
674 Network osNet = osNetworkService.network(osPort.getNetworkId());
675 if (osNet == null) {
676 final String errorFormat = ERR_FLOW + "no network(%s) exists";
677 final String error = String.format(errorFormat,
678 fip.getFloatingIpAddress(),
679 osPort.getNetworkId());
680 throw new IllegalStateException(error);
681 }
682 MacAddress srcMac = MacAddress.valueOf(osPort.getMacAddress());
683 log.trace("Mac address of openstack port: {}", srcMac);
684 InstancePort instPort = instancePortService.instancePort(srcMac);
685
686 if (instPort == null) {
687 final String errorFormat = ERR_FLOW + "no host(MAC:%s) found";
688 final String error = String.format(errorFormat,
689 fip.getFloatingIpAddress(), srcMac);
690 throw new IllegalStateException(error);
691 }
692
Jian Lide679782018-06-05 01:41:29 +0900693 ExternalPeerRouter externalPeerRouter = externalPeerRouter(osNet);
694 if (externalPeerRouter == null) {
695 final String errorFormat = ERR_FLOW + "no external peer router found";
696 throw new IllegalStateException(errorFormat);
697 }
698
699 updateComputeNodeRules(instPort, osNet, event.subject(), false);
700 updateGatewayNodeRules(fip, instPort, osNet,
701 externalPeerRouter, event.subject(), false);
Jian Li1064e4f2018-05-29 16:16:53 +0900702 }
703 });
704 break;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900705 default:
Hyunsun Moon0d457362017-06-27 17:19:41 +0900706 // do nothing
Hyunsun Moon44aac662017-02-18 02:07:01 +0900707 break;
708 }
709 }
710 }
Jian Li99892e92018-04-13 14:59:39 +0900711
Jian Li24ec59f2018-05-23 19:01:25 +0900712 private class InternalInstancePortListener implements InstancePortListener {
713
714 @Override
715 public boolean isRelevant(InstancePortEvent event) {
Jian Li24ec59f2018-05-23 19:01:25 +0900716
Jian Lie1a39032018-06-19 21:49:36 +0900717 if (event.type() == OPENSTACK_INSTANCE_MIGRATION_ENDED ||
718 event.type() == OPENSTACK_INSTANCE_MIGRATION_STARTED) {
719 Set<NetFloatingIP> ips = osRouterAdminService.floatingIps();
720 NetFloatingIP fip = associatedFloatingIp(event.subject(), ips);
721
722 // we check the possible NPE to avoid duplicated null check
723 // for OPENSTACK_INSTANCE_MIGRATION_ENDED and
724 // OPENSTACK_INSTANCE_MIGRATION_STARTED cases
725 if (fip == null || !isAssociatedWithVM(osNetworkService, fip)) {
726 return false;
727 }
728 }
729
730 // do not allow to proceed without leadership
731 NodeId leader = leadershipService.getLeader(appId.name());
732
733 return Objects.equals(localNodeId, leader);
Jian Li24ec59f2018-05-23 19:01:25 +0900734 }
735
736 @Override
737 public void event(InstancePortEvent event) {
Jian Lie1a39032018-06-19 21:49:36 +0900738 InstancePort instPort = event.subject();
Jian Li24ec59f2018-05-23 19:01:25 +0900739 Set<OpenstackNode> gateways = osNodeService.completeNodes(GATEWAY);
740
Jian Lie1a39032018-06-19 21:49:36 +0900741 Set<NetFloatingIP> ips = osRouterAdminService.floatingIps();
742 NetFloatingIP fip;
743 Port osPort;
744 Network osNet;
745 ExternalPeerRouter externalPeerRouter;
Jian Li24ec59f2018-05-23 19:01:25 +0900746
747 switch (event.type()) {
Jian Lie1a39032018-06-19 21:49:36 +0900748 case OPENSTACK_INSTANCE_PORT_DETECTED:
Jian Li77323c52018-06-24 01:26:18 +0900749 if (instPort != null && instPort.portId() != null) {
Jian Li46b74002018-07-15 18:39:08 +0900750 osRouterAdminService.floatingIps().stream()
751 .filter(f -> f.getPortId() != null)
752 .filter(f -> f.getPortId().equals(instPort.portId()))
Jian Li628a7cb2018-08-11 23:04:24 +0900753 .forEach(f -> setFloatingIpRules(f, instPort, null, true));
Jian Lie1a39032018-06-19 21:49:36 +0900754 }
755
756 break;
757
Jian Li24ec59f2018-05-23 19:01:25 +0900758 case OPENSTACK_INSTANCE_MIGRATION_STARTED:
Jian Lie1a39032018-06-19 21:49:36 +0900759
760 fip = associatedFloatingIp(event.subject(), ips);
761
762 if (fip == null) {
763 return;
764 }
765
766 osPort = osNetworkService.port(fip.getPortId());
767 osNet = osNetworkService.network(osPort.getNetworkId());
768 externalPeerRouter = externalPeerRouter(osNet);
769
770 if (externalPeerRouter == null) {
771 final String errorFormat = ERR_FLOW + "no external peer router found";
772 throw new IllegalStateException(errorFormat);
773 }
774
Jian Li24ec59f2018-05-23 19:01:25 +0900775 eventExecutor.execute(() -> {
776
Jian Li24ec59f2018-05-23 19:01:25 +0900777 // since DownstreamExternal rules should only be placed in
778 // corresponding gateway node, we need to install new rule to
779 // the corresponding gateway node
780 setDownstreamExternalRulesHelper(fip, osNet,
781 event.subject(), externalPeerRouter, gateways, true);
782
783 // since ComputeNodeToGateway rules should only be placed in
784 // corresponding compute node, we need to install new rule to
785 // the target compute node, and remove rules from original node
786 setComputeNodeToGatewayHelper(event.subject(), osNet, gateways, true);
Jian Li24ec59f2018-05-23 19:01:25 +0900787 });
788 break;
789 case OPENSTACK_INSTANCE_MIGRATION_ENDED:
790
Jian Liec5c32b2018-07-13 14:28:58 +0900791 InstancePort revisedInstPort = swapStaleLocation(event.subject());
792
793 fip = associatedFloatingIp(revisedInstPort, ips);
Jian Lie1a39032018-06-19 21:49:36 +0900794
795 if (fip == null) {
796 return;
797 }
798
799 osPort = osNetworkService.port(fip.getPortId());
800 osNet = osNetworkService.network(osPort.getNetworkId());
801 externalPeerRouter = externalPeerRouter(osNet);
802
803 if (externalPeerRouter == null) {
804 final String errorFormat = ERR_FLOW + "no external peer router found";
805 throw new IllegalStateException(errorFormat);
806 }
807
808 // If we only have one gateway, we simply do not remove any
Jian Li24ec59f2018-05-23 19:01:25 +0900809 // flow rules from either gateway or compute node
810 if (gateways.size() == 1) {
811 return;
812 }
813
Jian Lie1a39032018-06-19 21:49:36 +0900814 // Checks whether the destination compute node's device id
Jian Li24ec59f2018-05-23 19:01:25 +0900815 // has identical gateway hash or not
816 // if it is true, we simply do not remove the rules, as
817 // it has been overwritten at port detention event
818 // if it is false, we will remove the rules
Jian Liec5c32b2018-07-13 14:28:58 +0900819 DeviceId newDeviceId = event.subject().deviceId();
820 DeviceId oldDeviceId = revisedInstPort.deviceId();
Jian Li24ec59f2018-05-23 19:01:25 +0900821
822 OpenstackNode oldGateway = getGwByComputeDevId(gateways, oldDeviceId);
823 OpenstackNode newGateway = getGwByComputeDevId(gateways, newDeviceId);
824
825 if (oldGateway != null && oldGateway.equals(newGateway)) {
826 return;
827 }
828
829 eventExecutor.execute(() -> {
830
Jian Lie1a39032018-06-19 21:49:36 +0900831 // We need to remove the old ComputeNodeToGateway rules from
Jian Li24ec59f2018-05-23 19:01:25 +0900832 // original compute node
Jian Liec5c32b2018-07-13 14:28:58 +0900833 setComputeNodeToGatewayHelper(revisedInstPort, osNet, gateways, false);
Jian Li24ec59f2018-05-23 19:01:25 +0900834
Jian Lie1a39032018-06-19 21:49:36 +0900835 // Since DownstreamExternal rules should only be placed in
Jian Li24ec59f2018-05-23 19:01:25 +0900836 // corresponding gateway node, we need to remove old rule from
837 // the corresponding gateway node
Jian Liec5c32b2018-07-13 14:28:58 +0900838 setDownstreamExternalRulesHelper(fip, osNet, revisedInstPort,
839 externalPeerRouter, gateways, false);
Jian Li24ec59f2018-05-23 19:01:25 +0900840 });
841 break;
842 default:
843 break;
844 }
845 }
846 }
Jian Lie1a39032018-06-19 21:49:36 +0900847
848 private class InternalOpenstackNetworkListener implements OpenstackNetworkListener {
849
850 @Override
851 public boolean isRelevant(OpenstackNetworkEvent event) {
852 // do not allow to proceed without leadership
853 NodeId leader = leadershipService.getLeader(appId.name());
Jian Lida03ce92018-07-24 21:41:53 +0900854 return Objects.equals(localNodeId, leader);
Jian Lie1a39032018-06-19 21:49:36 +0900855 }
856
857 @Override
858 public void event(OpenstackNetworkEvent event) {
859 switch (event.type()) {
Jian Li8f64feb2018-07-24 13:20:16 +0900860 case OPENSTACK_PORT_PRE_REMOVE:
Jian Li427811e2018-08-28 17:35:16 +0900861 InstancePort instPort =
862 instancePortService.instancePort(event.port().getId());
Jian Libcc42282018-09-13 20:59:34 +0900863
864 if (instPort == null) {
865 break;
866 }
867
Jian Li427811e2018-08-28 17:35:16 +0900868 NetFloatingIP fip =
869 associatedFloatingIp(instPort, osRouterAdminService.floatingIps());
870
871 if (fip != null) {
872 eventExecutor.execute(() ->
873 updateFipStore(instancePortService.instancePort(event.port().getId())));
874 } else {
875 instancePortService.removeInstancePort(instPort.portId());
876 }
Jian Li8f64feb2018-07-24 13:20:16 +0900877 break;
Jian Lie1a39032018-06-19 21:49:36 +0900878 default:
879 break;
880 }
881 }
882
883 private void updateFipStore(InstancePort port) {
884
885 if (port == null) {
886 return;
887 }
888
889 Set<NetFloatingIP> ips = osRouterAdminService.floatingIps();
890 for (NetFloatingIP fip : ips) {
891 if (Strings.isNullOrEmpty(fip.getFixedIpAddress())) {
892 continue;
893 }
894 if (Strings.isNullOrEmpty(fip.getFloatingIpAddress())) {
895 continue;
896 }
897 if (fip.getFixedIpAddress().equals(port.ipAddress().toString())) {
898 NeutronFloatingIP neutronFip = (NeutronFloatingIP) fip;
899 // invalidate bound fixed IP and port
900 neutronFip.setFixedIpAddress(null);
901 neutronFip.setPortId(null);
Jian Lie1a39032018-06-19 21:49:36 +0900902
903 // Following update will in turn trigger
904 // OPENSTACK_FLOATING_IP_DISASSOCIATED event
905 osRouterAdminService.updateFloatingIp(neutronFip);
906 log.info("Updated floating IP {}, due to host removal",
907 neutronFip.getFloatingIpAddress());
908 }
909 }
910 }
911 }
Hyunsun Moon44aac662017-02-18 02:07:01 +0900912}