Clean up ShortestPathFirst
[bgpcep.git] / pcep / ietf-stateful / src / main / java / org / opendaylight / protocol / pcep / ietf / stateful / 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.stateful;
9
10 import static com.google.common.base.Preconditions.checkArgument;
11 import static java.util.Objects.requireNonNull;
12
13 import com.google.common.collect.ImmutableMap;
14 import com.google.common.collect.ImmutableMap.Builder;
15 import io.netty.buffer.ByteBuf;
16 import io.netty.buffer.Unpooled;
17 import java.util.Map;
18 import org.eclipse.jdt.annotation.NonNull;
19 import org.opendaylight.protocol.pcep.PCEPDeserializerException;
20 import org.opendaylight.protocol.pcep.spi.TlvParser;
21 import org.opendaylight.protocol.pcep.spi.TlvSerializer;
22 import org.opendaylight.protocol.pcep.spi.TlvUtil;
23 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev200720.path.binding.tlv.PathBinding;
24 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev200720.path.binding.tlv.PathBindingBuilder;
25 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev200720.path.binding.tlv.path.binding.BindingTypeValue;
26 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev200720.path.binding.tlv.path.binding.binding.type.value.MplsLabel;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev200720.path.binding.tlv.path.binding.binding.type.value.MplsLabelBuilder;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev200720.path.binding.tlv.path.binding.binding.type.value.MplsLabelEntry;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev200720.path.binding.tlv.path.binding.binding.type.value.MplsLabelEntryBuilder;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev181109.Tlv;
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 import org.opendaylight.yangtools.yang.common.netty.ByteBufUtils;
35
36 /**
37  * Parser for {@link PathBinding}.
38  */
39 public final class PathBindingTlvParser implements TlvParser, TlvSerializer {
40     // TODO: to be confirmed by IANA
41     public static final int TYPE = 31;
42
43     private static final Uint16 MPLS_LABEL = Uint16.ZERO;
44     private static final Uint16 MPLS_STACK_ENTRY = Uint16.ONE;
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     // 2 bytes type + 4 bytes binding
54     private static final int MPLS_BINDING_LENGTH = 6;
55
56     private static final Map<Uint16, 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<Uint16, 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         checkArgument(tlv instanceof PathBinding, "The TLV must be PathBinding type, but was %s", tlv.getClass());
79         final PathBinding pTlv = (PathBinding) tlv;
80         final BindingTypeValue bindingTypeValue = pTlv.getBindingTypeValue();
81         checkArgument(bindingTypeValue != null, "Missing Binding Value in Path Bidning TLV: %s", pTlv);
82         final ByteBuf body = Unpooled.buffer(MPLS_BINDING_LENGTH);
83         final PathBindingTlvCodec codec = BT_SERIALIZERS.get(bindingTypeValue.implementedInterface());
84         checkArgument(codec != null, "Unsupported Path Binding Type: %s", bindingTypeValue.implementedInterface());
85         codec.writeBinding(body, bindingTypeValue);
86
87         TlvUtil.formatTlv(TYPE, body, buffer);
88     }
89
90     @Override
91     public Tlv parseTlv(final ByteBuf buffer) throws PCEPDeserializerException {
92         if (buffer == null) {
93             return null;
94         }
95         final Uint16 type = ByteBufUtils.readUint16(buffer);
96         final PathBindingTlvCodec codec = BT_PARSERS.get(type);
97         if (codec == null) {
98             throw new PCEPDeserializerException("Unsupported Path Binding Type: " + type);
99         }
100         return new PathBindingBuilder().setBindingTypeValue(codec.readEntry(buffer)).build();
101     }
102
103     private static final class MplsLabelCodec extends PathBindingTlvCodec {
104         MplsLabelCodec() {
105             super(MPLS_LABEL);
106         }
107
108         @Override
109         void writeEntry(final ByteBuf buf, final BindingTypeValue bindingValue) {
110             checkArgument(bindingValue instanceof MplsLabel, "bindingValue is not MplsLabel");
111             final MplsLabel mplsLabel = (MplsLabel) bindingValue;
112             ByteBufUtils.write(buf, Uint32.valueOf(getMplsStackEntry(mplsLabel.getMplsLabel())));
113         }
114
115         @Override
116         BindingTypeValue readEntry(final ByteBuf buffer) {
117             return new MplsLabelBuilder().setMplsLabel(getMplsLabel(buffer.readUnsignedInt())).build();
118         }
119     }
120
121     private static final class MplsLabelEntryCodec extends PathBindingTlvCodec {
122         MplsLabelEntryCodec() {
123             super(MPLS_STACK_ENTRY);
124         }
125
126         @Override
127         void writeEntry(final ByteBuf buf, final BindingTypeValue bindingValue) {
128             checkArgument(bindingValue instanceof MplsLabelEntry, "bindingValue is not MplsLabelEntry");
129             final MplsLabelEntry mplsEntry = (MplsLabelEntry) bindingValue;
130             final long entry = getMplsStackEntry(mplsEntry.getLabel())
131                     | mplsEntry.getTrafficClass().toJava() << TC_SHIFT
132                     | (mplsEntry.getBottomOfStack() ? 1 : 0) << S_SHIFT
133                     | mplsEntry.getTimeToLive().toJava();
134             ByteBufUtils.write(buf, Uint32.valueOf(entry));
135         }
136
137         @Override
138         BindingTypeValue readEntry(final ByteBuf buffer) {
139             final long entry = buffer.readUnsignedInt();
140             return new MplsLabelEntryBuilder()
141                     .setLabel(getMplsLabel(entry))
142                     .setTrafficClass(Uint8.valueOf(entry >> TC_SHIFT & TC_MASK))
143                     .setBottomOfStack((entry >> S_SHIFT & S_MASK) == 1)
144                     .setTimeToLive(Uint8.valueOf(entry & TTL_MASK))
145                     .build();
146         }
147     }
148
149     private abstract static class PathBindingTlvCodec {
150         private final @NonNull Uint16 bindingType;
151
152         PathBindingTlvCodec(final Uint16 bindingType) {
153             this.bindingType = requireNonNull(bindingType);
154         }
155
156         final @NonNull Uint16 getBindingType() {
157             return bindingType;
158         }
159
160         final void writeBinding(final ByteBuf buf, final BindingTypeValue binding) {
161             ByteBufUtils.writeMandatory(buf, bindingType, "bindingType");
162             writeEntry(buf, binding);
163         }
164
165         abstract BindingTypeValue readEntry(ByteBuf buf);
166
167         abstract void writeEntry(ByteBuf buf, BindingTypeValue value);
168     }
169
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     private static long getMplsStackEntry(final org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.network
177             .concepts.rev131125.MplsLabel mplsLabel) {
178         return mplsLabel.getValue().toJava() << LABEL_SHIFT;
179     }
180 }