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