blob: 1c838def66e3648c84f29539062a0369a52bcca1 [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.onlab.packet.Ethernet;
22import org.onlab.packet.IpAddress;
23import org.onlab.packet.MacAddress;
daniel parkee8700b2017-05-11 15:50:03 +090024import org.onlab.packet.VlanId;
Hyunsun Moon44aac662017-02-18 02:07:01 +090025import org.onosproject.cluster.ClusterService;
26import org.onosproject.cluster.LeadershipService;
27import org.onosproject.cluster.NodeId;
28import org.onosproject.core.ApplicationId;
29import org.onosproject.core.CoreService;
Jian Li24ec59f2018-05-23 19:01:25 +090030import org.onosproject.net.DeviceId;
Hyunsun Moon44aac662017-02-18 02:07:01 +090031import org.onosproject.net.device.DeviceService;
32import org.onosproject.net.flow.DefaultTrafficSelector;
33import org.onosproject.net.flow.DefaultTrafficTreatment;
34import org.onosproject.net.flow.TrafficSelector;
35import org.onosproject.net.flow.TrafficTreatment;
Daniel Park4fa1f5e2018-10-17 12:41:52 +090036import org.onosproject.net.packet.PacketService;
Hyunsun Moon44aac662017-02-18 02:07:01 +090037import org.onosproject.openstacknetworking.api.Constants;
daniel park32b42202018-03-14 16:53:44 +090038import org.onosproject.openstacknetworking.api.ExternalPeerRouter;
Hyunsun Moon44aac662017-02-18 02:07:01 +090039import org.onosproject.openstacknetworking.api.InstancePort;
Jian Liec5c32b2018-07-13 14:28:58 +090040import org.onosproject.openstacknetworking.api.InstancePortAdminService;
Jian Li24ec59f2018-05-23 19:01:25 +090041import org.onosproject.openstacknetworking.api.InstancePortEvent;
42import org.onosproject.openstacknetworking.api.InstancePortListener;
sanghodc375372017-06-08 10:41:30 +090043import org.onosproject.openstacknetworking.api.OpenstackFlowRuleService;
Jian Lie1a39032018-06-19 21:49:36 +090044import org.onosproject.openstacknetworking.api.OpenstackNetworkEvent;
45import org.onosproject.openstacknetworking.api.OpenstackNetworkListener;
sanghodc375372017-06-08 10:41:30 +090046import org.onosproject.openstacknetworking.api.OpenstackNetworkService;
Jian Lif3a28b02018-06-11 21:29:13 +090047import org.onosproject.openstacknetworking.api.OpenstackRouterAdminService;
Hyunsun Moon44aac662017-02-18 02:07:01 +090048import org.onosproject.openstacknetworking.api.OpenstackRouterEvent;
49import org.onosproject.openstacknetworking.api.OpenstackRouterListener;
Jian Li8f64feb2018-07-24 13:20:16 +090050import org.onosproject.openstacknetworking.api.PreCommitPortService;
Hyunsun Moon0d457362017-06-27 17:19:41 +090051import org.onosproject.openstacknode.api.OpenstackNode;
52import org.onosproject.openstacknode.api.OpenstackNodeEvent;
53import org.onosproject.openstacknode.api.OpenstackNodeListener;
54import org.onosproject.openstacknode.api.OpenstackNodeService;
Hyunsun Moon44aac662017-02-18 02:07:01 +090055import org.openstack4j.model.network.NetFloatingIP;
56import org.openstack4j.model.network.Network;
daniel parkee8700b2017-05-11 15:50:03 +090057import org.openstack4j.model.network.NetworkType;
Hyunsun Moon44aac662017-02-18 02:07:01 +090058import org.openstack4j.model.network.Port;
Jian Lif3a28b02018-06-11 21:29:13 +090059import org.openstack4j.openstack.networking.domain.NeutronFloatingIP;
Jian Li34220ea2018-11-14 01:30:24 +090060import org.osgi.service.component.annotations.Activate;
61import org.osgi.service.component.annotations.Component;
62import org.osgi.service.component.annotations.Deactivate;
63import org.osgi.service.component.annotations.Reference;
64import org.osgi.service.component.annotations.ReferenceCardinality;
Hyunsun Moon44aac662017-02-18 02:07:01 +090065import org.slf4j.Logger;
66import org.slf4j.LoggerFactory;
67
68import java.util.Objects;
Jian Li99892e92018-04-13 14:59:39 +090069import java.util.Set;
Hyunsun Moon44aac662017-02-18 02:07:01 +090070import java.util.concurrent.ExecutorService;
71
72import static java.util.concurrent.Executors.newSingleThreadExecutor;
73import static org.onlab.util.Tools.groupedThreads;
sanghodc375372017-06-08 10:41:30 +090074import static org.onosproject.openstacknetworking.api.Constants.GW_COMMON_TABLE;
75import static org.onosproject.openstacknetworking.api.Constants.OPENSTACK_NETWORKING_APP_ID;
daniel parkeeb8e042018-02-21 14:06:58 +090076import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_EXTERNAL_FLOATING_ROUTING_RULE;
sanghodc375372017-06-08 10:41:30 +090077import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_FLOATING_EXTERNAL;
daniel parkeeb8e042018-02-21 14:06:58 +090078import static org.onosproject.openstacknetworking.api.Constants.ROUTING_TABLE;
Jian Li8a5fb642018-09-14 15:50:04 +090079import static org.onosproject.openstacknetworking.api.InstancePort.State.REMOVE_PENDING;
Jian Lie1a39032018-06-19 21:49:36 +090080import static org.onosproject.openstacknetworking.api.InstancePortEvent.Type.OPENSTACK_INSTANCE_MIGRATION_ENDED;
81import static org.onosproject.openstacknetworking.api.InstancePortEvent.Type.OPENSTACK_INSTANCE_MIGRATION_STARTED;
Jian Li8f64feb2018-07-24 13:20:16 +090082import static org.onosproject.openstacknetworking.api.OpenstackNetworkEvent.Type.OPENSTACK_PORT_PRE_REMOVE;
Jian Li24ec59f2018-05-23 19:01:25 +090083import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.associatedFloatingIp;
Daniel Park4fa1f5e2018-10-17 12:41:52 +090084import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.externalPeerRouterForNetwork;
Jian Li1064e4f2018-05-29 16:16:53 +090085import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.getGwByComputeDevId;
Daniel Park4fa1f5e2018-10-17 12:41:52 +090086import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.getGwByInstancePort;
Jian Li24ec59f2018-05-23 19:01:25 +090087import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.isAssociatedWithVM;
Jian Li32b03622018-11-06 17:54:24 +090088import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.processGarpPacketForFloatingIp;
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
Jian Li4d138702018-11-27 17:25:28 +0900104 private static final String NO_EXT_PEER_ROUTER_MSG = "no external peer router found";
105
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700106 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Hyunsun Moon44aac662017-02-18 02:07:01 +0900107 protected CoreService coreService;
108
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700109 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Hyunsun Moon44aac662017-02-18 02:07:01 +0900110 protected DeviceService deviceService;
111
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700112 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Hyunsun Moon44aac662017-02-18 02:07:01 +0900113 protected LeadershipService leadershipService;
114
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700115 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Hyunsun Moon44aac662017-02-18 02:07:01 +0900116 protected ClusterService clusterService;
117
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700118 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Hyunsun Moon44aac662017-02-18 02:07:01 +0900119 protected OpenstackNodeService osNodeService;
120
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700121 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jian Liec5c32b2018-07-13 14:28:58 +0900122 protected InstancePortAdminService instancePortService;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900123
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700124 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jian Lif3a28b02018-06-11 21:29:13 +0900125 protected OpenstackRouterAdminService osRouterAdminService;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900126
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700127 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Hyunsun Moon44aac662017-02-18 02:07:01 +0900128 protected OpenstackNetworkService osNetworkService;
129
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700130 @Reference(cardinality = ReferenceCardinality.MANDATORY)
sanghodc375372017-06-08 10:41:30 +0900131 protected OpenstackFlowRuleService osFlowRuleService;
132
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700133 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jian Li8f64feb2018-07-24 13:20:16 +0900134 protected PreCommitPortService preCommitPortService;
135
Ray Milkeyd5425682018-10-23 10:21:33 -0700136 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Daniel Park4fa1f5e2018-10-17 12:41:52 +0900137 protected PacketService packetService;
138
Hyunsun Moon44aac662017-02-18 02:07:01 +0900139 private final ExecutorService eventExecutor = newSingleThreadExecutor(
140 groupedThreads(this.getClass().getSimpleName(), "event-handler", log));
Jian Li5ecfd1a2018-12-10 11:41:03 +0900141 private final OpenstackRouterListener
142 floatingIpListener = new InternalFloatingIpListener();
143 private final InstancePortListener
144 instancePortListener = new InternalInstancePortListener();
145 private final OpenstackNodeListener
146 osNodeListener = new InternalNodeListener();
147 private final OpenstackNetworkListener
148 osNetworkListener = new InternalOpenstackNetworkListener();
149 private final InstancePortListener
150 instPortListener = new InternalInstancePortListener();
Jian Lie1a39032018-06-19 21:49:36 +0900151
Hyunsun Moon44aac662017-02-18 02:07:01 +0900152 private ApplicationId appId;
153 private NodeId localNodeId;
154
155 @Activate
156 protected void activate() {
157 appId = coreService.registerApplication(OPENSTACK_NETWORKING_APP_ID);
158 localNodeId = clusterService.getLocalNode().id();
159 leadershipService.runForLeadership(appId.name());
Jian Li24ec59f2018-05-23 19:01:25 +0900160 osRouterAdminService.addListener(floatingIpListener);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900161 osNodeService.addListener(osNodeListener);
Jian Li24ec59f2018-05-23 19:01:25 +0900162 instancePortService.addListener(instancePortListener);
Jian Lie1a39032018-06-19 21:49:36 +0900163 osNodeService.addListener(osNodeListener);
164 osNetworkService.addListener(osNetworkListener);
165 instancePortService.addListener(instPortListener);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900166
167 log.info("Started");
168 }
169
170 @Deactivate
171 protected void deactivate() {
Jian Li24ec59f2018-05-23 19:01:25 +0900172 instancePortService.removeListener(instancePortListener);
Jian Lie1a39032018-06-19 21:49:36 +0900173 instancePortService.removeListener(instPortListener);
174 osNetworkService.removeListener(osNetworkListener);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900175 osNodeService.removeListener(osNodeListener);
Jian Li24ec59f2018-05-23 19:01:25 +0900176 osRouterAdminService.removeListener(floatingIpListener);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900177 leadershipService.withdraw(appId.name());
178 eventExecutor.shutdown();
179
180 log.info("Stopped");
181 }
182
Jian Li628a7cb2018-08-11 23:04:24 +0900183 private void setFloatingIpRules(NetFloatingIP floatingIp, InstancePort instPort,
Jian Li1064e4f2018-05-29 16:16:53 +0900184 OpenstackNode gateway, boolean install) {
Jian Li628a7cb2018-08-11 23:04:24 +0900185
186 if (instPort == null) {
187 log.debug("No instance port found");
188 return;
189 }
190
191 Network osNet = osNetworkService.network(instPort.networkId());
Jian Li8f64feb2018-07-24 13:20:16 +0900192
Daniel Park4fa1f5e2018-10-17 12:41:52 +0900193 ExternalPeerRouter externalPeerRouter = externalPeerRouterForNetwork(osNet,
194 osNetworkService, osRouterAdminService);
daniel park32b42202018-03-14 16:53:44 +0900195 if (externalPeerRouter == null) {
Jian Li4d138702018-11-27 17:25:28 +0900196 final String errorFormat = ERR_FLOW + NO_EXT_PEER_ROUTER_MSG;
daniel parkc2a2ed62018-04-10 15:17:42 +0900197 throw new IllegalStateException(errorFormat);
daniel park32b42202018-03-14 16:53:44 +0900198 }
199
Jian Li8f64feb2018-07-24 13:20:16 +0900200 if (install) {
Jian Li628a7cb2018-08-11 23:04:24 +0900201 preCommitPortService.subscribePreCommit(instPort.portId(),
Jian Li8f64feb2018-07-24 13:20:16 +0900202 OPENSTACK_PORT_PRE_REMOVE, this.getClass().getName());
Jian Li628a7cb2018-08-11 23:04:24 +0900203 log.info("Subscribed the port {} on listening pre-remove event", instPort.portId());
Jian Li8f64feb2018-07-24 13:20:16 +0900204 } else {
Jian Li628a7cb2018-08-11 23:04:24 +0900205 preCommitPortService.unsubscribePreCommit(instPort.portId(),
206 OPENSTACK_PORT_PRE_REMOVE, instancePortService, this.getClass().getName());
207 log.info("Unsubscribed the port {} on listening pre-remove event", instPort.portId());
Jian Li8f64feb2018-07-24 13:20:16 +0900208 }
209
Jian Lide679782018-06-05 01:41:29 +0900210 updateComputeNodeRules(instPort, osNet, gateway, install);
211 updateGatewayNodeRules(floatingIp, instPort, osNet, externalPeerRouter, gateway, install);
212
Jian Lide679782018-06-05 01:41:29 +0900213 // TODO: need to refactor setUpstreamRules if possible
daniel park32b42202018-03-14 16:53:44 +0900214 setUpstreamRules(floatingIp, osNet, instPort, externalPeerRouter, install);
Jian Li8f64feb2018-07-24 13:20:16 +0900215
daniel parkc2a2ed62018-04-10 15:17:42 +0900216 log.trace("Succeeded to set flow rules for floating ip {}:{} and install: {}",
217 floatingIp.getFloatingIpAddress(),
218 floatingIp.getFixedIpAddress(),
219 install);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900220 }
221
Jian Lide679782018-06-05 01:41:29 +0900222 private synchronized void updateGatewayNodeRules(NetFloatingIP fip,
223 InstancePort instPort,
224 Network osNet,
225 ExternalPeerRouter router,
226 OpenstackNode gateway,
227 boolean install) {
228
229 Set<OpenstackNode> completedGws = osNodeService.completeNodes(GATEWAY);
230 Set<OpenstackNode> finalGws = Sets.newConcurrentHashSet();
231 finalGws.addAll(ImmutableSet.copyOf(completedGws));
232
Jian Lia171a432018-06-11 11:52:11 +0900233
234 if (gateway == null) {
235 // these are floating IP related cases...
236 setDownstreamExternalRulesHelper(fip, osNet, instPort, router,
237 ImmutableSet.copyOf(finalGws), install);
238
Jian Lide679782018-06-05 01:41:29 +0900239 } else {
Jian Lia171a432018-06-11 11:52:11 +0900240 // these are openstack node related cases...
241 if (install) {
242 if (completedGws.contains(gateway)) {
243 if (completedGws.size() > 1) {
244 finalGws.remove(gateway);
245 if (fip.getPortId() != null) {
246 setDownstreamExternalRulesHelper(fip, osNet, instPort, router,
247 ImmutableSet.copyOf(finalGws), false);
248 finalGws.add(gateway);
249 }
250 }
Jian Lide679782018-06-05 01:41:29 +0900251 if (fip.getPortId() != null) {
252 setDownstreamExternalRulesHelper(fip, osNet, instPort, router,
253 ImmutableSet.copyOf(finalGws), true);
254 }
Jian Lia171a432018-06-11 11:52:11 +0900255 } else {
256 log.warn("Detected node should be included in completed gateway set");
Jian Lide679782018-06-05 01:41:29 +0900257 }
258 } else {
Jian Lia171a432018-06-11 11:52:11 +0900259 if (!completedGws.contains(gateway)) {
Jian Li4d138702018-11-27 17:25:28 +0900260 if (!completedGws.isEmpty() && fip.getPortId() != null) {
261 setDownstreamExternalRulesHelper(fip, osNet, instPort, router,
Jian Lia171a432018-06-11 11:52:11 +0900262 ImmutableSet.copyOf(finalGws), true);
Jian Lia171a432018-06-11 11:52:11 +0900263 }
264 } else {
265 log.warn("Detected node should NOT be included in completed gateway set");
266 }
Jian Lide679782018-06-05 01:41:29 +0900267 }
268 }
269 }
270
271 private synchronized void updateComputeNodeRules(InstancePort instPort,
272 Network osNet,
273 OpenstackNode gateway,
274 boolean install) {
Jian Li1064e4f2018-05-29 16:16:53 +0900275
276 Set<OpenstackNode> completedGws = osNodeService.completeNodes(GATEWAY);
277 Set<OpenstackNode> finalGws = Sets.newConcurrentHashSet();
278 finalGws.addAll(ImmutableSet.copyOf(completedGws));
279
280 if (gateway == null) {
281 // these are floating IP related cases...
282 setComputeNodeToGatewayHelper(instPort, osNet,
283 ImmutableSet.copyOf(finalGws), install);
Jian Lide679782018-06-05 01:41:29 +0900284
Jian Li1064e4f2018-05-29 16:16:53 +0900285 } else {
286 // these are openstack node related cases...
287 if (install) {
288 if (completedGws.contains(gateway)) {
289 if (completedGws.size() > 1) {
290 finalGws.remove(gateway);
291 setComputeNodeToGatewayHelper(instPort, osNet,
292 ImmutableSet.copyOf(finalGws), false);
293 finalGws.add(gateway);
294 }
295
296 setComputeNodeToGatewayHelper(instPort, osNet,
297 ImmutableSet.copyOf(finalGws), true);
298 } else {
299 log.warn("Detected node should be included in completed gateway set");
300 }
301 } else {
302 if (!completedGws.contains(gateway)) {
303 finalGws.add(gateway);
304 setComputeNodeToGatewayHelper(instPort, osNet,
305 ImmutableSet.copyOf(finalGws), false);
306 finalGws.remove(gateway);
Jian Li4d138702018-11-27 17:25:28 +0900307 if (!completedGws.isEmpty()) {
Jian Li1064e4f2018-05-29 16:16:53 +0900308 setComputeNodeToGatewayHelper(instPort, osNet,
309 ImmutableSet.copyOf(finalGws), true);
310 }
311 } else {
312 log.warn("Detected node should NOT be included in completed gateway set");
313 }
314 }
315 }
316 }
317
318 // a helper method
319 private void setComputeNodeToGatewayHelper(InstancePort instPort,
320 Network osNet,
321 Set<OpenstackNode> gateways,
322 boolean install) {
daniel parkeeb8e042018-02-21 14:06:58 +0900323
324 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder()
325 .matchEthType(Ethernet.TYPE_IPV4)
326 .matchIPSrc(instPort.ipAddress().toIpPrefix())
327 .matchEthDst(Constants.DEFAULT_GATEWAY_MAC);
328
Daniel Park3f26e792018-11-26 18:34:53 +0900329 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
daniel parkeeb8e042018-02-21 14:06:58 +0900330
Jian Li5ecfd1a2018-12-10 11:41:03 +0900331 OpenstackNode selectedGatewayNode =
332 getGwByComputeDevId(gateways, instPort.deviceId());
Jian Li1064e4f2018-05-29 16:16:53 +0900333
daniel parkeeb8e042018-02-21 14:06:58 +0900334 if (selectedGatewayNode == null) {
Daniel Park3f26e792018-11-26 18:34:53 +0900335 log.warn(ERR_FLOW + "no gateway node selected");
Jian Lifb64d882018-11-27 10:57:40 +0900336 return;
daniel parkeeb8e042018-02-21 14:06:58 +0900337 }
Daniel Park3f26e792018-11-26 18:34:53 +0900338
339 switch (osNet.getNetworkType()) {
340 case VXLAN:
341 if (osNodeService.node(instPort.deviceId()).tunnelPortNum() == null) {
342 log.warn(ERR_FLOW + "no tunnel port");
343 return;
344 }
345 sBuilder.matchTunnelId(Long.parseLong(osNet.getProviderSegID()));
346 tBuilder.extension(buildExtension(
daniel parkeeb8e042018-02-21 14:06:58 +0900347 deviceService,
348 instPort.deviceId(),
349 selectedGatewayNode.dataIp().getIp4Address()),
350 instPort.deviceId())
Daniel Park3f26e792018-11-26 18:34:53 +0900351 .setOutput(osNodeService.node(instPort.deviceId()).tunnelPortNum());
352 break;
353 case VLAN:
354 if (osNodeService.node(instPort.deviceId()).vlanPortNum() == null) {
355 log.warn(ERR_FLOW + "no vlan port");
356 return;
357 }
358 sBuilder.matchVlanId(VlanId.vlanId(osNet.getProviderSegID()));
359 tBuilder.setOutput(osNodeService.node(instPort.deviceId()).vlanPortNum());
360 break;
361 default:
362 log.warn(ERR_FLOW + "no supported network type");
363 }
daniel parkeeb8e042018-02-21 14:06:58 +0900364
365 osFlowRuleService.setRule(
366 appId,
367 instPort.deviceId(),
368 sBuilder.build(),
Daniel Park3f26e792018-11-26 18:34:53 +0900369 tBuilder.build(),
daniel parkeeb8e042018-02-21 14:06:58 +0900370 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,
Jian Li32b03622018-11-06 17:54:24 +0900454 InstancePort instPort,
455 ExternalPeerRouter externalPeerRouter,
daniel park32b42202018-03-14 16:53:44 +0900456 boolean install) {
Hyunsun Moon44aac662017-02-18 02:07:01 +0900457 IpAddress floating = IpAddress.valueOf(floatingIp.getFloatingIpAddress());
daniel parkee8700b2017-05-11 15:50:03 +0900458 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder()
Hyunsun Moon44aac662017-02-18 02:07:01 +0900459 .matchEthType(Ethernet.TYPE_IPV4)
daniel parkee8700b2017-05-11 15:50:03 +0900460 .matchIPSrc(instPort.ipAddress().toIpPrefix());
461
462 switch (osNet.getNetworkType()) {
463 case VXLAN:
464 sBuilder.matchTunnelId(Long.valueOf(osNet.getProviderSegID()));
465 break;
466 case VLAN:
467 sBuilder.matchVlanId(VlanId.vlanId(osNet.getProviderSegID()));
468 break;
469 default:
Ray Milkeyc6c9b172018-02-26 09:36:31 -0800470 final String error = String.format(ERR_UNSUPPORTED_NET_TYPE,
Hyunsun Moon0d457362017-06-27 17:19:41 +0900471 osNet.getNetworkType());
daniel parkee8700b2017-05-11 15:50:03 +0900472 throw new IllegalStateException(error);
473 }
Hyunsun Moon44aac662017-02-18 02:07:01 +0900474
Daniel Park75e3d7f2018-05-29 14:43:53 +0900475 TrafficSelector selector = sBuilder.build();
daniel parkeeb8e042018-02-21 14:06:58 +0900476
Hyunsun Moon0d457362017-06-27 17:19:41 +0900477 osNodeService.completeNodes(GATEWAY).forEach(gNode -> {
Daniel Park75e3d7f2018-05-29 14:43:53 +0900478 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder()
479 .setIpSrc(floating.getIp4Address())
480 .setEthSrc(instPort.macAddress())
Jian Li5e2ad4a2018-07-16 13:40:53 +0900481 .setEthDst(externalPeerRouter.macAddress());
Hyunsun Moon44aac662017-02-18 02:07:01 +0900482
Daniel Park75e3d7f2018-05-29 14:43:53 +0900483 if (osNet.getNetworkType().equals(NetworkType.VLAN)) {
484 tBuilder.popVlan();
485 }
486
Jian Li5e2ad4a2018-07-16 13:40:53 +0900487 if (!externalPeerRouter.vlanId().equals(VlanId.NONE)) {
488 tBuilder.pushVlan().setVlanId(externalPeerRouter.vlanId());
Daniel Park75e3d7f2018-05-29 14:43:53 +0900489 }
sanghodc375372017-06-08 10:41:30 +0900490 osFlowRuleService.setRule(
Hyunsun Moon44aac662017-02-18 02:07:01 +0900491 appId,
Hyunsun Moon0d457362017-06-27 17:19:41 +0900492 gNode.intgBridge(),
Daniel Park75e3d7f2018-05-29 14:43:53 +0900493 selector,
daniel parkeeb8e042018-02-21 14:06:58 +0900494 tBuilder.setOutput(gNode.uplinkPortNum()).build(),
Hyunsun Moon44aac662017-02-18 02:07:01 +0900495 PRIORITY_FLOATING_EXTERNAL,
sanghodc375372017-06-08 10:41:30 +0900496 GW_COMMON_TABLE,
Hyunsun Moon44aac662017-02-18 02:07:01 +0900497 install);
Daniel Park75e3d7f2018-05-29 14:43:53 +0900498 });
daniel parkc2a2ed62018-04-10 15:17:42 +0900499 log.trace("Succeeded to set flow rules for upstream on gateway nodes");
Hyunsun Moon44aac662017-02-18 02:07:01 +0900500 }
501
Jian Li99892e92018-04-13 14:59:39 +0900502 private void associateFloatingIp(NetFloatingIP osFip) {
Jian Li628a7cb2018-08-11 23:04:24 +0900503 InstancePort instPort = instancePortService.instancePort(osFip.getPortId());
504
505 if (instPort == null) {
506 log.warn("Failed to insert floating IP rule for {} due to missing of port info.",
507 osFip.getFloatingIpAddress());
508 return;
Jian Li99892e92018-04-13 14:59:39 +0900509 }
Jian Li628a7cb2018-08-11 23:04:24 +0900510
Jian Li99892e92018-04-13 14:59:39 +0900511 // set floating IP rules only if the port is associated to a VM
Jian Li628a7cb2018-08-11 23:04:24 +0900512 if (!Strings.isNullOrEmpty(instPort.deviceId().toString())) {
513 setFloatingIpRules(osFip, instPort, null, true);
Daniel Park4fa1f5e2018-10-17 12:41:52 +0900514 processGratuitousArpPacket(osFip, instPort);
515
Jian Li99892e92018-04-13 14:59:39 +0900516 }
517 }
518
Daniel Park4fa1f5e2018-10-17 12:41:52 +0900519 private void processGratuitousArpPacket(NetFloatingIP floatingIP,
520 InstancePort instancePort) {
521 Set<OpenstackNode> gws = ImmutableSet.copyOf(osNodeService.completeNodes(GATEWAY));
522
523 Network osNet = osNetworkService.network(instancePort.networkId());
524
525
526 OpenstackNode selectedGw = getGwByInstancePort(gws, instancePort);
527 ExternalPeerRouter externalPeerRouter =
528 externalPeerRouterForNetwork(osNet, osNetworkService, osRouterAdminService);
529 if (externalPeerRouter == null) {
Jian Li4d138702018-11-27 17:25:28 +0900530 log.error("Failed to process GARP packet for floating ip {}, because " +
531 NO_EXT_PEER_ROUTER_MSG);
Daniel Park4fa1f5e2018-10-17 12:41:52 +0900532 return;
533 }
534
Jian Li32b03622018-11-06 17:54:24 +0900535 processGarpPacketForFloatingIp(floatingIP, instancePort,
536 externalPeerRouter.vlanId(), selectedGw, packetService);
Daniel Park4fa1f5e2018-10-17 12:41:52 +0900537
538 }
539
Jian Li99892e92018-04-13 14:59:39 +0900540 private void disassociateFloatingIp(NetFloatingIP osFip, String portId) {
Jian Li628a7cb2018-08-11 23:04:24 +0900541 InstancePort instPort = instancePortService.instancePort(portId);
Jian Lie1a39032018-06-19 21:49:36 +0900542
Jian Li628a7cb2018-08-11 23:04:24 +0900543 if (instPort == null) {
544 log.warn("Failed to remove floating IP rule for {} due to missing of port info.",
545 osFip.getFloatingIpAddress());
546 return;
Jian Lie1a39032018-06-19 21:49:36 +0900547 }
548
Jian Li99892e92018-04-13 14:59:39 +0900549 // set floating IP rules only if the port is associated to a VM
Jian Li628a7cb2018-08-11 23:04:24 +0900550 if (!Strings.isNullOrEmpty(instPort.deviceId().toString())) {
551 setFloatingIpRules(osFip, instPort, null, false);
Jian Li99892e92018-04-13 14:59:39 +0900552 }
553 }
554
Hyunsun Moon0d457362017-06-27 17:19:41 +0900555 private class InternalFloatingIpListener implements OpenstackRouterListener {
Hyunsun Moon44aac662017-02-18 02:07:01 +0900556
557 @Override
558 public boolean isRelevant(OpenstackRouterEvent event) {
Hyunsun Moon44aac662017-02-18 02:07:01 +0900559 return event.floatingIp() != null;
560 }
561
Jian Li34220ea2018-11-14 01:30:24 +0900562 private boolean isRelevantHelper() {
563 return Objects.equals(localNodeId, leadershipService.getLeader(appId.name()));
564 }
565
Hyunsun Moon44aac662017-02-18 02:07:01 +0900566 @Override
567 public void event(OpenstackRouterEvent event) {
568 switch (event.type()) {
569 case OPENSTACK_FLOATING_IP_ASSOCIATED:
Jian Li4d138702018-11-27 17:25:28 +0900570 eventExecutor.execute(() -> processFloatingIpAssociation(event));
Hyunsun Moon7a5f9042017-05-11 18:19:01 +0900571 break;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900572 case OPENSTACK_FLOATING_IP_DISASSOCIATED:
Jian Li4d138702018-11-27 17:25:28 +0900573 eventExecutor.execute(() -> processFloatingIpDisassociation(event));
Hyunsun Moon7a5f9042017-05-11 18:19:01 +0900574 break;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900575 case OPENSTACK_FLOATING_IP_CREATED:
Jian Li4d138702018-11-27 17:25:28 +0900576 eventExecutor.execute(() -> processFloatingIpCreation(event));
Hyunsun Moonb720e632017-05-16 15:41:36 +0900577 break;
Jian Lia171a432018-06-11 11:52:11 +0900578 case OPENSTACK_FLOATING_IP_REMOVED:
Jian Li4d138702018-11-27 17:25:28 +0900579 eventExecutor.execute(() -> processFloatingIpRemoval(event));
Jian Lia171a432018-06-11 11:52:11 +0900580 break;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900581 case OPENSTACK_FLOATING_IP_UPDATED:
Hyunsun Moon44aac662017-02-18 02:07:01 +0900582 default:
583 // do nothing for the other events
584 break;
585 }
586 }
Jian Li4d138702018-11-27 17:25:28 +0900587
588 private void processFloatingIpAssociation(OpenstackRouterEvent event) {
589 if (!isRelevantHelper()) {
590 return;
591 }
592
593 NetFloatingIP osFip = event.floatingIp();
594 if (instancePortService.instancePort(osFip.getPortId()) != null) {
595 associateFloatingIp(osFip);
596 log.info("Associated floating IP {}:{}",
597 osFip.getFloatingIpAddress(),
598 osFip.getFixedIpAddress());
599 }
600 }
601
602 private void processFloatingIpDisassociation(OpenstackRouterEvent event) {
603 if (!isRelevantHelper()) {
604 return;
605 }
606
607 NetFloatingIP osFip = event.floatingIp();
608 if (instancePortService.instancePort(event.portId()) != null) {
609 disassociateFloatingIp(osFip, event.portId());
610 log.info("Disassociated floating IP {}:{}",
611 osFip.getFloatingIpAddress(),
612 osFip.getFixedIpAddress());
613 }
614 }
615
616 private void processFloatingIpCreation(OpenstackRouterEvent event) {
617 if (!isRelevantHelper()) {
618 return;
619 }
620
621 NetFloatingIP osFip = event.floatingIp();
622 String portId = osFip.getPortId();
623 if (!Strings.isNullOrEmpty(portId) &&
624 instancePortService.instancePort(portId) != null) {
625 associateFloatingIp(event.floatingIp());
626 }
627 log.info("Created floating IP {}", osFip.getFloatingIpAddress());
628 }
629
630 private void processFloatingIpRemoval(OpenstackRouterEvent event) {
631 if (!isRelevantHelper()) {
632 return;
633 }
634
635 NetFloatingIP osFip = event.floatingIp();
636 String portId = osFip.getPortId();
637 if (!Strings.isNullOrEmpty(osFip.getPortId())) {
638 // in case the floating IP is not associated with any port due to
639 // port removal, we simply do not execute floating IP disassociation
640 if (osNetworkService.port(portId) != null &&
641 instancePortService.instancePort(portId) != null) {
642 disassociateFloatingIp(osFip, portId);
643 }
644
645 // since we skip floating IP disassociation, we need to
646 // manually unsubscribe the port pre-remove event
647 preCommitPortService.unsubscribePreCommit(osFip.getPortId(),
648 OPENSTACK_PORT_PRE_REMOVE, instancePortService,
649 this.getClass().getName());
650 log.info("Unsubscribed the port {} on listening pre-remove event",
651 osFip.getPortId());
652 }
653 log.info("Removed floating IP {}", osFip.getFloatingIpAddress());
654 }
Hyunsun Moon44aac662017-02-18 02:07:01 +0900655 }
656
657 private class InternalNodeListener implements OpenstackNodeListener {
658
659 @Override
660 public boolean isRelevant(OpenstackNodeEvent event) {
Hyunsun Moon44aac662017-02-18 02:07:01 +0900661 return event.subject().type() == GATEWAY;
662 }
663
Jian Li34220ea2018-11-14 01:30:24 +0900664 private boolean isRelevantHelper() {
665 return Objects.equals(localNodeId, leadershipService.getLeader(appId.name()));
666 }
667
Hyunsun Moon44aac662017-02-18 02:07:01 +0900668 @Override
669 public void event(OpenstackNodeEvent event) {
Hyunsun Moon44aac662017-02-18 02:07:01 +0900670
671 switch (event.type()) {
Hyunsun Moon0d457362017-06-27 17:19:41 +0900672 case OPENSTACK_NODE_COMPLETE:
Jian Li4d138702018-11-27 17:25:28 +0900673 eventExecutor.execute(() -> processNodeCompletion(event));
Hyunsun Moon44aac662017-02-18 02:07:01 +0900674 break;
Hyunsun Moon0d457362017-06-27 17:19:41 +0900675 case OPENSTACK_NODE_INCOMPLETE:
Jian Li4d138702018-11-27 17:25:28 +0900676 eventExecutor.execute(() -> processNodeIncompletion(event));
Jian Li1064e4f2018-05-29 16:16:53 +0900677 break;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900678 default:
Hyunsun Moon0d457362017-06-27 17:19:41 +0900679 // do nothing
Hyunsun Moon44aac662017-02-18 02:07:01 +0900680 break;
681 }
682 }
Jian Li4d138702018-11-27 17:25:28 +0900683
684 private void processNodeCompletion(OpenstackNodeEvent event) {
685 if (!isRelevantHelper()) {
686 return;
687 }
688
689 for (NetFloatingIP fip : osRouterAdminService.floatingIps()) {
690
691 if (Strings.isNullOrEmpty(fip.getPortId())) {
692 continue;
693 }
694
695 Port osPort = osNetworkService.port(fip.getPortId());
696 InstancePort instPort = instancePortService.instancePort(fip.getPortId());
697
698 // we check both Openstack Port and Instance Port
699 if (osPort == null || instPort == null) {
700 continue;
701 }
702
703 setFloatingIpRules(fip, instPort, event.subject(), true);
704 }
705 }
706
707 private void processNodeIncompletion(OpenstackNodeEvent event) {
708 if (!isRelevantHelper()) {
709 return;
710 }
711
712 for (NetFloatingIP fip : osRouterAdminService.floatingIps()) {
713 if (Strings.isNullOrEmpty(fip.getPortId())) {
714 continue;
715 }
716 Port osPort = osNetworkService.port(fip.getPortId());
717 if (osPort == null) {
718 log.warn("Failed to set floating IP {}", fip.getId());
719 continue;
720 }
721 Network osNet = osNetworkService.network(osPort.getNetworkId());
722 if (osNet == null) {
723 final String errorFormat = ERR_FLOW + "no network(%s) exists";
724 final String error = String.format(errorFormat,
725 fip.getFloatingIpAddress(),
726 osPort.getNetworkId());
727 throw new IllegalStateException(error);
728 }
729 MacAddress srcMac = MacAddress.valueOf(osPort.getMacAddress());
730 log.trace("Mac address of openstack port: {}", srcMac);
731 InstancePort instPort = instancePortService.instancePort(srcMac);
732
733 if (instPort == null) {
734 final String errorFormat = ERR_FLOW + "no host(MAC:%s) found";
735 final String error = String.format(errorFormat,
736 fip.getFloatingIpAddress(), srcMac);
737 throw new IllegalStateException(error);
738 }
739
740 ExternalPeerRouter externalPeerRouter = externalPeerRouterForNetwork(osNet,
741 osNetworkService, osRouterAdminService);
742 if (externalPeerRouter == null) {
743 final String errorFormat = ERR_FLOW + NO_EXT_PEER_ROUTER_MSG;
744 throw new IllegalStateException(errorFormat);
745 }
746
747 updateComputeNodeRules(instPort, osNet, event.subject(), false);
748 updateGatewayNodeRules(fip, instPort, osNet,
749 externalPeerRouter, event.subject(), false);
750 }
751 }
Hyunsun Moon44aac662017-02-18 02:07:01 +0900752 }
Jian Li99892e92018-04-13 14:59:39 +0900753
Jian Li24ec59f2018-05-23 19:01:25 +0900754 private class InternalInstancePortListener implements InstancePortListener {
755
Jian Li34220ea2018-11-14 01:30:24 +0900756 private boolean isRelevantHelper(InstancePortEvent event) {
Jian Li24ec59f2018-05-23 19:01:25 +0900757
Jian Lie1a39032018-06-19 21:49:36 +0900758 if (event.type() == OPENSTACK_INSTANCE_MIGRATION_ENDED ||
759 event.type() == OPENSTACK_INSTANCE_MIGRATION_STARTED) {
760 Set<NetFloatingIP> ips = osRouterAdminService.floatingIps();
761 NetFloatingIP fip = associatedFloatingIp(event.subject(), ips);
762
763 // we check the possible NPE to avoid duplicated null check
764 // for OPENSTACK_INSTANCE_MIGRATION_ENDED and
765 // OPENSTACK_INSTANCE_MIGRATION_STARTED cases
766 if (fip == null || !isAssociatedWithVM(osNetworkService, fip)) {
767 return false;
768 }
769 }
770
Jian Li34220ea2018-11-14 01:30:24 +0900771 return Objects.equals(localNodeId, leadershipService.getLeader(appId.name()));
Jian Li24ec59f2018-05-23 19:01:25 +0900772 }
773
774 @Override
775 public void event(InstancePortEvent event) {
Jian Li24ec59f2018-05-23 19:01:25 +0900776 switch (event.type()) {
Jian Lie1a39032018-06-19 21:49:36 +0900777 case OPENSTACK_INSTANCE_PORT_DETECTED:
Jian Li4d138702018-11-27 17:25:28 +0900778 eventExecutor.execute(() -> processInstancePortDetection(event));
Jian Lie1a39032018-06-19 21:49:36 +0900779 break;
Jian Li24ec59f2018-05-23 19:01:25 +0900780 case OPENSTACK_INSTANCE_MIGRATION_STARTED:
Jian Li4d138702018-11-27 17:25:28 +0900781 eventExecutor.execute(() -> processInstanceMigrationStart(event));
Jian Li24ec59f2018-05-23 19:01:25 +0900782 break;
783 case OPENSTACK_INSTANCE_MIGRATION_ENDED:
Jian Li4d138702018-11-27 17:25:28 +0900784 eventExecutor.execute(() -> processInstanceMigrationEnd(event));
Jian Li24ec59f2018-05-23 19:01:25 +0900785 break;
786 default:
787 break;
788 }
789 }
Jian Li4d138702018-11-27 17:25:28 +0900790
791 private void processInstancePortDetection(InstancePortEvent event) {
792 if (!isRelevantHelper(event)) {
793 return;
794 }
795
796 InstancePort instPort = event.subject();
797
798 if (instPort != null && instPort.portId() != null) {
799 osRouterAdminService.floatingIps().stream()
800 .filter(f -> f.getPortId() != null)
801 .filter(f -> f.getPortId().equals(instPort.portId()))
802 .forEach(f -> setFloatingIpRules(f,
803 instPort, null, true));
804 }
805 }
806
807 private void processInstanceMigrationStart(InstancePortEvent event) {
808 if (!isRelevantHelper(event)) {
809 return;
810 }
811
812 Set<OpenstackNode> gateways = osNodeService.completeNodes(GATEWAY);
813 Set<NetFloatingIP> ips = osRouterAdminService.floatingIps();
814 NetFloatingIP fip = associatedFloatingIp(event.subject(), ips);
815
816 if (fip == null) {
817 return;
818 }
819
820 Port osPort = osNetworkService.port(fip.getPortId());
821 Network osNet = osNetworkService.network(osPort.getNetworkId());
822 ExternalPeerRouter externalPeerRouter = externalPeerRouterForNetwork(osNet,
823 osNetworkService, osRouterAdminService);
824
825 if (externalPeerRouter == null) {
826 final String errorFormat = ERR_FLOW + NO_EXT_PEER_ROUTER_MSG;
827 throw new IllegalStateException(errorFormat);
828 }
829
830 // since DownstreamExternal rules should only be placed in
831 // corresponding gateway node, we need to install new rule to
832 // the corresponding gateway node
833 setDownstreamExternalRulesHelper(fip, osNet,
834 event.subject(), externalPeerRouter, gateways, true);
835
836 // since ComputeNodeToGateway rules should only be placed in
837 // corresponding compute node, we need to install new rule to
838 // the target compute node, and remove rules from original node
839 setComputeNodeToGatewayHelper(event.subject(), osNet, gateways, true);
840 }
841
842 private void processInstanceMigrationEnd(InstancePortEvent event) {
843 if (!isRelevantHelper(event)) {
844 return;
845 }
846
847 InstancePort oldInstPort = swapStaleLocation(event.subject());
848
849 Set<NetFloatingIP> ips = osRouterAdminService.floatingIps();
850 NetFloatingIP fip = associatedFloatingIp(oldInstPort, ips);
851
852 if (fip == null) {
853 return;
854 }
855
856 Set<OpenstackNode> gateways = osNodeService.completeNodes(GATEWAY);
857 Port osPort = osNetworkService.port(fip.getPortId());
858 Network osNet = osNetworkService.network(osPort.getNetworkId());
859 ExternalPeerRouter externalPeerRouter = externalPeerRouterForNetwork(osNet,
860 osNetworkService, osRouterAdminService);
861
862 if (externalPeerRouter == null) {
863 final String errorFormat = ERR_FLOW + NO_EXT_PEER_ROUTER_MSG;
864 throw new IllegalStateException(errorFormat);
865 }
866
867 // We need to remove the old ComputeNodeToGateway rules from
868 // original compute node
869 setComputeNodeToGatewayHelper(oldInstPort, osNet, gateways, false);
870
871 // If we only have one gateway, we simply do not remove any
872 // flow rules from either gateway or compute node
873 if (gateways.size() == 1) {
874 return;
875 }
876
877 // Checks whether the destination compute node's device id
878 // has identical gateway hash or not
879 // if it is true, we simply do not remove the rules, as
880 // it has been overwritten at port detention event
881 // if it is false, we will remove the rules
882 DeviceId newDeviceId = event.subject().deviceId();
883 DeviceId oldDeviceId = oldInstPort.deviceId();
884
885 OpenstackNode oldGateway = getGwByComputeDevId(gateways, oldDeviceId);
886 OpenstackNode newGateway = getGwByComputeDevId(gateways, newDeviceId);
887
888 if (oldGateway != null && oldGateway.equals(newGateway)) {
889 return;
890 }
891
892 // Since DownstreamExternal rules should only be placed in
893 // corresponding gateway node, we need to remove old rule from
894 // the corresponding gateway node
895 setDownstreamExternalRulesHelper(fip, osNet, oldInstPort,
896 externalPeerRouter, gateways, false);
897 }
Jian Li24ec59f2018-05-23 19:01:25 +0900898 }
Jian Lie1a39032018-06-19 21:49:36 +0900899
900 private class InternalOpenstackNetworkListener implements OpenstackNetworkListener {
901
Jian Li34220ea2018-11-14 01:30:24 +0900902 private boolean isRelevantHelper() {
903 return Objects.equals(localNodeId, leadershipService.getLeader(appId.name()));
Jian Lie1a39032018-06-19 21:49:36 +0900904 }
905
906 @Override
907 public void event(OpenstackNetworkEvent event) {
Jian Li4d138702018-11-27 17:25:28 +0900908 if (event.type() == OPENSTACK_PORT_PRE_REMOVE) {
909 eventExecutor.execute(() -> {
Jian Li34220ea2018-11-14 01:30:24 +0900910
Jian Li4d138702018-11-27 17:25:28 +0900911 if (!isRelevantHelper()) {
912 return;
913 }
Jian Li34220ea2018-11-14 01:30:24 +0900914
Jian Li4d138702018-11-27 17:25:28 +0900915 processPortPreRemoval(event);
916 });
Jian Lie1a39032018-06-19 21:49:36 +0900917 }
918 }
919
Jian Li4d138702018-11-27 17:25:28 +0900920 private void processPortPreRemoval(OpenstackNetworkEvent event) {
Jian Li32b03622018-11-06 17:54:24 +0900921 InstancePort instPort = instancePortService.instancePort(
922 event.port().getId());
923 if (instPort == null) {
924 return;
925 }
926 NetFloatingIP fip = associatedFloatingIp(instPort,
927 osRouterAdminService.floatingIps());
928
929 if (fip != null) {
930 instancePortService.updateInstancePort(
931 instPort.updateState(REMOVE_PENDING));
932 updateFipStore(event.port().getId());
933 } else {
934 instancePortService.removeInstancePort(instPort.portId());
935 }
936 }
937
Jian Li2360acb2018-10-17 00:46:31 +0900938 private void updateFipStore(String portId) {
Jian Lie1a39032018-06-19 21:49:36 +0900939
Jian Li2360acb2018-10-17 00:46:31 +0900940 if (portId == null) {
Jian Lie1a39032018-06-19 21:49:36 +0900941 return;
942 }
943
944 Set<NetFloatingIP> ips = osRouterAdminService.floatingIps();
945 for (NetFloatingIP fip : ips) {
946 if (Strings.isNullOrEmpty(fip.getFixedIpAddress())) {
947 continue;
948 }
949 if (Strings.isNullOrEmpty(fip.getFloatingIpAddress())) {
950 continue;
951 }
Jian Li2360acb2018-10-17 00:46:31 +0900952 if (fip.getPortId().equals(portId)) {
Jian Lie1a39032018-06-19 21:49:36 +0900953 NeutronFloatingIP neutronFip = (NeutronFloatingIP) fip;
954 // invalidate bound fixed IP and port
955 neutronFip.setFixedIpAddress(null);
956 neutronFip.setPortId(null);
Jian Lie1a39032018-06-19 21:49:36 +0900957
958 // Following update will in turn trigger
959 // OPENSTACK_FLOATING_IP_DISASSOCIATED event
960 osRouterAdminService.updateFloatingIp(neutronFip);
961 log.info("Updated floating IP {}, due to host removal",
962 neutronFip.getFloatingIpAddress());
963 }
964 }
965 }
966 }
Hyunsun Moon44aac662017-02-18 02:07:01 +0900967}