343bbd3feca337b70456606a0a87896ca1f61560
[bgpcep.git] / pcep / ietf-stateful07 / src / main / java / org / opendaylight / protocol / pcep / ietf / stateful07 / PathBindingTlvParser.java
1 /*
2  * Copyright (c) 2016 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
9 package org.opendaylight.protocol.pcep.ietf.stateful07;
10
11 import com.google.common.base.Preconditions;
12 import com.google.common.collect.ImmutableMap;
13 import com.google.common.collect.ImmutableMap.Builder;
14 import io.netty.buffer.ByteBuf;
15 import io.netty.buffer.Unpooled;
16 import java.util.Map;
17 import org.opendaylight.protocol.pcep.spi.PCEPDeserializerException;
18 import org.opendaylight.protocol.pcep.spi.TlvParser;
19 import org.opendaylight.protocol.pcep.spi.TlvSerializer;
20 import org.opendaylight.protocol.pcep.spi.TlvUtil;
21 import org.opendaylight.protocol.util.ByteBufWriteUtil;
22 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev131222.path.binding.tlv.PathBinding;
23 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev131222.path.binding.tlv.PathBindingBuilder;
24 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev131222.path.binding.tlv.path.binding.BindingTypeValue;
25 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev131222.path.binding.tlv.path.binding.binding.type.value.MplsLabel;
26 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev131222.path.binding.tlv.path.binding.binding.type.value.MplsLabelBuilder;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev131222.path.binding.tlv.path.binding.binding.type.value.MplsLabelEntry;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev131222.path.binding.tlv.path.binding.binding.type.value.MplsLabelEntryBuilder;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev131005.Tlv;
30 import org.opendaylight.yangtools.concepts.Codec;
31
32 /**
33  * Parser for {@link PathBinding}
34  */
35 public final class PathBindingTlvParser implements TlvParser, TlvSerializer {
36
37     // TODO: to be confirmed by IANA
38     public static final int TYPE = 31;
39
40     private static final int MPLS_LABEL = 0;
41     private static final int MPLS_STACK_ENTRY = 1;
42
43     private static final int LABEL_MASK = 0xfffff;
44     private static final int TC_MASK = 0x7;
45     private static final int S_MASK = 0x1;
46     private static final int TTL_MASK = 0xff;
47     private static final int LABEL_SHIFT = 12;
48     private static final int TC_SHIFT = LABEL_SHIFT - 3;
49     private static final int S_SHIFT = TC_SHIFT - 1;
50     private static final int MPLS_ENTRY_LENGTH = 4;
51     private static final int MPLS_BINDING_LENGTH = MPLS_ENTRY_LENGTH + 2;
52
53     private static final Map<Integer, PathBindingTlvCodec> BT_PARSERS;
54     private static final Map<Class<? extends BindingTypeValue>, PathBindingTlvCodec> BT_SERIALIZERS;
55
56     static {
57         final MplsLabelCodec mplsLabelCodec = new MplsLabelCodec();
58         final MplsLabelEntryCodec mplsLabelEntryCodec = new MplsLabelEntryCodec();
59         final Builder<Integer, PathBindingTlvCodec> parsers = ImmutableMap.<Integer, PathBindingTlvCodec>builder();
60         final Builder<Class<? extends BindingTypeValue>, PathBindingTlvCodec> serializers =
61                 ImmutableMap.<Class<? extends BindingTypeValue>, PathBindingTlvCodec>builder();
62
63         parsers.put(mplsLabelCodec.getBindingType(), mplsLabelCodec);
64         serializers.put(MplsLabel.class, mplsLabelCodec);
65
66         parsers.put(mplsLabelEntryCodec.getBindingType(), mplsLabelEntryCodec);
67         serializers.put(MplsLabelEntry.class, mplsLabelEntryCodec);
68
69         BT_PARSERS = parsers.build();
70         BT_SERIALIZERS = serializers.build();
71     }
72
73     @Override
74     public void serializeTlv(final Tlv tlv, final ByteBuf buffer) {
75         Preconditions.checkArgument(tlv instanceof PathBinding, "The TLV must be PathBinding type, but was %s", tlv.getClass());
76         final PathBinding pTlv = (PathBinding) tlv;
77         final BindingTypeValue bindingTypeValue = pTlv.getBindingTypeValue();
78         Preconditions.checkArgument((pTlv.getBindingValue() != null && pTlv.getBindingType() != null) || bindingTypeValue != null, "Missing Binding Value in Path Bidning TLV: %s", pTlv);
79         final ByteBuf body = Unpooled.buffer(MPLS_BINDING_LENGTH);
80         if (bindingTypeValue == null) {
81             backwardsSerializer(pTlv, body);
82         } else {
83             final PathBindingTlvCodec codec = BT_SERIALIZERS.get(bindingTypeValue.getImplementedInterface());
84             Preconditions.checkArgument(codec != null, "Unsupported Path Binding Type: %s", bindingTypeValue.getImplementedInterface());
85             ByteBufWriteUtil.writeUnsignedShort(codec.getBindingType(), body);
86             body.writeBytes(codec.serialize(bindingTypeValue));
87         }
88         TlvUtil.formatTlv(TYPE, body, buffer);
89     }
90
91     @Override
92     public Tlv parseTlv(final ByteBuf buffer) throws PCEPDeserializerException {
93         if (buffer == null) {
94             return null;
95         }
96         final int type = buffer.readUnsignedShort();
97         final PathBindingTlvCodec codec = BT_PARSERS.get(type);
98         if (codec == null) {
99             throw new PCEPDeserializerException("Unsupported Path Binding Type: " + type);
100         }
101         final PathBindingBuilder builder = new PathBindingBuilder();
102         backwardsParser(type, buffer, builder);
103         return builder.setBindingTypeValue(codec.deserialize(buffer)).build();
104     }
105
106     private void backwardsParser(final int type, final ByteBuf buffer, final PathBindingBuilder builder) {
107         builder.setBindingType((short) type);
108         final byte[] value = new byte[buffer.readableBytes()];
109         //codec will do the reading from buffer
110         buffer.getBytes(0, value);
111         builder.setBindingValue(value);
112     }
113
114     private void backwardsSerializer(final PathBinding pTlv, final ByteBuf body) {
115         ByteBufWriteUtil.writeUnsignedShort((int)pTlv.getBindingType(), body);
116         body.writeBytes(pTlv.getBindingValue());
117     }
118
119     private static final class MplsLabelCodec implements PathBindingTlvCodec {
120
121         @Override
122         public ByteBuf serialize(final BindingTypeValue bindingValue) {
123             final MplsLabel mplsLabel = (MplsLabel) bindingValue;
124             final ByteBuf value = Unpooled.buffer(MPLS_ENTRY_LENGTH);
125             ByteBufWriteUtil.writeUnsignedInt(getMplsStackEntry(mplsLabel.getMplsLabel()), value);
126             return value;
127         }
128
129         @Override
130         public BindingTypeValue deserialize(final ByteBuf buffer) {
131             final MplsLabelBuilder builder = new MplsLabelBuilder();
132             builder.setMplsLabel(getMplsLabel(buffer.readUnsignedInt()));
133             return builder.build();
134         }
135
136         @Override
137         public int getBindingType() {
138             return MPLS_LABEL;
139         }
140     }
141
142     private static final class MplsLabelEntryCodec implements PathBindingTlvCodec {
143
144         @Override
145         public ByteBuf serialize(final BindingTypeValue bindingValue) {
146             final MplsLabelEntry mplsEntry = ((MplsLabelEntry) bindingValue);
147             final ByteBuf value = Unpooled.buffer(MPLS_ENTRY_LENGTH);
148             final long entry = getMplsStackEntry(mplsEntry.getLabel())
149                     | mplsEntry.getTrafficClass() << TC_SHIFT
150                     | (mplsEntry.isBottomOfStack() ? 1 : 0) << S_SHIFT
151                     | mplsEntry.getTimeToLive();
152             ByteBufWriteUtil.writeUnsignedInt(entry, value);
153             return value;
154         }
155
156         @Override
157         public BindingTypeValue deserialize(final ByteBuf buffer) {
158             final MplsLabelEntryBuilder builder = new MplsLabelEntryBuilder();
159             final long entry = buffer.readUnsignedInt();
160             builder.setLabel(getMplsLabel(entry));
161             builder.setTrafficClass((short) ((entry >> TC_SHIFT) & TC_MASK));
162             builder.setBottomOfStack(((entry >> S_SHIFT) & S_MASK) == 1);
163             builder.setTimeToLive((short) (entry & TTL_MASK));
164             return builder.build();
165         }
166
167         @Override
168         public int getBindingType() {
169             return MPLS_STACK_ENTRY;
170         }
171     }
172
173     private interface PathBindingTlvCodec extends Codec<ByteBuf, BindingTypeValue> {
174         int getBindingType();
175     }
176
177     private static org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.network.concepts.rev131125.MplsLabel getMplsLabel(
178             final long mplsStackEntry) {
179         return new org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.network.concepts.rev131125.MplsLabel(
180                 (mplsStackEntry >> LABEL_SHIFT) & LABEL_MASK);
181     }
182
183     private static long getMplsStackEntry(
184             final org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.network.concepts.rev131125.MplsLabel mplsLabel) {
185         return mplsLabel.getValue() << LABEL_SHIFT;
186     }
187
188 }