natservice dead code removal
[netvirt.git] / natservice / impl / src / main / java / org / opendaylight / netvirt / natservice / internal / NaptPacketInHandler.java
1 /*
2  * Copyright (c) 2016, 2018 Ericsson India Global Services Pvt Ltd. and others.  All rights reserved.
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6  * and is available at http://www.eclipse.org/legal/epl-v10.html
7  */
8 package org.opendaylight.netvirt.natservice.internal;
9
10 import com.google.common.primitives.Ints;
11 import java.math.BigInteger;
12 import java.util.concurrent.ConcurrentHashMap;
13 import java.util.concurrent.ConcurrentMap;
14 import java.util.concurrent.ExecutorService;
15 import java.util.concurrent.ThreadPoolExecutor;
16 import javax.annotation.PreDestroy;
17 import javax.inject.Inject;
18 import javax.inject.Singleton;
19 import org.opendaylight.genius.mdsalutil.MetaDataUtil;
20 import org.opendaylight.genius.mdsalutil.NWUtil;
21 import org.opendaylight.genius.mdsalutil.NwConstants;
22 import org.opendaylight.genius.mdsalutil.packet.Ethernet;
23 import org.opendaylight.genius.mdsalutil.packet.IPv4;
24 import org.opendaylight.genius.mdsalutil.packet.TCP;
25 import org.opendaylight.genius.mdsalutil.packet.UDP;
26 import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.PacketProcessingListener;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.PacketReceived;
28 import org.opendaylight.yangtools.util.concurrent.SpecialExecutors;
29 import org.slf4j.Logger;
30 import org.slf4j.LoggerFactory;
31
32 @Singleton
33 public class NaptPacketInHandler implements PacketProcessingListener {
34
35     private static final Logger LOG = LoggerFactory.getLogger(NaptPacketInHandler.class);
36     private static final ConcurrentMap<String,NatPacketProcessingState> INCOMING_PKT_MAP = new ConcurrentHashMap<>();
37     private final NaptEventHandler naptEventHandler;
38     private final ExecutorService firstPacketExecutorService = SpecialExecutors.newBlockingBoundedFastThreadPool(
39             NatConstants.SNAT_PACKET_THEADPOOL_SIZE, Integer.MAX_VALUE, "Napt-firstPacket", NaptPacketInHandler.class);
40     private final ExecutorService retryPacketExecutorService = SpecialExecutors.newBlockingBoundedFastThreadPool(
41             NatConstants.SNAT_PACKET_RETRY_THEADPOOL_SIZE, Integer.MAX_VALUE, "Napt-retryPacket",
42             NaptPacketInHandler.class);
43
44     @Inject
45     public NaptPacketInHandler(NaptEventHandler naptEventHandler) {
46         this.naptEventHandler = naptEventHandler;
47     }
48
49     @PreDestroy
50     public void close() {
51         firstPacketExecutorService.shutdown();
52         retryPacketExecutorService.shutdown();
53     }
54
55     @Override
56     // TODO Clean up the exception handling
57     @SuppressWarnings("checkstyle:IllegalCatch")
58     public void onPacketReceived(PacketReceived packetReceived) {
59         String internalIPAddress = "";
60         int portNumber = 0;
61         long routerId = 0L;
62         NAPTEntryEvent.Operation operation = NAPTEntryEvent.Operation.ADD;
63         NAPTEntryEvent.Protocol protocol;
64
65         Short tableId = packetReceived.getTableId().getValue();
66
67         LOG.trace("onPacketReceived : packet: {}, tableId {}", packetReceived, tableId);
68
69         if (tableId == NwConstants.OUTBOUND_NAPT_TABLE) {
70             LOG.debug("onPacketReceived : NAPTPacketInHandler Packet for Outbound NAPT Table");
71             byte[] inPayload = packetReceived.getPayload();
72             Ethernet ethPkt = new Ethernet();
73             if (inPayload != null) {
74                 try {
75                     ethPkt.deserialize(inPayload, 0, inPayload.length * Byte.SIZE);
76                 } catch (Exception e) {
77                     LOG.warn("onPacketReceived: Failed to decode Packet", e);
78                     return;
79                 }
80                 if (ethPkt.getPayload() instanceof IPv4) {
81                     IPv4 ipPkt = (IPv4) ethPkt.getPayload();
82                     byte[] ipSrc = Ints.toByteArray(ipPkt.getSourceAddress());
83
84                     internalIPAddress = NWUtil.toStringIpAddress(ipSrc);
85                     LOG.trace("onPacketReceived : Retrieved internalIPAddress {}", internalIPAddress);
86                     if (ipPkt.getPayload() instanceof TCP) {
87                         TCP tcpPkt = (TCP) ipPkt.getPayload();
88                         portNumber = tcpPkt.getSourcePort();
89                         if (portNumber < 0) {
90                             portNumber = 32767 + portNumber + 32767 + 2;
91                             LOG.trace("onPacketReceived : Retrieved and extracted TCP portNumber {}", portNumber);
92                         }
93                         protocol = NAPTEntryEvent.Protocol.TCP;
94                         LOG.trace("onPacketReceived : Retrieved TCP portNumber {}", portNumber);
95                     } else if (ipPkt.getPayload() instanceof UDP) {
96                         UDP udpPkt = (UDP) ipPkt.getPayload();
97                         portNumber = udpPkt.getSourcePort();
98                         if (portNumber < 0) {
99                             portNumber = 32767 + portNumber + 32767 + 2;
100                             LOG.trace("onPacketReceived : Retrieved and extracted UDP portNumber {}", portNumber);
101                         }
102                         protocol = NAPTEntryEvent.Protocol.UDP;
103                         LOG.trace("onPacketReceived : Retrieved UDP portNumber {}", portNumber);
104                     } else {
105                         LOG.error("onPacketReceived : Incoming Packet is neither TCP or UDP packet");
106                         return;
107                     }
108                 } else {
109                     LOG.error("onPacketReceived : Incoming Packet is not IPv4 packet");
110                     return;
111                 }
112
113                 if (internalIPAddress != null) {
114                     BigInteger metadata = packetReceived.getMatch().getMetadata().getMetadata();
115                     routerId = MetaDataUtil.getNatRouterIdFromMetadata(metadata);
116                     if (routerId <= 0) {
117                         LOG.error("onPacketReceived : Router ID is invalid");
118                         return;
119                     }
120                     String sourceIPPortKey = routerId + NatConstants.COLON_SEPARATOR
121                             + internalIPAddress + NatConstants.COLON_SEPARATOR + portNumber;
122
123                     NatPacketProcessingState state = INCOMING_PKT_MAP.get(sourceIPPortKey);
124                     if (state == null) {
125                         state = new NatPacketProcessingState(System.currentTimeMillis());
126                         INCOMING_PKT_MAP.put(sourceIPPortKey, state);
127                         LOG.trace("onPacketReceived : Processing new SNAT({}) Packet", sourceIPPortKey);
128
129                         //send to Event Queue
130                         NAPTEntryEvent naptEntryEvent = new NAPTEntryEvent(internalIPAddress, portNumber, routerId,
131                             operation, protocol, packetReceived, false, state);
132                         LOG.info("onPacketReceived : First Packet IN Queue Size : {}",
133                                 ((ThreadPoolExecutor)firstPacketExecutorService).getQueue().size());
134                         firstPacketExecutorService.execute(() -> naptEventHandler.handleEvent(naptEntryEvent));
135                     } else {
136                         LOG.trace("onPacketReceived : SNAT({}) Packet already processed.", sourceIPPortKey);
137                         NAPTEntryEvent naptEntryEvent = new NAPTEntryEvent(internalIPAddress, portNumber, routerId,
138                             operation, protocol, packetReceived, true, state);
139                         LOG.debug("onPacketReceived : Retry Packet IN Queue Size : {}",
140                                 ((ThreadPoolExecutor)retryPacketExecutorService).getQueue().size());
141
142                         long firstPacketInTime = state.getFirstPacketInTime();
143                         retryPacketExecutorService.execute(() -> {
144                             if (System.currentTimeMillis() - firstPacketInTime > 4000) {
145                                 LOG.error("onPacketReceived : Flow not installed even after 4sec."
146                                         + "Dropping SNAT ({}) Packet", sourceIPPortKey);
147                                 removeIncomingPacketMap(sourceIPPortKey);
148                                 return;
149                             }
150                             naptEventHandler.handleEvent(naptEntryEvent);
151                         });
152                     }
153                 } else {
154                     LOG.error("onPacketReceived : Retrived internalIPAddress is NULL");
155                 }
156             }
157         } else {
158             LOG.trace("onPacketReceived : Packet is not from the Outbound NAPT table");
159         }
160     }
161
162     public static void removeIncomingPacketMap(String sourceIPPortKey) {
163         INCOMING_PKT_MAP.remove(sourceIPPortKey);
164         LOG.debug("removeIncomingPacketMap : sourceIPPortKey {} mapping is removed from map", sourceIPPortKey);
165     }
166
167     static class NatPacketProcessingState {
168         private final long firstPacketInTime;
169
170         NatPacketProcessingState(long firstPacketInTime) {
171             this.firstPacketInTime = firstPacketInTime;
172         }
173
174         long getFirstPacketInTime() {
175             return firstPacketInTime;
176         }
177
178         void setFlowInstalledTime() {
179         }
180     }
181 }