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
30using namespace ns3;
31
32
39{
40public:
41 SwitchFlowTableTestCase () : TestCase ("Switch test case")
42 {
43 m_chain = chain_create ();
44 }
45
47 {
48 chain_destroy (m_chain);
49 }
50
51private:
52 virtual void DoRun (void);
53
54 sw_chain* m_chain;
55};
56
57void
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{
188public:
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.