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