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