2 * Copyright (c) 2016, 2017 Ericsson India Global Services Pvt Ltd. and others. All rights reserved.
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
8 package org.opendaylight.genius.arputil.internal;
10 import static com.google.common.base.Preconditions.checkArgument;
11 import static com.google.common.base.Preconditions.checkNotNull;
12 import static org.opendaylight.mdsal.binding.util.Datastore.OPERATIONAL;
14 import com.google.common.util.concurrent.FutureCallback;
15 import com.google.common.util.concurrent.Futures;
16 import com.google.common.util.concurrent.ListenableFuture;
17 import com.google.common.util.concurrent.MoreExecutors;
18 import com.google.common.util.concurrent.SettableFuture;
19 import java.net.InetAddress;
20 import java.net.UnknownHostException;
21 import java.nio.charset.StandardCharsets;
22 import java.util.ArrayList;
23 import java.util.List;
24 import java.util.concurrent.ConcurrentHashMap;
25 import java.util.concurrent.ConcurrentMap;
26 import java.util.concurrent.ExecutionException;
27 import java.util.concurrent.ExecutorService;
28 import java.util.concurrent.Future;
29 import javax.inject.Inject;
30 import javax.inject.Singleton;
31 import org.apache.aries.blueprint.annotation.service.Reference;
32 import org.opendaylight.genius.arputil.api.ArpConstants;
33 import org.opendaylight.genius.mdsalutil.MDSALUtil;
34 import org.opendaylight.genius.mdsalutil.MetaDataUtil;
35 import org.opendaylight.genius.mdsalutil.NWUtil;
36 import org.opendaylight.genius.mdsalutil.packet.ARP;
37 import org.opendaylight.genius.mdsalutil.packet.Ethernet;
38 import org.opendaylight.infrautils.inject.AbstractLifecycle;
39 import org.opendaylight.infrautils.metrics.Meter;
40 import org.opendaylight.infrautils.metrics.MetricProvider;
41 import org.opendaylight.infrautils.utils.concurrent.Executors;
42 import org.opendaylight.mdsal.binding.api.DataBroker;
43 import org.opendaylight.mdsal.binding.api.NotificationPublishService;
44 import org.opendaylight.mdsal.binding.api.NotificationService;
45 import org.opendaylight.mdsal.binding.util.Datastore.Operational;
46 import org.opendaylight.mdsal.binding.util.ManagedNewTransactionRunner;
47 import org.opendaylight.mdsal.binding.util.ManagedNewTransactionRunnerImpl;
48 import org.opendaylight.openflowplugin.libraries.liblldp.HexEncode;
49 import org.opendaylight.openflowplugin.libraries.liblldp.Packet;
50 import org.opendaylight.openflowplugin.libraries.liblldp.PacketException;
51 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IetfInetUtil;
52 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
53 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.MacAddress;
54 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.PhysAddress;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.Action;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNodeConnector;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.arputil.rev160406.ArpRequestReceivedBuilder;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.arputil.rev160406.ArpResponseReceivedBuilder;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.arputil.rev160406.GetMacInput;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.arputil.rev160406.GetMacOutput;
61 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.arputil.rev160406.GetMacOutputBuilder;
62 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.arputil.rev160406.MacChangedBuilder;
63 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.arputil.rev160406.OdlArputilService;
64 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.arputil.rev160406.SendArpRequestInput;
65 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.arputil.rev160406.SendArpRequestInputBuilder;
66 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.arputil.rev160406.SendArpRequestOutput;
67 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.arputil.rev160406.SendArpResponseInput;
68 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.arputil.rev160406.SendArpResponseOutput;
69 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.arputil.rev160406.interfaces.InterfaceAddress;
70 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.GetEgressActionsForInterfaceInputBuilder;
71 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.GetEgressActionsForInterfaceOutput;
72 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.GetInterfaceFromIfIndexInput;
73 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.GetInterfaceFromIfIndexInputBuilder;
74 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.GetInterfaceFromIfIndexOutput;
75 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.GetPortFromInterfaceInputBuilder;
76 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.GetPortFromInterfaceOutput;
77 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.OdlInterfaceRpcService;
78 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorRef;
79 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
80 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRef;
81 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
82 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnector;
83 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
84 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey;
85 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.Metadata;
86 import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.PacketInReason;
87 import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.PacketProcessingListener;
88 import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.PacketProcessingService;
89 import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.PacketReceived;
90 import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.SendToController;
91 import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.TransmitPacketInput;
92 import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.TransmitPacketInputBuilder;
93 import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.TransmitPacketOutput;
94 import org.opendaylight.yangtools.concepts.ListenerRegistration;
95 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
96 import org.opendaylight.yangtools.yang.common.RpcError.ErrorType;
97 import org.opendaylight.yangtools.yang.common.RpcResult;
98 import org.opendaylight.yangtools.yang.common.RpcResultBuilder;
99 import org.opendaylight.yangtools.yang.common.Uint64;
100 import org.slf4j.Logger;
101 import org.slf4j.LoggerFactory;
104 public class ArpUtilImpl extends AbstractLifecycle implements OdlArputilService, PacketProcessingListener {
105 private static final Logger LOG = LoggerFactory.getLogger(ArpUtilImpl.class);
106 private static final String MODULENAME = "odl.genius.arputil.";
107 private static final String OPENFLOW_PFX = "openflow:";
109 private final ManagedNewTransactionRunner txRunner;
110 private final PacketProcessingService packetProcessingService;
111 private final NotificationPublishService notificationPublishService;
112 private final NotificationService notificationService;
113 private final OdlInterfaceRpcService odlInterfaceRpcService;
114 private ListenerRegistration<ArpUtilImpl> listenerRegistration;
115 private final ExecutorService threadPool = Executors.newFixedThreadPool(1, "ArpUtil", LOG);
116 private final ConcurrentMap<String, String> macsDB = new ConcurrentHashMap<>();
117 private final ConcurrentMap<String, SettableFuture<RpcResult<GetMacOutput>>> macAddrs = new ConcurrentHashMap<>();
119 private final Meter arpRespRecvd;
120 private final Meter arpRespRecvdNotification;
121 private final Meter arpRespRecvdNotificationRejected;
122 private final Meter arpReqRecvd;
123 private final Meter arpReqRecvdNotification;
124 private final Meter arpReqRecvdNotificationRejected;
128 public ArpUtilImpl(@Reference final DataBroker dataBroker,
129 final PacketProcessingService packetProcessingService,
130 @Reference final NotificationPublishService notificationPublishService,
131 @Reference final NotificationService notificationService,
132 final OdlInterfaceRpcService odlInterfaceRpcService,
133 @Reference final MetricProvider metricProvider) {
134 this.txRunner = new ManagedNewTransactionRunnerImpl(dataBroker);
135 this.packetProcessingService = packetProcessingService;
136 this.notificationPublishService = notificationPublishService;
137 this.notificationService = notificationService;
138 this.odlInterfaceRpcService = odlInterfaceRpcService;
140 arpRespRecvd = metricProvider.newMeter(this,MODULENAME + "arpResponseReceived");
141 arpRespRecvdNotification = metricProvider.newMeter(this,MODULENAME + "arpResponseReceivedNotification");
142 arpRespRecvdNotificationRejected = metricProvider.newMeter(this,
143 MODULENAME + "arpResponseReceivedNotificationRejected");
144 arpReqRecvd = metricProvider.newMeter(this,MODULENAME + "arpRequestReceived");
145 arpReqRecvdNotification = metricProvider.newMeter(this,MODULENAME + "arpRequestReceivedNotification");
146 arpReqRecvdNotificationRejected = metricProvider.newMeter(this,
147 MODULENAME + "arpRequestReceivedNotificationRejected");
151 public void start() {
152 LOG.info("{} start", getClass().getSimpleName());
153 listenerRegistration = notificationService.registerNotificationListener(this);
158 LOG.info("{} stop", getClass().getSimpleName());
160 if (listenerRegistration != null) {
161 listenerRegistration.close();
162 listenerRegistration = null;
166 private String getIpAddressInString(IpAddress ipAddress) throws UnknownHostException {
167 return InetAddress.getByName(ipAddress.getIpv4Address().getValue()).getHostAddress();
171 public ListenableFuture<RpcResult<GetMacOutput>> getMac(GetMacInput input) {
173 final String dstIpAddress = getIpAddressInString(input.getIpaddress());
174 LOG.trace("getMac rpc invoked for ip {}", dstIpAddress);
175 if (macAddrs.get(dstIpAddress) != null) {
176 if (LOG.isInfoEnabled()) {
177 LOG.info("get mac already in progress for the ip {}", dstIpAddress);
179 return macAddrs.get(dstIpAddress);
181 SendArpRequestInputBuilder builder = new SendArpRequestInputBuilder()
182 .setInterfaceAddress(input.getInterfaceAddress()).setIpaddress(input.getIpaddress());
183 ListenableFuture<RpcResult<SendArpRequestOutput>> arpReqFt = sendArpRequest(builder.build());
184 final SettableFuture<RpcResult<GetMacOutput>> ft = SettableFuture.create();
186 Futures.addCallback(arpReqFt, new FutureCallback<RpcResult<SendArpRequestOutput>>() {
188 public void onFailure(Throwable ex) {
189 RpcResultBuilder<GetMacOutput> resultBuilder = RpcResultBuilder.<GetMacOutput>failed()
190 .withError(ErrorType.APPLICATION, ex.getMessage(), ex);
191 ft.set(resultBuilder.build());
195 public void onSuccess(RpcResult<SendArpRequestOutput> result) {
196 LOG.trace("Successfully sent the arp pkt out for ip {}", dstIpAddress);
198 }, MoreExecutors.directExecutor());
200 macAddrs.put(dstIpAddress, ft);
202 } catch (UnknownHostException e) {
203 LOG.error("Failed to handle getMac request for {}", input.getIpaddress(), e);
204 RpcResultBuilder<GetMacOutput> resultBuilder = RpcResultBuilder.<GetMacOutput>failed()
205 .withError(ErrorType.APPLICATION, e.getMessage(), e);
206 return Futures.immediateFuture(resultBuilder.build());
210 private byte[] getIpAddressBytes(IpAddress ip) throws UnknownHostException {
211 return InetAddress.getByName(ip.getIpv4Address().getValue()).getAddress();
215 public ListenableFuture<RpcResult<SendArpRequestOutput>> sendArpRequest(SendArpRequestInput arpReqInput) {
216 LOG.trace("rpc sendArpRequest invoked for ip {}", arpReqInput.getIpaddress());
219 String interfaceName = null;
224 RpcResultBuilder<SendArpRequestOutput> failureBuilder = RpcResultBuilder.failed();
225 RpcResultBuilder<SendArpRequestOutput> successBuilder = RpcResultBuilder.success();
228 dstIpBytes = getIpAddressBytes(arpReqInput.getIpaddress());
229 } catch (UnknownHostException e) {
230 LOG.error("Cannot get IP address", e);
231 failureBuilder.withError(ErrorType.APPLICATION, ArpConstants.UNKNOWN_IP_ADDRESS_SUPPLIED);
232 return Futures.immediateFuture(failureBuilder.build());
235 int localErrorCount = 0;
236 for (InterfaceAddress interfaceAddress : arpReqInput.nonnullInterfaceAddress()) {
238 interfaceName = interfaceAddress.getInterface();
239 srcIpBytes = getIpAddressBytes(interfaceAddress.getIpAddress());
241 GetPortFromInterfaceOutput portResult = getPortFromInterface(interfaceName);
242 checkNotNull(portResult);
243 dpnId = portResult.getDpid();
244 Long portid = portResult.getPortno().toJava();
245 checkArgument(null != dpnId && !Uint64.ZERO.equals(dpnId),
246 ArpConstants.DPN_NOT_FOUND_ERROR, interfaceName);
248 NodeConnectorRef ref = MDSALUtil.getNodeConnRef(dpnId, portid.toString());
249 checkNotNull(ref, ArpConstants.NODE_CONNECTOR_NOT_FOUND_ERROR, interfaceName);
251 LOG.trace("sendArpRequest received dpnId {} out interface {}", dpnId, interfaceName);
252 if (interfaceAddress.getMacaddress() == null) {
253 srcMac = txRunner.<Operational, ExecutionException, byte[]>
254 applyInterruptiblyWithNewReadOnlyTransactionAndClose(OPERATIONAL,
255 tx -> tx.read((InstanceIdentifier<NodeConnector>) ref.getValue()).get()
256 .map(nc -> nc.augmentation(FlowCapableNodeConnector.class))
257 .map(FlowCapableNodeConnector::getHardwareAddress)
258 .map(MacAddress::getValue)
259 .map(HexEncode::bytesFromHexString)
262 String macAddr = interfaceAddress.getMacaddress().getValue();
263 srcMac = HexEncode.bytesFromHexString(macAddr);
265 checkNotNull(srcMac, ArpConstants.FAILED_TO_GET_SRC_MAC_FOR_INTERFACE, interfaceName, ref.getValue());
266 checkNotNull(srcIpBytes, ArpConstants.FAILED_TO_GET_SRC_IP_FOR_INTERFACE, interfaceName);
268 payload = ArpPacketUtil.getPayload(ArpConstants.ARP_REQUEST_OP, srcMac, srcIpBytes,
269 ArpPacketUtil.ETHERNET_BROADCAST_DESTINATION, dstIpBytes);
271 List<Action> actions = getEgressAction(interfaceName);
272 sendPacketOutWithActions(dpnId, payload, ref, actions);
274 LOG.trace("sent arp request for {}", arpReqInput.getIpaddress());
275 } catch (UnknownHostException | PacketException | InterruptedException | ExecutionException e) {
276 LOG.trace("failed to send arp req for {} on interface {}", arpReqInput.getIpaddress(), interfaceName);
278 failureBuilder.withError(ErrorType.APPLICATION,
279 ArpConstants.FAILED_TO_SEND_ARP_REQ_FOR_INTERFACE + interfaceName, e);
280 successBuilder.withError(ErrorType.APPLICATION,
281 ArpConstants.FAILED_TO_SEND_ARP_REQ_FOR_INTERFACE + interfaceName, e);
285 if (localErrorCount == arpReqInput.getInterfaceAddress().size()) {
286 // All the requests failed
287 return Futures.immediateFuture(failureBuilder.build());
289 return Futures.immediateFuture(successBuilder.build());
292 public ListenableFuture<RpcResult<TransmitPacketOutput>> sendPacketOut(
293 Uint64 dpnId, byte[] payload, NodeConnectorRef ref) {
294 NodeConnectorRef nodeConnectorRef = MDSALUtil.getNodeConnRef(dpnId, "0xfffffffd");
295 return packetProcessingService.transmitPacket(new TransmitPacketInputBuilder().setPayload(payload)
296 .setNode(new NodeRef(InstanceIdentifier.builder(Nodes.class)
297 .child(Node.class, new NodeKey(new NodeId(OPENFLOW_PFX + dpnId))).build()))
298 .setIngress(nodeConnectorRef).setEgress(ref).build());
301 private Future<RpcResult<TransmitPacketOutput>> sendPacketOutWithActions(
302 Uint64 dpnId, byte[] payload, NodeConnectorRef ref, List<Action> actions) {
303 NodeConnectorRef nodeConnectorRef = MDSALUtil.getNodeConnRef(dpnId, "0xfffffffd");
304 TransmitPacketInput transmitPacketInput = new TransmitPacketInputBuilder().setPayload(payload)
305 .setNode(new NodeRef(InstanceIdentifier.builder(Nodes.class)
306 .child(Node.class, new NodeKey(new NodeId(OPENFLOW_PFX + dpnId))).build()))
307 .setIngress(nodeConnectorRef).setEgress(ref).setAction(actions).build();
308 LOG.trace("PacketOut message framed for transmitting {}", transmitPacketInput);
309 return packetProcessingService.transmitPacket(transmitPacketInput);
312 private List<Action> getEgressAction(String interfaceName) {
313 List<Action> actions = new ArrayList<>();
315 GetEgressActionsForInterfaceInputBuilder egressAction = new GetEgressActionsForInterfaceInputBuilder()
316 .setIntfName(interfaceName);
317 OdlInterfaceRpcService intfRpc = odlInterfaceRpcService;
318 if (intfRpc == null) {
319 LOG.error("Unable to obtain interfaceMgrRpc service, ignoring egress actions for interfaceName {}",
323 Future<RpcResult<GetEgressActionsForInterfaceOutput>> result = intfRpc
324 .getEgressActionsForInterface(egressAction.build());
325 RpcResult<GetEgressActionsForInterfaceOutput> rpcResult = result.get();
326 if (!rpcResult.isSuccessful()) {
327 LOG.warn("RPC Call to Get egress actions for interface {} returned with Errors {}", interfaceName,
328 rpcResult.getErrors());
330 actions = rpcResult.getResult().getAction();
332 } catch (InterruptedException | ExecutionException e) {
333 LOG.error("Exception when egress actions for interface {}", interfaceName, e);
339 public ListenableFuture<RpcResult<SendArpResponseOutput>> sendArpResponse(SendArpResponseInput input) {
340 LOG.trace("sendArpResponse rpc invoked");
346 String interfaceName = input.getInterface();
347 GetPortFromInterfaceOutput portResult = getPortFromInterface(interfaceName);
348 checkNotNull(portResult);
349 dpnId = portResult.getDpid();
350 Long portid = portResult.getPortno().toJava();
351 NodeConnectorRef ref = MDSALUtil.getNodeConnRef(dpnId, portid.toString());
352 checkArgument(null != dpnId && !Uint64.ZERO.equals(dpnId),
353 ArpConstants.DPN_NOT_FOUND_ERROR, interfaceName);
354 checkNotNull(ref, ArpConstants.NODE_CONNECTOR_NOT_FOUND_ERROR, interfaceName);
356 LOG.trace("sendArpRequest received dpnId {} out interface {}", dpnId, interfaceName);
358 byte[] srcIpBytes = getIpAddressBytes(input.getSrcIpaddress());
359 byte[] dstIpBytes = getIpAddressBytes(input.getDstIpaddress());
360 if (input.getSrcMacaddress() == null) {
361 srcMac = portResult.getPhyAddress().getBytes(StandardCharsets.UTF_8);
363 String macAddr = input.getSrcMacaddress().getValue();
364 srcMac = HexEncode.bytesFromHexString(macAddr);
366 byte[] dstMac = NWUtil.parseMacAddress(input.getDstMacaddress().getValue());
367 checkNotNull(srcIpBytes, ArpConstants.FAILED_TO_GET_SRC_IP_FOR_INTERFACE, interfaceName);
368 payload = ArpPacketUtil.getPayload(ArpConstants.ARP_RESPONSE_OP, srcMac, srcIpBytes, dstMac, dstIpBytes);
370 List<Action> actions = getEgressAction(interfaceName);
371 sendPacketOutWithActions(dpnId, payload, ref, actions);
372 LOG.debug("Sent ARP response for IP {}, from source MAC {} to target MAC {} and target IP {} via dpnId {}",
373 input.getSrcIpaddress().getIpv4Address().getValue(), HexEncode.bytesToHexStringFormat(srcMac),
374 HexEncode.bytesToHexStringFormat(dstMac), input.getDstIpaddress().getIpv4Address().getValue(),
376 } catch (UnknownHostException | PacketException | InterruptedException | ExecutionException e) {
377 LOG.error("failed to send arp response for {}: ", input.getSrcIpaddress(), e);
378 return RpcResultBuilder.<SendArpResponseOutput>failed()
379 .withError(ErrorType.APPLICATION, e.getMessage(), e).buildFuture();
381 RpcResultBuilder<SendArpResponseOutput> rpcResultBuilder = RpcResultBuilder.success();
382 return Futures.immediateFuture(rpcResultBuilder.build());
386 public void onPacketReceived(PacketReceived packetReceived) {
387 Class<? extends PacketInReason> pktInReason = packetReceived.getPacketInReason();
388 LOG.trace("Packet Received {}", packetReceived);
390 if (pktInReason == SendToController.class) {
392 Uint64 dpnId = extractDpnId(packetReceived);
393 int tableId = packetReceived.getTableId().getValue().toJava();
395 byte[] data = packetReceived.getPayload();
396 Ethernet ethernet = new Ethernet();
398 ethernet.deserialize(data, 0, data.length * Byte.SIZE);
399 if (ethernet.getEtherType() != ArpConstants.ETH_TYPE_ARP) {
403 Packet pkt = ethernet.getPayload();
405 InetAddress srcInetAddr = InetAddress.getByAddress(arp.getSenderProtocolAddress());
406 InetAddress dstInetAddr = InetAddress.getByAddress(arp.getTargetProtocolAddress());
407 byte[] srcMac = ethernet.getSourceMACAddress();
408 byte[] dstMac = ethernet.getDestinationMACAddress();
410 Metadata metadata = packetReceived.getMatch().getMetadata();
412 String interfaceName = getInterfaceName(metadata);
414 checkAndFireMacChangedNotification(interfaceName, srcInetAddr, srcMac);
415 macsDB.put(interfaceName + "-" + srcInetAddr.getHostAddress(), NWUtil.toStringMacAddress(srcMac));
416 if (arp.getOpCode() == ArpConstants.ARP_REQUEST_OP) {
417 fireArpReqRecvdNotification(interfaceName, srcInetAddr, srcMac, dstInetAddr, dpnId, tableId,
418 metadata.getMetadata());
420 fireArpRespRecvdNotification(interfaceName, srcInetAddr, srcMac, dpnId, tableId,
421 metadata.getMetadata(), dstInetAddr, dstMac);
423 if (macAddrs.get(srcInetAddr.getHostAddress()) != null) {
424 threadPool.execute(new MacResponderTask(arp));
426 } catch (PacketException | UnknownHostException | InterruptedException | ExecutionException e) {
427 LOG.trace("Failed to decode packet", e);
432 private GetPortFromInterfaceOutput getPortFromInterface(String interfaceName)
433 throws InterruptedException, ExecutionException {
434 GetPortFromInterfaceInputBuilder getPortFromInterfaceInputBuilder = new GetPortFromInterfaceInputBuilder();
435 getPortFromInterfaceInputBuilder.setIntfName(interfaceName);
437 Future<RpcResult<GetPortFromInterfaceOutput>> portFromInterface = odlInterfaceRpcService
438 .getPortFromInterface(getPortFromInterfaceInputBuilder.build());
439 GetPortFromInterfaceOutput result = portFromInterface.get().getResult();
440 LOG.trace("getPortFromInterface rpc result is {} ", result);
441 if (result != null) {
442 LOG.trace("getPortFromInterface rpc result is {} {} ", result.getDpid(), result.getPortno());
447 private String getInterfaceName(Metadata metadata)
448 throws InterruptedException, ExecutionException {
449 LOG.debug("metadata received is {} ", metadata);
451 GetInterfaceFromIfIndexInputBuilder ifIndexInputBuilder = new GetInterfaceFromIfIndexInputBuilder();
452 Uint64 lportTag = MetaDataUtil.getLportFromMetadata(metadata.getMetadata());
454 ifIndexInputBuilder.setIfIndex(lportTag.intValue());
455 GetInterfaceFromIfIndexInput input = ifIndexInputBuilder.build();
457 Future<RpcResult<GetInterfaceFromIfIndexOutput>> interfaceFromIfIndex = odlInterfaceRpcService
458 .getInterfaceFromIfIndex(input);
459 if (interfaceFromIfIndex.get().isSuccessful()) {
460 GetInterfaceFromIfIndexOutput interfaceFromIfIndexOutput = interfaceFromIfIndex.get().getResult();
461 return interfaceFromIfIndexOutput.getInterfaceName();
463 LOG.error("RPC call to get interface name for if index {} failed with errors {}", lportTag,
464 interfaceFromIfIndex.get().getErrors());
469 private class MacResponderTask implements Runnable {
472 MacResponderTask(ARP arp) {
479 GetMacOutputBuilder outputBuilder;
482 srcAddr = InetAddress.getByAddress(arp.getSenderProtocolAddress());
483 srcMac = NWUtil.toStringMacAddress(arp.getSenderHardwareAddress());
484 SettableFuture<RpcResult<GetMacOutput>> future = macAddrs.remove(srcAddr.getHostAddress());
485 if (future == null) {
486 LOG.trace("There are no pending mac requests.");
489 outputBuilder = new GetMacOutputBuilder().setMacaddress(new PhysAddress(srcMac));
490 future.set(RpcResultBuilder.success(outputBuilder.build()).build());
491 if (LOG.isTraceEnabled()) {
492 LOG.trace("sent the mac response for ip {}", srcAddr.getHostAddress());
494 } catch (UnknownHostException e) {
495 LOG.error("failed to send mac response", e);
500 private void fireArpRespRecvdNotification(String interfaceName, InetAddress srcInetAddr, byte[] srcMacAddressBytes,
501 Uint64 dpnId, int tableId, Uint64 metadata, InetAddress dstInetAddr, byte[] dstMacAddressBytes)
502 throws InterruptedException {
505 IpAddress srcIp = IetfInetUtil.INSTANCE.ipAddressFor(srcInetAddr);
506 IpAddress dstIp = IetfInetUtil.INSTANCE.ipAddressFor(dstInetAddr);
507 String srcMacAddress = NWUtil.toStringMacAddress(srcMacAddressBytes);
508 PhysAddress srcMac = new PhysAddress(srcMacAddress);
509 String dstMacAddress = NWUtil.toStringMacAddress(dstMacAddressBytes);
510 PhysAddress dstMac = new PhysAddress(dstMacAddress);
511 ArpResponseReceivedBuilder builder = new ArpResponseReceivedBuilder();
512 builder.setInterface(interfaceName);
513 builder.setSrcIpaddress(srcIp);
514 builder.setDpnId(dpnId);
515 builder.setOfTableId((long) tableId);
516 builder.setSrcMac(srcMac);
517 builder.setMetadata(metadata);
518 builder.setDstIpaddress(dstIp);
519 builder.setDstMac(dstMac);
520 ListenableFuture<?> offerNotification = notificationPublishService.offerNotification(builder.build());
521 if (offerNotification != null && offerNotification.equals(NotificationPublishService.REJECTED)) {
522 arpRespRecvdNotificationRejected.mark();
525 arpRespRecvdNotification.mark();
529 private void fireArpReqRecvdNotification(String interfaceName, InetAddress srcInetAddr, byte[] srcMac,
530 InetAddress dstInetAddr, Uint64 dpnId, int tableId, Uint64 metadata) throws InterruptedException {
532 String macAddress = NWUtil.toStringMacAddress(srcMac);
533 ArpRequestReceivedBuilder builder = new ArpRequestReceivedBuilder();
534 builder.setInterface(interfaceName);
535 builder.setDpnId(dpnId);
536 builder.setOfTableId((long) tableId);
537 builder.setSrcIpaddress(IetfInetUtil.INSTANCE.ipAddressFor(srcInetAddr));
538 builder.setDstIpaddress(IetfInetUtil.INSTANCE.ipAddressFor(dstInetAddr));
539 builder.setSrcMac(new PhysAddress(macAddress));
540 builder.setMetadata(metadata);
541 ListenableFuture<?> offerNotification = notificationPublishService.offerNotification(builder.build());
542 if (offerNotification != null && offerNotification.equals(NotificationPublishService.REJECTED)) {
543 arpReqRecvdNotificationRejected.mark();
545 arpReqRecvdNotification.mark();
549 private void checkAndFireMacChangedNotification(String interfaceName, InetAddress inetAddr, byte[] macAddressBytes)
550 throws InterruptedException {
552 IpAddress ip = IetfInetUtil.INSTANCE.ipAddressFor(inetAddr);
553 String macAddress = NWUtil.toStringMacAddress(macAddressBytes);
554 PhysAddress mac = new PhysAddress(macAddress);
556 if (!macAddress.equals(macsDB.get(interfaceName + "-" + inetAddr.getHostAddress()))) {
557 if (LOG.isTraceEnabled()) {
558 LOG.trace("mac address changed for {}", inetAddr);
560 MacChangedBuilder builder = new MacChangedBuilder();
561 builder.setInterface(interfaceName);
562 builder.setIpaddress(ip);
563 builder.setMacaddress(mac);
564 notificationPublishService.putNotification(builder.build());
568 private Uint64 extractDpnId(PacketReceived packetReceived) {
569 NodeKey nodeKey = packetReceived.getIngress().getValue().firstKeyOf(Node.class);
570 String nodeKeyString = nodeKey.getId().getValue();
572 if (!nodeKeyString.startsWith(OPENFLOW_PFX)) {
573 LOG.warn("Could not extract DPN for packet-in, doesn't start with 'openflow:' {}", packetReceived);
577 return Uint64.valueOf(nodeKeyString.substring(OPENFLOW_PFX.length()));