blob: 16607b155f60de78fbe171d29b45ead987064b0d [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) {
Jian Li71670d12018-03-02 21:31:07 +0900147 final String errorFormat = ERR_FLOW + "no network(%s) exists";
148 final String error = String.format(errorFormat,
Hyunsun Moon44aac662017-02-18 02:07:01 +0900149 floatingIp.getFloatingIpAddress(),
150 osPort.getNetworkId());
151 throw new IllegalStateException(error);
152 }
153
154 MacAddress srcMac = MacAddress.valueOf(osPort.getMacAddress());
155 InstancePort instPort = instancePortService.instancePort(srcMac);
156 if (instPort == null) {
Jian Li71670d12018-03-02 21:31:07 +0900157 final String errorFormat = ERR_FLOW + "no host(MAC:%s) found";
158 final String error = String.format(errorFormat,
Hyunsun Moon44aac662017-02-18 02:07:01 +0900159 floatingIp.getFloatingIpAddress(), srcMac);
160 throw new IllegalStateException(error);
161 }
162
daniel parkeeb8e042018-02-21 14:06:58 +0900163 setComputeNodeToGateway(instPort, osNet, install);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900164 setDownstreamRules(floatingIp, osNet, instPort, install);
165 setUpstreamRules(floatingIp, osNet, instPort, install);
166 }
167
daniel parkeeb8e042018-02-21 14:06:58 +0900168 private void setComputeNodeToGateway(InstancePort instPort, Network osNet, boolean install) {
169 TrafficTreatment treatment;
170
171 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder()
172 .matchEthType(Ethernet.TYPE_IPV4)
173 .matchIPSrc(instPort.ipAddress().toIpPrefix())
174 .matchEthDst(Constants.DEFAULT_GATEWAY_MAC);
175
176 switch (osNet.getNetworkType()) {
177 case VXLAN:
178 sBuilder.matchTunnelId(Long.parseLong(osNet.getProviderSegID()));
179 break;
180 case VLAN:
181 sBuilder.matchVlanId(VlanId.vlanId(osNet.getProviderSegID()));
182 break;
183 default:
184 final String error = String.format(
Ray Milkeyc6c9b172018-02-26 09:36:31 -0800185 ERR_UNSUPPORTED_NET_TYPE,
daniel parkeeb8e042018-02-21 14:06:58 +0900186 osNet.getNetworkType().toString());
187 throw new IllegalStateException(error);
188 }
189
190 OpenstackNode selectedGatewayNode = selectGatewayNode();
191 if (selectedGatewayNode == null) {
192 return;
193 }
194 treatment = DefaultTrafficTreatment.builder()
195 .extension(buildExtension(
196 deviceService,
197 instPort.deviceId(),
198 selectedGatewayNode.dataIp().getIp4Address()),
199 instPort.deviceId())
200 .setOutput(osNodeService.node(instPort.deviceId()).tunnelPortNum())
201 .build();
202
203 osFlowRuleService.setRule(
204 appId,
205 instPort.deviceId(),
206 sBuilder.build(),
207 treatment,
208 PRIORITY_EXTERNAL_FLOATING_ROUTING_RULE,
209 ROUTING_TABLE,
210 install);
211 }
212
213 private OpenstackNode selectGatewayNode() {
214 //TODO support multiple loadbalancing options.
215 return osNodeService.completeNodes(GATEWAY).stream().findAny().orElse(null);
216 }
217
Hyunsun Moon44aac662017-02-18 02:07:01 +0900218 private void setDownstreamRules(NetFloatingIP floatingIp, Network osNet,
219 InstancePort instPort, boolean install) {
Hyunsun Moon0d457362017-06-27 17:19:41 +0900220 OpenstackNode cNode = osNodeService.node(instPort.deviceId());
221 if (cNode == null) {
222 final String error = String.format("Cannot find openstack node for device %s",
223 instPort.deviceId());
224 throw new IllegalStateException(error);
225 }
226 if (osNet.getNetworkType() == NetworkType.VXLAN && cNode.dataIp() == null) {
Jian Li71670d12018-03-02 21:31:07 +0900227 final String errorFormat = ERR_FLOW + "VXLAN mode is not ready for %s";
228 final String error = String.format(errorFormat, floatingIp, cNode.hostname());
Hyunsun Moon0d457362017-06-27 17:19:41 +0900229 throw new IllegalStateException(error);
230 }
231 if (osNet.getNetworkType() == NetworkType.VLAN && cNode.vlanIntf() == null) {
Jian Li71670d12018-03-02 21:31:07 +0900232 final String errorFormat = ERR_FLOW + "VLAN mode is not ready for %s";
233 final String error = String.format(errorFormat, floatingIp, cNode.hostname());
Hyunsun Moon0d457362017-06-27 17:19:41 +0900234 throw new IllegalStateException(error);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900235 }
236
237 IpAddress floating = IpAddress.valueOf(floatingIp.getFloatingIpAddress());
238 TrafficSelector externalSelector = DefaultTrafficSelector.builder()
239 .matchEthType(Ethernet.TYPE_IPV4)
240 .matchIPDst(floating.toIpPrefix())
241 .build();
242
Hyunsun Moon0d457362017-06-27 17:19:41 +0900243 osNodeService.completeNodes(GATEWAY).forEach(gNode -> {
daniel parkee8700b2017-05-11 15:50:03 +0900244 TrafficTreatment.Builder externalBuilder = DefaultTrafficTreatment.builder()
Hyunsun Moon44aac662017-02-18 02:07:01 +0900245 .setEthSrc(Constants.DEFAULT_GATEWAY_MAC)
246 .setEthDst(instPort.macAddress())
daniel parkee8700b2017-05-11 15:50:03 +0900247 .setIpDst(instPort.ipAddress().getIp4Address());
248
249 switch (osNet.getNetworkType()) {
250 case VXLAN:
251 externalBuilder.setTunnelId(Long.valueOf(osNet.getProviderSegID()))
252 .extension(buildExtension(
253 deviceService,
Hyunsun Moon0d457362017-06-27 17:19:41 +0900254 gNode.intgBridge(),
255 cNode.dataIp().getIp4Address()),
256 gNode.intgBridge())
257 .setOutput(gNode.tunnelPortNum());
daniel parkee8700b2017-05-11 15:50:03 +0900258 break;
259 case VLAN:
260 externalBuilder.pushVlan()
261 .setVlanId(VlanId.vlanId(osNet.getProviderSegID()))
Hyunsun Moon0d457362017-06-27 17:19:41 +0900262 .setOutput(gNode.vlanPortNum());
daniel parkee8700b2017-05-11 15:50:03 +0900263 break;
264 default:
Ray Milkeyc6c9b172018-02-26 09:36:31 -0800265 final String error = String.format(ERR_UNSUPPORTED_NET_TYPE,
Hyunsun Moon0d457362017-06-27 17:19:41 +0900266 osNet.getNetworkType());
daniel parkee8700b2017-05-11 15:50:03 +0900267 throw new IllegalStateException(error);
268 }
Hyunsun Moon44aac662017-02-18 02:07:01 +0900269
sanghodc375372017-06-08 10:41:30 +0900270 osFlowRuleService.setRule(
Hyunsun Moon44aac662017-02-18 02:07:01 +0900271 appId,
Hyunsun Moon0d457362017-06-27 17:19:41 +0900272 gNode.intgBridge(),
Hyunsun Moon44aac662017-02-18 02:07:01 +0900273 externalSelector,
daniel parkee8700b2017-05-11 15:50:03 +0900274 externalBuilder.build(),
Hyunsun Moon44aac662017-02-18 02:07:01 +0900275 PRIORITY_FLOATING_EXTERNAL,
sanghodc375372017-06-08 10:41:30 +0900276 GW_COMMON_TABLE,
Hyunsun Moon44aac662017-02-18 02:07:01 +0900277 install);
278
Hyunsun Moon0d457362017-06-27 17:19:41 +0900279 // access from one VM to the others via floating IP
Hyunsun Moon44aac662017-02-18 02:07:01 +0900280 TrafficSelector internalSelector = DefaultTrafficSelector.builder()
281 .matchEthType(Ethernet.TYPE_IPV4)
282 .matchIPDst(floating.toIpPrefix())
Hyunsun Moon0d457362017-06-27 17:19:41 +0900283 .matchInPort(gNode.tunnelPortNum())
Hyunsun Moon44aac662017-02-18 02:07:01 +0900284 .build();
285
daniel parkee8700b2017-05-11 15:50:03 +0900286 TrafficTreatment.Builder internalBuilder = DefaultTrafficTreatment.builder()
Hyunsun Moon44aac662017-02-18 02:07:01 +0900287 .setEthSrc(Constants.DEFAULT_GATEWAY_MAC)
288 .setEthDst(instPort.macAddress())
daniel parkee8700b2017-05-11 15:50:03 +0900289 .setIpDst(instPort.ipAddress().getIp4Address());
290
291 switch (osNet.getNetworkType()) {
292 case VXLAN:
293 internalBuilder.setTunnelId(Long.valueOf(osNet.getProviderSegID()))
294 .extension(buildExtension(
295 deviceService,
Hyunsun Moon0d457362017-06-27 17:19:41 +0900296 gNode.intgBridge(),
297 cNode.dataIp().getIp4Address()),
298 gNode.intgBridge())
daniel parkee8700b2017-05-11 15:50:03 +0900299 .setOutput(PortNumber.IN_PORT);
300 break;
301 case VLAN:
302 internalBuilder.pushVlan()
303 .setVlanId(VlanId.vlanId(osNet.getProviderSegID()))
304 .setOutput(PortNumber.IN_PORT);
305 break;
306 default:
Ray Milkeyc6c9b172018-02-26 09:36:31 -0800307 final String error = String.format(ERR_UNSUPPORTED_NET_TYPE,
Hyunsun Moon0d457362017-06-27 17:19:41 +0900308 osNet.getNetworkType());
daniel parkee8700b2017-05-11 15:50:03 +0900309 throw new IllegalStateException(error);
310 }
Hyunsun Moon44aac662017-02-18 02:07:01 +0900311
sanghodc375372017-06-08 10:41:30 +0900312 osFlowRuleService.setRule(
Hyunsun Moon44aac662017-02-18 02:07:01 +0900313 appId,
Hyunsun Moon0d457362017-06-27 17:19:41 +0900314 gNode.intgBridge(),
Hyunsun Moon44aac662017-02-18 02:07:01 +0900315 internalSelector,
daniel parkee8700b2017-05-11 15:50:03 +0900316 internalBuilder.build(),
Hyunsun Moon44aac662017-02-18 02:07:01 +0900317 PRIORITY_FLOATING_INTERNAL,
sanghodc375372017-06-08 10:41:30 +0900318 GW_COMMON_TABLE,
Hyunsun Moon44aac662017-02-18 02:07:01 +0900319 install);
320 });
321 }
322
323 private void setUpstreamRules(NetFloatingIP floatingIp, Network osNet,
324 InstancePort instPort, boolean install) {
325 IpAddress floating = IpAddress.valueOf(floatingIp.getFloatingIpAddress());
daniel parkee8700b2017-05-11 15:50:03 +0900326 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder()
Hyunsun Moon44aac662017-02-18 02:07:01 +0900327 .matchEthType(Ethernet.TYPE_IPV4)
daniel parkee8700b2017-05-11 15:50:03 +0900328 .matchIPSrc(instPort.ipAddress().toIpPrefix());
329
330 switch (osNet.getNetworkType()) {
331 case VXLAN:
332 sBuilder.matchTunnelId(Long.valueOf(osNet.getProviderSegID()));
333 break;
334 case VLAN:
335 sBuilder.matchVlanId(VlanId.vlanId(osNet.getProviderSegID()));
336 break;
337 default:
Ray Milkeyc6c9b172018-02-26 09:36:31 -0800338 final String error = String.format(ERR_UNSUPPORTED_NET_TYPE,
Hyunsun Moon0d457362017-06-27 17:19:41 +0900339 osNet.getNetworkType());
daniel parkee8700b2017-05-11 15:50:03 +0900340 throw new IllegalStateException(error);
341 }
Hyunsun Moon44aac662017-02-18 02:07:01 +0900342
daniel parkeeb8e042018-02-21 14:06:58 +0900343 MacAddress externalPeerRouterMac = externalPeerRouterMac(osNet);
344 if (externalPeerRouterMac == null) {
345 return;
346 }
347
348
Hyunsun Moon0d457362017-06-27 17:19:41 +0900349 osNodeService.completeNodes(GATEWAY).forEach(gNode -> {
daniel parkee8700b2017-05-11 15:50:03 +0900350 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder()
Hyunsun Moon44aac662017-02-18 02:07:01 +0900351 .setIpSrc(floating.getIp4Address())
daniel parkeeb8e042018-02-21 14:06:58 +0900352 .setEthSrc(instPort.macAddress())
353 .setEthDst(externalPeerRouterMac);
daniel parkee8700b2017-05-11 15:50:03 +0900354
355 if (osNet.getNetworkType().equals(NetworkType.VLAN)) {
356 tBuilder.popVlan();
357 }
Hyunsun Moon44aac662017-02-18 02:07:01 +0900358
sanghodc375372017-06-08 10:41:30 +0900359 osFlowRuleService.setRule(
Hyunsun Moon44aac662017-02-18 02:07:01 +0900360 appId,
Hyunsun Moon0d457362017-06-27 17:19:41 +0900361 gNode.intgBridge(),
daniel parkee8700b2017-05-11 15:50:03 +0900362 sBuilder.build(),
daniel parkeeb8e042018-02-21 14:06:58 +0900363 tBuilder.setOutput(gNode.uplinkPortNum()).build(),
Hyunsun Moon44aac662017-02-18 02:07:01 +0900364 PRIORITY_FLOATING_EXTERNAL,
sanghodc375372017-06-08 10:41:30 +0900365 GW_COMMON_TABLE,
Hyunsun Moon44aac662017-02-18 02:07:01 +0900366 install);
367 });
368 }
369
daniel parkeeb8e042018-02-21 14:06:58 +0900370 private MacAddress externalPeerRouterMac(Network network) {
371 if (network == null) {
372 return null;
373 }
374
375 Subnet subnet = osNetworkService.subnets(network.getId()).stream().findAny().orElse(null);
376
377 if (subnet == null) {
378 return null;
379 }
380
381 RouterInterface osRouterIface = osRouterService.routerInterfaces().stream()
382 .filter(i -> Objects.equals(i.getSubnetId(), subnet.getId()))
383 .findAny().orElse(null);
384 if (osRouterIface == null) {
385 return null;
386 }
387
388 Router osRouter = osRouterService.router(osRouterIface.getId());
389 if (osRouter == null) {
390 return null;
391 }
392 if (osRouter.getExternalGatewayInfo() == null) {
393 return null;
394 }
395
396 ExternalGateway exGatewayInfo = osRouter.getExternalGatewayInfo();
397
398 return osNetworkService.externalPeerRouterMac(exGatewayInfo);
399 }
Hyunsun Moon0d457362017-06-27 17:19:41 +0900400 private class InternalFloatingIpListener implements OpenstackRouterListener {
Hyunsun Moon44aac662017-02-18 02:07:01 +0900401
402 @Override
403 public boolean isRelevant(OpenstackRouterEvent event) {
404 // do not allow to proceed without leadership
405 NodeId leader = leadershipService.getLeader(appId.name());
406 if (!Objects.equals(localNodeId, leader)) {
407 return false;
408 }
409 return event.floatingIp() != null;
410 }
411
412 @Override
413 public void event(OpenstackRouterEvent event) {
414 switch (event.type()) {
415 case OPENSTACK_FLOATING_IP_ASSOCIATED:
Hyunsun Moon7a5f9042017-05-11 18:19:01 +0900416 eventExecutor.execute(() -> {
Hyunsun Moonb720e632017-05-16 15:41:36 +0900417 NetFloatingIP osFip = event.floatingIp();
418 associateFloatingIp(osFip);
419 log.info("Associated floating IP {}:{}",
420 osFip.getFloatingIpAddress(), osFip.getFixedIpAddress());
Hyunsun Moon7a5f9042017-05-11 18:19:01 +0900421 });
422 break;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900423 case OPENSTACK_FLOATING_IP_DISASSOCIATED:
424 eventExecutor.execute(() -> {
Hyunsun Moonb720e632017-05-16 15:41:36 +0900425 NetFloatingIP osFip = event.floatingIp();
426 disassociateFloatingIp(osFip, event.portId());
427 log.info("Disassociated floating IP {}:{}",
428 osFip.getFloatingIpAddress(), osFip.getFixedIpAddress());
Hyunsun Moon7a5f9042017-05-11 18:19:01 +0900429 });
430 break;
431 case OPENSTACK_FLOATING_IP_REMOVED:
432 eventExecutor.execute(() -> {
Hyunsun Moonb720e632017-05-16 15:41:36 +0900433 NetFloatingIP osFip = event.floatingIp();
434 if (!Strings.isNullOrEmpty(osFip.getPortId())) {
435 disassociateFloatingIp(osFip, osFip.getPortId());
Hyunsun Moon7a5f9042017-05-11 18:19:01 +0900436 }
Hyunsun Moonb720e632017-05-16 15:41:36 +0900437 log.info("Removed floating IP {}", osFip.getFloatingIpAddress());
Hyunsun Moon44aac662017-02-18 02:07:01 +0900438 });
439 break;
440 case OPENSTACK_FLOATING_IP_CREATED:
Hyunsun Moonb720e632017-05-16 15:41:36 +0900441 eventExecutor.execute(() -> {
442 NetFloatingIP osFip = event.floatingIp();
443 if (!Strings.isNullOrEmpty(osFip.getPortId())) {
444 associateFloatingIp(event.floatingIp());
445 }
446 log.info("Created floating IP {}", osFip.getFloatingIpAddress());
447 });
448 break;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900449 case OPENSTACK_FLOATING_IP_UPDATED:
Hyunsun Moon44aac662017-02-18 02:07:01 +0900450 case OPENSTACK_ROUTER_CREATED:
451 case OPENSTACK_ROUTER_UPDATED:
452 case OPENSTACK_ROUTER_REMOVED:
453 case OPENSTACK_ROUTER_INTERFACE_ADDED:
454 case OPENSTACK_ROUTER_INTERFACE_UPDATED:
455 case OPENSTACK_ROUTER_INTERFACE_REMOVED:
456 default:
457 // do nothing for the other events
458 break;
459 }
460 }
Hyunsun Moonb720e632017-05-16 15:41:36 +0900461
462 private void associateFloatingIp(NetFloatingIP osFip) {
463 Port osPort = osNetworkService.port(osFip.getPortId());
464 if (osPort == null) {
Jian Li71670d12018-03-02 21:31:07 +0900465 final String errorFormat = ERR_FLOW + "port(%s) not found";
466 final String error = String.format(errorFormat,
Hyunsun Moonb720e632017-05-16 15:41:36 +0900467 osFip.getFloatingIpAddress(), osFip.getPortId());
468 throw new IllegalStateException(error);
469 }
470 // set floating IP rules only if the port is associated to a VM
471 if (!Strings.isNullOrEmpty(osPort.getDeviceId())) {
472 setFloatingIpRules(osFip, osPort, true);
473 }
474 }
475
476 private void disassociateFloatingIp(NetFloatingIP osFip, String portId) {
477 Port osPort = osNetworkService.port(portId);
478 if (osPort == null) {
479 // FIXME when a port with floating IP removed without
480 // disassociation step, it can reach here
481 return;
482 }
483 // set floating IP rules only if the port is associated to a VM
484 if (!Strings.isNullOrEmpty(osPort.getDeviceId())) {
485 setFloatingIpRules(osFip, osPort, false);
486 }
487 }
Hyunsun Moon44aac662017-02-18 02:07:01 +0900488 }
489
490 private class InternalNodeListener implements OpenstackNodeListener {
491
492 @Override
493 public boolean isRelevant(OpenstackNodeEvent event) {
494 // do not allow to proceed without leadership
495 NodeId leader = leadershipService.getLeader(appId.name());
496 if (!Objects.equals(localNodeId, leader)) {
497 return false;
498 }
499 return event.subject().type() == GATEWAY;
500 }
501
502 @Override
503 public void event(OpenstackNodeEvent event) {
Hyunsun Moon44aac662017-02-18 02:07:01 +0900504
505 switch (event.type()) {
Hyunsun Moon0d457362017-06-27 17:19:41 +0900506 case OPENSTACK_NODE_COMPLETE:
Hyunsun Moon44aac662017-02-18 02:07:01 +0900507 eventExecutor.execute(() -> {
Hyunsun Moon7a5f9042017-05-11 18:19:01 +0900508 for (NetFloatingIP fip : osRouterService.floatingIps()) {
509 if (Strings.isNullOrEmpty(fip.getPortId())) {
510 continue;
511 }
512 Port osPort = osNetworkService.port(fip.getPortId());
513 if (osPort == null) {
514 log.warn("Failed to set floating IP {}", fip.getId());
515 continue;
516 }
517 setFloatingIpRules(fip, osPort, true);
518 }
Hyunsun Moon44aac662017-02-18 02:07:01 +0900519 });
520 break;
Hyunsun Moon0d457362017-06-27 17:19:41 +0900521 case OPENSTACK_NODE_CREATED:
522 case OPENSTACK_NODE_UPDATED:
523 case OPENSTACK_NODE_REMOVED:
524 case OPENSTACK_NODE_INCOMPLETE:
Hyunsun Moon44aac662017-02-18 02:07:01 +0900525 default:
Hyunsun Moon0d457362017-06-27 17:19:41 +0900526 // do nothing
Hyunsun Moon44aac662017-02-18 02:07:01 +0900527 break;
528 }
529 }
530 }
531}