blob: 57444d03bbafb94c4a81bda8d3152cb69e628759 [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;
32import org.onosproject.net.Port;
33import org.onosproject.net.PortNumber;
34import org.onosproject.net.behaviour.ExtensionTreatmentResolver;
35import org.onosproject.net.device.DeviceService;
36import org.onosproject.net.driver.DefaultDriverData;
37import org.onosproject.net.driver.DefaultDriverHandler;
38import org.onosproject.net.driver.Driver;
39import org.onosproject.net.driver.DriverHandler;
40import org.onosproject.net.driver.DriverService;
41import org.onosproject.net.flow.DefaultTrafficSelector;
42import org.onosproject.net.flow.DefaultTrafficTreatment;
43import org.onosproject.net.flow.TrafficSelector;
44import org.onosproject.net.flow.TrafficTreatment;
45import org.onosproject.net.flow.instructions.ExtensionPropertyException;
46import org.onosproject.net.flow.instructions.ExtensionTreatment;
47import org.onosproject.net.flow.instructions.ExtensionTreatmentType;
48import org.onosproject.net.flowobjective.DefaultForwardingObjective;
49import org.onosproject.net.flowobjective.FlowObjectiveService;
50import org.onosproject.net.flowobjective.ForwardingObjective;
51import org.onosproject.net.packet.InboundPacket;
sangho93447f12016-02-24 00:33:22 +090052import org.onosproject.openstackinterface.OpenstackInterfaceService;
53import org.onosproject.openstackinterface.OpenstackPort;
sangho93447f12016-02-24 00:33:22 +090054import org.onosproject.openstackinterface.OpenstackRouterInterface;
55import org.onosproject.openstackinterface.OpenstackSubnet;
Kyuhwi Choiee9e3712016-02-22 22:49:36 +090056import org.onosproject.openstackinterface.OpenstackFloatingIP;
sangho48907542016-03-28 16:07:07 +090057import org.onosproject.openstacknetworking.OpenstackNetworkingConfig;
Kyuhwi Choiee9e3712016-02-22 22:49:36 +090058import org.onosproject.openstacknetworking.OpenstackPortInfo;
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;
sangho0c2a3da2016-02-16 13:39:07 +090061import org.slf4j.Logger;
62import org.slf4j.LoggerFactory;
63
Kyuhwi Choi5e65e2c2016-04-01 11:48:15 +090064import java.util.List;
sangho0c2a3da2016-02-16 13:39:07 +090065import java.util.stream.StreamSupport;
66
67import static com.google.common.base.Preconditions.checkNotNull;
Kyuhwi Choi5e65e2c2016-04-01 11:48:15 +090068import static org.onlab.osgi.DefaultServiceDirectory.getService;
sangho0c2a3da2016-02-16 13:39:07 +090069
70/**
71 * Populates Routing Flow Rules.
72 */
73public class OpenstackRoutingRulePopulator {
74
Kyuhwi Choie2b37e32016-02-05 14:04:14 +090075 private final Logger log = LoggerFactory.getLogger(getClass());
sangho0c2a3da2016-02-16 13:39:07 +090076
Kyuhwi Choie2b37e32016-02-05 14:04:14 +090077 private final ApplicationId appId;
78 private final FlowObjectiveService flowObjectiveService;
sangho93447f12016-02-24 00:33:22 +090079 private final OpenstackInterfaceService openstackService;
Kyuhwi Choie2b37e32016-02-05 14:04:14 +090080 private final DeviceService deviceService;
81 private final DriverService driverService;
sangho48907542016-03-28 16:07:07 +090082 private final OpenstackNetworkingConfig config;
Kyuhwi Choi92d9ea42016-06-13 17:28:00 +090083 private final ScalableGatewayService gatewayService;
sangho0c2a3da2016-02-16 13:39:07 +090084
Kyuhwi Choie2b37e32016-02-05 14:04:14 +090085 private static final String PORTNAME_PREFIX_TUNNEL = "vxlan";
86 private static final String PORTNAME = "portName";
Kyuhwi Choiee9e3712016-02-22 22:49:36 +090087 private static final String PORTNAME_PREFIX_VM = "tap";
Kyuhwi Choie2b37e32016-02-05 14:04:14 +090088
89 private static final String PORTNOTNULL = "Port can not be null";
Kyuhwi Choiee9e3712016-02-22 22:49:36 +090090 private static final String DEVICENOTNULL = "Device can not be null";
Kyuhwi Choi92d9ea42016-06-13 17:28:00 +090091 private static final String EXTPORTNOTNULL = "External port can not be null";
Kyuhwi Choie2b37e32016-02-05 14:04:14 +090092 private static final String TUNNEL_DESTINATION = "tunnelDst";
sangho0c2a3da2016-02-16 13:39:07 +090093 private static final int ROUTING_RULE_PRIORITY = 25000;
Kyuhwi Choiee9e3712016-02-22 22:49:36 +090094 private static final int FLOATING_RULE_PRIORITY = 42000;
95 private static final int PNAT_RULE_PRIORITY = 26000;
sangho0c2a3da2016-02-16 13:39:07 +090096 private static final int PNAT_TIMEOUT = 120;
Daniel Park23193902016-03-24 18:17:19 +090097 private static final int PREFIX_LENGTH = 32;
sangho0c2a3da2016-02-16 13:39:07 +090098 private static final MacAddress GATEWAYMAC = MacAddress.valueOf("1f:1f:1f:1f:1f:1f");
99
100 private InboundPacket inboundPacket;
101 private OpenstackPort openstackPort;
102 private int portNum;
103 private MacAddress externalInterface;
104 private MacAddress externalRouter;
sangho0c2a3da2016-02-16 13:39:07 +0900105
Kyuhwi Choie2b37e32016-02-05 14:04:14 +0900106 /**
107 * The constructor of openstackRoutingRulePopulator.
108 *
109 * @param appId Caller`s appId
Kyuhwi Choi5e65e2c2016-04-01 11:48:15 +0900110 * @param openstackService Opestack REST request handler
Kyuhwi Choie2b37e32016-02-05 14:04:14 +0900111 * @param flowObjectiveService FlowObjectiveService
112 * @param deviceService DeviceService
113 * @param driverService DriverService
Kyuhwi Choi5e65e2c2016-04-01 11:48:15 +0900114 * @param config Configuration for openstack environment
Kyuhwi Choi92d9ea42016-06-13 17:28:00 +0900115 * @param gatewayService scalable gateway service
Kyuhwi Choie2b37e32016-02-05 14:04:14 +0900116 */
sangho93447f12016-02-24 00:33:22 +0900117 public OpenstackRoutingRulePopulator(ApplicationId appId, OpenstackInterfaceService openstackService,
Daniel Park81a61a12016-02-26 08:24:44 +0900118 FlowObjectiveService flowObjectiveService, DeviceService deviceService,
Kyuhwi Choi92d9ea42016-06-13 17:28:00 +0900119 DriverService driverService, OpenstackNetworkingConfig config,
120 ScalableGatewayService gatewayService) {
sangho0c2a3da2016-02-16 13:39:07 +0900121 this.appId = appId;
122 this.flowObjectiveService = flowObjectiveService;
Daniel Park81a61a12016-02-26 08:24:44 +0900123 this.openstackService = checkNotNull(openstackService);
sangho0c2a3da2016-02-16 13:39:07 +0900124 this.deviceService = deviceService;
125 this.driverService = driverService;
Daniel Park81a61a12016-02-26 08:24:44 +0900126 this.config = config;
Kyuhwi Choi92d9ea42016-06-13 17:28:00 +0900127 this.gatewayService = gatewayService;
sangho0c2a3da2016-02-16 13:39:07 +0900128 }
129
Kyuhwi Choie2b37e32016-02-05 14:04:14 +0900130 /**
131 * Populates flow rules for Pnat configurations.
Daniel Park81a61a12016-02-26 08:24:44 +0900132 *
133 * @param inboundPacket Packet-in event packet
Kyuhwi Choie2b37e32016-02-05 14:04:14 +0900134 * @param openstackPort Target VM information
135 * @param portNum Pnat port number
Hyunsun Moon0dba61f2016-03-03 14:05:21 -0800136 * @param externalIp external ip address
Kyuhwi Choie2b37e32016-02-05 14:04:14 +0900137 * @param externalInterfaceMacAddress Gateway external interface macaddress
138 * @param externalRouterMacAddress Outer(physical) router`s macaddress
139 */
sangho0c2a3da2016-02-16 13:39:07 +0900140 public void populatePnatFlowRules(InboundPacket inboundPacket, OpenstackPort openstackPort, int portNum,
Kyuhwi Choie2b37e32016-02-05 14:04:14 +0900141 Ip4Address externalIp, MacAddress externalInterfaceMacAddress,
142 MacAddress externalRouterMacAddress) {
sangho0c2a3da2016-02-16 13:39:07 +0900143 this.inboundPacket = inboundPacket;
144 this.openstackPort = openstackPort;
145 this.portNum = portNum;
146 this.externalInterface = externalInterfaceMacAddress;
147 this.externalRouter = externalRouterMacAddress;
148
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900149 long vni = getVni(openstackPort.networkId());
sangho0c2a3da2016-02-16 13:39:07 +0900150
Kyuhwi Choie2b37e32016-02-05 14:04:14 +0900151 populatePnatIncomingFlowRules(vni, externalIp);
152 populatePnatOutgoingFlowRules(vni, externalIp);
sangho0c2a3da2016-02-16 13:39:07 +0900153 }
154
Kyuhwi Choie2b37e32016-02-05 14:04:14 +0900155 private void populatePnatOutgoingFlowRules(long vni, Ip4Address externalIp) {
sangho0c2a3da2016-02-16 13:39:07 +0900156 IPv4 iPacket = (IPv4) inboundPacket.parsed().getPayload();
157
158 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
159 sBuilder.matchEthType(Ethernet.TYPE_IPV4)
160 .matchIPProtocol(iPacket.getProtocol())
161 .matchTunnelId(vni)
162 .matchIPSrc(IpPrefix.valueOf(iPacket.getSourceAddress(), 32))
163 .matchIPDst(IpPrefix.valueOf(iPacket.getDestinationAddress(), 32));
164
165 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
sangho0c2a3da2016-02-16 13:39:07 +0900166
167 switch (iPacket.getProtocol()) {
168 case IPv4.PROTOCOL_TCP:
169 TCP tcpPacket = (TCP) iPacket.getPayload();
170 sBuilder.matchTcpSrc(TpPort.tpPort(tcpPacket.getSourcePort()))
171 .matchTcpDst(TpPort.tpPort(tcpPacket.getDestinationPort()));
Kyuhwi Choie2b37e32016-02-05 14:04:14 +0900172 tBuilder.setTcpSrc(TpPort.tpPort(portNum));
sangho0c2a3da2016-02-16 13:39:07 +0900173 break;
174 case IPv4.PROTOCOL_UDP:
175 UDP udpPacket = (UDP) iPacket.getPayload();
Kyuhwi Choie2b37e32016-02-05 14:04:14 +0900176 sBuilder.matchUdpSrc(TpPort.tpPort(udpPacket.getSourcePort()))
sangho0c2a3da2016-02-16 13:39:07 +0900177 .matchUdpDst(TpPort.tpPort(udpPacket.getDestinationPort()));
Kyuhwi Choie2b37e32016-02-05 14:04:14 +0900178 tBuilder.setUdpSrc(TpPort.tpPort(portNum));
sangho0c2a3da2016-02-16 13:39:07 +0900179 break;
180 default:
Daniel Park81a61a12016-02-26 08:24:44 +0900181 log.debug("Unsupported IPv4 protocol {}");
sangho0c2a3da2016-02-16 13:39:07 +0900182 break;
183 }
184
Kyuhwi Choi92d9ea42016-06-13 17:28:00 +0900185 tBuilder.setIpSrc(externalIp);
186 gatewayService.getGatewayNodes().forEach(node -> {
187 tBuilder.setOutput(gatewayService.getGatewayExternalPorts(node.getGatewayDeviceId()).get(0));
188 ForwardingObjective fo = DefaultForwardingObjective.builder()
189 .withSelector(sBuilder.build())
190 .withTreatment(tBuilder.build())
191 .withFlag(ForwardingObjective.Flag.VERSATILE)
192 .withPriority(PNAT_RULE_PRIORITY)
193 .makeTemporary(PNAT_TIMEOUT)
194 .fromApp(appId)
195 .add();
sangho0c2a3da2016-02-16 13:39:07 +0900196
Kyuhwi Choi92d9ea42016-06-13 17:28:00 +0900197 flowObjectiveService.forward(node.getGatewayDeviceId(), fo);
198 });
Kyuhwi Choi5e65e2c2016-04-01 11:48:15 +0900199
sangho0c2a3da2016-02-16 13:39:07 +0900200 }
201
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900202 private Port getPortOfExternalInterface() {
203 return deviceService.getPorts(getGatewayNode().id()).stream()
Daniel Park81a61a12016-02-26 08:24:44 +0900204 .filter(p -> p.annotations().value(PORTNAME).equals(config.gatewayExternalInterfaceName()))
sangho0c2a3da2016-02-16 13:39:07 +0900205 .findAny().orElse(null);
206 }
207
208
Kyuhwi Choie2b37e32016-02-05 14:04:14 +0900209 private void populatePnatIncomingFlowRules(long vni, Ip4Address externalIp) {
sangho0c2a3da2016-02-16 13:39:07 +0900210 IPv4 iPacket = (IPv4) inboundPacket.parsed().getPayload();
sangho0c2a3da2016-02-16 13:39:07 +0900211
212 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
213 sBuilder.matchEthType(Ethernet.TYPE_IPV4)
214 .matchIPProtocol(iPacket.getProtocol())
Kyuhwi Choie2b37e32016-02-05 14:04:14 +0900215 .matchIPDst(IpPrefix.valueOf(externalIp, 32))
sangho0c2a3da2016-02-16 13:39:07 +0900216 .matchIPSrc(IpPrefix.valueOf(iPacket.getDestinationAddress(), 32));
217
218 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
219 tBuilder.setTunnelId(vni)
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900220 .setEthDst(inboundPacket.parsed().getSourceMAC())
sangho0c2a3da2016-02-16 13:39:07 +0900221 .setIpDst(IpAddress.valueOf(iPacket.getSourceAddress()));
222
223 switch (iPacket.getProtocol()) {
224 case IPv4.PROTOCOL_TCP:
225 TCP tcpPacket = (TCP) iPacket.getPayload();
226 sBuilder.matchTcpSrc(TpPort.tpPort(tcpPacket.getDestinationPort()))
227 .matchTcpDst(TpPort.tpPort(portNum));
228 tBuilder.setTcpDst(TpPort.tpPort(tcpPacket.getSourcePort()));
229 break;
230 case IPv4.PROTOCOL_UDP:
231 UDP udpPacket = (UDP) iPacket.getPayload();
232 sBuilder.matchUdpSrc(TpPort.tpPort(udpPacket.getDestinationPort()))
233 .matchUdpDst(TpPort.tpPort(portNum));
234 tBuilder.setUdpDst(TpPort.tpPort(udpPacket.getSourcePort()));
235 break;
236 default:
237 break;
238 }
239
Kyuhwi Choi92d9ea42016-06-13 17:28:00 +0900240 getGatewayNodeList().forEach(node -> {
241 DeviceId deviceId = node.id();
242 tBuilder.extension(buildNiciraExtenstion(deviceId, getHostIpfromOpenstackPort(openstackPort)), deviceId)
243 .setOutput(getTunnelPort(deviceId));
sangho0c2a3da2016-02-16 13:39:07 +0900244
Kyuhwi Choi92d9ea42016-06-13 17:28:00 +0900245 ForwardingObjective fo = DefaultForwardingObjective.builder()
246 .withSelector(sBuilder.build())
247 .withTreatment(tBuilder.build())
248 .withFlag(ForwardingObjective.Flag.VERSATILE)
249 .withPriority(PNAT_RULE_PRIORITY)
250 .makeTemporary(PNAT_TIMEOUT)
251 .fromApp(appId)
252 .add();
sangho0c2a3da2016-02-16 13:39:07 +0900253
Kyuhwi Choi92d9ea42016-06-13 17:28:00 +0900254 flowObjectiveService.forward(deviceId, fo);
255 });
256 }
257
258 private List<Device> getGatewayNodeList() {
259 List<Device> devices = Lists.newArrayList();
260 gatewayService.getGatewayDeviceIds().forEach(deviceId ->
261 devices.add(checkNotNull(deviceService.getDevice(deviceId))));
262 return devices;
sangho0c2a3da2016-02-16 13:39:07 +0900263 }
264
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900265 private Ip4Address getHostIpfromOpenstackPort(OpenstackPort openstackPort) {
266 Device device = getDevicefromOpenstackPort(openstackPort);
Daniel Park23193902016-03-24 18:17:19 +0900267 return config.nodes().get(device.id());
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900268 }
Daniel Park81a61a12016-02-26 08:24:44 +0900269
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900270 private Device getDevicefromOpenstackPort(OpenstackPort openstackPort) {
271 String openstackPortName = PORTNAME_PREFIX_VM + openstackPort.id().substring(0, 11);
272 Device device = StreamSupport.stream(deviceService.getDevices().spliterator(), false)
Kyuhwi Choi92d9ea42016-06-13 17:28:00 +0900273 .filter(d -> findPortinDevice(d.id(), openstackPortName))
Kyuhwi Choi5e65e2c2016-04-01 11:48:15 +0900274 .iterator()
275 .next();
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900276 checkNotNull(device, DEVICENOTNULL);
277 return device;
278 }
279
Kyuhwi Choi92d9ea42016-06-13 17:28:00 +0900280 private boolean findPortinDevice(DeviceId deviceId, String openstackPortName) {
281 Port port = deviceService.getPorts(deviceId)
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900282 .stream()
283 .filter(p -> p.isEnabled() && p.annotations().value(PORTNAME).equals(openstackPortName))
284 .findAny()
285 .orElse(null);
Daniel Park23193902016-03-24 18:17:19 +0900286 return port != null;
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900287 }
288
289 /**
Kyuhwi Choi5e65e2c2016-04-01 11:48:15 +0900290 * Builds Nicira extension for tagging remoteIp of vxlan.
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900291 *
Kyuhwi Choi92d9ea42016-06-13 17:28:00 +0900292 * @param deviceId Device Id of vxlan source device
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900293 * @param hostIp Remote Ip of vxlan destination device
294 * @return NiciraExtension Treatment
295 */
Kyuhwi Choi92d9ea42016-06-13 17:28:00 +0900296 public ExtensionTreatment buildNiciraExtenstion(DeviceId deviceId, Ip4Address hostIp) {
297 Driver driver = driverService.getDriver(deviceId);
298 DriverHandler driverHandler = new DefaultDriverHandler(new DefaultDriverData(driver, deviceId));
sangho0c2a3da2016-02-16 13:39:07 +0900299 ExtensionTreatmentResolver resolver = driverHandler.behaviour(ExtensionTreatmentResolver.class);
300
301 ExtensionTreatment extensionInstruction =
302 resolver.getExtensionInstruction(
303 ExtensionTreatmentType.ExtensionTreatmentTypes.NICIRA_SET_TUNNEL_DST.type());
304
305 try {
Kyuhwi Choie2b37e32016-02-05 14:04:14 +0900306 extensionInstruction.setPropertyValue(TUNNEL_DESTINATION, hostIp);
sangho0c2a3da2016-02-16 13:39:07 +0900307 } catch (ExtensionPropertyException e) {
308 log.error("Error setting Nicira extension setting {}", e);
309 }
310
311 return extensionInstruction;
312 }
313
Daniel Park81a61a12016-02-26 08:24:44 +0900314 /**
315 * Returns port number of vxlan tunnel.
316 *
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900317 * @param deviceId Target Device Id
318 * @return PortNumber
Daniel Park81a61a12016-02-26 08:24:44 +0900319 */
320 public PortNumber getTunnelPort(DeviceId deviceId) {
sangho0c2a3da2016-02-16 13:39:07 +0900321 Port port = deviceService.getPorts(deviceId).stream()
Kyuhwi Choie2b37e32016-02-05 14:04:14 +0900322 .filter(p -> p.annotations().value(PORTNAME).equals(PORTNAME_PREFIX_TUNNEL))
sangho0c2a3da2016-02-16 13:39:07 +0900323 .findAny().orElse(null);
324
325 if (port == null) {
326 log.error("No TunnelPort was created.");
327 return null;
328 }
329 return port.number();
330
331 }
332
Kyuhwi Choie2b37e32016-02-05 14:04:14 +0900333 /**
334 * Populates flow rules from openstackComputeNode to GatewayNode.
335 *
336 * @param vni Target network
Kyuhwi Choie2b37e32016-02-05 14:04:14 +0900337 */
Daniel Park23193902016-03-24 18:17:19 +0900338 public void populateExternalRules(long vni) {
sangho0c2a3da2016-02-16 13:39:07 +0900339
340 // 1. computeNode to gateway
341 populateComputeNodeRules(vni);
342 // 2. gatewayNode to controller
343 populateRuleGatewaytoController(vni);
344 }
345
346 private void populateRuleGatewaytoController(long vni) {
sangho0c2a3da2016-02-16 13:39:07 +0900347 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
348 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
349
350 sBuilder.matchEthType(Ethernet.TYPE_IPV4)
351 .matchTunnelId(vni)
352 .matchEthDst(GATEWAYMAC);
353 tBuilder.setOutput(PortNumber.CONTROLLER);
354
355 ForwardingObjective fo = DefaultForwardingObjective.builder()
356 .withSelector(sBuilder.build())
357 .withTreatment(tBuilder.build())
358 .withFlag(ForwardingObjective.Flag.VERSATILE)
359 .withPriority(ROUTING_RULE_PRIORITY)
360 .fromApp(appId)
361 .add();
362
Kyuhwi Choi92d9ea42016-06-13 17:28:00 +0900363 getGatewayNodeList().forEach(device -> flowObjectiveService.forward(device.id(), fo));
sangho0c2a3da2016-02-16 13:39:07 +0900364 }
365
366 private void populateComputeNodeRules(long vni) {
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900367 StreamSupport.stream(deviceService.getDevices().spliterator(), false)
sangho0c2a3da2016-02-16 13:39:07 +0900368 .filter(d -> !checkGatewayNode(d.id()))
Kyuhwi Choi92d9ea42016-06-13 17:28:00 +0900369 .forEach(d -> populateRuleToGatewayBySgw(d.id(),
370 gatewayService.getGroupIdForGatewayLoadBalance(d.id()), vni));
sangho0c2a3da2016-02-16 13:39:07 +0900371 }
372
Kyuhwi Choi92d9ea42016-06-13 17:28:00 +0900373 private void populateRuleToGatewayBySgw(DeviceId deviceId, GroupId groupId, long vni) {
sangho0c2a3da2016-02-16 13:39:07 +0900374 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
375 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
376
377 sBuilder.matchEthType(Ethernet.TYPE_IPV4)
378 .matchTunnelId(vni)
379 .matchEthDst(GATEWAYMAC);
Kyuhwi Choi92d9ea42016-06-13 17:28:00 +0900380 tBuilder.group(groupId);
sangho0c2a3da2016-02-16 13:39:07 +0900381
382 ForwardingObjective fo = DefaultForwardingObjective.builder()
383 .withSelector(sBuilder.build())
384 .withTreatment(tBuilder.build())
385 .withFlag(ForwardingObjective.Flag.SPECIFIC)
386 .withPriority(ROUTING_RULE_PRIORITY)
387 .fromApp(appId)
388 .add();
389
Kyuhwi Choi92d9ea42016-06-13 17:28:00 +0900390 flowObjectiveService.forward(deviceId, fo);
391 }
392
393 private void populateRuleToGateway(DeviceId deviceId, Device gatewayDevice, long vni) {
394 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
395 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
396
397 sBuilder.matchEthType(Ethernet.TYPE_IPV4)
398 .matchTunnelId(vni)
399 .matchEthDst(GATEWAYMAC);
400 tBuilder.extension(buildNiciraExtenstion(deviceId, config.nodes().get(gatewayDevice.id())), deviceId)
401 .setOutput(getTunnelPort(deviceId));
402
403 ForwardingObjective fo = DefaultForwardingObjective.builder()
404 .withSelector(sBuilder.build())
405 .withTreatment(tBuilder.build())
406 .withFlag(ForwardingObjective.Flag.SPECIFIC)
407 .withPriority(ROUTING_RULE_PRIORITY)
408 .fromApp(appId)
409 .add();
410
411 flowObjectiveService.forward(deviceId, fo);
sangho0c2a3da2016-02-16 13:39:07 +0900412 }
413
sangho0c2a3da2016-02-16 13:39:07 +0900414 private Device getGatewayNode() {
Daniel Park81a61a12016-02-26 08:24:44 +0900415 return checkNotNull(deviceService.getDevice(DeviceId.deviceId(config.gatewayBridgeId())));
sangho0c2a3da2016-02-16 13:39:07 +0900416 }
417
418 private boolean checkGatewayNode(DeviceId deviceId) {
Kyuhwi Choi92d9ea42016-06-13 17:28:00 +0900419 return gatewayService.getGatewayDeviceIds().stream().anyMatch(dId -> dId.equals(deviceId));
sangho0c2a3da2016-02-16 13:39:07 +0900420 }
421
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900422 private long getVni(String netId) {
423 return Long.parseLong(openstackService.network(netId).segmentId());
Kyuhwi Choie2b37e32016-02-05 14:04:14 +0900424 }
425
426 /**
427 * Remove flow rules for external connection.
428 *
429 * @param routerInterface Corresponding routerInterface
430 */
sangho0c2a3da2016-02-16 13:39:07 +0900431 public void removeExternalRules(OpenstackRouterInterface routerInterface) {
Kyuhwi Choie2b37e32016-02-05 14:04:14 +0900432 OpenstackSubnet openstackSubnet = openstackService.subnet(routerInterface.subnetId());
sangho0c2a3da2016-02-16 13:39:07 +0900433 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
434 sBuilder.matchEthType(Ethernet.TYPE_IPV4)
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900435 .matchTunnelId(getVni(openstackSubnet.networkId()))
sangho0c2a3da2016-02-16 13:39:07 +0900436 .matchEthDst(GATEWAYMAC);
437
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900438 StreamSupport.stream(deviceService.getDevices().spliterator(), false)
sangho0c2a3da2016-02-16 13:39:07 +0900439 .forEach(d -> {
Daniel Park23193902016-03-24 18:17:19 +0900440 ForwardingObjective.Flag flag = checkGatewayNode(d.id()) ?
Kyuhwi Choi5e65e2c2016-04-01 11:48:15 +0900441 ForwardingObjective.Flag.VERSATILE :
442 ForwardingObjective.Flag.SPECIFIC;
Daniel Park23193902016-03-24 18:17:19 +0900443 removeRule(d.id(), sBuilder, flag, ROUTING_RULE_PRIORITY);
sangho0c2a3da2016-02-16 13:39:07 +0900444 });
445
446 }
447
Kyuhwi Choi92d9ea42016-06-13 17:28:00 +0900448 private void removeRule(DeviceId deviceId, TrafficSelector.Builder sBuilder,
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900449 ForwardingObjective.Flag flag, int priority) {
sangho0c2a3da2016-02-16 13:39:07 +0900450 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
451
452 ForwardingObjective fo = DefaultForwardingObjective.builder()
453 .withSelector(sBuilder.build())
454 .withTreatment(tBuilder.build())
455 .withFlag(flag)
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900456 .withPriority(priority)
sangho0c2a3da2016-02-16 13:39:07 +0900457 .fromApp(appId)
458 .remove();
459
Kyuhwi Choi92d9ea42016-06-13 17:28:00 +0900460 flowObjectiveService.forward(deviceId, fo);
sangho0c2a3da2016-02-16 13:39:07 +0900461 }
462
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900463 /**
464 * Populates flow rules for floatingIp configuration.
465 *
466 * @param floatingIP Corresponding floating ip information
467 */
468 public void populateFloatingIpRules(OpenstackFloatingIP floatingIP) {
469 OpenstackPort port = openstackService.port(floatingIP.portId());
470 //1. incoming rules
471 populateFloatingIpIncomingRules(floatingIP, port);
472 //2. outgoing rules
473 populateFloatingIpOutgoingRules(floatingIP, port);
474 }
475
476 private void populateFloatingIpIncomingRules(OpenstackFloatingIP floatingIP, OpenstackPort port) {
477 DeviceId portDeviceId = getDevicefromOpenstackPort(port).id();
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900478
479 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
480 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
481
482 sBuilder.matchEthType(Ethernet.TYPE_IPV4)
Daniel Park23193902016-03-24 18:17:19 +0900483 .matchIPDst(IpPrefix.valueOf(floatingIP.floatingIpAddress(), PREFIX_LENGTH));
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900484
Kyuhwi Choi92d9ea42016-06-13 17:28:00 +0900485 getGatewayNodeList().forEach(device -> {
486 DeviceId deviceId = device.id();
487 tBuilder.setEthSrc(GATEWAYMAC)
488 .setEthDst(port.macAddress())
489 .setIpDst(floatingIP.fixedIpAddress())
490 .setTunnelId(getVni(port.networkId()))
491 .extension(buildNiciraExtenstion(deviceId, config.nodes().get(portDeviceId)), deviceId)
492 .setOutput(getTunnelPort(deviceId));
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900493
Kyuhwi Choi92d9ea42016-06-13 17:28:00 +0900494 ForwardingObjective fo = DefaultForwardingObjective.builder()
495 .withSelector(sBuilder.build())
496 .withTreatment(tBuilder.build())
497 .withFlag(ForwardingObjective.Flag.VERSATILE)
498 .withPriority(FLOATING_RULE_PRIORITY)
499 .fromApp(appId)
500 .add();
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900501
Kyuhwi Choi92d9ea42016-06-13 17:28:00 +0900502 flowObjectiveService.forward(deviceId, fo);
503 });
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900504 }
505
506 private void populateFloatingIpOutgoingRules(OpenstackFloatingIP floatingIP, OpenstackPort port) {
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900507 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
508 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
509
510 sBuilder.matchEthType(Ethernet.TYPE_IPV4)
511 .matchTunnelId(getVni(port.networkId()))
512 .matchIPSrc(IpPrefix.valueOf(floatingIP.fixedIpAddress(), 32));
513
Kyuhwi Choi92d9ea42016-06-13 17:28:00 +0900514 getGatewayNodeList().forEach(device -> {
515 DeviceId deviceId = device.id();
516 tBuilder.setIpSrc(floatingIP.floatingIpAddress())
517 .setOutput(getExternalPortNum(deviceId));
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900518
Kyuhwi Choi92d9ea42016-06-13 17:28:00 +0900519 ForwardingObjective fo = DefaultForwardingObjective.builder()
520 .withSelector(sBuilder.build())
521 .withTreatment(tBuilder.build())
522 .withFlag(ForwardingObjective.Flag.VERSATILE)
523 .withPriority(FLOATING_RULE_PRIORITY)
524 .fromApp(appId)
525 .add();
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900526
Kyuhwi Choi92d9ea42016-06-13 17:28:00 +0900527 flowObjectiveService.forward(deviceId, fo);
528 });
529 }
530
531 private PortNumber getExternalPortNum(DeviceId deviceId) {
532 return checkNotNull(gatewayService.getGatewayExternalPorts(deviceId).get(0), PORTNOTNULL);
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900533 }
534
535 /**
536 * Removes flow rules for floating ip configuration.
537 *
538 * @param floatingIP Corresponding floating ip information
Ray Milkeyd4334db2016-04-05 17:39:44 -0700539 * @param portInfo stored information about deleted vm
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900540 */
541 public void removeFloatingIpRules(OpenstackFloatingIP floatingIP, OpenstackPortInfo portInfo) {
542 TrafficSelector.Builder sOutgoingBuilder = DefaultTrafficSelector.builder();
543 TrafficSelector.Builder sIncomingBuilder = DefaultTrafficSelector.builder();
544
545 sOutgoingBuilder.matchEthType(Ethernet.TYPE_IPV4)
546 .matchTunnelId(portInfo.vni())
Daniel Park23193902016-03-24 18:17:19 +0900547 .matchIPSrc(IpPrefix.valueOf(portInfo.ip(), PREFIX_LENGTH));
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900548
549 sIncomingBuilder.matchEthType(Ethernet.TYPE_IPV4)
Daniel Park23193902016-03-24 18:17:19 +0900550 .matchIPDst(IpPrefix.valueOf(floatingIP.floatingIpAddress(), PREFIX_LENGTH));
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900551
Kyuhwi Choi92d9ea42016-06-13 17:28:00 +0900552 getGatewayNodeList().forEach(device -> {
553 removeRule(device.id(), sOutgoingBuilder, ForwardingObjective.Flag.VERSATILE, FLOATING_RULE_PRIORITY);
554 removeRule(device.id(), sIncomingBuilder, ForwardingObjective.Flag.VERSATILE, FLOATING_RULE_PRIORITY);
555 });
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900556 }
557
Kyuhwi Choi5e65e2c2016-04-01 11:48:15 +0900558 /**
559 * Populates L3 rules for east to west traffic.
560 *
Kyuhwi Choi92d9ea42016-06-13 17:28:00 +0900561 * @param openstackPort target VM
Kyuhwi Choi5e65e2c2016-04-01 11:48:15 +0900562 * @param targetList target openstackRouterInterfaces
563 */
Kyuhwi Choi92d9ea42016-06-13 17:28:00 +0900564 public void populateL3Rules(OpenstackPort openstackPort, List<OpenstackRouterInterface> targetList) {
565 Device device = getDevicefromOpenstackPort(openstackPort);
566 Port port = getPortFromOpenstackPort(device, openstackPort);
567 Ip4Address vmIp = openstackPort.fixedIps().values().iterator().next();
Kyuhwi Choi5e65e2c2016-04-01 11:48:15 +0900568
569 if (port == null) {
570 return;
571 }
572
573 targetList.forEach(routerInterface -> {
Kyuhwi Choi92d9ea42016-06-13 17:28:00 +0900574 long vni = getVni(openstackService.port(routerInterface.portId()).networkId());
Kyuhwi Choi5e65e2c2016-04-01 11:48:15 +0900575
576 if (vmIp == null) {
577 return;
578 }
579
Kyuhwi Choi92d9ea42016-06-13 17:28:00 +0900580 populateL3RulestoSameNode(vmIp, openstackPort, port, device, vni);
Kyuhwi Choi5e65e2c2016-04-01 11:48:15 +0900581
582 deviceService.getAvailableDevices().forEach(d -> {
Kyuhwi Choi92d9ea42016-06-13 17:28:00 +0900583 if (!d.equals(device) && !checkGatewayNode(d.id())) {
584 populateL3RulestoDifferentNode(vmIp, vni, d.id(), getHostIpfromOpenstackPort(openstackPort));
Kyuhwi Choi5e65e2c2016-04-01 11:48:15 +0900585 }
586 });
587
588 });
589 }
590
591 private void populateL3RulestoDifferentNode(Ip4Address vmIp, long vni, DeviceId deviceId, Ip4Address hostIp) {
592 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
593 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
594
595 sBuilder.matchEthType(Ethernet.TYPE_IPV4)
596 .matchTunnelId(vni)
597 .matchIPDst(vmIp.toIpPrefix());
598 tBuilder.extension(buildNiciraExtenstion(deviceId, hostIp), deviceId)
599 .setOutput(getTunnelPort(deviceId));
600
601 ForwardingObjective fo = DefaultForwardingObjective.builder()
602 .withSelector(sBuilder.build())
603 .withTreatment(tBuilder.build())
604 .withPriority(ROUTING_RULE_PRIORITY)
605 .withFlag(ForwardingObjective.Flag.SPECIFIC)
606 .fromApp(appId)
607 .add();
608
609 flowObjectiveService.forward(deviceId, fo);
610 }
611
612 private void populateL3RulestoSameNode(Ip4Address vmIp, OpenstackPort p, Port port, Device device, long vni) {
613 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
614 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
615
616 sBuilder.matchEthType(Ethernet.TYPE_IPV4)
617 .matchIPDst(vmIp.toIpPrefix())
618 .matchTunnelId(vni);
619
620 tBuilder.setEthDst(p.macAddress())
621 .setOutput(port.number());
622
623 ForwardingObjective fo = DefaultForwardingObjective.builder()
624 .withSelector(sBuilder.build())
625 .withTreatment(tBuilder.build())
626 .withPriority(ROUTING_RULE_PRIORITY)
627 .withFlag(ForwardingObjective.Flag.SPECIFIC)
628 .fromApp(appId)
629 .add();
630
631 flowObjectiveService.forward(device.id(), fo);
632 }
633
634 private Port getPortFromOpenstackPort(Device device, OpenstackPort p) {
635 String openstackPortName = PORTNAME_PREFIX_VM + p.id().substring(0, 11);
636 return deviceService.getPorts(device.id())
637 .stream()
638 .filter(pt -> pt.annotations().value(PORTNAME).equals(openstackPortName))
639 .findAny()
640 .orElse(null);
641 }
642
643 /**
644 * Removes L3 rules for routerInterface events.
645 *
646 * @param vmIp Corresponding Vm ip
647 * @param routerInterfaces Corresponding routerInterfaces
648 */
649 public void removeL3Rules(Ip4Address vmIp, List<OpenstackRouterInterface> routerInterfaces) {
650 if (vmIp == null) {
651 return;
652 }
653
654 OpenstackRoutingService routingService = getService(OpenstackRoutingService.class);
655
656 deviceService.getAvailableDevices().forEach(d -> {
Kyuhwi Choi92d9ea42016-06-13 17:28:00 +0900657 if (!checkGatewayNode(d.id())) {
Kyuhwi Choi5e65e2c2016-04-01 11:48:15 +0900658 routerInterfaces.forEach(routerInterface -> {
659 String networkId = routingService.networkIdForRouterInterface(routerInterface.portId());
660 long vni = getVni(networkId);
661
662 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
663
664 sBuilder.matchEthType(Ethernet.TYPE_IPV4)
665 .matchIPDst(vmIp.toIpPrefix())
666 .matchTunnelId(vni);
667
668 removeRule(d.id(), sBuilder, ForwardingObjective.Flag.SPECIFIC, ROUTING_RULE_PRIORITY);
669 });
670 }
671 });
672 }
sangho0c2a3da2016-02-16 13:39:07 +0900673}