Promote MessageRegistry to pcep-api
[bgpcep.git] / pcep / segment-routing / src / main / java / org / opendaylight / protocol / pcep / segment / routing / AbstractSrSubobjectParser.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.pcep.segment.routing;
9
10 import static com.google.common.base.Preconditions.checkArgument;
11
12 import io.netty.buffer.ByteBuf;
13 import io.netty.buffer.Unpooled;
14 import org.opendaylight.protocol.pcep.PCEPDeserializerException;
15 import org.opendaylight.protocol.util.BitArray;
16 import org.opendaylight.protocol.util.Ipv4Util;
17 import org.opendaylight.protocol.util.Ipv6Util;
18 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddressNoZone;
19 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.segment.routing.rev200720.NaiType;
20 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.segment.routing.rev200720.SrSubobject;
21 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.segment.routing.rev200720.sr.subobject.Nai;
22 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.segment.routing.rev200720.sr.subobject.nai.IpAdjacency;
23 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.segment.routing.rev200720.sr.subobject.nai.IpAdjacencyBuilder;
24 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.segment.routing.rev200720.sr.subobject.nai.IpNodeId;
25 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.segment.routing.rev200720.sr.subobject.nai.IpNodeIdBuilder;
26 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.segment.routing.rev200720.sr.subobject.nai.Ipv6Local;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.segment.routing.rev200720.sr.subobject.nai.Ipv6LocalBuilder;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.segment.routing.rev200720.sr.subobject.nai.UnnumberedAdjacency;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.segment.routing.rev200720.sr.subobject.nai.UnnumberedAdjacencyBuilder;
30 import org.opendaylight.yangtools.yang.common.Uint32;
31 import org.opendaylight.yangtools.yang.common.netty.ByteBufUtils;
32
33 public abstract class AbstractSrSubobjectParser {
34     protected static final int MINIMAL_LENGTH = 4;
35     protected static final int BITSET_LENGTH = 8;
36     protected static final int M_FLAG_POSITION = 7;
37     protected static final int C_FLAG_POSITION = 6;
38     protected static final int S_FLAG_POSITION = 5;
39     protected static final int F_FLAG_POSITION = 4;
40     protected static final int MPLS_LABEL_OFFSET = 12;
41
42     private static final int NAI_TYPE_BITS_OFFSET = 4;
43
44     private static class SrSubobjectImpl implements SrSubobject {
45         private final boolean mflag;
46         private final boolean cflag;
47         private final NaiType naiType;
48         private final Uint32 sid;
49         private final Nai nai;
50
51         SrSubobjectImpl(final boolean mflag, final boolean cflag, final NaiType naiType, final Uint32 sid,
52                 final Nai nai) {
53             this.mflag = mflag;
54             this.cflag = cflag;
55             this.naiType = naiType;
56             this.sid = sid;
57             this.nai = nai;
58         }
59
60         @Override
61         public Class<SrSubobject> implementedInterface() {
62             return SrSubobject.class;
63         }
64
65         @Override
66         public Boolean getMFlag() {
67             return mflag;
68         }
69
70         @Override
71         public Boolean getCFlag() {
72             return cflag;
73         }
74
75         @Override
76         public NaiType getNaiType() {
77             return naiType;
78         }
79
80         @Override
81         public Uint32 getSid() {
82             return sid;
83         }
84
85         @Override
86         public Nai getNai() {
87             return nai;
88         }
89     }
90
91     public ByteBuf serializeSubobject(final SrSubobject srSubobject) {
92         checkArgument(srSubobject.getNai() != null || srSubobject.getSid() != null,
93                 "Both SID and NAI are absent in SR subobject.");
94
95         final ByteBuf buffer = Unpooled.buffer(MINIMAL_LENGTH);
96
97         /* Write NAI Type */
98         buffer.writeByte(srSubobject.getNaiType().getIntValue() << NAI_TYPE_BITS_OFFSET);
99
100         /* Flags set according to RFC8664#section 4.3.1 */
101         final BitArray bits = new BitArray(BITSET_LENGTH);
102         bits.set(M_FLAG_POSITION, srSubobject.getMFlag());
103         /* C flag MUST be set to 0 if M flag is set to 0 */
104         if (!srSubobject.getMFlag()) {
105             bits.set(C_FLAG_POSITION, Boolean.FALSE);
106         } else {
107             bits.set(C_FLAG_POSITION, srSubobject.getCFlag());
108         }
109         /* M & C flags MUST be set to 0 if S flag is set to 1 */
110         if (srSubobject.getSid() == null) {
111             bits.set(M_FLAG_POSITION, Boolean.FALSE);
112             bits.set(C_FLAG_POSITION, Boolean.FALSE);
113             bits.set(S_FLAG_POSITION, Boolean.TRUE);
114         }
115         /* F flag MUST be set if NT=0 or NAI is absent */
116         if (srSubobject.getNai() == null || srSubobject.getNaiType().getIntValue() == 0) {
117             bits.set(F_FLAG_POSITION, Boolean.TRUE);
118         }
119         /* Write Flags */
120         bits.toByteBuf(buffer);
121
122         /* Write SID */
123         if (srSubobject.getSid() != null) {
124             if (srSubobject.getMFlag()) {
125                 buffer.writeInt(srSubobject.getSid().intValue() << MPLS_LABEL_OFFSET);
126             } else {
127                 ByteBufUtils.writeOrZero(buffer, srSubobject.getSid());
128             }
129         }
130
131         /* Write NAI */
132         final Nai nai = srSubobject.getNai();
133         if (nai != null) {
134             serializeNai(nai, srSubobject.getNaiType(), buffer);
135         }
136         return buffer;
137     }
138
139     private static void serializeNai(final Nai nai, final NaiType naiType, final ByteBuf buffer) {
140         switch (naiType) {
141             case Ipv4NodeId:
142                 Ipv4Util.writeIpv4Address(((IpNodeId) nai).getIpAddress().getIpv4AddressNoZone(), buffer);
143                 break;
144             case Ipv6NodeId:
145                 Ipv6Util.writeIpv6Address(((IpNodeId) nai).getIpAddress().getIpv6AddressNoZone(), buffer);
146                 break;
147             case Ipv4Adjacency:
148                 Ipv4Util.writeIpv4Address(((IpAdjacency) nai).getLocalIpAddress().getIpv4AddressNoZone(), buffer);
149                 Ipv4Util.writeIpv4Address(((IpAdjacency) nai).getRemoteIpAddress().getIpv4AddressNoZone(), buffer);
150                 break;
151             case Ipv6Adjacency:
152                 Ipv6Util.writeIpv6Address(((IpAdjacency) nai).getLocalIpAddress().getIpv6AddressNoZone(), buffer);
153                 Ipv6Util.writeIpv6Address(((IpAdjacency) nai).getRemoteIpAddress().getIpv6AddressNoZone(), buffer);
154                 break;
155             case Unnumbered:
156                 final UnnumberedAdjacency unnumbered = (UnnumberedAdjacency) nai;
157                 ByteBufUtils.writeOrZero(buffer, unnumbered.getLocalNodeId());
158                 ByteBufUtils.writeOrZero(buffer, unnumbered.getLocalInterfaceId());
159                 ByteBufUtils.writeOrZero(buffer, unnumbered.getRemoteNodeId());
160                 ByteBufUtils.writeOrZero(buffer, unnumbered.getRemoteInterfaceId());
161                 break;
162             case Ipv6Local:
163                 final Ipv6Local ipv6Local = (Ipv6Local) nai;
164                 Ipv6Util.writeIpv6Address(ipv6Local.getLocalIpv6Address(), buffer);
165                 ByteBufUtils.writeOrZero(buffer, ipv6Local.getLocalId());
166                 Ipv6Util.writeIpv6Address(ipv6Local.getRemoteIpv6Address(), buffer);
167                 ByteBufUtils.writeOrZero(buffer, ipv6Local.getRemoteId());
168                 break;
169             default:
170                 break;
171         }
172     }
173
174     private static Nai parseNai(final NaiType naiType, final ByteBuf buffer) {
175         return switch (naiType) {
176             case Ipv4NodeId -> new IpNodeIdBuilder()
177                 .setIpAddress(new IpAddressNoZone(Ipv4Util.addressForByteBuf(buffer)))
178                 .build();
179             case Ipv6NodeId -> new IpNodeIdBuilder()
180                 .setIpAddress(new IpAddressNoZone(Ipv6Util.addressForByteBuf(buffer)))
181                 .build();
182             case Ipv4Adjacency -> new IpAdjacencyBuilder()
183                 .setLocalIpAddress(new IpAddressNoZone(Ipv4Util.addressForByteBuf(buffer)))
184                 .setRemoteIpAddress(new IpAddressNoZone(Ipv4Util.addressForByteBuf(buffer)))
185                 .build();
186             case Ipv6Adjacency -> new IpAdjacencyBuilder()
187                 .setLocalIpAddress(new IpAddressNoZone(Ipv6Util.addressForByteBuf(buffer)))
188                 .setRemoteIpAddress(new IpAddressNoZone(Ipv6Util.addressForByteBuf(buffer)))
189                 .build();
190             case Unnumbered -> new UnnumberedAdjacencyBuilder()
191                 .setLocalNodeId(ByteBufUtils.readUint32(buffer))
192                 .setLocalInterfaceId(ByteBufUtils.readUint32(buffer))
193                 .setRemoteNodeId(ByteBufUtils.readUint32(buffer))
194                 .setRemoteInterfaceId(ByteBufUtils.readUint32(buffer))
195                 .build();
196             case Ipv6Local -> new Ipv6LocalBuilder()
197                 .setLocalIpv6Address(Ipv6Util.addressForByteBuf(buffer))
198                 .setLocalId(ByteBufUtils.readUint32(buffer))
199                 .setRemoteIpv6Address(Ipv6Util.addressForByteBuf(buffer))
200                 .setRemoteId(ByteBufUtils.readUint32(buffer))
201                 .build();
202             default -> null;
203         };
204     }
205
206     protected static SrSubobject parseSrSubobject(final ByteBuf buffer) throws PCEPDeserializerException {
207         final int naiTypeByte = buffer.readByte() >> NAI_TYPE_BITS_OFFSET;
208         final NaiType naiType = NaiType.forValue(naiTypeByte);
209         final BitArray bitSet = BitArray.valueOf(buffer.readByte());
210         final boolean f = bitSet.get(F_FLAG_POSITION);
211         final boolean s = bitSet.get(S_FLAG_POSITION);
212         final boolean c = bitSet.get(C_FLAG_POSITION);
213         final boolean m = bitSet.get(M_FLAG_POSITION);
214
215         if (f && s) {
216             throw new PCEPDeserializerException("Both SID and NAI are absent in SR subobject.");
217         }
218
219         final Uint32 sid;
220         if (!s) {
221             final long tmp = buffer.readUnsignedInt();
222             sid = Uint32.valueOf(m ? tmp >> MPLS_LABEL_OFFSET : tmp);
223         } else {
224             sid = null;
225         }
226         final Nai nai;
227         if (naiType != null && naiType.getIntValue() != 0 && !f) {
228             nai = parseNai(naiType, buffer);
229         } else {
230             nai = null;
231         }
232         return new SrSubobjectImpl(m, c, naiType, sid, nai);
233     }
234 }