2 * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
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
8 package org.opendaylight.l2switch.packethandler.decoders;
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.slf4j.Logger;
35 import org.slf4j.LoggerFactory;
38 * Ethernet Packet Decoder.
40 public class EthernetDecoder extends AbstractPacketDecoder<PacketReceived, EthernetPacketReceived>
41 implements PacketProcessingListener {
42 private static final Logger LOG = LoggerFactory.getLogger(EthernetDecoder.class);
43 public static final Integer LENGTH_MAX = 1500;
44 public static final Integer ETHERTYPE_MIN = 1536;
45 public static final Integer ETHERTYPE_8021Q = 0x8100;
46 public static final Integer ETHERTYPE_QINQ = 0x9100;
48 public EthernetDecoder(NotificationPublishService notificationProviderService,
49 NotificationService notificationService) {
50 super(EthernetPacketReceived.class, notificationProviderService, notificationService);
54 public void onPacketReceived(PacketReceived packetReceived) {
55 decodeAndPublish(packetReceived);
59 * Decode a RawPacket into an EthernetPacket.
61 * @param packetReceived
62 * -- data from wire to deserialize
63 * @return EthernetPacketReceived
66 public EthernetPacketReceived decode(PacketReceived packetReceived) {
67 byte[] data = packetReceived.getPayload();
68 EthernetPacketReceivedBuilder builder = new EthernetPacketReceivedBuilder();
70 // Save original rawPacket & set the payloadOffset/payloadLength fields
71 RawPacketFieldsBuilder rpfb = new RawPacketFieldsBuilder().setIngress(packetReceived.getIngress())
72 .setConnectionCookie(packetReceived.getConnectionCookie()).setFlowCookie(packetReceived.getFlowCookie())
73 .setTableId(packetReceived.getTableId()).setPacketInReason(packetReceived.getPacketInReason())
74 .setPayloadOffset(0).setPayloadLength(data.length);
75 if (packetReceived.getMatch() != null) {
76 rpfb.setMatch(new MatchBuilder(packetReceived.getMatch()).build());
78 ArrayList<PacketChain> packetChain = new ArrayList<>();
79 packetChain.add(new PacketChainBuilder()
80 .setPacket(new RawPacketBuilder().setRawPacketFields(rpfb.build()).build())
84 EthernetPacketBuilder epBuilder = new EthernetPacketBuilder();
86 // Deserialize the destination & source fields
87 epBuilder.setDestinationMac(
88 new MacAddress(HexEncode.bytesToHexStringFormat(BitBufferHelper.getBits(data, 0, 48))));
89 epBuilder.setSourceMac(
90 new MacAddress(HexEncode.bytesToHexStringFormat(BitBufferHelper.getBits(data, 48, 48))));
92 // Deserialize the optional field 802.1Q headers
93 Integer nextField = BitBufferHelper.getInt(BitBufferHelper.getBits(data, 96, 16));
94 int extraHeaderBits = 0;
95 ArrayList<Header8021q> headerList = new ArrayList<>();
96 while (nextField.equals(ETHERTYPE_8021Q) || nextField.equals(ETHERTYPE_QINQ)) {
97 Header8021qBuilder headerBuilder = new Header8021qBuilder();
98 headerBuilder.setTPID(Header8021qType.forValue(nextField));
100 // Read 2 more bytes for priority (3bits), drop eligible (1bit),
102 byte[] vlanBytes = BitBufferHelper.getBits(data, 112 + extraHeaderBits, 16);
104 // Remove the sign & right-shift to get the priority code
105 headerBuilder.setPriorityCode((short) ((vlanBytes[0] & 0xff) >> 5));
107 // Remove the sign & remove priority code bits & right-shift to
108 // get drop-eligible bit
109 headerBuilder.setDropEligible(1 == (vlanBytes[0] & 0xff & 0x10) >> 4);
111 // Remove priority code & drop-eligible bits, to get the VLAN-id
112 vlanBytes[0] = (byte) (vlanBytes[0] & 0x0F);
113 headerBuilder.setVlan(new VlanId(BitBufferHelper.getInt(vlanBytes)));
115 // Add 802.1Q header to the growing collection
116 headerList.add(headerBuilder.build());
118 // Reset value of "nextField" to correspond to following 2 bytes
119 // for next 802.1Q header or EtherType/Length
120 nextField = BitBufferHelper.getInt(BitBufferHelper.getBits(data, 128 + extraHeaderBits, 16));
122 // 802.1Q header means payload starts at a later position
123 extraHeaderBits += 32;
125 // Set 802.1Q headers
126 if (!headerList.isEmpty()) {
127 epBuilder.setHeader8021q(headerList);
130 // Deserialize the EtherType or Length field
131 if (nextField >= ETHERTYPE_MIN) {
132 epBuilder.setEthertype(KnownEtherType.forValue(nextField));
133 } else if (nextField <= LENGTH_MAX) {
134 epBuilder.setEthernetLength(nextField);
136 LOG.debug("Undefined header, value is not valid EtherType or length. Value is {}", nextField);
139 // Determine start & end of payload
140 int payloadStart = (112 + extraHeaderBits) / NetUtils.NUM_BITS_IN_A_BYTE;
141 int payloadEnd = data.length - 4;
142 epBuilder.setPayloadOffset(payloadStart);
143 epBuilder.setPayloadLength(payloadEnd - payloadStart);
145 // Deserialize the CRC
146 epBuilder.setCrc(BitBufferHelper
147 .getLong(BitBufferHelper.getBits(data, (data.length - 4) * NetUtils.NUM_BITS_IN_A_BYTE, 32)));
149 // Set EthernetPacket field
150 packetChain.add(new PacketChainBuilder().setPacket(epBuilder.build()).build());
153 builder.setPayload(data);
154 } catch (BufferException be) {
155 LOG.info("Exception during decoding raw packet to ethernet.");
158 // ToDo: Possibly log these values
160 * if (_logger.isTraceEnabled()) {
161 * _logger.trace("{}: {}: {} (offset {} bitsize {})", new Object[] {
162 * this.getClass().getSimpleName(), hdrField,
163 * HexEncode.bytesToHexString(hdrFieldBytes), startOffset, numBits }); }
165 builder.setPacketChain(packetChain);
166 return builder.build();
170 public NotificationListener getConsumedNotificationListener() {
175 public boolean canDecode(PacketReceived packetReceived) {
176 return packetReceived != null && packetReceived.getPayload() != null;