blob: e44824177141cdbd420006e4ef9f7d2df3e72a03 [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
Kyuhwi Choi92d9ea42016-06-13 17:28:00 +090018import com.google.common.collect.Lists;
sangho0c2a3da2016-02-16 13:39:07 +090019import org.onlab.packet.Ethernet;
20import org.onlab.packet.IPv4;
21import org.onlab.packet.Ip4Address;
22import org.onlab.packet.IpAddress;
23import org.onlab.packet.IpPrefix;
24import org.onlab.packet.MacAddress;
25import org.onlab.packet.TCP;
26import org.onlab.packet.TpPort;
27import org.onlab.packet.UDP;
28import org.onosproject.core.ApplicationId;
Kyuhwi Choi92d9ea42016-06-13 17:28:00 +090029import org.onosproject.core.GroupId;
sangho0c2a3da2016-02-16 13:39:07 +090030import org.onosproject.net.Device;
31import org.onosproject.net.DeviceId;
sangho6032f342016-07-07 14:32:03 +090032import org.onosproject.net.Host;
sangho0c2a3da2016-02-16 13:39:07 +090033import org.onosproject.net.Port;
34import org.onosproject.net.PortNumber;
35import org.onosproject.net.behaviour.ExtensionTreatmentResolver;
36import org.onosproject.net.device.DeviceService;
37import org.onosproject.net.driver.DefaultDriverData;
38import org.onosproject.net.driver.DefaultDriverHandler;
39import org.onosproject.net.driver.Driver;
40import org.onosproject.net.driver.DriverHandler;
41import org.onosproject.net.driver.DriverService;
42import org.onosproject.net.flow.DefaultTrafficSelector;
43import org.onosproject.net.flow.DefaultTrafficTreatment;
44import org.onosproject.net.flow.TrafficSelector;
45import org.onosproject.net.flow.TrafficTreatment;
46import org.onosproject.net.flow.instructions.ExtensionPropertyException;
47import org.onosproject.net.flow.instructions.ExtensionTreatment;
48import org.onosproject.net.flow.instructions.ExtensionTreatmentType;
49import org.onosproject.net.flowobjective.DefaultForwardingObjective;
50import org.onosproject.net.flowobjective.FlowObjectiveService;
51import org.onosproject.net.flowobjective.ForwardingObjective;
52import org.onosproject.net.packet.InboundPacket;
sangho93447f12016-02-24 00:33:22 +090053import org.onosproject.openstackinterface.OpenstackInterfaceService;
54import org.onosproject.openstackinterface.OpenstackPort;
sangho93447f12016-02-24 00:33:22 +090055import org.onosproject.openstackinterface.OpenstackRouterInterface;
56import org.onosproject.openstackinterface.OpenstackSubnet;
Kyuhwi Choiee9e3712016-02-22 22:49:36 +090057import org.onosproject.openstackinterface.OpenstackFloatingIP;
sangho6032f342016-07-07 14:32:03 +090058import org.onosproject.openstacknetworking.Constants;
Kyuhwi Choi5e65e2c2016-04-01 11:48:15 +090059import org.onosproject.openstacknetworking.OpenstackRoutingService;
Kyuhwi Choi92d9ea42016-06-13 17:28:00 +090060import org.onosproject.scalablegateway.api.ScalableGatewayService;
sangho6032f342016-07-07 14:32:03 +090061import org.onosproject.openstacknode.OpenstackNode;
62import org.onosproject.openstacknode.OpenstackNodeService;
sangho0c2a3da2016-02-16 13:39:07 +090063import org.slf4j.Logger;
64import org.slf4j.LoggerFactory;
65
Kyuhwi Choi5e65e2c2016-04-01 11:48:15 +090066import java.util.List;
sangho6032f342016-07-07 14:32:03 +090067import java.util.Optional;
sangho0c2a3da2016-02-16 13:39:07 +090068import java.util.stream.StreamSupport;
69
70import static com.google.common.base.Preconditions.checkNotNull;
Kyuhwi Choi5e65e2c2016-04-01 11:48:15 +090071import static org.onlab.osgi.DefaultServiceDirectory.getService;
sangho0c2a3da2016-02-16 13:39:07 +090072
73/**
74 * Populates Routing Flow Rules.
75 */
76public class OpenstackRoutingRulePopulator {
77
Kyuhwi Choie2b37e32016-02-05 14:04:14 +090078 private final Logger log = LoggerFactory.getLogger(getClass());
sangho0c2a3da2016-02-16 13:39:07 +090079
Kyuhwi Choie2b37e32016-02-05 14:04:14 +090080 private final ApplicationId appId;
81 private final FlowObjectiveService flowObjectiveService;
sangho93447f12016-02-24 00:33:22 +090082 private final OpenstackInterfaceService openstackService;
Kyuhwi Choie2b37e32016-02-05 14:04:14 +090083 private final DeviceService deviceService;
84 private final DriverService driverService;
Kyuhwi Choi92d9ea42016-06-13 17:28:00 +090085 private final ScalableGatewayService gatewayService;
sangho6032f342016-07-07 14:32:03 +090086 private final OpenstackNodeService nodeService;
sangho0c2a3da2016-02-16 13:39:07 +090087
Kyuhwi Choie2b37e32016-02-05 14:04:14 +090088 private static final String PORTNAME_PREFIX_TUNNEL = "vxlan";
89 private static final String PORTNAME = "portName";
Kyuhwi Choiee9e3712016-02-22 22:49:36 +090090 private static final String PORTNAME_PREFIX_VM = "tap";
Kyuhwi Choie2b37e32016-02-05 14:04:14 +090091
92 private static final String PORTNOTNULL = "Port can not be null";
Kyuhwi Choiee9e3712016-02-22 22:49:36 +090093 private static final String DEVICENOTNULL = "Device can not be null";
Kyuhwi Choi92d9ea42016-06-13 17:28:00 +090094 private static final String EXTPORTNOTNULL = "External port can not be null";
Kyuhwi Choie2b37e32016-02-05 14:04:14 +090095 private static final String TUNNEL_DESTINATION = "tunnelDst";
sangho0c2a3da2016-02-16 13:39:07 +090096 private static final int ROUTING_RULE_PRIORITY = 25000;
Kyuhwi Choiee9e3712016-02-22 22:49:36 +090097 private static final int FLOATING_RULE_PRIORITY = 42000;
98 private static final int PNAT_RULE_PRIORITY = 26000;
sangho0c2a3da2016-02-16 13:39:07 +090099 private static final int PNAT_TIMEOUT = 120;
Daniel Park23193902016-03-24 18:17:19 +0900100 private static final int PREFIX_LENGTH = 32;
sangho0c2a3da2016-02-16 13:39:07 +0900101
102 private InboundPacket inboundPacket;
103 private OpenstackPort openstackPort;
104 private int portNum;
105 private MacAddress externalInterface;
106 private MacAddress externalRouter;
sangho0c2a3da2016-02-16 13:39:07 +0900107
Kyuhwi Choie2b37e32016-02-05 14:04:14 +0900108 /**
109 * The constructor of openstackRoutingRulePopulator.
110 *
111 * @param appId Caller`s appId
Kyuhwi Choi5e65e2c2016-04-01 11:48:15 +0900112 * @param openstackService Opestack REST request handler
Kyuhwi Choie2b37e32016-02-05 14:04:14 +0900113 * @param flowObjectiveService FlowObjectiveService
114 * @param deviceService DeviceService
115 * @param driverService DriverService
Kyuhwi Choi92d9ea42016-06-13 17:28:00 +0900116 * @param gatewayService scalable gateway service
Kyuhwi Choie2b37e32016-02-05 14:04:14 +0900117 */
sangho6032f342016-07-07 14:32:03 +0900118 public OpenstackRoutingRulePopulator(ApplicationId appId,
119 OpenstackInterfaceService openstackService,
120 FlowObjectiveService flowObjectiveService,
121 DeviceService deviceService,
122 DriverService driverService,
123 OpenstackNodeService nodeService,
Kyuhwi Choi92d9ea42016-06-13 17:28:00 +0900124 ScalableGatewayService gatewayService) {
sangho0c2a3da2016-02-16 13:39:07 +0900125 this.appId = appId;
126 this.flowObjectiveService = flowObjectiveService;
Daniel Park81a61a12016-02-26 08:24:44 +0900127 this.openstackService = checkNotNull(openstackService);
sangho0c2a3da2016-02-16 13:39:07 +0900128 this.deviceService = deviceService;
129 this.driverService = driverService;
Kyuhwi Choi92d9ea42016-06-13 17:28:00 +0900130 this.gatewayService = gatewayService;
sangho6032f342016-07-07 14:32:03 +0900131 this.nodeService = nodeService;
sangho0c2a3da2016-02-16 13:39:07 +0900132 }
133
Kyuhwi Choie2b37e32016-02-05 14:04:14 +0900134 /**
135 * Populates flow rules for Pnat configurations.
Daniel Park81a61a12016-02-26 08:24:44 +0900136 *
137 * @param inboundPacket Packet-in event packet
Kyuhwi Choie2b37e32016-02-05 14:04:14 +0900138 * @param openstackPort Target VM information
139 * @param portNum Pnat port number
Hyunsun Moon0dba61f2016-03-03 14:05:21 -0800140 * @param externalIp external ip address
Kyuhwi Choie2b37e32016-02-05 14:04:14 +0900141 * @param externalInterfaceMacAddress Gateway external interface macaddress
142 * @param externalRouterMacAddress Outer(physical) router`s macaddress
143 */
sangho0c2a3da2016-02-16 13:39:07 +0900144 public void populatePnatFlowRules(InboundPacket inboundPacket, OpenstackPort openstackPort, int portNum,
Kyuhwi Choie2b37e32016-02-05 14:04:14 +0900145 Ip4Address externalIp, MacAddress externalInterfaceMacAddress,
146 MacAddress externalRouterMacAddress) {
sangho0c2a3da2016-02-16 13:39:07 +0900147 this.inboundPacket = inboundPacket;
148 this.openstackPort = openstackPort;
149 this.portNum = portNum;
150 this.externalInterface = externalInterfaceMacAddress;
151 this.externalRouter = externalRouterMacAddress;
152
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900153 long vni = getVni(openstackPort.networkId());
sangho0c2a3da2016-02-16 13:39:07 +0900154
Kyuhwi Choie2b37e32016-02-05 14:04:14 +0900155 populatePnatIncomingFlowRules(vni, externalIp);
156 populatePnatOutgoingFlowRules(vni, externalIp);
sangho0c2a3da2016-02-16 13:39:07 +0900157 }
158
Kyuhwi Choie2b37e32016-02-05 14:04:14 +0900159 private void populatePnatOutgoingFlowRules(long vni, Ip4Address externalIp) {
sangho0c2a3da2016-02-16 13:39:07 +0900160 IPv4 iPacket = (IPv4) inboundPacket.parsed().getPayload();
161
162 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
163 sBuilder.matchEthType(Ethernet.TYPE_IPV4)
164 .matchIPProtocol(iPacket.getProtocol())
165 .matchTunnelId(vni)
166 .matchIPSrc(IpPrefix.valueOf(iPacket.getSourceAddress(), 32))
167 .matchIPDst(IpPrefix.valueOf(iPacket.getDestinationAddress(), 32));
168
169 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
sangho0c2a3da2016-02-16 13:39:07 +0900170
171 switch (iPacket.getProtocol()) {
172 case IPv4.PROTOCOL_TCP:
173 TCP tcpPacket = (TCP) iPacket.getPayload();
174 sBuilder.matchTcpSrc(TpPort.tpPort(tcpPacket.getSourcePort()))
175 .matchTcpDst(TpPort.tpPort(tcpPacket.getDestinationPort()));
Kyuhwi Choie2b37e32016-02-05 14:04:14 +0900176 tBuilder.setTcpSrc(TpPort.tpPort(portNum));
sangho0c2a3da2016-02-16 13:39:07 +0900177 break;
178 case IPv4.PROTOCOL_UDP:
179 UDP udpPacket = (UDP) iPacket.getPayload();
Kyuhwi Choie2b37e32016-02-05 14:04:14 +0900180 sBuilder.matchUdpSrc(TpPort.tpPort(udpPacket.getSourcePort()))
sangho0c2a3da2016-02-16 13:39:07 +0900181 .matchUdpDst(TpPort.tpPort(udpPacket.getDestinationPort()));
Kyuhwi Choie2b37e32016-02-05 14:04:14 +0900182 tBuilder.setUdpSrc(TpPort.tpPort(portNum));
sangho0c2a3da2016-02-16 13:39:07 +0900183 break;
184 default:
Daniel Park81a61a12016-02-26 08:24:44 +0900185 log.debug("Unsupported IPv4 protocol {}");
sangho0c2a3da2016-02-16 13:39:07 +0900186 break;
187 }
188
Kyuhwi Choi92d9ea42016-06-13 17:28:00 +0900189 tBuilder.setIpSrc(externalIp);
190 gatewayService.getGatewayNodes().forEach(node -> {
191 tBuilder.setOutput(gatewayService.getGatewayExternalPorts(node.getGatewayDeviceId()).get(0));
192 ForwardingObjective fo = DefaultForwardingObjective.builder()
193 .withSelector(sBuilder.build())
194 .withTreatment(tBuilder.build())
195 .withFlag(ForwardingObjective.Flag.VERSATILE)
196 .withPriority(PNAT_RULE_PRIORITY)
197 .makeTemporary(PNAT_TIMEOUT)
198 .fromApp(appId)
199 .add();
sangho0c2a3da2016-02-16 13:39:07 +0900200
Kyuhwi Choi92d9ea42016-06-13 17:28:00 +0900201 flowObjectiveService.forward(node.getGatewayDeviceId(), fo);
202 });
Kyuhwi Choi5e65e2c2016-04-01 11:48:15 +0900203
sangho0c2a3da2016-02-16 13:39:07 +0900204 }
205
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900206 private Port getPortOfExternalInterface() {
207 return deviceService.getPorts(getGatewayNode().id()).stream()
sangho6032f342016-07-07 14:32:03 +0900208 .filter(p -> p.annotations().value(PORTNAME)
209 .equals(org.onosproject.openstacknode.Constants.PATCH_INTG_BRIDGE))
sangho0c2a3da2016-02-16 13:39:07 +0900210 .findAny().orElse(null);
211 }
212
213
Kyuhwi Choie2b37e32016-02-05 14:04:14 +0900214 private void populatePnatIncomingFlowRules(long vni, Ip4Address externalIp) {
sangho0c2a3da2016-02-16 13:39:07 +0900215 IPv4 iPacket = (IPv4) inboundPacket.parsed().getPayload();
sangho0c2a3da2016-02-16 13:39:07 +0900216
217 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
218 sBuilder.matchEthType(Ethernet.TYPE_IPV4)
219 .matchIPProtocol(iPacket.getProtocol())
Kyuhwi Choie2b37e32016-02-05 14:04:14 +0900220 .matchIPDst(IpPrefix.valueOf(externalIp, 32))
sangho0c2a3da2016-02-16 13:39:07 +0900221 .matchIPSrc(IpPrefix.valueOf(iPacket.getDestinationAddress(), 32));
222
223 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
224 tBuilder.setTunnelId(vni)
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900225 .setEthDst(inboundPacket.parsed().getSourceMAC())
sangho0c2a3da2016-02-16 13:39:07 +0900226 .setIpDst(IpAddress.valueOf(iPacket.getSourceAddress()));
227
228 switch (iPacket.getProtocol()) {
229 case IPv4.PROTOCOL_TCP:
230 TCP tcpPacket = (TCP) iPacket.getPayload();
231 sBuilder.matchTcpSrc(TpPort.tpPort(tcpPacket.getDestinationPort()))
232 .matchTcpDst(TpPort.tpPort(portNum));
233 tBuilder.setTcpDst(TpPort.tpPort(tcpPacket.getSourcePort()));
234 break;
235 case IPv4.PROTOCOL_UDP:
236 UDP udpPacket = (UDP) iPacket.getPayload();
237 sBuilder.matchUdpSrc(TpPort.tpPort(udpPacket.getDestinationPort()))
238 .matchUdpDst(TpPort.tpPort(portNum));
239 tBuilder.setUdpDst(TpPort.tpPort(udpPacket.getSourcePort()));
240 break;
241 default:
242 break;
243 }
244
Kyuhwi Choi92d9ea42016-06-13 17:28:00 +0900245 getGatewayNodeList().forEach(node -> {
246 DeviceId deviceId = node.id();
sangho6032f342016-07-07 14:32:03 +0900247 tBuilder.extension(buildNiciraExtenstion(deviceId,
248 getHostIpfromOpenstackPort(openstackPort).getIp4Address()), deviceId)
Kyuhwi Choi92d9ea42016-06-13 17:28:00 +0900249 .setOutput(getTunnelPort(deviceId));
sangho0c2a3da2016-02-16 13:39:07 +0900250
Kyuhwi Choi92d9ea42016-06-13 17:28:00 +0900251 ForwardingObjective fo = DefaultForwardingObjective.builder()
252 .withSelector(sBuilder.build())
253 .withTreatment(tBuilder.build())
254 .withFlag(ForwardingObjective.Flag.VERSATILE)
255 .withPriority(PNAT_RULE_PRIORITY)
256 .makeTemporary(PNAT_TIMEOUT)
257 .fromApp(appId)
258 .add();
sangho0c2a3da2016-02-16 13:39:07 +0900259
Kyuhwi Choi92d9ea42016-06-13 17:28:00 +0900260 flowObjectiveService.forward(deviceId, fo);
261 });
262 }
263
264 private List<Device> getGatewayNodeList() {
265 List<Device> devices = Lists.newArrayList();
266 gatewayService.getGatewayDeviceIds().forEach(deviceId ->
267 devices.add(checkNotNull(deviceService.getDevice(deviceId))));
268 return devices;
sangho0c2a3da2016-02-16 13:39:07 +0900269 }
270
sangho6032f342016-07-07 14:32:03 +0900271 private IpAddress getHostIpfromOpenstackPort(OpenstackPort openstackPort) {
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900272 Device device = getDevicefromOpenstackPort(openstackPort);
sangho6032f342016-07-07 14:32:03 +0900273
274 Optional<IpAddress> ipAddress = nodeService.dataIp(device.id());
275 if (!ipAddress.isPresent()) {
276 log.warn("No IP address found for device {}", device.id());
277 return null;
278 }
279
280 return ipAddress.get();
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900281 }
Daniel Park81a61a12016-02-26 08:24:44 +0900282
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900283 private Device getDevicefromOpenstackPort(OpenstackPort openstackPort) {
284 String openstackPortName = PORTNAME_PREFIX_VM + openstackPort.id().substring(0, 11);
285 Device device = StreamSupport.stream(deviceService.getDevices().spliterator(), false)
Kyuhwi Choi92d9ea42016-06-13 17:28:00 +0900286 .filter(d -> findPortinDevice(d.id(), openstackPortName))
Kyuhwi Choi5e65e2c2016-04-01 11:48:15 +0900287 .iterator()
288 .next();
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900289 checkNotNull(device, DEVICENOTNULL);
290 return device;
291 }
292
Kyuhwi Choi92d9ea42016-06-13 17:28:00 +0900293 private boolean findPortinDevice(DeviceId deviceId, String openstackPortName) {
294 Port port = deviceService.getPorts(deviceId)
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900295 .stream()
296 .filter(p -> p.isEnabled() && p.annotations().value(PORTNAME).equals(openstackPortName))
297 .findAny()
298 .orElse(null);
Daniel Park23193902016-03-24 18:17:19 +0900299 return port != null;
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900300 }
301
302 /**
Kyuhwi Choi5e65e2c2016-04-01 11:48:15 +0900303 * Builds Nicira extension for tagging remoteIp of vxlan.
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900304 *
Kyuhwi Choi92d9ea42016-06-13 17:28:00 +0900305 * @param deviceId Device Id of vxlan source device
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900306 * @param hostIp Remote Ip of vxlan destination device
307 * @return NiciraExtension Treatment
308 */
Kyuhwi Choi92d9ea42016-06-13 17:28:00 +0900309 public ExtensionTreatment buildNiciraExtenstion(DeviceId deviceId, Ip4Address hostIp) {
310 Driver driver = driverService.getDriver(deviceId);
311 DriverHandler driverHandler = new DefaultDriverHandler(new DefaultDriverData(driver, deviceId));
sangho0c2a3da2016-02-16 13:39:07 +0900312 ExtensionTreatmentResolver resolver = driverHandler.behaviour(ExtensionTreatmentResolver.class);
313
314 ExtensionTreatment extensionInstruction =
315 resolver.getExtensionInstruction(
316 ExtensionTreatmentType.ExtensionTreatmentTypes.NICIRA_SET_TUNNEL_DST.type());
317
318 try {
Kyuhwi Choie2b37e32016-02-05 14:04:14 +0900319 extensionInstruction.setPropertyValue(TUNNEL_DESTINATION, hostIp);
sangho0c2a3da2016-02-16 13:39:07 +0900320 } catch (ExtensionPropertyException e) {
321 log.error("Error setting Nicira extension setting {}", e);
322 }
323
324 return extensionInstruction;
325 }
326
Daniel Park81a61a12016-02-26 08:24:44 +0900327 /**
328 * Returns port number of vxlan tunnel.
329 *
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900330 * @param deviceId Target Device Id
331 * @return PortNumber
Daniel Park81a61a12016-02-26 08:24:44 +0900332 */
333 public PortNumber getTunnelPort(DeviceId deviceId) {
sangho0c2a3da2016-02-16 13:39:07 +0900334 Port port = deviceService.getPorts(deviceId).stream()
Kyuhwi Choie2b37e32016-02-05 14:04:14 +0900335 .filter(p -> p.annotations().value(PORTNAME).equals(PORTNAME_PREFIX_TUNNEL))
sangho0c2a3da2016-02-16 13:39:07 +0900336 .findAny().orElse(null);
337
338 if (port == null) {
339 log.error("No TunnelPort was created.");
340 return null;
341 }
342 return port.number();
343
344 }
345
Kyuhwi Choie2b37e32016-02-05 14:04:14 +0900346 /**
347 * Populates flow rules from openstackComputeNode to GatewayNode.
348 *
349 * @param vni Target network
Kyuhwi Choie2b37e32016-02-05 14:04:14 +0900350 */
Daniel Park23193902016-03-24 18:17:19 +0900351 public void populateExternalRules(long vni) {
sangho0c2a3da2016-02-16 13:39:07 +0900352
353 // 1. computeNode to gateway
354 populateComputeNodeRules(vni);
355 // 2. gatewayNode to controller
356 populateRuleGatewaytoController(vni);
357 }
358
359 private void populateRuleGatewaytoController(long vni) {
sangho0c2a3da2016-02-16 13:39:07 +0900360 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
361 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
362
363 sBuilder.matchEthType(Ethernet.TYPE_IPV4)
364 .matchTunnelId(vni)
sangho6032f342016-07-07 14:32:03 +0900365 .matchEthDst(Constants.GATEWAY_MAC);
sangho0c2a3da2016-02-16 13:39:07 +0900366 tBuilder.setOutput(PortNumber.CONTROLLER);
367
368 ForwardingObjective fo = DefaultForwardingObjective.builder()
369 .withSelector(sBuilder.build())
370 .withTreatment(tBuilder.build())
371 .withFlag(ForwardingObjective.Flag.VERSATILE)
372 .withPriority(ROUTING_RULE_PRIORITY)
373 .fromApp(appId)
374 .add();
375
Kyuhwi Choi92d9ea42016-06-13 17:28:00 +0900376 getGatewayNodeList().forEach(device -> flowObjectiveService.forward(device.id(), fo));
sangho0c2a3da2016-02-16 13:39:07 +0900377 }
378
379 private void populateComputeNodeRules(long vni) {
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900380 StreamSupport.stream(deviceService.getDevices().spliterator(), false)
sangho6032f342016-07-07 14:32:03 +0900381 .filter(d -> isTypeOf(d.id(), OpenstackNodeService.NodeType.COMPUTE))
Kyuhwi Choi92d9ea42016-06-13 17:28:00 +0900382 .forEach(d -> populateRuleToGatewayBySgw(d.id(),
383 gatewayService.getGroupIdForGatewayLoadBalance(d.id()), vni));
sangho0c2a3da2016-02-16 13:39:07 +0900384 }
385
Kyuhwi Choi92d9ea42016-06-13 17:28:00 +0900386 private void populateRuleToGatewayBySgw(DeviceId deviceId, GroupId groupId, long vni) {
sangho0c2a3da2016-02-16 13:39:07 +0900387 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
388 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
389
390 sBuilder.matchEthType(Ethernet.TYPE_IPV4)
391 .matchTunnelId(vni)
sangho6032f342016-07-07 14:32:03 +0900392 .matchEthDst(Constants.GATEWAY_MAC);
393
Kyuhwi Choi92d9ea42016-06-13 17:28:00 +0900394 tBuilder.group(groupId);
sangho0c2a3da2016-02-16 13:39:07 +0900395
396 ForwardingObjective fo = DefaultForwardingObjective.builder()
397 .withSelector(sBuilder.build())
398 .withTreatment(tBuilder.build())
399 .withFlag(ForwardingObjective.Flag.SPECIFIC)
400 .withPriority(ROUTING_RULE_PRIORITY)
401 .fromApp(appId)
402 .add();
403
Kyuhwi Choi92d9ea42016-06-13 17:28:00 +0900404 flowObjectiveService.forward(deviceId, fo);
405 }
406
sangho6032f342016-07-07 14:32:03 +0900407 /*
Kyuhwi Choi92d9ea42016-06-13 17:28:00 +0900408 private void populateRuleToGateway(DeviceId deviceId, Device gatewayDevice, long vni) {
409 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
410 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
411
412 sBuilder.matchEthType(Ethernet.TYPE_IPV4)
413 .matchTunnelId(vni)
sangho6032f342016-07-07 14:32:03 +0900414 .matchEthDst(Constants.GATEWAY_MAC);
415 tBuilder.extension(buildNiciraExtenstion(deviceId, nodeService.nodes().get(gatewayDevice.id())), deviceId)
Kyuhwi Choi92d9ea42016-06-13 17:28:00 +0900416 .setOutput(getTunnelPort(deviceId));
417
418 ForwardingObjective fo = DefaultForwardingObjective.builder()
419 .withSelector(sBuilder.build())
420 .withTreatment(tBuilder.build())
421 .withFlag(ForwardingObjective.Flag.SPECIFIC)
422 .withPriority(ROUTING_RULE_PRIORITY)
423 .fromApp(appId)
424 .add();
425
426 flowObjectiveService.forward(deviceId, fo);
sangho0c2a3da2016-02-16 13:39:07 +0900427 }
sangho6032f342016-07-07 14:32:03 +0900428 */
sangho0c2a3da2016-02-16 13:39:07 +0900429
sangho0c2a3da2016-02-16 13:39:07 +0900430 private Device getGatewayNode() {
sangho6032f342016-07-07 14:32:03 +0900431
432 // TODO Return the correct gateway node
433 Optional<OpenstackNode> gwNode = nodeService.nodes().stream()
434 .filter(n -> n.type().equals(OpenstackNodeService.NodeType.GATEWAY))
435 .findFirst();
436
437 if (!gwNode.isPresent()) {
438 log.warn("No Gateway is defined.");
439 return null;
440 }
441
442 return deviceService.getDevice(gwNode.get().intBridge());
sangho0c2a3da2016-02-16 13:39:07 +0900443 }
444
sangho6032f342016-07-07 14:32:03 +0900445 private boolean isTypeOf(DeviceId deviceId, OpenstackNodeService.NodeType type) {
446
447 Optional<OpenstackNode> node = nodeService.nodes().stream()
448 .filter(n -> n.intBridge().equals(deviceId) ||
449 (n.routerBridge().isPresent() && n.routerBridge().get().equals(deviceId)))
450 .filter(n -> n.type().equals(type))
451 .findFirst();
452
453 if (node.isPresent()) {
454 return true;
455 }
456
457 return false;
sangho0c2a3da2016-02-16 13:39:07 +0900458 }
459
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900460 private long getVni(String netId) {
461 return Long.parseLong(openstackService.network(netId).segmentId());
Kyuhwi Choie2b37e32016-02-05 14:04:14 +0900462 }
463
464 /**
465 * Remove flow rules for external connection.
466 *
467 * @param routerInterface Corresponding routerInterface
468 */
sangho0c2a3da2016-02-16 13:39:07 +0900469 public void removeExternalRules(OpenstackRouterInterface routerInterface) {
Kyuhwi Choie2b37e32016-02-05 14:04:14 +0900470 OpenstackSubnet openstackSubnet = openstackService.subnet(routerInterface.subnetId());
sangho0c2a3da2016-02-16 13:39:07 +0900471 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
472 sBuilder.matchEthType(Ethernet.TYPE_IPV4)
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900473 .matchTunnelId(getVni(openstackSubnet.networkId()))
sangho6032f342016-07-07 14:32:03 +0900474 .matchEthDst(Constants.GATEWAY_MAC);
sangho0c2a3da2016-02-16 13:39:07 +0900475
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900476 StreamSupport.stream(deviceService.getDevices().spliterator(), false)
sangho0c2a3da2016-02-16 13:39:07 +0900477 .forEach(d -> {
sangho6032f342016-07-07 14:32:03 +0900478 ForwardingObjective.Flag flag = isTypeOf(d.id(), OpenstackNodeService.NodeType.GATEWAY) ?
Kyuhwi Choi5e65e2c2016-04-01 11:48:15 +0900479 ForwardingObjective.Flag.VERSATILE :
480 ForwardingObjective.Flag.SPECIFIC;
Daniel Park23193902016-03-24 18:17:19 +0900481 removeRule(d.id(), sBuilder, flag, ROUTING_RULE_PRIORITY);
sangho0c2a3da2016-02-16 13:39:07 +0900482 });
483
484 }
485
Kyuhwi Choi92d9ea42016-06-13 17:28:00 +0900486 private void removeRule(DeviceId deviceId, TrafficSelector.Builder sBuilder,
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900487 ForwardingObjective.Flag flag, int priority) {
sangho0c2a3da2016-02-16 13:39:07 +0900488 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
489
490 ForwardingObjective fo = DefaultForwardingObjective.builder()
491 .withSelector(sBuilder.build())
492 .withTreatment(tBuilder.build())
493 .withFlag(flag)
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900494 .withPriority(priority)
sangho0c2a3da2016-02-16 13:39:07 +0900495 .fromApp(appId)
496 .remove();
497
Kyuhwi Choi92d9ea42016-06-13 17:28:00 +0900498 flowObjectiveService.forward(deviceId, fo);
sangho0c2a3da2016-02-16 13:39:07 +0900499 }
500
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900501 /**
502 * Populates flow rules for floatingIp configuration.
503 *
504 * @param floatingIP Corresponding floating ip information
505 */
506 public void populateFloatingIpRules(OpenstackFloatingIP floatingIP) {
507 OpenstackPort port = openstackService.port(floatingIP.portId());
508 //1. incoming rules
509 populateFloatingIpIncomingRules(floatingIP, port);
510 //2. outgoing rules
511 populateFloatingIpOutgoingRules(floatingIP, port);
512 }
513
514 private void populateFloatingIpIncomingRules(OpenstackFloatingIP floatingIP, OpenstackPort port) {
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900515 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
516 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
517
518 sBuilder.matchEthType(Ethernet.TYPE_IPV4)
Daniel Park23193902016-03-24 18:17:19 +0900519 .matchIPDst(IpPrefix.valueOf(floatingIP.floatingIpAddress(), PREFIX_LENGTH));
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900520
sangho6032f342016-07-07 14:32:03 +0900521 DeviceId gatewayDeviceId = DeviceId.deviceId(port.deviceId());
522 Optional<IpAddress> ipAddress = nodeService.dataIp(gatewayDeviceId);
523 if (!ipAddress.isPresent()) {
524 log.warn("No IP address found for device {}", port.deviceId());
525 return;
526 }
527 tBuilder.setEthSrc(Constants.GATEWAY_MAC)
528 .setEthDst(port.macAddress())
529 .setIpDst(floatingIP.fixedIpAddress())
530 .setTunnelId(getVni(port.networkId()))
531 .extension(buildNiciraExtenstion(gatewayDeviceId,
532 ipAddress.get().getIp4Address()), gatewayDeviceId)
533 .setOutput(getTunnelPort(gatewayDeviceId));
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900534
sangho6032f342016-07-07 14:32:03 +0900535 ForwardingObjective fo = DefaultForwardingObjective.builder()
536 .withSelector(sBuilder.build())
537 .withTreatment(tBuilder.build())
538 .withFlag(ForwardingObjective.Flag.VERSATILE)
539 .withPriority(FLOATING_RULE_PRIORITY)
540 .fromApp(appId)
541 .add();
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900542
sangho6032f342016-07-07 14:32:03 +0900543 flowObjectiveService.forward(getGatewayNode().id(), fo);
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900544 }
545
546 private void populateFloatingIpOutgoingRules(OpenstackFloatingIP floatingIP, OpenstackPort port) {
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900547 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
548 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
549
550 sBuilder.matchEthType(Ethernet.TYPE_IPV4)
551 .matchTunnelId(getVni(port.networkId()))
552 .matchIPSrc(IpPrefix.valueOf(floatingIP.fixedIpAddress(), 32));
553
Kyuhwi Choi92d9ea42016-06-13 17:28:00 +0900554 getGatewayNodeList().forEach(device -> {
555 DeviceId deviceId = device.id();
556 tBuilder.setIpSrc(floatingIP.floatingIpAddress())
sangho6032f342016-07-07 14:32:03 +0900557 .setEthSrc(Constants.GW_EXT_INT_MAC)
558 .setEthDst(Constants.PHY_ROUTER_MAC)
Kyuhwi Choi92d9ea42016-06-13 17:28:00 +0900559 .setOutput(getExternalPortNum(deviceId));
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900560
Kyuhwi Choi92d9ea42016-06-13 17:28:00 +0900561 ForwardingObjective fo = DefaultForwardingObjective.builder()
562 .withSelector(sBuilder.build())
563 .withTreatment(tBuilder.build())
564 .withFlag(ForwardingObjective.Flag.VERSATILE)
565 .withPriority(FLOATING_RULE_PRIORITY)
566 .fromApp(appId)
567 .add();
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900568
Kyuhwi Choi92d9ea42016-06-13 17:28:00 +0900569 flowObjectiveService.forward(deviceId, fo);
570 });
571 }
572
573 private PortNumber getExternalPortNum(DeviceId deviceId) {
574 return checkNotNull(gatewayService.getGatewayExternalPorts(deviceId).get(0), PORTNOTNULL);
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900575 }
576
577 /**
578 * Removes flow rules for floating ip configuration.
579 *
sangho6032f342016-07-07 14:32:03 +0900580 * @param floatingIp Corresponding floating ip information
581 * @param host host information for vm to remove
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900582 */
sangho6032f342016-07-07 14:32:03 +0900583 public void removeFloatingIpRules(OpenstackFloatingIP floatingIp, Host host) {
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900584 TrafficSelector.Builder sOutgoingBuilder = DefaultTrafficSelector.builder();
585 TrafficSelector.Builder sIncomingBuilder = DefaultTrafficSelector.builder();
586
sangho6032f342016-07-07 14:32:03 +0900587 // XXX FloatingIp.tenant_id() == host.vxlan_id ???
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900588 sOutgoingBuilder.matchEthType(Ethernet.TYPE_IPV4)
sangho6032f342016-07-07 14:32:03 +0900589 .matchTunnelId(Integer.parseInt(host.annotations().value(Constants.VXLAN_ID)))
590 .matchIPSrc(IpPrefix.valueOf(floatingIp.fixedIpAddress(), PREFIX_LENGTH));
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900591
592 sIncomingBuilder.matchEthType(Ethernet.TYPE_IPV4)
sangho6032f342016-07-07 14:32:03 +0900593 .matchIPDst(IpPrefix.valueOf(floatingIp.floatingIpAddress(), PREFIX_LENGTH));
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900594
Kyuhwi Choi92d9ea42016-06-13 17:28:00 +0900595 getGatewayNodeList().forEach(device -> {
596 removeRule(device.id(), sOutgoingBuilder, ForwardingObjective.Flag.VERSATILE, FLOATING_RULE_PRIORITY);
597 removeRule(device.id(), sIncomingBuilder, ForwardingObjective.Flag.VERSATILE, FLOATING_RULE_PRIORITY);
598 });
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900599 }
600
Kyuhwi Choi5e65e2c2016-04-01 11:48:15 +0900601 /**
602 * Populates L3 rules for east to west traffic.
603 *
Kyuhwi Choi92d9ea42016-06-13 17:28:00 +0900604 * @param openstackPort target VM
Kyuhwi Choi5e65e2c2016-04-01 11:48:15 +0900605 * @param targetList target openstackRouterInterfaces
606 */
Kyuhwi Choi92d9ea42016-06-13 17:28:00 +0900607 public void populateL3Rules(OpenstackPort openstackPort, List<OpenstackRouterInterface> targetList) {
608 Device device = getDevicefromOpenstackPort(openstackPort);
609 Port port = getPortFromOpenstackPort(device, openstackPort);
610 Ip4Address vmIp = openstackPort.fixedIps().values().iterator().next();
Kyuhwi Choi5e65e2c2016-04-01 11:48:15 +0900611
612 if (port == null) {
613 return;
614 }
615
616 targetList.forEach(routerInterface -> {
Kyuhwi Choi92d9ea42016-06-13 17:28:00 +0900617 long vni = getVni(openstackService.port(routerInterface.portId()).networkId());
Kyuhwi Choi5e65e2c2016-04-01 11:48:15 +0900618
619 if (vmIp == null) {
620 return;
621 }
622
Kyuhwi Choi92d9ea42016-06-13 17:28:00 +0900623 populateL3RulestoSameNode(vmIp, openstackPort, port, device, vni);
Kyuhwi Choi5e65e2c2016-04-01 11:48:15 +0900624
625 deviceService.getAvailableDevices().forEach(d -> {
sangho6032f342016-07-07 14:32:03 +0900626 if (!d.equals(device) && !d.equals(getGatewayNode())) {
627 populateL3RulestoDifferentNode(vmIp, vni, d.id(),
628 getHostIpfromOpenstackPort(openstackPort).getIp4Address());
Kyuhwi Choi5e65e2c2016-04-01 11:48:15 +0900629 }
630 });
631
632 });
633 }
634
635 private void populateL3RulestoDifferentNode(Ip4Address vmIp, long vni, DeviceId deviceId, Ip4Address hostIp) {
636 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
637 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
638
639 sBuilder.matchEthType(Ethernet.TYPE_IPV4)
640 .matchTunnelId(vni)
641 .matchIPDst(vmIp.toIpPrefix());
642 tBuilder.extension(buildNiciraExtenstion(deviceId, hostIp), deviceId)
643 .setOutput(getTunnelPort(deviceId));
644
645 ForwardingObjective fo = DefaultForwardingObjective.builder()
646 .withSelector(sBuilder.build())
647 .withTreatment(tBuilder.build())
648 .withPriority(ROUTING_RULE_PRIORITY)
649 .withFlag(ForwardingObjective.Flag.SPECIFIC)
650 .fromApp(appId)
651 .add();
652
653 flowObjectiveService.forward(deviceId, fo);
654 }
655
656 private void populateL3RulestoSameNode(Ip4Address vmIp, OpenstackPort p, Port port, Device device, long vni) {
657 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
658 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
659
660 sBuilder.matchEthType(Ethernet.TYPE_IPV4)
661 .matchIPDst(vmIp.toIpPrefix())
662 .matchTunnelId(vni);
663
664 tBuilder.setEthDst(p.macAddress())
665 .setOutput(port.number());
666
667 ForwardingObjective fo = DefaultForwardingObjective.builder()
668 .withSelector(sBuilder.build())
669 .withTreatment(tBuilder.build())
670 .withPriority(ROUTING_RULE_PRIORITY)
671 .withFlag(ForwardingObjective.Flag.SPECIFIC)
672 .fromApp(appId)
673 .add();
674
675 flowObjectiveService.forward(device.id(), fo);
676 }
677
678 private Port getPortFromOpenstackPort(Device device, OpenstackPort p) {
679 String openstackPortName = PORTNAME_PREFIX_VM + p.id().substring(0, 11);
680 return deviceService.getPorts(device.id())
681 .stream()
682 .filter(pt -> pt.annotations().value(PORTNAME).equals(openstackPortName))
683 .findAny()
684 .orElse(null);
685 }
686
687 /**
688 * Removes L3 rules for routerInterface events.
689 *
690 * @param vmIp Corresponding Vm ip
691 * @param routerInterfaces Corresponding routerInterfaces
692 */
693 public void removeL3Rules(Ip4Address vmIp, List<OpenstackRouterInterface> routerInterfaces) {
694 if (vmIp == null) {
695 return;
696 }
697
698 OpenstackRoutingService routingService = getService(OpenstackRoutingService.class);
699
700 deviceService.getAvailableDevices().forEach(d -> {
sangho6032f342016-07-07 14:32:03 +0900701 if (isTypeOf(d.id(), OpenstackNodeService.NodeType.COMPUTE)) {
Kyuhwi Choi5e65e2c2016-04-01 11:48:15 +0900702 routerInterfaces.forEach(routerInterface -> {
703 String networkId = routingService.networkIdForRouterInterface(routerInterface.portId());
704 long vni = getVni(networkId);
705
706 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
707
708 sBuilder.matchEthType(Ethernet.TYPE_IPV4)
709 .matchIPDst(vmIp.toIpPrefix())
710 .matchTunnelId(vni);
711
712 removeRule(d.id(), sBuilder, ForwardingObjective.Flag.SPECIFIC, ROUTING_RULE_PRIORITY);
713 });
714 }
715 });
716 }
sangho0c2a3da2016-02-16 13:39:07 +0900717}