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