Line data Source code
1 : /*
2 : * Copyright (c) 2013 Juniper Networks, Inc. All rights reserved.
3 : */
4 :
5 : #include "bgp/bgp_session.h"
6 :
7 : #include <algorithm>
8 : #include <string>
9 :
10 : #include "bgp/bgp_log.h"
11 : #include "bgp/bgp_peer.h"
12 : #include "bgp/bgp_server.h"
13 : #include "bgp/bgp_session_manager.h"
14 : #include "bgp/bgp_update_sender.h"
15 :
16 : using std::string;
17 :
18 : using boost::asio::mutable_buffer;
19 :
20 : // Extract the total BGP message length. This is a 2 byte field after the
21 : // 16 byte marker. If the buffer doesn't have 18 bytes available return -1.
22 176145 : int BgpMessageReader::MsgLength(Buffer buffer, int offset) {
23 176145 : size_t size = TcpSession::BufferSize(buffer);
24 176144 : int remain = size - offset;
25 176144 : if (remain < BgpMessageReader::kHeaderLenSize) {
26 4 : return -1;
27 : }
28 176140 : const uint8_t *data = TcpSession::BufferData(buffer) + offset;
29 176139 : data += 16;
30 176139 : int length = get_value(data, 2);
31 176141 : if (bgp_log_test::unit_test())
32 176140 : assert(length <= 4096);
33 176140 : return length;
34 : }
35 :
36 14182 : BgpMessageReader::BgpMessageReader(TcpSession *session,
37 14182 : ReceiveCallback callback)
38 14182 : : TcpMessageReader(session, callback) {
39 14176 : }
40 :
41 28368 : BgpMessageReader::~BgpMessageReader() {
42 28368 : }
43 :
44 14180 : BgpSession::BgpSession(BgpSessionManager *session_mgr, Socket *socket)
45 : : TcpSession(session_mgr, socket),
46 14183 : session_mgr_(session_mgr),
47 14183 : peer_(NULL),
48 14183 : task_instance_(-1),
49 28356 : reader_(new BgpMessageReader(this,
50 28361 : boost::bind(&BgpSession::ReceiveMsg, this, _1, _2))) {
51 14174 : }
52 :
53 27273 : BgpSession::~BgpSession() {
54 27273 : }
55 :
56 : //
57 : // Concurrency: called in the context of io::Reader task.
58 : //
59 176136 : bool BgpSession::ReceiveMsg(const u_int8_t *msg, size_t size) {
60 176136 : return (peer_ ? peer_->ReceiveMsg(this, msg, size) : false);
61 : }
62 :
63 : //
64 : // Concurrency: called in the context of bgp::Config task.
65 : //
66 : // Process write ready callback.
67 : //
68 : // 1. Tell BgpUpdateSender that the IPeer is send ready.
69 : // 2. Tell BgpPeer that it's send ready so that it can resume Keepalives.
70 : //
71 0 : void BgpSession::ProcessWriteReady() {
72 0 : if (!peer_)
73 0 : return;
74 0 : BgpServer *server = peer_->server();
75 0 : BgpUpdateSender *sender = server->update_sender();
76 0 : sender->PeerSendReady(peer_);
77 0 : peer_->SetSendReady();
78 : }
79 :
80 : //
81 : // Concurrency: called in the context of io thread.
82 : //
83 : // Handle write ready callback. Enqueue the session to a WorkQueue in the
84 : // BgpSessionManager. The WorkQueue gets processed in the context of the
85 : // bgp::Config task. This ensures that we don't access the BgpPeer while
86 : // the BgpPeer is trying to clear our back pointer to it.
87 : //
88 : // We can ignore any errors since the StateMachine will get informed of the
89 : // TcpSession close independently and react to it.
90 : //
91 0 : void BgpSession::WriteReady(const boost::system::error_code &error) {
92 0 : if (error)
93 0 : return;
94 0 : session_mgr_->EnqueueWriteReady(this);
95 : }
96 :
97 12039 : void BgpSession::LogNotification(int code, int subcode, const string &direction,
98 : const string &peer_key,
99 : const BgpProto::Notification &msg) const {
100 : // Use SYS_DEBUG for connection collision, SYS_NOTICE for the rest.
101 12039 : if (code == BgpProto::Notification::Cease &&
102 : subcode == BgpProto::Notification::ConnectionCollision) {
103 1661 : BGP_LOG(BgpPeerNotification, SandeshLevel::SYS_DEBUG, BGP_LOG_FLAG_ALL,
104 : peer_key, direction, code, subcode, msg.ToString());
105 : } else {
106 10378 : BGP_LOG(BgpPeerNotificationNotice, SandeshLevel::SYS_NOTICE,
107 : BGP_LOG_FLAG_ALL, peer_key, direction, code, subcode,
108 : msg.ToString());
109 : }
110 12039 : }
111 :
112 7331 : void BgpSession::SendNotification(int code, int subcode,
113 : const string &data) {
114 7331 : BgpProto::Notification msg;
115 7331 : msg.error = code;
116 7331 : msg.subcode = subcode;
117 7331 : msg.data = data;
118 : uint8_t buf[BgpProto::kMaxMessageSize];
119 7331 : int msglen = BgpProto::Encode(&msg, buf, sizeof(buf));
120 :
121 7330 : LogNotification(code, subcode, BGP_PEER_DIR_OUT,
122 14660 : peer_ ? peer_->ToUVEKey() : ToString(), msg);
123 7330 : if (msglen > BgpProto::kMinMessageSize) {
124 7330 : Send(buf, msglen, NULL);
125 : }
126 7331 : }
127 :
128 11056 : void BgpSession::set_peer(BgpPeer *peer) {
129 11056 : peer_ = peer;
130 11056 : task_instance_ = peer_->GetTaskInstance();
131 11056 : }
132 :
133 : //
134 : // Dissociate the peer from the this BgpSession.
135 : // Do not invalidate the task_instance since it can be used to spawn an
136 : // io::ReaderTask while this method is being executed.
137 : //
138 6188 : void BgpSession::clear_peer() {
139 6188 : peer_ = NULL;
140 6188 : }
|