blob: add26349665f0e45e5fae5aeae2d8bd6d02b4b9e [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;
sangho0c2a3da2016-02-16 13:39:07 +090026import org.onlab.packet.Ip4Address;
sangho3d2bf9c2016-08-26 17:19:55 +090027import org.onlab.packet.IpPrefix;
sangho0c2a3da2016-02-16 13:39:07 +090028import org.onlab.packet.MacAddress;
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -070029import org.onlab.util.Tools;
sangho0c2a3da2016-02-16 13:39:07 +090030import org.onosproject.core.ApplicationId;
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -070031import org.onosproject.core.GroupId;
Kyuhwi Choie2b37e32016-02-05 14:04:14 +090032import org.onosproject.net.DeviceId;
sangho6032f342016-07-07 14:32:03 +090033import org.onosproject.net.Host;
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -070034import org.onosproject.net.PortNumber;
sangho0c2a3da2016-02-16 13:39:07 +090035import org.onosproject.net.device.DeviceService;
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -070036import org.onosproject.net.flow.DefaultTrafficSelector;
37import org.onosproject.net.flow.DefaultTrafficTreatment;
38import org.onosproject.net.flow.TrafficSelector;
39import org.onosproject.net.flow.TrafficTreatment;
40import org.onosproject.net.flowobjective.DefaultForwardingObjective;
sangho0c2a3da2016-02-16 13:39:07 +090041import org.onosproject.net.flowobjective.FlowObjectiveService;
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -070042import org.onosproject.net.flowobjective.ForwardingObjective;
sangho93447f12016-02-24 00:33:22 +090043import org.onosproject.openstackinterface.OpenstackInterfaceService;
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -070044import org.onosproject.openstackinterface.OpenstackNetwork;
sangho93447f12016-02-24 00:33:22 +090045import org.onosproject.openstackinterface.OpenstackPort;
46import org.onosproject.openstackinterface.OpenstackRouter;
47import org.onosproject.openstackinterface.OpenstackRouterInterface;
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -070048import org.onosproject.openstackinterface.OpenstackSubnet;
49import org.onosproject.openstacknetworking.AbstractVmHandler;
sangho6032f342016-07-07 14:32:03 +090050import org.onosproject.openstacknetworking.Constants;
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -070051import org.onosproject.openstacknetworking.OpenstackRoutingService;
52import org.onosproject.openstacknetworking.RulePopulatorUtil;
sangho6032f342016-07-07 14:32:03 +090053import org.onosproject.openstacknode.OpenstackNode;
54import org.onosproject.openstacknode.OpenstackNodeEvent;
55import org.onosproject.openstacknode.OpenstackNodeListener;
56import org.onosproject.openstacknode.OpenstackNodeService;
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -070057import org.onosproject.scalablegateway.api.GatewayNode;
58import org.onosproject.scalablegateway.api.ScalableGatewayService;
sangho0c2a3da2016-02-16 13:39:07 +090059import org.slf4j.Logger;
60import org.slf4j.LoggerFactory;
61
sangho3d2bf9c2016-08-26 17:19:55 +090062import java.util.HashMap;
63import java.util.Map;
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -070064import java.util.Objects;
Daniel Park23193902016-03-24 18:17:19 +090065import java.util.Optional;
sangho6032f342016-07-07 14:32:03 +090066import java.util.Set;
sangho0c2a3da2016-02-16 13:39:07 +090067import java.util.concurrent.ExecutorService;
sangho0c2a3da2016-02-16 13:39:07 +090068import java.util.stream.Collectors;
69
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -070070import static java.util.concurrent.Executors.newSingleThreadScheduledExecutor;
sangho0c2a3da2016-02-16 13:39:07 +090071import static org.onlab.util.Tools.groupedThreads;
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -070072import static org.onosproject.openstacknetworking.Constants.*;
73import static org.onosproject.openstacknetworking.RulePopulatorUtil.buildExtension;
74import static org.onosproject.openstacknode.OpenstackNodeService.NodeType.COMPUTE;
75import static org.onosproject.openstacknode.OpenstackNodeService.NodeType.GATEWAY;
sangho0c2a3da2016-02-16 13:39:07 +090076
sangho0c2a3da2016-02-16 13:39:07 +090077@Component(immediate = true)
Kyuhwi Choie2b37e32016-02-05 14:04:14 +090078@Service
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -070079public class OpenstackRoutingManager extends AbstractVmHandler implements OpenstackRoutingService {
Kyuhwi Choie2b37e32016-02-05 14:04:14 +090080
81 private final Logger log = LoggerFactory.getLogger(getClass());
sangho0c2a3da2016-02-16 13:39:07 +090082
83 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -070084 protected FlowObjectiveService flowObjectiveService;
sangho0c2a3da2016-02-16 13:39:07 +090085
86 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
87 protected DeviceService deviceService;
88
89 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
sangho93447f12016-02-24 00:33:22 +090090 protected OpenstackInterfaceService openstackService;
sangho0c2a3da2016-02-16 13:39:07 +090091
92 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -070093 protected OpenstackNodeService nodeService;
sangho6032f342016-07-07 14:32:03 +090094
95 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Kyuhwi Choi92d9ea42016-06-13 17:28:00 +090096 protected ScalableGatewayService gatewayService;
Daniel Park23193902016-03-24 18:17:19 +090097
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -070098 private final ExecutorService eventExecutor = newSingleThreadScheduledExecutor(
99 groupedThreads(this.getClass().getSimpleName(), "event-handler", log));
100 private final InternalNodeListener nodeListener = new InternalNodeListener();
sangho6032f342016-07-07 14:32:03 +0900101
sangho0c2a3da2016-02-16 13:39:07 +0900102 private ApplicationId appId;
sangho0c2a3da2016-02-16 13:39:07 +0900103
104 @Activate
105 protected void activate() {
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700106 super.activate();
107 appId = coreService.registerApplication(ROUTING_APP_ID);
108 nodeService.addListener(nodeListener);
sangho0c2a3da2016-02-16 13:39:07 +0900109 }
110
111 @Deactivate
112 protected void deactivate() {
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700113 nodeService.removeListener(nodeListener);
Kyuhwi Choi5e65e2c2016-04-01 11:48:15 +0900114 log.info("stopped");
sangho0c2a3da2016-02-16 13:39:07 +0900115 }
116
sangho0c2a3da2016-02-16 13:39:07 +0900117 @Override
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700118 public void createRouter(OpenstackRouter osRouter) {
sangho0c2a3da2016-02-16 13:39:07 +0900119 }
120
121 @Override
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700122 public void updateRouter(OpenstackRouter osRouter) {
123 if (osRouter.gatewayExternalInfo().externalFixedIps().size() > 0) {
124 openstackService.ports().stream()
125 .filter(osPort -> osPort.deviceOwner().equals(DEVICE_OWNER_ROUTER_INTERFACE) &&
126 osPort.deviceId().equals(osRouter.id()))
sangho3d2bf9c2016-08-26 17:19:55 +0900127 .forEach(osPort -> {
128 String subnetId = osPort.fixedIps().keySet().stream().findFirst().get();
129 setExternalConnection(osRouter, subnetId);
130 });
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700131
132 log.info("Connected external gateway {} to router {}",
133 osRouter.gatewayExternalInfo().externalFixedIps(),
134 osRouter.name());
135 } else {
136 openstackService.ports().stream()
137 .filter(osPort -> osPort.deviceOwner().equals(DEVICE_OWNER_ROUTER_INTERFACE) &&
138 osPort.deviceId().equals(osRouter.id()))
139 .forEach(osPort -> unsetExternalConnection(osRouter, osPort.networkId()));
140
141 log.info("Disconnected external gateway from router {}",
142 osRouter.name());
143 }
144 }
145
146 @Override
147 public void removeRouter(String osRouterId) {
148 // TODO implement this
149 }
150
151 @Override
152 public void addRouterInterface(OpenstackRouterInterface routerIface) {
153 OpenstackRouter osRouter = openstackRouter(routerIface.id());
154 OpenstackPort osPort = openstackService.port(routerIface.portId());
155 if (osRouter == null || osPort == null) {
156 log.warn("Failed to add router interface {}", routerIface);
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900157 return;
158 }
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700159
160 setRoutes(osRouter, Optional.empty());
161 if (osRouter.gatewayExternalInfo().externalFixedIps().size() > 0) {
sangho3d2bf9c2016-08-26 17:19:55 +0900162 String subnetId = osPort.fixedIps().keySet().stream().findFirst().get();
163 setExternalConnection(osRouter, subnetId);
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900164 }
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700165 log.info("Connected {} to router {}", osPort.fixedIps(), osRouter.name());
sangho0c2a3da2016-02-16 13:39:07 +0900166 }
167
168 @Override
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700169 public void removeRouterInterface(OpenstackRouterInterface routerIface) {
170 OpenstackRouter osRouter = openstackService.router(routerIface.id());
171 if (osRouter == null) {
172 log.warn("Failed to remove router interface {}", routerIface);
Kyuhwi Choi5e65e2c2016-04-01 11:48:15 +0900173 return;
174 }
sanghod177f8f2016-06-29 21:52:23 +0900175
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700176 OpenstackSubnet osSubnet = openstackService.subnet(routerIface.subnetId());
177 OpenstackNetwork osNet = openstackService.network(osSubnet.networkId());
178
sangho3d2bf9c2016-08-26 17:19:55 +0900179 unsetRoutes(osRouter, osSubnet);
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700180 if (osRouter.gatewayExternalInfo().externalFixedIps().size() > 0) {
181 unsetExternalConnection(osRouter, osNet.id());
Kyuhwi Choi5e65e2c2016-04-01 11:48:15 +0900182 }
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700183 log.info("Disconnected {} from router {}", osSubnet.cidr(), osRouter.name());
Kyuhwi Choi5e65e2c2016-04-01 11:48:15 +0900184 }
185
sangho3d2bf9c2016-08-26 17:19:55 +0900186 private void setExternalConnection(OpenstackRouter osRouter, String osSubNetId) {
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700187 if (!osRouter.gatewayExternalInfo().isEnablePnat()) {
188 log.debug("Source NAT is disabled");
sangho6032f342016-07-07 14:32:03 +0900189 return;
190 }
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700191
sangho3d2bf9c2016-08-26 17:19:55 +0900192 OpenstackSubnet osSubNet = openstackService.subnet(osSubNetId);
193 OpenstackNetwork osNet = openstackService.network(osSubNet.networkId());
194 populateExternalRules(osNet, osSubNet);
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900195 }
196
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700197 private void unsetExternalConnection(OpenstackRouter osRouter, String osNetId) {
198 if (!osRouter.gatewayExternalInfo().isEnablePnat()) {
199 log.debug("Source NAT is disabled");
200 return;
sangho0c2a3da2016-02-16 13:39:07 +0900201 }
202
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700203 // FIXME router interface is subnet specific, not network
204 OpenstackNetwork osNet = openstackService.network(osNetId);
205 removeExternalRules(osNet);
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900206 }
207
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700208 private void setRoutes(OpenstackRouter osRouter, Optional<Host> host) {
sangho3d2bf9c2016-08-26 17:19:55 +0900209 Set<OpenstackSubnet> routableSubNets = routableSubNets(osRouter.id());
210 if (routableSubNets.size() < 2) {
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700211 // no other subnet interface is connected to this router, do nothing
212 return;
213 }
214
sangho3d2bf9c2016-08-26 17:19:55 +0900215 Set<String> routableSubNetIds = routableSubNets.stream()
216 .map(OpenstackSubnet::id)
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700217 .collect(Collectors.toSet());
218
sangho3d2bf9c2016-08-26 17:19:55 +0900219
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700220 Set<Host> hosts = host.isPresent() ? ImmutableSet.of(host.get()) :
221 Tools.stream(hostService.getHosts())
sangho3d2bf9c2016-08-26 17:19:55 +0900222 .filter(h -> routableSubNetIds.contains(h.annotations().value(SUBNET_ID)))
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700223 .collect(Collectors.toSet());
224
sangho3d2bf9c2016-08-26 17:19:55 +0900225 hosts.forEach(h -> populateRoutingRules(h, routableSubNets));
Kyuhwi Choi92d9ea42016-06-13 17:28:00 +0900226 }
227
sangho3d2bf9c2016-08-26 17:19:55 +0900228 private void unsetRoutes(OpenstackRouter osRouter, OpenstackSubnet osSubNet) {
229 Set<OpenstackSubnet> routableSubNets = routableSubNets(osRouter.id());
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700230 Tools.stream(hostService.getHosts())
231 .filter(h -> Objects.equals(
sangho3d2bf9c2016-08-26 17:19:55 +0900232 h.annotations().value(NETWORK_ID), osSubNet.id()))
233 .forEach(h -> removeRoutingRules(h, routableSubNets));
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700234
sangho3d2bf9c2016-08-26 17:19:55 +0900235 routableSubNets.forEach(n -> {
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700236 Tools.stream(hostService.getHosts())
237 .filter(h -> Objects.equals(
sangho3d2bf9c2016-08-26 17:19:55 +0900238 h.annotations().value(SUBNET_ID),
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700239 n.id()))
sangho3d2bf9c2016-08-26 17:19:55 +0900240 .forEach(h -> removeRoutingRules(h, ImmutableSet.of(osSubNet)));
241 log.debug("Removed between {} to {}", n.name(), osSubNet.name());
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900242 });
sangho0c2a3da2016-02-16 13:39:07 +0900243 }
244
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700245 private OpenstackRouter openstackRouter(String routerId) {
sangho0c2a3da2016-02-16 13:39:07 +0900246 return openstackService.routers().stream().filter(r ->
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700247 r.id().equals(routerId)).iterator().next();
sangho0c2a3da2016-02-16 13:39:07 +0900248 }
249
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700250 private Optional<OpenstackPort> routerIfacePort(String osNetId) {
251 // FIXME router interface is subnet specific, not network
252 return openstackService.ports().stream()
253 .filter(p -> p.deviceOwner().equals(DEVICE_OWNER_ROUTER_INTERFACE) &&
254 p.networkId().equals(osNetId))
sangho6032f342016-07-07 14:32:03 +0900255 .findAny();
256 }
257
sangho3d2bf9c2016-08-26 17:19:55 +0900258 private Set<OpenstackSubnet> routableSubNets(String osRouterId) {
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700259 return openstackService.ports().stream()
260 .filter(p -> p.deviceOwner().equals(DEVICE_OWNER_ROUTER_INTERFACE) &&
261 p.deviceId().equals(osRouterId))
sangho3d2bf9c2016-08-26 17:19:55 +0900262 .map(p -> openstackService.subnet(p.fixedIps().keySet().stream().findFirst().get()))
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700263 .collect(Collectors.toSet());
264 }
sangho6032f342016-07-07 14:32:03 +0900265
sangho3d2bf9c2016-08-26 17:19:55 +0900266 private void populateExternalRules(OpenstackNetwork osNet, OpenstackSubnet osSubNet) {
267 populateCnodeToGateway(Long.valueOf(osNet.segmentId()), osSubNet.cidr());
268 populateGatewayToController(Long.valueOf(osNet.segmentId()), osSubNet.cidr());
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700269 }
270
271 private void removeExternalRules(OpenstackNetwork osNet) {
272 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
273 sBuilder.matchEthType(Ethernet.TYPE_IPV4)
274 .matchTunnelId(Long.valueOf(osNet.segmentId()))
275 .matchEthDst(Constants.DEFAULT_GATEWAY_MAC);
276
Sho SHIMIZUa09e1bb2016-08-01 14:25:25 -0700277 nodeService.completeNodes().forEach(node -> {
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700278 ForwardingObjective.Flag flag = node.type().equals(GATEWAY) ?
279 ForwardingObjective.Flag.VERSATILE :
280 ForwardingObjective.Flag.SPECIFIC;
281
282 RulePopulatorUtil.removeRule(
283 flowObjectiveService,
284 appId,
285 node.intBridge(),
286 sBuilder.build(),
287 flag,
288 ROUTING_RULE_PRIORITY);
289 });
290 }
291
sangho3d2bf9c2016-08-26 17:19:55 +0900292 private void populateRoutingRules(Host host, Set<OpenstackSubnet> osSubNets) {
293 String osSubNetId = host.annotations().value(SUBNET_ID);
294 if (osSubNetId == null) {
Daniel Park81a61a12016-02-26 08:24:44 +0900295 return;
296 }
297
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700298 DeviceId localDevice = host.location().deviceId();
299 PortNumber localPort = host.location().port();
300 if (!nodeService.dataIp(localDevice).isPresent()) {
301 log.warn("Failed to populate L3 rules");
302 return;
sangho6032f342016-07-07 14:32:03 +0900303 }
sanghod177f8f2016-06-29 21:52:23 +0900304
sangho3d2bf9c2016-08-26 17:19:55 +0900305 Map<String, String> vniMap = new HashMap<>();
306 openstackService.networks().stream().forEach(n -> vniMap.put(n.id(), n.segmentId()));
307
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700308 // TODO improve pipeline, do we have to install access rules between networks
309 // for every single VMs?
sangho3d2bf9c2016-08-26 17:19:55 +0900310 osSubNets.stream().filter(osSubNet -> !osSubNet.id().equals(osSubNetId)).forEach(osSubNet -> {
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700311 populateRoutingRulestoSameNode(
312 host.ipAddresses().stream().findFirst().get().getIp4Address(),
313 host.mac(),
314 localPort, localDevice,
sangho3d2bf9c2016-08-26 17:19:55 +0900315 Long.valueOf(vniMap.get(osSubNet.networkId())),
316 osSubNet.cidr());
sanghod177f8f2016-06-29 21:52:23 +0900317
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700318 nodeService.completeNodes().stream()
319 .filter(node -> node.type().equals(COMPUTE))
320 .filter(node -> !node.intBridge().equals(localDevice))
321 .forEach(node -> populateRoutingRulestoDifferentNode(
322 host.ipAddresses().stream().findFirst().get().getIp4Address(),
sangho3d2bf9c2016-08-26 17:19:55 +0900323 Long.valueOf(vniMap.get(osSubNet.networkId())),
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700324 node.intBridge(),
sangho3d2bf9c2016-08-26 17:19:55 +0900325 nodeService.dataIp(localDevice).get().getIp4Address(),
326 osSubNet.cidr()));
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700327 });
Daniel Park81a61a12016-02-26 08:24:44 +0900328 }
329
sangho3d2bf9c2016-08-26 17:19:55 +0900330 private void removeRoutingRules(Host host, Set<OpenstackSubnet> osSubNets) {
331 String osSubNetId = host.annotations().value(SUBNET_ID);
332 if (osSubNetId == null) {
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700333 return;
sangho6032f342016-07-07 14:32:03 +0900334 }
335
sangho3d2bf9c2016-08-26 17:19:55 +0900336 Map<String, String> vniMap = new HashMap<>();
337 openstackService.networks().stream().forEach(n -> vniMap.put(n.id(), n.segmentId()));
338
339 osSubNets.stream().filter(osSubNet -> !osSubNet.id().equals(osSubNetId)).forEach(osSubNet -> {
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700340 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
341 sBuilder.matchEthType(Ethernet.TYPE_IPV4)
342 .matchIPDst(host.ipAddresses().stream().findFirst().get().toIpPrefix())
sangho3d2bf9c2016-08-26 17:19:55 +0900343 .matchIPSrc(IpPrefix.valueOf(osSubNet.cidr()))
344 .matchTunnelId(Long.valueOf(vniMap.get(osSubNet.networkId())));
sangho6032f342016-07-07 14:32:03 +0900345
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700346 nodeService.completeNodes().stream()
347 .filter(node -> node.type().equals(COMPUTE))
348 .forEach(node -> RulePopulatorUtil.removeRule(
349 flowObjectiveService,
350 appId,
351 node.intBridge(),
352 sBuilder.build(),
353 ForwardingObjective.Flag.SPECIFIC,
354 ROUTING_RULE_PRIORITY));
355 });
sangho3d2bf9c2016-08-26 17:19:55 +0900356 log.debug("Removed routing rule from {} to {}", host, osSubNets);
Daniel Park81a61a12016-02-26 08:24:44 +0900357 }
Kyuhwi Choi5e65e2c2016-04-01 11:48:15 +0900358
sangho3d2bf9c2016-08-26 17:19:55 +0900359 private void populateGatewayToController(long vni, String subNetCidr) {
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700360 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
361 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
sangho6032f342016-07-07 14:32:03 +0900362
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700363 sBuilder.matchEthType(Ethernet.TYPE_IPV4)
364 .matchTunnelId(vni)
sangho3d2bf9c2016-08-26 17:19:55 +0900365 .matchIPSrc(IpPrefix.valueOf(subNetCidr))
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700366 .matchEthDst(Constants.DEFAULT_GATEWAY_MAC);
367 tBuilder.setOutput(PortNumber.CONTROLLER);
sangho6032f342016-07-07 14:32:03 +0900368
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700369 ForwardingObjective fo = DefaultForwardingObjective.builder()
370 .withSelector(sBuilder.build())
371 .withTreatment(tBuilder.build())
372 .withFlag(ForwardingObjective.Flag.VERSATILE)
373 .withPriority(ROUTING_RULE_PRIORITY)
374 .fromApp(appId)
375 .add();
sangho6032f342016-07-07 14:32:03 +0900376
Sho SHIMIZUa09e1bb2016-08-01 14:25:25 -0700377 gatewayService.getGatewayDeviceIds().forEach(deviceId -> flowObjectiveService.forward(deviceId, fo));
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700378 }
sangho6032f342016-07-07 14:32:03 +0900379
sangho3d2bf9c2016-08-26 17:19:55 +0900380 private void populateCnodeToGateway(long vni, String subnetCidr) {
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700381 nodeService.completeNodes().stream()
382 .filter(node -> node.type().equals(COMPUTE))
383 .forEach(node -> populateRuleToGateway(
384 node.intBridge(),
385 gatewayService.getGatewayGroupId(node.intBridge()),
sangho3d2bf9c2016-08-26 17:19:55 +0900386 vni, subnetCidr));
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700387 }
sangho6032f342016-07-07 14:32:03 +0900388
sangho3d2bf9c2016-08-26 17:19:55 +0900389 private void populateRuleToGateway(DeviceId deviceId, GroupId groupId, long vni, String cidr) {
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700390 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
391 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
sangho6032f342016-07-07 14:32:03 +0900392
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700393 sBuilder.matchEthType(Ethernet.TYPE_IPV4)
394 .matchTunnelId(vni)
sangho3d2bf9c2016-08-26 17:19:55 +0900395 .matchIPSrc(IpPrefix.valueOf(cidr))
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700396 .matchEthDst(Constants.DEFAULT_GATEWAY_MAC);
397
398 tBuilder.group(groupId);
399 ForwardingObjective fo = DefaultForwardingObjective.builder()
400 .withSelector(sBuilder.build())
401 .withTreatment(tBuilder.build())
402 .withFlag(ForwardingObjective.Flag.SPECIFIC)
403 .withPriority(ROUTING_RULE_PRIORITY)
404 .fromApp(appId)
405 .add();
406
407 flowObjectiveService.forward(deviceId, fo);
408 }
409
410 private void populateRoutingRulestoDifferentNode(Ip4Address vmIp, long vni,
sangho3d2bf9c2016-08-26 17:19:55 +0900411 DeviceId deviceId, Ip4Address hostIp,
412 String cidr) {
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700413 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
414 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
415
416 sBuilder.matchEthType(Ethernet.TYPE_IPV4)
417 .matchTunnelId(vni)
sangho3d2bf9c2016-08-26 17:19:55 +0900418 .matchIPSrc(IpPrefix.valueOf(cidr))
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700419 .matchIPDst(vmIp.toIpPrefix());
420 tBuilder.extension(buildExtension(deviceService, deviceId, hostIp), deviceId)
421 .setOutput(nodeService.tunnelPort(deviceId).get());
422
423 ForwardingObjective fo = DefaultForwardingObjective.builder()
424 .withSelector(sBuilder.build())
425 .withTreatment(tBuilder.build())
sangho3d2bf9c2016-08-26 17:19:55 +0900426 .withPriority(EW_ROUTING_RULE_PRIORITY)
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700427 .withFlag(ForwardingObjective.Flag.SPECIFIC)
428 .fromApp(appId)
429 .add();
430
431 flowObjectiveService.forward(deviceId, fo);
432 }
433
434 private void populateRoutingRulestoSameNode(Ip4Address vmIp, MacAddress vmMac,
sangho3d2bf9c2016-08-26 17:19:55 +0900435 PortNumber port, DeviceId deviceId, long vni,
436 String cidr) {
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700437 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
438 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
439
sangho3d2bf9c2016-08-26 17:19:55 +0900440 // FIXME: we need to check the VNI of the dest IP also just in case...
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700441 sBuilder.matchEthType(Ethernet.TYPE_IPV4)
442 .matchIPDst(vmIp.toIpPrefix())
sangho3d2bf9c2016-08-26 17:19:55 +0900443 .matchIPSrc(IpPrefix.valueOf(cidr))
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700444 .matchTunnelId(vni);
445
446 tBuilder.setEthDst(vmMac)
447 .setOutput(port);
448
449 ForwardingObjective fo = DefaultForwardingObjective.builder()
450 .withSelector(sBuilder.build())
451 .withTreatment(tBuilder.build())
sangho3d2bf9c2016-08-26 17:19:55 +0900452 .withPriority(EW_ROUTING_RULE_PRIORITY)
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700453 .withFlag(ForwardingObjective.Flag.SPECIFIC)
454 .fromApp(appId)
455 .add();
456
457 flowObjectiveService.forward(deviceId, fo);
458 }
459
460 private void reloadRoutingRules() {
461 eventExecutor.execute(() -> openstackService.ports().stream()
462 .filter(osPort -> osPort.deviceOwner().equals(DEVICE_OWNER_ROUTER_INTERFACE))
463 .forEach(osPort -> {
464 OpenstackRouter osRouter = openstackRouter(osPort.deviceId());
465 setRoutes(osRouter, Optional.empty());
466 if (osRouter.gatewayExternalInfo().externalFixedIps().size() > 0) {
sangho3d2bf9c2016-08-26 17:19:55 +0900467 String subnetId = osPort.fixedIps().keySet().stream().findFirst().get();
468 setExternalConnection(osRouter, subnetId);
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700469 }
470 }));
471 }
472
473 @Override
474 protected void hostDetected(Host host) {
475 String osNetId = host.annotations().value(NETWORK_ID);
476 Optional<OpenstackPort> routerIface = routerIfacePort(osNetId);
477 if (!routerIface.isPresent()) {
478 return;
sangho6032f342016-07-07 14:32:03 +0900479 }
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700480 eventExecutor.execute(() -> setRoutes(
481 openstackRouter(routerIface.get().deviceId()),
482 Optional.of(host)));
483 }
484
485 @Override
486 protected void hostRemoved(Host host) {
487 String osNetId = host.annotations().value(NETWORK_ID);
488 Optional<OpenstackPort> routerIface = routerIfacePort(osNetId);
489 if (!routerIface.isPresent()) {
490 return;
491 }
sangho3d2bf9c2016-08-26 17:19:55 +0900492 Set<OpenstackSubnet> routableSubNets = routableSubNets(routerIface.get().deviceId());
493 eventExecutor.execute(() -> removeRoutingRules(host, routableSubNets));
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700494 }
495
496 private class InternalNodeListener implements OpenstackNodeListener {
Kyuhwi Choi5e65e2c2016-04-01 11:48:15 +0900497
498 @Override
sangho6032f342016-07-07 14:32:03 +0900499 public void event(OpenstackNodeEvent event) {
500 OpenstackNode node = event.node();
501
502 switch (event.type()) {
503 case COMPLETE:
504 log.info("COMPLETE node {} detected", node.hostname());
Hyunsun Moon5aa480b2016-08-03 12:23:14 -0700505 eventExecutor.execute(() -> {
506 if (node.type() == GATEWAY) {
507 GatewayNode gnode = GatewayNode.builder()
508 .gatewayDeviceId(node.intBridge())
509 .dataIpAddress(node.dataIp().getIp4Address())
510 .uplinkIntf(node.externalPortName().get())
511 .build();
512 gatewayService.addGatewayNode(gnode);
513 }
514 reloadRoutingRules();
515 });
sangho6032f342016-07-07 14:32:03 +0900516 break;
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700517 case INIT:
518 case DEVICE_CREATED:
sangho6032f342016-07-07 14:32:03 +0900519 case INCOMPLETE:
Daniel Parkf1af0682016-08-09 14:39:57 +0900520 eventExecutor.execute(() -> {
521 if (node.type() == GATEWAY) {
522 GatewayNode gnode = GatewayNode.builder()
523 .gatewayDeviceId(node.intBridge())
524 .dataIpAddress(node.dataIp().getIp4Address())
525 .uplinkIntf(node.externalPortName().get())
526 .build();
527 gatewayService.deleteGatewayNode(gnode);
528 }
529 reloadRoutingRules();
530 });
sangho6032f342016-07-07 14:32:03 +0900531 default:
532 break;
Kyuhwi Choi5e65e2c2016-04-01 11:48:15 +0900533 }
sangho6032f342016-07-07 14:32:03 +0900534 }
535 }
sangho0c2a3da2016-02-16 13:39:07 +0900536}