A Discrete-Event Network Simulator
API
ofswitch13-device.cc
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2015 University of Campinas (Unicamp)
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License version 2 as
6  * published by the Free Software Foundation;
7  *
8  * This program is distributed in the hope that it will be useful,
9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11  * GNU General Public License for more details.
12  *
13  * You should have received a copy of the GNU General Public License
14  * along with this program; if not, write to the Free Software
15  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
16  *
17  * Author: Luciano Jerez Chaves <ljerezchaves@gmail.com>
18  */
19 
20 #include "ofswitch13-device.h"
21 
22 #include "ofswitch13-port.h"
23 
24 #include <ns3/object-vector.h>
25 
26 #undef NS_LOG_APPEND_CONTEXT
27 #define NS_LOG_APPEND_CONTEXT \
28  if (m_dpId) \
29  { \
30  std::clog << "[dp " << m_dpId << "] "; \
31  }
32 
33 namespace ns3
34 {
35 
36 NS_LOG_COMPONENT_DEFINE("OFSwitch13Device");
37 NS_OBJECT_ENSURE_REGISTERED(OFSwitch13Device);
38 
39 // Initializing OFSwitch13Device static members.
43 
44 /********** Public methods **********/
46  : m_dpId(0),
47  m_datapath(nullptr),
48  m_cpuConsumed(0),
49  m_cpuTokens(0),
50  m_cFlowMod(0),
51  m_cGroupMod(0),
52  m_cMeterMod(0),
53  m_cPacketIn(0),
54  m_cPacketOut(0)
55 {
56  NS_LOG_FUNCTION(this);
57  NS_LOG_INFO("OpenFlow version: " << OFP_VERSION);
58 
59  m_dpId = ++m_globalDpId;
60  NS_LOG_DEBUG("New datapath ID " << m_dpId);
62 }
63 
65 {
66  NS_LOG_FUNCTION(this);
67 }
68 
69 TypeId
71 {
72  static TypeId tid =
73  TypeId("ns3::OFSwitch13Device")
74  .SetParent<Object>()
75  .SetGroupName("OFSwitch13")
76  .AddConstructor<OFSwitch13Device>()
77  .AddAttribute(
78  "CpuCapacity",
79  "CPU processing capacity (in terms of throughput).",
80  DataRateValue(DataRate("100Gb/s")),
81  MakeDataRateAccessor(&OFSwitch13Device::m_cpuCapacity),
82  MakeDataRateChecker())
83  .AddAttribute("DatapathId",
84  "The unique identification of this OpenFlow switch.",
86  UintegerValue(0),
88  MakeUintegerChecker<uint64_t>())
89  .AddAttribute(
90  "FlowTableSize",
91  "The maximum number of entries allowed on each flow table.",
92  UintegerValue(FLOW_TABLE_MAX_ENTRIES),
95  MakeUintegerChecker<uint32_t>(0, FLOW_TABLE_MAX_ENTRIES))
96  .AddAttribute(
97  "GroupTableSize",
98  "The maximum number of entries allowed on group table.",
99  UintegerValue(GROUP_TABLE_MAX_ENTRIES),
102  MakeUintegerChecker<uint32_t>(0, GROUP_TABLE_MAX_ENTRIES))
103  .AddAttribute(
104  "MeterTableSize",
105  "The maximum number of entries allowed on meter table.",
106  UintegerValue(METER_TABLE_MAX_ENTRIES),
109  MakeUintegerChecker<uint32_t>(0, METER_TABLE_MAX_ENTRIES))
110  .AddAttribute(
111  "PipelineTables",
112  "The number of pipeline flow tables.",
114  UintegerValue(64),
116  MakeUintegerChecker<uint32_t>(1, (OFPTT_MAX + 1)))
117  .AddAttribute("PortList",
118  "The list of ports associated to this switch.",
121  MakeObjectVectorChecker<OFSwitch13Port>())
122  .AddAttribute(
123  "TcamDelay",
124  "Average time to perform a TCAM operation in pipeline.",
125  TimeValue(MicroSeconds(20)),
127  MakeTimeChecker(Time(0)))
128  .AddAttribute(
129  "TimeoutInterval",
130  "The interval between timeout operations on datapath.",
131  TimeValue(MilliSeconds(100)),
134 
135  .AddTraceSource(
136  "BufferExpire",
137  "Trace source indicating an expired packet in buffer.",
139  "ns3::Packet::TracedCallback")
140  .AddTraceSource(
141  "BufferRetrieve",
142  "Trace source indicating a packet retrieved from buffer.",
145  "ns3::Packet::TracedCallback")
146  .AddTraceSource(
147  "BufferSave",
148  "Trace source indicating a packet saved into buffer.",
150  "ns3::Packet::TracedCallback")
151  .AddTraceSource(
152  "MeterDrop",
153  "Trace source indicating a packet dropped by meter band.",
155  "ns3::OFSwitch13Device::MeterDropTracedCallback")
156  .AddTraceSource(
157  "OverloadDrop",
158  "Trace source indicating a packet dropped by CPU "
159  "overloaded processing capacity.",
161  "ns3::Packet::TracedCallback")
162  .AddTraceSource(
163  "TableDrop",
164  "Trace source indicating an unmatched packet dropped by "
165  "a flow table without a table-miss entry.",
167  "ns3::OFSwitch13Device::TableDropTracedCallback")
168  .AddTraceSource(
169  "PipelinePacket",
170  "Trace source indicating a packet sent to pipeline.",
172  "ns3::Packet::TracedCallback")
173  .AddTraceSource(
174  "DatapathTimeout",
175  "Trace source indicating a datapath timeout operation.",
178  "ns3::OFSwitch13Device::DeviceTracedCallback")
179 
180  .AddTraceSource(
181  "CpuLoad",
182  "Traced value indicating the avg CPU processing load"
183  " (periodically updated on datapath timeout operation).",
185  "ns3::TracedValueCallback::DataRate")
186  .AddTraceSource(
187  "GroupEntries",
188  "Traced value indicating the number of group entries"
189  " (periodically updated on datapath timeout operation).",
191  "ns3::TracedValueCallback::Uint32")
192  .AddTraceSource(
193  "MeterEntries",
194  "Traced value indicating the number of meter entries"
195  " (periodically updated on datapath timeout operation).",
197  "ns3::TracedValueCallback::Uint32")
198  .AddTraceSource(
199  "PipelineDelay",
200  "Traced value indicating the avg pipeline lookup delay"
201  " (periodically updated on datapath timeout operation).",
203  "ns3::TracedValueCallback::Time")
204  .AddTraceSource(
205  "SumFlowEntries",
206  "Traced value indicating the total number of flow entries"
207  " (periodically updated on datapath timeout operation).",
209  "ns3::TracedValueCallback::Uint32");
210  return tid;
211 }
212 
213 uint64_t
215 {
216  return m_dpId;
217 }
218 
219 uint64_t
221 {
222  return m_dpId;
223 }
224 
225 uint64_t
227 {
228  return m_cFlowMod;
229 }
230 
231 uint64_t
233 {
234  return m_cGroupMod;
235 }
236 
237 uint64_t
239 {
240  return m_cMeterMod;
241 }
242 
243 uint64_t
245 {
246  return m_cPacketIn;
247 }
248 
249 uint64_t
251 {
252  return m_cPacketOut;
253 }
254 
255 uint32_t
257 {
258  return m_bufferPkts.size();
259 }
260 
261 uint32_t
263 {
264  return m_bufferSize;
265 }
266 
267 double
269 {
270  if (GetBufferSize() == 0)
271  {
272  return 0.0;
273  }
274  return static_cast<double>(GetBufferEntries()) /
275  static_cast<double>(GetBufferSize());
276 }
277 
278 DataRate
280 {
281  return m_cpuCapacity;
282 }
283 
284 DataRate
286 {
287  return m_cpuLoad;
288 }
289 
290 double
292 {
293  if (GetCpuCapacity().GetBitRate() == 0)
294  {
295  return 0.0;
296  }
297  return static_cast<double>(GetCpuLoad().GetBitRate()) /
298  static_cast<double>(GetCpuCapacity().GetBitRate());
299 }
300 
301 Time
303 {
304  return m_timeout;
305 }
306 
307 uint32_t
309 {
310  return m_flowTabSize;
311 }
312 
313 uint32_t
315 {
316  NS_ASSERT_MSG(m_datapath, "No datapath defined yet.");
317  NS_ASSERT_MSG(tableId < GetNPipelineTables(), "Invalid table ID.");
318  return m_datapath->pipeline->tables[tableId]->stats->active_count;
319 }
320 
321 uint32_t
323 {
324  NS_ASSERT_MSG(m_datapath, "No datapath defined yet.");
325  NS_ASSERT_MSG(tableId < GetNPipelineTables(), "Invalid table ID.");
326  return m_datapath->pipeline->tables[tableId]->features->max_entries;
327 }
328 
329 double
331 {
332  if (GetFlowTableSize(tableId) == 0)
333  {
334  return 0.0;
335  }
336  return static_cast<double>(GetFlowTableEntries(tableId)) /
337  static_cast<double>(GetFlowTableSize(tableId));
338 }
339 
340 uint32_t
342 {
343  NS_ASSERT_MSG(m_datapath, "No datapath defined yet.");
344  return m_datapath->groups->entries_num;
345 }
346 
347 uint32_t
349 {
350  return m_groupTabSize;
351 }
352 
353 double
355 {
356  if (GetGroupTableSize() == 0)
357  {
358  return 0.0;
359  }
360  return static_cast<double>(GetGroupTableEntries()) /
361  static_cast<double>(GetGroupTableSize());
362 }
363 
364 uint32_t
366 {
367  NS_ASSERT_MSG(m_datapath, "No datapath defined yet.");
368  return m_datapath->meters->entries_num;
369 }
370 
371 uint32_t
373 {
374  return m_meterTabSize;
375 }
376 
377 double
379 {
380  if (GetMeterTableSize() == 0)
381  {
382  return 0.0;
383  }
384  return static_cast<double>(GetMeterTableEntries()) /
385  static_cast<double>(GetMeterTableSize());
386 }
387 
388 uint32_t
390 {
391  return m_controllers.size();
392 }
393 
394 uint32_t
396 {
397  return m_numPipeTabs;
398 }
399 
400 uint32_t
402 {
403  return m_ports.size();
404 }
405 
406 Time
408 {
409  return m_pipeDelay;
410 }
411 
412 uint32_t
414 {
415  uint32_t flowEntries = 0;
416  for (size_t i = 0; i < GetNPipelineTables(); i++)
417  {
418  flowEntries += GetFlowTableEntries(i);
419  }
420  return flowEntries;
421 }
422 
423 struct datapath*
425 {
426  return m_datapath;
427 }
428 
431 {
432  NS_LOG_FUNCTION(this << portDevice);
433 
434  NS_LOG_INFO("Adding port addr " << portDevice->GetAddress());
435  NS_ABORT_MSG_IF(GetNSwitchPorts() >= DP_MAX_PORTS,
436  "No more ports allowed.");
437 
438  // Create the OpenFlow port for this device.
439  Ptr<OFSwitch13Port> ofPort;
440  ofPort = CreateObject<OFSwitch13Port>(m_datapath, portDevice, this);
441 
442  // Save port in port list (assert port no and vector index).
443  m_ports.emplace_back(ofPort);
444  NS_ASSERT((m_ports.size() == ofPort->GetPortNo()) &&
445  (m_ports.size() == m_datapath->ports_num));
446 
447  return ofPort;
448 }
449 
452 {
453  NS_LOG_FUNCTION(this << no);
454 
455  // Assert port no (starts at 1).
456  NS_ASSERT_MSG(no > 0 && no <= m_ports.size(), "Port is out of range.");
457  return m_ports.at(no - 1);
458 }
459 
460 void
462  uint32_t portNo,
463  uint64_t tunnelId)
464 {
465  NS_LOG_FUNCTION(this << packet << portNo << tunnelId);
466 
467  // Check the packet for conformance to CPU processing capacity.
468  uint32_t pktSizeBits = packet->GetSize() * 8;
469  if (m_cpuTokens < pktSizeBits)
470  {
471  // Packet will be dropped. Increase counter and fire drop trace source.
472  NS_LOG_DEBUG("Drop packet due to CPU overloaded capacity.");
473  m_loadDropTrace(packet);
474  return;
475  }
476 
477  // Consume tokens, fire trace source and schedule the packet to the
478  // pipeline.
479  m_cpuTokens -= pktSizeBits;
480  m_cpuConsumed += pktSizeBits;
481  m_pipePacketTrace(packet);
484  this,
485  packet,
486  portNo,
487  tunnelId);
488 }
489 
490 void
492 {
493  NS_LOG_FUNCTION(this << ctrlAddr);
494 
495  NS_ASSERT(!ctrlAddr.IsInvalid());
497  "Invalid address type (only IPv4 supported by now).");
499  "Controller address already in use.");
500 
501  // Start a TCP connection to this target controller.
502  int error = 0;
503  TypeId tcpFact = TypeId::LookupByName("ns3::TcpSocketFactory");
504  Ptr<Socket> ctrlSocket = Socket::CreateSocket(GetObject<Node>(), tcpFact);
505  ctrlSocket->SetAttribute("SegmentSize", UintegerValue(8900));
506 
507  error = ctrlSocket->Bind();
508  if (error)
509  {
510  NS_LOG_ERROR("Error binding socket " << error);
511  return;
512  }
513 
514  error = ctrlSocket->Connect(InetSocketAddress::ConvertFrom(ctrlAddr));
515  if (error)
516  {
517  NS_LOG_ERROR("Error connecting socket " << error);
518  return;
519  }
520 
521  ctrlSocket->SetConnectCallback(
524 
525  // Create a RemoteController object for this controller and save it.
526  Ptr<RemoteController> remoteCtrl = Create<RemoteController>();
527  remoteCtrl->m_address = ctrlAddr;
528  remoteCtrl->m_socket = ctrlSocket;
529  m_controllers.emplace_back(remoteCtrl);
530 }
531 
532 // BOFUSS overriding and callback functions.
533 void
535  struct packet* pkt,
536  uint8_t tableId,
537  uint8_t reason)
538 {
540  dev->SendPacketInMessage(pkt,
541  tableId,
542  reason,
543  dev->m_datapath->config.miss_send_len);
544 }
545 
546 int
548  struct remote* remote)
549 {
551  Ptr<Packet> packet = PacketFromBuffer(buffer);
552  Ptr<RemoteController> remoteCtrl = dev->GetRemoteController(remote);
553 
554  ofpbuf_delete(buffer);
555  return dev->SendToController(packet, remoteCtrl);
556 }
557 
558 void
560  uint32_t outPort,
561  uint32_t outQueue,
562  uint16_t maxLength,
563  uint64_t cookie)
564 {
566  switch (outPort)
567  {
568  case (OFPP_TABLE): {
569  if (pkt->packet_out)
570  {
571  // Makes sure packet cannot be resubmit to pipeline again setting
572  // packet_out to false. Also, pipeline_process_packet takes
573  // ownership of the packet, we need a copy.
574  struct packet* pkt_copy = packet_clone(pkt);
575  pkt_copy->packet_out = false;
576  pipeline_process_packet(pkt_copy->dp->pipeline, pkt_copy);
577  }
578  break;
579  }
580  case (OFPP_IN_PORT): {
581  dev->SendToSwitchPort(pkt, pkt->in_port, outQueue);
582  break;
583  }
584  case (OFPP_CONTROLLER): {
585  dev->SendPacketInMessage(pkt,
586  pkt->table_id,
587  pkt->handle_std->table_miss ? OFPR_NO_MATCH
588  : OFPR_ACTION,
589  maxLength,
590  cookie);
591  break;
592  }
593  case (OFPP_FLOOD):
594  case (OFPP_ALL): {
595  struct sw_port* p;
596  LIST_FOR_EACH(p, struct sw_port, node, &pkt->dp->port_list)
597  {
598  if ((p->stats->port_no == pkt->in_port) ||
599  (outPort == OFPP_FLOOD && p->conf->config & OFPPC_NO_FWD))
600  {
601  continue;
602  }
603  dev->SendToSwitchPort(pkt, p->stats->port_no);
604  }
605  break;
606  }
607  case (OFPP_NORMAL):
608  case (OFPP_LOCAL):
609  default: {
610  if (pkt->in_port != outPort)
611  {
612  dev->SendToSwitchPort(pkt, outPort, outQueue);
613  }
614  }
615  }
616 }
617 
618 void
619 OFSwitch13Device::MeterCreatedCallback(struct meter_entry* entry)
620 {
622  dev->NotifyMeterEntryCreated(entry);
623 }
624 
625 void
627  struct meter_entry* entry)
628 {
630  dev->NotifyPacketDroppedByMeter(pkt, entry);
631 }
632 
633 void
635  struct flow_table* table)
636 {
638  dev->NotifyPacketDroppedByTable(pkt, table);
639 }
640 
641 void
642 OFSwitch13Device::PacketCloneCallback(struct packet* pkt, struct packet* clone)
643 {
645  dev->NotifyPacketCloned(pkt, clone);
646 }
647 
648 void
650 {
652  dev->NotifyPacketDestroyed(pkt);
653 }
654 
655 void
657 {
659  dev->BufferPacketSave(pkt->ns3_uid, timeout);
660 }
661 
662 void
664 {
666  dev->BufferPacketRetrieve(pkt->ns3_uid);
667 }
668 
671 {
672  auto it = OFSwitch13Device::m_globalSwitchMap.find(id);
673  if (it != OFSwitch13Device::m_globalSwitchMap.end())
674  {
675  return it->second;
676  }
677  NS_ABORT_MSG("Error when retrieving datapath.");
678 }
679 
680 /********** Protected methods **********/
681 void
683 {
684  NS_LOG_FUNCTION(this);
685 
686  for (auto& port : m_ports)
687  {
688  port->Dispose();
689  port = nullptr;
690  }
691  m_ports.clear();
692  m_bufferPkts.clear();
693 
694  for (auto& ctrl : m_controllers)
695  {
696  free(ctrl->m_remote);
697  }
698  m_controllers.clear();
699 
700  dp_buffers_destroy(m_datapath->buffers);
701  pipeline_destroy(m_datapath->pipeline);
702  group_table_destroy(m_datapath->groups);
703  meter_table_destroy(m_datapath->meters);
704 
705  free(m_datapath->mfr_desc);
706  free(m_datapath->hw_desc);
707  free(m_datapath->sw_desc);
708  free(m_datapath->dp_desc);
709  free(m_datapath->serial_num);
710  free(m_datapath);
711 
713 
715 }
716 
717 void
719 {
720  NS_LOG_FUNCTION(this);
721 
722  // Create the datapath.
724 
725  // Set the attribute values again so it can now update the dapatah structs.
729 
730  // Execute the first datapath timeout.
732 
733  // Chain up.
735 }
736 
737 /********** Private methods **********/
738 struct datapath*
740 {
741  NS_LOG_FUNCTION(this);
742 
743  struct datapath* dp = (struct datapath*)xmalloc(sizeof(struct datapath));
744 
745  dp->mfr_desc = (char*)xmalloc(DESC_STR_LEN);
746  dp->hw_desc = (char*)xmalloc(DESC_STR_LEN);
747  dp->sw_desc = (char*)xmalloc(DESC_STR_LEN);
748  dp->dp_desc = (char*)xmalloc(DESC_STR_LEN);
749  dp->serial_num = (char*)xmalloc(DESC_STR_LEN);
750  strncpy(dp->mfr_desc, "The ns-3 team", DESC_STR_LEN);
751  strncpy(dp->hw_desc, "N/A", DESC_STR_LEN);
752  strncpy(dp->sw_desc, "The ns-3 OFSwitch13 module", DESC_STR_LEN);
753  strncpy(dp->dp_desc, "Using BOFUSS (from CPqD)", DESC_STR_LEN);
754  strncpy(dp->serial_num, "3.1.0", DESC_STR_LEN);
755 
756  dp->id = m_dpId;
757  dp->last_timeout = time_now();
759  list_init(&dp->remotes);
760 
761  // unused
762  dp->generation_id = -1;
763 
764  memset(dp->ports, 0x00, sizeof(dp->ports));
765  dp->local_port = nullptr;
766 
767  // Set the number of flow tables from the PipelineTables attribute.
768  dp->pipeline_num_tables = GetNPipelineTables();
769 
770  dp->buffers = dp_buffers_create(dp);
771  dp->pipeline = pipeline_create(dp);
772  dp->groups = group_table_create(dp);
773  dp->meters = meter_table_create(dp);
774 
775  m_bufferSize = dp_buffers_size(dp->buffers);
776 
777  list_init(&dp->port_list);
778  dp->ports_num = 0;
779  dp->max_queues = PORT_MAX_QUEUES;
780  dp->exp = nullptr;
781 
782  dp->config.flags =
783  OFPC_FRAG_NORMAL; // IP fragments with no special handling
784  dp->config.miss_send_len = OFP_DEFAULT_MISS_SEND_LEN; // 128 bytes
785 
786  // BOFUSS callbacks
787  dp->pkt_clone_cb = &OFSwitch13Device::PacketCloneCallback;
788  dp->pkt_destroy_cb = &OFSwitch13Device::PacketDestroyCallback;
789  dp->buff_save_cb = &OFSwitch13Device::BufferSaveCallback;
790  dp->buff_retrieve_cb = &OFSwitch13Device::BufferRetrieveCallback;
791  dp->meter_drop_cb = &OFSwitch13Device::MeterDropCallback;
792  dp->miss_drop_cb = &OFSwitch13Device::TableDropCallback;
793  dp->meter_created_cb = &OFSwitch13Device::MeterCreatedCallback;
794 
795  return dp;
796 }
797 
798 void
799 OFSwitch13Device::SetFlowTableSize(uint8_t tableId, uint32_t value)
800 {
801  NS_LOG_FUNCTION(this << tableId << value);
802 
803  NS_ASSERT_MSG(m_datapath, "No datapath defined yet.");
805  "Can't reduce table size to this value.");
806  m_datapath->pipeline->tables[tableId]->features->max_entries = value;
807 }
808 
809 void
811 {
812  NS_LOG_FUNCTION(this << value);
813 
815  if (m_datapath)
816  {
817  for (size_t i = 0; i < GetNPipelineTables(); i++)
818  {
820  }
821  }
822 }
823 
824 void
826 {
827  NS_LOG_FUNCTION(this << value);
828 
830  if (m_datapath)
831  {
833  "Can't reduce table size to this value.");
834  for (size_t i = 0; i < 4; i++)
835  {
836  m_datapath->groups->features->max_groups[i] = value;
837  }
838  }
839 }
840 
841 void
843 {
844  NS_LOG_FUNCTION(this << value);
845 
847  if (m_datapath)
848  {
850  "Can't reduce table size to this value.");
851  m_datapath->meters->features->max_meter = value;
852  }
853 }
854 
855 void
857 {
858  meter_table_add_tokens(dp->meters);
859  pipeline_timeout(dp->pipeline);
860 
861  // Check for chan/s in links (port) status.
862  for (const auto& port : m_ports)
863  {
864  port->PortUpdateState();
865  }
866 
867  // Update traced values.
871 
872  // The pipeline delay is estimated as k * log (n), where 'k' is the
873  // m_tcamDelay set to the time for a single TCAM operation, and 'n' is the
874  // current number of entries on all flow tables.
875  m_pipeDelay =
876  m_sumFlowEntries < 2U
877  ? m_tcamDelay
878  : m_tcamDelay *
879  (int64_t)ceil(log2(static_cast<double>(m_sumFlowEntries)));
880 
881  // The CPU load is estimated based on the CPU consumed tokens since last
882  // timeout operation.
884  m_cpuConsumed = 0;
885 
886  // Refill the pipeline bucket with tokens based on elapsed time
887  // (bucket capacity is set to the number of tokens for an entire second).
888  Time elapTime = Simulator::Now() - m_lastTimeout;
889  uint64_t addTokens = m_cpuCapacity.GetBitRate() * elapTime.GetSeconds();
890  uint64_t maxTokens = m_cpuCapacity.GetBitRate();
891  m_cpuTokens = std::min(m_cpuTokens + addTokens, maxTokens);
892 
893  dp->last_timeout = time_now();
898  this,
899  m_datapath);
900 }
901 
902 int
904  uint8_t tableId,
905  uint8_t reason,
906  uint16_t maxLength,
907  uint64_t cookie)
908 {
909  NS_LOG_FUNCTION(this << pkt->ns3_uid << tableId << reason);
910 
911  // Create the packet_in message.
912  struct ofl_msg_packet_in msg;
913  msg.header.type = OFPT_PACKET_IN;
914  msg.total_len = pkt->buffer->size;
915  msg.reason = (enum ofp_packet_in_reason)reason;
916  msg.table_id = tableId;
917  msg.cookie = cookie;
918  msg.data = (uint8_t*)pkt->buffer->data;
919 
920  // A maxLength of OFPCML_NO_BUFFER means that the complete packet should be
921  // sent, and it should not be buffered. However, in this implementation we
922  // always save the packet into buffer to avoid losing ns-3 packet id
923  // reference. This is not full compliant with OpenFlow specification, but
924  // works very well here.
925  dp_buffers_save(pkt->dp->buffers, pkt);
926  msg.buffer_id = pkt->buffer_id;
927  msg.data_length = MIN(maxLength, pkt->buffer->size);
928 
929  if (!pkt->handle_std->valid)
930  {
931  packet_handle_std_validate(pkt->handle_std);
932  }
933  msg.match = (struct ofl_match_header*)&pkt->handle_std->match;
934 
935  // Increase packet-in counter and send the message.
936  m_cPacketIn++;
937  return dp_send_message(pkt->dp, (struct ofl_msg_header*)&msg, nullptr);
938 }
939 
940 bool
942  uint32_t portNo,
943  uint32_t queueNo)
944 {
945  NS_LOG_FUNCTION(this << pkt->ns3_uid << portNo);
946 
948  if (!port)
949  {
950  NS_LOG_ERROR("Can't forward packet to invalid port.");
951  return false;
952  }
953 
954  // When a packet is sent to OpenFlow pipeline, we keep track of its original
955  // ns3::Packet using the PipelinePacket structure. When the packet is
956  // processed by the pipeline with no internal changes, we forward the
957  // original ns3::Packet to the specified output port. When internal changes
958  // are necessary, we need to create a new packet with the modified content
959  // and copy all packet tags to this new one. This approach is more expensive
960  // than the previous one, but is far more simple than identifying which
961  // changes were performed in the packet to modify the original ns3::Packet.
962  Ptr<Packet> packet;
963  if (m_pipePkt.IsValid())
964  {
965  NS_ASSERT_MSG(m_pipePkt.HasId(pkt->ns3_uid), "Invalid packet ID.");
966  if (pkt->changes)
967  {
968  // The original ns-3 packet was modified by OpenFlow switch.
969  // Create a new packet with modified data and copy tags from the
970  // original packet.
971  NS_LOG_DEBUG("Packet " << pkt->ns3_uid << " modified by switch.");
972  packet = PacketFromBuffer(pkt->buffer);
974  }
975  else
976  {
977  // Using the original ns-3 packet.
978  packet = m_pipePkt.GetPacket();
979  }
980  }
981  else
982  {
983  // This is a new packet, probably created by the controller and sent to
984  // the switch within an OpenFlow packet-out message.
985  NS_ASSERT_MSG(pkt->ns3_uid == 0, "Invalid packet ID.");
986  NS_LOG_DEBUG("Creating new ns-3 packet from OpenFlow buffer.");
987  packet = PacketFromBuffer(pkt->buffer);
988  }
989 
990  // Send the packet to switch port.
991  return port->Send(packet, queueNo, pkt->tunnel_id);
992 }
993 
994 void
996  uint32_t portNo,
997  uint64_t tunnelId)
998 {
999  NS_LOG_FUNCTION(this << packet << portNo << tunnelId);
1000 
1001  NS_ASSERT_MSG(!m_pipePkt.IsValid(), "Another packet in pipeline.");
1002 
1003  // Creating the internal OpenFlow packet structure from ns-3 packet
1004  // Allocate buffer with some extra space for OpenFlow packet modifications.
1005  uint32_t headRoom = 128 + 2;
1006  uint32_t bodyRoom = packet->GetSize() + VLAN_ETH_HEADER_LEN;
1007  struct ofpbuf* buffer = BufferFromPacket(packet, bodyRoom, headRoom);
1008  struct packet* pkt =
1009  packet_create(m_datapath, portNo, buffer, tunnelId, false);
1010 
1011  // Save the ns-3 packet into pipeline structure. Note that we are using a
1012  // private packet uid to avoid conflicts with ns3::Packet uid.
1013  pkt->ns3_uid = OFSwitch13Device::GetNewPacketId();
1014  m_pipePkt.SetPacket(pkt->ns3_uid, packet);
1015 
1016  // Send the packet to pipeline.
1017  pipeline_process_packet(m_datapath->pipeline, pkt);
1018 }
1019 
1020 int
1022  Ptr<RemoteController> remoteCtrl)
1023 {
1024  if (!remoteCtrl->m_socket)
1025  {
1026  NS_LOG_ERROR("No controller connection. Discarding message.");
1027  return -1;
1028  }
1029 
1030  // TODO: No support for auxiliary connections.
1031  return remoteCtrl->m_handler->SendMessage(packet);
1032 }
1033 
1034 void
1036 {
1037  NS_LOG_FUNCTION(this << packet << from);
1038 
1039  struct ofl_msg_header* msg;
1040  ofl_err error;
1041 
1042  Ptr<RemoteController> remoteCtrl = GetRemoteController(from);
1043  NS_ASSERT_MSG(remoteCtrl, "Error returning controller for this address.");
1044 
1045  struct sender senderCtrl;
1046  senderCtrl.remote = remoteCtrl->m_remote;
1047  senderCtrl.conn_id = 0; // TODO No support for auxiliary connections
1048 
1049  // Get the OpenFlow buffer and unpack the message.
1050  struct ofpbuf* buffer = BufferFromPacket(packet, packet->GetSize());
1051  error = ofl_msg_unpack((uint8_t*)buffer->data,
1052  buffer->size,
1053  &msg,
1054  &senderCtrl.xid,
1055  m_datapath->exp);
1056 
1057  // Check for error while unpacking the message.
1058  if (error)
1059  {
1060  // The BOFUSS librady only unpacks messages that has the same
1061  // OFP_VERSION that is supported by the datapath implementation.
1062  // However, when an OpenFlow connection is first established, each side
1063  // of the connection must immediately send an OFPT_HELLO message with
1064  // the version field set to the highest OpenFlow switch protocol version
1065  // supported by the sender. Upon receipt of this message, the recipient
1066  // must calculate the OpenFlow switch protocol version to be used, and
1067  // the negotiated version must be the smaller of the version number that
1068  // was sent and the one that was received in the version fields. So, for
1069  // the OFPT_HELLO message, we will check for advertised version to see
1070  // if it is higher than ours, in which case we can continue.
1071  struct ofp_header* header = (struct ofp_header*)buffer->data;
1072  if (header->type != OFPT_HELLO || header->version <= OFP_VERSION)
1073  {
1074  // This is not a hello message or the advertised version is lower
1075  // than OFP_VERSION. Notify the error and return.
1076  ReplyWithErrorMessage(error, buffer, &senderCtrl);
1077  ofpbuf_delete(buffer);
1078  return;
1079  }
1080  else
1081  {
1082  // The advertised version is equal or higher than OFP_VERSION. Let's
1083  // change the message version to OFP_VERSION so the message can be
1084  // successfully unpacked and we can continue.
1085  header->version = OFP_VERSION;
1086  error = ofl_msg_unpack((uint8_t*)buffer->data,
1087  buffer->size,
1088  &msg,
1089  &senderCtrl.xid,
1090  m_datapath->exp);
1091 
1092  // Check for any other error while unpacking the message.
1093  if (error)
1094  {
1095  // Notify the error and return.
1096  ReplyWithErrorMessage(error, buffer, &senderCtrl);
1097  ofpbuf_delete(buffer);
1098  return;
1099  }
1100  }
1101  }
1102 
1103  // Print message content.
1104  char* msgStr = ofl_msg_to_string(msg, m_datapath->exp);
1106  NS_LOG_DEBUG("RX from controller " << ctrlIp << ": " << msgStr);
1107  free(msgStr);
1108 
1109  // Increase internal counters based on message type.
1110  switch (msg->type)
1111  {
1112  case (OFPT_PACKET_OUT): {
1113  m_cPacketOut++;
1114  break;
1115  }
1116  case (OFPT_FLOW_MOD): {
1117  m_cFlowMod++;
1118  break;
1119  }
1120  case (OFPT_METER_MOD): {
1121  m_cMeterMod++;
1122  break;
1123  }
1124  case (OFPT_GROUP_MOD): {
1125  m_cGroupMod++;
1126  break;
1127  }
1128  default: {
1129  }
1130  }
1131 
1132  // Send the message to handler.
1133  error = handle_control_msg(m_datapath, msg, &senderCtrl);
1134  if (error)
1135  {
1136  // It is assumed that if a handler returns with error, it did not use
1137  // any part of the control message, thus it can be freed up. If no error
1138  // is returned however, the message must be freed inside the handler
1139  // because the handler might keep parts of the message.
1140  ofl_msg_free(msg, m_datapath->exp);
1141  ReplyWithErrorMessage(error, buffer, &senderCtrl);
1142  }
1143 
1144  // If we got here, let's free the buffer.
1145  ofpbuf_delete(buffer);
1146 }
1147 
1148 int
1150  struct ofpbuf* buffer,
1151  struct sender* senderCtrl)
1152 {
1153  NS_LOG_FUNCTION(this << error);
1154 
1155  struct ofl_msg_error err;
1156  err.header.type = OFPT_ERROR;
1157  err.type = (enum ofp_error_type)ofl_error_type(error);
1158  err.code = ofl_error_code(error);
1159  err.data_length = buffer->size;
1160  err.data = (uint8_t*)buffer->data;
1161 
1162  char* msgStr = ofl_msg_to_string((struct ofl_msg_header*)&err, nullptr);
1163  NS_LOG_ERROR("Error processing OpenFlow message. Reply with " << msgStr);
1164  free(msgStr);
1165 
1166  return dp_send_message(m_datapath,
1167  (struct ofl_msg_header*)&err,
1168  senderCtrl);
1169 }
1170 
1171 void
1173 {
1174  NS_LOG_FUNCTION(this << socket);
1175 
1176  NS_LOG_INFO("Controller accepted connection request!");
1177  Ptr<RemoteController> remoteCtrl = GetRemoteController(socket);
1178  remoteCtrl->m_remote = remote_create(m_datapath);
1179 
1180  // As we have more than one socket that is used for communication between
1181  // this OpenFlow switch device and controllers, we need to handle the
1182  // process of sending/receiving OpenFlow messages to/from sockets in an
1183  // independent way. So, each socket has its own socket handler to this end.
1184  remoteCtrl->m_handler = CreateObject<OFSwitch13SocketHandler>(socket);
1185  remoteCtrl->m_handler->SetReceiveCallback(
1187 
1188  // Send the OpenFlow Hello message.
1189  struct ofl_msg_header msg;
1190  msg.type = OFPT_HELLO;
1191 
1192  struct sender senderCtrl;
1193  senderCtrl.remote = remoteCtrl->m_remote;
1194  senderCtrl.conn_id = 0; // TODO No support for auxiliary connections.
1195  senderCtrl.xid = 0;
1196  dp_send_message(m_datapath, &msg, &senderCtrl);
1197 }
1198 
1199 void
1201 {
1202  NS_LOG_FUNCTION(this << socket);
1203 
1204  NS_LOG_ERROR("Controller did not accepted connection request!");
1205 
1206  // Loop over controllers looking for the one associated to this socket and
1207  // remove it from the collection.
1208  for (auto it = m_controllers.begin(); it != m_controllers.end(); it++)
1209  {
1210  Ptr<RemoteController> remoteCtrl = *it;
1211  if (remoteCtrl->m_socket == socket)
1212  {
1213  m_controllers.erase(it);
1214  return;
1215  }
1216  }
1217 }
1218 
1219 void
1221 {
1222  NS_LOG_FUNCTION(this << entry->config->meter_id);
1223 
1224  // Update meter entry last_fill field with the time of last datapath
1225  // timeout, and force a new bucket refill based on this elapsed time.
1226  for (size_t i = 0; i < entry->config->meter_bands_num; i++)
1227  {
1228  entry->stats->band_stats[i]->last_fill =
1229  static_cast<uint64_t>(m_lastTimeout.GetMilliSeconds());
1230  }
1231  refill_bucket(entry);
1232 }
1233 
1234 void
1235 OFSwitch13Device::NotifyPacketCloned(struct packet* pkt, struct packet* clone)
1236 {
1237  NS_LOG_FUNCTION(this << pkt->ns3_uid);
1238 
1239  // Assigning a new unique ID for this cloned packet.
1240  clone->ns3_uid = OFSwitch13Device::GetNewPacketId();
1241  m_pipePkt.NewCopy(clone->ns3_uid);
1242 }
1243 
1244 void
1246 {
1247  NS_LOG_FUNCTION(this << pkt->ns3_uid);
1248 
1249  // This is the packet current under pipeline. Let's delete this copy.
1250  if (m_pipePkt.IsValid() && m_pipePkt.HasId(pkt->ns3_uid))
1251  {
1252  bool valid = m_pipePkt.DelCopy(pkt->ns3_uid);
1253  if (!valid)
1254  {
1255  NS_LOG_DEBUG("Packet " << pkt->ns3_uid << " done at this switch.");
1256  }
1257  return;
1258  }
1259 
1260  // This destroyed packet has no ns-3 ID. This packet was probably created by
1261  // the OpenFlow controller and sent to the switch within an OpenFlow
1262  // packet-out message. No action is required here.
1263  if (pkt->ns3_uid == 0)
1264  {
1265  NS_LOG_DEBUG("Deleting lib packet with no corresponding ns-3 packet.");
1266  return;
1267  }
1268 
1269  // If we got here, this packet must not be valid on the pipeline structure.
1270  NS_ASSERT_MSG((m_pipePkt.IsValid() && !m_pipePkt.HasId(pkt->ns3_uid)) ||
1271  !m_pipePkt.IsValid(),
1272  "Packet still valid in pipeline.");
1273 
1274  // This destroyed packet is probably an old packet that was previously saved
1275  // into buffer and will be deleted now, freeing up space for a new packet at
1276  // same buffer index (that's how the library handles the buffer). So, we are
1277  // going to remove this packet from our buffer, if it still exists there.
1278  BufferPacketDelete(pkt->ns3_uid);
1279  NS_LOG_DEBUG("Packet " << pkt->ns3_uid << " done at this switch.");
1280 }
1281 
1282 void
1284  struct meter_entry* entry)
1285 {
1286  NS_LOG_FUNCTION(this << pkt->ns3_uid << entry->stats->meter_id);
1287 
1288  uint32_t meterId = entry->stats->meter_id;
1289  NS_ASSERT_MSG(m_pipePkt.HasId(pkt->ns3_uid), "Invalid packet ID.");
1290  NS_LOG_DEBUG("OpenFlow meter id " << meterId << " dropped packet "
1291  << pkt->ns3_uid);
1292 
1293  // Fire drop trace source.
1294  m_meterDropTrace(m_pipePkt.GetPacket(), meterId);
1295 }
1296 
1297 void
1299  struct flow_table* table)
1300 {
1301  NS_LOG_FUNCTION(this << pkt->ns3_uid << table->stats->table_id);
1302 
1303  uint8_t tableId = table->stats->table_id;
1304  NS_ASSERT_MSG(m_pipePkt.HasId(pkt->ns3_uid), "Invalid packet ID.");
1305  NS_LOG_DEBUG("OpenFlow table id "
1306  << +tableId << " dropped unmatched packet " << pkt->ns3_uid);
1307 
1308  // Fire drop trace source.
1309  m_tableDropTrace(m_pipePkt.GetPacket(), tableId);
1310 }
1311 
1312 void
1314 {
1315  NS_LOG_FUNCTION(this << packetId);
1316 
1317  NS_ASSERT_MSG(m_pipePkt.HasId(packetId), "Invalid packet ID.");
1318 
1319  // Remove from pipeline and save into buffer.
1320  std::pair<uint64_t, Ptr<Packet>> entry(packetId, m_pipePkt.GetPacket());
1321  auto ret = m_bufferPkts.insert(entry);
1322  if (ret.second == true)
1323  {
1324  NS_LOG_DEBUG("Packet " << packetId << " saved into buffer.");
1326  }
1327  else
1328  {
1329  NS_LOG_WARN("Packet " << packetId << " already in buffer.");
1330  }
1331  m_pipePkt.DelCopy(packetId);
1332  NS_ASSERT_MSG(!m_pipePkt.IsValid(), "Packet copy still in pipeline.");
1333 
1334  // Scheduling the buffer remove for expired packet. Since packet timeout
1335  // resolution is expressed in seconds, let's double it to avoid rounding
1336  // conflicts.
1339  this,
1340  packetId);
1341 }
1342 
1343 void
1345 {
1346  NS_LOG_FUNCTION(this << packetId);
1347 
1348  NS_ASSERT_MSG(!m_pipePkt.IsValid(), "Another packet in pipeline.");
1349 
1350  // Find packet in buffer.
1351  auto it = m_bufferPkts.find(packetId);
1352  NS_ASSERT_MSG(it != m_bufferPkts.end(), "Packet not found in buffer.");
1353 
1354  // Save packet into pipeline structure.
1355  m_pipePkt.SetPacket(it->first, it->second);
1357 
1358  // Delete packet from buffer.
1359  NS_LOG_DEBUG("Packet " << packetId << " removed from buffer.");
1360  m_bufferPkts.erase(it);
1361 }
1362 
1363 void
1365 {
1366  NS_LOG_FUNCTION(this << packetId);
1367 
1368  // Delete from buffer map.
1369  auto it = m_bufferPkts.find(packetId);
1370  if (it != m_bufferPkts.end())
1371  {
1372  NS_LOG_DEBUG("Expired packet " << packetId << " deleted from buffer.");
1373  m_bufferExpireTrace(it->second);
1374  m_bufferPkts.erase(it);
1375  }
1376 }
1377 
1380 {
1381  NS_LOG_FUNCTION(this << socket);
1382 
1383  for (const auto& ctrl : m_controllers)
1384  {
1385  if (ctrl->m_socket == socket)
1386  {
1387  return ctrl;
1388  }
1389  }
1390  NS_ABORT_MSG("Error returning controller for this socket.");
1391 }
1392 
1395 {
1396  NS_LOG_FUNCTION(this << address);
1397 
1398  for (const auto& ctrl : m_controllers)
1399  {
1400  if (ctrl->m_address == address)
1401  {
1402  return ctrl;
1403  }
1404  }
1405  return nullptr;
1406 }
1407 
1410 {
1411  NS_LOG_FUNCTION(this << remote);
1412 
1413  for (const auto& ctrl : m_controllers)
1414  {
1415  if (ctrl->m_remote == remote)
1416  {
1417  return ctrl;
1418  }
1419  }
1420  NS_ABORT_MSG("Error returning controller for this remote pointer.");
1421 }
1422 
1423 uint64_t
1425 {
1426  return ++m_globalPktId;
1427 }
1428 
1429 bool
1431 {
1432  // Copy packet tags.
1433  PacketTagIterator pktIt = srcPkt->GetPacketTagIterator();
1434  while (pktIt.HasNext())
1435  {
1436  PacketTagIterator::Item item = pktIt.Next();
1437  Callback<ObjectBase*> constructor = item.GetTypeId().GetConstructor();
1438  Tag* tag = dynamic_cast<Tag*>(constructor());
1439  item.GetTag(*tag);
1440  dstPkt->AddPacketTag(*tag);
1441  delete tag;
1442  }
1443 
1444  // Copy byte tags.
1445  ByteTagIterator bytIt = srcPkt->GetByteTagIterator();
1446  while (bytIt.HasNext())
1447  {
1448  ByteTagIterator::Item item = bytIt.Next();
1449  Callback<ObjectBase*> constructor = item.GetTypeId().GetConstructor();
1450  Tag* tag = dynamic_cast<Tag*>(constructor());
1451  item.GetTag(*tag);
1452  dstPkt->AddByteTag(*tag);
1453  delete tag;
1454  }
1455 
1456  return true;
1457 }
1458 
1459 void
1461 {
1462  std::pair<uint64_t, Ptr<OFSwitch13Device>> entry(id, dev);
1463  auto ret = OFSwitch13Device::m_globalSwitchMap.insert(entry);
1464  NS_ABORT_MSG_IF(ret.second == false, "Error when registering datapath.");
1465 }
1466 
1467 void
1469 {
1470  auto it = OFSwitch13Device::m_globalSwitchMap.find(id);
1471  if (it != OFSwitch13Device::m_globalSwitchMap.end())
1472  {
1474  return;
1475  }
1476  NS_ABORT_MSG("Error when removing datapath.");
1477 }
1478 
1480  : m_socket(nullptr),
1481  m_handler(nullptr),
1482  m_remote(nullptr)
1483 {
1484  m_address = Address();
1485 }
1486 
1488  : m_valid(false),
1489  m_packet(nullptr)
1490 {
1491 }
1492 
1493 void
1495 {
1496  NS_ASSERT_MSG(id && packet, "Invalid packet metadata values.");
1497  m_valid = true;
1498  m_packet = packet;
1499  m_ids.emplace_back(id);
1500 }
1501 
1504 {
1505  NS_ASSERT_MSG(IsValid(), "Invalid packet metadata.");
1506  return m_packet;
1507 }
1508 
1509 void
1511 {
1512  m_valid = false;
1513  m_packet = nullptr;
1514  m_ids.clear();
1515 }
1516 
1517 bool
1519 {
1520  return m_valid;
1521 }
1522 
1523 void
1525 {
1526  NS_ASSERT_MSG(m_valid, "Invalid packet metadata.");
1527  m_ids.emplace_back(id);
1528 }
1529 
1530 bool
1532 {
1533  NS_ASSERT_MSG(m_valid, "Invalid packet metadata.");
1534 
1535  for (auto it = m_ids.begin(); it != m_ids.end(); it++)
1536  {
1537  if (*it == id)
1538  {
1539  m_ids.erase(it);
1540  break;
1541  }
1542  }
1543  if (m_ids.size() == 0)
1544  {
1545  Invalidate();
1546  }
1547  return m_valid;
1548 }
1549 
1550 bool
1552 {
1553  NS_ASSERT_MSG(m_valid, "Invalid packet metadata.");
1554 
1555  for (auto it = m_ids.begin(); it != m_ids.end(); it++)
1556  {
1557  if (*it == id)
1558  {
1559  return true;
1560  }
1561  }
1562  return false;
1563 }
1564 
1565 } // namespace ns3
#define min(a, b)
Definition: 80211b.c:42
a polymophic address class
Definition: address.h:100
bool IsInvalid() const
Definition: address.cc:71
Identifies a byte tag and a set of bytes within a packet to which the tag applies.
Definition: packet.h:64
void GetTag(Tag &tag) const
Read the requested tag and store it in the user-provided tag instance.
Definition: packet.cc:54
TypeId GetTypeId() const
Definition: packet.cc:36
Iterator over the set of byte tags in a packet.
Definition: packet.h:57
bool HasNext() const
Definition: packet.cc:72
Callback template class.
Definition: callback.h:443
Class for representing data rates.
Definition: data-rate.h:90
uint64_t GetBitRate() const
Get the underlying bitrate.
Definition: data-rate.cc:305
AttributeValue implementation for DataRate.
static bool IsMatchingType(const Address &address)
Ipv4Address GetIpv4() const
static InetSocketAddress ConvertFrom(const Address &address)
Returns an InetSocketAddress which corresponds to the input Address.
Ipv4 addresses are stored in host order in this class.
Definition: ipv4-address.h:43
RemoteController()
Default (empty) constructor.
Address m_address
Controller address.
An OpenFlow 1.3 device that switches multiple CSMA segments via OpenFlow protocol.
CtrlList_t m_controllers
Collection of active controllers.
struct datapath * GetDatapathStruct()
Get a pointer to the internal BOFUSS datapath structure.
Ptr< OFSwitch13Port > GetSwitchPort(uint32_t no) const
Get the OFSwitch13Port pointer from its number.
static void BufferSaveCallback(struct packet *pkt, time_t timeout)
Callback fired when a packet is saved into buffer.
void SocketCtrlFailed(Ptr< Socket > socket)
Socket callback fired when a TCP connection to controller fail.
double GetCpuUsage() const
TracedCallback signature for packets dropped by meter bands.
uint32_t GetBufferEntries() const
TracedCallback signature for packets dropped by meter bands.
uint32_t m_numPipeTabs
Number of pipeline flow tables.
uint64_t m_cpuConsumed
CPU processing tokens consumed.
uint32_t GetGroupTableSize() const
TracedCallback signature for packets dropped by meter bands.
IdPacketMap_t m_bufferPkts
Packets saved in switch buffer.
TracedCallback< Ptr< const Packet > > m_pipePacketTrace
Trace source fired when a packet is sent to pipeline.
uint32_t GetFlowTableEntries(uint8_t tableId) const
TracedCallback signature for packets dropped by meter bands.
TracedValue< DataRate > m_cpuLoad
Average CPU processing load.
uint32_t GetMeterTableSize() const
TracedCallback signature for packets dropped by meter bands.
void SetFlowTableSize(uint8_t tableId, uint32_t value)
Structure to save the list of ports in this datapath.
void DoDispose() override
TracedCallback signature for packets dropped by meter bands.
uint32_t GetNSwitchPorts() const
TracedCallback signature for packets dropped by meter bands.
static void PacketDestroyCallback(struct packet *pkt)
Callback fired when a packet is destroyed.
double GetBufferUsage() const
TracedCallback signature for packets dropped by meter bands.
PipelinePacket m_pipePkt
Packet under switch pipeline.
Ptr< OFSwitch13Device::RemoteController > GetRemoteController(Ptr< Socket > socket)
Get the remote controller for this socket.
void SendToPipeline(Ptr< Packet > packet, uint32_t portNo, uint64_t tunnelId=0)
Send the packet to the OpenFlow BOFUSS pipeline.
void NotifyPacketDroppedByMeter(struct packet *pkt, struct meter_entry *entry)
Notify this device of a packet dropped by OpenFlow meter band.
double GetFlowTableUsage(uint8_t tableId) const
TracedCallback signature for packets dropped by meter bands.
void DatapathTimeout(struct datapath *dp)
Check if any flow in any table is timed out and update port status.
void SocketCtrlSucceeded(Ptr< Socket > socket)
Socket callback fired when a TCP connection to controller succeed.
uint64_t GetFlowModCounter() const
TracedCallback< Ptr< const OFSwitch13Device > > m_datapathTimeoutTrace
Trace source fired when the datapath timeout operation is completed.
Time GetDatapathTimeout() const
TracedCallback signature for packets dropped by meter bands.
void ReceiveFromSwitchPort(Ptr< Packet > packet, uint32_t portNo, uint64_t tunnelId=0)
Called when a packet is received on one of the switch's ports.
void ReceiveFromController(Ptr< Packet > packet, Address from)
Receive an OpenFlow packet from controller.
uint32_t GetNControllers() const
TracedCallback signature for packets dropped by meter bands.
static Ptr< OFSwitch13Device > GetDevice(uint64_t id)
Retrieve and existing OpenFlow device object by its datapath ID.
TracedCallback< Ptr< const Packet >, uint8_t > m_tableDropTrace
Trace source fired when an unmatched packet is dropped by flow table.
static void MeterCreatedCallback(struct meter_entry *entry)
Callback fired when a new meter entry is created at meter table.
OFSwitch13Device()
Default constructor.
double GetMeterTableUsage() const
TracedCallback signature for packets dropped by meter bands.
PortList_t m_ports
List of switch ports.
double GetGroupTableUsage() const
TracedCallback signature for packets dropped by meter bands.
void BufferPacketSave(uint64_t packetId, time_t timeout)
Notify this device of a packet saved into buffer.
void NotifyMeterEntryCreated(struct meter_entry *entry)
Notify this device of a new meter entry created at meter table.
void NotifyPacketCloned(struct packet *pkt, struct packet *clone)
Notify this device of a packet cloned by the OpenFlow pipeline.
static void RegisterDatapath(uint64_t id, Ptr< OFSwitch13Device > dev)
Insert a new OpenFlow device in global map.
uint32_t GetGroupTableEntries() const
TracedCallback signature for packets dropped by meter bands.
Time m_timeout
Datapath timeout interval.
static uint64_t m_globalDpId
Global counter for datapath IDs.
DataRate GetCpuLoad() const
TracedCallback signature for packets dropped by meter bands.
TracedValue< uint32_t > m_groupEntries
Number of entries in group table.
TracedCallback< Ptr< const Packet > > m_bufferSaveTrace
Trace source fired when a packet is saved into buffer.
void StartControllerConnection(Address ctrlAddr)
Starts the TCP connection between this switch and the target controller indicated by the address para...
void NotifyPacketDestroyed(struct packet *pkt)
Notify this device of a packet destroyed by the OpenFlow pipeline.
TracedCallback< Ptr< const Packet > > m_loadDropTrace
Trace source fired when a packet is dropped due to overloaded switch.
void BufferPacketRetrieve(uint64_t packetId)
Notify this device of a packet retrieved from buffer.
Ptr< OFSwitch13Port > AddSwitchPort(Ptr< NetDevice > portDevice)
Add a 'port' to the switch device.
uint64_t m_cGroupMod
Pipeline group mod counter.
static uint64_t m_globalPktId
Global counter for packets IDs.
uint64_t m_cPacketIn
Pipeline packet in counter.
DataRate GetCpuCapacity() const
TracedCallback signature for packets dropped by meter bands.
Time m_tcamDelay
Flow Table TCAM lookup delay.
uint32_t m_meterTabSize
Meter table maximum entries.
int SendPacketInMessage(struct packet *pkt, uint8_t tableId, uint8_t reason, uint16_t maxLength, uint64_t cookie=0)
Create an OpenFlow packet in message and send the packet to all controllers with open connections.
void SetGroupTableSize(uint32_t value)
Structure to save the list of ports in this datapath.
static void BufferRetrieveCallback(struct packet *pkt)
Callback fired when a packet is retrieved from buffer.
TracedValue< uint32_t > m_sumFlowEntries
Sum of entries in all flow tables.
uint32_t GetMeterTableEntries() const
TracedCallback signature for packets dropped by meter bands.
void NotifyPacketDroppedByTable(struct packet *pkt, struct flow_table *table)
Notify this device of an unmatched packet dropped by OpenFlow flow table without a table-miss entry.
struct datapath * DatapathNew()
Creates a new datapath.
static void MeterDropCallback(struct packet *pkt, struct meter_entry *entry)
Callback fired when a packet is dropped by meter band.
static void UnregisterDatapath(uint64_t id)
Remove an existing OpenFlow device from global map.
static void TableDropCallback(struct packet *pkt, struct flow_table *table)
Callback fired when an unmatched packet is dropped by a flow table without a table-miss entry.
struct datapath * m_datapath
BOFUSS datapath structure.
uint64_t m_cMeterMod
Pipeline meter mod counter.
static uint64_t GetNewPacketId()
Increase the global packet ID counter and return a new packet ID.
~OFSwitch13Device() override
Dummy destructor, see DoDispose.
uint64_t GetPacketInCounter() const
TracedValue< Time > m_pipeDelay
Average delay for pipeline packet processing.
uint64_t GetDatapathId() const
Get the OpenFlow datapath ID.
void NotifyConstructionCompleted() override
TracedCallback signature for packets dropped by meter bands.
uint64_t m_cFlowMod
Pipeline flow mod counter.
int ReplyWithErrorMessage(ofl_err error, struct ofpbuf *buffer, struct sender *senderCtrl)
Create an OpenFlow error message and send it back to the sender controller.
uint32_t m_flowTabSize
Flow table maximum entries.
uint64_t GetPacketOutCounter() const
uint32_t m_groupTabSize
Group table maximum entries.
static bool CopyTags(Ptr< const Packet > srcPkt, Ptr< const Packet > dstPkt)
Copy all tags (packet and byte) from srcPkt packet to dstPkt packet.
static void DpActionsOutputPort(struct packet *pkt, uint32_t outPort, uint32_t outQueue, uint16_t maxLength, uint64_t cookie)
Overriding BOFUSS dp_actions_output_port weak function from udatapath/dp_actions.c.
static int SendOpenflowBufferToRemote(struct ofpbuf *buffer, struct remote *remote)
Overriding BOFUSS send_openflow_buffer_to_remote weak function from udatapath/datapath....
std::map< uint64_t, Ptr< OFSwitch13Device > > DpIdDevMap_t
Structure to map datapath id to OpenFlow device.
uint32_t m_bufferSize
Buffer size in terms of packets.
static TypeId GetTypeId()
Register this type.
void BufferPacketDelete(uint64_t packetId)
Delete the ns-3 packet from buffer map.
uint64_t m_cPacketOut
Pipeline packet out counter.
void SetMeterTableSize(uint32_t value)
Structure to save the list of ports in this datapath.
uint64_t GetDpId() const
Alias for the GetDatapathId () method.
uint64_t m_cpuTokens
CPU processing tokens available.
int SendToController(Ptr< Packet > packet, Ptr< OFSwitch13Device::RemoteController > remoteCtrl)
Send a packet to the controller node.
Time m_lastTimeout
Datapath last timeout.
bool SendToSwitchPort(struct packet *pkt, uint32_t portNo, uint32_t queueNo=0)
Send a message over a specific switch port.
TracedCallback< Ptr< const Packet > > m_bufferRetrieveTrace
Trace source fired when a packet is retrieved from buffer.
uint64_t GetGroupModCounter() const
TracedCallback< Ptr< const Packet > > m_bufferExpireTrace
Trace source fired when a packet in buffer expires.
static void SendPacketToController(struct pipeline *pl, struct packet *pkt, uint8_t tableId, uint8_t reason)
Overriding BOFUSS send_packet_to_controller weak function from udatapath/pipeline....
uint32_t GetNPipelineTables() const
TracedCallback signature for packets dropped by meter bands.
uint32_t GetSumFlowEntries() const
TracedCallback signature for packets dropped by meter bands.
static DpIdDevMap_t m_globalSwitchMap
As the integration of BOFUSS and ns-3 involve overriding some C functions, we are using a global map ...
TracedCallback< Ptr< const Packet >, uint32_t > m_meterDropTrace
Trace source fired when a packet is dropped by a meter band.
uint64_t m_dpId
This datapath id.
uint32_t GetDftFlowTableSize() const
TracedCallback signature for packets dropped by meter bands.
static void PacketCloneCallback(struct packet *pkt, struct packet *clone)
Callback fired when a packet is cloned.
uint32_t GetBufferSize() const
TracedCallback signature for packets dropped by meter bands.
TracedValue< uint32_t > m_meterEntries
Number of entries in meter table.
uint64_t GetMeterModCounter() const
uint32_t GetFlowTableSize(uint8_t tableId) const
TracedCallback signature for packets dropped by meter bands.
Time GetPipelineDelay() const
TracedCallback signature for packets dropped by meter bands.
void SetDftFlowTableSize(uint32_t value)
Structure to save the list of ports in this datapath.
DataRate m_cpuCapacity
CPU processing capacity.
uint32_t GetPortNo() const
Get the OpenFlow port number for this port.
virtual void NotifyConstructionCompleted()
Notifier called once the ObjectBase is fully constructed.
Definition: object-base.cc:75
void SetAttribute(std::string name, const AttributeValue &value)
Set a single attribute, raising fatal errors if unsuccessful.
Definition: object-base.cc:200
A base class which provides memory management and object aggregation.
Definition: object.h:89
virtual void DoDispose()
Destructor implementation.
Definition: object.cc:353
PacketTagIterator GetPacketTagIterator() const
Returns an object which can be used to iterate over the list of packet tags.
Definition: packet.cc:1039
uint32_t GetSize() const
Returns the the size in bytes of the packet (including the zero-filled initial payload).
Definition: packet.h:863
void AddPacketTag(const Tag &tag) const
Add a packet tag.
Definition: packet.cc:979
void AddByteTag(const Tag &tag) const
Tag each byte included in this packet with a new byte tag.
Definition: packet.cc:934
ByteTagIterator GetByteTagIterator() const
Returns an iterator over the set of byte tags included in this packet.
Definition: packet.cc:956
Identifies a packet tag within a packet.
Definition: packet.h:143
TypeId GetTypeId() const
Definition: packet.cc:118
void GetTag(Tag &tag) const
Read the requested tag and store it in the user-provided tag instance.
Definition: packet.cc:124
Iterator over the set of packet tags in a packet.
Definition: packet.h:137
bool HasNext() const
Definition: packet.cc:98
Smart pointer class similar to boost::intrusive_ptr.
Definition: ptr.h:78
static EventId Schedule(const Time &delay, FUNC f, Ts &&... args)
Schedule an event to expire after delay.
Definition: simulator.h:568
static Time Now()
Return the current simulation virtual time.
Definition: simulator.cc:199
virtual int Connect(const Address &address)=0
Initiate a connection to a remote host.
static Ptr< Socket > CreateSocket(Ptr< Node > node, TypeId tid)
This method wraps the creation of sockets that is performed on a given node by a SocketFactory specif...
Definition: socket.cc:72
virtual int Bind(const Address &address)=0
Allocate a local endpoint for this socket.
void SetConnectCallback(Callback< void, Ptr< Socket >> connectionSucceeded, Callback< void, Ptr< Socket >> connectionFailed)
Specify callbacks to allow the caller to determine if the connection succeeds of fails.
Definition: socket.cc:85
tag a set of bytes in a packet
Definition: tag.h:39
Simulation virtual time values and global simulation resolution.
Definition: nstime.h:105
int64_t GetMilliSeconds() const
Get an approximation of the time stored in this instance in the indicated unit.
Definition: nstime.h:407
double GetSeconds() const
Get an approximation of the time stored in this instance in the indicated unit.
Definition: nstime.h:402
@ S
second
Definition: nstime.h:116
static Time FromInteger(uint64_t value, Unit unit)
Create a Time equal to value in unit unit.
Definition: nstime.h:498
AttributeValue implementation for Time.
Definition: nstime.h:1423
a unique identifier for an interface.
Definition: type-id.h:60
static TypeId LookupByName(std::string name)
Get a TypeId by name.
Definition: type-id.cc:839
@ ATTR_GET
The attribute can be read.
Definition: type-id.h:65
@ ATTR_CONSTRUCT
The attribute can be written at construction-time.
Definition: type-id.h:67
Callback< ObjectBase * > GetConstructor() const
Get the constructor callback.
Definition: type-id.cc:1088
TypeId SetParent(TypeId tid)
Set the parent TypeId.
Definition: type-id.cc:935
Hold an unsigned integer type.
Definition: uinteger.h:45
uint16_t port
Definition: dsdv-manet.cc:45
#define NS_ASSERT(condition)
At runtime, in debugging builds, if this condition is not true, the program prints the source file,...
Definition: assert.h:66
#define NS_ASSERT_MSG(condition, message)
At runtime, in debugging builds, if this condition is not true, the program prints the message to out...
Definition: assert.h:86
ObjectPtrContainerValue ObjectVectorValue
ObjectVectorValue is an alias for ObjectPtrContainerValue.
Definition: object-vector.h:40
Ptr< const AttributeAccessor > MakeObjectVectorAccessor(U T::*memberVariable)
MakeAccessorHelper implementation for ObjectVector.
Definition: object-vector.h:76
Ptr< const AttributeAccessor > MakeTimeAccessor(T1 a1)
Create an AttributeAccessor for a class data member, or a lone class get functor or set method.
Definition: nstime.h:1424
Ptr< const AttributeAccessor > MakeUintegerAccessor(T1 a1)
Create an AttributeAccessor for a class data member, or a lone class get functor or set method.
Definition: uinteger.h:46
#define NS_ABORT_MSG(msg)
Unconditional abnormal program termination with a message.
Definition: abort.h:49
#define NS_ABORT_MSG_IF(cond, msg)
Abnormal program termination if a condition is true, with a message.
Definition: abort.h:108
#define NS_LOG_ERROR(msg)
Use NS_LOG to output a message of level LOG_ERROR.
Definition: log.h:254
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
Definition: log.h:202
#define NS_LOG_DEBUG(msg)
Use NS_LOG to output a message of level LOG_DEBUG.
Definition: log.h:268
#define NS_LOG_FUNCTION(parameters)
If log level LOG_FUNCTION is enabled, this macro will output all input parameters separated by ",...
#define NS_LOG_WARN(msg)
Use NS_LOG to output a message of level LOG_WARN.
Definition: log.h:261
#define NS_LOG_INFO(msg)
Use NS_LOG to output a message of level LOG_INFO.
Definition: log.h:275
void(* DataRate)(DataRate oldValue, DataRate newValue)
TracedValue callback signature for DataRate.
Definition: data-rate.h:328
#define NS_OBJECT_ENSURE_REGISTERED(type)
Register an Object subclass with the TypeId system.
Definition: object-base.h:46
Ptr< Packet > PacketFromBuffer(struct ofpbuf *buffer)
Create a new ns3::Packet from internal BOFUSS buffer.
struct ofpbuf * BufferFromPacket(Ptr< const Packet > packet, size_t bodyRoom, size_t headRoom)
Create an internal BOFUSS buffer from ns3::Packet.
Time MicroSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition: nstime.h:1360
Time MilliSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition: nstime.h:1348
Ptr< const TraceSourceAccessor > MakeTraceSourceAccessor(T a)
Create a TraceSourceAccessor which will control access to the underlying trace source.
address
Definition: first.py:40
void(* Time)(Time oldValue, Time newValue)
TracedValue callback signature for Time.
Definition: nstime.h:848
Every class exported by the ns3 library is enclosed in the ns3 namespace.
Callback< R, Args... > MakeCallback(R(T::*memPtr)(Args...), OBJ objPtr)
Build Callbacks for class method members which take varying numbers of arguments and potentially retu...
Definition: callback.h:707
Ptr< const AttributeChecker > MakeTimeChecker(const Time min, const Time max)
Helper to make a Time checker with bounded range.
Definition: time.cc:535
value
Definition: second.py:41
time_t time_now(void)
Overriding BOFUSS time_now weak function from timeval.c.
ns3::Time timeout
void SetPacket(uint64_t id, Ptr< Packet > packet)
Save packet metadata.
bool DelCopy(uint64_t id)
Delete an existing copy for this packet.
PipelinePacket()
Default (empty) constructor.
bool HasId(uint64_t id)
Check for packet id in the internal list of IDs for this packet.
void Invalidate()
Invalidate packet metatada.
bool IsValid() const
Check for valid packet metadata.
void NewCopy(uint64_t id)
Notify a new copy for this packet, with a new unique ID.