blob: c8ce876a6951e7ae9d18421f1fc5c2703b7140c1 [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()))
jskim3d66aca2016-09-22 16:45:10 +0900140 .forEach(osPort -> {
141 String subnetId = osPort.fixedIps().keySet().stream().findFirst().get();
142 OpenstackSubnet osSubNet = openstackService.subnet(subnetId);
143 unsetExternalConnection(osRouter, osPort.networkId(), osSubNet.cidr());
144 });
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700145
146 log.info("Disconnected external gateway from router {}",
147 osRouter.name());
148 }
149 }
150
151 @Override
152 public void removeRouter(String osRouterId) {
153 // TODO implement this
154 }
155
156 @Override
157 public void addRouterInterface(OpenstackRouterInterface routerIface) {
158 OpenstackRouter osRouter = openstackRouter(routerIface.id());
159 OpenstackPort osPort = openstackService.port(routerIface.portId());
160 if (osRouter == null || osPort == null) {
161 log.warn("Failed to add router interface {}", routerIface);
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900162 return;
163 }
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700164
Daniel Parka8d896c2016-08-26 14:31:33 +0900165 setGatewayIcmp(Ip4Address.valueOf(openstackService.subnet(routerIface.subnetId()).gatewayIp()));
166
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700167 setRoutes(osRouter, Optional.empty());
168 if (osRouter.gatewayExternalInfo().externalFixedIps().size() > 0) {
sangho3d2bf9c2016-08-26 17:19:55 +0900169 String subnetId = osPort.fixedIps().keySet().stream().findFirst().get();
170 setExternalConnection(osRouter, subnetId);
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900171 }
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700172 log.info("Connected {} to router {}", osPort.fixedIps(), osRouter.name());
sangho0c2a3da2016-02-16 13:39:07 +0900173 }
174
175 @Override
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700176 public void removeRouterInterface(OpenstackRouterInterface routerIface) {
177 OpenstackRouter osRouter = openstackService.router(routerIface.id());
178 if (osRouter == null) {
179 log.warn("Failed to remove router interface {}", routerIface);
Kyuhwi Choi5e65e2c2016-04-01 11:48:15 +0900180 return;
181 }
sanghod177f8f2016-06-29 21:52:23 +0900182
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700183 OpenstackSubnet osSubnet = openstackService.subnet(routerIface.subnetId());
184 OpenstackNetwork osNet = openstackService.network(osSubnet.networkId());
185
Daniel Parka8d896c2016-08-26 14:31:33 +0900186 unsetGatewayIcmp(Ip4Address.valueOf(openstackService.subnet(routerIface.subnetId()).gatewayIp()));
187
sangho3d2bf9c2016-08-26 17:19:55 +0900188 unsetRoutes(osRouter, osSubnet);
Daniel Parka8d896c2016-08-26 14:31:33 +0900189
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700190 if (osRouter.gatewayExternalInfo().externalFixedIps().size() > 0) {
jskim3d66aca2016-09-22 16:45:10 +0900191 unsetExternalConnection(osRouter, osNet.id(), osSubnet.cidr());
Kyuhwi Choi5e65e2c2016-04-01 11:48:15 +0900192 }
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700193 log.info("Disconnected {} from router {}", osSubnet.cidr(), osRouter.name());
Kyuhwi Choi5e65e2c2016-04-01 11:48:15 +0900194 }
195
Daniel Parka8d896c2016-08-26 14:31:33 +0900196 private void setGatewayIcmp(Ip4Address gatewayIp) {
197 if (gatewayIp == null) {
198 return;
199 }
Sho SHIMIZU8ebb04a2016-10-06 15:58:29 -0700200 gatewayService.getGatewayDeviceIds().forEach(deviceId -> populateGatewayIcmpRule(gatewayIp, deviceId));
Daniel Parka8d896c2016-08-26 14:31:33 +0900201 }
202
203 private void populateGatewayIcmpRule(Ip4Address gatewayIp, DeviceId deviceId) {
204 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
205 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
206
207 sBuilder.matchEthType(Ethernet.TYPE_IPV4)
208 .matchIPProtocol(IPv4.PROTOCOL_ICMP)
209 .matchIPDst(gatewayIp.toIpPrefix());
210
211 tBuilder.setOutput(PortNumber.CONTROLLER);
212
213 ForwardingObjective fo = DefaultForwardingObjective.builder()
214 .withSelector(sBuilder.build())
215 .withTreatment(tBuilder.build())
216 .withPriority(GATEWAY_ICMP_PRIORITY)
217 .withFlag(ForwardingObjective.Flag.VERSATILE)
218 .fromApp(appId)
219 .add();
220
221 flowObjectiveService.forward(deviceId, fo);
222 }
223
224 private void unsetGatewayIcmp(Ip4Address gatewayIp) {
225 if (gatewayIp == null) {
226 return;
227 }
228 gatewayService.getGatewayDeviceIds().forEach(deviceId -> {
229 removeGatewayIcmpRule(gatewayIp, deviceId);
230 });
231 }
232
233 private void removeGatewayIcmpRule(Ip4Address gatewayIp, DeviceId deviceId) {
234 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
235
236 sBuilder.matchEthType(Ethernet.TYPE_IPV4)
237 .matchIPProtocol(IPv4.PROTOCOL_ICMP)
238 .matchIPDst(gatewayIp.toIpPrefix());
239
240 RulePopulatorUtil.removeRule(flowObjectiveService, appId, deviceId, sBuilder.build(),
241 ForwardingObjective.Flag.VERSATILE, GATEWAY_ICMP_PRIORITY);
242
243 }
sangho3d2bf9c2016-08-26 17:19:55 +0900244 private void setExternalConnection(OpenstackRouter osRouter, String osSubNetId) {
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700245 if (!osRouter.gatewayExternalInfo().isEnablePnat()) {
246 log.debug("Source NAT is disabled");
sangho6032f342016-07-07 14:32:03 +0900247 return;
248 }
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700249
sangho3d2bf9c2016-08-26 17:19:55 +0900250 OpenstackSubnet osSubNet = openstackService.subnet(osSubNetId);
251 OpenstackNetwork osNet = openstackService.network(osSubNet.networkId());
252 populateExternalRules(osNet, osSubNet);
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900253 }
254
jskim3d66aca2016-09-22 16:45:10 +0900255 private void unsetExternalConnection(OpenstackRouter osRouter, String osNetId, String subNetCidr) {
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700256 if (!osRouter.gatewayExternalInfo().isEnablePnat()) {
257 log.debug("Source NAT is disabled");
258 return;
sangho0c2a3da2016-02-16 13:39:07 +0900259 }
260
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700261 // FIXME router interface is subnet specific, not network
262 OpenstackNetwork osNet = openstackService.network(osNetId);
jskim3d66aca2016-09-22 16:45:10 +0900263 removeExternalRules(osNet, subNetCidr);
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900264 }
265
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700266 private void setRoutes(OpenstackRouter osRouter, Optional<Host> host) {
sangho3d2bf9c2016-08-26 17:19:55 +0900267 Set<OpenstackSubnet> routableSubNets = routableSubNets(osRouter.id());
268 if (routableSubNets.size() < 2) {
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700269 // no other subnet interface is connected to this router, do nothing
270 return;
271 }
272
sangho3d2bf9c2016-08-26 17:19:55 +0900273 Set<String> routableSubNetIds = routableSubNets.stream()
274 .map(OpenstackSubnet::id)
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700275 .collect(Collectors.toSet());
276
jskim8f27c4e2016-09-27 18:43:31 +0900277 if (host.isPresent()) {
278 if (!routableSubNetIds.contains(host.get().annotations().value(SUBNET_ID))) {
279 // subnet of host is not connected to this router, do nothing.
280 return;
281 }
282 }
sangho3d2bf9c2016-08-26 17:19:55 +0900283
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700284 Set<Host> hosts = host.isPresent() ? ImmutableSet.of(host.get()) :
285 Tools.stream(hostService.getHosts())
sangho3d2bf9c2016-08-26 17:19:55 +0900286 .filter(h -> routableSubNetIds.contains(h.annotations().value(SUBNET_ID)))
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700287 .collect(Collectors.toSet());
288
sangho3d2bf9c2016-08-26 17:19:55 +0900289 hosts.forEach(h -> populateRoutingRules(h, routableSubNets));
Kyuhwi Choi92d9ea42016-06-13 17:28:00 +0900290 }
291
sangho3d2bf9c2016-08-26 17:19:55 +0900292 private void unsetRoutes(OpenstackRouter osRouter, OpenstackSubnet osSubNet) {
293 Set<OpenstackSubnet> routableSubNets = routableSubNets(osRouter.id());
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700294 Tools.stream(hostService.getHosts())
295 .filter(h -> Objects.equals(
sangho3d2bf9c2016-08-26 17:19:55 +0900296 h.annotations().value(NETWORK_ID), osSubNet.id()))
297 .forEach(h -> removeRoutingRules(h, routableSubNets));
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700298
sangho3d2bf9c2016-08-26 17:19:55 +0900299 routableSubNets.forEach(n -> {
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700300 Tools.stream(hostService.getHosts())
301 .filter(h -> Objects.equals(
sangho3d2bf9c2016-08-26 17:19:55 +0900302 h.annotations().value(SUBNET_ID),
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700303 n.id()))
sangho3d2bf9c2016-08-26 17:19:55 +0900304 .forEach(h -> removeRoutingRules(h, ImmutableSet.of(osSubNet)));
305 log.debug("Removed between {} to {}", n.name(), osSubNet.name());
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900306 });
sangho0c2a3da2016-02-16 13:39:07 +0900307 }
308
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700309 private OpenstackRouter openstackRouter(String routerId) {
sangho0c2a3da2016-02-16 13:39:07 +0900310 return openstackService.routers().stream().filter(r ->
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700311 r.id().equals(routerId)).iterator().next();
sangho0c2a3da2016-02-16 13:39:07 +0900312 }
313
jskim8f27c4e2016-09-27 18:43:31 +0900314 private Optional<OpenstackPort> routerIfacePort(String osNetId, String osSubNetId) {
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700315 // FIXME router interface is subnet specific, not network
316 return openstackService.ports().stream()
317 .filter(p -> p.deviceOwner().equals(DEVICE_OWNER_ROUTER_INTERFACE) &&
jskim8f27c4e2016-09-27 18:43:31 +0900318 p.networkId().equals(osNetId) &&
319 p.fixedIps().containsKey(osSubNetId))
sangho6032f342016-07-07 14:32:03 +0900320 .findAny();
321 }
322
sangho3d2bf9c2016-08-26 17:19:55 +0900323 private Set<OpenstackSubnet> routableSubNets(String osRouterId) {
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700324 return openstackService.ports().stream()
325 .filter(p -> p.deviceOwner().equals(DEVICE_OWNER_ROUTER_INTERFACE) &&
326 p.deviceId().equals(osRouterId))
sangho3d2bf9c2016-08-26 17:19:55 +0900327 .map(p -> openstackService.subnet(p.fixedIps().keySet().stream().findFirst().get()))
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700328 .collect(Collectors.toSet());
329 }
sangho6032f342016-07-07 14:32:03 +0900330
sangho3d2bf9c2016-08-26 17:19:55 +0900331 private void populateExternalRules(OpenstackNetwork osNet, OpenstackSubnet osSubNet) {
332 populateCnodeToGateway(Long.valueOf(osNet.segmentId()), osSubNet.cidr());
333 populateGatewayToController(Long.valueOf(osNet.segmentId()), osSubNet.cidr());
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700334 }
335
jskim3d66aca2016-09-22 16:45:10 +0900336 private void removeExternalRules(OpenstackNetwork osNet, String subNetCidr) {
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700337 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
338 sBuilder.matchEthType(Ethernet.TYPE_IPV4)
339 .matchTunnelId(Long.valueOf(osNet.segmentId()))
jskim3d66aca2016-09-22 16:45:10 +0900340 .matchIPSrc(IpPrefix.valueOf(subNetCidr))
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700341 .matchEthDst(Constants.DEFAULT_GATEWAY_MAC);
342
Sho SHIMIZUa09e1bb2016-08-01 14:25:25 -0700343 nodeService.completeNodes().forEach(node -> {
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700344 ForwardingObjective.Flag flag = node.type().equals(GATEWAY) ?
345 ForwardingObjective.Flag.VERSATILE :
346 ForwardingObjective.Flag.SPECIFIC;
347
348 RulePopulatorUtil.removeRule(
349 flowObjectiveService,
350 appId,
351 node.intBridge(),
352 sBuilder.build(),
353 flag,
354 ROUTING_RULE_PRIORITY);
355 });
356 }
357
sangho3d2bf9c2016-08-26 17:19:55 +0900358 private void populateRoutingRules(Host host, Set<OpenstackSubnet> osSubNets) {
359 String osSubNetId = host.annotations().value(SUBNET_ID);
360 if (osSubNetId == null) {
Daniel Park81a61a12016-02-26 08:24:44 +0900361 return;
362 }
363
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700364 DeviceId localDevice = host.location().deviceId();
365 PortNumber localPort = host.location().port();
366 if (!nodeService.dataIp(localDevice).isPresent()) {
367 log.warn("Failed to populate L3 rules");
368 return;
sangho6032f342016-07-07 14:32:03 +0900369 }
sanghod177f8f2016-06-29 21:52:23 +0900370
sangho3d2bf9c2016-08-26 17:19:55 +0900371 Map<String, String> vniMap = new HashMap<>();
Sho SHIMIZU8ebb04a2016-10-06 15:58:29 -0700372 openstackService.networks().forEach(n -> vniMap.put(n.id(), n.segmentId()));
sangho3d2bf9c2016-08-26 17:19:55 +0900373
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700374 // TODO improve pipeline, do we have to install access rules between networks
375 // for every single VMs?
sangho3d2bf9c2016-08-26 17:19:55 +0900376 osSubNets.stream().filter(osSubNet -> !osSubNet.id().equals(osSubNetId)).forEach(osSubNet -> {
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700377 populateRoutingRulestoSameNode(
378 host.ipAddresses().stream().findFirst().get().getIp4Address(),
379 host.mac(),
380 localPort, localDevice,
sangho3d2bf9c2016-08-26 17:19:55 +0900381 Long.valueOf(vniMap.get(osSubNet.networkId())),
382 osSubNet.cidr());
sanghod177f8f2016-06-29 21:52:23 +0900383
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700384 nodeService.completeNodes().stream()
385 .filter(node -> node.type().equals(COMPUTE))
386 .filter(node -> !node.intBridge().equals(localDevice))
387 .forEach(node -> populateRoutingRulestoDifferentNode(
388 host.ipAddresses().stream().findFirst().get().getIp4Address(),
sangho3d2bf9c2016-08-26 17:19:55 +0900389 Long.valueOf(vniMap.get(osSubNet.networkId())),
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700390 node.intBridge(),
sangho3d2bf9c2016-08-26 17:19:55 +0900391 nodeService.dataIp(localDevice).get().getIp4Address(),
392 osSubNet.cidr()));
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700393 });
Daniel Park81a61a12016-02-26 08:24:44 +0900394 }
395
sangho3d2bf9c2016-08-26 17:19:55 +0900396 private void removeRoutingRules(Host host, Set<OpenstackSubnet> osSubNets) {
397 String osSubNetId = host.annotations().value(SUBNET_ID);
398 if (osSubNetId == null) {
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700399 return;
sangho6032f342016-07-07 14:32:03 +0900400 }
401
sangho3d2bf9c2016-08-26 17:19:55 +0900402 Map<String, String> vniMap = new HashMap<>();
Sho SHIMIZU8ebb04a2016-10-06 15:58:29 -0700403 openstackService.networks().forEach(n -> vniMap.put(n.id(), n.segmentId()));
sangho3d2bf9c2016-08-26 17:19:55 +0900404
405 osSubNets.stream().filter(osSubNet -> !osSubNet.id().equals(osSubNetId)).forEach(osSubNet -> {
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700406 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
407 sBuilder.matchEthType(Ethernet.TYPE_IPV4)
408 .matchIPDst(host.ipAddresses().stream().findFirst().get().toIpPrefix())
sangho3d2bf9c2016-08-26 17:19:55 +0900409 .matchIPSrc(IpPrefix.valueOf(osSubNet.cidr()))
410 .matchTunnelId(Long.valueOf(vniMap.get(osSubNet.networkId())));
sangho6032f342016-07-07 14:32:03 +0900411
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700412 nodeService.completeNodes().stream()
413 .filter(node -> node.type().equals(COMPUTE))
414 .forEach(node -> RulePopulatorUtil.removeRule(
415 flowObjectiveService,
416 appId,
417 node.intBridge(),
418 sBuilder.build(),
419 ForwardingObjective.Flag.SPECIFIC,
jskime4e99fa2016-09-13 13:11:53 +0900420 EW_ROUTING_RULE_PRIORITY));
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700421 });
sangho3d2bf9c2016-08-26 17:19:55 +0900422 log.debug("Removed routing rule from {} to {}", host, osSubNets);
Daniel Park81a61a12016-02-26 08:24:44 +0900423 }
Kyuhwi Choi5e65e2c2016-04-01 11:48:15 +0900424
sangho3d2bf9c2016-08-26 17:19:55 +0900425 private void populateGatewayToController(long vni, String subNetCidr) {
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700426 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
427 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
sangho6032f342016-07-07 14:32:03 +0900428
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700429 sBuilder.matchEthType(Ethernet.TYPE_IPV4)
430 .matchTunnelId(vni)
sangho3d2bf9c2016-08-26 17:19:55 +0900431 .matchIPSrc(IpPrefix.valueOf(subNetCidr))
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700432 .matchEthDst(Constants.DEFAULT_GATEWAY_MAC);
433 tBuilder.setOutput(PortNumber.CONTROLLER);
sangho6032f342016-07-07 14:32:03 +0900434
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700435 ForwardingObjective fo = DefaultForwardingObjective.builder()
436 .withSelector(sBuilder.build())
437 .withTreatment(tBuilder.build())
438 .withFlag(ForwardingObjective.Flag.VERSATILE)
439 .withPriority(ROUTING_RULE_PRIORITY)
440 .fromApp(appId)
441 .add();
sangho6032f342016-07-07 14:32:03 +0900442
Sho SHIMIZUa09e1bb2016-08-01 14:25:25 -0700443 gatewayService.getGatewayDeviceIds().forEach(deviceId -> flowObjectiveService.forward(deviceId, fo));
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700444 }
sangho6032f342016-07-07 14:32:03 +0900445
sangho3d2bf9c2016-08-26 17:19:55 +0900446 private void populateCnodeToGateway(long vni, String subnetCidr) {
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700447 nodeService.completeNodes().stream()
448 .filter(node -> node.type().equals(COMPUTE))
449 .forEach(node -> populateRuleToGateway(
450 node.intBridge(),
451 gatewayService.getGatewayGroupId(node.intBridge()),
sangho3d2bf9c2016-08-26 17:19:55 +0900452 vni, subnetCidr));
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700453 }
sangho6032f342016-07-07 14:32:03 +0900454
sangho3d2bf9c2016-08-26 17:19:55 +0900455 private void populateRuleToGateway(DeviceId deviceId, GroupId groupId, long vni, String cidr) {
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700456 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
457 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
sangho6032f342016-07-07 14:32:03 +0900458
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700459 sBuilder.matchEthType(Ethernet.TYPE_IPV4)
460 .matchTunnelId(vni)
sangho3d2bf9c2016-08-26 17:19:55 +0900461 .matchIPSrc(IpPrefix.valueOf(cidr))
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700462 .matchEthDst(Constants.DEFAULT_GATEWAY_MAC);
463
464 tBuilder.group(groupId);
465 ForwardingObjective fo = DefaultForwardingObjective.builder()
466 .withSelector(sBuilder.build())
467 .withTreatment(tBuilder.build())
468 .withFlag(ForwardingObjective.Flag.SPECIFIC)
469 .withPriority(ROUTING_RULE_PRIORITY)
470 .fromApp(appId)
471 .add();
472
473 flowObjectiveService.forward(deviceId, fo);
474 }
475
476 private void populateRoutingRulestoDifferentNode(Ip4Address vmIp, long vni,
sangho3d2bf9c2016-08-26 17:19:55 +0900477 DeviceId deviceId, Ip4Address hostIp,
478 String cidr) {
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700479 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
480 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
481
482 sBuilder.matchEthType(Ethernet.TYPE_IPV4)
483 .matchTunnelId(vni)
sangho3d2bf9c2016-08-26 17:19:55 +0900484 .matchIPSrc(IpPrefix.valueOf(cidr))
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700485 .matchIPDst(vmIp.toIpPrefix());
486 tBuilder.extension(buildExtension(deviceService, deviceId, hostIp), deviceId)
487 .setOutput(nodeService.tunnelPort(deviceId).get());
488
489 ForwardingObjective fo = DefaultForwardingObjective.builder()
490 .withSelector(sBuilder.build())
491 .withTreatment(tBuilder.build())
sangho3d2bf9c2016-08-26 17:19:55 +0900492 .withPriority(EW_ROUTING_RULE_PRIORITY)
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700493 .withFlag(ForwardingObjective.Flag.SPECIFIC)
494 .fromApp(appId)
495 .add();
496
497 flowObjectiveService.forward(deviceId, fo);
498 }
499
500 private void populateRoutingRulestoSameNode(Ip4Address vmIp, MacAddress vmMac,
sangho3d2bf9c2016-08-26 17:19:55 +0900501 PortNumber port, DeviceId deviceId, long vni,
502 String cidr) {
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700503 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
504 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
505
sangho3d2bf9c2016-08-26 17:19:55 +0900506 // FIXME: we need to check the VNI of the dest IP also just in case...
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700507 sBuilder.matchEthType(Ethernet.TYPE_IPV4)
508 .matchIPDst(vmIp.toIpPrefix())
sangho3d2bf9c2016-08-26 17:19:55 +0900509 .matchIPSrc(IpPrefix.valueOf(cidr))
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700510 .matchTunnelId(vni);
511
512 tBuilder.setEthDst(vmMac)
513 .setOutput(port);
514
515 ForwardingObjective fo = DefaultForwardingObjective.builder()
516 .withSelector(sBuilder.build())
517 .withTreatment(tBuilder.build())
sangho3d2bf9c2016-08-26 17:19:55 +0900518 .withPriority(EW_ROUTING_RULE_PRIORITY)
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700519 .withFlag(ForwardingObjective.Flag.SPECIFIC)
520 .fromApp(appId)
521 .add();
522
523 flowObjectiveService.forward(deviceId, fo);
524 }
525
526 private void reloadRoutingRules() {
527 eventExecutor.execute(() -> openstackService.ports().stream()
528 .filter(osPort -> osPort.deviceOwner().equals(DEVICE_OWNER_ROUTER_INTERFACE))
529 .forEach(osPort -> {
530 OpenstackRouter osRouter = openstackRouter(osPort.deviceId());
Daniel Parka8d896c2016-08-26 14:31:33 +0900531
532 setGatewayIcmp(Ip4Address.valueOf(openstackService
533 .subnet(osPort.fixedIps().keySet().stream().findAny().get()).gatewayIp()));
534
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700535 setRoutes(osRouter, Optional.empty());
536 if (osRouter.gatewayExternalInfo().externalFixedIps().size() > 0) {
sangho3d2bf9c2016-08-26 17:19:55 +0900537 String subnetId = osPort.fixedIps().keySet().stream().findFirst().get();
538 setExternalConnection(osRouter, subnetId);
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700539 }
540 }));
541 }
542
543 @Override
544 protected void hostDetected(Host host) {
545 String osNetId = host.annotations().value(NETWORK_ID);
jskim8f27c4e2016-09-27 18:43:31 +0900546 String osSubNetId = host.annotations().value(SUBNET_ID);
547 Optional<OpenstackPort> routerIface = routerIfacePort(osNetId, osSubNetId);
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700548 if (!routerIface.isPresent()) {
549 return;
sangho6032f342016-07-07 14:32:03 +0900550 }
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700551 eventExecutor.execute(() -> setRoutes(
552 openstackRouter(routerIface.get().deviceId()),
553 Optional.of(host)));
554 }
555
556 @Override
557 protected void hostRemoved(Host host) {
558 String osNetId = host.annotations().value(NETWORK_ID);
jskim8f27c4e2016-09-27 18:43:31 +0900559 String osSubNetId = host.annotations().value(SUBNET_ID);
560 Optional<OpenstackPort> routerIface = routerIfacePort(osNetId, osSubNetId);
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700561 if (!routerIface.isPresent()) {
562 return;
563 }
sangho3d2bf9c2016-08-26 17:19:55 +0900564 Set<OpenstackSubnet> routableSubNets = routableSubNets(routerIface.get().deviceId());
565 eventExecutor.execute(() -> removeRoutingRules(host, routableSubNets));
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700566 }
567
jskimaa851932016-10-27 17:45:30 +0900568 @Override
569 public void reinstallVmFlow(Host host) {
570 if (host == null) {
571 hostService.getHosts().forEach(h -> {
572 hostDetected(h);
573 log.info("Re-Install data plane flow of virtual machine {}", h);
574 });
575 } else {
576 hostDetected(host);
577 log.info("Re-Install data plane flow of virtual machine {}", host);
578 }
579 }
580
581 @Override
582 public void purgeVmFlow(Host host) {
583 if (host == null) {
584 hostService.getHosts().forEach(h -> {
585 hostRemoved(h);
586 log.info("Purge data plane flow of virtual machine {}", h);
587 });
588 } else {
589 hostRemoved(host);
590 log.info("Purge data plane flow of virtual machine {}", host);
591 }
592 }
593
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700594 private class InternalNodeListener implements OpenstackNodeListener {
Kyuhwi Choi5e65e2c2016-04-01 11:48:15 +0900595
596 @Override
sangho6032f342016-07-07 14:32:03 +0900597 public void event(OpenstackNodeEvent event) {
598 OpenstackNode node = event.node();
599
600 switch (event.type()) {
601 case COMPLETE:
602 log.info("COMPLETE node {} detected", node.hostname());
Hyunsun Moon5aa480b2016-08-03 12:23:14 -0700603 eventExecutor.execute(() -> {
604 if (node.type() == GATEWAY) {
605 GatewayNode gnode = GatewayNode.builder()
606 .gatewayDeviceId(node.intBridge())
607 .dataIpAddress(node.dataIp().getIp4Address())
608 .uplinkIntf(node.externalPortName().get())
609 .build();
610 gatewayService.addGatewayNode(gnode);
611 }
612 reloadRoutingRules();
613 });
sangho6032f342016-07-07 14:32:03 +0900614 break;
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700615 case INIT:
616 case DEVICE_CREATED:
sangho6032f342016-07-07 14:32:03 +0900617 case INCOMPLETE:
Daniel Parkf1af0682016-08-09 14:39:57 +0900618 eventExecutor.execute(() -> {
619 if (node.type() == GATEWAY) {
620 GatewayNode gnode = GatewayNode.builder()
621 .gatewayDeviceId(node.intBridge())
622 .dataIpAddress(node.dataIp().getIp4Address())
623 .uplinkIntf(node.externalPortName().get())
624 .build();
625 gatewayService.deleteGatewayNode(gnode);
626 }
627 reloadRoutingRules();
628 });
sangho6032f342016-07-07 14:32:03 +0900629 default:
630 break;
Kyuhwi Choi5e65e2c2016-04-01 11:48:15 +0900631 }
sangho6032f342016-07-07 14:32:03 +0900632 }
633 }
sangho0c2a3da2016-02-16 13:39:07 +0900634}