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
9 package org.opendaylight.netvirt.natservice.internal;
11 import org.opendaylight.genius.mdsalutil.MetaDataUtil;
12 import org.opendaylight.genius.mdsalutil.NwConstants;
13 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.SalFlowListener;
14 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.FlowAdded;
15 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.FlowRemoved;
16 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.FlowUpdated;
17 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.NodeErrorNotification;
18 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.NodeExperimenterErrorNotification;
19 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.SwitchFlowRemoved;
20 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.RemovedReasonFlags;
21 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.TcpMatchFields;
22 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.UdpMatchFields;
23 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.Layer3Match;
24 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.Layer4Match;
25 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._3.match.Ipv4Match;
26 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4Prefix;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._4.match.TcpMatch;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._4.match.UdpMatch;
29 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
30 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;
31 import org.slf4j.Logger;
32 import org.slf4j.LoggerFactory;
33 import org.opendaylight.genius.mdsalutil.FlowEntity;
34 import org.opendaylight.genius.mdsalutil.interfaces.IMdsalApiManager;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
36 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
37 import java.math.BigInteger;
39 public class NaptFlowRemovedEventHandler implements SalFlowListener{
40 private DataBroker dataBroker;
41 private final EventDispatcher naptEventdispatcher;
42 private static final Logger LOG = LoggerFactory.getLogger(NaptFlowRemovedEventHandler.class);
43 private final NaptPacketInHandler naptPacketInHandler;
44 private IMdsalApiManager mdsalManager;
45 private NaptManager naptManager;
47 public NaptFlowRemovedEventHandler(EventDispatcher eventDispatcher, DataBroker dataBroker, NaptPacketInHandler handler,
48 IMdsalApiManager mdsalManager, NaptManager naptManager) {
49 this.naptEventdispatcher = eventDispatcher;
50 this.dataBroker = dataBroker;
51 this.naptPacketInHandler = handler;
52 this.mdsalManager = mdsalManager;
53 this.naptManager = naptManager;
57 public void onSwitchFlowRemoved(SwitchFlowRemoved switchFlowRemoved) {
60 If the removed flow is from the OUTBOUND NAPT table :
61 1) Get the ActionInfo of the flow.
62 2) From the ActionInfo of the flow get the internal IP address, port and the protocol.
63 3) Get the Metadata matching info of the flow.
64 4) From the Metadata matching info of the flow get router ID.
65 5) Querry the container intext-ip-port-map using the router ID
66 and the internal IP address, port to get the external IP address, port
67 6) Instantiate an NaptEntry event and populate the external IP address, port and the router ID.
68 7) Place the NaptEntry event to the queue.
71 short tableId = switchFlowRemoved.getTableId();
72 RemovedReasonFlags removedReasonFlag = switchFlowRemoved.getRemovedReason();
74 if (tableId == NwConstants.OUTBOUND_NAPT_TABLE && removedReasonFlag.isIDLETIMEOUT()) {
75 LOG.info("NaptFlowRemovedEventHandler : onSwitchFlowRemoved() entry");
77 //Get the internal internal IP address and the port number from the IPv4 match.
78 Ipv4Prefix internalIpv4Address = null;
79 Layer3Match layer3Match = switchFlowRemoved.getMatch().getLayer3Match();
80 if (layer3Match instanceof Ipv4Match) {
81 Ipv4Match internalIpv4Match = (Ipv4Match) layer3Match;
82 internalIpv4Address = internalIpv4Match.getIpv4Source();
84 if(internalIpv4Address == null){
85 LOG.error("NaptFlowRemovedEventHandler : Matching internal IP is null while retrieving the value from the Outbound NAPT flow");
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];
96 //Get the protocol from the layer4 match
97 NAPTEntryEvent.Protocol protocol = null;
98 Integer internalPortNumber = null;
99 Layer4Match layer4Match = switchFlowRemoved.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;
109 if(protocol == null){
110 LOG.error("NaptFlowRemovedEventHandler : Matching protocol is null while retrieving the value from the Outbound NAPT flow");
114 //Get the router ID from the metadata.
116 BigInteger metadata = switchFlowRemoved.getMatch().getMetadata().getMetadata();
117 if (MetaDataUtil.getNatRouterIdFromMetadata(metadata) != 0) {
118 routerId = MetaDataUtil.getNatRouterIdFromMetadata(metadata);
120 LOG.error("NaptFlowRemovedEventHandler : Null exception while retrieving routerId");
124 //Get the external IP address and the port from the model
125 IpPortExternal ipPortExternal = NatUtil.getExternalIpPortMap(dataBroker, routerId, internalIpv4HostAddress, internalPortNumber.toString(), protocol);
126 if (ipPortExternal == null) {
127 LOG.error("NaptFlowRemovedEventHandler : IpPortExternal not found, BGP vpn might be associated with router");
128 //router must be associated with BGP vpn ID
129 long bgpVpnId = routerId;
130 LOG.debug("NaptFlowRemovedEventHandler : BGP VPN ID {}", bgpVpnId);
131 String vpnName = NatUtil.getRouterName(dataBroker, bgpVpnId);
132 String routerName = NatUtil.getRouterIdfromVpnInstance(dataBroker, vpnName);
133 routerId = NatUtil.getVpnId(dataBroker, routerName);
134 LOG.debug("NaptFlowRemovedEventHandler : Router ID {}", routerId);
135 ipPortExternal = NatUtil.getExternalIpPortMap(dataBroker, routerId, internalIpv4HostAddress, internalPortNumber.toString(), protocol);
136 if(ipPortExternal == null) {
137 LOG.error("NaptFlowRemovedEventHandler : IpPortExternal is null while queried from the model for routerId {}",routerId);
141 String externalIpAddress = ipPortExternal.getIpAddress();
142 int externalPortNumber = ipPortExternal.getPortNum();
144 //Create an NAPT event and place it in the queue.
145 NAPTEntryEvent naptEntryEvent = new NAPTEntryEvent(externalIpAddress, externalPortNumber, routerId, NAPTEntryEvent.Operation.DELETE, protocol, null, false);
146 naptEventdispatcher.addNaptEvent(naptEntryEvent);
148 //Get the DPN ID from the Node
149 InstanceIdentifier<Node> nodeRef = switchFlowRemoved.getNode().getValue().firstIdentifierOf(Node.class);
150 String dpn = nodeRef.firstKeyOf(Node.class).getId().getValue();
151 BigInteger dpnId = getDpnId(dpn);
152 String switchFlowRef = NatUtil.getNaptFlowRef(dpnId, tableId, String.valueOf(routerId), internalIpv4HostAddress, internalPortNumber);
154 //Inform the MDSAL manager to inform about the flow removal.
155 LOG.debug("NaptFlowRemovedEventHandler : DPN ID {}, Metadata {}, SwitchFlowRef {}, internalIpv4HostAddress{}", dpnId, routerId, switchFlowRef, internalIpv4AddressAsString);
156 FlowEntity snatFlowEntity = NatUtil.buildFlowEntity(dpnId, tableId, switchFlowRef);
157 mdsalManager.removeFlow(snatFlowEntity);
159 LOG.debug("Received flow removed notification due to idleTimeout of flow from switch for flowref {}",switchFlowRef);
160 //Remove the SourceIP:Port key from the Napt packet handler map.
161 String internalIpPortKey = internalIpv4HostAddress + ":" + internalPortNumber;
162 naptPacketInHandler.removeIncomingPacketMap(internalIpPortKey);
164 //Remove the mapping of internal fixed ip/port to external ip/port from the datastore.
165 SessionAddress internalSessionAddress = new SessionAddress(internalIpv4HostAddress, internalPortNumber);
166 naptManager.releaseIpExtPortMapping(routerId, internalSessionAddress, protocol);
167 LOG.info("NaptFlowRemovedEventHandler : onSwitchFlowRemoved() exit");
169 LOG.debug("Received flow removed notification due to flowdelete from switch for flowref");
174 private BigInteger getDpnId(String node) {
176 String temp[] = node.split(":");
177 BigInteger dpnId = new BigInteger(temp[1]);
183 public void onFlowAdded(FlowAdded arg0) {
184 // TODO Auto-generated method stub
189 public void onFlowRemoved(FlowRemoved arg0) {
190 // TODO Auto-generated method stub
195 public void onFlowUpdated(FlowUpdated arg0) {
196 // TODO Auto-generated method stub
201 public void onNodeErrorNotification(NodeErrorNotification arg0) {
202 // TODO Auto-generated method stub
207 public void onNodeExperimenterErrorNotification(NodeExperimenterErrorNotification arg0) {
208 // TODO Auto-generated method stub