A Discrete-Event Network Simulator
API
openflow-switch-test-suite.cc
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2011 Blake Hurd
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
16  * 02111-1307 USA
17  *
18  * Author: Blake Hurd <naimorai@gmail.com>
19  */
20 
21 // An essential include is test.h
22 #include "ns3/openflow-interface.h"
23 #include "ns3/openflow-switch-net-device.h"
24 #include "ns3/test.h"
25 
26 // Do not put your test classes in namespace ns3. You may find it useful
27 // to use the using directive to access the ns3 namespace directly
28 using namespace ns3;
29 
36 {
37  public:
39  : TestCase("Switch test case")
40  {
41  m_chain = chain_create();
42  }
43 
45  {
46  chain_destroy(m_chain);
47  }
48 
49  private:
50  void DoRun() override;
51 
52  sw_chain* m_chain;
53 };
54 
55 void
57 {
58  // Flow Table implementation is used by the OpenFlowSwitchNetDevice under the chain_ methods
59  // we should test its implementation to verify the flow table works.
60 
61  // Initialization
62  time_init(); // OFSI requires this, otherwise we crash before we can do anything.
63 
64  size_t actions_len = 0; // Flow is created with 0 actions.
65  int output_port = 0; // Flow will be modified later with an action to output on port 0.
66 
67  Mac48Address dl_src("00:00:00:00:00:00");
68  Mac48Address dl_dst("00:00:00:00:00:01");
69  Ipv4Address nw_src("192.168.1.1");
70  Ipv4Address nw_dst("192.168.1.2");
71  int tp_src = 5000;
72  int tp_dst = 80;
73 
74  // Create an sw_flow_key; in actual usage this is generated from the received packet's headers.
75  sw_flow_key key;
76  key.wildcards = 0;
77 
78  key.flow.in_port = htons(0);
79 
80  key.flow.dl_vlan = htons(OFP_VLAN_NONE);
81  key.flow.dl_type = htons(ETH_TYPE_IP);
82  key.flow.nw_proto = htons(IP_TYPE_UDP);
83 
84  key.flow.reserved = 0;
85  key.flow.mpls_label1 = htonl(MPLS_INVALID_LABEL);
86  key.flow.mpls_label2 = htonl(MPLS_INVALID_LABEL);
87 
88  // Set Mac Addresses
89  dl_src.CopyTo(key.flow.dl_src);
90  dl_dst.CopyTo(key.flow.dl_dst);
91 
92  // Set IP Addresses
93  key.flow.nw_src = htonl(nw_src.Get());
94  key.flow.nw_dst = htonl(nw_dst.Get());
95 
96  // Set TCP/UDP Ports
97  key.flow.tp_src = htonl(tp_src);
98  key.flow.tp_dst = htonl(tp_dst);
99 
100  // Create flow
101  ofp_flow_mod ofm;
102  ofm.header.version = OFP_VERSION;
103  ofm.header.type = OFPT_FLOW_MOD;
104  ofm.header.length = htons(sizeof(ofp_flow_mod) + actions_len);
105  ofm.command = htons(OFPFC_ADD);
106  ofm.idle_timeout = htons(OFP_FLOW_PERMANENT);
107  ofm.hard_timeout = htons(OFP_FLOW_PERMANENT);
108  ofm.buffer_id = htonl(-1);
109  ofm.priority = OFP_DEFAULT_PRIORITY;
110 
111  ofm.match.wildcards = key.wildcards; // Wildcard fields
112  ofm.match.in_port = key.flow.in_port; // Input switch port
113  memcpy(ofm.match.dl_src, key.flow.dl_src, sizeof ofm.match.dl_src); // Ethernet source address.
114  memcpy(ofm.match.dl_dst,
115  key.flow.dl_dst,
116  sizeof ofm.match.dl_dst); // Ethernet destination address.
117  ofm.match.dl_vlan = key.flow.dl_vlan; // Input VLAN OFP_VLAN_NONE;
118  ofm.match.dl_type = key.flow.dl_type; // Ethernet frame type ETH_TYPE_IP;
119  ofm.match.nw_proto = key.flow.nw_proto; // IP Protocol
120  ofm.match.nw_src = key.flow.nw_src; // IP source address
121  ofm.match.nw_dst = key.flow.nw_dst; // IP destination address
122  ofm.match.tp_src = key.flow.tp_src; // TCP/UDP source port
123  ofm.match.tp_dst = key.flow.tp_dst; // TCP/UDP destination port
124  ofm.match.mpls_label1 = key.flow.mpls_label1; // Top of label stack
125  ofm.match.mpls_label2 = key.flow.mpls_label1; // Second label (if available)
126 
127  // Build a sw_flow from the ofp_flow_mod
128  sw_flow* flow = flow_alloc(actions_len);
129  NS_TEST_ASSERT_MSG_NE(flow, 0, "Cannot allocate memory for the flow.");
130 
131  flow_extract_match(&flow->key, &ofm.match);
132 
133  // Fill out flow.
134  flow->priority = flow->key.wildcards ? ntohs(ofm.priority) : -1;
135  flow->idle_timeout = ntohs(ofm.idle_timeout);
136  flow->hard_timeout = ntohs(ofm.hard_timeout);
137  flow->used = flow->created = time_now();
138  flow->sf_acts->actions_len = actions_len;
139  flow->byte_count = 0;
140  flow->packet_count = 0;
141  memcpy(flow->sf_acts->actions, ofm.actions, actions_len);
142 
143  // Insert the flow into the Flow Table
144  NS_TEST_ASSERT_MSG_EQ(chain_insert(m_chain, flow), 0, "Flow table failed to insert Flow.");
145 
146  // Use key to match the flow to verify we created it correctly.
147  NS_TEST_ASSERT_MSG_NE(chain_lookup(m_chain, &key),
148  0,
149  "Key provided doesn't match to the flow that was created from it.");
150 
151  // Modify key to make sure the flow doesn't match it.
152  dl_dst.CopyTo(key.flow.dl_src);
153  dl_src.CopyTo(key.flow.dl_dst);
154  key.flow.nw_src = htonl(nw_dst.Get());
155  key.flow.nw_dst = htonl(nw_src.Get());
156  key.flow.tp_src = htonl(tp_dst);
157  key.flow.tp_dst = htonl(tp_src);
158 
159  NS_TEST_ASSERT_MSG_EQ(chain_lookup(m_chain, &key),
160  0,
161  "Key provided shouldn't match the flow but it does.");
162 
163  // Modify key back to matching the flow so we can test flow modification.
164  dl_dst.CopyTo(key.flow.dl_dst);
165  dl_src.CopyTo(key.flow.dl_src);
166  key.flow.nw_src = htonl(nw_src.Get());
167  key.flow.nw_dst = htonl(nw_dst.Get());
168  key.flow.tp_src = htonl(tp_src);
169  key.flow.tp_dst = htonl(tp_dst);
170 
171  // Testing Flow Modification; chain_modify should return 1, for 1 flow modified.
172  // Create output-to-port action
173  ofp_action_output acts[1];
174  acts[0].type = htons(OFPAT_OUTPUT);
175  acts[0].len = htons(sizeof(ofp_action_output));
176  acts[0].port = output_port;
177 
178  uint16_t priority = key.wildcards ? ntohs(ofm.priority) : -1;
180  chain_modify(m_chain, &key, priority, false, (const ofp_action_header*)acts, sizeof(acts)),
181  1,
182  "Flow table failed to modify Flow.");
183 
184  // Testing Flow Deletion; chain_delete should return 1, for 1 flow deleted.
185  // Note: By providing chain_delete with output_port, the flow must have an action that outputs
186  // on that port in order to delete the flow. This is how we verify that our action was truly
187  // added via the flow modification.
188  NS_TEST_ASSERT_MSG_EQ(chain_delete(m_chain, &key, output_port, 0, 0),
189  1,
190  "Flow table failed to delete Flow.");
191  NS_TEST_ASSERT_MSG_EQ(chain_lookup(m_chain, &key),
192  0,
193  "Key provided shouldn't match the flow but it does.");
194 }
195 
202 {
203  public:
204  SwitchTestSuite();
205 };
206 
208  : TestSuite("openflow", UNIT)
209 {
210  AddTestCase(new SwitchFlowTableTestCase, TestCase::QUICK);
211 }
212 
sw_chain * m_chain
OpenFlow service function chain.
void DoRun() override
Implementation to actually run this TestCase.
Ipv4 addresses are stored in host order in this class.
Definition: ipv4-address.h:42
uint32_t Get() const
Get the host-order 32-bit IP address.
an EUI-48 address
Definition: mac48-address.h:46
void CopyTo(uint8_t buffer[6]) const
encapsulates test code
Definition: test.h:1060
void AddTestCase(TestCase *testCase, TestDuration duration=QUICK)
Add an individual child TestCase to this test suite.
Definition: test.cc:301
A suite of tests to run.
Definition: test.h:1256
#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:144
#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:564
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.