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 // This is an example TestCase.
34 {
35 public:
36  SwitchFlowTableTestCase () : TestCase ("Switch test case")
37  {
38  m_chain = chain_create ();
39  }
40 
42  {
43  chain_destroy (m_chain);
44  }
45 
46 private:
47  virtual void DoRun (void);
48 
49  sw_chain* m_chain;
50 };
51 
52 void
54 {
55  // Flow Table implementation is used by the OpenFlowSwitchNetDevice under the chain_ methods
56  // we should test its implementation to verify the flow table works.
57 
58  // Initialization
59  time_init (); // OFSI requires this, otherwise we crash before we can do anything.
60 
61  size_t actions_len = 0; // Flow is created with 0 actions.
62  int output_port = 0; // Flow will be modified later with an action to output on port 0.
63 
64  Mac48Address dl_src ("00:00:00:00:00:00"), dl_dst ("00:00:00:00:00:01");
65  Ipv4Address nw_src ("192.168.1.1"), nw_dst ("192.168.1.2");
66  int tp_src = 5000, tp_dst = 80;
67 
68  // Create an sw_flow_key; in actual usage this is generated from the received packet's headers.
69  sw_flow_key key;
70  key.wildcards = 0;
71 
72  key.flow.in_port = htons (0);
73 
74  key.flow.dl_vlan = htons (OFP_VLAN_NONE);
75  key.flow.dl_type = htons (ETH_TYPE_IP);
76  key.flow.nw_proto = htons (IP_TYPE_UDP);
77 
78  key.flow.reserved = 0;
79  key.flow.mpls_label1 = htonl (MPLS_INVALID_LABEL);
80  key.flow.mpls_label2 = htonl (MPLS_INVALID_LABEL);
81 
82  // Set Mac Addresses
83  dl_src.CopyTo (key.flow.dl_src);
84  dl_dst.CopyTo (key.flow.dl_dst);
85 
86  // Set IP Addresses
87  key.flow.nw_src = htonl (nw_src.Get ());
88  key.flow.nw_dst = htonl (nw_dst.Get ());
89 
90  // Set TCP/UDP Ports
91  key.flow.tp_src = htonl (tp_src);
92  key.flow.tp_dst = htonl (tp_dst);
93 
94  // Create flow
95  ofp_flow_mod ofm;
96  ofm.header.version = OFP_VERSION;
97  ofm.header.type = OFPT_FLOW_MOD;
98  ofm.header.length = htons (sizeof (ofp_flow_mod) + actions_len);
99  ofm.command = htons (OFPFC_ADD);
100  ofm.idle_timeout = htons (OFP_FLOW_PERMANENT);
101  ofm.hard_timeout = htons (OFP_FLOW_PERMANENT);
102  ofm.buffer_id = htonl (-1);
103  ofm.priority = OFP_DEFAULT_PRIORITY;
104 
105  ofm.match.wildcards = key.wildcards; // Wildcard fields
106  ofm.match.in_port = key.flow.in_port; // Input switch port
107  memcpy (ofm.match.dl_src, key.flow.dl_src, sizeof ofm.match.dl_src); // Ethernet source address.
108  memcpy (ofm.match.dl_dst, key.flow.dl_dst, sizeof ofm.match.dl_dst); // Ethernet destination address.
109  ofm.match.dl_vlan = key.flow.dl_vlan; // Input VLAN OFP_VLAN_NONE;
110  ofm.match.dl_type = key.flow.dl_type; // Ethernet frame type ETH_TYPE_IP;
111  ofm.match.nw_proto = key.flow.nw_proto; // IP Protocol
112  ofm.match.nw_src = key.flow.nw_src; // IP source address
113  ofm.match.nw_dst = key.flow.nw_dst; // IP destination address
114  ofm.match.tp_src = key.flow.tp_src; // TCP/UDP source port
115  ofm.match.tp_dst = key.flow.tp_dst; // TCP/UDP destination port
116  ofm.match.mpls_label1 = key.flow.mpls_label1; // Top of label stack
117  ofm.match.mpls_label2 = key.flow.mpls_label1; // Second label (if available)
118 
119  // Build a sw_flow from the ofp_flow_mod
120  sw_flow *flow = flow_alloc (actions_len);
121  NS_TEST_ASSERT_MSG_NE (flow, 0, "Cannot allocate memory for the flow.");
122 
123  flow_extract_match (&flow->key, &ofm.match);
124 
125  // Fill out flow.
126  flow->priority = flow->key.wildcards ? ntohs (ofm.priority) : -1;
127  flow->idle_timeout = ntohs (ofm.idle_timeout);
128  flow->hard_timeout = ntohs (ofm.hard_timeout);
129  flow->used = flow->created = time_now ();
130  flow->sf_acts->actions_len = actions_len;
131  flow->byte_count = 0;
132  flow->packet_count = 0;
133  memcpy (flow->sf_acts->actions, ofm.actions, actions_len);
134 
135  // Insert the flow into the Flow Table
136  NS_TEST_ASSERT_MSG_EQ (chain_insert (m_chain, flow), 0, "Flow table failed to insert Flow.");
137 
138  // Use key to match the flow to verify we created it correctly.
139  NS_TEST_ASSERT_MSG_NE (chain_lookup (m_chain, &key), 0, "Key provided doesn't match to the flow that was created from it.");
140 
141  // Modify key to make sure the flow doesn't match it.
142  dl_dst.CopyTo (key.flow.dl_src);
143  dl_src.CopyTo (key.flow.dl_dst);
144  key.flow.nw_src = htonl (nw_dst.Get ());
145  key.flow.nw_dst = htonl (nw_src.Get ());
146  key.flow.tp_src = htonl (tp_dst);
147  key.flow.tp_dst = htonl (tp_src);
148 
149  NS_TEST_ASSERT_MSG_EQ (chain_lookup (m_chain, &key), 0, "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;
167  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.");
168 
169  // Testing Flow Deletion; chain_delete should return 1, for 1 flow deleted.
170  // 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.
171  // This is how we verify that our action was truly added via the flow modification.
172  NS_TEST_ASSERT_MSG_EQ (chain_delete (m_chain, &key, output_port, 0, 0), 1, "Flow table failed to delete Flow.");
173  NS_TEST_ASSERT_MSG_EQ (chain_lookup (m_chain, &key), 0, "Key provided shouldn't match the flow but it does.");
174 }
175 
177 {
178 public:
179  SwitchTestSuite ();
180 };
181 
183 {
184  AddTestCase (new SwitchFlowTableTestCase, TestCase::QUICK);
185 }
186 
187 // Do not forget to allocate an instance of this TestSuite
189 
A suite of tests to run.
Definition: test.h:1342
encapsulates test code
Definition: test.h:1155
void CopyTo(uint8_t buffer[6]) const
void AddTestCase(TestCase *testCase, TestDuration duration=QUICK)
Add an individual child TestCase to this test suite.
Definition: test.cc:299
#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:168
static SwitchTestSuite switchTestSuite
virtual void DoRun(void)
Implementation to actually run this TestCase.
Every class exported by the ns3 library is enclosed in the ns3 namespace.
an EUI-48 address
Definition: mac48-address.h:43
Ipv4 addresses are stored in host order in this class.
Definition: ipv4-address.h:40
#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:624
uint32_t Get(void) const
Get the host-order 32-bit IP address.