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