Initial code drop
[bgpcep.git] / bgp / parser-impl / src / main / java / org / opendaylight / protocol / bgp / parser / impl / message / BGPNotificationMessageParser.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
12 import org.slf4j.Logger;
13 import org.slf4j.LoggerFactory;
14
15 import org.opendaylight.protocol.bgp.parser.BGPDocumentedException;
16 import org.opendaylight.protocol.bgp.parser.BGPError;
17 import org.opendaylight.protocol.bgp.parser.message.BGPNotificationMessage;
18 import org.opendaylight.protocol.util.ByteArray;
19 import com.google.common.primitives.UnsignedBytes;
20
21 /**
22  * Parser for BGPNotification message.
23  */
24 public final class BGPNotificationMessageParser {
25
26         private static final Logger logger = LoggerFactory.getLogger(BGPNotificationMessageParser.class);
27
28         private static final int ERROR_SIZE = 2; // bytes
29
30         private static class BGPErr {
31                 private final int errorCode;
32                 private final int errorSubcode;
33
34                 public BGPErr(final int errorCode, final int errorSubcode) {
35                         this.errorCode = errorCode;
36                         this.errorSubcode = errorSubcode;
37                 }
38
39                 public int getErrorCode() {
40                         return this.errorCode;
41                 }
42
43                 public int getErrorSubcode() {
44                         return this.errorSubcode;
45                 }
46         }
47
48         /**
49          * Serializes BGP Notification message.
50          * 
51          * @param msg to be serialized
52          * @return BGP Notification message converted to byte array
53          */
54         public static byte[] put(final BGPNotificationMessage msg) {
55                 if (msg == null)
56                         throw new IllegalArgumentException("BGP Notification message cannot be null");
57                 logger.trace("Started serializing Notification message: {}", msg);
58
59                 final byte[] msgBody = (msg.getData() == null) ? new byte[ERROR_SIZE] : new byte[ERROR_SIZE + msg.getData().length];
60
61                 final BGPErr numError = parseBGPError(msg.getError());
62
63                 if (numError == null)
64                         throw new IllegalArgumentException("Cannot parse BGP Error: " + msg.getError());
65
66                 msgBody[0] = ByteArray.intToBytes(numError.getErrorCode())[Integer.SIZE / Byte.SIZE - 1];
67
68                 msgBody[1] = ByteArray.intToBytes(numError.getErrorSubcode())[Integer.SIZE / Byte.SIZE - 1];
69
70                 if (msg.getData() != null)
71                         System.arraycopy(msg.getData(), 0, msgBody, ERROR_SIZE, msg.getData().length);
72                 logger.trace("Notification message serialized to: {}", Arrays.toString(msgBody));
73                 return msgBody;
74         }
75
76         /**
77          * Parses BGP Notification message to bytes.
78          * 
79          * @param bytes byte array to be parsed
80          * @return BGPNotification message
81          * @throws BGPDocumentedException
82          */
83         public static BGPNotificationMessage parse(final byte[] bytes) throws BGPDocumentedException {
84                 if (bytes == null || bytes.length == 0)
85                         throw new IllegalArgumentException("Byte array cannot be null or empty.");
86                 logger.trace("Started parsing of notification message: {}", Arrays.toString(bytes));
87
88                 if (bytes.length < ERROR_SIZE)
89                         throw new BGPDocumentedException("Notification message too small.", BGPError.BAD_MSG_LENGTH, ByteArray.intToBytes(bytes.length));
90                 final int errorCode = UnsignedBytes.toInt(bytes[0]);
91                 final int errorSubcode = UnsignedBytes.toInt(bytes[1]);
92
93                 final BGPError err = putBGPError(new BGPErr(errorCode, errorSubcode));
94                 byte[] data = null;
95                 if (bytes.length > ERROR_SIZE) {
96                         data = ByteArray.subByte(bytes, ERROR_SIZE, bytes.length - ERROR_SIZE);
97                 }
98                 logger.trace("Notification message was parsed: err = {}, data = {}.", err, Arrays.toString(data));
99                 return (data == null) ? new BGPNotificationMessage(err) : new BGPNotificationMessage(err, data);
100         }
101
102         private static BGPErr parseBGPError(final BGPError err) {
103                 switch (err) {
104                 case CONNECTION_NOT_SYNC:
105                         return new BGPErr(1, 1);
106                 case BAD_MSG_LENGTH:
107                         return new BGPErr(1, 2);
108                 case BAD_MSG_TYPE:
109                         return new BGPErr(1, 3);
110                 case UNSPECIFIC_OPEN_ERROR:
111                         return new BGPErr(2, 0);
112                 case VERSION_NOT_SUPPORTED:
113                         return new BGPErr(2, 1);
114                 case BAD_PEER_AS:
115                         return new BGPErr(2, 2);
116                 case BAD_BGP_ID:
117                         return new BGPErr(2, 3);
118                 case OPT_PARAM_NOT_SUPPORTED:
119                         return new BGPErr(2, 4);
120                 case HOLD_TIME_NOT_ACC:
121                         return new BGPErr(2, 6);
122                 case MALFORMED_ATTR_LIST:
123                         return new BGPErr(3, 1);
124                 case WELL_KNOWN_ATTR_NOT_RECOGNIZED:
125                         return new BGPErr(3, 2);
126                 case WELL_KNOWN_ATTR_MISSING:
127                         return new BGPErr(3, 3);
128                 case ATTR_FLAGS_MISSING:
129                         return new BGPErr(3, 4);
130                 case ATTR_LENGTH_ERROR:
131                         return new BGPErr(3, 5);
132                 case ORIGIN_ATTR_NOT_VALID:
133                         return new BGPErr(3, 6);
134                 case NEXT_HOP_NOT_VALID:
135                         return new BGPErr(3, 8);
136                 case OPT_ATTR_ERROR:
137                         return new BGPErr(3, 9);
138                 case NETWORK_NOT_VALID:
139                         return new BGPErr(3, 10);
140                 case AS_PATH_MALFORMED:
141                         return new BGPErr(3, 11);
142                 case HOLD_TIMER_EXPIRED:
143                         return new BGPErr(4, 0);
144                 case FSM_ERROR:
145                         return new BGPErr(5, 0);
146                 case CEASE:
147                         return new BGPErr(6, 0);
148                 default:
149                         return null;
150                 }
151         }
152
153         private static BGPError putBGPError(final BGPErr err) {
154                 final int e = err.getErrorCode();
155                 final int s = err.getErrorSubcode();
156                 if (e == 1) {
157                         if (s == 1)
158                                 return BGPError.CONNECTION_NOT_SYNC;
159                         if (s == 2)
160                                 return BGPError.BAD_MSG_LENGTH;
161                         if (s == 3)
162                                 return BGPError.BAD_MSG_TYPE;
163                 } else if (e == 2) {
164                         if (s == 0)
165                                 return BGPError.UNSPECIFIC_OPEN_ERROR;
166                         if (s == 1)
167                                 return BGPError.VERSION_NOT_SUPPORTED;
168                         if (s == 2)
169                                 return BGPError.BAD_PEER_AS;
170                         if (s == 3)
171                                 return BGPError.BAD_BGP_ID;
172                         if (s == 4)
173                                 return BGPError.OPT_PARAM_NOT_SUPPORTED;
174                         if (s == 6)
175                                 return BGPError.HOLD_TIME_NOT_ACC;
176                 } else if (e == 3) {
177                         if (s == 1)
178                                 return BGPError.MALFORMED_ATTR_LIST;
179                         if (s == 2)
180                                 return BGPError.WELL_KNOWN_ATTR_NOT_RECOGNIZED;
181                         if (s == 3)
182                                 return BGPError.WELL_KNOWN_ATTR_MISSING;
183                         if (s == 4)
184                                 return BGPError.ATTR_FLAGS_MISSING;
185                         if (s == 5)
186                                 return BGPError.ATTR_LENGTH_ERROR;
187                         if (s == 6)
188                                 return BGPError.ORIGIN_ATTR_NOT_VALID;
189                         if (s == 8)
190                                 return BGPError.NEXT_HOP_NOT_VALID;
191                         if (s == 9)
192                                 return BGPError.OPT_ATTR_ERROR;
193                         if (s == 10)
194                                 return BGPError.NETWORK_NOT_VALID;
195                         if (s == 11)
196                                 return BGPError.AS_PATH_MALFORMED;
197                 } else if (e == 4)
198                         return BGPError.HOLD_TIMER_EXPIRED;
199                 else if (e == 5)
200                         return BGPError.FSM_ERROR;
201                 else if (e == 6)
202                         return BGPError.CEASE;
203                 throw new IllegalArgumentException("BGP Error code " + e + " and subcode " + s + " not recognized.");
204         }
205 }