blob: b109d2cb856d80a9357e2d3789cbdd5b28984e32 [file] [log] [blame]
Hyunsun Moon44aac662017-02-18 02:07:01 +09001/*
Brian O'Connora09fe5b2017-08-03 21:12:30 -07002 * Copyright 2016-present Open Networking Foundation
Hyunsun Moon44aac662017-02-18 02:07:01 +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.impl;
17
18import org.apache.felix.scr.annotations.Activate;
19import org.apache.felix.scr.annotations.Component;
20import org.apache.felix.scr.annotations.Deactivate;
21import org.apache.felix.scr.annotations.Reference;
22import org.apache.felix.scr.annotations.ReferenceCardinality;
23import org.onlab.packet.Ethernet;
24import org.onlab.packet.IPv4;
25import org.onlab.packet.IpAddress;
26import org.onlab.packet.IpPrefix;
Hyunsun Moon44aac662017-02-18 02:07:01 +090027import org.onlab.packet.TCP;
28import org.onlab.packet.TpPort;
29import org.onlab.packet.UDP;
daniel parkee8700b2017-05-11 15:50:03 +090030import org.onlab.packet.VlanId;
Hyunsun Moon44aac662017-02-18 02:07:01 +090031import org.onlab.util.KryoNamespace;
32import org.onosproject.core.ApplicationId;
33import org.onosproject.core.CoreService;
34import org.onosproject.net.DeviceId;
35import org.onosproject.net.device.DeviceService;
36import org.onosproject.net.flow.DefaultTrafficSelector;
37import org.onosproject.net.flow.DefaultTrafficTreatment;
38import org.onosproject.net.flow.TrafficSelector;
39import org.onosproject.net.flow.TrafficTreatment;
Hyunsun Moon44aac662017-02-18 02:07:01 +090040import org.onosproject.net.packet.DefaultOutboundPacket;
41import org.onosproject.net.packet.InboundPacket;
42import org.onosproject.net.packet.PacketContext;
43import org.onosproject.net.packet.PacketProcessor;
44import org.onosproject.net.packet.PacketService;
daniel park576969a2018-03-09 07:07:41 +090045import org.onosproject.openstacknetworking.api.ExternalPeerRouter;
Hyunsun Moon44aac662017-02-18 02:07:01 +090046import org.onosproject.openstacknetworking.api.InstancePort;
47import org.onosproject.openstacknetworking.api.InstancePortService;
sanghodc375372017-06-08 10:41:30 +090048import org.onosproject.openstacknetworking.api.OpenstackFlowRuleService;
Hyunsun Moon44aac662017-02-18 02:07:01 +090049import org.onosproject.openstacknetworking.api.OpenstackNetworkService;
sanghodc375372017-06-08 10:41:30 +090050import org.onosproject.openstacknetworking.api.OpenstackRouterService;
Jian Li26949762018-03-30 15:46:37 +090051import org.onosproject.openstacknetworking.util.RulePopulatorUtil;
Hyunsun Moon0d457362017-06-27 17:19:41 +090052import org.onosproject.openstacknode.api.OpenstackNode;
53import org.onosproject.openstacknode.api.OpenstackNodeService;
Hyunsun Moon44aac662017-02-18 02:07:01 +090054import org.onosproject.store.serializers.KryoNamespaces;
55import org.onosproject.store.service.ConsistentMap;
daniel park0bc7fdb2017-03-13 14:20:08 +090056import org.onosproject.store.service.DistributedSet;
Hyunsun Moon44aac662017-02-18 02:07:01 +090057import org.onosproject.store.service.Serializer;
58import org.onosproject.store.service.StorageService;
59import org.openstack4j.model.network.ExternalGateway;
60import org.openstack4j.model.network.IP;
61import org.openstack4j.model.network.Network;
daniel parkee8700b2017-05-11 15:50:03 +090062import org.openstack4j.model.network.NetworkType;
Hyunsun Moon44aac662017-02-18 02:07:01 +090063import org.openstack4j.model.network.Port;
64import org.openstack4j.model.network.Router;
65import org.openstack4j.model.network.RouterInterface;
66import org.openstack4j.model.network.Subnet;
67import org.slf4j.Logger;
68
69import java.nio.ByteBuffer;
70import java.util.Objects;
Hyunsun Moon0d457362017-06-27 17:19:41 +090071import java.util.Set;
Hyunsun Moon44aac662017-02-18 02:07:01 +090072import java.util.concurrent.ExecutorService;
Hyunsun Moon0d457362017-06-27 17:19:41 +090073import java.util.stream.Collectors;
Hyunsun Moon44aac662017-02-18 02:07:01 +090074
75import static java.util.concurrent.Executors.newSingleThreadExecutor;
76import static org.onlab.util.Tools.groupedThreads;
daniel parkeeb8e042018-02-21 14:06:58 +090077import static org.onosproject.openstacknetworking.api.Constants.DEFAULT_GATEWAY_MAC;
78import static org.onosproject.openstacknetworking.api.Constants.GW_COMMON_TABLE;
79import static org.onosproject.openstacknetworking.api.Constants.OPENSTACK_NETWORKING_APP_ID;
80import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_SNAT_RULE;
Hyunsun Moon0d457362017-06-27 17:19:41 +090081import static org.onosproject.openstacknode.api.OpenstackNode.NodeType.GATEWAY;
Hyunsun Moon44aac662017-02-18 02:07:01 +090082import static org.slf4j.LoggerFactory.getLogger;
83
84/**
85 * Handle packets needs SNAT.
86 */
87@Component(immediate = true)
88public class OpenstackRoutingSnatHandler {
89
90 private final Logger log = getLogger(getClass());
91
92 private static final String ERR_PACKETIN = "Failed to handle packet in: ";
daniel parkee8700b2017-05-11 15:50:03 +090093 private static final String ERR_UNSUPPORTED_NET_TYPE = "Unsupported network type";
Ray Milkey3717e602018-02-01 13:49:47 -080094 private static final long TIME_OUT_SNAT_PORT_MS = 120L * 1000L;
sangho79d6a832017-05-02 14:53:46 +090095 private static final int TP_PORT_MINIMUM_NUM = 65000;
Hyunsun Moon44aac662017-02-18 02:07:01 +090096 private static final int TP_PORT_MAXIMUM_NUM = 65535;
97
98 private static final KryoNamespace.Builder NUMBER_SERIALIZER = KryoNamespace.newBuilder()
99 .register(KryoNamespaces.API);
100
101 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
102 protected CoreService coreService;
103
104 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
105 protected PacketService packetService;
106
107 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
108 protected StorageService storageService;
109
110 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Hyunsun Moon44aac662017-02-18 02:07:01 +0900111 protected DeviceService deviceService;
112
113 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
114 protected InstancePortService instancePortService;
115
116 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
117 protected OpenstackNodeService osNodeService;
118
119 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
120 protected OpenstackNetworkService osNetworkService;
121
122 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
123 protected OpenstackRouterService osRouterService;
124
sanghodc375372017-06-08 10:41:30 +0900125 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
126 protected OpenstackFlowRuleService osFlowRuleService;
127
Hyunsun Moon44aac662017-02-18 02:07:01 +0900128 private final ExecutorService eventExecutor = newSingleThreadExecutor(
129 groupedThreads(this.getClass().getSimpleName(), "event-handler", log));
Hyunsun Moon0d457362017-06-27 17:19:41 +0900130 private final PacketProcessor packetProcessor = new InternalPacketProcessor();
Hyunsun Moon44aac662017-02-18 02:07:01 +0900131
daniel park0bc7fdb2017-03-13 14:20:08 +0900132 private ConsistentMap<Integer, Long> allocatedPortNumMap;
133 private DistributedSet<Integer> unUsedPortNumSet;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900134 private ApplicationId appId;
135
136 @Activate
137 protected void activate() {
138 appId = coreService.registerApplication(OPENSTACK_NETWORKING_APP_ID);
daniel park0bc7fdb2017-03-13 14:20:08 +0900139
140 allocatedPortNumMap = storageService.<Integer, Long>consistentMapBuilder()
Hyunsun Moon44aac662017-02-18 02:07:01 +0900141 .withSerializer(Serializer.using(NUMBER_SERIALIZER.build()))
daniel park0bc7fdb2017-03-13 14:20:08 +0900142 .withName("openstackrouting-allocatedportnummap")
Hyunsun Moon44aac662017-02-18 02:07:01 +0900143 .withApplicationId(appId)
144 .build();
145
daniel park0bc7fdb2017-03-13 14:20:08 +0900146 unUsedPortNumSet = storageService.<Integer>setBuilder()
147 .withName("openstackrouting-unusedportnumset")
148 .withSerializer(Serializer.using(KryoNamespaces.API))
149 .build()
150 .asDistributedSet();
151
152 initializeUnusedPortNumSet();
153
Hyunsun Moon44aac662017-02-18 02:07:01 +0900154 packetService.addProcessor(packetProcessor, PacketProcessor.director(1));
155 log.info("Started");
156 }
157
daniel park0bc7fdb2017-03-13 14:20:08 +0900158 private void initializeUnusedPortNumSet() {
159 for (int i = TP_PORT_MINIMUM_NUM; i < TP_PORT_MAXIMUM_NUM; i++) {
Hyunsun Moon0e058f22017-04-19 17:00:52 +0900160 if (!allocatedPortNumMap.containsKey(i)) {
161 unUsedPortNumSet.add(i);
daniel park0bc7fdb2017-03-13 14:20:08 +0900162 }
163 }
164
165 clearPortNumMap();
166 }
167
Hyunsun Moon44aac662017-02-18 02:07:01 +0900168 @Deactivate
169 protected void deactivate() {
170 packetService.removeProcessor(packetProcessor);
171 eventExecutor.shutdown();
172 log.info("Stopped");
173 }
174
175 private void processSnatPacket(PacketContext context, Ethernet eth) {
176 IPv4 iPacket = (IPv4) eth.getPayload();
177 InboundPacket packetIn = context.inPacket();
178
Hyunsun Moon0e058f22017-04-19 17:00:52 +0900179 int patPort = getPortNum();
Hyunsun Moon44aac662017-02-18 02:07:01 +0900180
181 InstancePort srcInstPort = instancePortService.instancePort(eth.getSourceMAC());
182 if (srcInstPort == null) {
Hyunsun Moon0e058f22017-04-19 17:00:52 +0900183 log.error(ERR_PACKETIN + "source host(MAC:{}) does not exist",
Hyunsun Moon44aac662017-02-18 02:07:01 +0900184 eth.getSourceMAC());
185 return;
186 }
Hyunsun Moon0e058f22017-04-19 17:00:52 +0900187
Hyunsun Moon44aac662017-02-18 02:07:01 +0900188 IpAddress srcIp = IpAddress.valueOf(iPacket.getSourceAddress());
189 Subnet srcSubnet = getSourceSubnet(srcInstPort, srcIp);
190 IpAddress externalGatewayIp = getExternalIp(srcSubnet);
daniel parkb5817102018-02-15 00:18:51 +0900191
Hyunsun Moon44aac662017-02-18 02:07:01 +0900192 if (externalGatewayIp == null) {
193 return;
194 }
195
daniel park576969a2018-03-09 07:07:41 +0900196 ExternalPeerRouter externalPeerRouter = externalPeerRouter(srcSubnet);
197 if (externalPeerRouter == null) {
daniel parkb5817102018-02-15 00:18:51 +0900198 return;
199 }
200
Hyunsun Moon44aac662017-02-18 02:07:01 +0900201 populateSnatFlowRules(context.inPacket(),
202 srcInstPort,
203 TpPort.tpPort(patPort),
daniel park576969a2018-03-09 07:07:41 +0900204 externalGatewayIp, externalPeerRouter);
205
Hyunsun Moon44aac662017-02-18 02:07:01 +0900206
Ray Milkeyf0c47612017-09-28 11:29:38 -0700207 packetOut(eth.duplicate(),
Hyunsun Moon44aac662017-02-18 02:07:01 +0900208 packetIn.receivedFrom().deviceId(),
209 patPort,
daniel park576969a2018-03-09 07:07:41 +0900210 externalGatewayIp, externalPeerRouter);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900211 }
212
daniel park576969a2018-03-09 07:07:41 +0900213 private ExternalPeerRouter externalPeerRouter(Subnet subnet) {
daniel parkeeb8e042018-02-21 14:06:58 +0900214 RouterInterface osRouterIface = osRouterService.routerInterfaces().stream()
215 .filter(i -> Objects.equals(i.getSubnetId(), subnet.getId()))
216 .findAny().orElse(null);
217 if (osRouterIface == null) {
218 return null;
219 }
220
221 Router osRouter = osRouterService.router(osRouterIface.getId());
222 if (osRouter == null) {
223 return null;
224 }
225 if (osRouter.getExternalGatewayInfo() == null) {
226 return null;
227 }
228
229 ExternalGateway exGatewayInfo = osRouter.getExternalGatewayInfo();
daniel park576969a2018-03-09 07:07:41 +0900230 return osNetworkService.externalPeerRouter(exGatewayInfo);
daniel parkeeb8e042018-02-21 14:06:58 +0900231 }
232
Hyunsun Moon44aac662017-02-18 02:07:01 +0900233 private Subnet getSourceSubnet(InstancePort instance, IpAddress srcIp) {
234 Port osPort = osNetworkService.port(instance.portId());
235 IP fixedIp = osPort.getFixedIps().stream()
236 .filter(ip -> IpAddress.valueOf(ip.getIpAddress()).equals(srcIp))
237 .findAny().orElse(null);
238 if (fixedIp == null) {
239 return null;
240 }
241 return osNetworkService.subnet(fixedIp.getSubnetId());
242 }
243
244 private IpAddress getExternalIp(Subnet srcSubnet) {
245 RouterInterface osRouterIface = osRouterService.routerInterfaces().stream()
246 .filter(i -> Objects.equals(i.getSubnetId(), srcSubnet.getId()))
247 .findAny().orElse(null);
248 if (osRouterIface == null) {
249 // this subnet is not connected to the router
250 log.trace(ERR_PACKETIN + "source subnet(ID:{}, CIDR:{}) has no router",
251 srcSubnet.getId(), srcSubnet.getCidr());
252 return null;
253 }
254
255 Router osRouter = osRouterService.router(osRouterIface.getId());
256 if (osRouter.getExternalGatewayInfo() == null) {
257 // this router does not have external connectivity
258 log.trace(ERR_PACKETIN + "router({}) has no external gateway",
259 osRouter.getName());
260 return null;
261 }
262
263 ExternalGateway exGatewayInfo = osRouter.getExternalGatewayInfo();
264 if (!exGatewayInfo.isEnableSnat()) {
265 // SNAT is disabled in this router
266 log.trace(ERR_PACKETIN + "router({}) SNAT is disabled", osRouter.getName());
267 return null;
268 }
269
270 // TODO fix openstack4j for ExternalGateway provides external fixed IP list
271 Port exGatewayPort = osNetworkService.ports(exGatewayInfo.getNetworkId())
272 .stream()
273 .filter(port -> Objects.equals(port.getDeviceId(), osRouter.getId()))
274 .findAny().orElse(null);
275 if (exGatewayPort == null) {
276 log.trace(ERR_PACKETIN + "no external gateway port for router({})",
277 osRouter.getName());
278 return null;
279 }
280
281 return IpAddress.valueOf(exGatewayPort.getFixedIps().stream()
282 .findFirst().get().getIpAddress());
283 }
284
285 private void populateSnatFlowRules(InboundPacket packetIn, InstancePort srcInstPort,
daniel park576969a2018-03-09 07:07:41 +0900286 TpPort patPort, IpAddress externalIp, ExternalPeerRouter externalPeerRouter) {
Hyunsun Moon44aac662017-02-18 02:07:01 +0900287 Network osNet = osNetworkService.network(srcInstPort.networkId());
288 if (osNet == null) {
Jian Li71670d12018-03-02 21:31:07 +0900289 final String error = String.format("%s network %s not found",
290 ERR_PACKETIN, srcInstPort.networkId());
Hyunsun Moon44aac662017-02-18 02:07:01 +0900291 throw new IllegalStateException(error);
292 }
293
294 setDownstreamRules(srcInstPort,
daniel parkee8700b2017-05-11 15:50:03 +0900295 osNet.getProviderSegID(),
296 osNet.getNetworkType(),
Hyunsun Moon44aac662017-02-18 02:07:01 +0900297 externalIp,
daniel park576969a2018-03-09 07:07:41 +0900298 externalPeerRouter,
Hyunsun Moon44aac662017-02-18 02:07:01 +0900299 patPort,
300 packetIn);
301
daniel parkee8700b2017-05-11 15:50:03 +0900302 setUpstreamRules(osNet.getProviderSegID(),
303 osNet.getNetworkType(),
Hyunsun Moon44aac662017-02-18 02:07:01 +0900304 externalIp,
daniel park576969a2018-03-09 07:07:41 +0900305 externalPeerRouter,
Hyunsun Moon44aac662017-02-18 02:07:01 +0900306 patPort,
307 packetIn);
308 }
309
Hyunsun Moon0d457362017-06-27 17:19:41 +0900310 private void setDownstreamRules(InstancePort srcInstPort, String segmentId,
311 NetworkType networkType,
daniel parkb5817102018-02-15 00:18:51 +0900312 IpAddress externalIp,
daniel park576969a2018-03-09 07:07:41 +0900313 ExternalPeerRouter externalPeerRouter,
daniel parkb5817102018-02-15 00:18:51 +0900314 TpPort patPort,
Hyunsun Moon44aac662017-02-18 02:07:01 +0900315 InboundPacket packetIn) {
316 IPv4 iPacket = (IPv4) packetIn.parsed().getPayload();
317 IpAddress internalIp = IpAddress.valueOf(iPacket.getSourceAddress());
318
319 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder()
320 .matchEthType(Ethernet.TYPE_IPV4)
321 .matchIPProtocol(iPacket.getProtocol())
Hyunsun Moon0d457362017-06-27 17:19:41 +0900322 .matchIPDst(IpPrefix.valueOf(externalIp.getIp4Address(), 32))
Hyunsun Moon44aac662017-02-18 02:07:01 +0900323 .matchIPSrc(IpPrefix.valueOf(iPacket.getDestinationAddress(), 32));
324
325 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder()
Hyunsun Moon44aac662017-02-18 02:07:01 +0900326 .setEthDst(packetIn.parsed().getSourceMAC())
327 .setIpDst(internalIp);
328
daniel park576969a2018-03-09 07:07:41 +0900329 if (!externalPeerRouter.externalPeerRouterVlanId().equals(VlanId.NONE)) {
330 sBuilder.matchVlanId(externalPeerRouter.externalPeerRouterVlanId());
331 tBuilder.popVlan();
332 }
333
daniel parkee8700b2017-05-11 15:50:03 +0900334 switch (networkType) {
335 case VXLAN:
336 tBuilder.setTunnelId(Long.parseLong(segmentId));
337 break;
338 case VLAN:
339 tBuilder.pushVlan()
340 .setVlanId(VlanId.vlanId(segmentId))
341 .setEthSrc(DEFAULT_GATEWAY_MAC);
342 break;
343 default:
Jian Li71670d12018-03-02 21:31:07 +0900344 final String error = String.format("%s %s",
345 ERR_UNSUPPORTED_NET_TYPE, networkType.toString());
daniel parkee8700b2017-05-11 15:50:03 +0900346 throw new IllegalStateException(error);
347 }
348
349
Hyunsun Moon44aac662017-02-18 02:07:01 +0900350 switch (iPacket.getProtocol()) {
351 case IPv4.PROTOCOL_TCP:
352 TCP tcpPacket = (TCP) iPacket.getPayload();
353 sBuilder.matchTcpSrc(TpPort.tpPort(tcpPacket.getDestinationPort()))
354 .matchTcpDst(patPort);
355 tBuilder.setTcpDst(TpPort.tpPort(tcpPacket.getSourcePort()));
356 break;
357 case IPv4.PROTOCOL_UDP:
358 UDP udpPacket = (UDP) iPacket.getPayload();
359 sBuilder.matchUdpSrc(TpPort.tpPort(udpPacket.getDestinationPort()))
360 .matchUdpDst(patPort);
361 tBuilder.setUdpDst(TpPort.tpPort(udpPacket.getSourcePort()));
362 break;
363 default:
364 break;
365 }
366
Hyunsun Moon0d457362017-06-27 17:19:41 +0900367 OpenstackNode srcNode = osNodeService.node(srcInstPort.deviceId());
368 osNodeService.completeNodes(GATEWAY).forEach(gNode -> {
Hyunsun Moon44aac662017-02-18 02:07:01 +0900369 TrafficTreatment.Builder tmpBuilder =
370 DefaultTrafficTreatment.builder(tBuilder.build());
daniel parkee8700b2017-05-11 15:50:03 +0900371 switch (networkType) {
372 case VXLAN:
373 tmpBuilder.extension(RulePopulatorUtil.buildExtension(
374 deviceService,
Hyunsun Moon0d457362017-06-27 17:19:41 +0900375 gNode.intgBridge(),
376 srcNode.dataIp().getIp4Address()), gNode.intgBridge())
377 .setOutput(gNode.tunnelPortNum());
daniel parkee8700b2017-05-11 15:50:03 +0900378 break;
379 case VLAN:
Hyunsun Moon0d457362017-06-27 17:19:41 +0900380 tmpBuilder.setOutput(gNode.vlanPortNum());
daniel parkee8700b2017-05-11 15:50:03 +0900381 break;
382 default:
Jian Li71670d12018-03-02 21:31:07 +0900383 final String error = String.format("%s %s",
384 ERR_UNSUPPORTED_NET_TYPE, networkType.toString());
daniel parkee8700b2017-05-11 15:50:03 +0900385 throw new IllegalStateException(error);
386 }
Hyunsun Moon44aac662017-02-18 02:07:01 +0900387
sanghodc375372017-06-08 10:41:30 +0900388 osFlowRuleService.setRule(
389 appId,
Hyunsun Moon0d457362017-06-27 17:19:41 +0900390 gNode.intgBridge(),
sanghodc375372017-06-08 10:41:30 +0900391 sBuilder.build(),
392 tmpBuilder.build(),
393 PRIORITY_SNAT_RULE,
394 GW_COMMON_TABLE,
395 true);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900396 });
397 }
398
Hyunsun Moon0d457362017-06-27 17:19:41 +0900399 private void setUpstreamRules(String segmentId, NetworkType networkType,
daniel park576969a2018-03-09 07:07:41 +0900400 IpAddress externalIp, ExternalPeerRouter externalPeerRouter,
daniel parkb5817102018-02-15 00:18:51 +0900401 TpPort patPort,
Hyunsun Moon44aac662017-02-18 02:07:01 +0900402 InboundPacket packetIn) {
403 IPv4 iPacket = (IPv4) packetIn.parsed().getPayload();
daniel parkee8700b2017-05-11 15:50:03 +0900404
405 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder()
Hyunsun Moon44aac662017-02-18 02:07:01 +0900406 .matchEthType(Ethernet.TYPE_IPV4)
407 .matchIPProtocol(iPacket.getProtocol())
Hyunsun Moon44aac662017-02-18 02:07:01 +0900408 .matchIPSrc(IpPrefix.valueOf(iPacket.getSourceAddress(), 32))
409 .matchIPDst(IpPrefix.valueOf(iPacket.getDestinationAddress(), 32));
410
411 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
daniel parkee8700b2017-05-11 15:50:03 +0900412
413 switch (networkType) {
414 case VXLAN:
415 sBuilder.matchTunnelId(Long.parseLong(segmentId));
416 break;
417 case VLAN:
418 sBuilder.matchVlanId(VlanId.vlanId(segmentId));
419 tBuilder.popVlan();
420 break;
421 default:
Jian Li71670d12018-03-02 21:31:07 +0900422 final String error = String.format("%s %s",
423 ERR_UNSUPPORTED_NET_TYPE, networkType.toString());
daniel parkee8700b2017-05-11 15:50:03 +0900424 throw new IllegalStateException(error);
425 }
426
Hyunsun Moon44aac662017-02-18 02:07:01 +0900427 switch (iPacket.getProtocol()) {
428 case IPv4.PROTOCOL_TCP:
429 TCP tcpPacket = (TCP) iPacket.getPayload();
430 sBuilder.matchTcpSrc(TpPort.tpPort(tcpPacket.getSourcePort()))
431 .matchTcpDst(TpPort.tpPort(tcpPacket.getDestinationPort()));
432 tBuilder.setTcpSrc(patPort)
daniel park576969a2018-03-09 07:07:41 +0900433 .setEthDst(externalPeerRouter.externalPeerRouterMac());
Hyunsun Moon44aac662017-02-18 02:07:01 +0900434 break;
435 case IPv4.PROTOCOL_UDP:
436 UDP udpPacket = (UDP) iPacket.getPayload();
437 sBuilder.matchUdpSrc(TpPort.tpPort(udpPacket.getSourcePort()))
438 .matchUdpDst(TpPort.tpPort(udpPacket.getDestinationPort()));
439 tBuilder.setUdpSrc(patPort)
daniel park576969a2018-03-09 07:07:41 +0900440 .setEthDst(externalPeerRouter.externalPeerRouterMac());
Hyunsun Moon44aac662017-02-18 02:07:01 +0900441 break;
442 default:
443 log.debug("Unsupported IPv4 protocol {}");
444 break;
445 }
446
daniel park576969a2018-03-09 07:07:41 +0900447 if (!externalPeerRouter.externalPeerRouterVlanId().equals(VlanId.NONE)) {
448 tBuilder.pushVlan().setVlanId(externalPeerRouter.externalPeerRouterVlanId());
449 }
450
Hyunsun Moon44aac662017-02-18 02:07:01 +0900451 tBuilder.setIpSrc(externalIp);
Hyunsun Moon0d457362017-06-27 17:19:41 +0900452 osNodeService.completeNodes(GATEWAY).forEach(gNode -> {
Hyunsun Moon44aac662017-02-18 02:07:01 +0900453 TrafficTreatment.Builder tmpBuilder =
454 DefaultTrafficTreatment.builder(tBuilder.build());
daniel parkb5817102018-02-15 00:18:51 +0900455 tmpBuilder.setOutput(gNode.uplinkPortNum());
Hyunsun Moon44aac662017-02-18 02:07:01 +0900456
sanghodc375372017-06-08 10:41:30 +0900457 osFlowRuleService.setRule(
458 appId,
Hyunsun Moon0d457362017-06-27 17:19:41 +0900459 gNode.intgBridge(),
sanghodc375372017-06-08 10:41:30 +0900460 sBuilder.build(),
461 tmpBuilder.build(),
462 PRIORITY_SNAT_RULE,
463 GW_COMMON_TABLE,
464 true);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900465 });
466 }
467
468 private void packetOut(Ethernet ethPacketIn, DeviceId srcDevice, int patPort,
daniel park576969a2018-03-09 07:07:41 +0900469 IpAddress externalIp, ExternalPeerRouter externalPeerRouter) {
Hyunsun Moon44aac662017-02-18 02:07:01 +0900470 IPv4 iPacket = (IPv4) ethPacketIn.getPayload();
Hyunsun Moon44aac662017-02-18 02:07:01 +0900471 switch (iPacket.getProtocol()) {
472 case IPv4.PROTOCOL_TCP:
473 TCP tcpPacket = (TCP) iPacket.getPayload();
474 tcpPacket.setSourcePort(patPort);
475 tcpPacket.resetChecksum();
476 tcpPacket.setParent(iPacket);
477 iPacket.setPayload(tcpPacket);
478 break;
479 case IPv4.PROTOCOL_UDP:
480 UDP udpPacket = (UDP) iPacket.getPayload();
481 udpPacket.setSourcePort(patPort);
482 udpPacket.resetChecksum();
483 udpPacket.setParent(iPacket);
484 iPacket.setPayload(udpPacket);
485 break;
486 default:
487 log.trace("Temporally, this method can process UDP and TCP protocol.");
488 return;
489 }
490
491 iPacket.setSourceAddress(externalIp.toString());
492 iPacket.resetChecksum();
493 iPacket.setParent(ethPacketIn);
daniel park576969a2018-03-09 07:07:41 +0900494 ethPacketIn.setSourceMACAddress(DEFAULT_GATEWAY_MAC);
495 ethPacketIn.setDestinationMACAddress(externalPeerRouter.externalPeerRouterMac());
Hyunsun Moon44aac662017-02-18 02:07:01 +0900496 ethPacketIn.setPayload(iPacket);
daniel park576969a2018-03-09 07:07:41 +0900497
498 if (!externalPeerRouter.externalPeerRouterVlanId().equals(VlanId.NONE)) {
499 ethPacketIn.setVlanID(externalPeerRouter.externalPeerRouterVlanId().toShort());
500 }
501
daniel parkee8700b2017-05-11 15:50:03 +0900502 ethPacketIn.resetChecksum();
Hyunsun Moon44aac662017-02-18 02:07:01 +0900503
Hyunsun Moon0d457362017-06-27 17:19:41 +0900504 OpenstackNode srcNode = osNodeService.node(srcDevice);
505 if (srcNode == null) {
506 final String error = String.format("Cannot find openstack node for %s",
507 srcDevice);
508 throw new IllegalStateException(error);
509 }
daniel parkee8700b2017-05-11 15:50:03 +0900510
daniel park576969a2018-03-09 07:07:41 +0900511 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
512
Hyunsun Moon44aac662017-02-18 02:07:01 +0900513 packetService.emit(new DefaultOutboundPacket(
514 srcDevice,
daniel park576969a2018-03-09 07:07:41 +0900515 tBuilder.setOutput(srcNode.uplinkPortNum()).build(),
Hyunsun Moon44aac662017-02-18 02:07:01 +0900516 ByteBuffer.wrap(ethPacketIn.serialize())));
517 }
518
Hyunsun Moon0e058f22017-04-19 17:00:52 +0900519 private int getPortNum() {
daniel park0bc7fdb2017-03-13 14:20:08 +0900520 if (unUsedPortNumSet.isEmpty()) {
Hyunsun Moon44aac662017-02-18 02:07:01 +0900521 clearPortNumMap();
Hyunsun Moon44aac662017-02-18 02:07:01 +0900522 }
daniel park0bc7fdb2017-03-13 14:20:08 +0900523 int portNum = findUnusedPortNum();
daniel park0bc7fdb2017-03-13 14:20:08 +0900524 if (portNum != 0) {
Hyunsun Moon0e058f22017-04-19 17:00:52 +0900525 unUsedPortNumSet.remove(portNum);
526 allocatedPortNumMap.put(portNum, System.currentTimeMillis());
daniel park0bc7fdb2017-03-13 14:20:08 +0900527 }
Hyunsun Moon44aac662017-02-18 02:07:01 +0900528 return portNum;
529 }
530
531 private int findUnusedPortNum() {
Hyunsun Moon0e058f22017-04-19 17:00:52 +0900532 return unUsedPortNumSet.stream().findAny().orElse(0);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900533 }
534
535 private void clearPortNumMap() {
daniel park0bc7fdb2017-03-13 14:20:08 +0900536 allocatedPortNumMap.entrySet().forEach(e -> {
Hyunsun Moon0e058f22017-04-19 17:00:52 +0900537 if (System.currentTimeMillis() - e.getValue().value() > TIME_OUT_SNAT_PORT_MS) {
daniel park0bc7fdb2017-03-13 14:20:08 +0900538 allocatedPortNumMap.remove(e.getKey());
539 unUsedPortNumSet.add(e.getKey());
Hyunsun Moon44aac662017-02-18 02:07:01 +0900540 }
541 });
542 }
543
544 private class InternalPacketProcessor implements PacketProcessor {
545
546 @Override
547 public void process(PacketContext context) {
Hyunsun Moon0d457362017-06-27 17:19:41 +0900548 Set<DeviceId> gateways = osNodeService.completeNodes(OpenstackNode.NodeType.GATEWAY)
549 .stream().map(OpenstackNode::intgBridge)
550 .collect(Collectors.toSet());
Hyunsun Moon44aac662017-02-18 02:07:01 +0900551 if (context.isHandled()) {
552 return;
Hyunsun Moon0d457362017-06-27 17:19:41 +0900553 } else if (!gateways.contains(context.inPacket().receivedFrom().deviceId())) {
Hyunsun Moon44aac662017-02-18 02:07:01 +0900554 // return if the packet is not from gateway nodes
555 return;
556 }
557
558 InboundPacket pkt = context.inPacket();
559 Ethernet eth = pkt.parsed();
560 if (eth == null || eth.getEtherType() == Ethernet.TYPE_ARP) {
561 return;
562 }
563
564 IPv4 iPacket = (IPv4) eth.getPayload();
565 switch (iPacket.getProtocol()) {
566 case IPv4.PROTOCOL_ICMP:
567 break;
568 case IPv4.PROTOCOL_UDP:
569 UDP udpPacket = (UDP) iPacket.getPayload();
570 if (udpPacket.getDestinationPort() == UDP.DHCP_SERVER_PORT &&
571 udpPacket.getSourcePort() == UDP.DHCP_CLIENT_PORT) {
572 // don't process DHCP
573 break;
574 }
575 default:
576 eventExecutor.execute(() -> processSnatPacket(context, eth));
577 break;
578 }
579 }
580 }
581}