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