2 * Copyright (c) 2016 Ericsson India Global Services Pvt Ltd. and others. All rights reserved.
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
8 package org.opendaylight.netvirt.natservice.internal;
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;
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;
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;
59 public void onSwitchFlowRemoved(SwitchFlowRemoved switchFlowRemoved) {
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.
73 short tableId = switchFlowRemoved.getTableId();
74 RemovedReasonFlags removedReasonFlag = switchFlowRemoved.getRemovedReason();
76 if (tableId == NwConstants.OUTBOUND_NAPT_TABLE && removedReasonFlag.isIDLETIMEOUT()) {
77 LOG.info("NaptFlowRemovedEventHandler : onSwitchFlowRemoved() entry");
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();
86 if(internalIpv4Address == null){
87 LOG.error("NaptFlowRemovedEventHandler : Matching internal IP is null while retrieving the value from the Outbound NAPT flow");
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];
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;
111 if(protocol == null){
112 LOG.error("NaptFlowRemovedEventHandler : Matching protocol is null while retrieving the value from the Outbound NAPT flow");
116 //Get the router ID from the metadata.
118 BigInteger metadata = switchFlowRemoved.getMatch().getMetadata().getMetadata();
119 if (MetaDataUtil.getNatRouterIdFromMetadata(metadata) != 0) {
120 routerId = MetaDataUtil.getNatRouterIdFromMetadata(metadata);
122 LOG.error("NaptFlowRemovedEventHandler : Null exception while retrieving routerId");
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);
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);
147 String externalIpAddress = ipPortExternal.getIpAddress();
148 int externalPortNumber = ipPortExternal.getPortNum();
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);
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);
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);
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);
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");
175 LOG.debug("Received flow removed notification due to flowdelete from switch for flowref");
180 private BigInteger getDpnId(String node) {
182 String temp[] = node.split(":");
183 BigInteger dpnId = new BigInteger(temp[1]);
189 public void onFlowAdded(FlowAdded arg0) {
190 // TODO Auto-generated method stub
195 public void onFlowRemoved(FlowRemoved arg0) {
196 // TODO Auto-generated method stub
201 public void onFlowUpdated(FlowUpdated arg0) {
202 // TODO Auto-generated method stub
207 public void onNodeErrorNotification(NodeErrorNotification arg0) {
208 // TODO Auto-generated method stub
213 public void onNodeExperimenterErrorNotification(NodeExperimenterErrorNotification arg0) {
214 // TODO Auto-generated method stub