A Discrete-Event Network Simulator
API
Loading...
Searching...
No Matches
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
23namespace ns3
24{
25
26NS_LOG_COMPONENT_DEFINE("OpenFlowSwitchNetDevice");
27
28NS_OBJECT_ENSURE_REGISTERED(OpenFlowSwitchNetDevice);
29
30/**
31 * Generate an ID.
32 *
33 * \return Generated ID.
34 */
35static uint64_t
37{
38 uint8_t ea[ETH_ADDR_LEN];
39 eth_addr_random(ea);
40 return eth_addr_to_uint64(ea);
41}
42
43const char*
45{
46 return "The ns-3 team";
47}
48
49const char*
51{
52 return "N/A";
53}
54
55const char*
57{
58 return "Simulated OpenFlow Switch";
59}
60
61const char*
63{
64 return "N/A";
65}
66
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
135void
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
156void
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
169int
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
213void
215{
217 m_ifIndex = index;
218}
219
222{
224 return m_ifIndex;
225}
226
229{
231 return m_channel;
232}
233
234void
236{
239}
240
243{
245 return m_address;
246}
247
248bool
250{
252 m_mtu = mtu;
253 return true;
254}
255
256uint16_t
258{
260 return m_mtu;
261}
262
263bool
265{
267 return true;
268}
269
270void
272{
273}
274
275bool
277{
279 return true;
280}
281
284{
287}
288
289bool
291{
293 return true;
294}
295
298{
299 NS_LOG_FUNCTION(this << multicastGroup);
300 Mac48Address multicast = Mac48Address::GetMulticast(multicastGroup);
301 return multicast;
302}
303
304bool
306{
308 return false;
309}
310
311bool
313{
315 return true;
316}
317
318void
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
335bool
336OpenFlowSwitchNetDevice::Send(Ptr<Packet> packet, const Address& dest, uint16_t protocolNumber)
337{
339 return SendFrom(packet, m_address, dest, protocolNumber);
340}
341
342bool
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
368{
370 return m_node;
371}
372
373void
375{
377 m_node = node;
378}
379
380bool
382{
384 return true;
385}
386
387void
389{
391 m_rxCallback = cb;
392}
393
394void
396{
399}
400
401bool
403{
405 return true;
406}
407
410{
411 NS_LOG_FUNCTION(this << addr);
412 return Mac48Address::GetMulticast(addr);
413}
414
415// Add a virtual port table entry.
416int
417OpenFlowSwitchNetDevice::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
465ofpbuf*
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
634void
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 {
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
746int
747OpenFlowSwitchNetDevice::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
777void
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
804void
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
855void*
856OpenFlowSwitchNetDevice::MakeOpenflowReply(size_t openflow_len, uint8_t type, ofpbuf** bufferp)
857{
858 return make_openflow_xid(openflow_len, type, 0, bufferp);
859}
860
861int
863{
864 if (m_controller)
865 {
866 update_openflow_length(buffer);
867 m_controller->ReceiveFromSwitch(this, buffer);
868 }
869
870 return 0;
871}
872
873void
874OpenFlowSwitchNetDevice::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
899void
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
912 /// \todo This should probably be fixed eventually to specify different available features.
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
919void
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
940void
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
955int
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
976void
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
990void
991OpenFlowSwitchNetDevice::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
1009void
1010OpenFlowSwitchNetDevice::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
1020void
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);
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
1056void
1057OpenFlowSwitchNetDevice::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
1112int
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
1168int
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;
1198 /// \todo Possibly disable the Port's Net Device via the appropriate interface.
1199 }
1200 else if ((opm->config & htonl(OFPPC_PORT_DOWN)) == 0 && (p.config & OFPPC_PORT_DOWN))
1201 {
1202 p.config &= ~OFPPC_PORT_DOWN;
1203 /// \todo Possibly enable the Port's Net Device via the appropriate interface.
1204 }
1205 }
1206 }
1207
1208 return 0;
1209}
1210
1211int
1213{
1215 return 0;
1216}
1217
1218int
1220{
1222 return 0;
1223}
1224
1225int
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
1237int
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
1254int
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
1299int
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
1323int
1324OpenFlowSwitchNetDevice::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);
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
1410int
1411OpenFlowSwitchNetDevice::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);
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
1459int
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
1494int
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
1534void
1536{
1537 if (cb)
1538 {
1539 cb->s->DoCleanup(cb->state);
1540 free(cb->s);
1541 free(cb);
1542 }
1543}
1544
1545int
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 {
1585 "Switch needs to be registered to a controller in order to start the stats reply.");
1586 }
1587
1588 return 0;
1589}
1590
1591int
1593{
1594 return SendOpenflowBuffer(make_echo_reply((ofp_header*)oh));
1595}
1596
1597int
1599{
1600 return 0;
1601}
1602
1603int
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
1667sw_chain*
1669{
1670 return m_chain;
1671}
1672
1675{
1677 return m_ports.size();
1678}
1679
1682{
1684 return m_ports[n];
1685}
1686
1687int
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
1700vport_table_t
1702{
1703 return m_vportTable;
1704}
1705
1706} // namespace ns3
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)
Callback template class.
Definition: callback.h:438
bool IsNull() const
Check for null implementation.
Definition: callback.h:571
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)
static Mac48Address GetBroadcast()
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:231
virtual void DoDispose()
Destructor implementation.
Definition: object.cc:444
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.
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
AttributeValue implementation for Time.
Definition: nstime.h:1406
a unique identifier for an interface.
Definition: type-id.h:59
TypeId SetParent(TypeId tid)
Set the parent TypeId.
Definition: type-id.cc:932
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
Ptr< const AttributeChecker > MakeTimeChecker()
Helper to make an unbounded Time checker.
Definition: nstime.h:1427
Ptr< const AttributeAccessor > MakeTimeAccessor(T1 a1)
Definition: nstime.h:1407
Ptr< const AttributeAccessor > MakeUintegerAccessor(T1 a1)
Definition: uinteger.h:46
#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:1355
Time Seconds(double value)
Construct a Time in the indicated unit.
Definition: nstime.h:1319
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.
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:706
static uint64_t GenerateId()
Generate an ID.
void discard_buffer(uint32_t id)
#define OFP_SUPPORTED_CAPABILITIES
uint32_t save_buffer(ofpbuf *)
ofpbuf * retrieve_buffer(uint32_t id)
#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.