A Discrete-Event Network Simulator
API
ofswitch13-learning-controller.cc
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2015 University of Campinas (Unicamp)
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License version 2 as
6  * published by the Free Software Foundation;
7  *
8  * This program is distributed in the hope that it will be useful,
9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11  * GNU General Public License for more details.
12  *
13  * You should have received a copy of the GNU General Public License
14  * along with this program; if not, write to the Free Software
15  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
16  *
17  * Author: Luciano Jerez Chaves <ljerezchaves@gmail.com>
18  */
19 
20 #ifdef NS3_OFSWITCH13
21 
23 
24 namespace ns3
25 {
26 
27 NS_LOG_COMPONENT_DEFINE("OFSwitch13LearningController");
28 NS_OBJECT_ENSURE_REGISTERED(OFSwitch13LearningController);
29 
30 /********** Public methods ***********/
32 {
33  NS_LOG_FUNCTION(this);
34 }
35 
37 {
38  NS_LOG_FUNCTION(this);
39 }
40 
41 TypeId
43 {
44  static TypeId tid = TypeId("ns3::OFSwitch13LearningController")
46  .SetGroupName("OFSwitch13")
47  .AddConstructor<OFSwitch13LearningController>();
48  return tid;
49 }
50 
51 void
53 {
54  NS_LOG_FUNCTION(this);
55 
56  m_learnedInfo.clear();
58 }
59 
60 ofl_err
61 OFSwitch13LearningController::HandlePacketIn(struct ofl_msg_packet_in* msg,
62  Ptr<const RemoteSwitch> swtch,
63  uint32_t xid)
64 {
65  NS_LOG_FUNCTION(this << swtch << xid);
66 
67  static int prio = 100;
68  uint32_t outPort = OFPP_FLOOD;
69  enum ofp_packet_in_reason reason = msg->reason;
70 
71  // Get the switch datapath ID
72  uint64_t swDpId = swtch->GetDpId();
73 
74  char* msgStr =
75  ofl_structs_match_to_string((struct ofl_match_header*)msg->match,
76  nullptr);
77  NS_LOG_DEBUG("Packet in match: " << msgStr);
78  free(msgStr);
79 
80  if (reason == OFPR_NO_MATCH)
81  {
82  // Let's get necessary information (input port and mac address)
83  uint32_t inPort;
84  size_t portLen = OXM_LENGTH(OXM_OF_IN_PORT); // (Always 4 bytes)
85  struct ofl_match_tlv* input =
86  oxm_match_lookup(OXM_OF_IN_PORT, (struct ofl_match*)msg->match);
87  memcpy(&inPort, input->value, portLen);
88 
89  Mac48Address src48;
90  struct ofl_match_tlv* ethSrc =
91  oxm_match_lookup(OXM_OF_ETH_SRC, (struct ofl_match*)msg->match);
92  src48.CopyFrom(ethSrc->value);
93 
94  Mac48Address dst48;
95  struct ofl_match_tlv* ethDst =
96  oxm_match_lookup(OXM_OF_ETH_DST, (struct ofl_match*)msg->match);
97  dst48.CopyFrom(ethDst->value);
98 
99  // Get L2Table for this datapath
100  auto it = m_learnedInfo.find(swDpId);
101  if (it != m_learnedInfo.end())
102  {
103  L2Table_t* l2Table = &it->second;
104 
105  // Looking for out port based on dst address (except for broadcast)
106  if (!dst48.IsBroadcast())
107  {
108  auto itDst = l2Table->find(dst48);
109  if (itDst != l2Table->end())
110  {
111  outPort = itDst->second;
112  }
113  else
114  {
115  NS_LOG_DEBUG("No L2 info for mac " << dst48 << ". Flood.");
116  }
117  }
118 
119  // Learning port from source address
120  NS_ASSERT_MSG(!src48.IsBroadcast(), "Invalid src broadcast addr");
121  auto itSrc = l2Table->find(src48);
122  if (itSrc == l2Table->end())
123  {
124  std::pair<Mac48Address, uint32_t> entry(src48, inPort);
125  auto ret = l2Table->insert(entry);
126  if (ret.second == false)
127  {
128  NS_LOG_ERROR("Can't insert mac48address / port pair");
129  }
130  else
131  {
132  NS_LOG_DEBUG("Learning that mac "
133  << src48 << " can be found at port "
134  << inPort);
135 
136  // Send a flow-mod to switch creating this flow. Let's
137  // configure the flow entry to 10s idle timeout and to
138  // notify the controller when flow expires. (flags=0x0001)
139  std::ostringstream cmd;
140  cmd << "flow-mod cmd=add,table=0,idle=10,flags=0x0001"
141  << ",prio=" << ++prio << " eth_dst=" << src48
142  << " apply:output=" << inPort;
143  DpctlExecute(swDpId, cmd.str());
144  }
145  }
146  else
147  {
148  NS_ASSERT_MSG(itSrc->second == inPort,
149  "Inconsistent L2 switching table");
150  }
151  }
152  else
153  {
154  NS_LOG_ERROR("No L2 table for this datapath id " << swDpId);
155  }
156 
157  // Lets send the packet out to switch.
158  struct ofl_msg_packet_out reply;
159  reply.header.type = OFPT_PACKET_OUT;
160  reply.buffer_id = msg->buffer_id;
161  reply.in_port = inPort;
162  reply.data_length = 0;
163  reply.data = nullptr;
164 
165  if (msg->buffer_id == NO_BUFFER)
166  {
167  // No packet buffer. Send data back to switch
168  reply.data_length = msg->data_length;
169  reply.data = msg->data;
170  }
171 
172  // Create output action
173  struct ofl_action_output* a = (struct ofl_action_output*)xmalloc(
174  sizeof(struct ofl_action_output));
175  a->header.type = OFPAT_OUTPUT;
176  a->port = outPort;
177  a->max_len = 0;
178 
179  reply.actions_num = 1;
180  reply.actions = (struct ofl_action_header**)&a;
181 
182  SendToSwitch(swtch, (struct ofl_msg_header*)&reply, xid);
183  free(a);
184  }
185  else
186  {
187  NS_LOG_WARN("This controller can't handle the packet. Unkwnon reason.");
188  }
189 
190  // All handlers must free the message when everything is ok
191  ofl_msg_free((struct ofl_msg_header*)msg, nullptr);
192  return 0;
193 }
194 
195 ofl_err
197  struct ofl_msg_flow_removed* msg,
198  Ptr<const RemoteSwitch> swtch,
199  uint32_t xid)
200 {
201  NS_LOG_FUNCTION(this << swtch << xid);
202 
203  // Get the switch datapath ID
204  uint64_t swDpId = swtch->GetDpId();
205 
206  NS_LOG_DEBUG("Flow entry expired. Removing from L2 switch table.");
207  auto it = m_learnedInfo.find(swDpId);
208  if (it != m_learnedInfo.end())
209  {
210  Mac48Address mac48;
211  struct ofl_match_tlv* ethSrc =
212  oxm_match_lookup(OXM_OF_ETH_DST,
213  (struct ofl_match*)msg->stats->match);
214  mac48.CopyFrom(ethSrc->value);
215 
216  L2Table_t* l2Table = &it->second;
217  auto itSrc = l2Table->find(mac48);
218  if (itSrc != l2Table->end())
219  {
220  l2Table->erase(itSrc);
221  }
222  }
223 
224  // All handlers must free the message when everything is ok
225  ofl_msg_free_flow_removed(msg, true, nullptr);
226  return 0;
227 }
228 
229 /********** Private methods **********/
230 void
231 OFSwitch13LearningController::HandshakeSuccessful(Ptr<const RemoteSwitch> swtch)
232 {
233  NS_LOG_FUNCTION(this << swtch);
234 
235  // Get the switch datapath ID
236  uint64_t swDpId = swtch->GetDpId();
237 
238  // After a successfull handshake, let's install the table-miss entry,
239  // setting to 128 bytes the maximum amount of data from a packet that should
240  // be sent to the controller.
241  DpctlExecute(swDpId,
242  "flow-mod cmd=add,table=0,prio=0 "
243  "apply:output=ctrl:128");
244 
245  // Configure te switch to buffer packets and send only the first 128 bytes
246  // of each packet sent to the controller when not using an output action to
247  // the OFPP_CONTROLLER logical port.
248  DpctlExecute(swDpId, "set-config miss=128");
249 
250  // Create an empty L2SwitchingTable and insert it into m_learnedInfo
251  L2Table_t l2Table;
252  std::pair<uint64_t, L2Table_t> entry(swDpId, l2Table);
253  auto ret = m_learnedInfo.insert(entry);
254  if (ret.second == false)
255  {
256  NS_LOG_ERROR("Table exists for this datapath.");
257  }
258 }
259 
260 } // namespace ns3
261 #endif // NS3_OFSWITCH13
OFSwitch13Controller()
Default constructor.
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 DoDispose() override
Destructor implementation.
ofl_err HandlePacketIn(struct ofl_msg_packet_in *msg, Ptr< const RemoteSwitch > swtch, uint32_t xid) override
Handle packet-in messages sent from switch to this controller.
ofl_err HandleFlowRemoved(struct ofl_msg_flow_removed *msg, Ptr< const RemoteSwitch > swtch, uint32_t xid) override
Handle flow removed messages sent from switch to this controller.
DatapathMap_t m_learnedInfo
Switching information for all dapataths.
OFSwitch13LearningController()
Default constructor.
void HandshakeSuccessful(Ptr< const RemoteSwitch > swtch) override
Function invoked after a successfully handshake procedure between this controller and a remote switch...
void DoDispose() override
Destructor implementation.
static TypeId GetTypeId()
Register this type.
std::map< Mac48Address, uint32_t > L2Table_t
L2SwitchingTable: map MacAddress to port.
~OFSwitch13LearningController() override
Dummy destructor.
TypeId SetParent(TypeId tid)
Set the parent TypeId.
Definition: type-id.cc:935
#define NS_ASSERT_MSG(condition, message)
At runtime, in debugging builds, if this condition is not true, the program prints the message to out...
Definition: assert.h:86
#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(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_OBJECT_ENSURE_REGISTERED(type)
Register an Object subclass with the TypeId system.
Definition: object-base.h:46
Every class exported by the ns3 library is enclosed in the ns3 namespace.
cmd
Definition: second.py:33