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