diff --git a/Makefile.am b/Makefile.am index bf2cf728..479d4aa9 100644 --- a/Makefile.am +++ b/Makefile.am @@ -17,7 +17,7 @@ AM_CPPFLAGS = $(SSL_CFLAGS) -g AM_CPPFLAGS += -I $(top_srcdir)/include AM_CPPFLAGS += -I $(top_srcdir)/lib -AM_CFLAGS = -Wstrict-prototypes +AM_CFLAGS = -Wstrict-prototypes -Werror if NDEBUG AM_CPPFLAGS += -DNDEBUG diff --git a/README.md b/README.md index 5b21934a..7c7b44ab 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,32 @@ -# OpenFlow 1.3 Software Switch +# Basic OpenFlow Software Switch (BOFUSS) -This is an [OpenFlow 1.3][ofp13] compatible user-space software switch implementation. The code is based on the [Ericsson TrafficLab 1.1 softswitch -implementation][ericssonsw11], with changes in the forwarding plane to support -OpenFlow 1.3. +This is an [OpenFlow 1.3][ofp13] compatible user-space software switch implementation. The code is based on the [Ericsson TrafficLab 1.1 softswitch implementation][ericssonsw11], with changes in the forwarding plane to support +OpenFlow 1.3. + +### [A paper that describes the basic architecture, selected use cases and a few benchmarks is available on Arxiv](https://arxiv.org/abs/1901.06699). +If you use the switch for academic purpuses, please consider the use of this citation. + +``` +@article{fernandes2020road, + title={The road to BOFUSS: The basic OpenFlow userspace software switch}, + author={Fernandes, Eder Le{\~a}o and Rojas, Elisa and Alvarez-Horcajo, Joaquin and Kis, Zolt{\`a}n Lajos and Sanvito, Davide and Bonelli, Nicola and Cascone, Carmelo and Rothenberg, Christian Esteve}, + journal={Journal of Network and Computer Applications}, + pages={102685}, + year={2020}, + publisher={Elsevier} +} + +``` + +## [Please read the FAQ before posting an issue](https://github.com/CPqD/ofsoftswitch13/wiki/Frequently-Asked-Questions) + +Check the [Wiki](https://github.com/CPqD/ofsoftswitch13/wiki) for some resources that could possibly help you to modify the switch. + +**UPDATE**: A new experimental branch with contributions from the [BEBA EU Project][beba-eu] is available with lots of performance improvements and OpenFlow extensions. If you want to try the code checkout to the BEBA-EU branch. + +```bash +$ git checkout remotes/origin/BEBA-EU +``` The following components are available in this package: * `ofdatapath`: the switch implementation @@ -10,9 +34,10 @@ The following components are available in this package: * `oflib`: a library for converting to/from 1.3 wire format * `dpctl`: a tool for configuring the switch from the console + # Getting Started -These instructions have been tested on Ubuntu 12.04. Other distributions or versions may need different steps. +These instructions have been tested on Ubuntu 16.04. Other distributions or versions may need different steps. ## Before building The switch makes use of the NetBee library to parse packets, so we need to install it first. @@ -20,44 +45,38 @@ The switch makes use of the NetBee library to parse packets, so we need to insta 1. Install the following packages: ``` - $ sudo apt-get install cmake libpcap-dev libxerces-c2-dev libpcre3-dev flex bison + $ sudo apt-get install cmake libpcap-dev libxerces-c3.1 libxerces-c-dev libpcre3 libpcre3-dev flex bison pkg-config autoconf libtool libboost-dev ``` -2. Download and unpack the source code from: http://www.nbee.org/download/nbeesrc-12-05-16.php - -3. Create the build system +2. Clone and build netbee ``` - $ cd nbeesrc/src + $ git clone https://github.com/netgroup-polito/netbee.git + $ cd netbee/src $ cmake . - ``` - -4. Compile - - ``` $ make ``` -5. Add the shared libraries built in `/nbeesrc/bin/` to your `/usr/local/lib` directory +3. Add the shared libraries built in `/nbeesrc/bin/` to your `/usr/local/lib` directory ``` $ sudo cp ../bin/libn*.so /usr/local/lib ``` -6. Run `ldconfig` +4. Run `ldconfig` ``` $ sudo ldconfig ``` -7. Put the folder `nbeesrc/include` in the `/usr/include` +5. Put the contens of folder `nbeesrc/include` in the `/usr/include` ``` - $ sudo cp -R ../include /usr/include + $ sudo cp -R ../include/* /usr/include/ ``` ## Building -Run the following commands in the `of13softswitch` directory to build and install everything: +Run the following commands in the `ofsoftswitch13` directory to build and install everything: $ ./boot.sh $ ./configure @@ -108,13 +127,7 @@ You can send requests to the switch using the `dpctl` utility. $ utilities/dpctl tcp:: flow-mod table=0,cmd=add in_port=1 meter:1 ``` -For a complete list of commands and arguments, use the `--help` argument. - -The `dpctl` utility has some limitations at the moment: -* No support for OXM masks -* No support for multipart messages -* Some set_field action fields are not present - +For a complete list of commands and arguments, use the `--help` argument. Also, check the wiki for [Flow Mod examples](https://github.com/CPqD/ofsoftswitch13/wiki/Dpctl-Flow-Mod-Cases) # Contribute Please submit your bug reports, fixes and suggestions as pull requests on @@ -126,32 +139,15 @@ code from the original Stanford switch). # Acknowledgments -This project is supported by Ericsson Innovation Center in Brazil. -Maintained by CPqD in technical collaboration with Ericsson Research. - -**Contributions:** - -Zoltán Lajos Kis, ofsoftswitch 1.1 implementation and guidance for OpenFlow spec related subjects. - -Jean Tourrilhes, lots of critical memory bug fixes on table features. - -Khai Nguyen Dinh and Thanh Le Dinh, contributions on meter features. - -Rich Lane, added the right compiler linker. - -yu-iwata, fixed flow deletion without matchin out_port. - -Yuval Adler, bug fixes related to matching on vlan and ethertype. - -Hiroyasu OHYAMA, correct URL of NetBee Library. - -... +This project was supported by Ericsson Innovation Center in Brazil. +Formerly maintained by CPqD in technical collaboration with Ericsson Research. -*"Your name here" -- please, let us* -*know if we forgot to add your name to the list of contributors!* +[**List of Contributors**](https://github.com/CPqD/ofsoftswitch13/wiki/List-of-Contributors) # Contact -E-mail: Eder Leao Fernandes (ederlf@cpqd.com.br) +E-mail: Eder Leao Fernandes (ederleaofernandes at gmail . com) [ofp13]: https://www.opennetworking.org/images/stories/downloads/specification/openflow-spec-v1.3.0.pdf [ericssonsw11]: https://github.com/TrafficLab/of11softswitch +[compileubuntu14]: http://tocai.dia.uniroma3.it/compunet-wiki/index.php/Installing_and_setting_up_OpenFlow_tools +[beba-eu]: http://www.beba-project.eu/ diff --git a/boot.sh b/boot.sh index 97921fac..284e4695 100755 --- a/boot.sh +++ b/boot.sh @@ -3,12 +3,18 @@ set -e # Generate list of files in debian/ to distribute. -(echo '# Automatically generated by boot.sh (from Git tree).' && - printf 'EXTRA_DIST += \\\n' && - git ls-files debian | grep -v '^debian/\.gitignore$' | - sed -e 's/\(.*\)/ \1 \\/' -e '$s/ \\//') > debian/automake.mk +if [ -d .git ]; then + (echo '# Automatically generated by boot.sh (from Git tree).' && + printf 'EXTRA_DIST += \\\n' && + git ls-files debian | grep -v '^debian/\.gitignore$' | + sed -e 's/\(.*\)/ \1 \\/' -e '$s/ \\//') > debian/automake.mk +else + (echo '# Automatically generated by boot.sh (from ls).' && + printf 'EXTRA_DIST += \\\n' && + ls debian | grep -v '^debian/\.gitignore$' | + sed -e 's/^/debian\//' -e 's/\(.*\)/ \1 \\/' -e '$s/ \\//') > debian/automake.mk +fi cat debian/control.in > debian/control - # Bootstrap configure system from .ac/.am files autoreconf --install --force diff --git a/customnetpdl.xml b/customnetpdl.xml index 77b4a713..091ed67b 100644 --- a/customnetpdl.xml +++ b/customnetpdl.xml @@ -737,6 +737,7 @@ + @@ -891,10 +892,13 @@ - - - - + + + + + + + @@ -1040,7 +1044,7 @@ - + @@ -1151,7 +1155,7 @@ --> - + @@ -1412,7 +1416,7 @@ --> - + @@ -1734,7 +1738,6 @@ -
@@ -1746,6 +1749,28 @@ + + + + + + + + + + + + + +
+ + + + + + + + diff --git a/debian/openflow-common.install b/debian/openflow-common.install index eed7413e..624bc344 100644 --- a/debian/openflow-common.install +++ b/debian/openflow-common.install @@ -1,3 +1,2 @@ -_debian/utilities/ofp-parse-leaks usr/bin _debian/utilities/ofp-pki usr/sbin _debian/utilities/vlogconf usr/sbin diff --git a/debian/openflow-controller.default b/debian/openflow-controller.default index 3b84b62a..03a19b0d 100644 --- a/debian/openflow-controller.default +++ b/debian/openflow-controller.default @@ -5,11 +5,11 @@ # This is a space-delimited list of connection methods: # # * "pssl:[PORT]": Listen for SSL connections on the specified PORT -# (default: 6633). The private key, certificate, and CA certificate +# (default: 6653). The private key, certificate, and CA certificate # must be specified below. # # * "pctp:[PORT]": Listen for TCP connections on the specified PORT -# (default: 6633). Not recommended for security reasons. +# (default: 6653). Not recommended for security reasons. # # * "nl:DP_IDX": Listen on local datapath DP_IDX. Used only if this # machine is also an OpenFlow switch and not running the secure diff --git a/debian/openflow-switch.template b/debian/openflow-switch.template index f3f641e8..fe1aae79 100644 --- a/debian/openflow-switch.template +++ b/debian/openflow-switch.template @@ -69,8 +69,8 @@ SWITCH_IP=dhcp # CONTROLLER: Location of controller. # One of the following formats: -# tcp:HOST[:PORT] via TCP to PORT (default: 6633) on HOST -# ssl:HOST[:PORT] via SSL to PORT (default: 6633) on HOST +# tcp:HOST[:PORT] via TCP to PORT (default: 6653) on HOST +# ssl:HOST[:PORT] via SSL to PORT (default: 6653) on HOST # The default below assumes that the controller is running locally. # This setting has no effect when MODE is set to 'discovery'. #CONTROLLER="tcp:127.0.0.1" diff --git a/include/openflow/openflow.h b/include/openflow/openflow.h index caa4e840..3dc14125 100644 --- a/include/openflow/openflow.h +++ b/include/openflow/openflow.h @@ -1,3 +1,37 @@ +/* Copyright (c) 2008 The Board of Trustees of The Leland Stanford + * Junior University + * Copyright (c) 2011, 2012 Open Networking Foundation + * + * We are making the OpenFlow specification and associated documentation + * (Software) available for public use and benefit with the expectation + * that others will use, modify and enhance the Software and contribute + * those enhancements back to the community. However, since we would + * like to make the Software available for broadest use, with as few + * restrictions as possible permission is hereby granted, free of + * charge, to any person obtaining a copy of this Software to deal in + * the Software under the copyrights without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * The name and trademarks of copyright holder(s) may NOT be used in + * advertising or publicity pertaining to the Software or any + * derivatives without specific, written prior permission. + */ + /* OpenFlow: protocol between controller and datapath. */ #ifndef OPENFLOW_OPENFLOW_H @@ -8,16 +42,18 @@ #else #include #endif + #ifdef SWIG #define OFP_ASSERT(EXPR) /* SWIG can't handle OFP_ASSERT. */ #elif !defined(__cplusplus) /* Build-time assertion for use in a declaration context. */ #define OFP_ASSERT(EXPR) \ - extern int (*build_assert(void))[ sizeof(struct { \ - unsigned int build_assert_failed : (EXPR) ? 1 : -1; })] + extern int (*build_assert(void))[ sizeof(struct { \ + unsigned int build_assert_failed : (EXPR) ? 1 : -1; })] #else /* __cplusplus */ #define OFP_ASSERT(_EXPR) typedef int build_assert_failed[(_EXPR) ? 1 : -1] #endif /* __cplusplus */ + #ifndef SWIG #define OFP_PACKED __attribute__((packed)) #else @@ -25,671 +61,1140 @@ #endif /* Version number: - * Non-experimental versions released: 0x01 - * Experimental versions released: 0x81 -- 0x99 + * OpenFlow versions released: 0x01 = 1.0 ; 0x02 = 1.1 ; 0x03 = 1.2 + * 0x04 = 1.3 */ -/* The most significant bit being set in the version field indicates an - * experimental OpenFlow version. +/* The most significant bit in the version field is reserved and must + * be set to zero. */ - #define OFP_VERSION 0x04 +#define PIPELINE_TABLES 64 #define OFP_MAX_TABLE_NAME_LEN 32 #define OFP_MAX_PORT_NAME_LEN 16 -#define OFP_TCP_PORT 6633 -#define OFP_SSL_PORT 6633 +/* Official IANA registered port for OpenFlow. */ +#define OFP_TCP_PORT 6653 +#define OFP_SSL_PORT 6653 + #define OFP_ETH_ALEN 6 /* Bytes in an Ethernet address. */ -/* Number of tables in the pipeline */ -#define PIPELINE_TABLES 64 -/* Header on all OpenFlow packets. */ -struct ofp_header { - uint8_t version; /* OFP_VERSION. */ - uint8_t type; /* One of the OFPT_ constants. */ - uint16_t length; /* Length including this ofp_header. */ - uint32_t xid; /* Transaction id associated with this packet. - Replies use the same id as was in the request - total_len facilitate pairing. */ +/* Port numbering. Ports are numbered starting from 1. */ +enum ofp_port_no { + /* Maximum number of physical and logical switch ports. */ + OFPP_MAX = 0xffffff00, + + /* Reserved OpenFlow Port (fake output "ports"). */ + OFPP_IN_PORT = 0xfffffff8, /* Send the packet out the input port. This + reserved port must be explicitly used + in order to send back out of the input + port. */ + OFPP_TABLE = 0xfffffff9, /* Submit the packet to the first flow table + NB: This destination port can only be + used in packet-out messages. */ + OFPP_NORMAL = 0xfffffffa, /* Forward using non-OpenFlow pipeline. */ + OFPP_FLOOD = 0xfffffffb, /* Flood using non-OpenFlow pipeline. */ + OFPP_ALL = 0xfffffffc, /* All standard ports except input port. */ + OFPP_CONTROLLER = 0xfffffffd, /* Send to controller. */ + OFPP_LOCAL = 0xfffffffe, /* Local openflow "port". */ + OFPP_ANY = 0xffffffff /* Special value used in some requests when + no port is specified (i.e. wildcarded). */ }; -OFP_ASSERT(sizeof(struct ofp_header) == 8); enum ofp_type { - /* Immutable messages. */ - OFPT_HELLO = 0, /* Symmetric message */ - OFPT_ERROR = 1, /* Symmetric message */ - OFPT_ECHO_REQUEST = 2, /* Symmetric message */ - OFPT_ECHO_REPLY = 3, /* Symmetric message */ - OFPT_EXPERIMENTER = 4, /* Symmetric message */ + /* Immutable messages. */ + OFPT_HELLO = 0, /* Symmetric message */ + OFPT_ERROR = 1, /* Symmetric message */ + OFPT_ECHO_REQUEST = 2, /* Symmetric message */ + OFPT_ECHO_REPLY = 3, /* Symmetric message */ + OFPT_EXPERIMENTER = 4, /* Symmetric message */ + /* Switch configuration messages. */ - OFPT_FEATURES_REQUEST = 5, /* Controller/switch message */ - OFPT_FEATURES_REPLY = 6, /* Controller/switch message */ - OFPT_GET_CONFIG_REQUEST = 7, /* Controller/switch message */ - OFPT_GET_CONFIG_REPLY = 8, /* Controller/switch message */ - OFPT_SET_CONFIG = 9, /* Controller/switch message */ + OFPT_FEATURES_REQUEST = 5, /* Controller/switch message */ + OFPT_FEATURES_REPLY = 6, /* Controller/switch message */ + OFPT_GET_CONFIG_REQUEST = 7, /* Controller/switch message */ + OFPT_GET_CONFIG_REPLY = 8, /* Controller/switch message */ + OFPT_SET_CONFIG = 9, /* Controller/switch message */ + /* Asynchronous messages. */ - OFPT_PACKET_IN = 10, /* Async message */ - OFPT_FLOW_REMOVED = 11, /* Async message */ - OFPT_PORT_STATUS = 12, /* Async message */ + OFPT_PACKET_IN = 10, /* Async message */ + OFPT_FLOW_REMOVED = 11, /* Async message */ + OFPT_PORT_STATUS = 12, /* Async message */ + /* Controller command messages. */ - OFPT_PACKET_OUT = 13, /* Controller/switch message */ - OFPT_FLOW_MOD = 14, /* Controller/switch message */ - OFPT_GROUP_MOD = 15, /* Controller/switch message */ - OFPT_PORT_MOD = 16, /* Controller/switch message */ - OFPT_TABLE_MOD = 17, /* Controller/switch message */ - /* Statistics messages. */ - OFPT_MULTIPART_REQUEST = 18, /* Controller/switch message */ - OFPT_MULTIPART_REPLY = 19, /* Controller/switch message */ + OFPT_PACKET_OUT = 13, /* Controller/switch message */ + OFPT_FLOW_MOD = 14, /* Controller/switch message */ + OFPT_GROUP_MOD = 15, /* Controller/switch message */ + OFPT_PORT_MOD = 16, /* Controller/switch message */ + OFPT_TABLE_MOD = 17, /* Controller/switch message */ + + /* Multipart messages. */ + OFPT_MULTIPART_REQUEST = 18, /* Controller/switch message */ + OFPT_MULTIPART_REPLY = 19, /* Controller/switch message */ + /* Barrier messages. */ - OFPT_BARRIER_REQUEST = 20, /* Controller/switch message */ - OFPT_BARRIER_REPLY = 21, /* Controller/switch message */ + OFPT_BARRIER_REQUEST = 20, /* Controller/switch message */ + OFPT_BARRIER_REPLY = 21, /* Controller/switch message */ + /* Queue Configuration messages. */ - OFPT_QUEUE_GET_CONFIG_REQUEST = 22, /* Controller/switch message */ - OFPT_QUEUE_GET_CONFIG_REPLY = 23, /* Controller/switch message */ + OFPT_QUEUE_GET_CONFIG_REQUEST = 22, /* Controller/switch message */ + OFPT_QUEUE_GET_CONFIG_REPLY = 23, /* Controller/switch message */ + /* Controller role change request messages. */ - OFPT_ROLE_REQUEST = 24, /* Controller/switch message */ - OFPT_ROLE_REPLY = 25, /* Controller/switch message */ - /* Asynchronous message configuration */ - OFPT_GET_ASYNC_REQUEST = 26, /* Controller/switch message */ - OFPT_GET_ASYNC_REPLY = 27, /* Controller/switch message */ - OFPT_SET_ASYNC = 28, /* Controller/switch message */ + OFPT_ROLE_REQUEST = 24, /* Controller/switch message */ + OFPT_ROLE_REPLY = 25, /* Controller/switch message */ + + /* Asynchronous message configuration. */ + OFPT_GET_ASYNC_REQUEST = 26, /* Controller/switch message */ + OFPT_GET_ASYNC_REPLY = 27, /* Controller/switch message */ + OFPT_SET_ASYNC = 28, /* Controller/switch message */ + /* Meters and rate limiters configuration messages. */ - OFPT_METER_MOD = 29, /* Controller/switch message */ + OFPT_METER_MOD = 29, /* Controller/switch message */ }; -/* OFPT_HELLO. This message has an empty body, but implementations must - * ignore any data included in the body, to allow for future extensions. */ +/* Header on all OpenFlow packets. */ +struct ofp_header { + uint8_t version; /* OFP_VERSION. */ + uint8_t type; /* One of the OFPT_ constants. */ + uint16_t length; /* Length including this ofp_header. */ + uint32_t xid; /* Transaction id associated with this packet. + Replies use the same id as was in the request + to facilitate pairing. */ +}; +OFP_ASSERT(sizeof(struct ofp_header) == 8); + +/* Hello elements types. + */ +enum ofp_hello_elem_type { + OFPHET_VERSIONBITMAP = 1, /* Bitmap of version supported. */ +}; + +/* Common header for all Hello Elements */ +struct ofp_hello_elem_header { + uint16_t type; /* One of OFPHET_*. */ + uint16_t length; /* Length in bytes of the element, + including this header, excluding padding. */ +}; +OFP_ASSERT(sizeof(struct ofp_hello_elem_header) == 4); + +/* Version bitmap Hello Element */ +struct ofp_hello_elem_versionbitmap { + uint16_t type; /* OFPHET_VERSIONBITMAP. */ + uint16_t length; /* Length in bytes of this element, + including this header, excluding padding. */ + /* Followed by: + * - Exactly (length - 4) bytes containing the bitmaps, then + * - Exactly (length + 7)/8*8 - (length) (between 0 and 7) + * bytes of all-zero bytes */ + uint32_t bitmaps[0]; /* List of bitmaps - supported versions */ +}; +OFP_ASSERT(sizeof(struct ofp_hello_elem_versionbitmap) == 4); + +/* OFPT_HELLO. This message includes zero or more hello elements having + * variable size. Unknown elements types must be ignored/skipped, to allow + * for future extensions. */ struct ofp_hello { struct ofp_header header; + + /* Hello element list */ + struct ofp_hello_elem_header elements[0]; /* List of elements - 0 or more */ }; +OFP_ASSERT(sizeof(struct ofp_hello) == 8); #define OFP_DEFAULT_MISS_SEND_LEN 128 -/******** Common Structures **********************/ +enum ofp_config_flags { + /* Handling of IP fragments. */ + OFPC_FRAG_NORMAL = 0, /* No special handling for fragments. */ + OFPC_FRAG_DROP = 1 << 0, /* Drop fragments. */ + OFPC_FRAG_REASM = 1 << 1, /* Reassemble (only if OFPC_IP_REASM set). */ + OFPC_FRAG_MASK = 3, /* Bitmask of flags dealing with frag. */ +}; +/* Switch configuration. */ +struct ofp_switch_config { + struct ofp_header header; + uint16_t flags; /* Bitmap of OFPC_* flags. */ + uint16_t miss_send_len; /* Max bytes of packet that datapath + should send to the controller. See + ofp_controller_max_len for valid values. + */ +}; +OFP_ASSERT(sizeof(struct ofp_switch_config) == 12); -/* Description of a port */ -struct ofp_port { - uint32_t port_no; - uint8_t pad[4]; - uint8_t hw_addr[OFP_ETH_ALEN]; - uint8_t pad2[2]; /* Align to 64 bits. */ - char name[OFP_MAX_PORT_NAME_LEN]; /* Null-terminated */ - uint32_t config; /* Bitmap of OFPPC_* flags. */ - uint32_t state; /* Bitmap of OFPPS_* flags. */ - /* Bitmaps of OFPPF_* that describe features. All bits zeroed if - * unsupported or unavailable. */ - uint32_t curr; /* Current features. */ - uint32_t advertised; /* Features being advertised by the port. */ - uint32_t supported; /* Features supported by the port. */ - uint32_t peer; /* Features advertised by peer. */ - uint32_t curr_speed; /* Current port bitrate in kbps. */ - uint32_t max_speed; /* Max port bitrate in kbps */ +/* Flags to configure the table. Reserved for future use. */ +enum ofp_table_config { + OFPTC_DEPRECATED_MASK = 3, /* Deprecated bits */ }; -OFP_ASSERT(sizeof(struct ofp_port) == 64); -/* Flags to indicate behavior of the physical port. These flags are -* used in ofp_port to describe the current configuration. They are -* used in the ofp_port_mod message to configure the port’s behavior. -*/ -enum ofp_port_config { - OFPPC_PORT_DOWN = 1 << 0, /* Port is administratively down. */ - OFPPC_NO_RECV = 1 << 2, /* Drop all packets received by port. */ - OFPPC_NO_FWD = 1 << 5, /* Drop packets forwarded to port. */ - OFPPC_NO_PACKET_IN = 1 << 6 /* Do not send packet-in msgs for port. */ +/* Table numbering. Tables can use any number up to OFPT_MAX. */ +enum ofp_table { + /* Last usable table number. */ + OFPTT_MAX = 0xfe, + + /* Fake tables. */ + OFPTT_ALL = 0xff /* Wildcard table used for table config, + flow stats and flow deletes. */ }; -/* Current state of the physical port. These are not configurable from -* the controller. -*/ -enum ofp_port_state { - OFPPS_LINK_DOWN = 1 << 0, /* No physical link present. */ - OFPPS_BLOCKED = 1 << 1, /* Port is blocked */ - OFPPS_LIVE = 1 << 2, /* Live for Fast Failover Group. */ + +/* Configure/Modify behavior of a flow table */ +struct ofp_table_mod { + struct ofp_header header; + uint8_t table_id; /* ID of the table, OFPTT_ALL indicates all tables */ + uint8_t pad[3]; /* Pad to 32 bits */ + uint32_t config; /* Bitmap of OFPTC_* flags */ }; +OFP_ASSERT(sizeof(struct ofp_table_mod) == 16); -/* Port numbering. Ports are numbered starting from 1. */ -enum ofp_port_no { - /* Maximum number of physical and logical switch ports. */ - OFPP_MAX = 0xffffff00, - /* Reserved OpenFlow Port (fake output "ports"). */ - OFPP_IN_PORT = 0xfffffff8, /* Send the packet out the input port. This - reserved port must be explicitly used - in order to send back out of the input - port. */ - OFPP_TABLE = 0xfffffff9, /* Submit the packet to the first flow table - NB: This destination port can only be - used in packet-out messages. */ - OFPP_NORMAL = 0xfffffffa, /* Process with normal L2/L3 switching. */ - OFPP_FLOOD = 0xfffffffb, /* All physical ports in VLAN, except input - port and those blocked or link down. */ - OFPP_ALL = 0xfffffffc, /* All physical ports except input port. */ - OFPP_CONTROLLER = 0xfffffffd, /* Send to controller. */ - OFPP_LOCAL = 0xfffffffe, /* Local openflow "port". */ - OFPP_ANY = 0xffffffff /* Wildcard port used only for flow mod - (delete) and flow stats requests. Selects - all flows regardless of output port - (including flows with no output port). */ +/* Capabilities supported by the datapath. */ +enum ofp_capabilities { + OFPC_FLOW_STATS = 1 << 0, /* Flow statistics. */ + OFPC_TABLE_STATS = 1 << 1, /* Table statistics. */ + OFPC_PORT_STATS = 1 << 2, /* Port statistics. */ + OFPC_GROUP_STATS = 1 << 3, /* Group statistics. */ + OFPC_IP_REASM = 1 << 5, /* Can reassemble IP fragments. */ + OFPC_QUEUE_STATS = 1 << 6, /* Queue statistics. */ + OFPC_PORT_BLOCKED = 1 << 8 /* Switch will block looping ports. */ +}; + +/* Flags to indicate behavior of the physical port. These flags are + * used in ofp_port to describe the current configuration. They are + * used in the ofp_port_mod message to configure the port's behavior. + */ +enum ofp_port_config { + OFPPC_PORT_DOWN = 1 << 0, /* Port is administratively down. */ + + OFPPC_NO_RECV = 1 << 2, /* Drop all packets received by port. */ + OFPPC_NO_FWD = 1 << 5, /* Drop packets forwarded to port. */ + OFPPC_NO_PACKET_IN = 1 << 6 /* Do not send packet-in msgs for port. */ +}; + +/* Current state of the physical port. These are not configurable from + * the controller. + */ +enum ofp_port_state { + OFPPS_LINK_DOWN = 1 << 0, /* No physical link present. */ + OFPPS_BLOCKED = 1 << 1, /* Port is blocked */ + OFPPS_LIVE = 1 << 2, /* Live for Fast Failover Group. */ }; /* Features of ports available in a datapath. */ enum ofp_port_features { - OFPPF_10MB_HD = 1 << 0, /* 10 Mb half-duplex rate support. */ - OFPPF_10MB_FD = 1 << 1, /* 10 Mb full-duplex rate support. */ - OFPPF_100MB_HD = 1 << 2, /* 100 Mb half-duplex rate support. */ - OFPPF_100MB_FD = 1 << 3, /* 100 Mb full-duplex rate support. */ - OFPPF_1GB_HD = 1 << 4, /* 1 Gb half-duplex rate support. */ - OFPPF_1GB_FD = 1 << 5, /* 1 Gb full-duplex rate support. */ - OFPPF_10GB_FD = 1 << 6, /* 10 Gb full-duplex rate support. */ - OFPPF_40GB_FD = 1 << 7, /* 40 Gb full-duplex rate support. */ - OFPPF_100GB_FD = 1 << 8, /* 100 Gb full-duplex rate support. */ - OFPPF_1TB_FD = 1 << 9, /* 1 Tb full-duplex rate support. */ - OFPPF_OTHER = 1 << 10, /* Other rate, not in the list. */ - OFPPF_COPPER = 1 << 11, /* Copper medium. */ - OFPPF_FIBER = 1 << 12, /* Fiber medium. */ - OFPPF_AUTONEG = 1 << 13, /* Auto-negotiation. */ - OFPPF_PAUSE = 1 << 14, /* Pause. */ + OFPPF_10MB_HD = 1 << 0, /* 10 Mb half-duplex rate support. */ + OFPPF_10MB_FD = 1 << 1, /* 10 Mb full-duplex rate support. */ + OFPPF_100MB_HD = 1 << 2, /* 100 Mb half-duplex rate support. */ + OFPPF_100MB_FD = 1 << 3, /* 100 Mb full-duplex rate support. */ + OFPPF_1GB_HD = 1 << 4, /* 1 Gb half-duplex rate support. */ + OFPPF_1GB_FD = 1 << 5, /* 1 Gb full-duplex rate support. */ + OFPPF_10GB_FD = 1 << 6, /* 10 Gb full-duplex rate support. */ + OFPPF_40GB_FD = 1 << 7, /* 40 Gb full-duplex rate support. */ + OFPPF_100GB_FD = 1 << 8, /* 100 Gb full-duplex rate support. */ + OFPPF_1TB_FD = 1 << 9, /* 1 Tb full-duplex rate support. */ + OFPPF_OTHER = 1 << 10, /* Other rate, not in the list. */ + + OFPPF_COPPER = 1 << 11, /* Copper medium. */ + OFPPF_FIBER = 1 << 12, /* Fiber medium. */ + OFPPF_AUTONEG = 1 << 13, /* Auto-negotiation. */ + OFPPF_PAUSE = 1 << 14, /* Pause. */ OFPPF_PAUSE_ASYM = 1 << 15 /* Asymmetric pause. */ }; -/* Common description for a queue. */ -struct ofp_queue_prop_header { - uint16_t property; /* One of OFPQT_. */ - uint16_t len; /* Length of property, including this header. */ - uint8_t pad[4]; /* 64-bit alignemnt. */ -}; -OFP_ASSERT(sizeof(struct ofp_queue_prop_header) == 8); +/* Description of a port */ +struct ofp_port { + uint32_t port_no; + uint8_t pad[4]; + uint8_t hw_addr[OFP_ETH_ALEN]; + uint8_t pad2[2]; /* Align to 64 bits. */ + char name[OFP_MAX_PORT_NAME_LEN]; /* Null-terminated */ -/* Full description for a queue. */ -struct ofp_packet_queue { - uint32_t queue_id; /* id for the specific queue. */ - uint32_t port; /* Port this queue is attached to. */ - uint16_t len; /* Length in bytes of this queue desc. */ - uint8_t pad[6]; /* 64-bit alignment. */ - struct ofp_queue_prop_header properties[0]; /* List of properties. */ + uint32_t config; /* Bitmap of OFPPC_* flags. */ + uint32_t state; /* Bitmap of OFPPS_* flags. */ + + /* Bitmaps of OFPPF_* that describe features. All bits zeroed if + * unsupported or unavailable. */ + uint32_t curr; /* Current features. */ + uint32_t advertised; /* Features being advertised by the port. */ + uint32_t supported; /* Features supported by the port. */ + uint32_t peer; /* Features advertised by peer. */ + + uint32_t curr_speed; /* Current port bitrate in kbps. */ + uint32_t max_speed; /* Max port bitrate in kbps */ }; -OFP_ASSERT(sizeof(struct ofp_packet_queue) == 16); +OFP_ASSERT(sizeof(struct ofp_port) == 64); -/* All ones is used to indicate all queues in a port (for stats retrieval). */ -#define OFPQ_ALL 0xffffffff +/* Switch features. */ +struct ofp_switch_features { + struct ofp_header header; + uint64_t datapath_id; /* Datapath unique ID. The lower 48-bits are for + a MAC address, while the upper 16-bits are + implementer-defined. */ -/* Min rate > 1000 means not configured. */ -#define OFPQ_MIN_RATE_UNCFG 0xffff + uint32_t n_buffers; /* Max packets buffered at once. */ + uint8_t n_tables; /* Number of tables supported by datapath. */ + uint8_t auxiliary_id; /* Identify auxiliary connections */ + uint8_t pad[2]; /* Align to 64-bits. */ -enum ofp_queue_properties { - OFPQT_MIN_RATE = 1, /* Minimum datarate guaranteed. */ - OFPQT_MAX_RATE = 2, /* Maximum datarate. */ - OFPQT_EXPERIMENTER = 0xffff /* Experimenter defined property. */ + /* Features. */ + uint32_t capabilities; /* Bitmap of support "ofp_capabilities". */ + uint32_t reserved; }; +OFP_ASSERT(sizeof(struct ofp_switch_features) == 32); -/* Min-Rate queue property description. */ -struct ofp_queue_prop_min_rate { - struct ofp_queue_prop_header prop_header; /* prop: OFPQT_MIN, len: 16. */ - uint16_t rate; /* In 1/10 of a percent; >1000 -> disabled. */ - uint8_t pad[6]; /* 64-bit alignment */ +/* What changed about the physical port */ +enum ofp_port_reason { + OFPPR_ADD = 0, /* The port was added. */ + OFPPR_DELETE = 1, /* The port was removed. */ + OFPPR_MODIFY = 2, /* Some attribute of the port has changed. */ }; -OFP_ASSERT(sizeof(struct ofp_queue_prop_min_rate) == 16); -/* Max-Rate queue property description. */ -struct ofp_queue_prop_max_rate { - struct ofp_queue_prop_header prop_header; /* prop: OFPQT_MAX, len: 16. */ - uint16_t rate; /* In 1/10 of a percent; >1000 -> disabled. */ - uint8_t pad[6]; /* 64-bit alignment */ +/* A physical port has changed in the datapath */ +struct ofp_port_status { + struct ofp_header header; + uint8_t reason; /* One of OFPPR_*. */ + uint8_t pad[7]; /* Align to 64-bits. */ + struct ofp_port desc; }; -OFP_ASSERT(sizeof(struct ofp_queue_prop_max_rate) == 16); +OFP_ASSERT(sizeof(struct ofp_port_status) == 80); -/* Experimenter queue property description. */ -struct ofp_queue_prop_experimenter { - struct ofp_queue_prop_header prop_header; /* prop: OFPQT_EXPERIMENTER, len: 16. */ - uint32_t experimenter; /* Experimenter ID which takes the same - form as in struct ofp_experimenter_header. */ - uint8_t pad[4]; /* 64-bit alignment */ - uint8_t data[0]; /* Experimenter defined data. */ +/* Modify behavior of the physical port */ +struct ofp_port_mod { + struct ofp_header header; + uint32_t port_no; + uint8_t pad[4]; + uint8_t hw_addr[OFP_ETH_ALEN]; /* The hardware address is not + configurable. This is used to + sanity-check the request, so it must + be the same as returned in an + ofp_port struct. */ + uint8_t pad2[2]; /* Pad to 64 bits. */ + uint32_t config; /* Bitmap of OFPPC_* flags. */ + uint32_t mask; /* Bitmap of OFPPC_* flags to be changed. */ + + uint32_t advertise; /* Bitmap of OFPPF_*. Zero all bits to prevent + any action taking place. */ + uint8_t pad3[4]; /* Pad to 64 bits. */ +}; +OFP_ASSERT(sizeof(struct ofp_port_mod) == 40); + +/* ## -------------------------- ## */ +/* ## OpenFlow Extensible Match. ## */ +/* ## -------------------------- ## */ + +/* The match type indicates the match structure (set of fields that compose the + * match) in use. The match type is placed in the type field at the beginning + * of all match structures. The "OpenFlow Extensible Match" type corresponds + * to OXM TLV format described below and must be supported by all OpenFlow + * switches. Extensions that define other match types may be published on the + * ONF wiki. Support for extensions is optional. + */ +enum ofp_match_type { + OFPMT_STANDARD = 0, /* Deprecated. */ + OFPMT_OXM = 1, /* OpenFlow Extensible Match */ }; -OFP_ASSERT(sizeof(struct ofp_queue_prop_experimenter) == 16); /* Fields to match against flows */ struct ofp_match { - uint16_t type; /* One of OFPMT_* */ - uint16_t length; /* Length of ofp_match (excluding padding) */ - /* Followed by: - * -Exactly (length - 4) (possibly 0) bytes containing OXM TLVs,then - * -Exactly ((length+7)/8*8-length)(between 0 and 7) bytes of - * all-zerobytes - * In summary, ofp_match is padded as needed, to make its overall size - * a multiple of 8, to preserve alignement in structures using it. - */ - uint8_t oxm_fields[4]; /* OXMs start here - Make compiler happy */ + uint16_t type; /* One of OFPMT_* */ + uint16_t length; /* Length of ofp_match (excluding padding) */ + /* Followed by: + * - Exactly (length - 4) (possibly 0) bytes containing OXM TLVs, then + * - Exactly ((length + 7)/8*8 - length) (between 0 and 7) bytes of + * all-zero bytes + * In summary, ofp_match is padded as needed, to make its overall size + * a multiple of 8, to preserve alignment in structures using it. + */ + uint8_t oxm_fields[0]; /* 0 or more OXM match fields */ + uint8_t pad[4]; /* Zero bytes - see above for sizing */ }; OFP_ASSERT(sizeof(struct ofp_match) == 8); -/* The match type indicates the match structure (set of fields that compose the -* match) in use. The match type is placed in the type field at the beginning -* of all match structures. The "OpenFlow Extensible Match" type corresponds -* to OXM TLV format described below and must be supported by all OpenFlow -* switches. Extensions that define other match types may be published on the -* ONF wiki. Support for extensions is optional. -*/ -enum ofp_match_type { - OFPMT_STANDARD = 0, /* Deprecated. */ - OFPMT_OXM = 1, /* OpenFlow Extensible Match */ -}; +/* Components of a OXM TLV header. + * Those macros are not valid for the experimenter class, macros for the + * experimenter class will depend on the experimenter header used. */ +#define OXM_HEADER__(CLASS, FIELD, HASMASK, LENGTH) \ + (((CLASS) << 16) | ((FIELD) << 9) | ((HASMASK) << 8) | (LENGTH)) +#define OXM_HEADER(CLASS, FIELD, LENGTH) \ + OXM_HEADER__(CLASS, FIELD, 0, LENGTH) +#define OXM_HEADER_W(CLASS, FIELD, LENGTH) \ + OXM_HEADER__(CLASS, FIELD, 1, (LENGTH) * 2) +#define OXM_CLASS(HEADER) ((HEADER) >> 16) +#define OXM_FIELD(HEADER) (((HEADER) >> 9) & 0x7f) +#define OXM_TYPE(HEADER) (((HEADER) >> 9) & 0x7fffff) +#define OXM_HASMASK(HEADER) (((HEADER) >> 8) & 1) +#define OXM_LENGTH(HEADER) ((HEADER) & 0xff) + +#define OXM_MAKE_WILD_HEADER(HEADER) \ + OXM_HEADER_W(OXM_CLASS(HEADER), OXM_FIELD(HEADER), OXM_LENGTH(HEADER)) /* OXM Class IDs. -* The high order bit differentiate reserved classes from member classes. -* Classes 0x0000 to 0x7FFF are member classes, allocated by ONF. -* Classes 0x8000 to 0xFFFE are reserved classes, reserved for standardisation. -*/ + * The high order bit differentiate reserved classes from member classes. + * Classes 0x0000 to 0x7FFF are member classes, allocated by ONF. + * Classes 0x8000 to 0xFFFE are reserved classes, reserved for standardisation. + */ enum ofp_oxm_class { - OFPXMC_NXM_0 = 0x0000, /* Backward compatibility with NXM */ - OFPXMC_NXM_1 = 0x0001, /* Backward compatibility with NXM */ - OFPXMC_OPENFLOW_BASIC = 0x8000, /* Basic class for OpenFlow */ - OFPXMC_EXPERIMENTER = 0xFFFF, /* Experimenter class */ + OFPXMC_NXM_0 = 0x0000, /* Backward compatibility with NXM */ + OFPXMC_NXM_1 = 0x0001, /* Backward compatibility with NXM */ + OFPXMC_OPENFLOW_BASIC = 0x8000, /* Basic class for OpenFlow */ + OFPXMC_EXPERIMENTER = 0xFFFF, /* Experimenter class */ }; /* OXM Flow match field types for OpenFlow basic class. */ enum oxm_ofb_match_fields { - OFPXMT_OFB_IN_PORT = 0, /* Switch input port. */ - OFPXMT_OFB_IN_PHY_PORT = 1, /* Switch physical input port. */ - OFPXMT_OFB_METADATA = 2, /* Metadata passed between tables. */ - OFPXMT_OFB_ETH_DST = 3, /* Ethernet destination address. */ - OFPXMT_OFB_ETH_SRC = 4, /* Ethernet source address. */ - OFPXMT_OFB_ETH_TYPE = 5, /* Ethernet frame type. */ - OFPXMT_OFB_VLAN_VID = 6, /* VLAN id. */ - OFPXMT_OFB_VLAN_PCP = 7, /* VLAN priority. */ - OFPXMT_OFB_IP_DSCP = 8, /* IP DSCP (6 bits in ToS field). */ - OFPXMT_OFB_IP_ECN = 9, /* IP ECN (2 bits in ToS field). */ - OFPXMT_OFB_IP_PROTO = 10, /* IP protocol. */ - OFPXMT_OFB_IPV4_SRC = 11, /* IPv4 source address. */ - OFPXMT_OFB_IPV4_DST = 12, /* IPv4 destination address. */ - OFPXMT_OFB_TCP_SRC = 13, /* TCP source port. */ - OFPXMT_OFB_TCP_DST = 14, /* TCP destination port. */ - OFPXMT_OFB_UDP_SRC = 15, /* UDP source port. */ - OFPXMT_OFB_UDP_DST = 16, /* UDP destination port. */ - OFPXMT_OFB_SCTP_SRC = 17, /* SCTP source port. */ - OFPXMT_OFB_SCTP_DST = 18, /* SCTP destination port. */ - OFPXMT_OFB_ICMPV4_TYPE = 19, /* ICMP type. */ - OFPXMT_OFB_ICMPV4_CODE = 20, /* ICMP code. */ - OFPXMT_OFB_ARP_OP = 21, /* ARP opcode. */ - OFPXMT_OFB_ARP_SPA = 22, /* ARP source IPv4 address. */ - OFPXMT_OFB_ARP_TPA = 23, /* ARP target IPv4 address. */ - OFPXMT_OFB_ARP_SHA = 24, /* ARP source hardware address. */ - OFPXMT_OFB_ARP_THA = 25, /* ARP target hardware address. */ - OFPXMT_OFB_IPV6_SRC = 26, /* IPv6 source address. */ - OFPXMT_OFB_IPV6_DST = 27, /* IPv6 destination address. */ - OFPXMT_OFB_IPV6_FLABEL = 28, /* IPv6 Flow Label */ - OFPXMT_OFB_ICMPV6_TYPE = 29, /* ICMPv6 type. */ - OFPXMT_OFB_ICMPV6_CODE = 30, /* ICMPv6 code. */ + OFPXMT_OFB_IN_PORT = 0, /* Switch input port. */ + OFPXMT_OFB_IN_PHY_PORT = 1, /* Switch physical input port. */ + OFPXMT_OFB_METADATA = 2, /* Metadata passed between tables. */ + OFPXMT_OFB_ETH_DST = 3, /* Ethernet destination address. */ + OFPXMT_OFB_ETH_SRC = 4, /* Ethernet source address. */ + OFPXMT_OFB_ETH_TYPE = 5, /* Ethernet frame type. */ + OFPXMT_OFB_VLAN_VID = 6, /* VLAN id. */ + OFPXMT_OFB_VLAN_PCP = 7, /* VLAN priority. */ + OFPXMT_OFB_IP_DSCP = 8, /* IP DSCP (6 bits in ToS field). */ + OFPXMT_OFB_IP_ECN = 9, /* IP ECN (2 bits in ToS field). */ + OFPXMT_OFB_IP_PROTO = 10, /* IP protocol. */ + OFPXMT_OFB_IPV4_SRC = 11, /* IPv4 source address. */ + OFPXMT_OFB_IPV4_DST = 12, /* IPv4 destination address. */ + OFPXMT_OFB_TCP_SRC = 13, /* TCP source port. */ + OFPXMT_OFB_TCP_DST = 14, /* TCP destination port. */ + OFPXMT_OFB_UDP_SRC = 15, /* UDP source port. */ + OFPXMT_OFB_UDP_DST = 16, /* UDP destination port. */ + OFPXMT_OFB_SCTP_SRC = 17, /* SCTP source port. */ + OFPXMT_OFB_SCTP_DST = 18, /* SCTP destination port. */ + OFPXMT_OFB_ICMPV4_TYPE = 19, /* ICMP type. */ + OFPXMT_OFB_ICMPV4_CODE = 20, /* ICMP code. */ + OFPXMT_OFB_ARP_OP = 21, /* ARP opcode. */ + OFPXMT_OFB_ARP_SPA = 22, /* ARP source IPv4 address. */ + OFPXMT_OFB_ARP_TPA = 23, /* ARP target IPv4 address. */ + OFPXMT_OFB_ARP_SHA = 24, /* ARP source hardware address. */ + OFPXMT_OFB_ARP_THA = 25, /* ARP target hardware address. */ + OFPXMT_OFB_IPV6_SRC = 26, /* IPv6 source address. */ + OFPXMT_OFB_IPV6_DST = 27, /* IPv6 destination address. */ + OFPXMT_OFB_IPV6_FLABEL = 28, /* IPv6 Flow Label */ + OFPXMT_OFB_ICMPV6_TYPE = 29, /* ICMPv6 type. */ + OFPXMT_OFB_ICMPV6_CODE = 30, /* ICMPv6 code. */ OFPXMT_OFB_IPV6_ND_TARGET = 31, /* Target address for ND. */ - OFPXMT_OFB_IPV6_ND_SLL = 32, /* Source link-layer for ND. */ - OFPXMT_OFB_IPV6_ND_TLL = 33, /* Target link-layer for ND. */ - OFPXMT_OFB_MPLS_LABEL = 34, /* MPLS label. */ - OFPXMT_OFB_MPLS_TC = 35, /* MPLS TC. */ - OFPXMT_OFB_MPLS_BOS = 36, /* MPLS BoS bit. */ - OFPXMT_OFB_PBB_ISID = 37, /* PBB I-SID. */ - OFPXMT_OFB_TUNNEL_ID = 38, /* Logical Port Metadata. */ - OFPXMT_OFB_IPV6_EXTHDR = 39 /* IPv6 Extension Header pseudo-field */ -}; + OFPXMT_OFB_IPV6_ND_SLL = 32, /* Source link-layer for ND. */ + OFPXMT_OFB_IPV6_ND_TLL = 33, /* Target link-layer for ND. */ + OFPXMT_OFB_MPLS_LABEL = 34, /* MPLS label. */ + OFPXMT_OFB_MPLS_TC = 35, /* MPLS TC. */ + OFPXMT_OFB_MPLS_BOS = 36, /* MPLS BoS bit. */ + OFPXMT_OFB_PBB_ISID = 37, /* PBB I-SID. */ + OFPXMT_OFB_TUNNEL_ID = 38, /* Logical Port Metadata. */ + OFPXMT_OFB_IPV6_EXTHDR = 39, /* IPv6 Extension Header pseudo-field */ +}; + +#define OFPXMT_OFB_ALL ((UINT64_C(1) << 40) - 1) + +/* OpenFlow port on which the packet was received. + * May be a physical port, a logical port, or the reserved port OFPP_LOCAL + * + * Prereqs: None. + * + * Format: 32-bit integer in network byte order. + * + * Masking: Not maskable. */ +#define OXM_OF_IN_PORT OXM_HEADER (0x8000, OFPXMT_OFB_IN_PORT, 4) + +/* Physical port on which the packet was received. + * + * Consider a packet received on a tunnel interface defined over a link + * aggregation group (LAG) with two physical port members. If the tunnel + * interface is the logical port bound to OpenFlow. In this case, + * OFPXMT_OF_IN_PORT is the tunnel's port number and OFPXMT_OF_IN_PHY_PORT is + * the physical port number of the LAG on which the tunnel is configured. + * + * When a packet is received directly on a physical port and not processed by a + * logical port, OFPXMT_OF_IN_PORT and OFPXMT_OF_IN_PHY_PORT have the same + * value. + * + * This field is usually not available in a regular match and only available + * in ofp_packet_in messages when it's different from OXM_OF_IN_PORT. + * + * Prereqs: OXM_OF_IN_PORT must be present. + * + * Format: 32-bit integer in network byte order. + * + * Masking: Not maskable. */ +#define OXM_OF_IN_PHY_PORT OXM_HEADER (0x8000, OFPXMT_OFB_IN_PHY_PORT, 4) + +/* Table metadata. + * + * Prereqs: None. + * + * Format: 64-bit integer in network byte order. + * + * Masking: Arbitrary masks. + */ +#define OXM_OF_METADATA OXM_HEADER (0x8000, OFPXMT_OFB_METADATA, 8) +#define OXM_OF_METADATA_W OXM_HEADER_W(0x8000, OFPXMT_OFB_METADATA, 8) + +/* Source or destination address in Ethernet header. + * + * Prereqs: None. + * + * Format: 48-bit Ethernet MAC address. + * + * Masking: Arbitrary masks. */ +#define OXM_OF_ETH_DST OXM_HEADER (0x8000, OFPXMT_OFB_ETH_DST, 6) +#define OXM_OF_ETH_DST_W OXM_HEADER_W(0x8000, OFPXMT_OFB_ETH_DST, 6) +#define OXM_OF_ETH_SRC OXM_HEADER (0x8000, OFPXMT_OFB_ETH_SRC, 6) +#define OXM_OF_ETH_SRC_W OXM_HEADER_W(0x8000, OFPXMT_OFB_ETH_SRC, 6) + +/* Packet's Ethernet type. + * + * Prereqs: None. + * + * Format: 16-bit integer in network byte order. + * + * Masking: Not maskable. */ +#define OXM_OF_ETH_TYPE OXM_HEADER (0x8000, OFPXMT_OFB_ETH_TYPE, 2) /* The VLAN id is 12-bits, so we can use the entire 16 bits to indicate -* special conditions. -*/ + * special conditions. + */ enum ofp_vlan_id { OFPVID_PRESENT = 0x1000, /* Bit that indicate that a VLAN id is set */ - OFPVID_NONE = 0x0000, /* No VLAN id was set. */ -}; + OFPVID_NONE = 0x0000, /* No VLAN id was set. */ +}; +/* Define for compatibility */ +#define OFP_VLAN_NONE OFPVID_NONE + +/* 802.1Q VID. + * + * For a packet with an 802.1Q header, this is the VLAN-ID (VID) from the + * outermost tag, with the CFI bit forced to 1. For a packet with no 802.1Q + * header, this has value OFPVID_NONE. + * + * Prereqs: None. + * + * Format: 16-bit integer in network byte order with bit 13 indicating + * presence of VLAN header and 3 most-significant bits forced to 0. + * Only the lower 13 bits have meaning. + * + * Masking: Arbitrary masks. + * + * This field can be used in various ways: + * + * - If it is not constrained at all, the nx_match matches packets without + * an 802.1Q header or with an 802.1Q header that has any VID value. + * + * - Testing for an exact match with 0x0 matches only packets without + * an 802.1Q header. + * + * - Testing for an exact match with a VID value with CFI=1 matches packets + * that have an 802.1Q header with a specified VID. + * + * - Testing for an exact match with a nonzero VID value with CFI=0 does + * not make sense. The switch may reject this combination. + * + * - Testing with nxm_value=0, nxm_mask=0x0fff matches packets with no 802.1Q + * header or with an 802.1Q header with a VID of 0. + * + * - Testing with nxm_value=0x1000, nxm_mask=0x1000 matches packets with + * an 802.1Q header that has any VID value. + */ +#define OXM_OF_VLAN_VID OXM_HEADER (0x8000, OFPXMT_OFB_VLAN_VID, 2) +#define OXM_OF_VLAN_VID_W OXM_HEADER_W(0x8000, OFPXMT_OFB_VLAN_VID, 2) + +/* 802.1Q PCP. + * + * For a packet with an 802.1Q header, this is the VLAN-PCP from the + * outermost tag. For a packet with no 802.1Q header, this has value + * 0. + * + * Prereqs: OXM_OF_VLAN_VID must be different from OFPVID_NONE. + * + * Format: 8-bit integer with 5 most-significant bits forced to 0. + * Only the lower 3 bits have meaning. + * + * Masking: Not maskable. + */ +#define OXM_OF_VLAN_PCP OXM_HEADER (0x8000, OFPXMT_OFB_VLAN_PCP, 1) + +/* The Diff Serv Code Point (DSCP) bits of the IP header. + * Part of the IPv4 ToS field or the IPv6 Traffic Class field. + * + * Prereqs: OXM_OF_ETH_TYPE must be either 0x0800 or 0x86dd. + * + * Format: 8-bit integer with 2 most-significant bits forced to 0. + * Only the lower 6 bits have meaning. + * + * Masking: Not maskable. */ +#define OXM_OF_IP_DSCP OXM_HEADER (0x8000, OFPXMT_OFB_IP_DSCP, 1) + +/* The ECN bits of the IP header. + * Part of the IPv4 ToS field or the IPv6 Traffic Class field. + * + * Prereqs: OXM_OF_ETH_TYPE must be either 0x0800 or 0x86dd. + * + * Format: 8-bit integer with 6 most-significant bits forced to 0. + * Only the lower 2 bits have meaning. + * + * Masking: Not maskable. */ +#define OXM_OF_IP_ECN OXM_HEADER (0x8000, OFPXMT_OFB_IP_ECN, 1) + +/* The "protocol" byte in the IP header. + * + * Prereqs: OXM_OF_ETH_TYPE must be either 0x0800 or 0x86dd. + * + * Format: 8-bit integer. + * + * Masking: Not maskable. */ +#define OXM_OF_IP_PROTO OXM_HEADER (0x8000, OFPXMT_OFB_IP_PROTO, 1) + +/* The source or destination address in the IP header. + * + * Prereqs: OXM_OF_ETH_TYPE must match 0x0800 exactly. + * + * Format: 32-bit integer in network byte order. + * + * Masking: Arbitrary masks. + */ +#define OXM_OF_IPV4_SRC OXM_HEADER (0x8000, OFPXMT_OFB_IPV4_SRC, 4) +#define OXM_OF_IPV4_SRC_W OXM_HEADER_W(0x8000, OFPXMT_OFB_IPV4_SRC, 4) +#define OXM_OF_IPV4_DST OXM_HEADER (0x8000, OFPXMT_OFB_IPV4_DST, 4) +#define OXM_OF_IPV4_DST_W OXM_HEADER_W(0x8000, OFPXMT_OFB_IPV4_DST, 4) + +/* The source or destination port in the TCP header. + * + * Prereqs: + * OXM_OF_ETH_TYPE must be either 0x0800 or 0x86dd. + * OXM_OF_IP_PROTO must match 6 exactly. + * + * Format: 16-bit integer in network byte order. + * + * Masking: Not maskable. */ +#define OXM_OF_TCP_SRC OXM_HEADER (0x8000, OFPXMT_OFB_TCP_SRC, 2) +#define OXM_OF_TCP_DST OXM_HEADER (0x8000, OFPXMT_OFB_TCP_DST, 2) + +/* The source or destination port in the UDP header. + * + * Prereqs: + * OXM_OF_ETH_TYPE must match either 0x0800 or 0x86dd. + * OXM_OF_IP_PROTO must match 17 exactly. + * + * Format: 16-bit integer in network byte order. + * + * Masking: Not maskable. */ +#define OXM_OF_UDP_SRC OXM_HEADER (0x8000, OFPXMT_OFB_UDP_SRC, 2) +#define OXM_OF_UDP_DST OXM_HEADER (0x8000, OFPXMT_OFB_UDP_DST, 2) + +/* The source or destination port in the SCTP header. + * + * Prereqs: + * OXM_OF_ETH_TYPE must match either 0x0800 or 0x86dd. + * OXM_OF_IP_PROTO must match 132 exactly. + * + * Format: 16-bit integer in network byte order. + * + * Masking: Not maskable. */ +#define OXM_OF_SCTP_SRC OXM_HEADER (0x8000, OFPXMT_OFB_SCTP_SRC, 2) +#define OXM_OF_SCTP_DST OXM_HEADER (0x8000, OFPXMT_OFB_SCTP_DST, 2) + +/* The type or code in the ICMP header. + * + * Prereqs: + * OXM_OF_ETH_TYPE must match 0x0800 exactly. + * OXM_OF_IP_PROTO must match 1 exactly. + * + * Format: 8-bit integer. + * + * Masking: Not maskable. */ +#define OXM_OF_ICMPV4_TYPE OXM_HEADER (0x8000, OFPXMT_OFB_ICMPV4_TYPE, 1) +#define OXM_OF_ICMPV4_CODE OXM_HEADER (0x8000, OFPXMT_OFB_ICMPV4_CODE, 1) + +/* ARP opcode. + * + * For an Ethernet+IP ARP packet, the opcode in the ARP header. Always 0 + * otherwise. + * + * Prereqs: OXM_OF_ETH_TYPE must match 0x0806 exactly. + * + * Format: 16-bit integer in network byte order. + * + * Masking: Not maskable. */ +#define OXM_OF_ARP_OP OXM_HEADER (0x8000, OFPXMT_OFB_ARP_OP, 2) + +/* For an Ethernet+IP ARP packet, the source or target protocol address + * in the ARP header. Always 0 otherwise. + * + * Prereqs: OXM_OF_ETH_TYPE must match 0x0806 exactly. + * + * Format: 32-bit integer in network byte order. + * + * Masking: Arbitrary masks. + */ +#define OXM_OF_ARP_SPA OXM_HEADER (0x8000, OFPXMT_OFB_ARP_SPA, 4) +#define OXM_OF_ARP_SPA_W OXM_HEADER_W(0x8000, OFPXMT_OFB_ARP_SPA, 4) +#define OXM_OF_ARP_TPA OXM_HEADER (0x8000, OFPXMT_OFB_ARP_TPA, 4) +#define OXM_OF_ARP_TPA_W OXM_HEADER_W(0x8000, OFPXMT_OFB_ARP_TPA, 4) + +/* For an Ethernet+IP ARP packet, the source or target hardware address + * in the ARP header. Always 0 otherwise. + * + * Prereqs: OXM_OF_ETH_TYPE must match 0x0806 exactly. + * + * Format: 48-bit Ethernet MAC address. + * + * Masking: Not maskable. */ +#define OXM_OF_ARP_SHA OXM_HEADER (0x8000, OFPXMT_OFB_ARP_SHA, 6) +#define OXM_OF_ARP_SHA_W OXM_HEADER_W (0x8000, OFPXMT_OFB_ARP_SHA, 6) +#define OXM_OF_ARP_THA OXM_HEADER (0x8000, OFPXMT_OFB_ARP_THA, 6) +#define OXM_OF_ARP_THA_W OXM_HEADER_W (0x8000, OFPXMT_OFB_ARP_THA, 6) + + +/* The source or destination address in the IPv6 header. + * + * Prereqs: OXM_OF_ETH_TYPE must match 0x86dd exactly. + * + * Format: 128-bit IPv6 address. + * + * Masking: Arbitrary masks. + */ +#define OXM_OF_IPV6_SRC OXM_HEADER (0x8000, OFPXMT_OFB_IPV6_SRC, 16) +#define OXM_OF_IPV6_SRC_W OXM_HEADER_W(0x8000, OFPXMT_OFB_IPV6_SRC, 16) +#define OXM_OF_IPV6_DST OXM_HEADER (0x8000, OFPXMT_OFB_IPV6_DST, 16) +#define OXM_OF_IPV6_DST_W OXM_HEADER_W(0x8000, OFPXMT_OFB_IPV6_DST, 16) + +/* The IPv6 Flow Label + * + * Prereqs: + * OXM_OF_ETH_TYPE must match 0x86dd exactly + * + * Format: 32-bit integer with 12 most-significant bits forced to 0. + * Only the lower 20 bits have meaning. + * + * Masking: Arbitrary masks. + */ +#define OXM_OF_IPV6_FLABEL OXM_HEADER (0x8000, OFPXMT_OFB_IPV6_FLABEL, 4) +#define OXM_OF_IPV6_FLABEL_W OXM_HEADER_W(0x8000, OFPXMT_OFB_IPV6_FLABEL, 4) + +/* The type or code in the ICMPv6 header. + * + * Prereqs: + * OXM_OF_ETH_TYPE must match 0x86dd exactly. + * OXM_OF_IP_PROTO must match 58 exactly. + * + * Format: 8-bit integer. + * + * Masking: Not maskable. */ +#define OXM_OF_ICMPV6_TYPE OXM_HEADER (0x8000, OFPXMT_OFB_ICMPV6_TYPE, 1) +#define OXM_OF_ICMPV6_CODE OXM_HEADER (0x8000, OFPXMT_OFB_ICMPV6_CODE, 1) + +/* The target address in an IPv6 Neighbor Discovery message. + * + * Prereqs: + * OXM_OF_ETH_TYPE must match 0x86dd exactly. + * OXM_OF_IP_PROTO must match 58 exactly. + * OXM_OF_ICMPV6_TYPE must be either 135 or 136. + * + * Format: 128-bit IPv6 address. + * + * Masking: Not maskable. */ +#define OXM_OF_IPV6_ND_TARGET OXM_HEADER (0x8000, OFPXMT_OFB_IPV6_ND_TARGET, 16) + +/* The source link-layer address option in an IPv6 Neighbor Discovery + * message. + * + * Prereqs: + * OXM_OF_ETH_TYPE must match 0x86dd exactly. + * OXM_OF_IP_PROTO must match 58 exactly. + * OXM_OF_ICMPV6_TYPE must be exactly 135. + * + * Format: 48-bit Ethernet MAC address. + * + * Masking: Not maskable. */ +#define OXM_OF_IPV6_ND_SLL OXM_HEADER (0x8000, OFPXMT_OFB_IPV6_ND_SLL, 6) + +/* The target link-layer address option in an IPv6 Neighbor Discovery + * message. + * + * Prereqs: + * OXM_OF_ETH_TYPE must match 0x86dd exactly. + * OXM_OF_IP_PROTO must match 58 exactly. + * OXM_OF_ICMPV6_TYPE must be exactly 136. + * + * Format: 48-bit Ethernet MAC address. + * + * Masking: Not maskable. */ +#define OXM_OF_IPV6_ND_TLL OXM_HEADER (0x8000, OFPXMT_OFB_IPV6_ND_TLL, 6) + +/* The LABEL in the first MPLS shim header. + * + * Prereqs: + * OXM_OF_ETH_TYPE must match 0x8847 or 0x8848 exactly. + * + * Format: 32-bit integer in network byte order with 12 most-significant + * bits forced to 0. Only the lower 20 bits have meaning. + * + * Masking: Not maskable. */ +#define OXM_OF_MPLS_LABEL OXM_HEADER (0x8000, OFPXMT_OFB_MPLS_LABEL, 4) + +/* The TC in the first MPLS shim header. + * + * Prereqs: + * OXM_OF_ETH_TYPE must match 0x8847 or 0x8848 exactly. + * + * Format: 8-bit integer with 5 most-significant bits forced to 0. + * Only the lower 3 bits have meaning. + * + * Masking: Not maskable. */ +#define OXM_OF_MPLS_TC OXM_HEADER (0x8000, OFPXMT_OFB_MPLS_TC, 1) + +/* The BoS bit in the first MPLS shim header. + * + * Prereqs: + * OXM_OF_ETH_TYPE must match 0x8847 or 0x8848 exactly. + * + * Format: 8-bit integer with 7 most-significant bits forced to 0. + * Only the lowest bit have a meaning. + * + * Masking: Not maskable. */ +#define OXM_OF_MPLS_BOS OXM_HEADER (0x8000, OFPXMT_OFB_MPLS_BOS, 1) + +/* IEEE 802.1ah I-SID. + * + * For a packet with a PBB header, this is the I-SID from the + * outermost service tag. + * + * Prereqs: + * OXM_OF_ETH_TYPE must match 0x88E7 exactly. + * + * Format: 24-bit integer in network byte order. + * + * Masking: Arbitrary masks. */ +#define OXM_OF_PBB_ISID OXM_HEADER (0x8000, OFPXMT_OFB_PBB_ISID, 3) +#define OXM_OF_PBB_ISID_W OXM_HEADER_W(0x8000, OFPXMT_OFB_PBB_ISID, 3) + +/* Logical Port Metadata. + * + * Metadata associated with a logical port. + * If the logical port performs encapsulation and decapsulation, this + * is the demultiplexing field from the encapsulation header. + * For example, for a packet received via GRE tunnel including a (32-bit) key, + * the key is stored in the low 32-bits and the high bits are zeroed. + * For a MPLS logical port, the low 20 bits represent the MPLS Label. + * For a VxLAN logical port, the low 24 bits represent the VNI. + * If the packet is not received through a logical port, the value is 0. + * + * Prereqs: None. + * + * Format: 64-bit integer in network byte order. + * + * Masking: Arbitrary masks. */ +#define OXM_OF_TUNNEL_ID OXM_HEADER (0x8000, OFPXMT_OFB_TUNNEL_ID, 8) +#define OXM_OF_TUNNEL_ID_W OXM_HEADER_W(0x8000, OFPXMT_OFB_TUNNEL_ID, 8) + +/* The IPv6 Extension Header pseudo-field. + * + * Prereqs: + * OXM_OF_ETH_TYPE must match 0x86dd exactly + * + * Format: 16-bit integer with 7 most-significant bits forced to 0. + * Only the lower 9 bits have meaning. + * + * Masking: Maskable. */ +#define OXM_OF_IPV6_EXTHDR OXM_HEADER (0x8000, OFPXMT_OFB_IPV6_EXTHDR, 2) +#define OXM_OF_IPV6_EXTHDR_W OXM_HEADER_W(0x8000, OFPXMT_OFB_IPV6_EXTHDR, 2) /* Bit definitions for IPv6 Extension Header pseudo-field. */ -enum ofp_ipv6exthdr_flags { - OFPIEH_NONEXT = 1 << 0, /* "No next header" encountered. */ - OFPIEH_ESP = 1 << 1, /* Encrypted Sec Payload header present. */ - OFPIEH_AUTH = 1 << 2, /* Authentication header present. */ - OFPIEH_DEST = 1 << 3, /* 1 or 2 dest headers present. */ - OFPIEH_FRAG = 1 << 4, /* Fragment header present. */ - OFPIEH_ROUTER = 1 << 5, /* Router header present. */ - OFPIEH_HOP = 1 << 6, /* Hop-by-hop header present. */ - OFPIEH_UNREP = 1 << 7, /* Unexpected repeats encountered. */ - OFPIEH_UNSEQ = 1 << 8, /* Unexpected sequencing encountered. */ -}; - -/* Header for OXM experimenter match fields. */ +enum ofp_ipv6exthdr_flags { + OFPIEH_NONEXT = 1 << 0, /* "No next header" encountered. */ + OFPIEH_ESP = 1 << 1, /* Encrypted Sec Payload header present. */ + OFPIEH_AUTH = 1 << 2, /* Authentication header present. */ + OFPIEH_DEST = 1 << 3, /* 1 or 2 dest headers present. */ + OFPIEH_FRAG = 1 << 4, /* Fragment header present. */ + OFPIEH_ROUTER = 1 << 5, /* Router header present. */ + OFPIEH_HOP = 1 << 6, /* Hop-by-hop header present. */ + OFPIEH_UNREP = 1 << 7, /* Unexpected repeats encountered. */ + OFPIEH_UNSEQ = 1 << 8, /* Unexpected sequencing encountered. */ +}; + +/* Header for OXM experimenter match fields. + * The experimenter class should not use OXM_HEADER() macros for defining + * fields due to this extra header. */ struct ofp_oxm_experimenter_header { - uint32_t oxm_header; /* oxm_class = OFPXMC_EXPERIMENTER */ - uint32_t experimenter; /* Experimenter ID which takes the same - form as in struct ofp_experimenter_header. */ + uint32_t oxm_header; /* oxm_class = OFPXMC_EXPERIMENTER */ + uint32_t experimenter; /* Experimenter ID which takes the same + form as in struct ofp_experimenter_header. */ }; OFP_ASSERT(sizeof(struct ofp_oxm_experimenter_header) == 8); -enum ofp_instruction_type { - OFPIT_GOTO_TABLE = 1, /* Setup the next table in the lookup */ - OFPIT_WRITE_METADATA = 2, /* Setup the metadata field for use later in - pipeline */ - OFPIT_WRITE_ACTIONS = 3, /* Write the action(s) onto the datapath action - set */ - OFPIT_APPLY_ACTIONS = 4, /* Applies the action(s) immediately */ - OFPIT_CLEAR_ACTIONS = 5, /* Clears all actions from the datapath - action set */ - OFPIT_METER = 6, /* Apply meter (rate limiter) */ - - OFPIT_EXPERIMENTER = 0xFFFF /* Experimenter instruction */ -}; - -/* Generic ofp_instruction structure */ -struct ofp_instruction { - uint16_t type; /* Instruction type */ - uint16_t len; /* Length of this struct in bytes. */ - uint8_t pad[4]; /* Align to 64-bits */ -}; -OFP_ASSERT(sizeof(struct ofp_instruction) == 8); - -/* Instruction structure for OFPIT_GOTO_TABLE */ -struct ofp_instruction_goto_table { - uint16_t type; /* OFPIT_GOTO_TABLE */ - uint16_t len; /* Length of this struct in bytes. */ - uint8_t table_id; /* Set next table in the lookup pipeline */ - uint8_t pad[3]; /* Pad to 64 bits. */ -}; -OFP_ASSERT(sizeof(struct ofp_instruction_goto_table) == 8); - -/* Instruction structure for OFPIT_WRITE_METADATA */ -struct ofp_instruction_write_metadata { - uint16_t type; /* OFPIT_WRITE_METADATA */ - uint16_t len; /* Length of this struct in bytes. */ - uint8_t pad[4]; /* Align to 64-bits */ - uint64_t metadata; /* Metadata value to write */ - uint64_t metadata_mask; /* Metadata write bitmask */ -}; -OFP_ASSERT(sizeof(struct ofp_instruction_write_metadata) == 24); - -/* Action header that is common to all actions. The length includes the -* header and any padding used to make the action 64-bit aligned. -* NB: The length of an action *must* always be a multiple of eight. */ -struct ofp_action_header { - uint16_t type; /* One of OFPAT_*. */ - uint16_t len; /* Length of action, including this - header. This is the length of action, - including any padding to make it - 64-bit aligned. */ - uint8_t pad[4]; -}; -OFP_ASSERT(sizeof(struct ofp_action_header) == 8); - -/* Instruction structure for OFPIT_WRITE/APPLY/CLEAR_ACTIONS */ -struct ofp_instruction_actions { - uint16_t type; /* One of OFPIT_*_ACTIONS */ - uint16_t len; /* Length of this struct in bytes. */ - uint8_t pad[4]; /* Align to 64-bits */ - struct ofp_action_header actions[0]; /* Actions associated with - OFPIT_WRITE_ACTIONS and - OFPIT_APPLY_ACTIONS */ -}; -OFP_ASSERT(sizeof(struct ofp_instruction_actions) == 8); - -/* Instruction structure for OFPIT_METER */ -struct ofp_instruction_meter { - uint16_t type; /* OFPIT_METER */ - uint16_t len; /* Length is 8. */ - uint32_t meter_id; /* Meter instance. */ -}; -OFP_ASSERT(sizeof(struct ofp_instruction_meter) == 8); - +/* ## ----------------- ## */ +/* ## OpenFlow Actions. ## */ +/* ## ----------------- ## */ enum ofp_action_type { - OFPAT_OUTPUT = 0, /* Output to switch port. */ + OFPAT_OUTPUT = 0, /* Output to switch port. */ OFPAT_COPY_TTL_OUT = 11, /* Copy TTL "outwards" -- from next-to-outermost to outermost */ - OFPAT_COPY_TTL_IN = 12, /* Copy TTL "inwards" -- from outermost to - next-to-outermost */ + OFPAT_COPY_TTL_IN = 12, /* Copy TTL "inwards" -- from outermost to + next-to-outermost */ OFPAT_SET_MPLS_TTL = 15, /* MPLS TTL */ OFPAT_DEC_MPLS_TTL = 16, /* Decrement MPLS TTL */ - OFPAT_PUSH_VLAN = 17, /* Push a new VLAN tag */ - OFPAT_POP_VLAN = 18, /* Pop the outer VLAN tag */ - OFPAT_PUSH_MPLS = 19, /* Push a new MPLS tag */ - OFPAT_POP_MPLS = 20, /* Pop the outer MPLS tag */ - OFPAT_SET_QUEUE = 21, /* Set queue id when outputting to a port */ - OFPAT_GROUP = 22, /* Apply group. */ - OFPAT_SET_NW_TTL = 23, /* IP TTL. */ - OFPAT_DEC_NW_TTL = 24, /* Decrement IP TTL. */ - OFPAT_SET_FIELD = 25, /* Set a header field using OXM TLV format. */ - OFPAT_PUSH_PBB = 26, /*Push a new PBB service tag (I-TAG) */ - OFPAT_POP_PBB = 27, /* Pop the outer PBB service tag (I-TAG) */ + + OFPAT_PUSH_VLAN = 17, /* Push a new VLAN tag */ + OFPAT_POP_VLAN = 18, /* Pop the outer VLAN tag */ + OFPAT_PUSH_MPLS = 19, /* Push a new MPLS tag */ + OFPAT_POP_MPLS = 20, /* Pop the outer MPLS tag */ + OFPAT_SET_QUEUE = 21, /* Set queue id when outputting to a port */ + OFPAT_GROUP = 22, /* Apply group. */ + OFPAT_SET_NW_TTL = 23, /* IP TTL. */ + OFPAT_DEC_NW_TTL = 24, /* Decrement IP TTL. */ + OFPAT_SET_FIELD = 25, /* Set a header field using OXM TLV format. */ + OFPAT_PUSH_PBB = 26, /* Push a new PBB service tag (I-TAG) */ + OFPAT_POP_PBB = 27, /* Pop the outer PBB service tag (I-TAG) */ OFPAT_EXPERIMENTER = 0xffff }; - - -/* Action structure for OFPAT_OUTPUT, which sends packets out ’port’. -* When the ’port’ is the OFPP_CONTROLLER, ’max_len’ indicates the max -* number of bytes to send. A ’max_len’ of zero means no bytes of the -* packet should be sent. A ’max_len’ of OFPCML_NO_BUFFER means that -* the packet is not buffered and the complete packet is to be sent to -* the controller. */ -struct ofp_action_output { - uint16_t type; /* OFPAT_OUTPUT. */ - uint16_t len; /* Length is 16. */ - uint32_t port; /* Output port. */ - uint16_t max_len; /* Max length to send to controller. */ - uint8_t pad[6]; /* Pad to 64 bits. */ +/* Action header that is common to all actions. The length includes the + * header and any padding used to make the action 64-bit aligned. + * NB: The length of an action *must* always be a multiple of eight. */ +struct ofp_action_header { + uint16_t type; /* One of OFPAT_*. */ + uint16_t len; /* Length of action, including this + header. This is the length of action, + including any padding to make it + 64-bit aligned. */ + uint8_t pad[4]; }; -OFP_ASSERT(sizeof(struct ofp_action_output) == 16); +OFP_ASSERT(sizeof(struct ofp_action_header) == 8); enum ofp_controller_max_len { - OFPCML_MAX = 0xffe5, /* maximum max_len value which can be used - to request a specific byte length. */ - OFPCML_NO_BUFFER = 0xffff /* indicates that no buffering should be - applied and the whole packet is to be - sent to the controller. */ -}; - -/* Action structure for OFPAT_GROUP. */ -struct ofp_action_group { - uint16_t type; /* OFPAT_GROUP. */ - uint16_t len; /* Length is 8. */ - uint32_t group_id; /* Group identifier. */ -}; -OFP_ASSERT(sizeof(struct ofp_action_group) == 8); - -/* OFPAT_SET_QUEUE action struct: send packets to given queue on port. */ -struct ofp_action_set_queue { - uint16_t type; /* OFPAT_SET_QUEUE. */ - uint16_t len; /* Len is 8. */ - uint32_t queue_id; /* Queue id for the packets. */ + OFPCML_MAX = 0xffe5, /* maximum max_len value which can be used + to request a specific byte length. */ + OFPCML_NO_BUFFER = 0xffff /* indicates that no buffering should be + applied and the whole packet is to be + sent to the controller. */ +}; + +/* Action structure for OFPAT_OUTPUT, which sends packets out 'port'. + * When the 'port' is the OFPP_CONTROLLER, 'max_len' indicates the max + * number of bytes to send. A 'max_len' of zero means no bytes of the + * packet should be sent. A 'max_len' of OFPCML_NO_BUFFER means that + * the packet is not buffered and the complete packet is to be sent to + * the controller. */ +struct ofp_action_output { + uint16_t type; /* OFPAT_OUTPUT. */ + uint16_t len; /* Length is 16. */ + uint32_t port; /* Output port. */ + uint16_t max_len; /* Max length to send to controller. */ + uint8_t pad[6]; /* Pad to 64 bits. */ }; -OFP_ASSERT(sizeof(struct ofp_action_set_queue) == 8); +OFP_ASSERT(sizeof(struct ofp_action_output) == 16); /* Action structure for OFPAT_SET_MPLS_TTL. */ struct ofp_action_mpls_ttl { - uint16_t type; /* OFPAT_SET_MPLS_TTL. */ - uint16_t len; /* Length is 8. */ - uint8_t mpls_ttl; /* MPLS TTL */ - uint8_t pad[3]; + uint16_t type; /* OFPAT_SET_MPLS_TTL. */ + uint16_t len; /* Length is 8. */ + uint8_t mpls_ttl; /* MPLS TTL */ + uint8_t pad[3]; }; OFP_ASSERT(sizeof(struct ofp_action_mpls_ttl) == 8); -/* Action structure for OFPAT_SET_NW_TTL. */ -struct ofp_action_nw_ttl { - uint16_t type; /* OFPAT_SET_NW_TTL. */ - uint16_t len; /* Length is 8. */ - uint8_t nw_ttl; /* IP TTL */ - uint8_t pad[3]; -}; -OFP_ASSERT(sizeof(struct ofp_action_nw_ttl) == 8); - /* Action structure for OFPAT_PUSH_VLAN/MPLS/PBB. */ struct ofp_action_push { - uint16_t type; /* OFPAT_PUSH_VLAN/MPLS/PBB. */ - uint16_t len; /* Length is 8. */ - uint16_t ethertype; /* Ethertype */ - uint8_t pad[2]; + uint16_t type; /* OFPAT_PUSH_VLAN/MPLS/PBB. */ + uint16_t len; /* Length is 8. */ + uint16_t ethertype; /* Ethertype */ + uint8_t pad[2]; }; OFP_ASSERT(sizeof(struct ofp_action_push) == 8); /* Action structure for OFPAT_POP_MPLS. */ struct ofp_action_pop_mpls { - uint16_t type; /* OFPAT_POP_MPLS. */ - uint16_t len; /* Length is 8. */ - uint16_t ethertype; /* Ethertype */ - uint8_t pad[2]; + uint16_t type; /* OFPAT_POP_MPLS. */ + uint16_t len; /* Length is 8. */ + uint16_t ethertype; /* Ethertype */ + uint8_t pad[2]; }; OFP_ASSERT(sizeof(struct ofp_action_pop_mpls) == 8); +/* Action structure for OFPAT_GROUP. */ +struct ofp_action_group { + uint16_t type; /* OFPAT_GROUP. */ + uint16_t len; /* Length is 8. */ + uint32_t group_id; /* Group identifier. */ +}; +OFP_ASSERT(sizeof(struct ofp_action_group) == 8); + +/* Action structure for OFPAT_SET_NW_TTL. */ +struct ofp_action_nw_ttl { + uint16_t type; /* OFPAT_SET_NW_TTL. */ + uint16_t len; /* Length is 8. */ + uint8_t nw_ttl; /* IP TTL */ + uint8_t pad[3]; +}; +OFP_ASSERT(sizeof(struct ofp_action_nw_ttl) == 8); + /* Action structure for OFPAT_SET_FIELD. */ struct ofp_action_set_field { - uint16_t type; /* OFPAT_SET_FIELD. */ - uint16_t len; /* Length is padded to 64 bits. */ - /* Followed by: - * -Exactly oxm_len bytes containing a single OXM TLV,then - * -Exactly((oxm_len + 4) + 7)/8*8 - (oxm_len +4)(between 0 and 7) - * bytes of all - zerobytes - */ - uint8_t field[4]; /* OXM TLV - Make compiler happy */ + uint16_t type; /* OFPAT_SET_FIELD. */ + uint16_t len; /* Length is padded to 64 bits. */ + /* Followed by: + * - Exactly (4 + oxm_length) bytes containing a single OXM TLV, then + * - Exactly ((8 + oxm_length) + 7)/8*8 - (8 + oxm_length) + * (between 0 and 7) bytes of all-zero bytes + */ + uint8_t field[4]; /* OXM TLV - Make compiler happy */ }; OFP_ASSERT(sizeof(struct ofp_action_set_field) == 8); /* Action header for OFPAT_EXPERIMENTER. -* The rest of the body is experimenter-defined. */ + * The rest of the body is experimenter-defined. */ struct ofp_action_experimenter_header { - uint16_t type; /* OFPAT_EXPERIMENTER. */ - uint16_t len; /* Length is a multiple of 8. */ - uint32_t experimenter; /* Experimenter ID which takes the same - form as in struct - ofp_experimenter_header. */ + uint16_t type; /* OFPAT_EXPERIMENTER. */ + uint16_t len; /* Length is a multiple of 8. */ + uint32_t experimenter; /* Experimenter ID which takes the same + form as in struct + ofp_experimenter_header. */ }; OFP_ASSERT(sizeof(struct ofp_action_experimenter_header) == 8); +/* ## ---------------------- ## */ +/* ## OpenFlow Instructions. ## */ +/* ## ---------------------- ## */ -/*************Controller-to-Switch Messages******************/ +enum ofp_instruction_type { + OFPIT_GOTO_TABLE = 1, /* Setup the next table in the lookup + pipeline */ + OFPIT_WRITE_METADATA = 2, /* Setup the metadata field for use later in + pipeline */ + OFPIT_WRITE_ACTIONS = 3, /* Write the action(s) onto the datapath action + set */ + OFPIT_APPLY_ACTIONS = 4, /* Applies the action(s) immediately */ + OFPIT_CLEAR_ACTIONS = 5, /* Clears all actions from the datapath + action set */ + OFPIT_METER = 6, /* Apply meter (rate limiter) */ -/* Switch features. */ -struct ofp_switch_features { - struct ofp_header header; - uint64_t datapath_id; /* Datapath unique ID. The lower 48-bits are for - a MAC address, while the upper 16-bits are - implementer-defined. */ - uint32_t n_buffers; /* Max packets buffered at once. */ - uint8_t n_tables; /* Number of tables supported by datapath. */ - uint8_t auxiliary_id; /* Identify auxiliary connections. */ - uint8_t pad[2]; /* Align to 64-bits. */ - /* Features. */ - uint32_t capabilities; /* Bitmap of support "ofp_capabilities". */ - uint32_t reserved; + OFPIT_EXPERIMENTER = 0xFFFF /* Experimenter instruction */ }; -OFP_ASSERT(sizeof(struct ofp_switch_features) == 32); -/* Capabilities supported by the datapath. */ -enum ofp_capabilities { - OFPC_FLOW_STATS = 1 << 0, /* Flow statistics. */ - OFPC_TABLE_STATS = 1 << 1, /* Table statistics. */ - OFPC_PORT_STATS = 1 << 2, /* Port statistics. */ - OFPC_GROUP_STATS = 1 << 3, /* Group statistics. */ - OFPC_IP_REASM = 1 << 5, /* Can reassemble IP fragments. */ - OFPC_QUEUE_STATS = 1 << 6, /* Queue statistics. */ - OFPC_PORT_BLOCKED = 1 << 8 /* Switch will block looping ports. */ +/* Instruction header that is common to all instructions. The length includes + * the header and any padding used to make the instruction 64-bit aligned. + * NB: The length of an instruction *must* always be a multiple of eight. */ +struct ofp_instruction { + uint16_t type; /* Instruction type */ + uint16_t len; /* Length of this struct in bytes. */ }; +OFP_ASSERT(sizeof(struct ofp_instruction) == 4); -/* Switch configuration. */ -struct ofp_switch_config { - struct ofp_header header; - uint16_t flags; /* OFPC_* flags. */ - uint16_t miss_send_len; /* Max bytes of new flow that datapath - should send to the controller. See - ofp_controller_max_len for valid values.*/ +/* Instruction structure for OFPIT_GOTO_TABLE */ +struct ofp_instruction_goto_table { + uint16_t type; /* OFPIT_GOTO_TABLE */ + uint16_t len; /* Length of this struct in bytes. */ + uint8_t table_id; /* Set next table in the lookup pipeline */ + uint8_t pad[3]; /* Pad to 64 bits. */ }; -OFP_ASSERT(sizeof(struct ofp_switch_config) == 12); +OFP_ASSERT(sizeof(struct ofp_instruction_goto_table) == 8); -enum ofp_config_flags { - /* Handling of IP fragments. */ - OFPC_FRAG_NORMAL = 0, /* No special handling for fragments. */ - OFPC_FRAG_DROP = 1 << 0, /* Drop fragments. */ - OFPC_FRAG_REASM = 1 << 1, /* Reassemble (only if OFPC_IP_REASM set). */ - OFPC_FRAG_MASK = 3, - /* TTL processing - applicable for IP and MPLS packets */ - OFPC_INVALID_TTL_TO_CONTROLLER = 1 << 2, /* Send packets with invalid TTL -to the controller */ +/* Instruction structure for OFPIT_WRITE_METADATA */ +struct ofp_instruction_write_metadata { + uint16_t type; /* OFPIT_WRITE_METADATA */ + uint16_t len; /* Length of this struct in bytes. */ + uint8_t pad[4]; /* Align to 64-bits */ + uint64_t metadata; /* Metadata value to write */ + uint64_t metadata_mask; /* Metadata write bitmask */ }; +OFP_ASSERT(sizeof(struct ofp_instruction_write_metadata) == 24); -/* Table numbering. Tables can use any number up to OFPT_MAX. */ -enum ofp_table { - /* Last usable table number. */ - OFPTT_MAX = 0xfe, - /* Fake tables. */ - OFPTT_ALL = 0xff /* Wildcard table used for table config, - flow stats and flow deletes. */ +/* Instruction structure for OFPIT_WRITE/APPLY/CLEAR_ACTIONS */ +struct ofp_instruction_actions { + uint16_t type; /* One of OFPIT_*_ACTIONS */ + uint16_t len; /* Length of this struct in bytes. */ + uint8_t pad[4]; /* Align to 64-bits */ + struct ofp_action_header actions[0]; /* 0 or more actions associated with + OFPIT_WRITE_ACTIONS and + OFPIT_APPLY_ACTIONS */ }; +OFP_ASSERT(sizeof(struct ofp_instruction_actions) == 8); -/* Configure/Modify behavior of a flow table */ -struct ofp_table_mod { - struct ofp_header header; - uint8_t table_id; /* ID of the table, OFPTT_ALL indicates all tables */ - uint8_t pad[3]; /* Pad to 32 bits */ - uint32_t config; /* Bitmap of OFPTC_* flags */ +/* Instruction structure for OFPIT_METER */ +struct ofp_instruction_meter { + uint16_t type; /* OFPIT_METER */ + uint16_t len; /* Length is 8. */ + uint32_t meter_id; /* Meter instance. */ }; -OFP_ASSERT(sizeof(struct ofp_table_mod) == 16); +OFP_ASSERT(sizeof(struct ofp_instruction_meter) == 8); -enum ofp_table_config { - OFPTC_TABLE_MISS_CONTROLLER = 0, /* Send to controller. */ - OFPTC_TABLE_MISS_CONTINUE = 1 << 0, /* Continue to the next table in the - pipeline (OpenFlow 1.0 behavior). */ - OFPTC_TABLE_MISS_DROP = 1 << 1, /* Drop the packet. */ - OFPTC_TABLE_MISS_MASK = 3 +/* Instruction structure for experimental instructions */ +struct ofp_instruction_experimenter { + uint16_t type; /* OFPIT_EXPERIMENTER */ + uint16_t len; /* Length of this struct in bytes */ + uint32_t experimenter; /* Experimenter ID which takes the same form + as in struct ofp_experimenter_header. */ + /* Experimenter-defined arbitrary additional data. */ }; +OFP_ASSERT(sizeof(struct ofp_instruction_experimenter) == 8); -#define OFP_DEFAULT_PRIORITY 0x8000 -#define OFP_FLOW_PERMANENT 0 - -/* Flow setup and teardown (controller -> datapath). */ -struct ofp_flow_mod { - struct ofp_header header; - uint64_t cookie; /* Opaque controller-issued identifier. */ - uint64_t cookie_mask; /* Mask used to restrict the cookie bits - that must match when the command is - OFPFC_MODIFY* or OFPFC_DELETE*. A value - of 0 indicates no restriction. */ - /* Flow actions. */ - uint8_t table_id; /* ID of the table to put the flow in. - For OFPFC_DELETE_* commands, OFPTT_ALL - can also be used to delete matching - flows from all tables. */ - uint8_t command; /* One of OFPFC_*. */ - uint16_t idle_timeout; /* Idle time before discarding (seconds). */ - uint16_t hard_timeout; /* Max time before discarding (seconds). */ - uint16_t priority; /* Priority level of flow entry. */ - uint32_t buffer_id; /* Buffered packet to apply to, or - OFP_NO_BUFFER. - Not meaningful for OFPFC_DELETE*. */ - uint32_t out_port; /* For OFPFC_DELETE* commands, require - matching entries to include this as an - output port. A value of OFPP_ANY - indicates no restriction. */ - uint32_t out_group; /* For OFPFC_DELETE* commands, require - matching entries to include this as an - output group. A value of OFPG_ANY - indicates no restriction. */ - uint16_t flags; /* One of OFPFF_*. */ - uint8_t pad[2]; - struct ofp_match match; /* Fields to match. Variable size. */ - //struct ofp_instruction instructions[0]; /* Instruction set */ -}; -OFP_ASSERT(sizeof(struct ofp_flow_mod) == 56); +/* ## --------------------------- ## */ +/* ## OpenFlow Flow Modification. ## */ +/* ## --------------------------- ## */ enum ofp_flow_mod_command { - OFPFC_ADD = 0, /* New flow. */ - OFPFC_MODIFY = 1, /* Modify all matching flows. */ + OFPFC_ADD = 0, /* New flow. */ + OFPFC_MODIFY = 1, /* Modify all matching flows. */ OFPFC_MODIFY_STRICT = 2, /* Modify entry strictly matching wildcards and priority. */ - OFPFC_DELETE = 3, /* Delete all matching flows. */ + OFPFC_DELETE = 3, /* Delete all matching flows. */ OFPFC_DELETE_STRICT = 4, /* Delete entry strictly matching wildcards and priority. */ }; +/* Value used in "idle_timeout" and "hard_timeout" to indicate that the entry + * is permanent. */ +#define OFP_FLOW_PERMANENT 0 + +/* By default, choose a priority in the middle. */ +#define OFP_DEFAULT_PRIORITY 0x8000 + enum ofp_flow_mod_flags { - OFPFF_SEND_FLOW_REM = 1 << 0, /* Send flow removed message when flow - * expires or is deleted. */ - OFPFF_CHECK_OVERLAP = 1 << 1, /* Check for overlapping entries first. */ - OFPFF_RESET_COUNTS = 1 << 2, /* Reset flow packet and byte counts. */ - OFPFF_NO_PKT_COUNTS = 1 << 3, /* Don’t keep track of packet count. */ - OFPFF_NO_BYT_COUNTS = 1 << 4 /*Don’t keep track of byte count. */ + OFPFF_SEND_FLOW_REM = 1 << 0, /* Send flow removed message when flow + * expires or is deleted. */ + OFPFF_CHECK_OVERLAP = 1 << 1, /* Check for overlapping entries first. */ + OFPFF_RESET_COUNTS = 1 << 2, /* Reset flow packet and byte counts. */ + OFPFF_NO_PKT_COUNTS = 1 << 3, /* Don't keep track of packet count. */ + OFPFF_NO_BYT_COUNTS = 1 << 4, /* Don't keep track of byte count. */ }; +/* Flow setup and teardown (controller -> datapath). */ +struct ofp_flow_mod { + struct ofp_header header; + uint64_t cookie; /* Opaque controller-issued identifier. */ + uint64_t cookie_mask; /* Mask used to restrict the cookie bits + that must match when the command is + OFPFC_MODIFY* or OFPFC_DELETE*. A value + of 0 indicates no restriction. */ + uint8_t table_id; /* ID of the table to put the flow in. + For OFPFC_DELETE_* commands, OFPTT_ALL + can also be used to delete matching + flows from all tables. */ + uint8_t command; /* One of OFPFC_*. */ + uint16_t idle_timeout; /* Idle time before discarding (seconds). */ + uint16_t hard_timeout; /* Max time before discarding (seconds). */ + uint16_t priority; /* Priority level of flow entry. */ + uint32_t buffer_id; /* Buffered packet to apply to, or + OFP_NO_BUFFER. + Not meaningful for OFPFC_DELETE*. */ + uint32_t out_port; /* For OFPFC_DELETE* commands, require + matching entries to include this as an + output port. A value of OFPP_ANY + indicates no restriction. */ + uint32_t out_group; /* For OFPFC_DELETE* commands, require + matching entries to include this as an + output group. A value of OFPG_ANY + indicates no restriction. */ + uint16_t flags; /* Bitmap of OFPFF_* flags. */ + uint8_t pad[2]; + struct ofp_match match; /* Fields to match. Variable size. */ + /* The variable size and padded match is always followed by instructions. */ + /*struct ofp_instruction instructions[0];*/ /* Instruction set - 0 or more. + The length of the instruction + set is inferred from the + length field in the header. */ +}; +OFP_ASSERT(sizeof(struct ofp_flow_mod) == 56); + /* Group numbering. Groups can use any number up to OFPG_MAX. */ enum ofp_group { /* Last usable group number. */ @@ -698,1056 +1203,1135 @@ enum ofp_group { /* Fake groups. */ OFPG_ALL = 0xfffffffc, /* Represents all groups for group delete commands. */ - OFPG_ANY = 0xffffffff /* Wildcard group used only for flow stats - requests. Selects all flows regardless of - group (including flows with no group).*/ + OFPG_ANY = 0xffffffff /* Special wildcard: no group specified. */ +}; + +/* Group commands */ +enum ofp_group_mod_command { + OFPGC_ADD = 0, /* New group. */ + OFPGC_MODIFY = 1, /* Modify all matching groups. */ + OFPGC_DELETE = 2, /* Delete all matching groups. */ }; /* Bucket for use in groups. */ struct ofp_bucket { - uint16_t len; /* Length the bucket in bytes, including - this header and any padding to make it - 64-bit aligned. */ - uint16_t weight; /* Relative weight of bucket. Only - defined for select groups. */ - uint32_t watch_port; /* Port whose state affects whether this - bucket is live. Only required for fast - failover groups. */ - uint32_t watch_group; /* Group whose state affects whether this - bucket is live. Only required for fast - failover groups. */ - uint8_t pad[4]; - struct ofp_action_header actions[0]; /* The action length is inferred - from the length field in the - header. */ + uint16_t len; /* Length of the bucket in bytes, including + this header and any padding to make it + 64-bit aligned. */ + uint16_t weight; /* Relative weight of bucket. Only + defined for select groups. */ + uint32_t watch_port; /* Port whose state affects whether this + bucket is live. Only required for fast + failover groups. */ + uint32_t watch_group; /* Group whose state affects whether this + bucket is live. Only required for fast + failover groups. */ + uint8_t pad[4]; + struct ofp_action_header actions[0]; /* 0 or more actions associated with + the bucket - The action list length + is inferred from the length + of the bucket. */ }; OFP_ASSERT(sizeof(struct ofp_bucket) == 16); /* Group setup and teardown (controller -> datapath). */ struct ofp_group_mod { - struct ofp_header header; - uint16_t command; /* One of OFPGC_*. */ - uint8_t type; /* One of OFPGT_*. */ - uint8_t pad; /* Pad to 64 bits. */ - uint32_t group_id; /* Group identifier. */ - struct ofp_bucket buckets[0]; /* The length of the bucket array is inferred + struct ofp_header header; + uint16_t command; /* One of OFPGC_*. */ + uint8_t type; /* One of OFPGT_*. */ + uint8_t pad; /* Pad to 64 bits. */ + uint32_t group_id; /* Group identifier. */ + struct ofp_bucket buckets[0]; /* The length of the bucket array is inferred from the length field in the header. */ }; OFP_ASSERT(sizeof(struct ofp_group_mod) == 16); -/* Group commands */ -enum ofp_group_mod_command { - OFPGC_ADD = 0, /* New group. */ - OFPGC_MODIFY = 1, /* Modify all matching groups. */ - OFPGC_DELETE = 2, /* Delete all matching groups. */ -}; - -/* Group types. Values in the range [128, 255] are reserved for experimental -* use. */ +/* Group types. Values in the range [128, 255] are reserved for experimental + * use. */ enum ofp_group_type { - OFPGT_ALL = 0, /* All (multicast/broadcast) group. */ - OFPGT_SELECT = 1, /* Select group. */ + OFPGT_ALL = 0, /* All (multicast/broadcast) group. */ + OFPGT_SELECT = 1, /* Select group. */ OFPGT_INDIRECT = 2, /* Indirect group. */ - OFPGT_FF = 3, /* Fast failover group. */ + OFPGT_FF = 3, /* Fast failover group. */ }; +/* Special buffer-id to indicate 'no buffer' */ +#define OFP_NO_BUFFER 0xffffffff -/* Modify behavior of the physical port */ -struct ofp_port_mod { - struct ofp_header header; - uint32_t port_no; - uint8_t pad[4]; - uint8_t hw_addr[OFP_ETH_ALEN]; /* The hardware address is not - configurable. This is used to - sanity-check the request, so it must - be the same as returned in an - ofp_port struct. */ - uint8_t pad2[2]; /* Pad to 64 bits. */ - uint32_t config; /* Bitmap of OFPPC_* flags. */ - uint32_t mask; /* Bitmap of OFPPC_* flags to be changed. */ - uint32_t advertise; /* Bitmap of OFPPF_*. Zero all bits to prevent - any action taking place. */ - uint8_t pad3[4]; /* Pad to 64 bits. */ +/* Send packet (controller -> datapath). */ +struct ofp_packet_out { + struct ofp_header header; + uint32_t buffer_id; /* ID assigned by datapath (OFP_NO_BUFFER + if none). */ + uint32_t in_port; /* Packet's input port or OFPP_CONTROLLER. */ + uint16_t actions_len; /* Size of action array in bytes. */ + uint8_t pad[6]; + struct ofp_action_header actions[0]; /* Action list - 0 or more. */ + /* The variable size action list is optionally followed by packet data. + * This data is only present and meaningful if buffer_id == -1. + * uint8_t data[0]; Packet data. The length is inferred + from the length field in the header. */ }; -OFP_ASSERT(sizeof(struct ofp_port_mod) == 40); +OFP_ASSERT(sizeof(struct ofp_packet_out) == 24); -/* Common header for all meter bands */ -struct ofp_meter_band_header { - uint16_t type; /* One of OFPMBT_*. */ - uint16_t len; /* Length in bytes of this band. */ - uint32_t rate; /* Rate for this band. */ - uint32_t burst_size; /* Size of bursts. */ +/* Why is this packet being sent to the controller? */ +enum ofp_packet_in_reason { + OFPR_NO_MATCH = 0, /* No matching flow (table-miss flow entry). */ + OFPR_ACTION = 1, /* Action explicitly output to controller. */ + OFPR_INVALID_TTL = 2, /* Packet has invalid TTL */ }; -OFP_ASSERT(sizeof(struct ofp_meter_band_header) == 12); -/* Meter configuration. OFPT_METER_MOD. */ -struct ofp_meter_mod { +/* Packet received on port (datapath -> controller). */ +struct ofp_packet_in { struct ofp_header header; - uint16_t command; /* One of OFPMC_*. */ - uint16_t flags; /* One of OFPMF_*. */ - uint32_t meter_id; /* Meter instance. */ - struct ofp_meter_band_header bands[0]; /* The bands length is - inferred from the length field - in the header. */ + uint32_t buffer_id; /* ID assigned by datapath. */ + uint16_t total_len; /* Full length of frame. */ + uint8_t reason; /* Reason packet is being sent (one of OFPR_*) */ + uint8_t table_id; /* ID of the table that was looked up */ + uint64_t cookie; /* Cookie of the flow entry that was looked up. */ + struct ofp_match match; /* Packet metadata. Variable size. */ + /* The variable size and padded match is always followed by: + * - Exactly 2 all-zero padding bytes, then + * - An Ethernet frame whose length is inferred from header.length. + * The padding bytes preceding the Ethernet frame ensure that the IP + * header (if any) following the Ethernet header is 32-bit aligned. + */ + //uint8_t pad[2]; /* Align to 64 bit + 16 bit */ + //uint8_t data[0]; /* Ethernet frame */ }; -OFP_ASSERT(sizeof(struct ofp_meter_mod) == 16); +OFP_ASSERT(sizeof(struct ofp_packet_in) == 32); -/* Meter numbering. Flow meters can use any number up to OFPM_MAX. */ -enum ofp_meter { - /* Last usable meter. */ - OFPM_MAX = 0xffff0000, - /* Virtual meters. */ - OFPM_SLOWPATH = 0xfffffffd, - OFPM_CONTROLLER = 0xfffffffe, - OFPM_ALL = 0xffffffff, /* Meter for slow datapath, if any. */ - /* Meter for controller connection. */ - /* Represents all meters for stat requests - commands. */ +/* Why was this flow removed? */ +enum ofp_flow_removed_reason { + OFPRR_IDLE_TIMEOUT = 0, /* Flow idle time exceeded idle_timeout. */ + OFPRR_HARD_TIMEOUT = 1, /* Time exceeded hard_timeout. */ + OFPRR_DELETE = 2, /* Evicted by a DELETE flow mod. */ + OFPRR_GROUP_DELETE = 3, /* Group was removed. */ + OFPRR_METER_DELETE = 4, /* Meter was removed */ }; -/* Meter commands */ -enum ofp_meter_mod_command { - OFPMC_ADD, /* New meter. */ - OFPMC_MODIFY, /* Modify specified meter. */ - OFPMC_DELETE, /* Delete specified meter. */ -}; +/* Flow removed (datapath -> controller). */ +struct ofp_flow_removed { + struct ofp_header header; + uint64_t cookie; /* Opaque controller-issued identifier. */ -/* Meter configuration flags */ -enum ofp_meter_flags { - OFPMF_KBPS = 1 << 0, /* Rate value in kb/s (kilo-bit per second). */ - OFPMF_PKTPS = 1 << 1, /* Rate value in packet/sec. */ - OFPMF_BURST = 1 << 2, /* Do burst size. */ - OFPMF_STATS = 1 << 3, /* Collect statistics. */ + uint16_t priority; /* Priority level of flow entry. */ + uint8_t reason; /* One of OFPRR_*. */ + uint8_t table_id; /* ID of the table */ + + uint32_t duration_sec; /* Time flow was alive in seconds. */ + uint32_t duration_nsec; /* Time flow was alive in nanoseconds beyond + duration_sec. */ + uint16_t idle_timeout; /* Idle timeout from original flow mod. */ + uint16_t hard_timeout; /* Hard timeout from original flow mod. */ + uint64_t packet_count; + uint64_t byte_count; + struct ofp_match match; /* Description of fields. Variable size. */ }; +OFP_ASSERT(sizeof(struct ofp_flow_removed) == 56); +/* Meter numbering. Flow meters can use any number up to OFPM_MAX. */ +enum ofp_meter { + /* Last usable meter. */ + OFPM_MAX = 0xffff0000, + + /* Virtual meters. */ + OFPM_SLOWPATH = 0xfffffffd, /* Meter for slow datapath. */ + OFPM_CONTROLLER = 0xfffffffe, /* Meter for controller connection. */ + OFPM_ALL = 0xffffffff, /* Represents all meters for stat requests + commands. */ +}; /* Meter band types */ enum ofp_meter_band_type { - OFPMBT_DROP = 1, /* Drop packet. */ - OFPMBT_DSCP_REMARK = 2, /* Remark DSCP in the IP header. */ - OFPMBT_EXPERIMENTER = 0xFFFF /* Experimenter meter band. */ + OFPMBT_DROP = 1, /* Drop packet. */ + OFPMBT_DSCP_REMARK = 2, /* Remark DSCP in the IP header. */ + OFPMBT_EXPERIMENTER = 0xFFFF /* Experimenter meter band. */ }; +/* Common header for all meter bands */ +struct ofp_meter_band_header { + uint16_t type; /* One of OFPMBT_*. */ + uint16_t len; /* Length in bytes of this band. */ + uint32_t rate; /* Rate for this band. */ + uint32_t burst_size; /* Size of bursts. */ +}; +OFP_ASSERT(sizeof(struct ofp_meter_band_header) == 12); + /* OFPMBT_DROP band - drop packets */ struct ofp_meter_band_drop { - uint16_t type; /* OFPMBT_DROP. */ - uint16_t len; /* Length in bytes of this band. */ - uint32_t rate; /* Rate for dropping packets. */ - uint32_t burst_size; /* Size of bursts. */ - uint8_t pad[4]; + uint16_t type; /* OFPMBT_DROP. */ + uint16_t len; /* Length in bytes of this band. */ + uint32_t rate; /* Rate for dropping packets. */ + uint32_t burst_size; /* Size of bursts. */ + uint8_t pad[4]; }; OFP_ASSERT(sizeof(struct ofp_meter_band_drop) == 16); /* OFPMBT_DSCP_REMARK band - Remark DSCP in the IP header */ struct ofp_meter_band_dscp_remark { - uint16_t type; /* OFPMBT_DSCP_REMARK. */ - uint16_t len; /* Length in bytes of this band. */ - uint32_t rate; /* Rate for remarking packets. */ - uint32_t burst_size; /* Size of bursts. */ - uint8_t prec_level; /* Number of precendence level to substract. */ - uint8_t pad[3]; + uint16_t type; /* OFPMBT_DSCP_REMARK. */ + uint16_t len; /* Length in bytes of this band. */ + uint32_t rate; /* Rate for remarking packets. */ + uint32_t burst_size; /* Size of bursts. */ + uint8_t prec_level; /* Number of drop precedence level to add. */ + uint8_t pad[3]; }; OFP_ASSERT(sizeof(struct ofp_meter_band_dscp_remark) == 16); -/* OFPMBT_EXPERIMENTER band - Write actions in action set */ +/* OFPMBT_EXPERIMENTER band - Experimenter type. + * The rest of the band is experimenter-defined. */ struct ofp_meter_band_experimenter { - uint16_t type; /* One of OFPMBT_*. */ - uint16_t len; /* Length in bytes of this band. */ - uint32_t rate; /* Rate for this band. */ - uint32_t burst_size; /* Size of bursts. */ - uint32_t experimenter; /* Experimenter ID which takes the same - form as in struct - ofp_experimenter_header. */ + uint16_t type; /* One of OFPMBT_*. */ + uint16_t len; /* Length in bytes of this band. */ + uint32_t rate; /* Rate for this band. */ + uint32_t burst_size; /* Size of bursts. */ + uint32_t experimenter; /* Experimenter ID which takes the same + form as in struct + ofp_experimenter_header. */ +}; +OFP_ASSERT(sizeof(struct ofp_meter_band_experimenter) == 16); + +/* Meter commands */ +enum ofp_meter_mod_command { + OFPMC_ADD, /* New meter. */ + OFPMC_MODIFY, /* Modify specified meter. */ + OFPMC_DELETE, /* Delete specified meter. */ +}; + +/* Meter configuration flags */ +enum ofp_meter_flags { + OFPMF_KBPS = 1 << 0, /* Rate value in kb/s (kilo-bit per second). */ + OFPMF_PKTPS = 1 << 1, /* Rate value in packet/sec. */ + OFPMF_BURST = 1 << 2, /* Do burst size. */ + OFPMF_STATS = 1 << 3, /* Collect statistics. */ +}; + +/* Meter configuration. OFPT_METER_MOD. */ +struct ofp_meter_mod { + struct ofp_header header; + uint16_t command; /* One of OFPMC_*. */ + uint16_t flags; /* Bitmap of OFPMF_* flags. */ + uint32_t meter_id; /* Meter instance. */ + struct ofp_meter_band_header bands[0]; /* The band list length is + inferred from the length field + in the header. */ +}; +OFP_ASSERT(sizeof(struct ofp_meter_mod) == 16); + +/* Values for 'type' in ofp_error_message. These values are immutable: they + * will not change in future versions of the protocol (although new values may + * be added). */ +enum ofp_error_type { + OFPET_HELLO_FAILED = 0, /* Hello protocol failed. */ + OFPET_BAD_REQUEST = 1, /* Request was not understood. */ + OFPET_BAD_ACTION = 2, /* Error in action description. */ + OFPET_BAD_INSTRUCTION = 3, /* Error in instruction list. */ + OFPET_BAD_MATCH = 4, /* Error in match. */ + OFPET_FLOW_MOD_FAILED = 5, /* Problem modifying flow entry. */ + OFPET_GROUP_MOD_FAILED = 6, /* Problem modifying group entry. */ + OFPET_PORT_MOD_FAILED = 7, /* Port mod request failed. */ + OFPET_TABLE_MOD_FAILED = 8, /* Table mod request failed. */ + OFPET_QUEUE_OP_FAILED = 9, /* Queue operation failed. */ + OFPET_SWITCH_CONFIG_FAILED = 10, /* Switch config request failed. */ + OFPET_ROLE_REQUEST_FAILED = 11, /* Controller Role request failed. */ + OFPET_METER_MOD_FAILED = 12, /* Error in meter. */ + OFPET_TABLE_FEATURES_FAILED = 13, /* Setting table features failed. */ + OFPET_EXPERIMENTER = 0xffff /* Experimenter error messages. */ +}; + +/* ofp_error_msg 'code' values for OFPET_HELLO_FAILED. 'data' contains an + * ASCII text string that may give failure details. */ +enum ofp_hello_failed_code { + OFPHFC_INCOMPATIBLE = 0, /* No compatible version. */ + OFPHFC_EPERM = 1, /* Permissions error. */ +}; + +/* ofp_error_msg 'code' values for OFPET_BAD_REQUEST. 'data' contains at least + * the first 64 bytes of the failed request. */ +enum ofp_bad_request_code { + OFPBRC_BAD_VERSION = 0, /* ofp_header.version not supported. */ + OFPBRC_BAD_TYPE = 1, /* ofp_header.type not supported. */ + OFPBRC_BAD_MULTIPART = 2, /* ofp_multipart_request.type not supported. */ + OFPBRC_BAD_EXPERIMENTER = 3, /* Experimenter id not supported + * (in ofp_experimenter_header or + * ofp_multipart_request or + * ofp_multipart_reply). */ + OFPBRC_BAD_EXP_TYPE = 4, /* Experimenter type not supported. */ + OFPBRC_EPERM = 5, /* Permissions error. */ + OFPBRC_BAD_LEN = 6, /* Wrong request length for type. */ + OFPBRC_BUFFER_EMPTY = 7, /* Specified buffer has already been used. */ + OFPBRC_BUFFER_UNKNOWN = 8, /* Specified buffer does not exist. */ + OFPBRC_BAD_TABLE_ID = 9, /* Specified table-id invalid or does not + * exist. */ + OFPBRC_IS_SLAVE = 10, /* Denied because controller is slave. */ + OFPBRC_BAD_PORT = 11, /* Invalid port. */ + OFPBRC_BAD_PACKET = 12, /* Invalid packet in packet-out. */ + OFPBRC_MULTIPART_BUFFER_OVERFLOW = 13, /* ofp_multipart_request + overflowed the assigned buffer. */ +}; + +/* ofp_error_msg 'code' values for OFPET_BAD_ACTION. 'data' contains at least + * the first 64 bytes of the failed request. */ +enum ofp_bad_action_code { + OFPBAC_BAD_TYPE = 0, /* Unknown or unsupported action type. */ + OFPBAC_BAD_LEN = 1, /* Length problem in actions. */ + OFPBAC_BAD_EXPERIMENTER = 2, /* Unknown experimenter id specified. */ + OFPBAC_BAD_EXP_TYPE = 3, /* Unknown action for experimenter id. */ + OFPBAC_BAD_OUT_PORT = 4, /* Problem validating output port. */ + OFPBAC_BAD_ARGUMENT = 5, /* Bad action argument. */ + OFPBAC_EPERM = 6, /* Permissions error. */ + OFPBAC_TOO_MANY = 7, /* Can't handle this many actions. */ + OFPBAC_BAD_QUEUE = 8, /* Problem validating output queue. */ + OFPBAC_BAD_OUT_GROUP = 9, /* Invalid group id in forward action. */ + OFPBAC_MATCH_INCONSISTENT = 10, /* Action can't apply for this match, + or Set-Field missing prerequisite. */ + OFPBAC_UNSUPPORTED_ORDER = 11, /* Action order is unsupported for the + action list in an Apply-Actions instruction */ + OFPBAC_BAD_TAG = 12, /* Actions uses an unsupported + tag/encap. */ + OFPBAC_BAD_SET_TYPE = 13, /* Unsupported type in SET_FIELD action. */ + OFPBAC_BAD_SET_LEN = 14, /* Length problem in SET_FIELD action. */ + OFPBAC_BAD_SET_ARGUMENT = 15, /* Bad argument in SET_FIELD action. */ +}; + +/* ofp_error_msg 'code' values for OFPET_BAD_INSTRUCTION. 'data' contains at least + * the first 64 bytes of the failed request. */ +enum ofp_bad_instruction_code { + OFPBIC_UNKNOWN_INST = 0, /* Unknown instruction. */ + OFPBIC_UNSUP_INST = 1, /* Switch or table does not support the + instruction. */ + OFPBIC_BAD_TABLE_ID = 2, /* Invalid Table-ID specified. */ + OFPBIC_UNSUP_METADATA = 3, /* Metadata value unsupported by datapath. */ + OFPBIC_UNSUP_METADATA_MASK = 4, /* Metadata mask value unsupported by + datapath. */ + OFPBIC_BAD_EXPERIMENTER = 5, /* Unknown experimenter id specified. */ + OFPBIC_BAD_EXP_TYPE = 6, /* Unknown instruction for experimenter id. */ + OFPBIC_BAD_LEN = 7, /* Length problem in instructions. */ + OFPBIC_EPERM = 8, /* Permissions error. */ +}; + +/* ofp_error_msg 'code' values for OFPET_BAD_MATCH. 'data' contains at least + * the first 64 bytes of the failed request. */ +enum ofp_bad_match_code { + OFPBMC_BAD_TYPE = 0, /* Unsupported match type specified by the + match */ + OFPBMC_BAD_LEN = 1, /* Length problem in match. */ + OFPBMC_BAD_TAG = 2, /* Match uses an unsupported tag/encap. */ + OFPBMC_BAD_DL_ADDR_MASK = 3, /* Unsupported datalink addr mask - switch + does not support arbitrary datalink + address mask. */ + OFPBMC_BAD_NW_ADDR_MASK = 4, /* Unsupported network addr mask - switch + does not support arbitrary network + address mask. */ + OFPBMC_BAD_WILDCARDS = 5, /* Unsupported combination of fields masked + or omitted in the match. */ + OFPBMC_BAD_FIELD = 6, /* Unsupported field type in the match. */ + OFPBMC_BAD_VALUE = 7, /* Unsupported value in a match field. */ + OFPBMC_BAD_MASK = 8, /* Unsupported mask specified in the match, + field is not dl-address or nw-address. */ + OFPBMC_BAD_PREREQ = 9, /* A prerequisite was not met. */ + OFPBMC_DUP_FIELD = 10, /* A field type was duplicated. */ + OFPBMC_EPERM = 11, /* Permissions error. */ +}; + +/* ofp_error_msg 'code' values for OFPET_FLOW_MOD_FAILED. 'data' contains + * at least the first 64 bytes of the failed request. */ +enum ofp_flow_mod_failed_code { + OFPFMFC_UNKNOWN = 0, /* Unspecified error. */ + OFPFMFC_TABLE_FULL = 1, /* Flow not added because table was full. */ + OFPFMFC_BAD_TABLE_ID = 2, /* Table does not exist */ + OFPFMFC_OVERLAP = 3, /* Attempted to add overlapping flow with + CHECK_OVERLAP flag set. */ + OFPFMFC_EPERM = 4, /* Permissions error. */ + OFPFMFC_BAD_TIMEOUT = 5, /* Flow not added because of unsupported + idle/hard timeout. */ + OFPFMFC_BAD_COMMAND = 6, /* Unsupported or unknown command. */ + OFPFMFC_BAD_FLAGS = 7, /* Unsupported or unknown flags. */ +}; + +/* ofp_error_msg 'code' values for OFPET_GROUP_MOD_FAILED. 'data' contains + * at least the first 64 bytes of the failed request. */ +enum ofp_group_mod_failed_code { + OFPGMFC_GROUP_EXISTS = 0, /* Group not added because a group ADD + attempted to replace an + already-present group. */ + OFPGMFC_INVALID_GROUP = 1, /* Group not added because Group + specified is invalid. */ + OFPGMFC_WEIGHT_UNSUPPORTED = 2, /* Switch does not support unequal load + sharing with select groups. */ + OFPGMFC_OUT_OF_GROUPS = 3, /* The group table is full. */ + OFPGMFC_OUT_OF_BUCKETS = 4, /* The maximum number of action buckets + for a group has been exceeded. */ + OFPGMFC_CHAINING_UNSUPPORTED = 5, /* Switch does not support groups that + forward to groups. */ + OFPGMFC_WATCH_UNSUPPORTED = 6, /* This group cannot watch the watch_port + or watch_group specified. */ + OFPGMFC_LOOP = 7, /* Group entry would cause a loop. */ + OFPGMFC_UNKNOWN_GROUP = 8, /* Group not modified because a group + MODIFY attempted to modify a + non-existent group. */ + OFPGMFC_CHAINED_GROUP = 9, /* Group not deleted because another + group is forwarding to it. */ + OFPGMFC_BAD_TYPE = 10, /* Unsupported or unknown group type. */ + OFPGMFC_BAD_COMMAND = 11, /* Unsupported or unknown command. */ + OFPGMFC_BAD_BUCKET = 12, /* Error in bucket. */ + OFPGMFC_BAD_WATCH = 13, /* Error in watch port/group. */ + OFPGMFC_EPERM = 14, /* Permissions error. */ +}; + +/* ofp_error_msg 'code' values for OFPET_PORT_MOD_FAILED. 'data' contains + * at least the first 64 bytes of the failed request. */ +enum ofp_port_mod_failed_code { + OFPPMFC_BAD_PORT = 0, /* Specified port number does not exist. */ + OFPPMFC_BAD_HW_ADDR = 1, /* Specified hardware address does not + * match the port number. */ + OFPPMFC_BAD_CONFIG = 2, /* Specified config is invalid. */ + OFPPMFC_BAD_ADVERTISE = 3, /* Specified advertise is invalid. */ + OFPPMFC_EPERM = 4, /* Permissions error. */ +}; + +/* ofp_error_msg 'code' values for OFPET_TABLE_MOD_FAILED. 'data' contains + * at least the first 64 bytes of the failed request. */ +enum ofp_table_mod_failed_code { + OFPTMFC_BAD_TABLE = 0, /* Specified table does not exist. */ + OFPTMFC_BAD_CONFIG = 1, /* Specified config is invalid. */ + OFPTMFC_EPERM = 2, /* Permissions error. */ +}; + +/* ofp_error msg 'code' values for OFPET_QUEUE_OP_FAILED. 'data' contains + * at least the first 64 bytes of the failed request */ +enum ofp_queue_op_failed_code { + OFPQOFC_BAD_PORT = 0, /* Invalid port (or port does not exist). */ + OFPQOFC_BAD_QUEUE = 1, /* Queue does not exist. */ + OFPQOFC_EPERM = 2, /* Permissions error. */ +}; + +/* ofp_error_msg 'code' values for OFPET_SWITCH_CONFIG_FAILED. 'data' contains + * at least the first 64 bytes of the failed request. */ +enum ofp_switch_config_failed_code { + OFPSCFC_BAD_FLAGS = 0, /* Specified flags is invalid. */ + OFPSCFC_BAD_LEN = 1, /* Specified len is invalid. */ + OFPSCFC_EPERM = 2, /* Permissions error. */ +}; + +/* ofp_error_msg 'code' values for OFPET_ROLE_REQUEST_FAILED. 'data' contains + * at least the first 64 bytes of the failed request. */ +enum ofp_role_request_failed_code { + OFPRRFC_STALE = 0, /* Stale Message: old generation_id. */ + OFPRRFC_UNSUP = 1, /* Controller role change unsupported. */ + OFPRRFC_BAD_ROLE = 2, /* Invalid role. */ +}; + +/* ofp_error_msg 'code' values for OFPET_METER_MOD_FAILED. 'data' contains + * at least the first 64 bytes of the failed request. */ +enum ofp_meter_mod_failed_code { + OFPMMFC_UNKNOWN = 0, /* Unspecified error. */ + OFPMMFC_METER_EXISTS = 1, /* Meter not added because a Meter ADD + * attempted to replace an existing Meter. */ + OFPMMFC_INVALID_METER = 2, /* Meter not added because Meter specified + * is invalid, + * or invalid meter in meter action. */ + OFPMMFC_UNKNOWN_METER = 3, /* Meter not modified because a Meter MODIFY + * attempted to modify a non-existent Meter, + * or bad meter in meter action. */ + OFPMMFC_BAD_COMMAND = 4, /* Unsupported or unknown command. */ + OFPMMFC_BAD_FLAGS = 5, /* Flag configuration unsupported. */ + OFPMMFC_BAD_RATE = 6, /* Rate unsupported. */ + OFPMMFC_BAD_BURST = 7, /* Burst size unsupported. */ + OFPMMFC_BAD_BAND = 8, /* Band unsupported. */ + OFPMMFC_BAD_BAND_VALUE = 9, /* Band value unsupported. */ + OFPMMFC_OUT_OF_METERS = 10, /* No more meters available. */ + OFPMMFC_OUT_OF_BANDS = 11, /* The maximum number of properties + * for a meter has been exceeded. */ }; -OFP_ASSERT(sizeof(struct ofp_meter_band_experimenter) == 16); - -struct ofp_multipart_request { - struct ofp_header header; - uint16_t type; /* One of the OFPMP_* constants. */ - uint16_t flags; /* OFPMP_REQ_* flags (none yet defined). */ - uint8_t pad[4]; - uint8_t body[0]; /* Body of the request. */ +/* ofp_error_msg 'code' values for OFPET_TABLE_FEATURES_FAILED. 'data' contains + * at least the first 64 bytes of the failed request. */ +enum ofp_table_features_failed_code { + OFPTFFC_BAD_TABLE = 0, /* Specified table does not exist. */ + OFPTFFC_BAD_METADATA = 1, /* Invalid metadata mask. */ + OFPTFFC_BAD_TYPE = 2, /* Unknown property type. */ + OFPTFFC_BAD_LEN = 3, /* Length problem in properties. */ + OFPTFFC_BAD_ARGUMENT = 4, /* Unsupported property value. */ + OFPTFFC_EPERM = 5, /* Permissions error. */ }; -OFP_ASSERT(sizeof(struct ofp_multipart_request) == 16); -enum ofp_multipart_request_flags { - OFPMPF_REQ_MORE = 1 << 0 /* More requests to follow. */ -}; +/* OFPT_ERROR: Error message (datapath -> controller). */ +struct ofp_error_msg { + struct ofp_header header; -enum ofp_multipart_reply_flags { - OFPMPF_REPLY_MORE = 1 << 0 /* More replies to follow. */ + uint16_t type; + uint16_t code; + uint8_t data[0]; /* Variable-length data. Interpreted based + on the type and code. No padding. */ }; +OFP_ASSERT(sizeof(struct ofp_error_msg) == 12); -struct ofp_multipart_reply { - struct ofp_header header; - uint16_t type; /* One of the OFPMP_* constants. */ - uint16_t flags; /* OFPMP_REPLY_* flags. */ - uint8_t pad[4]; - uint8_t body[0]; /* Body of the reply. */ +/* OFPET_EXPERIMENTER: Error message (datapath -> controller). */ +struct ofp_error_experimenter_msg { + struct ofp_header header; + + uint16_t type; /* OFPET_EXPERIMENTER. */ + uint16_t exp_type; /* Experimenter defined. */ + uint32_t experimenter; /* Experimenter ID which takes the same form + as in struct ofp_experimenter_header. */ + uint8_t data[0]; /* Variable-length data. Interpreted based + on the type and code. No padding. */ }; -OFP_ASSERT(sizeof(struct ofp_multipart_reply) == 16); +OFP_ASSERT(sizeof(struct ofp_error_experimenter_msg) == 16); -enum ofp_multipart_types { +enum ofp_multipart_type { /* Description of this OpenFlow switch. - * The request body is empty. - * The reply body is struct ofp_desc. */ + * The request body is empty. + * The reply body is struct ofp_desc. */ OFPMP_DESC = 0, + /* Individual flow statistics. - * The request body is struct ofp_flow_multipart_request. - * The reply body is an array of struct ofp_flow_stats. */ + * The request body is struct ofp_flow_stats_request. + * The reply body is an array of struct ofp_flow_stats. */ OFPMP_FLOW = 1, + /* Aggregate flow statistics. - * The request body is struct ofp_aggregate_stats_request. - * The reply body is struct ofp_aggregate_stats_reply. */ + * The request body is struct ofp_aggregate_stats_request. + * The reply body is struct ofp_aggregate_stats_reply. */ OFPMP_AGGREGATE = 2, + /* Flow table statistics. - * The request body is empty. - * The reply body is an array of struct ofp_table_stats. */ + * The request body is empty. + * The reply body is an array of struct ofp_table_stats. */ OFPMP_TABLE = 3, + /* Port statistics. - * The request body is struct ofp_port_stats_request. - * The reply body is an array of struct ofp_port_stats. */ + * The request body is struct ofp_port_stats_request. + * The reply body is an array of struct ofp_port_stats. */ OFPMP_PORT_STATS = 4, + /* Queue statistics for a port - * The request body is struct ofp_queue_stats_request. - * The reply body is an array of struct ofp_queue_stats */ + * The request body is struct ofp_queue_stats_request. + * The reply body is an array of struct ofp_queue_stats */ OFPMP_QUEUE = 5, + /* Group counter statistics. - * The request body is struct ofp_group_stats_request. - * The reply is an array of struct ofp_group_stats. */ + * The request body is struct ofp_group_stats_request. + * The reply is an array of struct ofp_group_stats. */ OFPMP_GROUP = 6, - /* Group description statistics. - * The request body is empty. - * The reply body is an array of struct ofp_group_desc_stats. */ + + /* Group description. + * The request body is empty. + * The reply body is an array of struct ofp_group_desc. */ OFPMP_GROUP_DESC = 7, + /* Group features. - * The request body is empty. - * The reply body is struct ofp_group_features_stats. */ + * The request body is empty. + * The reply body is struct ofp_group_features. */ OFPMP_GROUP_FEATURES = 8, + /* Meter statistics. * The request body is struct ofp_meter_multipart_requests. * The reply body is an array of struct ofp_meter_stats. */ OFPMP_METER = 9, + /* Meter configuration. - * The request body is struct ofp_meter_multipart_requests. - * The reply body is an array of struct ofp_meter_config. */ + * The request body is struct ofp_meter_multipart_requests. + * The reply body is an array of struct ofp_meter_config. */ OFPMP_METER_CONFIG = 10, + /* Meter features. - * The request body is empty. - * The reply body is struct ofp_meter_features. */ + * The request body is empty. + * The reply body is struct ofp_meter_features. */ OFPMP_METER_FEATURES = 11, + /* Table features. - * The request body is either empty or contains an array of - * struct ofp_table_features containing the controller’s - * desired view of the switch. If the switch is unable to - * set the specified view an error is returned. - * The reply body is an array of struct ofp_table_features. */ + * The request body is either empty or contains an array of + * struct ofp_table_features containing the controller's + * desired view of the switch. If the switch is unable to + * set the specified view an error is returned. + * The reply body is an array of struct ofp_table_features. */ OFPMP_TABLE_FEATURES = 12, + /* Port description. - * The request body is empty. - * The reply body is an array of struct ofp_port. */ + * The request body is empty. + * The reply body is an array of struct ofp_port. */ OFPMP_PORT_DESC = 13, + /* Experimenter extension. - * The request and reply bodies begin with - * struct ofp_experimenter_stats_header. - * The request and reply bodies are otherwise experimenter-defined. */ + * The request and reply bodies begin with + * struct ofp_experimenter_multipart_header. + * The request and reply bodies are otherwise experimenter-defined. */ OFPMP_EXPERIMENTER = 0xffff }; +/* Backward compatibility with 1.3.1 - avoid breaking the API. */ +#define ofp_multipart_types ofp_multipart_type + +enum ofp_multipart_request_flags { + OFPMPF_REQ_MORE = 1 << 0 /* More requests to follow. */ +}; + +struct ofp_multipart_request { + struct ofp_header header; + uint16_t type; /* One of the OFPMP_* constants. */ + uint16_t flags; /* OFPMPF_REQ_* flags. */ + uint8_t pad[4]; + uint8_t body[0]; /* Body of the request. 0 or more bytes. */ +}; +OFP_ASSERT(sizeof(struct ofp_multipart_request) == 16); + +enum ofp_multipart_reply_flags { + OFPMPF_REPLY_MORE = 1 << 0 /* More replies to follow. */ +}; + +struct ofp_multipart_reply { + struct ofp_header header; + uint16_t type; /* One of the OFPMP_* constants. */ + uint16_t flags; /* OFPMPF_REPLY_* flags. */ + uint8_t pad[4]; + uint8_t body[0]; /* Body of the reply. 0 or more bytes. */ +}; +OFP_ASSERT(sizeof(struct ofp_multipart_reply) == 16); + #define DESC_STR_LEN 256 #define SERIAL_NUM_LEN 32 -/* Body of reply to OFPMP_DESC request. Each entry is a NULL-terminated -* ASCII string. */ +/* Body of reply to OFPMP_DESC request. Each entry is a NULL-terminated + * ASCII string. */ struct ofp_desc { - char mfr_desc[DESC_STR_LEN]; /* Manufacturer description. */ - char hw_desc[DESC_STR_LEN]; /* Hardware description. */ - char sw_desc[DESC_STR_LEN]; /* Software description. */ - char serial_num[SERIAL_NUM_LEN]; /* Serial number. */ - char dp_desc[DESC_STR_LEN]; /* Human readable description of datapath. */ + char mfr_desc[DESC_STR_LEN]; /* Manufacturer description. */ + char hw_desc[DESC_STR_LEN]; /* Hardware description. */ + char sw_desc[DESC_STR_LEN]; /* Software description. */ + char serial_num[SERIAL_NUM_LEN]; /* Serial number. */ + char dp_desc[DESC_STR_LEN]; /* Human readable description of datapath. */ }; OFP_ASSERT(sizeof(struct ofp_desc) == 1056); /* Body for ofp_multipart_request of type OFPMP_FLOW. */ struct ofp_flow_stats_request { - uint8_t table_id; /* ID of table to read (from ofp_table_stats), - OFPTT_ALL for all tables. */ - uint8_t pad[3]; /* Align to 32 bits. */ - uint32_t out_port; /* Require matching entries to include this - as an output port. A value of OFPP_ANY - indicates no restriction. */ - uint32_t out_group; /* Require matching entries to include this - as an output group. A value of OFPG_ANY - indicates no restriction. */ - uint8_t pad2[4]; /* Align to 64 bits. */ - uint64_t cookie; /* Require matching entries to contain this - cookie value */ - uint64_t cookie_mask; /* Mask used to restrict the cookie bits that - must match. A value of 0 indicates - no restriction. */ - struct ofp_match match; /* Fields to match. Variable size. */ + uint8_t table_id; /* ID of table to read (from ofp_table_stats), + OFPTT_ALL for all tables. */ + uint8_t pad[3]; /* Align to 32 bits. */ + uint32_t out_port; /* Require matching entries to include this + as an output port. A value of OFPP_ANY + indicates no restriction. */ + uint32_t out_group; /* Require matching entries to include this + as an output group. A value of OFPG_ANY + indicates no restriction. */ + uint8_t pad2[4]; /* Align to 64 bits. */ + uint64_t cookie; /* Require matching entries to contain this + cookie value */ + uint64_t cookie_mask; /* Mask used to restrict the cookie bits that + must match. A value of 0 indicates + no restriction. */ + struct ofp_match match; /* Fields to match. Variable size. */ }; OFP_ASSERT(sizeof(struct ofp_flow_stats_request) == 40); /* Body of reply to OFPMP_FLOW request. */ struct ofp_flow_stats { - uint16_t length; /* Length of this entry. */ - uint8_t table_id; /* ID of table flow came from. */ - uint8_t pad; - uint32_t duration_sec; /* Time flow has been alive in seconds. */ - uint32_t duration_nsec; /* Time flow has been alive in nanoseconds beyond - duration_sec. */ - uint16_t priority; /* Priority of the entry. */ - uint16_t idle_timeout; /* Number of seconds idle before expiration. */ - uint16_t hard_timeout; /* Number of seconds before expiration. */ - uint8_t pad2[6]; /* Align to 64-bits. */ - uint64_t cookie; /* Opaque controller-issued identifier. */ - uint64_t packet_count; /* Number of packets in flow. */ - uint64_t byte_count; /* Number of bytes in flow. */ - struct ofp_match match; /* Description of fields. Variable size. */ - //struct ofp_instruction instructions[0]; /* Instruction set. */ + uint16_t length; /* Length of this entry. */ + uint8_t table_id; /* ID of table flow came from. */ + uint8_t pad; + uint32_t duration_sec; /* Time flow has been alive in seconds. */ + uint32_t duration_nsec; /* Time flow has been alive in nanoseconds beyond + duration_sec. */ + uint16_t priority; /* Priority of the entry. */ + uint16_t idle_timeout; /* Number of seconds idle before expiration. */ + uint16_t hard_timeout; /* Number of seconds before expiration. */ + uint16_t flags; /* Bitmap of OFPFF_* flags. */ + uint8_t pad2[4]; /* Align to 64-bits. */ + uint64_t cookie; /* Opaque controller-issued identifier. */ + uint64_t packet_count; /* Number of packets in flow. */ + uint64_t byte_count; /* Number of bytes in flow. */ + struct ofp_match match; /* Description of fields. Variable size. */ + /* The variable size and padded match is always followed by instructions. */ + //struct ofp_instruction instructions[0]; /* Instruction set - 0 or more. */ }; OFP_ASSERT(sizeof(struct ofp_flow_stats) == 56); /* Body for ofp_multipart_request of type OFPMP_AGGREGATE. */ struct ofp_aggregate_stats_request { - uint8_t table_id; /* ID of table to read (from ofp_table_stats) - OFPTT_ALL for all tables. */ - uint8_t pad[3]; /* Align to 32 bits. */ - uint32_t out_port; /* Require matching entries to include this - as an output port. A value of OFPP_ANY - indicates no restriction. */ - uint32_t out_group; /* Require matching entries to include this - as an output group. A value of OFPG_ANY - indicates no restriction. */ - uint8_t pad2[4]; /* Align to 64 bits. */ - uint64_t cookie; /* Require matching entries to contain this - cookie value */ - uint64_t cookie_mask; /* Mask used to restrict the cookie bits that - must match. A value of 0 indicates - no restriction. */ - struct ofp_match match; /* Fields to match. Variable size. */ + uint8_t table_id; /* ID of table to read (from ofp_table_stats) + OFPTT_ALL for all tables. */ + uint8_t pad[3]; /* Align to 32 bits. */ + uint32_t out_port; /* Require matching entries to include this + as an output port. A value of OFPP_ANY + indicates no restriction. */ + uint32_t out_group; /* Require matching entries to include this + as an output group. A value of OFPG_ANY + indicates no restriction. */ + uint8_t pad2[4]; /* Align to 64 bits. */ + uint64_t cookie; /* Require matching entries to contain this + cookie value */ + uint64_t cookie_mask; /* Mask used to restrict the cookie bits that + must match. A value of 0 indicates + no restriction. */ + struct ofp_match match; /* Fields to match. Variable size. */ }; OFP_ASSERT(sizeof(struct ofp_aggregate_stats_request) == 40); /* Body of reply to OFPMP_AGGREGATE request. */ struct ofp_aggregate_stats_reply { - uint64_t packet_count; /* Number of packets in flows. */ - uint64_t byte_count; /* Number of bytes in flows. */ - uint32_t flow_count; /* Number of flows. */ - uint8_t pad[4]; /* Align to 64 bits. */ + uint64_t packet_count; /* Number of packets in flows. */ + uint64_t byte_count; /* Number of bytes in flows. */ + uint32_t flow_count; /* Number of flows. */ + uint8_t pad[4]; /* Align to 64 bits. */ }; OFP_ASSERT(sizeof(struct ofp_aggregate_stats_reply) == 24); -/* Body of reply to OFPMP_TABLE request. */ -struct ofp_table_stats { - uint8_t table_id; /* Identifier of table. Lower numbered tables - are consulted first. */ - uint8_t pad[3]; /* Align to 32-bits. */ - uint32_t active_count; /* Number of active entries. */ - uint64_t lookup_count; /* Number of packets looked up in table. */ - uint64_t matched_count; /* Number of packets that hit table. */ -}; -OFP_ASSERT(sizeof(struct ofp_table_stats) == 24); - -struct ofp_table_feature_prop_header{ - uint16_t type; /* One of OFPTFPT_NEXT_TABLES, - OFPTFPT_NEXT_TABLES_MISS. */ - uint16_t length; /* Length in bytes of this property. */ -}; -OFP_ASSERT(sizeof(struct ofp_table_feature_prop_header) == 4); - -/* Body for ofp_multipart_request of type OFPMP_TABLE_FEATURES./ -* Body of reply to OFPMP_TABLE_FEATURES request. */ -struct ofp_table_features { - uint16_t length; /* Length is padded to 64 bits. */ - uint8_t table_id; /* Identifier of table. Lower numbered tables - are consulted first. */ - uint8_t pad[5]; /* Align to 64-bits. */ - char name[OFP_MAX_TABLE_NAME_LEN]; - uint64_t metadata_match; /* Bits of metadata table can match. */ - uint64_t metadata_write; /* Bits of metadata table can write. */ - uint32_t config; /* Bitmap of OFPTC_* values */ - uint32_t max_entries; /* Max number of entries supported. */ - /* Table Feature Property list */ - struct ofp_table_feature_prop_header properties[0]; -}; -OFP_ASSERT(sizeof(struct ofp_table_features) == 64); - /* Table Feature property types. -* Low order bit cleared indicates a property for a regular Flow Entry. -* Low order bit set indicates a property for the Table-Miss Flow Entry. -*/ + * Low order bit cleared indicates a property for a regular Flow Entry. + * Low order bit set indicates a property for the Table-Miss Flow Entry. + */ enum ofp_table_feature_prop_type { - OFPTFPT_INSTRUCTIONS = 0, /* Instructions property. */ - OFPTFPT_INSTRUCTIONS_MISS = 1, /* Instructions for table-miss. */ - OFPTFPT_NEXT_TABLES = 2, /* Next Table property. */ - OFPTFPT_NEXT_TABLES_MISS = 3, /* Next Table for table-miss. */ - OFPTFPT_WRITE_ACTIONS = 4, /* Write Actions property. */ - OFPTFPT_WRITE_ACTIONS_MISS = 5, /* Write Actions for table-miss. */ - OFPTFPT_APPLY_ACTIONS = 6, /* Apply Actions property. */ - OFPTFPT_APPLY_ACTIONS_MISS = 7, /* Apply Actions for table-miss. */ - OFPTFPT_MATCH = 8, /* Match property. */ - OFPTFPT_WILDCARDS = 10, /* Wildcards property. */ - OFPTFPT_WRITE_SETFIELD = 12, /* Write Set-Field property. */ - OFPTFPT_WRITE_SETFIELD_MISS = 13, /* Write Set-Field for table-miss. */ - OFPTFPT_APPLY_SETFIELD = 14, /* Apply Set-Field property. */ - OFPTFPT_APPLY_SETFIELD_MISS = 15, /* Apply Set-Field for table-miss. */ - OFPTFPT_EXPERIMENTER = 0xFFFE, /* Experimenter property. */ - OFPTFPT_EXPERIMENTER_MISS = 0xFFFF, /* Experimenter for table-miss. */ + OFPTFPT_INSTRUCTIONS = 0, /* Instructions property. */ + OFPTFPT_INSTRUCTIONS_MISS = 1, /* Instructions for table-miss. */ + OFPTFPT_NEXT_TABLES = 2, /* Next Table property. */ + OFPTFPT_NEXT_TABLES_MISS = 3, /* Next Table for table-miss. */ + OFPTFPT_WRITE_ACTIONS = 4, /* Write Actions property. */ + OFPTFPT_WRITE_ACTIONS_MISS = 5, /* Write Actions for table-miss. */ + OFPTFPT_APPLY_ACTIONS = 6, /* Apply Actions property. */ + OFPTFPT_APPLY_ACTIONS_MISS = 7, /* Apply Actions for table-miss. */ + OFPTFPT_MATCH = 8, /* Match property. */ + OFPTFPT_WILDCARDS = 10, /* Wildcards property. */ + OFPTFPT_WRITE_SETFIELD = 12, /* Write Set-Field property. */ + OFPTFPT_WRITE_SETFIELD_MISS = 13, /* Write Set-Field for table-miss. */ + OFPTFPT_APPLY_SETFIELD = 14, /* Apply Set-Field property. */ + OFPTFPT_APPLY_SETFIELD_MISS = 15, /* Apply Set-Field for table-miss. */ + OFPTFPT_EXPERIMENTER = 0xFFFE, /* Experimenter property. */ + OFPTFPT_EXPERIMENTER_MISS = 0xFFFF, /* Experimenter for table-miss. */ +}; + +/* Common header for all Table Feature Properties */ +struct ofp_table_feature_prop_header { + uint16_t type; /* One of OFPTFPT_*. */ + uint16_t length; /* Length in bytes of this property. */ }; +OFP_ASSERT(sizeof(struct ofp_table_feature_prop_header) == 4); /* Instructions property */ struct ofp_table_feature_prop_instructions { - uint16_t type; /* One of OFPTFPT_INSTRUCTIONS, - OFPTFPT_INSTRUCTIONS_MISS. */ - uint16_t length; /* Length in bytes of this property. */ + uint16_t type; /* One of OFPTFPT_INSTRUCTIONS, + OFPTFPT_INSTRUCTIONS_MISS. */ + uint16_t length; /* Length in bytes of this property. */ /* Followed by: - * - - Exactly (length - 4) bytes containing the instruction ids, then - * - - Exactly (length + 7)/8*8 - (length) (between 0 and 7) - * - bytes of all-zero bytes */ - struct ofp_instruction instruction_ids[0]; /* List of instructions */ + * - Exactly (length - 4) bytes containing the instruction ids, then + * - Exactly (length + 7)/8*8 - (length) (between 0 and 7) + * bytes of all-zero bytes */ + struct ofp_instruction instruction_ids[0]; /* List of instructions */ }; OFP_ASSERT(sizeof(struct ofp_table_feature_prop_instructions) == 4); - +/* Next Tables property */ struct ofp_table_feature_prop_next_tables { - uint16_t type; /* One of OFPTFPT_NEXT_TABLES, - OFPTFPT_NEXT_TABLES_MISS. */ - uint16_t length; /* Length in bytes of this property. */ + uint16_t type; /* One of OFPTFPT_NEXT_TABLES, + OFPTFPT_NEXT_TABLES_MISS. */ + uint16_t length; /* Length in bytes of this property. */ /* Followed by: - * - - Exactly (length - 4) bytes containing the table_ids, then - * - - Exactly (length + 7)/8*8 - (length) (between 0 and 7) - * - bytes of all-zero bytes */ - uint8_t next_table_ids[0]; + * - Exactly (length - 4) bytes containing the table_ids, then + * - Exactly (length + 7)/8*8 - (length) (between 0 and 7) + * bytes of all-zero bytes */ + uint8_t next_table_ids[0]; /* List of table ids. */ }; OFP_ASSERT(sizeof(struct ofp_table_feature_prop_next_tables) == 4); /* Actions property */ struct ofp_table_feature_prop_actions { - uint16_t type; /* One of OFPTFPT_WRITE_ACTIONS, - OFPTFPT_WRITE_ACTIONS_MISS, - OFPTFPT_APPLY_ACTIONS, - OFPTFPT_APPLY_ACTIONS_MISS. */ - - uint16_t length; /* Length in bytes of this property. */ + uint16_t type; /* One of OFPTFPT_WRITE_ACTIONS, + OFPTFPT_WRITE_ACTIONS_MISS, + OFPTFPT_APPLY_ACTIONS, + OFPTFPT_APPLY_ACTIONS_MISS. */ + uint16_t length; /* Length in bytes of this property. */ /* Followed by: - * - - Exactly (length - 4) bytes containing the action_ids, then - * - - Exactly (length + 7)/8*8 - (length) (between 0 and 7) - * - bytes of all-zero bytes */ - struct ofp_action_header action_ids[0];/* List of actions */ + * - Exactly (length - 4) bytes containing the action_ids, then + * - Exactly (length + 7)/8*8 - (length) (between 0 and 7) + * bytes of all-zero bytes */ + struct ofp_action_header action_ids[0]; /* List of actions */ }; OFP_ASSERT(sizeof(struct ofp_table_feature_prop_actions) == 4); /* Match, Wildcard or Set-Field property */ struct ofp_table_feature_prop_oxm { - uint16_t type; /* One of OFPTFPT_MATCH, - OFPTFPT_WILDCARDS, - OFPTFPT_WRITE_SETFIELD, - OFPTFPT_WRITE_SETFIELD_MISS, - OFPTFPT_APPLY_SETFIELD, - OFPTFPT_APPLY_SETFIELD_MISS. */ - - uint16_t length; /* Length in bytes of this property. */ + uint16_t type; /* One of OFPTFPT_MATCH, + OFPTFPT_WILDCARDS, + OFPTFPT_WRITE_SETFIELD, + OFPTFPT_WRITE_SETFIELD_MISS, + OFPTFPT_APPLY_SETFIELD, + OFPTFPT_APPLY_SETFIELD_MISS. */ + uint16_t length; /* Length in bytes of this property. */ /* Followed by: - * - - Exactly (length - 4) bytes containing the oxm_ids, then - * - - Exactly (length + 7)/8*8 - (length) (between 0 and 7) - * - bytes of all-zero bytes */ - uint32_t oxm_ids[0]; /* Array of OXM headers */ + * - Exactly (length - 4) bytes containing the oxm_ids, then + * - Exactly (length + 7)/8*8 - (length) (between 0 and 7) + * bytes of all-zero bytes */ + uint32_t oxm_ids[0]; /* Array of OXM headers */ }; OFP_ASSERT(sizeof(struct ofp_table_feature_prop_oxm) == 4); +/* Experimenter table feature property */ +struct ofp_table_feature_prop_experimenter { + uint16_t type; /* One of OFPTFPT_EXPERIMENTER, + OFPTFPT_EXPERIMENTER_MISS. */ + uint16_t length; /* Length in bytes of this property. */ + uint32_t experimenter; /* Experimenter ID which takes the same + form as in struct + ofp_experimenter_header. */ + uint32_t exp_type; /* Experimenter defined. */ + /* Followed by: + * - Exactly (length - 12) bytes containing the experimenter data, then + * - Exactly (length + 7)/8*8 - (length) (between 0 and 7) + * bytes of all-zero bytes */ + uint32_t experimenter_data[0]; +}; +OFP_ASSERT(sizeof(struct ofp_table_feature_prop_experimenter) == 12); + +/* Body for ofp_multipart_request of type OFPMP_TABLE_FEATURES./ + * Body of reply to OFPMP_TABLE_FEATURES request. */ +struct ofp_table_features { + uint16_t length; /* Length is padded to 64 bits. */ + uint8_t table_id; /* Identifier of table. Lower numbered tables + are consulted first. */ + uint8_t pad[5]; /* Align to 64-bits. */ + char name[OFP_MAX_TABLE_NAME_LEN]; + uint64_t metadata_match; /* Bits of metadata table can match. */ + uint64_t metadata_write; /* Bits of metadata table can write. */ + uint32_t config; /* Bitmap of OFPTC_* values */ + uint32_t max_entries; /* Max number of entries supported. */ -/* Body for ofp_multipart_request of type OFPMP_PORT_STATS. */ -struct ofp_port_stats_request { - uint32_t port_no; /* OFPMP_PORT_STATS message must request statistics - * either for a single port (specified in - * port_no) or for all ports (if port_no == - * OFPP_ANY). */ - uint8_t pad[4]; + /* Table Feature Property list */ + struct ofp_table_feature_prop_header properties[0]; /* List of properties */ }; -OFP_ASSERT(sizeof(struct ofp_port_stats_request) == 8); +OFP_ASSERT(sizeof(struct ofp_table_features) == 64); -/* Body of reply to OFPMP_PORT_STATS request. If a counter is unsupported, set -* the field to all ones. */ -struct ofp_port_stats { - uint32_t port_no; - uint8_t pad[4]; /* Align to 64-bits. */ - uint64_t rx_packets; /* Number of received packets. */ - uint64_t tx_packets; /* Number of transmitted packets. */ - uint64_t rx_bytes; /* Number of received bytes. */ - uint64_t tx_bytes; /* Number of transmitted bytes. */ - uint64_t rx_dropped; /* Number of packets dropped by RX. */ - uint64_t tx_dropped; /* Number of packets dropped by TX. */ - uint64_t rx_errors; /* Number of receive errors. This is a super-set - of more specific receive errors and should be - greater than or equal to the sum of all - rx_*_err values. */ - uint64_t tx_errors; /* Number of transmit errors. This is a super-set - of more specific transmit errors and should be - greater than or equal to the sum of all - tx_*_err values (none currently defined.) */ - uint64_t rx_frame_err; /* Number of frame alignment errors. */ - uint64_t rx_over_err; /* Number of packets with RX overrun. */ - uint64_t rx_crc_err; /* Number of CRC errors. */ - uint64_t collisions; /* Number of collisions. */ - uint32_t duration_sec; /* Time port has been alive in seconds. */ - uint32_t duration_nsec; /* Time port has been alive in nanoseconds beyond - duration_sec. */ +/* Body of reply to OFPMP_TABLE request. */ +struct ofp_table_stats { + uint8_t table_id; /* Identifier of table. Lower numbered tables + are consulted first. */ + uint8_t pad[3]; /* Align to 32-bits. */ + uint32_t active_count; /* Number of active entries. */ + uint64_t lookup_count; /* Number of packets looked up in table. */ + uint64_t matched_count; /* Number of packets that hit table. */ }; -OFP_ASSERT(sizeof(struct ofp_port_stats) == 112); +OFP_ASSERT(sizeof(struct ofp_table_stats) == 24); -struct ofp_queue_stats_request { - uint32_t port_no; /* All ports if OFPP_ANY. */ - uint32_t queue_id; /* All queues if OFPQ_ALL. */ +/* Body for ofp_multipart_request of type OFPMP_PORT. */ +struct ofp_port_stats_request { + uint32_t port_no; /* OFPMP_PORT message must request statistics + * either for a single port (specified in + * port_no) or for all ports (if port_no == + * OFPP_ANY). */ + uint8_t pad[4]; }; -OFP_ASSERT(sizeof(struct ofp_queue_stats_request) == 8); +OFP_ASSERT(sizeof(struct ofp_port_stats_request) == 8); -struct ofp_queue_stats { - uint32_t port_no; - uint32_t queue_id; /* Queue i.d */ - uint64_t tx_bytes; /* Number of transmitted bytes. */ - uint64_t tx_packets; /* Number of transmitted packets. */ - uint64_t tx_errors; /* Number of packets dropped due to overrun. */ - uint32_t duration_sec; /* Time queue has been alive in seconds. */ - uint32_t duration_nsec; /* Time queue has been alive in nanoseconds beyond +/* Body of reply to OFPMP_PORT request. If a counter is unsupported, set + * the field to all ones. */ +struct ofp_port_stats { + uint32_t port_no; + uint8_t pad[4]; /* Align to 64-bits. */ + uint64_t rx_packets; /* Number of received packets. */ + uint64_t tx_packets; /* Number of transmitted packets. */ + uint64_t rx_bytes; /* Number of received bytes. */ + uint64_t tx_bytes; /* Number of transmitted bytes. */ + uint64_t rx_dropped; /* Number of packets dropped by RX. */ + uint64_t tx_dropped; /* Number of packets dropped by TX. */ + uint64_t rx_errors; /* Number of receive errors. This is a super-set + of more specific receive errors and should be + greater than or equal to the sum of all + rx_*_err values. */ + uint64_t tx_errors; /* Number of transmit errors. This is a super-set + of more specific transmit errors and should be + greater than or equal to the sum of all + tx_*_err values (none currently defined.) */ + uint64_t rx_frame_err; /* Number of frame alignment errors. */ + uint64_t rx_over_err; /* Number of packets with RX overrun. */ + uint64_t rx_crc_err; /* Number of CRC errors. */ + uint64_t collisions; /* Number of collisions. */ + uint32_t duration_sec; /* Time port has been alive in seconds. */ + uint32_t duration_nsec; /* Time port has been alive in nanoseconds beyond duration_sec. */ }; -OFP_ASSERT(sizeof(struct ofp_queue_stats) == 40); +OFP_ASSERT(sizeof(struct ofp_port_stats) == 112); /* Body of OFPMP_GROUP request. */ struct ofp_group_stats_request { - uint32_t group_id; /* All groups if OFPG_ALL. */ - uint8_t pad[4]; /* Align to 64 bits. */ + uint32_t group_id; /* All groups if OFPG_ALL. */ + uint8_t pad[4]; /* Align to 64 bits. */ }; OFP_ASSERT(sizeof(struct ofp_group_stats_request) == 8); /* Used in group stats replies. */ struct ofp_bucket_counter { - uint64_t packet_count; /* Number of packets processed by bucket. */ - uint64_t byte_count; /* Number of bytes processed by bucket. */ + uint64_t packet_count; /* Number of packets processed by bucket. */ + uint64_t byte_count; /* Number of bytes processed by bucket. */ }; OFP_ASSERT(sizeof(struct ofp_bucket_counter) == 16); /* Body of reply to OFPMP_GROUP request. */ struct ofp_group_stats { - uint16_t length; /* Length of this entry. */ - uint8_t pad[2]; /* Align to 64 bits. */ - uint32_t group_id; /* Group identifier. */ - uint32_t ref_count; /* Number of flows or groups that directly forward - to this group. */ - uint8_t pad2[4]; /* Align to 64 bits. */ - uint64_t packet_count; /* Number of packets processed by group. */ - uint64_t byte_count; /* Number of bytes processed by group. */ - uint32_t duration_sec; /* Time group has been alive in seconds. */ - uint32_t duration_nsec; /* Time group has been alive in nanoseconds beyond + uint16_t length; /* Length of this entry. */ + uint8_t pad[2]; /* Align to 64 bits. */ + uint32_t group_id; /* Group identifier. */ + uint32_t ref_count; /* Number of flows or groups that directly forward + to this group. */ + uint8_t pad2[4]; /* Align to 64 bits. */ + uint64_t packet_count; /* Number of packets processed by group. */ + uint64_t byte_count; /* Number of bytes processed by group. */ + uint32_t duration_sec; /* Time group has been alive in seconds. */ + uint32_t duration_nsec; /* Time group has been alive in nanoseconds beyond duration_sec. */ - struct ofp_bucket_counter bucket_stats[0]; - + struct ofp_bucket_counter bucket_stats[0]; /* One counter set per bucket. */ }; OFP_ASSERT(sizeof(struct ofp_group_stats) == 40); /* Body of reply to OFPMP_GROUP_DESC request. */ -struct ofp_group_desc_stats { - uint16_t length; /* Length of this entry. */ - uint8_t type; /* One of OFPGT_*. */ - uint8_t pad; /* Pad to 64 bits. */ - uint32_t group_id; /* Group identifier. */ - struct ofp_bucket buckets[0]; +struct ofp_group_desc { + uint16_t length; /* Length of this entry. */ + uint8_t type; /* One of OFPGT_*. */ + uint8_t pad; /* Pad to 64 bits. */ + uint32_t group_id; /* Group identifier. */ + struct ofp_bucket buckets[0]; /* List of buckets - 0 or more. */ }; -OFP_ASSERT(sizeof(struct ofp_group_desc_stats) == 8); +OFP_ASSERT(sizeof(struct ofp_group_desc) == 8); -/* Body of reply to OFPMP_GROUP_FEATURES request. Group features. */ -struct ofp_group_features_stats { - uint32_t types; /* Bitmap of OFPGT_* values supported. */ - uint32_t capabilities; /* Bitmap of OFPGFC_* capability supported. */ - uint32_t max_groups[4]; /* Maximum number of groups for each type. */ - uint32_t actions[4]; /* Bitmaps of OFPAT_* that are supported. */ -}; -OFP_ASSERT(sizeof(struct ofp_group_features_stats) == 40); +/* Backward compatibility with 1.3.1 - avoid breaking the API. */ +#define ofp_group_desc_stats ofp_group_desc /* Group configuration flags */ enum ofp_group_capabilities { - OFPGFC_SELECT_WEIGHT = 1 << 0, /* Support weight for select groups */ - OFPGFC_SELECT_LIVENESS = 1 << 1, /* Support liveness for select groups */ - OFPGFC_CHAINING = 1 << 2, /* Support chaining groups */ - OFPGFC_CHAINING_CHECKS = 1 << 3, /* Check chaining for loops and delete */ + OFPGFC_SELECT_WEIGHT = 1 << 0, /* Support weight for select groups */ + OFPGFC_SELECT_LIVENESS = 1 << 1, /* Support liveness for select groups */ + OFPGFC_CHAINING = 1 << 2, /* Support chaining groups */ + OFPGFC_CHAINING_CHECKS = 1 << 3, /* Check chaining for loops and delete */ }; +/* Body of reply to OFPMP_GROUP_FEATURES request. Group features. */ +struct ofp_group_features { + uint32_t types; /* Bitmap of (1 << OFPGT_*) values supported. */ + uint32_t capabilities; /* Bitmap of OFPGFC_* capability supported. */ + uint32_t max_groups[4]; /* Maximum number of groups for each type. */ + uint32_t actions[4]; /* Bitmaps of (1 << OFPAT_*) values supported. */ +}; +OFP_ASSERT(sizeof(struct ofp_group_features) == 40); + /* Body of OFPMP_METER and OFPMP_METER_CONFIG requests. */ struct ofp_meter_multipart_request { - uint32_t meter_id; /* Meter instance, or OFPM_ALL. */ - uint8_t pad[4]; /* Align to 64 bits. */ + uint32_t meter_id; /* Meter instance, or OFPM_ALL. */ + uint8_t pad[4]; /* Align to 64 bits. */ }; OFP_ASSERT(sizeof(struct ofp_meter_multipart_request) == 8); /* Statistics for each meter band */ struct ofp_meter_band_stats { - uint64_t packet_band_count; /* Number of packets in band. */ - uint64_t byte_band_count; /* Number of bytes in band. */ + uint64_t packet_band_count; /* Number of packets in band. */ + uint64_t byte_band_count; /* Number of bytes in band. */ }; OFP_ASSERT(sizeof(struct ofp_meter_band_stats) == 16); /* Body of reply to OFPMP_METER request. Meter statistics. */ struct ofp_meter_stats { - uint32_t meter_id; /* Meter instance. */ - uint16_t len; /* Length in bytes of this stats. */ - uint8_t pad[6]; - uint32_t flow_count; /* Number of flows bound to meter. */ - uint64_t packet_in_count; /* Number of packets in input. */ - uint64_t byte_in_count; /* Number of bytes in input. */ - uint32_t duration_sec; /* Time meter has been alive in seconds. */ - uint32_t duration_nsec; /* Time meter has been alive in nanoseconds beyond - duration_sec. */ + uint32_t meter_id; /* Meter instance. */ + uint16_t len; /* Length in bytes of this stats. */ + uint8_t pad[6]; + uint32_t flow_count; /* Number of flows bound to meter. */ + uint64_t packet_in_count; /* Number of packets in input. */ + uint64_t byte_in_count; /* Number of bytes in input. */ + uint32_t duration_sec; /* Time meter has been alive in seconds. */ + uint32_t duration_nsec; /* Time meter has been alive in nanoseconds beyond + duration_sec. */ struct ofp_meter_band_stats band_stats[0]; /* The band_stats length is - inferred from the length field. */ + inferred from the length field. */ }; OFP_ASSERT(sizeof(struct ofp_meter_stats) == 40); /* Body of reply to OFPMP_METER_CONFIG request. Meter configuration. */ struct ofp_meter_config { - uint16_t length; /* Length of this entry. */ - uint16_t flags; /* All OFPMC_* that apply. */ - uint32_t meter_id; /* Meter instance. */ + uint16_t length; /* Length of this entry. */ + uint16_t flags; /* All OFPMF_* that apply. */ + uint32_t meter_id; /* Meter instance. */ struct ofp_meter_band_header bands[0]; /* The bands length is - inferred from the length field. */ + inferred from the length field. */ }; OFP_ASSERT(sizeof(struct ofp_meter_config) == 8); /* Body of reply to OFPMP_METER_FEATURES request. Meter features. */ struct ofp_meter_features { - uint32_t max_meter; /* Maximum number of meters. */ - uint32_t band_types; /* Bitmaps of OFPMBT_* values supported. */ - uint32_t capabilities; /* Bitmaps of "ofp_meter_flags". */ - uint8_t max_bands; /* Maximum bands per meters */ - uint8_t max_color; /* Maximum color value */ - uint8_t pad[2]; + uint32_t max_meter; /* Maximum number of meters. */ + uint32_t band_types; /* Bitmaps of (1 << OFPMBT_*) values supported. */ + uint32_t capabilities; /* Bitmaps of "ofp_meter_flags". */ + uint8_t max_bands; /* Maximum bands per meters */ + uint8_t max_color; /* Maximum color value */ + uint8_t pad[2]; }; OFP_ASSERT(sizeof(struct ofp_meter_features) == 16); - /* Body for ofp_multipart_request/reply of type OFPMP_EXPERIMENTER. */ -struct ofp_experimenter_stats_header { - uint32_t experimenter; /* Experimenter ID which takes the same form - as in struct ofp_experimenter_header. */ - uint32_t exp_type; /* Experimenter defined. */ - /* Experimenter-defined arbitrary additional data. */ -}; -OFP_ASSERT(sizeof(struct ofp_experimenter_stats_header) == 8); - -/* Query for port queue configuration. */ -struct ofp_queue_get_config_request { - struct ofp_header header; - uint32_t port; /* Port to be queried. Should refer - to a valid physical port (i.e. < OFPP_MAX), - or OFPP_ANY to request all configured - queues.*/ - uint8_t pad[4]; -}; -OFP_ASSERT(sizeof(struct ofp_queue_get_config_request) == 16); - -/* Queue configuration for a given port. */ -struct ofp_queue_get_config_reply { - struct ofp_header header; - uint32_t port; - uint8_t pad[4]; - struct ofp_packet_queue queues[0]; /* List of configured queues. */ -}; -OFP_ASSERT(sizeof(struct ofp_queue_get_config_reply) == 16); - -/* Send packet (controller -> datapath). */ -struct ofp_packet_out { - struct ofp_header header; - uint32_t buffer_id; /* ID assigned by datapath (OFP_NO_BUFFER - if none). */ - uint32_t in_port; /* Packet’s input port or OFPP_CONTROLLER. */ - uint16_t actions_len; /* Size of action array in bytes. */ - uint8_t pad[6]; - struct ofp_action_header actions[0]; /* Action list. */ - /* uint8_t data[0]; */ /* Packet data. The length is inferred - from the length field in the header. - (Only meaningful if buffer_id == -1.) */ +struct ofp_experimenter_multipart_header { + uint32_t experimenter; /* Experimenter ID which takes the same form + as in struct ofp_experimenter_header. */ + uint32_t exp_type; /* Experimenter defined. */ + /* Experimenter-defined arbitrary additional data. */ }; -OFP_ASSERT(sizeof(struct ofp_packet_out) == 24); - -/* Role request and reply message. */ -struct ofp_role_request { - struct ofp_header header; /* Type OFPT_ROLE_REQUEST/OFPT_ROLE_REPLY. */ - uint32_t role; /* One of NX_ROLE_*. */ - uint8_t pad[4]; /* Align to 64 bits. */ - uint64_t generation_id; /* Master Election Generation Id */ -}; -OFP_ASSERT(sizeof(struct ofp_role_request) == 24); - -/* Controller roles. */ -enum ofp_controller_role { - OFPCR_ROLE_NOCHANGE = 0, /* Don’t change current role. */ - OFPCR_ROLE_EQUAL = 1, /* Default role, full access. */ - OFPCR_ROLE_MASTER = 2, /* Full access, at most one master. */ - OFPCR_ROLE_SLAVE = 3, /* Read-only access. */ -}; - -/* Asynchronous message configuration. */ -struct ofp_async_config { - struct ofp_header header; /* OFPT_GET_ASYNC_REPLY or OFPT_SET_ASYNC. */ - uint32_t packet_in_mask[2]; /* Bitmasks of OFPR_* values. */ - uint32_t port_status_mask[2]; /* Bitmasks of OFPPR_* values. */ - uint32_t flow_removed_mask[2];/* Bitmasks of OFPRR_* values. */ -}; -OFP_ASSERT(sizeof(struct ofp_async_config) == 32); - - - -#define OFP_NO_BUFFER 0xffffffff +OFP_ASSERT(sizeof(struct ofp_experimenter_multipart_header) == 8); -/* Packet received on port (datapath -> controller). */ -struct ofp_packet_in { - struct ofp_header header; - uint32_t buffer_id; /* ID assigned by datapath. */ - uint16_t total_len; /* Full length of frame. */ - uint8_t reason; /* Reason packet is being sent (one of OFPR_*) */ - uint8_t table_id; /* ID of the table that was looked up */ - uint64_t cookie; /* Cookie of the flow entry that was looked up. */ - struct ofp_match match; /* Packet metadata. Variable size. */ - /* Followed by: - * -Exactly 2 all-zero padding bytes,then - * -An Ethernetframe whose length is inferred from header.length. - * The padding bytes preceding the Ethernet frame ensure that the IP - * header (if any) following the Ethernet header is 32-bit aligned. - */ - //uint8_t pad[2]; /* Align to 64 bit + 16 bit */ - //uint8_t data[0]; /* Ethernet frame */ +/* Experimenter extension. */ +struct ofp_experimenter_header { + struct ofp_header header; /* Type OFPT_EXPERIMENTER. */ + uint32_t experimenter; /* Experimenter ID: + * - MSB 0: low-order bytes are IEEE OUI. + * - MSB != 0: defined by ONF. */ + uint32_t exp_type; /* Experimenter defined. */ + /* Experimenter-defined arbitrary additional data. */ }; -OFP_ASSERT(sizeof(struct ofp_packet_in) == 32); +OFP_ASSERT(sizeof(struct ofp_experimenter_header) == 16); -/* Why is this packet being sent to the controller? */ -enum ofp_packet_in_reason { - OFPR_NO_MATCH = 0, /* No matching flow. */ - OFPR_ACTION = 1, /* Action explicitly output to controller. */ - OFPR_INVALID_TTL = 2, /* Packet has invalid TTL */ -}; +/* All ones is used to indicate all queues in a port (for stats retrieval). */ +#define OFPQ_ALL 0xffffffff -/* Flow removed (datapath -> controller). */ -struct ofp_flow_removed { - struct ofp_header header; - uint64_t cookie; /* Opaque controller-issued identifier. */ - uint16_t priority; /* Priority level of flow entry. */ - uint8_t reason; /* One of OFPRR_*. */ - uint8_t table_id; /* ID of the table */ - uint32_t duration_sec; /* Time flow was alive in seconds. */ - uint32_t duration_nsec; /* Time flow was alive in nanoseconds beyond - duration_sec. */ - uint16_t idle_timeout; /* Idle timeout from original flow mod. */ - uint16_t hard_timeout; /* Hard timeout from original flow mod. */ - uint64_t packet_count; - uint64_t byte_count; - struct ofp_match match; /* Description of fields. Variable size. */ -}; -OFP_ASSERT(sizeof(struct ofp_flow_removed) == 56); +/* Min rate > 1000 means not configured. */ +#define OFPQ_MIN_RATE_UNCFG 0xffff -/* Why was this flow removed? */ -enum ofp_flow_removed_reason { - OFPRR_IDLE_TIMEOUT = 0, /* Flow idle time exceeded idle_timeout. */ - OFPRR_HARD_TIMEOUT = 1, /* Time exceeded hard_timeout. */ - OFPRR_DELETE = 2, /* Evicted by a DELETE flow mod. */ - OFPRR_GROUP_DELETE = 3, /* Group was removed. */ - OFPRR_METER_DELETE = 4, /* Meter was removed. */ -}; +/* Max rate > 1000 means not configured. */ +#define OFPQ_MAX_RATE_UNCFG 0xffff -/* A physical port has changed in the datapath */ -struct ofp_port_status { - struct ofp_header header; - uint8_t reason; /* One of OFPPR_*. */ - uint8_t pad[7]; /* Align to 64-bits. */ - struct ofp_port desc; +enum ofp_queue_properties { + OFPQT_MIN_RATE = 1, /* Minimum datarate guaranteed. */ + OFPQT_MAX_RATE = 2, /* Maximum datarate. */ + OFPQT_EXPERIMENTER = 0xffff /* Experimenter defined property. */ }; -OFP_ASSERT(sizeof(struct ofp_port_status) == 80); -/* What changed about the physical port */ -enum ofp_port_reason { - OFPPR_ADD = 0, /* The port was added. */ - OFPPR_DELETE = 1, /* The port was removed. */ - OFPPR_MODIFY = 2, /* Some attribute of the port has changed. */ +/* Common description for a queue. */ +struct ofp_queue_prop_header { + uint16_t property; /* One of OFPQT_. */ + uint16_t len; /* Length of property, including this header. */ + uint8_t pad[4]; /* 64-bit alignment. */ }; +OFP_ASSERT(sizeof(struct ofp_queue_prop_header) == 8); -/* OFPT_ERROR: Error message (datapath -> controller). */ -struct ofp_error_msg { - struct ofp_header header; - uint16_t type; - uint16_t code; - uint8_t data[0]; /* Variable-length data. Interpreted based - on the type and code. No padding. */ +/* Min-Rate queue property description. */ +struct ofp_queue_prop_min_rate { + struct ofp_queue_prop_header prop_header; /* prop: OFPQT_MIN, len: 16. */ + uint16_t rate; /* In 1/10 of a percent; >1000 -> disabled. */ + uint8_t pad[6]; /* 64-bit alignment */ }; -OFP_ASSERT(sizeof(struct ofp_error_msg) == 12); +OFP_ASSERT(sizeof(struct ofp_queue_prop_min_rate) == 16); -/* Values for ’type’ in ofp_error_message. These values are immutable: they -* will not change in future versions of the protocol (although new values may -* be added). */ -enum ofp_error_type { - OFPET_HELLO_FAILED = 0, /* Hello protocol failed. */ - OFPET_BAD_REQUEST = 1, /* Request was not understood. */ - OFPET_BAD_ACTION = 2, /* Error in action description. */ - OFPET_BAD_INSTRUCTION = 3, /* Error in instruction list. */ - OFPET_BAD_MATCH = 4, /* Error in match. */ - OFPET_FLOW_MOD_FAILED = 5, /* Problem modifying flow entry. */ - OFPET_GROUP_MOD_FAILED = 6, /* Problem modifying group entry. */ - OFPET_PORT_MOD_FAILED = 7, /* Port mod request failed. */ - OFPET_TABLE_MOD_FAILED = 8, /* Table mod request failed. */ - OFPET_QUEUE_OP_FAILED = 9, /* Queue operation failed. */ - OFPET_SWITCH_CONFIG_FAILED = 10, /* Switch config request failed. */ - OFPET_ROLE_REQUEST_FAILED = 11, /* Controller Role request failed. */ - OFPET_METER_MOD_FAILED = 12, /* Error in meter. */ - OFPET_TABLE_FEATURES_FAILED = 13, /* Setting table features failed. */ - OFPET_EXPERIMENTER = 0xffff /* Experimenter error messages. */ +/* Max-Rate queue property description. */ +struct ofp_queue_prop_max_rate { + struct ofp_queue_prop_header prop_header; /* prop: OFPQT_MAX, len: 16. */ + uint16_t rate; /* In 1/10 of a percent; >1000 -> disabled. */ + uint8_t pad[6]; /* 64-bit alignment */ }; +OFP_ASSERT(sizeof(struct ofp_queue_prop_max_rate) == 16); -/* ofp_error_msg ’code’ values for OFPET_HELLO_FAILED. ’data’ contains an -* ASCII text string that may give failure details. */ -enum ofp_hello_failed_code { - OFPHFC_INCOMPATIBLE = 0, /* No compatible version. */ - OFPHFC_EPERM = 1, /* Permissions error. */ +/* Experimenter queue property description. */ +struct ofp_queue_prop_experimenter { + struct ofp_queue_prop_header prop_header; /* prop: OFPQT_EXPERIMENTER, len: 16. */ + uint32_t experimenter; /* Experimenter ID which takes the same + form as in struct + ofp_experimenter_header. */ + uint8_t pad[4]; /* 64-bit alignment */ + uint8_t data[0]; /* Experimenter defined data. */ }; +OFP_ASSERT(sizeof(struct ofp_queue_prop_experimenter) == 16); -/* ofp_error_msg ’code’ values for OFPET_BAD_REQUEST. ’data’ contains at least -* the first 64 bytes of the failed request. */ -enum ofp_bad_request_code { - OFPBRC_BAD_VERSION = 0, /* ofp_header.version not supported. */ - OFPBRC_BAD_TYPE = 1, /* ofp_header.type not supported. */ - OFPBRC_BAD_MULTIPART = 2, /* ofp_multipart_request.type not supported. */ - OFPBRC_BAD_EXPERIMENTER = 3, /* Experimenter id not supported - * (in ofp_experimenter_header or - * ofp_multipart_request or ofp_multipart_reply). */ - OFPBRC_BAD_EXP_TYPE = 4, /* Experimenter type not supported. */ - OFPBRC_EPERM = 5, /* Permissions error. */ - OFPBRC_BAD_LEN = 6, /* Wrong request length for type. */ - OFPBRC_BUFFER_EMPTY = 7, /* Specified buffer has already been used. */ - OFPBRC_BUFFER_UNKNOWN = 8, /* Specified buffer does not exist. */ - OFPBRC_BAD_TABLE_ID = 9, /* Specified table-id invalid or does not - * exist. */ - OFPBRC_IS_SLAVE = 10, /* Denied because controller is slave. */ - OFPBRC_BAD_PORT = 11, /* Invalid port. */ - OFPBRC_BAD_PACKET = 12, /* Invalid packet in packet-out. */ - OFPBRC_MULTIPART_BUFFER_OVERFLOW = 13, /* ofp_multipart_request - overflowed the assigned buffer. */ - -}; - -/* ofp_error_msg ’code’ values for OFPET_BAD_ACTION. ’data’ contains at least -* the first 64 bytes of the failed request. */ -enum ofp_bad_action_code { - OFPBAC_BAD_TYPE = 0, /* Unknown action type. */ - OFPBAC_BAD_LEN = 1, /* Length problem in actions. */ - OFPBAC_BAD_EXPERIMENTER = 2, /* Unknown experimenter id specified. */ - OFPBAC_BAD_EXP_TYPE = 3, /* Unknown action for experimenter id. */ - OFPBAC_BAD_OUT_PORT = 4, /* Problem validating output port. */ - OFPBAC_BAD_ARGUMENT = 5, /* Bad action argument. */ - OFPBAC_EPERM = 6, /* Permissions error. */ - OFPBAC_TOO_MANY = 7, /* Can’t handle this many actions. */ - OFPBAC_BAD_QUEUE = 8, /* Problem validating output queue. */ - OFPBAC_BAD_OUT_GROUP = 9, /* Invalid group id in forward action. */ - OFPBAC_MATCH_INCONSISTENT = 10, /* Action can’t apply for this match, - or Set-Field missing prerequisite. */ - OFPBAC_UNSUPPORTED_ORDER = 11, /* Action order is unsupported for the - action list in an Apply-Actions instruction */ - OFPBAC_BAD_TAG = 12, /* Actions uses an unsupported - tag/encap. */ - OFPBAC_BAD_SET_TYPE = 13, /* Unsupported type in SET_FIELD action. */ - OFPBAC_BAD_SET_LEN = 14, /* Length problem in SET_FIELD action. */ - OFPBAC_BAD_SET_ARGUMENT = 15, /* Bad argument in SET_FIELD action. */ +/* Full description for a queue. */ +struct ofp_packet_queue { + uint32_t queue_id; /* id for the specific queue. */ + uint32_t port; /* Port this queue is attached to. */ + uint16_t len; /* Length in bytes of this queue desc. */ + uint8_t pad[6]; /* 64-bit alignment. */ + struct ofp_queue_prop_header properties[0]; /* List of properties. */ }; +OFP_ASSERT(sizeof(struct ofp_packet_queue) == 16); -/* ofp_error_msg ’code’ values for OFPET_BAD_INSTRUCTION. ’data’ contains at least -* the first 64 bytes of the failed request. */ -enum ofp_bad_instruction_code { - OFPBIC_UNKNOWN_INST = 0, /* Unknown instruction. */ - OFPBIC_UNSUP_INST = 1, /* Switch or table does not support the - instruction. */ - OFPBIC_BAD_TABLE_ID = 2, /* Invalid Table-ID specified. */ - OFPBIC_UNSUP_METADATA = 3, /* Metadata value unsupported by datapath. */ - OFPBIC_UNSUP_METADATA_MASK = 4, /* Metadata mask value unsupported by - datapath. */ - OFPBIC_BAD_EXPERIMENTER = 5, /* Unknown experimenter id specified. */ - OFPBIC_BAD_EXP_TYPE = 6, /* Unknown instruction for experimenter id. */ - OFPBIC_BAD_LEN = 7, /* Length problem in instructions. */ - OFPBIC_EPERM = 8, /* Permissions error. */ +/* Query for port queue configuration. */ +struct ofp_queue_get_config_request { + struct ofp_header header; + uint32_t port; /* Port to be queried. Should refer + to a valid physical port (i.e. <= OFPP_MAX), + or OFPP_ANY to request all configured + queues.*/ + uint8_t pad[4]; }; +OFP_ASSERT(sizeof(struct ofp_queue_get_config_request) == 16); -/* ofp_error_msg ’code’ values for OFPET_BAD_MATCH. ’data’ contains at least -* the first 64 bytes of the failed request. */ -enum ofp_bad_match_code { - OFPBMC_BAD_TYPE = 0, /* Unsupported match type specified by the - match */ - OFPBMC_BAD_LEN = 1, /* Length problem in match. */ - OFPBMC_BAD_TAG = 2, /* Match uses an unsupported tag/encap. */ - OFPBMC_BAD_DL_ADDR_MASK = 3, /* Unsupported datalink addr mask - switch - does not support arbitrary datalink - address mask. */ - OFPBMC_BAD_NW_ADDR_MASK = 4, /* Unsupported network addr mask - switch - does not support arbitrary network - address mask. */ - OFPBMC_BAD_WILDCARDS = 5, /* Unsupported combination of fields masked - or omitted in the match. */ - OFPBMC_BAD_FIELD = 6, /* Unsupported field type in the match. */ - OFPBMC_BAD_VALUE = 7, /* Unsupported value in a match field. */ - OFPBMC_BAD_MASK = 8, /* Unsupported mask specified in the match, - field is not dl-address or nw-address. */ - OFPBMC_BAD_PREREQ = 9, /* A prerequisite was not met. */ - OFPBMC_DUP_FIELD = 10, /* A field type was duplicated. */ - OFPBMC_EPERM = 11, /* Permissions error. */ -}; - -/* ofp_error_msg ’code’ values for OFPET_FLOW_MOD_FAILED. ’data’ contains -* at least the first 64 bytes of the failed request. */ -enum ofp_flow_mod_failed_code { - OFPFMFC_UNKNOWN = 0, /* Unspecified error. */ - OFPFMFC_TABLE_FULL = 1, /* Flow not added because table was full. */ - OFPFMFC_BAD_TABLE_ID = 2, /* Table does not exist */ - OFPFMFC_OVERLAP = 3, /* Attempted to add overlapping flow with - CHECK_OVERLAP flag set. */ - OFPFMFC_EPERM = 4, /* Permissions error. */ - OFPFMFC_BAD_TIMEOUT = 5, /* Flow not added because of unsupported - idle/hard timeout. */ - OFPFMFC_BAD_COMMAND = 6, /* Unsupported or unknown command. */ - OFPFMFC_BAD_FLAGS = 7, /* Unsupported or unknown flags. */ -}; - -/* ofp_error_msg ’code’ values for OFPET_GROUP_MOD_FAILED. ’data’ contains -* at least the first 64 bytes of the failed request. */ -enum ofp_group_mod_failed_code { - OFPGMFC_GROUP_EXISTS = 0, /* Group not added because a group ADD - attempted to replace an - already-present group. */ - OFPGMFC_INVALID_GROUP = 1, /* Group not added because Group */ - - OFPGMFC_OUT_OF_GROUPS = 3, /* The group table is full. */ - - OFPGMFC_OUT_OF_BUCKETS = 4, /* The maximum number of action buckets - for a group has been exceeded. */ - OFPGMFC_CHAINING_UNSUPPORTED = 5, /* Switch does not support groups that - forward to groups. */ - OFPGMFC_WATCH_UNSUPPORTED = 6, /* This group cannot watch the watch_port - or watch_group specified. */ - OFPGMFC_LOOP = 7, /* Group entry would cause a loop. */ - OFPGMFC_UNKNOWN_GROUP = 8, /* Group not modified because a group - MODIFY attempted to modify a - non-existent group. */ - OFPGMFC_CHAINED_GROUP = 9, /* Group not deleted because another - group is forwarding to it. */ - OFPGMFC_BAD_TYPE = 10, /* Unsupported or unknown group type. */ - OFPGMFC_BAD_COMMAND = 11, /* Unsupported or unknown command. */ - OFPGMFC_BAD_BUCKET = 12, /* Error in bucket. */ - OFPGMFC_BAD_WATCH = 13, /* Error in watch port/group. */ - OFPGMFC_EPERM = 14, /* Permissions error. */ -}; - -/* ofp_error_msg ’code’ values for OFPET_PORT_MOD_FAILED. ’data’ contains -* at least the first 64 bytes of the failed request. */ -enum ofp_port_mod_failed_code { - OFPPMFC_BAD_PORT = 0, /* Specified port number does not exist. */ - OFPPMFC_BAD_HW_ADDR = 1, /* Specified hardware address does not - * match the port number. */ - OFPPMFC_BAD_CONFIG = 2, /* Specified config is invalid. */ - OFPPMFC_BAD_ADVERTISE = 3, /* Specified advertise is invalid. */ - OFPPMFC_EPERM = 4, /* Permissions error. */ +/* Queue configuration for a given port. */ +struct ofp_queue_get_config_reply { + struct ofp_header header; + uint32_t port; + uint8_t pad[4]; + struct ofp_packet_queue queues[0]; /* List of configured queues. */ }; +OFP_ASSERT(sizeof(struct ofp_queue_get_config_reply) == 16); -/* ofp_error_msg ’code’ values for OFPET_TABLE_MOD_FAILED. ’data’ contains -* at least the first 64 bytes of the failed request. */ -enum ofp_table_mod_failed_code { - OFPTMFC_BAD_TABLE = 0, /* Specified table does not exist. */ - OFPTMFC_BAD_CONFIG = 1, /* Specified config is invalid. */ - OFPTMFC_EPERM = 2, /* Permissions error. */ +/* OFPAT_SET_QUEUE action struct: send packets to given queue on port. */ +struct ofp_action_set_queue { + uint16_t type; /* OFPAT_SET_QUEUE. */ + uint16_t len; /* Len is 8. */ + uint32_t queue_id; /* Queue id for the packets. */ }; +OFP_ASSERT(sizeof(struct ofp_action_set_queue) == 8); -/* ofp_error msg ’code’ values for OFPET_QUEUE_OP_FAILED. ’data’ contains -* at least the first 64 bytes of the failed request */ -enum ofp_queue_op_failed_code { - OFPQOFC_BAD_PORT = 0, /* Invalid port (or port does not exist). */ - OFPQOFC_BAD_QUEUE = 1, /* Queue does not exist. */ - OFPQOFC_EPERM = 2, /* Permissions error. */ +struct ofp_queue_stats_request { + uint32_t port_no; /* All ports if OFPP_ANY. */ + uint32_t queue_id; /* All queues if OFPQ_ALL. */ }; +OFP_ASSERT(sizeof(struct ofp_queue_stats_request) == 8); -/* ofp_error_msg ’code’ values for OFPET_SWITCH_CONFIG_FAILED. ’data’ contains -* at least the first 64 bytes of the failed request. */ -enum ofp_switch_config_failed_code { - OFPSCFC_BAD_FLAGS = 0, /* Specified flags is invalid. */ - OFPSCFC_BAD_LEN = 1, /* Specified len is invalid. */ - OFPQCFC_EPERM = 2, /* Permissions error. */ +struct ofp_queue_stats { + uint32_t port_no; + uint32_t queue_id; /* Queue i.d */ + uint64_t tx_bytes; /* Number of transmitted bytes. */ + uint64_t tx_packets; /* Number of transmitted packets. */ + uint64_t tx_errors; /* Number of packets dropped due to overrun. */ + uint32_t duration_sec; /* Time queue has been alive in seconds. */ + uint32_t duration_nsec; /* Time queue has been alive in nanoseconds beyond + duration_sec. */ }; +OFP_ASSERT(sizeof(struct ofp_queue_stats) == 40); -/* ofp_error_msg ’code’ values for OFPET_ROLE_REQUEST_FAILED. ’data’ contains -* at least the first 64 bytes of the failed request. */ -enum ofp_role_request_failed_code { - OFPRRFC_STALE = 0, /* Stale Message: old generation_id. */ - OFPRRFC_UNSUP = 1, /* Controller role change unsupported. */ - OFPRRFC_BAD_ROLE = 2, /* Invalid role. */ -}; +/* Configures the "role" of the sending controller. The default role is: + * + * - Equal (OFPCR_ROLE_EQUAL), which allows the controller access to all + * OpenFlow features. All controllers have equal responsibility. + * + * The other possible roles are a related pair: + * + * - Master (OFPCR_ROLE_MASTER) is equivalent to Equal, except that there + * may be at most one Master controller at a time: when a controller + * configures itself as Master, any existing Master is demoted to the + * Slave role. + * + * - Slave (OFPCR_ROLE_SLAVE) allows the controller read-only access to + * OpenFlow features. In particular attempts to modify the flow table + * will be rejected with an OFPBRC_EPERM error. + * + * Slave controllers do not receive OFPT_PACKET_IN or OFPT_FLOW_REMOVED + * messages, but they do receive OFPT_PORT_STATUS messages. + */ -/* ofp_error_msg ’code’ values for OFPET_METER_MOD_FAILED. ’data’ contains -* at least the first 64 bytes of the failed request. */ -enum ofp_meter_mod_failed_code { - OFPMMFC_UNKNOWN = 0, /* Unspecified error. */ - OFPMMFC_METER_EXISTS = 1, /* Meter not added because a Meter ADD - * attempted to replace an existing Meter. */ - OFPMMFC_INVALID_METER = 2, /* Meter not added because Meter specified - * is invalid. */ - OFPMMFC_UNKNOWN_METER = 3, /* Meter not modified because a Meter - MODIFY attempted to modify a non-existent - Meter. */ - OFPMMFC_BAD_COMMAND = 4, /* Unsupported or unknown command. */ - OFPMMFC_BAD_FLAGS = 5, /* Flag configuration unsupported. */ - OFPMMFC_BAD_RATE = 6, /* Rate unsupported. */ - OFPMMFC_BAD_BURST = 7, /* Burst size unsupported. */ - OFPMMFC_BAD_BAND = 8, /* Band unsupported. */ - OFPMMFC_BAD_BAND_VALUE = 9, /* Band value unsupported. */ - OFPMMFC_OUT_OF_METERS = 10, /* No more meters available. */ - OFPMMFC_OUT_OF_BANDS = 11, /* The maximum number of properties - * for a meter has been exceeded. */ +/* Controller roles. */ +enum ofp_controller_role { + OFPCR_ROLE_NOCHANGE = 0, /* Don't change current role. */ + OFPCR_ROLE_EQUAL = 1, /* Default role, full access. */ + OFPCR_ROLE_MASTER = 2, /* Full access, at most one master. */ + OFPCR_ROLE_SLAVE = 3, /* Read-only access. */ }; -/* ofp_error_msg ’code’ values for OFPET_TABLE_FEATURES_FAILED. ’data’ contains -* at least the first 64 bytes of the failed request. */ -enum ofp_table_features_failed_code { - OFPTFFC_BAD_TABLE = 0, /* Specified table does not exist. */ - OFPTFFC_BAD_METADATA = 1, /* Invalid metadata mask. */ - OFPTFFC_BAD_TYPE = 2, /* Unknown property type. */ - OFPTFFC_BAD_LEN = 3, /* Length problem in properties. */ - OFPTFFC_BAD_ARGUMENT = 4, /* Unsupported property value. */ - OFPTFFC_EPERM = 5, /* Permissions error. */ +/* Role request and reply message. */ +struct ofp_role_request { + struct ofp_header header; /* Type OFPT_ROLE_REQUEST/OFPT_ROLE_REPLY. */ + uint32_t role; /* One of OFPCR_ROLE_*. */ + uint8_t pad[4]; /* Align to 64 bits. */ + uint64_t generation_id; /* Master Election Generation Id */ }; +OFP_ASSERT(sizeof(struct ofp_role_request) == 24); -/* OFPET_EXPERIMENTER: Error message (datapath -> controller). */ -struct ofp_error_experimenter_msg { - struct ofp_header header; - uint16_t type; /* OFPET_EXPERIMENTER. */ - uint16_t exp_type; /* Experimenter defined. */ - uint32_t experimenter; /* Experimenter ID which takes the same form - as in struct ofp_experimenter_header. */ - uint8_t data[0]; /* Variable-length data. Interpreted based - on the type and code. No padding. */ +/* Asynchronous message configuration. */ +struct ofp_async_config { + struct ofp_header header; /* OFPT_GET_ASYNC_REPLY or OFPT_SET_ASYNC. */ + uint32_t packet_in_mask[2]; /* Bitmasks of OFPR_* values. */ + uint32_t port_status_mask[2]; /* Bitmasks of OFPPR_* values. */ + uint32_t flow_removed_mask[2];/* Bitmasks of OFPRR_* values. */ }; -OFP_ASSERT(sizeof(struct ofp_error_experimenter_msg) == 16); +OFP_ASSERT(sizeof(struct ofp_async_config) == 32); -/* Experimenter extension. */ -struct ofp_experimenter_header { - struct ofp_header header; /* Type OFPT_EXPERIMENTER. */ - uint32_t experimenter; /* Experimenter ID: - * - MSB 0: low-order bytes are IEEE OUI. - * - MSB != 0: defined by ONF. */ - uint32_t exp_type; /* Experimenter defined. */ - /* Experimenter-defined arbitrary additional data. */ -}; -OFP_ASSERT(sizeof(struct ofp_experimenter_header) == 16); #endif /* openflow/openflow.h */ diff --git a/install.sh b/install.sh new file mode 100755 index 00000000..154c4fb9 --- /dev/null +++ b/install.sh @@ -0,0 +1,46 @@ +#!/bin/bash + +# Script to install on most recent versions of Ubuntu +# Tested on the LTS versions 14.04 and 16.04. +# Feel free to contribute to additional systems + +UBUNTU_DEPS="g++ gcc cmake libc6-dev libpcap-dev libxerces-c3.1 libxerces-c-dev libpcre3 libpcre3-dev flex bison pkg-config autoconf libtool libboost-dev" + +BUILD_DIR="$(pwd -P)" +install_deps() +{ + if [ $(lsb_release -si) = "Ubuntu" ]; then + sudo apt-get install $UBUNTU_DEPS + fi +} + +install_nbee() +{ + if [ ! -d "netbee" ]; then + git clone https://github.com/netgroup-polito/netbee.git + fi + cd netbee/src + cmake . + make + cd .. + sudo cp bin/libn*.so /usr/local/lib + sudo ldconfig + sudo cp -R include/* /usr/include/ +} + +switch() +{ + if [ ${BUILD_DIR##*/} != "ofsoftswitch13" ]; then + cd $BUILD_DIR/ofsoftswitch13 + else + cd $BUILD_DIR + fi + ./boot.sh + ./configure + make + sudo make install +} + +install_deps +install_nbee +switch \ No newline at end of file diff --git a/lib/automake.mk b/lib/automake.mk index fe7ec798..9b50cf58 100644 --- a/lib/automake.mk +++ b/lib/automake.mk @@ -31,8 +31,6 @@ lib_libopenflow_a_SOURCES = \ lib/hmap.h \ lib/ipv6_util.c \ lib/ipv6_util.h \ - lib/leak-checker.c \ - lib/leak-checker.h \ lib/list.c \ lib/list.h \ lib/mac-learning.c \ diff --git a/lib/backtrace.c b/lib/backtrace.c index fc301987..2661f904 100644 --- a/lib/backtrace.c +++ b/lib/backtrace.c @@ -59,7 +59,7 @@ get_max_stack(void) for (line_number = 1; fgets(line, sizeof line, f); line_number++) { if (strstr(line, "[stack]")) { uintptr_t end; - if (sscanf(line, "%*"SCNxPTR"-%"SCNxPTR, &end) != 1) { + if (sscanf(line, "%*x-%"SCNxPTR, &end) != 1) { VLOG_WARN(LOG_MODULE, "%s:%d: parse error", file_name, line_number); continue; } @@ -90,6 +90,10 @@ stack_low(void) uintptr_t low; asm("movl %%esp,%0" : "=g" (low)); return low; +#elif __x86_64__ + uintptr_t low; + asm("movq %%rsp,%0" : "=g" (low)); + return low; #else /* This causes a warning in GCC that cannot be disabled, so use it only on * non-x86. */ @@ -112,7 +116,7 @@ backtrace_capture(struct backtrace *backtrace) size_t n; n = 0; - for (frame = __builtin_frame_address(1); + for (frame = __builtin_frame_address(0); frame != NULL && in_stack(frame) && frame[0] != NULL && n < BACKTRACE_MAX_FRAMES; frame = frame[0]) diff --git a/lib/csum.c b/lib/csum.c index 81b3dc13..430e7bac 100644 --- a/lib/csum.c +++ b/lib/csum.c @@ -113,3 +113,30 @@ recalc_csum32(uint16_t old_csum, uint32_t old_u32, uint32_t new_u32) return recalc_csum16(recalc_csum16(old_csum, old_u32, new_u32), old_u32 >> 16, new_u32 >> 16); } + +/* Returns the new checksum for a packet in which the checksum field previously + * contained 'old_csum' and in which a field that contained 'old_u64' was + * changed to contain 'new_u64'. */ +uint16_t +recalc_csum64(uint16_t old_csum, uint64_t old_u64, uint64_t new_u64) +{ + return recalc_csum32(recalc_csum32(old_csum, old_u64, new_u64), + old_u64 >> 32, new_u64 >> 32); +} + + +/* Returns the new checksum for a packet in which the checksum field previously + * contained 'old_csum' and in which a field that contained 'old_u32' was + * changed to contain 'new_u12'. */ +uint16_t +recalc_csum128(uint16_t old_csum, uint8_t old_u128[16], uint8_t new_u128[16]) +{ + uint64_t old_left, old_right; + uint64_t new_left, new_right; + old_right = *((uint64_t*) ( old_u128 + 8 )); + new_right = *((uint64_t*) ( new_u128 + 8 )); + old_left = *((uint64_t*) ( old_u128 )); + new_left = *((uint64_t*) ( new_u128 )); + return recalc_csum64(recalc_csum64(old_csum, old_right, new_right), + old_left, new_left); +} \ No newline at end of file diff --git a/lib/csum.h b/lib/csum.h index d9253e00..50ecb898 100644 --- a/lib/csum.h +++ b/lib/csum.h @@ -44,5 +44,7 @@ uint32_t csum_continue(uint32_t partial, const void *, size_t); uint16_t csum_finish(uint32_t partial); uint16_t recalc_csum16(uint16_t old_csum, uint16_t old_u16, uint16_t new_u16); uint16_t recalc_csum32(uint16_t old_csum, uint32_t old_u32, uint32_t new_u32); +uint16_t recalc_csum64(uint16_t old_csum, uint64_t old_u64, uint64_t new_u64); +uint16_t recalc_csum128(uint16_t old_csum, uint8_t old_u128[16], uint8_t new_u128[16]); #endif /* csum.h */ diff --git a/lib/daemon.c b/lib/daemon.c index 7a300c0d..cae95502 100644 --- a/lib/daemon.c +++ b/lib/daemon.c @@ -223,10 +223,14 @@ daemonize(void) /* Child process. */ close(fds[0]); make_pidfile(); - write(fds[1], &c, 1); + if (write(fds[1], &c, 1) != 1){ + ofp_fatal(errno, "daemon child failed to write signal startup"); + } close(fds[1]); setsid(); - chdir("/"); + if (chdir("/") != 0){ + ofp_fatal(errno, "daemon child failed to change the current directory"); + } break; case -1: diff --git a/lib/dhcp-client.c b/lib/dhcp-client.c index b97af0d8..39a6b06d 100644 --- a/lib/dhcp-client.c +++ b/lib/dhcp-client.c @@ -931,7 +931,7 @@ do_receive_msg(struct dhclient *cli, struct dhcp_msg *msg) int error; ofpbuf_clear(&b); - error = netdev_recv(cli->netdev, &b); + error = netdev_recv(cli->netdev, &b, 0); if (error) { goto drained; } @@ -997,7 +997,7 @@ do_send_msg(struct dhclient *cli, const struct dhcp_msg *msg) memcpy(eh.eth_dst, eth_addr_broadcast, ETH_ADDR_LEN); eh.eth_type = htons(ETH_TYPE_IP); - nh.ip_ihl_ver = IP_IHL_VER(5, IP_VERSION); + nh.ip_ihl_ver = IP_IHL_VER(5, IPV4_VERSION); nh.ip_tos = 0; nh.ip_tot_len = htons(IP_HEADER_LEN + UDP_HEADER_LEN + b.size); /* We can't guarantee uniqueness of ip_id versus the host's, screwing up @@ -1047,7 +1047,7 @@ do_send_msg(struct dhclient *cli, const struct dhcp_msg *msg) } else { VLOG_INFO(LOG_MODULE, "sending %s", dhcp_type_name(msg->type)); } - error = netdev_send(cli->netdev, &b, 0); + error = netdev_send(cli->netdev, &b, ETH_TOTAL_MAX); if (error) { VLOG_ERR(LOG_MODULE, "send failed on %s: %s", netdev_get_name(cli->netdev), strerror(error)); diff --git a/lib/dpif.c.bak b/lib/dpif.c.bak deleted file mode 100644 index 9a6a7232..00000000 --- a/lib/dpif.c.bak +++ /dev/null @@ -1,392 +0,0 @@ -/* Copyright (c) 2008, 2009 The Board of Trustees of The Leland Stanford - * Junior University - * - * We are making the OpenFlow specification and associated documentation - * (Software) available for public use and benefit with the expectation - * that others will use, modify and enhance the Software and contribute - * those enhancements back to the community. However, since we would - * like to make the Software available for broadest use, with as few - * restrictions as possible permission is hereby granted, free of - * charge, to any person obtaining a copy of this Software to deal in - * the Software under the copyrights without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * - * The name and trademarks of copyright holder(s) may NOT be used in - * advertising or publicity pertaining to the Software or any - * derivatives without specific, written prior permission. - */ - -#include -#include "dpif.h" - -#include -#include -#include -#include -#include -#include -#include - -#include "netlink.h" -#include "netlink-protocol.h" -#include "ofpbuf.h" -#include "openflow/openflow-netlink.h" -#include "openflow/openflow.h" -#include "packets.h" -#include "util.h" -#include "xtoxll.h" - -#include "vlog.h" -#define LOG_MODULE VLM_dpif - -/* Not really much point in logging many dpif errors. */ -static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 60); - -/* The Generic Netlink family number used for OpenFlow. */ -static int openflow_family; - -static int lookup_openflow_multicast_group(int dp_idx, int *multicast_group); -static int send_mgmt_command(struct dpif *, int dp_idx, int command, - const char *netdev); - -/* Opens a socket for a local datapath, initializing 'dp'. If - * 'subscribe_dp_idx' is nonnegative, listens for asynchronous messages - * (packet-in, etc.) from the datapath with that number; otherwise, 'dp' will - * receive only replies to explicitly initiated requests. */ -int -dpif_open(int subscribe_dp_idx, struct dpif *dp) -{ - struct nl_sock *sock; - int multicast_group = 0; - int retval; - - retval = nl_lookup_genl_family(DP_GENL_FAMILY_NAME, &openflow_family); - if (retval) { - return retval; - } - - if (subscribe_dp_idx >= 0) { - retval = lookup_openflow_multicast_group(subscribe_dp_idx, - &multicast_group); - if (retval) { - return retval; - } - } - - /* Specify a large so_rcvbuf size because we occasionally need to be able - * to retrieve large collections of flow records. */ - retval = nl_sock_create(NETLINK_GENERIC, multicast_group, 0, - 4 * 1024u * 1024, &sock); - if (retval) { - return retval; - } - - dp->sock = sock; - return 0; -} - -/* Closes 'dp'. */ -void -dpif_close(struct dpif *dp) -{ - if (dp) { - nl_sock_destroy(dp->sock); - } -} - -static const struct nl_policy openflow_policy[] = { - [DP_GENL_A_DP_IDX] = { .type = NL_A_U32, - .optional = false }, - [DP_GENL_A_OPENFLOW] = { .type = NL_A_UNSPEC, - .min_len = sizeof(struct ofp_header), - .max_len = 65535, - .optional = false }, -}; - -/* Tries to receive an openflow message from datapath 'dp_idx' on 'sock'. If - * successful, stores the received message into '*msgp' and returns 0. The - * caller is responsible for destroying the message with ofpbuf_delete(). On - * failure, returns a positive errno value and stores a null pointer into - * '*msgp'. - * - * Only Netlink messages with embedded OpenFlow messages are accepted. Other - * Netlink messages provoke errors. - * - * If 'wait' is true, dpif_recv_openflow waits for a message to be ready; - * otherwise, returns EAGAIN if the 'sock' receive buffer is empty. */ -int -dpif_recv_openflow(struct dpif *dp, int dp_idx, struct ofpbuf **bufferp, - bool wait) -{ - struct nlattr *attrs[ARRAY_SIZE(openflow_policy)]; - struct ofpbuf *buffer; - struct ofp_header *oh; - uint16_t ofp_len; - - buffer = *bufferp = NULL; - do { - int retval; - - do { - ofpbuf_delete(buffer); - retval = nl_sock_recv(dp->sock, &buffer, wait); - } while (retval == ENOBUFS - || (!retval - && (nl_msg_nlmsghdr(buffer)->nlmsg_type == NLMSG_DONE - || nl_msg_nlmsgerr(buffer, NULL)))); - if (retval) { - if (retval != EAGAIN) { - VLOG_WARN_RL(LOG_MODULE, &rl, "dpif_recv_openflow: %s", strerror(retval)); - } - return retval; - } - - if (nl_msg_genlmsghdr(buffer) == NULL) { - VLOG_DBG_RL(LOG_MODULE, &rl, "received packet too short for Generic Netlink"); - goto error; - } - if (nl_msg_nlmsghdr(buffer)->nlmsg_type != openflow_family) { - VLOG_DBG_RL(LOG_MODULE, &rl, - "received type (%"PRIu16") != openflow family (%d)", - nl_msg_nlmsghdr(buffer)->nlmsg_type, openflow_family); - goto error; - } - - if (!nl_policy_parse(buffer, NLMSG_HDRLEN + GENL_HDRLEN, - openflow_policy, attrs, - ARRAY_SIZE(openflow_policy))) { - goto error; - } - } while (nl_attr_get_u32(attrs[DP_GENL_A_DP_IDX]) != dp_idx); - - oh = buffer->data = (void *) nl_attr_get(attrs[DP_GENL_A_OPENFLOW]); - buffer->size = nl_attr_get_size(attrs[DP_GENL_A_OPENFLOW]); - ofp_len = ntohs(oh->length); - if (ofp_len != buffer->size) { - VLOG_WARN_RL(LOG_MODULE, &rl, - "ofp_header.length %"PRIu16" != attribute length %zu\n", - ofp_len, buffer->size); - buffer->size = MIN(ofp_len, buffer->size); - } - *bufferp = buffer; - return 0; - -error: - ofpbuf_delete(buffer); - return EPROTO; -} - -/* Encapsulates 'msg', which must contain an OpenFlow message, in a Netlink - * message, and sends it to the OpenFlow local datapath numbered 'dp_idx' via - * 'sock'. - * - * Returns 0 if successful, otherwise a positive errno value. Returns EAGAIN - * if the 'sock' send buffer is full. - * - * If the send is successful, then the kernel module will receive it, but there - * is no guarantee that any reply will not be dropped (see nl_sock_transact() - * for details). - */ -int -dpif_send_openflow(struct dpif *dp, int dp_idx, struct ofpbuf *buffer) -{ - struct ofp_header *oh; - unsigned int dump_flag; - struct ofpbuf hdr; - struct nlattr *nla; - uint32_t fixed_buffer[64 / 4]; - struct iovec iov[3]; - int pad_bytes; - int n_iov; - int retval; - - /* The reply to OFPT_STATS_REQUEST may be multiple segments long, so we - * need to specify NLM_F_DUMP in the request. */ - oh = ofpbuf_at_assert(buffer, 0, sizeof *oh); - dump_flag = oh->type == OFPT_STATS_REQUEST ? NLM_F_DUMP : 0; - - ofpbuf_use(&hdr, fixed_buffer, sizeof fixed_buffer); - nl_msg_put_genlmsghdr(&hdr, dp->sock, 32, openflow_family, - NLM_F_REQUEST | dump_flag, DP_GENL_C_OPENFLOW, 1); - nl_msg_put_u32(&hdr, DP_GENL_A_DP_IDX, dp_idx); - nla = ofpbuf_put_uninit(&hdr, sizeof *nla); - nla->nla_len = sizeof *nla + buffer->size; - nla->nla_type = DP_GENL_A_OPENFLOW; - pad_bytes = NLA_ALIGN(nla->nla_len) - nla->nla_len; - nl_msg_nlmsghdr(&hdr)->nlmsg_len = hdr.size + buffer->size + pad_bytes; - n_iov = 2; - iov[0].iov_base = hdr.data; - iov[0].iov_len = hdr.size; - iov[1].iov_base = buffer->data; - iov[1].iov_len = buffer->size; - if (pad_bytes) { - static char zeros[NLA_ALIGNTO]; - n_iov++; - iov[2].iov_base = zeros; - iov[2].iov_len = pad_bytes; - } - retval = nl_sock_sendv(dp->sock, iov, n_iov, false); - if (retval && retval != EAGAIN) { - VLOG_WARN_RL(LOG_MODULE, &rl, "dpif_send_openflow: %s", strerror(retval)); - } - return retval; -} - -/* Creates local datapath numbered 'dp_idx' with the name 'dp_name'. A - * 'dp_idx' of -1 or null 'dp_name' will have the kernel module choose values. - * (At least one or the other must be provided, however, so that the caller can - * identify the datapath that was created.) Returns 0 if successful, otherwise - * a positive errno value. */ -int -dpif_add_dp(struct dpif *dp, int dp_idx, const char *dp_name) -{ - return send_mgmt_command(dp, dp_idx, DP_GENL_C_ADD_DP, dp_name); -} - -/* Destroys a local datapath. If 'dp_idx' is not -1, destroys the datapath - * with that number; if 'dp_name' is not NULL, destroys the datapath with that - * name. Exactly one of 'dp_idx' and 'dp_name' should be used. Returns 0 if - * successful, otherwise a positive errno value. */ -int -dpif_del_dp(struct dpif *dp, int dp_idx, const char *dp_name) -{ - return send_mgmt_command(dp, dp_idx, DP_GENL_C_DEL_DP, dp_name); -} - -/* Adds the Ethernet device named 'netdev' to the local datapath numbered - * 'dp_idx'. Returns 0 if successful, otherwise a positive errno value. */ -int -dpif_add_port(struct dpif *dp, int dp_idx, const char *netdev) -{ - return send_mgmt_command(dp, dp_idx, DP_GENL_C_ADD_PORT, netdev); -} - -/* Removes the Ethernet device named 'netdev' from the local datapath numbered - * 'dp_idx'. Returns 0 if successful, otherwise a positive errno value. */ -int -dpif_del_port(struct dpif *dp, int dp_idx, const char *netdev) -{ - return send_mgmt_command(dp, dp_idx, DP_GENL_C_DEL_PORT, netdev); -} - -static const struct nl_policy openflow_multicast_policy[] = { - [DP_GENL_A_DP_IDX] = { .type = NL_A_U32 }, - [DP_GENL_A_DP_NAME] = { .type = NL_A_STRING }, - [DP_GENL_A_MC_GROUP] = { .type = NL_A_U32 }, -}; - -/* Looks up the Netlink multicast group and datapath index of a datapath - * by either the datapath index or name. If 'dp_idx' points to a value - * of '-1', then 'dp_name' is used to lookup the datapath. If successful, - * stores the multicast group in '*multicast_group' and the index in - * '*dp_idx' and returns 0. Otherwise, returns a positive errno value. */ -static int -query_datapath(int *dp_idx, int *multicast_group, const char *dp_name) -{ - struct nl_sock *sock; - struct ofpbuf request, *reply; - struct nlattr *attrs[ARRAY_SIZE(openflow_multicast_policy)]; - int retval; - - retval = nl_sock_create(NETLINK_GENERIC, 0, 0, 0, &sock); - if (retval) { - return retval; - } - ofpbuf_init(&request, 0); - nl_msg_put_genlmsghdr(&request, sock, 0, openflow_family, NLM_F_REQUEST, - DP_GENL_C_QUERY_DP, 1); - if (*dp_idx != -1) { - nl_msg_put_u32(&request, DP_GENL_A_DP_IDX, *dp_idx); - } - if (dp_name) { - nl_msg_put_string(&request, DP_GENL_A_DP_NAME, dp_name); - } - retval = nl_sock_transact(sock, &request, &reply); - ofpbuf_uninit(&request); - if (retval) { - nl_sock_destroy(sock); - return retval; - } - if (!nl_policy_parse(reply, NLMSG_HDRLEN + GENL_HDRLEN, - openflow_multicast_policy, attrs, - ARRAY_SIZE(openflow_multicast_policy))) { - nl_sock_destroy(sock); - ofpbuf_delete(reply); - return EPROTO; - } - *dp_idx = nl_attr_get_u32(attrs[DP_GENL_A_DP_IDX]); - *multicast_group = nl_attr_get_u32(attrs[DP_GENL_A_MC_GROUP]); - nl_sock_destroy(sock); - ofpbuf_delete(reply); - - return 0; -} - -/* Looks up the Netlink multicast group used by datapath 'dp_idx'. If - * successful, stores the multicast group in '*multicast_group' and returns 0. - * Otherwise, returns a positve errno value. */ -static int -lookup_openflow_multicast_group(int dp_idx, int *multicast_group) -{ - return query_datapath(&dp_idx, multicast_group, NULL); -} - -/* Looks up the datatpath index based on the name. Returns the index, or - * -1 on error. */ -int -dpif_get_idx(const char *name) -{ - int dp_idx = -1; - int mc_group = 0; - - if (query_datapath(&dp_idx, &mc_group, name)) { - return -1; - } - - return dp_idx; -} - -/* Sends the given 'command' to datapath 'dp', related to the local datapath - * numbered 'dp_idx'. If 'arg' is nonnull, adds it to the command as the - * datapath or port name attribute depending on the requested operation. - * Returns 0 if successful, otherwise a positive errno value. */ -static int -send_mgmt_command(struct dpif *dp, int dp_idx, int command, const char *arg) -{ - struct ofpbuf request, *reply; - int retval; - - ofpbuf_init(&request, 0); - nl_msg_put_genlmsghdr(&request, dp->sock, 32, openflow_family, - NLM_F_REQUEST | NLM_F_ACK, command, 1); - if (dp_idx != -1) { - nl_msg_put_u32(&request, DP_GENL_A_DP_IDX, dp_idx); - } - if (arg) { - if ((command == DP_GENL_C_ADD_DP) || (command == DP_GENL_C_DEL_DP)) { - nl_msg_put_string(&request, DP_GENL_A_DP_NAME, arg); - } else { - nl_msg_put_string(&request, DP_GENL_A_PORTNAME, arg); - } - } - retval = nl_sock_transact(dp->sock, &request, &reply); - ofpbuf_uninit(&request); - ofpbuf_delete(reply); - - return retval; -} diff --git a/lib/leak-checker.c b/lib/leak-checker.c deleted file mode 100644 index b1445885..00000000 --- a/lib/leak-checker.c +++ /dev/null @@ -1,252 +0,0 @@ -/* Copyright (c) 2008, 2009 The Board of Trustees of The Leland Stanford - * Junior University - * - * We are making the OpenFlow specification and associated documentation - * (Software) available for public use and benefit with the expectation - * that others will use, modify and enhance the Software and contribute - * those enhancements back to the community. However, since we would - * like to make the Software available for broadest use, with as few - * restrictions as possible permission is hereby granted, free of - * charge, to any person obtaining a copy of this Software to deal in - * the Software under the copyrights without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * - * The name and trademarks of copyright holder(s) may NOT be used in - * advertising or publicity pertaining to the Software or any - * derivatives without specific, written prior permission. - */ - -#include -#include "leak-checker.h" -#include -#include "backtrace.h" - -#define LOG_MODULE VLM_leak_checker -#include "vlog.h" - -#ifndef HAVE_MALLOC_HOOKS -void -leak_checker_start(const char *file_name UNUSED) -{ - VLOG_WARN(LOG_MODULE, "not enabling leak checker because the libc in use does not " - "have the required hooks"); -} - -void -leak_checker_set_limit(off_t max_size UNUSED) -{ -} - -void -leak_checker_claim(const void *p UNUSED) -{ -} - -void -leak_checker_usage(void) -{ - printf(" --check-leaks=FILE (accepted but ignored in this build)\n"); -} -#else /* HAVE_MALLOC_HOOKS */ -#include -#include -#include -#include - -typedef void *malloc_hook_type(size_t, const void *); -typedef void *realloc_hook_type(void *, size_t, const void *); -typedef void free_hook_type(void *, const void *); - -struct hooks { - malloc_hook_type *malloc_hook_func; - realloc_hook_type *realloc_hook_func; - free_hook_type *free_hook_func; -}; - -static malloc_hook_type hook_malloc; -static realloc_hook_type hook_realloc; -static free_hook_type hook_free; - -static struct hooks libc_hooks; -static const struct hooks our_hooks = { hook_malloc, hook_realloc, hook_free }; - -static FILE *file; -static off_t limit = 10 * 1000 * 1000; - -static void -get_hooks(struct hooks *hooks) -{ - hooks->malloc_hook_func = __malloc_hook; - hooks->realloc_hook_func = __realloc_hook; - hooks->free_hook_func = __free_hook; -} - -static void -set_hooks(const struct hooks *hooks) -{ - __malloc_hook = hooks->malloc_hook_func; - __realloc_hook = hooks->realloc_hook_func; - __free_hook = hooks->free_hook_func; -} - -void -leak_checker_start(const char *file_name) -{ - if (!file) { - file = fopen(file_name, "w"); - if (!file) { - VLOG_WARN(LOG_MODULE, "failed to create \"%s\": %s", - file_name, strerror(errno)); - return; - } - setvbuf(file, NULL, _IONBF, 0); - VLOG_WARN(LOG_MODULE, "enabled memory leak logging to \"%s\"", file_name); - get_hooks(&libc_hooks); - set_hooks(&our_hooks); - } -} - -void -leak_checker_stop(void) -{ - if (file) { - fclose(file); - file = NULL; - set_hooks(&libc_hooks); - VLOG_WARN(LOG_MODULE, "disabled memory leak logging"); - } -} - -void -leak_checker_set_limit(off_t limit_) -{ - limit = limit_; -} - -void -leak_checker_usage(void) -{ - printf(" --check-leaks=FILE log malloc and free calls to FILE\n"); -} - -static void PRINTF_FORMAT(1, 2) -log_callers(const char *format, ...) -{ - struct backtrace backtrace; - va_list args; - int i; - - va_start(args, format); - vfprintf(file, format, args); - va_end(args); - - putc(':', file); - backtrace_capture(&backtrace); - for (i = 0; i < backtrace.n_frames; i++) { - fprintf(file, " 0x%"PRIxPTR"", backtrace.frames[i]); - } - putc('\n', file); -} - -static void -reset_hooks(void) -{ - static int count; - - if (count++ >= 100 && limit && file) { - struct stat s; - count = 0; - if (fstat(fileno(file), &s) < 0) { - VLOG_WARN(LOG_MODULE, "cannot fstat leak checker log file: %s", - strerror(errno)); - return; - } - if (s.st_size > limit) { - VLOG_WARN(LOG_MODULE, "leak checker log file size exceeded limit"); - leak_checker_stop(); - return; - } - } - if (file) { - set_hooks(&our_hooks); - } -} - -static void * -hook_malloc(size_t size, const void *caller UNUSED) -{ - void *p; - - set_hooks(&libc_hooks); - p = malloc(size); - get_hooks(&libc_hooks); - - log_callers("malloc(%zu) -> %p", size, p); - - reset_hooks(); - return p; -} - -void -leak_checker_claim(const void *p) -{ - if (!file) { - return; - } - - if (p) { - set_hooks(&libc_hooks); - log_callers("claim(%p)", p); - reset_hooks(); - } -} - -static void -hook_free(void *p, const void *caller UNUSED) -{ - if (!p) { - return; - } - - set_hooks(&libc_hooks); - free(p); - get_hooks(&libc_hooks); - - log_callers("free(%p)", p); - - reset_hooks(); -} - -static void * -hook_realloc(void *p, size_t size, const void *caller UNUSED) -{ - void *q; - - set_hooks(&libc_hooks); - q = realloc(p, size); - get_hooks(&libc_hooks); - - if (p != q) { - log_callers("realloc(%p, %zu) -> %p", p, size, q); - } - - reset_hooks(); - - return q; -} -#endif /* HAVE_MALLOC_HOOKS */ diff --git a/lib/leak-checker.h b/lib/leak-checker.h deleted file mode 100644 index c0317a76..00000000 --- a/lib/leak-checker.h +++ /dev/null @@ -1,58 +0,0 @@ -/* Copyright (c) 2008, 2009 The Board of Trustees of The Leland Stanford - * Junior University - * - * We are making the OpenFlow specification and associated documentation - * (Software) available for public use and benefit with the expectation - * that others will use, modify and enhance the Software and contribute - * those enhancements back to the community. However, since we would - * like to make the Software available for broadest use, with as few - * restrictions as possible permission is hereby granted, free of - * charge, to any person obtaining a copy of this Software to deal in - * the Software under the copyrights without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * - * The name and trademarks of copyright holder(s) may NOT be used in - * advertising or publicity pertaining to the Software or any - * derivatives without specific, written prior permission. - */ - -#ifndef LEAK_CHECKER_H -#define LEAK_CHECKER_H 1 - -#include - -#define LEAK_CHECKER_OPTION_ENUMS \ - OPT_CHECK_LEAKS, \ - OPT_LEAK_LIMIT -#define LEAK_CHECKER_LONG_OPTIONS \ - {"check-leaks", required_argument, 0, OPT_CHECK_LEAKS}, \ - {"leak-limit", required_argument, 0, OPT_LEAK_LIMIT} -#define LEAK_CHECKER_OPTION_HANDLERS \ - case OPT_CHECK_LEAKS: \ - leak_checker_start(optarg); \ - break; \ - case OPT_LEAK_LIMIT: \ - leak_checker_set_limit(atol(optarg)); \ - break; -void leak_checker_start(const char *file_name); -void leak_checker_set_limit(off_t limit); -void leak_checker_stop(void); -void leak_checker_claim(const void *); -void leak_checker_usage(void); - -#endif /* leak-checker.h */ diff --git a/lib/leak-checker.man b/lib/leak-checker.man deleted file mode 100644 index 7b376e1a..00000000 --- a/lib/leak-checker.man +++ /dev/null @@ -1,7 +0,0 @@ -.TP -\fB--check-leaks=\fIfile\fR -. -Logs information about memory allocation and deallocation to -\fIfile\fR, to allow for debugging memory leaks in \fB\*(PN\fR. This -option slows down \fB\*(PN\fR considerably, so it should only be used -when a memory leak is suspected. diff --git a/lib/netdev.c b/lib/netdev.c index 470f1d92..480641c1 100644 --- a/lib/netdev.c +++ b/lib/netdev.c @@ -34,7 +34,7 @@ * * The modification includes code from libpcap; the copyright notice for that * code is - /* + * * pcap-linux.c: Packet capture interface to the Linux kernel * * Copyright (c) 2000 Torsten Landschoff @@ -71,6 +71,7 @@ #include #include #include +#include #include #include @@ -96,7 +97,6 @@ #endif #include -#include #include #include #include @@ -121,6 +121,7 @@ #include "socket-util.h" #include "svec.h" + /* linux/if.h defines IFF_LOWER_UP, net/if.h doesn't. * net/if.h defines if_nameindex(), linux/if.h doesn't. * We can't include both headers, so define IFF_LOWER_UP ourselves. */ @@ -141,6 +142,8 @@ struct netdev { int tap_fd; /* TAP character device, if any, otherwise the * network device. */ + int netlink_fd; + /* one socket per queue.These are valid only for ordinary network devices*/ int queue_fd[NETDEV_MAX_QUEUES + 1]; uint16_t num_queues; @@ -220,6 +223,7 @@ get_ipv6_address(const char *name, struct in6_addr *in6) fclose(file); } +#define TC_QDISC_NO_CONFIG_ERR 512 /* All queues in a port, lie beneath a qdisc */ #define TC_QDISC 0x0001 /* This is a root class. In order to efficiently share excess bandwidth @@ -436,7 +440,8 @@ do_setup_qdisc(const char *netdev_name) error = system(command); if (error) { VLOG_WARN(LOG_MODULE, "Problem configuring qdisc for device %s",netdev_name); - return error; + fprintf(stderr, "Error is %d\n", error); + return error; } return 0; } @@ -448,10 +453,13 @@ static int do_remove_qdisc(const char *netdev_name) { char command[1024]; - + int error; snprintf(command, sizeof(command), COMMAND_DEL_DEV_QDISC, netdev_name); - system(command); - + error = system(command); + if (error && error != TC_QDISC_NO_CONFIG_ERR) { + VLOG_WARN(LOG_MODULE, "Problem configuring qdisc for device %s ",netdev_name); + return error; + } /* There is no need for a device to already be configured. Therefore no * need to indicate any error */ return 0; @@ -721,7 +729,9 @@ do_open_netdev(const char *name, int ethertype, int tap_fd, struct netdev **netdev_) { int netdev_fd; + int netlink_fd; struct sockaddr_ll sll; + struct sockaddr_nl snl; struct ifreq ifr; unsigned int ifindex; uint8_t etheraddr[ETH_ADDR_LEN]; @@ -731,9 +741,22 @@ do_open_netdev(const char *name, int ethertype, int tap_fd, int hwaddr_family; int error; struct netdev *netdev; - + uint32_t val; init_netdev(); *netdev_ = NULL; + netdev_fd = -1; + + netlink_fd = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE); + + if (netlink_fd < 0) { + return errno; + } + + /* Set non-blocking mode. */ + error = set_nonblocking(netlink_fd); + if (error) { + goto error_already_set; + } /* Create raw socket. */ netdev_fd = socket(PF_PACKET, SOCK_RAW, @@ -744,20 +767,29 @@ do_open_netdev(const char *name, int ethertype, int tap_fd, if (netdev_fd < 0) { return errno; } - #ifdef HAVE_PACKET_AUXDATA - uint32_t val = 1; - if (setsockopt(netdev_fd, SOL_PACKET, PACKET_AUXDATA, &val, + #ifdef HAVE_PACKET_AUXDATA + val = 1; + if (setsockopt(netdev_fd, SOL_PACKET, PACKET_AUXDATA, &val, sizeof val) == -1 && errno != ENOPROTOOPT){ - VLOG_ERR(LOG_MODULE, "setsockopt(SO_RCVBUF,%zu): %s", val, strerror(errno)); - } - #endif - + VLOG_ERR(LOG_MODULE, "setsockopt(SO_RCVBUF,%"PRIu32"): %s", val, + strerror(errno)); + } + #endif + /* Set non-blocking mode. */ error = set_nonblocking(netdev_fd); if (error) { goto error_already_set; } + memset (&snl,0,sizeof(snl)); + snl.nl_family = AF_NETLINK; + snl.nl_groups = RTMGRP_LINK; + + if (bind(netlink_fd, (struct sockaddr *)&snl, sizeof(snl)) < 0){ + VLOG_ERR(LOG_MODULE, "netlink bind to %s failed: %s", name, strerror(errno)); + goto error; + } /* Get ethernet device index. */ strncpy(ifr.ifr_name, name, sizeof ifr.ifr_name); if (ioctl(netdev_fd, SIOCGIFINDEX, &ifr) < 0) { @@ -825,6 +857,7 @@ do_open_netdev(const char *name, int ethertype, int tap_fd, netdev->txqlen = txqlen; netdev->hwaddr_family = hwaddr_family; netdev->netdev_fd = netdev_fd; + netdev->netlink_fd = netlink_fd; netdev->tap_fd = tap_fd < 0 ? netdev_fd : tap_fd; netdev->queue_fd[0] = netdev->tap_fd; memcpy(netdev->etheraddr, etheraddr, sizeof etheraddr); @@ -895,13 +928,47 @@ netdev_close(struct netdev *netdev) /* Pads 'buffer' out with zero-bytes to the minimum valid length of an * Ethernet packet, if necessary. */ static void -pad_to_minimum_length(struct ofpbuf *buffer) +pad_to_minimum_length(struct ofpbuf *buffer) { if (buffer->size < ETH_TOTAL_MIN) { ofpbuf_put_zeros(buffer, ETH_TOTAL_MIN - buffer->size); } } +int +netdev_link_state(struct netdev *netdev) +{ + int len; + char buff[4096]; + struct nlmsghdr *nlm; + struct ifinfomsg *ifa; + enum netdev_flags flags; + nlm = (struct nlmsghdr *)buff; + do + { + len = recv (netdev->netlink_fd,nlm,4096,0); + for (;(NLMSG_OK (nlm, len)) && (nlm->nlmsg_type != NLMSG_DONE); nlm = NLMSG_NEXT(nlm, len)) + { + if (nlm->nlmsg_type != RTM_NEWLINK) + continue; + ifa = (struct ifinfomsg *) NLMSG_DATA (nlm); + if (ifa->ifi_index == netdev->ifindex){ + if (ifa->ifi_flags & IFF_UP){ + netdev_nodev_get_flags(netdev->name, &flags); + netdev_set_flags(netdev, flags, false); + return NETDEV_LINK_UP; + } + else { + netdev_nodev_get_flags(netdev->name, &flags); + netdev_set_flags(netdev, flags, false); + return NETDEV_LINK_DOWN; + } + } + } + } while (len < 0 && errno == EINTR); + return NETDEV_LINK_NO_CHANGE; +} + /* Attempts to receive a packet from 'netdev' into 'buffer', which the caller * must have initialized with sufficient room for the packet. The space * required to receive any packet is ETH_HEADER_LEN bytes, plus VLAN_HEADER_LEN @@ -915,9 +982,8 @@ pad_to_minimum_length(struct ofpbuf *buffer) * be returned. */ int -netdev_recv(struct netdev *netdev, struct ofpbuf *buffer) +netdev_recv(struct netdev *netdev, struct ofpbuf *buffer, size_t max_mtu) { - #ifdef HAVE_PACKET_AUXDATA /* Code from libpcap to reconstruct VLAN header */ struct iovec iov; @@ -950,7 +1016,7 @@ netdev_recv(struct netdev *netdev, struct ofpbuf *buffer) msg.msg_controllen = sizeof(cmsg_buf); msg.msg_flags = 0; - iov.iov_len = buffer->allocated; + iov.iov_len = max_mtu; iov.iov_base = buffer->data; #else @@ -975,7 +1041,6 @@ netdev_recv(struct netdev *netdev, struct ofpbuf *buffer) n_bytes = recvfrom(netdev->tap_fd, ofpbuf_tail(buffer), (ssize_t)ofpbuf_tailroom(buffer), 0, (struct sockaddr *)&sll, &sll_len); - #endif /* ifdef HAVE_PACKET_AUXDATA */ } while (n_bytes < 0 && errno == EINTR); } @@ -992,7 +1057,7 @@ netdev_recv(struct netdev *netdev, struct ofpbuf *buffer) for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) { struct tpacket_auxdata *aux; struct vlan_tag *tag; - + uint16_t eth_type; buffer->size += n_bytes; if (cmsg->cmsg_len < CMSG_LEN(sizeof(struct tpacket_auxdata)) || @@ -1001,15 +1066,23 @@ netdev_recv(struct netdev *netdev, struct ofpbuf *buffer) continue; } aux = (struct tpacket_auxdata *)CMSG_DATA(cmsg); - if (aux->tp_vlan_tci == 0) + if (aux->tp_vlan_tci == 0){ continue; + } /* VLAN tag found. Shift MAC addresses down and insert VLAN tag */ /* Create headroom for the VLAN tag */ - ofpbuf_reserve(buffer, VLAN_HEADER_LEN); + eth_type = ntohs(*((uint16_t *)((uint8_t*)buffer->data + ETHER_ADDR_LEN * 2))); ofpbuf_push_uninit(buffer, VLAN_HEADER_LEN); memmove(buffer->data, (uint8_t*)buffer->data+VLAN_HEADER_LEN, ETH_ALEN * 2); tag = (struct vlan_tag *)((uint8_t*)buffer->data + ETH_ALEN * 2); - tag->vlan_tp_id = htons(ETH_P_8021Q); + if (eth_type == ETH_TYPE_VLAN_PBB_S || + eth_type == ETH_TYPE_VLAN_PBB_B || + eth_type == ETH_TYPE_VLAN){ + tag->vlan_tp_id = htons(ETH_TYPE_VLAN_PBB_B); + } + else { + tag->vlan_tp_id = htons(ETH_P_8021Q); + } tag->vlan_tci = htons(aux->tp_vlan_tci); } #else @@ -1020,14 +1093,13 @@ netdev_recv(struct netdev *netdev, struct ofpbuf *buffer) return EAGAIN; } buffer->size += n_bytes; - +#endif /* When the kernel internally sends out an Ethernet frame on an * interface, it gives us a copy *before* padding the frame to the * minimum length. Thus, when it sends out something like an ARP * request, we see a too-short frame. So pad it out to the minimum * length. */ pad_to_minimum_length(buffer); -#endif return 0; } @@ -1077,7 +1149,6 @@ netdev_send(struct netdev *netdev, const struct ofpbuf *buffer, do { n_bytes = write(netdev->queue_fd[class_id], buffer->data, buffer->size); } while (n_bytes < 0 && errno == EINTR); - if (n_bytes < 0) { /* The Linux AF_PACKET implementation never blocks waiting for room * for packets, instead returning ENOBUFS. Translate this into EAGAIN diff --git a/lib/netdev.h b/lib/netdev.h index b1937bb2..342b0ab4 100644 --- a/lib/netdev.h +++ b/lib/netdev.h @@ -68,16 +68,25 @@ enum netdev_pseudo_ethertype { NETDEV_ETH_TYPE_802_2 /* Receive all IEEE 802.2 frames. */ }; +enum netdev_link_state { + NETDEV_LINK_UP = 1, + NETDEV_LINK_DOWN = 2, + NETDEV_LINK_NO_CHANGE = 3 +}; + #define NETDEV_MAX_QUEUES 8 + + struct netdev; int netdev_open(const char *name, int ethertype, struct netdev **); int netdev_open_tap(const char *name, struct netdev **); void netdev_close(struct netdev *); -int netdev_recv(struct netdev *, struct ofpbuf *); +int netdev_recv(struct netdev *, struct ofpbuf *, size_t); void netdev_recv_wait(struct netdev *); +int netdev_link_state(struct netdev *netdev); int netdev_drain(struct netdev *); int netdev_send(struct netdev *, const struct ofpbuf *, uint16_t class_id); void netdev_send_wait(struct netdev *); diff --git a/lib/ofp.c b/lib/ofp.c index b75681ec..6f9c878e 100644 --- a/lib/ofp.c +++ b/lib/ofp.c @@ -184,7 +184,7 @@ update_instruction_length(struct ofpbuf *buffer, size_t oia_offset) struct ofpbuf * make_flow_mod(uint8_t command, uint8_t table_id, - const struct flow *flow, size_t actions_len) + const struct flow *flow UNUSED, size_t actions_len) { struct ofp_flow_mod *ofm; size_t size = sizeof *ofm + actions_len; @@ -636,15 +636,16 @@ check_output_port(uint32_t port, int max_ports, bool table_allowed) static int check_setqueue_action(const union ofp_action *a, unsigned int len) { - const struct ofp_action_set_queue *oaq; + const struct ofp_action_set_queue *oaq UNUSED; int error; error = check_action_exact_len(a, len, 8); if (error) { return error; } - - oaq = (const struct ofp_action_set_queue *) a; + /*TODO check if this functions is relevant and finish or + remove it accordingly */ + /*oaq = (const struct ofp_action_set_queue *) a;*/ return 0; } diff --git a/lib/ofp.c~ b/lib/ofp.c~ deleted file mode 100644 index 3ebf083d..00000000 --- a/lib/ofp.c~ +++ /dev/null @@ -1,763 +0,0 @@ -/* Copyright (c) 2008, 2009 The Board of Trustees of The Leland Stanford - * Junior University - * - * We are making the OpenFlow specification and associated documentation - * (Software) available for public use and benefit with the expectation - * that others will use, modify and enhance the Software and contribute - * those enhancements back to the community. However, since we would - * like to make the Software available for broadest use, with as few - * restrictions as possible permission is hereby granted, free of - * charge, to any person obtaining a copy of this Software to deal in - * the Software under the copyrights without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * - * The name and trademarks of copyright holder(s) may NOT be used in - * advertising or publicity pertaining to the Software or any - * derivatives without specific, written prior permission. - */ - -/* Zoltan: - * During the move to OpenFlow 1.1 parts of the code was taken from - * the following repository, with the license below: - * git://openflow.org/of1.1-spec-test.git (lib/ofp-util.h) - */ -/* - * Copyright (c) 2008, 2009, 2010 Nicira Networks. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include -#include -#include -#include -#include -#include -#include "ofp.h" -#include "ofpbuf.h" -#include "openflow/openflow.h" -#include "openflow/nicira-ext.h" -#include "packets.h" -#include "random.h" -#include "util.h" - -#define LOG_MODULE VLM_ofp -#include "vlog.h" - -/* XXX we should really use consecutive xids to avoid probabilistic - * failures. */ -static inline uint32_t -alloc_xid(void) -{ - return random_uint32(); -} - -/* Allocates and stores in '*bufferp' a new ofpbuf with a size of - * 'openflow_len', starting with an OpenFlow header with the given 'type' and - * an arbitrary transaction id. Allocated bytes beyond the header, if any, are - * zeroed. - * - * The caller is responsible for freeing '*bufferp' when it is no longer - * needed. - * - * The OpenFlow header length is initially set to 'openflow_len'; if the - * message is later extended, the length should be updated with - * update_openflow_length() before sending. - * - * Returns the header. */ -void * -make_openflow(size_t openflow_len, uint8_t type, struct ofpbuf **bufferp) -{ - *bufferp = ofpbuf_new(openflow_len); - return put_openflow_xid(openflow_len, type, alloc_xid(), *bufferp); -} - -/* Allocates and stores in '*bufferp' a new ofpbuf with a size of - * 'openflow_len', starting with an OpenFlow header with the given 'type' and - * transaction id 'xid'. Allocated bytes beyond the header, if any, are - * zeroed. - * - * The caller is responsible for freeing '*bufferp' when it is no longer - * needed. - * - * The OpenFlow header length is initially set to 'openflow_len'; if the - * message is later extended, the length should be updated with - * update_openflow_length() before sending. - * - * Returns the header. */ -void * -make_openflow_xid(size_t openflow_len, uint8_t type, uint32_t xid, - struct ofpbuf **bufferp) -{ - *bufferp = ofpbuf_new(openflow_len); - return put_openflow_xid(openflow_len, type, xid, *bufferp); -} - -/* Appends 'openflow_len' bytes to 'buffer', starting with an OpenFlow header - * with the given 'type' and an arbitrary transaction id. Allocated bytes - * beyond the header, if any, are zeroed. - * - * The OpenFlow header length is initially set to 'openflow_len'; if the - * message is later extended, the length should be updated with - * update_openflow_length() before sending. - * - * Returns the header. */ -void * -put_openflow(size_t openflow_len, uint8_t type, struct ofpbuf *buffer) -{ - return put_openflow_xid(openflow_len, type, alloc_xid(), buffer); -} - -/* Appends 'openflow_len' bytes to 'buffer', starting with an OpenFlow header - * with the given 'type' and an transaction id 'xid'. Allocated bytes beyond - * the header, if any, are zeroed. - * - * The OpenFlow header length is initially set to 'openflow_len'; if the - * message is later extended, the length should be updated with - * update_openflow_length() before sending. - * - * Returns the header. */ -void * -put_openflow_xid(size_t openflow_len, uint8_t type, uint32_t xid, - struct ofpbuf *buffer) -{ - struct ofp_header *oh; - - assert(openflow_len >= sizeof *oh); - assert(openflow_len <= UINT16_MAX); - - oh = ofpbuf_put_uninit(buffer, openflow_len); - oh->version = OFP_VERSION; - oh->type = type; - oh->length = htons(openflow_len); - oh->xid = xid; - memset(oh + 1, 0, openflow_len - sizeof *oh); - return oh; -} - -/* Updates the 'length' field of the OpenFlow message in 'buffer' to - * 'buffer->size'. */ -void -update_openflow_length(struct ofpbuf *buffer) -{ - struct ofp_header *oh = ofpbuf_at_assert(buffer, 0, sizeof *oh); - oh->length = htons(buffer->size); -} - -/* Updates the 'len' field of the instruction header in 'buffer' to - * "what it should be"(tm). */ -void -update_instruction_length(struct ofpbuf *buffer, size_t oia_offset) -{ - struct ofp_header *oh = ofpbuf_at_assert(buffer, 0, sizeof *oh); - struct ofp_instruction *ih = ofpbuf_at_assert(buffer, oia_offset, - sizeof *ih); - ih->len = htons(buffer->size - oia_offset); -} - -struct ofpbuf * -make_flow_mod(uint8_t command, uint8_t table_id, - const struct flow *flow, size_t actions_len) -{ - struct ofp_flow_mod *ofm; - size_t size = sizeof *ofm + actions_len; - struct ofpbuf *out = ofpbuf_new(size); - ofm = ofpbuf_put_zeros(out, sizeof *ofm); - ofm->header.version = OFP_VERSION; - ofm->header.type = OFPT_FLOW_MOD; - ofm->header.length = htons(size); - ofm->cookie = 0; - /*TODO fill match - ofm->match.in_port = flow->in_port; - memcpy(ofm->match.dl_src, flow->dl_src, sizeof ofm->match.dl_src); - memcpy(ofm->match.dl_dst, flow->dl_dst, sizeof ofm->match.dl_dst); - ofm->match.dl_vlan = flow->dl_vlan; - ofm->match.dl_vlan_pcp = flow->dl_vlan_pcp; - ofm->match.dl_type = flow->dl_type; - ofm->match.nw_src = flow->nw_src; - ofm->match.nw_dst = flow->nw_dst; - ofm->match.nw_proto = flow->nw_proto; - ofm->match.nw_tos = flow->nw_tos; - ofm->match.tp_src = flow->tp_src; - ofm->match.tp_dst = flow->tp_dst; */ - ofm->command = command; - ofm->table_id = table_id; - - return out; -} - -struct ofpbuf * -make_add_flow(const struct flow *flow, uint32_t buffer_id, uint8_t table_id, - uint16_t idle_timeout, size_t actions_len) -{ - struct ofp_instruction_actions *oia; - size_t instruction_len = sizeof *oia + actions_len; - struct ofpbuf *out = make_flow_mod(OFPFC_ADD, table_id, - flow, instruction_len); - struct ofp_flow_mod *ofm = out->data; - ofm->idle_timeout = htons(idle_timeout); - ofm->hard_timeout = htons(OFP_FLOW_PERMANENT); - ofm->buffer_id = htonl(buffer_id); - /* Use a single apply-actions for now - Jean II */ - oia = ofpbuf_put_zeros(out, sizeof *oia); - oia->type = htons(OFPIT_APPLY_ACTIONS); - oia->len = htons(instruction_len); - return out; -} - - - -struct ofpbuf * -make_del_flow(const struct flow *flow, uint8_t table_id) -{ - struct ofpbuf *out = make_flow_mod(OFPFC_DELETE_STRICT, table_id, flow, 0); - struct ofp_flow_mod *ofm = out->data; - ofm->out_port = htonl(OFPP_ANY); - return out; -} - - -struct ofpbuf * -make_add_simple_flow(const struct flow *flow, - uint32_t buffer_id, uint32_t out_port, - uint16_t idle_timeout) -{ - if (out_port != OFPP_ANY) { - struct ofp_action_output *oao; - struct ofpbuf *buffer; - - buffer = make_add_flow(flow, buffer_id, 0x00, idle_timeout, sizeof *oao); - oao = ofpbuf_put_zeros(buffer, sizeof *oao); - oao->type = htons(OFPAT_OUTPUT); - oao->len = htons(sizeof *oao); - oao->port = htonl(out_port); - return buffer; - } else { - return make_add_flow(flow, buffer_id, 0, idle_timeout, 0); - } -} - - - -struct ofpbuf * -make_packet_out(const struct ofpbuf *packet, uint32_t buffer_id, - uint32_t in_port, - const struct ofp_action_header *actions, size_t n_actions) -{ - size_t actions_len = n_actions * sizeof *actions; - struct ofp_packet_out *opo; - size_t size = sizeof *opo + actions_len + (packet ? packet->size : 0); - struct ofpbuf *out = ofpbuf_new(size); - - opo = ofpbuf_put_uninit(out, sizeof *opo); - opo->header.version = OFP_VERSION; - opo->header.type = OFPT_PACKET_OUT; - opo->header.length = htons(size); - opo->header.xid = htonl(0); - opo->buffer_id = htonl(buffer_id); - opo->in_port = htonl(in_port); - opo->actions_len = htons(actions_len); - ofpbuf_put(out, actions, actions_len); - if (packet) { - ofpbuf_put(out, packet->data, packet->size); - } - return out; -} - - -struct ofpbuf * -make_unbuffered_packet_out(const struct ofpbuf *packet, - uint32_t in_port, uint32_t out_port) -{ - struct ofp_action_output action; - action.type = htons(OFPAT_OUTPUT); - action.len = htons(sizeof action); - action.port = htonl(out_port); - return make_packet_out(packet, UINT32_MAX, in_port, - (struct ofp_action_header *) &action, 1); -} - -struct ofpbuf * -make_buffered_packet_out(uint32_t buffer_id, - uint32_t in_port, uint32_t out_port) -{ - if (out_port != OFPP_ANY) { - struct ofp_action_output action; - action.type = htons(OFPAT_OUTPUT); - action.len = htons(sizeof action); - action.port = htonl(out_port); - return make_packet_out(NULL, buffer_id, in_port, - (struct ofp_action_header *) &action, 1); - } else { - return make_packet_out(NULL, buffer_id, in_port, NULL, 0); - } -} - - -/* Creates and returns an OFPT_ECHO_REQUEST message with an empty payload. */ -struct ofpbuf * -make_echo_request(void) -{ - struct ofp_header *rq; - struct ofpbuf *out = ofpbuf_new(sizeof *rq); - rq = ofpbuf_put_uninit(out, sizeof *rq); - rq->version = OFP_VERSION; - rq->type = OFPT_ECHO_REQUEST; - rq->length = htons(sizeof *rq); - rq->xid = alloc_xid(); - return out; -} - -/* Creates and returns an OFPT_ECHO_REPLY message matching the - * OFPT_ECHO_REQUEST message in 'rq'. */ -struct ofpbuf * -make_echo_reply(const struct ofp_header *rq) -{ - size_t size = ntohs(rq->length); - struct ofpbuf *out = ofpbuf_new(size); - struct ofp_header *reply = ofpbuf_put(out, rq, size); - reply->type = OFPT_ECHO_REPLY; - return out; -} - - -static int -check_message_type(uint8_t got_type, uint8_t want_type) -{ - if (got_type != want_type) { - VLOG_WARN(LOG_MODULE, "received bad message type %d (expected %d)", - got_type, want_type); - return ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_BAD_TYPE);; - } - return 0; -} - -/* Checks that 'msg' has type 'type' and that it is exactly 'size' bytes long. - * Returns 0 if the checks pass, otherwise an OpenFlow error code (produced - * with ofp_mkerr()). */ -int -check_ofp_message(const struct ofp_header *msg, uint8_t type, size_t size) -{ - size_t got_size; - int error; - - error = check_message_type(msg->type, type); - if (error) { - return error; - } - - got_size = ntohs(msg->length); - if (got_size != size) { - VLOG_WARN(LOG_MODULE, "received %d message of length %zu (expected %zu)", - type, got_size, size); - return ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_BAD_LEN); - } - - return 0; -} - -/* Checks that 'inst' has type 'type' and that 'inst' is 'size' plus a - * nonnegative integer multiple of 'array_elt_size' bytes long. Returns 0 if - * the checks pass, otherwise an OpenFlow error code (produced with - * ofp_mkerr()). - * - * If 'n_array_elts' is nonnull, then '*n_array_elts' is set to the number of - * 'array_elt_size' blocks in 'msg' past the first 'min_size' bytes, when - * successful. */ -int -check_ofp_instruction_array(const struct ofp_instruction *inst, uint8_t type, - size_t min_size, size_t array_elt_size, - size_t *n_array_elts) -{ - size_t got_size; - - assert(array_elt_size); - - if (ntohs(inst->type) != type) { - VLOG_WARN(LOG_MODULE, "received bad instruction type %X (expected %X)", - ntohs(inst->type), type); - return ofp_mkerr(OFPET_BAD_INSTRUCTION, OFPBIC_UNSUP_INST); - } - - got_size = ntohs(inst->len); - if (got_size < min_size) { - VLOG_WARN(LOG_MODULE, "received %X instruction of length %zu " - "(expected at least %zu)", - type, got_size, min_size); - return ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_BAD_LEN); - } - if ((got_size - min_size) % array_elt_size) { - VLOG_WARN(LOG_MODULE, "received %X message of bad length %zu: the " - "excess over %zu (%zu) is not evenly divisible by %zu " - "(remainder is %zu)", - type, got_size, min_size, got_size - min_size, - array_elt_size, (got_size - min_size) % array_elt_size); - return ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_BAD_LEN);; - } - if (n_array_elts) { - *n_array_elts = (got_size - min_size) / array_elt_size; - } - return 0; -} - - -/* Checks that 'msg' has type 'type' and that 'msg' is 'size' plus a - * nonnegative integer multiple of 'array_elt_size' bytes long. Returns 0 if - * the checks pass, otherwise an OpenFlow error code (produced with - * ofp_mkerr()). - * - * If 'n_array_elts' is nonnull, then '*n_array_elts' is set to the number of - * 'array_elt_size' blocks in 'msg' past the first 'min_size' bytes, when - * successful. */ -int -check_ofp_message_array(const struct ofp_header *msg, uint8_t type, - size_t min_size, size_t array_elt_size, - size_t *n_array_elts) -{ - size_t got_size; - int error; - - assert(array_elt_size); - - error = check_message_type(msg->type, type); - if (error) { - return error; - } - - got_size = ntohs(msg->length); - if (got_size < min_size) { - VLOG_WARN(LOG_MODULE, "received %d message of length %zu " - "(expected at least %zu)", - type, got_size, min_size); - return ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_BAD_LEN); - } - if ((got_size - min_size) % array_elt_size) { - VLOG_WARN(LOG_MODULE, - "received %d message of bad length %zu: the " - "excess over %zu (%zu) is not evenly divisible by %zu " - "(remainder is %zu)", - type, got_size, min_size, got_size - min_size, - array_elt_size, (got_size - min_size) % array_elt_size); - return ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_BAD_LEN); - } - if (n_array_elts) { - *n_array_elts = (got_size - min_size) / array_elt_size; - } - return 0; -} - - -int -check_ofp_packet_out(const struct ofp_header *oh, struct ofpbuf *data, - int *n_actionsp, int max_ports) -{ - const struct ofp_packet_out *opo; - unsigned int actions_len, n_actions; - size_t extra; - int error; - - *n_actionsp = 0; - error = check_ofp_message_array(oh, OFPT_PACKET_OUT, - sizeof *opo, 1, &extra); - if (error) { - return error; - } - opo = (const struct ofp_packet_out *) oh; - - actions_len = ntohs(opo->actions_len); - if (actions_len > extra) { - VLOG_WARN(LOG_MODULE, "packet-out claims %u bytes of actions " - "but message has room for only %zu bytes", - actions_len, extra); - return ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_BAD_LEN); - } - if (actions_len % sizeof(union ofp_action)) { - VLOG_WARN(LOG_MODULE, "packet-out claims %u bytes of actions, " - "which is not a multiple of %zu", - actions_len, sizeof(union ofp_action)); - return ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_BAD_LEN); - } - - n_actions = actions_len / sizeof(union ofp_action); - error = validate_actions((const union ofp_action *) opo->actions, - n_actions, max_ports, true); - if (error) { - return error; - } - - data->data = (void *) &opo->actions[n_actions]; - data->size = extra - actions_len; - *n_actionsp = n_actions; - return 0; -} - -/*const struct ofp_flow_stats */ -const struct ofp_flow_stats * -flow_stats_first(struct flow_stats_iterator *iter, - const struct ofp_stats_reply *osr) -{ - iter->pos = osr->body; - iter->end = osr->body + (ntohs(osr->header.length) - - offsetof(struct ofp_stats_reply, body)); - return flow_stats_next(iter); -} - -/*const struct ofp_flow_stats */ -const struct ofp_flow_stats * -flow_stats_next(struct flow_stats_iterator *iter) -{ - static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5); - ptrdiff_t bytes_left = iter->end - iter->pos; - const struct ofp_flow_stats *fs; - size_t length; - - if (bytes_left < sizeof *fs) { - if (bytes_left != 0) { - VLOG_WARN_RL(LOG_MODULE, &rl, "%td leftover bytes in flow stats reply", - bytes_left); - } - return NULL; - } - - fs = (const void *) iter->pos; - length = ntohs(fs->length); - if (length < sizeof *fs) { - VLOG_WARN_RL(LOG_MODULE, &rl, "flow stats length %zu is shorter than min %zu", - length, sizeof *fs); - return NULL; - } else if (length > bytes_left) { - VLOG_WARN_RL(LOG_MODULE, &rl, "flow stats length %zu but only %td bytes left", - length, bytes_left); - return NULL; - } - /* TODO: Change instructions - else if ((length - sizeof *fs) % sizeof fs->instructions[0]) { - VLOG_WARN_RL(LOG_MODULE, &rl, "flow stats length %zu has %zu bytes " - "left over in final action", length, - (length - sizeof *fs) % sizeof fs->instructions[0]); - return NULL; - }*/ - iter->pos += length; - return fs; -} - -/* Alignment of ofp_actions. */ -#define ACTION_ALIGNMENT 8 - - -static int -check_action_exact_len(const union ofp_action *a, unsigned int len, - unsigned int required_len) -{ - if (len != required_len) { - VLOG_DBG(LOG_MODULE, "action %u has invalid length %"PRIu16" (must be %u)\n", - a->type, ntohs(a->header.len), required_len); - return ofp_mkerr(OFPET_BAD_ACTION, OFPBAC_BAD_LEN); - } - return 0; -} - -/* Checks that 'port' is a valid output port for the OFPAT_OUTPUT action, given - * that the switch will never have more than 'max_ports' ports. Returns 0 if - * 'port' is valid, otherwise an ofp_mkerr() return code.*/ -static int -check_output_port(uint32_t port, int max_ports, bool table_allowed) -{ - switch (port) { - case OFPP_IN_PORT: - case OFPP_NORMAL: - case OFPP_FLOOD: - case OFPP_ALL: - case OFPP_CONTROLLER: - case OFPP_LOCAL: - return 0; - - case OFPP_TABLE: - if (table_allowed) { - return 0; - } else { - return ofp_mkerr(OFPET_BAD_ACTION, OFPBAC_BAD_OUT_PORT); - } - - default: - if (port < max_ports) { - return 0; - } - VLOG_WARN(LOG_MODULE, "unknown output port %x", port); - return ofp_mkerr(OFPET_BAD_ACTION, OFPBAC_BAD_OUT_PORT);; - } -} - -/* Checks that 'action' is a valid OFPAT_ENQUEUE action, given that the switch - * will never have more than 'max_ports' ports. Returns 0 if 'port' is valid, - * otherwise an ofp_mkerr() return code.*/ -static int -check_setqueue_action(const union ofp_action *a, unsigned int len) -{ - const struct ofp_action_set_queue *oaq; - int error; - - error = check_action_exact_len(a, len, 8); - if (error) { - return error; - } - - oaq = (const struct ofp_action_set_queue *) a; - return 0; -} - -static int -check_nicira_action(const union ofp_action *a, unsigned int len) -{ - const struct nx_action_header *nah; - - if (len < 16) { - VLOG_DBG(LOG_MODULE, "Nicira vendor action only %u bytes", len); - return ofp_mkerr(OFPET_BAD_ACTION, OFPBAC_BAD_LEN);; - } - nah = (const struct nx_action_header *) a; - - switch (ntohs(nah->subtype)) { - case NXAST_RESUBMIT: - case NXAST_SET_TUNNEL: - return check_action_exact_len(a, len, 16); - default: - return ofp_mkerr(OFPET_BAD_ACTION, OFPBAC_BAD_EXPERIMENTER); - } -} - -static int -check_action(const union ofp_action *a, unsigned int len, int max_ports, - bool is_packet_out) -{ - int error; - - switch (ntohs(a->type)) { - case OFPAT_OUTPUT: { - const struct ofp_action_output *oao; - error = check_action_exact_len(a, len, 16); - if (error) { - return error; - } - oao = (const struct ofp_action_output *) a; - return check_output_port(ntohl(oao->port), max_ports, is_packet_out); - } - - - case OFPAT_EXPERIMENTER: - return (a->experimenter.experimenter == htonl(NX_VENDOR_ID) - ? check_nicira_action(a, len) - : ofp_mkerr(OFPET_BAD_ACTION, OFPBAC_BAD_EXPERIMENTER)); - - case OFPAT_SET_QUEUE: - return check_setqueue_action(a, len); - - default: - VLOG_WARN(LOG_MODULE, "unknown action type %"PRIu16, - ntohs(a->type)); - return ofp_mkerr(OFPET_BAD_ACTION, OFPBAC_BAD_TYPE); - } -} - -int -validate_actions(const union ofp_action *actions, size_t n_actions, - int max_ports, bool is_packet_out) -{ - const union ofp_action *a; - - for (a = actions; a < &actions[n_actions]; ) { - unsigned int len = ntohs(a->header.len); - unsigned int n_slots = len / ACTION_ALIGNMENT; - unsigned int slots_left = &actions[n_actions] - a; - int error; - - if (n_slots > slots_left) { - VLOG_DBG(LOG_MODULE, - "action requires %u slots but only %u remain", - n_slots, slots_left); - return ofp_mkerr(OFPET_BAD_ACTION, OFPBAC_BAD_LEN); - } else if (!len) { - VLOG_DBG(LOG_MODULE, "action has invalid length 0"); - return ofp_mkerr(OFPET_BAD_ACTION, OFPBAC_BAD_LEN); - } else if (len % ACTION_ALIGNMENT) { - VLOG_DBG(LOG_MODULE, "action length %u is not a multiple " - "of %d", len, ACTION_ALIGNMENT); - return ofp_mkerr(OFPET_BAD_ACTION, OFPBAC_BAD_LEN); - } - - error = check_action(a, len, max_ports, is_packet_out); - if (error) { - return error; - } - a += n_slots; - } - return 0; -} - -/* Returns true if 'action' outputs to 'port' (which must be in network byte - * order), false otherwise. */ -bool -action_outputs_to_port(const union ofp_action *action, uint32_t port) -{ - switch (ntohs(action->type)) { - case OFPAT_OUTPUT: { - const struct ofp_action_output *oao; - oao = (const struct ofp_action_output *) action; - return oao->port == port; - } - default: - return false; - } -} - -/* The set of actions must either come from a trusted source or have been - * previously validated with validate_actions().*/ -const union ofp_action * -actions_first(struct actions_iterator *iter, - const union ofp_action *oa, size_t n_actions) -{ - iter->pos = oa; - iter->end = oa + n_actions; - return actions_next(iter); -} - -const union ofp_action * -actions_next(struct actions_iterator *iter) -{ - if (iter->pos < iter->end) { - const union ofp_action *a = iter->pos; - unsigned int len = ntohs(a->header.len); - iter->pos += len / ACTION_ALIGNMENT; - return a; - } else { - return NULL; - } -} - - - diff --git a/lib/ofp.h~ b/lib/ofp.h~ deleted file mode 100644 index eca9ab94..00000000 --- a/lib/ofp.h~ +++ /dev/null @@ -1,140 +0,0 @@ -/* Copyright (c) 2008, 2009 The Board of Trustees of The Leland Stanford - * Junior University - * - * We are making the OpenFlow specification and associated documentation - * (Software) available for public use and benefit with the expectation - * that others will use, modify and enhance the Software and contribute - * those enhancements back to the community. However, since we would - * like to make the Software available for broadest use, with as few - * restrictions as possible permission is hereby granted, free of - * charge, to any person obtaining a copy of this Software to deal in - * the Software under the copyrights without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * - * The name and trademarks of copyright holder(s) may NOT be used in - * advertising or publicity pertaining to the Software or any - * derivatives without specific, written prior permission. - */ - -/* Zoltan: - * During the move to OpenFlow 1.1 parts of the code was taken from - * the following repository, with the license below: - * git://openflow.org/of1.1-spec-test.git (lib/ofp-util.h) - */ -/* - * Copyright (c) 2008, 2009, 2010 Nicira Networks. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -#ifndef OFP_H -#define OFP_H 1 - -#include -#include -#include -#include -#include "ofpbuf.h" -#include "flow.h" -#include "../include/openflow/openflow.h" - -/* OpenFlow protocol utility functions. */ -void *make_openflow(size_t openflow_len, uint8_t type, struct ofpbuf **); -void *make_openflow_xid(size_t openflow_len, uint8_t type, - uint32_t xid, struct ofpbuf **); -void *put_openflow(size_t openflow_len, uint8_t type, struct ofpbuf *); -void *put_openflow_xid(size_t openflow_len, uint8_t type, uint32_t xid, - struct ofpbuf *); -void update_openflow_length(struct ofpbuf *); -void update_instruction_length(struct ofpbuf *, size_t oia_offset); -struct ofpbuf *make_flow_mod(uint8_t command, uint8_t table_id, - const struct flow *, size_t actions_len); -struct ofpbuf *make_add_flow(const struct flow *, uint32_t buffer_id, - uint8_t table_id, - uint16_t max_idle, size_t actions_len); -struct ofpbuf *make_del_flow(const struct flow *, uint8_t table_id); -struct ofpbuf *make_add_simple_flow(const struct flow *, - uint32_t buffer_id, uint32_t out_port, - uint16_t max_idle); - -struct ofpbuf *make_packet_out(const struct ofpbuf *packet, uint32_t buffer_id, - uint32_t in_port, - const struct ofp_action_header *, - size_t n_actions); -struct ofpbuf *make_buffered_packet_out(uint32_t buffer_id, - uint32_t in_port, uint32_t out_port); -struct ofpbuf *make_unbuffered_packet_out(const struct ofpbuf *packet, - uint32_t in_port, uint32_t out_port); -struct ofpbuf *make_echo_request(void); -struct ofpbuf *make_echo_reply(const struct ofp_header *rq); -int check_ofp_message(const struct ofp_header *, uint8_t type, size_t size); -int check_ofp_instruction_array(const struct ofp_instruction *, uint8_t type, - size_t size, size_t array_elt_size, - size_t *n_array_elts); -int check_ofp_message_array(const struct ofp_header *, uint8_t type, - size_t size, size_t array_elt_size, - size_t *n_array_elts); -int check_ofp_packet_out(const struct ofp_header *, struct ofpbuf *data, - int *n_actions, int max_ports); - -struct flow_stats_iterator { - const uint8_t *pos, *end; -}; -const struct ofp_flow_stats *flow_stats_first(struct flow_stats_iterator *, - const struct ofp_stats_reply *); -const struct ofp_flow_stats *flow_stats_next(struct flow_stats_iterator *); - -struct actions_iterator { - const union ofp_action *pos, *end; -}; -const union ofp_action *actions_first(struct actions_iterator *, - const union ofp_action *, - size_t n_actions); -const union ofp_action *actions_next(struct actions_iterator *); -int validate_actions(const union ofp_action *, size_t n_actions, - int max_ports, bool is_packet_out); -bool action_outputs_to_port(const union ofp_action *, uint32_t port); - - -static inline int -ofp_mkerr(uint16_t type, uint16_t code) -{ - assert(type > 0 && type <= 0x7fff); - return (type << 16) | code; -} - -/* Hack to get the action parser to do sort of the right stuff. */ -union ofp_action { - uint16_t type; - struct ofp_action_header header; - struct ofp_action_experimenter_header experimenter; -}; -OFP_ASSERT(sizeof(union ofp_action) == 8); - -#endif /* ofp.h */ diff --git a/lib/ofpstat.c.bak b/lib/ofpstat.c.bak deleted file mode 100644 index d14d70f2..00000000 --- a/lib/ofpstat.c.bak +++ /dev/null @@ -1,259 +0,0 @@ -/*- - * Copyright (c) 2008, 2009 - * The Board of Trustees of The Leland Stanford Junior University - * - * We are making the OpenFlow specification and associated documentation - * (Software) available for public use and benefit with the expectation that - * others will use, modify and enhance the Software and contribute those - * enhancements back to the community. However, since we would like to make the - * Software available for broadest use, with as few restrictions as possible - * permission is hereby granted, free of charge, to any person obtaining a copy - * of this Software to deal in the Software under the copyrights without - * restriction, including without limitation the rights to use, copy, modify, - * merge, publish, distribute, sublicense, and/or sell copies of the Software, - * and to permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - * - * The name and trademarks of copyright holder(s) may NOT be used in - * advertising or publicity pertaining to the Software or any derivatives - * without specific, written prior permission. - */ - -#include -#include - -#include "openflow/openflow.h" -#include "ofpstat.h" - -#define INC_IFP_STAT(ifps, tag) do {++(ifps)->tag;} while (0) - -static void inc_protocol_message(struct ofpstat *, struct ofp_header *); -static void inc_error_notification(struct ofpstat *, struct ofp_header *); -static void inc_flow_manipulation(struct ofpstat *, struct ofp_header *); - -static void -inc_protocol_message(struct ofpstat *ifps, struct ofp_header *hdr) -{ - switch (hdr->type) { - case OFPT_HELLO: - INC_IFP_STAT(ifps, ofps_hello); - break; - case OFPT_ERROR: - INC_IFP_STAT(ifps, ofps_error); - break; - case OFPT_ECHO_REQUEST: - INC_IFP_STAT(ifps, ofps_echo_request); - break; - case OFPT_ECHO_REPLY: - INC_IFP_STAT(ifps, ofps_echo_reply); - break; - case OFPT_VENDOR: - INC_IFP_STAT(ifps, ofps_vendor); - break; - case OFPT_FEATURES_REQUEST: - INC_IFP_STAT(ifps, ofps_feats_request); - break; - case OFPT_FEATURES_REPLY: - INC_IFP_STAT(ifps, ofps_feats_reply); - break; - case OFPT_GET_CONFIG_REQUEST: - INC_IFP_STAT(ifps, ofps_get_config_request); - break; - case OFPT_GET_CONFIG_REPLY: - INC_IFP_STAT(ifps, ofps_get_config_reply); - break; - case OFPT_SET_CONFIG: - INC_IFP_STAT(ifps, ofps_set_config); - break; - case OFPT_PACKET_IN: - INC_IFP_STAT(ifps, ofps_packet_in); - break; - case OFPT_FLOW_REMOVED: - INC_IFP_STAT(ifps, ofps_flow_removed); - break; - case OFPT_PORT_STATUS: - INC_IFP_STAT(ifps, ofps_port_status); - break; - case OFPT_PACKET_OUT: - INC_IFP_STAT(ifps, ofps_packet_out); - break; - case OFPT_FLOW_MOD: - INC_IFP_STAT(ifps, ofps_flow_mod); - break; - case OFPT_PORT_MOD: - INC_IFP_STAT(ifps, ofps_port_mod); - break; - case OFPT_MULTIPART_REQUEST: - INC_IFP_STAT(ifps, ofps_stats_request); - break; - case OFPT_MULTIPART_REPLY: - INC_IFP_STAT(ifps, ofps_stats_reply); - break; - case OFPT_BARRIER_REQUEST: - INC_IFP_STAT(ifps, ofps_barrier_request); - break; - case OFPT_BARRIER_REPLY: - INC_IFP_STAT(ifps, ofps_barrier_reply); - break; - default: - INC_IFP_STAT(ifps, ofps_unknown); - break; - } -} - -static void -inc_error_notification(struct ofpstat *ifps, struct ofp_header *hdr) -{ - struct ofp_error_msg *errmsg = (struct ofp_error_msg *)hdr; - uint16_t errtype = ntohs(errmsg->type); - uint16_t errcode = ntohs(errmsg->code); - - switch (errtype) { - case OFPET_HELLO_FAILED: - INC_IFP_STAT(ifps, ofps_error_type.hello_fail); - switch (errcode) { - case OFPHFC_INCOMPATIBLE: - INC_IFP_STAT(ifps, ofps_error_code.hf_incompat); - break; - case OFPHFC_EPERM: - INC_IFP_STAT(ifps, ofps_error_code.hf_eperm); - break; - default: - INC_IFP_STAT(ifps, ofps_error_code.unknown); - break; - } - break; - case OFPET_BAD_REQUEST: - INC_IFP_STAT(ifps, ofps_error_type.bad_request); - switch (errcode) { - case OFPBRC_BAD_VERSION: - INC_IFP_STAT(ifps, ofps_error_code.br_bad_version); - break; - case OFPBRC_BAD_TYPE: - INC_IFP_STAT(ifps, ofps_error_code.br_bad_type); - break; - case OFPBRC_BAD_STAT: - INC_IFP_STAT(ifps, ofps_error_code.br_bad_stat); - break; - case OFPBRC_BAD_VENDOR: - INC_IFP_STAT(ifps, ofps_error_code.br_bad_vendor); - break; - case OFPBRC_EPERM: - INC_IFP_STAT(ifps, ofps_error_code.br_eperm); - break; - default: - INC_IFP_STAT(ifps, ofps_error_code.unknown); - break; - } - break; - case OFPET_BAD_ACTION: - INC_IFP_STAT(ifps, ofps_error_type.bad_action); - switch (errcode) { - case OFPBAC_BAD_TYPE: - INC_IFP_STAT(ifps, ofps_error_code.ba_bad_type); - break; - case OFPBAC_BAD_LEN: - INC_IFP_STAT(ifps, ofps_error_code.ba_bad_len); - break; - case OFPBAC_BAD_VENDOR: - INC_IFP_STAT(ifps, ofps_error_code.ba_bad_vendor); - break; - case OFPBAC_BAD_VENDOR_TYPE: - INC_IFP_STAT(ifps, ofps_error_code.ba_bad_vendor_type); - break; - case OFPBAC_BAD_OUT_PORT: - INC_IFP_STAT(ifps, ofps_error_code.ba_bad_out_port); - break; - case OFPBAC_BAD_ARGUMENT: - INC_IFP_STAT(ifps, ofps_error_code.ba_bad_argument); - break; - case OFPBAC_EPERM: - INC_IFP_STAT(ifps, ofps_error_code.ba_eperm); - break; - default: - INC_IFP_STAT(ifps, ofps_error_code.unknown); - break; - } - break; - case OFPET_FLOW_MOD_FAILED: - INC_IFP_STAT(ifps, ofps_error_type.flow_mod_fail); - switch (errcode) { - case OFPFMFC_ALL_TABLES_FULL: - INC_IFP_STAT(ifps, ofps_error_code.fmf_all_tables_full); - break; - case OFPFMFC_OVERLAP: - INC_IFP_STAT(ifps, ofps_error_code.fmf_overlap); - break; - case OFPFMFC_EPERM: - INC_IFP_STAT(ifps, ofps_error_code.fmf_eperm); - break; - case OFPFMFC_BAD_EMERG_TIMEOUT: - INC_IFP_STAT(ifps, ofps_error_code.fmf_emerg); - break; - default: - INC_IFP_STAT(ifps, ofps_error_code.unknown); - break; - } - break; - default: - INC_IFP_STAT(ifps, ofps_error_type.unknown); - break; - } -} - -static void -inc_flow_manipulation(struct ofpstat *ifps, struct ofp_header *hdr) -{ - struct ofp_flow_mod *flowmodmsg = (struct ofp_flow_mod *)hdr; - uint16_t flowmodops = ntohs(flowmodmsg->command); - - switch (flowmodops) { - case OFPFC_ADD: - INC_IFP_STAT(ifps, ofps_flow_mod_ops.add); - break; - case OFPFC_MODIFY: - INC_IFP_STAT(ifps, ofps_flow_mod_ops.modify); - break; - case OFPFC_MODIFY_STRICT: - INC_IFP_STAT(ifps, ofps_flow_mod_ops.modify_strict); - break; - case OFPFC_DELETE: - INC_IFP_STAT(ifps, ofps_flow_mod_ops.delete); - break; - case OFPFC_DELETE_STRICT: - INC_IFP_STAT(ifps, ofps_flow_mod_ops.delete_strict); - break; - default: - INC_IFP_STAT(ifps, ofps_flow_mod_ops.unknown); - break; - } -} - -void -ofpstat_inc_protocol_stat(struct ofpstat *ifps, struct ofp_header *hdr) -{ - ++ifps->ofps_total; - inc_protocol_message(ifps, hdr); - - switch (hdr->type) { - case OFPT_ERROR: - inc_error_notification(ifps, hdr); - break; - case OFPT_FLOW_MOD: - inc_flow_manipulation(ifps, hdr); - break; - default: - break; - } -} diff --git a/lib/ofpstat.h.bak b/lib/ofpstat.h.bak deleted file mode 100644 index c7e21dde..00000000 --- a/lib/ofpstat.h.bak +++ /dev/null @@ -1,102 +0,0 @@ -/*- - * Copyright (c) 2008, 2009 - * The Board of Trustees of The Leland Stanford Junior University - * - * We are making the OpenFlow specification and associated documentation - * (Software) available for public use and benefit with the expectation that - * others will use, modify and enhance the Software and contribute those - * enhancements back to the community. However, since we would like to make the - * Software available for broadest use, with as few restrictions as possible - * permission is hereby granted, free of charge, to any person obtaining a copy - * of this Software to deal in the Software under the copyrights without - * restriction, including without limitation the rights to use, copy, modify, - * merge, publish, distribute, sublicense, and/or sell copies of the Software, - * and to permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - * - * The name and trademarks of copyright holder(s) may NOT be used in - * advertising or publicity pertaining to the Software or any derivatives - * without specific, written prior permission. - */ - -#ifndef OFPSTAT_H_ -#define OFPSTAT_H_ - -struct ofp_header; - -struct ofpstat { - uint64_t ofps_total; - uint64_t ofps_unknown; - - uint64_t ofps_hello; - uint64_t ofps_error; - struct { - uint64_t hello_fail; - uint64_t bad_request; - uint64_t bad_action; - uint64_t flow_mod_fail; - uint64_t unknown; - } ofps_error_type; - struct { - uint64_t hf_incompat; - uint64_t hf_eperm; - uint64_t br_bad_version; - uint64_t br_bad_type; - uint64_t br_bad_stat; - uint64_t br_bad_vendor; - uint64_t br_eperm; - uint64_t ba_bad_type; - uint64_t ba_bad_len; - uint64_t ba_bad_vendor; - uint64_t ba_bad_vendor_type; - uint64_t ba_bad_out_port; - uint64_t ba_bad_argument; - uint64_t ba_eperm; - uint64_t fmf_all_tables_full; - uint64_t fmf_overlap; - uint64_t fmf_eperm; - uint64_t fmf_emerg; - uint64_t unknown; - } ofps_error_code; - uint64_t ofps_echo_request; - uint64_t ofps_echo_reply; - uint64_t ofps_vendor; - uint64_t ofps_feats_request; - uint64_t ofps_feats_reply; - uint64_t ofps_get_config_request; - uint64_t ofps_get_config_reply; - uint64_t ofps_set_config; - uint64_t ofps_packet_in; - uint64_t ofps_flow_removed; - uint64_t ofps_port_status; - uint64_t ofps_packet_out; - uint64_t ofps_flow_mod; - struct { - uint64_t add; - uint64_t modify; - uint64_t modify_strict; - uint64_t delete; - uint64_t delete_strict; - uint64_t unknown; - } ofps_flow_mod_ops; - uint64_t ofps_port_mod; - uint64_t ofps_stats_request; - uint64_t ofps_stats_reply; - uint64_t ofps_barrier_request; - uint64_t ofps_barrier_reply; -}; - -void ofpstat_inc_protocol_stat(struct ofpstat *, struct ofp_header *); - -#endif diff --git a/lib/packets.h b/lib/packets.h index 0868c424..8e166ea1 100644 --- a/lib/packets.h +++ b/lib/packets.h @@ -104,7 +104,7 @@ static inline bool eth_addr_is_reserved(const uint8_t ea[ETH_ADDR_LEN]) } #define ETH_ADDR_FMT \ - "%02"PRIx8":%02"PRIx8":%02"PRIx8":%02"PRIx8":%02"PRIx8":%02"PRIx8 + "%02" PRIx8 ":%02" PRIx8 ":%02" PRIx8 ":%02" PRIx8 ":%02" PRIx8 ":%02" PRIx8 #define ETH_ADDR_ARGS(ea) \ (ea)[0], (ea)[1], (ea)[2], (ea)[3], (ea)[4], (ea)[5] @@ -198,7 +198,7 @@ BUILD_ASSERT_DECL(VLAN_ETH_HEADER_LEN == sizeof(struct vlan_eth_header)); * argument of a comma expression, but it makes sure that 'ip' is a pointer. * This is useful since a common mistake is to pass an integer instead of a * pointer to IP_ARGS. */ -#define IP_FMT "%"PRIu8".%"PRIu8".%"PRIu8".%"PRIu8 +#define IP_FMT "%" PRIu8 ".%" PRIu8 ".%" PRIu8 ".%" PRIu8 #define IP_ARGS(ip) \ ((void) (ip)[0], ((uint8_t *) ip)[0]), \ ((uint8_t *) ip)[1], \ @@ -221,8 +221,7 @@ BUILD_ASSERT_DECL(VLAN_ETH_HEADER_LEN == sizeof(struct vlan_eth_header)); -#define IP_VERSION 4 - +#define IPV4_VERSION 4 #define IP_DONT_FRAGMENT 0x4000 /* Don't fragment. */ #define IP_MORE_FRAGMENTS 0x2000 /* More fragments. */ #define IP_FRAG_OFF_MASK 0x1fff /* Fragment offset. */ @@ -259,8 +258,12 @@ BUILD_ASSERT_DECL(IP_HEADER_LEN == sizeof(struct ip_header)); #define IPV6_TC(ipv6_ver_tc_fl) ((ipv6_ver_tc_fl) & 0xff00000) #define IPV6_FLABEL(ipv6_ver_tc_fl) ((ipv6_ver_tc_fl) & 0xffff) -#define IPV6_FLABEL_MASK 0xfffff - +#define IPV6_VERSION 6 +#define IPV6_DSCP_MASK 0x0fc00000 +#define IPV6_DSCP_SHIFT 22 +#define IPV6_ECN_MASK 0x0003 +#define IPV6_ECN_SHIFT 20 +#define IPV6_FLABEL_MASK 0x000fffff #define IPV6_HEADER_LEN 40 struct ipv6_header { uint32_t ipv6_ver_tc_fl; @@ -301,12 +304,14 @@ struct ipv6_nd_header{ uint32_t reserved; struct in6_addr target_addr; }; +BUILD_ASSERT_DECL(IPV6_ND_HEADER_LEN == sizeof(struct ipv6_nd_header)); #define IPV6_ND_OPT_HD_LEN 2 struct ipv6_nd_options_hd{ uint8_t type; uint8_t length; }; +BUILD_ASSERT_DECL(IPV6_ND_OPT_HD_LEN == sizeof(struct ipv6_nd_options_hd)); #define UDP_HEADER_LEN 8 struct udp_header { @@ -344,7 +349,7 @@ BUILD_ASSERT_DECL(TCP_HEADER_LEN == sizeof(struct tcp_header)); struct sctp_header { uint16_t sctp_src; uint16_t sctp_dst; - uint32_t sctp_verif; + uint32_t sctp_ver_tag; uint32_t sctp_csum; }; BUILD_ASSERT_DECL(SCTP_HEADER_LEN == sizeof(struct sctp_header)); @@ -376,6 +381,8 @@ struct qtag_prefix { uint16_t tci; }; + +#define PBB_ISID_LEN 3 #define PBB_HEADER_LEN 18 #define PBB_ISID_MASK 0xffffff diff --git a/lib/process.c b/lib/process.c index 38d3b022..d5d8df35 100644 --- a/lib/process.c +++ b/lib/process.c @@ -263,7 +263,10 @@ process_exited(struct process *p) return true; } else { char buf[_POSIX_PIPE_BUF]; - read(fds[0], buf, sizeof buf); + if (read(fds[0], buf, sizeof buf) != sizeof(buf)){ + fprintf(stderr, "read failed: %s\n", + strerror(errno)); + } return false; } } @@ -367,7 +370,10 @@ sigchld_handler(int signr UNUSED) } } } - write(fds[1], "", 1); + if (write(fds[1], "", 1) != 1){ + fprintf(stderr, "write failed: %s\n", + strerror(errno)); + } } static bool diff --git a/lib/queue.c b/lib/queue.c index 33e50067..24eb01d7 100644 --- a/lib/queue.c +++ b/lib/queue.c @@ -35,7 +35,6 @@ #include "queue.h" #include #include "compiler.h" -#include "leak-checker.h" #include "ofpbuf.h" static void check_queue(struct ofp_queue *q); @@ -91,7 +90,6 @@ void queue_push_tail(struct ofp_queue *q, struct ofpbuf *b) { check_queue(q); - leak_checker_claim(b); b->next = NULL; if (q->n++) { diff --git a/lib/rconn.c.bak b/lib/rconn.c.bak deleted file mode 100644 index a46b0b31..00000000 --- a/lib/rconn.c.bak +++ /dev/null @@ -1,985 +0,0 @@ -/* Copyright (c) 2008, 2009 The Board of Trustees of The Leland Stanford - * Junior University - * - * We are making the OpenFlow specification and associated documentation - * (Software) available for public use and benefit with the expectation - * that others will use, modify and enhance the Software and contribute - * those enhancements back to the community. However, since we would - * like to make the Software available for broadest use, with as few - * restrictions as possible permission is hereby granted, free of - * charge, to any person obtaining a copy of this Software to deal in - * the Software under the copyrights without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * - * The name and trademarks of copyright holder(s) may NOT be used in - * advertising or publicity pertaining to the Software or any - * derivatives without specific, written prior permission. - */ - -#include -#include "rconn.h" -#include -#include -#include -#include -#include -#include "ofp.h" -#include "ofpbuf.h" -#include "openflow/openflow.h" -#include "poll-loop.h" -#include "sat-math.h" -#include "timeval.h" -#include "util.h" -#include "vconn.h" -#include "vconn-provider.h" - -#define LOG_MODULE VLM_rconn -#include "vlog.h" - -#define STATES \ - STATE(VOID, 1 << 0) \ - STATE(BACKOFF, 1 << 1) \ - STATE(CONNECTING, 1 << 2) \ - STATE(ACTIVE, 1 << 3) \ - STATE(IDLE, 1 << 4) -enum state { -#define STATE(NAME, VALUE) S_##NAME = VALUE, - STATES -#undef STATE -}; - -static const char * -state_name(enum state state) -{ - switch (state) { -#define STATE(NAME, VALUE) case S_##NAME: return #NAME; - STATES -#undef STATE - } - return "***ERROR***"; -} - -/* A reliable connection to an OpenFlow switch or controller. - * - * See the large comment in rconn.h for more information. */ -struct rconn { - enum state state; - time_t state_entered; - - struct vconn *vconn; - char *name; - bool reliable; - - struct ofp_queue txq; - - int backoff; - int max_backoff; - time_t backoff_deadline; - time_t last_received; - time_t last_connected; - unsigned int packets_sent; - unsigned int seqno; - - /* In S_ACTIVE and S_IDLE, probably_admitted reports whether we believe - * that the peer has made a (positive) admission control decision on our - * connection. If we have not yet been (probably) admitted, then the - * connection does not reset the timer used for deciding whether the switch - * should go into fail-open mode. - * - * last_admitted reports the last time we believe such a positive admission - * control decision was made. */ - bool probably_admitted; - time_t last_admitted; - - /* These values are simply for statistics reporting, not used directly by - * anything internal to the rconn (or the secchan for that matter). */ - unsigned int packets_received; - unsigned int n_attempted_connections, n_successful_connections; - time_t creation_time; - unsigned long int total_time_connected; - - /* If we can't connect to the peer, it could be for any number of reasons. - * Usually, one would assume it is because the peer is not running or - * because the network is partitioned. But it could also be because the - * network topology has changed, in which case the upper layer will need to - * reassess it (in particular, obtain a new IP address via DHCP and find - * the new location of the controller). We set this flag when we suspect - * that this could be the case. */ - bool questionable_connectivity; - time_t last_questioned; - - /* Throughout this file, "probe" is shorthand for "inactivity probe". - * When nothing has been received from the peer for a while, we send out - * an echo request as an inactivity probe packet. We should receive back - * a response. */ - int probe_interval; /* Secs of inactivity before sending probe. */ - - /* Messages sent or received are copied to the monitor connections. */ -#define MAX_MONITORS 8 - struct vconn *monitors[8]; - size_t n_monitors; - - /* Protocol statistical informaition. */ - /* TODO Zoltan: Temporarily removed when moving to OpenFlow 1.1 */ - /* - struct ofpstat ofps_rcvd; - struct ofpstat ofps_sent; - */ - - uint32_t idle_echo_xid; -}; - -static unsigned int elapsed_in_this_state(const struct rconn *); -static unsigned int timeout(const struct rconn *); -static bool timed_out(const struct rconn *); -static void state_transition(struct rconn *, enum state); -static int try_send(struct rconn *); -static int reconnect(struct rconn *); -static void disconnect(struct rconn *, int error); -static void flush_queue(struct rconn *); -static void question_connectivity(struct rconn *); -static void copy_to_monitor(struct rconn *, const struct ofpbuf *); -static bool is_connected_state(enum state); -static bool is_admitted_msg(const struct ofpbuf *); - -/* Creates a new rconn, connects it (reliably) to 'name', and returns it. */ -struct rconn * -rconn_new(const char *name, int inactivity_probe_interval, int max_backoff) -{ - struct rconn *rc = rconn_create(inactivity_probe_interval, max_backoff); - rconn_connect(rc, name); - return rc; -} - -/* Creates a new rconn, connects it (unreliably) to 'vconn', and returns it. */ -struct rconn * -rconn_new_from_vconn(const char *name, struct vconn *vconn) -{ - struct rconn *rc = rconn_create(60, 0); - rconn_connect_unreliably(rc, name, vconn); - return rc; -} - -/* Creates and returns a new rconn. - * - * 'probe_interval' is a number of seconds. If the interval passes once - * without an OpenFlow message being received from the peer, the rconn sends - * out an "echo request" message. If the interval passes again without a - * message being received, the rconn disconnects and re-connects to the peer. - * Setting 'probe_interval' to 0 disables this behavior. - * - * 'max_backoff' is the maximum number of seconds between attempts to connect - * to the peer. The actual interval starts at 1 second and doubles on each - * failure until it reaches 'max_backoff'. If 0 is specified, the default of - * 60 seconds is used. */ -struct rconn * -rconn_create(int probe_interval, int max_backoff) -{ - struct rconn *rc = xcalloc(1, sizeof *rc); - - rc->state = S_VOID; - rc->state_entered = time_now(); - - rc->vconn = NULL; - rc->name = xstrdup("void"); - rc->reliable = false; - - queue_init(&rc->txq); - - rc->backoff = 0; - rc->max_backoff = max_backoff ? max_backoff : 60; - rc->backoff_deadline = TIME_MIN; - rc->last_received = time_now(); - rc->last_connected = time_now(); - rc->seqno = 0; - - rc->packets_sent = 0; - - rc->probably_admitted = false; - rc->last_admitted = time_now(); - - rc->packets_received = 0; - rc->n_attempted_connections = 0; - rc->n_successful_connections = 0; - rc->creation_time = time_now(); - rc->total_time_connected = 0; - - rc->questionable_connectivity = false; - rc->last_questioned = time_now(); - - rc->probe_interval = probe_interval ? MAX(1, probe_interval) : 0; - - rc->n_monitors = 0; - - /* TODO Zoltan: Temporarily removed when moving to OpenFlow 1.1 */ - /* - memset(&rc->ofps_rcvd, 0, sizeof(rc->ofps_rcvd)); - memset(&rc->ofps_sent, 0, sizeof(rc->ofps_sent)); - */ - - rc->idle_echo_xid = 0; - - return rc; -} - -int -rconn_connect(struct rconn *rc, const char *name) -{ - rconn_disconnect(rc); - free(rc->name); - rc->name = xstrdup(name); - rc->reliable = true; - return reconnect(rc); -} - -void -rconn_connect_unreliably(struct rconn *rc, - const char *name, struct vconn *vconn) -{ - assert(vconn != NULL); - rconn_disconnect(rc); - free(rc->name); - rc->name = xstrdup(name); - rc->reliable = false; - rc->vconn = vconn; - rc->last_connected = time_now(); - state_transition(rc, S_ACTIVE); -} - -void -rconn_disconnect(struct rconn *rc) -{ - if (rc->state != S_VOID) { - if (rc->vconn) { - vconn_close(rc->vconn); - rc->vconn = NULL; - } - free(rc->name); - rc->name = xstrdup("void"); - rc->reliable = false; - - rc->backoff = 0; - rc->backoff_deadline = TIME_MIN; - - state_transition(rc, S_VOID); - } -} - -/* Disconnects 'rc' and frees the underlying storage. */ -void -rconn_destroy(struct rconn *rc) -{ - if (rc) { - size_t i; - - free(rc->name); - vconn_close(rc->vconn); - flush_queue(rc); - queue_destroy(&rc->txq); - for (i = 0; i < rc->n_monitors; i++) { - vconn_close(rc->monitors[i]); - } - free(rc); - } -} - -static unsigned int -timeout_VOID(const struct rconn *rc UNUSED) -{ - return UINT_MAX; -} - -static void -run_VOID(struct rconn *rc UNUSED) -{ - /* Nothing to do. */ -} - -static int -reconnect(struct rconn *rc) -{ - int retval; - - VLOG_INFO(LOG_MODULE, "%s: connecting...", rc->name); - rc->n_attempted_connections++; - retval = vconn_open(rc->name, OFP_VERSION, &rc->vconn); - if (!retval) { - if (!vconn_is_reconnectable(rc->vconn)) { - rc->reliable = false; - } - rc->backoff_deadline = time_now() + rc->backoff; - state_transition(rc, S_CONNECTING); - } else { - VLOG_WARN(LOG_MODULE, "%s: connection failed (%s)", rc->name, strerror(retval)); - rc->backoff_deadline = TIME_MAX; /* Prevent resetting backoff. */ - disconnect(rc, 0); - } - return retval; -} - -static unsigned int -timeout_BACKOFF(const struct rconn *rc) -{ - return rc->backoff; -} - -static void -run_BACKOFF(struct rconn *rc) -{ - if (timed_out(rc)) { - reconnect(rc); - } -} - -static unsigned int -timeout_CONNECTING(const struct rconn *rc) -{ - return MAX(1, rc->backoff); -} - -static void -run_CONNECTING(struct rconn *rc) -{ - int retval = vconn_connect(rc->vconn); - if (!retval) { - VLOG_INFO(LOG_MODULE, "%s: connected", rc->name); - rc->n_successful_connections++; - state_transition(rc, S_ACTIVE); - rc->last_connected = rc->state_entered; - } else if (retval != EAGAIN) { - VLOG_INFO(LOG_MODULE, "%s: connection failed (%s)", rc->name, strerror(retval)); - disconnect(rc, retval); - } else if (timed_out(rc)) { - VLOG_INFO(LOG_MODULE, "%s: connection timed out", rc->name); - rc->backoff_deadline = TIME_MAX; /* Prevent resetting backoff. */ - disconnect(rc, 0); - } -} - -static void -do_tx_work(struct rconn *rc) -{ - if (!rc->txq.n) { - return; - } - while (rc->txq.n > 0) { - int error = try_send(rc); - if (error) { - break; - } - } - if (!rc->txq.n) { - poll_immediate_wake(); - } -} - -static unsigned int -timeout_ACTIVE(const struct rconn *rc) -{ - if (rc->probe_interval) { - unsigned int base = MAX(rc->last_received, rc->state_entered); - unsigned int arg = base + rc->probe_interval - rc->state_entered; - return arg; - } - return UINT_MAX; -} - -static void -run_ACTIVE(struct rconn *rc) -{ - if (timed_out(rc)) { - unsigned int base = MAX(rc->last_received, rc->state_entered); - VLOG_DBG(LOG_MODULE, "%s: idle %u seconds, sending inactivity probe", - rc->name, (unsigned int) (time_now() - base)); - - /* Ordering is important here: rconn_send() can transition to BACKOFF, - * and we don't want to transition back to IDLE if so, because then we - * can end up queuing a packet with vconn == NULL and then *boom*. */ - state_transition(rc, S_IDLE); - rconn_send(rc, make_echo_request(), NULL); - return; - } - - do_tx_work(rc); -} - -static unsigned int -timeout_IDLE(const struct rconn *rc) -{ - return rc->probe_interval; -} - -static void -run_IDLE(struct rconn *rc) -{ - if (timed_out(rc)) { - question_connectivity(rc); - VLOG_ERR(LOG_MODULE, "%s: no response to inactivity probe after %u " - "seconds, disconnecting", - rc->name, elapsed_in_this_state(rc)); - disconnect(rc, 0); - } else { - do_tx_work(rc); - } -} - -/* Performs whatever activities are necessary to maintain 'rc': if 'rc' is - * disconnected, attempts to (re)connect, backing off as necessary; if 'rc' is - * connected, attempts to send packets in the send queue, if any. */ -void -rconn_run(struct rconn *rc) -{ - int old_state; - do { - old_state = rc->state; - switch (rc->state) { -#define STATE(NAME, VALUE) case S_##NAME: run_##NAME(rc); break; - STATES -#undef STATE - default: - NOT_REACHED(); - } - } while (rc->state != old_state); -} - -/* Causes the next call to poll_block() to wake up when rconn_run() should be - * called on 'rc'. */ -void -rconn_run_wait(struct rconn *rc) -{ - unsigned int timeo = timeout(rc); - if (timeo != UINT_MAX) { - unsigned int expires = sat_add(rc->state_entered, timeo); - unsigned int remaining = sat_sub(expires, time_now()); - poll_timer_wait(sat_mul(remaining, 1000)); - } - - if ((rc->state & (S_ACTIVE | S_IDLE)) && rc->txq.n) { - vconn_wait(rc->vconn, WAIT_SEND); - } -} - -/* Attempts to receive a packet from 'rc'. If successful, returns the packet; - * otherwise, returns a null pointer. The caller is responsible for freeing - * the packet (with ofpbuf_delete()). */ -struct ofpbuf * -rconn_recv(struct rconn *rc) -{ - if (rc->state & (S_ACTIVE | S_IDLE)) { - struct ofpbuf *buffer; - int error = vconn_recv(rc->vconn, &buffer); - if (!error) { - struct ofp_header *h = buffer->data; - copy_to_monitor(rc, buffer); - if (is_admitted_msg(buffer) - || time_now() - rc->last_connected >= 30) { - rc->probably_admitted = true; - rc->last_admitted = time_now(); - } - rc->last_received = time_now(); - rc->packets_received++; - /* TODO Zoltan: Temporarily removed when moving to OpenFlow 1.1 */ - /* ofpstat_inc_protocol_stat(&rc->ofps_rcvd, h); */ - if (rc->state == S_IDLE) { - /* Check liveliness of a peer. */ - if (h->type == OFPT_ECHO_REPLY) { - if (rc->idle_echo_xid == 0) { - state_transition(rc, S_ACTIVE); - } else { - if (rc->idle_echo_xid == h->xid) - state_transition(rc, S_ACTIVE); - rc->idle_echo_xid = 0; - } - } else { - state_transition(rc, S_ACTIVE); - } - } - return buffer; - } else if (error != EAGAIN) { - disconnect(rc, error); - } - } - return NULL; -} - -/* Causes the next call to poll_block() to wake up when a packet may be ready - * to be received by vconn_recv() on 'rc'. */ -void -rconn_recv_wait(struct rconn *rc) -{ - if (rc->vconn) { - vconn_wait(rc->vconn, WAIT_RECV); - } -} - -/* Sends 'b' on 'rc'. Returns 0 if successful (in which case 'b' is - * destroyed), or ENOTCONN if 'rc' is not currently connected (in which case - * the caller retains ownership of 'b'). - * - * If 'n_queued' is non-null, then '*n_queued' will be incremented while the - * packet is in flight, then decremented when it has been sent (or discarded - * due to disconnection). Because 'b' may be sent (or discarded) before this - * function returns, the caller may not be able to observe any change in - * '*n_queued'. - * - * There is no rconn_send_wait() function: an rconn has a send queue that it - * takes care of sending if you call rconn_run(), which will have the side - * effect of waking up poll_block(). */ -int -rconn_send(struct rconn *rc, struct ofpbuf *b, int *n_queued) -{ - if (rconn_is_connected(rc)) { - copy_to_monitor(rc, b); - b->private_p = n_queued; - if (n_queued) { - ++*n_queued; - } - queue_push_tail(&rc->txq, b); - - /* If the queue was empty before we added 'b', try to send some - * packets. (But if the queue had packets in it, it's because the - * vconn is backlogged and there's no point in stuffing more into it - * now. We'll get back to that in rconn_run().) */ - if (rc->txq.n == 1) { - try_send(rc); - } - return 0; - } else { - return ENOTCONN; - } -} - -/* Sends 'b' on 'rc'. Increments '*n_queued' while the packet is in flight; it - * will be decremented when it has been sent (or discarded due to - * disconnection). Returns 0 if successful, EAGAIN if '*n_queued' is already - * at least as large as 'queue_limit', or ENOTCONN if 'rc' is not currently - * connected. Regardless of return value, 'b' is destroyed. - * - * Because 'b' may be sent (or discarded) before this function returns, the - * caller may not be able to observe any change in '*n_queued'. - * - * There is no rconn_send_wait() function: an rconn has a send queue that it - * takes care of sending if you call rconn_run(), which will have the side - * effect of waking up poll_block(). */ -int -rconn_send_with_limit(struct rconn *rc, struct ofpbuf *b, - int *n_queued, int queue_limit) -{ - int retval; - retval = *n_queued >= queue_limit ? EAGAIN : rconn_send(rc, b, n_queued); - if (retval) { - ofpbuf_delete(b); - } - return retval; -} - -/* Returns the total number of packets successfully sent on the underlying - * vconn. A packet is not counted as sent while it is still queued in the - * rconn, only when it has been successfuly passed to the vconn. */ -unsigned int -rconn_packets_sent(const struct rconn *rc) -{ - return rc->packets_sent; -} - -/* Adds 'vconn' to 'rc' as a monitoring connection, to which all messages sent - * and received on 'rconn' will be copied. 'rc' takes ownership of 'vconn'. */ -void -rconn_add_monitor(struct rconn *rc, struct vconn *vconn) -{ - if (rc->n_monitors < ARRAY_SIZE(rc->monitors)) { - VLOG_INFO(LOG_MODULE, "new monitor connection from %s", vconn_get_name(vconn)); - rc->monitors[rc->n_monitors++] = vconn; - } else { - VLOG_DBG(LOG_MODULE, "too many monitor connections, discarding %s", - vconn_get_name(vconn)); - vconn_close(vconn); - } -} - -/* Returns 'rc''s name (the 'name' argument passed to rconn_new()). */ -const char * -rconn_get_name(const struct rconn *rc) -{ - return rc->name; -} - -/* Returns true if 'rconn' is connected or in the process of reconnecting, - * false if 'rconn' is disconnected and will not reconnect on its own. */ -bool -rconn_is_alive(const struct rconn *rconn) -{ - return rconn->state != S_VOID; -} - -/* Returns true if 'rconn' is connected, false otherwise. */ -bool -rconn_is_connected(const struct rconn *rconn) -{ - return is_connected_state(rconn->state); -} - -/* Returns 0 if 'rconn' is connected. Otherwise, if 'rconn' is in a "failure - * mode" (that is, it is not connected), returns the number of seconds that it - * has been in failure mode, ignoring any times that it connected but the - * controller's admission control policy caused it to be quickly - * disconnected. */ -int -rconn_failure_duration(const struct rconn *rconn) -{ - return rconn_is_connected(rconn) ? 0 : time_now() - rconn->last_admitted; -} - -/* Returns the IP address of the peer, or 0 if the peer is not connected over - * an IP-based protocol or if its IP address is not known. */ -uint32_t -rconn_get_ip(const struct rconn *rconn) -{ - return rconn->vconn ? vconn_get_ip(rconn->vconn) : 0; -} - -/* If 'rconn' can't connect to the peer, it could be for any number of reasons. - * Usually, one would assume it is because the peer is not running or because - * the network is partitioned. But it could also be because the network - * topology has changed, in which case the upper layer will need to reassess it - * (in particular, obtain a new IP address via DHCP and find the new location - * of the controller). When this appears that this might be the case, this - * function returns true. It also clears the questionability flag and prevents - * it from being set again for some time. */ -bool -rconn_is_connectivity_questionable(struct rconn *rconn) -{ - bool questionable = rconn->questionable_connectivity; - rconn->questionable_connectivity = false; - return questionable; -} - -/* Returns the total number of packets successfully received by the underlying - * vconn. */ -unsigned int -rconn_packets_received(const struct rconn *rc) -{ - return rc->packets_received; -} - -/* Returns a string representing the internal state of 'rc'. The caller must - * not modify or free the string. */ -const char * -rconn_get_state(const struct rconn *rc) -{ - return state_name(rc->state); -} - -/* Returns the number of connection attempts made by 'rc', including any - * ongoing attempt that has not yet succeeded or failed. */ -unsigned int -rconn_get_attempted_connections(const struct rconn *rc) -{ - return rc->n_attempted_connections; -} - -/* Returns the number of successful connection attempts made by 'rc'. */ -unsigned int -rconn_get_successful_connections(const struct rconn *rc) -{ - return rc->n_successful_connections; -} - -/* Returns the time at which the last successful connection was made by - * 'rc'. */ -time_t -rconn_get_last_connection(const struct rconn *rc) -{ - return rc->last_connected; -} - -/* Returns the time at which 'rc' was created. */ -time_t -rconn_get_creation_time(const struct rconn *rc) -{ - return rc->creation_time; -} - -/* Returns the approximate number of seconds that 'rc' has been connected. */ -unsigned long int -rconn_get_total_time_connected(const struct rconn *rc) -{ - return (rc->total_time_connected - + (rconn_is_connected(rc) ? elapsed_in_this_state(rc) : 0)); -} - -/* Returns the current amount of backoff, in seconds. This is the amount of - * time after which the rconn will transition from BACKOFF to CONNECTING. */ -int -rconn_get_backoff(const struct rconn *rc) -{ - return rc->backoff; -} - -/* Returns the number of seconds spent in this state so far. */ -unsigned int -rconn_get_state_elapsed(const struct rconn *rc) -{ - return elapsed_in_this_state(rc); -} - -/* Returns 'rc''s current connection sequence number, a number that changes - * every time that 'rconn' connects or disconnects. */ -unsigned int -rconn_get_connection_seqno(const struct rconn *rc) -{ - return rc->seqno; -} - -/* Returns protocol statistical information. */ -/* TODO Zoltan: Temporarily removed when moving to OpenFlow 1.1 */ -/* -void -rconn_update_protocol_stat(struct rconn *rconn, - struct ofpstat *ofps_rcvd, - struct ofpstat *ofps_sent) -{ - struct vconn *vconn = rconn->vconn; - - if (vconn != NULL) { - rconn->ofps_rcvd.ofps_total += vconn->ofps_rcvd.ofps_total; - vconn->ofps_rcvd.ofps_total = 0; - rconn->ofps_rcvd.ofps_hello += vconn->ofps_rcvd.ofps_hello; - vconn->ofps_rcvd.ofps_hello = 0; - } - *ofps_rcvd = rconn->ofps_rcvd; - - if (vconn != NULL) { - rconn->ofps_sent.ofps_total += vconn->ofps_sent.ofps_total; - vconn->ofps_sent.ofps_total = 0; - rconn->ofps_sent.ofps_hello += vconn->ofps_sent.ofps_hello; - vconn->ofps_sent.ofps_hello = 0; - rconn->ofps_sent.ofps_error += vconn->ofps_sent.ofps_error; - vconn->ofps_sent.ofps_error = 0; - rconn->ofps_sent.ofps_error_type.hello_fail - += vconn->ofps_sent.ofps_error_type.hello_fail; - vconn->ofps_sent.ofps_error_type.hello_fail = 0; - rconn->ofps_sent.ofps_error_code.hf_incompat - += vconn->ofps_sent.ofps_error_code.hf_incompat; - vconn->ofps_sent.ofps_error_code.hf_incompat = 0; - } - *ofps_sent = rconn->ofps_sent; -} -*/ - -/* Tries to send a packet from 'rc''s send buffer. Returns 0 if successful, - * otherwise a positive errno value. */ -static int -try_send(struct rconn *rc) -{ - int retval = 0; - struct ofpbuf *next = rc->txq.head->next; - struct ofp_header *h = rc->txq.head->data; - int *n_queued = rc->txq.head->private_p; - /* TODO Zoltan: Temporarily removed when moving to OpenFlow 1.1 */ - /* ofpstat_inc_protocol_stat(&rc->ofps_sent, h); */ - rc->idle_echo_xid = h->xid; - retval = vconn_send(rc->vconn, rc->txq.head); - if (retval) { - rc->idle_echo_xid = 0; - if (retval != EAGAIN) { - disconnect(rc, retval); - } - return retval; - } - rc->packets_sent++; - if (n_queued) { - --*n_queued; - } - queue_advance_head(&rc->txq, next); - return 0; -} - -/* Disconnects 'rc'. 'error' is used only for logging purposes. If it is - * nonzero, then it should be EOF to indicate the connection was closed by the - * peer in a normal fashion or a positive errno value. */ -static void -disconnect(struct rconn *rc, int error) -{ - if (rc->reliable) { - time_t now = time_now(); - - if (rc->state & (S_CONNECTING | S_ACTIVE | S_IDLE)) { - if (error > 0) { - VLOG_WARN(LOG_MODULE, "%s: connection dropped (%s)", - rc->name, strerror(error)); - } else if (error == EOF) { - if (rc->reliable) { - VLOG_INFO(LOG_MODULE, "%s: connection closed by peer", rc->name); - } - } else { - VLOG_INFO(LOG_MODULE, "%s: connection dropped", rc->name); - } - vconn_close(rc->vconn); - rc->vconn = NULL; - flush_queue(rc); - } - - if (now >= rc->backoff_deadline) { - rc->backoff = 1; - } else { - rc->backoff = MIN(rc->max_backoff, MAX(1, 2 * rc->backoff)); - VLOG_INFO(LOG_MODULE, "%s: waiting %d seconds before reconnect", - rc->name, rc->backoff); - } - rc->backoff_deadline = now + rc->backoff; - state_transition(rc, S_BACKOFF); - if (now - rc->last_connected > 60) { - question_connectivity(rc); - } - } else { - rconn_disconnect(rc); - } -} - -/* Drops all the packets from 'rc''s send queue and decrements their queue - * counts. */ -static void -flush_queue(struct rconn *rc) -{ - if (!rc->txq.n) { - return; - } - while (rc->txq.n > 0) { - struct ofpbuf *b = queue_pop_head(&rc->txq); - int *n_queued = b->private_p; - if (n_queued) { - --*n_queued; - } - ofpbuf_delete(b); - } - poll_immediate_wake(); -} - -static unsigned int -elapsed_in_this_state(const struct rconn *rc) -{ - return time_now() - rc->state_entered; -} - -static unsigned int -timeout(const struct rconn *rc) -{ - switch (rc->state) { -#define STATE(NAME, VALUE) case S_##NAME: return timeout_##NAME(rc); - STATES -#undef STATE - default: - NOT_REACHED(); - } -} - -static bool -timed_out(const struct rconn *rc) -{ - return time_now() >= sat_add(rc->state_entered, timeout(rc)); -} - -static void -state_transition(struct rconn *rc, enum state state) -{ - rc->seqno += (rc->state == S_ACTIVE) != (state == S_ACTIVE); - if (is_connected_state(state) && !is_connected_state(rc->state)) { - rc->probably_admitted = false; - } - if (rconn_is_connected(rc)) { - rc->total_time_connected += elapsed_in_this_state(rc); - } - VLOG_DBG(LOG_MODULE, "%s: entering %s", rc->name, state_name(state)); - rc->state = state; - rc->state_entered = time_now(); -} - -static void -question_connectivity(struct rconn *rc) -{ - time_t now = time_now(); - if (now - rc->last_questioned > 60) { - rc->questionable_connectivity = true; - rc->last_questioned = now; - } -} - -static void -copy_to_monitor(struct rconn *rc, const struct ofpbuf *b) -{ - struct ofpbuf *clone = NULL; - int retval; - size_t i; - - for (i = 0; i < rc->n_monitors; ) { - struct vconn *vconn = rc->monitors[i]; - - if (!clone) { - clone = ofpbuf_clone(b); - } - retval = vconn_send(vconn, clone); - if (!retval) { - clone = NULL; - } else if (retval != EAGAIN) { - VLOG_DBG(LOG_MODULE, "%s: closing monitor connection to %s: %s", - rconn_get_name(rc), vconn_get_name(vconn), - strerror(retval)); - rc->monitors[i] = rc->monitors[--rc->n_monitors]; - continue; - } - i++; - } - ofpbuf_delete(clone); -} - -static bool -is_connected_state(enum state state) -{ - return (state & (S_ACTIVE | S_IDLE)) != 0; -} - -static bool -is_admitted_msg(const struct ofpbuf *b) -{ - struct ofp_header *oh = b->data; - - switch(oh->type) { - case OFPT_HELLO : - case OFPT_ECHO_REQUEST : - case OFPT_ECHO_REPLY : - case OFPT_EXPERIMENTER : - case OFPT_FEATURES_REQUEST : - case OFPT_GET_CONFIG_REQUEST : - case OFPT_SET_CONFIG : - case OFPT_FLOW_REMOVED : - case OFPT_PACKET_OUT : - case OFPT_FLOW_MOD : - case OFPT_GROUP_MOD : - case OFPT_PORT_MOD : - case OFPT_TABLE_MOD : - case OFPT_STATS_REQUEST : - case OFPT_BARRIER_REQUEST : - case OFPT_QUEUE_GET_CONFIG_REQUEST : { - return true; - } - default: { - return false; - } - } -} diff --git a/lib/signals.c b/lib/signals.c index 93327b1f..640e8750 100644 --- a/lib/signals.c +++ b/lib/signals.c @@ -115,7 +115,10 @@ bool signal_poll(struct signal *s) { char buf[_POSIX_PIPE_BUF]; - read(fds[0], buf, sizeof buf); + if (read(fds[0], buf, sizeof buf) != sizeof(buf)){ + fprintf(stderr, "read failed: %s\n", + strerror(errno)); + } if (signaled[s->signr]) { signaled[s->signr] = 0; return true; @@ -139,7 +142,10 @@ static void signal_handler(int signr) { if (signr >= 1 && signr < N_SIGNALS) { - write(fds[1], "", 1); + if (write(fds[1], "", 1) != 1){ + fprintf(stderr, "write failed: %s\n", + strerror(errno)); + } signaled[signr] = true; } } diff --git a/lib/util.h b/lib/util.h index fde681fa..3daaef8f 100644 --- a/lib/util.h +++ b/lib/util.h @@ -40,6 +40,7 @@ #include #include #include +#include "config.h" #include "compiler.h" #ifndef va_copy diff --git a/lib/vconn-ssl.c b/lib/vconn-ssl.c index 7f415a09..c802238f 100644 --- a/lib/vconn-ssl.c +++ b/lib/vconn-ssl.c @@ -48,7 +48,6 @@ #include #include #include "dynamic-string.h" -#include "leak-checker.h" #include "ofpbuf.h" #include "openflow/openflow.h" #include "packets.h" @@ -719,7 +718,6 @@ ssl_send(struct vconn *vconn, struct ofpbuf *buffer) ssl_clear_txbuf(sslv); return 0; case EAGAIN: - leak_checker_claim(buffer); ssl_register_tx_waiter(vconn); return 0; default: diff --git a/lib/vconn-stream.c b/lib/vconn-stream.c index 25a9eef0..f15dc892 100644 --- a/lib/vconn-stream.c +++ b/lib/vconn-stream.c @@ -40,7 +40,6 @@ #include #include #include -#include "leak-checker.h" #include "ofpbuf.h" #include "openflow/openflow.h" #include "poll-loop.h" @@ -214,7 +213,6 @@ stream_send(struct vconn *vconn, struct ofpbuf *buffer) ofpbuf_delete(buffer); return 0; } else if (retval >= 0 || errno == EAGAIN) { - leak_checker_claim(buffer); s->txbuf = buffer; if (retval > 0) { ofpbuf_pull(buffer, retval); diff --git a/lib/vconn.c b/lib/vconn.c index 5468307c..607a814a 100644 --- a/lib/vconn.c +++ b/lib/vconn.c @@ -342,13 +342,9 @@ vcs_recv_hello(struct vconn *vconn) struct ofp_header *oh = b->data; if (oh->type == OFPT_HELLO) { - if (b->size > sizeof *oh) { - struct ds msg = DS_EMPTY_INITIALIZER; - ds_put_format(&msg, "%s: extra-long hello:\n", vconn->name); - ds_put_hex_dump(&msg, b->data, b->size, 0, true); - VLOG_WARN_RL(LOG_MODULE, &rl, "%s", ds_cstr(&msg)); - ds_destroy(&msg); - } + /*TODO: handle OFPHET_VERSIONBITMAP */ + /*if (b->size > sizeof *oh) { + }*/ vconn->version = MIN(OFP_VERSION, oh->version); if (vconn->version < vconn->min_version) { diff --git a/lib/vconn.h.bak b/lib/vconn.h.bak deleted file mode 100644 index f4f96a6c..00000000 --- a/lib/vconn.h.bak +++ /dev/null @@ -1,82 +0,0 @@ -/* Copyright (c) 2008, 2009 The Board of Trustees of The Leland Stanford - * Junior University - * - * We are making the OpenFlow specification and associated documentation - * (Software) available for public use and benefit with the expectation - * that others will use, modify and enhance the Software and contribute - * those enhancements back to the community. However, since we would - * like to make the Software available for broadest use, with as few - * restrictions as possible permission is hereby granted, free of - * charge, to any person obtaining a copy of this Software to deal in - * the Software under the copyrights without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * - * The name and trademarks of copyright holder(s) may NOT be used in - * advertising or publicity pertaining to the Software or any - * derivatives without specific, written prior permission. - */ - -#ifndef VCONN_H -#define VCONN_H 1 - -#include -#include -#include - -struct ofpbuf; -struct flow; -struct ofp_header; -struct ofp_stats_reply; -struct pvconn; -struct vconn; - -void vconn_usage(bool active, bool passive, bool bootstrap); - -/* Active vconns: virtual connections to OpenFlow devices. */ -int vconn_open(const char *name, int min_version, struct vconn **); -void vconn_close(struct vconn *); -const char *vconn_get_name(const struct vconn *); -uint32_t vconn_get_ip(const struct vconn *); -bool vconn_is_reconnectable(const struct vconn *); -int vconn_connect(struct vconn *); -int vconn_recv(struct vconn *, struct ofpbuf **); -int vconn_send(struct vconn *, struct ofpbuf *); -int vconn_recv_xid(struct vconn *, uint32_t xid, struct ofpbuf **); -int vconn_transact(struct vconn *, struct ofpbuf *, struct ofpbuf **); - -int vconn_open_block(const char *name, int min_version, struct vconn **); -int vconn_send_block(struct vconn *, struct ofpbuf *); -int vconn_recv_block(struct vconn *, struct ofpbuf **); - -enum vconn_wait_type { - WAIT_CONNECT, - WAIT_RECV, - WAIT_SEND -}; -void vconn_wait(struct vconn *, enum vconn_wait_type); -void vconn_connect_wait(struct vconn *); -void vconn_recv_wait(struct vconn *); -void vconn_send_wait(struct vconn *); - -/* Passive vconns: virtual listeners for incoming OpenFlow connections. */ -int pvconn_open(const char *name, struct pvconn **); -void pvconn_close(struct pvconn *); -int pvconn_accept(struct pvconn *, int min_version, struct vconn **); -void pvconn_wait(struct pvconn *); - -#endif /* vconn.h */ diff --git a/lib/vlog-modules.def b/lib/vlog-modules.def index c6f68d87..0cd50363 100644 --- a/lib/vlog-modules.def +++ b/lib/vlog-modules.def @@ -7,7 +7,6 @@ VLOG_MODULE(dhcp_client) VLOG_MODULE(dpif) VLOG_MODULE(fault) VLOG_MODULE(flow) -VLOG_MODULE(leak_checker) VLOG_MODULE(learning_switch) VLOG_MODULE(mac_learning) VLOG_MODULE(netdev) diff --git a/nbee_link/nbee_link.cpp b/nbee_link/nbee_link.cpp index 756fd48a..98b1d368 100644 --- a/nbee_link/nbee_link.cpp +++ b/nbee_link/nbee_link.cpp @@ -53,7 +53,7 @@ extern "C" int nblink_initialize(void) int NetPDLDecoderFlags = nbDECODER_GENERATEPDML; int ShowNetworkNames = 0; - char* NetPDLFileName = (char*) NETPDLDIR"/"NETPDLFILE; + char* NetPDLFileName = (char*) NETPDLDIR "/" NETPDLFILE; struct stat netpdlstat; struct sigaction sa; @@ -111,15 +111,6 @@ extern "C" int nblink_initialize(void) } -int nblink_add_entry_hmap(struct ofpbuf * pktin, struct hmap * pktout ,struct ofl_match_tlv * pktout_field, int Size) -/* -* This will add a field entry to the hash map structure. -*/ -{ - - - return 0; -} int nblink_check_for_entry_on_hmap(struct hmap * pktout ,uint32_t header, struct ofl_match_tlv * field) /* @@ -227,8 +218,7 @@ int nblink_extract_proto_fields(struct ofpbuf * pktin, _nbPDMLField * field, str * Function used to extract a field from the NetBee field structure. */ { -/* Found a NetPDL field usable on matching */ - +/* Found a NetPDL field usable on matching */ /* Copying data from the packet */ if (field->Mask != NULL) { @@ -242,21 +232,38 @@ int nblink_extract_proto_fields(struct ofpbuf * pktin, _nbPDMLField * field, str } else if (header == OXM_OF_VLAN_PCP){ uint16_t m_value; + uint8_t vlan_pcp; sscanf(field->Value, "%hx", &m_value); - m_value = (m_value & VLAN_PCP_MASK) >> VLAN_PCP_SHIFT; - ofl_structs_match_put16(pktout, header, m_value); + vlan_pcp = (m_value & VLAN_PCP_MASK) >> VLAN_PCP_SHIFT; + ofl_structs_match_put8(pktout, header, vlan_pcp); } else if(header == OXM_OF_IP_DSCP){ uint8_t m_value; - sscanf(field->Value, "%hhx", &m_value); - m_value = m_value & IP_DSCP_MASK; - ofl_structs_match_put8(pktout, header, m_value); + if (strcmp(field->Name, "ip dscp") == 0){ + sscanf(field->Value, "%hhx", &m_value); + m_value = (m_value & IP_DSCP_MASK) >> 2; + ofl_structs_match_put8(pktout, header, m_value); + } + else { + uint32_t field_value; + sscanf(field->Value, "%x", &field_value); + m_value = (field_value & IPV6_DSCP_MASK) >> IPV6_DSCP_SHIFT; + ofl_structs_match_put8(pktout, header, m_value); + } } else if(header == OXM_OF_IP_ECN){ uint8_t m_value; - sscanf(field->Value, "%hhx", &m_value); - m_value = m_value & OXM_OF_IP_ECN; - ofl_structs_match_put8(pktout, header, m_value); + if (strcmp(field->Name, "ip ecn") == 0){ + sscanf(field->Value, "%hhx", &m_value); + m_value = (m_value & IP_ECN_MASK); + ofl_structs_match_put8(pktout, header, m_value); + } + else { + uint32_t field_value; + sscanf(field->Value, "%x", &field_value); + m_value = field_value & IPV6_ECN_MASK; + ofl_structs_match_put8(pktout, header, m_value); + } } else if(header == OXM_OF_MPLS_LABEL){ uint32_t m_value; @@ -265,25 +272,33 @@ int nblink_extract_proto_fields(struct ofpbuf * pktin, _nbPDMLField * field, str ofl_structs_match_put32(pktout, header, m_value); } else if (header == OXM_OF_MPLS_TC){ - uint8_t m_value; - sscanf(field->Value, "%hhx", &m_value); + uint32_t m_value; + sscanf(field->Value, "%x", &m_value); m_value = (m_value & MPLS_TC_MASK) >> MPLS_TC_SHIFT; - ofl_structs_match_put32(pktout, header, m_value); + ofl_structs_match_put8(pktout, header, m_value); } else if (header == OXM_OF_MPLS_BOS){ - uint8_t m_value; - sscanf(field->Value, "%hhx", &m_value); + uint32_t m_value; + sscanf(field->Value, "%x", &m_value); m_value = (m_value & MPLS_S_MASK) >> MPLS_S_SHIFT; ofl_structs_match_put8(pktout, header, m_value); } - /*TODO: Add IPV6_FLABEL_SHIFT to lib/packets.h*/ - /*else if (header == OXM_OF_IPV6_FLABEL){ + else if (header == OXM_OF_PBB_ISID){ uint32_t m_value; + uint8_t pbb_isid[3]; sscanf(field->Value, "%x", &m_value); - m_value = (m_value & IPV6_FLABEL_MASK) >> IPV6_FLABEL_SHIFT; - memcpy(pktout_field->value, &m_value, field->Size); - - }*/ + m_value = (m_value & PBB_ISID_MASK); + pbb_isid[0] = (m_value >> 24) & 0xff; + pbb_isid[1] = (m_value >> 16) & 0xff; + pbb_isid[2] = m_value & 0xff; + ofl_structs_match_put_pbb_isid(pktout, header, pbb_isid); + } + else if (header == OXM_OF_IPV6_FLABEL){ + uint32_t m_value; + sscanf(field->Value, "%x", &m_value); + m_value = m_value & IPV6_FLABEL_MASK; + ofl_structs_match_put32(pktout, header, m_value); + } } else { @@ -315,7 +330,6 @@ int nblink_extract_proto_fields(struct ofpbuf * pktin, _nbPDMLField * field, str } case 4:{ uint32_t m_value; - if (header == OXM_OF_IPV4_DST || header == OXM_OF_IPV4_SRC || header == OXM_OF_ARP_SPA || header == OXM_OF_ARP_TPA){ m_value = *((uint32_t*)((uint8_t*)pktin->data + field->Position)); @@ -388,7 +402,6 @@ extern "C" int nblink_packet_parse(struct ofpbuf * pktin, struct ofl_match * pk string field_Name (field->Name); /* Copying data from the packet */ - if (protocol_Name.compare("ethernet") == 0 && pkt_proto->eth == NULL) { pkt_proto->eth = (struct eth_header *) ( (uint8_t*) pktin->data + proto->Position); @@ -399,8 +412,8 @@ extern "C" int nblink_packet_parse(struct ofpbuf * pktin, struct ofl_match * pk PDMLReader->GetPDMLField(proto->Name, (char*) "type", proto->FirstField, &field); nblink_extract_proto_fields(pktin, field, pktout, OXM_OF_ETH_TYPE); - } - else if ((protocol_Name.compare("vlan") == 0 || protocol_Name.compare("pbb_b") == 0)) + } + else if ((protocol_Name.compare("vlan") == 0)) { if(pkt_proto->vlan_last == NULL){ pkt_proto->vlan = pkt_proto->vlan_last = (struct vlan_header *) ((uint8_t*) pktin->data + proto->Position); @@ -443,7 +456,7 @@ extern "C" int nblink_packet_parse(struct ofpbuf * pktin, struct ofl_match * pk nblink_extract_proto_fields(pktin, field, pktout, OXM_OF_ARP_TPA); } - else if (protocol_Name.compare("pbb_s") == 0 && pkt_proto->pbb == NULL) + else if (protocol_Name.compare("pbb") == 0 && pkt_proto->pbb == NULL) { pkt_proto->pbb = (struct pbb_header *) ((uint8_t*) pktin->data + proto->Position); PDMLReader->GetPDMLField(proto->Name, (char*) "isid", proto->FirstField, &field); @@ -467,14 +480,19 @@ extern "C" int nblink_packet_parse(struct ofpbuf * pktin, struct ofl_match * pk } else if (protocol_Name.compare("ipv6") == 0 && pkt_proto->ipv6 == NULL) { + _nbPDMLField * ip_proto = NULL; + uint8_t i; pkt_proto->ipv6 = (struct ipv6_header *) ((uint8_t*) pktin->data + proto->Position); - PDMLReader->GetPDMLField(proto->Name, (char*) "flabel", proto->FirstField, &field); + PDMLReader->GetPDMLField(proto->Name, (char*) "ipv6 dscp", proto->FirstField, &field); + nblink_extract_proto_fields(pktin, field, pktout, OXM_OF_IP_DSCP); + PDMLReader->GetPDMLField(proto->Name, (char*) "ipv6 ecn", proto->FirstField, &field); + nblink_extract_proto_fields(pktin, field, pktout, OXM_OF_IP_ECN); + PDMLReader->GetPDMLField(proto->Name, (char*) "flabel", proto->FirstField, &field); nblink_extract_proto_fields(pktin, field, pktout, OXM_OF_IPV6_FLABEL); /*Initialize extension header OXM */ struct ofl_match_tlv * EH_field; uint16_t bit_field = OFPIEH_NONEXT; - uint8_t i; EH_field = (struct ofl_match_tlv *) malloc(sizeof(struct ofl_match_tlv)); EH_field->value = (uint8_t*) malloc(OXM_LENGTH(OXM_OF_IPV6_EXTHDR)); EH_field->header = OXM_OF_IPV6_EXTHDR; @@ -495,16 +513,17 @@ extern "C" int nblink_packet_parse(struct ofpbuf * pktin, struct ofl_match * pk hmap_insert_fast(&pktout->match_fields, &EH_field->hmap_node, hash_int(EH_field->header, 0)); + pktout->header.length += 6; + PDMLReader->GetPDMLField(proto->Name, (char*) "src", proto->FirstField, &field); nblink_extract_proto_fields(pktin, field, pktout, OXM_OF_IPV6_SRC); PDMLReader->GetPDMLField(proto->Name, (char*) "dst", proto->FirstField, &field); nblink_extract_proto_fields(pktin, field, pktout, OXM_OF_IPV6_DST); - PDMLReader->GetPDMLField(proto->Name, (char*) "nexthdr", proto->FirstField, &ip_proto); + PDMLReader->GetPDMLField(proto->Name, (char*) "nexthdr", proto->FirstField, &ip_proto); if (PDMLReader->GetPDMLField(proto->Name, (char*) "HBH", proto->FirstField, &field) == nbSUCCESS){ - nblink_extract_exthdr_fields(pktin, pktout, OFPIEH_HOP, field, &destination_num); - if(!field->NextField) + nblink_extract_exthdr_fields(pktin, pktout, OFPIEH_HOP, field, &destination_num); ip_proto = field->FirstChild; } if(PDMLReader->GetPDMLField(proto->Name, (char*) "FH", proto->FirstField, &field) == nbSUCCESS){ @@ -531,10 +550,11 @@ extern "C" int nblink_packet_parse(struct ofpbuf * pktin, struct ofl_match * pk nblink_extract_exthdr_fields(pktin, pktout, OFPIEH_ESP, field, &destination_num); if(!field->NextField) ip_proto = field->FirstChild; - } + } if (ip_proto){ + nblink_extract_proto_fields(pktin, ip_proto, pktout, OXM_OF_IP_PROTO); - } + } } if (protocol_Name.compare("tcp") == 0 && pkt_proto->tcp == NULL) { @@ -555,33 +575,42 @@ extern "C" int nblink_packet_parse(struct ofpbuf * pktin, struct ofl_match * pk else if (protocol_Name.compare("sctp") == 0 && pkt_proto->sctp == NULL) { pkt_proto->sctp = (struct sctp_header *) ((uint8_t*) pktin->data + proto->Position); + PDMLReader->GetPDMLField(proto->Name, (char*) "sport", proto->FirstField, &field); + nblink_extract_proto_fields(pktin, field, pktout, OXM_OF_SCTP_SRC); + PDMLReader->GetPDMLField(proto->Name, (char*) "dport", proto->FirstField, &field); + nblink_extract_proto_fields(pktin, field, pktout, OXM_OF_SCTP_DST); } if (protocol_Name.compare("icmp") == 0 && pkt_proto->icmp == NULL){ pkt_proto->icmp = (struct icmp_header *) ((uint8_t*) pktin->data + proto->Position); - PDMLReader->GetPDMLField(proto->Name, (char*) "type", proto->FirstField, &field); nblink_extract_proto_fields(pktin, field, pktout, OXM_OF_ICMPV4_TYPE); PDMLReader->GetPDMLField(proto->Name, (char*) "code", proto->FirstField, &field); - nblink_extract_proto_fields(pktin, field, pktout, OXM_OF_ICMPV4_CODE); + nblink_extract_proto_fields(pktin, field, pktout, OXM_OF_ICMPV4_CODE); + } else if (protocol_Name.compare("icmp6") == 0 && pkt_proto->icmp == NULL){ pkt_proto->icmp = (struct icmp_header *) ((uint8_t*) pktin->data + proto->Position); PDMLReader->GetPDMLField(proto->Name, (char*) "type", proto->FirstField, &field); nblink_extract_proto_fields(pktin, field, pktout, OXM_OF_ICMPV6_TYPE); - PDMLReader->GetPDMLField(proto->Name, (char*) "code", proto->FirstField, &field); + PDMLReader->GetPDMLField(proto->Name, (char*) "code", proto->FirstField, &field); nblink_extract_proto_fields(pktin, field, pktout, OXM_OF_ICMPV6_CODE); if (PDMLReader->GetPDMLField(proto->Name, (char*) "NeighSol", proto->FirstField, &field) == nbSUCCESS || PDMLReader->GetPDMLField(proto->Name, (char*) "NeighAdv", proto->FirstField, &field) == nbSUCCESS){ - PDMLReader->GetPDMLField(proto->Name, (char*) "target_address", proto->FirstField, &field); - nblink_extract_proto_fields(pktin, field, pktout, OXM_OF_IPV6_ND_TARGET); + PDMLReader->GetPDMLField(proto->Name, (char*) "target_address", proto->FirstField, &field); + + nblink_extract_proto_fields(pktin, field, pktout, OXM_OF_IPV6_ND_TARGET); } if (PDMLReader->GetPDMLField(proto->Name, (char*) "NDO", proto->FirstField, &field) == nbSUCCESS){ - PDMLReader->GetPDMLField(proto->Name, (char*) "src link_layer_address", proto->FirstField, &field); - nblink_extract_proto_fields(pktin, field, pktout, OXM_OF_IPV6_ND_SLL); - PDMLReader->GetPDMLField(proto->Name, (char*) "dst link_layer_address", proto->FirstField, &field); - nblink_extract_proto_fields(pktin, field, pktout, OXM_OF_IPV6_ND_TLL); + uint8_t type; + PDMLReader->GetPDMLField(proto->Name, (char*) "ndotype", proto->FirstField, &field); + if (PDMLReader->GetPDMLField(proto->Name, (char*) "src_link_layer_address", proto->FirstField, &field) == nbSUCCESS){ + nblink_extract_proto_fields(pktin, field, pktout, OXM_OF_IPV6_ND_SLL); + } + if(PDMLReader->GetPDMLField(proto->Name, (char*) "dst_link_layer_address", proto->FirstField, &field) == nbSUCCESS){ + nblink_extract_proto_fields(pktin, field, pktout, OXM_OF_IPV6_ND_TLL); + } } } while (!field->isField) @@ -598,8 +627,7 @@ extern "C" int nblink_packet_parse(struct ofpbuf * pktin, struct ofl_match * pk } proto = proto->NextProto; - } - + } return 1; } diff --git a/oflib/ofl-actions-pack.c b/oflib/ofl-actions-pack.c index ae05dc12..1c35f04e 100644 --- a/oflib/ofl-actions-pack.c +++ b/oflib/ofl-actions-pack.c @@ -207,10 +207,10 @@ ofl_actions_pack(struct ofl_action_header *src, struct ofp_action_header *dst, u switch (OXM_LENGTH(sa->field->header)){ case 1: case 6: + case 3: case 16: memcpy(data + (sizeof(struct ofp_action_set_field)), sa->field->value, OXM_LENGTH(sa->field->header)); break; - case 2:{ uint16_t value = htons(*((uint16_t*) sa->field->value)); memcpy(data + (sizeof(struct ofp_action_set_field)),&value,OXM_LENGTH(sa->field->header)); @@ -227,7 +227,7 @@ ofl_actions_pack(struct ofl_action_header *src, struct ofp_action_header *dst, u break; } case 8:{ - uint64_t value = htons(*((uint64_t*) sa->field->value)); + uint64_t value = hton64(*((uint64_t*) sa->field->value)); memcpy(data + (sizeof(struct ofp_action_set_field)),&value,OXM_LENGTH(sa->field->header)); break; } diff --git a/oflib/ofl-actions-print.c b/oflib/ofl-actions-print.c index dd38ee25..1bfc4d0d 100644 --- a/oflib/ofl-actions-print.c +++ b/oflib/ofl-actions-print.c @@ -45,7 +45,7 @@ #define ETH_ADDR_FMT \ - "%02"PRIx8":%02"PRIx8":%02"PRIx8":%02"PRIx8":%02"PRIx8":%02"PRIx8 + "%02" PRIx8 ":%02" PRIx8 ":%02" PRIx8 ":%02" PRIx8 ":%02" PRIx8 ":%02" PRIx8 #define ETH_ADDR_ARGS(ea) \ (ea)[0], (ea)[1], (ea)[2], (ea)[3], (ea)[4], (ea)[5] @@ -81,7 +81,6 @@ ofl_action_print(FILE *stream, struct ofl_action_header *act, struct ofl_exp *ex break; } case OFPAT_SET_FIELD:{ - size_t size; struct ofl_action_set_field *a = (struct ofl_action_set_field *)act; fprintf(stream, "{field:"); ofl_structs_oxm_tlv_print(stream, a->field); diff --git a/oflib/ofl-actions-unpack.c b/oflib/ofl-actions-unpack.c index 7a186ff1..90c2eb04 100644 --- a/oflib/ofl-actions-unpack.c +++ b/oflib/ofl-actions-unpack.c @@ -285,16 +285,18 @@ ofl_actions_unpack(struct ofp_action_header *src, size_t *len, struct ofl_action da->field->value = malloc(OXM_LENGTH(da->field->header)); /*TODO: need to check if other fields are valid */ if(da->field->header == OXM_OF_IN_PORT || da->field->header == OXM_OF_IN_PHY_PORT - || da->field->header == OXM_OF_METADATA){ + || da->field->header == OXM_OF_METADATA + || da->field->header == OXM_OF_IPV6_EXTHDR){ + return ofl_error(OFPET_BAD_ACTION, OFPBAC_BAD_SET_TYPE); } switch(OXM_LENGTH(da->field->header)){ case 1: + case 3: case 6: case 16: memcpy(da->field->value , value, OXM_LENGTH(da->field->header)); break; - case 2:{ uint16_t v = ntohs(*((uint16_t*) value)); memcpy(da->field->value , &v, OXM_LENGTH(da->field->header)); @@ -302,15 +304,15 @@ ofl_actions_unpack(struct ofp_action_header *src, size_t *len, struct ofl_action } case 4:{ uint32_t v; - uint8_t field = OXM_FIELD(da->field->header); - if( field != 11 && field != 12 && field != 22 && field != 23) - v = htonl(*((uint32_t*) value)); - else v = *((uint32_t*) value); + uint8_t field = OXM_FIELD(da->field->header); + if( field != 11 && field != 12 && field != 22 && field != 23) + v = htonl(*((uint32_t*) value)); + else v = *((uint32_t*) value); memcpy(da->field->value , &v, OXM_LENGTH(da->field->header)); break; } case 8:{ - uint64_t v = hton64(*((uint64_t*) value)); + uint64_t v = ntoh64(*((uint64_t*) value)); memcpy(da->field->value , &v, OXM_LENGTH(da->field->header)); break; } @@ -344,7 +346,7 @@ ofl_actions_unpack(struct ofp_action_header *src, size_t *len, struct ofl_action return ofl_error(OFPET_BAD_ACTION, OFPBAC_BAD_TYPE); } } - (*dst)->type = (enum ofp_action_type)ntohs(src->type); + (*dst)->type = (enum ofp_action_type)((int)ntohs(src->type)); return 0; } diff --git a/oflib/ofl-messages-pack.c b/oflib/ofl-messages-pack.c index 234f865e..b8c418d3 100644 --- a/oflib/ofl-messages-pack.c +++ b/oflib/ofl-messages-pack.c @@ -365,9 +365,9 @@ ofl_msg_pack_async_config(struct ofl_msg_async_config *msg, uint8_t **buf, size_ ac = (struct ofp_async_config*)(*buf); for(i = 0; i < 2; i++){ - ac->packet_in_mask[i] = msg->config->packet_in_mask[i]; - ac->port_status_mask[i] = msg->config->port_status_mask[i]; - ac->flow_removed_mask[i] = msg->config->flow_removed_mask[i]; + ac->packet_in_mask[i] = htonl(msg->config->packet_in_mask[i]); + ac->port_status_mask[i] = htonl(msg->config->port_status_mask[i]); + ac->flow_removed_mask[i] = htonl(msg->config->flow_removed_mask[i]); } return 0; } @@ -732,13 +732,13 @@ ofl_msg_pack_multipart_reply_group_desc(struct ofl_msg_multipart_reply_group_des static int ofl_msg_pack_multipart_reply_group_features(struct ofl_msg_multipart_reply_group_features *msg, uint8_t **buf, size_t *buf_len) { struct ofp_multipart_reply *resp; - struct ofp_group_features_stats *stats; + struct ofp_group_features *stats; int i; - *buf_len = sizeof(struct ofp_multipart_reply) + sizeof(struct ofp_group_features_stats); + *buf_len = sizeof(struct ofp_multipart_reply) + sizeof(struct ofp_group_features); *buf = (uint8_t *)malloc(*buf_len); resp = (struct ofp_multipart_reply *)(*buf); - stats = (struct ofp_group_features_stats *)resp->body; + stats = (struct ofp_group_features *)resp->body; stats->types = htonl(msg->types); stats->capabilities = htonl(msg->capabilities); for(i = 0; i < 4; i++){ diff --git a/oflib/ofl-messages-print.c b/oflib/ofl-messages-print.c index 24ddcd6c..0a40bb2e 100644 --- a/oflib/ofl-messages-print.c +++ b/oflib/ofl-messages-print.c @@ -205,7 +205,7 @@ ofl_msg_print_meter_mod(struct ofl_msg_meter_mod *msg, FILE *stream) { fprintf(stream,"{cmd=\""); ofl_meter_mod_command_print(stream, msg->command); fprintf(stream, "\", flags=\"0x%"PRIx16"\"",msg->flags); - fprintf(stream, "\", meter_id=\"%"PRIx32"\"",msg->meter_id); + fprintf(stream, "\", meter_id=\"%"PRIu32"\"",msg->meter_id); fprintf(stream,"\", bands=["); for (i=0; imeter_bands_num; i++) { @@ -329,7 +329,7 @@ ofl_msg_print_multipart_request(struct ofl_msg_multipart_request_header *msg, FI break; } case OFPMP_TABLE_FEATURES: { - ofl_msg_print_table_features_request((struct ofl_msg_multipart_request_table_features*)msg, stream); + ofl_msg_print_table_features_request((struct ofl_msg_multipart_request_table_features*)msg, stream); break; } case OFPMP_PORT_STATS: { @@ -357,7 +357,7 @@ ofl_msg_print_multipart_request(struct ofl_msg_multipart_request_header *msg, FI } case OFPMP_METER_FEATURES:{ break; - } + } case OFPMP_PORT_DESC:{ break; } @@ -382,7 +382,7 @@ ofl_msg_print_stats_reply_flow(struct ofl_msg_multipart_reply_flow *msg, FILE *s for (i=0; istats_num; i++) { ofl_structs_flow_stats_print(stream, msg->stats[i], exp); - if (i < msg->stats_num - 1) { fprintf(stream, ", "); }; + if (i < msg->stats_num - 1) { fprintf(stream, ",\n"); }; } fprintf(stream, "]"); @@ -402,7 +402,7 @@ ofl_msg_print_stats_reply_table(struct ofl_msg_multipart_reply_table *msg, FILE for (i=0; istats_num; i++) { ofl_structs_table_stats_print(stream, msg->stats[i]); - if (i < msg->stats_num - 1) { fprintf(stream, ", "); }; + if (i < msg->stats_num - 1) { fprintf(stream, ",\n"); }; } fprintf(stream, "]"); @@ -416,7 +416,7 @@ ofl_msg_print_stats_reply_port(struct ofl_msg_multipart_reply_port *msg, FILE *s for (i=0; istats_num; i++) { ofl_structs_port_stats_print(stream, msg->stats[i]); - if (i < msg->stats_num - 1) { fprintf(stream, ", "); }; + if (i < msg->stats_num - 1) { fprintf(stream, ",\n"); }; } fprintf(stream, "]"); @@ -430,7 +430,7 @@ ofl_msg_print_stats_reply_queue(struct ofl_msg_multipart_reply_queue *msg, FILE for (i=0; istats_num; i++) { ofl_structs_queue_stats_print(stream, msg->stats[i]); - if (i < msg->stats_num - 1) { fprintf(stream, ", "); }; + if (i < msg->stats_num - 1) { fprintf(stream, ",\n"); }; } fprintf(stream, "]"); @@ -444,7 +444,7 @@ ofl_msg_print_stats_reply_group(struct ofl_msg_multipart_reply_group *msg, FILE for (i=0; istats_num; i++) { ofl_structs_group_stats_print(stream, msg->stats[i]); - if (i < msg->stats_num - 1) { fprintf(stream, ", "); }; + if (i < msg->stats_num - 1) { fprintf(stream, ",\n"); }; } fprintf(stream, "]"); @@ -458,7 +458,7 @@ ofl_msg_print_stats_reply_meter(struct ofl_msg_multipart_reply_meter *msg, FILE for (i=0; istats_num; i++) { ofl_structs_meter_stats_print(stream, msg->stats[i]); - if (i < msg->stats_num - 1) { fprintf(stream, ", "); }; + if (i < msg->stats_num - 1) { fprintf(stream, ",\n"); }; } fprintf(stream, "]"); @@ -472,7 +472,7 @@ ofl_msg_print_stats_reply_meter_conf(struct ofl_msg_multipart_reply_meter_conf * for (i=0; istats_num; i++) { ofl_structs_meter_config_print(stream, msg->stats[i]); - if (i < msg->stats_num - 1) { fprintf(stream, ", "); }; + if (i < msg->stats_num - 1) { fprintf(stream, ",\n"); }; } fprintf(stream, "]"); @@ -492,7 +492,7 @@ ofl_msg_print_stats_reply_group_desc(struct ofl_msg_multipart_reply_group_desc * for (i=0; istats_num; i++) { ofl_structs_group_desc_stats_print(stream, msg->stats[i], exp); - if (i < msg->stats_num - 1) { fprintf(stream, ", "); }; + if (i < msg->stats_num - 1) { fprintf(stream, ",\n"); }; } fprintf(stream, "]"); @@ -510,17 +510,17 @@ static void ofl_msg_print_stats_reply_group_features(struct ofl_msg_multipart_re fprintf(stream, ": max_groups=%d, actions= ", msg->max_groups[i]); if(msg->actions[i] & 1){ ofl_action_type_print(stream, OFPAT_OUTPUT); - fprintf(stream, "/"); + fprintf(stream, "/"); } if(msg->actions[i] & OFPAT_COPY_TTL_OUT){ ofl_action_type_print(stream, OFPAT_COPY_TTL_OUT); - fprintf(stream, "/"); + fprintf(stream, "/"); } - if(msg->actions[i] & OFPAT_COPY_TTL_IN){ + if(msg->actions[i] & OFPAT_COPY_TTL_IN){ ofl_action_type_print(stream, OFPAT_COPY_TTL_IN); - fprintf(stream, "/"); + fprintf(stream, "/"); } for(j = OFPAT_SET_MPLS_TTL; j < OFPAT_POP_PBB; j++){ if (msg->actions[i] & j){ @@ -529,7 +529,7 @@ static void ofl_msg_print_stats_reply_group_features(struct ofl_msg_multipart_re } } if (i < 3) - fprintf(stream, ", "); + fprintf(stream, ",\n"); } } @@ -558,10 +558,10 @@ ofl_msg_print_table_features_reply(struct ofl_msg_multipart_reply_table_features static void ofl_msg_print_port_desc_reply(struct ofl_msg_multipart_reply_port_desc *msg, FILE *stream) { size_t i; - + for(i = 0; i < msg->stats_num; i++){ ofl_structs_port_print(stream, msg->stats[i]); - if (i < msg->stats_num - 1) { fprintf(stream, ", "); }; + if (i < msg->stats_num - 1) { fprintf(stream, ",\n"); }; } fprintf(stream, "}"); } @@ -630,7 +630,7 @@ ofl_msg_print_multipart_reply(struct ofl_msg_multipart_reply_header *msg, FILE * } case OFPMP_METER_CONFIG:{ ofl_msg_print_stats_reply_meter_conf((struct ofl_msg_multipart_reply_meter_conf*)msg, stream); - break; + break; } case OFPMP_METER_FEATURES:{ ofl_msg_print_reply_meter_features((struct ofl_msg_multipart_reply_meter_features*)msg, stream); @@ -672,20 +672,16 @@ ofl_msg_print_queue_get_config_reply(struct ofl_msg_queue_get_config_reply *msg, fprintf(stream, "]}"); } -static void +static void ofl_msg_print_role_msg(struct ofl_msg_role_request *msg, FILE *stream){ - - fprintf(stream, "{role= %d, generation_id= %lld}", msg->role, msg->generation_id); - + fprintf(stream, "{role= %d, generation_id= %"PRIu64"}", msg->role, msg->generation_id); } static void ofl_msg_print_async(struct ofl_msg_async_config* msg, FILE *stream){ - fprintf(stream, "{"); ofl_structs_async_config_print(stream, msg->config); fprintf(stream, "}"); - } char * @@ -749,19 +745,18 @@ ofl_msg_print(FILE *stream, struct ofl_msg_header *msg, struct ofl_exp *exp) { /*Role messages */ case OFPT_ROLE_REQUEST: case OFPT_ROLE_REPLY:{ - ofl_msg_print_role_msg((struct ofl_msg_role_request*)msg, stream); + ofl_msg_print_role_msg((struct ofl_msg_role_request*)msg, stream); } /* Queue Configuration messages. */ case OFPT_QUEUE_GET_CONFIG_REQUEST: { ofl_msg_print_queue_get_config_request((struct ofl_msg_queue_get_config_request *)msg, stream); return; } case OFPT_QUEUE_GET_CONFIG_REPLY: { ofl_msg_print_queue_get_config_reply((struct ofl_msg_queue_get_config_reply *)msg, stream); return; } - - /* Asynchronous message configuration. */ - case OFPT_GET_ASYNC_REQUEST:{return;} + + /* Asynchronous message configuration. */ + case OFPT_GET_ASYNC_REQUEST:{return;} case OFPT_GET_ASYNC_REPLY: - case OFPT_SET_ASYNC:{ofl_msg_print_async((struct ofl_msg_async_config*)msg, stream); return;} - - case OFPT_METER_MOD: {ofl_msg_print_meter_mod((struct ofl_msg_meter_mod*)msg, stream); return;} - - } + case OFPT_SET_ASYNC:{ofl_msg_print_async((struct ofl_msg_async_config*)msg, stream); return;} + + case OFPT_METER_MOD: {ofl_msg_print_meter_mod((struct ofl_msg_meter_mod*)msg, stream); return;} + } } diff --git a/oflib/ofl-messages-unpack.c b/oflib/ofl-messages-unpack.c index 9e180ce1..7ef7bb58 100644 --- a/oflib/ofl-messages-unpack.c +++ b/oflib/ofl-messages-unpack.c @@ -52,6 +52,7 @@ OFL_LOG_INIT(LOG_MODULE) static ofl_err ofl_msg_unpack_error(struct ofp_header *src, size_t *len, struct ofl_msg_header **msg) { + struct ofp_error_msg *se; struct ofl_msg_error *de; @@ -65,7 +66,7 @@ ofl_msg_unpack_error(struct ofp_header *src, size_t *len, struct ofl_msg_header de = (struct ofl_msg_error *)malloc(sizeof(struct ofl_msg_error)); - de->type = (enum ofp_error_type)ntohs(se->type); + de->type = (enum ofp_error_type)((int)ntohs(se->type)); de->code = ntohs(se->code); de->data_length = *len; de->data = *len > 0 ? (uint8_t *)memcpy(malloc(*len), se->data, *len) : NULL; @@ -78,6 +79,7 @@ ofl_msg_unpack_error(struct ofp_header *src, size_t *len, struct ofl_msg_header static ofl_err ofl_msg_unpack_echo(struct ofp_header *src, size_t *len, struct ofl_msg_header **msg) { + struct ofl_msg_echo *e = (struct ofl_msg_echo *)malloc(sizeof(struct ofl_msg_echo)); uint8_t *data; @@ -95,6 +97,7 @@ ofl_msg_unpack_echo(struct ofp_header *src, size_t *len, struct ofl_msg_header * static ofl_err ofl_msg_unpack_role_request(struct ofp_header *src, size_t *len, struct ofl_msg_header **msg) { + struct ofp_role_request *srl; struct ofl_msg_role_request *drl; @@ -116,6 +119,7 @@ ofl_msg_unpack_role_request(struct ofp_header *src, size_t *len, struct ofl_msg_ static ofl_err ofl_msg_unpack_features_reply(struct ofp_header *src, size_t *len, struct ofl_msg_header **msg) { + struct ofp_switch_features *sr; struct ofl_msg_features_reply *dr; @@ -141,6 +145,7 @@ ofl_msg_unpack_features_reply(struct ofp_header *src, size_t *len, struct ofl_ms static ofl_err ofl_msg_unpack_get_config_reply(struct ofp_header *src, size_t *len, struct ofl_msg_header **msg) { + struct ofp_switch_config *sr; struct ofl_msg_get_config_reply *dr; @@ -163,6 +168,7 @@ ofl_msg_unpack_get_config_reply(struct ofp_header *src, size_t *len, struct ofl_ static ofl_err ofl_msg_unpack_set_config(struct ofp_header *src, size_t *len, struct ofl_msg_header **msg) { + struct ofp_switch_config *sr; struct ofl_msg_set_config *dr; @@ -186,6 +192,7 @@ ofl_msg_unpack_set_config(struct ofp_header *src, size_t *len, struct ofl_msg_he static ofl_err ofl_msg_unpack_async_config(struct ofp_header *src, size_t *len, struct ofl_msg_header **msg){ + struct ofp_async_config *sac; struct ofl_msg_async_config *dac; int i; @@ -196,22 +203,21 @@ ofl_msg_unpack_async_config(struct ofp_header *src, size_t *len, struct ofl_msg_ } *len -= sizeof(struct ofp_async_config); - sac = (struct ofp_async_config*)src; dac = (struct ofl_msg_async_config*)malloc(sizeof(struct ofl_msg_async_config)); dac->config = (struct ofl_async_config*) malloc(sizeof(struct ofl_async_config)); for(i = 0; i < 2; i++){ - dac->config->packet_in_mask[i] = sac->packet_in_mask[i]; - dac->config->port_status_mask[i] = sac->port_status_mask[i]; - dac->config->flow_removed_mask[i] = sac->flow_removed_mask[i]; + dac->config->packet_in_mask[i] = ntohl(sac->packet_in_mask[i]); + dac->config->port_status_mask[i] = ntohl(sac->port_status_mask[i]); + dac->config->flow_removed_mask[i] = ntohl(sac->flow_removed_mask[i]); } - *msg = (struct ofl_msg_header*)dac; return 0; } static ofl_err ofl_msg_unpack_packet_in(struct ofp_header *src, uint8_t* buf, size_t *len, struct ofl_msg_header **msg) { + struct ofp_packet_in *sp; struct ofl_msg_packet_in *dp; uint8_t *ptr; @@ -267,6 +273,7 @@ ofl_msg_unpack_packet_in(struct ofp_header *src, uint8_t* buf, size_t *len, stru static ofl_err ofl_msg_unpack_flow_removed(struct ofp_header *src,uint8_t *buf, size_t *len, struct ofl_msg_header **msg, struct ofl_exp *exp) { + struct ofp_flow_removed *sr; struct ofl_msg_flow_removed *dr; ofl_err error; @@ -319,6 +326,7 @@ ofl_msg_unpack_flow_removed(struct ofp_header *src,uint8_t *buf, size_t *len, st static ofl_err ofl_msg_unpack_port_status(struct ofp_header *src, size_t *len, struct ofl_msg_header **msg) { + struct ofp_port_status *ss; struct ofl_msg_port_status *ds; ofl_err error; @@ -346,6 +354,7 @@ ofl_msg_unpack_port_status(struct ofp_header *src, size_t *len, struct ofl_msg_h static ofl_err ofl_msg_unpack_packet_out(struct ofp_header *src, size_t *len, struct ofl_msg_header **msg, struct ofl_exp *exp) { + struct ofp_packet_out *sp; struct ofl_msg_packet_out *dp; struct ofp_action_header *act; @@ -384,7 +393,7 @@ ofl_msg_unpack_packet_out(struct ofp_header *src, size_t *len, struct ofl_msg_he dp = (struct ofl_msg_packet_out *)malloc(sizeof(struct ofl_msg_packet_out)); dp->buffer_id = ntohl(sp->buffer_id); - + dp->in_port = ntohl(sp->in_port); if (*len < ntohs(sp->actions_len)) { OFL_LOG_WARN(LOG_MODULE, "Received PACKET_OUT message has invalid action length (%zu).", *len); free(dp); @@ -424,6 +433,7 @@ ofl_msg_unpack_packet_out(struct ofp_header *src, size_t *len, struct ofl_msg_he static ofl_err ofl_msg_unpack_flow_mod(struct ofp_header *src,uint8_t* buf, size_t *len, struct ofl_msg_header **msg, struct ofl_exp *exp) { + struct ofp_flow_mod *sm; struct ofl_msg_flow_mod *dm; struct ofp_instruction *inst; @@ -443,7 +453,7 @@ ofl_msg_unpack_flow_mod(struct ofp_header *src,uint8_t* buf, size_t *len, struct if (sm->table_id >= PIPELINE_TABLES && ((sm->command != OFPFC_DELETE || sm->command != OFPFC_DELETE_STRICT) && sm->table_id != OFPTT_ALL)) { - OFL_LOG_WARN(LOG_MODULE, "Received FLOW_MOD message has invalid table id (%zu).", sm->table_id ); + OFL_LOG_WARN(LOG_MODULE, "Received FLOW_MOD message has invalid table id (%d).", sm->table_id ); return ofl_error(OFPET_BAD_REQUEST, OFPBRC_BAD_TABLE_ID); } @@ -492,6 +502,7 @@ ofl_msg_unpack_flow_mod(struct ofp_header *src,uint8_t* buf, size_t *len, struct static ofl_err ofl_msg_unpack_group_mod(struct ofp_header *src, size_t *len, struct ofl_msg_header **msg, struct ofl_exp *exp) { + struct ofp_group_mod *sm; struct ofl_msg_group_mod *dm; struct ofp_bucket *bucket; @@ -528,7 +539,7 @@ ofl_msg_unpack_group_mod(struct ofp_header *src, size_t *len, struct ofl_msg_hea dm = (struct ofl_msg_group_mod *)malloc(sizeof(struct ofl_msg_group_mod)); - dm->command = (enum ofp_group_mod_command)ntohs(sm->command); + dm->command = (enum ofp_group_mod_command)((int)ntohs(sm->command)); dm->type = sm->type; dm->group_id = ntohl(sm->group_id); @@ -570,7 +581,8 @@ ofl_msg_unpack_group_mod(struct ofp_header *src, size_t *len, struct ofl_msg_hea static ofl_err ofl_msg_unpack_meter_mod(struct ofp_header *src, size_t *len, struct ofl_msg_header **msg) { - struct ofp_meter_mod *sm; + + struct ofp_meter_mod *sm; struct ofl_msg_meter_mod *dm; struct ofp_meter_band_header *band; ofl_err error; @@ -631,6 +643,7 @@ ofl_msg_unpack_meter_mod(struct ofp_header *src, size_t *len, struct ofl_msg_hea static ofl_err ofl_msg_unpack_port_mod(struct ofp_header *src, size_t *len, struct ofl_msg_header **msg) { + struct ofp_port_mod *sm; struct ofl_msg_port_mod *dm; @@ -665,6 +678,7 @@ ofl_msg_unpack_port_mod(struct ofp_header *src, size_t *len, struct ofl_msg_head static ofl_err ofl_msg_unpack_table_mod(struct ofp_header *src, size_t *len, struct ofl_msg_header **msg) { + struct ofp_table_mod *sm; struct ofl_msg_table_mod *dm; @@ -677,7 +691,7 @@ ofl_msg_unpack_table_mod(struct ofp_header *src, size_t *len, struct ofl_msg_hea sm = (struct ofp_table_mod *)src; dm = (struct ofl_msg_table_mod *)malloc(sizeof(struct ofl_msg_table_mod)); if (sm->table_id >= PIPELINE_TABLES) { - OFL_LOG_WARN(LOG_MODULE, "Received TABLE_MOD message has invalid table id (%zu).", sm->table_id ); + OFL_LOG_WARN(LOG_MODULE, "Received TABLE_MOD message has invalid table id (%d).", sm->table_id ); return ofl_error(OFPET_BAD_REQUEST, OFPBRC_BAD_TABLE_ID); } @@ -690,6 +704,7 @@ ofl_msg_unpack_table_mod(struct ofp_header *src, size_t *len, struct ofl_msg_hea static ofl_err ofl_msg_unpack_multipart_request_flow(struct ofp_multipart_request *os, uint8_t* buf, size_t *len, struct ofl_msg_header **msg, struct ofl_exp *exp) { + struct ofp_flow_stats_request *sm; struct ofl_msg_multipart_request_flow *dm; ofl_err error = 0; @@ -707,7 +722,7 @@ ofl_msg_unpack_multipart_request_flow(struct ofp_multipart_request *os, uint8_t* dm = (struct ofl_msg_multipart_request_flow *) malloc(sizeof(struct ofl_msg_multipart_request_flow)); if (sm->table_id != OFPTT_ALL && sm->table_id >= PIPELINE_TABLES) { - OFL_LOG_WARN(LOG_MODULE, "Received MULTIPART REQUEST FLOW message has invalid table id (%zu).", sm->table_id ); + OFL_LOG_WARN(LOG_MODULE, "Received MULTIPART REQUEST FLOW message has invalid table id (%d).", sm->table_id ); return ofl_error(OFPET_BAD_REQUEST, OFPBRC_BAD_TABLE_ID); } @@ -730,6 +745,7 @@ ofl_msg_unpack_multipart_request_flow(struct ofp_multipart_request *os, uint8_t* static ofl_err ofl_msg_unpack_multipart_request_port(struct ofp_multipart_request *os, size_t *len, struct ofl_msg_header **msg) { + struct ofp_port_stats_request *sm; struct ofl_msg_multipart_request_port *dm; @@ -760,6 +776,7 @@ ofl_msg_unpack_multipart_request_port(struct ofp_multipart_request *os, size_t * static ofl_err ofl_msg_unpack_multipart_request_empty(struct ofp_multipart_request *os UNUSED, size_t *len, struct ofl_msg_header **msg) { + // ofp_multipart_request length was checked at ofl_msg_unpack_multipart_request len -= sizeof(struct ofp_multipart_request); @@ -769,11 +786,11 @@ ofl_msg_unpack_multipart_request_empty(struct ofp_multipart_request *os UNUSED, static ofl_err ofl_msg_unpack_multipart_request_table_features(struct ofp_multipart_request *os, size_t *len, struct ofl_msg_header **msg, struct ofl_exp *exp){ + struct ofl_msg_multipart_request_table_features *dm; ofl_err error; uint8_t *features; size_t i; - dm = (struct ofl_msg_multipart_request_table_features*) malloc(sizeof(struct ofl_msg_multipart_request_table_features)); if (!(*len)){ dm->tables_num = 0; @@ -792,6 +809,12 @@ ofl_msg_unpack_multipart_request_table_features(struct ofp_multipart_request *os for(i = 0; i < dm->tables_num; i++){ error = ofl_structs_table_features_unpack((struct ofp_table_features*) features, len, &dm->table_features[i] , exp); + if (error) { + OFL_UTILS_FREE_ARR_FUN2(dm->table_features, i, + ofl_structs_free_table_features, exp); + free(dm); + return error; + } features += ntohs(((struct ofp_table_features*) features)->length); } *msg = (struct ofl_msg_header *)dm; @@ -800,6 +823,7 @@ ofl_msg_unpack_multipart_request_table_features(struct ofp_multipart_request *os static ofl_err ofl_msg_unpack_multipart_request_queue(struct ofp_multipart_request *os, size_t *len, struct ofl_msg_header **msg) { + struct ofp_queue_stats_request *sm; struct ofl_msg_multipart_request_queue *dm; @@ -830,6 +854,7 @@ ofl_msg_unpack_multipart_request_queue(struct ofp_multipart_request *os, size_t static ofl_err ofl_msg_unpack_multipart_request_group(struct ofp_multipart_request *os, size_t *len, struct ofl_msg_header **msg) { + struct ofp_group_stats_request *sm; struct ofl_msg_multipart_request_group *dm; @@ -852,6 +877,7 @@ ofl_msg_unpack_multipart_request_group(struct ofp_multipart_request *os, size_t static ofl_err ofl_msg_unpack_meter_multipart_request(struct ofp_multipart_request *os, size_t *len, struct ofl_msg_header **msg) { + struct ofp_meter_multipart_request *sm; struct ofl_msg_multipart_meter_request *dm; @@ -874,6 +900,7 @@ ofl_msg_unpack_meter_multipart_request(struct ofp_multipart_request *os, size_t static ofl_err ofl_msg_unpack_multipart_request(struct ofp_header *src,uint8_t *buf, size_t *len, struct ofl_msg_header **msg, struct ofl_exp *exp) { + struct ofl_msg_multipart_request_header *ofls; struct ofp_multipart_request *os; int error; @@ -956,7 +983,7 @@ ofl_msg_unpack_multipart_request(struct ofp_header *src,uint8_t *buf, size_t *le } ofls = (struct ofl_msg_multipart_request_header *)(*msg); - ofls->type = (enum ofp_multipart_types)ntohs(os->type); + ofls->type = (enum ofp_multipart_types)((int)ntohs(os->type)); ofls->flags = ntohs(os->flags); return 0; @@ -964,6 +991,7 @@ ofl_msg_unpack_multipart_request(struct ofp_header *src,uint8_t *buf, size_t *le static ofl_err ofl_msg_unpack_reply_desc(struct ofp_multipart_reply *os, size_t *len, struct ofl_msg_header **msg) { + struct ofp_desc *sm; struct ofl_msg_reply_desc *dm; @@ -989,6 +1017,7 @@ ofl_msg_unpack_reply_desc(struct ofp_multipart_reply *os, size_t *len, struct of static ofl_err ofl_msg_unpack_multipart_reply_flow(struct ofp_multipart_reply *os, uint8_t *buf, size_t *len, struct ofl_msg_header **msg, struct ofl_exp *exp) { + struct ofp_flow_stats *stat; struct ofl_msg_multipart_reply_flow *dm; ofl_err error; @@ -1027,6 +1056,7 @@ ofl_msg_unpack_multipart_reply_flow(struct ofp_multipart_reply *os, uint8_t *buf static ofl_err ofl_msg_unpack_multipart_reply_aggregate(struct ofp_multipart_reply *os, size_t *len, struct ofl_msg_header **msg) { + struct ofp_aggregate_stats_reply *sm; struct ofl_msg_multipart_reply_aggregate *dm; @@ -1051,6 +1081,7 @@ ofl_msg_unpack_multipart_reply_aggregate(struct ofp_multipart_reply *os, size_t static ofl_err ofl_msg_unpack_multipart_reply_table(struct ofp_multipart_reply *os, size_t *len, struct ofl_msg_header **msg) { + struct ofp_table_stats *stat; struct ofl_msg_multipart_reply_table *dm; ofl_err error; @@ -1084,6 +1115,7 @@ ofl_msg_unpack_multipart_reply_table(struct ofp_multipart_reply *os, size_t *len static ofl_err ofl_msg_unpack_multipart_reply_port(struct ofp_multipart_reply *os, size_t *len, struct ofl_msg_header **msg) { + struct ofp_port_stats *stat = (struct ofp_port_stats *)os->body; struct ofl_msg_multipart_reply_port *dm = (struct ofl_msg_multipart_reply_port *) malloc(sizeof(struct ofl_msg_multipart_reply_port)); ofl_err error; @@ -1092,7 +1124,6 @@ ofl_msg_unpack_multipart_reply_port(struct ofp_multipart_reply *os, size_t *len, // ofp_multipart_reply was already checked and subtracted in unpack_multipart_reply stat = (struct ofp_port_stats *)os->body; - dm = (struct ofl_msg_multipart_reply_port *) malloc(sizeof(struct ofl_msg_multipart_reply_port)); error = ofl_utils_count_ofp_port_stats(stat, *len, &dm->stats_num); if (error) { @@ -1118,6 +1149,7 @@ ofl_msg_unpack_multipart_reply_port(struct ofp_multipart_reply *os, size_t *len, static ofl_err ofl_msg_unpack_multipart_reply_queue(struct ofp_multipart_reply *os, size_t *len, struct ofl_msg_header **msg) { + struct ofp_queue_stats *stat = (struct ofp_queue_stats *)os->body; struct ofl_msg_multipart_reply_queue *dm = (struct ofl_msg_multipart_reply_queue *) malloc(sizeof(struct ofl_msg_multipart_reply_queue)); ofl_err error; @@ -1126,7 +1158,6 @@ ofl_msg_unpack_multipart_reply_queue(struct ofp_multipart_reply *os, size_t *len // ofp_multipart_reply was already checked and subtracted in unpack_multipart_reply stat = (struct ofp_queue_stats *)os->body; - dm = (struct ofl_msg_multipart_reply_queue *) malloc(sizeof(struct ofl_msg_multipart_reply_queue)); error = ofl_utils_count_ofp_queue_stats(stat, *len, &dm->stats_num); if (error) { @@ -1150,6 +1181,7 @@ ofl_msg_unpack_multipart_reply_queue(struct ofp_multipart_reply *os, size_t *len static ofl_err ofl_msg_unpack_multipart_reply_group(struct ofp_multipart_reply *os, size_t *len, struct ofl_msg_header **msg) { + struct ofp_group_stats *stat; struct ofl_msg_multipart_reply_group *dm; ofl_err error; @@ -1184,6 +1216,7 @@ ofl_msg_unpack_multipart_reply_group(struct ofp_multipart_reply *os, size_t *len static ofl_err ofl_msg_unpack_multipart_reply_group_desc(struct ofp_multipart_reply *os, size_t *len, struct ofl_msg_header **msg, struct ofl_exp *exp) { + struct ofp_group_desc_stats *stat; struct ofl_msg_multipart_reply_group_desc *dm; ofl_err error; @@ -1218,16 +1251,17 @@ ofl_msg_unpack_multipart_reply_group_desc(struct ofp_multipart_reply *os, size_t static ofl_err ofl_msg_unpack_multipart_reply_group_features(struct ofp_multipart_reply *os, size_t *len, struct ofl_msg_header **msg) { - struct ofp_group_features_stats *sm; + + struct ofp_group_features *sm; struct ofl_msg_multipart_reply_group_features *dm; int i; - if (*len < sizeof(struct ofp_group_features_stats)) { + if (*len < sizeof(struct ofp_group_features)) { OFL_LOG_WARN(LOG_MODULE, "Received OFPMP_GROUP_FEATURES stats reply has invalid length (%zu).", *len); return ofl_error(OFPET_BAD_REQUEST, OFPBRC_BAD_LEN); } - *len -= sizeof(struct ofp_group_features_stats); + *len -= sizeof(struct ofp_group_features); - sm = (struct ofp_group_features_stats *)os->body; + sm = (struct ofp_group_features *)os->body; dm = (struct ofl_msg_multipart_reply_group_features *) malloc(sizeof(struct ofl_msg_multipart_reply_group_features)); dm->types = ntohl(sm->types); @@ -1243,6 +1277,7 @@ ofl_msg_unpack_multipart_reply_group_features(struct ofp_multipart_reply *os, si static ofl_err ofl_msg_unpack_multipart_reply_table_features(struct ofp_multipart_reply *src, size_t *len, struct ofl_msg_header **msg, struct ofl_exp *exp){ + struct ofl_msg_multipart_reply_table_features *dm; int i; ofl_err error; @@ -1260,6 +1295,12 @@ ofl_msg_unpack_multipart_reply_table_features(struct ofp_multipart_reply *src, s for(i = 0; i < dm->tables_num; i++){ error = ofl_structs_table_features_unpack((struct ofp_table_features*) features, len, &dm->table_features[i] , exp); + if (error) { + OFL_UTILS_FREE_ARR_FUN2(dm->table_features, i, + ofl_structs_free_table_features, exp); + free(dm); + return error; + } features += ntohs(((struct ofp_table_features*) features)->length); } *msg = (struct ofl_msg_header *)dm; @@ -1268,6 +1309,7 @@ ofl_msg_unpack_multipart_reply_table_features(struct ofp_multipart_reply *src, s static ofl_err ofl_msg_unpack_multipart_reply_meter_stats(struct ofp_multipart_reply *os, size_t *len, struct ofl_msg_header **msg) { + struct ofp_meter_stats *stat; struct ofl_msg_multipart_reply_meter *dm; ofl_err error; @@ -1302,6 +1344,7 @@ ofl_msg_unpack_multipart_reply_meter_stats(struct ofp_multipart_reply *os, size_ static ofl_err ofl_msg_unpack_multipart_reply_meter_config(struct ofp_multipart_reply *os, size_t *len, struct ofl_msg_header **msg){ + struct ofp_meter_config *conf; struct ofl_msg_multipart_reply_meter_conf *dm; ofl_err error; @@ -1336,6 +1379,7 @@ ofl_msg_unpack_multipart_reply_meter_config(struct ofp_multipart_reply *os, size static ofl_err ofl_msg_unpack_multipart_reply_port_desc(struct ofp_multipart_reply *src, size_t *len, struct ofl_msg_header **msg) { + struct ofp_port *port; struct ofl_msg_multipart_reply_port_desc *pd; ofl_err error; @@ -1366,6 +1410,7 @@ ofl_msg_unpack_multipart_reply_port_desc(struct ofp_multipart_reply *src, size_t static ofl_err ofl_msg_unpack_multipart_reply_meter_features(struct ofp_multipart_reply *os, size_t *len, struct ofl_msg_header **msg) { + struct ofp_meter_features *src; struct ofl_msg_multipart_reply_meter_features *dst; @@ -1391,6 +1436,7 @@ ofl_msg_unpack_multipart_reply_meter_features(struct ofp_multipart_reply *os, si static ofl_err ofl_msg_unpack_multipart_reply(struct ofp_header *src, uint8_t *buf, size_t *len, struct ofl_msg_header **msg, struct ofl_exp *exp) { + struct ofl_msg_multipart_reply_header *ofls; struct ofp_multipart_reply *os; int error; @@ -1477,7 +1523,7 @@ ofl_msg_unpack_multipart_reply(struct ofp_header *src, uint8_t *buf, size_t *len } ofls = (struct ofl_msg_multipart_reply_header *)(*msg); - ofls->type = (enum ofp_multipart_types)ntohs(os->type); + ofls->type = (enum ofp_multipart_types)((int)ntohs(os->type)); ofls->flags = ntohs(os->flags); return 0; @@ -1485,6 +1531,7 @@ ofl_msg_unpack_multipart_reply(struct ofp_header *src, uint8_t *buf, size_t *len static ofl_err ofl_msg_unpack_queue_get_config_request(struct ofp_header *src, size_t *len, struct ofl_msg_header **msg) { + struct ofp_queue_get_config_request *sr; struct ofl_msg_queue_get_config_request *dr; @@ -1511,6 +1558,7 @@ ofl_msg_unpack_queue_get_config_request(struct ofp_header *src, size_t *len, str static ofl_err ofl_msg_unpack_queue_get_config_reply(struct ofp_header *src, size_t *len, struct ofl_msg_header **msg) { + struct ofp_queue_get_config_reply *sr; struct ofl_msg_queue_get_config_reply *dr; struct ofp_packet_queue *queue; @@ -1537,7 +1585,7 @@ ofl_msg_unpack_queue_get_config_reply(struct ofp_header *src, size_t *len, struc queue = sr->queues; for (i = 0; i < dr->queues_num; i++) { - error = ofl_structs_packet_queue_unpack(queue, len, &(dr->queues[i])); + error = ofl_structs_packet_queue_unpack(queue, len, &(dr->queues[i])); if (error) { OFL_UTILS_FREE_ARR_FUN(dr->queues, i, ofl_structs_free_packet_queue); @@ -1554,6 +1602,7 @@ ofl_msg_unpack_queue_get_config_reply(struct ofp_header *src, size_t *len, struc static ofl_err ofl_msg_unpack_empty(struct ofp_header *src UNUSED, size_t *len, struct ofl_msg_header **msg) { + // ofp_header length was checked at ofl_msg_unpack *len -= sizeof(struct ofp_header); diff --git a/oflib/ofl-messages.c b/oflib/ofl-messages.c index 73a2134a..d2c0f381 100644 --- a/oflib/ofl-messages.c +++ b/oflib/ofl-messages.c @@ -360,6 +360,94 @@ ofl_msg_free_flow_removed(struct ofl_msg_flow_removed *msg, bool with_stats, str +bool +ofl_msg_merge_multipart_request_table_features(struct ofl_msg_multipart_request_table_features *orig, struct ofl_msg_multipart_request_table_features *merge) { + uint32_t new_tables_num; + size_t i, j; + struct ofl_table_feature_prop_header **properties; + struct ofl_table_feature_prop_header *old_prop; + struct ofl_table_feature_prop_header *new_prop; + int properties_num; + int k; + + /* Keep body potentially empty if nothing to merge. Jean II */ + if(merge->tables_num) { + new_tables_num = orig->tables_num + merge->tables_num; + + orig->table_features = (struct ofl_table_features ** )realloc(orig->table_features, new_tables_num * sizeof(struct ofl_table_features *)); + + for (i=0; i < merge->tables_num; i++) { + j = orig->tables_num + i; + orig->table_features[j] = (struct ofl_table_features *)malloc(sizeof(struct ofl_table_features)); + memcpy(orig->table_features[j], merge->table_features[i], sizeof(struct ofl_table_features)); + properties = merge->table_features[i]->properties; + properties_num = merge->table_features[i]->properties_num; + for (k = 0; k < properties_num; k++) { + old_prop = properties[k]; + switch (old_prop->type) { + case OFPTFPT_INSTRUCTIONS: + case OFPTFPT_INSTRUCTIONS_MISS: { + struct ofl_table_feature_prop_instructions *old_prop_i = (struct ofl_table_feature_prop_instructions*) old_prop; + struct ofl_table_feature_prop_instructions *new_prop_i; + new_prop_i = (struct ofl_table_feature_prop_instructions*) malloc(sizeof(struct ofl_table_feature_prop_instructions)); + new_prop = (struct ofl_table_feature_prop_header *) new_prop_i; + memcpy((char *) new_prop, (char *) old_prop, sizeof(struct ofl_table_feature_prop_instructions)); + new_prop_i->instruction_ids = (struct ofl_instruction_header*) malloc(sizeof(struct ofl_instruction_header) * old_prop_i->ids_num); + memcpy((char *) new_prop_i->instruction_ids, (char *) old_prop_i->instruction_ids, sizeof(struct ofl_instruction_header) * old_prop_i->ids_num); + break; + } + case OFPTFPT_NEXT_TABLES: + case OFPTFPT_NEXT_TABLES_MISS: { + struct ofl_table_feature_prop_next_tables *old_prop_nt = (struct ofl_table_feature_prop_next_tables*) old_prop; + struct ofl_table_feature_prop_next_tables *new_prop_nt; + new_prop_nt = (struct ofl_table_feature_prop_next_tables*) malloc(sizeof(struct ofl_table_feature_prop_next_tables)); + new_prop = (struct ofl_table_feature_prop_header *) new_prop_nt; + memcpy((char *) new_prop, (char *) old_prop, sizeof(struct ofl_table_feature_prop_next_tables)); + new_prop_nt->next_table_ids = (uint8_t*) malloc(sizeof(uint8_t) * old_prop_nt->table_num); + memcpy((char *) new_prop_nt->next_table_ids, (char *) old_prop_nt->next_table_ids, sizeof(uint8_t) * old_prop_nt->table_num); + break; + } + case OFPTFPT_WRITE_ACTIONS: + case OFPTFPT_WRITE_ACTIONS_MISS: + case OFPTFPT_APPLY_ACTIONS: + case OFPTFPT_APPLY_ACTIONS_MISS: { + struct ofl_table_feature_prop_actions *old_prop_a = (struct ofl_table_feature_prop_actions*) old_prop; + struct ofl_table_feature_prop_actions *new_prop_a; + new_prop_a = (struct ofl_table_feature_prop_actions*) malloc(sizeof(struct ofl_table_feature_prop_actions)); + new_prop = (struct ofl_table_feature_prop_header *) new_prop_a; + memcpy((char *) new_prop, (char *) old_prop, sizeof(struct ofl_table_feature_prop_actions)); + new_prop_a->action_ids = (struct ofl_action_header*) malloc(sizeof(struct ofl_action_header) * old_prop_a->actions_num); + memcpy((char *) new_prop_a->action_ids, (char *) old_prop_a->action_ids, sizeof(struct ofl_action_header) * old_prop_a->actions_num); + break; + } + case OFPTFPT_MATCH: + case OFPTFPT_WILDCARDS: + case OFPTFPT_WRITE_SETFIELD: + case OFPTFPT_WRITE_SETFIELD_MISS: + case OFPTFPT_APPLY_SETFIELD: + case OFPTFPT_APPLY_SETFIELD_MISS: { + struct ofl_table_feature_prop_oxm *old_prop_o = (struct ofl_table_feature_prop_oxm*) old_prop; + struct ofl_table_feature_prop_oxm *new_prop_o; + new_prop_o = (struct ofl_table_feature_prop_oxm*) malloc(sizeof(struct ofl_table_feature_prop_oxm)); + new_prop = (struct ofl_table_feature_prop_header *) new_prop_o; + memcpy((char *) new_prop, (char *) old_prop, sizeof(struct ofl_table_feature_prop_oxm)); + new_prop_o->oxm_ids = (uint32_t*) malloc(sizeof(uint32_t) * old_prop_o->oxm_num); + memcpy((char *) new_prop_o->oxm_ids, (char *) old_prop_o->oxm_ids, sizeof(uint32_t) * old_prop_o->oxm_num); + break; + } + default: + new_prop = NULL; + } + orig->table_features[j]->properties[k] = new_prop; + } + } + + orig->tables_num = new_tables_num; + } + + return ((merge->header.flags & OFPMPF_REQ_MORE) == 0); +} + bool ofl_msg_merge_multipart_reply_flow(struct ofl_msg_multipart_reply_flow *orig, struct ofl_msg_multipart_reply_flow *merge) { uint32_t new_stats_num; diff --git a/oflib/ofl-packets.h b/oflib/ofl-packets.h index 2b3eb067..78893163 100644 --- a/oflib/ofl-packets.h +++ b/oflib/ofl-packets.h @@ -40,6 +40,7 @@ #define ETH_TYPE_MPLS 0x8847 #define ETH_TYPE_MPLS_MCAST 0x8848 +#define PBB_ISID_LEN 3 #define ETH_ADDR_LEN 6 #define IPv6_ADDR_LEN 16 diff --git a/oflib/ofl-print.c b/oflib/ofl-print.c index 2974a54c..7fe06b51 100644 --- a/oflib/ofl-print.c +++ b/oflib/ofl-print.c @@ -245,7 +245,7 @@ ofl_oxm_type_print(FILE *stream, uint32_t type){ case OXM_OF_UDP_SRC: {fprintf(stream, "udp_src"); return; } case OXM_OF_UDP_DST: {fprintf(stream, "udp_dst"); return; } case OXM_OF_SCTP_SRC: {fprintf(stream, "sctp_src"); return; } - case OXM_OF_SCTP_DST: {fprintf(stream, "udp_dst"); return; } + case OXM_OF_SCTP_DST: {fprintf(stream, "sctp_dst"); return; } case OXM_OF_ICMPV4_CODE: {fprintf(stream, "icmpv4_code"); return; } case OXM_OF_ICMPV4_TYPE: {fprintf(stream, "icmpv4_type"); return; } case OXM_OF_ARP_OP: {fprintf(stream, "arp_op"); return; } @@ -347,6 +347,7 @@ ofl_error_type_print(FILE *stream, uint16_t type) { case (OFPET_METER_MOD_FAILED): { fprintf(stream, "METER_MOD_FAILED"); return; } case (OFPET_QUEUE_OP_FAILED): { fprintf(stream, "QUEUE_OP_FAILED"); return; } case (OFPET_SWITCH_CONFIG_FAILED): { fprintf(stream, "SWITCH_CONFIG_FAILED"); return; } + case (OFPET_TABLE_FEATURES_FAILED): { fprintf(stream, "TABLE_FEATURES_FAILED"); return; } default: { fprintf(stream, "?(%u)", type); return; } } } @@ -505,6 +506,17 @@ ofl_error_code_print(FILE *stream, uint16_t type, uint16_t code) { } break; } + case (OFPET_TABLE_FEATURES_FAILED): { + switch (code) { + case (OFPTFFC_BAD_TABLE) : { fprintf(stream, "BAD_TABLE"); return; } + case (OFPTFFC_BAD_METADATA) : { fprintf(stream, "BAD_METADATA"); return; } + case (OFPTFFC_BAD_TYPE) : { fprintf(stream, "BAD_TYPE"); return; } + case (OFPTFFC_BAD_LEN) : { fprintf(stream, "BAD_LEN"); return; } + case (OFPTFFC_BAD_ARGUMENT) : { fprintf(stream, "BAD_ARGUMENT"); return; } + case (OFPTFFC_EPERM) : { fprintf(stream, "EPERM"); return; } + } + break; + } } fprintf(stream, "?(%u)", code); } diff --git a/oflib/ofl-structs-match.c b/oflib/ofl-structs-match.c index 8147611a..61fd4ca6 100644 --- a/oflib/ofl-structs-match.c +++ b/oflib/ofl-structs-match.c @@ -147,6 +147,32 @@ ofl_structs_match_put64m(struct ofl_match *match, uint32_t header, uint64_t valu } +void +ofl_structs_match_put_pbb_isid(struct ofl_match *match, uint32_t header, uint8_t value[PBB_ISID_LEN]){ + struct ofl_match_tlv *m = malloc(sizeof (struct ofl_match_tlv)); + int len = OXM_LENGTH(header); + + m->header = header; + m->value = malloc(len); + memcpy(m->value, value, len); + hmap_insert(&match->match_fields,&m->hmap_node,hash_int(header, 0)); + match->header.length += len + 4; +} + + +void +ofl_structs_match_put_pbb_isidm(struct ofl_match *match, uint32_t header, uint8_t value[PBB_ISID_LEN], uint8_t mask[PBB_ISID_LEN]){ + struct ofl_match_tlv *m = malloc(sizeof (struct ofl_match_tlv)); + int len = OXM_LENGTH(header); + + m->header = header; + m->value = malloc(len*2); + memcpy(m->value, value, len); + memcpy(m->value + len, mask, len); + hmap_insert(&match->match_fields,&m->hmap_node,hash_int(header, 0)); + match->header.length += len*2 + 4; +} + void ofl_structs_match_put_eth(struct ofl_match *match, uint32_t header, uint8_t value[ETH_ADDR_LEN]){ struct ofl_match_tlv *m = malloc(sizeof (struct ofl_match_tlv)); diff --git a/oflib/ofl-structs-pack.c b/oflib/ofl-structs-pack.c index 2ea85b02..1ab892aa 100644 --- a/oflib/ofl-structs-pack.c +++ b/oflib/ofl-structs-pack.c @@ -94,8 +94,6 @@ size_t ofl_structs_instructions_pack(struct ofl_instruction_header *src, struct ofp_instruction *dst, struct ofl_exp *exp) { dst->type = htons(src->type); - memset(dst->pad, 0x00, 4); - switch (src->type) { case OFPIT_GOTO_TABLE: { struct ofl_instruction_goto_table *si = (struct ofl_instruction_goto_table *)src; @@ -128,7 +126,7 @@ ofl_structs_instructions_pack(struct ofl_instruction_header *src, struct ofp_ins struct ofp_instruction_actions *di = (struct ofp_instruction_actions *)dst; total_len = sizeof(struct ofp_instruction_actions) + ofl_actions_ofp_total_len(si->actions, si->actions_num, exp); - + di->len = htons(total_len); memset(di->pad, 0x00, 4); data = (uint8_t *)dst + sizeof(struct ofp_instruction_actions); @@ -543,7 +541,8 @@ ofl_structs_flow_stats_pack(struct ofl_flow_stats *src, uint8_t *dst, struct ofl flow_stats->priority = htons(src->priority); flow_stats->idle_timeout = htons(src->idle_timeout); flow_stats->hard_timeout = htons(src->hard_timeout); - memset(flow_stats->pad2, 0x00, 6); + flow_stats->flags = htons(src->flags); + memset(flow_stats->pad2, 0x00, 4); flow_stats->cookie = hton64(src->cookie); flow_stats->packet_count = hton64(src->packet_count); flow_stats->byte_count = hton64(src->byte_count); @@ -764,7 +763,6 @@ ofl_structs_queue_prop_pack(struct ofl_queue_prop_header *src, dp->prop_header.len = htons(sizeof(struct ofp_queue_prop_min_rate)); dp->rate = htons(sp->rate); memset(dp->pad, 0x00, 6); - return sizeof(struct ofp_queue_prop_min_rate); } case OFPQT_MAX_RATE:{ @@ -817,13 +815,10 @@ ofl_structs_packet_queue_pack(struct ofl_packet_queue *src, struct ofp_packet_qu total_len = sizeof(struct ofp_packet_queue) + ofl_structs_queue_prop_ofp_total_len(src->properties, src->properties_num); - dst->len = htons(total_len); - memset(dst->pad, 0x00, 2); + memset(dst->pad, 0x00, 6); dst->queue_id = htonl(src->queue_id); - data = (uint8_t *)dst + sizeof(struct ofp_packet_queue); - for (i=0; iproperties_num; i++) { len = ofl_structs_queue_prop_pack(src->properties[i], (struct ofp_queue_prop_header *)data); diff --git a/oflib/ofl-structs-print.c b/oflib/ofl-structs-print.c index 76a7d3b8..776bb44b 100644 --- a/oflib/ofl-structs-print.c +++ b/oflib/ofl-structs-print.c @@ -48,11 +48,11 @@ #define ETH_ADDR_FMT \ - "%02"PRIx8":%02"PRIx8":%02"PRIx8":%02"PRIx8":%02"PRIx8":%02"PRIx8 + "%02" PRIx8 ":%02" PRIx8 ":%02" PRIx8 ":%02" PRIx8 ":%02" PRIx8 ":%02" PRIx8 #define ETH_ADDR_ARGS(ea) \ (ea)[0], (ea)[1], (ea)[2], (ea)[3], (ea)[4], (ea)[5] -#define IP_FMT "%"PRIu8".%"PRIu8".%"PRIu8".%"PRIu8 +#define IP_FMT "%" PRIu8 ".%" PRIu8 ".%" PRIu8 ".%" PRIu8 char * ofl_structs_port_to_string(struct ofl_port *port) { @@ -389,30 +389,30 @@ ofl_structs_oxm_tlv_print(FILE *stream, struct ofl_match_tlv *f) fprintf(stream, "icmpv6_code=\"%d\"", *f->value); break; case OFPXMT_OFB_MPLS_LABEL: - fprintf(stream, "mpls_label=\"%d\"",((uint32_t) *f->value) & 0x000fffff); + fprintf(stream, "mpls_label=\"%d\"",*((uint32_t*) f->value) & 0x000fffff); break; case OFPXMT_OFB_MPLS_TC: fprintf(stream, "mpls_tc=\"%d\"", *f->value & 0x3); break; case OFPXMT_OFB_MPLS_BOS: - fprintf(stream, "mpls_bos=\"%d\"", *f->value & 0xfe); + fprintf(stream, "mpls_bos=\"%d\"", *f->value & 0x1); break; case OFPXMT_OFB_METADATA: - fprintf(stream, "metadata=\"0x%llx\"", *((uint64_t*) f->value)); + fprintf(stream, "metadata=\"0x%"PRIx64"\"", *((uint64_t*) f->value)); if (OXM_HASMASK(f->header)) { - fprintf(stream, ", metadata_mask=\"0x%llx\"", *((uint64_t*)(f->value+8))); + fprintf(stream, ", metadata_mask=\"0x%"PRIx64"\"", *((uint64_t*)(f->value+8))); } break; case OFPXMT_OFB_PBB_ISID : fprintf(stream, "pbb_isid=\"%d\"", *((uint32_t*) f->value)); if (OXM_HASMASK(f->header)) { - fprintf(stream, ", pbb_isid_mask=\"%d\"", *((uint32_t*)(f->value+4))); + fprintf(stream, ", pbb_isid_mask=\"%x%x%x\"", (f->value+4)[0], (f->value+4)[1], (f->value+4)[2]); } break; case OFPXMT_OFB_TUNNEL_ID: - fprintf(stream, "tunnel_id=\"%lld\"", *((uint64_t*) f->value)); + fprintf(stream, "tunnel_id=\"0x%"PRIx64"\"", *((uint64_t*) f->value)); if (OXM_HASMASK(f->header)) { - fprintf(stream, ", tunnel_id_mask=\"%lld\"", *((uint64_t*)(f->value+8))); + fprintf(stream, ", tunnel_id_mask=\"0x%"PRIx64"\"", *((uint64_t*)(f->value+8))); } break; case OFPXMT_OFB_IPV6_EXTHDR: @@ -517,12 +517,18 @@ ofl_structs_queue_prop_print(FILE *stream, struct ofl_queue_prop_header *p) { case (OFPQT_MIN_RATE): { struct ofl_queue_prop_min_rate *pm = (struct ofl_queue_prop_min_rate *)p; - fprintf(stream, "{rate=\"%u\"}", pm->rate); + fprintf(stream, "{min rate=\"%u\"}", pm->rate); break; } - - } + case (OFPQT_MAX_RATE): { + struct ofl_queue_prop_max_rate *pm = (struct ofl_queue_prop_max_rate *)p; + fprintf(stream, "{max rate=\"%u\"}", pm->rate); + break; + } + case (OFPQT_EXPERIMENTER): + break; + } } char * @@ -723,8 +729,8 @@ ofl_structs_meter_features_to_string(struct ofl_meter_features* s){ void ofl_structs_meter_features_print(FILE *stream, struct ofl_meter_features* s){ - fprintf(stream, "{max_meter=\"%"PRIu32"\", band_types=\"%"PRIx32"\"," - "capabilities =\"%"PRIx32"\", max_bands = %u , max_color = %u", + fprintf(stream, "{max_meter=\"%"PRIu32"\", band_types=\"0x%"PRIx32"\"," + "capabilities =\"0x%"PRIx32"\", max_bands = %u , max_color = %u", s->max_meter, s->band_types, s->capabilities, s->max_bands, s->max_color); fprintf(stream, "}"); @@ -850,7 +856,7 @@ ofl_structs_table_features_print(FILE *stream, struct ofl_table_features *s){ fprintf(stream, "{table=\""); ofl_table_print(stream, s->table_id); fprintf(stream, "\", name=\"%s\", " - "metadata_match=\"%"PRIx64"\", metadata_write=\"%"PRIx64"\", config=\"%"PRIu32"\"," + "metadata_match=\"0x%"PRIx64"\", metadata_write=\"0x%"PRIx64"\", config=\"%"PRIu32"\"," "max_entries=\"%"PRIu32"\"", s->name, s->metadata_match, s->metadata_write, s->config, s->max_entries); for(i =0; i < s->properties_num; i++){ diff --git a/oflib/ofl-structs-unpack.c b/oflib/ofl-structs-unpack.c index fbf54f83..69462db2 100644 --- a/oflib/ofl-structs-unpack.c +++ b/oflib/ofl-structs-unpack.c @@ -49,12 +49,12 @@ ofl_err ofl_structs_instructions_unpack(struct ofp_instruction *src, size_t *len, struct ofl_instruction_header **dst, struct ofl_exp *exp) { size_t ilen; struct ofl_instruction_header *inst = NULL; - + if (*len < sizeof(struct ofp_instruction)) { OFL_LOG_WARN(LOG_MODULE, "Received instruction is too short (%zu).", *len); return ofl_error(OFPET_BAD_ACTION, OFPBAC_BAD_LEN); } - + if (*len < ntohs(src->len)) { OFL_LOG_WARN(LOG_MODULE, "Received instruction has invalid length (set to %u, but only %zu received).", ntohs(src->len), *len); return ofl_error(OFPET_BAD_ACTION, OFPBAC_BAD_LEN); @@ -157,7 +157,7 @@ ofl_structs_instructions_unpack(struct ofp_instruction *src, size_t *len, struct } inst = (struct ofl_instruction_header *)malloc(sizeof(struct ofl_instruction_header)); - inst->type = (enum ofp_instruction_type)ntohs(src->type); + inst->type = (enum ofp_instruction_type)((int)ntohs(src->type)); ilen -= sizeof(struct ofp_instruction_actions); break; @@ -192,10 +192,13 @@ ofl_structs_instructions_unpack(struct ofp_instruction *src, size_t *len, struct } break; } + default: + OFL_LOG_WARN(LOG_MODULE, "The received instruction type (%d) is invalid.", ntohs(src->type)); + return ofl_error(OFPET_BAD_INSTRUCTION, OFPBIC_UNKNOWN_INST); } // must set type before check, so free works correctly - inst->type = (enum ofp_instruction_type)ntohs(src->type); + inst->type = (enum ofp_instruction_type)((int)ntohs(src->type)); if (ilen != 0) { *len = *len - ntohs(src->len) + ilen; @@ -211,7 +214,7 @@ ofl_structs_instructions_unpack(struct ofp_instruction *src, size_t *len, struct } static ofl_err -ofl_structs_table_properties_unpack(struct ofp_table_feature_prop_header * src, size_t *len, struct ofl_table_feature_prop_header **dst, struct ofl_exp *exp){ +ofl_structs_table_properties_unpack(struct ofp_table_feature_prop_header * src, size_t *len, struct ofl_table_feature_prop_header **dst, struct ofl_exp *exp UNUSED){ size_t plen; ofl_err error; struct ofl_table_feature_prop_header * prop = NULL; @@ -223,7 +226,7 @@ ofl_structs_table_properties_unpack(struct ofp_table_feature_prop_header * src, if (*len < ntohs(src->length)) { OFL_LOG_WARN(LOG_MODULE, "Received table property has invalid length (set to %u, but only %zu received).", ntohs(src->length), *len); - return ofl_error(OFPET_BAD_ACTION, OFPBAC_BAD_LEN); + return ofl_error(OFPET_TABLE_FEATURES_FAILED, OFPTFFC_BAD_LEN); } plen = ntohs(src->length); @@ -337,9 +340,13 @@ ofl_structs_table_properties_unpack(struct ofp_table_feature_prop_header * src, break; } + default: + OFL_LOG_WARN(LOG_MODULE, "The received property contained a unknown property (%u).", ntohs(src->type)); + return ofl_error(OFPET_TABLE_FEATURES_FAILED, OFPTFFC_BAD_TYPE); } + // must set type before check, so free works correctly - prop->type = (enum ofp_table_feature_prop_type) ntohs(src->type); + prop->type = (enum ofp_table_feature_prop_type)((int)ntohs(src->type)); /* Make sure it can be reused for packing. Jean II */ prop->length = ntohs(src->length); @@ -491,7 +498,6 @@ ofl_structs_flow_stats_unpack(struct ofp_flow_stats *src, uint8_t *buf, size_t * OFL_LOG_WARN(LOG_MODULE, "Received flow stats has invalid length (%zu).", *len); return ofl_error(OFPET_BAD_REQUEST, OFPBRC_BAD_LEN); } - if (*len < ntohs(src->length)) { OFL_LOG_WARN(LOG_MODULE, "Received flow stats reply has invalid length (set to %u, but only %zu received).", ntohs(src->length), *len); return ofl_error(OFPET_BAD_REQUEST, OFPBRC_BAD_LEN); @@ -515,6 +521,7 @@ ofl_structs_flow_stats_unpack(struct ofp_flow_stats *src, uint8_t *buf, size_t * s->priority = ntohs( src->priority); s->idle_timeout = ntohs( src->idle_timeout); s->hard_timeout = ntohs( src->hard_timeout); + s->flags = ntohs( src->flags); s->cookie = ntoh64(src->cookie); s->packet_count = ntoh64(src->packet_count); s->byte_count = ntoh64(src->byte_count); @@ -824,7 +831,7 @@ ofl_structs_queue_prop_unpack(struct ofp_queue_prop_header *src, size_t *len, st } } - (*dst)->type = (enum ofp_queue_properties)ntohs(src->property); + (*dst)->type = (enum ofp_queue_properties)((int)ntohs(src->property)); return 0; } @@ -835,7 +842,7 @@ ofl_structs_packet_queue_unpack(struct ofp_packet_queue *src, size_t *len, struc struct ofp_queue_prop_header *prop; ofl_err error; size_t i; - + size_t prop_len; if (*len < ntohs(src->len)) { OFL_LOG_WARN(LOG_MODULE, "Received packet queue has invalid length (%zu).", *len); return ofl_error(OFPET_BAD_ACTION, OFPBRC_BAD_LEN); @@ -845,7 +852,8 @@ ofl_structs_packet_queue_unpack(struct ofp_packet_queue *src, size_t *len, struc q = (struct ofl_packet_queue *)malloc(sizeof(struct ofl_packet_queue)); q->queue_id = ntohl(src->queue_id); - error = ofl_utils_count_ofp_queue_props((uint8_t *)src->properties, *len, &q->properties_num); + prop_len = ntohs(src->len) - sizeof(struct ofp_packet_queue); + error = ofl_utils_count_ofp_queue_props((uint8_t *)src->properties, prop_len, &q->properties_num); if (error) { free(q); return error; @@ -857,7 +865,6 @@ ofl_structs_packet_queue_unpack(struct ofp_packet_queue *src, size_t *len, struc ofl_structs_queue_prop_unpack(prop, len, &(q->properties[i])); prop = (struct ofp_queue_prop_header *)((uint8_t *)prop + ntohs(prop->len)); } - *dst = q; return 0; } @@ -1146,7 +1153,8 @@ ofl_structs_oxm_match_unpack(struct ofp_match* src, uint8_t* buf, size_t *len, s } else { m->header.length = 0; - m->header.type = ntohs(src->type); + m->header.type = ntohs(src->type); + m->match_fields = (struct hmap) HMAP_INITIALIZER(&m->match_fields); } ofpbuf_delete(b); *dst = m; @@ -1158,9 +1166,7 @@ ofl_structs_match_unpack(struct ofp_match *src,uint8_t * buf, size_t *len, struc switch (ntohs(src->type)) { case (OFPMT_OXM): { - - return ofl_structs_oxm_match_unpack(src, buf, len, (struct ofl_match**) dst ); - + return ofl_structs_oxm_match_unpack(src, buf, len, (struct ofl_match**) dst ); } default: { if (exp == NULL || exp->match == NULL || exp->match->unpack == NULL) { diff --git a/oflib/ofl-structs.c b/oflib/ofl-structs.c index c3ea0716..efae08fe 100644 --- a/oflib/ofl-structs.c +++ b/oflib/ofl-structs.c @@ -50,7 +50,6 @@ ofl_utils_count_ofp_table_features_properties(void *data, size_t data_len, size_ struct ofp_table_feature_prop_header *prop; uint8_t *d; - d = (uint8_t*) data; *count = 0; while (data_len >= sizeof(struct ofp_table_feature_prop_header)){ @@ -68,9 +67,9 @@ ofl_utils_count_ofp_table_features_properties(void *data, size_t data_len, size_ ofl_err ofl_utils_count_ofp_table_features(void *data, size_t data_len, size_t *count){ + struct ofp_table_features *feature; uint8_t *d; - d = (uint8_t*) data; *count = 0; while (data_len >= sizeof(struct ofp_table_features)){ @@ -90,37 +89,33 @@ ofl_utils_count_ofp_table_features(void *data, size_t data_len, size_t *count){ ofl_err ofl_utils_count_ofp_instructions(void *data, size_t data_len, size_t *count) { + struct ofp_instruction *inst; uint8_t *d; - d = (uint8_t *)data; *count = 0; /* this is needed so that buckets are handled correctly */ - while (data_len >= sizeof(struct ofp_instruction)- 4) { + while (data_len > sizeof(struct ofp_instruction)) { inst = (struct ofp_instruction *)d; if (data_len < ntohs(inst->len) || ntohs(inst->len) < sizeof(struct ofp_instruction) - 4) { OFL_LOG_WARN(LOG_MODULE, "Received instruction has invalid length."); return ofl_error(OFPET_BAD_REQUEST, OFPBRC_BAD_LEN); - } data_len -= ntohs(inst->len); d += ntohs(inst->len); (*count)++; - } - return 0; } ofl_err ofl_utils_count_ofp_buckets(void *data, size_t data_len, size_t *count) { + struct ofp_bucket *bucket; uint8_t *d; - d = (uint8_t *)data; *count = 0; - while (data_len >= sizeof(struct ofp_bucket)) { bucket = (struct ofp_bucket *)d; @@ -132,19 +127,17 @@ ofl_utils_count_ofp_buckets(void *data, size_t data_len, size_t *count) { d += ntohs(bucket->len); (*count)++; } - return 0; } ofl_err ofl_utils_count_ofp_meter_bands(void *data, size_t data_len, size_t *count) { + struct ofp_meter_band_header *mb; uint8_t *d; - d = (uint8_t *)data; *count = 0; - while (data_len >= sizeof(struct ofp_meter_band_header)) { mb = (struct ofp_meter_band_header *)d; @@ -156,12 +149,12 @@ ofl_utils_count_ofp_meter_bands(void *data, size_t data_len, size_t *count) { d += ntohs(mb->len); (*count)++; } - return 0; } ofl_err ofl_utils_count_ofp_ports(void *data UNUSED, size_t data_len, size_t *count) { + *count = data_len / sizeof(struct ofp_port); return 0; } @@ -169,12 +162,11 @@ ofl_utils_count_ofp_ports(void *data UNUSED, size_t data_len, size_t *count) { ofl_err ofl_utils_count_ofp_packet_queues(void *data, size_t data_len, size_t *count) { + struct ofp_packet_queue *queue; uint8_t *d; - d = (uint8_t *)data; *count = 0; - while (data_len >= sizeof(struct ofp_packet_queue)) { queue = (struct ofp_packet_queue *)d; @@ -186,16 +178,14 @@ ofl_utils_count_ofp_packet_queues(void *data, size_t data_len, size_t *count) { d += ntohs(queue->len); (*count)++; } - return 0; - } ofl_err ofl_utils_count_ofp_flow_stats(void *data, size_t data_len, size_t *count) { + struct ofp_flow_stats *stat; uint8_t *d; - d = (uint8_t *)data; *count = 0; while (data_len >= sizeof(struct ofp_flow_stats)) { @@ -208,18 +198,16 @@ ofl_utils_count_ofp_flow_stats(void *data, size_t data_len, size_t *count) { d += ntohs(stat->length); (*count)++; } - return 0; } ofl_err ofl_utils_count_ofp_group_stats(void *data, size_t data_len, size_t *count) { + struct ofp_group_stats *stat; uint8_t *d; - d = (uint8_t *)data; *count = 0; - while (data_len >= sizeof(struct ofp_group_stats)) { stat = (struct ofp_group_stats *)d; @@ -231,44 +219,45 @@ ofl_utils_count_ofp_group_stats(void *data, size_t data_len, size_t *count) { d += ntohs(stat->length); (*count)++; } - return 0; } ofl_err ofl_utils_count_ofp_table_stats(void *data UNUSED, size_t data_len, size_t *count) { + *count = data_len / sizeof(struct ofp_table_stats); return 0; - } ofl_err ofl_utils_count_ofp_bucket_counters(void *data UNUSED, size_t data_len, size_t *count) { + *count = data_len / sizeof(struct ofp_bucket_counter); return 0; } ofl_err ofl_utils_count_ofp_port_stats(void *data UNUSED, size_t data_len, size_t *count) { + *count = data_len / sizeof(struct ofp_port_stats); return 0; } ofl_err ofl_utils_count_ofp_queue_stats(void *data UNUSED, size_t data_len, size_t *count) { + *count = data_len / sizeof(struct ofp_queue_stats); return 0; } ofl_err ofl_utils_count_ofp_group_desc_stats(void *data UNUSED, size_t data_len, size_t *count) { + struct ofp_group_desc_stats *stat; uint8_t *d; - d = (uint8_t *)data; *count = 0; - while (data_len >= sizeof(struct ofp_group_desc_stats)) { stat = (struct ofp_group_desc_stats *)d; @@ -280,18 +269,15 @@ ofl_utils_count_ofp_group_desc_stats(void *data UNUSED, size_t data_len, size_t d += ntohs(stat->length); (*count)++; } - return 0; } ofl_err -ofl_utils_count_ofp_queue_props(void *data, size_t data_len, size_t *count) { +ofl_utils_count_ofp_queue_props(void *data, size_t data_len, size_t *count) { struct ofp_queue_prop_header *prop; uint8_t *d; - d = (uint8_t *)data; (*count) = 0; - while (data_len >= sizeof(struct ofp_queue_prop_header)) { prop = (struct ofp_queue_prop_header *)d; @@ -303,15 +289,14 @@ ofl_utils_count_ofp_queue_props(void *data, size_t data_len, size_t *count) { d += ntohs(prop->len); (*count)++; } - return 0; } ofl_err ofl_utils_count_ofp_meter_stats(void *data, size_t data_len, size_t *count){ + struct ofp_meter_stats *stats; uint8_t *d; - d = (uint8_t *)data; (*count) = 0; @@ -331,11 +316,10 @@ ofl_utils_count_ofp_meter_stats(void *data, size_t data_len, size_t *count){ ofl_err ofl_utils_count_ofp_meter_band_stats(void *data, size_t data_len, size_t *count){ - uint8_t *d; + uint8_t *d; d = (uint8_t *)data; (*count) = 0; - while (data_len >= sizeof(struct ofp_meter_band_stats)) { if (data_len < sizeof(struct ofp_meter_band_stats)) { @@ -351,12 +335,11 @@ ofl_utils_count_ofp_meter_band_stats(void *data, size_t data_len, size_t *count) ofl_err ofl_utils_count_ofp_meter_config(void *data, size_t data_len, size_t *count){ + struct ofp_meter_config *config; uint8_t *d; - d = (uint8_t *)data; (*count) = 0; - while (data_len >= sizeof(struct ofp_meter_config)) { config = (struct ofp_meter_config *)d; if (data_len < ntohs(config->length) || ntohs(config->length) < sizeof(struct ofp_meter_config)) { @@ -373,11 +356,13 @@ ofl_utils_count_ofp_meter_config(void *data, size_t data_len, size_t *count){ void ofl_structs_free_packet_queue(struct ofl_packet_queue *queue) { OFL_UTILS_FREE_ARR(queue->properties, queue->properties_num); + free(queue); } void ofl_structs_free_instruction(struct ofl_instruction_header *inst, struct ofl_exp *exp) { + switch (inst->type) { case OFPIT_GOTO_TABLE: case OFPIT_WRITE_METADATA: @@ -406,16 +391,19 @@ ofl_structs_free_instruction(struct ofl_instruction_header *inst, struct ofl_exp } void ofl_structs_free_meter_bands(struct ofl_meter_band_header *meter_band){ + free(meter_band); } void ofl_structs_free_meter_band_stats(struct ofl_meter_band_stats* s){ + free(s); } void ofl_structs_free_meter_stats(struct ofl_meter_stats *stats){ + OFL_UTILS_FREE_ARR_FUN(stats->band_stats, stats->meter_bands_num, ofl_structs_free_meter_band_stats); free(stats); @@ -423,6 +411,7 @@ ofl_structs_free_meter_stats(struct ofl_meter_stats *stats){ void ofl_structs_free_meter_config(struct ofl_meter_config *conf){ + OFL_UTILS_FREE_ARR_FUN(conf->bands, conf->meter_bands_num, ofl_structs_free_meter_bands); free(conf); @@ -430,11 +419,13 @@ ofl_structs_free_meter_config(struct ofl_meter_config *conf){ void ofl_structs_free_table_stats(struct ofl_table_stats *stats) { + free(stats); } void ofl_structs_free_bucket(struct ofl_bucket *bucket, struct ofl_exp *exp) { + OFL_UTILS_FREE_ARR_FUN2(bucket->actions, bucket->actions_num, ofl_actions_free, exp); free(bucket); @@ -443,6 +434,7 @@ ofl_structs_free_bucket(struct ofl_bucket *bucket, struct ofl_exp *exp) { void ofl_structs_free_flow_stats(struct ofl_flow_stats *stats, struct ofl_exp *exp) { + OFL_UTILS_FREE_ARR_FUN2(stats->instructions, stats->instructions_num, ofl_structs_free_instruction, exp); ofl_structs_free_match(stats->match, exp); @@ -451,18 +443,21 @@ ofl_structs_free_flow_stats(struct ofl_flow_stats *stats, struct ofl_exp *exp) { void ofl_structs_free_port(struct ofl_port *port) { + free(port->name); free(port); } void ofl_structs_free_group_stats(struct ofl_group_stats *stats) { + OFL_UTILS_FREE_ARR(stats->counters, stats->counters_num); free(stats); } void ofl_structs_free_group_desc_stats(struct ofl_group_desc_stats *stats, struct ofl_exp *exp) { + OFL_UTILS_FREE_ARR_FUN2(stats->buckets, stats->buckets_num, ofl_structs_free_bucket, exp); free(stats); @@ -470,6 +465,11 @@ ofl_structs_free_group_desc_stats(struct ofl_group_desc_stats *stats, struct ofl void ofl_structs_free_table_features(struct ofl_table_features* features, struct ofl_exp *exp){ + + /* We sometime sets it to NULL (see set feature request). Jean II */ + if (features == NULL) + return; + OFL_UTILS_FREE_ARR_FUN2(features->properties, features->properties_num, ofl_structs_free_table_properties, exp); free(features->name); @@ -478,6 +478,7 @@ ofl_structs_free_table_features(struct ofl_table_features* features, struct ofl_ void ofl_structs_free_table_properties(struct ofl_table_feature_prop_header *prop, struct ofl_exp *exp UNUSED){ + switch(prop->type){ case (OFPTFPT_INSTRUCTIONS): case (OFPTFPT_INSTRUCTIONS_MISS):{ @@ -515,6 +516,7 @@ ofl_structs_free_table_properties(struct ofl_table_feature_prop_header *prop, st void ofl_structs_free_match(struct ofl_match_header *match, struct ofl_exp *exp) { + switch (match->type) { case (OFPMT_OXM): { if (match->length > sizeof(struct ofp_match)){ diff --git a/oflib/ofl-structs.h b/oflib/ofl-structs.h index 5c4dde64..94209ed5 100644 --- a/oflib/ofl-structs.h +++ b/oflib/ofl-structs.h @@ -154,6 +154,7 @@ struct ofl_flow_stats { uint16_t idle_timeout; /* Number of seconds idle before expiration. */ uint16_t hard_timeout; /* Number of seconds before expiration. */ + uint16_t flags; /* One of OFPFF_*/ uint64_t cookie; /* Opaque controller-issued identifier. */ uint64_t packet_count; /* Number of packets in flow. */ uint64_t byte_count; /* Number of bytes in flow. */ @@ -432,6 +433,12 @@ ofl_structs_match_put64(struct ofl_match *match, uint32_t header, uint64_t value void ofl_structs_match_put64m(struct ofl_match *match, uint32_t header, uint64_t value, uint64_t mask); +void +ofl_structs_match_put_pbb_isid(struct ofl_match *match, uint32_t header, uint8_t value[PBB_ISID_LEN]); + +void +ofl_structs_match_put_pbb_isidm(struct ofl_match *match, uint32_t header, uint8_t value[PBB_ISID_LEN], uint8_t mask[PBB_ISID_LEN]); + void ofl_structs_match_put_eth(struct ofl_match *match, uint32_t header, uint8_t value[ETH_ADDR_LEN]); diff --git a/oflib/oxm-match.c b/oflib/oxm-match.c index e21edaaa..31d26cfe 100644 --- a/oflib/oxm-match.c +++ b/oflib/oxm-match.c @@ -67,16 +67,6 @@ static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5); -/* Possible masks for TLV OXM_ETH_DST_W. */ -static const uint8_t eth_all_0s[ETH_ADDR_LEN] - = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; -static const uint8_t eth_all_1s[ETH_ADDR_LEN] - = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; -static const uint8_t eth_mcast_1[ETH_ADDR_LEN] - = {0x01, 0x00, 0x00, 0x00, 0x00, 0x00}; -static const uint8_t eth_mcast_0[ETH_ADDR_LEN] - = {0xfe, 0xff, 0xff, 0xff, 0xff, 0xff}; - struct oxm_field all_fields[NUM_OXM_FIELDS] = { #define DEFINE_FIELD(HEADER, DL_TYPES, NW_PROTO, MASKABLE) \ { HMAP_NODE_NULL_INITIALIZER, OFI_OXM_##HEADER, OXM_##HEADER, \ @@ -110,12 +100,71 @@ oxm_init(void) } } +bool +check_bad_wildcard(uint8_t value, uint8_t mask){ + uint8_t masked = value & mask; + if (value == masked){ + return false; + } + else { + return true; + } +} + +bool +check_bad_wildcard16(uint16_t value, uint16_t mask){ + uint16_t masked = value & mask; + if (value == masked){ + return false; + } + else { + return true; + } +} + +bool +check_bad_wildcard32(uint32_t value, uint32_t mask){ + uint32_t masked = value & mask; + if (value == masked){ + return false; + } + else { + return true; + } +} + +bool +check_bad_wildcard48(uint8_t *value, uint8_t *mask){ + return (check_bad_wildcard16(*((uint16_t *) value), *((uint16_t *) mask)) || + check_bad_wildcard32(*((uint32_t *) (value + 2)), + *((uint32_t *) (mask + 2)))); +} + +bool +check_bad_wildcard64(uint64_t value, uint64_t mask){ + uint64_t masked = value & mask; + if (value == masked){ + return false; + } + else { + return true; + } +} + +bool +check_bad_wildcard128(uint8_t *value, uint8_t *mask){ + return (check_bad_wildcard64(*((uint64_t *) value), *((uint64_t *) mask)) || + check_bad_wildcard64(*((uint64_t *) (value + 8)), + *((uint64_t *) (mask + 8)))); +} + + struct oxm_field * oxm_field_lookup(uint32_t header) { struct oxm_field *f; - oxm_init(); + HMAP_FOR_EACH_WITH_HASH(f, struct oxm_field, hmap_node, hash_int(header, 0), &all_oxm_fields) { if (f->header == header) { @@ -159,13 +208,13 @@ oxm_prereqs_ok(const struct oxm_field *field, const struct ofl_match *rule) { struct ofl_match_tlv *omt = NULL; - + bool found = false; /*Check ICMP type*/ if (field->header == OXM_OF_IPV6_ND_SLL || field->header == OXM_OF_IPV6_ND_TARGET ){ - bool found = false; + HMAP_FOR_EACH_WITH_HASH (omt, struct ofl_match_tlv, hmap_node, hash_int(OXM_OF_ICMPV6_TYPE, 0), &rule->match_fields) { - if (*omt->value != ICMPV6_NEIGHSOL){ + if (*(omt)->value != ICMPV6_NEIGHSOL){ return false; } found = true; @@ -174,8 +223,7 @@ oxm_prereqs_ok(const struct oxm_field *field, const struct ofl_match *rule) return false; } /*Check ICMP type*/ - if (field->header == OXM_OF_IPV6_ND_TLL || field->header == OXM_OF_IPV6_ND_TARGET){ - bool found = false; + if ((field->header == OXM_OF_IPV6_ND_TLL || field->header == OXM_OF_IPV6_ND_TARGET) && !found){ HMAP_FOR_EACH_WITH_HASH (omt, struct ofl_match_tlv, hmap_node, hash_int(OXM_OF_ICMPV6_TYPE, 0), &rule->match_fields) { if (*omt->value != ICMPV6_NEIGHADV){ @@ -189,7 +237,7 @@ oxm_prereqs_ok(const struct oxm_field *field, const struct ofl_match *rule) /*Check for IP_PROTO */ if (field->nw_proto){ - bool found = false; + found = false; HMAP_FOR_EACH_WITH_HASH (omt, struct ofl_match_tlv, hmap_node, hash_int(OXM_OF_IP_PROTO, 0), &rule->match_fields) { uint8_t ip_proto; @@ -247,7 +295,6 @@ static uint8_t* get_oxm_value(struct ofl_match *m, uint32_t header){ static int parse_oxm_entry(struct ofl_match *match, const struct oxm_field *f, const void *value, const void *mask){ - switch (f->index) { case OFI_OXM_OF_IN_PORT: { uint32_t* in_port = (uint32_t*) value; @@ -266,6 +313,9 @@ parse_oxm_entry(struct ofl_match *match, const struct oxm_field *f, return 0; } case OFI_OXM_OF_METADATA_W:{ + if (check_bad_wildcard64(ntoh64(*((uint64_t*) value)), ntoh64(*((uint64_t*) mask)))){ + return ofp_mkerr(OFPET_BAD_MATCH, OFPBMC_BAD_WILDCARDS); + } ofl_structs_match_put64m(match, f->header, ntoh64(*((uint64_t*) value)), ntoh64(*((uint64_t*) mask))); return 0; } @@ -277,6 +327,9 @@ parse_oxm_entry(struct ofl_match *match, const struct oxm_field *f, } case OFI_OXM_OF_ETH_DST_W: case OFI_OXM_OF_ETH_SRC_W:{ + if (check_bad_wildcard48((uint8_t* )value, (uint8_t* )mask)){ + return ofp_mkerr(OFPET_BAD_MATCH, OFPBMC_BAD_WILDCARDS); + } ofl_structs_match_put_eth_m(match, f->header,(uint8_t* )value, (uint8_t* )mask ); return 0; } @@ -300,6 +353,10 @@ parse_oxm_entry(struct ofl_match *match, const struct oxm_field *f, uint16_t* vlan_id = (uint16_t*) value; uint16_t* vlan_mask = (uint16_t*) mask; + if (check_bad_wildcard16(ntohs(*vlan_id), ntohs(*vlan_mask))){ + return ofp_mkerr(OFPET_BAD_MATCH, OFPBMC_BAD_WILDCARDS); + } + if (ntohs(*vlan_id) > OFPVID_PRESENT+VLAN_VID_MAX) return ofp_mkerr(OFPET_BAD_MATCH, OFPBMC_BAD_VALUE); else @@ -342,25 +399,33 @@ parse_oxm_entry(struct ofl_match *match, const struct oxm_field *f, case OFI_OXM_OF_IPV4_SRC: case OFI_OXM_OF_IPV4_DST: case OFI_OXM_OF_ARP_TPA: - case OFI_OXM_OF_ARP_SPA: + case OFI_OXM_OF_ARP_SPA:{ ofl_structs_match_put32(match, f->header, *((uint32_t*) value)); return 0; + } case OFI_OXM_OF_IPV4_DST_W: case OFI_OXM_OF_IPV4_SRC_W: case OFI_OXM_OF_ARP_SPA_W: - case OFI_OXM_OF_ARP_TPA_W: - ofl_structs_match_put32m(match, f->header, *((uint32_t*) value), *((uint32_t*) mask)); - return 0; + case OFI_OXM_OF_ARP_TPA_W:{ + if (check_bad_wildcard32(*((uint32_t*) value), *((uint32_t*) mask))){ + return ofp_mkerr(OFPET_BAD_MATCH, OFPBMC_BAD_WILDCARDS); + } + ofl_structs_match_put32m(match, f->header, *((uint32_t*) value), *((uint32_t*) mask)); + return 0; + } case OFI_OXM_OF_ARP_SHA: case OFI_OXM_OF_ARP_THA: ofl_structs_match_put_eth(match, f->header,(uint8_t* )value); return 0; case OFI_OXM_OF_ARP_SHA_W: - case OFI_OXM_OF_ARP_THA_W: + case OFI_OXM_OF_ARP_THA_W:{ + if (check_bad_wildcard48((uint8_t* )value, (uint8_t* )mask)){ + return ofp_mkerr(OFPET_BAD_MATCH, OFPBMC_BAD_WILDCARDS); + } ofl_structs_match_put_eth_m(match, f->header,(uint8_t* )value, (uint8_t* )mask ); return 0; - + } /* IPv6 addresses. */ case OFI_OXM_OF_IPV6_SRC: case OFI_OXM_OF_IPV6_DST:{ @@ -369,6 +434,9 @@ parse_oxm_entry(struct ofl_match *match, const struct oxm_field *f, } case OFI_OXM_OF_IPV6_SRC_W: case OFI_OXM_OF_IPV6_DST_W:{ + if (check_bad_wildcard128((uint8_t* ) value,(uint8_t* ) mask)){ + return ofp_mkerr(OFPET_BAD_MATCH, OFPBMC_BAD_WILDCARDS); + } ofl_structs_match_put_ipv6m(match, f->header,(uint8_t* ) value,(uint8_t* ) mask); return 0; } @@ -377,6 +445,9 @@ parse_oxm_entry(struct ofl_match *match, const struct oxm_field *f, return 0; } case OFI_OXM_OF_IPV6_FLABEL_W:{ + if (check_bad_wildcard32(*((uint32_t*) value), *((uint32_t*) mask))){ + return ofp_mkerr(OFPET_BAD_MATCH, OFPBMC_BAD_WILDCARDS); + } ofl_structs_match_put32m(match, f->header, ntohl(*((uint32_t*) value)), ntohl(*((uint32_t*) mask))); return 0; } @@ -388,24 +459,25 @@ parse_oxm_entry(struct ofl_match *match, const struct oxm_field *f, case OFI_OXM_OF_UDP_DST: /* SCTP header. */ case OFI_OXM_OF_SCTP_SRC: - case OFI_OXM_OF_SCTP_DST: - ofl_structs_match_put16(match, f->header, ntohs(*((uint16_t*) value))); - return 0; - + case OFI_OXM_OF_SCTP_DST:{ + ofl_structs_match_put16(match, f->header, ntohs(*((uint16_t*) value))); + return 0; + } /* ICMP header. */ case OFI_OXM_OF_ICMPV4_TYPE: case OFI_OXM_OF_ICMPV4_CODE: /* ICMPv6 header. */ case OFI_OXM_OF_ICMPV6_TYPE: case OFI_OXM_OF_ICMPV6_CODE:{ - uint8_t *v = (uint8_t*) value; - ofl_structs_match_put8(match, f->header, *v); + uint8_t *v = (uint8_t*) value; + ofl_structs_match_put8(match, f->header, *v); return 0; } /* IPv6 Neighbor Discovery. */ - case OFI_OXM_OF_IPV6_ND_TARGET: - ofl_structs_match_put_ipv6(match, f->header,(uint8_t* ) value); + case OFI_OXM_OF_IPV6_ND_TARGET:{ + ofl_structs_match_put_ipv6(match, f->header,(uint8_t* ) value); return 0; + } case OFI_OXM_OF_IPV6_ND_SLL: case OFI_OXM_OF_IPV6_ND_TLL: ofl_structs_match_put_eth(match, f->header,(uint8_t* )value); @@ -428,18 +500,32 @@ parse_oxm_entry(struct ofl_match *match, const struct oxm_field *f, ofl_structs_match_put8(match, f->header, *v); return 0; } - case OFI_OXM_OF_PBB_ISID: - ofl_structs_match_put32(match, f->header, ntohl(*((uint32_t*) value))); - return 0; - case OFI_OXM_OF_PBB_ISID_W: - ofl_structs_match_put32m(match, f->header, ntohl(*((uint32_t*) value)), ntohl(*((uint32_t*) mask))); - return 0; + case OFI_OXM_OF_PBB_ISID:{ + uint8_t* pbb_isid; + pbb_isid = (uint8_t*) value; + ofl_structs_match_put_pbb_isid(match, f->header, pbb_isid); + return 0; + } + case OFI_OXM_OF_PBB_ISID_W:{ + uint8_t* pbb_isid; + uint8_t* pbb_isid_mask; + pbb_isid = (uint8_t*) value; + pbb_isid_mask = (uint8_t*) mask; + if (check_bad_wildcard32(*((uint32_t*) value), *((uint32_t*) mask))){ + return ofp_mkerr(OFPET_BAD_MATCH, OFPBMC_BAD_WILDCARDS); + } + ofl_structs_match_put_pbb_isidm(match, f->header, pbb_isid, (uint8_t*) &pbb_isid_mask); + return 0; + } case OFI_OXM_OF_TUNNEL_ID:{ - ofl_structs_match_put64(match, f->header, *((uint64_t*) value)); + ofl_structs_match_put64(match, f->header, ntoh64(*((uint64_t*) value))); return 0; } case OFI_OXM_OF_TUNNEL_ID_W:{ - ofl_structs_match_put64m(match, f->header,*((uint64_t*) value),*((uint64_t*) mask)); + if (check_bad_wildcard64(*((uint64_t*) value), *((uint64_t*) mask))){ + return ofp_mkerr(OFPET_BAD_MATCH, OFPBMC_BAD_WILDCARDS); + } + ofl_structs_match_put64m(match, f->header,ntoh64(*((uint64_t*) value)),ntoh64(*((uint64_t*) mask))); return 0; } case OFI_OXM_OF_IPV6_EXTHDR: @@ -472,7 +558,7 @@ oxm_pull_match(struct ofpbuf *buf, struct ofl_match * match_dst, int match_len) if (!p) { VLOG_DBG_RL(LOG_MODULE,&rl, "oxm_match length %u, rounded up to a " "multiple of 8, is longer than space in message (max " - "length %d)", match_len, buf->size); + "length %zu)", match_len, buf->size); return ofp_mkerr(OFPET_BAD_MATCH, OFPBRC_BAD_LEN); } @@ -486,7 +572,6 @@ oxm_pull_match(struct ofpbuf *buf, struct ofl_match * match_dst, int match_len) const struct oxm_field *f; int error; f = oxm_field_lookup(header); - if (!f) { error = ofp_mkerr(OFPET_BAD_MATCH, OFPBMC_BAD_FIELD); } @@ -628,6 +713,24 @@ oxm_put_64w(struct ofpbuf *buf, uint32_t header, uint64_t value, uint64_t mask) ofpbuf_put(buf, &mask, sizeof mask); } +static void +oxm_put_pbb(struct ofpbuf *buf, uint32_t header, + const uint8_t value[PBB_ISID_LEN]) +{ + oxm_put_header(buf, header); + ofpbuf_put(buf, value, PBB_ISID_LEN); + +} + +static void +oxm_put_pbbm(struct ofpbuf *buf, uint32_t header, + const uint8_t value[PBB_ISID_LEN], const uint8_t mask[PBB_ISID_LEN]) +{ + oxm_put_header(buf, header); + ofpbuf_put(buf, value, PBB_ISID_LEN); + ofpbuf_put(buf, mask, PBB_ISID_LEN); +} + static void oxm_put_eth(struct ofpbuf *buf, uint32_t header, const uint8_t value[ETH_ADDR_LEN]) @@ -686,7 +789,8 @@ oxm_put_eth_dst(struct ofpbuf *b, static bool is_requisite(uint32_t header){ if(header == OXM_OF_IN_PORT || header == OXM_OF_ETH_TYPE - || header == OXM_OF_VLAN_VID || header == OXM_OF_IP_PROTO) { + || header == OXM_OF_VLAN_VID || header == OXM_OF_IP_PROTO || + header == OXM_OF_ICMPV6_TYPE) { return true; } return false; @@ -735,6 +839,13 @@ int oxm_put_match(struct ofpbuf *buf, struct ofl_match *omt){ oxm_put_8(buf,oft->header, value); } + HMAP_FOR_EACH_WITH_HASH(oft, struct ofl_match_tlv, hmap_node, hash_int(OXM_OF_ICMPV6_TYPE, 0), + &omt->match_fields) { + uint8_t value; + memcpy(&value, oft->value,sizeof(uint8_t)); + oxm_put_8(buf,oft->header, value); + } + /* Loop through the remaining fields */ HMAP_FOR_EACH(oft, struct ofl_match_tlv, hmap_node, &omt->match_fields){ @@ -773,6 +884,20 @@ int oxm_put_match(struct ofpbuf *buf, struct ofl_match *omt){ } break; } + case (PBB_ISID_LEN):{ + { + uint8_t value[PBB_ISID_LEN]; + memcpy(&value, oft->value, PBB_ISID_LEN); + if(!has_mask) + oxm_put_pbb(buf,oft->header, value); + else { + uint8_t mask[PBB_ISID_LEN]; + memcpy(&mask, oft->value + length ,PBB_ISID_LEN); + oxm_put_pbbm(buf, oft->header,value, mask); + } + break; + } + } case (sizeof(uint32_t)):{ uint32_t value; memcpy(&value, oft->value,sizeof(uint32_t)); diff --git a/oflib/oxm-match.h b/oflib/oxm-match.h index f870f175..605cf4fa 100644 --- a/oflib/oxm-match.h +++ b/oflib/oxm-match.h @@ -43,8 +43,8 @@ * limitations under the License. */ -#ifndef OX_MATCH_H -#define OX_MATCH_H 1 +#ifndef OXM_MATCH_H +#define OXM_MATCH_H 1 #include #include @@ -52,20 +52,9 @@ #include "ofpbuf.h" #include "hmap.h" #include "packets.h" +#include "openflow/openflow.h" #include "../oflib/ofl-structs.h" -#define OXM_HEADER__(VENDOR, FIELD, HASMASK, LENGTH) \ - (((VENDOR) << 16) | ((FIELD) << 9) | ((HASMASK) << 8) | (LENGTH)) -#define OXM_HEADER(VENDOR, FIELD, LENGTH) \ - OXM_HEADER__(VENDOR, FIELD, 0, LENGTH) -#define OXM_HEADER_W(VENDOR, FIELD, LENGTH) \ - OXM_HEADER__(VENDOR, FIELD, 1, (LENGTH) * 2) - -#define OXM_HEADER_VL(VENDOR,FIELD) \ - OXM_HEADER__(VENDOR,FIELD,0,0) - -#define OXM_HEADER_VL_W(VENDOR,FIELD) \ - OXM_HEADER__(VENDOR,FIELD,1,0) #define OXM_VENDOR(HEADER) ((HEADER) >> 16) #define OXM_FIELD(HEADER) (((HEADER) >> 9) & 0x7f) @@ -75,211 +64,6 @@ #define VENDOR_FROM_TYPE(TYPE) ((TYPE) >> 7) #define FIELD_FROM_TYPE(TYPE) ((TYPE) & 0x7f) -#define OXM_MAKE_WILD_HEADER(HEADER) \ - OXM_HEADER_W(OXM_VENDOR(HEADER), OXM_FIELD(HEADER), OXM_LENGTH(HEADER)) - -/* ## ------------------------------- ## */ -/* ## OpenFlow 1.2-compatible fields. ## */ -/* ## ------------------------------- ## */ - -/* Physical or virtual port on which the packet was received. - * - * Prereqs: None. - * - * Format: 16-bit integer. */ -#define OXM_OF_IN_PORT OXM_HEADER (0x8000, 0, 4) - - -/* Physical port on which the packet was received. - * - * Prereqs: None. - * - * Format: 32-bit integer. */ -#define OXM_OF_IN_PHY_PORT OXM_HEADER (0x8000, 1, 4) - -/* Metadata passed btw tables. */ -#define OXM_OF_METADATA OXM_HEADER (0x8000, 2, 8) -#define OXM_OF_METADATA_W OXM_HEADER_W (0x8000, 2, 8) - -/* Ethernet destination address.*/ -#define OXM_OF_ETH_DST OXM_HEADER (0x8000,3,6) -#define OXM_OF_ETH_DST_W OXM_HEADER_W(0x8000,3,6) - -/* Ethernet source address.*/ -#define OXM_OF_ETH_SRC OXM_HEADER (0x8000, 4,6) -#define OXM_OF_ETH_SRC_W OXM_HEADER_W(0x8000,4,6) - -/* Ethernet frame type. */ -#define OXM_OF_ETH_TYPE OXM_HEADER (0x8000, 5, 2) - -/* VLAN id. */ -#define OXM_OF_VLAN_VID OXM_HEADER (0x8000, 6, 2) -#define OXM_OF_VLAN_VID_W OXM_HEADER_W (0x8000, 6, 2) - - /* VLAN priority. */ -#define OXM_OF_VLAN_PCP OXM_HEADER (0x8000, 7, 1) - - -/* IP ToS (DSCP field, 6 bits). */ -#define OXM_OF_IP_DSCP OXM_HEADER (0x8000, 8, 1) - -/* IP ECN */ -#define OXM_OF_IP_ECN OXM_HEADER (0x8000, 9, 1) - -/* IP protocol. */ -#define OXM_OF_IP_PROTO OXM_HEADER (0x8000, 10, 1) - - /* IP source address. */ -#define OXM_OF_IPV4_SRC OXM_HEADER (0x8000,11, 4) -#define OXM_OF_IPV4_SRC_W OXM_HEADER_W (0x8000,11, 4) - -/* IP destination address. */ -#define OXM_OF_IPV4_DST OXM_HEADER (0x8000,12 , 4) -#define OXM_OF_IPV4_DST_W OXM_HEADER_W (0x8000,12 , 4) - -/* TCP source port. */ -#define OXM_OF_TCP_SRC OXM_HEADER (0x8000, 13, 2) - - /* TCP destination port. */ -#define OXM_OF_TCP_DST OXM_HEADER (0x8000, 14, 2) - -/* UDP source port. */ -#define OXM_OF_UDP_SRC OXM_HEADER (0x8000, 15, 2) - - /* UDP destination port. */ -#define OXM_OF_UDP_DST OXM_HEADER (0x8000, 16, 2) - -/* SCTP source port. */ -#define OXM_OF_SCTP_SRC OXM_HEADER (0x8000, 17, 2) - - /* SCTP destination port. */ -#define OXM_OF_SCTP_DST OXM_HEADER (0x8000, 18, 2) - -/* ICMPv4 type. */ -#define OXM_OF_ICMPV4_TYPE OXM_HEADER (0x8000, 19, 1) - -/* ICMPv4 code. */ -#define OXM_OF_ICMPV4_CODE OXM_HEADER (0x8000, 20, 1) - - /* ARP operation code. */ -#define OXM_OF_ARP_OP OXM_HEADER (0x8000,21, 2) - - /* IPv4 source address of ARP. */ -#define OXM_OF_ARP_SPA OXM_HEADER (0x8000,22, 4) -#define OXM_OF_ARP_SPA_W OXM_HEADER_W (0x8000,22, 4) - -/* IPv4 destination address of ARP. */ -#define OXM_OF_ARP_TPA OXM_HEADER (0x8000,23 , 4) -#define OXM_OF_ARP_TPA_W OXM_HEADER_W (0x8000,23 , 4) - -/* ARP Ethernet destination address.*/ -#define OXM_OF_ARP_SHA OXM_HEADER (0x8000,24,6) -#define OXM_OF_ARP_SHA_W OXM_HEADER_W(0x8000,24,6) - -/* ARP Ethernet source address.*/ -#define OXM_OF_ARP_THA OXM_HEADER (0x8000, 25,6) -#define OXM_OF_ARP_THA_W OXM_HEADER_W(0x8000,25,6) - -/* IPv6 source address */ -#define OXM_OF_IPV6_SRC OXM_HEADER (0x8000, 26, 16) -#define OXM_OF_IPV6_SRC_W OXM_HEADER_W(0x8000, 26, 16) - -/* IPv6 destination address*/ -#define OXM_OF_IPV6_DST OXM_HEADER (0x8000, 27, 16) -#define OXM_OF_IPV6_DST_W OXM_HEADER_W(0x8000, 27, 16) - -/* IPv6 flow label*/ -#define OXM_OF_IPV6_FLABEL OXM_HEADER (0x8000, 28, 4) -#define OXM_OF_IPV6_FLABEL_W OXM_HEADER_W (0x8000, 28, 4) - -/* ICMPv6 message type field */ -#define OXM_OF_ICMPV6_TYPE OXM_HEADER (0x8000, 29, 1) - -/* ICMPv6 type code */ -#define OXM_OF_ICMPV6_CODE OXM_HEADER (0x8000, 30, 1) - -/* IPv6 nd target*/ -#define OXM_OF_IPV6_ND_TARGET OXM_HEADER (0x8000, 31, 16) - -/* IPv6 nd target*/ -#define OXM_OF_IPV6_ND_SLL OXM_HEADER (0x8000, 32, 6) - -/* IPv6 dnd target*/ -#define OXM_OF_IPV6_ND_TLL OXM_HEADER (0x8000, 33, 6) - -/* MPLS label. */ -#define OXM_OF_MPLS_LABEL OXM_HEADER (0x8000, 34, 4) - -/* MPLS TC. */ -#define OXM_OF_MPLS_TC OXM_HEADER (0x8000, 35, 1) - -#define OXM_OF_MPLS_BOS OXM_HEADER (0x8000, 36, 1) - -#define OXM_OF_PBB_ISID OXM_HEADER (0x8000, 37, 4) -#define OXM_OF_PBB_ISID_W OXM_HEADER_W (0x8000, 37, 4) - -#define OXM_OF_TUNNEL_ID OXM_HEADER (0x8000, 38, 8) -#define OXM_OF_TUNNEL_ID_W OXM_HEADER_W (0x8000, 38, 8) - -#define OXM_OF_IPV6_EXTHDR OXM_HEADER (0x8000, 39, 2) -#define OXM_OF_IPV6_EXTHDR_W OXM_HEADER_W (0x8000, 39, 2) - -/* ## ------------------------------- ## */ -/* ## IPv6 compatible fields. ## */ -/* ## ------------------------------- ## */ - - -/* Traffic Class */ -#define OXM_OF_IPV6_TC OXM_HEADER (0x0002, 5, 1) -#define OXM_OF_IPV6_TC_W OXM_HEADER_W (0x0002, 5, 1) - -/* IPv6 Hop-by-Hop EH ID*/ -#define OXM_OF_IPV6_HBH_ID OXM_HEADER (0x0002, 8, 1) -#define OXM_OF_IPV6_HBH_ID_W OXM_HEADER_W (0x0002, 8, 1) - -#define OXM_OF_IPV6_HBH_OPT_CODE OXM_HEADER (0x0002, 9, 1) - -#define OXM_OF_IPV6_HBH_OPT_VALUE OXM_HEADER_VL (0x0002, 10) - -/* IPv6 Destination Option EH ID*/ -#define OXM_OF_IPV6_DOH_ID OXM_HEADER (0x0002, 16, 1) -#define OXM_OF_IPV6_DOH_ID_W OXM_HEADER_W (0x0002, 16, 1) - -#define OXM_OF_IPV6_DOH_OPT_CODE OXM_HEADER (0x0002, 17, 1) - -#define OXM_OF_IPV6_DOH_OPT_VALUE OXM_HEADER_VL (0x0002, 18) - - -/* IPv6 Routing EH ID*/ -#define OXM_OF_IPV6_RH_ID OXM_HEADER (0x0002, 24, 1) -#define OXM_OF_IPV6_RH_ID_W OXM_HEADER_W (0x0002, 24, 1) - -#define OXM_OF_IPV6_RH_ADDRESS OXM_HEADER (0x0002, 25, 16) - -/* IPv6 Fragmentation EH ID*/ -#define OXM_OF_IPV6_FH_ID OXM_HEADER (0x0002, 32, 1) -#define OXM_OF_IPV6_FH_ID_W OXM_HEADER_W (0x0002, 32, 1) - -/* IPv6 Authentication EH ID*/ -#define OXM_OF_IPV6_AH_ID OXM_HEADER (0x0002, 40, 1) -#define OXM_OF_IPV6_AH_ID_W OXM_HEADER_W (0x0002, 40, 1) - -/* IPv6 Encapsulating Security Payload */ -#define OXM_OF_IPV6_ESP_ID OXM_HEADER (0x0002, 48, 1) - -/* IPv6 Mobility EH */ -#define OXM_OF_IPV6_MH_ID OXM_HEADER (0x0002, 56, 1) - -/* ## ------------------------------- ## */ -/* ## TTL fields. ## */ -/* ## ------------------------------- ## */ - -/* MPLS TTL */ -#define OXM_OF_MPLS_TTL OXM_HEADER (0x0002, 80, 4) - -/* IPv4 TTL */ -#define OXM_OF_IPV4_TTL OXM_HEADER (0x0002, 81, 1) - enum oxm_field_index { #define DEFINE_FIELD(HEADER,DL_TYPES, NW_PROTO, MASKABLE) \ OFI_OXM_##HEADER, @@ -299,6 +83,24 @@ struct oxm_field { /* All the known fields. */ extern struct oxm_field all_fields[NUM_OXM_FIELDS]; +bool +check_bad_wildcard(uint8_t value, uint8_t mask); + +bool +check_bad_wildcard16(uint16_t value, uint16_t mask); + +bool +check_bad_wildcard32(uint32_t value, uint32_t mask); + +bool +check_bad_wildcard48(uint8_t *value, uint8_t *mask); + +bool +check_bad_wildcard64(uint64_t value, uint64_t mask); + +bool +check_bad_wildcard128(uint8_t *value, uint8_t *mask); + struct oxm_field * oxm_field_lookup(uint32_t header); @@ -323,4 +125,4 @@ oxm_field_bits(uint32_t header); -#endif /* nx-match.h */ +#endif /* oxm-match.h */ diff --git a/secchan/in-band.c b/secchan/in-band.c index c3f6c5b7..2a8c1353 100644 --- a/secchan/in-band.c +++ b/secchan/in-band.c @@ -258,7 +258,7 @@ in_band_status_cb(struct status_reply *sr, void *in_band_) } void -get_ofp_packet_payload(struct ofp_packet_in *opi, struct ofpbuf *payload) +get_ofp_packet_payload(struct ofp_packet_in *opi UNUSED, struct ofpbuf *payload UNUSED) { //payload->data = opi->data; //payload->size = ntohs(opi->header.length) - offsetof(struct ofp_packet_in, diff --git a/secchan/ofprotocol.8.in b/secchan/ofprotocol.8.in index 4aae44a3..13739911 100644 --- a/secchan/ofprotocol.8.in +++ b/secchan/ofprotocol.8.in @@ -36,13 +36,13 @@ using the following forms: .TP \fBssl:\fIhost\fR[\fB:\fIport\fR] -The specified SSL \fIport\fR (default: 6633) on the given remote +The specified SSL \fIport\fR (default: 6653) on the given remote \fIhost\fR. The \fB--private-key\fR, \fB--certificate\fR, and \fB--ca-cert\fR options are mandatory when this form is used. .TP \fBtcp:\fIhost\fR[\fB:\fIport\fR] -The specified TCP \fIport\fR (default: 6633) on the given remote +The specified TCP \fIport\fR (default: 6653) on the given remote \fIhost\fR. .TP @@ -320,13 +320,13 @@ multiple connection methods. .RS .TP \fBpssl:\fR[\fIport\fR] -Listens for SSL connections on \fIport\fR (default: 6633). The +Listens for SSL connections on \fIport\fR (default: 6653). The \fB--private-key\fR, \fB--certificate\fR, and \fB--ca-cert\fR options are mandatory when this form is used. .TP \fBptcp:\fR[\fIport\fR] -Listens for TCP connections on \fIport\fR (default: 6633). +Listens for TCP connections on \fIport\fR (default: 6653). .TP \fBpunix:\fIfile\fR @@ -450,7 +450,6 @@ require the controller to send the CA certificate, but .so lib/vlog.man .SS "Other Options" .so lib/common.man -.so lib/leak-checker.man .SH "SEE ALSO" diff --git a/secchan/ratelimit.c b/secchan/ratelimit.c index 6992387f..f147bff5 100644 --- a/secchan/ratelimit.c +++ b/secchan/ratelimit.c @@ -83,7 +83,7 @@ drop_packet(struct rate_limiter *rl) longest = &rl->queues[0]; n_longest = 1; - for (q = &rl->queues[0]; q < &rl->queues[OFPP_MAX]; q++) { + for (q = &rl->queues[0]; q < &rl->queues[65535]; q++) { if (longest->n < q->n) { longest = q; n_longest = 1; diff --git a/secchan/secchan.c b/secchan/secchan.c index 3f67fdb2..12c4b0d3 100644 --- a/secchan/secchan.c +++ b/secchan/secchan.c @@ -49,7 +49,6 @@ #include "failover.h" #include "fault.h" #include "in-band.h" -#include "leak-checker.h" #include "list.h" #include "ofp.h" #include "ofpbuf.h" @@ -344,10 +343,10 @@ get_ofp_packet_in(struct relay *r) return NULL; } -/* Need to adapt 1.2 packet-in changes */ +/* Need to adapt 1.3 packet-in changes */ bool get_ofp_packet_eth_header(struct relay *r, struct ofp_packet_in **opip, - struct eth_header **ethp) + struct eth_header **ethp UNUSED) { const int min_len = 0; //offsetof(struct ofp_packet_in, data) + ETH_HEADER_LEN; struct ofp_packet_in *opi = get_ofp_packet_in(r); @@ -600,7 +599,6 @@ parse_options(int argc, char *argv[], struct settings *s) {"version", no_argument, 0, 'V'}, DAEMON_LONG_OPTIONS, VLOG_LONG_OPTIONS, - LEAK_CHECKER_LONG_OPTIONS, #ifdef HAVE_OPENSSL VCONN_SSL_LONG_OPTIONS {"bootstrap-ca-cert", required_argument, 0, OPT_BOOTSTRAP_CA_CERT}, @@ -732,8 +730,6 @@ parse_options(int argc, char *argv[], struct settings *s) VLOG_OPTION_HANDLERS - LEAK_CHECKER_OPTION_HANDLERS - #ifdef HAVE_OPENSSL VCONN_SSL_OPTION_HANDLERS @@ -845,6 +841,5 @@ usage(void) printf("\nOther options:\n" " -h, --help display this help message\n" " -V, --version display version information\n"); - leak_checker_usage(); exit(EXIT_SUCCESS); } diff --git a/secchan/stp-secchan.c b/secchan/stp-secchan.c index 1567e286..3f717de2 100644 --- a/secchan/stp-secchan.c +++ b/secchan/stp-secchan.c @@ -64,7 +64,7 @@ static bool stp_local_packet_cb(struct relay *r, void *stp_) { struct ofpbuf *msg = r->halves[HALF_LOCAL].rxbuf; - struct ofp_header *oh; + struct ofp_header *oh UNUSED; struct stp_data *stp = stp_; struct ofp_packet_in *opi; struct eth_header *eth; @@ -74,13 +74,13 @@ stp_local_packet_cb(struct relay *r, void *stp_) struct flow flow; oh = msg->data; - /*if (oh->type == OFPT_FEATURES_REPLY - && msg->size >= offsetof(struct ofp_switch_features, ports)) { + /*if (oh->type == OFPT_FEATURES_REPLY*/ + /*&& msg->size >= offsetof(struct ofp_switch_features, ports)) {*/ /* TODO Zoltan: Temporarily removed when moving to Openflow 1.1 */ - /* struct ofp_switch_features *osf = msg->data; - osf->capabilities |= htonl(OFPC_STP); * - return false; - }*/ + /* struct ofp_switch_features *osf = msg->data; */ + /* osf->capabilities |= htonl(OFPC_STP); * */ + /* return false; */ + /*}*/ if (!get_ofp_packet_eth_header(r, &opi, ð) || !eth_addr_equals(eth->eth_dst, stp_eth_addr)) { diff --git a/udatapath/action_set.c b/udatapath/action_set.c index 43c1ec6d..601e2842 100644 --- a/udatapath/action_set.c +++ b/udatapath/action_set.c @@ -188,7 +188,7 @@ action_set_write_actions(struct action_set *set, for (i=0; iaction); list_remove(&entry->node); free(entry); + } + + /* Clear the action set in any case. Group processing depend on + * a clean action-set. Jean II */ + action_set_clear_actions(pkt->action_set); /* According to the spec. if there was a group action, the output * port action should be ignored */ @@ -218,7 +223,7 @@ action_set_execute(struct action_set *set, struct packet *pkt, uint64_t cookie) uint32_t group_id = pkt->out_group; pkt->out_group = OFPG_ANY; - action_set_clear_actions(pkt->action_set); + /* Transfer packet to the group. It will be destroyed. Jean II */ group_table_execute(pkt->dp->groups, pkt, group_id); return; @@ -230,11 +235,13 @@ action_set_execute(struct action_set *set, struct packet *pkt, uint64_t cookie) pkt->out_port_max_len = 0; pkt->out_queue = 0; - action_set_clear_actions(pkt->action_set); dp_actions_output_port(pkt, port_id, queue_id, max_len, cookie); + packet_destroy(pkt); return; } - } + + /* No output or group action. Just drop the packet. Jean II */ + packet_destroy(pkt); } char * diff --git a/udatapath/crc32.c b/udatapath/crc32.c index f6c2c0b3..f1503569 100644 --- a/udatapath/crc32.c +++ b/udatapath/crc32.c @@ -1,68 +1,131 @@ -/* Copyright (c) 2008 The Board of Trustees of The Leland Stanford - * Junior University - * - * We are making the OpenFlow specification and associated documentation - * (Software) available for public use and benefit with the expectation - * that others will use, modify and enhance the Software and contribute - * those enhancements back to the community. However, since we would - * like to make the Software available for broadest use, with as few - * restrictions as possible permission is hereby granted, free of - * charge, to any person obtaining a copy of this Software to deal in - * the Software under the copyrights without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * - * The name and trademarks of copyright holder(s) may NOT be used in - * advertising or publicity pertaining to the Software or any - * derivatives without specific, written prior permission. - */ +/** + * \file crc32c.c + * Functions and types for CRC checks. + * + * Generated on Thu Dec 11 18:04:34 2014, + * by pycrc v0.8.2, http://www.tty1.net/pycrc/ + * using the configuration: + * Width = 32 + * Poly = 0x1edc6f41 + * XorIn = 0xffffffff + * ReflectIn = True + * XorOut = 0xffffffff + * ReflectOut = True + * Algorithm = table-driven + *****************************************************************************/ +#include "crc32.h" /* include the header file generated with pycrc */ +#include +#include -#include -#include "crc32.h" +/** + * Static table used for the table_driven implementation. + *****************************************************************************/ +static const crc_t crc_table[256] = { + 0x00000000, 0xf26b8303, 0xe13b70f7, 0x1350f3f4, + 0xc79a971f, 0x35f1141c, 0x26a1e7e8, 0xd4ca64eb, + 0x8ad958cf, 0x78b2dbcc, 0x6be22838, 0x9989ab3b, + 0x4d43cfd0, 0xbf284cd3, 0xac78bf27, 0x5e133c24, + 0x105ec76f, 0xe235446c, 0xf165b798, 0x030e349b, + 0xd7c45070, 0x25afd373, 0x36ff2087, 0xc494a384, + 0x9a879fa0, 0x68ec1ca3, 0x7bbcef57, 0x89d76c54, + 0x5d1d08bf, 0xaf768bbc, 0xbc267848, 0x4e4dfb4b, + 0x20bd8ede, 0xd2d60ddd, 0xc186fe29, 0x33ed7d2a, + 0xe72719c1, 0x154c9ac2, 0x061c6936, 0xf477ea35, + 0xaa64d611, 0x580f5512, 0x4b5fa6e6, 0xb93425e5, + 0x6dfe410e, 0x9f95c20d, 0x8cc531f9, 0x7eaeb2fa, + 0x30e349b1, 0xc288cab2, 0xd1d83946, 0x23b3ba45, + 0xf779deae, 0x05125dad, 0x1642ae59, 0xe4292d5a, + 0xba3a117e, 0x4851927d, 0x5b016189, 0xa96ae28a, + 0x7da08661, 0x8fcb0562, 0x9c9bf696, 0x6ef07595, + 0x417b1dbc, 0xb3109ebf, 0xa0406d4b, 0x522bee48, + 0x86e18aa3, 0x748a09a0, 0x67dafa54, 0x95b17957, + 0xcba24573, 0x39c9c670, 0x2a993584, 0xd8f2b687, + 0x0c38d26c, 0xfe53516f, 0xed03a29b, 0x1f682198, + 0x5125dad3, 0xa34e59d0, 0xb01eaa24, 0x42752927, + 0x96bf4dcc, 0x64d4cecf, 0x77843d3b, 0x85efbe38, + 0xdbfc821c, 0x2997011f, 0x3ac7f2eb, 0xc8ac71e8, + 0x1c661503, 0xee0d9600, 0xfd5d65f4, 0x0f36e6f7, + 0x61c69362, 0x93ad1061, 0x80fde395, 0x72966096, + 0xa65c047d, 0x5437877e, 0x4767748a, 0xb50cf789, + 0xeb1fcbad, 0x197448ae, 0x0a24bb5a, 0xf84f3859, + 0x2c855cb2, 0xdeeedfb1, 0xcdbe2c45, 0x3fd5af46, + 0x7198540d, 0x83f3d70e, 0x90a324fa, 0x62c8a7f9, + 0xb602c312, 0x44694011, 0x5739b3e5, 0xa55230e6, + 0xfb410cc2, 0x092a8fc1, 0x1a7a7c35, 0xe811ff36, + 0x3cdb9bdd, 0xceb018de, 0xdde0eb2a, 0x2f8b6829, + 0x82f63b78, 0x709db87b, 0x63cd4b8f, 0x91a6c88c, + 0x456cac67, 0xb7072f64, 0xa457dc90, 0x563c5f93, + 0x082f63b7, 0xfa44e0b4, 0xe9141340, 0x1b7f9043, + 0xcfb5f4a8, 0x3dde77ab, 0x2e8e845f, 0xdce5075c, + 0x92a8fc17, 0x60c37f14, 0x73938ce0, 0x81f80fe3, + 0x55326b08, 0xa759e80b, 0xb4091bff, 0x466298fc, + 0x1871a4d8, 0xea1a27db, 0xf94ad42f, 0x0b21572c, + 0xdfeb33c7, 0x2d80b0c4, 0x3ed04330, 0xccbbc033, + 0xa24bb5a6, 0x502036a5, 0x4370c551, 0xb11b4652, + 0x65d122b9, 0x97baa1ba, 0x84ea524e, 0x7681d14d, + 0x2892ed69, 0xdaf96e6a, 0xc9a99d9e, 0x3bc21e9d, + 0xef087a76, 0x1d63f975, 0x0e330a81, 0xfc588982, + 0xb21572c9, 0x407ef1ca, 0x532e023e, 0xa145813d, + 0x758fe5d6, 0x87e466d5, 0x94b49521, 0x66df1622, + 0x38cc2a06, 0xcaa7a905, 0xd9f75af1, 0x2b9cd9f2, + 0xff56bd19, 0x0d3d3e1a, 0x1e6dcdee, 0xec064eed, + 0xc38d26c4, 0x31e6a5c7, 0x22b65633, 0xd0ddd530, + 0x0417b1db, 0xf67c32d8, 0xe52cc12c, 0x1747422f, + 0x49547e0b, 0xbb3ffd08, 0xa86f0efc, 0x5a048dff, + 0x8ecee914, 0x7ca56a17, 0x6ff599e3, 0x9d9e1ae0, + 0xd3d3e1ab, 0x21b862a8, 0x32e8915c, 0xc083125f, + 0x144976b4, 0xe622f5b7, 0xf5720643, 0x07198540, + 0x590ab964, 0xab613a67, 0xb831c993, 0x4a5a4a90, + 0x9e902e7b, 0x6cfbad78, 0x7fab5e8c, 0x8dc0dd8f, + 0xe330a81a, 0x115b2b19, 0x020bd8ed, 0xf0605bee, + 0x24aa3f05, 0xd6c1bc06, 0xc5914ff2, 0x37faccf1, + 0x69e9f0d5, 0x9b8273d6, 0x88d28022, 0x7ab90321, + 0xae7367ca, 0x5c18e4c9, 0x4f48173d, 0xbd23943e, + 0xf36e6f75, 0x0105ec76, 0x12551f82, 0xe03e9c81, + 0x34f4f86a, 0xc69f7b69, 0xd5cf889d, 0x27a40b9e, + 0x79b737ba, 0x8bdcb4b9, 0x988c474d, 0x6ae7c44e, + 0xbe2da0a5, 0x4c4623a6, 0x5f16d052, 0xad7d5351 +}; -void -crc32_init(struct crc32 *crc, unsigned int polynomial) +/** + * Reflect all bits of a \a data word of \a data_len bytes. + * + * \param data The data word to be reflected. + * \param data_len The width of \a data expressed in number of bits. + * \return The reflected data. + *****************************************************************************/ +crc_t crc_reflect(crc_t data, size_t data_len) { - int i; + unsigned int i; + crc_t ret; - for (i = 0; i < CRC32_TABLE_SIZE; ++i) { - unsigned int reg = i << 24; - int j; - for (j = 0; j < CRC32_TABLE_BITS; j++) { - int topBit = (reg & 0x80000000) != 0; - reg <<= 1; - if (topBit) - reg ^= polynomial; - } - crc->table[i] = reg; + ret = data & 0x01; + for (i = 1; i < data_len; i++) { + data >>= 1; + ret = (ret << 1) | (data & 0x01); } + return ret; } -unsigned int -crc32_calculate(const struct crc32 *crc, const void *data_, size_t n_bytes) + +/** + * Update the crc value with new data. + * + * \param crc The current crc value. + * \param data Pointer to a buffer of \a data_len bytes. + * \param data_len Number of bytes in the \a data buffer. + * \return The updated crc value. + *****************************************************************************/ +crc_t crc_update(crc_t crc, const unsigned char *data, size_t data_len) { - const uint8_t *data = data_; - unsigned int result = 0; - size_t i; + unsigned int tbl_idx; + + while (data_len--) { + tbl_idx = (crc ^ *data) & 0xff; + crc = (crc_table[tbl_idx] ^ (crc >> 8)) & 0xffffffff; - for (i = 0; i < n_bytes; i++) { - unsigned int top = result >> 24; - top ^= data[i]; - result = (result << 8) ^ crc->table[top]; + data++; } - return result; + return crc & 0xffffffff; } + diff --git a/udatapath/crc32.h b/udatapath/crc32.h index 355aefdf..4421ee98 100644 --- a/udatapath/crc32.h +++ b/udatapath/crc32.h @@ -1,50 +1,92 @@ -/* Copyright (c) 2008 The Board of Trustees of The Leland Stanford - * Junior University - * - * We are making the OpenFlow specification and associated documentation - * (Software) available for public use and benefit with the expectation - * that others will use, modify and enhance the Software and contribute - * those enhancements back to the community. However, since we would - * like to make the Software available for broadest use, with as few - * restrictions as possible permission is hereby granted, free of - * charge, to any person obtaining a copy of this Software to deal in - * the Software under the copyrights without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * - * The name and trademarks of copyright holder(s) may NOT be used in - * advertising or publicity pertaining to the Software or any - * derivatives without specific, written prior permission. - */ - -#ifndef CRC32_H -#define CRC32_H 1 +/** + * \file crc32c.h + * Functions and types for CRC checks. + * + * Generated on Thu Dec 11 18:04:29 2014, + * by pycrc v0.8.2, http://www.tty1.net/pycrc/ + * using the configuration: + * Width = 32 + * Poly = 0x1edc6f41 + * XorIn = 0xffffffff + * ReflectIn = True + * XorOut = 0xffffffff + * ReflectOut = True + * Algorithm = table-driven + *****************************************************************************/ +#ifndef __CRC32C_H__ +#define __CRC32C_H__ +#include #include -#include -#define CRC32_TABLE_BITS 8 -#define CRC32_TABLE_SIZE (1u << CRC32_TABLE_BITS) +#ifdef __cplusplus +extern "C" { +#endif -struct crc32 { - unsigned int table[CRC32_TABLE_SIZE]; -}; -void crc32_init(struct crc32 *, unsigned int polynomial); -unsigned int crc32_calculate(const struct crc32 *, const void *, size_t); +/** + * The definition of the used algorithm. + * + * This is not used anywhere in the generated code, but it may be used by the + * application code to call algoritm-specific code, is desired. + *****************************************************************************/ +#define CRC_ALGO_TABLE_DRIVEN 1 -#endif /* crc32.h */ + +/** + * The type of the CRC values. + * + * This type must be big enough to contain at least 32 bits. + *****************************************************************************/ +typedef uint_fast32_t crc_t; + + +/** + * Reflect all bits of a \a data word of \a data_len bytes. + * + * \param data The data word to be reflected. + * \param data_len The width of \a data expressed in number of bits. + * \return The reflected data. + *****************************************************************************/ +crc_t crc_reflect(crc_t data, size_t data_len); + + +/** + * Calculate the initial crc value. + * + * \return The initial crc value. + *****************************************************************************/ +static inline crc_t crc_init(void) +{ + return 0xffffffff; +} + + +/** + * Update the crc value with new data. + * + * \param crc The current crc value. + * \param data Pointer to a buffer of \a data_len bytes. + * \param data_len Number of bytes in the \a data buffer. + * \return The updated crc value. + *****************************************************************************/ +crc_t crc_update(crc_t crc, const unsigned char *data, size_t data_len); + + +/** + * Calculate the final crc value. + * + * \param crc The current crc value. + * \return The final crc value. + *****************************************************************************/ +static inline crc_t crc_finalize(crc_t crc) +{ + return crc ^ 0xffffffff; +} + + +#ifdef __cplusplus +} /* closing brace for extern "C" */ +#endif + +#endif /* __CRC32C_H__ */ \ No newline at end of file diff --git a/udatapath/datapath.c b/udatapath/datapath.c index 7e002199..df45af71 100644 --- a/udatapath/datapath.c +++ b/udatapath/datapath.c @@ -159,8 +159,10 @@ dp_new(void) { if(strlen(dp->dp_desc) == 0) { /* just use "$HOSTNAME pid=$$" */ char hostnametmp[DESC_STR_LEN]; - gethostname(hostnametmp,sizeof hostnametmp); - snprintf(dp->dp_desc, sizeof dp->dp_desc,"%s pid=%u",hostnametmp, getpid()); + char pid[10]; + gethostname(hostnametmp,sizeof hostnametmp); + sprintf(pid, "%u", getpid()); + snprintf(dp->dp_desc, strlen(hostnametmp) + 5 + strlen(pid),"%s pid=%s",hostnametmp, pid); } /* FIXME: Should not depend on udatapath_as_lib */ @@ -195,7 +197,7 @@ dp_run(struct datapath *dp) { pipeline_timeout(dp->pipeline); } - poll_timer_wait(1000); + poll_timer_wait(100); dp_ports_run(dp); /* Talk to remotes. */ @@ -249,10 +251,10 @@ remote_run(struct datapath *dp, struct remote *r) static void remote_rconn_run(struct datapath *dp, struct remote *r, uint8_t conn_id) { - struct rconn *rconn; + struct rconn *rconn = NULL; ofl_err error; size_t i; - + rconn = NULL; if (conn_id == MAIN_CONNECTION) rconn = r->rconn; else if (conn_id == PTIN_CONNECTION) @@ -337,6 +339,9 @@ remote_destroy(struct remote *r) rconn_destroy(r->rconn_aux); } rconn_destroy(r->rconn); + if(r->mp_req_msg != NULL) { + ofl_msg_free((struct ofl_msg_header *) r->mp_req_msg, NULL); + } free(r); } } @@ -351,6 +356,8 @@ remote_create(struct datapath *dp, struct rconn *rconn, struct rconn *rconn_aux) remote->rconn_aux = rconn_aux; remote->cb_dump = NULL; remote->n_txq = 0; + remote->mp_req_msg = NULL; + remote->mp_req_xid = 0; /* Currently not needed. Jean II. */ remote->role = OFPCR_ROLE_EQUAL; /* Set the remote configuration to receive any asynchronous message*/ for(i = 0; i < 2; i++){ @@ -482,20 +489,20 @@ send_openflow_buffer(struct datapath *dp, struct ofpbuf *buffer, continue; if((p->reason == OFPPR_DELETE) && !(r->config.port_status_mask[0] & 0x2)) continue; - if((p->reason == OFPPR_MODIFY) && !(r->config.packet_in_mask[0] & 0x4)) + if((p->reason == OFPPR_MODIFY) && !(r->config.port_status_mask[0] & 0x4)) continue; } case (OFPT_FLOW_REMOVED):{ struct ofp_flow_removed *p= (struct ofp_flow_removed *)buffer->data; - if((p->reason == OFPRR_IDLE_TIMEOUT) && !(r->config.port_status_mask[0] & 0x1)) + if((p->reason == OFPRR_IDLE_TIMEOUT) && !(r->config.flow_removed_mask[0] & 0x1)) continue; - if((p->reason == OFPRR_HARD_TIMEOUT) && !(r->config.port_status_mask[0] & 0x2)) + if((p->reason == OFPRR_HARD_TIMEOUT) && !(r->config.flow_removed_mask[0] & 0x2)) continue; - if((p->reason == OFPRR_DELETE) && !(r->config.packet_in_mask[0] & 0x4)) + if((p->reason == OFPRR_DELETE) && !(r->config.flow_removed_mask[0] & 0x4)) continue; - if((p->reason == OFPRR_GROUP_DELETE) && !(r->config.packet_in_mask[0] & 0x8)) + if((p->reason == OFPRR_GROUP_DELETE) && !(r->config.flow_removed_mask[0] & 0x8)) continue; - if((p->reason == OFPRR_METER_DELETE) && !(r->config.packet_in_mask[0] & 0x10)) + if((p->reason == OFPRR_METER_DELETE) && !(r->config.flow_removed_mask[0] & 0x10)) continue; } } @@ -512,7 +519,7 @@ send_openflow_buffer(struct datapath *dp, struct ofpbuf *buffer, continue; if((p->reason == OFPPR_DELETE) && !(r->config.port_status_mask[1] & 0x2)) continue; - if((p->reason == OFPPR_MODIFY) && !(r->config.packet_in_mask[1] & 0x4)) + if((p->reason == OFPPR_MODIFY) && !(r->config.port_status_mask[1] & 0x4)) continue; } } @@ -568,8 +575,6 @@ dp_send_message(struct datapath *dp, struct ofl_msg_header *msg, error = send_openflow_buffer(dp, ofpbuf, sender); if (error) { VLOG_WARN_RL(LOG_MODULE, &rl, "There was an error sending the message!"); - /* TODO Zoltan: is delete needed? */ - ofpbuf_delete(ofpbuf); return error; } return 0; @@ -586,8 +591,9 @@ dp_handle_set_desc(struct datapath *dp, struct ofl_exp_openflow_msg_set_dp_desc static ofl_err dp_check_generation_id(struct datapath *dp, uint64_t new_gen_id){ - if(dp->generation_id >= 0 && ((uint64_t)(dp->generation_id - new_gen_id) < 0) ) + if(dp->generation_id >= 0 && ((int64_t)(new_gen_id - dp->generation_id) < 0) ){ return ofl_error(OFPET_ROLE_REQUEST_FAILED, OFPRRFC_STALE); + } else dp->generation_id = new_gen_id; return 0; @@ -596,10 +602,12 @@ dp_check_generation_id(struct datapath *dp, uint64_t new_gen_id){ ofl_err dp_handle_role_request(struct datapath *dp, struct ofl_msg_role_request *msg, const struct sender *sender) { - uint32_t role = msg->role; + uint32_t role = msg->role; + uint64_t generation_id = msg->generation_id; switch (msg->role) { case OFPCR_ROLE_NOCHANGE:{ role = sender->remote->role; + generation_id = dp->generation_id; break; } case OFPCR_ROLE_EQUAL: { @@ -641,7 +649,7 @@ dp_handle_role_request(struct datapath *dp, struct ofl_msg_role_request *msg, struct ofl_msg_role_request reply = {{.type = OFPT_ROLE_REPLY}, .role = role, - .generation_id = msg->generation_id}; + .generation_id = generation_id}; dp_send_message(dp, (struct ofl_msg_header *)&reply, sender); } diff --git a/udatapath/datapath.h b/udatapath/datapath.h index c0ea3e51..f845bd36 100644 --- a/udatapath/datapath.h +++ b/udatapath/datapath.h @@ -146,6 +146,10 @@ struct remote { uint32_t role; /*OpenFlow controller role.*/ struct ofl_async_config config; /* Asynchronous messages configuration, set from controller*/ + + /* Multipart request message pending reassembly. */ + struct ofl_msg_multipart_request_header *mp_req_msg; /* Message. */ + uint32_t mp_req_xid; /* Multipart request OpenFlow transaction ID. */ }; /* Creates a new datapath */ diff --git a/udatapath/dp_actions.c b/udatapath/dp_actions.c index ea176513..f2d5737a 100644 --- a/udatapath/dp_actions.c +++ b/udatapath/dp_actions.c @@ -43,6 +43,7 @@ #include "packet.h" #include "packets.h" #include "pipeline.h" +#include "crc32.h" #include "util.h" #include "oflib/oxm-match.h" #include "hash.h" @@ -80,6 +81,7 @@ set_field(struct packet *pkt, struct ofl_action_set_field *act ) { /*Field existence is guaranteed by the field pre-requisite on matching */ + fprintf(stderr, "Header %d\n", OXM_FIELD(act->field->header)); switch(act->field->header){ case OXM_OF_ETH_DST:{ memcpy(pkt->handle_std->proto->eth->eth_dst, @@ -92,47 +94,72 @@ set_field(struct packet *pkt, struct ofl_action_set_field *act ) break; } case OXM_OF_ETH_TYPE:{ - uint16_t *v = (uint16_t*) act->field->value; - *v = htons(*v); - memcpy(&pkt->handle_std->proto->eth->eth_type, - v, OXM_LENGTH(act->field->header)); + uint16_t v = *((uint16_t*) act->field->value); + pkt->handle_std->proto->eth->eth_type = htons(v); break; } case OXM_OF_VLAN_VID:{ struct vlan_header *vlan = pkt->handle_std->proto->vlan; - uint16_t v = (*(uint16_t*)act->field->value); - vlan->vlan_tci = htons((ntohs(vlan->vlan_tci) & ~VLAN_VID_MASK) - | (v & VLAN_VID_MASK)); + /* VLAN existence is no guaranteed by match prerquisite*/ + if(vlan != NULL){ + uint16_t v = (*(uint16_t*)act->field->value); + vlan->vlan_tci = htons((ntohs(vlan->vlan_tci) & ~VLAN_VID_MASK) | (v & VLAN_VID_MASK)); + } break; } case OXM_OF_VLAN_PCP:{ struct vlan_header *vlan = pkt->handle_std->proto->vlan; - - vlan->vlan_tci = (vlan->vlan_tci & ~htons(VLAN_PCP_MASK)) - | htons(*act->field->value << VLAN_PCP_SHIFT); - break; + /* VLAN existence is no guaranteed by match prerquisite*/ + if(vlan != NULL){ + vlan->vlan_tci = (vlan->vlan_tci & ~htons(VLAN_PCP_MASK)) + | htons(*act->field->value << VLAN_PCP_SHIFT); + break; + } } case OXM_OF_IP_DSCP:{ - struct ip_header *ipv4 = pkt->handle_std->proto->ipv4; - uint8_t tos = (ipv4->ip_tos & ~IP_DSCP_MASK) | - (*act->field->value << 2); - - ipv4->ip_csum = recalc_csum16(ipv4->ip_csum, (uint16_t) - (ipv4->ip_tos), (uint16_t)tos); - ipv4->ip_tos = tos; + if (pkt->handle_std->proto->ipv4){ + struct ip_header *ipv4 = pkt->handle_std->proto->ipv4; + uint8_t tos = (ipv4->ip_tos & ~IP_DSCP_MASK) | + (*act->field->value << 2); + uint16_t old_val = htons((ipv4->ip_ihl_ver << 8) + ipv4->ip_tos); + uint16_t new_val = htons((ipv4->ip_ihl_ver << 8) + tos); + ipv4->ip_csum = recalc_csum16(ipv4->ip_csum, old_val, new_val); + ipv4->ip_tos = tos; + } + else if (pkt->handle_std->proto->ipv6){ + struct ipv6_header *ipv6 = pkt->handle_std->proto->ipv6; + uint32_t ipv6_ver_tc_fl = (ipv6->ipv6_ver_tc_fl & ~htonl(IPV6_DSCP_MASK)) | + htonl((((uint32_t) *act->field->value) << IPV6_DSCP_SHIFT)); + ipv6->ipv6_ver_tc_fl = ipv6_ver_tc_fl; + } break; } case OXM_OF_IP_ECN:{ - struct ip_header *ipv4 = pkt->handle_std->proto->ipv4; - uint8_t tos = (ipv4->ip_tos & ~IP_ECN_MASK) | + if (pkt->handle_std->proto->ipv4){ + struct ip_header *ipv4 = pkt->handle_std->proto->ipv4; + uint8_t tos = (ipv4->ip_tos & ~IP_ECN_MASK) | (*act->field->value & IP_ECN_MASK); - ipv4->ip_csum = recalc_csum16(ipv4->ip_csum, (uint16_t) - (ipv4->ip_tos), (uint16_t)tos); - ipv4->ip_tos = tos; - break; + uint16_t old_val = htons((ipv4->ip_ihl_ver << 8) + ipv4->ip_tos); + uint16_t new_val = htons((ipv4->ip_ihl_ver << 8) + tos); + ipv4->ip_csum = recalc_csum16(ipv4->ip_csum, old_val, new_val); + ipv4->ip_tos = tos; + } + else if (pkt->handle_std->proto->ipv6){ + struct ipv6_header *ipv6 = pkt->handle_std->proto->ipv6; + uint32_t ipv6_ver_tc_fl = (ipv6->ipv6_ver_tc_fl & ~htonl(IPV6_ECN_MASK)) | + htonl((((uint32_t) *act->field->value) << IPV6_ECN_SHIFT)); + ipv6->ipv6_ver_tc_fl = ipv6_ver_tc_fl; + } + break; } case OXM_OF_IP_PROTO:{ - pkt->handle_std->proto->ipv4->ip_proto = *act->field->value; + struct ip_header *ipv4 = pkt->handle_std->proto->ipv4; + uint16_t new_val, old_val; + uint8_t proto = *act->field->value; + old_val = htons((ipv4->ip_ttl << 8) + ipv4->ip_proto); + new_val = htons((ipv4->ip_ttl << 8) + proto); + ipv4->ip_csum = recalc_csum16(ipv4->ip_csum, old_val, new_val); + ipv4->ip_proto = proto; break; } case OXM_OF_IPV4_SRC:{ @@ -177,72 +204,94 @@ set_field(struct packet *pkt, struct ofl_action_set_field *act ) } case OXM_OF_TCP_SRC:{ struct tcp_header *tcp = pkt->handle_std->proto->tcp; - uint16_t *v = (uint16_t*) act->field->value; - *v = htons(*v); - tcp->tcp_csum = recalc_csum16(tcp->tcp_csum, tcp->tcp_src,*v); - memcpy(&tcp->tcp_src, v, OXM_LENGTH(act->field->header)); - + uint16_t v = htons(*(uint16_t*) act->field->value); + tcp->tcp_csum = recalc_csum16(tcp->tcp_csum, tcp->tcp_src, v); + tcp->tcp_src = v; break; } case OXM_OF_TCP_DST:{ struct tcp_header *tcp = pkt->handle_std->proto->tcp; - uint16_t *v = (uint16_t*) act->field->value; - *v = htons(*v); - tcp->tcp_csum = recalc_csum16(tcp->tcp_csum, tcp->tcp_dst,*v); - memcpy(&tcp->tcp_dst, v, OXM_LENGTH(act->field->header)); - + uint16_t v = htons(*(uint16_t*) act->field->value); + tcp->tcp_csum = recalc_csum16(tcp->tcp_csum, tcp->tcp_dst, v); + tcp->tcp_dst = v; break; } case OXM_OF_UDP_SRC:{ struct udp_header *udp = pkt->handle_std->proto->udp; - uint16_t *v = (uint16_t*) act->field->value; - *v = htons(*v); - udp->udp_csum = recalc_csum16(udp->udp_csum, udp->udp_dst, *v); - memcpy(&udp->udp_src, v, OXM_LENGTH(act->field->header)); + uint16_t v = htons(*(uint16_t*) act->field->value); + udp->udp_csum = recalc_csum16(udp->udp_csum, udp->udp_src, v); + udp->udp_src = v; break; } case OXM_OF_UDP_DST:{ struct udp_header *udp = pkt->handle_std->proto->udp; - uint16_t *v = (uint16_t*) act->field->value; - *v = htons(*v); - udp->udp_csum = recalc_csum16(udp->udp_csum, udp->udp_dst, *v); - memcpy(&udp->udp_dst, v, OXM_LENGTH(act->field->header)); + uint16_t v = htons(*(uint16_t*) act->field->value); + udp->udp_csum = recalc_csum16(udp->udp_csum, udp->udp_dst, v); + udp->udp_dst = v; break; } /*TODO recalculate SCTP checksum*/ case OXM_OF_SCTP_SRC:{ - uint16_t *v = (uint16_t*) act->field->value; - *v = htons(*v); - memcpy(&pkt->handle_std->proto->sctp->sctp_src, - v, OXM_LENGTH(act->field->header)); - break; + crc_t crc; + struct sctp_header *sctp = pkt->handle_std->proto->sctp; + size_t len = ((uint8_t*) ofpbuf_tail(pkt->handle_std->pkt->buffer)) - (uint8_t *) sctp; + uint16_t v = htons(*(uint16_t*) act->field->value); + sctp->sctp_csum = 0; + sctp->sctp_src = v; + crc = crc_init(); + crc = crc_update(crc, (unsigned char*)sctp, len); + crc = crc_finalize(crc); + sctp->sctp_csum = crc; + break; } case OXM_OF_SCTP_DST:{ - uint16_t *v = (uint16_t*) act->field->value; - *v = htons(*v); - memcpy(&pkt->handle_std->proto->sctp->sctp_dst, - v, OXM_LENGTH(act->field->header)); - break; + crc_t crc; + struct sctp_header *sctp = pkt->handle_std->proto->sctp; + size_t len = ((uint8_t*) ofpbuf_tail(pkt->handle_std->pkt->buffer)) - (uint8_t *) sctp; + uint16_t v = htons(*(uint16_t*) act->field->value); + sctp->sctp_csum = 0; + sctp->sctp_dst = v; + crc = crc_init(); + crc = crc_update(crc, (unsigned char*)sctp, len); + crc = crc_finalize(crc); + sctp->sctp_csum = crc; + break; } case OXM_OF_ICMPV4_TYPE: case OXM_OF_ICMPV6_TYPE:{ - pkt->handle_std->proto->icmp->icmp_type = *act->field->value; + struct icmp_header *icmp_header = pkt->handle_std->proto->icmp; + uint16_t new_val, old_val; + uint8_t icmp_type = *act->field->value; + old_val = htons((icmp_header->icmp_type << 8) + icmp_header->icmp_code); + new_val = htons((icmp_type << 8) + icmp_header->icmp_code); + icmp_header->icmp_csum = recalc_csum16(icmp_header->icmp_csum , old_val, new_val); + icmp_header->icmp_type = *act->field->value; break; } - case OXM_OF_ICMPV4_CODE: case OXM_OF_ICMPV6_CODE:{ - pkt->handle_std->proto->icmp->icmp_code = *act->field->value; + struct icmp_header *icmp_header = pkt->handle_std->proto->icmp; + uint16_t new_val, old_val; + uint8_t icmp_code = *act->field->value; + old_val = htons((icmp_header->icmp_type << 8) + icmp_header->icmp_code); + new_val = htons((icmp_header->icmp_type << 8) + icmp_code); + icmp_header->icmp_csum = recalc_csum16(icmp_header->icmp_csum , old_val, new_val); + icmp_header->icmp_code = *act->field->value; + break; + } + case OXM_OF_ARP_OP: { + pkt->handle_std->proto->arp->ar_op = htons(*((uint16_t*) act->field->value)); break; } - case OXM_OF_ARP_OP: case OXM_OF_ARP_SPA:{ pkt->handle_std->proto->arp->ar_spa = *((uint32_t*) act->field->value); + break; } case OXM_OF_ARP_TPA:{ pkt->handle_std->proto->arp->ar_tpa = *((uint32_t*) act->field->value); + break; } case OXM_OF_ARP_SHA:{ memcpy(pkt->handle_std->proto->arp->ar_sha, @@ -252,17 +301,40 @@ set_field(struct packet *pkt, struct ofl_action_set_field *act ) case OXM_OF_ARP_THA:{ memcpy(pkt->handle_std->proto->arp->ar_tha, act->field->value, OXM_LENGTH(act->field->header)); - break; + break; } case OXM_OF_IPV6_SRC:{ + struct ipv6_header *ipv6 = pkt->handle_std->proto->ipv6; + /*Reconstruct TCP or UDP checksum*/ + if (pkt->handle_std->proto->tcp != NULL) { + struct tcp_header *tcp = pkt->handle_std->proto->tcp; + tcp->tcp_csum = recalc_csum128(tcp->tcp_csum, + ipv6->ipv6_src.s6_addr, act->field->value); + } else if (pkt->handle_std->proto->udp != NULL) { + struct udp_header *udp = pkt->handle_std->proto->udp; + udp->udp_csum = recalc_csum128(udp->udp_csum, + ipv6->ipv6_src.s6_addr, act->field->value); + } memcpy(&pkt->handle_std->proto->ipv6->ipv6_src, act->field->value, OXM_LENGTH(act->field->header)); - break; + break; } case OXM_OF_IPV6_DST:{ + struct ipv6_header *ipv6 = pkt->handle_std->proto->ipv6; + /*Reconstruct TCP or UDP checksum*/ + if (pkt->handle_std->proto->tcp != NULL) { + struct tcp_header *tcp = pkt->handle_std->proto->tcp; + tcp->tcp_csum = recalc_csum128(tcp->tcp_csum, + ipv6->ipv6_dst.s6_addr, act->field->value); + } else if (pkt->handle_std->proto->udp != NULL) { + struct udp_header *udp = pkt->handle_std->proto->udp; + udp->udp_csum = recalc_csum128(udp->udp_csum, + ipv6->ipv6_dst.s6_addr, act->field->value); + } memcpy(&pkt->handle_std->proto->ipv6->ipv6_dst, act->field->value, OXM_LENGTH(act->field->header)); - break; + + break; } case OXM_OF_IPV6_FLABEL:{ struct ipv6_header *ipv6 = (struct ipv6_header*) @@ -276,42 +348,43 @@ set_field(struct packet *pkt, struct ofl_action_set_field *act ) case OXM_OF_IPV6_ND_TARGET:{ struct icmp_header *icmp = pkt->handle_std->proto->icmp; uint8_t offset; + uint8_t old_value[16]; uint8_t *data = (uint8_t*)icmp; - /*ICMP header + neighbor discovery header reserverd bytes*/ + /*ICMP header + neighbor discovery header reserved bytes*/ offset = sizeof(struct icmp_header) + 4; - + memcpy(old_value, data + offset, OXM_LENGTH(act->field->header)); memcpy(data + offset, act->field->value, OXM_LENGTH(act->field->header)); + icmp->icmp_csum = recalc_csum128(icmp->icmp_csum, + old_value, act->field->value); break; } - case OXM_OF_IPV6_ND_SLL:{ - struct icmp_header *icmp = pkt->handle_std->proto->icmp; - uint8_t offset; - struct ipv6_nd_options_hd *opt = (struct ipv6_nd_options_hd*) - icmp + sizeof(struct icmp_header); - uint8_t *data = (uint8_t*) opt; - /*ICMP header + neighbor discovery header reserverd bytes*/ - offset = sizeof(struct ipv6_nd_header); - - if(opt->type == ND_OPT_SLL){ - memcpy(data + offset, act->field->value, - OXM_LENGTH(act->field->header)); - } - break; - } + case OXM_OF_IPV6_ND_SLL: case OXM_OF_IPV6_ND_TLL:{ struct icmp_header *icmp = pkt->handle_std->proto->icmp; uint8_t offset; + uint32_t old_val32; + uint32_t new_val32; + uint16_t old_val16; + uint16_t new_val16; struct ipv6_nd_options_hd *opt = (struct ipv6_nd_options_hd*) - icmp + sizeof(struct icmp_header); + ((uint8_t*) icmp + sizeof(struct icmp_header) + + sizeof(struct ipv6_nd_header)); uint8_t *data = (uint8_t*) opt; - /*ICMP header + neighbor discovery header reserverd bytes*/ - offset = sizeof(struct ipv6_nd_header); + /*ICMP header + neighbor discovery header reserved bytes*/ + offset = sizeof(struct ipv6_nd_options_hd); + if(opt->type == ND_OPT_SLL || opt->type == ND_OPT_TLL){ + old_val16 = *((uint16_t*) (data + offset)); + old_val32 = *((uint32_t*) (data + offset + sizeof(uint16_t))); - if(opt->type == ND_OPT_TLL){ memcpy(data + offset, act->field->value, OXM_LENGTH(act->field->header)); - } break; + new_val16 = *((uint16_t*) (act->field->value)); + new_val32 = *((uint32_t*) (act->field->value + sizeof(uint16_t))); + icmp->icmp_csum = recalc_csum16(icmp->icmp_csum, old_val16, new_val16); + icmp->icmp_csum = recalc_csum32(icmp->icmp_csum, old_val32, new_val32); + } + break; } case OXM_OF_MPLS_LABEL:{ struct mpls_header *mpls = pkt->handle_std->proto->mpls; @@ -324,17 +397,29 @@ set_field(struct packet *pkt, struct ofl_action_set_field *act ) struct mpls_header *mpls = pkt->handle_std->proto->mpls; mpls->fields = (mpls->fields & ~ntohl(MPLS_TC_MASK)) | ntohl((*act->field->value << MPLS_TC_SHIFT) & MPLS_TC_MASK); + break; } case OXM_OF_MPLS_BOS:{ struct mpls_header *mpls = pkt->handle_std->proto->mpls; mpls->fields = (mpls->fields & ~ntohl(MPLS_S_MASK)) | ntohl((*act->field->value << MPLS_S_SHIFT) & MPLS_S_MASK); + break; } case OXM_OF_PBB_ISID :{ struct pbb_header *pbb = pkt->handle_std->proto->pbb; - uint32_t v = *((uint32_t*) act->field->value); - pbb->id = (pbb->id & ~ntohl(PBB_ISID_MASK)) | - ntohl(v & PBB_ISID_MASK); + uint8_t* pbb_isid; + pbb_isid = act->field->value; + pbb->id = (pbb->id & 0xFF) | ((pbb_isid[2] << 24) | (pbb_isid[1] << 16) | (pbb_isid[1] << 8)); + break; + } + case OXM_OF_TUNNEL_ID :{ + struct ofl_match_tlv *f; + HMAP_FOR_EACH_WITH_HASH(f, struct ofl_match_tlv, + hmap_node, hash_int(OXM_OF_TUNNEL_ID, 0), &(pkt)->handle_std->match.match_fields){ + uint64_t *tunnel_id = (uint64_t*) f->value; + *tunnel_id = *((uint64_t*) act->field->value); + } + break; } default: VLOG_WARN_RL(LOG_MODULE, &rl, "Trying to set unknow field."); @@ -351,21 +436,27 @@ static void copy_ttl_out(struct packet *pkt, struct ofl_action_header *act UNUSED) { packet_handle_std_validate(pkt->handle_std); if (pkt->handle_std->proto->mpls != NULL) { - struct mpls_header *mpls = pkt->handle_std->proto->mpls; - + struct mpls_header *mpls = pkt->handle_std->proto->mpls; if ((ntohl(mpls->fields) & MPLS_S_MASK) == 0) { // There is an inner MPLS header struct mpls_header *in_mpls = (struct mpls_header *)((uint8_t *)mpls + MPLS_HEADER_LEN); - mpls->fields = (mpls->fields & ~htonl(MPLS_TTL_MASK)) | (in_mpls->fields & htonl(MPLS_TTL_MASK)); - } else if (pkt->buffer->size >= ETH_HEADER_LEN + MPLS_HEADER_LEN + IP_HEADER_LEN) { - // Assumes an IPv4 header follows, if there is place for it - struct ip_header *ipv4 = (struct ip_header *)((uint8_t *)mpls + MPLS_HEADER_LEN); - - mpls->fields = (mpls->fields & ~htonl(MPLS_TTL_MASK)) | htonl((uint32_t)ipv4->ip_ttl & MPLS_TTL_MASK); - - } else { + } else if (pkt->buffer->size >= ETH_HEADER_LEN + MPLS_HEADER_LEN + + IP_HEADER_LEN || pkt->buffer->size >= ETH_HEADER_LEN + + MPLS_HEADER_LEN + IPV6_HEADER_LEN) { + // Assumes an IPv4 or Ipv6 header follows, if there is place for it + uint8_t version = *((uint8_t *)mpls + MPLS_HEADER_LEN) >> 4; + if (version == IPV4_VERSION){ + struct ip_header *ipv4 = (struct ip_header *)((uint8_t *)mpls + MPLS_HEADER_LEN); + mpls->fields = (mpls->fields & ~htonl(MPLS_TTL_MASK)) | htonl((uint32_t)ipv4->ip_ttl & MPLS_TTL_MASK); + } + else if (version == IPV6_VERSION){ + struct ipv6_header *ipv6 = (struct ipv6_header *)((uint8_t *)mpls + MPLS_HEADER_LEN); + mpls->fields = (mpls->fields & ~htonl(MPLS_TTL_MASK)) | htonl((uint32_t)ipv6->ipv6_hop_limit & MPLS_TTL_MASK); + } + } + else { VLOG_WARN_RL(LOG_MODULE, &rl, "Trying to execute copy ttl in action on packet with only one mpls."); } } else { @@ -386,17 +477,26 @@ copy_ttl_in(struct packet *pkt, struct ofl_action_header *act UNUSED) { in_mpls->fields = (in_mpls->fields & ~htonl(MPLS_TTL_MASK)) | (mpls->fields & htonl(MPLS_TTL_MASK)); - } else if (pkt->buffer->size >= ETH_HEADER_LEN + MPLS_HEADER_LEN + IP_HEADER_LEN) { - // Assumes an IPv4 header follows, if there is place for it - struct ip_header *ipv4 = (struct ip_header *)((uint8_t *)mpls + MPLS_HEADER_LEN); - - uint8_t new_ttl = (ntohl(mpls->fields) & MPLS_TTL_MASK) >> MPLS_TTL_SHIFT; - uint16_t old_val = htons((ipv4->ip_proto) + (ipv4->ip_ttl<<8)); - uint16_t new_val = htons((ipv4->ip_proto) + (new_ttl<<8)); - ipv4->ip_csum = recalc_csum16(ipv4->ip_csum, old_val, new_val); - ipv4->ip_ttl = new_ttl; - - } else { + } else if (pkt->buffer->size >= ETH_HEADER_LEN + MPLS_HEADER_LEN + + IP_HEADER_LEN || pkt->buffer->size >= ETH_HEADER_LEN + + MPLS_HEADER_LEN + IPV6_HEADER_LEN) { + // Assumes an IPv4 or Ipv6 header follows, if there is place for it + uint8_t version = *((uint8_t *)mpls + MPLS_HEADER_LEN) >> 4; + if (version == IPV4_VERSION){ + struct ip_header *ipv4 = (struct ip_header *)((uint8_t *)mpls + MPLS_HEADER_LEN); + uint8_t new_ttl = (ntohl(mpls->fields) & MPLS_TTL_MASK) >> MPLS_TTL_SHIFT; + uint16_t old_val = htons((ipv4->ip_proto) + (ipv4->ip_ttl<<8)); + uint16_t new_val = htons((ipv4->ip_proto) + (new_ttl<<8)); + ipv4->ip_csum = recalc_csum16(ipv4->ip_csum, old_val, new_val); + ipv4->ip_ttl = new_ttl; + } + else if (version == IPV6_VERSION){ + struct ipv6_header *ipv6 = (struct ipv6_header *)((uint8_t *)mpls + MPLS_HEADER_LEN); + uint8_t new_ttl = (ntohl(mpls->fields) & MPLS_TTL_MASK) >> MPLS_TTL_SHIFT; + ipv6->ipv6_hop_limit = new_ttl; + } + } + else { VLOG_WARN_RL(LOG_MODULE, &rl, "Trying to execute copy ttl in action on packet with only one mpls."); } } else { @@ -547,13 +647,16 @@ push_mpls(struct packet *pkt, struct ofl_action_push *act) { if (pkt->handle_std->proto->eth != NULL) { struct eth_header *eth, *new_eth; struct snap_header *snap, *new_snap; + struct vlan_header *vlan, *new_vlan; struct mpls_header *mpls, *new_mpls, *push_mpls; - struct ip_header *ipv4; - struct ipv6_header *ipv6; + struct ip_header *ipv4, *new_ipv4; + struct ipv6_header *ipv6, *new_ipv6; size_t eth_size; + size_t head_offset; eth = pkt->handle_std->proto->eth; snap = pkt->handle_std->proto->eth_snap; + vlan = pkt->handle_std->proto->vlan_last; mpls = pkt->handle_std->proto->mpls; ipv4 = pkt->handle_std->proto->ipv4; ipv6 = pkt->handle_std->proto->ipv6; @@ -562,19 +665,24 @@ push_mpls(struct packet *pkt, struct ofl_action_push *act) { ? ETH_HEADER_LEN : ETH_HEADER_LEN + LLC_HEADER_LEN + SNAP_HEADER_LEN; + head_offset = vlan == NULL ? eth_size + : (uint8_t *)vlan - (uint8_t *)eth + VLAN_HEADER_LEN; + if (ofpbuf_headroom(pkt->buffer) >= MPLS_HEADER_LEN) { // there is available space in headroom, move eth backwards pkt->buffer->data = (uint8_t *)(pkt->buffer->data) - MPLS_HEADER_LEN; pkt->buffer->size += MPLS_HEADER_LEN; - memmove(pkt->buffer->data, eth, eth_size); - + memmove(pkt->buffer->data, eth, head_offset); new_eth = (struct eth_header *)(pkt->buffer->data); new_snap = snap == NULL ? NULL - : (struct snap_header *)((uint8_t *)new_eth - + ETH_HEADER_LEN + MPLS_HEADER_LEN + LLC_HEADER_LEN); - push_mpls = (struct mpls_header *)((uint8_t *)new_eth + eth_size); + : (struct snap_header *)((uint8_t *)snap - MPLS_HEADER_LEN); + new_vlan = vlan == NULL ? NULL + : (struct vlan_header *)((uint8_t *)vlan - MPLS_HEADER_LEN); + push_mpls = (struct mpls_header *)((uint8_t *)new_eth + head_offset); new_mpls = mpls; + new_ipv4 = ipv4; + new_ipv6 = ipv6; } else { // not enough headroom, use tailroom of the packet @@ -584,39 +692,51 @@ push_mpls(struct packet *pkt, struct ofl_action_push *act) { new_eth = (struct eth_header *)(pkt->buffer->data); new_snap = snap == NULL ? NULL - : (struct snap_header *)((uint8_t *)new_eth - + ETH_HEADER_LEN + MPLS_HEADER_LEN + LLC_HEADER_LEN); - push_mpls = (struct mpls_header *)((uint8_t *)new_eth + ETH_HEADER_LEN); + : (struct snap_header *)((uint8_t *)snap - (uint8_t *)eth + (uint8_t *)new_eth); + new_vlan = vlan == NULL ? NULL + : (struct vlan_header *)((uint8_t *)vlan - (uint8_t *)eth + (uint8_t *)new_eth); + push_mpls = (struct mpls_header *)((uint8_t *)new_eth + head_offset); // push data to create space for new MPLS memmove((uint8_t *)push_mpls + MPLS_HEADER_LEN, push_mpls, - pkt->buffer->size - ETH_HEADER_LEN); - - new_mpls = mpls == NULL ? NULL - : (struct mpls_header *)((uint8_t *)push_mpls + MPLS_HEADER_LEN); + pkt->buffer->size - head_offset); + + new_mpls = mpls == NULL ? NULL + : (struct mpls_header *)((uint8_t *)push_mpls + MPLS_HEADER_LEN); + // Note: if ipv4 was not null, then there was no MPLS header in 1.1 + new_ipv4 = ipv4 == NULL ? NULL + : (struct ip_header *)((uint8_t *)push_mpls + MPLS_HEADER_LEN); + new_ipv6 = ipv6 == NULL ? NULL + : (struct ipv6_header *)((uint8_t *)push_mpls + MPLS_HEADER_LEN); } if (new_mpls != NULL) { push_mpls->fields = new_mpls->fields & ~htonl(MPLS_S_MASK); - } else if (ipv4 != NULL) { + } else if (new_ipv4 != NULL) { // copy IP TTL to MPLS TTL (rest is zero), and set S bit - push_mpls->fields = htonl((uint32_t)ipv4->ip_ttl & MPLS_TTL_MASK) | htonl(MPLS_S_MASK); - } else if (ipv6 != NULL) { + push_mpls->fields = htonl((uint32_t)new_ipv4->ip_ttl & MPLS_TTL_MASK) | htonl(MPLS_S_MASK); + } else if (new_ipv6 != NULL) { // copy IP HOP LIMIT to MPLS TTL (rest is zero), and set S bit - push_mpls->fields = htonl((uint32_t)ipv6->ipv6_hop_limit & MPLS_TTL_MASK) | htonl(MPLS_S_MASK); - } - else { + push_mpls->fields = htonl((uint32_t)new_ipv6->ipv6_hop_limit & MPLS_TTL_MASK) | htonl(MPLS_S_MASK); + } else { push_mpls->fields = htonl(MPLS_S_MASK); } - if (new_snap != NULL) { - new_snap->snap_type = ntohs(act->ethertype); + if (new_vlan != NULL) { + new_vlan->vlan_next_type = htons(act->ethertype); + } else if (new_snap != NULL) { + new_snap->snap_type = htons(act->ethertype); } else { - new_eth->eth_type = ntohs(act->ethertype); + new_eth->eth_type = htons(act->ethertype); } - pkt->handle_std->valid = false; + if (new_snap != NULL) { + new_eth->eth_type = htons(ntohs(new_eth->eth_type) + MPLS_HEADER_LEN); + } + // in 1.1 all proto but eth and mpls will be hidden, + // so revalidating won't be a tedious work (probably) + pkt->handle_std->valid = false; } else { VLOG_WARN_RL(LOG_MODULE, &rl, "Trying to execute PUSH_MPLS action on packet with no eth."); } @@ -786,8 +906,12 @@ set_nw_ttl(struct packet *pkt, struct ofl_action_set_nw_ttl *act) { uint16_t new_val = htons((ipv4->ip_proto) + (act->nw_ttl<<8)); ipv4->ip_csum = recalc_csum16(ipv4->ip_csum, old_val, new_val); ipv4->ip_ttl = act->nw_ttl; - } else { - VLOG_WARN_RL(LOG_MODULE, &rl, "Trying to execute SET_NW_TTL action on packet with no ipv4."); + } else if (pkt->handle_std->proto->ipv6 != NULL){ + struct ipv6_header *ipv6 = pkt->handle_std->proto->ipv6; + ipv6->ipv6_hop_limit = act->nw_ttl; + } + else { + VLOG_WARN_RL(LOG_MODULE, &rl, "Trying to execute SET_NW_TTL action on packet with no ipv4 or ipv6."); } } @@ -807,7 +931,13 @@ dec_nw_ttl(struct packet *pkt, struct ofl_action_header *act UNUSED) { ipv4->ip_csum = recalc_csum16(ipv4->ip_csum, old_val, new_val); ipv4->ip_ttl = new_ttl; } - } else { + } else if (pkt->handle_std->proto->ipv6 != NULL){ + struct ipv6_header *ipv6 = pkt->handle_std->proto->ipv6; + if (ipv6->ipv6_hop_limit > 0){ + --ipv6->ipv6_hop_limit; + } + } + else { VLOG_WARN_RL(LOG_MODULE, &rl, "Trying to execute DEC_NW_TTL action on packet with no ipv4."); } } @@ -918,10 +1048,17 @@ dp_execute_action_list(struct packet *pkt, dp_execute_action(pkt, actions[i]); if (pkt->out_group != OFPG_ANY) { + struct packet *pkt_clone; uint32_t group = pkt->out_group; pkt->out_group = OFPG_ANY; VLOG_DBG_RL(LOG_MODULE, &rl, "Group action; executing group (%u).", group); - group_table_execute(pkt->dp->groups, pkt, group); + /* The group must process a copy of the packet in the current state, + * so that when we return we continue processing an unmodified + * version of the packet. The group must also ignore the current + * action-set. We need to clone the packet with an empty + * action-set. Jean II */ + pkt_clone = packet_clone(pkt); + group_table_execute(pkt_clone->dp->groups, pkt_clone, group); } else if (pkt->out_port != OFPP_ANY) { uint32_t port = pkt->out_port; @@ -945,8 +1082,11 @@ dp_actions_output_port(struct packet *pkt, uint32_t out_port, uint32_t out_queue case (OFPP_TABLE): { if (pkt->packet_out) { // NOTE: hackish; makes sure packet cannot be resubmit to pipeline again. - pkt->packet_out = false; - pipeline_process_packet(pkt->dp->pipeline, pkt); + // pipeline_process_packet takes overship of the packet, we need a copy. + struct packet *pkt_copy = packet_clone(pkt); + + pkt_copy->packet_out = false; + pipeline_process_packet(pkt->dp->pipeline, pkt_copy); } else { VLOG_WARN_RL(LOG_MODULE, &rl, "Trying to resubmit packet to pipeline."); } @@ -1082,4 +1222,5 @@ dp_actions_check_set_field_req(struct ofl_msg_flow_mod *msg, size_t actions_num, } } return 0; -} \ No newline at end of file +} + diff --git a/udatapath/dp_control.c b/udatapath/dp_control.c index 2cfde9ed..d9a6b75d 100644 --- a/udatapath/dp_control.c +++ b/udatapath/dp_control.c @@ -126,10 +126,9 @@ handle_control_packet_out(struct datapath *dp, struct ofl_msg_packet_out *msg, const struct sender *sender) { struct packet *pkt; int error; - - if(sender->remote->role == OFPCR_ROLE_SLAVE) + if(sender->remote->role == OFPCR_ROLE_SLAVE){ return ofl_error(OFPET_BAD_REQUEST, OFPBRC_IS_SLAVE); - + } error = dp_actions_validate(dp, msg->actions_num, msg->actions); if (error) { return error; @@ -137,11 +136,15 @@ handle_control_packet_out(struct datapath *dp, struct ofl_msg_packet_out *msg, if (msg->buffer_id == NO_BUFFER) { struct ofpbuf *buf; + /* If there is no packet in the message, send error message */ + if (!msg->data_length){ + return ofl_error(OFPET_BAD_REQUEST, OFPBRC_BAD_PACKET); + } /* NOTE: the created packet will take the ownership of data in msg. */ buf = ofpbuf_new(0); ofpbuf_use(buf, msg->data, msg->data_length); - ofpbuf_put_uninit(buf, msg->data_length); - pkt = packet_create(dp, msg->in_port, buf, true); + ofpbuf_put_uninit(buf, msg->data_length); + pkt = packet_create(dp, msg->in_port, buf, true); } else { /* NOTE: in this case packet should not have data */ pkt = dp_buffers_retrieve(dp->buffers, msg->buffer_id); @@ -155,7 +158,7 @@ handle_control_packet_out(struct datapath *dp, struct ofl_msg_packet_out *msg, dp_execute_action_list(pkt, msg->actions_num, msg->actions, 0xffffffffffffffff); packet_destroy(pkt); - ofl_msg_free_packet_out(msg, false, dp->exp); + ofl_msg_free_packet_out(msg, false, dp->exp); return 0; } diff --git a/udatapath/dp_ports.c b/udatapath/dp_ports.c index 684357ec..ded2fe12 100644 --- a/udatapath/dp_ports.c +++ b/udatapath/dp_ports.c @@ -215,7 +215,7 @@ static void process_buffer(struct datapath *dp, struct sw_port *p, struct ofpbuf *buffer) { struct packet *pkt; - if (p->conf->config & ((OFPPC_NO_RECV | OFPPC_PORT_DOWN) != 0)) { + if ((p->conf->config & (OFPPC_NO_RECV | OFPPC_PORT_DOWN)) != 0) { ofpbuf_delete(buffer); return; } @@ -229,6 +229,7 @@ void dp_ports_run(struct datapath *dp) { // static, so an unused buffer can be reused at the dp_ports_run call static struct ofpbuf *buffer = NULL; + int max_mtu = 0; struct sw_port *p, *pn; @@ -247,8 +248,28 @@ dp_ports_run(struct datapath *dp) { } #endif + // find largest MTU on our interfaces + // buffer is shared among all (idle) interfaces... + LIST_FOR_EACH_SAFE (p, pn, struct sw_port, node, &dp->port_list) { + const int mtu = netdev_get_mtu(p->netdev); + if (IS_HW_PORT(p)) + continue; + if (mtu > max_mtu) + max_mtu = mtu; + } + LIST_FOR_EACH_SAFE (p, pn, struct sw_port, node, &dp->port_list) { int error; + /* Check for interface state change */ + enum netdev_link_state link_state = netdev_link_state(p->netdev); + if (link_state == NETDEV_LINK_UP){ + p->conf->state &= ~OFPPS_LINK_DOWN; + dp_port_live_update(p); + } + else if (link_state == NETDEV_LINK_DOWN){ + p->conf->state |= OFPPS_LINK_DOWN; + dp_port_live_update(p); + } if (IS_HW_PORT(p)) { continue; @@ -258,14 +279,9 @@ dp_ports_run(struct datapath *dp) { * to the controller or adding a vlan tag, plus an extra 2 bytes to * allow IP headers to be aligned on a 4-byte boundary. */ const int headroom = 128 + 2; - const int hard_header = VLAN_ETH_HEADER_LEN; - const int mtu = netdev_get_mtu(p->netdev); - buffer = ofpbuf_new_with_headroom(hard_header + mtu, headroom); - } - error = netdev_recv(p->netdev, buffer); - if (error == ENETDOWN){ - VLOG_ERR(LOG_MODULE, "Não tenho nada mas tô aqui..."); + buffer = ofpbuf_new_with_headroom(VLAN_ETH_HEADER_LEN + max_mtu, headroom); } + error = netdev_recv(p->netdev, buffer, VLAN_ETH_HEADER_LEN + max_mtu); if (!error) { p->stats->rx_packets++; p->stats->rx_bytes += buffer->size; @@ -273,9 +289,6 @@ dp_ports_run(struct datapath *dp) { process_buffer(dp, p, buffer); buffer = NULL; } else if (error != EAGAIN) { - if(error == ENETDOWN){ - p->conf->state = OFPPS_LINK_DOWN; - } VLOG_ERR_RL(LOG_MODULE, &rl, "error receiving data from %s: %s", netdev_get_name(p->netdev), strerror(error)); } @@ -398,6 +411,7 @@ new_port(struct datapath *dp, struct sw_port *port, uint32_t port_no, / * FIXME: Add current, supported and advertised features * / #endif } + dp_port_live_update(port); port->stats = xmalloc(sizeof(struct ofl_port_stats)); port->stats->port_no = port_no; @@ -548,7 +562,7 @@ dp_ports_lookup_queue(struct sw_port *p, uint32_t queue_id) { struct sw_queue *q; - if (queue_id <= p->max_queues) { + if (queue_id < p->max_queues) { q = &(p->queues[queue_id]); if (q->port != NULL) { @@ -644,7 +658,6 @@ dp_ports_output_all(struct datapath *dp, struct ofpbuf *buffer, int in_port, boo if (flood && p->conf->config & OFPPC_NO_FWD) { continue; } - dp_ports_output(dp, buffer, p->stats->port_no, 0); } @@ -656,6 +669,7 @@ dp_ports_handle_port_mod(struct datapath *dp, struct ofl_msg_port_mod *msg, const struct sender *sender) { struct sw_port *p; + struct ofl_msg_port_status rep_msg; if(sender->remote->role == OFPCR_ROLE_SLAVE) return ofl_error(OFPET_BAD_REQUEST, OFPBRC_IS_SLAVE); @@ -676,15 +690,14 @@ dp_ports_handle_port_mod(struct datapath *dp, struct ofl_msg_port_mod *msg, if (msg->mask) { p->conf->config &= ~msg->mask; p->conf->config |= msg->config & msg->mask; + dp_port_live_update(p); } /*Notify all controllers that the port status has changed*/ - struct ofl_msg_port_status rep_msg = - {{.type = OFPT_PORT_STATUS}, - .reason = OFPPR_MODIFY, .desc = p->conf}; - + rep_msg.header.type = OFPT_PORT_STATUS; + rep_msg.reason = OFPPR_MODIFY; + rep_msg.desc = p->conf; dp_send_message(dp, (struct ofl_msg_header *)&rep_msg, NULL/*sender*/); - ofl_msg_free((struct ofl_msg_header *)msg, dp->exp); return 0; } @@ -692,7 +705,20 @@ dp_ports_handle_port_mod(struct datapath *dp, struct ofl_msg_port_mod *msg, static void dp_port_stats_update(struct sw_port *port) { port->stats->duration_sec = (time_msec() - port->created) / 1000; - port->stats->duration_nsec = ((time_msec() - port->created) % 1000) * 1000; + port->stats->duration_nsec = ((time_msec() - port->created) % 1000) * 1000000; +} + +void +dp_port_live_update(struct sw_port *p) { + + if((p->conf->state & OFPPS_LINK_DOWN) + || (p->conf->config & OFPPC_PORT_DOWN)) { + /* Port not live */ + p->conf->state &= ~OFPPS_LIVE; + } else { + /* Port is live */ + p->conf->state |= OFPPS_LIVE; + } } ofl_err @@ -771,7 +797,7 @@ dp_ports_handle_port_desc_request(struct datapath *dp, static void dp_ports_queue_update(struct sw_queue *queue) { queue->stats->duration_sec = (time_msec() - queue->created) / 1000; - queue->stats->duration_nsec = ((time_msec() - queue->created) % 1000) * 1000; + queue->stats->duration_nsec = ((time_msec() - queue->created) % 1000) * 1000000; } ofl_err @@ -968,7 +994,7 @@ static int port_add_queue(struct sw_port *p, uint32_t queue_id, struct ofl_queue_prop_min_rate * mr) { - if (queue_id > p->max_queues) { + if (queue_id >= p->max_queues) { return EXFULL; } diff --git a/udatapath/dp_ports.h b/udatapath/dp_ports.h index cea9dab6..6ae98347 100644 --- a/udatapath/dp_ports.h +++ b/udatapath/dp_ports.h @@ -149,6 +149,10 @@ ofl_err dp_ports_handle_port_mod(struct datapath *dp, struct ofl_msg_port_mod *msg, const struct sender *sender); +/* Update Live flag on a port/ */ +void +dp_port_live_update(struct sw_port *port); + /* Handles a port stats request message. */ ofl_err dp_ports_handle_stats_request_port(struct datapath *dp, diff --git a/udatapath/flow_entry.c b/udatapath/flow_entry.c index d0719051..b7287bb2 100644 --- a/udatapath/flow_entry.c +++ b/udatapath/flow_entry.c @@ -150,6 +150,19 @@ flow_entry_replace_instructions(struct flow_entry *entry, init_group_refs(entry); } +void +flow_entry_modify_stats(struct flow_entry *entry, + struct ofl_msg_flow_mod *mod) { + + /* Reset flow counters as needed. Jean II */ + if ((mod->flags & OFPFF_RESET_COUNTS) != 0) { + if (!(entry->no_pkt_count)) + entry->stats->packet_count = 0; + if (!(entry->no_byt_count)) + entry->stats->byte_count = 0; + } +} + bool flow_entry_idle_timeout(struct flow_entry *entry) { bool timeout; @@ -178,7 +191,7 @@ flow_entry_hard_timeout(struct flow_entry *entry) { void flow_entry_update(struct flow_entry *entry) { entry->stats->duration_sec = (time_msec() - entry->created) / 1000; - entry->stats->duration_nsec = ((time_msec() - entry->created) % 1000) * 1000; + entry->stats->duration_nsec = ((time_msec() - entry->created) % 1000) * 1000000; } /* Returns true if the flow entry has a reference to the given group. */ @@ -331,6 +344,7 @@ flow_entry_create(struct datapath *dp, struct flow_table *table, struct ofl_msg_ entry->stats->priority = mod->priority; entry->stats->idle_timeout = mod->idle_timeout; entry->stats->hard_timeout = mod->hard_timeout; + entry->stats->flags = mod->flags; entry->stats->cookie = mod->cookie; entry->no_pkt_count = ((mod->flags & OFPFF_NO_PKT_COUNTS) != 0 ); entry->no_byt_count = ((mod->flags & OFPFF_NO_BYT_COUNTS) != 0 ); diff --git a/udatapath/flow_entry.h b/udatapath/flow_entry.h index 0c893f0d..f411f904 100644 --- a/udatapath/flow_entry.h +++ b/udatapath/flow_entry.h @@ -83,6 +83,9 @@ void flow_entry_replace_instructions(struct flow_entry *entry, size_t instructions_num, struct ofl_instruction_header **instructions); +void +flow_entry_modify_stats(struct flow_entry *entry, + struct ofl_msg_flow_mod *mod); /* Checks if the entry should time out because of its idle timeout. If so, the * packet is freed, flow removed message is generated, and true is returned. */ diff --git a/udatapath/flow_table.c b/udatapath/flow_table.c index 5d236808..defa4bad 100644 --- a/udatapath/flow_table.c +++ b/udatapath/flow_table.c @@ -55,14 +55,24 @@ uint32_t oxm_ids[]={OXM_OF_IN_PORT,OXM_OF_IN_PHY_PORT,OXM_OF_METADATA,OXM_OF_ET OXM_OF_IPV6_ND_TLL, OXM_OF_MPLS_LABEL, OXM_OF_MPLS_TC, OXM_OF_MPLS_BOS, OXM_OF_PBB_ISID, OXM_OF_TUNNEL_ID, OXM_OF_IPV6_EXTHDR}; +#define NUM_OXM_IDS (sizeof(oxm_ids) / sizeof(uint32_t)) +/* Do *NOT* use N_OXM_FIELDS, it's ligically wrong and can run over + * the oxm_ids array. Jean II */ + uint32_t wildcarded[] = {OXM_OF_METADATA, OXM_OF_ETH_DST, OXM_OF_ETH_SRC, OXM_OF_VLAN_VID, OXM_OF_IPV4_SRC, OXM_OF_IPV4_DST, OXM_OF_ARP_SPA, OXM_OF_ARP_TPA, OXM_OF_ARP_SHA, OXM_OF_ARP_THA, OXM_OF_IPV6_SRC, OXM_OF_IPV6_DST , OXM_OF_IPV6_FLABEL, OXM_OF_PBB_ISID, OXM_OF_TUNNEL_ID, OXM_OF_IPV6_EXTHDR}; +#define NUM_WILD_IDS (sizeof(wildcarded) / sizeof(uint32_t)) struct ofl_instruction_header instructions[] = { {OFPIT_GOTO_TABLE}, {OFPIT_WRITE_METADATA },{OFPIT_WRITE_ACTIONS},{OFPIT_APPLY_ACTIONS}, {OFPIT_CLEAR_ACTIONS},{OFPIT_METER}} ; +struct ofl_instruction_header instructions_nogoto[] = { + {OFPIT_WRITE_METADATA },{OFPIT_WRITE_ACTIONS},{OFPIT_APPLY_ACTIONS}, + {OFPIT_CLEAR_ACTIONS},{OFPIT_METER}} ; + +#define N_INSTRUCTIONS (sizeof(instructions) / sizeof(struct ofl_instruction_header)) struct ofl_action_header actions[] = { {OFPAT_OUTPUT, 4}, {OFPAT_COPY_TTL_OUT, 4},{OFPAT_COPY_TTL_IN, 4},{OFPAT_SET_MPLS_TTL, 4}, @@ -70,6 +80,8 @@ struct ofl_action_header actions[] = { {OFPAT_OUTPUT, 4}, {OFPAT_POP_MPLS, 4},{OFPAT_SET_QUEUE, 4}, {OFPAT_GROUP, 4}, {OFPAT_SET_NW_TTL, 4}, {OFPAT_DEC_NW_TTL, 4}, {OFPAT_SET_FIELD, 4}, {OFPAT_PUSH_PBB, 4}, {OFPAT_POP_PBB, 4} } ; +#define N_ACTIONS (sizeof(actions) / sizeof(struct ofl_action_header)) + /* When inserting an entry, this function adds the flow entry to the list of * hard and idle timeout entries, if appropriate. */ static void @@ -147,6 +159,7 @@ flow_table_modify(struct flow_table *table, struct ofl_msg_flow_mod *mod, bool s LIST_FOR_EACH (entry, struct flow_entry, match_node, &table->match_entries) { if (flow_entry_matches(entry, mod, strict, true/*check_cookie*/)) { flow_entry_replace_instructions(entry, mod->instructions_num, mod->instructions); + flow_entry_modify_stats(entry, mod); *insts_kept = true; } } @@ -257,7 +270,7 @@ flow_table_timeout(struct flow_table *table) { static void -flow_table_create_property(struct ofl_table_feature_prop_header **prop, enum ofp_table_feature_prop_type type){ +flow_table_create_property(struct ofl_table_feature_prop_header **prop, enum ofp_table_feature_prop_type type, uint8_t table_id){ switch(type){ case OFPTFPT_INSTRUCTIONS: @@ -265,8 +278,14 @@ flow_table_create_property(struct ofl_table_feature_prop_header **prop, enum ofp struct ofl_table_feature_prop_instructions *inst_capabilities; inst_capabilities = xmalloc(sizeof(struct ofl_table_feature_prop_instructions)); inst_capabilities->header.type = type; - inst_capabilities->ids_num = N_INSTRUCTIONS; - inst_capabilities->instruction_ids = instructions; + inst_capabilities->instruction_ids = xmalloc(sizeof(instructions)); + if (table_id < PIPELINE_TABLES - 1) { + inst_capabilities->ids_num = N_INSTRUCTIONS; + memcpy(inst_capabilities->instruction_ids, instructions, sizeof(instructions)); + } else { + inst_capabilities->ids_num = N_INSTRUCTIONS - 1; + memcpy(inst_capabilities->instruction_ids, instructions_nogoto, sizeof(instructions_nogoto)); + } inst_capabilities->header.length = ofl_structs_table_features_properties_ofp_len(&inst_capabilities->header, NULL); (*prop) = (struct ofl_table_feature_prop_header*) inst_capabilities; break; @@ -275,12 +294,15 @@ flow_table_create_property(struct ofl_table_feature_prop_header **prop, enum ofp case OFPTFPT_NEXT_TABLES_MISS:{ struct ofl_table_feature_prop_next_tables *tbl_reachable; int i; + uint8_t next; tbl_reachable = xmalloc(sizeof(struct ofl_table_feature_prop_next_tables)); tbl_reachable->header.type = type; - tbl_reachable->table_num = PIPELINE_TABLES ; - tbl_reachable->next_table_ids = xmalloc(sizeof(uint8_t) * tbl_reachable->table_num); - for(i=0; i < tbl_reachable->table_num; i++) - tbl_reachable->next_table_ids[i] = i; + tbl_reachable->table_num = PIPELINE_TABLES - 1 - table_id; + if (tbl_reachable->table_num > 0) { + tbl_reachable->next_table_ids = xmalloc(sizeof(uint8_t) * tbl_reachable->table_num); + for (i = 0, next = table_id + 1; i < tbl_reachable->table_num; i++, next++) + tbl_reachable->next_table_ids[i] = next; + } tbl_reachable->header.length = ofl_structs_table_features_properties_ofp_len(&tbl_reachable->header, NULL); *prop = (struct ofl_table_feature_prop_header*) tbl_reachable; break; @@ -293,7 +315,8 @@ flow_table_create_property(struct ofl_table_feature_prop_header **prop, enum ofp act_capabilities = xmalloc(sizeof(struct ofl_table_feature_prop_actions)); act_capabilities->header.type = type; act_capabilities->actions_num= N_ACTIONS; - act_capabilities->action_ids = actions; + act_capabilities->action_ids = xmalloc(sizeof(actions)); + memcpy(act_capabilities->action_ids, actions, sizeof(actions)); act_capabilities->header.length = ofl_structs_table_features_properties_ofp_len(&act_capabilities->header, NULL); *prop = (struct ofl_table_feature_prop_header*) act_capabilities; break; @@ -304,11 +327,11 @@ flow_table_create_property(struct ofl_table_feature_prop_header **prop, enum ofp case OFPTFPT_WRITE_SETFIELD: case OFPTFPT_WRITE_SETFIELD_MISS:{ struct ofl_table_feature_prop_oxm *oxm_capabilities; - int i; oxm_capabilities = xmalloc(sizeof(struct ofl_table_feature_prop_oxm)); oxm_capabilities->header.type = type; - oxm_capabilities->oxm_num = NUM_OXM_FIELDS; - oxm_capabilities->oxm_ids = oxm_ids; + oxm_capabilities->oxm_num = NUM_OXM_IDS; + oxm_capabilities->oxm_ids = xmalloc(sizeof(oxm_ids)); + memcpy(oxm_capabilities->oxm_ids, oxm_ids, sizeof(oxm_ids)); oxm_capabilities->header.length = ofl_structs_table_features_properties_ofp_len(&oxm_capabilities->header, NULL); *prop = (struct ofl_table_feature_prop_header*) oxm_capabilities; break; @@ -317,8 +340,9 @@ flow_table_create_property(struct ofl_table_feature_prop_header **prop, enum ofp struct ofl_table_feature_prop_oxm *oxm_capabilities; oxm_capabilities = xmalloc(sizeof(struct ofl_table_feature_prop_oxm)); oxm_capabilities->header.type = type; - oxm_capabilities->oxm_num = N_WILDCARDED; - oxm_capabilities->oxm_ids = wildcarded; + oxm_capabilities->oxm_num = NUM_WILD_IDS; + oxm_capabilities->oxm_ids = xmalloc(sizeof(wildcarded)); + memcpy(oxm_capabilities->oxm_ids, wildcarded, sizeof(wildcarded)); oxm_capabilities->header.length = ofl_structs_table_features_properties_ofp_len(&oxm_capabilities->header, NULL); *prop = (struct ofl_table_feature_prop_header*) oxm_capabilities; break; @@ -338,7 +362,7 @@ flow_table_features(struct ofl_table_features *features){ j = 0; for(type = OFPTFPT_INSTRUCTIONS; type <= OFPTFPT_APPLY_SETFIELD_MISS; type++){ //features->properties[j] = xmalloc(sizeof(struct ofl_table_feature_prop_header)); - flow_table_create_property(&features->properties[j], type); + flow_table_create_property(&features->properties[j], type, features->table_id); if(type == OFPTFPT_MATCH|| type == OFPTFPT_WILDCARDS){ type++; } @@ -361,6 +385,7 @@ flow_table_create(struct datapath *dp, uint8_t table_id) { table = xmalloc(sizeof(struct flow_table)); table->dp = dp; + table->disabled = 0; /*Init table stats */ table->stats = xmalloc(sizeof(struct ofl_table_stats)); @@ -375,7 +400,7 @@ flow_table_create(struct datapath *dp, uint8_t table_id) { table->features->name = ds_cstr(&string); table->features->metadata_match = 0xffffffffffffffff; table->features->metadata_write = 0xffffffffffffffff; - table->features->config = OFPTC_TABLE_MISS_CONTROLLER; + table->features->config = OFPTC_DEPRECATED_MASK; table->features->max_entries = FLOW_TABLE_MAX_ENTRIES; table->features->properties_num = flow_table_features(table->features); diff --git a/udatapath/flow_table.h b/udatapath/flow_table.h index 9210095a..9ee45635 100644 --- a/udatapath/flow_table.h +++ b/udatapath/flow_table.h @@ -37,13 +37,9 @@ #include "timeval.h" -#define FLOW_TABLE_MAX_ENTRIES 1024 +#define FLOW_TABLE_MAX_ENTRIES 4096 #define TABLE_FEATURES_NUM 14 -// EEDJAS: N_OXM_FIELDS is an enum value exported by oxm-match.h via ofl-structs.h -// #define N_OXM_FIELDS 40 -#define N_INSTRUCTIONS 6 -#define N_ACTIONS 16 -#define N_WILDCARDED 16 + /**************************************************************************** * Implementation of a flow table. The current implementation stores flow * entries in priority and then insertion order. @@ -52,6 +48,7 @@ struct flow_table { struct datapath *dp; + bool disabled; /* Don't use that table. */ struct ofl_table_features *features; /*store table features*/ struct ofl_table_stats *stats; /* structure storing table statistics. */ diff --git a/udatapath/group_entry.c b/udatapath/group_entry.c index 399baa11..e5efb84e 100644 --- a/udatapath/group_entry.c +++ b/udatapath/group_entry.c @@ -83,20 +83,15 @@ struct group_entry * group_entry_create(struct datapath *dp, struct group_table *table, struct ofl_msg_group_mod *mod) { struct group_entry *entry; size_t i; - uint64_t now; - - now = time_msec(); + entry = xmalloc(sizeof(struct group_entry)); - entry->dp = dp; entry->table = table; - entry->desc = xmalloc(sizeof(struct ofl_group_desc_stats)); entry->desc->type = mod->type; entry->desc->group_id = mod->group_id; entry->desc->buckets_num = mod->buckets_num; entry->desc->buckets = mod->buckets; - entry->stats = xmalloc(sizeof(struct ofl_group_stats)); entry->stats->group_id = mod->group_id; entry->stats->ref_count = 0; @@ -112,7 +107,6 @@ group_entry_create(struct datapath *dp, struct group_table *table, struct ofl_ms entry->stats->counters[i]->packet_count = 0; entry->stats->counters[i]->byte_count = 0; } - switch (mod->type) { case (OFPGT_SELECT): { init_select_group(entry, mod); @@ -122,9 +116,7 @@ group_entry_create(struct datapath *dp, struct group_table *table, struct ofl_ms entry->data = NULL; } } - list_init(&entry->flow_refs); - return entry; } @@ -175,9 +167,9 @@ execute_all(struct group_entry *entry, struct packet *pkt) { because we cannot associate to any particular flow */ action_set_execute(p->action_set, p, 0xffffffffffffffff); - - packet_destroy(p); + /* Clone will be destroyed above. Jean II */ } + packet_destroy(pkt); } /* Executes a group entry of type SELECT. */ @@ -187,7 +179,6 @@ execute_select(struct group_entry *entry, struct packet *pkt) { if (b != -1) { struct ofl_bucket *bucket = entry->desc->buckets[b]; - struct packet *p = packet_clone(pkt); if (VLOG_IS_DBG_ENABLED(LOG_MODULE)) { char *b = ofl_structs_bucket_to_string(bucket, entry->dp->exp); @@ -195,19 +186,19 @@ execute_select(struct group_entry *entry, struct packet *pkt) { free(b); } - action_set_write_actions(p->action_set, bucket->actions_num, bucket->actions); + action_set_write_actions(pkt->action_set, bucket->actions_num, bucket->actions); - entry->stats->byte_count += p->buffer->size; + entry->stats->byte_count += pkt->buffer->size; entry->stats->packet_count++; - entry->stats->counters[b]->byte_count += p->buffer->size; + entry->stats->counters[b]->byte_count += pkt->buffer->size; entry->stats->counters[b]->packet_count++; /* Cookie field is set 0xffffffffffffffff because we cannot associate to any particular flow */ - action_set_execute(p->action_set, p, 0xffffffffffffffff); - packet_destroy(p); + action_set_execute(pkt->action_set, pkt, 0xffffffffffffffff); } else { VLOG_DBG_RL(LOG_MODULE, &rl, "No bucket in group."); + packet_destroy(pkt); } } @@ -217,7 +208,6 @@ execute_indirect(struct group_entry *entry, struct packet *pkt) { if (entry->desc->buckets_num > 0) { struct ofl_bucket *bucket = entry->desc->buckets[0]; - struct packet *p = packet_clone(pkt); if (VLOG_IS_DBG_ENABLED(LOG_MODULE)) { char *b = ofl_structs_bucket_to_string(bucket, entry->dp->exp); @@ -225,19 +215,19 @@ execute_indirect(struct group_entry *entry, struct packet *pkt) { free(b); } - action_set_write_actions(p->action_set, bucket->actions_num, bucket->actions); + action_set_write_actions(pkt->action_set, bucket->actions_num, bucket->actions); - entry->stats->byte_count += p->buffer->size; + entry->stats->byte_count += pkt->buffer->size; entry->stats->packet_count++; - entry->stats->counters[0]->byte_count += p->buffer->size; + entry->stats->counters[0]->byte_count += pkt->buffer->size; entry->stats->counters[0]->packet_count++; /* Cookie field is set 0xffffffffffffffff because we cannot associate to any particular flow */ - action_set_execute(p->action_set, p, 0xffffffffffffffff); - packet_destroy(p); + action_set_execute(pkt->action_set, pkt, 0xffffffffffffffff); } else { VLOG_DBG_RL(LOG_MODULE, &rl, "No bucket in group."); + packet_destroy(pkt); } } @@ -248,7 +238,6 @@ execute_ff(struct group_entry *entry, struct packet *pkt) { if (b != -1) { struct ofl_bucket *bucket = entry->desc->buckets[b]; - struct packet *p = packet_clone(pkt); if (VLOG_IS_DBG_ENABLED(LOG_MODULE)) { char *b = ofl_structs_bucket_to_string(bucket, entry->dp->exp); @@ -256,19 +245,19 @@ execute_ff(struct group_entry *entry, struct packet *pkt) { free(b); } - action_set_write_actions(p->action_set, bucket->actions_num, bucket->actions); + action_set_write_actions(pkt->action_set, bucket->actions_num, bucket->actions); - entry->stats->byte_count += p->buffer->size; + entry->stats->byte_count += pkt->buffer->size; entry->stats->packet_count++; - entry->stats->counters[b]->byte_count += p->buffer->size; + entry->stats->counters[b]->byte_count += pkt->buffer->size; entry->stats->counters[b]->packet_count++; /* Cookie field is set 0xffffffffffffffff because we cannot associate to any particular flow */ - action_set_execute(p->action_set, p, 0xffffffffffffffff); - packet_destroy(p); + action_set_execute(pkt->action_set, pkt, 0xffffffffffffffff); } else { VLOG_DBG_RL(LOG_MODULE, &rl, "No bucket in group."); + packet_destroy(pkt); } } @@ -280,9 +269,18 @@ group_entry_execute(struct group_entry *entry, VLOG_DBG_RL(LOG_MODULE, &rl, "Executing group %u.", entry->stats->group_id); - /* NOTE: Packet is copied for all buckets now (even if there is only one). - * This allows execution of the original packet onward. It is not clear - * whether that is allowed or not according to the spec. though. */ + /* Group action are often used in the action-set. Action-set + * processing is terminal, so the original packet is passed to us + * for processing. In that case, the caller must clear the + * action-set of the packet. See action_set_execute(). + * Spec v1.1 and later also say that a group action can occur in + * action-list, in that case it must process a clone/copy of the + * packet and execution continue on the original packet. In that + * case, the caller must do the appropriate cloning of the packet. + * See dp_execute_action_list(). + * In any case, we won't return the packet to the caller, we will + * destroy it or pass it to someone. + * Jean II */ switch (entry->desc->type) { case (OFPGT_ALL): { @@ -303,6 +301,7 @@ group_entry_execute(struct group_entry *entry, } default: { VLOG_WARN_RL(LOG_MODULE, &rl, "Trying to execute unknown group type (%u) in group (%u).", entry->desc->type, entry->stats->group_id); + packet_destroy(packet); } } } @@ -310,7 +309,7 @@ group_entry_execute(struct group_entry *entry, void group_entry_update(struct group_entry *entry){ entry->stats->duration_sec = (time_msec() - entry->created) / 1000; - entry->stats->duration_nsec = ((time_msec() - entry->created) % 1000) * 1000; + entry->stats->duration_nsec = ((time_msec() - entry->created) % 1000) * 1000000; } /* Returns true if the group entry has reference to the flow entry. */ diff --git a/udatapath/group_table.h b/udatapath/group_table.h index 2289ab45..4ef564f8 100644 --- a/udatapath/group_table.h +++ b/udatapath/group_table.h @@ -44,7 +44,7 @@ ****************************************************************************/ -#define GROUP_TABLE_MAX_ENTRIES 1024 +#define GROUP_TABLE_MAX_ENTRIES 4096 #define GROUP_TABLE_MAX_BUCKETS 8192 struct datapath; diff --git a/udatapath/match_std.c b/udatapath/match_std.c index 54226293..d9d1f8ad 100644 --- a/udatapath/match_std.c +++ b/udatapath/match_std.c @@ -35,6 +35,10 @@ #include "oflib/oxm-match.h" #include "match_std.h" + +#include "vlog.h" +#define LOG_MODULE VLM_flow_e + /* Returns true if two 8 bit values match */ static inline bool match_8(uint8_t *a, uint8_t *b) { @@ -44,7 +48,7 @@ match_8(uint8_t *a, uint8_t *b) { /* Returns true if two masked 8 bit values match */ static inline bool match_mask8(uint8_t *a, uint8_t *am, uint8_t *b) { - return ((~(am[0]) & (a[0] ^ b[0])) == 0); + return (((am[0]) & (a[0] ^ b[0])) == 0); } /* Returns true if two 16 bit values match */ @@ -61,8 +65,21 @@ match_mask16(uint8_t *a, uint8_t *am, uint8_t *b) { uint16_t *a1 = (uint16_t *) a; uint16_t *b1 = (uint16_t *) b; uint16_t *mask = (uint16_t *) am; + return (((*mask) & (*a1 ^ *b1)) == 0); +} - return (((~*mask) & (*a1 ^ *b1)) == 0); +/* Returns true if two 24 bit values match */ +static inline bool +match_24(uint8_t *a, uint8_t *b) { + return (match_16(a, b) && + match_8(a+2, b+2)); +} + +/* Returns true if two masked 24 bit values match */ +static inline bool +match_mask24(uint8_t *a, uint8_t *am, uint8_t *b) { + return (match_mask16(a, am, b) && + match_mask8(a+2, am+2, b+2)); } /* Returns true if two 32 bit values match */ @@ -70,7 +87,6 @@ static inline bool match_32(uint8_t *a, uint8_t *b) { uint32_t *a1 = (uint32_t *) a; uint32_t *b1 = (uint32_t *) b; - return (*a1 == *b1); } @@ -80,8 +96,7 @@ match_mask32(uint8_t *a, uint8_t *am, uint8_t *b) { uint32_t *a1 = (uint32_t *) a; uint32_t *b1 = (uint32_t *) b; uint32_t *mask = (uint32_t *) am; - - return (((~*mask) & (*a1 ^ *b1)) == 0); + return (((*mask) & (*a1 ^ *b1)) == 0); } /* Returns true if two 48 bit values match */ @@ -103,7 +118,6 @@ static inline bool match_64(uint8_t *a, uint8_t *b) { uint64_t *a1 = (uint64_t *) a; uint64_t *b1 = (uint64_t *) b; - return (*a1 == *b1); } @@ -113,8 +127,7 @@ match_mask64(uint8_t *a, uint8_t *am, uint8_t *b) { uint64_t *a1 = (uint64_t *) a; uint64_t *b1 = (uint64_t *) b; uint64_t *mask = (uint64_t *) am; - - return (((~*mask) & (*a1 ^ *b1)) == 0); + return (((*mask) & (*a1 ^ *b1)) == 0); } /* Returns true if two 128 bit values match */ @@ -163,10 +176,6 @@ packet_match(struct ofl_match *flow_match, struct ofl_match *packet){ packet_header |= field_len; flow_mask = f->value + field_len; } - - char *f_str = ofl_structs_oxm_tlv_to_string(f); - free(f_str); - /* Lookup the packet header */ packet_f = oxm_match_lookup(packet_header, packet); if (!packet_f) { @@ -195,17 +204,25 @@ packet_match(struct ofl_match *flow_match, struct ofl_match *packet){ switch (packet_header) { case OXM_OF_VLAN_VID: { /* Special handling for VLAN ID */ - uint16_t *flow_vlan_id = (uint16_t*) flow_val; - if (*flow_vlan_id == OFPVID_NONE) { + uint16_t flow_vlan_id = *((uint16_t*) flow_val); + if (flow_vlan_id == OFPVID_NONE) { /* Packet has a VLAN tag when none should be there */ return false; - } else if (*flow_vlan_id == OFPVID_PRESENT) { + } else if (flow_vlan_id == OFPVID_PRESENT) { /* Any VLAN ID is acceptable. No further checks */ } else { /* Check the VLAN ID */ - *flow_vlan_id &= VLAN_VID_MASK; - if (!match_16(flow_val, packet_val)) - return false; + flow_vlan_id &= VLAN_VID_MASK; + if (has_mask){ + if (!match_mask16((uint8_t*) &flow_vlan_id, flow_mask, packet_val)){ + return false; + } + } + else { + if (!match_16((uint8_t*) &flow_vlan_id, packet_val)){ + return false; + } + } } break; } @@ -231,6 +248,16 @@ packet_match(struct ofl_match *flow_match, struct ofl_match *packet){ break; } break; + case 3: + if (has_mask) { + if (!match_mask24(flow_val, flow_mask, packet_val)) + return false; + } + else { + if (!match_24(flow_val, packet_val)) + return false; + } + break; case 4: if (has_mask) { if (!match_mask32(flow_val, flow_mask, packet_val)) @@ -283,7 +310,7 @@ packet_match(struct ofl_match *flow_match, struct ofl_match *packet){ static inline bool strict_mask8(uint8_t *a, uint8_t *b, uint8_t *am, uint8_t *bm) { - return ((am[0] == bm[0]) && ((a[0] ^ b[0]) & ~am[0])) == 0; + return ((am[0] == bm[0]) && ((a[0] ^ b[0]) & am[0])) == 0; } static inline bool @@ -292,7 +319,13 @@ strict_mask16(uint8_t *a, uint8_t *b, uint8_t *am, uint8_t *bm) { uint16_t *b1 = (uint16_t *) b; uint16_t *mask_a = (uint16_t *) am; uint16_t *mask_b = (uint16_t *) bm; - return ((*mask_a == *mask_b) && ((*a1 ^ *b1) & ~(*mask_a))) == 0; + return ((*mask_a == *mask_b) && ((*a1 ^ *b1) & (*mask_a))) == 0; +} + +static inline bool +strict_mask24(uint8_t *a, uint8_t *b, uint8_t *am, uint8_t *bm) { + return strict_mask16(a, b, am, bm) && + strict_mask8(a+2, b+2, am+2, bm+2); } static inline bool @@ -301,7 +334,16 @@ strict_mask32(uint8_t *a, uint8_t *b, uint8_t *am, uint8_t *bm) { uint32_t *b1 = (uint32_t *) b; uint32_t *mask_a = (uint32_t *) am; uint32_t *mask_b = (uint32_t *) bm; - return ((*mask_a == *mask_b) && ((*a1 ^ *b1) & ~(*mask_a))) == 0; + return ((*mask_a == *mask_b) && ((*a1 ^ *b1) & (*mask_a))) == 0; +} + +static inline bool +strict_mask_ip(uint8_t *a, uint8_t *b, uint8_t *am, uint8_t *bm) { + uint32_t *a1 = (uint32_t *) a; + uint32_t *b1 = (uint32_t *) b; + uint32_t *mask_a = (uint32_t *) am; + uint32_t *mask_b = (uint32_t *) bm; + return ((*mask_a == *mask_b) && ((*a1 ^ *b1) & (*mask_a))) == 0; } static inline bool @@ -316,7 +358,7 @@ strict_mask64(uint8_t *a, uint8_t *b, uint8_t *am, uint8_t *bm) { uint64_t *b1 = (uint64_t *) b; uint64_t *mask_a = (uint64_t *) am; uint64_t *mask_b = (uint64_t *) bm; - return ((*mask_a == *mask_b) && ((*a1 ^ *b1) & ~(*mask_a))) == 0; + return ((*mask_a == *mask_b) && ((*a1 ^ *b1) & (*mask_a))) == 0; } static inline bool @@ -341,6 +383,7 @@ match_std_strict(struct ofl_match *a, struct ofl_match *b) { int field_len; uint8_t *flow_mod_val, *flow_mod_mask=0; uint8_t *flow_entry_val, *flow_entry_mask=0; + uint8_t oxm_field; bool has_mask; /* Both matches all wildcarded */ @@ -361,6 +404,7 @@ match_std_strict(struct ofl_match *a, struct ofl_match *b) { } /* At this point match length and has_mask are equal */ + oxm_field = OXM_FIELD(flow_mod_match->header); has_mask = OXM_HASMASK(flow_mod_match->header); field_len = OXM_LENGTH(flow_mod_match->header); flow_mod_val = flow_mod_match->value; @@ -374,62 +418,96 @@ match_std_strict(struct ofl_match *a, struct ofl_match *b) { switch (field_len) { case 1: if (has_mask) { - if (!strict_mask8(flow_mod_val, flow_entry_val, flow_mod_mask, flow_entry_mask)) + if (!strict_mask8(flow_mod_val, flow_entry_val, flow_mod_mask, flow_entry_mask)){ return false; + } } else { - if (!match_8(flow_mod_val, flow_entry_val)) + if (!match_8(flow_mod_val, flow_entry_val)){ return false; + } } break; case 2: if (has_mask) { - if (!strict_mask16(flow_mod_val, flow_entry_val, flow_mod_mask, flow_entry_mask)) + if (!strict_mask16(flow_mod_val, flow_entry_val, flow_mod_mask, flow_entry_mask)){ return false; + } } else { - if (!match_16(flow_mod_val, flow_entry_val)) + if (!match_16(flow_mod_val, flow_entry_val)){ return false; + } + } + break; + case 3: + if (has_mask) { + if (!strict_mask24(flow_mod_val, flow_entry_val, flow_mod_mask, flow_entry_mask)) + return false; + } + else { + if (!match_24(flow_mod_val, flow_entry_val)){ + return false; + } } break; case 4: if (has_mask) { - if (!strict_mask32(flow_mod_val, flow_entry_val, flow_mod_mask, flow_entry_mask)) + /* Quick and dirty fix for IP addresses matching + TODO: Matching needs a huge refactoring */ + if (oxm_field == OFPXMT_OFB_IPV4_SRC || + oxm_field == OFPXMT_OFB_IPV4_DST || + oxm_field == OFPXMT_OFB_ARP_SPA || + oxm_field == OFPXMT_OFB_ARP_TPA) { + if (!strict_mask_ip(flow_mod_val, flow_entry_val, flow_mod_mask, flow_entry_mask)){ + return false; + } + } + if (!strict_mask32(flow_mod_val, flow_entry_val, flow_mod_mask, flow_entry_mask)){ return false; + } } else { - if (!match_32(flow_mod_val, flow_entry_val)) + + if (!match_32(flow_mod_val, flow_entry_val)){ return false; + } } break; case 6: if (has_mask) { - if (!strict_mask48(flow_mod_val, flow_entry_val, flow_mod_mask, flow_entry_mask)) + if (!strict_mask48(flow_mod_val, flow_entry_val, flow_mod_mask, flow_entry_mask)){ return false; + } } else { - if (!match_48(flow_mod_val, flow_entry_val)) + if (!match_48(flow_mod_val, flow_entry_val)){ return false; + } } break; case 8: if (has_mask) { - if (!strict_mask64(flow_mod_val, flow_entry_val, flow_mod_mask, flow_entry_mask)) + if (!strict_mask64(flow_mod_val, flow_entry_val, flow_mod_mask, flow_entry_mask)){ return false; + } } else { - if (!match_64(flow_mod_val, flow_entry_val)) + if (!match_64(flow_mod_val, flow_entry_val)){ return false; + } } break; case 16: if (has_mask) { - if (!strict_mask128(flow_mod_val, flow_entry_val, flow_mod_mask, flow_entry_mask)) + if (!strict_mask128(flow_mod_val, flow_entry_val, flow_mod_mask, flow_entry_mask)){ return false; + } } else { - if (!match_128(flow_mod_val, flow_entry_val)) + if (!match_128(flow_mod_val, flow_entry_val)){ return false; + } } break; default: @@ -460,6 +538,12 @@ nonstrict_mask16(uint8_t *a, uint8_t *b, uint8_t *am, uint8_t *bm) { return (~(*mask_a) & (~(*a1) | ~(*b1) | *mask_b) & (*a1| *b1 | *mask_b)) == 0; } +static inline bool +nonstrict_mask24(uint8_t *a, uint8_t *b, uint8_t *am, uint8_t *bm) { + return nonstrict_mask16(a, b, am, bm) && + nonstrict_mask8(a+2, b+2, am+2, bm+2); +} + static inline bool nonstrict_mask32(uint8_t *a, uint8_t *b, uint8_t *am, uint8_t *bm) { uint32_t *a1 = (uint32_t *) a; @@ -554,6 +638,16 @@ match_std_nonstrict(struct ofl_match *a, struct ofl_match *b) return false; } break; + case 3: + if (has_mask) { + if (!nonstrict_mask24(flow_mod_val, flow_entry_val, flow_mod_mask, flow_entry_mask)) + return false; + } + else { + if (!match_24(flow_mod_val, flow_entry_val)) + return false; + } + break; case 4: if (has_mask) { if (!nonstrict_mask32(flow_mod_val, flow_entry_val, flow_mod_mask, flow_entry_mask)) @@ -613,7 +707,7 @@ match_std_nonstrict(struct ofl_match *a, struct ofl_match *b) static inline bool incompatible_8(uint8_t *a, uint8_t *b, uint8_t *am, uint8_t *bm) { - return (( ~(*am|*bm) & (*a^*b) ) != 0); + return (( (*am&*a) ^ (*bm&*b) ) != 0); } static inline bool @@ -623,7 +717,7 @@ incompatible_16(uint8_t *a, uint8_t *b, uint8_t *am, uint8_t *bm) { uint16_t *mask_a = (uint16_t *) am; uint16_t *mask_b = (uint16_t *) bm; - return (( ~(*mask_a|*mask_b) & (*a1^*b1) ) != 0); + return (( (*mask_a&*a1) ^ (*mask_b&*b1) ) != 0); } static inline bool @@ -633,7 +727,7 @@ incompatible_32(uint8_t *a, uint8_t *b, uint8_t *am, uint8_t *bm) { uint32_t *mask_a = (uint32_t *) am; uint32_t *mask_b = (uint32_t *) bm; - return (( ~(*mask_a|*mask_b) & (*a1^*b1) ) != 0); + return (( (*mask_a&*a1)^(*mask_b&*b1) ) != 0); } static inline bool @@ -649,7 +743,7 @@ incompatible_64(uint8_t *a, uint8_t *b, uint8_t *am, uint8_t *bm) { uint64_t *mask_a = (uint64_t *) am; uint64_t *mask_b = (uint64_t *) bm; - return (( ~(*mask_a|*mask_b) & (*a1^*b1) ) != 0); + return (( (*mask_a&*a1) ^ (*mask_b&*b1) ) != 0); } static inline bool @@ -667,7 +761,8 @@ incompatible_128(uint8_t *a, uint8_t *b, uint8_t *am, uint8_t *bm) { bool match_std_overlap(struct ofl_match *a, struct ofl_match *b) { - uint64_t all_mask[2] = {0, 0}; + uint64_t all_mask[2] = {~0L, ~0L}; + struct ofl_match_tlv *f_a; struct ofl_match_tlv *f_b; int header, header_m; diff --git a/udatapath/meter_entry.c b/udatapath/meter_entry.c index 2bea3739..6da82b55 100644 --- a/udatapath/meter_entry.c +++ b/udatapath/meter_entry.c @@ -30,6 +30,7 @@ */ #include +#include "csum.h" #include "flow_entry.h" #include "meter_entry.h" #include "meter_table.h" @@ -141,7 +142,7 @@ meter_entry_create(struct datapath *dp, struct meter_table *table, struct ofl_ms void meter_entry_update(struct meter_entry *entry) { entry->stats->duration_sec = (time_msec() - entry->created) / 1000; - entry->stats->duration_nsec = ((time_msec() - entry->created) % 1000) * 1000; + entry->stats->duration_nsec = ((time_msec() - entry->created) % 1000) * 1000000; } void @@ -166,7 +167,7 @@ static bool consume_tokens(struct ofl_meter_band_stats *band, uint16_t meter_flag, struct packet *pkt){ if(meter_flag & OFPMF_KBPS){ - uint32_t pkt_size = (pkt->buffer->size*8)/1024; + uint32_t pkt_size = pkt->buffer->size * 8; if (band->tokens >= pkt_size) { band->tokens -= pkt_size; return true; @@ -195,7 +196,6 @@ choose_band(struct meter_entry *entry, struct packet *pkt) for(i = 0; i < entry->stats->meter_bands_num; i++) { struct ofl_meter_band_header *band_header = entry->config->bands[i]; - if(!consume_tokens(entry->stats->band_stats[i], entry->config->flags, pkt) && band_header->rate > tmp_rate) { tmp_rate = band_header->rate; @@ -205,8 +205,7 @@ choose_band(struct meter_entry *entry, struct packet *pkt) return band_index; } -/// type - conversion -// Not handle burst size + void meter_entry_apply(struct meter_entry *entry, struct packet **pkt){ @@ -218,35 +217,66 @@ meter_entry_apply(struct meter_entry *entry, struct packet **pkt){ b = choose_band(entry, *pkt); if(b != -1){ - struct ofl_meter_band_header *band_header = (struct ofl_meter_band_header*) entry->config->bands[b]; - switch(band_header->type){ - case OFPMBT_DROP:{ + struct ofl_meter_band_header *band_header = (struct ofl_meter_band_header*) entry->config->bands[b]; + switch(band_header->type){ + case OFPMBT_DROP:{ drop = true; - break; - } - case OFPMBT_DSCP_REMARK:{ - struct ofl_meter_band_dscp_remark *band_header = (struct ofl_meter_band_dscp_remark *) entry->config->bands[b]; - // descrease dscp in ipv4 header - uint8_t new_dscp = ((*pkt)->handle_std->proto->ipv4->ip_tos >> 5) - band_header->prec_level; - (*pkt)->handle_std->proto->ipv4->ip_tos = (new_dscp << 5) | ((*pkt)->handle_std->proto->ipv4->ip_tos & 0x1f); - break; - } - case OFPMBT_EXPERIMENTER:{ - break; - } + break; + } + case OFPMBT_DSCP_REMARK:{ + packet_handle_std_validate((*pkt)->handle_std); + if ((*pkt)->handle_std->valid) + { + struct ofl_meter_band_dscp_remark *band_header = (struct ofl_meter_band_dscp_remark *) entry->config->bands[b]; + /* Nothing prevent this band to be used for non-IP packets, so filter them out. Jean II */ + if ((*pkt)->handle_std->proto->ipv4 != NULL) { + // Fetch dscp in ipv4 header + struct ip_header *ipv4 = (*pkt)->handle_std->proto->ipv4; + uint8_t old_drop = ipv4->ip_tos & 0x1C; + /* The spec says that we need to increase + the drop precedence of the packet. + We need a valid DSCP out of the process, + so we can only modify dscp if the + drop precedence is low (tos 0x***010**) + or medium (tos 0x***100**). Jean II */ + if (((old_drop == 0x8) && (band_header->prec_level <= 2)) || ((old_drop == 0x10) && (band_header->prec_level <= 1))) { + uint8_t new_drop = old_drop + (band_header->prec_level << 3); + uint8_t new_tos = new_drop | (ipv4->ip_tos & 0xE3); + uint16_t old_val = htons((ipv4->ip_ihl_ver << 8) + ipv4->ip_tos); + uint16_t new_val = htons((ipv4->ip_ihl_ver << 8) + new_tos); + ipv4->ip_csum = recalc_csum16(ipv4->ip_csum, old_val, new_val); + ipv4->ip_tos = new_tos; + } + } + else if ((*pkt)->handle_std->proto->ipv6 != NULL){ + struct ipv6_header *ipv6 = (*pkt)->handle_std->proto->ipv6; + uint32_t ipv6_ver_tc_fl = ntohl(ipv6->ipv6_ver_tc_fl); + uint32_t old_drop = ipv6_ver_tc_fl & 0x1C00000; + if (((old_drop == 0x800000) && (band_header->prec_level <= 2)) || ((old_drop == 0x1000000) && (band_header->prec_level <= 1))){ + uint32_t prec_level = band_header->prec_level << 23; + uint32_t new_drop = old_drop + prec_level; + ipv6->ipv6_ver_tc_fl = htonl(new_drop | (ipv6_ver_tc_fl & 0xFE3FFFFF)); + } + } + (*pkt)->handle_std->valid = false; } - entry->stats->band_stats[b]->byte_band_count += (*pkt)->buffer->size; - entry->stats->band_stats[b]->packet_band_count++; + break; + } + case OFPMBT_EXPERIMENTER:{ + break; + } + } + entry->stats->band_stats[b]->byte_band_count += (*pkt)->buffer->size; + entry->stats->band_stats[b]->packet_band_count++; if (drop){ - VLOG_ERR_RL(LOG_MODULE, &rl, "Dropping packet: rate %d", band_header->rate); - packet_destroy(*pkt); - *pkt = NULL; + VLOG_DBG_RL(LOG_MODULE, &rl, "Dropping packet: rate %d", band_header->rate); + packet_destroy(*pkt); + *pkt = NULL; } - } + } } - /* Returns true if the meter entry has reference to the flow entry. */ static bool has_flow_ref(struct meter_entry *entry, struct flow_entry *fe) { @@ -288,38 +318,35 @@ meter_entry_del_flow_ref(struct meter_entry *entry, struct flow_entry *fe) { void refill_bucket(struct meter_entry *entry) { - size_t i; + long long int now = time_msec(); + size_t i; for(i = 0; i < entry->config->meter_bands_num; i++) { - long long int now = time_msec(); - long long int tokens = !(entry->config->flags & OFPMF_PKTPS) ? - (now - entry->stats->band_stats[i]->last_fill) * - entry->config->bands[i]->rate + entry->stats->band_stats[i]->tokens - : (now - entry->stats->band_stats[i]->last_fill) * - (entry->config->bands[i]->rate * 1000) + entry->stats->band_stats[i]->tokens; - + uint32_t rate; + uint32_t burst_size; + uint64_t tokens; + long long int elapsed_msec = now - entry->stats->band_stats[i]->last_fill; + rate = entry->config->bands[i]->rate * 1000; + burst_size = entry->config->bands[i]->burst_size * 1000; + tokens = ((rate * elapsed_msec) / 1000) + entry->stats->band_stats[i]->tokens; + entry->stats->band_stats[i]->last_fill = now; if (!(entry->config->flags & OFPMF_BURST)){ if(entry->config->flags & OFPMF_KBPS && tokens >= 1){ - entry->stats->band_stats[i]->tokens = MIN(tokens, entry->config->bands[i]->rate); - entry->stats->band_stats[i]->last_fill = now; - + entry->stats->band_stats[i]->tokens = MIN(tokens, rate); } else{ if(tokens >= 1000) { - entry->stats->band_stats[i]->tokens = MIN(tokens, entry->config->bands[i]->rate * 1000); - entry->stats->band_stats[i]->last_fill = now; - + entry->stats->band_stats[i]->tokens = MIN(tokens, rate); } } } else { - if(entry->config->flags & OFPMF_KBPS && tokens >= 1 ) { - entry->stats->band_stats[i]->tokens = MIN(tokens, entry->config->bands[i]->burst_size); - + if(entry->config->flags & OFPMF_KBPS && tokens >= 1 ){ + entry->stats->band_stats[i]->tokens = MIN(tokens,burst_size); } else { if(tokens >= 1000) { - entry->stats->band_stats[i]->tokens = MIN(tokens, entry->config->bands[i]->burst_size * 1000); + entry->stats->band_stats[i]->tokens = MIN(tokens,burst_size); } } } diff --git a/udatapath/meter_table.c b/udatapath/meter_table.c index b2e7a12f..10efa2fb 100644 --- a/udatapath/meter_table.c +++ b/udatapath/meter_table.c @@ -163,6 +163,12 @@ meter_table_modify(struct meter_table *table, struct ofl_msg_meter_mod *mod) { list_replace(&new_entry->flow_refs, &entry->flow_refs); list_init(&entry->flow_refs); + new_entry->stats->flow_count = entry->stats->flow_count; + new_entry->stats->packet_in_count = entry->stats->packet_in_count; + new_entry->stats->byte_in_count = entry->stats->byte_in_count; + new_entry->stats->duration_sec = entry->stats->duration_sec; + new_entry->stats->duration_nsec = entry->stats->duration_nsec; + meter_entry_destroy(entry); ofl_msg_free_meter_mod(mod, false); return 0; @@ -277,7 +283,7 @@ meter_table_handle_stats_request_meter_conf(struct meter_table *table, struct ofl_msg_multipart_meter_request *msg UNUSED, const struct sender *sender) { struct meter_entry *entry; - + struct ofl_msg_multipart_reply_meter_conf reply; if (msg->meter_id == OFPM_ALL) { entry = NULL; } else { @@ -288,13 +294,13 @@ meter_table_handle_stats_request_meter_conf(struct meter_table *table, } } - struct ofl_msg_multipart_reply_meter_conf reply = - {{{.type = OFPT_MULTIPART_REPLY}, - .type = OFPMP_METER_CONFIG, .flags = 0x0000}, - .stats_num = table->entries_num, - .stats = xmalloc(sizeof(struct ofl_meter_config *) * (msg->meter_id == OFPM_ALL ? table->entries_num : 1)) - }; - + reply.header.header.type = OFPT_MULTIPART_REPLY; + reply.header.type = OFPMP_METER_CONFIG; + reply.header.flags = 0x0000; + reply.stats_num = table->entries_num; + reply.stats = xmalloc(sizeof(struct ofl_meter_config *) * + (msg->meter_id == OFPM_ALL ? table->entries_num : 1)); + if (msg->meter_id == OFPM_ALL) { struct meter_entry *e; size_t i = 0; diff --git a/udatapath/packet.c b/udatapath/packet.c index 0ab614a9..5911f342 100644 --- a/udatapath/packet.c +++ b/udatapath/packet.c @@ -75,7 +75,12 @@ packet_clone(struct packet *pkt) { clone->dp = pkt->dp; clone->buffer = ofpbuf_clone(pkt->buffer); clone->in_port = pkt->in_port; - clone->action_set = action_set_clone(pkt->action_set); + /* There is no case we need to keep the action-set, but if it's needed + * we could add a parameter to the function... Jean II + * clone->action_set = action_set_clone(pkt->action_set); + */ + clone->action_set = action_set_create(pkt->dp->exp); + clone->packet_out = pkt->packet_out; clone->out_group = OFPG_ANY; diff --git a/udatapath/packet_handle_std.c b/udatapath/packet_handle_std.c index 1a75df3e..21a7c3e2 100644 --- a/udatapath/packet_handle_std.c +++ b/udatapath/packet_handle_std.c @@ -49,10 +49,22 @@ void packet_handle_std_validate(struct packet_handle_std *handle) { - + struct ofl_match_tlv * iter, *next, *f; + uint64_t metadata = 0; + uint64_t tunnel_id = 0; if(handle->valid) return; - struct ofl_match_tlv * iter, *next; + + HMAP_FOR_EACH_WITH_HASH(f, struct ofl_match_tlv, + hmap_node, hash_int(OXM_OF_METADATA,0), &handle->match.match_fields){ + metadata = *((uint64_t*) f->value); + } + + HMAP_FOR_EACH_WITH_HASH(f, struct ofl_match_tlv, + hmap_node, hash_int(OXM_OF_TUNNEL_ID,0), &handle->match.match_fields){ + tunnel_id = *((uint64_t*) f->value); + } + HMAP_FOR_EACH_SAFE(iter, next, struct ofl_match_tlv, hmap_node, &handle->match.match_fields){ free(iter->value); free(iter); @@ -67,8 +79,9 @@ packet_handle_std_validate(struct packet_handle_std *handle) { /* Add in_port value to the hash_map */ ofl_structs_match_put32(&handle->match, OXM_OF_IN_PORT, handle->pkt->in_port); - /*Add metadata value to the hash_map */ - ofl_structs_match_put64(&handle->match, OXM_OF_METADATA, 0xffffffffffffffff); + /*Add metadata and tunnel_id value to the hash_map */ + ofl_structs_match_put64(&handle->match, OXM_OF_METADATA, metadata); + ofl_structs_match_put64(&handle->match, OXM_OF_TUNNEL_ID, tunnel_id); return; } diff --git a/udatapath/pipeline.c b/udatapath/pipeline.c index 8327c844..ba4cc551 100644 --- a/udatapath/pipeline.c +++ b/udatapath/pipeline.c @@ -46,7 +46,6 @@ #include "meter_table.h" #include "oflib/ofl.h" #include "oflib/ofl-structs.h" -#include "nbee_link/nbee_link.h" #include "util.h" #include "hash.h" #include "oflib/oxm-match.h" @@ -65,23 +64,18 @@ struct pipeline * pipeline_create(struct datapath *dp) { struct pipeline *pl; int i; - pl = xmalloc(sizeof(struct pipeline)); for (i=0; itables[i] = flow_table_create(dp, i); } pl->dp = dp; - nblink_initialize(); - return pl; } static bool is_table_miss(struct flow_entry *entry){ - return ((entry->stats->priority) == 0 && (entry->match->length <= 4)); - } /* Sends a packet to the controller in a packet_in message */ @@ -115,9 +109,10 @@ send_packet_to_controller(struct pipeline *pl, struct packet *pkt, uint8_t table ports */ msg.match = (struct ofl_match_header*)m; dp_send_message(pl->dp, (struct ofl_msg_header *)&msg, NULL); - ofl_structs_free_match((struct ofl_match_header* ) m, NULL); } +/* Pass the packet through the flow tables. + * This function takes ownership of the packet and will destroy it. */ void pipeline_process_packet(struct pipeline *pl, struct packet *pkt) { struct flow_table *table, *next_table; @@ -129,13 +124,7 @@ pipeline_process_packet(struct pipeline *pl, struct packet *pkt) { } if (!packet_handle_std_is_ttl_valid(pkt->handle_std)) { - if ((pl->dp->config.flags & OFPC_INVALID_TTL_TO_CONTROLLER) != 0) { - VLOG_DBG_RL(LOG_MODULE, &rl, "Packet has invalid TTL, sending to controller."); - - send_packet_to_controller(pl, pkt, 0/*table_id*/, OFPR_INVALID_TTL); - } else { - VLOG_DBG_RL(LOG_MODULE, &rl, "Packet has invalid TTL, dropping."); - } + send_packet_to_controller(pl, pkt, 0/*table_id*/, OFPR_INVALID_TTL); packet_destroy(pkt); return; } @@ -174,7 +163,6 @@ pipeline_process_packet(struct pipeline *pl, struct packet *pkt) { because we cannot associate it to any particular flow */ action_set_execute(pkt->action_set, pkt, 0xffffffffffffffff); - packet_destroy(pkt); return; } @@ -234,6 +222,10 @@ pipeline_handle_flow_mod(struct pipeline *pl, struct ofl_msg_flow_mod *msg, return error; } } + /* Reject goto in the last table. */ + if ((msg->table_id == (PIPELINE_TABLES - 1)) + && (msg->instructions[i]->type == OFPIT_GOTO_TABLE)) + return ofl_error(OFPET_BAD_INSTRUCTION, OFPBIC_UNSUP_INST); } if (msg->table_id == 0xff) { @@ -368,39 +360,173 @@ ofl_err pipeline_handle_stats_request_table_features_request(struct pipeline *pl, struct ofl_msg_multipart_request_header *msg, const struct sender *sender) { - size_t i, j; struct ofl_table_features **features; struct ofl_msg_multipart_request_table_features *feat = (struct ofl_msg_multipart_request_table_features *) msg; + int i; /* Feature index in feature array. Jean II */ + int table_id; + ofl_err error = 0; + + /* Further validation of request not done in + * ofl_structs_table_features_unpack(). Jean II */ + if(feat->table_features != NULL) { + for(i = 0; i < feat->tables_num; i++){ + if(feat->table_features[i]->table_id >= PIPELINE_TABLES) + return ofl_error(OFPET_TABLE_FEATURES_FAILED, OFPTFFC_BAD_TABLE); + /* We may want to validate things like config, max_entries, + * metadata... */ + } + } + + /* Check if we already received fragments of a multipart request. */ + if(sender->remote->mp_req_msg != NULL) { + bool nomore; + + /* We can only merge requests having the same XID. */ + if(sender->xid != sender->remote->mp_req_xid) + { + VLOG_ERR(LOG_MODULE, "multipart request: wrong xid (0x%X != 0x%X)", sender->xid, sender->remote->mp_req_xid); + + /* Technically, as our buffer can only hold one pending request, + * this is a buffer overflow ! Jean II */ + /* Return error. */ + return ofl_error(OFPET_BAD_REQUEST, OFPBRC_MULTIPART_BUFFER_OVERFLOW); + } + + VLOG_DBG(LOG_MODULE, "multipart request: merging with previous fragments (%zu+%zu)", ((struct ofl_msg_multipart_request_table_features *) sender->remote->mp_req_msg)->tables_num, feat->tables_num); + + /* Merge the request with previous fragments. */ + nomore = ofl_msg_merge_multipart_request_table_features((struct ofl_msg_multipart_request_table_features *) sender->remote->mp_req_msg, feat); + + /* Check if incomplete. */ + if(!nomore) + return 0; - /*Check to see if the body is empty*/ + VLOG_DBG(LOG_MODULE, "multipart request: reassembly complete (%zu)", ((struct ofl_msg_multipart_request_table_features *) sender->remote->mp_req_msg)->tables_num); + + /* Use the complete request. */ + feat = (struct ofl_msg_multipart_request_table_features *) sender->remote->mp_req_msg; + +#if 0 + { + char *str; + str = ofl_msg_to_string((struct ofl_msg_header *) feat, pl->dp->exp); + VLOG_DBG(LOG_MODULE, "\nMerged request:\n%s\n\n", str); + free(str); + } +#endif + + } else { + /* Check if the request is an initial fragment. */ + if(msg->flags & OFPMPF_REQ_MORE) { + struct ofl_msg_multipart_request_table_features* saved_msg; + + VLOG_DBG(LOG_MODULE, "multipart request: create reassembly buffer (%zu)", feat->tables_num); + + /* Create a buffer the do reassembly. */ + saved_msg = (struct ofl_msg_multipart_request_table_features*) malloc(sizeof(struct ofl_msg_multipart_request_table_features)); + saved_msg->header.header.type = OFPT_MULTIPART_REQUEST; + saved_msg->header.type = OFPMP_TABLE_FEATURES; + saved_msg->header.flags = 0; + saved_msg->tables_num = 0; + saved_msg->table_features = NULL; + + /* Save the fragment for later use. */ + ofl_msg_merge_multipart_request_table_features(saved_msg, feat); + sender->remote->mp_req_msg = (struct ofl_msg_multipart_request_header *) saved_msg; + sender->remote->mp_req_xid = sender->xid; + + return 0; + } + + /* Non fragmented request. Nothing to do... */ + VLOG_DBG(LOG_MODULE, "multipart request: non-fragmented request (%zu)", feat->tables_num); + } + + /*Check to see if the body is empty.*/ + /* Should check merge->tables_num instead. Jean II */ if(feat->table_features != NULL){ - /* Change tables configuration - TODO: Remove flows*/ + int last_table_id = 0; + + /* Check that the table features make sense. */ for(i = 0; i < feat->tables_num; i++){ - pl->tables[feat->table_features[i]->table_id]->features = feat->table_features[i]; + /* Table-IDs must be in ascending order. */ + table_id = feat->table_features[i]->table_id; + if(table_id < last_table_id) { + error = ofl_error(OFPET_TABLE_FEATURES_FAILED, OFPTFFC_BAD_TABLE); + break; + } + /* Can't go over out internal max-entries. */ + if (feat->table_features[i]->max_entries > FLOW_TABLE_MAX_ENTRIES) { + error = ofl_error(OFPET_TABLE_FEATURES_FAILED, OFPTFFC_BAD_ARGUMENT); + break; + } } + + if (error == 0) { + + /* Disable all tables, they will be selectively re-enabled. */ + for(table_id = 0; table_id < PIPELINE_TABLES; table_id++){ + pl->tables[table_id]->disabled = true; + } + /* Change tables configuration + TODO: Remove flows*/ + VLOG_DBG(LOG_MODULE, "pipeline_handle_stats_request_table_features_request: updating features"); + for(i = 0; i < feat->tables_num; i++){ + table_id = feat->table_features[i]->table_id; + + /* Replace whole table feature. */ + ofl_structs_free_table_features(pl->tables[table_id]->features, pl->dp->exp); + pl->tables[table_id]->features = feat->table_features[i]; + feat->table_features[i] = NULL; + + /* Re-enable table. */ + pl->tables[table_id]->disabled = false; + } + } + } + + /* Cleanup request. */ + if(sender->remote->mp_req_msg != NULL) { + ofl_msg_free((struct ofl_msg_header *) sender->remote->mp_req_msg, pl->dp->exp); + sender->remote->mp_req_msg = NULL; + sender->remote->mp_req_xid = 0; /* Currently not needed. Jean II. */ + } + + if (error) { + return error; } - j = 0; + table_id = 0; /* Query for table capabilities */ loop: ; features = (struct ofl_table_features**) xmalloc(sizeof(struct ofl_table_features *) * 8); + /* Return 8 tables per reply segment. */ for (i = 0; i < 8; i++){ - features[i] = pl->tables[j]->features; - j++; + /* Skip disabled tables. */ + while((table_id < PIPELINE_TABLES) && (pl->tables[table_id]->disabled == true)) + table_id++; + /* Stop at the last table. */ + if(table_id >= PIPELINE_TABLES) + break; + /* Use that table in the reply. */ + features[i] = pl->tables[table_id]->features; + table_id++; } + VLOG_DBG(LOG_MODULE, "multipart reply: returning %d tables, next table-id %d", i, table_id); { struct ofl_msg_multipart_reply_table_features reply = - {{{.type = OFPT_MULTIPART_REPLY}, - .type = OFPMP_TABLE_FEATURES, .flags = j == PIPELINE_TABLES? 0x00000000:OFPMPF_REPLY_MORE}, + {{{.type = OFPT_MULTIPART_REPLY}, + .type = OFPMP_TABLE_FEATURES, + .flags = (table_id == PIPELINE_TABLES ? 0x00000000 : OFPMPF_REPLY_MORE) }, .table_features = features, - .tables_num = 8}; + .tables_num = i }; dp_send_message(pl->dp, (struct ofl_msg_header *)&reply, sender); } - if (j < PIPELINE_TABLES){ + if (table_id < PIPELINE_TABLES){ goto loop; } + free(features); return 0; } @@ -504,7 +630,7 @@ execute_entry(struct pipeline *pl, struct flow_entry *entry, hmap_node, hash_int(OXM_OF_METADATA,0), &(*pkt)->handle_std->match.match_fields){ uint64_t *metadata = (uint64_t*) f->value; *metadata = (*metadata & ~wi->metadata_mask) | (wi->metadata & wi->metadata_mask); - VLOG_DBG_RL(LOG_MODULE, &rl, "Executing write metadata: %llx", *metadata); + VLOG_DBG_RL(LOG_MODULE, &rl, "Executing write metadata: 0x%"PRIx64"", *metadata); } break; } diff --git a/udatapath/udatapath.c b/udatapath/udatapath.c index 8484ef89..30577b10 100644 --- a/udatapath/udatapath.c +++ b/udatapath/udatapath.c @@ -130,12 +130,12 @@ udatapath_cmd(int argc, char *argv[]) for (i = optind; i < argc; i += 2) { const char *pvconn_name = argv[i]; const char *pvconn_name_aux = NULL; - if (use_multiple_connections) - pvconn_name_aux = argv[i + 1]; - struct pvconn *pvconn, *pvconn_aux = NULL; int retval, retval_aux; + if (use_multiple_connections) + pvconn_name_aux = argv[i + 1]; + retval = pvconn_open(pvconn_name, &pvconn); if (!retval || retval == EAGAIN) { // Get another listener if we are using auxiliary connections @@ -254,9 +254,9 @@ parse_options(struct datapath *dp, int argc, char *argv[]) if (strlen(optarg) != 12 || strspn(optarg, "0123456789abcdefABCDEF") != 12) { ofp_fatal(0, "argument to -d or --datapath-id must be " - "exactly 12 hex digits"); + "exactly 16 hex digits"); } - dpid = strtoll(optarg, NULL, 16); + dpid = strtoll(optarg, NULL, 12); if (!dpid) { ofp_fatal(0, "argument to -d or --datapath-id must " "be nonzero"); diff --git a/utilities/automake.mk b/utilities/automake.mk index 85592373..c484f712 100644 --- a/utilities/automake.mk +++ b/utilities/automake.mk @@ -4,13 +4,13 @@ bin_PROGRAMS += \ utilities/ofp-discover \ utilities/ofp-kill bin_SCRIPTS += utilities/ofp-pki -noinst_SCRIPTS += utilities/ofp-pki-cgi utilities/ofp-parse-leaks +noinst_PROGRAMS += \ + utilities/ofp-read EXTRA_DIST += \ utilities/dpctl.8.in \ utilities/ofp-discover.8.in \ utilities/ofp-kill.8.in \ - utilities/ofp-parse-leaks.in \ utilities/ofp-pki-cgi.in \ utilities/ofp-pki.8.in \ utilities/ofp-pki.in \ @@ -19,7 +19,6 @@ DISTCLEANFILES += \ utilities/dpctl.8 \ utilities/ofp-discover.8 \ utilities/ofp-kill.8 \ - utilities/ofp-parse-leaks \ utilities/ofp-pki \ utilities/ofp-pki.8 \ utilities/ofp-pki-cgi \ @@ -43,3 +42,7 @@ utilities_ofp_discover_LDADD = lib/libopenflow.a utilities_ofp_kill_SOURCES = utilities/ofp-kill.c utilities_ofp_kill_LDADD = lib/libopenflow.a + +utilities_ofp_read_SOURCES = utilities/ofp-read.c +utilities_ofp_read_LDADD = lib/libopenflow.a oflib/liboflib.a + diff --git a/utilities/dpctl.c b/utilities/dpctl.c index dd34dff8..930f9a22 100644 --- a/utilities/dpctl.c +++ b/utilities/dpctl.c @@ -82,6 +82,7 @@ // response, barrier resp., or the error #define XID 0xf0ff00f0 +static uint32_t global_xid = XID; struct command { char *name; @@ -178,7 +179,7 @@ static int parse16(char *str, struct names16 *names, size_t names_num, uint16_t max, uint16_t *val); static int -parse16m(char *str, struct names16 *names, size_t names_num, uint16_t max, uint16_t *val, uint16_t *mask); +parse16m(char *str, struct names16 *names, size_t names_num, uint16_t max, uint16_t *val, uint16_t **mask) UNUSED; static int parse32(char *str, struct names32 *names, size_t names_num, uint32_t max, uint32_t *val); @@ -186,6 +187,15 @@ parse32(char *str, struct names32 *names, size_t names_num, uint32_t max, uint32 static int parse32m(char *str, struct names32 *names, size_t names_num, uint32_t max, uint32_t *val, uint32_t **mask); +static int +parse64(char *str, uint64_t max, uint64_t *val); + +static int +parse64m(char *str, uint64_t max, uint64_t *val, uint64_t **mask); + +static void +set_table_features_match(struct vconn *vconn, int argc, char *argv[]); + static struct ofl_exp_msg dpctl_exp_msg = {.pack = ofl_exp_msg_pack, .unpack = ofl_exp_msg_unpack, @@ -202,13 +212,13 @@ static struct ofl_exp dpctl_exp = static void dpctl_transact(struct vconn *vconn, struct ofl_msg_header *req, - struct ofl_msg_header **repl) { + struct ofl_msg_header **repl, uint32_t *repl_xid_p) { struct ofpbuf *ofpbufreq, *ofpbufrepl; uint8_t *bufreq; size_t bufreq_size; int error; - error = ofl_msg_pack(req, XID, &bufreq, &bufreq_size, &dpctl_exp); + error = ofl_msg_pack(req, global_xid, &bufreq, &bufreq_size, &dpctl_exp); if (error) { ofp_fatal(0, "Error packing request."); } @@ -220,7 +230,7 @@ dpctl_transact(struct vconn *vconn, struct ofl_msg_header *req, if (error) { ofp_fatal(0, "Error during transaction."); } - error = ofl_msg_unpack(ofpbufrepl->data, ofpbufrepl->size, repl, NULL /*xid_ptr*/, &dpctl_exp); + error = ofl_msg_unpack(ofpbufrepl->data, ofpbufrepl->size, repl, repl_xid_p, &dpctl_exp); if (error) { ofp_fatal(0, "Error unpacking reply."); @@ -238,14 +248,15 @@ static void dpctl_transact_and_print(struct vconn *vconn, struct ofl_msg_header *req, struct ofl_msg_header **repl) { struct ofl_msg_header *reply; + uint32_t repl_xid; char *str; str = ofl_msg_to_string(req, &dpctl_exp); - printf("\nSENDING:\n%s\n\n", str); + printf("\nSENDING (xid=0x%X):\n%s\n\n", global_xid, str); free(str); - dpctl_transact(vconn, req, &reply); + dpctl_transact(vconn, req, &reply, &repl_xid); str = ofl_msg_to_string(reply, &dpctl_exp); - printf("\nRECEIVED:\n%s\n\n", str); + printf("\nRECEIVED (xid=0x%X):\n%s\n\n", repl_xid, str); free(str); if (repl != NULL) { @@ -258,12 +269,13 @@ dpctl_transact_and_print(struct vconn *vconn, struct ofl_msg_header *req, static void dpctl_barrier(struct vconn *vconn) { struct ofl_msg_header *reply; + uint32_t repl_xid; char *str; struct ofl_msg_header req = {.type = OFPT_BARRIER_REQUEST}; - dpctl_transact(vconn, &req, &reply); + dpctl_transact(vconn, &req, &reply, &repl_xid); if (reply->type == OFPT_BARRIER_REPLY) { str = ofl_msg_to_string(reply, &dpctl_exp); @@ -271,7 +283,7 @@ dpctl_barrier(struct vconn *vconn) { free(str); } else { str = ofl_msg_to_string(reply, &dpctl_exp); - printf("\nRECEIVED:\n%s\n\n", str); + printf("\nRECEIVED (xid=0x%X):\n%s\n\n", repl_xid, str); free(str); } @@ -284,7 +296,7 @@ dpctl_send(struct vconn *vconn, struct ofl_msg_header *msg) { size_t buf_size; int error; - error = ofl_msg_pack(msg, XID, &buf, &buf_size, &dpctl_exp); + error = ofl_msg_pack(msg, global_xid, &buf, &buf_size, &dpctl_exp); if (error) { ofp_fatal(0, "Error packing request."); } @@ -305,7 +317,7 @@ static void dpctl_send_and_print(struct vconn *vconn, struct ofl_msg_header *msg) { char *str; str = ofl_msg_to_string(msg, &dpctl_exp); - printf("\nSENDING:\n%s\n\n", str); + printf("\nSENDING (xid=0x%X):\n%s\n\n", global_xid, str); free(str); dpctl_send(vconn, msg); @@ -316,6 +328,7 @@ ping(struct vconn *vconn, int argc, char *argv[]) { uint16_t payload_size = 0; size_t times = 0, i; struct ofl_msg_echo *reply; + uint32_t repl_xid; struct ofl_msg_echo req = {{.type = OFPT_ECHO_REQUEST}, @@ -346,7 +359,7 @@ ping(struct vconn *vconn, int argc, char *argv[]) { random_bytes(req.data, payload_size); gettimeofday(&start, NULL); - dpctl_transact(vconn, (struct ofl_msg_header *)&req, (struct ofl_msg_header **)&reply); + dpctl_transact(vconn, (struct ofl_msg_header *)&req, (struct ofl_msg_header **)&reply, &repl_xid); gettimeofday(&end, NULL); if ((req.data_length != reply->data_length) || @@ -617,15 +630,16 @@ flow_mod(struct vconn *vconn, int argc, char *argv[]) { parse_match(argv[1], &(msg.match)); } else { - if(msg.command == OFPFC_DELETE) + if(msg.command == OFPFC_DELETE) { inst_num = 0; - else { + parse_match(argv[1], &(msg.match)); + } else { /*We copy the value because we don't know if it is an instruction or match. If the match is empty, the argv is modified causing errors to instructions parsing*/ - char *cpy = malloc(strlen(argv[1])); - memcpy(cpy, argv[1], strlen(argv[1])); + char *cpy = malloc(strlen(argv[1])+1); + memcpy(cpy, argv[1], strlen(argv[1]) + 1); parse_match(cpy, &(msg.match)); free(cpy); if(msg.match->length <= 4){ @@ -923,6 +937,7 @@ static struct command all_commands[] = { {"table-mod", 1, 1, table_mod }, {"queue-get-config", 1, 1, queue_get_config}, {"set-desc", 1, 1, set_desc}, + {"set-table-match", 0, 2, set_table_features_match}, {"queue-mod", 3, 3, queue_mod}, {"queue-del", 2, 2, queue_del} @@ -997,6 +1012,7 @@ parse_options(int argc, char *argv[]) {"strict", no_argument, 0, OPT_STRICT}, {"help", no_argument, 0, 'h'}, {"version", no_argument, 0, 'V'}, + {"xid", required_argument, 0, 'x'}, VCONN_SSL_LONG_OPTIONS {0, 0, 0, 0}, }; @@ -1034,6 +1050,10 @@ parse_options(int argc, char *argv[]) vlog_set_verbosity(optarg); break; + case 'x': + global_xid = strtoul(optarg, NULL, 0); + break; + VCONN_SSL_OPTION_HANDLERS case '?': @@ -1102,7 +1122,9 @@ parse_match(char *str, struct ofl_match_header **match) { ofl_structs_match_init(m); for (token = strtok_r(str, KEY_SEP, &saveptr); token != NULL; token = strtok_r(NULL, KEY_SEP, &saveptr)) { - if (strncmp(token, "apply", strlen("apply")) == 0 || strncmp(token, "write", strlen("write")) == 0 ) { + if (strncmp(token, "apply", strlen("apply")) == 0 || + strncmp(token, "write", strlen("write")) == 0 || + strncmp(token, "goto", strlen("goto")) == 0) { break; } /* In_port */ @@ -1125,8 +1147,10 @@ parse_match(char *str, struct ofl_match_header **match) { else { if (mask == NULL) ofl_structs_match_put_eth(m,OXM_OF_ETH_SRC,eth_src); - else + else { ofl_structs_match_put_eth_m(m,OXM_OF_ETH_SRC_W,eth_src,mask); + free(mask); + } } continue; } @@ -1139,8 +1163,10 @@ parse_match(char *str, struct ofl_match_header **match) { else { if (mask == NULL) ofl_structs_match_put_eth(m,OXM_OF_ETH_DST,eth_dst); - else + else { ofl_structs_match_put_eth_m(m,OXM_OF_ETH_DST_W,eth_dst, mask); + free(mask); + } } continue; } @@ -1154,8 +1180,10 @@ parse_match(char *str, struct ofl_match_header **match) { else { if (mask == NULL) ofl_structs_match_put_eth(m, OXM_OF_ARP_SHA, arp_sha); - else + else { ofl_structs_match_put_eth_m(m, OXM_OF_ARP_SHA_W, arp_sha, mask); + free(mask); + } } continue; } @@ -1168,8 +1196,10 @@ parse_match(char *str, struct ofl_match_header **match) { else { if (mask == NULL) ofl_structs_match_put_eth(m,OXM_OF_ARP_THA, arp_tha); - else + else { ofl_structs_match_put_eth_m(m,OXM_OF_ARP_THA_W, arp_tha, mask); + free(mask); + } } continue; } @@ -1182,8 +1212,10 @@ parse_match(char *str, struct ofl_match_header **match) { else { if (mask == NULL) ofl_structs_match_put32(m, OXM_OF_ARP_SPA,arp_src); - else + else { ofl_structs_match_put32m(m, OXM_OF_ARP_SPA_W, arp_src, *mask); + free(mask); + } } continue; } @@ -1196,8 +1228,10 @@ parse_match(char *str, struct ofl_match_header **match) { else { if (mask == NULL) ofl_structs_match_put32(m, OXM_OF_ARP_TPA, arp_target); - else + else { ofl_structs_match_put32m(m, OXM_OF_ARP_TPA_W, arp_target, *mask); + free(mask); + } } continue; } @@ -1283,8 +1317,10 @@ parse_match(char *str, struct ofl_match_header **match) { else { if (mask == NULL) ofl_structs_match_put32(m, OXM_OF_IPV4_SRC,nw_src); - else + else { ofl_structs_match_put32m(m, OXM_OF_IPV4_SRC_W, nw_src, *mask); + free(mask); + } } continue; } @@ -1297,8 +1333,10 @@ parse_match(char *str, struct ofl_match_header **match) { else { if (mask == NULL) ofl_structs_match_put32(m, OXM_OF_IPV4_DST,nw_dst); - else + else { ofl_structs_match_put32m(m, OXM_OF_IPV4_DST_W,nw_dst, *mask); + free(mask); + } } continue; } @@ -1445,8 +1483,10 @@ parse_match(char *str, struct ofl_match_header **match) { else if(mask == NULL) ofl_structs_match_put32(m, OXM_OF_IPV6_FLABEL, ipv6_label); - else + else { ofl_structs_match_put32m(m, OXM_OF_IPV6_FLABEL_W, ipv6_label, *mask); + free (mask); + } continue; } @@ -1490,6 +1530,7 @@ parse_match(char *str, struct ofl_match_header **match) { else { ofl_structs_match_put_eth(m,OXM_OF_IPV6_ND_SLL, eth_src); } + if (mask != NULL) free(mask); continue; } if (strncmp(token, MATCH_IPV6_ND_TLL KEY_VAL, strlen(MATCH_IPV6_ND_TLL KEY_VAL)) == 0) { @@ -1501,16 +1542,24 @@ parse_match(char *str, struct ofl_match_header **match) { else { ofl_structs_match_put_eth(m, OXM_OF_IPV6_ND_TLL,eth_dst); } + if (mask != NULL) free(mask); continue; } /* Metadata */ if (strncmp(token, MATCH_METADATA KEY_VAL, strlen(MATCH_METADATA KEY_VAL)) == 0) { uint64_t metadata; - if (sscanf(token, MATCH_METADATA KEY_VAL "0x%"SCNx64"", (&metadata)) != 1) { - ofp_fatal(0, "Error parsing %s: %s.", MATCH_METADATA, token); + uint64_t *mask; + if (parse64m(token + strlen(MATCH_METADATA KEY_VAL), 0xffffffffffffffffULL, &metadata, &mask)) { + ofp_fatal(0, "Error parsing meta: %s.", token); } - else ofl_structs_match_put64(m, OXM_OF_METADATA, metadata); + else + if(mask == NULL) + ofl_structs_match_put64(m, OXM_OF_METADATA, metadata); + else { + ofl_structs_match_put64m(m, OXM_OF_METADATA_W, metadata, *mask); + free (mask); + } continue; } /*PBB ISID*/ @@ -1525,10 +1574,17 @@ parse_match(char *str, struct ofl_match_header **match) { /* Tunnel ID */ if (strncmp(token, MATCH_TUNNEL_ID KEY_VAL, strlen(MATCH_TUNNEL_ID KEY_VAL)) == 0) { uint64_t tunn_id; - if (sscanf(token, MATCH_TUNNEL_ID KEY_VAL "0x%"SCNx64"", (&tunn_id)) != 1) { - ofp_fatal(0, "Error parsing %s: %s.", MATCH_TUNNEL_ID, token); + uint64_t *mask; + if (parse64m(token + strlen(MATCH_TUNNEL_ID KEY_VAL), 0xffffffffffffffffULL, &tunn_id, &mask)) { + ofp_fatal(0, "Error parsing tunn_id: %s.", token); } - else ofl_structs_match_put64(m, OXM_OF_TUNNEL_ID, tunn_id); + else + if(mask == NULL) + ofl_structs_match_put64(m, OXM_OF_TUNNEL_ID, tunn_id); + else { + ofl_structs_match_put64m(m, OXM_OF_TUNNEL_ID_W, tunn_id, *mask); + free (mask); + } continue; } /*Extension Headers */ @@ -1560,6 +1616,7 @@ parse_set_field(char *token, struct ofl_action_set_field *act) { act->field->header = OXM_OF_ETH_SRC; act->field->value = (uint8_t*) dl_src; } + if (mask != NULL) free(mask); return 0; } if (strncmp(token, MATCH_DL_DST KEY_VAL2, strlen(MATCH_DL_DST KEY_VAL2)) == 0) { @@ -1572,6 +1629,7 @@ parse_set_field(char *token, struct ofl_action_set_field *act) { act->field->header = OXM_OF_ETH_DST; act->field->value = (uint8_t*) dl_dst; } + if (mask != NULL) free(mask); return 0; } if (strncmp(token, MATCH_DL_TYPE KEY_VAL2, strlen(MATCH_DL_TYPE KEY_VAL2)) == 0) { @@ -1599,6 +1657,7 @@ parse_set_field(char *token, struct ofl_action_set_field *act) { act->field->header = OXM_OF_ARP_SHA; act->field->value = (uint8_t*) arp_sha; } + if (mask != NULL) free(mask); return 0; } if (strncmp(token, MATCH_ARP_THA KEY_VAL2, strlen(MATCH_ARP_THA KEY_VAL2)) == 0) { @@ -1612,6 +1671,7 @@ parse_set_field(char *token, struct ofl_action_set_field *act) { act->field->header = OXM_OF_ARP_THA; act->field->value = (uint8_t*) arp_tha; } + if (mask != NULL) free(mask); return 0; } if (strncmp(token, MATCH_ARP_SPA KEY_VAL2, strlen(MATCH_ARP_SPA KEY_VAL2)) == 0) { @@ -1625,6 +1685,7 @@ parse_set_field(char *token, struct ofl_action_set_field *act) { act->field->header = OXM_OF_ARP_SPA; act->field->value = (uint8_t*) arp_src; } + if (mask != NULL) free(mask); return 0; } if (strncmp(token, MATCH_ARP_TPA KEY_VAL2, strlen(MATCH_ARP_TPA KEY_VAL2)) == 0) { @@ -1638,6 +1699,7 @@ parse_set_field(char *token, struct ofl_action_set_field *act) { act->field->header = OXM_OF_ARP_TPA; act->field->value = (uint8_t*) arp_target; } + if (mask != NULL) free(mask); return 0; } if (strncmp(token, MATCH_ARP_OP KEY_VAL2, strlen(MATCH_ARP_OP KEY_VAL2)) == 0) { @@ -1660,6 +1722,7 @@ parse_set_field(char *token, struct ofl_action_set_field *act) { else { act->field = (struct ofl_match_tlv*) malloc(sizeof(struct ofl_match_tlv)); act->field->header = OXM_OF_VLAN_VID; + *dl_vlan = *dl_vlan | OFPVID_PRESENT; act->field->value = (uint8_t*) dl_vlan; } return 0; @@ -1747,6 +1810,7 @@ parse_set_field(char *token, struct ofl_action_set_field *act) { act->field->header = OXM_OF_IPV4_SRC; act->field->value = (uint8_t*) nw_src; } + if (mask != NULL) free(mask); return 0; } if (strncmp(token, MATCH_NW_DST KEY_VAL2, strlen(MATCH_NW_DST KEY_VAL2)) == 0) { @@ -1761,6 +1825,7 @@ parse_set_field(char *token, struct ofl_action_set_field *act) { act->field->header = OXM_OF_IPV4_DST; act->field->value = (uint8_t*) nw_dst; } + if (mask != NULL) free(mask); return 0; } if (strncmp(token, MATCH_IP_ECN KEY_VAL2, strlen(MATCH_NW_DST KEY_VAL2)) == 0) { @@ -1813,8 +1878,8 @@ parse_set_field(char *token, struct ofl_action_set_field *act) { } if (strncmp(token, MATCH_TP_DST KEY_VAL2, strlen(MATCH_TP_DST KEY_VAL2)) == 0) { uint16_t* tp_dst = xmalloc(2); - if (parse16(token + strlen(MATCH_TP_SRC KEY_VAL2), NULL, 0, 0xffff, tp_dst)) { - ofp_fatal(0, "Error parsing tcp_src: %s.", token); + if (parse16(token + strlen(MATCH_TP_DST KEY_VAL2), NULL, 0, 0xffff, tp_dst)) { + ofp_fatal(0, "Error parsing tcp_dst: %s.", token); }else{ act->field = (struct ofl_match_tlv*) malloc(sizeof(struct ofl_match_tlv)); act->field->header = OXM_OF_TCP_DST; @@ -1822,6 +1887,28 @@ parse_set_field(char *token, struct ofl_action_set_field *act) { } return 0; } + if (strncmp(token, MATCH_UDP_SRC KEY_VAL2, strlen(MATCH_UDP_SRC KEY_VAL2)) == 0) { + uint16_t* udp_src = xmalloc(2); + if (parse16(token+ strlen(MATCH_UDP_SRC KEY_VAL2), NULL, 0, 0xffff, udp_src)) { + ofp_fatal(0, "Error parsing udp_src: %s.", token); + }else{ + act->field = (struct ofl_match_tlv*) malloc(sizeof(struct ofl_match_tlv)); + act->field->header = OXM_OF_UDP_SRC; + act->field->value = (uint8_t*) udp_src; + } + return 0; + } + if (strncmp(token, MATCH_UDP_DST KEY_VAL2, strlen(MATCH_UDP_DST KEY_VAL2)) == 0) { + uint16_t* udp_dst = xmalloc(2); + if (parse16(token+ strlen(MATCH_UDP_DST KEY_VAL2), NULL, 0, 0xffff, udp_dst)) { + ofp_fatal(0, "Error parsing udp_dst: %s.", token); + }else{ + act->field = (struct ofl_match_tlv*) malloc(sizeof(struct ofl_match_tlv)); + act->field->header = OXM_OF_UDP_DST; + act->field->value = (uint8_t*) udp_dst; + } + return 0; + } if (strncmp(token, MATCH_NW_SRC_IPV6 KEY_VAL2 , strlen(MATCH_NW_SRC_IPV6 KEY_VAL2)) == 0) { struct in6_addr *addr = (struct in6_addr*) malloc(sizeof(struct in6_addr)); struct in6_addr mask; @@ -1860,6 +1947,19 @@ parse_set_field(char *token, struct ofl_action_set_field *act) { } return 0; } + /* Tunnel ID */ + if (strncmp(token, MATCH_TUNNEL_ID KEY_VAL2, strlen(MATCH_TUNNEL_ID KEY_VAL2)) == 0) { + uint64_t *tunn_id = malloc(sizeof(uint64_t)); + if (parse64(token + strlen(MATCH_TUNNEL_ID KEY_VAL2), 0xffffffffffffffffULL, tunn_id)) { + ofp_fatal(0, "Error parsing tunn_id: %s.", token); + } + else { + act->field = (struct ofl_match_tlv*) malloc(sizeof(struct ofl_match_tlv)); + act->field->header = OXM_OF_TUNNEL_ID; + act->field->value = (uint8_t*) tunn_id; + } + return 0; + } ofp_fatal(0, "Error parsing set_field arg: %s.", token); } @@ -2040,19 +2140,17 @@ parse_inst(char *str, struct ofl_instruction_header **inst) { return; } case (OFPIT_WRITE_METADATA): { - char *token, *saveptr = NULL; + uint64_t *mask; struct ofl_instruction_write_metadata *i = xmalloc(sizeof(struct ofl_instruction_write_metadata)); i->header.type = OFPIT_WRITE_METADATA; - token = strtok_r(s, KEY_SEP, &saveptr); - if (sscanf(token, "0x%"SCNx64"", &(i->metadata)) != 1) { + if (parse64m(s, 0xffffffffffffffffULL, &(i->metadata), &mask)) { ofp_fatal(0, "Error parsing metadata in write metadata instruction: %s.", s); - } - token = strtok_r(NULL, KEY_SEP, &saveptr); - if (token == NULL) { - i->metadata_mask = 0xffffffffffffffffULL; } else { - if (sscanf(token, "0x%"SCNx64"", &(i->metadata_mask)) != 1) { - ofp_fatal(0, "Error parsing metadata_mask in write metadata instruction: %s.", s); + if (mask == NULL) { + i->metadata_mask = 0xffffffffffffffffULL; + } else { + i->metadata_mask = *mask; + free (mask); } } (*inst) = (struct ofl_instruction_header *)i; @@ -2110,7 +2208,7 @@ parse_flow_stat_args(char *str, struct ofl_msg_multipart_request_flow *req) { continue; } if (strncmp(token, FLOW_MOD_COOKIE_MASK KEY_VAL, strlen(FLOW_MOD_COOKIE_MASK KEY_VAL)) == 0) { - if (sscanf(token, FLOW_MOD_COOKIE KEY_VAL "0x%"SCNx64"", &(req->cookie)) != 1) { + if (sscanf(token, FLOW_MOD_COOKIE_MASK KEY_VAL "0x%"SCNx64"", &(req->cookie_mask)) != 1) { ofp_fatal(0, "Error parsing flow_stat cookie mask: %s.", token); } continue; @@ -2159,7 +2257,7 @@ parse_flow_mod_args(char *str, struct ofl_msg_flow_mod *req) { continue; } if (strncmp(token, FLOW_MOD_COOKIE_MASK KEY_VAL, strlen(FLOW_MOD_COOKIE_MASK KEY_VAL)) == 0) { - if (sscanf(token, FLOW_MOD_COOKIE KEY_VAL "0x%"SCNx64"", &(req->cookie)) != 1) { + if (sscanf(token, FLOW_MOD_COOKIE_MASK KEY_VAL "0x%"SCNx64"", &(req->cookie_mask)) != 1) { ofp_fatal(0, "Error parsing flow_mod cookie mask: %s.", token); } continue; @@ -2413,6 +2511,7 @@ parse_port_mod(char *str, struct ofl_msg_port_mod *msg) { if (parse_dl_addr(token + strlen(PORT_MOD_HW_ADDR KEY_VAL), msg->hw_addr, &mask)) { ofp_fatal(0, "Error parsing port_mod hw_addr: %s.", token); } + if (mask != NULL) free(mask); continue; } if (strncmp(token, PORT_MOD_HW_CONFIG KEY_VAL, strlen(PORT_MOD_HW_CONFIG KEY_VAL)) == 0) { @@ -2589,8 +2688,15 @@ parse8(char *str, struct names8 *names, size_t names_num, uint8_t max, uint8_t * } } - if ((max > 0) && (sscanf(str, "%"SCNu8"", val)) == 1 && ((*val) <= max)) { - return 0; + /* Checks for value in hexadecimal. */ + if (str[0] == '0' && str[1] == 'x') { + if ((max > 0) && (sscanf(str, "0x%"SCNx8"", val)) == 1 && (*val <= max)) { + return 0; + } + } else { + if ((max > 0) && (sscanf(str, "%"SCNu8"", val)) == 1 && (*val <= max)) { + return 0; + } } return -1; } @@ -2606,43 +2712,58 @@ parse16(char *str, struct names16 *names, size_t names_num, uint16_t max, uint16 } } - /* Checks if the passed value is hexadecimal. */ - if( str[1] == 'x'){ - if ((max > 0) && (sscanf(str, "%"SCNx16"", val)) == 1 && (*val <= max)) { + /* Checks for value in hexadecimal. */ + if (str[0] == '0' && str[1] == 'x') { + if ((max > 0) && (sscanf(str, "0x%"SCNx16"", val)) == 1 && (*val <= max)) { return 0; } - } - else { - if ((max > 0) && (sscanf(str, "%"SCNu16"", val)) == 1 && (*val <= max)) { + } else { + if ((max > 0) && (sscanf(str, "%"SCNu16"", val)) == 1 && (*val <= max)) { return 0; - } + } } return -1; } static int -parse16m(char *str, struct names16 *names, size_t names_num, uint16_t max, uint16_t *val, uint16_t *mask){ +parse16m(char *str, struct names16 *names, size_t names_num, uint16_t max, uint16_t *val, uint16_t **mask){ size_t i; - char *token, *saveptr = NULL; + int read; + char *saveptr = NULL; for (i=0; i 0) && (*val <= max)) { - if (!sscanf(str, "%"SCNu16"", val)) - return -1; + /* Checks for value in hexadecimal. */ + if (str[0] == '0' && str[1] == 'x') { + read = sscanf(str, "0x%"SCNx16"", val); + } else { + read = sscanf(str, "%"SCNu16"", val); + } + if ((read == 0) || (max == 0) || (*val > max)) { + return -1; } - token = strtok_r(str, MASK_SEP, &saveptr); - if(token == NULL) - mask = NULL; - else { - mask = (uint16_t*) malloc(sizeof(uint16_t)); - sscanf(token, "%"SCNu16"", mask); + strtok_r(str, MASK_SEP, &saveptr); + if (strcmp (saveptr, "") == 0) { + *mask = NULL; + return 0; + } + *mask = (uint16_t*) malloc(sizeof(uint16_t)); + + /* Checks for mask in hexadecimal. */ + if (saveptr[0] == '0' && saveptr[1] == 'x') { + read = sscanf(saveptr, "0x%"SCNx16"", *mask); + } else { + read = sscanf(saveptr, "%"SCNu16"", *mask); + } + if (read == 0) { + return -1; } return 0; @@ -2659,8 +2780,15 @@ parse32(char *str, struct names32 *names, size_t names_num, uint32_t max, uint32 } } - if ((max > 0) && (sscanf(str, "%"SCNu32"", val)) == 1 && ((*val) <= max)) { - return 0; + /* Checks for value in hexadecimal. */ + if (str[0] == '0' && str[1] == 'x') { + if ((max > 0) && (sscanf(str, "0x%"SCNx32"", val)) == 1 && (*val <= max)) { + return 0; + } + } else { + if ((max > 0) && (sscanf(str, "%"SCNu32"", val)) == 1 && (*val <= max)) { + return 0; + } } return -1; } @@ -2669,26 +2797,294 @@ static int parse32m(char *str, struct names32 *names, size_t names_num, uint32_t max, uint32_t *val, uint32_t **mask){ size_t i; + int read; char *saveptr = NULL; for (i=0; i 0) && (*val <= max)) { - if (!sscanf(str, "%"SCNu32"", val)) - return -1; + /* Checks for value in hexadecimal. */ + if (str[0] == '0' && str[1] == 'x') { + read = sscanf(str, "0x%"SCNx32"", val); + } else { + read = sscanf(str, "%"SCNu32"", val); + } + if ((read == 0) || (max == 0) || (*val > max)) { + return -1; } strtok_r(str, MASK_SEP, &saveptr); + if (strcmp (saveptr, "") == 0) { + *mask = NULL; + return 0; + } + *mask = (uint32_t*) malloc(sizeof(uint32_t)); + + /* Checks for mask in hexadecimal. */ + if (saveptr[0] == '0' && saveptr[1] == 'x') { + read = sscanf(saveptr, "0x%"SCNx32"", *mask); + } else { + read = sscanf(saveptr, "%"SCNu32"", *mask); + } + if (read == 0) { + return -1; + } + return 0; +} + +static int +parse64(char *str, uint64_t max, uint64_t *val) { + int read; + + /* Checks for value in hexadecimal. */ + if (str[0] == '0' && str[1] == 'x') { + read = sscanf(str, "0x%"SCNx64"", val); + } else { + read = sscanf(str, "%"SCNu64"", val); + } + if ((read == 0) || (max == 0) || (*val > max)) { + return -1; + } + return 0; +} - if(saveptr == NULL) +static int +parse64m(char *str, uint64_t max, uint64_t *val, uint64_t **mask) { + int read; + char *saveptr = NULL; + + /* Checks for value in hexadecimal. */ + if (str[0] == '0' && str[1] == 'x') { + read = sscanf(str, "0x%"SCNx64"", val); + } else { + read = sscanf(str, "%"SCNu64"", val); + } + if ((read == 0) || (max == 0) || (*val > max)) { + return -1; + } + + strtok_r(str, MASK_SEP, &saveptr); + if (strcmp (saveptr, "") == 0) { *mask = NULL; - else { - *mask = (uint32_t*) malloc(sizeof(uint32_t)); - sscanf(saveptr, "%"SCNu32"", *mask); + return 0; + } + *mask = (uint64_t*) malloc(sizeof(uint64_t)); + + /* Checks for mask in hexadecimal. */ + if (saveptr[0] == '0' && saveptr[1] == 'x') { + read = sscanf(saveptr, "0x%"SCNx64"", *mask); + } else { + read = sscanf(saveptr, "%"SCNu64"", *mask); + } + if (read == 0) { + return -1; } return 0; } + +struct oxm_str_mapping { + char * name; + uint32_t oxm_id; +}; +struct oxm_str_mapping oxm_str_map[] = + { { .name=MATCH_IN_PORT, .oxm_id=OXM_OF_IN_PORT }, + { .name=MATCH_DL_SRC, .oxm_id=OXM_OF_ETH_SRC }, + { .name=MATCH_DL_DST, .oxm_id=OXM_OF_ETH_DST }, + { .name=MATCH_ARP_SHA, .oxm_id=OXM_OF_ARP_SHA }, + { .name=MATCH_ARP_THA, .oxm_id=OXM_OF_ARP_THA }, + { .name=MATCH_ARP_SPA, .oxm_id=OXM_OF_ARP_SPA }, + { .name=MATCH_ARP_TPA, .oxm_id=OXM_OF_ARP_TPA }, + { .name=MATCH_ARP_OP, .oxm_id=OXM_OF_ARP_OP }, + { .name=MATCH_DL_VLAN, .oxm_id=OXM_OF_VLAN_VID }, + { .name=MATCH_DL_VLAN_PCP, .oxm_id=OXM_OF_VLAN_PCP }, + { .name=MATCH_DL_TYPE, .oxm_id=OXM_OF_ETH_TYPE }, + { .name=MATCH_IP_ECN, .oxm_id=OXM_OF_IP_ECN }, + { .name=MATCH_IP_DSCP, .oxm_id=OXM_OF_IP_DSCP }, + { .name=MATCH_NW_PROTO, .oxm_id=OXM_OF_IP_PROTO }, + { .name=MATCH_NW_SRC, .oxm_id=OXM_OF_IPV4_SRC }, + { .name=MATCH_NW_DST, .oxm_id=OXM_OF_IPV4_DST }, + { .name=MATCH_ICMPV4_CODE, .oxm_id=OXM_OF_ICMPV4_CODE }, + { .name=MATCH_ICMPV4_TYPE, .oxm_id=OXM_OF_ICMPV4_TYPE }, + { .name=MATCH_TP_SRC, .oxm_id=OXM_OF_TCP_SRC }, + { .name=MATCH_TP_DST, .oxm_id=OXM_OF_TCP_DST }, + { .name=MATCH_UDP_SRC, .oxm_id=OXM_OF_UDP_SRC }, + { .name=MATCH_UDP_DST, .oxm_id=OXM_OF_UDP_DST }, + { .name=MATCH_SCTP_SRC, .oxm_id=OXM_OF_SCTP_SRC }, + { .name=MATCH_SCTP_DST, .oxm_id=OXM_OF_SCTP_DST }, + { .name=MATCH_MPLS_LABEL, .oxm_id=OXM_OF_MPLS_LABEL }, + { .name=MATCH_MPLS_TC, .oxm_id=OXM_OF_MPLS_TC }, + { .name=MATCH_MPLS_BOS, .oxm_id=OXM_OF_MPLS_BOS }, + { .name=MATCH_NW_SRC_IPV6, .oxm_id=OXM_OF_IPV6_SRC }, + { .name=MATCH_NW_DST_IPV6, .oxm_id=OXM_OF_IPV6_DST }, + { .name=MATCH_IPV6_FLABEL, .oxm_id=OXM_OF_IPV6_FLABEL }, + { .name=MATCH_ICMPV6_CODE, .oxm_id=OXM_OF_ICMPV6_CODE }, + { .name=MATCH_ICMPV6_TYPE, .oxm_id=OXM_OF_ICMPV6_TYPE }, + { .name=MATCH_IPV6_ND_TARGET, .oxm_id=OXM_OF_IPV6_ND_TARGET }, + { .name=MATCH_IPV6_ND_SLL, .oxm_id=OXM_OF_IPV6_ND_SLL }, + { .name=MATCH_IPV6_ND_TLL, .oxm_id=OXM_OF_IPV6_ND_TLL }, + { .name=MATCH_METADATA, .oxm_id=OXM_OF_METADATA }, + { .name=MATCH_PBB_ISID, .oxm_id=OXM_OF_PBB_ISID }, + { .name=MATCH_TUNNEL_ID, .oxm_id=OXM_OF_TUNNEL_ID }, + { .name=MATCH_EXT_HDR, .oxm_id=OXM_OF_IPV6_EXTHDR }, + }; + +static void +parse_feature_prop_match(char *str, struct ofl_table_feature_prop_oxm **prop_addr) { + char *token, *saveptr = NULL; + const int oxm_max = sizeof(oxm_str_map) / sizeof(oxm_str_map[0]); + uint32_t *oxm_array = (uint32_t *) xmalloc(sizeof(uint32_t) * 80); + struct ofl_table_feature_prop_oxm *property; + int oxm_num = 0; + int id; + + for (token = strtok_r(str, KEY_SEP, &saveptr); token != NULL; token = strtok_r(NULL, KEY_SEP, &saveptr)) { + if (strncmp(token, "apply", strlen("apply")) == 0 || strncmp(token, "write", strlen("write")) == 0 ) { + break; + } + if (oxm_num >= oxm_max) { + break; + } + for (id = 0; id < oxm_max; id++) { + + if (strncmp(token, oxm_str_map[id].name, strlen(oxm_str_map[id].name)) == 0) { + oxm_array[oxm_num++] = oxm_str_map[id].oxm_id; + break; + } + } + } + + property = (struct ofl_table_feature_prop_oxm *) xmalloc(sizeof(struct ofl_table_feature_prop_oxm)); + property->header.type = OFPTFPT_MATCH; + property->header.length = (sizeof(struct ofp_table_feature_prop_oxm) + oxm_num * sizeof(uint32_t)); + property->oxm_num = oxm_num; + property->oxm_ids = oxm_array; + (*prop_addr) = property; +} + +static void +set_table_features_match(struct vconn *vconn, int argc, char *argv[]) { + struct ofl_msg_multipart_request_table_features req_init = + {{{.type = OFPT_MULTIPART_REQUEST}, + .type = OFPMP_TABLE_FEATURES, .flags = 0x0000}, + .tables_num = 0, + .table_features = NULL, + }; + struct ofl_msg_header *reply; + struct ofl_msg_multipart_request_table_features *table_feat; + int t; + int last_table; + int batch_table; + uint32_t repl_xid; + + /* Extract current table features */ + dpctl_transact(vconn, (struct ofl_msg_header *)&req_init, &reply, &repl_xid); + table_feat = (struct ofl_msg_multipart_request_table_features *) reply; + + if (argc > 0) { + struct ofl_table_feature_prop_oxm *new_match; + struct ofl_table_feature_prop_header **properties; + int properties_num; + int i; + + /* New match features */ + parse_feature_prop_match(argv[0], &new_match); + { + char *str; + str = ofl_structs_table_properties_to_string((struct ofl_table_feature_prop_header *) new_match); + printf("New match property:%s\n\n", str); + free(str); + } + + /* Set them in all the table features */ + for(t = 0; t < table_feat->tables_num; t++) { + properties = table_feat->table_features[t]->properties; + properties_num = table_feat->table_features[t]->properties_num; + for (i = 0; i < properties_num; i++) { + if(properties[i]->type == OFPTFPT_MATCH) { + struct ofl_table_feature_prop_oxm *clone_match; + clone_match = (struct ofl_table_feature_prop_oxm *) xmalloc(sizeof(struct ofl_table_feature_prop_oxm)); + memcpy((char *) clone_match, (char *) new_match, sizeof(struct ofl_table_feature_prop_oxm)); + clone_match->oxm_ids = (uint32_t *) xmalloc(clone_match->oxm_num * sizeof(uint32_t)); + memcpy((char *) clone_match->oxm_ids, new_match->oxm_ids, clone_match->oxm_num * sizeof(uint32_t)); + + ofl_structs_free_table_properties(properties[i], &dpctl_exp); + properties[i] = (struct ofl_table_feature_prop_header *) clone_match; + } + } + } + + ofl_structs_free_table_properties((struct ofl_table_feature_prop_header *) new_match, &dpctl_exp); + + } + + { + int features_len; + printf("\nJII table-num:%zu\n", table_feat->tables_num); + features_len = ofl_structs_table_features_ofp_total_len(table_feat->table_features, table_feat->tables_num, NULL); + printf("\nJII features_len:%d\n", features_len); + } + + /* Turn the reply into a request */ + table_feat->header.header.type = OFPT_MULTIPART_REQUEST; + + /* Renumber tables to form multipart request */ + last_table = table_feat->table_features[table_feat->tables_num - 1]->table_id; + t = 0; + batch_table = table_feat->tables_num; + while(t <= last_table) { + int i; + int prev_t = t; + for(i = 0; i < batch_table; i++) { + table_feat->table_features[i]->table_id = t; + table_feat->table_features[i]->name[0] = '\0'; + t++; + if(t > last_table) + break; + } + + /* Set the request parameters. */ + table_feat->tables_num = t - prev_t; + +#if 0 + { + char *str; + str = ofl_msg_to_string(reply, &dpctl_exp); + printf("\nNew table request (t=%d/%d, num=%d):\n%s\n\n", t, last_table, table_feat->tables_num, str); + free(str); + } +#endif + + /* Intermediate and last segment are not treated the same. Jean II */ + if(t <= last_table) { + struct ofpbuf *ofpbufreq; + uint8_t *bufreq; + size_t bufreq_size; + int error; + + table_feat->header.flags = OFPMPF_REQ_MORE; + + error = ofl_msg_pack((struct ofl_msg_header *)table_feat, XID, &bufreq, &bufreq_size, NULL); + if (error) { + ofp_fatal(0, "Error packing request."); + } + printf("\nJII-req-pack:%zu\n", bufreq_size); + + ofpbufreq = ofpbuf_new(0); + ofpbuf_use(ofpbufreq, bufreq, bufreq_size); + ofpbuf_put_uninit(ofpbufreq, bufreq_size); + error = vconn_send_block(vconn, ofpbufreq); + if (error) { + ofp_fatal(0, "Error during transaction."); + } + /* No reply. */ + } else { + table_feat->header.flags = 0; + + dpctl_transact_and_print(vconn, (struct ofl_msg_header *)table_feat, NULL); + } + } +} diff --git a/utilities/dpctl.c.bak b/utilities/dpctl.c.bak deleted file mode 100644 index e57aaf03..00000000 --- a/utilities/dpctl.c.bak +++ /dev/null @@ -1,1980 +0,0 @@ -/* Copyright (c) 2011, TrafficLab, Ericsson Research, Hungary - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the Ericsson Research nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * - * Author: Zoltán Lajos Kis - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "dpctl.h" -#include "oflib/ofl-messages.h" -#include "oflib/ofl-structs.h" -#include "oflib/ofl-actions.h" -#include "oflib/ofl-print.h" -#include "oflib/ofl.h" -#include "oflib-exp/ofl-exp.h" -#include "oflib-exp/ofl-exp-openflow.h" -#include "oflib/oxm-match.h" - -#include "command-line.h" -#include "compiler.h" -#include "dpif.h" -#include "openflow/nicira-ext.h" -#include "openflow/openflow-ext.h" -#include "ofpbuf.h" -#include "openflow/openflow.h" -#include "packets.h" -#include "random.h" -#include "socket-util.h" -#include "timeval.h" -#include "util.h" -#include "vconn-ssl.h" -#include "vconn.h" -#include "ipv6_util.h" - -#include "ofpstat.h" -#include "openflow/private-ext.h" - -#include "vlog.h" - -#define LOG_MODULE VLM_dpctl - - -// NOTE: the request and the barrier is sent with the same xid, -// so a vconn_receive_block will return with either the -// response, barrier resp., or the error -#define XID 0xf0ff00f0 - - -struct command { - char *name; - int min_args; - int max_args; - void (*handler)(struct vconn *vconn, int argc, char *argv[]); -}; - -static struct command all_commands[]; - -static void -usage(void) NO_RETURN; - -static void -parse_options(int argc, char *argv[]); - -static uint8_t mask_all[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; - - - -static void -parse_flow_mod_args(char *str, struct ofl_msg_flow_mod *req); - -static void -parse_group_mod_args(char *str, struct ofl_msg_group_mod *req); - -static void -parse_bucket(char *str, struct ofl_bucket *b); - -static void -parse_flow_stat_args(char *str, struct ofl_msg_stats_request_flow *req); - -static void -parse_match(char *str, struct ofl_match_header **match); - -static void -parse_inst(char *str, struct ofl_instruction_header **inst); - -static void -parse_actions(char *str, size_t *acts_num, struct ofl_action_header ***acts); - -static void -parse_config(char *str, struct ofl_config *config); - -static void -parse_port_mod(char *str, struct ofl_msg_port_mod *msg); - -static void -parse_table_mod(char *str, struct ofl_msg_table_mod *msg); - - -static void -make_all_match(struct ofl_match_header **match); - - - - -static int -parse_port(char *str, uint32_t *port); - -static int -parse_queue(char *str, uint32_t *port); - -static int -parse_group(char *str, uint32_t *group); - -static int -parse_table(char *str, uint8_t *table); - -static int -parse_dl_addr(char *str, uint8_t *addr); - -static int -parse_nw_addr(char *str, uint32_t *addr); - -static int -parse_vlan_vid(char *str, uint16_t *vid); - - -static int -parse8(char *str, struct names8 *names, size_t names_num, uint8_t max, uint8_t *val); - -static int -parse16(char *str, struct names16 *names, size_t names_num, uint16_t max, uint16_t *val); - -static int -parse32(char *str, struct names32 *names, size_t names_num, uint32_t max, uint32_t *val); - - -static struct ofl_exp_msg dpctl_exp_msg = - {.pack = ofl_exp_msg_pack, - .unpack = ofl_exp_msg_unpack, - .free = ofl_exp_msg_free, - .to_string = ofl_exp_msg_to_string}; - -static struct ofl_exp dpctl_exp = - {.act = NULL, - .inst = NULL, - .match = NULL, - .stats = NULL, - .msg = &dpctl_exp_msg}; - - -static void -dpctl_transact(struct vconn *vconn, struct ofl_msg_header *req, - struct ofl_msg_header **repl) { - struct ofpbuf *ofpbufreq, *ofpbufrepl; - uint8_t *bufreq; - size_t bufreq_size; - int error; - - error = ofl_msg_pack(req, XID, &bufreq, &bufreq_size, &dpctl_exp); - if (error) { - ofp_fatal(0, "Error packing request."); - } - - ofpbufreq = ofpbuf_new(0); - ofpbuf_use(ofpbufreq, bufreq, bufreq_size); - ofpbuf_put_uninit(ofpbufreq, bufreq_size); - - error = vconn_transact(vconn, ofpbufreq, &ofpbufrepl); - if (error) { - ofp_fatal(0, "Error during transaction."); - } - - error = ofl_msg_unpack(ofpbufrepl->data, ofpbufrepl->size, repl, NULL /*xid_ptr*/, &dpctl_exp); - if (error) { - ofp_fatal(0, "Error unpacking reply."); - } - - /* NOTE: if unpack was successful, message takes over ownership of buffer's - * data. Rconn and vconn does not allocate headroom, so the ofpbuf - * wrapper can simply be deleted, keeping the data for the message. */ - ofpbufrepl->base = NULL; - ofpbufrepl->data = NULL; - ofpbuf_delete(ofpbufrepl); -} - -static void -dpctl_transact_and_print(struct vconn *vconn, struct ofl_msg_header *req, - struct ofl_msg_header **repl) { - struct ofl_msg_header *reply; - char *str; - - str = ofl_msg_to_string(req, &dpctl_exp); - printf("\nSENDING:\n%s\n\n", str); - free(str); - - dpctl_transact(vconn, req, &reply); - - str = ofl_msg_to_string(reply, &dpctl_exp); - printf("\nRECEIVED:\n%s\n\n", str); - free(str); - - if (repl != NULL) { - (*repl) = reply; - } else { - ofl_msg_free(reply, &dpctl_exp); - } -} - -static void -dpctl_barrier(struct vconn *vconn) { - struct ofl_msg_header *reply; - char *str; - - struct ofl_msg_header req = - {.type = OFPT_BARRIER_REQUEST}; - - dpctl_transact(vconn, &req, &reply); - - if (reply->type == OFPT_BARRIER_REPLY) { - str = ofl_msg_to_string(reply, &dpctl_exp); - printf("\nOK.\n\n"); - free(str); - } else { - str = ofl_msg_to_string(reply, &dpctl_exp); - printf("\nRECEIVED:\n%s\n\n", str); - free(str); - } - -} - -static void -dpctl_send(struct vconn *vconn, struct ofl_msg_header *msg) { - struct ofpbuf *ofpbuf; - uint8_t *buf; - size_t buf_size; - int error; - - error = ofl_msg_pack(msg, XID, &buf, &buf_size, &dpctl_exp); - if (error) { - ofp_fatal(0, "Error packing request."); - } - - ofpbuf = ofpbuf_new(0); - ofpbuf_use(ofpbuf, buf, buf_size); - ofpbuf_put_uninit(ofpbuf, buf_size); - - error = vconn_send_block(vconn, ofpbuf); - if (error) { - ofp_fatal(0, "Error during transaction."); - } - - dpctl_barrier(vconn); -} - -static void -dpctl_send_and_print(struct vconn *vconn, struct ofl_msg_header *msg) { - char *str; - - str = ofl_msg_to_string(msg, &dpctl_exp); - printf("\nSENDING:\n%s\n\n", str); - free(str); - - dpctl_send(vconn, msg); -} - -static void -ping(struct vconn *vconn, int argc, char *argv[]) { - uint16_t payload_size = 0; - size_t times = 0, i; - struct ofl_msg_echo *reply; - - struct ofl_msg_echo req = - {{.type = OFPT_ECHO_REQUEST}, - .data_length = 0, - .data = NULL}; - - if (argc > 0) { - times = atoi(argv[0]); - } - if (times == 0) { - times = 4; - } - if (argc > 1) { - payload_size = atoi(argv[1]); - } else { - payload_size = 1024; - } - if (payload_size > UINT16_MAX - sizeof(struct ofp_header)) { - ofp_fatal(0, "payload must be between 0 and %zu bytes.", UINT16_MAX - sizeof(struct ofp_header)); - } - - req.data_length = payload_size; - req.data = xmalloc(payload_size); - - for (i=0; idata_length) || - (memcmp(req.data, reply->data, req.data_length) != 0)) { - ofp_fatal(0, "Reply does not match request."); - } - - printf("%zu bytes from %s: time=%.1f ms\n", - (reply->data_length - sizeof(struct ofp_header)), - vconn_get_name(vconn), - (1000*(double)(end.tv_sec - start.tv_sec)) + (.001*(end.tv_usec - start.tv_usec))); - - } - - free(req.data); - ofl_msg_free((struct ofl_msg_header *)reply, &dpctl_exp); -} - -static void -monitor(struct vconn *vconn, int argc UNUSED, char *argv[] UNUSED) { - struct ofpbuf *buf; - struct ofl_msg_header *msg; - char *str; - int error; - - printf("MONITORING %s...\n\n", vconn_get_name(vconn)); - - for (;;) { - if (vconn_recv_block(vconn, &buf) == 0) { - - error = ofl_msg_unpack(buf->data, buf->size, &msg, NULL /*xid_ptr*/, &dpctl_exp); - if (error) { - ofp_fatal(0, "Error unpacking reply."); - } - - /* NOTE: if unpack was successful, message takes over ownership of buffer's - * data. Rconn and vconn does not allocate headroom, so the ofpbuf - * wrapper can simply be deleted, keeping the data for the message. */ - buf->base = NULL; - buf->data = NULL; - ofpbuf_delete(buf); - - str = ofl_msg_to_string(msg, &dpctl_exp); - printf("\nRECEIVED:\n%s\n\n", str); - free(str); - - ofl_msg_free(msg, &dpctl_exp); - } - } -} - -static void -features(struct vconn *vconn, int argc UNUSED, char *argv[] UNUSED) { - struct ofl_msg_header req = - {.type = OFPT_FEATURES_REQUEST}; - - dpctl_transact_and_print(vconn, (struct ofl_msg_header *)&req, NULL); -} - - - -static void -get_config(struct vconn *vconn, int argc UNUSED, char *argv[] UNUSED) { - struct ofl_msg_header req = - {.type = OFPT_GET_CONFIG_REQUEST}; - - dpctl_transact_and_print(vconn, (struct ofl_msg_header *)&req, NULL); -} - - - -static void -stats_desc(struct vconn *vconn, int argc UNUSED, char *argv[] UNUSED) { - struct ofl_msg_stats_request_header req = - {{.type = OFPT_MULTIPART_REQUEST}, - .type = OFPMP_DESC, .flags = 0x0000}; - - dpctl_transact_and_print(vconn, (struct ofl_msg_header *)&req, NULL); -} - -static void -stats_flow(struct vconn *vconn, int argc, char *argv[]) { - struct ofl_msg_stats_request_flow req = - {{{.type = OFPT_MULTIPART_REQUEST}, - .type = OFPMP_FLOW, .flags = 0x0000}, - .cookie = 0x0000000000000000ULL, - .cookie_mask = 0x0000000000000000ULL, - .table_id = 0xff, - .out_port = OFPP_ANY, - .out_group = OFPG_ANY, - .match = NULL}; - - if (argc > 0) { - parse_flow_stat_args(argv[0], &req); - } - if (argc > 1) { - parse_match(argv[1], &(req.match)); - } else { - make_all_match(&(req.match)); - } - - dpctl_transact_and_print(vconn, (struct ofl_msg_header *)&req, NULL); -} - -static void -stats_aggr(struct vconn *vconn, int argc, char *argv[]) { - struct ofl_msg_stats_request_flow req = - {{{.type = OFPT_MULTIPART_REQUEST}, - .type = OFPMP_AGGREGATE, .flags = 0x0000}, - .cookie = 0x0000000000000000ULL, - .cookie_mask = 0x0000000000000000ULL, - .table_id = 0xff, - .out_port = OFPP_ANY, - .out_group = OFPG_ANY, - .match = NULL}; - - if (argc > 0) { - parse_flow_stat_args(argv[0], &req); - } - if (argc > 1) { - parse_match(argv[1], &(req.match)); - } else { - make_all_match(&(req.match)); - } - - dpctl_transact_and_print(vconn, (struct ofl_msg_header *)&req, NULL); -} - -static void -stats_table(struct vconn *vconn, int argc UNUSED, char *argv[] UNUSED) { - struct ofl_msg_stats_request_header req = - {{.type = OFPT_MULTIPART_REQUEST}, - .type = OFPMP_TABLE, .flags = 0x0000}; - - dpctl_transact_and_print(vconn, (struct ofl_msg_header *)&req, NULL); -} - - - -static void -stats_port(struct vconn *vconn, int argc, char *argv[]) { - struct ofl_msg_stats_request_port req = - {{{.type = OFPT_MULTIPART_REQUEST}, - .type = OFPMP_PORT_STATS, .flags = 0x0000}, - .port_no = OFPP_ANY}; - - if (argc > 0 && parse_port(argv[0], &req.port_no)) { - ofp_fatal(0, "Error parsing port: %s.", argv[0]); - } - - dpctl_transact_and_print(vconn, (struct ofl_msg_header *)&req, NULL); -} - - - -static void -stats_queue(struct vconn *vconn, int argc, char *argv[]) { - struct ofl_msg_stats_request_queue req = - {{{.type = OFPT_MULTIPART_REQUEST}, - .type = OFPMP_QUEUE, .flags = 0x0000}, - .port_no = OFPP_ANY, - .queue_id = OFPQ_ALL}; - - if (argc > 0 && parse_port(argv[0], &req.port_no)) { - ofp_fatal(0, "Error parsing port: %s.", argv[0]); - } - if (argc > 1 && parse_queue(argv[1], &req.queue_id)) { - ofp_fatal(0, "Error parsing queue: %s.", argv[1]); - } - - dpctl_transact_and_print(vconn, (struct ofl_msg_header *)&req, NULL); -} - - - -static void -stats_group(struct vconn *vconn, int argc, char *argv[]) { - struct ofl_msg_stats_request_group req = - {{{.type = OFPT_MULTIPART_REQUEST}, - .type = OFPMP_GROUP, .flags = 0x0000}, - .group_id = OFPG_ALL}; - - if (argc > 0 && parse_group(argv[0], &req.group_id)) { - ofp_fatal(0, "Error parsing group: %s.", argv[0]); - } - - dpctl_transact_and_print(vconn, (struct ofl_msg_header *)&req, NULL); -} - - - -static void -stats_group_desc(struct vconn *vconn, int argc, char *argv[]) { - struct ofl_msg_stats_request_group req = - {{{.type = OFPT_MULTIPART_REQUEST}, - .type = OFPMP_GROUP_DESC, .flags = 0x0000}, - .group_id = OFPG_ALL}; - - if (argc > 0 && parse_group(argv[0], &req.group_id)) { - ofp_fatal(0, "Error parsing group: %s.", argv[0]); - } - - dpctl_transact_and_print(vconn, (struct ofl_msg_header *)&req, NULL); -} - - - - - -static void -set_config(struct vconn *vconn, int argc UNUSED, char *argv[]) { - struct ofl_msg_set_config msg = - {{.type = OFPT_SET_CONFIG}, - .config = NULL}; - - msg.config = xmalloc(sizeof(struct ofl_config)); - msg.config->flags = OFPC_FRAG_NORMAL; - msg.config->miss_send_len = OFP_DEFAULT_MISS_SEND_LEN; - - parse_config(argv[0], msg.config); - - dpctl_send_and_print(vconn, (struct ofl_msg_header *)&msg); -} - - - -static void -flow_mod(struct vconn *vconn, int argc, char *argv[]) { - struct ofl_msg_flow_mod msg = - {{.type = OFPT_FLOW_MOD}, - .cookie = 0x0000000000000000ULL, - .cookie_mask = 0x0000000000000000ULL, - .table_id = 0xff, - .command = OFPFC_ADD, - .idle_timeout = OFP_FLOW_PERMANENT, - .hard_timeout = OFP_FLOW_PERMANENT, - .priority = OFP_DEFAULT_PRIORITY, - .buffer_id = 0xffffffff, - .out_port = OFPP_ANY, - .out_group = OFPG_ANY, - .flags = 0x0000, - .match = NULL, - .instructions_num = 0, - .instructions = NULL}; - - parse_flow_mod_args(argv[0], &msg); - - if (argc > 1) { - size_t i; - size_t inst_num = argc - 2; - parse_match(argv[1], &(msg.match)); - - msg.instructions_num = inst_num; - msg.instructions = xmalloc(sizeof(struct ofl_instrcution_header *) * inst_num); - - for (i=0; i < inst_num; i++) { - parse_inst(argv[2+i], &(msg.instructions[i])); - } - } else { - make_all_match(&(msg.match)); - } - dpctl_send_and_print(vconn, (struct ofl_msg_header *)&msg); -} - - - -static void -group_mod(struct vconn *vconn, int argc, char *argv[]) { - struct ofl_msg_group_mod msg = - {{.type = OFPT_GROUP_MOD}, - .command = OFPGC_ADD, - .type = OFPGT_ALL, - .group_id = OFPG_ALL, - .buckets_num = 0, - .buckets = NULL}; - - parse_group_mod_args(argv[0], &msg); - - if (argc > 1) { - size_t i; - size_t buckets_num = (argc - 1) / 2; - - msg.buckets_num = buckets_num; - msg.buckets = xmalloc(sizeof(struct ofl_bucket *) * buckets_num); - - for (i=0; i < buckets_num; i++) { - msg.buckets[i] = xmalloc(sizeof(struct ofl_bucket)); - msg.buckets[i]->weight = 0; - msg.buckets[i]->watch_port = OFPP_ANY; - msg.buckets[i]->watch_group = OFPG_ANY; - msg.buckets[i]->actions_num = 0; - msg.buckets[i]->actions = NULL; - - parse_bucket(argv[i*2+1], msg.buckets[i]); - parse_actions(argv[i*2+2], &(msg.buckets[i]->actions_num), &(msg.buckets[i]->actions)); - } - } - - dpctl_send_and_print(vconn, (struct ofl_msg_header *)&msg); -} - - - -static void -port_mod(struct vconn *vconn, int argc UNUSED, char *argv[]) { - struct ofl_msg_port_mod msg = - {{.type = OFPT_PORT_MOD}, - .port_no = OFPP_ANY, - .config = 0x00000000, - .mask = 0x00000000, - .advertise = 0x00000000 - }; - memcpy(msg.hw_addr, mask_all, OFP_ETH_ALEN); - - parse_port_mod(argv[0], &msg); - - dpctl_send_and_print(vconn, (struct ofl_msg_header *)&msg); -} - - - -static void -table_mod(struct vconn *vconn, int argc UNUSED, char *argv[]) { - struct ofl_msg_table_mod msg = - {{.type = OFPT_TABLE_MOD}, - .table_id = 0xff, - .config = 0x00}; - - parse_table_mod(argv[0], &msg); - - dpctl_send_and_print(vconn, (struct ofl_msg_header *)&msg); -} - - - -static void -queue_get_config(struct vconn *vconn, int argc UNUSED, char *argv[]) { - struct ofl_msg_queue_get_config_request msg = - {{.type = OFPT_QUEUE_GET_CONFIG_REQUEST}, - .port = OFPP_ALL}; - - if (parse_port(argv[0], &msg.port)) { - ofp_fatal(0, "Error parsing queue_get_config port: %s.", argv[0]); - } - - dpctl_send_and_print(vconn, (struct ofl_msg_header *)&msg); -} - - - -static void -set_desc(struct vconn *vconn, int argc UNUSED, char *argv[]) { - struct ofl_exp_openflow_msg_set_dp_desc msg = - {{{{.type = OFPT_EXPERIMENTER}, - .experimenter_id = OPENFLOW_VENDOR_ID}, - .type = OFP_EXT_SET_DESC}, - .dp_desc = argv[0]}; - - dpctl_send_and_print(vconn, (struct ofl_msg_header *)&msg); -} - - - -static void -queue_mod(struct vconn *vconn, int argc UNUSED, char *argv[]) { - struct ofl_packet_queue *pq; - struct ofl_queue_prop_min_rate *p; - - struct ofl_exp_openflow_msg_queue msg = - {{{{.type = OFPT_EXPERIMENTER}, - .experimenter_id = OPENFLOW_VENDOR_ID}, - .type = OFP_EXT_QUEUE_MODIFY}, - .port_id = OFPP_ANY, - .queue = NULL}; - - if (parse_port(argv[0], &msg.port_id)) { - ofp_fatal(0, "Error parsing queue_mod port: %s.", argv[0]); - } - - pq = xmalloc(sizeof(struct ofl_packet_queue)); - msg.queue = pq; - if (parse_queue(argv[1], &pq->queue_id)) { - ofp_fatal(0, "Error parsing queue_mod queue: %s.", argv[1]); - } - - pq->properties_num = 1; - pq->properties = xmalloc(sizeof(struct ofl_queue_prop_header *)); - - p = xmalloc(sizeof(struct ofl_queue_prop_min_rate)); - pq->properties[0] = (struct ofl_queue_prop_header *)p; - p->header.type = OFPQT_MIN_RATE; - - if (parse16(argv[2], NULL,0, UINT16_MAX, &p->rate)) { - ofp_fatal(0, "Error parsing queue_mod bw: %s.", argv[2]); - } - - - dpctl_send_and_print(vconn, (struct ofl_msg_header *)&msg); -} - - - -static void -queue_del(struct vconn *vconn, int argc UNUSED, char *argv[]) { - struct ofl_packet_queue *pq; - - struct ofl_exp_openflow_msg_queue msg = - {{{{.type = OFPT_EXPERIMENTER}, - .experimenter_id = OPENFLOW_VENDOR_ID}, - .type = OFP_EXT_QUEUE_DELETE}, - .port_id = OFPP_ANY, - .queue = NULL}; - - if (parse_port(argv[0], &msg.port_id)) { - ofp_fatal(0, "Error parsing queue_mod port: %s.", argv[0]); - } - - pq = xmalloc(sizeof(struct ofl_packet_queue)); - msg.queue = pq; - if (parse_queue(argv[1], &pq->queue_id)) { - ofp_fatal(0, "Error parsing queue_mod queue: %s.", argv[1]); - } - - pq->properties_num = 0; - pq->properties = NULL; - - dpctl_send_and_print(vconn, (struct ofl_msg_header *)&msg); -} - -static struct command all_commands[] = { - {"ping", 0, 2, ping}, - {"monitor", 0, 0, monitor}, - - {"features", 0, 0, features }, - {"get-config", 0, 0, get_config}, - {"stats-desc", 0, 0, stats_desc }, - {"stats-flow", 0, 2, stats_flow}, - {"stats-aggr", 0, 2, stats_aggr}, - {"stats-table", 0, 0, stats_table }, - {"stats-port", 0, 1, stats_port }, - {"stats-queue", 0, 2, stats_queue }, - {"stats-group", 0, 1, stats_group }, - {"stats-group-desc", 0, 1, stats_group_desc }, - - {"set-config", 1, 1, set_config}, - {"flow-mod", 1, 7/*+1 for each inst type*/, flow_mod }, - {"group-mod", 1, UINT8_MAX, group_mod }, - {"port-mod", 1, 1, port_mod }, - {"table-mod", 1, 1, table_mod }, - {"queue-get-config", 1, 1, queue_get_config}, - - {"set-desc", 1, 1, set_desc}, - {"queue-mod", 3, 3, queue_mod}, - {"queue-del", 2, 2, queue_del} -}; - - -int main(int argc, char *argv[]) -{ - struct command *p; - struct vconn *vconn; - size_t i; - int error; - - set_program_name(argv[0]); - time_init(); - vlog_init(); - parse_options(argc, argv); - signal(SIGPIPE, SIG_IGN); - - argc -= optind; - argv += optind; - if (argc < 1) - ofp_fatal(0, "missing SWITCH; use --help for help"); - if (argc < 2) - ofp_fatal(0, "missing COMMAND; use --help for help"); - - error = vconn_open_block(argv[0], OFP_VERSION, &vconn); - if (error) { - ofp_fatal(error, "Error connecting to switch %s.", argv[0]); - } - argc -= 1; - argv += 1; - - for (i=0; iname, argv[0]) == 0) { - argc -= 1; - argv += 1; - if (argc < p->min_args) - ofp_fatal(0, "'%s' command requires at least %d arguments", - p->name, p->min_args); - else if (argc > p->max_args) - ofp_fatal(0, "'%s' command takes at most %d arguments", - p->name, p->max_args); - else { - p->handler(vconn, argc, argv); - if (ferror(stdout)) { - ofp_fatal(0, "write to stdout failed"); - } - if (ferror(stderr)) { - ofp_fatal(0, "write to stderr failed"); - } - vconn_close(vconn); - exit(0); - } - } - } - ofp_fatal(0, "unknown command '%s'; use --help for help", argv[0]); - vconn_close(vconn); - return 0; -} - -static void -parse_options(int argc, char *argv[]) -{ - enum { - OPT_STRICT = UCHAR_MAX + 1 - }; - static struct option long_options[] = { - {"timeout", required_argument, 0, 't'}, - {"verbose", optional_argument, 0, 'v'}, - {"strict", no_argument, 0, OPT_STRICT}, - {"help", no_argument, 0, 'h'}, - {"version", no_argument, 0, 'V'}, - VCONN_SSL_LONG_OPTIONS - {0, 0, 0, 0}, - }; - char *short_options = long_options_to_short_options(long_options); - - for (;;) { - unsigned long int timeout; - int c; - - c = getopt_long(argc, argv, short_options, long_options, NULL); - if (c == -1) { - break; - } - - switch (c) { - case 't': - timeout = strtoul(optarg, NULL, 10); - if (timeout <= 0) { - ofp_fatal(0, "value %s on -t or --timeout is not at least 1", - optarg); - } else { - time_alarm(timeout); - } - break; - - case 'h': - usage(); - - case 'V': - printf("%s %s compiled "__DATE__" "__TIME__"\n", - program_name, VERSION BUILDNR); - exit(EXIT_SUCCESS); - - case 'v': - vlog_set_verbosity(optarg); - break; - - VCONN_SSL_OPTION_HANDLERS - - case '?': - exit(EXIT_FAILURE); - - default: - abort(); - } - } - free(short_options); -} - - - -static void -usage(void) -{ - printf("%s: OpenFlow switch management utility\n" - "usage: %s [OPTIONS] SWITCH COMMAND [ARG...]\n" - " SWITCH ping [N] [B] latency of B-byte echos N times\n" - " SWITCH monitor monitors packets from the switch\n" - "\n" - " SWITCH features show basic information\n" - " SWITCH get-config get switch configuration\n" - " SWITCH stats-desc print switch description\n" - " SWITCH stats-flow [ARG [MATCH]] print flow stats\n" - " SWITCH stats-aggr [ARG [MATCH]] print flow aggregate stats\n" - " SWITCH stats-table print table stats\n" - " SWITCH stats-port [PORT] print port statistics\n" - " SWITCH stats-queue [PORT [QUEUE]] print queue statistics\n" - " SWITCH stats-group [GROUP] print group statistics\n" - " SWITCH stats-group-desc [GROUP] print group desc statistics\n" - "\n" - " SWITCH set-config ARG set switch configuration\n" - " SWITCH flow-mod ARG [MATCH [INST...]] send flow_mod message\n" - " SWITCH group-mod ARG [BUCARG ACT...] send group_mod message\n" - " SWITCH port-mod ARG send port_mod message\n" - " SWITCH table-mod ARG send table_mod message\n" - " SWITCH queue-get-config PORT send queue_get_config message\n" - "\n" - "OpenFlow extensions\n" - " SWITCH set-desc DESC sets the DP description\n" - " SWITCH queue-mod PORT QUEUE BW adds/modifies queue\n" - " SWITCH queue-del PORT QUEUE deletes queue\n" - "\n", - program_name, program_name); - vconn_usage(true, false, false); - vlog_usage(); - printf("\nOther options:\n" - " --strict use strict match for flow commands\n" - " -t, --timeout=SECS give up after SECS seconds\n" - " -h, --help display this help message\n" - " -V, --version display version information\n"); - exit(EXIT_SUCCESS); -} - -static void -parse_match(char *str, struct ofl_match_header **match) { - // TODO parse masks - char *token, *saveptr = NULL; - struct ofl_match *m = xmalloc(sizeof(struct ofl_match)); - ofl_structs_match_init(m); - - for (token = strtok_r(str, KEY_SEP, &saveptr); token != NULL; token = strtok_r(NULL, KEY_SEP, &saveptr)) { - if (strncmp(token, "apply", strlen("apply")) == 0 ) { - break; - } - /* In_port */ - if (strncmp(token, MATCH_IN_PORT KEY_VAL, strlen(MATCH_IN_PORT KEY_VAL)) == 0) { - uint32_t in_port; - if (parse_port(token + strlen(MATCH_IN_PORT KEY_VAL), &in_port)) { - ofp_fatal(0, "Error parsing port: %s.", token); - } - else ofl_structs_match_put32(m,OXM_OF_IN_PORT,in_port); - continue; - } - - /* Ethernet Address*/ - if (strncmp(token, MATCH_DL_SRC KEY_VAL, strlen(MATCH_DL_SRC KEY_VAL)) == 0) { - uint8_t eth_src[6]; - if (parse_dl_addr(token + strlen(MATCH_DL_SRC KEY_VAL), eth_src)) { - ofp_fatal(0, "Error parsing dl_src: %s.", token); - } - else ofl_structs_match_put_eth(m,OXM_OF_ETH_SRC,eth_src); - continue; - } - if (strncmp(token, MATCH_DL_DST KEY_VAL, strlen(MATCH_DL_DST KEY_VAL)) == 0) { - uint8_t eth_dst[6]; - if (parse_dl_addr(token + strlen(MATCH_DL_DST KEY_VAL), eth_dst)) { - ofp_fatal(0, "Error parsing dl_dst: %s.", token); - } - else ofl_structs_match_put_eth(m,OXM_OF_ETH_DST,eth_dst); - continue; - } - - /* ARP */ - if (strncmp(token, MATCH_ARP_SHA KEY_VAL, strlen(MATCH_ARP_SHA KEY_VAL)) == 0) { - uint8_t arp_sha[6]; - if (parse_dl_addr(token + strlen(MATCH_DL_SRC KEY_VAL), arp_sha)) { - ofp_fatal(0, "Error parsing arp_sha: %s.", token); - } - else ofl_structs_match_put_eth(m, OXM_OF_ARP_SHA, arp_sha); - continue; - } - if (strncmp(token, MATCH_ARP_THA KEY_VAL, strlen(MATCH_ARP_THA KEY_VAL)) == 0) { - uint8_t arp_tha[6]; - if (parse_dl_addr(token + strlen(MATCH_ARP_THA KEY_VAL), arp_tha)) { - ofp_fatal(0, "Error parsing arp_tha %s.", token); - } - else ofl_structs_match_put_eth(m,OXM_OF_ARP_THA, arp_tha); - continue; - } - if (strncmp(token, MATCH_ARP_OP KEY_VAL, strlen(MATCH_ARP_OP KEY_VAL)) == 0) { - uint8_t arp_op; - if (parse8(token + strlen(MATCH_DL_VLAN_PCP KEY_VAL), NULL, 0, 0x7, &arp_op)) { - ofp_fatal(0, "Error parsing arp_op: %s.", token); - } else - ofl_structs_match_put8(m, OXM_OF_ARP_OP, arp_op); - continue; - } - - /* VLAN */ - if (strncmp(token, MATCH_DL_VLAN KEY_VAL, strlen(MATCH_DL_VLAN KEY_VAL)) == 0) { - uint16_t dl_vlan; - if (parse_vlan_vid(token + strlen(MATCH_DL_VLAN KEY_VAL), &dl_vlan)) { - ofp_fatal(0, "Error parsing vlan label: %s.", token); - } - else ofl_structs_match_put16(m,OXM_OF_VLAN_VID, dl_vlan); - continue; - } - if (strncmp(token, MATCH_DL_VLAN_PCP KEY_VAL, strlen(MATCH_DL_VLAN_PCP KEY_VAL)) == 0) { - uint8_t pcp; - if (parse8(token + strlen(MATCH_DL_VLAN_PCP KEY_VAL), NULL, 0, 0x7, &pcp)) { - ofp_fatal(0, "Error parsing vlan pcp: %s.", token); - } else - ofl_structs_match_put8(m, OXM_OF_VLAN_PCP, pcp); - continue; - } - - /* Eth Type */ - if (strncmp(token, MATCH_DL_TYPE KEY_VAL, strlen(MATCH_DL_TYPE KEY_VAL)) == 0) { - uint16_t dl_type; - if (parse16(token + strlen(MATCH_DL_TYPE KEY_VAL), NULL, 0, 0xffff, &dl_type)) { - ofp_fatal(0, "Error parsing eth_type: %s.", token); - } - else - ofl_structs_match_put16(m, OXM_OF_ETH_TYPE,dl_type); - continue; - } - - /* IP */ - if (strncmp(token, MATCH_IP_ECN, strlen(MATCH_IP_ECN KEY_VAL)) == 0) { - uint8_t ip_ecn; - if (parse8(token + strlen(MATCH_IP_ECN KEY_VAL), NULL, 0, 0x3f, &ip_ecn)) { - ofp_fatal(0, "Error parsing nw_tos: %s.", token); - } - else - ofl_structs_match_put8(m, OXM_OF_IP_ECN, ip_ecn); - continue; - } - if (strncmp(token, MATCH_IP_DSCP, strlen(MATCH_IP_DSCP KEY_VAL)) == 0) { - uint8_t ip_dscp; - if (parse8(token + strlen(MATCH_IP_DSCP KEY_VAL), NULL, 0, 0x3f, &ip_dscp)) { - ofp_fatal(0, "Error parsing nw_tos: %s.", token); - } - else - ofl_structs_match_put8(m, OXM_OF_IP_DSCP, ip_dscp); - continue; - } - if (strncmp(token, MATCH_NW_PROTO KEY_VAL, strlen(MATCH_NW_PROTO KEY_VAL)) == 0) { - uint8_t nw_proto; - if (parse8(token + strlen(MATCH_NW_PROTO KEY_VAL), NULL, 0, 0xff, &nw_proto)) { - ofp_fatal(0, "Error parsing ip_proto: %s.", token); - } - else ofl_structs_match_put8(m,OXM_OF_IP_PROTO, nw_proto); - continue; - } - if (strncmp(token, MATCH_NW_SRC KEY_VAL, strlen(MATCH_NW_SRC KEY_VAL)) == 0) { - uint32_t nw_src; - if (parse_nw_addr(token + strlen(MATCH_NW_SRC KEY_VAL), &(nw_src))) { - ofp_fatal(0, "Error parsing ip_src: %s.", token); - } - else ofl_structs_match_put32(m, OXM_OF_IPV4_SRC,nw_src); - continue; - } - if (strncmp(token, MATCH_NW_DST KEY_VAL, strlen(MATCH_NW_DST KEY_VAL)) == 0) { - uint32_t nw_dst; - if (parse_nw_addr(token + strlen(MATCH_NW_DST KEY_VAL), &nw_dst)) { - ofp_fatal(0, "Error parsing ip_dst: %s.", token); - } - else ofl_structs_match_put32(m, OXM_OF_IPV4_DST,nw_dst); - continue; - } - - /* ICMP */ - if (strncmp(token, MATCH_ICMPV4_CODE, strlen(MATCH_ICMPV4_CODE KEY_VAL)) == 0) { - uint8_t icmpv4_code; - if (parse8(token + strlen(MATCH_ICMPV4_CODE KEY_VAL), NULL, 0, 0x3f, &icmpv4_code)) { - ofp_fatal(0, "Error parsing icmpv4_code: %s.", token); - } - else - ofl_structs_match_put8(m, OXM_OF_ICMPV4_CODE, icmpv4_code); - continue; - } - if (strncmp(token, MATCH_ICMPV4_TYPE, strlen(MATCH_ICMPV4_TYPE KEY_VAL)) == 0) { - uint8_t icmpv4_type; - if (parse8(token + strlen(MATCH_ICMPV4_TYPE KEY_VAL), NULL, 0, 0x3f, &icmpv4_type)) { - ofp_fatal(0, "Error parsing icmpv4_type: %s.", token); - } - else - ofl_structs_match_put8(m, OXM_OF_ICMPV4_CODE, icmpv4_type); - continue; - } - - /* TCP */ - if (strncmp(token, MATCH_TP_SRC KEY_VAL, strlen(MATCH_TP_SRC KEY_VAL)) == 0) { - uint16_t tp_src; - if (parse16(token + strlen(MATCH_TP_SRC KEY_VAL), NULL, 0, 0xffff, &tp_src)) { - ofp_fatal(0, "Error parsing tcp_src: %s.", token); - } - else ofl_structs_match_put16(m, OXM_OF_TCP_SRC,tp_src); - continue; - } - if (strncmp(token, MATCH_TP_DST KEY_VAL, strlen(MATCH_TP_DST KEY_VAL)) == 0) { - uint16_t tp_dst; - if (parse16(token + strlen(MATCH_TP_DST KEY_VAL), NULL, 0, 0xffff, &tp_dst)) { - ofp_fatal(0, "Error parsing tcp_dst: %s.", token); - } - else ofl_structs_match_put16(m, OXM_OF_TCP_DST,tp_dst); - continue; - } - - /*UDP */ - if (strncmp(token, MATCH_UDP_SRC KEY_VAL, strlen(MATCH_UDP_SRC KEY_VAL)) == 0) { - uint16_t udp_src; - if (parse16(token + strlen(MATCH_UDP_SRC KEY_VAL), NULL, 0, 0xffff, &udp_src)) { - ofp_fatal(0, "Error parsing udp_src: %s.", token); - } - else ofl_structs_match_put16(m, OXM_OF_UDP_SRC,udp_src); - continue; - } - if (strncmp(token, MATCH_UDP_DST KEY_VAL, strlen(MATCH_UDP_DST KEY_VAL)) == 0) { - uint16_t udp_dst; - if (parse16(token + strlen(MATCH_UDP_DST KEY_VAL), NULL, 0, 0xffff, &udp_dst)) { - ofp_fatal(0, "Error parsing udp_dst: %s.", token); - } - else ofl_structs_match_put16(m, OXM_OF_UDP_DST,udp_dst); - continue; - } - - /*SCTP*/ - if (strncmp(token, MATCH_SCTP_SRC KEY_VAL, strlen(MATCH_SCTP_SRC KEY_VAL)) == 0) { - uint16_t sctp_src; - if (parse16(token + strlen(MATCH_SCTP_SRC KEY_VAL), NULL, 0, 0xffff, &sctp_src)) { - ofp_fatal(0, "Error parsing sctp_src: %s.", token); - } - else ofl_structs_match_put16(m, OXM_OF_SCTP_SRC,sctp_src); - continue; - } - if (strncmp(token, MATCH_SCTP_DST KEY_VAL, strlen(MATCH_SCTP_DST KEY_VAL)) == 0) { - uint16_t sctp_dst; - if (parse16(token + strlen(MATCH_SCTP_DST KEY_VAL), NULL, 0, 0xffff, &sctp_dst)) { - ofp_fatal(0, "Error parsing sctp_dst: %s.", token); - } - else ofl_structs_match_put16(m, OXM_OF_SCTP_DST,sctp_dst); - continue; - } - - /* MPLS */ - if (strncmp(token, MATCH_MPLS_LABEL KEY_VAL, strlen(MATCH_MPLS_LABEL KEY_VAL)) == 0) { - uint32_t mpls_label; - if (parse32(token + strlen(MATCH_MPLS_LABEL KEY_VAL), NULL, 0, 0xfffff, &mpls_label)) { - ofp_fatal(0, "Error parsing mpls_label: %s.", token); - } - else ofl_structs_match_put32(m,OXM_OF_MPLS_LABEL,mpls_label); - } - if (strncmp(token, MATCH_MPLS_TC KEY_VAL, strlen(MATCH_MPLS_TC KEY_VAL)) == 0) { - uint8_t mpls_tc; - if (parse8(token + strlen(MATCH_MPLS_TC KEY_VAL), NULL, 0, 0x07, &mpls_tc)) { - ofp_fatal(0, "Error parsing mpls_tc: %s.", token); - } - else - ofl_structs_match_put8(m, OXM_OF_MPLS_TC, mpls_tc); - continue; - } - - /* IPv6 */ - if (strncmp(token, MATCH_NW_SRC_IPV6 KEY_VAL , strlen(MATCH_NW_SRC_IPV6 KEY_VAL)) == 0) { - struct in6_addr addr, mask; - if (str_to_ipv6(token + strlen(MATCH_NW_DST_IPV6)+1, &addr, &mask) < 0) { - ofp_fatal(0, "Error parsing nw_src_ipv6: %s.", token); - } - else { - ofl_structs_match_put_ipv6(m, OXM_OF_IPV6_SRC, addr.s6_addr); - } - continue; - } - if (strncmp(token, MATCH_NW_DST_IPV6 KEY_VAL , strlen(MATCH_NW_DST_IPV6 KEY_VAL)) == 0) { - struct in6_addr addr, mask; - if (str_to_ipv6(token + strlen(MATCH_NW_DST_IPV6)+1, &addr, &mask) < 0) { - ofp_fatal(0, "Error parsing nw_src_ipv6: %s.", token); - } - else { - ofl_structs_match_put_ipv6(m, OXM_OF_IPV6_DST, addr.s6_addr); - } - continue; - } - if (strncmp(token, MATCH_IPV6_FLABEL KEY_VAL, strlen(MATCH_IPV6_FLABEL KEY_VAL)) == 0) { - uint32_t ipv6_label; - if (parse32(token + strlen(MATCH_IPV6_FLABEL KEY_VAL), NULL, 0, 0xfffff, &ipv6_label)) { - ofp_fatal(0, "Error parsing ipv6_label: %s.", token); - } - else ofl_structs_match_put32(m,OXM_OF_IPV6_FLABEL, ipv6_label); - } - - /* ICMPv6 */ - if (strncmp(token, MATCH_ICMPV6_CODE, strlen(MATCH_ICMPV6_CODE KEY_VAL)) == 0) { - uint8_t icmpv6_code; - if (parse8(token + strlen(MATCH_ICMPV6_CODE KEY_VAL), NULL, 0, 0x3f, &icmpv6_code)) { - ofp_fatal(0, "Error parsing icmpv6_code: %s.", token); - } - else - ofl_structs_match_put8(m, OXM_OF_ICMPV6_CODE, icmpv6_code); - continue; - } - if (strncmp(token, MATCH_ICMPV6_TYPE, strlen(MATCH_ICMPV6_TYPE KEY_VAL)) == 0) { - uint8_t icmpv6_type; - if (parse8(token + strlen(MATCH_ICMPV6_TYPE KEY_VAL), NULL, 0, 0x3f, &icmpv6_type)) { - ofp_fatal(0, "Error parsing icmpv6_type: %s.", token); - } - else - ofl_structs_match_put8(m, OXM_OF_ICMPV6_CODE, icmpv6_type); - continue; - } - - /* IPv6 ND */ - if (strncmp(token, MATCH_IPV6_ND_TARGET KEY_VAL , strlen(MATCH_IPV6_ND_TARGET KEY_VAL)) == 0) { - struct in6_addr addr, mask; - if (str_to_ipv6(token + strlen(MATCH_IPV6_ND_TARGET)+1, &addr, &mask) < 0) { - ofp_fatal(0, "Error parsing ipv6_nd_target %s.", token); - } - else { - ofl_structs_match_put_ipv6(m, OXM_OF_IPV6_ND_TARGET, addr.s6_addr); - } - continue; - } - if (strncmp(token, MATCH_IPV6_ND_SLL KEY_VAL, strlen(MATCH_IPV6_ND_SLL KEY_VAL)) == 0) { - uint8_t eth_src[6]; - if (parse_dl_addr(token + strlen(MATCH_IPV6_ND_SLL KEY_VAL), eth_src)) { - ofp_fatal(0, "Error parsing ipv6_nd_sll: %s.", token); - } - else ofl_structs_match_put_eth(m,OXM_OF_IPV6_ND_SLL, eth_src); - continue; - } - if (strncmp(token, MATCH_IPV6_ND_TLL KEY_VAL, strlen(MATCH_IPV6_ND_TLL KEY_VAL)) == 0) { - uint8_t eth_dst[6]; - if (parse_dl_addr(token + strlen(MATCH_IPV6_ND_TLL KEY_VAL), eth_dst)) { - ofp_fatal(0, "Error parsing ipv_nd_tll: %s.", token); - } - else ofl_structs_match_put_eth(m, OXM_OF_IPV6_ND_TLL,eth_dst); - continue; - } - - /* Metadata */ - if (strncmp(token, MATCH_METADATA KEY_VAL, strlen(MATCH_METADATA KEY_VAL)) == 0) { - uint64_t metadata; - if (sscanf(token, MATCH_METADATA KEY_VAL "0x%"SCNx64"", (&metadata))) { - ofp_fatal(0, "Error parsing %s: %s.", MATCH_METADATA, token); - } - else ofl_structs_match_put64(m, OXM_OF_METADATA, metadata); - continue; - } - ofp_fatal(0, "Error parsing match arg: %s.", token); - } - - (*match) = (struct ofl_match_header *)m; -} - -static int -parse_set_field(char *token, struct ofl_action_set_field *act) { - - - if (strncmp(token, MATCH_DL_SRC KEY_VAL, strlen(MATCH_DL_SRC KEY_VAL)) == 0) { - uint8_t* dl_src = xmalloc(6); - if (parse_dl_addr(token + strlen(MATCH_DL_SRC KEY_VAL), dl_src)) { - ofp_fatal(0, "Error parsing dl_src: %s.", token); - }else{ - act->field = (struct ofl_match_tlv*) malloc(sizeof(struct ofl_match_tlv)); - act->field->header = OXM_OF_ETH_SRC; - act->field->value = (uint8_t*) dl_src; - } - return 0; - } - if (strncmp(token, MATCH_DL_DST KEY_VAL, strlen(MATCH_DL_DST KEY_VAL)) == 0) { - uint8_t* dl_dst = xmalloc(6); - if (parse_dl_addr(token + strlen(MATCH_DL_SRC KEY_VAL), dl_dst)) { - ofp_fatal(0, "Error parsing dl_dst: %s.", token); - }else{ - act->field = (struct ofl_match_tlv*) malloc(sizeof(struct ofl_match_tlv)); - act->field->header = OXM_OF_ETH_DST; - act->field->value = (uint8_t*) dl_dst; - } - } - if (strncmp(token, MATCH_DL_VLAN KEY_VAL, strlen(MATCH_DL_VLAN KEY_VAL)) == 0) { - uint16_t *dl_vlan = malloc(sizeof(uint16_t)); - if (parse_vlan_vid(token + strlen(MATCH_DL_VLAN KEY_VAL), dl_vlan)) { - ofp_fatal(0, "Error parsing vlan label: %s.", token); - } - else { - act->field = (struct ofl_match_tlv*) malloc(sizeof(struct ofl_match_tlv)); - act->field->header = OXM_OF_VLAN_VID; - act->field->value = (uint8_t*) dl_vlan; - } - return 0; - } - if (strncmp(token, MATCH_DL_VLAN_PCP KEY_VAL, strlen(MATCH_DL_VLAN_PCP KEY_VAL)) == 0) { - uint8_t* vlan_pcp = malloc(sizeof(uint8_t)); - if (parse8(token + strlen(MATCH_DL_VLAN_PCP KEY_VAL), NULL, 0, 0x7, vlan_pcp)) { - ofp_fatal(0, "Error parsing vlan pcp: %s.", token); - } - else{ - act->field = (struct ofl_match_tlv*) malloc(sizeof(struct ofl_match_tlv)); - act->field->header = OXM_OF_VLAN_PCP; - act->field->value = (uint8_t*) vlan_pcp; - } - return 0; - } - if (strncmp(token, MATCH_DL_TYPE KEY_VAL, strlen(MATCH_DL_TYPE KEY_VAL)) == 0) { - uint16_t* dl_type = xmalloc(sizeof(uint16_t)); - if (parse16(token + strlen(MATCH_DL_TYPE KEY_VAL), NULL, 0, 0xffff, dl_type)) { - ofp_fatal(0, "Error parsing dl_type: %s.", token); - } - else { - act->field = (struct ofl_match_tlv*) malloc(sizeof(struct ofl_match_tlv)); - act->field->header = OXM_OF_ETH_TYPE; - act->field->value = (uint8_t*) dl_type; - } - return 0; - } - if (strncmp(token, MATCH_NW_SRC KEY_VAL, strlen(MATCH_NW_SRC KEY_VAL)) == 0) { - uint32_t* nw_src = malloc(sizeof(uint32_t)); - if (parse_nw_addr(token + strlen(MATCH_NW_SRC KEY_VAL), nw_src)) { - ofp_fatal(0, "Error parsing ip_src: %s.", token); - } - else { - act->field = (struct ofl_match_tlv*) malloc(sizeof(struct ofl_match_tlv)); - act->field->header = OXM_OF_IPV4_SRC; - act->field->value = (uint8_t*) nw_src; - } - return 0; - } - if (strncmp(token, MATCH_NW_DST KEY_VAL, strlen(MATCH_NW_DST KEY_VAL)) == 0) { - uint32_t * nw_dst = malloc(sizeof(uint32_t)); - if (parse_nw_addr(token + strlen(MATCH_NW_DST KEY_VAL), nw_dst)) { - ofp_fatal(0, "Error parsing ip_dst: %s.", token); - } - else { - act->field = (struct ofl_match_tlv*) malloc(sizeof(struct ofl_match_tlv)); - act->field->header = OXM_OF_IPV4_DST; - act->field->value = (uint8_t*) nw_dst; - } - return 0; - } - if (strncmp(token, MATCH_TP_SRC KEY_VAL, strlen(MATCH_TP_SRC KEY_VAL)) == 0) { - uint16_t* tp_src = xmalloc(2); - if (parse16(token+ strlen(MATCH_TP_SRC KEY_VAL), NULL, 0, 0xffff, tp_src)) { - ofp_fatal(0, "Error parsing tcp_src: %s.", token); - }else{ - act->field = (struct ofl_match_tlv*) malloc(sizeof(struct ofl_match_tlv)); - act->field->header = OXM_OF_TCP_SRC; - act->field->value = (uint8_t*) tp_src; - } - return 0; - } - if (strncmp(token, MATCH_TP_DST KEY_VAL, strlen(MATCH_TP_DST KEY_VAL)) == 0) { - uint16_t* tp_dst = xmalloc(2); - if (parse16(token + strlen(MATCH_TP_SRC KEY_VAL), NULL, 0, 0xffff, tp_dst)) { - ofp_fatal(0, "Error parsing tcp_src: %s.", token); - }else{ - act->field = (struct ofl_match_tlv*) malloc(sizeof(struct ofl_match_tlv)); - act->field->header = OXM_OF_TCP_DST; - act->field->value = (uint8_t*) tp_dst; - } - return 0; - } - ofp_fatal(0, "Error parsing set_field arg: %s.", token); -} - -static void -make_all_match(struct ofl_match_header **match) { - struct ofl_match *m = xmalloc(sizeof(struct ofl_match)); - - ofl_structs_match_init(m); - - (*match) = (struct ofl_match_header *)m; -} - - -static void -parse_action(uint16_t type, char *str, struct ofl_action_header **act) { - switch (type) { - case (OFPAT_OUTPUT): { - char *token, *saveptr = NULL; - struct ofl_action_output *a = xmalloc(sizeof(struct ofl_action_output)); - - token = strtok_r(str, KEY_VAL2, &saveptr); - if (parse_port(token, &(a->port))) { - ofp_fatal(0, "Error parsing port in output action: %s.", str); - } - token = strtok_r(NULL, KEY_VAL2, &saveptr); - if (token == NULL) { - a->max_len = 0; - } else { - if (parse16(token, NULL, 0, 0xffff - sizeof(struct ofp_header), &(a->max_len))) { - ofp_fatal(0, "Error parsing max_len in output action: %s.", str); - } - } - (*act) = (struct ofl_action_header *)a; - break; - } - case (OFPAT_SET_FIELD):{ - struct ofl_action_set_field *a = xmalloc(sizeof (struct ofl_action_set_field)); - if (parse_set_field(str, a)) { - ofp_fatal(0, "Error parsing field in set_field action: %s.", str); - } - (*act) = (struct ofl_action_header *)a; - break; - } - case (OFPAT_COPY_TTL_OUT): - case (OFPAT_COPY_TTL_IN): { - struct ofl_action_header *a = xmalloc(sizeof(struct ofl_action_header)); - (*act) = a; - break; - } - case (OFPAT_SET_MPLS_TTL): { - struct ofl_action_mpls_ttl *a = xmalloc(sizeof(struct ofl_action_mpls_ttl)); - if (parse8(str, NULL, 0, 255, &(a->mpls_ttl))) { - ofp_fatal(0, "Error parsing ttl in mpls_ttl action: %s.", str); - } - (*act) = (struct ofl_action_header *)a; - break; - } - case (OFPAT_DEC_MPLS_TTL): { - struct ofl_action_header *a = xmalloc(sizeof(struct ofl_action_header)); - (*act) = a; - break; - } - case (OFPAT_PUSH_VLAN): - case (OFPAT_PUSH_MPLS): { - struct ofl_action_push *a = xmalloc(sizeof(struct ofl_action_push)); - if (sscanf(str, "0x%"SCNx16"", &(a->ethertype)) != 1) { - ofp_fatal(0, "Error parsing ethertype in push_mpls/vlan action: %s.", str); - } - (*act) = (struct ofl_action_header *)a; - break; - } - case (OFPAT_POP_VLAN): { - struct ofl_action_header *a = xmalloc(sizeof(struct ofl_action_header)); - (*act) = a; - break; - } - case (OFPAT_POP_MPLS): { - struct ofl_action_pop_mpls *a = xmalloc(sizeof(struct ofl_action_pop_mpls)); - if (sscanf(str, "0x%"SCNx16"", &(a->ethertype)) != 1) { - ofp_fatal(0, "Error parsing ethertype in pop_mpls action: %s.", str); - } - (*act) = (struct ofl_action_header *)a; - break; - } - case (OFPAT_SET_QUEUE): { - struct ofl_action_set_queue *a = xmalloc(sizeof(struct ofl_action_set_queue)); - if (parse32(str, NULL, 0, 0xffffffff, &(a->queue_id))) { - ofp_fatal(0, "Error parsing queue in queue action: %s.", str); - } - (*act) = (struct ofl_action_header *)a; - break; - } - case (OFPAT_GROUP): { - struct ofl_action_group *a = xmalloc(sizeof(struct ofl_action_group)); - if (parse_group(str, &(a->group_id))) { - ofp_fatal(0, "Error parsing group in group action: %s.", str); - } - (*act) = (struct ofl_action_header *)a; - break; - } - case (OFPAT_SET_NW_TTL): { - struct ofl_action_set_nw_ttl *a = xmalloc(sizeof(struct ofl_action_set_nw_ttl)); - if (parse8(str, NULL, 0, 255, &(a->nw_ttl))) { - ofp_fatal(0, "Error parsing ttl in mpls_ttl action: %s.", str); - } - (*act) = (struct ofl_action_header *)a; - break; - } - case (OFPAT_DEC_NW_TTL): { - struct ofl_action_header *a = xmalloc(sizeof(struct ofl_action_header)); - (*act) = a; - break; - } - default: { - ofp_fatal(0, "Error parsing action: %s.", str); - } - } - (*act)->type = type; -} - -static void -parse_actions(char *str, size_t *acts_num, struct ofl_action_header ***acts) { - char *token, *saveptr = NULL; - char *s; - size_t i; - bool found; - struct ofl_action_header *act = NULL; - - for (token = strtok_r(str, KEY_SEP, &saveptr); token != NULL; token = strtok_r(NULL, KEY_SEP, &saveptr)) { - found = false; - for (i=0; iheader.type = OFPIT_GOTO_TABLE; - if (parse_table(s, &(i->table_id))) { - ofp_fatal(0, "Error parsing table in goto instruction: %s.", s); - } - (*inst) = (struct ofl_instruction_header *)i; - return; - } - case (OFPIT_WRITE_METADATA): { - char *token, *saveptr = NULL; - struct ofl_instruction_write_metadata *i = xmalloc(sizeof(struct ofl_instruction_write_metadata)); - i->header.type = OFPIT_WRITE_METADATA; - token = strtok_r(s, KEY_SEP, &saveptr); - if (sscanf(token, "0x%"SCNx64"", &(i->metadata)) != 1) { - ofp_fatal(0, "Error parsing metadata in write metadata instruction: %s.", s); - } - token = strtok_r(NULL, KEY_SEP, &saveptr); - if (token == NULL) { - i->metadata_mask = 0xffffffffffffffffULL; - } else { - if (sscanf(token, "0x%"SCNx64"", &(i->metadata_mask)) != 1) { - ofp_fatal(0, "Error parsing metadata_mask in write metadata instruction: %s.", s); - } - } - (*inst) = (struct ofl_instruction_header *)i; - return; - } - case (OFPIT_WRITE_ACTIONS): { - struct ofl_instruction_actions *i = xmalloc(sizeof(struct ofl_instruction_actions)); - i->header.type = OFPIT_WRITE_ACTIONS; - i->actions = NULL; - i->actions_num = 0; - parse_actions(s, &(i->actions_num), &(i->actions)); - (*inst) = (struct ofl_instruction_header *)i; - return; - } - case (OFPIT_APPLY_ACTIONS): { - struct ofl_instruction_actions *i = xmalloc(sizeof(struct ofl_instruction_actions)); - i->header.type = OFPIT_APPLY_ACTIONS; - i->actions = NULL; - i->actions_num = 0; - parse_actions(s, &(i->actions_num), &(i->actions)); - (*inst) = (struct ofl_instruction_header *)i; - return; - } - case (OFPIT_CLEAR_ACTIONS): { - struct ofl_instruction_header *i = xmalloc(sizeof(struct ofl_instruction_header)); - i->type = OFPIT_CLEAR_ACTIONS; - (*inst) = (struct ofl_instruction_header *)i; - return; - } - } - } - } - ofp_fatal(0, "Error parsing instruction: %s.", str); -} - - -static void -parse_flow_stat_args(char *str, struct ofl_msg_stats_request_flow *req) { - char *token, *saveptr = NULL; - - for (token = strtok_r(str, KEY_SEP, &saveptr); token != NULL; token = strtok_r(NULL, KEY_SEP, &saveptr)) { - if (strncmp(token, FLOW_MOD_COOKIE KEY_VAL, strlen(FLOW_MOD_COOKIE KEY_VAL)) == 0) { - if (sscanf(token, FLOW_MOD_COOKIE KEY_VAL "0x%"SCNx64"", &(req->cookie)) != 1) { - ofp_fatal(0, "Error parsing flow_stat cookie: %s.", token); - } - continue; - } - if (strncmp(token, FLOW_MOD_COOKIE_MASK KEY_VAL, strlen(FLOW_MOD_COOKIE_MASK KEY_VAL)) == 0) { - if (sscanf(token, FLOW_MOD_COOKIE KEY_VAL "0x%"SCNx64"", &(req->cookie)) != 1) { - ofp_fatal(0, "Error parsing flow_stat cookie mask: %s.", token); - } - continue; - } - if (strncmp(token, FLOW_MOD_TABLE_ID KEY_VAL, strlen(FLOW_MOD_TABLE_ID KEY_VAL)) == 0) { - if (parse8(token + strlen(FLOW_MOD_TABLE_ID KEY_VAL), table_names, NUM_ELEMS(table_names), 254, &req->table_id)) { - ofp_fatal(0, "Error parsing flow_stat table: %s.", token); - } - continue; - } - if (strncmp(token, FLOW_MOD_OUT_PORT KEY_VAL, strlen(FLOW_MOD_OUT_PORT KEY_VAL)) == 0) { - if (parse_port(token + strlen(FLOW_MOD_OUT_PORT KEY_VAL), &req->out_port)) { - ofp_fatal(0, "Error parsing flow_stat port: %s.", token); - } - continue; - } - if (strncmp(token, FLOW_MOD_OUT_GROUP KEY_VAL, strlen(FLOW_MOD_OUT_GROUP KEY_VAL)) == 0) { - if (parse_group(token + strlen(FLOW_MOD_OUT_GROUP KEY_VAL), &req->out_port)) { - ofp_fatal(0, "Error parsing flow_stat group: %s.", token); - } - continue; - } - ofp_fatal(0, "Error parsing flow_stat arg: %s.", token); - } -} - - - -static void -parse_flow_mod_args(char *str, struct ofl_msg_flow_mod *req) { - char *token, *saveptr = NULL; - - for (token = strtok_r(str, KEY_SEP, &saveptr); token != NULL; token = strtok_r(NULL, KEY_SEP, &saveptr)) { - if (strncmp(token, FLOW_MOD_COMMAND KEY_VAL, strlen(FLOW_MOD_COMMAND KEY_VAL)) == 0) { - uint8_t command; - if (parse8(token + strlen(FLOW_MOD_COMMAND KEY_VAL), flow_mod_cmd_names, NUM_ELEMS(flow_mod_cmd_names),0, &command)) { - ofp_fatal(0, "Error parsing flow_mod command: %s.", token); - } - req->command = command; - continue; - } - if (strncmp(token, FLOW_MOD_COOKIE KEY_VAL, strlen(FLOW_MOD_COOKIE KEY_VAL)) == 0) { - if (sscanf(token, FLOW_MOD_COOKIE KEY_VAL "0x%"SCNx64"", &(req->cookie)) != 1) { - ofp_fatal(0, "Error parsing flow_mod cookie: %s.", token); - } - continue; - } - if (strncmp(token, FLOW_MOD_COOKIE_MASK KEY_VAL, strlen(FLOW_MOD_COOKIE_MASK KEY_VAL)) == 0) { - if (sscanf(token, FLOW_MOD_COOKIE KEY_VAL "0x%"SCNx64"", &(req->cookie)) != 1) { - ofp_fatal(0, "Error parsing flow_mod cookie mask: %s.", token); - } - continue; - } - if (strncmp(token, FLOW_MOD_TABLE_ID KEY_VAL, strlen(FLOW_MOD_TABLE_ID KEY_VAL)) == 0) { - if (parse8(token + strlen(FLOW_MOD_TABLE_ID KEY_VAL), table_names, NUM_ELEMS(table_names), 254, &req->table_id)) { - ofp_fatal(0, "Error parsing flow_mod table: %s.", token); - } - continue; - } - if (strncmp(token, FLOW_MOD_IDLE KEY_VAL, strlen(FLOW_MOD_IDLE KEY_VAL)) == 0) { - if (sscanf(token, FLOW_MOD_IDLE KEY_VAL "%"SCNu16"", &(req->idle_timeout)) != 1) { - ofp_fatal(0, "Error parsing %s: %s.", FLOW_MOD_IDLE, token); - } - continue; - } - if (strncmp(token, FLOW_MOD_HARD KEY_VAL, strlen(FLOW_MOD_HARD KEY_VAL)) == 0) { - if (sscanf(token, FLOW_MOD_HARD KEY_VAL "%"SCNu16"", &(req->hard_timeout)) != 1) { - ofp_fatal(0, "Error parsing %s: %s.", FLOW_MOD_HARD, token); - } - continue; - } - if (strncmp(token, FLOW_MOD_PRIO KEY_VAL, strlen(FLOW_MOD_PRIO KEY_VAL)) == 0) { - if (sscanf(token, FLOW_MOD_PRIO KEY_VAL "%"SCNu16"", &(req->priority)) != 1) { - ofp_fatal(0, "Error parsing %s: %s.", FLOW_MOD_PRIO, token); - } - continue; - } - if (strncmp(token, FLOW_MOD_BUFFER KEY_VAL, strlen(FLOW_MOD_BUFFER KEY_VAL)) == 0) { - if (parse32(token + strlen(FLOW_MOD_BUFFER KEY_VAL), buffer_names, NUM_ELEMS(buffer_names), UINT32_MAX, &req->buffer_id)) { - ofp_fatal(0, "Error parsing flow_mod buffer: %s.", token); - } - continue; - } - if (strncmp(token, FLOW_MOD_OUT_PORT KEY_VAL, strlen(FLOW_MOD_OUT_PORT KEY_VAL)) == 0) { - if (parse_port(token + strlen(FLOW_MOD_OUT_PORT KEY_VAL), &req->out_port)) { - ofp_fatal(0, "Error parsing flow_mod port: %s.", token); - } - continue; - } - if (strncmp(token, FLOW_MOD_OUT_GROUP KEY_VAL, strlen(FLOW_MOD_OUT_GROUP KEY_VAL)) == 0) { - if (parse_group(token + strlen(FLOW_MOD_OUT_GROUP KEY_VAL), &req->out_port)) { - ofp_fatal(0, "Error parsing flow_mod group: %s.", token); - } - continue; - } - if (strncmp(token, FLOW_MOD_FLAGS KEY_VAL, strlen(FLOW_MOD_FLAGS KEY_VAL)) == 0) { - if (sscanf(token, FLOW_MOD_FLAGS KEY_VAL "0x%"SCNx16"", &(req->flags)) != 1) { - ofp_fatal(0, "Error parsing %s: %s.", FLOW_MOD_FLAGS, token); - } - continue; - } - ofp_fatal(0, "Error parsing flow_mod arg: %s.", token); - } -} - -static void -parse_group_mod_args(char *str, struct ofl_msg_group_mod *req) { - char *token, *saveptr = NULL; - - for (token = strtok_r(str, KEY_SEP, &saveptr); token != NULL; token = strtok_r(NULL, KEY_SEP, &saveptr)) { - if (strncmp(token, GROUP_MOD_COMMAND KEY_VAL, strlen(GROUP_MOD_COMMAND KEY_VAL)) == 0) { - uint16_t command; - if (parse16(token + strlen(GROUP_MOD_COMMAND KEY_VAL), group_mod_cmd_names, NUM_ELEMS(group_mod_cmd_names),0, &command)) { - ofp_fatal(0, "Error parsing group_mod command: %s.", token); - } - req->command = command; - continue; - } - if (strncmp(token, GROUP_MOD_GROUP KEY_VAL, strlen(GROUP_MOD_GROUP KEY_VAL)) == 0) { - if (parse_group(token + strlen(GROUP_MOD_GROUP KEY_VAL), &req->group_id)) { - ofp_fatal(0, "Error parsing group_mod group: %s.", token); - } - continue; - } - if (strncmp(token, GROUP_MOD_TYPE KEY_VAL, strlen(GROUP_MOD_TYPE KEY_VAL)) == 0) { - uint8_t type; - if (parse8(token + strlen(GROUP_MOD_TYPE KEY_VAL), group_type_names, NUM_ELEMS(group_type_names), UINT8_MAX, &type)) { - ofp_fatal(0, "Error parsing group_mod type: %s.", token); - } - req->type = type; - continue; - } - ofp_fatal(0, "Error parsing group_mod arg: %s.", token); - } -} - -static void -parse_bucket(char *str, struct ofl_bucket *b) { - char *token, *saveptr = NULL; - - for (token = strtok_r(str, KEY_SEP, &saveptr); token != NULL; token = strtok_r(NULL, KEY_SEP, &saveptr)) { - if (strncmp(token, BUCKET_WEIGHT KEY_VAL, strlen(BUCKET_WEIGHT KEY_VAL)) == 0) { - if (parse16(token + strlen(BUCKET_WEIGHT KEY_VAL), NULL, 0, UINT16_MAX, &b->weight)) { - ofp_fatal(0, "Error parsing bucket_weight: %s.", token); - } - continue; - } - if (strncmp(token, BUCKET_WATCH_PORT KEY_VAL, strlen(BUCKET_WATCH_PORT KEY_VAL)) == 0) { - if (parse_port(token + strlen(BUCKET_WATCH_PORT KEY_VAL), &b->watch_port)) { - ofp_fatal(0, "Error parsing bucket watch port: %s.", token); - } - continue; - } - if (strncmp(token, BUCKET_WATCH_GROUP KEY_VAL, strlen(BUCKET_WATCH_GROUP KEY_VAL)) == 0) { - if (parse_group(token + strlen(BUCKET_WATCH_GROUP KEY_VAL), &b->watch_group)) { - ofp_fatal(0, "Error parsing bucket watch group: %s.", token); - } - continue; - } - ofp_fatal(0, "Error parsing bucket arg: %s.", token); - } -} - -static void -parse_config(char *str, struct ofl_config *c) { - char *token, *saveptr = NULL; - - for (token = strtok_r(str, KEY_SEP, &saveptr); token != NULL; token = strtok_r(NULL, KEY_SEP, &saveptr)) { - if (strncmp(token, CONFIG_FLAGS KEY_VAL, strlen(CONFIG_FLAGS KEY_VAL)) == 0) { - if (sscanf(token + strlen(CONFIG_FLAGS KEY_VAL), "0x%"SCNx16"", &c->flags) != 1) { - ofp_fatal(0, "Error parsing config flags: %s.", token); - } - continue; - } - if (strncmp(token, CONFIG_MISS KEY_VAL, strlen(CONFIG_MISS KEY_VAL)) == 0) { - if (parse16(token + strlen(CONFIG_MISS KEY_VAL), NULL, 0, UINT16_MAX - sizeof(struct ofp_packet_in), &c->miss_send_len)) { - ofp_fatal(0, "Error parsing config miss send len: %s.", token); - } - continue; - } - ofp_fatal(0, "Error parsing config arg: %s.", token); - } -} - -static void -parse_port_mod(char *str, struct ofl_msg_port_mod *msg) { - char *token, *saveptr = NULL; - - for (token = strtok_r(str, KEY_SEP, &saveptr); token != NULL; token = strtok_r(NULL, KEY_SEP, &saveptr)) { - if (strncmp(token, PORT_MOD_PORT KEY_VAL, strlen(PORT_MOD_PORT KEY_VAL)) == 0) { - if (parse_port(token + strlen(PORT_MOD_PORT KEY_VAL), &msg->port_no)) { - ofp_fatal(0, "Error parsing port_mod port: %s.", token); - } - continue; - } - if (strncmp(token, PORT_MOD_HW_ADDR KEY_VAL, strlen(PORT_MOD_HW_ADDR KEY_VAL)) == 0) { - if (parse_dl_addr(token + strlen(PORT_MOD_HW_ADDR KEY_VAL), msg->hw_addr)) { - ofp_fatal(0, "Error parsing port_mod hw_addr: %s.", token); - } - continue; - } - if (strncmp(token, PORT_MOD_HW_CONFIG KEY_VAL, strlen(PORT_MOD_HW_CONFIG KEY_VAL)) == 0) { - if (sscanf(token + strlen(PORT_MOD_HW_CONFIG KEY_VAL), "0x%"SCNx32"", &msg->config) != 1) { - ofp_fatal(0, "Error parsing port_mod conf: %s.", token); - } - continue; - } - if (strncmp(token, PORT_MOD_MASK KEY_VAL, strlen(PORT_MOD_MASK KEY_VAL)) == 0) { - if (sscanf(token + strlen(PORT_MOD_MASK KEY_VAL), "0x%"SCNx32"", &msg->mask) != 1) { - ofp_fatal(0, "Error parsing port_mod mask: %s.", token); - } - continue; - } - if (strncmp(token, PORT_MOD_ADVERTISE KEY_VAL, strlen(PORT_MOD_ADVERTISE KEY_VAL)) == 0) { - if (sscanf(token + strlen(PORT_MOD_ADVERTISE KEY_VAL), "0x%"SCNx32"", &msg->advertise) != 1) { - ofp_fatal(0, "Error parsing port_mod advertise: %s.", token); - } - continue; - } - ofp_fatal(0, "Error parsing port_mod arg: %s.", token); - } -} - - -static void -parse_table_mod(char *str, struct ofl_msg_table_mod *msg) { - char *token, *saveptr = NULL; - - for (token = strtok_r(str, KEY_SEP, &saveptr); token != NULL; token = strtok_r(NULL, KEY_SEP, &saveptr)) { - if (strncmp(token, TABLE_MOD_TABLE KEY_VAL, strlen(TABLE_MOD_TABLE KEY_VAL)) == 0) { - if (parse_table(token + strlen(TABLE_MOD_TABLE KEY_VAL), &msg->table_id)) { - ofp_fatal(0, "Error parsing table_mod table: %s.", token); - } - continue; - } - if (strncmp(token, TABLE_MOD_CONFIG KEY_VAL, strlen(TABLE_MOD_CONFIG KEY_VAL)) == 0) { - if (sscanf(token + strlen(TABLE_MOD_CONFIG KEY_VAL), "0x%"SCNx32"", &msg->config) != 1) { - ofp_fatal(0, "Error parsing table_mod conf: %s.", token); - } - continue; - } - ofp_fatal(0, "Error parsing table_mod arg: %s.", token); - } -} - - -static int -parse_port(char *str, uint32_t *port) { - return parse32(str, port_names, NUM_ELEMS(port_names), OFPP_MAX, port); -} - -static int -parse_queue(char *str, uint32_t *port) { - return parse32(str, queue_names, NUM_ELEMS(queue_names), 0xfffffffe, port); -} - -static int -parse_group(char *str, uint32_t *group) { - return parse32(str, group_names, NUM_ELEMS(group_names), OFPG_MAX, group); -} - -static int -parse_table(char *str, uint8_t *table) { - return parse8(str, table_names, NUM_ELEMS(table_names), 0xfe, table); -} - -static int -parse_dl_addr(char *str, uint8_t *addr) { - return (sscanf(str, "%"SCNx8":%"SCNx8":%"SCNx8":%"SCNx8":%"SCNx8":%"SCNx8, - addr, addr+1, addr+2, addr+3, addr+4, addr+5) != 6); -} - -static int -parse_nw_addr(char *str, uint32_t *addr) { - // TODO Zoltan: netmask ? - // TODO Zoltan: DNS lookup ? - uint8_t a[4]; - - if (sscanf(str, "%"SCNu8".%"SCNu8".%"SCNu8".%"SCNu8, - &a[0], &a[1], &a[2], &a[3]) == 4) { - *addr = (a[3] << 24) | (a[2] << 16) | (a[1] << 8) | a[0]; - return 0; - } - return -1; -} - -static int -parse_vlan_vid(char *str, uint16_t *vid) { - return parse16(str, vlan_vid_names, NUM_ELEMS(vlan_vid_names), 0xfff, vid); -} - - - - - -static int -parse8(char *str, struct names8 *names, size_t names_num, uint8_t max, uint8_t *val) { - size_t i; - - for (i=0; i 0) && (sscanf(str, "%"SCNu8"", val)) == 1 && (*val <= max)) { - return 0; - } - return -1; -} - -static int -parse16(char *str, struct names16 *names, size_t names_num, uint16_t max, uint16_t *val) { - size_t i; - - for (i=0; i 0) && (sscanf(str, "%"SCNx16"", val)) == 1 && (*val <= max)) { - return 0; - } - } - else { - if ((max > 0) && (sscanf(str, "%"SCNu16"", val)) == 1 && (*val <= max)) { - return 0; - } - } - return -1; -} - -static int -parse32(char *str, struct names32 *names, size_t names_num, uint32_t max, uint32_t *val) { - size_t i; - - for (i=0; i 0) && (sscanf(str, "%"SCNu32"", val)) == 1 && ((*val) <= max)) { - return 0; - } - return -1; -} - diff --git a/utilities/dpctl_parser.py b/utilities/dpctl_parser.py new file mode 100644 index 00000000..37b9d9ce --- /dev/null +++ b/utilities/dpctl_parser.py @@ -0,0 +1,104 @@ +#!/usr/bin/env python2.7 +import os +import subprocess +import sys +import json +import re +import ast +# +# A simple python utility which helps monitoring and debugging +# the flows set at the switch (using OF1.3). It displays the flows per +# table in a more convinient way. +# It uses the dpctl tool to send the flow stats req. +# +# To run the application simply supply the datapath used, for example: +# +# pyhon2.7 dpctl_parser.py unix:/var/run/dp0 +# +# Enjoy... +# +# Written by Simhon Doctori. +# For any issues please send reqs to simhond@gmail.com +# +# Regular expression to parse the output +first_parse = re.compile(r'^stat_repl\{type="flow", flags="0x0", stats=\[') +flow_parse = re.compile(r'(\{table="[0-9]+",\s?match="oxm\{[.A-Fa-z\s?+,"0-9:=_-]+\}",\s?dur_s="[0-9]+",\s?dur_ns="[0-9]+",\s?prio="[0-9]+",\s?idle_to="[0-9]+",\s?hard_to="[0-9]+",\s?cookie="0x[0-9a-fA-F]+",\s?pkt_cnt="[0-9]+",\s?byte_cnt="[0-9]+",\s?insts=\[((apply\{acts=\[[A-Fa-z,\s\{\}"0-9:\.=_-]*\]\})?(write\{acts=\[[A-Fa-z,\s\{\}"0-9:\.=_-]*\]\})?(,\s)?(meta\{meta="0x[0-9a-fA-F]+", mask="0x[0-9a-fA-F]+"\})?(,\s)?(goto\{table="[0-9]+"\})?)\]\})+') +flow_parse_values = re.compile(r'(\{table="(?P[0-9]+)",\s?match="oxm\{(?P[A-Fa-z,\s\?+,"0-9:\.=_-]+)\}",\s?dur_s="(?P[0-9]+)",\s?dur_ns="(?P[0-9]+)",\s?prio="(?P[0-9]+)",\s?idle_to="(?P[0-9]+)",\s?hard_to="[0-9]+",\s?cookie="(?P0x[0-9a-fA-F]+)",\s?pkt_cnt="(?P[0-9]+)",\s?byte_cnt="(?P[0-9]+)",\s?insts=\[(?P(apply\{acts=\[[A-Fa-z,\s\{\}"0-9:\.=_-]*\]\})?(write\{acts=\[[A-Fa-z,\s\{\}"0-9:\.=_-]*\]\})?(,\s)?(meta\{meta="0x[0-9a-fA-F]+", mask="0x[0-9a-fA-F]+"\})?(,\s)?(goto\{table="[0-9]+"\})?)\]\})+') + + + +def process_flow (ix,flow): + new_flow = {} + if flow_parse_values.match(flow): + new_flow['table'] = flow_parse_values.search(flow).group('table') + new_flow['match'] = flow_parse_values.search(flow).group('match') + new_flow['dur_s'] = flow_parse_values.search(flow).group('dur_s') + new_flow['prio'] = flow_parse_values.search(flow).group('prio') + new_flow['dur_ns'] = flow_parse_values.search(flow).group('dur_ns') + new_flow['idle_to'] = flow_parse_values.search(flow).group('idle_to') + new_flow['cookie'] = flow_parse_values.search(flow).group('cookie') + new_flow['pkts'] = flow_parse_values.search(flow).group('pkts') + new_flow['bytes'] = flow_parse_values.search(flow).group('bytes') + new_flow['insts'] = flow_parse_values.search(flow).group('insts') + #print 'Flow {0} ->'.format(ix),new_flow + return new_flow + + + +def do_parse(line): + print 'received input is:' + #print line + print '\nstart parsing...' + m = first_parse.match(line) + if m: + new_str = line[m.end():len(line)-2] + #print 'new str:',new_str + #print 'findall:',flow_parse.findall(new_str) + cnt = 0 + for x in flow_parse.findall(new_str): + cnt += 1 + #print 'entry number {0} :\n'.format(cnt),x[0] + flow_lists.extend([process_flow(cnt,x[0])]) + else: + print 'match not found' + + +def parse_list(): + last_table_id = -1 + for x in flow_lists: + table_id = x['table'] + if table_to_parse!=-1 and table_to_parse!=table_id: + continue + if last_table_id ./dpctl_output") +#print 'parsing the output file' + +with open("./dpctl_output") as f: + for line in f: + if 'stat_repl' in line: + do_parse(line) +parse_list() +#print 'delete the output file' +os.system("rm -rf ./dpctl_output") +print '\n\nExit' diff --git a/utilities/ofp-parse-leaks.in b/utilities/ofp-parse-leaks.in deleted file mode 100755 index 059c8509..00000000 --- a/utilities/ofp-parse-leaks.in +++ /dev/null @@ -1,285 +0,0 @@ -#! @PERL@ - -use strict; -use warnings; - -if (grep($_ eq '--help', @ARGV)) { - print < 1; -die "$0: $ARGV[0] does not exist" if @ARGV > 0 && ! -e $ARGV[0]; - -our ($binary); -our ($a2l) = search_path("addr2line"); -my ($no_syms) = "symbols will not be translated"; -if (!@ARGV) { - print "no binary specified; $no_syms\n"; -} elsif (! -e $ARGV[0]) { - print "$ARGV[0] does not exist; $no_syms"; -} elsif (!defined($a2l)) { - print "addr2line not found in PATH; $no_syms"; -} else { - $binary = $ARGV[0]; -} - -our ($objdump) = search_path("objdump"); -print "objdump not found; dynamic library symbols will not be translated\n" - if !defined($objdump); - -our %blocks; -our @segments; -while () { - my $ptr = "((?:0x)?[0-9a-fA-F]+|\\(nil\\))"; - my $callers = ":((?: $ptr)+)"; - if (/^malloc\((\d+)\) -> $ptr$callers$/) { - allocated($., $2, $1, $3); - } elsif (/^claim\($ptr\)$callers$/) { - claimed($., $1, $2); - } elsif (/realloc\($ptr, (\d+)\) -> $ptr$callers$/) { - my ($callers) = $4; - freed($., $1, $callers); - allocated($., $3, $2, $callers); - } elsif (/^free\($ptr\)$callers$/) { - freed($., $1, $2); - } elsif (/^segment: $ptr-$ptr $ptr [-r][-w][-x][sp] (.*)/) { - add_segment(hex($1), hex($2), hex($3), $4); - } else { - print "stdin:$.: syntax error\n"; - } -} -if (%blocks) { - my $n_blocks = scalar(keys(%blocks)); - my $n_bytes = 0; - $n_bytes += $_->{SIZE} foreach values(%blocks); - print "$n_bytes bytes in $n_blocks blocks not freed at end of run\n"; - my %blocks_by_callers; - foreach my $block (values(%blocks)) { - my ($trimmed_callers) = trim_callers($block->{CALLERS}); - push (@{$blocks_by_callers{$trimmed_callers}}, $block); - } - foreach my $callers (sort {@{$b} <=> @{$a}} (values(%blocks_by_callers))) { - $n_blocks = scalar(@{$callers}); - $n_bytes = 0; - $n_bytes += $_->{SIZE} foreach @{$callers}; - print "$n_bytes bytes in these $n_blocks blocks were not freed:\n"; - my $i = 0; - my $max = 5; - foreach my $block (sort {$a->{LINE} <=> $b->{LINE}} (@{$callers})) { - printf "\t%d-byte block at 0x%08x allocated on stdin:%d\n", - $block->{SIZE}, $block->{BASE}, $block->{LINE}; - last if $i++ > $max; - } - print "\t...and ", $n_blocks - $max, " others...\n" - if $n_blocks > $max; - print "The blocks listed above were allocated by:\n"; - print_callers("\t", ${$callers}[0]->{CALLERS}); - } -} -sub interp_pointer { - my ($s_ptr) = @_; - return $s_ptr eq '(nil)' ? 0 : hex($s_ptr); -} - -sub allocated { - my ($line, $s_base, $size, $callers) = @_; - my ($base) = interp_pointer($s_base); - return if !$base; - my ($info) = {LINE => $line, - BASE => $base, - SIZE => $size, - CALLERS => $callers}; - if (exists($blocks{$base})) { - print "In-use address returned by allocator:\n"; - print "\tInitial allocation:\n"; - print_block("\t\t", $blocks{$base}); - print "\tNew allocation:\n"; - print_block("\t\t", $info); - } - $blocks{$base} = $info; -} - -sub claimed { - my ($line, $s_base, $callers) = @_; - my ($base) = interp_pointer($s_base); - return if !$base; - if (exists($blocks{$base})) { - $blocks{$base}{LINE} = $line; - $blocks{$base}{CALLERS} = $callers; - } else { - printf "Claim asserted on not-in-use block 0x%08x by:\n", $base; - print_callers('', $callers); - } -} - -sub freed { - my ($line, $s_base, $callers) = @_; - my ($base) = interp_pointer($s_base); - return if !$base; - - if (!delete($blocks{$base})) { - printf "Bad free of not-allocated address 0x%08x on stdin:%d by:\n", $base, $line; - print_callers('', $callers); - } -} - -sub print_block { - my ($prefix, $info) = @_; - printf '%s%d-byte block at 0x%08x allocated on stdin:%d by:' . "\n", - $prefix, $info->{SIZE}, $info->{BASE}, $info->{LINE}; - print_callers($prefix, $info->{CALLERS}); -} - -sub print_callers { - my ($prefix, $callers) = @_; - foreach my $pc (split(' ', $callers)) { - print "$prefix\t", lookup_pc($pc), "\n"; - } -} - -our (%cache); -sub lookup_pc { - my ($s_pc) = @_; - if (defined($binary)) { - my ($pc) = hex($s_pc); - my ($output) = "$s_pc: "; - if (!exists($cache{$pc})) { - open(A2L, "$a2l -fe $binary --demangle $s_pc|"); - chomp(my $function = ); - chomp(my $line = ); - close(A2L); - if ($function eq '??') { - ($function, $line) = lookup_pc_by_segment($pc); - } - $line =~ s/^(\.\.\/)*//; - $line = "..." . substr($line, -25) if length($line) > 28; - $cache{$pc} = "$s_pc: $function ($line)"; - } - return $cache{$pc}; - } else { - return "$s_pc"; - } -} - -sub trim_callers { - my ($in) = @_; - my (@out); - foreach my $pc (split(' ', $in)) { - my $xlated = lookup_pc($pc); - if ($xlated =~ /\?\?/) { - push(@out, "...") if !@out || $out[$#out] ne '...'; - } else { - push(@out, $pc); - } - } - return join(' ', @out); -} - -sub search_path { - my ($target) = @_; - for my $dir (split (':', $ENV{PATH})) { - my ($file) = "$dir/$target"; - return $file if -e $file; - } - return undef; -} - -sub add_segment { - my ($vm_start, $vm_end, $vm_pgoff, $file) = @_; - for (my $i = 0; $i <= $#segments; $i++) { - my ($s) = $segments[$i]; - next if $vm_end <= $s->{START} || $vm_start >= $s->{END}; - if ($vm_start <= $s->{START} && $vm_end >= $s->{END}) { - splice(@segments, $i, 1); - --$i; - } else { - $s->{START} = $vm_end if $vm_end > $s->{START}; - $s->{END} = $vm_start if $vm_start <= $s->{END}; - } - } - push(@segments, {START => $vm_start, - END => $vm_end, - PGOFF => $vm_pgoff, - FILE => $file}); - @segments = sort { $a->{START} <=> $b->{START} } @segments; -} - -sub binary_search { - my ($array, $value) = @_; - my $l = 0; - my $r = $#{$array}; - while ($l <= $r) { - my $m = int(($l + $r) / 2); - my $e = $array->[$m]; - if ($value < $e->{START}) { - $r = $m - 1; - } elsif ($value >= $e->{END}) { - $l = $m + 1; - } else { - return $e; - } - } - return undef; -} - -sub read_sections { - my ($file) = @_; - my (@sections); - open(OBJDUMP, "$objdump -h $file|"); - while () { - my $ptr = "([0-9a-fA-F]+)"; - my ($name, $size, $vma, $lma, $file_off) - = /^\s*\d+\s+(\S+)\s+$ptr\s+$ptr\s+$ptr\s+$ptr/ - or next; - push(@sections, {START => hex($file_off), - END => hex($file_off) + hex($size), - NAME => $name}); - } - close(OBJDUMP); - return [sort { $a->{START} <=> $b->{START} } @sections ]; -} - -our %file_to_sections; -sub segment_to_section { - my ($file, $file_offset) = @_; - if (!defined($file_to_sections{$file})) { - $file_to_sections{$file} = read_sections($file); - } - return binary_search($file_to_sections{$file}, $file_offset); -} - -sub address_to_segment { - my ($pc) = @_; - return binary_search(\@segments, $pc); -} - -sub lookup_pc_by_segment { - return ('??', 0) if !defined($objdump); - - my ($pc) = @_; - my ($segment) = address_to_segment($pc); - return ('??', 0) if !defined($segment) || $segment->{FILE} eq ''; - - my ($file_offset) = $pc - $segment->{START} + $segment->{PGOFF}; - my ($section) = segment_to_section($segment->{FILE}, $file_offset); - return ('??', 0) if !defined($section); - - my ($section_offset) = $file_offset - $section->{START}; - open(A2L, sprintf("%s -fe %s --demangle --section=$section->{NAME} 0x%x|", - $a2l, $segment->{FILE}, $section_offset)); - chomp(my $function = ); - chomp(my $line = ); - close(A2L); - - return ($function, $line); -} - -# Local Variables: -# mode: perl -# End: diff --git a/utilities/ofp-read.c b/utilities/ofp-read.c new file mode 100644 index 00000000..6b95fe84 --- /dev/null +++ b/utilities/ofp-read.c @@ -0,0 +1,106 @@ +/* Copyright (c) 2013, Marco Canini + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the software nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include +#include +#include + +#include "oflib/ofl-messages.h" + +#include "timeval.h" +#include "vlog.h" + +static size_t read_all(FILE *file, uint8_t **buf) +{ + size_t buf_len; + uint8_t *data; + *buf = NULL; + + fseek(file, 0, SEEK_END); + buf_len = ftell(file); + rewind(file); + + data = (uint8_t*) malloc(buf_len); + if (fread(data, buf_len, 1, file) != 1){ + if (ferror(file)) { + fprintf(stderr, "Cannot read msg file.\n"); + } + return -1; + } + *buf = data; + return buf_len; +} + +int main(int argc, char **argv) +{ + uint8_t *buf ,*buf0; + size_t buf_len = 0; + ofl_err err; + struct ofl_msg_header *msg = NULL; + uint32_t xid; + FILE *msg_file; + struct ofp_header *oh; + + if (argc < 2) { + fprintf(stderr, "Expecting msg file.\n"); + return 1; + } + + time_init(); + vlog_init(); + vlog_set_verbosity(NULL); + + msg_file = fopen(argv[1], "r"); + if (msg_file == NULL) { + fprintf(stderr, "Cannot open msg file.\n"); + return 1; + } + buf_len = read_all(msg_file, &buf); + buf0 = buf; + + while (buf_len > 0) { + oh = (struct ofp_header *)buf; + err = ofl_msg_unpack(buf, ntohs(oh->length), &msg, &xid, NULL); + if (err == 0) { + //printf("Success!\n"); + ofl_msg_print(stdout, msg, NULL); + printf("\n\n"); + ofl_msg_free(msg, NULL); + } else { + free(buf); + printf("Failed :-( error type: %d code %d\n", ofl_error_type(err), ofl_error_code(err)); + return 1; + } + buf_len -= ntohs(oh->length); + buf += ntohs(oh->length); + } + free(buf0); + return 0; +} +