OpenSDN source code
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
bfd_session.cc
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2014 CodiLime, Inc. All rights reserved.
3  */
4 
5 #include "bfd/bfd_session.h"
7 #include "bfd/bfd_common.h"
8 #include "bfd/bfd_connection.h"
9 
10 #include <boost/asio.hpp>
11 #include <boost/random.hpp>
12 #include <string>
13 #include <algorithm>
14 
15 #include "base/logging.h"
16 
17 namespace BFD {
18 
19 Session::Session(Discriminator localDiscriminator,
20  const SessionKey &key,
22  const SessionConfig &config, Connection *communicator) :
23  localDiscriminator_(localDiscriminator),
24  key_(key),
25  sendTimer_(TimerManager::CreateTimer(*evm->io_service(),
26  "BFD TX", TaskScheduler::GetInstance()->GetTaskId("BFD"), 0)),
27  recvTimer_(TimerManager::CreateTimer(*evm->io_service(),
28  "BFD RX", TaskScheduler::GetInstance()->GetTaskId("BFD"), 0)),
29  currentConfig_(config),
30  nextConfig_(config),
31  sm_(CreateStateMachine(evm, this)),
32  pollSequence_(false),
33  communicator_(communicator),
34  local_endpoint_(key.local_address, GetRandomLocalPort()),
35  remote_endpoint_(key.remote_address, key.remote_port),
36  started_(false),
37  stopped_(false) {
40  sm_->SetCallback(boost::optional<ChangeCb>(
41  boost::bind(&Session::CallStateChangeCallbacks, this, _1, _2)));
42 }
43 
44 uint16_t Session::GetRandomLocalPort() const {
45  boost::random::uniform_int_distribution<> dist(kSendPortMin, kSendPortMax);
46  return dist(randomGen);
47 }
48 
50  Stop();
51  callbacks_.clear();
52 }
53 
55  ControlPacket packet;
56 
58  PreparePacket(nextConfig_, &packet);
59  SendPacket(&packet);
60 
61  // Workaround: Timer code isn't re-entrant
62  this->sendTimer_->Reschedule(tx_interval().total_milliseconds());
63  return true;
64 }
65 
67 
68  if (local_state_non_locking() == kUp) {
69  // Bfd state will transition to Down state,
70  // restore to default values
71  remoteSession_.minRxInterval = boost::posix_time::seconds(1);
72  remoteSession_.minTxInterval = boost::posix_time::seconds(0);
73  }
74  sm_->ProcessTimeout();
76 
77  return false;
78 }
79 
80 std::string Session::toString() const {
81  std::ostringstream out;
82  out << "SessionKey: " << key_.to_string() << "\n";
83  out << "LocalDiscriminator: 0x" << std::hex << localDiscriminator_ << "\n";
84  out << "RemoteDiscriminator: 0x" << std::hex << remoteSession_.discriminator
85  << "\n";
86  out << "DesiredMinTxInterval: " << currentConfig_.desiredMinTxInterval
87  << "\n";
88  out << "RequiredMinRxInterval: " << currentConfig_.requiredMinRxInterval
89  << "\n";
90  out << "RemoteMinRxInterval: " << remoteSession_.minRxInterval << "\n";
91  out << "RemoteMinTxInterval: " << remoteSession_.minTxInterval << "\n";
92  out << "Local State:" << local_state() << "\n";
93  out << "Remote State:" << remote_state().state << "\n";
94 
95  return out.str();
96 }
97 
99  int elapsed_time_ms;
100  int remaining_time_ms;
101  TimeInterval ti = tx_interval();
102 
103  // get the elapsed time only if the bfd session timer is running,
104  // otherwise program the config send timer value
105  if (started_ == true) {
106  elapsed_time_ms = sendTimer_->GetElapsedTime();
107  sendTimer_->Cancel();
108  if (elapsed_time_ms < 0) {
109  remaining_time_ms = 0;
110  } else {
111  remaining_time_ms = ti.total_milliseconds() - elapsed_time_ms;
112  }
113  } else {
114  // timer not yet started, program with config value
115  remaining_time_ms = ti.total_milliseconds();
116  }
117 
118  if (remaining_time_ms > 0) {
119  sendTimer_->Start(remaining_time_ms,
120  boost::bind(&Session::SendTimerExpired, this));
121  } else {
122  // fire the timer now!
123  sendTimer_->Start(0,
124  boost::bind(&Session::SendTimerExpired, this));
125  }
126  if (started_ != true) {
127  started_ = true;
128  }
129 }
130 
133 
134  recvTimer_->Cancel();
135  recvTimer_->Start(ti.total_milliseconds(),
136  boost::bind(&Session::RecvTimerExpired, this));
137 }
138 
140  return sm_->GetState();
141 }
142 
144  return local_state_non_locking();
145 }
146 
147 // If periodic BFD Control packets are already being sent (the remote
148 // system is not in Demand mode), the Poll Sequence MUST be performed by
149 // setting the Poll (P) bit on those scheduled periodic transmissions;
150 // additional packets MUST NOT be sent.
152  pollSequence_ = true;
153  if (local_state_non_locking() != kUp &&
155  ControlPacket packet;
156  PreparePacket(nextConfig_, &packet);
157  SendPacket(&packet);
158  }
159 }
160 
162  ControlPacket *packet) {
163 
164  packet->state = local_state_non_locking();
165  packet->poll = pollSequence_;
171 }
172 
174  TimeInterval oldMinRxInterval = remoteSession_.minRxInterval;
177  remoteSession_.state = packet->state;
178  if ((local_state_non_locking() == kUp) && packet->poll) {
183  } else {
184  // After sending the BFD pkt with previous agreed rate, update
185  // the SendTimer() with new remoteSession_.minRxInterval so as to
186  // not impact the remote Session's detection time.
188  }
189  } else if (local_state_non_locking() == kInit ||
195  if (packet->required_min_rx_interval.total_microseconds() &&
196  oldMinRxInterval >= (packet->required_min_rx_interval * 10)) {
197  // reschedule the sendtimer to the new value
199  }
200  }
201 
202  sm_->ProcessRemoteState(packet->state);
203 
204  // poll sequence
205  if (packet->poll) {
206  ControlPacket newPacket;
207  PreparePacket(nextConfig_, &newPacket);
208  newPacket.poll = false; // poll & final are forbidden in single packet
209  newPacket.final = true;
210  SendPacket(&newPacket);
211  }
212  if (packet->final) {
213  pollSequence_ = false;
215  }
216 
217  if (local_state_non_locking() == kUp ||
220  }
221 
222  return kResultCode_Ok;
223 }
224 
225 void Session::SendPacket(const ControlPacket *packet) {
226  boost::asio::mutable_buffer buffer =
227  boost::asio::mutable_buffer(new uint8_t[kMinimalPacketLength],
228  kMinimalPacketLength);
229  int pktSize = EncodeControlPacket(packet,
230  boost::asio::buffer_cast<uint8_t *>(buffer), kMinimalPacketLength);
231  if (pktSize != kMinimalPacketLength) {
232  LOG(ERROR,
233  "Unable to encode packet: pktSize " << pktSize
234  << ", session: " << toString());
236  const uint8_t *p = boost::asio::buffer_cast<const uint8_t *>(buffer);
237  delete[] p;
238  } else {
240  key_.index, buffer, pktSize);
241  stats_.tx_count++;
242  }
243 }
244 
246  return std::max(currentConfig_.requiredMinRxInterval,
249 }
250 
252  TimeInterval minInterval, maxInterval;
253 
254  TimeInterval negotiatedInterval =
257 
258  minInterval = negotiatedInterval * 3/4;
260  maxInterval = negotiatedInterval * 9/10;
261  } else {
262  maxInterval = negotiatedInterval;
263  }
264 
265  boost::random::uniform_int_distribution<>
266  dist(minInterval.total_microseconds(),
267  maxInterval.total_microseconds());
268  return boost::posix_time::microseconds(dist(randomGen));
269 }
270 
271 const SessionKey &Session::key() const {
272  return key_;
273 }
274 
276  if (stopped_ == false) {
279  stopped_ = true;
280  started_ = false;
281  sm_->SetCallback(boost::optional<ChangeCb>());
282  }
283 }
284 
286  return nextConfig_;
287 }
288 
290  return remoteSession_;
291 }
292 
294  return localDiscriminator_;
295 }
296 
298  const SessionKey &key, const BFD::BFDState &new_state) {
299  for (Callbacks::const_iterator it = callbacks_.begin();
300  it != callbacks_.end(); ++it) {
301  it->second(key, new_state);
302  }
303 }
304 
306  callbacks_[client_id] = cb;
307 }
308 
310  callbacks_.erase(client_id);
311 }
312 
317  pollSequence_ = true;
318 }
319 
321  return callbacks_.size();
322 }
323 
324 bool Session::Up() const {
325  return local_state() == kUp;
326 }
327 
328 } // namespace BFD
bool RecvTimerExpired()
Definition: bfd_session.cc:66
uint32_t Discriminator
Definition: bfd_common.h:17
const SessionKey & key() const
Definition: bfd_session.cc:271
virtual void SendPacket(const boost::asio::ip::udp::endpoint &local_endpoint, const boost::asio::ip::udp::endpoint &remote_endpoint, const SessionIndex &session_index, const boost::asio::mutable_buffer &packet, int pktSize)=0
SessionConfig nextConfig_
Definition: bfd_session.h:115
void UnregisterChangeCallback(ClientId client_id)
Definition: bfd_session.cc:309
int EncodeControlPacket(const ControlPacket *msg, uint8_t *data, size_t size)
The TaskScheduler keeps track of what tasks are currently schedulable. When a task is enqueued it is ...
Definition: task.h:178
void PreparePacket(const SessionConfig &config, ControlPacket *packet)
Definition: bfd_session.cc:161
TimeInterval desiredMinTxInterval
Definition: bfd_common.h:125
BFDState local_state_non_locking() const
Definition: bfd_session.cc:139
int reference_count()
Definition: bfd_session.cc:320
bool SendTimerExpired()
Definition: bfd_session.cc:54
Callbacks callbacks_
Definition: bfd_session.h:124
BFDStats stats_
Definition: bfd_session.h:125
std::string toString() const
Definition: bfd_session.cc:80
Connection * communicator_
Definition: bfd_session.h:119
TimeInterval tx_interval()
Definition: bfd_session.cc:251
uint32_t ClientId
Definition: bfd_common.h:19
boost::scoped_ptr< StateMachine > sm_
Definition: bfd_session.h:117
SessionConfig currentConfig_
Definition: bfd_session.h:114
Discriminator discriminator
Definition: bfd_session.h:31
TimeInterval requiredMinRxInterval
Definition: bfd_common.h:126
boost::random::taus88 randomGen
Definition: bfd_common.cc:43
BFDRemoteSessionState remote_state() const
Definition: bfd_session.cc:289
void CallStateChangeCallbacks(const SessionKey &key, const BFD::BFDState &new_state)
Definition: bfd_session.cc:297
Timer * recvTimer_
Definition: bfd_session.h:113
TimeInterval detection_time()
Definition: bfd_session.cc:245
Timer * sendTimer_
Definition: bfd_session.h:112
TimeInterval minRxInterval
Definition: bfd_session.h:32
uint32_t send_timer_expired_count
Definition: bfd_session.h:49
BFD::Discriminator sender_discriminator
BFD::Discriminator receiver_discriminator
boost::posix_time::time_duration TimeInterval
Definition: bfd_common.h:18
TimeInterval required_min_rx_interval
SessionIndex index
Definition: bfd_common.h:116
int tx_error_count
Definition: bfd_session.h:47
void RegisterChangeCallback(ClientId client_id, ChangeCb cb)
Definition: bfd_session.cc:305
BFDRemoteSessionState remoteSession_
Definition: bfd_session.h:116
boost::asio::ip::udp::endpoint remote_endpoint_
Definition: bfd_session.h:121
Discriminator localDiscriminator_
Definition: bfd_session.h:110
SessionConfig config() const
Definition: bfd_session.cc:285
ResultCode
Definition: bfd_common.h:41
const int kMinimalPacketLength
Definition: bfd_common.cc:41
bool Cancel()
Definition: timer.cc:150
StateMachine * CreateStateMachine(EventManager *evm, Session *session)
boost::function< void(const SessionKey &key, const BFD::BFDState &state)> ChangeCb
Definition: bfd_common.h:131
BFDState
Definition: bfd_common.h:21
SessionKey key_
Definition: bfd_session.h:111
boost::asio::ip::udp::endpoint local_endpoint_
Definition: bfd_session.h:120
void InitPollSequence()
Definition: bfd_session.cc:151
virtual ~Session()
Definition: bfd_session.cc:49
bool Start(int time, Handler handler, ErrorHandler error_handler=NULL)
Definition: timer.cc:108
uint32_t receive_timer_expired_count
Definition: bfd_session.h:48
BFDState local_state() const
Definition: bfd_session.cc:143
#define LOG(_Level, _Msg)
Definition: logging.h:33
TimeInterval desired_min_tx_interval
ResultCode ProcessControlPacket(const ControlPacket *packet)
Definition: bfd_session.cc:173
Discriminator local_discriminator() const
Definition: bfd_session.cc:293
bool Reschedule(int time)
Definition: timer.cc:137
int64_t GetElapsedTime() const
Definition: timer.cc:235
void SendPacket(const ControlPacket *packet)
Definition: bfd_session.cc:225
bool pollSequence_
Definition: bfd_session.h:118
const std::string to_string() const
Definition: bfd_common.h:107
TimeInterval minTxInterval
Definition: bfd_session.h:33
void ScheduleSendTimer()
Definition: bfd_session.cc:98
void ScheduleRecvDeadlineTimer()
Definition: bfd_session.cc:131
bool Up() const
Definition: bfd_session.cc:324
static EventManager evm
void UpdateConfig(const SessionConfig &config)
Definition: bfd_session.cc:313
static bool DeleteTimer(Timer *Timer)
Definition: timer.cc:222
uint16_t GetRandomLocalPort() const
Definition: bfd_session.cc:44