MPLS.java 5.13 KB
/*
 * Copyright 2015-present Open Networking Laboratory
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.onlab.packet;

import java.nio.ByteBuffer;
import java.util.HashMap;
import java.util.Map;

import static com.google.common.base.MoreObjects.toStringHelper;
import static org.onlab.packet.PacketUtils.checkInput;

/**
 * Representation of an MPLS Packet.
 */
public class MPLS extends BasePacket {
    public static final int HEADER_LENGTH = 4;

    public static final byte PROTOCOL_IPV4 = 0x1;
    public static final byte PROTOCOL_MPLS = 0x6;
    static Map<Byte, Deserializer<? extends IPacket>> protocolDeserializerMap
            = new HashMap<>();

    static {
        protocolDeserializerMap.put(PROTOCOL_IPV4, IPv4.deserializer());
        protocolDeserializerMap.put(PROTOCOL_MPLS, MPLS.deserializer());
    }

    protected int label; //20bits
    protected byte bos; //1bit
    protected byte ttl; //8bits
    protected byte protocol;

    /**
     * Default constructor that sets the version to 4.
     */
    public MPLS() {
        super();
        this.bos = 1;
        this.protocol = PROTOCOL_IPV4;
    }

    @Override
    public byte[] serialize() {
        byte[] payloadData = null;
        if (payload != null) {
            payload.setParent(this);
            payloadData = payload.serialize();
        }

        byte[] data = new byte[(4 + ((payloadData != null) ? payloadData.length : 0)) ];
        ByteBuffer bb = ByteBuffer.wrap(data);

        bb.putInt(((this.label & 0x000fffff) << 12) | ((this.bos & 0x1) << 8 | (this.ttl & 0xff)));
        if (payloadData != null) {
            bb.put(payloadData);
        }

        return data;
    }

    @Override
    public IPacket deserialize(byte[] data, int offset, int length) {
        ByteBuffer bb = ByteBuffer.wrap(data, offset, length);

        int mplsheader = bb.getInt();
        this.label = ((mplsheader & 0xfffff000) >> 12);
        this.bos = (byte) ((mplsheader & 0x00000100) >> 8);
        this.bos = (byte) (mplsheader & 0x000000ff);
        this.protocol = (this.bos == 1) ? PROTOCOL_IPV4 : PROTOCOL_MPLS;

        Deserializer<? extends IPacket> deserializer;
        if (protocolDeserializerMap.containsKey(this.protocol)) {
            deserializer = protocolDeserializerMap.get(this.protocol);
        } else {
            deserializer = Data.deserializer();
        }
        try {
            this.payload = deserializer.deserialize(data, bb.position(), bb.limit() - bb.position());
            this.payload.setParent(this);
        } catch (DeserializationException e) {
            return this;
        }

        return this;
    }

    /**
     * Returns the MPLS label.
     *
     * @return MPLS label
     */
    public int getLabel() {
        return label;
    }

    /**
     * Sets the MPLS label.
     *
     * @param label MPLS label
     */
    public void setLabel(int label) {
        this.label = label;
    }

    /**
     * Returns the MPLS TTL of the packet.
     *
     * @return MPLS TTL of the packet
     */
    public byte getTtl() {
        return ttl;
    }

    /**
     * Sets the MPLS TTL of the packet.
     *
     * @param ttl MPLS TTL
     */
    public void setTtl(byte ttl) {
        this.ttl = ttl;
    }

    /**
     * Deserializer function for MPLS packets.
     *
     * @return deserializer function
     */
    public static Deserializer<MPLS> deserializer() {
        return (data, offset, length) -> {
            checkInput(data, offset, length, HEADER_LENGTH);

            MPLS mpls = new MPLS();
            ByteBuffer bb = ByteBuffer.wrap(data, offset, length);

            int mplsheader = bb.getInt();
            mpls.label = ((mplsheader & 0xfffff000) >>> 12);
            mpls.bos = (byte) ((mplsheader & 0x00000100) >> 8);
            mpls.ttl = (byte) (mplsheader & 0x000000ff);
            mpls.protocol = (mpls.bos == 1) ? PROTOCOL_IPV4 : PROTOCOL_MPLS;

            Deserializer<? extends IPacket> deserializer;
            if (protocolDeserializerMap.containsKey(mpls.protocol)) {
                deserializer = protocolDeserializerMap.get(mpls.protocol);
            } else {
                deserializer = Data.deserializer();
            }
            mpls.payload = deserializer.deserialize(data, bb.position(), bb.limit() - bb.position());
            mpls.payload.setParent(mpls);

            return mpls;
        };
    }

    @Override
    public String toString() {
        return toStringHelper(getClass())
                .add("label", Integer.toString(label))
                .add("bos", Byte.toString(bos))
                .add("ttl", Byte.toString(ttl))
                .add("protocol", Byte.toString(protocol))
                .toString();
    }
}