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