2 * Copyright (c) 2015 Cisco Systems, Inc. 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
9 package org.opendaylight.netvirt.openstack.netvirt.providers.openflow13.services.arp;
11 import static com.google.common.base.Preconditions.checkNotNull;
13 import java.util.concurrent.Future;
15 import org.opendaylight.controller.liblldp.EtherTypes;
16 import org.opendaylight.controller.liblldp.Ethernet;
17 import org.opendaylight.controller.liblldp.NetUtils;
18 import org.opendaylight.controller.liblldp.PacketException;
19 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv4Address;
20 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev100924.MacAddress;
21 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId;
22 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorRef;
23 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
24 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRef;
25 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnector;
26 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnectorKey;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.PacketProcessingService;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.TransmitPacketInput;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.TransmitPacketInputBuilder;
32 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
33 import org.opendaylight.yangtools.yang.common.RpcResult;
34 import org.slf4j.Logger;
35 import org.slf4j.LoggerFactory;
37 import com.google.common.util.concurrent.Futures;
38 import com.google.common.util.concurrent.JdkFutureAdapters;
39 import com.google.common.util.concurrent.ListenableFuture;
42 * Uses packet-out for sending ARP Requests.
44 public class ArpSender {
46 private static final Logger LOG = LoggerFactory.getLogger(ArpSender.class);
48 private static final String OFPP_ALL = "0xfffffffc";
49 private final PacketProcessingService packetProcessingService;
51 public ArpSender(PacketProcessingService packetProcessingService) {
52 this.packetProcessingService = checkNotNull(packetProcessingService);
56 * Sends ARP Request as packet-out from all openflow physical ports on the given node.
58 * @param senderAddress the addresses used in sender part of ARP packet
59 * @param tpa the target protocol address, in this case IPv4 address for which MAC should be
61 * @param nodeIid the path to node from where the ARP packet will be flooded
62 * @return future result about success of packet-out
64 public ListenableFuture<RpcResult<Void>> floodArp(ArpMessageAddress senderAddress, Ipv4Address tpa,
65 InstanceIdentifier<Node> nodeIid) {
66 checkNotNull(senderAddress);
68 checkNotNull(nodeIid);
69 // node connector representing all physical ports on node
70 NodeConnectorKey nodeConnectorKey = new NodeConnectorKey(createNodeConnectorId(OFPP_ALL,
71 nodeIid.firstKeyOf(Node.class, NodeKey.class).getId()));
72 InstanceIdentifier<NodeConnector> egressNc = nodeIid.child(NodeConnector.class, nodeConnectorKey);
73 return sendArp(senderAddress, tpa, null, egressNc);
76 private NodeConnectorId createNodeConnectorId(String connectorId, NodeId nodeId) {
77 return new NodeConnectorId(nodeId.getValue() + ":" + connectorId);
81 * Sends ARP Request as packet-out from the given port (node connector).
83 * @param senderAddress the addresses used in sender part of ARP packet
84 * @param tpa the target protocol address, in this case IPv4 address for which MAC should be
86 * @param arpRequestDestMacAddress the destination MAC address to be used in the ARP packet or null if not known.
87 * @param egressNc the path to node connector from where the ARP packet will be sent @return future result about success of packet-out
89 public ListenableFuture<RpcResult<Void>> sendArp(ArpMessageAddress senderAddress, Ipv4Address tpa,
90 MacAddress arpRequestDestMacAddress, InstanceIdentifier<NodeConnector> egressNc) {
91 checkNotNull(senderAddress);
93 checkNotNull(egressNc);
94 final Ethernet arpFrame = createArpFrame(senderAddress, tpa, arpRequestDestMacAddress);
95 byte[] arpFrameAsBytes;
97 arpFrameAsBytes = arpFrame.serialize();
98 } catch (PacketException e) {
99 LOG.warn("Serializition of ARP packet is not successful.", e);
100 if (LOG.isDebugEnabled()) {
101 LOG.debug("ARP packet: {}", ArpUtils.getArpFrameToStringFormat(arpFrame));
103 return Futures.immediateFailedFuture(e);
105 // Generate packet with destination switch and port
106 TransmitPacketInput packet = new TransmitPacketInputBuilder().setEgress(new NodeConnectorRef(egressNc))
107 .setNode(new NodeRef(egressNc.firstIdentifierOf(Node.class)))
108 .setPayload(arpFrameAsBytes)
110 if (LOG.isTraceEnabled()) {
111 LOG.trace("Sending ARP REQUEST \n{}", ArpUtils.getArpFrameToStringFormat(arpFrame));
113 Future<RpcResult<Void>> futureTransmitPacketResult = packetProcessingService.transmitPacket(packet);
114 return JdkFutureAdapters.listenInPoolThread(futureTransmitPacketResult);
117 private Ethernet createArpFrame(ArpMessageAddress senderAddress, Ipv4Address tpa, MacAddress arpRequestDestMacAddress) {
118 byte[] senderMac = ArpUtils.macToBytes(senderAddress.getHardwareAddress());
119 byte[] senderIp = ArpUtils.ipToBytes(senderAddress.getProtocolAddress());
121 if (arpRequestDestMacAddress != null) {
122 targetMac = ArpUtils.macToBytes(arpRequestDestMacAddress);
124 targetMac = NetUtils.getBroadcastMACAddr();
126 byte[] targetIp = ArpUtils.ipToBytes(tpa);
127 Ethernet arpFrame = new Ethernet().setSourceMACAddress(senderMac)
128 .setDestinationMACAddress(targetMac)
129 .setEtherType(EtherTypes.ARP.shortValue());
130 Arp arp = new Arp().setOperation(ArpOperation.REQUEST.intValue())
131 .setSenderHardwareAddress(senderMac)
132 .setSenderProtocolAddress(senderIp)
133 .setTargetHardwareAddress(targetMac)
134 .setTargetProtocolAddress(targetIp);
135 arpFrame.setPayload(arp);