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