ns3-bgp  0.2
BGP module for ns-3.
bgp.cc
Go to the documentation of this file.
1 
11 #include <arpa/inet.h>
12 #include "bgp.h"
13 #include "ns3/log.h"
14 #include "ns3/enum.h"
15 #include "ns3/ipv4-list-routing.h"
16 #include "ns3/ipv4-static-routing.h"
17 #include "ns3/tcp-socket-factory.h"
18 #include "ns3/simulator.h"
19 
20 namespace ns3 {
21 
22 NS_LOG_COMPONENT_DEFINE("Bgp");
23 NS_OBJECT_ENSURE_REGISTERED(Bgp);
24 
25 Peer::Peer() {
26  allow_local_as = 0;
27  passive = false;
28  weight = 0;
29  no_nexthop_check = false;
30  forced_default_nexthop = false;
31  ibgp_alter_nexthop = false;
32  ebgp_multihop = 1;
33 }
34 
39 void Session::Drop() {
40  socket->SetRecvCallback(MakeNullCallback<void, Ptr<Socket>>());
41  socket->SetCloseCallbacks(
42  MakeNullCallback<void, Ptr<Socket>>(),
43  MakeNullCallback<void, Ptr<Socket>>()
44  );
45  socket->Close();
46  socket = nullptr;
47  fsm->resetHard();
48 
49 }
50 
51 TypeId Bgp::GetTypeId (void) {
52  static TypeId tid = TypeId("ns3::Bgp")
53  .SetParent<Application>()
54  .SetGroupName("Internet")
55  .AddConstructor<Bgp>()
56  .AddAttribute("LibbgpLogLevel", "Log level for libbgp to use",
57  EnumValue(libbgp::INFO),
58  MakeEnumAccessor(&Bgp::_log_level),
59  MakeEnumChecker(
60  libbgp::FATAL, "Fatal",
61  libbgp::ERROR, "Error",
62  libbgp::WARN, "Warning",
63  libbgp::INFO, "Info",
64  libbgp::DEBUG, "Debug"))
65  .AddAttribute("RouterID", "Local BGP ID",
66  Ipv4AddressValue(),
67  MakeIpv4AddressAccessor(&Bgp::_bgp_id),
68  MakeIpv4AddressChecker())
69  .AddAttribute("HoldTimer", "Hold Timer",
70  TimeValue(Seconds(120)),
71  MakeTimeAccessor(&Bgp::_hold_timer),
72  MakeTimeChecker(Seconds(3), Seconds(UINT16_MAX)))
73  .AddAttribute("ClockInterval", "Time to wait between ticking FSMs",
74  TimeValue(Seconds(1)),
75  MakeTimeAccessor(&Bgp::_clock_interval),
76  MakeTimeChecker())
77  .AddAttribute("ErrorHold", "Time to wait before retry.",
78  TimeValue(Seconds(45)),
79  MakeTimeAccessor(&Bgp::_error_hold),
80  MakeTimeChecker());
81 
82  return tid;
83 }
84 
85 Bgp::Bgp() : _logger("(local)"), _rib(&_logger) {
86  _log_level = libbgp::INFO;
87 
88  _logger.setLogLevel(_log_level);
89  _routing = CreateObject<BgpRouting>();
90  _routing->SetRib(&_rib);
91 
92  _running = false;
93  _listen_socket = nullptr;
94 }
95 
96 void Bgp::StartApplication(void) {
97  if (_running) {
98  NS_LOG_WARN("BGP application already started.");
99  return;
100  }
101 
102  NS_LOG_LOGIC("creating configuration template...");
103  _template.clock = &_clock;
104  _template.forced_default_nexthop4 = false;
105  _template.hold_timer = (uint16_t) _hold_timer.GetSeconds();
106  _template.no_collision_detection = false;
107  _template.no_nexthop_check4 = false;
108  _template.rev_bus = &_bus;
109  _template.rib4 = &_rib;
110  _template.router_id = htonl(_bgp_id.Get());
111  _template.use_4b_asn = true;
112 
113  Ptr<Ipv4> ipv4 = GetNode()->GetObject<Ipv4>();
114 
115  NS_LOG_LOGIC("installing BgpRouting...");
116 
117  Ptr<Ipv4ListRouting> list_routing = CreateObject<Ipv4ListRouting>();
118  list_routing->AddRoutingProtocol(CreateObject<Ipv4StaticRouting>(), 10);
119  list_routing->AddRoutingProtocol(_routing, 5);
120  ipv4->SetRoutingProtocol(list_routing);
121 
122  NS_LOG_LOGIC("starting listening socket...");
123 
124  _listen_socket = Socket::CreateSocket(GetNode(), TcpSocketFactory::GetTypeId());
125 
126  if (_listen_socket->Bind(InetSocketAddress(Ipv4Address::GetAny(), 179)) == -1) {
127  NS_FATAL_ERROR("failed to bind socket.");
128  }
129 
130  if (_listen_socket->Listen() == -1) {
131  NS_FATAL_ERROR("failed to listen socket");
132  }
133 
134  NS_LOG_LOGIC("registering callbacks...");
135 
136  _listen_socket->SetAcceptCallback(
137  MakeCallback(&Bgp::HandleConnectInRequest, this),
138  MakeCallback(&Bgp::HandleConnectIn, this)
139  );
140 
141  NS_LOG_LOGIC("sending OPEN message to peers...");
142 
143  for (Ptr<Peer> &peer : _peers) {
144  if (peer->passive) {
145  NS_LOG_LOGIC("skipping passive peer AS" << peer->peer_asn << " (" << peer->peer_address << ").");
146  continue;
147  }
148 
149  // allow other events to run too.
150  Simulator::ScheduleNow(&Bgp::ConnectPeer, this, peer);
151 
152  }
153 
154  NS_LOG_LOGIC("init complete.");
155  _running = true;
156 
157  Simulator::Schedule(_clock_interval, &Bgp::Tick, this);
158 }
159 
160 void Bgp::StopApplication(void) {
161  if (!_running) return;
162 
163  _running = false;
164 
165  NS_LOG_LOGIC("closing listening socket...");
166 
167  _listen_socket->Close();
168  _listen_socket->SetAcceptCallback(
169  MakeNullCallback<bool, Ptr<Socket>, const Address &> (),
170  MakeNullCallback<void, Ptr<Socket>, const Address &> ()
171  );
172 
173  NS_LOG_LOGIC("de-peering...");
174 
175  for (std::vector<Ptr<Session>>::iterator s = _sessions.begin(); s != _sessions.end();) {
176  (*s)->Drop();
177  _sessions.erase(s);
178  }
179 
180  NS_LOG_LOGIC("stopped.");
181 }
182 
183 void Bgp::Tick() {
184  for (Ptr<Session> session : _sessions) {
185  session->fsm->tick();
186  }
187 
188  if (_running) Simulator::Schedule(_clock_interval, &Bgp::Tick, this);
189  else NS_LOG_LOGIC("ticker stopped.");
190 }
191 
192 bool Bgp::ConnectPeer(Ptr<Peer> peer) {
193  if (!_running) return false;
194 
195  for (const Ptr<Session> session : _sessions) {
196  if (session->peer == peer) {
197  NS_LOG_LOGIC("session or fsm for peer AS" << peer->peer_asn << " (" << peer->peer_address << ") already exist, skipping.");
198  return false;
199  }
200  }
201 
202  NS_LOG_LOGIC("obtaning local address information for peer AS" << peer->peer_asn << " (" << peer->peer_address << ").");
203 
204  Ipv4InterfaceAddress local_address = _routing->GetAddressByNexthop(peer->peer_address);
205 
206  if (local_address.GetLocal().Get() == 0) {
207  NS_LOG_WARN("peer AS" << peer->peer_asn << " (" << peer->peer_address << ") unreachable on any device, skipping.");
208  return false;
209  }
210 
211  NS_LOG_LOGIC("create and bind socket for peer AS" << peer->peer_asn << " (" << peer->peer_address << ").");
212 
213  Ptr<Socket> peer_socket = Socket::CreateSocket(GetNode(), TcpSocketFactory::GetTypeId());
214 
215  NS_LOG_LOGIC("using local address: " << local_address);
216  NS_LOG_LOGIC("registering callbacks...");
217 
218  peer_socket->SetConnectCallback(
219  MakeCallback(&Bgp::HandleConnectOut, this),
220  MakeCallback(&Bgp::HandleConnectOutFailed, this)
221  );
222 
223  if (peer->local_asn != peer->peer_asn) peer_socket->SetIpTtl(peer->ebgp_multihop);
224 
225  if (peer_socket->Connect(InetSocketAddress(peer->peer_address, 179)) == -1) {
226  NS_LOG_ERROR("failed to connect: " << strerror(errno));
227  return false;
228  }
229 
230  return true;
231 }
232 
233 bool Bgp::HandleConnectInRequest(Ptr<Socket> socket, const Address &src) {
234  return true;
235 }
236 
237 void Bgp::HandleConnectOutFailed(Ptr<Socket> socket) {
238  NS_LOG_WARN("socket connect failed: " << socket);
239 }
240 
241 void Bgp::HandleClose(Ptr<Socket> socket) {
242  NS_LOG_LOGIC("handling connection shutdown: " << socket);
243 
244  for (std::vector<Ptr<Session>>::iterator session = _sessions.begin();
245  session != _sessions.end(); session++) {
246  if ((*session)->socket == socket) {
247 
248  if (_running && !(*session)->peer->passive) {
249  NS_LOG_LOGIC("scheduled retry in " << _error_hold.GetSeconds() << " seconds.");
250  Simulator::Schedule(_error_hold, &Bgp::ConnectPeer, this, (*session)->peer);
251  }
252 
253  NS_LOG_INFO("dropping session of AS" << (*session)->peer->peer_asn << "/" << ((*session)->local_init ? 'L' : 'R') << " (" << (*session)->peer->peer_address << ").");
254  (*session)->Drop();
255  _sessions.erase(session);
256  return;
257  }
258  }
259 
260 }
261 
262 void Bgp::HandleConnectIn(Ptr<Socket> socket, const Address &peer_addr) {
263  NS_LOG_LOGIC("incoming connection.");
264  SessionInit(false, socket);
265 }
266 
267 void Bgp::HandleConnectOut(Ptr<Socket> socket) {
268  NS_LOG_LOGIC("connected. unregister connect callback...");
269  socket->SetConnectCallback(
270  MakeNullCallback<void, Ptr<Socket>>(),
271  MakeNullCallback<void, Ptr<Socket>>()
272  );
273  SessionInit(true, socket);
274 }
275 
276 bool Bgp::SessionInit(bool local_init, Ptr<Socket> socket) {
277  Address peer_addr;
278 
279  if (socket->GetPeerName(peer_addr) == -1) {
280  NS_LOG_WARN("failed to get peer information.");
281  socket->Close();
282  return false;
283  }
284 
285  InetSocketAddress peer_sockaddr = InetSocketAddress::ConvertFrom(peer_addr);
286  Ptr<Peer> peer = nullptr;
287 
288  NS_LOG_LOGIC("prepareing session with " << peer_sockaddr.GetIpv4() << "...");
289 
290  for (Ptr<Peer> _peer : _peers) {
291  if (_peer->peer_address == peer_sockaddr.GetIpv4()) {
292  peer = _peer;
293  break;
294  }
295  }
296 
297  if (peer == nullptr) {
298  NS_LOG_WARN("socket peer address " << peer_sockaddr.GetIpv4() << " does not belong to any peer.");
299  socket->Close();
300  return false;
301  }
302 
303  for (const Ptr<Session> session : _sessions) {
304  if (session->peer == peer && session->fsm->getState() == libbgp::ESTABLISHED) {
305  NS_LOG_INFO("session or fsm for peer AS" << peer->peer_asn << " (" << peer->peer_address << ") already exist and established, closing socket.");
306  socket->Close();
307  return false;
308  }
309  }
310 
311  Ipv4InterfaceAddress local_addr = _routing->GetAddressByNexthop(peer_sockaddr.GetIpv4());
312 
313  if (local_addr.GetLocal().Get() == 0) {
314  NS_LOG_WARN("peer AS" << peer->peer_asn << " (" << peer->peer_address << ") unreachable on any device.");
315  socket->Close();
316  return false;
317  }
318 
319  NS_LOG_LOGIC("matching peer found. (AS" << peer->peer_asn << ", " << peer->peer_address << ").");
320 
321  char peer_name[128];
322  snprintf(
323  peer_name, 128, "AS%d/AS%d/%c",
324  peer->local_asn, peer->peer_asn,
325  local_init ? 'L' : 'R');
326  libbgp::BgpConfig peer_config(_template);
327 
328  Ptr<BgpLog> peer_logger = Create<BgpLog>(peer_name);
329  Ptr<BgpNs3SocketOut> peer_out_handler = Create<BgpNs3SocketOut>(socket, MakeCallback(&Bgp::HandleStateChange, this));
330 
331  peer_logger->setLogLevel(_log_level);
332 
333  peer_config.asn = peer->local_asn;
334  peer_config.in_filters4 = peer->ingress_rules;
335  peer_config.out_filters4 = peer->egress_rules;
336  peer_config.log_handler = PeekPointer(peer_logger);
337  peer_config.default_nexthop4 = htonl(local_addr.GetLocal().Get());
338  peer_config.out_handler = PeekPointer(peer_out_handler);
339  peer_config.peer_asn = peer->peer_asn;
340  peer_config.peering_lan4 = libbgp::Prefix4(
341  htonl(local_addr.GetLocal().CombineMask(local_addr.GetMask()).Get()),
342  local_addr.GetMask().GetPrefixLength());
343 
344  peer_config.allow_local_as = peer->allow_local_as;
345  peer_config.no_nexthop_check4 = peer->no_nexthop_check;
346  peer_config.weight = peer->weight;
347  peer_config.forced_default_nexthop4 = peer->forced_default_nexthop;
348  peer_config.ibgp_alter_nexthop = peer->ibgp_alter_nexthop;
349 
350  Ptr<BgpNs3Fsm> peer_fsm = Create<BgpNs3Fsm>(peer_config);
351  Ptr<Session> peer_session = Create<Session>();
352  Ptr<BgpNs3SocketIn> in_handler = Create<BgpNs3SocketIn>(peer_fsm);
353  peer_session->peer = peer;
354  peer_session->socket = socket;
355  peer_session->fsm = peer_fsm;
356  peer_session->logger = peer_logger;
357  peer_session->out_handler = peer_out_handler;
358  peer_session->in_handler = in_handler;
359  peer_session->local_init = local_init;
360 
361  socket->SetRecvCallback(MakeCallback(&BgpNs3SocketIn::HandleRead, in_handler));
362  socket->SetCloseCallbacks(
363  MakeCallback(&Bgp::HandleClose, this),
364  MakeCallback(&Bgp::HandleClose, this)
365  );
366 
367  if (local_init) peer_fsm->start();
368 
369  _sessions.push_back(peer_session);
370 
371  return true;
372 }
373 
374 void Bgp::HandleStateChange(Ptr<Socket> socket, int old_state, int new_state) {
375  if (new_state == libbgp::IDLE || new_state == libbgp::BROKEN) {
376  socket->Close();
377  }
378 }
379 
385 void Bgp::AddPeer(const Peer &peer) {
386  NS_ASSERT(!_running);
387  _peers.push_back(Create<Peer>(peer));
388 }
389 
396 void Bgp::AddRoute(libbgp::Prefix4 route, uint32_t nexthop) {
397  NS_ASSERT(!_running);
398  _rib.insert(&_logger, route, nexthop);
399 }
400 
408 void Bgp::AddRoute(uint32_t prefix, uint8_t mask, uint32_t nexthop) {
409  NS_ASSERT(!_running);
410  AddRoute(libbgp::Prefix4(prefix, mask), nexthop);
411 }
412 
420 void Bgp::AddRoute(const Ipv4Address &prefix, const Ipv4Mask &mask, const Ipv4Address &nexthop) {
421  NS_ASSERT(!_running);
422  AddRoute(htonl(prefix.Get()), (uint8_t) mask.GetPrefixLength(), htonl(nexthop.Get()));
423 }
424 
430 void Bgp::SetLibbgpLogLevel(libbgp::LogLevel log_level) {
431  NS_ASSERT(!_running);
432  _log_level = log_level;
433 }
434 
440 void Bgp::SetBgpId(Ipv4Address bgp_id) {
441  NS_ASSERT(!_running);
442  _bgp_id = bgp_id;
443 }
444 
450 void Bgp::SetHoldTimer(Time hold_timer) {
451  NS_ASSERT(!_running);
452  _hold_timer = hold_timer;
453 }
454 
460 void Bgp::SetClockInterval(Time interval) {
461  NS_ASSERT(!_running);
462  _clock_interval = interval;
463 }
464 
471 }
472 
bool forced_default_nexthop
always use peering IP as nexthop.
Definition: bgp.h:48
BgpLogHandler * log_handler
void SetHoldTimer(Time hold_timer)
Set local hold timer.
Definition: bgp.cc:450
Peer configuration class.
Definition: bgp.h:34
void SetBgpId(Ipv4Address bgp_id)
Set local router ID.
Definition: bgp.cc:440
BgpFilterRules in_filters4
uint32_t default_nexthop4
bool ibgp_alter_nexthop
alter IBGP nexthop attribute the same way as EBGP.
Definition: bgp.h:49
bool forced_default_nexthop4
int32_t weight
weight of this peer
Definition: bgp.h:46
int8_t allow_local_as
Allow N local ASN in AS_PATH.
Definition: bgp.h:45
Definition: bgp-log.cc:15
void AddPeer(const Peer &peer)
Add a peer to the BGP application.
Definition: bgp.cc:385
bool passive
passive peering (don&#39;t send OPEN)
Definition: bgp.h:44
bool no_nexthop_check
disable nexthop attribute validation
Definition: bgp.h:47
BgpFilterRules out_filters4
void AddRoute(libbgp::Prefix4 route, uint32_t nexthop)
Add a route to BGP routing table.
Definition: bgp.cc:396
void HandleRead(Ptr< Socket > socket)
Handle reading from socket.
BgpOutHandler * out_handler
void Drop()
Drop this session.
Definition: bgp.cc:39
The Bgp Application.
Definition: bgp.h:77
void SetLibbgpLogLevel(libbgp::LogLevel log_level)
Set libbgp log level.
Definition: bgp.cc:430
void SetClockInterval(Time interval)
Set Tick() interval.
Definition: bgp.cc:460