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