blob: 075d974c72d4d15052555b935aff240c9a9a358c [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 Li24ec59f2018-05-23 19:01:25 +0900141 private final OpenstackRouterListener floatingIpListener = new InternalFloatingIpListener();
142 private final InstancePortListener instancePortListener = new InternalInstancePortListener();
Hyunsun Moon44aac662017-02-18 02:07:01 +0900143 private final OpenstackNodeListener osNodeListener = new InternalNodeListener();
Jian Lie1a39032018-06-19 21:49:36 +0900144 private final OpenstackNetworkListener osNetworkListener = new InternalOpenstackNetworkListener();
145 private final InstancePortListener instPortListener = new InternalInstancePortListener();
146
Hyunsun Moon44aac662017-02-18 02:07:01 +0900147 private ApplicationId appId;
148 private NodeId localNodeId;
149
150 @Activate
151 protected void activate() {
152 appId = coreService.registerApplication(OPENSTACK_NETWORKING_APP_ID);
153 localNodeId = clusterService.getLocalNode().id();
154 leadershipService.runForLeadership(appId.name());
Jian Li24ec59f2018-05-23 19:01:25 +0900155 osRouterAdminService.addListener(floatingIpListener);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900156 osNodeService.addListener(osNodeListener);
Jian Li24ec59f2018-05-23 19:01:25 +0900157 instancePortService.addListener(instancePortListener);
Jian Lie1a39032018-06-19 21:49:36 +0900158 osNodeService.addListener(osNodeListener);
159 osNetworkService.addListener(osNetworkListener);
160 instancePortService.addListener(instPortListener);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900161
162 log.info("Started");
163 }
164
165 @Deactivate
166 protected void deactivate() {
Jian Li24ec59f2018-05-23 19:01:25 +0900167 instancePortService.removeListener(instancePortListener);
Jian Lie1a39032018-06-19 21:49:36 +0900168 instancePortService.removeListener(instPortListener);
169 osNetworkService.removeListener(osNetworkListener);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900170 osNodeService.removeListener(osNodeListener);
Jian Li24ec59f2018-05-23 19:01:25 +0900171 osRouterAdminService.removeListener(floatingIpListener);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900172 leadershipService.withdraw(appId.name());
173 eventExecutor.shutdown();
174
175 log.info("Stopped");
176 }
177
Jian Li628a7cb2018-08-11 23:04:24 +0900178 private void setFloatingIpRules(NetFloatingIP floatingIp, InstancePort instPort,
Jian Li1064e4f2018-05-29 16:16:53 +0900179 OpenstackNode gateway, boolean install) {
Jian Li628a7cb2018-08-11 23:04:24 +0900180
181 if (instPort == null) {
182 log.debug("No instance port found");
183 return;
184 }
185
186 Network osNet = osNetworkService.network(instPort.networkId());
Jian Li8f64feb2018-07-24 13:20:16 +0900187
Daniel Park4fa1f5e2018-10-17 12:41:52 +0900188 ExternalPeerRouter externalPeerRouter = externalPeerRouterForNetwork(osNet,
189 osNetworkService, osRouterAdminService);
daniel park32b42202018-03-14 16:53:44 +0900190 if (externalPeerRouter == null) {
Jian Li4d138702018-11-27 17:25:28 +0900191 final String errorFormat = ERR_FLOW + NO_EXT_PEER_ROUTER_MSG;
daniel parkc2a2ed62018-04-10 15:17:42 +0900192 throw new IllegalStateException(errorFormat);
daniel park32b42202018-03-14 16:53:44 +0900193 }
194
Jian Li8f64feb2018-07-24 13:20:16 +0900195 if (install) {
Jian Li628a7cb2018-08-11 23:04:24 +0900196 preCommitPortService.subscribePreCommit(instPort.portId(),
Jian Li8f64feb2018-07-24 13:20:16 +0900197 OPENSTACK_PORT_PRE_REMOVE, this.getClass().getName());
Jian Li628a7cb2018-08-11 23:04:24 +0900198 log.info("Subscribed the port {} on listening pre-remove event", instPort.portId());
Jian Li8f64feb2018-07-24 13:20:16 +0900199 } else {
Jian Li628a7cb2018-08-11 23:04:24 +0900200 preCommitPortService.unsubscribePreCommit(instPort.portId(),
201 OPENSTACK_PORT_PRE_REMOVE, instancePortService, this.getClass().getName());
202 log.info("Unsubscribed the port {} on listening pre-remove event", instPort.portId());
Jian Li8f64feb2018-07-24 13:20:16 +0900203 }
204
Jian Lide679782018-06-05 01:41:29 +0900205 updateComputeNodeRules(instPort, osNet, gateway, install);
206 updateGatewayNodeRules(floatingIp, instPort, osNet, externalPeerRouter, gateway, install);
207
Jian Lide679782018-06-05 01:41:29 +0900208 // TODO: need to refactor setUpstreamRules if possible
daniel park32b42202018-03-14 16:53:44 +0900209 setUpstreamRules(floatingIp, osNet, instPort, externalPeerRouter, install);
Jian Li8f64feb2018-07-24 13:20:16 +0900210
daniel parkc2a2ed62018-04-10 15:17:42 +0900211 log.trace("Succeeded to set flow rules for floating ip {}:{} and install: {}",
212 floatingIp.getFloatingIpAddress(),
213 floatingIp.getFixedIpAddress(),
214 install);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900215 }
216
Jian Lide679782018-06-05 01:41:29 +0900217 private synchronized void updateGatewayNodeRules(NetFloatingIP fip,
218 InstancePort instPort,
219 Network osNet,
220 ExternalPeerRouter router,
221 OpenstackNode gateway,
222 boolean install) {
223
224 Set<OpenstackNode> completedGws = osNodeService.completeNodes(GATEWAY);
225 Set<OpenstackNode> finalGws = Sets.newConcurrentHashSet();
226 finalGws.addAll(ImmutableSet.copyOf(completedGws));
227
Jian Lia171a432018-06-11 11:52:11 +0900228
229 if (gateway == null) {
230 // these are floating IP related cases...
231 setDownstreamExternalRulesHelper(fip, osNet, instPort, router,
232 ImmutableSet.copyOf(finalGws), install);
233
Jian Lide679782018-06-05 01:41:29 +0900234 } else {
Jian Lia171a432018-06-11 11:52:11 +0900235 // these are openstack node related cases...
236 if (install) {
237 if (completedGws.contains(gateway)) {
238 if (completedGws.size() > 1) {
239 finalGws.remove(gateway);
240 if (fip.getPortId() != null) {
241 setDownstreamExternalRulesHelper(fip, osNet, instPort, router,
242 ImmutableSet.copyOf(finalGws), false);
243 finalGws.add(gateway);
244 }
245 }
Jian Lide679782018-06-05 01:41:29 +0900246 if (fip.getPortId() != null) {
247 setDownstreamExternalRulesHelper(fip, osNet, instPort, router,
248 ImmutableSet.copyOf(finalGws), true);
249 }
Jian Lia171a432018-06-11 11:52:11 +0900250 } else {
251 log.warn("Detected node should be included in completed gateway set");
Jian Lide679782018-06-05 01:41:29 +0900252 }
253 } else {
Jian Lia171a432018-06-11 11:52:11 +0900254 if (!completedGws.contains(gateway)) {
Jian Li4d138702018-11-27 17:25:28 +0900255 if (!completedGws.isEmpty() && fip.getPortId() != null) {
256 setDownstreamExternalRulesHelper(fip, osNet, instPort, router,
Jian Lia171a432018-06-11 11:52:11 +0900257 ImmutableSet.copyOf(finalGws), true);
Jian Lia171a432018-06-11 11:52:11 +0900258 }
259 } else {
260 log.warn("Detected node should NOT be included in completed gateway set");
261 }
Jian Lide679782018-06-05 01:41:29 +0900262 }
263 }
264 }
265
266 private synchronized void updateComputeNodeRules(InstancePort instPort,
267 Network osNet,
268 OpenstackNode gateway,
269 boolean install) {
Jian Li1064e4f2018-05-29 16:16:53 +0900270
271 Set<OpenstackNode> completedGws = osNodeService.completeNodes(GATEWAY);
272 Set<OpenstackNode> finalGws = Sets.newConcurrentHashSet();
273 finalGws.addAll(ImmutableSet.copyOf(completedGws));
274
275 if (gateway == null) {
276 // these are floating IP related cases...
277 setComputeNodeToGatewayHelper(instPort, osNet,
278 ImmutableSet.copyOf(finalGws), install);
Jian Lide679782018-06-05 01:41:29 +0900279
Jian Li1064e4f2018-05-29 16:16:53 +0900280 } else {
281 // these are openstack node related cases...
282 if (install) {
283 if (completedGws.contains(gateway)) {
284 if (completedGws.size() > 1) {
285 finalGws.remove(gateway);
286 setComputeNodeToGatewayHelper(instPort, osNet,
287 ImmutableSet.copyOf(finalGws), false);
288 finalGws.add(gateway);
289 }
290
291 setComputeNodeToGatewayHelper(instPort, osNet,
292 ImmutableSet.copyOf(finalGws), true);
293 } else {
294 log.warn("Detected node should be included in completed gateway set");
295 }
296 } else {
297 if (!completedGws.contains(gateway)) {
298 finalGws.add(gateway);
299 setComputeNodeToGatewayHelper(instPort, osNet,
300 ImmutableSet.copyOf(finalGws), false);
301 finalGws.remove(gateway);
Jian Li4d138702018-11-27 17:25:28 +0900302 if (!completedGws.isEmpty()) {
Jian Li1064e4f2018-05-29 16:16:53 +0900303 setComputeNodeToGatewayHelper(instPort, osNet,
304 ImmutableSet.copyOf(finalGws), true);
305 }
306 } else {
307 log.warn("Detected node should NOT be included in completed gateway set");
308 }
309 }
310 }
311 }
312
313 // a helper method
314 private void setComputeNodeToGatewayHelper(InstancePort instPort,
315 Network osNet,
316 Set<OpenstackNode> gateways,
317 boolean install) {
daniel parkeeb8e042018-02-21 14:06:58 +0900318
319 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder()
320 .matchEthType(Ethernet.TYPE_IPV4)
321 .matchIPSrc(instPort.ipAddress().toIpPrefix())
322 .matchEthDst(Constants.DEFAULT_GATEWAY_MAC);
323
Daniel Park3f26e792018-11-26 18:34:53 +0900324 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
daniel parkeeb8e042018-02-21 14:06:58 +0900325
Jian Li1064e4f2018-05-29 16:16:53 +0900326 OpenstackNode selectedGatewayNode = getGwByComputeDevId(gateways, instPort.deviceId());
327
daniel parkeeb8e042018-02-21 14:06:58 +0900328 if (selectedGatewayNode == null) {
Daniel Park3f26e792018-11-26 18:34:53 +0900329 log.warn(ERR_FLOW + "no gateway node selected");
Jian Lifb64d882018-11-27 10:57:40 +0900330 return;
daniel parkeeb8e042018-02-21 14:06:58 +0900331 }
Daniel Park3f26e792018-11-26 18:34:53 +0900332
333 switch (osNet.getNetworkType()) {
334 case VXLAN:
335 if (osNodeService.node(instPort.deviceId()).tunnelPortNum() == null) {
336 log.warn(ERR_FLOW + "no tunnel port");
337 return;
338 }
339 sBuilder.matchTunnelId(Long.parseLong(osNet.getProviderSegID()));
340 tBuilder.extension(buildExtension(
daniel parkeeb8e042018-02-21 14:06:58 +0900341 deviceService,
342 instPort.deviceId(),
343 selectedGatewayNode.dataIp().getIp4Address()),
344 instPort.deviceId())
Daniel Park3f26e792018-11-26 18:34:53 +0900345 .setOutput(osNodeService.node(instPort.deviceId()).tunnelPortNum());
346 break;
347 case VLAN:
348 if (osNodeService.node(instPort.deviceId()).vlanPortNum() == null) {
349 log.warn(ERR_FLOW + "no vlan port");
350 return;
351 }
352 sBuilder.matchVlanId(VlanId.vlanId(osNet.getProviderSegID()));
353 tBuilder.setOutput(osNodeService.node(instPort.deviceId()).vlanPortNum());
354 break;
355 default:
356 log.warn(ERR_FLOW + "no supported network type");
357 }
daniel parkeeb8e042018-02-21 14:06:58 +0900358
359 osFlowRuleService.setRule(
360 appId,
361 instPort.deviceId(),
362 sBuilder.build(),
Daniel Park3f26e792018-11-26 18:34:53 +0900363 tBuilder.build(),
daniel parkeeb8e042018-02-21 14:06:58 +0900364 PRIORITY_EXTERNAL_FLOATING_ROUTING_RULE,
365 ROUTING_TABLE,
366 install);
daniel parkc2a2ed62018-04-10 15:17:42 +0900367 log.trace("Succeeded to set flow rules from compute node to gateway on compute node");
daniel parkeeb8e042018-02-21 14:06:58 +0900368 }
369
Jian Lide679782018-06-05 01:41:29 +0900370 private void setDownstreamExternalRulesHelper(NetFloatingIP floatingIp,
371 Network osNet,
372 InstancePort instPort,
373 ExternalPeerRouter externalPeerRouter,
374 Set<OpenstackNode> gateways, boolean install) {
375 OpenstackNode cNode = osNodeService.node(instPort.deviceId());
376 if (cNode == null) {
377 final String error = String.format("Cannot find openstack node for device %s",
378 instPort.deviceId());
379 throw new IllegalStateException(error);
380 }
381 if (osNet.getNetworkType() == NetworkType.VXLAN && cNode.dataIp() == null) {
382 final String errorFormat = ERR_FLOW + "VXLAN mode is not ready for %s";
383 final String error = String.format(errorFormat, floatingIp, cNode.hostname());
384 throw new IllegalStateException(error);
385 }
386 if (osNet.getNetworkType() == NetworkType.VLAN && cNode.vlanIntf() == null) {
387 final String errorFormat = ERR_FLOW + "VLAN mode is not ready for %s";
388 final String error = String.format(errorFormat, floatingIp, cNode.hostname());
389 throw new IllegalStateException(error);
390 }
391
392 IpAddress floating = IpAddress.valueOf(floatingIp.getFloatingIpAddress());
393
394 OpenstackNode selectedGatewayNode = getGwByComputeDevId(gateways, instPort.deviceId());
395
396 if (selectedGatewayNode == null) {
397 final String errorFormat = ERR_FLOW + "no gateway node selected";
398 throw new IllegalStateException(errorFormat);
399 }
400
401 TrafficSelector.Builder externalSelectorBuilder = DefaultTrafficSelector.builder()
402 .matchEthType(Ethernet.TYPE_IPV4)
Daniel Park319b9ab2018-09-14 11:27:04 +0900403 .matchInPort(selectedGatewayNode.uplinkPortNum())
Jian Lide679782018-06-05 01:41:29 +0900404 .matchIPDst(floating.toIpPrefix());
405
406 TrafficTreatment.Builder externalTreatmentBuilder = DefaultTrafficTreatment.builder()
407 .setEthSrc(Constants.DEFAULT_GATEWAY_MAC)
408 .setEthDst(instPort.macAddress())
409 .setIpDst(instPort.ipAddress().getIp4Address());
410
Jian Li5e2ad4a2018-07-16 13:40:53 +0900411 if (!externalPeerRouter.vlanId().equals(VlanId.NONE)) {
412 externalSelectorBuilder.matchVlanId(externalPeerRouter.vlanId()).build();
Jian Lide679782018-06-05 01:41:29 +0900413 externalTreatmentBuilder.popVlan();
414 }
415
416 switch (osNet.getNetworkType()) {
417 case VXLAN:
418 externalTreatmentBuilder.setTunnelId(Long.valueOf(osNet.getProviderSegID()))
419 .extension(buildExtension(
420 deviceService,
421 selectedGatewayNode.intgBridge(),
422 cNode.dataIp().getIp4Address()),
423 selectedGatewayNode.intgBridge())
424 .setOutput(selectedGatewayNode.tunnelPortNum());
425 break;
426 case VLAN:
427 externalTreatmentBuilder.pushVlan()
428 .setVlanId(VlanId.vlanId(osNet.getProviderSegID()))
429 .setOutput(selectedGatewayNode.vlanPortNum());
430 break;
431 default:
432 final String error = String.format(ERR_UNSUPPORTED_NET_TYPE,
433 osNet.getNetworkType());
434 throw new IllegalStateException(error);
435 }
436
437 osFlowRuleService.setRule(
438 appId,
439 selectedGatewayNode.intgBridge(),
440 externalSelectorBuilder.build(),
441 externalTreatmentBuilder.build(),
442 PRIORITY_FLOATING_EXTERNAL,
443 GW_COMMON_TABLE,
444 install);
445 }
446
Hyunsun Moon44aac662017-02-18 02:07:01 +0900447 private void setUpstreamRules(NetFloatingIP floatingIp, Network osNet,
Jian Li32b03622018-11-06 17:54:24 +0900448 InstancePort instPort,
449 ExternalPeerRouter externalPeerRouter,
daniel park32b42202018-03-14 16:53:44 +0900450 boolean install) {
Hyunsun Moon44aac662017-02-18 02:07:01 +0900451 IpAddress floating = IpAddress.valueOf(floatingIp.getFloatingIpAddress());
daniel parkee8700b2017-05-11 15:50:03 +0900452 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder()
Hyunsun Moon44aac662017-02-18 02:07:01 +0900453 .matchEthType(Ethernet.TYPE_IPV4)
daniel parkee8700b2017-05-11 15:50:03 +0900454 .matchIPSrc(instPort.ipAddress().toIpPrefix());
455
456 switch (osNet.getNetworkType()) {
457 case VXLAN:
458 sBuilder.matchTunnelId(Long.valueOf(osNet.getProviderSegID()));
459 break;
460 case VLAN:
461 sBuilder.matchVlanId(VlanId.vlanId(osNet.getProviderSegID()));
462 break;
463 default:
Ray Milkeyc6c9b172018-02-26 09:36:31 -0800464 final String error = String.format(ERR_UNSUPPORTED_NET_TYPE,
Hyunsun Moon0d457362017-06-27 17:19:41 +0900465 osNet.getNetworkType());
daniel parkee8700b2017-05-11 15:50:03 +0900466 throw new IllegalStateException(error);
467 }
Hyunsun Moon44aac662017-02-18 02:07:01 +0900468
Daniel Park75e3d7f2018-05-29 14:43:53 +0900469 TrafficSelector selector = sBuilder.build();
daniel parkeeb8e042018-02-21 14:06:58 +0900470
Hyunsun Moon0d457362017-06-27 17:19:41 +0900471 osNodeService.completeNodes(GATEWAY).forEach(gNode -> {
Daniel Park75e3d7f2018-05-29 14:43:53 +0900472 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder()
473 .setIpSrc(floating.getIp4Address())
474 .setEthSrc(instPort.macAddress())
Jian Li5e2ad4a2018-07-16 13:40:53 +0900475 .setEthDst(externalPeerRouter.macAddress());
Hyunsun Moon44aac662017-02-18 02:07:01 +0900476
Daniel Park75e3d7f2018-05-29 14:43:53 +0900477 if (osNet.getNetworkType().equals(NetworkType.VLAN)) {
478 tBuilder.popVlan();
479 }
480
Jian Li5e2ad4a2018-07-16 13:40:53 +0900481 if (!externalPeerRouter.vlanId().equals(VlanId.NONE)) {
482 tBuilder.pushVlan().setVlanId(externalPeerRouter.vlanId());
Daniel Park75e3d7f2018-05-29 14:43:53 +0900483 }
sanghodc375372017-06-08 10:41:30 +0900484 osFlowRuleService.setRule(
Hyunsun Moon44aac662017-02-18 02:07:01 +0900485 appId,
Hyunsun Moon0d457362017-06-27 17:19:41 +0900486 gNode.intgBridge(),
Daniel Park75e3d7f2018-05-29 14:43:53 +0900487 selector,
daniel parkeeb8e042018-02-21 14:06:58 +0900488 tBuilder.setOutput(gNode.uplinkPortNum()).build(),
Hyunsun Moon44aac662017-02-18 02:07:01 +0900489 PRIORITY_FLOATING_EXTERNAL,
sanghodc375372017-06-08 10:41:30 +0900490 GW_COMMON_TABLE,
Hyunsun Moon44aac662017-02-18 02:07:01 +0900491 install);
Daniel Park75e3d7f2018-05-29 14:43:53 +0900492 });
daniel parkc2a2ed62018-04-10 15:17:42 +0900493 log.trace("Succeeded to set flow rules for upstream on gateway nodes");
Hyunsun Moon44aac662017-02-18 02:07:01 +0900494 }
495
Jian Li99892e92018-04-13 14:59:39 +0900496 private void associateFloatingIp(NetFloatingIP osFip) {
Jian Li628a7cb2018-08-11 23:04:24 +0900497 InstancePort instPort = instancePortService.instancePort(osFip.getPortId());
498
499 if (instPort == null) {
500 log.warn("Failed to insert floating IP rule for {} due to missing of port info.",
501 osFip.getFloatingIpAddress());
502 return;
Jian Li99892e92018-04-13 14:59:39 +0900503 }
Jian Li628a7cb2018-08-11 23:04:24 +0900504
Jian Li99892e92018-04-13 14:59:39 +0900505 // set floating IP rules only if the port is associated to a VM
Jian Li628a7cb2018-08-11 23:04:24 +0900506 if (!Strings.isNullOrEmpty(instPort.deviceId().toString())) {
507 setFloatingIpRules(osFip, instPort, null, true);
Daniel Park4fa1f5e2018-10-17 12:41:52 +0900508 processGratuitousArpPacket(osFip, instPort);
509
Jian Li99892e92018-04-13 14:59:39 +0900510 }
511 }
512
Daniel Park4fa1f5e2018-10-17 12:41:52 +0900513 private void processGratuitousArpPacket(NetFloatingIP floatingIP,
514 InstancePort instancePort) {
515 Set<OpenstackNode> gws = ImmutableSet.copyOf(osNodeService.completeNodes(GATEWAY));
516
517 Network osNet = osNetworkService.network(instancePort.networkId());
518
519
520 OpenstackNode selectedGw = getGwByInstancePort(gws, instancePort);
521 ExternalPeerRouter externalPeerRouter =
522 externalPeerRouterForNetwork(osNet, osNetworkService, osRouterAdminService);
523 if (externalPeerRouter == null) {
Jian Li4d138702018-11-27 17:25:28 +0900524 log.error("Failed to process GARP packet for floating ip {}, because " +
525 NO_EXT_PEER_ROUTER_MSG);
Daniel Park4fa1f5e2018-10-17 12:41:52 +0900526 return;
527 }
528
Jian Li32b03622018-11-06 17:54:24 +0900529 processGarpPacketForFloatingIp(floatingIP, instancePort,
530 externalPeerRouter.vlanId(), selectedGw, packetService);
Daniel Park4fa1f5e2018-10-17 12:41:52 +0900531
532 }
533
Jian Li99892e92018-04-13 14:59:39 +0900534 private void disassociateFloatingIp(NetFloatingIP osFip, String portId) {
Jian Li628a7cb2018-08-11 23:04:24 +0900535 InstancePort instPort = instancePortService.instancePort(portId);
Jian Lie1a39032018-06-19 21:49:36 +0900536
Jian Li628a7cb2018-08-11 23:04:24 +0900537 if (instPort == null) {
538 log.warn("Failed to remove floating IP rule for {} due to missing of port info.",
539 osFip.getFloatingIpAddress());
540 return;
Jian Lie1a39032018-06-19 21:49:36 +0900541 }
542
Jian Li99892e92018-04-13 14:59:39 +0900543 // set floating IP rules only if the port is associated to a VM
Jian Li628a7cb2018-08-11 23:04:24 +0900544 if (!Strings.isNullOrEmpty(instPort.deviceId().toString())) {
545 setFloatingIpRules(osFip, instPort, null, false);
Jian Li99892e92018-04-13 14:59:39 +0900546 }
547 }
548
Hyunsun Moon0d457362017-06-27 17:19:41 +0900549 private class InternalFloatingIpListener implements OpenstackRouterListener {
Hyunsun Moon44aac662017-02-18 02:07:01 +0900550
551 @Override
552 public boolean isRelevant(OpenstackRouterEvent event) {
Hyunsun Moon44aac662017-02-18 02:07:01 +0900553 return event.floatingIp() != null;
554 }
555
Jian Li34220ea2018-11-14 01:30:24 +0900556 private boolean isRelevantHelper() {
557 return Objects.equals(localNodeId, leadershipService.getLeader(appId.name()));
558 }
559
Hyunsun Moon44aac662017-02-18 02:07:01 +0900560 @Override
561 public void event(OpenstackRouterEvent event) {
562 switch (event.type()) {
563 case OPENSTACK_FLOATING_IP_ASSOCIATED:
Jian Li4d138702018-11-27 17:25:28 +0900564 eventExecutor.execute(() -> processFloatingIpAssociation(event));
Hyunsun Moon7a5f9042017-05-11 18:19:01 +0900565 break;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900566 case OPENSTACK_FLOATING_IP_DISASSOCIATED:
Jian Li4d138702018-11-27 17:25:28 +0900567 eventExecutor.execute(() -> processFloatingIpDisassociation(event));
Hyunsun Moon7a5f9042017-05-11 18:19:01 +0900568 break;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900569 case OPENSTACK_FLOATING_IP_CREATED:
Jian Li4d138702018-11-27 17:25:28 +0900570 eventExecutor.execute(() -> processFloatingIpCreation(event));
Hyunsun Moonb720e632017-05-16 15:41:36 +0900571 break;
Jian Lia171a432018-06-11 11:52:11 +0900572 case OPENSTACK_FLOATING_IP_REMOVED:
Jian Li4d138702018-11-27 17:25:28 +0900573 eventExecutor.execute(() -> processFloatingIpRemoval(event));
Jian Lia171a432018-06-11 11:52:11 +0900574 break;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900575 case OPENSTACK_FLOATING_IP_UPDATED:
Hyunsun Moon44aac662017-02-18 02:07:01 +0900576 default:
577 // do nothing for the other events
578 break;
579 }
580 }
Jian Li4d138702018-11-27 17:25:28 +0900581
582 private void processFloatingIpAssociation(OpenstackRouterEvent event) {
583 if (!isRelevantHelper()) {
584 return;
585 }
586
587 NetFloatingIP osFip = event.floatingIp();
588 if (instancePortService.instancePort(osFip.getPortId()) != null) {
589 associateFloatingIp(osFip);
590 log.info("Associated floating IP {}:{}",
591 osFip.getFloatingIpAddress(),
592 osFip.getFixedIpAddress());
593 }
594 }
595
596 private void processFloatingIpDisassociation(OpenstackRouterEvent event) {
597 if (!isRelevantHelper()) {
598 return;
599 }
600
601 NetFloatingIP osFip = event.floatingIp();
602 if (instancePortService.instancePort(event.portId()) != null) {
603 disassociateFloatingIp(osFip, event.portId());
604 log.info("Disassociated floating IP {}:{}",
605 osFip.getFloatingIpAddress(),
606 osFip.getFixedIpAddress());
607 }
608 }
609
610 private void processFloatingIpCreation(OpenstackRouterEvent event) {
611 if (!isRelevantHelper()) {
612 return;
613 }
614
615 NetFloatingIP osFip = event.floatingIp();
616 String portId = osFip.getPortId();
617 if (!Strings.isNullOrEmpty(portId) &&
618 instancePortService.instancePort(portId) != null) {
619 associateFloatingIp(event.floatingIp());
620 }
621 log.info("Created floating IP {}", osFip.getFloatingIpAddress());
622 }
623
624 private void processFloatingIpRemoval(OpenstackRouterEvent event) {
625 if (!isRelevantHelper()) {
626 return;
627 }
628
629 NetFloatingIP osFip = event.floatingIp();
630 String portId = osFip.getPortId();
631 if (!Strings.isNullOrEmpty(osFip.getPortId())) {
632 // in case the floating IP is not associated with any port due to
633 // port removal, we simply do not execute floating IP disassociation
634 if (osNetworkService.port(portId) != null &&
635 instancePortService.instancePort(portId) != null) {
636 disassociateFloatingIp(osFip, portId);
637 }
638
639 // since we skip floating IP disassociation, we need to
640 // manually unsubscribe the port pre-remove event
641 preCommitPortService.unsubscribePreCommit(osFip.getPortId(),
642 OPENSTACK_PORT_PRE_REMOVE, instancePortService,
643 this.getClass().getName());
644 log.info("Unsubscribed the port {} on listening pre-remove event",
645 osFip.getPortId());
646 }
647 log.info("Removed floating IP {}", osFip.getFloatingIpAddress());
648 }
Hyunsun Moon44aac662017-02-18 02:07:01 +0900649 }
650
651 private class InternalNodeListener implements OpenstackNodeListener {
652
653 @Override
654 public boolean isRelevant(OpenstackNodeEvent event) {
Hyunsun Moon44aac662017-02-18 02:07:01 +0900655 return event.subject().type() == GATEWAY;
656 }
657
Jian Li34220ea2018-11-14 01:30:24 +0900658 private boolean isRelevantHelper() {
659 return Objects.equals(localNodeId, leadershipService.getLeader(appId.name()));
660 }
661
Hyunsun Moon44aac662017-02-18 02:07:01 +0900662 @Override
663 public void event(OpenstackNodeEvent event) {
Hyunsun Moon44aac662017-02-18 02:07:01 +0900664
665 switch (event.type()) {
Hyunsun Moon0d457362017-06-27 17:19:41 +0900666 case OPENSTACK_NODE_COMPLETE:
Jian Li4d138702018-11-27 17:25:28 +0900667 eventExecutor.execute(() -> processNodeCompletion(event));
Hyunsun Moon44aac662017-02-18 02:07:01 +0900668 break;
Hyunsun Moon0d457362017-06-27 17:19:41 +0900669 case OPENSTACK_NODE_INCOMPLETE:
Jian Li4d138702018-11-27 17:25:28 +0900670 eventExecutor.execute(() -> processNodeIncompletion(event));
Jian Li1064e4f2018-05-29 16:16:53 +0900671 break;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900672 default:
Hyunsun Moon0d457362017-06-27 17:19:41 +0900673 // do nothing
Hyunsun Moon44aac662017-02-18 02:07:01 +0900674 break;
675 }
676 }
Jian Li4d138702018-11-27 17:25:28 +0900677
678 private void processNodeCompletion(OpenstackNodeEvent event) {
679 if (!isRelevantHelper()) {
680 return;
681 }
682
683 for (NetFloatingIP fip : osRouterAdminService.floatingIps()) {
684
685 if (Strings.isNullOrEmpty(fip.getPortId())) {
686 continue;
687 }
688
689 Port osPort = osNetworkService.port(fip.getPortId());
690 InstancePort instPort = instancePortService.instancePort(fip.getPortId());
691
692 // we check both Openstack Port and Instance Port
693 if (osPort == null || instPort == null) {
694 continue;
695 }
696
697 setFloatingIpRules(fip, instPort, event.subject(), true);
698 }
699 }
700
701 private void processNodeIncompletion(OpenstackNodeEvent event) {
702 if (!isRelevantHelper()) {
703 return;
704 }
705
706 for (NetFloatingIP fip : osRouterAdminService.floatingIps()) {
707 if (Strings.isNullOrEmpty(fip.getPortId())) {
708 continue;
709 }
710 Port osPort = osNetworkService.port(fip.getPortId());
711 if (osPort == null) {
712 log.warn("Failed to set floating IP {}", fip.getId());
713 continue;
714 }
715 Network osNet = osNetworkService.network(osPort.getNetworkId());
716 if (osNet == null) {
717 final String errorFormat = ERR_FLOW + "no network(%s) exists";
718 final String error = String.format(errorFormat,
719 fip.getFloatingIpAddress(),
720 osPort.getNetworkId());
721 throw new IllegalStateException(error);
722 }
723 MacAddress srcMac = MacAddress.valueOf(osPort.getMacAddress());
724 log.trace("Mac address of openstack port: {}", srcMac);
725 InstancePort instPort = instancePortService.instancePort(srcMac);
726
727 if (instPort == null) {
728 final String errorFormat = ERR_FLOW + "no host(MAC:%s) found";
729 final String error = String.format(errorFormat,
730 fip.getFloatingIpAddress(), srcMac);
731 throw new IllegalStateException(error);
732 }
733
734 ExternalPeerRouter externalPeerRouter = externalPeerRouterForNetwork(osNet,
735 osNetworkService, osRouterAdminService);
736 if (externalPeerRouter == null) {
737 final String errorFormat = ERR_FLOW + NO_EXT_PEER_ROUTER_MSG;
738 throw new IllegalStateException(errorFormat);
739 }
740
741 updateComputeNodeRules(instPort, osNet, event.subject(), false);
742 updateGatewayNodeRules(fip, instPort, osNet,
743 externalPeerRouter, event.subject(), false);
744 }
745 }
Hyunsun Moon44aac662017-02-18 02:07:01 +0900746 }
Jian Li99892e92018-04-13 14:59:39 +0900747
Jian Li24ec59f2018-05-23 19:01:25 +0900748 private class InternalInstancePortListener implements InstancePortListener {
749
Jian Li34220ea2018-11-14 01:30:24 +0900750 private boolean isRelevantHelper(InstancePortEvent event) {
Jian Li24ec59f2018-05-23 19:01:25 +0900751
Jian Lie1a39032018-06-19 21:49:36 +0900752 if (event.type() == OPENSTACK_INSTANCE_MIGRATION_ENDED ||
753 event.type() == OPENSTACK_INSTANCE_MIGRATION_STARTED) {
754 Set<NetFloatingIP> ips = osRouterAdminService.floatingIps();
755 NetFloatingIP fip = associatedFloatingIp(event.subject(), ips);
756
757 // we check the possible NPE to avoid duplicated null check
758 // for OPENSTACK_INSTANCE_MIGRATION_ENDED and
759 // OPENSTACK_INSTANCE_MIGRATION_STARTED cases
760 if (fip == null || !isAssociatedWithVM(osNetworkService, fip)) {
761 return false;
762 }
763 }
764
Jian Li34220ea2018-11-14 01:30:24 +0900765 return Objects.equals(localNodeId, leadershipService.getLeader(appId.name()));
Jian Li24ec59f2018-05-23 19:01:25 +0900766 }
767
768 @Override
769 public void event(InstancePortEvent event) {
Jian Li24ec59f2018-05-23 19:01:25 +0900770 switch (event.type()) {
Jian Lie1a39032018-06-19 21:49:36 +0900771 case OPENSTACK_INSTANCE_PORT_DETECTED:
Jian Li4d138702018-11-27 17:25:28 +0900772 eventExecutor.execute(() -> processInstancePortDetection(event));
Jian Lie1a39032018-06-19 21:49:36 +0900773 break;
Jian Li24ec59f2018-05-23 19:01:25 +0900774 case OPENSTACK_INSTANCE_MIGRATION_STARTED:
Jian Li4d138702018-11-27 17:25:28 +0900775 eventExecutor.execute(() -> processInstanceMigrationStart(event));
Jian Li24ec59f2018-05-23 19:01:25 +0900776 break;
777 case OPENSTACK_INSTANCE_MIGRATION_ENDED:
Jian Li4d138702018-11-27 17:25:28 +0900778 eventExecutor.execute(() -> processInstanceMigrationEnd(event));
Jian Li24ec59f2018-05-23 19:01:25 +0900779 break;
780 default:
781 break;
782 }
783 }
Jian Li4d138702018-11-27 17:25:28 +0900784
785 private void processInstancePortDetection(InstancePortEvent event) {
786 if (!isRelevantHelper(event)) {
787 return;
788 }
789
790 InstancePort instPort = event.subject();
791
792 if (instPort != null && instPort.portId() != null) {
793 osRouterAdminService.floatingIps().stream()
794 .filter(f -> f.getPortId() != null)
795 .filter(f -> f.getPortId().equals(instPort.portId()))
796 .forEach(f -> setFloatingIpRules(f,
797 instPort, null, true));
798 }
799 }
800
801 private void processInstanceMigrationStart(InstancePortEvent event) {
802 if (!isRelevantHelper(event)) {
803 return;
804 }
805
806 Set<OpenstackNode> gateways = osNodeService.completeNodes(GATEWAY);
807 Set<NetFloatingIP> ips = osRouterAdminService.floatingIps();
808 NetFloatingIP fip = associatedFloatingIp(event.subject(), ips);
809
810 if (fip == null) {
811 return;
812 }
813
814 Port osPort = osNetworkService.port(fip.getPortId());
815 Network osNet = osNetworkService.network(osPort.getNetworkId());
816 ExternalPeerRouter externalPeerRouter = externalPeerRouterForNetwork(osNet,
817 osNetworkService, osRouterAdminService);
818
819 if (externalPeerRouter == null) {
820 final String errorFormat = ERR_FLOW + NO_EXT_PEER_ROUTER_MSG;
821 throw new IllegalStateException(errorFormat);
822 }
823
824 // since DownstreamExternal rules should only be placed in
825 // corresponding gateway node, we need to install new rule to
826 // the corresponding gateway node
827 setDownstreamExternalRulesHelper(fip, osNet,
828 event.subject(), externalPeerRouter, gateways, true);
829
830 // since ComputeNodeToGateway rules should only be placed in
831 // corresponding compute node, we need to install new rule to
832 // the target compute node, and remove rules from original node
833 setComputeNodeToGatewayHelper(event.subject(), osNet, gateways, true);
834 }
835
836 private void processInstanceMigrationEnd(InstancePortEvent event) {
837 if (!isRelevantHelper(event)) {
838 return;
839 }
840
841 InstancePort oldInstPort = swapStaleLocation(event.subject());
842
843 Set<NetFloatingIP> ips = osRouterAdminService.floatingIps();
844 NetFloatingIP fip = associatedFloatingIp(oldInstPort, ips);
845
846 if (fip == null) {
847 return;
848 }
849
850 Set<OpenstackNode> gateways = osNodeService.completeNodes(GATEWAY);
851 Port osPort = osNetworkService.port(fip.getPortId());
852 Network osNet = osNetworkService.network(osPort.getNetworkId());
853 ExternalPeerRouter externalPeerRouter = externalPeerRouterForNetwork(osNet,
854 osNetworkService, osRouterAdminService);
855
856 if (externalPeerRouter == null) {
857 final String errorFormat = ERR_FLOW + NO_EXT_PEER_ROUTER_MSG;
858 throw new IllegalStateException(errorFormat);
859 }
860
861 // We need to remove the old ComputeNodeToGateway rules from
862 // original compute node
863 setComputeNodeToGatewayHelper(oldInstPort, osNet, gateways, false);
864
865 // If we only have one gateway, we simply do not remove any
866 // flow rules from either gateway or compute node
867 if (gateways.size() == 1) {
868 return;
869 }
870
871 // Checks whether the destination compute node's device id
872 // has identical gateway hash or not
873 // if it is true, we simply do not remove the rules, as
874 // it has been overwritten at port detention event
875 // if it is false, we will remove the rules
876 DeviceId newDeviceId = event.subject().deviceId();
877 DeviceId oldDeviceId = oldInstPort.deviceId();
878
879 OpenstackNode oldGateway = getGwByComputeDevId(gateways, oldDeviceId);
880 OpenstackNode newGateway = getGwByComputeDevId(gateways, newDeviceId);
881
882 if (oldGateway != null && oldGateway.equals(newGateway)) {
883 return;
884 }
885
886 // Since DownstreamExternal rules should only be placed in
887 // corresponding gateway node, we need to remove old rule from
888 // the corresponding gateway node
889 setDownstreamExternalRulesHelper(fip, osNet, oldInstPort,
890 externalPeerRouter, gateways, false);
891 }
Jian Li24ec59f2018-05-23 19:01:25 +0900892 }
Jian Lie1a39032018-06-19 21:49:36 +0900893
894 private class InternalOpenstackNetworkListener implements OpenstackNetworkListener {
895
Jian Li34220ea2018-11-14 01:30:24 +0900896 private boolean isRelevantHelper() {
897 return Objects.equals(localNodeId, leadershipService.getLeader(appId.name()));
Jian Lie1a39032018-06-19 21:49:36 +0900898 }
899
900 @Override
901 public void event(OpenstackNetworkEvent event) {
Jian Li4d138702018-11-27 17:25:28 +0900902 if (event.type() == OPENSTACK_PORT_PRE_REMOVE) {
903 eventExecutor.execute(() -> {
Jian Li34220ea2018-11-14 01:30:24 +0900904
Jian Li4d138702018-11-27 17:25:28 +0900905 if (!isRelevantHelper()) {
906 return;
907 }
Jian Li34220ea2018-11-14 01:30:24 +0900908
Jian Li4d138702018-11-27 17:25:28 +0900909 processPortPreRemoval(event);
910 });
Jian Lie1a39032018-06-19 21:49:36 +0900911 }
912 }
913
Jian Li4d138702018-11-27 17:25:28 +0900914 private void processPortPreRemoval(OpenstackNetworkEvent event) {
Jian Li32b03622018-11-06 17:54:24 +0900915 InstancePort instPort = instancePortService.instancePort(
916 event.port().getId());
917 if (instPort == null) {
918 return;
919 }
920 NetFloatingIP fip = associatedFloatingIp(instPort,
921 osRouterAdminService.floatingIps());
922
923 if (fip != null) {
924 instancePortService.updateInstancePort(
925 instPort.updateState(REMOVE_PENDING));
926 updateFipStore(event.port().getId());
927 } else {
928 instancePortService.removeInstancePort(instPort.portId());
929 }
930 }
931
Jian Li2360acb2018-10-17 00:46:31 +0900932 private void updateFipStore(String portId) {
Jian Lie1a39032018-06-19 21:49:36 +0900933
Jian Li2360acb2018-10-17 00:46:31 +0900934 if (portId == null) {
Jian Lie1a39032018-06-19 21:49:36 +0900935 return;
936 }
937
938 Set<NetFloatingIP> ips = osRouterAdminService.floatingIps();
939 for (NetFloatingIP fip : ips) {
940 if (Strings.isNullOrEmpty(fip.getFixedIpAddress())) {
941 continue;
942 }
943 if (Strings.isNullOrEmpty(fip.getFloatingIpAddress())) {
944 continue;
945 }
Jian Li2360acb2018-10-17 00:46:31 +0900946 if (fip.getPortId().equals(portId)) {
Jian Lie1a39032018-06-19 21:49:36 +0900947 NeutronFloatingIP neutronFip = (NeutronFloatingIP) fip;
948 // invalidate bound fixed IP and port
949 neutronFip.setFixedIpAddress(null);
950 neutronFip.setPortId(null);
Jian Lie1a39032018-06-19 21:49:36 +0900951
952 // Following update will in turn trigger
953 // OPENSTACK_FLOATING_IP_DISASSOCIATED event
954 osRouterAdminService.updateFloatingIp(neutronFip);
955 log.info("Updated floating IP {}, due to host removal",
956 neutronFip.getFloatingIpAddress());
957 }
958 }
959 }
960 }
Hyunsun Moon44aac662017-02-18 02:07:01 +0900961}