1 package org.opendaylight.l2switch.packethandler.decoders;
3 import org.opendaylight.controller.sal.packet.BitBufferHelper;
4 import org.opendaylight.controller.sal.packet.BufferException;
5 import org.opendaylight.controller.sal.utils.HexEncode;
6 import org.opendaylight.controller.sal.utils.NetUtils;
7 import org.opendaylight.l2switch.packethandler.decoders.PacketDecoder;
8 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev100924.MacAddress;
9 import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.basepacket.rev140528.Packet;
10 import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.basepacket.rev140528.PacketType;
11 import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.basepacket.rev140528.packet.PacketPayloadTypeBuilder;
12 import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.basepacket.rev140528.packet.RawPacket;
13 import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.basepacket.rev140528.packet.RawPacketBuilder;
14 import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.ethernet.rev140528.EthernetPacketBuilder;
15 import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.ethernet.rev140528.EthernetPacketGrp;
16 import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.ethernet.rev140528.EthernetPacketReceivedBuilder;
17 import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.ethernet.rev140528.Header8021qType;
18 import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.ethernet.rev140528.KnownEtherType;
19 import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.ethernet.rev140528.ethernet.packet.grp.Header8021q;
20 import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.ethernet.rev140528.ethernet.packet.grp.Header8021qBuilder;
21 import org.opendaylight.yangtools.yang.binding.Notification;
22 import org.slf4j.Logger;
23 import org.slf4j.LoggerFactory;
25 import java.util.ArrayList;
26 import java.util.Arrays;
29 * Ethernet Packet Decoder
31 public class EthernetDecoder implements PacketDecoder {
32 private static final Logger _logger = LoggerFactory.getLogger(EthernetDecoder.class);
33 public static final Integer LENGTH_MAX = 1500;
34 public static final Integer ETHERTYPE_MIN = 1536;
35 public static final Integer ETHERTYPE_8021Q = 0x8100;
36 public static final Integer ETHERTYPE_QINQ = 0x9100;
39 * Decode a RawPacket into an EthernetPacket
41 * @param packet -- data from wire to deserialize
43 * @throws BufferException
46 public Packet decode(Packet packet) {
47 RawPacket rawPacket = packet.getRawPacket();
48 EthernetPacketBuilder builder = new EthernetPacketBuilder();
49 byte[] data = rawPacket.getPayload();
52 // Save original rawPacket
53 builder.setRawPacket(new RawPacketBuilder().setIngress(rawPacket.getIngress()).setPayload(data).build());
55 // Deserialize the destination & source fields
56 builder.setDestinationMac(new MacAddress(HexEncode.bytesToHexStringFormat(BitBufferHelper.getBits(data, 0, 48))));
57 builder.setSourceMac(new MacAddress(HexEncode.bytesToHexStringFormat(BitBufferHelper.getBits(data, 48, 48))));
59 // Deserialize the optional field 802.1Q headers
60 Integer nextField = BitBufferHelper.getInt(BitBufferHelper.getBits(data, 96, 16));
61 int extraHeaderBits = 0;
62 ArrayList<Header8021q> headerList = new ArrayList<Header8021q>();
63 while(nextField.equals(ETHERTYPE_8021Q) || nextField.equals(ETHERTYPE_QINQ)) {
64 Header8021qBuilder hBuilder = new Header8021qBuilder();
65 hBuilder.setType(Header8021qType.forValue(nextField));
67 // Read 2 more bytes for priority (3bits), drop eligible (1bit), vlan-id (12bits)
68 byte[] vlanBytes = BitBufferHelper.getBits(data, 112 + extraHeaderBits, 16);
70 // Remove the sign & right-shift to get the priority code
71 hBuilder.setPriorityCode((short) ((vlanBytes[0] & 0xff) >> 5));
73 // Remove the sign & remove priority code bits & right-shift to get drop-eligible bit
74 hBuilder.setDropEligible(1 == (((vlanBytes[0] & 0xff) & 0x10) >> 4));
76 // Remove priority code & drop-eligible bits, to get the VLAN-id
77 vlanBytes[0] = (byte) (vlanBytes[0] & 0x0F);
78 hBuilder.setVlan(BitBufferHelper.getInt(vlanBytes));
80 // Add 802.1Q header to the growing collection
81 headerList.add(hBuilder.build());
83 // Reset value of "nextField" to correspond to following 2 bytes for next 802.1Q header or EtherType/Length
84 nextField = BitBufferHelper.getInt(BitBufferHelper.getBits(data, 128 + extraHeaderBits, 16));
86 // 802.1Q header means payload starts at a later position
87 extraHeaderBits += 32;
90 if(!headerList.isEmpty()) {
91 builder.setHeader8021q(headerList);
94 // Deserialize the EtherType or Length field
95 if(nextField >= ETHERTYPE_MIN) {
96 builder.setEthertype(KnownEtherType.forValue(nextField));
97 } else if(nextField <= LENGTH_MAX) {
98 builder.setEthernetLength(nextField);
100 _logger.debug("Undefined header, value is not valid EtherType or length. Value is " + nextField);
103 // Deserialize the payload now
104 int payloadStart = 96 + 16 + extraHeaderBits;
105 int payloadSize = data.length * NetUtils.NumBitsInAByte - payloadStart;
106 int start = payloadStart / NetUtils.NumBitsInAByte;
107 int stop = start + payloadSize / NetUtils.NumBitsInAByte;
108 builder.setEthernetPayload(Arrays.copyOfRange(data, start, stop));
110 if(null != builder.getEthertype()) {
111 builder.setPacketPayloadType(new PacketPayloadTypeBuilder()
112 .setPacketType(PacketType.Ethernet)
113 .setPayloadType(builder.getEthertype().getIntValue())
117 } catch(BufferException be) {
118 _logger.info("Exception during decoding raw packet to ethernet.");
121 return builder.build();
123 //ToDo: Possibly log these values
124 /*if (_logger.isTraceEnabled()) {
125 _logger.trace("{}: {}: {} (offset {} bitsize {})",
126 new Object[] { this.getClass().getSimpleName(), hdrField,
127 HexEncode.bytesToHexString(hdrFieldBytes),
128 startOffset, numBits });
133 public Notification buildPacketNotification(Packet decodedPacket) {
134 if(!(decodedPacket instanceof EthernetPacketGrp)) return null;
136 EthernetPacketReceivedBuilder ethernetPacketReceivedBuilder = new EthernetPacketReceivedBuilder((EthernetPacketGrp) decodedPacket);
137 return ethernetPacketReceivedBuilder.build();