blob: 31bb899f1ea7d58ae44621cf9313108e2994b9ca [file] [log] [blame]
sangho0c2a3da2016-02-16 13:39:07 +09001/*
Brian O'Connor5ab426f2016-04-09 01:19:45 -07002 * Copyright 2016-present Open Networking Laboratory
sangho0c2a3da2016-02-16 13:39:07 +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.routing;
17
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -070018import com.google.common.collect.ImmutableSet;
sangho0c2a3da2016-02-16 13:39:07 +090019import 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.apache.felix.scr.annotations.Service;
25import org.onlab.packet.Ethernet;
Daniel Parka8d896c2016-08-26 14:31:33 +090026import org.onlab.packet.IPv4;
sangho0c2a3da2016-02-16 13:39:07 +090027import org.onlab.packet.Ip4Address;
sangho3d2bf9c2016-08-26 17:19:55 +090028import org.onlab.packet.IpPrefix;
sangho0c2a3da2016-02-16 13:39:07 +090029import org.onlab.packet.MacAddress;
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -070030import org.onlab.util.Tools;
sangho0c2a3da2016-02-16 13:39:07 +090031import org.onosproject.core.ApplicationId;
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -070032import org.onosproject.core.GroupId;
Kyuhwi Choie2b37e32016-02-05 14:04:14 +090033import org.onosproject.net.DeviceId;
sangho6032f342016-07-07 14:32:03 +090034import org.onosproject.net.Host;
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -070035import org.onosproject.net.PortNumber;
sangho0c2a3da2016-02-16 13:39:07 +090036import org.onosproject.net.device.DeviceService;
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -070037import org.onosproject.net.flow.DefaultTrafficSelector;
38import org.onosproject.net.flow.DefaultTrafficTreatment;
39import org.onosproject.net.flow.TrafficSelector;
40import org.onosproject.net.flow.TrafficTreatment;
41import org.onosproject.net.flowobjective.DefaultForwardingObjective;
sangho0c2a3da2016-02-16 13:39:07 +090042import org.onosproject.net.flowobjective.FlowObjectiveService;
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -070043import org.onosproject.net.flowobjective.ForwardingObjective;
sangho93447f12016-02-24 00:33:22 +090044import org.onosproject.openstackinterface.OpenstackInterfaceService;
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -070045import org.onosproject.openstackinterface.OpenstackNetwork;
sangho93447f12016-02-24 00:33:22 +090046import org.onosproject.openstackinterface.OpenstackPort;
47import org.onosproject.openstackinterface.OpenstackRouter;
48import org.onosproject.openstackinterface.OpenstackRouterInterface;
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -070049import org.onosproject.openstackinterface.OpenstackSubnet;
50import org.onosproject.openstacknetworking.AbstractVmHandler;
sangho6032f342016-07-07 14:32:03 +090051import org.onosproject.openstacknetworking.Constants;
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -070052import org.onosproject.openstacknetworking.OpenstackRoutingService;
53import org.onosproject.openstacknetworking.RulePopulatorUtil;
sangho6032f342016-07-07 14:32:03 +090054import org.onosproject.openstacknode.OpenstackNode;
55import org.onosproject.openstacknode.OpenstackNodeEvent;
56import org.onosproject.openstacknode.OpenstackNodeListener;
57import org.onosproject.openstacknode.OpenstackNodeService;
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -070058import org.onosproject.scalablegateway.api.GatewayNode;
59import org.onosproject.scalablegateway.api.ScalableGatewayService;
sangho0c2a3da2016-02-16 13:39:07 +090060import org.slf4j.Logger;
61import org.slf4j.LoggerFactory;
62
sangho3d2bf9c2016-08-26 17:19:55 +090063import java.util.HashMap;
64import java.util.Map;
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -070065import java.util.Objects;
Daniel Park23193902016-03-24 18:17:19 +090066import java.util.Optional;
sangho6032f342016-07-07 14:32:03 +090067import java.util.Set;
sangho0c2a3da2016-02-16 13:39:07 +090068import java.util.concurrent.ExecutorService;
sangho0c2a3da2016-02-16 13:39:07 +090069import java.util.stream.Collectors;
70
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -070071import static java.util.concurrent.Executors.newSingleThreadScheduledExecutor;
sangho0c2a3da2016-02-16 13:39:07 +090072import static org.onlab.util.Tools.groupedThreads;
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -070073import static org.onosproject.openstacknetworking.Constants.*;
74import static org.onosproject.openstacknetworking.RulePopulatorUtil.buildExtension;
75import static org.onosproject.openstacknode.OpenstackNodeService.NodeType.COMPUTE;
76import static org.onosproject.openstacknode.OpenstackNodeService.NodeType.GATEWAY;
sangho0c2a3da2016-02-16 13:39:07 +090077
sangho0c2a3da2016-02-16 13:39:07 +090078@Component(immediate = true)
Kyuhwi Choie2b37e32016-02-05 14:04:14 +090079@Service
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -070080public class OpenstackRoutingManager extends AbstractVmHandler implements OpenstackRoutingService {
Kyuhwi Choie2b37e32016-02-05 14:04:14 +090081
82 private final Logger log = LoggerFactory.getLogger(getClass());
sangho0c2a3da2016-02-16 13:39:07 +090083
84 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -070085 protected FlowObjectiveService flowObjectiveService;
sangho0c2a3da2016-02-16 13:39:07 +090086
87 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
88 protected DeviceService deviceService;
89
90 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
sangho93447f12016-02-24 00:33:22 +090091 protected OpenstackInterfaceService openstackService;
sangho0c2a3da2016-02-16 13:39:07 +090092
93 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -070094 protected OpenstackNodeService nodeService;
sangho6032f342016-07-07 14:32:03 +090095
96 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Kyuhwi Choi92d9ea42016-06-13 17:28:00 +090097 protected ScalableGatewayService gatewayService;
Daniel Park23193902016-03-24 18:17:19 +090098
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -070099 private final ExecutorService eventExecutor = newSingleThreadScheduledExecutor(
100 groupedThreads(this.getClass().getSimpleName(), "event-handler", log));
101 private final InternalNodeListener nodeListener = new InternalNodeListener();
sangho6032f342016-07-07 14:32:03 +0900102
sangho0c2a3da2016-02-16 13:39:07 +0900103 private ApplicationId appId;
sangho0c2a3da2016-02-16 13:39:07 +0900104
105 @Activate
106 protected void activate() {
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700107 super.activate();
108 appId = coreService.registerApplication(ROUTING_APP_ID);
109 nodeService.addListener(nodeListener);
sangho0c2a3da2016-02-16 13:39:07 +0900110 }
111
112 @Deactivate
113 protected void deactivate() {
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700114 nodeService.removeListener(nodeListener);
Kyuhwi Choi5e65e2c2016-04-01 11:48:15 +0900115 log.info("stopped");
sangho0c2a3da2016-02-16 13:39:07 +0900116 }
117
sangho0c2a3da2016-02-16 13:39:07 +0900118 @Override
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700119 public void createRouter(OpenstackRouter osRouter) {
sangho0c2a3da2016-02-16 13:39:07 +0900120 }
121
122 @Override
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700123 public void updateRouter(OpenstackRouter osRouter) {
124 if (osRouter.gatewayExternalInfo().externalFixedIps().size() > 0) {
125 openstackService.ports().stream()
126 .filter(osPort -> osPort.deviceOwner().equals(DEVICE_OWNER_ROUTER_INTERFACE) &&
127 osPort.deviceId().equals(osRouter.id()))
sangho3d2bf9c2016-08-26 17:19:55 +0900128 .forEach(osPort -> {
129 String subnetId = osPort.fixedIps().keySet().stream().findFirst().get();
130 setExternalConnection(osRouter, subnetId);
131 });
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700132
133 log.info("Connected external gateway {} to router {}",
134 osRouter.gatewayExternalInfo().externalFixedIps(),
135 osRouter.name());
136 } else {
137 openstackService.ports().stream()
138 .filter(osPort -> osPort.deviceOwner().equals(DEVICE_OWNER_ROUTER_INTERFACE) &&
139 osPort.deviceId().equals(osRouter.id()))
140 .forEach(osPort -> unsetExternalConnection(osRouter, osPort.networkId()));
141
142 log.info("Disconnected external gateway from router {}",
143 osRouter.name());
144 }
145 }
146
147 @Override
148 public void removeRouter(String osRouterId) {
149 // TODO implement this
150 }
151
152 @Override
153 public void addRouterInterface(OpenstackRouterInterface routerIface) {
154 OpenstackRouter osRouter = openstackRouter(routerIface.id());
155 OpenstackPort osPort = openstackService.port(routerIface.portId());
156 if (osRouter == null || osPort == null) {
157 log.warn("Failed to add router interface {}", routerIface);
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900158 return;
159 }
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700160
Daniel Parka8d896c2016-08-26 14:31:33 +0900161 setGatewayIcmp(Ip4Address.valueOf(openstackService.subnet(routerIface.subnetId()).gatewayIp()));
162
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700163 setRoutes(osRouter, Optional.empty());
164 if (osRouter.gatewayExternalInfo().externalFixedIps().size() > 0) {
sangho3d2bf9c2016-08-26 17:19:55 +0900165 String subnetId = osPort.fixedIps().keySet().stream().findFirst().get();
166 setExternalConnection(osRouter, subnetId);
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900167 }
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700168 log.info("Connected {} to router {}", osPort.fixedIps(), osRouter.name());
sangho0c2a3da2016-02-16 13:39:07 +0900169 }
170
171 @Override
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700172 public void removeRouterInterface(OpenstackRouterInterface routerIface) {
173 OpenstackRouter osRouter = openstackService.router(routerIface.id());
174 if (osRouter == null) {
175 log.warn("Failed to remove router interface {}", routerIface);
Kyuhwi Choi5e65e2c2016-04-01 11:48:15 +0900176 return;
177 }
sanghod177f8f2016-06-29 21:52:23 +0900178
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700179 OpenstackSubnet osSubnet = openstackService.subnet(routerIface.subnetId());
180 OpenstackNetwork osNet = openstackService.network(osSubnet.networkId());
181
Daniel Parka8d896c2016-08-26 14:31:33 +0900182 unsetGatewayIcmp(Ip4Address.valueOf(openstackService.subnet(routerIface.subnetId()).gatewayIp()));
183
sangho3d2bf9c2016-08-26 17:19:55 +0900184 unsetRoutes(osRouter, osSubnet);
Daniel Parka8d896c2016-08-26 14:31:33 +0900185
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700186 if (osRouter.gatewayExternalInfo().externalFixedIps().size() > 0) {
187 unsetExternalConnection(osRouter, osNet.id());
Kyuhwi Choi5e65e2c2016-04-01 11:48:15 +0900188 }
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700189 log.info("Disconnected {} from router {}", osSubnet.cidr(), osRouter.name());
Kyuhwi Choi5e65e2c2016-04-01 11:48:15 +0900190 }
191
Daniel Parka8d896c2016-08-26 14:31:33 +0900192 private void setGatewayIcmp(Ip4Address gatewayIp) {
193 if (gatewayIp == null) {
194 return;
195 }
196 gatewayService.getGatewayDeviceIds().stream().forEach(deviceId -> {
197 populateGatewayIcmpRule(gatewayIp, deviceId);
198 });
199 }
200
201 private void populateGatewayIcmpRule(Ip4Address gatewayIp, DeviceId deviceId) {
202 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
203 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
204
205 sBuilder.matchEthType(Ethernet.TYPE_IPV4)
206 .matchIPProtocol(IPv4.PROTOCOL_ICMP)
207 .matchIPDst(gatewayIp.toIpPrefix());
208
209 tBuilder.setOutput(PortNumber.CONTROLLER);
210
211 ForwardingObjective fo = DefaultForwardingObjective.builder()
212 .withSelector(sBuilder.build())
213 .withTreatment(tBuilder.build())
214 .withPriority(GATEWAY_ICMP_PRIORITY)
215 .withFlag(ForwardingObjective.Flag.VERSATILE)
216 .fromApp(appId)
217 .add();
218
219 flowObjectiveService.forward(deviceId, fo);
220 }
221
222 private void unsetGatewayIcmp(Ip4Address gatewayIp) {
223 if (gatewayIp == null) {
224 return;
225 }
226 gatewayService.getGatewayDeviceIds().forEach(deviceId -> {
227 removeGatewayIcmpRule(gatewayIp, deviceId);
228 });
229 }
230
231 private void removeGatewayIcmpRule(Ip4Address gatewayIp, DeviceId deviceId) {
232 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
233
234 sBuilder.matchEthType(Ethernet.TYPE_IPV4)
235 .matchIPProtocol(IPv4.PROTOCOL_ICMP)
236 .matchIPDst(gatewayIp.toIpPrefix());
237
238 RulePopulatorUtil.removeRule(flowObjectiveService, appId, deviceId, sBuilder.build(),
239 ForwardingObjective.Flag.VERSATILE, GATEWAY_ICMP_PRIORITY);
240
241 }
sangho3d2bf9c2016-08-26 17:19:55 +0900242 private void setExternalConnection(OpenstackRouter osRouter, String osSubNetId) {
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700243 if (!osRouter.gatewayExternalInfo().isEnablePnat()) {
244 log.debug("Source NAT is disabled");
sangho6032f342016-07-07 14:32:03 +0900245 return;
246 }
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700247
sangho3d2bf9c2016-08-26 17:19:55 +0900248 OpenstackSubnet osSubNet = openstackService.subnet(osSubNetId);
249 OpenstackNetwork osNet = openstackService.network(osSubNet.networkId());
250 populateExternalRules(osNet, osSubNet);
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900251 }
252
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700253 private void unsetExternalConnection(OpenstackRouter osRouter, String osNetId) {
254 if (!osRouter.gatewayExternalInfo().isEnablePnat()) {
255 log.debug("Source NAT is disabled");
256 return;
sangho0c2a3da2016-02-16 13:39:07 +0900257 }
258
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700259 // FIXME router interface is subnet specific, not network
260 OpenstackNetwork osNet = openstackService.network(osNetId);
261 removeExternalRules(osNet);
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900262 }
263
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700264 private void setRoutes(OpenstackRouter osRouter, Optional<Host> host) {
sangho3d2bf9c2016-08-26 17:19:55 +0900265 Set<OpenstackSubnet> routableSubNets = routableSubNets(osRouter.id());
266 if (routableSubNets.size() < 2) {
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700267 // no other subnet interface is connected to this router, do nothing
268 return;
269 }
270
sangho3d2bf9c2016-08-26 17:19:55 +0900271 Set<String> routableSubNetIds = routableSubNets.stream()
272 .map(OpenstackSubnet::id)
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700273 .collect(Collectors.toSet());
274
sangho3d2bf9c2016-08-26 17:19:55 +0900275
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700276 Set<Host> hosts = host.isPresent() ? ImmutableSet.of(host.get()) :
277 Tools.stream(hostService.getHosts())
sangho3d2bf9c2016-08-26 17:19:55 +0900278 .filter(h -> routableSubNetIds.contains(h.annotations().value(SUBNET_ID)))
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700279 .collect(Collectors.toSet());
280
sangho3d2bf9c2016-08-26 17:19:55 +0900281 hosts.forEach(h -> populateRoutingRules(h, routableSubNets));
Kyuhwi Choi92d9ea42016-06-13 17:28:00 +0900282 }
283
sangho3d2bf9c2016-08-26 17:19:55 +0900284 private void unsetRoutes(OpenstackRouter osRouter, OpenstackSubnet osSubNet) {
285 Set<OpenstackSubnet> routableSubNets = routableSubNets(osRouter.id());
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700286 Tools.stream(hostService.getHosts())
287 .filter(h -> Objects.equals(
sangho3d2bf9c2016-08-26 17:19:55 +0900288 h.annotations().value(NETWORK_ID), osSubNet.id()))
289 .forEach(h -> removeRoutingRules(h, routableSubNets));
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700290
sangho3d2bf9c2016-08-26 17:19:55 +0900291 routableSubNets.forEach(n -> {
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700292 Tools.stream(hostService.getHosts())
293 .filter(h -> Objects.equals(
sangho3d2bf9c2016-08-26 17:19:55 +0900294 h.annotations().value(SUBNET_ID),
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700295 n.id()))
sangho3d2bf9c2016-08-26 17:19:55 +0900296 .forEach(h -> removeRoutingRules(h, ImmutableSet.of(osSubNet)));
297 log.debug("Removed between {} to {}", n.name(), osSubNet.name());
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900298 });
sangho0c2a3da2016-02-16 13:39:07 +0900299 }
300
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700301 private OpenstackRouter openstackRouter(String routerId) {
sangho0c2a3da2016-02-16 13:39:07 +0900302 return openstackService.routers().stream().filter(r ->
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700303 r.id().equals(routerId)).iterator().next();
sangho0c2a3da2016-02-16 13:39:07 +0900304 }
305
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700306 private Optional<OpenstackPort> routerIfacePort(String osNetId) {
307 // FIXME router interface is subnet specific, not network
308 return openstackService.ports().stream()
309 .filter(p -> p.deviceOwner().equals(DEVICE_OWNER_ROUTER_INTERFACE) &&
310 p.networkId().equals(osNetId))
sangho6032f342016-07-07 14:32:03 +0900311 .findAny();
312 }
313
sangho3d2bf9c2016-08-26 17:19:55 +0900314 private Set<OpenstackSubnet> routableSubNets(String osRouterId) {
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700315 return openstackService.ports().stream()
316 .filter(p -> p.deviceOwner().equals(DEVICE_OWNER_ROUTER_INTERFACE) &&
317 p.deviceId().equals(osRouterId))
sangho3d2bf9c2016-08-26 17:19:55 +0900318 .map(p -> openstackService.subnet(p.fixedIps().keySet().stream().findFirst().get()))
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700319 .collect(Collectors.toSet());
320 }
sangho6032f342016-07-07 14:32:03 +0900321
sangho3d2bf9c2016-08-26 17:19:55 +0900322 private void populateExternalRules(OpenstackNetwork osNet, OpenstackSubnet osSubNet) {
323 populateCnodeToGateway(Long.valueOf(osNet.segmentId()), osSubNet.cidr());
324 populateGatewayToController(Long.valueOf(osNet.segmentId()), osSubNet.cidr());
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700325 }
326
327 private void removeExternalRules(OpenstackNetwork osNet) {
328 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
329 sBuilder.matchEthType(Ethernet.TYPE_IPV4)
330 .matchTunnelId(Long.valueOf(osNet.segmentId()))
331 .matchEthDst(Constants.DEFAULT_GATEWAY_MAC);
332
Sho SHIMIZUa09e1bb2016-08-01 14:25:25 -0700333 nodeService.completeNodes().forEach(node -> {
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700334 ForwardingObjective.Flag flag = node.type().equals(GATEWAY) ?
335 ForwardingObjective.Flag.VERSATILE :
336 ForwardingObjective.Flag.SPECIFIC;
337
338 RulePopulatorUtil.removeRule(
339 flowObjectiveService,
340 appId,
341 node.intBridge(),
342 sBuilder.build(),
343 flag,
344 ROUTING_RULE_PRIORITY);
345 });
346 }
347
sangho3d2bf9c2016-08-26 17:19:55 +0900348 private void populateRoutingRules(Host host, Set<OpenstackSubnet> osSubNets) {
349 String osSubNetId = host.annotations().value(SUBNET_ID);
350 if (osSubNetId == null) {
Daniel Park81a61a12016-02-26 08:24:44 +0900351 return;
352 }
353
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700354 DeviceId localDevice = host.location().deviceId();
355 PortNumber localPort = host.location().port();
356 if (!nodeService.dataIp(localDevice).isPresent()) {
357 log.warn("Failed to populate L3 rules");
358 return;
sangho6032f342016-07-07 14:32:03 +0900359 }
sanghod177f8f2016-06-29 21:52:23 +0900360
sangho3d2bf9c2016-08-26 17:19:55 +0900361 Map<String, String> vniMap = new HashMap<>();
362 openstackService.networks().stream().forEach(n -> vniMap.put(n.id(), n.segmentId()));
363
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700364 // TODO improve pipeline, do we have to install access rules between networks
365 // for every single VMs?
sangho3d2bf9c2016-08-26 17:19:55 +0900366 osSubNets.stream().filter(osSubNet -> !osSubNet.id().equals(osSubNetId)).forEach(osSubNet -> {
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700367 populateRoutingRulestoSameNode(
368 host.ipAddresses().stream().findFirst().get().getIp4Address(),
369 host.mac(),
370 localPort, localDevice,
sangho3d2bf9c2016-08-26 17:19:55 +0900371 Long.valueOf(vniMap.get(osSubNet.networkId())),
372 osSubNet.cidr());
sanghod177f8f2016-06-29 21:52:23 +0900373
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700374 nodeService.completeNodes().stream()
375 .filter(node -> node.type().equals(COMPUTE))
376 .filter(node -> !node.intBridge().equals(localDevice))
377 .forEach(node -> populateRoutingRulestoDifferentNode(
378 host.ipAddresses().stream().findFirst().get().getIp4Address(),
sangho3d2bf9c2016-08-26 17:19:55 +0900379 Long.valueOf(vniMap.get(osSubNet.networkId())),
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700380 node.intBridge(),
sangho3d2bf9c2016-08-26 17:19:55 +0900381 nodeService.dataIp(localDevice).get().getIp4Address(),
382 osSubNet.cidr()));
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700383 });
Daniel Park81a61a12016-02-26 08:24:44 +0900384 }
385
sangho3d2bf9c2016-08-26 17:19:55 +0900386 private void removeRoutingRules(Host host, Set<OpenstackSubnet> osSubNets) {
387 String osSubNetId = host.annotations().value(SUBNET_ID);
388 if (osSubNetId == null) {
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700389 return;
sangho6032f342016-07-07 14:32:03 +0900390 }
391
sangho3d2bf9c2016-08-26 17:19:55 +0900392 Map<String, String> vniMap = new HashMap<>();
393 openstackService.networks().stream().forEach(n -> vniMap.put(n.id(), n.segmentId()));
394
395 osSubNets.stream().filter(osSubNet -> !osSubNet.id().equals(osSubNetId)).forEach(osSubNet -> {
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700396 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
397 sBuilder.matchEthType(Ethernet.TYPE_IPV4)
398 .matchIPDst(host.ipAddresses().stream().findFirst().get().toIpPrefix())
sangho3d2bf9c2016-08-26 17:19:55 +0900399 .matchIPSrc(IpPrefix.valueOf(osSubNet.cidr()))
400 .matchTunnelId(Long.valueOf(vniMap.get(osSubNet.networkId())));
sangho6032f342016-07-07 14:32:03 +0900401
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700402 nodeService.completeNodes().stream()
403 .filter(node -> node.type().equals(COMPUTE))
404 .forEach(node -> RulePopulatorUtil.removeRule(
405 flowObjectiveService,
406 appId,
407 node.intBridge(),
408 sBuilder.build(),
409 ForwardingObjective.Flag.SPECIFIC,
410 ROUTING_RULE_PRIORITY));
411 });
sangho3d2bf9c2016-08-26 17:19:55 +0900412 log.debug("Removed routing rule from {} to {}", host, osSubNets);
Daniel Park81a61a12016-02-26 08:24:44 +0900413 }
Kyuhwi Choi5e65e2c2016-04-01 11:48:15 +0900414
sangho3d2bf9c2016-08-26 17:19:55 +0900415 private void populateGatewayToController(long vni, String subNetCidr) {
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700416 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
417 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
sangho6032f342016-07-07 14:32:03 +0900418
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700419 sBuilder.matchEthType(Ethernet.TYPE_IPV4)
420 .matchTunnelId(vni)
sangho3d2bf9c2016-08-26 17:19:55 +0900421 .matchIPSrc(IpPrefix.valueOf(subNetCidr))
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700422 .matchEthDst(Constants.DEFAULT_GATEWAY_MAC);
423 tBuilder.setOutput(PortNumber.CONTROLLER);
sangho6032f342016-07-07 14:32:03 +0900424
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700425 ForwardingObjective fo = DefaultForwardingObjective.builder()
426 .withSelector(sBuilder.build())
427 .withTreatment(tBuilder.build())
428 .withFlag(ForwardingObjective.Flag.VERSATILE)
429 .withPriority(ROUTING_RULE_PRIORITY)
430 .fromApp(appId)
431 .add();
sangho6032f342016-07-07 14:32:03 +0900432
Sho SHIMIZUa09e1bb2016-08-01 14:25:25 -0700433 gatewayService.getGatewayDeviceIds().forEach(deviceId -> flowObjectiveService.forward(deviceId, fo));
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700434 }
sangho6032f342016-07-07 14:32:03 +0900435
sangho3d2bf9c2016-08-26 17:19:55 +0900436 private void populateCnodeToGateway(long vni, String subnetCidr) {
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700437 nodeService.completeNodes().stream()
438 .filter(node -> node.type().equals(COMPUTE))
439 .forEach(node -> populateRuleToGateway(
440 node.intBridge(),
441 gatewayService.getGatewayGroupId(node.intBridge()),
sangho3d2bf9c2016-08-26 17:19:55 +0900442 vni, subnetCidr));
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700443 }
sangho6032f342016-07-07 14:32:03 +0900444
sangho3d2bf9c2016-08-26 17:19:55 +0900445 private void populateRuleToGateway(DeviceId deviceId, GroupId groupId, long vni, String cidr) {
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700446 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
447 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
sangho6032f342016-07-07 14:32:03 +0900448
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700449 sBuilder.matchEthType(Ethernet.TYPE_IPV4)
450 .matchTunnelId(vni)
sangho3d2bf9c2016-08-26 17:19:55 +0900451 .matchIPSrc(IpPrefix.valueOf(cidr))
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700452 .matchEthDst(Constants.DEFAULT_GATEWAY_MAC);
453
454 tBuilder.group(groupId);
455 ForwardingObjective fo = DefaultForwardingObjective.builder()
456 .withSelector(sBuilder.build())
457 .withTreatment(tBuilder.build())
458 .withFlag(ForwardingObjective.Flag.SPECIFIC)
459 .withPriority(ROUTING_RULE_PRIORITY)
460 .fromApp(appId)
461 .add();
462
463 flowObjectiveService.forward(deviceId, fo);
464 }
465
466 private void populateRoutingRulestoDifferentNode(Ip4Address vmIp, long vni,
sangho3d2bf9c2016-08-26 17:19:55 +0900467 DeviceId deviceId, Ip4Address hostIp,
468 String cidr) {
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700469 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
470 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
471
472 sBuilder.matchEthType(Ethernet.TYPE_IPV4)
473 .matchTunnelId(vni)
sangho3d2bf9c2016-08-26 17:19:55 +0900474 .matchIPSrc(IpPrefix.valueOf(cidr))
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700475 .matchIPDst(vmIp.toIpPrefix());
476 tBuilder.extension(buildExtension(deviceService, deviceId, hostIp), deviceId)
477 .setOutput(nodeService.tunnelPort(deviceId).get());
478
479 ForwardingObjective fo = DefaultForwardingObjective.builder()
480 .withSelector(sBuilder.build())
481 .withTreatment(tBuilder.build())
sangho3d2bf9c2016-08-26 17:19:55 +0900482 .withPriority(EW_ROUTING_RULE_PRIORITY)
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700483 .withFlag(ForwardingObjective.Flag.SPECIFIC)
484 .fromApp(appId)
485 .add();
486
487 flowObjectiveService.forward(deviceId, fo);
488 }
489
490 private void populateRoutingRulestoSameNode(Ip4Address vmIp, MacAddress vmMac,
sangho3d2bf9c2016-08-26 17:19:55 +0900491 PortNumber port, DeviceId deviceId, long vni,
492 String cidr) {
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700493 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
494 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
495
sangho3d2bf9c2016-08-26 17:19:55 +0900496 // FIXME: we need to check the VNI of the dest IP also just in case...
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700497 sBuilder.matchEthType(Ethernet.TYPE_IPV4)
498 .matchIPDst(vmIp.toIpPrefix())
sangho3d2bf9c2016-08-26 17:19:55 +0900499 .matchIPSrc(IpPrefix.valueOf(cidr))
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700500 .matchTunnelId(vni);
501
502 tBuilder.setEthDst(vmMac)
503 .setOutput(port);
504
505 ForwardingObjective fo = DefaultForwardingObjective.builder()
506 .withSelector(sBuilder.build())
507 .withTreatment(tBuilder.build())
sangho3d2bf9c2016-08-26 17:19:55 +0900508 .withPriority(EW_ROUTING_RULE_PRIORITY)
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700509 .withFlag(ForwardingObjective.Flag.SPECIFIC)
510 .fromApp(appId)
511 .add();
512
513 flowObjectiveService.forward(deviceId, fo);
514 }
515
516 private void reloadRoutingRules() {
517 eventExecutor.execute(() -> openstackService.ports().stream()
518 .filter(osPort -> osPort.deviceOwner().equals(DEVICE_OWNER_ROUTER_INTERFACE))
519 .forEach(osPort -> {
520 OpenstackRouter osRouter = openstackRouter(osPort.deviceId());
Daniel Parka8d896c2016-08-26 14:31:33 +0900521
522 setGatewayIcmp(Ip4Address.valueOf(openstackService
523 .subnet(osPort.fixedIps().keySet().stream().findAny().get()).gatewayIp()));
524
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700525 setRoutes(osRouter, Optional.empty());
526 if (osRouter.gatewayExternalInfo().externalFixedIps().size() > 0) {
sangho3d2bf9c2016-08-26 17:19:55 +0900527 String subnetId = osPort.fixedIps().keySet().stream().findFirst().get();
528 setExternalConnection(osRouter, subnetId);
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700529 }
530 }));
531 }
532
533 @Override
534 protected void hostDetected(Host host) {
535 String osNetId = host.annotations().value(NETWORK_ID);
536 Optional<OpenstackPort> routerIface = routerIfacePort(osNetId);
537 if (!routerIface.isPresent()) {
538 return;
sangho6032f342016-07-07 14:32:03 +0900539 }
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700540 eventExecutor.execute(() -> setRoutes(
541 openstackRouter(routerIface.get().deviceId()),
542 Optional.of(host)));
543 }
544
545 @Override
546 protected void hostRemoved(Host host) {
547 String osNetId = host.annotations().value(NETWORK_ID);
548 Optional<OpenstackPort> routerIface = routerIfacePort(osNetId);
549 if (!routerIface.isPresent()) {
550 return;
551 }
sangho3d2bf9c2016-08-26 17:19:55 +0900552 Set<OpenstackSubnet> routableSubNets = routableSubNets(routerIface.get().deviceId());
553 eventExecutor.execute(() -> removeRoutingRules(host, routableSubNets));
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700554 }
555
556 private class InternalNodeListener implements OpenstackNodeListener {
Kyuhwi Choi5e65e2c2016-04-01 11:48:15 +0900557
558 @Override
sangho6032f342016-07-07 14:32:03 +0900559 public void event(OpenstackNodeEvent event) {
560 OpenstackNode node = event.node();
561
562 switch (event.type()) {
563 case COMPLETE:
564 log.info("COMPLETE node {} detected", node.hostname());
Hyunsun Moon5aa480b2016-08-03 12:23:14 -0700565 eventExecutor.execute(() -> {
566 if (node.type() == GATEWAY) {
567 GatewayNode gnode = GatewayNode.builder()
568 .gatewayDeviceId(node.intBridge())
569 .dataIpAddress(node.dataIp().getIp4Address())
570 .uplinkIntf(node.externalPortName().get())
571 .build();
572 gatewayService.addGatewayNode(gnode);
573 }
574 reloadRoutingRules();
575 });
sangho6032f342016-07-07 14:32:03 +0900576 break;
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700577 case INIT:
578 case DEVICE_CREATED:
sangho6032f342016-07-07 14:32:03 +0900579 case INCOMPLETE:
Daniel Parkf1af0682016-08-09 14:39:57 +0900580 eventExecutor.execute(() -> {
581 if (node.type() == GATEWAY) {
582 GatewayNode gnode = GatewayNode.builder()
583 .gatewayDeviceId(node.intBridge())
584 .dataIpAddress(node.dataIp().getIp4Address())
585 .uplinkIntf(node.externalPortName().get())
586 .build();
587 gatewayService.deleteGatewayNode(gnode);
588 }
589 reloadRoutingRules();
590 });
sangho6032f342016-07-07 14:32:03 +0900591 default:
592 break;
Kyuhwi Choi5e65e2c2016-04-01 11:48:15 +0900593 }
sangho6032f342016-07-07 14:32:03 +0900594 }
595 }
sangho0c2a3da2016-02-16 13:39:07 +0900596}