Merge "BUG-99: cleanup packages"
[bgpcep.git] / bgp / parser-impl / src / main / java / org / opendaylight / protocol / bgp / parser / impl / message / BGPOpenMessageParser.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;
9
10 import java.util.Arrays;
11 import java.util.List;
12 import java.util.Map;
13 import java.util.Map.Entry;
14
15 import org.opendaylight.protocol.bgp.parser.BGPDocumentedException;
16 import org.opendaylight.protocol.bgp.parser.BGPError;
17 import org.opendaylight.protocol.bgp.parser.BGPParsingException;
18 import org.opendaylight.protocol.bgp.parser.impl.message.open.BGPParameterParser;
19 import org.opendaylight.protocol.concepts.Ipv4Util;
20 import org.opendaylight.protocol.util.ByteArray;
21 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.AsNumber;
22 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv4Address;
23 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130918.Open;
24 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130918.OpenBuilder;
25 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130918.open.BgpParameters;
26 import org.slf4j.Logger;
27 import org.slf4j.LoggerFactory;
28
29 import com.google.common.collect.Lists;
30 import com.google.common.collect.Maps;
31 import com.google.common.primitives.UnsignedBytes;
32
33 /**
34  * Parser for BGP Open message.
35  */
36 public final class BGPOpenMessageParser {
37
38         private static final Logger logger = LoggerFactory.getLogger(BGPOpenMessageParser.class);
39
40         private static final int VERSION_SIZE = 1;
41         private static final int AS_SIZE = 2;
42         private static final int HOLD_TIME_SIZE = 2;
43         private static final int BGP_ID_SIZE = 4;
44         private static final int OPT_PARAM_LENGTH_SIZE = 1;
45
46         private static final int MIN_MSG_LENGTH = VERSION_SIZE + AS_SIZE + HOLD_TIME_SIZE + BGP_ID_SIZE + OPT_PARAM_LENGTH_SIZE;
47
48         private static final int BGP_VERSION = 4;
49
50         private BGPOpenMessageParser() {
51
52         }
53
54         /**
55          * Serializes given BGP Open message to byte array, without the header.
56          * 
57          * @param msg BGP Open message to be serialized.
58          * @return BGP Open message converted to byte array
59          */
60         public static byte[] put(final Open msg) {
61                 if (msg == null)
62                         throw new IllegalArgumentException("BGPOpen message cannot be null");
63                 logger.trace("Started serializing open message: {}", msg);
64
65                 final Map<byte[], Integer> optParams = Maps.newHashMap();
66
67                 int optParamsLength = 0;
68
69                 if (msg.getBgpParameters() != null) {
70                         for (final BgpParameters param : msg.getBgpParameters()) {
71                                 final byte[] p = BGPParameterParser.put(param);
72                                 optParams.put(p, p.length);
73                                 optParamsLength += p.length;
74                         }
75                 }
76
77                 final byte[] msgBody = (msg.getBgpParameters() == null || msg.getBgpParameters().isEmpty()) ? new byte[MIN_MSG_LENGTH]
78                                 : new byte[MIN_MSG_LENGTH + optParamsLength];
79
80                 int offset = 0;
81
82                 msgBody[offset] = ByteArray.intToBytes(BGP_VERSION)[(Integer.SIZE / Byte.SIZE) - 1];
83                 offset += VERSION_SIZE;
84
85                 // When our AS number does not fit into two bytes, we report it as AS_TRANS
86                 int openAS = msg.getMyAsNumber();
87                 if (openAS > 65535)
88                         openAS = 2345;
89
90                 System.arraycopy(ByteArray.longToBytes(openAS), 6, msgBody, offset, AS_SIZE);
91                 offset += AS_SIZE;
92
93                 System.arraycopy(ByteArray.intToBytes(msg.getHoldTimer()), 2, msgBody, offset, HOLD_TIME_SIZE);
94                 offset += HOLD_TIME_SIZE;
95
96                 System.arraycopy(Ipv4Util.bytesForAddress(msg.getBgpIdentifier()), 0, msgBody, offset, BGP_ID_SIZE);
97                 offset += BGP_ID_SIZE;
98
99                 msgBody[offset] = ByteArray.intToBytes(optParamsLength)[Integer.SIZE / Byte.SIZE - 1];
100
101                 int index = MIN_MSG_LENGTH;
102                 if (optParams != null) {
103                         for (final Entry<byte[], Integer> entry : optParams.entrySet()) {
104                                 System.arraycopy(entry.getKey(), 0, msgBody, index, entry.getValue());
105                                 index += entry.getValue();
106                         }
107                 }
108                 logger.trace("Open message serialized to: {}", Arrays.toString(msgBody));
109                 return msgBody;
110         }
111
112         /**
113          * Parses given byte array to BGP Open message
114          * 
115          * @param bytes byte array representing BGP Open message, without header
116          * @return BGP Open Message
117          * @throws BGPDocumentedException if the parsing was unsuccessful
118          */
119         public static Open parse(final byte[] bytes) throws BGPDocumentedException {
120                 if (bytes == null || bytes.length == 0)
121                         throw new IllegalArgumentException("Byte array cannot be null or empty.");
122                 logger.trace("Started parsing of open message: {}", Arrays.toString(bytes));
123
124                 if (bytes.length < MIN_MSG_LENGTH)
125                         throw new BGPDocumentedException("Open message too small.", BGPError.BAD_MSG_LENGTH, ByteArray.intToBytes(bytes.length));
126                 if (UnsignedBytes.toInt(bytes[0]) != BGP_VERSION)
127                         throw new BGPDocumentedException("BGP Protocol version " + UnsignedBytes.toInt(bytes[0]) + " not supported.", BGPError.VERSION_NOT_SUPPORTED, ByteArray.subByte(
128                                         ByteArray.intToBytes(BGP_VERSION), 2, 2));
129
130                 int offset = VERSION_SIZE;
131                 final AsNumber as = new AsNumber(ByteArray.bytesToLong(ByteArray.subByte(bytes, offset, AS_SIZE)));
132                 offset += AS_SIZE;
133
134                 // TODO: BAD_PEER_AS Error: when is an AS unacceptable?
135
136                 final short holdTime = ByteArray.bytesToShort(ByteArray.subByte(bytes, offset, HOLD_TIME_SIZE));
137                 offset += HOLD_TIME_SIZE;
138                 if (holdTime == 1 || holdTime == 2)
139                         throw new BGPDocumentedException("Hold time value not acceptable.", BGPError.HOLD_TIME_NOT_ACC);
140
141                 Ipv4Address bgpId = null;
142                 try {
143                         bgpId = Ipv4Util.addressForBytes(ByteArray.subByte(bytes, offset, BGP_ID_SIZE));
144                 } catch (final IllegalArgumentException e) {
145                         throw new BGPDocumentedException("BGP Identifier is not a valid IPv4 Address", BGPError.BAD_BGP_ID);
146                 }
147                 offset += BGP_ID_SIZE;
148
149                 final int optLength = UnsignedBytes.toInt(bytes[offset]);
150
151                 List<BgpParameters> optParams = Lists.newArrayList();
152                 if (optLength > 0) {
153                         try {
154                                 optParams = BGPParameterParser.parse(ByteArray.subByte(bytes, MIN_MSG_LENGTH, optLength));
155                         } catch (final BGPParsingException e) {
156                                 throw new BGPDocumentedException("Optional parameter not parsed: ." + e.getMessage(), BGPError.UNSPECIFIC_OPEN_ERROR);
157                         }
158                 }
159                 logger.trace("Open message was parsed: AS = {}, holdTimer = {}, bgpId = {}, optParams = {}", as, holdTime, bgpId, optParams);
160                 return new OpenBuilder().setMyAsNumber(as.getValue().intValue()).setHoldTimer((int) holdTime).setBgpIdentifier(bgpId).setBgpParameters(
161                                 optParams).build();
162         }
163 }