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