291d974bba324b6b5c54ffa9a84d83cc5bae9bf4
[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.spi.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.rev181109.SidType;
20 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.segment.routing.rev181109.SrSubobject;
21 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.segment.routing.rev181109.sr.subobject.Nai;
22 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.segment.routing.rev181109.sr.subobject.nai.IpAdjacency;
23 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.segment.routing.rev181109.sr.subobject.nai.IpAdjacencyBuilder;
24 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.segment.routing.rev181109.sr.subobject.nai.IpNodeId;
25 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.segment.routing.rev181109.sr.subobject.nai.IpNodeIdBuilder;
26 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.segment.routing.rev181109.sr.subobject.nai.UnnumberedAdjacency;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.segment.routing.rev181109.sr.subobject.nai.UnnumberedAdjacencyBuilder;
28 import org.opendaylight.yangtools.yang.common.Uint32;
29 import org.opendaylight.yangtools.yang.common.netty.ByteBufUtils;
30
31 public abstract class AbstractSrSubobjectParser {
32     protected static final int MINIMAL_LENGTH = 4;
33     protected static final int BITSET_LENGTH = 8;
34     protected static final int M_FLAG_POSITION = 7;
35     protected static final int C_FLAG_POSITION = 6;
36     protected static final int S_FLAG_POSITION = 5;
37     protected static final int F_FLAG_POSITION = 4;
38     protected static final int MPLS_LABEL_OFFSET = 12;
39
40     private static final int SID_TYPE_BITS_OFFSET = 4;
41
42     private static class SrSubobjectImpl implements SrSubobject {
43         private final boolean mflag;
44         private final boolean cflag;
45         private final SidType sidType;
46         private final Uint32 sid;
47         private final Nai nai;
48
49         SrSubobjectImpl(final boolean mflag, final boolean cflag, final SidType sidType, final Uint32 sid,
50                 final Nai nai) {
51             this.mflag = mflag;
52             this.cflag = cflag;
53             this.sidType = sidType;
54             this.sid = sid;
55             this.nai = nai;
56         }
57
58         @Override
59         public Class<SrSubobject> implementedInterface() {
60             return SrSubobject.class;
61         }
62
63         @Override
64         public Boolean isMFlag() {
65             return this.mflag;
66         }
67
68         @Override
69         public Boolean isCFlag() {
70             return this.cflag;
71         }
72
73         @Override
74         public SidType getSidType() {
75             return this.sidType;
76         }
77
78         @Override
79         public Uint32 getSid() {
80             return this.sid;
81         }
82
83         @Override
84         public Nai getNai() {
85             return this.nai;
86         }
87     }
88
89     public ByteBuf serializeSubobject(final SrSubobject srSubobject) {
90         final ByteBuf buffer = Unpooled.buffer(MINIMAL_LENGTH);
91         // sid type
92         buffer.writeByte(srSubobject.getSidType().getIntValue() << SID_TYPE_BITS_OFFSET);
93
94         final BitArray bits = new BitArray(BITSET_LENGTH);
95         bits.set(M_FLAG_POSITION, srSubobject.isMFlag());
96         bits.set(C_FLAG_POSITION, srSubobject.isCFlag());
97         if (srSubobject.getSid() == null) {
98             bits.set(S_FLAG_POSITION, Boolean.TRUE);
99         }
100         if (srSubobject.getNai() == null) {
101             bits.set(F_FLAG_POSITION, Boolean.TRUE);
102         }
103         // bits
104         bits.toByteBuf(buffer);
105         // sid
106         checkArgument(srSubobject.getNai() != null || srSubobject.getSid() != null,
107                 "Both SID and NAI are absent in SR subobject.");
108         if (srSubobject.getSid() != null) {
109             if (srSubobject.isMFlag()) {
110                 buffer.writeInt(srSubobject.getSid().intValue() << MPLS_LABEL_OFFSET);
111             } else {
112                 ByteBufUtils.writeOrZero(buffer, srSubobject.getSid());
113             }
114         }
115         // nai
116         final Nai nai = srSubobject.getNai();
117         if (nai != null) {
118             serializeNai(nai, srSubobject.getSidType() ,buffer);
119         }
120         return buffer;
121     }
122
123     private static void serializeNai(final Nai nai, final SidType sidType, final ByteBuf buffer) {
124         switch (sidType) {
125             case Ipv4NodeId:
126                 Ipv4Util.writeIpv4Address(((IpNodeId) nai).getIpAddress().getIpv4AddressNoZone(), buffer);
127                 break;
128             case Ipv6NodeId:
129                 Ipv6Util.writeIpv6Address(((IpNodeId) nai).getIpAddress().getIpv6AddressNoZone(), buffer);
130                 break;
131             case Ipv4Adjacency:
132                 Ipv4Util.writeIpv4Address(((IpAdjacency) nai).getLocalIpAddress().getIpv4AddressNoZone(), buffer);
133                 Ipv4Util.writeIpv4Address(((IpAdjacency) nai).getRemoteIpAddress().getIpv4AddressNoZone(), buffer);
134                 break;
135             case Ipv6Adjacency:
136                 Ipv6Util.writeIpv6Address(((IpAdjacency) nai).getLocalIpAddress().getIpv6AddressNoZone(), buffer);
137                 Ipv6Util.writeIpv6Address(((IpAdjacency) nai).getRemoteIpAddress().getIpv6AddressNoZone(), buffer);
138                 break;
139             case Unnumbered:
140                 final UnnumberedAdjacency unnumbered = (UnnumberedAdjacency) nai;
141                 ByteBufUtils.writeOrZero(buffer, unnumbered.getLocalNodeId());
142                 ByteBufUtils.writeOrZero(buffer, unnumbered.getLocalInterfaceId());
143                 ByteBufUtils.writeOrZero(buffer, unnumbered.getRemoteNodeId());
144                 ByteBufUtils.writeOrZero(buffer, unnumbered.getRemoteInterfaceId());
145                 break;
146             default:
147                 break;
148         }
149     }
150
151     private static Nai parseNai(final SidType sidType, final ByteBuf buffer) {
152         switch (sidType) {
153             case Ipv4NodeId:
154                 return new IpNodeIdBuilder().setIpAddress(new IpAddressNoZone(Ipv4Util.addressForByteBuf(buffer)))
155                         .build();
156             case Ipv6NodeId:
157                 return new IpNodeIdBuilder().setIpAddress(new IpAddressNoZone(Ipv6Util.addressForByteBuf(buffer)))
158                         .build();
159             case Ipv4Adjacency:
160                 return new IpAdjacencyBuilder()
161                         .setLocalIpAddress(new IpAddressNoZone(Ipv4Util.addressForByteBuf(buffer)))
162                         .setRemoteIpAddress(new IpAddressNoZone(Ipv4Util.addressForByteBuf(buffer))).build();
163             case Ipv6Adjacency:
164                 return new IpAdjacencyBuilder()
165                         .setLocalIpAddress(new IpAddressNoZone(Ipv6Util.addressForByteBuf(buffer)))
166                         .setRemoteIpAddress(new IpAddressNoZone(Ipv6Util.addressForByteBuf(buffer))).build();
167             case Unnumbered:
168                 return new UnnumberedAdjacencyBuilder()
169                         .setLocalNodeId(ByteBufUtils.readUint32(buffer))
170                         .setLocalInterfaceId(ByteBufUtils.readUint32(buffer))
171                         .setRemoteNodeId(ByteBufUtils.readUint32(buffer))
172                         .setRemoteInterfaceId(ByteBufUtils.readUint32(buffer)).build();
173             default:
174                 return null;
175         }
176     }
177
178     protected static SrSubobject parseSrSubobject(final ByteBuf buffer) throws PCEPDeserializerException {
179         final int sidTypeByte = buffer.readByte() >> SID_TYPE_BITS_OFFSET;
180         final SidType sidType = SidType.forValue(sidTypeByte);
181         final BitArray bitSet = BitArray.valueOf(buffer.readByte());
182         final boolean f = bitSet.get(F_FLAG_POSITION);
183         final boolean s = bitSet.get(S_FLAG_POSITION);
184         final boolean c = bitSet.get(C_FLAG_POSITION);
185         final boolean m = bitSet.get(M_FLAG_POSITION);
186
187         if (f && s) {
188             throw new PCEPDeserializerException("Both SID and NAI are absent in SR subobject.");
189         }
190
191         final Uint32 sid;
192         if (!s) {
193             final long tmp = buffer.readUnsignedInt();
194             sid = Uint32.valueOf(m ? tmp >> MPLS_LABEL_OFFSET : tmp);
195         } else {
196             sid = null;
197         }
198         final Nai nai;
199         if (sidType != null && !f) {
200             nai = parseNai(sidType, buffer);
201         } else {
202             nai = null;
203         }
204         return new SrSubobjectImpl(m, c, sidType, sid, nai);
205     }
206 }