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.opendaylight.yangtools.yang.common.Uint16;
35 import org.opendaylight.yangtools.yang.common.Uint8;
36 import org.slf4j.Logger;
37 import org.slf4j.LoggerFactory;
40 * Ethernet Packet Decoder.
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;
50 public EthernetDecoder(NotificationPublishService notificationProviderService,
51 NotificationService notificationService) {
52 super(EthernetPacketReceived.class, notificationProviderService, notificationService);
56 public void onPacketReceived(PacketReceived packetReceived) {
57 decodeAndPublish(packetReceived);
61 * Decode a RawPacket into an EthernetPacket.
63 * @param packetReceived
64 * -- data from wire to deserialize
65 * @return EthernetPacketReceived
68 public EthernetPacketReceived decode(PacketReceived packetReceived) {
69 byte[] data = packetReceived.getPayload();
70 EthernetPacketReceivedBuilder builder = new EthernetPacketReceivedBuilder();
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());
80 ArrayList<PacketChain> packetChain = new ArrayList<>();
81 packetChain.add(new PacketChainBuilder()
82 .setPacket(new RawPacketBuilder().setRawPacketFields(rpfb.build()).build())
86 EthernetPacketBuilder epBuilder = new EthernetPacketBuilder();
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))));
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));
102 // Read 2 more bytes for priority (3bits), drop eligible (1bit),
104 byte[] vlanBytes = BitBufferHelper.getBits(data, 112 + extraHeaderBits, 16);
106 // Remove the sign & right-shift to get the priority code
107 headerBuilder.setPriorityCode(Uint8.valueOf((short) ((vlanBytes[0] & 0xff) >> 5)));
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);
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)));
117 // Add 802.1Q header to the growing collection
118 headerList.add(headerBuilder.build());
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));
124 // 802.1Q header means payload starts at a later position
125 extraHeaderBits += 32;
127 // Set 802.1Q headers
128 if (!headerList.isEmpty()) {
129 epBuilder.setHeader8021q(headerList);
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));
138 LOG.debug("Undefined header, value is not valid EtherType or length. Value is {}", nextField);
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);
147 // Deserialize the CRC
148 epBuilder.setCrc(BitBufferHelper
149 .getUint32(BitBufferHelper.getBits(data, (data.length - 4) * NetUtils.NUM_BITS_IN_A_BYTE, 32)));
151 // Set EthernetPacket field
152 packetChain.add(new PacketChainBuilder().setPacket(epBuilder.build()).build());
155 builder.setPayload(data);
156 } catch (BufferException be) {
157 LOG.info("Exception during decoding raw packet to ethernet.");
160 // ToDo: Possibly log these values
162 * if (_logger.isTraceEnabled()) {
163 * _logger.trace("{}: {}: {} (offset {} bitsize {})", new Object[] {
164 * this.getClass().getSimpleName(), hdrField,
165 * HexEncode.bytesToHexString(hdrFieldBytes), startOffset, numBits }); }
167 builder.setPacketChain(packetChain);
168 return builder.build();
172 public NotificationListener getConsumedNotificationListener() {
177 public boolean canDecode(PacketReceived packetReceived) {
178 return packetReceived != null && packetReceived.getPayload() != null;