Migrate pcep-ietf-stateful07 to use ByteBufUtils
[bgpcep.git] / pcep / ietf-stateful07 / src / main / java / org / opendaylight / protocol / pcep / ietf / stateful07 / Stateful07RSVPErrorSpecTlvParser.java
1 /*
2  * Copyright (c) 2013 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 static com.google.common.base.Preconditions.checkArgument;
11 import static org.opendaylight.protocol.util.ByteBufWriteUtil.writeIpv4Address;
12 import static org.opendaylight.protocol.util.ByteBufWriteUtil.writeIpv6Address;
13
14 import io.netty.buffer.ByteBuf;
15 import io.netty.buffer.Unpooled;
16 import java.nio.charset.StandardCharsets;
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.BitArray;
22 import org.opendaylight.protocol.util.ByteArray;
23 import org.opendaylight.protocol.util.Ipv4Util;
24 import org.opendaylight.protocol.util.Ipv6Util;
25 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddressNoZone;
26 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.iana.rev130816.EnterpriseNumber;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev181109.rsvp.error.spec.tlv.RsvpErrorSpec;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev181109.rsvp.error.spec.tlv.RsvpErrorSpecBuilder;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev181109.rsvp.error.spec.tlv.rsvp.error.spec.ErrorType;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev181109.rsvp.error.spec.tlv.rsvp.error.spec.error.type.RsvpCase;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev181109.rsvp.error.spec.tlv.rsvp.error.spec.error.type.RsvpCaseBuilder;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev181109.rsvp.error.spec.tlv.rsvp.error.spec.error.type.UserCase;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev181109.rsvp.error.spec.tlv.rsvp.error.spec.error.type.UserCaseBuilder;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev181109.rsvp.error.spec.tlv.rsvp.error.spec.error.type.rsvp._case.RsvpError;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev181109.rsvp.error.spec.tlv.rsvp.error.spec.error.type.rsvp._case.RsvpErrorBuilder;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev181109.rsvp.error.spec.tlv.rsvp.error.spec.error.type.user._case.UserError;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev181109.rsvp.error.spec.tlv.rsvp.error.spec.error.type.user._case.UserErrorBuilder;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev181109.Tlv;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.rsvp.rev150820.ErrorSpec.Flags;
40 import org.opendaylight.yangtools.yang.common.netty.ByteBufUtils;
41
42 /**
43  * Parser for {@link RsvpErrorSpec}.
44  */
45 public final class Stateful07RSVPErrorSpecTlvParser implements TlvParser, TlvSerializer {
46     public static final int TYPE = 21;
47
48     private static final int FLAGS_SIZE = 8;
49     private static final int HEADER_LENGTH = 4;
50
51     private static final int RSVP_ERROR_CLASS_NUM = 6;
52     private static final int RSVP_IPV4_ERROR_CLASS_TYPE = 1;
53     private static final int RSVP_IPV6_ERROR_CLASS_TYPE = 2;
54
55     private static final int USER_ERROR_CLASS_NUM = 194;
56     private static final int USER_ERROR_CLASS_TYPE = 1;
57
58     private static final int IN_PLACE = 7;
59     private static final int NOT_GUILTY = 6;
60
61     @Override
62     public RsvpErrorSpec parseTlv(final ByteBuf buffer) throws PCEPDeserializerException {
63         if (buffer == null) {
64             return null;
65         }
66         // throw away contents of length field
67         buffer.readUnsignedShort();
68         final int classNum = buffer.readUnsignedByte();
69         final int classType = buffer.readUnsignedByte();
70         ErrorType errorType = null;
71         if (classNum == RSVP_ERROR_CLASS_NUM) {
72             errorType = parseRsvp(classType, buffer.slice());
73         } else if (classNum == USER_ERROR_CLASS_NUM && classType == USER_ERROR_CLASS_TYPE) {
74             errorType = parseUserError(buffer.slice());
75         }
76         return new RsvpErrorSpecBuilder().setErrorType(errorType).build();
77     }
78
79     @Override
80     public void serializeTlv(final Tlv tlv, final ByteBuf buffer) {
81         checkArgument(tlv instanceof RsvpErrorSpec, "RSVPErrorSpecTlv is mandatory.");
82         final RsvpErrorSpec rsvp = (RsvpErrorSpec) tlv;
83         final ByteBuf body = Unpooled.buffer();
84         if (rsvp.getErrorType().implementedInterface().equals(RsvpCase.class)) {
85             final RsvpCase r = (RsvpCase) rsvp.getErrorType();
86             serializeRsvp(r.getRsvpError(), body);
87             TlvUtil.formatTlv(TYPE, body, buffer);
88         } else {
89             final UserCase u = (UserCase) rsvp.getErrorType();
90             serializerUserError(u.getUserError(), body);
91             TlvUtil.formatTlv(TYPE, body, buffer);
92         }
93     }
94
95     private static UserCase parseUserError(final ByteBuf buffer) {
96         final UserErrorBuilder error = new UserErrorBuilder()
97                 .setEnterprise(new EnterpriseNumber(ByteBufUtils.readUint32(buffer)));
98         error.setSubOrg(ByteBufUtils.readUint8(buffer));
99         final int errDescrLength = buffer.readUnsignedByte();
100         error.setValue(ByteBufUtils.readUint16(buffer));
101         error.setDescription(ByteArray.bytesToHRString(ByteArray.readBytes(buffer, errDescrLength)));
102         // if we have any subobjects, place the implementation here
103         return new UserCaseBuilder().setUserError(error.build()).build();
104     }
105
106     private static void serializerUserError(final UserError ue, final ByteBuf body) {
107         final String description = ue.getDescription();
108         final byte[] desc = description == null ? new byte[0] : description.getBytes(StandardCharsets.UTF_8);
109         final ByteBuf userErrorBuf = Unpooled.buffer();
110         final EnterpriseNumber enterprise = ue.getEnterprise();
111         checkArgument(enterprise != null, "EnterpriseNumber is mandatory");
112         ByteBufUtils.write(userErrorBuf, enterprise.getValue());
113         ByteBufUtils.writeOrZero(userErrorBuf, ue.getSubOrg());
114         userErrorBuf.writeByte(desc.length);
115         ByteBufUtils.writeMandatory(userErrorBuf, ue.getValue(), "Value");
116         userErrorBuf.writeBytes(desc);
117         userErrorBuf.writeZero(TlvUtil.getPadding(desc.length, TlvUtil.PADDED_TO));
118         formatRSVPObject(USER_ERROR_CLASS_NUM, USER_ERROR_CLASS_TYPE, userErrorBuf, body);
119     }
120
121     private static RsvpCase parseRsvp(final int classType, final ByteBuf buffer) {
122         final RsvpErrorBuilder builder = new RsvpErrorBuilder();
123         if (classType == RSVP_IPV4_ERROR_CLASS_TYPE) {
124             builder.setNode(new IpAddressNoZone(Ipv4Util.noZoneAddressForByteBuf(buffer)));
125         } else if (classType == RSVP_IPV6_ERROR_CLASS_TYPE) {
126             builder.setNode(new IpAddressNoZone(Ipv6Util.noZoneAddressForByteBuf(buffer)));
127         }
128         final BitArray flags = BitArray.valueOf(buffer, FLAGS_SIZE);
129         builder.setFlags(new Flags(flags.get(IN_PLACE), flags.get(NOT_GUILTY)));
130         builder.setCode(ByteBufUtils.readUint8(buffer));
131         builder.setValue(ByteBufUtils.readUint16(buffer));
132         return new RsvpCaseBuilder().setRsvpError(builder.build()).build();
133     }
134
135     private static void serializeRsvp(final RsvpError rsvp, final ByteBuf body) {
136         final BitArray flags = new BitArray(FLAGS_SIZE);
137         flags.set(IN_PLACE, rsvp.getFlags().isInPlace());
138         flags.set(NOT_GUILTY, rsvp.getFlags().isNotGuilty());
139         final IpAddressNoZone node = rsvp.getNode();
140         checkArgument(node != null, "Node is mandatory.");
141         final ByteBuf rsvpObjBuf = Unpooled.buffer();
142         int type = 0;
143         if (node.getIpv4AddressNoZone() != null) {
144             type = RSVP_IPV4_ERROR_CLASS_TYPE;
145             writeIpv4Address(node.getIpv4AddressNoZone(), rsvpObjBuf);
146         } else {
147             type = RSVP_IPV6_ERROR_CLASS_TYPE;
148             writeIpv6Address(node.getIpv6AddressNoZone(), rsvpObjBuf);
149         }
150         flags.toByteBuf(rsvpObjBuf);
151         ByteBufUtils.writeMandatory(rsvpObjBuf, rsvp.getCode(), "Code");
152         ByteBufUtils.writeMandatory(rsvpObjBuf, rsvp.getValue(), "Value");
153         formatRSVPObject(RSVP_ERROR_CLASS_NUM, type, rsvpObjBuf, body);
154     }
155
156     private static void formatRSVPObject(final int objClass, final int type, final ByteBuf body, final ByteBuf out) {
157         out.writeShort(body.writerIndex() + HEADER_LENGTH);
158         out.writeByte(objClass);
159         out.writeByte(type);
160         out.writeBytes(body);
161     }
162 }