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