A Discrete-Event Network Simulator
API
Loading...
Searching...
No Matches
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
28using 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
55void
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:
205};
206
208 : TestSuite("openflow", Type::UNIT)
209{
210 AddTestCase(new SwitchFlowTableTestCase, TestCase::Duration::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:1061
void AddTestCase(TestCase *testCase, Duration duration=Duration::QUICK)
Add an individual child TestCase to this test suite.
Definition: test.cc:301
A suite of tests to run.
Definition: test.h:1268
Type
Type of test.
Definition: test.h:1275
#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:145
#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:565
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.