Pavlin Radoslavov

Refactor the BGP code in the SDN-IP application:

 * Resolves ONOS-476
 * Moved the BGP message-specific processing from class BgpSession
   to per-message type classes: BgpKeepalive, BgpNotification,
   BgpOpen, BgpUpdate
 * Minor modifications in some of the methods or BGP-specific API
   to accomodate the above change.
   No functional changes.

Change-Id: I95df128fa31c60397a279aaca25a487b7991a6e1
...@@ -90,7 +90,8 @@ class BgpFrameDecoder extends FrameDecoder { ...@@ -90,7 +90,8 @@ class BgpFrameDecoder extends FrameDecoder {
90 int errorSubcode = 90 int errorSubcode =
91 MessageHeaderError.CONNECTION_NOT_SYNCHRONIZED; 91 MessageHeaderError.CONNECTION_NOT_SYNCHRONIZED;
92 ChannelBuffer txMessage = 92 ChannelBuffer txMessage =
93 - bgpSession.prepareBgpNotification(errorCode, errorSubcode, 93 + BgpNotification.prepareBgpNotification(errorCode,
94 + errorSubcode,
94 null); 95 null);
95 ctx.getChannel().write(txMessage); 96 ctx.getChannel().write(txMessage);
96 bgpSession.closeSession(ctx); 97 bgpSession.closeSession(ctx);
...@@ -114,7 +115,7 @@ class BgpFrameDecoder extends FrameDecoder { ...@@ -114,7 +115,7 @@ class BgpFrameDecoder extends FrameDecoder {
114 // 115 //
115 // Send NOTIFICATION and close the connection 116 // Send NOTIFICATION and close the connection
116 ChannelBuffer txMessage = 117 ChannelBuffer txMessage =
117 - bgpSession.prepareBgpNotificationBadMessageLength(length); 118 + BgpNotification.prepareBgpNotificationBadMessageLength(length);
118 ctx.getChannel().write(txMessage); 119 ctx.getChannel().write(txMessage);
119 bgpSession.closeSession(ctx); 120 bgpSession.closeSession(ctx);
120 return null; 121 return null;
...@@ -145,16 +146,16 @@ class BgpFrameDecoder extends FrameDecoder { ...@@ -145,16 +146,16 @@ class BgpFrameDecoder extends FrameDecoder {
145 // 146 //
146 switch (type) { 147 switch (type) {
147 case BgpConstants.BGP_TYPE_OPEN: 148 case BgpConstants.BGP_TYPE_OPEN:
148 - bgpSession.processBgpOpen(ctx, message); 149 + BgpOpen.processBgpOpen(bgpSession, ctx, message);
149 break; 150 break;
150 case BgpConstants.BGP_TYPE_UPDATE: 151 case BgpConstants.BGP_TYPE_UPDATE:
151 - bgpSession.processBgpUpdate(ctx, message); 152 + BgpUpdate.processBgpUpdate(bgpSession, ctx, message);
152 break; 153 break;
153 case BgpConstants.BGP_TYPE_NOTIFICATION: 154 case BgpConstants.BGP_TYPE_NOTIFICATION:
154 - bgpSession.processBgpNotification(ctx, message); 155 + BgpNotification.processBgpNotification(bgpSession, ctx, message);
155 break; 156 break;
156 case BgpConstants.BGP_TYPE_KEEPALIVE: 157 case BgpConstants.BGP_TYPE_KEEPALIVE:
157 - bgpSession.processBgpKeepalive(ctx, message); 158 + BgpKeepalive.processBgpKeepalive(bgpSession, ctx, message);
158 break; 159 break;
159 default: 160 default:
160 // 161 //
...@@ -166,7 +167,7 @@ class BgpFrameDecoder extends FrameDecoder { ...@@ -166,7 +167,7 @@ class BgpFrameDecoder extends FrameDecoder {
166 ChannelBuffer data = ChannelBuffers.buffer(1); 167 ChannelBuffer data = ChannelBuffers.buffer(1);
167 data.writeByte(type); 168 data.writeByte(type);
168 ChannelBuffer txMessage = 169 ChannelBuffer txMessage =
169 - bgpSession.prepareBgpNotification(errorCode, errorSubcode, 170 + BgpNotification.prepareBgpNotification(errorCode, errorSubcode,
170 data); 171 data);
171 ctx.getChannel().write(txMessage); 172 ctx.getChannel().write(txMessage);
172 bgpSession.closeSession(ctx); 173 bgpSession.closeSession(ctx);
......
1 +/*
2 + * Copyright 2014 Open Networking Laboratory
3 + *
4 + * 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
7 + *
8 + * 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.
15 + */
16 +package org.onosproject.sdnip.bgp;
17 +
18 +import org.jboss.netty.buffer.ChannelBuffer;
19 +import org.jboss.netty.buffer.ChannelBuffers;
20 +import org.jboss.netty.channel.ChannelHandlerContext;
21 +import org.slf4j.Logger;
22 +import org.slf4j.LoggerFactory;
23 +
24 +/**
25 + * A class for handling BGP KEEPALIVE messages.
26 + */
27 +final class BgpKeepalive {
28 + private static final Logger log =
29 + LoggerFactory.getLogger(BgpKeepalive.class);
30 +
31 + /**
32 + * Default constructor.
33 + * <p>
34 + * The constructor is private to prevent creating an instance of
35 + * this utility class.
36 + */
37 + private BgpKeepalive() {
38 + }
39 +
40 + /**
41 + * Processes BGP KEEPALIVE message.
42 + *
43 + * @param bgpSession the BGP Session to use
44 + * @param ctx the Channel Handler Context
45 + * @param message the message to process
46 + */
47 + static void processBgpKeepalive(BgpSession bgpSession,
48 + ChannelHandlerContext ctx,
49 + ChannelBuffer message) {
50 + if (message.readableBytes() + BgpConstants.BGP_HEADER_LENGTH !=
51 + BgpConstants.BGP_KEEPALIVE_EXPECTED_LENGTH) {
52 + log.debug("BGP RX KEEPALIVE Error from {}: " +
53 + "Invalid total message length {}. Expected {}",
54 + bgpSession.getRemoteAddress(),
55 + message.readableBytes() + BgpConstants.BGP_HEADER_LENGTH,
56 + BgpConstants.BGP_KEEPALIVE_EXPECTED_LENGTH);
57 + //
58 + // ERROR: Bad Message Length
59 + //
60 + // Send NOTIFICATION and close the connection
61 + ChannelBuffer txMessage =
62 + BgpNotification.prepareBgpNotificationBadMessageLength(
63 + message.readableBytes() + BgpConstants.BGP_HEADER_LENGTH);
64 + ctx.getChannel().write(txMessage);
65 + bgpSession.closeSession(ctx);
66 + return;
67 + }
68 +
69 + //
70 + // Parse the KEEPALIVE message: nothing to do
71 + //
72 + log.trace("BGP RX KEEPALIVE message from {}",
73 + bgpSession.getRemoteAddress());
74 +
75 + // Start the Session Timeout timer
76 + bgpSession.restartSessionTimeoutTimer(ctx);
77 + }
78 +
79 + /**
80 + * Prepares BGP KEEPALIVE message.
81 + *
82 + * @return the message to transmit (BGP header included)
83 + */
84 + static ChannelBuffer prepareBgpKeepalive() {
85 + ChannelBuffer message =
86 + ChannelBuffers.buffer(BgpConstants.BGP_MESSAGE_MAX_LENGTH);
87 +
88 + //
89 + // Prepare the KEEPALIVE message payload: nothing to do
90 + //
91 + return BgpMessage.prepareBgpMessage(BgpConstants.BGP_TYPE_KEEPALIVE,
92 + message);
93 + }
94 +}
1 +/*
2 + * Copyright 2014 Open Networking Laboratory
3 + *
4 + * 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
7 + *
8 + * 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.
15 + */
16 +package org.onosproject.sdnip.bgp;
17 +
18 +import org.jboss.netty.buffer.ChannelBuffer;
19 +import org.jboss.netty.buffer.ChannelBuffers;
20 +import org.slf4j.Logger;
21 +import org.slf4j.LoggerFactory;
22 +
23 +/**
24 + * A class for preparing BGP messages.
25 + */
26 +final class BgpMessage {
27 + private static final Logger log =
28 + LoggerFactory.getLogger(BgpMessage.class);
29 +
30 + /**
31 + * Default constructor.
32 + * <p>
33 + * The constructor is private to prevent creating an instance of
34 + * this utility class.
35 + */
36 + private BgpMessage() {
37 + }
38 +
39 + /**
40 + * Prepares BGP message.
41 + *
42 + * @param type the BGP message type
43 + * @param payload the message payload to transmit (BGP header excluded)
44 + * @return the message to transmit (BGP header included)
45 + */
46 + static ChannelBuffer prepareBgpMessage(int type, ChannelBuffer payload) {
47 + ChannelBuffer message =
48 + ChannelBuffers.buffer(BgpConstants.BGP_HEADER_LENGTH +
49 + payload.readableBytes());
50 +
51 + // Write the marker
52 + for (int i = 0; i < BgpConstants.BGP_HEADER_MARKER_LENGTH; i++) {
53 + message.writeByte(0xff);
54 + }
55 +
56 + // Write the rest of the BGP header
57 + message.writeShort(BgpConstants.BGP_HEADER_LENGTH +
58 + payload.readableBytes());
59 + message.writeByte(type);
60 +
61 + // Write the payload
62 + message.writeBytes(payload);
63 + return message;
64 + }
65 +}
1 +/*
2 + * Copyright 2014 Open Networking Laboratory
3 + *
4 + * 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
7 + *
8 + * 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.
15 + */
16 +package org.onosproject.sdnip.bgp;
17 +
18 +import org.jboss.netty.buffer.ChannelBuffer;
19 +import org.jboss.netty.buffer.ChannelBuffers;
20 +import org.jboss.netty.channel.ChannelHandlerContext;
21 +import org.onosproject.sdnip.bgp.BgpConstants.Notifications.MessageHeaderError;
22 +import org.slf4j.Logger;
23 +import org.slf4j.LoggerFactory;
24 +
25 +/**
26 + * A class for handling BGP NOTIFICATION messages.
27 + */
28 +final class BgpNotification {
29 + private static final Logger log =
30 + LoggerFactory.getLogger(BgpNotification.class);
31 +
32 + /**
33 + * Default constructor.
34 + * <p>
35 + * The constructor is private to prevent creating an instance of
36 + * this utility class.
37 + */
38 + private BgpNotification() {
39 + }
40 +
41 + /**
42 + * Processes BGP NOTIFICATION message.
43 + *
44 + * @param bgpSession the BGP Session to use
45 + * @param ctx the Channel Handler Context
46 + * @param message the message to process
47 + */
48 + static void processBgpNotification(BgpSession bgpSession,
49 + ChannelHandlerContext ctx,
50 + ChannelBuffer message) {
51 + int minLength =
52 + BgpConstants.BGP_NOTIFICATION_MIN_LENGTH - BgpConstants.BGP_HEADER_LENGTH;
53 + if (message.readableBytes() < minLength) {
54 + log.debug("BGP RX NOTIFICATION Error from {}: " +
55 + "Message length {} too short. Must be at least {}",
56 + bgpSession.getRemoteAddress(), message.readableBytes(),
57 + minLength);
58 + //
59 + // ERROR: Bad Message Length
60 + //
61 + // NOTE: We do NOT send NOTIFICATION in response to a notification
62 + return;
63 + }
64 +
65 + //
66 + // Parse the NOTIFICATION message
67 + //
68 + int errorCode = message.readUnsignedByte();
69 + int errorSubcode = message.readUnsignedByte();
70 + int dataLength = message.readableBytes();
71 +
72 + log.debug("BGP RX NOTIFICATION message from {}: Error Code {} " +
73 + "Error Subcode {} Data Length {}",
74 + bgpSession.getRemoteAddress(), errorCode, errorSubcode,
75 + dataLength);
76 +
77 + //
78 + // NOTE: If the peer sent a NOTIFICATION, we leave it to the peer to
79 + // close the connection.
80 + //
81 +
82 + // Start the Session Timeout timer
83 + bgpSession.restartSessionTimeoutTimer(ctx);
84 + }
85 +
86 + /**
87 + * Prepares BGP NOTIFICATION message.
88 + *
89 + * @param errorCode the BGP NOTIFICATION Error Code
90 + * @param errorSubcode the BGP NOTIFICATION Error Subcode if applicable,
91 + * otherwise BgpConstants.Notifications.ERROR_SUBCODE_UNSPECIFIC
92 + * @param data the BGP NOTIFICATION Data if applicable, otherwise null
93 + * @return the message to transmit (BGP header included)
94 + */
95 + static ChannelBuffer prepareBgpNotification(int errorCode,
96 + int errorSubcode,
97 + ChannelBuffer data) {
98 + ChannelBuffer message =
99 + ChannelBuffers.buffer(BgpConstants.BGP_MESSAGE_MAX_LENGTH);
100 +
101 + //
102 + // Prepare the NOTIFICATION message payload
103 + //
104 + message.writeByte(errorCode);
105 + message.writeByte(errorSubcode);
106 + if (data != null) {
107 + message.writeBytes(data);
108 + }
109 + return BgpMessage.prepareBgpMessage(BgpConstants.BGP_TYPE_NOTIFICATION,
110 + message);
111 + }
112 +
113 + /**
114 + * Prepares BGP NOTIFICATION message: Bad Message Length.
115 + *
116 + * @param length the erroneous Length field
117 + * @return the message to transmit (BGP header included)
118 + */
119 + static ChannelBuffer prepareBgpNotificationBadMessageLength(int length) {
120 + int errorCode = MessageHeaderError.ERROR_CODE;
121 + int errorSubcode = MessageHeaderError.BAD_MESSAGE_LENGTH;
122 + ChannelBuffer data = ChannelBuffers.buffer(2);
123 + data.writeShort(length);
124 +
125 + return prepareBgpNotification(errorCode, errorSubcode, data);
126 + }
127 +}
1 +/*
2 + * Copyright 2014 Open Networking Laboratory
3 + *
4 + * 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
7 + *
8 + * 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.
15 + */
16 +package org.onosproject.sdnip.bgp;
17 +
18 +import org.jboss.netty.buffer.ChannelBuffer;
19 +import org.jboss.netty.buffer.ChannelBuffers;
20 +import org.jboss.netty.channel.ChannelHandlerContext;
21 +import org.onlab.packet.Ip4Address;
22 +import org.onosproject.sdnip.bgp.BgpConstants.Notifications;
23 +import org.onosproject.sdnip.bgp.BgpConstants.Notifications.OpenMessageError;
24 +import org.slf4j.Logger;
25 +import org.slf4j.LoggerFactory;
26 +
27 +/**
28 + * A class for handling BGP OPEN messages.
29 + */
30 +final class BgpOpen {
31 + private static final Logger log = LoggerFactory.getLogger(BgpOpen.class);
32 +
33 + /**
34 + * Default constructor.
35 + * <p>
36 + * The constructor is private to prevent creating an instance of
37 + * this utility class.
38 + */
39 + private BgpOpen() {
40 + }
41 +
42 + /**
43 + * Processes BGP OPEN message.
44 + *
45 + * @param bgpSession the BGP Session to use
46 + * @param ctx the Channel Handler Context
47 + * @param message the message to process
48 + */
49 + static void processBgpOpen(BgpSession bgpSession,
50 + ChannelHandlerContext ctx,
51 + ChannelBuffer message) {
52 + int minLength =
53 + BgpConstants.BGP_OPEN_MIN_LENGTH - BgpConstants.BGP_HEADER_LENGTH;
54 + if (message.readableBytes() < minLength) {
55 + log.debug("BGP RX OPEN Error from {}: " +
56 + "Message length {} too short. Must be at least {}",
57 + bgpSession.getRemoteAddress(), message.readableBytes(),
58 + minLength);
59 + //
60 + // ERROR: Bad Message Length
61 + //
62 + // Send NOTIFICATION and close the connection
63 + ChannelBuffer txMessage =
64 + BgpNotification.prepareBgpNotificationBadMessageLength(
65 + message.readableBytes() + BgpConstants.BGP_HEADER_LENGTH);
66 + ctx.getChannel().write(txMessage);
67 + bgpSession.closeSession(ctx);
68 + return;
69 + }
70 +
71 + //
72 + // Parse the OPEN message
73 + //
74 + // Remote BGP version
75 + int remoteBgpVersion = message.readUnsignedByte();
76 + if (remoteBgpVersion != BgpConstants.BGP_VERSION) {
77 + log.debug("BGP RX OPEN Error from {}: " +
78 + "Unsupported BGP version {}. Should be {}",
79 + bgpSession.getRemoteAddress(), remoteBgpVersion,
80 + BgpConstants.BGP_VERSION);
81 + //
82 + // ERROR: Unsupported Version Number
83 + //
84 + // Send NOTIFICATION and close the connection
85 + int errorCode = OpenMessageError.ERROR_CODE;
86 + int errorSubcode = OpenMessageError.UNSUPPORTED_VERSION_NUMBER;
87 + ChannelBuffer data = ChannelBuffers.buffer(2);
88 + data.writeShort(BgpConstants.BGP_VERSION);
89 + ChannelBuffer txMessage =
90 + BgpNotification.prepareBgpNotification(errorCode, errorSubcode,
91 + data);
92 + ctx.getChannel().write(txMessage);
93 + bgpSession.closeSession(ctx);
94 + return;
95 + }
96 + bgpSession.setRemoteBgpVersion(remoteBgpVersion);
97 +
98 + // Remote AS number
99 + long remoteAs = message.readUnsignedShort();
100 + //
101 + // Verify that the AS number is same for all other BGP Sessions
102 + // NOTE: This check applies only for our use-case where all BGP
103 + // sessions are iBGP.
104 + //
105 + for (BgpSession bs : bgpSession.getBgpSessionManager().getBgpSessions()) {
106 + if ((bs.getRemoteAs() != 0) && (remoteAs != bs.getRemoteAs())) {
107 + log.debug("BGP RX OPEN Error from {}: Bad Peer AS {}. " +
108 + "Expected {}",
109 + bgpSession.getRemoteAddress(), remoteAs,
110 + bs.getRemoteAs());
111 + //
112 + // ERROR: Bad Peer AS
113 + //
114 + // Send NOTIFICATION and close the connection
115 + int errorCode = OpenMessageError.ERROR_CODE;
116 + int errorSubcode = OpenMessageError.BAD_PEER_AS;
117 + ChannelBuffer txMessage =
118 + BgpNotification.prepareBgpNotification(errorCode,
119 + errorSubcode, null);
120 + ctx.getChannel().write(txMessage);
121 + bgpSession.closeSession(ctx);
122 + return;
123 + }
124 + }
125 + bgpSession.setRemoteAs(remoteAs);
126 +
127 + // Remote Hold Time
128 + long remoteHoldtime = message.readUnsignedShort();
129 + if ((remoteHoldtime != 0) &&
130 + (remoteHoldtime < BgpConstants.BGP_KEEPALIVE_MIN_HOLDTIME)) {
131 + log.debug("BGP RX OPEN Error from {}: " +
132 + "Unacceptable Hold Time field {}. " +
133 + "Should be 0 or at least {}",
134 + bgpSession.getRemoteAddress(), remoteHoldtime,
135 + BgpConstants.BGP_KEEPALIVE_MIN_HOLDTIME);
136 + //
137 + // ERROR: Unacceptable Hold Time
138 + //
139 + // Send NOTIFICATION and close the connection
140 + int errorCode = OpenMessageError.ERROR_CODE;
141 + int errorSubcode = OpenMessageError.UNACCEPTABLE_HOLD_TIME;
142 + ChannelBuffer txMessage =
143 + BgpNotification.prepareBgpNotification(errorCode, errorSubcode,
144 + null);
145 + ctx.getChannel().write(txMessage);
146 + bgpSession.closeSession(ctx);
147 + return;
148 + }
149 + bgpSession.setRemoteHoldtime(remoteHoldtime);
150 +
151 + // Remote BGP Identifier
152 + Ip4Address remoteBgpId =
153 + Ip4Address.valueOf((int) message.readUnsignedInt());
154 + bgpSession.setRemoteBgpId(remoteBgpId);
155 +
156 + // Optional Parameters
157 + int optParamLen = message.readUnsignedByte();
158 + if (message.readableBytes() < optParamLen) {
159 + log.debug("BGP RX OPEN Error from {}: " +
160 + "Invalid Optional Parameter Length field {}. " +
161 + "Remaining Optional Parameters {}",
162 + bgpSession.getRemoteAddress(), optParamLen,
163 + message.readableBytes());
164 + //
165 + // ERROR: Invalid Optional Parameter Length field: Unspecific
166 + //
167 + // Send NOTIFICATION and close the connection
168 + int errorCode = OpenMessageError.ERROR_CODE;
169 + int errorSubcode = Notifications.ERROR_SUBCODE_UNSPECIFIC;
170 + ChannelBuffer txMessage =
171 + BgpNotification.prepareBgpNotification(errorCode, errorSubcode,
172 + null);
173 + ctx.getChannel().write(txMessage);
174 + bgpSession.closeSession(ctx);
175 + return;
176 + }
177 + // NOTE: Parse the optional parameters (if needed)
178 + message.readBytes(optParamLen); // NOTE: data ignored
179 +
180 + log.debug("BGP RX OPEN message from {}: " +
181 + "BGPv{} AS {} BGP-ID {} Holdtime {}",
182 + bgpSession.getRemoteAddress(), remoteBgpVersion, remoteAs,
183 + remoteBgpId, remoteHoldtime);
184 +
185 + // Send my OPEN followed by KEEPALIVE
186 + ChannelBuffer txMessage = prepareBgpOpen(bgpSession);
187 + ctx.getChannel().write(txMessage);
188 + //
189 + txMessage = BgpKeepalive.prepareBgpKeepalive();
190 + ctx.getChannel().write(txMessage);
191 +
192 + // Start the KEEPALIVE timer
193 + bgpSession.restartKeepaliveTimer(ctx);
194 +
195 + // Start the Session Timeout timer
196 + bgpSession.restartSessionTimeoutTimer(ctx);
197 + }
198 +
199 + /**
200 + * Prepares BGP OPEN message.
201 + *
202 + * @param bgpSession the BGP Session to use
203 + * @return the message to transmit (BGP header included)
204 + */
205 + private static ChannelBuffer prepareBgpOpen(BgpSession bgpSession) {
206 + ChannelBuffer message =
207 + ChannelBuffers.buffer(BgpConstants.BGP_MESSAGE_MAX_LENGTH);
208 +
209 + //
210 + // Prepare the OPEN message payload
211 + //
212 + message.writeByte(bgpSession.getLocalBgpVersion());
213 + message.writeShort((int) bgpSession.getLocalAs());
214 + message.writeShort((int) bgpSession.getLocalHoldtime());
215 + message.writeInt(bgpSession.getLocalBgpId().toInt());
216 + message.writeByte(0); // No Optional Parameters
217 + return BgpMessage.prepareBgpMessage(BgpConstants.BGP_TYPE_OPEN,
218 + message);
219 + }
220 +}
...@@ -18,18 +18,14 @@ package org.onosproject.sdnip.bgp; ...@@ -18,18 +18,14 @@ package org.onosproject.sdnip.bgp;
18 import java.net.InetAddress; 18 import java.net.InetAddress;
19 import java.net.InetSocketAddress; 19 import java.net.InetSocketAddress;
20 import java.net.SocketAddress; 20 import java.net.SocketAddress;
21 -import java.util.ArrayList;
22 import java.util.Collection; 21 import java.util.Collection;
23 import java.util.Collections; 22 import java.util.Collections;
24 -import java.util.HashMap;
25 import java.util.Map; 23 import java.util.Map;
26 import java.util.concurrent.ConcurrentHashMap; 24 import java.util.concurrent.ConcurrentHashMap;
27 import java.util.concurrent.ConcurrentMap; 25 import java.util.concurrent.ConcurrentMap;
28 import java.util.concurrent.TimeUnit; 26 import java.util.concurrent.TimeUnit;
29 27
30 -import org.apache.commons.lang3.tuple.Pair;
31 import org.jboss.netty.buffer.ChannelBuffer; 28 import org.jboss.netty.buffer.ChannelBuffer;
32 -import org.jboss.netty.buffer.ChannelBuffers;
33 import org.jboss.netty.channel.ChannelHandlerContext; 29 import org.jboss.netty.channel.ChannelHandlerContext;
34 import org.jboss.netty.channel.ChannelStateEvent; 30 import org.jboss.netty.channel.ChannelStateEvent;
35 import org.jboss.netty.channel.ExceptionEvent; 31 import org.jboss.netty.channel.ExceptionEvent;
...@@ -42,9 +38,6 @@ import org.onlab.packet.Ip4Address; ...@@ -42,9 +38,6 @@ import org.onlab.packet.Ip4Address;
42 import org.onlab.packet.Ip4Prefix; 38 import org.onlab.packet.Ip4Prefix;
43 import org.onosproject.sdnip.bgp.BgpConstants.Notifications; 39 import org.onosproject.sdnip.bgp.BgpConstants.Notifications;
44 import org.onosproject.sdnip.bgp.BgpConstants.Notifications.HoldTimerExpired; 40 import org.onosproject.sdnip.bgp.BgpConstants.Notifications.HoldTimerExpired;
45 -import org.onosproject.sdnip.bgp.BgpConstants.Notifications.MessageHeaderError;
46 -import org.onosproject.sdnip.bgp.BgpConstants.Notifications.OpenMessageError;
47 -import org.onosproject.sdnip.bgp.BgpConstants.Notifications.UpdateMessageError;
48 import org.slf4j.Logger; 41 import org.slf4j.Logger;
49 import org.slf4j.LoggerFactory; 42 import org.slf4j.LoggerFactory;
50 43
...@@ -94,6 +87,18 @@ public class BgpSession extends SimpleChannelHandler { ...@@ -94,6 +87,18 @@ public class BgpSession extends SimpleChannelHandler {
94 */ 87 */
95 BgpSession(BgpSessionManager bgpSessionManager) { 88 BgpSession(BgpSessionManager bgpSessionManager) {
96 this.bgpSessionManager = bgpSessionManager; 89 this.bgpSessionManager = bgpSessionManager;
90 +
91 + // NOTE: We support only BGP4
92 + this.localBgpVersion = BgpConstants.BGP_VERSION;
93 + }
94 +
95 + /**
96 + * Gets the BGP Session Manager.
97 + *
98 + * @return the BGP Session Manager
99 + */
100 + BgpSessionManager getBgpSessionManager() {
101 + return bgpSessionManager;
97 } 102 }
98 103
99 /** 104 /**
...@@ -101,8 +106,8 @@ public class BgpSession extends SimpleChannelHandler { ...@@ -101,8 +106,8 @@ public class BgpSession extends SimpleChannelHandler {
101 * 106 *
102 * @return the BGP RIB-IN routing entries 107 * @return the BGP RIB-IN routing entries
103 */ 108 */
104 - public Collection<BgpRouteEntry> getBgpRibIn() { 109 + public Map<Ip4Prefix, BgpRouteEntry> bgpRibIn() {
105 - return bgpRibIn.values(); 110 + return bgpRibIn;
106 } 111 }
107 112
108 /** 113 /**
...@@ -143,6 +148,15 @@ public class BgpSession extends SimpleChannelHandler { ...@@ -143,6 +148,15 @@ public class BgpSession extends SimpleChannelHandler {
143 } 148 }
144 149
145 /** 150 /**
151 + * Sets the BGP session remote BGP version.
152 + *
153 + * @param remoteBgpVersion the BGP session remote BGP version to set
154 + */
155 + void setRemoteBgpVersion(int remoteBgpVersion) {
156 + this.remoteBgpVersion = remoteBgpVersion;
157 + }
158 +
159 + /**
146 * Gets the BGP session remote AS number. 160 * Gets the BGP session remote AS number.
147 * 161 *
148 * @return the BGP session remote AS number 162 * @return the BGP session remote AS number
...@@ -152,6 +166,23 @@ public class BgpSession extends SimpleChannelHandler { ...@@ -152,6 +166,23 @@ public class BgpSession extends SimpleChannelHandler {
152 } 166 }
153 167
154 /** 168 /**
169 + * Sets the BGP session remote AS number.
170 + *
171 + * @param remoteAs the BGP session remote AS number to set
172 + */
173 + void setRemoteAs(long remoteAs) {
174 + this.remoteAs = remoteAs;
175 +
176 + //
177 + // NOTE: Currently, the local AS number is always set to the remote AS.
178 + // This is done, because the peer setup is always iBGP.
179 + // In the future the local AS number should be configured as part
180 + // of an explicit BGP peering configuration.
181 + //
182 + this.localAs = remoteAs;
183 + }
184 +
185 + /**
155 * Gets the BGP session remote Holdtime. 186 * Gets the BGP session remote Holdtime.
156 * 187 *
157 * @return the BGP session remote Holdtime 188 * @return the BGP session remote Holdtime
...@@ -161,6 +192,32 @@ public class BgpSession extends SimpleChannelHandler { ...@@ -161,6 +192,32 @@ public class BgpSession extends SimpleChannelHandler {
161 } 192 }
162 193
163 /** 194 /**
195 + * Sets the BGP session remote Holdtime.
196 + *
197 + * @param remoteHoldtime the BGP session remote Holdtime to set
198 + */
199 + void setRemoteHoldtime(long remoteHoldtime) {
200 + this.remoteHoldtime = remoteHoldtime;
201 +
202 + //
203 + // NOTE: Currently. the local BGP Holdtime is always set to the remote
204 + // BGP holdtime.
205 + // In the future, the local BGP Holdtime should be configured as part
206 + // of an explicit BGP peering configuration.
207 + //
208 + this.localHoldtime = remoteHoldtime;
209 +
210 + // Set the local Keepalive interval
211 + if (localHoldtime == 0) {
212 + localKeepaliveInterval = 0;
213 + } else {
214 + localKeepaliveInterval = Math.max(localHoldtime /
215 + BgpConstants.BGP_KEEPALIVE_PER_HOLD_INTERVAL,
216 + BgpConstants.BGP_KEEPALIVE_MIN_INTERVAL);
217 + }
218 + }
219 +
220 + /**
164 * Gets the BGP session remote BGP Identifier as an IPv4 address. 221 * Gets the BGP session remote BGP Identifier as an IPv4 address.
165 * 222 *
166 * @return the BGP session remote BGP Identifier as an IPv4 address 223 * @return the BGP session remote BGP Identifier as an IPv4 address
...@@ -170,6 +227,15 @@ public class BgpSession extends SimpleChannelHandler { ...@@ -170,6 +227,15 @@ public class BgpSession extends SimpleChannelHandler {
170 } 227 }
171 228
172 /** 229 /**
230 + * Sets the BGP session remote BGP Identifier as an IPv4 address.
231 + *
232 + * @param remoteBgpId the BGP session remote BGP Identifier to set
233 + */
234 + void setRemoteBgpId(Ip4Address remoteBgpId) {
235 + this.remoteBgpId = remoteBgpId;
236 + }
237 +
238 + /**
173 * Gets the BGP session local address. 239 * Gets the BGP session local address.
174 * 240 *
175 * @return the BGP session local address 241 * @return the BGP session local address
...@@ -179,6 +245,15 @@ public class BgpSession extends SimpleChannelHandler { ...@@ -179,6 +245,15 @@ public class BgpSession extends SimpleChannelHandler {
179 } 245 }
180 246
181 /** 247 /**
248 + * Gets the BGP session local IPv4 address.
249 + *
250 + * @return the BGP session local IPv4 address
251 + */
252 + public Ip4Address getLocalIp4Address() {
253 + return localIp4Address;
254 + }
255 +
256 + /**
182 * Gets the BGP session local BGP version. 257 * Gets the BGP session local BGP version.
183 * 258 *
184 * @return the BGP session local BGP version 259 * @return the BGP session local BGP version
...@@ -282,6 +357,12 @@ public class BgpSession extends SimpleChannelHandler { ...@@ -282,6 +357,12 @@ public class BgpSession extends SimpleChannelHandler {
282 remoteAddress); 357 remoteAddress);
283 ctx.getChannel().close(); 358 ctx.getChannel().close();
284 } 359 }
360 +
361 + //
362 + // Assign the local BGP ID
363 + // NOTE: This should be configuration-based
364 + //
365 + localBgpId = bgpSessionManager.getMyBgpId();
285 } 366 }
286 367
287 @Override 368 @Override
...@@ -326,1536 +407,87 @@ public class BgpSession extends SimpleChannelHandler { ...@@ -326,1536 +407,87 @@ public class BgpSession extends SimpleChannelHandler {
326 } 407 }
327 408
328 /** 409 /**
329 - * Processes BGP OPEN message. 410 + * Restarts the BGP KeepaliveTimer.
330 - *
331 - * @param ctx the Channel Handler Context
332 - * @param message the message to process
333 */ 411 */
334 - void processBgpOpen(ChannelHandlerContext ctx, ChannelBuffer message) { 412 + void restartKeepaliveTimer(ChannelHandlerContext ctx) {
335 - int minLength = 413 + if (localKeepaliveInterval == 0) {
336 - BgpConstants.BGP_OPEN_MIN_LENGTH - BgpConstants.BGP_HEADER_LENGTH; 414 + return; // Nothing to do
337 - if (message.readableBytes() < minLength) {
338 - log.debug("BGP RX OPEN Error from {}: " +
339 - "Message length {} too short. Must be at least {}",
340 - remoteAddress, message.readableBytes(), minLength);
341 - //
342 - // ERROR: Bad Message Length
343 - //
344 - // Send NOTIFICATION and close the connection
345 - ChannelBuffer txMessage = prepareBgpNotificationBadMessageLength(
346 - message.readableBytes() + BgpConstants.BGP_HEADER_LENGTH);
347 - ctx.getChannel().write(txMessage);
348 - closeSession(ctx);
349 - return;
350 - }
351 -
352 - //
353 - // Parse the OPEN message
354 - //
355 - // Remote BGP version
356 - remoteBgpVersion = message.readUnsignedByte();
357 - if (remoteBgpVersion != BgpConstants.BGP_VERSION) {
358 - log.debug("BGP RX OPEN Error from {}: " +
359 - "Unsupported BGP version {}. Should be {}",
360 - remoteAddress, remoteBgpVersion,
361 - BgpConstants.BGP_VERSION);
362 - //
363 - // ERROR: Unsupported Version Number
364 - //
365 - // Send NOTIFICATION and close the connection
366 - int errorCode = OpenMessageError.ERROR_CODE;
367 - int errorSubcode = OpenMessageError.UNSUPPORTED_VERSION_NUMBER;
368 - ChannelBuffer data = ChannelBuffers.buffer(2);
369 - data.writeShort(BgpConstants.BGP_VERSION);
370 - ChannelBuffer txMessage =
371 - prepareBgpNotification(errorCode, errorSubcode, data);
372 - ctx.getChannel().write(txMessage);
373 - closeSession(ctx);
374 - return;
375 - }
376 -
377 - // Remote AS number
378 - remoteAs = message.readUnsignedShort();
379 - //
380 - // Verify that the AS number is same for all other BGP Sessions
381 - // NOTE: This check applies only for our use-case where all BGP
382 - // sessions are iBGP.
383 - //
384 - for (BgpSession bgpSession : bgpSessionManager.getBgpSessions()) {
385 - if (remoteAs != bgpSession.getRemoteAs()) {
386 - log.debug("BGP RX OPEN Error from {}: Bad Peer AS {}. " +
387 - "Expected {}",
388 - remoteAddress, remoteAs, bgpSession.getRemoteAs());
389 - //
390 - // ERROR: Bad Peer AS
391 - //
392 - // Send NOTIFICATION and close the connection
393 - int errorCode = OpenMessageError.ERROR_CODE;
394 - int errorSubcode = OpenMessageError.BAD_PEER_AS;
395 - ChannelBuffer txMessage =
396 - prepareBgpNotification(errorCode, errorSubcode, null);
397 - ctx.getChannel().write(txMessage);
398 - closeSession(ctx);
399 - return;
400 - }
401 - }
402 -
403 - // Remote Hold Time
404 - remoteHoldtime = message.readUnsignedShort();
405 - if ((remoteHoldtime != 0) &&
406 - (remoteHoldtime < BgpConstants.BGP_KEEPALIVE_MIN_HOLDTIME)) {
407 - log.debug("BGP RX OPEN Error from {}: " +
408 - "Unacceptable Hold Time field {}. " +
409 - "Should be 0 or at least {}",
410 - remoteAddress, remoteHoldtime,
411 - BgpConstants.BGP_KEEPALIVE_MIN_HOLDTIME);
412 - //
413 - // ERROR: Unacceptable Hold Time
414 - //
415 - // Send NOTIFICATION and close the connection
416 - int errorCode = OpenMessageError.ERROR_CODE;
417 - int errorSubcode = OpenMessageError.UNACCEPTABLE_HOLD_TIME;
418 - ChannelBuffer txMessage =
419 - prepareBgpNotification(errorCode, errorSubcode, null);
420 - ctx.getChannel().write(txMessage);
421 - closeSession(ctx);
422 - return;
423 - }
424 -
425 - // Remote BGP Identifier
426 - remoteBgpId = Ip4Address.valueOf((int) message.readUnsignedInt());
427 -
428 - // Optional Parameters
429 - int optParamLen = message.readUnsignedByte();
430 - if (message.readableBytes() < optParamLen) {
431 - log.debug("BGP RX OPEN Error from {}: " +
432 - "Invalid Optional Parameter Length field {}. " +
433 - "Remaining Optional Parameters {}",
434 - remoteAddress, optParamLen, message.readableBytes());
435 - //
436 - // ERROR: Invalid Optional Parameter Length field: Unspecific
437 - //
438 - // Send NOTIFICATION and close the connection
439 - int errorCode = OpenMessageError.ERROR_CODE;
440 - int errorSubcode = Notifications.ERROR_SUBCODE_UNSPECIFIC;
441 - ChannelBuffer txMessage =
442 - prepareBgpNotification(errorCode, errorSubcode, null);
443 - ctx.getChannel().write(txMessage);
444 - closeSession(ctx);
445 - return;
446 } 415 }
447 - // NOTE: Parse the optional parameters (if needed) 416 + keepaliveTimeout = timer.newTimeout(new TransmitKeepaliveTask(ctx),
448 - message.readBytes(optParamLen); // NOTE: data ignored 417 + localKeepaliveInterval,
449 - 418 + TimeUnit.SECONDS);
450 - //
451 - // Copy some of the remote peer's state/setup to the local setup:
452 - // - BGP version
453 - // - AS number (NOTE: the peer setup is always iBGP)
454 - // - Holdtime
455 - // Also, assign the local BGP ID based on the local setup
456 - //
457 - localBgpVersion = remoteBgpVersion;
458 - localAs = remoteAs;
459 - localHoldtime = remoteHoldtime;
460 - localBgpId = bgpSessionManager.getMyBgpId();
461 -
462 - // Set the Keepalive interval
463 - if (localHoldtime == 0) {
464 - localKeepaliveInterval = 0;
465 - } else {
466 - localKeepaliveInterval = Math.max(localHoldtime /
467 - BgpConstants.BGP_KEEPALIVE_PER_HOLD_INTERVAL,
468 - BgpConstants.BGP_KEEPALIVE_MIN_INTERVAL);
469 } 419 }
470 420
471 - log.debug("BGP RX OPEN message from {}: " + 421 + /**
472 - "BGPv{} AS {} BGP-ID {} Holdtime {}", 422 + * Task class for transmitting KEEPALIVE messages.
473 - remoteAddress, remoteBgpVersion, remoteAs, 423 + */
474 - remoteBgpId, remoteHoldtime); 424 + private final class TransmitKeepaliveTask implements TimerTask {
475 - 425 + private final ChannelHandlerContext ctx;
476 - // Send my OPEN followed by KEEPALIVE
477 - ChannelBuffer txMessage = prepareBgpOpen();
478 - ctx.getChannel().write(txMessage);
479 - //
480 - txMessage = prepareBgpKeepalive();
481 - ctx.getChannel().write(txMessage);
482 -
483 - // Start the KEEPALIVE timer
484 - restartKeepaliveTimer(ctx);
485 -
486 - // Start the Session Timeout timer
487 - restartSessionTimeoutTimer(ctx);
488 - }
489 426
490 /** 427 /**
491 - * Processes BGP UPDATE message. 428 + * Constructor for given Channel Handler Context.
492 * 429 *
493 - * @param ctx the Channel Handler Context 430 + * @param ctx the Channel Handler Context to use
494 - * @param message the message to process
495 */ 431 */
496 - void processBgpUpdate(ChannelHandlerContext ctx, ChannelBuffer message) { 432 + TransmitKeepaliveTask(ChannelHandlerContext ctx) {
497 - Collection<BgpRouteEntry> addedRoutes = null; 433 + this.ctx = ctx;
498 - Map<Ip4Prefix, BgpRouteEntry> deletedRoutes = new HashMap<>();
499 -
500 - int minLength =
501 - BgpConstants.BGP_UPDATE_MIN_LENGTH - BgpConstants.BGP_HEADER_LENGTH;
502 - if (message.readableBytes() < minLength) {
503 - log.debug("BGP RX UPDATE Error from {}: " +
504 - "Message length {} too short. Must be at least {}",
505 - remoteAddress, message.readableBytes(), minLength);
506 - //
507 - // ERROR: Bad Message Length
508 - //
509 - // Send NOTIFICATION and close the connection
510 - ChannelBuffer txMessage = prepareBgpNotificationBadMessageLength(
511 - message.readableBytes() + BgpConstants.BGP_HEADER_LENGTH);
512 - ctx.getChannel().write(txMessage);
513 - closeSession(ctx);
514 - return;
515 } 434 }
516 435
517 - log.debug("BGP RX UPDATE message from {}", remoteAddress); 436 + @Override
518 - 437 + public void run(Timeout timeout) throws Exception {
519 - // 438 + if (timeout.isCancelled()) {
520 - // Parse the UPDATE message
521 - //
522 -
523 - //
524 - // Parse the Withdrawn Routes
525 - //
526 - int withdrawnRoutesLength = message.readUnsignedShort();
527 - if (withdrawnRoutesLength > message.readableBytes()) {
528 - // ERROR: Malformed Attribute List
529 - actionsBgpUpdateMalformedAttributeList(ctx);
530 return; 439 return;
531 } 440 }
532 - Collection<Ip4Prefix> withdrawnPrefixes = null; 441 + if (!ctx.getChannel().isOpen()) {
533 - try {
534 - withdrawnPrefixes = parsePackedPrefixes(withdrawnRoutesLength,
535 - message);
536 - } catch (BgpParseException e) {
537 - // ERROR: Invalid Network Field
538 - log.debug("Exception parsing Withdrawn Prefixes from BGP peer {}: ",
539 - remoteBgpId, e);
540 - actionsBgpUpdateInvalidNetworkField(ctx);
541 return; 442 return;
542 } 443 }
543 - for (Ip4Prefix prefix : withdrawnPrefixes) {
544 - log.debug("BGP RX UPDATE message WITHDRAWN from {}: {}",
545 - remoteAddress, prefix);
546 - BgpRouteEntry bgpRouteEntry = bgpRibIn.get(prefix);
547 - if (bgpRouteEntry != null) {
548 - deletedRoutes.put(prefix, bgpRouteEntry);
549 - }
550 - }
551 444
552 - // 445 + // Transmit the KEEPALIVE
553 - // Parse the Path Attributes 446 + ChannelBuffer txMessage = BgpKeepalive.prepareBgpKeepalive();
554 - // 447 + ctx.getChannel().write(txMessage);
555 - try {
556 - addedRoutes = parsePathAttributes(ctx, message);
557 - } catch (BgpParseException e) {
558 - log.debug("Exception parsing Path Attributes from BGP peer {}: ",
559 - remoteBgpId, e);
560 - // NOTE: The session was already closed, so nothing else to do
561 - return;
562 - }
563 - // Ignore WITHDRAWN routes that are ADDED
564 - for (BgpRouteEntry bgpRouteEntry : addedRoutes) {
565 - deletedRoutes.remove(bgpRouteEntry.prefix());
566 - }
567 448
568 - // Update the BGP RIB-IN 449 + // Restart the KEEPALIVE timer
569 - for (BgpRouteEntry bgpRouteEntry : deletedRoutes.values()) { 450 + restartKeepaliveTimer(ctx);
570 - bgpRibIn.remove(bgpRouteEntry.prefix());
571 - }
572 - for (BgpRouteEntry bgpRouteEntry : addedRoutes) {
573 - bgpRibIn.put(bgpRouteEntry.prefix(), bgpRouteEntry);
574 } 451 }
575 -
576 - // Push the updates to the BGP Merged RIB
577 - BgpSessionManager.BgpRouteSelector bgpRouteSelector =
578 - bgpSessionManager.getBgpRouteSelector();
579 - bgpRouteSelector.routeUpdates(this, addedRoutes,
580 - deletedRoutes.values());
581 -
582 - // Start the Session Timeout timer
583 - restartSessionTimeoutTimer(ctx);
584 } 452 }
585 453
586 /** 454 /**
587 - * Parse BGP Path Attributes from the BGP UPDATE message. 455 + * Restarts the BGP Session Timeout Timer.
588 - *
589 - * @param ctx the Channel Handler Context
590 - * @param message the message to parse
591 - * @return a collection of the result BGP Route Entries
592 - * @throws BgpParseException
593 */ 456 */
594 - private Collection<BgpRouteEntry> parsePathAttributes( 457 + void restartSessionTimeoutTimer(ChannelHandlerContext ctx) {
595 - ChannelHandlerContext ctx, 458 + if (remoteHoldtime == 0) {
596 - ChannelBuffer message) 459 + return; // Nothing to do
597 - throws BgpParseException {
598 - Map<Ip4Prefix, BgpRouteEntry> addedRoutes = new HashMap<>();
599 -
600 - //
601 - // Parsed values
602 - //
603 - Short origin = -1; // Mandatory
604 - BgpRouteEntry.AsPath asPath = null; // Mandatory
605 - Ip4Address nextHop = null; // Mandatory
606 - long multiExitDisc = // Optional
607 - BgpConstants.Update.MultiExitDisc.LOWEST_MULTI_EXIT_DISC;
608 - Long localPref = null; // Mandatory
609 - Long aggregatorAsNumber = null; // Optional: unused
610 - Ip4Address aggregatorIpAddress = null; // Optional: unused
611 -
612 - //
613 - // Get and verify the Path Attributes Length
614 - //
615 - int pathAttributeLength = message.readUnsignedShort();
616 - if (pathAttributeLength > message.readableBytes()) {
617 - // ERROR: Malformed Attribute List
618 - actionsBgpUpdateMalformedAttributeList(ctx);
619 - String errorMsg = "Malformed Attribute List";
620 - throw new BgpParseException(errorMsg);
621 - }
622 - if (pathAttributeLength == 0) {
623 - return addedRoutes.values();
624 - }
625 -
626 - //
627 - // Parse the Path Attributes
628 - //
629 - int pathAttributeEnd = message.readerIndex() + pathAttributeLength;
630 - while (message.readerIndex() < pathAttributeEnd) {
631 - int attrFlags = message.readUnsignedByte();
632 - if (message.readerIndex() >= pathAttributeEnd) {
633 - // ERROR: Malformed Attribute List
634 - actionsBgpUpdateMalformedAttributeList(ctx);
635 - String errorMsg = "Malformed Attribute List";
636 - throw new BgpParseException(errorMsg);
637 - }
638 - int attrTypeCode = message.readUnsignedByte();
639 -
640 - // The Attribute Flags
641 - boolean optionalBit = ((0x80 & attrFlags) != 0);
642 - boolean transitiveBit = ((0x40 & attrFlags) != 0);
643 - boolean partialBit = ((0x20 & attrFlags) != 0);
644 - boolean extendedLengthBit = ((0x10 & attrFlags) != 0);
645 -
646 - // The Attribute Length
647 - int attrLen = 0;
648 - int attrLenOctets = 1;
649 - if (extendedLengthBit) {
650 - attrLenOctets = 2;
651 - }
652 - if (message.readerIndex() + attrLenOctets > pathAttributeEnd) {
653 - // ERROR: Malformed Attribute List
654 - actionsBgpUpdateMalformedAttributeList(ctx);
655 - String errorMsg = "Malformed Attribute List";
656 - throw new BgpParseException(errorMsg);
657 - }
658 - if (extendedLengthBit) {
659 - attrLen = message.readUnsignedShort();
660 - } else {
661 - attrLen = message.readUnsignedByte();
662 - }
663 - if (message.readerIndex() + attrLen > pathAttributeEnd) {
664 - // ERROR: Malformed Attribute List
665 - actionsBgpUpdateMalformedAttributeList(ctx);
666 - String errorMsg = "Malformed Attribute List";
667 - throw new BgpParseException(errorMsg);
668 - }
669 -
670 - //
671 - // Verify the Attribute Flags
672 - //
673 - verifyBgpUpdateAttributeFlags(ctx, attrTypeCode, attrLen,
674 - attrFlags, message);
675 -
676 - //
677 - // Extract the Attribute Value based on the Attribute Type Code
678 - //
679 - switch (attrTypeCode) {
680 -
681 - case BgpConstants.Update.Origin.TYPE:
682 - // Attribute Type Code ORIGIN
683 - origin = parseAttributeTypeOrigin(ctx, attrTypeCode, attrLen,
684 - attrFlags, message);
685 - break;
686 -
687 - case BgpConstants.Update.AsPath.TYPE:
688 - // Attribute Type Code AS_PATH
689 - asPath = parseAttributeTypeAsPath(ctx, attrTypeCode, attrLen,
690 - attrFlags, message);
691 - break;
692 -
693 - case BgpConstants.Update.NextHop.TYPE:
694 - // Attribute Type Code NEXT_HOP
695 - nextHop = parseAttributeTypeNextHop(ctx, attrTypeCode, attrLen,
696 - attrFlags, message);
697 - break;
698 -
699 - case BgpConstants.Update.MultiExitDisc.TYPE:
700 - // Attribute Type Code MULTI_EXIT_DISC
701 - multiExitDisc =
702 - parseAttributeTypeMultiExitDisc(ctx, attrTypeCode, attrLen,
703 - attrFlags, message);
704 - break;
705 -
706 - case BgpConstants.Update.LocalPref.TYPE:
707 - // Attribute Type Code LOCAL_PREF
708 - localPref =
709 - parseAttributeTypeLocalPref(ctx, attrTypeCode, attrLen,
710 - attrFlags, message);
711 - break;
712 -
713 - case BgpConstants.Update.AtomicAggregate.TYPE:
714 - // Attribute Type Code ATOMIC_AGGREGATE
715 - parseAttributeTypeAtomicAggregate(ctx, attrTypeCode, attrLen,
716 - attrFlags, message);
717 - // Nothing to do: this attribute is primarily informational
718 - break;
719 -
720 - case BgpConstants.Update.Aggregator.TYPE:
721 - // Attribute Type Code AGGREGATOR
722 - Pair<Long, Ip4Address> aggregator =
723 - parseAttributeTypeAggregator(ctx, attrTypeCode, attrLen,
724 - attrFlags, message);
725 - aggregatorAsNumber = aggregator.getLeft();
726 - aggregatorIpAddress = aggregator.getRight();
727 - break;
728 -
729 - default:
730 - // NOTE: Parse any new Attribute Types if needed
731 - if (!optionalBit) {
732 - // ERROR: Unrecognized Well-known Attribute
733 - actionsBgpUpdateUnrecognizedWellKnownAttribute(
734 - ctx, attrTypeCode, attrLen, attrFlags, message);
735 - String errorMsg = "Unrecognized Well-known Attribute: " +
736 - attrTypeCode;
737 - throw new BgpParseException(errorMsg);
738 - }
739 -
740 - // Skip the data from the unrecognized attribute
741 - log.debug("BGP RX UPDATE message from {}: " +
742 - "Unrecognized Attribute Type {}",
743 - remoteAddress, attrTypeCode);
744 - message.skipBytes(attrLen);
745 - break;
746 - }
747 - }
748 -
749 - //
750 - // Verify the Well-known Attributes
751 - //
752 - verifyBgpUpdateWellKnownAttributes(ctx, origin, asPath, nextHop,
753 - localPref);
754 -
755 - //
756 - // Parse the NLRI (Network Layer Reachability Information)
757 - //
758 - Collection<Ip4Prefix> addedPrefixes = null;
759 - int nlriLength = message.readableBytes();
760 - try {
761 - addedPrefixes = parsePackedPrefixes(nlriLength, message);
762 - } catch (BgpParseException e) {
763 - // ERROR: Invalid Network Field
764 - log.debug("Exception parsing NLRI from BGP peer {}: ",
765 - remoteBgpId, e);
766 - actionsBgpUpdateInvalidNetworkField(ctx);
767 - // Rethrow the exception
768 - throw e;
769 - }
770 -
771 - // Generate the added routes
772 - for (Ip4Prefix prefix : addedPrefixes) {
773 - BgpRouteEntry bgpRouteEntry =
774 - new BgpRouteEntry(this, prefix, nextHop,
775 - origin.byteValue(), asPath, localPref);
776 - bgpRouteEntry.setMultiExitDisc(multiExitDisc);
777 - if (bgpRouteEntry.hasAsPathLoop(localAs)) {
778 - log.debug("BGP RX UPDATE message IGNORED from {}: {} " +
779 - "nextHop {}: contains AS Path loop",
780 - remoteAddress, prefix, nextHop);
781 - continue;
782 - } else {
783 - log.debug("BGP RX UPDATE message ADDED from {}: {} nextHop {}",
784 - remoteAddress, prefix, nextHop);
785 } 460 }
786 - addedRoutes.put(prefix, bgpRouteEntry); 461 + if (sessionTimeout != null) {
462 + sessionTimeout.cancel();
787 } 463 }
788 - 464 + sessionTimeout = timer.newTimeout(new SessionTimeoutTask(ctx),
789 - return addedRoutes.values(); 465 + remoteHoldtime,
466 + TimeUnit.SECONDS);
790 } 467 }
791 468
792 /** 469 /**
793 - * Verifies BGP UPDATE Well-known Attributes. 470 + * Task class for BGP Session timeout.
794 - *
795 - * @param ctx the Channel Handler Context
796 - * @param origin the ORIGIN well-known mandatory attribute
797 - * @param asPath the AS_PATH well-known mandatory attribute
798 - * @param nextHop the NEXT_HOP well-known mandatory attribute
799 - * @param localPref the LOCAL_PREF required attribute
800 - * @throws BgpParseException
801 */ 471 */
802 - private void verifyBgpUpdateWellKnownAttributes( 472 + private final class SessionTimeoutTask implements TimerTask {
803 - ChannelHandlerContext ctx, 473 + private final ChannelHandlerContext ctx;
804 - Short origin,
805 - BgpRouteEntry.AsPath asPath,
806 - Ip4Address nextHop,
807 - Long localPref)
808 - throws BgpParseException {
809 - //
810 - // Check for Missing Well-known Attributes
811 - //
812 - if ((origin == null) || (origin == -1)) {
813 - // Missing Attribute Type Code ORIGIN
814 - int type = BgpConstants.Update.Origin.TYPE;
815 - actionsBgpUpdateMissingWellKnownAttribute(ctx, type);
816 - String errorMsg = "Missing Well-known Attribute: ORIGIN";
817 - throw new BgpParseException(errorMsg);
818 - }
819 - if (asPath == null) {
820 - // Missing Attribute Type Code AS_PATH
821 - int type = BgpConstants.Update.AsPath.TYPE;
822 - actionsBgpUpdateMissingWellKnownAttribute(ctx, type);
823 - String errorMsg = "Missing Well-known Attribute: AS_PATH";
824 - throw new BgpParseException(errorMsg);
825 - }
826 - if (nextHop == null) {
827 - // Missing Attribute Type Code NEXT_HOP
828 - int type = BgpConstants.Update.NextHop.TYPE;
829 - actionsBgpUpdateMissingWellKnownAttribute(ctx, type);
830 - String errorMsg = "Missing Well-known Attribute: NEXT_HOP";
831 - throw new BgpParseException(errorMsg);
832 - }
833 - if (localPref == null) {
834 - // Missing Attribute Type Code LOCAL_PREF
835 - // NOTE: Required for iBGP
836 - int type = BgpConstants.Update.LocalPref.TYPE;
837 - actionsBgpUpdateMissingWellKnownAttribute(ctx, type);
838 - String errorMsg = "Missing Well-known Attribute: LOCAL_PREF";
839 - throw new BgpParseException(errorMsg);
840 - }
841 - }
842 474
843 /** 475 /**
844 - * Verifies the BGP UPDATE Attribute Flags. 476 + * Constructor for given Channel Handler Context.
845 * 477 *
846 - * @param ctx the Channel Handler Context 478 + * @param ctx the Channel Handler Context to use
847 - * @param attrTypeCode the attribute type code
848 - * @param attrLen the attribute length (in octets)
849 - * @param attrFlags the attribute flags
850 - * @param message the message to parse
851 - * @throws BgpParseException
852 */ 479 */
853 - private void verifyBgpUpdateAttributeFlags( 480 + SessionTimeoutTask(ChannelHandlerContext ctx) {
854 - ChannelHandlerContext ctx, 481 + this.ctx = ctx;
855 - int attrTypeCode,
856 - int attrLen,
857 - int attrFlags,
858 - ChannelBuffer message)
859 - throws BgpParseException {
860 -
861 - //
862 - // Assign the Attribute Type Name and the Well-known flag
863 - //
864 - String typeName = "UNKNOWN";
865 - boolean isWellKnown = false;
866 - switch (attrTypeCode) {
867 - case BgpConstants.Update.Origin.TYPE:
868 - isWellKnown = true;
869 - typeName = "ORIGIN";
870 - break;
871 - case BgpConstants.Update.AsPath.TYPE:
872 - isWellKnown = true;
873 - typeName = "AS_PATH";
874 - break;
875 - case BgpConstants.Update.NextHop.TYPE:
876 - isWellKnown = true;
877 - typeName = "NEXT_HOP";
878 - break;
879 - case BgpConstants.Update.MultiExitDisc.TYPE:
880 - isWellKnown = false;
881 - typeName = "MULTI_EXIT_DISC";
882 - break;
883 - case BgpConstants.Update.LocalPref.TYPE:
884 - isWellKnown = true;
885 - typeName = "LOCAL_PREF";
886 - break;
887 - case BgpConstants.Update.AtomicAggregate.TYPE:
888 - isWellKnown = true;
889 - typeName = "ATOMIC_AGGREGATE";
890 - break;
891 - case BgpConstants.Update.Aggregator.TYPE:
892 - isWellKnown = false;
893 - typeName = "AGGREGATOR";
894 - break;
895 - default:
896 - isWellKnown = false;
897 - typeName = "UNKNOWN(" + attrTypeCode + ")";
898 - break;
899 } 482 }
900 483
901 - // 484 + @Override
902 - // Verify the Attribute Flags 485 + public void run(Timeout timeout) throws Exception {
903 - // 486 + if (timeout.isCancelled()) {
904 - boolean optionalBit = ((0x80 & attrFlags) != 0); 487 + return;
905 - boolean transitiveBit = ((0x40 & attrFlags) != 0);
906 - boolean partialBit = ((0x20 & attrFlags) != 0);
907 - if ((isWellKnown && optionalBit) ||
908 - (isWellKnown && (!transitiveBit)) ||
909 - (isWellKnown && partialBit) ||
910 - (optionalBit && (!transitiveBit) && partialBit)) {
911 - //
912 - // ERROR: The Optional bit cannot be set for Well-known attributes
913 - // ERROR: The Transtive bit MUST be 1 for well-known attributes
914 - // ERROR: The Partial bit MUST be 0 for well-known attributes
915 - // ERROR: The Partial bit MUST be 0 for optional non-transitive
916 - // attributes
917 - //
918 - actionsBgpUpdateAttributeFlagsError(
919 - ctx, attrTypeCode, attrLen, attrFlags, message);
920 - String errorMsg = "Attribute Flags Error for " + typeName + ": " +
921 - attrFlags;
922 - throw new BgpParseException(errorMsg);
923 } 488 }
924 - } 489 + if (!ctx.getChannel().isOpen()) {
925 - 490 + return;
926 - /**
927 - * Parses BGP UPDATE Attribute Type ORIGIN.
928 - *
929 - * @param ctx the Channel Handler Context
930 - * @param attrTypeCode the attribute type code
931 - * @param attrLen the attribute length (in octets)
932 - * @param attrFlags the attribute flags
933 - * @param message the message to parse
934 - * @return the parsed ORIGIN value
935 - * @throws BgpParseException
936 - */
937 - private short parseAttributeTypeOrigin(
938 - ChannelHandlerContext ctx,
939 - int attrTypeCode,
940 - int attrLen,
941 - int attrFlags,
942 - ChannelBuffer message)
943 - throws BgpParseException {
944 -
945 - // Check the Attribute Length
946 - if (attrLen != BgpConstants.Update.Origin.LENGTH) {
947 - // ERROR: Attribute Length Error
948 - actionsBgpUpdateAttributeLengthError(
949 - ctx, attrTypeCode, attrLen, attrFlags, message);
950 - String errorMsg = "Attribute Length Error";
951 - throw new BgpParseException(errorMsg);
952 - }
953 -
954 - message.markReaderIndex();
955 - short origin = message.readUnsignedByte();
956 - switch (origin) {
957 - case BgpConstants.Update.Origin.IGP:
958 - // FALLTHROUGH
959 - case BgpConstants.Update.Origin.EGP:
960 - // FALLTHROUGH
961 - case BgpConstants.Update.Origin.INCOMPLETE:
962 - break;
963 - default:
964 - // ERROR: Invalid ORIGIN Attribute
965 - message.resetReaderIndex();
966 - actionsBgpUpdateInvalidOriginAttribute(
967 - ctx, attrTypeCode, attrLen, attrFlags, message, origin);
968 - String errorMsg = "Invalid ORIGIN Attribute: " + origin;
969 - throw new BgpParseException(errorMsg);
970 - }
971 -
972 - return origin;
973 - }
974 -
975 - /**
976 - * Parses BGP UPDATE Attribute AS Path.
977 - *
978 - * @param ctx the Channel Handler Context
979 - * @param attrTypeCode the attribute type code
980 - * @param attrLen the attribute length (in octets)
981 - * @param attrFlags the attribute flags
982 - * @param message the message to parse
983 - * @return the parsed AS Path
984 - * @throws BgpParseException
985 - */
986 - private BgpRouteEntry.AsPath parseAttributeTypeAsPath(
987 - ChannelHandlerContext ctx,
988 - int attrTypeCode,
989 - int attrLen,
990 - int attrFlags,
991 - ChannelBuffer message)
992 - throws BgpParseException {
993 - ArrayList<BgpRouteEntry.PathSegment> pathSegments = new ArrayList<>();
994 -
995 - //
996 - // Parse the message
997 - //
998 - while (attrLen > 0) {
999 - if (attrLen < 2) {
1000 - // ERROR: Malformed AS_PATH
1001 - actionsBgpUpdateMalformedAsPath(ctx);
1002 - String errorMsg = "Malformed AS Path";
1003 - throw new BgpParseException(errorMsg);
1004 - }
1005 - // Get the Path Segment Type and Length (in number of ASes)
1006 - short pathSegmentType = message.readUnsignedByte();
1007 - short pathSegmentLength = message.readUnsignedByte();
1008 - attrLen -= 2;
1009 -
1010 - // Verify the Path Segment Type
1011 - switch (pathSegmentType) {
1012 - case BgpConstants.Update.AsPath.AS_SET:
1013 - // FALLTHROUGH
1014 - case BgpConstants.Update.AsPath.AS_SEQUENCE:
1015 - // FALLTHROUGH
1016 - case BgpConstants.Update.AsPath.AS_CONFED_SEQUENCE:
1017 - // FALLTHROUGH
1018 - case BgpConstants.Update.AsPath.AS_CONFED_SET:
1019 - break;
1020 - default:
1021 - // ERROR: Invalid Path Segment Type
1022 - //
1023 - // NOTE: The BGP Spec (RFC 4271) doesn't contain Error Subcode
1024 - // for "Invalid Path Segment Type", hence we return
1025 - // the error as "Malformed AS_PATH".
1026 - //
1027 - actionsBgpUpdateMalformedAsPath(ctx);
1028 - String errorMsg =
1029 - "Invalid AS Path Segment Type: " + pathSegmentType;
1030 - throw new BgpParseException(errorMsg);
1031 - }
1032 -
1033 - // Parse the AS numbers
1034 - if (2 * pathSegmentLength > attrLen) {
1035 - // ERROR: Malformed AS_PATH
1036 - actionsBgpUpdateMalformedAsPath(ctx);
1037 - String errorMsg = "Malformed AS Path";
1038 - throw new BgpParseException(errorMsg);
1039 - }
1040 - attrLen -= (2 * pathSegmentLength);
1041 - ArrayList<Long> segmentAsNumbers = new ArrayList<>();
1042 - while (pathSegmentLength-- > 0) {
1043 - long asNumber = message.readUnsignedShort();
1044 - segmentAsNumbers.add(asNumber);
1045 - }
1046 -
1047 - BgpRouteEntry.PathSegment pathSegment =
1048 - new BgpRouteEntry.PathSegment((byte) pathSegmentType,
1049 - segmentAsNumbers);
1050 - pathSegments.add(pathSegment);
1051 - }
1052 -
1053 - return new BgpRouteEntry.AsPath(pathSegments);
1054 - }
1055 -
1056 - /**
1057 - * Parses BGP UPDATE Attribute Type NEXT_HOP.
1058 - *
1059 - * @param ctx the Channel Handler Context
1060 - * @param attrTypeCode the attribute type code
1061 - * @param attrLen the attribute length (in octets)
1062 - * @param attrFlags the attribute flags
1063 - * @param message the message to parse
1064 - * @return the parsed NEXT_HOP value
1065 - * @throws BgpParseException
1066 - */
1067 - private Ip4Address parseAttributeTypeNextHop(
1068 - ChannelHandlerContext ctx,
1069 - int attrTypeCode,
1070 - int attrLen,
1071 - int attrFlags,
1072 - ChannelBuffer message)
1073 - throws BgpParseException {
1074 -
1075 - // Check the Attribute Length
1076 - if (attrLen != BgpConstants.Update.NextHop.LENGTH) {
1077 - // ERROR: Attribute Length Error
1078 - actionsBgpUpdateAttributeLengthError(
1079 - ctx, attrTypeCode, attrLen, attrFlags, message);
1080 - String errorMsg = "Attribute Length Error";
1081 - throw new BgpParseException(errorMsg);
1082 - }
1083 -
1084 - message.markReaderIndex();
1085 - Ip4Address nextHopAddress =
1086 - Ip4Address.valueOf((int) message.readUnsignedInt());
1087 - //
1088 - // Check whether the NEXT_HOP IP address is semantically correct.
1089 - // As per RFC 4271, Section 6.3:
1090 - //
1091 - // a) It MUST NOT be the IP address of the receiving speaker
1092 - // b) In the case of an EBGP ....
1093 - //
1094 - // Here we check only (a), because (b) doesn't apply for us: all our
1095 - // peers are iBGP.
1096 - //
1097 - if (nextHopAddress.equals(localIp4Address)) {
1098 - // ERROR: Invalid NEXT_HOP Attribute
1099 - message.resetReaderIndex();
1100 - actionsBgpUpdateInvalidNextHopAttribute(
1101 - ctx, attrTypeCode, attrLen, attrFlags, message,
1102 - nextHopAddress);
1103 - String errorMsg = "Invalid NEXT_HOP Attribute: " + nextHopAddress;
1104 - throw new BgpParseException(errorMsg);
1105 - }
1106 -
1107 - return nextHopAddress;
1108 - }
1109 -
1110 - /**
1111 - * Parses BGP UPDATE Attribute Type MULTI_EXIT_DISC.
1112 - *
1113 - * @param ctx the Channel Handler Context
1114 - * @param attrTypeCode the attribute type code
1115 - * @param attrLen the attribute length (in octets)
1116 - * @param attrFlags the attribute flags
1117 - * @param message the message to parse
1118 - * @return the parsed MULTI_EXIT_DISC value
1119 - * @throws BgpParseException
1120 - */
1121 - private long parseAttributeTypeMultiExitDisc(
1122 - ChannelHandlerContext ctx,
1123 - int attrTypeCode,
1124 - int attrLen,
1125 - int attrFlags,
1126 - ChannelBuffer message)
1127 - throws BgpParseException {
1128 -
1129 - // Check the Attribute Length
1130 - if (attrLen != BgpConstants.Update.MultiExitDisc.LENGTH) {
1131 - // ERROR: Attribute Length Error
1132 - actionsBgpUpdateAttributeLengthError(
1133 - ctx, attrTypeCode, attrLen, attrFlags, message);
1134 - String errorMsg = "Attribute Length Error";
1135 - throw new BgpParseException(errorMsg);
1136 - }
1137 -
1138 - long multiExitDisc = message.readUnsignedInt();
1139 - return multiExitDisc;
1140 - }
1141 -
1142 - /**
1143 - * Parses BGP UPDATE Attribute Type LOCAL_PREF.
1144 - *
1145 - * @param ctx the Channel Handler Context
1146 - * @param attrTypeCode the attribute type code
1147 - * @param attrLen the attribute length (in octets)
1148 - * @param attrFlags the attribute flags
1149 - * @param message the message to parse
1150 - * @return the parsed LOCAL_PREF value
1151 - * @throws BgpParseException
1152 - */
1153 - private long parseAttributeTypeLocalPref(
1154 - ChannelHandlerContext ctx,
1155 - int attrTypeCode,
1156 - int attrLen,
1157 - int attrFlags,
1158 - ChannelBuffer message)
1159 - throws BgpParseException {
1160 -
1161 - // Check the Attribute Length
1162 - if (attrLen != BgpConstants.Update.LocalPref.LENGTH) {
1163 - // ERROR: Attribute Length Error
1164 - actionsBgpUpdateAttributeLengthError(
1165 - ctx, attrTypeCode, attrLen, attrFlags, message);
1166 - String errorMsg = "Attribute Length Error";
1167 - throw new BgpParseException(errorMsg);
1168 - }
1169 -
1170 - long localPref = message.readUnsignedInt();
1171 - return localPref;
1172 - }
1173 -
1174 - /**
1175 - * Parses BGP UPDATE Attribute Type ATOMIC_AGGREGATE.
1176 - *
1177 - * @param ctx the Channel Handler Context
1178 - * @param attrTypeCode the attribute type code
1179 - * @param attrLen the attribute length (in octets)
1180 - * @param attrFlags the attribute flags
1181 - * @param message the message to parse
1182 - * @throws BgpParseException
1183 - */
1184 - private void parseAttributeTypeAtomicAggregate(
1185 - ChannelHandlerContext ctx,
1186 - int attrTypeCode,
1187 - int attrLen,
1188 - int attrFlags,
1189 - ChannelBuffer message)
1190 - throws BgpParseException {
1191 -
1192 - // Check the Attribute Length
1193 - if (attrLen != BgpConstants.Update.AtomicAggregate.LENGTH) {
1194 - // ERROR: Attribute Length Error
1195 - actionsBgpUpdateAttributeLengthError(
1196 - ctx, attrTypeCode, attrLen, attrFlags, message);
1197 - String errorMsg = "Attribute Length Error";
1198 - throw new BgpParseException(errorMsg);
1199 - }
1200 -
1201 - // Nothing to do: this attribute is primarily informational
1202 - }
1203 -
1204 - /**
1205 - * Parses BGP UPDATE Attribute Type AGGREGATOR.
1206 - *
1207 - * @param ctx the Channel Handler Context
1208 - * @param attrTypeCode the attribute type code
1209 - * @param attrLen the attribute length (in octets)
1210 - * @param attrFlags the attribute flags
1211 - * @param message the message to parse
1212 - * @return the parsed AGGREGATOR value: a tuple of <AS-Number, IP-Address>
1213 - * @throws BgpParseException
1214 - */
1215 - private Pair<Long, Ip4Address> parseAttributeTypeAggregator(
1216 - ChannelHandlerContext ctx,
1217 - int attrTypeCode,
1218 - int attrLen,
1219 - int attrFlags,
1220 - ChannelBuffer message)
1221 - throws BgpParseException {
1222 -
1223 - // Check the Attribute Length
1224 - if (attrLen != BgpConstants.Update.Aggregator.LENGTH) {
1225 - // ERROR: Attribute Length Error
1226 - actionsBgpUpdateAttributeLengthError(
1227 - ctx, attrTypeCode, attrLen, attrFlags, message);
1228 - String errorMsg = "Attribute Length Error";
1229 - throw new BgpParseException(errorMsg);
1230 - }
1231 -
1232 - // The AGGREGATOR AS number
1233 - long aggregatorAsNumber = message.readUnsignedShort();
1234 - // The AGGREGATOR IP address
1235 - Ip4Address aggregatorIpAddress =
1236 - Ip4Address.valueOf((int) message.readUnsignedInt());
1237 -
1238 - Pair<Long, Ip4Address> aggregator = Pair.of(aggregatorAsNumber,
1239 - aggregatorIpAddress);
1240 - return aggregator;
1241 - }
1242 -
1243 - /**
1244 - * Parses a message that contains encoded IPv4 network prefixes.
1245 - * <p>
1246 - * The IPv4 prefixes are encoded in the form:
1247 - * <Length, Prefix> where Length is the length in bits of the IPv4 prefix,
1248 - * and Prefix is the IPv4 prefix (padded with trailing bits to the end
1249 - * of an octet).
1250 - *
1251 - * @param totalLength the total length of the data to parse
1252 - * @param message the message with data to parse
1253 - * @return a collection of parsed IPv4 network prefixes
1254 - * @throws BgpParseException
1255 - */
1256 - private Collection<Ip4Prefix> parsePackedPrefixes(int totalLength,
1257 - ChannelBuffer message)
1258 - throws BgpParseException {
1259 - Collection<Ip4Prefix> result = new ArrayList<>();
1260 -
1261 - if (totalLength == 0) {
1262 - return result;
1263 - }
1264 -
1265 - // Parse the data
1266 - int dataEnd = message.readerIndex() + totalLength;
1267 - while (message.readerIndex() < dataEnd) {
1268 - int prefixBitlen = message.readUnsignedByte();
1269 - int prefixBytelen = (prefixBitlen + 7) / 8; // Round-up
1270 - if (message.readerIndex() + prefixBytelen > dataEnd) {
1271 - String errorMsg = "Malformed Network Prefixes";
1272 - throw new BgpParseException(errorMsg);
1273 - }
1274 -
1275 - long address = 0;
1276 - long extraShift = (4 - prefixBytelen) * 8;
1277 - while (prefixBytelen > 0) {
1278 - address <<= 8;
1279 - address |= message.readUnsignedByte();
1280 - prefixBytelen--;
1281 - }
1282 - address <<= extraShift;
1283 - Ip4Prefix prefix =
1284 - Ip4Prefix.valueOf(Ip4Address.valueOf((int) address),
1285 - prefixBitlen);
1286 - result.add(prefix);
1287 - }
1288 -
1289 - return result;
1290 - }
1291 -
1292 - /**
1293 - * Applies the appropriate actions after detecting BGP UPDATE
1294 - * Invalid Network Field Error: send NOTIFICATION and close the channel.
1295 - *
1296 - * @param ctx the Channel Handler Context
1297 - */
1298 - private void actionsBgpUpdateInvalidNetworkField(
1299 - ChannelHandlerContext ctx) {
1300 - log.debug("BGP RX UPDATE Error from {}: Invalid Network Field",
1301 - remoteAddress);
1302 -
1303 - //
1304 - // ERROR: Invalid Network Field
1305 - //
1306 - // Send NOTIFICATION and close the connection
1307 - int errorCode = UpdateMessageError.ERROR_CODE;
1308 - int errorSubcode = UpdateMessageError.INVALID_NETWORK_FIELD;
1309 - ChannelBuffer txMessage =
1310 - prepareBgpNotification(errorCode, errorSubcode, null);
1311 - ctx.getChannel().write(txMessage);
1312 - closeSession(ctx);
1313 - }
1314 -
1315 - /**
1316 - * Applies the appropriate actions after detecting BGP UPDATE
1317 - * Malformed Attribute List Error: send NOTIFICATION and close the channel.
1318 - *
1319 - * @param ctx the Channel Handler Context
1320 - */
1321 - private void actionsBgpUpdateMalformedAttributeList(
1322 - ChannelHandlerContext ctx) {
1323 - log.debug("BGP RX UPDATE Error from {}: Malformed Attribute List",
1324 - remoteAddress);
1325 -
1326 - //
1327 - // ERROR: Malformed Attribute List
1328 - //
1329 - // Send NOTIFICATION and close the connection
1330 - int errorCode = UpdateMessageError.ERROR_CODE;
1331 - int errorSubcode = UpdateMessageError.MALFORMED_ATTRIBUTE_LIST;
1332 - ChannelBuffer txMessage =
1333 - prepareBgpNotification(errorCode, errorSubcode, null);
1334 - ctx.getChannel().write(txMessage);
1335 - closeSession(ctx);
1336 - }
1337 -
1338 - /**
1339 - * Applies the appropriate actions after detecting BGP UPDATE
1340 - * Missing Well-known Attribute Error: send NOTIFICATION and close the
1341 - * channel.
1342 - *
1343 - * @param ctx the Channel Handler Context
1344 - * @param missingAttrTypeCode the missing attribute type code
1345 - */
1346 - private void actionsBgpUpdateMissingWellKnownAttribute(
1347 - ChannelHandlerContext ctx,
1348 - int missingAttrTypeCode) {
1349 - log.debug("BGP RX UPDATE Error from {}: Missing Well-known Attribute: {}",
1350 - remoteAddress, missingAttrTypeCode);
1351 -
1352 - //
1353 - // ERROR: Missing Well-known Attribute
1354 - //
1355 - // Send NOTIFICATION and close the connection
1356 - int errorCode = UpdateMessageError.ERROR_CODE;
1357 - int errorSubcode = UpdateMessageError.MISSING_WELL_KNOWN_ATTRIBUTE;
1358 - ChannelBuffer data = ChannelBuffers.buffer(1);
1359 - data.writeByte(missingAttrTypeCode);
1360 - ChannelBuffer txMessage =
1361 - prepareBgpNotification(errorCode, errorSubcode, data);
1362 - ctx.getChannel().write(txMessage);
1363 - closeSession(ctx);
1364 - }
1365 -
1366 - /**
1367 - * Applies the appropriate actions after detecting BGP UPDATE
1368 - * Invalid ORIGIN Attribute Error: send NOTIFICATION and close the channel.
1369 - *
1370 - * @param ctx the Channel Handler Context
1371 - * @param attrTypeCode the attribute type code
1372 - * @param attrLen the attribute length (in octets)
1373 - * @param attrFlags the attribute flags
1374 - * @param message the message with the data
1375 - * @param origin the ORIGIN attribute value
1376 - */
1377 - private void actionsBgpUpdateInvalidOriginAttribute(
1378 - ChannelHandlerContext ctx,
1379 - int attrTypeCode,
1380 - int attrLen,
1381 - int attrFlags,
1382 - ChannelBuffer message,
1383 - short origin) {
1384 - log.debug("BGP RX UPDATE Error from {}: Invalid ORIGIN Attribute",
1385 - remoteAddress);
1386 -
1387 - //
1388 - // ERROR: Invalid ORIGIN Attribute
1389 - //
1390 - // Send NOTIFICATION and close the connection
1391 - int errorCode = UpdateMessageError.ERROR_CODE;
1392 - int errorSubcode = UpdateMessageError.INVALID_ORIGIN_ATTRIBUTE;
1393 - ChannelBuffer data =
1394 - prepareBgpUpdateNotificationDataPayload(attrTypeCode, attrLen,
1395 - attrFlags, message);
1396 - ChannelBuffer txMessage =
1397 - prepareBgpNotification(errorCode, errorSubcode, data);
1398 - ctx.getChannel().write(txMessage);
1399 - closeSession(ctx);
1400 - }
1401 -
1402 - /**
1403 - * Applies the appropriate actions after detecting BGP UPDATE
1404 - * Attribute Flags Error: send NOTIFICATION and close the channel.
1405 - *
1406 - * @param ctx the Channel Handler Context
1407 - * @param attrTypeCode the attribute type code
1408 - * @param attrLen the attribute length (in octets)
1409 - * @param attrFlags the attribute flags
1410 - * @param message the message with the data
1411 - */
1412 - private void actionsBgpUpdateAttributeFlagsError(
1413 - ChannelHandlerContext ctx,
1414 - int attrTypeCode,
1415 - int attrLen,
1416 - int attrFlags,
1417 - ChannelBuffer message) {
1418 - log.debug("BGP RX UPDATE Error from {}: Attribute Flags Error",
1419 - remoteAddress);
1420 -
1421 - //
1422 - // ERROR: Attribute Flags Error
1423 - //
1424 - // Send NOTIFICATION and close the connection
1425 - int errorCode = UpdateMessageError.ERROR_CODE;
1426 - int errorSubcode = UpdateMessageError.ATTRIBUTE_FLAGS_ERROR;
1427 - ChannelBuffer data =
1428 - prepareBgpUpdateNotificationDataPayload(attrTypeCode, attrLen,
1429 - attrFlags, message);
1430 - ChannelBuffer txMessage =
1431 - prepareBgpNotification(errorCode, errorSubcode, data);
1432 - ctx.getChannel().write(txMessage);
1433 - closeSession(ctx);
1434 - }
1435 -
1436 - /**
1437 - * Applies the appropriate actions after detecting BGP UPDATE
1438 - * Invalid NEXT_HOP Attribute Error: send NOTIFICATION and close the
1439 - * channel.
1440 - *
1441 - * @param ctx the Channel Handler Context
1442 - * @param attrTypeCode the attribute type code
1443 - * @param attrLen the attribute length (in octets)
1444 - * @param attrFlags the attribute flags
1445 - * @param message the message with the data
1446 - * @param nextHop the NEXT_HOP attribute value
1447 - */
1448 - private void actionsBgpUpdateInvalidNextHopAttribute(
1449 - ChannelHandlerContext ctx,
1450 - int attrTypeCode,
1451 - int attrLen,
1452 - int attrFlags,
1453 - ChannelBuffer message,
1454 - Ip4Address nextHop) {
1455 - log.debug("BGP RX UPDATE Error from {}: Invalid NEXT_HOP Attribute {}",
1456 - remoteAddress, nextHop);
1457 -
1458 - //
1459 - // ERROR: Invalid ORIGIN Attribute
1460 - //
1461 - // Send NOTIFICATION and close the connection
1462 - int errorCode = UpdateMessageError.ERROR_CODE;
1463 - int errorSubcode = UpdateMessageError.INVALID_NEXT_HOP_ATTRIBUTE;
1464 - ChannelBuffer data =
1465 - prepareBgpUpdateNotificationDataPayload(attrTypeCode, attrLen,
1466 - attrFlags, message);
1467 - ChannelBuffer txMessage =
1468 - prepareBgpNotification(errorCode, errorSubcode, data);
1469 - ctx.getChannel().write(txMessage);
1470 - closeSession(ctx);
1471 - }
1472 -
1473 - /**
1474 - * Applies the appropriate actions after detecting BGP UPDATE
1475 - * Unrecognized Well-known Attribute Error: send NOTIFICATION and close
1476 - * the channel.
1477 - *
1478 - * @param ctx the Channel Handler Context
1479 - * @param attrTypeCode the attribute type code
1480 - * @param attrLen the attribute length (in octets)
1481 - * @param attrFlags the attribute flags
1482 - * @param message the message with the data
1483 - */
1484 - private void actionsBgpUpdateUnrecognizedWellKnownAttribute(
1485 - ChannelHandlerContext ctx,
1486 - int attrTypeCode,
1487 - int attrLen,
1488 - int attrFlags,
1489 - ChannelBuffer message) {
1490 - log.debug("BGP RX UPDATE Error from {}: " +
1491 - "Unrecognized Well-known Attribute Error: {}",
1492 - remoteAddress, attrTypeCode);
1493 -
1494 - //
1495 - // ERROR: Unrecognized Well-known Attribute
1496 - //
1497 - // Send NOTIFICATION and close the connection
1498 - int errorCode = UpdateMessageError.ERROR_CODE;
1499 - int errorSubcode =
1500 - UpdateMessageError.UNRECOGNIZED_WELL_KNOWN_ATTRIBUTE;
1501 - ChannelBuffer data =
1502 - prepareBgpUpdateNotificationDataPayload(attrTypeCode, attrLen,
1503 - attrFlags, message);
1504 - ChannelBuffer txMessage =
1505 - prepareBgpNotification(errorCode, errorSubcode, data);
1506 - ctx.getChannel().write(txMessage);
1507 - closeSession(ctx);
1508 - }
1509 -
1510 - /**
1511 - * Applies the appropriate actions after detecting BGP UPDATE
1512 - * Attribute Length Error: send NOTIFICATION and close the channel.
1513 - *
1514 - * @param ctx the Channel Handler Context
1515 - * @param attrTypeCode the attribute type code
1516 - * @param attrLen the attribute length (in octets)
1517 - * @param attrFlags the attribute flags
1518 - * @param message the message with the data
1519 - */
1520 - private void actionsBgpUpdateAttributeLengthError(
1521 - ChannelHandlerContext ctx,
1522 - int attrTypeCode,
1523 - int attrLen,
1524 - int attrFlags,
1525 - ChannelBuffer message) {
1526 - log.debug("BGP RX UPDATE Error from {}: Attribute Length Error",
1527 - remoteAddress);
1528 -
1529 - //
1530 - // ERROR: Attribute Length Error
1531 - //
1532 - // Send NOTIFICATION and close the connection
1533 - int errorCode = UpdateMessageError.ERROR_CODE;
1534 - int errorSubcode = UpdateMessageError.ATTRIBUTE_LENGTH_ERROR;
1535 - ChannelBuffer data =
1536 - prepareBgpUpdateNotificationDataPayload(attrTypeCode, attrLen,
1537 - attrFlags, message);
1538 - ChannelBuffer txMessage =
1539 - prepareBgpNotification(errorCode, errorSubcode, data);
1540 - ctx.getChannel().write(txMessage);
1541 - closeSession(ctx);
1542 - }
1543 -
1544 - /**
1545 - * Applies the appropriate actions after detecting BGP UPDATE
1546 - * Malformed AS_PATH Error: send NOTIFICATION and close the channel.
1547 - *
1548 - * @param ctx the Channel Handler Context
1549 - */
1550 - private void actionsBgpUpdateMalformedAsPath(
1551 - ChannelHandlerContext ctx) {
1552 - log.debug("BGP RX UPDATE Error from {}: Malformed AS Path",
1553 - remoteAddress);
1554 -
1555 - //
1556 - // ERROR: Malformed AS_PATH
1557 - //
1558 - // Send NOTIFICATION and close the connection
1559 - int errorCode = UpdateMessageError.ERROR_CODE;
1560 - int errorSubcode = UpdateMessageError.MALFORMED_AS_PATH;
1561 - ChannelBuffer txMessage =
1562 - prepareBgpNotification(errorCode, errorSubcode, null);
1563 - ctx.getChannel().write(txMessage);
1564 - closeSession(ctx);
1565 - }
1566 -
1567 - /**
1568 - * Processes BGP NOTIFICATION message.
1569 - *
1570 - * @param ctx the Channel Handler Context
1571 - * @param message the message to process
1572 - */
1573 - void processBgpNotification(ChannelHandlerContext ctx,
1574 - ChannelBuffer message) {
1575 - int minLength =
1576 - BgpConstants.BGP_NOTIFICATION_MIN_LENGTH - BgpConstants.BGP_HEADER_LENGTH;
1577 - if (message.readableBytes() < minLength) {
1578 - log.debug("BGP RX NOTIFICATION Error from {}: " +
1579 - "Message length {} too short. Must be at least {}",
1580 - remoteAddress, message.readableBytes(), minLength);
1581 - //
1582 - // ERROR: Bad Message Length
1583 - //
1584 - // NOTE: We do NOT send NOTIFICATION in response to a notification
1585 - return;
1586 - }
1587 -
1588 - //
1589 - // Parse the NOTIFICATION message
1590 - //
1591 - int errorCode = message.readUnsignedByte();
1592 - int errorSubcode = message.readUnsignedByte();
1593 - int dataLength = message.readableBytes();
1594 -
1595 - log.debug("BGP RX NOTIFICATION message from {}: Error Code {} " +
1596 - "Error Subcode {} Data Length {}",
1597 - remoteAddress, errorCode, errorSubcode, dataLength);
1598 -
1599 - //
1600 - // NOTE: If the peer sent a NOTIFICATION, we leave it to the peer to
1601 - // close the connection.
1602 - //
1603 -
1604 - // Start the Session Timeout timer
1605 - restartSessionTimeoutTimer(ctx);
1606 - }
1607 -
1608 - /**
1609 - * Processes BGP KEEPALIVE message.
1610 - *
1611 - * @param ctx the Channel Handler Context
1612 - * @param message the message to process
1613 - */
1614 - void processBgpKeepalive(ChannelHandlerContext ctx,
1615 - ChannelBuffer message) {
1616 - if (message.readableBytes() + BgpConstants.BGP_HEADER_LENGTH !=
1617 - BgpConstants.BGP_KEEPALIVE_EXPECTED_LENGTH) {
1618 - log.debug("BGP RX KEEPALIVE Error from {}: " +
1619 - "Invalid total message length {}. Expected {}",
1620 - remoteAddress,
1621 - message.readableBytes() + BgpConstants.BGP_HEADER_LENGTH,
1622 - BgpConstants.BGP_KEEPALIVE_EXPECTED_LENGTH);
1623 - //
1624 - // ERROR: Bad Message Length
1625 - //
1626 - // Send NOTIFICATION and close the connection
1627 - ChannelBuffer txMessage = prepareBgpNotificationBadMessageLength(
1628 - message.readableBytes() + BgpConstants.BGP_HEADER_LENGTH);
1629 - ctx.getChannel().write(txMessage);
1630 - closeSession(ctx);
1631 - return;
1632 - }
1633 -
1634 - //
1635 - // Parse the KEEPALIVE message: nothing to do
1636 - //
1637 - log.trace("BGP RX KEEPALIVE message from {}", remoteAddress);
1638 -
1639 - // Start the Session Timeout timer
1640 - restartSessionTimeoutTimer(ctx);
1641 - }
1642 -
1643 - /**
1644 - * Prepares BGP OPEN message.
1645 - *
1646 - * @return the message to transmit (BGP header included)
1647 - */
1648 - private ChannelBuffer prepareBgpOpen() {
1649 - ChannelBuffer message =
1650 - ChannelBuffers.buffer(BgpConstants.BGP_MESSAGE_MAX_LENGTH);
1651 -
1652 - //
1653 - // Prepare the OPEN message payload
1654 - //
1655 - message.writeByte(localBgpVersion);
1656 - message.writeShort((int) localAs);
1657 - message.writeShort((int) localHoldtime);
1658 - message.writeInt(bgpSessionManager.getMyBgpId().toInt());
1659 - message.writeByte(0); // No Optional Parameters
1660 - return prepareBgpMessage(BgpConstants.BGP_TYPE_OPEN, message);
1661 - }
1662 -
1663 - /**
1664 - * Prepares BGP KEEPALIVE message.
1665 - *
1666 - * @return the message to transmit (BGP header included)
1667 - */
1668 - private ChannelBuffer prepareBgpKeepalive() {
1669 - ChannelBuffer message =
1670 - ChannelBuffers.buffer(BgpConstants.BGP_MESSAGE_MAX_LENGTH);
1671 -
1672 - //
1673 - // Prepare the KEEPALIVE message payload: nothing to do
1674 - //
1675 - return prepareBgpMessage(BgpConstants.BGP_TYPE_KEEPALIVE, message);
1676 - }
1677 -
1678 - /**
1679 - * Prepares BGP NOTIFICATION message.
1680 - *
1681 - * @param errorCode the BGP NOTIFICATION Error Code
1682 - * @param errorSubcode the BGP NOTIFICATION Error Subcode if applicable,
1683 - * otherwise BgpConstants.Notifications.ERROR_SUBCODE_UNSPECIFIC
1684 - * @param data the BGP NOTIFICATION Data if applicable, otherwise null
1685 - * @return the message to transmit (BGP header included)
1686 - */
1687 - ChannelBuffer prepareBgpNotification(int errorCode, int errorSubcode,
1688 - ChannelBuffer data) {
1689 - ChannelBuffer message =
1690 - ChannelBuffers.buffer(BgpConstants.BGP_MESSAGE_MAX_LENGTH);
1691 -
1692 - //
1693 - // Prepare the NOTIFICATION message payload
1694 - //
1695 - message.writeByte(errorCode);
1696 - message.writeByte(errorSubcode);
1697 - if (data != null) {
1698 - message.writeBytes(data);
1699 - }
1700 - return prepareBgpMessage(BgpConstants.BGP_TYPE_NOTIFICATION, message);
1701 - }
1702 -
1703 - /**
1704 - * Prepares BGP NOTIFICATION message: Bad Message Length.
1705 - *
1706 - * @param length the erroneous Length field
1707 - * @return the message to transmit (BGP header included)
1708 - */
1709 - ChannelBuffer prepareBgpNotificationBadMessageLength(int length) {
1710 - int errorCode = MessageHeaderError.ERROR_CODE;
1711 - int errorSubcode = MessageHeaderError.BAD_MESSAGE_LENGTH;
1712 - ChannelBuffer data = ChannelBuffers.buffer(2);
1713 - data.writeShort(length);
1714 -
1715 - return prepareBgpNotification(errorCode, errorSubcode, data);
1716 - }
1717 -
1718 - /**
1719 - * Prepares BGP UPDATE Notification data payload.
1720 - *
1721 - * @param attrTypeCode the attribute type code
1722 - * @param attrLen the attribute length (in octets)
1723 - * @param attrFlags the attribute flags
1724 - * @param message the message with the data
1725 - * @return the buffer with the data payload for the BGP UPDATE Notification
1726 - */
1727 - private ChannelBuffer prepareBgpUpdateNotificationDataPayload(
1728 - int attrTypeCode,
1729 - int attrLen,
1730 - int attrFlags,
1731 - ChannelBuffer message) {
1732 - // Compute the attribute length field octets
1733 - boolean extendedLengthBit = ((0x10 & attrFlags) != 0);
1734 - int attrLenOctets = 1;
1735 - if (extendedLengthBit) {
1736 - attrLenOctets = 2;
1737 - }
1738 - ChannelBuffer data =
1739 - ChannelBuffers.buffer(attrLen + attrLenOctets + 1);
1740 - data.writeByte(attrTypeCode);
1741 - if (extendedLengthBit) {
1742 - data.writeShort(attrLen);
1743 - } else {
1744 - data.writeByte(attrLen);
1745 - }
1746 - data.writeBytes(message, attrLen);
1747 - return data;
1748 - }
1749 -
1750 - /**
1751 - * Prepares BGP message.
1752 - *
1753 - * @param type the BGP message type
1754 - * @param payload the message payload to transmit (BGP header excluded)
1755 - * @return the message to transmit (BGP header included)
1756 - */
1757 - private ChannelBuffer prepareBgpMessage(int type, ChannelBuffer payload) {
1758 - ChannelBuffer message =
1759 - ChannelBuffers.buffer(BgpConstants.BGP_HEADER_LENGTH +
1760 - payload.readableBytes());
1761 -
1762 - // Write the marker
1763 - for (int i = 0; i < BgpConstants.BGP_HEADER_MARKER_LENGTH; i++) {
1764 - message.writeByte(0xff);
1765 - }
1766 -
1767 - // Write the rest of the BGP header
1768 - message.writeShort(BgpConstants.BGP_HEADER_LENGTH +
1769 - payload.readableBytes());
1770 - message.writeByte(type);
1771 -
1772 - // Write the payload
1773 - message.writeBytes(payload);
1774 - return message;
1775 - }
1776 -
1777 - /**
1778 - * Restarts the BGP KeepaliveTimer.
1779 - */
1780 - private void restartKeepaliveTimer(ChannelHandlerContext ctx) {
1781 - if (localKeepaliveInterval == 0) {
1782 - return; // Nothing to do
1783 - }
1784 - keepaliveTimeout = timer.newTimeout(new TransmitKeepaliveTask(ctx),
1785 - localKeepaliveInterval,
1786 - TimeUnit.SECONDS);
1787 - }
1788 -
1789 - /**
1790 - * Task class for transmitting KEEPALIVE messages.
1791 - */
1792 - private final class TransmitKeepaliveTask implements TimerTask {
1793 - private final ChannelHandlerContext ctx;
1794 -
1795 - /**
1796 - * Constructor for given Channel Handler Context.
1797 - *
1798 - * @param ctx the Channel Handler Context to use
1799 - */
1800 - TransmitKeepaliveTask(ChannelHandlerContext ctx) {
1801 - this.ctx = ctx;
1802 - }
1803 -
1804 - @Override
1805 - public void run(Timeout timeout) throws Exception {
1806 - if (timeout.isCancelled()) {
1807 - return;
1808 - }
1809 - if (!ctx.getChannel().isOpen()) {
1810 - return;
1811 - }
1812 -
1813 - // Transmit the KEEPALIVE
1814 - ChannelBuffer txMessage = prepareBgpKeepalive();
1815 - ctx.getChannel().write(txMessage);
1816 -
1817 - // Restart the KEEPALIVE timer
1818 - restartKeepaliveTimer(ctx);
1819 - }
1820 - }
1821 -
1822 - /**
1823 - * Restarts the BGP Session Timeout Timer.
1824 - */
1825 - private void restartSessionTimeoutTimer(ChannelHandlerContext ctx) {
1826 - if (remoteHoldtime == 0) {
1827 - return; // Nothing to do
1828 - }
1829 - if (sessionTimeout != null) {
1830 - sessionTimeout.cancel();
1831 - }
1832 - sessionTimeout = timer.newTimeout(new SessionTimeoutTask(ctx),
1833 - remoteHoldtime,
1834 - TimeUnit.SECONDS);
1835 - }
1836 -
1837 - /**
1838 - * Task class for BGP Session timeout.
1839 - */
1840 - private final class SessionTimeoutTask implements TimerTask {
1841 - private final ChannelHandlerContext ctx;
1842 -
1843 - /**
1844 - * Constructor for given Channel Handler Context.
1845 - *
1846 - * @param ctx the Channel Handler Context to use
1847 - */
1848 - SessionTimeoutTask(ChannelHandlerContext ctx) {
1849 - this.ctx = ctx;
1850 - }
1851 -
1852 - @Override
1853 - public void run(Timeout timeout) throws Exception {
1854 - if (timeout.isCancelled()) {
1855 - return;
1856 - }
1857 - if (!ctx.getChannel().isOpen()) {
1858 - return;
1859 } 491 }
1860 492
1861 log.debug("BGP Session Timeout: peer {}", remoteAddress); 493 log.debug("BGP Session Timeout: peer {}", remoteAddress);
...@@ -1866,30 +498,10 @@ public class BgpSession extends SimpleChannelHandler { ...@@ -1866,30 +498,10 @@ public class BgpSession extends SimpleChannelHandler {
1866 int errorCode = HoldTimerExpired.ERROR_CODE; 498 int errorCode = HoldTimerExpired.ERROR_CODE;
1867 int errorSubcode = Notifications.ERROR_SUBCODE_UNSPECIFIC; 499 int errorSubcode = Notifications.ERROR_SUBCODE_UNSPECIFIC;
1868 ChannelBuffer txMessage = 500 ChannelBuffer txMessage =
1869 - prepareBgpNotification(errorCode, errorSubcode, null); 501 + BgpNotification.prepareBgpNotification(errorCode, errorSubcode,
502 + null);
1870 ctx.getChannel().write(txMessage); 503 ctx.getChannel().write(txMessage);
1871 closeChannel(ctx); 504 closeChannel(ctx);
1872 } 505 }
1873 } 506 }
1874 -
1875 - /**
1876 - * An exception indicating a parsing error of the BGP message.
1877 - */
1878 - private static class BgpParseException extends Exception {
1879 - /**
1880 - * Default constructor.
1881 - */
1882 - public BgpParseException() {
1883 - super();
1884 - }
1885 -
1886 - /**
1887 - * Constructor for a specific exception details message.
1888 - *
1889 - * @param message the message with the exception details
1890 - */
1891 - public BgpParseException(String message) {
1892 - super(message);
1893 - }
1894 - }
1895 } 507 }
......
1 +/*
2 + * Copyright 2014 Open Networking Laboratory
3 + *
4 + * 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
7 + *
8 + * 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.
15 + */
16 +package org.onosproject.sdnip.bgp;
17 +
18 +import java.util.ArrayList;
19 +import java.util.Collection;
20 +import java.util.HashMap;
21 +import java.util.Map;
22 +
23 +import org.apache.commons.lang3.tuple.Pair;
24 +import org.jboss.netty.buffer.ChannelBuffer;
25 +import org.jboss.netty.buffer.ChannelBuffers;
26 +import org.jboss.netty.channel.ChannelHandlerContext;
27 +import org.onlab.packet.Ip4Address;
28 +import org.onlab.packet.Ip4Prefix;
29 +import org.onosproject.sdnip.bgp.BgpConstants.Notifications.UpdateMessageError;
30 +import org.slf4j.Logger;
31 +import org.slf4j.LoggerFactory;
32 +
33 +/**
34 + * A class for handling BGP UPDATE messages.
35 + */
36 +final class BgpUpdate {
37 + private static final Logger log = LoggerFactory.getLogger(BgpUpdate.class);
38 +
39 + /**
40 + * Default constructor.
41 + * <p>
42 + * The constructor is private to prevent creating an instance of
43 + * this utility class.
44 + */
45 + private BgpUpdate() {
46 + }
47 +
48 + /**
49 + * Processes BGP UPDATE message.
50 + *
51 + * @param bgpSession the BGP Session to use
52 + * @param ctx the Channel Handler Context
53 + * @param message the message to process
54 + */
55 + static void processBgpUpdate(BgpSession bgpSession,
56 + ChannelHandlerContext ctx,
57 + ChannelBuffer message) {
58 + Collection<BgpRouteEntry> addedRoutes = null;
59 + Map<Ip4Prefix, BgpRouteEntry> deletedRoutes = new HashMap<>();
60 +
61 + int minLength =
62 + BgpConstants.BGP_UPDATE_MIN_LENGTH - BgpConstants.BGP_HEADER_LENGTH;
63 + if (message.readableBytes() < minLength) {
64 + log.debug("BGP RX UPDATE Error from {}: " +
65 + "Message length {} too short. Must be at least {}",
66 + bgpSession.getRemoteAddress(), message.readableBytes(),
67 + minLength);
68 + //
69 + // ERROR: Bad Message Length
70 + //
71 + // Send NOTIFICATION and close the connection
72 + ChannelBuffer txMessage =
73 + BgpNotification.prepareBgpNotificationBadMessageLength(
74 + message.readableBytes() + BgpConstants.BGP_HEADER_LENGTH);
75 + ctx.getChannel().write(txMessage);
76 + bgpSession.closeSession(ctx);
77 + return;
78 + }
79 +
80 + log.debug("BGP RX UPDATE message from {}",
81 + bgpSession.getRemoteAddress());
82 +
83 + //
84 + // Parse the UPDATE message
85 + //
86 +
87 + //
88 + // Parse the Withdrawn Routes
89 + //
90 + int withdrawnRoutesLength = message.readUnsignedShort();
91 + if (withdrawnRoutesLength > message.readableBytes()) {
92 + // ERROR: Malformed Attribute List
93 + actionsBgpUpdateMalformedAttributeList(bgpSession, ctx);
94 + return;
95 + }
96 + Collection<Ip4Prefix> withdrawnPrefixes = null;
97 + try {
98 + withdrawnPrefixes = parsePackedPrefixes(withdrawnRoutesLength,
99 + message);
100 + } catch (BgpParseException e) {
101 + // ERROR: Invalid Network Field
102 + log.debug("Exception parsing Withdrawn Prefixes from BGP peer {}: ",
103 + bgpSession.getRemoteBgpId(), e);
104 + actionsBgpUpdateInvalidNetworkField(bgpSession, ctx);
105 + return;
106 + }
107 + for (Ip4Prefix prefix : withdrawnPrefixes) {
108 + log.debug("BGP RX UPDATE message WITHDRAWN from {}: {}",
109 + bgpSession.getRemoteAddress(), prefix);
110 + BgpRouteEntry bgpRouteEntry = bgpSession.bgpRibIn().get(prefix);
111 + if (bgpRouteEntry != null) {
112 + deletedRoutes.put(prefix, bgpRouteEntry);
113 + }
114 + }
115 +
116 + //
117 + // Parse the Path Attributes
118 + //
119 + try {
120 + addedRoutes = parsePathAttributes(bgpSession, ctx, message);
121 + } catch (BgpParseException e) {
122 + log.debug("Exception parsing Path Attributes from BGP peer {}: ",
123 + bgpSession.getRemoteBgpId(), e);
124 + // NOTE: The session was already closed, so nothing else to do
125 + return;
126 + }
127 + // Ignore WITHDRAWN routes that are ADDED
128 + for (BgpRouteEntry bgpRouteEntry : addedRoutes) {
129 + deletedRoutes.remove(bgpRouteEntry.prefix());
130 + }
131 +
132 + // Update the BGP RIB-IN
133 + for (BgpRouteEntry bgpRouteEntry : deletedRoutes.values()) {
134 + bgpSession.bgpRibIn().remove(bgpRouteEntry.prefix());
135 + }
136 + for (BgpRouteEntry bgpRouteEntry : addedRoutes) {
137 + bgpSession.bgpRibIn().put(bgpRouteEntry.prefix(), bgpRouteEntry);
138 + }
139 +
140 + // Push the updates to the BGP Merged RIB
141 + BgpSessionManager.BgpRouteSelector bgpRouteSelector =
142 + bgpSession.getBgpSessionManager().getBgpRouteSelector();
143 + bgpRouteSelector.routeUpdates(bgpSession, addedRoutes,
144 + deletedRoutes.values());
145 +
146 + // Start the Session Timeout timer
147 + bgpSession.restartSessionTimeoutTimer(ctx);
148 + }
149 +
150 + /**
151 + * Parse BGP Path Attributes from the BGP UPDATE message.
152 + *
153 + * @param bgpSession the BGP Session to use
154 + * @param ctx the Channel Handler Context
155 + * @param message the message to parse
156 + * @return a collection of the result BGP Route Entries
157 + * @throws BgpParseException
158 + */
159 + private static Collection<BgpRouteEntry> parsePathAttributes(
160 + BgpSession bgpSession,
161 + ChannelHandlerContext ctx,
162 + ChannelBuffer message)
163 + throws BgpParseException {
164 + Map<Ip4Prefix, BgpRouteEntry> addedRoutes = new HashMap<>();
165 +
166 + //
167 + // Parsed values
168 + //
169 + Short origin = -1; // Mandatory
170 + BgpRouteEntry.AsPath asPath = null; // Mandatory
171 + Ip4Address nextHop = null; // Mandatory
172 + long multiExitDisc = // Optional
173 + BgpConstants.Update.MultiExitDisc.LOWEST_MULTI_EXIT_DISC;
174 + Long localPref = null; // Mandatory
175 + Long aggregatorAsNumber = null; // Optional: unused
176 + Ip4Address aggregatorIpAddress = null; // Optional: unused
177 +
178 + //
179 + // Get and verify the Path Attributes Length
180 + //
181 + int pathAttributeLength = message.readUnsignedShort();
182 + if (pathAttributeLength > message.readableBytes()) {
183 + // ERROR: Malformed Attribute List
184 + actionsBgpUpdateMalformedAttributeList(bgpSession, ctx);
185 + String errorMsg = "Malformed Attribute List";
186 + throw new BgpParseException(errorMsg);
187 + }
188 + if (pathAttributeLength == 0) {
189 + return addedRoutes.values();
190 + }
191 +
192 + //
193 + // Parse the Path Attributes
194 + //
195 + int pathAttributeEnd = message.readerIndex() + pathAttributeLength;
196 + while (message.readerIndex() < pathAttributeEnd) {
197 + int attrFlags = message.readUnsignedByte();
198 + if (message.readerIndex() >= pathAttributeEnd) {
199 + // ERROR: Malformed Attribute List
200 + actionsBgpUpdateMalformedAttributeList(bgpSession, ctx);
201 + String errorMsg = "Malformed Attribute List";
202 + throw new BgpParseException(errorMsg);
203 + }
204 + int attrTypeCode = message.readUnsignedByte();
205 +
206 + // The Attribute Flags
207 + boolean optionalBit = ((0x80 & attrFlags) != 0);
208 + boolean transitiveBit = ((0x40 & attrFlags) != 0);
209 + boolean partialBit = ((0x20 & attrFlags) != 0);
210 + boolean extendedLengthBit = ((0x10 & attrFlags) != 0);
211 +
212 + // The Attribute Length
213 + int attrLen = 0;
214 + int attrLenOctets = 1;
215 + if (extendedLengthBit) {
216 + attrLenOctets = 2;
217 + }
218 + if (message.readerIndex() + attrLenOctets > pathAttributeEnd) {
219 + // ERROR: Malformed Attribute List
220 + actionsBgpUpdateMalformedAttributeList(bgpSession, ctx);
221 + String errorMsg = "Malformed Attribute List";
222 + throw new BgpParseException(errorMsg);
223 + }
224 + if (extendedLengthBit) {
225 + attrLen = message.readUnsignedShort();
226 + } else {
227 + attrLen = message.readUnsignedByte();
228 + }
229 + if (message.readerIndex() + attrLen > pathAttributeEnd) {
230 + // ERROR: Malformed Attribute List
231 + actionsBgpUpdateMalformedAttributeList(bgpSession, ctx);
232 + String errorMsg = "Malformed Attribute List";
233 + throw new BgpParseException(errorMsg);
234 + }
235 +
236 + // Verify the Attribute Flags
237 + verifyBgpUpdateAttributeFlags(bgpSession, ctx, attrTypeCode,
238 + attrLen, attrFlags, message);
239 +
240 + //
241 + // Extract the Attribute Value based on the Attribute Type Code
242 + //
243 + switch (attrTypeCode) {
244 +
245 + case BgpConstants.Update.Origin.TYPE:
246 + // Attribute Type Code ORIGIN
247 + origin = parseAttributeTypeOrigin(bgpSession, ctx,
248 + attrTypeCode, attrLen,
249 + attrFlags, message);
250 + break;
251 +
252 + case BgpConstants.Update.AsPath.TYPE:
253 + // Attribute Type Code AS_PATH
254 + asPath = parseAttributeTypeAsPath(bgpSession, ctx,
255 + attrTypeCode, attrLen,
256 + attrFlags, message);
257 + break;
258 +
259 + case BgpConstants.Update.NextHop.TYPE:
260 + // Attribute Type Code NEXT_HOP
261 + nextHop = parseAttributeTypeNextHop(bgpSession, ctx,
262 + attrTypeCode, attrLen,
263 + attrFlags, message);
264 + break;
265 +
266 + case BgpConstants.Update.MultiExitDisc.TYPE:
267 + // Attribute Type Code MULTI_EXIT_DISC
268 + multiExitDisc =
269 + parseAttributeTypeMultiExitDisc(bgpSession, ctx,
270 + attrTypeCode, attrLen,
271 + attrFlags, message);
272 + break;
273 +
274 + case BgpConstants.Update.LocalPref.TYPE:
275 + // Attribute Type Code LOCAL_PREF
276 + localPref =
277 + parseAttributeTypeLocalPref(bgpSession, ctx,
278 + attrTypeCode, attrLen,
279 + attrFlags, message);
280 + break;
281 +
282 + case BgpConstants.Update.AtomicAggregate.TYPE:
283 + // Attribute Type Code ATOMIC_AGGREGATE
284 + parseAttributeTypeAtomicAggregate(bgpSession, ctx,
285 + attrTypeCode, attrLen,
286 + attrFlags, message);
287 + // Nothing to do: this attribute is primarily informational
288 + break;
289 +
290 + case BgpConstants.Update.Aggregator.TYPE:
291 + // Attribute Type Code AGGREGATOR
292 + Pair<Long, Ip4Address> aggregator =
293 + parseAttributeTypeAggregator(bgpSession, ctx,
294 + attrTypeCode, attrLen,
295 + attrFlags, message);
296 + aggregatorAsNumber = aggregator.getLeft();
297 + aggregatorIpAddress = aggregator.getRight();
298 + break;
299 +
300 + default:
301 + // NOTE: Parse any new Attribute Types if needed
302 + if (!optionalBit) {
303 + // ERROR: Unrecognized Well-known Attribute
304 + actionsBgpUpdateUnrecognizedWellKnownAttribute(
305 + bgpSession, ctx, attrTypeCode, attrLen, attrFlags,
306 + message);
307 + String errorMsg = "Unrecognized Well-known Attribute: " +
308 + attrTypeCode;
309 + throw new BgpParseException(errorMsg);
310 + }
311 +
312 + // Skip the data from the unrecognized attribute
313 + log.debug("BGP RX UPDATE message from {}: " +
314 + "Unrecognized Attribute Type {}",
315 + bgpSession.getRemoteAddress(), attrTypeCode);
316 + message.skipBytes(attrLen);
317 + break;
318 + }
319 + }
320 +
321 + // Verify the Well-known Attributes
322 + verifyBgpUpdateWellKnownAttributes(bgpSession, ctx, origin, asPath,
323 + nextHop, localPref);
324 +
325 + //
326 + // Parse the NLRI (Network Layer Reachability Information)
327 + //
328 + Collection<Ip4Prefix> addedPrefixes = null;
329 + int nlriLength = message.readableBytes();
330 + try {
331 + addedPrefixes = parsePackedPrefixes(nlriLength, message);
332 + } catch (BgpParseException e) {
333 + // ERROR: Invalid Network Field
334 + log.debug("Exception parsing NLRI from BGP peer {}: ",
335 + bgpSession.getRemoteBgpId(), e);
336 + actionsBgpUpdateInvalidNetworkField(bgpSession, ctx);
337 + // Rethrow the exception
338 + throw e;
339 + }
340 +
341 + // Generate the added routes
342 + for (Ip4Prefix prefix : addedPrefixes) {
343 + BgpRouteEntry bgpRouteEntry =
344 + new BgpRouteEntry(bgpSession, prefix, nextHop,
345 + origin.byteValue(), asPath, localPref);
346 + bgpRouteEntry.setMultiExitDisc(multiExitDisc);
347 + if (bgpRouteEntry.hasAsPathLoop(bgpSession.getLocalAs())) {
348 + log.debug("BGP RX UPDATE message IGNORED from {}: {} " +
349 + "nextHop {}: contains AS Path loop",
350 + bgpSession.getRemoteAddress(), prefix, nextHop);
351 + continue;
352 + } else {
353 + log.debug("BGP RX UPDATE message ADDED from {}: {} nextHop {}",
354 + bgpSession.getRemoteAddress(), prefix, nextHop);
355 + }
356 + addedRoutes.put(prefix, bgpRouteEntry);
357 + }
358 +
359 + return addedRoutes.values();
360 + }
361 +
362 + /**
363 + * Verifies BGP UPDATE Well-known Attributes.
364 + *
365 + * @param bgpSession the BGP Session to use
366 + * @param ctx the Channel Handler Context
367 + * @param origin the ORIGIN well-known mandatory attribute
368 + * @param asPath the AS_PATH well-known mandatory attribute
369 + * @param nextHop the NEXT_HOP well-known mandatory attribute
370 + * @param localPref the LOCAL_PREF required attribute
371 + * @throws BgpParseException
372 + */
373 + private static void verifyBgpUpdateWellKnownAttributes(
374 + BgpSession bgpSession,
375 + ChannelHandlerContext ctx,
376 + Short origin,
377 + BgpRouteEntry.AsPath asPath,
378 + Ip4Address nextHop,
379 + Long localPref)
380 + throws BgpParseException {
381 + //
382 + // Check for Missing Well-known Attributes
383 + //
384 + if ((origin == null) || (origin == -1)) {
385 + // Missing Attribute Type Code ORIGIN
386 + int type = BgpConstants.Update.Origin.TYPE;
387 + actionsBgpUpdateMissingWellKnownAttribute(bgpSession, ctx, type);
388 + String errorMsg = "Missing Well-known Attribute: ORIGIN";
389 + throw new BgpParseException(errorMsg);
390 + }
391 + if (asPath == null) {
392 + // Missing Attribute Type Code AS_PATH
393 + int type = BgpConstants.Update.AsPath.TYPE;
394 + actionsBgpUpdateMissingWellKnownAttribute(bgpSession, ctx, type);
395 + String errorMsg = "Missing Well-known Attribute: AS_PATH";
396 + throw new BgpParseException(errorMsg);
397 + }
398 + if (nextHop == null) {
399 + // Missing Attribute Type Code NEXT_HOP
400 + int type = BgpConstants.Update.NextHop.TYPE;
401 + actionsBgpUpdateMissingWellKnownAttribute(bgpSession, ctx, type);
402 + String errorMsg = "Missing Well-known Attribute: NEXT_HOP";
403 + throw new BgpParseException(errorMsg);
404 + }
405 + if (localPref == null) {
406 + // Missing Attribute Type Code LOCAL_PREF
407 + // NOTE: Required for iBGP
408 + int type = BgpConstants.Update.LocalPref.TYPE;
409 + actionsBgpUpdateMissingWellKnownAttribute(bgpSession, ctx, type);
410 + String errorMsg = "Missing Well-known Attribute: LOCAL_PREF";
411 + throw new BgpParseException(errorMsg);
412 + }
413 + }
414 +
415 + /**
416 + * Verifies the BGP UPDATE Attribute Flags.
417 + *
418 + * @param bgpSession the BGP Session to use
419 + * @param ctx the Channel Handler Context
420 + * @param attrTypeCode the attribute type code
421 + * @param attrLen the attribute length (in octets)
422 + * @param attrFlags the attribute flags
423 + * @param message the message to parse
424 + * @throws BgpParseException
425 + */
426 + private static void verifyBgpUpdateAttributeFlags(
427 + BgpSession bgpSession,
428 + ChannelHandlerContext ctx,
429 + int attrTypeCode,
430 + int attrLen,
431 + int attrFlags,
432 + ChannelBuffer message)
433 + throws BgpParseException {
434 +
435 + //
436 + // Assign the Attribute Type Name and the Well-known flag
437 + //
438 + String typeName = "UNKNOWN";
439 + boolean isWellKnown = false;
440 + switch (attrTypeCode) {
441 + case BgpConstants.Update.Origin.TYPE:
442 + isWellKnown = true;
443 + typeName = "ORIGIN";
444 + break;
445 + case BgpConstants.Update.AsPath.TYPE:
446 + isWellKnown = true;
447 + typeName = "AS_PATH";
448 + break;
449 + case BgpConstants.Update.NextHop.TYPE:
450 + isWellKnown = true;
451 + typeName = "NEXT_HOP";
452 + break;
453 + case BgpConstants.Update.MultiExitDisc.TYPE:
454 + isWellKnown = false;
455 + typeName = "MULTI_EXIT_DISC";
456 + break;
457 + case BgpConstants.Update.LocalPref.TYPE:
458 + isWellKnown = true;
459 + typeName = "LOCAL_PREF";
460 + break;
461 + case BgpConstants.Update.AtomicAggregate.TYPE:
462 + isWellKnown = true;
463 + typeName = "ATOMIC_AGGREGATE";
464 + break;
465 + case BgpConstants.Update.Aggregator.TYPE:
466 + isWellKnown = false;
467 + typeName = "AGGREGATOR";
468 + break;
469 + default:
470 + isWellKnown = false;
471 + typeName = "UNKNOWN(" + attrTypeCode + ")";
472 + break;
473 + }
474 +
475 + //
476 + // Verify the Attribute Flags
477 + //
478 + boolean optionalBit = ((0x80 & attrFlags) != 0);
479 + boolean transitiveBit = ((0x40 & attrFlags) != 0);
480 + boolean partialBit = ((0x20 & attrFlags) != 0);
481 + if ((isWellKnown && optionalBit) ||
482 + (isWellKnown && (!transitiveBit)) ||
483 + (isWellKnown && partialBit) ||
484 + (optionalBit && (!transitiveBit) && partialBit)) {
485 + //
486 + // ERROR: The Optional bit cannot be set for Well-known attributes
487 + // ERROR: The Transtive bit MUST be 1 for well-known attributes
488 + // ERROR: The Partial bit MUST be 0 for well-known attributes
489 + // ERROR: The Partial bit MUST be 0 for optional non-transitive
490 + // attributes
491 + //
492 + actionsBgpUpdateAttributeFlagsError(
493 + bgpSession, ctx, attrTypeCode, attrLen, attrFlags, message);
494 + String errorMsg = "Attribute Flags Error for " + typeName + ": " +
495 + attrFlags;
496 + throw new BgpParseException(errorMsg);
497 + }
498 + }
499 +
500 + /**
501 + * Parses BGP UPDATE Attribute Type ORIGIN.
502 + *
503 + * @param bgpSession the BGP Session to use
504 + * @param ctx the Channel Handler Context
505 + * @param attrTypeCode the attribute type code
506 + * @param attrLen the attribute length (in octets)
507 + * @param attrFlags the attribute flags
508 + * @param message the message to parse
509 + * @return the parsed ORIGIN value
510 + * @throws BgpParseException
511 + */
512 + private static short parseAttributeTypeOrigin(
513 + BgpSession bgpSession,
514 + ChannelHandlerContext ctx,
515 + int attrTypeCode,
516 + int attrLen,
517 + int attrFlags,
518 + ChannelBuffer message)
519 + throws BgpParseException {
520 +
521 + // Check the Attribute Length
522 + if (attrLen != BgpConstants.Update.Origin.LENGTH) {
523 + // ERROR: Attribute Length Error
524 + actionsBgpUpdateAttributeLengthError(
525 + bgpSession, ctx, attrTypeCode, attrLen, attrFlags, message);
526 + String errorMsg = "Attribute Length Error";
527 + throw new BgpParseException(errorMsg);
528 + }
529 +
530 + message.markReaderIndex();
531 + short origin = message.readUnsignedByte();
532 + switch (origin) {
533 + case BgpConstants.Update.Origin.IGP:
534 + // FALLTHROUGH
535 + case BgpConstants.Update.Origin.EGP:
536 + // FALLTHROUGH
537 + case BgpConstants.Update.Origin.INCOMPLETE:
538 + break;
539 + default:
540 + // ERROR: Invalid ORIGIN Attribute
541 + message.resetReaderIndex();
542 + actionsBgpUpdateInvalidOriginAttribute(
543 + bgpSession, ctx, attrTypeCode, attrLen, attrFlags, message,
544 + origin);
545 + String errorMsg = "Invalid ORIGIN Attribute: " + origin;
546 + throw new BgpParseException(errorMsg);
547 + }
548 +
549 + return origin;
550 + }
551 +
552 + /**
553 + * Parses BGP UPDATE Attribute AS Path.
554 + *
555 + * @param bgpSession the BGP Session to use
556 + * @param ctx the Channel Handler Context
557 + * @param attrTypeCode the attribute type code
558 + * @param attrLen the attribute length (in octets)
559 + * @param attrFlags the attribute flags
560 + * @param message the message to parse
561 + * @return the parsed AS Path
562 + * @throws BgpParseException
563 + */
564 + private static BgpRouteEntry.AsPath parseAttributeTypeAsPath(
565 + BgpSession bgpSession,
566 + ChannelHandlerContext ctx,
567 + int attrTypeCode,
568 + int attrLen,
569 + int attrFlags,
570 + ChannelBuffer message)
571 + throws BgpParseException {
572 + ArrayList<BgpRouteEntry.PathSegment> pathSegments = new ArrayList<>();
573 +
574 + //
575 + // Parse the message
576 + //
577 + while (attrLen > 0) {
578 + if (attrLen < 2) {
579 + // ERROR: Malformed AS_PATH
580 + actionsBgpUpdateMalformedAsPath(bgpSession, ctx);
581 + String errorMsg = "Malformed AS Path";
582 + throw new BgpParseException(errorMsg);
583 + }
584 + // Get the Path Segment Type and Length (in number of ASes)
585 + short pathSegmentType = message.readUnsignedByte();
586 + short pathSegmentLength = message.readUnsignedByte();
587 + attrLen -= 2;
588 +
589 + // Verify the Path Segment Type
590 + switch (pathSegmentType) {
591 + case BgpConstants.Update.AsPath.AS_SET:
592 + // FALLTHROUGH
593 + case BgpConstants.Update.AsPath.AS_SEQUENCE:
594 + // FALLTHROUGH
595 + case BgpConstants.Update.AsPath.AS_CONFED_SEQUENCE:
596 + // FALLTHROUGH
597 + case BgpConstants.Update.AsPath.AS_CONFED_SET:
598 + break;
599 + default:
600 + // ERROR: Invalid Path Segment Type
601 + //
602 + // NOTE: The BGP Spec (RFC 4271) doesn't contain Error Subcode
603 + // for "Invalid Path Segment Type", hence we return
604 + // the error as "Malformed AS_PATH".
605 + //
606 + actionsBgpUpdateMalformedAsPath(bgpSession, ctx);
607 + String errorMsg =
608 + "Invalid AS Path Segment Type: " + pathSegmentType;
609 + throw new BgpParseException(errorMsg);
610 + }
611 +
612 + // Parse the AS numbers
613 + if (2 * pathSegmentLength > attrLen) {
614 + // ERROR: Malformed AS_PATH
615 + actionsBgpUpdateMalformedAsPath(bgpSession, ctx);
616 + String errorMsg = "Malformed AS Path";
617 + throw new BgpParseException(errorMsg);
618 + }
619 + attrLen -= (2 * pathSegmentLength);
620 + ArrayList<Long> segmentAsNumbers = new ArrayList<>();
621 + while (pathSegmentLength-- > 0) {
622 + long asNumber = message.readUnsignedShort();
623 + segmentAsNumbers.add(asNumber);
624 + }
625 +
626 + BgpRouteEntry.PathSegment pathSegment =
627 + new BgpRouteEntry.PathSegment((byte) pathSegmentType,
628 + segmentAsNumbers);
629 + pathSegments.add(pathSegment);
630 + }
631 +
632 + return new BgpRouteEntry.AsPath(pathSegments);
633 + }
634 +
635 + /**
636 + * Parses BGP UPDATE Attribute Type NEXT_HOP.
637 + *
638 + * @param bgpSession the BGP Session to use
639 + * @param ctx the Channel Handler Context
640 + * @param attrTypeCode the attribute type code
641 + * @param attrLen the attribute length (in octets)
642 + * @param attrFlags the attribute flags
643 + * @param message the message to parse
644 + * @return the parsed NEXT_HOP value
645 + * @throws BgpParseException
646 + */
647 + private static Ip4Address parseAttributeTypeNextHop(
648 + BgpSession bgpSession,
649 + ChannelHandlerContext ctx,
650 + int attrTypeCode,
651 + int attrLen,
652 + int attrFlags,
653 + ChannelBuffer message)
654 + throws BgpParseException {
655 +
656 + // Check the Attribute Length
657 + if (attrLen != BgpConstants.Update.NextHop.LENGTH) {
658 + // ERROR: Attribute Length Error
659 + actionsBgpUpdateAttributeLengthError(
660 + bgpSession, ctx, attrTypeCode, attrLen, attrFlags, message);
661 + String errorMsg = "Attribute Length Error";
662 + throw new BgpParseException(errorMsg);
663 + }
664 +
665 + message.markReaderIndex();
666 + Ip4Address nextHopAddress =
667 + Ip4Address.valueOf((int) message.readUnsignedInt());
668 + //
669 + // Check whether the NEXT_HOP IP address is semantically correct.
670 + // As per RFC 4271, Section 6.3:
671 + //
672 + // a) It MUST NOT be the IP address of the receiving speaker
673 + // b) In the case of an EBGP ....
674 + //
675 + // Here we check only (a), because (b) doesn't apply for us: all our
676 + // peers are iBGP.
677 + //
678 + if (nextHopAddress.equals(bgpSession.getLocalIp4Address())) {
679 + // ERROR: Invalid NEXT_HOP Attribute
680 + message.resetReaderIndex();
681 + actionsBgpUpdateInvalidNextHopAttribute(
682 + bgpSession, ctx, attrTypeCode, attrLen, attrFlags, message,
683 + nextHopAddress);
684 + String errorMsg = "Invalid NEXT_HOP Attribute: " + nextHopAddress;
685 + throw new BgpParseException(errorMsg);
686 + }
687 +
688 + return nextHopAddress;
689 + }
690 +
691 + /**
692 + * Parses BGP UPDATE Attribute Type MULTI_EXIT_DISC.
693 + *
694 + * @param bgpSession the BGP Session to use
695 + * @param ctx the Channel Handler Context
696 + * @param attrTypeCode the attribute type code
697 + * @param attrLen the attribute length (in octets)
698 + * @param attrFlags the attribute flags
699 + * @param message the message to parse
700 + * @return the parsed MULTI_EXIT_DISC value
701 + * @throws BgpParseException
702 + */
703 + private static long parseAttributeTypeMultiExitDisc(
704 + BgpSession bgpSession,
705 + ChannelHandlerContext ctx,
706 + int attrTypeCode,
707 + int attrLen,
708 + int attrFlags,
709 + ChannelBuffer message)
710 + throws BgpParseException {
711 +
712 + // Check the Attribute Length
713 + if (attrLen != BgpConstants.Update.MultiExitDisc.LENGTH) {
714 + // ERROR: Attribute Length Error
715 + actionsBgpUpdateAttributeLengthError(
716 + bgpSession, ctx, attrTypeCode, attrLen, attrFlags, message);
717 + String errorMsg = "Attribute Length Error";
718 + throw new BgpParseException(errorMsg);
719 + }
720 +
721 + long multiExitDisc = message.readUnsignedInt();
722 + return multiExitDisc;
723 + }
724 +
725 + /**
726 + * Parses BGP UPDATE Attribute Type LOCAL_PREF.
727 + *
728 + * @param bgpSession the BGP Session to use
729 + * @param ctx the Channel Handler Context
730 + * @param attrTypeCode the attribute type code
731 + * @param attrLen the attribute length (in octets)
732 + * @param attrFlags the attribute flags
733 + * @param message the message to parse
734 + * @return the parsed LOCAL_PREF value
735 + * @throws BgpParseException
736 + */
737 + private static long parseAttributeTypeLocalPref(
738 + BgpSession bgpSession,
739 + ChannelHandlerContext ctx,
740 + int attrTypeCode,
741 + int attrLen,
742 + int attrFlags,
743 + ChannelBuffer message)
744 + throws BgpParseException {
745 +
746 + // Check the Attribute Length
747 + if (attrLen != BgpConstants.Update.LocalPref.LENGTH) {
748 + // ERROR: Attribute Length Error
749 + actionsBgpUpdateAttributeLengthError(
750 + bgpSession, ctx, attrTypeCode, attrLen, attrFlags, message);
751 + String errorMsg = "Attribute Length Error";
752 + throw new BgpParseException(errorMsg);
753 + }
754 +
755 + long localPref = message.readUnsignedInt();
756 + return localPref;
757 + }
758 +
759 + /**
760 + * Parses BGP UPDATE Attribute Type ATOMIC_AGGREGATE.
761 + *
762 + * @param bgpSession the BGP Session to use
763 + * @param ctx the Channel Handler Context
764 + * @param attrTypeCode the attribute type code
765 + * @param attrLen the attribute length (in octets)
766 + * @param attrFlags the attribute flags
767 + * @param message the message to parse
768 + * @throws BgpParseException
769 + */
770 + private static void parseAttributeTypeAtomicAggregate(
771 + BgpSession bgpSession,
772 + ChannelHandlerContext ctx,
773 + int attrTypeCode,
774 + int attrLen,
775 + int attrFlags,
776 + ChannelBuffer message)
777 + throws BgpParseException {
778 +
779 + // Check the Attribute Length
780 + if (attrLen != BgpConstants.Update.AtomicAggregate.LENGTH) {
781 + // ERROR: Attribute Length Error
782 + actionsBgpUpdateAttributeLengthError(
783 + bgpSession, ctx, attrTypeCode, attrLen, attrFlags, message);
784 + String errorMsg = "Attribute Length Error";
785 + throw new BgpParseException(errorMsg);
786 + }
787 +
788 + // Nothing to do: this attribute is primarily informational
789 + }
790 +
791 + /**
792 + * Parses BGP UPDATE Attribute Type AGGREGATOR.
793 + *
794 + * @param bgpSession the BGP Session to use
795 + * @param ctx the Channel Handler Context
796 + * @param attrTypeCode the attribute type code
797 + * @param attrLen the attribute length (in octets)
798 + * @param attrFlags the attribute flags
799 + * @param message the message to parse
800 + * @return the parsed AGGREGATOR value: a tuple of <AS-Number, IP-Address>
801 + * @throws BgpParseException
802 + */
803 + private static Pair<Long, Ip4Address> parseAttributeTypeAggregator(
804 + BgpSession bgpSession,
805 + ChannelHandlerContext ctx,
806 + int attrTypeCode,
807 + int attrLen,
808 + int attrFlags,
809 + ChannelBuffer message)
810 + throws BgpParseException {
811 +
812 + // Check the Attribute Length
813 + if (attrLen != BgpConstants.Update.Aggregator.LENGTH) {
814 + // ERROR: Attribute Length Error
815 + actionsBgpUpdateAttributeLengthError(
816 + bgpSession, ctx, attrTypeCode, attrLen, attrFlags, message);
817 + String errorMsg = "Attribute Length Error";
818 + throw new BgpParseException(errorMsg);
819 + }
820 +
821 + // The AGGREGATOR AS number
822 + long aggregatorAsNumber = message.readUnsignedShort();
823 + // The AGGREGATOR IP address
824 + Ip4Address aggregatorIpAddress =
825 + Ip4Address.valueOf((int) message.readUnsignedInt());
826 +
827 + Pair<Long, Ip4Address> aggregator = Pair.of(aggregatorAsNumber,
828 + aggregatorIpAddress);
829 + return aggregator;
830 + }
831 +
832 + /**
833 + * Parses a message that contains encoded IPv4 network prefixes.
834 + * <p>
835 + * The IPv4 prefixes are encoded in the form:
836 + * <Length, Prefix> where Length is the length in bits of the IPv4 prefix,
837 + * and Prefix is the IPv4 prefix (padded with trailing bits to the end
838 + * of an octet).
839 + *
840 + * @param totalLength the total length of the data to parse
841 + * @param message the message with data to parse
842 + * @return a collection of parsed IPv4 network prefixes
843 + * @throws BgpParseException
844 + */
845 + private static Collection<Ip4Prefix> parsePackedPrefixes(
846 + int totalLength,
847 + ChannelBuffer message)
848 + throws BgpParseException {
849 + Collection<Ip4Prefix> result = new ArrayList<>();
850 +
851 + if (totalLength == 0) {
852 + return result;
853 + }
854 +
855 + // Parse the data
856 + int dataEnd = message.readerIndex() + totalLength;
857 + while (message.readerIndex() < dataEnd) {
858 + int prefixBitlen = message.readUnsignedByte();
859 + int prefixBytelen = (prefixBitlen + 7) / 8; // Round-up
860 + if (message.readerIndex() + prefixBytelen > dataEnd) {
861 + String errorMsg = "Malformed Network Prefixes";
862 + throw new BgpParseException(errorMsg);
863 + }
864 +
865 + long address = 0;
866 + long extraShift = (4 - prefixBytelen) * 8;
867 + while (prefixBytelen > 0) {
868 + address <<= 8;
869 + address |= message.readUnsignedByte();
870 + prefixBytelen--;
871 + }
872 + address <<= extraShift;
873 + Ip4Prefix prefix =
874 + Ip4Prefix.valueOf(Ip4Address.valueOf((int) address),
875 + prefixBitlen);
876 + result.add(prefix);
877 + }
878 +
879 + return result;
880 + }
881 +
882 + /**
883 + * Applies the appropriate actions after detecting BGP UPDATE
884 + * Invalid Network Field Error: send NOTIFICATION and close the channel.
885 + *
886 + * @param bgpSession the BGP Session to use
887 + * @param ctx the Channel Handler Context
888 + */
889 + private static void actionsBgpUpdateInvalidNetworkField(
890 + BgpSession bgpSession,
891 + ChannelHandlerContext ctx) {
892 + log.debug("BGP RX UPDATE Error from {}: Invalid Network Field",
893 + bgpSession.getRemoteAddress());
894 +
895 + //
896 + // ERROR: Invalid Network Field
897 + //
898 + // Send NOTIFICATION and close the connection
899 + int errorCode = UpdateMessageError.ERROR_CODE;
900 + int errorSubcode = UpdateMessageError.INVALID_NETWORK_FIELD;
901 + ChannelBuffer txMessage =
902 + BgpNotification.prepareBgpNotification(errorCode, errorSubcode,
903 + null);
904 + ctx.getChannel().write(txMessage);
905 + bgpSession.closeSession(ctx);
906 + }
907 +
908 + /**
909 + * Applies the appropriate actions after detecting BGP UPDATE
910 + * Malformed Attribute List Error: send NOTIFICATION and close the channel.
911 + *
912 + * @param bgpSession the BGP Session to use
913 + * @param ctx the Channel Handler Context
914 + */
915 + private static void actionsBgpUpdateMalformedAttributeList(
916 + BgpSession bgpSession,
917 + ChannelHandlerContext ctx) {
918 + log.debug("BGP RX UPDATE Error from {}: Malformed Attribute List",
919 + bgpSession.getRemoteAddress());
920 +
921 + //
922 + // ERROR: Malformed Attribute List
923 + //
924 + // Send NOTIFICATION and close the connection
925 + int errorCode = UpdateMessageError.ERROR_CODE;
926 + int errorSubcode = UpdateMessageError.MALFORMED_ATTRIBUTE_LIST;
927 + ChannelBuffer txMessage =
928 + BgpNotification.prepareBgpNotification(errorCode, errorSubcode,
929 + null);
930 + ctx.getChannel().write(txMessage);
931 + bgpSession.closeSession(ctx);
932 + }
933 +
934 + /**
935 + * Applies the appropriate actions after detecting BGP UPDATE
936 + * Missing Well-known Attribute Error: send NOTIFICATION and close the
937 + * channel.
938 + *
939 + * @param bgpSession the BGP Session to use
940 + * @param ctx the Channel Handler Context
941 + * @param missingAttrTypeCode the missing attribute type code
942 + */
943 + private static void actionsBgpUpdateMissingWellKnownAttribute(
944 + BgpSession bgpSession,
945 + ChannelHandlerContext ctx,
946 + int missingAttrTypeCode) {
947 + log.debug("BGP RX UPDATE Error from {}: Missing Well-known Attribute: {}",
948 + bgpSession.getRemoteAddress(), missingAttrTypeCode);
949 +
950 + //
951 + // ERROR: Missing Well-known Attribute
952 + //
953 + // Send NOTIFICATION and close the connection
954 + int errorCode = UpdateMessageError.ERROR_CODE;
955 + int errorSubcode = UpdateMessageError.MISSING_WELL_KNOWN_ATTRIBUTE;
956 + ChannelBuffer data = ChannelBuffers.buffer(1);
957 + data.writeByte(missingAttrTypeCode);
958 + ChannelBuffer txMessage =
959 + BgpNotification.prepareBgpNotification(errorCode, errorSubcode,
960 + data);
961 + ctx.getChannel().write(txMessage);
962 + bgpSession.closeSession(ctx);
963 + }
964 +
965 + /**
966 + * Applies the appropriate actions after detecting BGP UPDATE
967 + * Invalid ORIGIN Attribute Error: send NOTIFICATION and close the channel.
968 + *
969 + * @param bgpSession the BGP Session to use
970 + * @param ctx the Channel Handler Context
971 + * @param attrTypeCode the attribute type code
972 + * @param attrLen the attribute length (in octets)
973 + * @param attrFlags the attribute flags
974 + * @param message the message with the data
975 + * @param origin the ORIGIN attribute value
976 + */
977 + private static void actionsBgpUpdateInvalidOriginAttribute(
978 + BgpSession bgpSession,
979 + ChannelHandlerContext ctx,
980 + int attrTypeCode,
981 + int attrLen,
982 + int attrFlags,
983 + ChannelBuffer message,
984 + short origin) {
985 + log.debug("BGP RX UPDATE Error from {}: Invalid ORIGIN Attribute",
986 + bgpSession.getRemoteAddress());
987 +
988 + //
989 + // ERROR: Invalid ORIGIN Attribute
990 + //
991 + // Send NOTIFICATION and close the connection
992 + int errorCode = UpdateMessageError.ERROR_CODE;
993 + int errorSubcode = UpdateMessageError.INVALID_ORIGIN_ATTRIBUTE;
994 + ChannelBuffer data =
995 + prepareBgpUpdateNotificationDataPayload(attrTypeCode, attrLen,
996 + attrFlags, message);
997 + ChannelBuffer txMessage =
998 + BgpNotification.prepareBgpNotification(errorCode, errorSubcode,
999 + data);
1000 + ctx.getChannel().write(txMessage);
1001 + bgpSession.closeSession(ctx);
1002 + }
1003 +
1004 + /**
1005 + * Applies the appropriate actions after detecting BGP UPDATE
1006 + * Attribute Flags Error: send NOTIFICATION and close the channel.
1007 + *
1008 + * @param bgpSession the BGP Session to use
1009 + * @param ctx the Channel Handler Context
1010 + * @param attrTypeCode the attribute type code
1011 + * @param attrLen the attribute length (in octets)
1012 + * @param attrFlags the attribute flags
1013 + * @param message the message with the data
1014 + */
1015 + private static void actionsBgpUpdateAttributeFlagsError(
1016 + BgpSession bgpSession,
1017 + ChannelHandlerContext ctx,
1018 + int attrTypeCode,
1019 + int attrLen,
1020 + int attrFlags,
1021 + ChannelBuffer message) {
1022 + log.debug("BGP RX UPDATE Error from {}: Attribute Flags Error",
1023 + bgpSession.getRemoteAddress());
1024 +
1025 + //
1026 + // ERROR: Attribute Flags Error
1027 + //
1028 + // Send NOTIFICATION and close the connection
1029 + int errorCode = UpdateMessageError.ERROR_CODE;
1030 + int errorSubcode = UpdateMessageError.ATTRIBUTE_FLAGS_ERROR;
1031 + ChannelBuffer data =
1032 + prepareBgpUpdateNotificationDataPayload(attrTypeCode, attrLen,
1033 + attrFlags, message);
1034 + ChannelBuffer txMessage =
1035 + BgpNotification.prepareBgpNotification(errorCode, errorSubcode,
1036 + data);
1037 + ctx.getChannel().write(txMessage);
1038 + bgpSession.closeSession(ctx);
1039 + }
1040 +
1041 + /**
1042 + * Applies the appropriate actions after detecting BGP UPDATE
1043 + * Invalid NEXT_HOP Attribute Error: send NOTIFICATION and close the
1044 + * channel.
1045 + *
1046 + * @param bgpSession the BGP Session to use
1047 + * @param ctx the Channel Handler Context
1048 + * @param attrTypeCode the attribute type code
1049 + * @param attrLen the attribute length (in octets)
1050 + * @param attrFlags the attribute flags
1051 + * @param message the message with the data
1052 + * @param nextHop the NEXT_HOP attribute value
1053 + */
1054 + private static void actionsBgpUpdateInvalidNextHopAttribute(
1055 + BgpSession bgpSession,
1056 + ChannelHandlerContext ctx,
1057 + int attrTypeCode,
1058 + int attrLen,
1059 + int attrFlags,
1060 + ChannelBuffer message,
1061 + Ip4Address nextHop) {
1062 + log.debug("BGP RX UPDATE Error from {}: Invalid NEXT_HOP Attribute {}",
1063 + bgpSession.getRemoteAddress(), nextHop);
1064 +
1065 + //
1066 + // ERROR: Invalid ORIGIN Attribute
1067 + //
1068 + // Send NOTIFICATION and close the connection
1069 + int errorCode = UpdateMessageError.ERROR_CODE;
1070 + int errorSubcode = UpdateMessageError.INVALID_NEXT_HOP_ATTRIBUTE;
1071 + ChannelBuffer data =
1072 + prepareBgpUpdateNotificationDataPayload(attrTypeCode, attrLen,
1073 + attrFlags, message);
1074 + ChannelBuffer txMessage =
1075 + BgpNotification.prepareBgpNotification(errorCode, errorSubcode,
1076 + data);
1077 + ctx.getChannel().write(txMessage);
1078 + bgpSession.closeSession(ctx);
1079 + }
1080 +
1081 + /**
1082 + * Applies the appropriate actions after detecting BGP UPDATE
1083 + * Unrecognized Well-known Attribute Error: send NOTIFICATION and close
1084 + * the channel.
1085 + *
1086 + * @param bgpSession the BGP Session to use
1087 + * @param ctx the Channel Handler Context
1088 + * @param attrTypeCode the attribute type code
1089 + * @param attrLen the attribute length (in octets)
1090 + * @param attrFlags the attribute flags
1091 + * @param message the message with the data
1092 + */
1093 + private static void actionsBgpUpdateUnrecognizedWellKnownAttribute(
1094 + BgpSession bgpSession,
1095 + ChannelHandlerContext ctx,
1096 + int attrTypeCode,
1097 + int attrLen,
1098 + int attrFlags,
1099 + ChannelBuffer message) {
1100 + log.debug("BGP RX UPDATE Error from {}: " +
1101 + "Unrecognized Well-known Attribute Error: {}",
1102 + bgpSession.getRemoteAddress(), attrTypeCode);
1103 +
1104 + //
1105 + // ERROR: Unrecognized Well-known Attribute
1106 + //
1107 + // Send NOTIFICATION and close the connection
1108 + int errorCode = UpdateMessageError.ERROR_CODE;
1109 + int errorSubcode =
1110 + UpdateMessageError.UNRECOGNIZED_WELL_KNOWN_ATTRIBUTE;
1111 + ChannelBuffer data =
1112 + prepareBgpUpdateNotificationDataPayload(attrTypeCode, attrLen,
1113 + attrFlags, message);
1114 + ChannelBuffer txMessage =
1115 + BgpNotification.prepareBgpNotification(errorCode, errorSubcode,
1116 + data);
1117 + ctx.getChannel().write(txMessage);
1118 + bgpSession.closeSession(ctx);
1119 + }
1120 +
1121 + /**
1122 + * Applies the appropriate actions after detecting BGP UPDATE
1123 + * Attribute Length Error: send NOTIFICATION and close the channel.
1124 + *
1125 + * @param bgpSession the BGP Session to use
1126 + * @param ctx the Channel Handler Context
1127 + * @param attrTypeCode the attribute type code
1128 + * @param attrLen the attribute length (in octets)
1129 + * @param attrFlags the attribute flags
1130 + * @param message the message with the data
1131 + */
1132 + private static void actionsBgpUpdateAttributeLengthError(
1133 + BgpSession bgpSession,
1134 + ChannelHandlerContext ctx,
1135 + int attrTypeCode,
1136 + int attrLen,
1137 + int attrFlags,
1138 + ChannelBuffer message) {
1139 + log.debug("BGP RX UPDATE Error from {}: Attribute Length Error",
1140 + bgpSession.getRemoteAddress());
1141 +
1142 + //
1143 + // ERROR: Attribute Length Error
1144 + //
1145 + // Send NOTIFICATION and close the connection
1146 + int errorCode = UpdateMessageError.ERROR_CODE;
1147 + int errorSubcode = UpdateMessageError.ATTRIBUTE_LENGTH_ERROR;
1148 + ChannelBuffer data =
1149 + prepareBgpUpdateNotificationDataPayload(attrTypeCode, attrLen,
1150 + attrFlags, message);
1151 + ChannelBuffer txMessage =
1152 + BgpNotification.prepareBgpNotification(errorCode, errorSubcode,
1153 + data);
1154 + ctx.getChannel().write(txMessage);
1155 + bgpSession.closeSession(ctx);
1156 + }
1157 +
1158 + /**
1159 + * Applies the appropriate actions after detecting BGP UPDATE
1160 + * Malformed AS_PATH Error: send NOTIFICATION and close the channel.
1161 + *
1162 + * @param bgpSession the BGP Session to use
1163 + * @param ctx the Channel Handler Context
1164 + */
1165 + private static void actionsBgpUpdateMalformedAsPath(
1166 + BgpSession bgpSession,
1167 + ChannelHandlerContext ctx) {
1168 + log.debug("BGP RX UPDATE Error from {}: Malformed AS Path",
1169 + bgpSession.getRemoteAddress());
1170 +
1171 + //
1172 + // ERROR: Malformed AS_PATH
1173 + //
1174 + // Send NOTIFICATION and close the connection
1175 + int errorCode = UpdateMessageError.ERROR_CODE;
1176 + int errorSubcode = UpdateMessageError.MALFORMED_AS_PATH;
1177 + ChannelBuffer txMessage =
1178 + BgpNotification.prepareBgpNotification(errorCode, errorSubcode,
1179 + null);
1180 + ctx.getChannel().write(txMessage);
1181 + bgpSession.closeSession(ctx);
1182 + }
1183 +
1184 + /**
1185 + * Prepares BGP UPDATE Notification data payload.
1186 + *
1187 + * @param attrTypeCode the attribute type code
1188 + * @param attrLen the attribute length (in octets)
1189 + * @param attrFlags the attribute flags
1190 + * @param message the message with the data
1191 + * @return the buffer with the data payload for the BGP UPDATE Notification
1192 + */
1193 + private static ChannelBuffer prepareBgpUpdateNotificationDataPayload(
1194 + int attrTypeCode,
1195 + int attrLen,
1196 + int attrFlags,
1197 + ChannelBuffer message) {
1198 + // Compute the attribute length field octets
1199 + boolean extendedLengthBit = ((0x10 & attrFlags) != 0);
1200 + int attrLenOctets = 1;
1201 + if (extendedLengthBit) {
1202 + attrLenOctets = 2;
1203 + }
1204 + ChannelBuffer data =
1205 + ChannelBuffers.buffer(attrLen + attrLenOctets + 1);
1206 + data.writeByte(attrTypeCode);
1207 + if (extendedLengthBit) {
1208 + data.writeShort(attrLen);
1209 + } else {
1210 + data.writeByte(attrLen);
1211 + }
1212 + data.writeBytes(message, attrLen);
1213 + return data;
1214 + }
1215 +
1216 + /**
1217 + * An exception indicating a parsing error of the BGP message.
1218 + */
1219 + private static final class BgpParseException extends Exception {
1220 + /**
1221 + * Default constructor.
1222 + */
1223 + private BgpParseException() {
1224 + super();
1225 + }
1226 +
1227 + /**
1228 + * Constructor for a specific exception details message.
1229 + *
1230 + * @param message the message with the exception details
1231 + */
1232 + private BgpParseException(String message) {
1233 + super(message);
1234 + }
1235 + }
1236 +}
...@@ -81,7 +81,7 @@ public class BgpRoutesListCommand extends AbstractShellCommand { ...@@ -81,7 +81,7 @@ public class BgpRoutesListCommand extends AbstractShellCommand {
81 81
82 // Print the routes 82 // Print the routes
83 if (foundBgpSession != null) { 83 if (foundBgpSession != null) {
84 - printRoutes(foundBgpSession.getBgpRibIn()); 84 + printRoutes(foundBgpSession.bgpRibIn().values());
85 } else { 85 } else {
86 printRoutes(service.getBgpRoutes()); 86 printRoutes(service.getBgpRoutes());
87 } 87 }
......
...@@ -303,7 +303,7 @@ public class BgpSessionManagerTest { ...@@ -303,7 +303,7 @@ public class BgpSessionManagerTest {
303 private Collection<BgpRouteEntry> waitForBgpRibIn(BgpSession bgpSession, 303 private Collection<BgpRouteEntry> waitForBgpRibIn(BgpSession bgpSession,
304 long expectedRoutes) 304 long expectedRoutes)
305 throws InterruptedException { 305 throws InterruptedException {
306 - Collection<BgpRouteEntry> bgpRibIn = bgpSession.getBgpRibIn(); 306 + Collection<BgpRouteEntry> bgpRibIn = bgpSession.bgpRibIn().values();
307 307
308 final int maxChecks = 500; // Max wait of 5 seconds 308 final int maxChecks = 500; // Max wait of 5 seconds
309 for (int i = 0; i < maxChecks; i++) { 309 for (int i = 0; i < maxChecks; i++) {
...@@ -311,7 +311,7 @@ public class BgpSessionManagerTest { ...@@ -311,7 +311,7 @@ public class BgpSessionManagerTest {
311 break; 311 break;
312 } 312 }
313 Thread.sleep(10); 313 Thread.sleep(10);
314 - bgpRibIn = bgpSession.getBgpRibIn(); 314 + bgpRibIn = bgpSession.bgpRibIn().values();
315 } 315 }
316 316
317 return bgpRibIn; 317 return bgpRibIn;
......