blob: b34ae9c3597fbab3bd8e48526619da7b32dab297 [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;
19import org.apache.felix.scr.annotations.Activate;
20import org.apache.felix.scr.annotations.Component;
21import org.apache.felix.scr.annotations.Deactivate;
22import org.apache.felix.scr.annotations.Reference;
23import org.apache.felix.scr.annotations.ReferenceCardinality;
24import org.onlab.packet.Ethernet;
25import org.onlab.packet.IpAddress;
26import org.onlab.packet.MacAddress;
daniel parkee8700b2017-05-11 15:50:03 +090027import org.onlab.packet.VlanId;
Hyunsun Moon44aac662017-02-18 02:07:01 +090028import org.onosproject.cluster.ClusterService;
29import org.onosproject.cluster.LeadershipService;
30import org.onosproject.cluster.NodeId;
31import org.onosproject.core.ApplicationId;
32import org.onosproject.core.CoreService;
33import org.onosproject.net.PortNumber;
34import org.onosproject.net.device.DeviceService;
35import org.onosproject.net.flow.DefaultTrafficSelector;
36import org.onosproject.net.flow.DefaultTrafficTreatment;
37import org.onosproject.net.flow.TrafficSelector;
38import org.onosproject.net.flow.TrafficTreatment;
Hyunsun Moon44aac662017-02-18 02:07:01 +090039import org.onosproject.openstacknetworking.api.Constants;
40import org.onosproject.openstacknetworking.api.InstancePort;
41import org.onosproject.openstacknetworking.api.InstancePortService;
sanghodc375372017-06-08 10:41:30 +090042import org.onosproject.openstacknetworking.api.OpenstackFlowRuleService;
43import org.onosproject.openstacknetworking.api.OpenstackNetworkService;
Hyunsun Moon44aac662017-02-18 02:07:01 +090044import org.onosproject.openstacknetworking.api.OpenstackRouterEvent;
45import org.onosproject.openstacknetworking.api.OpenstackRouterListener;
46import org.onosproject.openstacknetworking.api.OpenstackRouterService;
Hyunsun Moon0d457362017-06-27 17:19:41 +090047import org.onosproject.openstacknode.api.OpenstackNode;
48import org.onosproject.openstacknode.api.OpenstackNodeEvent;
49import org.onosproject.openstacknode.api.OpenstackNodeListener;
50import org.onosproject.openstacknode.api.OpenstackNodeService;
daniel parkeeb8e042018-02-21 14:06:58 +090051import org.openstack4j.model.network.ExternalGateway;
Hyunsun Moon44aac662017-02-18 02:07:01 +090052import org.openstack4j.model.network.NetFloatingIP;
53import org.openstack4j.model.network.Network;
daniel parkee8700b2017-05-11 15:50:03 +090054import org.openstack4j.model.network.NetworkType;
Hyunsun Moon44aac662017-02-18 02:07:01 +090055import org.openstack4j.model.network.Port;
daniel parkeeb8e042018-02-21 14:06:58 +090056import org.openstack4j.model.network.Router;
57import org.openstack4j.model.network.RouterInterface;
58import org.openstack4j.model.network.Subnet;
Hyunsun Moon44aac662017-02-18 02:07:01 +090059import org.slf4j.Logger;
60import org.slf4j.LoggerFactory;
61
62import java.util.Objects;
Hyunsun Moon44aac662017-02-18 02:07:01 +090063import java.util.concurrent.ExecutorService;
64
65import static java.util.concurrent.Executors.newSingleThreadExecutor;
66import static org.onlab.util.Tools.groupedThreads;
sanghodc375372017-06-08 10:41:30 +090067import static org.onosproject.openstacknetworking.api.Constants.GW_COMMON_TABLE;
68import static org.onosproject.openstacknetworking.api.Constants.OPENSTACK_NETWORKING_APP_ID;
daniel parkeeb8e042018-02-21 14:06:58 +090069import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_EXTERNAL_FLOATING_ROUTING_RULE;
sanghodc375372017-06-08 10:41:30 +090070import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_FLOATING_EXTERNAL;
71import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_FLOATING_INTERNAL;
daniel parkeeb8e042018-02-21 14:06:58 +090072import static org.onosproject.openstacknetworking.api.Constants.ROUTING_TABLE;
Hyunsun Moon44aac662017-02-18 02:07:01 +090073import static org.onosproject.openstacknetworking.impl.RulePopulatorUtil.buildExtension;
Hyunsun Moon0d457362017-06-27 17:19:41 +090074import static org.onosproject.openstacknode.api.OpenstackNode.NodeType.GATEWAY;
Hyunsun Moon44aac662017-02-18 02:07:01 +090075
76/**
77 * Handles OpenStack floating IP events.
78 */
79@Component(immediate = true)
80public class OpenstackRoutingFloatingIpHandler {
81
82 private final Logger log = LoggerFactory.getLogger(getClass());
83
84 private static final String ERR_FLOW = "Failed set flows for floating IP %s: ";
Ray Milkeyc6c9b172018-02-26 09:36:31 -080085 private static final String ERR_UNSUPPORTED_NET_TYPE = "Unsupported network type %s";
Hyunsun Moon44aac662017-02-18 02:07:01 +090086
87 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
88 protected CoreService coreService;
89
90 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
91 protected DeviceService deviceService;
92
93 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Hyunsun Moon44aac662017-02-18 02:07:01 +090094 protected LeadershipService leadershipService;
95
96 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
97 protected ClusterService clusterService;
98
99 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
100 protected OpenstackNodeService osNodeService;
101
102 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
103 protected InstancePortService instancePortService;
104
105 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
106 protected OpenstackRouterService osRouterService;
107
108 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
109 protected OpenstackNetworkService osNetworkService;
110
sanghodc375372017-06-08 10:41:30 +0900111 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
112 protected OpenstackFlowRuleService osFlowRuleService;
113
Hyunsun Moon44aac662017-02-18 02:07:01 +0900114 private final ExecutorService eventExecutor = newSingleThreadExecutor(
115 groupedThreads(this.getClass().getSimpleName(), "event-handler", log));
Hyunsun Moon0d457362017-06-27 17:19:41 +0900116 private final OpenstackRouterListener floatingIpLisener = new InternalFloatingIpListener();
Hyunsun Moon44aac662017-02-18 02:07:01 +0900117 private final OpenstackNodeListener osNodeListener = new InternalNodeListener();
118
119 private ApplicationId appId;
120 private NodeId localNodeId;
121
122 @Activate
123 protected void activate() {
124 appId = coreService.registerApplication(OPENSTACK_NETWORKING_APP_ID);
125 localNodeId = clusterService.getLocalNode().id();
126 leadershipService.runForLeadership(appId.name());
127 osRouterService.addListener(floatingIpLisener);
128 osNodeService.addListener(osNodeListener);
129
130 log.info("Started");
131 }
132
133 @Deactivate
134 protected void deactivate() {
135 osNodeService.removeListener(osNodeListener);
136 osRouterService.removeListener(floatingIpLisener);
137 leadershipService.withdraw(appId.name());
138 eventExecutor.shutdown();
139
140 log.info("Stopped");
141 }
142
Hyunsun Moon44aac662017-02-18 02:07:01 +0900143 private void setFloatingIpRules(NetFloatingIP floatingIp, Port osPort,
144 boolean install) {
145 Network osNet = osNetworkService.network(osPort.getNetworkId());
146 if (osNet == null) {
147 final String error = String.format(ERR_FLOW + "no network(%s) exists",
148 floatingIp.getFloatingIpAddress(),
149 osPort.getNetworkId());
150 throw new IllegalStateException(error);
151 }
152
153 MacAddress srcMac = MacAddress.valueOf(osPort.getMacAddress());
154 InstancePort instPort = instancePortService.instancePort(srcMac);
155 if (instPort == null) {
156 final String error = String.format(ERR_FLOW + "no host(MAC:%s) found",
157 floatingIp.getFloatingIpAddress(), srcMac);
158 throw new IllegalStateException(error);
159 }
160
daniel parkeeb8e042018-02-21 14:06:58 +0900161 setComputeNodeToGateway(instPort, osNet, install);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900162 setDownstreamRules(floatingIp, osNet, instPort, install);
163 setUpstreamRules(floatingIp, osNet, instPort, install);
164 }
165
daniel parkeeb8e042018-02-21 14:06:58 +0900166 private void setComputeNodeToGateway(InstancePort instPort, Network osNet, boolean install) {
167 TrafficTreatment treatment;
168
169 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder()
170 .matchEthType(Ethernet.TYPE_IPV4)
171 .matchIPSrc(instPort.ipAddress().toIpPrefix())
172 .matchEthDst(Constants.DEFAULT_GATEWAY_MAC);
173
174 switch (osNet.getNetworkType()) {
175 case VXLAN:
176 sBuilder.matchTunnelId(Long.parseLong(osNet.getProviderSegID()));
177 break;
178 case VLAN:
179 sBuilder.matchVlanId(VlanId.vlanId(osNet.getProviderSegID()));
180 break;
181 default:
182 final String error = String.format(
Ray Milkeyc6c9b172018-02-26 09:36:31 -0800183 ERR_UNSUPPORTED_NET_TYPE,
daniel parkeeb8e042018-02-21 14:06:58 +0900184 osNet.getNetworkType().toString());
185 throw new IllegalStateException(error);
186 }
187
188 OpenstackNode selectedGatewayNode = selectGatewayNode();
189 if (selectedGatewayNode == null) {
190 return;
191 }
192 treatment = DefaultTrafficTreatment.builder()
193 .extension(buildExtension(
194 deviceService,
195 instPort.deviceId(),
196 selectedGatewayNode.dataIp().getIp4Address()),
197 instPort.deviceId())
198 .setOutput(osNodeService.node(instPort.deviceId()).tunnelPortNum())
199 .build();
200
201 osFlowRuleService.setRule(
202 appId,
203 instPort.deviceId(),
204 sBuilder.build(),
205 treatment,
206 PRIORITY_EXTERNAL_FLOATING_ROUTING_RULE,
207 ROUTING_TABLE,
208 install);
209 }
210
211 private OpenstackNode selectGatewayNode() {
212 //TODO support multiple loadbalancing options.
213 return osNodeService.completeNodes(GATEWAY).stream().findAny().orElse(null);
214 }
215
Hyunsun Moon44aac662017-02-18 02:07:01 +0900216 private void setDownstreamRules(NetFloatingIP floatingIp, Network osNet,
217 InstancePort instPort, boolean install) {
Hyunsun Moon0d457362017-06-27 17:19:41 +0900218 OpenstackNode cNode = osNodeService.node(instPort.deviceId());
219 if (cNode == null) {
220 final String error = String.format("Cannot find openstack node for device %s",
221 instPort.deviceId());
222 throw new IllegalStateException(error);
223 }
224 if (osNet.getNetworkType() == NetworkType.VXLAN && cNode.dataIp() == null) {
225 final String error = String.format(ERR_FLOW +
226 "VXLAN mode is not ready for %s", floatingIp, cNode.hostname());
227 throw new IllegalStateException(error);
228 }
229 if (osNet.getNetworkType() == NetworkType.VLAN && cNode.vlanIntf() == null) {
230 final String error = String.format(ERR_FLOW +
231 "VLAN mode is not ready for %s", floatingIp, cNode.hostname());
232 throw new IllegalStateException(error);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900233 }
234
235 IpAddress floating = IpAddress.valueOf(floatingIp.getFloatingIpAddress());
236 TrafficSelector externalSelector = DefaultTrafficSelector.builder()
237 .matchEthType(Ethernet.TYPE_IPV4)
238 .matchIPDst(floating.toIpPrefix())
239 .build();
240
Hyunsun Moon0d457362017-06-27 17:19:41 +0900241 osNodeService.completeNodes(GATEWAY).forEach(gNode -> {
daniel parkee8700b2017-05-11 15:50:03 +0900242 TrafficTreatment.Builder externalBuilder = DefaultTrafficTreatment.builder()
Hyunsun Moon44aac662017-02-18 02:07:01 +0900243 .setEthSrc(Constants.DEFAULT_GATEWAY_MAC)
244 .setEthDst(instPort.macAddress())
daniel parkee8700b2017-05-11 15:50:03 +0900245 .setIpDst(instPort.ipAddress().getIp4Address());
246
247 switch (osNet.getNetworkType()) {
248 case VXLAN:
249 externalBuilder.setTunnelId(Long.valueOf(osNet.getProviderSegID()))
250 .extension(buildExtension(
251 deviceService,
Hyunsun Moon0d457362017-06-27 17:19:41 +0900252 gNode.intgBridge(),
253 cNode.dataIp().getIp4Address()),
254 gNode.intgBridge())
255 .setOutput(gNode.tunnelPortNum());
daniel parkee8700b2017-05-11 15:50:03 +0900256 break;
257 case VLAN:
258 externalBuilder.pushVlan()
259 .setVlanId(VlanId.vlanId(osNet.getProviderSegID()))
Hyunsun Moon0d457362017-06-27 17:19:41 +0900260 .setOutput(gNode.vlanPortNum());
daniel parkee8700b2017-05-11 15:50:03 +0900261 break;
262 default:
Ray Milkeyc6c9b172018-02-26 09:36:31 -0800263 final String error = String.format(ERR_UNSUPPORTED_NET_TYPE,
Hyunsun Moon0d457362017-06-27 17:19:41 +0900264 osNet.getNetworkType());
daniel parkee8700b2017-05-11 15:50:03 +0900265 throw new IllegalStateException(error);
266 }
Hyunsun Moon44aac662017-02-18 02:07:01 +0900267
sanghodc375372017-06-08 10:41:30 +0900268 osFlowRuleService.setRule(
Hyunsun Moon44aac662017-02-18 02:07:01 +0900269 appId,
Hyunsun Moon0d457362017-06-27 17:19:41 +0900270 gNode.intgBridge(),
Hyunsun Moon44aac662017-02-18 02:07:01 +0900271 externalSelector,
daniel parkee8700b2017-05-11 15:50:03 +0900272 externalBuilder.build(),
Hyunsun Moon44aac662017-02-18 02:07:01 +0900273 PRIORITY_FLOATING_EXTERNAL,
sanghodc375372017-06-08 10:41:30 +0900274 GW_COMMON_TABLE,
Hyunsun Moon44aac662017-02-18 02:07:01 +0900275 install);
276
Hyunsun Moon0d457362017-06-27 17:19:41 +0900277 // access from one VM to the others via floating IP
Hyunsun Moon44aac662017-02-18 02:07:01 +0900278 TrafficSelector internalSelector = DefaultTrafficSelector.builder()
279 .matchEthType(Ethernet.TYPE_IPV4)
280 .matchIPDst(floating.toIpPrefix())
Hyunsun Moon0d457362017-06-27 17:19:41 +0900281 .matchInPort(gNode.tunnelPortNum())
Hyunsun Moon44aac662017-02-18 02:07:01 +0900282 .build();
283
daniel parkee8700b2017-05-11 15:50:03 +0900284 TrafficTreatment.Builder internalBuilder = DefaultTrafficTreatment.builder()
Hyunsun Moon44aac662017-02-18 02:07:01 +0900285 .setEthSrc(Constants.DEFAULT_GATEWAY_MAC)
286 .setEthDst(instPort.macAddress())
daniel parkee8700b2017-05-11 15:50:03 +0900287 .setIpDst(instPort.ipAddress().getIp4Address());
288
289 switch (osNet.getNetworkType()) {
290 case VXLAN:
291 internalBuilder.setTunnelId(Long.valueOf(osNet.getProviderSegID()))
292 .extension(buildExtension(
293 deviceService,
Hyunsun Moon0d457362017-06-27 17:19:41 +0900294 gNode.intgBridge(),
295 cNode.dataIp().getIp4Address()),
296 gNode.intgBridge())
daniel parkee8700b2017-05-11 15:50:03 +0900297 .setOutput(PortNumber.IN_PORT);
298 break;
299 case VLAN:
300 internalBuilder.pushVlan()
301 .setVlanId(VlanId.vlanId(osNet.getProviderSegID()))
302 .setOutput(PortNumber.IN_PORT);
303 break;
304 default:
Ray Milkeyc6c9b172018-02-26 09:36:31 -0800305 final String error = String.format(ERR_UNSUPPORTED_NET_TYPE,
Hyunsun Moon0d457362017-06-27 17:19:41 +0900306 osNet.getNetworkType());
daniel parkee8700b2017-05-11 15:50:03 +0900307 throw new IllegalStateException(error);
308 }
Hyunsun Moon44aac662017-02-18 02:07:01 +0900309
sanghodc375372017-06-08 10:41:30 +0900310 osFlowRuleService.setRule(
Hyunsun Moon44aac662017-02-18 02:07:01 +0900311 appId,
Hyunsun Moon0d457362017-06-27 17:19:41 +0900312 gNode.intgBridge(),
Hyunsun Moon44aac662017-02-18 02:07:01 +0900313 internalSelector,
daniel parkee8700b2017-05-11 15:50:03 +0900314 internalBuilder.build(),
Hyunsun Moon44aac662017-02-18 02:07:01 +0900315 PRIORITY_FLOATING_INTERNAL,
sanghodc375372017-06-08 10:41:30 +0900316 GW_COMMON_TABLE,
Hyunsun Moon44aac662017-02-18 02:07:01 +0900317 install);
318 });
319 }
320
321 private void setUpstreamRules(NetFloatingIP floatingIp, Network osNet,
322 InstancePort instPort, boolean install) {
323 IpAddress floating = IpAddress.valueOf(floatingIp.getFloatingIpAddress());
daniel parkee8700b2017-05-11 15:50:03 +0900324 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder()
Hyunsun Moon44aac662017-02-18 02:07:01 +0900325 .matchEthType(Ethernet.TYPE_IPV4)
daniel parkee8700b2017-05-11 15:50:03 +0900326 .matchIPSrc(instPort.ipAddress().toIpPrefix());
327
328 switch (osNet.getNetworkType()) {
329 case VXLAN:
330 sBuilder.matchTunnelId(Long.valueOf(osNet.getProviderSegID()));
331 break;
332 case VLAN:
333 sBuilder.matchVlanId(VlanId.vlanId(osNet.getProviderSegID()));
334 break;
335 default:
Ray Milkeyc6c9b172018-02-26 09:36:31 -0800336 final String error = String.format(ERR_UNSUPPORTED_NET_TYPE,
Hyunsun Moon0d457362017-06-27 17:19:41 +0900337 osNet.getNetworkType());
daniel parkee8700b2017-05-11 15:50:03 +0900338 throw new IllegalStateException(error);
339 }
Hyunsun Moon44aac662017-02-18 02:07:01 +0900340
daniel parkeeb8e042018-02-21 14:06:58 +0900341 MacAddress externalPeerRouterMac = externalPeerRouterMac(osNet);
342 if (externalPeerRouterMac == null) {
343 return;
344 }
345
346
Hyunsun Moon0d457362017-06-27 17:19:41 +0900347 osNodeService.completeNodes(GATEWAY).forEach(gNode -> {
daniel parkee8700b2017-05-11 15:50:03 +0900348 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder()
Hyunsun Moon44aac662017-02-18 02:07:01 +0900349 .setIpSrc(floating.getIp4Address())
daniel parkeeb8e042018-02-21 14:06:58 +0900350 .setEthSrc(instPort.macAddress())
351 .setEthDst(externalPeerRouterMac);
daniel parkee8700b2017-05-11 15:50:03 +0900352
353 if (osNet.getNetworkType().equals(NetworkType.VLAN)) {
354 tBuilder.popVlan();
355 }
Hyunsun Moon44aac662017-02-18 02:07:01 +0900356
sanghodc375372017-06-08 10:41:30 +0900357 osFlowRuleService.setRule(
Hyunsun Moon44aac662017-02-18 02:07:01 +0900358 appId,
Hyunsun Moon0d457362017-06-27 17:19:41 +0900359 gNode.intgBridge(),
daniel parkee8700b2017-05-11 15:50:03 +0900360 sBuilder.build(),
daniel parkeeb8e042018-02-21 14:06:58 +0900361 tBuilder.setOutput(gNode.uplinkPortNum()).build(),
Hyunsun Moon44aac662017-02-18 02:07:01 +0900362 PRIORITY_FLOATING_EXTERNAL,
sanghodc375372017-06-08 10:41:30 +0900363 GW_COMMON_TABLE,
Hyunsun Moon44aac662017-02-18 02:07:01 +0900364 install);
365 });
366 }
367
daniel parkeeb8e042018-02-21 14:06:58 +0900368 private MacAddress externalPeerRouterMac(Network network) {
369 if (network == null) {
370 return null;
371 }
372
373 Subnet subnet = osNetworkService.subnets(network.getId()).stream().findAny().orElse(null);
374
375 if (subnet == null) {
376 return null;
377 }
378
379 RouterInterface osRouterIface = osRouterService.routerInterfaces().stream()
380 .filter(i -> Objects.equals(i.getSubnetId(), subnet.getId()))
381 .findAny().orElse(null);
382 if (osRouterIface == null) {
383 return null;
384 }
385
386 Router osRouter = osRouterService.router(osRouterIface.getId());
387 if (osRouter == null) {
388 return null;
389 }
390 if (osRouter.getExternalGatewayInfo() == null) {
391 return null;
392 }
393
394 ExternalGateway exGatewayInfo = osRouter.getExternalGatewayInfo();
395
396 return osNetworkService.externalPeerRouterMac(exGatewayInfo);
397 }
Hyunsun Moon0d457362017-06-27 17:19:41 +0900398 private class InternalFloatingIpListener implements OpenstackRouterListener {
Hyunsun Moon44aac662017-02-18 02:07:01 +0900399
400 @Override
401 public boolean isRelevant(OpenstackRouterEvent event) {
402 // do not allow to proceed without leadership
403 NodeId leader = leadershipService.getLeader(appId.name());
404 if (!Objects.equals(localNodeId, leader)) {
405 return false;
406 }
407 return event.floatingIp() != null;
408 }
409
410 @Override
411 public void event(OpenstackRouterEvent event) {
412 switch (event.type()) {
413 case OPENSTACK_FLOATING_IP_ASSOCIATED:
Hyunsun Moon7a5f9042017-05-11 18:19:01 +0900414 eventExecutor.execute(() -> {
Hyunsun Moonb720e632017-05-16 15:41:36 +0900415 NetFloatingIP osFip = event.floatingIp();
416 associateFloatingIp(osFip);
417 log.info("Associated floating IP {}:{}",
418 osFip.getFloatingIpAddress(), osFip.getFixedIpAddress());
Hyunsun Moon7a5f9042017-05-11 18:19:01 +0900419 });
420 break;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900421 case OPENSTACK_FLOATING_IP_DISASSOCIATED:
422 eventExecutor.execute(() -> {
Hyunsun Moonb720e632017-05-16 15:41:36 +0900423 NetFloatingIP osFip = event.floatingIp();
424 disassociateFloatingIp(osFip, event.portId());
425 log.info("Disassociated floating IP {}:{}",
426 osFip.getFloatingIpAddress(), osFip.getFixedIpAddress());
Hyunsun Moon7a5f9042017-05-11 18:19:01 +0900427 });
428 break;
429 case OPENSTACK_FLOATING_IP_REMOVED:
430 eventExecutor.execute(() -> {
Hyunsun Moonb720e632017-05-16 15:41:36 +0900431 NetFloatingIP osFip = event.floatingIp();
432 if (!Strings.isNullOrEmpty(osFip.getPortId())) {
433 disassociateFloatingIp(osFip, osFip.getPortId());
Hyunsun Moon7a5f9042017-05-11 18:19:01 +0900434 }
Hyunsun Moonb720e632017-05-16 15:41:36 +0900435 log.info("Removed floating IP {}", osFip.getFloatingIpAddress());
Hyunsun Moon44aac662017-02-18 02:07:01 +0900436 });
437 break;
438 case OPENSTACK_FLOATING_IP_CREATED:
Hyunsun Moonb720e632017-05-16 15:41:36 +0900439 eventExecutor.execute(() -> {
440 NetFloatingIP osFip = event.floatingIp();
441 if (!Strings.isNullOrEmpty(osFip.getPortId())) {
442 associateFloatingIp(event.floatingIp());
443 }
444 log.info("Created floating IP {}", osFip.getFloatingIpAddress());
445 });
446 break;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900447 case OPENSTACK_FLOATING_IP_UPDATED:
Hyunsun Moon44aac662017-02-18 02:07:01 +0900448 case OPENSTACK_ROUTER_CREATED:
449 case OPENSTACK_ROUTER_UPDATED:
450 case OPENSTACK_ROUTER_REMOVED:
451 case OPENSTACK_ROUTER_INTERFACE_ADDED:
452 case OPENSTACK_ROUTER_INTERFACE_UPDATED:
453 case OPENSTACK_ROUTER_INTERFACE_REMOVED:
454 default:
455 // do nothing for the other events
456 break;
457 }
458 }
Hyunsun Moonb720e632017-05-16 15:41:36 +0900459
460 private void associateFloatingIp(NetFloatingIP osFip) {
461 Port osPort = osNetworkService.port(osFip.getPortId());
462 if (osPort == null) {
463 final String error = String.format(ERR_FLOW + "port(%s) not found",
464 osFip.getFloatingIpAddress(), osFip.getPortId());
465 throw new IllegalStateException(error);
466 }
467 // set floating IP rules only if the port is associated to a VM
468 if (!Strings.isNullOrEmpty(osPort.getDeviceId())) {
469 setFloatingIpRules(osFip, osPort, true);
470 }
471 }
472
473 private void disassociateFloatingIp(NetFloatingIP osFip, String portId) {
474 Port osPort = osNetworkService.port(portId);
475 if (osPort == null) {
476 // FIXME when a port with floating IP removed without
477 // disassociation step, it can reach here
478 return;
479 }
480 // set floating IP rules only if the port is associated to a VM
481 if (!Strings.isNullOrEmpty(osPort.getDeviceId())) {
482 setFloatingIpRules(osFip, osPort, false);
483 }
484 }
Hyunsun Moon44aac662017-02-18 02:07:01 +0900485 }
486
487 private class InternalNodeListener implements OpenstackNodeListener {
488
489 @Override
490 public boolean isRelevant(OpenstackNodeEvent event) {
491 // do not allow to proceed without leadership
492 NodeId leader = leadershipService.getLeader(appId.name());
493 if (!Objects.equals(localNodeId, leader)) {
494 return false;
495 }
496 return event.subject().type() == GATEWAY;
497 }
498
499 @Override
500 public void event(OpenstackNodeEvent event) {
Hyunsun Moon44aac662017-02-18 02:07:01 +0900501
502 switch (event.type()) {
Hyunsun Moon0d457362017-06-27 17:19:41 +0900503 case OPENSTACK_NODE_COMPLETE:
Hyunsun Moon44aac662017-02-18 02:07:01 +0900504 eventExecutor.execute(() -> {
Hyunsun Moon7a5f9042017-05-11 18:19:01 +0900505 for (NetFloatingIP fip : osRouterService.floatingIps()) {
506 if (Strings.isNullOrEmpty(fip.getPortId())) {
507 continue;
508 }
509 Port osPort = osNetworkService.port(fip.getPortId());
510 if (osPort == null) {
511 log.warn("Failed to set floating IP {}", fip.getId());
512 continue;
513 }
514 setFloatingIpRules(fip, osPort, true);
515 }
Hyunsun Moon44aac662017-02-18 02:07:01 +0900516 });
517 break;
Hyunsun Moon0d457362017-06-27 17:19:41 +0900518 case OPENSTACK_NODE_CREATED:
519 case OPENSTACK_NODE_UPDATED:
520 case OPENSTACK_NODE_REMOVED:
521 case OPENSTACK_NODE_INCOMPLETE:
Hyunsun Moon44aac662017-02-18 02:07:01 +0900522 default:
Hyunsun Moon0d457362017-06-27 17:19:41 +0900523 // do nothing
Hyunsun Moon44aac662017-02-18 02:07:01 +0900524 break;
525 }
526 }
527 }
528}