Migrate ListenableFutures.addErrorLogging() callers
[genius.git] / ipv6util / impl / src / main / java / org / opendaylight / genius / ipv6util / nd / Ipv6NsHelper.java
1 /*
2  * Copyright (c) 2017 Red Hat, 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 package org.opendaylight.genius.ipv6util.nd;
9
10 import java.net.InetAddress;
11 import java.net.UnknownHostException;
12 import java.nio.ByteBuffer;
13 import java.util.ArrayList;
14 import java.util.Arrays;
15 import java.util.List;
16 import javax.inject.Inject;
17 import javax.inject.Singleton;
18 import org.opendaylight.genius.ipv6util.api.Icmpv6Type;
19 import org.opendaylight.genius.ipv6util.api.Ipv6Constants;
20 import org.opendaylight.genius.ipv6util.api.Ipv6Util;
21 import org.opendaylight.genius.mdsalutil.ActionInfo;
22 import org.opendaylight.genius.mdsalutil.MDSALUtil;
23 import org.opendaylight.genius.mdsalutil.NwConstants;
24 import org.opendaylight.genius.mdsalutil.actions.ActionGroup;
25 import org.opendaylight.genius.mdsalutil.packet.IPProtocols;
26 import org.opendaylight.infrautils.utils.concurrent.LoggingFutures;
27 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv6Address;
28 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.MacAddress;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.ipv6.nd.packet.rev160620.NeighborSolicitationPacket;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.ipv6.nd.packet.rev160620.NeighborSolicitationPacketBuilder;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorRef;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRef;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.PacketProcessingService;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.TransmitPacketInput;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.TransmitPacketInputBuilder;
40 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
41 import org.opendaylight.yangtools.yang.common.Uint64;
42 import org.slf4j.Logger;
43 import org.slf4j.LoggerFactory;
44
45 @Singleton
46 public class Ipv6NsHelper {
47
48     private static final Logger LOG = LoggerFactory.getLogger(Ipv6NsHelper.class);
49
50     private final PacketProcessingService packetService;
51
52     @Inject
53     public Ipv6NsHelper(final PacketProcessingService packetService) {
54         this.packetService = packetService;
55     }
56
57     private byte[] frameNeighborSolicitationRequest(MacAddress srcMacAddress, Ipv6Address srcIpv6Address,
58             Ipv6Address targetIpv6Address) {
59         MacAddress macAddress = Ipv6Util.getIpv6MulticastMacAddress(targetIpv6Address);
60         Ipv6Address snMcastAddr = Ipv6Util.getIpv6SolicitedNodeMcastAddress(targetIpv6Address);
61
62         NeighborSolicitationPacketBuilder nsPacket = new NeighborSolicitationPacketBuilder();
63         nsPacket.setSourceMac(srcMacAddress);
64         nsPacket.setDestinationMac(macAddress);
65         nsPacket.setEthertype(NwConstants.ETHTYPE_IPV6);
66
67         nsPacket.setVersion(Ipv6Constants.IPV6_VERSION);
68         nsPacket.setFlowLabel((long) 0);
69         nsPacket.setIpv6Length(32);
70         nsPacket.setNextHeader(IPProtocols.IPV6ICMP.shortValue());
71         nsPacket.setHopLimit(Ipv6Constants.ICMP_V6_MAX_HOP_LIMIT);
72         nsPacket.setSourceIpv6(srcIpv6Address);
73         nsPacket.setDestinationIpv6(snMcastAddr);
74
75         nsPacket.setIcmp6Type(Icmpv6Type.NEIGHBOR_SOLICITATION.getValue());
76         nsPacket.setIcmp6Code((short) 0);
77         nsPacket.setIcmp6Chksum(0);
78
79         nsPacket.setReserved((long) 0);
80         nsPacket.setTargetIpAddress(targetIpv6Address);
81         nsPacket.setOptionType(Ipv6Constants.ICMP_V6_OPTION_SOURCE_LLA);
82         nsPacket.setSourceAddrLength((short) 1);
83         nsPacket.setSourceLlAddress(srcMacAddress);
84
85         return fillNeighborSolicitationPacket(nsPacket.build());
86     }
87
88     private byte[] icmp6NsPayloadtoByte(NeighborSolicitationPacket pdu) {
89         byte[] data = new byte[36];
90         Arrays.fill(data, (byte) 0);
91
92         ByteBuffer buf = ByteBuffer.wrap(data);
93         buf.put((byte) pdu.getIcmp6Type().shortValue());
94         buf.put((byte) pdu.getIcmp6Code().shortValue());
95         buf.putShort((short) pdu.getIcmp6Chksum().intValue());
96         buf.putInt((int) pdu.getReserved().longValue());
97         try {
98             byte[] address = null;
99             address = InetAddress.getByName(pdu.getTargetIpAddress().getValue()).getAddress();
100             buf.put(address);
101         } catch (UnknownHostException e) {
102             LOG.error("Serializing NS target address failed", e);
103         }
104
105         buf.put((byte) pdu.getOptionType().shortValue());
106         buf.put((byte) pdu.getSourceAddrLength().shortValue());
107         buf.put(Ipv6Util.bytesFromHexString(pdu.getSourceLlAddress().getValue()));
108         return data;
109     }
110
111     private byte[] fillNeighborSolicitationPacket(NeighborSolicitationPacket pdu) {
112         ByteBuffer buf = ByteBuffer.allocate(Ipv6Constants.ICMPV6_OFFSET + pdu.getIpv6Length().toJava());
113
114         buf.put(Ipv6Util.convertEthernetHeaderToByte(pdu), 0, 14);
115         buf.put(Ipv6Util.convertIpv6HeaderToByte(pdu), 0, 40);
116         buf.put(icmp6NsPayloadtoByte(pdu), 0, pdu.getIpv6Length().toJava());
117         int checksum = Ipv6Util.calculateIcmpv6Checksum(buf.array(), pdu);
118         buf.putShort(Ipv6Constants.ICMPV6_OFFSET + 2, (short) checksum);
119         return buf.array();
120     }
121
122     public boolean transmitNeighborSolicitation(Uint64 dpnId, NodeConnectorRef nodeRef, MacAddress srcMacAddress,
123             Ipv6Address srcIpv6Address, Ipv6Address targetIpv6Address) {
124         byte[] txPayload = frameNeighborSolicitationRequest(srcMacAddress, srcIpv6Address, targetIpv6Address);
125         NodeConnectorRef nodeConnectorRef = MDSALUtil.getNodeConnRef(dpnId, "0xfffffffd");
126         TransmitPacketInput input = new TransmitPacketInputBuilder().setPayload(txPayload)
127                 .setNode(new NodeRef(InstanceIdentifier.builder(Nodes.class)
128                         .child(Node.class, new NodeKey(new NodeId("openflow:" + dpnId))).build()))
129                 .setEgress(nodeRef).setIngress(nodeConnectorRef).build();
130
131         // Tx the packet out of the controller.
132         LOG.debug("Transmitting the Neighbor Solicitation packet out on {}", dpnId);
133         LoggingFutures.addErrorLogging(packetService.transmitPacket(input), LOG, "transmitPacket");
134         return true;
135     }
136
137     public void transmitNeighborSolicitationToOfGroup(Uint64 dpId, MacAddress srcMacAddress,
138             Ipv6Address srcIpv6Address, Ipv6Address targetIpv6Address, long ofGroupId) {
139         byte[] txPayload = frameNeighborSolicitationRequest(srcMacAddress, srcIpv6Address, targetIpv6Address);
140         List<ActionInfo> lstActionInfo = new ArrayList<>();
141         lstActionInfo.add(new ActionGroup(ofGroupId));
142
143         TransmitPacketInput input = MDSALUtil.getPacketOutDefault(lstActionInfo, txPayload, dpId);
144         // Tx the packet out of the controller.
145         LOG.debug(
146                 "Transmitting Neighbor Solicitation packet out. srcMacAddress={}, srcIpv6Address={}, "
147                         + "targetIpv6Address={}, dpId={}, ofGroupId={}",
148                 srcMacAddress.getValue(), srcIpv6Address.getValue(), targetIpv6Address.getValue(), dpId, ofGroupId);
149         LoggingFutures.addErrorLogging(packetService.transmitPacket(input), LOG, "transmitPacket");
150     }
151 }