blob: bfb07014317c2c3a368be7923fd7ef0fc8d835de [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;
45import org.onosproject.openstacknetworking.api.InstancePort;
46import org.onosproject.openstacknetworking.api.InstancePortService;
sanghodc375372017-06-08 10:41:30 +090047import org.onosproject.openstacknetworking.api.OpenstackFlowRuleService;
Hyunsun Moon44aac662017-02-18 02:07:01 +090048import org.onosproject.openstacknetworking.api.OpenstackNetworkService;
sanghodc375372017-06-08 10:41:30 +090049import org.onosproject.openstacknetworking.api.OpenstackRouterService;
Hyunsun Moon0d457362017-06-27 17:19:41 +090050import org.onosproject.openstacknode.api.OpenstackNode;
51import org.onosproject.openstacknode.api.OpenstackNodeService;
Hyunsun Moon44aac662017-02-18 02:07:01 +090052import org.onosproject.store.serializers.KryoNamespaces;
53import org.onosproject.store.service.ConsistentMap;
daniel park0bc7fdb2017-03-13 14:20:08 +090054import org.onosproject.store.service.DistributedSet;
Hyunsun Moon44aac662017-02-18 02:07:01 +090055import org.onosproject.store.service.Serializer;
56import org.onosproject.store.service.StorageService;
57import org.openstack4j.model.network.ExternalGateway;
58import org.openstack4j.model.network.IP;
59import org.openstack4j.model.network.Network;
daniel parkee8700b2017-05-11 15:50:03 +090060import org.openstack4j.model.network.NetworkType;
Hyunsun Moon44aac662017-02-18 02:07:01 +090061import org.openstack4j.model.network.Port;
62import org.openstack4j.model.network.Router;
63import org.openstack4j.model.network.RouterInterface;
64import org.openstack4j.model.network.Subnet;
65import org.slf4j.Logger;
66
67import java.nio.ByteBuffer;
68import java.util.Objects;
Hyunsun Moon0d457362017-06-27 17:19:41 +090069import java.util.Set;
Hyunsun Moon44aac662017-02-18 02:07:01 +090070import java.util.concurrent.ExecutorService;
Hyunsun Moon0d457362017-06-27 17:19:41 +090071import java.util.stream.Collectors;
Hyunsun Moon44aac662017-02-18 02:07:01 +090072
73import static java.util.concurrent.Executors.newSingleThreadExecutor;
74import static org.onlab.util.Tools.groupedThreads;
Hyunsun Moon0d457362017-06-27 17:19:41 +090075import static org.onosproject.openstacknetworking.api.Constants.*;
76import static org.onosproject.openstacknode.api.OpenstackNode.NodeType.GATEWAY;
Hyunsun Moon44aac662017-02-18 02:07:01 +090077import static org.slf4j.LoggerFactory.getLogger;
78
79/**
80 * Handle packets needs SNAT.
81 */
82@Component(immediate = true)
83public class OpenstackRoutingSnatHandler {
84
85 private final Logger log = getLogger(getClass());
86
87 private static final String ERR_PACKETIN = "Failed to handle packet in: ";
daniel parkee8700b2017-05-11 15:50:03 +090088 private static final String ERR_UNSUPPORTED_NET_TYPE = "Unsupported network type";
daniel park0bc7fdb2017-03-13 14:20:08 +090089 private static final long TIME_OUT_SNAT_PORT_MS = 120 * 1000;
sangho79d6a832017-05-02 14:53:46 +090090 private static final int TP_PORT_MINIMUM_NUM = 65000;
Hyunsun Moon44aac662017-02-18 02:07:01 +090091 private static final int TP_PORT_MAXIMUM_NUM = 65535;
92
93 private static final KryoNamespace.Builder NUMBER_SERIALIZER = KryoNamespace.newBuilder()
94 .register(KryoNamespaces.API);
95
96 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
97 protected CoreService coreService;
98
99 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
100 protected PacketService packetService;
101
102 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
103 protected StorageService storageService;
104
105 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Hyunsun Moon44aac662017-02-18 02:07:01 +0900106 protected DeviceService deviceService;
107
108 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
109 protected InstancePortService instancePortService;
110
111 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
112 protected OpenstackNodeService osNodeService;
113
114 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
115 protected OpenstackNetworkService osNetworkService;
116
117 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
118 protected OpenstackRouterService osRouterService;
119
sanghodc375372017-06-08 10:41:30 +0900120 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
121 protected OpenstackFlowRuleService osFlowRuleService;
122
Hyunsun Moon44aac662017-02-18 02:07:01 +0900123 private final ExecutorService eventExecutor = newSingleThreadExecutor(
124 groupedThreads(this.getClass().getSimpleName(), "event-handler", log));
Hyunsun Moon0d457362017-06-27 17:19:41 +0900125 private final PacketProcessor packetProcessor = new InternalPacketProcessor();
Hyunsun Moon44aac662017-02-18 02:07:01 +0900126
daniel park0bc7fdb2017-03-13 14:20:08 +0900127 private ConsistentMap<Integer, Long> allocatedPortNumMap;
128 private DistributedSet<Integer> unUsedPortNumSet;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900129 private ApplicationId appId;
130
131 @Activate
132 protected void activate() {
133 appId = coreService.registerApplication(OPENSTACK_NETWORKING_APP_ID);
daniel park0bc7fdb2017-03-13 14:20:08 +0900134
135 allocatedPortNumMap = storageService.<Integer, Long>consistentMapBuilder()
Hyunsun Moon44aac662017-02-18 02:07:01 +0900136 .withSerializer(Serializer.using(NUMBER_SERIALIZER.build()))
daniel park0bc7fdb2017-03-13 14:20:08 +0900137 .withName("openstackrouting-allocatedportnummap")
Hyunsun Moon44aac662017-02-18 02:07:01 +0900138 .withApplicationId(appId)
139 .build();
140
daniel park0bc7fdb2017-03-13 14:20:08 +0900141 unUsedPortNumSet = storageService.<Integer>setBuilder()
142 .withName("openstackrouting-unusedportnumset")
143 .withSerializer(Serializer.using(KryoNamespaces.API))
144 .build()
145 .asDistributedSet();
146
147 initializeUnusedPortNumSet();
148
Hyunsun Moon44aac662017-02-18 02:07:01 +0900149 packetService.addProcessor(packetProcessor, PacketProcessor.director(1));
150 log.info("Started");
151 }
152
daniel park0bc7fdb2017-03-13 14:20:08 +0900153 private void initializeUnusedPortNumSet() {
154 for (int i = TP_PORT_MINIMUM_NUM; i < TP_PORT_MAXIMUM_NUM; i++) {
Hyunsun Moon0e058f22017-04-19 17:00:52 +0900155 if (!allocatedPortNumMap.containsKey(i)) {
156 unUsedPortNumSet.add(i);
daniel park0bc7fdb2017-03-13 14:20:08 +0900157 }
158 }
159
160 clearPortNumMap();
161 }
162
Hyunsun Moon44aac662017-02-18 02:07:01 +0900163 @Deactivate
164 protected void deactivate() {
165 packetService.removeProcessor(packetProcessor);
166 eventExecutor.shutdown();
167 log.info("Stopped");
168 }
169
170 private void processSnatPacket(PacketContext context, Ethernet eth) {
171 IPv4 iPacket = (IPv4) eth.getPayload();
172 InboundPacket packetIn = context.inPacket();
173
Hyunsun Moon0e058f22017-04-19 17:00:52 +0900174 int patPort = getPortNum();
Hyunsun Moon44aac662017-02-18 02:07:01 +0900175
176 InstancePort srcInstPort = instancePortService.instancePort(eth.getSourceMAC());
177 if (srcInstPort == null) {
Hyunsun Moon0e058f22017-04-19 17:00:52 +0900178 log.error(ERR_PACKETIN + "source host(MAC:{}) does not exist",
Hyunsun Moon44aac662017-02-18 02:07:01 +0900179 eth.getSourceMAC());
180 return;
181 }
Hyunsun Moon0e058f22017-04-19 17:00:52 +0900182
Hyunsun Moon44aac662017-02-18 02:07:01 +0900183 IpAddress srcIp = IpAddress.valueOf(iPacket.getSourceAddress());
184 Subnet srcSubnet = getSourceSubnet(srcInstPort, srcIp);
185 IpAddress externalGatewayIp = getExternalIp(srcSubnet);
186 if (externalGatewayIp == null) {
187 return;
188 }
189
190 populateSnatFlowRules(context.inPacket(),
191 srcInstPort,
192 TpPort.tpPort(patPort),
193 externalGatewayIp);
194
195 packetOut((Ethernet) eth.clone(),
196 packetIn.receivedFrom().deviceId(),
197 patPort,
198 externalGatewayIp);
199 }
200
201 private Subnet getSourceSubnet(InstancePort instance, IpAddress srcIp) {
202 Port osPort = osNetworkService.port(instance.portId());
203 IP fixedIp = osPort.getFixedIps().stream()
204 .filter(ip -> IpAddress.valueOf(ip.getIpAddress()).equals(srcIp))
205 .findAny().orElse(null);
206 if (fixedIp == null) {
207 return null;
208 }
209 return osNetworkService.subnet(fixedIp.getSubnetId());
210 }
211
212 private IpAddress getExternalIp(Subnet srcSubnet) {
213 RouterInterface osRouterIface = osRouterService.routerInterfaces().stream()
214 .filter(i -> Objects.equals(i.getSubnetId(), srcSubnet.getId()))
215 .findAny().orElse(null);
216 if (osRouterIface == null) {
217 // this subnet is not connected to the router
218 log.trace(ERR_PACKETIN + "source subnet(ID:{}, CIDR:{}) has no router",
219 srcSubnet.getId(), srcSubnet.getCidr());
220 return null;
221 }
222
223 Router osRouter = osRouterService.router(osRouterIface.getId());
224 if (osRouter.getExternalGatewayInfo() == null) {
225 // this router does not have external connectivity
226 log.trace(ERR_PACKETIN + "router({}) has no external gateway",
227 osRouter.getName());
228 return null;
229 }
230
231 ExternalGateway exGatewayInfo = osRouter.getExternalGatewayInfo();
232 if (!exGatewayInfo.isEnableSnat()) {
233 // SNAT is disabled in this router
234 log.trace(ERR_PACKETIN + "router({}) SNAT is disabled", osRouter.getName());
235 return null;
236 }
237
238 // TODO fix openstack4j for ExternalGateway provides external fixed IP list
239 Port exGatewayPort = osNetworkService.ports(exGatewayInfo.getNetworkId())
240 .stream()
241 .filter(port -> Objects.equals(port.getDeviceId(), osRouter.getId()))
242 .findAny().orElse(null);
243 if (exGatewayPort == null) {
244 log.trace(ERR_PACKETIN + "no external gateway port for router({})",
245 osRouter.getName());
246 return null;
247 }
248
249 return IpAddress.valueOf(exGatewayPort.getFixedIps().stream()
250 .findFirst().get().getIpAddress());
251 }
252
253 private void populateSnatFlowRules(InboundPacket packetIn, InstancePort srcInstPort,
254 TpPort patPort, IpAddress externalIp) {
255 Network osNet = osNetworkService.network(srcInstPort.networkId());
256 if (osNet == null) {
257 final String error = String.format(ERR_PACKETIN + "network %s not found",
258 srcInstPort.networkId());
259 throw new IllegalStateException(error);
260 }
261
262 setDownstreamRules(srcInstPort,
daniel parkee8700b2017-05-11 15:50:03 +0900263 osNet.getProviderSegID(),
264 osNet.getNetworkType(),
Hyunsun Moon44aac662017-02-18 02:07:01 +0900265 externalIp,
266 patPort,
267 packetIn);
268
daniel parkee8700b2017-05-11 15:50:03 +0900269 setUpstreamRules(osNet.getProviderSegID(),
270 osNet.getNetworkType(),
Hyunsun Moon44aac662017-02-18 02:07:01 +0900271 externalIp,
272 patPort,
273 packetIn);
274 }
275
Hyunsun Moon0d457362017-06-27 17:19:41 +0900276 private void setDownstreamRules(InstancePort srcInstPort, String segmentId,
277 NetworkType networkType,
Hyunsun Moon44aac662017-02-18 02:07:01 +0900278 IpAddress externalIp, TpPort patPort,
279 InboundPacket packetIn) {
280 IPv4 iPacket = (IPv4) packetIn.parsed().getPayload();
281 IpAddress internalIp = IpAddress.valueOf(iPacket.getSourceAddress());
282
283 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder()
284 .matchEthType(Ethernet.TYPE_IPV4)
285 .matchIPProtocol(iPacket.getProtocol())
Hyunsun Moon0d457362017-06-27 17:19:41 +0900286 .matchIPDst(IpPrefix.valueOf(externalIp.getIp4Address(), 32))
Hyunsun Moon44aac662017-02-18 02:07:01 +0900287 .matchIPSrc(IpPrefix.valueOf(iPacket.getDestinationAddress(), 32));
288
289 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder()
Hyunsun Moon44aac662017-02-18 02:07:01 +0900290 .setEthDst(packetIn.parsed().getSourceMAC())
291 .setIpDst(internalIp);
292
daniel parkee8700b2017-05-11 15:50:03 +0900293 switch (networkType) {
294 case VXLAN:
295 tBuilder.setTunnelId(Long.parseLong(segmentId));
296 break;
297 case VLAN:
298 tBuilder.pushVlan()
299 .setVlanId(VlanId.vlanId(segmentId))
300 .setEthSrc(DEFAULT_GATEWAY_MAC);
301 break;
302 default:
303 final String error = String.format(
304 ERR_UNSUPPORTED_NET_TYPE + "%s",
305 networkType.toString());
306 throw new IllegalStateException(error);
307 }
308
309
Hyunsun Moon44aac662017-02-18 02:07:01 +0900310 switch (iPacket.getProtocol()) {
311 case IPv4.PROTOCOL_TCP:
312 TCP tcpPacket = (TCP) iPacket.getPayload();
313 sBuilder.matchTcpSrc(TpPort.tpPort(tcpPacket.getDestinationPort()))
314 .matchTcpDst(patPort);
315 tBuilder.setTcpDst(TpPort.tpPort(tcpPacket.getSourcePort()));
316 break;
317 case IPv4.PROTOCOL_UDP:
318 UDP udpPacket = (UDP) iPacket.getPayload();
319 sBuilder.matchUdpSrc(TpPort.tpPort(udpPacket.getDestinationPort()))
320 .matchUdpDst(patPort);
321 tBuilder.setUdpDst(TpPort.tpPort(udpPacket.getSourcePort()));
322 break;
323 default:
324 break;
325 }
326
Hyunsun Moon0d457362017-06-27 17:19:41 +0900327 OpenstackNode srcNode = osNodeService.node(srcInstPort.deviceId());
328 osNodeService.completeNodes(GATEWAY).forEach(gNode -> {
Hyunsun Moon44aac662017-02-18 02:07:01 +0900329 TrafficTreatment.Builder tmpBuilder =
330 DefaultTrafficTreatment.builder(tBuilder.build());
daniel parkee8700b2017-05-11 15:50:03 +0900331 switch (networkType) {
332 case VXLAN:
333 tmpBuilder.extension(RulePopulatorUtil.buildExtension(
334 deviceService,
Hyunsun Moon0d457362017-06-27 17:19:41 +0900335 gNode.intgBridge(),
336 srcNode.dataIp().getIp4Address()), gNode.intgBridge())
337 .setOutput(gNode.tunnelPortNum());
daniel parkee8700b2017-05-11 15:50:03 +0900338 break;
339 case VLAN:
Hyunsun Moon0d457362017-06-27 17:19:41 +0900340 tmpBuilder.setOutput(gNode.vlanPortNum());
daniel parkee8700b2017-05-11 15:50:03 +0900341 break;
342 default:
Hyunsun Moon0d457362017-06-27 17:19:41 +0900343 final String error = String.format(ERR_UNSUPPORTED_NET_TYPE + "%s",
daniel parkee8700b2017-05-11 15:50:03 +0900344 networkType.toString());
345 throw new IllegalStateException(error);
346 }
Hyunsun Moon44aac662017-02-18 02:07:01 +0900347
sanghodc375372017-06-08 10:41:30 +0900348 osFlowRuleService.setRule(
349 appId,
Hyunsun Moon0d457362017-06-27 17:19:41 +0900350 gNode.intgBridge(),
sanghodc375372017-06-08 10:41:30 +0900351 sBuilder.build(),
352 tmpBuilder.build(),
353 PRIORITY_SNAT_RULE,
354 GW_COMMON_TABLE,
355 true);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900356 });
357 }
358
Hyunsun Moon0d457362017-06-27 17:19:41 +0900359 private void setUpstreamRules(String segmentId, NetworkType networkType,
360 IpAddress externalIp, TpPort patPort,
Hyunsun Moon44aac662017-02-18 02:07:01 +0900361 InboundPacket packetIn) {
362 IPv4 iPacket = (IPv4) packetIn.parsed().getPayload();
daniel parkee8700b2017-05-11 15:50:03 +0900363
364 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder()
Hyunsun Moon44aac662017-02-18 02:07:01 +0900365 .matchEthType(Ethernet.TYPE_IPV4)
366 .matchIPProtocol(iPacket.getProtocol())
Hyunsun Moon44aac662017-02-18 02:07:01 +0900367 .matchIPSrc(IpPrefix.valueOf(iPacket.getSourceAddress(), 32))
368 .matchIPDst(IpPrefix.valueOf(iPacket.getDestinationAddress(), 32));
369
370 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
daniel parkee8700b2017-05-11 15:50:03 +0900371
372 switch (networkType) {
373 case VXLAN:
374 sBuilder.matchTunnelId(Long.parseLong(segmentId));
375 break;
376 case VLAN:
377 sBuilder.matchVlanId(VlanId.vlanId(segmentId));
378 tBuilder.popVlan();
379 break;
380 default:
Hyunsun Moon0d457362017-06-27 17:19:41 +0900381 final String error = String.format(ERR_UNSUPPORTED_NET_TYPE + "%s",
daniel parkee8700b2017-05-11 15:50:03 +0900382 networkType.toString());
383 throw new IllegalStateException(error);
384 }
385
Hyunsun Moon44aac662017-02-18 02:07:01 +0900386 switch (iPacket.getProtocol()) {
387 case IPv4.PROTOCOL_TCP:
388 TCP tcpPacket = (TCP) iPacket.getPayload();
389 sBuilder.matchTcpSrc(TpPort.tpPort(tcpPacket.getSourcePort()))
390 .matchTcpDst(TpPort.tpPort(tcpPacket.getDestinationPort()));
391 tBuilder.setTcpSrc(patPort)
392 .setEthDst(DEFAULT_EXTERNAL_ROUTER_MAC);
393 break;
394 case IPv4.PROTOCOL_UDP:
395 UDP udpPacket = (UDP) iPacket.getPayload();
396 sBuilder.matchUdpSrc(TpPort.tpPort(udpPacket.getSourcePort()))
397 .matchUdpDst(TpPort.tpPort(udpPacket.getDestinationPort()));
398 tBuilder.setUdpSrc(patPort)
399 .setEthDst(DEFAULT_EXTERNAL_ROUTER_MAC);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900400 break;
401 default:
402 log.debug("Unsupported IPv4 protocol {}");
403 break;
404 }
405
406 tBuilder.setIpSrc(externalIp);
Hyunsun Moon0d457362017-06-27 17:19:41 +0900407 osNodeService.completeNodes(GATEWAY).forEach(gNode -> {
Hyunsun Moon44aac662017-02-18 02:07:01 +0900408 TrafficTreatment.Builder tmpBuilder =
409 DefaultTrafficTreatment.builder(tBuilder.build());
Hyunsun Moon0d457362017-06-27 17:19:41 +0900410 tmpBuilder.setOutput(gNode.patchPortNum());
Hyunsun Moon44aac662017-02-18 02:07:01 +0900411
sanghodc375372017-06-08 10:41:30 +0900412 osFlowRuleService.setRule(
413 appId,
Hyunsun Moon0d457362017-06-27 17:19:41 +0900414 gNode.intgBridge(),
sanghodc375372017-06-08 10:41:30 +0900415 sBuilder.build(),
416 tmpBuilder.build(),
417 PRIORITY_SNAT_RULE,
418 GW_COMMON_TABLE,
419 true);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900420 });
421 }
422
423 private void packetOut(Ethernet ethPacketIn, DeviceId srcDevice, int patPort,
424 IpAddress externalIp) {
425 IPv4 iPacket = (IPv4) ethPacketIn.getPayload();
Hyunsun Moon44aac662017-02-18 02:07:01 +0900426 switch (iPacket.getProtocol()) {
427 case IPv4.PROTOCOL_TCP:
428 TCP tcpPacket = (TCP) iPacket.getPayload();
429 tcpPacket.setSourcePort(patPort);
430 tcpPacket.resetChecksum();
431 tcpPacket.setParent(iPacket);
432 iPacket.setPayload(tcpPacket);
433 break;
434 case IPv4.PROTOCOL_UDP:
435 UDP udpPacket = (UDP) iPacket.getPayload();
436 udpPacket.setSourcePort(patPort);
437 udpPacket.resetChecksum();
438 udpPacket.setParent(iPacket);
439 iPacket.setPayload(udpPacket);
440 break;
441 default:
442 log.trace("Temporally, this method can process UDP and TCP protocol.");
443 return;
444 }
445
446 iPacket.setSourceAddress(externalIp.toString());
447 iPacket.resetChecksum();
448 iPacket.setParent(ethPacketIn);
449 ethPacketIn.setDestinationMACAddress(DEFAULT_EXTERNAL_ROUTER_MAC);
450 ethPacketIn.setPayload(iPacket);
daniel parkee8700b2017-05-11 15:50:03 +0900451 ethPacketIn.resetChecksum();
Hyunsun Moon44aac662017-02-18 02:07:01 +0900452
Hyunsun Moon0d457362017-06-27 17:19:41 +0900453 OpenstackNode srcNode = osNodeService.node(srcDevice);
454 if (srcNode == null) {
455 final String error = String.format("Cannot find openstack node for %s",
456 srcDevice);
457 throw new IllegalStateException(error);
458 }
daniel parkee8700b2017-05-11 15:50:03 +0900459
Hyunsun Moon0d457362017-06-27 17:19:41 +0900460 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
461 .setOutput(srcNode.patchPortNum()).build();
Hyunsun Moon44aac662017-02-18 02:07:01 +0900462 packetService.emit(new DefaultOutboundPacket(
463 srcDevice,
464 treatment,
465 ByteBuffer.wrap(ethPacketIn.serialize())));
466 }
467
Hyunsun Moon0e058f22017-04-19 17:00:52 +0900468 private int getPortNum() {
daniel park0bc7fdb2017-03-13 14:20:08 +0900469 if (unUsedPortNumSet.isEmpty()) {
Hyunsun Moon44aac662017-02-18 02:07:01 +0900470 clearPortNumMap();
Hyunsun Moon44aac662017-02-18 02:07:01 +0900471 }
daniel park0bc7fdb2017-03-13 14:20:08 +0900472 int portNum = findUnusedPortNum();
daniel park0bc7fdb2017-03-13 14:20:08 +0900473 if (portNum != 0) {
Hyunsun Moon0e058f22017-04-19 17:00:52 +0900474 unUsedPortNumSet.remove(portNum);
475 allocatedPortNumMap.put(portNum, System.currentTimeMillis());
daniel park0bc7fdb2017-03-13 14:20:08 +0900476 }
Hyunsun Moon44aac662017-02-18 02:07:01 +0900477 return portNum;
478 }
479
480 private int findUnusedPortNum() {
Hyunsun Moon0e058f22017-04-19 17:00:52 +0900481 return unUsedPortNumSet.stream().findAny().orElse(0);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900482 }
483
484 private void clearPortNumMap() {
daniel park0bc7fdb2017-03-13 14:20:08 +0900485 allocatedPortNumMap.entrySet().forEach(e -> {
Hyunsun Moon0e058f22017-04-19 17:00:52 +0900486 if (System.currentTimeMillis() - e.getValue().value() > TIME_OUT_SNAT_PORT_MS) {
daniel park0bc7fdb2017-03-13 14:20:08 +0900487 allocatedPortNumMap.remove(e.getKey());
488 unUsedPortNumSet.add(e.getKey());
Hyunsun Moon44aac662017-02-18 02:07:01 +0900489 }
490 });
491 }
492
493 private class InternalPacketProcessor implements PacketProcessor {
494
495 @Override
496 public void process(PacketContext context) {
Hyunsun Moon0d457362017-06-27 17:19:41 +0900497 Set<DeviceId> gateways = osNodeService.completeNodes(OpenstackNode.NodeType.GATEWAY)
498 .stream().map(OpenstackNode::intgBridge)
499 .collect(Collectors.toSet());
Hyunsun Moon44aac662017-02-18 02:07:01 +0900500 if (context.isHandled()) {
501 return;
Hyunsun Moon0d457362017-06-27 17:19:41 +0900502 } else if (!gateways.contains(context.inPacket().receivedFrom().deviceId())) {
Hyunsun Moon44aac662017-02-18 02:07:01 +0900503 // return if the packet is not from gateway nodes
504 return;
505 }
506
507 InboundPacket pkt = context.inPacket();
508 Ethernet eth = pkt.parsed();
509 if (eth == null || eth.getEtherType() == Ethernet.TYPE_ARP) {
510 return;
511 }
512
513 IPv4 iPacket = (IPv4) eth.getPayload();
514 switch (iPacket.getProtocol()) {
515 case IPv4.PROTOCOL_ICMP:
516 break;
517 case IPv4.PROTOCOL_UDP:
518 UDP udpPacket = (UDP) iPacket.getPayload();
519 if (udpPacket.getDestinationPort() == UDP.DHCP_SERVER_PORT &&
520 udpPacket.getSourcePort() == UDP.DHCP_CLIENT_PORT) {
521 // don't process DHCP
522 break;
523 }
524 default:
525 eventExecutor.execute(() -> processSnatPacket(context, eth));
526 break;
527 }
528 }
529 }
530}