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