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];
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.",
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
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);
117}
118
123
124void
126{
128
129 for (auto b = m_ports.begin(), e = m_ports.end(); b != e; b++)
130 {
132 b->netdev = nullptr;
133 }
134 m_ports.clear();
135
136 m_controller = nullptr;
137
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 {
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
185
186 NS_LOG_DEBUG("RegisterProtocolHandler for " << switchPort->GetInstanceTypeId().GetName());
189 0,
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
292
293bool
295{
297 return false;
298}
299
300bool
302{
304 return true;
305}
306
307void
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
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
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
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
414 if (vpe)
415 {
416 NS_LOG_ERROR("vport " << vport << " already exists!");
418 return EINVAL;
419 }
420
421 // check whether actions are valid
422 uint16_t v_code = ofi::ValidateVPortActions(ovpm->actions, actions_len);
424 {
426 return EINVAL;
427 }
428
430
431 vpe->vport = vport;
432 vpe->parent_port = parent_port;
434 {
435 NS_LOG_ERROR("port " << vport << " is not in the virtual port range (" << OFPP_VP_START
436 << "-" << OFPP_VP_END << ")");
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
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;
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
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 {
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
522 }
523 }
524 else
525 {
526 // ARP Packet; the underlying OpenFlow header isn't used to match, so this is probably
527 // superfluous.
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.
536 arp_hd.GetDestinationHardwareAddress().CopyTo(
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
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 {
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
572 }
573 }
574 else if (ip_h->ip_proto == UdpL4Protocol::PROT_NUMBER)
575 {
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);
589 udp_csum = csum_add16(udp_csum, udp_h->udp_len);
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
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,
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 {
649 {
650 m_rxCallback(this, packet, protocol, src);
651 }
654 {
656 {
657 m_rxCallback(this, packet, protocol, src);
658 }
659 else
660 {
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;
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
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 {
700 }
701 }
702
703 // If any flows have expired, delete them and notify the controller.
705 sw_flow* f;
706 sw_flow* n;
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());
727 list_remove(&f->node);
728 flow_free(f);
729 }
730
731 m_lastExecute = now;
732 }
733}
734
735int
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 {
755 }
756 prev_port = i;
757 }
758 if (prev_port != -1)
759 {
761 }
762
763 return 0;
764}
765
766void
768{
769 if (out_port >= 0 && out_port < DP_MAX_PORTS)
770 {
772 if (p.netdev && !(p.config & OFPPC_PORT_DOWN))
773 {
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 {
804 }
805 else if (out_port == OFPP_ALL)
806 {
808 }
809 else if (out_port == OFPP_CONTROLLER)
810 {
812 }
813 else if (out_port == OFPP_IN_PORT)
814 {
816 }
817 else if (out_port == OFPP_TABLE)
818 {
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 {
828 }
829 else
830 {
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 {
841 }
842}
843
844void*
849
850int
852{
853 if (m_controller)
854 {
856 m_controller->ReceiveFromSwitch(this, buffer);
857 }
858
859 return 0;
860}
861
862void
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
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;
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);
924 }
925
926 SendOpenflowBuffer(buffer);
927}
928
929void
931{
932 ofpbuf* buffer;
936 &buffer);
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{
949
950 // Port is always enabled because the Net Device is always enabled.
952
953 if (p.netdev->IsLinkUp())
954 {
956 }
957 else
958 {
960 }
961
962 return ((orig_config != p.config) || (orig_state != p.state));
963}
964
965void
967{
968 ofpbuf* 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
981{
982 ofpbuf* 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;
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,
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
1034 {
1036 }
1037 }
1038
1039 // Clean up; at this point we're done with the packet.
1040 m_packetData.erase(packet_uid);
1042 ofpbuf_delete(buffer);
1043}
1044
1045void
1047{
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) &&
1057 {
1058 ofpbuf_delete(buffer);
1059 return;
1060 }
1061
1062 // drop MPLS packets with TTL 1
1063 if (buffer->l2_5)
1064 {
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
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,
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) &&
1112 {
1113 return 0;
1114 }
1115
1116 // run through the chain of port table entries
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{
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
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 {
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 {
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;
1220 osc->flags = htons(m_flags);
1221 osc->miss_send_len = htons(m_missSendLen);
1222
1223 return SendOpenflowBuffer(buffer);
1224}
1225
1226int
1228{
1230
1234 {
1236 }
1237
1238 m_flags = n_flags;
1239 m_missSendLen = ntohs(osc->miss_send_len);
1240 return 0;
1241}
1242
1243int
1245{
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);
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{
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 {
1301 {
1304 ovpm,
1305 ntohs(ovpm->header.length));
1306 }
1307 }
1308
1309 return 0;
1310}
1311
1312int
1314{
1315 size_t actions_len = ntohs(ofm->header.length) - sizeof *ofm;
1316
1317 // Allocate memory.
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);
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 {
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,
1388 false);
1389 ofpbuf_delete(buffer);
1390 }
1391 else
1392 {
1393 return -ESRCH;
1394 }
1395 }
1396 return 0;
1397}
1398
1399int
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);
1409 {
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 {
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,
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{
1487 ofpbuf* buffer;
1488 int err;
1489
1490 if (cb->done)
1491 {
1492 return 0;
1493 }
1494
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{
1538 size_t rq_len = ntohs(rq->header.length);
1539 int type = ntohs(rq->type);
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
1585
1586int
1588{
1589 return 0;
1590}
1591
1592int
1594{
1595 // Check encapsulated length.
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 {
1609 error = length < sizeof(ofp_header) ? -EFAULT : ReceiveFeaturesRequest(msg);
1610 break;
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;
1639 error = length < sizeof(ofp_header) ? -EFAULT : ReceiveVPortTableFeaturesRequest(msg);
1640 break;
1641 default:
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:23
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.
Packet header for IPv4.
Definition ipv4-header.h:23
static constexpr uint16_t PROT_NUMBER
Protocol number.
Describes an IPv6 address.
an EUI-48 address
static Mac48Address GetMulticast(Ipv4Address address)
static bool IsMatchingType(const Address &address)
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.
Definition ptr.h:66
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
static constexpr uint8_t PROT_NUMBER
Protocol number (see http://www.iana.org/assignments/protocol-numbers)
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
AttributeValue implementation for Time.
Definition nstime.h:1431
a unique identifier for an interface.
Definition type-id.h:49
TypeId SetParent(TypeId tid)
Set the parent TypeId.
Definition type-id.cc:1001
Packet header for UDP packets.
Definition udp-header.h:30
static constexpr uint8_t PROT_NUMBER
Protocol number (see http://www.iana.org/assignments/protocol-numbers)
Hold an unsigned integer type.
Definition uinteger.h:34
OpenFlow statistics.
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
Ptr< const AttributeChecker > MakeTimeChecker()
Helper to make an unbounded Time checker.
Definition nstime.h:1452
#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
#define NS_OBJECT_ENSURE_REGISTERED(type)
Register an Object subclass with the TypeId system.
Definition object-base.h:35
Ptr< T > Create(Ts &&... args)
Create class instances by constructors with varying numbers of arguments and return them by Ptr.
Definition ptr.h:436
Time NanoSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition nstime.h:1380
Time Seconds(double value)
Construct a Time in the indicated unit.
Definition nstime.h:1344
void ExecuteVPortActions(Ptr< OpenFlowSwitchNetDevice > swtch, uint64_t packet_uid, ofpbuf *buffer, sw_flow_key *key, const ofp_action_header *actions, size_t actions_len)
Executes a list of virtual port table entry actions.
void ExecuteActions(Ptr< OpenFlowSwitchNetDevice > swtch, uint64_t packet_uid, ofpbuf *buffer, sw_flow_key *key, const ofp_action_header *actions, size_t actions_len, int ignore_no_fwd)
Executes a list of flow table actions.
uint16_t ValidateActions(const sw_flow_key *key, const ofp_action_header *actions, size_t actions_len)
Validates a list of flow table actions.
uint16_t ValidateVPortActions(const ofp_action_header *actions, size_t actions_len)
Validates a list of virtual port table entry actions.
Every class exported by the ns3 library is enclosed in the ns3 namespace.
Ptr< const AttributeAccessor > MakeTimeAccessor(T1 a1)
Definition nstime.h:1432
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.
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.
bool done
Whether we are done requesting stats.
Packet Metadata, allows us to track the packet's metadata as it passes through the switch.
ofpbuf * buffer
The OpenFlow buffer as created from the Packet, with its data and headers.
Ptr< Packet > packet
The Packet itself.