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