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