Fix SrNodeAttributesParser + test
[bgpcep.git] / bgp / linkstate / src / main / java / org / opendaylight / protocol / bgp / linkstate / attribute / sr / SrNodeAttributesParser.java
1 /*
2  * Copyright (c) 2015 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.bgp.linkstate.attribute.sr;
9
10 import io.netty.buffer.ByteBuf;
11 import io.netty.buffer.Unpooled;
12 import java.util.ArrayList;
13 import java.util.List;
14 import org.opendaylight.protocol.bgp.linkstate.spi.TlvUtil;
15 import org.opendaylight.protocol.util.BitArray;
16 import org.opendaylight.protocol.util.ByteArray;
17 import org.opendaylight.protocol.util.ByteBufWriteUtil;
18 import org.opendaylight.protocol.util.Ipv4Util;
19 import org.opendaylight.protocol.util.Ipv6Util;
20 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpAddress;
21 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpPrefix;
22 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev150210.node.state.SrAlgorithm;
23 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev150210.node.state.SrAlgorithmBuilder;
24 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev150210.node.state.SrCapabilities;
25 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev150210.node.state.SrCapabilitiesBuilder;
26 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev150210.node.state.SrSidLabel;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev150210.node.state.SrSidLabelBuilder;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.segment.routing.rev150206.Algorithm;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.segment.routing.rev150206.SidLabel;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.segment.routing.rev150206.SidLabelBinding.SidLabelFlags;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.segment.routing.rev150206.SrCapabilities.Flags;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.segment.routing.rev150206.Weight;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.segment.routing.rev150206.sid.label.binding.SubTlvs;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.segment.routing.rev150206.sid.label.binding.SubTlvsBuilder;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.segment.routing.rev150206.sid.sub.tlvs.SubtlvType;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.segment.routing.rev150206.sid.sub.tlvs.subtlv.type.EroMetricCase;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.segment.routing.rev150206.sid.sub.tlvs.subtlv.type.EroMetricCaseBuilder;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.segment.routing.rev150206.sid.sub.tlvs.subtlv.type.Ipv4EroBackupCase;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.segment.routing.rev150206.sid.sub.tlvs.subtlv.type.Ipv4EroBackupCaseBuilder;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.segment.routing.rev150206.sid.sub.tlvs.subtlv.type.Ipv4EroCase;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.segment.routing.rev150206.sid.sub.tlvs.subtlv.type.Ipv4EroCaseBuilder;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.segment.routing.rev150206.sid.sub.tlvs.subtlv.type.Ipv6EroBackupCase;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.segment.routing.rev150206.sid.sub.tlvs.subtlv.type.Ipv6EroBackupCaseBuilder;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.segment.routing.rev150206.sid.sub.tlvs.subtlv.type.Ipv6EroCase;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.segment.routing.rev150206.sid.sub.tlvs.subtlv.type.Ipv6EroCaseBuilder;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.segment.routing.rev150206.sid.sub.tlvs.subtlv.type.SidLabelCase;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.segment.routing.rev150206.sid.sub.tlvs.subtlv.type.SidLabelCaseBuilder;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.segment.routing.rev150206.sid.sub.tlvs.subtlv.type.UnnumberedEroBackupCase;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.segment.routing.rev150206.sid.sub.tlvs.subtlv.type.UnnumberedEroBackupCaseBuilder;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.segment.routing.rev150206.sid.sub.tlvs.subtlv.type.UnnumberedEroCase;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.segment.routing.rev150206.sid.sub.tlvs.subtlv.type.UnnumberedEroCaseBuilder;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.network.concepts.rev131125.TeMetric;
53 import org.slf4j.Logger;
54 import org.slf4j.LoggerFactory;
55
56 public final class SrNodeAttributesParser {
57
58     private static final Logger LOG = LoggerFactory.getLogger(SrNodeAttributesParser.class);
59
60     private SrNodeAttributesParser() {
61         throw new UnsupportedOperationException();
62     }
63
64     private static final int FLAGS_SIZE = 8;
65
66     /* SR Capabilities flags */
67     private static final int IPV4 = 0;
68     private static final int IPV6 = 1;
69
70     /* SID Label flags */
71     private static final int AFI = 0;
72     private static final int MIRROR = 1;
73
74     /* SID Label Tlv types */
75     private static final int SID_TLV_TYPE = 1;
76     private static final int ERO_METRIC = 2;
77     private static final int ERO_IPV4 = 3;
78     private static final int ERO_IPV6 = 4;
79     private static final int UNNUMBERED_ERO = 5;
80     private static final int BACKUP_IPV4 = 6;
81     private static final int BACKUP_IPV6 = 7;
82     private static final int UNNUMBERED_BACKUP_ERO = 8;
83
84     private static final int UNNUMBERED_4_SIZE = 8;
85
86     private static final byte LOOSE = (byte) 128;
87
88     private static List<SubTlvs> parseSidSubtlvs(final ByteBuf buffer) {
89         final List<SubTlvs> subs = new ArrayList<>();
90         while (buffer.isReadable()) {
91             final int type = buffer.readUnsignedByte();
92             final int length = buffer.readUnsignedByte();
93             final ByteBuf value = buffer.readSlice(length);
94             SubtlvType sub = null;
95             switch (type) {
96             case SID_TLV_TYPE:
97                 sub = new SidLabelCaseBuilder().setSid(new SidLabel(ByteArray.readAllBytes(value))).build();
98                 break;
99             case ERO_METRIC:
100                 sub = new EroMetricCaseBuilder().setEroMetric(new TeMetric(value.readUnsignedInt())).build();
101                 break;
102             case ERO_IPV4:
103                 final Ipv4EroCaseBuilder ero4 = new Ipv4EroCaseBuilder().setLoose(value.readUnsignedByte() != 0);
104                 ero4.setAddress(new IpAddress(Ipv4Util.addressForByteBuf(value)));
105                 sub = ero4.build();
106                 break;
107             case ERO_IPV6:
108                 final Ipv6EroCaseBuilder ero6 = new Ipv6EroCaseBuilder().setLoose(value.readUnsignedByte() != 0);
109                 ero6.setAddress(new IpAddress(Ipv6Util.addressForByteBuf(value)));
110                 sub = ero6.build();
111                 break;
112             case UNNUMBERED_ERO:
113                 final UnnumberedEroCaseBuilder un = new UnnumberedEroCaseBuilder().setLoose(value.readUnsignedByte() != 0);
114                 un.setRouterId(readRouterId(value));
115                 un.setInterfaceId(value.readUnsignedInt());
116                 sub = un.build();
117                 break;
118             case BACKUP_IPV4:
119                 final Ipv4EroBackupCaseBuilder erob4 = new Ipv4EroBackupCaseBuilder().setLoose(value.readUnsignedByte() != 0);
120                 erob4.setAddress(new IpAddress(Ipv4Util.addressForByteBuf(value)));
121                 sub = erob4.build();
122                 break;
123             case BACKUP_IPV6:
124                 final Ipv6EroBackupCaseBuilder erob6 = new Ipv6EroBackupCaseBuilder().setLoose(value.readUnsignedByte() != 0);
125                 erob6.setAddress(new IpAddress(Ipv6Util.addressForByteBuf(value)));
126                 sub = erob6.build();
127                 break;
128             case UNNUMBERED_BACKUP_ERO:
129                 final UnnumberedEroBackupCaseBuilder unb = new UnnumberedEroBackupCaseBuilder().setLoose(value.readUnsignedByte() != 0);
130                 unb.setRouterId(readRouterId(value));
131                 unb.setInterfaceId(value.readUnsignedInt());
132                 sub = unb.build();
133                 break;
134             default:
135                 LOG.debug("Unknown SID Label Subtlv found, type {}", type);
136                 // we don't want to add null sub-tlv, so skip to next loop iteration
137                 continue;
138             }
139             subs.add(new SubTlvsBuilder().setSubtlvType(sub).build());
140         }
141         return subs;
142     }
143
144     private static byte[] readRouterId(final ByteBuf value) {
145         if (value.readableBytes() == UNNUMBERED_4_SIZE) {
146             return ByteArray.readBytes(value, Ipv4Util.IP4_LENGTH);
147         }
148         return ByteArray.readBytes(value, Ipv6Util.IPV6_LENGTH);
149     }
150
151     public static SrSidLabel parseSidLabelBinding(final ByteBuf buffer) {
152         final SrSidLabelBuilder builder = new SrSidLabelBuilder();
153         final BitArray flags = BitArray.valueOf(buffer, FLAGS_SIZE);
154         builder.setSidLabelFlags(new SidLabelFlags(flags.get(AFI), flags.get(MIRROR)));
155         builder.setWeight(new Weight(buffer.readUnsignedByte()));
156         builder.setValueRange(buffer.readUnsignedShort());
157         final int bitLength = buffer.getUnsignedByte(buffer.readerIndex());
158         IpPrefix prefix = null;
159         if (bitLength / Byte.SIZE == Ipv4Util.IP4_LENGTH) {
160             prefix = new IpPrefix(Ipv4Util.prefixForByteBuf(buffer));
161         } else {
162             prefix = new IpPrefix(Ipv6Util.prefixForByteBuf(buffer));
163         }
164         builder.setFecPrefix(prefix);
165         builder.setSubTlvs(parseSidSubtlvs(buffer));
166         return builder.build();
167     }
168
169     private static byte serializeLoose(final boolean loose) {
170         return loose ? LOOSE : 0;
171     }
172
173     private static void serializeSidSubtlvs(final List<SubTlvs> subTlvs, final ByteBuf buffer) {
174         for (final SubTlvs sub : subTlvs) {
175             final SubtlvType type = sub.getSubtlvType();
176             if (type instanceof SidLabelCase) {
177                 TlvUtil.writeSrTLV(SID_TLV_TYPE, Unpooled.wrappedBuffer(((SidLabelCase)type).getSid().getValue()), buffer);
178             } else if (type instanceof EroMetricCase) {
179                 final ByteBuf b = Unpooled.buffer();
180                 ByteBufWriteUtil.writeUnsignedInt(((EroMetricCase)type).getEroMetric().getValue(), b);
181                 TlvUtil.writeSrTLV(ERO_METRIC, b, buffer);
182             } else if (type instanceof Ipv4EroCase) {
183                 final ByteBuf b = Unpooled.buffer(Ipv4Util.IP4_LENGTH + FLAGS_SIZE);
184                 final Ipv4EroCase ero = (Ipv4EroCase)type;
185                 b.writeByte(serializeLoose(ero.isLoose()));
186                 ByteBufWriteUtil.writeIpv4Address(ero.getAddress().getIpv4Address(), b);
187                 TlvUtil.writeSrTLV(ERO_IPV4, b, buffer);
188             } else if (type instanceof Ipv6EroCase) {
189                 final ByteBuf b = Unpooled.buffer(Ipv6Util.IPV6_LENGTH + FLAGS_SIZE);
190                 final Ipv6EroCase ero = (Ipv6EroCase)type;
191                 b.writeByte(serializeLoose(ero.isLoose()));
192                 ByteBufWriteUtil.writeIpv6Address(ero.getAddress().getIpv6Address(), b);
193                 TlvUtil.writeSrTLV(ERO_IPV6, b, buffer);
194             } else if (type instanceof UnnumberedEroCase) {
195                 final UnnumberedEroCase ero = (UnnumberedEroCase)type;
196                 final ByteBuf b = Unpooled.buffer();
197                 b.writeByte(serializeLoose(ero.isLoose()));
198                 b.writeBytes(ero.getRouterId());
199                 ByteBufWriteUtil.writeUnsignedInt(ero.getInterfaceId(), b);
200                 TlvUtil.writeSrTLV(UNNUMBERED_ERO, b, buffer);
201             } else if (type instanceof Ipv4EroBackupCase) {
202                 final ByteBuf b = Unpooled.buffer(Ipv4Util.IP4_LENGTH + FLAGS_SIZE);
203                 final Ipv4EroBackupCase ero = (Ipv4EroBackupCase)type;
204                 b.writeByte(serializeLoose(ero.isLoose()));
205                 ByteBufWriteUtil.writeIpv4Address(ero.getAddress().getIpv4Address(), b);
206                 TlvUtil.writeSrTLV(BACKUP_IPV4, b, buffer);
207             } else if (type instanceof Ipv6EroBackupCase) {
208                 final ByteBuf b = Unpooled.buffer(Ipv6Util.IPV6_LENGTH + FLAGS_SIZE);
209                 final Ipv6EroBackupCase ero = (Ipv6EroBackupCase)type;
210                 b.writeByte(serializeLoose(ero.isLoose()));
211                 ByteBufWriteUtil.writeIpv6Address(ero.getAddress().getIpv6Address(), b);
212                 TlvUtil.writeSrTLV(BACKUP_IPV6, b, buffer);
213             } else if (type instanceof UnnumberedEroBackupCase) {
214                 final UnnumberedEroBackupCase ero = (UnnumberedEroBackupCase)type;
215                 final ByteBuf b = Unpooled.buffer();
216                 b.writeByte(serializeLoose(ero.isLoose()));
217                 b.writeBytes(ero.getRouterId());
218                 ByteBufWriteUtil.writeUnsignedInt(ero.getInterfaceId(), b);
219                 TlvUtil.writeSrTLV(UNNUMBERED_BACKUP_ERO, b, buffer);
220             }
221         }
222     }
223
224     public static void serializeSidLabelBinding(final SrSidLabel binding, final ByteBuf buffer) {
225         final SidLabelFlags flags = binding.getSidLabelFlags();
226         final BitArray bs = new BitArray(FLAGS_SIZE);
227         bs.set(AFI, flags.isAddressFamily());
228         bs.set(MIRROR, flags.isMirrorContext());
229         bs.toByteBuf(buffer);
230         buffer.writeByte(binding.getWeight().getValue());
231         buffer.writeShort(binding.getValueRange());
232         final IpPrefix prefix = binding.getFecPrefix();
233         if (prefix.getIpv4Prefix() != null) {
234             buffer.writeBytes(Ipv4Util.bytesForPrefixBegin(prefix.getIpv4Prefix()));
235         } else {
236             buffer.writeBytes(Ipv6Util.bytesForPrefixBegin(prefix.getIpv6Prefix()));
237         }
238         if (binding.getSubTlvs() != null) {
239             serializeSidSubtlvs(binding.getSubTlvs(), buffer);
240         }
241     }
242
243     public static SrCapabilities parseSrCapabilities(final ByteBuf buffer) {
244         final SrCapabilitiesBuilder builder = new SrCapabilitiesBuilder();
245         final BitArray flags = BitArray.valueOf(buffer, FLAGS_SIZE);
246         builder.setFlags(new Flags(flags.get(IPV4), flags.get(IPV6)));
247         builder.setValueRange((long)buffer.readUnsignedMedium());
248         buffer.skipBytes(2);
249         builder.setSid(new SidLabel(ByteArray.readAllBytes(buffer)));
250         return builder.build();
251     }
252
253     public static void serializeSrCapabilities(final SrCapabilities caps, final ByteBuf buffer) {
254         final Flags flags = caps.getFlags();
255         final BitArray bs = new BitArray(FLAGS_SIZE);
256         bs.set(IPV4, flags.isIpv4());
257         bs.set(IPV6, flags.isIpv6());
258         bs.toByteBuf(buffer);
259         buffer.writeMedium(caps.getValueRange().intValue());
260         buffer.writeByte(SID_TLV_TYPE);
261         final byte[] sid = caps.getSid().getValue();
262         buffer.writeByte(sid.length);
263         buffer.writeBytes(sid);
264     }
265
266     public static SrAlgorithm parseSrAlgorithms(final ByteBuf buffer) {
267         final SrAlgorithmBuilder builder = new SrAlgorithmBuilder();
268         final List<Algorithm> algs = new ArrayList<>();
269         while (buffer.isReadable()) {
270             algs.add(Algorithm.forValue(buffer.readUnsignedByte()));
271         }
272         builder.setAlgorithm(algs);
273         return builder.build();
274     }
275
276     public static void serializeSrAlgorithms(final SrAlgorithm alg, final ByteBuf buffer) {
277         if (alg.getAlgorithm() != null) {
278             for (final Algorithm a : alg.getAlgorithm()) {
279                 buffer.writeByte(a.getIntValue());
280             }
281         }
282     }
283 }