Support for SNAT and DNAT features in L3 forwarding services.
[vpnservice.git] / natservice / natservice-impl / src / main / java / org / opendaylight / vpnservice / natservice / internal / NaptFlowRemovedEventHandler.java
diff --git a/natservice/natservice-impl/src/main/java/org/opendaylight/vpnservice/natservice/internal/NaptFlowRemovedEventHandler.java b/natservice/natservice-impl/src/main/java/org/opendaylight/vpnservice/natservice/internal/NaptFlowRemovedEventHandler.java
new file mode 100644 (file)
index 0000000..f0206e2
--- /dev/null
@@ -0,0 +1,202 @@
+/*
+ * Copyright (c) 2016 Ericsson India Global Services Pvt Ltd. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.vpnservice.natservice.internal;
+
+import org.opendaylight.vpnservice.mdsalutil.MetaDataUtil;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.SalFlowListener;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.FlowAdded;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.FlowRemoved;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.FlowUpdated;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.NodeErrorNotification;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.NodeExperimenterErrorNotification;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.SwitchFlowRemoved;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.RemovedReasonFlags;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.TcpMatchFields;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.UdpMatchFields;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.Layer3Match;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.Layer4Match;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._3.match.Ipv4Match;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv4Prefix;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._4.match.TcpMatch;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._4.match.UdpMatch;
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.intext.ip.port.map.ip.port.mapping.intext.ip.protocol.type.ip.port.map.IpPortExternal;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.opendaylight.vpnservice.mdsalutil.FlowEntity;
+import org.opendaylight.vpnservice.mdsalutil.interfaces.IMdsalApiManager;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import java.math.BigInteger;
+
+public class NaptFlowRemovedEventHandler implements SalFlowListener{
+    private DataBroker dataBroker;
+    private final EventDispatcher naptEventdispatcher;
+    private static final Logger LOG = LoggerFactory.getLogger(NaptFlowRemovedEventHandler.class);
+    private final NaptPacketInHandler naptPacketInHandler;
+    private IMdsalApiManager mdsalManager;
+    private NaptManager naptManager;
+
+    public NaptFlowRemovedEventHandler(EventDispatcher eventDispatcher, DataBroker dataBroker, NaptPacketInHandler handler,
+                                       IMdsalApiManager mdsalManager, NaptManager naptManager) {
+        this.naptEventdispatcher = eventDispatcher;
+        this.dataBroker = dataBroker;
+        this.naptPacketInHandler = handler;
+        this.mdsalManager = mdsalManager;
+        this.naptManager = naptManager;
+    }
+
+    @Override
+    public void onSwitchFlowRemoved(SwitchFlowRemoved switchFlowRemoved) {
+
+/*
+        If the removed flow is from the OUTBOUND NAPT table :
+        1) Get the ActionInfo of the flow.
+        2) From the ActionInfo of the flow get the internal IP address, port and the protocol.
+        3) Get the Metadata matching info of the flow.
+        4) From the Metadata matching info of the flow get router ID.
+        5) Querry the container intext-ip-port-map using the router ID
+           and the internal IP address, port to get the external IP address, port
+        6) Instantiate an NaptEntry event and populate the external IP address, port and the router ID.
+        7) Place the NaptEntry event to the queue.
+*/
+
+        short tableId = switchFlowRemoved.getTableId();
+        RemovedReasonFlags removedReasonFlag = switchFlowRemoved.getRemovedReason();
+
+        if (tableId == NatConstants.OUTBOUND_NAPT_TABLE) {
+            LOG.info("NaptFlowRemovedEventHandler : onSwitchFlowRemoved() entry");
+
+            //Get the internal internal IP address and the port number from the IPv4 match.
+            Ipv4Prefix internalIpv4Address = null;
+            Layer3Match layer3Match = switchFlowRemoved.getMatch().getLayer3Match();
+            if (layer3Match instanceof Ipv4Match) {
+                Ipv4Match internalIpv4Match = (Ipv4Match) layer3Match;
+                internalIpv4Address = internalIpv4Match.getIpv4Source();
+            }
+            if(internalIpv4Address == null){
+                LOG.error("NaptFlowRemovedEventHandler : Matching internal IP is null while retrieving the value from the Outbound NAPT flow");
+                return;
+            }
+            //Get the internal IP as a string
+            String internalIpv4AddressAsString = internalIpv4Address.getValue();
+            String[] internalIpv4AddressParts = internalIpv4AddressAsString.split("/");
+            String internalIpv4HostAddress = null;
+            if(internalIpv4AddressParts.length >= 1){
+                internalIpv4HostAddress = internalIpv4AddressParts[0];
+            }
+
+            //Get the protocol from the layer4 match
+            NAPTEntryEvent.Protocol protocol = null;
+            Integer internalPortNumber = null;
+            Layer4Match layer4Match = switchFlowRemoved.getMatch().getLayer4Match();
+            if (layer4Match instanceof TcpMatch) {
+                TcpMatchFields tcpMatchFields = (TcpMatchFields)layer4Match;
+                internalPortNumber = tcpMatchFields.getTcpSourcePort().getValue();
+                protocol = NAPTEntryEvent.Protocol.TCP;
+            }else if (layer4Match instanceof UdpMatch){
+                UdpMatchFields udpMatchFields = (UdpMatchFields)layer4Match;
+                internalPortNumber = udpMatchFields.getUdpSourcePort().getValue();
+                protocol = NAPTEntryEvent.Protocol.UDP;
+            }
+            if(protocol == null){
+                LOG.error("NaptFlowRemovedEventHandler : Matching protocol is null while retrieving the value from the Outbound NAPT flow");
+                return;
+            }
+
+            //Get the router ID from the metadata.
+            Long routerId;
+            BigInteger metadata = switchFlowRemoved.getMatch().getMetadata().getMetadata();
+            if(MetaDataUtil.getNatRouterIdFromMetadata(metadata) != 0) {
+                routerId = MetaDataUtil.getNatRouterIdFromMetadata(metadata);
+            }else {
+                LOG.error("NaptFlowRemovedEventHandler : Null exception while retrieving routerId");
+                return;
+            }
+
+            //Get the external IP address and the port from the model
+            IpPortExternal ipPortExternal = NatUtil.getExternalIpPortMap(dataBroker, routerId, internalIpv4HostAddress, internalPortNumber.toString(), protocol);
+            if(ipPortExternal == null){
+                LOG.error("NaptFlowRemovedEventHandler : IpPortExternal is null while querried from the model");
+                return;
+            }
+            String externalIpAddress = ipPortExternal.getIpAddress();
+            int externalPortNumber = ipPortExternal.getPortNum();
+
+            //Create an NAPT event and place it in the queue.
+            NAPTEntryEvent naptEntryEvent =  new NAPTEntryEvent(externalIpAddress, externalPortNumber, routerId, NAPTEntryEvent.Operation.DELETE, protocol);
+            naptEventdispatcher.addNaptEvent(naptEntryEvent);
+
+            //Get the DPN ID from the Node
+            InstanceIdentifier<Node> nodeRef = switchFlowRemoved.getNode().getValue().firstIdentifierOf(Node.class);
+            String dpn = nodeRef.firstKeyOf(Node.class).getId().getValue();
+            BigInteger dpnId = getDpnId(dpn);
+
+            //Inform the MDSAL manager to inform about the flow removal.
+            String switchFlowRef = NatUtil.getNaptFlowRef(dpnId, tableId, String.valueOf(metadata), internalIpv4HostAddress, internalPortNumber);
+            LOG.debug("NaptFlowRemovedEventHandler : DPN ID {}, Metadata {}, SwitchFlowRef {}, internalIpv4HostAddress{}", dpnId, metadata, switchFlowRef, internalIpv4AddressAsString);
+            FlowEntity snatFlowEntity = NatUtil.buildFlowEntity(dpnId, tableId, switchFlowRef);
+            mdsalManager.removeFlow(snatFlowEntity);
+
+            if(removedReasonFlag.isIDLETIMEOUT()) {
+                LOG.debug("Received flow removed notification due to idleTimeout of flow from switch for flowref {}",switchFlowRef);
+                //Remove the SourceIP:Port key from the Napt packet handler map.
+                String internalIpPortKey = internalIpv4HostAddress + ":" + internalPortNumber;
+                naptPacketInHandler.removeIncomingPacketMap(internalIpPortKey);
+
+                //Remove the mapping of internal fixed ip/port to external ip/port from the datastore.
+                SessionAddress internalSessionAddress = new SessionAddress(internalIpv4HostAddress, internalPortNumber);
+                naptManager.releaseIpExtPortMapping(routerId, internalSessionAddress, protocol);
+            } else {
+                LOG.debug("Received flow removed notification due to flowdelete from switch for flowref {}",switchFlowRef);
+            }
+
+            LOG.info("NaptFlowRemovedEventHandler : onSwitchFlowRemoved() exit");
+        }
+    }
+
+    private BigInteger getDpnId(String node) {
+        //openflow:1]
+        String temp[] = node.split(":");
+        BigInteger dpnId = new BigInteger(temp[1]);
+        return dpnId;
+
+    }
+
+    @Override
+    public void onFlowAdded(FlowAdded arg0) {
+        // TODO Auto-generated method stub
+
+    }
+
+    @Override
+    public void onFlowRemoved(FlowRemoved arg0) {
+        // TODO Auto-generated method stub
+
+    }
+
+    @Override
+    public void onFlowUpdated(FlowUpdated arg0) {
+        // TODO Auto-generated method stub
+
+    }
+
+    @Override
+    public void onNodeErrorNotification(NodeErrorNotification arg0) {
+        // TODO Auto-generated method stub
+
+    }
+
+    @Override
+    public void onNodeExperimenterErrorNotification(NodeExperimenterErrorNotification arg0) {
+        // TODO Auto-generated method stub
+
+    }
+
+}