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