Bug 7170: ARP thread is sleeping 2s
[netvirt.git] / vpnservice / vpnmanager / vpnmanager-impl / src / main / java / org / opendaylight / netvirt / vpnmanager / ArpNotificationHandler.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.vpnmanager;
9
10 import java.math.BigInteger;
11 import java.util.Arrays;
12 import java.util.List;
13 import java.util.concurrent.Future;
14 import java.util.concurrent.TimeUnit;
15
16 import org.apache.commons.lang3.tuple.ImmutablePair;
17 import org.apache.commons.lang3.tuple.Pair;
18 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
19 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
20 import org.opendaylight.genius.interfacemanager.interfaces.IInterfaceManager;
21 import org.opendaylight.genius.mdsalutil.MDSALUtil;
22 import org.opendaylight.genius.mdsalutil.MetaDataUtil;
23 import org.opendaylight.netvirt.elanmanager.api.IElanService;
24 import org.opendaylight.netvirt.vpnmanager.utilities.InterfaceUtils;
25 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.VpnAfConfig;
26 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.VpnInterfaces;
27 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.interfaces.VpnInterface;
28 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.interfaces.VpnInterfaceBuilder;
29 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.interfaces.VpnInterfaceKey;
30 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
31 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.MacAddress;
32 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.PhysAddress;
33 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.arputil.rev160406.ArpRequestReceived;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.arputil.rev160406.ArpResponseReceived;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.arputil.rev160406.MacChanged;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.arputil.rev160406.OdlArputilListener;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.arputil.rev160406.OdlArputilService;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.arputil.rev160406.SendArpResponseInput;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.arputil.rev160406.SendArpResponseInputBuilder;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.IdManagerService;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.OdlInterfaceRpcService;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.Adjacencies;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.adjacency.list.Adjacency;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.adjacency.list.AdjacencyBuilder;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.adjacency.list.AdjacencyKey;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.id.to.vpn.instance.VpnIds;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.neutron.vpn.portip.port.data.VpnPortipToPort;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.l3.rev150712.floatingips.attributes.Floatingips;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.l3.rev150712.floatingips.attributes.floatingips.Floatingip;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.ports.attributes.Ports;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.ports.attributes.ports.Port;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.ports.attributes.ports.PortKey;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.rev150712.Neutron;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.subnets.rev150712.subnets.attributes.Subnets;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.subnets.rev150712.subnets.attributes.subnets.Subnet;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.subnets.rev150712.subnets.attributes.subnets.SubnetKey;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.vpn.config.rev161130.VpnConfig;
59 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
60 import org.opendaylight.yangtools.yang.common.RpcResult;
61 import org.slf4j.Logger;
62 import org.slf4j.LoggerFactory;
63
64 import com.google.common.base.Optional;
65 import com.google.common.cache.Cache;
66 import com.google.common.cache.CacheBuilder;
67 import com.google.common.collect.Maps;
68 import com.google.common.util.concurrent.FutureCallback;
69 import com.google.common.util.concurrent.Futures;
70 import com.google.common.util.concurrent.JdkFutureAdapters;
71
72
73 public class ArpNotificationHandler implements OdlArputilListener {
74     private static final Logger LOG = LoggerFactory.getLogger(ArpNotificationHandler.class);
75     // temp where Key is VPNInstance+IP and value is timestamp
76     private final Cache<Pair<String, String>, BigInteger> migrateArpReqCache;
77
78     DataBroker dataBroker;
79     VpnInterfaceManager vpnIfManager;
80     IdManagerService idManager;
81     OdlArputilService arpManager;
82     final IElanService elanService;
83     ArpMonitoringHandler arpScheduler;
84     OdlInterfaceRpcService ifaceMgrRpcService;
85     IInterfaceManager interfaceManager;
86     private final VpnConfig config;
87
88
89     public ArpNotificationHandler(DataBroker dataBroker, VpnInterfaceManager vpnIfMgr,
90             final IElanService elanService, IdManagerService idManager, OdlArputilService arpManager,
91             ArpMonitoringHandler arpScheduler, OdlInterfaceRpcService ifaceMgrRpcService,
92             IInterfaceManager interfaceManager, VpnConfig vpnConfig) {
93         this.dataBroker = dataBroker;
94         vpnIfManager = vpnIfMgr;
95         this.elanService = elanService;
96         this.idManager = idManager;
97         this.arpManager = arpManager;
98         this.arpScheduler = arpScheduler;
99         this.ifaceMgrRpcService = ifaceMgrRpcService;
100         this.interfaceManager = interfaceManager;
101         this.config = vpnConfig;
102
103         long duration = config.getArpLearnTimeout() * 10;
104         long cacheSize = config.getArpCacheSize().longValue();
105         migrateArpReqCache =
106                 CacheBuilder.newBuilder().maximumSize(cacheSize).expireAfterWrite(duration, TimeUnit.MILLISECONDS).build();
107     }
108
109     @Override
110     public void onMacChanged(MacChanged notification){
111
112     }
113
114     @Override
115     public void onArpRequestReceived(ArpRequestReceived notification){
116         LOG.trace("ArpNotification Request Received from interface {} and IP {} having MAC {} target destination {}",
117                 notification.getInterface(), notification.getSrcIpaddress().getIpv4Address().getValue(),
118                 notification.getSrcMac().getValue(),notification.getDstIpaddress().getIpv4Address().getValue());
119         String srcInterface = notification.getInterface();
120         IpAddress srcIP = notification.getSrcIpaddress();
121         PhysAddress srcMac = notification.getSrcMac();
122         IpAddress targetIP = notification.getDstIpaddress();
123         BigInteger metadata = notification.getMetadata();
124         if (metadata != null && metadata != BigInteger.ZERO) {
125             long vpnId = MetaDataUtil.getVpnIdFromMetadata(metadata);
126             // Respond to ARP request only if vpnservice is configured on the interface
127             InstanceIdentifier<VpnIds> vpnIdsInstanceIdentifier = VpnUtil.getVpnIdToVpnInstanceIdentifier(vpnId);
128             Optional<VpnIds> vpnIdsOptional
129                     = VpnUtil.read(dataBroker, LogicalDatastoreType.CONFIGURATION, vpnIdsInstanceIdentifier);
130             if (!vpnIdsOptional.isPresent()) {
131                 // Donot respond to ARP requests on unknown VPNs
132                 LOG.trace("ARP NO_RESOLVE: VPN {} not configured. Ignoring responding to ARP requests on this VPN", vpnId);
133                 return;
134             }
135             VpnIds vpnIds = vpnIdsOptional.get();
136             String vpnName = vpnIds.getVpnInstanceName();
137             if (VpnUtil.isInterfaceAssociatedWithVpn(dataBroker, vpnName, srcInterface)) {
138                 LOG.debug("Received ARP request for target IP {}, sender MAC {} and sender IP {} via interface {}",
139                         targetIP.getIpv4Address().getValue(), srcMac.getValue(), srcIP.getIpv4Address().getValue(), srcInterface);
140                 String ipToQuery = notification.getSrcIpaddress().getIpv4Address().getValue();
141                 LOG.trace("ArpRequest being processed for Source IP {}", ipToQuery);
142                 VpnPortipToPort vpnPortipToPort = VpnUtil.getNeutronPortFromVpnPortFixedIp(dataBroker, vpnName, ipToQuery);
143                 boolean isGarp = srcIP.equals(targetIP);
144                 if (isGarp && vpnPortipToPort != null) {
145                     String oldPortName = vpnPortipToPort.getPortName();
146                     String oldMac = vpnPortipToPort.getMacAddress();
147                     if (!oldMac.equalsIgnoreCase(srcMac.getValue())) {
148                         //MAC has changed for requested IP
149                         LOG.trace("ARP request Source IP/MAC data modified for IP {} with MAC {} and Port {}",
150                                 ipToQuery, srcMac, srcInterface);
151                         if (!vpnPortipToPort.isConfig()) {
152                             synchronized ((vpnName + ipToQuery).intern()) {
153                                 removeMipAdjacency(vpnName, oldPortName, srcIP);
154                                 VpnUtil.removeVpnPortFixedIpToPort(dataBroker, vpnName, ipToQuery);
155
156                                 putVpnIpToMigrateArpCache(vpnName, ipToQuery, srcMac);
157                             }
158                         } else {
159                             //MAC mismatch for a Neutron learned IP
160                             LOG.warn("MAC Address mismatch for Interface {} having a Mac {},  IP {} and ARP learnt Mac {}",
161                                     oldPortName, oldMac, ipToQuery, srcMac.getValue());
162                             return;
163                         }
164                     }
165                 } else if (isGarp && shouldLearnMacFromArpPackets(vpnName, ipToQuery)) {
166                     learnMacFromArpPackets(vpnName, srcInterface, srcIP, srcMac);
167                 }
168                 if (elanService.isExternalInterface(srcInterface)) {
169                     handleArpRequestFromExternalInterface(srcInterface, srcIP, srcMac, targetIP);
170                     return;
171                 }
172             }
173         }
174     }
175
176     private void handleArpRequestForSubnetIp(String srcInterface, IpAddress srcIP, PhysAddress srcMac,
177             IpAddress targetIP, VpnPortipToPort vpnTargetIpToPort) {
178         String macAddress = vpnTargetIpToPort.getMacAddress();
179         PhysAddress targetMac = new PhysAddress(macAddress);
180         processArpRequest(srcIP, srcMac, targetIP, targetMac, srcInterface);
181         return;
182     }
183
184     private void handleArpRequestForExternalVpn(String srcInterface, IpAddress srcIP, PhysAddress srcMac,
185             IpAddress targetIP, String targetIpToQuery, VpnPortipToPort vpnTargetIpToPort) {
186         if (vpnTargetIpToPort != null) {
187             if (vpnTargetIpToPort.isSubnetIp()) {
188                 handleArpRequestForSubnetIp(srcInterface, srcIP, srcMac, targetIP, vpnTargetIpToPort);
189             }
190             return;
191         }
192         // Respond for gateway Ips ARP requests if L3vpn configured without a router
193         Port prt;
194         String gw = null;
195         Uuid portUuid = new Uuid(srcInterface);
196         InstanceIdentifier<Port> inst = InstanceIdentifier.create(Neutron.class).child(Ports.class)
197                 .child(Port.class, new PortKey(portUuid));
198         Optional<Port> port = VpnUtil.read(dataBroker, LogicalDatastoreType.CONFIGURATION, inst);
199         if (port.isPresent()) {
200             prt = port.get();
201             //TODO(Gobinath): Need to fix this as assuming port will belong to only one Subnet would be incorrect"
202             Uuid subnetUUID = prt.getFixedIps().get(0).getSubnetId();
203             LOG.trace("Subnet UUID for this VPN Interface is {}", subnetUUID);
204             SubnetKey subnetkey = new SubnetKey(subnetUUID);
205             InstanceIdentifier<Subnet> subnetidentifier = InstanceIdentifier.create(Neutron.class)
206                     .child(Subnets.class).child(Subnet.class, subnetkey);
207             Optional<Subnet> subnet = VpnUtil.read(dataBroker, LogicalDatastoreType.CONFIGURATION,
208                     subnetidentifier);
209             if (subnet.isPresent()) {
210                 gw = subnet.get().getGatewayIp().getIpv4Address().getValue();
211                 if (targetIpToQuery.equalsIgnoreCase(gw)) {
212                     LOG.trace("Target Destination matches the Gateway IP {} so respond for ARP", gw);
213                     processArpRequest(srcIP, srcMac, targetIP, null, srcInterface);
214                 }
215             }
216         }
217     }
218
219     @Override
220     public void onArpResponseReceived(ArpResponseReceived notification){
221         LOG.trace("ArpNotification Response Received from interface {} and IP {} having MAC {}",notification.getInterface(),
222                 notification.getIpaddress().getIpv4Address().getValue(), notification.getMacaddress().getValue());
223         String srcInterface = notification.getInterface();
224         IpAddress srcIP = notification.getIpaddress();
225         PhysAddress srcMac = notification.getMacaddress();
226         BigInteger metadata = notification.getMetadata();
227         if (metadata != null && metadata != BigInteger.ZERO) {
228             long vpnId = MetaDataUtil.getVpnIdFromMetadata(metadata);
229             InstanceIdentifier<VpnIds>
230             vpnIdsInstanceIdentifier = VpnUtil.getVpnIdToVpnInstanceIdentifier(vpnId);
231             Optional<VpnIds> vpnIdsOptional
232             = VpnUtil.read(dataBroker, LogicalDatastoreType.CONFIGURATION, vpnIdsInstanceIdentifier);
233             if (!vpnIdsOptional.isPresent()) {
234                 // Donot respond to ARP requests on unknown VPNs
235                 LOG.trace("ARP NO_RESOLVE: VPN {} not configured. Ignoring responding to ARP requests on this VPN", vpnId);
236                 return;
237             }
238             String vpnName = vpnIdsOptional.get().getVpnInstanceName();
239             if (VpnUtil.isInterfaceAssociatedWithVpn(dataBroker, vpnName, srcInterface)) {
240                 String ipToQuery = notification.getIpaddress().getIpv4Address().getValue();
241                 VpnPortipToPort vpnPortipToPort = VpnUtil.getNeutronPortFromVpnPortFixedIp(dataBroker, vpnName, ipToQuery);
242                 if (vpnPortipToPort != null) {
243                     String oldMac = vpnPortipToPort.getMacAddress();
244                     String oldPortName = vpnPortipToPort.getPortName();
245                     if (!oldMac.equalsIgnoreCase(srcMac.getValue())) {
246                         //MAC has changed for requested IP
247                         LOG.trace("ARP response Source IP/MAC data modified for IP {} with MAC {} and Port {}",
248                                 ipToQuery, srcMac, srcInterface);
249                         if (!vpnPortipToPort.isConfig()) {
250                             synchronized ((vpnName + ipToQuery).intern()) {
251                                 removeMipAdjacency(vpnName, oldPortName, srcIP);
252                                 VpnUtil.removeVpnPortFixedIpToPort(dataBroker, vpnName, ipToQuery);
253
254                                 putVpnIpToMigrateArpCache(vpnName, ipToQuery, srcMac);
255                             }
256                         } else {
257                             //MAC mismatch for a Neutron learned IP set learnt back to false
258                             LOG.warn("MAC Address mismatch for Interface {} having a Mac  {} , IP {} and Arp learnt Mac {}",
259                                     srcInterface, oldMac, ipToQuery, srcMac.getValue());
260                         }
261                     }
262                 } else if (shouldLearnMacFromArpPackets(vpnName, ipToQuery)) {
263                     learnMacFromArpPackets(vpnName, srcInterface, srcIP, srcMac);
264                 }
265             }
266         }
267     }
268
269     private void learnMacFromArpPackets(String vpnName, String srcInterface,
270                                         IpAddress srcIP, PhysAddress srcMac) {
271         String ipToQuery = srcIP.getIpv4Address().getValue();
272         /* Traffic coming from external interfaces should always be learnt */
273         if (interfaceManager.isExternalInterface(srcInterface) ||
274                 !VpnUtil.isNeutronPortConfigured(dataBroker, srcInterface, srcIP)) {
275             synchronized ((vpnName + ipToQuery).intern()) {
276                 VpnUtil.createVpnPortFixedIpToPort(dataBroker, vpnName, ipToQuery, srcInterface,
277                         srcMac.getValue(), false, false, true);
278                 addMipAdjacency(vpnName, srcInterface, srcIP, srcMac.getValue());
279             }
280         }
281     }
282
283     private void handleArpRequestFromExternalInterface(String srcInterface, IpAddress srcIP, PhysAddress srcMac,
284             IpAddress targetIP) {
285         Port port = VpnUtil.getNeutronPortForFloatingIp(dataBroker, targetIP);
286         String floatingIp = targetIP.getIpv4Address().getValue();
287         if (port == null) {
288             LOG.trace("No neutron port found for with floating ip {}", floatingIp);
289             return;
290         }
291
292         MacAddress targetMac = port.getMacAddress();
293         if (targetMac == null) {
294             LOG.trace("No mac address found for floating ip {}", floatingIp);
295             return;
296         }
297
298         // don't allow ARP responses if it arrives from different dpn
299         String localPortInterface = getFloatingInternalInterface(floatingIp);
300         if (localPortInterface != null && !localPortInterface.isEmpty()) {
301             BigInteger dpnIdSrc = InterfaceUtils.getDpnForInterface(ifaceMgrRpcService, srcInterface);
302             BigInteger dpnIdLocal = InterfaceUtils.getDpnForInterface(ifaceMgrRpcService, localPortInterface);
303             if (!dpnIdSrc.equals(dpnIdLocal)) {
304                 LOG.trace("Not same dpnId, so don't respond for ARP - dpnIdSrc:{} dpnIdLocal:{}", dpnIdSrc, dpnIdLocal);
305                 return;
306             }
307         }
308         LOG.trace("Target destination matches floating IP {} so respond for ARP", floatingIp);
309         vpnIfManager.processArpRequest(srcIP, srcMac, targetIP, new PhysAddress(targetMac.getValue()), srcInterface);
310     }
311
312     public void processArpRequest(IpAddress srcIP, PhysAddress srcMac, IpAddress targetIP, PhysAddress targetMac,
313             String srcInterface){
314         //Build ARP response with ARP requests TargetIp TargetMac as the Arp Response SrcIp and SrcMac
315         SendArpResponseInput input = new SendArpResponseInputBuilder().setInterface(srcInterface)
316                 .setDstIpaddress(srcIP).setDstMacaddress(srcMac).setSrcIpaddress(targetIP).setSrcMacaddress(targetMac).build();
317         final String msgFormat = String.format("Send ARP Response on interface %s to destination %s", srcInterface, srcIP);
318         Future<RpcResult<Void>> future = arpManager.sendArpResponse(input);
319         Futures.addCallback(JdkFutureAdapters.listenInPoolThread(future), new FutureCallback<RpcResult<Void>>() {
320             @Override
321             public void onFailure(Throwable error) {
322                 LOG.error("Error - {}", msgFormat, error);
323             }
324
325             @Override
326             public void onSuccess(RpcResult<Void> result) {
327                 if(!result.isSuccessful()) {
328                     LOG.warn("Rpc call to {} failed", msgFormat);
329                 } else {
330                     LOG.debug("Successful RPC Result - {}", msgFormat);
331                 }
332             }
333         });
334     }
335
336     private void addMipAdjacency(String vpnName, String vpnInterface, IpAddress prefix, String mipMacAddress){
337
338         LOG.trace("Adding {} adjacency to VPN Interface {} ",prefix,vpnInterface);
339         InstanceIdentifier<VpnInterface> vpnIfId = VpnUtil.getVpnInterfaceIdentifier(vpnInterface);
340         InstanceIdentifier<Adjacencies> path = vpnIfId.augmentation(Adjacencies.class);
341         synchronized (vpnInterface.intern()) {
342             Optional<Adjacencies> adjacencies = VpnUtil.read(dataBroker, LogicalDatastoreType.CONFIGURATION, path);
343             String nextHopIpAddr = null;
344             String nextHopMacAddress = null;
345             String ip = prefix.getIpv4Address().getValue();
346             if (adjacencies.isPresent()) {
347                 List<Adjacency> adjacencyList = adjacencies.get().getAdjacency();
348                 ip = VpnUtil.getIpPrefix(ip);
349                 for (Adjacency adjacs : adjacencyList) {
350                     if (adjacs.isPrimaryAdjacency()) {
351                         nextHopIpAddr = adjacs.getIpAddress();
352                         nextHopMacAddress = adjacs.getMacAddress();
353                         break;
354                     }
355                 }
356                 if (nextHopIpAddr != null) {
357                     String rd = VpnUtil.getVpnRd(dataBroker, vpnName);
358                     long label =
359                             VpnUtil.getUniqueId(idManager, VpnConstants.VPN_IDPOOL_NAME,
360                                     VpnUtil.getNextHopLabelKey((rd != null) ? rd : vpnName, ip));
361                     if (label == 0) {
362                         LOG.error("Unable to fetch label from Id Manager. Bailing out of adding MIP adjacency {} "
363                                 + "to vpn interface {} for vpn {}", ip, vpnInterface, vpnName);
364                         return;
365                     }
366                     String nextHopIp = nextHopIpAddr.split("/")[0];
367                     AdjacencyBuilder newAdjBuilder = new AdjacencyBuilder().setIpAddress(ip).setKey
368                             (new AdjacencyKey(ip)).setNextHopIpList(Arrays.asList(nextHopIp));
369                     if (mipMacAddress != null && !mipMacAddress.equals(nextHopMacAddress)) {
370                         newAdjBuilder.setMacAddress(mipMacAddress);
371                     }
372                     adjacencyList.add(newAdjBuilder.build());
373                     Adjacencies aug = VpnUtil.getVpnInterfaceAugmentation(adjacencyList);
374                     VpnInterface newVpnIntf = new VpnInterfaceBuilder().setKey(new VpnInterfaceKey(vpnInterface)).
375                             setName(vpnInterface).setVpnInstanceName(vpnName).addAugmentation(Adjacencies.class, aug)
376                             .build();
377                     VpnUtil.syncUpdate(dataBroker, LogicalDatastoreType.CONFIGURATION, vpnIfId, newVpnIntf);
378                     LOG.debug(" Successfully stored subnetroute Adjacency into VpnInterface {}", vpnInterface);
379                 }
380             }
381         }
382
383     }
384
385     private void removeMipAdjacency(String vpnName, String vpnInterface, IpAddress prefix) {
386         String ip = VpnUtil.getIpPrefix(prefix.getIpv4Address().getValue());
387         LOG.trace("Removing {} adjacency from Old VPN Interface {} ", ip,vpnInterface);
388         InstanceIdentifier<VpnInterface> vpnIfId = VpnUtil.getVpnInterfaceIdentifier(vpnInterface);
389         InstanceIdentifier<Adjacencies> path = vpnIfId.augmentation(Adjacencies.class);
390         synchronized (vpnInterface.intern()) {
391             Optional<Adjacencies> adjacencies = VpnUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL, path);
392             if (adjacencies.isPresent()) {
393                 InstanceIdentifier<Adjacency> adjacencyIdentifier = InstanceIdentifier.builder(VpnInterfaces.class).
394                         child(VpnInterface.class, new VpnInterfaceKey(vpnInterface)).augmentation(Adjacencies.class)
395                         .child(Adjacency.class, new AdjacencyKey(ip)).build();
396                 MDSALUtil.syncDelete(dataBroker, LogicalDatastoreType.CONFIGURATION, adjacencyIdentifier);
397                 LOG.trace("Successfully Deleted Adjacency into VpnInterface {}", vpnInterface);
398             }
399         }
400     }
401
402     public String getFloatingInternalInterface(String targetIpValue) {
403         if (targetIpValue == null || targetIpValue.isEmpty()) {
404             return null;
405         }
406         InstanceIdentifier<Floatingips> identifier = InstanceIdentifier.create(Neutron.class).child(Floatingips.class);
407         Optional<Floatingips> optInterface = VpnUtil.read(dataBroker, LogicalDatastoreType.CONFIGURATION, identifier);
408         if (optInterface.isPresent()) {
409             Floatingips fips = optInterface.get();
410             if (fips != null) {
411                 for (Floatingip fip : fips.getFloatingip()) {
412                     String ipv4Addr = fip.getFloatingIpAddress().getIpv4Address().getValue();
413                     if (targetIpValue.equals(ipv4Addr)) {
414                         return fip.getPortId().getValue();
415                     }
416                 }
417             }
418         }
419         return null;
420     }
421
422     private void putVpnIpToMigrateArpCache(String vpnName, String ipToQuery, PhysAddress srcMac) {
423         long cacheSize = config.getArpCacheSize().longValue();
424         if (migrateArpReqCache.size() >= cacheSize) {
425             LOG.debug("ARP_MIGRATE_CACHE: max size {} reached, assuming cache eviction we still put IP {}"
426                     + " vpnName {} with MAC {}", cacheSize, ipToQuery, vpnName, srcMac);
427         }
428         LOG.debug("ARP_MIGRATE_CACHE: add to dirty cache IP {} vpnName {} with MAC {}", ipToQuery, vpnName, srcMac);
429         migrateArpReqCache.put(new ImmutablePair<>(vpnName, ipToQuery),
430                 new BigInteger(String.valueOf(System.currentTimeMillis())));
431     }
432
433     private boolean shouldLearnMacFromArpPackets(String vpnName, String ipToQuery) {
434         if (migrateArpReqCache == null || migrateArpReqCache.size() == 0) {
435             return true;
436         }
437         Pair<String, String> keyPair = new ImmutablePair<>(vpnName, ipToQuery);
438         BigInteger prevTimeStampCached = migrateArpReqCache.getIfPresent(keyPair);
439         if (prevTimeStampCached == null) {
440             LOG.debug("ARP_MIGRATE_CACHE: there is no IP {} vpnName {} in dirty cache, so learn it",
441                     ipToQuery, vpnName);
442             return true;
443         }
444         if (System.currentTimeMillis() > prevTimeStampCached.longValue() + config.getArpLearnTimeout()) {
445             LOG.debug("ARP_MIGRATE_CACHE: older than timeout value - remove from dirty cache IP {} vpnName {}",
446                     ipToQuery, vpnName);
447             migrateArpReqCache.invalidate(keyPair);
448             return true;
449         }
450         LOG.debug("ARP_MIGRATE_CACHE: younger than timeout value - ignore learning IP {} vpnName {}",
451                 ipToQuery, vpnName);
452         return false;
453     }
454 }