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