blob: d2c928fe2d8fe6aea4f520ff0243b5bc5504602c [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;
Hyunsun Moonda27e432016-07-13 13:09:45 -070072import static org.onosproject.net.AnnotationKeys.PORT_NAME;
sangho0c2a3da2016-02-16 13:39:07 +090073
74/**
75 * Populates Routing Flow Rules.
76 */
77public class OpenstackRoutingRulePopulator {
78
Kyuhwi Choie2b37e32016-02-05 14:04:14 +090079 private final Logger log = LoggerFactory.getLogger(getClass());
sangho0c2a3da2016-02-16 13:39:07 +090080
Kyuhwi Choie2b37e32016-02-05 14:04:14 +090081 private final ApplicationId appId;
82 private final FlowObjectiveService flowObjectiveService;
sangho93447f12016-02-24 00:33:22 +090083 private final OpenstackInterfaceService openstackService;
Kyuhwi Choie2b37e32016-02-05 14:04:14 +090084 private final DeviceService deviceService;
85 private final DriverService driverService;
Kyuhwi Choi92d9ea42016-06-13 17:28:00 +090086 private final ScalableGatewayService gatewayService;
sangho6032f342016-07-07 14:32:03 +090087 private final OpenstackNodeService nodeService;
sangho0c2a3da2016-02-16 13:39:07 +090088
Kyuhwi Choie2b37e32016-02-05 14:04:14 +090089 private static final String PORTNAME_PREFIX_TUNNEL = "vxlan";
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 Choie2b37e32016-02-05 14:04:14 +090094 private static final String TUNNEL_DESTINATION = "tunnelDst";
sangho0c2a3da2016-02-16 13:39:07 +090095 private static final int ROUTING_RULE_PRIORITY = 25000;
Kyuhwi Choiee9e3712016-02-22 22:49:36 +090096 private static final int FLOATING_RULE_PRIORITY = 42000;
97 private static final int PNAT_RULE_PRIORITY = 26000;
sangho0c2a3da2016-02-16 13:39:07 +090098 private static final int PNAT_TIMEOUT = 120;
Daniel Park23193902016-03-24 18:17:19 +090099 private static final int PREFIX_LENGTH = 32;
sangho0c2a3da2016-02-16 13:39:07 +0900100
101 private InboundPacket inboundPacket;
102 private OpenstackPort openstackPort;
103 private int portNum;
104 private MacAddress externalInterface;
105 private MacAddress externalRouter;
sangho0c2a3da2016-02-16 13:39:07 +0900106
Kyuhwi Choie2b37e32016-02-05 14:04:14 +0900107 /**
108 * The constructor of openstackRoutingRulePopulator.
109 *
110 * @param appId Caller`s appId
Kyuhwi Choi5e65e2c2016-04-01 11:48:15 +0900111 * @param openstackService Opestack REST request handler
Kyuhwi Choie2b37e32016-02-05 14:04:14 +0900112 * @param flowObjectiveService FlowObjectiveService
113 * @param deviceService DeviceService
114 * @param driverService DriverService
Hyunsun Moonda27e432016-07-13 13:09:45 -0700115 * @param nodeService openstack node service
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 -> {
Kyuhwi Choi176c83d2016-07-14 11:39:37 +0900191 tBuilder.setOutput(gatewayService.getGatewayExternalPort(node.getGatewayDeviceId()));
Kyuhwi Choi92d9ea42016-06-13 17:28:00 +0900192 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()
Hyunsun Moonda27e432016-07-13 13:09:45 -0700208 .filter(p -> p.annotations().value(PORT_NAME)
sangho6032f342016-07-07 14:32:03 +0900209 .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()
Hyunsun Moonda27e432016-07-13 13:09:45 -0700296 .filter(p -> p.isEnabled() && p.annotations().value(PORT_NAME).equals(openstackPortName))
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900297 .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()
Hyunsun Moonda27e432016-07-13 13:09:45 -0700335 .filter(p -> p.annotations().value(PORT_NAME).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
sangho0c2a3da2016-02-16 13:39:07 +0900407 private Device getGatewayNode() {
sangho6032f342016-07-07 14:32:03 +0900408
409 // TODO Return the correct gateway node
410 Optional<OpenstackNode> gwNode = nodeService.nodes().stream()
411 .filter(n -> n.type().equals(OpenstackNodeService.NodeType.GATEWAY))
412 .findFirst();
413
414 if (!gwNode.isPresent()) {
415 log.warn("No Gateway is defined.");
416 return null;
417 }
418
419 return deviceService.getDevice(gwNode.get().intBridge());
sangho0c2a3da2016-02-16 13:39:07 +0900420 }
421
sangho6032f342016-07-07 14:32:03 +0900422 private boolean isTypeOf(DeviceId deviceId, OpenstackNodeService.NodeType type) {
423
424 Optional<OpenstackNode> node = nodeService.nodes().stream()
425 .filter(n -> n.intBridge().equals(deviceId) ||
426 (n.routerBridge().isPresent() && n.routerBridge().get().equals(deviceId)))
427 .filter(n -> n.type().equals(type))
428 .findFirst();
429
430 if (node.isPresent()) {
431 return true;
432 }
433
434 return false;
sangho0c2a3da2016-02-16 13:39:07 +0900435 }
436
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900437 private long getVni(String netId) {
438 return Long.parseLong(openstackService.network(netId).segmentId());
Kyuhwi Choie2b37e32016-02-05 14:04:14 +0900439 }
440
441 /**
442 * Remove flow rules for external connection.
443 *
444 * @param routerInterface Corresponding routerInterface
445 */
sangho0c2a3da2016-02-16 13:39:07 +0900446 public void removeExternalRules(OpenstackRouterInterface routerInterface) {
Kyuhwi Choie2b37e32016-02-05 14:04:14 +0900447 OpenstackSubnet openstackSubnet = openstackService.subnet(routerInterface.subnetId());
sangho0c2a3da2016-02-16 13:39:07 +0900448 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
449 sBuilder.matchEthType(Ethernet.TYPE_IPV4)
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900450 .matchTunnelId(getVni(openstackSubnet.networkId()))
sangho6032f342016-07-07 14:32:03 +0900451 .matchEthDst(Constants.GATEWAY_MAC);
sangho0c2a3da2016-02-16 13:39:07 +0900452
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900453 StreamSupport.stream(deviceService.getDevices().spliterator(), false)
sangho0c2a3da2016-02-16 13:39:07 +0900454 .forEach(d -> {
sangho6032f342016-07-07 14:32:03 +0900455 ForwardingObjective.Flag flag = isTypeOf(d.id(), OpenstackNodeService.NodeType.GATEWAY) ?
Kyuhwi Choi5e65e2c2016-04-01 11:48:15 +0900456 ForwardingObjective.Flag.VERSATILE :
457 ForwardingObjective.Flag.SPECIFIC;
Daniel Park23193902016-03-24 18:17:19 +0900458 removeRule(d.id(), sBuilder, flag, ROUTING_RULE_PRIORITY);
sangho0c2a3da2016-02-16 13:39:07 +0900459 });
460
461 }
462
Kyuhwi Choi92d9ea42016-06-13 17:28:00 +0900463 private void removeRule(DeviceId deviceId, TrafficSelector.Builder sBuilder,
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900464 ForwardingObjective.Flag flag, int priority) {
sangho0c2a3da2016-02-16 13:39:07 +0900465 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
466
467 ForwardingObjective fo = DefaultForwardingObjective.builder()
468 .withSelector(sBuilder.build())
469 .withTreatment(tBuilder.build())
470 .withFlag(flag)
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900471 .withPriority(priority)
sangho0c2a3da2016-02-16 13:39:07 +0900472 .fromApp(appId)
473 .remove();
474
Kyuhwi Choi92d9ea42016-06-13 17:28:00 +0900475 flowObjectiveService.forward(deviceId, fo);
sangho0c2a3da2016-02-16 13:39:07 +0900476 }
477
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900478 /**
479 * Populates flow rules for floatingIp configuration.
480 *
481 * @param floatingIP Corresponding floating ip information
482 */
483 public void populateFloatingIpRules(OpenstackFloatingIP floatingIP) {
484 OpenstackPort port = openstackService.port(floatingIP.portId());
485 //1. incoming rules
486 populateFloatingIpIncomingRules(floatingIP, port);
487 //2. outgoing rules
488 populateFloatingIpOutgoingRules(floatingIP, port);
489 }
490
491 private void populateFloatingIpIncomingRules(OpenstackFloatingIP floatingIP, OpenstackPort port) {
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900492 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
493 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
494
495 sBuilder.matchEthType(Ethernet.TYPE_IPV4)
Daniel Park23193902016-03-24 18:17:19 +0900496 .matchIPDst(IpPrefix.valueOf(floatingIP.floatingIpAddress(), PREFIX_LENGTH));
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900497
sangho6032f342016-07-07 14:32:03 +0900498 DeviceId gatewayDeviceId = DeviceId.deviceId(port.deviceId());
499 Optional<IpAddress> ipAddress = nodeService.dataIp(gatewayDeviceId);
500 if (!ipAddress.isPresent()) {
501 log.warn("No IP address found for device {}", port.deviceId());
502 return;
503 }
504 tBuilder.setEthSrc(Constants.GATEWAY_MAC)
505 .setEthDst(port.macAddress())
506 .setIpDst(floatingIP.fixedIpAddress())
507 .setTunnelId(getVni(port.networkId()))
508 .extension(buildNiciraExtenstion(gatewayDeviceId,
509 ipAddress.get().getIp4Address()), gatewayDeviceId)
510 .setOutput(getTunnelPort(gatewayDeviceId));
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900511
sangho6032f342016-07-07 14:32:03 +0900512 ForwardingObjective fo = DefaultForwardingObjective.builder()
513 .withSelector(sBuilder.build())
514 .withTreatment(tBuilder.build())
515 .withFlag(ForwardingObjective.Flag.VERSATILE)
516 .withPriority(FLOATING_RULE_PRIORITY)
517 .fromApp(appId)
518 .add();
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900519
sangho6032f342016-07-07 14:32:03 +0900520 flowObjectiveService.forward(getGatewayNode().id(), fo);
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900521 }
522
523 private void populateFloatingIpOutgoingRules(OpenstackFloatingIP floatingIP, OpenstackPort port) {
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900524 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
525 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
526
527 sBuilder.matchEthType(Ethernet.TYPE_IPV4)
528 .matchTunnelId(getVni(port.networkId()))
529 .matchIPSrc(IpPrefix.valueOf(floatingIP.fixedIpAddress(), 32));
530
Kyuhwi Choi92d9ea42016-06-13 17:28:00 +0900531 getGatewayNodeList().forEach(device -> {
532 DeviceId deviceId = device.id();
533 tBuilder.setIpSrc(floatingIP.floatingIpAddress())
sangho6032f342016-07-07 14:32:03 +0900534 .setEthSrc(Constants.GW_EXT_INT_MAC)
535 .setEthDst(Constants.PHY_ROUTER_MAC)
Kyuhwi Choi92d9ea42016-06-13 17:28:00 +0900536 .setOutput(getExternalPortNum(deviceId));
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900537
Kyuhwi Choi92d9ea42016-06-13 17:28:00 +0900538 ForwardingObjective fo = DefaultForwardingObjective.builder()
539 .withSelector(sBuilder.build())
540 .withTreatment(tBuilder.build())
541 .withFlag(ForwardingObjective.Flag.VERSATILE)
542 .withPriority(FLOATING_RULE_PRIORITY)
543 .fromApp(appId)
544 .add();
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900545
Kyuhwi Choi92d9ea42016-06-13 17:28:00 +0900546 flowObjectiveService.forward(deviceId, fo);
547 });
548 }
549
550 private PortNumber getExternalPortNum(DeviceId deviceId) {
Kyuhwi Choi176c83d2016-07-14 11:39:37 +0900551 return checkNotNull(gatewayService.getGatewayExternalPort(deviceId), PORTNOTNULL);
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900552 }
553
554 /**
555 * Removes flow rules for floating ip configuration.
556 *
sangho6032f342016-07-07 14:32:03 +0900557 * @param floatingIp Corresponding floating ip information
558 * @param host host information for vm to remove
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900559 */
sangho6032f342016-07-07 14:32:03 +0900560 public void removeFloatingIpRules(OpenstackFloatingIP floatingIp, Host host) {
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900561 TrafficSelector.Builder sOutgoingBuilder = DefaultTrafficSelector.builder();
562 TrafficSelector.Builder sIncomingBuilder = DefaultTrafficSelector.builder();
563
sangho6032f342016-07-07 14:32:03 +0900564 // XXX FloatingIp.tenant_id() == host.vxlan_id ???
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900565 sOutgoingBuilder.matchEthType(Ethernet.TYPE_IPV4)
sangho6032f342016-07-07 14:32:03 +0900566 .matchTunnelId(Integer.parseInt(host.annotations().value(Constants.VXLAN_ID)))
567 .matchIPSrc(IpPrefix.valueOf(floatingIp.fixedIpAddress(), PREFIX_LENGTH));
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900568
569 sIncomingBuilder.matchEthType(Ethernet.TYPE_IPV4)
sangho6032f342016-07-07 14:32:03 +0900570 .matchIPDst(IpPrefix.valueOf(floatingIp.floatingIpAddress(), PREFIX_LENGTH));
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900571
Kyuhwi Choi92d9ea42016-06-13 17:28:00 +0900572 getGatewayNodeList().forEach(device -> {
573 removeRule(device.id(), sOutgoingBuilder, ForwardingObjective.Flag.VERSATILE, FLOATING_RULE_PRIORITY);
574 removeRule(device.id(), sIncomingBuilder, ForwardingObjective.Flag.VERSATILE, FLOATING_RULE_PRIORITY);
575 });
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900576 }
577
Kyuhwi Choi5e65e2c2016-04-01 11:48:15 +0900578 /**
579 * Populates L3 rules for east to west traffic.
580 *
Kyuhwi Choi92d9ea42016-06-13 17:28:00 +0900581 * @param openstackPort target VM
Kyuhwi Choi5e65e2c2016-04-01 11:48:15 +0900582 * @param targetList target openstackRouterInterfaces
583 */
Kyuhwi Choi92d9ea42016-06-13 17:28:00 +0900584 public void populateL3Rules(OpenstackPort openstackPort, List<OpenstackRouterInterface> targetList) {
585 Device device = getDevicefromOpenstackPort(openstackPort);
586 Port port = getPortFromOpenstackPort(device, openstackPort);
587 Ip4Address vmIp = openstackPort.fixedIps().values().iterator().next();
Kyuhwi Choi5e65e2c2016-04-01 11:48:15 +0900588
589 if (port == null) {
590 return;
591 }
592
593 targetList.forEach(routerInterface -> {
Kyuhwi Choi92d9ea42016-06-13 17:28:00 +0900594 long vni = getVni(openstackService.port(routerInterface.portId()).networkId());
Kyuhwi Choi5e65e2c2016-04-01 11:48:15 +0900595
596 if (vmIp == null) {
597 return;
598 }
599
Kyuhwi Choi92d9ea42016-06-13 17:28:00 +0900600 populateL3RulestoSameNode(vmIp, openstackPort, port, device, vni);
Kyuhwi Choi5e65e2c2016-04-01 11:48:15 +0900601
602 deviceService.getAvailableDevices().forEach(d -> {
sangho6032f342016-07-07 14:32:03 +0900603 if (!d.equals(device) && !d.equals(getGatewayNode())) {
604 populateL3RulestoDifferentNode(vmIp, vni, d.id(),
605 getHostIpfromOpenstackPort(openstackPort).getIp4Address());
Kyuhwi Choi5e65e2c2016-04-01 11:48:15 +0900606 }
607 });
Kyuhwi Choi5e65e2c2016-04-01 11:48:15 +0900608 });
609 }
610
611 private void populateL3RulestoDifferentNode(Ip4Address vmIp, long vni, DeviceId deviceId, Ip4Address hostIp) {
612 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
613 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
614
615 sBuilder.matchEthType(Ethernet.TYPE_IPV4)
616 .matchTunnelId(vni)
617 .matchIPDst(vmIp.toIpPrefix());
618 tBuilder.extension(buildNiciraExtenstion(deviceId, hostIp), deviceId)
619 .setOutput(getTunnelPort(deviceId));
620
621 ForwardingObjective fo = DefaultForwardingObjective.builder()
622 .withSelector(sBuilder.build())
623 .withTreatment(tBuilder.build())
624 .withPriority(ROUTING_RULE_PRIORITY)
625 .withFlag(ForwardingObjective.Flag.SPECIFIC)
626 .fromApp(appId)
627 .add();
628
629 flowObjectiveService.forward(deviceId, fo);
630 }
631
632 private void populateL3RulestoSameNode(Ip4Address vmIp, OpenstackPort p, Port port, Device device, long vni) {
633 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
634 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
635
636 sBuilder.matchEthType(Ethernet.TYPE_IPV4)
637 .matchIPDst(vmIp.toIpPrefix())
638 .matchTunnelId(vni);
639
640 tBuilder.setEthDst(p.macAddress())
641 .setOutput(port.number());
642
643 ForwardingObjective fo = DefaultForwardingObjective.builder()
644 .withSelector(sBuilder.build())
645 .withTreatment(tBuilder.build())
646 .withPriority(ROUTING_RULE_PRIORITY)
647 .withFlag(ForwardingObjective.Flag.SPECIFIC)
648 .fromApp(appId)
649 .add();
650
651 flowObjectiveService.forward(device.id(), fo);
652 }
653
654 private Port getPortFromOpenstackPort(Device device, OpenstackPort p) {
655 String openstackPortName = PORTNAME_PREFIX_VM + p.id().substring(0, 11);
656 return deviceService.getPorts(device.id())
657 .stream()
Hyunsun Moonda27e432016-07-13 13:09:45 -0700658 .filter(pt -> pt.annotations().value(PORT_NAME).equals(openstackPortName))
Kyuhwi Choi5e65e2c2016-04-01 11:48:15 +0900659 .findAny()
660 .orElse(null);
661 }
662
663 /**
664 * Removes L3 rules for routerInterface events.
665 *
666 * @param vmIp Corresponding Vm ip
667 * @param routerInterfaces Corresponding routerInterfaces
668 */
669 public void removeL3Rules(Ip4Address vmIp, List<OpenstackRouterInterface> routerInterfaces) {
670 if (vmIp == null) {
671 return;
672 }
673
674 OpenstackRoutingService routingService = getService(OpenstackRoutingService.class);
675
676 deviceService.getAvailableDevices().forEach(d -> {
sangho6032f342016-07-07 14:32:03 +0900677 if (isTypeOf(d.id(), OpenstackNodeService.NodeType.COMPUTE)) {
Kyuhwi Choi5e65e2c2016-04-01 11:48:15 +0900678 routerInterfaces.forEach(routerInterface -> {
679 String networkId = routingService.networkIdForRouterInterface(routerInterface.portId());
680 long vni = getVni(networkId);
681
682 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
683
684 sBuilder.matchEthType(Ethernet.TYPE_IPV4)
685 .matchIPDst(vmIp.toIpPrefix())
686 .matchTunnelId(vni);
687
688 removeRule(d.id(), sBuilder, ForwardingObjective.Flag.SPECIFIC, ROUTING_RULE_PRIORITY);
689 });
690 }
691 });
692 }
sangho0c2a3da2016-02-16 13:39:07 +0900693}