blob: 73e9f19b7bd77c421c3ea3547cab42f19d9c525d [file] [log] [blame]
Hyunsun Moon44aac662017-02-18 02:07:01 +09001/*
Brian O'Connora09fe5b2017-08-03 21:12:30 -07002 * Copyright 2016-present Open Networking Foundation
Hyunsun Moon44aac662017-02-18 02:07:01 +09003 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16package org.onosproject.openstacknetworking.impl;
17
18import com.google.common.base.Strings;
Jian Li1064e4f2018-05-29 16:16:53 +090019import com.google.common.collect.ImmutableSet;
Jian Li1064e4f2018-05-29 16:16:53 +090020import com.google.common.collect.Sets;
Hyunsun Moon44aac662017-02-18 02:07:01 +090021import org.apache.felix.scr.annotations.Activate;
22import org.apache.felix.scr.annotations.Component;
23import org.apache.felix.scr.annotations.Deactivate;
24import org.apache.felix.scr.annotations.Reference;
25import org.apache.felix.scr.annotations.ReferenceCardinality;
26import org.onlab.packet.Ethernet;
27import org.onlab.packet.IpAddress;
28import org.onlab.packet.MacAddress;
daniel parkee8700b2017-05-11 15:50:03 +090029import org.onlab.packet.VlanId;
Hyunsun Moon44aac662017-02-18 02:07:01 +090030import org.onosproject.cluster.ClusterService;
31import org.onosproject.cluster.LeadershipService;
32import org.onosproject.cluster.NodeId;
33import org.onosproject.core.ApplicationId;
34import org.onosproject.core.CoreService;
Jian Li24ec59f2018-05-23 19:01:25 +090035import org.onosproject.net.DeviceId;
Hyunsun Moon44aac662017-02-18 02:07:01 +090036import org.onosproject.net.PortNumber;
37import org.onosproject.net.device.DeviceService;
38import org.onosproject.net.flow.DefaultTrafficSelector;
39import org.onosproject.net.flow.DefaultTrafficTreatment;
40import org.onosproject.net.flow.TrafficSelector;
41import org.onosproject.net.flow.TrafficTreatment;
Hyunsun Moon44aac662017-02-18 02:07:01 +090042import org.onosproject.openstacknetworking.api.Constants;
daniel park32b42202018-03-14 16:53:44 +090043import org.onosproject.openstacknetworking.api.ExternalPeerRouter;
Hyunsun Moon44aac662017-02-18 02:07:01 +090044import org.onosproject.openstacknetworking.api.InstancePort;
Jian Liec5c32b2018-07-13 14:28:58 +090045import org.onosproject.openstacknetworking.api.InstancePortAdminService;
Jian Li24ec59f2018-05-23 19:01:25 +090046import org.onosproject.openstacknetworking.api.InstancePortEvent;
47import org.onosproject.openstacknetworking.api.InstancePortListener;
sanghodc375372017-06-08 10:41:30 +090048import org.onosproject.openstacknetworking.api.OpenstackFlowRuleService;
Jian Lie1a39032018-06-19 21:49:36 +090049import org.onosproject.openstacknetworking.api.OpenstackNetworkEvent;
50import org.onosproject.openstacknetworking.api.OpenstackNetworkListener;
sanghodc375372017-06-08 10:41:30 +090051import org.onosproject.openstacknetworking.api.OpenstackNetworkService;
Jian Lif3a28b02018-06-11 21:29:13 +090052import org.onosproject.openstacknetworking.api.OpenstackRouterAdminService;
Hyunsun Moon44aac662017-02-18 02:07:01 +090053import org.onosproject.openstacknetworking.api.OpenstackRouterEvent;
54import org.onosproject.openstacknetworking.api.OpenstackRouterListener;
Jian Li8f64feb2018-07-24 13:20:16 +090055import org.onosproject.openstacknetworking.api.PreCommitPortService;
Hyunsun Moon0d457362017-06-27 17:19:41 +090056import org.onosproject.openstacknode.api.OpenstackNode;
57import org.onosproject.openstacknode.api.OpenstackNodeEvent;
58import org.onosproject.openstacknode.api.OpenstackNodeListener;
59import org.onosproject.openstacknode.api.OpenstackNodeService;
daniel parkeeb8e042018-02-21 14:06:58 +090060import org.openstack4j.model.network.ExternalGateway;
Hyunsun Moon44aac662017-02-18 02:07:01 +090061import org.openstack4j.model.network.NetFloatingIP;
62import org.openstack4j.model.network.Network;
daniel parkee8700b2017-05-11 15:50:03 +090063import org.openstack4j.model.network.NetworkType;
Hyunsun Moon44aac662017-02-18 02:07:01 +090064import org.openstack4j.model.network.Port;
daniel parkeeb8e042018-02-21 14:06:58 +090065import org.openstack4j.model.network.Router;
66import org.openstack4j.model.network.RouterInterface;
67import org.openstack4j.model.network.Subnet;
Jian Lif3a28b02018-06-11 21:29:13 +090068import org.openstack4j.openstack.networking.domain.NeutronFloatingIP;
Hyunsun Moon44aac662017-02-18 02:07:01 +090069import org.slf4j.Logger;
70import org.slf4j.LoggerFactory;
71
72import java.util.Objects;
Jian Li99892e92018-04-13 14:59:39 +090073import java.util.Set;
Hyunsun Moon44aac662017-02-18 02:07:01 +090074import java.util.concurrent.ExecutorService;
75
76import static java.util.concurrent.Executors.newSingleThreadExecutor;
77import static org.onlab.util.Tools.groupedThreads;
sanghodc375372017-06-08 10:41:30 +090078import static org.onosproject.openstacknetworking.api.Constants.GW_COMMON_TABLE;
79import static org.onosproject.openstacknetworking.api.Constants.OPENSTACK_NETWORKING_APP_ID;
daniel parkeeb8e042018-02-21 14:06:58 +090080import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_EXTERNAL_FLOATING_ROUTING_RULE;
sanghodc375372017-06-08 10:41:30 +090081import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_FLOATING_EXTERNAL;
82import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_FLOATING_INTERNAL;
daniel parkeeb8e042018-02-21 14:06:58 +090083import static org.onosproject.openstacknetworking.api.Constants.ROUTING_TABLE;
Jian Lie1a39032018-06-19 21:49:36 +090084import static org.onosproject.openstacknetworking.api.InstancePortEvent.Type.OPENSTACK_INSTANCE_MIGRATION_ENDED;
85import static org.onosproject.openstacknetworking.api.InstancePortEvent.Type.OPENSTACK_INSTANCE_MIGRATION_STARTED;
Jian Li8f64feb2018-07-24 13:20:16 +090086import static org.onosproject.openstacknetworking.api.OpenstackNetworkEvent.Type.OPENSTACK_PORT_PRE_REMOVE;
Jian Li24ec59f2018-05-23 19:01:25 +090087import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.associatedFloatingIp;
Jian Li1064e4f2018-05-29 16:16:53 +090088import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.getGwByComputeDevId;
Jian Li24ec59f2018-05-23 19:01:25 +090089import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.isAssociatedWithVM;
Jian Liec5c32b2018-07-13 14:28:58 +090090import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.swapStaleLocation;
Jian Li26949762018-03-30 15:46:37 +090091import static org.onosproject.openstacknetworking.util.RulePopulatorUtil.buildExtension;
Hyunsun Moon0d457362017-06-27 17:19:41 +090092import static org.onosproject.openstacknode.api.OpenstackNode.NodeType.GATEWAY;
Jian Lic2403592018-07-18 12:56:45 +090093import static org.openstack4j.model.network.NetworkType.FLAT;
Hyunsun Moon44aac662017-02-18 02:07:01 +090094
95/**
96 * Handles OpenStack floating IP events.
97 */
98@Component(immediate = true)
99public class OpenstackRoutingFloatingIpHandler {
100
101 private final Logger log = LoggerFactory.getLogger(getClass());
102
103 private static final String ERR_FLOW = "Failed set flows for floating IP %s: ";
Ray Milkeyc6c9b172018-02-26 09:36:31 -0800104 private static final String ERR_UNSUPPORTED_NET_TYPE = "Unsupported network type %s";
Hyunsun Moon44aac662017-02-18 02:07:01 +0900105
106 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
107 protected CoreService coreService;
108
109 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
110 protected DeviceService deviceService;
111
112 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Hyunsun Moon44aac662017-02-18 02:07:01 +0900113 protected LeadershipService leadershipService;
114
115 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
116 protected ClusterService clusterService;
117
118 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
119 protected OpenstackNodeService osNodeService;
120
121 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Jian Liec5c32b2018-07-13 14:28:58 +0900122 protected InstancePortAdminService instancePortService;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900123
124 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Jian Lif3a28b02018-06-11 21:29:13 +0900125 protected OpenstackRouterAdminService osRouterAdminService;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900126
127 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
128 protected OpenstackNetworkService osNetworkService;
129
sanghodc375372017-06-08 10:41:30 +0900130 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
131 protected OpenstackFlowRuleService osFlowRuleService;
132
Jian Li8f64feb2018-07-24 13:20:16 +0900133 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
134 protected PreCommitPortService preCommitPortService;
135
Hyunsun Moon44aac662017-02-18 02:07:01 +0900136 private final ExecutorService eventExecutor = newSingleThreadExecutor(
137 groupedThreads(this.getClass().getSimpleName(), "event-handler", log));
Jian Li24ec59f2018-05-23 19:01:25 +0900138 private final OpenstackRouterListener floatingIpListener = new InternalFloatingIpListener();
139 private final InstancePortListener instancePortListener = new InternalInstancePortListener();
Hyunsun Moon44aac662017-02-18 02:07:01 +0900140 private final OpenstackNodeListener osNodeListener = new InternalNodeListener();
Jian Lie1a39032018-06-19 21:49:36 +0900141 private final OpenstackNetworkListener osNetworkListener = new InternalOpenstackNetworkListener();
142 private final InstancePortListener instPortListener = new InternalInstancePortListener();
143
Hyunsun Moon44aac662017-02-18 02:07:01 +0900144 private ApplicationId appId;
145 private NodeId localNodeId;
146
147 @Activate
148 protected void activate() {
149 appId = coreService.registerApplication(OPENSTACK_NETWORKING_APP_ID);
150 localNodeId = clusterService.getLocalNode().id();
151 leadershipService.runForLeadership(appId.name());
Jian Li24ec59f2018-05-23 19:01:25 +0900152 osRouterAdminService.addListener(floatingIpListener);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900153 osNodeService.addListener(osNodeListener);
Jian Li24ec59f2018-05-23 19:01:25 +0900154 instancePortService.addListener(instancePortListener);
Jian Lie1a39032018-06-19 21:49:36 +0900155 osNodeService.addListener(osNodeListener);
156 osNetworkService.addListener(osNetworkListener);
157 instancePortService.addListener(instPortListener);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900158
159 log.info("Started");
160 }
161
162 @Deactivate
163 protected void deactivate() {
Jian Li24ec59f2018-05-23 19:01:25 +0900164 instancePortService.removeListener(instancePortListener);
Jian Lie1a39032018-06-19 21:49:36 +0900165 instancePortService.removeListener(instPortListener);
166 osNetworkService.removeListener(osNetworkListener);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900167 osNodeService.removeListener(osNodeListener);
Jian Li24ec59f2018-05-23 19:01:25 +0900168 osRouterAdminService.removeListener(floatingIpListener);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900169 leadershipService.withdraw(appId.name());
170 eventExecutor.shutdown();
171
172 log.info("Stopped");
173 }
174
Hyunsun Moon44aac662017-02-18 02:07:01 +0900175 private void setFloatingIpRules(NetFloatingIP floatingIp, Port osPort,
Jian Li1064e4f2018-05-29 16:16:53 +0900176 OpenstackNode gateway, boolean install) {
Hyunsun Moon44aac662017-02-18 02:07:01 +0900177 Network osNet = osNetworkService.network(osPort.getNetworkId());
Jian Li8f64feb2018-07-24 13:20:16 +0900178
Hyunsun Moon44aac662017-02-18 02:07:01 +0900179 if (osNet == null) {
Jian Li71670d12018-03-02 21:31:07 +0900180 final String errorFormat = ERR_FLOW + "no network(%s) exists";
181 final String error = String.format(errorFormat,
Hyunsun Moon44aac662017-02-18 02:07:01 +0900182 floatingIp.getFloatingIpAddress(),
183 osPort.getNetworkId());
184 throw new IllegalStateException(error);
185 }
186
187 MacAddress srcMac = MacAddress.valueOf(osPort.getMacAddress());
daniel parkc2a2ed62018-04-10 15:17:42 +0900188 log.trace("Mac address of openstack port: {}", srcMac);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900189 InstancePort instPort = instancePortService.instancePort(srcMac);
Jian Li99892e92018-04-13 14:59:39 +0900190
Jian Li99892e92018-04-13 14:59:39 +0900191 if (instPort == null) {
Jian Li71670d12018-03-02 21:31:07 +0900192 final String errorFormat = ERR_FLOW + "no host(MAC:%s) found";
193 final String error = String.format(errorFormat,
Hyunsun Moon44aac662017-02-18 02:07:01 +0900194 floatingIp.getFloatingIpAddress(), srcMac);
195 throw new IllegalStateException(error);
196 }
197
daniel park32b42202018-03-14 16:53:44 +0900198 ExternalPeerRouter externalPeerRouter = externalPeerRouter(osNet);
199 if (externalPeerRouter == null) {
daniel parkc2a2ed62018-04-10 15:17:42 +0900200 final String errorFormat = ERR_FLOW + "no external peer router found";
201 throw new IllegalStateException(errorFormat);
daniel park32b42202018-03-14 16:53:44 +0900202 }
203
Jian Li8f64feb2018-07-24 13:20:16 +0900204 if (install) {
205 preCommitPortService.subscribePreCommit(osPort.getId(),
206 OPENSTACK_PORT_PRE_REMOVE, this.getClass().getName());
207 log.info("Subscribed the port pre-remove event");
208 } else {
209 preCommitPortService.unsubscribePreCommit(osPort.getId(),
210 OPENSTACK_PORT_PRE_REMOVE, this.getClass().getName());
211 log.info("Unsubscribed the port pre-remove event");
212 }
213
Jian Lide679782018-06-05 01:41:29 +0900214 updateComputeNodeRules(instPort, osNet, gateway, install);
215 updateGatewayNodeRules(floatingIp, instPort, osNet, externalPeerRouter, gateway, install);
216
217 // FIXME: downstream internal rules are still duplicated in all gateway nodes
218 // need to make the internal rules de-duplicated sooner or later
219 setDownstreamInternalRules(floatingIp, osNet, instPort, install);
220
221 // TODO: need to refactor setUpstreamRules if possible
daniel park32b42202018-03-14 16:53:44 +0900222 setUpstreamRules(floatingIp, osNet, instPort, externalPeerRouter, install);
Jian Li8f64feb2018-07-24 13:20:16 +0900223
daniel parkc2a2ed62018-04-10 15:17:42 +0900224 log.trace("Succeeded to set flow rules for floating ip {}:{} and install: {}",
225 floatingIp.getFloatingIpAddress(),
226 floatingIp.getFixedIpAddress(),
227 install);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900228 }
229
Jian Lide679782018-06-05 01:41:29 +0900230 private synchronized void updateGatewayNodeRules(NetFloatingIP fip,
231 InstancePort instPort,
232 Network osNet,
233 ExternalPeerRouter router,
234 OpenstackNode gateway,
235 boolean install) {
236
237 Set<OpenstackNode> completedGws = osNodeService.completeNodes(GATEWAY);
238 Set<OpenstackNode> finalGws = Sets.newConcurrentHashSet();
239 finalGws.addAll(ImmutableSet.copyOf(completedGws));
240
Jian Lia171a432018-06-11 11:52:11 +0900241
242 if (gateway == null) {
243 // these are floating IP related cases...
244 setDownstreamExternalRulesHelper(fip, osNet, instPort, router,
245 ImmutableSet.copyOf(finalGws), install);
246
Jian Lide679782018-06-05 01:41:29 +0900247 } else {
Jian Lia171a432018-06-11 11:52:11 +0900248 // these are openstack node related cases...
249 if (install) {
250 if (completedGws.contains(gateway)) {
251 if (completedGws.size() > 1) {
252 finalGws.remove(gateway);
253 if (fip.getPortId() != null) {
254 setDownstreamExternalRulesHelper(fip, osNet, instPort, router,
255 ImmutableSet.copyOf(finalGws), false);
256 finalGws.add(gateway);
257 }
258 }
Jian Lide679782018-06-05 01:41:29 +0900259 if (fip.getPortId() != null) {
260 setDownstreamExternalRulesHelper(fip, osNet, instPort, router,
261 ImmutableSet.copyOf(finalGws), true);
262 }
Jian Lia171a432018-06-11 11:52:11 +0900263 } else {
264 log.warn("Detected node should be included in completed gateway set");
Jian Lide679782018-06-05 01:41:29 +0900265 }
266 } else {
Jian Lia171a432018-06-11 11:52:11 +0900267 if (!completedGws.contains(gateway)) {
268 if (completedGws.size() >= 1) {
269 if (fip.getPortId() != null) {
270 setDownstreamExternalRulesHelper(fip, osNet, instPort, router,
271 ImmutableSet.copyOf(finalGws), true);
272 }
273 }
274 } else {
275 log.warn("Detected node should NOT be included in completed gateway set");
276 }
Jian Lide679782018-06-05 01:41:29 +0900277 }
278 }
279 }
280
281 private synchronized void updateComputeNodeRules(InstancePort instPort,
282 Network osNet,
283 OpenstackNode gateway,
284 boolean install) {
Jian Li1064e4f2018-05-29 16:16:53 +0900285
286 Set<OpenstackNode> completedGws = osNodeService.completeNodes(GATEWAY);
287 Set<OpenstackNode> finalGws = Sets.newConcurrentHashSet();
288 finalGws.addAll(ImmutableSet.copyOf(completedGws));
289
290 if (gateway == null) {
291 // these are floating IP related cases...
292 setComputeNodeToGatewayHelper(instPort, osNet,
293 ImmutableSet.copyOf(finalGws), install);
Jian Lide679782018-06-05 01:41:29 +0900294
Jian Li1064e4f2018-05-29 16:16:53 +0900295 } else {
296 // these are openstack node related cases...
297 if (install) {
298 if (completedGws.contains(gateway)) {
299 if (completedGws.size() > 1) {
300 finalGws.remove(gateway);
301 setComputeNodeToGatewayHelper(instPort, osNet,
302 ImmutableSet.copyOf(finalGws), false);
303 finalGws.add(gateway);
304 }
305
306 setComputeNodeToGatewayHelper(instPort, osNet,
307 ImmutableSet.copyOf(finalGws), true);
308 } else {
309 log.warn("Detected node should be included in completed gateway set");
310 }
311 } else {
312 if (!completedGws.contains(gateway)) {
313 finalGws.add(gateway);
314 setComputeNodeToGatewayHelper(instPort, osNet,
315 ImmutableSet.copyOf(finalGws), false);
316 finalGws.remove(gateway);
317 if (completedGws.size() >= 1) {
318 setComputeNodeToGatewayHelper(instPort, osNet,
319 ImmutableSet.copyOf(finalGws), true);
320 }
321 } else {
322 log.warn("Detected node should NOT be included in completed gateway set");
323 }
324 }
325 }
326 }
327
328 // a helper method
329 private void setComputeNodeToGatewayHelper(InstancePort instPort,
330 Network osNet,
331 Set<OpenstackNode> gateways,
332 boolean install) {
daniel parkeeb8e042018-02-21 14:06:58 +0900333 TrafficTreatment treatment;
334
335 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder()
336 .matchEthType(Ethernet.TYPE_IPV4)
337 .matchIPSrc(instPort.ipAddress().toIpPrefix())
338 .matchEthDst(Constants.DEFAULT_GATEWAY_MAC);
339
340 switch (osNet.getNetworkType()) {
341 case VXLAN:
342 sBuilder.matchTunnelId(Long.parseLong(osNet.getProviderSegID()));
343 break;
344 case VLAN:
345 sBuilder.matchVlanId(VlanId.vlanId(osNet.getProviderSegID()));
346 break;
347 default:
348 final String error = String.format(
Ray Milkeyc6c9b172018-02-26 09:36:31 -0800349 ERR_UNSUPPORTED_NET_TYPE,
daniel parkeeb8e042018-02-21 14:06:58 +0900350 osNet.getNetworkType().toString());
351 throw new IllegalStateException(error);
352 }
353
Jian Li1064e4f2018-05-29 16:16:53 +0900354 OpenstackNode selectedGatewayNode = getGwByComputeDevId(gateways, instPort.deviceId());
355
daniel parkeeb8e042018-02-21 14:06:58 +0900356 if (selectedGatewayNode == null) {
daniel parkc2a2ed62018-04-10 15:17:42 +0900357 final String errorFormat = ERR_FLOW + "no gateway node selected";
358 throw new IllegalStateException(errorFormat);
daniel parkeeb8e042018-02-21 14:06:58 +0900359 }
360 treatment = DefaultTrafficTreatment.builder()
361 .extension(buildExtension(
362 deviceService,
363 instPort.deviceId(),
364 selectedGatewayNode.dataIp().getIp4Address()),
365 instPort.deviceId())
366 .setOutput(osNodeService.node(instPort.deviceId()).tunnelPortNum())
367 .build();
368
369 osFlowRuleService.setRule(
370 appId,
371 instPort.deviceId(),
372 sBuilder.build(),
373 treatment,
374 PRIORITY_EXTERNAL_FLOATING_ROUTING_RULE,
375 ROUTING_TABLE,
376 install);
daniel parkc2a2ed62018-04-10 15:17:42 +0900377 log.trace("Succeeded to set flow rules from compute node to gateway on compute node");
daniel parkeeb8e042018-02-21 14:06:58 +0900378 }
379
Jian Lide679782018-06-05 01:41:29 +0900380 private void setDownstreamInternalRules(NetFloatingIP floatingIp,
381 Network osNet,
382 InstancePort instPort,
383 boolean install) {
Hyunsun Moon0d457362017-06-27 17:19:41 +0900384 OpenstackNode cNode = osNodeService.node(instPort.deviceId());
385 if (cNode == null) {
386 final String error = String.format("Cannot find openstack node for device %s",
387 instPort.deviceId());
388 throw new IllegalStateException(error);
389 }
390 if (osNet.getNetworkType() == NetworkType.VXLAN && cNode.dataIp() == null) {
Jian Li71670d12018-03-02 21:31:07 +0900391 final String errorFormat = ERR_FLOW + "VXLAN mode is not ready for %s";
392 final String error = String.format(errorFormat, floatingIp, cNode.hostname());
Hyunsun Moon0d457362017-06-27 17:19:41 +0900393 throw new IllegalStateException(error);
394 }
395 if (osNet.getNetworkType() == NetworkType.VLAN && cNode.vlanIntf() == null) {
Jian Li71670d12018-03-02 21:31:07 +0900396 final String errorFormat = ERR_FLOW + "VLAN mode is not ready for %s";
397 final String error = String.format(errorFormat, floatingIp, cNode.hostname());
Hyunsun Moon0d457362017-06-27 17:19:41 +0900398 throw new IllegalStateException(error);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900399 }
400
401 IpAddress floating = IpAddress.valueOf(floatingIp.getFloatingIpAddress());
Hyunsun Moon44aac662017-02-18 02:07:01 +0900402
Jian Lide679782018-06-05 01:41:29 +0900403 // TODO: following code snippet will be refactored sooner or later
Hyunsun Moon0d457362017-06-27 17:19:41 +0900404 osNodeService.completeNodes(GATEWAY).forEach(gNode -> {
Hyunsun Moon0d457362017-06-27 17:19:41 +0900405 // access from one VM to the others via floating IP
Hyunsun Moon44aac662017-02-18 02:07:01 +0900406 TrafficSelector internalSelector = DefaultTrafficSelector.builder()
407 .matchEthType(Ethernet.TYPE_IPV4)
408 .matchIPDst(floating.toIpPrefix())
Hyunsun Moon0d457362017-06-27 17:19:41 +0900409 .matchInPort(gNode.tunnelPortNum())
Hyunsun Moon44aac662017-02-18 02:07:01 +0900410 .build();
411
daniel parkee8700b2017-05-11 15:50:03 +0900412 TrafficTreatment.Builder internalBuilder = DefaultTrafficTreatment.builder()
Hyunsun Moon44aac662017-02-18 02:07:01 +0900413 .setEthSrc(Constants.DEFAULT_GATEWAY_MAC)
414 .setEthDst(instPort.macAddress())
daniel parkee8700b2017-05-11 15:50:03 +0900415 .setIpDst(instPort.ipAddress().getIp4Address());
416
417 switch (osNet.getNetworkType()) {
418 case VXLAN:
419 internalBuilder.setTunnelId(Long.valueOf(osNet.getProviderSegID()))
420 .extension(buildExtension(
421 deviceService,
Hyunsun Moon0d457362017-06-27 17:19:41 +0900422 gNode.intgBridge(),
423 cNode.dataIp().getIp4Address()),
424 gNode.intgBridge())
daniel parkee8700b2017-05-11 15:50:03 +0900425 .setOutput(PortNumber.IN_PORT);
426 break;
427 case VLAN:
428 internalBuilder.pushVlan()
429 .setVlanId(VlanId.vlanId(osNet.getProviderSegID()))
430 .setOutput(PortNumber.IN_PORT);
431 break;
432 default:
Ray Milkeyc6c9b172018-02-26 09:36:31 -0800433 final String error = String.format(ERR_UNSUPPORTED_NET_TYPE,
Hyunsun Moon0d457362017-06-27 17:19:41 +0900434 osNet.getNetworkType());
daniel parkee8700b2017-05-11 15:50:03 +0900435 throw new IllegalStateException(error);
436 }
Hyunsun Moon44aac662017-02-18 02:07:01 +0900437
sanghodc375372017-06-08 10:41:30 +0900438 osFlowRuleService.setRule(
Hyunsun Moon44aac662017-02-18 02:07:01 +0900439 appId,
Hyunsun Moon0d457362017-06-27 17:19:41 +0900440 gNode.intgBridge(),
Hyunsun Moon44aac662017-02-18 02:07:01 +0900441 internalSelector,
daniel parkee8700b2017-05-11 15:50:03 +0900442 internalBuilder.build(),
Hyunsun Moon44aac662017-02-18 02:07:01 +0900443 PRIORITY_FLOATING_INTERNAL,
sanghodc375372017-06-08 10:41:30 +0900444 GW_COMMON_TABLE,
Hyunsun Moon44aac662017-02-18 02:07:01 +0900445 install);
446 });
daniel parkc2a2ed62018-04-10 15:17:42 +0900447 log.trace("Succeeded to set flow rules for downstream on gateway nodes");
Hyunsun Moon44aac662017-02-18 02:07:01 +0900448 }
449
Jian Lide679782018-06-05 01:41:29 +0900450 private void setDownstreamExternalRulesHelper(NetFloatingIP floatingIp,
451 Network osNet,
452 InstancePort instPort,
453 ExternalPeerRouter externalPeerRouter,
454 Set<OpenstackNode> gateways, boolean install) {
455 OpenstackNode cNode = osNodeService.node(instPort.deviceId());
456 if (cNode == null) {
457 final String error = String.format("Cannot find openstack node for device %s",
458 instPort.deviceId());
459 throw new IllegalStateException(error);
460 }
461 if (osNet.getNetworkType() == NetworkType.VXLAN && cNode.dataIp() == null) {
462 final String errorFormat = ERR_FLOW + "VXLAN mode is not ready for %s";
463 final String error = String.format(errorFormat, floatingIp, cNode.hostname());
464 throw new IllegalStateException(error);
465 }
466 if (osNet.getNetworkType() == NetworkType.VLAN && cNode.vlanIntf() == null) {
467 final String errorFormat = ERR_FLOW + "VLAN mode is not ready for %s";
468 final String error = String.format(errorFormat, floatingIp, cNode.hostname());
469 throw new IllegalStateException(error);
470 }
471
472 IpAddress floating = IpAddress.valueOf(floatingIp.getFloatingIpAddress());
473
474 OpenstackNode selectedGatewayNode = getGwByComputeDevId(gateways, instPort.deviceId());
475
476 if (selectedGatewayNode == null) {
477 final String errorFormat = ERR_FLOW + "no gateway node selected";
478 throw new IllegalStateException(errorFormat);
479 }
480
481 TrafficSelector.Builder externalSelectorBuilder = DefaultTrafficSelector.builder()
482 .matchEthType(Ethernet.TYPE_IPV4)
483 .matchIPDst(floating.toIpPrefix());
484
485 TrafficTreatment.Builder externalTreatmentBuilder = DefaultTrafficTreatment.builder()
486 .setEthSrc(Constants.DEFAULT_GATEWAY_MAC)
487 .setEthDst(instPort.macAddress())
488 .setIpDst(instPort.ipAddress().getIp4Address());
489
Jian Li5e2ad4a2018-07-16 13:40:53 +0900490 if (!externalPeerRouter.vlanId().equals(VlanId.NONE)) {
491 externalSelectorBuilder.matchVlanId(externalPeerRouter.vlanId()).build();
Jian Lide679782018-06-05 01:41:29 +0900492 externalTreatmentBuilder.popVlan();
493 }
494
495 switch (osNet.getNetworkType()) {
496 case VXLAN:
497 externalTreatmentBuilder.setTunnelId(Long.valueOf(osNet.getProviderSegID()))
498 .extension(buildExtension(
499 deviceService,
500 selectedGatewayNode.intgBridge(),
501 cNode.dataIp().getIp4Address()),
502 selectedGatewayNode.intgBridge())
503 .setOutput(selectedGatewayNode.tunnelPortNum());
504 break;
505 case VLAN:
506 externalTreatmentBuilder.pushVlan()
507 .setVlanId(VlanId.vlanId(osNet.getProviderSegID()))
508 .setOutput(selectedGatewayNode.vlanPortNum());
509 break;
510 default:
511 final String error = String.format(ERR_UNSUPPORTED_NET_TYPE,
512 osNet.getNetworkType());
513 throw new IllegalStateException(error);
514 }
515
516 osFlowRuleService.setRule(
517 appId,
518 selectedGatewayNode.intgBridge(),
519 externalSelectorBuilder.build(),
520 externalTreatmentBuilder.build(),
521 PRIORITY_FLOATING_EXTERNAL,
522 GW_COMMON_TABLE,
523 install);
524 }
525
Hyunsun Moon44aac662017-02-18 02:07:01 +0900526 private void setUpstreamRules(NetFloatingIP floatingIp, Network osNet,
daniel park32b42202018-03-14 16:53:44 +0900527 InstancePort instPort, ExternalPeerRouter externalPeerRouter,
528 boolean install) {
Hyunsun Moon44aac662017-02-18 02:07:01 +0900529 IpAddress floating = IpAddress.valueOf(floatingIp.getFloatingIpAddress());
daniel parkee8700b2017-05-11 15:50:03 +0900530 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder()
Hyunsun Moon44aac662017-02-18 02:07:01 +0900531 .matchEthType(Ethernet.TYPE_IPV4)
daniel parkee8700b2017-05-11 15:50:03 +0900532 .matchIPSrc(instPort.ipAddress().toIpPrefix());
533
534 switch (osNet.getNetworkType()) {
535 case VXLAN:
536 sBuilder.matchTunnelId(Long.valueOf(osNet.getProviderSegID()));
537 break;
538 case VLAN:
539 sBuilder.matchVlanId(VlanId.vlanId(osNet.getProviderSegID()));
540 break;
541 default:
Ray Milkeyc6c9b172018-02-26 09:36:31 -0800542 final String error = String.format(ERR_UNSUPPORTED_NET_TYPE,
Hyunsun Moon0d457362017-06-27 17:19:41 +0900543 osNet.getNetworkType());
daniel parkee8700b2017-05-11 15:50:03 +0900544 throw new IllegalStateException(error);
545 }
Hyunsun Moon44aac662017-02-18 02:07:01 +0900546
Daniel Park75e3d7f2018-05-29 14:43:53 +0900547 TrafficSelector selector = sBuilder.build();
daniel parkeeb8e042018-02-21 14:06:58 +0900548
Hyunsun Moon0d457362017-06-27 17:19:41 +0900549 osNodeService.completeNodes(GATEWAY).forEach(gNode -> {
Daniel Park75e3d7f2018-05-29 14:43:53 +0900550 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder()
551 .setIpSrc(floating.getIp4Address())
552 .setEthSrc(instPort.macAddress())
Jian Li5e2ad4a2018-07-16 13:40:53 +0900553 .setEthDst(externalPeerRouter.macAddress());
Hyunsun Moon44aac662017-02-18 02:07:01 +0900554
Daniel Park75e3d7f2018-05-29 14:43:53 +0900555 if (osNet.getNetworkType().equals(NetworkType.VLAN)) {
556 tBuilder.popVlan();
557 }
558
Jian Li5e2ad4a2018-07-16 13:40:53 +0900559 if (!externalPeerRouter.vlanId().equals(VlanId.NONE)) {
560 tBuilder.pushVlan().setVlanId(externalPeerRouter.vlanId());
Daniel Park75e3d7f2018-05-29 14:43:53 +0900561 }
sanghodc375372017-06-08 10:41:30 +0900562 osFlowRuleService.setRule(
Hyunsun Moon44aac662017-02-18 02:07:01 +0900563 appId,
Hyunsun Moon0d457362017-06-27 17:19:41 +0900564 gNode.intgBridge(),
Daniel Park75e3d7f2018-05-29 14:43:53 +0900565 selector,
daniel parkeeb8e042018-02-21 14:06:58 +0900566 tBuilder.setOutput(gNode.uplinkPortNum()).build(),
Hyunsun Moon44aac662017-02-18 02:07:01 +0900567 PRIORITY_FLOATING_EXTERNAL,
sanghodc375372017-06-08 10:41:30 +0900568 GW_COMMON_TABLE,
Hyunsun Moon44aac662017-02-18 02:07:01 +0900569 install);
Daniel Park75e3d7f2018-05-29 14:43:53 +0900570 });
daniel parkc2a2ed62018-04-10 15:17:42 +0900571 log.trace("Succeeded to set flow rules for upstream on gateway nodes");
Hyunsun Moon44aac662017-02-18 02:07:01 +0900572 }
573
daniel park32b42202018-03-14 16:53:44 +0900574 private ExternalPeerRouter externalPeerRouter(Network network) {
daniel parkeeb8e042018-02-21 14:06:58 +0900575 if (network == null) {
576 return null;
577 }
578
579 Subnet subnet = osNetworkService.subnets(network.getId()).stream().findAny().orElse(null);
580
581 if (subnet == null) {
582 return null;
583 }
584
Jian Lif3a28b02018-06-11 21:29:13 +0900585 RouterInterface osRouterIface = osRouterAdminService.routerInterfaces().stream()
daniel parkeeb8e042018-02-21 14:06:58 +0900586 .filter(i -> Objects.equals(i.getSubnetId(), subnet.getId()))
587 .findAny().orElse(null);
588 if (osRouterIface == null) {
589 return null;
590 }
591
Jian Lif3a28b02018-06-11 21:29:13 +0900592 Router osRouter = osRouterAdminService.router(osRouterIface.getId());
daniel parkeeb8e042018-02-21 14:06:58 +0900593 if (osRouter == null) {
594 return null;
595 }
596 if (osRouter.getExternalGatewayInfo() == null) {
597 return null;
598 }
599
600 ExternalGateway exGatewayInfo = osRouter.getExternalGatewayInfo();
daniel park65e1c202018-04-03 13:15:28 +0900601 return osNetworkService.externalPeerRouter(exGatewayInfo);
daniel parkeeb8e042018-02-21 14:06:58 +0900602 }
daniel park65e1c202018-04-03 13:15:28 +0900603
Jian Li99892e92018-04-13 14:59:39 +0900604 private void associateFloatingIp(NetFloatingIP osFip) {
605 Port osPort = osNetworkService.port(osFip.getPortId());
606 if (osPort == null) {
607 final String errorFormat = ERR_FLOW + "port(%s) not found";
608 final String error = String.format(errorFormat,
609 osFip.getFloatingIpAddress(), osFip.getPortId());
610 throw new IllegalStateException(error);
611 }
612 // set floating IP rules only if the port is associated to a VM
613 if (!Strings.isNullOrEmpty(osPort.getDeviceId())) {
Jian Lie1a39032018-06-19 21:49:36 +0900614
615 if (instancePortService.instancePort(osPort.getId()) == null) {
Jian Lie1a39032018-06-19 21:49:36 +0900616 return;
617 }
618
Jian Li1064e4f2018-05-29 16:16:53 +0900619 setFloatingIpRules(osFip, osPort, null, true);
Jian Li99892e92018-04-13 14:59:39 +0900620 }
621 }
622
623 private void disassociateFloatingIp(NetFloatingIP osFip, String portId) {
624 Port osPort = osNetworkService.port(portId);
Jian Lie1a39032018-06-19 21:49:36 +0900625
626 if (osPort == null) {
627 final String errorFormat = ERR_FLOW + "port(%s) not found";
628 final String error = String.format(errorFormat,
629 osFip.getFloatingIpAddress(), osFip.getPortId());
630 throw new IllegalStateException(error);
631 }
632
Jian Li99892e92018-04-13 14:59:39 +0900633 // set floating IP rules only if the port is associated to a VM
634 if (!Strings.isNullOrEmpty(osPort.getDeviceId())) {
Jian Lie1a39032018-06-19 21:49:36 +0900635
Jian Lie1a39032018-06-19 21:49:36 +0900636 if (instancePortService.instancePort(osPort.getId()) == null) {
Jian Li46b74002018-07-15 18:39:08 +0900637 return;
Jian Lie1a39032018-06-19 21:49:36 +0900638 }
639
Jian Li1064e4f2018-05-29 16:16:53 +0900640 setFloatingIpRules(osFip, osPort, null, false);
Jian Li99892e92018-04-13 14:59:39 +0900641 }
642 }
643
Hyunsun Moon0d457362017-06-27 17:19:41 +0900644 private class InternalFloatingIpListener implements OpenstackRouterListener {
Hyunsun Moon44aac662017-02-18 02:07:01 +0900645
646 @Override
647 public boolean isRelevant(OpenstackRouterEvent event) {
648 // do not allow to proceed without leadership
649 NodeId leader = leadershipService.getLeader(appId.name());
650 if (!Objects.equals(localNodeId, leader)) {
651 return false;
652 }
653 return event.floatingIp() != null;
654 }
655
656 @Override
657 public void event(OpenstackRouterEvent event) {
658 switch (event.type()) {
659 case OPENSTACK_FLOATING_IP_ASSOCIATED:
Hyunsun Moon7a5f9042017-05-11 18:19:01 +0900660 eventExecutor.execute(() -> {
Hyunsun Moonb720e632017-05-16 15:41:36 +0900661 NetFloatingIP osFip = event.floatingIp();
662 associateFloatingIp(osFip);
663 log.info("Associated floating IP {}:{}",
664 osFip.getFloatingIpAddress(), osFip.getFixedIpAddress());
Hyunsun Moon7a5f9042017-05-11 18:19:01 +0900665 });
666 break;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900667 case OPENSTACK_FLOATING_IP_DISASSOCIATED:
668 eventExecutor.execute(() -> {
Hyunsun Moonb720e632017-05-16 15:41:36 +0900669 NetFloatingIP osFip = event.floatingIp();
670 disassociateFloatingIp(osFip, event.portId());
671 log.info("Disassociated floating IP {}:{}",
672 osFip.getFloatingIpAddress(), osFip.getFixedIpAddress());
Hyunsun Moon7a5f9042017-05-11 18:19:01 +0900673 });
674 break;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900675 case OPENSTACK_FLOATING_IP_CREATED:
Hyunsun Moonb720e632017-05-16 15:41:36 +0900676 eventExecutor.execute(() -> {
677 NetFloatingIP osFip = event.floatingIp();
678 if (!Strings.isNullOrEmpty(osFip.getPortId())) {
679 associateFloatingIp(event.floatingIp());
680 }
681 log.info("Created floating IP {}", osFip.getFloatingIpAddress());
682 });
683 break;
Jian Lia171a432018-06-11 11:52:11 +0900684 case OPENSTACK_FLOATING_IP_REMOVED:
685 eventExecutor.execute(() -> {
686 NetFloatingIP osFip = event.floatingIp();
687 if (!Strings.isNullOrEmpty(osFip.getPortId())) {
Jian Lic2403592018-07-18 12:56:45 +0900688 // in case the floating IP is not associated with any port due to
689 // port removal, we simply do not execute floating IP disassociation
690 if (osNetworkService.port(osFip.getPortId()) != null) {
691 disassociateFloatingIp(osFip, osFip.getPortId());
692 }
Jian Lia171a432018-06-11 11:52:11 +0900693 }
694 log.info("Removed floating IP {}", osFip.getFloatingIpAddress());
695 });
696 break;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900697 case OPENSTACK_FLOATING_IP_UPDATED:
Hyunsun Moon44aac662017-02-18 02:07:01 +0900698 case OPENSTACK_ROUTER_CREATED:
699 case OPENSTACK_ROUTER_UPDATED:
700 case OPENSTACK_ROUTER_REMOVED:
701 case OPENSTACK_ROUTER_INTERFACE_ADDED:
702 case OPENSTACK_ROUTER_INTERFACE_UPDATED:
703 case OPENSTACK_ROUTER_INTERFACE_REMOVED:
704 default:
705 // do nothing for the other events
706 break;
707 }
708 }
709 }
710
711 private class InternalNodeListener implements OpenstackNodeListener {
712
713 @Override
714 public boolean isRelevant(OpenstackNodeEvent event) {
715 // do not allow to proceed without leadership
716 NodeId leader = leadershipService.getLeader(appId.name());
717 if (!Objects.equals(localNodeId, leader)) {
718 return false;
719 }
720 return event.subject().type() == GATEWAY;
721 }
722
723 @Override
724 public void event(OpenstackNodeEvent event) {
Hyunsun Moon44aac662017-02-18 02:07:01 +0900725
726 switch (event.type()) {
Hyunsun Moon0d457362017-06-27 17:19:41 +0900727 case OPENSTACK_NODE_COMPLETE:
Hyunsun Moon44aac662017-02-18 02:07:01 +0900728 eventExecutor.execute(() -> {
Jian Lif3a28b02018-06-11 21:29:13 +0900729 for (NetFloatingIP fip : osRouterAdminService.floatingIps()) {
Jian Lie1a39032018-06-19 21:49:36 +0900730
Hyunsun Moon7a5f9042017-05-11 18:19:01 +0900731 if (Strings.isNullOrEmpty(fip.getPortId())) {
732 continue;
733 }
Jian Lie1a39032018-06-19 21:49:36 +0900734
Hyunsun Moon7a5f9042017-05-11 18:19:01 +0900735 Port osPort = osNetworkService.port(fip.getPortId());
736 if (osPort == null) {
737 log.warn("Failed to set floating IP {}", fip.getId());
738 continue;
739 }
Jian Lie1a39032018-06-19 21:49:36 +0900740
Jian Li46b74002018-07-15 18:39:08 +0900741 if (instancePortService.instancePort(fip.getPortId()) == null) {
Jian Lie1a39032018-06-19 21:49:36 +0900742 continue;
743 }
Jian Liec5c32b2018-07-13 14:28:58 +0900744
Jian Li1064e4f2018-05-29 16:16:53 +0900745 setFloatingIpRules(fip, osPort, event.subject(), true);
Hyunsun Moon7a5f9042017-05-11 18:19:01 +0900746 }
Hyunsun Moon44aac662017-02-18 02:07:01 +0900747 });
748 break;
Hyunsun Moon0d457362017-06-27 17:19:41 +0900749 case OPENSTACK_NODE_INCOMPLETE:
Jian Li1064e4f2018-05-29 16:16:53 +0900750 eventExecutor.execute(() -> {
Jian Lif3a28b02018-06-11 21:29:13 +0900751 for (NetFloatingIP fip : osRouterAdminService.floatingIps()) {
Jian Li1064e4f2018-05-29 16:16:53 +0900752 if (Strings.isNullOrEmpty(fip.getPortId())) {
753 continue;
754 }
755 Port osPort = osNetworkService.port(fip.getPortId());
756 if (osPort == null) {
757 log.warn("Failed to set floating IP {}", fip.getId());
758 continue;
759 }
760 Network osNet = osNetworkService.network(osPort.getNetworkId());
761 if (osNet == null) {
762 final String errorFormat = ERR_FLOW + "no network(%s) exists";
763 final String error = String.format(errorFormat,
764 fip.getFloatingIpAddress(),
765 osPort.getNetworkId());
766 throw new IllegalStateException(error);
767 }
768 MacAddress srcMac = MacAddress.valueOf(osPort.getMacAddress());
769 log.trace("Mac address of openstack port: {}", srcMac);
770 InstancePort instPort = instancePortService.instancePort(srcMac);
771
772 if (instPort == null) {
773 final String errorFormat = ERR_FLOW + "no host(MAC:%s) found";
774 final String error = String.format(errorFormat,
775 fip.getFloatingIpAddress(), srcMac);
776 throw new IllegalStateException(error);
777 }
778
Jian Lide679782018-06-05 01:41:29 +0900779 ExternalPeerRouter externalPeerRouter = externalPeerRouter(osNet);
780 if (externalPeerRouter == null) {
781 final String errorFormat = ERR_FLOW + "no external peer router found";
782 throw new IllegalStateException(errorFormat);
783 }
784
785 updateComputeNodeRules(instPort, osNet, event.subject(), false);
786 updateGatewayNodeRules(fip, instPort, osNet,
787 externalPeerRouter, event.subject(), false);
Jian Li1064e4f2018-05-29 16:16:53 +0900788 }
789 });
790 break;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900791 default:
Hyunsun Moon0d457362017-06-27 17:19:41 +0900792 // do nothing
Hyunsun Moon44aac662017-02-18 02:07:01 +0900793 break;
794 }
795 }
796 }
Jian Li99892e92018-04-13 14:59:39 +0900797
Jian Li24ec59f2018-05-23 19:01:25 +0900798 private class InternalInstancePortListener implements InstancePortListener {
799
800 @Override
801 public boolean isRelevant(InstancePortEvent event) {
Jian Li24ec59f2018-05-23 19:01:25 +0900802
Jian Lie1a39032018-06-19 21:49:36 +0900803 if (event.type() == OPENSTACK_INSTANCE_MIGRATION_ENDED ||
804 event.type() == OPENSTACK_INSTANCE_MIGRATION_STARTED) {
805 Set<NetFloatingIP> ips = osRouterAdminService.floatingIps();
806 NetFloatingIP fip = associatedFloatingIp(event.subject(), ips);
807
808 // we check the possible NPE to avoid duplicated null check
809 // for OPENSTACK_INSTANCE_MIGRATION_ENDED and
810 // OPENSTACK_INSTANCE_MIGRATION_STARTED cases
811 if (fip == null || !isAssociatedWithVM(osNetworkService, fip)) {
812 return false;
813 }
814 }
815
816 // do not allow to proceed without leadership
817 NodeId leader = leadershipService.getLeader(appId.name());
818
819 return Objects.equals(localNodeId, leader);
Jian Li24ec59f2018-05-23 19:01:25 +0900820 }
821
822 @Override
823 public void event(InstancePortEvent event) {
Jian Lie1a39032018-06-19 21:49:36 +0900824 InstancePort instPort = event.subject();
Jian Li24ec59f2018-05-23 19:01:25 +0900825 Set<OpenstackNode> gateways = osNodeService.completeNodes(GATEWAY);
826
Jian Lie1a39032018-06-19 21:49:36 +0900827 Set<NetFloatingIP> ips = osRouterAdminService.floatingIps();
828 NetFloatingIP fip;
829 Port osPort;
830 Network osNet;
831 ExternalPeerRouter externalPeerRouter;
Jian Li24ec59f2018-05-23 19:01:25 +0900832
833 switch (event.type()) {
Jian Lie1a39032018-06-19 21:49:36 +0900834 case OPENSTACK_INSTANCE_PORT_DETECTED:
Jian Li77323c52018-06-24 01:26:18 +0900835 if (instPort != null && instPort.portId() != null) {
836 String portId = instPort.portId();
Jian Lie1a39032018-06-19 21:49:36 +0900837
Jian Li77323c52018-06-24 01:26:18 +0900838 Port port = osNetworkService.port(portId);
839
Jian Li46b74002018-07-15 18:39:08 +0900840 osRouterAdminService.floatingIps().stream()
841 .filter(f -> f.getPortId() != null)
842 .filter(f -> f.getPortId().equals(instPort.portId()))
843 .forEach(f -> setFloatingIpRules(f, port, null, true));
Jian Lie1a39032018-06-19 21:49:36 +0900844 }
845
846 break;
847
Jian Li24ec59f2018-05-23 19:01:25 +0900848 case OPENSTACK_INSTANCE_MIGRATION_STARTED:
Jian Lie1a39032018-06-19 21:49:36 +0900849
850 fip = associatedFloatingIp(event.subject(), ips);
851
852 if (fip == null) {
853 return;
854 }
855
856 osPort = osNetworkService.port(fip.getPortId());
857 osNet = osNetworkService.network(osPort.getNetworkId());
858 externalPeerRouter = externalPeerRouter(osNet);
859
860 if (externalPeerRouter == null) {
861 final String errorFormat = ERR_FLOW + "no external peer router found";
862 throw new IllegalStateException(errorFormat);
863 }
864
Jian Li24ec59f2018-05-23 19:01:25 +0900865 eventExecutor.execute(() -> {
866
867 // since downstream internal rules are located in all gateway
868 // nodes, therefore, we simply update the rules with new compute node info
869 setDownstreamInternalRules(fip, osNet, event.subject(), true);
870
871 // since DownstreamExternal rules should only be placed in
872 // corresponding gateway node, we need to install new rule to
873 // the corresponding gateway node
874 setDownstreamExternalRulesHelper(fip, osNet,
875 event.subject(), externalPeerRouter, gateways, true);
876
877 // since ComputeNodeToGateway rules should only be placed in
878 // corresponding compute node, we need to install new rule to
879 // the target compute node, and remove rules from original node
880 setComputeNodeToGatewayHelper(event.subject(), osNet, gateways, true);
Jian Li24ec59f2018-05-23 19:01:25 +0900881 });
882 break;
883 case OPENSTACK_INSTANCE_MIGRATION_ENDED:
884
Jian Liec5c32b2018-07-13 14:28:58 +0900885 InstancePort revisedInstPort = swapStaleLocation(event.subject());
886
887 fip = associatedFloatingIp(revisedInstPort, ips);
Jian Lie1a39032018-06-19 21:49:36 +0900888
889 if (fip == null) {
890 return;
891 }
892
893 osPort = osNetworkService.port(fip.getPortId());
894 osNet = osNetworkService.network(osPort.getNetworkId());
895 externalPeerRouter = externalPeerRouter(osNet);
896
897 if (externalPeerRouter == null) {
898 final String errorFormat = ERR_FLOW + "no external peer router found";
899 throw new IllegalStateException(errorFormat);
900 }
901
902 // If we only have one gateway, we simply do not remove any
Jian Li24ec59f2018-05-23 19:01:25 +0900903 // flow rules from either gateway or compute node
904 if (gateways.size() == 1) {
905 return;
906 }
907
Jian Lie1a39032018-06-19 21:49:36 +0900908 // Checks whether the destination compute node's device id
Jian Li24ec59f2018-05-23 19:01:25 +0900909 // has identical gateway hash or not
910 // if it is true, we simply do not remove the rules, as
911 // it has been overwritten at port detention event
912 // if it is false, we will remove the rules
Jian Liec5c32b2018-07-13 14:28:58 +0900913 DeviceId newDeviceId = event.subject().deviceId();
914 DeviceId oldDeviceId = revisedInstPort.deviceId();
Jian Li24ec59f2018-05-23 19:01:25 +0900915
916 OpenstackNode oldGateway = getGwByComputeDevId(gateways, oldDeviceId);
917 OpenstackNode newGateway = getGwByComputeDevId(gateways, newDeviceId);
918
919 if (oldGateway != null && oldGateway.equals(newGateway)) {
920 return;
921 }
922
923 eventExecutor.execute(() -> {
924
Jian Lie1a39032018-06-19 21:49:36 +0900925 // We need to remove the old ComputeNodeToGateway rules from
Jian Li24ec59f2018-05-23 19:01:25 +0900926 // original compute node
Jian Liec5c32b2018-07-13 14:28:58 +0900927 setComputeNodeToGatewayHelper(revisedInstPort, osNet, gateways, false);
Jian Li24ec59f2018-05-23 19:01:25 +0900928
Jian Lie1a39032018-06-19 21:49:36 +0900929 // Since DownstreamExternal rules should only be placed in
Jian Li24ec59f2018-05-23 19:01:25 +0900930 // corresponding gateway node, we need to remove old rule from
931 // the corresponding gateway node
Jian Liec5c32b2018-07-13 14:28:58 +0900932 setDownstreamExternalRulesHelper(fip, osNet, revisedInstPort,
933 externalPeerRouter, gateways, false);
Jian Li24ec59f2018-05-23 19:01:25 +0900934 });
935 break;
936 default:
937 break;
938 }
939 }
940 }
Jian Lie1a39032018-06-19 21:49:36 +0900941
942 private class InternalOpenstackNetworkListener implements OpenstackNetworkListener {
943
944 @Override
945 public boolean isRelevant(OpenstackNetworkEvent event) {
946 // do not allow to proceed without leadership
947 NodeId leader = leadershipService.getLeader(appId.name());
Jian Lic2403592018-07-18 12:56:45 +0900948 return Objects.equals(localNodeId, leader) &&
949 event.subject().getNetworkType() != FLAT;
Jian Lie1a39032018-06-19 21:49:36 +0900950 }
951
952 @Override
953 public void event(OpenstackNetworkEvent event) {
Jian Li8f64feb2018-07-24 13:20:16 +0900954 String portId;
955
Jian Lie1a39032018-06-19 21:49:36 +0900956 switch (event.type()) {
Jian Li8f64feb2018-07-24 13:20:16 +0900957 case OPENSTACK_PORT_PRE_REMOVE:
958 portId = event.port().getId();
Jian Liec5c32b2018-07-13 14:28:58 +0900959
960 InstancePort instPort = instancePortService.instancePort(portId);
Jian Liec5c32b2018-07-13 14:28:58 +0900961 updateFipStore(instPort);
962
Jian Li8f64feb2018-07-24 13:20:16 +0900963 break;
964 case OPENSTACK_PORT_REMOVED:
965 portId = event.port().getId();
966
967 instancePortService.removeInstancePort(portId);
968
Jian Lie1a39032018-06-19 21:49:36 +0900969 break;
970 default:
971 break;
972 }
973 }
974
975 private void updateFipStore(InstancePort port) {
976
977 if (port == null) {
978 return;
979 }
980
981 Set<NetFloatingIP> ips = osRouterAdminService.floatingIps();
982 for (NetFloatingIP fip : ips) {
983 if (Strings.isNullOrEmpty(fip.getFixedIpAddress())) {
984 continue;
985 }
986 if (Strings.isNullOrEmpty(fip.getFloatingIpAddress())) {
987 continue;
988 }
989 if (fip.getFixedIpAddress().equals(port.ipAddress().toString())) {
990 NeutronFloatingIP neutronFip = (NeutronFloatingIP) fip;
991 // invalidate bound fixed IP and port
992 neutronFip.setFixedIpAddress(null);
993 neutronFip.setPortId(null);
Jian Lie1a39032018-06-19 21:49:36 +0900994
995 // Following update will in turn trigger
996 // OPENSTACK_FLOATING_IP_DISASSOCIATED event
997 osRouterAdminService.updateFloatingIp(neutronFip);
998 log.info("Updated floating IP {}, due to host removal",
999 neutronFip.getFloatingIpAddress());
1000 }
1001 }
1002 }
1003 }
Hyunsun Moon44aac662017-02-18 02:07:01 +09001004}