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