├── .abat-automerge ├── .gitignore ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── docs ├── Detailed_Testing_Methodology.txt ├── Doxyfile ├── flow_query_test_plan.txt └── images │ └── oftest_arch.png ├── oft ├── platforms ├── bpp.py ├── dppv.py ├── eth.py ├── knet_inject.py ├── local.py ├── ovs-dummy.py ├── remote.py ├── veth8.py ├── veth_inject.py ├── veth_sim.py └── vpip.py ├── pylint.sh ├── run_switch.py ├── src └── python │ ├── .gitignore │ ├── loxi │ ├── LICENSE.pyloxi │ ├── __init__.py │ ├── connection.py │ ├── generic_util.py │ ├── of10 │ │ ├── __init__.py │ │ ├── action.py │ │ ├── common.py │ │ ├── const.py │ │ ├── message.py │ │ └── util.py │ ├── of11 │ │ ├── __init__.py │ │ ├── action.py │ │ ├── common.py │ │ ├── const.py │ │ ├── instruction.py │ │ ├── message.py │ │ └── util.py │ ├── of12 │ │ ├── __init__.py │ │ ├── action.py │ │ ├── common.py │ │ ├── const.py │ │ ├── instruction.py │ │ ├── message.py │ │ ├── oxm.py │ │ └── util.py │ ├── of13 │ │ ├── __init__.py │ │ ├── action.py │ │ ├── action_id.py │ │ ├── bsn_tlv.py │ │ ├── common.py │ │ ├── const.py │ │ ├── instruction.py │ │ ├── instruction_id.py │ │ ├── message.py │ │ ├── meter_band.py │ │ ├── oxm.py │ │ └── util.py │ ├── of14 │ │ ├── __init__.py │ │ ├── action.py │ │ ├── action_id.py │ │ ├── async_config_prop.py │ │ ├── bsn_tlv.py │ │ ├── bundle_prop.py │ │ ├── common.py │ │ ├── const.py │ │ ├── instruction.py │ │ ├── instruction_id.py │ │ ├── message.py │ │ ├── meter_band.py │ │ ├── oxm.py │ │ ├── port_desc_prop.py │ │ ├── port_mod_prop.py │ │ ├── port_stats_prop.py │ │ ├── queue_desc_prop.py │ │ ├── queue_stats_prop.py │ │ ├── role_prop.py │ │ ├── table_mod_prop.py │ │ └── util.py │ ├── of15 │ │ ├── __init__.py │ │ ├── action.py │ │ ├── action_id.py │ │ ├── async_config_prop.py │ │ ├── bsn_tlv.py │ │ ├── bundle_prop.py │ │ ├── common.py │ │ ├── const.py │ │ ├── instruction.py │ │ ├── instruction_id.py │ │ ├── message.py │ │ ├── meter_band.py │ │ ├── oxm.py │ │ ├── port_desc_prop.py │ │ ├── port_mod_prop.py │ │ ├── port_stats_prop.py │ │ ├── queue_desc_prop.py │ │ ├── queue_stats_prop.py │ │ ├── role_prop.py │ │ ├── table_mod_prop.py │ │ └── util.py │ └── pp.py │ └── oftest │ ├── __init__.py │ ├── afpacket.py │ ├── base_tests.py │ ├── controller.py │ ├── dataplane.py │ ├── help_formatter.py │ ├── illegal_message.py │ ├── mpls.py │ ├── netutils.py │ ├── oft12 │ ├── __init__.py │ ├── packet.py │ └── testutils.py │ ├── ofutils.py │ ├── packet.py │ ├── parse.py │ ├── pcap_writer.py │ ├── test_parse.py │ ├── testutils.py │ └── vxlan.py ├── tests-1.2 ├── basic.py ├── flow_mods.py ├── groups.py └── ipv6.py ├── tests-1.3 ├── actions.py ├── basic.py ├── bsn_controller_connections.py ├── bsn_flow_checksum.py ├── bsn_gentable.py ├── bsn_in_ports.py ├── bsn_role_status.py ├── flow_mod.py ├── flow_stats.py ├── groups.py ├── match.py ├── pktin_match.py └── role_request.py ├── tests-1.4 ├── bsn_histogram.py ├── bundle.py └── role_status.py ├── tests ├── FuncUtils.py ├── actions.py ├── basic.py ├── bsn_mirror.py ├── bsn_shell.py ├── caps.py ├── counters.py ├── cxn.py ├── default_drop.py ├── detailed_contr_sw_messages.py ├── flow_expire.py ├── flow_matches.py ├── flow_query.py ├── flow_stats.py ├── latency.py ├── load.py ├── message_types.py ├── nicira_dec_ttl.py ├── nicira_role.py ├── oft ├── openflow_protocol_messages.py ├── pktact.py └── port_stats.py └── tools ├── ovs-ctl ├── README ├── ovs-ctl-default.example.conf └── ovs-ctl.py └── update-pyloxi.sh /.abat-automerge: -------------------------------------------------------------------------------- 1 | #!/bin/bash -eux 2 | cd $(dirname $(readlink -f $0)) 3 | ./pylint.sh 4 | 5 | # Exercise uncommonly used options 6 | ./oft --version 7 | ./oft --help 8 | ./oft --list 9 | ./oft --list-test-names 10 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.pyc 2 | profiles/*.pyc 3 | *~ 4 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | OpenFlow Test Framework 2 | 3 | Copyright (c) 2010 The Board of Trustees of The Leland Stanford 4 | Junior University 5 | 6 | Except where otherwise noted, this software is distributed under 7 | the OpenFlow Software License. See 8 | http://www.openflowswitch.org/wp/legal/ for current details. 9 | 10 | We are making the OpenFlow specification and associated documentation 11 | (Software) available for public use and benefit with the expectation 12 | that others will use, modify and enhance the Software and contribute 13 | those enhancements back to the community. However, since we would like 14 | to make the Software available for broadest use, with as few 15 | restrictions as possible permission is hereby granted, free of charge, 16 | to any person obtaining a copy of this Software to deal in the 17 | Software under the copyrights without restriction, including without 18 | limitation the rights to use, copy, modify, merge, publish, 19 | distribute, sublicense, and/or sell copies of the Software, and to 20 | permit persons to whom the Software is furnished to do so, subject to 21 | the following conditions: 22 | 23 | The above copyright notice and this permission notice shall be 24 | included in all copies or substantial portions of the Software. 25 | 26 | THE SOFTWARE IS PROVIDED -Y´AS IS¡, WITHOUT WARRANTY OF ANY KIND, 27 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 28 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 29 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 30 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 31 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 32 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 33 | 34 | The name and trademarks of copyright holder(s) may NOT be used in 35 | advertising or publicity pertaining to the Software or any derivatives 36 | without specific, written prior permission. 37 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | OFTest OpenFlow Testing Framework 2 | 3 | --- 4 | 5 | # Introduction 6 | 7 | OFTest is a Python based OpenFlow switch test framework and collection of test cases. It is based on unittest, which is included in the standard Python distribution. 8 | 9 | This document is meant to provide an introduction to the framework, discuss the basics of running tests and to provide examples of how to add tests. 10 | 11 | For information on writing new tests or making improvements to the test framework see the file [DEVELOPING](DEVELOPING.md). 12 | 13 | --- 14 | 15 | # How It Works 16 | 17 | OFTest is meant to exercise a candidate OpenFlow switch (henceforth the device under test (DUT) or switch under test (SUT)). Below is the "horseshoe" disagram for OFTest that demonstrates the interaction between OFTest and SUT. 18 | 19 | ![OFTest Architecture](docs/images/oftest_arch.png) 20 | 21 | As you can see, the SUT is in the middle. The test fixture, the OFTest server, connects to both the control plane and the data plane of the SUT. It coordinates OpenFlow commands with data plane stimulus and monitoring. 22 | 23 | Some additional info on OFTest: 24 | 25 | * OFTests starts with the very basics of OpenFlow, but provides a framework for development of more complicated tests. 26 | * It was used as the primary vehicle for validating OpenFlow 1.1 (see the `oft-1.1` branch in the Git repository). 27 | * A prototype implementation of an OpenFlow 1.1 switch, OFPS, was implemented in the same framework as OFTest (also in the `oft-1.1` branch). 28 | 29 | --- 30 | 31 | # Getting OFTest 32 | 33 | You can check out OFTest with git with the following command: 34 | 35 | git clone git://github.com/floodlight/oftest 36 | 37 | --- 38 | 39 | # Quick Start 40 | 41 | You need to have Python and Scapy installed on your system. See 'Pre-requisites' below. 42 | 43 | Make sure your switch is running and trying to connect to a controller on the machine where you're running oft (normally port `6653`). 44 | 45 | cd oftest 46 | ./oft --list 47 | sudo ./oft basic.Echo 48 | sudo ./oft --verbose --log-file="" 49 | sudo ./oft basic -i 1@veth1 -i 2@veth3 50 | 51 | --- 52 | 53 | # Extending OFTest 54 | 55 | We welcome any kind of patch. Send all patches as pull requests to `floodlight/oftest`. We recommend you check out the [CONTRIBUTING.md] document for ideas and requirements around patches. 56 | 57 | --- 58 | 59 | # Longer Start 60 | 61 | ## Configure Pre-requisites 62 | 63 | The following software is required to run OFTest: 64 | 65 | * Python 2.7 66 | * Scapy 67 | * tcpdump (optional - Scapy will complain if it's missing) 68 | * Doxygen and doxypy (optional - for documentation generation) 69 | * PyLint (optional - for source checking) 70 | 71 | Most of these can be installed using your package manager. For example: 72 | 73 | sudo yum install python # for RHEL-based distros 74 | sudo apt-get install scapy # for Debian-based distros 75 | 76 | You will also need an OpenFlow-compliant switch instance to test. This switch must be running OpenFlow 1.0+ and attempting to connect to a controller on the machine running `oft`. 77 | 78 | Finally root/sudo privilege is required on the host, in order to run `oft`. 79 | 80 | ## Start the Switch 81 | 82 | The switch must be running and actively attempting to connect to a controller on the test host at the port number used by oft (`6653` by default, or specified as `--port=` as an argument to oft). 83 | 84 | If you're new to the test environment and want to check its sanity, you can do the following. This requires that your host kernel supports virtual Ethernet interfaces. This is best done in a window separate from where you will run oft. 85 | 86 | 1. Check out OpenFlow (preferably at the same level as oftest): 87 | 88 | git clone git://openflowswitch.org/openflow.git 89 | 90 | 2. Build OpenFlow: 91 | 92 | cd openflow 93 | ./boot.sh 94 | ./configure; make 95 | cd ../oftest 96 | 97 | 4. Run the switch startup script: 98 | 99 | sudo ./run_switch.py 100 | 101 | ## Run OFTest 102 | 103 | Now you can run `oft` (see below). Use `--help` to see command line switches. 104 | 105 | cd 106 | sudo ./oft --help 107 | 108 | If you use a port number other than the default, make sure you use the same one for the switch as for oft. For example, to run the `basic` collection of tests: 109 | 110 | sudo ./oft basic -i 1@veth1 -i 2@veth3 111 | 112 | Once you're finished, use `Ctrl-C` to terminate the switch daemons. To clean up the virtual ethernet interfaces, use: 113 | 114 | sudo rmmod veth 115 | 116 | New tools allow you to run an OVS instance as well. See `oftest/tools/ovs-ctl`. You will need to install a version of [Open vSwitch](http://openvswitch.org/) for this to work. 117 | 118 | --- 119 | 120 | # Configuring OFTest 121 | 122 | ## Platforms 123 | 124 | The "platform" is a configuration file (written in Python) that tells OFTest how to send packets to and receive packets from the dataplane of the switch. 125 | 126 | ### `eth` 127 | 128 | The default platform, `eth`, uses Linux Ethernet interfaces and is configured with the `-i` option (or `--interface`). Pass the option as `-i ofport@interface`, for example `-i 1@eth1`. If no `-i` options are given the the default configuration uses vEths for backwards-compatibility with the original OpenFlow reference switch. 129 | 130 | ### `remote` 131 | 132 | Another common platform, `remote`, provides support for testing of switches on a different host. This can be useful for cases where interfaces are not available on one host (i.e. they're not bound to a Linux interface driver) or where OFTest cannot run on the same host (unsupported OS, missing software, etc.). 133 | 134 | This can be enable by modifying the `platforms/remote.py` file to point to 4 NICs on the host running OFTest, like so: 135 | 136 | remote_port_map = { 137 | 23 : "eth2", # OpenFlow port 23 of the switch is connected to physical port on the server eth2 138 | 24 : "eth3", # OpenFlow port 24 of the switch is connected to physical port on the server eth3 139 | 25 : "eth4", 140 | 26 : "eth5" 141 | } 142 | 143 | ## Passing Parameters to Tests 144 | 145 | There is a facility for passing test-specific parameters into tests that works as follows. On the command line, give the parameter 146 | 147 | --test-params="key1=17;key2=True" 148 | 149 | Currently the keys used control whether VLAN tagged packets are used and whether VLAN tag stripping should be included as an action. These parameters include: 150 | 151 | vid=N: Use tagged packets with VLAN id of N 152 | strip_vlan=bool: If True, add the strip VLAN tag action to the packet test 153 | 154 | --- 155 | -------------------------------------------------------------------------------- /docs/Detailed_Testing_Methodology.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/floodlight/oftest/0c20d87bc4d97c5c410e8cdd3be83dea214f5085/docs/Detailed_Testing_Methodology.txt -------------------------------------------------------------------------------- /docs/images/oftest_arch.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/floodlight/oftest/0c20d87bc4d97c5c410e8cdd3be83dea214f5085/docs/images/oftest_arch.png -------------------------------------------------------------------------------- /platforms/bpp.py: -------------------------------------------------------------------------------- 1 | """ 2 | Platform configuration file 3 | platform == bpp 4 | """ 5 | 6 | ############################################################################### 7 | # 8 | # This platform assumes BPP VPI specifications on the command line. 9 | # 10 | ############################################################################### 11 | 12 | import sys 13 | import os 14 | import argparse 15 | import subprocess 16 | import dppv 17 | 18 | # The port specification is passed via the "--platform-args" option to OFTest. 19 | # Note that we must guard against abbreviations supported by argparse 20 | if not "--platform-args" in " ".join(sys.argv): 21 | raise Exception("--platform-args must be specified") 22 | 23 | ap = argparse.ArgumentParser("bpp") 24 | ap.add_argument("--platform-args") 25 | (ops, rest) = ap.parse_known_args() 26 | 27 | if not "@" in ops.platform_args: 28 | # Assume it is just a device name. Get the ports from the track database. 29 | if "," in ops.platform_args: 30 | (type_, d) = ops.platform_args.split(",") 31 | else: 32 | (type_, d) = ("udp", ops.platform_args) 33 | 34 | trackScript = "/usr/bin/track" 35 | if not os.path.exists(trackScript): 36 | raise Exception("Cannot find the track script (looked at %s" % trackScript) 37 | 38 | ports = eval("[" + subprocess.check_output([trackScript, "getports", d]) + "]") 39 | ops.platform_args = type_ + "," + ",".join( "%s@%s:%s" % (p, d, p) for p in ports) 40 | 41 | print "new platform_args: ", ops.platform_args 42 | exit; 43 | # 44 | ############################################################################### 45 | 46 | vpi_port_map = {} 47 | ports = ops.platform_args.split(",") 48 | bpptype = "udp" 49 | if ports[0] == "udp" or ports[0] == "tcp": 50 | bpptype = ports.pop(0) 51 | 52 | for ps in ports: 53 | (p, vpi) = ps.split("@") 54 | vpi_port_map[int(p)] = "bpp|%s|%s" % (bpptype, vpi) 55 | 56 | print vpi_port_map; 57 | 58 | def platform_config_update(config): 59 | """ 60 | Update configuration for the remote platform 61 | 62 | @param config The configuration dictionary to use/update 63 | This routine defines the port map used for this configuration 64 | """ 65 | 66 | global vpi_port_map 67 | config["port_map"] = vpi_port_map.copy() 68 | config["caps_table_idx"] = 0 69 | # 70 | # The class for DataPlanePorts must be specified here: 71 | # 72 | config['dataplane'] = { 'portclass': dppv.DataPlanePortVPI } 73 | config['allow_user'] = True 74 | -------------------------------------------------------------------------------- /platforms/dppv.py: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # 3 | # DataPlanePort implementation for VPI platforms. 4 | # 5 | # The VPI-based platforms available here (bpp and vpi) depend upon 6 | # this module for the implementation of the OFTest DataPlanePort interface. 7 | # 8 | ############################################################################### 9 | import sys 10 | import os 11 | import logging 12 | import time 13 | 14 | from oftest import config 15 | 16 | # Requires the libvpi and pyvpi packages 17 | from vpi import vpi 18 | 19 | class DataPlanePortVPI: 20 | """ 21 | Class defining a port monitoring VPI object. 22 | 23 | """ 24 | 25 | # 26 | # OFTest creates and destroys DataPlanePorts for each test. 27 | # We just cache them here. 28 | cachedVPIs = {} 29 | 30 | def vpiInit(self, interface_name, port_number, pcap_dir="."): 31 | self.vpiSpec = interface_name; 32 | if self.vpiSpec in self.cachedVPIs: 33 | self.vpi = self.cachedVPIs[self.vpiSpec] 34 | else: 35 | self.vpi = vpi.Vpi(self.vpiSpec) 36 | pcapspec = "pcapdump|%s/oft-port%.2d.pcap|mpls|PORT%d" % (pcap_dir, port_number, port_number) 37 | self.vpi.AddSendRecvListener(pcapspec); 38 | self.cachedVPIs[self.vpiSpec] = self.vpi 39 | 40 | return self.vpi 41 | 42 | 43 | def __init__(self, interface_name, port_number): 44 | """ 45 | Set up a port monitor object 46 | @param interface_name The name of the physical interface like eth1 47 | @param port_number The port number associated with this port 48 | """ 49 | self.interface_name = interface_name 50 | self.port_number = port_number 51 | logname = "VPI:" + interface_name 52 | self.logger = logging.getLogger(logname) 53 | 54 | path = "." 55 | if config['log_file']: 56 | path = config['log_file'] 57 | 58 | if self.vpiInit(interface_name, port_number, 59 | os.path.dirname(os.path.abspath(path))) == None: 60 | raise Exception("Could not create VPI interface %s" % interface_name) 61 | 62 | self.logger.info("VPI: %s:%d\n" % (interface_name, port_number)) 63 | 64 | def fileno(self): 65 | return self.vpi.DescriptorGet() 66 | 67 | def recv(self): 68 | pkt = self.vpi.Recv(False) 69 | return (pkt, time.time()) 70 | 71 | def send(self, packet): 72 | """ 73 | Send a packet to the dataplane port 74 | @param packet The packet data to send to the port 75 | @retval The number of bytes sent 76 | """ 77 | _len = len(packet); 78 | self.vpi.Send(packet) 79 | return _len; 80 | -------------------------------------------------------------------------------- /platforms/eth.py: -------------------------------------------------------------------------------- 1 | """ 2 | Eth platform 3 | 4 | This platform uses the --interface command line option to choose the ethernet interfaces. 5 | """ 6 | 7 | def platform_config_update(config): 8 | """ 9 | Update configuration for the local platform 10 | 11 | @param config The configuration dictionary to use/update 12 | """ 13 | 14 | port_map = {} 15 | 16 | for (ofport, interface) in config["interfaces"]: 17 | port_map[ofport] = interface 18 | 19 | # Default to a veth configuration compatible with the reference switch 20 | if not port_map: 21 | port_map = { 22 | 1: 'veth1', 23 | 2: 'veth3', 24 | 3: 'veth5', 25 | 4: 'veth7', 26 | } 27 | 28 | config['port_map'] = port_map 29 | -------------------------------------------------------------------------------- /platforms/knet_inject.py: -------------------------------------------------------------------------------- 1 | """ 2 | Platform configuration file 3 | platform == knet_inject 4 | """ 5 | 6 | ############################################################################### 7 | # 8 | # This platform assumes the loopback configuration file 9 | # and the interface name to openflow port number configuration file 10 | # are specified on the command line. 11 | # Both files are expected to be in yaml format. 12 | # The intent is to generate port_map dictionary, whose keys are 13 | # openflow port numbers and whose values are interface names. 14 | # Packets written to a specific interface will be seen on the corresponding 15 | # openflow port. 16 | # The loopback connections in the loopback configuration file are assumed 17 | # to be unique; i.e. if interfaceA is connected to interfaceB, there is no 18 | # configuration stating interfaceB is connected to interfaceA. 19 | # 20 | ############################################################################### 21 | 22 | import sys 23 | import os 24 | import argparse 25 | import subprocess 26 | import yaml 27 | 28 | # The loopback port specification is passed via the "--platform-args" 29 | # option to OFTest. 30 | # Note that we must guard against abbreviations supported by argparse 31 | if not "--platform-args" in " ".join(sys.argv): 32 | raise Exception("--platform-args must be specified") 33 | 34 | ap = argparse.ArgumentParser("knet_inject") 35 | ap.add_argument("--platform-args") 36 | (ops, rest) = ap.parse_known_args() 37 | 38 | ############################################################################### 39 | # --platform-args=, 40 | 41 | """ 42 | sample config file specifying loopback connections ; 43 | note no duplicate loopback configuration 44 | ethernet11: ethernet12 45 | ethernet9: ethernet10 46 | ethernet3: ethernet4 47 | ethernet1: ethernet2 48 | ethernet7: ethernet8 49 | ethernet5: ethernet6 50 | 51 | sample config file specifying ifname2ofport mapping ; 52 | each interface appearing as a key in the loopback configuration 53 | must have a corresponding entry in the ifname2ofport mapping 54 | ethernet1 : 1 55 | ethernet2 : 2 56 | ethernet3 : 3 57 | ethernet4 : 4 58 | ethernet5 : 5 59 | ethernet6 : 6 60 | ethernet7 : 7 61 | ethernet8 : 8 62 | ethernet9 : 9 63 | ethernet10 : 10 64 | ethernet11 : 11 65 | ethernet12 : 12 66 | """ 67 | 68 | args = ops.platform_args.split(",") 69 | # first arg: loopback cfg file 70 | # second arg: ifname to ofport number mapping cfg file 71 | if len(args) != 2: 72 | raise Exception("Expecting ,") 73 | lbcfgfile = args[0] 74 | if2numcfgfile = args[1] 75 | 76 | # read config files 77 | if os.path.isfile(lbcfgfile): 78 | print(lbcfgfile) 79 | with open(lbcfgfile) as f: 80 | lbcfg = yaml.load(f) 81 | else: 82 | lbcfg = {} 83 | if os.path.isfile(if2numcfgfile): 84 | print(if2numcfgfile) 85 | with open(if2numcfgfile) as f: 86 | if2numcfg = yaml.load(f) 87 | else: 88 | if2numcfg = {} 89 | 90 | # lbcfg sanity check: keys and values should have no overlap 91 | if set(lbcfg.keys()) != ( set(lbcfg.keys()) - set(lbcfg.values()) ): 92 | raise Exception("Loopback configuration keys and values overlap") 93 | 94 | # set up injection ports 95 | # keys are mapped from interface name to ofport number 96 | # values are mapped from interface name to knet injection port name 97 | def inj_port(x): 98 | basename = 'ethernet' 99 | if x.startswith(basename): 100 | return basename + x[len(basename):].replace('/', '-').replace(':', '_') 101 | else: 102 | raise Exception("Injection port name does not start with '%s'" 103 | % basename) 104 | 105 | port_map = { if2numcfg[k]: inj_port(v) 106 | for k,v in lbcfg.iteritems() if k in if2numcfg } 107 | 108 | print "Port to injection port mapping:" 109 | print port_map 110 | 111 | loopback_port_map = { if2numcfg[k]: if2numcfg[v] 112 | for k, v in lbcfg.iteritems() if k in if2numcfg } 113 | 114 | print "Loopback port connections:" 115 | print loopback_port_map 116 | 117 | def platform_config_update(config): 118 | """ 119 | Update configuration for the remote platform 120 | 121 | @param config The configuration dictionary to use/update 122 | This routine defines the port map used for this configuration 123 | """ 124 | 125 | global port_map 126 | config["port_map"] = port_map.copy() 127 | config["caps_table_idx"] = 0 128 | config['allow_user'] = True 129 | config["loopback_port_map"] = loopback_port_map.copy() 130 | -------------------------------------------------------------------------------- /platforms/local.py: -------------------------------------------------------------------------------- 1 | """ 2 | Local platform 3 | 4 | This platform uses veth pairs to send packets to and from a userspace 5 | switch. The switch should be connected to veth0, veth2, veth4, and veth6. 6 | """ 7 | 8 | def platform_config_update(config): 9 | """ 10 | Update configuration for the local platform 11 | 12 | @param config The configuration dictionary to use/update 13 | """ 14 | base_of_port = 1 15 | base_if_index = 1 16 | port_count = 4 17 | 18 | port_map = {} 19 | # Use every other veth interface (veth1, veth3, ...) 20 | for idx in range(port_count): 21 | port_map[base_of_port + idx] = "veth%d" % (base_if_index + 2 * idx) 22 | config['port_map'] = port_map 23 | -------------------------------------------------------------------------------- /platforms/ovs-dummy.py: -------------------------------------------------------------------------------- 1 | """ 2 | Dummy platform 3 | 4 | This platform uses Open vSwitch dummy interfaces. 5 | """ 6 | 7 | import logging 8 | import os 9 | import select 10 | import socket 11 | import struct 12 | import sys 13 | import time 14 | from threading import Thread 15 | from threading import Lock 16 | 17 | RCV_TIMEOUT = 10000 18 | RUN_DIR = os.environ.get("OVS_RUNDIR", "/var/run/openvswitch") 19 | 20 | class DataPlanePortOVSDummy: 21 | """ 22 | Class defining a port monitoring object that uses Unix domain 23 | sockets for ports, intended for connecting to Open vSwitch "dummy" 24 | netdevs. 25 | """ 26 | 27 | def __init__(self, interface_name, port_number, max_pkts=1024): 28 | """ 29 | Set up a port monitor object 30 | @param interface_name The name of the physical interface like eth1 31 | @param port_number The port number associated with this port 32 | @param max_pkts Maximum number of pkts to keep in queue 33 | """ 34 | self.interface_name = interface_name 35 | self.max_pkts = max_pkts 36 | self.port_number = port_number 37 | self.txq = [] 38 | self.rxbuf = "" 39 | logname = "dp-" + interface_name 40 | self.logger = logging.getLogger(logname) 41 | try: 42 | self.socket = DataPlanePortOVSDummy.interface_open(interface_name) 43 | except: 44 | self.logger.info("Could not open socket") 45 | raise 46 | self.logger.info("Opened port monitor (class %s)", type(self).__name__) 47 | 48 | @staticmethod 49 | def interface_open(interface_name): 50 | """ 51 | Open a Unix domain socket interface. 52 | @param interface_name port name as a string such as 'eth1' 53 | @retval s socket 54 | """ 55 | s = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) 56 | s.settimeout(RCV_TIMEOUT) 57 | s.setblocking(0) 58 | s.connect("%s/%s" % (RUN_DIR, interface_name)) 59 | return s 60 | 61 | def __del__(self): 62 | if self.socket: 63 | self.socket.close() 64 | 65 | def fileno(self): 66 | """ 67 | Return an integer file descriptor that can be passed to select(2). 68 | """ 69 | return self.socket.fileno() 70 | 71 | def recv(self): 72 | while True: 73 | rout, wout, eout = select.select([self.socket], [], [], 0) 74 | if not rout: 75 | return 76 | 77 | if len(self.rxbuf) < 2: 78 | n = 2 - len(self.rxbuf) 79 | else: 80 | frame_len = struct.unpack('>h', self.rxbuf[:2])[0] 81 | n = (2 + frame_len) - len(self.rxbuf) 82 | 83 | data = self.socket.recv(n) 84 | self.rxbuf += data 85 | if len(data) == n and len(self.rxbuf) > 2: 86 | rcvtime = time.time() 87 | packet = self.rxbuf[2:] 88 | self.logger.debug("Pkt len " + str(len(packet)) + 89 | " in at " + str(rcvtime) + " on port " + 90 | str(self.port_number)) 91 | self.rxbuf = "" 92 | return (packet, rcvtime) 93 | 94 | def send(self, packet): 95 | if len(self.txq) < self.max_pkts: 96 | self.txq.append(struct.pack('>h', len(packet)) + packet) 97 | retval = len(packet) 98 | else: 99 | retval = 0 100 | self.__run_tx() 101 | return retval 102 | 103 | def __run_tx(self): 104 | while self.txq: 105 | rout, wout, eout = select.select([], [self.socket], [], 0) 106 | if not wout: 107 | return 108 | 109 | retval = self.socket.send(self.txq[0]) 110 | if retval > 0: 111 | self.txq[0] = self.txq[0][retval:] 112 | if len(self.txq[0]) == 0: 113 | self.txq = self.txq[1:] 114 | 115 | def down(self): 116 | pass 117 | 118 | def up(self): 119 | pass 120 | 121 | # Update this dictionary to suit your environment. 122 | dummy_port_map = { 123 | 1 : "p1", 124 | 2 : "p2", 125 | 3 : "p3", 126 | 4 : "p4" 127 | } 128 | 129 | def platform_config_update(config): 130 | """ 131 | Update configuration for the dummy platform 132 | 133 | @param config The configuration dictionary to use/update 134 | """ 135 | global dummy_port_map 136 | config["port_map"] = dummy_port_map.copy() 137 | config["caps_table_idx"] = 0 138 | config["dataplane"] = {"portclass": DataPlanePortOVSDummy} 139 | config["allow_user"] = True 140 | -------------------------------------------------------------------------------- /platforms/remote.py: -------------------------------------------------------------------------------- 1 | """ 2 | Remote platform 3 | 4 | This platform uses physical ethernet interfaces. 5 | """ 6 | 7 | # Update this dictionary to suit your environment. 8 | remote_port_map = { 9 | 23 : "eth2", 10 | 24 : "eth3", 11 | 25 : "eth4", 12 | 26 : "eth5" 13 | } 14 | 15 | def platform_config_update(config): 16 | """ 17 | Update configuration for the remote platform 18 | 19 | @param config The configuration dictionary to use/update 20 | """ 21 | global remote_port_map 22 | config["port_map"] = remote_port_map.copy() 23 | config["caps_table_idx"] = 0 24 | -------------------------------------------------------------------------------- /platforms/veth8.py: -------------------------------------------------------------------------------- 1 | """ 2 | veth8 platform 3 | 4 | This platform uses 8 veth pairs. The switch should connect to veth0, veth2, ..., veth14. 5 | """ 6 | 7 | def platform_config_update(config): 8 | """ 9 | Update configuration for the local platform 10 | 11 | @param config The configuration dictionary to use/update 12 | """ 13 | 14 | config['port_map'] = { 15 | 1: 'veth1', 16 | 2: 'veth3', 17 | 3: 'veth5', 18 | 4: 'veth7', 19 | 5: 'veth9', 20 | 6: 'veth11', 21 | 7: 'veth13', 22 | 8: 'veth15', 23 | } 24 | -------------------------------------------------------------------------------- /platforms/veth_inject.py: -------------------------------------------------------------------------------- 1 | """ 2 | Platform configuration file 3 | platform == veth_inject 4 | """ 5 | 6 | ############################################################################### 7 | # 8 | # This platform assumes the loopback configuration file 9 | # and the interface name to openflow port number configuration file 10 | # are specified on the command line. 11 | # Both files are expected to be in yaml format. 12 | # The intent is to generate port_map dictionary, whose keys are 13 | # openflow port numbers and whose values are interface names. 14 | # Packets written to a specific interface will be seen on the corresponding 15 | # openflow port. 16 | # The loopback connections in the loopback configuration file are assumed 17 | # to be unique; i.e. if interfaceA is connected to interfaceB, there is no 18 | # configuration stating interfaceB is connected to interfaceA. 19 | # 20 | ############################################################################### 21 | 22 | import sys 23 | import os 24 | import argparse 25 | import subprocess 26 | import yaml 27 | 28 | # The loopback port specification is passed via the "--platform-args" 29 | # option to OFTest. 30 | # Note that we must guard against abbreviations supported by argparse 31 | if not "--platform-args" in " ".join(sys.argv): 32 | raise Exception("--platform-args must be specified") 33 | 34 | ap = argparse.ArgumentParser("veth_inject") 35 | ap.add_argument("--platform-args") 36 | (ops, rest) = ap.parse_known_args() 37 | 38 | ############################################################################### 39 | # --platform-args=, 40 | 41 | """ 42 | sample config file specifying loopback connections ; 43 | note no duplicate loopback configuration 44 | ethernet11: ethernet12 45 | ethernet9: ethernet10 46 | ethernet3: ethernet4 47 | ethernet1: ethernet2 48 | ethernet7: ethernet8 49 | ethernet5: ethernet6 50 | 51 | sample config file specifying ifname2ofport mapping ; 52 | each interface appearing as a key in the loopback configuration 53 | must have a corresponding entry in the ifname2ofport mapping 54 | ethernet1 : 1 55 | ethernet2 : 2 56 | ethernet3 : 3 57 | ethernet4 : 4 58 | ethernet5 : 5 59 | ethernet6 : 6 60 | ethernet7 : 7 61 | ethernet8 : 8 62 | ethernet9 : 9 63 | ethernet10 : 10 64 | ethernet11 : 11 65 | ethernet12 : 12 66 | """ 67 | 68 | args = ops.platform_args.split(",") 69 | # first arg: loopback cfg file 70 | # second arg: ifname to ofport number mapping cfg file 71 | if len(args) != 2: 72 | raise Exception("Expecting ,") 73 | lbcfgfile = args[0] 74 | if2numcfgfile = args[1] 75 | 76 | # read config files 77 | if os.path.isfile(lbcfgfile): 78 | print(lbcfgfile) 79 | with open(lbcfgfile) as f: 80 | lbcfg = yaml.load(f) 81 | else: 82 | lbcfg = {} 83 | if os.path.isfile(if2numcfgfile): 84 | print(if2numcfgfile) 85 | with open(if2numcfgfile) as f: 86 | if2numcfg = yaml.load(f) 87 | else: 88 | if2numcfg = {} 89 | 90 | # lbcfg sanity check: keys and values should have no overlap 91 | if set(lbcfg.keys()) != ( set(lbcfg.keys()) - set(lbcfg.values()) ): 92 | raise Exception("Loopback configuration keys and values overlap") 93 | 94 | # set up injection ports 95 | # keys are mapped from interface name to ofport number 96 | # values are mapped from interface name to veth injection port name 97 | def inj_port(x): 98 | basename = 'ethernet' 99 | if x.startswith(basename): 100 | return 'vet' + x[len(basename):].replace('/', ',').replace(':', '#') + 'j' 101 | else: 102 | raise Exception("Injection port name does not start with '%s'" 103 | % basename) 104 | 105 | port_map = { if2numcfg[k]: inj_port(v) 106 | for k,v in lbcfg.iteritems() if k in if2numcfg } 107 | 108 | print "Port to injection port mapping:" 109 | print port_map 110 | 111 | loopback_port_map = { if2numcfg[k]: if2numcfg[v] 112 | for k, v in lbcfg.iteritems() if k in if2numcfg } 113 | 114 | print "Loopback port connections:" 115 | print loopback_port_map 116 | 117 | def platform_config_update(config): 118 | """ 119 | Update configuration for the remote platform 120 | 121 | @param config The configuration dictionary to use/update 122 | This routine defines the port map used for this configuration 123 | """ 124 | 125 | global port_map 126 | config["port_map"] = port_map.copy() 127 | config["caps_table_idx"] = 0 128 | config['allow_user'] = True 129 | config["loopback_port_map"] = loopback_port_map.copy() 130 | -------------------------------------------------------------------------------- /platforms/veth_sim.py: -------------------------------------------------------------------------------- 1 | """ 2 | Platform configuration file 3 | platform == veth_sim 4 | """ 5 | 6 | ############################################################################### 7 | # 8 | ############################################################################### 9 | 10 | import os 11 | import sys 12 | import argparse 13 | import yaml 14 | 15 | if not "--platform-args" in " ".join(sys.argv): 16 | raise Exception("--platform-args must be specified") 17 | 18 | ap = argparse.ArgumentParser("veth_sim") 19 | ap.add_argument("--platform-args") 20 | (ops, rest) = ap.parse_known_args() 21 | 22 | """ 23 | sample veth-cfgfile: 24 | eth1: eth1_oft 25 | eth2: eth2_oft 26 | eth3: eth3_oft 27 | 28 | sample ifname2ofport-cfgfile: 29 | eth1: 1 30 | eth2: 2 31 | eth3: 3 32 | """ 33 | 34 | args = ops.platform_args.split(",") 35 | # first arg: veth mapping cfg file 36 | # second arg: ifname to ofport number mapping cfg file 37 | if len(args) != 2: 38 | raise Exception("Expecting ,") 39 | vethcfgfile = args[0] 40 | if2numcfgfile = args[1] 41 | 42 | vethcfg = {} 43 | if os.path.isfile(vethcfgfile): 44 | print(vethcfgfile) 45 | with open(vethcfgfile) as f: 46 | vethcfg = yaml.load(f) 47 | 48 | if2numcfg = {} 49 | if os.path.isfile(if2numcfgfile): 50 | print(if2numcfgfile) 51 | with open(if2numcfgfile) as f: 52 | if2numcfg = yaml.load(f) 53 | 54 | port_map = { int(v) : vethcfg[k] 55 | for k, v in if2numcfg.items() if k in vethcfg} 56 | 57 | print "Veth-sim port mapping" 58 | print port_map 59 | 60 | def platform_config_update(config): 61 | global port_map 62 | config["port_map"] = port_map.copy() 63 | -------------------------------------------------------------------------------- /platforms/vpip.py: -------------------------------------------------------------------------------- 1 | """ 2 | Platform configuration file 3 | platform == vpi 4 | """ 5 | 6 | ############################################################################### 7 | # 8 | # This platform module allows VPI port specifications on the command line. 9 | # 10 | ############################################################################### 11 | 12 | import sys 13 | import os 14 | import argparse 15 | import dppv 16 | 17 | # The port specification is passed via the "--platform-args" option to OFTest. 18 | # Note that we must guard against abbreviations supported by argparse 19 | if not "--platform-args" in " ".join(sys.argv): 20 | raise Exception("--platform-args must be specified") 21 | 22 | ap = argparse.ArgumentParser("vpi") 23 | ap.add_argument("--platform-args") 24 | (ops, rest) = ap.parse_known_args() 25 | 26 | vpi_port_map = {} 27 | ports = ops.platform_args.split(",") 28 | for ps in ports: 29 | (p, vpi) = ps.split("@") 30 | vpi_port_map[int(p)] = vpi 31 | 32 | print vpi_port_map; 33 | 34 | def platform_config_update(config): 35 | """ 36 | Update configuration for the remote platform 37 | 38 | @param config The configuration dictionary to use/update 39 | This routine defines the port map used for this configuration 40 | """ 41 | 42 | global vpi_port_map 43 | config["port_map"] = vpi_port_map.copy() 44 | config["caps_table_idx"] = 0 45 | # 46 | # The class for DataPlanePorts must be specified here: 47 | # 48 | config['dataplane'] = { 'portclass': dppv.DataPlanePortVPI } 49 | config['allow_user'] = True 50 | -------------------------------------------------------------------------------- /pylint.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | cd $(dirname $(readlink -f $0)) 3 | PYTHONPATH=src/python:tests:tests-1.3 pylint -E tests/*.py tests-1.3/*.py src/python/oftest/*.py 4 | -------------------------------------------------------------------------------- /run_switch.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # 3 | # Create veth pairs and start up switch daemons 4 | # 5 | 6 | import os 7 | import time 8 | from subprocess import Popen,PIPE,call,check_call 9 | from optparse import OptionParser 10 | 11 | parser = OptionParser(version="%prog 0.1") 12 | parser.set_defaults(port_count=4) 13 | parser.set_defaults(of_dir="../openflow") 14 | parser.set_defaults(port=6653) 15 | parser.add_option("-n", "--port_count", type="int", 16 | help="Number of veth pairs to create") 17 | parser.add_option("-o", "--of_dir", help="OpenFlow root directory for host") 18 | parser.add_option("-p", "--port", type="int", 19 | help="Port for OFP to listen on") 20 | parser.add_option("-N", "--no_wait", action="store_true", 21 | help="Do not wait 2 seconds to start daemons") 22 | (options, args) = parser.parse_args() 23 | 24 | call(["/sbin/modprobe", "veth"]) 25 | for idx in range(0, options.port_count): 26 | print "Creating veth pair " + str(idx) 27 | veth = "veth%d" % (idx*2) 28 | veth_peer = "veth%d" % (idx*2+1) 29 | call(["/sbin/ip", "link", "add", "name", veth, "type", "veth", 30 | "peer", "name", veth_peer]) 31 | 32 | for idx in range(0, 2 * options.port_count): 33 | cmd = ["/sbin/ifconfig", 34 | "veth" + str(idx), 35 | "192.168.1" + str(idx) + ".1", 36 | "netmask", 37 | "255.255.255.0"] 38 | print "Cmd: " + str(cmd) 39 | call(cmd) 40 | 41 | veths = "veth0" 42 | for idx in range(1, options.port_count): 43 | veths += ",veth" + str(2 * idx) 44 | 45 | ofd = options.of_dir + "/udatapath/ofdatapath" 46 | ofp = options.of_dir + "/secchan/ofprotocol" 47 | 48 | try: 49 | check_call(["ls", ofd]) 50 | except: 51 | print "Could not find datapath daemon: " + ofd 52 | sys.exit(1) 53 | 54 | try: 55 | check_call(["ls", ofp]) 56 | except: 57 | print "Could not find protocol daemon: " + ofp 58 | sys.exit(1) 59 | 60 | if not options.no_wait: 61 | print "Starting ofprotocol in 2 seconds; ^C to quit" 62 | time.sleep(2) 63 | else: 64 | print "Starting ofprotocol; ^C to quit" 65 | 66 | ofd_op = Popen([ofd, "-i", veths, "punix:/tmp/ofd"]) 67 | print "Started ofdatapath on IFs " + veths + " with pid " + str(ofd_op.pid) 68 | 69 | call([ofp, "unix:/tmp/ofd", "tcp:127.0.0.1:" + str(options.port), 70 | "--fail=closed", "--max-backoff=1"]) 71 | 72 | ofd_op.kill() 73 | 74 | 75 | 76 | 77 | 78 | -------------------------------------------------------------------------------- /src/python/.gitignore: -------------------------------------------------------------------------------- 1 | /build/ 2 | /dist/ 3 | /oftest.egg-info/ 4 | *.pyc 5 | -------------------------------------------------------------------------------- /src/python/loxi/LICENSE.pyloxi: -------------------------------------------------------------------------------- 1 | OpenFlow Test Framework 2 | 3 | Copyright (c) 2010 The Board of Trustees of The Leland Stanford 4 | Junior University 5 | 6 | Except where otherwise noted, this software is distributed under 7 | the OpenFlow Software License. See 8 | http://www.openflowswitch.org/wp/legal/ for current details. 9 | 10 | We are making the OpenFlow specification and associated documentation 11 | (Software) available for public use and benefit with the expectation 12 | that others will use, modify and enhance the Software and contribute 13 | those enhancements back to the community. However, since we would like 14 | to make the Software available for broadest use, with as few 15 | restrictions as possible permission is hereby granted, free of charge, 16 | to any person obtaining a copy of this Software to deal in the 17 | Software under the copyrights without restriction, including without 18 | limitation the rights to use, copy, modify, merge, publish, 19 | distribute, sublicense, and/or sell copies of the Software, and to 20 | permit persons to whom the Software is furnished to do so, subject to 21 | the following conditions: 22 | 23 | The above copyright notice and this permission notice shall be 24 | included in all copies or substantial portions of the Software. 25 | 26 | THE SOFTWARE IS PROVIDED -Y´AS IS¡, WITHOUT WARRANTY OF ANY KIND, 27 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 28 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 29 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 30 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 31 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 32 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 33 | 34 | The name and trademarks of copyright holder(s) may NOT be used in 35 | advertising or publicity pertaining to the Software or any derivatives 36 | without specific, written prior permission. 37 | -------------------------------------------------------------------------------- /src/python/loxi/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior University 2 | # Copyright (c) 2011, 2012 Open Networking Foundation 3 | # Copyright (c) 2012, 2013 Big Switch Networks, Inc. 4 | # See the file LICENSE.pyloxi which should have been included in the source distribution 5 | # Automatically generated by LOXI from template toplevel_init.py 6 | # Do not modify 7 | 8 | version_names = { 9 | 1: "1.0", 10 | 2: "1.1", 11 | 3: "1.2", 12 | 4: "1.3", 13 | 5: "1.4", 14 | 6: "1.5", 15 | } 16 | 17 | def protocol(ver): 18 | """ 19 | Import and return the protocol module for the given wire version. 20 | """ 21 | if ver == 1: 22 | from . import of10 23 | return of10 24 | 25 | if ver == 2: 26 | from . import of11 27 | return of11 28 | 29 | if ver == 3: 30 | from . import of12 31 | return of12 32 | 33 | if ver == 4: 34 | from . import of13 35 | return of13 36 | 37 | if ver == 5: 38 | from . import of14 39 | return of14 40 | 41 | if ver == 6: 42 | from . import of15 43 | return of15 44 | 45 | raise ValueError 46 | 47 | class ProtocolError(Exception): 48 | """ 49 | Raised when failing to deserialize an invalid OpenFlow message. 50 | """ 51 | pass 52 | 53 | class Unimplemented(Exception): 54 | """ 55 | Raised when an OpenFlow feature is not yet implemented in PyLoxi. 56 | """ 57 | pass 58 | 59 | def unimplemented(msg): 60 | raise Unimplemented(msg) 61 | 62 | class OFObject(object): 63 | """ 64 | Superclass of all OpenFlow classes 65 | """ 66 | def __init__(self, *args): 67 | raise NotImplementedError("cannot instantiate abstract class") 68 | 69 | def __ne__(self, other): 70 | return not self.__eq__(other) 71 | 72 | def show(self): 73 | import loxi.pp 74 | return loxi.pp.pp(self) 75 | -------------------------------------------------------------------------------- /src/python/loxi/generic_util.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior University 2 | # Copyright (c) 2011, 2012 Open Networking Foundation 3 | # Copyright (c) 2012, 2013 Big Switch Networks, Inc. 4 | # See the file LICENSE.pyloxi which should have been included in the source distribution 5 | """ 6 | Utility functions independent of the protocol version 7 | """ 8 | 9 | # Automatically generated by LOXI from template generic_util.py 10 | # Do not modify 11 | 12 | import loxi 13 | import struct 14 | import functools 15 | 16 | def pack_list(values): 17 | return "".join([x.pack() for x in values]) 18 | 19 | def unpack_list(reader, deserializer): 20 | """ 21 | The deserializer function should take an OFReader and return the new object. 22 | """ 23 | entries = [] 24 | while not reader.is_empty(): 25 | entries.append(deserializer(reader)) 26 | return entries 27 | 28 | def pad_to(alignment, length): 29 | """ 30 | Return a string of zero bytes that will pad a string of length 'length' to 31 | a multiple of 'alignment'. 32 | """ 33 | return "\x00" * ((length + alignment - 1)/alignment*alignment - length) 34 | 35 | class OFReader(object): 36 | """ 37 | Cursor over a read-only buffer 38 | 39 | OpenFlow messages are best thought of as a sequence of elements of 40 | variable size, rather than a C-style struct with fixed offsets and 41 | known field lengths. This class supports efficiently reading 42 | fields sequentially and is intended to be used recursively by the 43 | parsers of child objects which will implicitly update the offset. 44 | 45 | buf: buffer object 46 | start: initial position in the buffer 47 | length: number of bytes after start 48 | offset: distance from start 49 | """ 50 | def __init__(self, buf, start=0, length=None): 51 | self.buf = buf 52 | self.start = start 53 | if length is None: 54 | self.length = len(buf) - start 55 | else: 56 | self.length = length 57 | self.offset = 0 58 | 59 | def read(self, fmt): 60 | st = struct.Struct(fmt) 61 | if self.offset + st.size > self.length: 62 | raise loxi.ProtocolError("Buffer too short") 63 | result = st.unpack_from(self.buf, self.start+self.offset) 64 | self.offset += st.size 65 | return result 66 | 67 | def read_all(self): 68 | s = self.buf[(self.start+self.offset):(self.start+self.length)] 69 | assert(len(s) == self.length - self.offset) 70 | self.offset = self.length 71 | return s 72 | 73 | def peek(self, fmt, offset=0): 74 | st = struct.Struct(fmt) 75 | if self.offset + offset + st.size > self.length: 76 | raise loxi.ProtocolError("Buffer too short") 77 | result = st.unpack_from(self.buf, self.start + self.offset + offset) 78 | return result 79 | 80 | def skip(self, length): 81 | if self.offset + length > self.length: 82 | raise loxi.ProtocolError("Buffer too short") 83 | self.offset += length 84 | 85 | def skip_align(self): 86 | new_offset = int((self.offset + 7) / 8) * 8 87 | if new_offset > self.length: 88 | raise loxi.ProtocolError("Buffer too short") 89 | self.offset = new_offset 90 | 91 | def is_empty(self): 92 | return self.offset == self.length 93 | 94 | # Used when parsing objects that have their own length fields 95 | def slice(self, length, rewind=0): 96 | if self.offset + length - rewind > self.length: 97 | raise loxi.ProtocolError("Buffer too short") 98 | reader = OFReader(self.buf, self.start + self.offset - rewind, length) 99 | reader.skip(rewind) 100 | self.offset += length - rewind 101 | return reader 102 | -------------------------------------------------------------------------------- /src/python/loxi/of10/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior University 2 | # Copyright (c) 2011, 2012 Open Networking Foundation 3 | # Copyright (c) 2012, 2013 Big Switch Networks, Inc. 4 | # See the file LICENSE.pyloxi which should have been included in the source distribution 5 | 6 | # Automatically generated by LOXI from template init.py 7 | # Do not modify 8 | 9 | from . import action 10 | from . import message 11 | from .const import * 12 | from .common import * 13 | from loxi import ProtocolError 14 | -------------------------------------------------------------------------------- /src/python/loxi/of10/util.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior University 2 | # Copyright (c) 2011, 2012 Open Networking Foundation 3 | # Copyright (c) 2012, 2013 Big Switch Networks, Inc. 4 | # See the file LICENSE.pyloxi which should have been included in the source distribution 5 | # Automatically generated by LOXI from template util.py 6 | # Do not modify 7 | 8 | import struct 9 | from . import const 10 | 11 | def pretty_mac(mac): 12 | return ':'.join(["%02x" % x for x in mac]) 13 | 14 | def pretty_ipv4(v): 15 | return "%d.%d.%d.%d" % ((v >> 24) & 0xFF, (v >> 16) & 0xFF, (v >> 8) & 0xFF, v & 0xFF) 16 | 17 | def pretty_ipv6(v): 18 | return ":".join(["%0.2x%0.2x" % (ord(v[i]), ord(v[i+1])) for i in range(0, len(v), 2)]) 19 | 20 | def pretty_flags(v, flag_names): 21 | set_flags = [] 22 | for flag_name in flag_names: 23 | flag_value = getattr(const, flag_name) 24 | if v & flag_value == flag_value: 25 | set_flags.append(flag_name) 26 | elif v & flag_value: 27 | set_flags.append('%s&%#x' % (flag_name, v & flag_value)) 28 | v &= ~flag_value 29 | if v: 30 | set_flags.append("%#x" % v) 31 | return '|'.join(set_flags) or '0' 32 | 33 | def pretty_wildcards(v): 34 | if v == const.OFPFW_ALL: 35 | return 'OFPFW_ALL' 36 | flag_names = ['OFPFW_IN_PORT', 'OFPFW_DL_VLAN', 'OFPFW_DL_SRC', 'OFPFW_DL_DST', 37 | 'OFPFW_DL_TYPE', 'OFPFW_NW_PROTO', 'OFPFW_TP_SRC', 'OFPFW_TP_DST', 38 | 'OFPFW_NW_SRC_MASK', 'OFPFW_NW_DST_MASK', 'OFPFW_DL_VLAN_PCP', 39 | 'OFPFW_NW_TOS'] 40 | return pretty_flags(v, flag_names) 41 | 42 | def pretty_port(v): 43 | named_ports = [(k,v2) for (k,v2) in const.__dict__.items() if k.startswith('OFPP_')] 44 | for (k, v2) in named_ports: 45 | if v == v2: 46 | return k 47 | return v 48 | 49 | def pack_port_no(value): 50 | return struct.pack("!H", value) 51 | 52 | def unpack_port_no(reader): 53 | return reader.read("!H")[0] 54 | 55 | def pack_fm_cmd(value): 56 | return struct.pack("!H", value) 57 | 58 | def unpack_fm_cmd(reader): 59 | return reader.read("!H")[0] 60 | 61 | def init_wc_bmap(): 62 | return const.OFPFW_ALL 63 | 64 | def pack_wc_bmap(value): 65 | return struct.pack("!L", value) 66 | 67 | def unpack_wc_bmap(reader): 68 | return reader.read("!L")[0] 69 | 70 | def init_match_bmap(): 71 | return const.OFPFW_ALL 72 | 73 | def pack_match_bmap(value): 74 | return struct.pack("!L", value) 75 | 76 | def unpack_match_bmap(reader): 77 | return reader.read("!L")[0] 78 | 79 | MASK64 = (1 << 64) - 1 80 | 81 | def pack_bitmap_128(value): 82 | x = 0l 83 | for y in value: 84 | x |= 1 << y 85 | return struct.pack("!QQ", (x >> 64) & MASK64, x & MASK64) 86 | 87 | def unpack_bitmap_128(reader): 88 | hi, lo = reader.read("!QQ") 89 | x = (hi << 64) | lo 90 | i = 0 91 | value = set() 92 | while x != 0: 93 | if x & 1 == 1: 94 | value.add(i) 95 | i += 1 96 | x >>= 1 97 | return value 98 | 99 | def pack_bitmap_512(value): 100 | words = [0] * 8 101 | for v in value: 102 | assert v < 512 103 | words[7-int(v/64)] |= 1 << (v % 64) 104 | return struct.pack("!8Q", *words) 105 | 106 | def unpack_bitmap_512(reader): 107 | words = reader.read("!8Q") 108 | x = 0l 109 | for word in words: 110 | x <<= 64 111 | x |= word 112 | i = 0 113 | value = set() 114 | while x != 0: 115 | if x & 1 == 1: 116 | value.add(i) 117 | i += 1 118 | x >>= 1 119 | return value 120 | 121 | def pack_checksum_128(value): 122 | return struct.pack("!QQ", (value >> 64) & MASK64, value & MASK64) 123 | 124 | def unpack_checksum_128(reader): 125 | hi, lo = reader.read("!QQ") 126 | return (hi << 64) | lo 127 | -------------------------------------------------------------------------------- /src/python/loxi/of11/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior University 2 | # Copyright (c) 2011, 2012 Open Networking Foundation 3 | # Copyright (c) 2012, 2013 Big Switch Networks, Inc. 4 | # See the file LICENSE.pyloxi which should have been included in the source distribution 5 | 6 | # Automatically generated by LOXI from template init.py 7 | # Do not modify 8 | 9 | from . import action 10 | from . import message 11 | from . import instruction 12 | from .const import * 13 | from .common import * 14 | from loxi import ProtocolError 15 | -------------------------------------------------------------------------------- /src/python/loxi/of11/util.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior University 2 | # Copyright (c) 2011, 2012 Open Networking Foundation 3 | # Copyright (c) 2012, 2013 Big Switch Networks, Inc. 4 | # See the file LICENSE.pyloxi which should have been included in the source distribution 5 | # Automatically generated by LOXI from template util.py 6 | # Do not modify 7 | 8 | import struct 9 | from . import const 10 | 11 | def pretty_mac(mac): 12 | return ':'.join(["%02x" % x for x in mac]) 13 | 14 | def pretty_ipv4(v): 15 | return "%d.%d.%d.%d" % ((v >> 24) & 0xFF, (v >> 16) & 0xFF, (v >> 8) & 0xFF, v & 0xFF) 16 | 17 | def pretty_ipv6(v): 18 | return ":".join(["%0.2x%0.2x" % (ord(v[i]), ord(v[i+1])) for i in range(0, len(v), 2)]) 19 | 20 | def pretty_flags(v, flag_names): 21 | set_flags = [] 22 | for flag_name in flag_names: 23 | flag_value = getattr(const, flag_name) 24 | if v & flag_value == flag_value: 25 | set_flags.append(flag_name) 26 | elif v & flag_value: 27 | set_flags.append('%s&%#x' % (flag_name, v & flag_value)) 28 | v &= ~flag_value 29 | if v: 30 | set_flags.append("%#x" % v) 31 | return '|'.join(set_flags) or '0' 32 | 33 | def pretty_wildcards(v): 34 | if v == const.OFPFW_ALL: 35 | return 'OFPFW_ALL' 36 | flag_names = ['OFPFW_IN_PORT', 'OFPFW_DL_VLAN', 'OFPFW_DL_SRC', 'OFPFW_DL_DST', 37 | 'OFPFW_DL_TYPE', 'OFPFW_NW_PROTO', 'OFPFW_TP_SRC', 'OFPFW_TP_DST', 38 | 'OFPFW_NW_SRC_MASK', 'OFPFW_NW_DST_MASK', 'OFPFW_DL_VLAN_PCP', 39 | 'OFPFW_NW_TOS'] 40 | return pretty_flags(v, flag_names) 41 | 42 | def pretty_port(v): 43 | named_ports = [(k,v2) for (k,v2) in const.__dict__.items() if k.startswith('OFPP_')] 44 | for (k, v2) in named_ports: 45 | if v == v2: 46 | return k 47 | return v 48 | 49 | def pack_port_no(value): 50 | return struct.pack("!L", value) 51 | 52 | def unpack_port_no(reader): 53 | return reader.read("!L")[0] 54 | 55 | def pack_fm_cmd(value): 56 | return struct.pack("!B", value) 57 | 58 | def unpack_fm_cmd(reader): 59 | return reader.read("!B")[0] 60 | 61 | def init_wc_bmap(): 62 | return const.OFPFW_ALL 63 | 64 | def pack_wc_bmap(value): 65 | return struct.pack("!L", value) 66 | 67 | def unpack_wc_bmap(reader): 68 | return reader.read("!L")[0] 69 | 70 | def init_match_bmap(): 71 | return const.OFPFW_ALL 72 | 73 | def pack_match_bmap(value): 74 | return struct.pack("!L", value) 75 | 76 | def unpack_match_bmap(reader): 77 | return reader.read("!L")[0] 78 | 79 | MASK64 = (1 << 64) - 1 80 | 81 | def pack_bitmap_128(value): 82 | x = 0l 83 | for y in value: 84 | x |= 1 << y 85 | return struct.pack("!QQ", (x >> 64) & MASK64, x & MASK64) 86 | 87 | def unpack_bitmap_128(reader): 88 | hi, lo = reader.read("!QQ") 89 | x = (hi << 64) | lo 90 | i = 0 91 | value = set() 92 | while x != 0: 93 | if x & 1 == 1: 94 | value.add(i) 95 | i += 1 96 | x >>= 1 97 | return value 98 | 99 | def pack_bitmap_512(value): 100 | words = [0] * 8 101 | for v in value: 102 | assert v < 512 103 | words[7-int(v/64)] |= 1 << (v % 64) 104 | return struct.pack("!8Q", *words) 105 | 106 | def unpack_bitmap_512(reader): 107 | words = reader.read("!8Q") 108 | x = 0l 109 | for word in words: 110 | x <<= 64 111 | x |= word 112 | i = 0 113 | value = set() 114 | while x != 0: 115 | if x & 1 == 1: 116 | value.add(i) 117 | i += 1 118 | x >>= 1 119 | return value 120 | 121 | def pack_checksum_128(value): 122 | return struct.pack("!QQ", (value >> 64) & MASK64, value & MASK64) 123 | 124 | def unpack_checksum_128(reader): 125 | hi, lo = reader.read("!QQ") 126 | return (hi << 64) | lo 127 | -------------------------------------------------------------------------------- /src/python/loxi/of12/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior University 2 | # Copyright (c) 2011, 2012 Open Networking Foundation 3 | # Copyright (c) 2012, 2013 Big Switch Networks, Inc. 4 | # See the file LICENSE.pyloxi which should have been included in the source distribution 5 | 6 | # Automatically generated by LOXI from template init.py 7 | # Do not modify 8 | 9 | from . import action 10 | from . import oxm 11 | from . import message 12 | from . import instruction 13 | from .const import * 14 | from .common import * 15 | from loxi import ProtocolError 16 | -------------------------------------------------------------------------------- /src/python/loxi/of12/util.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior University 2 | # Copyright (c) 2011, 2012 Open Networking Foundation 3 | # Copyright (c) 2012, 2013 Big Switch Networks, Inc. 4 | # See the file LICENSE.pyloxi which should have been included in the source distribution 5 | # Automatically generated by LOXI from template util.py 6 | # Do not modify 7 | 8 | import struct 9 | from . import const 10 | 11 | def pretty_mac(mac): 12 | return ':'.join(["%02x" % x for x in mac]) 13 | 14 | def pretty_ipv4(v): 15 | return "%d.%d.%d.%d" % ((v >> 24) & 0xFF, (v >> 16) & 0xFF, (v >> 8) & 0xFF, v & 0xFF) 16 | 17 | def pretty_ipv6(v): 18 | return ":".join(["%0.2x%0.2x" % (ord(v[i]), ord(v[i+1])) for i in range(0, len(v), 2)]) 19 | 20 | def pretty_flags(v, flag_names): 21 | set_flags = [] 22 | for flag_name in flag_names: 23 | flag_value = getattr(const, flag_name) 24 | if v & flag_value == flag_value: 25 | set_flags.append(flag_name) 26 | elif v & flag_value: 27 | set_flags.append('%s&%#x' % (flag_name, v & flag_value)) 28 | v &= ~flag_value 29 | if v: 30 | set_flags.append("%#x" % v) 31 | return '|'.join(set_flags) or '0' 32 | 33 | 34 | def pretty_port(v): 35 | named_ports = [(k,v2) for (k,v2) in const.__dict__.items() if k.startswith('OFPP_')] 36 | for (k, v2) in named_ports: 37 | if v == v2: 38 | return k 39 | return v 40 | 41 | def pack_port_no(value): 42 | return struct.pack("!L", value) 43 | 44 | def unpack_port_no(reader): 45 | return reader.read("!L")[0] 46 | 47 | def pack_fm_cmd(value): 48 | return struct.pack("!B", value) 49 | 50 | def unpack_fm_cmd(reader): 51 | return reader.read("!B")[0] 52 | 53 | def init_wc_bmap(): 54 | return 0 55 | 56 | def pack_wc_bmap(value): 57 | return struct.pack("!Q", value) 58 | 59 | def unpack_wc_bmap(reader): 60 | return reader.read("!Q")[0] 61 | 62 | def init_match_bmap(): 63 | return 0 64 | 65 | def pack_match_bmap(value): 66 | return struct.pack("!Q", value) 67 | 68 | def unpack_match_bmap(reader): 69 | return reader.read("!Q")[0] 70 | 71 | MASK64 = (1 << 64) - 1 72 | 73 | def pack_bitmap_128(value): 74 | x = 0l 75 | for y in value: 76 | x |= 1 << y 77 | return struct.pack("!QQ", (x >> 64) & MASK64, x & MASK64) 78 | 79 | def unpack_bitmap_128(reader): 80 | hi, lo = reader.read("!QQ") 81 | x = (hi << 64) | lo 82 | i = 0 83 | value = set() 84 | while x != 0: 85 | if x & 1 == 1: 86 | value.add(i) 87 | i += 1 88 | x >>= 1 89 | return value 90 | 91 | def pack_bitmap_512(value): 92 | words = [0] * 8 93 | for v in value: 94 | assert v < 512 95 | words[7-int(v/64)] |= 1 << (v % 64) 96 | return struct.pack("!8Q", *words) 97 | 98 | def unpack_bitmap_512(reader): 99 | words = reader.read("!8Q") 100 | x = 0l 101 | for word in words: 102 | x <<= 64 103 | x |= word 104 | i = 0 105 | value = set() 106 | while x != 0: 107 | if x & 1 == 1: 108 | value.add(i) 109 | i += 1 110 | x >>= 1 111 | return value 112 | 113 | def pack_checksum_128(value): 114 | return struct.pack("!QQ", (value >> 64) & MASK64, value & MASK64) 115 | 116 | def unpack_checksum_128(reader): 117 | hi, lo = reader.read("!QQ") 118 | return (hi << 64) | lo 119 | -------------------------------------------------------------------------------- /src/python/loxi/of13/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior University 2 | # Copyright (c) 2011, 2012 Open Networking Foundation 3 | # Copyright (c) 2012, 2013 Big Switch Networks, Inc. 4 | # See the file LICENSE.pyloxi which should have been included in the source distribution 5 | 6 | # Automatically generated by LOXI from template init.py 7 | # Do not modify 8 | 9 | from . import action 10 | from . import action_id 11 | from . import oxm 12 | from . import message 13 | from . import bsn_tlv 14 | from . import instruction 15 | from . import instruction_id 16 | from . import meter_band 17 | from .const import * 18 | from .common import * 19 | from loxi import ProtocolError 20 | -------------------------------------------------------------------------------- /src/python/loxi/of13/meter_band.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior University 2 | # Copyright (c) 2011, 2012 Open Networking Foundation 3 | # Copyright (c) 2012, 2013 Big Switch Networks, Inc. 4 | # See the file LICENSE.pyloxi which should have been included in the source distribution 5 | 6 | # Automatically generated by LOXI from template module.py 7 | # Do not modify 8 | 9 | import struct 10 | import loxi 11 | from . import util 12 | import loxi.generic_util 13 | 14 | import sys 15 | ofp = sys.modules['loxi.of13'] 16 | 17 | class meter_band(loxi.OFObject): 18 | subtypes = {} 19 | 20 | 21 | def __init__(self, type=None): 22 | if type != None: 23 | self.type = type 24 | else: 25 | self.type = 0 26 | return 27 | 28 | def pack(self): 29 | packed = [] 30 | packed.append(struct.pack("!H", self.type)) 31 | packed.append(struct.pack("!H", 0)) # placeholder for len at index 1 32 | length = sum([len(x) for x in packed]) 33 | packed[1] = struct.pack("!H", length) 34 | return ''.join(packed) 35 | 36 | @staticmethod 37 | def unpack(reader): 38 | subtype, = reader.peek('!H', 0) 39 | subclass = meter_band.subtypes.get(subtype) 40 | if subclass: 41 | return subclass.unpack(reader) 42 | 43 | obj = meter_band() 44 | obj.type = reader.read("!H")[0] 45 | _len = reader.read("!H")[0] 46 | orig_reader = reader 47 | reader = orig_reader.slice(_len, 4) 48 | return obj 49 | 50 | def __eq__(self, other): 51 | if type(self) != type(other): return False 52 | if self.type != other.type: return False 53 | return True 54 | 55 | def pretty_print(self, q): 56 | q.text("meter_band {") 57 | with q.group(): 58 | with q.indent(2): 59 | q.breakable() 60 | q.breakable() 61 | q.text('}') 62 | 63 | 64 | class drop(meter_band): 65 | type = 1 66 | 67 | def __init__(self, rate=None, burst_size=None): 68 | if rate != None: 69 | self.rate = rate 70 | else: 71 | self.rate = 0 72 | if burst_size != None: 73 | self.burst_size = burst_size 74 | else: 75 | self.burst_size = 0 76 | return 77 | 78 | def pack(self): 79 | packed = [] 80 | packed.append(struct.pack("!H", self.type)) 81 | packed.append(struct.pack("!H", 0)) # placeholder for len at index 1 82 | packed.append(struct.pack("!L", self.rate)) 83 | packed.append(struct.pack("!L", self.burst_size)) 84 | packed.append('\x00' * 4) 85 | length = sum([len(x) for x in packed]) 86 | packed[1] = struct.pack("!H", length) 87 | return ''.join(packed) 88 | 89 | @staticmethod 90 | def unpack(reader): 91 | obj = drop() 92 | _type = reader.read("!H")[0] 93 | assert(_type == 1) 94 | _len = reader.read("!H")[0] 95 | orig_reader = reader 96 | reader = orig_reader.slice(_len, 4) 97 | obj.rate = reader.read("!L")[0] 98 | obj.burst_size = reader.read("!L")[0] 99 | reader.skip(4) 100 | return obj 101 | 102 | def __eq__(self, other): 103 | if type(self) != type(other): return False 104 | if self.rate != other.rate: return False 105 | if self.burst_size != other.burst_size: return False 106 | return True 107 | 108 | def pretty_print(self, q): 109 | q.text("drop {") 110 | with q.group(): 111 | with q.indent(2): 112 | q.breakable() 113 | q.text("rate = "); 114 | q.text("%#x" % self.rate) 115 | q.text(","); q.breakable() 116 | q.text("burst_size = "); 117 | q.text("%#x" % self.burst_size) 118 | q.breakable() 119 | q.text('}') 120 | 121 | meter_band.subtypes[1] = drop 122 | 123 | class dscp_remark(meter_band): 124 | type = 2 125 | 126 | def __init__(self, rate=None, burst_size=None, prec_level=None): 127 | if rate != None: 128 | self.rate = rate 129 | else: 130 | self.rate = 0 131 | if burst_size != None: 132 | self.burst_size = burst_size 133 | else: 134 | self.burst_size = 0 135 | if prec_level != None: 136 | self.prec_level = prec_level 137 | else: 138 | self.prec_level = 0 139 | return 140 | 141 | def pack(self): 142 | packed = [] 143 | packed.append(struct.pack("!H", self.type)) 144 | packed.append(struct.pack("!H", 0)) # placeholder for len at index 1 145 | packed.append(struct.pack("!L", self.rate)) 146 | packed.append(struct.pack("!L", self.burst_size)) 147 | packed.append(struct.pack("!B", self.prec_level)) 148 | packed.append('\x00' * 3) 149 | length = sum([len(x) for x in packed]) 150 | packed[1] = struct.pack("!H", length) 151 | return ''.join(packed) 152 | 153 | @staticmethod 154 | def unpack(reader): 155 | obj = dscp_remark() 156 | _type = reader.read("!H")[0] 157 | assert(_type == 2) 158 | _len = reader.read("!H")[0] 159 | orig_reader = reader 160 | reader = orig_reader.slice(_len, 4) 161 | obj.rate = reader.read("!L")[0] 162 | obj.burst_size = reader.read("!L")[0] 163 | obj.prec_level = reader.read("!B")[0] 164 | reader.skip(3) 165 | return obj 166 | 167 | def __eq__(self, other): 168 | if type(self) != type(other): return False 169 | if self.rate != other.rate: return False 170 | if self.burst_size != other.burst_size: return False 171 | if self.prec_level != other.prec_level: return False 172 | return True 173 | 174 | def pretty_print(self, q): 175 | q.text("dscp_remark {") 176 | with q.group(): 177 | with q.indent(2): 178 | q.breakable() 179 | q.text("rate = "); 180 | q.text("%#x" % self.rate) 181 | q.text(","); q.breakable() 182 | q.text("burst_size = "); 183 | q.text("%#x" % self.burst_size) 184 | q.text(","); q.breakable() 185 | q.text("prec_level = "); 186 | q.text("%#x" % self.prec_level) 187 | q.breakable() 188 | q.text('}') 189 | 190 | meter_band.subtypes[2] = dscp_remark 191 | 192 | class experimenter(meter_band): 193 | type = 65535 194 | 195 | def __init__(self, rate=None, burst_size=None, experimenter=None): 196 | if rate != None: 197 | self.rate = rate 198 | else: 199 | self.rate = 0 200 | if burst_size != None: 201 | self.burst_size = burst_size 202 | else: 203 | self.burst_size = 0 204 | if experimenter != None: 205 | self.experimenter = experimenter 206 | else: 207 | self.experimenter = 0 208 | return 209 | 210 | def pack(self): 211 | packed = [] 212 | packed.append(struct.pack("!H", self.type)) 213 | packed.append(struct.pack("!H", 0)) # placeholder for len at index 1 214 | packed.append(struct.pack("!L", self.rate)) 215 | packed.append(struct.pack("!L", self.burst_size)) 216 | packed.append(struct.pack("!L", self.experimenter)) 217 | length = sum([len(x) for x in packed]) 218 | packed[1] = struct.pack("!H", length) 219 | return ''.join(packed) 220 | 221 | @staticmethod 222 | def unpack(reader): 223 | obj = experimenter() 224 | _type = reader.read("!H")[0] 225 | assert(_type == 65535) 226 | _len = reader.read("!H")[0] 227 | orig_reader = reader 228 | reader = orig_reader.slice(_len, 4) 229 | obj.rate = reader.read("!L")[0] 230 | obj.burst_size = reader.read("!L")[0] 231 | obj.experimenter = reader.read("!L")[0] 232 | return obj 233 | 234 | def __eq__(self, other): 235 | if type(self) != type(other): return False 236 | if self.rate != other.rate: return False 237 | if self.burst_size != other.burst_size: return False 238 | if self.experimenter != other.experimenter: return False 239 | return True 240 | 241 | def pretty_print(self, q): 242 | q.text("experimenter {") 243 | with q.group(): 244 | with q.indent(2): 245 | q.breakable() 246 | q.text("rate = "); 247 | q.text("%#x" % self.rate) 248 | q.text(","); q.breakable() 249 | q.text("burst_size = "); 250 | q.text("%#x" % self.burst_size) 251 | q.text(","); q.breakable() 252 | q.text("experimenter = "); 253 | q.text("%#x" % self.experimenter) 254 | q.breakable() 255 | q.text('}') 256 | 257 | meter_band.subtypes[65535] = experimenter 258 | 259 | 260 | -------------------------------------------------------------------------------- /src/python/loxi/of13/util.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior University 2 | # Copyright (c) 2011, 2012 Open Networking Foundation 3 | # Copyright (c) 2012, 2013 Big Switch Networks, Inc. 4 | # See the file LICENSE.pyloxi which should have been included in the source distribution 5 | # Automatically generated by LOXI from template util.py 6 | # Do not modify 7 | 8 | import struct 9 | from . import const 10 | 11 | def pretty_mac(mac): 12 | return ':'.join(["%02x" % x for x in mac]) 13 | 14 | def pretty_ipv4(v): 15 | return "%d.%d.%d.%d" % ((v >> 24) & 0xFF, (v >> 16) & 0xFF, (v >> 8) & 0xFF, v & 0xFF) 16 | 17 | def pretty_ipv6(v): 18 | return ":".join(["%0.2x%0.2x" % (ord(v[i]), ord(v[i+1])) for i in range(0, len(v), 2)]) 19 | 20 | def pretty_flags(v, flag_names): 21 | set_flags = [] 22 | for flag_name in flag_names: 23 | flag_value = getattr(const, flag_name) 24 | if v & flag_value == flag_value: 25 | set_flags.append(flag_name) 26 | elif v & flag_value: 27 | set_flags.append('%s&%#x' % (flag_name, v & flag_value)) 28 | v &= ~flag_value 29 | if v: 30 | set_flags.append("%#x" % v) 31 | return '|'.join(set_flags) or '0' 32 | 33 | 34 | def pretty_port(v): 35 | named_ports = [(k,v2) for (k,v2) in const.__dict__.items() if k.startswith('OFPP_')] 36 | for (k, v2) in named_ports: 37 | if v == v2: 38 | return k 39 | return v 40 | 41 | def pack_port_no(value): 42 | return struct.pack("!L", value) 43 | 44 | def unpack_port_no(reader): 45 | return reader.read("!L")[0] 46 | 47 | def pack_fm_cmd(value): 48 | return struct.pack("!B", value) 49 | 50 | def unpack_fm_cmd(reader): 51 | return reader.read("!B")[0] 52 | 53 | def init_wc_bmap(): 54 | return 0 55 | 56 | def pack_wc_bmap(value): 57 | return struct.pack("!Q", value) 58 | 59 | def unpack_wc_bmap(reader): 60 | return reader.read("!Q")[0] 61 | 62 | def init_match_bmap(): 63 | return 0 64 | 65 | def pack_match_bmap(value): 66 | return struct.pack("!Q", value) 67 | 68 | def unpack_match_bmap(reader): 69 | return reader.read("!Q")[0] 70 | 71 | MASK64 = (1 << 64) - 1 72 | 73 | def pack_bitmap_128(value): 74 | x = 0l 75 | for y in value: 76 | x |= 1 << y 77 | return struct.pack("!QQ", (x >> 64) & MASK64, x & MASK64) 78 | 79 | def unpack_bitmap_128(reader): 80 | hi, lo = reader.read("!QQ") 81 | x = (hi << 64) | lo 82 | i = 0 83 | value = set() 84 | while x != 0: 85 | if x & 1 == 1: 86 | value.add(i) 87 | i += 1 88 | x >>= 1 89 | return value 90 | 91 | def pack_bitmap_512(value): 92 | words = [0] * 8 93 | for v in value: 94 | assert v < 512 95 | words[7-int(v/64)] |= 1 << (v % 64) 96 | return struct.pack("!8Q", *words) 97 | 98 | def unpack_bitmap_512(reader): 99 | words = reader.read("!8Q") 100 | x = 0l 101 | for word in words: 102 | x <<= 64 103 | x |= word 104 | i = 0 105 | value = set() 106 | while x != 0: 107 | if x & 1 == 1: 108 | value.add(i) 109 | i += 1 110 | x >>= 1 111 | return value 112 | 113 | def pack_checksum_128(value): 114 | return struct.pack("!QQ", (value >> 64) & MASK64, value & MASK64) 115 | 116 | def unpack_checksum_128(reader): 117 | hi, lo = reader.read("!QQ") 118 | return (hi << 64) | lo 119 | -------------------------------------------------------------------------------- /src/python/loxi/of14/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior University 2 | # Copyright (c) 2011, 2012 Open Networking Foundation 3 | # Copyright (c) 2012, 2013 Big Switch Networks, Inc. 4 | # See the file LICENSE.pyloxi which should have been included in the source distribution 5 | 6 | # Automatically generated by LOXI from template init.py 7 | # Do not modify 8 | 9 | from . import action 10 | from . import action_id 11 | from . import oxm 12 | from . import message 13 | from . import async_config_prop 14 | from . import bsn_tlv 15 | from . import bundle_prop 16 | from . import instruction 17 | from . import instruction_id 18 | from . import meter_band 19 | from . import port_desc_prop 20 | from . import port_mod_prop 21 | from . import port_stats_prop 22 | from . import queue_desc_prop 23 | from . import queue_stats_prop 24 | from . import role_prop 25 | from . import table_mod_prop 26 | from .const import * 27 | from .common import * 28 | from loxi import ProtocolError 29 | -------------------------------------------------------------------------------- /src/python/loxi/of14/bundle_prop.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior University 2 | # Copyright (c) 2011, 2012 Open Networking Foundation 3 | # Copyright (c) 2012, 2013 Big Switch Networks, Inc. 4 | # See the file LICENSE.pyloxi which should have been included in the source distribution 5 | 6 | # Automatically generated by LOXI from template module.py 7 | # Do not modify 8 | 9 | import struct 10 | import loxi 11 | from . import util 12 | import loxi.generic_util 13 | 14 | import sys 15 | ofp = sys.modules['loxi.of14'] 16 | 17 | class bundle_prop(loxi.OFObject): 18 | subtypes = {} 19 | 20 | 21 | def __init__(self, type=None): 22 | if type != None: 23 | self.type = type 24 | else: 25 | self.type = 0 26 | return 27 | 28 | def pack(self): 29 | packed = [] 30 | packed.append(struct.pack("!H", self.type)) 31 | packed.append(struct.pack("!H", 0)) # placeholder for length at index 1 32 | length = sum([len(x) for x in packed]) 33 | packed[1] = struct.pack("!H", length) 34 | return ''.join(packed) 35 | 36 | @staticmethod 37 | def unpack(reader): 38 | subtype, = reader.peek('!H', 0) 39 | subclass = bundle_prop.subtypes.get(subtype) 40 | if subclass: 41 | return subclass.unpack(reader) 42 | 43 | obj = bundle_prop() 44 | obj.type = reader.read("!H")[0] 45 | _length = reader.read("!H")[0] 46 | orig_reader = reader 47 | reader = orig_reader.slice(_length, 4) 48 | return obj 49 | 50 | def __eq__(self, other): 51 | if type(self) != type(other): return False 52 | if self.type != other.type: return False 53 | return True 54 | 55 | def pretty_print(self, q): 56 | q.text("bundle_prop {") 57 | with q.group(): 58 | with q.indent(2): 59 | q.breakable() 60 | q.breakable() 61 | q.text('}') 62 | 63 | 64 | class experimenter(bundle_prop): 65 | subtypes = {} 66 | 67 | type = 65535 68 | 69 | def __init__(self, experimenter=None, exp_type=None): 70 | if experimenter != None: 71 | self.experimenter = experimenter 72 | else: 73 | self.experimenter = 0 74 | if exp_type != None: 75 | self.exp_type = exp_type 76 | else: 77 | self.exp_type = 0 78 | return 79 | 80 | def pack(self): 81 | packed = [] 82 | packed.append(struct.pack("!H", self.type)) 83 | packed.append(struct.pack("!H", 0)) # placeholder for length at index 1 84 | packed.append(struct.pack("!L", self.experimenter)) 85 | packed.append(struct.pack("!L", self.exp_type)) 86 | length = sum([len(x) for x in packed]) 87 | packed[1] = struct.pack("!H", length) 88 | return ''.join(packed) 89 | 90 | @staticmethod 91 | def unpack(reader): 92 | subtype, = reader.peek('!L', 4) 93 | subclass = experimenter.subtypes.get(subtype) 94 | if subclass: 95 | return subclass.unpack(reader) 96 | 97 | obj = experimenter() 98 | _type = reader.read("!H")[0] 99 | assert(_type == 65535) 100 | _length = reader.read("!H")[0] 101 | orig_reader = reader 102 | reader = orig_reader.slice(_length, 4) 103 | obj.experimenter = reader.read("!L")[0] 104 | obj.exp_type = reader.read("!L")[0] 105 | return obj 106 | 107 | def __eq__(self, other): 108 | if type(self) != type(other): return False 109 | if self.experimenter != other.experimenter: return False 110 | if self.exp_type != other.exp_type: return False 111 | return True 112 | 113 | def pretty_print(self, q): 114 | q.text("experimenter {") 115 | with q.group(): 116 | with q.indent(2): 117 | q.breakable() 118 | q.text("exp_type = "); 119 | q.text("%#x" % self.exp_type) 120 | q.breakable() 121 | q.text('}') 122 | 123 | bundle_prop.subtypes[65535] = experimenter 124 | 125 | 126 | -------------------------------------------------------------------------------- /src/python/loxi/of14/meter_band.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior University 2 | # Copyright (c) 2011, 2012 Open Networking Foundation 3 | # Copyright (c) 2012, 2013 Big Switch Networks, Inc. 4 | # See the file LICENSE.pyloxi which should have been included in the source distribution 5 | 6 | # Automatically generated by LOXI from template module.py 7 | # Do not modify 8 | 9 | import struct 10 | import loxi 11 | from . import util 12 | import loxi.generic_util 13 | 14 | import sys 15 | ofp = sys.modules['loxi.of14'] 16 | 17 | class meter_band(loxi.OFObject): 18 | subtypes = {} 19 | 20 | 21 | def __init__(self, type=None): 22 | if type != None: 23 | self.type = type 24 | else: 25 | self.type = 0 26 | return 27 | 28 | def pack(self): 29 | packed = [] 30 | packed.append(struct.pack("!H", self.type)) 31 | packed.append(struct.pack("!H", 0)) # placeholder for len at index 1 32 | length = sum([len(x) for x in packed]) 33 | packed[1] = struct.pack("!H", length) 34 | return ''.join(packed) 35 | 36 | @staticmethod 37 | def unpack(reader): 38 | subtype, = reader.peek('!H', 0) 39 | subclass = meter_band.subtypes.get(subtype) 40 | if subclass: 41 | return subclass.unpack(reader) 42 | 43 | obj = meter_band() 44 | obj.type = reader.read("!H")[0] 45 | _len = reader.read("!H")[0] 46 | orig_reader = reader 47 | reader = orig_reader.slice(_len, 4) 48 | return obj 49 | 50 | def __eq__(self, other): 51 | if type(self) != type(other): return False 52 | if self.type != other.type: return False 53 | return True 54 | 55 | def pretty_print(self, q): 56 | q.text("meter_band {") 57 | with q.group(): 58 | with q.indent(2): 59 | q.breakable() 60 | q.breakable() 61 | q.text('}') 62 | 63 | 64 | class drop(meter_band): 65 | type = 1 66 | 67 | def __init__(self, rate=None, burst_size=None): 68 | if rate != None: 69 | self.rate = rate 70 | else: 71 | self.rate = 0 72 | if burst_size != None: 73 | self.burst_size = burst_size 74 | else: 75 | self.burst_size = 0 76 | return 77 | 78 | def pack(self): 79 | packed = [] 80 | packed.append(struct.pack("!H", self.type)) 81 | packed.append(struct.pack("!H", 0)) # placeholder for len at index 1 82 | packed.append(struct.pack("!L", self.rate)) 83 | packed.append(struct.pack("!L", self.burst_size)) 84 | packed.append('\x00' * 4) 85 | length = sum([len(x) for x in packed]) 86 | packed[1] = struct.pack("!H", length) 87 | return ''.join(packed) 88 | 89 | @staticmethod 90 | def unpack(reader): 91 | obj = drop() 92 | _type = reader.read("!H")[0] 93 | assert(_type == 1) 94 | _len = reader.read("!H")[0] 95 | orig_reader = reader 96 | reader = orig_reader.slice(_len, 4) 97 | obj.rate = reader.read("!L")[0] 98 | obj.burst_size = reader.read("!L")[0] 99 | reader.skip(4) 100 | return obj 101 | 102 | def __eq__(self, other): 103 | if type(self) != type(other): return False 104 | if self.rate != other.rate: return False 105 | if self.burst_size != other.burst_size: return False 106 | return True 107 | 108 | def pretty_print(self, q): 109 | q.text("drop {") 110 | with q.group(): 111 | with q.indent(2): 112 | q.breakable() 113 | q.text("rate = "); 114 | q.text("%#x" % self.rate) 115 | q.text(","); q.breakable() 116 | q.text("burst_size = "); 117 | q.text("%#x" % self.burst_size) 118 | q.breakable() 119 | q.text('}') 120 | 121 | meter_band.subtypes[1] = drop 122 | 123 | class dscp_remark(meter_band): 124 | type = 2 125 | 126 | def __init__(self, rate=None, burst_size=None, prec_level=None): 127 | if rate != None: 128 | self.rate = rate 129 | else: 130 | self.rate = 0 131 | if burst_size != None: 132 | self.burst_size = burst_size 133 | else: 134 | self.burst_size = 0 135 | if prec_level != None: 136 | self.prec_level = prec_level 137 | else: 138 | self.prec_level = 0 139 | return 140 | 141 | def pack(self): 142 | packed = [] 143 | packed.append(struct.pack("!H", self.type)) 144 | packed.append(struct.pack("!H", 0)) # placeholder for len at index 1 145 | packed.append(struct.pack("!L", self.rate)) 146 | packed.append(struct.pack("!L", self.burst_size)) 147 | packed.append(struct.pack("!B", self.prec_level)) 148 | packed.append('\x00' * 3) 149 | length = sum([len(x) for x in packed]) 150 | packed[1] = struct.pack("!H", length) 151 | return ''.join(packed) 152 | 153 | @staticmethod 154 | def unpack(reader): 155 | obj = dscp_remark() 156 | _type = reader.read("!H")[0] 157 | assert(_type == 2) 158 | _len = reader.read("!H")[0] 159 | orig_reader = reader 160 | reader = orig_reader.slice(_len, 4) 161 | obj.rate = reader.read("!L")[0] 162 | obj.burst_size = reader.read("!L")[0] 163 | obj.prec_level = reader.read("!B")[0] 164 | reader.skip(3) 165 | return obj 166 | 167 | def __eq__(self, other): 168 | if type(self) != type(other): return False 169 | if self.rate != other.rate: return False 170 | if self.burst_size != other.burst_size: return False 171 | if self.prec_level != other.prec_level: return False 172 | return True 173 | 174 | def pretty_print(self, q): 175 | q.text("dscp_remark {") 176 | with q.group(): 177 | with q.indent(2): 178 | q.breakable() 179 | q.text("rate = "); 180 | q.text("%#x" % self.rate) 181 | q.text(","); q.breakable() 182 | q.text("burst_size = "); 183 | q.text("%#x" % self.burst_size) 184 | q.text(","); q.breakable() 185 | q.text("prec_level = "); 186 | q.text("%#x" % self.prec_level) 187 | q.breakable() 188 | q.text('}') 189 | 190 | meter_band.subtypes[2] = dscp_remark 191 | 192 | class experimenter(meter_band): 193 | type = 65535 194 | 195 | def __init__(self, rate=None, burst_size=None, experimenter=None): 196 | if rate != None: 197 | self.rate = rate 198 | else: 199 | self.rate = 0 200 | if burst_size != None: 201 | self.burst_size = burst_size 202 | else: 203 | self.burst_size = 0 204 | if experimenter != None: 205 | self.experimenter = experimenter 206 | else: 207 | self.experimenter = 0 208 | return 209 | 210 | def pack(self): 211 | packed = [] 212 | packed.append(struct.pack("!H", self.type)) 213 | packed.append(struct.pack("!H", 0)) # placeholder for len at index 1 214 | packed.append(struct.pack("!L", self.rate)) 215 | packed.append(struct.pack("!L", self.burst_size)) 216 | packed.append(struct.pack("!L", self.experimenter)) 217 | length = sum([len(x) for x in packed]) 218 | packed[1] = struct.pack("!H", length) 219 | return ''.join(packed) 220 | 221 | @staticmethod 222 | def unpack(reader): 223 | obj = experimenter() 224 | _type = reader.read("!H")[0] 225 | assert(_type == 65535) 226 | _len = reader.read("!H")[0] 227 | orig_reader = reader 228 | reader = orig_reader.slice(_len, 4) 229 | obj.rate = reader.read("!L")[0] 230 | obj.burst_size = reader.read("!L")[0] 231 | obj.experimenter = reader.read("!L")[0] 232 | return obj 233 | 234 | def __eq__(self, other): 235 | if type(self) != type(other): return False 236 | if self.rate != other.rate: return False 237 | if self.burst_size != other.burst_size: return False 238 | if self.experimenter != other.experimenter: return False 239 | return True 240 | 241 | def pretty_print(self, q): 242 | q.text("experimenter {") 243 | with q.group(): 244 | with q.indent(2): 245 | q.breakable() 246 | q.text("rate = "); 247 | q.text("%#x" % self.rate) 248 | q.text(","); q.breakable() 249 | q.text("burst_size = "); 250 | q.text("%#x" % self.burst_size) 251 | q.text(","); q.breakable() 252 | q.text("experimenter = "); 253 | q.text("%#x" % self.experimenter) 254 | q.breakable() 255 | q.text('}') 256 | 257 | meter_band.subtypes[65535] = experimenter 258 | 259 | 260 | -------------------------------------------------------------------------------- /src/python/loxi/of14/queue_stats_prop.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior University 2 | # Copyright (c) 2011, 2012 Open Networking Foundation 3 | # Copyright (c) 2012, 2013 Big Switch Networks, Inc. 4 | # See the file LICENSE.pyloxi which should have been included in the source distribution 5 | 6 | # Automatically generated by LOXI from template module.py 7 | # Do not modify 8 | 9 | import struct 10 | import loxi 11 | from . import util 12 | import loxi.generic_util 13 | 14 | import sys 15 | ofp = sys.modules['loxi.of14'] 16 | 17 | class queue_stats_prop(loxi.OFObject): 18 | subtypes = {} 19 | 20 | 21 | def __init__(self, type=None): 22 | if type != None: 23 | self.type = type 24 | else: 25 | self.type = 0 26 | return 27 | 28 | def pack(self): 29 | packed = [] 30 | packed.append(struct.pack("!H", self.type)) 31 | packed.append(struct.pack("!H", 0)) # placeholder for length at index 1 32 | length = sum([len(x) for x in packed]) 33 | packed[1] = struct.pack("!H", length) 34 | return ''.join(packed) 35 | 36 | @staticmethod 37 | def unpack(reader): 38 | subtype, = reader.peek('!H', 0) 39 | subclass = queue_stats_prop.subtypes.get(subtype) 40 | if subclass: 41 | return subclass.unpack(reader) 42 | 43 | obj = queue_stats_prop() 44 | obj.type = reader.read("!H")[0] 45 | _length = reader.read("!H")[0] 46 | orig_reader = reader 47 | reader = orig_reader.slice(_length, 4) 48 | return obj 49 | 50 | def __eq__(self, other): 51 | if type(self) != type(other): return False 52 | if self.type != other.type: return False 53 | return True 54 | 55 | def pretty_print(self, q): 56 | q.text("queue_stats_prop {") 57 | with q.group(): 58 | with q.indent(2): 59 | q.breakable() 60 | q.breakable() 61 | q.text('}') 62 | 63 | 64 | class experimenter(queue_stats_prop): 65 | subtypes = {} 66 | 67 | type = 65535 68 | 69 | def __init__(self, experimenter=None, exp_type=None): 70 | if experimenter != None: 71 | self.experimenter = experimenter 72 | else: 73 | self.experimenter = 0 74 | if exp_type != None: 75 | self.exp_type = exp_type 76 | else: 77 | self.exp_type = 0 78 | return 79 | 80 | def pack(self): 81 | packed = [] 82 | packed.append(struct.pack("!H", self.type)) 83 | packed.append(struct.pack("!H", 0)) # placeholder for length at index 1 84 | packed.append(struct.pack("!L", self.experimenter)) 85 | packed.append(struct.pack("!L", self.exp_type)) 86 | length = sum([len(x) for x in packed]) 87 | packed[1] = struct.pack("!H", length) 88 | return ''.join(packed) 89 | 90 | @staticmethod 91 | def unpack(reader): 92 | subtype, = reader.peek('!L', 4) 93 | subclass = experimenter.subtypes.get(subtype) 94 | if subclass: 95 | return subclass.unpack(reader) 96 | 97 | obj = experimenter() 98 | _type = reader.read("!H")[0] 99 | assert(_type == 65535) 100 | _length = reader.read("!H")[0] 101 | orig_reader = reader 102 | reader = orig_reader.slice(_length, 4) 103 | obj.experimenter = reader.read("!L")[0] 104 | obj.exp_type = reader.read("!L")[0] 105 | return obj 106 | 107 | def __eq__(self, other): 108 | if type(self) != type(other): return False 109 | if self.experimenter != other.experimenter: return False 110 | if self.exp_type != other.exp_type: return False 111 | return True 112 | 113 | def pretty_print(self, q): 114 | q.text("experimenter {") 115 | with q.group(): 116 | with q.indent(2): 117 | q.breakable() 118 | q.text("exp_type = "); 119 | q.text("%#x" % self.exp_type) 120 | q.breakable() 121 | q.text('}') 122 | 123 | queue_stats_prop.subtypes[65535] = experimenter 124 | 125 | 126 | -------------------------------------------------------------------------------- /src/python/loxi/of14/role_prop.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior University 2 | # Copyright (c) 2011, 2012 Open Networking Foundation 3 | # Copyright (c) 2012, 2013 Big Switch Networks, Inc. 4 | # See the file LICENSE.pyloxi which should have been included in the source distribution 5 | 6 | # Automatically generated by LOXI from template module.py 7 | # Do not modify 8 | 9 | import struct 10 | import loxi 11 | from . import util 12 | import loxi.generic_util 13 | 14 | import sys 15 | ofp = sys.modules['loxi.of14'] 16 | 17 | class role_prop(loxi.OFObject): 18 | subtypes = {} 19 | 20 | 21 | def __init__(self, type=None): 22 | if type != None: 23 | self.type = type 24 | else: 25 | self.type = 0 26 | return 27 | 28 | def pack(self): 29 | packed = [] 30 | packed.append(struct.pack("!H", self.type)) 31 | packed.append(struct.pack("!H", 0)) # placeholder for length at index 1 32 | length = sum([len(x) for x in packed]) 33 | packed[1] = struct.pack("!H", length) 34 | return ''.join(packed) 35 | 36 | @staticmethod 37 | def unpack(reader): 38 | subtype, = reader.peek('!H', 0) 39 | subclass = role_prop.subtypes.get(subtype) 40 | if subclass: 41 | return subclass.unpack(reader) 42 | 43 | obj = role_prop() 44 | obj.type = reader.read("!H")[0] 45 | _length = reader.read("!H")[0] 46 | orig_reader = reader 47 | reader = orig_reader.slice(_length, 4) 48 | return obj 49 | 50 | def __eq__(self, other): 51 | if type(self) != type(other): return False 52 | if self.type != other.type: return False 53 | return True 54 | 55 | def pretty_print(self, q): 56 | q.text("role_prop {") 57 | with q.group(): 58 | with q.indent(2): 59 | q.breakable() 60 | q.breakable() 61 | q.text('}') 62 | 63 | 64 | class experimenter(role_prop): 65 | subtypes = {} 66 | 67 | type = 65535 68 | 69 | def __init__(self, experimenter=None, exp_type=None): 70 | if experimenter != None: 71 | self.experimenter = experimenter 72 | else: 73 | self.experimenter = 0 74 | if exp_type != None: 75 | self.exp_type = exp_type 76 | else: 77 | self.exp_type = 0 78 | return 79 | 80 | def pack(self): 81 | packed = [] 82 | packed.append(struct.pack("!H", self.type)) 83 | packed.append(struct.pack("!H", 0)) # placeholder for length at index 1 84 | packed.append(struct.pack("!L", self.experimenter)) 85 | packed.append(struct.pack("!L", self.exp_type)) 86 | length = sum([len(x) for x in packed]) 87 | packed[1] = struct.pack("!H", length) 88 | return ''.join(packed) 89 | 90 | @staticmethod 91 | def unpack(reader): 92 | subtype, = reader.peek('!L', 4) 93 | subclass = experimenter.subtypes.get(subtype) 94 | if subclass: 95 | return subclass.unpack(reader) 96 | 97 | obj = experimenter() 98 | _type = reader.read("!H")[0] 99 | assert(_type == 65535) 100 | _length = reader.read("!H")[0] 101 | orig_reader = reader 102 | reader = orig_reader.slice(_length, 4) 103 | obj.experimenter = reader.read("!L")[0] 104 | obj.exp_type = reader.read("!L")[0] 105 | return obj 106 | 107 | def __eq__(self, other): 108 | if type(self) != type(other): return False 109 | if self.experimenter != other.experimenter: return False 110 | if self.exp_type != other.exp_type: return False 111 | return True 112 | 113 | def pretty_print(self, q): 114 | q.text("experimenter {") 115 | with q.group(): 116 | with q.indent(2): 117 | q.breakable() 118 | q.text("exp_type = "); 119 | q.text("%#x" % self.exp_type) 120 | q.breakable() 121 | q.text('}') 122 | 123 | role_prop.subtypes[65535] = experimenter 124 | 125 | 126 | -------------------------------------------------------------------------------- /src/python/loxi/of14/table_mod_prop.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior University 2 | # Copyright (c) 2011, 2012 Open Networking Foundation 3 | # Copyright (c) 2012, 2013 Big Switch Networks, Inc. 4 | # See the file LICENSE.pyloxi which should have been included in the source distribution 5 | 6 | # Automatically generated by LOXI from template module.py 7 | # Do not modify 8 | 9 | import struct 10 | import loxi 11 | from . import util 12 | import loxi.generic_util 13 | 14 | import sys 15 | ofp = sys.modules['loxi.of14'] 16 | 17 | class table_mod_prop(loxi.OFObject): 18 | subtypes = {} 19 | 20 | 21 | def __init__(self, type=None): 22 | if type != None: 23 | self.type = type 24 | else: 25 | self.type = 0 26 | return 27 | 28 | def pack(self): 29 | packed = [] 30 | packed.append(struct.pack("!H", self.type)) 31 | packed.append(struct.pack("!H", 0)) # placeholder for length at index 1 32 | length = sum([len(x) for x in packed]) 33 | packed[1] = struct.pack("!H", length) 34 | return ''.join(packed) 35 | 36 | @staticmethod 37 | def unpack(reader): 38 | subtype, = reader.peek('!H', 0) 39 | subclass = table_mod_prop.subtypes.get(subtype) 40 | if subclass: 41 | return subclass.unpack(reader) 42 | 43 | obj = table_mod_prop() 44 | obj.type = reader.read("!H")[0] 45 | _length = reader.read("!H")[0] 46 | orig_reader = reader 47 | reader = orig_reader.slice(_length, 4) 48 | return obj 49 | 50 | def __eq__(self, other): 51 | if type(self) != type(other): return False 52 | if self.type != other.type: return False 53 | return True 54 | 55 | def pretty_print(self, q): 56 | q.text("table_mod_prop {") 57 | with q.group(): 58 | with q.indent(2): 59 | q.breakable() 60 | q.breakable() 61 | q.text('}') 62 | 63 | 64 | 65 | -------------------------------------------------------------------------------- /src/python/loxi/of14/util.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior University 2 | # Copyright (c) 2011, 2012 Open Networking Foundation 3 | # Copyright (c) 2012, 2013 Big Switch Networks, Inc. 4 | # See the file LICENSE.pyloxi which should have been included in the source distribution 5 | # Automatically generated by LOXI from template util.py 6 | # Do not modify 7 | 8 | import struct 9 | from . import const 10 | 11 | def pretty_mac(mac): 12 | return ':'.join(["%02x" % x for x in mac]) 13 | 14 | def pretty_ipv4(v): 15 | return "%d.%d.%d.%d" % ((v >> 24) & 0xFF, (v >> 16) & 0xFF, (v >> 8) & 0xFF, v & 0xFF) 16 | 17 | def pretty_ipv6(v): 18 | return ":".join(["%0.2x%0.2x" % (ord(v[i]), ord(v[i+1])) for i in range(0, len(v), 2)]) 19 | 20 | def pretty_flags(v, flag_names): 21 | set_flags = [] 22 | for flag_name in flag_names: 23 | flag_value = getattr(const, flag_name) 24 | if v & flag_value == flag_value: 25 | set_flags.append(flag_name) 26 | elif v & flag_value: 27 | set_flags.append('%s&%#x' % (flag_name, v & flag_value)) 28 | v &= ~flag_value 29 | if v: 30 | set_flags.append("%#x" % v) 31 | return '|'.join(set_flags) or '0' 32 | 33 | 34 | def pretty_port(v): 35 | named_ports = [(k,v2) for (k,v2) in const.__dict__.items() if k.startswith('OFPP_')] 36 | for (k, v2) in named_ports: 37 | if v == v2: 38 | return k 39 | return v 40 | 41 | def pack_port_no(value): 42 | return struct.pack("!L", value) 43 | 44 | def unpack_port_no(reader): 45 | return reader.read("!L")[0] 46 | 47 | def pack_fm_cmd(value): 48 | return struct.pack("!B", value) 49 | 50 | def unpack_fm_cmd(reader): 51 | return reader.read("!B")[0] 52 | 53 | def init_wc_bmap(): 54 | return 0 55 | 56 | def pack_wc_bmap(value): 57 | return struct.pack("!Q", value) 58 | 59 | def unpack_wc_bmap(reader): 60 | return reader.read("!Q")[0] 61 | 62 | def init_match_bmap(): 63 | return 0 64 | 65 | def pack_match_bmap(value): 66 | return struct.pack("!Q", value) 67 | 68 | def unpack_match_bmap(reader): 69 | return reader.read("!Q")[0] 70 | 71 | MASK64 = (1 << 64) - 1 72 | 73 | def pack_bitmap_128(value): 74 | x = 0l 75 | for y in value: 76 | x |= 1 << y 77 | return struct.pack("!QQ", (x >> 64) & MASK64, x & MASK64) 78 | 79 | def unpack_bitmap_128(reader): 80 | hi, lo = reader.read("!QQ") 81 | x = (hi << 64) | lo 82 | i = 0 83 | value = set() 84 | while x != 0: 85 | if x & 1 == 1: 86 | value.add(i) 87 | i += 1 88 | x >>= 1 89 | return value 90 | 91 | def pack_bitmap_512(value): 92 | words = [0] * 8 93 | for v in value: 94 | assert v < 512 95 | words[7-int(v/64)] |= 1 << (v % 64) 96 | return struct.pack("!8Q", *words) 97 | 98 | def unpack_bitmap_512(reader): 99 | words = reader.read("!8Q") 100 | x = 0l 101 | for word in words: 102 | x <<= 64 103 | x |= word 104 | i = 0 105 | value = set() 106 | while x != 0: 107 | if x & 1 == 1: 108 | value.add(i) 109 | i += 1 110 | x >>= 1 111 | return value 112 | 113 | def pack_checksum_128(value): 114 | return struct.pack("!QQ", (value >> 64) & MASK64, value & MASK64) 115 | 116 | def unpack_checksum_128(reader): 117 | hi, lo = reader.read("!QQ") 118 | return (hi << 64) | lo 119 | -------------------------------------------------------------------------------- /src/python/loxi/of15/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior University 2 | # Copyright (c) 2011, 2012 Open Networking Foundation 3 | # Copyright (c) 2012, 2013 Big Switch Networks, Inc. 4 | # See the file LICENSE.pyloxi which should have been included in the source distribution 5 | 6 | # Automatically generated by LOXI from template init.py 7 | # Do not modify 8 | 9 | from . import action 10 | from . import action_id 11 | from . import oxm 12 | from . import message 13 | from . import async_config_prop 14 | from . import bsn_tlv 15 | from . import bundle_prop 16 | from . import instruction 17 | from . import instruction_id 18 | from . import meter_band 19 | from . import port_desc_prop 20 | from . import port_mod_prop 21 | from . import port_stats_prop 22 | from . import queue_desc_prop 23 | from . import queue_stats_prop 24 | from . import role_prop 25 | from . import table_mod_prop 26 | from .const import * 27 | from .common import * 28 | from loxi import ProtocolError 29 | -------------------------------------------------------------------------------- /src/python/loxi/of15/bundle_prop.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior University 2 | # Copyright (c) 2011, 2012 Open Networking Foundation 3 | # Copyright (c) 2012, 2013 Big Switch Networks, Inc. 4 | # See the file LICENSE.pyloxi which should have been included in the source distribution 5 | 6 | # Automatically generated by LOXI from template module.py 7 | # Do not modify 8 | 9 | import struct 10 | import loxi 11 | from . import util 12 | import loxi.generic_util 13 | 14 | import sys 15 | ofp = sys.modules['loxi.of15'] 16 | 17 | class bundle_prop(loxi.OFObject): 18 | subtypes = {} 19 | 20 | 21 | def __init__(self, type=None): 22 | if type != None: 23 | self.type = type 24 | else: 25 | self.type = 0 26 | return 27 | 28 | def pack(self): 29 | packed = [] 30 | packed.append(struct.pack("!H", self.type)) 31 | packed.append(struct.pack("!H", 0)) # placeholder for length at index 1 32 | length = sum([len(x) for x in packed]) 33 | packed[1] = struct.pack("!H", length) 34 | return ''.join(packed) 35 | 36 | @staticmethod 37 | def unpack(reader): 38 | subtype, = reader.peek('!H', 0) 39 | subclass = bundle_prop.subtypes.get(subtype) 40 | if subclass: 41 | return subclass.unpack(reader) 42 | 43 | obj = bundle_prop() 44 | obj.type = reader.read("!H")[0] 45 | _length = reader.read("!H")[0] 46 | orig_reader = reader 47 | reader = orig_reader.slice(_length, 4) 48 | return obj 49 | 50 | def __eq__(self, other): 51 | if type(self) != type(other): return False 52 | if self.type != other.type: return False 53 | return True 54 | 55 | def pretty_print(self, q): 56 | q.text("bundle_prop {") 57 | with q.group(): 58 | with q.indent(2): 59 | q.breakable() 60 | q.breakable() 61 | q.text('}') 62 | 63 | 64 | class experimenter(bundle_prop): 65 | subtypes = {} 66 | 67 | type = 65535 68 | 69 | def __init__(self, experimenter=None, exp_type=None): 70 | if experimenter != None: 71 | self.experimenter = experimenter 72 | else: 73 | self.experimenter = 0 74 | if exp_type != None: 75 | self.exp_type = exp_type 76 | else: 77 | self.exp_type = 0 78 | return 79 | 80 | def pack(self): 81 | packed = [] 82 | packed.append(struct.pack("!H", self.type)) 83 | packed.append(struct.pack("!H", 0)) # placeholder for length at index 1 84 | packed.append(struct.pack("!L", self.experimenter)) 85 | packed.append(struct.pack("!L", self.exp_type)) 86 | length = sum([len(x) for x in packed]) 87 | packed[1] = struct.pack("!H", length) 88 | return ''.join(packed) 89 | 90 | @staticmethod 91 | def unpack(reader): 92 | subtype, = reader.peek('!L', 4) 93 | subclass = experimenter.subtypes.get(subtype) 94 | if subclass: 95 | return subclass.unpack(reader) 96 | 97 | obj = experimenter() 98 | _type = reader.read("!H")[0] 99 | assert(_type == 65535) 100 | _length = reader.read("!H")[0] 101 | orig_reader = reader 102 | reader = orig_reader.slice(_length, 4) 103 | obj.experimenter = reader.read("!L")[0] 104 | obj.exp_type = reader.read("!L")[0] 105 | return obj 106 | 107 | def __eq__(self, other): 108 | if type(self) != type(other): return False 109 | if self.experimenter != other.experimenter: return False 110 | if self.exp_type != other.exp_type: return False 111 | return True 112 | 113 | def pretty_print(self, q): 114 | q.text("experimenter {") 115 | with q.group(): 116 | with q.indent(2): 117 | q.breakable() 118 | q.text("exp_type = "); 119 | q.text("%#x" % self.exp_type) 120 | q.breakable() 121 | q.text('}') 122 | 123 | bundle_prop.subtypes[65535] = experimenter 124 | 125 | class time(bundle_prop): 126 | type = 1 127 | 128 | def __init__(self, scheduled_time=None): 129 | if scheduled_time != None: 130 | self.scheduled_time = scheduled_time 131 | else: 132 | self.scheduled_time = [] 133 | return 134 | 135 | def pack(self): 136 | packed = [] 137 | packed.append(struct.pack("!H", self.type)) 138 | packed.append(struct.pack("!H", 0)) # placeholder for length at index 1 139 | packed.append('\x00' * 4) 140 | packed.append(loxi.generic_util.pack_list(self.scheduled_time)) 141 | length = sum([len(x) for x in packed]) 142 | packed[1] = struct.pack("!H", length) 143 | return ''.join(packed) 144 | 145 | @staticmethod 146 | def unpack(reader): 147 | obj = time() 148 | _type = reader.read("!H")[0] 149 | assert(_type == 1) 150 | _length = reader.read("!H")[0] 151 | orig_reader = reader 152 | reader = orig_reader.slice(_length, 4) 153 | reader.skip(4) 154 | obj.scheduled_time = loxi.generic_util.unpack_list(reader, ofp.common.time.unpack) 155 | return obj 156 | 157 | def __eq__(self, other): 158 | if type(self) != type(other): return False 159 | if self.scheduled_time != other.scheduled_time: return False 160 | return True 161 | 162 | def pretty_print(self, q): 163 | q.text("time {") 164 | with q.group(): 165 | with q.indent(2): 166 | q.breakable() 167 | q.text("scheduled_time = "); 168 | q.pp(self.scheduled_time) 169 | q.breakable() 170 | q.text('}') 171 | 172 | bundle_prop.subtypes[1] = time 173 | 174 | 175 | -------------------------------------------------------------------------------- /src/python/loxi/of15/queue_stats_prop.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior University 2 | # Copyright (c) 2011, 2012 Open Networking Foundation 3 | # Copyright (c) 2012, 2013 Big Switch Networks, Inc. 4 | # See the file LICENSE.pyloxi which should have been included in the source distribution 5 | 6 | # Automatically generated by LOXI from template module.py 7 | # Do not modify 8 | 9 | import struct 10 | import loxi 11 | from . import util 12 | import loxi.generic_util 13 | 14 | import sys 15 | ofp = sys.modules['loxi.of15'] 16 | 17 | class queue_stats_prop(loxi.OFObject): 18 | subtypes = {} 19 | 20 | 21 | def __init__(self, type=None): 22 | if type != None: 23 | self.type = type 24 | else: 25 | self.type = 0 26 | return 27 | 28 | def pack(self): 29 | packed = [] 30 | packed.append(struct.pack("!H", self.type)) 31 | packed.append(struct.pack("!H", 0)) # placeholder for length at index 1 32 | length = sum([len(x) for x in packed]) 33 | packed[1] = struct.pack("!H", length) 34 | return ''.join(packed) 35 | 36 | @staticmethod 37 | def unpack(reader): 38 | subtype, = reader.peek('!H', 0) 39 | subclass = queue_stats_prop.subtypes.get(subtype) 40 | if subclass: 41 | return subclass.unpack(reader) 42 | 43 | obj = queue_stats_prop() 44 | obj.type = reader.read("!H")[0] 45 | _length = reader.read("!H")[0] 46 | orig_reader = reader 47 | reader = orig_reader.slice(_length, 4) 48 | return obj 49 | 50 | def __eq__(self, other): 51 | if type(self) != type(other): return False 52 | if self.type != other.type: return False 53 | return True 54 | 55 | def pretty_print(self, q): 56 | q.text("queue_stats_prop {") 57 | with q.group(): 58 | with q.indent(2): 59 | q.breakable() 60 | q.breakable() 61 | q.text('}') 62 | 63 | 64 | class experimenter(queue_stats_prop): 65 | subtypes = {} 66 | 67 | type = 65535 68 | 69 | def __init__(self, experimenter=None, exp_type=None): 70 | if experimenter != None: 71 | self.experimenter = experimenter 72 | else: 73 | self.experimenter = 0 74 | if exp_type != None: 75 | self.exp_type = exp_type 76 | else: 77 | self.exp_type = 0 78 | return 79 | 80 | def pack(self): 81 | packed = [] 82 | packed.append(struct.pack("!H", self.type)) 83 | packed.append(struct.pack("!H", 0)) # placeholder for length at index 1 84 | packed.append(struct.pack("!L", self.experimenter)) 85 | packed.append(struct.pack("!L", self.exp_type)) 86 | length = sum([len(x) for x in packed]) 87 | packed[1] = struct.pack("!H", length) 88 | return ''.join(packed) 89 | 90 | @staticmethod 91 | def unpack(reader): 92 | subtype, = reader.peek('!L', 4) 93 | subclass = experimenter.subtypes.get(subtype) 94 | if subclass: 95 | return subclass.unpack(reader) 96 | 97 | obj = experimenter() 98 | _type = reader.read("!H")[0] 99 | assert(_type == 65535) 100 | _length = reader.read("!H")[0] 101 | orig_reader = reader 102 | reader = orig_reader.slice(_length, 4) 103 | obj.experimenter = reader.read("!L")[0] 104 | obj.exp_type = reader.read("!L")[0] 105 | return obj 106 | 107 | def __eq__(self, other): 108 | if type(self) != type(other): return False 109 | if self.experimenter != other.experimenter: return False 110 | if self.exp_type != other.exp_type: return False 111 | return True 112 | 113 | def pretty_print(self, q): 114 | q.text("experimenter {") 115 | with q.group(): 116 | with q.indent(2): 117 | q.breakable() 118 | q.text("exp_type = "); 119 | q.text("%#x" % self.exp_type) 120 | q.breakable() 121 | q.text('}') 122 | 123 | queue_stats_prop.subtypes[65535] = experimenter 124 | 125 | class bsn(experimenter): 126 | type = 65535 127 | experimenter = 6035143 128 | exp_type = 0 129 | 130 | def __init__(self, experimenter_data=None): 131 | if experimenter_data != None: 132 | self.experimenter_data = experimenter_data 133 | else: 134 | self.experimenter_data = '' 135 | return 136 | 137 | def pack(self): 138 | packed = [] 139 | packed.append(struct.pack("!H", self.type)) 140 | packed.append(struct.pack("!H", 0)) # placeholder for length at index 1 141 | packed.append(struct.pack("!L", self.experimenter)) 142 | packed.append(struct.pack("!L", self.exp_type)) 143 | packed.append(self.experimenter_data) 144 | length = sum([len(x) for x in packed]) 145 | packed[1] = struct.pack("!H", length) 146 | return ''.join(packed) 147 | 148 | @staticmethod 149 | def unpack(reader): 150 | obj = bsn() 151 | _type = reader.read("!H")[0] 152 | assert(_type == 65535) 153 | _length = reader.read("!H")[0] 154 | orig_reader = reader 155 | reader = orig_reader.slice(_length, 4) 156 | _experimenter = reader.read("!L")[0] 157 | assert(_experimenter == 6035143) 158 | _exp_type = reader.read("!L")[0] 159 | assert(_exp_type == 0) 160 | obj.experimenter_data = str(reader.read_all()) 161 | return obj 162 | 163 | def __eq__(self, other): 164 | if type(self) != type(other): return False 165 | if self.experimenter_data != other.experimenter_data: return False 166 | return True 167 | 168 | def pretty_print(self, q): 169 | q.text("bsn {") 170 | with q.group(): 171 | with q.indent(2): 172 | q.breakable() 173 | q.text("experimenter_data = "); 174 | q.pp(self.experimenter_data) 175 | q.breakable() 176 | q.text('}') 177 | 178 | experimenter.subtypes[6035143] = bsn 179 | 180 | 181 | -------------------------------------------------------------------------------- /src/python/loxi/of15/role_prop.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior University 2 | # Copyright (c) 2011, 2012 Open Networking Foundation 3 | # Copyright (c) 2012, 2013 Big Switch Networks, Inc. 4 | # See the file LICENSE.pyloxi which should have been included in the source distribution 5 | 6 | # Automatically generated by LOXI from template module.py 7 | # Do not modify 8 | 9 | import struct 10 | import loxi 11 | from . import util 12 | import loxi.generic_util 13 | 14 | import sys 15 | ofp = sys.modules['loxi.of15'] 16 | 17 | class role_prop(loxi.OFObject): 18 | subtypes = {} 19 | 20 | 21 | def __init__(self, type=None): 22 | if type != None: 23 | self.type = type 24 | else: 25 | self.type = 0 26 | return 27 | 28 | def pack(self): 29 | packed = [] 30 | packed.append(struct.pack("!H", self.type)) 31 | packed.append(struct.pack("!H", 0)) # placeholder for length at index 1 32 | length = sum([len(x) for x in packed]) 33 | packed[1] = struct.pack("!H", length) 34 | return ''.join(packed) 35 | 36 | @staticmethod 37 | def unpack(reader): 38 | subtype, = reader.peek('!H', 0) 39 | subclass = role_prop.subtypes.get(subtype) 40 | if subclass: 41 | return subclass.unpack(reader) 42 | 43 | obj = role_prop() 44 | obj.type = reader.read("!H")[0] 45 | _length = reader.read("!H")[0] 46 | orig_reader = reader 47 | reader = orig_reader.slice(_length, 4) 48 | return obj 49 | 50 | def __eq__(self, other): 51 | if type(self) != type(other): return False 52 | if self.type != other.type: return False 53 | return True 54 | 55 | def pretty_print(self, q): 56 | q.text("role_prop {") 57 | with q.group(): 58 | with q.indent(2): 59 | q.breakable() 60 | q.breakable() 61 | q.text('}') 62 | 63 | 64 | class experimenter(role_prop): 65 | subtypes = {} 66 | 67 | type = 65535 68 | 69 | def __init__(self, experimenter=None, exp_type=None): 70 | if experimenter != None: 71 | self.experimenter = experimenter 72 | else: 73 | self.experimenter = 0 74 | if exp_type != None: 75 | self.exp_type = exp_type 76 | else: 77 | self.exp_type = 0 78 | return 79 | 80 | def pack(self): 81 | packed = [] 82 | packed.append(struct.pack("!H", self.type)) 83 | packed.append(struct.pack("!H", 0)) # placeholder for length at index 1 84 | packed.append(struct.pack("!L", self.experimenter)) 85 | packed.append(struct.pack("!L", self.exp_type)) 86 | length = sum([len(x) for x in packed]) 87 | packed[1] = struct.pack("!H", length) 88 | return ''.join(packed) 89 | 90 | @staticmethod 91 | def unpack(reader): 92 | subtype, = reader.peek('!L', 4) 93 | subclass = experimenter.subtypes.get(subtype) 94 | if subclass: 95 | return subclass.unpack(reader) 96 | 97 | obj = experimenter() 98 | _type = reader.read("!H")[0] 99 | assert(_type == 65535) 100 | _length = reader.read("!H")[0] 101 | orig_reader = reader 102 | reader = orig_reader.slice(_length, 4) 103 | obj.experimenter = reader.read("!L")[0] 104 | obj.exp_type = reader.read("!L")[0] 105 | return obj 106 | 107 | def __eq__(self, other): 108 | if type(self) != type(other): return False 109 | if self.experimenter != other.experimenter: return False 110 | if self.exp_type != other.exp_type: return False 111 | return True 112 | 113 | def pretty_print(self, q): 114 | q.text("experimenter {") 115 | with q.group(): 116 | with q.indent(2): 117 | q.breakable() 118 | q.text("exp_type = "); 119 | q.text("%#x" % self.exp_type) 120 | q.breakable() 121 | q.text('}') 122 | 123 | role_prop.subtypes[65535] = experimenter 124 | 125 | class bsn(experimenter): 126 | type = 65535 127 | experimenter = 6035143 128 | exp_type = 55 129 | 130 | def __init__(self, experimenter_data=None): 131 | if experimenter_data != None: 132 | self.experimenter_data = experimenter_data 133 | else: 134 | self.experimenter_data = '' 135 | return 136 | 137 | def pack(self): 138 | packed = [] 139 | packed.append(struct.pack("!H", self.type)) 140 | packed.append(struct.pack("!H", 0)) # placeholder for length at index 1 141 | packed.append(struct.pack("!L", self.experimenter)) 142 | packed.append(struct.pack("!L", self.exp_type)) 143 | packed.append(self.experimenter_data) 144 | length = sum([len(x) for x in packed]) 145 | packed[1] = struct.pack("!H", length) 146 | return ''.join(packed) 147 | 148 | @staticmethod 149 | def unpack(reader): 150 | obj = bsn() 151 | _type = reader.read("!H")[0] 152 | assert(_type == 65535) 153 | _length = reader.read("!H")[0] 154 | orig_reader = reader 155 | reader = orig_reader.slice(_length, 4) 156 | _experimenter = reader.read("!L")[0] 157 | assert(_experimenter == 6035143) 158 | _exp_type = reader.read("!L")[0] 159 | assert(_exp_type == 55) 160 | obj.experimenter_data = str(reader.read_all()) 161 | return obj 162 | 163 | def __eq__(self, other): 164 | if type(self) != type(other): return False 165 | if self.experimenter_data != other.experimenter_data: return False 166 | return True 167 | 168 | def pretty_print(self, q): 169 | q.text("bsn {") 170 | with q.group(): 171 | with q.indent(2): 172 | q.breakable() 173 | q.text("experimenter_data = "); 174 | q.pp(self.experimenter_data) 175 | q.breakable() 176 | q.text('}') 177 | 178 | experimenter.subtypes[6035143] = bsn 179 | 180 | 181 | -------------------------------------------------------------------------------- /src/python/loxi/of15/table_mod_prop.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior University 2 | # Copyright (c) 2011, 2012 Open Networking Foundation 3 | # Copyright (c) 2012, 2013 Big Switch Networks, Inc. 4 | # See the file LICENSE.pyloxi which should have been included in the source distribution 5 | 6 | # Automatically generated by LOXI from template module.py 7 | # Do not modify 8 | 9 | import struct 10 | import loxi 11 | from . import util 12 | import loxi.generic_util 13 | 14 | import sys 15 | ofp = sys.modules['loxi.of15'] 16 | 17 | class table_mod_prop(loxi.OFObject): 18 | subtypes = {} 19 | 20 | 21 | def __init__(self, type=None): 22 | if type != None: 23 | self.type = type 24 | else: 25 | self.type = 0 26 | return 27 | 28 | def pack(self): 29 | packed = [] 30 | packed.append(struct.pack("!H", self.type)) 31 | packed.append(struct.pack("!H", 0)) # placeholder for length at index 1 32 | length = sum([len(x) for x in packed]) 33 | packed[1] = struct.pack("!H", length) 34 | return ''.join(packed) 35 | 36 | @staticmethod 37 | def unpack(reader): 38 | subtype, = reader.peek('!H', 0) 39 | subclass = table_mod_prop.subtypes.get(subtype) 40 | if subclass: 41 | return subclass.unpack(reader) 42 | 43 | obj = table_mod_prop() 44 | obj.type = reader.read("!H")[0] 45 | _length = reader.read("!H")[0] 46 | orig_reader = reader 47 | reader = orig_reader.slice(_length, 4) 48 | return obj 49 | 50 | def __eq__(self, other): 51 | if type(self) != type(other): return False 52 | if self.type != other.type: return False 53 | return True 54 | 55 | def pretty_print(self, q): 56 | q.text("table_mod_prop {") 57 | with q.group(): 58 | with q.indent(2): 59 | q.breakable() 60 | q.breakable() 61 | q.text('}') 62 | 63 | 64 | class eviction(table_mod_prop): 65 | type = 2 66 | 67 | def __init__(self, flags=None): 68 | if flags != None: 69 | self.flags = flags 70 | else: 71 | self.flags = 0 72 | return 73 | 74 | def pack(self): 75 | packed = [] 76 | packed.append(struct.pack("!H", self.type)) 77 | packed.append(struct.pack("!H", 0)) # placeholder for length at index 1 78 | packed.append(struct.pack("!L", self.flags)) 79 | length = sum([len(x) for x in packed]) 80 | packed[1] = struct.pack("!H", length) 81 | return ''.join(packed) 82 | 83 | @staticmethod 84 | def unpack(reader): 85 | obj = eviction() 86 | _type = reader.read("!H")[0] 87 | assert(_type == 2) 88 | _length = reader.read("!H")[0] 89 | orig_reader = reader 90 | reader = orig_reader.slice(_length, 4) 91 | obj.flags = reader.read("!L")[0] 92 | return obj 93 | 94 | def __eq__(self, other): 95 | if type(self) != type(other): return False 96 | if self.flags != other.flags: return False 97 | return True 98 | 99 | def pretty_print(self, q): 100 | q.text("eviction {") 101 | with q.group(): 102 | with q.indent(2): 103 | q.breakable() 104 | q.text("flags = "); 105 | value_name_map = {1: 'OFPTMPEF_OTHER', 2: 'OFPTMPEF_IMPORTANCE', 4: 'OFPTMPEF_LIFETIME'} 106 | q.text(util.pretty_flags(self.flags, value_name_map.values())) 107 | q.breakable() 108 | q.text('}') 109 | 110 | table_mod_prop.subtypes[2] = eviction 111 | 112 | class experimenter(table_mod_prop): 113 | subtypes = {} 114 | 115 | type = 65535 116 | 117 | def __init__(self, experimenter=None, exp_type=None): 118 | if experimenter != None: 119 | self.experimenter = experimenter 120 | else: 121 | self.experimenter = 0 122 | if exp_type != None: 123 | self.exp_type = exp_type 124 | else: 125 | self.exp_type = 0 126 | return 127 | 128 | def pack(self): 129 | packed = [] 130 | packed.append(struct.pack("!H", self.type)) 131 | packed.append(struct.pack("!H", 0)) # placeholder for length at index 1 132 | packed.append(struct.pack("!L", self.experimenter)) 133 | packed.append(struct.pack("!L", self.exp_type)) 134 | length = sum([len(x) for x in packed]) 135 | packed[1] = struct.pack("!H", length) 136 | return ''.join(packed) 137 | 138 | @staticmethod 139 | def unpack(reader): 140 | subtype, = reader.peek('!L', 4) 141 | subclass = experimenter.subtypes.get(subtype) 142 | if subclass: 143 | return subclass.unpack(reader) 144 | 145 | obj = experimenter() 146 | _type = reader.read("!H")[0] 147 | assert(_type == 65535) 148 | _length = reader.read("!H")[0] 149 | orig_reader = reader 150 | reader = orig_reader.slice(_length, 4) 151 | obj.experimenter = reader.read("!L")[0] 152 | obj.exp_type = reader.read("!L")[0] 153 | return obj 154 | 155 | def __eq__(self, other): 156 | if type(self) != type(other): return False 157 | if self.experimenter != other.experimenter: return False 158 | if self.exp_type != other.exp_type: return False 159 | return True 160 | 161 | def pretty_print(self, q): 162 | q.text("experimenter {") 163 | with q.group(): 164 | with q.indent(2): 165 | q.breakable() 166 | q.text("exp_type = "); 167 | q.text("%#x" % self.exp_type) 168 | q.breakable() 169 | q.text('}') 170 | 171 | table_mod_prop.subtypes[65535] = experimenter 172 | 173 | class vacancy(table_mod_prop): 174 | type = 3 175 | 176 | def __init__(self, vacancy_down=None, vacancy_up=None, vacancy=None): 177 | if vacancy_down != None: 178 | self.vacancy_down = vacancy_down 179 | else: 180 | self.vacancy_down = 0 181 | if vacancy_up != None: 182 | self.vacancy_up = vacancy_up 183 | else: 184 | self.vacancy_up = 0 185 | if vacancy != None: 186 | self.vacancy = vacancy 187 | else: 188 | self.vacancy = 0 189 | return 190 | 191 | def pack(self): 192 | packed = [] 193 | packed.append(struct.pack("!H", self.type)) 194 | packed.append(struct.pack("!H", 0)) # placeholder for length at index 1 195 | packed.append(struct.pack("!B", self.vacancy_down)) 196 | packed.append(struct.pack("!B", self.vacancy_up)) 197 | packed.append(struct.pack("!B", self.vacancy)) 198 | packed.append('\x00' * 1) 199 | length = sum([len(x) for x in packed]) 200 | packed[1] = struct.pack("!H", length) 201 | return ''.join(packed) 202 | 203 | @staticmethod 204 | def unpack(reader): 205 | obj = vacancy() 206 | _type = reader.read("!H")[0] 207 | assert(_type == 3) 208 | _length = reader.read("!H")[0] 209 | orig_reader = reader 210 | reader = orig_reader.slice(_length, 4) 211 | obj.vacancy_down = reader.read("!B")[0] 212 | obj.vacancy_up = reader.read("!B")[0] 213 | obj.vacancy = reader.read("!B")[0] 214 | reader.skip(1) 215 | return obj 216 | 217 | def __eq__(self, other): 218 | if type(self) != type(other): return False 219 | if self.vacancy_down != other.vacancy_down: return False 220 | if self.vacancy_up != other.vacancy_up: return False 221 | if self.vacancy != other.vacancy: return False 222 | return True 223 | 224 | def pretty_print(self, q): 225 | q.text("vacancy {") 226 | with q.group(): 227 | with q.indent(2): 228 | q.breakable() 229 | q.text("vacancy_down = "); 230 | q.text("%#x" % self.vacancy_down) 231 | q.text(","); q.breakable() 232 | q.text("vacancy_up = "); 233 | q.text("%#x" % self.vacancy_up) 234 | q.text(","); q.breakable() 235 | q.text("vacancy = "); 236 | q.text("%#x" % self.vacancy) 237 | q.breakable() 238 | q.text('}') 239 | 240 | table_mod_prop.subtypes[3] = vacancy 241 | 242 | 243 | -------------------------------------------------------------------------------- /src/python/loxi/of15/util.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior University 2 | # Copyright (c) 2011, 2012 Open Networking Foundation 3 | # Copyright (c) 2012, 2013 Big Switch Networks, Inc. 4 | # See the file LICENSE.pyloxi which should have been included in the source distribution 5 | # Automatically generated by LOXI from template util.py 6 | # Do not modify 7 | 8 | import struct 9 | from . import const 10 | 11 | def pretty_mac(mac): 12 | return ':'.join(["%02x" % x for x in mac]) 13 | 14 | def pretty_ipv4(v): 15 | return "%d.%d.%d.%d" % ((v >> 24) & 0xFF, (v >> 16) & 0xFF, (v >> 8) & 0xFF, v & 0xFF) 16 | 17 | def pretty_ipv6(v): 18 | return ":".join(["%0.2x%0.2x" % (ord(v[i]), ord(v[i+1])) for i in range(0, len(v), 2)]) 19 | 20 | def pretty_flags(v, flag_names): 21 | set_flags = [] 22 | for flag_name in flag_names: 23 | flag_value = getattr(const, flag_name) 24 | if v & flag_value == flag_value: 25 | set_flags.append(flag_name) 26 | elif v & flag_value: 27 | set_flags.append('%s&%#x' % (flag_name, v & flag_value)) 28 | v &= ~flag_value 29 | if v: 30 | set_flags.append("%#x" % v) 31 | return '|'.join(set_flags) or '0' 32 | 33 | 34 | def pretty_port(v): 35 | named_ports = [(k,v2) for (k,v2) in const.__dict__.items() if k.startswith('OFPP_')] 36 | for (k, v2) in named_ports: 37 | if v == v2: 38 | return k 39 | return v 40 | 41 | def pack_port_no(value): 42 | return struct.pack("!L", value) 43 | 44 | def unpack_port_no(reader): 45 | return reader.read("!L")[0] 46 | 47 | def pack_fm_cmd(value): 48 | return struct.pack("!B", value) 49 | 50 | def unpack_fm_cmd(reader): 51 | return reader.read("!B")[0] 52 | 53 | def init_wc_bmap(): 54 | return 0 55 | 56 | def pack_wc_bmap(value): 57 | return struct.pack("!Q", value) 58 | 59 | def unpack_wc_bmap(reader): 60 | return reader.read("!Q")[0] 61 | 62 | def init_match_bmap(): 63 | return 0 64 | 65 | def pack_match_bmap(value): 66 | return struct.pack("!Q", value) 67 | 68 | def unpack_match_bmap(reader): 69 | return reader.read("!Q")[0] 70 | 71 | MASK64 = (1 << 64) - 1 72 | 73 | def pack_bitmap_128(value): 74 | x = 0l 75 | for y in value: 76 | x |= 1 << y 77 | return struct.pack("!QQ", (x >> 64) & MASK64, x & MASK64) 78 | 79 | def unpack_bitmap_128(reader): 80 | hi, lo = reader.read("!QQ") 81 | x = (hi << 64) | lo 82 | i = 0 83 | value = set() 84 | while x != 0: 85 | if x & 1 == 1: 86 | value.add(i) 87 | i += 1 88 | x >>= 1 89 | return value 90 | 91 | def pack_bitmap_512(value): 92 | words = [0] * 8 93 | for v in value: 94 | assert v < 512 95 | words[7-int(v/64)] |= 1 << (v % 64) 96 | return struct.pack("!8Q", *words) 97 | 98 | def unpack_bitmap_512(reader): 99 | words = reader.read("!8Q") 100 | x = 0l 101 | for word in words: 102 | x <<= 64 103 | x |= word 104 | i = 0 105 | value = set() 106 | while x != 0: 107 | if x & 1 == 1: 108 | value.add(i) 109 | i += 1 110 | x >>= 1 111 | return value 112 | 113 | def pack_checksum_128(value): 114 | return struct.pack("!QQ", (value >> 64) & MASK64, value & MASK64) 115 | 116 | def unpack_checksum_128(reader): 117 | hi, lo = reader.read("!QQ") 118 | return (hi << 64) | lo 119 | -------------------------------------------------------------------------------- /src/python/loxi/pp.py: -------------------------------------------------------------------------------- 1 | # Copyright 2013, Big Switch Networks, Inc. 2 | 3 | """ 4 | pp - port of Ruby's PP library 5 | Also based on Lindig, C., & GbR, G. D. (2000). Strictly Pretty. 6 | 7 | Example usage: 8 | >>> import pp.pp as pp 9 | >>> print pp([[1, 2], [3, 4]], maxwidth=15) 10 | [ 11 | [ 1, 2 ], 12 | [ 3, 4 ] 13 | ] 14 | """ 15 | import unittest 16 | from contextlib import contextmanager 17 | 18 | def pp(obj, maxwidth=79): 19 | """ 20 | Pretty-print the given object. 21 | """ 22 | ctx = PrettyPrinter(maxwidth=maxwidth) 23 | ctx.pp(obj) 24 | return str(ctx) 25 | 26 | 27 | ## Pretty-printers for builtin classes 28 | 29 | def pretty_print_list(pp, obj): 30 | with pp.group(): 31 | pp.text('[') 32 | with pp.indent(2): 33 | for v in obj: 34 | if not pp.first(): pp.text(',') 35 | pp.breakable() 36 | pp.pp(v) 37 | pp.breakable() 38 | pp.text(']') 39 | 40 | def pretty_print_dict(pp, obj): 41 | with pp.group(): 42 | pp.text('{') 43 | with pp.indent(2): 44 | for (k, v) in sorted(obj.items()): 45 | if not pp.first(): pp.text(',') 46 | pp.breakable() 47 | pp.pp(k) 48 | pp.text(': ') 49 | pp.pp(v) 50 | pp.breakable() 51 | pp.text('}') 52 | 53 | pretty_printers = { 54 | list: pretty_print_list, 55 | dict: pretty_print_dict, 56 | } 57 | 58 | 59 | ## Implementation 60 | 61 | class PrettyPrinter(object): 62 | def __init__(self, maxwidth): 63 | self.maxwidth = maxwidth 64 | self.cur_indent = 0 65 | self.root_group = Group() 66 | self.group_stack = [self.root_group] 67 | 68 | def current_group(self): 69 | return self.group_stack[-1] 70 | 71 | def text(self, s): 72 | self.current_group().append(str(s)) 73 | 74 | def breakable(self, sep=' '): 75 | self.current_group().append(Breakable(sep, self.cur_indent)) 76 | 77 | def first(self): 78 | return self.current_group().first() 79 | 80 | @contextmanager 81 | def indent(self, n): 82 | self.cur_indent += n 83 | yield 84 | self.cur_indent -= n 85 | 86 | @contextmanager 87 | def group(self): 88 | self.group_stack.append(Group()) 89 | yield 90 | new_group = self.group_stack.pop() 91 | self.current_group().append(new_group) 92 | 93 | def pp(self, obj): 94 | if hasattr(obj, "pretty_print"): 95 | obj.pretty_print(self) 96 | elif type(obj) in pretty_printers: 97 | pretty_printers[type(obj)](self, obj) 98 | else: 99 | self.text(repr(obj)) 100 | 101 | def __str__(self): 102 | return self.root_group.render(0, self.maxwidth) 103 | 104 | class Group(object): 105 | __slots__ = ["fragments", "length", "_first"] 106 | 107 | def __init__(self): 108 | self.fragments = [] 109 | self.length = 0 110 | self._first = True 111 | 112 | def append(self, x): 113 | self.fragments.append(x) 114 | self.length += len(x) 115 | 116 | def first(self): 117 | if self._first: 118 | self._first = False 119 | return True 120 | return False 121 | 122 | def __len__(self): 123 | return self.length 124 | 125 | def render(self, curwidth, maxwidth): 126 | dobreak = len(self) > (maxwidth - curwidth) 127 | 128 | a = [] 129 | for x in self.fragments: 130 | if isinstance(x, Breakable): 131 | if dobreak: 132 | a.append('\n') 133 | a.append(' ' * x.indent) 134 | curwidth = 0 135 | else: 136 | a.append(x.sep) 137 | elif isinstance(x, Group): 138 | a.append(x.render(curwidth, maxwidth)) 139 | else: 140 | a.append(x) 141 | curwidth += len(a[-1]) 142 | return ''.join(a) 143 | 144 | class Breakable(object): 145 | __slots__ = ["sep", "indent"] 146 | 147 | def __init__(self, sep, indent): 148 | self.sep = sep 149 | self.indent = indent 150 | 151 | def __len__(self): 152 | return len(self.sep) 153 | 154 | 155 | ## Tests 156 | 157 | class TestPP(unittest.TestCase): 158 | def test_scalars(self): 159 | self.assertEquals(pp(1), "1") 160 | self.assertEquals(pp("foo"), "'foo'") 161 | 162 | def test_hash(self): 163 | expected = """{ 1: 'a', 'b': 2 }""" 164 | self.assertEquals(pp(eval(expected)), expected) 165 | expected = """\ 166 | { 167 | 1: 'a', 168 | 'b': 2 169 | }""" 170 | self.assertEquals(pp(eval(expected), maxwidth=0), expected) 171 | 172 | def test_array(self): 173 | expected = """[ 1, 'a', 2 ]""" 174 | self.assertEquals(pp(eval(expected)), expected) 175 | expected = """\ 176 | [ 177 | 1, 178 | 'a', 179 | 2 180 | ]""" 181 | self.assertEquals(pp(eval(expected), maxwidth=0), expected) 182 | 183 | def test_nested(self): 184 | expected = """[ [ 1, 2 ], [ 3, 4 ] ]""" 185 | self.assertEquals(pp(eval(expected)), expected) 186 | expected = """\ 187 | [ 188 | [ 189 | 1, 190 | 2 191 | ], 192 | [ 193 | 3, 194 | 4 195 | ] 196 | ]""" 197 | self.assertEquals(pp(eval(expected), maxwidth=0), expected) 198 | 199 | def test_breaking(self): 200 | expected = """\ 201 | [ 202 | [ 1, 2 ], 203 | 'abcdefghijklmnopqrstuvwxyz' 204 | ]""" 205 | self.assertEquals(pp(eval(expected), maxwidth=24), expected) 206 | expected = """\ 207 | [ 208 | [ 'abcd', 2 ], 209 | [ '0123456789' ], 210 | [ 211 | '0123456789', 212 | 'abcdefghij' 213 | ], 214 | [ 'abcdefghijklmnop' ], 215 | [ 216 | 'abcdefghijklmnopq' 217 | ], 218 | { 'k': 'v' }, 219 | { 220 | 1: [ 2, [ 3, 4 ] ], 221 | 'foo': 'abcdefghijklmnop' 222 | } 223 | ]""" 224 | self.assertEquals(pp(eval(expected), maxwidth=24), expected) 225 | expected = """\ 226 | [ 227 | [ 1, 2 ], 228 | [ 3, 4 ] 229 | ]""" 230 | self.assertEquals(pp(eval(expected), maxwidth=15), expected) 231 | 232 | # This is an edge case where our simpler algorithm breaks down. 233 | @unittest.expectedFailure 234 | def test_greedy_breaking(self): 235 | expected = """\ 236 | abc def 237 | ghijklmnopqrstuvwxyz\ 238 | """ 239 | pp = PrettyPrinter(maxwidth=8) 240 | pp.text("abc") 241 | with pp.group(): 242 | pp.breakable() 243 | pp.text("def") 244 | with pp.group(): 245 | pp.breakable() 246 | pp.text("ghijklmnopqrstuvwxyz") 247 | self.assertEquals(str(pp), expected) 248 | 249 | if __name__ == '__main__': 250 | unittest.main() 251 | -------------------------------------------------------------------------------- /src/python/oftest/__init__.py: -------------------------------------------------------------------------------- 1 | '''Docstring to silence pylint; ignores --ignore option for __init__.py''' 2 | import sys 3 | import os 4 | import logging 5 | 6 | # Global config dictionary 7 | # Populated by oft. 8 | config = {} 9 | 10 | # Global DataPlane instance used by all tests. 11 | # Populated by oft. 12 | dataplane_instance = None 13 | 14 | def open_logfile(name): 15 | """ 16 | (Re)open logfile 17 | 18 | When using a log directory a new logfile is created for each test. The same 19 | code is used to implement a single logfile in the absence of --log-dir. 20 | """ 21 | 22 | _format = "%(asctime)s.%(msecs)03d %(name)-10s: %(levelname)-8s: %(message)s" 23 | _datefmt = "%H:%M:%S" 24 | 25 | if config["log_dir"] != None: 26 | filename = os.path.join(config["log_dir"], name) + ".log" 27 | else: 28 | filename = config["log_file"] 29 | 30 | logger = logging.getLogger() 31 | 32 | # Remove any existing handlers 33 | for handler in logger.handlers: 34 | logger.removeHandler(handler) 35 | handler.close() 36 | 37 | # Add a new handler 38 | handler = logging.FileHandler(filename, mode='a') 39 | handler.setFormatter(logging.Formatter(_format, _datefmt)) 40 | logger.addHandler(handler) 41 | -------------------------------------------------------------------------------- /src/python/oftest/afpacket.py: -------------------------------------------------------------------------------- 1 | """ 2 | AF_PACKET receive support 3 | 4 | When VLAN offload is enabled on the NIC Linux will not deliver the VLAN tag 5 | in the data returned by recv. Instead, it delivers the VLAN TCI in a control 6 | message. Python 2.x doesn't have built-in support for recvmsg, so we have to 7 | use ctypes to call it. The recv function exported by this module reconstructs 8 | the VLAN tag if it was offloaded. 9 | """ 10 | 11 | import os 12 | import socket 13 | import errno 14 | import struct 15 | from ctypes import * 16 | 17 | ETH_P_8021Q = 0x8100 18 | SOL_PACKET = 263 19 | PACKET_AUXDATA = 8 20 | TP_STATUS_VLAN_VALID = 1 << 4 21 | 22 | class struct_iovec(Structure): 23 | _fields_ = [ 24 | ("iov_base", c_void_p), 25 | ("iov_len", c_size_t), 26 | ] 27 | 28 | class struct_msghdr(Structure): 29 | _fields_ = [ 30 | ("msg_name", c_void_p), 31 | ("msg_namelen", c_uint32), 32 | ("msg_iov", POINTER(struct_iovec)), 33 | ("msg_iovlen", c_size_t), 34 | ("msg_control", c_void_p), 35 | ("msg_controllen", c_size_t), 36 | ("msg_flags", c_int), 37 | ] 38 | 39 | class struct_cmsghdr(Structure): 40 | _fields_ = [ 41 | ("cmsg_len", c_size_t), 42 | ("cmsg_level", c_int), 43 | ("cmsg_type", c_int), 44 | ] 45 | 46 | class struct_tpacket_auxdata(Structure): 47 | _fields_ = [ 48 | ("tp_status", c_uint), 49 | ("tp_len", c_uint), 50 | ("tp_snaplen", c_uint), 51 | ("tp_mac", c_ushort), 52 | ("tp_net", c_ushort), 53 | ("tp_vlan_tci", c_ushort), 54 | ("tp_padding", c_ushort), 55 | ] 56 | 57 | libc = CDLL("libc.so.6") 58 | recvmsg = libc.recvmsg 59 | recvmsg.argtypes = [c_int, POINTER(struct_msghdr), c_int] 60 | recvmsg.retype = c_int 61 | 62 | # the above recvmsg uses libc c function call, 63 | # to get the errno, use external libc errno global variable, __errno_location 64 | get_errno_loc = libc.__errno_location 65 | get_errno_loc.restype = POINTER(c_int) 66 | 67 | def enable_auxdata(sk): 68 | """ 69 | Ask the kernel to return the VLAN tag in a control message 70 | 71 | Must be called on the socket before afpacket.recv. 72 | """ 73 | sk.setsockopt(SOL_PACKET, PACKET_AUXDATA, 1) 74 | 75 | def recv(sk, bufsize): 76 | """ 77 | Receive a packet from an AF_PACKET socket 78 | @sk Socket 79 | @bufsize Maximum packet size 80 | """ 81 | buf = create_string_buffer(bufsize) 82 | 83 | ctrl_bufsize = sizeof(struct_cmsghdr) + sizeof(struct_tpacket_auxdata) + sizeof(c_size_t) 84 | ctrl_buf = create_string_buffer(ctrl_bufsize) 85 | 86 | iov = struct_iovec() 87 | iov.iov_base = cast(buf, c_void_p) 88 | iov.iov_len = bufsize 89 | 90 | msghdr = struct_msghdr() 91 | msghdr.msg_name = None 92 | msghdr.msg_namelen = 0 93 | msghdr.msg_iov = pointer(iov) 94 | msghdr.msg_iovlen = 1 95 | msghdr.msg_control = cast(ctrl_buf, c_void_p) 96 | msghdr.msg_controllen = ctrl_bufsize 97 | msghdr.msg_flags = 0 98 | 99 | rv = recvmsg(sk.fileno(), byref(msghdr), 0) 100 | if rv < 0: 101 | # when recvmsg return negative, it could be caused by the corresponding 102 | # interface down, raise the ENETDOWN exception to caller. 103 | # Other errors will be treated as runtime errors 104 | e = get_errno_loc()[0] 105 | if e == errno.ENETDOWN: 106 | # raise exception with socket number 107 | raise OSError(errno.ENETDOWN, "Connection Down", sk.fileno()) 108 | else: 109 | raise RuntimeError("recvmsg failed: rv=%d", rv) 110 | 111 | # The kernel only delivers control messages we ask for. We 112 | # only enabled PACKET_AUXDATA, so we can assume it's the 113 | # only control message. 114 | assert msghdr.msg_controllen >= sizeof(struct_cmsghdr) 115 | 116 | cmsghdr = struct_cmsghdr.from_buffer(ctrl_buf) # pylint: disable=E1101 117 | assert cmsghdr.cmsg_level == SOL_PACKET 118 | assert cmsghdr.cmsg_type == PACKET_AUXDATA 119 | 120 | auxdata = struct_tpacket_auxdata.from_buffer(ctrl_buf, sizeof(struct_cmsghdr)) # pylint: disable=E1101 121 | 122 | if auxdata.tp_vlan_tci != 0 or auxdata.tp_status & TP_STATUS_VLAN_VALID: 123 | # Insert VLAN tag 124 | tag = struct.pack("!HH", ETH_P_8021Q, auxdata.tp_vlan_tci) 125 | return buf.raw[:12] + tag + buf.raw[12:rv] 126 | else: 127 | return buf.raw[:rv] 128 | -------------------------------------------------------------------------------- /src/python/oftest/base_tests.py: -------------------------------------------------------------------------------- 1 | """ 2 | Base classes for test cases 3 | 4 | Tests will usually inherit from one of these classes to have the controller 5 | and/or dataplane automatically set up. 6 | """ 7 | 8 | import logging 9 | import unittest 10 | import os 11 | 12 | import oftest 13 | from oftest import config 14 | import oftest.controller as controller 15 | import oftest.dataplane as dataplane 16 | import ofp 17 | 18 | class BaseTest(unittest.TestCase): 19 | def __str__(self): 20 | return self.id().replace('.runTest', '') 21 | 22 | def setUp(self): 23 | oftest.open_logfile(str(self)) 24 | logging.info("** START TEST CASE " + str(self)) 25 | 26 | def tearDown(self): 27 | logging.info("** END TEST CASE " + str(self)) 28 | 29 | class SimpleProtocol(BaseTest): 30 | """ 31 | Root class for setting up the controller 32 | """ 33 | 34 | def setUp(self): 35 | BaseTest.setUp(self) 36 | 37 | self.controller = controller.Controller( 38 | switch=config["switch_ip"], 39 | host=config["controller_host"], 40 | port=config["controller_port"]) 41 | self.controller.start() 42 | 43 | try: 44 | #@todo Add an option to wait for a pkt transaction to ensure version 45 | # compatibilty? 46 | self.controller.connect(timeout=20) 47 | 48 | # By default, respond to echo requests 49 | self.controller.keep_alive = True 50 | 51 | if not self.controller.active: 52 | raise Exception("Controller startup failed") 53 | if self.controller.switch_addr is None: 54 | raise Exception("Controller startup failed (no switch addr)") 55 | logging.info("Connected " + str(self.controller.switch_addr)) 56 | request = ofp.message.features_request() 57 | reply, pkt = self.controller.transact(request) 58 | self.assertTrue(reply is not None, 59 | "Did not complete features_request for handshake") 60 | if reply.version == 1: 61 | self.supported_actions = reply.actions 62 | logging.info("Supported actions: " + hex(self.supported_actions)) 63 | except: 64 | self.controller.kill() 65 | del self.controller 66 | raise 67 | 68 | def inheritSetup(self, parent): 69 | """ 70 | Inherit the setup of a parent 71 | 72 | This allows running at test from within another test. Do the 73 | following: 74 | 75 | sub_test = SomeTestClass() # Create an instance of the test class 76 | sub_test.inheritSetup(self) # Inherit setup of parent 77 | sub_test.runTest() # Run the test 78 | 79 | Normally, only the parent's setUp and tearDown are called and 80 | the state after the sub_test is run must be taken into account 81 | by subsequent operations. 82 | """ 83 | logging.info("** Setup " + str(self) + " inheriting from " 84 | + str(parent)) 85 | self.controller = parent.controller 86 | self.supported_actions = parent.supported_actions 87 | 88 | def tearDown(self): 89 | self.controller.shutdown() 90 | self.controller.join() 91 | del self.controller 92 | BaseTest.tearDown(self) 93 | 94 | def assertTrue(self, cond, msg): 95 | if not cond: 96 | logging.error("** FAILED ASSERTION: " + msg) 97 | unittest.TestCase.assertTrue(self, cond, msg) 98 | 99 | class SimpleDataPlane(SimpleProtocol): 100 | """ 101 | Root class that sets up the controller and dataplane 102 | """ 103 | def setUp(self): 104 | SimpleProtocol.setUp(self) 105 | self.dataplane = oftest.dataplane_instance 106 | self.dataplane.flush() 107 | if config["log_dir"] != None: 108 | filename = os.path.join(config["log_dir"], str(self)) + ".pcap" 109 | self.dataplane.start_pcap(filename) 110 | 111 | def inheritSetup(self, parent): 112 | """ 113 | Inherit the setup of a parent 114 | 115 | See SimpleProtocol.inheritSetup 116 | """ 117 | SimpleProtocol.inheritSetup(self, parent) 118 | self.dataplane = parent.dataplane 119 | 120 | def tearDown(self): 121 | if config["log_dir"] != None: 122 | self.dataplane.stop_pcap() 123 | SimpleProtocol.tearDown(self) 124 | 125 | class DataPlaneOnly(BaseTest): 126 | """ 127 | Root class that sets up only the dataplane 128 | """ 129 | 130 | def setUp(self): 131 | BaseTest.setUp(self) 132 | self.dataplane = oftest.dataplane_instance 133 | self.dataplane.flush() 134 | if config["log_dir"] != None: 135 | filename = os.path.join(config["log_dir"], str(self)) + ".pcap" 136 | self.dataplane.start_pcap(filename) 137 | 138 | def tearDown(self): 139 | if config["log_dir"] != None: 140 | self.dataplane.stop_pcap() 141 | BaseTest.tearDown(self) 142 | -------------------------------------------------------------------------------- /src/python/oftest/help_formatter.py: -------------------------------------------------------------------------------- 1 | import optparse 2 | 3 | # Don't wrap description text to give us more control over newlines. 4 | class HelpFormatter(optparse.IndentedHelpFormatter): 5 | def format_description(self, description): 6 | if description: 7 | indent = " "*self.current_indent 8 | return indent + description 9 | else: 10 | return None 11 | -------------------------------------------------------------------------------- /src/python/oftest/illegal_message.py: -------------------------------------------------------------------------------- 1 | """ 2 | Support an illegal message 3 | """ 4 | 5 | import struct 6 | import ofp 7 | 8 | class illegal_message_type(object): 9 | version = ofp.OFP_VERSION 10 | type = 217 11 | 12 | def __init__(self, xid=None): 13 | self.xid = xid 14 | 15 | def pack(self): 16 | packed = [] 17 | packed.append(struct.pack("!B", self.version)) 18 | packed.append(struct.pack("!B", self.type)) 19 | packed.append(struct.pack("!H", 0)) # placeholder for length at index 2 20 | packed.append(struct.pack("!L", self.xid)) 21 | length = sum([len(x) for x in packed]) 22 | packed[2] = struct.pack("!H", length) 23 | return ''.join(packed) 24 | 25 | @staticmethod 26 | def unpack(buf): 27 | raise NotImplementedError() 28 | 29 | def __eq__(self, other): 30 | if type(self) != type(other): return False 31 | if self.version != other.version: return False 32 | if self.type != other.type: return False 33 | if self.xid != other.xid: return False 34 | return True 35 | 36 | def __ne__(self, other): 37 | return not self.__eq__(other) 38 | 39 | def __str__(self): 40 | return self.show() 41 | 42 | def show(self): 43 | return "illegal_message_type" 44 | -------------------------------------------------------------------------------- /src/python/oftest/mpls.py: -------------------------------------------------------------------------------- 1 | # Imported from scapy at revision 1270:113ef25f9583 2 | # This file is not included in the Ubuntu packages of scapy, so it is checked 3 | # in to our repo to simplify installation. This file is under the GPLv2. 4 | 5 | # http://trac.secdev.org/scapy/ticket/31 6 | 7 | # scapy.contrib.description = MPLS 8 | # scapy.contrib.status = loads 9 | 10 | from scapy.packet import Packet,bind_layers 11 | from scapy.fields import BitField,ByteField 12 | from scapy.layers.l2 import Ether 13 | 14 | class MPLS(Packet): 15 | name = "MPLS" 16 | fields_desc = [ BitField("label", 3, 20), 17 | BitField("cos", 0, 3), 18 | BitField("s", 1, 1), 19 | ByteField("ttl", 0) ] 20 | 21 | bind_layers(Ether, MPLS, type=0x8847) 22 | 23 | # Not in upstream scapy 24 | bind_layers(MPLS, MPLS, s=0) 25 | -------------------------------------------------------------------------------- /src/python/oftest/netutils.py: -------------------------------------------------------------------------------- 1 | 2 | """ 3 | Network utilities for the OpenFlow test framework 4 | """ 5 | 6 | ########################################################################### 7 | ## ## 8 | ## Promiscuous mode enable/disable ## 9 | ## ## 10 | ## Based on code from Scapy by Phillippe Biondi ## 11 | ## ## 12 | ## ## 13 | ## This program is free software; you can redistribute it and/or modify it ## 14 | ## under the terms of the GNU General Public License as published by the ## 15 | ## Free Software Foundation; either version 2, or (at your option) any ## 16 | ## later version. ## 17 | ## ## 18 | ## This program is distributed in the hope that it will be useful, but ## 19 | ## WITHOUT ANY WARRANTY; without even the implied warranty of ## 20 | ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ## 21 | ## General Public License for more details. ## 22 | ## ## 23 | ############################################################################# 24 | 25 | import socket 26 | from fcntl import ioctl 27 | import struct 28 | 29 | # From net/if_arp.h 30 | ARPHDR_ETHER = 1 31 | ARPHDR_LOOPBACK = 772 32 | 33 | # From bits/ioctls.h 34 | SIOCGIFHWADDR = 0x8927 # Get hardware address 35 | SIOCGIFINDEX = 0x8933 # name -> if_index mapping 36 | 37 | # From netpacket/packet.h 38 | PACKET_ADD_MEMBERSHIP = 1 39 | PACKET_DROP_MEMBERSHIP = 2 40 | PACKET_MR_PROMISC = 1 41 | 42 | # From bits/socket.h 43 | SOL_PACKET = 263 44 | 45 | def get_if(iff,cmd): 46 | s=socket.socket() 47 | ifreq = ioctl(s, cmd, struct.pack("16s16x",iff)) 48 | s.close() 49 | return ifreq 50 | 51 | def get_if_index(iff): 52 | return int(struct.unpack("I",get_if(iff, SIOCGIFINDEX)[16:20])[0]) 53 | 54 | def set_promisc(s,iff,val=1): 55 | mreq = struct.pack("IHH8s", get_if_index(iff), PACKET_MR_PROMISC, 0, "") 56 | if val: 57 | cmd = PACKET_ADD_MEMBERSHIP 58 | else: 59 | cmd = PACKET_DROP_MEMBERSHIP 60 | s.setsockopt(SOL_PACKET, cmd, mreq) 61 | 62 | -------------------------------------------------------------------------------- /src/python/oftest/oft12/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/floodlight/oftest/0c20d87bc4d97c5c410e8cdd3be83dea214f5085/src/python/oftest/oft12/__init__.py -------------------------------------------------------------------------------- /src/python/oftest/ofutils.py: -------------------------------------------------------------------------------- 1 | 2 | """ 3 | Utilities for the OpenFlow test framework 4 | """ 5 | 6 | import random 7 | import time 8 | import os 9 | import fcntl 10 | import logging 11 | 12 | default_timeout = None # set by oft 13 | default_negative_timeout = None # set by oft 14 | 15 | def gen_xid(): 16 | return random.randrange(1,0xffffffff) 17 | 18 | """ 19 | Wait on a condition variable until the given function returns non-None or a timeout expires. 20 | The condition variable must already be acquired. 21 | The timeout value -1 means use the default timeout. 22 | There is deliberately no support for an infinite timeout. 23 | """ 24 | def timed_wait(cv, fn, timeout=-1): 25 | if timeout == -1: 26 | timeout = default_timeout 27 | 28 | end_time = time.time() + timeout 29 | while True: 30 | val = fn() 31 | if val != None: 32 | return val 33 | 34 | remaining_time = end_time - time.time() 35 | cv.wait(remaining_time) 36 | 37 | if time.time() > end_time: 38 | return None 39 | 40 | class EventDescriptor(): 41 | """ 42 | Similar to a condition variable, but can be passed to select(). 43 | Only supports one waiter. 44 | """ 45 | 46 | def __init__(self): 47 | self.pipe_rd, self.pipe_wr = os.pipe() 48 | fcntl.fcntl(self.pipe_wr, fcntl.F_SETFL, os.O_NONBLOCK) 49 | 50 | def __del__(self): 51 | os.close(self.pipe_rd) 52 | os.close(self.pipe_wr) 53 | 54 | def notify(self): 55 | try: 56 | os.write(self.pipe_wr, "x") 57 | except OSError as e: 58 | logging.warn("Failed to notify EventDescriptor: %s", e) 59 | 60 | def wait(self): 61 | os.read(self.pipe_rd, 1) 62 | 63 | def fileno(self): 64 | return self.pipe_rd 65 | -------------------------------------------------------------------------------- /src/python/oftest/packet.py: -------------------------------------------------------------------------------- 1 | # Distributed under the OpenFlow Software License (see LICENSE) 2 | # Copyright (c) 2010 The Board of Trustees of The Leland Stanford Junior University 3 | # Copyright (c) 2012, 2013 Big Switch Networks, Inc. 4 | """ 5 | Wrap scapy to satisfy pylint 6 | """ 7 | from oftest import config 8 | import sys 9 | 10 | try: 11 | import scapy.config 12 | import scapy.route 13 | import scapy.layers.l2 14 | import scapy.layers.inet 15 | import scapy.layers.sctp 16 | if not config["disable_ipv6"]: 17 | import scapy.route6 18 | import scapy.layers.inet6 19 | except ImportError: 20 | sys.exit("Need to install scapy for packet parsing") 21 | 22 | Ether = scapy.layers.l2.Ether 23 | LLC = scapy.layers.l2.LLC 24 | SNAP = scapy.layers.l2.SNAP 25 | Dot1Q = scapy.layers.l2.Dot1Q 26 | IP = scapy.layers.inet.IP 27 | IPOption = scapy.layers.inet.IPOption 28 | ARP = scapy.layers.inet.ARP 29 | TCP = scapy.layers.inet.TCP 30 | UDP = scapy.layers.inet.UDP 31 | ICMP = scapy.layers.inet.ICMP 32 | SCTP = scapy.layers.sctp.SCTP 33 | 34 | if not config["disable_ipv6"]: 35 | IPv6 = scapy.layers.inet6.IPv6 36 | ICMPv6Unknown = scapy.layers.inet6.ICMPv6Unknown 37 | ICMPv6EchoRequest = scapy.layers.inet6.ICMPv6EchoRequest 38 | ICMPv6EchoReply = scapy.layers.inet6.ICMPv6EchoReply 39 | ICMPv6ND_NS = scapy.layers.inet6.ICMPv6ND_NS 40 | ICMPv6ND_NA = scapy.layers.inet6.ICMPv6ND_NA 41 | ICMPv6ND_RA = scapy.layers.inet6.ICMPv6ND_RA 42 | ICMPv6ND_RS = scapy.layers.inet6.ICMPv6ND_RS 43 | ICMPv6NDOptSrcLLAddr = scapy.layers.inet6.ICMPv6NDOptSrcLLAddr 44 | ICMPv6NDOptDstLLAddr = scapy.layers.inet6.ICMPv6NDOptDstLLAddr 45 | ICMPv6NDOptPrefixInfo = scapy.layers.inet6.ICMPv6NDOptPrefixInfo 46 | ICMPv6DestUnreach = scapy.layers.inet6.ICMPv6DestUnreach 47 | ICMPv6TimeExceeded = scapy.layers.inet6.ICMPv6TimeExceeded 48 | 49 | import scapy.config as scapy_config 50 | if 'vxlan' in scapy_config.Conf.load_layers: 51 | # pylint: disable=no-name-in-module, import-error 52 | import scapy.layers.vxlan 53 | # pylint: disable=no-member 54 | VXLAN = scapy.layers.vxlan.VXLAN 55 | else: 56 | from oftest import vxlan 57 | VXLAN = vxlan.VXLAN 58 | -------------------------------------------------------------------------------- /src/python/oftest/pcap_writer.py: -------------------------------------------------------------------------------- 1 | """ 2 | Pcap file writer 3 | """ 4 | 5 | import struct 6 | 7 | PcapHeader = struct.Struct(" 1, "Not enough ports for test") 37 | 38 | delete_all_flows(self.controller) 39 | 40 | pkt = simple_tcp_packet() 41 | match = packet_to_flow_match(self, pkt) 42 | match.wildcards &= ~ofp.OFPFW_IN_PORT 43 | self.assertTrue(match is not None, 44 | "Could not generate flow match from pkt") 45 | act = ofp.action.output() 46 | 47 | of_ports = config["port_map"].keys() 48 | of_ports.sort() 49 | self.assertTrue(len(of_ports) > 1, "Not enough ports for test") 50 | 51 | ingress_port = of_ports[0] 52 | egress_port = of_ports[1] 53 | logging.info("Ingress " + str(ingress_port) + 54 | " to egress " + str(egress_port)) 55 | 56 | match.in_port = ingress_port 57 | 58 | request = ofp.message.flow_add() 59 | request.match = match 60 | request.cookie = random.randint(0,9007199254740992) 61 | request.buffer_id = 0xffffffff 62 | request.idle_timeout = 1 63 | request.flags |= ofp.OFPFF_SEND_FLOW_REM 64 | act.port = egress_port 65 | request.actions.append(act) 66 | 67 | logging.info("Inserting flow") 68 | self.controller.message_send(request) 69 | do_barrier(self.controller) 70 | 71 | (response, pkt) = self.controller.poll(exp_msg=ofp.OFPT_FLOW_REMOVED, 72 | timeout=test_timeout) 73 | 74 | self.assertTrue(response is not None, 75 | 'Did not receive flow removed message ') 76 | 77 | self.assertEqual(request.cookie, response.cookie, 78 | 'Cookies do not match') 79 | 80 | self.assertEqual(ofp.OFPRR_IDLE_TIMEOUT, response.reason, 81 | 'Flow table entry removal reason is not idle_timeout') 82 | 83 | self.assertEqual(match, response.match, 84 | 'Flow table entry does not match') 85 | 86 | sleep(1) 87 | -------------------------------------------------------------------------------- /tests/latency.py: -------------------------------------------------------------------------------- 1 | """ 2 | Latency tests 3 | 4 | These tests are mostly helpful for finding an optimal value for the 5 | --default-negative-timeout option. If this value is too large it will 6 | unnecessarily some down testing, but if it is too small then tests 7 | may pass when they should have failed. 8 | 9 | Most of this latency is caused by OFTest. Actual switch latency should be just 10 | a few microseconds, but OFTest can add milliseconds on top of that. 11 | """ 12 | 13 | import logging 14 | import unittest 15 | import time 16 | 17 | from oftest import config 18 | import ofp 19 | import oftest.base_tests as base_tests 20 | 21 | from oftest.testutils import * 22 | 23 | class DataplaneLatency(base_tests.SimpleDataPlane): 24 | """ 25 | Measure and assert dataplane latency 26 | 27 | All packets must arrive within the default timeout, and 90% must 28 | arrive within the default negative timeout. 29 | """ 30 | def runTest(self): 31 | in_port, out_port = openflow_ports(2) 32 | 33 | delete_all_flows(self.controller) 34 | 35 | pkt = str(simple_tcp_packet()) 36 | 37 | request = ofp.message.flow_add( 38 | match=ofp.match(wildcards=ofp.OFPFW_ALL), 39 | buffer_id=0xffffffff, 40 | actions=[ofp.action.output(out_port)]) 41 | 42 | self.controller.message_send(request) 43 | do_barrier(self.controller) 44 | 45 | latencies = [] 46 | for i in xrange(0, 1000): 47 | start_time = time.time() 48 | self.dataplane.send(in_port, pkt) 49 | verify_packet(self, pkt, out_port) 50 | end_time = time.time() 51 | latencies.append(end_time - start_time) 52 | 53 | latencies.sort() 54 | 55 | latency_min = latencies[0] 56 | latency_90 = latencies[int(len(latencies)*0.9)] 57 | latency_max = latencies[-1] 58 | 59 | logging.debug("Minimum latency: %f ms", latency_min * 1000.0) 60 | logging.debug("90%% latency: %f ms", latency_90 * 1000.0) 61 | logging.debug("Maximum latency: %f ms", latency_max * 1000.0) 62 | 63 | self.assertGreater(config["default_timeout"], latency_max) 64 | self.assertGreater(config["default_negative_timeout"], latency_90) 65 | 66 | class PktinLatency(base_tests.SimpleDataPlane): 67 | """ 68 | Measure and assert packet-in latency 69 | 70 | All packet-ins must arrive within the default timeout, and 90% must 71 | arrive within the default negative timeout. 72 | """ 73 | def runTest(self): 74 | in_port, = openflow_ports(1) 75 | 76 | delete_all_flows(self.controller) 77 | 78 | pkt = str(simple_tcp_packet()) 79 | 80 | request = ofp.message.flow_add( 81 | match=ofp.match(wildcards=ofp.OFPFW_ALL), 82 | buffer_id=0xffffffff, 83 | actions=[ofp.action.output(ofp.OFPP_CONTROLLER)]) 84 | 85 | self.controller.message_send(request) 86 | do_barrier(self.controller) 87 | 88 | latencies = [] 89 | for i in xrange(0, 1000): 90 | start_time = time.time() 91 | self.dataplane.send(in_port, pkt) 92 | verify_packet_in(self, pkt, in_port, ofp.OFPR_ACTION) 93 | end_time = time.time() 94 | latencies.append(end_time - start_time) 95 | 96 | latencies.sort() 97 | 98 | latency_min = latencies[0] 99 | latency_90 = latencies[int(len(latencies)*0.9)] 100 | latency_max = latencies[-1] 101 | 102 | logging.debug("Minimum latency: %f ms", latency_min * 1000.0) 103 | logging.debug("90%% latency: %f ms", latency_90 * 1000.0) 104 | logging.debug("Maximum latency: %f ms", latency_max * 1000.0) 105 | 106 | self.assertGreater(config["default_timeout"], latency_max) 107 | self.assertGreater(config["default_negative_timeout"], latency_90) 108 | -------------------------------------------------------------------------------- /tests/nicira_dec_ttl.py: -------------------------------------------------------------------------------- 1 | import logging 2 | import struct 3 | 4 | from oftest import config 5 | import ofp 6 | import oftest.base_tests as base_tests 7 | 8 | from oftest.testutils import * 9 | 10 | @nonstandard 11 | class TtlDecrement(base_tests.SimpleDataPlane): 12 | def runTest(self): 13 | of_ports = config["port_map"].keys() 14 | of_ports.sort() 15 | self.assertTrue(len(of_ports) >= 3, "Not enough ports for test") 16 | portA = of_ports[0] 17 | portB = of_ports[1] 18 | portC = of_ports[2] 19 | 20 | # Test using flow mods (does not test drop) 21 | flow_match_test(self, config["port_map"], 22 | pkt=simple_tcp_packet(pktlen=100, ip_ttl=2), 23 | exp_pkt=simple_tcp_packet(pktlen=100, ip_ttl=1), 24 | action_list=[ofp.action.nicira_dec_ttl()]) 25 | 26 | outpkt = simple_tcp_packet(pktlen=100, ip_ttl=3) 27 | msg = ofp.message.packet_out(in_port=ofp.OFPP_NONE, 28 | data=str(outpkt), 29 | buffer_id=0xffffffff, 30 | actions=[ 31 | ofp.action.nicira_dec_ttl(), 32 | ofp.action.output(port=portA), 33 | ofp.action.nicira_dec_ttl(), 34 | ofp.action.output(port=portB), 35 | ofp.action.nicira_dec_ttl(), 36 | ofp.action.output(port=portC)]) 37 | self.controller.message_send(msg) 38 | 39 | verify_packet(self, simple_tcp_packet(ip_ttl=2), portA) 40 | verify_packet(self, simple_tcp_packet(ip_ttl=1), portB) 41 | verify_no_packet(self, simple_tcp_packet(ip_ttl=0), portC) 42 | verify_no_other_packets(self) 43 | 44 | @nonstandard 45 | class TtlDecrementZeroTtl(base_tests.SimpleDataPlane): 46 | def runTest(self): 47 | of_ports = config["port_map"].keys() 48 | of_ports.sort() 49 | self.assertTrue(len(of_ports) >= 2, "Not enough ports for test") 50 | portA = of_ports[0] 51 | portB = of_ports[1] 52 | 53 | outpkt = simple_tcp_packet(pktlen=100, ip_ttl=0) 54 | msg = ofp.message.packet_out(in_port=ofp.OFPP_NONE, 55 | data=str(outpkt), 56 | buffer_id=0xffffffff, 57 | actions=[ 58 | ofp.action.output(port=portA), 59 | ofp.action.nicira_dec_ttl(), 60 | ofp.action.output(port=portB)]) 61 | self.controller.message_send(msg) 62 | 63 | verify_packet(self, simple_tcp_packet(ip_ttl=0), portA) 64 | verify_no_packet(self, simple_tcp_packet(ip_ttl=0), portB) 65 | verify_no_other_packets(self) 66 | -------------------------------------------------------------------------------- /tests/oft: -------------------------------------------------------------------------------- 1 | ../oft -------------------------------------------------------------------------------- /tools/ovs-ctl/ovs-ctl-default.example.conf: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # 3 | # This is the example/default ovs-ctl config file. 4 | # 5 | # ovs-ctl config files will be searched and read, by default, int he following 6 | # order: 7 | # 8 | # /opt/ovs/ovs-ctl-default.conf 9 | # ~/.ovs-ctl 10 | # 11 | # This behavior can be modified and change specifically on the command line: 12 | # 13 | # Change the location of the default config file: 14 | # > ovs-ctl --default-config-file=/path/to/file 15 | # 16 | # Disable the default config file: 17 | # > ovs-ctl --no-default 18 | # 19 | # Read these specific config files: 20 | # > ovs-ctl --config-file file1 file2 file3 21 | # 22 | # Note: The default config file reading behavior is equivalent to: 23 | # 24 | # > ovs-ctl --default /opt/ovs/ovs-ctl-default.conf --config-file ~/.ovs-ctl 25 | # 26 | # This is also equivalent to: 27 | # > ovs-ctl --no-default --config-file /opt/ovs/ovs-ctl-default.conf ~/.ovs-ctl 28 | # 29 | # 30 | ############################################################################### 31 | 32 | # 33 | # Default options can be specified here 34 | # 35 | [Defaults] 36 | # Default all configurations to 1.4.0 37 | config:1.4.0 38 | 39 | # 40 | # Specific OVS configurations go here 41 | # 42 | [1.4.0] 43 | # ovs-1.4.0, configured and built into /opt/ovs/1.4.0 44 | # Can be selected with 'ovs-ctl.py --config 1.4.0' 45 | ovs_src_dir:/opt/ovs/src/openvswitch-1.4.0 46 | ovs_base_dir:/opt/ovs/1.4.0 47 | ovs_runtime_dir:/var/run/ovs/1.4.0 48 | 49 | 50 | [1.3.0] 51 | # ovs-1.3.0, configured and built into /opt/ovs/1.3.0 52 | # Can be selected with 'ovsctl.py --config 1.3.0' 53 | ovs_src_dir:/opt/ovs/src/openvswitch-1.3.0 54 | ovs_base_dir:/opt/ovs/1.3.0 55 | ovs_runtime_dir:/var/run/ovs/1.3.0 56 | 57 | [1.2.2] 58 | # ovs-1.2.2, configured and built into /opt/ovs/1.2.2 59 | # Can be selected with 'ovsctl.py --config 1.2.2' 60 | ovs_src_dir:/opt/ovs/src/openvswitch-1.2.2 61 | ovs_base_dir:/opt/ovs/1.2.2 62 | ovs_runtime_dir:/var/run/ovs/1.2.2 63 | 64 | # 65 | # In the above configurations, the locations of the tools 66 | # are derived by ovs-ctl relative to 'ovs_src_dir' and 'ovs_base_dir' 67 | # 68 | # Individual tools and locations can be specified directly in 69 | # the configuration (as well as the command line): 70 | # 71 | # Try: 72 | # 'ovs-ctl.py --no-default --config-file ovs-ctl-default.example.conf --config MyExample' 73 | # 74 | # In general, every command line option can be specified in a config file section. 75 | # 76 | # The precedence of options is: 77 | # 1. Command Line Options 78 | # 2. [The Config You Specified] 79 | # 3. [The Defaults sections] 80 | # 81 | 82 | [MyExampleConfig] 83 | ovs_vswitchd_schema:/path/to/vswitch/schema/file 84 | ovs_vswitchdL:/path/to/vswitchd 85 | ovs_vsctl:/path/to/vsctl 86 | ovs_ofctl:/path/to/ofctl 87 | ovsdb_tool:/path/to/ovsdb_tool 88 | ovsd_db_file:/path/to/ovs_db_file 89 | ovs_db_sock:/path/to/ovs_db_sock 90 | ovs_kmod:/path/to/ovs_kmod 91 | 92 | 93 | 94 | 95 | 96 | 97 | -------------------------------------------------------------------------------- /tools/update-pyloxi.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash -eux 2 | wget -O loxi.tar.gz https://github.com/floodlight/loxigen-artifacts/tarball/master 3 | SHA1=$( tar -tzf loxi.tar.gz| head -n1 | grep -oP 'floodlight-loxigen-artifacts-\K\w+') 4 | git rm -rq src/python/loxi 5 | git checkout HEAD src/python/loxi/LICENSE.pyloxi 6 | tar -xzf loxi.tar.gz --xform s,floodlight-loxigen-artifacts-$SHA1/pyloxi,src/python, 7 | git add src/python/loxi 8 | git commit -m "update pyloxi to $SHA1" 9 | rm loxi.tar.gz 10 | --------------------------------------------------------------------------------