A Discrete-Event Network Simulator
API
ofswitch13-port.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-port.h"
21 
22 #include "ofswitch13-device.h"
23 #include "queue-tag.h"
24 #include "tunnel-id-tag.h"
25 
26 #include <ns3/csma-net-device.h>
27 #include <ns3/ethernet-header.h>
28 #include <ns3/ethernet-trailer.h>
29 #include <ns3/pointer.h>
30 #include <ns3/virtual-net-device.h>
31 
32 #undef NS_LOG_APPEND_CONTEXT
33 #define NS_LOG_APPEND_CONTEXT \
34  std::clog << "[dp " << m_dpId << " port " << m_portNo << "] ";
35 
36 namespace ns3
37 {
38 
39 NS_LOG_COMPONENT_DEFINE("OFSwitch13Port");
40 NS_OBJECT_ENSURE_REGISTERED(OFSwitch13Port);
41 
42 static ObjectFactory
44 {
45  // Setting default internal queue configuration.
46  ObjectFactory queueFactory;
47  queueFactory.SetTypeId("ns3::OFSwitch13PriorityQueue");
48  return queueFactory;
49 }
50 
52  : m_dpId(0),
53  m_portNo(0),
54  m_swPort(nullptr),
55  m_netDev(nullptr),
56  m_openflowDev(nullptr)
57 {
58  NS_LOG_FUNCTION(this);
59 }
60 
62 {
63  NS_LOG_FUNCTION(this);
64 }
65 
66 void
68 {
69  NS_LOG_FUNCTION(this);
70 
71  m_portQueue->Dispose();
72  if (m_swPort)
73  {
74  ofl_structs_free_port(m_swPort->conf);
75  free(m_swPort->stats);
76  }
77 
78  m_swPort = nullptr;
79  m_openflowDev = nullptr;
80  m_netDev = nullptr;
81 }
82 
83 TypeId
85 {
86  static TypeId tid =
87  TypeId("ns3::OFSwitch13Port")
88  .SetParent<Object>()
89  .SetGroupName("OFSwitch13")
90  .AddConstructor<OFSwitch13Port>()
91  .AddAttribute(
92  "PortQueue",
93  "The OpenFlow queue to use as the TX queue in this port.",
94  PointerValue(),
96  MakePointerChecker<OFSwitch13Queue>())
97  .AddAttribute(
98  "QueueFactory",
99  "The object factory for the OpenFlow queue.",
104 
105  .AddTraceSource(
106  "SwitchPortRx",
107  "Trace source indicating a packet received at this port.",
109  "ns3::Packet::TracedCallback")
110  .AddTraceSource(
111  "SwitchPortTx",
112  "Trace source indicating a packet sent at this port.",
114  "ns3::Packet::TracedCallback");
115  return tid;
116 }
117 
118 OFSwitch13Port::OFSwitch13Port(struct datapath* dp,
119  Ptr<NetDevice> netDev,
120  Ptr<OFSwitch13Device> openflowDev)
121  : m_dpId(0),
122  m_portNo(0),
123  m_swPort(nullptr),
124  m_netDev(netDev),
125  m_openflowDev(openflowDev)
126 {
127  NS_LOG_FUNCTION(this << netDev << openflowDev);
128 
129  m_dpId = dp->id;
130  m_portNo = ++(dp->ports_num);
131  m_swPort = &dp->ports[m_portNo];
132  memset(m_swPort, '\0', sizeof *m_swPort);
133 
134  // Saving datapath pointer.
135  m_swPort->dp = dp;
136 }
137 
138 void
140 {
141  NS_LOG_FUNCTION(this);
142 
143  // Check for valid NetDevice type
144  Ptr<CsmaNetDevice> csmaDev = m_netDev->GetObject<CsmaNetDevice>();
145  Ptr<VirtualNetDevice> virtDev = m_netDev->GetObject<VirtualNetDevice>();
146  NS_ABORT_MSG_IF(!csmaDev && !virtDev,
147  "NetDevice must be CsmaNetDevice or VirtualNetDevice.");
148 
149  // Filling BOFUSS internal structures for this port.
150  size_t oflPortSize = sizeof(struct ofl_port);
151  size_t oflPortStatsSize = sizeof(struct ofl_port_stats);
152 
153  m_swPort->conf = (struct ofl_port*)xmalloc(oflPortSize);
154  memset(m_swPort->conf, 0x00, oflPortSize);
155  m_swPort->conf->port_no = m_portNo;
156  m_swPort->conf->name = (char*)xmalloc(OFP_MAX_PORT_NAME_LEN);
157  snprintf(m_swPort->conf->name, OFP_MAX_PORT_NAME_LEN, "Port %d", m_portNo);
158  m_netDev->GetAddress().CopyTo(m_swPort->conf->hw_addr);
159  m_swPort->conf->config = 0x00000000;
160  m_swPort->conf->state = 0x00000000 | OFPPS_LIVE;
161  m_swPort->conf->curr = GetPortFeatures();
162  m_swPort->conf->advertised = GetPortFeatures();
163  m_swPort->conf->supported = GetPortFeatures();
164  m_swPort->conf->peer = 0x00000000; // FIXME no information about peer port
165  m_swPort->conf->curr_speed = port_speed(m_swPort->conf->curr);
166  m_swPort->conf->max_speed = port_speed(m_swPort->conf->supported);
167 
168  dp_port_live_update(m_swPort);
169 
170  m_swPort->stats = (struct ofl_port_stats*)xmalloc(oflPortStatsSize);
171  memset(m_swPort->stats, 0x00, oflPortStatsSize);
172  m_swPort->stats->port_no = m_portNo;
173  m_swPort->flags |= SWP_USED;
174 
175  // To avoid a null check failure in BOFUSS
176  // dp_ports_handle_stats_request_port (), we are pointing m_swPort->netdev
177  // to corresponding ns3::NetDevice, but this pointer must not be used!
178  m_swPort->netdev = (struct netdev*)PeekPointer(m_netDev);
179 
180  // Creating the OFSwitch13Queue for this switch port
181  memset(m_swPort->queues, 0x00, sizeof(m_swPort->queues));
182  m_swPort->max_queues = m_swPort->dp->max_queues;
183  m_swPort->num_queues = 0;
185  m_portQueue->SetPortStruct(m_swPort);
186  m_portQueue->Initialize();
187  if (csmaDev)
188  {
189  csmaDev->SetQueue(m_portQueue);
190  }
191 
192  m_swPort->created = time_msec();
193 
194  list_push_back(&m_swPort->dp->port_list, &m_swPort->node);
195 
196  // Notify the controller that this port has been added/created
197  struct ofl_msg_port_status msg;
198  msg.header.type = OFPT_PORT_STATUS;
199  msg.reason = OFPPR_ADD;
200  msg.desc = m_swPort->conf;
201  dp_send_message(m_swPort->dp, (struct ofl_msg_header*)&msg, nullptr);
202 
203  // Register the receive callback to get packets from the NetDevice.
204  if (csmaDev)
205  {
206  csmaDev->SetOpenFlowReceiveCallback(
208  }
209  else
210  {
211  NS_ASSERT(virtDev);
212  virtDev->SetOpenFlowReceiveCallback(
214  }
215 }
216 
219 {
220  return m_netDev;
221 }
222 
223 uint32_t
225 {
226  return m_portNo;
227 }
228 
231 {
232  return m_portQueue;
233 }
234 
237 {
238  return m_openflowDev;
239 }
240 
241 bool
243 {
244  uint32_t orig_state = m_swPort->conf->state;
245  if (m_netDev->IsLinkUp())
246  {
247  m_swPort->conf->state &= ~OFPPS_LINK_DOWN;
248  }
249  else
250  {
251  m_swPort->conf->state |= OFPPS_LINK_DOWN;
252  }
253  dp_port_live_update(m_swPort);
254 
255  if (orig_state != m_swPort->conf->state)
256  {
257  NS_LOG_INFO("Port status has changed. Notifying the controller.");
258  struct ofl_msg_port_status msg;
259  msg.header.type = OFPT_PORT_STATUS;
260  msg.reason = OFPPR_MODIFY;
261  msg.desc = m_swPort->conf;
262  dp_send_message(m_swPort->dp, (struct ofl_msg_header*)&msg, nullptr);
263  return true;
264  }
265  return false;
266 }
267 
268 uint32_t
270 {
271  NS_LOG_FUNCTION(this);
272 
273  DataRate dr;
274  Ptr<Channel> channel = m_netDev->GetChannel();
275  if (channel)
276  {
277  Ptr<CsmaChannel> csmaChannel = channel->GetObject<CsmaChannel>();
278  if (csmaChannel)
279  {
280  DataRateValue drv;
281  csmaChannel->GetAttribute("DataRate", drv);
282  dr = drv.Get();
283  }
284  }
285 
286  uint32_t feat = 0x00000000;
287  feat |= OFPPF_COPPER;
288  feat |= OFPPF_AUTONEG;
289 
290  if (dr == DataRate("10Mbps"))
291  {
292  feat |= OFPPF_10MB_FD;
293  }
294  else if (dr == DataRate("100Mbps"))
295  {
296  feat |= OFPPF_100MB_FD;
297  }
298  else if (dr == DataRate("1Gbps"))
299  {
300  feat |= OFPPF_1GB_FD;
301  }
302  else if (dr == DataRate("10Gbps"))
303  {
304  feat |= OFPPF_10GB_FD;
305  }
306  else if (dr == DataRate("40Gbps"))
307  {
308  feat |= OFPPF_40GB_FD;
309  }
310  else if (dr == DataRate("100Gbps"))
311  {
312  feat |= OFPPF_100GB_FD;
313  }
314  else if (dr == DataRate("1000Gbps"))
315  {
316  feat |= OFPPF_1TB_FD;
317  }
318  else
319  {
320  feat |= OFPPF_OTHER;
321  }
322  return feat;
323 }
324 
325 bool
327  Ptr<const Packet> packet,
328  uint16_t protocol,
329  const Address& from,
330  const Address& to,
331  NetDevice::PacketType packetType)
332 {
333  NS_LOG_FUNCTION(this << packet);
334 
335  // Check port configuration.
336  if ((m_swPort->conf->config & (OFPPC_NO_RECV | OFPPC_PORT_DOWN)) != 0)
337  {
338  NS_LOG_WARN("This port is down or inoperating. Discarding packet");
339  return false;
340  }
341 
342  // Update port stats
343  m_swPort->stats->rx_packets++;
344  m_swPort->stats->rx_bytes += packet->GetSize();
345 
346  // Fire RX trace source
347  m_rxTrace(packet);
348  NS_LOG_DEBUG("Pkt " << packet->GetUid() << " received at this port.");
349 
350  // Retrieve the tunnel id from packet, if available.
351  Ptr<Packet> localPacket = packet->Copy();
352  TunnelIdTag tunnelIdTag;
353  localPacket->PeekPacketTag(tunnelIdTag);
354  uint64_t tunnelId = tunnelIdTag.GetTunnelId();
355  NS_LOG_DEBUG("Pkt tunnel id is " << tunnelId);
356 
357  // Send the packet to the OpenFlow pipeline
358  NS_LOG_DEBUG("Pkt copy " << localPacket->GetUid() << " sent to pipeline.");
359  m_openflowDev->ReceiveFromSwitchPort(localPacket, m_portNo, tunnelId);
360  return true;
361 }
362 
363 bool
365  uint32_t queueNo,
366  uint64_t tunnelId)
367 {
368  NS_LOG_FUNCTION(this << packet << queueNo << tunnelId);
369 
370  if (m_swPort->conf->config & (OFPPC_PORT_DOWN))
371  {
372  NS_LOG_WARN("This port is down. Discarding packet");
373  return false;
374  }
375 
376  // Fire TX trace source (with complete packet)
377  m_txTrace(packet);
378 
379  Ptr<Packet> packetCopy = packet->Copy();
380  NS_LOG_DEBUG("Pkt " << packetCopy->GetUid()
381  << " will be sent at this port.");
382 
383  // Removing the Ethernet header and trailer from packet, which will be
384  // included again by CsmaNetDevice
385  EthernetTrailer trailer;
386  packetCopy->RemoveTrailer(trailer);
387  EthernetHeader header;
388  packetCopy->RemoveHeader(header);
389 
390  // Tagging the packet with queue and tunnel ids.
391  QueueTag queueTag(queueNo);
392  packetCopy->ReplacePacketTag(queueTag);
393  NS_LOG_DEBUG("Pkt queue will be " << queueNo);
394 
395  TunnelIdTag tunnelIdTag(tunnelId);
396  packetCopy->ReplacePacketTag(tunnelIdTag);
397  NS_LOG_DEBUG("Pkt tunnel tag will be " << tunnelId);
398 
399  // Send the packet over the underlying net device.
400  bool status = m_netDev->SendFrom(packetCopy,
401  header.GetSource(),
402  header.GetDestination(),
403  header.GetLengthType());
404  // Updating port statistics
405  if (status)
406  {
407  m_swPort->stats->tx_packets++;
408  m_swPort->stats->tx_bytes += packetCopy->GetSize();
409  }
410  else
411  {
412  m_swPort->stats->tx_dropped++;
413  }
414  return status;
415 }
416 
417 struct sw_port*
419 {
420  return m_swPort;
421 }
422 
423 } // namespace ns3
a polymophic address class
Definition: address.h:100
Csma Channel.
Definition: csma-channel.h:93
A Device for a Csma Network Link.
Class for representing data rates.
Definition: data-rate.h:90
AttributeValue implementation for DataRate.
Packet header for Ethernet.
uint16_t GetLengthType() const
Mac48Address GetDestination() const
Mac48Address GetSource() const
Packet trailer for Ethernet.
PacketType
Packet types are used as they are in Linux.
Definition: net-device.h:300
A OpenFlow switch port, interconnecting the underlying NetDevice to the OpenFlow device through the O...
static TypeId GetTypeId()
Register this type.
uint32_t m_portNo
Port number.
bool Send(Ptr< const Packet > packet, uint32_t queueNo=0, uint64_t tunnelId=0)
Send a packet over this OpenFlow switch port.
struct sw_port * m_swPort
BOFUSS port structure.
TracedCallback< Ptr< const Packet > > m_rxTrace
Trace source fired when a packet arrives at this switch port.
~OFSwitch13Port() override
Dummy destructor, see DoDispose.
Ptr< OFSwitch13Queue > m_portQueue
OpenFlow port Queue.
Ptr< OFSwitch13Device > m_openflowDev
OpenFlow device.
ObjectFactory m_factQueue
Factory for port queue.
void NotifyConstructionCompleted() override
Notifier called once the ObjectBase is fully constructed.
TracedCallback< Ptr< const Packet > > m_txTrace
Trace source fired when a packet will be sent over this switch port.
Ptr< OFSwitch13Device > GetSwitchDevice() const
Get the OFSwitch13Device pointer from this port.
void DoDispose() override
Destructor implementation.
uint32_t GetPortNo() const
Get the OpenFlow port number for this port.
uint64_t m_dpId
OpenFlow datapath ID.
OFSwitch13Port()
Default constructor.
Ptr< OFSwitch13Queue > GetPortQueue() const
Get the OpenFlow queue for this port.
bool PortUpdateState()
Update the port state field based on NetDevice status, and notify the controller when changes occurs.
Ptr< NetDevice > m_netDev
Underlying NetDevice.
uint32_t GetPortFeatures()
Create the bitmaps of OFPPF_* describing port features.
struct sw_port * GetPortStruct()
Get a pointer to the internal BOFUSS port structure.
bool Receive(Ptr< NetDevice > device, Ptr< const Packet > packet, uint16_t protocol, const Address &from, const Address &to, NetDevice::PacketType packetType)
Called when a packet is received on this OpenFlow switch port by the underlying NetDevice.
Ptr< NetDevice > GetPortDevice() const
Get the NetDevice pointer from the underlying port.
The OpenFlow 1.3 queue interface.
Instantiate subclasses of ns3::Object.
Ptr< Object > Create() const
Create an Object instance of the configured TypeId.
void SetTypeId(TypeId tid)
Set the TypeId of the Objects to be created by this factory.
AttributeValue implementation for ObjectFactory.
A base class which provides memory management and object aggregation.
Definition: object.h:89
uint32_t RemoveHeader(Header &header)
Deserialize and remove the header from the internal buffer.
Definition: packet.cc:294
uint32_t RemoveTrailer(Trailer &trailer)
Remove a deserialized trailer from the internal buffer.
Definition: packet.cc:336
uint32_t GetSize() const
Returns the the size in bytes of the packet (including the zero-filled initial payload).
Definition: packet.h:863
Ptr< Packet > Copy() const
performs a COW copy of the packet.
Definition: packet.cc:131
uint64_t GetUid() const
Returns the packet's Uid.
Definition: packet.cc:412
bool PeekPacketTag(Tag &tag) const
Search a matching tag and call Tag::Deserialize if it is found.
Definition: packet.cc:1002
bool ReplacePacketTag(Tag &tag)
Replace the value of a packet tag.
Definition: packet.cc:994
Hold objects of type Ptr<T>.
Definition: pointer.h:37
Smart pointer class similar to boost::intrusive_ptr.
Definition: ptr.h:78
Tag used to hold the queue id before enqueueing a packet into OFSwitch13Queue.
Definition: queue-tag.h:36
Tag used to hold the tunnel metadata information (tunnel ID) when sending/receiving a packet to/from ...
Definition: tunnel-id-tag.h:36
uint64_t GetTunnelId() const
a unique identifier for an interface.
Definition: type-id.h:60
@ 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
TypeId SetParent(TypeId tid)
Set the parent TypeId.
Definition: type-id.cc:935
A virtual device, similar to Linux TUN/TAP interfaces.
#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
Ptr< const AttributeChecker > MakeObjectFactoryChecker()
Ptr< const AttributeAccessor > MakeObjectFactoryAccessor(T1 a1)
Create an AttributeAccessor for a class data member, or a lone class get functor or set method.
Ptr< const AttributeAccessor > MakePointerAccessor(T1 a1)
Create an AttributeAccessor for a class data member, or a lone class get functor or set method.
Definition: pointer.h:231
#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_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< const TraceSourceAccessor > MakeTraceSourceAccessor(T a)
Create a TraceSourceAccessor which will control access to the underlying trace source.
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
static ObjectFactory GetDefaultQueueFactory()
U * PeekPointer(const Ptr< U > &p)
Definition: ptr.h:488
channel
Definition: third.py:81
long long int time_msec(void)
Overriding BOFUSS time_msec weak function from timeval.c.