Commit baba3f1eded447bc43610358e56c5aba0eb17669
1 parent
29763531
regress, secchan, testes, third-party, utilities
Showing
531 changed files
with
67615 additions
and
0 deletions
Too many changes to show.
To preserve performance only 43 of 531 files are displayed.
regress/CREDITS
0 → 100755
| 1 | +Credit goes to those who contributed code to the regression suite. Unless | |
| 2 | +otherwise noted, the contributors are at Stanford University. | |
| 3 | + | |
| 4 | + | |
| 5 | +Test writers/editors: | |
| 6 | + Clay Collier | |
| 7 | + David Erickson | |
| 8 | + Mikio Hara (NEC) | |
| 9 | + Brandon Heller | |
| 10 | + Peyman Kazemian | |
| 11 | + Masayoshi Kobayashi (NEC) | |
| 12 | + Bob Lantz | |
| 13 | + Brandon Nefcy | |
| 14 | + Rob Sherwood (Deutsche Telekom R&D Labs) | |
| 15 | + Jean Tourrilhes (HP Labs) | |
| 16 | + Tatsuya Yabe (NEC) | |
| 17 | + Yiannis Yiakoumis | |
| 18 | + | |
| 19 | +Supporting libraries: | |
| 20 | + Adam Covington | |
| 21 | + Glen Gibb | |
| 22 | + Jad Naous | ... | ... |
regress/INSTALL
0 → 100755
| 1 | + Installation Instructions for OpenFlow Reference Tests | |
| 2 | + | |
| 3 | +This document describes how to install and execute the OpenFlow reference test | |
| 4 | +suite, which provides an automated way to verify that an OpenFlow switch | |
| 5 | +adheres to the OpenFlow Protocol. Out of the box, tests work with the OpenFlow | |
| 6 | +Reference Linux Switch, but can support other platforms by defining custom | |
| 7 | +setup and teardown scripts. Additional tests verify the reference learning | |
| 8 | +Ethernet switch controller included with the OpenFlow Reference Linux Switch. | |
| 9 | + | |
| 10 | +Please send any comments to: | |
| 11 | + | |
| 12 | + <openflow-discuss@openflowswitch.org> | |
| 13 | + | |
| 14 | +=== Prerequisites === | |
| 15 | + | |
| 16 | +The tests require no other packets to be sent on the testing interfaces. | |
| 17 | +Built-in programs like avahi-daemon and/or network-manager may send packets, | |
| 18 | +causing the tests to report failure. The simplest way to remove these packets | |
| 19 | +is to disable the ipv6 module and reboot, as well as remove avahi-daemon. | |
| 20 | + | |
| 21 | +All test configurations require the following Perl modules: | |
| 22 | + perl-Convert-Binary-C | |
| 23 | + perl-Data-HexDump | |
| 24 | + perl-Net-Pcap (perl-Net-Pcap-0.16-1) | |
| 25 | + perl-Net-RawIP.i386 (perl-Net-RawIP-0.23-1) | |
| 26 | + perl-Error.noarch (perl-Error-0.17012-1) | |
| 27 | + | |
| 28 | +These packages can be installed from source via www.cpan.org, or you can use | |
| 29 | +pre-built packages (much faster!). | |
| 30 | + | |
| 31 | +The code has been tested on CentOS 5.1/5.2, Ubuntu Hardy Heron, and Debian | |
| 32 | +Unstable under the following configurations. | |
| 33 | + | |
| 34 | +** Config 1 - Four virtual Ethernet loopback pairs | |
| 35 | + | |
| 36 | +To set these up, you must have a kernel version >= 2.6.24 and the veth kernel | |
| 37 | +module compiled. | |
| 38 | + | |
| 39 | +To set up link pairs, you must also have iproute installed. | |
| 40 | + | |
| 41 | +Scripts to simplify this are included in bin/: | |
| 42 | +-bin/veth_setup.pl | |
| 43 | +-bin/veth_teardown.pl | |
| 44 | + | |
| 45 | +Before running any veth tests, make sure to run bin/veth_setup.pl, which will | |
| 46 | +create interfaces veth{0..7}. The usual ports of eth{1..8} are remapped to these | |
| 47 | +ports via the file veth.map in /bin/. To remove these interfaces, run | |
| 48 | +bin/veth_teardown.pl | |
| 49 | + | |
| 50 | +** Config 2 - Two quad-port Ethernet NICs connected by physical loopback cables | |
| 51 | + | |
| 52 | +Assign ports as eth{1..8} and connect cables as: | |
| 53 | + eth1 to eth5 | |
| 54 | + eth2 to eth6 | |
| 55 | + eth3 to eth7 | |
| 56 | + eth4 to eth8 | |
| 57 | + | |
| 58 | +** Config 3 - Four local ethernet ports connected to external switch | |
| 59 | + | |
| 60 | +A third configuration is to use four ports of Ethernet on the test machine, | |
| 61 | +connected to an external switch. To do this, you must provide custom setup | |
| 62 | +and teardown scripts that enable/disable OpenFlow on the external switch via | |
| 63 | +SSH, telnet, or SNMP. See the scripts in bin/ for examples of how to create | |
| 64 | +these. | |
| 65 | + | |
| 66 | +** Config 4 - One quad-port Ethernet NIC connected to a NetFPGA | |
| 67 | + | |
| 68 | +This testing configuration is used to verify the NetFPGA's OpenFlow | |
| 69 | +functionality. It requires 4 ports of Ethernet connected to corresponding ports | |
| 70 | +on the NetFPGA in the following arrangement: | |
| 71 | + eth1 to nf2c0 | |
| 72 | + eth2 to nf2c1 | |
| 73 | + eth3 to nf2c2 | |
| 74 | + eth4 to nf2c3 | |
| 75 | + | |
| 76 | +This test also assumes that you have correctly installed the NetFPGA ahead of | |
| 77 | +time. For further information about the NetFPGA please see | |
| 78 | +http://www.netfpga.org/ | |
| 79 | + | |
| 80 | +Of particular note, by default installing the NetFPGA also puts the | |
| 81 | +NF2/lib/Perl5 directory into your PERL5LIB environment variable, this must be | |
| 82 | +removed else the tests will fail. Ensure that your PERL5LIB only contains the | |
| 83 | +path set by the env_vars file that will be discussed later in this document. | |
| 84 | + | |
| 85 | + | |
| 86 | +=== Ubuntu Quickstart === | |
| 87 | + | |
| 88 | +Follow these instructions to quickly create a VM or physical machine with | |
| 89 | +OpenFlow that runs the tests. | |
| 90 | + | |
| 91 | +Ubuntu is recommended because it is based on Debian sources and has a recent | |
| 92 | +kernel version - which removes the need for some steps. | |
| 93 | + | |
| 94 | +If installing as a VM, you'll need to install VMWare Server (Windows/Linux, | |
| 95 | +free) or VMWare Fusion (Mac, $$$). | |
| 96 | + | |
| 97 | +Download the Ubuntu 8.04 Desktop or Server ISO, and install Ubuntu. | |
| 98 | + | |
| 99 | +If you prefer, install VMWare Tools to enable better mouse and display support. | |
| 100 | +Alternately, install SSH and use it for the rest of the instructions: | |
| 101 | + sudo apt-get install ssh | |
| 102 | +Install GCC, which is required for OpenFlow: | |
| 103 | + sudo apt-get install gcc | |
| 104 | +Download and untar OpenFlow v0.8.1 | |
| 105 | + wget http://openflowswitch.org/downloads/openflow-v0.8.1.tar.gz | |
| 106 | + tar xzf openflow-v0.8.1.tar.gz | |
| 107 | +Build OpenFlow user-space and kernel-space switches: | |
| 108 | + cd openflow-v0.8.1 | |
| 109 | + ./configure --with-l26=/lib/modules/`uname -r` | |
| 110 | + make | |
| 111 | + sudo make install | |
| 112 | +Now, download and untar the OpenFlow Test Suite: | |
| 113 | + wget http://openflowswitch.org/downloads/openflow-test-v0.8.1-r2.tar.gz | |
| 114 | +Install required packages for the test suite: | |
| 115 | + sudo apt-get install liberror-perl libio-interface-perl liblist-moreutils-perl libpcap0.8-dev | |
| 116 | +Download the following: | |
| 117 | + wget http://search.cpan.org/CPAN/authors/id/S/SA/SAPER/Net-Pcap-0.14.tar.gz | |
| 118 | + wget http://search.cpan.org/CPAN/authors/id/S/SZ/SZABGAB/Net-RawIP-0.21.tar.gz | |
| 119 | + wget http://search.cpan.org/CPAN/authors/id/M/MH/MHX/Convert-Binary-C-0.71.tar.gz | |
| 120 | + wget http://search.cpan.org/CPAN/authors/id/F/FT/FTASSIN/Data-HexDump-0.02.tar.gz | |
| 121 | +For each package: | |
| 122 | + tar xzf <package.tar.gz> | |
| 123 | + cd <package> | |
| 124 | + perl Makefile.PL | |
| 125 | + make | |
| 126 | + make install | |
| 127 | +Remove avahi-daemon, which often causes tests to fail by sending out messages: | |
| 128 | + sudo apt-get remove avahi-daemon | |
| 129 | +Create a root password, to be used later: | |
| 130 | + sudo passwd root | |
| 131 | + | |
| 132 | +From here, skip to the Running The Tests section below. | |
| 133 | + | |
| 134 | + | |
| 135 | +=== CentOS 5.2 === | |
| 136 | + | |
| 137 | +First, download and verify you can build the current version of OpenFlow. | |
| 138 | + | |
| 139 | +Install the RPMForge repository: | |
| 140 | + wget http://dag.wieers.com/rpm/packages/rpmforge-release/rpmforge-release-0.3.6-1.el5.rf.i386.rpm | |
| 141 | + rpm -Uhv rpmforge-release-0.3.6-1.el5.rf.i386.rpm | |
| 142 | + | |
| 143 | +Install Perl packages: | |
| 144 | + yum -y install perl-Convert-Binary-C perl-Data-HexDump perl-Net-Pcap perl-Net-RawIP.i386 perl-Error.noarch | |
| 145 | + | |
| 146 | +To run tests with Veth pairs, you'll need to upgrade to a newer version of the kernel. | |
| 147 | + | |
| 148 | +Install iproute: | |
| 149 | + yum -y install iproute | |
| 150 | + | |
| 151 | +From here, skip to the Running The Tests section below. | |
| 152 | + | |
| 153 | +=== Debian Install === | |
| 154 | + | |
| 155 | +These instructions derive from http://netfpga.org/netfpgawiki/index.php/Ubuntu_Compatibility | |
| 156 | + | |
| 157 | +Some instructions may no longer be necessary. | |
| 158 | + | |
| 159 | +*The version of libnet-pcap-perl that Debian and Ubuntu 6.06/7.04/7.10 provides is ANCIENT (version 0.04). The latest stable version is 0.14. No newer version is available as a package, so we must build it ourselves. | |
| 160 | +*The version of libpcap that Debian and Ubuntu 7.04 provides by default is old (version 0.72). The latest stable version is 0.9.8. Fortunately, the package manager has a newer version called "libpcap0.8" that is really version 0.9.5 | |
| 161 | +*Remove old packages / install new ones | |
| 162 | + | |
| 163 | +May not be necessary: | |
| 164 | + apt-get remove libpcap0.7 libpcap0.7-dev libpcap-dev libnet-pcap-perl | |
| 165 | + | |
| 166 | +Will be necessary: | |
| 167 | + apt-get install liberror-perl libio-interface-perl liblist-moreutils-perl libpcap0.8 libpcap0.8-dev psmisc | |
| 168 | +Listed individually: | |
| 169 | + apt-get install liberror-perl | |
| 170 | + apt-get install libio-interface-perl (Used to manually build a newer version of Net::PCap) | |
| 171 | + apt-get install liblist-moreutils-perl (Used to manually build a newer version of Net::RawIP) | |
| 172 | + apt-get install libpcap0.8 | |
| 173 | + apt-get install libpcap0.8-dev | |
| 174 | + apt-get install psmisc (Used to get killall) | |
| 175 | + | |
| 176 | +Required packages have Debian versions at packages.debian.org, however these packages may not be the newest, or not exist at all. libnet-rawip-perl and libnet-pacp-perl may work, but have not been tested. We'll manually install these two packages: | |
| 177 | +http://search.cpan.org/~saper/Net-Pcap-0.14/Pcap.pm | |
| 178 | +http://search.cpan.org/~szabgab/Net-RawIP-0.21/lib/Net/RawIP.pm | |
| 179 | +http://search.cpan.org/dist/Convert-Binary-C/lib/Convert/Binary/C.pm | |
| 180 | +http://search.cpan.org/dist/Data-HexDump/lib/Data/HexDump.pm | |
| 181 | + | |
| 182 | +Download the following: | |
| 183 | + wget http://search.cpan.org/CPAN/authors/id/S/SA/SAPER/Net-Pcap-0.14.tar.gz | |
| 184 | + wget http://search.cpan.org/CPAN/authors/id/S/SZ/SZABGAB/Net-RawIP-0.21.tar.gz | |
| 185 | + wget http://search.cpan.org/CPAN/authors/id/M/MH/MHX/Convert-Binary-C-0.71.tar.gz | |
| 186 | + wget http://search.cpan.org/CPAN/authors/id/F/FT/FTASSIN/Data-HexDump-0.02.tar.gz | |
| 187 | +For each package: | |
| 188 | + tar xzf <package.tar.gz> | |
| 189 | + cd <package> | |
| 190 | + perl Makefile.PL | |
| 191 | + make | |
| 192 | + make install | |
| 193 | + | |
| 194 | +Install if you want to use veth pairs: | |
| 195 | + apt-get install iproute | |
| 196 | + | |
| 197 | +=== Running the Tests === | |
| 198 | + | |
| 199 | +In the sections below, {platform} refers to: | |
| 200 | +user | |
| 201 | +user_veth | |
| 202 | +kmod | |
| 203 | +kmod_veth | |
| 204 | +nf2 | |
| 205 | + | |
| 206 | +First copy the env_vars file to your home directory: | |
| 207 | + cd ~/ | |
| 208 | + cp <openflow_dir>/regress/scripts/env_vars . | |
| 209 | + | |
| 210 | +Update the OF_ROOT (openflow) environment variable to point to your OpenFlow | |
| 211 | +directory in your setup. These exports can also be added to your ~/.bashrc | |
| 212 | +file to load automatically: | |
| 213 | + vim env_vars | |
| 214 | + | |
| 215 | +Enter a root shell session, or set up sudo. The perl-Net-RawIP library requires | |
| 216 | +root access to bind to ports. | |
| 217 | + su | |
| 218 | + | |
| 219 | +Source the environment variables: | |
| 220 | + source env_vars | |
| 221 | + | |
| 222 | +For a setup with virtual ethernet pairs, set them up: | |
| 223 | + veth_setup.pl | |
| 224 | + | |
| 225 | +Verify your setup by running regression tests on your platform of choice: | |
| 226 | + of_{platform}_test.pl | |
| 227 | +For the user-space switch, the tests should show pass for all scripts except | |
| 228 | +the _X_controller ones. For the kernel-space switch, all tests should pass. | |
| 229 | + | |
| 230 | +To see more options for the regression script, type: | |
| 231 | + of_{platform}_test.pl --help | |
| 232 | + | |
| 233 | +== Writing Your Own Tests == | |
| 234 | + | |
| 235 | +Look at an example controller test: | |
| 236 | + vim <openflow_dir>/regress/projects/learning_switch/regress/test_unicast_unknown/run.pl | |
| 237 | + | |
| 238 | +Look at an example black box switch test: | |
| 239 | + vim <openflow_dir>/regress/projects/black_box/regress/test_hello/run.pl | |
| 240 | + | |
| 241 | +To run an individual test (learning switch example): | |
| 242 | + cd <openflow_dir>/regres/projects/learning_switch/regress/test_unicast_unknown | |
| 243 | + of_{platform}_setup.pl; ./run.pl; of_{platform}_teardown.pl | |
| 244 | + | |
| 245 | +To see traffic when running a black box test, use tcpdump. Secchan and the | |
| 246 | +Perl code use the loopback interface to communicate, and you can snoop on this: | |
| 247 | + tcpdump -X -i lo -s 256 | |
| 248 | + | |
| 249 | +It can be convenient to run your test in isolation, without setup and teardown | |
| 250 | +automatically called. To set up the OF kmod and interfaces, run: | |
| 251 | + of_{platform}_setup.pl | |
| 252 | + | |
| 253 | +To remove the OF kmod cleanly, run: | |
| 254 | + of_{platform}_teardown.pl | |
| 255 | +Note that the kmod refuses removal until the interfaces and datapaths have been removed. | |
| 256 | + | |
| 257 | +== Reporting Bugs == | |
| 258 | + | |
| 259 | +Please report problems to: | |
| 260 | +openflow-discuss@openflowswitch.org | |
| 261 | + | |
| 262 | +or post them directly to our bug tracking system: | |
| 263 | + | |
| 264 | +http://www.openflowswitch.org/bugs/openflow | ... | ... |
regress/LICENSE
0 → 100755
| 1 | +Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior | |
| 2 | +University | |
| 3 | + | |
| 4 | + | |
| 5 | +We are making the OpenFlow tests and associated documentation (Software) | |
| 6 | +available for public use and benefit with the expectation that others will | |
| 7 | +use, modify and enhance the Software and contribute those enhancements back | |
| 8 | +to the community. However, since we would like to make the Software | |
| 9 | +available for broadest use, with as few restrictions as possible permission | |
| 10 | +is hereby granted, free of charge, to any person obtaining a copy of this | |
| 11 | +Software) to deal in the Software under the copyrights without restriction, | |
| 12 | +including without limitation the rights to use, copy, modify, merge, | |
| 13 | +publish, distribute, sublicense, and/or sell copies of the Software, and to | |
| 14 | +permit persons to whom the Software is furnished to do so, subject to the | |
| 15 | +following conditions: | |
| 16 | + | |
| 17 | +The above copyright notice and this permission notice shall be included in | |
| 18 | +all copies or substantial portions of the Software. | |
| 19 | + | |
| 20 | +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
| 21 | +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
| 22 | +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
| 23 | +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
| 24 | +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | |
| 25 | +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | |
| 26 | +DEALINGS IN THE SOFTWARE. | |
| 27 | + | |
| 28 | +The name and trademarks of copyright holder(s) may NOT be used in | |
| 29 | +advertising or publicity pertaining to the Software or any derivatives | |
| 30 | +without specific, written prior permission. | ... | ... |
regress/README
0 → 100755
| 1 | + OpenFlow Reference Tests <http://openflowswitch.org> | |
| 2 | + | |
| 3 | +What's here? | |
| 4 | +------------ | |
| 5 | + | |
| 6 | +This distribution includes: | |
| 7 | + | |
| 8 | + - 55+ "black box" tests to verify that an OF switch conforms to the | |
| 9 | + OF protocol 0x01 | |
| 10 | + | |
| 11 | + - 7 tests to verify that the reference controller acts as a learning | |
| 12 | + Ethernet switch | |
| 13 | + | |
| 14 | +The tests are intended to simplify the process of creating an OF switch | |
| 15 | +that conforms to spec. | |
| 16 | + | |
| 17 | +Please see INSTALL for instruction on installing and running the tests. | |
| 18 | + | |
| 19 | +Changelog | |
| 20 | +--------------- | |
| 21 | +1.0.0-r1 | |
| 22 | + - Added Open vSwitch scripts : kernel + user + interface maps | |
| 23 | + - Added VETH scripts for Open vSwitch : kernel + user | |
| 24 | + - Updated HP-ProCurve scipts : 5400/3500 and 6600 | |
| 25 | + - Assorted fixes to libraries : | |
| 26 | + accept port > 10 | |
| 27 | + accept vlan interfaces | |
| 28 | + more explicit error messages | |
| 29 | + - Assorted fixes to tests : | |
| 30 | + test_switch_config/ -> add delay | |
| 31 | + test_forward_broadcast_exact_port/ -> run for allports | |
| 32 | + test_set_n_match_nw_tos/ -> fixup nw_tos usage | |
| 33 | + test_set_nw_dst/ -> cleanup | |
| 34 | + test_failover_startup/ -> argv parsing was broken | |
| 35 | + - Add new test : test_set_dl_nw_flip -> flip dl & nw addresses | |
| 36 | + - Add new command line options : no_vlan, no_slicing and no_barrier, | |
| 37 | + no_emerg | |
| 38 | + - Add ability to run a single test with --testPath | |
| 39 | + - New debugging function : dpctl_show_flows | |
| 40 | + | |
| 41 | +1.0.0 | |
| 42 | + - all tests updated to OpenFlow wire protocol 0x01 | |
| 43 | + - added tests for new features in the OpenFlow 1.0.0 spec | |
| 44 | + | |
| 45 | +0.9.0 | |
| 46 | + - all tests updated to OpenFlow wire protocol 0x98 | |
| 47 | + | |
| 48 | +v0.8.2 | |
| 49 | + - Added support for the NetFPGA | |
| 50 | + - Integrated the tests into the OpenFlow directory structure | |
| 51 | + | |
| 52 | +v0.8.1-r2 | |
| 53 | + - refactored code to make new test ports easier | |
| 54 | + - fixed documentation bug in test_LLC | |
| 55 | + - changed all interfaces IPs to 192.168.20X.X to not conflict with the | |
| 56 | + IP addrs typically assigned via DHCP by home routers | |
| 57 | + - added easy support for testing user-space switch with physical ports | |
| 58 | + - added easy support for user-space switch with virtual ports | |
| 59 | + | |
| 60 | +v0.8.1-r1 | |
| 61 | + - added instructions for Debian install | |
| 62 | + - fixed timing bug in packet_out | |
| 63 | + | |
| 64 | +v0.8.1-r0 | |
| 65 | + - all tests updated to OF spec v0.8.1 | |
| 66 | + - added black box test switch_config | |
| 67 | + - fixed timing dependence in learning switch tests | |
| 68 | + | |
| 69 | +v0.2.1 | |
| 70 | + - initial release for OF spec v0.5.1, code tested for ref OF code v0.2.1 | |
| 71 | + | |
| 72 | +Platform support | |
| 73 | +---------------- | |
| 74 | + | |
| 75 | +The code is written in Perl5, and should in theory work on any system. | |
| 76 | +It has been tested with CentOS 5.4, Ubuntu 9.10, Fedora Core 12, and Debian Unstable. | |
| 77 | + | |
| 78 | +Learning Switch Tests | |
| 79 | +---------------- | |
| 80 | + | |
| 81 | +Two tests currently fail with OF Reference v0.8.1: | |
| 82 | + | |
| 83 | +-Unicast, send to self: the switch is forwarding packets with source and destination on the same port to that port instead of dropping it. | |
| 84 | + | |
| 85 | +-Unicast, hub connected:the switch is forwarding traffic to the same port it has came out of, although the source and destination are on the same port and switch already knows about that. | |
| 86 | + | |
| 87 | +Both failing tests can be re-activated by changing | |
| 88 | +projects/learning_switch/regress/tests.txt | |
| 89 | + | |
| 90 | +=== Unicast, unknown dest === | |
| 91 | +:; Name: test_unicast_unknown | |
| 92 | +:; Owner: Peyman | |
| 93 | +:; Description | |
| 94 | +::send packet out p0 to unknown MAC addr | |
| 95 | +::verify unmodified packet received at p1..p3 | |
| 96 | +::verify counters incremented | |
| 97 | + | |
| 98 | +=== Unicast, known dest === | |
| 99 | +:; Name: test_unicast_known | |
| 100 | +:; Owner: Peyman | |
| 101 | +:; Description: Send to known unicast address, verify switch sent to only one port | |
| 102 | +::send out p0 to p1 | |
| 103 | +::verify received at p1..p3 | |
| 104 | +::send out p1 to p0 | |
| 105 | +::verify received at p0, NOT p2, p3 | |
| 106 | +::send out p2 to p0 | |
| 107 | +::verify received at p0, NOT p1, p3 | |
| 108 | +::send out p3 to p0 | |
| 109 | +::verify received at p0, NOT p1, p2 | |
| 110 | +::verify counters | |
| 111 | + | |
| 112 | +=== Broadcast === | |
| 113 | +:; Name: test_broadcast | |
| 114 | +:; Owner: Peyman | |
| 115 | +:; Description: Send to broadcast address, verify received on all ports | |
| 116 | +::send out p0 to all | |
| 117 | +::verify received at p1..p3 | |
| 118 | +::send out p0 to all, again | |
| 119 | +::verify received at p1..p3, again | |
| 120 | +::repeat for each port | |
| 121 | +::verify counters | |
| 122 | + | |
| 123 | +=== Unicast, send to self === | |
| 124 | +:; Name: test_unicast_self | |
| 125 | +:; Owner: Peyman | |
| 126 | +:; Description: Send to self, verify dropped | |
| 127 | + | |
| 128 | +=== Unicast, change attachment point === | |
| 129 | +:; Name: test_unicast_move | |
| 130 | +:; Owner: Peyman | |
| 131 | +:; Description: Send normal unicast, but then change attachment point (one MAC sent from multiple ports), verify that new location is used | |
| 132 | +::send form host A at p0 to p1 | |
| 133 | +::verify received at p1..p3 | |
| 134 | +::send from p1 to host A | |
| 135 | +::verify received at p0, NOT p1, p2, p3 | |
| 136 | +::(original p0 has now moves to p2) | |
| 137 | +::send from host A (currently at p2) to p1 | |
| 138 | +::verify received at p1, NOT p0, p2, p3 | |
| 139 | +::send from p1 to Host A (currently at p2) | |
| 140 | +::verify received p2, NOT p0, p1, p3 | |
| 141 | + | |
| 142 | +=== Unicast, hub connected === | |
| 143 | +:; Name: test_hub_connected | |
| 144 | +:; Owner: Peyman | |
| 145 | +:; Description: if a port connects to a hub, we may receive traffic for which the sender and receiver are connected to the same port. This traffic should be dropped. | |
| 146 | + | |
| 147 | +=== Unicast, multiple hosts per port === | |
| 148 | +:; Name: test_unicast_multiple_hosts | |
| 149 | +:; Owner: Peyman | |
| 150 | +:; Description: assume each port is connected to a switch, so that each port receives traffic from multiple MAC addresses - say, 20 per port. Other than multiple MAC addrs per port, this is just like test_unicast_known. Each port sends to a host at a different port. | |
| 151 | + | |
| 152 | + | |
| 153 | +Black Box Tests | |
| 154 | +---------------- | |
| 155 | + | |
| 156 | +One test currently fails with the OF Reference v0.8.1 kmod: | |
| 157 | + | |
| 158 | +-LLC: Pkt is forwarded to the controller, when it should be dropped. | |
| 159 | + | |
| 160 | +Two tests are currently failing with the OF Reference v0.8.1 user-space switch: | |
| 161 | + | |
| 162 | +-test_forward_exact_controller | |
| 163 | +-test_forward_wildcard_controller | |
| 164 | + | |
| 165 | +All failing tests can be re-activated by changing | |
| 166 | +projects/black_box/regress/tests.txt | |
| 167 | + | |
| 168 | +== Basic Functionality == | |
| 169 | + | |
| 170 | +=== Hello === | |
| 171 | +:; Name: test_hello | |
| 172 | +:; Owner: Brandon Heller | |
| 173 | +:; Description: send hello packet to switch, verify reply with correct params | |
| 174 | + | |
| 175 | +=== Send from Switch to Controller === | |
| 176 | +:; Name: test_packet_in | |
| 177 | +:; Owner: Brandon Heller | |
| 178 | +:; Description: send packet from switch to SC, verify it is received at the controller | |
| 179 | + | |
| 180 | +=== Send from Controller to Switch === | |
| 181 | +:; Name: test_packet_out | |
| 182 | +:; Owner: Brandon Heller | |
| 183 | +:; Description: send packet to switch on secure chan for each output port, ensure packet received at proper ports. | |
| 184 | + | |
| 185 | +=== Switch Config === | |
| 186 | +:; Name: test_switch_config | |
| 187 | +:; Owner: Brandon Heller | |
| 188 | +:; Description: verify default switch config, set config, verify that config has changed | |
| 189 | +:; Status: done | |
| 190 | + | |
| 191 | +=== Flow Expired === | |
| 192 | +:; Name: test_flow_expired | |
| 193 | +:; Owner: Brandon Heller | |
| 194 | +:; Description: send add flow message for short timeout, verify no error message received, plus flow timeout message received within time bounds | |
| 195 | +::send a second add flow message and keep it active with packets; verify that flow expires only if idle | |
| 196 | + | |
| 197 | +=== Miss Send Length === | |
| 198 | +:; Name: test_miss_send_length | |
| 199 | +:; Owner: Brandon Heller | |
| 200 | +:; Description: get the miss send length from the hello message, then send a packet to switch, verify correct length for forwarded chunk of packet | |
| 201 | + | |
| 202 | +== Modify State Tests == | |
| 203 | + | |
| 204 | +=== Forward Any Port === | |
| 205 | +:; Name: test_forward_any_port | |
| 206 | +:; Owner: Brandon Heller | |
| 207 | +:; Description: add a flow mod with all wildcards set, and ensure that all packets get diverted to the specified port. | |
| 208 | + | |
| 209 | +=== Forward Exact Port === | |
| 210 | +:; Name: test_forward_exact_port | |
| 211 | +:; Owner: Brandon Heller | |
| 212 | +:; Description: add an exact flow entry, verify a packet is forwarded to the correct port, for all port combinations | |
| 213 | + | |
| 214 | +=== Forward Exact ALL === | |
| 215 | +:; Name: test_forward_exact_all | |
| 216 | +:; Owner: Brandon Nefcy | |
| 217 | +:; Description: add an exact flow entry, verify a packet is sent out all ports, for all port combinations | |
| 218 | +:; Implementation: One packet is sent in to eth0, eth1, eth2, and eth3. An exact match flow entry is set up for each, with the expected action to be flooding the packet out on all ports except the input port. | |
| 219 | + | |
| 220 | +=== Forward Exact Controller === | |
| 221 | +:; Name: test_forward_exact_controller | |
| 222 | +:; Owner: Brandon Nefcy | |
| 223 | +:; Description: add an exact flow entry, verify a packet is forwarded to the secure channel | |
| 224 | +:; Implementation: One packet is sent in on each of eth0, eth1, eth2, and eth3. Test behavior expects to see each packet arrive via the secchan. | |
| 225 | + | |
| 226 | +=== Forward Wildcard Port === | |
| 227 | +:; Name: test_forward_wildcard_port | |
| 228 | +:; Owner: Brandon Nefcy | |
| 229 | +:; Description: Test each individual wildcard field. verify a matching packet is forwarded to the correct port, for all port combinations, and a mismatching packet is sent to secchan | |
| 230 | +:; Implementation: For each possible single-input-port to single-output-port combination flows are set up, one at a time, where each flow is wildcarded on a single field, with enough flows rotated in to test every wildcard field. For each, a matching packet is sent in and expected on the appropriate output port, and a mismatching packet is sent in and expected on the secchan output | |
| 231 | + | |
| 232 | +=== Forward Wildcard ALL === | |
| 233 | +:; Name: test_forward_wildcard_all | |
| 234 | +:; Owner: Brandon Nefcy | |
| 235 | +:; Description: same as test_forward_wildcard_port, but instead of sending from one input to one output, sends from one input to all outputs. | |
| 236 | +:; Implementation: Combination of test_foward_wildcard_port and test_forward_exact_all | |
| 237 | + | |
| 238 | +=== Forward Wildcard Controller === | |
| 239 | +:; Name: test_forward_wildcard_controller | |
| 240 | +:; Owner: Brandon Nefcy | |
| 241 | +:; Description: Combination of test_forward_wildcard_port and test_forward_exact_controller. Tests various single wildcard flows where matching packets and mismatching packets are both sent to secchan. | |
| 242 | +:; Status: Checked in, working, but with limitations as mentioned in test_forward_wildcard_port | |
| 243 | + | |
| 244 | +=== Forward After Expiration === | |
| 245 | +:; Name: test_forward_after_expiration | |
| 246 | +:; Owner: Brandon Nefcy | |
| 247 | +:; Description: insert short-lived flow, use it to forward packet, wait until expiration, send packet again, verify nothing received and counters zeroed | |
| 248 | +:; Implementation: An exact match flow entry is inserted for a specific input port -> output port combination (ie eth0->eth1), a packet is sent to match this entry with the test expecting the appropriate output behavior. The test waits for the flow entry to expire and verifies the expiration via a secchan flow expiration message, then proceeds to re-send the same packet from before, expecting a secchan OFPR_NO_MATCH message. The above is repeated for all combinations of input port -> output port. | |
| 249 | + | |
| 250 | +=== Overlapping Flow Entries === | |
| 251 | +:; Name: test_forward_overlapping_flow_entries | |
| 252 | +:; Owner: Brandon Nefcy | |
| 253 | +:; Description: insert both wildcard and exact match flow entries that overlap, verify that the exact match takes precedence | |
| 254 | +:; Implementation: One packet is sent in on eth0, eth1, eth2, and eth3. Before each packet is sent, two flow entries are set up, one where the entire flow is wildcarded and the action is to send to secchan, and another where the flow is set up to be an exact-match for the packet about to be sent and the action is to flood the packet. The test verifies that the sent packets are flooded out, and no secchan messages are received other than the flows expiring. | |
| 255 | + | |
| 256 | +=== Delete === | |
| 257 | +:; Name: test_delete | |
| 258 | +:; Owner: Masa | |
| 259 | +:; Description: insert two flow entries (one wildcard entry and one exact entry where the exact one is covered by the wildcard one). Send packets to verify they are forwarded correctly. Then delete the wildcard entry with DELETE (not strict) -- both the wildcard and the exeact entries should be deleted. To check this, send a packet matching to the exact entry to verify it gets sent to contoller. Re-insert the entry and verify that counters are zeroed. | |
| 260 | +::; Note -- Counter reading has not been implemented yet so the last part is not verified (5/2/2008) | |
| 261 | +:; Status: Done (rewritten with clean format) | |
| 262 | + | |
| 263 | +=== Delete Strict === | |
| 264 | +:; Name: test_delete_strict | |
| 265 | +:; Owner: Masa | |
| 266 | +:; Description: insert two flow entries (one wildcard entry and one exact entry where the exact one is covered by the wildcard one. The output ports of these two entries are different). Send packets to verify they are forwarded correctly. Then delete the wildcard entry with DELETE_STRICT (not strict) -- only the wildcard entry should be deleted (the exeact entry should not be deleted). To check this, send a packet matching to the exact entry to verify it gets forwarded. | |
| 267 | +:; Status: Done (rewritten with clean format) | |
| 268 | + | |
| 269 | +== Unusual Data == | |
| 270 | + | |
| 271 | +=== IP Options === | |
| 272 | +:; Name: test_ip_options | |
| 273 | +:; Owner: Masa | |
| 274 | +:; Description: suggested by Nicira. | |
| 275 | +::;(1) Create a flow entry that matches to a UDP flow coming from port eth7 (action = forward to port eth8). | |
| 276 | +::;(2) Send UDP packets with IP time stamp option (ip_hdr_len=7) to port eth7. | |
| 277 | +::;(3) To see whether the packet comes out from port eth8. | |
| 278 | +::; As of May 2, 2008, test succeeded. | |
| 279 | + | |
| 280 | +=== IP Protocol === | |
| 281 | +:; Name: test_ip_protocol | |
| 282 | +:; Owner: Masa | |
| 283 | +:; Description: | |
| 284 | +:: Added by Masa | |
| 285 | +:: see if src/dst port fields are used for matching only for TCP/UDP packets | |
| 286 | +:: As of May 2, 2008, the result is the following. Even if protocol is not TCP nor UDP, port number fields seems used for matching. Only when protocol number is specified to zero, port number fields are not used for matching.. It seems a strange behavior. | |
| 287 | +:; Status: Done (rewritten w/ clean format) | |
| 288 | +:; Note : TCP checksum (in TCP header) is not calculated due to lack of NF2::TCP library (but OF switch won't check it anyway). | |
| 289 | + | |
| 290 | +=== IP Offset > Pkt Len === | |
| 291 | +:; Name: test_ip_offset | |
| 292 | +:; Owner: Masa | |
| 293 | +:; Description: | |
| 294 | +:: possible security risk, shouldn't be an issue | |
| 295 | +:: suggested by Nicira | |
| 296 | +:: Create a flow entry. Send several packets matching the entry but whose IP Offset > Pkt Len. Verify all the packets are forwarded to the specified port (specified by the flow entry). | |
| 297 | + | |
| 298 | +=== TCP Options === | |
| 299 | +:; Name: test_tcp_options | |
| 300 | +:; Owner: Masa | |
| 301 | +:; Description: | |
| 302 | +:: See if TCP options affect operation | |
| 303 | +:: Install a TCP flow entry. Sent a TCP pkt that matches to the installed entry but has TCP option. Verify the packet is forwarded to the specified port. | |
| 304 | +:; Note : TCP checksum (in TCP header) is not calculated due to lack of NF2::TCP library (but OF switch won't check it anyway). | |
| 305 | + | |
| 306 | +=== LLC === | |
| 307 | +:; Name: test_llc | |
| 308 | +:; Owner: Masa | |
| 309 | +:; Description: see LLC packet format; adds 5B to Eth packet | |
| 310 | +::; Install a flow entry (exact match to an IP flow). Send an IP packet that matches to the installed entry and has the following Ethernet LLC/SNAP header. Verify it is forwarded to the specified port. | |
| 311 | +:::; Dst MAC (6 byte) | |
| 312 | +:::; Src MAC (6 byte) | |
| 313 | +:::; Length (2 byte) = data length from LLC header to the end of IP packet | |
| 314 | +:::; LLC header (3 byte) = 0xAA 0xAA 0x03 (always this value for IP packets) | |
| 315 | +:::; SNAP header(5 byte) = OUI(3B)+Type(2B)=0x000000 + 0x0800(IP) (always this value for IP packets) | |
| 316 | +:::; IP Packet | |
| 317 | +:; NOTE: It fails (pkt is forwarded to the controller) as of June 11, 2008. | |
| 318 | + | |
| 319 | + | |
| 320 | +Bugs/Shortcomings | |
| 321 | +----------------- | |
| 322 | + | |
| 323 | +- test_llc and test_ip_protocol are not actually run when enabled in a tests.txt file | |
| 324 | + | |
| 325 | +Contact | |
| 326 | +------- | |
| 327 | + | |
| 328 | +e-mail: openflow-discuss@openflowswitch.org | |
| 329 | +www: http://openflowswitch.org/ | ... | ... |
regress/bin/eth.map
0 → 100755
regress/bin/nf2.map
0 → 100755
regress/bin/of_hp_eth.map
0 → 100755
regress/bin/of_hp_setup.pl
0 → 100755
| 1 | +#!/usr/bin/perl -w | |
| 2 | + | |
| 3 | +use Getopt::Long; | |
| 4 | + | |
| 5 | +use OF::OFUtil; | |
| 6 | +use Test::TestLib; | |
| 7 | +use Time::HiRes qw(usleep); | |
| 8 | + | |
| 9 | +my $mapFile; | |
| 10 | +my $of_hp_switch_ip; | |
| 11 | +my $of_hp_vlan; | |
| 12 | +my $of_hp_controller; | |
| 13 | +my $of_hp_listener; | |
| 14 | +my $of_hp_community; | |
| 15 | + | |
| 16 | +# Process command line options | |
| 17 | +# Don't fail on unrecognised options, those failures are tricky | |
| 18 | +# to diagnose. For example projects/controller_disconnect sets --emerg | |
| 19 | +# Jean II | |
| 20 | +Getopt::Long::Configure( 'pass_through' ); | |
| 21 | +GetOptions( "map=s" => \$mapFile, ); | |
| 22 | +Getopt::Long::Configure( 'default' ); | |
| 23 | + | |
| 24 | +# If not specified on command line, use environment variable. | |
| 25 | +# Try specific first, then try generic - Jean II | |
| 26 | +if ( (! defined($mapFile) ) && (defined($ENV{'OFT_HP_MAP_ETH'})) ) { | |
| 27 | + $mapFile = "$ENV{OFT_HP_MAP_ETH}"; | |
| 28 | +} | |
| 29 | +if ( (! defined($mapFile) ) && (defined($ENV{'OFT_MAP_ETH'})) ) { | |
| 30 | + $mapFile = "$ENV{OFT_MAP_ETH}"; | |
| 31 | +} | |
| 32 | + | |
| 33 | +if ( defined($mapFile) ) { | |
| 34 | + nftest_process_iface_map($mapFile); | |
| 35 | +} | |
| 36 | + | |
| 37 | +setup_pcap_interfaces(); | |
| 38 | + | |
| 39 | +# Get HP switch address and configuration - Jean II | |
| 40 | +if (defined($ENV{'OFT_HP_SWITCH_IP'})) { | |
| 41 | + $of_hp_switch_ip = $ENV{'OFT_HP_SWITCH_IP'}; | |
| 42 | +} else { | |
| 43 | + $of_hp_switch_ip = "10.10.10.1"; | |
| 44 | +} | |
| 45 | +if (defined($ENV{'OFT_HP_VLAN'})) { | |
| 46 | + $of_hp_vlan = $ENV{'OFT_HP_VLAN'}; | |
| 47 | +} else { | |
| 48 | + $of_hp_vlan = 18; | |
| 49 | +} | |
| 50 | +if (defined($ENV{'OFT_HP_CONTROLLER'})) { | |
| 51 | + $of_hp_controller = $ENV{'OFT_HP_CONTROLLER'}; | |
| 52 | +} else { | |
| 53 | + my $of_port = get_of_port(); | |
| 54 | + $of_hp_controller = "tcp:10.10.10.2:$of_port"; | |
| 55 | +} | |
| 56 | +if (defined($ENV{'OFT_HP_LISTENER'})) { | |
| 57 | + # Transform into a passive string | |
| 58 | + ($proto, $host, $port) = split(/:/,$ENV{'OFT_HP_LISTENER'}); | |
| 59 | + $of_hp_listener = "p$proto:$port"; | |
| 60 | +} | |
| 61 | +if (defined($ENV{'OFT_HP_COMMUNITY'})) { | |
| 62 | + $of_hp_community = $ENV{'OFT_HP_COMMUNITY'}; | |
| 63 | +} else { | |
| 64 | + $of_hp_community = 'public'; | |
| 65 | +} | |
| 66 | + | |
| 67 | + | |
| 68 | +# disable OpenFlow module to make sure it restarts | |
| 69 | +`snmpset -v2c -c ${of_hp_community} ${of_hp_switch_ip} iso.org.dod.internet.private.enterprises.11.2.14.11.5.1.7.1.35.1.1.2.${of_hp_vlan} i 2`; | |
| 70 | + | |
| 71 | +# Make sure the snmp commands don't coalesce | |
| 72 | +usleep(200000); | |
| 73 | + | |
| 74 | +# set OpenFlow Controller string | |
| 75 | +`snmpset -v2c -c ${of_hp_community} ${of_hp_switch_ip} iso.org.dod.internet.private.enterprises.11.2.14.11.5.1.7.1.35.1.1.3.${of_hp_vlan} s ${of_hp_controller}`; | |
| 76 | + | |
| 77 | +# set OpenFlow Listener string | |
| 78 | +if (defined($of_hp_listener)) { | |
| 79 | + `snmpset -v2c -c ${of_hp_community} ${of_hp_switch_ip} iso.org.dod.internet.private.enterprises.11.2.14.11.5.1.7.1.35.1.1.4.${of_hp_vlan} s ${of_hp_listener}`; | |
| 80 | +} | |
| 81 | + | |
| 82 | +# enable OpenFlow module | |
| 83 | +`snmpset -v2c -c ${of_hp_community} ${of_hp_switch_ip} iso.org.dod.internet.private.enterprises.11.2.14.11.5.1.7.1.35.1.1.2.${of_hp_vlan} i 1`; | |
| 84 | + | |
| 85 | +# Starting OpenFlow takes time, give switch a bit of time... | |
| 86 | +usleep(900000); | ... | ... |
regress/bin/of_hp_teardown.pl
0 → 100755
| 1 | +#!/usr/bin/perl -w | |
| 2 | + | |
| 3 | +use Getopt::Long; | |
| 4 | + | |
| 5 | +use OF::OFUtil; | |
| 6 | +use Test::TestLib; | |
| 7 | + | |
| 8 | +my $mapFile; | |
| 9 | +my $of_hp_switch_ip; | |
| 10 | +my $of_hp_community; | |
| 11 | + | |
| 12 | +# Process command line options | |
| 13 | +unless ( GetOptions( "map=s" => \$mapFile, ) ) { | |
| 14 | + print "unrecognized option\n"; | |
| 15 | + exit 1; | |
| 16 | +} | |
| 17 | + | |
| 18 | +# If not specified on command line, use environment variable. | |
| 19 | +# Try specific first, then try generic - Jean II | |
| 20 | +if ( (! defined($mapFile) ) && (defined($ENV{'OFT_HP_MAP_ETH'})) ) { | |
| 21 | + $mapFile = "$ENV{OFT_HP_MAP_ETH}"; | |
| 22 | +} | |
| 23 | +if ( (! defined($mapFile) ) && (defined($ENV{'OFT_MAP_ETH'})) ) { | |
| 24 | + $mapFile = "$ENV{OFT_MAP_ETH}"; | |
| 25 | +} | |
| 26 | + | |
| 27 | +if ( defined($mapFile) ) { | |
| 28 | + nftest_process_iface_map($mapFile); | |
| 29 | +} | |
| 30 | + | |
| 31 | +# Get HP switch address - Jean II | |
| 32 | +if (defined($ENV{'OFT_HP_SWITCH_IP'})) { | |
| 33 | + $of_hp_switch_ip = $ENV{'OFT_HP_SWITCH_IP'}; | |
| 34 | +} else { | |
| 35 | + $of_hp_switch_ip = "10.10.10.1"; | |
| 36 | +} | |
| 37 | +if (defined($ENV{'OFT_HP_VLAN'})) { | |
| 38 | + $of_hp_vlan = $ENV{'OFT_HP_VLAN'}; | |
| 39 | +} else { | |
| 40 | + $of_hp_vlan = 18; | |
| 41 | +} | |
| 42 | +if (defined($ENV{'OFT_HP_COMMUNITY'})) { | |
| 43 | + $of_hp_community = $ENV{'OFT_HP_COMMUNITY'}; | |
| 44 | +} else { | |
| 45 | + $of_hp_community = 'public'; | |
| 46 | +} | |
| 47 | + | |
| 48 | +# disable OpenFlow module | |
| 49 | +`snmpset -v2c -c ${of_hp_community} ${of_hp_switch_ip} iso.org.dod.internet.private.enterprises.11.2.14.11.5.1.7.1.35.1.1.2.${of_hp_vlan} i 2`; | |
| 50 | + | ... | ... |
regress/bin/of_hp_test.pl
0 → 100755
| 1 | +#!/usr/bin/perl -w | |
| 2 | + | |
| 3 | +############################################################################## | |
| 4 | +# | |
| 5 | +# Wrapper for running OpenFlow regression tests against ProCurve 3500/5400 | |
| 6 | +# Jean Tourrilhes - HP-Labs - copyright 2009-2010 | |
| 7 | +# $Id: of_regress_test.pl 105 2008-06-06 04:07:05Z brandonh $ | |
| 8 | +# | |
| 9 | +############################################################################## | |
| 10 | + | |
| 11 | +use OF::Base; | |
| 12 | +use Test::RegressTest; | |
| 13 | +use strict; | |
| 14 | +use OF::OFUtil; | |
| 15 | + | |
| 16 | +# check vars are set. | |
| 17 | +check_OF_vars_set(); | |
| 18 | + | |
| 19 | +sub INT_Handler { | |
| 20 | + my $signame = shift; | |
| 21 | + print "\nNo interrupt handler implemented yet...\n"; | |
| 22 | + print "\nExited with SIG$signame\n"; | |
| 23 | + exit(1); | |
| 24 | +} | |
| 25 | + | |
| 26 | +# For the 5406zl and 3500yl... | |
| 27 | + | |
| 28 | +# HP switch starts at port 1 == 'A1' or 1 == '1' | |
| 29 | +# Test need extra delay due to slow controller socket | |
| 30 | +# Add more idle time due to stat resolution | |
| 31 | +# byte count is not available - Jean II | |
| 32 | +push @ARGV, "--root=$ENV{'OFT_ROOT'}", "--common-st-args=hp", "--controller=".$ENV{'OFT_HP_CONTROLLER'}, "--port_base=1", "--send_delay=300000", "--base_idle=2", "--ignore_byte_count"; | |
| 33 | + | |
| 34 | +# Use a single random port instead of all four | |
| 35 | +push @ARGV, "--less_ports"; | |
| 36 | + | |
| 37 | +# For QinQ, you will need the premium license... | |
| 38 | +push @ARGV, "--no_vlan"; | |
| 39 | + | |
| 40 | +# The hardware can not support slicing | |
| 41 | +push @ARGV, "--no_slicing"; | |
| 42 | + | |
| 43 | +# The hardware can not support barrier | |
| 44 | +push @ARGV, "--no_barrier"; | |
| 45 | + | |
| 46 | +# The hardware can not support emergency flow table | |
| 47 | +push @ARGV, "--no_emerg"; | |
| 48 | + | |
| 49 | +# Check for listener | |
| 50 | +if ( defined($ENV{'OFT_HP_LISTENER'}) ) { | |
| 51 | + push @ARGV, "--listener=$ENV{OFT_HP_LISTENER}"; | |
| 52 | +} | |
| 53 | + | |
| 54 | +# Check for specific MAP file... | |
| 55 | +if ( defined($ENV{'OFT_HP_MAP_ETH'}) ) { | |
| 56 | + push @ARGV, "--map=$ENV{OFT_HP_MAP_ETH}"; | |
| 57 | +} | |
| 58 | + | |
| 59 | +# Other configuration is through Environment Variables, See of_hp_setup.pl | |
| 60 | +# Jean II | |
| 61 | + | |
| 62 | +run_regress_test( \&INT_Handler, @ARGV ); | ... | ... |
regress/bin/of_hp_test_6600.pl
0 → 100755
| 1 | +#!/usr/bin/perl -w | |
| 2 | + | |
| 3 | +############################################################################## | |
| 4 | +# | |
| 5 | +# Wrapper for running OpenFlow regression tests against ProCurve 6600 | |
| 6 | +# Jean Tourrilhes - HP-Labs - copyright 2009-2010 | |
| 7 | +# $Id: of_regress_test.pl 105 2008-06-06 04:07:05Z brandonh $ | |
| 8 | +# | |
| 9 | +############################################################################## | |
| 10 | + | |
| 11 | +use OF::Base; | |
| 12 | +use Test::RegressTest; | |
| 13 | +use strict; | |
| 14 | +use OF::OFUtil; | |
| 15 | + | |
| 16 | +# check vars are set. | |
| 17 | +check_OF_vars_set(); | |
| 18 | + | |
| 19 | +sub INT_Handler { | |
| 20 | + my $signame = shift; | |
| 21 | + print "\nNo interrupt handler implemented yet...\n"; | |
| 22 | + print "\nExited with SIG$signame\n"; | |
| 23 | + exit(1); | |
| 24 | +} | |
| 25 | + | |
| 26 | +# For the 6600... | |
| 27 | + | |
| 28 | +# HP switch starts at port 25 == '1' | |
| 29 | +# Test need extra delay due to slow controller socket | |
| 30 | +# Add more idle time due to stat resolution | |
| 31 | +# byte count is not available - Jean II | |
| 32 | +push @ARGV, "--root=$ENV{'OFT_ROOT'}", "--common-st-args=hp", "--controller=".$ENV{'OFT_HP_CONTROLLER'}, "--port_base=25", "--send_delay=650000", "--base_idle=3", "--ignore_byte_count"; | |
| 33 | + | |
| 34 | +# Use a single random port instead of all four | |
| 35 | +push @ARGV, "--less_ports"; | |
| 36 | + | |
| 37 | +# For QinQ, you will need the premium license... | |
| 38 | +push @ARGV, "--no_vlan"; | |
| 39 | + | |
| 40 | +# The hardware can not support slicing | |
| 41 | +push @ARGV, "--no_slicing"; | |
| 42 | + | |
| 43 | +# The hardware can not support barrier | |
| 44 | +push @ARGV, "--no_barrier"; | |
| 45 | + | |
| 46 | +# The hardware can not support emergency flow table | |
| 47 | +push @ARGV, "--no_emerg"; | |
| 48 | + | |
| 49 | +# Check for listener | |
| 50 | +if ( defined($ENV{'OFT_HP_LISTENER'}) ) { | |
| 51 | + push @ARGV, "--listener=$ENV{OFT_HP_LISTENER}"; | |
| 52 | +} | |
| 53 | + | |
| 54 | +# Check for specific MAP file... | |
| 55 | +if ( defined($ENV{'OFT_HP_MAP_ETH'}) ) { | |
| 56 | + push @ARGV, "--map=$ENV{OFT_HP_MAP_ETH}"; | |
| 57 | +} | |
| 58 | + | |
| 59 | +# Other configuration is through Environment Variables, See of_hp_setup.pl | |
| 60 | +# Jean II | |
| 61 | + | |
| 62 | +run_regress_test( \&INT_Handler, @ARGV ); | ... | ... |
regress/bin/of_kmod_setup.pl
0 → 100755
| 1 | +#!/usr/bin/perl -w | |
| 2 | + | |
| 3 | +use Getopt::Long; | |
| 4 | + | |
| 5 | +use OF::OFUtil; | |
| 6 | +use Test::TestLib; | |
| 7 | + | |
| 8 | +my $mapFile, $controller; | |
| 9 | + | |
| 10 | +# Process command line options | |
| 11 | +unless ( GetOptions( "map=s" => \$mapFile, | |
| 12 | + "emerg" => \$emerg, | |
| 13 | + "controller=s", \$controller) ) { | |
| 14 | + print "unrecognized option\n"; | |
| 15 | + exit 1; | |
| 16 | +} | |
| 17 | + | |
| 18 | +if ( defined($mapFile) ) { | |
| 19 | + nftest_process_iface_map($mapFile); | |
| 20 | +} | |
| 21 | + | |
| 22 | +setup_kmod($controller, $emerg); | ... | ... |
regress/bin/of_kmod_teardown.pl
0 → 100755
| 1 | +#!/usr/bin/perl -w | |
| 2 | + | |
| 3 | +use Getopt::Long; | |
| 4 | + | |
| 5 | +use OF::OFUtil; | |
| 6 | +use Test::TestLib; | |
| 7 | + | |
| 8 | +my $mapFile; | |
| 9 | + | |
| 10 | +# Process command line options | |
| 11 | +unless ( GetOptions( "map=s" => \$mapFile, ) ) { | |
| 12 | + print "unrecognized option\n"; | |
| 13 | + exit 1; | |
| 14 | +} | |
| 15 | + | |
| 16 | +if ( defined($mapFile) ) { | |
| 17 | + nftest_process_iface_map($mapFile); | |
| 18 | +} | |
| 19 | + | |
| 20 | +teardown_kmod(); | ... | ... |
regress/bin/of_kmod_test.pl
0 → 100755
| 1 | +#!/usr/bin/perl -w | |
| 2 | + | |
| 3 | +############################################################################## | |
| 4 | +# | |
| 5 | +# Wrapper for OpenFlow regression tests | |
| 6 | +# $Id: of_regress_test.pl 105 2008-06-06 04:07:05Z brandonh $ | |
| 7 | +# | |
| 8 | +############################################################################## | |
| 9 | + | |
| 10 | +use OF::Base; | |
| 11 | +use Test::RegressTest; | |
| 12 | +use strict; | |
| 13 | +use OF::OFUtil; | |
| 14 | + | |
| 15 | +# check vars are set. | |
| 16 | +check_OF_vars_set(); | |
| 17 | + | |
| 18 | +sub INT_Handler { | |
| 19 | + my $signame = shift; | |
| 20 | + print "\nNo interrupt handler implemented yet...\n"; | |
| 21 | + print "\nExited with SIG$signame\n"; | |
| 22 | + exit(1); | |
| 23 | +} | |
| 24 | + | |
| 25 | +push (@ARGV, "--root=$ENV{'OFT_ROOT'}", "--map=$ENV{'OFT_ROOT'}/bin/eth.map", "--port_base=1", "--common-st-args=kmod"); | |
| 26 | + | |
| 27 | +run_regress_test( \&INT_Handler, @ARGV ); | ... | ... |
regress/bin/of_kmod_veth_setup.pl
0 → 100755
| 1 | +#!/usr/bin/perl -w | |
| 2 | + | |
| 3 | +use Getopt::Long; | |
| 4 | + | |
| 5 | +use OF::OFUtil; | |
| 6 | +use Test::TestLib; | |
| 7 | + | |
| 8 | +my ($mapFile, $controller); | |
| 9 | + | |
| 10 | +# Process command line options | |
| 11 | +unless ( GetOptions( "map=s" => \$mapFile, | |
| 12 | + "emerg" => \$emerg, | |
| 13 | + "controller=s", \$controller) ) { | |
| 14 | + print "unrecognized option\n"; | |
| 15 | + exit 1; | |
| 16 | +} | |
| 17 | + | |
| 18 | +if ( defined($mapFile) ) { | |
| 19 | + nftest_process_iface_map($mapFile); | |
| 20 | +} | |
| 21 | +#else, use pre-defined veth map | |
| 22 | +else { | |
| 23 | + nftest_process_iface_map("$ENV{'OFT_ROOT'}/bin/veth.map"); | |
| 24 | +} | |
| 25 | + | |
| 26 | +setup_kmod($controller, $emerg); | ... | ... |
regress/bin/of_kmod_veth_teardown.pl
0 → 100755
| 1 | +#!/usr/bin/perl -w | |
| 2 | + | |
| 3 | +use Getopt::Long; | |
| 4 | + | |
| 5 | +use OF::OFUtil; | |
| 6 | +use Test::TestLib; | |
| 7 | + | |
| 8 | +my $mapFile; | |
| 9 | + | |
| 10 | +# Process command line options | |
| 11 | +unless ( GetOptions( "map=s" => \$mapFile, ) ) { | |
| 12 | + print "unrecognized option\n"; | |
| 13 | + exit 1; | |
| 14 | +} | |
| 15 | + | |
| 16 | +if ( defined($mapFile) ) { | |
| 17 | + nftest_process_iface_map($mapFile); | |
| 18 | +} | |
| 19 | +#else, use pre-defined veth map | |
| 20 | +else { | |
| 21 | + nftest_process_iface_map("$ENV{'OFT_ROOT'}/bin/veth.map"); | |
| 22 | +} | |
| 23 | + | |
| 24 | +teardown_kmod(); | ... | ... |
regress/bin/of_kmod_veth_test.pl
0 → 100755
| 1 | +#!/usr/bin/perl -w | |
| 2 | + | |
| 3 | +############################################################################## | |
| 4 | +# | |
| 5 | +# Wrapper for OpenFlow regression tests | |
| 6 | +# $Id: of_regress_test.pl 105 2008-06-06 04:07:05Z brandonh $ | |
| 7 | +# | |
| 8 | +############################################################################## | |
| 9 | + | |
| 10 | +use OF::Base; | |
| 11 | +use Test::RegressTest; | |
| 12 | +use strict; | |
| 13 | +use OF::OFUtil; | |
| 14 | + | |
| 15 | +# check vars are set. | |
| 16 | +check_OF_vars_set(); | |
| 17 | + | |
| 18 | +sub INT_Handler { | |
| 19 | + my $signame = shift; | |
| 20 | + print "\nNo interrupt handler implemented yet...\n"; | |
| 21 | + print "\nExited with SIG$signame\n"; | |
| 22 | + exit(1); | |
| 23 | +} | |
| 24 | + | |
| 25 | +push (@ARGV, "--map=$ENV{'OFT_ROOT'}/bin/veth.map", "--root=$ENV{'OFT_ROOT'}", "--port_base=1", "--common-st-args=kmod_veth"); | |
| 26 | + | |
| 27 | +run_regress_test( \&INT_Handler, @ARGV ); | ... | ... |
regress/bin/of_nf2_setup.pl
0 → 100755
| 1 | +#!/usr/bin/perl -w | |
| 2 | + | |
| 3 | +use Getopt::Long; | |
| 4 | +use Data::Dumper; | |
| 5 | + | |
| 6 | +use OF::OFUtil; | |
| 7 | +use Test::TestLib; | |
| 8 | + | |
| 9 | +my ($mapFile, $controller); | |
| 10 | + | |
| 11 | +print "Calling of_nf2_setup.pl\n"; | |
| 12 | +print Dumper(@ARGV) . "\n"; | |
| 13 | + | |
| 14 | +# Process command line options | |
| 15 | +unless ( GetOptions( "map=s" => \$mapFile, | |
| 16 | + "emerg" => \$emerg, | |
| 17 | + "controller=s", \$controller) ) { | |
| 18 | + print "unrecognized option\n"; | |
| 19 | + exit 1; | |
| 20 | +} | |
| 21 | + | |
| 22 | +if ( defined($mapFile) ) { | |
| 23 | + nftest_process_iface_map($mapFile); | |
| 24 | +} | |
| 25 | + | |
| 26 | +setup_NF2($controller, $emerg); | ... | ... |
regress/bin/of_nf2_teardown.pl
0 → 100755
| 1 | +#!/usr/bin/perl -w | |
| 2 | + | |
| 3 | +use Getopt::Long; | |
| 4 | + | |
| 5 | +use OF::OFUtil; | |
| 6 | +use Test::TestLib; | |
| 7 | + | |
| 8 | +my $mapFile; | |
| 9 | + | |
| 10 | +# Process command line options | |
| 11 | +unless ( GetOptions( "map=s" => \$mapFile, ) ) { | |
| 12 | + print "unrecognized option\n"; | |
| 13 | + exit 1; | |
| 14 | +} | |
| 15 | + | |
| 16 | +if ( defined($mapFile) ) { | |
| 17 | + nftest_process_iface_map($mapFile); | |
| 18 | +} | |
| 19 | + | |
| 20 | +teardown_NF2(); | ... | ... |
regress/bin/of_nf2_test.pl
0 → 100755
| 1 | +#!/usr/bin/perl -w | |
| 2 | + | |
| 3 | +############################################################################## | |
| 4 | +# | |
| 5 | +# Wrapper for OpenFlow regression tests | |
| 6 | +# $Id: of_regress_test.pl 105 2008-06-06 04:07:05Z brandonh $ | |
| 7 | +# | |
| 8 | +############################################################################## | |
| 9 | + | |
| 10 | +use OF::Base; | |
| 11 | +use Test::RegressTest; | |
| 12 | +use strict; | |
| 13 | +use OF::OFUtil; | |
| 14 | + | |
| 15 | +# check vars are set. | |
| 16 | +check_OF_vars_set(); | |
| 17 | + | |
| 18 | +sub INT_Handler { | |
| 19 | + my $signame = shift; | |
| 20 | + print "\nNo interrupt handler implemented yet...\n"; | |
| 21 | + print "\nExited with SIG$signame\n"; | |
| 22 | + exit(1); | |
| 23 | +} | |
| 24 | + | |
| 25 | +push (@ARGV, "--root=$ENV{'OFT_ROOT'}", "--map=$ENV{'OFT_ROOT'}/bin/nf2.map", "--port_base=1", "--common-st-args=nf2"); | |
| 26 | +push @ARGV, "--no_slicing"; | |
| 27 | + | |
| 28 | +run_regress_test( \&INT_Handler, @ARGV ); | ... | ... |
regress/bin/of_ovs_eth.map
0 → 100755
regress/bin/of_ovs_setup.pl
0 → 100755
| 1 | +#!/usr/bin/perl -w | |
| 2 | +# Jean Tourrilhes - HP-Labs | |
| 3 | + | |
| 4 | +use Getopt::Long; | |
| 5 | + | |
| 6 | +use OF::OFUtil; | |
| 7 | +use Test::TestLib; | |
| 8 | + | |
| 9 | +my $mapFile; | |
| 10 | + | |
| 11 | +# The map file is necessary. It assing the real interface to the | |
| 12 | +# fictious names used by the test suite. | |
| 13 | +# eth1->eth4 are capture interfaces used to send/receive probe packets | |
| 14 | +# eth5->eth8 are configured to run the OpenFlow switch | |
| 15 | +# Jean II | |
| 16 | + | |
| 17 | +# Process command line options | |
| 18 | +# Don't fail on unrecognised options, those failures are tricky | |
| 19 | +# to diagnose. For example projects/controller_disconnect sets --emerg | |
| 20 | +# Jean II | |
| 21 | +Getopt::Long::Configure( 'pass_through' ); | |
| 22 | +GetOptions( "map=s" => \$mapFile, ); | |
| 23 | +Getopt::Long::Configure( 'default' ); | |
| 24 | + | |
| 25 | +# If not specified on command line, use enviroment variable. | |
| 26 | +# Try specific first, then try generic - Jean II | |
| 27 | +if ( (! defined($mapFile) ) && (defined($ENV{'OFT_OVS_MAP_ETH'})) ) { | |
| 28 | + $mapFile = "$ENV{OFT_OVS_MAP_ETH}"; | |
| 29 | +} | |
| 30 | +if ( (! defined($mapFile) ) && (defined($ENV{'OFT_MAP_ETH'})) ) { | |
| 31 | + $mapFile = "$ENV{OFT_MAP_ETH}"; | |
| 32 | +} | |
| 33 | + | |
| 34 | +# Set up the mappings | |
| 35 | +if ( defined($mapFile) ) { | |
| 36 | + nftest_process_iface_map($mapFile); | |
| 37 | +} | |
| 38 | + | |
| 39 | +# Debug... | |
| 40 | +#for ( my $i = 1 ; $i <= 8 ; $i++ ) { | |
| 41 | +# my $iface = nftest_get_iface("eth$i"); | |
| 42 | +# print "iface($i) = $iface\n"; | |
| 43 | +#} | |
| 44 | + | |
| 45 | +# Start capturing on eth1->eth4 | |
| 46 | +setup_pcap_interfaces(); | |
| 47 | + | |
| 48 | +# Get the directly where Open vSwitch resides | |
| 49 | +my $ovs_dir = $ENV{'OFT_OVS_ROOT'}; | |
| 50 | +my $of_port = get_of_port(); | |
| 51 | + | |
| 52 | +# Setup the kernel module | |
| 53 | +`insmod ${ovs_dir}/datapath/linux-2.6/openvswitch_mod.ko`; | |
| 54 | +`${ovs_dir}/utilities/ovs-dpctl add-dp dp0`; | |
| 55 | + | |
| 56 | +# Not needed after 0.99.2 | |
| 57 | +#for ( my $i = 5 ; $i <= 8 ; $i++ ) { | |
| 58 | +# my $iface = nftest_get_iface("eth$i"); | |
| 59 | +# `${ovs_dir}/utilities/ovs-dpctl add-if dp0 $iface`; | |
| 60 | +#} | |
| 61 | + | |
| 62 | +# create command line arguments containing all four ports | |
| 63 | +my $if_string = ''; | |
| 64 | +for ( my $i = 5 ; $i <= 7 ; $i++ ) { | |
| 65 | + $if_string .= nftest_get_iface("eth$i") . ','; | |
| 66 | +} | |
| 67 | +$if_string .= nftest_get_iface("eth8"); | |
| 68 | + | |
| 69 | +# create Open vSwitch openflow switch on four ports eth5->eth9 | |
| 70 | +system("${ovs_dir}/utilities/ovs-openflowd dp0 --ports=${if_string} tcp:127.0.0.1:${of_port} --listen=ptcp:6634 --fail=closed --inactivity-probe=999999 &"); | |
| 71 | + | |
| 72 | +# For 0.99.0, you'll need to manually add ports as above | |
| 73 | +#system("${ovs_dir}/utilities/ovs-openflowd dp0 tcp:127.0.0.1:${of_port} --listen=ptcp:6634 --fail=closed --inactivity-probe=999999 &"); | |
| 74 | + | |
| 75 | +# Up to 0.90.6, you would use secchan, after that you need to use ovs-openflowd | |
| 76 | +#system("${ovs_dir}/secchan/secchan dp0 tcp:127.0.0.1:${of_port} --listen=ptcp:6634 --fail=closed --inactivity-probe=999999 &"); | ... | ... |
regress/bin/of_ovs_teardown.pl
0 → 100755
| 1 | +#!/usr/bin/perl -w | |
| 2 | +# Jean Tourrilhes - HP-Labs | |
| 3 | + | |
| 4 | +use Getopt::Long; | |
| 5 | + | |
| 6 | +use OF::OFUtil; | |
| 7 | +use Test::TestLib; | |
| 8 | + | |
| 9 | +my $mapFile; | |
| 10 | + | |
| 11 | +# Process command line options | |
| 12 | +unless ( GetOptions( "map=s" => \$mapFile, ) ) { | |
| 13 | + print "unrecognized option\n"; | |
| 14 | + exit 1; | |
| 15 | +} | |
| 16 | + | |
| 17 | +# If not specified on command line, use enviroment variable. | |
| 18 | +# Try specific first, then try generic - Jean II | |
| 19 | +if ( (! defined($mapFile) ) && (defined($ENV{'OFT_OVS_MAP_ETH'})) ) { | |
| 20 | + $mapFile = "$ENV{OFT_OVS_MAP_ETH}"; | |
| 21 | +} | |
| 22 | +if ( (! defined($mapFile) ) && (defined($ENV{'OFT_MAP_ETH'})) ) { | |
| 23 | + $mapFile = "$ENV{OFT_MAP_ETH}"; | |
| 24 | +} | |
| 25 | + | |
| 26 | +if ( defined($mapFile) ) { | |
| 27 | + nftest_process_iface_map($mapFile); | |
| 28 | +} | |
| 29 | + | |
| 30 | +# Get the directly where Open vSwitch resides | |
| 31 | +my $ovs_dir = $ENV{'OFT_OVS_ROOT'}; | |
| 32 | + | |
| 33 | +# Start by killing secchan or ovs-openflowd | |
| 34 | +`killall secchan`; | |
| 35 | +`killall ovs-openflowd`; | |
| 36 | + | |
| 37 | +# check if openflow kernel module loaded | |
| 38 | +my $of_kmod_loaded = `lsmod | grep openvswitch_mod`; | |
| 39 | +if ( $of_kmod_loaded eq "" ) { exit 0; } | |
| 40 | + | |
| 41 | +print "tearing down interfaces and datapaths\n"; | |
| 42 | + | |
| 43 | +# remove interfaces from openflow | |
| 44 | +for ( my $i = 5 ; $i <= 8 ; $i++ ) { | |
| 45 | + my $iface = nftest_get_iface("eth$i"); | |
| 46 | + `${ovs_dir}/utilities/ovs-dpctl del-if dp0 $iface`; | |
| 47 | +} | |
| 48 | + | |
| 49 | +`${ovs_dir}/utilities/ovs-dpctl del-dp dp0`; | |
| 50 | + | |
| 51 | +my $of_kmod_removed = `rmmod openvswitch_mod`; | |
| 52 | +if ( $of_kmod_removed ne "" ) { | |
| 53 | + die "failed to remove kernel module... please fix!\n"; | |
| 54 | +} | |
| 55 | + | |
| 56 | +$of_kmod_loaded = `lsmod | grep openvswitch_mod`; | |
| 57 | +if ( $of_kmod_loaded ne "" ) { | |
| 58 | + die "failed to remove kernel module... please fix!\n"; | |
| 59 | +} | ... | ... |
regress/bin/of_ovs_test.pl
0 → 100755
| 1 | +#!/usr/bin/perl -w | |
| 2 | + | |
| 3 | +############################################################################## | |
| 4 | +# | |
| 5 | +# Wrapper for running OpenFlow regression tests against Open vSwitch | |
| 6 | +# Jean Tourrilhes - HP-Labs - copyright 2009-2010 | |
| 7 | +# $Id: of_regress_test.pl 105 2008-06-06 04:07:05Z brandonh $ | |
| 8 | +# | |
| 9 | +############################################################################## | |
| 10 | + | |
| 11 | +use OF::Base; | |
| 12 | +use Test::RegressTest; | |
| 13 | +use strict; | |
| 14 | +use OF::OFUtil; | |
| 15 | + | |
| 16 | +# check vars are set. | |
| 17 | +check_OF_vars_set(); | |
| 18 | + | |
| 19 | +sub INT_Handler { | |
| 20 | + my $signame = shift; | |
| 21 | + print "\nNo interrupt handler implemented yet...\n"; | |
| 22 | + print "\nExited with SIG$signame\n"; | |
| 23 | + exit(1); | |
| 24 | +} | |
| 25 | + | |
| 26 | +# For Open vSwitch | |
| 27 | + | |
| 28 | +# Open vSwitch starts at port 1 | |
| 29 | +# Get a bit of speedup by tweaking send_delay and base_idle | |
| 30 | +# Jean II | |
| 31 | +my $of_port = get_of_port(); | |
| 32 | +push @ARGV, "--root=$ENV{'OFT_ROOT'}", "--common-st-args=ovs", "--controller=tcp:localhost:$of_port,tcp:localhost:$of_port", "--listener=tcp:127.0.0.1:6634", "--port_base=1", "--send_delay=2000", "--base_idle=2"; | |
| 33 | + | |
| 34 | +# Use a single random port instead of all four | |
| 35 | +push @ARGV, "--less_ports"; | |
| 36 | + | |
| 37 | +# Don't bother with VLAN if we go outside the box, too many issues... | |
| 38 | +#push @ARGV, "--no_vlan"; | |
| 39 | + | |
| 40 | +# Don't bother with QoS currently, it's broken... | |
| 41 | +push @ARGV, "--no_slicing"; | |
| 42 | + | |
| 43 | +# The bother with emergency flow table tests, it's not supported... | |
| 44 | +push @ARGV, "--no_emerg"; | |
| 45 | + | |
| 46 | +# Don't forget to configure the OVS_ROOT environment variable | |
| 47 | +# Jean II | |
| 48 | + | |
| 49 | +# Check for specific MAP file... | |
| 50 | +if ( defined($ENV{'OFT_OVS_MAP_ETH'}) ) { | |
| 51 | + push @ARGV, "--map=$ENV{OFT_OVS_MAP_ETH}"; | |
| 52 | +} | |
| 53 | + | |
| 54 | +run_regress_test( \&INT_Handler, @ARGV ); | ... | ... |
regress/bin/of_ovs_user_setup.pl
0 → 100755
| 1 | +#!/usr/bin/perl -w | |
| 2 | +# Jean Tourrilhes - HP-Labs | |
| 3 | + | |
| 4 | +use Getopt::Long; | |
| 5 | + | |
| 6 | +use OF::OFUtil; | |
| 7 | +use Test::TestLib; | |
| 8 | + | |
| 9 | +my $mapFile; | |
| 10 | + | |
| 11 | +# The map file is necessary. It assing the real interface to the | |
| 12 | +# fictious names used by the test suite. | |
| 13 | +# eth1->eth4 are capture interfaces used to send/receive probe packets | |
| 14 | +# eth5->eth8 are configured to run the OpenFlow switch | |
| 15 | +# Jean II | |
| 16 | + | |
| 17 | +# Process command line options | |
| 18 | +# Don't fail on unrecognised options, those failures are tricky | |
| 19 | +# to diagnose. For example projects/controller_disconnect sets --emerg | |
| 20 | +# Jean II | |
| 21 | +Getopt::Long::Configure( 'pass_through' ); | |
| 22 | +GetOptions( "map=s" => \$mapFile, ); | |
| 23 | +Getopt::Long::Configure( 'default' ); | |
| 24 | + | |
| 25 | +# If not specified on command line, use enviroment variable. | |
| 26 | +# Try specific first, then try generic - Jean II | |
| 27 | +if ( (! defined($mapFile) ) && (defined($ENV{'OFT_OVS_MAP_ETH'})) ) { | |
| 28 | + $mapFile = "$ENV{OFT_OVS_MAP_ETH}"; | |
| 29 | +} | |
| 30 | +if ( (! defined($mapFile) ) && (defined($ENV{'OFT_MAP_ETH'})) ) { | |
| 31 | + $mapFile = "$ENV{OFT_MAP_ETH}"; | |
| 32 | +} | |
| 33 | + | |
| 34 | +# Set up the mappings | |
| 35 | +if ( defined($mapFile) ) { | |
| 36 | + nftest_process_iface_map($mapFile); | |
| 37 | +} | |
| 38 | + | |
| 39 | +# Debug... | |
| 40 | +#for ( my $i = 1 ; $i <= 8 ; $i++ ) { | |
| 41 | +# my $iface = nftest_get_iface("eth$i"); | |
| 42 | +# print "iface($i) = $iface\n"; | |
| 43 | +#} | |
| 44 | + | |
| 45 | +# Start capturing on eth1->eth4 | |
| 46 | +setup_pcap_interfaces(); | |
| 47 | + | |
| 48 | +# Get the directly where Open vSwitch resides | |
| 49 | +my $ovs_dir = $ENV{'OFT_OVS_ROOT'}; | |
| 50 | +my $of_port = get_of_port(); | |
| 51 | + | |
| 52 | +# create command line arguments containing all four ports | |
| 53 | +my $if_string = ''; | |
| 54 | +for ( my $i = 5 ; $i <= 7 ; $i++ ) { | |
| 55 | + $if_string .= nftest_get_iface("eth$i") . ','; | |
| 56 | +} | |
| 57 | +$if_string .= nftest_get_iface("eth8"); | |
| 58 | + | |
| 59 | +# create userspace Open vSwitch openflow switch on four ports | |
| 60 | +system("${ovs_dir}/utilities/ovs-openflowd netdev\@br0 --ports=${if_string} tcp:127.0.0.1:${of_port} --listen=ptcp:6634 --fail=closed --inactivity-probe=999999 &"); | ... | ... |
regress/bin/of_ovs_user_teardown.pl
0 → 100755
| 1 | +#!/usr/bin/perl -w | |
| 2 | +# Jean Tourrilhes - HP-Labs | |
| 3 | + | |
| 4 | +use Getopt::Long; | |
| 5 | + | |
| 6 | +use OF::OFUtil; | |
| 7 | +use Test::TestLib; | |
| 8 | + | |
| 9 | +my $mapFile; | |
| 10 | + | |
| 11 | +# Process command line options | |
| 12 | +unless ( GetOptions( "map=s" => \$mapFile, ) ) { | |
| 13 | + print "unrecognized option\n"; | |
| 14 | + exit 1; | |
| 15 | +} | |
| 16 | + | |
| 17 | +# If not specified on command line, use enviroment variable. | |
| 18 | +# Try specific first, then try generic - Jean II | |
| 19 | +if ( (! defined($mapFile) ) && (defined($ENV{'OFT_OVS_MAP_ETH'})) ) { | |
| 20 | + $mapFile = "$ENV{OFT_OVS_MAP_ETH}"; | |
| 21 | +} | |
| 22 | +if ( (! defined($mapFile) ) && (defined($ENV{'OFT_MAP_ETH'})) ) { | |
| 23 | + $mapFile = "$ENV{OFT_MAP_ETH}"; | |
| 24 | +} | |
| 25 | + | |
| 26 | +if ( defined($mapFile) ) { | |
| 27 | + nftest_process_iface_map($mapFile); | |
| 28 | +} | |
| 29 | + | |
| 30 | +# Get the directly where Open vSwitch resides | |
| 31 | +my $ovs_dir = $ENV{'OFT_OVS_ROOT'}; | |
| 32 | + | |
| 33 | +# Just kill ovs-openflowd | |
| 34 | +`killall ovs-openflowd`; | ... | ... |
regress/bin/of_ovs_user_test.pl
0 → 100755
| 1 | +#!/usr/bin/perl -w | |
| 2 | + | |
| 3 | +############################################################################## | |
| 4 | +# | |
| 5 | +# Wrapper for OpenFlow regression tests | |
| 6 | +# $Id: of_regress_test.pl 105 2008-06-06 04:07:05Z brandonh $ | |
| 7 | +# | |
| 8 | +############################################################################## | |
| 9 | + | |
| 10 | +use OF::Base; | |
| 11 | +use Test::RegressTest; | |
| 12 | +use strict; | |
| 13 | +use OF::OFUtil; | |
| 14 | + | |
| 15 | +# check vars are set. | |
| 16 | +check_OF_vars_set(); | |
| 17 | + | |
| 18 | +sub INT_Handler { | |
| 19 | + my $signame = shift; | |
| 20 | + print "\nNo interrupt handler implemented yet...\n"; | |
| 21 | + print "\nExited with SIG$signame\n"; | |
| 22 | + exit(1); | |
| 23 | +} | |
| 24 | + | |
| 25 | +# For Open vSwitch | |
| 26 | + | |
| 27 | +# Open vSwitch starts at port 1 | |
| 28 | +# Get a bit of speedup by tweaking send_delay and base_idle | |
| 29 | +# Jean II | |
| 30 | +my $of_port = get_of_port(); | |
| 31 | +push @ARGV, "--root=$ENV{'OFT_ROOT'}", "--common-st-args=ovs_user", "--controller=tcp:localhost:$of_port,tcp:localhost:$of_port", "--listener=tcp:127.0.0.1:6634", "--port_base=1", "--send_delay=2000", "--base_idle=2"; | |
| 32 | + | |
| 33 | +# Use a single random port instead of all four | |
| 34 | +push @ARGV, "--less_ports"; | |
| 35 | + | |
| 36 | +# Don't bother with QoS currently, it's broken... | |
| 37 | +push @ARGV, "--no_slicing"; | |
| 38 | + | |
| 39 | +# The bother with emergency flow table tests, it's not supported... | |
| 40 | +push @ARGV, "--no_emerg"; | |
| 41 | + | |
| 42 | +# Don't forget to configure the OVS_ROOT environment variable | |
| 43 | +# Jean II | |
| 44 | + | |
| 45 | +# Check for specific MAP file... | |
| 46 | +if ( defined($ENV{'OFT_OVS_MAP_ETH'}) ) { | |
| 47 | + push @ARGV, "--map=$ENV{OFT_OVS_MAP_ETH}"; | |
| 48 | +} | |
| 49 | + | |
| 50 | +run_regress_test( \&INT_Handler, @ARGV ); | ... | ... |
regress/bin/of_ovs_user_veth_test.pl
0 → 100755
| 1 | +#!/usr/bin/perl -w | |
| 2 | + | |
| 3 | +############################################################################## | |
| 4 | +# | |
| 5 | +# Wrapper for running OpenFlow regression tests against Open vSwitch | |
| 6 | +# using veth | |
| 7 | +# Jean Tourrilhes - HP-Labs - copyright 2009-2010 | |
| 8 | +# $Id: of_regress_test.pl 105 2008-06-06 04:07:05Z brandonh $ | |
| 9 | +# | |
| 10 | +############################################################################## | |
| 11 | + | |
| 12 | +use OF::Base; | |
| 13 | +use Test::RegressTest; | |
| 14 | +use strict; | |
| 15 | +use OF::OFUtil; | |
| 16 | + | |
| 17 | +# check vars are set. | |
| 18 | +check_OF_vars_set(); | |
| 19 | + | |
| 20 | +sub INT_Handler { | |
| 21 | + my $signame = shift; | |
| 22 | + print "\nNo interrupt handler implemented yet...\n"; | |
| 23 | + print "\nExited with SIG$signame\n"; | |
| 24 | + exit(1); | |
| 25 | +} | |
| 26 | + | |
| 27 | +# For Open vSwitch | |
| 28 | + | |
| 29 | +# Open vSwitch starts at port 1 | |
| 30 | +# Get a bit of speedup by tweaking send_delay and base_idle | |
| 31 | +# Jean II | |
| 32 | +my $of_port = get_of_port(); | |
| 33 | +push @ARGV, "--root=$ENV{'OFT_ROOT'}", "--common-st-args=ovs_user", "--controller=tcp:localhost:$of_port,tcp:localhost:$of_port", "--listener=tcp:127.0.0.1:6634", "--port_base=1", "--send_delay=2000", "--base_idle=2", "--map=$ENV{'OFT_ROOT'}/bin/veth.map"; | |
| 34 | + | |
| 35 | +# Use a single random port instead of all four | |
| 36 | +push @ARGV, "--less_ports"; | |
| 37 | + | |
| 38 | +# Don't bother with QoS currently, it's broken... | |
| 39 | +push @ARGV, "--no_slicing"; | |
| 40 | + | |
| 41 | +# The bother with emergency flow table tests, it's not supported... | |
| 42 | +push @ARGV, "--no_emerg"; | |
| 43 | + | |
| 44 | +# Don't forget to configure the OVS_ROOT environment variable | |
| 45 | +# Jean II | |
| 46 | + | |
| 47 | +run_regress_test( \&INT_Handler, @ARGV ); | ... | ... |
regress/bin/of_ovs_veth_test.pl
0 → 100755
| 1 | +#!/usr/bin/perl -w | |
| 2 | + | |
| 3 | +############################################################################## | |
| 4 | +# | |
| 5 | +# Wrapper for running OpenFlow regression tests against Open vSwitch | |
| 6 | +# using veth | |
| 7 | +# Jean Tourrilhes - HP-Labs - copyright 2009-2010 | |
| 8 | +# $Id: of_regress_test.pl 105 2008-06-06 04:07:05Z brandonh $ | |
| 9 | +# | |
| 10 | +############################################################################## | |
| 11 | + | |
| 12 | +use OF::Base; | |
| 13 | +use Test::RegressTest; | |
| 14 | +use strict; | |
| 15 | +use OF::OFUtil; | |
| 16 | + | |
| 17 | +# check vars are set. | |
| 18 | +check_OF_vars_set(); | |
| 19 | + | |
| 20 | +sub INT_Handler { | |
| 21 | + my $signame = shift; | |
| 22 | + print "\nNo interrupt handler implemented yet...\n"; | |
| 23 | + print "\nExited with SIG$signame\n"; | |
| 24 | + exit(1); | |
| 25 | +} | |
| 26 | + | |
| 27 | +# For Open vSwitch | |
| 28 | + | |
| 29 | +# Open vSwitch starts at port 1 | |
| 30 | +# Get a bit of speedup by tweaking send_delay and base_idle | |
| 31 | +# Jean II | |
| 32 | +my $of_port = get_of_port(); | |
| 33 | +push @ARGV, "--root=$ENV{'OFT_ROOT'}", "--common-st-args=ovs", "--controller=tcp:localhost:$of_port,tcp:localhost:$of_port", "--listener=tcp:127.0.0.1:6634", "--port_base=1", "--send_delay=2000", "--base_idle=2", "--map=$ENV{'OFT_ROOT'}/bin/veth.map"; | |
| 34 | + | |
| 35 | +# Use a single random port instead of all four | |
| 36 | +push @ARGV, "--less_ports"; | |
| 37 | + | |
| 38 | +# Don't bother with QoS currently, it's broken... | |
| 39 | +push @ARGV, "--no_slicing"; | |
| 40 | + | |
| 41 | +# The bother with emergency flow table tests, it's not supported... | |
| 42 | +push @ARGV, "--no_emerg"; | |
| 43 | + | |
| 44 | +# Don't forget to configure the OVS_ROOT environment variable | |
| 45 | +# Jean II | |
| 46 | + | |
| 47 | +run_regress_test( \&INT_Handler, @ARGV ); | ... | ... |
regress/bin/of_user_setup.pl
0 → 100755
| 1 | +#!/usr/bin/perl -w | |
| 2 | + | |
| 3 | +use Getopt::Long; | |
| 4 | + | |
| 5 | +use OF::OFUtil; | |
| 6 | +use Test::TestLib; | |
| 7 | + | |
| 8 | +my ($mapFile, $controller); | |
| 9 | + | |
| 10 | +# Process command line options | |
| 11 | +unless ( GetOptions( "map=s" => \$mapFile, | |
| 12 | + "emerg" => \$emerg, | |
| 13 | + "controller=s", \$controller) ) { | |
| 14 | + print "unrecognized option\n"; | |
| 15 | + exit 1; | |
| 16 | +} | |
| 17 | + | |
| 18 | +if ( defined($mapFile) ) { | |
| 19 | + nftest_process_iface_map($mapFile); | |
| 20 | +} | |
| 21 | + | |
| 22 | +setup_user($controller, $emerg); | ... | ... |
regress/bin/of_user_teardown.pl
0 → 100755
| 1 | +#!/usr/bin/perl -w | |
| 2 | + | |
| 3 | +use Getopt::Long; | |
| 4 | + | |
| 5 | +use OF::OFUtil; | |
| 6 | +use Test::TestLib; | |
| 7 | + | |
| 8 | +my $mapFile; | |
| 9 | + | |
| 10 | +# Process command line options | |
| 11 | +unless ( GetOptions( "map=s" => \$mapFile, ) ) { | |
| 12 | + print "unrecognized option\n"; | |
| 13 | + exit 1; | |
| 14 | +} | |
| 15 | + | |
| 16 | +if ( defined($mapFile) ) { | |
| 17 | + nftest_process_iface_map($mapFile); | |
| 18 | +} | |
| 19 | + | |
| 20 | +teardown_user(); | ... | ... |
regress/bin/of_user_test.pl
0 → 100755
| 1 | +#!/usr/bin/perl -w | |
| 2 | + | |
| 3 | +############################################################################## | |
| 4 | +# | |
| 5 | +# Wrapper for OpenFlow regression tests | |
| 6 | +# $Id: of_regress_test.pl 105 2008-06-06 04:07:05Z brandonh $ | |
| 7 | +# | |
| 8 | +############################################################################## | |
| 9 | + | |
| 10 | +use OF::Base; | |
| 11 | +use Test::RegressTest; | |
| 12 | +use strict; | |
| 13 | +use OF::OFUtil; | |
| 14 | + | |
| 15 | +# check vars are set. | |
| 16 | +check_OF_vars_set(); | |
| 17 | + | |
| 18 | +sub INT_Handler { | |
| 19 | + my $signame = shift; | |
| 20 | + print "\nNo interrupt handler implemented yet...\n"; | |
| 21 | + print "\nExited with SIG$signame\n"; | |
| 22 | + exit(1); | |
| 23 | +} | |
| 24 | + | |
| 25 | +push (@ARGV, "--root=$ENV{'OFT_ROOT'}", "--map=$ENV{'OFT_ROOT'}/bin/eth.map", "--port_base=1", "--common-st-args=user"); | |
| 26 | + | |
| 27 | +run_regress_test( \&INT_Handler, @ARGV ); | ... | ... |
regress/bin/of_user_veth_setup.pl
0 → 100755
| 1 | +#!/usr/bin/perl -w | |
| 2 | + | |
| 3 | +use Getopt::Long; | |
| 4 | + | |
| 5 | +use OF::OFUtil; | |
| 6 | +use Test::TestLib; | |
| 7 | + | |
| 8 | +my ($mapFile, $controller); | |
| 9 | + | |
| 10 | +# Process command line options | |
| 11 | +unless ( GetOptions( "map=s" => \$mapFile, | |
| 12 | + "emerg" => \$emerg, | |
| 13 | + "controller=s", \$controller) ) { | |
| 14 | + print "unrecognized option\n"; | |
| 15 | + exit 1; | |
| 16 | +} | |
| 17 | + | |
| 18 | +if ( defined($mapFile) ) { | |
| 19 | + nftest_process_iface_map($mapFile); | |
| 20 | +} | |
| 21 | +#else, use pre-defined veth map | |
| 22 | +else { | |
| 23 | + nftest_process_iface_map("$ENV{'OFT_ROOT'}/bin/veth.map"); | |
| 24 | +} | |
| 25 | + | |
| 26 | +setup_user($controller, $emerg); | ... | ... |
regress/bin/of_user_veth_teardown.pl
0 → 100755
| 1 | +#!/usr/bin/perl -w | |
| 2 | + | |
| 3 | +use Getopt::Long; | |
| 4 | + | |
| 5 | +use OF::OFUtil; | |
| 6 | +use Test::TestLib; | |
| 7 | + | |
| 8 | +my $mapFile; | |
| 9 | + | |
| 10 | +# Process command line options | |
| 11 | +unless ( GetOptions( "map=s" => \$mapFile, ) ) { | |
| 12 | + print "unrecognized option\n"; | |
| 13 | + exit 1; | |
| 14 | +} | |
| 15 | + | |
| 16 | +if ( defined($mapFile) ) { | |
| 17 | + nftest_process_iface_map($mapFile); | |
| 18 | +} | |
| 19 | +#else, use pre-defined veth map | |
| 20 | +else { | |
| 21 | + nftest_process_iface_map("$ENV{'OFT_ROOT'}/bin/veth.map"); | |
| 22 | +} | |
| 23 | + | |
| 24 | +teardown_user(); | ... | ... |
regress/bin/of_user_veth_test.pl
0 → 100755
| 1 | +#!/usr/bin/perl -w | |
| 2 | + | |
| 3 | +############################################################################## | |
| 4 | +# | |
| 5 | +# Wrapper for OpenFlow regression tests | |
| 6 | +# $Id: of_regress_test.pl 105 2008-06-06 04:07:05Z brandonh $ | |
| 7 | +# | |
| 8 | +############################################################################## | |
| 9 | + | |
| 10 | +use OF::Base; | |
| 11 | +use Test::RegressTest; | |
| 12 | +use strict; | |
| 13 | +use OF::OFUtil; | |
| 14 | + | |
| 15 | +# check vars are set. | |
| 16 | +check_OF_vars_set(); | |
| 17 | + | |
| 18 | +sub INT_Handler { | |
| 19 | + my $signame = shift; | |
| 20 | + print "\nNo interrupt handler implemented yet...\n"; | |
| 21 | + print "\nExited with SIG$signame\n"; | |
| 22 | + exit(1); | |
| 23 | +} | |
| 24 | + | |
| 25 | +push( @ARGV, "--map=$ENV{'OFT_ROOT'}/bin/veth.map", "--root=$ENV{'OFT_ROOT'}", "--port_base=1", "--common-st-args=user_veth"); | |
| 26 | + | |
| 27 | +run_regress_test( \&INT_Handler, @ARGV ); | ... | ... |
regress/bin/veth.map
0 → 100755
regress/bin/veth_setup.pl
0 → 100755
regress/bin/veth_teardown.pl
0 → 100755
regress/lib/Perl5/OF/Base.pm
0 → 100755
| 1 | +############################################################# | |
| 2 | +# $Id: Base.pm 3161 2007-12-13 21:08:05Z grg $ | |
| 3 | +# | |
| 4 | +# Module provides basic functions for use by OF Perl scripts. | |
| 5 | +# | |
| 6 | +# Revisions: | |
| 7 | +# | |
| 8 | +############################################################## | |
| 9 | + | |
| 10 | +package OF::Base; | |
| 11 | + | |
| 12 | +use Exporter; | |
| 13 | +@ISA = ('Exporter'); | |
| 14 | +@EXPORT = qw( &check_OF_vars_set | |
| 15 | +); | |
| 16 | + | |
| 17 | +############################################################## | |
| 18 | +# | |
| 19 | +# Check that the user has set up their environment correctly. | |
| 20 | +# | |
| 21 | +############################################################## | |
| 22 | +sub check_OF_vars_set { | |
| 23 | + | |
| 24 | + my @of_vars = qw(OFT_ROOT OF_ROOT); | |
| 25 | + | |
| 26 | + for (@of_vars) { | |
| 27 | + my_die("Please set shell variable $_ and try again.") | |
| 28 | + unless defined $ENV{$_}; | |
| 29 | + } | |
| 30 | + | |
| 31 | +} | |
| 32 | + | |
| 33 | +############################################################## | |
| 34 | +# | |
| 35 | +# Define a my_die function if it doesn't already exist | |
| 36 | +# | |
| 37 | +############################################################## | |
| 38 | + | |
| 39 | +if ( !defined(&my_die) ) { | |
| 40 | + eval( ' | |
| 41 | + sub my_die { | |
| 42 | + my $mess = shift @_; | |
| 43 | + (my $cmd = $0) =~ s/.*\///; | |
| 44 | + print STDERR "\n$cmd: $mess\n"; | |
| 45 | + exit 1; | |
| 46 | + } | |
| 47 | + ' ); | |
| 48 | +} | |
| 49 | + | |
| 50 | +# Always end library in 1 | |
| 51 | +1; | ... | ... |
regress/lib/Perl5/OF/Includes.pm
0 → 100755
| 1 | +use Test::TestLib; | |
| 2 | +use Test::PacketLib; | |
| 3 | + | |
| 4 | +use OF::Base; | |
| 5 | +use OF::OFUtil; | |
| 6 | +use OF::OFPacketLib; | |
| 7 | + | |
| 8 | +use IO::Socket; | |
| 9 | + | |
| 10 | +use Data::HexDump; | |
| 11 | + | |
| 12 | +use Data::Dumper; | |
| 13 | + | |
| 14 | +use Time::HiRes qw(sleep gettimeofday tv_interval usleep); | |
| 15 | + | |
| 16 | +1; | |
| 0 | 17 | \ No newline at end of file | ... | ... |
regress/lib/Perl5/OF/OFPacketLib.pm
0 → 100755
| 1 | +#################################### | |
| 2 | +# vim:set shiftwidth=2 softtabstop=2 expandtab: | |
| 3 | +# | |
| 4 | +# $Id: PacketLib.pm 3074 2007-12-06 03:01:04Z grg $ | |
| 5 | +# | |
| 6 | +# This provides functions for manipulating packets. | |
| 7 | +# | |
| 8 | +# The goal is to provide functions that make it easy to create and | |
| 9 | +# manipulate packets, so that we can avoid stupid errors. | |
| 10 | +# | |
| 11 | +##################################### | |
| 12 | + | |
| 13 | +package OF::OFPacketLib; | |
| 14 | + | |
| 15 | +use strict; | |
| 16 | + | |
| 17 | +use Convert::Binary::C; | |
| 18 | +use Data::Dumper; | |
| 19 | +use Data::HexDump; | |
| 20 | +use OF::Base; | |
| 21 | + | |
| 22 | +use Exporter; | |
| 23 | +use vars qw(@ISA @EXPORT); # needed cos strict is on | |
| 24 | +@ISA = qw(Exporter); | |
| 25 | +@EXPORT = qw($ofp %enums); | |
| 26 | + | |
| 27 | +our $ofp = Convert::Binary::C->new; | |
| 28 | + | |
| 29 | +# Convert::Binary::C config generated with `ccconfig` | |
| 30 | +# should run this during make to customize to a machine | |
| 31 | +my %config = ( | |
| 32 | + 'Alignment' => 4, | |
| 33 | + 'Assert' => [ | |
| 34 | + 'cpu(i386)', | |
| 35 | + 'machine(i386)', | |
| 36 | + 'system(linux)', | |
| 37 | + 'system(posix)', | |
| 38 | + 'system(unix)' | |
| 39 | + ], | |
| 40 | + 'ByteOrder' => 'LittleEndian', | |
| 41 | + 'CharSize' => 1, | |
| 42 | + 'CompoundAlignment' => 1, | |
| 43 | + 'Define' => [ | |
| 44 | + '__CHAR_BIT__=8', | |
| 45 | + '__DBL_DIG__=15', | |
| 46 | + '__DBL_EPSILON__=2.2204460492503131e-16', | |
| 47 | + '__DBL_MANT_DIG__=53', | |
| 48 | + '__DBL_MAX_10_EXP__=308', | |
| 49 | + '__DBL_MAX_EXP__=1024', | |
| 50 | + '__DBL_MAX__=1.7976931348623157e+308', | |
| 51 | + '__DBL_MIN_10_EXP__=(-307)', | |
| 52 | + '__DBL_MIN_EXP__=(-1021)', | |
| 53 | + '__DBL_MIN__=2.2250738585072014e-308', | |
| 54 | + '__DECIMAL_DIG__=21', | |
| 55 | + '__ELF__=1', | |
| 56 | + '__FLT_DIG__=6', | |
| 57 | + '__FLT_EPSILON__=1.19209290e-7F', | |
| 58 | + '__FLT_EVAL_METHOD__=2', | |
| 59 | + '__FLT_MANT_DIG__=24', | |
| 60 | + '__FLT_MAX_10_EXP__=38', | |
| 61 | + '__FLT_MAX_EXP__=128', | |
| 62 | + '__FLT_MAX__=3.40282347e+38F', | |
| 63 | + '__FLT_MIN_10_EXP__=(-37)', | |
| 64 | + '__FLT_MIN_EXP__=(-125)', | |
| 65 | + '__FLT_MIN__=1.17549435e-38F', | |
| 66 | + '__FLT_RADIX__=2', | |
| 67 | + '__GNUC_MINOR__=1', | |
| 68 | + '__GNUC_PATCHLEVEL__=2', | |
| 69 | + '__GNUC_RH_RELEASE__=14', | |
| 70 | + '__GNUC__=4', | |
| 71 | + '__INT_MAX__=2147483647', | |
| 72 | + '__LDBL_DIG__=18', | |
| 73 | + '__LDBL_EPSILON__=1.08420217248550443401e-19L', | |
| 74 | + '__LDBL_MANT_DIG__=64', | |
| 75 | + '__LDBL_MAX_10_EXP__=4932', | |
| 76 | + '__LDBL_MAX_EXP__=16384', | |
| 77 | + '__LDBL_MAX__=1.18973149535723176502e+4932L', | |
| 78 | + '__LDBL_MIN_10_EXP__=(-4931)', | |
| 79 | + '__LDBL_MIN_EXP__=(-16381)', | |
| 80 | + '__LDBL_MIN__=3.36210314311209350626e-4932L', | |
| 81 | + '__LONG_LONG_MAX__=9223372036854775807LL', | |
| 82 | + '__LONG_MAX__=2147483647L', | |
| 83 | + '__NO_INLINE__=1', | |
| 84 | + '__PTRDIFF_TYPE__=int', | |
| 85 | + '__SCHAR_MAX__=127', | |
| 86 | + '__SHRT_MAX__=32767', | |
| 87 | + '__SIZE_TYPE__=unsigned int', | |
| 88 | + '__USER_LABEL_PREFIX__=', | |
| 89 | + '__WCHAR_TYPE__=long int', | |
| 90 | + '__WINT_TYPE__=unsigned int', | |
| 91 | + '__attribute__(x)=', | |
| 92 | + '__builtin_va_list=int', | |
| 93 | + '__gnu_linux__=1', | |
| 94 | + '__i386=1', | |
| 95 | + '__i386__=1', | |
| 96 | + '__linux=1', | |
| 97 | + '__linux__=1', | |
| 98 | + '__unix=1', | |
| 99 | + '__unix__=1', | |
| 100 | + 'i386=1', | |
| 101 | + 'linux=1', | |
| 102 | + 'unix=1' | |
| 103 | + ], | |
| 104 | + 'DisabledKeywords' => [ | |
| 105 | + 'restrict' | |
| 106 | + ], | |
| 107 | + 'DoubleSize' => 8, | |
| 108 | + 'EnumSize' => 4, | |
| 109 | + 'FloatSize' => 4, | |
| 110 | + 'HasCPPComments' => 1, | |
| 111 | + 'Include' => [ | |
| 112 | + '/usr/lib/gcc/i386-redhat-linux/4.1.2/include', | |
| 113 | + '/usr/include' | |
| 114 | + ], | |
| 115 | + 'IntSize' => 4, | |
| 116 | + 'KeywordMap' => { | |
| 117 | + '__asm' => 'asm', | |
| 118 | + '__asm__' => 'asm', | |
| 119 | + '__complex' => undef, | |
| 120 | + '__complex__' => undef, | |
| 121 | + '__const' => 'const', | |
| 122 | + '__const__' => 'const', | |
| 123 | + '__extension__' => undef, | |
| 124 | + '__imag' => undef, | |
| 125 | + '__imag__' => undef, | |
| 126 | + '__inline' => 'inline', | |
| 127 | + '__inline__' => 'inline', | |
| 128 | + '__real' => undef, | |
| 129 | + '__real__' => undef, | |
| 130 | + '__restrict' => 'restrict', | |
| 131 | + '__restrict__' => 'restrict', | |
| 132 | + '__signed' => 'signed', | |
| 133 | + '__signed__' => 'signed', | |
| 134 | + '__volatile' => 'volatile', | |
| 135 | + '__volatile__' => 'volatile' | |
| 136 | + }, | |
| 137 | + 'LongDoubleSize' => 12, | |
| 138 | + 'LongLongSize' => 8, | |
| 139 | + 'LongSize' => 4, | |
| 140 | + 'PointerSize' => 4, | |
| 141 | + 'ShortSize' => 2, | |
| 142 | + 'UnsignedChars' => 0 | |
| 143 | + ); | |
| 144 | + | |
| 145 | + | |
| 146 | +#!!! | |
| 147 | +$ofp->configure(%config); | |
| 148 | + | |
| 149 | +#$ofp->configure('Include' => ['/usr/include']); | |
| 150 | + | |
| 151 | +# set to big endian for network order, regardless of machine endianness | |
| 152 | +$ofp->configure(ByteOrder => 'BigEndian'); | |
| 153 | + | |
| 154 | +# ensure environment variables set before reading C file | |
| 155 | +check_OF_vars_set(); | |
| 156 | + | |
| 157 | +# load C structs and enums | |
| 158 | +my $of_file = $ENV{'OF_ROOT'}.'/include/openflow/openflow.h'; | |
| 159 | +#print "$of_file\n"; | |
| 160 | + | |
| 161 | +eval { $ofp->parse_file($of_file) }; | |
| 162 | +if ($@) { die "error in parse_file $@\n"; } | |
| 163 | + | |
| 164 | +#!!! | |
| 165 | +#print $ofp->sizeof('ofp_action') . "\n"; | |
| 166 | +#print $ofp->sizeof('ofp_packet_in') . "\n"; | |
| 167 | +#print $ofp->sizeof('ofp_flow_mod') . "\n"; | |
| 168 | +#print $ofp->offsetof('ofp_action', 'arg.output') . "\n"; | |
| 169 | +#exit 1; | |
| 170 | + | |
| 171 | +my @enum_list = $ofp->enum; | |
| 172 | +our %enums; # "global" enum hash | |
| 173 | +#print Dumper(@enum_list); | |
| 174 | +foreach my $enum_hash_ref (@enum_list) { | |
| 175 | + my %enum_hash = %{$enum_hash_ref->{'enumerators'}}; | |
| 176 | + while( my($key, $val) = each(%enum_hash) ) { | |
| 177 | + $enums{$key} = $val; | |
| 178 | + } | |
| 179 | +} | |
| 180 | + | |
| 181 | +1; | |
| 182 | + | |
| 183 | +__END__ | ... | ... |
regress/lib/Perl5/OF/OFUtil.pm
0 → 100755
| 1 | +############################################################# | |
| 2 | +# $Id: OFUtil.pm 3161 2007-12-13 21:08:05Z bdh $ | |
| 3 | +# | |
| 4 | +# Module provides basic functions for use by OF Perl scripts. | |
| 5 | +# | |
| 6 | +# Revisions: | |
| 7 | +# | |
| 8 | +############################################################## | |
| 9 | + | |
| 10 | +package OF::OFUtil; | |
| 11 | + | |
| 12 | +use Getopt::Long; | |
| 13 | +use Test::TestLib; | |
| 14 | +use Error qw(:try); | |
| 15 | +use OF::OFPacketLib; | |
| 16 | +use Test::PacketLib; | |
| 17 | +use Exporter; | |
| 18 | +use Data::Dumper; | |
| 19 | +use Socket qw(:all); | |
| 20 | +use IO::Socket; | |
| 21 | +#use IO::Socket::INET; | |
| 22 | +use Data::HexDump; | |
| 23 | +use Time::HiRes qw(sleep gettimeofday tv_interval usleep); | |
| 24 | + | |
| 25 | +@ISA = ('Exporter'); | |
| 26 | +@EXPORT = qw( | |
| 27 | + &trim | |
| 28 | + &send_and_count | |
| 29 | + &expect_and_count | |
| 30 | + &save_counters | |
| 31 | + &verify_counters | |
| 32 | + &setup_pcap_interfaces | |
| 33 | + &setup_kmod | |
| 34 | + &setup_user | |
| 35 | + &setup_NF2 | |
| 36 | + &teardown_kmod | |
| 37 | + &teardown_user | |
| 38 | + &teardown_NF2 | |
| 39 | + &compare | |
| 40 | + &create_controller_socket | |
| 41 | + &run_learning_switch_test | |
| 42 | + &do_hello_sequence | |
| 43 | + &enter_barrier | |
| 44 | + &wait_for_barrier_exit | |
| 45 | + &send_get_config_request | |
| 46 | + &wait_for_get_config_reply | |
| 47 | + &get_switch_features | |
| 48 | + &get_config | |
| 49 | + &set_config | |
| 50 | + &run_black_box_test | |
| 51 | + &create_flow_mod_from_udp | |
| 52 | + &create_flow_mod_from_udp_actionbytes | |
| 53 | + &create_flow_mod_from_udp_action | |
| 54 | + &wait_for_flow_expired | |
| 55 | + &wait_for_flow_expired_all | |
| 56 | + &wait_for_flow_expired_readone | |
| 57 | + &wait_for_flow_expired_readsize | |
| 58 | + &wait_for_flow_expired_total_bytes | |
| 59 | + &wait_for_one_packet_in | |
| 60 | + &verify_header | |
| 61 | + &get_of_ver | |
| 62 | + &get_of_port | |
| 63 | + &get_of_miss_send_len_default | |
| 64 | + &get_default_black_box_pkt | |
| 65 | + &get_default_black_box_pkt_len | |
| 66 | + &for_all_port_pairs | |
| 67 | + &for_all_ports | |
| 68 | + &for_all_wildcards | |
| 69 | + &for_all_port_triplets | |
| 70 | + &forward_simple | |
| 71 | + &flow_mod_length | |
| 72 | + &combine_args | |
| 73 | + &get_original_value | |
| 74 | + &generate_expect_packet | |
| 75 | + &replace_sending_pkt | |
| 76 | + &create_vlan_pkt | |
| 77 | + &forward_simple_icmp | |
| 78 | + &get_default_black_box_pkt_len_icmp | |
| 79 | + &create_flow_mod_from_icmp_action | |
| 80 | + &create_flow_mod_from_icmp | |
| 81 | + &forward_simple_arp | |
| 82 | + &get_default_black_box_pkt_len_arp | |
| 83 | + &create_flow_mod_from_arp_action | |
| 84 | + &create_flow_mod_from_arp | |
| 85 | + &wait_for_two_flow_expired | |
| 86 | + &get_dpinst | |
| 87 | + &wait_for_echo_request | |
| 88 | + &dpctl_del_flows | |
| 89 | + &dpctl_show_flows | |
| 90 | +); | |
| 91 | + | |
| 92 | +my $nf2_kernel_module_path = 'datapath/linux-2.6'; | |
| 93 | +my $nf2_kernel_module_name_no_ext = 'ofdatapath_netfpga'; | |
| 94 | +my $nf2_kernel_module_name = $nf2_kernel_module_name_no_ext . '.ko'; | |
| 95 | +my $openflow_dir = $ENV{OF_ROOT}; | |
| 96 | + | |
| 97 | +if (! -e "$openflow_dir/include/openflow/openflow.h") { | |
| 98 | + die "please set OF_ROOT in path so that OFUtil.pm can extract constants" | |
| 99 | +} | |
| 100 | + | |
| 101 | +sub get_define { | |
| 102 | + my $val = shift; | |
| 103 | + my $retval = `grep \"#define $val \" \$OF_ROOT/include/openflow/openflow.h | awk '{print \$3}'`; | |
| 104 | + chomp $retval; | |
| 105 | + return $retval; | |
| 106 | +} | |
| 107 | + | |
| 108 | +# extract #defines from openflow.h | |
| 109 | +my $of_ver = get_define('OFP_VERSION'); | |
| 110 | +my $of_port = get_define('OFP_TCP_PORT'); | |
| 111 | +my $of_miss_send_len = get_define('OFP_DEFAULT_MISS_SEND_LEN'); | |
| 112 | + | |
| 113 | +# sending/receiving interfaces - NOT OpenFlow ones | |
| 114 | +my @interfaces = ( "eth1", "eth2", "eth3", "eth4" ); | |
| 115 | + | |
| 116 | +############################################################## | |
| 117 | + | |
| 118 | +sub trim($) { | |
| 119 | + my $string = shift; | |
| 120 | + $string =~ s/^\s+//; | |
| 121 | + $string =~ s/\s+$//; | |
| 122 | + return $string; | |
| 123 | +} | |
| 124 | + | |
| 125 | +sub get_if_rx { | |
| 126 | + my $interface = shift; | |
| 127 | + return | |
| 128 | +`/sbin/ifconfig $interface | grep \'RX packets:\' | awk \'{print \$2}\' | awk -F : \'{print \$2}\'`; | |
| 129 | +} | |
| 130 | + | |
| 131 | +sub get_if_tx { | |
| 132 | + my $interface = shift; | |
| 133 | + return | |
| 134 | +`/sbin/ifconfig $interface | grep \'TX packets:\' | awk \'{print \$2}\' | awk -F : \'{print \$2}\'`; | |
| 135 | +} | |
| 136 | + | |
| 137 | +sub send_and_count { | |
| 138 | + my ( $interface, $pkt, $counters ) = @_; | |
| 139 | + nftest_send( $interface, $pkt ); | |
| 140 | + $$counters{$interface}{tx_pkts}++; | |
| 141 | +} | |
| 142 | + | |
| 143 | +sub expect_and_count { | |
| 144 | + my ( $interface, $pkt, $counters ) = @_; | |
| 145 | + nftest_expect( $interface, $pkt ); | |
| 146 | + $$counters{$interface}{rx_pkts}++; | |
| 147 | +} | |
| 148 | + | |
| 149 | +sub save_counters { | |
| 150 | + my $counters = @_; | |
| 151 | + foreach my $i ( keys %counters ) { | |
| 152 | + $$counters{$i}{rx_pkts} = get_if_rx($i); | |
| 153 | + $$counters{$i}{tx_pkts} = get_if_tx($i); | |
| 154 | + } | |
| 155 | +} | |
| 156 | + | |
| 157 | +sub verify_counters { | |
| 158 | + my ( %c1, %c2, %delta ); | |
| 159 | + my $errors = 0; | |
| 160 | + foreach my $i ( keys %c1 ) { | |
| 161 | + if ( $c1{$i}{rx_pkts} + $delta{$i}{rx_pkts} != $c2{$i}{rx_pkts} ) { | |
| 162 | + $errors++; | |
| 163 | + print "rx_pkts comparison failed for interface $i, please fix\n"; | |
| 164 | + } | |
| 165 | + if ( $c1{$i}{tx_pkts} + $delta{$i}{tx_pkts} != $c2{$i}{tx_pkts} ) { | |
| 166 | + $errors++; | |
| 167 | + print "tx_init + tx_pkts != tx_final for interface $i, please fix\n"; | |
| 168 | + } | |
| 169 | + } | |
| 170 | + return $errors; | |
| 171 | +} | |
| 172 | + | |
| 173 | +sub setup_pcap_interfaces { | |
| 174 | + | |
| 175 | + # ensure all interfaces use an address | |
| 176 | + for ( my $i = 1 ; $i <= 4 ; $i++ ) { | |
| 177 | + my $iface = nftest_get_iface("eth$i"); | |
| 178 | + `/sbin/ifconfig $iface 192.168.10$i.1`; | |
| 179 | + } | |
| 180 | +} | |
| 181 | + | |
| 182 | +sub start_ofprotocol { | |
| 183 | + | |
| 184 | + my ( $dpinst, $controller, $emerg ) = @_; | |
| 185 | + if ( !$controller) { $controller = nftest_default_controllers(); } | |
| 186 | + my $cmd; | |
| 187 | + if (defined $emerg) { | |
| 188 | + $cmd = "${openflow_dir}/secchan/ofprotocol $dpinst $controller --emerg-flow --inactivity-probe=10 &"; | |
| 189 | + } else { | |
| 190 | + $cmd = "${openflow_dir}/secchan/ofprotocol $dpinst $controller --inactivity-probe=999999 &"; | |
| 191 | + } | |
| 192 | + print "about to run $cmd\n"; | |
| 193 | + system($cmd); | |
| 194 | +} | |
| 195 | + | |
| 196 | +sub setup_kmod { | |
| 197 | + | |
| 198 | + setup_pcap_interfaces(); | |
| 199 | + | |
| 200 | + # verify kernel module not loaded | |
| 201 | + my $of_kmod_loaded = `lsmod | grep ofdatapath`; | |
| 202 | + if ( $of_kmod_loaded ne "" ) { | |
| 203 | + print "openflow kernel module already loaded... please fix!\n"; | |
| 204 | + exit 1; | |
| 205 | + } | |
| 206 | + | |
| 207 | + # verify controller not already running | |
| 208 | + my $controller_loaded = `ps -A | grep controller`; | |
| 209 | + if ( $controller_loaded ne "" ) { | |
| 210 | + print "controller already loaded... please remove and try again!\n"; | |
| 211 | + exit 1; | |
| 212 | + } | |
| 213 | + | |
| 214 | + my $openflow_dir = $ENV{'OF_ROOT'}; | |
| 215 | + | |
| 216 | + # create openflow switch on four ports | |
| 217 | + `insmod ${openflow_dir}/datapath/linux-2.6/ofdatapath.ko`; | |
| 218 | + | |
| 219 | + `${openflow_dir}/utilities/dpctl adddp nl:0`; | |
| 220 | + | |
| 221 | + for ( my $i = 5 ; $i <= 8 ; $i++ ) { | |
| 222 | + my $iface = nftest_get_iface("eth$i"); | |
| 223 | + `${openflow_dir}/utilities/dpctl addif nl:0 $iface`; | |
| 224 | + } | |
| 225 | + | |
| 226 | + start_ofprotocol("nl:0", @_); | |
| 227 | +} | |
| 228 | + | |
| 229 | +sub setup_NF2 { | |
| 230 | + | |
| 231 | + setup_pcap_interfaces(); | |
| 232 | + | |
| 233 | + # load the openflow bitfile on the NetFPGA | |
| 234 | + system("nf2_download ${openflow_dir}/hw-lib/nf2/openflow_switch.bit"); | |
| 235 | + sleep(2); | |
| 236 | + | |
| 237 | + # turn on phy(0-3) interrupt mask | |
| 238 | + # in order to avoid asynchronous port_mod_change message | |
| 239 | + `regwrite 0x04c006c 0xffff`; | |
| 240 | + `regwrite 0x04c00ec 0xffff`; | |
| 241 | + `regwrite 0x04c016c 0xffff`; | |
| 242 | + `regwrite 0x04c01ec 0xffff`; | |
| 243 | + | |
| 244 | + # create openflow switch on four ports | |
| 245 | + my $if_string = ''; | |
| 246 | + for (my $i = 5 ; $i <= 7 ; $i++) { | |
| 247 | + $if_string .= nftest_get_iface("eth$i") . ','; | |
| 248 | + } | |
| 249 | + $if_string .= nftest_get_iface("eth8"); | |
| 250 | + | |
| 251 | + print "about to create ofdatapath` punix:/var/run/test -i $if_string \& \n"; | |
| 252 | + system("${openflow_dir}/udatapath/ofdatapath punix:/var/run/test -i $if_string \&"); | |
| 253 | + | |
| 254 | + sleep(1); | |
| 255 | + | |
| 256 | + start_ofprotocol("unix:/var/run/test", @_); | |
| 257 | +} | |
| 258 | + | |
| 259 | + | |
| 260 | +sub setup_user { | |
| 261 | + setup_pcap_interfaces(); | |
| 262 | + | |
| 263 | + # create openflow switch on four ports | |
| 264 | + my $if_string = ''; | |
| 265 | + for (my $i = 5 ; $i <= 7 ; $i++) { | |
| 266 | + $if_string .= nftest_get_iface("eth$i") . ','; | |
| 267 | + } | |
| 268 | + $if_string .= nftest_get_iface("eth8"); | |
| 269 | + | |
| 270 | + print "about to create ofdatapath` punix:/var/run/test -i $if_string \& \n"; | |
| 271 | + system("${openflow_dir}/udatapath/ofdatapath punix:/var/run/test -i $if_string \&"); | |
| 272 | + | |
| 273 | + start_ofprotocol("unix:/var/run/test", @_); | |
| 274 | + | |
| 275 | + #create a queue in each port | |
| 276 | + for ($i = 1;$i <= 4; $i++) { | |
| 277 | + system("${openflow_dir}/utilities/dpctl add-queue unix:/var/run/test $i 1 10"); | |
| 278 | + } | |
| 279 | + | |
| 280 | + | |
| 281 | +} | |
| 282 | + | |
| 283 | +sub teardown_kmod { | |
| 284 | + | |
| 285 | + # check that we're root? | |
| 286 | + my $who = `whoami`; | |
| 287 | + if ( trim($who) ne 'root' ) { die "must be root\n"; } | |
| 288 | + | |
| 289 | + `killall ofprotocol`; | |
| 290 | + | |
| 291 | + # check if openflow kernel module loaded | |
| 292 | + my $of_kmod_loaded = `lsmod | grep ofdatapath`; | |
| 293 | + if ( $of_kmod_loaded eq "" ) { exit 0; } | |
| 294 | + | |
| 295 | + print "tearing down interfaces and datapaths\n"; | |
| 296 | + | |
| 297 | + # remove interfaces from openflow | |
| 298 | + for ( my $i = 5 ; $i <= 8 ; $i++ ) { | |
| 299 | + my $iface = nftest_get_iface("eth$i"); | |
| 300 | + `${openflow_dir}/utilities/dpctl delif nl:0 $iface`; | |
| 301 | + } | |
| 302 | + | |
| 303 | + `${openflow_dir}/utilities/dpctl deldp nl:0`; | |
| 304 | + | |
| 305 | + my $of_kmod_removed = `rmmod ofdatapath`; | |
| 306 | + if ( $of_kmod_removed ne "" ) { | |
| 307 | + die "failed to remove kernel module... please fix!\n"; | |
| 308 | + } | |
| 309 | + | |
| 310 | + $of_kmod_loaded = `lsmod | grep ofdatapath`; | |
| 311 | + if ( $of_kmod_loaded ne "" ) { | |
| 312 | + die "failed to remove kernel module... please fix!\n"; | |
| 313 | + } | |
| 314 | + | |
| 315 | + exit 0; | |
| 316 | +} | |
| 317 | + | |
| 318 | +sub teardown_NF2 { | |
| 319 | + teardown_user(); | |
| 320 | +} | |
| 321 | + | |
| 322 | +sub teardown_user { | |
| 323 | + | |
| 324 | + # check that we're root? | |
| 325 | + my $who = `whoami`; | |
| 326 | + if ( trim($who) ne 'root' ) { die "must be root\n"; } | |
| 327 | + | |
| 328 | + `killall ofdatapath`; | |
| 329 | + `killall ofprotocol`; | |
| 330 | + | |
| 331 | + exit 0; | |
| 332 | +} | |
| 333 | + | |
| 334 | +sub compare { | |
| 335 | + my ( $test, $val, $op, $expected ) = @_; | |
| 336 | + my $success = eval "$val $op $expected" ? 1 : 0; | |
| 337 | + if ( !$success ) { die "$test: error $val not $op $expected\n"; } | |
| 338 | +} | |
| 339 | + | |
| 340 | +sub create_controller_socket { | |
| 341 | + my ($host, $port) = @_; | |
| 342 | + print "about to make socket: tcp:$host:$port\n"; | |
| 343 | + my $sock = new IO::Socket::INET( | |
| 344 | + LocalHost => $host, | |
| 345 | + LocalPort => $port, | |
| 346 | + Proto => 'tcp', | |
| 347 | + Listen => 1, | |
| 348 | + Reuse => 1 | |
| 349 | + ); | |
| 350 | + die "Could not create socket: $!\n" unless $sock; | |
| 351 | + # Don't hold to data - Jean II | |
| 352 | + # This does NOT work, as it apply only to SOL_SOCKET | |
| 353 | + $sock->sockopt(TCP_NODELAY, 1) or die "\$sock->sockopt NODELAY, 1: $! ($^E)"; | |
| 354 | + # This works properly - Jean II | |
| 355 | + setsockopt($sock, IPPROTO_TCP, TCP_NODELAY, pack("l", 1)) or die "\$sock->sockopt NODELAY, 1: $! ($^E)"; | |
| 356 | + $sock->autoflush(); | |
| 357 | + # It also tried $| = 1; before the print but it did not help - Jean II | |
| 358 | + print "made socket\n"; | |
| 359 | + return $sock; | |
| 360 | +} | |
| 361 | + | |
| 362 | +# This does not look like it's used ? - Jean II | |
| 363 | +sub process_command_line() { | |
| 364 | + my %options = (); | |
| 365 | + | |
| 366 | + GetOptions( \%options, "map=s" ); | |
| 367 | + | |
| 368 | + # Process the mappings if specified | |
| 369 | + if ( defined( $options{'map'} ) ) { | |
| 370 | + nftest_process_iface_map( $options{'map'} ); | |
| 371 | + } else { | |
| 372 | + # If not specified on command line, use enviroment variable | |
| 373 | + # Jean II | |
| 374 | + if (defined($ENV{'OFT_MAP_ETH'})) { | |
| 375 | + nftest_process_iface_map( $ENV{OFT_MAP_ETH} ); | |
| 376 | + } | |
| 377 | + } | |
| 378 | + | |
| 379 | + return %options; | |
| 380 | +} | |
| 381 | + | |
| 382 | +sub run_learning_switch_test { | |
| 383 | + | |
| 384 | + # test is a function pointer | |
| 385 | + my ( $test_ref, $argv_ref) = @_; | |
| 386 | + | |
| 387 | + my %options = nftest_init( $argv_ref, \@interfaces, ); | |
| 388 | + | |
| 389 | + my ( %init_counters, %final_counters, %delta ); | |
| 390 | + | |
| 391 | + my $pid; | |
| 392 | + | |
| 393 | + # Fork off a process for controller | |
| 394 | + if ( !( $pid = fork ) ) { | |
| 395 | + | |
| 396 | + # extract host and port from controller string if passed in | |
| 397 | + if (defined $options{'controller'}) { | |
| 398 | + # Assume fully qualified string : | |
| 399 | + # tcp:<controller>:<port> | |
| 400 | + # Jean II | |
| 401 | + ($controller, $failover) = split(/,/,$options{'controller'}); | |
| 402 | + ($proto, $host, $port) = split(/:/,$controller); | |
| 403 | + # Check for string missing the protocol - Jean II | |
| 404 | + if ( ! defined ($port) ) { | |
| 405 | + die "Invalid controller string $options{'controller'}" | |
| 406 | + } | |
| 407 | + #!!! | |
| 408 | + print "Controller : using protocol $proto and port $port\n"; | |
| 409 | + } | |
| 410 | + # Run controller from this process | |
| 411 | + if ( ! defined ($port) ) { | |
| 412 | + exec "$ENV{'OF_ROOT'}/controller/controller", "ptcp:"; | |
| 413 | + } else { | |
| 414 | + exec "$ENV{'OF_ROOT'}/controller/controller", "p$proto:$port"; | |
| 415 | + } | |
| 416 | + die "Failed to launch controller: $!"; | |
| 417 | + } | |
| 418 | + else { | |
| 419 | + my $exitCode = 1; | |
| 420 | + try { | |
| 421 | + | |
| 422 | + # Run control from this process | |
| 423 | + print "added controller...\n"; | |
| 424 | + | |
| 425 | + # Wait for controller to load | |
| 426 | + sleep(1); | |
| 427 | + | |
| 428 | + nftest_start( \@interfaces, ); | |
| 429 | + | |
| 430 | + save_counters( \%init_counters ); | |
| 431 | + | |
| 432 | + # Run test | |
| 433 | + my %delta = &$test_ref(); | |
| 434 | + | |
| 435 | + # sleep as long as needed for the test to finish | |
| 436 | + sleep 5; | |
| 437 | + | |
| 438 | + # check counter values | |
| 439 | + save_counters( \%final_counters ); | |
| 440 | + my $total_errors = verify_counters( %init_counters, %final_counters, %delta ); | |
| 441 | + | |
| 442 | + #print "about to nftest_finish()\n"; | |
| 443 | + my $unmatched = nftest_finish(); | |
| 444 | + | |
| 445 | + print "Checking pkt errors\n"; | |
| 446 | + $total_errors += nftest_print_errors($unmatched); | |
| 447 | + | |
| 448 | + if ( $total_errors == 0 ) { | |
| 449 | + print "SUCCESS!\n"; | |
| 450 | + $exitCode = 0; | |
| 451 | + } | |
| 452 | + else { | |
| 453 | + print "FAIL: $total_errors errors\n"; | |
| 454 | + $exitCode = 1; | |
| 455 | + } | |
| 456 | + | |
| 457 | + } | |
| 458 | + catch Error with { | |
| 459 | + | |
| 460 | + # Catch and print any errors that occurred during control processing | |
| 461 | + my $ex = shift; | |
| 462 | + if ($ex) { | |
| 463 | + print $ex->stringify(); | |
| 464 | + } | |
| 465 | + } | |
| 466 | + finally { | |
| 467 | + | |
| 468 | + # Ensure controller killed even if we have an error | |
| 469 | + kill 9, $pid; | |
| 470 | + | |
| 471 | + # Exit with the resulting exit code | |
| 472 | + exit($exitCode); | |
| 473 | + }; | |
| 474 | + } | |
| 475 | +} | |
| 476 | + | |
| 477 | +sub do_hello_sequence { | |
| 478 | + | |
| 479 | + my ( $ofp, $sock ) = @_; | |
| 480 | + | |
| 481 | + my $hdr_args_hello = { | |
| 482 | + version => $of_ver, | |
| 483 | + type => $enums{'OFPT_HELLO'}, | |
| 484 | + length => $ofp->sizeof('ofp_header'), | |
| 485 | + xid => 0 | |
| 486 | + }; | |
| 487 | + my $hello = $ofp->pack( 'ofp_header', $hdr_args_hello); | |
| 488 | + | |
| 489 | + # Send 'hello' message | |
| 490 | + syswrite( $sock, $hello ); | |
| 491 | + | |
| 492 | + # Should add timeout here - will crash if no reply | |
| 493 | + my $recvd_mesg; | |
| 494 | + sysread( $sock, $recvd_mesg, 1512 ) || die "Failed to receive message: $!"; | |
| 495 | + | |
| 496 | + #print "received message after features request\n"; | |
| 497 | + | |
| 498 | + # Inspect message | |
| 499 | + my $msg_size = length($recvd_mesg); | |
| 500 | + my $expected_size = $ofp->sizeof('ofp_header'); | |
| 501 | +# my $expected_size = $ofp->sizeof('ofp_switch_features') + 4 * $ofp->sizeof('ofp_phy_port'); | |
| 502 | + | |
| 503 | + # should probably account for the expected 4 ports' info | |
| 504 | + # !!! disabled until we can inspect these | |
| 505 | + #compare( "msg size", length($recvd_mesg), '==', $expected_size ); | |
| 506 | + | |
| 507 | + #my $msg = $ofp->unpack( 'ofp_switch_features', $recvd_mesg ); | |
| 508 | + my $msg = $ofp->unpack( 'ofp_hello', $recvd_mesg ); | |
| 509 | + | |
| 510 | + #print HexDump ($recvd_mesg); | |
| 511 | + #print Dumper($msg); | |
| 512 | + | |
| 513 | + # Verify fields | |
| 514 | + verify_header( $msg, 'OFPT_HELLO', $msg_size ); | |
| 515 | + | |
| 516 | + print "received Hello\n"; | |
| 517 | +} | |
| 518 | + | |
| 519 | +sub enter_barrier { | |
| 520 | + my ($ofp, $sock, $xid) = @_; | |
| 521 | + | |
| 522 | + my $hdr_args = { | |
| 523 | + version => $of_ver, | |
| 524 | + type => $enums{'OFPT_BARRIER_REQUEST'}, | |
| 525 | + length => $ofp->sizeof('ofp_header'), | |
| 526 | + xid => $xid | |
| 527 | + }; | |
| 528 | + my $request = $ofp->pack('ofp_header', $hdr_args); | |
| 529 | + | |
| 530 | + syswrite($sock, $request); | |
| 531 | + | |
| 532 | + print "Sent barrier request, xid:$xid\n"; | |
| 533 | +} | |
| 534 | + | |
| 535 | +sub wait_for_barrier_exit { | |
| 536 | + my ($ofp, $sock, $xid) = @_; | |
| 537 | + | |
| 538 | + my $rcvd_msg; | |
| 539 | + | |
| 540 | + print "Receiving barrier reply, xid = $xid\n"; | |
| 541 | + | |
| 542 | + sysread($sock, $rcvd_msg, 256) | |
| 543 | + || die "Failed to receive message: $!"; | |
| 544 | + | |
| 545 | + my $num_read = length($rcvd_msg); | |
| 546 | + my $msg_size = $ofp->sizeof('ofp_header'); | |
| 547 | + my $msg = $ofp->unpack('ofp_hello', $rcvd_msg); | |
| 548 | + | |
| 549 | + print Dumper($msg); | |
| 550 | + compare("MsgVer", $$msg{'header'}{'version'}, '==', get_of_ver()); | |
| 551 | + compare("MsgType", $$msg{'header'}{'type'}, '==', $enums{'OFPT_BARRIER_REPLY'}); | |
| 552 | + compare("MsgLen", $$msg{'header'}{'length'}, '==', $msg_size); | |
| 553 | + | |
| 554 | + print "Received barrier reply, xid:$xid\n"; | |
| 555 | + | |
| 556 | + return $msg; | |
| 557 | +} | |
| 558 | + | |
| 559 | +sub send_get_config_request { | |
| 560 | + my ($ofp, $sock, $xid) = @_; | |
| 561 | + | |
| 562 | + my $hdr_args = { | |
| 563 | + version => $of_ver, | |
| 564 | + type => $enums{'OFPT_GET_CONFIG_REQUEST'}, | |
| 565 | + length => $ofp->sizeof('ofp_header'), | |
| 566 | + xid => $xid | |
| 567 | + }; | |
| 568 | + my $request = $ofp->pack('ofp_header', $hdr_args); | |
| 569 | + | |
| 570 | + syswrite($sock, $request); | |
| 571 | + | |
| 572 | + print "Sent get config request, xid:$xid\n"; | |
| 573 | +} | |
| 574 | + | |
| 575 | +sub wait_for_get_config_reply { | |
| 576 | + my ($ofp, $sock, $xid) = @_; | |
| 577 | + | |
| 578 | + my $rcvd_msg; | |
| 579 | + | |
| 580 | + print "Receiving get config reply, xid = $xid\n"; | |
| 581 | + | |
| 582 | + sysread($sock, $rcvd_msg, 256) | |
| 583 | + || die "Failed to receive message: $!"; | |
| 584 | + | |
| 585 | + my $num_read = length($rcvd_msg); | |
| 586 | + my $msg_size = $ofp->sizeof('ofp_switch_config'); | |
| 587 | + my $msg = $ofp->unpack('ofp_switch_config', $rcvd_msg); | |
| 588 | + | |
| 589 | + print Dumper($msg); | |
| 590 | + compare("MsgVer", $$msg{'header'}{'version'}, '==', get_of_ver()); | |
| 591 | + compare("MsgType", $$msg{'header'}{'type'}, '==', $enums{'OFPT_GET_CONFIG_REPLY'}); | |
| 592 | + compare("MsgLen", $$msg{'header'}{'length'}, '==', $msg_size); | |
| 593 | + | |
| 594 | + print "Received get config reply, xid = $xid\n"; | |
| 595 | + | |
| 596 | + return $msg; | |
| 597 | +} | |
| 598 | + | |
| 599 | +sub get_switch_features { | |
| 600 | + | |
| 601 | + my ( $ofp, $sock ) = @_; | |
| 602 | + | |
| 603 | + my $hdr_args_features_request = { | |
| 604 | + version => $of_ver, | |
| 605 | + type => $enums{'OFPT_FEATURES_REQUEST'}, | |
| 606 | + length => $ofp->sizeof('ofp_header'), # should generate automatically! | |
| 607 | + xid => 0x00000000 | |
| 608 | + }; | |
| 609 | + my $features_request = $ofp->pack( 'ofp_header', $hdr_args_features_request ); | |
| 610 | + | |
| 611 | + # Send 'features_request' message | |
| 612 | + syswrite( $sock, $features_request ); | |
| 613 | + | |
| 614 | + # Should add timeout here - will crash if no reply | |
| 615 | + my $recvd_mesg; | |
| 616 | + sysread( $sock, $recvd_mesg, 1512 ) || die "Failed to receive message: $!"; | |
| 617 | + | |
| 618 | + #print "received message after features request\n"; | |
| 619 | + | |
| 620 | + # Inspect message | |
| 621 | + my $msg_size = length($recvd_mesg); | |
| 622 | + #my $expected_size = $ofp->sizeof('ofp_switch_config'); | |
| 623 | + | |
| 624 | + #compare( "msg size", length($recvd_mesg), '==', $expected_size ); | |
| 625 | + | |
| 626 | + my $msg = $ofp->unpack( 'ofp_switch_features', $recvd_mesg ); | |
| 627 | + | |
| 628 | + #print HexDump ($recvd_mesg); | |
| 629 | + #print Dumper($msg); | |
| 630 | + | |
| 631 | + # Verify header fields | |
| 632 | + verify_header( $msg, 'OFPT_FEATURES_REPLY', $msg_size ); | |
| 633 | + | |
| 634 | + return $msg; | |
| 635 | +} | |
| 636 | + | |
| 637 | +sub get_config { | |
| 638 | + | |
| 639 | + my ( $ofp, $sock ) = @_; | |
| 640 | + | |
| 641 | + my $hdr_args_get_config_request = { | |
| 642 | + version => $of_ver, | |
| 643 | + type => $enums{'OFPT_GET_CONFIG_REQUEST'}, | |
| 644 | + length => $ofp->sizeof('ofp_header'), | |
| 645 | + xid => 0x0000000 | |
| 646 | + }; | |
| 647 | + | |
| 648 | + my $get_config_request = $ofp->pack( 'ofp_header', $hdr_args_get_config_request ); | |
| 649 | + | |
| 650 | + # Send 'get_config_request' message | |
| 651 | + syswrite( $sock, $get_config_request ); | |
| 652 | + | |
| 653 | + # Should add timeout here - will crash if no reply | |
| 654 | + my $recvd_mesg; | |
| 655 | + sysread( $sock, $recvd_mesg, 1512 ) || die "Failed to receive message: $!"; | |
| 656 | + | |
| 657 | + #print "received message after features request\n"; | |
| 658 | + | |
| 659 | + # Inspect message | |
| 660 | + my $msg_size = length($recvd_mesg); | |
| 661 | + my $expected_size = $ofp->sizeof('ofp_switch_config'); | |
| 662 | + | |
| 663 | + compare( "get_config msg size", length($recvd_mesg), '==', $expected_size ); | |
| 664 | + | |
| 665 | + my $msg = $ofp->unpack( 'ofp_switch_config', $recvd_mesg ); | |
| 666 | + | |
| 667 | + #print HexDump ($recvd_mesg); | |
| 668 | + #print Dumper($msg); | |
| 669 | + | |
| 670 | + # Verify header fields | |
| 671 | + verify_header( $msg, 'OFPT_GET_CONFIG_REPLY', $msg_size ); | |
| 672 | + | |
| 673 | + return $msg; | |
| 674 | +} | |
| 675 | + | |
| 676 | +sub set_config { | |
| 677 | + | |
| 678 | + my ( $ofp, $sock, $options_ref, $flags, $miss_send_len ) = @_; | |
| 679 | + my $hdr_args = { | |
| 680 | + version => $of_ver, | |
| 681 | + type => $enums{'OFPT_SET_CONFIG'}, | |
| 682 | + length => $ofp->sizeof('ofp_switch_config'), | |
| 683 | + xid => 0x0000000 | |
| 684 | + }; | |
| 685 | + | |
| 686 | + my $set_config_args = { | |
| 687 | + header => $hdr_args, | |
| 688 | + flags => $flags, | |
| 689 | + miss_send_len => $miss_send_len | |
| 690 | + }; | |
| 691 | + | |
| 692 | + my $set_config = $ofp->pack( 'ofp_switch_config', $set_config_args ); | |
| 693 | + | |
| 694 | + # Send 'set_config_request' message | |
| 695 | + syswrite( $sock, $set_config ); | |
| 696 | + | |
| 697 | + # Give OF switch time to process the set_config | |
| 698 | + usleep($$options_ref{'send_delay'}); | |
| 699 | +} | |
| 700 | + | |
| 701 | + | |
| 702 | +sub run_black_box_test { | |
| 703 | + | |
| 704 | + my ( $test_ref, $argv_ref, $dont_exit ) = @_; | |
| 705 | + | |
| 706 | + my %options = nftest_init( $argv_ref, \@interfaces, ); | |
| 707 | + | |
| 708 | + my ($proto, $host, $port) = nftest_parse_controllers( $options{'controller'} ); | |
| 709 | + print "using host $host and port $port\n"; | |
| 710 | + | |
| 711 | + $sock = create_controller_socket($host, $port); | |
| 712 | + | |
| 713 | + my $total_errors = 0; | |
| 714 | + try { | |
| 715 | + | |
| 716 | + # Wait for ofprotocol to connect | |
| 717 | + print "waiting for ofprotocol to connect\n"; | |
| 718 | + my $new_sock = $sock->accept(); | |
| 719 | + | |
| 720 | + do_hello_sequence( $ofp, $new_sock ); | |
| 721 | + | |
| 722 | + # Launch PCAP listening interface | |
| 723 | + nftest_start( \@interfaces ); | |
| 724 | + | |
| 725 | + &$test_ref( $new_sock, \%options ); | |
| 726 | + | |
| 727 | + # Sleep as long as needed for the test to finish | |
| 728 | + sleep 0.5; | |
| 729 | + } | |
| 730 | + catch Error with { | |
| 731 | + | |
| 732 | + # Catch and print any errors that occurred during control processing | |
| 733 | + my $ex = shift; | |
| 734 | + if ($ex) { | |
| 735 | + print $ex->stringify(); | |
| 736 | + } | |
| 737 | + $total_errors = 1; | |
| 738 | + } | |
| 739 | + finally { | |
| 740 | + | |
| 741 | + close($sock); | |
| 742 | + | |
| 743 | + my $unmatched = nftest_finish(); | |
| 744 | + print "Checking pkt errors\n"; | |
| 745 | + $total_errors += nftest_print_errors($unmatched); | |
| 746 | + | |
| 747 | + # if no errors earlier, and packets match, then success | |
| 748 | + my $exitCode; | |
| 749 | + if ( $total_errors == 0 ) { | |
| 750 | + print "SUCCESS!\n"; | |
| 751 | + $exitCode = 0; | |
| 752 | + } | |
| 753 | + else { | |
| 754 | + print "FAIL: $total_errors errors\n"; | |
| 755 | + $exitCode = 1; | |
| 756 | + } | |
| 757 | + if (!$dont_exit ) { exit($exitCode); } | |
| 758 | + }; | |
| 759 | +} | |
| 760 | + | |
| 761 | +sub create_flow_mod_from_udp { | |
| 762 | + my ( $ofp, $udp_pkt, $in_port, $out_port, $max_idle, $flags, | |
| 763 | + $wildcards, $chg_field, $chg_val, $vlan_id, $nw_tos, $cookie ) = @_; | |
| 764 | + | |
| 765 | + my $flow_mod_pkt; | |
| 766 | + | |
| 767 | + $flow_mod_pkt = create_flow_mod_from_udp_action( $ofp, $udp_pkt, $in_port, | |
| 768 | + $out_port, $max_idle, $flags, $wildcards, 'OFPFC_ADD', $chg_field, | |
| 769 | + $chg_val, $vlan_id, $nw_tos, $cookie ); | |
| 770 | + | |
| 771 | + return $flow_mod_pkt; | |
| 772 | +} | |
| 773 | + | |
| 774 | +sub flow_mod_length { | |
| 775 | + my ($mod_type, $chg_field) = @_; | |
| 776 | + | |
| 777 | + my $action_length = 0; | |
| 778 | + | |
| 779 | + if ($mod_type eq 'drop') { | |
| 780 | + $action_length = 0; | |
| 781 | + } elsif (defined $chg_field) { | |
| 782 | + if (($chg_field eq 'dl_src') || ($chg_field eq 'dl_dst')) { | |
| 783 | + $action_length = $ofp->sizeof('ofp_action_dl_addr') | |
| 784 | + + $ofp->sizeof('ofp_action_output'); | |
| 785 | + } elsif (($chg_field eq 'nw_src') || ($chg_field eq 'nw_dst')) { | |
| 786 | + $action_length = $ofp->sizeof('ofp_action_nw_addr') | |
| 787 | + + $ofp->sizeof('ofp_action_output'); | |
| 788 | + } elsif ($chg_field eq 'nw_tos') { | |
| 789 | + $action_length = $ofp->sizeof('ofp_action_nw_tos') | |
| 790 | + + $ofp->sizeof('ofp_action_output'); | |
| 791 | + } elsif (($chg_field eq 'tp_src') || ($chg_field eq 'tp_dst')) { | |
| 792 | + $action_length = $ofp->sizeof('ofp_action_tp_port') | |
| 793 | + + $ofp->sizeof('ofp_action_output'); | |
| 794 | + } elsif ($chg_field eq 'strip_vlan') { | |
| 795 | + $action_length = $ofp->sizeof('ofp_action_header') | |
| 796 | + + $ofp->sizeof('ofp_action_output'); | |
| 797 | + } elsif ($chg_field eq 'vlan_vid') { | |
| 798 | + $action_length = $ofp->sizeof('ofp_action_vlan_vid') | |
| 799 | + + $ofp->sizeof('ofp_action_output'); | |
| 800 | + } elsif ($chg_field eq 'vlan_pcp') { | |
| 801 | + $action_length = $ofp->sizeof('ofp_action_vlan_pcp') | |
| 802 | + + $ofp->sizeof('ofp_action_output'); | |
| 803 | + } else { | |
| 804 | + $action_length = $ofp->sizeof('ofp_action_output'); | |
| 805 | + } | |
| 806 | + } elsif ($mod_type eq 'enqueue') { | |
| 807 | + $action_length = $ofp->sizeof('ofp_action_enqueue'); | |
| 808 | + } | |
| 809 | + else { | |
| 810 | + $action_length = $ofp->sizeof('ofp_action_output'); | |
| 811 | + } | |
| 812 | + | |
| 813 | + my $length = $ofp->sizeof('ofp_flow_mod') + $action_length; | |
| 814 | + return $length; | |
| 815 | +} | |
| 816 | + | |
| 817 | +sub combine_args { | |
| 818 | + my ($mod_type, $out_port, $chg_field, $chg_val, $queue_id) = @_; | |
| 819 | + | |
| 820 | + my @pad_6 = (0,0,0,0,0,0); | |
| 821 | + my @pad_4 = (0,0,0,0); | |
| 822 | + my @pad_3 = (0,0,0); | |
| 823 | + my @pad_2 = (0,0); | |
| 824 | + | |
| 825 | + my $nw_addr_org; | |
| 826 | + my $ok_org; | |
| 827 | + | |
| 828 | + my @dl_addr_org; | |
| 829 | + my $chg_vlan_pcp_val; | |
| 830 | + | |
| 831 | + #OUTPUT | |
| 832 | + #and No action for drops | |
| 833 | + my $action_output_args; | |
| 834 | + my $action_output; | |
| 835 | + | |
| 836 | + my $max_len; | |
| 837 | + if ($out_port != $enums{'OFPP_CONTROLLER'}) { | |
| 838 | + $max_len = 0; | |
| 839 | + } else { | |
| 840 | + $max_len = 65535; | |
| 841 | + } | |
| 842 | + if ($mod_type ne 'drop') { | |
| 843 | + if ($mod_type eq 'enqueue') { | |
| 844 | + $action_enqueue_args = { | |
| 845 | + type => $enums{'OFPAT_ENQUEUE'}, | |
| 846 | + len => $ofp->sizeof('ofp_action_enqueue'), | |
| 847 | + port => $out_port, | |
| 848 | + pad => \@pad_6, | |
| 849 | + queue_id => $queue_id, | |
| 850 | + }; | |
| 851 | + $action_enqueue = $ofp->pack('ofp_action_enqueue', $action_enqueue_args); | |
| 852 | + } | |
| 853 | + else { | |
| 854 | + $action_output_args = { | |
| 855 | + type => $enums{'OFPAT_OUTPUT'}, | |
| 856 | + len => $ofp->sizeof('ofp_action_output'), | |
| 857 | + port => $out_port, | |
| 858 | + max_len => $max_len, | |
| 859 | + }; | |
| 860 | + $action_output = $ofp->pack('ofp_action_output', $action_output_args); | |
| 861 | + } | |
| 862 | + } | |
| 863 | + | |
| 864 | + #MODIFY ACTION | |
| 865 | + my $action_mod_args; | |
| 866 | + my $action_mod; | |
| 867 | + if (defined $chg_field) { | |
| 868 | + if ($chg_field eq 'dl_src') { #SET_DL_SRC | |
| 869 | + @dl_addr_org = NF2::PDU::get_MAC_address($chg_val); | |
| 870 | + $action_mod_args = { | |
| 871 | + type => $enums{'OFPAT_SET_DL_SRC'}, | |
| 872 | + len => $ofp->sizeof('ofp_action_dl_addr'), | |
| 873 | + dl_addr => \@dl_addr_org, | |
| 874 | + pad => \@pad_6, | |
| 875 | + }; | |
| 876 | + $action_mod = $ofp->pack('ofp_action_dl_addr', $action_mod_args); | |
| 877 | + } elsif ($chg_field eq 'dl_dst') { #SET_DL_DST | |
| 878 | + @dl_addr_org = NF2::PDU::get_MAC_address($chg_val); | |
| 879 | + $action_mod_args = { | |
| 880 | + type => $enums{'OFPAT_SET_DL_DST'}, | |
| 881 | + len => $ofp->sizeof('ofp_action_dl_addr'), | |
| 882 | + dl_addr => \@dl_addr_org, | |
| 883 | + pad => \@pad_6, | |
| 884 | + }; | |
| 885 | + $action_mod = $ofp->pack('ofp_action_dl_addr', $action_mod_args); | |
| 886 | + } elsif ($chg_field eq 'nw_src') { #SET_NW_SRC | |
| 887 | + ($nw_addr_org, $ok_org) = NF2::IP_hdr::getIP($chg_val); | |
| 888 | + $action_mod_args = { | |
| 889 | + type => $enums{'OFPAT_SET_NW_SRC'}, | |
| 890 | + len => $ofp->sizeof('ofp_action_nw_addr'), | |
| 891 | + nw_addr => $nw_addr_org, | |
| 892 | + }; | |
| 893 | + $action_mod = $ofp->pack('ofp_action_nw_addr', $action_mod_args); | |
| 894 | + } elsif ($chg_field eq 'nw_dst') { #SET_NW_DST | |
| 895 | + ($nw_addr_org, $ok_org) = NF2::IP_hdr::getIP($chg_val); | |
| 896 | + $action_mod_args = { | |
| 897 | + type => $enums{'OFPAT_SET_NW_DST'}, | |
| 898 | + len => $ofp->sizeof('ofp_action_nw_addr'), | |
| 899 | + nw_addr => $nw_addr_org, | |
| 900 | + }; | |
| 901 | + $action_mod = $ofp->pack('ofp_action_nw_addr', $action_mod_args); | |
| 902 | + } elsif ($chg_field eq 'nw_tos') { #SET_NW_TOS | |
| 903 | + $action_mod_args = { | |
| 904 | + type => $enums{'OFPAT_SET_NW_TOS'}, | |
| 905 | + len => $ofp->sizeof('ofp_action_nw_tos'), | |
| 906 | + nw_tos => $chg_val, | |
| 907 | + pad => \@pad_3, | |
| 908 | + }; | |
| 909 | + $action_mod = $ofp->pack('ofp_action_nw_tos', $action_mod_args); | |
| 910 | + } elsif ($chg_field eq 'tp_src') { #SET_TP_SRC | |
| 911 | + $action_mod_args = { | |
| 912 | + type => $enums{'OFPAT_SET_TP_SRC'}, | |
| 913 | + len => $ofp->sizeof('ofp_action_tp_port'), | |
| 914 | + tp_port => $chg_val, | |
| 915 | + pad => \@pad_2, | |
| 916 | + }; | |
| 917 | + $action_mod = $ofp->pack('ofp_action_tp_port', $action_mod_args); | |
| 918 | + } elsif ($chg_field eq 'tp_dst') { #SET_TP_DST | |
| 919 | + $action_mod_args = { | |
| 920 | + type => $enums{'OFPAT_SET_TP_DST'}, | |
| 921 | + len => $ofp->sizeof('ofp_action_tp_port'), | |
| 922 | + tp_port => $chg_val, | |
| 923 | + pad => \@pad_2, | |
| 924 | + }; | |
| 925 | + $action_mod = $ofp->pack('ofp_action_tp_port', $action_mod_args); | |
| 926 | + } elsif ($chg_field eq 'strip_vlan') { #STRIP_VLAN | |
| 927 | + $action_mod_args = { | |
| 928 | + type => $enums{'OFPAT_STRIP_VLAN'}, | |
| 929 | + len => $ofp->sizeof('ofp_action_header'), | |
| 930 | + pad => \@pad_4, | |
| 931 | + }; | |
| 932 | + $action_mod = $ofp->pack('ofp_action_header', $action_mod_args); | |
| 933 | + } elsif ($chg_field eq 'vlan_vid') { #SET_VLAN_VID | |
| 934 | + $action_mod_args = { | |
| 935 | + type => $enums{'OFPAT_SET_VLAN_VID'}, | |
| 936 | + len => $ofp->sizeof('ofp_action_vlan_vid'), | |
| 937 | + vlan_vid => $chg_val & 0x0fff, | |
| 938 | + pad => \@pad_2, | |
| 939 | + }; | |
| 940 | + $action_mod = $ofp->pack('ofp_action_vlan_vid', $action_mod_args); | |
| 941 | + } elsif ($chg_field eq 'vlan_pcp') { #SET_VLAN_PCP | |
| 942 | + $chg_vlan_pcp_val = ($chg_val>>13) & 0x0007; | |
| 943 | + $action_mod_args = { | |
| 944 | + type => $enums{'OFPAT_SET_VLAN_PCP'}, | |
| 945 | + len => $ofp->sizeof('ofp_action_vlan_pcp'), | |
| 946 | + vlan_pcp => $chg_vlan_pcp_val, | |
| 947 | + pad => \@pad_3, | |
| 948 | + }; | |
| 949 | + $action_mod = $ofp->pack('ofp_action_vlan_pcp', $action_mod_args); | |
| 950 | + } else { | |
| 951 | + $action_mod = undef; | |
| 952 | + } | |
| 953 | + } else { | |
| 954 | + $action_mod = undef; | |
| 955 | + } | |
| 956 | + | |
| 957 | + if (defined $action_mod) { | |
| 958 | + $flow_mod_actions = $action_mod . $action_output; | |
| 959 | + } elsif (defined $action_enqueue) { | |
| 960 | + $flow_mod_actions = $action_enqueue; | |
| 961 | + } else { | |
| 962 | + $flow_mod_actions = $action_output; | |
| 963 | + } | |
| 964 | + | |
| 965 | + return $flow_mod_actions; | |
| 966 | +} | |
| 967 | + | |
| 968 | +sub create_flow_mod_from_udp_actionbytes { | |
| 969 | + my ( $ofp, $udp_pkt, $in_port, $max_idle, $flags, | |
| 970 | + $wildcards, $mod_type, $action_bytes, $vlan_id, | |
| 971 | + $nw_tos, $cookie) = @_; | |
| 972 | + | |
| 973 | + $cookie = 0 if !defined($cookie); | |
| 974 | + | |
| 975 | + my $length = $ofp->sizeof('ofp_flow_mod') + length $action_bytes; | |
| 976 | + | |
| 977 | + my $hdr_args = { | |
| 978 | + version => $of_ver, | |
| 979 | + type => $enums{'OFPT_FLOW_MOD'}, | |
| 980 | + length => $length, | |
| 981 | + xid => 0x0000000 | |
| 982 | + }; | |
| 983 | + | |
| 984 | + # might be cleaner to convert the exported colon-hex MAC addrs | |
| 985 | + #print ${$udp_pkt->{Ethernet_hdr}}->SA . "\n"; | |
| 986 | + #print ${$test_pkt->{Ethernet_hdr}}->SA . "\n"; | |
| 987 | + my $ref_to_eth_hdr = ( $udp_pkt->{'Ethernet_hdr'} ); | |
| 988 | + my $ref_to_ip_hdr = ( $udp_pkt->{'IP_hdr'} ); | |
| 989 | + | |
| 990 | + # pointer to array | |
| 991 | + my $eth_hdr_bytes = $$ref_to_eth_hdr->{'bytes'}; | |
| 992 | + my $ip_hdr_bytes = $$ref_to_ip_hdr->{'bytes'}; | |
| 993 | + my @dst_mac_subarray = @{$eth_hdr_bytes}[ 0 .. 5 ]; | |
| 994 | + my @src_mac_subarray = @{$eth_hdr_bytes}[ 6 .. 11 ]; | |
| 995 | + | |
| 996 | + my @src_ip_subarray = @{$ip_hdr_bytes}[ 12 .. 15 ]; | |
| 997 | + my @dst_ip_subarray = @{$ip_hdr_bytes}[ 16 .. 19 ]; | |
| 998 | + | |
| 999 | + my $src_ip = | |
| 1000 | + ( ( 2**24 ) * $src_ip_subarray[0] + | |
| 1001 | + ( 2**16 ) * $src_ip_subarray[1] + | |
| 1002 | + ( 2**8 ) * $src_ip_subarray[2] + | |
| 1003 | + $src_ip_subarray[3] ); | |
| 1004 | + | |
| 1005 | + my $dst_ip = | |
| 1006 | + ( ( 2**24 ) * $dst_ip_subarray[0] + | |
| 1007 | + ( 2**16 ) * $dst_ip_subarray[1] + | |
| 1008 | + ( 2**8 ) * $dst_ip_subarray[2] + | |
| 1009 | + $dst_ip_subarray[3] ); | |
| 1010 | + | |
| 1011 | + my $dl_vlan; | |
| 1012 | + my $dl_vlan_pcp; | |
| 1013 | + if (defined $vlan_id) { | |
| 1014 | + $dl_vlan = $vlan_id & 0x0fff; | |
| 1015 | + $dl_vlan_pcp = (($vlan_id >> 13) & 0x0007); | |
| 1016 | + } else { | |
| 1017 | + $dl_vlan = 0xffff; | |
| 1018 | + $dl_vlan_pcp = 0x0; | |
| 1019 | + } | |
| 1020 | + | |
| 1021 | + my $match_nw_tos; | |
| 1022 | + if (defined $nw_tos) { | |
| 1023 | + $match_nw_tos = $nw_tos & 0xfc; | |
| 1024 | + } else { | |
| 1025 | + $match_nw_tos = 0; | |
| 1026 | + } | |
| 1027 | + | |
| 1028 | + my $match_args = { | |
| 1029 | + wildcards => $wildcards, | |
| 1030 | + in_port => $in_port, | |
| 1031 | + dl_src => \@src_mac_subarray, | |
| 1032 | + dl_dst => \@dst_mac_subarray, | |
| 1033 | + dl_vlan => $dl_vlan, | |
| 1034 | + dl_type => 0x0800, | |
| 1035 | + dl_vlan_pcp => $dl_vlan_pcp, | |
| 1036 | + nw_src => $src_ip, | |
| 1037 | + nw_dst => $dst_ip, | |
| 1038 | + nw_tos => $match_nw_tos, | |
| 1039 | + nw_proto => 17, #udp | |
| 1040 | + tp_src => ${ $udp_pkt->{UDP_pdu} }->SrcPort, | |
| 1041 | + tp_dst => ${ $udp_pkt->{UDP_pdu} }->DstPort | |
| 1042 | + }; | |
| 1043 | + | |
| 1044 | + # organize flow_mod packet | |
| 1045 | + my $flow_mod_args = { | |
| 1046 | + header => $hdr_args, | |
| 1047 | + match => $match_args, | |
| 1048 | + command => $enums{"$mod_type"}, | |
| 1049 | + idle_timeout => $max_idle, | |
| 1050 | + hard_timeout => $max_idle, | |
| 1051 | + flags => $flags, | |
| 1052 | + priority => 0, | |
| 1053 | + buffer_id => -1, | |
| 1054 | + out_port => $enums{'OFPP_NONE'}, | |
| 1055 | + cookie => $cookie, | |
| 1056 | + }; | |
| 1057 | + my $flow_mod = $ofp->pack( 'ofp_flow_mod', $flow_mod_args ); | |
| 1058 | + my $flow_mod_pkt = $flow_mod . $action_bytes; | |
| 1059 | + return $flow_mod_pkt; | |
| 1060 | +} | |
| 1061 | + | |
| 1062 | +sub create_flow_mod_from_udp_action { | |
| 1063 | + my ( $ofp, $udp_pkt, $in_port, $out_port, $max_idle, $flags, | |
| 1064 | + $wildcards, $mod_type, $chg_field, $chg_val, $vlan_id, | |
| 1065 | + $nw_tos, $cookie, $queue_id) = @_; | |
| 1066 | + | |
| 1067 | + if ( $mod_type ne 'drop' | |
| 1068 | + && $mod_type ne 'enqueue' | |
| 1069 | + && $mod_type ne 'OFPFC_ADD' | |
| 1070 | + && $mod_type ne 'OFPFC_DELETE' | |
| 1071 | + && $mod_type ne 'OFPFC_DELETE_STRICT') | |
| 1072 | + { | |
| 1073 | + die "Undefined flow mod type: $mod_type\n"; | |
| 1074 | + } | |
| 1075 | + | |
| 1076 | + my $length_expect = flow_mod_length($mod_type, $chg_field); | |
| 1077 | + my $flow_mod_actions = combine_args($mod_type, $out_port, $chg_field, $chg_val, $queue_id); | |
| 1078 | + my $length = $ofp->sizeof('ofp_flow_mod') + length $flow_mod_actions; | |
| 1079 | + if( $length != $length_expect) { | |
| 1080 | + die "Mismatching length for $mod_type, $length != $length_expect\n"; | |
| 1081 | + } | |
| 1082 | + | |
| 1083 | + $flow_mod_pkt = | |
| 1084 | + create_flow_mod_from_udp_actionbytes( $ofp, $udp_pkt, $in_port, $max_idle, $flags, $wildcards, $mod_type, $flow_mod_actions, $vlan_id, $nw_tos, $cookie); | |
| 1085 | + | |
| 1086 | + return $flow_mod_pkt; | |
| 1087 | +} | |
| 1088 | + | |
| 1089 | + | |
| 1090 | +sub wait_for_flow_expired { | |
| 1091 | + | |
| 1092 | + my ( $ofp, $sock, $options_ref, $pkt_len, $pkt_total, $idle_timeout, | |
| 1093 | + $cookie ) = @_; | |
| 1094 | + | |
| 1095 | + wait_for_flow_expired_readsize( $ofp, $sock, $options_ref, $pkt_len, | |
| 1096 | + $pkt_total, $idle_timeout, $cookie, undef); | |
| 1097 | +} | |
| 1098 | + | |
| 1099 | +sub wait_for_flow_expired_all { | |
| 1100 | + | |
| 1101 | + my ( $ofp, $sock, $options_ref, $cookie ) = @_; | |
| 1102 | + | |
| 1103 | + wait_for_flow_expired_readsize( $ofp, $sock, $options_ref, | |
| 1104 | + $$options_ref{'pkt_len'}, $$options_ref{'pkt_total'}, | |
| 1105 | + $cookie, undef ); | |
| 1106 | +} | |
| 1107 | + | |
| 1108 | +sub wait_for_flow_expired_readone { | |
| 1109 | + | |
| 1110 | + my ( $ofp, $sock, $options_ref, $pkt_len, $pkt_total, $idle_timeout, | |
| 1111 | + $cookie ) = @_; | |
| 1112 | + | |
| 1113 | + wait_for_flow_expired_readsize( $ofp, $sock, $options_ref, $pkt_len, $pkt_total, $idle_timeout, | |
| 1114 | + $cookie, $ofp->sizeof('ofp_flow_removed') ); | |
| 1115 | +} | |
| 1116 | + | |
| 1117 | +sub wait_for_flow_expired_readsize { | |
| 1118 | + | |
| 1119 | + # can specify the reading size from socket (by the last argument, $read_size_) | |
| 1120 | + | |
| 1121 | + my ( $ofp, $sock, $options_ref, $pkt_len, $pkt_total, $idle_timeout, | |
| 1122 | + $cookie, $read_size_ ) = @_; | |
| 1123 | + wait_for_flow_expired_total_bytes( $ofp, $sock, $options_ref, ( $pkt_len * $pkt_total ), | |
| 1124 | + $pkt_total, $idle_timeout, $cookie, $read_size_ ); | |
| 1125 | +} | |
| 1126 | + | |
| 1127 | +sub wait_for_flow_expired_total_bytes { | |
| 1128 | + my ( $ofp, $sock, $options_ref, $bytes, $pkt_total, $idle_timeout, | |
| 1129 | + $cookie, $read_size_ ) = @_; | |
| 1130 | + my $read_size; | |
| 1131 | + | |
| 1132 | + if ( defined $read_size_ ) { | |
| 1133 | + $read_size = $read_size_; | |
| 1134 | + } else { | |
| 1135 | + $read_size = 1512; | |
| 1136 | + } | |
| 1137 | + | |
| 1138 | + my $recvd_mesg; | |
| 1139 | + sysread( $sock, $recvd_mesg, $read_size ) | |
| 1140 | + || die "Failed to receive ofp_flow_removed message: $!"; | |
| 1141 | + | |
| 1142 | + #print HexDump ($recvd_mesg); | |
| 1143 | + | |
| 1144 | + # Inspect message | |
| 1145 | + my $msg_size = length($recvd_mesg); | |
| 1146 | + my $expected_size = $ofp->sizeof('ofp_flow_removed'); | |
| 1147 | + compare( "ofp_flow_removed msg size", length($recvd_mesg), '==', $expected_size ); | |
| 1148 | + | |
| 1149 | + my $msg = $ofp->unpack( 'ofp_flow_removed', $recvd_mesg ); | |
| 1150 | + | |
| 1151 | + #print Dumper($msg); | |
| 1152 | + | |
| 1153 | + # Verify fields | |
| 1154 | + compare( "ofp_flow_removed header version", $$msg{'header'}{'version'}, '==', $of_ver ); | |
| 1155 | + compare( "ofp_flow_removed header type", $$msg{'header'}{'type'}, '==', $enums{'OFPT_FLOW_REMOVED'} ); | |
| 1156 | + compare( "ofp_flow_removed header length", $$msg{'header'}{'length'}, '==', $msg_size ); | |
| 1157 | + | |
| 1158 | + # Disable for platforms that don't have byte counts... - Jean II | |
| 1159 | + if ( not defined( $$options_ref{'ignore_byte_count'} ) ) { | |
| 1160 | + compare( "ofp_flow_removed byte_count", $$msg{'byte_count'}, '==', $bytes ); | |
| 1161 | + } | |
| 1162 | + compare( "ofp_flow_removed packet_count", $$msg{'packet_count'}, '==', $pkt_total ); | |
| 1163 | + | |
| 1164 | + if ( defined $idle_timeout ) { | |
| 1165 | + compare( "ofp_flow_removed idle_timeout", $$msg{'idle_timeout'}, '==', $idle_timeout ); | |
| 1166 | + } | |
| 1167 | + | |
| 1168 | + if ( defined $cookie ) { | |
| 1169 | + compare( "ofp_flow_removed cookie", $$msg{'cookie'}, '==', $cookie ); | |
| 1170 | + } | |
| 1171 | +} | |
| 1172 | + | |
| 1173 | +sub wait_for_one_packet_in { | |
| 1174 | + | |
| 1175 | + # wait for a packet which arrives via socket, and verify it is the expected packet | |
| 1176 | + # $sock: socket | |
| 1177 | + # $pkt_len: packet length of the expected packet to receive | |
| 1178 | + # $pkt : expected packet to receive | |
| 1179 | + | |
| 1180 | + my ( $ofp, $sock, $pkt_len, $pkt ) = @_; | |
| 1181 | + | |
| 1182 | + my $pkt_in_msg_size; # read size from socket | |
| 1183 | + if ( $pkt_len < $of_miss_send_len ) { | |
| 1184 | + | |
| 1185 | + # Due to padding, the size of ofp_packet_in header is $ofp->sizeof('ofp_packet_in')-2 | |
| 1186 | + $pkt_in_msg_size = ( $ofp->sizeof('ofp_packet_in') - 2 ) + $pkt_len; | |
| 1187 | + } | |
| 1188 | + else { | |
| 1189 | + $pkt_in_msg_size = ( $ofp->sizeof('ofp_packet_in') - 2 ) + $of_miss_send_len; | |
| 1190 | + } | |
| 1191 | + | |
| 1192 | + my $recvd_mesg; | |
| 1193 | + sysread( $sock, $recvd_mesg, $pkt_in_msg_size ) | |
| 1194 | + || die "Failed to receive message: $!"; | |
| 1195 | + | |
| 1196 | + # Inspect message | |
| 1197 | + my $msg_size = length($recvd_mesg); | |
| 1198 | + my $expected_size = $pkt_in_msg_size; | |
| 1199 | + compare( "ofp_packet_in msg size", length($recvd_mesg), '==', $expected_size ); | |
| 1200 | + | |
| 1201 | + my $msg = $ofp->unpack( 'ofp_packet_in', $recvd_mesg ); | |
| 1202 | + | |
| 1203 | + # print Dumper($msg); | |
| 1204 | + | |
| 1205 | + # Verify fields | |
| 1206 | + compare( "ofp_packet_in header version", $$msg{'header'}{'version'}, '==', $of_ver ); | |
| 1207 | + compare( "ofp_packet_in header type", $$msg{'header'}{'type'}, '==', $enums{'OFPT_PACKET_IN'} ); | |
| 1208 | + compare( "ofp_packet_in header length", $$msg{'header'}{'length'}, '==', $msg_size ); | |
| 1209 | + compare( "ofp_packet_in header length", $$msg{'total_len'}, '==', $pkt_len ); | |
| 1210 | + | |
| 1211 | + my $recvd_pkt_data = substr( $recvd_mesg, $ofp->offsetof( 'ofp_packet_in', 'data' ) ); | |
| 1212 | + | |
| 1213 | + # print "packet expecting\n"; | |
| 1214 | + # print HexDump ($pkt); | |
| 1215 | + # print "packet received\n"; | |
| 1216 | + # print HexDump ($recvd_pkt_data); | |
| 1217 | + | |
| 1218 | + if ( $recvd_pkt_data ne $pkt ) { | |
| 1219 | + die "ERROR: received packet data didn't match the expecting packet\n"; | |
| 1220 | + } | |
| 1221 | +} | |
| 1222 | + | |
| 1223 | +sub verify_header { | |
| 1224 | + | |
| 1225 | + my ( $msg, $ofpt, $msg_size ) = @_; | |
| 1226 | + | |
| 1227 | + compare( "header version", $$msg{'header'}{'version'}, '==', $of_ver ); | |
| 1228 | + compare( "header type", $$msg{'header'}{'type'}, '==', $enums{$ofpt} ); | |
| 1229 | + compare( "header length", $$msg{'header'}{'length'}, '==', $msg_size ); | |
| 1230 | +} | |
| 1231 | + | |
| 1232 | +sub get_of_ver { | |
| 1233 | + return $of_ver; | |
| 1234 | +} | |
| 1235 | + | |
| 1236 | +sub get_of_port { | |
| 1237 | + return $of_port; | |
| 1238 | +} | |
| 1239 | + | |
| 1240 | +sub get_of_miss_send_len_default { | |
| 1241 | + return $of_miss_send_len; | |
| 1242 | +} | |
| 1243 | + | |
| 1244 | +sub get_default_black_box_pkt { | |
| 1245 | + my ($in_port, $out_port) = @_; | |
| 1246 | + | |
| 1247 | + return get_default_black_box_pkt_len($in_port, $out_port, 64); | |
| 1248 | +} | |
| 1249 | + | |
| 1250 | +sub get_default_black_box_pkt_len { | |
| 1251 | + my ($in_port, $out_port, $len, $vlan_id) = @_; | |
| 1252 | + | |
| 1253 | + my $pkt_args = { | |
| 1254 | + DA => "00:00:00:00:00:" . sprintf( "%02d", $out_port ), | |
| 1255 | + SA => "00:00:00:00:00:" . sprintf( "%02d", $in_port ), | |
| 1256 | + VLAN_ID => $vlan_id, | |
| 1257 | + src_ip => "192.168.200." . ( $in_port ), | |
| 1258 | + dst_ip => "192.168.201." . ( $out_port ), | |
| 1259 | + ttl => 64, | |
| 1260 | + len => $len, | |
| 1261 | + src_port => 1, | |
| 1262 | + dst_port => 0 | |
| 1263 | + }; | |
| 1264 | + return new NF2::UDP_pkt(%$pkt_args); | |
| 1265 | +} | |
| 1266 | + | |
| 1267 | +sub for_all_port_pairs { | |
| 1268 | + | |
| 1269 | + my ( $ofp, $sock, $options_ref, $fcn_ref, $wc ) = @_; | |
| 1270 | + | |
| 1271 | + my $port_base = $$options_ref{'port_base'}; | |
| 1272 | + my $num_ports = $$options_ref{'num_ports'}; | |
| 1273 | + | |
| 1274 | + # Check if we need to be exhaustive or not... | |
| 1275 | + if ( defined( $$options_ref{'less_ports'} ) ) { | |
| 1276 | + # Just pick a pair of random ports | |
| 1277 | + my $source_port = int(rand($num_ports)); | |
| 1278 | + my $offset = int(rand($num_ports - 1)) + 1; | |
| 1279 | + my $dest_port = ($source_port + $offset) % $num_ports; | |
| 1280 | + print "sending from port offset $source_port to $dest_port\n"; | |
| 1281 | + &$fcn_ref( $ofp, $sock, $options_ref, $source_port, $dest_port, $wc); | |
| 1282 | + } else { | |
| 1283 | + # send from every port to every other port | |
| 1284 | + for ( my $i = 0 ; $i < $num_ports ; $i++ ) { | |
| 1285 | + for ( my $j = 0 ; $j < $num_ports ; $j++ ) { | |
| 1286 | + if ( $i != $j ) { | |
| 1287 | + print "sending from port offset $i to $j\n"; | |
| 1288 | + &$fcn_ref( $ofp, $sock, $options_ref, $i, $j, $wc); | |
| 1289 | + } | |
| 1290 | + } | |
| 1291 | + } | |
| 1292 | + } | |
| 1293 | +} | |
| 1294 | + | |
| 1295 | +sub for_all_ports { | |
| 1296 | + | |
| 1297 | + my ( $ofp, $sock, $options_ref, $fcn_ref, $wc ) = @_; | |
| 1298 | + | |
| 1299 | + my $port_base = $$options_ref{'port_base'}; | |
| 1300 | + my $num_ports = $$options_ref{'num_ports'}; | |
| 1301 | + | |
| 1302 | + | |
| 1303 | + # Check if we need to be exhaustive or not... | |
| 1304 | + if ( defined( $$options_ref{'less_ports'} ) ) { | |
| 1305 | + # Just pick one random port | |
| 1306 | + my $random_port = int(rand($num_ports)); | |
| 1307 | + print "sending from port offset $random_port to (all port offsets but $random_port)\n"; | |
| 1308 | + &$fcn_ref( $ofp, $sock, $options_ref, $random_port, -1, $wc); | |
| 1309 | + } else { | |
| 1310 | + # send from every port | |
| 1311 | + for ( my $i = 0 ; $i < $num_ports ; $i++ ) { | |
| 1312 | + print "sending from port offset $i to (all port offsets but $i)\n"; | |
| 1313 | + &$fcn_ref( $ofp, $sock, $options_ref, $i, -1, $wc); | |
| 1314 | + } | |
| 1315 | + } | |
| 1316 | +} | |
| 1317 | + | |
| 1318 | +sub for_all_wildcards { | |
| 1319 | + | |
| 1320 | + my ( $ofp, $sock, $options_ref, $fcn_ref) = @_; | |
| 1321 | + | |
| 1322 | + my $port_base = $$options_ref{'port_base'}; | |
| 1323 | + my $num_ports = $$options_ref{'num_ports'}; | |
| 1324 | + | |
| 1325 | + my %wildcards = ( | |
| 1326 | + 0x000001 => 'IN_PORT', | |
| 1327 | + 0x000002 => 'DL_VLAN', | |
| 1328 | + 0x000004 => 'DL_SRC', | |
| 1329 | + 0x000008 => 'DL_DST', | |
| 1330 | + #0x000010 => 'DL_TYPE', # currently fixed at 0x0800 | |
| 1331 | + #0x000020 => 'NW_PROTO', # currently fixed at 0x17 | |
| 1332 | + 0x000040 => 'TP_SRC', | |
| 1333 | + 0x000080 => 'TP_DST', | |
| 1334 | + 0x003f00 => 'NW_SRC', | |
| 1335 | + 0x0fc000 => 'NW_DST', | |
| 1336 | + 0x100000 => 'DL_VLAN_PCP', | |
| 1337 | + 0x200000 => 'NW_TOS', | |
| 1338 | + ); | |
| 1339 | + | |
| 1340 | + # Disable "1 ||" below for a more complete test | |
| 1341 | + # Check if we need to be exhaustive or not... | |
| 1342 | + if ( 1 || defined( $$options_ref{'less_ports'} ) ) { | |
| 1343 | + # Just pick a pair of random ports | |
| 1344 | + my $source_port = int(rand($num_ports)); | |
| 1345 | + my $offset = int(rand($num_ports - 1)) + 1; | |
| 1346 | + my $dest_port = ($source_port + $offset) % $num_ports; | |
| 1347 | + | |
| 1348 | + print "sending from $source_port to $dest_port\n"; | |
| 1349 | + | |
| 1350 | + for my $wc (sort keys %wildcards) { | |
| 1351 | + printf ("wildcards: 0x%04x ".$wildcards{$wc}."\n", $wc); | |
| 1352 | + &$fcn_ref( $ofp, $sock, $options_ref, $source_port, $dest_port, $wc); | |
| 1353 | + } | |
| 1354 | + } else { | |
| 1355 | + # send from every port | |
| 1356 | + for ( $i = 0 ; $i < $num_ports ; $i++ ) { | |
| 1357 | + my $j = ($i + 1) % 4; | |
| 1358 | + print "sending from $i to $j\n"; | |
| 1359 | + for my $wc (sort keys %wildcards) { | |
| 1360 | + printf ("wildcards: 0x%04x ".$wildcards{$wc}."\n", $wc); | |
| 1361 | + &$fcn_ref( $ofp, $sock, $options_ref, $i, $j, $wc); | |
| 1362 | + } | |
| 1363 | + } | |
| 1364 | + } | |
| 1365 | +} | |
| 1366 | + | |
| 1367 | +sub for_all_port_triplets { | |
| 1368 | + my ( $ofp, $sock, $options_ref, $fcn_ref, $wc ) = @_; | |
| 1369 | + | |
| 1370 | + my $port_base = $$options_ref{'port_base'}; | |
| 1371 | + my $num_ports = $$options_ref{'num_ports'}; | |
| 1372 | + | |
| 1373 | + # Check if we need to be exhaustive or not... | |
| 1374 | + if ( defined( $$options_ref{'less_ports'} ) ) { | |
| 1375 | + # Just pick a triplet of random ports | |
| 1376 | + my $source_port = int(rand($num_ports)); | |
| 1377 | + my $offset = int(rand($num_ports - 1)) + 1; | |
| 1378 | + my $dest_port = ($source_port + $offset) % $num_ports; | |
| 1379 | + my $offset2 = int(rand($num_ports - 2)) + 1; | |
| 1380 | + if( $offset2 >= $offset) { | |
| 1381 | + $offset2++; | |
| 1382 | + } | |
| 1383 | + my $dest2_port = ($source_port + $offset2) % $num_ports; | |
| 1384 | + | |
| 1385 | + &$fcn_ref( $ofp, $sock, $options_ref, $source_port, $dest_port, $dest2_port, $wc); | |
| 1386 | + } else { | |
| 1387 | + # send from every port to every other port | |
| 1388 | + for ( my $i = 0 ; $i < $num_ports ; $i++ ) { | |
| 1389 | + for ( my $j = 0 ; $j < $num_ports ; $j++ ) { | |
| 1390 | + my $o_port2 = ( ( $j + 1 ) % 4 ); | |
| 1391 | + if ( $i != $j && $i != $o_port2) { | |
| 1392 | + &$fcn_ref( $ofp, $sock, $options_ref, $i, $j, $o_port2, $wc); | |
| 1393 | + } | |
| 1394 | + } | |
| 1395 | + } | |
| 1396 | + } | |
| 1397 | +} | |
| 1398 | + | |
| 1399 | +sub get_original_value { | |
| 1400 | + my ($chg_field, $test_pkt, $vlan_id) = @_; | |
| 1401 | + | |
| 1402 | + my $chg_val; | |
| 1403 | + if ($chg_field eq 'dl_src') { | |
| 1404 | + $chg_val = ${$test_pkt->{Ethernet_hdr}}->SA; | |
| 1405 | + } elsif ($chg_field eq 'dl_dst') { | |
| 1406 | + $chg_val = ${$test_pkt->{Ethernet_hdr}}->DA; | |
| 1407 | + } elsif ($chg_field eq 'nw_src') { | |
| 1408 | + $chg_val = ${$test_pkt->{IP_hdr}}->src_ip; | |
| 1409 | + } elsif ($chg_field eq 'nw_dst') { | |
| 1410 | + $chg_val = ${$test_pkt->{IP_hdr}}->dst_ip; | |
| 1411 | + } elsif ($chg_field eq 'tp_src') { | |
| 1412 | + $chg_val = ${$test_pkt->{UDP_pdu}}->SrcPort; | |
| 1413 | + } elsif ($chg_field eq 'tp_dst') { | |
| 1414 | + $chg_val = ${$test_pkt->{UDP_pdu}}->DstPort; | |
| 1415 | + } elsif ($chg_field eq 'vlan_vid') { | |
| 1416 | + if (defined $vlan_id) { | |
| 1417 | + $chg_val = ${$test_pkt->{Ethernet_hdr}}->VLAN_ID; | |
| 1418 | + } else { | |
| 1419 | + $chg_val = 0x999; #12-bit value | |
| 1420 | + } | |
| 1421 | + } elsif ($chg_field eq 'vlan_pcp') { | |
| 1422 | + if (defined $vlan_id) { | |
| 1423 | + $chg_val = ${$test_pkt->{Ethernet_hdr}}->VLAN_ID; | |
| 1424 | + } else { | |
| 1425 | + $chg_val = 0x6000; #Upper 3-bit is valid | |
| 1426 | + } | |
| 1427 | + } else { | |
| 1428 | + $chg_val = 0; | |
| 1429 | + } | |
| 1430 | + return $chg_val; | |
| 1431 | +} | |
| 1432 | + | |
| 1433 | +sub create_vlan_pkt { | |
| 1434 | + my ($in_port, $out_port, $pkt_len, $vlan_id, $chg_field) = @_; | |
| 1435 | + | |
| 1436 | + my $test_pkt_vlan; | |
| 1437 | + if ((defined $chg_field) && !(defined $vlan_id)) { | |
| 1438 | + if ($chg_field eq 'vlan_vid') { | |
| 1439 | + $test_pkt_vlan = get_default_black_box_pkt_len( $in_port, $out_port, $pkt_len, 0x999 ); | |
| 1440 | + } elsif ($chg_field eq 'vlan_pcp') { | |
| 1441 | + $test_pkt_vlan = get_default_black_box_pkt_len( $in_port, $out_port, $pkt_len, 0x6000 ); | |
| 1442 | + } | |
| 1443 | + } | |
| 1444 | + return $test_pkt_vlan; | |
| 1445 | +} | |
| 1446 | + | |
| 1447 | +sub replace_sending_pkt { | |
| 1448 | + my ($chg_field, $chg_val, $test_pkt, $vlan_id) = @_; | |
| 1449 | + | |
| 1450 | + my $dummy_chg_val; | |
| 1451 | + my $vlan_vid_val; | |
| 1452 | + my $vlan_pcp_val; | |
| 1453 | + if ($chg_field eq 'dl_src') { | |
| 1454 | + ${$test_pkt->{Ethernet_hdr}}->SA("12:34:56:78:9a:bc"); | |
| 1455 | + } elsif ($chg_field eq 'dl_dst') { | |
| 1456 | + ${$test_pkt->{Ethernet_hdr}}->DA("12:34:56:78:9a:bc"); | |
| 1457 | + } elsif ($chg_field eq 'nw_src') { | |
| 1458 | + ${$test_pkt->{IP_hdr}}->src_ip("111.122.133.144"); | |
| 1459 | + #Dummy rewrite in order to get re-calculated UDP checksum | |
| 1460 | + $dummy_chg_val = ${$test_pkt->{UDP_pdu}}->SrcPort; | |
| 1461 | + ${$test_pkt->{UDP_pdu}}->SrcPort($dummy_chg_val); | |
| 1462 | + } elsif ($chg_field eq 'nw_dst') { | |
| 1463 | + ${$test_pkt->{IP_hdr}}->dst_ip("111.122.133.144"); | |
| 1464 | + #Dummy rewrite in order to get re-calculated UDP checksum | |
| 1465 | + $dummy_chg_val = ${$test_pkt->{UDP_pdu}}->SrcPort; | |
| 1466 | + ${$test_pkt->{UDP_pdu}}->SrcPort($dummy_chg_val); | |
| 1467 | + } elsif ($chg_field eq 'tp_src') { | |
| 1468 | + ${$test_pkt->{UDP_pdu}}->SrcPort(55); | |
| 1469 | + } elsif ($chg_field eq 'tp_dst') { | |
| 1470 | + ${$test_pkt->{UDP_pdu}}->DstPort(55); | |
| 1471 | + } elsif ($chg_field eq 'vlan_vid') { | |
| 1472 | + if (defined $vlan_id) { | |
| 1473 | + $vlan_pcp_val = $chg_val & 0xe000; | |
| 1474 | + ${$test_pkt->{Ethernet_hdr}}->VLAN_ID(0x0987 | $vlan_pcp_val); | |
| 1475 | + } | |
| 1476 | + } elsif ($chg_field eq 'vlan_pcp') { | |
| 1477 | + if (defined $vlan_id) { | |
| 1478 | + $vlan_vid_val = $chg_val & 0x0fff; | |
| 1479 | + ${$test_pkt->{Ethernet_hdr}}->VLAN_ID(0x6000 | $vlan_vid_val); | |
| 1480 | + } | |
| 1481 | + } | |
| 1482 | + return $test_pkt; | |
| 1483 | +} | |
| 1484 | + | |
| 1485 | +sub generate_expect_packet { | |
| 1486 | + my ( $chg_field, $chg_val, $ip_checksum_org, $udp_checksum_org, $test_pkt, $test_pkt_novlan, $test_pkt_vlan, $vlan_id ) = @_; | |
| 1487 | + | |
| 1488 | + # Need to expect modified header value when modify action has been issued. | |
| 1489 | + # Replace the value accordingly. | |
| 1490 | + if ($chg_field eq 'dl_src') { | |
| 1491 | + ${$test_pkt->{Ethernet_hdr}}->SA("$chg_val"); | |
| 1492 | + } | |
| 1493 | + if ($chg_field eq 'dl_dst') { | |
| 1494 | + ${$test_pkt->{Ethernet_hdr}}->DA("$chg_val"); | |
| 1495 | + } | |
| 1496 | + if ($chg_field eq 'nw_src') { | |
| 1497 | + ${$test_pkt->{IP_hdr}}->src_ip("$chg_val"); | |
| 1498 | + ${$test_pkt->{IP_hdr}}->checksum($ip_checksum_org); | |
| 1499 | + ${$test_pkt->{UDP_pdu}}->Checksum($udp_checksum_org); | |
| 1500 | + } | |
| 1501 | + if ($chg_field eq 'nw_dst') { | |
| 1502 | + ${$test_pkt->{IP_hdr}}->dst_ip("$chg_val"); | |
| 1503 | + ${$test_pkt->{IP_hdr}}->checksum($ip_checksum_org); | |
| 1504 | + ${$test_pkt->{UDP_pdu}}->Checksum($udp_checksum_org); | |
| 1505 | + } | |
| 1506 | + if ($chg_field eq 'tp_src') { | |
| 1507 | + ${$test_pkt->{UDP_pdu}}->SrcPort("$chg_val"); | |
| 1508 | + } | |
| 1509 | + if ($chg_field eq 'tp_dst') { | |
| 1510 | + ${$test_pkt->{UDP_pdu}}->DstPort("$chg_val"); | |
| 1511 | + } | |
| 1512 | + if ($chg_field eq 'strip_vlan') { | |
| 1513 | + $test_pkt_novlan->{UDP_pdu} = $test_pkt->{UDP_pdu}; | |
| 1514 | + $test_pkt = $test_pkt_novlan; | |
| 1515 | + } | |
| 1516 | + if (($chg_field eq 'vlan_vid') || ($chg_field eq 'vlan_pcp')) { | |
| 1517 | + if (defined $vlan_id) { | |
| 1518 | + ${$test_pkt->{Ethernet_hdr}}->VLAN_ID("$chg_val"); | |
| 1519 | + } else { | |
| 1520 | + $test_pkt_vlan->{UDP_pdu} = $test_pkt->{UDP_pdu}; | |
| 1521 | + $test_pkt = $test_pkt_vlan; | |
| 1522 | + } | |
| 1523 | + } | |
| 1524 | + return $test_pkt; | |
| 1525 | +} | |
| 1526 | + | |
| 1527 | +sub forward_simple { | |
| 1528 | + | |
| 1529 | + my ( $ofp, $sock, $options_ref, $in_port_offset, $out_port_offset, | |
| 1530 | + $wildcards, $type, $nowait, $chg_field, $vlan_id, $cookie ) = @_; | |
| 1531 | + | |
| 1532 | + my $in_port = $in_port_offset + $$options_ref{'port_base'}; | |
| 1533 | + my $out_port; | |
| 1534 | + if ($type eq 'all') { | |
| 1535 | + $out_port = $enums{'OFPP_ALL'}; # all physical ports except the input | |
| 1536 | + } | |
| 1537 | + elsif ($type eq 'controller') { | |
| 1538 | + $out_port = $enums{'OFPP_CONTROLLER'}; #send to the secure channel | |
| 1539 | + } | |
| 1540 | + else { | |
| 1541 | + $out_port = $out_port_offset + $$options_ref{'port_base'}; | |
| 1542 | + } | |
| 1543 | + | |
| 1544 | + my $test_pkt = get_default_black_box_pkt_len( $in_port, $out_port, $$options_ref{'pkt_len'}, $vlan_id ); | |
| 1545 | + my $test_pkt_novlan = get_default_black_box_pkt_len( $in_port, $out_port, $$options_ref{'pkt_len'}) ; | |
| 1546 | + my $test_pkt_vlan = create_vlan_pkt( $in_port, $out_port, $$options_ref{'pkt_len'}, $vlan_id, $chg_field); | |
| 1547 | + | |
| 1548 | + #print HexDump ($test_pkt->packed); | |
| 1549 | + #print HexDump ($test_pkt_novlan->packed); | |
| 1550 | + #print HexDump ($test_pkt_vlan->packed); | |
| 1551 | + | |
| 1552 | + my $ip_checksum_org = ${$test_pkt->{IP_hdr}}->checksum; | |
| 1553 | + my $udp_checksum_org = ${$test_pkt->{UDP_pdu}}->Checksum; | |
| 1554 | + | |
| 1555 | + my $chg_val; | |
| 1556 | + my $send_pkt; | |
| 1557 | + if (defined $chg_field) { | |
| 1558 | + #Save original value | |
| 1559 | + $chg_val = get_original_value($chg_field, $test_pkt, $vlan_id); | |
| 1560 | + #Replace the test packet | |
| 1561 | + $test_pkt = replace_sending_pkt($chg_field, $chg_val, $test_pkt, $vlan_id); | |
| 1562 | + #Get the replaced vlan id | |
| 1563 | + if (defined $vlan_id) { | |
| 1564 | + $vlan_id = ${$test_pkt->{Ethernet_hdr}}->VLAN_ID; | |
| 1565 | + } | |
| 1566 | + } | |
| 1567 | + | |
| 1568 | + my $flow_mod_pkt; | |
| 1569 | + my $flags = $enums{'OFPFF_SEND_FLOW_REM'}; | |
| 1570 | + if ($type eq 'drop') { | |
| 1571 | + $flow_mod_pkt = create_flow_mod_from_udp_action( $ofp, $test_pkt, $in_port, $out_port, | |
| 1572 | + $$options_ref{'max_idle'}, $flags, | |
| 1573 | + $wildcards, 'drop', undef, undef, | |
| 1574 | + $vlan_id, undef, $cookie, undef); | |
| 1575 | + } elsif ($type eq 'enqueue') { | |
| 1576 | + my $queue_id = 1; | |
| 1577 | + $flow_mod_pkt = create_flow_mod_from_udp_action( $ofp, $test_pkt, $in_port, $out_port, | |
| 1578 | + $$options_ref{'max_idle'}, $flags, | |
| 1579 | + $wildcards, 'enqueue', undef, undef, | |
| 1580 | + $vlan_id, undef, $cookie, $queue_id); | |
| 1581 | + } else { | |
| 1582 | + $flow_mod_pkt = create_flow_mod_from_udp( $ofp, $test_pkt, $in_port, $out_port, | |
| 1583 | + $$options_ref{'max_idle'}, $flags, | |
| 1584 | + $wildcards, $chg_field, $chg_val, $vlan_id, | |
| 1585 | + undef, $cookie); | |
| 1586 | + } | |
| 1587 | + | |
| 1588 | + print HexDump($flow_mod_pkt); | |
| 1589 | + #print Dumper($flow_mod_pkt); | |
| 1590 | + | |
| 1591 | + # Send 'flow_mod' message | |
| 1592 | + syswrite( $sock, $flow_mod_pkt ); | |
| 1593 | + print "sent flow_mod message\n"; | |
| 1594 | + | |
| 1595 | + # Give OF switch time to process the flow mod | |
| 1596 | + usleep($$options_ref{'send_delay'}); | |
| 1597 | + | |
| 1598 | + nftest_send( "eth" . ($in_port_offset + 1), $test_pkt->packed ); | |
| 1599 | + | |
| 1600 | + my $expect_pkt; | |
| 1601 | + # Regenerate expected packet in case of performing modify_action | |
| 1602 | + if (defined $chg_field) { | |
| 1603 | + $expect_pkt = generate_expect_packet($chg_field, $chg_val, $ip_checksum_org, | |
| 1604 | + $udp_checksum_org, $test_pkt, $test_pkt_novlan, $test_pkt_vlan, $vlan_id); | |
| 1605 | + } else { | |
| 1606 | + $expect_pkt = $test_pkt; | |
| 1607 | + } | |
| 1608 | + | |
| 1609 | + if ($type eq 'any' || $type eq 'port' || $type eq 'enqueue') { | |
| 1610 | + # expect single packet | |
| 1611 | + print "expect single packet\n"; | |
| 1612 | + nftest_expect( "eth" . ( $out_port_offset + 1 ), $expect_pkt->packed ); | |
| 1613 | + } | |
| 1614 | + elsif ($type eq 'all') { | |
| 1615 | + # expect packets on all other interfaces | |
| 1616 | + print "expect multiple packets\n"; | |
| 1617 | + for ( my $k = 0 ; $k < $$options_ref{'num_ports'} ; $k++ ) { | |
| 1618 | + if ( $k != $in_port_offset ) { | |
| 1619 | + nftest_expect( "eth" . ( $k + 1), $expect_pkt->packed ); | |
| 1620 | + } | |
| 1621 | + } | |
| 1622 | + } | |
| 1623 | + elsif ($type eq 'controller') { | |
| 1624 | + # expect at controller | |
| 1625 | + | |
| 1626 | + my $recvd_mesg; | |
| 1627 | + sysread( $sock, $recvd_mesg, 1512 ) || die "Failed to receive message: $!"; | |
| 1628 | + | |
| 1629 | + # Inspect message | |
| 1630 | + my $msg_size = length($recvd_mesg); | |
| 1631 | + my $expected_size = $ofp->offsetof( 'ofp_packet_in', 'data' ) + length( $expect_pkt->packed ); | |
| 1632 | + compare( "ofp_packet_in msg size", $msg_size, '==', $expected_size ); | |
| 1633 | + | |
| 1634 | + my $msg = $ofp->unpack( 'ofp_packet_in', $recvd_mesg ); | |
| 1635 | + | |
| 1636 | + #print HexDump ($recvd_mesg); | |
| 1637 | + #print Dumper($msg); | |
| 1638 | + | |
| 1639 | + # Verify fields | |
| 1640 | + print "Verifying ofprotocol message for packet sent in to eth" . ( $in_port + 1 ) . "\n"; | |
| 1641 | + | |
| 1642 | + verify_header( $msg, 'OFPT_PACKET_IN', $msg_size ); | |
| 1643 | + | |
| 1644 | + compare( "ofp_packet_in total len", $$msg{'total_len'}, '==', length( $test_pkt->packed ) ); | |
| 1645 | + compare( "ofp_packet_in in_port", $$msg{'in_port'}, '==', $in_port ); | |
| 1646 | + compare( "ofp_packet_in reason", $$msg{'reason'}, '==', $enums{'OFPR_ACTION'} ); | |
| 1647 | + | |
| 1648 | + # verify packet was unchanged! | |
| 1649 | + my $recvd_pkt_data = substr( $recvd_mesg, $ofp->offsetof( 'ofp_packet_in', 'data' ) ); | |
| 1650 | + if ( $recvd_pkt_data ne $test_pkt->packed ) { | |
| 1651 | + die "ERROR: sending from eth" | |
| 1652 | + . ($in_port_offset + 1) | |
| 1653 | + . " received packet data didn't match packet sent\n"; | |
| 1654 | + } | |
| 1655 | + } | |
| 1656 | + elsif ($type eq 'drop') { | |
| 1657 | + # do nothing! | |
| 1658 | + } | |
| 1659 | + else { | |
| 1660 | + die "invalid input to forward_simple\n"; | |
| 1661 | + } | |
| 1662 | + | |
| 1663 | + my $pkt_len = $$options_ref{'pkt_len'}; | |
| 1664 | + if (defined $vlan_id) { | |
| 1665 | + $$options_ref{'pkt_len'} = $pkt_len + 4; | |
| 1666 | + } | |
| 1667 | + | |
| 1668 | + if (not defined($nowait)) { | |
| 1669 | + print "wait \n"; | |
| 1670 | + wait_for_flow_expired_all( $ofp, $sock, $options_ref ); | |
| 1671 | + } | |
| 1672 | + | |
| 1673 | + $$options_ref{'pkt_len'} = $pkt_len; | |
| 1674 | +} | |
| 1675 | + | |
| 1676 | + | |
| 1677 | +#Sub functions for ICMP handling tests | |
| 1678 | + | |
| 1679 | +sub get_default_black_box_pkt_len_icmp { | |
| 1680 | + my ($in_port, $out_port, $len) = @_; | |
| 1681 | + | |
| 1682 | + my $pkt_args = { | |
| 1683 | + DA => "00:00:00:00:00:" . sprintf( "%02d", $out_port ), | |
| 1684 | + SA => "00:00:00:00:00:" . sprintf( "%02d", $in_port ), | |
| 1685 | + src_ip => "192.168.200." . ( $in_port ), | |
| 1686 | + dst_ip => "192.168.201." . ( $out_port ), | |
| 1687 | + ttl => 64, | |
| 1688 | + len => $len, | |
| 1689 | + src_port => 1, | |
| 1690 | + dst_port => 0 | |
| 1691 | + }; | |
| 1692 | + return new_icmp_test_pkt NF2::ICMP_pkt(%$pkt_args); | |
| 1693 | +} | |
| 1694 | + | |
| 1695 | +#Sub functions for ICMP handling tests | |
| 1696 | + | |
| 1697 | +sub get_default_black_box_pkt_len_arp { | |
| 1698 | + my ($in_port, $out_port, $len) = @_; | |
| 1699 | + | |
| 1700 | + my $pkt_args = { | |
| 1701 | + DA => "00:00:00:00:00:" . sprintf( "%02d", $out_port ), | |
| 1702 | + SA => "00:00:00:00:00:" . sprintf( "%02d", $in_port ), | |
| 1703 | + SenderIpAddr => "192.168.200." . ( $in_port ), | |
| 1704 | + SenderEthAddr => "00:00:00:00:01:" . sprintf("%02d", $in_port), | |
| 1705 | + TargetIpAddr => "192.168.201." . ( $out_port ), | |
| 1706 | + TargetEthAddr => "ff:ff:ff:ff:ff:ff", | |
| 1707 | + len => $len, | |
| 1708 | + }; | |
| 1709 | + return new_arp_test_pkt NF2::ARP_pkt(%$pkt_args); | |
| 1710 | +} | |
| 1711 | + | |
| 1712 | +sub create_flow_mod_from_icmp { | |
| 1713 | + | |
| 1714 | + my ( $ofp, $icmp_pkt, $in_port, $out_port, $max_idle, $flags, $wildcards, $fool ) = @_; | |
| 1715 | + | |
| 1716 | + my $flow_mod_pkt; | |
| 1717 | + | |
| 1718 | + $flow_mod_pkt = | |
| 1719 | + create_flow_mod_from_icmp_action( $ofp, $icmp_pkt, $in_port, $out_port, $max_idle, $flags, $wildcards, | |
| 1720 | + 'OFPFC_ADD', $fool, $cookie ); | |
| 1721 | + | |
| 1722 | + return $flow_mod_pkt; | |
| 1723 | +} | |
| 1724 | + | |
| 1725 | +sub create_flow_mod_from_icmp_action { | |
| 1726 | + | |
| 1727 | + my ( $ofp, $udp_pkt, $in_port, $out_port, $max_idle, $flags, | |
| 1728 | + $wildcards, $mod_type, $fool, $cookie ) = @_; | |
| 1729 | + | |
| 1730 | + $cookie = 0 if !defined($cookie); | |
| 1731 | + | |
| 1732 | + if ( $mod_type ne 'OFPFC_ADD' | |
| 1733 | + && $mod_type ne 'OFPFC_DELETE' | |
| 1734 | + && $mod_type ne 'OFPFC_DELETE_STRICT' ) | |
| 1735 | + { | |
| 1736 | + die "Undefined flow mod type: $mod_type\n"; | |
| 1737 | + } | |
| 1738 | + | |
| 1739 | + my $hdr_args = { | |
| 1740 | + version => $of_ver, | |
| 1741 | + type => $enums{'OFPT_FLOW_MOD'}, | |
| 1742 | + length => $ofp->sizeof('ofp_flow_mod') + $ofp->sizeof('ofp_action_output'), | |
| 1743 | + xid => 0x0000000 | |
| 1744 | + }; | |
| 1745 | + | |
| 1746 | + # might be cleaner to convert the exported colon-hex MAC addrs | |
| 1747 | + #print ${$udp_pkt->{Ethernet_hdr}}->SA . "\n"; | |
| 1748 | + #print ${$test_pkt->{Ethernet_hdr}}->SA . "\n"; | |
| 1749 | + my $ref_to_eth_hdr = ( $udp_pkt->{'Ethernet_hdr'} ); | |
| 1750 | + my $ref_to_ip_hdr = ( $udp_pkt->{'IP_hdr'} ); | |
| 1751 | + | |
| 1752 | + # pointer to array | |
| 1753 | + my $eth_hdr_bytes = $$ref_to_eth_hdr->{'bytes'}; | |
| 1754 | + my $ip_hdr_bytes = $$ref_to_ip_hdr->{'bytes'}; | |
| 1755 | + my @dst_mac_subarray = @{$eth_hdr_bytes}[ 0 .. 5 ]; | |
| 1756 | + my @src_mac_subarray = @{$eth_hdr_bytes}[ 6 .. 11 ]; | |
| 1757 | + | |
| 1758 | + my @src_ip_subarray = @{$ip_hdr_bytes}[ 12 .. 15 ]; | |
| 1759 | + my @dst_ip_subarray = @{$ip_hdr_bytes}[ 16 .. 19 ]; | |
| 1760 | + | |
| 1761 | + my $src_ip = | |
| 1762 | + ( ( 2**24 ) * $src_ip_subarray[0] + | |
| 1763 | + ( 2**16 ) * $src_ip_subarray[1] + | |
| 1764 | + ( 2**8 ) * $src_ip_subarray[2] + | |
| 1765 | + $src_ip_subarray[3] ); | |
| 1766 | + | |
| 1767 | + my $dst_ip = | |
| 1768 | + ( ( 2**24 ) * $dst_ip_subarray[0] + | |
| 1769 | + ( 2**16 ) * $dst_ip_subarray[1] + | |
| 1770 | + ( 2**8 ) * $dst_ip_subarray[2] + | |
| 1771 | + $dst_ip_subarray[3] ); | |
| 1772 | + | |
| 1773 | + my $icmp_type; | |
| 1774 | + if ($fool == 1) { | |
| 1775 | + $icmp_type = ~(${ $udp_pkt->{ICMP_pdu} }->Type); | |
| 1776 | + } else { | |
| 1777 | + $icmp_type = (${ $udp_pkt->{ICMP_pdu} }->Type); | |
| 1778 | + } | |
| 1779 | + | |
| 1780 | + my $icmp_code = ${ $udp_pkt->{ICMP_pdu} }->Code; | |
| 1781 | + | |
| 1782 | + my $match_args = { | |
| 1783 | + wildcards => $wildcards, | |
| 1784 | + in_port => $in_port, | |
| 1785 | + dl_src => \@src_mac_subarray, | |
| 1786 | + dl_dst => \@dst_mac_subarray, | |
| 1787 | + dl_vlan => 0xffff, | |
| 1788 | + dl_type => 0x0800, | |
| 1789 | + dl_vlan_pcp => 0x00, | |
| 1790 | + nw_src => $src_ip, | |
| 1791 | + nw_dst => $dst_ip, | |
| 1792 | + nw_tos => 0, | |
| 1793 | + nw_proto => 1, #ICMP | |
| 1794 | + tp_src => $icmp_type, | |
| 1795 | + tp_dst => $icmp_code | |
| 1796 | + }; | |
| 1797 | + | |
| 1798 | + my $max_len; | |
| 1799 | + if ($out_port != $enums{'OFPP_CONTROLLER'}) { | |
| 1800 | + $max_len = 0; | |
| 1801 | + } else { | |
| 1802 | + $max_len = 65535; | |
| 1803 | + } | |
| 1804 | + my $action_output_args = { | |
| 1805 | + type => $enums{'OFPAT_OUTPUT'}, | |
| 1806 | + len => $ofp->sizeof('ofp_action_output'), | |
| 1807 | + port => $out_port, | |
| 1808 | + max_len => $max_len, | |
| 1809 | + }; | |
| 1810 | + | |
| 1811 | + my $action_output = $ofp->pack( 'ofp_action_output', $action_output_args ); | |
| 1812 | + | |
| 1813 | + my $flow_mod_args = { | |
| 1814 | + header => $hdr_args, | |
| 1815 | + match => $match_args, | |
| 1816 | + | |
| 1817 | + # command => $enums{$mod_type}, | |
| 1818 | + command => $enums{"$mod_type"}, | |
| 1819 | + idle_timeout => $max_idle, | |
| 1820 | + hard_timeout => $max_idle, | |
| 1821 | + flags => $flags, | |
| 1822 | + priority => 0, | |
| 1823 | + buffer_id => -1, | |
| 1824 | + out_port => $enums{'OFPP_NONE'}, | |
| 1825 | + cookie => $cookie, | |
| 1826 | + }; | |
| 1827 | + my $flow_mod = $ofp->pack( 'ofp_flow_mod', $flow_mod_args ); | |
| 1828 | + | |
| 1829 | + my $flow_mod_pkt = $flow_mod . $action_output; | |
| 1830 | + | |
| 1831 | + return $flow_mod_pkt; | |
| 1832 | +} | |
| 1833 | + | |
| 1834 | +sub create_flow_mod_from_arp { | |
| 1835 | + | |
| 1836 | + my ( $ofp, $icmp_pkt, $in_port, $out_port, $max_idle, $flags, $wildcards, $fool ) = @_; | |
| 1837 | + | |
| 1838 | + my $flow_mod_pkt; | |
| 1839 | + | |
| 1840 | + $flow_mod_pkt = | |
| 1841 | + create_flow_mod_from_arp_action( $ofp, $icmp_pkt, $in_port, $out_port, $max_idle, $flags, $wildcards, | |
| 1842 | + 'OFPFC_ADD', $fool ); | |
| 1843 | + | |
| 1844 | + return $flow_mod_pkt; | |
| 1845 | +} | |
| 1846 | + | |
| 1847 | +sub create_flow_mod_from_arp_action { | |
| 1848 | + | |
| 1849 | + my ( $ofp, $udp_pkt, $in_port, $out_port, $max_idle, $flags, $wildcards, $mod_type, $fool ) = @_; | |
| 1850 | + | |
| 1851 | + if ( $mod_type ne 'OFPFC_ADD' | |
| 1852 | + && $mod_type ne 'OFPFC_DELETE' | |
| 1853 | + && $mod_type ne 'OFPFC_DELETE_STRICT' ) | |
| 1854 | + { | |
| 1855 | + die "Undefined flow mod type: $mod_type\n"; | |
| 1856 | + } | |
| 1857 | + | |
| 1858 | + my $hdr_args = { | |
| 1859 | + version => $of_ver, | |
| 1860 | + type => $enums{'OFPT_FLOW_MOD'}, | |
| 1861 | + length => $ofp->sizeof('ofp_flow_mod') + $ofp->sizeof('ofp_action_output'), | |
| 1862 | + xid => 0x0000000 | |
| 1863 | + }; | |
| 1864 | + | |
| 1865 | + # might be cleaner to convert the exported colon-hex MAC addrs | |
| 1866 | + #print ${$udp_pkt->{Ethernet_hdr}}->SA . "\n"; | |
| 1867 | + #print ${$test_pkt->{Ethernet_hdr}}->SA . "\n"; | |
| 1868 | + my $ref_to_eth_hdr = ( $udp_pkt->{'Ethernet_hdr'} ); | |
| 1869 | + my $ref_to_arp_hdr = ( $udp_pkt->{'ARP_hdr'} ); | |
| 1870 | + | |
| 1871 | + # pointer to array | |
| 1872 | + my $eth_hdr_bytes = $$ref_to_eth_hdr->{'bytes'}; | |
| 1873 | + my $arp_hdr_bytes = $$ref_to_arp_hdr->{'bytes'}; | |
| 1874 | + my @dst_mac_subarray = @{$eth_hdr_bytes}[ 0 .. 5 ]; | |
| 1875 | + my @src_mac_subarray = @{$eth_hdr_bytes}[ 6 .. 11 ]; | |
| 1876 | + | |
| 1877 | + my @src_ip_subarray = @{$arp_hdr_bytes}[ 14 .. 17 ]; | |
| 1878 | + my @dst_ip_subarray = @{$arp_hdr_bytes}[ 24 .. 27 ]; | |
| 1879 | + | |
| 1880 | + my $src_ip = | |
| 1881 | + ( ( 2**24 ) * $src_ip_subarray[0] + | |
| 1882 | + ( 2**16 ) * $src_ip_subarray[1] + | |
| 1883 | + ( 2**8 ) * $src_ip_subarray[2] + | |
| 1884 | + $src_ip_subarray[3] ); | |
| 1885 | + | |
| 1886 | + my $dst_ip = | |
| 1887 | + ( ( 2**24 ) * $dst_ip_subarray[0] + | |
| 1888 | + ( 2**16 ) * $dst_ip_subarray[1] + | |
| 1889 | + ( 2**8 ) * $dst_ip_subarray[2] + | |
| 1890 | + $dst_ip_subarray[3] ); | |
| 1891 | + | |
| 1892 | + my $arp_opcode; | |
| 1893 | + if ($fool == 1) { | |
| 1894 | + $arp_opcode = ~(${$ref_to_arp_hdr}->Op); | |
| 1895 | + } else { | |
| 1896 | + $arp_opcode = (${$ref_to_arp_hdr}->Op); | |
| 1897 | + } | |
| 1898 | + | |
| 1899 | + my $match_args = { | |
| 1900 | + wildcards => $wildcards, | |
| 1901 | + in_port => $in_port, | |
| 1902 | + dl_src => \@src_mac_subarray, | |
| 1903 | + dl_dst => \@dst_mac_subarray, | |
| 1904 | + dl_vlan => 0xffff, | |
| 1905 | + dl_type => 0x0806, | |
| 1906 | + dl_vlan_pcp => 0x00, | |
| 1907 | + nw_src => $src_ip, | |
| 1908 | + nw_dst => $dst_ip, | |
| 1909 | + nw_proto => $arp_opcode, | |
| 1910 | + tp_src => 0x0000, | |
| 1911 | + tp_dst => 0x0000 | |
| 1912 | + }; | |
| 1913 | + | |
| 1914 | + my $max_len; | |
| 1915 | + if ($out_port != $enums{'OFPP_CONTROLLER'}) { | |
| 1916 | + $max_len = 0; | |
| 1917 | + } else { | |
| 1918 | + $max_len = 65535; | |
| 1919 | + } | |
| 1920 | + my $action_output_args = { | |
| 1921 | + type => $enums{'OFPAT_OUTPUT'}, | |
| 1922 | + len => $ofp->sizeof('ofp_action_output'), | |
| 1923 | + port => $out_port, | |
| 1924 | + max_len => $max_len, | |
| 1925 | + }; | |
| 1926 | + | |
| 1927 | + my $action_output = $ofp->pack( 'ofp_action_output', $action_output_args ); | |
| 1928 | + | |
| 1929 | + my $flow_mod_args = { | |
| 1930 | + header => $hdr_args, | |
| 1931 | + match => $match_args, | |
| 1932 | + | |
| 1933 | + # command => $enums{$mod_type}, | |
| 1934 | + command => $enums{"$mod_type"}, | |
| 1935 | + idle_timeout => $max_idle, | |
| 1936 | + hard_timeout => $max_idle, | |
| 1937 | + flags => $flags, | |
| 1938 | + priority => 0, | |
| 1939 | + buffer_id => -1, | |
| 1940 | + out_port => $enums{'OFPP_NONE'} | |
| 1941 | + }; | |
| 1942 | + my $flow_mod = $ofp->pack( 'ofp_flow_mod', $flow_mod_args ); | |
| 1943 | + | |
| 1944 | + my $flow_mod_pkt = $flow_mod . $action_output; | |
| 1945 | + | |
| 1946 | + return $flow_mod_pkt; | |
| 1947 | +} | |
| 1948 | + | |
| 1949 | +sub forward_simple_icmp { | |
| 1950 | + | |
| 1951 | + my ( $ofp, $sock, $options_ref, $in_port_offset, $out_port_offset, $wildcards, $type, $fool, $nowait ) = @_; | |
| 1952 | + | |
| 1953 | + my $in_port = $in_port_offset + $$options_ref{'port_base'}; | |
| 1954 | + my $out_port; | |
| 1955 | + | |
| 1956 | + my $fool_port = 0; | |
| 1957 | + my $flow_mod_pkt_fool; | |
| 1958 | + | |
| 1959 | + my $flags = $enums{'OFPFF_SEND_FLOW_REM'}; | |
| 1960 | + | |
| 1961 | + if ($type eq 'all') { | |
| 1962 | + $out_port = $enums{'OFPP_ALL'}; # all physical ports except the input | |
| 1963 | + } | |
| 1964 | + elsif ($type eq 'controller') { | |
| 1965 | + $out_port = $enums{'OFPP_CONTROLLER'}; #send to the secure channel | |
| 1966 | + } | |
| 1967 | + else { | |
| 1968 | + $out_port = $out_port_offset + $$options_ref{'port_base'}; | |
| 1969 | + } | |
| 1970 | + | |
| 1971 | + if ($fool == 1) { | |
| 1972 | + $fool_port = ($out_port_offset + $$options_ref{'port_base'} + 1) % $$options_ref{'num_ports'}; | |
| 1973 | + if ($fool_port == $in_port) { | |
| 1974 | + $fool_port = ($out_port_offset + $$options_ref{'port_base'} + 2) % $$options_ref{'num_ports'}; | |
| 1975 | + } | |
| 1976 | + } | |
| 1977 | + | |
| 1978 | + my $test_pkt = get_default_black_box_pkt_len_icmp( $in_port, $out_port, $$options_ref{'pkt_len'} ); | |
| 1979 | + | |
| 1980 | + #print HexDump ( $test_pkt->packed ); | |
| 1981 | + | |
| 1982 | + if (($fool == 1) && ($type eq 'port') && ($wildcards != 0x40)) { | |
| 1983 | + my $flow_mod_pkt_fool = | |
| 1984 | + create_flow_mod_from_icmp( $ofp, $test_pkt, $in_port, $fool_port, $$options_ref{'max_idle'}, $flags, $wildcards, $fool ); | |
| 1985 | + print HexDump($flow_mod_pkt_fool); | |
| 1986 | + #print Dumper($flow_mod_pkt_fool); | |
| 1987 | + # Send 'flow_mod' message | |
| 1988 | + print $sock $flow_mod_pkt_fool; | |
| 1989 | + print "sent flow_mod message\n"; | |
| 1990 | + # Give OF switch time to process the flow mod | |
| 1991 | + usleep($$options_ref{'send_delay'}); | |
| 1992 | + } | |
| 1993 | + | |
| 1994 | + my $flow_mod_pkt = | |
| 1995 | + create_flow_mod_from_icmp( $ofp, $test_pkt, $in_port, $out_port, $$options_ref{'max_idle'}, $flags, $wildcards, 0 ); | |
| 1996 | + | |
| 1997 | + #print HexDump($flow_mod_pkt); | |
| 1998 | + #print Dumper($flow_mod_pkt); | |
| 1999 | + | |
| 2000 | + # Send 'flow_mod' message | |
| 2001 | + print $sock $flow_mod_pkt; | |
| 2002 | + print "sent flow_mod message\n"; | |
| 2003 | + | |
| 2004 | + # Give OF switch time to process the flow mod | |
| 2005 | + usleep($$options_ref{'send_delay'}); | |
| 2006 | + | |
| 2007 | + nftest_send( "eth" . ($in_port_offset + 1), $test_pkt->packed ); | |
| 2008 | + #print HexDump($test_pkt->packed); | |
| 2009 | + | |
| 2010 | + if ($type eq 'any' || $type eq 'port') { | |
| 2011 | + # expect single packet | |
| 2012 | + print "expect single packet\n"; | |
| 2013 | + nftest_expect( "eth" . ( $out_port_offset + 1 ), $test_pkt->packed ); | |
| 2014 | + } | |
| 2015 | + elsif ($type eq 'all') { | |
| 2016 | + # expect packets on all other interfaces | |
| 2017 | + print "expect multiple packets\n"; | |
| 2018 | + for ( my $k = 0 ; $k < $$options_ref{'num_ports'} ; $k++ ) { | |
| 2019 | + if ( $k != $in_port_offset ) { | |
| 2020 | + nftest_expect( "eth" . ( $k + 1), $test_pkt->packed ); | |
| 2021 | + } | |
| 2022 | + } | |
| 2023 | + } | |
| 2024 | + elsif ($type eq 'controller') { | |
| 2025 | + # expect at controller | |
| 2026 | + | |
| 2027 | + my $recvd_mesg; | |
| 2028 | + sysread( $sock, $recvd_mesg, 1512 ) || die "Failed to receive message: $!"; | |
| 2029 | + | |
| 2030 | + # Inspect message | |
| 2031 | + my $msg_size = length($recvd_mesg); | |
| 2032 | + my $expected_size = $ofp->offsetof( 'ofp_packet_in', 'data' ) + length( $test_pkt->packed ); | |
| 2033 | + compare( "ofp_packet_in icmp msg size", $msg_size, '==', $expected_size ); | |
| 2034 | + | |
| 2035 | + my $msg = $ofp->unpack( 'ofp_packet_in', $recvd_mesg ); | |
| 2036 | + | |
| 2037 | + #print HexDump ($recvd_mesg); | |
| 2038 | + #print Dumper($msg); | |
| 2039 | + | |
| 2040 | + # Verify fields | |
| 2041 | + print "Verifying ofprotocol message for packet sent in to eth" . ( $in_port + 1 ) . "\n"; | |
| 2042 | + | |
| 2043 | + verify_header( $msg, 'OFPT_PACKET_IN', $msg_size ); | |
| 2044 | + | |
| 2045 | + compare( "ofp_packet_in icmp total len", $$msg{'total_len'}, '==', length( $test_pkt->packed ) ); | |
| 2046 | + compare( "ofp_packet_in icmp in_port", $$msg{'in_port'}, '==', $in_port ); | |
| 2047 | + compare( "ofp_packet_in icmp reason", $$msg{'reason'}, '==', $enums{'OFPR_ACTION'} ); | |
| 2048 | + | |
| 2049 | + # verify packet was unchanged! | |
| 2050 | + my $recvd_pkt_data = substr( $recvd_mesg, $ofp->offsetof( 'ofp_packet_in', 'data' ) ); | |
| 2051 | + if ( $recvd_pkt_data ne $test_pkt->packed ) { | |
| 2052 | + die "ERROR: sending from eth" | |
| 2053 | + . ($in_port_offset + 1) | |
| 2054 | + . " received packet data didn't match packet sent\n"; | |
| 2055 | + } | |
| 2056 | + } | |
| 2057 | + else { | |
| 2058 | + die "invalid input to forward_simple_icmp\n"; | |
| 2059 | + } | |
| 2060 | + | |
| 2061 | + my $pkt_len = $$options_ref{'pkt_len'}; | |
| 2062 | + if (defined $vlan_id) { | |
| 2063 | + $$options_ref{'pkt_len'} = $pkt_len + 4; | |
| 2064 | + } | |
| 2065 | + | |
| 2066 | + if (not defined($nowait)) { | |
| 2067 | + print "wait \n"; | |
| 2068 | + if ($fool == 1) { | |
| 2069 | + print "wait for two flow exprired\n"; | |
| 2070 | + wait_for_two_flow_expired( $ofp, $sock, $$options_ref{'pkt_len'}, $$options_ref{'pkt_total'} ); | |
| 2071 | + } else { | |
| 2072 | + print "wait for flow expired\n"; | |
| 2073 | + wait_for_flow_expired( $ofp, $sock, $options_ref, $$options_ref{'pkt_len'}, $$options_ref{'pkt_total'} ); | |
| 2074 | + } | |
| 2075 | + } | |
| 2076 | +} | |
| 2077 | + | |
| 2078 | +sub forward_simple_arp { | |
| 2079 | + | |
| 2080 | + my ( $ofp, $sock, $options_ref, $in_port_offset, $out_port_offset, $wildcards, $type, $fool, $nowait ) = @_; | |
| 2081 | + | |
| 2082 | + my $in_port = $in_port_offset + $$options_ref{'port_base'}; | |
| 2083 | + my $out_port; | |
| 2084 | + | |
| 2085 | + my $fool_port = 0; | |
| 2086 | + my $flow_mod_pkt_fool; | |
| 2087 | + | |
| 2088 | + my $flags = $enums{'OFPFF_SEND_FLOW_REM'}; | |
| 2089 | + | |
| 2090 | + if ($type eq 'all') { | |
| 2091 | + $out_port = $enums{'OFPP_ALL'}; # all physical ports except the input | |
| 2092 | + } | |
| 2093 | + elsif ($type eq 'controller') { | |
| 2094 | + $out_port = $enums{'OFPP_CONTROLLER'}; #send to the secure channel | |
| 2095 | + } | |
| 2096 | + else { | |
| 2097 | + $out_port = $out_port_offset + $$options_ref{'port_base'}; | |
| 2098 | + } | |
| 2099 | + | |
| 2100 | + if ($fool == 1) { | |
| 2101 | + $fool_port = ($out_port_offset + $$options_ref{'port_base'} + 1) % $$options_ref{'num_ports'}; | |
| 2102 | + if ($fool_port == $in_port) { | |
| 2103 | + $fool_port = ($out_port_offset + $$options_ref{'port_base'} + 2) % $$options_ref{'num_ports'}; | |
| 2104 | + } | |
| 2105 | + } | |
| 2106 | + | |
| 2107 | + my $test_pkt = get_default_black_box_pkt_len_arp( $in_port, $out_port, $$options_ref{'pkt_len'} ); | |
| 2108 | + | |
| 2109 | + #print HexDump ( $test_pkt->packed ); | |
| 2110 | + | |
| 2111 | + if (($fool == 1) && ($type eq 'port') && ($wildcards != 0x40)) { | |
| 2112 | + my $flow_mod_pkt_fool = | |
| 2113 | + create_flow_mod_from_arp( $ofp, $test_pkt, $in_port, $fool_port, $$options_ref{'max_idle'}, $flags, $wildcards, $fool ); | |
| 2114 | + print HexDump($flow_mod_pkt_fool); | |
| 2115 | + #print Dumper($flow_mod_pkt_fool); | |
| 2116 | + # Send 'flow_mod' message | |
| 2117 | + print $sock $flow_mod_pkt_fool; | |
| 2118 | + print "sent flow_mod message\n"; | |
| 2119 | + # Give OF switch time to process the flow mod | |
| 2120 | + usleep($$options_ref{'send_delay'}); | |
| 2121 | + } | |
| 2122 | + | |
| 2123 | + my $flow_mod_pkt = | |
| 2124 | + create_flow_mod_from_arp( $ofp, $test_pkt, $in_port, $out_port, $$options_ref{'max_idle'}, $flags, $wildcards, 0 ); | |
| 2125 | + | |
| 2126 | + #print HexDump($flow_mod_pkt); | |
| 2127 | + #print Dumper($flow_mod_pkt); | |
| 2128 | + | |
| 2129 | + # Send 'flow_mod' message | |
| 2130 | + print $sock $flow_mod_pkt; | |
| 2131 | + print "sent flow_mod message\n"; | |
| 2132 | + | |
| 2133 | + # Give OF switch time to process the flow mod | |
| 2134 | + usleep($$options_ref{'send_delay'}); | |
| 2135 | + | |
| 2136 | + nftest_send( "eth" . ($in_port_offset + 1), $test_pkt->packed ); | |
| 2137 | + #print HexDump($test_pkt->packed); | |
| 2138 | + | |
| 2139 | + if ($type eq 'any' || $type eq 'port') { | |
| 2140 | + # expect single packet | |
| 2141 | + print "expect single packet\n"; | |
| 2142 | + nftest_expect( "eth" . ( $out_port_offset + 1 ), $test_pkt->packed ); | |
| 2143 | + } | |
| 2144 | + elsif ($type eq 'all') { | |
| 2145 | + # expect packets on all other interfaces | |
| 2146 | + print "expect multiple packets\n"; | |
| 2147 | + for ( my $k = 0 ; $k < $$options_ref{'num_ports'} ; $k++ ) { | |
| 2148 | + if ( $k != $in_port_offset ) { | |
| 2149 | + nftest_expect( "eth" . ( $k + 1), $test_pkt->packed ); | |
| 2150 | + } | |
| 2151 | + } | |
| 2152 | + } | |
| 2153 | + elsif ($type eq 'controller') { | |
| 2154 | + # expect at controller | |
| 2155 | + | |
| 2156 | + my $recvd_mesg; | |
| 2157 | + sysread( $sock, $recvd_mesg, 1512 ) || die "Failed to receive message: $!"; | |
| 2158 | + | |
| 2159 | + # Inspect message | |
| 2160 | + my $msg_size = length($recvd_mesg); | |
| 2161 | + my $expected_size = $ofp->offsetof( 'ofp_packet_in', 'data' ) + length( $test_pkt->packed ); | |
| 2162 | + compare( "ofp_packet_in arp msg size", $msg_size, '==', $expected_size ); | |
| 2163 | + | |
| 2164 | + my $msg = $ofp->unpack( 'ofp_packet_in', $recvd_mesg ); | |
| 2165 | + | |
| 2166 | + #print HexDump ($recvd_mesg); | |
| 2167 | + #print Dumper($msg); | |
| 2168 | + | |
| 2169 | + # Verify fields | |
| 2170 | + print "Verifying ofprotocol message for packet sent in to eth" . ( $in_port + 1 ) . "\n"; | |
| 2171 | + | |
| 2172 | + verify_header( $msg, 'OFPT_PACKET_IN', $msg_size ); | |
| 2173 | + | |
| 2174 | + compare( "ofp_packet_in arp total len", $$msg{'total_len'}, '==', length( $test_pkt->packed ) ); | |
| 2175 | + compare( "ofp_packet_in arp in_port", $$msg{'in_port'}, '==', $in_port ); | |
| 2176 | + compare( "ofp_packet_in arp reason", $$msg{'reason'}, '==', $enums{'OFPR_ACTION'} ); | |
| 2177 | + | |
| 2178 | + # verify packet was unchanged! | |
| 2179 | + my $recvd_pkt_data = substr( $recvd_mesg, $ofp->offsetof( 'ofp_packet_in', 'data' ) ); | |
| 2180 | + if ( $recvd_pkt_data ne $test_pkt->packed ) { | |
| 2181 | + die "ERROR: sending from eth" | |
| 2182 | + . ($in_port_offset + 1) | |
| 2183 | + . " received packet data didn't match packet sent\n"; | |
| 2184 | + } | |
| 2185 | + } | |
| 2186 | + else { | |
| 2187 | + die "invalid input to forward_simple_arp\n"; | |
| 2188 | + } | |
| 2189 | + | |
| 2190 | + my $pkt_len = $$options_ref{'pkt_len'}; | |
| 2191 | + if (defined $vlan_id) { | |
| 2192 | + $$options_ref{'pkt_len'} = $pkt_len + 4; | |
| 2193 | + } | |
| 2194 | + | |
| 2195 | + if (not defined($nowait)) { | |
| 2196 | + print "wait \n"; | |
| 2197 | + if ($fool == 1) { | |
| 2198 | + print "wait for two flow exprired\n"; | |
| 2199 | + wait_for_two_flow_expired( $ofp, $sock, $$options_ref{'pkt_len'}, $$options_ref{'pkt_total'} ); | |
| 2200 | + } else { | |
| 2201 | + print "wait for flow expired\n"; | |
| 2202 | + wait_for_flow_expired( $ofp, $sock, $options_ref, $$options_ref{'pkt_len'}, $$options_ref{'pkt_total'} ); | |
| 2203 | + } | |
| 2204 | + } | |
| 2205 | +} | |
| 2206 | + | |
| 2207 | +sub wait_for_two_flow_expired { | |
| 2208 | + | |
| 2209 | + my ( $ofp, $sock, $pkt_len, $pkt_total ) = @_; | |
| 2210 | + my $read_size = 1512; | |
| 2211 | + my $pkt_total_size = $pkt_len * $pkt_total; | |
| 2212 | + | |
| 2213 | + my $recvd_mesg; | |
| 2214 | + | |
| 2215 | + sysread( $sock, $recvd_mesg, $read_size ) | |
| 2216 | + || die "Failed to receive message: $!"; | |
| 2217 | + | |
| 2218 | + #print HexDump ($recvd_mesg); | |
| 2219 | + | |
| 2220 | + # Inspect message | |
| 2221 | + my $msg_size = length($recvd_mesg); | |
| 2222 | + my $expected_size = $ofp->sizeof('ofp_flow_removed'); | |
| 2223 | + #compare( "msg size", length($recvd_mesg), '==', $expected_size ); | |
| 2224 | + | |
| 2225 | + my $msg = $ofp->unpack( 'ofp_flow_removed', $recvd_mesg ); | |
| 2226 | + | |
| 2227 | + #print Dumper($msg); | |
| 2228 | + | |
| 2229 | + # Verify fields | |
| 2230 | + #compare( "header version", $$msg{'header'}{'version'}, '==', $of_ver ); | |
| 2231 | + #compare( "header type", $$msg{'header'}{'type'}, '==', $enums{'OFPT_FLOW_REMOVED'} ); | |
| 2232 | + #compare( "header length", $$msg{'header'}{'length'}, '==', $msg_size ); | |
| 2233 | + #compare( "byte_count", $$msg{'byte_count'}, '==', $bytes ); | |
| 2234 | + #compare( "packet_count", $$msg{'packet_count'}, '==', $pkt_total_size ); | |
| 2235 | + sleep 3; | |
| 2236 | +} | |
| 2237 | + | |
| 2238 | +sub wait_for_echo_request { | |
| 2239 | + | |
| 2240 | + my ( $ofp, $sock, $options_ref, $read_size_ ) = @_; | |
| 2241 | + my $read_size; | |
| 2242 | + | |
| 2243 | + if ( defined $read_size_ ) { | |
| 2244 | + $read_size = $read_size_; | |
| 2245 | + } else { | |
| 2246 | + $read_size = 1512; | |
| 2247 | + } | |
| 2248 | + | |
| 2249 | + my $recvd_mesg; | |
| 2250 | + sysread( $sock, $recvd_mesg, $read_size ) | |
| 2251 | + || die "Failed to receive ofp_echo_request message: $!"; | |
| 2252 | + | |
| 2253 | + #print HexDump ($recvd_mesg); | |
| 2254 | + | |
| 2255 | + # Inspect message | |
| 2256 | + my $msg_size = length($recvd_mesg); | |
| 2257 | + my $expected_size = $ofp->sizeof('ofp_header'); | |
| 2258 | + compare( "ofp_echo_reply msg size", length($recvd_mesg), '==', $expected_size ); | |
| 2259 | + | |
| 2260 | + my $msg = $ofp->unpack( 'ofp_header', $recvd_mesg ); | |
| 2261 | + | |
| 2262 | + #print Dumper($msg); | |
| 2263 | + # Verify fields | |
| 2264 | + compare( "header version", $$msg{'version'}, '==', $of_ver ); | |
| 2265 | + compare( "header type", $$msg{'type'}, '==', $enums{'OFPT_ECHO_REQUEST'} ); | |
| 2266 | + compare( "header length", $$msg{'length'}, '==', $msg_size ); | |
| 2267 | + | |
| 2268 | + return $$msg{'xid'}; | |
| 2269 | +} | |
| 2270 | + | |
| 2271 | +sub get_dpinst { | |
| 2272 | + my ($options_ref) = @_; | |
| 2273 | + | |
| 2274 | + my $platform = $$options_ref{'common-st-args'}; | |
| 2275 | + my $kmod_dpinst = "nl:0"; | |
| 2276 | + my $user_dpinst = "unix:/var/run/test"; | |
| 2277 | + my $dpinst; | |
| 2278 | + | |
| 2279 | + if ( not defined( $$options_ref{'listener'} ) ) { | |
| 2280 | + if (($platform eq 'user') or ($platform eq 'user_veth')) { | |
| 2281 | + $dpinst = $user_dpinst; | |
| 2282 | + } else { | |
| 2283 | + $dpinst = $kmod_dpinst; | |
| 2284 | + } | |
| 2285 | + } else { | |
| 2286 | + # For some platform, we have absolutely no way to guess | |
| 2287 | + # the proper argument to dpctl. | |
| 2288 | + # For example, on the HP test, it means guessing the IP | |
| 2289 | + # address and the port. So, we need a bit of help... | |
| 2290 | + # Jean II | |
| 2291 | + $dpinst = $$options_ref{'listener'}; | |
| 2292 | + } | |
| 2293 | + | |
| 2294 | + return $dpinst; | |
| 2295 | +} | |
| 2296 | + | |
| 2297 | +sub dpctl_del_flows { | |
| 2298 | + my ($options_ref) = @_; | |
| 2299 | + | |
| 2300 | + my $dpinst = get_dpinst($options_ref); | |
| 2301 | + `$ENV{'OF_ROOT'}/utilities/dpctl del-flows $dpinst`; | |
| 2302 | +} | |
| 2303 | + | |
| 2304 | +sub dpctl_show_flows { | |
| 2305 | + my ($options_ref) = @_; | |
| 2306 | + | |
| 2307 | + my $dpinst = get_dpinst($options_ref); | |
| 2308 | + system("$ENV{'OF_ROOT'}/utilities/dpctl dump-flows $dpinst"); | |
| 2309 | +} | |
| 2310 | + | |
| 2311 | +# Always end library in 1 | |
| 2312 | +1; | ... | ... |
regress/lib/Perl5/Test/Base.pm
0 → 100755
| 1 | +############################################################# | |
| 2 | +# $Id: Base.pm 3909 2008-06-06 03:31:57Z brandonh $ | |
| 3 | +# | |
| 4 | +# Module provides basic functions for use by NF2 Perl scripts. | |
| 5 | +# | |
| 6 | +# Revisions: | |
| 7 | +# | |
| 8 | +############################################################## | |
| 9 | + | |
| 10 | +package Test::Base; | |
| 11 | +use Exporter; | |
| 12 | +@ISA = ('Exporter'); | |
| 13 | +@EXPORT = qw( &check_NF2_vars_set | |
| 14 | + ); | |
| 15 | + | |
| 16 | +############################################################## | |
| 17 | +# | |
| 18 | +# Define a my_die function if it doesn't already exist | |
| 19 | +# | |
| 20 | +############################################################## | |
| 21 | + | |
| 22 | +if (!defined(&my_die)) { | |
| 23 | + eval(' | |
| 24 | + sub my_die { | |
| 25 | + my $mess = shift @_; | |
| 26 | + (my $cmd = $0) =~ s/.*\///; | |
| 27 | + print STDERR "\n$cmd: $mess\n"; | |
| 28 | + exit 1; | |
| 29 | + } | |
| 30 | + '); | |
| 31 | +} | |
| 32 | + | |
| 33 | +# Always end library in 1 | |
| 34 | +1; | ... | ... |