Bug-5644: Fix checkstyle invocation for l2switch builds
[l2switch.git] / packethandler / implementation / src / main / java / org / opendaylight / l2switch / packethandler / decoders / Ipv6Decoder.java
1 /*
2  * Copyright (c) 2014 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 package org.opendaylight.l2switch.packethandler.decoders;
9
10 import java.net.InetAddress;
11 import java.net.UnknownHostException;
12 import java.util.ArrayList;
13 import java.util.Arrays;
14 import java.util.List;
15
16 import org.opendaylight.controller.sal.binding.api.NotificationProviderService;
17 import org.opendaylight.l2switch.packethandler.decoders.utils.BitBufferHelper;
18 import org.opendaylight.l2switch.packethandler.decoders.utils.BufferException;
19 import org.opendaylight.l2switch.packethandler.decoders.utils.NetUtils;
20 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Dscp;
21 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv6Address;
22 import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.basepacket.rev140528.packet.chain.grp.PacketChain;
23 import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.basepacket.rev140528.packet.chain.grp.PacketChainBuilder;
24 import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.basepacket.rev140528.packet.chain.grp.packet.chain.Packet;
25 import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.ethernet.rev140528.EthernetPacketListener;
26 import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.ethernet.rev140528.EthernetPacketReceived;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.ethernet.rev140528.KnownEtherType;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.ethernet.rev140528.ethernet.packet.received.packet.chain.packet.EthernetPacket;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.ipv4.rev140528.KnownIpProtocols;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.ipv6.rev140528.Ipv6PacketReceived;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.ipv6.rev140528.Ipv6PacketReceivedBuilder;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.ipv6.rev140528.ipv6.packet.fields.ExtensionHeaders;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.ipv6.rev140528.ipv6.packet.fields.ExtensionHeadersBuilder;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.ipv6.rev140528.ipv6.packet.received.packet.chain.packet.Ipv6PacketBuilder;
35 import org.opendaylight.yangtools.yang.binding.NotificationListener;
36 import org.slf4j.Logger;
37 import org.slf4j.LoggerFactory;
38
39 /**
40  * IPv6 Packet Decoder
41  */
42 public class Ipv6Decoder extends AbstractPacketDecoder<EthernetPacketReceived, Ipv6PacketReceived>
43         implements EthernetPacketListener {
44
45     private static final Logger LOG = LoggerFactory.getLogger(Ipv6Decoder.class);
46
47     public Ipv6Decoder(NotificationProviderService notificationProviderService) {
48         super(Ipv6PacketReceived.class, notificationProviderService);
49     }
50
51     /**
52      * Decode an EthernetPacket into an Ipv4Packet
53      */
54     @Override
55     public Ipv6PacketReceived decode(EthernetPacketReceived ethernetPacketReceived) {
56         Ipv6PacketReceivedBuilder ipv6ReceivedBuilder = new Ipv6PacketReceivedBuilder();
57
58         // Find the latest packet in the packet-chain, which is an
59         // EthernetPacket
60         List<PacketChain> packetChainList = ethernetPacketReceived.getPacketChain();
61         EthernetPacket ethernetPacket = (EthernetPacket) packetChainList.get(packetChainList.size() - 1).getPacket();
62         int bitOffset = ethernetPacket.getPayloadOffset() * NetUtils.NumBitsInAByte;
63         byte[] data = ethernetPacketReceived.getPayload();
64
65         Ipv6PacketBuilder builder = new Ipv6PacketBuilder();
66         try {
67             builder.setVersion(BitBufferHelper.getShort(BitBufferHelper.getBits(data, bitOffset, 4)));
68             if (builder.getVersion().intValue() != 6) {
69                 LOG.debug("Version should be 6, but is {}", builder.getVersion());
70             }
71
72             builder.setDscp(new Dscp(BitBufferHelper.getShort(BitBufferHelper.getBits(data, bitOffset + 4, 6))));
73             builder.setEcn(BitBufferHelper.getShort(BitBufferHelper.getBits(data, bitOffset + 10, 2)));
74             builder.setFlowLabel(BitBufferHelper.getLong(BitBufferHelper.getBits(data, bitOffset + 12, 20)));
75             builder.setIpv6Length(BitBufferHelper.getInt(BitBufferHelper.getBits(data, bitOffset + 32, 16)));
76             builder.setNextHeader(KnownIpProtocols
77                     .forValue(BitBufferHelper.getInt(BitBufferHelper.getBits(data, bitOffset + 48, 8))));
78             builder.setHopLimit(BitBufferHelper.getShort(BitBufferHelper.getBits(data, bitOffset + 56, 8)));
79             builder.setSourceIpv6(Ipv6Address.getDefaultInstance(
80                     InetAddress.getByAddress(BitBufferHelper.getBits(data, bitOffset + 64, 128)).getHostAddress()));
81             builder.setDestinationIpv6(Ipv6Address.getDefaultInstance(
82                     InetAddress.getByAddress(BitBufferHelper.getBits(data, bitOffset + 192, 128)).getHostAddress()));
83             builder.setPayloadOffset((320 + bitOffset) / NetUtils.NumBitsInAByte);
84             builder.setPayloadLength(builder.getIpv6Length());
85
86             // Decode the optional "extension headers"
87             List<ExtensionHeaders> extensionHeaders = new ArrayList<ExtensionHeaders>();
88             KnownIpProtocols nextHeader = builder.getNextHeader();
89             int extHeaderOffset = 0;
90             while (nextHeader != null && !nextHeader.equals(KnownIpProtocols.Tcp)
91                     && !nextHeader.equals(KnownIpProtocols.Udp)) {
92                 // Set the extension header's type & length & data
93                 short nextHeaderType = BitBufferHelper
94                         .getShort(BitBufferHelper.getBits(data, 320 + extHeaderOffset + bitOffset, 8));
95                 nextHeader = KnownIpProtocols.forValue(nextHeaderType);
96                 int octetLength = BitBufferHelper
97                         .getInt(BitBufferHelper.getBits(data, 328 + extHeaderOffset + bitOffset, 8));
98                 int start = (336 + extHeaderOffset + bitOffset) / NetUtils.NumBitsInAByte;
99                 int end = start + 6 + octetLength;
100
101                 extensionHeaders.add(new ExtensionHeadersBuilder().setNextHeader(nextHeader).setLength(octetLength)
102                         .setData(Arrays.copyOfRange(data, start, end)).build());
103
104                 // Update the NextHeader field
105                 extHeaderOffset += 64 + octetLength * NetUtils.NumBitsInAByte;
106             }
107             if (!extensionHeaders.isEmpty()) {
108                 builder.setExtensionHeaders(extensionHeaders);
109             }
110         } catch (BufferException | UnknownHostException e) {
111             LOG.debug("Exception while decoding IPv4 packet", e.getMessage());
112         }
113
114         // build ipv6
115         packetChainList.add(new PacketChainBuilder().setPacket(builder.build()).build());
116         ipv6ReceivedBuilder.setPacketChain(packetChainList);
117
118         // carry forward the original payload.
119         ipv6ReceivedBuilder.setPayload(ethernetPacketReceived.getPayload());
120
121         return ipv6ReceivedBuilder.build();
122     }
123
124     @Override
125     public NotificationListener getConsumedNotificationListener() {
126         return this;
127     }
128
129     @Override
130     public void onEthernetPacketReceived(EthernetPacketReceived notification) {
131         decodeAndPublish(notification);
132     }
133
134     @Override
135     public boolean canDecode(EthernetPacketReceived ethernetPacketReceived) {
136         if (ethernetPacketReceived == null || ethernetPacketReceived.getPacketChain() == null)
137             return false;
138
139         // Only decode the latest packet in the chain
140         EthernetPacket ethernetPacket = null;
141         if (!ethernetPacketReceived.getPacketChain().isEmpty()) {
142             Packet packet = ethernetPacketReceived.getPacketChain()
143                     .get(ethernetPacketReceived.getPacketChain().size() - 1).getPacket();
144             if (packet instanceof EthernetPacket) {
145                 ethernetPacket = (EthernetPacket) packet;
146             }
147         }
148
149         return ethernetPacket != null && KnownEtherType.Ipv6.equals(ethernetPacket.getEthertype());
150     }
151 }