Update .gitreview for new repo
[netvirt.git] / openstack / net-virt-providers / src / main / java / org / opendaylight / netvirt / openstack / netvirt / providers / openflow13 / services / arp / ArpSender.java
1 /*
2  * Copyright (c) 2015 Cisco Systems, Inc. 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.netvirt.openstack.netvirt.providers.openflow13.services.arp;
10
11 import static com.google.common.base.Preconditions.checkNotNull;
12
13 import java.util.concurrent.Future;
14
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;
36
37 import com.google.common.util.concurrent.Futures;
38 import com.google.common.util.concurrent.JdkFutureAdapters;
39 import com.google.common.util.concurrent.ListenableFuture;
40
41 /**
42  * Uses packet-out for sending ARP Requests.
43  */
44 public class ArpSender {
45
46     private static final Logger LOG = LoggerFactory.getLogger(ArpSender.class);
47
48     private static final String OFPP_ALL = "0xfffffffc";
49     private final PacketProcessingService packetProcessingService;
50
51     public ArpSender(PacketProcessingService packetProcessingService) {
52         this.packetProcessingService = checkNotNull(packetProcessingService);
53     }
54
55     /**
56      * Sends ARP Request as packet-out from all openflow physical ports on the given node.
57      *
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
60      *        discovered
61      * @param nodeIid the path to node from where the ARP packet will be flooded
62      * @return future result about success of packet-out
63      */
64     public ListenableFuture<RpcResult<Void>> floodArp(ArpMessageAddress senderAddress, Ipv4Address tpa,
65             InstanceIdentifier<Node> nodeIid) {
66         checkNotNull(senderAddress);
67         checkNotNull(tpa);
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);
74     }
75
76     private NodeConnectorId createNodeConnectorId(String connectorId, NodeId nodeId) {
77         return new NodeConnectorId(nodeId.getValue() + ":" + connectorId);
78     }
79
80     /**
81      * Sends ARP Request as packet-out from the given port (node connector).
82      *
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
85      *        discovered
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
88      */
89     public ListenableFuture<RpcResult<Void>> sendArp(ArpMessageAddress senderAddress, Ipv4Address tpa,
90                                                      MacAddress arpRequestDestMacAddress, InstanceIdentifier<NodeConnector> egressNc) {
91         checkNotNull(senderAddress);
92         checkNotNull(tpa);
93         checkNotNull(egressNc);
94         final Ethernet arpFrame = createArpFrame(senderAddress, tpa, arpRequestDestMacAddress);
95         byte[] arpFrameAsBytes;
96         try {
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));
102             }
103             return Futures.immediateFailedFuture(e);
104         }
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)
109             .build();
110         if (LOG.isTraceEnabled()) {
111             LOG.trace("Sending ARP REQUEST \n{}", ArpUtils.getArpFrameToStringFormat(arpFrame));
112         }
113         Future<RpcResult<Void>> futureTransmitPacketResult = packetProcessingService.transmitPacket(packet);
114         return JdkFutureAdapters.listenInPoolThread(futureTransmitPacketResult);
115     }
116
117     private Ethernet createArpFrame(ArpMessageAddress senderAddress, Ipv4Address tpa, MacAddress arpRequestDestMacAddress) {
118         byte[] senderMac = ArpUtils.macToBytes(senderAddress.getHardwareAddress());
119         byte[] senderIp = ArpUtils.ipToBytes(senderAddress.getProtocolAddress());
120         byte[] targetMac;
121         if (arpRequestDestMacAddress != null) {
122             targetMac = ArpUtils.macToBytes(arpRequestDestMacAddress);
123         } else {
124             targetMac = NetUtils.getBroadcastMACAddr();
125         }
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);
136         return arpFrame;
137     }
138
139 }