blob: 05b919afa951fd5ad1e9263d60c1801c98ef074e [file] [log] [blame]
Hyunsun Moon44aac662017-02-18 02:07:01 +09001/*
2 * Copyright 2016-present Open Networking Laboratory
3 *
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;
40import org.onosproject.net.flowobjective.DefaultForwardingObjective;
41import org.onosproject.net.flowobjective.FlowObjectiveService;
42import org.onosproject.net.flowobjective.ForwardingObjective;
43import org.onosproject.net.packet.DefaultOutboundPacket;
44import org.onosproject.net.packet.InboundPacket;
45import org.onosproject.net.packet.PacketContext;
46import org.onosproject.net.packet.PacketProcessor;
47import org.onosproject.net.packet.PacketService;
48import org.onosproject.openstacknetworking.api.InstancePort;
49import org.onosproject.openstacknetworking.api.InstancePortService;
50import org.onosproject.openstacknetworking.api.OpenstackRouterService;
51import org.onosproject.openstacknetworking.api.OpenstackNetworkService;
52import org.onosproject.openstacknode.OpenstackNodeService;
Hyunsun Moon44aac662017-02-18 02:07:01 +090053import org.onosproject.store.serializers.KryoNamespaces;
54import org.onosproject.store.service.ConsistentMap;
daniel park0bc7fdb2017-03-13 14:20:08 +090055import org.onosproject.store.service.DistributedSet;
Hyunsun Moon44aac662017-02-18 02:07:01 +090056import org.onosproject.store.service.Serializer;
57import org.onosproject.store.service.StorageService;
58import org.openstack4j.model.network.ExternalGateway;
59import org.openstack4j.model.network.IP;
60import org.openstack4j.model.network.Network;
daniel parkee8700b2017-05-11 15:50:03 +090061import org.openstack4j.model.network.NetworkType;
Hyunsun Moon44aac662017-02-18 02:07:01 +090062import org.openstack4j.model.network.Port;
63import org.openstack4j.model.network.Router;
64import org.openstack4j.model.network.RouterInterface;
65import org.openstack4j.model.network.Subnet;
66import org.slf4j.Logger;
67
68import java.nio.ByteBuffer;
69import java.util.Objects;
70import java.util.concurrent.ExecutorService;
71
72import static java.util.concurrent.Executors.newSingleThreadExecutor;
73import static org.onlab.util.Tools.groupedThreads;
74import static org.onosproject.openstacknetworking.api.Constants.*;
75import static org.slf4j.LoggerFactory.getLogger;
76
77/**
78 * Handle packets needs SNAT.
79 */
80@Component(immediate = true)
81public class OpenstackRoutingSnatHandler {
82
83 private final Logger log = getLogger(getClass());
84
85 private static final String ERR_PACKETIN = "Failed to handle packet in: ";
daniel parkee8700b2017-05-11 15:50:03 +090086 private static final String ERR_UNSUPPORTED_NET_TYPE = "Unsupported network type";
Hyunsun Moon44aac662017-02-18 02:07:01 +090087 private static final int TIME_OUT_SNAT_RULE = 120;
daniel park0bc7fdb2017-03-13 14:20:08 +090088 private static final long TIME_OUT_SNAT_PORT_MS = 120 * 1000;
sangho79d6a832017-05-02 14:53:46 +090089 private static final int TP_PORT_MINIMUM_NUM = 65000;
Hyunsun Moon44aac662017-02-18 02:07:01 +090090 private static final int TP_PORT_MAXIMUM_NUM = 65535;
91
92 private static final KryoNamespace.Builder NUMBER_SERIALIZER = KryoNamespace.newBuilder()
93 .register(KryoNamespaces.API);
94
95 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
96 protected CoreService coreService;
97
98 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
99 protected PacketService packetService;
100
101 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
102 protected StorageService storageService;
103
104 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
105 protected FlowObjectiveService flowObjectiveService;
106
107 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
108 protected DeviceService deviceService;
109
110 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
111 protected InstancePortService instancePortService;
112
113 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
114 protected OpenstackNodeService osNodeService;
115
116 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
117 protected OpenstackNetworkService osNetworkService;
118
119 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
120 protected OpenstackRouterService osRouterService;
121
Hyunsun Moon44aac662017-02-18 02:07:01 +0900122 private final ExecutorService eventExecutor = newSingleThreadExecutor(
123 groupedThreads(this.getClass().getSimpleName(), "event-handler", log));
124 private final InternalPacketProcessor packetProcessor = new InternalPacketProcessor();
125
daniel park0bc7fdb2017-03-13 14:20:08 +0900126 private ConsistentMap<Integer, Long> allocatedPortNumMap;
127 private DistributedSet<Integer> unUsedPortNumSet;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900128 private ApplicationId appId;
129
130 @Activate
131 protected void activate() {
132 appId = coreService.registerApplication(OPENSTACK_NETWORKING_APP_ID);
daniel park0bc7fdb2017-03-13 14:20:08 +0900133
134 allocatedPortNumMap = storageService.<Integer, Long>consistentMapBuilder()
Hyunsun Moon44aac662017-02-18 02:07:01 +0900135 .withSerializer(Serializer.using(NUMBER_SERIALIZER.build()))
daniel park0bc7fdb2017-03-13 14:20:08 +0900136 .withName("openstackrouting-allocatedportnummap")
Hyunsun Moon44aac662017-02-18 02:07:01 +0900137 .withApplicationId(appId)
138 .build();
139
daniel park0bc7fdb2017-03-13 14:20:08 +0900140 unUsedPortNumSet = storageService.<Integer>setBuilder()
141 .withName("openstackrouting-unusedportnumset")
142 .withSerializer(Serializer.using(KryoNamespaces.API))
143 .build()
144 .asDistributedSet();
145
146 initializeUnusedPortNumSet();
147
Hyunsun Moon44aac662017-02-18 02:07:01 +0900148 packetService.addProcessor(packetProcessor, PacketProcessor.director(1));
149 log.info("Started");
150 }
151
daniel park0bc7fdb2017-03-13 14:20:08 +0900152 private void initializeUnusedPortNumSet() {
153 for (int i = TP_PORT_MINIMUM_NUM; i < TP_PORT_MAXIMUM_NUM; i++) {
Hyunsun Moon0e058f22017-04-19 17:00:52 +0900154 if (!allocatedPortNumMap.containsKey(i)) {
155 unUsedPortNumSet.add(i);
daniel park0bc7fdb2017-03-13 14:20:08 +0900156 }
157 }
158
159 clearPortNumMap();
160 }
161
Hyunsun Moon44aac662017-02-18 02:07:01 +0900162 @Deactivate
163 protected void deactivate() {
164 packetService.removeProcessor(packetProcessor);
165 eventExecutor.shutdown();
166 log.info("Stopped");
167 }
168
169 private void processSnatPacket(PacketContext context, Ethernet eth) {
170 IPv4 iPacket = (IPv4) eth.getPayload();
171 InboundPacket packetIn = context.inPacket();
172
Hyunsun Moon0e058f22017-04-19 17:00:52 +0900173 int patPort = getPortNum();
Hyunsun Moon44aac662017-02-18 02:07:01 +0900174
175 InstancePort srcInstPort = instancePortService.instancePort(eth.getSourceMAC());
176 if (srcInstPort == null) {
Hyunsun Moon0e058f22017-04-19 17:00:52 +0900177 log.error(ERR_PACKETIN + "source host(MAC:{}) does not exist",
Hyunsun Moon44aac662017-02-18 02:07:01 +0900178 eth.getSourceMAC());
179 return;
180 }
Hyunsun Moon0e058f22017-04-19 17:00:52 +0900181
Hyunsun Moon44aac662017-02-18 02:07:01 +0900182 IpAddress srcIp = IpAddress.valueOf(iPacket.getSourceAddress());
183 Subnet srcSubnet = getSourceSubnet(srcInstPort, srcIp);
184 IpAddress externalGatewayIp = getExternalIp(srcSubnet);
185 if (externalGatewayIp == null) {
186 return;
187 }
188
189 populateSnatFlowRules(context.inPacket(),
190 srcInstPort,
191 TpPort.tpPort(patPort),
192 externalGatewayIp);
193
194 packetOut((Ethernet) eth.clone(),
195 packetIn.receivedFrom().deviceId(),
196 patPort,
197 externalGatewayIp);
198 }
199
200 private Subnet getSourceSubnet(InstancePort instance, IpAddress srcIp) {
201 Port osPort = osNetworkService.port(instance.portId());
202 IP fixedIp = osPort.getFixedIps().stream()
203 .filter(ip -> IpAddress.valueOf(ip.getIpAddress()).equals(srcIp))
204 .findAny().orElse(null);
205 if (fixedIp == null) {
206 return null;
207 }
208 return osNetworkService.subnet(fixedIp.getSubnetId());
209 }
210
211 private IpAddress getExternalIp(Subnet srcSubnet) {
212 RouterInterface osRouterIface = osRouterService.routerInterfaces().stream()
213 .filter(i -> Objects.equals(i.getSubnetId(), srcSubnet.getId()))
214 .findAny().orElse(null);
215 if (osRouterIface == null) {
216 // this subnet is not connected to the router
217 log.trace(ERR_PACKETIN + "source subnet(ID:{}, CIDR:{}) has no router",
218 srcSubnet.getId(), srcSubnet.getCidr());
219 return null;
220 }
221
222 Router osRouter = osRouterService.router(osRouterIface.getId());
223 if (osRouter.getExternalGatewayInfo() == null) {
224 // this router does not have external connectivity
225 log.trace(ERR_PACKETIN + "router({}) has no external gateway",
226 osRouter.getName());
227 return null;
228 }
229
230 ExternalGateway exGatewayInfo = osRouter.getExternalGatewayInfo();
231 if (!exGatewayInfo.isEnableSnat()) {
232 // SNAT is disabled in this router
233 log.trace(ERR_PACKETIN + "router({}) SNAT is disabled", osRouter.getName());
234 return null;
235 }
236
237 // TODO fix openstack4j for ExternalGateway provides external fixed IP list
238 Port exGatewayPort = osNetworkService.ports(exGatewayInfo.getNetworkId())
239 .stream()
240 .filter(port -> Objects.equals(port.getDeviceId(), osRouter.getId()))
241 .findAny().orElse(null);
242 if (exGatewayPort == null) {
243 log.trace(ERR_PACKETIN + "no external gateway port for router({})",
244 osRouter.getName());
245 return null;
246 }
247
248 return IpAddress.valueOf(exGatewayPort.getFixedIps().stream()
249 .findFirst().get().getIpAddress());
250 }
251
252 private void populateSnatFlowRules(InboundPacket packetIn, InstancePort srcInstPort,
253 TpPort patPort, IpAddress externalIp) {
254 Network osNet = osNetworkService.network(srcInstPort.networkId());
255 if (osNet == null) {
256 final String error = String.format(ERR_PACKETIN + "network %s not found",
257 srcInstPort.networkId());
258 throw new IllegalStateException(error);
259 }
260
261 setDownstreamRules(srcInstPort,
daniel parkee8700b2017-05-11 15:50:03 +0900262 osNet.getProviderSegID(),
263 osNet.getNetworkType(),
Hyunsun Moon44aac662017-02-18 02:07:01 +0900264 externalIp,
265 patPort,
266 packetIn);
267
daniel parkee8700b2017-05-11 15:50:03 +0900268 setUpstreamRules(osNet.getProviderSegID(),
269 osNet.getNetworkType(),
Hyunsun Moon44aac662017-02-18 02:07:01 +0900270 externalIp,
271 patPort,
272 packetIn);
273 }
274
daniel parkee8700b2017-05-11 15:50:03 +0900275 private void setDownstreamRules(InstancePort srcInstPort, String segmentId, NetworkType networkType,
Hyunsun Moon44aac662017-02-18 02:07:01 +0900276 IpAddress externalIp, TpPort patPort,
277 InboundPacket packetIn) {
278 IPv4 iPacket = (IPv4) packetIn.parsed().getPayload();
279 IpAddress internalIp = IpAddress.valueOf(iPacket.getSourceAddress());
280
281 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder()
282 .matchEthType(Ethernet.TYPE_IPV4)
283 .matchIPProtocol(iPacket.getProtocol())
284 .matchIPDst(IpPrefix.valueOf(externalIp, 32))
285 .matchIPSrc(IpPrefix.valueOf(iPacket.getDestinationAddress(), 32));
286
287 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder()
Hyunsun Moon44aac662017-02-18 02:07:01 +0900288 .setEthDst(packetIn.parsed().getSourceMAC())
289 .setIpDst(internalIp);
290
daniel parkee8700b2017-05-11 15:50:03 +0900291 switch (networkType) {
292 case VXLAN:
293 tBuilder.setTunnelId(Long.parseLong(segmentId));
294 break;
295 case VLAN:
296 tBuilder.pushVlan()
297 .setVlanId(VlanId.vlanId(segmentId))
298 .setEthSrc(DEFAULT_GATEWAY_MAC);
299 break;
300 default:
301 final String error = String.format(
302 ERR_UNSUPPORTED_NET_TYPE + "%s",
303 networkType.toString());
304 throw new IllegalStateException(error);
305 }
306
307
Hyunsun Moon44aac662017-02-18 02:07:01 +0900308 switch (iPacket.getProtocol()) {
309 case IPv4.PROTOCOL_TCP:
310 TCP tcpPacket = (TCP) iPacket.getPayload();
311 sBuilder.matchTcpSrc(TpPort.tpPort(tcpPacket.getDestinationPort()))
312 .matchTcpDst(patPort);
313 tBuilder.setTcpDst(TpPort.tpPort(tcpPacket.getSourcePort()));
314 break;
315 case IPv4.PROTOCOL_UDP:
316 UDP udpPacket = (UDP) iPacket.getPayload();
317 sBuilder.matchUdpSrc(TpPort.tpPort(udpPacket.getDestinationPort()))
318 .matchUdpDst(patPort);
319 tBuilder.setUdpDst(TpPort.tpPort(udpPacket.getSourcePort()));
320 break;
321 default:
322 break;
323 }
324
daniel parke49eb382017-04-05 16:48:28 +0900325 osNodeService.gatewayDeviceIds().forEach(deviceId -> {
Hyunsun Moon44aac662017-02-18 02:07:01 +0900326 DeviceId srcDeviceId = srcInstPort.deviceId();
327 TrafficTreatment.Builder tmpBuilder =
328 DefaultTrafficTreatment.builder(tBuilder.build());
daniel parkee8700b2017-05-11 15:50:03 +0900329 switch (networkType) {
330 case VXLAN:
331 tmpBuilder.extension(RulePopulatorUtil.buildExtension(
332 deviceService,
333 deviceId,
334 osNodeService.dataIp(srcDeviceId).get().getIp4Address()), deviceId)
335 .setOutput(osNodeService.tunnelPort(deviceId).get());
336 break;
337 case VLAN:
338 tmpBuilder.setOutput(osNodeService.vlanPort(deviceId).get());
339 break;
340 default:
341 final String error = String.format(
342 ERR_UNSUPPORTED_NET_TYPE + "%s",
343 networkType.toString());
344 throw new IllegalStateException(error);
345 }
Hyunsun Moon44aac662017-02-18 02:07:01 +0900346
347 ForwardingObjective fo = DefaultForwardingObjective.builder()
348 .withSelector(sBuilder.build())
349 .withTreatment(tmpBuilder.build())
350 .withFlag(ForwardingObjective.Flag.VERSATILE)
351 .withPriority(PRIORITY_SNAT_RULE)
352 .makeTemporary(TIME_OUT_SNAT_RULE)
353 .fromApp(appId)
354 .add();
355
356 flowObjectiveService.forward(deviceId, fo);
357 });
358 }
359
daniel parkee8700b2017-05-11 15:50:03 +0900360 private void setUpstreamRules(String segmentId, NetworkType networkType, 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:
381 final String error = String.format(
382 ERR_UNSUPPORTED_NET_TYPE + "%s",
383 networkType.toString());
384 throw new IllegalStateException(error);
385 }
386
Hyunsun Moon44aac662017-02-18 02:07:01 +0900387 switch (iPacket.getProtocol()) {
388 case IPv4.PROTOCOL_TCP:
389 TCP tcpPacket = (TCP) iPacket.getPayload();
390 sBuilder.matchTcpSrc(TpPort.tpPort(tcpPacket.getSourcePort()))
391 .matchTcpDst(TpPort.tpPort(tcpPacket.getDestinationPort()));
392 tBuilder.setTcpSrc(patPort)
393 .setEthDst(DEFAULT_EXTERNAL_ROUTER_MAC);
394 break;
395 case IPv4.PROTOCOL_UDP:
396 UDP udpPacket = (UDP) iPacket.getPayload();
397 sBuilder.matchUdpSrc(TpPort.tpPort(udpPacket.getSourcePort()))
398 .matchUdpDst(TpPort.tpPort(udpPacket.getDestinationPort()));
399 tBuilder.setUdpSrc(patPort)
400 .setEthDst(DEFAULT_EXTERNAL_ROUTER_MAC);
401
402 break;
403 default:
404 log.debug("Unsupported IPv4 protocol {}");
405 break;
406 }
407
408 tBuilder.setIpSrc(externalIp);
daniel parke49eb382017-04-05 16:48:28 +0900409 osNodeService.gatewayDeviceIds().forEach(deviceId -> {
Hyunsun Moon44aac662017-02-18 02:07:01 +0900410 TrafficTreatment.Builder tmpBuilder =
411 DefaultTrafficTreatment.builder(tBuilder.build());
daniel parke49eb382017-04-05 16:48:28 +0900412 tmpBuilder.setOutput(osNodeService.externalPort(deviceId).get());
Hyunsun Moon44aac662017-02-18 02:07:01 +0900413 ForwardingObjective fo = DefaultForwardingObjective.builder()
414 .withSelector(sBuilder.build())
415 .withTreatment(tmpBuilder.build())
416 .withFlag(ForwardingObjective.Flag.VERSATILE)
417 .withPriority(PRIORITY_SNAT_RULE)
418 .makeTemporary(TIME_OUT_SNAT_RULE)
419 .fromApp(appId)
420 .add();
421
422 flowObjectiveService.forward(deviceId, fo);
423 });
424 }
425
426 private void packetOut(Ethernet ethPacketIn, DeviceId srcDevice, int patPort,
427 IpAddress externalIp) {
428 IPv4 iPacket = (IPv4) ethPacketIn.getPayload();
429
430 switch (iPacket.getProtocol()) {
431 case IPv4.PROTOCOL_TCP:
432 TCP tcpPacket = (TCP) iPacket.getPayload();
433 tcpPacket.setSourcePort(patPort);
434 tcpPacket.resetChecksum();
435 tcpPacket.setParent(iPacket);
436 iPacket.setPayload(tcpPacket);
437 break;
438 case IPv4.PROTOCOL_UDP:
439 UDP udpPacket = (UDP) iPacket.getPayload();
440 udpPacket.setSourcePort(patPort);
441 udpPacket.resetChecksum();
442 udpPacket.setParent(iPacket);
443 iPacket.setPayload(udpPacket);
444 break;
445 default:
446 log.trace("Temporally, this method can process UDP and TCP protocol.");
447 return;
448 }
449
450 iPacket.setSourceAddress(externalIp.toString());
451 iPacket.resetChecksum();
452 iPacket.setParent(ethPacketIn);
453 ethPacketIn.setDestinationMACAddress(DEFAULT_EXTERNAL_ROUTER_MAC);
454 ethPacketIn.setPayload(iPacket);
daniel parkee8700b2017-05-11 15:50:03 +0900455 ethPacketIn.resetChecksum();
Hyunsun Moon44aac662017-02-18 02:07:01 +0900456
457 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
daniel parkee8700b2017-05-11 15:50:03 +0900458 .setOutput(osNodeService.externalPort(srcDevice).get()).build();
459
Hyunsun Moon44aac662017-02-18 02:07:01 +0900460 packetService.emit(new DefaultOutboundPacket(
461 srcDevice,
462 treatment,
463 ByteBuffer.wrap(ethPacketIn.serialize())));
464 }
465
Hyunsun Moon0e058f22017-04-19 17:00:52 +0900466 private int getPortNum() {
daniel park0bc7fdb2017-03-13 14:20:08 +0900467 if (unUsedPortNumSet.isEmpty()) {
Hyunsun Moon44aac662017-02-18 02:07:01 +0900468 clearPortNumMap();
Hyunsun Moon44aac662017-02-18 02:07:01 +0900469 }
daniel park0bc7fdb2017-03-13 14:20:08 +0900470
471 int portNum = findUnusedPortNum();
daniel park0bc7fdb2017-03-13 14:20:08 +0900472 if (portNum != 0) {
Hyunsun Moon0e058f22017-04-19 17:00:52 +0900473 unUsedPortNumSet.remove(portNum);
474 allocatedPortNumMap.put(portNum, System.currentTimeMillis());
daniel park0bc7fdb2017-03-13 14:20:08 +0900475 }
476
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) {
497 if (context.isHandled()) {
498 return;
daniel parke49eb382017-04-05 16:48:28 +0900499 } else if (!osNodeService.gatewayDeviceIds().contains(
Hyunsun Moon44aac662017-02-18 02:07:01 +0900500 context.inPacket().receivedFrom().deviceId())) {
501 // return if the packet is not from gateway nodes
502 return;
503 }
504
505 InboundPacket pkt = context.inPacket();
506 Ethernet eth = pkt.parsed();
507 if (eth == null || eth.getEtherType() == Ethernet.TYPE_ARP) {
508 return;
509 }
510
511 IPv4 iPacket = (IPv4) eth.getPayload();
512 switch (iPacket.getProtocol()) {
513 case IPv4.PROTOCOL_ICMP:
514 break;
515 case IPv4.PROTOCOL_UDP:
516 UDP udpPacket = (UDP) iPacket.getPayload();
517 if (udpPacket.getDestinationPort() == UDP.DHCP_SERVER_PORT &&
518 udpPacket.getSourcePort() == UDP.DHCP_CLIENT_PORT) {
519 // don't process DHCP
520 break;
521 }
522 default:
523 eventExecutor.execute(() -> processSnatPacket(context, eth));
524 break;
525 }
526 }
527 }
528}