blob: 2b48baa9dc525e671e465b03ef041d07dbc8de4b [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
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700104 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Hyunsun Moon44aac662017-02-18 02:07:01 +0900105 protected CoreService coreService;
106
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700107 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Hyunsun Moon44aac662017-02-18 02:07:01 +0900108 protected DeviceService deviceService;
109
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700110 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Hyunsun Moon44aac662017-02-18 02:07:01 +0900111 protected LeadershipService leadershipService;
112
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700113 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Hyunsun Moon44aac662017-02-18 02:07:01 +0900114 protected ClusterService clusterService;
115
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700116 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Hyunsun Moon44aac662017-02-18 02:07:01 +0900117 protected OpenstackNodeService osNodeService;
118
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700119 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jian Liec5c32b2018-07-13 14:28:58 +0900120 protected InstancePortAdminService instancePortService;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900121
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700122 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jian Lif3a28b02018-06-11 21:29:13 +0900123 protected OpenstackRouterAdminService osRouterAdminService;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900124
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700125 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Hyunsun Moon44aac662017-02-18 02:07:01 +0900126 protected OpenstackNetworkService osNetworkService;
127
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700128 @Reference(cardinality = ReferenceCardinality.MANDATORY)
sanghodc375372017-06-08 10:41:30 +0900129 protected OpenstackFlowRuleService osFlowRuleService;
130
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700131 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jian Li8f64feb2018-07-24 13:20:16 +0900132 protected PreCommitPortService preCommitPortService;
133
Ray Milkeyd5425682018-10-23 10:21:33 -0700134 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Daniel Park4fa1f5e2018-10-17 12:41:52 +0900135 protected PacketService packetService;
136
Hyunsun Moon44aac662017-02-18 02:07:01 +0900137 private final ExecutorService eventExecutor = newSingleThreadExecutor(
138 groupedThreads(this.getClass().getSimpleName(), "event-handler", log));
Jian Li24ec59f2018-05-23 19:01:25 +0900139 private final OpenstackRouterListener floatingIpListener = new InternalFloatingIpListener();
140 private final InstancePortListener instancePortListener = new InternalInstancePortListener();
Hyunsun Moon44aac662017-02-18 02:07:01 +0900141 private final OpenstackNodeListener osNodeListener = new InternalNodeListener();
Jian Lie1a39032018-06-19 21:49:36 +0900142 private final OpenstackNetworkListener osNetworkListener = new InternalOpenstackNetworkListener();
143 private final InstancePortListener instPortListener = new InternalInstancePortListener();
144
Hyunsun Moon44aac662017-02-18 02:07:01 +0900145 private ApplicationId appId;
146 private NodeId localNodeId;
147
148 @Activate
149 protected void activate() {
150 appId = coreService.registerApplication(OPENSTACK_NETWORKING_APP_ID);
151 localNodeId = clusterService.getLocalNode().id();
152 leadershipService.runForLeadership(appId.name());
Jian Li24ec59f2018-05-23 19:01:25 +0900153 osRouterAdminService.addListener(floatingIpListener);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900154 osNodeService.addListener(osNodeListener);
Jian Li24ec59f2018-05-23 19:01:25 +0900155 instancePortService.addListener(instancePortListener);
Jian Lie1a39032018-06-19 21:49:36 +0900156 osNodeService.addListener(osNodeListener);
157 osNetworkService.addListener(osNetworkListener);
158 instancePortService.addListener(instPortListener);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900159
160 log.info("Started");
161 }
162
163 @Deactivate
164 protected void deactivate() {
Jian Li24ec59f2018-05-23 19:01:25 +0900165 instancePortService.removeListener(instancePortListener);
Jian Lie1a39032018-06-19 21:49:36 +0900166 instancePortService.removeListener(instPortListener);
167 osNetworkService.removeListener(osNetworkListener);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900168 osNodeService.removeListener(osNodeListener);
Jian Li24ec59f2018-05-23 19:01:25 +0900169 osRouterAdminService.removeListener(floatingIpListener);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900170 leadershipService.withdraw(appId.name());
171 eventExecutor.shutdown();
172
173 log.info("Stopped");
174 }
175
Jian Li628a7cb2018-08-11 23:04:24 +0900176 private void setFloatingIpRules(NetFloatingIP floatingIp, InstancePort instPort,
Jian Li1064e4f2018-05-29 16:16:53 +0900177 OpenstackNode gateway, boolean install) {
Jian Li628a7cb2018-08-11 23:04:24 +0900178
179 if (instPort == null) {
180 log.debug("No instance port found");
181 return;
182 }
183
184 Network osNet = osNetworkService.network(instPort.networkId());
Jian Li8f64feb2018-07-24 13:20:16 +0900185
Daniel Park4fa1f5e2018-10-17 12:41:52 +0900186 ExternalPeerRouter externalPeerRouter = externalPeerRouterForNetwork(osNet,
187 osNetworkService, osRouterAdminService);
daniel park32b42202018-03-14 16:53:44 +0900188 if (externalPeerRouter == null) {
daniel parkc2a2ed62018-04-10 15:17:42 +0900189 final String errorFormat = ERR_FLOW + "no external peer router found";
190 throw new IllegalStateException(errorFormat);
daniel park32b42202018-03-14 16:53:44 +0900191 }
192
Jian Li8f64feb2018-07-24 13:20:16 +0900193 if (install) {
Jian Li628a7cb2018-08-11 23:04:24 +0900194 preCommitPortService.subscribePreCommit(instPort.portId(),
Jian Li8f64feb2018-07-24 13:20:16 +0900195 OPENSTACK_PORT_PRE_REMOVE, this.getClass().getName());
Jian Li628a7cb2018-08-11 23:04:24 +0900196 log.info("Subscribed the port {} on listening pre-remove event", instPort.portId());
Jian Li8f64feb2018-07-24 13:20:16 +0900197 } else {
Jian Li628a7cb2018-08-11 23:04:24 +0900198 preCommitPortService.unsubscribePreCommit(instPort.portId(),
199 OPENSTACK_PORT_PRE_REMOVE, instancePortService, this.getClass().getName());
200 log.info("Unsubscribed the port {} on listening pre-remove event", instPort.portId());
Jian Li8f64feb2018-07-24 13:20:16 +0900201 }
202
Jian Lide679782018-06-05 01:41:29 +0900203 updateComputeNodeRules(instPort, osNet, gateway, install);
204 updateGatewayNodeRules(floatingIp, instPort, osNet, externalPeerRouter, gateway, install);
205
Jian Lide679782018-06-05 01:41:29 +0900206 // TODO: need to refactor setUpstreamRules if possible
daniel park32b42202018-03-14 16:53:44 +0900207 setUpstreamRules(floatingIp, osNet, instPort, externalPeerRouter, install);
Jian Li8f64feb2018-07-24 13:20:16 +0900208
daniel parkc2a2ed62018-04-10 15:17:42 +0900209 log.trace("Succeeded to set flow rules for floating ip {}:{} and install: {}",
210 floatingIp.getFloatingIpAddress(),
211 floatingIp.getFixedIpAddress(),
212 install);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900213 }
214
Jian Lide679782018-06-05 01:41:29 +0900215 private synchronized void updateGatewayNodeRules(NetFloatingIP fip,
216 InstancePort instPort,
217 Network osNet,
218 ExternalPeerRouter router,
219 OpenstackNode gateway,
220 boolean install) {
221
222 Set<OpenstackNode> completedGws = osNodeService.completeNodes(GATEWAY);
223 Set<OpenstackNode> finalGws = Sets.newConcurrentHashSet();
224 finalGws.addAll(ImmutableSet.copyOf(completedGws));
225
Jian Lia171a432018-06-11 11:52:11 +0900226
227 if (gateway == null) {
228 // these are floating IP related cases...
229 setDownstreamExternalRulesHelper(fip, osNet, instPort, router,
230 ImmutableSet.copyOf(finalGws), install);
231
Jian Lide679782018-06-05 01:41:29 +0900232 } else {
Jian Lia171a432018-06-11 11:52:11 +0900233 // these are openstack node related cases...
234 if (install) {
235 if (completedGws.contains(gateway)) {
236 if (completedGws.size() > 1) {
237 finalGws.remove(gateway);
238 if (fip.getPortId() != null) {
239 setDownstreamExternalRulesHelper(fip, osNet, instPort, router,
240 ImmutableSet.copyOf(finalGws), false);
241 finalGws.add(gateway);
242 }
243 }
Jian Lide679782018-06-05 01:41:29 +0900244 if (fip.getPortId() != null) {
245 setDownstreamExternalRulesHelper(fip, osNet, instPort, router,
246 ImmutableSet.copyOf(finalGws), true);
247 }
Jian Lia171a432018-06-11 11:52:11 +0900248 } else {
249 log.warn("Detected node should be included in completed gateway set");
Jian Lide679782018-06-05 01:41:29 +0900250 }
251 } else {
Jian Lia171a432018-06-11 11:52:11 +0900252 if (!completedGws.contains(gateway)) {
253 if (completedGws.size() >= 1) {
254 if (fip.getPortId() != null) {
255 setDownstreamExternalRulesHelper(fip, osNet, instPort, router,
256 ImmutableSet.copyOf(finalGws), true);
257 }
258 }
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);
302 if (completedGws.size() >= 1) {
303 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");
daniel parkeeb8e042018-02-21 14:06:58 +0900330 }
Daniel Park3f26e792018-11-26 18:34:53 +0900331
332 switch (osNet.getNetworkType()) {
333 case VXLAN:
334 if (osNodeService.node(instPort.deviceId()).tunnelPortNum() == null) {
335 log.warn(ERR_FLOW + "no tunnel port");
336 return;
337 }
Ray Milkeyc2631572018-11-26 16:19:23 -0800338 if (selectedGatewayNode == null) {
339 log.warn(ERR_FLOW + "no gateway node");
340 return;
341 }
Daniel Park3f26e792018-11-26 18:34:53 +0900342 sBuilder.matchTunnelId(Long.parseLong(osNet.getProviderSegID()));
343 tBuilder.extension(buildExtension(
daniel parkeeb8e042018-02-21 14:06:58 +0900344 deviceService,
345 instPort.deviceId(),
346 selectedGatewayNode.dataIp().getIp4Address()),
347 instPort.deviceId())
Daniel Park3f26e792018-11-26 18:34:53 +0900348 .setOutput(osNodeService.node(instPort.deviceId()).tunnelPortNum());
349 break;
350 case VLAN:
351 if (osNodeService.node(instPort.deviceId()).vlanPortNum() == null) {
352 log.warn(ERR_FLOW + "no vlan port");
353 return;
354 }
355 sBuilder.matchVlanId(VlanId.vlanId(osNet.getProviderSegID()));
356 tBuilder.setOutput(osNodeService.node(instPort.deviceId()).vlanPortNum());
357 break;
358 default:
359 log.warn(ERR_FLOW + "no supported network type");
360 }
daniel parkeeb8e042018-02-21 14:06:58 +0900361
362 osFlowRuleService.setRule(
363 appId,
364 instPort.deviceId(),
365 sBuilder.build(),
Daniel Park3f26e792018-11-26 18:34:53 +0900366 tBuilder.build(),
daniel parkeeb8e042018-02-21 14:06:58 +0900367 PRIORITY_EXTERNAL_FLOATING_ROUTING_RULE,
368 ROUTING_TABLE,
369 install);
daniel parkc2a2ed62018-04-10 15:17:42 +0900370 log.trace("Succeeded to set flow rules from compute node to gateway on compute node");
daniel parkeeb8e042018-02-21 14:06:58 +0900371 }
372
Jian Lide679782018-06-05 01:41:29 +0900373 private void setDownstreamExternalRulesHelper(NetFloatingIP floatingIp,
374 Network osNet,
375 InstancePort instPort,
376 ExternalPeerRouter externalPeerRouter,
377 Set<OpenstackNode> gateways, boolean install) {
378 OpenstackNode cNode = osNodeService.node(instPort.deviceId());
379 if (cNode == null) {
380 final String error = String.format("Cannot find openstack node for device %s",
381 instPort.deviceId());
382 throw new IllegalStateException(error);
383 }
384 if (osNet.getNetworkType() == NetworkType.VXLAN && cNode.dataIp() == null) {
385 final String errorFormat = ERR_FLOW + "VXLAN mode is not ready for %s";
386 final String error = String.format(errorFormat, floatingIp, cNode.hostname());
387 throw new IllegalStateException(error);
388 }
389 if (osNet.getNetworkType() == NetworkType.VLAN && cNode.vlanIntf() == null) {
390 final String errorFormat = ERR_FLOW + "VLAN mode is not ready for %s";
391 final String error = String.format(errorFormat, floatingIp, cNode.hostname());
392 throw new IllegalStateException(error);
393 }
394
395 IpAddress floating = IpAddress.valueOf(floatingIp.getFloatingIpAddress());
396
397 OpenstackNode selectedGatewayNode = getGwByComputeDevId(gateways, instPort.deviceId());
398
399 if (selectedGatewayNode == null) {
400 final String errorFormat = ERR_FLOW + "no gateway node selected";
401 throw new IllegalStateException(errorFormat);
402 }
403
404 TrafficSelector.Builder externalSelectorBuilder = DefaultTrafficSelector.builder()
405 .matchEthType(Ethernet.TYPE_IPV4)
Daniel Park319b9ab2018-09-14 11:27:04 +0900406 .matchInPort(selectedGatewayNode.uplinkPortNum())
Jian Lide679782018-06-05 01:41:29 +0900407 .matchIPDst(floating.toIpPrefix());
408
409 TrafficTreatment.Builder externalTreatmentBuilder = DefaultTrafficTreatment.builder()
410 .setEthSrc(Constants.DEFAULT_GATEWAY_MAC)
411 .setEthDst(instPort.macAddress())
412 .setIpDst(instPort.ipAddress().getIp4Address());
413
Jian Li5e2ad4a2018-07-16 13:40:53 +0900414 if (!externalPeerRouter.vlanId().equals(VlanId.NONE)) {
415 externalSelectorBuilder.matchVlanId(externalPeerRouter.vlanId()).build();
Jian Lide679782018-06-05 01:41:29 +0900416 externalTreatmentBuilder.popVlan();
417 }
418
419 switch (osNet.getNetworkType()) {
420 case VXLAN:
421 externalTreatmentBuilder.setTunnelId(Long.valueOf(osNet.getProviderSegID()))
422 .extension(buildExtension(
423 deviceService,
424 selectedGatewayNode.intgBridge(),
425 cNode.dataIp().getIp4Address()),
426 selectedGatewayNode.intgBridge())
427 .setOutput(selectedGatewayNode.tunnelPortNum());
428 break;
429 case VLAN:
430 externalTreatmentBuilder.pushVlan()
431 .setVlanId(VlanId.vlanId(osNet.getProviderSegID()))
432 .setOutput(selectedGatewayNode.vlanPortNum());
433 break;
434 default:
435 final String error = String.format(ERR_UNSUPPORTED_NET_TYPE,
436 osNet.getNetworkType());
437 throw new IllegalStateException(error);
438 }
439
440 osFlowRuleService.setRule(
441 appId,
442 selectedGatewayNode.intgBridge(),
443 externalSelectorBuilder.build(),
444 externalTreatmentBuilder.build(),
445 PRIORITY_FLOATING_EXTERNAL,
446 GW_COMMON_TABLE,
447 install);
448 }
449
Hyunsun Moon44aac662017-02-18 02:07:01 +0900450 private void setUpstreamRules(NetFloatingIP floatingIp, Network osNet,
Jian Li32b03622018-11-06 17:54:24 +0900451 InstancePort instPort,
452 ExternalPeerRouter externalPeerRouter,
daniel park32b42202018-03-14 16:53:44 +0900453 boolean install) {
Hyunsun Moon44aac662017-02-18 02:07:01 +0900454 IpAddress floating = IpAddress.valueOf(floatingIp.getFloatingIpAddress());
daniel parkee8700b2017-05-11 15:50:03 +0900455 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder()
Hyunsun Moon44aac662017-02-18 02:07:01 +0900456 .matchEthType(Ethernet.TYPE_IPV4)
daniel parkee8700b2017-05-11 15:50:03 +0900457 .matchIPSrc(instPort.ipAddress().toIpPrefix());
458
459 switch (osNet.getNetworkType()) {
460 case VXLAN:
461 sBuilder.matchTunnelId(Long.valueOf(osNet.getProviderSegID()));
462 break;
463 case VLAN:
464 sBuilder.matchVlanId(VlanId.vlanId(osNet.getProviderSegID()));
465 break;
466 default:
Ray Milkeyc6c9b172018-02-26 09:36:31 -0800467 final String error = String.format(ERR_UNSUPPORTED_NET_TYPE,
Hyunsun Moon0d457362017-06-27 17:19:41 +0900468 osNet.getNetworkType());
daniel parkee8700b2017-05-11 15:50:03 +0900469 throw new IllegalStateException(error);
470 }
Hyunsun Moon44aac662017-02-18 02:07:01 +0900471
Daniel Park75e3d7f2018-05-29 14:43:53 +0900472 TrafficSelector selector = sBuilder.build();
daniel parkeeb8e042018-02-21 14:06:58 +0900473
Hyunsun Moon0d457362017-06-27 17:19:41 +0900474 osNodeService.completeNodes(GATEWAY).forEach(gNode -> {
Daniel Park75e3d7f2018-05-29 14:43:53 +0900475 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder()
476 .setIpSrc(floating.getIp4Address())
477 .setEthSrc(instPort.macAddress())
Jian Li5e2ad4a2018-07-16 13:40:53 +0900478 .setEthDst(externalPeerRouter.macAddress());
Hyunsun Moon44aac662017-02-18 02:07:01 +0900479
Daniel Park75e3d7f2018-05-29 14:43:53 +0900480 if (osNet.getNetworkType().equals(NetworkType.VLAN)) {
481 tBuilder.popVlan();
482 }
483
Jian Li5e2ad4a2018-07-16 13:40:53 +0900484 if (!externalPeerRouter.vlanId().equals(VlanId.NONE)) {
485 tBuilder.pushVlan().setVlanId(externalPeerRouter.vlanId());
Daniel Park75e3d7f2018-05-29 14:43:53 +0900486 }
sanghodc375372017-06-08 10:41:30 +0900487 osFlowRuleService.setRule(
Hyunsun Moon44aac662017-02-18 02:07:01 +0900488 appId,
Hyunsun Moon0d457362017-06-27 17:19:41 +0900489 gNode.intgBridge(),
Daniel Park75e3d7f2018-05-29 14:43:53 +0900490 selector,
daniel parkeeb8e042018-02-21 14:06:58 +0900491 tBuilder.setOutput(gNode.uplinkPortNum()).build(),
Hyunsun Moon44aac662017-02-18 02:07:01 +0900492 PRIORITY_FLOATING_EXTERNAL,
sanghodc375372017-06-08 10:41:30 +0900493 GW_COMMON_TABLE,
Hyunsun Moon44aac662017-02-18 02:07:01 +0900494 install);
Daniel Park75e3d7f2018-05-29 14:43:53 +0900495 });
daniel parkc2a2ed62018-04-10 15:17:42 +0900496 log.trace("Succeeded to set flow rules for upstream on gateway nodes");
Hyunsun Moon44aac662017-02-18 02:07:01 +0900497 }
498
Jian Li99892e92018-04-13 14:59:39 +0900499 private void associateFloatingIp(NetFloatingIP osFip) {
Jian Li628a7cb2018-08-11 23:04:24 +0900500 InstancePort instPort = instancePortService.instancePort(osFip.getPortId());
501
502 if (instPort == null) {
503 log.warn("Failed to insert floating IP rule for {} due to missing of port info.",
504 osFip.getFloatingIpAddress());
505 return;
Jian Li99892e92018-04-13 14:59:39 +0900506 }
Jian Li628a7cb2018-08-11 23:04:24 +0900507
Jian Li99892e92018-04-13 14:59:39 +0900508 // set floating IP rules only if the port is associated to a VM
Jian Li628a7cb2018-08-11 23:04:24 +0900509 if (!Strings.isNullOrEmpty(instPort.deviceId().toString())) {
510 setFloatingIpRules(osFip, instPort, null, true);
Daniel Park4fa1f5e2018-10-17 12:41:52 +0900511 processGratuitousArpPacket(osFip, instPort);
512
Jian Li99892e92018-04-13 14:59:39 +0900513 }
514 }
515
Daniel Park4fa1f5e2018-10-17 12:41:52 +0900516 private void processGratuitousArpPacket(NetFloatingIP floatingIP,
517 InstancePort instancePort) {
518 Set<OpenstackNode> gws = ImmutableSet.copyOf(osNodeService.completeNodes(GATEWAY));
519
520 Network osNet = osNetworkService.network(instancePort.networkId());
521
522
523 OpenstackNode selectedGw = getGwByInstancePort(gws, instancePort);
524 ExternalPeerRouter externalPeerRouter =
525 externalPeerRouterForNetwork(osNet, osNetworkService, osRouterAdminService);
526 if (externalPeerRouter == null) {
Jian Li32b03622018-11-06 17:54:24 +0900527 log.error("Failed to process GARP packet for floating ip {} " +
528 "because no external peer router found");
Daniel Park4fa1f5e2018-10-17 12:41:52 +0900529 return;
530 }
531
Jian Li32b03622018-11-06 17:54:24 +0900532 processGarpPacketForFloatingIp(floatingIP, instancePort,
533 externalPeerRouter.vlanId(), selectedGw, packetService);
Daniel Park4fa1f5e2018-10-17 12:41:52 +0900534
535 }
536
Jian Li99892e92018-04-13 14:59:39 +0900537 private void disassociateFloatingIp(NetFloatingIP osFip, String portId) {
Jian Li628a7cb2018-08-11 23:04:24 +0900538 InstancePort instPort = instancePortService.instancePort(portId);
Jian Lie1a39032018-06-19 21:49:36 +0900539
Jian Li628a7cb2018-08-11 23:04:24 +0900540 if (instPort == null) {
541 log.warn("Failed to remove floating IP rule for {} due to missing of port info.",
542 osFip.getFloatingIpAddress());
543 return;
Jian Lie1a39032018-06-19 21:49:36 +0900544 }
545
Jian Li99892e92018-04-13 14:59:39 +0900546 // set floating IP rules only if the port is associated to a VM
Jian Li628a7cb2018-08-11 23:04:24 +0900547 if (!Strings.isNullOrEmpty(instPort.deviceId().toString())) {
548 setFloatingIpRules(osFip, instPort, null, false);
Jian Li99892e92018-04-13 14:59:39 +0900549 }
550 }
551
Hyunsun Moon0d457362017-06-27 17:19:41 +0900552 private class InternalFloatingIpListener implements OpenstackRouterListener {
Hyunsun Moon44aac662017-02-18 02:07:01 +0900553
554 @Override
555 public boolean isRelevant(OpenstackRouterEvent event) {
Hyunsun Moon44aac662017-02-18 02:07:01 +0900556 return event.floatingIp() != null;
557 }
558
Jian Li34220ea2018-11-14 01:30:24 +0900559 private boolean isRelevantHelper() {
560 return Objects.equals(localNodeId, leadershipService.getLeader(appId.name()));
561 }
562
Hyunsun Moon44aac662017-02-18 02:07:01 +0900563 @Override
564 public void event(OpenstackRouterEvent event) {
565 switch (event.type()) {
566 case OPENSTACK_FLOATING_IP_ASSOCIATED:
Hyunsun Moon7a5f9042017-05-11 18:19:01 +0900567 eventExecutor.execute(() -> {
Jian Li34220ea2018-11-14 01:30:24 +0900568
569 if (!isRelevantHelper()) {
570 return;
571 }
572
Hyunsun Moonb720e632017-05-16 15:41:36 +0900573 NetFloatingIP osFip = event.floatingIp();
Jian Li0488c732018-09-14 20:53:07 +0900574 if (instancePortService.instancePort(osFip.getPortId()) != null) {
575 associateFloatingIp(osFip);
576 log.info("Associated floating IP {}:{}",
577 osFip.getFloatingIpAddress(),
578 osFip.getFixedIpAddress());
579 }
Hyunsun Moon7a5f9042017-05-11 18:19:01 +0900580 });
581 break;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900582 case OPENSTACK_FLOATING_IP_DISASSOCIATED:
583 eventExecutor.execute(() -> {
Jian Li34220ea2018-11-14 01:30:24 +0900584
585 if (!isRelevantHelper()) {
586 return;
587 }
588
Hyunsun Moonb720e632017-05-16 15:41:36 +0900589 NetFloatingIP osFip = event.floatingIp();
Jian Li0488c732018-09-14 20:53:07 +0900590 if (instancePortService.instancePort(event.portId()) != null) {
591 disassociateFloatingIp(osFip, event.portId());
592 log.info("Disassociated floating IP {}:{}",
593 osFip.getFloatingIpAddress(),
594 osFip.getFixedIpAddress());
595 }
Hyunsun Moon7a5f9042017-05-11 18:19:01 +0900596 });
597 break;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900598 case OPENSTACK_FLOATING_IP_CREATED:
Hyunsun Moonb720e632017-05-16 15:41:36 +0900599 eventExecutor.execute(() -> {
Jian Li34220ea2018-11-14 01:30:24 +0900600
601 if (!isRelevantHelper()) {
602 return;
603 }
604
Hyunsun Moonb720e632017-05-16 15:41:36 +0900605 NetFloatingIP osFip = event.floatingIp();
Jian Li0488c732018-09-14 20:53:07 +0900606 String portId = osFip.getPortId();
607 if (!Strings.isNullOrEmpty(portId) &&
608 instancePortService.instancePort(portId) != null) {
Hyunsun Moonb720e632017-05-16 15:41:36 +0900609 associateFloatingIp(event.floatingIp());
610 }
611 log.info("Created floating IP {}", osFip.getFloatingIpAddress());
612 });
613 break;
Jian Lia171a432018-06-11 11:52:11 +0900614 case OPENSTACK_FLOATING_IP_REMOVED:
615 eventExecutor.execute(() -> {
Jian Li34220ea2018-11-14 01:30:24 +0900616
617 if (!isRelevantHelper()) {
618 return;
619 }
620
Jian Lia171a432018-06-11 11:52:11 +0900621 NetFloatingIP osFip = event.floatingIp();
Jian Li0488c732018-09-14 20:53:07 +0900622 String portId = osFip.getPortId();
Jian Lia171a432018-06-11 11:52:11 +0900623 if (!Strings.isNullOrEmpty(osFip.getPortId())) {
Jian Lic2403592018-07-18 12:56:45 +0900624 // in case the floating IP is not associated with any port due to
625 // port removal, we simply do not execute floating IP disassociation
Jian Li0488c732018-09-14 20:53:07 +0900626 if (osNetworkService.port(portId) != null &&
627 instancePortService.instancePort(portId) != null) {
628 disassociateFloatingIp(osFip, portId);
Jian Lic2403592018-07-18 12:56:45 +0900629 }
Jian Lida03ce92018-07-24 21:41:53 +0900630
631 // since we skip floating IP disassociation, we need to
632 // manually unsubscribe the port pre-remove event
633 preCommitPortService.unsubscribePreCommit(osFip.getPortId(),
Jian Li628a7cb2018-08-11 23:04:24 +0900634 OPENSTACK_PORT_PRE_REMOVE, instancePortService,
635 this.getClass().getName());
Jian Li32b03622018-11-06 17:54:24 +0900636 log.info("Unsubscribed the port {} on listening pre-remove event",
637 osFip.getPortId());
Jian Lia171a432018-06-11 11:52:11 +0900638 }
639 log.info("Removed floating IP {}", osFip.getFloatingIpAddress());
640 });
641 break;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900642 case OPENSTACK_FLOATING_IP_UPDATED:
Hyunsun Moon44aac662017-02-18 02:07:01 +0900643 case OPENSTACK_ROUTER_CREATED:
644 case OPENSTACK_ROUTER_UPDATED:
645 case OPENSTACK_ROUTER_REMOVED:
646 case OPENSTACK_ROUTER_INTERFACE_ADDED:
647 case OPENSTACK_ROUTER_INTERFACE_UPDATED:
648 case OPENSTACK_ROUTER_INTERFACE_REMOVED:
649 default:
650 // do nothing for the other events
651 break;
652 }
653 }
654 }
655
656 private class InternalNodeListener implements OpenstackNodeListener {
657
658 @Override
659 public boolean isRelevant(OpenstackNodeEvent event) {
Hyunsun Moon44aac662017-02-18 02:07:01 +0900660 return event.subject().type() == GATEWAY;
661 }
662
Jian Li34220ea2018-11-14 01:30:24 +0900663 private boolean isRelevantHelper() {
664 return Objects.equals(localNodeId, leadershipService.getLeader(appId.name()));
665 }
666
Hyunsun Moon44aac662017-02-18 02:07:01 +0900667 @Override
668 public void event(OpenstackNodeEvent event) {
Hyunsun Moon44aac662017-02-18 02:07:01 +0900669
670 switch (event.type()) {
Hyunsun Moon0d457362017-06-27 17:19:41 +0900671 case OPENSTACK_NODE_COMPLETE:
Hyunsun Moon44aac662017-02-18 02:07:01 +0900672 eventExecutor.execute(() -> {
Jian Li34220ea2018-11-14 01:30:24 +0900673
674 if (!isRelevantHelper()) {
675 return;
676 }
677
Jian Lif3a28b02018-06-11 21:29:13 +0900678 for (NetFloatingIP fip : osRouterAdminService.floatingIps()) {
Jian Lie1a39032018-06-19 21:49:36 +0900679
Hyunsun Moon7a5f9042017-05-11 18:19:01 +0900680 if (Strings.isNullOrEmpty(fip.getPortId())) {
681 continue;
682 }
Jian Lie1a39032018-06-19 21:49:36 +0900683
Hyunsun Moon7a5f9042017-05-11 18:19:01 +0900684 Port osPort = osNetworkService.port(fip.getPortId());
Jian Li628a7cb2018-08-11 23:04:24 +0900685 InstancePort instPort = instancePortService.instancePort(fip.getPortId());
686
687 // we check both Openstack Port and Instance Port
688 if (osPort == null || instPort == null) {
Hyunsun Moon7a5f9042017-05-11 18:19:01 +0900689 continue;
690 }
Jian Lie1a39032018-06-19 21:49:36 +0900691
Jian Li628a7cb2018-08-11 23:04:24 +0900692 setFloatingIpRules(fip, instPort, event.subject(), true);
Hyunsun Moon7a5f9042017-05-11 18:19:01 +0900693 }
Hyunsun Moon44aac662017-02-18 02:07:01 +0900694 });
695 break;
Hyunsun Moon0d457362017-06-27 17:19:41 +0900696 case OPENSTACK_NODE_INCOMPLETE:
Jian Li1064e4f2018-05-29 16:16:53 +0900697 eventExecutor.execute(() -> {
Jian Li34220ea2018-11-14 01:30:24 +0900698
699 if (!isRelevantHelper()) {
700 return;
701 }
702
Jian Lif3a28b02018-06-11 21:29:13 +0900703 for (NetFloatingIP fip : osRouterAdminService.floatingIps()) {
Jian Li1064e4f2018-05-29 16:16:53 +0900704 if (Strings.isNullOrEmpty(fip.getPortId())) {
705 continue;
706 }
707 Port osPort = osNetworkService.port(fip.getPortId());
708 if (osPort == null) {
709 log.warn("Failed to set floating IP {}", fip.getId());
710 continue;
711 }
712 Network osNet = osNetworkService.network(osPort.getNetworkId());
713 if (osNet == null) {
714 final String errorFormat = ERR_FLOW + "no network(%s) exists";
715 final String error = String.format(errorFormat,
716 fip.getFloatingIpAddress(),
717 osPort.getNetworkId());
718 throw new IllegalStateException(error);
719 }
720 MacAddress srcMac = MacAddress.valueOf(osPort.getMacAddress());
721 log.trace("Mac address of openstack port: {}", srcMac);
722 InstancePort instPort = instancePortService.instancePort(srcMac);
723
724 if (instPort == null) {
725 final String errorFormat = ERR_FLOW + "no host(MAC:%s) found";
726 final String error = String.format(errorFormat,
727 fip.getFloatingIpAddress(), srcMac);
728 throw new IllegalStateException(error);
729 }
730
Daniel Park4fa1f5e2018-10-17 12:41:52 +0900731 ExternalPeerRouter externalPeerRouter = externalPeerRouterForNetwork(osNet,
732 osNetworkService, osRouterAdminService);
Jian Lide679782018-06-05 01:41:29 +0900733 if (externalPeerRouter == null) {
734 final String errorFormat = ERR_FLOW + "no external peer router found";
735 throw new IllegalStateException(errorFormat);
736 }
737
738 updateComputeNodeRules(instPort, osNet, event.subject(), false);
739 updateGatewayNodeRules(fip, instPort, osNet,
740 externalPeerRouter, event.subject(), false);
Jian Li1064e4f2018-05-29 16:16:53 +0900741 }
742 });
743 break;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900744 default:
Hyunsun Moon0d457362017-06-27 17:19:41 +0900745 // do nothing
Hyunsun Moon44aac662017-02-18 02:07:01 +0900746 break;
747 }
748 }
749 }
Jian Li99892e92018-04-13 14:59:39 +0900750
Jian Li24ec59f2018-05-23 19:01:25 +0900751 private class InternalInstancePortListener implements InstancePortListener {
752
Jian Li34220ea2018-11-14 01:30:24 +0900753 private boolean isRelevantHelper(InstancePortEvent event) {
Jian Li24ec59f2018-05-23 19:01:25 +0900754
Jian Lie1a39032018-06-19 21:49:36 +0900755 if (event.type() == OPENSTACK_INSTANCE_MIGRATION_ENDED ||
756 event.type() == OPENSTACK_INSTANCE_MIGRATION_STARTED) {
757 Set<NetFloatingIP> ips = osRouterAdminService.floatingIps();
758 NetFloatingIP fip = associatedFloatingIp(event.subject(), ips);
759
760 // we check the possible NPE to avoid duplicated null check
761 // for OPENSTACK_INSTANCE_MIGRATION_ENDED and
762 // OPENSTACK_INSTANCE_MIGRATION_STARTED cases
763 if (fip == null || !isAssociatedWithVM(osNetworkService, fip)) {
764 return false;
765 }
766 }
767
Jian Li34220ea2018-11-14 01:30:24 +0900768 return Objects.equals(localNodeId, leadershipService.getLeader(appId.name()));
Jian Li24ec59f2018-05-23 19:01:25 +0900769 }
770
771 @Override
772 public void event(InstancePortEvent event) {
Jian Lie1a39032018-06-19 21:49:36 +0900773 InstancePort instPort = event.subject();
Jian Li24ec59f2018-05-23 19:01:25 +0900774
775 switch (event.type()) {
Jian Lie1a39032018-06-19 21:49:36 +0900776 case OPENSTACK_INSTANCE_PORT_DETECTED:
Jian Lie1a39032018-06-19 21:49:36 +0900777
Jian Li32b03622018-11-06 17:54:24 +0900778 eventExecutor.execute(() -> {
Jian Li34220ea2018-11-14 01:30:24 +0900779
780 if (!isRelevantHelper(event)) {
781 return;
782 }
783
Jian Li32b03622018-11-06 17:54:24 +0900784 if (instPort != null && instPort.portId() != null) {
785 osRouterAdminService.floatingIps().stream()
786 .filter(f -> f.getPortId() != null)
787 .filter(f -> f.getPortId().equals(instPort.portId()))
788 .forEach(f -> setFloatingIpRules(f,
789 instPort, null, true));
790 }
791 });
Jian Lie1a39032018-06-19 21:49:36 +0900792 break;
793
Jian Li24ec59f2018-05-23 19:01:25 +0900794 case OPENSTACK_INSTANCE_MIGRATION_STARTED:
Jian Lie1a39032018-06-19 21:49:36 +0900795
Jian Li24ec59f2018-05-23 19:01:25 +0900796 eventExecutor.execute(() -> {
797
Jian Li34220ea2018-11-14 01:30:24 +0900798 if (!isRelevantHelper(event)) {
799 return;
800 }
801
802 Set<OpenstackNode> gateways = osNodeService.completeNodes(GATEWAY);
803 Set<NetFloatingIP> ips = osRouterAdminService.floatingIps();
804 NetFloatingIP fip = associatedFloatingIp(event.subject(), ips);
805
806 if (fip == null) {
807 return;
808 }
809
810 Port osPort = osNetworkService.port(fip.getPortId());
811 Network osNet = osNetworkService.network(osPort.getNetworkId());
812 ExternalPeerRouter externalPeerRouter = externalPeerRouterForNetwork(osNet,
813 osNetworkService, osRouterAdminService);
814
815 if (externalPeerRouter == null) {
816 final String errorFormat = ERR_FLOW + "no external peer router found";
817 throw new IllegalStateException(errorFormat);
818 }
819
Jian Li24ec59f2018-05-23 19:01:25 +0900820 // since DownstreamExternal rules should only be placed in
821 // corresponding gateway node, we need to install new rule to
822 // the corresponding gateway node
823 setDownstreamExternalRulesHelper(fip, osNet,
824 event.subject(), externalPeerRouter, gateways, true);
825
826 // since ComputeNodeToGateway rules should only be placed in
827 // corresponding compute node, we need to install new rule to
828 // the target compute node, and remove rules from original node
829 setComputeNodeToGatewayHelper(event.subject(), osNet, gateways, true);
Jian Li24ec59f2018-05-23 19:01:25 +0900830 });
831 break;
832 case OPENSTACK_INSTANCE_MIGRATION_ENDED:
833
Jian Li9e287772018-10-26 09:41:18 +0900834 eventExecutor.execute(() -> {
Jian Li34220ea2018-11-14 01:30:24 +0900835
836 if (!isRelevantHelper(event)) {
837 return;
838 }
839
840 InstancePort oldInstPort = swapStaleLocation(event.subject());
841
842 Set<NetFloatingIP> ips = osRouterAdminService.floatingIps();
843 NetFloatingIP fip = associatedFloatingIp(oldInstPort, ips);
844
845 if (fip == null) {
846 return;
847 }
848
849 Set<OpenstackNode> gateways = osNodeService.completeNodes(GATEWAY);
850 Port osPort = osNetworkService.port(fip.getPortId());
851 Network osNet = osNetworkService.network(osPort.getNetworkId());
852 ExternalPeerRouter externalPeerRouter = externalPeerRouterForNetwork(osNet,
853 osNetworkService, osRouterAdminService);
854
855 if (externalPeerRouter == null) {
856 final String errorFormat = ERR_FLOW + "no external peer router found";
857 throw new IllegalStateException(errorFormat);
858 }
859
Jian Li9e287772018-10-26 09:41:18 +0900860 // We need to remove the old ComputeNodeToGateway rules from
861 // original compute node
862 setComputeNodeToGatewayHelper(oldInstPort, osNet, gateways, false);
Jian Li9e287772018-10-26 09:41:18 +0900863
864 // If we only have one gateway, we simply do not remove any
Jian Li34220ea2018-11-14 01:30:24 +0900865 // flow rules from either gateway or compute node
866 if (gateways.size() == 1) {
867 return;
868 }
Jian Li24ec59f2018-05-23 19:01:25 +0900869
Jian Li34220ea2018-11-14 01:30:24 +0900870 // Checks whether the destination compute node's device id
871 // has identical gateway hash or not
872 // if it is true, we simply do not remove the rules, as
873 // it has been overwritten at port detention event
874 // if it is false, we will remove the rules
875 DeviceId newDeviceId = event.subject().deviceId();
876 DeviceId oldDeviceId = oldInstPort.deviceId();
Jian Li24ec59f2018-05-23 19:01:25 +0900877
Jian Li34220ea2018-11-14 01:30:24 +0900878 OpenstackNode oldGateway = getGwByComputeDevId(gateways, oldDeviceId);
879 OpenstackNode newGateway = getGwByComputeDevId(gateways, newDeviceId);
Jian Li24ec59f2018-05-23 19:01:25 +0900880
Jian Li34220ea2018-11-14 01:30:24 +0900881 if (oldGateway != null && oldGateway.equals(newGateway)) {
882 return;
883 }
Jian Li24ec59f2018-05-23 19:01:25 +0900884
Jian Lie1a39032018-06-19 21:49:36 +0900885 // Since DownstreamExternal rules should only be placed in
Jian Li24ec59f2018-05-23 19:01:25 +0900886 // corresponding gateway node, we need to remove old rule from
887 // the corresponding gateway node
Jian Li9e287772018-10-26 09:41:18 +0900888 setDownstreamExternalRulesHelper(fip, osNet, oldInstPort,
Jian Liec5c32b2018-07-13 14:28:58 +0900889 externalPeerRouter, gateways, false);
Jian Li24ec59f2018-05-23 19:01:25 +0900890 });
891 break;
892 default:
893 break;
894 }
895 }
896 }
Jian Lie1a39032018-06-19 21:49:36 +0900897
898 private class InternalOpenstackNetworkListener implements OpenstackNetworkListener {
899
Jian Li34220ea2018-11-14 01:30:24 +0900900 private boolean isRelevantHelper() {
901 return Objects.equals(localNodeId, leadershipService.getLeader(appId.name()));
Jian Lie1a39032018-06-19 21:49:36 +0900902 }
903
904 @Override
905 public void event(OpenstackNetworkEvent event) {
906 switch (event.type()) {
Jian Li8f64feb2018-07-24 13:20:16 +0900907 case OPENSTACK_PORT_PRE_REMOVE:
Jian Li34220ea2018-11-14 01:30:24 +0900908 eventExecutor.execute(() -> {
909
910 if (!isRelevantHelper()) {
911 return;
912 }
913
914 processPortPreRemove(event);
915 });
Jian Li8f64feb2018-07-24 13:20:16 +0900916 break;
Jian Lie1a39032018-06-19 21:49:36 +0900917 default:
918 break;
919 }
920 }
921
Jian Li32b03622018-11-06 17:54:24 +0900922 private void processPortPreRemove(OpenstackNetworkEvent event) {
923 InstancePort instPort = instancePortService.instancePort(
924 event.port().getId());
925 if (instPort == null) {
926 return;
927 }
928 NetFloatingIP fip = associatedFloatingIp(instPort,
929 osRouterAdminService.floatingIps());
930
931 if (fip != null) {
932 instancePortService.updateInstancePort(
933 instPort.updateState(REMOVE_PENDING));
934 updateFipStore(event.port().getId());
935 } else {
936 instancePortService.removeInstancePort(instPort.portId());
937 }
938 }
939
Jian Li2360acb2018-10-17 00:46:31 +0900940 private void updateFipStore(String portId) {
Jian Lie1a39032018-06-19 21:49:36 +0900941
Jian Li2360acb2018-10-17 00:46:31 +0900942 if (portId == null) {
Jian Lie1a39032018-06-19 21:49:36 +0900943 return;
944 }
945
946 Set<NetFloatingIP> ips = osRouterAdminService.floatingIps();
947 for (NetFloatingIP fip : ips) {
948 if (Strings.isNullOrEmpty(fip.getFixedIpAddress())) {
949 continue;
950 }
951 if (Strings.isNullOrEmpty(fip.getFloatingIpAddress())) {
952 continue;
953 }
Jian Li2360acb2018-10-17 00:46:31 +0900954 if (fip.getPortId().equals(portId)) {
Jian Lie1a39032018-06-19 21:49:36 +0900955 NeutronFloatingIP neutronFip = (NeutronFloatingIP) fip;
956 // invalidate bound fixed IP and port
957 neutronFip.setFixedIpAddress(null);
958 neutronFip.setPortId(null);
Jian Lie1a39032018-06-19 21:49:36 +0900959
960 // Following update will in turn trigger
961 // OPENSTACK_FLOATING_IP_DISASSOCIATED event
962 osRouterAdminService.updateFloatingIp(neutronFip);
963 log.info("Updated floating IP {}, due to host removal",
964 neutronFip.getFloatingIpAddress());
965 }
966 }
967 }
968 }
Hyunsun Moon44aac662017-02-18 02:07:01 +0900969}