Merge "ITM Tep Auto Config Unit test using Guice."
[genius.git] / arputil / arputil-impl / src / main / java / org / opendaylight / genius / arputil / internal / ArpUtilImpl.java
1 /*
2  * Copyright (c) 2016, 2017 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
9 package org.opendaylight.genius.arputil.internal;
10
11 import static com.google.common.base.Preconditions.checkArgument;
12 import static com.google.common.base.Preconditions.checkNotNull;
13
14 import com.google.common.base.Optional;
15 import com.google.common.util.concurrent.FutureCallback;
16 import com.google.common.util.concurrent.Futures;
17 import com.google.common.util.concurrent.JdkFutureAdapters;
18 import com.google.common.util.concurrent.ListenableFuture;
19 import com.google.common.util.concurrent.SettableFuture;
20 import java.math.BigInteger;
21 import java.net.InetAddress;
22 import java.net.UnknownHostException;
23 import java.util.ArrayList;
24 import java.util.List;
25 import java.util.concurrent.ConcurrentHashMap;
26 import java.util.concurrent.ConcurrentMap;
27 import java.util.concurrent.ExecutionException;
28 import java.util.concurrent.ExecutorService;
29 import java.util.concurrent.Executors;
30 import java.util.concurrent.Future;
31 import javax.inject.Inject;
32 import javax.inject.Singleton;
33 import org.opendaylight.controller.liblldp.HexEncode;
34 import org.opendaylight.controller.liblldp.NetUtils;
35 import org.opendaylight.controller.liblldp.Packet;
36 import org.opendaylight.controller.liblldp.PacketException;
37 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
38 import org.opendaylight.controller.md.sal.binding.api.NotificationPublishService;
39 import org.opendaylight.controller.md.sal.binding.api.NotificationService;
40 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
41 import org.opendaylight.genius.mdsalutil.MDSALUtil;
42 import org.opendaylight.genius.mdsalutil.MetaDataUtil;
43 import org.opendaylight.genius.mdsalutil.NWUtil;
44 import org.opendaylight.genius.mdsalutil.packet.ARP;
45 import org.opendaylight.genius.mdsalutil.packet.Ethernet;
46 import org.opendaylight.infrautils.inject.AbstractLifecycle;
47 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
48 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.Interfaces;
49 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.InterfacesState;
50 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface;
51 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.InterfaceKey;
52 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.PhysAddress;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.Action;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.arputil.rev160406.ArpRequestReceivedBuilder;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.arputil.rev160406.ArpResponseReceivedBuilder;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.arputil.rev160406.GetMacInput;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.arputil.rev160406.GetMacOutput;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.arputil.rev160406.GetMacOutputBuilder;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.arputil.rev160406.MacChangedBuilder;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.arputil.rev160406.OdlArputilService;
61 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.arputil.rev160406.SendArpRequestInput;
62 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.arputil.rev160406.SendArpRequestInputBuilder;
63 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.arputil.rev160406.SendArpResponseInput;
64 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.arputil.rev160406.interfaces.InterfaceAddress;
65 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.GetEgressActionsForInterfaceInputBuilder;
66 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.GetEgressActionsForInterfaceOutput;
67 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.GetInterfaceFromIfIndexInput;
68 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.GetInterfaceFromIfIndexInputBuilder;
69 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.GetInterfaceFromIfIndexOutput;
70 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.GetPortFromInterfaceInputBuilder;
71 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.GetPortFromInterfaceOutput;
72 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.OdlInterfaceRpcService;
73 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId;
74 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorRef;
75 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
76 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRef;
77 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
78 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnector;
79 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
80 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey;
81 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.Metadata;
82 import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.PacketInReason;
83 import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.PacketProcessingListener;
84 import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.PacketProcessingService;
85 import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.PacketReceived;
86 import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.SendToController;
87 import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.TransmitPacketInputBuilder;
88 import org.opendaylight.yangtools.concepts.ListenerRegistration;
89 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
90 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.InstanceIdentifierBuilder;
91 import org.opendaylight.yangtools.yang.common.RpcError.ErrorType;
92 import org.opendaylight.yangtools.yang.common.RpcResult;
93 import org.opendaylight.yangtools.yang.common.RpcResultBuilder;
94 import org.slf4j.Logger;
95 import org.slf4j.LoggerFactory;
96
97 @Singleton
98 public class ArpUtilImpl extends AbstractLifecycle implements OdlArputilService, PacketProcessingListener {
99     private static final Logger LOG = LoggerFactory.getLogger(ArpUtilImpl.class);
100     private final DataBroker dataBroker;
101     private final PacketProcessingService packetProcessingService;
102     private final NotificationPublishService notificationPublishService;
103     private final NotificationService notificationService;
104     private final OdlInterfaceRpcService odlInterfaceRpcService;
105
106     private ListenerRegistration<ArpUtilImpl> listenerRegistration;
107
108     private static final String FAILED_TO_GET_SRC_IP_FOR_INTERFACE = "Failed to get src ip for %s";
109     private static final String FAILED_TO_GET_SRC_MAC_FOR_INTERFACE = "Failed to get src mac for interface %s iid %s ";
110     private static final String FAILED_TO_SEND_ARP_REQ_FOR_INTERFACE = "failed to send arp req for interface ";
111     private static final String UNKNOWN_IP_ADDRESS_SUPPLIED = "unknown ip address supplied";
112     private static final String NODE_CONNECTOR_NOT_FOUND_ERROR = "Node connector id not found for interface %s";
113     private static final String DPN_NOT_FOUND_ERROR = "dpn not found for interface %s ";
114     private static final short ARP_REQUEST_OP = (short) 1;
115     private static final short ARP_RESPONSE_OP = (short) 2;
116     private static final short ETH_TYPE_ARP = 0x0806;
117
118     private final ExecutorService threadPool = Executors.newFixedThreadPool(1);
119
120     private final ConcurrentMap<String, String> macsDB = new ConcurrentHashMap<>();
121     private final ConcurrentMap<String, SettableFuture<RpcResult<GetMacOutput>>> macAddrs = new ConcurrentHashMap<>();
122
123     @Inject
124     public ArpUtilImpl(final DataBroker dataBroker, final PacketProcessingService packetProcessingService,
125             final NotificationPublishService notificationPublishService, final NotificationService notificationService,
126             final OdlInterfaceRpcService odlInterfaceRpcService) {
127         this.dataBroker = dataBroker;
128         this.packetProcessingService = packetProcessingService;
129         this.notificationPublishService = notificationPublishService;
130         this.notificationService = notificationService;
131         this.odlInterfaceRpcService = odlInterfaceRpcService;
132     }
133
134     @Override
135     public void start() {
136         LOG.info("{} start", getClass().getSimpleName());
137         listenerRegistration = notificationService.registerNotificationListener(this);
138     }
139
140     @Override
141     public void stop() {
142         LOG.info("{} stop", getClass().getSimpleName());
143
144         if (listenerRegistration != null) {
145             listenerRegistration.close();
146             listenerRegistration = null;
147         }
148     }
149
150     private String getIpAddressInString(IpAddress ipAddress) throws UnknownHostException {
151         return InetAddress.getByName(ipAddress.getIpv4Address().getValue()).getHostAddress();
152     }
153
154     @Override
155     public Future<RpcResult<GetMacOutput>> getMac(GetMacInput input) {
156         try {
157             final String dstIpAddress = getIpAddressInString(input.getIpaddress());
158             LOG.trace("getMac rpc invoked for ip {}", dstIpAddress);
159             if (macAddrs.get(dstIpAddress) != null) {
160                 if (LOG.isInfoEnabled()) {
161                     LOG.info("get mac already in progress for the ip {}", dstIpAddress);
162                 }
163                 return macAddrs.get(dstIpAddress);
164             }
165             SendArpRequestInputBuilder builder = new SendArpRequestInputBuilder()
166                     .setInterfaceAddress(input.getInterfaceAddress()).setIpaddress(input.getIpaddress());
167             Future<RpcResult<Void>> arpReqFt = sendArpRequest(builder.build());
168             final SettableFuture<RpcResult<GetMacOutput>> ft = SettableFuture.create();
169
170             Futures.addCallback(JdkFutureAdapters.listenInPoolThread(arpReqFt, threadPool),
171                     new FutureCallback<RpcResult<Void>>() {
172                         @Override
173                         public void onFailure(Throwable ex) {
174                             RpcResultBuilder<GetMacOutput> resultBuilder = RpcResultBuilder.<GetMacOutput>failed()
175                                     .withError(ErrorType.APPLICATION, ex.getMessage(), ex);
176                             ft.set(resultBuilder.build());
177                         }
178
179                         @Override
180                         public void onSuccess(RpcResult<Void> result) {
181                             LOG.trace("Successfully sent the arp pkt out for ip {}", dstIpAddress);
182                         }
183                     });
184
185             macAddrs.put(dstIpAddress, ft);
186             return ft;
187         } catch (UnknownHostException e) {
188             LOG.error("Failed to handle getMac request for {}", input.getIpaddress(), e);
189             RpcResultBuilder<GetMacOutput> resultBuilder = RpcResultBuilder.<GetMacOutput>failed()
190                     .withError(ErrorType.APPLICATION, e.getMessage(), e);
191             return Futures.immediateFuture(resultBuilder.build());
192         }
193     }
194
195     private byte[] getIpAddressBytes(IpAddress ip) throws UnknownHostException {
196         return InetAddress.getByName(ip.getIpv4Address().getValue()).getAddress();
197     }
198
199     @Override
200     public Future<RpcResult<Void>> sendArpRequest(SendArpRequestInput arpReqInput) {
201         LOG.trace("rpc sendArpRequest invoked for ip {}", arpReqInput.getIpaddress());
202         BigInteger dpnId;
203         byte[] payload;
204         String interfaceName = null;
205         byte[] srcIpBytes;
206         byte[] dstIpBytes = null;
207         byte[] srcMac = null;
208
209         RpcResultBuilder<Void> failureBuilder = RpcResultBuilder.failed();
210         RpcResultBuilder<Void> successBuilder = RpcResultBuilder.success();
211
212         try {
213             dstIpBytes = getIpAddressBytes(arpReqInput.getIpaddress());
214         } catch (UnknownHostException e) {
215             LOG.error("Cannot get IP address", e);
216             failureBuilder.withError(ErrorType.APPLICATION, UNKNOWN_IP_ADDRESS_SUPPLIED);
217             return Futures.immediateFuture(failureBuilder.build());
218         }
219
220         int localErrorCount = 0;
221         for (InterfaceAddress interfaceAddress : arpReqInput.getInterfaceAddress()) {
222             try {
223                 interfaceName = interfaceAddress.getInterface();
224                 srcIpBytes = getIpAddressBytes(interfaceAddress.getIpAddress());
225
226                 NodeConnectorId id = getNodeConnectorFromInterfaceName(interfaceName);
227
228                 GetPortFromInterfaceOutput portResult = getPortFromInterface(interfaceName);
229                 checkNotNull(portResult);
230                 dpnId = portResult.getDpid();
231                 Long portid = portResult.getPortno();
232                 checkArgument(null != dpnId && !BigInteger.ZERO.equals(dpnId), DPN_NOT_FOUND_ERROR, interfaceName);
233
234                 NodeConnectorRef ref = MDSALUtil.getNodeConnRef(dpnId, portid.toString());
235                 checkNotNull(ref, NODE_CONNECTOR_NOT_FOUND_ERROR, interfaceName);
236
237                 LOG.trace("sendArpRequest received dpnId {} out interface {}", dpnId, interfaceName);
238                 if (interfaceAddress.getMacaddress() == null) {
239                     srcMac = MDSALUtil.getMacAddressForNodeConnector(dataBroker,
240                             (InstanceIdentifier<NodeConnector>) ref.getValue());
241                 } else {
242                     String macAddr = interfaceAddress.getMacaddress().getValue();
243                     srcMac = HexEncode.bytesFromHexString(macAddr);
244                 }
245                 checkNotNull(srcMac, FAILED_TO_GET_SRC_MAC_FOR_INTERFACE, interfaceName, ref.getValue());
246                 checkNotNull(srcIpBytes, FAILED_TO_GET_SRC_IP_FOR_INTERFACE, interfaceName);
247
248                 payload = ArpPacketUtil.getPayload(ARP_REQUEST_OP, srcMac, srcIpBytes,
249                         ArpPacketUtil.ETHERNET_BROADCAST_DESTINATION, dstIpBytes);
250
251                 List<Action> actions = getEgressAction(interfaceName);
252                 sendPacketOutWithActions(dpnId, payload, ref, actions);
253
254                 LOG.trace("sent arp request for {}", arpReqInput.getIpaddress());
255             } catch (UnknownHostException | PacketException | InterruptedException | ExecutionException e) {
256                 LOG.trace("failed to send arp req for {} on interface {}", arpReqInput.getIpaddress(), interfaceName);
257
258                 failureBuilder.withError(ErrorType.APPLICATION, FAILED_TO_SEND_ARP_REQ_FOR_INTERFACE + interfaceName,
259                         e);
260                 successBuilder.withError(ErrorType.APPLICATION, FAILED_TO_SEND_ARP_REQ_FOR_INTERFACE + interfaceName,
261                         e);
262                 localErrorCount++;
263             }
264         }
265         if (localErrorCount == arpReqInput.getInterfaceAddress().size()) {
266             // All the requests failed
267             return Futures.immediateFuture(failureBuilder.build());
268         }
269         return Futures.immediateFuture(successBuilder.build());
270     }
271
272     public Future<RpcResult<Void>> sendPacketOut(BigInteger dpnId, byte[] payload, NodeConnectorRef ref) {
273
274         NodeConnectorRef nodeConnectorRef = MDSALUtil.getNodeConnRef(dpnId, "0xfffffffd");
275         return packetProcessingService.transmitPacket(new TransmitPacketInputBuilder().setPayload(payload)
276                 .setNode(new NodeRef(InstanceIdentifier.builder(Nodes.class)
277                         .child(Node.class, new NodeKey(new NodeId("openflow:" + dpnId))).toInstance()))
278                 .setIngress(nodeConnectorRef).setEgress(ref).build());
279     }
280
281     public Future<RpcResult<Void>> sendPacketOutWithActions(BigInteger dpnId, byte[] payload, NodeConnectorRef ref,
282             List<Action> actions) {
283
284         NodeConnectorRef nodeConnectorRef = MDSALUtil.getNodeConnRef(dpnId, "0xfffffffd");
285         return packetProcessingService.transmitPacket(new TransmitPacketInputBuilder().setPayload(payload)
286                 .setNode(new NodeRef(InstanceIdentifier.builder(Nodes.class)
287                         .child(Node.class, new NodeKey(new NodeId("openflow:" + dpnId))).toInstance()))
288                 .setIngress(nodeConnectorRef).setEgress(ref).setAction(actions).build());
289     }
290
291     private List<Action> getEgressAction(String interfaceName) {
292         List<Action> actions = new ArrayList<>();
293         try {
294             GetEgressActionsForInterfaceInputBuilder egressAction = new GetEgressActionsForInterfaceInputBuilder()
295                     .setIntfName(interfaceName);
296             OdlInterfaceRpcService intfRpc = odlInterfaceRpcService;
297             if (intfRpc == null) {
298                 LOG.error("Unable to obtain interfaceMgrRpc service, ignoring egress actions for interfaceName {}",
299                         interfaceName);
300                 return actions;
301             }
302             Future<RpcResult<GetEgressActionsForInterfaceOutput>> result = intfRpc
303                     .getEgressActionsForInterface(egressAction.build());
304             RpcResult<GetEgressActionsForInterfaceOutput> rpcResult = result.get();
305             if (!rpcResult.isSuccessful()) {
306                 LOG.warn("RPC Call to Get egress actions for interface {} returned with Errors {}", interfaceName,
307                         rpcResult.getErrors());
308             } else {
309                 actions = rpcResult.getResult().getAction();
310             }
311         } catch (InterruptedException | ExecutionException e) {
312             LOG.error("Exception when egress actions for interface {}", interfaceName, e);
313         }
314         return actions;
315     }
316
317     @Override
318     public Future<RpcResult<Void>> sendArpResponse(SendArpResponseInput input) {
319         LOG.trace("sendArpResponse rpc invoked");
320         BigInteger dpnId;
321         byte[] payload;
322         byte[] srcMac;
323
324         try {
325             String interfaceName = input.getInterface();
326             GetPortFromInterfaceOutput portResult = getPortFromInterface(interfaceName);
327             checkNotNull(portResult);
328             dpnId = portResult.getDpid();
329             Long portid = portResult.getPortno();
330             NodeConnectorRef ref = MDSALUtil.getNodeConnRef(dpnId, portid.toString());
331             checkArgument(null != dpnId && !BigInteger.ZERO.equals(dpnId), DPN_NOT_FOUND_ERROR, interfaceName);
332             checkNotNull(ref, NODE_CONNECTOR_NOT_FOUND_ERROR, interfaceName);
333
334             LOG.trace("sendArpRequest received dpnId {} out interface {}", dpnId, interfaceName);
335
336             byte[] srcIpBytes = getIpAddressBytes(input.getSrcIpaddress());
337             byte[] dstIpBytes = getIpAddressBytes(input.getDstIpaddress());
338             if (input.getSrcMacaddress() == null) {
339                 srcMac = portResult.getPhyAddress().getBytes();
340             } else {
341                 String macAddr = input.getSrcMacaddress().getValue();
342                 srcMac = HexEncode.bytesFromHexString(macAddr);
343             }
344             byte[] dstMac = NWUtil.parseMacAddress(input.getDstMacaddress().getValue());
345             checkNotNull(srcIpBytes, FAILED_TO_GET_SRC_IP_FOR_INTERFACE, interfaceName);
346             payload = ArpPacketUtil.getPayload(ARP_RESPONSE_OP, srcMac, srcIpBytes, dstMac, dstIpBytes);
347
348             List<Action> actions = getEgressAction(interfaceName);
349             sendPacketOutWithActions(dpnId, payload, ref, actions);
350             LOG.debug("Sent ARP response for IP {}, from source MAC {} to target MAC {} and target IP {} via dpnId {}",
351                     input.getSrcIpaddress().getIpv4Address().getValue(), HexEncode.bytesToHexStringFormat(srcMac),
352                     HexEncode.bytesToHexStringFormat(dstMac), input.getDstIpaddress().getIpv4Address().getValue(),
353                     dpnId);
354         } catch (UnknownHostException | PacketException | InterruptedException | ExecutionException e) {
355             LOG.error("failed to send arp response for {}: ", input.getSrcIpaddress(), e);
356             return RpcResultBuilder.<Void>failed().withError(ErrorType.APPLICATION, e.getMessage(), e).buildFuture();
357         }
358         RpcResultBuilder<Void> rpcResultBuilder = RpcResultBuilder.success();
359         return Futures.immediateFuture(rpcResultBuilder.build());
360     }
361
362     @Override
363     public void onPacketReceived(PacketReceived packetReceived) {
364         Class<? extends PacketInReason> pktInReason = packetReceived.getPacketInReason();
365         LOG.trace("Packet Received {}", packetReceived);
366
367         if (pktInReason == SendToController.class) {
368
369             try {
370                 int tableId = packetReceived.getTableId().getValue();
371
372                 byte[] data = packetReceived.getPayload();
373                 Ethernet ethernet = new Ethernet();
374
375                 ethernet.deserialize(data, 0, data.length * NetUtils.NumBitsInAByte);
376                 if (ethernet.getEtherType() != ETH_TYPE_ARP) {
377                     return;
378                 }
379
380                 Packet pkt = ethernet.getPayload();
381                 ARP arp = (ARP) pkt;
382                 InetAddress srcInetAddr = InetAddress.getByAddress(arp.getSenderProtocolAddress());
383                 InetAddress dstInetAddr = InetAddress.getByAddress(arp.getTargetProtocolAddress());
384                 InetAddress addr = srcInetAddr;
385                 // For GARP learn target IP
386                 if (srcInetAddr.getHostAddress().equalsIgnoreCase(dstInetAddr.getHostAddress())) {
387                     addr = dstInetAddr;
388                 }
389                 byte[] srcMac = ethernet.getSourceMACAddress();
390                 byte[] dstMac = ethernet.getDestinationMACAddress();
391
392                 NodeConnectorRef ref = packetReceived.getIngress();
393
394                 Metadata metadata = packetReceived.getMatch().getMetadata();
395
396                 String interfaceName = getInterfaceName(ref, metadata, dataBroker);
397
398                 checkAndFireMacChangedNotification(interfaceName, srcInetAddr, srcMac);
399                 macsDB.put(interfaceName + "-" + srcInetAddr.getHostAddress(), NWUtil.toStringMacAddress(srcMac));
400                 if (arp.getOpCode() == ARP_REQUEST_OP) {
401                     fireArpReqRecvdNotification(interfaceName, srcInetAddr, srcMac, dstInetAddr, tableId,
402                             metadata.getMetadata());
403                 } else {
404                     fireArpRespRecvdNotification(interfaceName, srcInetAddr, srcMac, tableId, metadata.getMetadata(),
405                             dstInetAddr, dstMac);
406                 }
407                 if (macAddrs.get(srcInetAddr.getHostAddress()) != null) {
408                     threadPool.submit(new MacResponderTask(arp));
409                 }
410
411             } catch (PacketException | UnknownHostException | InterruptedException | ExecutionException e) {
412                 LOG.trace("Failed to decode packet", e);
413             }
414         }
415     }
416
417     private GetPortFromInterfaceOutput getPortFromInterface(String interfaceName)
418             throws InterruptedException, ExecutionException {
419         GetPortFromInterfaceInputBuilder getPortFromInterfaceInputBuilder = new GetPortFromInterfaceInputBuilder();
420         getPortFromInterfaceInputBuilder.setIntfName(interfaceName);
421
422         Future<RpcResult<GetPortFromInterfaceOutput>> portFromInterface = odlInterfaceRpcService
423                 .getPortFromInterface(getPortFromInterfaceInputBuilder.build());
424         GetPortFromInterfaceOutput result = portFromInterface.get().getResult();
425         LOG.trace("getPortFromInterface rpc result is {} ", result);
426         if (result != null) {
427             LOG.trace("getPortFromInterface rpc result is {} {} ", result.getDpid(), result.getPortno());
428         }
429         return result;
430     }
431
432     private String getInterfaceName(NodeConnectorRef ref, Metadata metadata, DataBroker dataBroker2)
433             throws InterruptedException, ExecutionException {
434         LOG.debug("metadata received is {} ", metadata);
435
436         GetInterfaceFromIfIndexInputBuilder ifIndexInputBuilder = new GetInterfaceFromIfIndexInputBuilder();
437         BigInteger lportTag = MetaDataUtil.getLportFromMetadata(metadata.getMetadata());
438
439         ifIndexInputBuilder.setIfIndex(lportTag.intValue());
440         GetInterfaceFromIfIndexInput input = ifIndexInputBuilder.build();
441
442         Future<RpcResult<GetInterfaceFromIfIndexOutput>> interfaceFromIfIndex = odlInterfaceRpcService
443                 .getInterfaceFromIfIndex(input);
444         GetInterfaceFromIfIndexOutput interfaceFromIfIndexOutput = interfaceFromIfIndex.get().getResult();
445         return interfaceFromIfIndexOutput.getInterfaceName();
446     }
447
448     class MacResponderTask implements Runnable {
449         ARP arp;
450
451         MacResponderTask(ARP arp) {
452             this.arp = arp;
453         }
454
455         @Override
456         public void run() {
457             InetAddress srcAddr;
458             GetMacOutputBuilder outputBuilder;
459             String srcMac;
460             SettableFuture<RpcResult<GetMacOutput>> future = null;
461             RpcResultBuilder<GetMacOutput> resultBuilder;
462             try {
463                 srcAddr = InetAddress.getByAddress(arp.getSenderProtocolAddress());
464                 srcMac = NWUtil.toStringMacAddress(arp.getSenderHardwareAddress());
465                 future = macAddrs.remove(srcAddr.getHostAddress());
466                 if (future == null) {
467                     LOG.trace("There are no pending mac requests.");
468                     return;
469                 }
470                 outputBuilder = new GetMacOutputBuilder().setMacaddress(new PhysAddress(srcMac));
471                 resultBuilder = RpcResultBuilder.success(outputBuilder.build());
472                 if (LOG.isTraceEnabled()) {
473                     LOG.trace("sent the mac response for ip {}", srcAddr.getHostAddress());
474                 }
475             } catch (UnknownHostException e) {
476                 LOG.error("failed to send mac response", e);
477                 resultBuilder = RpcResultBuilder.<GetMacOutput>failed().withError(ErrorType.APPLICATION, e.getMessage(),
478                         e);
479             }
480             future.set(resultBuilder.build());
481         }
482     }
483
484     private void fireArpRespRecvdNotification(String interfaceName, InetAddress srcInetAddr, byte[] srcMacAddressBytes,
485             int tableId, BigInteger metadata, InetAddress dstInetAddr, byte[] dstMacAddressBytes)
486                     throws InterruptedException {
487         ArpUtilCounters.arp_res_rcv.inc();
488
489         IpAddress srcIp = new IpAddress(srcInetAddr.getHostAddress().toCharArray());
490         IpAddress dstIp = new IpAddress(dstInetAddr.getHostAddress().toCharArray());
491         String srcMacAddress = NWUtil.toStringMacAddress(srcMacAddressBytes);
492         PhysAddress srcMac = new PhysAddress(srcMacAddress);
493         String dstMacAddress = NWUtil.toStringMacAddress(dstMacAddressBytes);
494         PhysAddress dstMac = new PhysAddress(dstMacAddress);
495         ArpResponseReceivedBuilder builder = new ArpResponseReceivedBuilder();
496         builder.setInterface(interfaceName);
497         builder.setSrcIpaddress(srcIp);
498         builder.setOfTableId((long) tableId);
499         builder.setSrcMac(srcMac);
500         builder.setMetadata(metadata);
501         builder.setDstIpaddress(dstIp);
502         builder.setDstMac(dstMac);
503         ListenableFuture<?> offerNotification = notificationPublishService.offerNotification(builder.build());
504         if (offerNotification != null && offerNotification.equals(NotificationPublishService.REJECTED)) {
505             ArpUtilCounters.arp_res_rcv_notification_rejected.inc();
506         } else {
507             ArpUtilCounters.arp_res_rcv_notification.inc();
508         }
509     }
510
511     private void fireArpReqRecvdNotification(String interfaceName, InetAddress srcInetAddr, byte[] srcMac,
512             InetAddress dstInetAddr, int tableId, BigInteger metadata) throws InterruptedException {
513         ArpUtilCounters.arp_req_rcv.inc();
514         String macAddress = NWUtil.toStringMacAddress(srcMac);
515         ArpRequestReceivedBuilder builder = new ArpRequestReceivedBuilder();
516         builder.setInterface(interfaceName);
517         builder.setOfTableId((long) tableId);
518         builder.setSrcIpaddress(new IpAddress(srcInetAddr.getHostAddress().toCharArray()));
519         builder.setDstIpaddress(new IpAddress(dstInetAddr.getHostAddress().toCharArray()));
520         builder.setSrcMac(new PhysAddress(macAddress));
521         builder.setMetadata(metadata);
522         ListenableFuture<?> offerNotification = notificationPublishService.offerNotification(builder.build());
523         if (offerNotification != null && offerNotification.equals(NotificationPublishService.REJECTED)) {
524             ArpUtilCounters.arp_req_rcv_notification_rejected.inc();
525         } else {
526             ArpUtilCounters.arp_req_rcv_notification.inc();
527         }
528     }
529
530     private void checkAndFireMacChangedNotification(String interfaceName, InetAddress inetAddr, byte[] macAddressBytes)
531             throws InterruptedException {
532
533         IpAddress ip = new IpAddress(inetAddr.getHostAddress().toCharArray());
534         String macAddress = NWUtil.toStringMacAddress(macAddressBytes);
535         PhysAddress mac = new PhysAddress(macAddress);
536
537         if (!macAddress.equals(macsDB.get(interfaceName + "-" + inetAddr.getHostAddress()))) {
538             if (LOG.isTraceEnabled()) {
539                 LOG.trace("mac address changed for " + inetAddr);
540             }
541             MacChangedBuilder builder = new MacChangedBuilder();
542             builder.setInterface(interfaceName);
543             builder.setIpaddress(ip);
544             builder.setMacaddress(mac);
545             notificationPublishService.putNotification(builder.build());
546         }
547     }
548
549     private InstanceIdentifier<Interface> buildInterfaceId(String interfaceName) {
550         InstanceIdentifierBuilder<Interface> idBuilder = InstanceIdentifier.builder(Interfaces.class)
551                 .child(Interface.class, new InterfaceKey(interfaceName));
552         return idBuilder.build();
553     }
554
555     private NodeConnectorId getNodeConnectorFromInterfaceName(String interfaceName) {
556         InstanceIdentifierBuilder<org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508
557             .interfaces.state.Interface> idBuilder = InstanceIdentifier.builder(InterfacesState.class)
558             .child(org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508
559             .interfaces.state.Interface.class, new org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf
560             .interfaces.rev140508.interfaces.state.InterfaceKey(interfaceName));
561
562         InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf
563             .interfaces.rev140508.interfaces.state.Interface> ifStateId = idBuilder.build();
564
565         Optional<org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf
566             .interfaces.rev140508.interfaces.state.Interface> ifStateOptional = MDSALUtil
567                 .read(dataBroker, LogicalDatastoreType.OPERATIONAL, ifStateId);
568
569         if (ifStateOptional.isPresent()) {
570             org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508
571                 .interfaces.state.Interface ifState = ifStateOptional
572                     .get();
573             List<String> lowerLayerIf = ifState.getLowerLayerIf();
574             if (!lowerLayerIf.isEmpty()) {
575                 return new NodeConnectorId(lowerLayerIf.get(0));
576             }
577         }
578         return null;
579     }
580 }