A Discrete-Event Network Simulator
API
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
openflow-switch-net-device.cc
Go to the documentation of this file.
1 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2 /*
3  * This program is free software; you can redistribute it and/or modify
4  * it under the terms of the GNU General Public License version 2 as
5  * published by the Free Software Foundation;
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software
14  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
15  *
16  * Author: Blake Hurd <naimorai@gmail.com>
17  */
18 #ifdef NS3_OPENFLOW
19 
21 
22 NS_LOG_COMPONENT_DEFINE ("OpenFlowSwitchNetDevice");
23 
24 namespace ns3 {
25 
26 NS_OBJECT_ENSURE_REGISTERED (OpenFlowSwitchNetDevice)
27  ;
28 
29 const char *
31 {
32  return "The ns-3 team";
33 }
34 
35 const char *
37 {
38  return "N/A";
39 }
40 
41 const char *
43 {
44  return "Simulated OpenFlow Switch";
45 }
46 
47 const char *
49 {
50  return "N/A";
51 }
52 
53 static uint64_t
54 GenerateId ()
55 {
56  uint8_t ea[ETH_ADDR_LEN];
57  eth_addr_random (ea);
58  return eth_addr_to_uint64 (ea);
59 }
60 
61 TypeId
63 {
64  static TypeId tid = TypeId ("ns3::OpenFlowSwitchNetDevice")
65  .SetParent<NetDevice> ()
66  .AddConstructor<OpenFlowSwitchNetDevice> ()
67  .AddAttribute ("ID",
68  "The identification of the OpenFlowSwitchNetDevice/Datapath, needed for OpenFlow compatibility.",
69  UintegerValue (GenerateId ()),
70  MakeUintegerAccessor (&OpenFlowSwitchNetDevice::m_id),
71  MakeUintegerChecker<uint64_t> ())
72  .AddAttribute ("FlowTableLookupDelay",
73  "A real switch will have an overhead for looking up in the flow table. For the default, we simulate a standard TCAM on an FPGA.",
74  TimeValue (NanoSeconds (30)),
75  MakeTimeAccessor (&OpenFlowSwitchNetDevice::m_lookupDelay),
76  MakeTimeChecker ())
77  .AddAttribute ("Flags", // Note: The Controller can configure this value, overriding the user's setting.
78  "Flags to turn different functionality on/off, such as whether to inform the controller when a flow expires, or how to handle fragments.",
79  UintegerValue (0), // Look at the ofp_config_flags enum in openflow/include/openflow.h for options.
80  MakeUintegerAccessor (&OpenFlowSwitchNetDevice::m_flags),
81  MakeUintegerChecker<uint16_t> ())
82  .AddAttribute ("FlowTableMissSendLength", // Note: The Controller can configure this value, overriding the user's setting.
83  "When forwarding a packet the switch didn't match up to the controller, it can be more efficient to forward only the first x bytes.",
84  UintegerValue (OFP_DEFAULT_MISS_SEND_LEN), // 128 bytes
85  MakeUintegerAccessor (&OpenFlowSwitchNetDevice::m_missSendLen),
86  MakeUintegerChecker<uint16_t> ())
87  ;
88  return tid;
89 }
90 
92  : m_node (0),
93  m_ifIndex (0),
94  m_mtu (0xffff)
95 {
97 
98  m_channel = CreateObject<BridgeChannel> ();
99 
100  time_init (); // OFSI's clock; needed to use the buffer storage system.
101  // m_lastTimeout = time_now ();
102 
103  m_controller = 0;
104  // m_listenPVConn = 0;
105 
106  m_chain = chain_create ();
107  if (m_chain == 0)
108  {
109  NS_LOG_ERROR ("Not enough memory to create the flow table.");
110  }
111 
112  m_ports.reserve (DP_MAX_PORTS);
113  vport_table_init (&m_vportTable);
114 }
115 
116 OpenFlowSwitchNetDevice::~OpenFlowSwitchNetDevice ()
117 {
119 }
120 
121 void
122 OpenFlowSwitchNetDevice::DoDispose ()
123 {
125 
126  for (Ports_t::iterator b = m_ports.begin (), e = m_ports.end (); b != e; b++)
127  {
128  SendPortStatus (*b, OFPPR_DELETE);
129  b->netdev = 0;
130  }
131  m_ports.clear ();
132 
133  m_controller = 0;
134 
135  chain_destroy (m_chain);
136  RBTreeDestroy (m_vportTable.table);
137  m_channel = 0;
138  m_node = 0;
139  NetDevice::DoDispose ();
140 }
141 
142 void
143 OpenFlowSwitchNetDevice::SetController (Ptr<ofi::Controller> c)
144 {
145  if (m_controller != 0)
146  {
147  NS_LOG_ERROR ("Controller already set.");
148  return;
149  }
150 
151  m_controller = c;
152  m_controller->AddSwitch (this);
153 }
154 
155 int
156 OpenFlowSwitchNetDevice::AddSwitchPort (Ptr<NetDevice> switchPort)
157 {
159  NS_ASSERT (switchPort != this);
160  if (!Mac48Address::IsMatchingType (switchPort->GetAddress ()))
161  {
162  NS_FATAL_ERROR ("Device does not support eui 48 addresses: cannot be added to switch.");
163  }
164  if (!switchPort->SupportsSendFrom ())
165  {
166  NS_FATAL_ERROR ("Device does not support SendFrom: cannot be added to switch.");
167  }
168  if (m_address == Mac48Address ())
169  {
170  m_address = Mac48Address::ConvertFrom (switchPort->GetAddress ());
171  }
172 
173  if (m_ports.size () < DP_MAX_PORTS)
174  {
175  ofi::Port p;
176  p.config = 0;
177  p.netdev = switchPort;
178  m_ports.push_back (p);
179 
180  // Notify the controller that this port has been added
181  SendPortStatus (p, OFPPR_ADD);
182 
183  NS_LOG_DEBUG ("RegisterProtocolHandler for " << switchPort->GetInstanceTypeId ().GetName ());
184  m_node->RegisterProtocolHandler (MakeCallback (&OpenFlowSwitchNetDevice::ReceiveFromDevice, this),
185  0, switchPort, true);
186  m_channel->AddChannel (switchPort->GetChannel ());
187  }
188  else
189  {
190  return EXFULL;
191  }
192 
193  return 0;
194 }
195 
196 void
197 OpenFlowSwitchNetDevice::SetIfIndex (const uint32_t index)
198 {
200  m_ifIndex = index;
201 }
202 
203 uint32_t
204 OpenFlowSwitchNetDevice::GetIfIndex (void) const
205 {
207  return m_ifIndex;
208 }
209 
210 Ptr<Channel>
211 OpenFlowSwitchNetDevice::GetChannel (void) const
212 {
214  return m_channel;
215 }
216 
217 void
218 OpenFlowSwitchNetDevice::SetAddress (Address address)
219 {
221  m_address = Mac48Address::ConvertFrom (address);
222 }
223 
224 Address
225 OpenFlowSwitchNetDevice::GetAddress (void) const
226 {
228  return m_address;
229 }
230 
231 bool
232 OpenFlowSwitchNetDevice::SetMtu (const uint16_t mtu)
233 {
235  m_mtu = mtu;
236  return true;
237 }
238 
239 uint16_t
240 OpenFlowSwitchNetDevice::GetMtu (void) const
241 {
243  return m_mtu;
244 }
245 
246 
247 bool
248 OpenFlowSwitchNetDevice::IsLinkUp (void) const
249 {
251  return true;
252 }
253 
254 
255 void
256 OpenFlowSwitchNetDevice::AddLinkChangeCallback (Callback<void> callback)
257 {
258 }
259 
260 bool
261 OpenFlowSwitchNetDevice::IsBroadcast (void) const
262 {
264  return true;
265 }
266 
267 Address
268 OpenFlowSwitchNetDevice::GetBroadcast (void) const
269 {
271  return Mac48Address ("ff:ff:ff:ff:ff:ff");
272 }
273 
274 bool
276 {
278  return true;
279 }
280 
281 Address
282 OpenFlowSwitchNetDevice::GetMulticast (Ipv4Address multicastGroup) const
283 {
284  NS_LOG_FUNCTION (this << multicastGroup);
285  Mac48Address multicast = Mac48Address::GetMulticast (multicastGroup);
286  return multicast;
287 }
288 
289 
290 bool
291 OpenFlowSwitchNetDevice::IsPointToPoint (void) const
292 {
294  return false;
295 }
296 
297 bool
298 OpenFlowSwitchNetDevice::IsBridge (void) const
299 {
301  return true;
302 }
303 
304 void
305 OpenFlowSwitchNetDevice::DoOutput (uint32_t packet_uid, int in_port, size_t max_len, int out_port, bool ignore_no_fwd)
306 {
307  if (out_port != OFPP_CONTROLLER)
308  {
309  OutputPort (packet_uid, in_port, out_port, ignore_no_fwd);
310  }
311  else
312  {
313  OutputControl (packet_uid, in_port, max_len, OFPR_ACTION);
314  }
315 }
316 
317 bool
318 OpenFlowSwitchNetDevice::Send (Ptr<Packet> packet, const Address& dest, uint16_t protocolNumber)
319 {
321  return SendFrom (packet, m_address, dest, protocolNumber);
322 }
323 
324 bool
325 OpenFlowSwitchNetDevice::SendFrom (Ptr<Packet> packet, const Address& src, const Address& dest, uint16_t protocolNumber)
326 {
328 
329  ofpbuf *buffer = BufferFromPacket (packet,src,dest,GetMtu (),protocolNumber);
330 
331  uint32_t packet_uid = save_buffer (buffer);
332  ofi::SwitchPacketMetadata data;
333  data.packet = packet;
334  data.buffer = buffer;
335  data.protocolNumber = protocolNumber;
336  data.src = Address (src);
337  data.dst = Address (dest);
338  m_packetData.insert (std::make_pair (packet_uid, data));
339 
340  RunThroughFlowTable (packet_uid, -1);
341 
342  return true;
343 }
344 
345 
346 Ptr<Node>
347 OpenFlowSwitchNetDevice::GetNode (void) const
348 {
350  return m_node;
351 }
352 
353 void
354 OpenFlowSwitchNetDevice::SetNode (Ptr<Node> node)
355 {
357  m_node = node;
358 }
359 
360 bool
361 OpenFlowSwitchNetDevice::NeedsArp (void) const
362 {
364  return true;
365 }
366 
367 void
368 OpenFlowSwitchNetDevice::SetReceiveCallback (NetDevice::ReceiveCallback cb)
369 {
371  m_rxCallback = cb;
372 }
373 
374 void
375 OpenFlowSwitchNetDevice::SetPromiscReceiveCallback (NetDevice::PromiscReceiveCallback cb)
376 {
378  m_promiscRxCallback = cb;
379 }
380 
381 bool
382 OpenFlowSwitchNetDevice::SupportsSendFrom () const
383 {
385  return true;
386 }
387 
388 Address
389 OpenFlowSwitchNetDevice::GetMulticast (Ipv6Address addr) const
390 {
391  NS_LOG_FUNCTION (this << addr);
392  return Mac48Address::GetMulticast (addr);
393 }
394 
395 // Add a virtual port table entry.
396 int
397 OpenFlowSwitchNetDevice::AddVPort (const ofp_vport_mod *ovpm)
398 {
399  size_t actions_len = ntohs (ovpm->header.length) - sizeof *ovpm;
400  unsigned int vport = ntohl (ovpm->vport);
401  unsigned int parent_port = ntohl (ovpm->parent_port);
402 
403  // check whether port table entry exists for specified port number
404  vport_table_entry *vpe = vport_table_lookup (&m_vportTable, vport);
405  if (vpe != 0)
406  {
407  NS_LOG_ERROR ("vport " << vport << " already exists!");
408  SendErrorMsg (OFPET_BAD_ACTION, OFPET_VPORT_MOD_FAILED, ovpm, ntohs (ovpm->header.length));
409  return EINVAL;
410  }
411 
412  // check whether actions are valid
413  uint16_t v_code = ofi::ValidateVPortActions (ovpm->actions, actions_len);
414  if (v_code != ACT_VALIDATION_OK)
415  {
416  SendErrorMsg (OFPET_BAD_ACTION, v_code, ovpm, ntohs (ovpm->header.length));
417  return EINVAL;
418  }
419 
420  vpe = vport_table_entry_alloc (actions_len);
421 
422  vpe->vport = vport;
423  vpe->parent_port = parent_port;
424  if (vport < OFPP_VP_START || vport > OFPP_VP_END)
425  {
426  NS_LOG_ERROR ("port " << vport << " is not in the virtual port range (" << OFPP_VP_START << "-" << OFPP_VP_END << ")");
427  SendErrorMsg (OFPET_BAD_ACTION, OFPET_VPORT_MOD_FAILED, ovpm, ntohs (ovpm->header.length));
428  free_vport_table_entry (vpe); // free allocated entry
429  return EINVAL;
430  }
431 
432  vpe->port_acts->actions_len = actions_len;
433  memcpy (vpe->port_acts->actions, ovpm->actions, actions_len);
434 
435  int error = insert_vport_table_entry (&m_vportTable, vpe);
436  if (error)
437  {
438  NS_LOG_ERROR ("could not insert port table entry for port " << vport);
439  }
440 
441  return error;
442 }
443 
444 ofpbuf *
445 OpenFlowSwitchNetDevice::BufferFromPacket (Ptr<Packet> packet, Address src, Address dst, int mtu, uint16_t protocol)
446 {
447  NS_LOG_INFO ("Creating Openflow buffer from packet.");
448 
449  /*
450  * Allocate buffer with some headroom to add headers in forwarding
451  * to the controller or adding a vlan tag, plus an extra 2 bytes to
452  * allow IP headers to be aligned on a 4-byte boundary.
453  */
454  const int headroom = 128 + 2;
455  const int hard_header = VLAN_ETH_HEADER_LEN;
456  ofpbuf *buffer = ofpbuf_new (headroom + hard_header + mtu);
457  buffer->data = (char*)buffer->data + headroom + hard_header;
458 
459  int l2_length = 0, l3_length = 0, l4_length = 0;
460 
461  // Load headers
462  EthernetHeader eth_hd;
463  if (packet->PeekHeader (eth_hd))
464  {
465  buffer->l2 = new eth_header;
466  eth_header* eth_h = (eth_header*)buffer->l2;
467  dst.CopyTo (eth_h->eth_dst); // Destination Mac Address
468  src.CopyTo (eth_h->eth_src); // Source Mac Address
469  eth_h->eth_type = htons (ETH_TYPE_IP); // Ether Type
470  NS_LOG_INFO ("Parsed EthernetHeader");
471 
472  l2_length = ETH_HEADER_LEN;
473  }
474 
475  // We have to wrap this because PeekHeader has an assert fail if we check for an Ipv4Header that isn't there.
476  if (protocol == Ipv4L3Protocol::PROT_NUMBER)
477  {
478  Ipv4Header ip_hd;
479  if (packet->PeekHeader (ip_hd))
480  {
481  buffer->l3 = new ip_header;
482  ip_header* ip_h = (ip_header*)buffer->l3;
483  ip_h->ip_ihl_ver = IP_IHL_VER (5, IP_VERSION); // Version
484  ip_h->ip_tos = ip_hd.GetTos (); // Type of Service/Differentiated Services
485  ip_h->ip_tot_len = packet->GetSize (); // Total Length
486  ip_h->ip_id = ip_hd.GetIdentification (); // Identification
487  ip_h->ip_frag_off = ip_hd.GetFragmentOffset (); // Fragment Offset
488  ip_h->ip_ttl = ip_hd.GetTtl (); // Time to Live
489  ip_h->ip_proto = ip_hd.GetProtocol (); // Protocol
490  ip_h->ip_src = htonl (ip_hd.GetSource ().Get ()); // Source Address
491  ip_h->ip_dst = htonl (ip_hd.GetDestination ().Get ()); // Destination Address
492  ip_h->ip_csum = csum (&ip_h, sizeof ip_h); // Header Checksum
493  NS_LOG_INFO ("Parsed Ipv4Header");
494 
495  l3_length = IP_HEADER_LEN;
496  }
497  }
498  else
499  {
500  // ARP Packet; the underlying OpenFlow header isn't used to match, so this is probably superfluous.
501  ArpHeader arp_hd;
502  if (packet->PeekHeader (arp_hd))
503  {
504  buffer->l3 = new arp_eth_header;
505  arp_eth_header* arp_h = (arp_eth_header*)buffer->l3;
506  arp_h->ar_hrd = ARP_HRD_ETHERNET; // Hardware type.
507  arp_h->ar_pro = ARP_PRO_IP; // Protocol type.
508  arp_h->ar_op = arp_hd.m_type; // Opcode.
509  arp_hd.GetDestinationHardwareAddress ().CopyTo (arp_h->ar_tha); // Target hardware address.
510  arp_hd.GetSourceHardwareAddress ().CopyTo (arp_h->ar_sha); // Sender hardware address.
511  arp_h->ar_tpa = arp_hd.GetDestinationIpv4Address ().Get (); // Target protocol address.
512  arp_h->ar_spa = arp_hd.GetSourceIpv4Address ().Get (); // Sender protocol address.
513  arp_h->ar_hln = sizeof arp_h->ar_tha; // Hardware address length.
514  arp_h->ar_pln = sizeof arp_h->ar_tpa; // Protocol address length.
515  NS_LOG_INFO ("Parsed ArpHeader");
516 
517  l3_length = ARP_ETH_HEADER_LEN;
518  }
519  }
520 
521  TcpHeader tcp_hd;
522  if (packet->PeekHeader (tcp_hd))
523  {
524  buffer->l4 = new tcp_header;
525  tcp_header* tcp_h = (tcp_header*)buffer->l4;
526  tcp_h->tcp_src = htons (tcp_hd.GetSourcePort ()); // Source Port
527  tcp_h->tcp_dst = htons (tcp_hd.GetDestinationPort ()); // Destination Port
528  tcp_h->tcp_seq = tcp_hd.GetSequenceNumber ().GetValue (); // Sequence Number
529  tcp_h->tcp_ack = tcp_hd.GetAckNumber ().GetValue (); // ACK Number
530  tcp_h->tcp_ctl = TCP_FLAGS (tcp_hd.GetFlags ()); // Data Offset + Reserved + Flags
531  tcp_h->tcp_winsz = tcp_hd.GetWindowSize (); // Window Size
532  tcp_h->tcp_urg = tcp_hd.GetUrgentPointer (); // Urgent Pointer
533  tcp_h->tcp_csum = csum (&tcp_h, sizeof tcp_h); // Header Checksum
534  NS_LOG_INFO ("Parsed TcpHeader");
535 
536  l4_length = TCP_HEADER_LEN;
537  }
538  else
539  {
540  UdpHeader udp_hd;
541  if (packet->PeekHeader (udp_hd))
542  {
543  buffer->l4 = new udp_header;
544  udp_header* udp_h = (udp_header*)buffer->l4;
545  udp_h->udp_src = htons (udp_hd.GetSourcePort ()); // Source Port
546  udp_h->udp_dst = htons (udp_hd.GetDestinationPort ()); // Destination Port
547  udp_h->udp_len = htons (UDP_HEADER_LEN + packet->GetSize ());
548 
549  if (protocol == Ipv4L3Protocol::PROT_NUMBER)
550  {
551  ip_header* ip_h = (ip_header*)buffer->l3;
552  uint32_t udp_csum = csum_add32 (0, ip_h->ip_src);
553  udp_csum = csum_add32 (udp_csum, ip_h->ip_dst);
554  udp_csum = csum_add16 (udp_csum, IP_TYPE_UDP << 8);
555  udp_csum = csum_add16 (udp_csum, udp_h->udp_len);
556  udp_csum = csum_continue (udp_csum, udp_h, sizeof udp_h);
557  udp_h->udp_csum = csum_finish (csum_continue (udp_csum, buffer->data, buffer->size)); // Header Checksum
558  }
559  else
560  {
561  udp_h->udp_csum = htons (0);
562  }
563  NS_LOG_INFO ("Parsed UdpHeader");
564 
565  l4_length = UDP_HEADER_LEN;
566  }
567  }
568 
569  // Load Packet data into buffer data
570  packet->CopyData ((uint8_t*)buffer->data, packet->GetSize ());
571 
572  if (buffer->l4)
573  {
574  ofpbuf_push (buffer, buffer->l4, l4_length);
575  delete (tcp_header*)buffer->l4;
576  }
577  if (buffer->l3)
578  {
579  ofpbuf_push (buffer, buffer->l3, l3_length);
580  delete (ip_header*)buffer->l3;
581  }
582  if (buffer->l2)
583  {
584  ofpbuf_push (buffer, buffer->l2, l2_length);
585  delete (eth_header*)buffer->l2;
586  }
587 
588  return buffer;
589 }
590 
591 void
592 OpenFlowSwitchNetDevice::ReceiveFromDevice (Ptr<NetDevice> netdev, Ptr<const Packet> packet, uint16_t protocol,
593  const Address& src, const Address& dst, PacketType packetType)
594 {
596  NS_LOG_INFO ("--------------------------------------------");
597  NS_LOG_DEBUG ("UID is " << packet->GetUid ());
598 
599  if (!m_promiscRxCallback.IsNull ())
600  {
601  m_promiscRxCallback (this, packet, protocol, src, dst, packetType);
602  }
603 
604  Mac48Address dst48 = Mac48Address::ConvertFrom (dst);
605  NS_LOG_INFO ("Received packet from " << Mac48Address::ConvertFrom (src) << " looking for " << dst48);
606 
607  for (size_t i = 0; i < m_ports.size (); i++)
608  {
609  if (m_ports[i].netdev == netdev)
610  {
611  if (packetType == PACKET_HOST && dst48 == m_address)
612  {
613  m_rxCallback (this, packet, protocol, src);
614  }
615  else if (packetType == PACKET_BROADCAST || packetType == PACKET_MULTICAST || packetType == PACKET_OTHERHOST)
616  {
617  if (packetType == PACKET_OTHERHOST && dst48 == m_address)
618  {
619  m_rxCallback (this, packet, protocol, src);
620  }
621  else
622  {
623  if (packetType != PACKET_OTHERHOST)
624  {
625  m_rxCallback (this, packet, protocol, src);
626  }
627 
628  ofi::SwitchPacketMetadata data;
629  data.packet = packet->Copy ();
630 
631  ofpbuf *buffer = BufferFromPacket (data.packet,src,dst,netdev->GetMtu (),protocol);
632  m_ports[i].rx_packets++;
633  m_ports[i].rx_bytes += buffer->size;
634  data.buffer = buffer;
635  uint32_t packet_uid = save_buffer (buffer);
636 
637  data.protocolNumber = protocol;
638  data.src = Address (src);
639  data.dst = Address (dst);
640  m_packetData.insert (std::make_pair (packet_uid, data));
641 
642  RunThroughFlowTable (packet_uid, i);
643  }
644  }
645 
646  break;
647  }
648  }
649 
650  // Run periodic execution.
651  Time now = Simulator::Now ();
652  if (now >= Seconds (m_lastExecute.GetSeconds () + 1)) // If a second or more has passed from the simulation time, execute.
653  {
654  // If port status is modified in any way, notify the controller.
655  for (size_t i = 0; i < m_ports.size (); i++)
656  {
657  if (UpdatePortStatus (m_ports[i]))
658  {
659  SendPortStatus (m_ports[i], OFPPR_MODIFY);
660  }
661  }
662 
663  // If any flows have expired, delete them and notify the controller.
664  List deleted = LIST_INITIALIZER (&deleted);
665  sw_flow *f, *n;
666  chain_timeout (m_chain, &deleted);
667  LIST_FOR_EACH_SAFE (f, n, sw_flow, node, &deleted)
668  {
669  std::ostringstream str;
670  str << "Flow [";
671  for (int i = 0; i < 6; i++)
672  str << (i!=0 ? ":" : "") << std::hex << f->key.flow.dl_src[i]/16 << f->key.flow.dl_src[i]%16;
673  str << " -> ";
674  for (int i = 0; i < 6; i++)
675  str << (i!=0 ? ":" : "") << std::hex << f->key.flow.dl_dst[i]/16 << f->key.flow.dl_dst[i]%16;
676  str << "] expired.";
677 
678  NS_LOG_INFO (str.str ());
679  SendFlowExpired (f, (ofp_flow_expired_reason)f->reason);
680  list_remove (&f->node);
681  flow_free (f);
682  }
683 
684  m_lastExecute = now;
685  }
686 }
687 
688 int
689 OpenFlowSwitchNetDevice::OutputAll (uint32_t packet_uid, int in_port, bool flood)
690 {
692  NS_LOG_INFO ("Flooding over ports.");
693 
694  int prev_port = -1;
695  for (size_t i = 0; i < m_ports.size (); i++)
696  {
697  if (i == (unsigned)in_port) // Originating port
698  {
699  continue;
700  }
701  if (flood && m_ports[i].config & OFPPC_NO_FLOOD) // Port configured to not allow flooding
702  {
703  continue;
704  }
705  if (prev_port != -1)
706  {
707  OutputPort (packet_uid, in_port, prev_port, false);
708  }
709  prev_port = i;
710  }
711  if (prev_port != -1)
712  {
713  OutputPort (packet_uid, in_port, prev_port, false);
714  }
715 
716  return 0;
717 }
718 
719 void
720 OpenFlowSwitchNetDevice::OutputPacket (uint32_t packet_uid, int out_port)
721 {
722  if (out_port >= 0 && out_port < DP_MAX_PORTS)
723  {
724  ofi::Port& p = m_ports[out_port];
725  if (p.netdev != 0 && !(p.config & OFPPC_PORT_DOWN))
726  {
727  ofi::SwitchPacketMetadata data = m_packetData.find (packet_uid)->second;
728  size_t bufsize = data.buffer->size;
729  NS_LOG_INFO ("Sending packet " << data.packet->GetUid () << " over port " << out_port);
730  if (p.netdev->SendFrom (data.packet->Copy (), data.src, data.dst, data.protocolNumber))
731  {
732  p.tx_packets++;
733  p.tx_bytes += bufsize;
734  }
735  else
736  {
737  p.tx_dropped++;
738  }
739  return;
740  }
741  }
742 
743  NS_LOG_DEBUG ("can't forward to bad port " << out_port);
744 }
745 
746 void
747 OpenFlowSwitchNetDevice::OutputPort (uint32_t packet_uid, int in_port, int out_port, bool ignore_no_fwd)
748 {
750 
751  if (out_port == OFPP_FLOOD)
752  {
753  OutputAll (packet_uid, in_port, true);
754  }
755  else if (out_port == OFPP_ALL)
756  {
757  OutputAll (packet_uid, in_port, false);
758  }
759  else if (out_port == OFPP_CONTROLLER)
760  {
761  OutputControl (packet_uid, in_port, 0, OFPR_ACTION);
762  }
763  else if (out_port == OFPP_IN_PORT)
764  {
765  OutputPacket (packet_uid, in_port);
766  }
767  else if (out_port == OFPP_TABLE)
768  {
769  RunThroughFlowTable (packet_uid, in_port < DP_MAX_PORTS ? in_port : -1, false);
770  }
771  else if (out_port >= OFPP_VP_START && out_port <= OFPP_VP_END)
772  {
773  // port is a virtual port
774  NS_LOG_INFO ("packet sent to virtual port " << out_port);
775  if (in_port < DP_MAX_PORTS)
776  {
777  RunThroughVPortTable (packet_uid, in_port, out_port);
778  }
779  else
780  {
781  RunThroughVPortTable (packet_uid, -1, out_port);
782  }
783  }
784  else if (in_port == out_port)
785  {
786  NS_LOG_DEBUG ("can't directly forward to input port");
787  }
788  else
789  {
790  OutputPacket (packet_uid, out_port);
791  }
792 }
793 
794 void*
795 OpenFlowSwitchNetDevice::MakeOpenflowReply (size_t openflow_len, uint8_t type, ofpbuf **bufferp)
796 {
797  return make_openflow_xid (openflow_len, type, 0, bufferp);
798 }
799 
800 int
801 OpenFlowSwitchNetDevice::SendOpenflowBuffer (ofpbuf *buffer)
802 {
803  if (m_controller != 0)
804  {
805  update_openflow_length (buffer);
806  m_controller->ReceiveFromSwitch (this, buffer);
807  }
808 
809  return 0;
810 }
811 
812 void
813 OpenFlowSwitchNetDevice::OutputControl (uint32_t packet_uid, int in_port, size_t max_len, int reason)
814 {
815  NS_LOG_INFO ("Sending packet to controller");
816 
817  ofpbuf* buffer = m_packetData.find (packet_uid)->second.buffer;
818  size_t total_len = buffer->size;
819  if (packet_uid != std::numeric_limits<uint32_t>::max () && max_len != 0 && buffer->size > max_len)
820  {
821  buffer->size = max_len;
822  }
823 
824  ofp_packet_in *opi = (ofp_packet_in*)ofpbuf_push_uninit (buffer, offsetof (ofp_packet_in, data));
825  opi->header.version = OFP_VERSION;
826  opi->header.type = OFPT_PACKET_IN;
827  opi->header.length = htons (buffer->size);
828  opi->header.xid = htonl (0);
829  opi->buffer_id = htonl (packet_uid);
830  opi->total_len = htons (total_len);
831  opi->in_port = htons (in_port);
832  opi->reason = reason;
833  opi->pad = 0;
834  SendOpenflowBuffer (buffer);
835 }
836 
837 void
838 OpenFlowSwitchNetDevice::FillPortDesc (ofi::Port p, ofp_phy_port *desc)
839 {
840  desc->port_no = htons (GetSwitchPortIndex (p));
841 
842  std::ostringstream nm;
843  nm << "eth" << GetSwitchPortIndex (p);
844  strncpy ((char *)desc->name, nm.str ().c_str (), sizeof desc->name);
845 
846  p.netdev->GetAddress ().CopyTo (desc->hw_addr);
847  desc->config = htonl (p.config);
848  desc->state = htonl (p.state);
849 
851  desc->curr = 0; // htonl(netdev_get_features(p->netdev, NETDEV_FEAT_CURRENT));
852  desc->supported = 0; // htonl(netdev_get_features(p->netdev, NETDEV_FEAT_SUPPORTED));
853  desc->advertised = 0; // htonl(netdev_get_features(p->netdev, NETDEV_FEAT_ADVERTISED));
854  desc->peer = 0; // htonl(netdev_get_features(p->netdev, NETDEV_FEAT_PEER));
855 }
856 
857 void
858 OpenFlowSwitchNetDevice::SendFeaturesReply ()
859 {
860  ofpbuf *buffer;
861  ofp_switch_features *ofr = (ofp_switch_features*)MakeOpenflowReply (sizeof *ofr, OFPT_FEATURES_REPLY, &buffer);
862  ofr->datapath_id = htonll (m_id);
863  ofr->n_tables = m_chain->n_tables;
864  ofr->n_buffers = htonl (N_PKT_BUFFERS);
865  ofr->capabilities = htonl (OFP_SUPPORTED_CAPABILITIES);
866  ofr->actions = htonl (OFP_SUPPORTED_ACTIONS);
867 
868  for (size_t i = 0; i < m_ports.size (); i++)
869  {
870  ofp_phy_port* opp = (ofp_phy_port*)ofpbuf_put_zeros (buffer, sizeof *opp);
871  FillPortDesc (m_ports[i], opp);
872  }
873 
874  SendOpenflowBuffer (buffer);
875 }
876 
877 void
878 OpenFlowSwitchNetDevice::SendVPortTableFeatures ()
879 {
880  ofpbuf *buffer;
881  ofp_vport_table_features *ovtfr = (ofp_vport_table_features*)MakeOpenflowReply (sizeof *ovtfr, OFPT_VPORT_TABLE_FEATURES_REPLY, &buffer);
882  ovtfr->actions = htonl (OFP_SUPPORTED_VPORT_TABLE_ACTIONS);
883  ovtfr->max_vports = htonl (m_vportTable.max_vports);
884  ovtfr->max_chain_depth = htons (-1); // support a chain depth of 2^16
885  ovtfr->mixed_chaining = true;
886  SendOpenflowBuffer (buffer);
887 }
888 
889 int
890 OpenFlowSwitchNetDevice::UpdatePortStatus (ofi::Port& p)
891 {
892  uint32_t orig_config = p.config;
893  uint32_t orig_state = p.state;
894 
895  // Port is always enabled because the Net Device is always enabled.
896  p.config &= ~OFPPC_PORT_DOWN;
897 
898  if (p.netdev->IsLinkUp ())
899  {
900  p.state &= ~OFPPS_LINK_DOWN;
901  }
902  else
903  {
904  p.state |= OFPPS_LINK_DOWN;
905  }
906 
907  return ((orig_config != p.config) || (orig_state != p.state));
908 }
909 
910 void
911 OpenFlowSwitchNetDevice::SendPortStatus (ofi::Port p, uint8_t status)
912 {
913  ofpbuf *buffer;
914  ofp_port_status *ops = (ofp_port_status*)MakeOpenflowReply (sizeof *ops, OFPT_PORT_STATUS, &buffer);
915  ops->reason = status;
916  memset (ops->pad, 0, sizeof ops->pad);
917  FillPortDesc (p, &ops->desc);
918 
919  SendOpenflowBuffer (buffer);
920  ofpbuf_delete (buffer);
921 }
922 
923 void
924 OpenFlowSwitchNetDevice::SendFlowExpired (sw_flow *flow, enum ofp_flow_expired_reason reason)
925 {
926  ofpbuf *buffer;
927  ofp_flow_expired *ofe = (ofp_flow_expired*)MakeOpenflowReply (sizeof *ofe, OFPT_FLOW_EXPIRED, &buffer);
928  flow_fill_match (&ofe->match, &flow->key);
929 
930  ofe->priority = htons (flow->priority);
931  ofe->reason = reason;
932  memset (ofe->pad, 0, sizeof ofe->pad);
933 
934  ofe->duration = htonl (time_now () - flow->created);
935  memset (ofe->pad2, 0, sizeof ofe->pad2);
936  ofe->packet_count = htonll (flow->packet_count);
937  ofe->byte_count = htonll (flow->byte_count);
938  SendOpenflowBuffer (buffer);
939 }
940 
941 void
942 OpenFlowSwitchNetDevice::SendErrorMsg (uint16_t type, uint16_t code, const void *data, size_t len)
943 {
944  ofpbuf *buffer;
945  ofp_error_msg *oem = (ofp_error_msg*)MakeOpenflowReply (sizeof(*oem) + len, OFPT_ERROR, &buffer);
946  oem->type = htons (type);
947  oem->code = htons (code);
948  memcpy (oem->data, data, len);
949  SendOpenflowBuffer (buffer);
950 }
951 
952 void
953 OpenFlowSwitchNetDevice::FlowTableLookup (sw_flow_key key, ofpbuf* buffer, uint32_t packet_uid, int port, bool send_to_controller)
954 {
955  sw_flow *flow = chain_lookup (m_chain, &key);
956  if (flow != 0)
957  {
958  NS_LOG_INFO ("Flow matched");
959  flow_used (flow, buffer);
960  ofi::ExecuteActions (this, packet_uid, buffer, &key, flow->sf_acts->actions, flow->sf_acts->actions_len, false);
961  }
962  else
963  {
964  NS_LOG_INFO ("Flow not matched.");
965 
966  if (send_to_controller)
967  {
968  OutputControl (packet_uid, port, m_missSendLen, OFPR_NO_MATCH);
969  }
970  }
971 
972  // Clean up; at this point we're done with the packet.
973  m_packetData.erase (packet_uid);
974  discard_buffer (packet_uid);
975  ofpbuf_delete (buffer);
976 }
977 
978 void
979 OpenFlowSwitchNetDevice::RunThroughFlowTable (uint32_t packet_uid, int port, bool send_to_controller)
980 {
981  ofi::SwitchPacketMetadata data = m_packetData.find (packet_uid)->second;
982  ofpbuf* buffer = data.buffer;
983 
984  sw_flow_key key;
985  key.wildcards = 0; // Lookup cannot take wildcards.
986  // Extract the matching key's flow data from the packet's headers; if the policy is to drop fragments and the message is a fragment, drop it.
987  if (flow_extract (buffer, port != -1 ? port : OFPP_NONE, &key.flow) && (m_flags & OFPC_FRAG_MASK) == OFPC_FRAG_DROP)
988  {
989  ofpbuf_delete (buffer);
990  return;
991  }
992 
993  // drop MPLS packets with TTL 1
994  if (buffer->l2_5)
995  {
996  mpls_header mpls_h;
997  mpls_h.value = ntohl (*((uint32_t*)buffer->l2_5));
998  if (mpls_h.ttl == 1)
999  {
1000  // increment mpls drop counter
1001  if (port != -1)
1002  {
1003  m_ports[port].mpls_ttl0_dropped++;
1004  }
1005  return;
1006  }
1007  }
1008 
1009  // If we received the packet on a port, and opted not to receive any messages from it...
1010  if (port != -1)
1011  {
1012  uint32_t config = m_ports[port].config;
1013  if (config & (OFPPC_NO_RECV | OFPPC_NO_RECV_STP)
1014  && config & (!eth_addr_equals (key.flow.dl_dst, stp_eth_addr) ? OFPPC_NO_RECV : OFPPC_NO_RECV_STP))
1015  {
1016  return;
1017  }
1018  }
1019 
1020  NS_LOG_INFO ("Matching against the flow table.");
1021  Simulator::Schedule (m_lookupDelay, &OpenFlowSwitchNetDevice::FlowTableLookup, this, key, buffer, packet_uid, port, send_to_controller);
1022 }
1023 
1024 int
1025 OpenFlowSwitchNetDevice::RunThroughVPortTable (uint32_t packet_uid, int port, uint32_t vport)
1026 {
1027  ofpbuf* buffer = m_packetData.find (packet_uid)->second.buffer;
1028 
1029  // extract the flow again since we need it
1030  // and the layer pointers may changed
1031  sw_flow_key key;
1032  key.wildcards = 0;
1033  if (flow_extract (buffer, port != -1 ? port : OFPP_NONE, &key.flow)
1034  && (m_flags & OFPC_FRAG_MASK) == OFPC_FRAG_DROP)
1035  {
1036  return 0;
1037  }
1038 
1039  // run through the chain of port table entries
1040  vport_table_entry *vpe = vport_table_lookup (&m_vportTable, vport);
1041  m_vportTable.lookup_count++;
1042  if (vpe)
1043  {
1044  m_vportTable.port_match_count++;
1045  }
1046  while (vpe != 0)
1047  {
1048  ofi::ExecuteVPortActions (this, packet_uid, m_packetData.find (packet_uid)->second.buffer, &key, vpe->port_acts->actions, vpe->port_acts->actions_len);
1049  vport_used (vpe, buffer); // update counters for virtual port
1050  if (vpe->parent_port_ptr == 0)
1051  {
1052  // if a port table's parent_port_ptr is 0 then
1053  // the parent_port should be a physical port
1054  if (vpe->parent_port <= OFPP_VP_START) // done traversing port chain, send packet to output port
1055  {
1056  OutputPort (packet_uid, port != -1 ? port : OFPP_NONE, vpe->parent_port, false);
1057  }
1058  else
1059  {
1060  NS_LOG_ERROR ("virtual port points to parent port\n");
1061  }
1062  }
1063  else // increment the number of port entries accessed by chaining
1064  {
1065  m_vportTable.chain_match_count++;
1066  }
1067  // move to the parent port entry
1068  vpe = vpe->parent_port_ptr;
1069  }
1070 
1071  return 0;
1072 }
1073 
1074 int
1075 OpenFlowSwitchNetDevice::ReceiveFeaturesRequest (const void *msg)
1076 {
1077  SendFeaturesReply ();
1078  return 0;
1079 }
1080 
1081 int
1082 OpenFlowSwitchNetDevice::ReceiveVPortTableFeaturesRequest (const void *msg)
1083 {
1084  SendVPortTableFeatures ();
1085  return 0;
1086 }
1087 
1088 int
1089 OpenFlowSwitchNetDevice::ReceiveGetConfigRequest (const void *msg)
1090 {
1091  ofpbuf *buffer;
1092  ofp_switch_config *osc = (ofp_switch_config*)MakeOpenflowReply (sizeof *osc, OFPT_GET_CONFIG_REPLY, &buffer);
1093  osc->flags = htons (m_flags);
1094  osc->miss_send_len = htons (m_missSendLen);
1095 
1096  return SendOpenflowBuffer (buffer);
1097 }
1098 
1099 int
1100 OpenFlowSwitchNetDevice::ReceiveSetConfig (const void *msg)
1101 {
1102  const ofp_switch_config *osc = (ofp_switch_config*)msg;
1103 
1104  int n_flags = ntohs (osc->flags) & (OFPC_SEND_FLOW_EXP | OFPC_FRAG_MASK);
1105  if ((n_flags & OFPC_FRAG_MASK) != OFPC_FRAG_NORMAL && (n_flags & OFPC_FRAG_MASK) != OFPC_FRAG_DROP)
1106  {
1107  n_flags = (n_flags & ~OFPC_FRAG_MASK) | OFPC_FRAG_DROP;
1108  }
1109 
1110  m_flags = n_flags;
1111  m_missSendLen = ntohs (osc->miss_send_len);
1112  return 0;
1113 }
1114 
1115 int
1116 OpenFlowSwitchNetDevice::ReceivePacketOut (const void *msg)
1117 {
1118  const ofp_packet_out *opo = (ofp_packet_out*)msg;
1119  ofpbuf *buffer;
1120  size_t actions_len = ntohs (opo->actions_len);
1121 
1122  if (actions_len > (ntohs (opo->header.length) - sizeof *opo))
1123  {
1124  NS_LOG_DEBUG ("message too short for number of actions");
1125  return -EINVAL;
1126  }
1127 
1128  if (ntohl (opo->buffer_id) == (uint32_t) -1)
1129  {
1130  // FIXME: can we avoid copying data here?
1131  int data_len = ntohs (opo->header.length) - sizeof *opo - actions_len;
1132  buffer = ofpbuf_new (data_len);
1133  ofpbuf_put (buffer, (uint8_t *)opo->actions + actions_len, data_len);
1134  }
1135  else
1136  {
1137  buffer = retrieve_buffer (ntohl (opo->buffer_id));
1138  if (buffer == 0)
1139  {
1140  return -ESRCH;
1141  }
1142  }
1143 
1144  sw_flow_key key;
1145  flow_extract (buffer, opo->in_port, &key.flow); // ntohs(opo->in_port)
1146 
1147  uint16_t v_code = ofi::ValidateActions (&key, opo->actions, actions_len);
1148  if (v_code != ACT_VALIDATION_OK)
1149  {
1150  SendErrorMsg (OFPET_BAD_ACTION, v_code, msg, ntohs (opo->header.length));
1151  ofpbuf_delete (buffer);
1152  return -EINVAL;
1153  }
1154 
1155  ofi::ExecuteActions (this, opo->buffer_id, buffer, &key, opo->actions, actions_len, true);
1156  return 0;
1157 }
1158 
1159 int
1160 OpenFlowSwitchNetDevice::ReceivePortMod (const void *msg)
1161 {
1162  ofp_port_mod* opm = (ofp_port_mod*)msg;
1163 
1164  int port = opm->port_no; // ntohs(opm->port_no);
1165  if (port < DP_MAX_PORTS)
1166  {
1167  ofi::Port& p = m_ports[port];
1168 
1169  // Make sure the port id hasn't changed since this was sent
1170  Mac48Address hw_addr = Mac48Address ();
1171  hw_addr.CopyFrom (opm->hw_addr);
1172  if (p.netdev->GetAddress () != hw_addr)
1173  {
1174  return 0;
1175  }
1176 
1177  if (opm->mask)
1178  {
1179  uint32_t config_mask = ntohl (opm->mask);
1180  p.config &= ~config_mask;
1181  p.config |= ntohl (opm->config) & config_mask;
1182  }
1183 
1184  if (opm->mask & htonl (OFPPC_PORT_DOWN))
1185  {
1186  if ((opm->config & htonl (OFPPC_PORT_DOWN)) && (p.config & OFPPC_PORT_DOWN) == 0)
1187  {
1188  p.config |= OFPPC_PORT_DOWN;
1190  }
1191  else if ((opm->config & htonl (OFPPC_PORT_DOWN)) == 0 && (p.config & OFPPC_PORT_DOWN))
1192  {
1193  p.config &= ~OFPPC_PORT_DOWN;
1195  }
1196  }
1197  }
1198 
1199  return 0;
1200 }
1201 
1202 // add or remove a virtual port table entry
1203 int
1204 OpenFlowSwitchNetDevice::ReceiveVPortMod (const void *msg)
1205 {
1206  const ofp_vport_mod *ovpm = (ofp_vport_mod*)msg;
1207 
1208  uint16_t command = ntohs (ovpm->command);
1209  if (command == OFPVP_ADD)
1210  {
1211  return AddVPort (ovpm);
1212  }
1213  else if (command == OFPVP_DELETE)
1214  {
1215  if (remove_vport_table_entry (&m_vportTable, ntohl (ovpm->vport)))
1216  {
1217  SendErrorMsg (OFPET_BAD_ACTION, OFPET_VPORT_MOD_FAILED, ovpm, ntohs (ovpm->header.length));
1218  }
1219  }
1220 
1221  return 0;
1222 }
1223 
1224 int
1225 OpenFlowSwitchNetDevice::AddFlow (const ofp_flow_mod *ofm)
1226 {
1227  size_t actions_len = ntohs (ofm->header.length) - sizeof *ofm;
1228 
1229  // Allocate memory.
1230  sw_flow *flow = flow_alloc (actions_len);
1231  if (flow == 0)
1232  {
1233  if (ntohl (ofm->buffer_id) != (uint32_t) -1)
1234  {
1235  discard_buffer (ntohl (ofm->buffer_id));
1236  }
1237  return -ENOMEM;
1238  }
1239 
1240  flow_extract_match (&flow->key, &ofm->match);
1241 
1242  uint16_t v_code = ofi::ValidateActions (&flow->key, ofm->actions, actions_len);
1243  if (v_code != ACT_VALIDATION_OK)
1244  {
1245  SendErrorMsg (OFPET_BAD_ACTION, v_code, ofm, ntohs (ofm->header.length));
1246  flow_free (flow);
1247  if (ntohl (ofm->buffer_id) != (uint32_t) -1)
1248  {
1249  discard_buffer (ntohl (ofm->buffer_id));
1250  }
1251  return -ENOMEM;
1252  }
1253 
1254  // Fill out flow.
1255  flow->priority = flow->key.wildcards ? ntohs (ofm->priority) : -1;
1256  flow->idle_timeout = ntohs (ofm->idle_timeout);
1257  flow->hard_timeout = ntohs (ofm->hard_timeout);
1258  flow->used = flow->created = time_now ();
1259  flow->sf_acts->actions_len = actions_len;
1260  flow->byte_count = 0;
1261  flow->packet_count = 0;
1262  memcpy (flow->sf_acts->actions, ofm->actions, actions_len);
1263 
1264  // Act.
1265  int error = chain_insert (m_chain, flow);
1266  if (error)
1267  {
1268  if (error == -ENOBUFS)
1269  {
1270  SendErrorMsg (OFPET_FLOW_MOD_FAILED, OFPFMFC_ALL_TABLES_FULL, ofm, ntohs (ofm->header.length));
1271  }
1272  flow_free (flow);
1273  if (ntohl (ofm->buffer_id) != (uint32_t) -1)
1274  {
1275  discard_buffer (ntohl (ofm->buffer_id));
1276  }
1277  return error;
1278  }
1279 
1280  NS_LOG_INFO ("Added new flow.");
1281  if (ntohl (ofm->buffer_id) != std::numeric_limits<uint32_t>::max ())
1282  {
1283  ofpbuf *buffer = retrieve_buffer (ofm->buffer_id); // ntohl(ofm->buffer_id)
1284  if (buffer)
1285  {
1286  sw_flow_key key;
1287  flow_used (flow, buffer);
1288  flow_extract (buffer, ofm->match.in_port, &key.flow); // ntohs(ofm->match.in_port);
1289  ofi::ExecuteActions (this, ofm->buffer_id, buffer, &key, ofm->actions, actions_len, false);
1290  ofpbuf_delete (buffer);
1291  }
1292  else
1293  {
1294  return -ESRCH;
1295  }
1296  }
1297  return 0;
1298 }
1299 
1300 int
1301 OpenFlowSwitchNetDevice::ModFlow (const ofp_flow_mod *ofm)
1302 {
1303  sw_flow_key key;
1304  flow_extract_match (&key, &ofm->match);
1305 
1306  size_t actions_len = ntohs (ofm->header.length) - sizeof *ofm;
1307 
1308  uint16_t v_code = ofi::ValidateActions (&key, ofm->actions, actions_len);
1309  if (v_code != ACT_VALIDATION_OK)
1310  {
1311  SendErrorMsg ((ofp_error_type)OFPET_BAD_ACTION, v_code, ofm, ntohs (ofm->header.length));
1312  if (ntohl (ofm->buffer_id) != (uint32_t) -1)
1313  {
1314  discard_buffer (ntohl (ofm->buffer_id));
1315  }
1316  return -ENOMEM;
1317  }
1318 
1319  uint16_t priority = key.wildcards ? ntohs (ofm->priority) : -1;
1320  int strict = (ofm->command == htons (OFPFC_MODIFY_STRICT)) ? 1 : 0;
1321  chain_modify (m_chain, &key, priority, strict, ofm->actions, actions_len);
1322 
1323  if (ntohl (ofm->buffer_id) != std::numeric_limits<uint32_t>::max ())
1324  {
1325  ofpbuf *buffer = retrieve_buffer (ofm->buffer_id); // ntohl (ofm->buffer_id)
1326  if (buffer)
1327  {
1328  sw_flow_key skb_key;
1329  flow_extract (buffer, ofm->match.in_port, &skb_key.flow); // ntohs(ofm->match.in_port);
1330  ofi::ExecuteActions (this, ofm->buffer_id, buffer, &skb_key, ofm->actions, actions_len, false);
1331  ofpbuf_delete (buffer);
1332  }
1333  else
1334  {
1335  return -ESRCH;
1336  }
1337  }
1338  return 0;
1339 }
1340 
1341 int
1342 OpenFlowSwitchNetDevice::ReceiveFlow (const void *msg)
1343 {
1345  const ofp_flow_mod *ofm = (ofp_flow_mod*)msg;
1346  uint16_t command = ntohs (ofm->command);
1347 
1348  if (command == OFPFC_ADD)
1349  {
1350  return AddFlow (ofm);
1351  }
1352  else if ((command == OFPFC_MODIFY) || (command == OFPFC_MODIFY_STRICT))
1353  {
1354  return ModFlow (ofm);
1355  }
1356  else if (command == OFPFC_DELETE)
1357  {
1358  sw_flow_key key;
1359  flow_extract_match (&key, &ofm->match);
1360  return chain_delete (m_chain, &key, ofm->out_port, 0, 0) ? 0 : -ESRCH;
1361  }
1362  else if (command == OFPFC_DELETE_STRICT)
1363  {
1364  sw_flow_key key;
1365  uint16_t priority;
1366  flow_extract_match (&key, &ofm->match);
1367  priority = key.wildcards ? ntohs (ofm->priority) : -1;
1368  return chain_delete (m_chain, &key, ofm->out_port, priority, 1) ? 0 : -ESRCH;
1369  }
1370  else
1371  {
1372  return -ENODEV;
1373  }
1374 }
1375 
1376 int
1377 OpenFlowSwitchNetDevice::StatsDump (ofi::StatsDumpCallback *cb)
1378 {
1379  ofp_stats_reply *osr;
1380  ofpbuf *buffer;
1381  int err;
1382 
1383  if (cb->done)
1384  {
1385  return 0;
1386  }
1387 
1388  osr = (ofp_stats_reply*)MakeOpenflowReply (sizeof *osr, OFPT_STATS_REPLY, &buffer);
1389  osr->type = htons (cb->s->type);
1390  osr->flags = 0;
1391 
1392  err = cb->s->DoDump (this, cb->state, buffer);
1393  if (err >= 0)
1394  {
1395  if (err == 0)
1396  {
1397  cb->done = true;
1398  }
1399  else
1400  {
1401  // Buffer might have been reallocated, so find our data again.
1402  osr = (ofp_stats_reply*)ofpbuf_at_assert (buffer, 0, sizeof *osr);
1403  osr->flags = ntohs (OFPSF_REPLY_MORE);
1404  }
1405 
1406  int err2 = SendOpenflowBuffer (buffer);
1407  if (err2)
1408  {
1409  err = err2;
1410  }
1411  }
1412 
1413  return err;
1414 }
1415 
1416 void
1417 OpenFlowSwitchNetDevice::StatsDone (ofi::StatsDumpCallback *cb)
1418 {
1419  if (cb)
1420  {
1421  cb->s->DoCleanup (cb->state);
1422  free (cb->s);
1423  free (cb);
1424  }
1425 }
1426 
1427 int
1428 OpenFlowSwitchNetDevice::ReceiveStatsRequest (const void *oh)
1429 {
1430  const ofp_stats_request *rq = (ofp_stats_request*)oh;
1431  size_t rq_len = ntohs (rq->header.length);
1432  int type = ntohs (rq->type);
1433  int body_len = rq_len - offsetof (ofp_stats_request, body);
1434  ofi::Stats* st = new ofi::Stats ((ofp_stats_types)type, (unsigned)body_len);
1435 
1436  if (st == 0)
1437  {
1438  return -EINVAL;
1439  }
1440 
1441  ofi::StatsDumpCallback cb;
1442  cb.done = false;
1443  cb.rq = (ofp_stats_request*)xmemdup (rq, rq_len);
1444  cb.s = st;
1445  cb.state = 0;
1446  cb.swtch = this;
1447 
1448  if (cb.s)
1449  {
1450  int err = cb.s->DoInit (rq->body, body_len, &cb.state);
1451  if (err)
1452  {
1453  NS_LOG_WARN ("failed initialization of stats request type " << type << ": " << strerror (-err));
1454  free (cb.rq);
1455  return err;
1456  }
1457  }
1458 
1459  if (m_controller != 0)
1460  {
1461  m_controller->StartDump (&cb);
1462  }
1463  else
1464  {
1465  NS_LOG_ERROR ("Switch needs to be registered to a controller in order to start the stats reply.");
1466  }
1467 
1468  return 0;
1469 }
1470 
1471 int
1472 OpenFlowSwitchNetDevice::ReceiveEchoRequest (const void *oh)
1473 {
1474  return SendOpenflowBuffer (make_echo_reply ((ofp_header*)oh));
1475 }
1476 
1477 int
1478 OpenFlowSwitchNetDevice::ReceiveEchoReply (const void *oh)
1479 {
1480  return 0;
1481 }
1482 
1483 int
1484 OpenFlowSwitchNetDevice::ForwardControlInput (const void *msg, size_t length)
1485 {
1486  // Check encapsulated length.
1487  ofp_header *oh = (ofp_header*) msg;
1488  if (ntohs (oh->length) > length)
1489  {
1490  return -EINVAL;
1491  }
1492  assert (oh->version == OFP_VERSION);
1493 
1494  int error = 0;
1495 
1496  // Figure out how to handle it.
1497  switch (oh->type)
1498  {
1499  case OFPT_FEATURES_REQUEST:
1500  error = length < sizeof(ofp_header) ? -EFAULT : ReceiveFeaturesRequest (msg);
1501  break;
1502  case OFPT_GET_CONFIG_REQUEST:
1503  error = length < sizeof(ofp_header) ? -EFAULT : ReceiveGetConfigRequest (msg);
1504  break;
1505  case OFPT_SET_CONFIG:
1506  error = length < sizeof(ofp_switch_config) ? -EFAULT : ReceiveSetConfig (msg);
1507  break;
1508  case OFPT_PACKET_OUT:
1509  error = length < sizeof(ofp_packet_out) ? -EFAULT : ReceivePacketOut (msg);
1510  break;
1511  case OFPT_FLOW_MOD:
1512  error = length < sizeof(ofp_flow_mod) ? -EFAULT : ReceiveFlow (msg);
1513  break;
1514  case OFPT_PORT_MOD:
1515  error = length < sizeof(ofp_port_mod) ? -EFAULT : ReceivePortMod (msg);
1516  break;
1517  case OFPT_STATS_REQUEST:
1518  error = length < sizeof(ofp_stats_request) ? -EFAULT : ReceiveStatsRequest (msg);
1519  break;
1520  case OFPT_ECHO_REQUEST:
1521  error = length < sizeof(ofp_header) ? -EFAULT : ReceiveEchoRequest (msg);
1522  break;
1523  case OFPT_ECHO_REPLY:
1524  error = length < sizeof(ofp_header) ? -EFAULT : ReceiveEchoReply (msg);
1525  break;
1526  case OFPT_VPORT_MOD:
1527  error = length < sizeof(ofp_vport_mod) ? -EFAULT : ReceiveVPortMod (msg);
1528  break;
1529  case OFPT_VPORT_TABLE_FEATURES_REQUEST:
1530  error = length < sizeof(ofp_header) ? -EFAULT : ReceiveVPortTableFeaturesRequest (msg);
1531  break;
1532  default:
1533  SendErrorMsg ((ofp_error_type)OFPET_BAD_REQUEST, (ofp_bad_request_code)OFPBRC_BAD_TYPE, msg, length);
1534  error = -EINVAL;
1535  }
1536 
1537  if (msg != 0)
1538  {
1539  free ((ofpbuf*)msg);
1540  }
1541  return error;
1542 }
1543 
1544 sw_chain*
1545 OpenFlowSwitchNetDevice::GetChain ()
1546 {
1547  return m_chain;
1548 }
1549 
1550 uint32_t
1551 OpenFlowSwitchNetDevice::GetNSwitchPorts (void) const
1552 {
1554  return m_ports.size ();
1555 }
1556 
1557 ofi::Port
1558 OpenFlowSwitchNetDevice::GetSwitchPort (uint32_t n) const
1559 {
1561  return m_ports[n];
1562 }
1563 
1564 int
1565 OpenFlowSwitchNetDevice::GetSwitchPortIndex (ofi::Port p)
1566 {
1567  for (size_t i = 0; i < m_ports.size (); i++)
1568  {
1569  if (m_ports[i].netdev == p.netdev)
1570  {
1571  return i;
1572  }
1573  }
1574  return -1;
1575 }
1576 
1577 vport_table_t
1578 OpenFlowSwitchNetDevice::GetVPortTable ()
1579 {
1580  return m_vportTable;
1581 }
1582 
1583 } // namespace ns3
1584 
1585 #endif // NS3_OPENFLOW
Time Seconds(double seconds)
create ns3::Time instances in units of seconds.
Definition: nstime.h:727
void discard_buffer(uint32_t id)
#define N_PKT_BUFFERS
#define NS_LOG_FUNCTION(parameters)
Definition: log.h:345
void ExecuteActions(Ptr< OpenFlowSwitchNetDevice > swtch, uint64_t packet_uid, ofpbuf *buffer, sw_flow_key *key, const ofp_action_header *actions, size_t actions_len, int ignore_no_fwd)
Executes a list of flow table actions.
static const char * GetSerialNumber()
uint16_t m_flags
Flags; configurable by the controller.
bool IsMulticast(const Address &ad)
Address family-independent test for a multicast address.
#define NS_ASSERT(condition)
Definition: assert.h:64
NS_OBJECT_ENSURE_REGISTERED(NullMessageSimulatorImpl)
#define NS_LOG_COMPONENT_DEFINE(name)
Definition: log.h:171
static const char * GetHardwareDescription()
#define NS_LOG_INFO(msg)
Definition: log.h:298
#define NS_LOG_FUNCTION_NOARGS()
Output the name of the function.
Definition: log.h:309
ofpbuf * retrieve_buffer(uint32_t id)
#define NS_FATAL_ERROR(msg)
fatal error handling
Definition: fatal-error.h:72
uint16_t port
Definition: dsdv-manet.cc:44
static TypeId GetTypeId(void)
static const char * GetManufacturerDescription()
void ExecuteVPortActions(Ptr< OpenFlowSwitchNetDevice > swtch, uint64_t packet_uid, ofpbuf *buffer, sw_flow_key *key, const ofp_action_header *actions, size_t actions_len)
Executes a list of virtual port table entry actions.
uint8_t data[writeSize]
uint64_t m_id
Unique identifier for this switch, needed for OpenFlow.
#define OFP_SUPPORTED_ACTIONS
Callback< R > MakeCallback(R(T::*memPtr)(void), OBJ objPtr)
Definition: callback.h:1238
uint32_t save_buffer(ofpbuf *)
static const char * GetSoftwareDescription()
TypeId AddAttribute(std::string name, std::string help, const AttributeValue &initialValue, Ptr< const AttributeAccessor > accessor, Ptr< const AttributeChecker > checker)
Definition: type-id.cc:688
#define OFP_SUPPORTED_VPORT_TABLE_ACTIONS
uint16_t ValidateActions(const sw_flow_key *key, const ofp_action_header *actions, size_t actions_len)
Validates a list of flow table actions.
#define NS_LOG_WARN(msg)
Definition: log.h:280
Time Now(void)
create an ns3::Time instance which contains the current simulation time.
Definition: simulator.cc:287
#define NS_LOG_DEBUG(msg)
Definition: log.h:289
Ptr< const AttributeChecker > MakeTimeChecker(const Time min, const Time max)
Helper to make a Time checker with bounded range.
Definition: time.cc:452
#define NS_LOG_ERROR(msg)
Definition: log.h:271
tuple address
Definition: first.py:37
uint16_t ValidateVPortActions(const ofp_action_header *actions, size_t actions_len)
Validates a list of virtual port table entry actions.
uint16_t m_missSendLen
Flow Table Miss Send Length; configurable by the controller.
TypeId SetParent(TypeId tid)
Definition: type-id.cc:611
#define OFP_SUPPORTED_CAPABILITIES
Time m_lookupDelay
Flow Table Lookup Delay [overhead].