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