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 175964 : int BgpMessageReader::MsgLength(Buffer buffer, int offset) {
23 175964 : size_t size = TcpSession::BufferSize(buffer);
24 175964 : int remain = size - offset;
25 175964 : if (remain < BgpMessageReader::kHeaderLenSize) {
26 4 : return -1;
27 : }
28 175960 : const uint8_t *data = TcpSession::BufferData(buffer) + offset;
29 175960 : data += 16;
30 175960 : int length = get_value(data, 2);
31 175958 : if (bgp_log_test::unit_test())
32 175958 : assert(length <= 4096);
33 175958 : return length;
34 : }
35 :
36 14222 : BgpMessageReader::BgpMessageReader(TcpSession *session,
37 14222 : ReceiveCallback callback)
38 14222 : : TcpMessageReader(session, callback) {
39 14213 : }
40 :
41 28448 : BgpMessageReader::~BgpMessageReader() {
42 28448 : }
43 :
44 14221 : BgpSession::BgpSession(BgpSessionManager *session_mgr, Socket *socket)
45 : : TcpSession(session_mgr, socket),
46 14224 : session_mgr_(session_mgr),
47 14224 : peer_(NULL),
48 14224 : task_instance_(-1),
49 28435 : reader_(new BgpMessageReader(this,
50 28441 : boost::bind(&BgpSession::ReceiveMsg, this, _1, _2))) {
51 14212 : }
52 :
53 27353 : BgpSession::~BgpSession() {
54 27353 : }
55 :
56 : //
57 : // Concurrency: called in the context of io::Reader task.
58 : //
59 175946 : bool BgpSession::ReceiveMsg(const u_int8_t *msg, size_t size) {
60 175946 : 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 12069 : 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 12069 : if (code == BgpProto::Notification::Cease &&
102 : subcode == BgpProto::Notification::ConnectionCollision) {
103 1683 : BGP_LOG(BgpPeerNotification, SandeshLevel::SYS_DEBUG, BGP_LOG_FLAG_ALL,
104 : peer_key, direction, code, subcode, msg.ToString());
105 : } else {
106 10386 : BGP_LOG(BgpPeerNotificationNotice, SandeshLevel::SYS_NOTICE,
107 : BGP_LOG_FLAG_ALL, peer_key, direction, code, subcode,
108 : msg.ToString());
109 : }
110 12069 : }
111 :
112 7326 : void BgpSession::SendNotification(int code, int subcode,
113 : const string &data) {
114 7326 : BgpProto::Notification msg;
115 7325 : msg.error = code;
116 7325 : msg.subcode = subcode;
117 7325 : msg.data = data;
118 : uint8_t buf[BgpProto::kMaxMessageSize];
119 7325 : int msglen = BgpProto::Encode(&msg, buf, sizeof(buf));
120 :
121 7323 : LogNotification(code, subcode, BGP_PEER_DIR_OUT,
122 14645 : peer_ ? peer_->ToUVEKey() : ToString(), msg);
123 7325 : if (msglen > BgpProto::kMinMessageSize) {
124 7325 : Send(buf, msglen, NULL);
125 : }
126 7326 : }
127 :
128 11091 : void BgpSession::set_peer(BgpPeer *peer) {
129 11091 : peer_ = peer;
130 11091 : task_instance_ = peer_->GetTaskInstance();
131 11091 : }
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 6195 : void BgpSession::clear_peer() {
139 6195 : peer_ = NULL;
140 6195 : }
|