Remove compatibility methods at BitBufferHelper
[l2switch.git] / packethandler / implementation / src / main / java / org / opendaylight / l2switch / packethandler / decoders / EthernetDecoder.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.util.ArrayList;
11 import org.opendaylight.l2switch.packethandler.decoders.utils.BitBufferHelper;
12 import org.opendaylight.l2switch.packethandler.decoders.utils.BufferException;
13 import org.opendaylight.l2switch.packethandler.decoders.utils.HexEncode;
14 import org.opendaylight.l2switch.packethandler.decoders.utils.NetUtils;
15 import org.opendaylight.mdsal.binding.api.NotificationPublishService;
16 import org.opendaylight.mdsal.binding.api.NotificationService;
17 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.MacAddress;
18 import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.basepacket.rev140528.packet.chain.grp.PacketChain;
19 import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.basepacket.rev140528.packet.chain.grp.PacketChainBuilder;
20 import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.basepacket.rev140528.packet.chain.grp.packet.chain.packet.RawPacketBuilder;
21 import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.basepacket.rev140528.packet.chain.grp.packet.chain.packet.raw.packet.RawPacketFieldsBuilder;
22 import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.basepacket.rev140528.packet.chain.grp.packet.chain.packet.raw.packet.raw.packet.fields.MatchBuilder;
23 import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.ethernet.rev140528.EthernetPacketReceived;
24 import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.ethernet.rev140528.EthernetPacketReceivedBuilder;
25 import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.ethernet.rev140528.Header8021qType;
26 import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.ethernet.rev140528.KnownEtherType;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.ethernet.rev140528.VlanId;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.ethernet.rev140528.ethernet.packet.fields.Header8021q;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.ethernet.rev140528.ethernet.packet.fields.Header8021qBuilder;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.ethernet.rev140528.ethernet.packet.received.packet.chain.packet.EthernetPacketBuilder;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.PacketProcessingListener;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.PacketReceived;
33 import org.opendaylight.yangtools.yang.binding.NotificationListener;
34 import org.opendaylight.yangtools.yang.common.Uint16;
35 import org.opendaylight.yangtools.yang.common.Uint8;
36 import org.slf4j.Logger;
37 import org.slf4j.LoggerFactory;
38
39 /**
40  * Ethernet Packet Decoder.
41  */
42 public class EthernetDecoder extends AbstractPacketDecoder<PacketReceived, EthernetPacketReceived>
43         implements PacketProcessingListener {
44     private static final Logger LOG = LoggerFactory.getLogger(EthernetDecoder.class);
45     public static final Integer LENGTH_MAX = 1500;
46     public static final Integer ETHERTYPE_MIN = 1536;
47     public static final Integer ETHERTYPE_8021Q = 0x8100;
48     public static final Integer ETHERTYPE_QINQ = 0x9100;
49
50     public EthernetDecoder(NotificationPublishService notificationProviderService,
51                            NotificationService notificationService) {
52         super(EthernetPacketReceived.class, notificationProviderService, notificationService);
53     }
54
55     @Override
56     public void onPacketReceived(PacketReceived packetReceived) {
57         decodeAndPublish(packetReceived);
58     }
59
60     /**
61      * Decode a RawPacket into an EthernetPacket.
62      *
63      * @param packetReceived
64      *            -- data from wire to deserialize
65      * @return EthernetPacketReceived
66      */
67     @Override
68     public EthernetPacketReceived decode(PacketReceived packetReceived) {
69         byte[] data = packetReceived.getPayload();
70         EthernetPacketReceivedBuilder builder = new EthernetPacketReceivedBuilder();
71
72         // Save original rawPacket & set the payloadOffset/payloadLength fields
73         RawPacketFieldsBuilder rpfb = new RawPacketFieldsBuilder().setIngress(packetReceived.getIngress())
74                 .setConnectionCookie(packetReceived.getConnectionCookie()).setFlowCookie(packetReceived.getFlowCookie())
75                 .setTableId(packetReceived.getTableId()).setPacketInReason(packetReceived.getPacketInReason())
76                 .setPayloadOffset(0).setPayloadLength(data.length);
77         if (packetReceived.getMatch() != null) {
78             rpfb.setMatch(new MatchBuilder(packetReceived.getMatch()).build());
79         }
80         ArrayList<PacketChain> packetChain = new ArrayList<>();
81         packetChain.add(new PacketChainBuilder()
82             .setPacket(new RawPacketBuilder().setRawPacketFields(rpfb.build()).build())
83             .build());
84
85         try {
86             EthernetPacketBuilder epBuilder = new EthernetPacketBuilder();
87
88             // Deserialize the destination & source fields
89             epBuilder.setDestinationMac(
90                 new MacAddress(HexEncode.bytesToHexStringFormat(BitBufferHelper.getBits(data, 0, 48))));
91             epBuilder.setSourceMac(
92                 new MacAddress(HexEncode.bytesToHexStringFormat(BitBufferHelper.getBits(data, 48, 48))));
93
94             // Deserialize the optional field 802.1Q headers
95             Integer nextField = BitBufferHelper.getInt(BitBufferHelper.getBits(data, 96, 16));
96             int extraHeaderBits = 0;
97             ArrayList<Header8021q> headerList = new ArrayList<>();
98             while (nextField.equals(ETHERTYPE_8021Q) || nextField.equals(ETHERTYPE_QINQ)) {
99                 Header8021qBuilder headerBuilder = new Header8021qBuilder();
100                 headerBuilder.setTPID(Header8021qType.forValue(nextField));
101
102                 // Read 2 more bytes for priority (3bits), drop eligible (1bit),
103                 // vlan-id (12bits)
104                 byte[] vlanBytes = BitBufferHelper.getBits(data, 112 + extraHeaderBits, 16);
105
106                 // Remove the sign & right-shift to get the priority code
107                 headerBuilder.setPriorityCode(Uint8.valueOf((short) ((vlanBytes[0] & 0xff) >> 5)));
108
109                 // Remove the sign & remove priority code bits & right-shift to
110                 // get drop-eligible bit
111                 headerBuilder.setDropEligible(1 == (vlanBytes[0] & 0xff & 0x10) >> 4);
112
113                 // Remove priority code & drop-eligible bits, to get the VLAN-id
114                 vlanBytes[0] = (byte) (vlanBytes[0] & 0x0F);
115                 headerBuilder.setVlan(new VlanId(BitBufferHelper.getUint16(vlanBytes)));
116
117                 // Add 802.1Q header to the growing collection
118                 headerList.add(headerBuilder.build());
119
120                 // Reset value of "nextField" to correspond to following 2 bytes
121                 // for next 802.1Q header or EtherType/Length
122                 nextField = BitBufferHelper.getInt(BitBufferHelper.getBits(data, 128 + extraHeaderBits, 16));
123
124                 // 802.1Q header means payload starts at a later position
125                 extraHeaderBits += 32;
126             }
127             // Set 802.1Q headers
128             if (!headerList.isEmpty()) {
129                 epBuilder.setHeader8021q(headerList);
130             }
131
132             // Deserialize the EtherType or Length field
133             if (nextField >= ETHERTYPE_MIN) {
134                 epBuilder.setEthertype(KnownEtherType.forValue(nextField));
135             } else if (nextField <= LENGTH_MAX) {
136                 epBuilder.setEthernetLength(Uint16.valueOf(nextField));
137             } else {
138                 LOG.debug("Undefined header, value is not valid EtherType or length.  Value is {}", nextField);
139             }
140
141             // Determine start & end of payload
142             int payloadStart = (112 + extraHeaderBits) / NetUtils.NUM_BITS_IN_A_BYTE;
143             int payloadEnd = data.length - 4;
144             epBuilder.setPayloadOffset(payloadStart);
145             epBuilder.setPayloadLength(payloadEnd - payloadStart);
146
147             // Deserialize the CRC
148             epBuilder.setCrc(BitBufferHelper
149                     .getUint32(BitBufferHelper.getBits(data, (data.length - 4) * NetUtils.NUM_BITS_IN_A_BYTE, 32)));
150
151             // Set EthernetPacket field
152             packetChain.add(new PacketChainBuilder().setPacket(epBuilder.build()).build());
153
154             // Set Payload field
155             builder.setPayload(data);
156         } catch (BufferException be) {
157             LOG.info("Exception during decoding raw packet to ethernet.");
158         }
159
160         // ToDo: Possibly log these values
161         /*
162          * if (_logger.isTraceEnabled()) {
163          * _logger.trace("{}: {}: {} (offset {} bitsize {})", new Object[] {
164          * this.getClass().getSimpleName(), hdrField,
165          * HexEncode.bytesToHexString(hdrFieldBytes), startOffset, numBits }); }
166          */
167         builder.setPacketChain(packetChain);
168         return builder.build();
169     }
170
171     @Override
172     public NotificationListener getConsumedNotificationListener() {
173         return this;
174     }
175
176     @Override
177     public boolean canDecode(PacketReceived packetReceived) {
178         return packetReceived != null && packetReceived.getPayload() != null;
179     }
180 }