blob: 339e46c9efd3bb259a6c8b897d5ddf52dd4e9999 [file] [log] [blame]
Thomas Vachuska781d18b2014-10-27 10:31:25 -07001/*
Thomas Vachuska4f1a60c2014-10-28 13:39:07 -07002 * Copyright 2014 Open Networking Laboratory
Thomas Vachuska781d18b2014-10-27 10:31:25 -07003 *
Thomas Vachuska4f1a60c2014-10-28 13:39:07 -07004 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
Thomas Vachuska781d18b2014-10-27 10:31:25 -07007 *
Thomas Vachuska4f1a60c2014-10-28 13:39:07 -07008 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
Thomas Vachuska781d18b2014-10-27 10:31:25 -070015 */
Jonathan Hartab63aac2014-10-16 08:52:55 -070016package org.onlab.onos.sdnip.bgp;
17
18import org.jboss.netty.buffer.ChannelBuffer;
19import org.jboss.netty.buffer.ChannelBuffers;
20import org.jboss.netty.channel.Channel;
21import org.jboss.netty.channel.ChannelHandlerContext;
22import org.jboss.netty.handler.codec.frame.FrameDecoder;
23import org.onlab.onos.sdnip.bgp.BgpConstants.Notifications.MessageHeaderError;
24import org.slf4j.Logger;
25import org.slf4j.LoggerFactory;
26
27/**
28 * Class for handling the decoding of the BGP messages.
29 */
30class BgpFrameDecoder extends FrameDecoder {
31 private static final Logger log =
32 LoggerFactory.getLogger(BgpFrameDecoder.class);
33
34 private final BgpSession bgpSession;
35
36 /**
37 * Constructor for a given BGP Session.
38 *
39 * @param bgpSession the BGP session state to use.
40 */
41 BgpFrameDecoder(BgpSession bgpSession) {
42 this.bgpSession = bgpSession;
43 }
44
45 @Override
46 protected Object decode(ChannelHandlerContext ctx,
47 Channel channel,
48 ChannelBuffer buf) throws Exception {
49 //
50 // NOTE: If we close the channel during the decoding, we might still
51 // see some incoming messages while the channel closing is completed.
52 //
53 if (bgpSession.isClosed()) {
54 return null;
55 }
56
57 log.trace("BGP Peer: decode(): remoteAddr = {} localAddr = {} " +
58 "messageSize = {}",
59 ctx.getChannel().getRemoteAddress(),
60 ctx.getChannel().getLocalAddress(),
61 buf.readableBytes());
62
63 // Test for minimum length of the BGP message
64 if (buf.readableBytes() < BgpConstants.BGP_HEADER_LENGTH) {
65 // No enough data received
66 return null;
67 }
68
69 //
70 // Mark the current buffer position in case we haven't received
71 // the whole message.
72 //
73 buf.markReaderIndex();
74
75 //
76 // Read and check the BGP message Marker field: it must be all ones
77 // (See RFC 4271, Section 4.1)
78 //
79 byte[] marker = new byte[BgpConstants.BGP_HEADER_MARKER_LENGTH];
80 buf.readBytes(marker);
81 for (int i = 0; i < marker.length; i++) {
82 if (marker[i] != (byte) 0xff) {
83 log.debug("BGP RX Error: invalid marker {} at position {}",
84 marker[i], i);
85 //
86 // ERROR: Connection Not Synchronized
87 //
88 // Send NOTIFICATION and close the connection
89 int errorCode = MessageHeaderError.ERROR_CODE;
90 int errorSubcode =
91 MessageHeaderError.CONNECTION_NOT_SYNCHRONIZED;
92 ChannelBuffer txMessage =
93 bgpSession.prepareBgpNotification(errorCode, errorSubcode,
94 null);
95 ctx.getChannel().write(txMessage);
96 bgpSession.closeChannel(ctx);
97 return null;
98 }
99 }
100
101 //
102 // Read and check the BGP message Length field
103 //
104 int length = buf.readUnsignedShort();
105 if ((length < BgpConstants.BGP_HEADER_LENGTH) ||
106 (length > BgpConstants.BGP_MESSAGE_MAX_LENGTH)) {
107 log.debug("BGP RX Error: invalid Length field {}. " +
108 "Must be between {} and {}",
109 length,
110 BgpConstants.BGP_HEADER_LENGTH,
111 BgpConstants.BGP_MESSAGE_MAX_LENGTH);
112 //
113 // ERROR: Bad Message Length
114 //
115 // Send NOTIFICATION and close the connection
116 ChannelBuffer txMessage =
117 bgpSession.prepareBgpNotificationBadMessageLength(length);
118 ctx.getChannel().write(txMessage);
119 bgpSession.closeChannel(ctx);
120 return null;
121 }
122
123 //
124 // Test whether the rest of the message is received:
125 // So far we have read the Marker (16 octets) and the
126 // Length (2 octets) fields.
127 //
128 int remainingMessageLen =
129 length - BgpConstants.BGP_HEADER_MARKER_LENGTH - 2;
130 if (buf.readableBytes() < remainingMessageLen) {
131 // No enough data received
132 buf.resetReaderIndex();
133 return null;
134 }
135
136 //
137 // Read the BGP message Type field, and process based on that type
138 //
139 int type = buf.readUnsignedByte();
140 remainingMessageLen--; // Adjust after reading the type
141 ChannelBuffer message = buf.readBytes(remainingMessageLen);
142
143 //
144 // Process the remaining of the message based on the message type
145 //
146 switch (type) {
147 case BgpConstants.BGP_TYPE_OPEN:
148 bgpSession.processBgpOpen(ctx, message);
149 break;
150 case BgpConstants.BGP_TYPE_UPDATE:
151 bgpSession.processBgpUpdate(ctx, message);
152 break;
153 case BgpConstants.BGP_TYPE_NOTIFICATION:
154 bgpSession.processBgpNotification(ctx, message);
155 break;
156 case BgpConstants.BGP_TYPE_KEEPALIVE:
157 bgpSession.processBgpKeepalive(ctx, message);
158 break;
159 default:
160 //
161 // ERROR: Bad Message Type
162 //
163 // Send NOTIFICATION and close the connection
164 int errorCode = MessageHeaderError.ERROR_CODE;
165 int errorSubcode = MessageHeaderError.BAD_MESSAGE_TYPE;
166 ChannelBuffer data = ChannelBuffers.buffer(1);
167 data.writeByte(type);
168 ChannelBuffer txMessage =
169 bgpSession.prepareBgpNotification(errorCode, errorSubcode,
170 data);
171 ctx.getChannel().write(txMessage);
172 bgpSession.closeChannel(ctx);
173 return null;
174 }
175 return null;
176 }
177}