Stale table=44 flows remains on VM deletion
[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.genius.mdsalutil.MetaDataUtil;
14 import org.opendaylight.genius.mdsalutil.NwConstants;
15 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4Prefix;
16 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.FlowAdded;
17 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.FlowRemoved;
18 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.FlowUpdated;
19 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.NodeErrorNotification;
20 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.NodeExperimenterErrorNotification;
21 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.SalFlowListener;
22 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.SwitchFlowRemoved;
23 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.RemovedFlowReason;
24 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.TcpMatchFields;
25 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.UdpMatchFields;
26 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.Layer3Match;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.Layer4Match;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._3.match.Ipv4Match;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._4.match.TcpMatch;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._4.match.UdpMatch;
31 import org.slf4j.Logger;
32 import org.slf4j.LoggerFactory;
33
34 @Singleton
35 public class NaptFlowRemovedEventHandler implements SalFlowListener {
36     private static final Logger LOG = LoggerFactory.getLogger(NaptFlowRemovedEventHandler.class);
37
38     private final EventDispatcher naptEventdispatcher;
39
40     @Inject
41     public NaptFlowRemovedEventHandler(final EventDispatcher eventDispatcher) {
42         this.naptEventdispatcher = eventDispatcher;
43     }
44
45     @Override
46     public void onSwitchFlowRemoved(SwitchFlowRemoved flowRemoved) {
47
48     }
49
50     @Override
51     public void onFlowAdded(FlowAdded arg0) {
52         // TODO Auto-generated method stub
53
54     }
55
56     @Override
57     public void onFlowRemoved(FlowRemoved flowRemoved) {
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 = flowRemoved.getTableId();
71         RemovedFlowReason removedReasonFlag = flowRemoved.getReason();
72         if (tableId == NwConstants.OUTBOUND_NAPT_TABLE
73                 && RemovedFlowReason.OFPRRIDLETIMEOUT.equals(removedReasonFlag)) {
74             LOG.info("onFlowRemoved : triggered for table-{} entry", tableId);
75
76             //Get the internal internal IP address and the port number from the IPv4 match.
77             Ipv4Prefix internalIpv4Address = null;
78             Layer3Match layer3Match = flowRemoved.getMatch().getLayer3Match();
79             if (layer3Match instanceof Ipv4Match) {
80                 Ipv4Match internalIpv4Match = (Ipv4Match) layer3Match;
81                 internalIpv4Address = internalIpv4Match.getIpv4Source();
82             }
83             if (internalIpv4Address == null) {
84                 LOG.error("onFlowRemoved : Matching internal IP is null while retrieving the "
85                     + "value from the Outbound NAPT flow");
86                 return;
87             }
88             //Get the internal IP as a string
89             String internalIpv4AddressAsString = internalIpv4Address.getValue();
90             String[] internalIpv4AddressParts = internalIpv4AddressAsString.split("/");
91             String internalIpv4HostAddress = null;
92             if (internalIpv4AddressParts.length >= 1) {
93                 internalIpv4HostAddress = internalIpv4AddressParts[0];
94             }
95
96             //Get the protocol from the layer4 match
97             NAPTEntryEvent.Protocol protocol = null;
98             Integer internalPortNumber = null;
99             Layer4Match layer4Match = flowRemoved.getMatch().getLayer4Match();
100             if (layer4Match instanceof TcpMatch) {
101                 TcpMatchFields tcpMatchFields = (TcpMatchFields) layer4Match;
102                 internalPortNumber = tcpMatchFields.getTcpSourcePort().getValue();
103                 protocol = NAPTEntryEvent.Protocol.TCP;
104             } else if (layer4Match instanceof UdpMatch) {
105                 UdpMatchFields udpMatchFields = (UdpMatchFields) layer4Match;
106                 internalPortNumber = udpMatchFields.getUdpSourcePort().getValue();
107                 protocol = NAPTEntryEvent.Protocol.UDP;
108             }
109             if (protocol == null) {
110                 LOG.error("onFlowRemoved : Matching protocol is null while retrieving the value "
111                     + "from the Outbound NAPT flow");
112                 return;
113             }
114
115             //Get the router ID from the metadata.
116             Long routerId;
117             BigInteger metadata = flowRemoved.getMatch().getMetadata().getMetadata();
118             if (MetaDataUtil.getNatRouterIdFromMetadata(metadata) != 0) {
119                 routerId = MetaDataUtil.getNatRouterIdFromMetadata(metadata);
120             } else {
121                 LOG.error("onFlowRemoved : Null exception while retrieving routerId");
122                 return;
123             }
124             String flowDpn = NatUtil.getDpnFromNodeRef(flowRemoved.getNode());
125             NAPTEntryEvent naptEntryEvent = new NAPTEntryEvent(internalIpv4HostAddress, internalPortNumber, flowDpn,
126                 routerId, NAPTEntryEvent.Operation.DELETE, protocol);
127             naptEventdispatcher.addFlowRemovedNaptEvent(naptEntryEvent);
128         } else {
129             LOG.debug("onFlowRemoved : Received flow removed notification due to flowdelete from switch for flowref");
130         }
131
132     }
133
134     @Override
135     public void onFlowUpdated(FlowUpdated arg0) {
136         // TODO Auto-generated method stub
137
138     }
139
140     @Override
141     public void onNodeErrorNotification(NodeErrorNotification arg0) {
142         // TODO Auto-generated method stub
143     }
144
145     @Override
146     public void onNodeExperimenterErrorNotification(NodeExperimenterErrorNotification arg0) {
147         // TODO Auto-generated method stub
148     }
149 }