d3af4414f17eebb2726da627fd24c1df63f7b32a
[bgpcep.git] / bgp / parser-impl / src / main / java / org / opendaylight / protocol / bgp / parser / impl / message / open / CapabilityParameterParser.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.bgp.parser.impl.message.open;
9
10 import java.util.Arrays;
11 import java.util.Map.Entry;
12
13 import org.slf4j.Logger;
14 import org.slf4j.LoggerFactory;
15
16
17 import org.opendaylight.protocol.bgp.concepts.BGPAddressFamily;
18 import org.opendaylight.protocol.bgp.concepts.BGPSubsequentAddressFamily;
19 import org.opendaylight.protocol.bgp.concepts.BGPTableType;
20 import org.opendaylight.protocol.bgp.parser.BGPParsingException;
21 import org.opendaylight.protocol.bgp.parser.impl.message.update.MPReachParser;
22 import org.opendaylight.protocol.bgp.parser.parameter.AS4BytesCapability;
23 import org.opendaylight.protocol.bgp.parser.parameter.CapabilityParameter;
24 import org.opendaylight.protocol.bgp.parser.parameter.GracefulCapability;
25 import org.opendaylight.protocol.bgp.parser.parameter.MultiprotocolCapability;
26 import org.opendaylight.protocol.util.ByteArray;
27 import org.opendaylight.protocol.concepts.ASNumber;
28 import com.google.common.primitives.UnsignedBytes;
29
30 /**
31  * Parser for BGP Capability Parameter.
32  */
33 public final class CapabilityParameterParser {
34
35         private static final Logger logger = LoggerFactory.getLogger(CapabilityParameterParser.class);
36
37         private static final int CODE_SIZE = 1; // bytes
38         private static final int LENGTH_SIZE = 1; // bytes
39         private static final int AFI_SIZE = 2; // bytes
40         private static final int SAFI_SIZE = 1; // bytes
41
42         private CapabilityParameterParser() {
43
44         }
45
46         /**
47          * Serializes given BGP Capability Parameter to byte array.
48          * 
49          * @param param BGP Capability to be serialized
50          * @return BGP Capability converted to byte array
51          */
52         public static byte[] put(final CapabilityParameter cap) {
53                 if (cap == null)
54                         throw new IllegalArgumentException("BGP Capability cannot be null");
55                 logger.trace("Started serializing BGP Capability: {}", cap);
56                 byte[] value = null;
57                 if (cap instanceof MultiprotocolCapability) {
58                         value = putMultiProtocolParameterValue((MultiprotocolCapability) cap);
59                 } else if (cap instanceof GracefulCapability) {
60                         value = putGracefulParameterValue((GracefulCapability) cap);
61                 } else if (cap instanceof AS4BytesCapability) {
62                         value = putAS4BytesParameterValue((AS4BytesCapability) cap);
63                 }
64                 final byte[] bytes = new byte[CODE_SIZE + LENGTH_SIZE + value.length];
65                 bytes[0] = ByteArray.intToBytes(cap.getCode())[Integer.SIZE / Byte.SIZE - 1];
66                 bytes[1] = ByteArray.intToBytes(value.length)[Integer.SIZE / Byte.SIZE - 1];
67                 System.arraycopy(value, 0, bytes, CODE_SIZE + LENGTH_SIZE, value.length);
68                 logger.trace("BGP Parameter serialized to: {}", Arrays.toString(bytes));
69                 return bytes;
70         }
71
72         /**
73          * Parses given byte array to Capability Parameter. Only Multiprotocol capability is supported.
74          * 
75          * @param bytes byte array representing BGP Parameters
76          * @return list of BGP Parameters
77          * @throws BGPParsingException if the parsing was unsuccessful
78          */
79         public static CapabilityParameter parse(final byte[] bytes) throws BGPParsingException {
80                 if (bytes == null || bytes.length == 0)
81                         throw new IllegalArgumentException("Byte array cannot be null or empty.");
82                 logger.trace("Started parsing of BGP Capability: {}", Arrays.toString(bytes));
83                 int byteOffset = 0;
84                 final int capCode = UnsignedBytes.toInt(bytes[byteOffset++]);
85                 final int capLength = UnsignedBytes.toInt(bytes[byteOffset++]);
86                 if (capCode == MultiprotocolCapability.CODE) {
87                         logger.trace("Parsed BGP Capability.");
88                         return parseMultiProtocolParameterValue(ByteArray.subByte(bytes, byteOffset, capLength));
89                 } else if (capCode == AS4BytesCapability.CODE) {
90                         logger.trace("Parsed AS4B Capability.");
91                         return parseAS4BParameterValue(ByteArray.subByte(bytes, byteOffset, capLength));
92                 } else
93                         logger.debug("Only Multiprotocol Capability Parameter is supported. Received code {}", capCode);
94                 return null;
95         }
96
97         private static byte[] putGracefulParameterValue(final GracefulCapability param) {
98                 final int RESTART_FLAGS_SIZE = 4; // bits
99                 final int TIMER_SIZE = 12; // bits
100                 final int AFI_SIZE = 2; // bytes
101                 final int SAFI_SIZE = 1; // bytes
102                 final int AF_FLAGS_SIZE = 1; // bytes
103                 final byte[] bytes = new byte[(RESTART_FLAGS_SIZE + TIMER_SIZE + (AFI_SIZE * Byte.SIZE + SAFI_SIZE * Byte.SIZE + AF_FLAGS_SIZE
104                                 * Byte.SIZE)
105                                 * param.getTableTypes().size())
106                                 / Byte.SIZE];
107                 if (param.isRestartFlag())
108                         bytes[0] = (byte) 0x80;
109                 int index = (RESTART_FLAGS_SIZE + TIMER_SIZE) / Byte.SIZE;
110                 for (final Entry<BGPTableType, Boolean> entry : param.getTableTypes().entrySet()) {
111                         final byte[] a = putAfi(entry.getKey().getAddressFamily());
112                         final byte s = putSafi(entry.getKey().getSubsequentAddressFamily());
113                         final byte f = (entry.getValue()) ? (byte) 0x80 : (byte) 0x00;
114                         System.arraycopy(a, 0, bytes, index, AFI_SIZE);
115                         index += AFI_SIZE;
116                         bytes[index] = s;
117                         index += SAFI_SIZE;
118                         bytes[index] = f;
119                         index += AF_FLAGS_SIZE;
120                 }
121                 return bytes;
122         }
123
124         private static byte[] putMultiProtocolParameterValue(final MultiprotocolCapability param) {
125                 final byte[] a = putAfi(param.getAfi());
126                 final byte s = putSafi(param.getSafi());
127
128                 final byte[] bytes = new byte[AFI_SIZE + SAFI_SIZE + 1]; // 2 byte is reserved 2B AFI + 1B Reserved + 1B SAFI
129                 System.arraycopy(a, 0, bytes, 0, AFI_SIZE);
130                 bytes[AFI_SIZE + 1] = s; // +1 = reserved
131                 return bytes;
132         }
133
134         private static byte[] putAS4BytesParameterValue(final AS4BytesCapability param) {
135                 return ByteArray.subByte(ByteArray.longToBytes(param.getASNumber().getAsn()), 4, 4);
136         }
137
138         private static MultiprotocolCapability parseMultiProtocolParameterValue(final byte[] bytes) throws BGPParsingException {
139                 final BGPAddressFamily afi = MPReachParser.parseAfi(ByteArray.bytesToInt(ByteArray.subByte(bytes, 0, AFI_SIZE)));
140                 final BGPSubsequentAddressFamily safi = MPReachParser.parseSafi(ByteArray.bytesToInt(ByteArray.subByte(bytes, AFI_SIZE + 1,
141                                 SAFI_SIZE)));
142                 return new MultiprotocolCapability(new BGPTableType(afi, safi));
143         }
144
145         private static AS4BytesCapability parseAS4BParameterValue(final byte[] bytes) {
146                 return new AS4BytesCapability(new ASNumber(ByteArray.bytesToLong(bytes)));
147         }
148
149         static byte[] putAfi(final BGPAddressFamily afi) {
150                 final byte[] a = ByteArray.intToBytes(serializeAfi(afi));
151                 return ByteArray.subByte(a, Integer.SIZE / Byte.SIZE - AFI_SIZE, AFI_SIZE);
152         }
153
154         static byte putSafi(final BGPSubsequentAddressFamily safi) {
155                 final byte[] a = ByteArray.intToBytes(serializeSafi(safi));
156                 return ByteArray.subByte(a, Integer.SIZE / Byte.SIZE - SAFI_SIZE, SAFI_SIZE)[0];
157         }
158
159         private static int serializeSafi(final BGPSubsequentAddressFamily type) {
160                 switch (type) {
161                 case Unicast:
162                         return 1;
163                 case MPLSLabeledVPN:
164                         return 128;
165                 case Linkstate:
166                         return MPReachParser.LS_SAFI;
167                 }
168                 return 0;
169         }
170
171         private static int serializeAfi(final BGPAddressFamily type) {
172                 switch (type) {
173                 case IPv4:
174                         return 1;
175                 case IPv6:
176                         return 2;
177                 case LinkState:
178                         return MPReachParser.LS_AFI;
179                 }
180                 return 0;
181         }
182 }