22 #include <ns3/internet-module.h>
23 #include <ns3/network-module.h>
44 OFSwitch13Controller::DoDispose();
52 .SetGroupName(
"OFSwitch13")
54 .AddAttribute(
"EnableMeter",
55 "Enable per-flow mettering.",
59 .AddAttribute(
"MeterRate",
60 "Per-flow meter rate.",
63 MakeDataRateChecker())
64 .AddAttribute(
"LinkAggregation",
65 "Enable link aggregation.",
69 .AddAttribute(
"ServerIpAddr",
70 "Server IPv4 address.",
74 .AddAttribute(
"ServerTcpPort",
78 MakeUintegerChecker<uint64_t>())
79 .AddAttribute(
"ServerMacAddr",
80 "Server MAC address.",
83 MakeAddressChecker());
94 char* msgStr = ofl_structs_match_to_string((
struct ofl_match_header*)msg->match,
nullptr);
98 if (msg->reason == OFPR_ACTION)
102 struct ofl_match_tlv* tlv;
103 tlv = oxm_match_lookup(OXM_OF_ETH_TYPE, (
struct ofl_match*)msg->match);
104 memcpy(ðType, tlv->value, OXM_LENGTH(OXM_OF_ETH_TYPE));
106 if (ethType == ArpL3Protocol::PROT_NUMBER)
111 else if (ethType == Ipv4L3Protocol::PROT_NUMBER)
119 ofl_msg_free((
struct ofl_msg_header*)msg,
nullptr);
130 if (swtch->GetDpId() == 1)
134 else if (swtch->GetDpId() == 2)
146 uint64_t swDpId = swtch->GetDpId();
153 "flow-mod cmd=add,table=0,prio=20 "
154 "eth_type=0x0806,arp_op=1 apply:output=ctrl");
161 "group-mod cmd=add,type=sel,group=3 "
162 "weight=1,port=any,group=any set_field=ip_src:10.1.1.1"
163 ",set_field=eth_src:00:00:00:00:00:01,output=1 "
164 "weight=1,port=any,group=any set_field=ip_src:10.1.1.1"
165 ",set_field=eth_src:00:00:00:00:00:01,output=2");
171 "group-mod cmd=add,type=ind,group=3 "
172 "weight=0,port=any,group=any set_field=ip_src:10.1.1.1"
173 ",set_field=eth_src:00:00:00:00:00:01,output=1");
178 "group-mod cmd=add,type=ind,group=1 "
179 "weight=0,port=any,group=any set_field=ip_dst:10.1.1.2,"
180 "set_field=eth_dst:00:00:00:00:00:08,output=3");
182 "group-mod cmd=add,type=ind,group=2 "
183 "weight=0,port=any,group=any set_field=ip_dst:10.1.1.3,"
184 "set_field=eth_dst:00:00:00:00:00:0a,output=4");
188 "flow-mod cmd=add,table=0,prio=500 "
189 "in_port=1,eth_type=0x0800,ip_proto=6,ip_dst=10.1.1.1,"
190 "eth_dst=00:00:00:00:00:01 apply:output=ctrl");
192 "flow-mod cmd=add,table=0,prio=500 "
193 "in_port=2,eth_type=0x0800,ip_proto=6,ip_dst=10.1.1.1,"
194 "eth_dst=00:00:00:00:00:01 apply:output=ctrl");
198 "flow-mod cmd=add,table=0,prio=700 "
199 "in_port=3,eth_type=0x0800,ip_proto=6 apply:group=3");
201 "flow-mod cmd=add,table=0,prio=700 "
202 "in_port=4,eth_type=0x0800,ip_proto=6 apply:group=3");
211 uint64_t swDpId = swtch->GetDpId();
217 "group-mod cmd=add,type=sel,group=1 "
218 "weight=1,port=any,group=any output=1 "
219 "weight=1,port=any,group=any output=2");
225 "group-mod cmd=add,type=ind,group=1 "
226 "weight=0,port=any,group=any output=1");
231 "flow-mod cmd=add,table=0,prio=500 "
232 "in_port=1 write:output=3");
234 "flow-mod cmd=add,table=0,prio=500 "
235 "in_port=2 write:output=3");
239 "flow-mod cmd=add,table=0,prio=500 "
240 "in_port=3 write:group=1");
250 struct ofl_match_tlv* tlv;
256 tlv = oxm_match_lookup(OXM_OF_ARP_OP, (
struct ofl_match*)msg->match);
257 memcpy(&arpOp, tlv->value, OXM_LENGTH(OXM_OF_ARP_OP));
261 tlv = oxm_match_lookup(OXM_OF_IN_PORT, (
struct ofl_match*)msg->match);
262 memcpy(&inPort, tlv->value, OXM_LENGTH(OXM_OF_IN_PORT));
273 tlv = oxm_match_lookup(OXM_OF_ARP_SHA, (
struct ofl_match*)msg->match);
275 tlv = oxm_match_lookup(OXM_OF_ARP_THA, (
struct ofl_match*)msg->match);
279 if (arpOp == ArpHeader::ARP_TYPE_REQUEST)
281 uint8_t replyData[64];
284 if (dstIp == serverIp)
301 struct ofl_action_output*
action =
302 (
struct ofl_action_output*)xmalloc(
sizeof(
struct ofl_action_output));
303 action->header.type = OFPAT_OUTPUT;
304 action->port = OFPP_IN_PORT;
308 struct ofl_msg_packet_out reply;
309 reply.header.type = OFPT_PACKET_OUT;
310 reply.buffer_id = OFP_NO_BUFFER;
311 reply.in_port = inPort;
312 reply.data_length = 64;
313 reply.data = &replyData[0];
314 reply.actions_num = 1;
315 reply.actions = (
struct ofl_action_header**)&
action;
317 SendToSwitch(swtch, (
struct ofl_msg_header*)&reply, xid);
322 ofl_msg_free((
struct ofl_msg_header*)msg,
nullptr);
333 static uint32_t connectionCounter = 0;
336 struct ofl_match_tlv* tlv;
342 tlv = oxm_match_lookup(OXM_OF_IN_PORT, (
struct ofl_match*)msg->match);
343 memcpy(&inPort, tlv->value, OXM_LENGTH(OXM_OF_IN_PORT));
347 tlv = oxm_match_lookup(OXM_OF_ETH_SRC, (
struct ofl_match*)msg->match);
359 tlv = oxm_match_lookup(OXM_OF_TCP_SRC, (
struct ofl_match*)msg->match);
360 memcpy(&srcPort, tlv->value, OXM_LENGTH(OXM_OF_TCP_SRC));
361 tlv = oxm_match_lookup(OXM_OF_TCP_DST, (
struct ofl_match*)msg->match);
362 memcpy(&dstPort, tlv->value, OXM_LENGTH(OXM_OF_TCP_DST));
366 uint8_t replyData[64];
371 struct ofl_action_output* arpAction =
372 (
struct ofl_action_output*)xmalloc(
sizeof(
struct ofl_action_output));
373 arpAction->header.type = OFPAT_OUTPUT;
374 arpAction->port = OFPP_IN_PORT;
375 arpAction->max_len = 0;
378 struct ofl_msg_packet_out arpRequest;
379 arpRequest.header.type = OFPT_PACKET_OUT;
380 arpRequest.buffer_id = OFP_NO_BUFFER;
381 arpRequest.in_port = inPort;
382 arpRequest.data_length = 64;
383 arpRequest.data = &replyData[0];
384 arpRequest.actions_num = 1;
385 arpRequest.actions = (
struct ofl_action_header**)&arpAction;
387 SendToSwitch(swtch, (
struct ofl_msg_header*)&arpRequest, 0);
392 "Invalid IP address / TCP port.");
395 uint16_t serverNumber = 1 + (connectionCounter % 2);
396 NS_LOG_INFO(
"Connection " << connectionCounter <<
" redirected to server " << serverNumber);
399 uint64_t swDpId = swtch->GetDpId();
404 std::ostringstream meterCmd;
405 meterCmd <<
"meter-mod cmd=add,flags=1,meter=" << connectionCounter
411 std::ostringstream flowCmd;
412 flowCmd <<
"flow-mod cmd=add,table=0,prio=1000 eth_type=0x0800,ip_proto=6"
417 flowCmd <<
" meter:" << connectionCounter;
419 flowCmd <<
" write:group=" << serverNumber;
423 struct ofl_action_group*
action =
424 (
struct ofl_action_group*)xmalloc(
sizeof(
struct ofl_action_group));
425 action->header.type = OFPAT_GROUP;
426 action->group_id = serverNumber;
429 struct ofl_msg_packet_out reply;
430 reply.header.type = OFPT_PACKET_OUT;
431 reply.buffer_id = msg->buffer_id;
432 reply.in_port = inPort;
433 reply.actions_num = 1;
434 reply.actions = (
struct ofl_action_header**)&
action;
435 reply.data_length = 0;
436 reply.data =
nullptr;
437 if (msg->buffer_id == NO_BUFFER)
440 reply.data_length = msg->data_length;
441 reply.data = msg->data;
444 SendToSwitch(swtch, (
struct ofl_msg_header*)&reply, xid);
448 ofl_msg_free((
struct ofl_msg_header*)msg,
nullptr);
457 case static_cast<uint32_t
>(OXM_OF_ARP_SPA):
458 case static_cast<uint32_t
>(OXM_OF_ARP_TPA):
459 case static_cast<uint32_t
>(OXM_OF_IPV4_DST):
460 case static_cast<uint32_t
>(OXM_OF_IPV4_SRC): {
462 int size = OXM_LENGTH(oxm_of);
463 struct ofl_match_tlv* tlv = oxm_match_lookup(oxm_of, match);
464 memcpy(&ip, tlv->value, size);
481 arp.
SetRequest(srcMac, srcIp, Mac48Address::GetBroadcast(), dstIp);
491 memset(buffer, 0, 46);
500 if (Node::ChecksumEnabled())
522 arp.
SetReply(srcMac, srcIp, dstMac, dstIp);
532 memset(buffer, 0, 46);
541 if (Node::ChecksumEnabled())
554 std::pair<Ipv4Address, Mac48Address> entry(ipAddr, macAddr);
555 std::pair<IpMacMap_t::iterator, bool> ret;
557 if (ret.second ==
true)
559 NS_LOG_INFO(
"New ARP entry: " << ipAddr <<
" - " << macAddr);
567 IpMacMap_t::iterator ret;
571 NS_LOG_INFO(
"Found ARP entry: " << ip <<
" - " << ret->second);
An border OpenFlow 1.3 controller.
Address m_serverIpAddress
Virtual server IP address.
ofl_err HandleConnectionRequest(struct ofl_msg_packet_in *msg, Ptr< const RemoteSwitch > swtch, uint32_t xid)
Handle TCP connection request.
Ipv4Address ExtractIpv4Address(uint32_t oxm_of, struct ofl_match *match)
Extract an IPv4 address from packet match.
Ptr< Packet > CreateArpRequest(Mac48Address srcMac, Ipv4Address srcIp, Ipv4Address dstIp)
Create an ARP request packet, encapsulated inside of an Ethernet frame.
void HandshakeSuccessful(Ptr< const RemoteSwitch > swtch) override
Function invoked after a successfully handshake procedure between this controller and a remote switch...
Ptr< Packet > CreateArpReply(Mac48Address srcMac, Ipv4Address srcIp, Mac48Address dstMac, Ipv4Address dstIp)
Create an ARP reply packet, encapsulated inside of an Ethernet frame.
uint16_t m_serverTcpPort
Virtual server TCP port.
void DoDispose() override
Destructor implementation.
QosController()
Default constructor.
ofl_err HandlePacketIn(struct ofl_msg_packet_in *msg, Ptr< const RemoteSwitch > swtch, uint32_t xid) override
Handle a packet in message sent by the switch to this controller.
static TypeId GetTypeId()
Register this type.
void ConfigureBorderSwitch(Ptr< const RemoteSwitch > swtch)
Configure the border switch.
Address m_serverMacAddress
Border switch MAC address.
void ConfigureAggregationSwitch(Ptr< const RemoteSwitch > swtch)
Configure the aggregation switch.
IpMacMap_t m_arpTable
ARP resolution table.
bool m_meterEnable
Enable per-flow mettering.
~QosController() override
Dummy destructor.
DataRate m_meterRate
Per-flow meter rate.
ofl_err HandleArpPacketIn(struct ofl_msg_packet_in *msg, Ptr< const RemoteSwitch > swtch, uint32_t xid)
Handle ARP request messages.
void SaveArpEntry(Ipv4Address ipAddr, Mac48Address macAddr)
Save the pair IP / MAC address in ARP table.
bool m_linkAggregation
Enable link aggregation.
Mac48Address GetArpEntry(Ipv4Address ip)
Perform an ARP resolution.
a polymophic address class
AttributeValue implementation for Address.
AttributeValue implementation for Boolean.
uint64_t GetBitRate() const
Get the underlying bitrate.
AttributeValue implementation for DataRate.
Packet trailer for Ethernet.
void EnableFcs(bool enable)
Enable or disable FCS checking and calculations.
void CalcFcs(Ptr< const Packet > p)
Updates the Fcs Field to the correct FCS.
Ipv4 addresses are stored in host order in this class.
void CopyFrom(const uint8_t buffer[6])
OpenFlow 1.3 controller base class that can handle a collection of OpenFlow switches and provides the...
int SendToSwitch(Ptr< const RemoteSwitch > swtch, struct ofl_msg_header *msg, uint32_t xid=0)
Send a OFLib message to a registered switch.
int DpctlExecute(uint64_t dpId, const std::string textCmd)
Execute a dpctl command to interact with the remote switch.
void AddAtEnd(Ptr< const Packet > packet)
Concatenate the input packet at the end of the current packet.
void AddHeader(const Header &header)
Add header to this packet.
uint32_t GetSize() const
Returns the the size in bytes of the packet (including the zero-filled initial payload).
uint32_t CopyData(uint8_t *buffer, uint32_t size) const
Copy the packet contents to a byte buffer.
void AddTrailer(const Trailer &trailer)
Add trailer to this packet.
Smart pointer class similar to boost::intrusive_ptr.
a unique identifier for an interface.
TypeId SetParent(TypeId tid)
Set the parent TypeId.
Hold an unsigned integer type.
#define NS_ASSERT_MSG(condition, message)
At runtime, in debugging builds, if this condition is not true, the program prints the message to out...
Ptr< const AttributeAccessor > MakeBooleanAccessor(T1 a1)
Create an AttributeAccessor for a class data member, or a lone class get functor or set method.
Ptr< const AttributeChecker > MakeBooleanChecker()
Ptr< const AttributeAccessor > MakeUintegerAccessor(T1 a1)
Create an AttributeAccessor for a class data member, or a lone class get functor or set method.
#define NS_ABORT_MSG(msg)
Unconditional abnormal program termination with a message.
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
#define NS_LOG_DEBUG(msg)
Use NS_LOG to output a message of level LOG_DEBUG.
#define NS_LOG_FUNCTION(parameters)
If log level LOG_FUNCTION is enabled, this macro will output all input parameters separated by ",...
#define NS_LOG_INFO(msg)
Use NS_LOG to output a message of level LOG_INFO.
void(* DataRate)(DataRate oldValue, DataRate newValue)
TracedValue callback signature for DataRate.
#define NS_OBJECT_ENSURE_REGISTERED(type)
Register an Object subclass with the TypeId system.