A Discrete-Event Network Simulator
API
openflow-switch-test-suite.cc
Go to the documentation of this file.
1 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2 /*
3  * Copyright (c) 2011 Blake Hurd
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License version 2 as
7  * published by the Free Software Foundation;
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
17  * 02111-1307 USA
18  *
19  * Author: Blake Hurd <naimorai@gmail.com>
20  */
21 
22 // An essential include is test.h
23 #include "ns3/test.h"
24 
25 #include "ns3/openflow-switch-net-device.h"
26 #include "ns3/openflow-interface.h"
27 
28 // Do not put your test classes in namespace ns3. You may find it useful
29 // to use the using directive to access the ns3 namespace directly
30 using namespace ns3;
31 
32 
39 {
40 public:
41  SwitchFlowTableTestCase () : TestCase ("Switch test case")
42  {
43  m_chain = chain_create ();
44  }
45 
47  {
48  chain_destroy (m_chain);
49  }
50 
51 private:
52  virtual void DoRun (void);
53 
54  sw_chain* m_chain;
55 };
56 
57 void
59 {
60  // Flow Table implementation is used by the OpenFlowSwitchNetDevice under the chain_ methods
61  // we should test its implementation to verify the flow table works.
62 
63  // Initialization
64  time_init (); // OFSI requires this, otherwise we crash before we can do anything.
65 
66  size_t actions_len = 0; // Flow is created with 0 actions.
67  int output_port = 0; // Flow will be modified later with an action to output on port 0.
68 
69  Mac48Address dl_src ("00:00:00:00:00:00"), dl_dst ("00:00:00:00:00:01");
70  Ipv4Address nw_src ("192.168.1.1"), nw_dst ("192.168.1.2");
71  int tp_src = 5000, tp_dst = 80;
72 
73  // Create an sw_flow_key; in actual usage this is generated from the received packet's headers.
74  sw_flow_key key;
75  key.wildcards = 0;
76 
77  key.flow.in_port = htons (0);
78 
79  key.flow.dl_vlan = htons (OFP_VLAN_NONE);
80  key.flow.dl_type = htons (ETH_TYPE_IP);
81  key.flow.nw_proto = htons (IP_TYPE_UDP);
82 
83  key.flow.reserved = 0;
84  key.flow.mpls_label1 = htonl (MPLS_INVALID_LABEL);
85  key.flow.mpls_label2 = htonl (MPLS_INVALID_LABEL);
86 
87  // Set Mac Addresses
88  dl_src.CopyTo (key.flow.dl_src);
89  dl_dst.CopyTo (key.flow.dl_dst);
90 
91  // Set IP Addresses
92  key.flow.nw_src = htonl (nw_src.Get ());
93  key.flow.nw_dst = htonl (nw_dst.Get ());
94 
95  // Set TCP/UDP Ports
96  key.flow.tp_src = htonl (tp_src);
97  key.flow.tp_dst = htonl (tp_dst);
98 
99  // Create flow
100  ofp_flow_mod ofm;
101  ofm.header.version = OFP_VERSION;
102  ofm.header.type = OFPT_FLOW_MOD;
103  ofm.header.length = htons (sizeof (ofp_flow_mod) + actions_len);
104  ofm.command = htons (OFPFC_ADD);
105  ofm.idle_timeout = htons (OFP_FLOW_PERMANENT);
106  ofm.hard_timeout = htons (OFP_FLOW_PERMANENT);
107  ofm.buffer_id = htonl (-1);
108  ofm.priority = OFP_DEFAULT_PRIORITY;
109 
110  ofm.match.wildcards = key.wildcards; // Wildcard fields
111  ofm.match.in_port = key.flow.in_port; // Input switch port
112  memcpy (ofm.match.dl_src, key.flow.dl_src, sizeof ofm.match.dl_src); // Ethernet source address.
113  memcpy (ofm.match.dl_dst, key.flow.dl_dst, sizeof ofm.match.dl_dst); // Ethernet destination address.
114  ofm.match.dl_vlan = key.flow.dl_vlan; // Input VLAN OFP_VLAN_NONE;
115  ofm.match.dl_type = key.flow.dl_type; // Ethernet frame type ETH_TYPE_IP;
116  ofm.match.nw_proto = key.flow.nw_proto; // IP Protocol
117  ofm.match.nw_src = key.flow.nw_src; // IP source address
118  ofm.match.nw_dst = key.flow.nw_dst; // IP destination address
119  ofm.match.tp_src = key.flow.tp_src; // TCP/UDP source port
120  ofm.match.tp_dst = key.flow.tp_dst; // TCP/UDP destination port
121  ofm.match.mpls_label1 = key.flow.mpls_label1; // Top of label stack
122  ofm.match.mpls_label2 = key.flow.mpls_label1; // Second label (if available)
123 
124  // Build a sw_flow from the ofp_flow_mod
125  sw_flow *flow = flow_alloc (actions_len);
126  NS_TEST_ASSERT_MSG_NE (flow, 0, "Cannot allocate memory for the flow.");
127 
128  flow_extract_match (&flow->key, &ofm.match);
129 
130  // Fill out flow.
131  flow->priority = flow->key.wildcards ? ntohs (ofm.priority) : -1;
132  flow->idle_timeout = ntohs (ofm.idle_timeout);
133  flow->hard_timeout = ntohs (ofm.hard_timeout);
134  flow->used = flow->created = time_now ();
135  flow->sf_acts->actions_len = actions_len;
136  flow->byte_count = 0;
137  flow->packet_count = 0;
138  memcpy (flow->sf_acts->actions, ofm.actions, actions_len);
139 
140  // Insert the flow into the Flow Table
141  NS_TEST_ASSERT_MSG_EQ (chain_insert (m_chain, flow), 0, "Flow table failed to insert Flow.");
142 
143  // Use key to match the flow to verify we created it correctly.
144  NS_TEST_ASSERT_MSG_NE (chain_lookup (m_chain, &key), 0, "Key provided doesn't match to the flow that was created from it.");
145 
146  // Modify key to make sure the flow doesn't match it.
147  dl_dst.CopyTo (key.flow.dl_src);
148  dl_src.CopyTo (key.flow.dl_dst);
149  key.flow.nw_src = htonl (nw_dst.Get ());
150  key.flow.nw_dst = htonl (nw_src.Get ());
151  key.flow.tp_src = htonl (tp_dst);
152  key.flow.tp_dst = htonl (tp_src);
153 
154  NS_TEST_ASSERT_MSG_EQ (chain_lookup (m_chain, &key), 0, "Key provided shouldn't match the flow but it does.");
155 
156  // Modify key back to matching the flow so we can test flow modification.
157  dl_dst.CopyTo (key.flow.dl_dst);
158  dl_src.CopyTo (key.flow.dl_src);
159  key.flow.nw_src = htonl (nw_src.Get ());
160  key.flow.nw_dst = htonl (nw_dst.Get ());
161  key.flow.tp_src = htonl (tp_src);
162  key.flow.tp_dst = htonl (tp_dst);
163 
164  // Testing Flow Modification; chain_modify should return 1, for 1 flow modified.
165  // Create output-to-port action
166  ofp_action_output acts[1];
167  acts[0].type = htons (OFPAT_OUTPUT);
168  acts[0].len = htons (sizeof (ofp_action_output));
169  acts[0].port = output_port;
170 
171  uint16_t priority = key.wildcards ? ntohs (ofm.priority) : -1;
172  NS_TEST_ASSERT_MSG_EQ (chain_modify (m_chain, &key, priority, false, (const ofp_action_header*)acts, sizeof (acts)), 1, "Flow table failed to modify Flow.");
173 
174  // Testing Flow Deletion; chain_delete should return 1, for 1 flow deleted.
175  // Note: By providing chain_delete with output_port, the flow must have an action that outputs on that port in order to delete the flow.
176  // This is how we verify that our action was truly added via the flow modification.
177  NS_TEST_ASSERT_MSG_EQ (chain_delete (m_chain, &key, output_port, 0, 0), 1, "Flow table failed to delete Flow.");
178  NS_TEST_ASSERT_MSG_EQ (chain_lookup (m_chain, &key), 0, "Key provided shouldn't match the flow but it does.");
179 }
180 
187 {
188 public:
189  SwitchTestSuite ();
190 };
191 
193 {
194  AddTestCase (new SwitchFlowTableTestCase, TestCase::QUICK);
195 }
196 
199 
virtual void DoRun(void)
Implementation to actually run this TestCase.
sw_chain * m_chain
OpenFlow service function chain.
Ipv4 addresses are stored in host order in this class.
Definition: ipv4-address.h:41
uint32_t Get(void) const
Get the host-order 32-bit IP address.
an EUI-48 address
Definition: mac48-address.h:44
void CopyTo(uint8_t buffer[6]) const
encapsulates test code
Definition: test.h:994
void AddTestCase(TestCase *testCase, TestDuration duration=QUICK)
Add an individual child TestCase to this test suite.
Definition: test.cc:299
A suite of tests to run.
Definition: test.h:1188
#define NS_TEST_ASSERT_MSG_EQ(actual, limit, msg)
Test that an actual and expected (limit) value are equal and report and abort if not.
Definition: test.h:141
#define NS_TEST_ASSERT_MSG_NE(actual, limit, msg)
Test that an actual and expected (limit) value are not equal and report and abort if not.
Definition: test.h:542
Every class exported by the ns3 library is enclosed in the ns3 namespace.
static SwitchTestSuite switchTestSuite
Do not forget to allocate an instance of this TestSuite.