Fixes for the below NAT issues :
[netvirt.git] / vpnservice / natservice / natservice-impl / src / main / java / org / opendaylight / netvirt / natservice / internal / NaptFlowRemovedEventHandler.java
1 /*
2  * Copyright (c) 2016 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
9 package org.opendaylight.netvirt.natservice.internal;
10
11 import org.opendaylight.genius.mdsalutil.MetaDataUtil;
12 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.SalFlowListener;
13 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.FlowAdded;
14 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.FlowRemoved;
15 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.FlowUpdated;
16 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.NodeErrorNotification;
17 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.NodeExperimenterErrorNotification;
18 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.SwitchFlowRemoved;
19 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.RemovedReasonFlags;
20 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.TcpMatchFields;
21 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.UdpMatchFields;
22 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.Layer3Match;
23 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.Layer4Match;
24 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._3.match.Ipv4Match;
25 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv4Prefix;
26 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._4.match.TcpMatch;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._4.match.UdpMatch;
28 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.intext.ip.port.map.ip.port.mapping.intext.ip.protocol.type.ip.port.map.IpPortExternal;
30 import org.slf4j.Logger;
31 import org.slf4j.LoggerFactory;
32 import org.opendaylight.genius.mdsalutil.FlowEntity;
33 import org.opendaylight.genius.mdsalutil.interfaces.IMdsalApiManager;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
35 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
36 import java.math.BigInteger;
37
38 public class NaptFlowRemovedEventHandler implements SalFlowListener{
39     private DataBroker dataBroker;
40     private final EventDispatcher naptEventdispatcher;
41     private static final Logger LOG = LoggerFactory.getLogger(NaptFlowRemovedEventHandler.class);
42     private final NaptPacketInHandler naptPacketInHandler;
43     private IMdsalApiManager mdsalManager;
44     private NaptManager naptManager;
45
46     public NaptFlowRemovedEventHandler(EventDispatcher eventDispatcher, DataBroker dataBroker, NaptPacketInHandler handler,
47                                        IMdsalApiManager mdsalManager, NaptManager naptManager) {
48         this.naptEventdispatcher = eventDispatcher;
49         this.dataBroker = dataBroker;
50         this.naptPacketInHandler = handler;
51         this.mdsalManager = mdsalManager;
52         this.naptManager = naptManager;
53     }
54
55     @Override
56     public void onSwitchFlowRemoved(SwitchFlowRemoved switchFlowRemoved) {
57
58 /*
59         If the removed flow is from the OUTBOUND NAPT table :
60         1) Get the ActionInfo of the flow.
61         2) From the ActionInfo of the flow get the internal IP address, port and the protocol.
62         3) Get the Metadata matching info of the flow.
63         4) From the Metadata matching info of the flow get router ID.
64         5) Querry the container intext-ip-port-map using the router ID
65            and the internal IP address, port to get the external IP address, port
66         6) Instantiate an NaptEntry event and populate the external IP address, port and the router ID.
67         7) Place the NaptEntry event to the queue.
68 */
69
70         short tableId = switchFlowRemoved.getTableId();
71         RemovedReasonFlags removedReasonFlag = switchFlowRemoved.getRemovedReason();
72
73         if (tableId == NatConstants.OUTBOUND_NAPT_TABLE && removedReasonFlag.isIDLETIMEOUT()) {
74             LOG.info("NaptFlowRemovedEventHandler : onSwitchFlowRemoved() entry");
75
76             //Get the internal internal IP address and the port number from the IPv4 match.
77             Ipv4Prefix internalIpv4Address = null;
78             Layer3Match layer3Match = switchFlowRemoved.getMatch().getLayer3Match();
79             if (layer3Match instanceof Ipv4Match) {
80                 Ipv4Match internalIpv4Match = (Ipv4Match) layer3Match;
81                 internalIpv4Address = internalIpv4Match.getIpv4Source();
82             }
83             if(internalIpv4Address == null){
84                 LOG.error("NaptFlowRemovedEventHandler : Matching internal IP is null while retrieving the value from the Outbound NAPT flow");
85                 return;
86             }
87             //Get the internal IP as a string
88             String internalIpv4AddressAsString = internalIpv4Address.getValue();
89             String[] internalIpv4AddressParts = internalIpv4AddressAsString.split("/");
90             String internalIpv4HostAddress = null;
91             if(internalIpv4AddressParts.length >= 1){
92                 internalIpv4HostAddress = internalIpv4AddressParts[0];
93             }
94
95             //Get the protocol from the layer4 match
96             NAPTEntryEvent.Protocol protocol = null;
97             Integer internalPortNumber = null;
98             Layer4Match layer4Match = switchFlowRemoved.getMatch().getLayer4Match();
99             if (layer4Match instanceof TcpMatch) {
100                 TcpMatchFields tcpMatchFields = (TcpMatchFields)layer4Match;
101                 internalPortNumber = tcpMatchFields.getTcpSourcePort().getValue();
102                 protocol = NAPTEntryEvent.Protocol.TCP;
103             }else if (layer4Match instanceof UdpMatch){
104                 UdpMatchFields udpMatchFields = (UdpMatchFields)layer4Match;
105                 internalPortNumber = udpMatchFields.getUdpSourcePort().getValue();
106                 protocol = NAPTEntryEvent.Protocol.UDP;
107             }
108             if(protocol == null){
109                 LOG.error("NaptFlowRemovedEventHandler : Matching protocol is null while retrieving the value from the Outbound NAPT flow");
110                 return;
111             }
112
113             //Get the router ID from the metadata.
114             Long routerId;
115             BigInteger metadata = switchFlowRemoved.getMatch().getMetadata().getMetadata();
116             if (MetaDataUtil.getNatRouterIdFromMetadata(metadata) != 0) {
117                 routerId = MetaDataUtil.getNatRouterIdFromMetadata(metadata);
118             } else {
119                 LOG.error("NaptFlowRemovedEventHandler : Null exception while retrieving routerId");
120                 return;
121             }
122
123             //Get the external IP address and the port from the model
124             IpPortExternal ipPortExternal = NatUtil.getExternalIpPortMap(dataBroker, routerId, internalIpv4HostAddress, internalPortNumber.toString(), protocol);
125             if (ipPortExternal == null) {
126                 LOG.debug("NaptFlowRemovedEventHandler : IpPortExternal not found, BGP vpn might be associated with router");
127                 //router must be associated with BGP vpn ID
128                 long bgpVpnId = routerId;
129                 LOG.debug("NaptFlowRemovedEventHandler : BGP VPN ID {}", bgpVpnId);
130                 String vpnName = NatUtil.getRouterName(dataBroker, bgpVpnId);
131                 String routerName = NatUtil.getRouterIdfromVpnId(dataBroker, vpnName);
132                 routerId = NatUtil.getVpnId(dataBroker, routerName);
133                 LOG.debug("NaptFlowRemovedEventHandler : Router ID {}", routerId);
134                 ipPortExternal = NatUtil.getExternalIpPortMap(dataBroker, routerId, internalIpv4HostAddress, internalPortNumber.toString(), protocol);
135                 if(ipPortExternal == null) {
136                     LOG.error("NaptFlowRemovedEventHandler : IpPortExternal is null while queried from the model for routerId {}",routerId);
137                     return;
138                 }
139             }
140             String externalIpAddress = ipPortExternal.getIpAddress();
141             int externalPortNumber = ipPortExternal.getPortNum();
142
143             //Create an NAPT event and place it in the queue.
144             NAPTEntryEvent naptEntryEvent =  new NAPTEntryEvent(externalIpAddress, externalPortNumber, routerId, NAPTEntryEvent.Operation.DELETE, protocol, null, false);
145             naptEventdispatcher.addNaptEvent(naptEntryEvent);
146
147             //Get the DPN ID from the Node
148             InstanceIdentifier<Node> nodeRef = switchFlowRemoved.getNode().getValue().firstIdentifierOf(Node.class);
149             String dpn = nodeRef.firstKeyOf(Node.class).getId().getValue();
150             BigInteger dpnId = getDpnId(dpn);
151             String switchFlowRef = NatUtil.getNaptFlowRef(dpnId, tableId, String.valueOf(routerId), internalIpv4HostAddress, internalPortNumber);
152
153             //Inform the MDSAL manager to inform about the flow removal.
154             LOG.debug("NaptFlowRemovedEventHandler : DPN ID {}, Metadata {}, SwitchFlowRef {}, internalIpv4HostAddress{}", dpnId, routerId, switchFlowRef, internalIpv4AddressAsString);
155             FlowEntity snatFlowEntity = NatUtil.buildFlowEntity(dpnId, tableId, switchFlowRef);
156             mdsalManager.removeFlow(snatFlowEntity);
157
158             LOG.debug("Received flow removed notification due to idleTimeout of flow from switch for flowref {}",switchFlowRef);
159             //Remove the SourceIP:Port key from the Napt packet handler map.
160             String internalIpPortKey = internalIpv4HostAddress + ":" + internalPortNumber;
161             naptPacketInHandler.removeIncomingPacketMap(internalIpPortKey);
162
163             //Remove the mapping of internal fixed ip/port to external ip/port from the datastore.
164             SessionAddress internalSessionAddress = new SessionAddress(internalIpv4HostAddress, internalPortNumber);
165             naptManager.releaseIpExtPortMapping(routerId, internalSessionAddress, protocol);
166             LOG.info("NaptFlowRemovedEventHandler : onSwitchFlowRemoved() exit");
167         }else {
168             LOG.debug("Received flow removed notification due to flowdelete from switch for flowref");
169         }
170
171     }
172
173     private BigInteger getDpnId(String node) {
174         //openflow:1]
175         String temp[] = node.split(":");
176         BigInteger dpnId = new BigInteger(temp[1]);
177         return dpnId;
178
179     }
180
181     @Override
182     public void onFlowAdded(FlowAdded arg0) {
183         // TODO Auto-generated method stub
184
185     }
186
187     @Override
188     public void onFlowRemoved(FlowRemoved arg0) {
189         // TODO Auto-generated method stub
190
191     }
192
193     @Override
194     public void onFlowUpdated(FlowUpdated arg0) {
195         // TODO Auto-generated method stub
196
197     }
198
199     @Override
200     public void onNodeErrorNotification(NodeErrorNotification arg0) {
201         // TODO Auto-generated method stub
202
203     }
204
205     @Override
206     public void onNodeExperimenterErrorNotification(NodeExperimenterErrorNotification arg0) {
207         // TODO Auto-generated method stub
208
209     }
210
211 }